diff options
Diffstat (limited to 'arch/arm/mach-s5pv210/clock.c')
-rw-r--r-- | arch/arm/mach-s5pv210/clock.c | 207 |
1 files changed, 195 insertions, 12 deletions
diff --git a/arch/arm/mach-s5pv210/clock.c b/arch/arm/mach-s5pv210/clock.c index d562670e1b0b..019c3a69b0e4 100644 --- a/arch/arm/mach-s5pv210/clock.c +++ b/arch/arm/mach-s5pv210/clock.c | |||
@@ -31,6 +31,8 @@ | |||
31 | #include <plat/clock-clksrc.h> | 31 | #include <plat/clock-clksrc.h> |
32 | #include <plat/s5pv210.h> | 32 | #include <plat/s5pv210.h> |
33 | 33 | ||
34 | static unsigned long xtal; | ||
35 | |||
34 | static struct clksrc_clk clk_mout_apll = { | 36 | static struct clksrc_clk clk_mout_apll = { |
35 | .clk = { | 37 | .clk = { |
36 | .name = "mout_apll", | 38 | .name = "mout_apll", |
@@ -259,6 +261,36 @@ static struct clksrc_clk clk_sclk_vpll = { | |||
259 | .reg_src = { .reg = S5P_CLK_SRC0, .shift = 12, .size = 1 }, | 261 | .reg_src = { .reg = S5P_CLK_SRC0, .shift = 12, .size = 1 }, |
260 | }; | 262 | }; |
261 | 263 | ||
264 | static struct clk *clkset_moutdmc0src_list[] = { | ||
265 | [0] = &clk_sclk_a2m.clk, | ||
266 | [1] = &clk_mout_mpll.clk, | ||
267 | [2] = NULL, | ||
268 | [3] = NULL, | ||
269 | }; | ||
270 | |||
271 | static struct clksrc_sources clkset_moutdmc0src = { | ||
272 | .sources = clkset_moutdmc0src_list, | ||
273 | .nr_sources = ARRAY_SIZE(clkset_moutdmc0src_list), | ||
274 | }; | ||
275 | |||
276 | static struct clksrc_clk clk_mout_dmc0 = { | ||
277 | .clk = { | ||
278 | .name = "mout_dmc0", | ||
279 | .id = -1, | ||
280 | }, | ||
281 | .sources = &clkset_moutdmc0src, | ||
282 | .reg_src = { .reg = S5P_CLK_SRC6, .shift = 24, .size = 2 }, | ||
283 | }; | ||
284 | |||
285 | static struct clksrc_clk clk_sclk_dmc0 = { | ||
286 | .clk = { | ||
287 | .name = "sclk_dmc0", | ||
288 | .id = -1, | ||
289 | .parent = &clk_mout_dmc0.clk, | ||
290 | }, | ||
291 | .reg_div = { .reg = S5P_CLK_DIV6, .shift = 28, .size = 4 }, | ||
292 | }; | ||
293 | |||
262 | static unsigned long s5pv210_clk_imem_get_rate(struct clk *clk) | 294 | static unsigned long s5pv210_clk_imem_get_rate(struct clk *clk) |
263 | { | 295 | { |
264 | return clk_get_rate(clk->parent) / 2; | 296 | return clk_get_rate(clk->parent) / 2; |
@@ -268,8 +300,29 @@ static struct clk_ops clk_hclk_imem_ops = { | |||
268 | .get_rate = s5pv210_clk_imem_get_rate, | 300 | .get_rate = s5pv210_clk_imem_get_rate, |
269 | }; | 301 | }; |
270 | 302 | ||
303 | static unsigned long s5pv210_clk_fout_apll_get_rate(struct clk *clk) | ||
304 | { | ||
305 | return s5p_get_pll45xx(xtal, __raw_readl(S5P_APLL_CON), pll_4508); | ||
306 | } | ||
307 | |||
308 | static struct clk_ops clk_fout_apll_ops = { | ||
309 | .get_rate = s5pv210_clk_fout_apll_get_rate, | ||
310 | }; | ||
311 | |||
271 | static struct clk init_clocks_disable[] = { | 312 | static struct clk init_clocks_disable[] = { |
272 | { | 313 | { |
314 | .name = "pdma", | ||
315 | .id = 0, | ||
316 | .parent = &clk_hclk_psys.clk, | ||
317 | .enable = s5pv210_clk_ip0_ctrl, | ||
318 | .ctrlbit = (1 << 3), | ||
319 | }, { | ||
320 | .name = "pdma", | ||
321 | .id = 1, | ||
322 | .parent = &clk_hclk_psys.clk, | ||
323 | .enable = s5pv210_clk_ip0_ctrl, | ||
324 | .ctrlbit = (1 << 4), | ||
325 | }, { | ||
273 | .name = "rot", | 326 | .name = "rot", |
274 | .id = -1, | 327 | .id = -1, |
275 | .parent = &clk_hclk_dsys.clk, | 328 | .parent = &clk_hclk_dsys.clk, |
@@ -431,6 +484,12 @@ static struct clk init_clocks_disable[] = { | |||
431 | .parent = &clk_p, | 484 | .parent = &clk_p, |
432 | .enable = s5pv210_clk_ip3_ctrl, | 485 | .enable = s5pv210_clk_ip3_ctrl, |
433 | .ctrlbit = (1 << 6), | 486 | .ctrlbit = (1 << 6), |
487 | }, { | ||
488 | .name = "spdif", | ||
489 | .id = -1, | ||
490 | .parent = &clk_p, | ||
491 | .enable = s5pv210_clk_ip3_ctrl, | ||
492 | .ctrlbit = (1 << 0), | ||
434 | }, | 493 | }, |
435 | }; | 494 | }; |
436 | 495 | ||
@@ -660,6 +719,53 @@ static struct clksrc_sources clkset_sclk_spdif = { | |||
660 | .nr_sources = ARRAY_SIZE(clkset_sclk_spdif_list), | 719 | .nr_sources = ARRAY_SIZE(clkset_sclk_spdif_list), |
661 | }; | 720 | }; |
662 | 721 | ||
722 | static int s5pv210_spdif_set_rate(struct clk *clk, unsigned long rate) | ||
723 | { | ||
724 | struct clk *pclk; | ||
725 | int ret; | ||
726 | |||
727 | pclk = clk_get_parent(clk); | ||
728 | if (IS_ERR(pclk)) | ||
729 | return -EINVAL; | ||
730 | |||
731 | ret = pclk->ops->set_rate(pclk, rate); | ||
732 | clk_put(pclk); | ||
733 | |||
734 | return ret; | ||
735 | } | ||
736 | |||
737 | static unsigned long s5pv210_spdif_get_rate(struct clk *clk) | ||
738 | { | ||
739 | struct clk *pclk; | ||
740 | int rate; | ||
741 | |||
742 | pclk = clk_get_parent(clk); | ||
743 | if (IS_ERR(pclk)) | ||
744 | return -EINVAL; | ||
745 | |||
746 | rate = pclk->ops->get_rate(clk); | ||
747 | clk_put(pclk); | ||
748 | |||
749 | return rate; | ||
750 | } | ||
751 | |||
752 | static struct clk_ops s5pv210_sclk_spdif_ops = { | ||
753 | .set_rate = s5pv210_spdif_set_rate, | ||
754 | .get_rate = s5pv210_spdif_get_rate, | ||
755 | }; | ||
756 | |||
757 | static struct clksrc_clk clk_sclk_spdif = { | ||
758 | .clk = { | ||
759 | .name = "sclk_spdif", | ||
760 | .id = -1, | ||
761 | .enable = s5pv210_clk_mask0_ctrl, | ||
762 | .ctrlbit = (1 << 27), | ||
763 | .ops = &s5pv210_sclk_spdif_ops, | ||
764 | }, | ||
765 | .sources = &clkset_sclk_spdif, | ||
766 | .reg_src = { .reg = S5P_CLK_SRC6, .shift = 12, .size = 2 }, | ||
767 | }; | ||
768 | |||
663 | static struct clk *clkset_group2_list[] = { | 769 | static struct clk *clkset_group2_list[] = { |
664 | [0] = &clk_ext_xtal_mux, | 770 | [0] = &clk_ext_xtal_mux, |
665 | [1] = &clk_xusbxti, | 771 | [1] = &clk_xusbxti, |
@@ -744,15 +850,6 @@ static struct clksrc_clk clksrcs[] = { | |||
744 | .sources = &clkset_sclk_mixer, | 850 | .sources = &clkset_sclk_mixer, |
745 | .reg_src = { .reg = S5P_CLK_SRC1, .shift = 4, .size = 1 }, | 851 | .reg_src = { .reg = S5P_CLK_SRC1, .shift = 4, .size = 1 }, |
746 | }, { | 852 | }, { |
747 | .clk = { | ||
748 | .name = "sclk_spdif", | ||
749 | .id = -1, | ||
750 | .enable = s5pv210_clk_mask0_ctrl, | ||
751 | .ctrlbit = (1 << 27), | ||
752 | }, | ||
753 | .sources = &clkset_sclk_spdif, | ||
754 | .reg_src = { .reg = S5P_CLK_SRC6, .shift = 12, .size = 2 }, | ||
755 | }, { | ||
756 | .clk = { | 853 | .clk = { |
757 | .name = "sclk_fimc", | 854 | .name = "sclk_fimc", |
758 | .id = 0, | 855 | .id = 0, |
@@ -953,12 +1050,93 @@ static struct clksrc_clk *sysclks[] = { | |||
953 | &clk_sclk_dac, | 1050 | &clk_sclk_dac, |
954 | &clk_sclk_pixel, | 1051 | &clk_sclk_pixel, |
955 | &clk_sclk_hdmi, | 1052 | &clk_sclk_hdmi, |
1053 | &clk_mout_dmc0, | ||
1054 | &clk_sclk_dmc0, | ||
1055 | &clk_sclk_audio0, | ||
1056 | &clk_sclk_audio1, | ||
1057 | &clk_sclk_audio2, | ||
1058 | &clk_sclk_spdif, | ||
1059 | }; | ||
1060 | |||
1061 | static u32 epll_div[][6] = { | ||
1062 | { 48000000, 0, 48, 3, 3, 0 }, | ||
1063 | { 96000000, 0, 48, 3, 2, 0 }, | ||
1064 | { 144000000, 1, 72, 3, 2, 0 }, | ||
1065 | { 192000000, 0, 48, 3, 1, 0 }, | ||
1066 | { 288000000, 1, 72, 3, 1, 0 }, | ||
1067 | { 32750000, 1, 65, 3, 4, 35127 }, | ||
1068 | { 32768000, 1, 65, 3, 4, 35127 }, | ||
1069 | { 45158400, 0, 45, 3, 3, 10355 }, | ||
1070 | { 45000000, 0, 45, 3, 3, 10355 }, | ||
1071 | { 45158000, 0, 45, 3, 3, 10355 }, | ||
1072 | { 49125000, 0, 49, 3, 3, 9961 }, | ||
1073 | { 49152000, 0, 49, 3, 3, 9961 }, | ||
1074 | { 67737600, 1, 67, 3, 3, 48366 }, | ||
1075 | { 67738000, 1, 67, 3, 3, 48366 }, | ||
1076 | { 73800000, 1, 73, 3, 3, 47710 }, | ||
1077 | { 73728000, 1, 73, 3, 3, 47710 }, | ||
1078 | { 36000000, 1, 32, 3, 4, 0 }, | ||
1079 | { 60000000, 1, 60, 3, 3, 0 }, | ||
1080 | { 72000000, 1, 72, 3, 3, 0 }, | ||
1081 | { 80000000, 1, 80, 3, 3, 0 }, | ||
1082 | { 84000000, 0, 42, 3, 2, 0 }, | ||
1083 | { 50000000, 0, 50, 3, 3, 0 }, | ||
1084 | }; | ||
1085 | |||
1086 | static int s5pv210_epll_set_rate(struct clk *clk, unsigned long rate) | ||
1087 | { | ||
1088 | unsigned int epll_con, epll_con_k; | ||
1089 | unsigned int i; | ||
1090 | |||
1091 | /* Return if nothing changed */ | ||
1092 | if (clk->rate == rate) | ||
1093 | return 0; | ||
1094 | |||
1095 | epll_con = __raw_readl(S5P_EPLL_CON); | ||
1096 | epll_con_k = __raw_readl(S5P_EPLL_CON1); | ||
1097 | |||
1098 | epll_con_k &= ~PLL46XX_KDIV_MASK; | ||
1099 | epll_con &= ~(1 << 27 | | ||
1100 | PLL46XX_MDIV_MASK << PLL46XX_MDIV_SHIFT | | ||
1101 | PLL46XX_PDIV_MASK << PLL46XX_PDIV_SHIFT | | ||
1102 | PLL46XX_SDIV_MASK << PLL46XX_SDIV_SHIFT); | ||
1103 | |||
1104 | for (i = 0; i < ARRAY_SIZE(epll_div); i++) { | ||
1105 | if (epll_div[i][0] == rate) { | ||
1106 | epll_con_k |= epll_div[i][5] << 0; | ||
1107 | epll_con |= (epll_div[i][1] << 27 | | ||
1108 | epll_div[i][2] << PLL46XX_MDIV_SHIFT | | ||
1109 | epll_div[i][3] << PLL46XX_PDIV_SHIFT | | ||
1110 | epll_div[i][4] << PLL46XX_SDIV_SHIFT); | ||
1111 | break; | ||
1112 | } | ||
1113 | } | ||
1114 | |||
1115 | if (i == ARRAY_SIZE(epll_div)) { | ||
1116 | printk(KERN_ERR "%s: Invalid Clock EPLL Frequency\n", | ||
1117 | __func__); | ||
1118 | return -EINVAL; | ||
1119 | } | ||
1120 | |||
1121 | __raw_writel(epll_con, S5P_EPLL_CON); | ||
1122 | __raw_writel(epll_con_k, S5P_EPLL_CON1); | ||
1123 | |||
1124 | printk(KERN_WARNING "EPLL Rate changes from %lu to %lu\n", | ||
1125 | clk->rate, rate); | ||
1126 | |||
1127 | clk->rate = rate; | ||
1128 | |||
1129 | return 0; | ||
1130 | } | ||
1131 | |||
1132 | static struct clk_ops s5pv210_epll_ops = { | ||
1133 | .set_rate = s5pv210_epll_set_rate, | ||
1134 | .get_rate = s5p_epll_get_rate, | ||
956 | }; | 1135 | }; |
957 | 1136 | ||
958 | void __init_or_cpufreq s5pv210_setup_clocks(void) | 1137 | void __init_or_cpufreq s5pv210_setup_clocks(void) |
959 | { | 1138 | { |
960 | struct clk *xtal_clk; | 1139 | struct clk *xtal_clk; |
961 | unsigned long xtal; | ||
962 | unsigned long vpllsrc; | 1140 | unsigned long vpllsrc; |
963 | unsigned long armclk; | 1141 | unsigned long armclk; |
964 | unsigned long hclk_msys; | 1142 | unsigned long hclk_msys; |
@@ -974,6 +1152,10 @@ void __init_or_cpufreq s5pv210_setup_clocks(void) | |||
974 | unsigned int ptr; | 1152 | unsigned int ptr; |
975 | u32 clkdiv0, clkdiv1; | 1153 | u32 clkdiv0, clkdiv1; |
976 | 1154 | ||
1155 | /* Set functions for clk_fout_epll */ | ||
1156 | clk_fout_epll.enable = s5p_epll_enable; | ||
1157 | clk_fout_epll.ops = &s5pv210_epll_ops; | ||
1158 | |||
977 | printk(KERN_DEBUG "%s: registering clocks\n", __func__); | 1159 | printk(KERN_DEBUG "%s: registering clocks\n", __func__); |
978 | 1160 | ||
979 | clkdiv0 = __raw_readl(S5P_CLK_DIV0); | 1161 | clkdiv0 = __raw_readl(S5P_CLK_DIV0); |
@@ -992,11 +1174,12 @@ void __init_or_cpufreq s5pv210_setup_clocks(void) | |||
992 | 1174 | ||
993 | apll = s5p_get_pll45xx(xtal, __raw_readl(S5P_APLL_CON), pll_4508); | 1175 | apll = s5p_get_pll45xx(xtal, __raw_readl(S5P_APLL_CON), pll_4508); |
994 | mpll = s5p_get_pll45xx(xtal, __raw_readl(S5P_MPLL_CON), pll_4502); | 1176 | mpll = s5p_get_pll45xx(xtal, __raw_readl(S5P_MPLL_CON), pll_4502); |
995 | epll = s5p_get_pll45xx(xtal, __raw_readl(S5P_EPLL_CON), pll_4500); | 1177 | epll = s5p_get_pll46xx(xtal, __raw_readl(S5P_EPLL_CON), |
1178 | __raw_readl(S5P_EPLL_CON1), pll_4600); | ||
996 | vpllsrc = clk_get_rate(&clk_vpllsrc.clk); | 1179 | vpllsrc = clk_get_rate(&clk_vpllsrc.clk); |
997 | vpll = s5p_get_pll45xx(vpllsrc, __raw_readl(S5P_VPLL_CON), pll_4502); | 1180 | vpll = s5p_get_pll45xx(vpllsrc, __raw_readl(S5P_VPLL_CON), pll_4502); |
998 | 1181 | ||
999 | clk_fout_apll.rate = apll; | 1182 | clk_fout_apll.ops = &clk_fout_apll_ops; |
1000 | clk_fout_mpll.rate = mpll; | 1183 | clk_fout_mpll.rate = mpll; |
1001 | clk_fout_epll.rate = epll; | 1184 | clk_fout_epll.rate = epll; |
1002 | clk_fout_vpll.rate = vpll; | 1185 | clk_fout_vpll.rate = vpll; |