Message ID | 20230804-tc358768-v1-11-1afd44b7826b@ideasonboard.com (mailing list archive) |
---|---|
State | New, archived |
Headers | show |
Series | drm/bridge: tc358768: Fixes and timings improvements | expand |
On 04/08/2023 13:44, Tomi Valkeinen wrote: I would rather have a commit message than a blank one. > Signed-off-by: Tomi Valkeinen <tomi.valkeinen@ideasonboard.com> > --- > drivers/gpu/drm/bridge/tc358768.c | 64 +++++++++++++++++++++++++++------------ > 1 file changed, 45 insertions(+), 19 deletions(-) > > diff --git a/drivers/gpu/drm/bridge/tc358768.c b/drivers/gpu/drm/bridge/tc358768.c > index ea19de5509ed..a567f136ddc7 100644 > --- a/drivers/gpu/drm/bridge/tc358768.c > +++ b/drivers/gpu/drm/bridge/tc358768.c > @@ -131,8 +131,17 @@ static const char * const tc358768_supplies[] = { > > struct tc358768_dsi_output { > struct mipi_dsi_device *dev; > + > + /* Legacy field if DRM_BRIDGE_ATTACH_NO_CONNECTOR is not used */ > struct drm_panel *panel; > - struct drm_bridge *bridge; > + > + /* > + * If DRM_BRIDGE_ATTACH_NO_CONNECTOR is not used and a panel is attached > + * to tc358768, 'next_bridge' contains the bridge the driver created > + * with drm_panel_bridge_add_typed(). Otherwise 'next_bridge' contains > + * the next bridge the driver found. > + */ > + struct drm_bridge *next_bridge; why it is better to call it next_bridge than just bridge? Is there a prev_bridge also? > }; > > struct tc358768_priv { > @@ -391,8 +400,6 @@ static int tc358768_dsi_host_attach(struct mipi_dsi_host *host, > struct mipi_dsi_device *dev) > { > struct tc358768_priv *priv = dsi_host_to_tc358768(host); > - struct drm_bridge *bridge; > - struct drm_panel *panel; > struct device_node *ep; > int ret; > > @@ -420,21 +427,7 @@ static int tc358768_dsi_host_attach(struct mipi_dsi_host *host, > return -ENOTSUPP; > } > > - ret = drm_of_find_panel_or_bridge(host->dev->of_node, 1, 0, &panel, > - &bridge); > - if (ret) > - return ret; > - > - if (panel) { > - bridge = drm_panel_bridge_add_typed(panel, > - DRM_MODE_CONNECTOR_DSI); > - if (IS_ERR(bridge)) > - return PTR_ERR(bridge); > - } > - > priv->output.dev = dev; > - priv->output.bridge = bridge; > - priv->output.panel = panel; > > priv->dsi_lanes = dev->lanes; > priv->dsi_bpp = mipi_dsi_pixel_format_to_bpp(dev->format); > @@ -463,7 +456,7 @@ static int tc358768_dsi_host_detach(struct mipi_dsi_host *host, > > drm_bridge_remove(&priv->bridge); > if (priv->output.panel) > - drm_panel_bridge_remove(priv->output.bridge); > + drm_panel_bridge_remove(priv->output.next_bridge); > > return 0; > } > @@ -544,7 +537,40 @@ static int tc358768_bridge_attach(struct drm_bridge *bridge, > return -ENOTSUPP; > } > > - return drm_bridge_attach(bridge->encoder, priv->output.bridge, bridge, > + if (flags & DRM_BRIDGE_ATTACH_NO_CONNECTOR) { > + struct device_node *node; > + > + /* Get the next bridge, connected to port@1. */ > + node = of_graph_get_remote_node(priv->dev->of_node, 1, -1); > + if (!node) > + return -ENODEV; > + > + priv->output.next_bridge = of_drm_find_bridge(node); > + of_node_put(node); > + if (!priv->output.next_bridge) > + return -EPROBE_DEFER; > + } else { > + struct drm_bridge *bridge; > + struct drm_panel *panel; > + int ret; > + > + ret = drm_of_find_panel_or_bridge(priv->dev->of_node, 1, 0, > + &panel, &bridge); > + if (ret) > + return ret; > + > + if (panel) { > + bridge = drm_panel_bridge_add_typed(panel, > + DRM_MODE_CONNECTOR_DSI); > + if (IS_ERR(bridge)) > + return PTR_ERR(bridge); > + } > + > + priv->output.next_bridge = bridge; > + priv->output.panel = panel; > + } > + > + return drm_bridge_attach(bridge->encoder, priv->output.next_bridge, bridge, > flags); > } > >
On 11/08/2023 19:44, Péter Ujfalusi wrote: > > > On 04/08/2023 13:44, Tomi Valkeinen wrote: > > I would rather have a commit message than a blank one. Oops... >> Signed-off-by: Tomi Valkeinen <tomi.valkeinen@ideasonboard.com> >> --- >> drivers/gpu/drm/bridge/tc358768.c | 64 +++++++++++++++++++++++++++------------ >> 1 file changed, 45 insertions(+), 19 deletions(-) >> >> diff --git a/drivers/gpu/drm/bridge/tc358768.c b/drivers/gpu/drm/bridge/tc358768.c >> index ea19de5509ed..a567f136ddc7 100644 >> --- a/drivers/gpu/drm/bridge/tc358768.c >> +++ b/drivers/gpu/drm/bridge/tc358768.c >> @@ -131,8 +131,17 @@ static const char * const tc358768_supplies[] = { >> >> struct tc358768_dsi_output { >> struct mipi_dsi_device *dev; >> + >> + /* Legacy field if DRM_BRIDGE_ATTACH_NO_CONNECTOR is not used */ >> struct drm_panel *panel; >> - struct drm_bridge *bridge; >> + >> + /* >> + * If DRM_BRIDGE_ATTACH_NO_CONNECTOR is not used and a panel is attached >> + * to tc358768, 'next_bridge' contains the bridge the driver created >> + * with drm_panel_bridge_add_typed(). Otherwise 'next_bridge' contains >> + * the next bridge the driver found. >> + */ >> + struct drm_bridge *next_bridge; > > why it is better to call it next_bridge than just bridge? Is there a > prev_bridge also? There is, prev bridge would be the bridge behind tc358768 in the chain. Bridge is tc358768. Next bridge is the following one. Here, it's in the tc358768_dsi_output struct, so bridge is perhaps ok. I just wanted to be extra clear here, as I think it's often called next_bridge in other drivers. Tomi
On 04.08.23 12:44, Tomi Valkeinen wrote: > Signed-off-by: Tomi Valkeinen <tomi.valkeinen@ideasonboard.com> > --- > drivers/gpu/drm/bridge/tc358768.c | 64 +++++++++++++++++++++++++++------------ > 1 file changed, 45 insertions(+), 19 deletions(-) > > diff --git a/drivers/gpu/drm/bridge/tc358768.c b/drivers/gpu/drm/bridge/tc358768.c > index ea19de5509ed..a567f136ddc7 100644 > --- a/drivers/gpu/drm/bridge/tc358768.c > +++ b/drivers/gpu/drm/bridge/tc358768.c > @@ -131,8 +131,17 @@ static const char * const tc358768_supplies[] = { > > struct tc358768_dsi_output { > struct mipi_dsi_device *dev; > + > + /* Legacy field if DRM_BRIDGE_ATTACH_NO_CONNECTOR is not used */ > struct drm_panel *panel; > - struct drm_bridge *bridge; > + > + /* > + * If DRM_BRIDGE_ATTACH_NO_CONNECTOR is not used and a panel is attached > + * to tc358768, 'next_bridge' contains the bridge the driver created > + * with drm_panel_bridge_add_typed(). Otherwise 'next_bridge' contains > + * the next bridge the driver found. > + */ > + struct drm_bridge *next_bridge; > }; > > struct tc358768_priv { > @@ -391,8 +400,6 @@ static int tc358768_dsi_host_attach(struct mipi_dsi_host *host, > struct mipi_dsi_device *dev) > { > struct tc358768_priv *priv = dsi_host_to_tc358768(host); > - struct drm_bridge *bridge; > - struct drm_panel *panel; > struct device_node *ep; > int ret; > > @@ -420,21 +427,7 @@ static int tc358768_dsi_host_attach(struct mipi_dsi_host *host, > return -ENOTSUPP; > } > > - ret = drm_of_find_panel_or_bridge(host->dev->of_node, 1, 0, &panel, > - &bridge); > - if (ret) > - return ret; > - > - if (panel) { > - bridge = drm_panel_bridge_add_typed(panel, > - DRM_MODE_CONNECTOR_DSI); > - if (IS_ERR(bridge)) > - return PTR_ERR(bridge); > - } > - > priv->output.dev = dev; > - priv->output.bridge = bridge; > - priv->output.panel = panel; > > priv->dsi_lanes = dev->lanes; > priv->dsi_bpp = mipi_dsi_pixel_format_to_bpp(dev->format); > @@ -463,7 +456,7 @@ static int tc358768_dsi_host_detach(struct mipi_dsi_host *host, > > drm_bridge_remove(&priv->bridge); > if (priv->output.panel) > - drm_panel_bridge_remove(priv->output.bridge); > + drm_panel_bridge_remove(priv->output.next_bridge); > > return 0; > } > @@ -544,7 +537,40 @@ static int tc358768_bridge_attach(struct drm_bridge *bridge, > return -ENOTSUPP; > } > > - return drm_bridge_attach(bridge->encoder, priv->output.bridge, bridge, > + if (flags & DRM_BRIDGE_ATTACH_NO_CONNECTOR) { > + struct device_node *node; > + > + /* Get the next bridge, connected to port@1. */ > + node = of_graph_get_remote_node(priv->dev->of_node, 1, -1); > + if (!node) > + return -ENODEV; > + > + priv->output.next_bridge = of_drm_find_bridge(node); > + of_node_put(node); > + if (!priv->output.next_bridge) > + return -EPROBE_DEFER; > + } else { > + struct drm_bridge *bridge; > + struct drm_panel *panel; > + int ret; > + > + ret = drm_of_find_panel_or_bridge(priv->dev->of_node, 1, 0, > + &panel, &bridge); > + if (ret) > + return ret; > + > + if (panel) { > + bridge = drm_panel_bridge_add_typed(panel, > + DRM_MODE_CONNECTOR_DSI); > + if (IS_ERR(bridge)) > + return PTR_ERR(bridge); > + } > + > + priv->output.next_bridge = bridge; > + priv->output.panel = panel; > + } > + > + return drm_bridge_attach(bridge->encoder, priv->output.next_bridge, bridge, > flags); > } > > This patch unfortunately breaks the display output on the Asus TF700T: [drm:drm_bridge_attach] *ERROR* failed to attach bridge /i2c-mux/i2c@1/dsi@7 to encoder LVDS-59: -517 tegra-dc 54200000.dc: failed to initialize RGB output: -517 drm drm: failed to initialize 54200000.dc: -517 ------------[ cut here ]------------ WARNING: CPU: 3 PID: 69 at lib/refcount.c:28 tegra_dc_init+0x24/0x5fc refcount_t: underflow; use-after-free. Modules linked in: elants_i2c panel_simple tc358768 atkbd vivaldi_fmap CPU: 3 PID: 69 Comm: kworker/u8:6 Not tainted 6.5.0-rc2-postmarketos-grate #95 Hardware name: NVIDIA Tegra SoC (Flattened Device Tree) Workqueue: events_unbound deferred_probe_work_func unwind_backtrace from show_stack+0x10/0x14 show_stack from dump_stack_lvl+0x40/0x4c dump_stack_lvl from __warn+0x94/0xc0 __warn from warn_slowpath_fmt+0x118/0x16c warn_slowpath_fmt from tegra_dc_init+0x24/0x5fc tegra_dc_init from host1x_device_init+0x84/0x15c host1x_device_init from host1x_drm_probe+0xd8/0x3c4 host1x_drm_probe from really_probe+0xc8/0x2dc really_probe from __driver_probe_device+0x88/0x19c __driver_probe_device from driver_probe_device+0x30/0x104 driver_probe_device from __device_attach_driver+0x94/0x108 __device_attach_driver from bus_for_each_drv+0x80/0xb8 bus_for_each_drv from __device_attach+0xa0/0x190 __device_attach from bus_probe_device+0x88/0x8c bus_probe_device from deferred_probe_work_func+0x78/0xa4 deferred_probe_work_func from process_one_work+0x208/0x420 process_one_work from worker_thread+0x54/0x550 worker_thread from kthread+0xdc/0xf8 kthread from ret_from_fork+0x14/0x2c Exception stack(0xcf9c5fb0 to 0xcf9c5ff8) 5fa0: 00000000 00000000 00000000 00000000 5fc0: 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 5fe0: 00000000 00000000 00000000 00000000 00000013 00000000 ---[ end trace 0000000000000000 ]--- Best regards, Maxim
On 13/08/2023 20:11, Maxim Schwalm wrote: > On 04.08.23 12:44, Tomi Valkeinen wrote: >> Signed-off-by: Tomi Valkeinen <tomi.valkeinen@ideasonboard.com> >> --- >> drivers/gpu/drm/bridge/tc358768.c | 64 +++++++++++++++++++++++++++------------ >> 1 file changed, 45 insertions(+), 19 deletions(-) >> >> diff --git a/drivers/gpu/drm/bridge/tc358768.c b/drivers/gpu/drm/bridge/tc358768.c >> index ea19de5509ed..a567f136ddc7 100644 >> --- a/drivers/gpu/drm/bridge/tc358768.c >> +++ b/drivers/gpu/drm/bridge/tc358768.c >> @@ -131,8 +131,17 @@ static const char * const tc358768_supplies[] = { >> >> struct tc358768_dsi_output { >> struct mipi_dsi_device *dev; >> + >> + /* Legacy field if DRM_BRIDGE_ATTACH_NO_CONNECTOR is not used */ >> struct drm_panel *panel; >> - struct drm_bridge *bridge; >> + >> + /* >> + * If DRM_BRIDGE_ATTACH_NO_CONNECTOR is not used and a panel is attached >> + * to tc358768, 'next_bridge' contains the bridge the driver created >> + * with drm_panel_bridge_add_typed(). Otherwise 'next_bridge' contains >> + * the next bridge the driver found. >> + */ >> + struct drm_bridge *next_bridge; >> }; >> >> struct tc358768_priv { >> @@ -391,8 +400,6 @@ static int tc358768_dsi_host_attach(struct mipi_dsi_host *host, >> struct mipi_dsi_device *dev) >> { >> struct tc358768_priv *priv = dsi_host_to_tc358768(host); >> - struct drm_bridge *bridge; >> - struct drm_panel *panel; >> struct device_node *ep; >> int ret; >> >> @@ -420,21 +427,7 @@ static int tc358768_dsi_host_attach(struct mipi_dsi_host *host, >> return -ENOTSUPP; >> } >> >> - ret = drm_of_find_panel_or_bridge(host->dev->of_node, 1, 0, &panel, >> - &bridge); >> - if (ret) >> - return ret; >> - >> - if (panel) { >> - bridge = drm_panel_bridge_add_typed(panel, >> - DRM_MODE_CONNECTOR_DSI); >> - if (IS_ERR(bridge)) >> - return PTR_ERR(bridge); >> - } >> - >> priv->output.dev = dev; >> - priv->output.bridge = bridge; >> - priv->output.panel = panel; >> >> priv->dsi_lanes = dev->lanes; >> priv->dsi_bpp = mipi_dsi_pixel_format_to_bpp(dev->format); >> @@ -463,7 +456,7 @@ static int tc358768_dsi_host_detach(struct mipi_dsi_host *host, >> >> drm_bridge_remove(&priv->bridge); >> if (priv->output.panel) >> - drm_panel_bridge_remove(priv->output.bridge); >> + drm_panel_bridge_remove(priv->output.next_bridge); >> >> return 0; >> } >> @@ -544,7 +537,40 @@ static int tc358768_bridge_attach(struct drm_bridge *bridge, >> return -ENOTSUPP; >> } >> >> - return drm_bridge_attach(bridge->encoder, priv->output.bridge, bridge, >> + if (flags & DRM_BRIDGE_ATTACH_NO_CONNECTOR) { >> + struct device_node *node; >> + >> + /* Get the next bridge, connected to port@1. */ >> + node = of_graph_get_remote_node(priv->dev->of_node, 1, -1); >> + if (!node) >> + return -ENODEV; >> + >> + priv->output.next_bridge = of_drm_find_bridge(node); >> + of_node_put(node); >> + if (!priv->output.next_bridge) >> + return -EPROBE_DEFER; >> + } else { >> + struct drm_bridge *bridge; >> + struct drm_panel *panel; >> + int ret; >> + >> + ret = drm_of_find_panel_or_bridge(priv->dev->of_node, 1, 0, >> + &panel, &bridge); >> + if (ret) >> + return ret; >> + >> + if (panel) { >> + bridge = drm_panel_bridge_add_typed(panel, >> + DRM_MODE_CONNECTOR_DSI); >> + if (IS_ERR(bridge)) >> + return PTR_ERR(bridge); >> + } >> + >> + priv->output.next_bridge = bridge; >> + priv->output.panel = panel; >> + } >> + >> + return drm_bridge_attach(bridge->encoder, priv->output.next_bridge, bridge, >> flags); >> } >> >> > This patch unfortunately breaks the display output on the Asus TF700T: > > [drm:drm_bridge_attach] *ERROR* failed to attach bridge /i2c-mux/i2c@1/dsi@7 to encoder LVDS-59: -517 > tegra-dc 54200000.dc: failed to initialize RGB output: -517 > drm drm: failed to initialize 54200000.dc: -517 > ------------[ cut here ]------------ > WARNING: CPU: 3 PID: 69 at lib/refcount.c:28 tegra_dc_init+0x24/0x5fc > refcount_t: underflow; use-after-free. > Modules linked in: elants_i2c panel_simple tc358768 atkbd vivaldi_fmap > CPU: 3 PID: 69 Comm: kworker/u8:6 Not tainted 6.5.0-rc2-postmarketos-grate #95 > Hardware name: NVIDIA Tegra SoC (Flattened Device Tree) > Workqueue: events_unbound deferred_probe_work_func > unwind_backtrace from show_stack+0x10/0x14 > show_stack from dump_stack_lvl+0x40/0x4c > dump_stack_lvl from __warn+0x94/0xc0 > __warn from warn_slowpath_fmt+0x118/0x16c > warn_slowpath_fmt from tegra_dc_init+0x24/0x5fc > tegra_dc_init from host1x_device_init+0x84/0x15c > host1x_device_init from host1x_drm_probe+0xd8/0x3c4 > host1x_drm_probe from really_probe+0xc8/0x2dc > really_probe from __driver_probe_device+0x88/0x19c > __driver_probe_device from driver_probe_device+0x30/0x104 > driver_probe_device from __device_attach_driver+0x94/0x108 > __device_attach_driver from bus_for_each_drv+0x80/0xb8 > bus_for_each_drv from __device_attach+0xa0/0x190 > __device_attach from bus_probe_device+0x88/0x8c > bus_probe_device from deferred_probe_work_func+0x78/0xa4 > deferred_probe_work_func from process_one_work+0x208/0x420 > process_one_work from worker_thread+0x54/0x550 > worker_thread from kthread+0xdc/0xf8 > kthread from ret_from_fork+0x14/0x2c > Exception stack(0xcf9c5fb0 to 0xcf9c5ff8) > 5fa0: 00000000 00000000 00000000 00000000 > 5fc0: 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 > 5fe0: 00000000 00000000 00000000 00000000 00000013 00000000 > ---[ end trace 0000000000000000 ]--- Sounds like the Tegra driver has issues cleaning up after getting a EPROBE_DEFER. The tc358768 driver might have an issue with a setup where a panel is directly attached to it. I don't have such a setup, but maybe I can fake it just to see if the probing goes ok. Tomi
On 13/08/2023 20:11, Maxim Schwalm wrote: > On 04.08.23 12:44, Tomi Valkeinen wrote: >> Signed-off-by: Tomi Valkeinen <tomi.valkeinen@ideasonboard.com> >> --- >> drivers/gpu/drm/bridge/tc358768.c | 64 +++++++++++++++++++++++++++------------ >> 1 file changed, 45 insertions(+), 19 deletions(-) >> >> diff --git a/drivers/gpu/drm/bridge/tc358768.c b/drivers/gpu/drm/bridge/tc358768.c >> index ea19de5509ed..a567f136ddc7 100644 >> --- a/drivers/gpu/drm/bridge/tc358768.c >> +++ b/drivers/gpu/drm/bridge/tc358768.c >> @@ -131,8 +131,17 @@ static const char * const tc358768_supplies[] = { >> >> struct tc358768_dsi_output { >> struct mipi_dsi_device *dev; >> + >> + /* Legacy field if DRM_BRIDGE_ATTACH_NO_CONNECTOR is not used */ >> struct drm_panel *panel; >> - struct drm_bridge *bridge; >> + >> + /* >> + * If DRM_BRIDGE_ATTACH_NO_CONNECTOR is not used and a panel is attached >> + * to tc358768, 'next_bridge' contains the bridge the driver created >> + * with drm_panel_bridge_add_typed(). Otherwise 'next_bridge' contains >> + * the next bridge the driver found. >> + */ >> + struct drm_bridge *next_bridge; >> }; >> >> struct tc358768_priv { >> @@ -391,8 +400,6 @@ static int tc358768_dsi_host_attach(struct mipi_dsi_host *host, >> struct mipi_dsi_device *dev) >> { >> struct tc358768_priv *priv = dsi_host_to_tc358768(host); >> - struct drm_bridge *bridge; >> - struct drm_panel *panel; >> struct device_node *ep; >> int ret; >> >> @@ -420,21 +427,7 @@ static int tc358768_dsi_host_attach(struct mipi_dsi_host *host, >> return -ENOTSUPP; >> } >> >> - ret = drm_of_find_panel_or_bridge(host->dev->of_node, 1, 0, &panel, >> - &bridge); >> - if (ret) >> - return ret; >> - >> - if (panel) { >> - bridge = drm_panel_bridge_add_typed(panel, >> - DRM_MODE_CONNECTOR_DSI); >> - if (IS_ERR(bridge)) >> - return PTR_ERR(bridge); >> - } >> - >> priv->output.dev = dev; >> - priv->output.bridge = bridge; >> - priv->output.panel = panel; >> >> priv->dsi_lanes = dev->lanes; >> priv->dsi_bpp = mipi_dsi_pixel_format_to_bpp(dev->format); >> @@ -463,7 +456,7 @@ static int tc358768_dsi_host_detach(struct mipi_dsi_host *host, >> >> drm_bridge_remove(&priv->bridge); >> if (priv->output.panel) >> - drm_panel_bridge_remove(priv->output.bridge); >> + drm_panel_bridge_remove(priv->output.next_bridge); >> >> return 0; >> } >> @@ -544,7 +537,40 @@ static int tc358768_bridge_attach(struct drm_bridge *bridge, >> return -ENOTSUPP; >> } >> >> - return drm_bridge_attach(bridge->encoder, priv->output.bridge, bridge, >> + if (flags & DRM_BRIDGE_ATTACH_NO_CONNECTOR) { >> + struct device_node *node; >> + >> + /* Get the next bridge, connected to port@1. */ >> + node = of_graph_get_remote_node(priv->dev->of_node, 1, -1); >> + if (!node) >> + return -ENODEV; >> + >> + priv->output.next_bridge = of_drm_find_bridge(node); >> + of_node_put(node); >> + if (!priv->output.next_bridge) >> + return -EPROBE_DEFER; >> + } else { >> + struct drm_bridge *bridge; >> + struct drm_panel *panel; >> + int ret; >> + >> + ret = drm_of_find_panel_or_bridge(priv->dev->of_node, 1, 0, >> + &panel, &bridge); >> + if (ret) >> + return ret; >> + >> + if (panel) { >> + bridge = drm_panel_bridge_add_typed(panel, >> + DRM_MODE_CONNECTOR_DSI); >> + if (IS_ERR(bridge)) >> + return PTR_ERR(bridge); >> + } >> + >> + priv->output.next_bridge = bridge; >> + priv->output.panel = panel; >> + } >> + >> + return drm_bridge_attach(bridge->encoder, priv->output.next_bridge, bridge, >> flags); >> } >> >> > This patch unfortunately breaks the display output on the Asus TF700T: > > [drm:drm_bridge_attach] *ERROR* failed to attach bridge /i2c-mux/i2c@1/dsi@7 to encoder LVDS-59: -517 > tegra-dc 54200000.dc: failed to initialize RGB output: -517 > drm drm: failed to initialize 54200000.dc: -517 > ------------[ cut here ]------------ > WARNING: CPU: 3 PID: 69 at lib/refcount.c:28 tegra_dc_init+0x24/0x5fc > refcount_t: underflow; use-after-free. > Modules linked in: elants_i2c panel_simple tc358768 atkbd vivaldi_fmap > CPU: 3 PID: 69 Comm: kworker/u8:6 Not tainted 6.5.0-rc2-postmarketos-grate #95 > Hardware name: NVIDIA Tegra SoC (Flattened Device Tree) > Workqueue: events_unbound deferred_probe_work_func > unwind_backtrace from show_stack+0x10/0x14 > show_stack from dump_stack_lvl+0x40/0x4c > dump_stack_lvl from __warn+0x94/0xc0 > __warn from warn_slowpath_fmt+0x118/0x16c > warn_slowpath_fmt from tegra_dc_init+0x24/0x5fc > tegra_dc_init from host1x_device_init+0x84/0x15c > host1x_device_init from host1x_drm_probe+0xd8/0x3c4 > host1x_drm_probe from really_probe+0xc8/0x2dc > really_probe from __driver_probe_device+0x88/0x19c > __driver_probe_device from driver_probe_device+0x30/0x104 > driver_probe_device from __device_attach_driver+0x94/0x108 > __device_attach_driver from bus_for_each_drv+0x80/0xb8 > bus_for_each_drv from __device_attach+0xa0/0x190 > __device_attach from bus_probe_device+0x88/0x8c > bus_probe_device from deferred_probe_work_func+0x78/0xa4 > deferred_probe_work_func from process_one_work+0x208/0x420 > process_one_work from worker_thread+0x54/0x550 > worker_thread from kthread+0xdc/0xf8 > kthread from ret_from_fork+0x14/0x2c > Exception stack(0xcf9c5fb0 to 0xcf9c5ff8) > 5fa0: 00000000 00000000 00000000 00000000 > 5fc0: 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 > 5fe0: 00000000 00000000 00000000 00000000 00000013 00000000 > ---[ end trace 0000000000000000 ]--- Hi Maxim, Can you try the attached patch (on top of the series)? If it helps, I'll refresh the series with the fix. Tomi
Hi Tomi, > From c13c691bd8826b978325575be9a87f577b83b86b Mon Sep 17 00:00:00 2001 > From: Tomi Valkeinen <tomi.valkeinen@ideasonboard.com> > Date: Mon, 14 Aug 2023 13:02:23 +0300 > Subject: [PATCH] drm/bridge: tc358768: fix 'Add DRM_BRIDGE_ATTACH_NO_CONNECTOR > support' > > Signed-off-by: Tomi Valkeinen <tomi.valkeinen@ideasonboard.com> > --- > drivers/gpu/drm/bridge/tc358768.c | 56 +++++++++++++------------------ > 1 file changed, 24 insertions(+), 32 deletions(-) > > diff --git a/drivers/gpu/drm/bridge/tc358768.c b/drivers/gpu/drm/bridge/tc358768.c > index 82ea4d9a814a..9705ce1bd028 100644 > --- a/drivers/gpu/drm/bridge/tc358768.c > +++ b/drivers/gpu/drm/bridge/tc358768.c > @@ -455,8 +455,6 @@ static int tc358768_dsi_host_detach(struct mipi_dsi_host *host, > struct tc358768_priv *priv = dsi_host_to_tc358768(host); > > drm_bridge_remove(&priv->bridge); > - if (priv->output.panel) > - drm_panel_bridge_remove(priv->output.next_bridge); > > return 0; > } > @@ -531,49 +529,42 @@ static int tc358768_bridge_attach(struct drm_bridge *bridge, > enum drm_bridge_attach_flags flags) > { > struct tc358768_priv *priv = bridge_to_tc358768(bridge); > + struct drm_bridge *next_bridge; > + struct drm_panel *panel; > + int ret; > > if (!drm_core_check_feature(bridge->dev, DRIVER_ATOMIC)) { > dev_err(priv->dev, "needs atomic updates support\n"); > return -ENOTSUPP; > } > > - if (flags & DRM_BRIDGE_ATTACH_NO_CONNECTOR) { > - struct device_node *node; > - > - /* Get the next bridge, connected to port@1. */ > - node = of_graph_get_remote_node(priv->dev->of_node, 1, -1); > - if (!node) > - return -ENODEV; > - > - priv->output.next_bridge = of_drm_find_bridge(node); > - of_node_put(node); > - if (!priv->output.next_bridge) > - return -EPROBE_DEFER; > - } else { > - struct drm_bridge *bridge; > - struct drm_panel *panel; > - int ret; > - > - ret = drm_of_find_panel_or_bridge(priv->dev->of_node, 1, 0, > - &panel, &bridge); > - if (ret) > - return ret; > - > - if (panel) { > - bridge = drm_panel_bridge_add_typed(panel, > - DRM_MODE_CONNECTOR_DSI); > - if (IS_ERR(bridge)) > - return PTR_ERR(bridge); > - } > + ret = drm_of_find_panel_or_bridge(priv->dev->of_node, 1, -1, &panel, > + &next_bridge); I think the right way is to wrap the panel in a bridge, so something like: next_bridge = devm_drm_of_get_bridge(dev, priv->dev->of_node, 1, -1) if (IS_ERR(next_bridge)) return ... priv->output.next_bridge = next_bridge; Sam > + if (ret) > + return ret; > > - priv->output.next_bridge = bridge; > - priv->output.panel = panel; > + if (panel) { > + next_bridge = drm_panel_bridge_add_typed(panel, > + DRM_MODE_CONNECTOR_DSI); > + if (IS_ERR(next_bridge)) > + return PTR_ERR(next_bridge); > } > > + priv->output.next_bridge = next_bridge; > + priv->output.panel = panel; > + > return drm_bridge_attach(bridge->encoder, priv->output.next_bridge, bridge, > flags); > } > > +void tc358768_bridge_detach(struct drm_bridge *bridge) > +{ > + struct tc358768_priv *priv = bridge_to_tc358768(bridge); > + > + if (priv->output.panel) > + drm_panel_bridge_remove(priv->output.next_bridge); > +} > + > static enum drm_mode_status > tc358768_bridge_mode_valid(struct drm_bridge *bridge, > const struct drm_display_info *info, > @@ -1156,6 +1147,7 @@ tc358768_atomic_get_input_bus_fmts(struct drm_bridge *bridge, > > static const struct drm_bridge_funcs tc358768_bridge_funcs = { > .attach = tc358768_bridge_attach, > + .detach = tc358768_bridge_detach, > .mode_valid = tc358768_bridge_mode_valid, > .pre_enable = tc358768_bridge_pre_enable, > .enable = tc358768_bridge_enable, > -- > 2.34.1 >
On Mon, Aug 14, 2023 at 12:10:41PM +0200, Sam Ravnborg wrote: > > From c13c691bd8826b978325575be9a87f577b83b86b Mon Sep 17 00:00:00 2001 > > From: Tomi Valkeinen <tomi.valkeinen@ideasonboard.com> > > Date: Mon, 14 Aug 2023 13:02:23 +0300 > > Subject: [PATCH] drm/bridge: tc358768: fix 'Add DRM_BRIDGE_ATTACH_NO_CONNECTOR > > support' > > > > Signed-off-by: Tomi Valkeinen <tomi.valkeinen@ideasonboard.com> > > --- > > drivers/gpu/drm/bridge/tc358768.c | 56 +++++++++++++------------------ > > 1 file changed, 24 insertions(+), 32 deletions(-) > > > > diff --git a/drivers/gpu/drm/bridge/tc358768.c b/drivers/gpu/drm/bridge/tc358768.c > > index 82ea4d9a814a..9705ce1bd028 100644 > > --- a/drivers/gpu/drm/bridge/tc358768.c > > +++ b/drivers/gpu/drm/bridge/tc358768.c > > @@ -455,8 +455,6 @@ static int tc358768_dsi_host_detach(struct mipi_dsi_host *host, > > struct tc358768_priv *priv = dsi_host_to_tc358768(host); > > > > drm_bridge_remove(&priv->bridge); > > - if (priv->output.panel) > > - drm_panel_bridge_remove(priv->output.next_bridge); > > > > return 0; > > } > > @@ -531,49 +529,42 @@ static int tc358768_bridge_attach(struct drm_bridge *bridge, > > enum drm_bridge_attach_flags flags) > > { > > struct tc358768_priv *priv = bridge_to_tc358768(bridge); > > + struct drm_bridge *next_bridge; > > + struct drm_panel *panel; > > + int ret; > > > > if (!drm_core_check_feature(bridge->dev, DRIVER_ATOMIC)) { > > dev_err(priv->dev, "needs atomic updates support\n"); > > return -ENOTSUPP; > > } > > > > - if (flags & DRM_BRIDGE_ATTACH_NO_CONNECTOR) { > > - struct device_node *node; > > - > > - /* Get the next bridge, connected to port@1. */ > > - node = of_graph_get_remote_node(priv->dev->of_node, 1, -1); > > - if (!node) > > - return -ENODEV; > > - > > - priv->output.next_bridge = of_drm_find_bridge(node); > > - of_node_put(node); > > - if (!priv->output.next_bridge) > > - return -EPROBE_DEFER; > > - } else { > > - struct drm_bridge *bridge; > > - struct drm_panel *panel; > > - int ret; > > - > > - ret = drm_of_find_panel_or_bridge(priv->dev->of_node, 1, 0, > > - &panel, &bridge); > > - if (ret) > > - return ret; > > - > > - if (panel) { > > - bridge = drm_panel_bridge_add_typed(panel, > > - DRM_MODE_CONNECTOR_DSI); > > - if (IS_ERR(bridge)) > > - return PTR_ERR(bridge); > > - } > > + ret = drm_of_find_panel_or_bridge(priv->dev->of_node, 1, -1, &panel, > > + &next_bridge); > > I think the right way is to wrap the panel in a bridge, > so something like: > > next_bridge = devm_drm_of_get_bridge(dev, priv->dev->of_node, 1, -1) > > if (IS_ERR(next_bridge)) > return ... > priv->output.next_bridge = next_bridge; Should we at some point bite the bullet and wrap panels in bridges directly in drm_panel.c ? That would simplify all the consumers. > > + if (ret) > > + return ret; > > > > - priv->output.next_bridge = bridge; > > - priv->output.panel = panel; > > + if (panel) { > > + next_bridge = drm_panel_bridge_add_typed(panel, > > + DRM_MODE_CONNECTOR_DSI); > > + if (IS_ERR(next_bridge)) > > + return PTR_ERR(next_bridge); > > } > > > > + priv->output.next_bridge = next_bridge; > > + priv->output.panel = panel; > > + > > return drm_bridge_attach(bridge->encoder, priv->output.next_bridge, bridge, > > flags); > > } > > > > +void tc358768_bridge_detach(struct drm_bridge *bridge) > > +{ > > + struct tc358768_priv *priv = bridge_to_tc358768(bridge); > > + > > + if (priv->output.panel) > > + drm_panel_bridge_remove(priv->output.next_bridge); > > +} > > + > > static enum drm_mode_status > > tc358768_bridge_mode_valid(struct drm_bridge *bridge, > > const struct drm_display_info *info, > > @@ -1156,6 +1147,7 @@ tc358768_atomic_get_input_bus_fmts(struct drm_bridge *bridge, > > > > static const struct drm_bridge_funcs tc358768_bridge_funcs = { > > .attach = tc358768_bridge_attach, > > + .detach = tc358768_bridge_detach, > > .mode_valid = tc358768_bridge_mode_valid, > > .pre_enable = tc358768_bridge_pre_enable, > > .enable = tc358768_bridge_enable,
Hi Sam, On 14/08/2023 13:10, Sam Ravnborg wrote: > Hi Tomi, > >> From c13c691bd8826b978325575be9a87f577b83b86b Mon Sep 17 00:00:00 2001 >> From: Tomi Valkeinen <tomi.valkeinen@ideasonboard.com> >> Date: Mon, 14 Aug 2023 13:02:23 +0300 >> Subject: [PATCH] drm/bridge: tc358768: fix 'Add DRM_BRIDGE_ATTACH_NO_CONNECTOR >> support' >> >> Signed-off-by: Tomi Valkeinen <tomi.valkeinen@ideasonboard.com> >> --- >> drivers/gpu/drm/bridge/tc358768.c | 56 +++++++++++++------------------ >> 1 file changed, 24 insertions(+), 32 deletions(-) >> >> diff --git a/drivers/gpu/drm/bridge/tc358768.c b/drivers/gpu/drm/bridge/tc358768.c >> index 82ea4d9a814a..9705ce1bd028 100644 >> --- a/drivers/gpu/drm/bridge/tc358768.c >> +++ b/drivers/gpu/drm/bridge/tc358768.c >> @@ -455,8 +455,6 @@ static int tc358768_dsi_host_detach(struct mipi_dsi_host *host, >> struct tc358768_priv *priv = dsi_host_to_tc358768(host); >> >> drm_bridge_remove(&priv->bridge); >> - if (priv->output.panel) >> - drm_panel_bridge_remove(priv->output.next_bridge); >> >> return 0; >> } >> @@ -531,49 +529,42 @@ static int tc358768_bridge_attach(struct drm_bridge *bridge, >> enum drm_bridge_attach_flags flags) >> { >> struct tc358768_priv *priv = bridge_to_tc358768(bridge); >> + struct drm_bridge *next_bridge; >> + struct drm_panel *panel; >> + int ret; >> >> if (!drm_core_check_feature(bridge->dev, DRIVER_ATOMIC)) { >> dev_err(priv->dev, "needs atomic updates support\n"); >> return -ENOTSUPP; >> } >> >> - if (flags & DRM_BRIDGE_ATTACH_NO_CONNECTOR) { >> - struct device_node *node; >> - >> - /* Get the next bridge, connected to port@1. */ >> - node = of_graph_get_remote_node(priv->dev->of_node, 1, -1); >> - if (!node) >> - return -ENODEV; >> - >> - priv->output.next_bridge = of_drm_find_bridge(node); >> - of_node_put(node); >> - if (!priv->output.next_bridge) >> - return -EPROBE_DEFER; >> - } else { >> - struct drm_bridge *bridge; >> - struct drm_panel *panel; >> - int ret; >> - >> - ret = drm_of_find_panel_or_bridge(priv->dev->of_node, 1, 0, >> - &panel, &bridge); >> - if (ret) >> - return ret; >> - >> - if (panel) { >> - bridge = drm_panel_bridge_add_typed(panel, >> - DRM_MODE_CONNECTOR_DSI); >> - if (IS_ERR(bridge)) >> - return PTR_ERR(bridge); >> - } >> + ret = drm_of_find_panel_or_bridge(priv->dev->of_node, 1, -1, &panel, >> + &next_bridge); > > I think the right way is to wrap the panel in a bridge, > so something like: > > next_bridge = devm_drm_of_get_bridge(dev, priv->dev->of_node, 1, -1) > > if (IS_ERR(next_bridge)) > return ... > priv->output.next_bridge = next_bridge; I tried that, but I had trouble with the cleanup side. In the fixup patch I attached in my reply to Maxim I used drm_of_find_panel_or_bridge() + drm_panel_bridge_add_typed(), and on bridge_detach callback I used drm_panel_bridge_remove() (if there is a panel). This worked for me, but it does feel like a bit too much work for a driver to do. Tomi
On 14.08.23 12:04, Tomi Valkeinen wrote: > On 13/08/2023 20:11, Maxim Schwalm wrote: >> On 04.08.23 12:44, Tomi Valkeinen wrote: >>> Signed-off-by: Tomi Valkeinen <tomi.valkeinen@ideasonboard.com> >>> --- >>> drivers/gpu/drm/bridge/tc358768.c | 64 +++++++++++++++++++++++++++------------ >>> 1 file changed, 45 insertions(+), 19 deletions(-) >>> >>> diff --git a/drivers/gpu/drm/bridge/tc358768.c b/drivers/gpu/drm/bridge/tc358768.c >>> index ea19de5509ed..a567f136ddc7 100644 >>> --- a/drivers/gpu/drm/bridge/tc358768.c >>> +++ b/drivers/gpu/drm/bridge/tc358768.c >>> @@ -131,8 +131,17 @@ static const char * const tc358768_supplies[] = { >>> >>> struct tc358768_dsi_output { >>> struct mipi_dsi_device *dev; >>> + >>> + /* Legacy field if DRM_BRIDGE_ATTACH_NO_CONNECTOR is not used */ >>> struct drm_panel *panel; >>> - struct drm_bridge *bridge; >>> + >>> + /* >>> + * If DRM_BRIDGE_ATTACH_NO_CONNECTOR is not used and a panel is attached >>> + * to tc358768, 'next_bridge' contains the bridge the driver created >>> + * with drm_panel_bridge_add_typed(). Otherwise 'next_bridge' contains >>> + * the next bridge the driver found. >>> + */ >>> + struct drm_bridge *next_bridge; >>> }; >>> >>> struct tc358768_priv { >>> @@ -391,8 +400,6 @@ static int tc358768_dsi_host_attach(struct mipi_dsi_host *host, >>> struct mipi_dsi_device *dev) >>> { >>> struct tc358768_priv *priv = dsi_host_to_tc358768(host); >>> - struct drm_bridge *bridge; >>> - struct drm_panel *panel; >>> struct device_node *ep; >>> int ret; >>> >>> @@ -420,21 +427,7 @@ static int tc358768_dsi_host_attach(struct mipi_dsi_host *host, >>> return -ENOTSUPP; >>> } >>> >>> - ret = drm_of_find_panel_or_bridge(host->dev->of_node, 1, 0, &panel, >>> - &bridge); >>> - if (ret) >>> - return ret; >>> - >>> - if (panel) { >>> - bridge = drm_panel_bridge_add_typed(panel, >>> - DRM_MODE_CONNECTOR_DSI); >>> - if (IS_ERR(bridge)) >>> - return PTR_ERR(bridge); >>> - } >>> - >>> priv->output.dev = dev; >>> - priv->output.bridge = bridge; >>> - priv->output.panel = panel; >>> >>> priv->dsi_lanes = dev->lanes; >>> priv->dsi_bpp = mipi_dsi_pixel_format_to_bpp(dev->format); >>> @@ -463,7 +456,7 @@ static int tc358768_dsi_host_detach(struct mipi_dsi_host *host, >>> >>> drm_bridge_remove(&priv->bridge); >>> if (priv->output.panel) >>> - drm_panel_bridge_remove(priv->output.bridge); >>> + drm_panel_bridge_remove(priv->output.next_bridge); >>> >>> return 0; >>> } >>> @@ -544,7 +537,40 @@ static int tc358768_bridge_attach(struct drm_bridge *bridge, >>> return -ENOTSUPP; >>> } >>> >>> - return drm_bridge_attach(bridge->encoder, priv->output.bridge, bridge, >>> + if (flags & DRM_BRIDGE_ATTACH_NO_CONNECTOR) { >>> + struct device_node *node; >>> + >>> + /* Get the next bridge, connected to port@1. */ >>> + node = of_graph_get_remote_node(priv->dev->of_node, 1, -1); >>> + if (!node) >>> + return -ENODEV; >>> + >>> + priv->output.next_bridge = of_drm_find_bridge(node); >>> + of_node_put(node); >>> + if (!priv->output.next_bridge) >>> + return -EPROBE_DEFER; >>> + } else { >>> + struct drm_bridge *bridge; >>> + struct drm_panel *panel; >>> + int ret; >>> + >>> + ret = drm_of_find_panel_or_bridge(priv->dev->of_node, 1, 0, >>> + &panel, &bridge); >>> + if (ret) >>> + return ret; >>> + >>> + if (panel) { >>> + bridge = drm_panel_bridge_add_typed(panel, >>> + DRM_MODE_CONNECTOR_DSI); >>> + if (IS_ERR(bridge)) >>> + return PTR_ERR(bridge); >>> + } >>> + >>> + priv->output.next_bridge = bridge; >>> + priv->output.panel = panel; >>> + } >>> + >>> + return drm_bridge_attach(bridge->encoder, priv->output.next_bridge, bridge, >>> flags); >>> } >>> >>> >> This patch unfortunately breaks the display output on the Asus TF700T: >> >> [drm:drm_bridge_attach] *ERROR* failed to attach bridge /i2c-mux/i2c@1/dsi@7 to encoder LVDS-59: -517 >> tegra-dc 54200000.dc: failed to initialize RGB output: -517 >> drm drm: failed to initialize 54200000.dc: -517 >> ------------[ cut here ]------------ >> WARNING: CPU: 3 PID: 69 at lib/refcount.c:28 tegra_dc_init+0x24/0x5fc >> refcount_t: underflow; use-after-free. >> Modules linked in: elants_i2c panel_simple tc358768 atkbd vivaldi_fmap >> CPU: 3 PID: 69 Comm: kworker/u8:6 Not tainted 6.5.0-rc2-postmarketos-grate #95 >> Hardware name: NVIDIA Tegra SoC (Flattened Device Tree) >> Workqueue: events_unbound deferred_probe_work_func >> unwind_backtrace from show_stack+0x10/0x14 >> show_stack from dump_stack_lvl+0x40/0x4c >> dump_stack_lvl from __warn+0x94/0xc0 >> __warn from warn_slowpath_fmt+0x118/0x16c >> warn_slowpath_fmt from tegra_dc_init+0x24/0x5fc >> tegra_dc_init from host1x_device_init+0x84/0x15c >> host1x_device_init from host1x_drm_probe+0xd8/0x3c4 >> host1x_drm_probe from really_probe+0xc8/0x2dc >> really_probe from __driver_probe_device+0x88/0x19c >> __driver_probe_device from driver_probe_device+0x30/0x104 >> driver_probe_device from __device_attach_driver+0x94/0x108 >> __device_attach_driver from bus_for_each_drv+0x80/0xb8 >> bus_for_each_drv from __device_attach+0xa0/0x190 >> __device_attach from bus_probe_device+0x88/0x8c >> bus_probe_device from deferred_probe_work_func+0x78/0xa4 >> deferred_probe_work_func from process_one_work+0x208/0x420 >> process_one_work from worker_thread+0x54/0x550 >> worker_thread from kthread+0xdc/0xf8 >> kthread from ret_from_fork+0x14/0x2c >> Exception stack(0xcf9c5fb0 to 0xcf9c5ff8) >> 5fa0: 00000000 00000000 00000000 00000000 >> 5fc0: 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 >> 5fe0: 00000000 00000000 00000000 00000000 00000013 00000000 >> ---[ end trace 0000000000000000 ]--- > > Hi Maxim, > > Can you try the attached patch (on top of the series)? If it helps, I'll > refresh the series with the fix. > Thanks, Tomi! This fixes the issue. Best regards, Maxim
diff --git a/drivers/gpu/drm/bridge/tc358768.c b/drivers/gpu/drm/bridge/tc358768.c index ea19de5509ed..a567f136ddc7 100644 --- a/drivers/gpu/drm/bridge/tc358768.c +++ b/drivers/gpu/drm/bridge/tc358768.c @@ -131,8 +131,17 @@ static const char * const tc358768_supplies[] = { struct tc358768_dsi_output { struct mipi_dsi_device *dev; + + /* Legacy field if DRM_BRIDGE_ATTACH_NO_CONNECTOR is not used */ struct drm_panel *panel; - struct drm_bridge *bridge; + + /* + * If DRM_BRIDGE_ATTACH_NO_CONNECTOR is not used and a panel is attached + * to tc358768, 'next_bridge' contains the bridge the driver created + * with drm_panel_bridge_add_typed(). Otherwise 'next_bridge' contains + * the next bridge the driver found. + */ + struct drm_bridge *next_bridge; }; struct tc358768_priv { @@ -391,8 +400,6 @@ static int tc358768_dsi_host_attach(struct mipi_dsi_host *host, struct mipi_dsi_device *dev) { struct tc358768_priv *priv = dsi_host_to_tc358768(host); - struct drm_bridge *bridge; - struct drm_panel *panel; struct device_node *ep; int ret; @@ -420,21 +427,7 @@ static int tc358768_dsi_host_attach(struct mipi_dsi_host *host, return -ENOTSUPP; } - ret = drm_of_find_panel_or_bridge(host->dev->of_node, 1, 0, &panel, - &bridge); - if (ret) - return ret; - - if (panel) { - bridge = drm_panel_bridge_add_typed(panel, - DRM_MODE_CONNECTOR_DSI); - if (IS_ERR(bridge)) - return PTR_ERR(bridge); - } - priv->output.dev = dev; - priv->output.bridge = bridge; - priv->output.panel = panel; priv->dsi_lanes = dev->lanes; priv->dsi_bpp = mipi_dsi_pixel_format_to_bpp(dev->format); @@ -463,7 +456,7 @@ static int tc358768_dsi_host_detach(struct mipi_dsi_host *host, drm_bridge_remove(&priv->bridge); if (priv->output.panel) - drm_panel_bridge_remove(priv->output.bridge); + drm_panel_bridge_remove(priv->output.next_bridge); return 0; } @@ -544,7 +537,40 @@ static int tc358768_bridge_attach(struct drm_bridge *bridge, return -ENOTSUPP; } - return drm_bridge_attach(bridge->encoder, priv->output.bridge, bridge, + if (flags & DRM_BRIDGE_ATTACH_NO_CONNECTOR) { + struct device_node *node; + + /* Get the next bridge, connected to port@1. */ + node = of_graph_get_remote_node(priv->dev->of_node, 1, -1); + if (!node) + return -ENODEV; + + priv->output.next_bridge = of_drm_find_bridge(node); + of_node_put(node); + if (!priv->output.next_bridge) + return -EPROBE_DEFER; + } else { + struct drm_bridge *bridge; + struct drm_panel *panel; + int ret; + + ret = drm_of_find_panel_or_bridge(priv->dev->of_node, 1, 0, + &panel, &bridge); + if (ret) + return ret; + + if (panel) { + bridge = drm_panel_bridge_add_typed(panel, + DRM_MODE_CONNECTOR_DSI); + if (IS_ERR(bridge)) + return PTR_ERR(bridge); + } + + priv->output.next_bridge = bridge; + priv->output.panel = panel; + } + + return drm_bridge_attach(bridge->encoder, priv->output.next_bridge, bridge, flags); }
Signed-off-by: Tomi Valkeinen <tomi.valkeinen@ideasonboard.com> --- drivers/gpu/drm/bridge/tc358768.c | 64 +++++++++++++++++++++++++++------------ 1 file changed, 45 insertions(+), 19 deletions(-)