From patchwork Fri Apr 5 10:00:36 2013 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Guennadi Liakhovetski X-Patchwork-Id: 2397581 Return-Path: X-Original-To: patchwork-linux-arm@patchwork.kernel.org Delivered-To: patchwork-process-083081@patchwork1.kernel.org Received: from casper.infradead.org (casper.infradead.org [85.118.1.10]) by patchwork1.kernel.org (Postfix) with ESMTP id 1C2543FD8C for ; Fri, 5 Apr 2013 10:17:59 +0000 (UTC) Received: from merlin.infradead.org ([2001:4978:20e::2]) by casper.infradead.org with esmtps (Exim 4.80.1 #2 (Red Hat Linux)) id 1UO3iY-0001Xs-6n for patchwork-linux-arm@patchwork.kernel.org; Fri, 05 Apr 2013 10:17:58 +0000 Received: from localhost ([::1] helo=merlin.infradead.org) by merlin.infradead.org with esmtp (Exim 4.80.1 #2 (Red Hat Linux)) id 1UO3Sn-0002ZJ-KJ; Fri, 05 Apr 2013 10:01:41 +0000 Received: from moutng.kundenserver.de ([212.227.126.187]) by merlin.infradead.org with esmtps (Exim 4.80.1 #2 (Red Hat Linux)) id 1UO3Rz-00022A-6I for linux-arm-kernel@lists.infradead.org; Fri, 05 Apr 2013 10:00:53 +0000 Received: from axis700.grange (dslb-094-221-122-203.pools.arcor-ip.net [94.221.122.203]) by mrelayeu.kundenserver.de (node=mreu2) with ESMTP (Nemesis) id 0LwE4w-1Ug8F70bE6-017UIS; Fri, 05 Apr 2013 12:00:39 +0200 Received: from 6a.grange (6a.grange [192.168.1.11]) by axis700.grange (Postfix) with ESMTPS id B66FD40BB3; Fri, 5 Apr 2013 12:00:38 +0200 (CEST) Received: from lyakh by 6a.grange with local (Exim 4.72) (envelope-from ) id 1UO3Rm-0003Fe-D6; Fri, 05 Apr 2013 12:00:38 +0200 From: Guennadi Liakhovetski To: linux-sh@vger.kernel.org Subject: [PATCH v5 1/3] ARM: shmobile: sh73a0: add support for adjusting CPU frequency Date: Fri, 5 Apr 2013 12:00:36 +0200 Message-Id: <1365156038-12467-2-git-send-email-g.liakhovetski@gmx.de> X-Mailer: git-send-email 1.7.2.5 In-Reply-To: <1365156038-12467-1-git-send-email-g.liakhovetski@gmx.de> References: <1365156038-12467-1-git-send-email-g.liakhovetski@gmx.de> X-Provags-ID: V02:K0:vdcEzq9KykMtbzbFdNkYaUE4sGJ7zQspgO3dS8CTKW0 +z9nwNy2e651A1S9ruvIHAge1qjWpE5Rg7ukV1zbKPLk9LbGt/ va3ILh/Ruk0Q3BtdD6FWsKAPMVfnQrEgfpXcWRUlc5eS5eqDRs DthMv9vFKVIScpIh4IhP1imegQbPKlYN6PYbUbALnIpERYECi1 YBPqms9IpLecfurFpsHUjAkiMoVv47O6UhH91sXFqTVmzv9q6w OISzaDMVz8NcoHmRRUKJrMPJh/3Bu/pHdXypDuk2/c5azGsDPl WtsUmKXLhAI+feVB/AQyqZbsThbGaUup3ZZuJ6WKpXoV8rLgyp 5qLyvswTscsrq9wnf3uSZp7r7iDiHvxMkxipO1Ftcv2+xTj8SI ErNqGDY90j8ew== X-CRM114-Version: 20100106-BlameMichelson ( TRE 0.8.0 (BSD) ) MR-646709E3 X-CRM114-CacheID: sfid-20130405_060051_636134_0743D4DC X-CRM114-Status: GOOD ( 20.52 ) X-Spam-Score: -4.3 (----) X-Spam-Report: SpamAssassin version 3.3.2 on merlin.infradead.org summary: Content analysis details: (-4.3 points) pts rule name description ---- ---------------------- -------------------------------------------------- -0.0 RCVD_IN_DNSWL_NONE RBL: Sender listed at http://www.dnswl.org/, no trust [212.227.126.187 listed in list.dnswl.org] 0.0 FREEMAIL_FROM Sender email is commonly abused enduser mail provider (g.liakhovetski[at]gmx.de) -0.0 SPF_HELO_PASS SPF: HELO matches SPF record -0.0 SPF_PASS SPF: sender matches SPF record -2.4 RP_MATCHES_RCVD Envelope sender domain matches handover relay domain -1.9 BAYES_00 BODY: Bayes spam probability is 0 to 1% [score: 0.0000] Cc: Magnus Damm , Guennadi Liakhovetski , cpufreq@vger.kernel.org, "Rafael J. Wysocki" , Simon Horman , linux-arm-kernel@lists.infradead.org X-BeenThere: linux-arm-kernel@lists.infradead.org X-Mailman-Version: 2.1.15 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , MIME-Version: 1.0 Sender: "linux-arm-kernel" Errors-To: linux-arm-kernel-bounces+patchwork-linux-arm=patchwork.kernel.org@lists.infradead.org On SH73A0 the output of PLL0 is supplied to two dividers, feeding clock to the CPU core and SGX. Lower CPU frequencies allow the use of lower supply voltages and thus reduce power consumption. Signed-off-by: Guennadi Liakhovetski --- v5: not based on MSTP-waiting rework, it needs more work arch/arm/mach-shmobile/clock-sh73a0.c | 95 ++++++++++++++++++++++++++++++++- 1 files changed, 93 insertions(+), 2 deletions(-) diff --git a/arch/arm/mach-shmobile/clock-sh73a0.c b/arch/arm/mach-shmobile/clock-sh73a0.c index 784fbaa..acb9e09 100644 --- a/arch/arm/mach-shmobile/clock-sh73a0.c +++ b/arch/arm/mach-shmobile/clock-sh73a0.c @@ -228,6 +228,11 @@ enum { DIV4_I, DIV4_ZG, DIV4_M3, DIV4_B, DIV4_M1, DIV4_M2, static struct clk div4_clks[DIV4_NR] = { [DIV4_I] = DIV4(FRQCRA, 20, 0xdff, CLK_ENABLE_ON_INIT), + /* + * ZG clock is dividing PLL0 frequency to supply SGX. Make sure not to + * exceed maximum frequencies of 201.5MHz for VDD_DVFS=1.175 and + * 239.2MHz for VDD_DVFS=1.315V. + */ [DIV4_ZG] = SH_CLK_DIV4(&pll0_clk, FRQCRA, 16, 0xd7f, CLK_ENABLE_ON_INIT), [DIV4_M3] = DIV4(FRQCRA, 12, 0x1dff, CLK_ENABLE_ON_INIT), [DIV4_B] = DIV4(FRQCRA, 8, 0xdff, CLK_ENABLE_ON_INIT), @@ -252,6 +257,85 @@ static struct clk twd_clk = { .ops = &twd_clk_ops, }; +static int (*div4_set_rate)(struct clk *clk, unsigned long rate); +static unsigned long (*div4_recalc)(struct clk *clk); +static long (*div4_round_rate)(struct clk *clk, unsigned long rate); + +static int zclk_set_rate(struct clk *clk, unsigned long rate) +{ + int ret; + + if (!clk->parent || !__clk_get(clk->parent)) + return -ENODEV; + + if (readl(FRQCRB) & (1 << 31)) + return -EBUSY; + + if (rate == clk_get_rate(clk->parent)) { + /* 1:1 - switch off divider */ + __raw_writel(__raw_readl(FRQCRB) & ~(1 << 28), FRQCRB); + /* nullify the divider to prepare for the next time */ + ret = div4_set_rate(clk, rate / 2); + if (!ret) + ret = frqcr_kick(); + if (ret > 0) + ret = 0; + } else { + /* Enable the divider */ + __raw_writel(__raw_readl(FRQCRB) | (1 << 28), FRQCRB); + + ret = frqcr_kick(); + if (ret >= 0) + /* + * set the divider - call the DIV4 method, it will kick + * FRQCRB too + */ + ret = div4_set_rate(clk, rate); + if (ret < 0) + goto esetrate; + } + +esetrate: + __clk_put(clk->parent); + return ret; +} + +static long zclk_round_rate(struct clk *clk, unsigned long rate) +{ + unsigned long div_freq = div4_round_rate(clk, rate), + parent_freq = clk_get_rate(clk->parent); + + if (rate > div_freq && abs(parent_freq - rate) < rate - div_freq) + return parent_freq; + + return div_freq; +} + +static unsigned long zclk_recalc(struct clk *clk) +{ + /* + * Must recalculate frequencies in case PLL0 has been changed, even if + * the divisor is unused ATM! + */ + unsigned long div_freq = div4_recalc(clk); + + if (__raw_readl(FRQCRB) & (1 << 28)) + return div_freq; + + return clk_get_rate(clk->parent); +} + +static void zclk_extend(void) +{ + /* We extend the DIV4 clock with a 1:1 pass-through case */ + div4_set_rate = div4_clks[DIV4_Z].ops->set_rate; + div4_round_rate = div4_clks[DIV4_Z].ops->round_rate; + div4_recalc = div4_clks[DIV4_Z].ops->recalc; + div4_clks[DIV4_Z].ops->set_rate = zclk_set_rate; + div4_clks[DIV4_Z].ops->round_rate = zclk_round_rate; + div4_clks[DIV4_Z].ops->recalc = zclk_recalc; +} + enum { DIV6_VCK1, DIV6_VCK2, DIV6_VCK3, DIV6_ZB1, DIV6_FLCTL, DIV6_SDHI0, DIV6_SDHI1, DIV6_SDHI2, DIV6_FSIA, DIV6_FSIB, DIV6_SUB, @@ -450,7 +534,7 @@ static struct clk *late_main_clks[] = { }; enum { MSTP001, - MSTP129, MSTP128, MSTP127, MSTP126, MSTP125, MSTP118, MSTP116, MSTP100, + MSTP129, MSTP128, MSTP127, MSTP126, MSTP125, MSTP118, MSTP116, MSTP112, MSTP100, MSTP219, MSTP218, MSTP217, MSTP207, MSTP206, MSTP204, MSTP203, MSTP202, MSTP201, MSTP200, MSTP331, MSTP329, MSTP328, MSTP325, MSTP323, MSTP322, @@ -471,6 +555,7 @@ static struct clk mstp_clks[MSTP_NR] = { [MSTP125] = MSTP(&div6_clks[DIV6_SUB], SMSTPCR1, 25, 0), /* TMU0 */ [MSTP118] = MSTP(&div4_clks[DIV4_B], SMSTPCR1, 18, 0), /* DSITX0 */ [MSTP116] = MSTP(&div4_clks[DIV4_HP], SMSTPCR1, 16, 0), /* IIC0 */ + [MSTP112] = MSTP(&div4_clks[DIV4_ZG], SMSTPCR1, 12, 0), /* SGX */ [MSTP100] = MSTP(&div4_clks[DIV4_B], SMSTPCR1, 0, 0), /* LCDC0 */ [MSTP219] = MSTP(&div6_clks[DIV6_SUB], SMSTPCR2, 19, 0), /* SCIFA7 */ [MSTP218] = MSTP(&div4_clks[DIV4_HP], SMSTPCR2, 18, 0), /* SY-DMAC */ @@ -513,6 +598,9 @@ static struct clk_lookup lookups[] = { CLKDEV_CON_ID("r_clk", &r_clk), CLKDEV_DEV_ID("smp_twd", &twd_clk), /* smp_twd */ + /* DIV4 clocks */ + CLKDEV_DEV_ID("cpufreq-cpu0", &div4_clks[DIV4_Z]), + /* DIV6 clocks */ CLKDEV_CON_ID("vck1_clk", &div6_clks[DIV6_VCK1]), CLKDEV_CON_ID("vck2_clk", &div6_clks[DIV6_VCK2]), @@ -604,8 +692,11 @@ void __init sh73a0_clock_init(void) for (k = 0; !ret && (k < ARRAY_SIZE(main_clks)); k++) ret = clk_register(main_clks[k]); - if (!ret) + if (!ret) { ret = sh_clk_div4_register(div4_clks, DIV4_NR, &div4_table); + if (!ret) + zclk_extend(); + } if (!ret) ret = sh_clk_div6_reparent_register(div6_clks, DIV6_NR);