clock.c 7.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330
  1. /*
  2. * Copyright (C) 2009 Samsung Electronics
  3. * Minkyu Kang <mk7.kang@samsung.com>
  4. * Heungjun Kim <riverful.kim@samsung.com>
  5. *
  6. * See file CREDITS for list of people who contributed to this
  7. * project.
  8. *
  9. * This program is free software; you can redistribute it and/or
  10. * modify it under the terms of the GNU General Public License as
  11. * published by the Free Software Foundation; either version 2 of
  12. * the License, or (at your option) any later version.
  13. *
  14. * This program is distributed in the hope that it will be useful,
  15. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  16. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  17. * GNU General Public License for more details.
  18. *
  19. * You should have received a copy of the GNU General Public License
  20. * along with this program; if not, write to the Free Software
  21. * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
  22. * MA 02111-1307 USA
  23. */
  24. #include <common.h>
  25. #include <asm/io.h>
  26. #include <asm/arch/clock.h>
  27. #include <asm/arch/clk.h>
  28. #define CLK_M 0
  29. #define CLK_D 1
  30. #define CLK_P 2
  31. #ifndef CONFIG_SYS_CLK_FREQ_C100
  32. #define CONFIG_SYS_CLK_FREQ_C100 12000000
  33. #endif
  34. #ifndef CONFIG_SYS_CLK_FREQ_C110
  35. #define CONFIG_SYS_CLK_FREQ_C110 24000000
  36. #endif
  37. unsigned long (*get_uart_clk)(int dev_index);
  38. unsigned long (*get_pwm_clk)(void);
  39. unsigned long (*get_arm_clk)(void);
  40. unsigned long (*get_pll_clk)(int);
  41. /* s5pc110: return pll clock frequency */
  42. static unsigned long s5pc100_get_pll_clk(int pllreg)
  43. {
  44. struct s5pc100_clock *clk =
  45. (struct s5pc100_clock *)samsung_get_base_clock();
  46. unsigned long r, m, p, s, mask, fout;
  47. unsigned int freq;
  48. switch (pllreg) {
  49. case APLL:
  50. r = readl(&clk->apll_con);
  51. break;
  52. case MPLL:
  53. r = readl(&clk->mpll_con);
  54. break;
  55. case EPLL:
  56. r = readl(&clk->epll_con);
  57. break;
  58. case HPLL:
  59. r = readl(&clk->hpll_con);
  60. break;
  61. default:
  62. printf("Unsupported PLL (%d)\n", pllreg);
  63. return 0;
  64. }
  65. /*
  66. * APLL_CON: MIDV [25:16]
  67. * MPLL_CON: MIDV [23:16]
  68. * EPLL_CON: MIDV [23:16]
  69. * HPLL_CON: MIDV [23:16]
  70. */
  71. if (pllreg == APLL)
  72. mask = 0x3ff;
  73. else
  74. mask = 0x0ff;
  75. m = (r >> 16) & mask;
  76. /* PDIV [13:8] */
  77. p = (r >> 8) & 0x3f;
  78. /* SDIV [2:0] */
  79. s = r & 0x7;
  80. /* FOUT = MDIV * FIN / (PDIV * 2^SDIV) */
  81. freq = CONFIG_SYS_CLK_FREQ_C100;
  82. fout = m * (freq / (p * (1 << s)));
  83. return fout;
  84. }
  85. /* s5pc100: return pll clock frequency */
  86. static unsigned long s5pc110_get_pll_clk(int pllreg)
  87. {
  88. struct s5pc110_clock *clk =
  89. (struct s5pc110_clock *)samsung_get_base_clock();
  90. unsigned long r, m, p, s, mask, fout;
  91. unsigned int freq;
  92. switch (pllreg) {
  93. case APLL:
  94. r = readl(&clk->apll_con);
  95. break;
  96. case MPLL:
  97. r = readl(&clk->mpll_con);
  98. break;
  99. case EPLL:
  100. r = readl(&clk->epll_con);
  101. break;
  102. case VPLL:
  103. r = readl(&clk->vpll_con);
  104. break;
  105. default:
  106. printf("Unsupported PLL (%d)\n", pllreg);
  107. return 0;
  108. }
  109. /*
  110. * APLL_CON: MIDV [25:16]
  111. * MPLL_CON: MIDV [25:16]
  112. * EPLL_CON: MIDV [24:16]
  113. * VPLL_CON: MIDV [24:16]
  114. */
  115. if (pllreg == APLL || pllreg == MPLL)
  116. mask = 0x3ff;
  117. else
  118. mask = 0x1ff;
  119. m = (r >> 16) & mask;
  120. /* PDIV [13:8] */
  121. p = (r >> 8) & 0x3f;
  122. /* SDIV [2:0] */
  123. s = r & 0x7;
  124. freq = CONFIG_SYS_CLK_FREQ_C110;
  125. if (pllreg == APLL) {
  126. if (s < 1)
  127. s = 1;
  128. /* FOUT = MDIV * FIN / (PDIV * 2^(SDIV - 1)) */
  129. fout = m * (freq / (p * (1 << (s - 1))));
  130. } else
  131. /* FOUT = MDIV * FIN / (PDIV * 2^SDIV) */
  132. fout = m * (freq / (p * (1 << s)));
  133. return fout;
  134. }
  135. /* s5pc110: return ARM clock frequency */
  136. static unsigned long s5pc110_get_arm_clk(void)
  137. {
  138. struct s5pc110_clock *clk =
  139. (struct s5pc110_clock *)samsung_get_base_clock();
  140. unsigned long div;
  141. unsigned long dout_apll, armclk;
  142. unsigned int apll_ratio;
  143. div = readl(&clk->div0);
  144. /* APLL_RATIO: [2:0] */
  145. apll_ratio = div & 0x7;
  146. dout_apll = get_pll_clk(APLL) / (apll_ratio + 1);
  147. armclk = dout_apll;
  148. return armclk;
  149. }
  150. /* s5pc100: return ARM clock frequency */
  151. static unsigned long s5pc100_get_arm_clk(void)
  152. {
  153. struct s5pc100_clock *clk =
  154. (struct s5pc100_clock *)samsung_get_base_clock();
  155. unsigned long div;
  156. unsigned long dout_apll, armclk;
  157. unsigned int apll_ratio, arm_ratio;
  158. div = readl(&clk->div0);
  159. /* ARM_RATIO: [6:4] */
  160. arm_ratio = (div >> 4) & 0x7;
  161. /* APLL_RATIO: [0] */
  162. apll_ratio = div & 0x1;
  163. dout_apll = get_pll_clk(APLL) / (apll_ratio + 1);
  164. armclk = dout_apll / (arm_ratio + 1);
  165. return armclk;
  166. }
  167. /* s5pc100: return HCLKD0 frequency */
  168. static unsigned long get_hclk(void)
  169. {
  170. struct s5pc100_clock *clk =
  171. (struct s5pc100_clock *)samsung_get_base_clock();
  172. unsigned long hclkd0;
  173. uint div, d0_bus_ratio;
  174. div = readl(&clk->div0);
  175. /* D0_BUS_RATIO: [10:8] */
  176. d0_bus_ratio = (div >> 8) & 0x7;
  177. hclkd0 = get_arm_clk() / (d0_bus_ratio + 1);
  178. return hclkd0;
  179. }
  180. /* s5pc100: return PCLKD1 frequency */
  181. static unsigned long get_pclkd1(void)
  182. {
  183. struct s5pc100_clock *clk =
  184. (struct s5pc100_clock *)samsung_get_base_clock();
  185. unsigned long d1_bus, pclkd1;
  186. uint div, d1_bus_ratio, pclkd1_ratio;
  187. div = readl(&clk->div0);
  188. /* D1_BUS_RATIO: [14:12] */
  189. d1_bus_ratio = (div >> 12) & 0x7;
  190. /* PCLKD1_RATIO: [18:16] */
  191. pclkd1_ratio = (div >> 16) & 0x7;
  192. /* ASYNC Mode */
  193. d1_bus = get_pll_clk(MPLL) / (d1_bus_ratio + 1);
  194. pclkd1 = d1_bus / (pclkd1_ratio + 1);
  195. return pclkd1;
  196. }
  197. /* s5pc110: return HCLKs frequency */
  198. static unsigned long get_hclk_sys(int dom)
  199. {
  200. struct s5pc110_clock *clk =
  201. (struct s5pc110_clock *)samsung_get_base_clock();
  202. unsigned long hclk;
  203. unsigned int div;
  204. unsigned int offset;
  205. unsigned int hclk_sys_ratio;
  206. if (dom == CLK_M)
  207. return get_hclk();
  208. div = readl(&clk->div0);
  209. /*
  210. * HCLK_MSYS_RATIO: [10:8]
  211. * HCLK_DSYS_RATIO: [19:16]
  212. * HCLK_PSYS_RATIO: [27:24]
  213. */
  214. offset = 8 + (dom << 0x3);
  215. hclk_sys_ratio = (div >> offset) & 0xf;
  216. hclk = get_pll_clk(MPLL) / (hclk_sys_ratio + 1);
  217. return hclk;
  218. }
  219. /* s5pc110: return PCLKs frequency */
  220. static unsigned long get_pclk_sys(int dom)
  221. {
  222. struct s5pc110_clock *clk =
  223. (struct s5pc110_clock *)samsung_get_base_clock();
  224. unsigned long pclk;
  225. unsigned int div;
  226. unsigned int offset;
  227. unsigned int pclk_sys_ratio;
  228. div = readl(&clk->div0);
  229. /*
  230. * PCLK_MSYS_RATIO: [14:12]
  231. * PCLK_DSYS_RATIO: [22:20]
  232. * PCLK_PSYS_RATIO: [30:28]
  233. */
  234. offset = 12 + (dom << 0x3);
  235. pclk_sys_ratio = (div >> offset) & 0x7;
  236. pclk = get_hclk_sys(dom) / (pclk_sys_ratio + 1);
  237. return pclk;
  238. }
  239. /* s5pc110: return peripheral clock frequency */
  240. static unsigned long s5pc110_get_pclk(void)
  241. {
  242. return get_pclk_sys(CLK_P);
  243. }
  244. /* s5pc100: return peripheral clock frequency */
  245. static unsigned long s5pc100_get_pclk(void)
  246. {
  247. return get_pclkd1();
  248. }
  249. /* s5pc1xx: return uart clock frequency */
  250. static unsigned long s5pc1xx_get_uart_clk(int dev_index)
  251. {
  252. if (cpu_is_s5pc110())
  253. return s5pc110_get_pclk();
  254. else
  255. return s5pc100_get_pclk();
  256. }
  257. /* s5pc1xx: return pwm clock frequency */
  258. static unsigned long s5pc1xx_get_pwm_clk(void)
  259. {
  260. if (cpu_is_s5pc110())
  261. return s5pc110_get_pclk();
  262. else
  263. return s5pc100_get_pclk();
  264. }
  265. void s5p_clock_init(void)
  266. {
  267. if (cpu_is_s5pc110()) {
  268. get_pll_clk = s5pc110_get_pll_clk;
  269. get_arm_clk = s5pc110_get_arm_clk;
  270. } else {
  271. get_pll_clk = s5pc100_get_pll_clk;
  272. get_arm_clk = s5pc100_get_arm_clk;
  273. }
  274. get_uart_clk = s5pc1xx_get_uart_clk;
  275. get_pwm_clk = s5pc1xx_get_pwm_clk;
  276. }