From patchwork Tue Jul 21 05:56:34 2009 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Sekhar Nori X-Patchwork-Id: 36460 Received: from bear.ext.ti.com (bear.ext.ti.com [192.94.94.41]) by demeter.kernel.org (8.14.2/8.14.2) with ESMTP id n6L5wN14006593 for ; Tue, 21 Jul 2009 05:58:23 GMT Received: from dlep33.itg.ti.com ([157.170.170.112]) by bear.ext.ti.com (8.13.7/8.13.7) with ESMTP id n6L5unjZ013485; Tue, 21 Jul 2009 00:56:54 -0500 Received: from linux.omap.com (localhost [127.0.0.1]) by dlep33.itg.ti.com (8.13.7/8.13.7) with ESMTP id n6L5umeb023444; Tue, 21 Jul 2009 00:56:48 -0500 (CDT) Received: from linux.omap.com (localhost [127.0.0.1]) by linux.omap.com (Postfix) with ESMTP id A846680630; Tue, 21 Jul 2009 00:56:43 -0500 (CDT) X-Original-To: davinci-linux-open-source@linux.davincidsp.com Delivered-To: davinci-linux-open-source@linux.davincidsp.com Received: from dbdp31.itg.ti.com (dbdp31.itg.ti.com [172.24.170.98]) by linux.omap.com (Postfix) with ESMTP id BBC6F80628 for ; Tue, 21 Jul 2009 00:56:39 -0500 (CDT) Received: from psplinux051.india.ti.com (localhost [127.0.0.1]) by dbdp31.itg.ti.com (8.13.8/8.13.8) with ESMTP id n6L5ubOw015060; Tue, 21 Jul 2009 11:26:37 +0530 (IST) Received: from psplinux051.india.ti.com (localhost [127.0.0.1]) by psplinux051.india.ti.com (8.13.1/8.13.1) with ESMTP id n6L5ubh0009994; Tue, 21 Jul 2009 11:26:37 +0530 Received: (from a0875516@localhost) by psplinux051.india.ti.com (8.13.1/8.13.1/Submit) id n6L5ubBI009991; Tue, 21 Jul 2009 11:26:37 +0530 From: Sekhar Nori To: davinci-linux-open-source@linux.davincidsp.com Date: Tue, 21 Jul 2009 11:26:34 +0530 Message-Id: <1248155796-9920-2-git-send-email-nsekhar@ti.com> X-Mailer: git-send-email 1.6.2.4 In-Reply-To: <1248155796-9920-1-git-send-email-nsekhar@ti.com> References: <1248155796-9920-1-git-send-email-nsekhar@ti.com> Cc: Subject: [PATCH 1/3] davinci: clock framework updates for CPUFreq support X-BeenThere: davinci-linux-open-source@linux.davincidsp.com X-Mailman-Version: 2.1.4 Precedence: list List-Id: davinci-linux-open-source.linux.davincidsp.com List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Sender: davinci-linux-open-source-bounces@linux.davincidsp.com Errors-To: davinci-linux-open-source-bounces@linux.davincidsp.com Update the clock framework for dynamic CPU frequency change. clk_round_rate, clk_set_rate have been updated to handle dynamic frequency changes. davinci_set_pllrate() changes the PLL rate of a given PLL. This function has been presented as a generic function though it has been tested only on OMAP-L138 EVM. No other currently available DaVinci device will probably use this function, but any future device specific changes will hopefully be small enough to get taken care using a cpu_is_xxx() macro. Finally, another function is implemented to recalculate the PLL derived rates after the PLL rate has been changed. Tested on OMAP-L138 EVM. Signed-off-by: Sekhar Nori --- arch/arm/mach-davinci/clock.c | 115 +++++++++++++++++++++++++++++++++++++++- arch/arm/mach-davinci/clock.h | 9 +++ 2 files changed, 121 insertions(+), 3 deletions(-) diff --git a/arch/arm/mach-davinci/clock.c b/arch/arm/mach-davinci/clock.c index 83d54d5..8c108eb 100644 --- a/arch/arm/mach-davinci/clock.c +++ b/arch/arm/mach-davinci/clock.c @@ -19,6 +19,7 @@ #include #include #include +#include #include @@ -99,17 +100,27 @@ long clk_round_rate(struct clk *clk, unsigned long rate) if (clk == NULL || IS_ERR(clk)) return -EINVAL; + if (clk->round_rate) + return clk->round_rate(clk, rate); + return clk->rate; } EXPORT_SYMBOL(clk_round_rate); int clk_set_rate(struct clk *clk, unsigned long rate) { + unsigned long flags; + int ret = -EINVAL; + if (clk == NULL || IS_ERR(clk)) - return -EINVAL; + return ret; + + spin_lock_irqsave(&clockfw_lock, flags); + if (clk->set_rate) + ret = clk->set_rate(clk, rate); + spin_unlock_irqrestore(&clockfw_lock, flags); - /* changing the clk rate is not supported */ - return -EINVAL; + return ret; } EXPORT_SYMBOL(clk_set_rate); @@ -273,6 +284,104 @@ static void __init clk_pll_init(struct clk *clk) pr_debug("] --> %lu MHz output.\n", clk->rate / 1000000); } +/** + * davinci_set_pllrate - set the output rate of a given PLL. + * + * Note: Currently tested to work with OMAP-L138 only. + * + * @pll: pll whose rate needs to be changed. + * @prediv: prediv value to be programmed. Passing 0 disables prediv. + * @pllm: pllm value to be programmed. Passing 0 leads to multiply-by-one. + * @postdiv: postdiv value to be programmed. Passing 0 disables postdiv. + */ +int davinci_set_pllrate(struct pll_data *pll, unsigned int prediv, + unsigned int mult, unsigned int postdiv) +{ + u32 ctrl; + + BUG_ON(pll->base == NULL); + + if (prediv) + prediv = (prediv - 1) | PLLDIV_EN; + if (postdiv) + postdiv = (postdiv - 1) | PLLDIV_EN; + if (mult) + mult = mult - 1; + + ctrl = __raw_readl(pll->base + PLLCTL); + + /* Switch the PLL to bypass mode */ + ctrl &= ~(PLLCTL_PLLENSRC | PLLCTL_PLLEN); + __raw_writel(ctrl, pll->base + PLLCTL); + + /* + * Wait for 4 OSCIN/CLKIN cycles to ensure that the PLLC has switched + * to bypass mode. Delay of 1us ensures we are good for all > 4MHz + * OSCIN/CLKIN inputs. Typically the input is ~25MHz. + */ + udelay(1); + + /* Reset and enable PLL */ + ctrl &= ~(PLLCTL_PLLRST | PLLCTL_PLLDIS); + __raw_writel(ctrl, pll->base + PLLCTL); + + if (pll->flags & PLL_HAS_PREDIV) + __raw_writel(prediv, pll->base + PREDIV); + + __raw_writel(mult, pll->base + PLLM); + + if (pll->flags & PLL_HAS_POSTDIV) + __raw_writel(postdiv, pll->base + POSTDIV); + + /* + * Wait for PLL to reset properly, OMAP-L138 datasheet says + * 'min' time = 125ns + */ + udelay(1); + + /* Bring PLL out of reset */ + ctrl |= PLLCTL_PLLRST; + __raw_writel(ctrl, pll->base + PLLCTL); + + /* + * Wait for PLL to lock. Time required per OMAP-L138 datasheet is + * (2000 * prediv)/sqrt(pllm) OSCIN cycles. We approximate sqrt(pllm) + * as 4 and OSCIN cycle as 25 MHz. + */ + udelay((2000 * (prediv + 1)) / 100); + + /* Remove PLL from bypass mode */ + ctrl |= PLLCTL_PLLEN; + __raw_writel(ctrl, pll->base + PLLCTL); + + return 0; +} +EXPORT_SYMBOL(davinci_set_pllrate); + +/** + * davinci_clk_recal_rates - recalculate rates of the davinci clock tree + * + * @clocks: pointer to the clock tree + */ +int davinci_clk_recalc_rates(struct davinci_clk *clocks) +{ + struct davinci_clk *c; + struct clk *clk; + + for (c = clocks; c->lk.clk; c++) { + clk = c->lk.clk; + + /* Re-calculate rates for PLL-derived clocks */ + if (!clk->pll_data && clk->flags & CLK_PLL) + clk_sysclk_recalc(clk); + else if (clk->flags & CLK_PSC) + clk->rate = clk->parent->rate; + } + + return 0; +} +EXPORT_SYMBOL(davinci_clk_recalc_rates); + int __init davinci_clk_init(struct davinci_clk *clocks) { struct davinci_clk *c; diff --git a/arch/arm/mach-davinci/clock.h b/arch/arm/mach-davinci/clock.h index 27233cb..f772e6e 100644 --- a/arch/arm/mach-davinci/clock.h +++ b/arch/arm/mach-davinci/clock.h @@ -22,6 +22,10 @@ /* PLL/Reset register offsets */ #define PLLCTL 0x100 #define PLLCTL_PLLEN BIT(0) +#define PLLCTL_PLLPWRDN BIT(1) +#define PLLCTL_PLLRST BIT(3) +#define PLLCTL_PLLDIS BIT(4) +#define PLLCTL_PLLENSRC BIT(5) #define PLLCTL_CLKMODE BIT(8) #define PLLM 0x110 @@ -71,6 +75,8 @@ struct clk { struct clk *parent; struct pll_data *pll_data; u32 div_reg; + int (*set_rate) (struct clk *clk, unsigned long rate); + int (*round_rate) (struct clk *clk, unsigned long rate); }; /* Clock flags */ @@ -94,6 +100,9 @@ struct davinci_clk { } int davinci_clk_init(struct davinci_clk *clocks); +int davinci_clk_recalc_rates(struct davinci_clk *clocks); +int davinci_set_pllrate(struct pll_data *pll, unsigned int prediv, + unsigned int mult, unsigned int postdiv); extern struct platform_device davinci_wdt_device;