lkml.org 
[lkml]   [2023]   [Aug]   [14]   [last100]   RSS Feed
Views: [wrap][no wrap]   [headers]  [forward] 
 
Messages in this thread
    Patch in this message
    /
    Date
    SubjectRe: [PATCH 11/11] drm/bridge: tc358768: Add DRM_BRIDGE_ATTACH_NO_CONNECTOR support
    From
    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
    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);
    + 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
    \
     
     \ /
      Last update: 2023-08-14 12:06    [W:3.305 / U:0.004 seconds]
    ©2003-2020 Jasper Spaans|hosted at Digital Ocean and TransIP|Read the blog|Advertise on this site