From patchwork Tue Jul 21 05:56:36 2009 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Sekhar Nori X-Patchwork-Id: 36461 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 n6L5wS8B006610 for ; Tue, 21 Jul 2009 05:58:29 GMT Received: from dlep34.itg.ti.com ([157.170.170.115]) by bear.ext.ti.com (8.13.7/8.13.7) with ESMTP id n6L5unY1013487; Tue, 21 Jul 2009 00:56:54 -0500 Received: from linux.omap.com (localhost [127.0.0.1]) by dlep34.itg.ti.com (8.13.7/8.13.7) with ESMTP id n6L5unNh006571; Tue, 21 Jul 2009 00:56:49 -0500 (CDT) Received: from linux.omap.com (localhost [127.0.0.1]) by linux.omap.com (Postfix) with ESMTP id ADEC280634; Tue, 21 Jul 2009 00:56:44 -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 D83FB8062A 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 n6L5ubwR015062; Tue, 21 Jul 2009 11:26:38 +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 n6L5ubjp010006; 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 n6L5ubor010003; 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:36 +0530 Message-Id: <1248155796-9920-4-git-send-email-nsekhar@ti.com> X-Mailer: git-send-email 1.6.2.4 In-Reply-To: <1248155796-9920-3-git-send-email-nsekhar@ti.com> References: <1248155796-9920-1-git-send-email-nsekhar@ti.com> <1248155796-9920-2-git-send-email-nsekhar@ti.com> <1248155796-9920-3-git-send-email-nsekhar@ti.com> Cc: Subject: [PATCH 3/3] davinci: DA850/OMAP-L138: add 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 add basic CPUFreq support for DA850/OMAP-L138 Currently, frequency scaling only on PLL0 is supported. No scaling of PLL1 or voltage levels as yet. Peripherals like MMC/SD which have a clock input synchronous with ARM clock will not work well since the clock will change behind their backs. Support for notification to such devices to adjust themselves to the new frequency will be added in later patches. Current defconfigs keep CPUFreq disabled so it will not affect normal operation. The patch moves Async3 clock source to PLL1 so that frequency scaling on PLL0 does not affect those peripherals. Without this the console on UART2 goes for a toss the moment CPUFreq kicks in. The OPP defintions assume clock input of 24MHz to the SoC. This is inline with hardcoding of input frequency in the .c files. At some point this will need to move into board dependent code as boards appear with different input clock. Tested with ondemand governer and a shell script to vary processor load. Note: This patch also does an off-topic change of making the JTAG id register definition derive from SYSCFG base address. Signed-off-by: Sekhar Nori --- arch/arm/mach-davinci/da850.c | 146 +++++++++++++++++++++++++++- arch/arm/mach-davinci/include/mach/da8xx.h | 4 +- 2 files changed, 147 insertions(+), 3 deletions(-) diff --git a/arch/arm/mach-davinci/da850.c b/arch/arm/mach-davinci/da850.c index 4a43ae2..fe71f13 100644 --- a/arch/arm/mach-davinci/da850.c +++ b/arch/arm/mach-davinci/da850.c @@ -15,6 +15,7 @@ #include #include #include +#include #include @@ -35,6 +36,8 @@ #define DA850_TIMER64P3_BASE 0x01f0d000 #define DA850_REF_FREQ 24000000 +static int da850_set_armrate(struct clk *clk, unsigned long rate); +static int da850_round_armrate(struct clk *clk, unsigned long rate); static struct pll_data pll0_data = { .num = 1, @@ -230,14 +233,14 @@ static struct clk uart0_clk = { static struct clk uart1_clk = { .name = "uart1", - .parent = &pll0_sysclk2, + .parent = &pll1_sysclk2, .lpsc = DA8XX_LPSC1_UART1, .psc_ctlr = 1, }; static struct clk uart2_clk = { .name = "uart2", - .parent = &pll0_sysclk2, + .parent = &pll1_sysclk2, .lpsc = DA8XX_LPSC1_UART2, .psc_ctlr = 1, }; @@ -276,6 +279,8 @@ static struct clk arm_clk = { .parent = &pll0_sysclk6, .lpsc = DA8XX_LPSC0_ARM, .flags = ALWAYS_ENABLED, + .set_rate = da850_set_armrate, + .round_rate = da850_round_armrate, }; static struct clk rmii_clk = { @@ -601,6 +606,65 @@ static struct davinci_timer_info da850_timer_info = { .clocksource_id = T0_TOP, }; +#define MAX_NUM_OPP 3 + +/* + * Notes: + * According to the TRM, minimum PLLM results in max power savings. + * The OPP definitions below should keep the PLLM as low as possible. + * + * The output of the PLLM must be between 400 to 600 MHz. + * This rules out prediv of anything but divide-by-one for 24Mhz OSC input. + */ +struct da850_opp { + unsigned int freq; /* in KHz */ + unsigned int prediv; + unsigned int mult; + unsigned int postdiv; +}; + +static const struct da850_opp da850_opp_300 = { + .freq = 300000, + .prediv = 1, + .mult = 25, + .postdiv = 2, +}; + +static const struct da850_opp da850_opp_200 = { + .freq = 200000, + .prediv = 1, + .mult = 25, + .postdiv = 3, +}; + +static const struct da850_opp da850_opp_96 = { + .freq = 96000, + .prediv = 1, + .mult = 20, + .postdiv = 5, +}; + +#define OPP(freq) \ + { \ + .index = (unsigned int) &da850_opp_##freq, \ + .frequency = freq * 1000, \ + } + +static struct cpufreq_frequency_table da850_freq_table[MAX_NUM_OPP+1] = { + OPP(300), + OPP(200), + OPP(96), + { + .index = 0, + .frequency = CPUFREQ_TABLE_END, + }, +}; + +void da850_init_cpufreq_table(struct cpufreq_frequency_table **table) +{ + *table = &da850_freq_table[0]; +} + static struct davinci_soc_info davinci_soc_info_da850 = { .io_desc = da850_io_desc, .io_desc_num = ARRAY_SIZE(da850_io_desc), @@ -623,9 +687,87 @@ static struct davinci_soc_info davinci_soc_info_da850 = { .gpio_irq = IRQ_DA8XX_GPIO0, .serial_dev = &da8xx_serial_device, .emac_pdata = &da8xx_emac_pdata, + .init_cpufreq_table = da850_init_cpufreq_table, }; +static int da850_round_armrate(struct clk *clk, unsigned long rate) +{ + int i, ret = 0, diff; + unsigned int best = (unsigned int) -1; + + rate /= 1000; /* convert to kHz */ + + for (i = 0; da850_freq_table[i].frequency != CPUFREQ_TABLE_END; i++) { + diff = da850_freq_table[i].frequency - rate; + if (diff < 0) + diff = -diff; + + if (diff < best) { + best = diff; + ret = da850_freq_table[i].frequency; + } + } + + return ret * 1000; +} + +static int da850_set_armrate(struct clk *clk, unsigned long rate) +{ + int i, ret; + unsigned int prediv, mult, postdiv; + struct da850_opp *opp; + struct clk *pllclk = &pll0_clk; + struct pll_data *pll = pllclk->pll_data; + + /* convert to KHz */ + rate /= 1000; + + for (i = 0; da850_freq_table[i].frequency != CPUFREQ_TABLE_END; i++) { + if (rate == da850_freq_table[i].frequency) + break; + } + + if (da850_freq_table[i].frequency == CPUFREQ_TABLE_END) { + printk(KERN_WARNING "%s: Unsupported ARM clock rate %ld\n", + __func__, rate); + return -EINVAL; + } + + opp = (struct da850_opp *) da850_freq_table[i].index; + prediv = opp->prediv; + mult = opp->mult; + postdiv = opp->postdiv; + + /* Unlock writing to PLL registers */ + __raw_writel(__raw_readl(IO_ADDRESS(DA8XX_CFGCHIP0_REG)) & ~BIT(4), + IO_ADDRESS(DA8XX_CFGCHIP0_REG)); + + ret = davinci_set_pllrate(pll, prediv, mult, postdiv); + if (ret) + return ret; + + /* Propogate new rate */ + pllclk->rate = pllclk->parent->rate; + pllclk->rate /= prediv; + pllclk->rate *= mult; + pllclk->rate /= postdiv; + + /* FIXME: unnecessarily re-calculates rates for PLL1 as well */ + davinci_clk_recalc_rates(da850_clks); + + return 0; +} + void __init da850_init(void) { davinci_common_init(&davinci_soc_info_da850); + + /* + * set Async3 clock source to come from PLL1 so PLL0 frequency changes + * dont affect as many peripherals as possible. + * Note: This changes the clock source for UART1/2. So, low level debug + * will garble beyond this point if the source rate changes. + */ + __raw_writel(__raw_readl(IO_ADDRESS(DA8XX_CFGCHIP3_REG)) | BIT(4), + IO_ADDRESS(DA8XX_CFGCHIP3_REG)); } diff --git a/arch/arm/mach-davinci/include/mach/da8xx.h b/arch/arm/mach-davinci/include/mach/da8xx.h index a8cb570..41ab824 100644 --- a/arch/arm/mach-davinci/include/mach/da8xx.h +++ b/arch/arm/mach-davinci/include/mach/da8xx.h @@ -28,10 +28,12 @@ #define DA8XX_CP_INTC_VIRT (IO_VIRT - DA8XX_CP_INTC_SIZE - SZ_4K) #define DA8XX_BOOT_CFG_BASE (IO_PHYS + 0x14000) +#define DA8XX_JTAG_ID_REG (DA8XX_BOOT_CFG_BASE + 0x18) +#define DA8XX_CFGCHIP0_REG (DA8XX_BOOT_CFG_BASE + 0x17c) +#define DA8XX_CFGCHIP3_REG (DA8XX_BOOT_CFG_BASE + 0x188) #define DA8XX_PSC0_BASE 0x01c10000 #define DA8XX_PLL0_BASE 0x01c11000 -#define DA8XX_JTAG_ID_REG 0x01c14018 #define DA8XX_TIMER64P0_BASE 0x01c20000 #define DA8XX_TIMER64P1_BASE 0x01c21000 #define DA8XX_GPIO_BASE 0x01e26000