aboutsummaryrefslogtreecommitdiffstats
path: root/arch/arm/mach-davinci/da850.c
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/da850.c
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/da850.c')
-rw-r--r--arch/arm/mach-davinci/da850.c153
1 files changed, 153 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),