exynos5250-cpufreq.c 8.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332
  1. /*
  2. * Copyright (c) 2010-20122Samsung Electronics Co., Ltd.
  3. * http://www.samsung.com
  4. *
  5. * EXYNOS5250 - CPU frequency scaling support
  6. *
  7. * This program is free software; you can redistribute it and/or modify
  8. * it under the terms of the GNU General Public License version 2 as
  9. * published by the Free Software Foundation.
  10. */
  11. #include <linux/module.h>
  12. #include <linux/kernel.h>
  13. #include <linux/err.h>
  14. #include <linux/clk.h>
  15. #include <linux/io.h>
  16. #include <linux/slab.h>
  17. #include <linux/cpufreq.h>
  18. #include <mach/map.h>
  19. #include <mach/regs-clock.h>
  20. #include <mach/cpufreq.h>
  21. #define CPUFREQ_LEVEL_END (L15 + 1)
  22. static struct clk *cpu_clk;
  23. static struct clk *moutcore;
  24. static struct clk *mout_mpll;
  25. static struct clk *mout_apll;
  26. struct cpufreq_clkdiv {
  27. unsigned int index;
  28. unsigned int clkdiv;
  29. unsigned int clkdiv1;
  30. };
  31. static unsigned int exynos5250_volt_table[CPUFREQ_LEVEL_END];
  32. static struct cpufreq_frequency_table exynos5250_freq_table[] = {
  33. {L0, 1700 * 1000},
  34. {L1, 1600 * 1000},
  35. {L2, 1500 * 1000},
  36. {L3, 1400 * 1000},
  37. {L4, 1300 * 1000},
  38. {L5, 1200 * 1000},
  39. {L6, 1100 * 1000},
  40. {L7, 1000 * 1000},
  41. {L8, 900 * 1000},
  42. {L9, 800 * 1000},
  43. {L10, 700 * 1000},
  44. {L11, 600 * 1000},
  45. {L12, 500 * 1000},
  46. {L13, 400 * 1000},
  47. {L14, 300 * 1000},
  48. {L15, 200 * 1000},
  49. {0, CPUFREQ_TABLE_END},
  50. };
  51. static struct cpufreq_clkdiv exynos5250_clkdiv_table[CPUFREQ_LEVEL_END];
  52. static unsigned int clkdiv_cpu0_5250[CPUFREQ_LEVEL_END][8] = {
  53. /*
  54. * Clock divider value for following
  55. * { ARM, CPUD, ACP, PERIPH, ATB, PCLK_DBG, APLL, ARM2 }
  56. */
  57. { 0, 3, 7, 7, 7, 3, 5, 0 }, /* 1700 MHz */
  58. { 0, 3, 7, 7, 7, 1, 4, 0 }, /* 1600 MHz */
  59. { 0, 2, 7, 7, 7, 1, 4, 0 }, /* 1500 MHz */
  60. { 0, 2, 7, 7, 6, 1, 4, 0 }, /* 1400 MHz */
  61. { 0, 2, 7, 7, 6, 1, 3, 0 }, /* 1300 MHz */
  62. { 0, 2, 7, 7, 5, 1, 3, 0 }, /* 1200 MHz */
  63. { 0, 3, 7, 7, 5, 1, 3, 0 }, /* 1100 MHz */
  64. { 0, 1, 7, 7, 4, 1, 2, 0 }, /* 1000 MHz */
  65. { 0, 1, 7, 7, 4, 1, 2, 0 }, /* 900 MHz */
  66. { 0, 1, 7, 7, 4, 1, 2, 0 }, /* 800 MHz */
  67. { 0, 1, 7, 7, 3, 1, 1, 0 }, /* 700 MHz */
  68. { 0, 1, 7, 7, 3, 1, 1, 0 }, /* 600 MHz */
  69. { 0, 1, 7, 7, 2, 1, 1, 0 }, /* 500 MHz */
  70. { 0, 1, 7, 7, 2, 1, 1, 0 }, /* 400 MHz */
  71. { 0, 1, 7, 7, 1, 1, 1, 0 }, /* 300 MHz */
  72. { 0, 1, 7, 7, 1, 1, 1, 0 }, /* 200 MHz */
  73. };
  74. static unsigned int clkdiv_cpu1_5250[CPUFREQ_LEVEL_END][2] = {
  75. /* Clock divider value for following
  76. * { COPY, HPM }
  77. */
  78. { 0, 2 }, /* 1700 MHz */
  79. { 0, 2 }, /* 1600 MHz */
  80. { 0, 2 }, /* 1500 MHz */
  81. { 0, 2 }, /* 1400 MHz */
  82. { 0, 2 }, /* 1300 MHz */
  83. { 0, 2 }, /* 1200 MHz */
  84. { 0, 2 }, /* 1100 MHz */
  85. { 0, 2 }, /* 1000 MHz */
  86. { 0, 2 }, /* 900 MHz */
  87. { 0, 2 }, /* 800 MHz */
  88. { 0, 2 }, /* 700 MHz */
  89. { 0, 2 }, /* 600 MHz */
  90. { 0, 2 }, /* 500 MHz */
  91. { 0, 2 }, /* 400 MHz */
  92. { 0, 2 }, /* 300 MHz */
  93. { 0, 2 }, /* 200 MHz */
  94. };
  95. static unsigned int exynos5_apll_pms_table[CPUFREQ_LEVEL_END] = {
  96. ((425 << 16) | (6 << 8) | 0), /* 1700 MHz */
  97. ((200 << 16) | (3 << 8) | 0), /* 1600 MHz */
  98. ((250 << 16) | (4 << 8) | 0), /* 1500 MHz */
  99. ((175 << 16) | (3 << 8) | 0), /* 1400 MHz */
  100. ((325 << 16) | (6 << 8) | 0), /* 1300 MHz */
  101. ((200 << 16) | (4 << 8) | 0), /* 1200 MHz */
  102. ((275 << 16) | (6 << 8) | 0), /* 1100 MHz */
  103. ((125 << 16) | (3 << 8) | 0), /* 1000 MHz */
  104. ((150 << 16) | (4 << 8) | 0), /* 900 MHz */
  105. ((100 << 16) | (3 << 8) | 0), /* 800 MHz */
  106. ((175 << 16) | (3 << 8) | 1), /* 700 MHz */
  107. ((200 << 16) | (4 << 8) | 1), /* 600 MHz */
  108. ((125 << 16) | (3 << 8) | 1), /* 500 MHz */
  109. ((100 << 16) | (3 << 8) | 1), /* 400 MHz */
  110. ((200 << 16) | (4 << 8) | 2), /* 300 MHz */
  111. ((100 << 16) | (3 << 8) | 2), /* 200 MHz */
  112. };
  113. /* ASV group voltage table */
  114. static const unsigned int asv_voltage_5250[CPUFREQ_LEVEL_END] = {
  115. 1300000, 1250000, 1225000, 1200000, 1150000,
  116. 1125000, 1100000, 1075000, 1050000, 1025000,
  117. 1012500, 1000000, 975000, 950000, 937500,
  118. 925000
  119. };
  120. static void set_clkdiv(unsigned int div_index)
  121. {
  122. unsigned int tmp;
  123. /* Change Divider - CPU0 */
  124. tmp = exynos5250_clkdiv_table[div_index].clkdiv;
  125. __raw_writel(tmp, EXYNOS5_CLKDIV_CPU0);
  126. while (__raw_readl(EXYNOS5_CLKDIV_STATCPU0) & 0x11111111)
  127. cpu_relax();
  128. /* Change Divider - CPU1 */
  129. tmp = exynos5250_clkdiv_table[div_index].clkdiv1;
  130. __raw_writel(tmp, EXYNOS5_CLKDIV_CPU1);
  131. while (__raw_readl(EXYNOS5_CLKDIV_STATCPU1) & 0x11)
  132. cpu_relax();
  133. }
  134. static void set_apll(unsigned int new_index,
  135. unsigned int old_index)
  136. {
  137. unsigned int tmp, pdiv;
  138. /* 1. MUX_CORE_SEL = MPLL, ARMCLK uses MPLL for lock time */
  139. clk_set_parent(moutcore, mout_mpll);
  140. do {
  141. cpu_relax();
  142. tmp = (__raw_readl(EXYNOS5_CLKMUX_STATCPU) >> 16);
  143. tmp &= 0x7;
  144. } while (tmp != 0x2);
  145. /* 2. Set APLL Lock time */
  146. pdiv = ((exynos5_apll_pms_table[new_index] >> 8) & 0x3f);
  147. __raw_writel((pdiv * 250), EXYNOS5_APLL_LOCK);
  148. /* 3. Change PLL PMS values */
  149. tmp = __raw_readl(EXYNOS5_APLL_CON0);
  150. tmp &= ~((0x3ff << 16) | (0x3f << 8) | (0x7 << 0));
  151. tmp |= exynos5_apll_pms_table[new_index];
  152. __raw_writel(tmp, EXYNOS5_APLL_CON0);
  153. /* 4. wait_lock_time */
  154. do {
  155. cpu_relax();
  156. tmp = __raw_readl(EXYNOS5_APLL_CON0);
  157. } while (!(tmp & (0x1 << 29)));
  158. /* 5. MUX_CORE_SEL = APLL */
  159. clk_set_parent(moutcore, mout_apll);
  160. do {
  161. cpu_relax();
  162. tmp = __raw_readl(EXYNOS5_CLKMUX_STATCPU);
  163. tmp &= (0x7 << 16);
  164. } while (tmp != (0x1 << 16));
  165. }
  166. bool exynos5250_pms_change(unsigned int old_index, unsigned int new_index)
  167. {
  168. unsigned int old_pm = (exynos5_apll_pms_table[old_index] >> 8);
  169. unsigned int new_pm = (exynos5_apll_pms_table[new_index] >> 8);
  170. return (old_pm == new_pm) ? 0 : 1;
  171. }
  172. static void exynos5250_set_frequency(unsigned int old_index,
  173. unsigned int new_index)
  174. {
  175. unsigned int tmp;
  176. if (old_index > new_index) {
  177. if (!exynos5250_pms_change(old_index, new_index)) {
  178. /* 1. Change the system clock divider values */
  179. set_clkdiv(new_index);
  180. /* 2. Change just s value in apll m,p,s value */
  181. tmp = __raw_readl(EXYNOS5_APLL_CON0);
  182. tmp &= ~(0x7 << 0);
  183. tmp |= (exynos5_apll_pms_table[new_index] & 0x7);
  184. __raw_writel(tmp, EXYNOS5_APLL_CON0);
  185. } else {
  186. /* Clock Configuration Procedure */
  187. /* 1. Change the system clock divider values */
  188. set_clkdiv(new_index);
  189. /* 2. Change the apll m,p,s value */
  190. set_apll(new_index, old_index);
  191. }
  192. } else if (old_index < new_index) {
  193. if (!exynos5250_pms_change(old_index, new_index)) {
  194. /* 1. Change just s value in apll m,p,s value */
  195. tmp = __raw_readl(EXYNOS5_APLL_CON0);
  196. tmp &= ~(0x7 << 0);
  197. tmp |= (exynos5_apll_pms_table[new_index] & 0x7);
  198. __raw_writel(tmp, EXYNOS5_APLL_CON0);
  199. /* 2. Change the system clock divider values */
  200. set_clkdiv(new_index);
  201. } else {
  202. /* Clock Configuration Procedure */
  203. /* 1. Change the apll m,p,s value */
  204. set_apll(new_index, old_index);
  205. /* 2. Change the system clock divider values */
  206. set_clkdiv(new_index);
  207. }
  208. }
  209. }
  210. static void __init set_volt_table(void)
  211. {
  212. unsigned int i;
  213. for (i = 0 ; i < CPUFREQ_LEVEL_END ; i++)
  214. exynos5250_volt_table[i] = asv_voltage_5250[i];
  215. }
  216. int exynos5250_cpufreq_init(struct exynos_dvfs_info *info)
  217. {
  218. int i;
  219. unsigned int tmp;
  220. unsigned long rate;
  221. set_volt_table();
  222. cpu_clk = clk_get(NULL, "armclk");
  223. if (IS_ERR(cpu_clk))
  224. return PTR_ERR(cpu_clk);
  225. moutcore = clk_get(NULL, "mout_cpu");
  226. if (IS_ERR(moutcore))
  227. goto err_moutcore;
  228. mout_mpll = clk_get(NULL, "mout_mpll");
  229. if (IS_ERR(mout_mpll))
  230. goto err_mout_mpll;
  231. rate = clk_get_rate(mout_mpll) / 1000;
  232. mout_apll = clk_get(NULL, "mout_apll");
  233. if (IS_ERR(mout_apll))
  234. goto err_mout_apll;
  235. for (i = L0; i < CPUFREQ_LEVEL_END; i++) {
  236. exynos5250_clkdiv_table[i].index = i;
  237. tmp = __raw_readl(EXYNOS5_CLKDIV_CPU0);
  238. tmp &= ~((0x7 << 0) | (0x7 << 4) | (0x7 << 8) |
  239. (0x7 << 12) | (0x7 << 16) | (0x7 << 20) |
  240. (0x7 << 24) | (0x7 << 28));
  241. tmp |= ((clkdiv_cpu0_5250[i][0] << 0) |
  242. (clkdiv_cpu0_5250[i][1] << 4) |
  243. (clkdiv_cpu0_5250[i][2] << 8) |
  244. (clkdiv_cpu0_5250[i][3] << 12) |
  245. (clkdiv_cpu0_5250[i][4] << 16) |
  246. (clkdiv_cpu0_5250[i][5] << 20) |
  247. (clkdiv_cpu0_5250[i][6] << 24) |
  248. (clkdiv_cpu0_5250[i][7] << 28));
  249. exynos5250_clkdiv_table[i].clkdiv = tmp;
  250. tmp = __raw_readl(EXYNOS5_CLKDIV_CPU1);
  251. tmp &= ~((0x7 << 0) | (0x7 << 4));
  252. tmp |= ((clkdiv_cpu1_5250[i][0] << 0) |
  253. (clkdiv_cpu1_5250[i][1] << 4));
  254. exynos5250_clkdiv_table[i].clkdiv1 = tmp;
  255. }
  256. info->mpll_freq_khz = rate;
  257. /* 800Mhz */
  258. info->pll_safe_idx = L9;
  259. info->cpu_clk = cpu_clk;
  260. info->volt_table = exynos5250_volt_table;
  261. info->freq_table = exynos5250_freq_table;
  262. info->set_freq = exynos5250_set_frequency;
  263. info->need_apll_change = exynos5250_pms_change;
  264. return 0;
  265. err_mout_apll:
  266. clk_put(mout_mpll);
  267. err_mout_mpll:
  268. clk_put(moutcore);
  269. err_moutcore:
  270. clk_put(cpu_clk);
  271. pr_err("%s: failed initialization\n", __func__);
  272. return -EINVAL;
  273. }
  274. EXPORT_SYMBOL(exynos5250_cpufreq_init);