clock.c 6.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303
  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_pclk)(void);
  38. unsigned long (*get_arm_clk)(void);
  39. unsigned long (*get_pll_clk)(int);
  40. /* s5pc110: return pll clock frequency */
  41. static unsigned long s5pc100_get_pll_clk(int pllreg)
  42. {
  43. struct s5pc100_clock *clk = (struct s5pc100_clock *)S5PC1XX_CLOCK_BASE;
  44. unsigned long r, m, p, s, mask, fout;
  45. unsigned int freq;
  46. switch (pllreg) {
  47. case APLL:
  48. r = readl(&clk->apll_con);
  49. break;
  50. case MPLL:
  51. r = readl(&clk->mpll_con);
  52. break;
  53. case EPLL:
  54. r = readl(&clk->epll_con);
  55. break;
  56. case HPLL:
  57. r = readl(&clk->hpll_con);
  58. break;
  59. default:
  60. printf("Unsupported PLL (%d)\n", pllreg);
  61. return 0;
  62. }
  63. /*
  64. * APLL_CON: MIDV [25:16]
  65. * MPLL_CON: MIDV [23:16]
  66. * EPLL_CON: MIDV [23:16]
  67. * HPLL_CON: MIDV [23:16]
  68. */
  69. if (pllreg == APLL)
  70. mask = 0x3ff;
  71. else
  72. mask = 0x0ff;
  73. m = (r >> 16) & mask;
  74. /* PDIV [13:8] */
  75. p = (r >> 8) & 0x3f;
  76. /* SDIV [2:0] */
  77. s = r & 0x7;
  78. /* FOUT = MDIV * FIN / (PDIV * 2^SDIV) */
  79. freq = CONFIG_SYS_CLK_FREQ_C100;
  80. fout = m * (freq / (p * (1 << s)));
  81. return fout;
  82. }
  83. /* s5pc100: return pll clock frequency */
  84. static unsigned long s5pc110_get_pll_clk(int pllreg)
  85. {
  86. struct s5pc110_clock *clk = (struct s5pc110_clock *)S5PC1XX_CLOCK_BASE;
  87. unsigned long r, m, p, s, mask, fout;
  88. unsigned int freq;
  89. switch (pllreg) {
  90. case APLL:
  91. r = readl(&clk->apll_con);
  92. break;
  93. case MPLL:
  94. r = readl(&clk->mpll_con);
  95. break;
  96. case EPLL:
  97. r = readl(&clk->epll_con);
  98. break;
  99. case VPLL:
  100. r = readl(&clk->vpll_con);
  101. break;
  102. default:
  103. printf("Unsupported PLL (%d)\n", pllreg);
  104. return 0;
  105. }
  106. /*
  107. * APLL_CON: MIDV [25:16]
  108. * MPLL_CON: MIDV [25:16]
  109. * EPLL_CON: MIDV [24:16]
  110. * VPLL_CON: MIDV [24:16]
  111. */
  112. if (pllreg == APLL || pllreg == MPLL)
  113. mask = 0x3ff;
  114. else
  115. mask = 0x1ff;
  116. m = (r >> 16) & mask;
  117. /* PDIV [13:8] */
  118. p = (r >> 8) & 0x3f;
  119. /* SDIV [2:0] */
  120. s = r & 0x7;
  121. freq = CONFIG_SYS_CLK_FREQ_C110;
  122. if (pllreg == APLL) {
  123. if (s < 1)
  124. s = 1;
  125. /* FOUT = MDIV * FIN / (PDIV * 2^(SDIV - 1)) */
  126. fout = m * (freq / (p * (1 << (s - 1))));
  127. } else
  128. /* FOUT = MDIV * FIN / (PDIV * 2^SDIV) */
  129. fout = m * (freq / (p * (1 << s)));
  130. return fout;
  131. }
  132. /* s5pc110: return ARM clock frequency */
  133. static unsigned long s5pc110_get_arm_clk(void)
  134. {
  135. struct s5pc110_clock *clk = (struct s5pc110_clock *)S5PC1XX_CLOCK_BASE;
  136. unsigned long div;
  137. unsigned long dout_apll, armclk;
  138. unsigned int apll_ratio;
  139. div = readl(&clk->div0);
  140. /* APLL_RATIO: [2:0] */
  141. apll_ratio = div & 0x7;
  142. dout_apll = get_pll_clk(APLL) / (apll_ratio + 1);
  143. armclk = dout_apll;
  144. return armclk;
  145. }
  146. /* s5pc100: return ARM clock frequency */
  147. static unsigned long s5pc100_get_arm_clk(void)
  148. {
  149. struct s5pc100_clock *clk = (struct s5pc100_clock *)S5PC1XX_CLOCK_BASE;
  150. unsigned long div;
  151. unsigned long dout_apll, armclk;
  152. unsigned int apll_ratio, arm_ratio;
  153. div = readl(&clk->div0);
  154. /* ARM_RATIO: [6:4] */
  155. arm_ratio = (div >> 4) & 0x7;
  156. /* APLL_RATIO: [0] */
  157. apll_ratio = div & 0x1;
  158. dout_apll = get_pll_clk(APLL) / (apll_ratio + 1);
  159. armclk = dout_apll / (arm_ratio + 1);
  160. return armclk;
  161. }
  162. /* s5pc100: return HCLKD0 frequency */
  163. static unsigned long get_hclk(void)
  164. {
  165. struct s5pc100_clock *clk = (struct s5pc100_clock *)S5PC1XX_CLOCK_BASE;
  166. unsigned long hclkd0;
  167. uint div, d0_bus_ratio;
  168. div = readl(&clk->div0);
  169. /* D0_BUS_RATIO: [10:8] */
  170. d0_bus_ratio = (div >> 8) & 0x7;
  171. hclkd0 = get_arm_clk() / (d0_bus_ratio + 1);
  172. return hclkd0;
  173. }
  174. /* s5pc100: return PCLKD1 frequency */
  175. static unsigned long get_pclkd1(void)
  176. {
  177. struct s5pc100_clock *clk = (struct s5pc100_clock *)S5PC1XX_CLOCK_BASE;
  178. unsigned long d1_bus, pclkd1;
  179. uint div, d1_bus_ratio, pclkd1_ratio;
  180. div = readl(&clk->div0);
  181. /* D1_BUS_RATIO: [14:12] */
  182. d1_bus_ratio = (div >> 12) & 0x7;
  183. /* PCLKD1_RATIO: [18:16] */
  184. pclkd1_ratio = (div >> 16) & 0x7;
  185. /* ASYNC Mode */
  186. d1_bus = get_pll_clk(MPLL) / (d1_bus_ratio + 1);
  187. pclkd1 = d1_bus / (pclkd1_ratio + 1);
  188. return pclkd1;
  189. }
  190. /* s5pc110: return HCLKs frequency */
  191. static unsigned long get_hclk_sys(int dom)
  192. {
  193. struct s5pc110_clock *clk = (struct s5pc110_clock *)S5PC1XX_CLOCK_BASE;
  194. unsigned long hclk;
  195. unsigned int div;
  196. unsigned int offset;
  197. unsigned int hclk_sys_ratio;
  198. if (dom == CLK_M)
  199. return get_hclk();
  200. div = readl(&clk->div0);
  201. /*
  202. * HCLK_MSYS_RATIO: [10:8]
  203. * HCLK_DSYS_RATIO: [19:16]
  204. * HCLK_PSYS_RATIO: [27:24]
  205. */
  206. offset = 8 + (dom << 0x3);
  207. hclk_sys_ratio = (div >> offset) & 0xf;
  208. hclk = get_pll_clk(MPLL) / (hclk_sys_ratio + 1);
  209. return hclk;
  210. }
  211. /* s5pc110: return PCLKs frequency */
  212. static unsigned long get_pclk_sys(int dom)
  213. {
  214. struct s5pc110_clock *clk = (struct s5pc110_clock *)S5PC1XX_CLOCK_BASE;
  215. unsigned long pclk;
  216. unsigned int div;
  217. unsigned int offset;
  218. unsigned int pclk_sys_ratio;
  219. div = readl(&clk->div0);
  220. /*
  221. * PCLK_MSYS_RATIO: [14:12]
  222. * PCLK_DSYS_RATIO: [22:20]
  223. * PCLK_PSYS_RATIO: [30:28]
  224. */
  225. offset = 12 + (dom << 0x3);
  226. pclk_sys_ratio = (div >> offset) & 0x7;
  227. pclk = get_hclk_sys(dom) / (pclk_sys_ratio + 1);
  228. return pclk;
  229. }
  230. /* s5pc110: return peripheral clock frequency */
  231. static unsigned long s5pc110_get_pclk(void)
  232. {
  233. return get_pclk_sys(CLK_P);
  234. }
  235. /* s5pc100: return peripheral clock frequency */
  236. static unsigned long s5pc100_get_pclk(void)
  237. {
  238. return get_pclkd1();
  239. }
  240. void s5pc1xx_clock_init(void)
  241. {
  242. if (cpu_is_s5pc110()) {
  243. get_pll_clk = s5pc110_get_pll_clk;
  244. get_arm_clk = s5pc110_get_arm_clk;
  245. get_pclk = s5pc110_get_pclk;
  246. } else {
  247. get_pll_clk = s5pc100_get_pll_clk;
  248. get_arm_clk = s5pc100_get_arm_clk;
  249. get_pclk = s5pc100_get_pclk;
  250. }
  251. }