From patchwork Sat Jul 20 08:29:35 2013 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Alexander Shiyan X-Patchwork-Id: 260422 Return-Path: X-Original-To: incoming-imx@patchwork.ozlabs.org Delivered-To: patchwork-incoming-imx@bilbo.ozlabs.org Received: from casper.infradead.org (unknown [IPv6:2001:770:15f::2]) (using TLSv1.2 with cipher DHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (Client did not present a certificate) by ozlabs.org (Postfix) with ESMTPS id DA2132C008A for ; Sat, 20 Jul 2013 18:30:47 +1000 (EST) Received: from merlin.infradead.org ([2001:4978:20e::2]) by casper.infradead.org with esmtps (Exim 4.80.1 #2 (Red Hat Linux)) id 1V0SYV-0003Fy-Df; Sat, 20 Jul 2013 08:30:19 +0000 Received: from localhost ([::1] helo=merlin.infradead.org) by merlin.infradead.org with esmtp (Exim 4.80.1 #2 (Red Hat Linux)) id 1V0SYT-0001iS-8y; Sat, 20 Jul 2013 08:30:17 +0000 Received: from smtp13.mail.ru ([94.100.176.90]) by merlin.infradead.org with esmtps (Exim 4.80.1 #2 (Red Hat Linux)) id 1V0SYM-0001i0-UC for linux-arm-kernel@lists.infradead.org; Sat, 20 Jul 2013 08:30:13 +0000 DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=mail.ru; s=mail2; h=Message-Id:Date:Subject:Cc:To:From; bh=QXzNKUcfuB04RZxu40Mw+STX010lDY/nmqYbbS81t30=; b=JD/8meWo6l/im9Yc1+/X7The1pF5nYYAwCocnvPHI3WQ7h4y+IGHLYWwX/tXr/7KuWm7XcW+aVSkMVCwY3RxeNh1PkFynuExp7KUXpRkj3cG/XfrCcQaDKKnhD/3IkeD/4ADRWh+Dr6DpsfM0GyrkDpDU71obUbZAU55nLDyxa0=; Received: from [188.134.40.128] (port=28830 helo=shc.zet) by smtp13.mail.ru with esmtpa (envelope-from ) id 1V0SXz-0007OQ-PL; Sat, 20 Jul 2013 12:29:47 +0400 From: Alexander Shiyan To: linux-arm-kernel@lists.infradead.org Subject: [RFC v2] ARM: i.MX pllv1: Implement set_rate Date: Sat, 20 Jul 2013 12:29:35 +0400 Message-Id: <1374308975-20596-1-git-send-email-shc_work@mail.ru> X-Mailer: git-send-email 1.8.1.5 X-Spam: Not detected X-Mras: Ok X-CRM114-Version: 20100106-BlameMichelson ( TRE 0.8.0 (BSD) ) MR-646709E3 X-CRM114-CacheID: sfid-20130720_043011_752508_42078FB7 X-CRM114-Status: GOOD ( 15.82 ) X-Spam-Score: -2.0 (--) X-Spam-Report: SpamAssassin version 3.3.2 on merlin.infradead.org summary: Content analysis details: (-2.0 points) pts rule name description ---- ---------------------- -------------------------------------------------- 0.0 FREEMAIL_FROM Sender email is commonly abused enduser mail provider (shc_work[at]mail.ru) -0.0 RCVD_IN_DNSWL_NONE RBL: Sender listed at http://www.dnswl.org/, no trust [94.100.176.90 listed in list.dnswl.org] -0.0 SPF_PASS SPF: sender matches SPF record -1.9 BAYES_00 BODY: Bayes spam probability is 0 to 1% [score: 0.0000] -0.1 DKIM_VALID_AU Message has a valid DKIM or DK signature from author's domain 0.1 DKIM_SIGNED Message has a DKIM or DK signature, not necessarily valid -0.1 DKIM_VALID Message has at least one valid DKIM or DK signature Cc: Alexander Shiyan , Sascha Hauer X-BeenThere: linux-arm-kernel@lists.infradead.org X-Mailman-Version: 2.1.15 Precedence: list List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , MIME-Version: 1.0 Sender: "linux-arm-kernel" Errors-To: linux-arm-kernel-bounces+incoming-imx=patchwork.ozlabs.org@lists.infradead.org List-Id: linux-imx-kernel.lists.patchwork.ozlabs.org This patch implements frequency change for i.MX pllv1. Selection of the values of the registers is not optimal, since is made by simple enumeration of all possible values. Signed-off-by: Alexander Shiyan --- arch/arm/mach-imx/clk-imx27.c | 2 +- arch/arm/mach-imx/clk-pllv1.c | 118 +++++++++++++++++++++++++++++++++++------- arch/arm/mach-imx/mx27.h | 7 ++- 3 files changed, 106 insertions(+), 21 deletions(-) diff --git a/arch/arm/mach-imx/clk-imx27.c b/arch/arm/mach-imx/clk-imx27.c index c3cfa41..2b363d9 100644 --- a/arch/arm/mach-imx/clk-imx27.c +++ b/arch/arm/mach-imx/clk-imx27.c @@ -125,7 +125,7 @@ int __init mx27_clocks_init(unsigned long fref) clk[vpu_sel] = imx_clk_mux("vpu_sel", CCM_CSCR, 21, 1, vpu_sel_clks, ARRAY_SIZE(vpu_sel_clks)); clk[vpu_div] = imx_clk_divider("vpu_div", "vpu_sel", CCM_PCDR0, 10, 6); clk[usb_div] = imx_clk_divider("usb_div", "spll_gate", CCM_CSCR, 28, 3); - clk[cpu_sel] = imx_clk_mux("cpu_sel", CCM_CSCR, 15, 1, cpu_sel_clks, ARRAY_SIZE(cpu_sel_clks)); + clk[cpu_sel] = imx_clk_mux_flags("cpu_sel", CCM_CSCR, 15, 1, cpu_sel_clks, ARRAY_SIZE(cpu_sel_clks), CLK_SET_RATE_PARENT); clk[clko_sel] = imx_clk_mux("clko_sel", CCM_CCSR, 0, 5, clko_sel_clks, ARRAY_SIZE(clko_sel_clks)); if (mx27_revision() >= IMX_CHIP_REVISION_2_0) clk[cpu_div] = imx_clk_divider("cpu_div", "cpu_sel", CCM_CSCR, 12, 2); diff --git a/arch/arm/mach-imx/clk-pllv1.c b/arch/arm/mach-imx/clk-pllv1.c index c1eaee3..722fea2 100644 --- a/arch/arm/mach-imx/clk-pllv1.c +++ b/arch/arm/mach-imx/clk-pllv1.c @@ -9,6 +9,8 @@ #include "common.h" #include "hardware.h" +#include "mx27.h" + /** * pll v1 * @@ -25,17 +27,13 @@ struct clk_pllv1 { #define to_clk_pllv1(clk) (container_of(clk, struct clk_pllv1, clk)) -static unsigned long clk_pllv1_recalc_rate(struct clk_hw *hw, - unsigned long parent_rate) +static unsigned long _clk_pllv1_recalc_rate(unsigned int mfi, unsigned int mfn, + unsigned int mfd, unsigned int pd, + unsigned long parent_rate) { - struct clk_pllv1 *pll = to_clk_pllv1(hw); - long long ll; - int mfn_abs; - unsigned int mfi, mfn, mfd, pd; - u32 reg; unsigned long rate; - - reg = readl(pll->base); + int mfn_abs = mfn; + long long ll; /* * Get the resulting clock rate from a PLL register value and the input @@ -47,15 +45,6 @@ static unsigned long clk_pllv1_recalc_rate(struct clk_hw *hw, * pd + 1 */ - mfi = (reg >> 10) & 0xf; - mfn = reg & 0x3ff; - mfd = (reg >> 16) & 0x3ff; - pd = (reg >> 26) & 0xf; - - mfi = mfi <= 5 ? 5 : mfi; - - mfn_abs = mfn; - /* * On all i.MXs except i.MX1 and i.MX21 mfn is a 10bit * 2's complements number @@ -78,8 +67,99 @@ static unsigned long clk_pllv1_recalc_rate(struct clk_hw *hw, return ll; } +static unsigned long clk_pllv1_recalc_rate(struct clk_hw *hw, + unsigned long parent_rate) +{ + struct clk_pllv1 *pll = to_clk_pllv1(hw); + unsigned int mfi, mfn, mfd, pd; + u32 reg = readl(pll->base); + + /* Avoid i.MX27 TO2 SPCTL0 bug */ + if (cpu_is_mx27() && (mx27_revision() == IMX_CHIP_REVISION_2_0)) + writel(reg, pll->base); + + mfi = (reg >> 10) & 0xf; + mfn = reg & 0x3ff; + mfd = (reg >> 16) & 0x3ff; + pd = (reg >> 26) & 0xf; + + mfi = mfi <= 5 ? 5 : mfi; + + return _clk_pllv1_recalc_rate(mfi, mfn, mfd, pd, parent_rate); +} + +static void _clk_pllv1_set_rate(unsigned long rate, unsigned long parent_rate, + unsigned int *reg) +{ + unsigned int pd, mfi, mfn, mfd, mfn_offs = 0; + long tmp, res, best = 0; + + pd = (parent_rate * 2 * 5) / rate; + if (pd > 15) + pd = 15; + mfi = rate / (parent_rate * 2 * (pd + 1)); + if (mfi < 5) + mfi = 5; + if (mfi < 15) { + tmp = parent_rate * 2; + tmp /= pd + 1; + tmp *= mfi; + if (tmp / parent_rate) { + mfi++; + /* Use negative values */ + mfn_offs = 0x200; + } + } else if (mfi > 15) + mfi = 15; + + for (mfd = 1; mfd < 0x400; mfd++) + for (mfn = 0; (mfn < mfd) && (mfn <= 0x1fe); mfn++) { + res = _clk_pllv1_recalc_rate(mfi, mfn_offs + mfn, mfd, + pd, parent_rate); + if (!best || (abs(rate - res) < abs(rate - best))) { + *reg = mfn_offs + mfn; + *reg |= mfi << 10; + *reg |= mfd << 16; + *reg |= pd << 26; + if (res == rate) + return; + best = res; + } + } +} + +static int clk_pllv1_set_rate(struct clk_hw *hw, unsigned long rate, + unsigned long parent_rate) +{ + struct clk_pllv1 *pll = to_clk_pllv1(hw); + u32 reg; + + _clk_pllv1_set_rate(rate, parent_rate, ®); + writel(reg, pll->base); + + return 0; +} + +static long clk_pllv1_round_rate(struct clk_hw *hw, unsigned long rate, + unsigned long *prate) +{ + unsigned int pd, mfi, mfn, mfd; + u32 reg; + + _clk_pllv1_set_rate(rate, *prate, ®); + + mfi = (reg >> 10) & 0xf; + mfn = reg & 0x3ff; + mfd = (reg >> 16) & 0x3ff; + pd = (reg >> 26) & 0xf; + + return _clk_pllv1_recalc_rate(mfi, mfn, mfd, pd, *prate); +} + static struct clk_ops clk_pllv1_ops = { - .recalc_rate = clk_pllv1_recalc_rate, + .recalc_rate = clk_pllv1_recalc_rate, + .round_rate = clk_pllv1_round_rate, + .set_rate = clk_pllv1_set_rate, }; struct clk *imx_clk_pllv1(const char *name, const char *parent, diff --git a/arch/arm/mach-imx/mx27.h b/arch/arm/mach-imx/mx27.h index 8a65f19..c64632b 100644 --- a/arch/arm/mach-imx/mx27.h +++ b/arch/arm/mach-imx/mx27.h @@ -231,8 +231,13 @@ #define MX27_DMA_REQ_SDHC3 36 #define MX27_DMA_REQ_NFC 37 -#ifndef __ASSEMBLY__ +#ifdef CONFIG_SOC_IMX27 extern int mx27_revision(void); +#else +static int mx27_revision(void) +{ + return -1; +} #endif #endif /* ifndef __MACH_MX27_H__ */