From patchwork Tue Feb 14 00:37:34 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Laurent Pinchart X-Patchwork-Id: 13139222 X-Patchwork-Delegate: kieran@bingham.xyz Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id 745B9C64EC7 for ; Tue, 14 Feb 2023 00:37:43 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S229795AbjBNAhm (ORCPT ); Mon, 13 Feb 2023 19:37:42 -0500 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:48472 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S230045AbjBNAhl (ORCPT ); Mon, 13 Feb 2023 19:37:41 -0500 Received: from perceval.ideasonboard.com (perceval.ideasonboard.com [IPv6:2001:4b98:dc2:55:216:3eff:fef7:d647]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id B754B1A49B for ; Mon, 13 Feb 2023 16:37:40 -0800 (PST) Received: from pendragon.ideasonboard.com (213-243-189-158.bb.dnainternet.fi [213.243.189.158]) by perceval.ideasonboard.com (Postfix) with ESMTPSA id F1E76496; Tue, 14 Feb 2023 01:37:38 +0100 (CET) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com; s=mail; t=1676335059; bh=vV8Poz7KcFFrPKJ+Q0B5tIcg0ixBf9vRYs7KQYoOV0o=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=e5+W+SsSUzMLjVvDRrL4UGU5Fqy3PaRFcRdGklw7zrldgnn5KGH/upNqZk8GE0zdy ryJNITN+tc4qmDdR2jH2+59MN/y9CploqDsYlDMcKJTcQobsGJAdekA8qTvjKW2QOp ONOEhjfmGf5cfVpI59dPEf0sZ/w4GCVkiM9Hx4Wc= From: Laurent Pinchart To: dri-devel@lists.freedesktop.org Cc: linux-renesas-soc@vger.kernel.org, Tomi Valkeinen , Kieran Bingham Subject: [PATCH 1/3] drm: rcar-du: lvds: Call function directly instead of through pointer Date: Tue, 14 Feb 2023 02:37:34 +0200 Message-Id: <20230214003736.18871-2-laurent.pinchart+renesas@ideasonboard.com> X-Mailer: git-send-email 2.39.1 In-Reply-To: <20230214003736.18871-1-laurent.pinchart+renesas@ideasonboard.com> References: <20230214003736.18871-1-laurent.pinchart+renesas@ideasonboard.com> MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: linux-renesas-soc@vger.kernel.org When disabling the companion bridge in rcar_lvds_atomic_disable(), there's no need to go through the bridge's operations to call .atomic_disable(). Call rcar_lvds_atomic_disable() on the companion directly. Signed-off-by: Laurent Pinchart Reviewed-by: Tomi Valkeinen --- drivers/gpu/drm/rcar-du/rcar_lvds.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/drivers/gpu/drm/rcar-du/rcar_lvds.c b/drivers/gpu/drm/rcar-du/rcar_lvds.c index 260ea5d8624e..61de18af62e6 100644 --- a/drivers/gpu/drm/rcar-du/rcar_lvds.c +++ b/drivers/gpu/drm/rcar-du/rcar_lvds.c @@ -582,8 +582,7 @@ static void rcar_lvds_atomic_disable(struct drm_bridge *bridge, /* Disable the companion LVDS encoder in dual-link mode. */ if (lvds->link_type != RCAR_LVDS_SINGLE_LINK && lvds->companion) - lvds->companion->funcs->atomic_disable(lvds->companion, - old_bridge_state); + rcar_lvds_atomic_disable(lvds->companion, old_bridge_state); pm_runtime_put_sync(lvds->dev); } From patchwork Tue Feb 14 00:37:35 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Laurent Pinchart X-Patchwork-Id: 13139223 X-Patchwork-Delegate: kieran@bingham.xyz Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id 8753CC636D4 for ; Tue, 14 Feb 2023 00:37:45 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S230232AbjBNAhp (ORCPT ); Mon, 13 Feb 2023 19:37:45 -0500 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:48486 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S230045AbjBNAho (ORCPT ); Mon, 13 Feb 2023 19:37:44 -0500 Received: from perceval.ideasonboard.com (perceval.ideasonboard.com [213.167.242.64]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 6A8971969E for ; Mon, 13 Feb 2023 16:37:43 -0800 (PST) Received: from pendragon.ideasonboard.com (213-243-189-158.bb.dnainternet.fi [213.243.189.158]) by perceval.ideasonboard.com (Postfix) with ESMTPSA id 851724B0; Tue, 14 Feb 2023 01:37:40 +0100 (CET) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com; s=mail; t=1676335060; bh=XAivNUEMKj0TgP7KLwpSiOdrIr36wyLodmkfAiZ8LLk=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=chxbyluFZ8GofiLFGsuRvDvhkMaWJ7KxhicWgJwCovfIwM/S3hKsXXCV4IBnjAPvc cT0SivlIdIpELMtJBugIdnEaIt1XxTNQtCqu5/ObrUJr2jcfVFihAnP3afYRryI/Be o9jJ9NlDcJUA0UNY6jmPvX78Oz2KmHYhB1uMnDmE= From: Laurent Pinchart To: dri-devel@lists.freedesktop.org Cc: linux-renesas-soc@vger.kernel.org, Tomi Valkeinen , Kieran Bingham Subject: [PATCH 2/3] drm: rcar-du: lvds: Move LVDS enable code to separate code section Date: Tue, 14 Feb 2023 02:37:35 +0200 Message-Id: <20230214003736.18871-3-laurent.pinchart+renesas@ideasonboard.com> X-Mailer: git-send-email 2.39.1 In-Reply-To: <20230214003736.18871-1-laurent.pinchart+renesas@ideasonboard.com> References: <20230214003736.18871-1-laurent.pinchart+renesas@ideasonboard.com> MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: linux-renesas-soc@vger.kernel.org To prepare for a rework of the LVDS disable code, which will need to be called from rcar_lvds_pclk_disable(), move the LVDS enable code, currently stored in the __rcar_lvds_atomic_enable() function, to a separate code section separate from bridge operations. It will be then extended with the LVDS disable code. As part of this rework the __rcar_lvds_atomic_enable() function is renamed to rcar_lvds_enable() to more clearly indicate its purpose. No functional change intended. Signed-off-by: Laurent Pinchart Reviewed-by: Geert Uytterhoeven Reviewed-by: Tomi Valkeinen --- drivers/gpu/drm/rcar-du/rcar_lvds.c | 97 +++++++++++++++-------------- 1 file changed, 50 insertions(+), 47 deletions(-) diff --git a/drivers/gpu/drm/rcar-du/rcar_lvds.c b/drivers/gpu/drm/rcar-du/rcar_lvds.c index 61de18af62e6..70cdd5ec64d5 100644 --- a/drivers/gpu/drm/rcar-du/rcar_lvds.c +++ b/drivers/gpu/drm/rcar-du/rcar_lvds.c @@ -311,46 +311,7 @@ static void rcar_lvds_pll_setup_d3_e3(struct rcar_lvds *lvds, unsigned int freq) } /* ----------------------------------------------------------------------------- - * Clock - D3/E3 only - */ - -int rcar_lvds_pclk_enable(struct drm_bridge *bridge, unsigned long freq) -{ - struct rcar_lvds *lvds = bridge_to_rcar_lvds(bridge); - int ret; - - if (WARN_ON(!(lvds->info->quirks & RCAR_LVDS_QUIRK_EXT_PLL))) - return -ENODEV; - - dev_dbg(lvds->dev, "enabling LVDS PLL, freq=%luHz\n", freq); - - ret = pm_runtime_resume_and_get(lvds->dev); - if (ret) - return ret; - - __rcar_lvds_pll_setup_d3_e3(lvds, freq, true); - - return 0; -} -EXPORT_SYMBOL_GPL(rcar_lvds_pclk_enable); - -void rcar_lvds_pclk_disable(struct drm_bridge *bridge) -{ - struct rcar_lvds *lvds = bridge_to_rcar_lvds(bridge); - - if (WARN_ON(!(lvds->info->quirks & RCAR_LVDS_QUIRK_EXT_PLL))) - return; - - dev_dbg(lvds->dev, "disabling LVDS PLL\n"); - - rcar_lvds_write(lvds, LVDPLLCR, 0); - - pm_runtime_put_sync(lvds->dev); -} -EXPORT_SYMBOL_GPL(rcar_lvds_pclk_disable); - -/* ----------------------------------------------------------------------------- - * Bridge + * Enable/disable */ static enum rcar_lvds_mode rcar_lvds_get_lvds_mode(struct rcar_lvds *lvds, @@ -394,10 +355,10 @@ static enum rcar_lvds_mode rcar_lvds_get_lvds_mode(struct rcar_lvds *lvds, return mode; } -static void __rcar_lvds_atomic_enable(struct drm_bridge *bridge, - struct drm_atomic_state *state, - struct drm_crtc *crtc, - struct drm_connector *connector) +static void rcar_lvds_enable(struct drm_bridge *bridge, + struct drm_atomic_state *state, + struct drm_crtc *crtc, + struct drm_connector *connector) { struct rcar_lvds *lvds = bridge_to_rcar_lvds(bridge); u32 lvdhcr; @@ -410,8 +371,7 @@ static void __rcar_lvds_atomic_enable(struct drm_bridge *bridge, /* Enable the companion LVDS encoder in dual-link mode. */ if (lvds->link_type != RCAR_LVDS_SINGLE_LINK && lvds->companion) - __rcar_lvds_atomic_enable(lvds->companion, state, crtc, - connector); + rcar_lvds_enable(lvds->companion, state, crtc, connector); /* * Hardcode the channels and control signals routing for now. @@ -531,6 +491,49 @@ static void __rcar_lvds_atomic_enable(struct drm_bridge *bridge, rcar_lvds_write(lvds, LVDCR0, lvdcr0); } +/* ----------------------------------------------------------------------------- + * Clock - D3/E3 only + */ + +int rcar_lvds_pclk_enable(struct drm_bridge *bridge, unsigned long freq) +{ + struct rcar_lvds *lvds = bridge_to_rcar_lvds(bridge); + int ret; + + if (WARN_ON(!(lvds->info->quirks & RCAR_LVDS_QUIRK_EXT_PLL))) + return -ENODEV; + + dev_dbg(lvds->dev, "enabling LVDS PLL, freq=%luHz\n", freq); + + ret = pm_runtime_resume_and_get(lvds->dev); + if (ret) + return ret; + + __rcar_lvds_pll_setup_d3_e3(lvds, freq, true); + + return 0; +} +EXPORT_SYMBOL_GPL(rcar_lvds_pclk_enable); + +void rcar_lvds_pclk_disable(struct drm_bridge *bridge) +{ + struct rcar_lvds *lvds = bridge_to_rcar_lvds(bridge); + + if (WARN_ON(!(lvds->info->quirks & RCAR_LVDS_QUIRK_EXT_PLL))) + return; + + dev_dbg(lvds->dev, "disabling LVDS PLL\n"); + + rcar_lvds_write(lvds, LVDPLLCR, 0); + + pm_runtime_put_sync(lvds->dev); +} +EXPORT_SYMBOL_GPL(rcar_lvds_pclk_disable); + +/* ----------------------------------------------------------------------------- + * Bridge + */ + static void rcar_lvds_atomic_enable(struct drm_bridge *bridge, struct drm_bridge_state *old_bridge_state) { @@ -542,7 +545,7 @@ static void rcar_lvds_atomic_enable(struct drm_bridge *bridge, bridge->encoder); crtc = drm_atomic_get_new_connector_state(state, connector)->crtc; - __rcar_lvds_atomic_enable(bridge, state, crtc, connector); + rcar_lvds_enable(bridge, state, crtc, connector); } static void rcar_lvds_atomic_disable(struct drm_bridge *bridge, From patchwork Tue Feb 14 00:37:36 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Laurent Pinchart X-Patchwork-Id: 13139224 X-Patchwork-Delegate: kieran@bingham.xyz Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id 359F5C636CC for ; Tue, 14 Feb 2023 00:37:46 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S230342AbjBNAhp (ORCPT ); Mon, 13 Feb 2023 19:37:45 -0500 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:48488 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S230045AbjBNAhp (ORCPT ); Mon, 13 Feb 2023 19:37:45 -0500 Received: from perceval.ideasonboard.com (perceval.ideasonboard.com [213.167.242.64]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id AD4C31A49B for ; Mon, 13 Feb 2023 16:37:43 -0800 (PST) Received: from pendragon.ideasonboard.com (213-243-189-158.bb.dnainternet.fi [213.243.189.158]) by perceval.ideasonboard.com (Postfix) with ESMTPSA id 194FB3D7; Tue, 14 Feb 2023 01:37:42 +0100 (CET) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com; s=mail; t=1676335062; bh=6P5t4s1EwSRu/HMKbiO2w1pauCdw8QdMPyjpn0A36A8=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=m3HYHoIq8LA11K1UPCAVS8MuerkpMY6DLFmTiNJbDtG0UumWhm+li89lomPljDNvC a7MjzVCfDxURXsQHJEM+WvzSryT1rXq3m+5Lf8mI8oC0uXjlnismyEIez0Kj8vbUkh CEVC8jxkuOeiXR4d5rT0WvmjVxW4elphRU4CrERE= From: Laurent Pinchart To: dri-devel@lists.freedesktop.org Cc: linux-renesas-soc@vger.kernel.org, Tomi Valkeinen , Kieran Bingham Subject: [PATCH 3/3] drm: rcar-du: lvds: Fix LVDS PLL disable on D3/E3 Date: Tue, 14 Feb 2023 02:37:36 +0200 Message-Id: <20230214003736.18871-4-laurent.pinchart+renesas@ideasonboard.com> X-Mailer: git-send-email 2.39.1 In-Reply-To: <20230214003736.18871-1-laurent.pinchart+renesas@ideasonboard.com> References: <20230214003736.18871-1-laurent.pinchart+renesas@ideasonboard.com> MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: linux-renesas-soc@vger.kernel.org On R-Car D3 and E3, the LVDS encoder provides the dot (pixel) clock to the DU, regardless of whether the LVDS output is used or not. When using the DPAD (RGB) output, the DU driver thus enables and disables the LVDS PLL manually, while when using the LVDS output, it lets the LVDS bridge driver handle the PLL configuration internally as part of the atomic enable and disable operations. This causes an issue when using the LVDS output. As bridges are disabled before CRTCs, the current implementation violates the enable/disable sequences documented in the hardware datasheet, which requires the dot clock to be enabled before the CRTC is started and disabled after it gets stopped. Fix the problem by enabling/disabling the LVDS PLL manually from the DU regardless of which output is used, and skipping the PLL handling in the LVDS bridge atomic enable and disable operations. This is however not enough. Disabling the LVDS encoder while leaving the PLL on still results in a vertical blanking wait timeout when disabling the DU. Investigation showed that the culprit is the LVEN bit. For an unclear reason, clearing the bit when disabling the LVDS encoder blocks vertical blanking interrupts. We thus have to delay disabling the whole LVDS encoder, not just disabling the PLL, until the DU is disabled. We could split the LVDS disable sequence by clearing the LVRES bit in the LVDS bridge atomic disable handler, and delaying the rest of the operations, in order to disable the LVDS output at bridge atomic disable time, before stopping the CRTC. This would make the code more complex, without a clear benefit, so keep the implementation simple(r). Signed-off-by: Laurent Pinchart Reviewed-by: Tomi Valkeinen --- drivers/gpu/drm/rcar-du/rcar_du_crtc.c | 18 ++-- drivers/gpu/drm/rcar-du/rcar_lvds.c | 114 +++++++++++++++---------- drivers/gpu/drm/rcar-du/rcar_lvds.h | 12 ++- 3 files changed, 86 insertions(+), 58 deletions(-) diff --git a/drivers/gpu/drm/rcar-du/rcar_du_crtc.c b/drivers/gpu/drm/rcar-du/rcar_du_crtc.c index 008e172ed43b..71e7fbace38d 100644 --- a/drivers/gpu/drm/rcar-du/rcar_du_crtc.c +++ b/drivers/gpu/drm/rcar-du/rcar_du_crtc.c @@ -749,16 +749,17 @@ static void rcar_du_crtc_atomic_enable(struct drm_crtc *crtc, /* * On D3/E3 the dot clock is provided by the LVDS encoder attached to - * the DU channel. We need to enable its clock output explicitly if - * the LVDS output is disabled. + * the DU channel. We need to enable its clock output explicitly before + * starting the CRTC, as the bridge hasn't been enabled by the atomic + * helpers yet. */ - if (rcdu->info->lvds_clk_mask & BIT(rcrtc->index) && - rstate->outputs == BIT(RCAR_DU_OUTPUT_DPAD0)) { + if (rcdu->info->lvds_clk_mask & BIT(rcrtc->index)) { + bool dot_clk_only = rstate->outputs == BIT(RCAR_DU_OUTPUT_DPAD0); struct drm_bridge *bridge = rcdu->lvds[rcrtc->index]; const struct drm_display_mode *mode = &crtc->state->adjusted_mode; - rcar_lvds_pclk_enable(bridge, mode->clock * 1000); + rcar_lvds_pclk_enable(bridge, mode->clock * 1000, dot_clk_only); } /* @@ -795,15 +796,15 @@ static void rcar_du_crtc_atomic_disable(struct drm_crtc *crtc, rcar_du_crtc_stop(rcrtc); rcar_du_crtc_put(rcrtc); - if (rcdu->info->lvds_clk_mask & BIT(rcrtc->index) && - rstate->outputs == BIT(RCAR_DU_OUTPUT_DPAD0)) { + if (rcdu->info->lvds_clk_mask & BIT(rcrtc->index)) { + bool dot_clk_only = rstate->outputs == BIT(RCAR_DU_OUTPUT_DPAD0); struct drm_bridge *bridge = rcdu->lvds[rcrtc->index]; /* * Disable the LVDS clock output, see * rcar_du_crtc_atomic_enable(). */ - rcar_lvds_pclk_disable(bridge); + rcar_lvds_pclk_disable(bridge, dot_clk_only); } if ((rcdu->info->dsi_clk_mask & BIT(rcrtc->index)) && @@ -815,7 +816,6 @@ static void rcar_du_crtc_atomic_disable(struct drm_crtc *crtc, * Disable the DSI clock output, see * rcar_du_crtc_atomic_enable(). */ - rcar_mipi_dsi_pclk_disable(bridge); } diff --git a/drivers/gpu/drm/rcar-du/rcar_lvds.c b/drivers/gpu/drm/rcar-du/rcar_lvds.c index 70cdd5ec64d5..ca215b588fd7 100644 --- a/drivers/gpu/drm/rcar-du/rcar_lvds.c +++ b/drivers/gpu/drm/rcar-du/rcar_lvds.c @@ -269,8 +269,8 @@ static void rcar_lvds_d3_e3_pll_calc(struct rcar_lvds *lvds, struct clk *clk, pll->pll_m, pll->pll_n, pll->pll_e, pll->div); } -static void __rcar_lvds_pll_setup_d3_e3(struct rcar_lvds *lvds, - unsigned int freq, bool dot_clock_only) +static void rcar_lvds_pll_setup_d3_e3(struct rcar_lvds *lvds, + unsigned int freq, bool dot_clock_only) { struct pll_info pll = { .diff = (unsigned long)-1 }; u32 lvdpllcr; @@ -305,11 +305,6 @@ static void __rcar_lvds_pll_setup_d3_e3(struct rcar_lvds *lvds, rcar_lvds_write(lvds, LVDDIV, 0); } -static void rcar_lvds_pll_setup_d3_e3(struct rcar_lvds *lvds, unsigned int freq) -{ - __rcar_lvds_pll_setup_d3_e3(lvds, freq, false); -} - /* ----------------------------------------------------------------------------- * Enable/disable */ @@ -425,8 +420,12 @@ static void rcar_lvds_enable(struct drm_bridge *bridge, /* * PLL clock configuration on all instances but the companion in * dual-link mode. + * + * The extended PLL has been turned on by an explicit call to + * rcar_lvds_pclk_enable() from the DU driver. */ - if (lvds->link_type == RCAR_LVDS_SINGLE_LINK || lvds->companion) { + if ((lvds->link_type == RCAR_LVDS_SINGLE_LINK || lvds->companion) && + !(lvds->info->quirks & RCAR_LVDS_QUIRK_EXT_PLL)) { const struct drm_crtc_state *crtc_state = drm_atomic_get_new_crtc_state(state, crtc); const struct drm_display_mode *mode = @@ -491,11 +490,56 @@ static void rcar_lvds_enable(struct drm_bridge *bridge, rcar_lvds_write(lvds, LVDCR0, lvdcr0); } +static void rcar_lvds_disable(struct drm_bridge *bridge) +{ + struct rcar_lvds *lvds = bridge_to_rcar_lvds(bridge); + u32 lvdcr0; + + /* + * Clear the LVDCR0 bits in the order specified by the hardware + * documentation, ending with a write of 0 to the full register to + * clear all remaining bits. + */ + lvdcr0 = rcar_lvds_read(lvds, LVDCR0); + + lvdcr0 &= ~LVDCR0_LVRES; + rcar_lvds_write(lvds, LVDCR0, lvdcr0); + + if (lvds->info->quirks & RCAR_LVDS_QUIRK_GEN3_LVEN) { + lvdcr0 &= ~LVDCR0_LVEN; + rcar_lvds_write(lvds, LVDCR0, lvdcr0); + } + + if (lvds->info->quirks & RCAR_LVDS_QUIRK_PWD) { + lvdcr0 &= ~LVDCR0_PWD; + rcar_lvds_write(lvds, LVDCR0, lvdcr0); + } + + if (!(lvds->info->quirks & RCAR_LVDS_QUIRK_EXT_PLL)) { + lvdcr0 &= ~LVDCR0_PLLON; + rcar_lvds_write(lvds, LVDCR0, lvdcr0); + } + + rcar_lvds_write(lvds, LVDCR0, 0); + rcar_lvds_write(lvds, LVDCR1, 0); + + /* The extended PLL is turned off in rcar_lvds_pclk_disable(). */ + if (!(lvds->info->quirks & RCAR_LVDS_QUIRK_EXT_PLL)) + rcar_lvds_write(lvds, LVDPLLCR, 0); + + /* Disable the companion LVDS encoder in dual-link mode. */ + if (lvds->link_type != RCAR_LVDS_SINGLE_LINK && lvds->companion) + rcar_lvds_disable(lvds->companion); + + pm_runtime_put_sync(lvds->dev); +} + /* ----------------------------------------------------------------------------- * Clock - D3/E3 only */ -int rcar_lvds_pclk_enable(struct drm_bridge *bridge, unsigned long freq) +int rcar_lvds_pclk_enable(struct drm_bridge *bridge, unsigned long freq, + bool dot_clk_only) { struct rcar_lvds *lvds = bridge_to_rcar_lvds(bridge); int ret; @@ -509,13 +553,13 @@ int rcar_lvds_pclk_enable(struct drm_bridge *bridge, unsigned long freq) if (ret) return ret; - __rcar_lvds_pll_setup_d3_e3(lvds, freq, true); + rcar_lvds_pll_setup_d3_e3(lvds, freq, dot_clk_only); return 0; } EXPORT_SYMBOL_GPL(rcar_lvds_pclk_enable); -void rcar_lvds_pclk_disable(struct drm_bridge *bridge) +void rcar_lvds_pclk_disable(struct drm_bridge *bridge, bool dot_clk_only) { struct rcar_lvds *lvds = bridge_to_rcar_lvds(bridge); @@ -524,6 +568,9 @@ void rcar_lvds_pclk_disable(struct drm_bridge *bridge) dev_dbg(lvds->dev, "disabling LVDS PLL\n"); + if (!dot_clk_only) + rcar_lvds_disable(bridge); + rcar_lvds_write(lvds, LVDPLLCR, 0); pm_runtime_put_sync(lvds->dev); @@ -552,42 +599,21 @@ static void rcar_lvds_atomic_disable(struct drm_bridge *bridge, struct drm_bridge_state *old_bridge_state) { struct rcar_lvds *lvds = bridge_to_rcar_lvds(bridge); - u32 lvdcr0; /* - * Clear the LVDCR0 bits in the order specified by the hardware - * documentation, ending with a write of 0 to the full register to - * clear all remaining bits. + * For D3 and E3, disabling the LVDS encoder before the DU would stall + * the DU, causing a vblank wait timeout when stopping the DU. This has + * been traced to clearing the LVEN bit, but the exact reason is + * unknown. Keep the encoder enabled, it will be disabled by an explicit + * call to rcar_lvds_pclk_disable() from the DU driver. + * + * We could clear the LVRES bit already to disable the LVDS output, but + * that's likely pointless. */ - lvdcr0 = rcar_lvds_read(lvds, LVDCR0); + if (lvds->info->quirks & RCAR_LVDS_QUIRK_EXT_PLL) + return; - lvdcr0 &= ~LVDCR0_LVRES; - rcar_lvds_write(lvds, LVDCR0, lvdcr0); - - if (lvds->info->quirks & RCAR_LVDS_QUIRK_GEN3_LVEN) { - lvdcr0 &= ~LVDCR0_LVEN; - rcar_lvds_write(lvds, LVDCR0, lvdcr0); - } - - if (lvds->info->quirks & RCAR_LVDS_QUIRK_PWD) { - lvdcr0 &= ~LVDCR0_PWD; - rcar_lvds_write(lvds, LVDCR0, lvdcr0); - } - - if (!(lvds->info->quirks & RCAR_LVDS_QUIRK_EXT_PLL)) { - lvdcr0 &= ~LVDCR0_PLLON; - rcar_lvds_write(lvds, LVDCR0, lvdcr0); - } - - rcar_lvds_write(lvds, LVDCR0, 0); - rcar_lvds_write(lvds, LVDCR1, 0); - rcar_lvds_write(lvds, LVDPLLCR, 0); - - /* Disable the companion LVDS encoder in dual-link mode. */ - if (lvds->link_type != RCAR_LVDS_SINGLE_LINK && lvds->companion) - rcar_lvds_atomic_disable(lvds->companion, old_bridge_state); - - pm_runtime_put_sync(lvds->dev); + rcar_lvds_disable(bridge); } static bool rcar_lvds_mode_fixup(struct drm_bridge *bridge, @@ -924,14 +950,12 @@ static const struct rcar_lvds_device_info rcar_lvds_r8a77990_info = { .gen = 3, .quirks = RCAR_LVDS_QUIRK_GEN3_LVEN | RCAR_LVDS_QUIRK_EXT_PLL | RCAR_LVDS_QUIRK_DUAL_LINK, - .pll_setup = rcar_lvds_pll_setup_d3_e3, }; static const struct rcar_lvds_device_info rcar_lvds_r8a77995_info = { .gen = 3, .quirks = RCAR_LVDS_QUIRK_GEN3_LVEN | RCAR_LVDS_QUIRK_PWD | RCAR_LVDS_QUIRK_EXT_PLL | RCAR_LVDS_QUIRK_DUAL_LINK, - .pll_setup = rcar_lvds_pll_setup_d3_e3, }; static const struct of_device_id rcar_lvds_of_table[] = { diff --git a/drivers/gpu/drm/rcar-du/rcar_lvds.h b/drivers/gpu/drm/rcar-du/rcar_lvds.h index bee7033b60d6..887c63500000 100644 --- a/drivers/gpu/drm/rcar-du/rcar_lvds.h +++ b/drivers/gpu/drm/rcar-du/rcar_lvds.h @@ -13,17 +13,21 @@ struct drm_bridge; #if IS_ENABLED(CONFIG_DRM_RCAR_LVDS) -int rcar_lvds_pclk_enable(struct drm_bridge *bridge, unsigned long freq); -void rcar_lvds_pclk_disable(struct drm_bridge *bridge); +int rcar_lvds_pclk_enable(struct drm_bridge *bridge, unsigned long freq, + bool dot_clk_only); +void rcar_lvds_pclk_disable(struct drm_bridge *bridge, bool dot_clk_only); bool rcar_lvds_dual_link(struct drm_bridge *bridge); bool rcar_lvds_is_connected(struct drm_bridge *bridge); #else static inline int rcar_lvds_pclk_enable(struct drm_bridge *bridge, - unsigned long freq) + unsigned long freq, bool dot_clk_only) { return -ENOSYS; } -static inline void rcar_lvds_pclk_disable(struct drm_bridge *bridge) { } +static inline void rcar_lvds_pclk_disable(struct drm_bridge *bridge, + bool dot_clock_only) +{ +} static inline bool rcar_lvds_dual_link(struct drm_bridge *bridge) { return false;