From patchwork Mon Aug 20 21:49:41 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Laurent Pinchart X-Patchwork-Id: 10570817 X-Patchwork-Delegate: geert@linux-m68k.org Return-Path: Received: from mail.wl.linuxfoundation.org (pdx-wl-mail.web.codeaurora.org [172.30.200.125]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id C1F66109C for ; Mon, 20 Aug 2018 21:48:52 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id A555D297AD for ; Mon, 20 Aug 2018 21:48:52 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id 99024297C4; Mon, 20 Aug 2018 21:48:52 +0000 (UTC) X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on pdx-wl-mail.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-8.0 required=2.0 tests=BAYES_00,DKIM_SIGNED, DKIM_VALID,DKIM_VALID_AU,MAILING_LIST_MULTI,RCVD_IN_DNSWL_HI autolearn=ham version=3.3.1 Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 26215297AD for ; Mon, 20 Aug 2018 21:48:52 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1726498AbeHUBGK (ORCPT ); Mon, 20 Aug 2018 21:06:10 -0400 Received: from perceval.ideasonboard.com ([213.167.242.64]:47844 "EHLO perceval.ideasonboard.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1726461AbeHUBGK (ORCPT ); Mon, 20 Aug 2018 21:06:10 -0400 Received: from avalon.bb.dnainternet.fi (dfj612ybrt5fhg77mgycy-3.rev.dnainternet.fi [IPv6:2001:14ba:21f5:5b00:2e86:4862:ef6a:2804]) by perceval.ideasonboard.com (Postfix) with ESMTPSA id 711441BF0; Mon, 20 Aug 2018 23:48:49 +0200 (CEST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com; s=mail; t=1534801729; bh=bT6wwDeeeXUcxMl+7a4/JDRyEANBgEfK6V22dqsjv/I=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=HecMitL8eW8dS33kmrseIG6ybL1K8jSZqp4gcngaFQeApqsQ825H0m3h7omoy7YKz aoTpdii8XG1g8iycRykRUhvKa1lNMvkc80tM39NEMngdN42LGfMp8n3sPclPm0TsWg mXhyqa3vHyXCnQgv/dr24Xb6vgQ8O8ozRSEGd3LQ= From: Laurent Pinchart To: dri-devel@lists.freedesktop.org Cc: linux-renesas-soc@vger.kernel.org, Jacopo Mondi , Ulrich Hecht Subject: [PATCH] drm: rcar-du: Improve non-DPLL clock selection Date: Tue, 21 Aug 2018 00:49:41 +0300 Message-Id: <20180820214941.22236-1-laurent.pinchart+renesas@ideasonboard.com> X-Mailer: git-send-email 2.16.4 In-Reply-To: <2548120.ZfZBKIsRRX@avalon> References: <2548120.ZfZBKIsRRX@avalon> Sender: linux-renesas-soc-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-renesas-soc@vger.kernel.org X-Virus-Scanned: ClamAV using ClamSMTP From: Jacopo Mondi DU channels not equipped with a DPLL use an SoC internal (provided by the CPG) or external clock source combined with a DU internal divider to generate the desired output dot clock frequency. The current clock selection procedure does not fully exploit the ability of external clock sources to generate the exact dot clock frequency by themselves, but relies instead on tuning the internal DU clock divider only, resulting in a less precise clock generation process. When possible, and desirable, ask the external clock source for the exact output dot clock frequency, and select the clock source that produces the frequency closest to the desired output dot clock. This patch specifically targets platforms (like Salvator-X[S] and ULCBs) where the DU's input dotclock.in is generated by the versaclock VC5 clock source, which is capable of generating the exact rate the DU needs as pixel clock output. This patch fixes higher resolution modes which requires an high pixel clock output currently not working on non-HDMI DU channel (such as 1920x1080@60Hz on the VGA output). Fixes: 1b30dbde8596 ("drm: rcar-du: Add support for external pixel clock") Signed-off-by: Jacopo Mondi [Factor out code to a helper function] Signed-off-by: Laurent Pinchart Acked-by: Jacopo Mondi --- drivers/gpu/drm/rcar-du/rcar_du_crtc.c | 86 ++++++++++++++++++++++------------ 1 file changed, 55 insertions(+), 31 deletions(-) diff --git a/drivers/gpu/drm/rcar-du/rcar_du_crtc.c b/drivers/gpu/drm/rcar-du/rcar_du_crtc.c index f8068170905a..2c9405458bbf 100644 --- a/drivers/gpu/drm/rcar-du/rcar_du_crtc.c +++ b/drivers/gpu/drm/rcar-du/rcar_du_crtc.c @@ -165,6 +165,48 @@ static void rcar_du_dpll_divider(struct rcar_du_crtc *rcrtc, best_diff); } +struct du_clk_params { + struct clk *clk; + unsigned long rate; + unsigned long diff; + u32 escr; +}; + +static void rcar_du_escr_divider(struct rcar_du_crtc *rcrtc, struct clk *clk, + unsigned long target, u32 escr, + struct du_clk_params *params) +{ + unsigned long rate; + unsigned long diff; + u32 div; + + /* + * If the target rate has already been achieved perfectly we can't do + * better. + */ + if (params->diff == 0) + return; + + /* + * Compute the input clock rate and internal divisor values to obtain + * the clock rate closest to the target frequency. + */ + rate = clk_round_rate(clk, target); + div = clamp(DIV_ROUND_CLOSEST(rate, target), 1UL, 64UL) - 1; + diff = abs(rate / (div + 1) - target); + + /* + * If the resulting frequency is better than any previously obtained, + * store the parameters. + */ + if (diff < params->diff) { + params->clk = clk; + params->rate = rate; + params->diff = diff; + params->escr = escr | div; + } +} + static const struct soc_device_attribute rcar_du_r8a7795_es1[] = { { .soc_id = "r8a7795", .revision = "ES1.*" }, { /* sentinel */ } @@ -225,42 +267,24 @@ static void rcar_du_crtc_set_display_timing(struct rcar_du_crtc *rcrtc) escr = ESCR_DCLKSEL_DCLKIN | div; } else { - unsigned long clk; - u32 div; - - /* - * Compute the clock divisor and select the internal or external - * dot clock based on the requested frequency. - */ - clk = clk_get_rate(rcrtc->clock); - div = DIV_ROUND_CLOSEST(clk, mode_clock); - div = clamp(div, 1U, 64U) - 1; - - escr = ESCR_DCLKSEL_CLKS | div; - - if (rcrtc->extclock) { - unsigned long extclk; - unsigned long extrate; - unsigned long rate; - u32 extdiv; + struct du_clk_params params = { .diff = (unsigned long)-1 }; - extclk = clk_get_rate(rcrtc->extclock); - extdiv = DIV_ROUND_CLOSEST(extclk, mode_clock); - extdiv = clamp(extdiv, 1U, 64U) - 1; + rcar_du_escr_divider(rcrtc, rcrtc->clock, mode_clock, + ESCR_DCLKSEL_CLKS, ¶ms); + if (rcrtc->extclock) + rcar_du_escr_divider(rcrtc, rcrtc->extclock, mode_clock, + ESCR_DCLKSEL_DCLKIN, ¶ms); - extrate = extclk / (extdiv + 1); - rate = clk / (div + 1); + dev_dbg(rcrtc->group->dev->dev, "mode clock %lu %s rate %lu\n", + mode_clock, params.clk == rcrtc->clock ? "cpg" : "ext", + params.rate); - if (abs((long)extrate - (long)mode_clock) < - abs((long)rate - (long)mode_clock)) - escr = ESCR_DCLKSEL_DCLKIN | extdiv; - - dev_dbg(rcrtc->group->dev->dev, - "mode clock %lu extrate %lu rate %lu ESCR 0x%08x\n", - mode_clock, extrate, rate, escr); - } + clk_set_rate(params.clk, params.rate); + escr = params.escr; } + dev_dbg(rcrtc->group->dev->dev, "%s: ESCR 0x%08x\n", __func__, escr); + rcar_du_group_write(rcrtc->group, rcrtc->index % 2 ? ESCR2 : ESCR, escr); rcar_du_group_write(rcrtc->group, rcrtc->index % 2 ? OTAR2 : OTAR, 0);