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-cisco@xs4all.nl Thanks-to: Tomi Valkeinen tomi.valkeinen@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);
if (r) return NULL; }r = hdmi5_core_enable(hdmi);
@@ -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);