Hi Michael, On 11.09.2020 15:54, Michael Tretter wrote: > Make the exynos_dsi driver a full drm bridge that can be found and used > from other drivers. > > Other drivers can only attach to the bridge, if a mipi dsi device > already attached to the bridge. This allows to defer the probe of the > display pipe until the downstream bridges are available, too. > > Signed-off-by: Michael Tretter <m.tretter@xxxxxxxxxxxxxx> This one (and the whole series applied) still fails on Exynos boards: [drm] Exynos DRM: using 11c00000.fimd device for DMA mapping operations exynos-drm exynos-drm: bound 11c00000.fimd (ops fimd_component_ops) OF: graph: no port node found in /soc/dsi@11c80000 8<--- cut here --- Unable to handle kernel NULL pointer dereference at virtual address 00000084 pgd = (ptrval) [00000084] *pgd=00000000 Internal error: Oops: 5 [#1] PREEMPT SMP ARM Modules linked in: CPU: 1 PID: 1 Comm: swapper/0 Not tainted 5.9.0-rc4-next-20200911-00010-g417dc70d70ec #1608 Hardware name: Samsung Exynos (Flattened Device Tree) PC is at drm_bridge_attach+0x18/0x164 LR is at exynos_dsi_bind+0x88/0xa8 pc : [<c0628c08>] lr : [<c064d560>] psr: 20000013 sp : ef0dfca8 ip : 00000002 fp : c13190e0 r10: 00000000 r9 : ee46d580 r8 : c13190e0 r7 : ee438800 r6 : 00000018 r5 : ef253810 r4 : ef39e840 r3 : 00000000 r2 : 00000018 r1 : ef39e888 r0 : ef39e840 Flags: nzCv IRQs on FIQs on Mode SVC_32 ISA ARM Segment none Control: 10c5387d Table: 4000404a DAC: 00000051 Process swapper/0 (pid: 1, stack limit = 0x(ptrval)) Stack: (0xef0dfca8 to 0xef0e0000) ... [<c0628c08>] (drm_bridge_attach) from [<c064d560>] (exynos_dsi_bind+0x88/0xa8) [<c064d560>] (exynos_dsi_bind) from [<c066a800>] (component_bind_all+0xfc/0x290) [<c066a800>] (component_bind_all) from [<c0649dc0>] (exynos_drm_bind+0xe4/0x19c) [<c0649dc0>] (exynos_drm_bind) from [<c066ad74>] (try_to_bring_up_master+0x1e4/0x2c4) [<c066ad74>] (try_to_bring_up_master) from [<c066b2b4>] (component_master_add_with_match+0xd4/0x108) [<c066b2b4>] (component_master_add_with_match) from [<c0649ae8>] (exynos_drm_platform_probe+0xe4/0x110) [<c0649ae8>] (exynos_drm_platform_probe) from [<c0674e6c>] (platform_drv_probe+0x6c/0xa4) [<c0674e6c>] (platform_drv_probe) from [<c067242c>] (really_probe+0x200/0x4fc) [<c067242c>] (really_probe) from [<c06728f0>] (driver_probe_device+0x78/0x1fc) [<c06728f0>] (driver_probe_device) from [<c0672cd8>] (device_driver_attach+0x58/0x60) [<c0672cd8>] (device_driver_attach) from [<c0672dbc>] (__driver_attach+0xdc/0x174) [<c0672dbc>] (__driver_attach) from [<c06701b4>] (bus_for_each_dev+0x68/0xb4) [<c06701b4>] (bus_for_each_dev) from [<c06714e8>] (bus_add_driver+0x158/0x214) [<c06714e8>] (bus_add_driver) from [<c0673c1c>] (driver_register+0x78/0x110) [<c0673c1c>] (driver_register) from [<c0649ca8>] (exynos_drm_init+0xe4/0x118) [<c0649ca8>] (exynos_drm_init) from [<c0102484>] (do_one_initcall+0x8c/0x42c) [<c0102484>] (do_one_initcall) from [<c11011c0>] (kernel_init_freeable+0x190/0x1dc) [<c11011c0>] (kernel_init_freeable) from [<c0af7880>] (kernel_init+0x8/0x118) [<c0af7880>] (kernel_init) from [<c0100114>] (ret_from_fork+0x14/0x20) Exception stack(0xef0dffb0 to 0xef0dfff8) ... ---[ end trace ee27f313f9ed9da1 ]--- # arm-linux-gnueabi-addr2line -e vmlinux c0628c08 drivers/gpu/drm/drm_bridge.c:184 (discriminator 1) I will try to debug it a bit more today. > --- > v2: > - move attach of out_bridge to bridge_attach > - add bridge_detach > - don't cleanup encoder if create_connector failed > --- > drivers/gpu/drm/exynos/exynos_drm_dsi.c | 103 +++++++++++++++++------- > 1 file changed, 75 insertions(+), 28 deletions(-) > > diff --git a/drivers/gpu/drm/exynos/exynos_drm_dsi.c b/drivers/gpu/drm/exynos/exynos_drm_dsi.c > index 2d75f9877dc0..5e7c1a99a3ee 100644 > --- a/drivers/gpu/drm/exynos/exynos_drm_dsi.c > +++ b/drivers/gpu/drm/exynos/exynos_drm_dsi.c > @@ -266,6 +266,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; > @@ -1602,6 +1603,60 @@ 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; > + struct drm_encoder *encoder = bridge->encoder; > + int ret; > + > + if (!dsi->out_bridge && !dsi->panel) > + return -EPROBE_DEFER; > + > + if (dsi->out_bridge) { > + ret = drm_bridge_attach(encoder, dsi->out_bridge, > + bridge, flags); > + if (ret) > + return ret; > + list_splice_init(&encoder->bridge_chain, &dsi->bridge_chain); > + } else { > + ret = exynos_dsi_create_connector(encoder); > + if (ret) > + return ret; > + > + if (dsi->panel) { > + dsi->connector.status = connector_status_connected; > + } > + } > + > + return 0; > +} > + > +static void exynos_dsi_bridge_detach(struct drm_bridge *bridge) > +{ > + struct exynos_dsi *dsi = bridge->driver_private; > + struct drm_encoder *encoder = bridge->encoder; > + struct drm_device *drm = encoder->dev; > + > + if (dsi->panel) { > + mutex_lock(&drm->mode_config.mutex); > + exynos_dsi_disable(&dsi->encoder); > + dsi->panel = NULL; > + dsi->connector.status = connector_status_disconnected; > + mutex_unlock(&drm->mode_config.mutex); > + } else { > + if (dsi->out_bridge->funcs->detach) > + dsi->out_bridge->funcs->detach(dsi->out_bridge); > + dsi->out_bridge = NULL; > + INIT_LIST_HEAD(&dsi->bridge_chain); > + } > +} > + > +static const struct drm_bridge_funcs exynos_dsi_bridge_funcs = { > + .attach = exynos_dsi_bridge_attach, > + .detach = exynos_dsi_bridge_detach, > +}; > + > MODULE_DEVICE_TABLE(of, exynos_dsi_of_match); > > static int exynos_dsi_host_attach(struct mipi_dsi_host *host, > @@ -1609,25 +1664,12 @@ static int exynos_dsi_host_attach(struct mipi_dsi_host *host, > { > struct exynos_dsi *dsi = host_to_dsi(host); > const struct exynos_dsi_host_ops *ops = dsi->driver_data->host_ops; > - struct drm_encoder *encoder = &dsi->encoder; > struct drm_bridge *out_bridge; > > - out_bridge = of_drm_find_bridge(device->dev.of_node); > + out_bridge = of_drm_find_bridge(device->dev.of_node); > if (out_bridge) { > - drm_bridge_attach(encoder, out_bridge, NULL, 0); > dsi->out_bridge = out_bridge; > - list_splice_init(&encoder->bridge_chain, &dsi->bridge_chain); > } else { > - int ret = exynos_dsi_create_connector(encoder); > - > - if (ret) { > - DRM_DEV_ERROR(dsi->dev, > - "failed to create connector ret = %d\n", > - ret); > - drm_encoder_cleanup(encoder); > - return ret; > - } > - > dsi->panel = of_drm_find_panel(device->dev.of_node); > if (IS_ERR(dsi->panel)) > dsi->panel = NULL; > @@ -1662,20 +1704,6 @@ static int exynos_dsi_host_detach(struct mipi_dsi_host *host, > { > struct exynos_dsi *dsi = host_to_dsi(host); > const struct exynos_dsi_host_ops *ops = dsi->driver_data->host_ops; > - struct drm_device *drm = dsi->encoder.dev; > - > - if (dsi->panel) { > - mutex_lock(&drm->mode_config.mutex); > - exynos_dsi_disable(&dsi->encoder); > - dsi->panel = NULL; > - dsi->connector.status = connector_status_disconnected; > - mutex_unlock(&drm->mode_config.mutex); > - } else { > - if (dsi->out_bridge->funcs->detach) > - dsi->out_bridge->funcs->detach(dsi->out_bridge); > - dsi->out_bridge = NULL; > - INIT_LIST_HEAD(&dsi->bridge_chain); > - } > > if (ops && ops->detach) > ops->detach(dsi->dsi_host.dev, device); > @@ -1786,7 +1814,15 @@ 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) > + goto err; > + > return 0; > + > +err: > + drm_encoder_cleanup(encoder); > + return ret; > } > > static void exynos_dsi_unbind(struct device *dev, struct device *master, > @@ -1796,6 +1832,8 @@ static void exynos_dsi_unbind(struct device *dev, struct device *master, > struct drm_encoder *encoder = &dsi->encoder; > > exynos_dsi_disable(encoder); > + > + drm_encoder_cleanup(encoder); > } > > static const struct component_ops exynos_dsi_component_ops = { > @@ -1806,6 +1844,7 @@ static const struct component_ops exynos_dsi_component_ops = { > static struct exynos_dsi *__exynos_dsi_probe(struct platform_device *pdev) > { > struct device *dev = &pdev->dev; > + struct drm_bridge *bridge; > struct resource *res; > struct exynos_dsi *dsi; > int ret, i; > @@ -1894,11 +1933,19 @@ static struct exynos_dsi *__exynos_dsi_probe(struct platform_device *pdev) > if (ret) > return ERR_PTR(ret); > > + 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); > + > mipi_dsi_host_unregister(&dsi->dsi_host); > } > Best regards -- Marek Szyprowski, PhD Samsung R&D Institute Poland _______________________________________________ dri-devel mailing list dri-devel@xxxxxxxxxxxxxxxxxxxxx https://lists.freedesktop.org/mailman/listinfo/dri-devel