From patchwork Thu Dec 8 09:56:59 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Geert Uytterhoeven X-Patchwork-Id: 13068387 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 bombadil.infradead.org (bombadil.infradead.org [198.137.202.133]) (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 AEEE5C3A5A7 for ; Thu, 8 Dec 2022 13:09:34 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=lists.infradead.org; s=bombadil.20210309; h=Sender: Content-Transfer-Encoding:Content-Type:List-Subscribe:List-Help:List-Post: List-Archive:List-Unsubscribe:List-Id:MIME-Version:References:In-Reply-To: Message-Id:Date:Subject:Cc:To:From:Reply-To:Content-ID:Content-Description: Resent-Date:Resent-From:Resent-Sender:Resent-To:Resent-Cc:Resent-Message-ID: List-Owner; bh=ruMTjYOBUrlgJtU79OPKwUsiD1/b7W7AWLuRRE+perE=; b=lZ1wJwAl2VlneD AHuDRphIj9rCHASWpVJSJc/JssyLstontTTGUJCHC7TqMUwGABn6VgzdR9OPRvEqNRC0QHSZkfJYu DY/wPuY4aD6Qf2z5IJvOiFj/GVbPhQY+/9CWiugu24uaforgA7wrRQzY2pHLQZN2mgTGDfc2E7ZW8 CnT0my91s/a3tnBJP55yUc5pYnnPwM8XThMHwWd0IQ4VgzC48cYumY5LPMT13qRBsYJdpp6BRdT6Z F4be+4IsoRaSpOC+K2fKhn5DDYBzV52RA6aL+zbVl8z01of5FO9qzynUAKaLXG+zQDQ/bMJxKA2SN j6Lxx7i3ITKTDofGoh1w==; Received: from localhost ([::1] helo=bombadil.infradead.org) by bombadil.infradead.org with esmtp (Exim 4.94.2 #2 (Red Hat Linux)) id 1p3GdZ-000LZi-QP; Thu, 08 Dec 2022 13:08:29 +0000 Received: from laurent.telenet-ops.be ([2a02:1800:110:4::f00:19]) by bombadil.infradead.org with esmtps (Exim 4.94.2 #2 (Red Hat Linux)) id 1p3Gd0-000Kfi-MK for linux-arm-kernel@lists.infradead.org; Thu, 08 Dec 2022 13:07:58 +0000 Received: from ramsan.of.borg ([IPv6:2a02:1810:ac12:ed20:5574:4fdf:a801:888e]) by laurent.telenet-ops.be with bizsmtp id tp7n280032deJRf01p7nsB; Thu, 08 Dec 2022 14:07:47 +0100 Received: from rox.of.borg ([192.168.97.57]) by ramsan.of.borg with esmtps (TLS1.3) tls TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 (Exim 4.93) (envelope-from ) id 1p3GIF-002tBF-JX; Thu, 08 Dec 2022 13:46:27 +0100 Received: from geert by rox.of.borg with local (Exim 4.93) (envelope-from ) id 1p3DeN-002fn0-4a; Thu, 08 Dec 2022 10:57:07 +0100 From: Geert Uytterhoeven To: Magnus Damm , Michael Turquette , Stephen Boyd Cc: Tho Vu , linux-renesas-soc@vger.kernel.org, linux-clk@vger.kernel.org, linux-arm-kernel@lists.infradead.org, Geert Uytterhoeven Subject: [PATCH 2/3] clk: renesas: rcar-gen4: Add support for fractional multiplication Date: Thu, 8 Dec 2022 10:56:59 +0100 Message-Id: X-Mailer: git-send-email 2.25.1 In-Reply-To: References: MIME-Version: 1.0 X-CRM114-Version: 20100106-BlameMichelson ( TRE 0.8.0 (BSD) ) MR-646709E3 X-CRM114-CacheID: sfid-20221208_050754_944524_8AD45A02 X-CRM114-Status: GOOD ( 19.22 ) X-BeenThere: linux-arm-kernel@lists.infradead.org X-Mailman-Version: 2.1.34 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Sender: "linux-arm-kernel" Errors-To: linux-arm-kernel-bounces+linux-arm-kernel=archiver.kernel.org@lists.infradead.org R-Car Gen4 PLLs support fractional multiplication, which can improve accuracy when configuring a specific frequency. Add support for fractional multiplication to the custom clock driver for PLLs, which is currently used only for PLL2 on R-Car V4H. Signed-off-by: Geert Uytterhoeven --- I am not so sure it is worth supporting this. On R-Car V4H, the following clock rates are seen for PLL2 and the Cortex-A76 CPU core clock, when using the Normal vs. the High-Performance mode: Multiplication Mode Integer Frational ---------- ---------- Normal (1.7 GHz): PLL2 3399999864 3399999997 Z0 1699999932 1699999999 High-Performance (1.8 GHz): PLL2 3599999856 3599999997 Z0 1799999928 1799999999 The improvement is of a similar order of magnitude as the accuracy of the external crystal, hence insignificant... With the current implementation, fractional multiplication does not have any impact on lower performance points, as those rely on changing the Z0 divider (which supports 32 steps only), instead of changing the PLL. --- drivers/clk/renesas/rcar-gen4-cpg.c | 69 ++++++++++++++++++++++------- 1 file changed, 54 insertions(+), 15 deletions(-) diff --git a/drivers/clk/renesas/rcar-gen4-cpg.c b/drivers/clk/renesas/rcar-gen4-cpg.c index c68d8b987054131b..54dc3aa82b499725 100644 --- a/drivers/clk/renesas/rcar-gen4-cpg.c +++ b/drivers/clk/renesas/rcar-gen4-cpg.c @@ -57,10 +57,13 @@ static u32 cpg_mode __initdata; #define SSMODE_DITHER BIT(1) /* Frequency Dithering */ #define SSMODE_CENTER BIT(0) /* Center (vs. Down) Spread Dithering */ +#define CPG_PLLxCR1_NF GENMASK(24, 0) /* Fractional mult. factor */ + /* PLL Clocks */ struct cpg_pll_clk { struct clk_hw hw; void __iomem *pllcr0_reg; + void __iomem *pllcr1_reg; void __iomem *pllecr_reg; u32 pllecr_pllst_mask; }; @@ -71,17 +74,26 @@ static unsigned long cpg_pll_clk_recalc_rate(struct clk_hw *hw, unsigned long parent_rate) { struct cpg_pll_clk *pll_clk = to_pll_clk(hw); - unsigned int mult; - - mult = FIELD_GET(CPG_PLLxCR0_NI, readl(pll_clk->pllcr0_reg)) + 1; + u32 cr0 = readl(pll_clk->pllcr0_reg); + unsigned int ni, nf; + unsigned long rate; + + ni = (FIELD_GET(CPG_PLLxCR0_NI, cr0) + 1) * 2; + rate = parent_rate * ni; + if (cr0 & CPG_PLLxCR0_SSMODE_FM) { + nf = FIELD_GET(CPG_PLLxCR1_NF, readl(pll_clk->pllcr1_reg)); + rate += ((u64)parent_rate * nf) >> 24; + } - return parent_rate * mult * 2; + return rate; } static int cpg_pll_clk_determine_rate(struct clk_hw *hw, struct clk_rate_request *req) { - unsigned int min_mult, max_mult, mult; + struct cpg_pll_clk *pll_clk = to_pll_clk(hw); + unsigned int min_mult, max_mult, ni, nf; + u32 cr0 = readl(pll_clk->pllcr0_reg); unsigned long prate; prate = req->best_parent_rate * 2; @@ -90,10 +102,23 @@ static int cpg_pll_clk_determine_rate(struct clk_hw *hw, if (max_mult < min_mult) return -EINVAL; - mult = DIV_ROUND_CLOSEST_ULL(req->rate, prate); - mult = clamp(mult, min_mult, max_mult); + if (cr0 & CPG_PLLxCR0_SSMODE_FM) { + ni = div64_ul(req->rate, prate); + if (ni < min_mult) { + ni = min_mult; + nf = 0; + } else { + ni = min(ni, max_mult); + nf = ((u64)(req->rate - prate * ni) << 24) / + req->best_parent_rate; + } + } else { + ni = DIV_ROUND_CLOSEST_ULL(req->rate, prate); + ni = clamp(ni, min_mult, max_mult); + nf = 0; + } + req->rate = prate * ni + (((u64)req->best_parent_rate * nf) >> 24); - req->rate = prate * mult; return 0; } @@ -101,17 +126,31 @@ static int cpg_pll_clk_set_rate(struct clk_hw *hw, unsigned long rate, unsigned long parent_rate) { struct cpg_pll_clk *pll_clk = to_pll_clk(hw); - unsigned int mult; + unsigned long prate = parent_rate * 2; + u32 cr0 = readl(pll_clk->pllcr0_reg); + unsigned int ni, nf; + int error; u32 val; - mult = DIV_ROUND_CLOSEST_ULL(rate, parent_rate * 2); - mult = clamp(mult, 1U, 256U); + if (cr0 & CPG_PLLxCR0_SSMODE_FM) { + ni = div64_ul(rate, prate); + if (ni < 1) { + ni = 1; + nf = 0; + } else { + ni = min(ni, 256U); + nf = ((u64)(rate - prate * ni) << 24) / parent_rate; + } + } else { + ni = DIV_ROUND_CLOSEST_ULL(rate, prate); + ni = clamp(ni, 1U, 256U); + } if (readl(pll_clk->pllcr0_reg) & CPG_PLLxCR0_KICK) return -EBUSY; cpg_reg_modify(pll_clk->pllcr0_reg, CPG_PLLxCR0_NI, - FIELD_PREP(CPG_PLLxCR0_NI, mult - 1)); + FIELD_PREP(CPG_PLLxCR0_NI, ni - 1)); /* * Set KICK bit in PLLxCR0 to update hardware setting and wait for @@ -161,12 +200,12 @@ static struct clk * __init cpg_pll_clk_register(const char *name, pll_clk->hw.init = &init; pll_clk->pllcr0_reg = base + cr0_offset; + pll_clk->pllcr1_reg = base + cr1_offset; pll_clk->pllecr_reg = base + CPG_PLLECR; pll_clk->pllecr_pllst_mask = CPG_PLLECR_PLLST(index); - /* Disable Fractional Multiplication and Frequency Dithering */ - writel(0, base + cr1_offset); - cpg_reg_modify(pll_clk->pllcr0_reg, CPG_PLLxCR0_SSMODE, 0); + /* Enable Fractional Multiplication */ + cpg_reg_modify(pll_clk->pllcr0_reg, 0, CPG_PLLxCR0_SSMODE_FM); clk = clk_register(NULL, &pll_clk->hw); if (IS_ERR(clk))