From patchwork Tue Nov 26 15:45:54 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Nikolaus Voss X-Patchwork-Id: 13886725 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 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 smtp.lore.kernel.org (Postfix) with ESMTPS id 35299D609BC for ; Wed, 27 Nov 2024 09:01:58 +0000 (UTC) Received: from gabe.freedesktop.org (localhost [127.0.0.1]) by gabe.freedesktop.org (Postfix) with ESMTP id C04E610EA4C; Wed, 27 Nov 2024 09:01:49 +0000 (UTC) X-Greylist: delayed 362 seconds by postgrey-1.36 at gabe; Tue, 26 Nov 2024 17:32:21 UTC Received: from mail.steuer-voss.de (mail.steuer-voss.de [85.183.69.95]) by gabe.freedesktop.org (Postfix) with ESMTPS id B25F510E96B for ; Tue, 26 Nov 2024 17:32:21 +0000 (UTC) X-Virus-Scanned: Debian amavisd-new at mail.steuer-voss.de Received: by mail.steuer-voss.de (Postfix, from userid 1000) id AD8B51622C; Tue, 26 Nov 2024 18:26:10 +0100 (CET) From: Nikolaus Voss Date: Tue, 26 Nov 2024 16:45:54 +0100 Subject: [PATCH] drm: bridge: fsl-ldb: fixup mode on freq mismatch To: Alexander Stein , Liu Ying , Luca Ceresoli , Fabio Estevam , Marek Vasut , Andrzej Hajda , Neil Armstrong , Robert Foss , Laurent Pinchart , Jonas Karlman , Jernej Skrabec , David Airlie , Daniel Vetter Cc: dri-devel@lists.freedesktop.org, linux-kernel@vger.kernel.org, nikolaus.voss@haag-streit.com Message-Id: <20241126172610.AD8B51622C@mail.steuer-voss.de> X-Mailman-Approved-At: Wed, 27 Nov 2024 09:01:48 +0000 X-BeenThere: dri-devel@lists.freedesktop.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: Direct Rendering Infrastructure - Development List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: dri-devel-bounces@lists.freedesktop.org Sender: "dri-devel" LDB clock has to be a fixed multiple of the pixel clock. As LDB and pixel clock are derived from different clock sources (at least on imx8mp), this constraint cannot be satisfied for any pixel clock, which leads to flickering and incomplete lines on the attached display. To overcome this, check this condition in mode_fixup() and adapt the pixel clock accordingly. Cc: Signed-off-by: Nikolaus Voss --- drivers/gpu/drm/bridge/fsl-ldb.c | 40 ++++++++++++++++++++++++++++---- 1 file changed, 36 insertions(+), 4 deletions(-) diff --git a/drivers/gpu/drm/bridge/fsl-ldb.c b/drivers/gpu/drm/bridge/fsl-ldb.c index 0e4bac7dd04ff..e341341b8c600 100644 --- a/drivers/gpu/drm/bridge/fsl-ldb.c +++ b/drivers/gpu/drm/bridge/fsl-ldb.c @@ -104,12 +104,14 @@ static inline struct fsl_ldb *to_fsl_ldb(struct drm_bridge *bridge) return container_of(bridge, struct fsl_ldb, bridge); } +static unsigned int fsl_ldb_link_freq_factor(const struct fsl_ldb *fsl_ldb) +{ + return fsl_ldb_is_dual(fsl_ldb) ? 3500 : 7000; +} + static unsigned long fsl_ldb_link_frequency(struct fsl_ldb *fsl_ldb, int clock) { - if (fsl_ldb_is_dual(fsl_ldb)) - return clock * 3500; - else - return clock * 7000; + return clock * fsl_ldb_link_freq_factor(fsl_ldb); } static int fsl_ldb_attach(struct drm_bridge *bridge, @@ -121,6 +123,35 @@ static int fsl_ldb_attach(struct drm_bridge *bridge, bridge, flags); } +static bool fsl_ldb_mode_fixup(struct drm_bridge *bridge, + const struct drm_display_mode *mode, + struct drm_display_mode *adjusted_mode) +{ + const struct fsl_ldb *fsl_ldb = to_fsl_ldb(bridge); + unsigned long requested_link_freq = + mode->clock * fsl_ldb_link_freq_factor(fsl_ldb); + unsigned long freq = clk_round_rate(fsl_ldb->clk, requested_link_freq); + + if (freq != requested_link_freq) { + /* + * this will lead to flicker and incomplete lines on + * the attached display, adjust the CRTC clock + * accordingly. + */ + int pclk = freq / fsl_ldb_link_freq_factor(fsl_ldb); + + if (adjusted_mode->clock != pclk) { + dev_warn(fsl_ldb->dev, "Adjusted pixel clk to match LDB clk (%d kHz -> %d kHz)!\n", + adjusted_mode->clock, pclk); + + adjusted_mode->clock = pclk; + adjusted_mode->crtc_clock = pclk; + } + } + + return true; +} + static void fsl_ldb_atomic_enable(struct drm_bridge *bridge, struct drm_bridge_state *old_bridge_state) { @@ -280,6 +311,7 @@ fsl_ldb_mode_valid(struct drm_bridge *bridge, static const struct drm_bridge_funcs funcs = { .attach = fsl_ldb_attach, + .mode_fixup = fsl_ldb_mode_fixup, .atomic_enable = fsl_ldb_atomic_enable, .atomic_disable = fsl_ldb_atomic_disable, .atomic_duplicate_state = drm_atomic_helper_bridge_duplicate_state,