diff options
Diffstat (limited to 'arch/arm/mach-davinci/da850.c')
-rw-r--r-- | arch/arm/mach-davinci/da850.c | 153 |
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 | |||
47 | static int da850_set_armrate(struct clk *clk, unsigned long rate); | ||
48 | static int da850_round_armrate(struct clk *clk, unsigned long rate); | ||
49 | static int da850_set_pll0rate(struct clk *clk, unsigned long armrate); | ||
43 | 50 | ||
44 | static struct pll_data pll0_data = { | 51 | static 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 | ||
62 | static struct clk pll0_aux_clk = { | 70 | static 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 | ||
288 | static struct clk rmii_clk = { | 298 | static 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 | */ | ||
842 | struct da850_opp { | ||
843 | unsigned int freq; /* in KHz */ | ||
844 | unsigned int prediv; | ||
845 | unsigned int mult; | ||
846 | unsigned int postdiv; | ||
847 | }; | ||
848 | |||
849 | static const struct da850_opp da850_opp_300 = { | ||
850 | .freq = 300000, | ||
851 | .prediv = 1, | ||
852 | .mult = 25, | ||
853 | .postdiv = 2, | ||
854 | }; | ||
855 | |||
856 | static const struct da850_opp da850_opp_200 = { | ||
857 | .freq = 200000, | ||
858 | .prediv = 1, | ||
859 | .mult = 25, | ||
860 | .postdiv = 3, | ||
861 | }; | ||
862 | |||
863 | static 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 | |||
876 | static 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 | |||
886 | static struct davinci_cpufreq_config cpufreq_info = { | ||
887 | .freq_table = &da850_freq_table[0], | ||
888 | }; | ||
889 | |||
890 | static struct platform_device da850_cpufreq_device = { | ||
891 | .name = "cpufreq-davinci", | ||
892 | .dev = { | ||
893 | .platform_data = &cpufreq_info, | ||
894 | }, | ||
895 | }; | ||
896 | |||
897 | int __init da850_register_cpufreq(void) | ||
898 | { | ||
899 | return platform_device_register(&da850_cpufreq_device); | ||
900 | } | ||
901 | |||
902 | static 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 | |||
923 | static 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 | |||
930 | static 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 | ||
955 | int __init da850_register_cpufreq(void) | ||
956 | { | ||
957 | return 0; | ||
958 | } | ||
959 | |||
960 | static int da850_set_armrate(struct clk *clk, unsigned long rate) | ||
961 | { | ||
962 | return -EINVAL; | ||
963 | } | ||
964 | |||
965 | static int da850_set_pll0rate(struct clk *clk, unsigned long armrate) | ||
966 | { | ||
967 | return -EINVAL; | ||
968 | } | ||
969 | |||
970 | static int da850_round_armrate(struct clk *clk, unsigned long rate) | ||
971 | { | ||
972 | return clk->rate; | ||
973 | } | ||
974 | #endif | ||
975 | |||
823 | static struct davinci_soc_info davinci_soc_info_da850 = { | 976 | static 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), |