s3c2416-cpufreq.c 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492
  1. // SPDX-License-Identifier: GPL-2.0-only
  2. /*
  3. * S3C2416/2450 CPUfreq Support
  4. *
  5. * Copyright 2011 Heiko Stuebner <heiko@sntech.de>
  6. *
  7. * based on s3c64xx_cpufreq.c
  8. *
  9. * Copyright 2009 Wolfson Microelectronics plc
  10. */
  11. #include <linux/kernel.h>
  12. #include <linux/types.h>
  13. #include <linux/init.h>
  14. #include <linux/cpufreq.h>
  15. #include <linux/clk.h>
  16. #include <linux/err.h>
  17. #include <linux/regulator/consumer.h>
  18. #include <linux/reboot.h>
  19. #include <linux/module.h>
  20. static DEFINE_MUTEX(cpufreq_lock);
  21. struct s3c2416_data {
  22. struct clk *armdiv;
  23. struct clk *armclk;
  24. struct clk *hclk;
  25. unsigned long regulator_latency;
  26. #ifdef CONFIG_ARM_S3C2416_CPUFREQ_VCORESCALE
  27. struct regulator *vddarm;
  28. #endif
  29. struct cpufreq_frequency_table *freq_table;
  30. bool is_dvs;
  31. bool disable_dvs;
  32. };
  33. static struct s3c2416_data s3c2416_cpufreq;
  34. struct s3c2416_dvfs {
  35. unsigned int vddarm_min;
  36. unsigned int vddarm_max;
  37. };
  38. /* pseudo-frequency for dvs mode */
  39. #define FREQ_DVS 132333
  40. /* frequency to sleep and reboot in
  41. * it's essential to leave dvs, as some boards do not reconfigure the
  42. * regulator on reboot
  43. */
  44. #define FREQ_SLEEP 133333
  45. /* Sources for the ARMCLK */
  46. #define SOURCE_HCLK 0
  47. #define SOURCE_ARMDIV 1
  48. #ifdef CONFIG_ARM_S3C2416_CPUFREQ_VCORESCALE
  49. /* S3C2416 only supports changing the voltage in the dvs-mode.
  50. * Voltages down to 1.0V seem to work, so we take what the regulator
  51. * can get us.
  52. */
  53. static struct s3c2416_dvfs s3c2416_dvfs_table[] = {
  54. [SOURCE_HCLK] = { 950000, 1250000 },
  55. [SOURCE_ARMDIV] = { 1250000, 1350000 },
  56. };
  57. #endif
  58. static struct cpufreq_frequency_table s3c2416_freq_table[] = {
  59. { 0, SOURCE_HCLK, FREQ_DVS },
  60. { 0, SOURCE_ARMDIV, 133333 },
  61. { 0, SOURCE_ARMDIV, 266666 },
  62. { 0, SOURCE_ARMDIV, 400000 },
  63. { 0, 0, CPUFREQ_TABLE_END },
  64. };
  65. static struct cpufreq_frequency_table s3c2450_freq_table[] = {
  66. { 0, SOURCE_HCLK, FREQ_DVS },
  67. { 0, SOURCE_ARMDIV, 133500 },
  68. { 0, SOURCE_ARMDIV, 267000 },
  69. { 0, SOURCE_ARMDIV, 534000 },
  70. { 0, 0, CPUFREQ_TABLE_END },
  71. };
  72. static unsigned int s3c2416_cpufreq_get_speed(unsigned int cpu)
  73. {
  74. struct s3c2416_data *s3c_freq = &s3c2416_cpufreq;
  75. if (cpu != 0)
  76. return 0;
  77. /* return our pseudo-frequency when in dvs mode */
  78. if (s3c_freq->is_dvs)
  79. return FREQ_DVS;
  80. return clk_get_rate(s3c_freq->armclk) / 1000;
  81. }
  82. static int s3c2416_cpufreq_set_armdiv(struct s3c2416_data *s3c_freq,
  83. unsigned int freq)
  84. {
  85. int ret;
  86. if (clk_get_rate(s3c_freq->armdiv) / 1000 != freq) {
  87. ret = clk_set_rate(s3c_freq->armdiv, freq * 1000);
  88. if (ret < 0) {
  89. pr_err("cpufreq: Failed to set armdiv rate %dkHz: %d\n",
  90. freq, ret);
  91. return ret;
  92. }
  93. }
  94. return 0;
  95. }
  96. static int s3c2416_cpufreq_enter_dvs(struct s3c2416_data *s3c_freq, int idx)
  97. {
  98. #ifdef CONFIG_ARM_S3C2416_CPUFREQ_VCORESCALE
  99. struct s3c2416_dvfs *dvfs;
  100. #endif
  101. int ret;
  102. if (s3c_freq->is_dvs) {
  103. pr_debug("cpufreq: already in dvs mode, nothing to do\n");
  104. return 0;
  105. }
  106. pr_debug("cpufreq: switching armclk to hclk (%lukHz)\n",
  107. clk_get_rate(s3c_freq->hclk) / 1000);
  108. ret = clk_set_parent(s3c_freq->armclk, s3c_freq->hclk);
  109. if (ret < 0) {
  110. pr_err("cpufreq: Failed to switch armclk to hclk: %d\n", ret);
  111. return ret;
  112. }
  113. #ifdef CONFIG_ARM_S3C2416_CPUFREQ_VCORESCALE
  114. /* changing the core voltage is only allowed when in dvs mode */
  115. if (s3c_freq->vddarm) {
  116. dvfs = &s3c2416_dvfs_table[idx];
  117. pr_debug("cpufreq: setting regulator to %d-%d\n",
  118. dvfs->vddarm_min, dvfs->vddarm_max);
  119. ret = regulator_set_voltage(s3c_freq->vddarm,
  120. dvfs->vddarm_min,
  121. dvfs->vddarm_max);
  122. /* when lowering the voltage failed, there is nothing to do */
  123. if (ret != 0)
  124. pr_err("cpufreq: Failed to set VDDARM: %d\n", ret);
  125. }
  126. #endif
  127. s3c_freq->is_dvs = 1;
  128. return 0;
  129. }
  130. static int s3c2416_cpufreq_leave_dvs(struct s3c2416_data *s3c_freq, int idx)
  131. {
  132. #ifdef CONFIG_ARM_S3C2416_CPUFREQ_VCORESCALE
  133. struct s3c2416_dvfs *dvfs;
  134. #endif
  135. int ret;
  136. if (!s3c_freq->is_dvs) {
  137. pr_debug("cpufreq: not in dvs mode, so can't leave\n");
  138. return 0;
  139. }
  140. #ifdef CONFIG_ARM_S3C2416_CPUFREQ_VCORESCALE
  141. if (s3c_freq->vddarm) {
  142. dvfs = &s3c2416_dvfs_table[idx];
  143. pr_debug("cpufreq: setting regulator to %d-%d\n",
  144. dvfs->vddarm_min, dvfs->vddarm_max);
  145. ret = regulator_set_voltage(s3c_freq->vddarm,
  146. dvfs->vddarm_min,
  147. dvfs->vddarm_max);
  148. if (ret != 0) {
  149. pr_err("cpufreq: Failed to set VDDARM: %d\n", ret);
  150. return ret;
  151. }
  152. }
  153. #endif
  154. /* force armdiv to hclk frequency for transition from dvs*/
  155. if (clk_get_rate(s3c_freq->armdiv) > clk_get_rate(s3c_freq->hclk)) {
  156. pr_debug("cpufreq: force armdiv to hclk frequency (%lukHz)\n",
  157. clk_get_rate(s3c_freq->hclk) / 1000);
  158. ret = s3c2416_cpufreq_set_armdiv(s3c_freq,
  159. clk_get_rate(s3c_freq->hclk) / 1000);
  160. if (ret < 0) {
  161. pr_err("cpufreq: Failed to set the armdiv to %lukHz: %d\n",
  162. clk_get_rate(s3c_freq->hclk) / 1000, ret);
  163. return ret;
  164. }
  165. }
  166. pr_debug("cpufreq: switching armclk parent to armdiv (%lukHz)\n",
  167. clk_get_rate(s3c_freq->armdiv) / 1000);
  168. ret = clk_set_parent(s3c_freq->armclk, s3c_freq->armdiv);
  169. if (ret < 0) {
  170. pr_err("cpufreq: Failed to switch armclk clock parent to armdiv: %d\n",
  171. ret);
  172. return ret;
  173. }
  174. s3c_freq->is_dvs = 0;
  175. return 0;
  176. }
  177. static int s3c2416_cpufreq_set_target(struct cpufreq_policy *policy,
  178. unsigned int index)
  179. {
  180. struct s3c2416_data *s3c_freq = &s3c2416_cpufreq;
  181. unsigned int new_freq;
  182. int idx, ret, to_dvs = 0;
  183. mutex_lock(&cpufreq_lock);
  184. idx = s3c_freq->freq_table[index].driver_data;
  185. if (idx == SOURCE_HCLK)
  186. to_dvs = 1;
  187. /* switching to dvs when it's not allowed */
  188. if (to_dvs && s3c_freq->disable_dvs) {
  189. pr_debug("cpufreq: entering dvs mode not allowed\n");
  190. ret = -EINVAL;
  191. goto out;
  192. }
  193. /* When leavin dvs mode, always switch the armdiv to the hclk rate
  194. * The S3C2416 has stability issues when switching directly to
  195. * higher frequencies.
  196. */
  197. new_freq = (s3c_freq->is_dvs && !to_dvs)
  198. ? clk_get_rate(s3c_freq->hclk) / 1000
  199. : s3c_freq->freq_table[index].frequency;
  200. if (to_dvs) {
  201. pr_debug("cpufreq: enter dvs\n");
  202. ret = s3c2416_cpufreq_enter_dvs(s3c_freq, idx);
  203. } else if (s3c_freq->is_dvs) {
  204. pr_debug("cpufreq: leave dvs\n");
  205. ret = s3c2416_cpufreq_leave_dvs(s3c_freq, idx);
  206. } else {
  207. pr_debug("cpufreq: change armdiv to %dkHz\n", new_freq);
  208. ret = s3c2416_cpufreq_set_armdiv(s3c_freq, new_freq);
  209. }
  210. out:
  211. mutex_unlock(&cpufreq_lock);
  212. return ret;
  213. }
  214. #ifdef CONFIG_ARM_S3C2416_CPUFREQ_VCORESCALE
  215. static void s3c2416_cpufreq_cfg_regulator(struct s3c2416_data *s3c_freq)
  216. {
  217. int count, v, i, found;
  218. struct cpufreq_frequency_table *pos;
  219. struct s3c2416_dvfs *dvfs;
  220. count = regulator_count_voltages(s3c_freq->vddarm);
  221. if (count < 0) {
  222. pr_err("cpufreq: Unable to check supported voltages\n");
  223. return;
  224. }
  225. if (!count)
  226. goto out;
  227. cpufreq_for_each_valid_entry(pos, s3c_freq->freq_table) {
  228. dvfs = &s3c2416_dvfs_table[pos->driver_data];
  229. found = 0;
  230. /* Check only the min-voltage, more is always ok on S3C2416 */
  231. for (i = 0; i < count; i++) {
  232. v = regulator_list_voltage(s3c_freq->vddarm, i);
  233. if (v >= dvfs->vddarm_min)
  234. found = 1;
  235. }
  236. if (!found) {
  237. pr_debug("cpufreq: %dkHz unsupported by regulator\n",
  238. pos->frequency);
  239. pos->frequency = CPUFREQ_ENTRY_INVALID;
  240. }
  241. }
  242. out:
  243. /* Guessed */
  244. s3c_freq->regulator_latency = 1 * 1000 * 1000;
  245. }
  246. #endif
  247. static int s3c2416_cpufreq_reboot_notifier_evt(struct notifier_block *this,
  248. unsigned long event, void *ptr)
  249. {
  250. struct s3c2416_data *s3c_freq = &s3c2416_cpufreq;
  251. int ret;
  252. struct cpufreq_policy *policy;
  253. mutex_lock(&cpufreq_lock);
  254. /* disable further changes */
  255. s3c_freq->disable_dvs = 1;
  256. mutex_unlock(&cpufreq_lock);
  257. /* some boards don't reconfigure the regulator on reboot, which
  258. * could lead to undervolting the cpu when the clock is reset.
  259. * Therefore we always leave the DVS mode on reboot.
  260. */
  261. if (s3c_freq->is_dvs) {
  262. pr_debug("cpufreq: leave dvs on reboot\n");
  263. policy = cpufreq_cpu_get(0);
  264. if (!policy) {
  265. pr_debug("cpufreq: get no policy for cpu0\n");
  266. return NOTIFY_BAD;
  267. }
  268. ret = cpufreq_driver_target(policy, FREQ_SLEEP, 0);
  269. cpufreq_cpu_put(policy);
  270. if (ret < 0)
  271. return NOTIFY_BAD;
  272. }
  273. return NOTIFY_DONE;
  274. }
  275. static struct notifier_block s3c2416_cpufreq_reboot_notifier = {
  276. .notifier_call = s3c2416_cpufreq_reboot_notifier_evt,
  277. };
  278. static int s3c2416_cpufreq_driver_init(struct cpufreq_policy *policy)
  279. {
  280. struct s3c2416_data *s3c_freq = &s3c2416_cpufreq;
  281. struct cpufreq_frequency_table *pos;
  282. struct clk *msysclk;
  283. unsigned long rate;
  284. int ret;
  285. if (policy->cpu != 0)
  286. return -EINVAL;
  287. msysclk = clk_get(NULL, "msysclk");
  288. if (IS_ERR(msysclk)) {
  289. ret = PTR_ERR(msysclk);
  290. pr_err("cpufreq: Unable to obtain msysclk: %d\n", ret);
  291. return ret;
  292. }
  293. /*
  294. * S3C2416 and S3C2450 share the same processor-ID and also provide no
  295. * other means to distinguish them other than through the rate of
  296. * msysclk. On S3C2416 msysclk runs at 800MHz and on S3C2450 at 533MHz.
  297. */
  298. rate = clk_get_rate(msysclk);
  299. if (rate == 800 * 1000 * 1000) {
  300. pr_info("cpufreq: msysclk running at %lukHz, using S3C2416 frequency table\n",
  301. rate / 1000);
  302. s3c_freq->freq_table = s3c2416_freq_table;
  303. policy->cpuinfo.max_freq = 400000;
  304. } else if (rate / 1000 == 534000) {
  305. pr_info("cpufreq: msysclk running at %lukHz, using S3C2450 frequency table\n",
  306. rate / 1000);
  307. s3c_freq->freq_table = s3c2450_freq_table;
  308. policy->cpuinfo.max_freq = 534000;
  309. }
  310. /* not needed anymore */
  311. clk_put(msysclk);
  312. if (s3c_freq->freq_table == NULL) {
  313. pr_err("cpufreq: No frequency information for this CPU, msysclk at %lukHz\n",
  314. rate / 1000);
  315. return -ENODEV;
  316. }
  317. s3c_freq->is_dvs = 0;
  318. s3c_freq->armdiv = clk_get(NULL, "armdiv");
  319. if (IS_ERR(s3c_freq->armdiv)) {
  320. ret = PTR_ERR(s3c_freq->armdiv);
  321. pr_err("cpufreq: Unable to obtain ARMDIV: %d\n", ret);
  322. return ret;
  323. }
  324. s3c_freq->hclk = clk_get(NULL, "hclk");
  325. if (IS_ERR(s3c_freq->hclk)) {
  326. ret = PTR_ERR(s3c_freq->hclk);
  327. pr_err("cpufreq: Unable to obtain HCLK: %d\n", ret);
  328. goto err_hclk;
  329. }
  330. /* chech hclk rate, we only support the common 133MHz for now
  331. * hclk could also run at 66MHz, but this not often used
  332. */
  333. rate = clk_get_rate(s3c_freq->hclk);
  334. if (rate < 133 * 1000 * 1000) {
  335. pr_err("cpufreq: HCLK not at 133MHz\n");
  336. ret = -EINVAL;
  337. goto err_armclk;
  338. }
  339. s3c_freq->armclk = clk_get(NULL, "armclk");
  340. if (IS_ERR(s3c_freq->armclk)) {
  341. ret = PTR_ERR(s3c_freq->armclk);
  342. pr_err("cpufreq: Unable to obtain ARMCLK: %d\n", ret);
  343. goto err_armclk;
  344. }
  345. #ifdef CONFIG_ARM_S3C2416_CPUFREQ_VCORESCALE
  346. s3c_freq->vddarm = regulator_get(NULL, "vddarm");
  347. if (IS_ERR(s3c_freq->vddarm)) {
  348. ret = PTR_ERR(s3c_freq->vddarm);
  349. pr_err("cpufreq: Failed to obtain VDDARM: %d\n", ret);
  350. goto err_vddarm;
  351. }
  352. s3c2416_cpufreq_cfg_regulator(s3c_freq);
  353. #else
  354. s3c_freq->regulator_latency = 0;
  355. #endif
  356. cpufreq_for_each_entry(pos, s3c_freq->freq_table) {
  357. /* special handling for dvs mode */
  358. if (pos->driver_data == 0) {
  359. if (!s3c_freq->hclk) {
  360. pr_debug("cpufreq: %dkHz unsupported as it would need unavailable dvs mode\n",
  361. pos->frequency);
  362. pos->frequency = CPUFREQ_ENTRY_INVALID;
  363. } else {
  364. continue;
  365. }
  366. }
  367. /* Check for frequencies we can generate */
  368. rate = clk_round_rate(s3c_freq->armdiv,
  369. pos->frequency * 1000);
  370. rate /= 1000;
  371. if (rate != pos->frequency) {
  372. pr_debug("cpufreq: %dkHz unsupported by clock (clk_round_rate return %lu)\n",
  373. pos->frequency, rate);
  374. pos->frequency = CPUFREQ_ENTRY_INVALID;
  375. }
  376. }
  377. /* Datasheet says PLL stabalisation time must be at least 300us,
  378. * so but add some fudge. (reference in LOCKCON0 register description)
  379. */
  380. cpufreq_generic_init(policy, s3c_freq->freq_table,
  381. (500 * 1000) + s3c_freq->regulator_latency);
  382. register_reboot_notifier(&s3c2416_cpufreq_reboot_notifier);
  383. return 0;
  384. #ifdef CONFIG_ARM_S3C2416_CPUFREQ_VCORESCALE
  385. err_vddarm:
  386. clk_put(s3c_freq->armclk);
  387. #endif
  388. err_armclk:
  389. clk_put(s3c_freq->hclk);
  390. err_hclk:
  391. clk_put(s3c_freq->armdiv);
  392. return ret;
  393. }
  394. static struct cpufreq_driver s3c2416_cpufreq_driver = {
  395. .flags = CPUFREQ_NEED_INITIAL_FREQ_CHECK,
  396. .verify = cpufreq_generic_frequency_table_verify,
  397. .target_index = s3c2416_cpufreq_set_target,
  398. .get = s3c2416_cpufreq_get_speed,
  399. .init = s3c2416_cpufreq_driver_init,
  400. .name = "s3c2416",
  401. .attr = cpufreq_generic_attr,
  402. };
  403. static int __init s3c2416_cpufreq_init(void)
  404. {
  405. return cpufreq_register_driver(&s3c2416_cpufreq_driver);
  406. }
  407. module_init(s3c2416_cpufreq_init);