On Tue, 15 Aug 2017 16:47:20 -0700 Eric Anholt <eric@xxxxxxxxxx> wrote: > We need the following things to happen in sequence: > > DSI host creation > DSI device creation in the panel driver (needs DSI host) > DSI device attach from panel to host. > DSI drm_panel_add() > DSI encoder creation > DSI encoder's DRM panel/bridge attach > > Unless we allow device creation while the host isn't up yet, we need > to break the -EPROBE_DEFER deadlock between the panel driver looking > up the host and the host driver looking up the panel. We can do so by > moving the DSI host creation outside of the component bind loop, and > the panel/bridge lookup/attach into the component bind process. > > Signed-off-by: Eric Anholt <eric@xxxxxxxxxx> Reviewed-by: Boris Brezillon <boris.brezillon@xxxxxxxxxxxxxxxxxx> > --- > drivers/gpu/drm/vc4/vc4_dsi.c | 97 +++++++++++++++++++++++++------------------ > 1 file changed, 57 insertions(+), 40 deletions(-) > > diff --git a/drivers/gpu/drm/vc4/vc4_dsi.c b/drivers/gpu/drm/vc4/vc4_dsi.c > index 2516cd3a1d87..ec1d646b3151 100644 > --- a/drivers/gpu/drm/vc4/vc4_dsi.c > +++ b/drivers/gpu/drm/vc4/vc4_dsi.c > @@ -33,6 +33,7 @@ > #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> > @@ -504,7 +505,6 @@ struct vc4_dsi { > struct mipi_dsi_host dsi_host; > struct drm_encoder *encoder; > struct drm_bridge *bridge; > - bool is_panel_bridge; > > void __iomem *regs; > > @@ -1289,7 +1289,6 @@ static int vc4_dsi_host_attach(struct mipi_dsi_host *host, > struct mipi_dsi_device *device) > { > struct vc4_dsi *dsi = host_to_dsi(host); > - int ret = 0; > > dsi->lanes = device->lanes; > dsi->channel = device->channel; > @@ -1324,34 +1323,12 @@ static int vc4_dsi_host_attach(struct mipi_dsi_host *host, > 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; > } > > @@ -1493,16 +1470,13 @@ static int vc4_dsi_bind(struct device *dev, struct device *master, void *data) > 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; > @@ -1517,7 +1491,6 @@ static int vc4_dsi_bind(struct device *dev, struct device *master, void *data) > 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); > @@ -1598,6 +1571,18 @@ static int vc4_dsi_bind(struct device *dev, struct device *master, void *data) > 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) { > @@ -1616,12 +1601,11 @@ static int vc4_dsi_bind(struct device *dev, struct device *master, void *data) > 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); > > @@ -1639,8 +1623,6 @@ static void vc4_dsi_unbind(struct device *dev, struct device *master, > > vc4_dsi_encoder_destroy(dsi->encoder); > > - mipi_dsi_host_unregister(&dsi->dsi_host); > - > if (dsi->port == 1) > vc4->dsi1 = NULL; > } > @@ -1652,12 +1634,47 @@ static const struct component_ops vc4_dsi_ops = { > > 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; > } > _______________________________________________ dri-devel mailing list dri-devel@xxxxxxxxxxxxxxxxxxxxx https://lists.freedesktop.org/mailman/listinfo/dri-devel