From patchwork Wed Oct 23 15:44:52 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Boris Brezillon X-Patchwork-Id: 11207129 Return-Path: Received: from mail.kernel.org (pdx-korg-mail-1.web.codeaurora.org [172.30.200.123]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id 1F59E13BD for ; Wed, 23 Oct 2019 15:46:17 +0000 (UTC) Received: from gabe.freedesktop.org (gabe.freedesktop.org [131.252.210.177]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by mail.kernel.org (Postfix) with ESMTPS id 080362086D for ; Wed, 23 Oct 2019 15:46:17 +0000 (UTC) DMARC-Filter: OpenDMARC Filter v1.3.2 mail.kernel.org 080362086D Authentication-Results: mail.kernel.org; dmarc=fail (p=none dis=none) header.from=collabora.com Authentication-Results: mail.kernel.org; spf=none smtp.mailfrom=dri-devel-bounces@lists.freedesktop.org Received: from gabe.freedesktop.org (localhost [127.0.0.1]) by gabe.freedesktop.org (Postfix) with ESMTP id 7BBBB6EB32; Wed, 23 Oct 2019 15:46:05 +0000 (UTC) X-Original-To: dri-devel@lists.freedesktop.org Delivered-To: dri-devel@lists.freedesktop.org Received: from bhuna.collabora.co.uk (bhuna.collabora.co.uk [46.235.227.227]) by gabe.freedesktop.org (Postfix) with ESMTPS id 6788C6EB1A for ; Wed, 23 Oct 2019 15:45:19 +0000 (UTC) Received: from localhost.localdomain (unknown [IPv6:2a01:e0a:2c:6930:5cf4:84a1:2763:fe0d]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) (Authenticated sender: bbrezillon) by bhuna.collabora.co.uk (Postfix) with ESMTPSA id 5E54B28F905; Wed, 23 Oct 2019 16:45:17 +0100 (BST) From: Boris Brezillon To: dri-devel@lists.freedesktop.org Subject: [PATCH v3 01/21] drm/vc4: Declare the DSI encoder as a bridge element Date: Wed, 23 Oct 2019 17:44:52 +0200 Message-Id: <20191023154512.9762-2-boris.brezillon@collabora.com> X-Mailer: git-send-email 2.21.0 In-Reply-To: <20191023154512.9762-1-boris.brezillon@collabora.com> References: <20191023154512.9762-1-boris.brezillon@collabora.com> MIME-Version: 1.0 X-BeenThere: dri-devel@lists.freedesktop.org X-Mailman-Version: 2.1.23 Precedence: list List-Id: Direct Rendering Infrastructure - Development List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: Mark Rutland , Neil Armstrong , Thierry Reding , Laurent Pinchart , kernel@collabora.com, Sam Ravnborg , Nikita Yushchenko , Andrey Smirnov , Kyungmin Park , Chris Healy , devicetree@vger.kernel.org, Jonas Karlman , Rob Herring , Jernej Skrabec , Seung-Woo Kim , Boris Brezillon Errors-To: dri-devel-bounces@lists.freedesktop.org Sender: "dri-devel" Encoder drivers will progressively transition to the drm_bridge interface in place of the drm_encoder one. Let's start with the VC4 driver, and use the ->pre_{enable,disable}() hooks to get rid of the hack resetting encoder->bridge.next (which was needed to control the encoder/bridge enable/disable sequence). Signed-off-by: Boris Brezillon Reviewed-by: Laurent Pinchart --- Changes in v3: * Embed a drm_bridge object in vc4_dsi since drm_encoder no longer has a dummy bridge Changes in v2: * New patch (replaces "drm/vc4: Get rid of the dsi->bridge field") --- drivers/gpu/drm/vc4/vc4_dsi.c | 88 +++++++++++++++++++++-------------- 1 file changed, 52 insertions(+), 36 deletions(-) diff --git a/drivers/gpu/drm/vc4/vc4_dsi.c b/drivers/gpu/drm/vc4/vc4_dsi.c index c9ba83ed49b9..49f8a313e759 100644 --- a/drivers/gpu/drm/vc4/vc4_dsi.c +++ b/drivers/gpu/drm/vc4/vc4_dsi.c @@ -498,7 +498,11 @@ struct vc4_dsi { struct mipi_dsi_host dsi_host; struct drm_encoder *encoder; - struct drm_bridge *bridge; + + /* Embed a bridge object so we can implement bridge funcs instead of + * encoder ones. + */ + struct drm_bridge bridge; void __iomem *regs; @@ -543,6 +547,11 @@ struct vc4_dsi { struct debugfs_regset32 regset; }; +static inline struct vc4_dsi *bridge_to_vc4_dsi(struct drm_bridge *bridge) +{ + return container_of(bridge, struct vc4_dsi, bridge); +} + #define host_to_dsi(host) container_of(host, struct vc4_dsi, dsi_host) static inline void @@ -747,16 +756,11 @@ dsi_esc_timing(u32 ns) return DIV_ROUND_UP(ns, ESC_TIME_NS); } -static void vc4_dsi_encoder_disable(struct drm_encoder *encoder) +static void vc4_dsi_bridge_post_disable(struct drm_bridge *bridge) { - struct vc4_dsi_encoder *vc4_encoder = to_vc4_dsi_encoder(encoder); - struct vc4_dsi *dsi = vc4_encoder->dsi; + struct vc4_dsi *dsi = bridge_to_vc4_dsi(bridge); struct device *dev = &dsi->pdev->dev; - drm_bridge_disable(dsi->bridge); - vc4_dsi_ulps(dsi, true); - drm_bridge_post_disable(dsi->bridge); - clk_disable_unprepare(dsi->pll_phy_clock); clk_disable_unprepare(dsi->escape_clock); clk_disable_unprepare(dsi->pixel_clock); @@ -764,6 +768,13 @@ static void vc4_dsi_encoder_disable(struct drm_encoder *encoder) pm_runtime_put(dev); } +static void vc4_dsi_bridge_disable(struct drm_bridge *bridge) +{ + struct vc4_dsi *dsi = bridge_to_vc4_dsi(bridge); + + vc4_dsi_ulps(dsi, true); +} + /* Extends the mode's blank intervals to handle BCM2835's integer-only * DSI PLL divider. * @@ -777,12 +788,11 @@ static void vc4_dsi_encoder_disable(struct drm_encoder *encoder) * higher-than-expected clock rate to the panel, but that's what the * firmware does too. */ -static bool vc4_dsi_encoder_mode_fixup(struct drm_encoder *encoder, - const struct drm_display_mode *mode, - struct drm_display_mode *adjusted_mode) +static bool vc4_dsi_bridge_mode_fixup(struct drm_bridge *bridge, + const struct drm_display_mode *mode, + struct drm_display_mode *adjusted_mode) { - struct vc4_dsi_encoder *vc4_encoder = to_vc4_dsi_encoder(encoder); - struct vc4_dsi *dsi = vc4_encoder->dsi; + struct vc4_dsi *dsi = bridge_to_vc4_dsi(bridge); struct clk *phy_parent = clk_get_parent(dsi->pll_phy_clock); unsigned long parent_rate = clk_get_rate(phy_parent); unsigned long pixel_clock_hz = mode->clock * 1000; @@ -816,11 +826,11 @@ static bool vc4_dsi_encoder_mode_fixup(struct drm_encoder *encoder, return true; } -static void vc4_dsi_encoder_enable(struct drm_encoder *encoder) +static void vc4_dsi_bridge_pre_enable(struct drm_bridge *bridge) { + struct drm_encoder *encoder = bridge->encoder; struct drm_display_mode *mode = &encoder->crtc->state->adjusted_mode; - struct vc4_dsi_encoder *vc4_encoder = to_vc4_dsi_encoder(encoder); - struct vc4_dsi *dsi = vc4_encoder->dsi; + struct vc4_dsi *dsi = bridge_to_vc4_dsi(bridge); struct device *dev = &dsi->pdev->dev; bool debug_dump_regs = false; unsigned long hs_clock; @@ -1054,8 +1064,12 @@ static void vc4_dsi_encoder_enable(struct drm_encoder *encoder) } vc4_dsi_ulps(dsi, false); +} - drm_bridge_pre_enable(dsi->bridge); +static void vc4_dsi_bridge_enable(struct drm_bridge *bridge) +{ + struct vc4_dsi *dsi = bridge_to_vc4_dsi(bridge); + bool debug_dump_regs = false; if (dsi->mode_flags & MIPI_DSI_MODE_VIDEO) { DSI_PORT_WRITE(DISP0_CTRL, @@ -1072,8 +1086,6 @@ static void vc4_dsi_encoder_enable(struct drm_encoder *encoder) DSI_DISP0_ENABLE); } - drm_bridge_enable(dsi->bridge); - if (debug_dump_regs) { struct drm_printer p = drm_info_printer(&dsi->pdev->dev); dev_info(&dsi->pdev->dev, "DSI regs after:\n"); @@ -1290,10 +1302,12 @@ static const struct mipi_dsi_host_ops vc4_dsi_host_ops = { .transfer = vc4_dsi_host_transfer, }; -static const struct drm_encoder_helper_funcs vc4_dsi_encoder_helper_funcs = { - .disable = vc4_dsi_encoder_disable, - .enable = vc4_dsi_encoder_enable, - .mode_fixup = vc4_dsi_encoder_mode_fixup, +static const struct drm_bridge_funcs vc4_dsi_bridge_funcs = { + .pre_enable = vc4_dsi_bridge_pre_enable, + .enable = vc4_dsi_bridge_enable, + .disable = vc4_dsi_bridge_disable, + .post_disable = vc4_dsi_bridge_post_disable, + .mode_fixup = vc4_dsi_bridge_mode_fixup, }; static const struct of_device_id vc4_dsi_dt_match[] = { @@ -1445,6 +1459,7 @@ static int vc4_dsi_bind(struct device *dev, struct device *master, void *data) struct vc4_dev *vc4 = to_vc4_dev(drm); struct vc4_dsi *dsi = dev_get_drvdata(dev); struct vc4_dsi_encoder *vc4_dsi_encoder; + struct drm_bridge *next_bridge; struct drm_panel *panel; const struct of_device_id *match; dma_cap_mask_t dma_mask; @@ -1561,7 +1576,7 @@ static int vc4_dsi_bind(struct device *dev, struct device *master, void *data) } ret = drm_of_find_panel_or_bridge(dev->of_node, 0, 0, - &panel, &dsi->bridge); + &panel, &next_bridge); if (ret) { /* If the bridge or panel pointed by dev->of_node is not * enabled, just return 0 here so that we don't prevent the DRM @@ -1576,10 +1591,10 @@ static int vc4_dsi_bind(struct device *dev, struct device *master, void *data) } if (panel) { - dsi->bridge = devm_drm_panel_bridge_add_typed(dev, panel, + next_bridge = devm_drm_panel_bridge_add_typed(dev, panel, DRM_MODE_CONNECTOR_DSI); - if (IS_ERR(dsi->bridge)) - return PTR_ERR(dsi->bridge); + if (IS_ERR(next_bridge)) + return PTR_ERR(next_bridge); } /* The esc clock rate is supposed to always be 100Mhz. */ @@ -1598,19 +1613,20 @@ static int vc4_dsi_bind(struct device *dev, struct device *master, void *data) drm_encoder_init(drm, dsi->encoder, &vc4_dsi_encoder_funcs, DRM_MODE_ENCODER_DSI, NULL); - drm_encoder_helper_add(dsi->encoder, &vc4_dsi_encoder_helper_funcs); - ret = drm_bridge_attach(dsi->encoder, dsi->bridge, NULL); + /* Declare ourself as the first bridge element. */ + dsi->bridge.funcs = &vc4_dsi_bridge_funcs; + ret = drm_bridge_attach(dsi->encoder, &dsi->bridge, NULL); + if (ret) { + dev_err(dev, "bridge attach failed: %d\n", ret); + return ret; + } + + ret = drm_bridge_attach(dsi->encoder, next_bridge, &dsi->bridge); if (ret) { dev_err(dev, "bridge attach failed: %d\n", ret); return ret; } - /* Disable the atomic helper calls into the bridge. We - * manually call the bridge pre_enable / enable / etc. calls - * from our driver, since we need to sequence them within the - * encoder's enable/disable paths. - */ - dsi->encoder->bridge = NULL; if (dsi->port == 0) vc4_debugfs_add_regset32(drm, "dsi0_regs", &dsi->regset); @@ -1629,7 +1645,7 @@ static void vc4_dsi_unbind(struct device *dev, struct device *master, struct vc4_dev *vc4 = to_vc4_dev(drm); struct vc4_dsi *dsi = dev_get_drvdata(dev); - if (dsi->bridge) + if (dsi->bridge.next) pm_runtime_disable(dev); vc4_dsi_encoder_destroy(dsi->encoder); From patchwork Wed Oct 23 15:44:53 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Boris Brezillon X-Patchwork-Id: 11207087 Return-Path: Received: from mail.kernel.org (pdx-korg-mail-1.web.codeaurora.org [172.30.200.123]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id 0808913BD for ; Wed, 23 Oct 2019 15:45:24 +0000 (UTC) Received: from gabe.freedesktop.org (gabe.freedesktop.org [131.252.210.177]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by mail.kernel.org (Postfix) with ESMTPS id E527621D71 for ; Wed, 23 Oct 2019 15:45:23 +0000 (UTC) DMARC-Filter: OpenDMARC Filter v1.3.2 mail.kernel.org E527621D71 Authentication-Results: mail.kernel.org; dmarc=fail (p=none dis=none) header.from=collabora.com Authentication-Results: mail.kernel.org; spf=none smtp.mailfrom=dri-devel-bounces@lists.freedesktop.org Received: from gabe.freedesktop.org (localhost [127.0.0.1]) by gabe.freedesktop.org (Postfix) with ESMTP id F295C6EB1C; Wed, 23 Oct 2019 15:45:22 +0000 (UTC) X-Original-To: dri-devel@lists.freedesktop.org Delivered-To: dri-devel@lists.freedesktop.org Received: from bhuna.collabora.co.uk (bhuna.collabora.co.uk [IPv6:2a00:1098:0:82:1000:25:2eeb:e3e3]) by gabe.freedesktop.org (Postfix) with ESMTPS id 071606EB1A for ; Wed, 23 Oct 2019 15:45:20 +0000 (UTC) Received: from localhost.localdomain (unknown [IPv6:2a01:e0a:2c:6930:5cf4:84a1:2763:fe0d]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) (Authenticated sender: bbrezillon) by bhuna.collabora.co.uk (Postfix) with ESMTPSA id 2922228F907; Wed, 23 Oct 2019 16:45:18 +0100 (BST) From: Boris Brezillon To: dri-devel@lists.freedesktop.org Subject: [PATCH v3 02/21] drm/exynos: Don't reset bridge->next Date: Wed, 23 Oct 2019 17:44:53 +0200 Message-Id: <20191023154512.9762-3-boris.brezillon@collabora.com> X-Mailer: git-send-email 2.21.0 In-Reply-To: <20191023154512.9762-1-boris.brezillon@collabora.com> References: <20191023154512.9762-1-boris.brezillon@collabora.com> MIME-Version: 1.0 X-BeenThere: dri-devel@lists.freedesktop.org X-Mailman-Version: 2.1.23 Precedence: list List-Id: Direct Rendering Infrastructure - Development List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: Mark Rutland , Neil Armstrong , Thierry Reding , Laurent Pinchart , kernel@collabora.com, Sam Ravnborg , Nikita Yushchenko , Andrey Smirnov , Kyungmin Park , Chris Healy , devicetree@vger.kernel.org, Jonas Karlman , Rob Herring , Jernej Skrabec , Seung-Woo Kim , Boris Brezillon Errors-To: dri-devel-bounces@lists.freedesktop.org Sender: "dri-devel" bridge->next is only points to the new bridge if drm_bridge_attach() succeeds. No need to reset it manually here. Note that this change is part of the attempt to make the bridge chain a double-linked list. In order to do that we must patch all drivers manipulating the bridge->next field. Signed-off-by: Boris Brezillon Reviewed-by: Laurent Pinchart Acked-by: Inki Dae --- Changes in v2: * Add Laurent's R-b (I'd like to have a R-b from the DRM exynos maintainers before applying that one) --- drivers/gpu/drm/exynos/exynos_dp.c | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/gpu/drm/exynos/exynos_dp.c b/drivers/gpu/drm/exynos/exynos_dp.c index 1e6aa24bf45e..4785885c0f4f 100644 --- a/drivers/gpu/drm/exynos/exynos_dp.c +++ b/drivers/gpu/drm/exynos/exynos_dp.c @@ -110,7 +110,6 @@ static int exynos_dp_bridge_attach(struct analogix_dp_plat_data *plat_data, if (ret) { DRM_DEV_ERROR(dp->dev, "Failed to attach bridge to drm\n"); - bridge->next = NULL; return ret; } } From patchwork Wed Oct 23 15:44:54 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Boris Brezillon X-Patchwork-Id: 11207091 Return-Path: Received: from mail.kernel.org (pdx-korg-mail-1.web.codeaurora.org [172.30.200.123]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id 5FAB113BD for ; Wed, 23 Oct 2019 15:45:31 +0000 (UTC) Received: from gabe.freedesktop.org (gabe.freedesktop.org [131.252.210.177]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by mail.kernel.org (Postfix) with ESMTPS id 4772721D71 for ; Wed, 23 Oct 2019 15:45:31 +0000 (UTC) DMARC-Filter: OpenDMARC Filter v1.3.2 mail.kernel.org 4772721D71 Authentication-Results: mail.kernel.org; dmarc=fail (p=none dis=none) header.from=collabora.com Authentication-Results: mail.kernel.org; spf=none smtp.mailfrom=dri-devel-bounces@lists.freedesktop.org Received: from gabe.freedesktop.org (localhost [127.0.0.1]) by gabe.freedesktop.org (Postfix) with ESMTP id DD7A0891B1; Wed, 23 Oct 2019 15:45:26 +0000 (UTC) X-Original-To: dri-devel@lists.freedesktop.org Delivered-To: dri-devel@lists.freedesktop.org Received: from bhuna.collabora.co.uk (bhuna.collabora.co.uk [IPv6:2a00:1098:0:82:1000:25:2eeb:e3e3]) by gabe.freedesktop.org (Postfix) with ESMTPS id B0B726EB1B for ; Wed, 23 Oct 2019 15:45:20 +0000 (UTC) Received: from localhost.localdomain (unknown [IPv6:2a01:e0a:2c:6930:5cf4:84a1:2763:fe0d]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) (Authenticated sender: bbrezillon) by bhuna.collabora.co.uk (Postfix) with ESMTPSA id EE7A128F90B; Wed, 23 Oct 2019 16:45:18 +0100 (BST) From: Boris Brezillon To: dri-devel@lists.freedesktop.org Subject: [PATCH v3 03/21] drm/exynos: Declare the DSI encoder as a bridge element Date: Wed, 23 Oct 2019 17:44:54 +0200 Message-Id: <20191023154512.9762-4-boris.brezillon@collabora.com> X-Mailer: git-send-email 2.21.0 In-Reply-To: <20191023154512.9762-1-boris.brezillon@collabora.com> References: <20191023154512.9762-1-boris.brezillon@collabora.com> MIME-Version: 1.0 X-BeenThere: dri-devel@lists.freedesktop.org X-Mailman-Version: 2.1.23 Precedence: list List-Id: Direct Rendering Infrastructure - Development List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: Mark Rutland , Neil Armstrong , Thierry Reding , Laurent Pinchart , kernel@collabora.com, Sam Ravnborg , Nikita Yushchenko , Andrey Smirnov , Kyungmin Park , Chris Healy , devicetree@vger.kernel.org, Jonas Karlman , Rob Herring , Jernej Skrabec , Seung-Woo Kim , Boris Brezillon Errors-To: dri-devel-bounces@lists.freedesktop.org Sender: "dri-devel" Encoder drivers will progressively transition to the drm_bridge interface in place of the drm_encoder one. Converting the Exynos DSI encoder driver to this approach allows us to use the ->pre_{enable,disable}() hooks and get rid of the hack resetting encoder->bridge.next (which was needed to control the encoder/bridge enable/disable sequence). Signed-off-by: Boris Brezillon --- Changes in v3: * Embed a drm_bridge object in exynos_dsi since drm_encoder no longer has a dummy bridge Changes in v2: * New patch (replacement for "drm/exynos: Get rid of exynos_dsi->out_bridge") --- drivers/gpu/drm/exynos/exynos_drm_dsi.c | 89 +++++++++++++++---------- 1 file changed, 55 insertions(+), 34 deletions(-) diff --git a/drivers/gpu/drm/exynos/exynos_drm_dsi.c b/drivers/gpu/drm/exynos/exynos_drm_dsi.c index 72726f2c7a9f..3915f50b005e 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_dsi.c +++ b/drivers/gpu/drm/exynos/exynos_drm_dsi.c @@ -252,10 +252,10 @@ struct exynos_dsi_driver_data { struct exynos_dsi { struct drm_encoder encoder; + struct drm_bridge bridge; struct mipi_dsi_host dsi_host; struct drm_connector connector; struct drm_panel *panel; - struct drm_bridge *out_bridge; struct device *dev; void __iomem *reg_base; @@ -291,6 +291,11 @@ static inline struct exynos_dsi *encoder_to_dsi(struct drm_encoder *e) return container_of(e, struct exynos_dsi, encoder); } +static inline struct exynos_dsi *bridge_to_dsi(struct drm_bridge *b) +{ + return container_of(b, struct exynos_dsi, bridge); +} + enum reg_idx { DSIM_STATUS_REG, /* Status register */ DSIM_SWRST_REG, /* Software reset register */ @@ -1374,25 +1379,38 @@ static void exynos_dsi_unregister_te_irq(struct exynos_dsi *dsi) } } -static void exynos_dsi_enable(struct drm_encoder *encoder) +static void exynos_dsi_pre_enable(struct drm_bridge *bridge) { - struct exynos_dsi *dsi = encoder_to_dsi(encoder); + struct exynos_dsi *dsi = bridge_to_dsi(bridge); int ret; if (dsi->state & DSIM_STATE_ENABLED) return; pm_runtime_get_sync(dsi->dev); - dsi->state |= DSIM_STATE_ENABLED; if (dsi->panel) { ret = drm_panel_prepare(dsi->panel); if (ret < 0) goto err_put_sync; - } else { - drm_bridge_pre_enable(dsi->out_bridge); } + dsi->state |= DSIM_STATE_ENABLED; + return; + +err_put_sync: + pm_runtime_put(dsi->dev); +} + +static void exynos_dsi_enable(struct drm_bridge *bridge) +{ + struct exynos_dsi *dsi = bridge_to_dsi(bridge); + int ret; + + if (!(dsi->state & DSIM_STATE_ENABLED) || + (dsi->state & DSIM_STATE_VIDOUT_AVAILABLE)) + return; + exynos_dsi_set_display_mode(dsi); exynos_dsi_set_display_enable(dsi, true); @@ -1400,8 +1418,6 @@ static void exynos_dsi_enable(struct drm_encoder *encoder) ret = drm_panel_enable(dsi->panel); if (ret < 0) goto err_display_disable; - } else { - drm_bridge_enable(dsi->out_bridge); } dsi->state |= DSIM_STATE_VIDOUT_AVAILABLE; @@ -1410,28 +1426,30 @@ static void exynos_dsi_enable(struct drm_encoder *encoder) err_display_disable: exynos_dsi_set_display_enable(dsi, false); drm_panel_unprepare(dsi->panel); - -err_put_sync: - dsi->state &= ~DSIM_STATE_ENABLED; - pm_runtime_put(dsi->dev); } -static void exynos_dsi_disable(struct drm_encoder *encoder) +static void exynos_dsi_disable(struct drm_bridge *bridge) { - struct exynos_dsi *dsi = encoder_to_dsi(encoder); + struct exynos_dsi *dsi = bridge_to_dsi(bridge); + + if (!(dsi->state & DSIM_STATE_VIDOUT_AVAILABLE)) + return; + + drm_panel_disable(dsi->panel); + exynos_dsi_set_display_enable(dsi, false); + dsi->state &= ~DSIM_STATE_VIDOUT_AVAILABLE; +} + +static void exynos_dsi_post_disable(struct drm_bridge *bridge) +{ + struct exynos_dsi *dsi = bridge_to_dsi(bridge); if (!(dsi->state & DSIM_STATE_ENABLED)) return; - dsi->state &= ~DSIM_STATE_VIDOUT_AVAILABLE; - - drm_panel_disable(dsi->panel); - drm_bridge_disable(dsi->out_bridge); - exynos_dsi_set_display_enable(dsi, false); drm_panel_unprepare(dsi->panel); - drm_bridge_post_disable(dsi->out_bridge); - dsi->state &= ~DSIM_STATE_ENABLED; pm_runtime_put_sync(dsi->dev); + dsi->state &= ~DSIM_STATE_ENABLED; } static enum drm_connector_status @@ -1499,9 +1517,11 @@ static int exynos_dsi_create_connector(struct drm_encoder *encoder) return 0; } -static const struct drm_encoder_helper_funcs exynos_dsi_encoder_helper_funcs = { +static const struct drm_bridge_funcs exynos_dsi_bridge_funcs = { + .pre_enable = exynos_dsi_pre_enable, .enable = exynos_dsi_enable, .disable = exynos_dsi_disable, + .post_disable = exynos_dsi_post_disable, }; static const struct drm_encoder_funcs exynos_dsi_encoder_funcs = { @@ -1520,9 +1540,7 @@ static int exynos_dsi_host_attach(struct mipi_dsi_host *host, out_bridge = of_drm_find_bridge(device->dev.of_node); if (out_bridge) { - drm_bridge_attach(encoder, out_bridge, NULL); - dsi->out_bridge = out_bridge; - encoder->bridge = NULL; + drm_bridge_attach(encoder, out_bridge, &dsi->bridge); } else { int ret = exynos_dsi_create_connector(encoder); @@ -1575,19 +1593,19 @@ static int exynos_dsi_host_detach(struct mipi_dsi_host *host, struct mipi_dsi_device *device) { struct exynos_dsi *dsi = host_to_dsi(host); + struct drm_bridge *out_bridge = dsi->bridge.next; struct drm_device *drm = dsi->encoder.dev; if (dsi->panel) { mutex_lock(&drm->mode_config.mutex); - exynos_dsi_disable(&dsi->encoder); + exynos_dsi_disable(&dsi->bridge); + exynos_dsi_post_disable(&dsi->bridge); drm_panel_detach(dsi->panel); dsi->panel = NULL; dsi->connector.status = connector_status_disconnected; mutex_unlock(&drm->mode_config.mutex); - } else { - if (dsi->out_bridge->funcs->detach) - dsi->out_bridge->funcs->detach(dsi->out_bridge); - dsi->out_bridge = NULL; + } else if (out_bridge && out_bridge->funcs->detach) { + out_bridge->funcs->detach(out_bridge); } if (drm->mode_config.poll_enabled) @@ -1687,16 +1705,18 @@ static int exynos_dsi_bind(struct device *dev, struct device *master, drm_encoder_init(drm_dev, encoder, &exynos_dsi_encoder_funcs, DRM_MODE_ENCODER_TMDS, NULL); - drm_encoder_helper_add(encoder, &exynos_dsi_encoder_helper_funcs); - ret = exynos_drm_set_possible_crtcs(encoder, EXYNOS_DISPLAY_TYPE_LCD); if (ret < 0) return ret; + /* Declare ourself as the first bridge element. */ + dsi->bridge.funcs = &exynos_dsi_bridge_funcs; + drm_bridge_attach(encoder, &dsi->bridge, NULL); + if (dsi->in_bridge_node) { in_bridge = of_drm_find_bridge(dsi->in_bridge_node); if (in_bridge) - drm_bridge_attach(encoder, in_bridge, NULL); + drm_bridge_attach(encoder, in_bridge, &dsi->bridge); } return mipi_dsi_host_register(&dsi->dsi_host); @@ -1708,7 +1728,8 @@ static void exynos_dsi_unbind(struct device *dev, struct device *master, struct drm_encoder *encoder = dev_get_drvdata(dev); struct exynos_dsi *dsi = encoder_to_dsi(encoder); - exynos_dsi_disable(encoder); + exynos_dsi_disable(&dsi->bridge); + exynos_dsi_post_disable(&dsi->bridge); mipi_dsi_host_unregister(&dsi->dsi_host); } From patchwork Wed Oct 23 15:44:55 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Boris Brezillon X-Patchwork-Id: 11207121 Return-Path: Received: from mail.kernel.org (pdx-korg-mail-1.web.codeaurora.org [172.30.200.123]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id 389FB1390 for ; Wed, 23 Oct 2019 15:46:10 +0000 (UTC) Received: from gabe.freedesktop.org (gabe.freedesktop.org [131.252.210.177]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by mail.kernel.org (Postfix) with ESMTPS id 2113720679 for ; Wed, 23 Oct 2019 15:46:10 +0000 (UTC) DMARC-Filter: OpenDMARC Filter v1.3.2 mail.kernel.org 2113720679 Authentication-Results: mail.kernel.org; dmarc=fail (p=none dis=none) header.from=collabora.com Authentication-Results: mail.kernel.org; spf=none smtp.mailfrom=dri-devel-bounces@lists.freedesktop.org Received: from gabe.freedesktop.org (localhost [127.0.0.1]) by gabe.freedesktop.org (Postfix) with ESMTP id E428B6EB2C; Wed, 23 Oct 2019 15:46:04 +0000 (UTC) X-Original-To: dri-devel@lists.freedesktop.org Delivered-To: dri-devel@lists.freedesktop.org Received: from bhuna.collabora.co.uk (bhuna.collabora.co.uk [IPv6:2a00:1098:0:82:1000:25:2eeb:e3e3]) by gabe.freedesktop.org (Postfix) with ESMTPS id B20296EB1B for ; Wed, 23 Oct 2019 15:45:22 +0000 (UTC) Received: from localhost.localdomain (unknown [IPv6:2a01:e0a:2c:6930:5cf4:84a1:2763:fe0d]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) (Authenticated sender: bbrezillon) by bhuna.collabora.co.uk (Postfix) with ESMTPSA id B794D28F90F; Wed, 23 Oct 2019 16:45:19 +0100 (BST) From: Boris Brezillon To: dri-devel@lists.freedesktop.org Subject: [PATCH v3 04/21] drm/bridge: Rename bridge helpers targeting a bridge chain Date: Wed, 23 Oct 2019 17:44:55 +0200 Message-Id: <20191023154512.9762-5-boris.brezillon@collabora.com> X-Mailer: git-send-email 2.21.0 In-Reply-To: <20191023154512.9762-1-boris.brezillon@collabora.com> References: <20191023154512.9762-1-boris.brezillon@collabora.com> MIME-Version: 1.0 X-BeenThere: dri-devel@lists.freedesktop.org X-Mailman-Version: 2.1.23 Precedence: list List-Id: Direct Rendering Infrastructure - Development List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: Mark Rutland , Neil Armstrong , Thierry Reding , Laurent Pinchart , kernel@collabora.com, Sam Ravnborg , Nikita Yushchenko , Andrey Smirnov , Kyungmin Park , Chris Healy , devicetree@vger.kernel.org, Jonas Karlman , Rob Herring , Jernej Skrabec , Seung-Woo Kim , Boris Brezillon Errors-To: dri-devel-bounces@lists.freedesktop.org Sender: "dri-devel" Change the prefix of bridge helpers targeting a bridge chain from drm_bridge_ to drm_bridge_chain_ to better reflect the fact that the operation will happen on all elements of chain, starting at the bridge passed in argument. Signed-off-by: Boris Brezillon Reviewed-by: Neil Armstrong Acked-by: Laurent Pinchart --- Changes in v3: * None Changes in v2: * Pass te bridge, not the encoder, so we can later act on a sub-chain instead of the whole chain --- drivers/gpu/drm/drm_atomic_helper.c | 19 +++-- drivers/gpu/drm/drm_bridge.c | 125 ++++++++++++++-------------- drivers/gpu/drm/drm_probe_helper.c | 2 +- drivers/gpu/drm/mediatek/mtk_hdmi.c | 4 +- include/drm/drm_bridge.h | 64 +++++++------- 5 files changed, 112 insertions(+), 102 deletions(-) diff --git a/drivers/gpu/drm/drm_atomic_helper.c b/drivers/gpu/drm/drm_atomic_helper.c index 587052751b48..cf678be58fa4 100644 --- a/drivers/gpu/drm/drm_atomic_helper.c +++ b/drivers/gpu/drm/drm_atomic_helper.c @@ -435,8 +435,9 @@ mode_fixup(struct drm_atomic_state *state) encoder = new_conn_state->best_encoder; funcs = encoder->helper_private; - ret = drm_bridge_mode_fixup(encoder->bridge, &new_crtc_state->mode, - &new_crtc_state->adjusted_mode); + ret = drm_bridge_chain_mode_fixup(encoder->bridge, + &new_crtc_state->mode, + &new_crtc_state->adjusted_mode); if (!ret) { DRM_DEBUG_ATOMIC("Bridge fixup failed\n"); return -EINVAL; @@ -501,7 +502,7 @@ static enum drm_mode_status mode_valid_path(struct drm_connector *connector, return ret; } - ret = drm_bridge_mode_valid(encoder->bridge, mode); + ret = drm_bridge_chain_mode_valid(encoder->bridge, mode); if (ret != MODE_OK) { DRM_DEBUG_ATOMIC("[BRIDGE] mode_valid() failed\n"); return ret; @@ -1020,7 +1021,7 @@ disable_outputs(struct drm_device *dev, struct drm_atomic_state *old_state) * Each encoder has at most one connector (since we always steal * it away), so we won't call disable hooks twice. */ - drm_atomic_bridge_disable(encoder->bridge, old_state); + drm_atomic_bridge_chain_disable(encoder->bridge, old_state); /* Right function depends upon target state. */ if (funcs) { @@ -1034,7 +1035,8 @@ disable_outputs(struct drm_device *dev, struct drm_atomic_state *old_state) funcs->dpms(encoder, DRM_MODE_DPMS_OFF); } - drm_atomic_bridge_post_disable(encoder->bridge, old_state); + drm_atomic_bridge_chain_post_disable(encoder->bridge, + old_state); } for_each_oldnew_crtc_in_state(old_state, crtc, old_crtc_state, new_crtc_state, i) { @@ -1215,7 +1217,8 @@ crtc_set_mode(struct drm_device *dev, struct drm_atomic_state *old_state) funcs->mode_set(encoder, mode, adjusted_mode); } - drm_bridge_mode_set(encoder->bridge, mode, adjusted_mode); + drm_bridge_chain_mode_set(encoder->bridge, mode, + adjusted_mode); } } @@ -1332,7 +1335,7 @@ void drm_atomic_helper_commit_modeset_enables(struct drm_device *dev, * Each encoder has at most one connector (since we always steal * it away), so we won't call enable hooks twice. */ - drm_atomic_bridge_pre_enable(encoder->bridge, old_state); + drm_atomic_bridge_chain_pre_enable(encoder->bridge, old_state); if (funcs) { if (funcs->atomic_enable) @@ -1343,7 +1346,7 @@ void drm_atomic_helper_commit_modeset_enables(struct drm_device *dev, funcs->commit(encoder); } - drm_atomic_bridge_enable(encoder->bridge, old_state); + drm_atomic_bridge_chain_enable(encoder->bridge, old_state); } drm_atomic_helper_commit_writebacks(dev, old_state); diff --git a/drivers/gpu/drm/drm_bridge.c b/drivers/gpu/drm/drm_bridge.c index cba537c99e43..54c874493c57 100644 --- a/drivers/gpu/drm/drm_bridge.c +++ b/drivers/gpu/drm/drm_bridge.c @@ -172,8 +172,8 @@ void drm_bridge_detach(struct drm_bridge *bridge) */ /** - * drm_bridge_mode_fixup - fixup proposed mode for all bridges in the - * encoder chain + * drm_bridge_chain_mode_fixup - fixup proposed mode for all bridges in the + * encoder chain * @bridge: bridge control structure * @mode: desired mode to be set for the bridge * @adjusted_mode: updated mode that works for this bridge @@ -186,9 +186,9 @@ void drm_bridge_detach(struct drm_bridge *bridge) * RETURNS: * true on success, false on failure */ -bool drm_bridge_mode_fixup(struct drm_bridge *bridge, - const struct drm_display_mode *mode, - struct drm_display_mode *adjusted_mode) +bool drm_bridge_chain_mode_fixup(struct drm_bridge *bridge, + const struct drm_display_mode *mode, + struct drm_display_mode *adjusted_mode) { bool ret = true; @@ -198,15 +198,16 @@ bool drm_bridge_mode_fixup(struct drm_bridge *bridge, if (bridge->funcs->mode_fixup) ret = bridge->funcs->mode_fixup(bridge, mode, adjusted_mode); - ret = ret && drm_bridge_mode_fixup(bridge->next, mode, adjusted_mode); + ret = ret && drm_bridge_chain_mode_fixup(bridge->next, mode, + adjusted_mode); return ret; } -EXPORT_SYMBOL(drm_bridge_mode_fixup); +EXPORT_SYMBOL(drm_bridge_chain_mode_fixup); /** - * drm_bridge_mode_valid - validate the mode against all bridges in the - * encoder chain. + * drm_bridge_chain_mode_valid - validate the mode against all bridges in the + * encoder chain. * @bridge: bridge control structure * @mode: desired mode to be validated * @@ -219,8 +220,9 @@ EXPORT_SYMBOL(drm_bridge_mode_fixup); * RETURNS: * MODE_OK on success, drm_mode_status Enum error code on failure */ -enum drm_mode_status drm_bridge_mode_valid(struct drm_bridge *bridge, - const struct drm_display_mode *mode) +enum drm_mode_status +drm_bridge_chain_mode_valid(struct drm_bridge *bridge, + const struct drm_display_mode *mode) { enum drm_mode_status ret = MODE_OK; @@ -233,12 +235,12 @@ enum drm_mode_status drm_bridge_mode_valid(struct drm_bridge *bridge, if (ret != MODE_OK) return ret; - return drm_bridge_mode_valid(bridge->next, mode); + return drm_bridge_chain_mode_valid(bridge->next, mode); } -EXPORT_SYMBOL(drm_bridge_mode_valid); +EXPORT_SYMBOL(drm_bridge_chain_mode_valid); /** - * drm_bridge_disable - disables all bridges in the encoder chain + * drm_bridge_chain_disable - disables all bridges in the encoder chain * @bridge: bridge control structure * * Calls &drm_bridge_funcs.disable op for all the bridges in the encoder @@ -247,20 +249,21 @@ EXPORT_SYMBOL(drm_bridge_mode_valid); * * Note: the bridge passed should be the one closest to the encoder */ -void drm_bridge_disable(struct drm_bridge *bridge) +void drm_bridge_chain_disable(struct drm_bridge *bridge) { if (!bridge) return; - drm_bridge_disable(bridge->next); + drm_bridge_chain_disable(bridge->next); if (bridge->funcs->disable) bridge->funcs->disable(bridge); } -EXPORT_SYMBOL(drm_bridge_disable); +EXPORT_SYMBOL(drm_bridge_chain_disable); /** - * drm_bridge_post_disable - cleans up after disabling all bridges in the encoder chain + * drm_bridge_chain_post_disable - cleans up after disabling all bridges in the + * encoder chain * @bridge: bridge control structure * * Calls &drm_bridge_funcs.post_disable op for all the bridges in the @@ -269,7 +272,7 @@ EXPORT_SYMBOL(drm_bridge_disable); * * Note: the bridge passed should be the one closest to the encoder */ -void drm_bridge_post_disable(struct drm_bridge *bridge) +void drm_bridge_chain_post_disable(struct drm_bridge *bridge) { if (!bridge) return; @@ -277,25 +280,25 @@ void drm_bridge_post_disable(struct drm_bridge *bridge) if (bridge->funcs->post_disable) bridge->funcs->post_disable(bridge); - drm_bridge_post_disable(bridge->next); + drm_bridge_chain_post_disable(bridge->next); } -EXPORT_SYMBOL(drm_bridge_post_disable); +EXPORT_SYMBOL(drm_bridge_chain_post_disable); /** - * drm_bridge_mode_set - set proposed mode for all bridges in the - * encoder chain + * drm_bridge_chain_mode_set - set proposed mode for all bridges in the + * encoder chain * @bridge: bridge control structure - * @mode: desired mode to be set for the bridge - * @adjusted_mode: updated mode that works for this bridge + * @mode: desired mode to be set for the encoder chain + * @adjusted_mode: updated mode that works for this encoder chain * * Calls &drm_bridge_funcs.mode_set op for all the bridges in the * encoder chain, starting from the first bridge to the last. * * Note: the bridge passed should be the one closest to the encoder */ -void drm_bridge_mode_set(struct drm_bridge *bridge, - const struct drm_display_mode *mode, - const struct drm_display_mode *adjusted_mode) +void drm_bridge_chain_mode_set(struct drm_bridge *bridge, + const struct drm_display_mode *mode, + const struct drm_display_mode *adjusted_mode) { if (!bridge) return; @@ -303,13 +306,13 @@ void drm_bridge_mode_set(struct drm_bridge *bridge, if (bridge->funcs->mode_set) bridge->funcs->mode_set(bridge, mode, adjusted_mode); - drm_bridge_mode_set(bridge->next, mode, adjusted_mode); + drm_bridge_chain_mode_set(bridge->next, mode, adjusted_mode); } -EXPORT_SYMBOL(drm_bridge_mode_set); +EXPORT_SYMBOL(drm_bridge_chain_mode_set); /** - * drm_bridge_pre_enable - prepares for enabling all - * bridges in the encoder chain + * drm_bridge_chain_pre_enable - prepares for enabling all bridges in the + * encoder chain * @bridge: bridge control structure * * Calls &drm_bridge_funcs.pre_enable op for all the bridges in the encoder @@ -318,20 +321,20 @@ EXPORT_SYMBOL(drm_bridge_mode_set); * * Note: the bridge passed should be the one closest to the encoder */ -void drm_bridge_pre_enable(struct drm_bridge *bridge) +void drm_bridge_chain_pre_enable(struct drm_bridge *bridge) { if (!bridge) return; - drm_bridge_pre_enable(bridge->next); + drm_bridge_chain_pre_enable(bridge->next); if (bridge->funcs->pre_enable) bridge->funcs->pre_enable(bridge); } -EXPORT_SYMBOL(drm_bridge_pre_enable); +EXPORT_SYMBOL(drm_bridge_chain_pre_enable); /** - * drm_bridge_enable - enables all bridges in the encoder chain + * drm_bridge_chain_enable - enables all bridges in the encoder chain * @bridge: bridge control structure * * Calls &drm_bridge_funcs.enable op for all the bridges in the encoder @@ -340,7 +343,7 @@ EXPORT_SYMBOL(drm_bridge_pre_enable); * * Note that the bridge passed should be the one closest to the encoder */ -void drm_bridge_enable(struct drm_bridge *bridge) +void drm_bridge_chain_enable(struct drm_bridge *bridge) { if (!bridge) return; @@ -348,12 +351,12 @@ void drm_bridge_enable(struct drm_bridge *bridge) if (bridge->funcs->enable) bridge->funcs->enable(bridge); - drm_bridge_enable(bridge->next); + drm_bridge_chain_enable(bridge->next); } -EXPORT_SYMBOL(drm_bridge_enable); +EXPORT_SYMBOL(drm_bridge_chain_enable); /** - * drm_atomic_bridge_disable - disables all bridges in the encoder chain + * drm_atomic_bridge_chain_disable - disables all bridges in the encoder chain * @bridge: bridge control structure * @state: atomic state being committed * @@ -364,24 +367,24 @@ EXPORT_SYMBOL(drm_bridge_enable); * * Note: the bridge passed should be the one closest to the encoder */ -void drm_atomic_bridge_disable(struct drm_bridge *bridge, - struct drm_atomic_state *state) +void drm_atomic_bridge_chain_disable(struct drm_bridge *bridge, + struct drm_atomic_state *state) { if (!bridge) return; - drm_atomic_bridge_disable(bridge->next, state); + drm_atomic_bridge_chain_disable(bridge->next, state); if (bridge->funcs->atomic_disable) bridge->funcs->atomic_disable(bridge, state); else if (bridge->funcs->disable) bridge->funcs->disable(bridge); } -EXPORT_SYMBOL(drm_atomic_bridge_disable); +EXPORT_SYMBOL(drm_atomic_bridge_chain_disable); /** - * drm_atomic_bridge_post_disable - cleans up after disabling all bridges in the - * encoder chain + * drm_atomic_bridge_chain_post_disable - cleans up after disabling all bridges + * in the encoder chain * @bridge: bridge control structure * @state: atomic state being committed * @@ -392,8 +395,8 @@ EXPORT_SYMBOL(drm_atomic_bridge_disable); * * Note: the bridge passed should be the one closest to the encoder */ -void drm_atomic_bridge_post_disable(struct drm_bridge *bridge, - struct drm_atomic_state *state) +void drm_atomic_bridge_chain_post_disable(struct drm_bridge *bridge, + struct drm_atomic_state *state) { if (!bridge) return; @@ -403,13 +406,13 @@ void drm_atomic_bridge_post_disable(struct drm_bridge *bridge, else if (bridge->funcs->post_disable) bridge->funcs->post_disable(bridge); - drm_atomic_bridge_post_disable(bridge->next, state); + drm_atomic_bridge_chain_post_disable(bridge->next, state); } -EXPORT_SYMBOL(drm_atomic_bridge_post_disable); +EXPORT_SYMBOL(drm_atomic_bridge_chain_post_disable); /** - * drm_atomic_bridge_pre_enable - prepares for enabling all bridges in the - * encoder chain + * drm_atomic_bridge_chain_pre_enable - prepares for enabling all bridges in + * the encoder chain * @bridge: bridge control structure * @state: atomic state being committed * @@ -420,23 +423,23 @@ EXPORT_SYMBOL(drm_atomic_bridge_post_disable); * * Note: the bridge passed should be the one closest to the encoder */ -void drm_atomic_bridge_pre_enable(struct drm_bridge *bridge, - struct drm_atomic_state *state) +void drm_atomic_bridge_chain_pre_enable(struct drm_bridge *bridge, + struct drm_atomic_state *state) { if (!bridge) return; - drm_atomic_bridge_pre_enable(bridge->next, state); + drm_atomic_bridge_chain_pre_enable(bridge->next, state); if (bridge->funcs->atomic_pre_enable) bridge->funcs->atomic_pre_enable(bridge, state); else if (bridge->funcs->pre_enable) bridge->funcs->pre_enable(bridge); } -EXPORT_SYMBOL(drm_atomic_bridge_pre_enable); +EXPORT_SYMBOL(drm_atomic_bridge_chain_pre_enable); /** - * drm_atomic_bridge_enable - enables all bridges in the encoder chain + * drm_atomic_bridge_chain_enable - enables all bridges in the encoder chain * @bridge: bridge control structure * @state: atomic state being committed * @@ -447,8 +450,8 @@ EXPORT_SYMBOL(drm_atomic_bridge_pre_enable); * * Note: the bridge passed should be the one closest to the encoder */ -void drm_atomic_bridge_enable(struct drm_bridge *bridge, - struct drm_atomic_state *state) +void drm_atomic_bridge_chain_enable(struct drm_bridge *bridge, + struct drm_atomic_state *state) { if (!bridge) return; @@ -458,9 +461,9 @@ void drm_atomic_bridge_enable(struct drm_bridge *bridge, else if (bridge->funcs->enable) bridge->funcs->enable(bridge); - drm_atomic_bridge_enable(bridge->next, state); + drm_atomic_bridge_chain_enable(bridge->next, state); } -EXPORT_SYMBOL(drm_atomic_bridge_enable); +EXPORT_SYMBOL(drm_atomic_bridge_chain_enable); #ifdef CONFIG_OF /** diff --git a/drivers/gpu/drm/drm_probe_helper.c b/drivers/gpu/drm/drm_probe_helper.c index a7c87abe88d0..c3ea722065c4 100644 --- a/drivers/gpu/drm/drm_probe_helper.c +++ b/drivers/gpu/drm/drm_probe_helper.c @@ -112,7 +112,7 @@ drm_mode_validate_pipeline(struct drm_display_mode *mode, continue; } - ret = drm_bridge_mode_valid(encoder->bridge, mode); + ret = drm_bridge_chain_mode_valid(encoder->bridge, mode); if (ret != MODE_OK) { /* There is also no point in continuing for crtc check * here. */ diff --git a/drivers/gpu/drm/mediatek/mtk_hdmi.c b/drivers/gpu/drm/mediatek/mtk_hdmi.c index c79b1f855d89..ea68b5adccbe 100644 --- a/drivers/gpu/drm/mediatek/mtk_hdmi.c +++ b/drivers/gpu/drm/mediatek/mtk_hdmi.c @@ -1247,8 +1247,8 @@ static int mtk_hdmi_conn_mode_valid(struct drm_connector *conn, struct drm_display_mode adjusted_mode; drm_mode_copy(&adjusted_mode, mode); - if (!drm_bridge_mode_fixup(hdmi->bridge.next, mode, - &adjusted_mode)) + if (!drm_bridge_chain_mode_fixup(hdmi->bridge.next, mode, + &adjusted_mode)) return MODE_BAD; } diff --git a/include/drm/drm_bridge.h b/include/drm/drm_bridge.h index c0a2286a81e9..726435baf4ad 100644 --- a/include/drm/drm_bridge.h +++ b/include/drm/drm_bridge.h @@ -254,9 +254,10 @@ struct drm_bridge_funcs { * there is one) when this callback is called. * * Note that this function will only be invoked in the context of an - * atomic commit. It will not be invoked from &drm_bridge_pre_enable. It - * would be prudent to also provide an implementation of @pre_enable if - * you are expecting driver calls into &drm_bridge_pre_enable. + * atomic commit. It will not be invoked from + * &drm_bridge_chain_pre_enable. It would be prudent to also provide an + * implementation of @pre_enable if you are expecting driver calls into + * &drm_bridge_chain_pre_enable. * * The @atomic_pre_enable callback is optional. */ @@ -279,9 +280,9 @@ struct drm_bridge_funcs { * chain if there is one. * * Note that this function will only be invoked in the context of an - * atomic commit. It will not be invoked from &drm_bridge_enable. It - * would be prudent to also provide an implementation of @enable if - * you are expecting driver calls into &drm_bridge_enable. + * atomic commit. It will not be invoked from &drm_bridge_chain_enable. + * It would be prudent to also provide an implementation of @enable if + * you are expecting driver calls into &drm_bridge_chain_enable. * * The @atomic_enable callback is optional. */ @@ -301,9 +302,10 @@ struct drm_bridge_funcs { * signals) feeding it is still running when this callback is called. * * Note that this function will only be invoked in the context of an - * atomic commit. It will not be invoked from &drm_bridge_disable. It - * would be prudent to also provide an implementation of @disable if - * you are expecting driver calls into &drm_bridge_disable. + * atomic commit. It will not be invoked from + * &drm_bridge_chain_disable. It would be prudent to also provide an + * implementation of @disable if you are expecting driver calls into + * &drm_bridge_chain_disable. * * The @atomic_disable callback is optional. */ @@ -325,10 +327,11 @@ struct drm_bridge_funcs { * called. * * Note that this function will only be invoked in the context of an - * atomic commit. It will not be invoked from &drm_bridge_post_disable. + * atomic commit. It will not be invoked from + * &drm_bridge_chain_post_disable. * It would be prudent to also provide an implementation of * @post_disable if you are expecting driver calls into - * &drm_bridge_post_disable. + * &drm_bridge_chain_post_disable. * * The @atomic_post_disable callback is optional. */ @@ -406,27 +409,28 @@ struct drm_bridge *of_drm_find_bridge(struct device_node *np); int drm_bridge_attach(struct drm_encoder *encoder, struct drm_bridge *bridge, struct drm_bridge *previous); -bool drm_bridge_mode_fixup(struct drm_bridge *bridge, - const struct drm_display_mode *mode, - struct drm_display_mode *adjusted_mode); -enum drm_mode_status drm_bridge_mode_valid(struct drm_bridge *bridge, - const struct drm_display_mode *mode); -void drm_bridge_disable(struct drm_bridge *bridge); -void drm_bridge_post_disable(struct drm_bridge *bridge); -void drm_bridge_mode_set(struct drm_bridge *bridge, - const struct drm_display_mode *mode, - const struct drm_display_mode *adjusted_mode); -void drm_bridge_pre_enable(struct drm_bridge *bridge); -void drm_bridge_enable(struct drm_bridge *bridge); +bool drm_bridge_chain_mode_fixup(struct drm_bridge *bridge, + const struct drm_display_mode *mode, + struct drm_display_mode *adjusted_mode); +enum drm_mode_status +drm_bridge_chain_mode_valid(struct drm_bridge *bridge, + const struct drm_display_mode *mode); +void drm_bridge_chain_disable(struct drm_bridge *bridge); +void drm_bridge_chain_post_disable(struct drm_bridge *bridge); +void drm_bridge_chain_mode_set(struct drm_bridge *bridge, + const struct drm_display_mode *mode, + const struct drm_display_mode *adjusted_mode); +void drm_bridge_chain_pre_enable(struct drm_bridge *bridge); +void drm_bridge_chain_enable(struct drm_bridge *bridge); -void drm_atomic_bridge_disable(struct drm_bridge *bridge, - struct drm_atomic_state *state); -void drm_atomic_bridge_post_disable(struct drm_bridge *bridge, +void drm_atomic_bridge_chain_disable(struct drm_bridge *bridge, + struct drm_atomic_state *state); +void drm_atomic_bridge_chain_post_disable(struct drm_bridge *bridge, + struct drm_atomic_state *state); +void drm_atomic_bridge_chain_pre_enable(struct drm_bridge *bridge, + struct drm_atomic_state *state); +void drm_atomic_bridge_chain_enable(struct drm_bridge *bridge, struct drm_atomic_state *state); -void drm_atomic_bridge_pre_enable(struct drm_bridge *bridge, - struct drm_atomic_state *state); -void drm_atomic_bridge_enable(struct drm_bridge *bridge, - struct drm_atomic_state *state); #ifdef CONFIG_DRM_PANEL_BRIDGE struct drm_bridge *drm_panel_bridge_add(struct drm_panel *panel); From patchwork Wed Oct 23 15:44:56 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Boris Brezillon X-Patchwork-Id: 11207105 Return-Path: Received: from mail.kernel.org (pdx-korg-mail-1.web.codeaurora.org [172.30.200.123]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id C8E811515 for ; Wed, 23 Oct 2019 15:45:47 +0000 (UTC) Received: from gabe.freedesktop.org (gabe.freedesktop.org [131.252.210.177]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by mail.kernel.org (Postfix) with ESMTPS id B1EE32086D for ; Wed, 23 Oct 2019 15:45:47 +0000 (UTC) DMARC-Filter: OpenDMARC Filter v1.3.2 mail.kernel.org B1EE32086D Authentication-Results: mail.kernel.org; dmarc=fail (p=none dis=none) header.from=collabora.com Authentication-Results: mail.kernel.org; spf=none smtp.mailfrom=dri-devel-bounces@lists.freedesktop.org Received: from gabe.freedesktop.org (localhost [127.0.0.1]) by gabe.freedesktop.org (Postfix) with ESMTP id 03C0C6EB1F; Wed, 23 Oct 2019 15:45:37 +0000 (UTC) X-Original-To: dri-devel@lists.freedesktop.org Delivered-To: dri-devel@lists.freedesktop.org Received: from bhuna.collabora.co.uk (bhuna.collabora.co.uk [46.235.227.227]) by gabe.freedesktop.org (Postfix) with ESMTPS id C3FA36EB1D for ; Wed, 23 Oct 2019 15:45:23 +0000 (UTC) Received: from localhost.localdomain (unknown [IPv6:2a01:e0a:2c:6930:5cf4:84a1:2763:fe0d]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) (Authenticated sender: bbrezillon) by bhuna.collabora.co.uk (Postfix) with ESMTPSA id 8E6F528F913; Wed, 23 Oct 2019 16:45:20 +0100 (BST) From: Boris Brezillon To: dri-devel@lists.freedesktop.org Subject: [PATCH v3 05/21] drm/bridge: Introduce drm_bridge_chain_get_next_bridge() Date: Wed, 23 Oct 2019 17:44:56 +0200 Message-Id: <20191023154512.9762-6-boris.brezillon@collabora.com> X-Mailer: git-send-email 2.21.0 In-Reply-To: <20191023154512.9762-1-boris.brezillon@collabora.com> References: <20191023154512.9762-1-boris.brezillon@collabora.com> MIME-Version: 1.0 X-BeenThere: dri-devel@lists.freedesktop.org X-Mailman-Version: 2.1.23 Precedence: list List-Id: Direct Rendering Infrastructure - Development List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: Mark Rutland , Neil Armstrong , Thierry Reding , Laurent Pinchart , kernel@collabora.com, Sam Ravnborg , Nikita Yushchenko , Andrey Smirnov , Kyungmin Park , Chris Healy , devicetree@vger.kernel.org, Jonas Karlman , Rob Herring , Jernej Skrabec , Seung-Woo Kim , Boris Brezillon Errors-To: dri-devel-bounces@lists.freedesktop.org Sender: "dri-devel" And use it in drivers accessing the bridge->next field directly. This is part of our attempt to make the bridge chain a double-linked list based on the generic list helpers. Signed-off-by: Boris Brezillon Reviewed-by: Neil Armstrong Reviewed-by: Laurent Pinchart --- Changes in v3: * Inline drm_bridge_chain_get_next_bridge() (Suggested by Laurent) Changes in v2: * Kill the last/first helpers (they're not really needed) * Drop the !bridge || !bridge->encoder test --- drivers/gpu/drm/exynos/exynos_drm_dsi.c | 3 ++- drivers/gpu/drm/mediatek/mtk_hdmi.c | 6 ++++-- drivers/gpu/drm/omapdrm/omap_drv.c | 4 ++-- drivers/gpu/drm/omapdrm/omap_encoder.c | 3 ++- drivers/gpu/drm/vc4/vc4_dsi.c | 4 +++- include/drm/drm_bridge.h | 13 +++++++++++++ 6 files changed, 26 insertions(+), 7 deletions(-) diff --git a/drivers/gpu/drm/exynos/exynos_drm_dsi.c b/drivers/gpu/drm/exynos/exynos_drm_dsi.c index 3915f50b005e..005c67894b78 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_dsi.c +++ b/drivers/gpu/drm/exynos/exynos_drm_dsi.c @@ -1593,9 +1593,10 @@ static int exynos_dsi_host_detach(struct mipi_dsi_host *host, struct mipi_dsi_device *device) { struct exynos_dsi *dsi = host_to_dsi(host); - struct drm_bridge *out_bridge = dsi->bridge.next; struct drm_device *drm = dsi->encoder.dev; + struct drm_bridge *out_bridge; + out_bridge = drm_bridge_chain_get_next_bridge(&dsi->bridge); if (dsi->panel) { mutex_lock(&drm->mode_config.mutex); exynos_dsi_disable(&dsi->bridge); diff --git a/drivers/gpu/drm/mediatek/mtk_hdmi.c b/drivers/gpu/drm/mediatek/mtk_hdmi.c index ea68b5adccbe..cfaa5aab8876 100644 --- a/drivers/gpu/drm/mediatek/mtk_hdmi.c +++ b/drivers/gpu/drm/mediatek/mtk_hdmi.c @@ -1238,16 +1238,18 @@ static int mtk_hdmi_conn_mode_valid(struct drm_connector *conn, struct drm_display_mode *mode) { struct mtk_hdmi *hdmi = hdmi_ctx_from_conn(conn); + struct drm_bridge *next_bridge; dev_dbg(hdmi->dev, "xres=%d, yres=%d, refresh=%d, intl=%d clock=%d\n", mode->hdisplay, mode->vdisplay, mode->vrefresh, !!(mode->flags & DRM_MODE_FLAG_INTERLACE), mode->clock * 1000); - if (hdmi->bridge.next) { + next_bridge = drm_bridge_chain_get_next_bridge(&hdmi->bridge); + if (next_bridge) { struct drm_display_mode adjusted_mode; drm_mode_copy(&adjusted_mode, mode); - if (!drm_bridge_chain_mode_fixup(hdmi->bridge.next, mode, + if (!drm_bridge_chain_mode_fixup(next_bridge, mode, &adjusted_mode)) return MODE_BAD; } diff --git a/drivers/gpu/drm/omapdrm/omap_drv.c b/drivers/gpu/drm/omapdrm/omap_drv.c index b3e22c890c51..865164fe28dc 100644 --- a/drivers/gpu/drm/omapdrm/omap_drv.c +++ b/drivers/gpu/drm/omapdrm/omap_drv.c @@ -217,8 +217,8 @@ static int omap_display_id(struct omap_dss_device *output) } else if (output->bridge) { struct drm_bridge *bridge = output->bridge; - while (bridge->next) - bridge = bridge->next; + while (drm_bridge_chain_get_next_bridge(bridge)) + bridge = drm_bridge_chain_get_next_bridge(bridge); node = bridge->of_node; } else if (output->panel) { diff --git a/drivers/gpu/drm/omapdrm/omap_encoder.c b/drivers/gpu/drm/omapdrm/omap_encoder.c index 24bbe9f2a32e..8ca54081997e 100644 --- a/drivers/gpu/drm/omapdrm/omap_encoder.c +++ b/drivers/gpu/drm/omapdrm/omap_encoder.c @@ -126,7 +126,8 @@ static void omap_encoder_mode_set(struct drm_encoder *encoder, for (dssdev = output; dssdev; dssdev = dssdev->next) omap_encoder_update_videomode_flags(&vm, dssdev->bus_flags); - for (bridge = output->bridge; bridge; bridge = bridge->next) { + for (bridge = output->bridge; bridge; + bridge = drm_bridge_chain_get_next_bridge(bridge)) { if (!bridge->timings) continue; diff --git a/drivers/gpu/drm/vc4/vc4_dsi.c b/drivers/gpu/drm/vc4/vc4_dsi.c index 49f8a313e759..49c47185aff0 100644 --- a/drivers/gpu/drm/vc4/vc4_dsi.c +++ b/drivers/gpu/drm/vc4/vc4_dsi.c @@ -1644,8 +1644,10 @@ static void vc4_dsi_unbind(struct device *dev, struct device *master, struct drm_device *drm = dev_get_drvdata(master); struct vc4_dev *vc4 = to_vc4_dev(drm); struct vc4_dsi *dsi = dev_get_drvdata(dev); + struct drm_bridge *bridge; - if (dsi->bridge.next) + bridge = drm_bridge_chain_get_next_bridge(&dsi->bridge); + if (bridge) pm_runtime_disable(dev); vc4_dsi_encoder_destroy(dsi->encoder); diff --git a/include/drm/drm_bridge.h b/include/drm/drm_bridge.h index 726435baf4ad..8aeba83fcf31 100644 --- a/include/drm/drm_bridge.h +++ b/include/drm/drm_bridge.h @@ -409,6 +409,19 @@ struct drm_bridge *of_drm_find_bridge(struct device_node *np); int drm_bridge_attach(struct drm_encoder *encoder, struct drm_bridge *bridge, struct drm_bridge *previous); +/** + * drm_bridge_chain_get_next_bridge() - Get the next bridge in the chain + * @bridge: bridge object + * + * RETURNS: + * the next bridge in the chain, or NULL if @bridge is the last. + */ +static inline struct drm_bridge * +drm_bridge_chain_get_next_bridge(struct drm_bridge *bridge) +{ + return bridge->next; +} + bool drm_bridge_chain_mode_fixup(struct drm_bridge *bridge, const struct drm_display_mode *mode, struct drm_display_mode *adjusted_mode); From patchwork Wed Oct 23 15:44:57 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Boris Brezillon X-Patchwork-Id: 11207095 Return-Path: Received: from mail.kernel.org (pdx-korg-mail-1.web.codeaurora.org [172.30.200.123]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id A48851390 for ; Wed, 23 Oct 2019 15:45:38 +0000 (UTC) Received: from gabe.freedesktop.org (gabe.freedesktop.org [131.252.210.177]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by mail.kernel.org (Postfix) with ESMTPS id 8CF402084C for ; Wed, 23 Oct 2019 15:45:38 +0000 (UTC) DMARC-Filter: OpenDMARC Filter v1.3.2 mail.kernel.org 8CF402084C Authentication-Results: mail.kernel.org; dmarc=fail (p=none dis=none) header.from=collabora.com Authentication-Results: mail.kernel.org; spf=none smtp.mailfrom=dri-devel-bounces@lists.freedesktop.org Received: from gabe.freedesktop.org (localhost [127.0.0.1]) by gabe.freedesktop.org (Postfix) with ESMTP id 124706E10B; Wed, 23 Oct 2019 15:45:36 +0000 (UTC) X-Original-To: dri-devel@lists.freedesktop.org Delivered-To: dri-devel@lists.freedesktop.org Received: from bhuna.collabora.co.uk (bhuna.collabora.co.uk [IPv6:2a00:1098:0:82:1000:25:2eeb:e3e3]) by gabe.freedesktop.org (Postfix) with ESMTPS id 7F7B86EB1B for ; Wed, 23 Oct 2019 15:45:24 +0000 (UTC) Received: from localhost.localdomain (unknown [IPv6:2a01:e0a:2c:6930:5cf4:84a1:2763:fe0d]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) (Authenticated sender: bbrezillon) by bhuna.collabora.co.uk (Postfix) with ESMTPSA id B7A1728F91F; Wed, 23 Oct 2019 16:45:22 +0100 (BST) From: Boris Brezillon To: dri-devel@lists.freedesktop.org Subject: [PATCH v3 06/21] drm: Stop accessing encoder->bridge directly Date: Wed, 23 Oct 2019 17:44:57 +0200 Message-Id: <20191023154512.9762-7-boris.brezillon@collabora.com> X-Mailer: git-send-email 2.21.0 In-Reply-To: <20191023154512.9762-1-boris.brezillon@collabora.com> References: <20191023154512.9762-1-boris.brezillon@collabora.com> MIME-Version: 1.0 X-BeenThere: dri-devel@lists.freedesktop.org X-Mailman-Version: 2.1.23 Precedence: list List-Id: Direct Rendering Infrastructure - Development List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: Mark Rutland , Neil Armstrong , Thierry Reding , Laurent Pinchart , kernel@collabora.com, Sam Ravnborg , Nikita Yushchenko , Andrey Smirnov , Kyungmin Park , Chris Healy , devicetree@vger.kernel.org, Jonas Karlman , Rob Herring , Jernej Skrabec , Seung-Woo Kim , Boris Brezillon Errors-To: dri-devel-bounces@lists.freedesktop.org Sender: "dri-devel" We are about to replace the single-linked bridge list by a double-linked one based on list.h, leading to the suppression of the encoder->bridge field. But before we can do that we must provide a drm_bridge_chain_get_first_bridge() bridge helper and patch all drivers and core helpers to use it instead of directly accessing encoder->bridge. Signed-off-by: Boris Brezillon Reviewed-by: Neil Armstrong Reviewed-by: Laurent Pinchart --- drivers/gpu/drm/drm_atomic_helper.c | 25 +++++++++++++++++-------- drivers/gpu/drm/drm_encoder.c | 3 ++- drivers/gpu/drm/drm_probe_helper.c | 4 +++- drivers/gpu/drm/msm/edp/edp_bridge.c | 10 ++++++++-- drivers/gpu/drm/rcar-du/rcar_du_crtc.c | 11 ++++++++--- include/drm/drm_bridge.h | 15 +++++++++++++++ 6 files changed, 53 insertions(+), 15 deletions(-) diff --git a/drivers/gpu/drm/drm_atomic_helper.c b/drivers/gpu/drm/drm_atomic_helper.c index cf678be58fa4..f02ddffd4960 100644 --- a/drivers/gpu/drm/drm_atomic_helper.c +++ b/drivers/gpu/drm/drm_atomic_helper.c @@ -419,6 +419,7 @@ mode_fixup(struct drm_atomic_state *state) for_each_new_connector_in_state(state, connector, new_conn_state, i) { const struct drm_encoder_helper_funcs *funcs; struct drm_encoder *encoder; + struct drm_bridge *bridge; WARN_ON(!!new_conn_state->best_encoder != !!new_conn_state->crtc); @@ -435,7 +436,8 @@ mode_fixup(struct drm_atomic_state *state) encoder = new_conn_state->best_encoder; funcs = encoder->helper_private; - ret = drm_bridge_chain_mode_fixup(encoder->bridge, + bridge = drm_bridge_chain_get_first_bridge(encoder); + ret = drm_bridge_chain_mode_fixup(bridge, &new_crtc_state->mode, &new_crtc_state->adjusted_mode); if (!ret) { @@ -493,6 +495,7 @@ static enum drm_mode_status mode_valid_path(struct drm_connector *connector, struct drm_crtc *crtc, const struct drm_display_mode *mode) { + struct drm_bridge *bridge; enum drm_mode_status ret; ret = drm_encoder_mode_valid(encoder, mode); @@ -502,7 +505,8 @@ static enum drm_mode_status mode_valid_path(struct drm_connector *connector, return ret; } - ret = drm_bridge_chain_mode_valid(encoder->bridge, mode); + bridge = drm_bridge_chain_get_first_bridge(encoder); + ret = drm_bridge_chain_mode_valid(bridge, mode); if (ret != MODE_OK) { DRM_DEBUG_ATOMIC("[BRIDGE] mode_valid() failed\n"); return ret; @@ -985,6 +989,7 @@ disable_outputs(struct drm_device *dev, struct drm_atomic_state *old_state) for_each_oldnew_connector_in_state(old_state, connector, old_conn_state, new_conn_state, i) { const struct drm_encoder_helper_funcs *funcs; struct drm_encoder *encoder; + struct drm_bridge *bridge; /* Shut down everything that's in the changeset and currently * still on. So need to check the old, saved state. */ @@ -1021,7 +1026,8 @@ disable_outputs(struct drm_device *dev, struct drm_atomic_state *old_state) * Each encoder has at most one connector (since we always steal * it away), so we won't call disable hooks twice. */ - drm_atomic_bridge_chain_disable(encoder->bridge, old_state); + bridge = drm_bridge_chain_get_first_bridge(encoder); + drm_atomic_bridge_chain_disable(bridge, old_state); /* Right function depends upon target state. */ if (funcs) { @@ -1035,7 +1041,7 @@ disable_outputs(struct drm_device *dev, struct drm_atomic_state *old_state) funcs->dpms(encoder, DRM_MODE_DPMS_OFF); } - drm_atomic_bridge_chain_post_disable(encoder->bridge, + drm_atomic_bridge_chain_post_disable(bridge, old_state); } @@ -1190,6 +1196,7 @@ crtc_set_mode(struct drm_device *dev, struct drm_atomic_state *old_state) const struct drm_encoder_helper_funcs *funcs; struct drm_encoder *encoder; struct drm_display_mode *mode, *adjusted_mode; + struct drm_bridge *bridge; if (!new_conn_state->best_encoder) continue; @@ -1217,8 +1224,8 @@ crtc_set_mode(struct drm_device *dev, struct drm_atomic_state *old_state) funcs->mode_set(encoder, mode, adjusted_mode); } - drm_bridge_chain_mode_set(encoder->bridge, mode, - adjusted_mode); + bridge = drm_bridge_chain_get_first_bridge(encoder); + drm_bridge_chain_mode_set(bridge, mode, adjusted_mode); } } @@ -1317,6 +1324,7 @@ void drm_atomic_helper_commit_modeset_enables(struct drm_device *dev, for_each_new_connector_in_state(old_state, connector, new_conn_state, i) { const struct drm_encoder_helper_funcs *funcs; struct drm_encoder *encoder; + struct drm_bridge *bridge; if (!new_conn_state->best_encoder) continue; @@ -1335,7 +1343,8 @@ void drm_atomic_helper_commit_modeset_enables(struct drm_device *dev, * Each encoder has at most one connector (since we always steal * it away), so we won't call enable hooks twice. */ - drm_atomic_bridge_chain_pre_enable(encoder->bridge, old_state); + bridge = drm_bridge_chain_get_first_bridge(encoder); + drm_atomic_bridge_chain_pre_enable(bridge, old_state); if (funcs) { if (funcs->atomic_enable) @@ -1346,7 +1355,7 @@ void drm_atomic_helper_commit_modeset_enables(struct drm_device *dev, funcs->commit(encoder); } - drm_atomic_bridge_chain_enable(encoder->bridge, old_state); + drm_atomic_bridge_chain_enable(bridge, old_state); } drm_atomic_helper_commit_writebacks(dev, old_state); diff --git a/drivers/gpu/drm/drm_encoder.c b/drivers/gpu/drm/drm_encoder.c index 80d88a55302e..4fe9e723e227 100644 --- a/drivers/gpu/drm/drm_encoder.c +++ b/drivers/gpu/drm/drm_encoder.c @@ -167,9 +167,10 @@ void drm_encoder_cleanup(struct drm_encoder *encoder) */ if (encoder->bridge) { - struct drm_bridge *bridge = encoder->bridge; + struct drm_bridge *bridge; struct drm_bridge *next; + bridge = drm_bridge_chain_get_first_bridge(encoder); while (bridge) { next = bridge->next; drm_bridge_detach(bridge); diff --git a/drivers/gpu/drm/drm_probe_helper.c b/drivers/gpu/drm/drm_probe_helper.c index c3ea722065c4..576b4b7dcd89 100644 --- a/drivers/gpu/drm/drm_probe_helper.c +++ b/drivers/gpu/drm/drm_probe_helper.c @@ -101,6 +101,7 @@ drm_mode_validate_pipeline(struct drm_display_mode *mode, /* Step 2: Validate against encoders and crtcs */ drm_connector_for_each_possible_encoder(connector, encoder) { + struct drm_bridge *bridge; struct drm_crtc *crtc; ret = drm_encoder_mode_valid(encoder, mode); @@ -112,7 +113,8 @@ drm_mode_validate_pipeline(struct drm_display_mode *mode, continue; } - ret = drm_bridge_chain_mode_valid(encoder->bridge, mode); + bridge = drm_bridge_chain_get_first_bridge(encoder); + ret = drm_bridge_chain_mode_valid(bridge, mode); if (ret != MODE_OK) { /* There is also no point in continuing for crtc check * here. */ diff --git a/drivers/gpu/drm/msm/edp/edp_bridge.c b/drivers/gpu/drm/msm/edp/edp_bridge.c index 2950bba4aca9..b65b5cc2dba2 100644 --- a/drivers/gpu/drm/msm/edp/edp_bridge.c +++ b/drivers/gpu/drm/msm/edp/edp_bridge.c @@ -55,8 +55,14 @@ static void edp_bridge_mode_set(struct drm_bridge *bridge, DBG("set mode: " DRM_MODE_FMT, DRM_MODE_ARG(mode)); list_for_each_entry(connector, &dev->mode_config.connector_list, head) { - if ((connector->encoder != NULL) && - (connector->encoder->bridge == bridge)) { + struct drm_encoder *encoder = connector->encoder; + struct drm_bridge *first_bridge; + + if (!connector->encoder) + continue; + + first_bridge = drm_bridge_chain_get_first_bridge(encoder); + if (bridge == first_bridge) { msm_edp_ctrl_timing_cfg(edp->ctrl, adjusted_mode, &connector->display_info); break; diff --git a/drivers/gpu/drm/rcar-du/rcar_du_crtc.c b/drivers/gpu/drm/rcar-du/rcar_du_crtc.c index 2da46e3dc4ae..7a1f1e5f0326 100644 --- a/drivers/gpu/drm/rcar-du/rcar_du_crtc.c +++ b/drivers/gpu/drm/rcar-du/rcar_du_crtc.c @@ -14,6 +14,7 @@ #include #include +#include #include #include #include @@ -680,9 +681,10 @@ static void rcar_du_crtc_atomic_enable(struct drm_crtc *crtc, rcdu->encoders[RCAR_DU_OUTPUT_LVDS0 + rcrtc->index]; const struct drm_display_mode *mode = &crtc->state->adjusted_mode; + struct drm_bridge *bridge; - rcar_lvds_clk_enable(encoder->base.bridge, - mode->clock * 1000); + bridge = drm_bridge_chain_get_first_bridge(&encoder->base); + rcar_lvds_clk_enable(bridge, mode->clock * 1000); } rcar_du_crtc_start(rcrtc); @@ -702,12 +704,15 @@ static void rcar_du_crtc_atomic_disable(struct drm_crtc *crtc, rstate->outputs == BIT(RCAR_DU_OUTPUT_DPAD0)) { struct rcar_du_encoder *encoder = rcdu->encoders[RCAR_DU_OUTPUT_LVDS0 + rcrtc->index]; + struct drm_bridge *bridge; + /* * Disable the LVDS clock output, see * rcar_du_crtc_atomic_enable(). */ - rcar_lvds_clk_disable(encoder->base.bridge); + bridge = drm_bridge_chain_get_first_bridge(&encoder->base); + rcar_lvds_clk_disable(bridge); } spin_lock_irq(&crtc->dev->event_lock); diff --git a/include/drm/drm_bridge.h b/include/drm/drm_bridge.h index 8aeba83fcf31..27eef63ce0ff 100644 --- a/include/drm/drm_bridge.h +++ b/include/drm/drm_bridge.h @@ -25,6 +25,7 @@ #include #include +#include #include #include @@ -422,6 +423,20 @@ drm_bridge_chain_get_next_bridge(struct drm_bridge *bridge) return bridge->next; } +/** + * drm_bridge_chain_get_first_bridge() - Get the first bridge in the chain + * @encoder: encoder object + * + * RETURNS: + * the first bridge in the chain, or NULL if @encoder has no bridge attached + * to it. + */ +static inline struct drm_bridge * +drm_bridge_chain_get_first_bridge(struct drm_encoder *encoder) +{ + return encoder->bridge; +} + bool drm_bridge_chain_mode_fixup(struct drm_bridge *bridge, const struct drm_display_mode *mode, struct drm_display_mode *adjusted_mode); From patchwork Wed Oct 23 15:44:58 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Boris Brezillon X-Patchwork-Id: 11207089 Return-Path: Received: from mail.kernel.org (pdx-korg-mail-1.web.codeaurora.org [172.30.200.123]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id 1F4D91390 for ; Wed, 23 Oct 2019 15:45:29 +0000 (UTC) Received: from gabe.freedesktop.org (gabe.freedesktop.org [131.252.210.177]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by mail.kernel.org (Postfix) with ESMTPS id 0659D21A4A for ; Wed, 23 Oct 2019 15:45:29 +0000 (UTC) DMARC-Filter: OpenDMARC Filter v1.3.2 mail.kernel.org 0659D21A4A Authentication-Results: mail.kernel.org; dmarc=fail (p=none dis=none) header.from=collabora.com Authentication-Results: mail.kernel.org; spf=none smtp.mailfrom=dri-devel-bounces@lists.freedesktop.org Received: from gabe.freedesktop.org (localhost [127.0.0.1]) by gabe.freedesktop.org (Postfix) with ESMTP id E7F81891B3; Wed, 23 Oct 2019 15:45:26 +0000 (UTC) X-Original-To: dri-devel@lists.freedesktop.org Delivered-To: dri-devel@lists.freedesktop.org Received: from bhuna.collabora.co.uk (bhuna.collabora.co.uk [46.235.227.227]) by gabe.freedesktop.org (Postfix) with ESMTPS id 6D45B6EB1B for ; Wed, 23 Oct 2019 15:45:25 +0000 (UTC) Received: from localhost.localdomain (unknown [IPv6:2a01:e0a:2c:6930:5cf4:84a1:2763:fe0d]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) (Authenticated sender: bbrezillon) by bhuna.collabora.co.uk (Postfix) with ESMTPSA id 88DC928F903; Wed, 23 Oct 2019 16:45:23 +0100 (BST) From: Boris Brezillon To: dri-devel@lists.freedesktop.org Subject: [PATCH v3 07/21] drm/bridge: Make the bridge chain a double-linked list Date: Wed, 23 Oct 2019 17:44:58 +0200 Message-Id: <20191023154512.9762-8-boris.brezillon@collabora.com> X-Mailer: git-send-email 2.21.0 In-Reply-To: <20191023154512.9762-1-boris.brezillon@collabora.com> References: <20191023154512.9762-1-boris.brezillon@collabora.com> MIME-Version: 1.0 X-BeenThere: dri-devel@lists.freedesktop.org X-Mailman-Version: 2.1.23 Precedence: list List-Id: Direct Rendering Infrastructure - Development List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: Mark Rutland , Neil Armstrong , Thierry Reding , Laurent Pinchart , kernel@collabora.com, Sam Ravnborg , Nikita Yushchenko , Andrey Smirnov , Kyungmin Park , Chris Healy , devicetree@vger.kernel.org, Jonas Karlman , Rob Herring , Jernej Skrabec , Seung-Woo Kim , Boris Brezillon Errors-To: dri-devel-bounces@lists.freedesktop.org Sender: "dri-devel" So that each element in the chain can easily access its predecessor. This will be needed to support bus format negotiation between elements of the bridge chain. Signed-off-by: Boris Brezillon Reviewed-by: Neil Armstrong Reviewed-by: Laurent Pinchart --- Changes in v3: * None Changes in v2: * Adjust things to the "dummy encoder bridge" change (patch 2 in this series) --- drivers/gpu/drm/drm_bridge.c | 171 ++++++++++++++++++++++------------ drivers/gpu/drm/drm_encoder.c | 16 +--- include/drm/drm_bridge.h | 12 ++- include/drm/drm_encoder.h | 9 +- 4 files changed, 135 insertions(+), 73 deletions(-) diff --git a/drivers/gpu/drm/drm_bridge.c b/drivers/gpu/drm/drm_bridge.c index 54c874493c57..c5cf8a9c4237 100644 --- a/drivers/gpu/drm/drm_bridge.c +++ b/drivers/gpu/drm/drm_bridge.c @@ -55,7 +55,7 @@ * just provide additional hooks to get the desired output at the end of the * encoder chain. * - * Bridges can also be chained up using the &drm_bridge.next pointer. + * Bridges can also be chained up using the &drm_bridge.chain_node field. * * Both legacy CRTC helpers and the new atomic modeset helpers support bridges. */ @@ -114,6 +114,7 @@ EXPORT_SYMBOL(drm_bridge_remove); int drm_bridge_attach(struct drm_encoder *encoder, struct drm_bridge *bridge, struct drm_bridge *previous) { + LIST_HEAD(tmp_list); int ret; if (!encoder || !bridge) @@ -127,6 +128,7 @@ int drm_bridge_attach(struct drm_encoder *encoder, struct drm_bridge *bridge, bridge->dev = encoder->dev; bridge->encoder = encoder; + list_add_tail(&bridge->chain_node, &tmp_list); if (bridge->funcs->attach) { ret = bridge->funcs->attach(bridge); @@ -138,9 +140,9 @@ int drm_bridge_attach(struct drm_encoder *encoder, struct drm_bridge *bridge, } if (previous) - previous->next = bridge; + list_splice(&tmp_list, &previous->chain_node); else - encoder->bridge = bridge; + list_splice(&tmp_list, &encoder->bridge_chain); return 0; } @@ -157,6 +159,7 @@ void drm_bridge_detach(struct drm_bridge *bridge) if (bridge->funcs->detach) bridge->funcs->detach(bridge); + list_del(&bridge->chain_node); bridge->dev = NULL; } @@ -190,18 +193,22 @@ bool drm_bridge_chain_mode_fixup(struct drm_bridge *bridge, const struct drm_display_mode *mode, struct drm_display_mode *adjusted_mode) { - bool ret = true; + struct drm_encoder *encoder; if (!bridge) return true; - if (bridge->funcs->mode_fixup) - ret = bridge->funcs->mode_fixup(bridge, mode, adjusted_mode); + encoder = bridge->encoder; + list_for_each_entry_from(bridge, &encoder->bridge_chain, + chain_node) { + if (!bridge->funcs->mode_fixup) + continue; - ret = ret && drm_bridge_chain_mode_fixup(bridge->next, mode, - adjusted_mode); + if (!bridge->funcs->mode_fixup(bridge, mode, adjusted_mode)) + return false; + } - return ret; + return true; } EXPORT_SYMBOL(drm_bridge_chain_mode_fixup); @@ -224,18 +231,24 @@ enum drm_mode_status drm_bridge_chain_mode_valid(struct drm_bridge *bridge, const struct drm_display_mode *mode) { - enum drm_mode_status ret = MODE_OK; + struct drm_encoder *encoder; if (!bridge) - return ret; + return MODE_OK; + + encoder = bridge->encoder; + list_for_each_entry_from(bridge, &encoder->bridge_chain, chain_node) { + enum drm_mode_status ret; + + if (!bridge->funcs->mode_valid) + continue; - if (bridge->funcs->mode_valid) ret = bridge->funcs->mode_valid(bridge, mode); + if (ret != MODE_OK) + return ret; + } - if (ret != MODE_OK) - return ret; - - return drm_bridge_chain_mode_valid(bridge->next, mode); + return MODE_OK; } EXPORT_SYMBOL(drm_bridge_chain_mode_valid); @@ -251,13 +264,20 @@ EXPORT_SYMBOL(drm_bridge_chain_mode_valid); */ void drm_bridge_chain_disable(struct drm_bridge *bridge) { + struct drm_encoder *encoder; + struct drm_bridge *iter; + if (!bridge) return; - drm_bridge_chain_disable(bridge->next); + encoder = bridge->encoder; + list_for_each_entry_reverse(iter, &encoder->bridge_chain, chain_node) { + if (iter->funcs->disable) + iter->funcs->disable(iter); - if (bridge->funcs->disable) - bridge->funcs->disable(bridge); + if (iter == bridge) + break; + } } EXPORT_SYMBOL(drm_bridge_chain_disable); @@ -274,13 +294,16 @@ EXPORT_SYMBOL(drm_bridge_chain_disable); */ void drm_bridge_chain_post_disable(struct drm_bridge *bridge) { + struct drm_encoder *encoder; + if (!bridge) return; - if (bridge->funcs->post_disable) - bridge->funcs->post_disable(bridge); - - drm_bridge_chain_post_disable(bridge->next); + encoder = bridge->encoder; + list_for_each_entry_from(bridge, &encoder->bridge_chain, chain_node) { + if (bridge->funcs->post_disable) + bridge->funcs->post_disable(bridge); + } } EXPORT_SYMBOL(drm_bridge_chain_post_disable); @@ -300,13 +323,16 @@ void drm_bridge_chain_mode_set(struct drm_bridge *bridge, const struct drm_display_mode *mode, const struct drm_display_mode *adjusted_mode) { + struct drm_encoder *encoder; + if (!bridge) return; - if (bridge->funcs->mode_set) - bridge->funcs->mode_set(bridge, mode, adjusted_mode); - - drm_bridge_chain_mode_set(bridge->next, mode, adjusted_mode); + encoder = bridge->encoder; + list_for_each_entry_from(bridge, &encoder->bridge_chain, chain_node) { + if (bridge->funcs->mode_set) + bridge->funcs->mode_set(bridge, mode, adjusted_mode); + } } EXPORT_SYMBOL(drm_bridge_chain_mode_set); @@ -323,13 +349,17 @@ EXPORT_SYMBOL(drm_bridge_chain_mode_set); */ void drm_bridge_chain_pre_enable(struct drm_bridge *bridge) { + struct drm_encoder *encoder; + struct drm_bridge *iter; + if (!bridge) return; - drm_bridge_chain_pre_enable(bridge->next); - - if (bridge->funcs->pre_enable) - bridge->funcs->pre_enable(bridge); + encoder = bridge->encoder; + list_for_each_entry_reverse(iter, &encoder->bridge_chain, chain_node) { + if (iter->funcs->pre_enable) + iter->funcs->pre_enable(iter); + } } EXPORT_SYMBOL(drm_bridge_chain_pre_enable); @@ -345,13 +375,16 @@ EXPORT_SYMBOL(drm_bridge_chain_pre_enable); */ void drm_bridge_chain_enable(struct drm_bridge *bridge) { + struct drm_encoder *encoder; + if (!bridge) return; - if (bridge->funcs->enable) - bridge->funcs->enable(bridge); - - drm_bridge_chain_enable(bridge->next); + encoder = bridge->encoder; + list_for_each_entry_from(bridge, &encoder->bridge_chain, chain_node) { + if (bridge->funcs->enable) + bridge->funcs->enable(bridge); + } } EXPORT_SYMBOL(drm_bridge_chain_enable); @@ -370,15 +403,23 @@ EXPORT_SYMBOL(drm_bridge_chain_enable); void drm_atomic_bridge_chain_disable(struct drm_bridge *bridge, struct drm_atomic_state *state) { + struct drm_encoder *encoder; + struct drm_bridge *iter; + if (!bridge) return; - drm_atomic_bridge_chain_disable(bridge->next, state); + encoder = bridge->encoder; + list_for_each_entry_reverse(iter, &encoder->bridge_chain, + chain_node) { + if (iter->funcs->atomic_disable) + iter->funcs->atomic_disable(iter, state); + else if (iter->funcs->disable) + iter->funcs->disable(iter); - if (bridge->funcs->atomic_disable) - bridge->funcs->atomic_disable(bridge, state); - else if (bridge->funcs->disable) - bridge->funcs->disable(bridge); + if (iter == bridge) + break; + } } EXPORT_SYMBOL(drm_atomic_bridge_chain_disable); @@ -398,15 +439,19 @@ EXPORT_SYMBOL(drm_atomic_bridge_chain_disable); void drm_atomic_bridge_chain_post_disable(struct drm_bridge *bridge, struct drm_atomic_state *state) { + struct drm_encoder *encoder; + if (!bridge) return; - if (bridge->funcs->atomic_post_disable) - bridge->funcs->atomic_post_disable(bridge, state); - else if (bridge->funcs->post_disable) - bridge->funcs->post_disable(bridge); - - drm_atomic_bridge_chain_post_disable(bridge->next, state); + encoder = bridge->encoder; + list_for_each_entry_from(bridge, &encoder->bridge_chain, + chain_node) { + if (bridge->funcs->atomic_post_disable) + bridge->funcs->atomic_post_disable(bridge, state); + else if (bridge->funcs->post_disable) + bridge->funcs->post_disable(bridge); + } } EXPORT_SYMBOL(drm_atomic_bridge_chain_post_disable); @@ -426,15 +471,23 @@ EXPORT_SYMBOL(drm_atomic_bridge_chain_post_disable); void drm_atomic_bridge_chain_pre_enable(struct drm_bridge *bridge, struct drm_atomic_state *state) { + struct drm_encoder *encoder; + struct drm_bridge *iter; + if (!bridge) return; - drm_atomic_bridge_chain_pre_enable(bridge->next, state); + encoder = bridge->encoder; + list_for_each_entry_reverse(iter, &bridge->encoder->bridge_chain, + chain_node) { + if (iter->funcs->atomic_pre_enable) + iter->funcs->atomic_pre_enable(iter, state); + else if (iter->funcs->pre_enable) + iter->funcs->pre_enable(iter); - if (bridge->funcs->atomic_pre_enable) - bridge->funcs->atomic_pre_enable(bridge, state); - else if (bridge->funcs->pre_enable) - bridge->funcs->pre_enable(bridge); + if (iter == bridge) + break; + } } EXPORT_SYMBOL(drm_atomic_bridge_chain_pre_enable); @@ -453,15 +506,19 @@ EXPORT_SYMBOL(drm_atomic_bridge_chain_pre_enable); void drm_atomic_bridge_chain_enable(struct drm_bridge *bridge, struct drm_atomic_state *state) { + struct drm_encoder *encoder; + if (!bridge) return; - if (bridge->funcs->atomic_enable) - bridge->funcs->atomic_enable(bridge, state); - else if (bridge->funcs->enable) - bridge->funcs->enable(bridge); - - drm_atomic_bridge_chain_enable(bridge->next, state); + encoder = bridge->encoder; + list_for_each_entry_from(bridge, &bridge->encoder->bridge_chain, + chain_node) { + if (bridge->funcs->atomic_enable) + bridge->funcs->atomic_enable(bridge, state); + else if (bridge->funcs->enable) + bridge->funcs->enable(bridge); + } } EXPORT_SYMBOL(drm_atomic_bridge_chain_enable); diff --git a/drivers/gpu/drm/drm_encoder.c b/drivers/gpu/drm/drm_encoder.c index 4fe9e723e227..e555281f43d4 100644 --- a/drivers/gpu/drm/drm_encoder.c +++ b/drivers/gpu/drm/drm_encoder.c @@ -140,6 +140,7 @@ int drm_encoder_init(struct drm_device *dev, goto out_put; } + INIT_LIST_HEAD(&encoder->bridge_chain); list_add_tail(&encoder->head, &dev->mode_config.encoder_list); encoder->index = dev->mode_config.num_encoder++; @@ -160,23 +161,16 @@ EXPORT_SYMBOL(drm_encoder_init); void drm_encoder_cleanup(struct drm_encoder *encoder) { struct drm_device *dev = encoder->dev; + struct drm_bridge *bridge, *next; /* Note that the encoder_list is considered to be static; should we * remove the drm_encoder at runtime we would have to decrement all * the indices on the drm_encoder after us in the encoder_list. */ - if (encoder->bridge) { - struct drm_bridge *bridge; - struct drm_bridge *next; - - bridge = drm_bridge_chain_get_first_bridge(encoder); - while (bridge) { - next = bridge->next; - drm_bridge_detach(bridge); - bridge = next; - } - } + list_for_each_entry_safe(bridge, next, &encoder->bridge_chain, + chain_node) + drm_bridge_detach(bridge); drm_mode_object_unregister(dev, &encoder->base); kfree(encoder->name); diff --git a/include/drm/drm_bridge.h b/include/drm/drm_bridge.h index 27eef63ce0ff..3ab16c95e59e 100644 --- a/include/drm/drm_bridge.h +++ b/include/drm/drm_bridge.h @@ -384,8 +384,8 @@ struct drm_bridge { struct drm_device *dev; /** @encoder: encoder to which this bridge is connected */ struct drm_encoder *encoder; - /** @next: the next bridge in the encoder chain */ - struct drm_bridge *next; + /** @chain_node: used to form a bridge chain */ + struct list_head chain_node; #ifdef CONFIG_OF /** @of_node: device node pointer to the bridge */ struct device_node *of_node; @@ -420,7 +420,10 @@ int drm_bridge_attach(struct drm_encoder *encoder, struct drm_bridge *bridge, static inline struct drm_bridge * drm_bridge_chain_get_next_bridge(struct drm_bridge *bridge) { - return bridge->next; + if (list_is_last(&bridge->chain_node, &bridge->encoder->bridge_chain)) + return NULL; + + return list_next_entry(bridge, chain_node); } /** @@ -434,7 +437,8 @@ drm_bridge_chain_get_next_bridge(struct drm_bridge *bridge) static inline struct drm_bridge * drm_bridge_chain_get_first_bridge(struct drm_encoder *encoder) { - return encoder->bridge; + return list_first_entry_or_null(&encoder->bridge_chain, + struct drm_bridge, chain_node); } bool drm_bridge_chain_mode_fixup(struct drm_bridge *bridge, diff --git a/include/drm/drm_encoder.h b/include/drm/drm_encoder.h index f06164f44efe..9b3dde177c81 100644 --- a/include/drm/drm_encoder.h +++ b/include/drm/drm_encoder.h @@ -172,7 +172,14 @@ struct drm_encoder { * &drm_connector_state.crtc. */ struct drm_crtc *crtc; - struct drm_bridge *bridge; + + /** + * @bridge_chain: Bridges attached to this encoder. The first entry of + * this list is always &drm_encoder.bridge. It may be followed by other + * bridge entities. + */ + struct list_head bridge_chain; + const struct drm_encoder_funcs *funcs; const struct drm_encoder_helper_funcs *helper_private; }; From patchwork Wed Oct 23 15:44:59 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Boris Brezillon X-Patchwork-Id: 11207093 Return-Path: Received: from mail.kernel.org (pdx-korg-mail-1.web.codeaurora.org [172.30.200.123]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id 484C913BD for ; Wed, 23 Oct 2019 15:45:33 +0000 (UTC) Received: from gabe.freedesktop.org (gabe.freedesktop.org [131.252.210.177]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by mail.kernel.org (Postfix) with ESMTPS id 30D9D21D71 for ; Wed, 23 Oct 2019 15:45:33 +0000 (UTC) DMARC-Filter: OpenDMARC Filter v1.3.2 mail.kernel.org 30D9D21D71 Authentication-Results: mail.kernel.org; dmarc=fail (p=none dis=none) header.from=collabora.com Authentication-Results: mail.kernel.org; spf=none smtp.mailfrom=dri-devel-bounces@lists.freedesktop.org Received: from gabe.freedesktop.org (localhost [127.0.0.1]) by gabe.freedesktop.org (Postfix) with ESMTP id CDBCC89D84; Wed, 23 Oct 2019 15:45:27 +0000 (UTC) X-Original-To: dri-devel@lists.freedesktop.org Delivered-To: dri-devel@lists.freedesktop.org Received: from bhuna.collabora.co.uk (bhuna.collabora.co.uk [46.235.227.227]) by gabe.freedesktop.org (Postfix) with ESMTPS id 6030C88EE9 for ; Wed, 23 Oct 2019 15:45:26 +0000 (UTC) Received: from localhost.localdomain (unknown [IPv6:2a01:e0a:2c:6930:5cf4:84a1:2763:fe0d]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) (Authenticated sender: bbrezillon) by bhuna.collabora.co.uk (Postfix) with ESMTPSA id 5F20428F924; Wed, 23 Oct 2019 16:45:24 +0100 (BST) From: Boris Brezillon To: dri-devel@lists.freedesktop.org Subject: [PATCH v3 08/21] drm/bridge: Add the drm_for_each_bridge_in_chain() helper Date: Wed, 23 Oct 2019 17:44:59 +0200 Message-Id: <20191023154512.9762-9-boris.brezillon@collabora.com> X-Mailer: git-send-email 2.21.0 In-Reply-To: <20191023154512.9762-1-boris.brezillon@collabora.com> References: <20191023154512.9762-1-boris.brezillon@collabora.com> MIME-Version: 1.0 X-BeenThere: dri-devel@lists.freedesktop.org X-Mailman-Version: 2.1.23 Precedence: list List-Id: Direct Rendering Infrastructure - Development List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: Mark Rutland , Neil Armstrong , Thierry Reding , Laurent Pinchart , kernel@collabora.com, Sam Ravnborg , Nikita Yushchenko , Andrey Smirnov , Kyungmin Park , Chris Healy , devicetree@vger.kernel.org, Jonas Karlman , Rob Herring , Jernej Skrabec , Seung-Woo Kim , Boris Brezillon Errors-To: dri-devel-bounces@lists.freedesktop.org Sender: "dri-devel" To iterate over all bridges attached to a specific encoder. Suggested-by: Laurent Pinchart Signed-off-by: Boris Brezillon Reviewed-by: Neil Armstrong Reviewed-by: Laurent Pinchart --- Changes in v3: * None Changes in v2: * New patch --- include/drm/drm_bridge.h | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/include/drm/drm_bridge.h b/include/drm/drm_bridge.h index 3ab16c95e59e..238e84ab63a3 100644 --- a/include/drm/drm_bridge.h +++ b/include/drm/drm_bridge.h @@ -441,6 +441,17 @@ drm_bridge_chain_get_first_bridge(struct drm_encoder *encoder) struct drm_bridge, chain_node); } +/** + * for_each_bridge_in_chain() - Iterate over all bridges present in a chain + * @encoder: the encoder to iterate bridges on + * @bridge: a bridge pointer updated to point to the current bridge at each + * iteration + * + * Iterate over all bridges present in the bridge chain attached to @encoder. + */ +#define drm_for_each_bridge_in_chain(encoder, bridge) \ + list_for_each_entry(bridge, &(encoder)->bridge_chain, chain_node) + bool drm_bridge_chain_mode_fixup(struct drm_bridge *bridge, const struct drm_display_mode *mode, struct drm_display_mode *adjusted_mode); From patchwork Wed Oct 23 15:45:00 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Boris Brezillon X-Patchwork-Id: 11207101 Return-Path: Received: from mail.kernel.org (pdx-korg-mail-1.web.codeaurora.org [172.30.200.123]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id D9BA01390 for ; Wed, 23 Oct 2019 15:45:43 +0000 (UTC) Received: from gabe.freedesktop.org (gabe.freedesktop.org [131.252.210.177]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by mail.kernel.org (Postfix) with ESMTPS id C21CB2084C for ; Wed, 23 Oct 2019 15:45:43 +0000 (UTC) DMARC-Filter: OpenDMARC Filter v1.3.2 mail.kernel.org C21CB2084C Authentication-Results: mail.kernel.org; dmarc=fail (p=none dis=none) header.from=collabora.com Authentication-Results: mail.kernel.org; spf=none smtp.mailfrom=dri-devel-bounces@lists.freedesktop.org Received: from gabe.freedesktop.org (localhost [127.0.0.1]) by gabe.freedesktop.org (Postfix) with ESMTP id 98D786EB21; Wed, 23 Oct 2019 15:45:36 +0000 (UTC) X-Original-To: dri-devel@lists.freedesktop.org Delivered-To: dri-devel@lists.freedesktop.org Received: from bhuna.collabora.co.uk (bhuna.collabora.co.uk [46.235.227.227]) by gabe.freedesktop.org (Postfix) with ESMTPS id 97DD88959D for ; Wed, 23 Oct 2019 15:45:27 +0000 (UTC) Received: from localhost.localdomain (unknown [IPv6:2a01:e0a:2c:6930:5cf4:84a1:2763:fe0d]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) (Authenticated sender: bbrezillon) by bhuna.collabora.co.uk (Postfix) with ESMTPSA id 2F96528F905; Wed, 23 Oct 2019 16:45:25 +0100 (BST) From: Boris Brezillon To: dri-devel@lists.freedesktop.org Subject: [PATCH v3 09/21] drm/bridge: Add a drm_bridge_state object Date: Wed, 23 Oct 2019 17:45:00 +0200 Message-Id: <20191023154512.9762-10-boris.brezillon@collabora.com> X-Mailer: git-send-email 2.21.0 In-Reply-To: <20191023154512.9762-1-boris.brezillon@collabora.com> References: <20191023154512.9762-1-boris.brezillon@collabora.com> MIME-Version: 1.0 X-BeenThere: dri-devel@lists.freedesktop.org X-Mailman-Version: 2.1.23 Precedence: list List-Id: Direct Rendering Infrastructure - Development List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: Mark Rutland , Neil Armstrong , Thierry Reding , Laurent Pinchart , kernel@collabora.com, Sam Ravnborg , Nikita Yushchenko , Andrey Smirnov , Kyungmin Park , Chris Healy , devicetree@vger.kernel.org, Jonas Karlman , Rob Herring , Jernej Skrabec , Seung-Woo Kim , Boris Brezillon Errors-To: dri-devel-bounces@lists.freedesktop.org Sender: "dri-devel" One of the last remaining objects to not have its atomic state. This is being motivated by our attempt to support runtime bus-format negotiation between elements of the bridge chain. This patch just paves the road for such a feature by adding a new drm_bridge_state object inheriting from drm_private_obj so we can re-use some of the existing state initialization/tracking logic. Signed-off-by: Boris Brezillon Reviewed-by: Neil Armstrong --- Changes in v3: * None Changes in v2: * Use drm_for_each_bridge_in_chain() * Rename helpers to be more consistent with the rest of the DRM API * Improve/fix the doc --- drivers/gpu/drm/drm_atomic.c | 39 +++++++ drivers/gpu/drm/drm_atomic_helper.c | 20 ++++ drivers/gpu/drm/drm_bridge.c | 168 +++++++++++++++++++++++++++- include/drm/drm_atomic.h | 3 + include/drm/drm_bridge.h | 118 +++++++++++++++++++ 5 files changed, 343 insertions(+), 5 deletions(-) diff --git a/drivers/gpu/drm/drm_atomic.c b/drivers/gpu/drm/drm_atomic.c index 419381abbdd1..6c249ce39380 100644 --- a/drivers/gpu/drm/drm_atomic.c +++ b/drivers/gpu/drm/drm_atomic.c @@ -30,6 +30,7 @@ #include #include +#include #include #include #include @@ -1010,6 +1011,44 @@ static void drm_atomic_connector_print_state(struct drm_printer *p, connector->funcs->atomic_print_state(p, state); } +/** + * drm_atomic_add_encoder_bridges - add bridges attached to an encoder + * @state: atomic state + * @encoder: DRM encoder + * + * This function adds all bridges attached to @encoder. This is needed to add + * bridge states to @state and make them available when + * &bridge_funcs.atomic_{check,pre_enable,enable,disable_post_disable}() are + * called + * + * Returns: + * 0 on success or can fail with -EDEADLK or -ENOMEM. When the error is EDEADLK + * then the w/w mutex code has detected a deadlock and the entire atomic + * sequence must be restarted. All other errors are fatal. + */ +int +drm_atomic_add_encoder_bridges(struct drm_atomic_state *state, + struct drm_encoder *encoder) +{ + struct drm_bridge_state *bridge_state; + struct drm_bridge *bridge; + + if (!encoder) + return 0; + + DRM_DEBUG_ATOMIC("Adding all bridges for [encoder:%d:%s] to %p\n", + encoder->base.id, encoder->name, state); + + drm_for_each_bridge_in_chain(encoder, bridge) { + bridge_state = drm_atomic_get_bridge_state(state, bridge); + if (IS_ERR(bridge_state)) + return PTR_ERR(bridge_state); + } + + return 0; +} +EXPORT_SYMBOL(drm_atomic_add_encoder_bridges); + /** * drm_atomic_add_affected_connectors - add connectors for crtc * @state: atomic state diff --git a/drivers/gpu/drm/drm_atomic_helper.c b/drivers/gpu/drm/drm_atomic_helper.c index f02ddffd4960..de985ba7ce2d 100644 --- a/drivers/gpu/drm/drm_atomic_helper.c +++ b/drivers/gpu/drm/drm_atomic_helper.c @@ -730,6 +730,26 @@ drm_atomic_helper_check_modeset(struct drm_device *dev, return ret; } + /* + * Iterate over all connectors again, and add all affected bridges to + * the state. + */ + for_each_oldnew_connector_in_state(state, connector, + old_connector_state, + new_connector_state, i) { + struct drm_encoder *encoder; + + encoder = old_connector_state->best_encoder; + ret = drm_atomic_add_encoder_bridges(state, encoder); + if (ret) + return ret; + + encoder = new_connector_state->best_encoder; + ret = drm_atomic_add_encoder_bridges(state, encoder); + if (ret) + return ret; + } + ret = mode_valid(state); if (ret) return ret; diff --git a/drivers/gpu/drm/drm_bridge.c b/drivers/gpu/drm/drm_bridge.c index c5cf8a9c4237..c53966767782 100644 --- a/drivers/gpu/drm/drm_bridge.c +++ b/drivers/gpu/drm/drm_bridge.c @@ -25,6 +25,7 @@ #include #include +#include #include #include @@ -89,6 +90,38 @@ void drm_bridge_remove(struct drm_bridge *bridge) } EXPORT_SYMBOL(drm_bridge_remove); +static struct drm_private_state * +drm_bridge_atomic_duplicate_priv_state(struct drm_private_obj *obj) +{ + struct drm_bridge *bridge = drm_priv_to_bridge(obj); + struct drm_bridge_state *state; + + if (bridge->funcs->atomic_duplicate_state) + state = bridge->funcs->atomic_duplicate_state(bridge); + else + state = drm_atomic_helper_bridge_duplicate_state(bridge); + + return &state->base; +} + +static void +drm_bridge_atomic_destroy_priv_state(struct drm_private_obj *obj, + struct drm_private_state *s) +{ + struct drm_bridge_state *state = drm_priv_to_bridge_state(s); + struct drm_bridge *bridge = drm_priv_to_bridge(obj); + + if (bridge->funcs->atomic_destroy_state) + bridge->funcs->atomic_destroy_state(bridge, state); + else + drm_atomic_helper_bridge_destroy_state(bridge, state); +} + +static const struct drm_private_state_funcs drm_bridge_priv_state_funcs = { + .atomic_duplicate_state = drm_bridge_atomic_duplicate_priv_state, + .atomic_destroy_state = drm_bridge_atomic_destroy_priv_state, +}; + /** * drm_bridge_attach - attach the bridge to an encoder's chain * @@ -114,6 +147,7 @@ EXPORT_SYMBOL(drm_bridge_remove); int drm_bridge_attach(struct drm_encoder *encoder, struct drm_bridge *bridge, struct drm_bridge *previous) { + struct drm_bridge_state *state; LIST_HEAD(tmp_list); int ret; @@ -132,19 +166,39 @@ int drm_bridge_attach(struct drm_encoder *encoder, struct drm_bridge *bridge, if (bridge->funcs->attach) { ret = bridge->funcs->attach(bridge); - if (ret < 0) { - bridge->dev = NULL; - bridge->encoder = NULL; - return ret; - } + if (ret < 0) + goto err_reset_bridge; } + if (bridge->funcs->atomic_reset) + state = bridge->funcs->atomic_reset(bridge); + else + state = drm_atomic_helper_bridge_reset(bridge); + + if (IS_ERR(state)) { + ret = PTR_ERR(state); + goto err_detach_bridge; + } + + drm_atomic_private_obj_init(bridge->dev, &bridge->base, + &state->base, + &drm_bridge_priv_state_funcs); + if (previous) list_splice(&tmp_list, &previous->chain_node); else list_splice(&tmp_list, &encoder->bridge_chain); return 0; + +err_detach_bridge: + if (bridge->funcs->detach) + bridge->funcs->detach(bridge); + +err_reset_bridge: + bridge->dev = NULL; + bridge->encoder = NULL; + return ret; } EXPORT_SYMBOL(drm_bridge_attach); @@ -156,6 +210,8 @@ void drm_bridge_detach(struct drm_bridge *bridge) if (WARN_ON(!bridge->dev)) return; + drm_atomic_private_obj_fini(&bridge->base); + if (bridge->funcs->detach) bridge->funcs->detach(bridge); @@ -522,6 +578,108 @@ void drm_atomic_bridge_chain_enable(struct drm_bridge *bridge, } EXPORT_SYMBOL(drm_atomic_bridge_chain_enable); +/** + * drm_atomic_helper_bridge_destroy_state() - Default destroy state helper + * @bridge: the bridge this state refers to + * @state: state object to destroy + * + * Just a simple kfree() for now. + */ +void drm_atomic_helper_bridge_destroy_state(struct drm_bridge *bridge, + struct drm_bridge_state *state) +{ + kfree(state); +} +EXPORT_SYMBOL(drm_atomic_helper_bridge_destroy_state); + +/** + * __drm_atomic_helper_bridge_reset() - Initialize a bridge state to its + * default + * @bridge: the bridge this state is refers to + * @state: bridge state to initialize + * + * For now it's just a memset(0) plus a state->bridge assignment. Might + * be extended in the future. + */ +void __drm_atomic_helper_bridge_reset(struct drm_bridge *bridge, + struct drm_bridge_state *state) +{ + memset(state, 0, sizeof(*state)); + state->bridge = bridge; +} +EXPORT_SYMBOL(__drm_atomic_helper_bridge_reset); + +/** + * drm_atomic_helper_bridge_reset() - default &drm_plane_funcs.reset hook for + * bridges + * @bridge: the bridge to reset state on + * + * Resets the atomic state for @bridge by freeing the state pointer (which + * might be NULL, e.g. at driver load time) and allocating a new empty state + * object. + * + * RETURNS: + * A valid drm_bridge_state object in case of success, an ERR_PTR() + * giving the reaon of the failure otherwise. + */ +struct drm_bridge_state * +drm_atomic_helper_bridge_reset(struct drm_bridge *bridge) +{ + struct drm_bridge_state *bridge_state; + + bridge_state = kzalloc(sizeof(*bridge_state), GFP_KERNEL); + if (!bridge_state) + return ERR_PTR(-ENOMEM); + + __drm_atomic_helper_bridge_reset(bridge, bridge_state); + return bridge_state; +} +EXPORT_SYMBOL(drm_atomic_helper_bridge_reset); + +/** + * __drm_atomic_helper_bridge_duplicate_state() - Copy the content of the + * current bridge state into a + * new one + * @bridge: bridge element the old and new states are referring to + * @new: new bridge state to copy to + * + * Should be used by custom &drm_bridge_funcs.atomic_duplicate() implementation + * to copy the previous state into the new object. + */ +void __drm_atomic_helper_bridge_duplicate_state(struct drm_bridge *bridge, + struct drm_bridge_state *new) +{ + __drm_atomic_helper_private_obj_duplicate_state(&bridge->base, + &new->base); + new->bridge = bridge; +} +EXPORT_SYMBOL(__drm_atomic_helper_bridge_duplicate_state); + +/** + * drm_atomic_helper_duplicate_bridge_state() - Default duplicate state helper + * @bridge: bridge containing the state to duplicate + * + * Default implementation of &drm_bridge_funcs.atomic_duplicate(). + * + * RETURNS: + * a valid state object or NULL if the allocation fails. + */ +struct drm_bridge_state * +drm_atomic_helper_bridge_duplicate_state(struct drm_bridge *bridge) +{ + struct drm_bridge_state *new; + + if (WARN_ON(!bridge->base.state)) + return NULL; + + new = kzalloc(sizeof(*new), GFP_KERNEL); + if (new) + __drm_atomic_helper_bridge_duplicate_state(bridge, new); + + return new; +} +EXPORT_SYMBOL(drm_atomic_helper_bridge_duplicate_state); + #ifdef CONFIG_OF /** * of_drm_find_bridge - find the bridge corresponding to the device node in diff --git a/include/drm/drm_atomic.h b/include/drm/drm_atomic.h index 927e1205d7aa..1c0a08217712 100644 --- a/include/drm/drm_atomic.h +++ b/include/drm/drm_atomic.h @@ -660,6 +660,9 @@ __drm_atomic_get_current_plane_state(struct drm_atomic_state *state, return plane->state; } +int __must_check +drm_atomic_add_encoder_bridges(struct drm_atomic_state *state, + struct drm_encoder *encoder); int __must_check drm_atomic_add_affected_connectors(struct drm_atomic_state *state, struct drm_crtc *crtc); diff --git a/include/drm/drm_bridge.h b/include/drm/drm_bridge.h index 238e84ab63a3..a608c47d1de5 100644 --- a/include/drm/drm_bridge.h +++ b/include/drm/drm_bridge.h @@ -25,6 +25,7 @@ #include #include +#include #include #include #include @@ -33,6 +34,23 @@ struct drm_bridge; struct drm_bridge_timings; struct drm_panel; +/** + * struct drm_bridge_state - Atomic bridge state object + * @base: inherit from &drm_private_state + * @bridge: the bridge this state refers to + */ +struct drm_bridge_state { + struct drm_private_state base; + + struct drm_bridge *bridge; +}; + +static inline struct drm_bridge_state * +drm_priv_to_bridge_state(struct drm_private_state *priv) +{ + return container_of(priv, struct drm_bridge_state, base); +} + /** * struct drm_bridge_funcs - drm_bridge control functions */ @@ -338,6 +356,48 @@ struct drm_bridge_funcs { */ void (*atomic_post_disable)(struct drm_bridge *bridge, struct drm_atomic_state *state); + + /** + * @atomic_duplicate_state: + * + * Duplicate the current bridge state object (which is guaranteed to be + * non-NULL). + * + * The atomic_duplicate_state() is optional, the core falls back on + * &drm_atomic_helper_bridge_duplicate_state() when not implemented. + * + * RETURNS: + * A valid drm_bridge_state object or NULL if the allocation fails. + */ + struct drm_bridge_state *(*atomic_duplicate_state)(struct drm_bridge *bridge); + + /** + * @atomic_destroy_state: + * + * Destroy a bridge state object previously allocated by + * &drm_bridge_funcs.atomic_duplicate_state(). + * + * The atomic_destroy_state hook is optional, the coref falls back on + * &drm_atomic_helper_bridge_destroy_state() when not implemented. + */ + void (*atomic_destroy_state)(struct drm_bridge *bridge, + struct drm_bridge_state *state); + + /** + * @atomic_reset: + * + * Reset the bridge to a predefined state (or retrieve its current + * state) and return a &drm_bridge_state object matching this state. + * This function is called at attach time. + * + * The atomic_reset hook is optional, the core falls back on + * &drm_atomic_helper_bridge_reset() when not implemented. + * + * RETURNS: + * A valid drm_bridge_state object in case of success, an ERR_PTR() + * giving the reaon of the failure otherwise. + */ + struct drm_bridge_state *(*atomic_reset)(struct drm_bridge *bridge); }; /** @@ -380,6 +440,8 @@ struct drm_bridge_timings { * struct drm_bridge - central DRM bridge control structure */ struct drm_bridge { + /** @base: inherit from &drm_private_object */ + struct drm_private_obj base; /** @dev: DRM device this bridge belongs to */ struct drm_device *dev; /** @encoder: encoder to which this bridge is connected */ @@ -404,6 +466,12 @@ struct drm_bridge { void *driver_private; }; +static inline struct drm_bridge * +drm_priv_to_bridge(struct drm_private_obj *priv) +{ + return container_of(priv, struct drm_bridge, base); +} + void drm_bridge_add(struct drm_bridge *bridge); void drm_bridge_remove(struct drm_bridge *bridge); struct drm_bridge *of_drm_find_bridge(struct device_node *np); @@ -475,6 +543,56 @@ void drm_atomic_bridge_chain_pre_enable(struct drm_bridge *bridge, void drm_atomic_bridge_chain_enable(struct drm_bridge *bridge, struct drm_atomic_state *state); +void __drm_atomic_helper_bridge_reset(struct drm_bridge *bridge, + struct drm_bridge_state *state); +struct drm_bridge_state * +drm_atomic_helper_bridge_reset(struct drm_bridge *bridge); +void drm_atomic_helper_bridge_destroy_state(struct drm_bridge *bridge, + struct drm_bridge_state *state); +void __drm_atomic_helper_bridge_duplicate_state(struct drm_bridge *bridge, + struct drm_bridge_state *new); +struct drm_bridge_state * +drm_atomic_helper_bridge_duplicate_state(struct drm_bridge *bridge); + +static inline struct drm_bridge_state * +drm_atomic_get_bridge_state(struct drm_atomic_state *state, + struct drm_bridge *bridge) +{ + struct drm_private_state *obj_state; + + obj_state = drm_atomic_get_private_obj_state(state, &bridge->base); + if (!obj_state) + return NULL; + + return drm_priv_to_bridge_state(obj_state); +} + +static inline struct drm_bridge_state * +drm_atomic_get_old_bridge_state(struct drm_atomic_state *state, + struct drm_bridge *bridge) +{ + struct drm_private_state *obj_state; + + obj_state = drm_atomic_get_old_private_obj_state(state, &bridge->base); + if (!obj_state) + return NULL; + + return drm_priv_to_bridge_state(obj_state); +} + +static inline struct drm_bridge_state * +drm_atomic_get_new_bridge_state(struct drm_atomic_state *state, + struct drm_bridge *bridge) +{ + struct drm_private_state *obj_state; + + obj_state = drm_atomic_get_new_private_obj_state(state, &bridge->base); + if (!obj_state) + return NULL; + + return drm_priv_to_bridge_state(obj_state); +} + #ifdef CONFIG_DRM_PANEL_BRIDGE struct drm_bridge *drm_panel_bridge_add(struct drm_panel *panel); struct drm_bridge *drm_panel_bridge_add_typed(struct drm_panel *panel, From patchwork Wed Oct 23 15:45:01 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Boris Brezillon X-Patchwork-Id: 11207099 Return-Path: Received: from mail.kernel.org (pdx-korg-mail-1.web.codeaurora.org [172.30.200.123]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id 317E213BD for ; Wed, 23 Oct 2019 15:45:42 +0000 (UTC) Received: from gabe.freedesktop.org (gabe.freedesktop.org [131.252.210.177]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by mail.kernel.org (Postfix) with ESMTPS id 19FBC2084C for ; Wed, 23 Oct 2019 15:45:42 +0000 (UTC) DMARC-Filter: OpenDMARC Filter v1.3.2 mail.kernel.org 19FBC2084C Authentication-Results: mail.kernel.org; dmarc=fail (p=none dis=none) header.from=collabora.com Authentication-Results: mail.kernel.org; spf=none smtp.mailfrom=dri-devel-bounces@lists.freedesktop.org Received: from gabe.freedesktop.org (localhost [127.0.0.1]) by gabe.freedesktop.org (Postfix) with ESMTP id 24F8B6EB1B; Wed, 23 Oct 2019 15:45:36 +0000 (UTC) X-Original-To: dri-devel@lists.freedesktop.org Delivered-To: dri-devel@lists.freedesktop.org Received: from bhuna.collabora.co.uk (bhuna.collabora.co.uk [IPv6:2a00:1098:0:82:1000:25:2eeb:e3e3]) by gabe.freedesktop.org (Postfix) with ESMTPS id 2EEB16EB1D for ; Wed, 23 Oct 2019 15:45:28 +0000 (UTC) Received: from localhost.localdomain (unknown [IPv6:2a01:e0a:2c:6930:5cf4:84a1:2763:fe0d]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) (Authenticated sender: bbrezillon) by bhuna.collabora.co.uk (Postfix) with ESMTPSA id EDF4728F90D; Wed, 23 Oct 2019 16:45:25 +0100 (BST) From: Boris Brezillon To: dri-devel@lists.freedesktop.org Subject: [PATCH v3 10/21] drm/bridge: Clarify the atomic enable/disable hooks semantics Date: Wed, 23 Oct 2019 17:45:01 +0200 Message-Id: <20191023154512.9762-11-boris.brezillon@collabora.com> X-Mailer: git-send-email 2.21.0 In-Reply-To: <20191023154512.9762-1-boris.brezillon@collabora.com> References: <20191023154512.9762-1-boris.brezillon@collabora.com> MIME-Version: 1.0 X-BeenThere: dri-devel@lists.freedesktop.org X-Mailman-Version: 2.1.23 Precedence: list List-Id: Direct Rendering Infrastructure - Development List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: Mark Rutland , Neil Armstrong , Thierry Reding , Laurent Pinchart , kernel@collabora.com, Sam Ravnborg , Nikita Yushchenko , Andrey Smirnov , Kyungmin Park , Chris Healy , devicetree@vger.kernel.org, Jonas Karlman , Rob Herring , Jernej Skrabec , Seung-Woo Kim , Boris Brezillon Errors-To: dri-devel-bounces@lists.freedesktop.org Sender: "dri-devel" The [pre_]enable/[post_]disable hooks are passed the old atomic state. Update the doc and rename the arguments to make it clear. Signed-off-by: Boris Brezillon Reviewed-by: Neil Armstrong Reviewed-by: Laurent Pinchart --- Changes in v3: * New patch --- drivers/gpu/drm/drm_bridge.c | 24 ++++++++++++------------ include/drm/drm_bridge.h | 16 ++++++++++++---- 2 files changed, 24 insertions(+), 16 deletions(-) diff --git a/drivers/gpu/drm/drm_bridge.c b/drivers/gpu/drm/drm_bridge.c index c53966767782..ca74bfe028c9 100644 --- a/drivers/gpu/drm/drm_bridge.c +++ b/drivers/gpu/drm/drm_bridge.c @@ -447,7 +447,7 @@ EXPORT_SYMBOL(drm_bridge_chain_enable); /** * drm_atomic_bridge_chain_disable - disables all bridges in the encoder chain * @bridge: bridge control structure - * @state: atomic state being committed + * @old_state: old atomic state * * Calls &drm_bridge_funcs.atomic_disable (falls back on * &drm_bridge_funcs.disable) op for all the bridges in the encoder chain, @@ -457,7 +457,7 @@ EXPORT_SYMBOL(drm_bridge_chain_enable); * Note: the bridge passed should be the one closest to the encoder */ void drm_atomic_bridge_chain_disable(struct drm_bridge *bridge, - struct drm_atomic_state *state) + struct drm_atomic_state *old_state) { struct drm_encoder *encoder; struct drm_bridge *iter; @@ -469,7 +469,7 @@ void drm_atomic_bridge_chain_disable(struct drm_bridge *bridge, list_for_each_entry_reverse(iter, &encoder->bridge_chain, chain_node) { if (iter->funcs->atomic_disable) - iter->funcs->atomic_disable(iter, state); + iter->funcs->atomic_disable(iter, old_state); else if (iter->funcs->disable) iter->funcs->disable(iter); @@ -483,7 +483,7 @@ EXPORT_SYMBOL(drm_atomic_bridge_chain_disable); * drm_atomic_bridge_chain_post_disable - cleans up after disabling all bridges * in the encoder chain * @bridge: bridge control structure - * @state: atomic state being committed + * @old_state: old atomic state * * Calls &drm_bridge_funcs.atomic_post_disable (falls back on * &drm_bridge_funcs.post_disable) op for all the bridges in the encoder chain, @@ -493,7 +493,7 @@ EXPORT_SYMBOL(drm_atomic_bridge_chain_disable); * Note: the bridge passed should be the one closest to the encoder */ void drm_atomic_bridge_chain_post_disable(struct drm_bridge *bridge, - struct drm_atomic_state *state) + struct drm_atomic_state *old_state) { struct drm_encoder *encoder; @@ -504,7 +504,7 @@ void drm_atomic_bridge_chain_post_disable(struct drm_bridge *bridge, list_for_each_entry_from(bridge, &encoder->bridge_chain, chain_node) { if (bridge->funcs->atomic_post_disable) - bridge->funcs->atomic_post_disable(bridge, state); + bridge->funcs->atomic_post_disable(bridge, old_state); else if (bridge->funcs->post_disable) bridge->funcs->post_disable(bridge); } @@ -515,7 +515,7 @@ EXPORT_SYMBOL(drm_atomic_bridge_chain_post_disable); * drm_atomic_bridge_chain_pre_enable - prepares for enabling all bridges in * the encoder chain * @bridge: bridge control structure - * @state: atomic state being committed + * @old_state: old atomic state * * Calls &drm_bridge_funcs.atomic_pre_enable (falls back on * &drm_bridge_funcs.pre_enable) op for all the bridges in the encoder chain, @@ -525,7 +525,7 @@ EXPORT_SYMBOL(drm_atomic_bridge_chain_post_disable); * Note: the bridge passed should be the one closest to the encoder */ void drm_atomic_bridge_chain_pre_enable(struct drm_bridge *bridge, - struct drm_atomic_state *state) + struct drm_atomic_state *old_state) { struct drm_encoder *encoder; struct drm_bridge *iter; @@ -537,7 +537,7 @@ void drm_atomic_bridge_chain_pre_enable(struct drm_bridge *bridge, list_for_each_entry_reverse(iter, &bridge->encoder->bridge_chain, chain_node) { if (iter->funcs->atomic_pre_enable) - iter->funcs->atomic_pre_enable(iter, state); + iter->funcs->atomic_pre_enable(iter, old_state); else if (iter->funcs->pre_enable) iter->funcs->pre_enable(iter); @@ -550,7 +550,7 @@ EXPORT_SYMBOL(drm_atomic_bridge_chain_pre_enable); /** * drm_atomic_bridge_chain_enable - enables all bridges in the encoder chain * @bridge: bridge control structure - * @state: atomic state being committed + * @old_state: old atomic state * * Calls &drm_bridge_funcs.atomic_enable (falls back on * &drm_bridge_funcs.enable) op for all the bridges in the encoder chain, @@ -560,7 +560,7 @@ EXPORT_SYMBOL(drm_atomic_bridge_chain_pre_enable); * Note: the bridge passed should be the one closest to the encoder */ void drm_atomic_bridge_chain_enable(struct drm_bridge *bridge, - struct drm_atomic_state *state) + struct drm_atomic_state *old_state) { struct drm_encoder *encoder; @@ -571,7 +571,7 @@ void drm_atomic_bridge_chain_enable(struct drm_bridge *bridge, list_for_each_entry_from(bridge, &bridge->encoder->bridge_chain, chain_node) { if (bridge->funcs->atomic_enable) - bridge->funcs->atomic_enable(bridge, state); + bridge->funcs->atomic_enable(bridge, old_state); else if (bridge->funcs->enable) bridge->funcs->enable(bridge); } diff --git a/include/drm/drm_bridge.h b/include/drm/drm_bridge.h index a608c47d1de5..e814e6d6e7c2 100644 --- a/include/drm/drm_bridge.h +++ b/include/drm/drm_bridge.h @@ -266,6 +266,8 @@ struct drm_bridge_funcs { * bridge's @atomic_pre_enable or @pre_enable function. If the preceding * element is a &drm_encoder it's called right before the encoder's * &drm_encoder_helper_funcs.atomic_enable hook. + * This hook is passed the old atomic state (atomic state after new/old + * states have been swapped). * * The display pipe (i.e. clocks and timing signals) feeding this bridge * will not yet be running when this callback is called. The bridge must @@ -281,7 +283,7 @@ struct drm_bridge_funcs { * The @atomic_pre_enable callback is optional. */ void (*atomic_pre_enable)(struct drm_bridge *bridge, - struct drm_atomic_state *state); + struct drm_atomic_state *old_state); /** * @atomic_enable: @@ -292,6 +294,8 @@ struct drm_bridge_funcs { * bridge's @atomic_enable or @enable function. If the preceding element * is a &drm_encoder it's called right after the encoder's * &drm_encoder_helper_funcs.atomic_enable hook. + * This hook is passed the old atomic state (atomic state after new/old + * states have been swapped). * * The bridge can assume that the display pipe (i.e. clocks and timing * signals) feeding it is running when this callback is called. This @@ -306,7 +310,7 @@ struct drm_bridge_funcs { * The @atomic_enable callback is optional. */ void (*atomic_enable)(struct drm_bridge *bridge, - struct drm_atomic_state *state); + struct drm_atomic_state *old_state); /** * @atomic_disable: * @@ -316,6 +320,8 @@ struct drm_bridge_funcs { * bridge's @atomic_disable or @disable vfunc. If the preceding element * is a &drm_encoder it's called right before the * &drm_encoder_helper_funcs.atomic_disable hook. + * This hook is passed the old atomic state (atomic state after new/old + * states have been swapped). * * The bridge can assume that the display pipe (i.e. clocks and timing * signals) feeding it is still running when this callback is called. @@ -329,7 +335,7 @@ struct drm_bridge_funcs { * The @atomic_disable callback is optional. */ void (*atomic_disable)(struct drm_bridge *bridge, - struct drm_atomic_state *state); + struct drm_atomic_state *old_state); /** * @atomic_post_disable: @@ -340,6 +346,8 @@ struct drm_bridge_funcs { * @atomic_post_disable or @post_disable function. If the preceding * element is a &drm_encoder it's called right after the encoder's * &drm_encoder_helper_funcs.atomic_disable hook. + * This hook is passed the old atomic state (atomic state after new/old + * states have been swapped). * * The bridge must assume that the display pipe (i.e. clocks and timing * signals) feeding it is no longer running when this callback is @@ -355,7 +363,7 @@ struct drm_bridge_funcs { * The @atomic_post_disable callback is optional. */ void (*atomic_post_disable)(struct drm_bridge *bridge, - struct drm_atomic_state *state); + struct drm_atomic_state *old_state); /** * @atomic_duplicate_state: From patchwork Wed Oct 23 15:45:02 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Boris Brezillon X-Patchwork-Id: 11207113 Return-Path: Received: from mail.kernel.org (pdx-korg-mail-1.web.codeaurora.org [172.30.200.123]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id 032D013BD for ; Wed, 23 Oct 2019 15:46:01 +0000 (UTC) Received: from gabe.freedesktop.org (gabe.freedesktop.org [131.252.210.177]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by mail.kernel.org (Postfix) with ESMTPS id DF0EC21A4C for ; Wed, 23 Oct 2019 15:46:00 +0000 (UTC) DMARC-Filter: OpenDMARC Filter v1.3.2 mail.kernel.org DF0EC21A4C Authentication-Results: mail.kernel.org; dmarc=fail (p=none dis=none) header.from=collabora.com Authentication-Results: mail.kernel.org; spf=none smtp.mailfrom=dri-devel-bounces@lists.freedesktop.org Received: from gabe.freedesktop.org (localhost [127.0.0.1]) by gabe.freedesktop.org (Postfix) with ESMTP id 177506EB27; Wed, 23 Oct 2019 15:45:57 +0000 (UTC) X-Original-To: dri-devel@lists.freedesktop.org Delivered-To: dri-devel@lists.freedesktop.org Received: from bhuna.collabora.co.uk (bhuna.collabora.co.uk [IPv6:2a00:1098:0:82:1000:25:2eeb:e3e3]) by gabe.freedesktop.org (Postfix) with ESMTPS id E9FCD6EB1E for ; Wed, 23 Oct 2019 15:45:28 +0000 (UTC) Received: from localhost.localdomain (unknown [IPv6:2a01:e0a:2c:6930:5cf4:84a1:2763:fe0d]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) (Authenticated sender: bbrezillon) by bhuna.collabora.co.uk (Postfix) with ESMTPSA id 22D9828F932; Wed, 23 Oct 2019 16:45:27 +0100 (BST) From: Boris Brezillon To: dri-devel@lists.freedesktop.org Subject: [PATCH v3 11/21] drm/bridge: Patch atomic hooks to take a drm_bridge_state Date: Wed, 23 Oct 2019 17:45:02 +0200 Message-Id: <20191023154512.9762-12-boris.brezillon@collabora.com> X-Mailer: git-send-email 2.21.0 In-Reply-To: <20191023154512.9762-1-boris.brezillon@collabora.com> References: <20191023154512.9762-1-boris.brezillon@collabora.com> MIME-Version: 1.0 X-BeenThere: dri-devel@lists.freedesktop.org X-Mailman-Version: 2.1.23 Precedence: list List-Id: Direct Rendering Infrastructure - Development List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: Mark Rutland , Neil Armstrong , Thierry Reding , Laurent Pinchart , kernel@collabora.com, Sam Ravnborg , Nikita Yushchenko , Andrey Smirnov , Kyungmin Park , Chris Healy , devicetree@vger.kernel.org, Jonas Karlman , Rob Herring , Jernej Skrabec , Seung-Woo Kim , Boris Brezillon Errors-To: dri-devel-bounces@lists.freedesktop.org Sender: "dri-devel" This way the drm_bridge_funcs interface is consistent with the rest of the subsystem. The only driver implementing those hooks (analogix DP) is patched too. Signed-off-by: Boris Brezillon Reviewed-by: Laurent Pinchart --- Changes in v3: * Old state clarification moved to a separate patch Changes in v2: * Pass the old bridge state --- .../drm/bridge/analogix/analogix_dp_core.c | 12 ++-- drivers/gpu/drm/drm_bridge.c | 61 +++++++++++++++---- include/drm/drm_bridge.h | 24 ++++---- 3 files changed, 69 insertions(+), 28 deletions(-) diff --git a/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c b/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c index bb411fe52ae8..e438e757f2ce 100644 --- a/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c +++ b/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c @@ -1290,8 +1290,9 @@ struct drm_crtc *analogix_dp_get_new_crtc(struct analogix_dp_device *dp, } static void analogix_dp_bridge_atomic_pre_enable(struct drm_bridge *bridge, - struct drm_atomic_state *state) + struct drm_bridge_state *bstate) { + struct drm_atomic_state *state = bstate->base.state; struct analogix_dp_device *dp = bridge->driver_private; struct drm_crtc *crtc; struct drm_crtc_state *old_crtc_state; @@ -1367,8 +1368,9 @@ static int analogix_dp_set_bridge(struct analogix_dp_device *dp) } static void analogix_dp_bridge_atomic_enable(struct drm_bridge *bridge, - struct drm_atomic_state *state) + struct drm_bridge_state *bstate) { + struct drm_atomic_state *state = bstate->base.state; struct analogix_dp_device *dp = bridge->driver_private; struct drm_crtc *crtc; struct drm_crtc_state *old_crtc_state; @@ -1441,8 +1443,9 @@ static void analogix_dp_bridge_disable(struct drm_bridge *bridge) } static void analogix_dp_bridge_atomic_disable(struct drm_bridge *bridge, - struct drm_atomic_state *state) + struct drm_bridge_state *bstate) { + struct drm_atomic_state *state = bstate->base.state; struct analogix_dp_device *dp = bridge->driver_private; struct drm_crtc *crtc; struct drm_crtc_state *new_crtc_state = NULL; @@ -1465,8 +1468,9 @@ static void analogix_dp_bridge_atomic_disable(struct drm_bridge *bridge, static void analogix_dp_bridge_atomic_post_disable(struct drm_bridge *bridge, - struct drm_atomic_state *state) + struct drm_bridge_state *bstate) { + struct drm_atomic_state *state = bstate->base.state; struct analogix_dp_device *dp = bridge->driver_private; struct drm_crtc *crtc; struct drm_crtc_state *new_crtc_state; diff --git a/drivers/gpu/drm/drm_bridge.c b/drivers/gpu/drm/drm_bridge.c index ca74bfe028c9..377866e3214f 100644 --- a/drivers/gpu/drm/drm_bridge.c +++ b/drivers/gpu/drm/drm_bridge.c @@ -468,10 +468,19 @@ void drm_atomic_bridge_chain_disable(struct drm_bridge *bridge, encoder = bridge->encoder; list_for_each_entry_reverse(iter, &encoder->bridge_chain, chain_node) { - if (iter->funcs->atomic_disable) - iter->funcs->atomic_disable(iter, old_state); - else if (iter->funcs->disable) + if (iter->funcs->atomic_disable) { + struct drm_bridge_state *old_bridge_state; + + old_bridge_state = + drm_atomic_get_old_bridge_state(old_state, + iter); + if (WARN_ON(!old_bridge_state)) + return; + + iter->funcs->atomic_disable(iter, old_bridge_state); + } else if (iter->funcs->disable) { iter->funcs->disable(iter); + } if (iter == bridge) break; @@ -503,10 +512,20 @@ void drm_atomic_bridge_chain_post_disable(struct drm_bridge *bridge, encoder = bridge->encoder; list_for_each_entry_from(bridge, &encoder->bridge_chain, chain_node) { - if (bridge->funcs->atomic_post_disable) - bridge->funcs->atomic_post_disable(bridge, old_state); - else if (bridge->funcs->post_disable) + if (bridge->funcs->atomic_post_disable) { + struct drm_bridge_state *old_bridge_state; + + old_bridge_state = + drm_atomic_get_old_bridge_state(old_state, + bridge); + if (WARN_ON(!old_bridge_state)) + return; + + bridge->funcs->atomic_post_disable(bridge, + old_bridge_state); + } else if (bridge->funcs->post_disable) { bridge->funcs->post_disable(bridge); + } } } EXPORT_SYMBOL(drm_atomic_bridge_chain_post_disable); @@ -536,10 +555,19 @@ void drm_atomic_bridge_chain_pre_enable(struct drm_bridge *bridge, encoder = bridge->encoder; list_for_each_entry_reverse(iter, &bridge->encoder->bridge_chain, chain_node) { - if (iter->funcs->atomic_pre_enable) - iter->funcs->atomic_pre_enable(iter, old_state); - else if (iter->funcs->pre_enable) + if (iter->funcs->atomic_pre_enable) { + struct drm_bridge_state *old_bridge_state; + + old_bridge_state = + drm_atomic_get_old_bridge_state(old_state, + iter); + if (WARN_ON(!old_bridge_state)) + return; + + iter->funcs->atomic_pre_enable(iter, old_bridge_state); + } else if (iter->funcs->pre_enable) { iter->funcs->pre_enable(iter); + } if (iter == bridge) break; @@ -570,10 +598,19 @@ void drm_atomic_bridge_chain_enable(struct drm_bridge *bridge, encoder = bridge->encoder; list_for_each_entry_from(bridge, &bridge->encoder->bridge_chain, chain_node) { - if (bridge->funcs->atomic_enable) - bridge->funcs->atomic_enable(bridge, old_state); - else if (bridge->funcs->enable) + if (bridge->funcs->atomic_enable) { + struct drm_bridge_state *old_bridge_state; + + old_bridge_state = + drm_atomic_get_old_bridge_state(old_state, + bridge); + if (WARN_ON(!old_bridge_state)) + return; + + bridge->funcs->atomic_enable(bridge, old_bridge_state); + } else if (bridge->funcs->enable) { bridge->funcs->enable(bridge); + } } } EXPORT_SYMBOL(drm_atomic_bridge_chain_enable); diff --git a/include/drm/drm_bridge.h b/include/drm/drm_bridge.h index e814e6d6e7c2..b1f557d8dba9 100644 --- a/include/drm/drm_bridge.h +++ b/include/drm/drm_bridge.h @@ -266,8 +266,8 @@ struct drm_bridge_funcs { * bridge's @atomic_pre_enable or @pre_enable function. If the preceding * element is a &drm_encoder it's called right before the encoder's * &drm_encoder_helper_funcs.atomic_enable hook. - * This hook is passed the old atomic state (atomic state after new/old - * states have been swapped). + * This hook is passed the old bridge state (the new one can be + * retrieved from bridge->state). * * The display pipe (i.e. clocks and timing signals) feeding this bridge * will not yet be running when this callback is called. The bridge must @@ -283,7 +283,7 @@ struct drm_bridge_funcs { * The @atomic_pre_enable callback is optional. */ void (*atomic_pre_enable)(struct drm_bridge *bridge, - struct drm_atomic_state *old_state); + struct drm_bridge_state *old_bridge_state); /** * @atomic_enable: @@ -294,8 +294,8 @@ struct drm_bridge_funcs { * bridge's @atomic_enable or @enable function. If the preceding element * is a &drm_encoder it's called right after the encoder's * &drm_encoder_helper_funcs.atomic_enable hook. - * This hook is passed the old atomic state (atomic state after new/old - * states have been swapped). + * This hook is passed the old bridge state (the new one can be + * retrieved from bridge->state). * * The bridge can assume that the display pipe (i.e. clocks and timing * signals) feeding it is running when this callback is called. This @@ -310,7 +310,7 @@ struct drm_bridge_funcs { * The @atomic_enable callback is optional. */ void (*atomic_enable)(struct drm_bridge *bridge, - struct drm_atomic_state *old_state); + struct drm_bridge_state *old_bridge_state); /** * @atomic_disable: * @@ -320,8 +320,8 @@ struct drm_bridge_funcs { * bridge's @atomic_disable or @disable vfunc. If the preceding element * is a &drm_encoder it's called right before the * &drm_encoder_helper_funcs.atomic_disable hook. - * This hook is passed the old atomic state (atomic state after new/old - * states have been swapped). + * This hook is passed the old bridge state (the new one can be + * retrieved from bridge->state). * * The bridge can assume that the display pipe (i.e. clocks and timing * signals) feeding it is still running when this callback is called. @@ -335,7 +335,7 @@ struct drm_bridge_funcs { * The @atomic_disable callback is optional. */ void (*atomic_disable)(struct drm_bridge *bridge, - struct drm_atomic_state *old_state); + struct drm_bridge_state *old_bridge_state); /** * @atomic_post_disable: @@ -346,8 +346,8 @@ struct drm_bridge_funcs { * @atomic_post_disable or @post_disable function. If the preceding * element is a &drm_encoder it's called right after the encoder's * &drm_encoder_helper_funcs.atomic_disable hook. - * This hook is passed the old atomic state (atomic state after new/old - * states have been swapped). + * This hook is passed the old bridge state (the new one can be + * retrieved from bridge->state). * * The bridge must assume that the display pipe (i.e. clocks and timing * signals) feeding it is no longer running when this callback is @@ -363,7 +363,7 @@ struct drm_bridge_funcs { * The @atomic_post_disable callback is optional. */ void (*atomic_post_disable)(struct drm_bridge *bridge, - struct drm_atomic_state *old_state); + struct drm_bridge_state *old_bridge_state); /** * @atomic_duplicate_state: From patchwork Wed Oct 23 15:45:03 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Boris Brezillon X-Patchwork-Id: 11207103 Return-Path: Received: from mail.kernel.org (pdx-korg-mail-1.web.codeaurora.org [172.30.200.123]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id 275E41390 for ; Wed, 23 Oct 2019 15:45:46 +0000 (UTC) Received: from gabe.freedesktop.org (gabe.freedesktop.org [131.252.210.177]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by mail.kernel.org (Postfix) with ESMTPS id 101032084C for ; Wed, 23 Oct 2019 15:45:46 +0000 (UTC) DMARC-Filter: OpenDMARC Filter v1.3.2 mail.kernel.org 101032084C Authentication-Results: mail.kernel.org; dmarc=fail (p=none dis=none) header.from=collabora.com Authentication-Results: mail.kernel.org; spf=none smtp.mailfrom=dri-devel-bounces@lists.freedesktop.org Received: from gabe.freedesktop.org (localhost [127.0.0.1]) by gabe.freedesktop.org (Postfix) with ESMTP id 6C0176EB20; Wed, 23 Oct 2019 15:45:36 +0000 (UTC) X-Original-To: dri-devel@lists.freedesktop.org Delivered-To: dri-devel@lists.freedesktop.org Received: from bhuna.collabora.co.uk (bhuna.collabora.co.uk [46.235.227.227]) by gabe.freedesktop.org (Postfix) with ESMTPS id BAF7A6EB1B for ; Wed, 23 Oct 2019 15:45:29 +0000 (UTC) Received: from localhost.localdomain (unknown [IPv6:2a01:e0a:2c:6930:5cf4:84a1:2763:fe0d]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) (Authenticated sender: bbrezillon) by bhuna.collabora.co.uk (Postfix) with ESMTPSA id F07D928F95D; Wed, 23 Oct 2019 16:45:27 +0100 (BST) From: Boris Brezillon To: dri-devel@lists.freedesktop.org Subject: [PATCH v3 12/21] drm/bridge: Add an ->atomic_check() hook Date: Wed, 23 Oct 2019 17:45:03 +0200 Message-Id: <20191023154512.9762-13-boris.brezillon@collabora.com> X-Mailer: git-send-email 2.21.0 In-Reply-To: <20191023154512.9762-1-boris.brezillon@collabora.com> References: <20191023154512.9762-1-boris.brezillon@collabora.com> MIME-Version: 1.0 X-BeenThere: dri-devel@lists.freedesktop.org X-Mailman-Version: 2.1.23 Precedence: list List-Id: Direct Rendering Infrastructure - Development List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: Mark Rutland , Neil Armstrong , Thierry Reding , Laurent Pinchart , kernel@collabora.com, Sam Ravnborg , Nikita Yushchenko , Andrey Smirnov , Kyungmin Park , Chris Healy , devicetree@vger.kernel.org, Jonas Karlman , Rob Herring , Jernej Skrabec , Seung-Woo Kim , Boris Brezillon Errors-To: dri-devel-bounces@lists.freedesktop.org Sender: "dri-devel" So that bridge drivers have a way to check/reject an atomic operation. The drm_atomic_bridge_chain_check() (which is just a wrapper around the ->atomic_check() hook) is called in place of drm_bridge_chain_mode_fixup() (when ->atomic_check() is not implemented, the core falls back on ->mode_fixup(), so the behavior should stay the same for existing bridge drivers). Signed-off-by: Boris Brezillon Reviewed-by: Neil Armstrong Reviewed-by: Laurent Pinchart --- Changes in v3: * None Changes in v2: * Clarify the fact that ->atomic_check() is replacing ->mode_fixup() --- drivers/gpu/drm/drm_atomic_helper.c | 12 +++--- drivers/gpu/drm/drm_bridge.c | 62 +++++++++++++++++++++++++++++ include/drm/drm_bridge.h | 29 +++++++++++++- 3 files changed, 96 insertions(+), 7 deletions(-) diff --git a/drivers/gpu/drm/drm_atomic_helper.c b/drivers/gpu/drm/drm_atomic_helper.c index de985ba7ce2d..1d0a19511a0d 100644 --- a/drivers/gpu/drm/drm_atomic_helper.c +++ b/drivers/gpu/drm/drm_atomic_helper.c @@ -437,12 +437,12 @@ mode_fixup(struct drm_atomic_state *state) funcs = encoder->helper_private; bridge = drm_bridge_chain_get_first_bridge(encoder); - ret = drm_bridge_chain_mode_fixup(bridge, - &new_crtc_state->mode, - &new_crtc_state->adjusted_mode); - if (!ret) { - DRM_DEBUG_ATOMIC("Bridge fixup failed\n"); - return -EINVAL; + ret = drm_atomic_bridge_chain_check(bridge, + new_crtc_state, + new_conn_state); + if (ret) { + DRM_DEBUG_ATOMIC("Bridge atomic check failed\n"); + return ret; } if (funcs && funcs->atomic_check) { diff --git a/drivers/gpu/drm/drm_bridge.c b/drivers/gpu/drm/drm_bridge.c index 377866e3214f..990e056296bd 100644 --- a/drivers/gpu/drm/drm_bridge.c +++ b/drivers/gpu/drm/drm_bridge.c @@ -615,6 +615,68 @@ void drm_atomic_bridge_chain_enable(struct drm_bridge *bridge, } EXPORT_SYMBOL(drm_atomic_bridge_chain_enable); +static int drm_atomic_bridge_check(struct drm_bridge *bridge, + struct drm_crtc_state *crtc_state, + struct drm_connector_state *conn_state) +{ + if (bridge->funcs->atomic_check) { + struct drm_bridge_state *bridge_state; + int ret; + + bridge_state = drm_atomic_get_new_bridge_state(crtc_state->state, + bridge); + if (WARN_ON(!bridge_state)) + return -EINVAL; + + ret = bridge->funcs->atomic_check(bridge, bridge_state, + crtc_state, conn_state); + if (ret) + return ret; + } else if (bridge->funcs->mode_fixup) { + if (!bridge->funcs->mode_fixup(bridge, &crtc_state->mode, + &crtc_state->adjusted_mode)) + return -EINVAL; + } + + return 0; +} + +/** + * drm_atomic_bridge_chain_check() - Do an atomic check on the bridge chain + * @bridge: bridge control structure + * @crtc_state: new CRTC state + * @conn_state: new connector state + * + * Calls &drm_bridge_funcs.atomic_check() (falls back on + * &drm_bridge_funcs.mode_fixup()) op for all the bridges in the encoder chain, + * starting from the last bridge to the first. These are called before calling + * &drm_encoder_helper_funcs.atomic_check() + * + * RETURNS: + * 0 on success, a negative error code on failure + */ +int drm_atomic_bridge_chain_check(struct drm_bridge *bridge, + struct drm_crtc_state *crtc_state, + struct drm_connector_state *conn_state) +{ + struct drm_encoder *encoder = bridge->encoder; + struct drm_bridge *iter; + + list_for_each_entry_reverse(iter, &encoder->bridge_chain, chain_node) { + int ret; + + ret = drm_atomic_bridge_check(iter, crtc_state, conn_state); + if (ret) + return ret; + + if (iter == bridge) + break; + } + + return 0; +} +EXPORT_SYMBOL(drm_atomic_bridge_chain_check); + /** * drm_atomic_helper_bridge_destroy_state() - Default destroy state helper * @bridge: the bridge this state refers to diff --git a/include/drm/drm_bridge.h b/include/drm/drm_bridge.h index b1f557d8dba9..2beb1ef9a733 100644 --- a/include/drm/drm_bridge.h +++ b/include/drm/drm_bridge.h @@ -127,7 +127,9 @@ struct drm_bridge_funcs { * this function passes all other callbacks must succeed for this * configuration. * - * The @mode_fixup callback is optional. + * The mode_fixup callback is optional. &drm_bridge_funcs.mode_fixup() + * is not called when &drm_bridge_funcs.atomic_check() is implemented, + * so only one of them should be provided. * * NOTE: * @@ -391,6 +393,28 @@ struct drm_bridge_funcs { void (*atomic_destroy_state)(struct drm_bridge *bridge, struct drm_bridge_state *state); + /** + * @atomic_check: + * + * This method is responsible for checking bridge state correctness. + * It can also check the state of the surrounding components in chain + * to make sure the whole pipeline can work properly. + * + * &drm_bridge_funcs.atomic_check() hooks are called in reverse + * order (from the last to the first bridge). + * + * This method is optional. &drm_bridge_funcs.mode_fixup() is not + * called when &drm_bridge_funcs.atomic_check() is implemented, so only + * one of them should be provided. + * + * RETURNS: + * zero if the check passed, a negative error code otherwise. + */ + int (*atomic_check)(struct drm_bridge *bridge, + struct drm_bridge_state *bridge_state, + struct drm_crtc_state *crtc_state, + struct drm_connector_state *conn_state); + /** * @atomic_reset: * @@ -542,6 +566,9 @@ void drm_bridge_chain_mode_set(struct drm_bridge *bridge, void drm_bridge_chain_pre_enable(struct drm_bridge *bridge); void drm_bridge_chain_enable(struct drm_bridge *bridge); +int drm_atomic_bridge_chain_check(struct drm_bridge *bridge, + struct drm_crtc_state *crtc_state, + struct drm_connector_state *conn_state); void drm_atomic_bridge_chain_disable(struct drm_bridge *bridge, struct drm_atomic_state *state); void drm_atomic_bridge_chain_post_disable(struct drm_bridge *bridge, From patchwork Wed Oct 23 15:45:04 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Boris Brezillon X-Patchwork-Id: 11207115 Return-Path: Received: from mail.kernel.org (pdx-korg-mail-1.web.codeaurora.org [172.30.200.123]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id 969361390 for ; Wed, 23 Oct 2019 15:46:07 +0000 (UTC) Received: from gabe.freedesktop.org (gabe.freedesktop.org [131.252.210.177]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by mail.kernel.org (Postfix) with ESMTPS id 7EF3621A4C for ; Wed, 23 Oct 2019 15:46:07 +0000 (UTC) DMARC-Filter: OpenDMARC Filter v1.3.2 mail.kernel.org 7EF3621A4C Authentication-Results: mail.kernel.org; dmarc=fail (p=none dis=none) header.from=collabora.com Authentication-Results: mail.kernel.org; spf=none smtp.mailfrom=dri-devel-bounces@lists.freedesktop.org Received: from gabe.freedesktop.org (localhost [127.0.0.1]) by gabe.freedesktop.org (Postfix) with ESMTP id C6E246EB29; Wed, 23 Oct 2019 15:46:04 +0000 (UTC) X-Original-To: dri-devel@lists.freedesktop.org Delivered-To: dri-devel@lists.freedesktop.org Received: from bhuna.collabora.co.uk (bhuna.collabora.co.uk [IPv6:2a00:1098:0:82:1000:25:2eeb:e3e3]) by gabe.freedesktop.org (Postfix) with ESMTPS id 76F558959D for ; Wed, 23 Oct 2019 15:45:30 +0000 (UTC) Received: from localhost.localdomain (unknown [IPv6:2a01:e0a:2c:6930:5cf4:84a1:2763:fe0d]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) (Authenticated sender: bbrezillon) by bhuna.collabora.co.uk (Postfix) with ESMTPSA id B6D2328F962; Wed, 23 Oct 2019 16:45:28 +0100 (BST) From: Boris Brezillon To: dri-devel@lists.freedesktop.org Subject: [PATCH v3 13/21] drm/bridge: Add the drm_bridge_chain_get_prev_bridge() helper Date: Wed, 23 Oct 2019 17:45:04 +0200 Message-Id: <20191023154512.9762-14-boris.brezillon@collabora.com> X-Mailer: git-send-email 2.21.0 In-Reply-To: <20191023154512.9762-1-boris.brezillon@collabora.com> References: <20191023154512.9762-1-boris.brezillon@collabora.com> MIME-Version: 1.0 X-BeenThere: dri-devel@lists.freedesktop.org X-Mailman-Version: 2.1.23 Precedence: list List-Id: Direct Rendering Infrastructure - Development List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: Mark Rutland , Neil Armstrong , Thierry Reding , Laurent Pinchart , kernel@collabora.com, Sam Ravnborg , Nikita Yushchenko , Andrey Smirnov , Kyungmin Park , Chris Healy , devicetree@vger.kernel.org, Jonas Karlman , Rob Herring , Jernej Skrabec , Seung-Woo Kim , Boris Brezillon Errors-To: dri-devel-bounces@lists.freedesktop.org Sender: "dri-devel" Will be useful for bridge drivers that want to do bus format negotiation with their neighbours. Signed-off-by: Boris Brezillon Reviewed-by: Neil Armstrong Reviewed-by: Laurent Pinchart --- Changes in v3: * Inline drm_bridge_chain_get_prev_bridge() * Fix the doc Changes in v2: * Fix the kerneldoc * Drop the !bridge || !bridge->encoder check --- include/drm/drm_bridge.h | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/include/drm/drm_bridge.h b/include/drm/drm_bridge.h index 2beb1ef9a733..3fb518494640 100644 --- a/include/drm/drm_bridge.h +++ b/include/drm/drm_bridge.h @@ -526,6 +526,22 @@ drm_bridge_chain_get_next_bridge(struct drm_bridge *bridge) return list_next_entry(bridge, chain_node); } +/** + * drm_bridge_chain_get_prev_bridge() - Get the previous bridge in the chain + * @bridge: bridge object + * + * RETURNS: + * the previous bridge in the chain, or NULL if @bridge is the first. + */ +static inline struct drm_bridge * +drm_bridge_chain_get_prev_bridge(struct drm_bridge *bridge) +{ + if (list_is_first(&bridge->chain_node, &bridge->encoder->bridge_chain)) + return NULL; + + return list_prev_entry(bridge, chain_node); +} + /** * drm_bridge_chain_get_first_bridge() - Get the first bridge in the chain * @encoder: encoder object From patchwork Wed Oct 23 15:45:05 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Boris Brezillon X-Patchwork-Id: 11207097 Return-Path: Received: from mail.kernel.org (pdx-korg-mail-1.web.codeaurora.org [172.30.200.123]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id 6357D13BD for ; Wed, 23 Oct 2019 15:45:40 +0000 (UTC) Received: from gabe.freedesktop.org (gabe.freedesktop.org [131.252.210.177]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by mail.kernel.org (Postfix) with ESMTPS id 4AF942084C for ; Wed, 23 Oct 2019 15:45:40 +0000 (UTC) DMARC-Filter: OpenDMARC Filter v1.3.2 mail.kernel.org 4AF942084C Authentication-Results: mail.kernel.org; dmarc=fail (p=none dis=none) header.from=collabora.com Authentication-Results: mail.kernel.org; spf=none smtp.mailfrom=dri-devel-bounces@lists.freedesktop.org Received: from gabe.freedesktop.org (localhost [127.0.0.1]) by gabe.freedesktop.org (Postfix) with ESMTP id 44EA36EB1D; Wed, 23 Oct 2019 15:45:36 +0000 (UTC) X-Original-To: dri-devel@lists.freedesktop.org Delivered-To: dri-devel@lists.freedesktop.org Received: from bhuna.collabora.co.uk (bhuna.collabora.co.uk [46.235.227.227]) by gabe.freedesktop.org (Postfix) with ESMTPS id 553E78959D for ; Wed, 23 Oct 2019 15:45:31 +0000 (UTC) Received: from localhost.localdomain (unknown [IPv6:2a01:e0a:2c:6930:5cf4:84a1:2763:fe0d]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) (Authenticated sender: bbrezillon) by bhuna.collabora.co.uk (Postfix) with ESMTPSA id 7DB1D28F969; Wed, 23 Oct 2019 16:45:29 +0100 (BST) From: Boris Brezillon To: dri-devel@lists.freedesktop.org Subject: [PATCH v3 14/21] drm/bridge: Add the necessary bits to support bus format negotiation Date: Wed, 23 Oct 2019 17:45:05 +0200 Message-Id: <20191023154512.9762-15-boris.brezillon@collabora.com> X-Mailer: git-send-email 2.21.0 In-Reply-To: <20191023154512.9762-1-boris.brezillon@collabora.com> References: <20191023154512.9762-1-boris.brezillon@collabora.com> MIME-Version: 1.0 X-BeenThere: dri-devel@lists.freedesktop.org X-Mailman-Version: 2.1.23 Precedence: list List-Id: Direct Rendering Infrastructure - Development List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: Mark Rutland , Neil Armstrong , Thierry Reding , Laurent Pinchart , kernel@collabora.com, Sam Ravnborg , Nikita Yushchenko , Andrey Smirnov , Kyungmin Park , Chris Healy , devicetree@vger.kernel.org, Jonas Karlman , Rob Herring , Jernej Skrabec , Seung-Woo Kim , Boris Brezillon Errors-To: dri-devel-bounces@lists.freedesktop.org Sender: "dri-devel" drm_bridge_state is extended to describe the input and output bus configuration. This bus configuration is exposed through the drm_bus_cfg struct which contains 2 properties: the bus format and the bus flags. Bus format negotiation is automated by the core, drivers just have to implement the ->atomic_get_{output,input}_bus_fmts() hooks if they want to take part to this negotiation. Negotiation happens in reserve order, starting from the last element of the chain (the one directly connected to the display) up to the first element of the chain (the one connected to the encoder). During this negotiation all supported formats are tested until we find one that works, meaning that the formats array should be in decreasing preference order (assuming the driver has a preference order). Note that the bus format negotiation works even if some elements in the chain don't implement the ->atomic_get_{output,input}_bus_fmts() hooks. In that case, the core advertises only MEDIA_BUS_FMT_FIXED and let the previous bridge element decide what to do (most of the time, bridge drivers will pick a default bus format of extract this piece of information from somewhere else, like a FW property). Bus flags negotiation is left to drivers which can simply propagate the flags from the input of the next bridge element if there's no conversion done inside the bridge, or tweak them if the bridge does some kind of signal inversion. Signed-off-by: Boris Brezillon --- Changes in v3: * Fix the commit message (Reported by Laurent) * Document the fact that bus formats should not be directly modified by drivers (Suggested by Laurent) * Document the fact that format order matters (Suggested by Laurent) * Propagate bus flags by default * Document the fact that drivers can tweak bus flags if needed * Let ->atomic_get_{output,input}_bus_fmts() allocate the bus format array (Suggested by Laurent) * Add a drm_atomic_helper_bridge_propagate_bus_fmt() * Mandate that bridge drivers return accurate input_fmts even if they are known to be the first element in the bridge chain Changes in v2: * Rework things to support more complex use cases --- drivers/gpu/drm/drm_bridge.c | 257 ++++++++++++++++++++++++++++++++++- include/drm/drm_bridge.h | 106 +++++++++++++++ 2 files changed, 362 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/drm_bridge.c b/drivers/gpu/drm/drm_bridge.c index 990e056296bd..6022fb3d406a 100644 --- a/drivers/gpu/drm/drm_bridge.c +++ b/drivers/gpu/drm/drm_bridge.c @@ -641,13 +641,251 @@ static int drm_atomic_bridge_check(struct drm_bridge *bridge, return 0; } +static int select_bus_fmt_recursive(struct drm_bridge *first, + struct drm_bridge *cur, + struct drm_crtc_state *crtc_state, + struct drm_connector_state *conn_state, + u32 out_bus_fmt) +{ + struct drm_bridge_state *cur_state; + unsigned int num_in_bus_fmts, i; + struct drm_bridge *prev; + u32 *in_bus_fmts; + int ret; + + prev = drm_bridge_chain_get_prev_bridge(cur); + cur_state = drm_atomic_get_new_bridge_state(crtc_state->state, cur); + if (WARN_ON(!cur_state)) + return -EINVAL; + + /* + * Bus format negotiation is not supported by this bridge, let's pass + * MEDIA_BUS_FMT_FIXED to the previous bridge in the chain and hope + * that it can handle this situation gracefully (by providing + * appropriate default values). + */ + if (!cur->funcs->atomic_get_input_bus_fmts) { + if (cur != first) { + ret = select_bus_fmt_recursive(first, prev, crtc_state, + conn_state, + MEDIA_BUS_FMT_FIXED); + if (ret) + return ret; + } + + cur_state->input_bus_cfg.fmt = MEDIA_BUS_FMT_FIXED; + cur_state->output_bus_cfg.fmt = out_bus_fmt; + return 0; + } + + in_bus_fmts = cur->funcs->atomic_get_input_bus_fmts(cur, cur_state, + crtc_state, + conn_state, + out_bus_fmt, + &num_in_bus_fmts); + if (!num_in_bus_fmts) + return -ENOTSUPP; + else if (!in_bus_fmts) + return -ENOMEM; + + if (first == cur) { + cur_state->input_bus_cfg.fmt = in_bus_fmts[0]; + cur_state->output_bus_cfg.fmt = out_bus_fmt; + kfree(in_bus_fmts); + return 0; + } + + for (i = 0; i < num_in_bus_fmts; i++) { + ret = select_bus_fmt_recursive(first, prev, crtc_state, + conn_state, in_bus_fmts[i]); + if (ret != -ENOTSUPP) + break; + } + + if (!ret) { + cur_state->input_bus_cfg.fmt = in_bus_fmts[i]; + cur_state->output_bus_cfg.fmt = out_bus_fmt; + } + + kfree(in_bus_fmts); + return ret; +} + +/* + * This function is called by &drm_atomic_bridge_chain_check() just before + * calling &drm_bridge_funcs.atomic_check() on all elements of the chain. + * It's providing bus format negotiation between bridge elements. The + * negotiation happens in reverse order, starting from the last element in + * the chain up to @bridge. + * + * Negotiation starts by retrieving supported output bus formats on the last + * bridge element and testing them one by one. The test is recursive, meaning + * that for each tested output format, the whole chain will be walked backward, + * and each element will have to choose an input bus format that can be + * transcoded to the requested output format. When a bridge element does not + * support transcoding into a specific output format -ENOTSUPP is returned and + * the next bridge element will have to try a different format. If none of the + * combinations worked, -ENOTSUPP is returned and the atomic modeset will fail. + * + * This implementation is relying on + * &drm_bridge_funcs.atomic_get_output_bus_fmts() and + * &drm_bridge_funcs.atomic_get_input_bus_fmts() to gather supported + * input/output formats. + * When &drm_bridge_funcs.atomic_get_output_bus_fmts() is not implemented by + * the last element of the chain, &drm_atomic_bridge_chain_select_bus_fmts() + * tries a single format: &drm_connector.display_info.bus_formats[0] if + * available, MEDIA_BUS_FMT_FIXED otherwise. + * When &drm_bridge_funcs.atomic_get_input_bus_fmts() is not implemented, + * &drm_atomic_bridge_chain_select_bus_fmts() skips the negotiation on the + * bridge element that lacks this hook and asks the previous element in the + * chain to try MEDIA_BUS_FMT_FIXED. It's up to bridge drivers to decide what + * to do in that case (fail if they want to enforce bus format negotiation, or + * provide a reasonable default if they need to support pipelines where not + * all elements support bus format negotiation). + */ +static int +drm_atomic_bridge_chain_select_bus_fmts(struct drm_bridge *bridge, + struct drm_crtc_state *crtc_state, + struct drm_connector_state *conn_state) +{ + struct drm_connector *conn = conn_state->connector; + struct drm_encoder *encoder = bridge->encoder; + struct drm_bridge_state *last_bridge_state; + unsigned int i, num_out_bus_fmts; + struct drm_bridge *last_bridge; + u32 *out_bus_fmts; + int ret = 0; + + last_bridge = list_last_entry(&encoder->bridge_chain, + struct drm_bridge, chain_node); + last_bridge_state = drm_atomic_get_new_bridge_state(crtc_state->state, + last_bridge); + if (WARN_ON(!last_bridge_state)) + return -EINVAL; + + if (last_bridge->funcs->atomic_get_output_bus_fmts) { + const struct drm_bridge_funcs *funcs = last_bridge->funcs; + + out_bus_fmts = funcs->atomic_get_output_bus_fmts(last_bridge, + last_bridge_state, + crtc_state, + conn_state, + &num_out_bus_fmts); + if (!num_out_bus_fmts) + return -ENOTSUPP; + else if (!out_bus_fmts) + return -ENOMEM; + } else { + num_out_bus_fmts = 1; + out_bus_fmts = kzalloc(sizeof(*out_bus_fmts), GFP_KERNEL); + if (!out_bus_fmts) + return -ENOMEM; + + if (conn->display_info.num_bus_formats && + conn->display_info.bus_formats) + out_bus_fmts[0] = conn->display_info.bus_formats[0]; + else + out_bus_fmts[0] = MEDIA_BUS_FMT_FIXED; + } + + for (i = 0; i < num_out_bus_fmts; i++) { + ret = select_bus_fmt_recursive(bridge, last_bridge, crtc_state, + conn_state, out_bus_fmts[i]); + if (ret != -ENOTSUPP) + break; + } + + kfree(out_bus_fmts); + + return ret; +} + +static void +drm_atomic_bridge_propagate_bus_flags(struct drm_bridge *bridge, + struct drm_connector *conn, + struct drm_atomic_state *state) +{ + struct drm_bridge_state *bridge_state, *next_bridge_state; + struct drm_bridge *next_bridge; + u32 output_flags; + + bridge_state = drm_atomic_get_new_bridge_state(state, bridge); + next_bridge = drm_bridge_chain_get_next_bridge(bridge); + + /* + * Let's try to apply the most common case here, that is, propagate + * display_info flags for the last bridge, and propagate the input + * flags of the next bridge element to the output end of the current + * bridge when the bridge is not the last one. + * There are exceptions to this rule, like when signal inversion is + * happening at the board level, but that's something drivers can deal + * with from their &drm_bridge_funcs.atomic_check() implementation by + * simply overriding the flags value we've set here. + */ + if (!next_bridge) { + output_flags = conn->display_info.bus_flags; + } else { + next_bridge_state = drm_atomic_get_new_bridge_state(state, + next_bridge); + output_flags = next_bridge_state->input_bus_cfg.flags; + } + + bridge_state->output_bus_cfg.flags = output_flags; + + /* + * Propage the output flags to the input end of the bridge. Again, it's + * not necessarily what all bridges want, but that's what most of them + * do, and by doing that by default we avoid forcing drivers to + * duplicate the "dummy propagation" logic. + */ + bridge_state->input_bus_cfg.flags = output_flags; +} + +/** + * drm_atomic_helper_bridge_propagate_bus_fmt() - Propagate output format to + * the input end of a bridge + * @bridge: bridge control structure + * @bridge_state: new bridge state + * @crtc_state: new CRTC state + * @conn_state: new connector state + * @output_fmt: tested output bus format + * @num_input_fmts: will contain the size of the returned array + * + * Helper that propagate the output format to the input end of bridge. + * Particularly useful for dummy bridge elements like the panel_bridge. + * + * RETURNS: + * a valid format array of size @num_input_fmts, or NULL if the allocation + * failed or if @num_input_fmts is set to 0 + */ +u32 * +drm_atomic_helper_bridge_propagate_bus_fmt(struct drm_bridge *bridge, + struct drm_bridge_state *bridge_state, + struct drm_crtc_state *crtc_state, + struct drm_connector_state *conn_state, + u32 output_fmt, + unsigned int *num_input_fmts) +{ + u32 *input_fmts; + + *num_input_fmts = 1; + input_fmts = kzalloc(sizeof(*input_fmts), GFP_KERNEL); + if (!input_fmts) + return NULL; + + input_fmts[0] = output_fmt; + return input_fmts; +} +EXPORT_SYMBOL(drm_atomic_helper_bridge_propagate_bus_fmt); + /** * drm_atomic_bridge_chain_check() - Do an atomic check on the bridge chain * @bridge: bridge control structure * @crtc_state: new CRTC state * @conn_state: new connector state * - * Calls &drm_bridge_funcs.atomic_check() (falls back on + * First trigger a bus format negotiation before calling + * &drm_bridge_funcs.atomic_check() (falls back on * &drm_bridge_funcs.mode_fixup()) op for all the bridges in the encoder chain, * starting from the last bridge to the first. These are called before calling * &drm_encoder_helper_funcs.atomic_check() @@ -659,12 +897,29 @@ int drm_atomic_bridge_chain_check(struct drm_bridge *bridge, struct drm_crtc_state *crtc_state, struct drm_connector_state *conn_state) { + struct drm_connector *conn = conn_state->connector; struct drm_encoder *encoder = bridge->encoder; struct drm_bridge *iter; + int ret; + + ret = drm_atomic_bridge_chain_select_bus_fmts(bridge, crtc_state, + conn_state); + if (ret) + return ret; list_for_each_entry_reverse(iter, &encoder->bridge_chain, chain_node) { int ret; + /* + * Bus flags are propagated by default. If a bridge needs to + * tweak the input bus flags for any reason, it should happen + * in its &drm_bridge_funcs.atomic_check() implementation such + * that preceding bridges in the chain can propagate the new + * bus flags. + */ + drm_atomic_bridge_propagate_bus_flags(iter, conn, + crtc_state->state); + ret = drm_atomic_bridge_check(iter, crtc_state, conn_state); if (ret) return ret; diff --git a/include/drm/drm_bridge.h b/include/drm/drm_bridge.h index 3fb518494640..d37aaf34b882 100644 --- a/include/drm/drm_bridge.h +++ b/include/drm/drm_bridge.h @@ -34,15 +34,43 @@ struct drm_bridge; struct drm_bridge_timings; struct drm_panel; +/** + * struct drm_bus_cfg - bus configuration + * @fmt: format used on this bus. This field should not be directly modified + * by drivers (&drm_atomic_bridge_chain_select_bus_fmts() takes care of + * the bus format negotiation). + * @flags: DRM_BUS_ flags used on this bus. Drivers should set the output bus + * flags to the input bus flags of the next bridge element (unless they + * have a good reason not to, like a passive signal inversion between + * those 2 elements). Input bus flags can be different from the output + * ones if there's some kind of conversion happening inside the bridge, + * but most of the times it's safe to just propagate the output bus + * flags to the input end. + * This bus flags selection/propagation should be done in the driver + * &drm_bridge_funcs.atomic_check() hook. + * + * Encodes the bus format and bus flags used by one end of the bridge or + * by the encoder output. + */ +struct drm_bus_cfg { + u32 fmt; + u32 flags; +}; + /** * struct drm_bridge_state - Atomic bridge state object * @base: inherit from &drm_private_state * @bridge: the bridge this state refers to + * @input_bus_info: input bus information + * @output_bus_info: output bus information */ struct drm_bridge_state { struct drm_private_state base; struct drm_bridge *bridge; + + struct drm_bus_cfg input_bus_cfg; + struct drm_bus_cfg output_bus_cfg; }; static inline struct drm_bridge_state * @@ -393,6 +421,69 @@ struct drm_bridge_funcs { void (*atomic_destroy_state)(struct drm_bridge *bridge, struct drm_bridge_state *state); + /** + * @atomic_get_output_bus_fmts: + * + * Return the supported bus formats on the output end of a bridge. + * The returned array must be allocated with kmalloc() and will be + * freed by the caller, if the allocation fails, NULL should be + * returned. num_output_fmts must be set to the returned array size. + * Formats listed in the returned array should be listed in decreasing + * preference order (the core will try all formats until it finds one + * that works). + * + * This method is only called on the last element of the bridge chain + * as part of the bus format negotiation process that happens in + * &drm_atomic_bridge_chain_select_bus_fmts(). + * This method is optional. When not implemented, the core will + * fallback to &drm_connector.display_info.bus_formats[0] if + * &drm_connector.display_info.num_bus_formats > 0, + * MEDIA_BUS_FMT_FIXED otherwise. + */ + u32 *(*atomic_get_output_bus_fmts)(struct drm_bridge *bridge, + struct drm_bridge_state *bridge_state, + struct drm_crtc_state *crtc_state, + struct drm_connector_state *conn_state, + unsigned int *num_output_fmts); + + /** + * @atomic_get_input_bus_fmts: + * + * Return the supported bus formats on the input end of a bridge for + * a specific output bus format. + * The returned array must be allocated with kmalloc() and will be + * freed by the caller, if the allocation fails, NULL should be + * returned. num_output_fmts must be set to the returned array size. + * Formats listed in the returned array should be listed in decreasing + * preference order (the core will try all formats until it finds one + * that works). + * + * This method is called on all element of the bridge chain as part of + * the bus format negotiation process that happens in + * &drm_atomic_bridge_chain_select_bus_fmts(). + * This method is optional. When not implemented, the core will bypass + * bus format negotiation on this element of the bridge without + * failing, and the previous element in the chain will be passed + * MEDIA_BUS_FMT_FIXED as its output bus format. + * + * Bridge drivers that need to support being linked to bridges that are + * not supporting bus format negotiation should handle the + * output_fmt == MEDIA_BUS_FMT_FIXED case appropriately, by selecting a + * sensible default value or extracting this information from somewhere + * else (FW property, &drm_display_mode, &drm_display_info, ...) + * + * Note: even if input format selection on the first bridge has no + * impact on the negotiation process (bus format negotiation stops once + * we reach the first element of the chain), drivers are expected to + * return accurate input formats. + */ + u32 *(*atomic_get_input_bus_fmts)(struct drm_bridge *bridge, + struct drm_bridge_state *bridge_state, + struct drm_crtc_state *crtc_state, + struct drm_connector_state *conn_state, + u32 output_fmt, + unsigned int *num_input_fmts); + /** * @atomic_check: * @@ -407,6 +498,13 @@ struct drm_bridge_funcs { * called when &drm_bridge_funcs.atomic_check() is implemented, so only * one of them should be provided. * + * If drivers need to tweak &drm_bridge_state.input_bus_cfg.flags or + * &drm_bridge_state.input_bus_cfg.flags it should should happen in + * this function. By default those fields are set to the next bridge + * &drm_bridge_state.input_bus_cfg.flags value or + * &drm_connector.display_info.bus_flags if the bridge is the last + * element in the chain. + * * RETURNS: * zero if the check passed, a negative error code otherwise. */ @@ -594,6 +692,14 @@ void drm_atomic_bridge_chain_pre_enable(struct drm_bridge *bridge, void drm_atomic_bridge_chain_enable(struct drm_bridge *bridge, struct drm_atomic_state *state); +u32 * +drm_atomic_helper_bridge_propagate_bus_fmt(struct drm_bridge *bridge, + struct drm_bridge_state *bridge_state, + struct drm_crtc_state *crtc_state, + struct drm_connector_state *conn_state, + u32 output_fmt, + unsigned int *num_input_fmts); + void __drm_atomic_helper_bridge_reset(struct drm_bridge *bridge, struct drm_bridge_state *state); struct drm_bridge_state * From patchwork Wed Oct 23 15:45:06 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Boris Brezillon X-Patchwork-Id: 11207123 Return-Path: Received: from mail.kernel.org (pdx-korg-mail-1.web.codeaurora.org [172.30.200.123]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id 1984C1390 for ; Wed, 23 Oct 2019 15:46:12 +0000 (UTC) Received: from gabe.freedesktop.org (gabe.freedesktop.org [131.252.210.177]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by mail.kernel.org (Postfix) with ESMTPS id 0213721D71 for ; Wed, 23 Oct 2019 15:46:12 +0000 (UTC) DMARC-Filter: OpenDMARC Filter v1.3.2 mail.kernel.org 0213721D71 Authentication-Results: mail.kernel.org; dmarc=fail (p=none dis=none) header.from=collabora.com Authentication-Results: mail.kernel.org; spf=none smtp.mailfrom=dri-devel-bounces@lists.freedesktop.org Received: from gabe.freedesktop.org (localhost [127.0.0.1]) by gabe.freedesktop.org (Postfix) with ESMTP id 65C846EB2E; Wed, 23 Oct 2019 15:46:05 +0000 (UTC) X-Original-To: dri-devel@lists.freedesktop.org Delivered-To: dri-devel@lists.freedesktop.org Received: from bhuna.collabora.co.uk (bhuna.collabora.co.uk [IPv6:2a00:1098:0:82:1000:25:2eeb:e3e3]) by gabe.freedesktop.org (Postfix) with ESMTPS id 195F58959D for ; Wed, 23 Oct 2019 15:45:32 +0000 (UTC) Received: from localhost.localdomain (unknown [IPv6:2a01:e0a:2c:6930:5cf4:84a1:2763:fe0d]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) (Authenticated sender: bbrezillon) by bhuna.collabora.co.uk (Postfix) with ESMTPSA id 4E57E28F96E; Wed, 23 Oct 2019 16:45:30 +0100 (BST) From: Boris Brezillon To: dri-devel@lists.freedesktop.org Subject: [PATCH v3 15/21] drm/imx: pd: Use bus format/flags provided by the bridge when available Date: Wed, 23 Oct 2019 17:45:06 +0200 Message-Id: <20191023154512.9762-16-boris.brezillon@collabora.com> X-Mailer: git-send-email 2.21.0 In-Reply-To: <20191023154512.9762-1-boris.brezillon@collabora.com> References: <20191023154512.9762-1-boris.brezillon@collabora.com> MIME-Version: 1.0 X-BeenThere: dri-devel@lists.freedesktop.org X-Mailman-Version: 2.1.23 Precedence: list List-Id: Direct Rendering Infrastructure - Development List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: Mark Rutland , Neil Armstrong , Thierry Reding , Laurent Pinchart , kernel@collabora.com, Sam Ravnborg , Nikita Yushchenko , Andrey Smirnov , Kyungmin Park , Chris Healy , devicetree@vger.kernel.org, Jonas Karlman , Rob Herring , Jernej Skrabec , Seung-Woo Kim , Boris Brezillon Errors-To: dri-devel-bounces@lists.freedesktop.org Sender: "dri-devel" Now that bridges can expose the bus format/flags they expect, we can use those instead of the relying on the display_info provided by the connector (which is only valid if the encoder is directly connected to bridge element driving the panel/display). We also explicitly expose the bus formats supported by our encoder by filling encoder->output_bus_caps with proper info. Signed-off-by: Boris Brezillon --- Hi Philipp, I think I addressed all your comments except the addition of SYNC_DRIVE_POSEDGE/NEGEDGE flags, which would require changing ipu_crtc_mode_set_nofb() to take those flags into account or turning those flags into their PIXDATA counterpart. If you don't mind, I'd like to leave that for later. Regards, Boris Changes in v3 (all suggested by Philipp): * Adjust to match core changes * Propagate output format to input format * Pick a default value when output_fmt = _FIXED * Add missing BGR888 and GBR888 fmts to imx_pd_bus_fmts[] Changes in v2: * Adjust things to match the new bus-format negotiation infra --- drivers/gpu/drm/imx/parallel-display.c | 174 +++++++++++++++++++++---- 1 file changed, 150 insertions(+), 24 deletions(-) diff --git a/drivers/gpu/drm/imx/parallel-display.c b/drivers/gpu/drm/imx/parallel-display.c index 35518e5de356..28ae083df3ca 100644 --- a/drivers/gpu/drm/imx/parallel-display.c +++ b/drivers/gpu/drm/imx/parallel-display.c @@ -24,6 +24,7 @@ struct imx_parallel_display { struct drm_connector connector; struct drm_encoder encoder; + struct drm_bridge bridge; struct device *dev; void *edid; int edid_len; @@ -31,7 +32,7 @@ struct imx_parallel_display { u32 bus_flags; struct drm_display_mode mode; struct drm_panel *panel; - struct drm_bridge *bridge; + struct drm_bridge *next_bridge; }; static inline struct imx_parallel_display *con_to_imxpd(struct drm_connector *c) @@ -44,6 +45,11 @@ static inline struct imx_parallel_display *enc_to_imxpd(struct drm_encoder *e) return container_of(e, struct imx_parallel_display, encoder); } +static inline struct imx_parallel_display *bridge_to_imxpd(struct drm_bridge *b) +{ + return container_of(b, struct imx_parallel_display, bridge); +} + static int imx_pd_connector_get_modes(struct drm_connector *connector) { struct imx_parallel_display *imxpd = con_to_imxpd(connector); @@ -89,37 +95,151 @@ static struct drm_encoder *imx_pd_connector_best_encoder( return &imxpd->encoder; } -static void imx_pd_encoder_enable(struct drm_encoder *encoder) +static void imx_pd_bridge_enable(struct drm_bridge *bridge) { - struct imx_parallel_display *imxpd = enc_to_imxpd(encoder); + struct imx_parallel_display *imxpd = bridge_to_imxpd(bridge); drm_panel_prepare(imxpd->panel); drm_panel_enable(imxpd->panel); } -static void imx_pd_encoder_disable(struct drm_encoder *encoder) +static void imx_pd_bridge_disable(struct drm_bridge *bridge) { - struct imx_parallel_display *imxpd = enc_to_imxpd(encoder); + struct imx_parallel_display *imxpd = bridge_to_imxpd(bridge); drm_panel_disable(imxpd->panel); drm_panel_unprepare(imxpd->panel); } -static int imx_pd_encoder_atomic_check(struct drm_encoder *encoder, - struct drm_crtc_state *crtc_state, - struct drm_connector_state *conn_state) +static const u32 imx_pd_bus_fmts[] = { + MEDIA_BUS_FMT_RGB888_1X24, + MEDIA_BUS_FMT_BGR888_1X24, + MEDIA_BUS_FMT_GBR888_1X24, + MEDIA_BUS_FMT_RGB666_1X18, + MEDIA_BUS_FMT_RGB666_1X24_CPADHI, + MEDIA_BUS_FMT_RGB565_1X16, +}; + +static u32 * +imx_pd_bridge_atomic_get_output_bus_fmts(struct drm_bridge *bridge, + struct drm_bridge_state *bridge_state, + struct drm_crtc_state *crtc_state, + struct drm_connector_state *conn_state, + unsigned int *num_output_fmts) +{ + struct drm_display_info *di = &conn_state->connector->display_info; + struct imx_parallel_display *imxpd = bridge_to_imxpd(bridge); + u32 *output_fmts; + + if (!imxpd->bus_format && !di->num_bus_formats) + *num_output_fmts = ARRAY_SIZE(imx_pd_bus_fmts); + else + *num_output_fmts = 1; + + output_fmts = kcalloc(*num_output_fmts, sizeof(*output_fmts), + GFP_KERNEL); + if (!output_fmts) + return NULL; + + if (!imxpd->bus_format && di->num_bus_formats) + output_fmts[0] = di->bus_formats[0]; + else if (!imxpd->bus_format) + memcpy(output_fmts, imx_pd_bus_fmts, + ARRAY_SIZE(imx_pd_bus_fmts)); + else + output_fmts[0] = imxpd->bus_format; + + return output_fmts; +} + +static u32 * +imx_pd_bridge_atomic_get_input_bus_fmts(struct drm_bridge *bridge, + struct drm_bridge_state *bridge_state, + struct drm_crtc_state *crtc_state, + struct drm_connector_state *conn_state, + u32 output_fmt, + unsigned int *num_input_fmts) +{ + struct imx_parallel_display *imxpd = bridge_to_imxpd(bridge); + u32 *input_fmts; + + *num_input_fmts = 0; + if (output_fmt == MEDIA_BUS_FMT_FIXED) { + /* + * The next bridge does not support bus format negotiation, + * let's use the default RGB888 value. + */ + *num_input_fmts = 1; + output_fmt = MEDIA_BUS_FMT_RGB888_1X24; + } else if (!imxpd->bus_format) { + unsigned int i; + + for (i = 0; i < ARRAY_SIZE(imx_pd_bus_fmts); i++) { + if (imx_pd_bus_fmts[i] == output_fmt) { + *num_input_fmts = 1; + break; + } + } + } else if (imxpd->bus_format == output_fmt) { + *num_input_fmts = 1; + } + + if (!*num_input_fmts) + return NULL; + + input_fmts = kcalloc(*num_input_fmts, sizeof(*input_fmts), + GFP_KERNEL); + if (!input_fmts) + return NULL; + + input_fmts[0] = output_fmt; + return input_fmts; +} + +static int imx_pd_bridge_atomic_check(struct drm_bridge *bridge, + struct drm_bridge_state *bridge_state, + struct drm_crtc_state *crtc_state, + struct drm_connector_state *conn_state) { struct imx_crtc_state *imx_crtc_state = to_imx_crtc_state(crtc_state); struct drm_display_info *di = &conn_state->connector->display_info; - struct imx_parallel_display *imxpd = enc_to_imxpd(encoder); + struct imx_parallel_display *imxpd = bridge_to_imxpd(bridge); + struct drm_bridge_state *next_bridge_state = NULL; + struct drm_bridge *next_bridge; + u32 bus_flags, bus_fmt; + unsigned int i; - if (!imxpd->bus_format && di->num_bus_formats) { - imx_crtc_state->bus_flags = di->bus_flags; - imx_crtc_state->bus_format = di->bus_formats[0]; - } else { - imx_crtc_state->bus_flags = imxpd->bus_flags; - imx_crtc_state->bus_format = imxpd->bus_format; + next_bridge = drm_bridge_chain_get_next_bridge(bridge); + if (next_bridge) + next_bridge_state = drm_atomic_get_new_bridge_state(crtc_state->state, + next_bridge); + + if (next_bridge_state) + bus_flags = next_bridge_state->input_bus_cfg.flags; + else if (!imxpd->bus_format && di->num_bus_formats) + bus_flags = di->bus_flags; + else + bus_flags = imxpd->bus_flags; + + bus_fmt = bridge_state->input_bus_cfg.fmt; + for (i = 0; i < ARRAY_SIZE(imx_pd_bus_fmts); i++) { + if (imx_pd_bus_fmts[i] == bus_fmt) + break; } + + if (i == ARRAY_SIZE(imx_pd_bus_fmts)) + return -EINVAL; + + if (bus_flags & + ~(DRM_BUS_FLAG_DE_LOW | DRM_BUS_FLAG_DE_HIGH | + DRM_BUS_FLAG_PIXDATA_DRIVE_POSEDGE | + DRM_BUS_FLAG_PIXDATA_DRIVE_NEGEDGE)) + return -EINVAL; + + bridge_state->output_bus_cfg.flags = bus_flags; + bridge_state->input_bus_cfg.flags = bus_flags; + imx_crtc_state->bus_flags = bus_flags; + imx_crtc_state->bus_format = bridge_state->input_bus_cfg.fmt; imx_crtc_state->di_hsync_pin = 2; imx_crtc_state->di_vsync_pin = 3; @@ -143,10 +263,12 @@ static const struct drm_encoder_funcs imx_pd_encoder_funcs = { .destroy = imx_drm_encoder_destroy, }; -static const struct drm_encoder_helper_funcs imx_pd_encoder_helper_funcs = { - .enable = imx_pd_encoder_enable, - .disable = imx_pd_encoder_disable, - .atomic_check = imx_pd_encoder_atomic_check, +static const struct drm_bridge_funcs imx_pd_bridge_funcs = { + .enable = imx_pd_bridge_enable, + .disable = imx_pd_bridge_disable, + .atomic_check = imx_pd_bridge_atomic_check, + .atomic_get_input_bus_fmts = imx_pd_bridge_atomic_get_input_bus_fmts, + .atomic_get_output_bus_fmts = imx_pd_bridge_atomic_get_output_bus_fmts, }; static int imx_pd_register(struct drm_device *drm, @@ -166,11 +288,13 @@ static int imx_pd_register(struct drm_device *drm, */ imxpd->connector.dpms = DRM_MODE_DPMS_OFF; - drm_encoder_helper_add(encoder, &imx_pd_encoder_helper_funcs); drm_encoder_init(drm, encoder, &imx_pd_encoder_funcs, DRM_MODE_ENCODER_NONE, NULL); - if (!imxpd->bridge) { + imxpd->bridge.funcs = &imx_pd_bridge_funcs; + drm_bridge_attach(encoder, &imxpd->bridge, NULL); + + if (!imxpd->next_bridge) { drm_connector_helper_add(&imxpd->connector, &imx_pd_connector_helper_funcs); drm_connector_init(drm, &imxpd->connector, @@ -181,8 +305,9 @@ static int imx_pd_register(struct drm_device *drm, if (imxpd->panel) drm_panel_attach(imxpd->panel, &imxpd->connector); - if (imxpd->bridge) { - ret = drm_bridge_attach(encoder, imxpd->bridge, NULL); + if (imxpd->next_bridge) { + ret = drm_bridge_attach(encoder, imxpd->next_bridge, + &imxpd->bridge); if (ret < 0) { dev_err(imxpd->dev, "failed to attach bridge: %d\n", ret); @@ -227,7 +352,8 @@ static int imx_pd_bind(struct device *dev, struct device *master, void *data) imxpd->bus_format = bus_format; /* port@1 is the output port */ - ret = drm_of_find_panel_or_bridge(np, 1, 0, &imxpd->panel, &imxpd->bridge); + ret = drm_of_find_panel_or_bridge(np, 1, 0, &imxpd->panel, + &imxpd->next_bridge); if (ret && ret != -ENODEV) return ret; From patchwork Wed Oct 23 15:45:07 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Boris Brezillon X-Patchwork-Id: 11207127 Return-Path: Received: from mail.kernel.org (pdx-korg-mail-1.web.codeaurora.org [172.30.200.123]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id 4421313BD for ; Wed, 23 Oct 2019 15:46:15 +0000 (UTC) Received: from gabe.freedesktop.org (gabe.freedesktop.org [131.252.210.177]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by mail.kernel.org (Postfix) with ESMTPS id 2CCB121928 for ; Wed, 23 Oct 2019 15:46:15 +0000 (UTC) DMARC-Filter: OpenDMARC Filter v1.3.2 mail.kernel.org 2CCB121928 Authentication-Results: mail.kernel.org; dmarc=fail (p=none dis=none) header.from=collabora.com Authentication-Results: mail.kernel.org; spf=none smtp.mailfrom=dri-devel-bounces@lists.freedesktop.org Received: from gabe.freedesktop.org (localhost [127.0.0.1]) by gabe.freedesktop.org (Postfix) with ESMTP id 5CC8D6EB2D; Wed, 23 Oct 2019 15:46:05 +0000 (UTC) X-Original-To: dri-devel@lists.freedesktop.org Delivered-To: dri-devel@lists.freedesktop.org Received: from bhuna.collabora.co.uk (bhuna.collabora.co.uk [46.235.227.227]) by gabe.freedesktop.org (Postfix) with ESMTPS id E86516E10B for ; Wed, 23 Oct 2019 15:45:32 +0000 (UTC) Received: from localhost.localdomain (unknown [IPv6:2a01:e0a:2c:6930:5cf4:84a1:2763:fe0d]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) (Authenticated sender: bbrezillon) by bhuna.collabora.co.uk (Postfix) with ESMTPSA id 1F33528F911; Wed, 23 Oct 2019 16:45:31 +0100 (BST) From: Boris Brezillon To: dri-devel@lists.freedesktop.org Subject: [PATCH v3 16/21] drm/bridge: lvds-encoder: Implement basic bus format negotiation Date: Wed, 23 Oct 2019 17:45:07 +0200 Message-Id: <20191023154512.9762-17-boris.brezillon@collabora.com> X-Mailer: git-send-email 2.21.0 In-Reply-To: <20191023154512.9762-1-boris.brezillon@collabora.com> References: <20191023154512.9762-1-boris.brezillon@collabora.com> MIME-Version: 1.0 X-BeenThere: dri-devel@lists.freedesktop.org X-Mailman-Version: 2.1.23 Precedence: list List-Id: Direct Rendering Infrastructure - Development List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: Mark Rutland , Neil Armstrong , Thierry Reding , Laurent Pinchart , kernel@collabora.com, Sam Ravnborg , Nikita Yushchenko , Andrey Smirnov , Kyungmin Park , Chris Healy , devicetree@vger.kernel.org, Jonas Karlman , Rob Herring , Jernej Skrabec , Seung-Woo Kim , Boris Brezillon Errors-To: dri-devel-bounces@lists.freedesktop.org Sender: "dri-devel" Some LVDS encoder might support several input/output bus formats. Add a way to describe the one used on a specific design by adding optional 'data-mapping' properties to the input/output ports. Signed-off-by: Boris Brezillon --- Changes in v3: * Use bus-width for the rgb24/rgb18 distinction * Adjust code to match core changes * Get rid of of_get_data_mapping() * Don't implement ->atomic_check() (the core now takes care of bus flags propagation) Changes in v2: * Make the bus-format negotiation logic more generic --- drivers/gpu/drm/bridge/lvds-encoder.c | 72 +++++++++++++++++++++++++++ 1 file changed, 72 insertions(+) diff --git a/drivers/gpu/drm/bridge/lvds-encoder.c b/drivers/gpu/drm/bridge/lvds-encoder.c index e2132a8d5106..a2a8f7f4ac97 100644 --- a/drivers/gpu/drm/bridge/lvds-encoder.c +++ b/drivers/gpu/drm/bridge/lvds-encoder.c @@ -6,6 +6,7 @@ #include #include #include +#include #include #include @@ -16,6 +17,8 @@ struct lvds_encoder { struct drm_bridge bridge; struct drm_bridge *panel_bridge; struct gpio_desc *powerdown_gpio; + u32 output_fmt; + u32 input_fmt; }; static int lvds_encoder_attach(struct drm_bridge *bridge) @@ -48,10 +51,40 @@ static void lvds_encoder_disable(struct drm_bridge *bridge) gpiod_set_value_cansleep(lvds_encoder->powerdown_gpio, 1); } +static u32 *lvds_atomic_get_input_bus_fmts(struct drm_bridge *bridge, + struct drm_bridge_state *bridge_state, + struct drm_crtc_state *crtc_state, + struct drm_connector_state *conn_state, + u32 output_fmt, + unsigned int *num_input_fmts) +{ + struct lvds_encoder *lvds_encoder = container_of(bridge, + struct lvds_encoder, + bridge); + u32 *input_fmts; + + if (output_fmt == MEDIA_BUS_FMT_FIXED || + output_fmt == lvds_encoder->output_fmt) + *num_input_fmts = 1; + else + *num_input_fmts = 0; + + if (!*num_input_fmts) + return NULL; + + input_fmts = kcalloc(*num_input_fmts, sizeof(*input_fmts), GFP_KERNEL); + if (!input_fmts) + return NULL; + + input_fmts[0] = lvds_encoder->input_fmt; + return input_fmts; +} + static struct drm_bridge_funcs funcs = { .attach = lvds_encoder_attach, .enable = lvds_encoder_enable, .disable = lvds_encoder_disable, + .atomic_get_input_bus_fmts = lvds_atomic_get_input_bus_fmts, }; static int lvds_encoder_probe(struct platform_device *pdev) @@ -62,11 +95,16 @@ static int lvds_encoder_probe(struct platform_device *pdev) struct device_node *panel_node; struct drm_panel *panel; struct lvds_encoder *lvds_encoder; + const char *output_data_mapping = NULL; + u32 input_bus_width = 0; lvds_encoder = devm_kzalloc(dev, sizeof(*lvds_encoder), GFP_KERNEL); if (!lvds_encoder) return -ENOMEM; + lvds_encoder->input_fmt = MEDIA_BUS_FMT_FIXED; + lvds_encoder->output_fmt = MEDIA_BUS_FMT_FIXED; + lvds_encoder->powerdown_gpio = devm_gpiod_get_optional(dev, "powerdown", GPIOD_OUT_HIGH); if (IS_ERR(lvds_encoder->powerdown_gpio)) { @@ -77,6 +115,25 @@ static int lvds_encoder_probe(struct platform_device *pdev) return err; } + port = of_graph_get_port_by_id(dev->of_node, 0); + if (!port) { + dev_dbg(dev, "port 0 not found\n"); + return -ENXIO; + } + + of_node_put(port); + + if (of_property_read_u32(port, "bus-width", &input_bus_width)) { + lvds_encoder->input_fmt = MEDIA_BUS_FMT_FIXED; + } else if (input_bus_width == 18) { + lvds_encoder->input_fmt = MEDIA_BUS_FMT_RGB666_1X18; + } else if (input_bus_width == 24) { + lvds_encoder->input_fmt = MEDIA_BUS_FMT_RGB888_1X24; + } else { + dev_dbg(dev, "unsupported bus-width)\n"); + return -ENOTSUPP; + } + /* Locate the panel DT node. */ port = of_graph_get_port_by_id(dev->of_node, 1); if (!port) { @@ -84,6 +141,21 @@ static int lvds_encoder_probe(struct platform_device *pdev) return -ENXIO; } + of_property_read_string(port, "data-mapping", &output_data_mapping); + if (!output_data_mapping) { + lvds_encoder->output_fmt = MEDIA_BUS_FMT_FIXED; + } else if (!strcmp(output_data_mapping, "jeida-18")) { + lvds_encoder->output_fmt = MEDIA_BUS_FMT_RGB666_1X7X3_SPWG; + } else if (!strcmp(output_data_mapping, "jeida-24")) { + lvds_encoder->output_fmt = MEDIA_BUS_FMT_RGB888_1X7X4_JEIDA; + } else if (!strcmp(output_data_mapping, "vesa-24")) { + lvds_encoder->output_fmt = MEDIA_BUS_FMT_RGB888_1X7X4_SPWG; + } else { + of_node_put(port); + dev_dbg(dev, "unsupported output data-mapping\n"); + return -ENOTSUPP; + } + endpoint = of_get_child_by_name(port, "endpoint"); of_node_put(port); if (!endpoint) { From patchwork Wed Oct 23 15:45:08 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Boris Brezillon X-Patchwork-Id: 11207111 Return-Path: Received: from mail.kernel.org (pdx-korg-mail-1.web.codeaurora.org [172.30.200.123]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id 66F1F13BD for ; Wed, 23 Oct 2019 15:45:58 +0000 (UTC) Received: from gabe.freedesktop.org (gabe.freedesktop.org [131.252.210.177]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by mail.kernel.org (Postfix) with ESMTPS id 4F7F120679 for ; Wed, 23 Oct 2019 15:45:58 +0000 (UTC) DMARC-Filter: OpenDMARC Filter v1.3.2 mail.kernel.org 4F7F120679 Authentication-Results: mail.kernel.org; dmarc=fail (p=none dis=none) header.from=collabora.com Authentication-Results: mail.kernel.org; spf=none smtp.mailfrom=dri-devel-bounces@lists.freedesktop.org Received: from gabe.freedesktop.org (localhost [127.0.0.1]) by gabe.freedesktop.org (Postfix) with ESMTP id 25BA16EB28; Wed, 23 Oct 2019 15:45:56 +0000 (UTC) X-Original-To: dri-devel@lists.freedesktop.org Delivered-To: dri-devel@lists.freedesktop.org Received: from bhuna.collabora.co.uk (bhuna.collabora.co.uk [46.235.227.227]) by gabe.freedesktop.org (Postfix) with ESMTPS id ABF7A8959D for ; Wed, 23 Oct 2019 15:45:33 +0000 (UTC) Received: from localhost.localdomain (unknown [IPv6:2a01:e0a:2c:6930:5cf4:84a1:2763:fe0d]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) (Authenticated sender: bbrezillon) by bhuna.collabora.co.uk (Postfix) with ESMTPSA id DD2A328F977; Wed, 23 Oct 2019 16:45:31 +0100 (BST) From: Boris Brezillon To: dri-devel@lists.freedesktop.org Subject: [PATCH v3 17/21] dt-bindings: display: bridge: lvds-transmitter: Add new props Date: Wed, 23 Oct 2019 17:45:08 +0200 Message-Id: <20191023154512.9762-18-boris.brezillon@collabora.com> X-Mailer: git-send-email 2.21.0 In-Reply-To: <20191023154512.9762-1-boris.brezillon@collabora.com> References: <20191023154512.9762-1-boris.brezillon@collabora.com> MIME-Version: 1.0 X-BeenThere: dri-devel@lists.freedesktop.org X-Mailman-Version: 2.1.23 Precedence: list List-Id: Direct Rendering Infrastructure - Development List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: Mark Rutland , Neil Armstrong , Thierry Reding , Laurent Pinchart , kernel@collabora.com, Sam Ravnborg , Nikita Yushchenko , Andrey Smirnov , Kyungmin Park , Chris Healy , devicetree@vger.kernel.org, Jonas Karlman , Rob Herring , Jernej Skrabec , Seung-Woo Kim , Boris Brezillon Errors-To: dri-devel-bounces@lists.freedesktop.org Sender: "dri-devel" Add the data-mapping property to describe the output bus format and the bus-width property to describe the input bus format. Signed-off-by: Boris Brezillon --- Changes in v3: * New patch --- .../bindings/display/bridge/lvds-transmitter.txt | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/Documentation/devicetree/bindings/display/bridge/lvds-transmitter.txt b/Documentation/devicetree/bindings/display/bridge/lvds-transmitter.txt index 60091db5dfa5..7b43b6f20279 100644 --- a/Documentation/devicetree/bindings/display/bridge/lvds-transmitter.txt +++ b/Documentation/devicetree/bindings/display/bridge/lvds-transmitter.txt @@ -36,6 +36,19 @@ graph bindings specified in Documentation/devicetree/bindings/graph.txt. - Video port 0 for parallel input - Video port 1 for LVDS output +Optional port 0 node properties: + +- bus-width: number of data lines use to transmit the RGB data. + Can be 18 or 24. + +Optional port 1 node properties: + +- data-mapping: see Documentation/devicetree/bindings/display/panel/lvds.yaml + for more details about this LVDS data-mapping property. + Supported values: + "jeida-18" + "jeida-24" + "vesa-24" Example ------- From patchwork Wed Oct 23 15:45:09 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Boris Brezillon X-Patchwork-Id: 11207107 Return-Path: Received: from mail.kernel.org (pdx-korg-mail-1.web.codeaurora.org [172.30.200.123]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id B15C113BD for ; Wed, 23 Oct 2019 15:45:49 +0000 (UTC) Received: from gabe.freedesktop.org (gabe.freedesktop.org [131.252.210.177]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by mail.kernel.org (Postfix) with ESMTPS id 99CA020679 for ; Wed, 23 Oct 2019 15:45:49 +0000 (UTC) DMARC-Filter: OpenDMARC Filter v1.3.2 mail.kernel.org 99CA020679 Authentication-Results: mail.kernel.org; dmarc=fail (p=none dis=none) header.from=collabora.com Authentication-Results: mail.kernel.org; spf=none smtp.mailfrom=dri-devel-bounces@lists.freedesktop.org Received: from gabe.freedesktop.org (localhost [127.0.0.1]) by gabe.freedesktop.org (Postfix) with ESMTP id 319386EB22; Wed, 23 Oct 2019 15:45:37 +0000 (UTC) X-Original-To: dri-devel@lists.freedesktop.org Delivered-To: dri-devel@lists.freedesktop.org Received: from bhuna.collabora.co.uk (bhuna.collabora.co.uk [IPv6:2a00:1098:0:82:1000:25:2eeb:e3e3]) by gabe.freedesktop.org (Postfix) with ESMTPS id 6D2D78959D for ; Wed, 23 Oct 2019 15:45:34 +0000 (UTC) Received: from localhost.localdomain (unknown [IPv6:2a01:e0a:2c:6930:5cf4:84a1:2763:fe0d]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) (Authenticated sender: bbrezillon) by bhuna.collabora.co.uk (Postfix) with ESMTPSA id A6C5928F907; Wed, 23 Oct 2019 16:45:32 +0100 (BST) From: Boris Brezillon To: dri-devel@lists.freedesktop.org Subject: [PATCH v3 18/21] drm/bridge: panel: Propage bus format/flags Date: Wed, 23 Oct 2019 17:45:09 +0200 Message-Id: <20191023154512.9762-19-boris.brezillon@collabora.com> X-Mailer: git-send-email 2.21.0 In-Reply-To: <20191023154512.9762-1-boris.brezillon@collabora.com> References: <20191023154512.9762-1-boris.brezillon@collabora.com> MIME-Version: 1.0 X-BeenThere: dri-devel@lists.freedesktop.org X-Mailman-Version: 2.1.23 Precedence: list List-Id: Direct Rendering Infrastructure - Development List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: Mark Rutland , Neil Armstrong , Thierry Reding , Laurent Pinchart , kernel@collabora.com, Sam Ravnborg , Nikita Yushchenko , Andrey Smirnov , Kyungmin Park , Chris Healy , devicetree@vger.kernel.org, Jonas Karlman , Rob Herring , Jernej Skrabec , Seung-Woo Kim , Boris Brezillon Errors-To: dri-devel-bounces@lists.freedesktop.org Sender: "dri-devel" So that the previous bridge element in the chain knows which input format the panel bridge expects. Signed-off-by: Boris Brezillon --- Changes in v3: * Adjust things to match the new bus-format negotiation approach * Use drm_atomic_helper_bridge_propagate_bus_fmt * Don't implement ->atomic_check() (the core now takes care of bus flags propagation) Changes in v2: * Adjust things to match the new bus-format negotiation approach --- drivers/gpu/drm/bridge/panel.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/gpu/drm/bridge/panel.c b/drivers/gpu/drm/bridge/panel.c index f4e293e7cf64..a70c363a2bd0 100644 --- a/drivers/gpu/drm/bridge/panel.c +++ b/drivers/gpu/drm/bridge/panel.c @@ -127,6 +127,7 @@ static const struct drm_bridge_funcs panel_bridge_bridge_funcs = { .enable = panel_bridge_enable, .disable = panel_bridge_disable, .post_disable = panel_bridge_post_disable, + .atomic_get_input_bus_fmts = drm_atomic_helper_bridge_propagate_bus_fmt, }; /** From patchwork Wed Oct 23 15:45:10 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Boris Brezillon X-Patchwork-Id: 11207109 Return-Path: Received: from mail.kernel.org (pdx-korg-mail-1.web.codeaurora.org [172.30.200.123]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id 47F811390 for ; Wed, 23 Oct 2019 15:45:57 +0000 (UTC) Received: from gabe.freedesktop.org (gabe.freedesktop.org [131.252.210.177]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by mail.kernel.org (Postfix) with ESMTPS id 3087920679 for ; Wed, 23 Oct 2019 15:45:57 +0000 (UTC) DMARC-Filter: OpenDMARC Filter v1.3.2 mail.kernel.org 3087920679 Authentication-Results: mail.kernel.org; dmarc=fail (p=none dis=none) header.from=collabora.com Authentication-Results: mail.kernel.org; spf=none smtp.mailfrom=dri-devel-bounces@lists.freedesktop.org Received: from gabe.freedesktop.org (localhost [127.0.0.1]) by gabe.freedesktop.org (Postfix) with ESMTP id 02C0A6EB26; Wed, 23 Oct 2019 15:45:56 +0000 (UTC) X-Original-To: dri-devel@lists.freedesktop.org Delivered-To: dri-devel@lists.freedesktop.org Received: from bhuna.collabora.co.uk (bhuna.collabora.co.uk [IPv6:2a00:1098:0:82:1000:25:2eeb:e3e3]) by gabe.freedesktop.org (Postfix) with ESMTPS id 374FA8959D for ; Wed, 23 Oct 2019 15:45:35 +0000 (UTC) Received: from localhost.localdomain (unknown [IPv6:2a01:e0a:2c:6930:5cf4:84a1:2763:fe0d]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) (Authenticated sender: bbrezillon) by bhuna.collabora.co.uk (Postfix) with ESMTPSA id 7181C28F90E; Wed, 23 Oct 2019 16:45:33 +0100 (BST) From: Boris Brezillon To: dri-devel@lists.freedesktop.org Subject: [PATCH v3 19/21] drm/panel: simple: Add support for Toshiba LTA089AC29000 panel Date: Wed, 23 Oct 2019 17:45:10 +0200 Message-Id: <20191023154512.9762-20-boris.brezillon@collabora.com> X-Mailer: git-send-email 2.21.0 In-Reply-To: <20191023154512.9762-1-boris.brezillon@collabora.com> References: <20191023154512.9762-1-boris.brezillon@collabora.com> MIME-Version: 1.0 X-BeenThere: dri-devel@lists.freedesktop.org X-Mailman-Version: 2.1.23 Precedence: list List-Id: Direct Rendering Infrastructure - Development List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: Mark Rutland , Neil Armstrong , Thierry Reding , Laurent Pinchart , kernel@collabora.com, Sam Ravnborg , Nikita Yushchenko , Andrey Smirnov , Kyungmin Park , Chris Healy , devicetree@vger.kernel.org, Jonas Karlman , Rob Herring , Jernej Skrabec , Seung-Woo Kim , Boris Brezillon Errors-To: dri-devel-bounces@lists.freedesktop.org Sender: "dri-devel" Add a new entry for the Toshiba LTA089AC29000 panel. Signed-off-by: Boris Brezillon --- Changes in v3: * None --- drivers/gpu/drm/panel/panel-simple.c | 36 ++++++++++++++++++++++++++++ 1 file changed, 36 insertions(+) diff --git a/drivers/gpu/drm/panel/panel-simple.c b/drivers/gpu/drm/panel/panel-simple.c index 5d487686d25c..27c92b44bd95 100644 --- a/drivers/gpu/drm/panel/panel-simple.c +++ b/drivers/gpu/drm/panel/panel-simple.c @@ -2937,6 +2937,39 @@ static const struct panel_desc toshiba_lt089ac29000 = { .connector_type = DRM_MODE_CONNECTOR_LVDS, }; +static const struct drm_display_mode toshiba_lta089ac29000_mode = { + .clock = 79500, + .hdisplay = 1280, + .hsync_start = 1280 + 192, + .hsync_end = 1280 + 192 + 128, + .htotal = 1280 + 192 + 128 + 64, + .vdisplay = 768, + .vsync_start = 768 + 20, + .vsync_end = 768 + 20 + 7, + .vtotal = 768 + 20 + 7 + 3, + .vrefresh = 60, +}; + +static const struct panel_desc toshiba_lta089ac29000 = { + .modes = &toshiba_lta089ac29000_mode, + .num_modes = 1, + .size = { + .width = 194, + .height = 116, + }, + /* + * FIXME: + * The panel supports 2 bus formats: jeida-24 and jeida-18. The + * mode is selected through the 8b6b_SEL pin. If anyone ever needs + * support for jeida-18 we should probably parse the 'data-mapping' + * property. + * In the unlikely event where 8b6b_SEL is connected to a GPIO, we'd + * need a new infra to allow bus format negotiation at the panel level. + */ + .bus_format = MEDIA_BUS_FMT_RGB888_1X7X4_JEIDA, + .bus_flags = DRM_BUS_FLAG_DE_HIGH | DRM_BUS_FLAG_PIXDATA_DRIVE_POSEDGE, +}; + static const struct drm_display_mode tpk_f07a_0102_mode = { .clock = 33260, .hdisplay = 800, @@ -3392,6 +3425,9 @@ static const struct of_device_id platform_of_match[] = { }, { .compatible = "toshiba,lt089ac29000", .data = &toshiba_lt089ac29000, + }, { + .compatible = "toshiba,lta089ac29000", + .data = &toshiba_lta089ac29000, }, { .compatible = "tpk,f07a-0102", .data = &tpk_f07a_0102, From patchwork Wed Oct 23 15:45:11 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Boris Brezillon X-Patchwork-Id: 11207125 Return-Path: Received: from mail.kernel.org (pdx-korg-mail-1.web.codeaurora.org [172.30.200.123]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id 82EF21390 for ; Wed, 23 Oct 2019 15:46:13 +0000 (UTC) Received: from gabe.freedesktop.org (gabe.freedesktop.org [131.252.210.177]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by mail.kernel.org (Postfix) with ESMTPS id 6B8DB20679 for ; Wed, 23 Oct 2019 15:46:13 +0000 (UTC) DMARC-Filter: OpenDMARC Filter v1.3.2 mail.kernel.org 6B8DB20679 Authentication-Results: mail.kernel.org; dmarc=fail (p=none dis=none) header.from=collabora.com Authentication-Results: mail.kernel.org; spf=none smtp.mailfrom=dri-devel-bounces@lists.freedesktop.org Received: from gabe.freedesktop.org (localhost [127.0.0.1]) by gabe.freedesktop.org (Postfix) with ESMTP id 45B446EB23; Wed, 23 Oct 2019 15:46:05 +0000 (UTC) X-Original-To: dri-devel@lists.freedesktop.org Delivered-To: dri-devel@lists.freedesktop.org Received: from bhuna.collabora.co.uk (bhuna.collabora.co.uk [IPv6:2a00:1098:0:82:1000:25:2eeb:e3e3]) by gabe.freedesktop.org (Postfix) with ESMTPS id 649DD6EB1F for ; Wed, 23 Oct 2019 15:45:36 +0000 (UTC) Received: from localhost.localdomain (unknown [IPv6:2a01:e0a:2c:6930:5cf4:84a1:2763:fe0d]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) (Authenticated sender: bbrezillon) by bhuna.collabora.co.uk (Postfix) with ESMTPSA id 3C5CF28F984; Wed, 23 Oct 2019 16:45:34 +0100 (BST) From: Boris Brezillon To: dri-devel@lists.freedesktop.org Subject: [PATCH v3 20/21] dt-bindings: display: panel: Add the LTA089AC29000 variant Date: Wed, 23 Oct 2019 17:45:11 +0200 Message-Id: <20191023154512.9762-21-boris.brezillon@collabora.com> X-Mailer: git-send-email 2.21.0 In-Reply-To: <20191023154512.9762-1-boris.brezillon@collabora.com> References: <20191023154512.9762-1-boris.brezillon@collabora.com> MIME-Version: 1.0 X-BeenThere: dri-devel@lists.freedesktop.org X-Mailman-Version: 2.1.23 Precedence: list List-Id: Direct Rendering Infrastructure - Development List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: Mark Rutland , Neil Armstrong , Thierry Reding , Laurent Pinchart , kernel@collabora.com, Sam Ravnborg , Nikita Yushchenko , Andrey Smirnov , Kyungmin Park , Chris Healy , devicetree@vger.kernel.org, Jonas Karlman , Rob Herring , Jernej Skrabec , Seung-Woo Kim , Boris Brezillon Errors-To: dri-devel-bounces@lists.freedesktop.org Sender: "dri-devel" The LTA089AC29000 and LT089AC29000 are not exactly the same. Let's add a new compatible for the LTA variant. Signed-off-by: Boris Brezillon Acked-by: Rob Herring --- .../bindings/display/panel/toshiba,lt089ac29000.txt | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/Documentation/devicetree/bindings/display/panel/toshiba,lt089ac29000.txt b/Documentation/devicetree/bindings/display/panel/toshiba,lt089ac29000.txt index 89826116628c..26ebfa098966 100644 --- a/Documentation/devicetree/bindings/display/panel/toshiba,lt089ac29000.txt +++ b/Documentation/devicetree/bindings/display/panel/toshiba,lt089ac29000.txt @@ -1,7 +1,10 @@ Toshiba 8.9" WXGA (1280x768) TFT LCD panel Required properties: -- compatible: should be "toshiba,lt089ac29000" +- compatible: should be one of the following + "toshiba,lt089ac29000" + "toshiba,lta089ac29000" + - power-supply: as specified in the base binding This binding is compatible with the simple-panel binding, which is specified From patchwork Wed Oct 23 15:45:12 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Boris Brezillon X-Patchwork-Id: 11207117 Return-Path: Received: from mail.kernel.org (pdx-korg-mail-1.web.codeaurora.org [172.30.200.123]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id 19D5713BD for ; Wed, 23 Oct 2019 15:46:08 +0000 (UTC) Received: from gabe.freedesktop.org (gabe.freedesktop.org [131.252.210.177]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by mail.kernel.org (Postfix) with ESMTPS id 0262F21A4A for ; Wed, 23 Oct 2019 15:46:08 +0000 (UTC) DMARC-Filter: OpenDMARC Filter v1.3.2 mail.kernel.org 0262F21A4A Authentication-Results: mail.kernel.org; dmarc=fail (p=none dis=none) header.from=collabora.com Authentication-Results: mail.kernel.org; spf=none smtp.mailfrom=dri-devel-bounces@lists.freedesktop.org Received: from gabe.freedesktop.org (localhost [127.0.0.1]) by gabe.freedesktop.org (Postfix) with ESMTP id D53166EB2B; Wed, 23 Oct 2019 15:46:04 +0000 (UTC) X-Original-To: dri-devel@lists.freedesktop.org Delivered-To: dri-devel@lists.freedesktop.org Received: from bhuna.collabora.co.uk (bhuna.collabora.co.uk [IPv6:2a00:1098:0:82:1000:25:2eeb:e3e3]) by gabe.freedesktop.org (Postfix) with ESMTPS id 4618B6EB23 for ; Wed, 23 Oct 2019 15:45:37 +0000 (UTC) Received: from localhost.localdomain (unknown [IPv6:2a01:e0a:2c:6930:5cf4:84a1:2763:fe0d]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) (Authenticated sender: bbrezillon) by bhuna.collabora.co.uk (Postfix) with ESMTPSA id 5A6C528F98C; Wed, 23 Oct 2019 16:45:35 +0100 (BST) From: Boris Brezillon To: dri-devel@lists.freedesktop.org Subject: [PATCH v3 21/21] ARM: dts: imx: imx51-zii-rdu1: Fix the display pipeline definition Date: Wed, 23 Oct 2019 17:45:12 +0200 Message-Id: <20191023154512.9762-22-boris.brezillon@collabora.com> X-Mailer: git-send-email 2.21.0 In-Reply-To: <20191023154512.9762-1-boris.brezillon@collabora.com> References: <20191023154512.9762-1-boris.brezillon@collabora.com> MIME-Version: 1.0 X-BeenThere: dri-devel@lists.freedesktop.org X-Mailman-Version: 2.1.23 Precedence: list List-Id: Direct Rendering Infrastructure - Development List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: Mark Rutland , Neil Armstrong , Thierry Reding , Laurent Pinchart , kernel@collabora.com, Sam Ravnborg , Nikita Yushchenko , Andrey Smirnov , Kyungmin Park , Chris Healy , devicetree@vger.kernel.org, Jonas Karlman , Rob Herring , Jernej Skrabec , Seung-Woo Kim , Boris Brezillon Errors-To: dri-devel-bounces@lists.freedesktop.org Sender: "dri-devel" The current definition does not represent the exact display pipeline we have on the board: the LVDS panel is actually connected through a parallel -> LVDS bridge. Let's fix that so the driver can select the proper bus format on the CRTC end. Signed-off-by: Boris Brezillon --- Changes in v3: * None Changes in v2: * None --- arch/arm/boot/dts/imx51-zii-rdu1.dts | 24 +++++++++++++++++++++++- 1 file changed, 23 insertions(+), 1 deletion(-) diff --git a/arch/arm/boot/dts/imx51-zii-rdu1.dts b/arch/arm/boot/dts/imx51-zii-rdu1.dts index 3596060f52e7..3fb84ea7f993 100644 --- a/arch/arm/boot/dts/imx51-zii-rdu1.dts +++ b/arch/arm/boot/dts/imx51-zii-rdu1.dts @@ -95,6 +95,28 @@ reg = <1>; display_out: endpoint { + remote-endpoint = <&lvds_encoder_in>; + }; + }; + }; + + lvds-encoder { + compatible = "lvds-encoder"; + #address-cells = <1>; + #size-cells = <0>; + + port@0 { + reg = <0>; + bus-width = <24>; + lvds_encoder_in: endpoint { + remote-endpoint = <&display_out>; + }; + }; + + port@1 { + reg = <1>; + data-mapping = "jeida-24"; + lvds_encoder_out: endpoint { remote-endpoint = <&panel_in>; }; }; @@ -110,7 +132,7 @@ port { panel_in: endpoint { - remote-endpoint = <&display_out>; + remote-endpoint = <&lvds_encoder_out>; }; }; };