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.tret...@pengutronix.de>

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@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel

Reply via email to