When the panel-driver is build as a module it currently fails hard as the
panel cannot be probed directly:

dw_mipi_dsi_bind()
  __dw_mipi_dsi_probe()
    creates dsi bus
    creates panel device
    triggers panel module load
    panel not probed (module not loaded or panel probe slow)
  drm_bridge_attach
    fails with -EINVAL due to empty panel_bridge

Additionally the panel probing can run concurrently with dsi bringup
making it possible that the panel can already be found but dsi-attach
hasn't finished running.

The newly added function provides the ability for glue drivers to
check if a dsi device was actually attached and also protects
the attach part to prevent concurrency issues from panel-assignment
and drm_bridge_create.

Using that check glue drivers are able to for example defer probe/bind
in the case that the panel is not completely set up yet.

Signed-off-by: Heiko Stuebner <[email protected]>
---
 drivers/gpu/drm/bridge/synopsys/dw-mipi-dsi.c | 25 +++++++++++++++++++
 include/drm/bridge/dw_mipi_dsi.h              |  1 +
 2 files changed, 26 insertions(+)

diff --git a/drivers/gpu/drm/bridge/synopsys/dw-mipi-dsi.c 
b/drivers/gpu/drm/bridge/synopsys/dw-mipi-dsi.c
index bb4aeca5c0f9..88fed22ff3f6 100644
--- a/drivers/gpu/drm/bridge/synopsys/dw-mipi-dsi.c
+++ b/drivers/gpu/drm/bridge/synopsys/dw-mipi-dsi.c
@@ -12,6 +12,7 @@
 #include <linux/component.h>
 #include <linux/iopoll.h>
 #include <linux/module.h>
+#include <linux/mutex.h>
 #include <linux/of_device.h>
 #include <linux/pm_runtime.h>
 #include <linux/reset.h>
@@ -219,6 +220,7 @@ struct dw_mipi_dsi {
        struct drm_bridge bridge;
        struct mipi_dsi_host dsi_host;
        struct drm_bridge *panel_bridge;
+       struct mutex panel_mutex;
        struct device *dev;
        void __iomem *base;
 
@@ -296,10 +298,14 @@ static int dw_mipi_dsi_host_attach(struct mipi_dsi_host 
*host,
                        return PTR_ERR(bridge);
        }
 
+       mutex_lock(&dsi->panel_mutex);
+
        dsi->panel_bridge = bridge;
 
        drm_bridge_add(&dsi->bridge);
 
+       mutex_unlock(&dsi->panel_mutex);
+
        return 0;
 }
 
@@ -308,13 +314,30 @@ static int dw_mipi_dsi_host_detach(struct mipi_dsi_host 
*host,
 {
        struct dw_mipi_dsi *dsi = host_to_dsi(host);
 
+       mutex_lock(&dsi->panel_mutex);
+
+       dsi->panel_bridge = NULL;
        drm_of_panel_bridge_remove(host->dev->of_node, 1, 0);
 
        drm_bridge_remove(&dsi->bridge);
 
+       mutex_unlock(&dsi->panel_mutex);
+
        return 0;
 }
 
+bool dw_mipi_dsi_device_attached(struct dw_mipi_dsi *dsi)
+{
+       bool output;
+
+       mutex_lock(&dsi->panel_mutex);
+       output = !!dsi->panel_bridge;
+       mutex_unlock(&dsi->panel_mutex);
+
+       return output;
+}
+EXPORT_SYMBOL_GPL(dw_mipi_dsi_device_attached);
+
 static void dw_mipi_message_config(struct dw_mipi_dsi *dsi,
                                   const struct mipi_dsi_msg *msg)
 {
@@ -867,6 +890,8 @@ __dw_mipi_dsi_probe(struct platform_device *pdev,
        dsi->dev = dev;
        dsi->plat_data = plat_data;
 
+       mutex_init(&dsi->panel_mutex);
+
        if (!plat_data->phy_ops->init || !plat_data->phy_ops->get_lane_mbps) {
                DRM_ERROR("Phy not properly configured\n");
                return ERR_PTR(-ENODEV);
diff --git a/include/drm/bridge/dw_mipi_dsi.h b/include/drm/bridge/dw_mipi_dsi.h
index 6d7f8eb5d9f2..131ff2569ed4 100644
--- a/include/drm/bridge/dw_mipi_dsi.h
+++ b/include/drm/bridge/dw_mipi_dsi.h
@@ -31,6 +31,7 @@ struct dw_mipi_dsi_plat_data {
        void *priv_data;
 };
 
+bool dw_mipi_dsi_device_attached(struct dw_mipi_dsi *dsi);
 struct dw_mipi_dsi *dw_mipi_dsi_probe(struct platform_device *pdev,
                                      const struct dw_mipi_dsi_plat_data
                                      *plat_data);
-- 
2.17.0

_______________________________________________
dri-devel mailing list
[email protected]
https://lists.freedesktop.org/mailman/listinfo/dri-devel

Reply via email to