Some display panels would come up with a non-DSI output which
can have an option to connect DSI interface by means of bridge
convertor.

This DSI to non-DSI bridge convertor would require a bridge
driver that would communicate the DSI controller for bridge
functionalities.

So, add support for bridge functionalities in Allwinner DSI
controller.

Signed-off-by: Jagan Teki <ja...@amarulasolutions.com>
---
 drivers/gpu/drm/sun4i/sun6i_mipi_dsi.c | 65 +++++++++++++++++++-------
 drivers/gpu/drm/sun4i/sun6i_mipi_dsi.h |  1 +
 2 files changed, 49 insertions(+), 17 deletions(-)

diff --git a/drivers/gpu/drm/sun4i/sun6i_mipi_dsi.c 
b/drivers/gpu/drm/sun4i/sun6i_mipi_dsi.c
index 0960b96b62cc..64d74313b842 100644
--- a/drivers/gpu/drm/sun4i/sun6i_mipi_dsi.c
+++ b/drivers/gpu/drm/sun4i/sun6i_mipi_dsi.c
@@ -781,6 +781,9 @@ static void sun6i_dsi_encoder_enable(struct drm_encoder 
*encoder)
        if (!IS_ERR(dsi->panel))
                drm_panel_prepare(dsi->panel);
 
+       if (!IS_ERR(dsi->bridge))
+               drm_bridge_pre_enable(dsi->bridge);
+
        /*
         * FIXME: This should be moved after the switch to HS mode.
         *
@@ -796,6 +799,9 @@ static void sun6i_dsi_encoder_enable(struct drm_encoder 
*encoder)
        if (!IS_ERR(dsi->panel))
                drm_panel_enable(dsi->panel);
 
+       if (!IS_ERR(dsi->bridge))
+               drm_bridge_enable(dsi->bridge);
+
        sun6i_dsi_start(dsi, DSI_START_HSC);
 
        udelay(1000);
@@ -812,6 +818,9 @@ static void sun6i_dsi_encoder_disable(struct drm_encoder 
*encoder)
        if (!IS_ERR(dsi->panel)) {
                drm_panel_disable(dsi->panel);
                drm_panel_unprepare(dsi->panel);
+       } else if (!IS_ERR(dsi->bridge)) {
+               drm_bridge_disable(dsi->bridge);
+               drm_bridge_post_disable(dsi->bridge);
        }
 
        phy_power_off(dsi->dphy);
@@ -973,11 +982,16 @@ static int sun6i_dsi_attach(struct mipi_dsi_host *host,
        struct sun6i_dsi *dsi = host_to_sun6i_dsi(host);
 
        dsi->device = device;
-       dsi->panel = of_drm_find_panel(device->dev.of_node);
-       if (IS_ERR(dsi->panel))
-               return PTR_ERR(dsi->panel);
 
-       dev_info(host->dev, "Attached device %s\n", device->name);
+       dsi->bridge = of_drm_find_bridge(device->dev.of_node);
+       if (!dsi->bridge) {
+               dsi->panel = of_drm_find_panel(device->dev.of_node);
+               if (IS_ERR(dsi->panel))
+                       return PTR_ERR(dsi->panel);
+       }
+
+       dev_info(host->dev, "Attached %s %s\n",
+                dsi->bridge ? "bridge" : "panel", device->name);
 
        return 0;
 }
@@ -1055,8 +1069,10 @@ static int sun6i_dsi_bind(struct device *dev, struct 
device *master,
        struct sun4i_tcon *tcon0 = sun4i_get_tcon0(drm);
        int ret;
 
-       if (!dsi->panel)
+       if (!(dsi->panel || dsi->bridge)) {
+               dev_info(drm->dev, "No panel or bridge found... DSI output 
disabled\n");
                return -EPROBE_DEFER;
+       }
 
        dsi->drv = drv;
 
@@ -1078,19 +1094,29 @@ static int sun6i_dsi_bind(struct device *dev, struct 
device *master,
        }
        dsi->encoder.possible_crtcs = BIT(0);
 
-       drm_connector_helper_add(&dsi->connector,
-                                &sun6i_dsi_connector_helper_funcs);
-       ret = drm_connector_init(drm, &dsi->connector,
-                                &sun6i_dsi_connector_funcs,
-                                DRM_MODE_CONNECTOR_DSI);
-       if (ret) {
-               dev_err(dsi->dev,
-                       "Couldn't initialise the DSI connector\n");
-               goto err_cleanup_connector;
+       if (dsi->panel) {
+               drm_connector_helper_add(&dsi->connector,
+                                        &sun6i_dsi_connector_helper_funcs);
+               ret = drm_connector_init(drm, &dsi->connector,
+                                        &sun6i_dsi_connector_funcs,
+                                        DRM_MODE_CONNECTOR_DSI);
+               if (ret) {
+                       dev_err(dsi->dev,
+                               "Couldn't initialise the DSI connector\n");
+                       goto err_cleanup_connector;
+               }
+
+               drm_connector_attach_encoder(&dsi->connector, &dsi->encoder);
+               drm_panel_attach(dsi->panel, &dsi->connector);
        }
 
-       drm_connector_attach_encoder(&dsi->connector, &dsi->encoder);
-       drm_panel_attach(dsi->panel, &dsi->connector);
+       if (dsi->bridge) {
+               ret = drm_bridge_attach(&dsi->encoder, dsi->bridge, NULL);
+               if (ret) {
+                       dev_err(dsi->dev, "Couldn't attach the DSI bridge\n");
+                       goto err_cleanup_connector;
+               }
+       }
 
        return 0;
 
@@ -1104,7 +1130,12 @@ static void sun6i_dsi_unbind(struct device *dev, struct 
device *master,
 {
        struct sun6i_dsi *dsi = dev_get_drvdata(dev);
 
-       drm_panel_detach(dsi->panel);
+       if (dsi->panel)
+               drm_panel_detach(dsi->panel);
+
+       if (dsi->bridge)
+               drm_bridge_detach(dsi->bridge);
+
 }
 
 static const struct component_ops sun6i_dsi_ops = {
diff --git a/drivers/gpu/drm/sun4i/sun6i_mipi_dsi.h 
b/drivers/gpu/drm/sun4i/sun6i_mipi_dsi.h
index 5c4983212f89..76874ff8e3ef 100644
--- a/drivers/gpu/drm/sun4i/sun6i_mipi_dsi.h
+++ b/drivers/gpu/drm/sun4i/sun6i_mipi_dsi.h
@@ -36,6 +36,7 @@ struct sun6i_dsi {
        struct sun4i_tcon       *tcon;
        struct mipi_dsi_device  *device;
        struct drm_panel        *panel;
+       struct drm_bridge       *bridge;
        const struct sun6i_dsi_variant  *variant;
 };
 
-- 
2.18.0.321.gffc6fa0e3

_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel

Reply via email to