aboutsummaryrefslogtreecommitdiffstats
path: root/arch/arm/mach-davinci
diff options
context:
space:
mode:
authorSekhar Nori <nsekhar@ti.com>2009-09-22 11:44:01 -0400
committerKevin Hilman <khilman@deeprootsystems.com>2009-11-25 13:21:29 -0500
commit683b1e1f0e6f7b2690c0ce76751ba8f26f0235c6 (patch)
tree2b8c1c9cc6067ee1dfca8d9bd9af188f6dd22193 /arch/arm/mach-davinci
parent6601b8030de3e9c29930684eeac15302a59f991a (diff)
davinci: DA850/OMAP-L138: add frequency scaling support
Adds basic frequency scaling support for DA850/OMAP-L138. Currently, frequency scaling only on PLL0 is supported. No scaling of PLL1 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 OPP defintions assume clock input of 24MHz to the SoC. This is inline with hardcoding of input frequency in the <soc>.c files. At some point this will need to move into board dependent code as new boards appear with a different reference clock. Tested on OMAP-L138 EVM with ondemand governer and a shell script to vary processor load. Signed-off-by: Sekhar Nori <nsekhar@ti.com> Signed-off-by: Kevin Hilman <khilman@deeprootsystems.com>
Diffstat (limited to 'arch/arm/mach-davinci')
-rw-r--r--arch/arm/mach-davinci/da850.c153
-rw-r--r--arch/arm/mach-davinci/include/mach/da8xx.h2
2 files changed, 155 insertions, 0 deletions
diff --git a/arch/arm/mach-davinci/da850.c b/arch/arm/mach-davinci/da850.c
index a62863c57459..49dcc71168c7 100644
--- a/arch/arm/mach-davinci/da850.c
+++ b/arch/arm/mach-davinci/da850.c
@@ -15,6 +15,7 @@
15#include <linux/init.h> 15#include <linux/init.h>
16#include <linux/clk.h> 16#include <linux/clk.h>
17#include <linux/platform_device.h> 17#include <linux/platform_device.h>
18#include <linux/cpufreq.h>
18 19
19#include <asm/mach/map.h> 20#include <asm/mach/map.h>
20 21
@@ -26,6 +27,7 @@
26#include <mach/common.h> 27#include <mach/common.h>
27#include <mach/time.h> 28#include <mach/time.h>
28#include <mach/da8xx.h> 29#include <mach/da8xx.h>
30#include <mach/cpufreq.h>
29 31
30#include "clock.h" 32#include "clock.h"
31#include "mux.h" 33#include "mux.h"
@@ -40,6 +42,11 @@
40#define DA850_REF_FREQ 24000000 42#define DA850_REF_FREQ 24000000
41 43
42#define CFGCHIP3_ASYNC3_CLKSRC BIT(4) 44#define CFGCHIP3_ASYNC3_CLKSRC BIT(4)
45#define CFGCHIP0_PLL_MASTER_LOCK BIT(4)
46
47static int da850_set_armrate(struct clk *clk, unsigned long rate);
48static int da850_round_armrate(struct clk *clk, unsigned long rate);
49static int da850_set_pll0rate(struct clk *clk, unsigned long armrate);
43 50
44static struct pll_data pll0_data = { 51static struct pll_data pll0_data = {
45 .num = 1, 52 .num = 1,
@@ -57,6 +64,7 @@ static struct clk pll0_clk = {
57 .parent = &ref_clk, 64 .parent = &ref_clk,
58 .pll_data = &pll0_data, 65 .pll_data = &pll0_data,
59 .flags = CLK_PLL, 66 .flags = CLK_PLL,
67 .set_rate = da850_set_pll0rate,
60}; 68};
61 69
62static struct clk pll0_aux_clk = { 70static struct clk pll0_aux_clk = {
@@ -283,6 +291,8 @@ static struct clk arm_clk = {
283 .parent = &pll0_sysclk6, 291 .parent = &pll0_sysclk6,
284 .lpsc = DA8XX_LPSC0_ARM, 292 .lpsc = DA8XX_LPSC0_ARM,
285 .flags = ALWAYS_ENABLED, 293 .flags = ALWAYS_ENABLED,
294 .set_rate = da850_set_armrate,
295 .round_rate = da850_round_armrate,
286}; 296};
287 297
288static struct clk rmii_clk = { 298static struct clk rmii_clk = {
@@ -820,6 +830,149 @@ static void da850_set_async3_src(int pllnum)
820 __raw_writel(v, DA8XX_SYSCFG_VIRT(DA8XX_CFGCHIP3_REG)); 830 __raw_writel(v, DA8XX_SYSCFG_VIRT(DA8XX_CFGCHIP3_REG));
821} 831}
822 832
833#ifdef CONFIG_CPU_FREQ
834/*
835 * Notes:
836 * According to the TRM, minimum PLLM results in maximum power savings.
837 * The OPP definitions below should keep the PLLM as low as possible.
838 *
839 * The output of the PLLM must be between 400 to 600 MHz.
840 * This rules out prediv of anything but divide-by-one for 24Mhz OSC input.
841 */
842struct da850_opp {
843 unsigned int freq; /* in KHz */
844 unsigned int prediv;
845 unsigned int mult;
846 unsigned int postdiv;
847};
848
849static const struct da850_opp da850_opp_300 = {
850 .freq = 300000,
851 .prediv = 1,
852 .mult = 25,
853 .postdiv = 2,
854};
855
856static const struct da850_opp da850_opp_200 = {
857 .freq = 200000,
858 .prediv = 1,
859 .mult = 25,
860 .postdiv = 3,
861};
862
863static const struct da850_opp da850_opp_96 = {
864 .freq = 96000,
865 .prediv = 1,
866 .mult = 20,
867 .postdiv = 5,
868};
869
870#define OPP(freq) \
871 { \
872 .index = (unsigned int) &da850_opp_##freq, \
873 .frequency = freq * 1000, \
874 }
875
876static struct cpufreq_frequency_table da850_freq_table[] = {
877 OPP(300),
878 OPP(200),
879 OPP(96),
880 {
881 .index = 0,
882 .frequency = CPUFREQ_TABLE_END,
883 },
884};
885
886static struct davinci_cpufreq_config cpufreq_info = {
887 .freq_table = &da850_freq_table[0],
888};
889
890static struct platform_device da850_cpufreq_device = {
891 .name = "cpufreq-davinci",
892 .dev = {
893 .platform_data = &cpufreq_info,
894 },
895};
896
897int __init da850_register_cpufreq(void)
898{
899 return platform_device_register(&da850_cpufreq_device);
900}
901
902static int da850_round_armrate(struct clk *clk, unsigned long rate)
903{
904 int i, ret = 0, diff;
905 unsigned int best = (unsigned int) -1;
906
907 rate /= 1000; /* convert to kHz */
908
909 for (i = 0; da850_freq_table[i].frequency != CPUFREQ_TABLE_END; i++) {
910 diff = da850_freq_table[i].frequency - rate;
911 if (diff < 0)
912 diff = -diff;
913
914 if (diff < best) {
915 best = diff;
916 ret = da850_freq_table[i].frequency;
917 }
918 }
919
920 return ret * 1000;
921}
922
923static int da850_set_armrate(struct clk *clk, unsigned long index)
924{
925 struct clk *pllclk = &pll0_clk;
926
927 return clk_set_rate(pllclk, index);
928}
929
930static int da850_set_pll0rate(struct clk *clk, unsigned long index)
931{
932 unsigned int prediv, mult, postdiv;
933 struct da850_opp *opp;
934 struct pll_data *pll = clk->pll_data;
935 unsigned int v;
936 int ret;
937
938 opp = (struct da850_opp *) da850_freq_table[index].index;
939 prediv = opp->prediv;
940 mult = opp->mult;
941 postdiv = opp->postdiv;
942
943 /* Unlock writing to PLL registers */
944 v = __raw_readl(DA8XX_SYSCFG_VIRT(DA8XX_CFGCHIP0_REG));
945 v &= ~CFGCHIP0_PLL_MASTER_LOCK;
946 __raw_writel(v, DA8XX_SYSCFG_VIRT(DA8XX_CFGCHIP0_REG));
947
948 ret = davinci_set_pllrate(pll, prediv, mult, postdiv);
949 if (WARN_ON(ret))
950 return ret;
951
952 return 0;
953}
954#else
955int __init da850_register_cpufreq(void)
956{
957 return 0;
958}
959
960static int da850_set_armrate(struct clk *clk, unsigned long rate)
961{
962 return -EINVAL;
963}
964
965static int da850_set_pll0rate(struct clk *clk, unsigned long armrate)
966{
967 return -EINVAL;
968}
969
970static int da850_round_armrate(struct clk *clk, unsigned long rate)
971{
972 return clk->rate;
973}
974#endif
975
823static struct davinci_soc_info davinci_soc_info_da850 = { 976static struct davinci_soc_info davinci_soc_info_da850 = {
824 .io_desc = da850_io_desc, 977 .io_desc = da850_io_desc,
825 .io_desc_num = ARRAY_SIZE(da850_io_desc), 978 .io_desc_num = ARRAY_SIZE(da850_io_desc),
diff --git a/arch/arm/mach-davinci/include/mach/da8xx.h b/arch/arm/mach-davinci/include/mach/da8xx.h
index 3b7527324bf4..401bf93fd32f 100644
--- a/arch/arm/mach-davinci/include/mach/da8xx.h
+++ b/arch/arm/mach-davinci/include/mach/da8xx.h
@@ -37,6 +37,7 @@ extern void __iomem *da8xx_syscfg_base;
37#define DA8XX_SYSCFG_BASE (IO_PHYS + 0x14000) 37#define DA8XX_SYSCFG_BASE (IO_PHYS + 0x14000)
38#define DA8XX_SYSCFG_VIRT(x) (da8xx_syscfg_base + (x)) 38#define DA8XX_SYSCFG_VIRT(x) (da8xx_syscfg_base + (x))
39#define DA8XX_JTAG_ID_REG 0x18 39#define DA8XX_JTAG_ID_REG 0x18
40#define DA8XX_CFGCHIP0_REG 0x17c
40#define DA8XX_CFGCHIP2_REG 0x184 41#define DA8XX_CFGCHIP2_REG 0x184
41#define DA8XX_CFGCHIP3_REG 0x188 42#define DA8XX_CFGCHIP3_REG 0x188
42 43
@@ -85,6 +86,7 @@ int da8xx_register_lcdc(struct da8xx_lcdc_platform_data *pdata);
85int da8xx_register_mmcsd0(struct davinci_mmc_config *config); 86int da8xx_register_mmcsd0(struct davinci_mmc_config *config);
86void __init da8xx_register_mcasp(int id, struct snd_platform_data *pdata); 87void __init da8xx_register_mcasp(int id, struct snd_platform_data *pdata);
87int da8xx_register_rtc(void); 88int da8xx_register_rtc(void);
89int da850_register_cpufreq(void);
88 90
89extern struct platform_device da8xx_serial_device; 91extern struct platform_device da8xx_serial_device;
90extern struct emac_platform_data da8xx_emac_pdata; 92extern struct emac_platform_data da8xx_emac_pdata;