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; |
