clock.c 9.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455
  1. /*
  2. * Copyright (C) 2010 Samsung Electronics
  3. * Minkyu Kang <mk7.kang@samsung.com>
  4. *
  5. * See file CREDITS for list of people who contributed to this
  6. * project.
  7. *
  8. * This program is free software; you can redistribute it and/or
  9. * modify it under the terms of the GNU General Public License as
  10. * published by the Free Software Foundation; either version 2 of
  11. * the License, or (at your option) any later version.
  12. *
  13. * This program is distributed in the hope that it will be useful,
  14. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  15. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  16. * GNU General Public License for more details.
  17. *
  18. * You should have received a copy of the GNU General Public License
  19. * along with this program; if not, write to the Free Software
  20. * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
  21. * MA 02111-1307 USA
  22. */
  23. #include <common.h>
  24. #include <asm/io.h>
  25. #include <asm/arch/clock.h>
  26. #include <asm/arch/clk.h>
  27. /* exynos4: return pll clock frequency */
  28. static unsigned long exynos4_get_pll_clk(int pllreg)
  29. {
  30. struct exynos4_clock *clk =
  31. (struct exynos4_clock *)samsung_get_base_clock();
  32. unsigned long r, m, p, s, k = 0, mask, fout;
  33. unsigned int freq;
  34. switch (pllreg) {
  35. case APLL:
  36. r = readl(&clk->apll_con0);
  37. break;
  38. case MPLL:
  39. r = readl(&clk->mpll_con0);
  40. break;
  41. case EPLL:
  42. r = readl(&clk->epll_con0);
  43. k = readl(&clk->epll_con1);
  44. break;
  45. case VPLL:
  46. r = readl(&clk->vpll_con0);
  47. k = readl(&clk->vpll_con1);
  48. break;
  49. default:
  50. printf("Unsupported PLL (%d)\n", pllreg);
  51. return 0;
  52. }
  53. /*
  54. * APLL_CON: MIDV [25:16]
  55. * MPLL_CON: MIDV [25:16]
  56. * EPLL_CON: MIDV [24:16]
  57. * VPLL_CON: MIDV [24:16]
  58. */
  59. if (pllreg == APLL || pllreg == MPLL)
  60. mask = 0x3ff;
  61. else
  62. mask = 0x1ff;
  63. m = (r >> 16) & mask;
  64. /* PDIV [13:8] */
  65. p = (r >> 8) & 0x3f;
  66. /* SDIV [2:0] */
  67. s = r & 0x7;
  68. freq = CONFIG_SYS_CLK_FREQ;
  69. if (pllreg == EPLL) {
  70. k = k & 0xffff;
  71. /* FOUT = (MDIV + K / 65536) * FIN / (PDIV * 2^SDIV) */
  72. fout = (m + k / 65536) * (freq / (p * (1 << s)));
  73. } else if (pllreg == VPLL) {
  74. k = k & 0xfff;
  75. /* FOUT = (MDIV + K / 1024) * FIN / (PDIV * 2^SDIV) */
  76. fout = (m + k / 1024) * (freq / (p * (1 << s)));
  77. } else {
  78. if (s < 1)
  79. s = 1;
  80. /* FOUT = MDIV * FIN / (PDIV * 2^(SDIV - 1)) */
  81. fout = m * (freq / (p * (1 << (s - 1))));
  82. }
  83. return fout;
  84. }
  85. /* exynos5: return pll clock frequency */
  86. static unsigned long exynos5_get_pll_clk(int pllreg)
  87. {
  88. struct exynos5_clock *clk =
  89. (struct exynos5_clock *)samsung_get_base_clock();
  90. unsigned long r, m, p, s, k = 0, mask, fout;
  91. unsigned int freq;
  92. switch (pllreg) {
  93. case APLL:
  94. r = readl(&clk->apll_con0);
  95. break;
  96. case MPLL:
  97. r = readl(&clk->mpll_con0);
  98. break;
  99. case EPLL:
  100. r = readl(&clk->epll_con0);
  101. k = readl(&clk->epll_con1);
  102. break;
  103. case VPLL:
  104. r = readl(&clk->vpll_con0);
  105. k = readl(&clk->vpll_con1);
  106. break;
  107. default:
  108. printf("Unsupported PLL (%d)\n", pllreg);
  109. return 0;
  110. }
  111. /*
  112. * APLL_CON: MIDV [25:16]
  113. * MPLL_CON: MIDV [25:16]
  114. * EPLL_CON: MIDV [24:16]
  115. * VPLL_CON: MIDV [24:16]
  116. */
  117. if (pllreg == APLL || pllreg == MPLL)
  118. mask = 0x3ff;
  119. else
  120. mask = 0x1ff;
  121. m = (r >> 16) & mask;
  122. /* PDIV [13:8] */
  123. p = (r >> 8) & 0x3f;
  124. /* SDIV [2:0] */
  125. s = r & 0x7;
  126. freq = CONFIG_SYS_CLK_FREQ;
  127. if (pllreg == EPLL) {
  128. k = k & 0xffff;
  129. /* FOUT = (MDIV + K / 65536) * FIN / (PDIV * 2^SDIV) */
  130. fout = (m + k / 65536) * (freq / (p * (1 << s)));
  131. } else if (pllreg == VPLL) {
  132. k = k & 0xfff;
  133. /* FOUT = (MDIV + K / 1024) * FIN / (PDIV * 2^SDIV) */
  134. fout = (m + k / 1024) * (freq / (p * (1 << s)));
  135. } else {
  136. if (s < 1)
  137. s = 1;
  138. /* FOUT = MDIV * FIN / (PDIV * 2^(SDIV - 1)) */
  139. fout = m * (freq / (p * (1 << (s - 1))));
  140. }
  141. return fout;
  142. }
  143. /* exynos4: return ARM clock frequency */
  144. static unsigned long exynos4_get_arm_clk(void)
  145. {
  146. struct exynos4_clock *clk =
  147. (struct exynos4_clock *)samsung_get_base_clock();
  148. unsigned long div;
  149. unsigned long armclk;
  150. unsigned int core_ratio;
  151. unsigned int core2_ratio;
  152. div = readl(&clk->div_cpu0);
  153. /* CORE_RATIO: [2:0], CORE2_RATIO: [30:28] */
  154. core_ratio = (div >> 0) & 0x7;
  155. core2_ratio = (div >> 28) & 0x7;
  156. armclk = get_pll_clk(APLL) / (core_ratio + 1);
  157. armclk /= (core2_ratio + 1);
  158. return armclk;
  159. }
  160. /* exynos5: return ARM clock frequency */
  161. static unsigned long exynos5_get_arm_clk(void)
  162. {
  163. struct exynos5_clock *clk =
  164. (struct exynos5_clock *)samsung_get_base_clock();
  165. unsigned long div;
  166. unsigned long armclk;
  167. unsigned int arm_ratio;
  168. unsigned int arm2_ratio;
  169. div = readl(&clk->div_cpu0);
  170. /* ARM_RATIO: [2:0], ARM2_RATIO: [30:28] */
  171. arm_ratio = (div >> 0) & 0x7;
  172. arm2_ratio = (div >> 28) & 0x7;
  173. armclk = get_pll_clk(APLL) / (arm_ratio + 1);
  174. armclk /= (arm2_ratio + 1);
  175. return armclk;
  176. }
  177. /* exynos4: return pwm clock frequency */
  178. static unsigned long exynos4_get_pwm_clk(void)
  179. {
  180. struct exynos4_clock *clk =
  181. (struct exynos4_clock *)samsung_get_base_clock();
  182. unsigned long pclk, sclk;
  183. unsigned int sel;
  184. unsigned int ratio;
  185. if (s5p_get_cpu_rev() == 0) {
  186. /*
  187. * CLK_SRC_PERIL0
  188. * PWM_SEL [27:24]
  189. */
  190. sel = readl(&clk->src_peril0);
  191. sel = (sel >> 24) & 0xf;
  192. if (sel == 0x6)
  193. sclk = get_pll_clk(MPLL);
  194. else if (sel == 0x7)
  195. sclk = get_pll_clk(EPLL);
  196. else if (sel == 0x8)
  197. sclk = get_pll_clk(VPLL);
  198. else
  199. return 0;
  200. /*
  201. * CLK_DIV_PERIL3
  202. * PWM_RATIO [3:0]
  203. */
  204. ratio = readl(&clk->div_peril3);
  205. ratio = ratio & 0xf;
  206. } else if (s5p_get_cpu_rev() == 1) {
  207. sclk = get_pll_clk(MPLL);
  208. ratio = 8;
  209. } else
  210. return 0;
  211. pclk = sclk / (ratio + 1);
  212. return pclk;
  213. }
  214. /* exynos5: return pwm clock frequency */
  215. static unsigned long exynos5_get_pwm_clk(void)
  216. {
  217. struct exynos5_clock *clk =
  218. (struct exynos5_clock *)samsung_get_base_clock();
  219. unsigned long pclk, sclk;
  220. unsigned int ratio;
  221. /*
  222. * CLK_DIV_PERIC3
  223. * PWM_RATIO [3:0]
  224. */
  225. ratio = readl(&clk->div_peric3);
  226. ratio = ratio & 0xf;
  227. sclk = get_pll_clk(MPLL);
  228. pclk = sclk / (ratio + 1);
  229. return pclk;
  230. }
  231. /* exynos4: return uart clock frequency */
  232. static unsigned long exynos4_get_uart_clk(int dev_index)
  233. {
  234. struct exynos4_clock *clk =
  235. (struct exynos4_clock *)samsung_get_base_clock();
  236. unsigned long uclk, sclk;
  237. unsigned int sel;
  238. unsigned int ratio;
  239. /*
  240. * CLK_SRC_PERIL0
  241. * UART0_SEL [3:0]
  242. * UART1_SEL [7:4]
  243. * UART2_SEL [8:11]
  244. * UART3_SEL [12:15]
  245. * UART4_SEL [16:19]
  246. * UART5_SEL [23:20]
  247. */
  248. sel = readl(&clk->src_peril0);
  249. sel = (sel >> (dev_index << 2)) & 0xf;
  250. if (sel == 0x6)
  251. sclk = get_pll_clk(MPLL);
  252. else if (sel == 0x7)
  253. sclk = get_pll_clk(EPLL);
  254. else if (sel == 0x8)
  255. sclk = get_pll_clk(VPLL);
  256. else
  257. return 0;
  258. /*
  259. * CLK_DIV_PERIL0
  260. * UART0_RATIO [3:0]
  261. * UART1_RATIO [7:4]
  262. * UART2_RATIO [8:11]
  263. * UART3_RATIO [12:15]
  264. * UART4_RATIO [16:19]
  265. * UART5_RATIO [23:20]
  266. */
  267. ratio = readl(&clk->div_peril0);
  268. ratio = (ratio >> (dev_index << 2)) & 0xf;
  269. uclk = sclk / (ratio + 1);
  270. return uclk;
  271. }
  272. /* exynos5: return uart clock frequency */
  273. static unsigned long exynos5_get_uart_clk(int dev_index)
  274. {
  275. struct exynos5_clock *clk =
  276. (struct exynos5_clock *)samsung_get_base_clock();
  277. unsigned long uclk, sclk;
  278. unsigned int sel;
  279. unsigned int ratio;
  280. /*
  281. * CLK_SRC_PERIC0
  282. * UART0_SEL [3:0]
  283. * UART1_SEL [7:4]
  284. * UART2_SEL [8:11]
  285. * UART3_SEL [12:15]
  286. * UART4_SEL [16:19]
  287. * UART5_SEL [23:20]
  288. */
  289. sel = readl(&clk->src_peric0);
  290. sel = (sel >> (dev_index << 2)) & 0xf;
  291. if (sel == 0x6)
  292. sclk = get_pll_clk(MPLL);
  293. else if (sel == 0x7)
  294. sclk = get_pll_clk(EPLL);
  295. else if (sel == 0x8)
  296. sclk = get_pll_clk(VPLL);
  297. else
  298. return 0;
  299. /*
  300. * CLK_DIV_PERIC0
  301. * UART0_RATIO [3:0]
  302. * UART1_RATIO [7:4]
  303. * UART2_RATIO [8:11]
  304. * UART3_RATIO [12:15]
  305. * UART4_RATIO [16:19]
  306. * UART5_RATIO [23:20]
  307. */
  308. ratio = readl(&clk->div_peric0);
  309. ratio = (ratio >> (dev_index << 2)) & 0xf;
  310. uclk = sclk / (ratio + 1);
  311. return uclk;
  312. }
  313. /* exynos4: set the mmc clock */
  314. static void exynos4_set_mmc_clk(int dev_index, unsigned int div)
  315. {
  316. struct exynos4_clock *clk =
  317. (struct exynos4_clock *)samsung_get_base_clock();
  318. unsigned int addr;
  319. unsigned int val;
  320. /*
  321. * CLK_DIV_FSYS1
  322. * MMC0_PRE_RATIO [15:8], MMC1_PRE_RATIO [31:24]
  323. * CLK_DIV_FSYS2
  324. * MMC2_PRE_RATIO [15:8], MMC3_PRE_RATIO [31:24]
  325. */
  326. if (dev_index < 2) {
  327. addr = (unsigned int)&clk->div_fsys1;
  328. } else {
  329. addr = (unsigned int)&clk->div_fsys2;
  330. dev_index -= 2;
  331. }
  332. val = readl(addr);
  333. val &= ~(0xff << ((dev_index << 4) + 8));
  334. val |= (div & 0xff) << ((dev_index << 4) + 8);
  335. writel(val, addr);
  336. }
  337. /* exynos5: set the mmc clock */
  338. static void exynos5_set_mmc_clk(int dev_index, unsigned int div)
  339. {
  340. struct exynos5_clock *clk =
  341. (struct exynos5_clock *)samsung_get_base_clock();
  342. unsigned int addr;
  343. unsigned int val;
  344. /*
  345. * CLK_DIV_FSYS1
  346. * MMC0_PRE_RATIO [15:8], MMC1_PRE_RATIO [31:24]
  347. * CLK_DIV_FSYS2
  348. * MMC2_PRE_RATIO [15:8], MMC3_PRE_RATIO [31:24]
  349. */
  350. if (dev_index < 2) {
  351. addr = (unsigned int)&clk->div_fsys1;
  352. } else {
  353. addr = (unsigned int)&clk->div_fsys2;
  354. dev_index -= 2;
  355. }
  356. val = readl(addr);
  357. val &= ~(0xff << ((dev_index << 4) + 8));
  358. val |= (div & 0xff) << ((dev_index << 4) + 8);
  359. writel(val, addr);
  360. }
  361. unsigned long get_pll_clk(int pllreg)
  362. {
  363. if (cpu_is_exynos5())
  364. return exynos5_get_pll_clk(pllreg);
  365. else
  366. return exynos4_get_pll_clk(pllreg);
  367. }
  368. unsigned long get_arm_clk(void)
  369. {
  370. if (cpu_is_exynos5())
  371. return exynos5_get_arm_clk();
  372. else
  373. return exynos4_get_arm_clk();
  374. }
  375. unsigned long get_pwm_clk(void)
  376. {
  377. if (cpu_is_exynos5())
  378. return exynos5_get_pwm_clk();
  379. else
  380. return exynos4_get_pwm_clk();
  381. }
  382. unsigned long get_uart_clk(int dev_index)
  383. {
  384. if (cpu_is_exynos5())
  385. return exynos5_get_uart_clk(dev_index);
  386. else
  387. return exynos4_get_uart_clk(dev_index);
  388. }
  389. void set_mmc_clk(int dev_index, unsigned int div)
  390. {
  391. if (cpu_is_exynos5())
  392. exynos5_set_mmc_clk(dev_index, div);
  393. else
  394. exynos4_set_mmc_clk(dev_index, div);
  395. }