[PATCH 36/60] drm/omap: hdmi4: Register a drm_bridge for EDID read
Laurent Pinchart
laurent.pinchart at ideasonboard.com
Sun Jul 7 18:19:13 UTC 2019
In order to integrate with a chain of drm_bridge, the internal HDMI4
encoder has to expose the EDID read operation through the drm_bridge
API. Register a bridge at initialisation time to do so.
For the time being make the next bridge in the chain optional as the
HDMI output is still based on omap_dss_device. The create_connector
argument to the bridge attach function is also ignored for the same
reason. This will be changed later when removing the related
omapdrm-specific display drivers.
Signed-off-by: Laurent Pinchart <laurent.pinchart at ideasonboard.com>
---
drivers/gpu/drm/omapdrm/dss/hdmi.h | 3 ++
drivers/gpu/drm/omapdrm/dss/hdmi4.c | 73 +++++++++++++++++++++++++++--
2 files changed, 71 insertions(+), 5 deletions(-)
diff --git a/drivers/gpu/drm/omapdrm/dss/hdmi.h b/drivers/gpu/drm/omapdrm/dss/hdmi.h
index 7f0dc490a31d..d1e3f625eebc 100644
--- a/drivers/gpu/drm/omapdrm/dss/hdmi.h
+++ b/drivers/gpu/drm/omapdrm/dss/hdmi.h
@@ -25,6 +25,7 @@
#include <linux/hdmi.h>
#include <sound/omap-hdmi-audio.h>
#include <media/cec.h>
+#include <drm/drm_bridge.h>
#include "omapdss.h"
#include "dss.h"
@@ -375,6 +376,7 @@ struct omap_hdmi {
bool core_enabled;
struct omap_dss_device output;
+ struct drm_bridge bridge;
struct platform_device *audio_pdev;
void (*audio_abort_cb)(struct device *dev);
@@ -390,5 +392,6 @@ struct omap_hdmi {
};
#define dssdev_to_hdmi(dssdev) container_of(dssdev, struct omap_hdmi, output)
+#define drm_bridge_to_hdmi(b) container_of(b, struct omap_hdmi, bridge)
#endif
diff --git a/drivers/gpu/drm/omapdrm/dss/hdmi4.c b/drivers/gpu/drm/omapdrm/dss/hdmi4.c
index 5d7b17b52dc0..3084a200911b 100644
--- a/drivers/gpu/drm/omapdrm/dss/hdmi4.c
+++ b/drivers/gpu/drm/omapdrm/dss/hdmi4.c
@@ -399,7 +399,8 @@ static void hdmi_disconnect(struct omap_dss_device *src,
omapdss_device_disconnect(dst, dst->next);
}
-static struct edid *hdmi_read_edid_data(struct omap_hdmi *hdmi)
+static struct edid *hdmi_read_edid_data(struct omap_hdmi *hdmi,
+ struct drm_connector *connector)
{
u8 *edid;
int r;
@@ -437,9 +438,12 @@ static struct edid *hdmi_read_edid_data(struct omap_hdmi *hdmi)
return NULL;
}
-static struct edid *hdmi_read_edid(struct omap_dss_device *dssdev)
+static struct edid *
+hdmi_do_read_edid(struct omap_hdmi *hdmi,
+ struct edid *(*read)(struct omap_hdmi *hdmi,
+ struct drm_connector *connector),
+ struct drm_connector *connector)
{
- struct omap_hdmi *hdmi = dssdev_to_hdmi(dssdev);
struct edid *edid = NULL;
unsigned int cec_addr;
bool need_enable;
@@ -461,7 +465,7 @@ static struct edid *hdmi_read_edid(struct omap_dss_device *dssdev)
if (r)
goto done;
- edid = hdmi_read_edid_data(hdmi);
+ edid = read(hdmi, connector);
done:
hdmi_runtime_put(hdmi);
@@ -483,6 +487,12 @@ static struct edid *hdmi_read_edid(struct omap_dss_device *dssdev)
return edid;
}
+static struct edid *hdmi_read_edid(struct omap_dss_device *dssdev)
+{
+ return hdmi_do_read_edid(dssdev_to_hdmi(dssdev), hdmi_read_edid_data,
+ NULL);
+}
+
static void hdmi_lost_hotplug(struct omap_dss_device *dssdev)
{
struct omap_hdmi *hdmi = dssdev_to_hdmi(dssdev);
@@ -526,6 +536,55 @@ static const struct omap_dss_device_ops hdmi_ops = {
},
};
+/* -----------------------------------------------------------------------------
+ * DRM Bridge Operations
+ */
+
+static int hdmi4_bridge_attach(struct drm_bridge *bridge, bool create_connector)
+{
+ struct omap_hdmi *hdmi = drm_bridge_to_hdmi(bridge);
+
+ if (!hdmi->output.next_bridge)
+ return 0;
+
+ return drm_bridge_attach(bridge->encoder, hdmi->output.next_bridge,
+ bridge, false);
+}
+
+static struct edid *hdmi4_bridge_read_edid(struct omap_hdmi *hdmi,
+ struct drm_connector *connector)
+{
+ return drm_do_get_edid(connector, hdmi4_core_ddc_read, &hdmi->core);
+}
+
+static struct edid *hdmi4_bridge_get_edid(struct drm_bridge *bridge,
+ struct drm_connector *connector)
+{
+ struct omap_hdmi *hdmi = drm_bridge_to_hdmi(bridge);
+
+ return hdmi_do_read_edid(hdmi, hdmi4_bridge_read_edid, connector);
+}
+
+static const struct drm_bridge_funcs hdmi4_bridge_funcs = {
+ .attach = hdmi4_bridge_attach,
+ .get_edid = hdmi4_bridge_get_edid,
+};
+
+static void hdmi4_bridge_init(struct omap_hdmi *hdmi)
+{
+ hdmi->bridge.funcs = &hdmi4_bridge_funcs;
+ hdmi->bridge.of_node = hdmi->pdev->dev.of_node;
+ hdmi->bridge.ops = DRM_BRIDGE_OP_EDID;
+ hdmi->bridge.type = DRM_MODE_CONNECTOR_HDMIA;
+
+ drm_bridge_add(&hdmi->bridge);
+}
+
+static void hdmi4_bridge_cleanup(struct omap_hdmi *hdmi)
+{
+ drm_bridge_remove(&hdmi->bridge);
+}
+
/* -----------------------------------------------------------------------------
* Audio Callbacks
*/
@@ -717,6 +776,8 @@ static int hdmi4_init_output(struct omap_hdmi *hdmi)
struct omap_dss_device *out = &hdmi->output;
int r;
+ hdmi4_bridge_init(hdmi);
+
out->dev = &hdmi->pdev->dev;
out->id = OMAP_DSS_OUTPUT_HDMI;
out->type = OMAP_DISPLAY_TYPE_HDMI;
@@ -727,7 +788,7 @@ static int hdmi4_init_output(struct omap_hdmi *hdmi)
out->of_port = 0;
out->ops_flags = OMAP_DSS_DEVICE_OP_EDID;
- r = omapdss_device_init_output(out, NULL);
+ r = omapdss_device_init_output(out, &hdmi->bridge);
if (r < 0)
return r;
@@ -742,6 +803,8 @@ static void hdmi4_uninit_output(struct omap_hdmi *hdmi)
omapdss_device_unregister(out);
omapdss_device_cleanup_output(out);
+
+ hdmi4_bridge_cleanup(hdmi);
}
static int hdmi4_probe_of(struct omap_hdmi *hdmi)
--
Regards,
Laurent Pinchart
More information about the dri-devel
mailing list