#include <drm/drm_crtc_helper.h>
 #include <drm/drm_edid.h>
 #include <drm/drm_mipi_dsi.h>
+#include <drm/drm_of.h>
 #include <drm/drm_panel.h>
 #include <linux/clk.h>
 #include <linux/clk-provider.h>
        struct mipi_dsi_host dsi_host;
        struct drm_encoder *encoder;
        struct drm_bridge *bridge;
-       bool is_panel_bridge;
 
        void __iomem *regs;
 
                               struct mipi_dsi_device *device)
 {
        struct vc4_dsi *dsi = host_to_dsi(host);
-       int ret = 0;
 
        dsi->lanes = device->lanes;
        dsi->channel = device->channel;
                return 0;
        }
 
-       dsi->bridge = of_drm_find_bridge(device->dev.of_node);
-       if (!dsi->bridge) {
-               struct drm_panel *panel =
-                       of_drm_find_panel(device->dev.of_node);
-
-               dsi->bridge = drm_panel_bridge_add(panel,
-                                                  DRM_MODE_CONNECTOR_DSI);
-               if (IS_ERR(dsi->bridge)) {
-                       ret = PTR_ERR(dsi->bridge);
-                       dsi->bridge = NULL;
-                       return ret;
-               }
-               dsi->is_panel_bridge = true;
-       }
-
-       return drm_bridge_attach(dsi->encoder, dsi->bridge, NULL);
+       return 0;
 }
 
 static int vc4_dsi_host_detach(struct mipi_dsi_host *host,
                               struct mipi_dsi_device *device)
 {
-       struct vc4_dsi *dsi = host_to_dsi(host);
-
-       if (dsi->is_panel_bridge) {
-               drm_panel_bridge_remove(dsi->bridge);
-               dsi->bridge = NULL;
-       }
-
        return 0;
 }
 
        struct platform_device *pdev = to_platform_device(dev);
        struct drm_device *drm = dev_get_drvdata(master);
        struct vc4_dev *vc4 = to_vc4_dev(drm);
-       struct vc4_dsi *dsi;
+       struct vc4_dsi *dsi = dev_get_drvdata(dev);
        struct vc4_dsi_encoder *vc4_dsi_encoder;
+       struct drm_panel *panel;
        const struct of_device_id *match;
        dma_cap_mask_t dma_mask;
        int ret;
 
-       dsi = devm_kzalloc(dev, sizeof(*dsi), GFP_KERNEL);
-       if (!dsi)
-               return -ENOMEM;
-
        match = of_match_device(vc4_dsi_dt_match, dev);
        if (!match)
                return -ENODEV;
        vc4_dsi_encoder->dsi = dsi;
        dsi->encoder = &vc4_dsi_encoder->base.base;
 
-       dsi->pdev = pdev;
        dsi->regs = vc4_ioremap_regs(pdev, 0);
        if (IS_ERR(dsi->regs))
                return PTR_ERR(dsi->regs);
                return ret;
        }
 
+       ret = drm_of_find_panel_or_bridge(dev->of_node, 0, 0,
+                                         &panel, &dsi->bridge);
+       if (ret)
+               return ret;
+
+       if (panel) {
+               dsi->bridge = devm_drm_panel_bridge_add(dev, panel,
+                                                       DRM_MODE_CONNECTOR_DSI);
+               if (IS_ERR(dsi->bridge))
+                       return PTR_ERR(dsi->bridge);
+       }
+
        /* The esc clock rate is supposed to always be 100Mhz. */
        ret = clk_set_rate(dsi->escape_clock, 100 * 1000000);
        if (ret) {
                         DRM_MODE_ENCODER_DSI, NULL);
        drm_encoder_helper_add(dsi->encoder, &vc4_dsi_encoder_helper_funcs);
 
-       dsi->dsi_host.ops = &vc4_dsi_host_ops;
-       dsi->dsi_host.dev = dev;
-
-       mipi_dsi_host_register(&dsi->dsi_host);
-
-       dev_set_drvdata(dev, dsi);
+       ret = drm_bridge_attach(dsi->encoder, dsi->bridge, NULL);
+       if (ret) {
+               dev_err(dev, "bridge attach failed: %d\n", ret);
+               return ret;
+       }
 
        pm_runtime_enable(dev);
 
 
        vc4_dsi_encoder_destroy(dsi->encoder);
 
-       mipi_dsi_host_unregister(&dsi->dsi_host);
-
        if (dsi->port == 1)
                vc4->dsi1 = NULL;
 }
 
 static int vc4_dsi_dev_probe(struct platform_device *pdev)
 {
-       return component_add(&pdev->dev, &vc4_dsi_ops);
+       struct device *dev = &pdev->dev;
+       struct vc4_dsi *dsi;
+       int ret;
+
+       dsi = devm_kzalloc(dev, sizeof(*dsi), GFP_KERNEL);
+       if (!dsi)
+               return -ENOMEM;
+       dev_set_drvdata(dev, dsi);
+
+       dsi->pdev = pdev;
+
+       /* Note, the initialization sequence for DSI and panels is
+        * tricky.  The component bind above won't get past its
+        * -EPROBE_DEFER until the panel/bridge probes.  The
+        * panel/bridge will return -EPROBE_DEFER until it has a
+        * mipi_dsi_host to register its device to.  So, we register
+        * the host during pdev probe time, so vc4 as a whole can then
+        * -EPROBE_DEFER its component bind process until the panel
+        * successfully attaches.
+        */
+       dsi->dsi_host.ops = &vc4_dsi_host_ops;
+       dsi->dsi_host.dev = dev;
+       mipi_dsi_host_register(&dsi->dsi_host);
+
+       ret = component_add(&pdev->dev, &vc4_dsi_ops);
+       if (ret) {
+               mipi_dsi_host_unregister(&dsi->dsi_host);
+               return ret;
+       }
+
+       return 0;
 }
 
 static int vc4_dsi_dev_remove(struct platform_device *pdev)
 {
+       struct device *dev = &pdev->dev;
+       struct vc4_dsi *dsi = dev_get_drvdata(dev);
+
        component_del(&pdev->dev, &vc4_dsi_ops);
+       mipi_dsi_host_unregister(&dsi->dsi_host);
+
        return 0;
 }