From patchwork Sun Mar 24 19:27:33 2013 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Guennadi Liakhovetski X-Patchwork-Id: 2327191 Return-Path: X-Original-To: patchwork-linux-arm@patchwork.kernel.org Delivered-To: patchwork-process-083081@patchwork1.kernel.org Received: from merlin.infradead.org (merlin.infradead.org [205.233.59.134]) by patchwork1.kernel.org (Postfix) with ESMTP id D02AC3FDDA for ; Sun, 24 Mar 2013 19:32:29 +0000 (UTC) Received: from localhost ([::1] helo=merlin.infradead.org) by merlin.infradead.org with esmtp (Exim 4.80.1 #2 (Red Hat Linux)) id 1UJqag-0004Wf-AC; Sun, 24 Mar 2013 19:28:26 +0000 Received: from moutng.kundenserver.de ([212.227.17.10]) by merlin.infradead.org with esmtps (Exim 4.80.1 #2 (Red Hat Linux)) id 1UJqa3-0004QL-Vq for linux-arm-kernel@lists.infradead.org; Sun, 24 Mar 2013 19:27:52 +0000 Received: from axis700.grange (dslb-094-221-101-036.pools.arcor-ip.net [94.221.101.36]) by mrelayeu.kundenserver.de (node=mrbap0) with ESMTP (Nemesis) id 0MVb0p-1UBHTb3lzL-00Z2Q9; Sun, 24 Mar 2013 20:27:37 +0100 Received: from 6a.grange (6a.grange [192.168.1.11]) by axis700.grange (Postfix) with ESMTPS id 6E5F340BB3; Sun, 24 Mar 2013 20:27:36 +0100 (CET) Received: from lyakh by 6a.grange with local (Exim 4.72) (envelope-from ) id 1UJqZs-0005Nm-2x; Sun, 24 Mar 2013 20:27:36 +0100 From: Guennadi Liakhovetski To: linux-sh@vger.kernel.org Subject: [PATCH v4 1/3] ARM: shmobile: sh73a0: add support for adjusting CPU frequency Date: Sun, 24 Mar 2013 20:27:33 +0100 Message-Id: <1364153255-20664-2-git-send-email-g.liakhovetski@gmx.de> X-Mailer: git-send-email 1.7.2.5 In-Reply-To: <1364153255-20664-1-git-send-email-g.liakhovetski@gmx.de> References: <1364153255-20664-1-git-send-email-g.liakhovetski@gmx.de> X-Provags-ID: V02:K0:CimOgdYSGgj+Ifh8xrbmBnIrpAWKlJt1WHt5MSAgNwu GJDdBNphFvcNlOuxMgKrkXojxH50w+kPbwQL/xSdexnUvNcPDg FEMyCBLXcu8fXzt41hTb0CgKrqenYo+jgML7p4c8FQ/f2BR0sM bvO2G4cS9466ilLFcT6dinybcC2MHDBbJYnIJGbn9Kgo5XqaZv tVYA9Zs+cAR3QyQZilxgeE6TUjpd2W6dDP0DQMDuCnE7xqCODm gWRUoXxLuWL3AyHDkoKhLDhP2KxFiEySANeXpsKXaR0D3VnigY ukmdCCq2EnitqwY2gBSH4hugmxzpW0OtBhzZVslyjFdmEXYnur I7hBvApQQu3niczwJd/lV6jY5CSu6w2aspSLn+rzEoJGZwjq7J 75LOCHBIafpLQ== X-CRM114-Version: 20100106-BlameMichelson ( TRE 0.8.0 (BSD) ) MR-646709E3 X-CRM114-CacheID: sfid-20130324_152748_489990_076C303B X-CRM114-Status: GOOD ( 20.67 ) X-Spam-Score: -3.2 (---) X-Spam-Report: SpamAssassin version 3.3.2 on merlin.infradead.org summary: Content analysis details: (-3.2 points) pts rule name description ---- ---------------------- -------------------------------------------------- -0.0 RCVD_IN_DNSWL_NONE RBL: Sender listed at http://www.dnswl.org/, no trust [212.227.17.10 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 -1.3 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 --- v4: update Z-clock lookup name for the new version of the cpufreq-cpu0 driver. 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 c992600..509be3e 100644 --- a/arch/arm/mach-shmobile/clock-sh73a0.c +++ b/arch/arm/mach-shmobile/clock-sh73a0.c @@ -282,6 +282,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), @@ -308,6 +313,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, @@ -506,7 +590,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, @@ -527,6 +611,7 @@ static struct clk mstp_clks[MSTP_NR] = { [MSTP125] = MSTP(&div6_clks[DIV6_SUB], SMSTPCR1, 25, MSTPSR1, 0), /* TMU0 */ [MSTP118] = MSTP(&div4_clks[DIV4_B], SMSTPCR1, 18, MSTPSR1, 0), /* DSITX0 */ [MSTP116] = MSTP(&div4_clks[DIV4_HP], SMSTPCR1, 16, MSTPSR1, 0), /* IIC0 */ + [MSTP112] = MSTP(&div4_clks[DIV4_ZG], SMSTPCR1, 12, MSTPSR1, 0), /* SGX */ [MSTP100] = MSTP(&div4_clks[DIV4_B], SMSTPCR1, 0, MSTPSR1, 0), /* LCDC0 */ [MSTP219] = MSTP(&div6_clks[DIV6_SUB], SMSTPCR2, 19, MSTPSR2, 0), /* SCIFA7 */ [MSTP218] = MSTP(&div4_clks[DIV4_HP], SMSTPCR2, 18, MSTPSR2, 0), /* SY-DMAC */ @@ -569,6 +654,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]), @@ -660,8 +748,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);