* [PATCHv3 0/6] drm/omap: hdmi: improve hdmi4 CEC, add CEC for hdmi5
@ 2021-04-28 13:25 ` Hans Verkuil
0 siblings, 0 replies; 19+ messages in thread
From: Hans Verkuil @ 2021-04-28 13:25 UTC (permalink / raw)
To: linux-media; +Cc: Tomi Valkeinen, Tony Lindgren, Laurent Pinchart, dri-devel
This series improves the drm_bridge support for CEC by introducing two
new bridge ops in the first patch, and using those in the second patch.
This makes it possible to call cec_s_conn_info() and set
CEC_CAP_CONNECTOR_INFO for the CEC adapter, so userspace can associate
the CEC adapter with the corresponding DRM connector.
The third patch simplifies CEC physical address handling by using the
cec_s_phys_addr_from_edid helper function that didn't exist when this
code was originally written.
The fourth patch adds the cec clock to ti,omap5-dss.txt.
The fifth patch the missing cec clock to the dra7 and omap5 device tree,
and the last patch adds CEC support to the OMAP5 driver.
Tested with a Pandaboard and a Beagle X15 board.
Regards,
Hans
Changes since v2:
- connector_attach can now return an error. If an error is
returned then connector_detach is called in reverse order
to clean up any previous connector_attach calls.
- connector_attach in hdmi4 and hdmi5 now return 0.
Changes since v1:
- as per suggestion from Laurent, changed cec_init/exit to
connector_attach/_detach which are just called for all
bridges. The DRM_BRIDGE_OP_CEC was dropped.
- added patch to add the cec clock to ti,omap5-dss.txt
- swapped the order of the last two patches
- incorporated Tomi's suggestions for the hdmi5 CEC support.
Hans Verkuil (6):
drm: drm_bridge: add connector_attach/detach bridge ops
drm/omapdrm/dss/hdmi4: switch to the connector bridge ops
drm/omapdrm/dss/hdmi4: simplify CEC Phys Addr handling
dt-bindings: display: ti: ti,omap5-dss.txt: add cec clock
dra7.dtsi/omap5.dtsi: add cec clock
drm/omapdrm/dss/hdmi5: add CEC support
.../bindings/display/ti/ti,omap5-dss.txt | 4 +-
arch/arm/boot/dts/dra7.dtsi | 5 +-
arch/arm/boot/dts/omap5.dtsi | 5 +-
drivers/gpu/drm/drm_bridge_connector.c | 25 ++-
drivers/gpu/drm/omapdrm/Kconfig | 8 +
drivers/gpu/drm/omapdrm/Makefile | 1 +
drivers/gpu/drm/omapdrm/dss/hdmi.h | 1 +
drivers/gpu/drm/omapdrm/dss/hdmi4.c | 41 ++--
drivers/gpu/drm/omapdrm/dss/hdmi4_cec.c | 13 +-
drivers/gpu/drm/omapdrm/dss/hdmi4_cec.h | 12 +-
drivers/gpu/drm/omapdrm/dss/hdmi5.c | 64 +++++-
drivers/gpu/drm/omapdrm/dss/hdmi5_cec.c | 209 ++++++++++++++++++
drivers/gpu/drm/omapdrm/dss/hdmi5_cec.h | 42 ++++
drivers/gpu/drm/omapdrm/dss/hdmi5_core.c | 35 ++-
drivers/gpu/drm/omapdrm/dss/hdmi5_core.h | 33 ++-
include/drm/drm_bridge.h | 27 +++
16 files changed, 470 insertions(+), 55 deletions(-)
create mode 100644 drivers/gpu/drm/omapdrm/dss/hdmi5_cec.c
create mode 100644 drivers/gpu/drm/omapdrm/dss/hdmi5_cec.h
--
2.30.2
^ permalink raw reply [flat|nested] 19+ messages in thread
* [PATCHv3 0/6] drm/omap: hdmi: improve hdmi4 CEC, add CEC for hdmi5
@ 2021-04-28 13:25 ` Hans Verkuil
0 siblings, 0 replies; 19+ messages in thread
From: Hans Verkuil @ 2021-04-28 13:25 UTC (permalink / raw)
To: linux-media; +Cc: Tony Lindgren, Tomi Valkeinen, Laurent Pinchart, dri-devel
This series improves the drm_bridge support for CEC by introducing two
new bridge ops in the first patch, and using those in the second patch.
This makes it possible to call cec_s_conn_info() and set
CEC_CAP_CONNECTOR_INFO for the CEC adapter, so userspace can associate
the CEC adapter with the corresponding DRM connector.
The third patch simplifies CEC physical address handling by using the
cec_s_phys_addr_from_edid helper function that didn't exist when this
code was originally written.
The fourth patch adds the cec clock to ti,omap5-dss.txt.
The fifth patch the missing cec clock to the dra7 and omap5 device tree,
and the last patch adds CEC support to the OMAP5 driver.
Tested with a Pandaboard and a Beagle X15 board.
Regards,
Hans
Changes since v2:
- connector_attach can now return an error. If an error is
returned then connector_detach is called in reverse order
to clean up any previous connector_attach calls.
- connector_attach in hdmi4 and hdmi5 now return 0.
Changes since v1:
- as per suggestion from Laurent, changed cec_init/exit to
connector_attach/_detach which are just called for all
bridges. The DRM_BRIDGE_OP_CEC was dropped.
- added patch to add the cec clock to ti,omap5-dss.txt
- swapped the order of the last two patches
- incorporated Tomi's suggestions for the hdmi5 CEC support.
Hans Verkuil (6):
drm: drm_bridge: add connector_attach/detach bridge ops
drm/omapdrm/dss/hdmi4: switch to the connector bridge ops
drm/omapdrm/dss/hdmi4: simplify CEC Phys Addr handling
dt-bindings: display: ti: ti,omap5-dss.txt: add cec clock
dra7.dtsi/omap5.dtsi: add cec clock
drm/omapdrm/dss/hdmi5: add CEC support
.../bindings/display/ti/ti,omap5-dss.txt | 4 +-
arch/arm/boot/dts/dra7.dtsi | 5 +-
arch/arm/boot/dts/omap5.dtsi | 5 +-
drivers/gpu/drm/drm_bridge_connector.c | 25 ++-
drivers/gpu/drm/omapdrm/Kconfig | 8 +
drivers/gpu/drm/omapdrm/Makefile | 1 +
drivers/gpu/drm/omapdrm/dss/hdmi.h | 1 +
drivers/gpu/drm/omapdrm/dss/hdmi4.c | 41 ++--
drivers/gpu/drm/omapdrm/dss/hdmi4_cec.c | 13 +-
drivers/gpu/drm/omapdrm/dss/hdmi4_cec.h | 12 +-
drivers/gpu/drm/omapdrm/dss/hdmi5.c | 64 +++++-
drivers/gpu/drm/omapdrm/dss/hdmi5_cec.c | 209 ++++++++++++++++++
drivers/gpu/drm/omapdrm/dss/hdmi5_cec.h | 42 ++++
drivers/gpu/drm/omapdrm/dss/hdmi5_core.c | 35 ++-
drivers/gpu/drm/omapdrm/dss/hdmi5_core.h | 33 ++-
include/drm/drm_bridge.h | 27 +++
16 files changed, 470 insertions(+), 55 deletions(-)
create mode 100644 drivers/gpu/drm/omapdrm/dss/hdmi5_cec.c
create mode 100644 drivers/gpu/drm/omapdrm/dss/hdmi5_cec.h
--
2.30.2
_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel
^ permalink raw reply [flat|nested] 19+ messages in thread
* [PATCHv3 1/6] drm: drm_bridge: add connector_attach/detach bridge ops
2021-04-28 13:25 ` Hans Verkuil
@ 2021-04-28 13:25 ` Hans Verkuil
-1 siblings, 0 replies; 19+ messages in thread
From: Hans Verkuil @ 2021-04-28 13:25 UTC (permalink / raw)
To: linux-media
Cc: Tomi Valkeinen, Tony Lindgren, Laurent Pinchart, dri-devel, Hans Verkuil
Add bridge connector_attach/detach ops. These ops are called when a
bridge is attached or detached to a drm_connector. These ops can be
used to register and unregister an HDMI CEC adapter for a bridge that
supports CEC.
Signed-off-by: Hans Verkuil <hverkuil-cisco@xs4all.nl>
---
drivers/gpu/drm/drm_bridge_connector.c | 25 +++++++++++++++++++++++-
include/drm/drm_bridge.h | 27 ++++++++++++++++++++++++++
2 files changed, 51 insertions(+), 1 deletion(-)
diff --git a/drivers/gpu/drm/drm_bridge_connector.c b/drivers/gpu/drm/drm_bridge_connector.c
index 791379816837..0676677badfe 100644
--- a/drivers/gpu/drm/drm_bridge_connector.c
+++ b/drivers/gpu/drm/drm_bridge_connector.c
@@ -203,6 +203,11 @@ static void drm_bridge_connector_destroy(struct drm_connector *connector)
{
struct drm_bridge_connector *bridge_connector =
to_drm_bridge_connector(connector);
+ struct drm_bridge *bridge;
+
+ drm_for_each_bridge_in_chain(bridge_connector->encoder, bridge)
+ if (bridge->funcs->connector_detach)
+ bridge->funcs->connector_detach(bridge, connector);
if (bridge_connector->bridge_hpd) {
struct drm_bridge *hpd = bridge_connector->bridge_hpd;
@@ -318,6 +323,7 @@ struct drm_connector *drm_bridge_connector_init(struct drm_device *drm,
struct i2c_adapter *ddc = NULL;
struct drm_bridge *bridge;
int connector_type;
+ int ret;
bridge_connector = kzalloc(sizeof(*bridge_connector), GFP_KERNEL);
if (!bridge_connector)
@@ -375,6 +381,23 @@ struct drm_connector *drm_bridge_connector_init(struct drm_device *drm,
connector->polled = DRM_CONNECTOR_POLL_CONNECT
| DRM_CONNECTOR_POLL_DISCONNECT;
- return connector;
+ ret = 0;
+ /* call connector_attach for all bridges */
+ drm_for_each_bridge_in_chain(encoder, bridge) {
+ if (!bridge->funcs->connector_attach)
+ continue;
+ ret = bridge->funcs->connector_attach(bridge, connector);
+ if (ret)
+ break;
+ }
+ if (!ret)
+ return connector;
+
+ /* on error, detach any previously successfully attached connectors */
+ list_for_each_entry_continue_reverse(bridge, &(encoder)->bridge_chain,
+ chain_node)
+ if (bridge->funcs->connector_detach)
+ bridge->funcs->connector_detach(bridge, connector);
+ return ERR_PTR(ret);
}
EXPORT_SYMBOL_GPL(drm_bridge_connector_init);
diff --git a/include/drm/drm_bridge.h b/include/drm/drm_bridge.h
index 2195daa289d2..333fbc3a03e9 100644
--- a/include/drm/drm_bridge.h
+++ b/include/drm/drm_bridge.h
@@ -629,6 +629,33 @@ struct drm_bridge_funcs {
* the DRM_BRIDGE_OP_HPD flag in their &drm_bridge->ops.
*/
void (*hpd_disable)(struct drm_bridge *bridge);
+
+ /**
+ * @connector_attach:
+ *
+ * This callback is invoked whenever our bridge is being attached to a
+ * &drm_connector. This is where an HDMI CEC adapter can be registered.
+ *
+ * The @connector_attach callback is optional.
+ *
+ * RETURNS:
+ *
+ * Zero on success, error code on failure.
+ */
+ int (*connector_attach)(struct drm_bridge *bridge,
+ struct drm_connector *conn);
+
+ /**
+ * @connector_detach:
+ *
+ * This callback is invoked whenever our bridge is being detached from a
+ * &drm_connector. This is where an HDMI CEC adapter can be
+ * unregistered.
+ *
+ * The @connector_detach callback is optional.
+ */
+ void (*connector_detach)(struct drm_bridge *bridge,
+ struct drm_connector *conn);
};
/**
--
2.30.2
^ permalink raw reply related [flat|nested] 19+ messages in thread
* [PATCHv3 1/6] drm: drm_bridge: add connector_attach/detach bridge ops
@ 2021-04-28 13:25 ` Hans Verkuil
0 siblings, 0 replies; 19+ messages in thread
From: Hans Verkuil @ 2021-04-28 13:25 UTC (permalink / raw)
To: linux-media
Cc: Tony Lindgren, Tomi Valkeinen, Laurent Pinchart, dri-devel, Hans Verkuil
Add bridge connector_attach/detach ops. These ops are called when a
bridge is attached or detached to a drm_connector. These ops can be
used to register and unregister an HDMI CEC adapter for a bridge that
supports CEC.
Signed-off-by: Hans Verkuil <hverkuil-cisco@xs4all.nl>
---
drivers/gpu/drm/drm_bridge_connector.c | 25 +++++++++++++++++++++++-
include/drm/drm_bridge.h | 27 ++++++++++++++++++++++++++
2 files changed, 51 insertions(+), 1 deletion(-)
diff --git a/drivers/gpu/drm/drm_bridge_connector.c b/drivers/gpu/drm/drm_bridge_connector.c
index 791379816837..0676677badfe 100644
--- a/drivers/gpu/drm/drm_bridge_connector.c
+++ b/drivers/gpu/drm/drm_bridge_connector.c
@@ -203,6 +203,11 @@ static void drm_bridge_connector_destroy(struct drm_connector *connector)
{
struct drm_bridge_connector *bridge_connector =
to_drm_bridge_connector(connector);
+ struct drm_bridge *bridge;
+
+ drm_for_each_bridge_in_chain(bridge_connector->encoder, bridge)
+ if (bridge->funcs->connector_detach)
+ bridge->funcs->connector_detach(bridge, connector);
if (bridge_connector->bridge_hpd) {
struct drm_bridge *hpd = bridge_connector->bridge_hpd;
@@ -318,6 +323,7 @@ struct drm_connector *drm_bridge_connector_init(struct drm_device *drm,
struct i2c_adapter *ddc = NULL;
struct drm_bridge *bridge;
int connector_type;
+ int ret;
bridge_connector = kzalloc(sizeof(*bridge_connector), GFP_KERNEL);
if (!bridge_connector)
@@ -375,6 +381,23 @@ struct drm_connector *drm_bridge_connector_init(struct drm_device *drm,
connector->polled = DRM_CONNECTOR_POLL_CONNECT
| DRM_CONNECTOR_POLL_DISCONNECT;
- return connector;
+ ret = 0;
+ /* call connector_attach for all bridges */
+ drm_for_each_bridge_in_chain(encoder, bridge) {
+ if (!bridge->funcs->connector_attach)
+ continue;
+ ret = bridge->funcs->connector_attach(bridge, connector);
+ if (ret)
+ break;
+ }
+ if (!ret)
+ return connector;
+
+ /* on error, detach any previously successfully attached connectors */
+ list_for_each_entry_continue_reverse(bridge, &(encoder)->bridge_chain,
+ chain_node)
+ if (bridge->funcs->connector_detach)
+ bridge->funcs->connector_detach(bridge, connector);
+ return ERR_PTR(ret);
}
EXPORT_SYMBOL_GPL(drm_bridge_connector_init);
diff --git a/include/drm/drm_bridge.h b/include/drm/drm_bridge.h
index 2195daa289d2..333fbc3a03e9 100644
--- a/include/drm/drm_bridge.h
+++ b/include/drm/drm_bridge.h
@@ -629,6 +629,33 @@ struct drm_bridge_funcs {
* the DRM_BRIDGE_OP_HPD flag in their &drm_bridge->ops.
*/
void (*hpd_disable)(struct drm_bridge *bridge);
+
+ /**
+ * @connector_attach:
+ *
+ * This callback is invoked whenever our bridge is being attached to a
+ * &drm_connector. This is where an HDMI CEC adapter can be registered.
+ *
+ * The @connector_attach callback is optional.
+ *
+ * RETURNS:
+ *
+ * Zero on success, error code on failure.
+ */
+ int (*connector_attach)(struct drm_bridge *bridge,
+ struct drm_connector *conn);
+
+ /**
+ * @connector_detach:
+ *
+ * This callback is invoked whenever our bridge is being detached from a
+ * &drm_connector. This is where an HDMI CEC adapter can be
+ * unregistered.
+ *
+ * The @connector_detach callback is optional.
+ */
+ void (*connector_detach)(struct drm_bridge *bridge,
+ struct drm_connector *conn);
};
/**
--
2.30.2
_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel
^ permalink raw reply related [flat|nested] 19+ messages in thread
* [PATCHv3 2/6] drm/omapdrm/dss/hdmi4: switch to the connector bridge ops
2021-04-28 13:25 ` Hans Verkuil
@ 2021-04-28 13:25 ` Hans Verkuil
-1 siblings, 0 replies; 19+ messages in thread
From: Hans Verkuil @ 2021-04-28 13:25 UTC (permalink / raw)
To: linux-media
Cc: Tomi Valkeinen, Tony Lindgren, Laurent Pinchart, dri-devel, Hans Verkuil
Implement the new connector_attach/detach bridge ops. This makes it
possible to associate a CEC adapter with a drm connector, which helps
userspace determine which cec device node belongs to which drm connector.
Signed-off-by: Hans Verkuil <hverkuil-cisco@xs4all.nl>
Reviewed-by: Tomi Valkeinen <tomi.valkeinen@ideasonboard.com>
---
drivers/gpu/drm/omapdrm/dss/hdmi4.c | 28 ++++++++++++++++++-------
drivers/gpu/drm/omapdrm/dss/hdmi4_cec.c | 9 +++++---
drivers/gpu/drm/omapdrm/dss/hdmi4_cec.h | 7 ++++---
3 files changed, 30 insertions(+), 14 deletions(-)
diff --git a/drivers/gpu/drm/omapdrm/dss/hdmi4.c b/drivers/gpu/drm/omapdrm/dss/hdmi4.c
index 35b750cebaeb..e29d4d186265 100644
--- a/drivers/gpu/drm/omapdrm/dss/hdmi4.c
+++ b/drivers/gpu/drm/omapdrm/dss/hdmi4.c
@@ -482,6 +482,23 @@ static struct edid *hdmi4_bridge_get_edid(struct drm_bridge *bridge,
return edid;
}
+static int hdmi4_bridge_connector_attach(struct drm_bridge *bridge,
+ struct drm_connector *conn)
+{
+ struct omap_hdmi *hdmi = drm_bridge_to_hdmi(bridge);
+
+ hdmi4_cec_init(hdmi->pdev, &hdmi->core, &hdmi->wp, conn);
+ return 0;
+}
+
+static void hdmi4_bridge_connector_detach(struct drm_bridge *bridge,
+ struct drm_connector *conn)
+{
+ struct omap_hdmi *hdmi = drm_bridge_to_hdmi(bridge);
+
+ hdmi4_cec_uninit(&hdmi->core);
+}
+
static const struct drm_bridge_funcs hdmi4_bridge_funcs = {
.attach = hdmi4_bridge_attach,
.mode_set = hdmi4_bridge_mode_set,
@@ -492,6 +509,8 @@ static const struct drm_bridge_funcs hdmi4_bridge_funcs = {
.atomic_disable = hdmi4_bridge_disable,
.hpd_notify = hdmi4_bridge_hpd_notify,
.get_edid = hdmi4_bridge_get_edid,
+ .connector_attach = hdmi4_bridge_connector_attach,
+ .connector_detach = hdmi4_bridge_connector_detach,
};
static void hdmi4_bridge_init(struct omap_hdmi *hdmi)
@@ -647,14 +666,10 @@ static int hdmi4_bind(struct device *dev, struct device *master, void *data)
if (r)
goto err_runtime_put;
- r = hdmi4_cec_init(hdmi->pdev, &hdmi->core, &hdmi->wp);
- if (r)
- goto err_pll_uninit;
-
r = hdmi_audio_register(hdmi);
if (r) {
DSSERR("Registering HDMI audio failed\n");
- goto err_cec_uninit;
+ goto err_pll_uninit;
}
hdmi->debugfs = dss_debugfs_create_file(dss, "hdmi", hdmi_dump_regs,
@@ -664,8 +679,6 @@ static int hdmi4_bind(struct device *dev, struct device *master, void *data)
return 0;
-err_cec_uninit:
- hdmi4_cec_uninit(&hdmi->core);
err_pll_uninit:
hdmi_pll_uninit(&hdmi->pll);
err_runtime_put:
@@ -682,7 +695,6 @@ static void hdmi4_unbind(struct device *dev, struct device *master, void *data)
if (hdmi->audio_pdev)
platform_device_unregister(hdmi->audio_pdev);
- hdmi4_cec_uninit(&hdmi->core);
hdmi_pll_uninit(&hdmi->pll);
}
diff --git a/drivers/gpu/drm/omapdrm/dss/hdmi4_cec.c b/drivers/gpu/drm/omapdrm/dss/hdmi4_cec.c
index 43592c1cf081..80ec52c9c846 100644
--- a/drivers/gpu/drm/omapdrm/dss/hdmi4_cec.c
+++ b/drivers/gpu/drm/omapdrm/dss/hdmi4_cec.c
@@ -335,10 +335,10 @@ void hdmi4_cec_set_phys_addr(struct hdmi_core_data *core, u16 pa)
}
int hdmi4_cec_init(struct platform_device *pdev, struct hdmi_core_data *core,
- struct hdmi_wp_data *wp)
+ struct hdmi_wp_data *wp, struct drm_connector *conn)
{
- const u32 caps = CEC_CAP_TRANSMIT | CEC_CAP_LOG_ADDRS |
- CEC_CAP_PASSTHROUGH | CEC_CAP_RC;
+ const u32 caps = CEC_CAP_DEFAULTS | CEC_CAP_CONNECTOR_INFO;
+ struct cec_connector_info conn_info;
int ret;
core->adap = cec_allocate_adapter(&hdmi_cec_adap_ops, core,
@@ -346,6 +346,8 @@ int hdmi4_cec_init(struct platform_device *pdev, struct hdmi_core_data *core,
ret = PTR_ERR_OR_ZERO(core->adap);
if (ret < 0)
return ret;
+ cec_fill_conn_info_from_drm(&conn_info, conn);
+ cec_s_conn_info(core->adap, &conn_info);
core->wp = wp;
/* Disable clock initially, hdmi_cec_adap_enable() manages it */
@@ -354,6 +356,7 @@ int hdmi4_cec_init(struct platform_device *pdev, struct hdmi_core_data *core,
ret = cec_register_adapter(core->adap, &pdev->dev);
if (ret < 0) {
cec_delete_adapter(core->adap);
+ core->adap = NULL;
return ret;
}
return 0;
diff --git a/drivers/gpu/drm/omapdrm/dss/hdmi4_cec.h b/drivers/gpu/drm/omapdrm/dss/hdmi4_cec.h
index 0292337c97cc..b59a54c3040e 100644
--- a/drivers/gpu/drm/omapdrm/dss/hdmi4_cec.h
+++ b/drivers/gpu/drm/omapdrm/dss/hdmi4_cec.h
@@ -29,7 +29,7 @@ struct platform_device;
void hdmi4_cec_set_phys_addr(struct hdmi_core_data *core, u16 pa);
void hdmi4_cec_irq(struct hdmi_core_data *core);
int hdmi4_cec_init(struct platform_device *pdev, struct hdmi_core_data *core,
- struct hdmi_wp_data *wp);
+ struct hdmi_wp_data *wp, struct drm_connector *conn);
void hdmi4_cec_uninit(struct hdmi_core_data *core);
#else
static inline void hdmi4_cec_set_phys_addr(struct hdmi_core_data *core, u16 pa)
@@ -41,8 +41,9 @@ static inline void hdmi4_cec_irq(struct hdmi_core_data *core)
}
static inline int hdmi4_cec_init(struct platform_device *pdev,
- struct hdmi_core_data *core,
- struct hdmi_wp_data *wp)
+ struct hdmi_core_data *core,
+ struct hdmi_wp_data *wp,
+ struct drm_connector *conn)
{
return 0;
}
--
2.30.2
^ permalink raw reply related [flat|nested] 19+ messages in thread
* [PATCHv3 2/6] drm/omapdrm/dss/hdmi4: switch to the connector bridge ops
@ 2021-04-28 13:25 ` Hans Verkuil
0 siblings, 0 replies; 19+ messages in thread
From: Hans Verkuil @ 2021-04-28 13:25 UTC (permalink / raw)
To: linux-media
Cc: Tony Lindgren, Tomi Valkeinen, Laurent Pinchart, dri-devel, Hans Verkuil
Implement the new connector_attach/detach bridge ops. This makes it
possible to associate a CEC adapter with a drm connector, which helps
userspace determine which cec device node belongs to which drm connector.
Signed-off-by: Hans Verkuil <hverkuil-cisco@xs4all.nl>
Reviewed-by: Tomi Valkeinen <tomi.valkeinen@ideasonboard.com>
---
drivers/gpu/drm/omapdrm/dss/hdmi4.c | 28 ++++++++++++++++++-------
drivers/gpu/drm/omapdrm/dss/hdmi4_cec.c | 9 +++++---
drivers/gpu/drm/omapdrm/dss/hdmi4_cec.h | 7 ++++---
3 files changed, 30 insertions(+), 14 deletions(-)
diff --git a/drivers/gpu/drm/omapdrm/dss/hdmi4.c b/drivers/gpu/drm/omapdrm/dss/hdmi4.c
index 35b750cebaeb..e29d4d186265 100644
--- a/drivers/gpu/drm/omapdrm/dss/hdmi4.c
+++ b/drivers/gpu/drm/omapdrm/dss/hdmi4.c
@@ -482,6 +482,23 @@ static struct edid *hdmi4_bridge_get_edid(struct drm_bridge *bridge,
return edid;
}
+static int hdmi4_bridge_connector_attach(struct drm_bridge *bridge,
+ struct drm_connector *conn)
+{
+ struct omap_hdmi *hdmi = drm_bridge_to_hdmi(bridge);
+
+ hdmi4_cec_init(hdmi->pdev, &hdmi->core, &hdmi->wp, conn);
+ return 0;
+}
+
+static void hdmi4_bridge_connector_detach(struct drm_bridge *bridge,
+ struct drm_connector *conn)
+{
+ struct omap_hdmi *hdmi = drm_bridge_to_hdmi(bridge);
+
+ hdmi4_cec_uninit(&hdmi->core);
+}
+
static const struct drm_bridge_funcs hdmi4_bridge_funcs = {
.attach = hdmi4_bridge_attach,
.mode_set = hdmi4_bridge_mode_set,
@@ -492,6 +509,8 @@ static const struct drm_bridge_funcs hdmi4_bridge_funcs = {
.atomic_disable = hdmi4_bridge_disable,
.hpd_notify = hdmi4_bridge_hpd_notify,
.get_edid = hdmi4_bridge_get_edid,
+ .connector_attach = hdmi4_bridge_connector_attach,
+ .connector_detach = hdmi4_bridge_connector_detach,
};
static void hdmi4_bridge_init(struct omap_hdmi *hdmi)
@@ -647,14 +666,10 @@ static int hdmi4_bind(struct device *dev, struct device *master, void *data)
if (r)
goto err_runtime_put;
- r = hdmi4_cec_init(hdmi->pdev, &hdmi->core, &hdmi->wp);
- if (r)
- goto err_pll_uninit;
-
r = hdmi_audio_register(hdmi);
if (r) {
DSSERR("Registering HDMI audio failed\n");
- goto err_cec_uninit;
+ goto err_pll_uninit;
}
hdmi->debugfs = dss_debugfs_create_file(dss, "hdmi", hdmi_dump_regs,
@@ -664,8 +679,6 @@ static int hdmi4_bind(struct device *dev, struct device *master, void *data)
return 0;
-err_cec_uninit:
- hdmi4_cec_uninit(&hdmi->core);
err_pll_uninit:
hdmi_pll_uninit(&hdmi->pll);
err_runtime_put:
@@ -682,7 +695,6 @@ static void hdmi4_unbind(struct device *dev, struct device *master, void *data)
if (hdmi->audio_pdev)
platform_device_unregister(hdmi->audio_pdev);
- hdmi4_cec_uninit(&hdmi->core);
hdmi_pll_uninit(&hdmi->pll);
}
diff --git a/drivers/gpu/drm/omapdrm/dss/hdmi4_cec.c b/drivers/gpu/drm/omapdrm/dss/hdmi4_cec.c
index 43592c1cf081..80ec52c9c846 100644
--- a/drivers/gpu/drm/omapdrm/dss/hdmi4_cec.c
+++ b/drivers/gpu/drm/omapdrm/dss/hdmi4_cec.c
@@ -335,10 +335,10 @@ void hdmi4_cec_set_phys_addr(struct hdmi_core_data *core, u16 pa)
}
int hdmi4_cec_init(struct platform_device *pdev, struct hdmi_core_data *core,
- struct hdmi_wp_data *wp)
+ struct hdmi_wp_data *wp, struct drm_connector *conn)
{
- const u32 caps = CEC_CAP_TRANSMIT | CEC_CAP_LOG_ADDRS |
- CEC_CAP_PASSTHROUGH | CEC_CAP_RC;
+ const u32 caps = CEC_CAP_DEFAULTS | CEC_CAP_CONNECTOR_INFO;
+ struct cec_connector_info conn_info;
int ret;
core->adap = cec_allocate_adapter(&hdmi_cec_adap_ops, core,
@@ -346,6 +346,8 @@ int hdmi4_cec_init(struct platform_device *pdev, struct hdmi_core_data *core,
ret = PTR_ERR_OR_ZERO(core->adap);
if (ret < 0)
return ret;
+ cec_fill_conn_info_from_drm(&conn_info, conn);
+ cec_s_conn_info(core->adap, &conn_info);
core->wp = wp;
/* Disable clock initially, hdmi_cec_adap_enable() manages it */
@@ -354,6 +356,7 @@ int hdmi4_cec_init(struct platform_device *pdev, struct hdmi_core_data *core,
ret = cec_register_adapter(core->adap, &pdev->dev);
if (ret < 0) {
cec_delete_adapter(core->adap);
+ core->adap = NULL;
return ret;
}
return 0;
diff --git a/drivers/gpu/drm/omapdrm/dss/hdmi4_cec.h b/drivers/gpu/drm/omapdrm/dss/hdmi4_cec.h
index 0292337c97cc..b59a54c3040e 100644
--- a/drivers/gpu/drm/omapdrm/dss/hdmi4_cec.h
+++ b/drivers/gpu/drm/omapdrm/dss/hdmi4_cec.h
@@ -29,7 +29,7 @@ struct platform_device;
void hdmi4_cec_set_phys_addr(struct hdmi_core_data *core, u16 pa);
void hdmi4_cec_irq(struct hdmi_core_data *core);
int hdmi4_cec_init(struct platform_device *pdev, struct hdmi_core_data *core,
- struct hdmi_wp_data *wp);
+ struct hdmi_wp_data *wp, struct drm_connector *conn);
void hdmi4_cec_uninit(struct hdmi_core_data *core);
#else
static inline void hdmi4_cec_set_phys_addr(struct hdmi_core_data *core, u16 pa)
@@ -41,8 +41,9 @@ static inline void hdmi4_cec_irq(struct hdmi_core_data *core)
}
static inline int hdmi4_cec_init(struct platform_device *pdev,
- struct hdmi_core_data *core,
- struct hdmi_wp_data *wp)
+ struct hdmi_core_data *core,
+ struct hdmi_wp_data *wp,
+ struct drm_connector *conn)
{
return 0;
}
--
2.30.2
_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel
^ permalink raw reply related [flat|nested] 19+ messages in thread
* [PATCHv3 3/6] drm/omapdrm/dss/hdmi4: simplify CEC Phys Addr handling
2021-04-28 13:25 ` Hans Verkuil
@ 2021-04-28 13:25 ` Hans Verkuil
-1 siblings, 0 replies; 19+ messages in thread
From: Hans Verkuil @ 2021-04-28 13:25 UTC (permalink / raw)
To: linux-media
Cc: Tomi Valkeinen, Tony Lindgren, Laurent Pinchart, dri-devel, Hans Verkuil
Switch to using cec_s_phys_addr_from_edid() instead of a two-step process
of calling cec_get_edid_phys_addr() followed by cec_s_phys_addr().
Signed-off-by: Hans Verkuil <hverkuil-cisco@xs4all.nl>
Reviewed-by: Tomi Valkeinen <tomi.valkeinen@ideasonboard.com>
---
drivers/gpu/drm/omapdrm/dss/hdmi4.c | 13 ++-----------
drivers/gpu/drm/omapdrm/dss/hdmi4_cec.c | 4 ++--
drivers/gpu/drm/omapdrm/dss/hdmi4_cec.h | 5 +++--
3 files changed, 7 insertions(+), 15 deletions(-)
diff --git a/drivers/gpu/drm/omapdrm/dss/hdmi4.c b/drivers/gpu/drm/omapdrm/dss/hdmi4.c
index e29d4d186265..40f791c668f4 100644
--- a/drivers/gpu/drm/omapdrm/dss/hdmi4.c
+++ b/drivers/gpu/drm/omapdrm/dss/hdmi4.c
@@ -432,7 +432,7 @@ static void hdmi4_bridge_hpd_notify(struct drm_bridge *bridge,
struct omap_hdmi *hdmi = drm_bridge_to_hdmi(bridge);
if (status == connector_status_disconnected)
- hdmi4_cec_set_phys_addr(&hdmi->core, CEC_PHYS_ADDR_INVALID);
+ hdmi4_cec_set_phys_addr(&hdmi->core, NULL);
}
static struct edid *hdmi4_bridge_get_edid(struct drm_bridge *bridge,
@@ -440,7 +440,6 @@ static struct edid *hdmi4_bridge_get_edid(struct drm_bridge *bridge,
{
struct omap_hdmi *hdmi = drm_bridge_to_hdmi(bridge);
struct edid *edid = NULL;
- unsigned int cec_addr;
bool need_enable;
int r;
@@ -466,15 +465,7 @@ static struct edid *hdmi4_bridge_get_edid(struct drm_bridge *bridge,
hdmi_runtime_put(hdmi);
mutex_unlock(&hdmi->lock);
- if (edid && edid->extensions) {
- unsigned int len = (edid->extensions + 1) * EDID_LENGTH;
-
- cec_addr = cec_get_edid_phys_addr((u8 *)edid, len, NULL);
- } else {
- cec_addr = CEC_PHYS_ADDR_INVALID;
- }
-
- hdmi4_cec_set_phys_addr(&hdmi->core, cec_addr);
+ hdmi4_cec_set_phys_addr(&hdmi->core, edid);
if (need_enable)
hdmi4_core_disable(&hdmi->core);
diff --git a/drivers/gpu/drm/omapdrm/dss/hdmi4_cec.c b/drivers/gpu/drm/omapdrm/dss/hdmi4_cec.c
index 80ec52c9c846..cf406d86c845 100644
--- a/drivers/gpu/drm/omapdrm/dss/hdmi4_cec.c
+++ b/drivers/gpu/drm/omapdrm/dss/hdmi4_cec.c
@@ -329,9 +329,9 @@ static const struct cec_adap_ops hdmi_cec_adap_ops = {
.adap_transmit = hdmi_cec_adap_transmit,
};
-void hdmi4_cec_set_phys_addr(struct hdmi_core_data *core, u16 pa)
+void hdmi4_cec_set_phys_addr(struct hdmi_core_data *core, struct edid *edid)
{
- cec_s_phys_addr(core->adap, pa, false);
+ cec_s_phys_addr_from_edid(core->adap, edid);
}
int hdmi4_cec_init(struct platform_device *pdev, struct hdmi_core_data *core,
diff --git a/drivers/gpu/drm/omapdrm/dss/hdmi4_cec.h b/drivers/gpu/drm/omapdrm/dss/hdmi4_cec.h
index b59a54c3040e..16bf259643b7 100644
--- a/drivers/gpu/drm/omapdrm/dss/hdmi4_cec.h
+++ b/drivers/gpu/drm/omapdrm/dss/hdmi4_cec.h
@@ -26,13 +26,14 @@ struct platform_device;
/* HDMI CEC funcs */
#ifdef CONFIG_OMAP4_DSS_HDMI_CEC
-void hdmi4_cec_set_phys_addr(struct hdmi_core_data *core, u16 pa);
+void hdmi4_cec_set_phys_addr(struct hdmi_core_data *core, struct edid *edid);
void hdmi4_cec_irq(struct hdmi_core_data *core);
int hdmi4_cec_init(struct platform_device *pdev, struct hdmi_core_data *core,
struct hdmi_wp_data *wp, struct drm_connector *conn);
void hdmi4_cec_uninit(struct hdmi_core_data *core);
#else
-static inline void hdmi4_cec_set_phys_addr(struct hdmi_core_data *core, u16 pa)
+static inline void hdmi4_cec_set_phys_addr(struct hdmi_core_data *core,
+ struct edid *edid)
{
}
--
2.30.2
^ permalink raw reply related [flat|nested] 19+ messages in thread
* [PATCHv3 3/6] drm/omapdrm/dss/hdmi4: simplify CEC Phys Addr handling
@ 2021-04-28 13:25 ` Hans Verkuil
0 siblings, 0 replies; 19+ messages in thread
From: Hans Verkuil @ 2021-04-28 13:25 UTC (permalink / raw)
To: linux-media
Cc: Tony Lindgren, Tomi Valkeinen, Laurent Pinchart, dri-devel, Hans Verkuil
Switch to using cec_s_phys_addr_from_edid() instead of a two-step process
of calling cec_get_edid_phys_addr() followed by cec_s_phys_addr().
Signed-off-by: Hans Verkuil <hverkuil-cisco@xs4all.nl>
Reviewed-by: Tomi Valkeinen <tomi.valkeinen@ideasonboard.com>
---
drivers/gpu/drm/omapdrm/dss/hdmi4.c | 13 ++-----------
drivers/gpu/drm/omapdrm/dss/hdmi4_cec.c | 4 ++--
drivers/gpu/drm/omapdrm/dss/hdmi4_cec.h | 5 +++--
3 files changed, 7 insertions(+), 15 deletions(-)
diff --git a/drivers/gpu/drm/omapdrm/dss/hdmi4.c b/drivers/gpu/drm/omapdrm/dss/hdmi4.c
index e29d4d186265..40f791c668f4 100644
--- a/drivers/gpu/drm/omapdrm/dss/hdmi4.c
+++ b/drivers/gpu/drm/omapdrm/dss/hdmi4.c
@@ -432,7 +432,7 @@ static void hdmi4_bridge_hpd_notify(struct drm_bridge *bridge,
struct omap_hdmi *hdmi = drm_bridge_to_hdmi(bridge);
if (status == connector_status_disconnected)
- hdmi4_cec_set_phys_addr(&hdmi->core, CEC_PHYS_ADDR_INVALID);
+ hdmi4_cec_set_phys_addr(&hdmi->core, NULL);
}
static struct edid *hdmi4_bridge_get_edid(struct drm_bridge *bridge,
@@ -440,7 +440,6 @@ static struct edid *hdmi4_bridge_get_edid(struct drm_bridge *bridge,
{
struct omap_hdmi *hdmi = drm_bridge_to_hdmi(bridge);
struct edid *edid = NULL;
- unsigned int cec_addr;
bool need_enable;
int r;
@@ -466,15 +465,7 @@ static struct edid *hdmi4_bridge_get_edid(struct drm_bridge *bridge,
hdmi_runtime_put(hdmi);
mutex_unlock(&hdmi->lock);
- if (edid && edid->extensions) {
- unsigned int len = (edid->extensions + 1) * EDID_LENGTH;
-
- cec_addr = cec_get_edid_phys_addr((u8 *)edid, len, NULL);
- } else {
- cec_addr = CEC_PHYS_ADDR_INVALID;
- }
-
- hdmi4_cec_set_phys_addr(&hdmi->core, cec_addr);
+ hdmi4_cec_set_phys_addr(&hdmi->core, edid);
if (need_enable)
hdmi4_core_disable(&hdmi->core);
diff --git a/drivers/gpu/drm/omapdrm/dss/hdmi4_cec.c b/drivers/gpu/drm/omapdrm/dss/hdmi4_cec.c
index 80ec52c9c846..cf406d86c845 100644
--- a/drivers/gpu/drm/omapdrm/dss/hdmi4_cec.c
+++ b/drivers/gpu/drm/omapdrm/dss/hdmi4_cec.c
@@ -329,9 +329,9 @@ static const struct cec_adap_ops hdmi_cec_adap_ops = {
.adap_transmit = hdmi_cec_adap_transmit,
};
-void hdmi4_cec_set_phys_addr(struct hdmi_core_data *core, u16 pa)
+void hdmi4_cec_set_phys_addr(struct hdmi_core_data *core, struct edid *edid)
{
- cec_s_phys_addr(core->adap, pa, false);
+ cec_s_phys_addr_from_edid(core->adap, edid);
}
int hdmi4_cec_init(struct platform_device *pdev, struct hdmi_core_data *core,
diff --git a/drivers/gpu/drm/omapdrm/dss/hdmi4_cec.h b/drivers/gpu/drm/omapdrm/dss/hdmi4_cec.h
index b59a54c3040e..16bf259643b7 100644
--- a/drivers/gpu/drm/omapdrm/dss/hdmi4_cec.h
+++ b/drivers/gpu/drm/omapdrm/dss/hdmi4_cec.h
@@ -26,13 +26,14 @@ struct platform_device;
/* HDMI CEC funcs */
#ifdef CONFIG_OMAP4_DSS_HDMI_CEC
-void hdmi4_cec_set_phys_addr(struct hdmi_core_data *core, u16 pa);
+void hdmi4_cec_set_phys_addr(struct hdmi_core_data *core, struct edid *edid);
void hdmi4_cec_irq(struct hdmi_core_data *core);
int hdmi4_cec_init(struct platform_device *pdev, struct hdmi_core_data *core,
struct hdmi_wp_data *wp, struct drm_connector *conn);
void hdmi4_cec_uninit(struct hdmi_core_data *core);
#else
-static inline void hdmi4_cec_set_phys_addr(struct hdmi_core_data *core, u16 pa)
+static inline void hdmi4_cec_set_phys_addr(struct hdmi_core_data *core,
+ struct edid *edid)
{
}
--
2.30.2
_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel
^ permalink raw reply related [flat|nested] 19+ messages in thread
* [PATCHv3 4/6] dt-bindings: display: ti: ti,omap5-dss.txt: add cec clock
2021-04-28 13:25 ` Hans Verkuil
@ 2021-04-28 13:25 ` Hans Verkuil
-1 siblings, 0 replies; 19+ messages in thread
From: Hans Verkuil @ 2021-04-28 13:25 UTC (permalink / raw)
To: linux-media
Cc: Tomi Valkeinen, Tony Lindgren, Laurent Pinchart, dri-devel,
Hans Verkuil, Rob Herring
The cec clock is required as well in order to support HDMI CEC,
document this.
Signed-off-by: Hans Verkuil <hverkuil-cisco@xs4all.nl>
Reviewed-by: Tomi Valkeinen <tomi.valkeinen@ideasonboard.com>
Acked-by: Rob Herring <robh@kernel.org>
---
Documentation/devicetree/bindings/display/ti/ti,omap5-dss.txt | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/Documentation/devicetree/bindings/display/ti/ti,omap5-dss.txt b/Documentation/devicetree/bindings/display/ti/ti,omap5-dss.txt
index 20861218649f..c321c67472f0 100644
--- a/Documentation/devicetree/bindings/display/ti/ti,omap5-dss.txt
+++ b/Documentation/devicetree/bindings/display/ti/ti,omap5-dss.txt
@@ -89,8 +89,8 @@ Required properties:
- interrupts: the HDMI interrupt line
- ti,hwmods: "dss_hdmi"
- vdda-supply: vdda power supply
-- clocks: handles to fclk and pll clock
-- clock-names: "fck", "sys_clk"
+- clocks: handles to fclk, pll and cec clock
+- clock-names: "fck", "sys_clk", "cec"
Optional nodes:
- Video port for HDMI output
--
2.30.2
^ permalink raw reply related [flat|nested] 19+ messages in thread
* [PATCHv3 4/6] dt-bindings: display: ti: ti, omap5-dss.txt: add cec clock
@ 2021-04-28 13:25 ` Hans Verkuil
0 siblings, 0 replies; 19+ messages in thread
From: Hans Verkuil @ 2021-04-28 13:25 UTC (permalink / raw)
To: linux-media
Cc: Tony Lindgren, Tomi Valkeinen, dri-devel, Laurent Pinchart, Hans Verkuil
The cec clock is required as well in order to support HDMI CEC,
document this.
Signed-off-by: Hans Verkuil <hverkuil-cisco@xs4all.nl>
Reviewed-by: Tomi Valkeinen <tomi.valkeinen@ideasonboard.com>
Acked-by: Rob Herring <robh@kernel.org>
---
Documentation/devicetree/bindings/display/ti/ti,omap5-dss.txt | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/Documentation/devicetree/bindings/display/ti/ti,omap5-dss.txt b/Documentation/devicetree/bindings/display/ti/ti,omap5-dss.txt
index 20861218649f..c321c67472f0 100644
--- a/Documentation/devicetree/bindings/display/ti/ti,omap5-dss.txt
+++ b/Documentation/devicetree/bindings/display/ti/ti,omap5-dss.txt
@@ -89,8 +89,8 @@ Required properties:
- interrupts: the HDMI interrupt line
- ti,hwmods: "dss_hdmi"
- vdda-supply: vdda power supply
-- clocks: handles to fclk and pll clock
-- clock-names: "fck", "sys_clk"
+- clocks: handles to fclk, pll and cec clock
+- clock-names: "fck", "sys_clk", "cec"
Optional nodes:
- Video port for HDMI output
--
2.30.2
_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel
^ permalink raw reply related [flat|nested] 19+ messages in thread
* [PATCHv3 5/6] dra7.dtsi/omap5.dtsi: add cec clock
2021-04-28 13:25 ` Hans Verkuil
@ 2021-04-28 13:25 ` Hans Verkuil
-1 siblings, 0 replies; 19+ messages in thread
From: Hans Verkuil @ 2021-04-28 13:25 UTC (permalink / raw)
To: linux-media
Cc: Tomi Valkeinen, Tony Lindgren, Laurent Pinchart, dri-devel, Hans Verkuil
Add cec clock to the dra7 and omap5 device trees.
Signed-off-by: Hans Verkuil <hverkuil-cisco@xs4all.nl>
Acked-by: Tony Lindgren <tony@atomide.com>
Reviewed-by: Tomi Valkeinen <tomi.valkeinen@ideasonboard.com>
---
arch/arm/boot/dts/dra7.dtsi | 5 +++--
arch/arm/boot/dts/omap5.dtsi | 5 +++--
2 files changed, 6 insertions(+), 4 deletions(-)
diff --git a/arch/arm/boot/dts/dra7.dtsi b/arch/arm/boot/dts/dra7.dtsi
index ce1194744f84..efe579ddb324 100644
--- a/arch/arm/boot/dts/dra7.dtsi
+++ b/arch/arm/boot/dts/dra7.dtsi
@@ -879,8 +879,9 @@ hdmi: encoder@0 {
interrupts = <GIC_SPI 96 IRQ_TYPE_LEVEL_HIGH>;
status = "disabled";
clocks = <&dss_clkctrl DRA7_DSS_DSS_CORE_CLKCTRL 9>,
- <&dss_clkctrl DRA7_DSS_DSS_CORE_CLKCTRL 10>;
- clock-names = "fck", "sys_clk";
+ <&dss_clkctrl DRA7_DSS_DSS_CORE_CLKCTRL 10>,
+ <&dss_clkctrl DRA7_DSS_DSS_CORE_CLKCTRL 11>;
+ clock-names = "fck", "sys_clk", "cec";
dmas = <&sdma_xbar 76>;
dma-names = "audio_tx";
};
diff --git a/arch/arm/boot/dts/omap5.dtsi b/arch/arm/boot/dts/omap5.dtsi
index e025b7c9a357..6726e1f1b07c 100644
--- a/arch/arm/boot/dts/omap5.dtsi
+++ b/arch/arm/boot/dts/omap5.dtsi
@@ -586,8 +586,9 @@ hdmi: encoder@0 {
interrupts = <GIC_SPI 101 IRQ_TYPE_LEVEL_HIGH>;
status = "disabled";
clocks = <&dss_clkctrl OMAP5_DSS_CORE_CLKCTRL 9>,
- <&dss_clkctrl OMAP5_DSS_CORE_CLKCTRL 10>;
- clock-names = "fck", "sys_clk";
+ <&dss_clkctrl OMAP5_DSS_CORE_CLKCTRL 10>,
+ <&dss_clkctrl OMAP5_DSS_CORE_CLKCTRL 11>;
+ clock-names = "fck", "sys_clk", "cec";
dmas = <&sdma 76>;
dma-names = "audio_tx";
};
--
2.30.2
^ permalink raw reply related [flat|nested] 19+ messages in thread
* [PATCHv3 5/6] dra7.dtsi/omap5.dtsi: add cec clock
@ 2021-04-28 13:25 ` Hans Verkuil
0 siblings, 0 replies; 19+ messages in thread
From: Hans Verkuil @ 2021-04-28 13:25 UTC (permalink / raw)
To: linux-media
Cc: Tony Lindgren, Tomi Valkeinen, Laurent Pinchart, dri-devel, Hans Verkuil
Add cec clock to the dra7 and omap5 device trees.
Signed-off-by: Hans Verkuil <hverkuil-cisco@xs4all.nl>
Acked-by: Tony Lindgren <tony@atomide.com>
Reviewed-by: Tomi Valkeinen <tomi.valkeinen@ideasonboard.com>
---
arch/arm/boot/dts/dra7.dtsi | 5 +++--
arch/arm/boot/dts/omap5.dtsi | 5 +++--
2 files changed, 6 insertions(+), 4 deletions(-)
diff --git a/arch/arm/boot/dts/dra7.dtsi b/arch/arm/boot/dts/dra7.dtsi
index ce1194744f84..efe579ddb324 100644
--- a/arch/arm/boot/dts/dra7.dtsi
+++ b/arch/arm/boot/dts/dra7.dtsi
@@ -879,8 +879,9 @@ hdmi: encoder@0 {
interrupts = <GIC_SPI 96 IRQ_TYPE_LEVEL_HIGH>;
status = "disabled";
clocks = <&dss_clkctrl DRA7_DSS_DSS_CORE_CLKCTRL 9>,
- <&dss_clkctrl DRA7_DSS_DSS_CORE_CLKCTRL 10>;
- clock-names = "fck", "sys_clk";
+ <&dss_clkctrl DRA7_DSS_DSS_CORE_CLKCTRL 10>,
+ <&dss_clkctrl DRA7_DSS_DSS_CORE_CLKCTRL 11>;
+ clock-names = "fck", "sys_clk", "cec";
dmas = <&sdma_xbar 76>;
dma-names = "audio_tx";
};
diff --git a/arch/arm/boot/dts/omap5.dtsi b/arch/arm/boot/dts/omap5.dtsi
index e025b7c9a357..6726e1f1b07c 100644
--- a/arch/arm/boot/dts/omap5.dtsi
+++ b/arch/arm/boot/dts/omap5.dtsi
@@ -586,8 +586,9 @@ hdmi: encoder@0 {
interrupts = <GIC_SPI 101 IRQ_TYPE_LEVEL_HIGH>;
status = "disabled";
clocks = <&dss_clkctrl OMAP5_DSS_CORE_CLKCTRL 9>,
- <&dss_clkctrl OMAP5_DSS_CORE_CLKCTRL 10>;
- clock-names = "fck", "sys_clk";
+ <&dss_clkctrl OMAP5_DSS_CORE_CLKCTRL 10>,
+ <&dss_clkctrl OMAP5_DSS_CORE_CLKCTRL 11>;
+ clock-names = "fck", "sys_clk", "cec";
dmas = <&sdma 76>;
dma-names = "audio_tx";
};
--
2.30.2
_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel
^ permalink raw reply related [flat|nested] 19+ messages in thread
* [PATCHv3 6/6] drm/omapdrm/dss/hdmi5: add CEC support
2021-04-28 13:25 ` Hans Verkuil
@ 2021-04-28 13:25 ` Hans Verkuil
-1 siblings, 0 replies; 19+ messages in thread
From: Hans Verkuil @ 2021-04-28 13:25 UTC (permalink / raw)
To: linux-media
Cc: Tomi Valkeinen, Tony Lindgren, Laurent Pinchart, dri-devel, Hans Verkuil
Add HDMI CEC support for OMAP5.
Signed-off-by: Hans Verkuil <hverkuil-cisco@xs4all.nl>
Reviewed-by: Tomi Valkeinen <tomi.valkeinen@ideasonboard.com>
---
drivers/gpu/drm/omapdrm/Kconfig | 8 +
drivers/gpu/drm/omapdrm/Makefile | 1 +
drivers/gpu/drm/omapdrm/dss/hdmi.h | 1 +
drivers/gpu/drm/omapdrm/dss/hdmi5.c | 64 +++++--
drivers/gpu/drm/omapdrm/dss/hdmi5_cec.c | 209 +++++++++++++++++++++++
drivers/gpu/drm/omapdrm/dss/hdmi5_cec.h | 42 +++++
drivers/gpu/drm/omapdrm/dss/hdmi5_core.c | 35 +++-
drivers/gpu/drm/omapdrm/dss/hdmi5_core.h | 33 +++-
8 files changed, 374 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/Kconfig b/drivers/gpu/drm/omapdrm/Kconfig
index e7281da5bc6a..08866ac7d869 100644
--- a/drivers/gpu/drm/omapdrm/Kconfig
+++ b/drivers/gpu/drm/omapdrm/Kconfig
@@ -80,6 +80,14 @@ config OMAP5_DSS_HDMI
Definition Multimedia Interface. See http://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/Makefile b/drivers/gpu/drm/omapdrm/Makefile
index 21e8277ff88f..0732bd2dae1e 100644
--- a/drivers/gpu/drm/omapdrm/Makefile
+++ b/drivers/gpu/drm/omapdrm/Makefile
@@ -29,6 +29,7 @@ omapdrm-$(CONFIG_OMAP2_DSS_HDMI_COMMON) += dss/hdmi_common.o dss/hdmi_wp.o \
omapdrm-$(CONFIG_OMAP4_DSS_HDMI) += dss/hdmi4.o dss/hdmi4_core.o
omapdrm-$(CONFIG_OMAP4_DSS_HDMI_CEC) += dss/hdmi4_cec.o
omapdrm-$(CONFIG_OMAP5_DSS_HDMI) += dss/hdmi5.o dss/hdmi5_core.o
+omapdrm-$(CONFIG_OMAP5_DSS_HDMI_CEC) += dss/hdmi5_cec.o
ccflags-$(CONFIG_OMAP2_DSS_DEBUG) += -DDEBUG
obj-$(CONFIG_DRM_OMAP) += omapdrm.o
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 65085d886da5..11941d7b1d81 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)
@@ -105,6 +107,9 @@ static irqreturn_t hdmi_irq_handler(int irq, void *data)
hdmi_wp_set_phy_pwr(wp, HDMI_PHYPWRCMD_LDOON);
}
+ if (irqstatus & HDMI_IRQ_CORE)
+ hdmi5_core_handle_irqs(&hdmi->core);
+
return IRQ_HANDLED;
}
@@ -112,9 +117,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 +137,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,9 +181,9 @@ 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);
hdmi_wp_set_irqstatus(&hdmi->wp,
- hdmi_wp_get_irqstatus(&hdmi->wp));
+ hdmi_wp_get_irqstatus(&hdmi->wp) & ~HDMI_IRQ_CORE);
r = dss_pll_enable(&hdmi->pll.pll);
if (r) {
@@ -225,7 +238,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 +286,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 +308,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 +437,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 +458,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 +482,31 @@ 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_connector_attach(struct drm_bridge *bridge,
+ struct drm_connector *conn)
+{
+ struct omap_hdmi *hdmi = drm_bridge_to_hdmi(bridge);
+
+ hdmi5_cec_init(hdmi->pdev, &hdmi->core, &hdmi->wp, conn);
+ return 0;
+}
+
+static void hdmi5_bridge_connector_detach(struct drm_bridge *bridge,
+ struct drm_connector *conn)
+{
+ 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,7 +515,10 @@ 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,
+ .connector_attach = hdmi5_bridge_connector_attach,
+ .connector_detach = hdmi5_bridge_connector_detach,
};
static void hdmi5_bridge_init(struct omap_hdmi *hdmi)
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..9df6805a5cb4
--- /dev/null
+++ b/drivers/gpu/drm/omapdrm/dss/hdmi5_cec.c
@@ -0,0 +1,209 @@
+// 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);
+
+ 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, unsigned int stat)
+{
+ struct cec_adapter *adap = core->adap;
+
+ 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);
+
+ return 0;
+ }
+
+ 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);
+
+ 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,
+};
+
+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;
+ 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)
+ goto disable_clk;
+
+ 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)
+ goto delete_adap;
+
+ return 0;
+
+delete_adap:
+ cec_delete_adapter(core->adap);
+disable_clk:
+ clk_disable_unprepare(core->cec_clk);
+ core->adap = NULL;
+ return ret;
+}
+
+void hdmi5_cec_uninit(struct hdmi_core_data *core)
+{
+ if (IS_ERR_OR_NULL(core->adap))
+ return;
+
+ cec_unregister_adapter(core->adap);
+ clk_disable_unprepare(core->cec_clk);
+}
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..d7732f9a675a
--- /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, unsigned int stat);
+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, unsigned int stat)
+{
+}
+
+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..de57384ad159 100644
--- a/drivers/gpu/drm/omapdrm/dss/hdmi5_core.c
+++ b/drivers/gpu/drm/omapdrm/dss/hdmi5_core.c
@@ -22,6 +22,7 @@
#include <sound/asoundef.h>
#include "hdmi5_core.h"
+#include "hdmi5_cec.h"
void hdmi5_core_ddc_init(struct hdmi_core_data *core)
{
@@ -229,6 +230,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 +527,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 +544,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);
@@ -548,14 +558,24 @@ static void hdmi_core_enable_interrupts(struct hdmi_core_data *core)
int hdmi5_core_handle_irqs(struct hdmi_core_data *core)
{
void __iomem *base = core->base;
+ unsigned int stat = hdmi_read_reg(base, HDMI_CORE_IH_CEC_STAT0);
+
+ if (stat) {
+ hdmi_write_reg(base, HDMI_CORE_IH_CEC_STAT0, stat);
+ hdmi5_cec_irq(core, stat);
+ }
+ /*
+ * 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 above.
+ */
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 +899,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..6bcef70a87cc 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);
--
2.30.2
^ permalink raw reply related [flat|nested] 19+ messages in thread
* [PATCHv3 6/6] drm/omapdrm/dss/hdmi5: add CEC support
@ 2021-04-28 13:25 ` Hans Verkuil
0 siblings, 0 replies; 19+ messages in thread
From: Hans Verkuil @ 2021-04-28 13:25 UTC (permalink / raw)
To: linux-media
Cc: Tony Lindgren, Tomi Valkeinen, Laurent Pinchart, dri-devel, Hans Verkuil
Add HDMI CEC support for OMAP5.
Signed-off-by: Hans Verkuil <hverkuil-cisco@xs4all.nl>
Reviewed-by: Tomi Valkeinen <tomi.valkeinen@ideasonboard.com>
---
drivers/gpu/drm/omapdrm/Kconfig | 8 +
drivers/gpu/drm/omapdrm/Makefile | 1 +
drivers/gpu/drm/omapdrm/dss/hdmi.h | 1 +
drivers/gpu/drm/omapdrm/dss/hdmi5.c | 64 +++++--
drivers/gpu/drm/omapdrm/dss/hdmi5_cec.c | 209 +++++++++++++++++++++++
drivers/gpu/drm/omapdrm/dss/hdmi5_cec.h | 42 +++++
drivers/gpu/drm/omapdrm/dss/hdmi5_core.c | 35 +++-
drivers/gpu/drm/omapdrm/dss/hdmi5_core.h | 33 +++-
8 files changed, 374 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/Kconfig b/drivers/gpu/drm/omapdrm/Kconfig
index e7281da5bc6a..08866ac7d869 100644
--- a/drivers/gpu/drm/omapdrm/Kconfig
+++ b/drivers/gpu/drm/omapdrm/Kconfig
@@ -80,6 +80,14 @@ config OMAP5_DSS_HDMI
Definition Multimedia Interface. See http://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/Makefile b/drivers/gpu/drm/omapdrm/Makefile
index 21e8277ff88f..0732bd2dae1e 100644
--- a/drivers/gpu/drm/omapdrm/Makefile
+++ b/drivers/gpu/drm/omapdrm/Makefile
@@ -29,6 +29,7 @@ omapdrm-$(CONFIG_OMAP2_DSS_HDMI_COMMON) += dss/hdmi_common.o dss/hdmi_wp.o \
omapdrm-$(CONFIG_OMAP4_DSS_HDMI) += dss/hdmi4.o dss/hdmi4_core.o
omapdrm-$(CONFIG_OMAP4_DSS_HDMI_CEC) += dss/hdmi4_cec.o
omapdrm-$(CONFIG_OMAP5_DSS_HDMI) += dss/hdmi5.o dss/hdmi5_core.o
+omapdrm-$(CONFIG_OMAP5_DSS_HDMI_CEC) += dss/hdmi5_cec.o
ccflags-$(CONFIG_OMAP2_DSS_DEBUG) += -DDEBUG
obj-$(CONFIG_DRM_OMAP) += omapdrm.o
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 65085d886da5..11941d7b1d81 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)
@@ -105,6 +107,9 @@ static irqreturn_t hdmi_irq_handler(int irq, void *data)
hdmi_wp_set_phy_pwr(wp, HDMI_PHYPWRCMD_LDOON);
}
+ if (irqstatus & HDMI_IRQ_CORE)
+ hdmi5_core_handle_irqs(&hdmi->core);
+
return IRQ_HANDLED;
}
@@ -112,9 +117,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 +137,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,9 +181,9 @@ 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);
hdmi_wp_set_irqstatus(&hdmi->wp,
- hdmi_wp_get_irqstatus(&hdmi->wp));
+ hdmi_wp_get_irqstatus(&hdmi->wp) & ~HDMI_IRQ_CORE);
r = dss_pll_enable(&hdmi->pll.pll);
if (r) {
@@ -225,7 +238,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 +286,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 +308,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 +437,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 +458,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 +482,31 @@ 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_connector_attach(struct drm_bridge *bridge,
+ struct drm_connector *conn)
+{
+ struct omap_hdmi *hdmi = drm_bridge_to_hdmi(bridge);
+
+ hdmi5_cec_init(hdmi->pdev, &hdmi->core, &hdmi->wp, conn);
+ return 0;
+}
+
+static void hdmi5_bridge_connector_detach(struct drm_bridge *bridge,
+ struct drm_connector *conn)
+{
+ 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,7 +515,10 @@ 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,
+ .connector_attach = hdmi5_bridge_connector_attach,
+ .connector_detach = hdmi5_bridge_connector_detach,
};
static void hdmi5_bridge_init(struct omap_hdmi *hdmi)
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..9df6805a5cb4
--- /dev/null
+++ b/drivers/gpu/drm/omapdrm/dss/hdmi5_cec.c
@@ -0,0 +1,209 @@
+// 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);
+
+ 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, unsigned int stat)
+{
+ struct cec_adapter *adap = core->adap;
+
+ 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);
+
+ return 0;
+ }
+
+ 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);
+
+ 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,
+};
+
+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;
+ 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)
+ goto disable_clk;
+
+ 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)
+ goto delete_adap;
+
+ return 0;
+
+delete_adap:
+ cec_delete_adapter(core->adap);
+disable_clk:
+ clk_disable_unprepare(core->cec_clk);
+ core->adap = NULL;
+ return ret;
+}
+
+void hdmi5_cec_uninit(struct hdmi_core_data *core)
+{
+ if (IS_ERR_OR_NULL(core->adap))
+ return;
+
+ cec_unregister_adapter(core->adap);
+ clk_disable_unprepare(core->cec_clk);
+}
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..d7732f9a675a
--- /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, unsigned int stat);
+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, unsigned int stat)
+{
+}
+
+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..de57384ad159 100644
--- a/drivers/gpu/drm/omapdrm/dss/hdmi5_core.c
+++ b/drivers/gpu/drm/omapdrm/dss/hdmi5_core.c
@@ -22,6 +22,7 @@
#include <sound/asoundef.h>
#include "hdmi5_core.h"
+#include "hdmi5_cec.h"
void hdmi5_core_ddc_init(struct hdmi_core_data *core)
{
@@ -229,6 +230,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 +527,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 +544,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);
@@ -548,14 +558,24 @@ static void hdmi_core_enable_interrupts(struct hdmi_core_data *core)
int hdmi5_core_handle_irqs(struct hdmi_core_data *core)
{
void __iomem *base = core->base;
+ unsigned int stat = hdmi_read_reg(base, HDMI_CORE_IH_CEC_STAT0);
+
+ if (stat) {
+ hdmi_write_reg(base, HDMI_CORE_IH_CEC_STAT0, stat);
+ hdmi5_cec_irq(core, stat);
+ }
+ /*
+ * 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 above.
+ */
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 +899,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..6bcef70a87cc 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);
--
2.30.2
_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel
^ permalink raw reply related [flat|nested] 19+ messages in thread
* Re: [PATCHv3 1/6] drm: drm_bridge: add connector_attach/detach bridge ops
2021-04-28 13:25 ` Hans Verkuil
@ 2021-05-04 8:26 ` Tomi Valkeinen
-1 siblings, 0 replies; 19+ messages in thread
From: Tomi Valkeinen @ 2021-05-04 8:26 UTC (permalink / raw)
To: Hans Verkuil, dri-devel, Maarten Lankhorst, Maxime Ripard,
Thomas Zimmermann, David Airlie, Daniel Vetter
Cc: Tony Lindgren, Laurent Pinchart, linux-media
On 28/04/2021 16:25, Hans Verkuil wrote:
> Add bridge connector_attach/detach ops. These ops are called when a
> bridge is attached or detached to a drm_connector. These ops can be
> used to register and unregister an HDMI CEC adapter for a bridge that
> supports CEC.
>
> Signed-off-by: Hans Verkuil <hverkuil-cisco@xs4all.nl>
> ---
> drivers/gpu/drm/drm_bridge_connector.c | 25 +++++++++++++++++++++++-
> include/drm/drm_bridge.h | 27 ++++++++++++++++++++++++++
> 2 files changed, 51 insertions(+), 1 deletion(-)
>
> diff --git a/drivers/gpu/drm/drm_bridge_connector.c b/drivers/gpu/drm/drm_bridge_connector.c
> index 791379816837..0676677badfe 100644
> --- a/drivers/gpu/drm/drm_bridge_connector.c
> +++ b/drivers/gpu/drm/drm_bridge_connector.c
> @@ -203,6 +203,11 @@ static void drm_bridge_connector_destroy(struct drm_connector *connector)
> {
> struct drm_bridge_connector *bridge_connector =
> to_drm_bridge_connector(connector);
> + struct drm_bridge *bridge;
> +
> + drm_for_each_bridge_in_chain(bridge_connector->encoder, bridge)
> + if (bridge->funcs->connector_detach)
> + bridge->funcs->connector_detach(bridge, connector);
>
> if (bridge_connector->bridge_hpd) {
> struct drm_bridge *hpd = bridge_connector->bridge_hpd;
> @@ -318,6 +323,7 @@ struct drm_connector *drm_bridge_connector_init(struct drm_device *drm,
> struct i2c_adapter *ddc = NULL;
> struct drm_bridge *bridge;
> int connector_type;
> + int ret;
>
> bridge_connector = kzalloc(sizeof(*bridge_connector), GFP_KERNEL);
> if (!bridge_connector)
> @@ -375,6 +381,23 @@ struct drm_connector *drm_bridge_connector_init(struct drm_device *drm,
> connector->polled = DRM_CONNECTOR_POLL_CONNECT
> | DRM_CONNECTOR_POLL_DISCONNECT;
>
> - return connector;
> + ret = 0;
> + /* call connector_attach for all bridges */
> + drm_for_each_bridge_in_chain(encoder, bridge) {
> + if (!bridge->funcs->connector_attach)
> + continue;
> + ret = bridge->funcs->connector_attach(bridge, connector);
> + if (ret)
> + break;
> + }
> + if (!ret)
> + return connector;
> +
> + /* on error, detach any previously successfully attached connectors */
> + list_for_each_entry_continue_reverse(bridge, &(encoder)->bridge_chain,
No need for parenthesis in (encoder) here.
> + chain_node)
> + if (bridge->funcs->connector_detach)
> + bridge->funcs->connector_detach(bridge, connector);
> + return ERR_PTR(ret);
> }
> EXPORT_SYMBOL_GPL(drm_bridge_connector_init);
> diff --git a/include/drm/drm_bridge.h b/include/drm/drm_bridge.h
> index 2195daa289d2..333fbc3a03e9 100644
> --- a/include/drm/drm_bridge.h
> +++ b/include/drm/drm_bridge.h
> @@ -629,6 +629,33 @@ struct drm_bridge_funcs {
> * the DRM_BRIDGE_OP_HPD flag in their &drm_bridge->ops.
> */
> void (*hpd_disable)(struct drm_bridge *bridge);
> +
> + /**
> + * @connector_attach:
> + *
> + * This callback is invoked whenever our bridge is being attached to a
> + * &drm_connector. This is where an HDMI CEC adapter can be registered.
> + *
> + * The @connector_attach callback is optional.
> + *
> + * RETURNS:
> + *
> + * Zero on success, error code on failure.
> + */
> + int (*connector_attach)(struct drm_bridge *bridge,
> + struct drm_connector *conn);
> +
> + /**
> + * @connector_detach:
> + *
> + * This callback is invoked whenever our bridge is being detached from a
> + * &drm_connector. This is where an HDMI CEC adapter can be
> + * unregistered.
> + *
> + * The @connector_detach callback is optional.
> + */
> + void (*connector_detach)(struct drm_bridge *bridge,
> + struct drm_connector *conn);
> };
>
> /**
>
Reviewed-by: Tomi Valkeinen <tomi.valkeinen@ideasonboard.com>
I can take this series as it's mostly omapdrm, but we'll need a
reviewed-by/acked-by from a maintainer for this patch.
Tomi
^ permalink raw reply [flat|nested] 19+ messages in thread
* Re: [PATCHv3 1/6] drm: drm_bridge: add connector_attach/detach bridge ops
@ 2021-05-04 8:26 ` Tomi Valkeinen
0 siblings, 0 replies; 19+ messages in thread
From: Tomi Valkeinen @ 2021-05-04 8:26 UTC (permalink / raw)
To: Hans Verkuil, dri-devel, Maarten Lankhorst, Maxime Ripard,
Thomas Zimmermann, David Airlie, Daniel Vetter
Cc: Tony Lindgren, Laurent Pinchart, linux-media
On 28/04/2021 16:25, Hans Verkuil wrote:
> Add bridge connector_attach/detach ops. These ops are called when a
> bridge is attached or detached to a drm_connector. These ops can be
> used to register and unregister an HDMI CEC adapter for a bridge that
> supports CEC.
>
> Signed-off-by: Hans Verkuil <hverkuil-cisco@xs4all.nl>
> ---
> drivers/gpu/drm/drm_bridge_connector.c | 25 +++++++++++++++++++++++-
> include/drm/drm_bridge.h | 27 ++++++++++++++++++++++++++
> 2 files changed, 51 insertions(+), 1 deletion(-)
>
> diff --git a/drivers/gpu/drm/drm_bridge_connector.c b/drivers/gpu/drm/drm_bridge_connector.c
> index 791379816837..0676677badfe 100644
> --- a/drivers/gpu/drm/drm_bridge_connector.c
> +++ b/drivers/gpu/drm/drm_bridge_connector.c
> @@ -203,6 +203,11 @@ static void drm_bridge_connector_destroy(struct drm_connector *connector)
> {
> struct drm_bridge_connector *bridge_connector =
> to_drm_bridge_connector(connector);
> + struct drm_bridge *bridge;
> +
> + drm_for_each_bridge_in_chain(bridge_connector->encoder, bridge)
> + if (bridge->funcs->connector_detach)
> + bridge->funcs->connector_detach(bridge, connector);
>
> if (bridge_connector->bridge_hpd) {
> struct drm_bridge *hpd = bridge_connector->bridge_hpd;
> @@ -318,6 +323,7 @@ struct drm_connector *drm_bridge_connector_init(struct drm_device *drm,
> struct i2c_adapter *ddc = NULL;
> struct drm_bridge *bridge;
> int connector_type;
> + int ret;
>
> bridge_connector = kzalloc(sizeof(*bridge_connector), GFP_KERNEL);
> if (!bridge_connector)
> @@ -375,6 +381,23 @@ struct drm_connector *drm_bridge_connector_init(struct drm_device *drm,
> connector->polled = DRM_CONNECTOR_POLL_CONNECT
> | DRM_CONNECTOR_POLL_DISCONNECT;
>
> - return connector;
> + ret = 0;
> + /* call connector_attach for all bridges */
> + drm_for_each_bridge_in_chain(encoder, bridge) {
> + if (!bridge->funcs->connector_attach)
> + continue;
> + ret = bridge->funcs->connector_attach(bridge, connector);
> + if (ret)
> + break;
> + }
> + if (!ret)
> + return connector;
> +
> + /* on error, detach any previously successfully attached connectors */
> + list_for_each_entry_continue_reverse(bridge, &(encoder)->bridge_chain,
No need for parenthesis in (encoder) here.
> + chain_node)
> + if (bridge->funcs->connector_detach)
> + bridge->funcs->connector_detach(bridge, connector);
> + return ERR_PTR(ret);
> }
> EXPORT_SYMBOL_GPL(drm_bridge_connector_init);
> diff --git a/include/drm/drm_bridge.h b/include/drm/drm_bridge.h
> index 2195daa289d2..333fbc3a03e9 100644
> --- a/include/drm/drm_bridge.h
> +++ b/include/drm/drm_bridge.h
> @@ -629,6 +629,33 @@ struct drm_bridge_funcs {
> * the DRM_BRIDGE_OP_HPD flag in their &drm_bridge->ops.
> */
> void (*hpd_disable)(struct drm_bridge *bridge);
> +
> + /**
> + * @connector_attach:
> + *
> + * This callback is invoked whenever our bridge is being attached to a
> + * &drm_connector. This is where an HDMI CEC adapter can be registered.
> + *
> + * The @connector_attach callback is optional.
> + *
> + * RETURNS:
> + *
> + * Zero on success, error code on failure.
> + */
> + int (*connector_attach)(struct drm_bridge *bridge,
> + struct drm_connector *conn);
> +
> + /**
> + * @connector_detach:
> + *
> + * This callback is invoked whenever our bridge is being detached from a
> + * &drm_connector. This is where an HDMI CEC adapter can be
> + * unregistered.
> + *
> + * The @connector_detach callback is optional.
> + */
> + void (*connector_detach)(struct drm_bridge *bridge,
> + struct drm_connector *conn);
> };
>
> /**
>
Reviewed-by: Tomi Valkeinen <tomi.valkeinen@ideasonboard.com>
I can take this series as it's mostly omapdrm, but we'll need a
reviewed-by/acked-by from a maintainer for this patch.
Tomi
_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel
^ permalink raw reply [flat|nested] 19+ messages in thread
* Re: [PATCHv3 1/6] drm: drm_bridge: add connector_attach/detach bridge ops
2021-05-04 8:26 ` Tomi Valkeinen
(?)
@ 2021-05-27 7:22 ` Hans Verkuil
2021-06-03 12:34 ` Laurent Pinchart
-1 siblings, 1 reply; 19+ messages in thread
From: Hans Verkuil @ 2021-05-27 7:22 UTC (permalink / raw)
To: Tomi Valkeinen, dri-devel, Maarten Lankhorst, Maxime Ripard,
Thomas Zimmermann, David Airlie, Daniel Vetter
Cc: Tony Lindgren, Laurent Pinchart, linux-media
On 04/05/2021 10:26, Tomi Valkeinen wrote:
> On 28/04/2021 16:25, Hans Verkuil wrote:
>> Add bridge connector_attach/detach ops. These ops are called when a
>> bridge is attached or detached to a drm_connector. These ops can be
>> used to register and unregister an HDMI CEC adapter for a bridge that
>> supports CEC.
>>
>> Signed-off-by: Hans Verkuil <hverkuil-cisco@xs4all.nl>
>> ---
>> drivers/gpu/drm/drm_bridge_connector.c | 25 +++++++++++++++++++++++-
>> include/drm/drm_bridge.h | 27 ++++++++++++++++++++++++++
>> 2 files changed, 51 insertions(+), 1 deletion(-)
>>
>> diff --git a/drivers/gpu/drm/drm_bridge_connector.c b/drivers/gpu/drm/drm_bridge_connector.c
>> index 791379816837..0676677badfe 100644
>> --- a/drivers/gpu/drm/drm_bridge_connector.c
>> +++ b/drivers/gpu/drm/drm_bridge_connector.c
>> @@ -203,6 +203,11 @@ static void drm_bridge_connector_destroy(struct drm_connector *connector)
>> {
>> struct drm_bridge_connector *bridge_connector =
>> to_drm_bridge_connector(connector);
>> + struct drm_bridge *bridge;
>> +
>> + drm_for_each_bridge_in_chain(bridge_connector->encoder, bridge)
>> + if (bridge->funcs->connector_detach)
>> + bridge->funcs->connector_detach(bridge, connector);
>>
>> if (bridge_connector->bridge_hpd) {
>> struct drm_bridge *hpd = bridge_connector->bridge_hpd;
>> @@ -318,6 +323,7 @@ struct drm_connector *drm_bridge_connector_init(struct drm_device *drm,
>> struct i2c_adapter *ddc = NULL;
>> struct drm_bridge *bridge;
>> int connector_type;
>> + int ret;
>>
>> bridge_connector = kzalloc(sizeof(*bridge_connector), GFP_KERNEL);
>> if (!bridge_connector)
>> @@ -375,6 +381,23 @@ struct drm_connector *drm_bridge_connector_init(struct drm_device *drm,
>> connector->polled = DRM_CONNECTOR_POLL_CONNECT
>> | DRM_CONNECTOR_POLL_DISCONNECT;
>>
>> - return connector;
>> + ret = 0;
>> + /* call connector_attach for all bridges */
>> + drm_for_each_bridge_in_chain(encoder, bridge) {
>> + if (!bridge->funcs->connector_attach)
>> + continue;
>> + ret = bridge->funcs->connector_attach(bridge, connector);
>> + if (ret)
>> + break;
>> + }
>> + if (!ret)
>> + return connector;
>> +
>> + /* on error, detach any previously successfully attached connectors */
>> + list_for_each_entry_continue_reverse(bridge, &(encoder)->bridge_chain,
>
> No need for parenthesis in (encoder) here.
>
>> + chain_node)
>> + if (bridge->funcs->connector_detach)
>> + bridge->funcs->connector_detach(bridge, connector);
>> + return ERR_PTR(ret);
>> }
>> EXPORT_SYMBOL_GPL(drm_bridge_connector_init);
>> diff --git a/include/drm/drm_bridge.h b/include/drm/drm_bridge.h
>> index 2195daa289d2..333fbc3a03e9 100644
>> --- a/include/drm/drm_bridge.h
>> +++ b/include/drm/drm_bridge.h
>> @@ -629,6 +629,33 @@ struct drm_bridge_funcs {
>> * the DRM_BRIDGE_OP_HPD flag in their &drm_bridge->ops.
>> */
>> void (*hpd_disable)(struct drm_bridge *bridge);
>> +
>> + /**
>> + * @connector_attach:
>> + *
>> + * This callback is invoked whenever our bridge is being attached to a
>> + * &drm_connector. This is where an HDMI CEC adapter can be registered.
>> + *
>> + * The @connector_attach callback is optional.
>> + *
>> + * RETURNS:
>> + *
>> + * Zero on success, error code on failure.
>> + */
>> + int (*connector_attach)(struct drm_bridge *bridge,
>> + struct drm_connector *conn);
>> +
>> + /**
>> + * @connector_detach:
>> + *
>> + * This callback is invoked whenever our bridge is being detached from a
>> + * &drm_connector. This is where an HDMI CEC adapter can be
>> + * unregistered.
>> + *
>> + * The @connector_detach callback is optional.
>> + */
>> + void (*connector_detach)(struct drm_bridge *bridge,
>> + struct drm_connector *conn);
>> };
>>
>> /**
>>
>
> Reviewed-by: Tomi Valkeinen <tomi.valkeinen@ideasonboard.com>
>
> I can take this series as it's mostly omapdrm, but we'll need a
> reviewed-by/acked-by from a maintainer for this patch.
Laurent, aren't you the drm bridge maintainer?
If so, can you review/ack this patch so Tomi can merge it?
Regards,
Hans
>
> Tomi
>
^ permalink raw reply [flat|nested] 19+ messages in thread
* Re: [PATCHv3 1/6] drm: drm_bridge: add connector_attach/detach bridge ops
2021-05-27 7:22 ` Hans Verkuil
@ 2021-06-03 12:34 ` Laurent Pinchart
0 siblings, 0 replies; 19+ messages in thread
From: Laurent Pinchart @ 2021-06-03 12:34 UTC (permalink / raw)
To: Hans Verkuil
Cc: Tomi Valkeinen, dri-devel, Maarten Lankhorst, Maxime Ripard,
Thomas Zimmermann, David Airlie, Daniel Vetter, Tony Lindgren,
linux-media
Hi Hans,
On Thu, May 27, 2021 at 09:22:12AM +0200, Hans Verkuil wrote:
> On 04/05/2021 10:26, Tomi Valkeinen wrote:
> > On 28/04/2021 16:25, Hans Verkuil wrote:
> >> Add bridge connector_attach/detach ops. These ops are called when a
> >> bridge is attached or detached to a drm_connector. These ops can be
> >> used to register and unregister an HDMI CEC adapter for a bridge that
> >> supports CEC.
> >>
> >> Signed-off-by: Hans Verkuil <hverkuil-cisco@xs4all.nl>
> >> ---
> >> drivers/gpu/drm/drm_bridge_connector.c | 25 +++++++++++++++++++++++-
> >> include/drm/drm_bridge.h | 27 ++++++++++++++++++++++++++
> >> 2 files changed, 51 insertions(+), 1 deletion(-)
> >>
> >> diff --git a/drivers/gpu/drm/drm_bridge_connector.c b/drivers/gpu/drm/drm_bridge_connector.c
> >> index 791379816837..0676677badfe 100644
> >> --- a/drivers/gpu/drm/drm_bridge_connector.c
> >> +++ b/drivers/gpu/drm/drm_bridge_connector.c
> >> @@ -203,6 +203,11 @@ static void drm_bridge_connector_destroy(struct drm_connector *connector)
> >> {
> >> struct drm_bridge_connector *bridge_connector =
> >> to_drm_bridge_connector(connector);
> >> + struct drm_bridge *bridge;
> >> +
> >> + drm_for_each_bridge_in_chain(bridge_connector->encoder, bridge)
> >> + if (bridge->funcs->connector_detach)
> >> + bridge->funcs->connector_detach(bridge, connector);
> >>
> >> if (bridge_connector->bridge_hpd) {
> >> struct drm_bridge *hpd = bridge_connector->bridge_hpd;
> >> @@ -318,6 +323,7 @@ struct drm_connector *drm_bridge_connector_init(struct drm_device *drm,
> >> struct i2c_adapter *ddc = NULL;
> >> struct drm_bridge *bridge;
> >> int connector_type;
> >> + int ret;
> >>
> >> bridge_connector = kzalloc(sizeof(*bridge_connector), GFP_KERNEL);
> >> if (!bridge_connector)
> >> @@ -375,6 +381,23 @@ struct drm_connector *drm_bridge_connector_init(struct drm_device *drm,
> >> connector->polled = DRM_CONNECTOR_POLL_CONNECT
> >> | DRM_CONNECTOR_POLL_DISCONNECT;
> >>
> >> - return connector;
> >> + ret = 0;
> >> + /* call connector_attach for all bridges */
> >> + drm_for_each_bridge_in_chain(encoder, bridge) {
> >> + if (!bridge->funcs->connector_attach)
> >> + continue;
> >> + ret = bridge->funcs->connector_attach(bridge, connector);
> >> + if (ret)
> >> + break;
> >> + }
> >> + if (!ret)
> >> + return connector;
> >> +
> >> + /* on error, detach any previously successfully attached connectors */
> >> + list_for_each_entry_continue_reverse(bridge, &(encoder)->bridge_chain,
> >
> > No need for parenthesis in (encoder) here.
> >
> >> + chain_node)
> >> + if (bridge->funcs->connector_detach)
> >> + bridge->funcs->connector_detach(bridge, connector);
> >> + return ERR_PTR(ret);
> >> }
> >> EXPORT_SYMBOL_GPL(drm_bridge_connector_init);
> >> diff --git a/include/drm/drm_bridge.h b/include/drm/drm_bridge.h
> >> index 2195daa289d2..333fbc3a03e9 100644
> >> --- a/include/drm/drm_bridge.h
> >> +++ b/include/drm/drm_bridge.h
> >> @@ -629,6 +629,33 @@ struct drm_bridge_funcs {
> >> * the DRM_BRIDGE_OP_HPD flag in their &drm_bridge->ops.
> >> */
> >> void (*hpd_disable)(struct drm_bridge *bridge);
> >> +
> >> + /**
> >> + * @connector_attach:
> >> + *
> >> + * This callback is invoked whenever our bridge is being attached to a
> >> + * &drm_connector. This is where an HDMI CEC adapter can be registered.
> >> + *
> >> + * The @connector_attach callback is optional.
> >> + *
> >> + * RETURNS:
> >> + *
> >> + * Zero on success, error code on failure.
> >> + */
> >> + int (*connector_attach)(struct drm_bridge *bridge,
> >> + struct drm_connector *conn);
> >> +
> >> + /**
> >> + * @connector_detach:
> >> + *
> >> + * This callback is invoked whenever our bridge is being detached from a
> >> + * &drm_connector. This is where an HDMI CEC adapter can be
> >> + * unregistered.
> >> + *
> >> + * The @connector_detach callback is optional.
> >> + */
> >> + void (*connector_detach)(struct drm_bridge *bridge,
> >> + struct drm_connector *conn);
> >> };
> >>
> >> /**
> >>
> >
> > Reviewed-by: Tomi Valkeinen <tomi.valkeinen@ideasonboard.com>
> >
> > I can take this series as it's mostly omapdrm, but we'll need a
> > reviewed-by/acked-by from a maintainer for this patch.
>
> Laurent, aren't you the drm bridge maintainer?
I'm merely a reviewer, but one without much free time these days :-(
> If so, can you review/ack this patch so Tomi can merge it?
Overall, I'm not fond of giving access to the connector to individual
bridges. It breaks the abstraction layers, and seems to be a bit of a
hack. On the other hand, a proper solution would likely involve lots of
work, so I'm not rejecting this, but I fear these operations will be
abused and we'll regret it later.
--
Regards,
Laurent Pinchart
^ permalink raw reply [flat|nested] 19+ messages in thread
* Re: [PATCHv3 1/6] drm: drm_bridge: add connector_attach/detach bridge ops
@ 2021-06-03 12:34 ` Laurent Pinchart
0 siblings, 0 replies; 19+ messages in thread
From: Laurent Pinchart @ 2021-06-03 12:34 UTC (permalink / raw)
To: Hans Verkuil
Cc: David Airlie, Tomi Valkeinen, Tony Lindgren, dri-devel,
Thomas Zimmermann, linux-media
Hi Hans,
On Thu, May 27, 2021 at 09:22:12AM +0200, Hans Verkuil wrote:
> On 04/05/2021 10:26, Tomi Valkeinen wrote:
> > On 28/04/2021 16:25, Hans Verkuil wrote:
> >> Add bridge connector_attach/detach ops. These ops are called when a
> >> bridge is attached or detached to a drm_connector. These ops can be
> >> used to register and unregister an HDMI CEC adapter for a bridge that
> >> supports CEC.
> >>
> >> Signed-off-by: Hans Verkuil <hverkuil-cisco@xs4all.nl>
> >> ---
> >> drivers/gpu/drm/drm_bridge_connector.c | 25 +++++++++++++++++++++++-
> >> include/drm/drm_bridge.h | 27 ++++++++++++++++++++++++++
> >> 2 files changed, 51 insertions(+), 1 deletion(-)
> >>
> >> diff --git a/drivers/gpu/drm/drm_bridge_connector.c b/drivers/gpu/drm/drm_bridge_connector.c
> >> index 791379816837..0676677badfe 100644
> >> --- a/drivers/gpu/drm/drm_bridge_connector.c
> >> +++ b/drivers/gpu/drm/drm_bridge_connector.c
> >> @@ -203,6 +203,11 @@ static void drm_bridge_connector_destroy(struct drm_connector *connector)
> >> {
> >> struct drm_bridge_connector *bridge_connector =
> >> to_drm_bridge_connector(connector);
> >> + struct drm_bridge *bridge;
> >> +
> >> + drm_for_each_bridge_in_chain(bridge_connector->encoder, bridge)
> >> + if (bridge->funcs->connector_detach)
> >> + bridge->funcs->connector_detach(bridge, connector);
> >>
> >> if (bridge_connector->bridge_hpd) {
> >> struct drm_bridge *hpd = bridge_connector->bridge_hpd;
> >> @@ -318,6 +323,7 @@ struct drm_connector *drm_bridge_connector_init(struct drm_device *drm,
> >> struct i2c_adapter *ddc = NULL;
> >> struct drm_bridge *bridge;
> >> int connector_type;
> >> + int ret;
> >>
> >> bridge_connector = kzalloc(sizeof(*bridge_connector), GFP_KERNEL);
> >> if (!bridge_connector)
> >> @@ -375,6 +381,23 @@ struct drm_connector *drm_bridge_connector_init(struct drm_device *drm,
> >> connector->polled = DRM_CONNECTOR_POLL_CONNECT
> >> | DRM_CONNECTOR_POLL_DISCONNECT;
> >>
> >> - return connector;
> >> + ret = 0;
> >> + /* call connector_attach for all bridges */
> >> + drm_for_each_bridge_in_chain(encoder, bridge) {
> >> + if (!bridge->funcs->connector_attach)
> >> + continue;
> >> + ret = bridge->funcs->connector_attach(bridge, connector);
> >> + if (ret)
> >> + break;
> >> + }
> >> + if (!ret)
> >> + return connector;
> >> +
> >> + /* on error, detach any previously successfully attached connectors */
> >> + list_for_each_entry_continue_reverse(bridge, &(encoder)->bridge_chain,
> >
> > No need for parenthesis in (encoder) here.
> >
> >> + chain_node)
> >> + if (bridge->funcs->connector_detach)
> >> + bridge->funcs->connector_detach(bridge, connector);
> >> + return ERR_PTR(ret);
> >> }
> >> EXPORT_SYMBOL_GPL(drm_bridge_connector_init);
> >> diff --git a/include/drm/drm_bridge.h b/include/drm/drm_bridge.h
> >> index 2195daa289d2..333fbc3a03e9 100644
> >> --- a/include/drm/drm_bridge.h
> >> +++ b/include/drm/drm_bridge.h
> >> @@ -629,6 +629,33 @@ struct drm_bridge_funcs {
> >> * the DRM_BRIDGE_OP_HPD flag in their &drm_bridge->ops.
> >> */
> >> void (*hpd_disable)(struct drm_bridge *bridge);
> >> +
> >> + /**
> >> + * @connector_attach:
> >> + *
> >> + * This callback is invoked whenever our bridge is being attached to a
> >> + * &drm_connector. This is where an HDMI CEC adapter can be registered.
> >> + *
> >> + * The @connector_attach callback is optional.
> >> + *
> >> + * RETURNS:
> >> + *
> >> + * Zero on success, error code on failure.
> >> + */
> >> + int (*connector_attach)(struct drm_bridge *bridge,
> >> + struct drm_connector *conn);
> >> +
> >> + /**
> >> + * @connector_detach:
> >> + *
> >> + * This callback is invoked whenever our bridge is being detached from a
> >> + * &drm_connector. This is where an HDMI CEC adapter can be
> >> + * unregistered.
> >> + *
> >> + * The @connector_detach callback is optional.
> >> + */
> >> + void (*connector_detach)(struct drm_bridge *bridge,
> >> + struct drm_connector *conn);
> >> };
> >>
> >> /**
> >>
> >
> > Reviewed-by: Tomi Valkeinen <tomi.valkeinen@ideasonboard.com>
> >
> > I can take this series as it's mostly omapdrm, but we'll need a
> > reviewed-by/acked-by from a maintainer for this patch.
>
> Laurent, aren't you the drm bridge maintainer?
I'm merely a reviewer, but one without much free time these days :-(
> If so, can you review/ack this patch so Tomi can merge it?
Overall, I'm not fond of giving access to the connector to individual
bridges. It breaks the abstraction layers, and seems to be a bit of a
hack. On the other hand, a proper solution would likely involve lots of
work, so I'm not rejecting this, but I fear these operations will be
abused and we'll regret it later.
--
Regards,
Laurent Pinchart
^ permalink raw reply [flat|nested] 19+ messages in thread
end of thread, other threads:[~2021-06-03 12:35 UTC | newest]
Thread overview: 19+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2021-04-28 13:25 [PATCHv3 0/6] drm/omap: hdmi: improve hdmi4 CEC, add CEC for hdmi5 Hans Verkuil
2021-04-28 13:25 ` Hans Verkuil
2021-04-28 13:25 ` [PATCHv3 1/6] drm: drm_bridge: add connector_attach/detach bridge ops Hans Verkuil
2021-04-28 13:25 ` Hans Verkuil
2021-05-04 8:26 ` Tomi Valkeinen
2021-05-04 8:26 ` Tomi Valkeinen
2021-05-27 7:22 ` Hans Verkuil
2021-06-03 12:34 ` Laurent Pinchart
2021-06-03 12:34 ` Laurent Pinchart
2021-04-28 13:25 ` [PATCHv3 2/6] drm/omapdrm/dss/hdmi4: switch to the connector " Hans Verkuil
2021-04-28 13:25 ` Hans Verkuil
2021-04-28 13:25 ` [PATCHv3 3/6] drm/omapdrm/dss/hdmi4: simplify CEC Phys Addr handling Hans Verkuil
2021-04-28 13:25 ` Hans Verkuil
2021-04-28 13:25 ` [PATCHv3 4/6] dt-bindings: display: ti: ti,omap5-dss.txt: add cec clock Hans Verkuil
2021-04-28 13:25 ` [PATCHv3 4/6] dt-bindings: display: ti: ti, omap5-dss.txt: " Hans Verkuil
2021-04-28 13:25 ` [PATCHv3 5/6] dra7.dtsi/omap5.dtsi: " Hans Verkuil
2021-04-28 13:25 ` Hans Verkuil
2021-04-28 13:25 ` [PATCHv3 6/6] drm/omapdrm/dss/hdmi5: add CEC support Hans Verkuil
2021-04-28 13:25 ` Hans Verkuil
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.