clock.c 7.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343
  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. /* s5pc110: return pll clock frequency */
  38. static unsigned long s5pc100_get_pll_clk(int pllreg)
  39. {
  40. struct s5pc100_clock *clk =
  41. (struct s5pc100_clock *)samsung_get_base_clock();
  42. unsigned long r, m, p, s, mask, fout;
  43. unsigned int freq;
  44. switch (pllreg) {
  45. case APLL:
  46. r = readl(&clk->apll_con);
  47. break;
  48. case MPLL:
  49. r = readl(&clk->mpll_con);
  50. break;
  51. case EPLL:
  52. r = readl(&clk->epll_con);
  53. break;
  54. case HPLL:
  55. r = readl(&clk->hpll_con);
  56. break;
  57. default:
  58. printf("Unsupported PLL (%d)\n", pllreg);
  59. return 0;
  60. }
  61. /*
  62. * APLL_CON: MIDV [25:16]
  63. * MPLL_CON: MIDV [23:16]
  64. * EPLL_CON: MIDV [23:16]
  65. * HPLL_CON: MIDV [23:16]
  66. */
  67. if (pllreg == APLL)
  68. mask = 0x3ff;
  69. else
  70. mask = 0x0ff;
  71. m = (r >> 16) & mask;
  72. /* PDIV [13:8] */
  73. p = (r >> 8) & 0x3f;
  74. /* SDIV [2:0] */
  75. s = r & 0x7;
  76. /* FOUT = MDIV * FIN / (PDIV * 2^SDIV) */
  77. freq = CONFIG_SYS_CLK_FREQ_C100;
  78. fout = m * (freq / (p * (1 << s)));
  79. return fout;
  80. }
  81. /* s5pc100: return pll clock frequency */
  82. static unsigned long s5pc110_get_pll_clk(int pllreg)
  83. {
  84. struct s5pc110_clock *clk =
  85. (struct s5pc110_clock *)samsung_get_base_clock();
  86. unsigned long r, m, p, s, mask, fout;
  87. unsigned int freq;
  88. switch (pllreg) {
  89. case APLL:
  90. r = readl(&clk->apll_con);
  91. break;
  92. case MPLL:
  93. r = readl(&clk->mpll_con);
  94. break;
  95. case EPLL:
  96. r = readl(&clk->epll_con);
  97. break;
  98. case VPLL:
  99. r = readl(&clk->vpll_con);
  100. break;
  101. default:
  102. printf("Unsupported PLL (%d)\n", pllreg);
  103. return 0;
  104. }
  105. /*
  106. * APLL_CON: MIDV [25:16]
  107. * MPLL_CON: MIDV [25:16]
  108. * EPLL_CON: MIDV [24:16]
  109. * VPLL_CON: MIDV [24:16]
  110. */
  111. if (pllreg == APLL || pllreg == MPLL)
  112. mask = 0x3ff;
  113. else
  114. mask = 0x1ff;
  115. m = (r >> 16) & mask;
  116. /* PDIV [13:8] */
  117. p = (r >> 8) & 0x3f;
  118. /* SDIV [2:0] */
  119. s = r & 0x7;
  120. freq = CONFIG_SYS_CLK_FREQ_C110;
  121. if (pllreg == APLL) {
  122. if (s < 1)
  123. s = 1;
  124. /* FOUT = MDIV * FIN / (PDIV * 2^(SDIV - 1)) */
  125. fout = m * (freq / (p * (1 << (s - 1))));
  126. } else
  127. /* FOUT = MDIV * FIN / (PDIV * 2^SDIV) */
  128. fout = m * (freq / (p * (1 << s)));
  129. return fout;
  130. }
  131. /* s5pc110: return ARM clock frequency */
  132. static unsigned long s5pc110_get_arm_clk(void)
  133. {
  134. struct s5pc110_clock *clk =
  135. (struct s5pc110_clock *)samsung_get_base_clock();
  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 =
  150. (struct s5pc100_clock *)samsung_get_base_clock();
  151. unsigned long div;
  152. unsigned long dout_apll, armclk;
  153. unsigned int apll_ratio, arm_ratio;
  154. div = readl(&clk->div0);
  155. /* ARM_RATIO: [6:4] */
  156. arm_ratio = (div >> 4) & 0x7;
  157. /* APLL_RATIO: [0] */
  158. apll_ratio = div & 0x1;
  159. dout_apll = get_pll_clk(APLL) / (apll_ratio + 1);
  160. armclk = dout_apll / (arm_ratio + 1);
  161. return armclk;
  162. }
  163. /* s5pc100: return HCLKD0 frequency */
  164. static unsigned long get_hclk(void)
  165. {
  166. struct s5pc100_clock *clk =
  167. (struct s5pc100_clock *)samsung_get_base_clock();
  168. unsigned long hclkd0;
  169. uint div, d0_bus_ratio;
  170. div = readl(&clk->div0);
  171. /* D0_BUS_RATIO: [10:8] */
  172. d0_bus_ratio = (div >> 8) & 0x7;
  173. hclkd0 = get_arm_clk() / (d0_bus_ratio + 1);
  174. return hclkd0;
  175. }
  176. /* s5pc100: return PCLKD1 frequency */
  177. static unsigned long get_pclkd1(void)
  178. {
  179. struct s5pc100_clock *clk =
  180. (struct s5pc100_clock *)samsung_get_base_clock();
  181. unsigned long d1_bus, pclkd1;
  182. uint div, d1_bus_ratio, pclkd1_ratio;
  183. div = readl(&clk->div0);
  184. /* D1_BUS_RATIO: [14:12] */
  185. d1_bus_ratio = (div >> 12) & 0x7;
  186. /* PCLKD1_RATIO: [18:16] */
  187. pclkd1_ratio = (div >> 16) & 0x7;
  188. /* ASYNC Mode */
  189. d1_bus = get_pll_clk(MPLL) / (d1_bus_ratio + 1);
  190. pclkd1 = d1_bus / (pclkd1_ratio + 1);
  191. return pclkd1;
  192. }
  193. /* s5pc110: return HCLKs frequency */
  194. static unsigned long get_hclk_sys(int dom)
  195. {
  196. struct s5pc110_clock *clk =
  197. (struct s5pc110_clock *)samsung_get_base_clock();
  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 =
  219. (struct s5pc110_clock *)samsung_get_base_clock();
  220. unsigned long pclk;
  221. unsigned int div;
  222. unsigned int offset;
  223. unsigned int pclk_sys_ratio;
  224. div = readl(&clk->div0);
  225. /*
  226. * PCLK_MSYS_RATIO: [14:12]
  227. * PCLK_DSYS_RATIO: [22:20]
  228. * PCLK_PSYS_RATIO: [30:28]
  229. */
  230. offset = 12 + (dom << 0x3);
  231. pclk_sys_ratio = (div >> offset) & 0x7;
  232. pclk = get_hclk_sys(dom) / (pclk_sys_ratio + 1);
  233. return pclk;
  234. }
  235. /* s5pc110: return peripheral clock frequency */
  236. static unsigned long s5pc110_get_pclk(void)
  237. {
  238. return get_pclk_sys(CLK_P);
  239. }
  240. /* s5pc100: return peripheral clock frequency */
  241. static unsigned long s5pc100_get_pclk(void)
  242. {
  243. return get_pclkd1();
  244. }
  245. /* s5pc1xx: return uart clock frequency */
  246. static unsigned long s5pc1xx_get_uart_clk(int dev_index)
  247. {
  248. if (cpu_is_s5pc110())
  249. return s5pc110_get_pclk();
  250. else
  251. return s5pc100_get_pclk();
  252. }
  253. /* s5pc1xx: return pwm clock frequency */
  254. static unsigned long s5pc1xx_get_pwm_clk(void)
  255. {
  256. if (cpu_is_s5pc110())
  257. return s5pc110_get_pclk();
  258. else
  259. return s5pc100_get_pclk();
  260. }
  261. unsigned long get_pll_clk(int pllreg)
  262. {
  263. if (cpu_is_s5pc110())
  264. return s5pc110_get_pll_clk(pllreg);
  265. else
  266. return s5pc100_get_pll_clk(pllreg);
  267. }
  268. unsigned long get_arm_clk(void)
  269. {
  270. if (cpu_is_s5pc110())
  271. return s5pc110_get_arm_clk();
  272. else
  273. return s5pc100_get_arm_clk();
  274. }
  275. unsigned long get_pwm_clk(void)
  276. {
  277. return s5pc1xx_get_pwm_clk();
  278. }
  279. unsigned long get_uart_clk(int dev_index)
  280. {
  281. return s5pc1xx_get_uart_clk(dev_index);
  282. }
  283. void set_mmc_clk(int dev_index, unsigned int div)
  284. {
  285. /* Do NOTHING */
  286. }