fsl_rcpm.c 8.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387
  1. /*
  2. * RCPM(Run Control/Power Management) support
  3. *
  4. * Copyright 2012-2015 Freescale Semiconductor Inc.
  5. *
  6. * Author: Chenhui Zhao <chenhui.zhao@freescale.com>
  7. *
  8. * This program is free software; you can redistribute it and/or modify it
  9. * under the terms of the GNU General Public License as published by the
  10. * Free Software Foundation; either version 2 of the License, or (at your
  11. * option) any later version.
  12. */
  13. #define pr_fmt(fmt) "%s: " fmt, __func__
  14. #include <linux/types.h>
  15. #include <linux/errno.h>
  16. #include <linux/of_address.h>
  17. #include <linux/export.h>
  18. #include <asm/io.h>
  19. #include <linux/fsl/guts.h>
  20. #include <asm/cputhreads.h>
  21. #include <asm/fsl_pm.h>
  22. #include <asm/smp.h>
  23. static struct ccsr_rcpm_v1 __iomem *rcpm_v1_regs;
  24. static struct ccsr_rcpm_v2 __iomem *rcpm_v2_regs;
  25. static unsigned int fsl_supported_pm_modes;
  26. static void rcpm_v1_irq_mask(int cpu)
  27. {
  28. int hw_cpu = get_hard_smp_processor_id(cpu);
  29. unsigned int mask = 1 << hw_cpu;
  30. setbits32(&rcpm_v1_regs->cpmimr, mask);
  31. setbits32(&rcpm_v1_regs->cpmcimr, mask);
  32. setbits32(&rcpm_v1_regs->cpmmcmr, mask);
  33. setbits32(&rcpm_v1_regs->cpmnmimr, mask);
  34. }
  35. static void rcpm_v2_irq_mask(int cpu)
  36. {
  37. int hw_cpu = get_hard_smp_processor_id(cpu);
  38. unsigned int mask = 1 << hw_cpu;
  39. setbits32(&rcpm_v2_regs->tpmimr0, mask);
  40. setbits32(&rcpm_v2_regs->tpmcimr0, mask);
  41. setbits32(&rcpm_v2_regs->tpmmcmr0, mask);
  42. setbits32(&rcpm_v2_regs->tpmnmimr0, mask);
  43. }
  44. static void rcpm_v1_irq_unmask(int cpu)
  45. {
  46. int hw_cpu = get_hard_smp_processor_id(cpu);
  47. unsigned int mask = 1 << hw_cpu;
  48. clrbits32(&rcpm_v1_regs->cpmimr, mask);
  49. clrbits32(&rcpm_v1_regs->cpmcimr, mask);
  50. clrbits32(&rcpm_v1_regs->cpmmcmr, mask);
  51. clrbits32(&rcpm_v1_regs->cpmnmimr, mask);
  52. }
  53. static void rcpm_v2_irq_unmask(int cpu)
  54. {
  55. int hw_cpu = get_hard_smp_processor_id(cpu);
  56. unsigned int mask = 1 << hw_cpu;
  57. clrbits32(&rcpm_v2_regs->tpmimr0, mask);
  58. clrbits32(&rcpm_v2_regs->tpmcimr0, mask);
  59. clrbits32(&rcpm_v2_regs->tpmmcmr0, mask);
  60. clrbits32(&rcpm_v2_regs->tpmnmimr0, mask);
  61. }
  62. static void rcpm_v1_set_ip_power(bool enable, u32 mask)
  63. {
  64. if (enable)
  65. setbits32(&rcpm_v1_regs->ippdexpcr, mask);
  66. else
  67. clrbits32(&rcpm_v1_regs->ippdexpcr, mask);
  68. }
  69. static void rcpm_v2_set_ip_power(bool enable, u32 mask)
  70. {
  71. if (enable)
  72. setbits32(&rcpm_v2_regs->ippdexpcr[0], mask);
  73. else
  74. clrbits32(&rcpm_v2_regs->ippdexpcr[0], mask);
  75. }
  76. static void rcpm_v1_cpu_enter_state(int cpu, int state)
  77. {
  78. int hw_cpu = get_hard_smp_processor_id(cpu);
  79. unsigned int mask = 1 << hw_cpu;
  80. switch (state) {
  81. case E500_PM_PH10:
  82. setbits32(&rcpm_v1_regs->cdozcr, mask);
  83. break;
  84. case E500_PM_PH15:
  85. setbits32(&rcpm_v1_regs->cnapcr, mask);
  86. break;
  87. default:
  88. pr_warn("Unknown cpu PM state (%d)\n", state);
  89. break;
  90. }
  91. }
  92. static void rcpm_v2_cpu_enter_state(int cpu, int state)
  93. {
  94. int hw_cpu = get_hard_smp_processor_id(cpu);
  95. u32 mask = 1 << cpu_core_index_of_thread(cpu);
  96. switch (state) {
  97. case E500_PM_PH10:
  98. /* one bit corresponds to one thread for PH10 of 6500 */
  99. setbits32(&rcpm_v2_regs->tph10setr0, 1 << hw_cpu);
  100. break;
  101. case E500_PM_PH15:
  102. setbits32(&rcpm_v2_regs->pcph15setr, mask);
  103. break;
  104. case E500_PM_PH20:
  105. setbits32(&rcpm_v2_regs->pcph20setr, mask);
  106. break;
  107. case E500_PM_PH30:
  108. setbits32(&rcpm_v2_regs->pcph30setr, mask);
  109. break;
  110. default:
  111. pr_warn("Unknown cpu PM state (%d)\n", state);
  112. }
  113. }
  114. static void rcpm_v1_cpu_die(int cpu)
  115. {
  116. rcpm_v1_cpu_enter_state(cpu, E500_PM_PH15);
  117. }
  118. #ifdef CONFIG_PPC64
  119. static void qoriq_disable_thread(int cpu)
  120. {
  121. int thread = cpu_thread_in_core(cpu);
  122. book3e_stop_thread(thread);
  123. }
  124. #endif
  125. static void rcpm_v2_cpu_die(int cpu)
  126. {
  127. #ifdef CONFIG_PPC64
  128. int primary;
  129. if (threads_per_core == 2) {
  130. primary = cpu_first_thread_sibling(cpu);
  131. if (cpu_is_offline(primary) && cpu_is_offline(primary + 1)) {
  132. /* if both threads are offline, put the cpu in PH20 */
  133. rcpm_v2_cpu_enter_state(cpu, E500_PM_PH20);
  134. } else {
  135. /* if only one thread is offline, disable the thread */
  136. qoriq_disable_thread(cpu);
  137. }
  138. }
  139. #endif
  140. if (threads_per_core == 1)
  141. rcpm_v2_cpu_enter_state(cpu, E500_PM_PH20);
  142. }
  143. static void rcpm_v1_cpu_exit_state(int cpu, int state)
  144. {
  145. int hw_cpu = get_hard_smp_processor_id(cpu);
  146. unsigned int mask = 1 << hw_cpu;
  147. switch (state) {
  148. case E500_PM_PH10:
  149. clrbits32(&rcpm_v1_regs->cdozcr, mask);
  150. break;
  151. case E500_PM_PH15:
  152. clrbits32(&rcpm_v1_regs->cnapcr, mask);
  153. break;
  154. default:
  155. pr_warn("Unknown cpu PM state (%d)\n", state);
  156. break;
  157. }
  158. }
  159. static void rcpm_v1_cpu_up_prepare(int cpu)
  160. {
  161. rcpm_v1_cpu_exit_state(cpu, E500_PM_PH15);
  162. rcpm_v1_irq_unmask(cpu);
  163. }
  164. static void rcpm_v2_cpu_exit_state(int cpu, int state)
  165. {
  166. int hw_cpu = get_hard_smp_processor_id(cpu);
  167. u32 mask = 1 << cpu_core_index_of_thread(cpu);
  168. switch (state) {
  169. case E500_PM_PH10:
  170. setbits32(&rcpm_v2_regs->tph10clrr0, 1 << hw_cpu);
  171. break;
  172. case E500_PM_PH15:
  173. setbits32(&rcpm_v2_regs->pcph15clrr, mask);
  174. break;
  175. case E500_PM_PH20:
  176. setbits32(&rcpm_v2_regs->pcph20clrr, mask);
  177. break;
  178. case E500_PM_PH30:
  179. setbits32(&rcpm_v2_regs->pcph30clrr, mask);
  180. break;
  181. default:
  182. pr_warn("Unknown cpu PM state (%d)\n", state);
  183. }
  184. }
  185. static void rcpm_v2_cpu_up_prepare(int cpu)
  186. {
  187. rcpm_v2_cpu_exit_state(cpu, E500_PM_PH20);
  188. rcpm_v2_irq_unmask(cpu);
  189. }
  190. static int rcpm_v1_plat_enter_state(int state)
  191. {
  192. u32 *pmcsr_reg = &rcpm_v1_regs->powmgtcsr;
  193. int ret = 0;
  194. int result;
  195. switch (state) {
  196. case PLAT_PM_SLEEP:
  197. setbits32(pmcsr_reg, RCPM_POWMGTCSR_SLP);
  198. /* Upon resume, wait for RCPM_POWMGTCSR_SLP bit to be clear. */
  199. result = spin_event_timeout(
  200. !(in_be32(pmcsr_reg) & RCPM_POWMGTCSR_SLP), 10000, 10);
  201. if (!result) {
  202. pr_err("timeout waiting for SLP bit to be cleared\n");
  203. ret = -ETIMEDOUT;
  204. }
  205. break;
  206. default:
  207. pr_warn("Unknown platform PM state (%d)", state);
  208. ret = -EINVAL;
  209. }
  210. return ret;
  211. }
  212. static int rcpm_v2_plat_enter_state(int state)
  213. {
  214. u32 *pmcsr_reg = &rcpm_v2_regs->powmgtcsr;
  215. int ret = 0;
  216. int result;
  217. switch (state) {
  218. case PLAT_PM_LPM20:
  219. /* clear previous LPM20 status */
  220. setbits32(pmcsr_reg, RCPM_POWMGTCSR_P_LPM20_ST);
  221. /* enter LPM20 status */
  222. setbits32(pmcsr_reg, RCPM_POWMGTCSR_LPM20_RQ);
  223. /* At this point, the device is in LPM20 status. */
  224. /* resume ... */
  225. result = spin_event_timeout(
  226. !(in_be32(pmcsr_reg) & RCPM_POWMGTCSR_LPM20_ST), 10000, 10);
  227. if (!result) {
  228. pr_err("timeout waiting for LPM20 bit to be cleared\n");
  229. ret = -ETIMEDOUT;
  230. }
  231. break;
  232. default:
  233. pr_warn("Unknown platform PM state (%d)\n", state);
  234. ret = -EINVAL;
  235. }
  236. return ret;
  237. }
  238. static int rcpm_v1_plat_enter_sleep(void)
  239. {
  240. return rcpm_v1_plat_enter_state(PLAT_PM_SLEEP);
  241. }
  242. static int rcpm_v2_plat_enter_sleep(void)
  243. {
  244. return rcpm_v2_plat_enter_state(PLAT_PM_LPM20);
  245. }
  246. static void rcpm_common_freeze_time_base(u32 *tben_reg, int freeze)
  247. {
  248. static u32 mask;
  249. if (freeze) {
  250. mask = in_be32(tben_reg);
  251. clrbits32(tben_reg, mask);
  252. } else {
  253. setbits32(tben_reg, mask);
  254. }
  255. /* read back to push the previous write */
  256. in_be32(tben_reg);
  257. }
  258. static void rcpm_v1_freeze_time_base(bool freeze)
  259. {
  260. rcpm_common_freeze_time_base(&rcpm_v1_regs->ctbenr, freeze);
  261. }
  262. static void rcpm_v2_freeze_time_base(bool freeze)
  263. {
  264. rcpm_common_freeze_time_base(&rcpm_v2_regs->pctbenr, freeze);
  265. }
  266. static unsigned int rcpm_get_pm_modes(void)
  267. {
  268. return fsl_supported_pm_modes;
  269. }
  270. static const struct fsl_pm_ops qoriq_rcpm_v1_ops = {
  271. .irq_mask = rcpm_v1_irq_mask,
  272. .irq_unmask = rcpm_v1_irq_unmask,
  273. .cpu_enter_state = rcpm_v1_cpu_enter_state,
  274. .cpu_exit_state = rcpm_v1_cpu_exit_state,
  275. .cpu_up_prepare = rcpm_v1_cpu_up_prepare,
  276. .cpu_die = rcpm_v1_cpu_die,
  277. .plat_enter_sleep = rcpm_v1_plat_enter_sleep,
  278. .set_ip_power = rcpm_v1_set_ip_power,
  279. .freeze_time_base = rcpm_v1_freeze_time_base,
  280. .get_pm_modes = rcpm_get_pm_modes,
  281. };
  282. static const struct fsl_pm_ops qoriq_rcpm_v2_ops = {
  283. .irq_mask = rcpm_v2_irq_mask,
  284. .irq_unmask = rcpm_v2_irq_unmask,
  285. .cpu_enter_state = rcpm_v2_cpu_enter_state,
  286. .cpu_exit_state = rcpm_v2_cpu_exit_state,
  287. .cpu_up_prepare = rcpm_v2_cpu_up_prepare,
  288. .cpu_die = rcpm_v2_cpu_die,
  289. .plat_enter_sleep = rcpm_v2_plat_enter_sleep,
  290. .set_ip_power = rcpm_v2_set_ip_power,
  291. .freeze_time_base = rcpm_v2_freeze_time_base,
  292. .get_pm_modes = rcpm_get_pm_modes,
  293. };
  294. static const struct of_device_id rcpm_matches[] = {
  295. {
  296. .compatible = "fsl,qoriq-rcpm-1.0",
  297. .data = &qoriq_rcpm_v1_ops,
  298. },
  299. {
  300. .compatible = "fsl,qoriq-rcpm-2.0",
  301. .data = &qoriq_rcpm_v2_ops,
  302. },
  303. {
  304. .compatible = "fsl,qoriq-rcpm-2.1",
  305. .data = &qoriq_rcpm_v2_ops,
  306. },
  307. {},
  308. };
  309. int __init fsl_rcpm_init(void)
  310. {
  311. struct device_node *np;
  312. const struct of_device_id *match;
  313. void __iomem *base;
  314. np = of_find_matching_node_and_match(NULL, rcpm_matches, &match);
  315. if (!np)
  316. return 0;
  317. base = of_iomap(np, 0);
  318. of_node_put(np);
  319. if (!base) {
  320. pr_err("of_iomap() error.\n");
  321. return -ENOMEM;
  322. }
  323. rcpm_v1_regs = base;
  324. rcpm_v2_regs = base;
  325. /* support sleep by default */
  326. fsl_supported_pm_modes = FSL_PM_SLEEP;
  327. qoriq_pm_ops = match->data;
  328. return 0;
  329. }