clock.c 6.6 KB

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