exynos4210-cpufreq.c 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568
  1. /*
  2. * Copyright (c) 2010-2011 Samsung Electronics Co., Ltd.
  3. * http://www.samsung.com
  4. *
  5. * EXYNOS4 - 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/types.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/regulator/consumer.h>
  18. #include <linux/cpufreq.h>
  19. #include <mach/map.h>
  20. #include <mach/regs-clock.h>
  21. #include <mach/regs-mem.h>
  22. #include <plat/clock.h>
  23. #include <plat/pm.h>
  24. static struct clk *cpu_clk;
  25. static struct clk *moutcore;
  26. static struct clk *mout_mpll;
  27. static struct clk *mout_apll;
  28. static struct regulator *arm_regulator;
  29. static struct regulator *int_regulator;
  30. static struct cpufreq_freqs freqs;
  31. static unsigned int memtype;
  32. enum exynos4_memory_type {
  33. DDR2 = 4,
  34. LPDDR2,
  35. DDR3,
  36. };
  37. enum cpufreq_level_index {
  38. L0, L1, L2, L3, CPUFREQ_LEVEL_END,
  39. };
  40. static struct cpufreq_frequency_table exynos4_freq_table[] = {
  41. {L0, 1000*1000},
  42. {L1, 800*1000},
  43. {L2, 400*1000},
  44. {L3, 100*1000},
  45. {0, CPUFREQ_TABLE_END},
  46. };
  47. static unsigned int clkdiv_cpu0[CPUFREQ_LEVEL_END][7] = {
  48. /*
  49. * Clock divider value for following
  50. * { DIVCORE, DIVCOREM0, DIVCOREM1, DIVPERIPH,
  51. * DIVATB, DIVPCLK_DBG, DIVAPLL }
  52. */
  53. /* ARM L0: 1000MHz */
  54. { 0, 3, 7, 3, 3, 0, 1 },
  55. /* ARM L1: 800MHz */
  56. { 0, 3, 7, 3, 3, 0, 1 },
  57. /* ARM L2: 400MHz */
  58. { 0, 1, 3, 1, 3, 0, 1 },
  59. /* ARM L3: 100MHz */
  60. { 0, 0, 1, 0, 3, 1, 1 },
  61. };
  62. static unsigned int clkdiv_cpu1[CPUFREQ_LEVEL_END][2] = {
  63. /*
  64. * Clock divider value for following
  65. * { DIVCOPY, DIVHPM }
  66. */
  67. /* ARM L0: 1000MHz */
  68. { 3, 0 },
  69. /* ARM L1: 800MHz */
  70. { 3, 0 },
  71. /* ARM L2: 400MHz */
  72. { 3, 0 },
  73. /* ARM L3: 100MHz */
  74. { 3, 0 },
  75. };
  76. static unsigned int clkdiv_dmc0[CPUFREQ_LEVEL_END][8] = {
  77. /*
  78. * Clock divider value for following
  79. * { DIVACP, DIVACP_PCLK, DIVDPHY, DIVDMC, DIVDMCD
  80. * DIVDMCP, DIVCOPY2, DIVCORE_TIMERS }
  81. */
  82. /* DMC L0: 400MHz */
  83. { 3, 1, 1, 1, 1, 1, 3, 1 },
  84. /* DMC L1: 400MHz */
  85. { 3, 1, 1, 1, 1, 1, 3, 1 },
  86. /* DMC L2: 266.7MHz */
  87. { 7, 1, 1, 2, 1, 1, 3, 1 },
  88. /* DMC L3: 200MHz */
  89. { 7, 1, 1, 3, 1, 1, 3, 1 },
  90. };
  91. static unsigned int clkdiv_top[CPUFREQ_LEVEL_END][5] = {
  92. /*
  93. * Clock divider value for following
  94. * { DIVACLK200, DIVACLK100, DIVACLK160, DIVACLK133, DIVONENAND }
  95. */
  96. /* ACLK200 L0: 200MHz */
  97. { 3, 7, 4, 5, 1 },
  98. /* ACLK200 L1: 200MHz */
  99. { 3, 7, 4, 5, 1 },
  100. /* ACLK200 L2: 160MHz */
  101. { 4, 7, 5, 7, 1 },
  102. /* ACLK200 L3: 133.3MHz */
  103. { 5, 7, 7, 7, 1 },
  104. };
  105. static unsigned int clkdiv_lr_bus[CPUFREQ_LEVEL_END][2] = {
  106. /*
  107. * Clock divider value for following
  108. * { DIVGDL/R, DIVGPL/R }
  109. */
  110. /* ACLK_GDL/R L0: 200MHz */
  111. { 3, 1 },
  112. /* ACLK_GDL/R L1: 200MHz */
  113. { 3, 1 },
  114. /* ACLK_GDL/R L2: 160MHz */
  115. { 4, 1 },
  116. /* ACLK_GDL/R L3: 133.3MHz */
  117. { 5, 1 },
  118. };
  119. struct cpufreq_voltage_table {
  120. unsigned int index; /* any */
  121. unsigned int arm_volt; /* uV */
  122. unsigned int int_volt;
  123. };
  124. static struct cpufreq_voltage_table exynos4_volt_table[CPUFREQ_LEVEL_END] = {
  125. {
  126. .index = L0,
  127. .arm_volt = 1200000,
  128. .int_volt = 1100000,
  129. }, {
  130. .index = L1,
  131. .arm_volt = 1100000,
  132. .int_volt = 1100000,
  133. }, {
  134. .index = L2,
  135. .arm_volt = 1000000,
  136. .int_volt = 1000000,
  137. }, {
  138. .index = L3,
  139. .arm_volt = 900000,
  140. .int_volt = 1000000,
  141. },
  142. };
  143. static unsigned int exynos4_apll_pms_table[CPUFREQ_LEVEL_END] = {
  144. /* APLL FOUT L0: 1000MHz */
  145. ((250 << 16) | (6 << 8) | 1),
  146. /* APLL FOUT L1: 800MHz */
  147. ((200 << 16) | (6 << 8) | 1),
  148. /* APLL FOUT L2 : 400MHz */
  149. ((200 << 16) | (6 << 8) | 2),
  150. /* APLL FOUT L3: 100MHz */
  151. ((200 << 16) | (6 << 8) | 4),
  152. };
  153. static int exynos4_verify_speed(struct cpufreq_policy *policy)
  154. {
  155. return cpufreq_frequency_table_verify(policy, exynos4_freq_table);
  156. }
  157. static unsigned int exynos4_getspeed(unsigned int cpu)
  158. {
  159. return clk_get_rate(cpu_clk) / 1000;
  160. }
  161. static void exynos4_set_clkdiv(unsigned int div_index)
  162. {
  163. unsigned int tmp;
  164. /* Change Divider - CPU0 */
  165. tmp = __raw_readl(S5P_CLKDIV_CPU);
  166. tmp &= ~(S5P_CLKDIV_CPU0_CORE_MASK | S5P_CLKDIV_CPU0_COREM0_MASK |
  167. S5P_CLKDIV_CPU0_COREM1_MASK | S5P_CLKDIV_CPU0_PERIPH_MASK |
  168. S5P_CLKDIV_CPU0_ATB_MASK | S5P_CLKDIV_CPU0_PCLKDBG_MASK |
  169. S5P_CLKDIV_CPU0_APLL_MASK);
  170. tmp |= ((clkdiv_cpu0[div_index][0] << S5P_CLKDIV_CPU0_CORE_SHIFT) |
  171. (clkdiv_cpu0[div_index][1] << S5P_CLKDIV_CPU0_COREM0_SHIFT) |
  172. (clkdiv_cpu0[div_index][2] << S5P_CLKDIV_CPU0_COREM1_SHIFT) |
  173. (clkdiv_cpu0[div_index][3] << S5P_CLKDIV_CPU0_PERIPH_SHIFT) |
  174. (clkdiv_cpu0[div_index][4] << S5P_CLKDIV_CPU0_ATB_SHIFT) |
  175. (clkdiv_cpu0[div_index][5] << S5P_CLKDIV_CPU0_PCLKDBG_SHIFT) |
  176. (clkdiv_cpu0[div_index][6] << S5P_CLKDIV_CPU0_APLL_SHIFT));
  177. __raw_writel(tmp, S5P_CLKDIV_CPU);
  178. do {
  179. tmp = __raw_readl(S5P_CLKDIV_STATCPU);
  180. } while (tmp & 0x1111111);
  181. /* Change Divider - CPU1 */
  182. tmp = __raw_readl(S5P_CLKDIV_CPU1);
  183. tmp &= ~((0x7 << 4) | 0x7);
  184. tmp |= ((clkdiv_cpu1[div_index][0] << 4) |
  185. (clkdiv_cpu1[div_index][1] << 0));
  186. __raw_writel(tmp, S5P_CLKDIV_CPU1);
  187. do {
  188. tmp = __raw_readl(S5P_CLKDIV_STATCPU1);
  189. } while (tmp & 0x11);
  190. /* Change Divider - DMC0 */
  191. tmp = __raw_readl(S5P_CLKDIV_DMC0);
  192. tmp &= ~(S5P_CLKDIV_DMC0_ACP_MASK | S5P_CLKDIV_DMC0_ACPPCLK_MASK |
  193. S5P_CLKDIV_DMC0_DPHY_MASK | S5P_CLKDIV_DMC0_DMC_MASK |
  194. S5P_CLKDIV_DMC0_DMCD_MASK | S5P_CLKDIV_DMC0_DMCP_MASK |
  195. S5P_CLKDIV_DMC0_COPY2_MASK | S5P_CLKDIV_DMC0_CORETI_MASK);
  196. tmp |= ((clkdiv_dmc0[div_index][0] << S5P_CLKDIV_DMC0_ACP_SHIFT) |
  197. (clkdiv_dmc0[div_index][1] << S5P_CLKDIV_DMC0_ACPPCLK_SHIFT) |
  198. (clkdiv_dmc0[div_index][2] << S5P_CLKDIV_DMC0_DPHY_SHIFT) |
  199. (clkdiv_dmc0[div_index][3] << S5P_CLKDIV_DMC0_DMC_SHIFT) |
  200. (clkdiv_dmc0[div_index][4] << S5P_CLKDIV_DMC0_DMCD_SHIFT) |
  201. (clkdiv_dmc0[div_index][5] << S5P_CLKDIV_DMC0_DMCP_SHIFT) |
  202. (clkdiv_dmc0[div_index][6] << S5P_CLKDIV_DMC0_COPY2_SHIFT) |
  203. (clkdiv_dmc0[div_index][7] << S5P_CLKDIV_DMC0_CORETI_SHIFT));
  204. __raw_writel(tmp, S5P_CLKDIV_DMC0);
  205. do {
  206. tmp = __raw_readl(S5P_CLKDIV_STAT_DMC0);
  207. } while (tmp & 0x11111111);
  208. /* Change Divider - TOP */
  209. tmp = __raw_readl(S5P_CLKDIV_TOP);
  210. tmp &= ~(S5P_CLKDIV_TOP_ACLK200_MASK | S5P_CLKDIV_TOP_ACLK100_MASK |
  211. S5P_CLKDIV_TOP_ACLK160_MASK | S5P_CLKDIV_TOP_ACLK133_MASK |
  212. S5P_CLKDIV_TOP_ONENAND_MASK);
  213. tmp |= ((clkdiv_top[div_index][0] << S5P_CLKDIV_TOP_ACLK200_SHIFT) |
  214. (clkdiv_top[div_index][1] << S5P_CLKDIV_TOP_ACLK100_SHIFT) |
  215. (clkdiv_top[div_index][2] << S5P_CLKDIV_TOP_ACLK160_SHIFT) |
  216. (clkdiv_top[div_index][3] << S5P_CLKDIV_TOP_ACLK133_SHIFT) |
  217. (clkdiv_top[div_index][4] << S5P_CLKDIV_TOP_ONENAND_SHIFT));
  218. __raw_writel(tmp, S5P_CLKDIV_TOP);
  219. do {
  220. tmp = __raw_readl(S5P_CLKDIV_STAT_TOP);
  221. } while (tmp & 0x11111);
  222. /* Change Divider - LEFTBUS */
  223. tmp = __raw_readl(S5P_CLKDIV_LEFTBUS);
  224. tmp &= ~(S5P_CLKDIV_BUS_GDLR_MASK | S5P_CLKDIV_BUS_GPLR_MASK);
  225. tmp |= ((clkdiv_lr_bus[div_index][0] << S5P_CLKDIV_BUS_GDLR_SHIFT) |
  226. (clkdiv_lr_bus[div_index][1] << S5P_CLKDIV_BUS_GPLR_SHIFT));
  227. __raw_writel(tmp, S5P_CLKDIV_LEFTBUS);
  228. do {
  229. tmp = __raw_readl(S5P_CLKDIV_STAT_LEFTBUS);
  230. } while (tmp & 0x11);
  231. /* Change Divider - RIGHTBUS */
  232. tmp = __raw_readl(S5P_CLKDIV_RIGHTBUS);
  233. tmp &= ~(S5P_CLKDIV_BUS_GDLR_MASK | S5P_CLKDIV_BUS_GPLR_MASK);
  234. tmp |= ((clkdiv_lr_bus[div_index][0] << S5P_CLKDIV_BUS_GDLR_SHIFT) |
  235. (clkdiv_lr_bus[div_index][1] << S5P_CLKDIV_BUS_GPLR_SHIFT));
  236. __raw_writel(tmp, S5P_CLKDIV_RIGHTBUS);
  237. do {
  238. tmp = __raw_readl(S5P_CLKDIV_STAT_RIGHTBUS);
  239. } while (tmp & 0x11);
  240. }
  241. static void exynos4_set_apll(unsigned int index)
  242. {
  243. unsigned int tmp;
  244. /* 1. MUX_CORE_SEL = MPLL, ARMCLK uses MPLL for lock time */
  245. clk_set_parent(moutcore, mout_mpll);
  246. do {
  247. tmp = (__raw_readl(S5P_CLKMUX_STATCPU)
  248. >> S5P_CLKSRC_CPU_MUXCORE_SHIFT);
  249. tmp &= 0x7;
  250. } while (tmp != 0x2);
  251. /* 2. Set APLL Lock time */
  252. __raw_writel(S5P_APLL_LOCKTIME, S5P_APLL_LOCK);
  253. /* 3. Change PLL PMS values */
  254. tmp = __raw_readl(S5P_APLL_CON0);
  255. tmp &= ~((0x3ff << 16) | (0x3f << 8) | (0x7 << 0));
  256. tmp |= exynos4_apll_pms_table[index];
  257. __raw_writel(tmp, S5P_APLL_CON0);
  258. /* 4. wait_lock_time */
  259. do {
  260. tmp = __raw_readl(S5P_APLL_CON0);
  261. } while (!(tmp & (0x1 << S5P_APLLCON0_LOCKED_SHIFT)));
  262. /* 5. MUX_CORE_SEL = APLL */
  263. clk_set_parent(moutcore, mout_apll);
  264. do {
  265. tmp = __raw_readl(S5P_CLKMUX_STATCPU);
  266. tmp &= S5P_CLKMUX_STATCPU_MUXCORE_MASK;
  267. } while (tmp != (0x1 << S5P_CLKSRC_CPU_MUXCORE_SHIFT));
  268. }
  269. static void exynos4_set_frequency(unsigned int old_index, unsigned int new_index)
  270. {
  271. unsigned int tmp;
  272. if (old_index > new_index) {
  273. /* The frequency changing to L0 needs to change apll */
  274. if (freqs.new == exynos4_freq_table[L0].frequency) {
  275. /* 1. Change the system clock divider values */
  276. exynos4_set_clkdiv(new_index);
  277. /* 2. Change the apll m,p,s value */
  278. exynos4_set_apll(new_index);
  279. } else {
  280. /* 1. Change the system clock divider values */
  281. exynos4_set_clkdiv(new_index);
  282. /* 2. Change just s value in apll m,p,s value */
  283. tmp = __raw_readl(S5P_APLL_CON0);
  284. tmp &= ~(0x7 << 0);
  285. tmp |= (exynos4_apll_pms_table[new_index] & 0x7);
  286. __raw_writel(tmp, S5P_APLL_CON0);
  287. }
  288. }
  289. else if (old_index < new_index) {
  290. /* The frequency changing from L0 needs to change apll */
  291. if (freqs.old == exynos4_freq_table[L0].frequency) {
  292. /* 1. Change the apll m,p,s value */
  293. exynos4_set_apll(new_index);
  294. /* 2. Change the system clock divider values */
  295. exynos4_set_clkdiv(new_index);
  296. } else {
  297. /* 1. Change just s value in apll m,p,s value */
  298. tmp = __raw_readl(S5P_APLL_CON0);
  299. tmp &= ~(0x7 << 0);
  300. tmp |= (exynos4_apll_pms_table[new_index] & 0x7);
  301. __raw_writel(tmp, S5P_APLL_CON0);
  302. /* 2. Change the system clock divider values */
  303. exynos4_set_clkdiv(new_index);
  304. }
  305. }
  306. }
  307. static int exynos4_target(struct cpufreq_policy *policy,
  308. unsigned int target_freq,
  309. unsigned int relation)
  310. {
  311. unsigned int index, old_index;
  312. unsigned int arm_volt, int_volt;
  313. freqs.old = exynos4_getspeed(policy->cpu);
  314. if (cpufreq_frequency_table_target(policy, exynos4_freq_table,
  315. freqs.old, relation, &old_index))
  316. return -EINVAL;
  317. if (cpufreq_frequency_table_target(policy, exynos4_freq_table,
  318. target_freq, relation, &index))
  319. return -EINVAL;
  320. freqs.new = exynos4_freq_table[index].frequency;
  321. freqs.cpu = policy->cpu;
  322. if (freqs.new == freqs.old)
  323. return 0;
  324. /* get the voltage value */
  325. arm_volt = exynos4_volt_table[index].arm_volt;
  326. int_volt = exynos4_volt_table[index].int_volt;
  327. cpufreq_notify_transition(&freqs, CPUFREQ_PRECHANGE);
  328. /* control regulator */
  329. if (freqs.new > freqs.old) {
  330. /* Voltage up */
  331. regulator_set_voltage(arm_regulator, arm_volt, arm_volt);
  332. regulator_set_voltage(int_regulator, int_volt, int_volt);
  333. }
  334. /* Clock Configuration Procedure */
  335. exynos4_set_frequency(old_index, index);
  336. /* control regulator */
  337. if (freqs.new < freqs.old) {
  338. /* Voltage down */
  339. regulator_set_voltage(arm_regulator, arm_volt, arm_volt);
  340. regulator_set_voltage(int_regulator, int_volt, int_volt);
  341. }
  342. cpufreq_notify_transition(&freqs, CPUFREQ_POSTCHANGE);
  343. return 0;
  344. }
  345. #ifdef CONFIG_PM
  346. static int exynos4_cpufreq_suspend(struct cpufreq_policy *policy)
  347. {
  348. return 0;
  349. }
  350. static int exynos4_cpufreq_resume(struct cpufreq_policy *policy)
  351. {
  352. return 0;
  353. }
  354. #endif
  355. static int exynos4_cpufreq_cpu_init(struct cpufreq_policy *policy)
  356. {
  357. policy->cur = policy->min = policy->max = exynos4_getspeed(policy->cpu);
  358. cpufreq_frequency_table_get_attr(exynos4_freq_table, policy->cpu);
  359. /* set the transition latency value */
  360. policy->cpuinfo.transition_latency = 100000;
  361. /*
  362. * EXYNOS4 multi-core processors has 2 cores
  363. * that the frequency cannot be set independently.
  364. * Each cpu is bound to the same speed.
  365. * So the affected cpu is all of the cpus.
  366. */
  367. cpumask_setall(policy->cpus);
  368. return cpufreq_frequency_table_cpuinfo(policy, exynos4_freq_table);
  369. }
  370. static struct cpufreq_driver exynos4_driver = {
  371. .flags = CPUFREQ_STICKY,
  372. .verify = exynos4_verify_speed,
  373. .target = exynos4_target,
  374. .get = exynos4_getspeed,
  375. .init = exynos4_cpufreq_cpu_init,
  376. .name = "exynos4_cpufreq",
  377. #ifdef CONFIG_PM
  378. .suspend = exynos4_cpufreq_suspend,
  379. .resume = exynos4_cpufreq_resume,
  380. #endif
  381. };
  382. static int __init exynos4_cpufreq_init(void)
  383. {
  384. cpu_clk = clk_get(NULL, "armclk");
  385. if (IS_ERR(cpu_clk))
  386. return PTR_ERR(cpu_clk);
  387. moutcore = clk_get(NULL, "moutcore");
  388. if (IS_ERR(moutcore))
  389. goto out;
  390. mout_mpll = clk_get(NULL, "mout_mpll");
  391. if (IS_ERR(mout_mpll))
  392. goto out;
  393. mout_apll = clk_get(NULL, "mout_apll");
  394. if (IS_ERR(mout_apll))
  395. goto out;
  396. arm_regulator = regulator_get(NULL, "vdd_arm");
  397. if (IS_ERR(arm_regulator)) {
  398. printk(KERN_ERR "failed to get resource %s\n", "vdd_arm");
  399. goto out;
  400. }
  401. int_regulator = regulator_get(NULL, "vdd_int");
  402. if (IS_ERR(int_regulator)) {
  403. printk(KERN_ERR "failed to get resource %s\n", "vdd_int");
  404. goto out;
  405. }
  406. /*
  407. * Check DRAM type.
  408. * Because DVFS level is different according to DRAM type.
  409. */
  410. memtype = __raw_readl(S5P_VA_DMC0 + S5P_DMC0_MEMCON_OFFSET);
  411. memtype = (memtype >> S5P_DMC0_MEMTYPE_SHIFT);
  412. memtype &= S5P_DMC0_MEMTYPE_MASK;
  413. if ((memtype < DDR2) && (memtype > DDR3)) {
  414. printk(KERN_ERR "%s: wrong memtype= 0x%x\n", __func__, memtype);
  415. goto out;
  416. } else {
  417. printk(KERN_DEBUG "%s: memtype= 0x%x\n", __func__, memtype);
  418. }
  419. return cpufreq_register_driver(&exynos4_driver);
  420. out:
  421. if (!IS_ERR(cpu_clk))
  422. clk_put(cpu_clk);
  423. if (!IS_ERR(moutcore))
  424. clk_put(moutcore);
  425. if (!IS_ERR(mout_mpll))
  426. clk_put(mout_mpll);
  427. if (!IS_ERR(mout_apll))
  428. clk_put(mout_apll);
  429. if (!IS_ERR(arm_regulator))
  430. regulator_put(arm_regulator);
  431. if (!IS_ERR(int_regulator))
  432. regulator_put(int_regulator);
  433. printk(KERN_ERR "%s: failed initialization\n", __func__);
  434. return -EINVAL;
  435. }
  436. late_initcall(exynos4_cpufreq_init);