diff mbox series

[04/16] drm/exynos: implement a drm bridge

Message ID 20200903165717.1272492-5-m.tretter@pengutronix.de (mailing list archive)
State Not Applicable
Headers show
Series drm/exynos: Convert driver to drm bridge | expand

Commit Message

Michael Tretter Sept. 3, 2020, 4:57 p.m. UTC
Make the exynos_dsi driver a full drm bridge that can be found and used
from other drivers.

Signed-off-by: Michael Tretter <m.tretter@pengutronix.de>
---
 drivers/gpu/drm/exynos/exynos_drm_dsi.c | 45 +++++++++++++++++++++++--
 1 file changed, 42 insertions(+), 3 deletions(-)
diff mbox series

Patch

diff --git a/drivers/gpu/drm/exynos/exynos_drm_dsi.c b/drivers/gpu/drm/exynos/exynos_drm_dsi.c
index ddbda33dea91..4d19630f33e7 100644
--- a/drivers/gpu/drm/exynos/exynos_drm_dsi.c
+++ b/drivers/gpu/drm/exynos/exynos_drm_dsi.c
@@ -253,6 +253,7 @@  struct exynos_dsi_driver_data {
 
 struct exynos_dsi {
 	struct drm_encoder encoder;
+	struct drm_bridge bridge;
 	struct mipi_dsi_host dsi_host;
 	struct drm_connector connector;
 	struct drm_panel *panel;
@@ -1523,19 +1524,43 @@  static const struct drm_encoder_helper_funcs exynos_dsi_encoder_helper_funcs = {
 	.disable = exynos_dsi_disable,
 };
 
+static int exynos_dsi_bridge_attach(struct drm_bridge *bridge,
+				    enum drm_bridge_attach_flags flags)
+{
+	struct exynos_dsi *dsi = bridge->driver_private;
+
+	if (!bridge->encoder) {
+		dev_err(dsi->dev, "missing encoder\n");
+		return -ENODEV;
+	}
+
+	return 0;
+}
+
+static const struct drm_bridge_funcs exynos_dsi_bridge_funcs = {
+	.attach = exynos_dsi_bridge_attach,
+};
+
 MODULE_DEVICE_TABLE(of, exynos_dsi_of_match);
 
 static int exynos_dsi_host_attach(struct mipi_dsi_host *host,
 				  struct mipi_dsi_device *device)
 {
 	struct exynos_dsi *dsi = host_to_dsi(host);
-	struct drm_encoder *encoder = &dsi->encoder;
-	struct drm_device *drm = encoder->dev;
+	struct drm_bridge *bridge = &dsi->bridge;
+	struct drm_encoder *encoder;
+	struct drm_device *drm;
 	struct drm_bridge *out_bridge;
 
+	if (!bridge->encoder)
+		return -EPROBE_DEFER;
+
+	encoder = bridge->encoder;
+	drm = encoder->dev;
+
 	out_bridge  = of_drm_find_bridge(device->dev.of_node);
 	if (out_bridge) {
-		drm_bridge_attach(encoder, out_bridge, NULL, 0);
+		drm_bridge_attach(encoder, out_bridge, bridge, 0);
 		dsi->out_bridge = out_bridge;
 		list_splice_init(&encoder->bridge_chain, &dsi->bridge_chain);
 	} else {
@@ -1715,6 +1740,10 @@  static int exynos_dsi_bind(struct device *dev, struct device *master,
 		of_node_put(in_bridge_node);
 	}
 
+	ret = drm_bridge_attach(encoder, &dsi->bridge, in_bridge, 0);
+	if (ret)
+		return ret;
+
 	return mipi_dsi_host_register(&dsi->dsi_host);
 }
 
@@ -1740,6 +1769,7 @@  static struct exynos_dsi *__exynos_dsi_probe(struct platform_device *pdev)
 	struct resource *res;
 	struct exynos_dsi *dsi;
 	int ret, i;
+	struct drm_bridge *bridge;
 
 	dsi = devm_kzalloc(dev, sizeof(*dsi), GFP_KERNEL);
 	if (!dsi)
@@ -1823,11 +1853,20 @@  static struct exynos_dsi *__exynos_dsi_probe(struct platform_device *pdev)
 
 	pm_runtime_enable(dev);
 
+	bridge = &dsi->bridge;
+	bridge->driver_private = dsi;
+	bridge->funcs = &exynos_dsi_bridge_funcs;
+	bridge->of_node = dev->of_node;
+
+	drm_bridge_add(bridge);
+
 	return dsi;
 }
 
 static void __exynos_dsi_remove(struct exynos_dsi *dsi)
 {
+	drm_bridge_remove(&dsi->bridge);
+
 	pm_runtime_disable(dsi->dev);
 }