exynos5250-cpufreq.c 8.8 KB

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