exynos5250-cpufreq.c 9.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348
  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, 6, 1, 3, 0 }, /* 1700 MHz - N/A */
  60. { 0, 3, 7, 7, 6, 1, 3, 0 }, /* 1600 MHz - N/A */
  61. { 0, 3, 7, 7, 5, 1, 3, 0 }, /* 1500 MHz - N/A */
  62. { 0, 3, 7, 7, 6, 1, 3, 0 }, /* 1400 MHz */
  63. { 0, 3, 7, 7, 6, 1, 3, 0 }, /* 1300 MHz */
  64. { 0, 3, 7, 7, 5, 1, 3, 0 }, /* 1200 MHz */
  65. { 0, 2, 7, 7, 5, 1, 2, 0 }, /* 1100 MHz */
  66. { 0, 2, 7, 7, 4, 1, 2, 0 }, /* 1000 MHz */
  67. { 0, 2, 7, 7, 4, 1, 2, 0 }, /* 900 MHz */
  68. { 0, 2, 7, 7, 3, 1, 1, 0 }, /* 800 MHz */
  69. { 0, 1, 7, 7, 3, 1, 1, 0 }, /* 700 MHz */
  70. { 0, 1, 7, 7, 2, 1, 1, 0 }, /* 600 MHz */
  71. { 0, 1, 7, 7, 2, 1, 1, 0 }, /* 500 MHz */
  72. { 0, 1, 7, 7, 1, 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 - N/A */
  81. { 0, 2 }, /* 1600 MHz - N/A */
  82. { 0, 2 }, /* 1500 MHz - N/A */
  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. (0), /* 1700 MHz - N/A */
  99. (0), /* 1600 MHz - N/A */
  100. (0), /* 1500 MHz - N/A */
  101. (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. 0, 0, 0, 0, 0, 0, 0, /* 1700 MHz ~ 1100 MHz Not supported */
  118. 1175000, 1125000, 1075000, 1050000, 1000000,
  119. 950000, 925000, 925000, 900000
  120. };
  121. static void set_clkdiv(unsigned int div_index)
  122. {
  123. unsigned int tmp;
  124. /* Change Divider - CPU0 */
  125. tmp = exynos5250_clkdiv_table[div_index].clkdiv;
  126. __raw_writel(tmp, EXYNOS5_CLKDIV_CPU0);
  127. while (__raw_readl(EXYNOS5_CLKDIV_STATCPU0) & 0x11111111)
  128. cpu_relax();
  129. /* Change Divider - CPU1 */
  130. tmp = exynos5250_clkdiv_table[div_index].clkdiv1;
  131. __raw_writel(tmp, EXYNOS5_CLKDIV_CPU1);
  132. while (__raw_readl(EXYNOS5_CLKDIV_STATCPU1) & 0x11)
  133. cpu_relax();
  134. }
  135. static void set_apll(unsigned int new_index,
  136. unsigned int old_index)
  137. {
  138. unsigned int tmp, pdiv;
  139. /* 1. MUX_CORE_SEL = MPLL, ARMCLK uses MPLL for lock time */
  140. clk_set_parent(moutcore, mout_mpll);
  141. do {
  142. cpu_relax();
  143. tmp = (__raw_readl(EXYNOS5_CLKMUX_STATCPU) >> 16);
  144. tmp &= 0x7;
  145. } while (tmp != 0x2);
  146. /* 2. Set APLL Lock time */
  147. pdiv = ((exynos5_apll_pms_table[new_index] >> 8) & 0x3f);
  148. __raw_writel((pdiv * 250), EXYNOS5_APLL_LOCK);
  149. /* 3. Change PLL PMS values */
  150. tmp = __raw_readl(EXYNOS5_APLL_CON0);
  151. tmp &= ~((0x3ff << 16) | (0x3f << 8) | (0x7 << 0));
  152. tmp |= exynos5_apll_pms_table[new_index];
  153. __raw_writel(tmp, EXYNOS5_APLL_CON0);
  154. /* 4. wait_lock_time */
  155. do {
  156. cpu_relax();
  157. tmp = __raw_readl(EXYNOS5_APLL_CON0);
  158. } while (!(tmp & (0x1 << 29)));
  159. /* 5. MUX_CORE_SEL = APLL */
  160. clk_set_parent(moutcore, mout_apll);
  161. do {
  162. cpu_relax();
  163. tmp = __raw_readl(EXYNOS5_CLKMUX_STATCPU);
  164. tmp &= (0x7 << 16);
  165. } while (tmp != (0x1 << 16));
  166. }
  167. bool exynos5250_pms_change(unsigned int old_index, unsigned int new_index)
  168. {
  169. unsigned int old_pm = (exynos5_apll_pms_table[old_index] >> 8);
  170. unsigned int new_pm = (exynos5_apll_pms_table[new_index] >> 8);
  171. return (old_pm == new_pm) ? 0 : 1;
  172. }
  173. static void exynos5250_set_frequency(unsigned int old_index,
  174. unsigned int new_index)
  175. {
  176. unsigned int tmp;
  177. if (old_index > new_index) {
  178. if (!exynos5250_pms_change(old_index, new_index)) {
  179. /* 1. Change the system clock divider values */
  180. set_clkdiv(new_index);
  181. /* 2. Change just s value in apll m,p,s value */
  182. tmp = __raw_readl(EXYNOS5_APLL_CON0);
  183. tmp &= ~(0x7 << 0);
  184. tmp |= (exynos5_apll_pms_table[new_index] & 0x7);
  185. __raw_writel(tmp, EXYNOS5_APLL_CON0);
  186. } else {
  187. /* Clock Configuration Procedure */
  188. /* 1. Change the system clock divider values */
  189. set_clkdiv(new_index);
  190. /* 2. Change the apll m,p,s value */
  191. set_apll(new_index, old_index);
  192. }
  193. } else if (old_index < new_index) {
  194. if (!exynos5250_pms_change(old_index, new_index)) {
  195. /* 1. Change just s value in apll m,p,s value */
  196. tmp = __raw_readl(EXYNOS5_APLL_CON0);
  197. tmp &= ~(0x7 << 0);
  198. tmp |= (exynos5_apll_pms_table[new_index] & 0x7);
  199. __raw_writel(tmp, EXYNOS5_APLL_CON0);
  200. /* 2. Change the system clock divider values */
  201. set_clkdiv(new_index);
  202. } else {
  203. /* Clock Configuration Procedure */
  204. /* 1. Change the apll m,p,s value */
  205. set_apll(new_index, old_index);
  206. /* 2. Change the system clock divider values */
  207. set_clkdiv(new_index);
  208. }
  209. }
  210. }
  211. static void __init set_volt_table(void)
  212. {
  213. unsigned int i;
  214. exynos5250_freq_table[L0].frequency = CPUFREQ_ENTRY_INVALID;
  215. exynos5250_freq_table[L1].frequency = CPUFREQ_ENTRY_INVALID;
  216. exynos5250_freq_table[L2].frequency = CPUFREQ_ENTRY_INVALID;
  217. exynos5250_freq_table[L3].frequency = CPUFREQ_ENTRY_INVALID;
  218. exynos5250_freq_table[L4].frequency = CPUFREQ_ENTRY_INVALID;
  219. exynos5250_freq_table[L5].frequency = CPUFREQ_ENTRY_INVALID;
  220. exynos5250_freq_table[L6].frequency = CPUFREQ_ENTRY_INVALID;
  221. max_support_idx = L7;
  222. for (i = 0 ; i < CPUFREQ_LEVEL_END ; i++)
  223. exynos5250_volt_table[i] = asv_voltage_5250[i];
  224. }
  225. int exynos5250_cpufreq_init(struct exynos_dvfs_info *info)
  226. {
  227. int i;
  228. unsigned int tmp;
  229. unsigned long rate;
  230. set_volt_table();
  231. cpu_clk = clk_get(NULL, "armclk");
  232. if (IS_ERR(cpu_clk))
  233. return PTR_ERR(cpu_clk);
  234. moutcore = clk_get(NULL, "mout_cpu");
  235. if (IS_ERR(moutcore))
  236. goto err_moutcore;
  237. mout_mpll = clk_get(NULL, "mout_mpll");
  238. if (IS_ERR(mout_mpll))
  239. goto err_mout_mpll;
  240. rate = clk_get_rate(mout_mpll) / 1000;
  241. mout_apll = clk_get(NULL, "mout_apll");
  242. if (IS_ERR(mout_apll))
  243. goto err_mout_apll;
  244. for (i = L0; i < CPUFREQ_LEVEL_END; i++) {
  245. exynos5250_clkdiv_table[i].index = i;
  246. tmp = __raw_readl(EXYNOS5_CLKDIV_CPU0);
  247. tmp &= ~((0x7 << 0) | (0x7 << 4) | (0x7 << 8) |
  248. (0x7 << 12) | (0x7 << 16) | (0x7 << 20) |
  249. (0x7 << 24) | (0x7 << 28));
  250. tmp |= ((clkdiv_cpu0_5250[i][0] << 0) |
  251. (clkdiv_cpu0_5250[i][1] << 4) |
  252. (clkdiv_cpu0_5250[i][2] << 8) |
  253. (clkdiv_cpu0_5250[i][3] << 12) |
  254. (clkdiv_cpu0_5250[i][4] << 16) |
  255. (clkdiv_cpu0_5250[i][5] << 20) |
  256. (clkdiv_cpu0_5250[i][6] << 24) |
  257. (clkdiv_cpu0_5250[i][7] << 28));
  258. exynos5250_clkdiv_table[i].clkdiv = tmp;
  259. tmp = __raw_readl(EXYNOS5_CLKDIV_CPU1);
  260. tmp &= ~((0x7 << 0) | (0x7 << 4));
  261. tmp |= ((clkdiv_cpu1_5250[i][0] << 0) |
  262. (clkdiv_cpu1_5250[i][1] << 4));
  263. exynos5250_clkdiv_table[i].clkdiv1 = tmp;
  264. }
  265. info->mpll_freq_khz = rate;
  266. /* 1000Mhz */
  267. info->pm_lock_idx = L7;
  268. /* 800Mhz */
  269. info->pll_safe_idx = L9;
  270. info->max_support_idx = max_support_idx;
  271. info->min_support_idx = min_support_idx;
  272. info->cpu_clk = cpu_clk;
  273. info->volt_table = exynos5250_volt_table;
  274. info->freq_table = exynos5250_freq_table;
  275. info->set_freq = exynos5250_set_frequency;
  276. info->need_apll_change = exynos5250_pms_change;
  277. return 0;
  278. err_mout_apll:
  279. clk_put(mout_mpll);
  280. err_mout_mpll:
  281. clk_put(moutcore);
  282. err_moutcore:
  283. clk_put(cpu_clk);
  284. pr_err("%s: failed initialization\n", __func__);
  285. return -EINVAL;
  286. }
  287. EXPORT_SYMBOL(exynos5250_cpufreq_init);