Message ID | 20230804-tc358768-v1-11-1afd44b7826b@ideasonboard.com |
---|---|
State | New |
Headers |
Return-Path: <linux-kernel-owner@vger.kernel.org> Delivered-To: ouuuleilei@gmail.com Received: by 2002:a05:612c:44a:b0:3f2:4152:657d with SMTP id ez10csp185883vqb; Fri, 4 Aug 2023 04:14:50 -0700 (PDT) X-Google-Smtp-Source: AGHT+IHnA7J5T2iwglU2LJXCs9194cQ2SsgCf3cr2sZ42255IOluZOEt7/m7rU1z3GPQmNzsiKuv X-Received: by 2002:a17:903:41c6:b0:1bb:ab0d:4f76 with SMTP id u6-20020a17090341c600b001bbab0d4f76mr1847742ple.58.1691147689706; Fri, 04 Aug 2023 04:14:49 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1691147689; cv=none; d=google.com; s=arc-20160816; b=FfyZxos8h/QRLxmlDTHUmPqY0qoV4DO2sGBG+K6BHRMnO4gXCrAvndesiK4+lX4eLm eT7J3fY5pLXROg3q0Wjg5k7+GCxTlzGYCof3LT64SXlcrE8vnD2o9bzul4PSfLfnu8Do LjjREnNUAGlj+jEHcmP9P4bL7sWCAmvzlpJ6MfbsHjQlKfQyK2ilhu7qgVEPYr+4BiS5 OhEgXA4vBJXPzhZbnLkggwCfnsdEhinVVAoFJBbBXZHOThF+HX9pWKkMeEQOJXXX78He bu+nRQ7wRE1f1505FYVVprMAbUvzsXoGNlw+mbGQc9Z0KfJ9Gvb+HIq7VqzrtNgKCKMc W4ww== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=list-id:precedence:cc:to:in-reply-to:references:message-id :content-transfer-encoding:mime-version:subject:date:from :dkim-signature; bh=kzVWueXpYGukXxzwso5CiX9i2OR433Tta+3HippSZVg=; fh=7GYuw25cWCmHG5LrbyQUwFOElFQ4tchxd/wzYEHngW8=; b=FkjDjzTOtcdvBa06Ka4kQL8T2ZU7Th7ke68gp6rBSJ3nEgaj7vRhYzCUMxIf0ge+LG 1/qrM4xhFyOGS+tw0G6f98L4e0s4c3wMy0QhtcztxdgtrwT2NVi/dfsFDwgi/GEdAXG1 yH0lS+V2FB/dYDmQ8iS2IItg9RbOKlL5yICs9V7hpk6ahJCN6eNcEjL9pmfSmzNl9TEU quBLTSEzxS7WVr+YiBnXPvTICpuVwI0J8PJFQLJGSzKIYRmMU4DhHWzwAk06WzDozpPy ZLsILfdi8g/lbX9SSl+vgX3slxjvNU4LIVQoVaCp+99Fd9qN44ZaTj6c3vXRL1tNs4f8 VXrA== ARC-Authentication-Results: i=1; mx.google.com; dkim=pass (test mode) header.i=@ideasonboard.com header.s=mail header.b=dGDYFKiR; spf=pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 2620:137:e000::1:20 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org Received: from out1.vger.email (out1.vger.email. [2620:137:e000::1:20]) by mx.google.com with ESMTP id t6-20020a170902e84600b001b89bcfb2c3si1690941plg.162.2023.08.04.04.14.26; Fri, 04 Aug 2023 04:14:49 -0700 (PDT) Received-SPF: pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 2620:137:e000::1:20 as permitted sender) client-ip=2620:137:e000::1:20; Authentication-Results: mx.google.com; dkim=pass (test mode) header.i=@ideasonboard.com header.s=mail header.b=dGDYFKiR; spf=pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 2620:137:e000::1:20 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S231535AbjHDKpp (ORCPT <rfc822;sukrut.bellary@gmail.com> + 99 others); Fri, 4 Aug 2023 06:45:45 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:46868 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S231609AbjHDKp0 (ORCPT <rfc822;linux-kernel@vger.kernel.org>); Fri, 4 Aug 2023 06:45:26 -0400 Received: from perceval.ideasonboard.com (perceval.ideasonboard.com [IPv6:2001:4b98:dc2:55:216:3eff:fef7:d647]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id F08B84C06 for <linux-kernel@vger.kernel.org>; Fri, 4 Aug 2023 03:44:55 -0700 (PDT) Received: from [127.0.1.1] (91-154-35-171.elisa-laajakaista.fi [91.154.35.171]) by perceval.ideasonboard.com (Postfix) with ESMTPSA id 0FFA81AB3; Fri, 4 Aug 2023 12:43:44 +0200 (CEST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com; s=mail; t=1691145824; bh=NVGv48ZsaW1J2ePUXosAluIgk8qR+1DrF7efAr7lM4w=; h=From:Date:Subject:References:In-Reply-To:To:Cc:From; b=dGDYFKiRY3ejkAX1kWBtrueu0SEW5lxRwH92ud9Fe8DbjpkvBgjWLhXcumV9/AJfF KF19+EBtC0ql19kWEcAO9xd1NdMKirgUIF5Ax3zAbA57x3H0cZ9iKndFzEVAVhzD3f +vSaM3Qz6n0tbhbNt7mDycPPs3CPG8wv26aLTXdk= From: Tomi Valkeinen <tomi.valkeinen@ideasonboard.com> Date: Fri, 04 Aug 2023 13:44:16 +0300 Subject: [PATCH 11/11] drm/bridge: tc358768: Add DRM_BRIDGE_ATTACH_NO_CONNECTOR support MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: 7bit Message-Id: <20230804-tc358768-v1-11-1afd44b7826b@ideasonboard.com> References: <20230804-tc358768-v1-0-1afd44b7826b@ideasonboard.com> In-Reply-To: <20230804-tc358768-v1-0-1afd44b7826b@ideasonboard.com> To: Andrzej Hajda <andrzej.hajda@intel.com>, Neil Armstrong <neil.armstrong@linaro.org>, Robert Foss <rfoss@kernel.org>, Laurent Pinchart <Laurent.pinchart@ideasonboard.com>, Jonas Karlman <jonas@kwiboo.se>, Jernej Skrabec <jernej.skrabec@gmail.com>, David Airlie <airlied@gmail.com>, Daniel Vetter <daniel@ffwll.ch>, =?utf-8?q?P=C3=A9ter_Ujfalusi?= <peter.ujfalusi@gmail.com>, Francesco Dolcini <francesco@dolcini.it> Cc: dri-devel@lists.freedesktop.org, linux-kernel@vger.kernel.org, Aradhya Bhatia <a-bhatia1@ti.com>, Tomi Valkeinen <tomi.valkeinen@ideasonboard.com> X-Mailer: b4 0.12.3 X-Developer-Signature: v=1; a=openpgp-sha256; l=3311; i=tomi.valkeinen@ideasonboard.com; h=from:subject:message-id; bh=NVGv48ZsaW1J2ePUXosAluIgk8qR+1DrF7efAr7lM4w=; b=owEBbQKS/ZANAwAIAfo9qoy8lh71AcsmYgBkzNaUTL0ctCqlqan7C6QJgIPS0jOOK19pqZh0f tnCtHFYzGWJAjMEAAEIAB0WIQTEOAw+ll79gQef86f6PaqMvJYe9QUCZMzWlAAKCRD6PaqMvJYe 9Z3oD/9GvdukB96G4adIbYXsQ7SSiIRzmYQYNiFOUQW55h6eof6UJRwPyXL+5wiOP9/MyFGtsLv Uk32KzqAHGJChrf2erw9ZGghKeZG0M/UQ8GJeQ+BjTSMGgOh0ySP/+bSgqvic65dsayZ5Fmg11b CVhophTt8Q4uCahRYBjQgc06ueGYQPKj8Qw0p6kJY1D3KhLvHxCDjQj4i+gFd9++hbPBw+wg0zc +n4vi3WG/S7vytZLqJvhZV3pKqteZw+SRNYux7kWeLOpQ2QIBOntlPm6KJi7ymcsAYBYFusDwiz 6Lscmd9PudbiBvPA+8vCcIZUaMuBNkZLYIlUtMtrBZHb9qlzKyRpoKtOeB0hql8j16N0b4DTg4C x7MR3m3NjuqvTdloSLRHfydtvDH9MJQhUdkxQRIPO++KLyQX9uVsN4OFnYfockwKfsSGvSxQQX6 YKAb5vw0FCx00uBHGxjZoFlhCBphTFmen4hmo9qU8+8wfP2dLt6Xj9189q8KSTUueFOX+gGJZGS 7tC54hRSst9FBUaZYC00YPgXkjAlWMcdNARl2zQXEJU/jJFWHjt22UXsiftwPgdei9SjR8fiamp 6cci8rii7FfrhOWFYz2a+31j4hZGvVaxW6Dnqxwl5aJPzLMFy7lGfj5Ap/TuxpQiywsljV50Aez Yqj74AJoa4QYsSw== X-Developer-Key: i=tomi.valkeinen@ideasonboard.com; a=openpgp; fpr=C4380C3E965EFD81079FF3A7FA3DAA8CBC961EF5 X-Spam-Status: No, score=-2.1 required=5.0 tests=BAYES_00,DKIM_SIGNED, DKIM_VALID,DKIM_VALID_AU,DKIM_VALID_EF,RCVD_IN_DNSWL_BLOCKED, SPF_HELO_PASS,SPF_PASS,URIBL_BLOCKED autolearn=ham autolearn_force=no version=3.4.6 X-Spam-Checker-Version: SpamAssassin 3.4.6 (2021-04-09) on lindbergh.monkeyblade.net Precedence: bulk List-ID: <linux-kernel.vger.kernel.org> X-Mailing-List: linux-kernel@vger.kernel.org X-getmail-retrieved-from-mailbox: INBOX X-GMAIL-THRID: 1773296879802539905 X-GMAIL-MSGID: 1773296879802539905 |
Series |
drm/bridge: tc358768: Fixes and timings improvements
|
|
Commit Message
Tomi Valkeinen
Aug. 4, 2023, 10:44 a.m. UTC
Signed-off-by: Tomi Valkeinen <tomi.valkeinen@ideasonboard.com>
---
drivers/gpu/drm/bridge/tc358768.c | 64 +++++++++++++++++++++++++++------------
1 file changed, 45 insertions(+), 19 deletions(-)
Comments
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
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); }