exynos4x12-cpufreq.c 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537
  1. /*
  2. * Copyright (c) 2010-2012 Samsung Electronics Co., Ltd.
  3. * http://www.samsung.com
  4. *
  5. * EXYNOS4X12 - 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/regs-clock.h>
  19. #include <mach/cpufreq.h>
  20. #define CPUFREQ_LEVEL_END (L13 + 1)
  21. static int max_support_idx;
  22. static int min_support_idx = (CPUFREQ_LEVEL_END - 1);
  23. static struct clk *cpu_clk;
  24. static struct clk *moutcore;
  25. static struct clk *mout_mpll;
  26. static struct clk *mout_apll;
  27. struct cpufreq_clkdiv {
  28. unsigned int index;
  29. unsigned int clkdiv;
  30. unsigned int clkdiv1;
  31. };
  32. static unsigned int exynos4x12_volt_table[CPUFREQ_LEVEL_END];
  33. static struct cpufreq_frequency_table exynos4x12_freq_table[] = {
  34. {L0, 1500 * 1000},
  35. {L1, 1400 * 1000},
  36. {L2, 1300 * 1000},
  37. {L3, 1200 * 1000},
  38. {L4, 1100 * 1000},
  39. {L5, 1000 * 1000},
  40. {L6, 900 * 1000},
  41. {L7, 800 * 1000},
  42. {L8, 700 * 1000},
  43. {L9, 600 * 1000},
  44. {L10, 500 * 1000},
  45. {L11, 400 * 1000},
  46. {L12, 300 * 1000},
  47. {L13, 200 * 1000},
  48. {0, CPUFREQ_TABLE_END},
  49. };
  50. static struct cpufreq_clkdiv exynos4x12_clkdiv_table[CPUFREQ_LEVEL_END];
  51. static unsigned int clkdiv_cpu0_4212[CPUFREQ_LEVEL_END][8] = {
  52. /*
  53. * Clock divider value for following
  54. * { DIVCORE, DIVCOREM0, DIVCOREM1, DIVPERIPH,
  55. * DIVATB, DIVPCLK_DBG, DIVAPLL, DIVCORE2 }
  56. */
  57. /* ARM L0: 1500 MHz */
  58. { 0, 3, 7, 0, 6, 1, 2, 0 },
  59. /* ARM L1: 1400 MHz */
  60. { 0, 3, 7, 0, 6, 1, 2, 0 },
  61. /* ARM L2: 1300 MHz */
  62. { 0, 3, 7, 0, 5, 1, 2, 0 },
  63. /* ARM L3: 1200 MHz */
  64. { 0, 3, 7, 0, 5, 1, 2, 0 },
  65. /* ARM L4: 1100 MHz */
  66. { 0, 3, 6, 0, 4, 1, 2, 0 },
  67. /* ARM L5: 1000 MHz */
  68. { 0, 2, 5, 0, 4, 1, 1, 0 },
  69. /* ARM L6: 900 MHz */
  70. { 0, 2, 5, 0, 3, 1, 1, 0 },
  71. /* ARM L7: 800 MHz */
  72. { 0, 2, 5, 0, 3, 1, 1, 0 },
  73. /* ARM L8: 700 MHz */
  74. { 0, 2, 4, 0, 3, 1, 1, 0 },
  75. /* ARM L9: 600 MHz */
  76. { 0, 2, 4, 0, 3, 1, 1, 0 },
  77. /* ARM L10: 500 MHz */
  78. { 0, 2, 4, 0, 3, 1, 1, 0 },
  79. /* ARM L11: 400 MHz */
  80. { 0, 2, 4, 0, 3, 1, 1, 0 },
  81. /* ARM L12: 300 MHz */
  82. { 0, 2, 4, 0, 2, 1, 1, 0 },
  83. /* ARM L13: 200 MHz */
  84. { 0, 1, 3, 0, 1, 1, 1, 0 },
  85. };
  86. static unsigned int clkdiv_cpu0_4412[CPUFREQ_LEVEL_END][8] = {
  87. /*
  88. * Clock divider value for following
  89. * { DIVCORE, DIVCOREM0, DIVCOREM1, DIVPERIPH,
  90. * DIVATB, DIVPCLK_DBG, DIVAPLL, DIVCORE2 }
  91. */
  92. /* ARM L0: 1500 MHz */
  93. { 0, 3, 7, 0, 6, 1, 2, 0 },
  94. /* ARM L1: 1400 MHz */
  95. { 0, 3, 7, 0, 6, 1, 2, 0 },
  96. /* ARM L2: 1300 MHz */
  97. { 0, 3, 7, 0, 5, 1, 2, 0 },
  98. /* ARM L3: 1200 MHz */
  99. { 0, 3, 7, 0, 5, 1, 2, 0 },
  100. /* ARM L4: 1100 MHz */
  101. { 0, 3, 6, 0, 4, 1, 2, 0 },
  102. /* ARM L5: 1000 MHz */
  103. { 0, 2, 5, 0, 4, 1, 1, 0 },
  104. /* ARM L6: 900 MHz */
  105. { 0, 2, 5, 0, 3, 1, 1, 0 },
  106. /* ARM L7: 800 MHz */
  107. { 0, 2, 5, 0, 3, 1, 1, 0 },
  108. /* ARM L8: 700 MHz */
  109. { 0, 2, 4, 0, 3, 1, 1, 0 },
  110. /* ARM L9: 600 MHz */
  111. { 0, 2, 4, 0, 3, 1, 1, 0 },
  112. /* ARM L10: 500 MHz */
  113. { 0, 2, 4, 0, 3, 1, 1, 0 },
  114. /* ARM L11: 400 MHz */
  115. { 0, 2, 4, 0, 3, 1, 1, 0 },
  116. /* ARM L12: 300 MHz */
  117. { 0, 2, 4, 0, 2, 1, 1, 0 },
  118. /* ARM L13: 200 MHz */
  119. { 0, 1, 3, 0, 1, 1, 1, 0 },
  120. };
  121. static unsigned int clkdiv_cpu1_4212[CPUFREQ_LEVEL_END][2] = {
  122. /* Clock divider value for following
  123. * { DIVCOPY, DIVHPM }
  124. */
  125. /* ARM L0: 1500 MHz */
  126. { 6, 0 },
  127. /* ARM L1: 1400 MHz */
  128. { 6, 0 },
  129. /* ARM L2: 1300 MHz */
  130. { 5, 0 },
  131. /* ARM L3: 1200 MHz */
  132. { 5, 0 },
  133. /* ARM L4: 1100 MHz */
  134. { 4, 0 },
  135. /* ARM L5: 1000 MHz */
  136. { 4, 0 },
  137. /* ARM L6: 900 MHz */
  138. { 3, 0 },
  139. /* ARM L7: 800 MHz */
  140. { 3, 0 },
  141. /* ARM L8: 700 MHz */
  142. { 3, 0 },
  143. /* ARM L9: 600 MHz */
  144. { 3, 0 },
  145. /* ARM L10: 500 MHz */
  146. { 3, 0 },
  147. /* ARM L11: 400 MHz */
  148. { 3, 0 },
  149. /* ARM L12: 300 MHz */
  150. { 3, 0 },
  151. /* ARM L13: 200 MHz */
  152. { 3, 0 },
  153. };
  154. static unsigned int clkdiv_cpu1_4412[CPUFREQ_LEVEL_END][3] = {
  155. /* Clock divider value for following
  156. * { DIVCOPY, DIVHPM, DIVCORES }
  157. */
  158. /* ARM L0: 1500 MHz */
  159. { 6, 0, 7 },
  160. /* ARM L1: 1400 MHz */
  161. { 6, 0, 6 },
  162. /* ARM L2: 1300 MHz */
  163. { 5, 0, 6 },
  164. /* ARM L3: 1200 MHz */
  165. { 5, 0, 5 },
  166. /* ARM L4: 1100 MHz */
  167. { 4, 0, 5 },
  168. /* ARM L5: 1000 MHz */
  169. { 4, 0, 4 },
  170. /* ARM L6: 900 MHz */
  171. { 3, 0, 4 },
  172. /* ARM L7: 800 MHz */
  173. { 3, 0, 3 },
  174. /* ARM L8: 700 MHz */
  175. { 3, 0, 3 },
  176. /* ARM L9: 600 MHz */
  177. { 3, 0, 2 },
  178. /* ARM L10: 500 MHz */
  179. { 3, 0, 2 },
  180. /* ARM L11: 400 MHz */
  181. { 3, 0, 1 },
  182. /* ARM L12: 300 MHz */
  183. { 3, 0, 1 },
  184. /* ARM L13: 200 MHz */
  185. { 3, 0, 0 },
  186. };
  187. static unsigned int exynos4x12_apll_pms_table[CPUFREQ_LEVEL_END] = {
  188. /* APLL FOUT L0: 1500 MHz */
  189. ((250 << 16) | (4 << 8) | (0x0)),
  190. /* APLL FOUT L1: 1400 MHz */
  191. ((175 << 16) | (3 << 8) | (0x0)),
  192. /* APLL FOUT L2: 1300 MHz */
  193. ((325 << 16) | (6 << 8) | (0x0)),
  194. /* APLL FOUT L3: 1200 MHz */
  195. ((200 << 16) | (4 << 8) | (0x0)),
  196. /* APLL FOUT L4: 1100 MHz */
  197. ((275 << 16) | (6 << 8) | (0x0)),
  198. /* APLL FOUT L5: 1000 MHz */
  199. ((125 << 16) | (3 << 8) | (0x0)),
  200. /* APLL FOUT L6: 900 MHz */
  201. ((150 << 16) | (4 << 8) | (0x0)),
  202. /* APLL FOUT L7: 800 MHz */
  203. ((100 << 16) | (3 << 8) | (0x0)),
  204. /* APLL FOUT L8: 700 MHz */
  205. ((175 << 16) | (3 << 8) | (0x1)),
  206. /* APLL FOUT L9: 600 MHz */
  207. ((200 << 16) | (4 << 8) | (0x1)),
  208. /* APLL FOUT L10: 500 MHz */
  209. ((125 << 16) | (3 << 8) | (0x1)),
  210. /* APLL FOUT L11 400 MHz */
  211. ((100 << 16) | (3 << 8) | (0x1)),
  212. /* APLL FOUT L12: 300 MHz */
  213. ((200 << 16) | (4 << 8) | (0x2)),
  214. /* APLL FOUT L13: 200 MHz */
  215. ((100 << 16) | (3 << 8) | (0x2)),
  216. };
  217. static const unsigned int asv_voltage_4x12[CPUFREQ_LEVEL_END] = {
  218. 1350000, 1287500, 1250000, 1187500, 1137500, 1087500, 1037500,
  219. 1000000, 987500, 975000, 950000, 925000, 900000, 900000
  220. };
  221. static void exynos4x12_set_clkdiv(unsigned int div_index)
  222. {
  223. unsigned int tmp;
  224. unsigned int stat_cpu1;
  225. /* Change Divider - CPU0 */
  226. tmp = exynos4x12_clkdiv_table[div_index].clkdiv;
  227. __raw_writel(tmp, EXYNOS4_CLKDIV_CPU);
  228. while (__raw_readl(EXYNOS4_CLKDIV_STATCPU) & 0x11111111)
  229. cpu_relax();
  230. /* Change Divider - CPU1 */
  231. tmp = exynos4x12_clkdiv_table[div_index].clkdiv1;
  232. __raw_writel(tmp, EXYNOS4_CLKDIV_CPU1);
  233. if (soc_is_exynos4212())
  234. stat_cpu1 = 0x11;
  235. else
  236. stat_cpu1 = 0x111;
  237. while (__raw_readl(EXYNOS4_CLKDIV_STATCPU1) & stat_cpu1)
  238. cpu_relax();
  239. }
  240. static void exynos4x12_set_apll(unsigned int index)
  241. {
  242. unsigned int tmp, pdiv;
  243. /* 1. MUX_CORE_SEL = MPLL, ARMCLK uses MPLL for lock time */
  244. clk_set_parent(moutcore, mout_mpll);
  245. do {
  246. cpu_relax();
  247. tmp = (__raw_readl(EXYNOS4_CLKMUX_STATCPU)
  248. >> EXYNOS4_CLKSRC_CPU_MUXCORE_SHIFT);
  249. tmp &= 0x7;
  250. } while (tmp != 0x2);
  251. /* 2. Set APLL Lock time */
  252. pdiv = ((exynos4x12_apll_pms_table[index] >> 8) & 0x3f);
  253. __raw_writel((pdiv * 250), EXYNOS4_APLL_LOCK);
  254. /* 3. Change PLL PMS values */
  255. tmp = __raw_readl(EXYNOS4_APLL_CON0);
  256. tmp &= ~((0x3ff << 16) | (0x3f << 8) | (0x7 << 0));
  257. tmp |= exynos4x12_apll_pms_table[index];
  258. __raw_writel(tmp, EXYNOS4_APLL_CON0);
  259. /* 4. wait_lock_time */
  260. do {
  261. cpu_relax();
  262. tmp = __raw_readl(EXYNOS4_APLL_CON0);
  263. } while (!(tmp & (0x1 << EXYNOS4_APLLCON0_LOCKED_SHIFT)));
  264. /* 5. MUX_CORE_SEL = APLL */
  265. clk_set_parent(moutcore, mout_apll);
  266. do {
  267. cpu_relax();
  268. tmp = __raw_readl(EXYNOS4_CLKMUX_STATCPU);
  269. tmp &= EXYNOS4_CLKMUX_STATCPU_MUXCORE_MASK;
  270. } while (tmp != (0x1 << EXYNOS4_CLKSRC_CPU_MUXCORE_SHIFT));
  271. }
  272. bool exynos4x12_pms_change(unsigned int old_index, unsigned int new_index)
  273. {
  274. unsigned int old_pm = exynos4x12_apll_pms_table[old_index] >> 8;
  275. unsigned int new_pm = exynos4x12_apll_pms_table[new_index] >> 8;
  276. return (old_pm == new_pm) ? 0 : 1;
  277. }
  278. static void exynos4x12_set_frequency(unsigned int old_index,
  279. unsigned int new_index)
  280. {
  281. unsigned int tmp;
  282. if (old_index > new_index) {
  283. if (!exynos4x12_pms_change(old_index, new_index)) {
  284. /* 1. Change the system clock divider values */
  285. exynos4x12_set_clkdiv(new_index);
  286. /* 2. Change just s value in apll m,p,s value */
  287. tmp = __raw_readl(EXYNOS4_APLL_CON0);
  288. tmp &= ~(0x7 << 0);
  289. tmp |= (exynos4x12_apll_pms_table[new_index] & 0x7);
  290. __raw_writel(tmp, EXYNOS4_APLL_CON0);
  291. } else {
  292. /* Clock Configuration Procedure */
  293. /* 1. Change the system clock divider values */
  294. exynos4x12_set_clkdiv(new_index);
  295. /* 2. Change the apll m,p,s value */
  296. exynos4x12_set_apll(new_index);
  297. }
  298. } else if (old_index < new_index) {
  299. if (!exynos4x12_pms_change(old_index, new_index)) {
  300. /* 1. Change just s value in apll m,p,s value */
  301. tmp = __raw_readl(EXYNOS4_APLL_CON0);
  302. tmp &= ~(0x7 << 0);
  303. tmp |= (exynos4x12_apll_pms_table[new_index] & 0x7);
  304. __raw_writel(tmp, EXYNOS4_APLL_CON0);
  305. /* 2. Change the system clock divider values */
  306. exynos4x12_set_clkdiv(new_index);
  307. } else {
  308. /* Clock Configuration Procedure */
  309. /* 1. Change the apll m,p,s value */
  310. exynos4x12_set_apll(new_index);
  311. /* 2. Change the system clock divider values */
  312. exynos4x12_set_clkdiv(new_index);
  313. }
  314. }
  315. }
  316. static void __init set_volt_table(void)
  317. {
  318. unsigned int i;
  319. max_support_idx = L1;
  320. /* Not supported */
  321. exynos4x12_freq_table[L0].frequency = CPUFREQ_ENTRY_INVALID;
  322. for (i = 0 ; i < CPUFREQ_LEVEL_END ; i++)
  323. exynos4x12_volt_table[i] = asv_voltage_4x12[i];
  324. }
  325. int exynos4x12_cpufreq_init(struct exynos_dvfs_info *info)
  326. {
  327. int i;
  328. unsigned int tmp;
  329. unsigned long rate;
  330. set_volt_table();
  331. cpu_clk = clk_get(NULL, "armclk");
  332. if (IS_ERR(cpu_clk))
  333. return PTR_ERR(cpu_clk);
  334. moutcore = clk_get(NULL, "moutcore");
  335. if (IS_ERR(moutcore))
  336. goto err_moutcore;
  337. mout_mpll = clk_get(NULL, "mout_mpll");
  338. if (IS_ERR(mout_mpll))
  339. goto err_mout_mpll;
  340. rate = clk_get_rate(mout_mpll) / 1000;
  341. mout_apll = clk_get(NULL, "mout_apll");
  342. if (IS_ERR(mout_apll))
  343. goto err_mout_apll;
  344. for (i = L0; i < CPUFREQ_LEVEL_END; i++) {
  345. exynos4x12_clkdiv_table[i].index = i;
  346. tmp = __raw_readl(EXYNOS4_CLKDIV_CPU);
  347. tmp &= ~(EXYNOS4_CLKDIV_CPU0_CORE_MASK |
  348. EXYNOS4_CLKDIV_CPU0_COREM0_MASK |
  349. EXYNOS4_CLKDIV_CPU0_COREM1_MASK |
  350. EXYNOS4_CLKDIV_CPU0_PERIPH_MASK |
  351. EXYNOS4_CLKDIV_CPU0_ATB_MASK |
  352. EXYNOS4_CLKDIV_CPU0_PCLKDBG_MASK |
  353. EXYNOS4_CLKDIV_CPU0_APLL_MASK);
  354. if (soc_is_exynos4212()) {
  355. tmp |= ((clkdiv_cpu0_4212[i][0] << EXYNOS4_CLKDIV_CPU0_CORE_SHIFT) |
  356. (clkdiv_cpu0_4212[i][1] << EXYNOS4_CLKDIV_CPU0_COREM0_SHIFT) |
  357. (clkdiv_cpu0_4212[i][2] << EXYNOS4_CLKDIV_CPU0_COREM1_SHIFT) |
  358. (clkdiv_cpu0_4212[i][3] << EXYNOS4_CLKDIV_CPU0_PERIPH_SHIFT) |
  359. (clkdiv_cpu0_4212[i][4] << EXYNOS4_CLKDIV_CPU0_ATB_SHIFT) |
  360. (clkdiv_cpu0_4212[i][5] << EXYNOS4_CLKDIV_CPU0_PCLKDBG_SHIFT) |
  361. (clkdiv_cpu0_4212[i][6] << EXYNOS4_CLKDIV_CPU0_APLL_SHIFT));
  362. } else {
  363. tmp &= ~EXYNOS4_CLKDIV_CPU0_CORE2_MASK;
  364. tmp |= ((clkdiv_cpu0_4412[i][0] << EXYNOS4_CLKDIV_CPU0_CORE_SHIFT) |
  365. (clkdiv_cpu0_4412[i][1] << EXYNOS4_CLKDIV_CPU0_COREM0_SHIFT) |
  366. (clkdiv_cpu0_4412[i][2] << EXYNOS4_CLKDIV_CPU0_COREM1_SHIFT) |
  367. (clkdiv_cpu0_4412[i][3] << EXYNOS4_CLKDIV_CPU0_PERIPH_SHIFT) |
  368. (clkdiv_cpu0_4412[i][4] << EXYNOS4_CLKDIV_CPU0_ATB_SHIFT) |
  369. (clkdiv_cpu0_4412[i][5] << EXYNOS4_CLKDIV_CPU0_PCLKDBG_SHIFT) |
  370. (clkdiv_cpu0_4412[i][6] << EXYNOS4_CLKDIV_CPU0_APLL_SHIFT) |
  371. (clkdiv_cpu0_4412[i][7] << EXYNOS4_CLKDIV_CPU0_CORE2_SHIFT));
  372. }
  373. exynos4x12_clkdiv_table[i].clkdiv = tmp;
  374. tmp = __raw_readl(EXYNOS4_CLKDIV_CPU1);
  375. if (soc_is_exynos4212()) {
  376. tmp &= ~(EXYNOS4_CLKDIV_CPU1_COPY_MASK |
  377. EXYNOS4_CLKDIV_CPU1_HPM_MASK);
  378. tmp |= ((clkdiv_cpu1_4212[i][0] << EXYNOS4_CLKDIV_CPU1_COPY_SHIFT) |
  379. (clkdiv_cpu1_4212[i][1] << EXYNOS4_CLKDIV_CPU1_HPM_SHIFT));
  380. } else {
  381. tmp &= ~(EXYNOS4_CLKDIV_CPU1_COPY_MASK |
  382. EXYNOS4_CLKDIV_CPU1_HPM_MASK |
  383. EXYNOS4_CLKDIV_CPU1_CORES_MASK);
  384. tmp |= ((clkdiv_cpu1_4412[i][0] << EXYNOS4_CLKDIV_CPU1_COPY_SHIFT) |
  385. (clkdiv_cpu1_4412[i][1] << EXYNOS4_CLKDIV_CPU1_HPM_SHIFT) |
  386. (clkdiv_cpu1_4412[i][2] << EXYNOS4_CLKDIV_CPU1_CORES_SHIFT));
  387. }
  388. exynos4x12_clkdiv_table[i].clkdiv1 = tmp;
  389. }
  390. info->mpll_freq_khz = rate;
  391. info->pm_lock_idx = L5;
  392. info->pll_safe_idx = L7;
  393. info->max_support_idx = max_support_idx;
  394. info->min_support_idx = min_support_idx;
  395. info->cpu_clk = cpu_clk;
  396. info->volt_table = exynos4x12_volt_table;
  397. info->freq_table = exynos4x12_freq_table;
  398. info->set_freq = exynos4x12_set_frequency;
  399. info->need_apll_change = exynos4x12_pms_change;
  400. return 0;
  401. err_mout_apll:
  402. clk_put(mout_mpll);
  403. err_mout_mpll:
  404. clk_put(moutcore);
  405. err_moutcore:
  406. clk_put(cpu_clk);
  407. pr_debug("%s: failed initialization\n", __func__);
  408. return -EINVAL;
  409. }
  410. EXPORT_SYMBOL(exynos4x12_cpufreq_init);