Hi Hans,

On 11/02/2021 12:37, Hans Verkuil wrote:
> Add HDMI CEC support for OMAP5.
> 
> Many thanks to Tomi for helping out how to enable CEC for omap5.
> 
> Signed-off-by: Hans Verkuil <hverkuil-ci...@xs4all.nl>
> Thanks-to: Tomi Valkeinen <tomi.valkei...@iki.fi>
> ---
>  drivers/gpu/drm/omapdrm/dss/Kconfig      |   8 +
>  drivers/gpu/drm/omapdrm/dss/Makefile     |   1 +
>  drivers/gpu/drm/omapdrm/dss/hdmi.h       |   1 +
>  drivers/gpu/drm/omapdrm/dss/hdmi5.c      |  63 +++++--
>  drivers/gpu/drm/omapdrm/dss/hdmi5_cec.c  | 201 +++++++++++++++++++++++
>  drivers/gpu/drm/omapdrm/dss/hdmi5_cec.h  |  42 +++++
>  drivers/gpu/drm/omapdrm/dss/hdmi5_core.c |  28 +++-
>  drivers/gpu/drm/omapdrm/dss/hdmi5_core.h |  33 +++-
>  8 files changed, 358 insertions(+), 19 deletions(-)
>  create mode 100644 drivers/gpu/drm/omapdrm/dss/hdmi5_cec.c
>  create mode 100644 drivers/gpu/drm/omapdrm/dss/hdmi5_cec.h
> 
> diff --git a/drivers/gpu/drm/omapdrm/dss/Kconfig 
> b/drivers/gpu/drm/omapdrm/dss/Kconfig
> index e11b258a2294..67a1ba14703b 100644
> --- a/drivers/gpu/drm/omapdrm/dss/Kconfig
> +++ b/drivers/gpu/drm/omapdrm/dss/Kconfig
> @@ -83,6 +83,14 @@ config OMAP5_DSS_HDMI
>         Definition Multimedia Interface. See https://www.hdmi.org/ for HDMI
>         specification.
>  
> +config OMAP5_DSS_HDMI_CEC
> +     bool "Enable HDMI CEC support for OMAP5"
> +     depends on OMAP5_DSS_HDMI
> +     select CEC_CORE
> +     default y
> +     help
> +       When selected the HDMI transmitter will support the CEC feature.
> +
>  config OMAP2_DSS_SDI
>       bool "SDI support"
>       default n
> diff --git a/drivers/gpu/drm/omapdrm/dss/Makefile 
> b/drivers/gpu/drm/omapdrm/dss/Makefile
> index f967e6948f2e..94fe0fa3b3c2 100644
> --- a/drivers/gpu/drm/omapdrm/dss/Makefile
> +++ b/drivers/gpu/drm/omapdrm/dss/Makefile
> @@ -17,4 +17,5 @@ omapdss-$(CONFIG_OMAP2_DSS_HDMI_COMMON) += hdmi_common.o 
> hdmi_wp.o hdmi_pll.o \
>  omapdss-$(CONFIG_OMAP4_DSS_HDMI) += hdmi4.o hdmi4_core.o
>  omapdss-$(CONFIG_OMAP4_DSS_HDMI_CEC) += hdmi4_cec.o
>  omapdss-$(CONFIG_OMAP5_DSS_HDMI) += hdmi5.o hdmi5_core.o
> +omapdss-$(CONFIG_OMAP5_DSS_HDMI_CEC) += hdmi5_cec.o
>  ccflags-$(CONFIG_OMAP2_DSS_DEBUG) += -DDEBUG
> diff --git a/drivers/gpu/drm/omapdrm/dss/hdmi.h 
> b/drivers/gpu/drm/omapdrm/dss/hdmi.h
> index c4a4e07f0b99..72d8ae441da6 100644
> --- a/drivers/gpu/drm/omapdrm/dss/hdmi.h
> +++ b/drivers/gpu/drm/omapdrm/dss/hdmi.h
> @@ -261,6 +261,7 @@ struct hdmi_core_data {
>       struct hdmi_wp_data *wp;
>       unsigned int core_pwr_cnt;
>       struct cec_adapter *adap;
> +     struct clk *cec_clk;
>  };
>  
>  static inline void hdmi_write_reg(void __iomem *base_addr, const u32 idx,
> diff --git a/drivers/gpu/drm/omapdrm/dss/hdmi5.c 
> b/drivers/gpu/drm/omapdrm/dss/hdmi5.c
> index 54e5cb5aa52d..b674d8ba173f 100644
> --- a/drivers/gpu/drm/omapdrm/dss/hdmi5.c
> +++ b/drivers/gpu/drm/omapdrm/dss/hdmi5.c
> @@ -29,12 +29,14 @@
>  #include <linux/of.h>
>  #include <linux/of_graph.h>
>  #include <sound/omap-hdmi-audio.h>
> +#include <media/cec.h>
>  
>  #include <drm/drm_atomic.h>
>  #include <drm/drm_atomic_state_helper.h>
>  
>  #include "omapdss.h"
>  #include "hdmi5_core.h"
> +#include "hdmi5_cec.h"
>  #include "dss.h"
>  
>  static int hdmi_runtime_get(struct omap_hdmi *hdmi)
> @@ -104,6 +106,10 @@ static irqreturn_t hdmi_irq_handler(int irq, void *data)
>       } else if (irqstatus & HDMI_IRQ_LINK_DISCONNECT) {
>               hdmi_wp_set_phy_pwr(wp, HDMI_PHYPWRCMD_LDOON);
>       }

Empty line here, please.

> +     if (irqstatus & HDMI_IRQ_CORE) {
> +             hdmi5_cec_irq(&hdmi->core);
> +             hdmi5_core_handle_irqs(&hdmi->core);
> +     }

It's a bit odd to call two functions here. Would it work if
hdmi5_core_handle_irqs() would read and clear HDMI_CORE_IH_CEC_STAT0,
and call hdmi5_cec_irq() if the stat != 0 ?

And it would be nice if hdmi5_core.c would enable and disable core
interrupt, but maybe that can be left for later if the need ever comes
to handle other interrupts than cec.

>  
>       return IRQ_HANDLED;
>  }
> @@ -112,9 +118,12 @@ static int hdmi_power_on_core(struct omap_hdmi *hdmi)
>  {
>       int r;
>  
> +     if (hdmi->core.core_pwr_cnt++)
> +             return 0;
> +
>       r = regulator_enable(hdmi->vdda_reg);
>       if (r)
> -             return r;
> +             goto err_reg_enable;
>  
>       r = hdmi_runtime_get(hdmi);
>       if (r)
> @@ -129,12 +138,17 @@ static int hdmi_power_on_core(struct omap_hdmi *hdmi)
>  
>  err_runtime_get:
>       regulator_disable(hdmi->vdda_reg);
> +err_reg_enable:
> +     hdmi->core.core_pwr_cnt--;
>  
>       return r;
>  }
>  
>  static void hdmi_power_off_core(struct omap_hdmi *hdmi)
>  {
> +     if (--hdmi->core.core_pwr_cnt)
> +             return;
> +
>       hdmi->core_enabled = false;
>  
>       hdmi_runtime_put(hdmi);
> @@ -168,7 +182,7 @@ static int hdmi_power_on_full(struct omap_hdmi *hdmi)
>               pc, &hdmi_cinfo);
>  
>       /* disable and clear irqs */
> -     hdmi_wp_clear_irqenable(&hdmi->wp, 0xffffffff);
> +     hdmi_wp_clear_irqenable(&hdmi->wp, ~HDMI_IRQ_CORE);

I guess the point here is to not touch CORE interrupt, as hdmi5_cec.c
handles that? The line below will still clear the CORE interrupt status.

>       hdmi_wp_set_irqstatus(&hdmi->wp,
>                       hdmi_wp_get_irqstatus(&hdmi->wp));
>  
> @@ -225,7 +239,7 @@ static int hdmi_power_on_full(struct omap_hdmi *hdmi)
>  
>  static void hdmi_power_off_full(struct omap_hdmi *hdmi)
>  {
> -     hdmi_wp_clear_irqenable(&hdmi->wp, 0xffffffff);
> +     hdmi_wp_clear_irqenable(&hdmi->wp, ~HDMI_IRQ_CORE);
>  
>       hdmi_wp_video_stop(&hdmi->wp);
>  
> @@ -273,11 +287,11 @@ static void hdmi_stop_audio_stream(struct omap_hdmi *hd)
>       REG_FLD_MOD(hd->wp.base, HDMI_WP_SYSCONFIG, hd->wp_idlemode, 3, 2);
>  }
>  
> -static int hdmi_core_enable(struct omap_hdmi *hdmi)
> +int hdmi5_core_enable(struct omap_hdmi *hdmi)
>  {
>       int r = 0;
>  
> -     DSSDBG("ENTER omapdss_hdmi_core_enable\n");
> +     DSSDBG("ENTER %s\n", __func__);
>  
>       mutex_lock(&hdmi->lock);
>  
> @@ -295,9 +309,9 @@ static int hdmi_core_enable(struct omap_hdmi *hdmi)
>       return r;
>  }
>  
> -static void hdmi_core_disable(struct omap_hdmi *hdmi)
> +void hdmi5_core_disable(struct omap_hdmi *hdmi)
>  {
> -     DSSDBG("Enter omapdss_hdmi_core_disable\n");
> +     DSSDBG("ENTER %s\n", __func__);
>  
>       mutex_lock(&hdmi->lock);
>  
> @@ -424,6 +438,15 @@ static void hdmi5_bridge_disable(struct drm_bridge 
> *bridge,
>       mutex_unlock(&hdmi->lock);
>  }
>  
> +static void hdmi5_bridge_hpd_notify(struct drm_bridge *bridge,
> +                                 enum drm_connector_status status)
> +{
> +     struct omap_hdmi *hdmi = drm_bridge_to_hdmi(bridge);
> +
> +     if (status == connector_status_disconnected)
> +             hdmi5_cec_set_phys_addr(&hdmi->core, NULL);
> +}
> +
>  static struct edid *hdmi5_bridge_get_edid(struct drm_bridge *bridge,
>                                         struct drm_connector *connector)
>  {
> @@ -436,7 +459,7 @@ static struct edid *hdmi5_bridge_get_edid(struct 
> drm_bridge *bridge,
>       need_enable = hdmi->core_enabled == false;
>  
>       if (need_enable) {
> -             r = hdmi_core_enable(hdmi);
> +             r = hdmi5_core_enable(hdmi);
>               if (r)
>                       return NULL;
>       }
> @@ -460,12 +483,29 @@ static struct edid *hdmi5_bridge_get_edid(struct 
> drm_bridge *bridge,
>       hdmi_runtime_put(hdmi);
>       mutex_unlock(&hdmi->lock);
>  
> +     hdmi5_cec_set_phys_addr(&hdmi->core, edid);
> +
>       if (need_enable)
> -             hdmi_core_disable(hdmi);
> +             hdmi5_core_disable(hdmi);
>  
>       return (struct edid *)edid;
>  }
>  
> +static int hdmi5_bridge_cec_init(struct drm_bridge *bridge,
> +                              struct drm_connector *conn)
> +{
> +     struct omap_hdmi *hdmi = drm_bridge_to_hdmi(bridge);
> +
> +     return hdmi5_cec_init(hdmi->pdev, &hdmi->core, &hdmi->wp, conn);
> +}
> +
> +static void hdmi5_bridge_cec_exit(struct drm_bridge *bridge)
> +{
> +     struct omap_hdmi *hdmi = drm_bridge_to_hdmi(bridge);
> +
> +     hdmi5_cec_uninit(&hdmi->core);
> +}
> +
>  static const struct drm_bridge_funcs hdmi5_bridge_funcs = {
>       .attach = hdmi5_bridge_attach,
>       .mode_set = hdmi5_bridge_mode_set,
> @@ -474,14 +514,17 @@ static const struct drm_bridge_funcs hdmi5_bridge_funcs 
> = {
>       .atomic_reset = drm_atomic_helper_bridge_reset,
>       .atomic_enable = hdmi5_bridge_enable,
>       .atomic_disable = hdmi5_bridge_disable,
> +     .hpd_notify = hdmi5_bridge_hpd_notify,
>       .get_edid = hdmi5_bridge_get_edid,
> +     .cec_init = hdmi5_bridge_cec_init,
> +     .cec_exit = hdmi5_bridge_cec_exit,
>  };
>  
>  static void hdmi5_bridge_init(struct omap_hdmi *hdmi)
>  {
>       hdmi->bridge.funcs = &hdmi5_bridge_funcs;
>       hdmi->bridge.of_node = hdmi->pdev->dev.of_node;
> -     hdmi->bridge.ops = DRM_BRIDGE_OP_EDID;
> +     hdmi->bridge.ops = DRM_BRIDGE_OP_EDID | DRM_BRIDGE_OP_CEC;
>       hdmi->bridge.type = DRM_MODE_CONNECTOR_HDMIA;
>  
>       drm_bridge_add(&hdmi->bridge);
> diff --git a/drivers/gpu/drm/omapdrm/dss/hdmi5_cec.c 
> b/drivers/gpu/drm/omapdrm/dss/hdmi5_cec.c
> new file mode 100644
> index 000000000000..26ef8f585b8d
> --- /dev/null
> +++ b/drivers/gpu/drm/omapdrm/dss/hdmi5_cec.c
> @@ -0,0 +1,201 @@
> +// SPDX-License-Identifier: GPL-2.0-only
> +/*
> + * HDMI CEC
> + *
> + * Copyright 2019 Cisco Systems, Inc. and/or its affiliates. All rights 
> reserved.
> + */
> +#include <linux/interrupt.h>
> +#include <linux/io.h>
> +#include <linux/module.h>
> +#include <linux/platform_device.h>
> +#include <linux/sched.h>
> +#include <linux/slab.h>
> +#include <linux/clk.h>
> +
> +#include "dss.h"
> +#include "hdmi.h"
> +#include "hdmi5_core.h"
> +#include "hdmi5_cec.h"
> +
> +static int hdmi5_cec_log_addr(struct cec_adapter *adap, u8 logical_addr)
> +{
> +     struct hdmi_core_data *core = cec_get_drvdata(adap);
> +     u8 v;
> +
> +     if (logical_addr == CEC_LOG_ADDR_INVALID) {
> +             hdmi_write_reg(core->base, HDMI_CORE_CEC_ADDR_L, 0);
> +             hdmi_write_reg(core->base, HDMI_CORE_CEC_ADDR_H, 0);

Empty line here

> +             return 0;
> +     }
> +
> +     if (logical_addr <= 7) {
> +             v = hdmi_read_reg(core->base, HDMI_CORE_CEC_ADDR_L);
> +             v |= 1 << logical_addr;
> +             hdmi_write_reg(core->base, HDMI_CORE_CEC_ADDR_L, v);
> +             v = hdmi_read_reg(core->base, HDMI_CORE_CEC_ADDR_H);
> +             v |= 1 << 7;
> +             hdmi_write_reg(core->base, HDMI_CORE_CEC_ADDR_H, v);
> +     } else {
> +             v = hdmi_read_reg(core->base, HDMI_CORE_CEC_ADDR_H);
> +             v |= 1 << (logical_addr - 8);
> +             v |= 1 << 7;
> +             hdmi_write_reg(core->base, HDMI_CORE_CEC_ADDR_H, v);
> +     }
> +
> +     return 0;
> +}
> +
> +static int hdmi5_cec_transmit(struct cec_adapter *adap, u8 attempts,
> +                           u32 signal_free_time, struct cec_msg *msg)
> +{
> +     struct hdmi_core_data *core = cec_get_drvdata(adap);
> +     unsigned int i, ctrl;
> +
> +     switch (signal_free_time) {
> +     case CEC_SIGNAL_FREE_TIME_RETRY:
> +             ctrl = CEC_CTRL_RETRY;
> +             break;
> +     case CEC_SIGNAL_FREE_TIME_NEW_INITIATOR:
> +     default:
> +             ctrl = CEC_CTRL_NORMAL;
> +             break;
> +     case CEC_SIGNAL_FREE_TIME_NEXT_XFER:
> +             ctrl = CEC_CTRL_IMMED;
> +             break;
> +     }
> +
> +     for (i = 0; i < msg->len; i++)
> +             hdmi_write_reg(core->base,
> +                            HDMI_CORE_CEC_TX_DATA0 + i * 4, msg->msg[i]);
> +
> +     hdmi_write_reg(core->base, HDMI_CORE_CEC_TX_CNT, msg->len);
> +     hdmi_write_reg(core->base, HDMI_CORE_CEC_CTRL,
> +                    ctrl | CEC_CTRL_START);
> +
> +     return 0;
> +}
> +
> +void hdmi5_cec_irq(struct hdmi_core_data *core)
> +{
> +     struct cec_adapter *adap = core->adap;
> +     unsigned int stat = hdmi_read_reg(core->base, HDMI_CORE_IH_CEC_STAT0);
> +
> +     if (stat == 0)
> +             return;
> +
> +     hdmi_write_reg(core->base, HDMI_CORE_IH_CEC_STAT0, stat);
> +
> +     if (stat & CEC_STAT_ERROR_INIT)
> +             cec_transmit_attempt_done(adap, CEC_TX_STATUS_ERROR);
> +     else if (stat & CEC_STAT_DONE)
> +             cec_transmit_attempt_done(adap, CEC_TX_STATUS_OK);
> +     else if (stat & CEC_STAT_NACK)
> +             cec_transmit_attempt_done(adap, CEC_TX_STATUS_NACK);
> +
> +     if (stat & CEC_STAT_EOM) {
> +             struct cec_msg msg = {};
> +             unsigned int len, i;
> +
> +             len = hdmi_read_reg(core->base, HDMI_CORE_CEC_RX_CNT);
> +             if (len > sizeof(msg.msg))
> +                     len = sizeof(msg.msg);
> +
> +             for (i = 0; i < len; i++)
> +                     msg.msg[i] =
> +                             hdmi_read_reg(core->base,
> +                                           HDMI_CORE_CEC_RX_DATA0 + i * 4);
> +
> +             hdmi_write_reg(core->base, HDMI_CORE_CEC_LOCK, 0);
> +
> +             msg.len = len;
> +             cec_received_msg(adap, &msg);
> +     }
> +}
> +
> +static int hdmi5_cec_enable(struct cec_adapter *adap, bool enable)
> +{
> +     struct hdmi_core_data *core = cec_get_drvdata(adap);
> +     struct omap_hdmi *hdmi = container_of(core, struct omap_hdmi, core);
> +     unsigned int irqs;
> +     int err;
> +
> +     if (!enable) {
> +             hdmi_write_reg(core->base, HDMI_CORE_CEC_MASK, ~0);
> +             hdmi_write_reg(core->base, HDMI_CORE_IH_MUTE_CEC_STAT0, ~0);
> +             hdmi_wp_clear_irqenable(core->wp, HDMI_IRQ_CORE);
> +             hdmi_wp_set_irqstatus(core->wp, HDMI_IRQ_CORE);
> +             REG_FLD_MOD(core->base, HDMI_CORE_MC_CLKDIS, 0x01, 5, 5);
> +             hdmi5_core_disable(hdmi);

Empty line.

> +             return 0;
> +     }

And here.

> +     err = hdmi5_core_enable(hdmi);
> +     if (err)
> +             return err;
> +
> +     REG_FLD_MOD(core->base, HDMI_CORE_MC_CLKDIS, 0x00, 5, 5);
> +     hdmi_write_reg(core->base, HDMI_CORE_IH_I2CM_STAT0, ~0);
> +     hdmi_write_reg(core->base, HDMI_CORE_IH_MUTE_I2CM_STAT0, ~0);
> +     hdmi_write_reg(core->base, HDMI_CORE_CEC_CTRL, 0);
> +     hdmi_write_reg(core->base, HDMI_CORE_IH_CEC_STAT0, ~0);
> +     hdmi_write_reg(core->base, HDMI_CORE_CEC_LOCK, 0);
> +     hdmi_write_reg(core->base, HDMI_CORE_CEC_TX_CNT, 0);
> +
> +     hdmi5_cec_log_addr(adap, CEC_LOG_ADDR_INVALID);
> +
> +     /* Enable HDMI core interrupts */
> +     hdmi_wp_set_irqenable(core->wp, HDMI_IRQ_CORE);
> +
> +     irqs = CEC_STAT_ERROR_INIT | CEC_STAT_NACK | CEC_STAT_EOM |
> +            CEC_STAT_DONE;
> +     hdmi_write_reg(core->base, HDMI_CORE_CEC_MASK, ~irqs);
> +     hdmi_write_reg(core->base, HDMI_CORE_IH_MUTE_CEC_STAT0, ~irqs);

Empty line.

> +     return 0;
> +}
> +
> +static const struct cec_adap_ops hdmi5_cec_ops = {
> +     .adap_enable = hdmi5_cec_enable,
> +     .adap_log_addr = hdmi5_cec_log_addr,
> +     .adap_transmit = hdmi5_cec_transmit,
> +};

There's a chance of race with these and the drm originating hdmi code.
hdmi5_core_enable/disable is protected with a mutex, but a few of the
registers are touched without any common lock held. Did you go through
these and ensure there's no race? With some studying, I can't see
anything that might cause issues, so maybe it's fine.

> +void hdmi5_cec_set_phys_addr(struct hdmi_core_data *core, struct edid *edid)
> +{
> +     cec_s_phys_addr_from_edid(core->adap, edid);
> +}
> +
> +int hdmi5_cec_init(struct platform_device *pdev, struct hdmi_core_data *core,
> +                struct hdmi_wp_data *wp, struct drm_connector *conn)
> +{
> +     const u32 caps = CEC_CAP_DEFAULTS | CEC_CAP_CONNECTOR_INFO;
> +     struct cec_connector_info conn_info;
> +     unsigned int ret;
> +
> +     core->cec_clk = devm_clk_get(&pdev->dev, "cec");
> +     if (IS_ERR(core->cec_clk))
> +             return PTR_ERR(core->cec_clk);
> +     ret = clk_prepare_enable(core->cec_clk);
> +     if (ret)
> +             return ret;
> +
> +     core->adap = cec_allocate_adapter(&hdmi5_cec_ops, core,
> +                                       "omap5", caps, CEC_MAX_LOG_ADDRS);
> +     ret = PTR_ERR_OR_ZERO(core->adap);
> +     if (ret < 0)
> +             return ret;

Empty line.

> +     cec_fill_conn_info_from_drm(&conn_info, conn);
> +     cec_s_conn_info(core->adap, &conn_info);
> +     core->wp = wp;
> +
> +     ret = cec_register_adapter(core->adap, &pdev->dev);
> +     if (ret < 0) {
> +             cec_delete_adapter(core->adap);
> +             return ret;
> +     }

Empty line.

> +     return 0;
> +}
> +
> +void hdmi5_cec_uninit(struct hdmi_core_data *core)
> +{
> +     clk_disable_unprepare(core->cec_clk);
> +     cec_unregister_adapter(core->adap);
> +}
> diff --git a/drivers/gpu/drm/omapdrm/dss/hdmi5_cec.h 
> b/drivers/gpu/drm/omapdrm/dss/hdmi5_cec.h
> new file mode 100644
> index 000000000000..904541da46da
> --- /dev/null
> +++ b/drivers/gpu/drm/omapdrm/dss/hdmi5_cec.h
> @@ -0,0 +1,42 @@
> +/* SPDX-License-Identifier: GPL-2.0-only */
> +/*
> + * HDMI header definition for OMAP5 HDMI CEC IP
> + *
> + * Copyright 2019 Cisco Systems, Inc. and/or its affiliates. All rights 
> reserved.
> + */
> +
> +#ifndef _HDMI5_CEC_H_
> +#define _HDMI5_CEC_H_
> +
> +/* HDMI CEC funcs */
> +#ifdef CONFIG_OMAP5_DSS_HDMI_CEC
> +void hdmi5_cec_set_phys_addr(struct hdmi_core_data *core,
> +                          struct edid *edid);
> +void hdmi5_cec_irq(struct hdmi_core_data *core);
> +int hdmi5_cec_init(struct platform_device *pdev, struct hdmi_core_data *core,
> +                struct hdmi_wp_data *wp, struct drm_connector *conn);
> +void hdmi5_cec_uninit(struct hdmi_core_data *core);
> +#else
> +static inline void hdmi5_cec_set_phys_addr(struct hdmi_core_data *core,
> +                                        struct edid *edid)
> +{
> +}
> +
> +static inline void hdmi5_cec_irq(struct hdmi_core_data *core)
> +{
> +}
> +
> +static inline int hdmi5_cec_init(struct platform_device *pdev,
> +                              struct hdmi_core_data *core,
> +                              struct hdmi_wp_data *wp,
> +                              struct drm_connector *conn)
> +{
> +     return 0;
> +}
> +
> +static inline void hdmi5_cec_uninit(struct hdmi_core_data *core)
> +{
> +}
> +#endif
> +
> +#endif
> diff --git a/drivers/gpu/drm/omapdrm/dss/hdmi5_core.c 
> b/drivers/gpu/drm/omapdrm/dss/hdmi5_core.c
> index 6cc2ad7a420c..13bc0f3d850b 100644
> --- a/drivers/gpu/drm/omapdrm/dss/hdmi5_core.c
> +++ b/drivers/gpu/drm/omapdrm/dss/hdmi5_core.c
> @@ -229,6 +229,19 @@ void hdmi5_core_dump(struct hdmi_core_data *core, struct 
> seq_file *s)
>       DUMPCORE(HDMI_CORE_I2CM_FS_SCL_LCNT_1_ADDR);
>       DUMPCORE(HDMI_CORE_I2CM_FS_SCL_LCNT_0_ADDR);
>       DUMPCORE(HDMI_CORE_I2CM_SDA_HOLD_ADDR);
> +
> +     DUMPCORE(HDMI_CORE_IH_CEC_STAT0);
> +     DUMPCORE(HDMI_CORE_IH_MUTE_CEC_STAT0);
> +     DUMPCORE(HDMI_CORE_CEC_CTRL);
> +     DUMPCORE(HDMI_CORE_CEC_MASK);
> +     DUMPCORE(HDMI_CORE_CEC_ADDR_L);
> +     DUMPCORE(HDMI_CORE_CEC_ADDR_H);
> +     DUMPCORE(HDMI_CORE_CEC_TX_CNT);
> +     DUMPCORE(HDMI_CORE_CEC_RX_CNT);
> +     DUMPCORE(HDMI_CORE_CEC_TX_DATA0);
> +     DUMPCORE(HDMI_CORE_CEC_RX_DATA0);
> +     DUMPCORE(HDMI_CORE_CEC_LOCK);
> +     DUMPCORE(HDMI_CORE_CEC_WKUPCTRL);
>  }
>  
>  static void hdmi_core_init(struct hdmi_core_vid_config *video_cfg,
> @@ -513,8 +526,6 @@ static void hdmi_core_mask_interrupts(struct 
> hdmi_core_data *core)
>       REG_FLD_MOD(base, HDMI_CORE_AUD_INT, 0x3, 3, 2);
>       REG_FLD_MOD(base, HDMI_CORE_AUD_GP_MASK, 0x3, 1, 0);
>  
> -     REG_FLD_MOD(base, HDMI_CORE_CEC_MASK, 0x7f, 6, 0);
> -
>       REG_FLD_MOD(base, HDMI_CORE_I2CM_CTLINT, 0x1, 6, 6);
>       REG_FLD_MOD(base, HDMI_CORE_I2CM_CTLINT, 0x1, 2, 2);
>       REG_FLD_MOD(base, HDMI_CORE_I2CM_INT, 0x1, 2, 2);
> @@ -532,8 +543,6 @@ static void hdmi_core_mask_interrupts(struct 
> hdmi_core_data *core)
>  
>       REG_FLD_MOD(base, HDMI_CORE_IH_AS_STAT0, 0x7, 2, 0);
>  
> -     REG_FLD_MOD(base, HDMI_CORE_IH_CEC_STAT0, 0x7f, 6, 0);
> -
>       REG_FLD_MOD(base, HDMI_CORE_IH_I2CM_STAT0, 0x3, 1, 0);
>  
>       REG_FLD_MOD(base, HDMI_CORE_IH_PHY_STAT0, 0xff, 7, 0);
> @@ -549,13 +558,17 @@ int hdmi5_core_handle_irqs(struct hdmi_core_data *core)
>  {
>       void __iomem *base = core->base;
>  
> +     /*
> +      * Clear all possible IRQ_CORE interrupts except for
> +      * HDMI_CORE_IH_I2CM_STAT0 (that interrupt is muted and
> +      * is handled by polling elsewhere) and HDMI_CORE_IH_CEC_STAT0
> +      * which is handled by the CEC code.
> +      */
>       REG_FLD_MOD(base, HDMI_CORE_IH_FC_STAT0, 0xff, 7, 0);
>       REG_FLD_MOD(base, HDMI_CORE_IH_FC_STAT1, 0xff, 7, 0);
>       REG_FLD_MOD(base, HDMI_CORE_IH_FC_STAT2, 0xff, 7, 0);
>       REG_FLD_MOD(base, HDMI_CORE_IH_AS_STAT0, 0xff, 7, 0);
>       REG_FLD_MOD(base, HDMI_CORE_IH_PHY_STAT0, 0xff, 7, 0);
> -     REG_FLD_MOD(base, HDMI_CORE_IH_I2CM_STAT0, 0xff, 7, 0);
> -     REG_FLD_MOD(base, HDMI_CORE_IH_CEC_STAT0, 0xff, 7, 0);
>       REG_FLD_MOD(base, HDMI_CORE_IH_VP_STAT0, 0xff, 7, 0);
>       REG_FLD_MOD(base, HDMI_CORE_IH_I2CMPHY_STAT0, 0xff, 7, 0);
>  
> @@ -879,5 +892,8 @@ int hdmi5_core_init(struct platform_device *pdev, struct 
> hdmi_core_data *core)
>       if (IS_ERR(core->base))
>               return PTR_ERR(core->base);
>  
> +     REG_FLD_MOD(core->base, HDMI_CORE_CEC_MASK, 0x7f, 6, 0);
> +     REG_FLD_MOD(core->base, HDMI_CORE_IH_CEC_STAT0, 0x7f, 6, 0);
> +
>       return 0;
>  }
> diff --git a/drivers/gpu/drm/omapdrm/dss/hdmi5_core.h 
> b/drivers/gpu/drm/omapdrm/dss/hdmi5_core.h
> index 070cbf5fb57d..a83b634f6011 100644
> --- a/drivers/gpu/drm/omapdrm/dss/hdmi5_core.h
> +++ b/drivers/gpu/drm/omapdrm/dss/hdmi5_core.h
> @@ -30,8 +30,18 @@
>  #define HDMI_CORE_IH_PHY_STAT0                       0x00410
>  #define HDMI_CORE_IH_I2CM_STAT0                      0x00414
>  #define HDMI_CORE_IH_CEC_STAT0                       0x00418
> +#define CEC_STAT_DONE                                BIT(0)
> +#define CEC_STAT_EOM                         BIT(1)
> +#define CEC_STAT_NACK                                BIT(2)
> +#define CEC_STAT_ARBLOST                     BIT(3)
> +#define CEC_STAT_ERROR_INIT                  BIT(4)
> +#define CEC_STAT_ERROR_FOLL                  BIT(5)
> +#define CEC_STAT_WAKEUP                              BIT(6)
> +
>  #define HDMI_CORE_IH_VP_STAT0                        0x0041C
>  #define HDMI_CORE_IH_I2CMPHY_STAT0           0x00420
> +#define HDMI_CORE_IH_MUTE_I2CM_STAT0            0x00614
> +#define HDMI_CORE_IH_MUTE_CEC_STAT0          0x00618
>  #define HDMI_CORE_IH_MUTE                    0x007FC
>  
>  /* HDMI Video Sampler */
> @@ -233,9 +243,6 @@
>  /* HDMI HDCP */
>  #define HDMI_CORE_HDCP_MASK                  0x14020
>  
> -/* HDMI CEC */
> -#define HDMI_CORE_CEC_MASK                   0x17408
> -
>  /* HDMI I2C Master */
>  #define HDMI_CORE_I2CM_SLAVE                 0x157C8
>  #define HDMI_CORE_I2CM_ADDRESS                       0x157CC
> @@ -258,6 +265,24 @@
>  #define HDMI_CORE_I2CM_FS_SCL_LCNT_0_ADDR    0x15810
>  #define HDMI_CORE_I2CM_SDA_HOLD_ADDR         0x15814
>  
> +/* HDMI CEC */
> +#define HDMI_CORE_CEC_CTRL                   0x153C8
> +#define CEC_CTRL_START                               BIT(0)
> +#define CEC_CTRL_FRAME_TYP                   (3 << 1)
> +#define CEC_CTRL_RETRY                               (0 << 1)
> +#define CEC_CTRL_NORMAL                              (1 << 1)
> +#define CEC_CTRL_IMMED                               (2 << 1)
> +
> +#define HDMI_CORE_CEC_MASK                   0x153D0
> +#define HDMI_CORE_CEC_ADDR_L                 0x153DC
> +#define HDMI_CORE_CEC_ADDR_H                 0x153E0
> +#define HDMI_CORE_CEC_TX_CNT                 0x153E4
> +#define HDMI_CORE_CEC_RX_CNT                 0x153E8
> +#define HDMI_CORE_CEC_TX_DATA0                       0x15408
> +#define HDMI_CORE_CEC_RX_DATA0                       0x15448
> +#define HDMI_CORE_CEC_LOCK                   0x15488
> +#define HDMI_CORE_CEC_WKUPCTRL                       0x1548C
> +
>  enum hdmi_core_packet_mode {
>       HDMI_PACKETMODERESERVEDVALUE = 0,
>       HDMI_PACKETMODE24BITPERPIXEL = 4,
> @@ -290,6 +315,8 @@ int hdmi5_core_handle_irqs(struct hdmi_core_data *core);
>  void hdmi5_configure(struct hdmi_core_data *core, struct hdmi_wp_data *wp,
>                       struct hdmi_config *cfg);
>  int hdmi5_core_init(struct platform_device *pdev, struct hdmi_core_data 
> *core);
> +int hdmi5_core_enable(struct omap_hdmi *hdmi);
> +void hdmi5_core_disable(struct omap_hdmi *hdmi);
>  
>  int hdmi5_audio_config(struct hdmi_core_data *core, struct hdmi_wp_data *wp,
>                       struct omap_dss_audio *audio, u32 pclk);
> 
_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel

Reply via email to