platsmp.c 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440
  1. /*
  2. * Copyright (C) 2015 Carlo Caione <carlo@endlessm.com>
  3. * Copyright (C) 2017 Martin Blumenstingl <martin.blumenstingl@googlemail.com>
  4. *
  5. * This program is free software; you can redistribute it and/or modify
  6. * it under the terms of the GNU General Public License as published by
  7. * the Free Software Foundation; either version 2 of the License, or
  8. * (at your option) any later version.
  9. *
  10. * This program is distributed in the hope that it will be useful, but WITHOUT
  11. * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  12. * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
  13. * more details.
  14. *
  15. */
  16. #include <linux/delay.h>
  17. #include <linux/init.h>
  18. #include <linux/io.h>
  19. #include <linux/of.h>
  20. #include <linux/of_address.h>
  21. #include <linux/regmap.h>
  22. #include <linux/reset.h>
  23. #include <linux/smp.h>
  24. #include <linux/mfd/syscon.h>
  25. #include <asm/cacheflush.h>
  26. #include <asm/cp15.h>
  27. #include <asm/smp_scu.h>
  28. #include <asm/smp_plat.h>
  29. #define MESON_SMP_SRAM_CPU_CTRL_REG (0x00)
  30. #define MESON_SMP_SRAM_CPU_CTRL_ADDR_REG(c) (0x04 + ((c - 1) << 2))
  31. #define MESON_CPU_AO_RTI_PWR_A9_CNTL0 (0x00)
  32. #define MESON_CPU_AO_RTI_PWR_A9_CNTL1 (0x04)
  33. #define MESON_CPU_AO_RTI_PWR_A9_MEM_PD0 (0x14)
  34. #define MESON_CPU_PWR_A9_CNTL0_M(c) (0x03 << ((c * 2) + 16))
  35. #define MESON_CPU_PWR_A9_CNTL1_M(c) (0x03 << ((c + 1) << 1))
  36. #define MESON_CPU_PWR_A9_MEM_PD0_M(c) (0x0f << (32 - (c * 4)))
  37. #define MESON_CPU_PWR_A9_CNTL1_ST(c) (0x01 << (c + 16))
  38. static void __iomem *sram_base;
  39. static void __iomem *scu_base;
  40. static struct regmap *pmu;
  41. static struct reset_control *meson_smp_get_core_reset(int cpu)
  42. {
  43. struct device_node *np = of_get_cpu_node(cpu, 0);
  44. return of_reset_control_get_exclusive(np, NULL);
  45. }
  46. static void meson_smp_set_cpu_ctrl(int cpu, bool on_off)
  47. {
  48. u32 val = readl(sram_base + MESON_SMP_SRAM_CPU_CTRL_REG);
  49. if (on_off)
  50. val |= BIT(cpu);
  51. else
  52. val &= ~BIT(cpu);
  53. /* keep bit 0 always enabled */
  54. val |= BIT(0);
  55. writel(val, sram_base + MESON_SMP_SRAM_CPU_CTRL_REG);
  56. }
  57. static void __init meson_smp_prepare_cpus(const char *scu_compatible,
  58. const char *pmu_compatible,
  59. const char *sram_compatible)
  60. {
  61. static struct device_node *node;
  62. /* SMP SRAM */
  63. node = of_find_compatible_node(NULL, NULL, sram_compatible);
  64. if (!node) {
  65. pr_err("Missing SRAM node\n");
  66. return;
  67. }
  68. sram_base = of_iomap(node, 0);
  69. if (!sram_base) {
  70. pr_err("Couldn't map SRAM registers\n");
  71. return;
  72. }
  73. /* PMU */
  74. pmu = syscon_regmap_lookup_by_compatible(pmu_compatible);
  75. if (IS_ERR(pmu)) {
  76. pr_err("Couldn't map PMU registers\n");
  77. return;
  78. }
  79. /* SCU */
  80. node = of_find_compatible_node(NULL, NULL, scu_compatible);
  81. if (!node) {
  82. pr_err("Missing SCU node\n");
  83. return;
  84. }
  85. scu_base = of_iomap(node, 0);
  86. if (!scu_base) {
  87. pr_err("Couldn't map SCU registers\n");
  88. return;
  89. }
  90. scu_enable(scu_base);
  91. }
  92. static void __init meson8b_smp_prepare_cpus(unsigned int max_cpus)
  93. {
  94. meson_smp_prepare_cpus("arm,cortex-a5-scu", "amlogic,meson8b-pmu",
  95. "amlogic,meson8b-smp-sram");
  96. }
  97. static void __init meson8_smp_prepare_cpus(unsigned int max_cpus)
  98. {
  99. meson_smp_prepare_cpus("arm,cortex-a9-scu", "amlogic,meson8-pmu",
  100. "amlogic,meson8-smp-sram");
  101. }
  102. static void meson_smp_begin_secondary_boot(unsigned int cpu)
  103. {
  104. /*
  105. * Set the entry point before powering on the CPU through the SCU. This
  106. * is needed if the CPU is in "warm" state (= after rebooting the
  107. * system without power-cycling, or when taking the CPU offline and
  108. * then taking it online again.
  109. */
  110. writel(__pa_symbol(secondary_startup),
  111. sram_base + MESON_SMP_SRAM_CPU_CTRL_ADDR_REG(cpu));
  112. /*
  113. * SCU Power on CPU (needs to be done before starting the CPU,
  114. * otherwise the secondary CPU will not start).
  115. */
  116. scu_cpu_power_enable(scu_base, cpu);
  117. }
  118. static int meson_smp_finalize_secondary_boot(unsigned int cpu)
  119. {
  120. unsigned long timeout;
  121. timeout = jiffies + (10 * HZ);
  122. while (readl(sram_base + MESON_SMP_SRAM_CPU_CTRL_ADDR_REG(cpu))) {
  123. if (!time_before(jiffies, timeout)) {
  124. pr_err("Timeout while waiting for CPU%d status\n",
  125. cpu);
  126. return -ETIMEDOUT;
  127. }
  128. }
  129. writel(__pa_symbol(secondary_startup),
  130. sram_base + MESON_SMP_SRAM_CPU_CTRL_ADDR_REG(cpu));
  131. meson_smp_set_cpu_ctrl(cpu, true);
  132. return 0;
  133. }
  134. static int meson8_smp_boot_secondary(unsigned int cpu,
  135. struct task_struct *idle)
  136. {
  137. struct reset_control *rstc;
  138. int ret;
  139. rstc = meson_smp_get_core_reset(cpu);
  140. if (IS_ERR(rstc)) {
  141. pr_err("Couldn't get the reset controller for CPU%d\n", cpu);
  142. return PTR_ERR(rstc);
  143. }
  144. meson_smp_begin_secondary_boot(cpu);
  145. /* Reset enable */
  146. ret = reset_control_assert(rstc);
  147. if (ret) {
  148. pr_err("Failed to assert CPU%d reset\n", cpu);
  149. goto out;
  150. }
  151. /* CPU power ON */
  152. ret = regmap_update_bits(pmu, MESON_CPU_AO_RTI_PWR_A9_CNTL1,
  153. MESON_CPU_PWR_A9_CNTL1_M(cpu), 0);
  154. if (ret < 0) {
  155. pr_err("Couldn't wake up CPU%d\n", cpu);
  156. goto out;
  157. }
  158. udelay(10);
  159. /* Isolation disable */
  160. ret = regmap_update_bits(pmu, MESON_CPU_AO_RTI_PWR_A9_CNTL0, BIT(cpu),
  161. 0);
  162. if (ret < 0) {
  163. pr_err("Error when disabling isolation of CPU%d\n", cpu);
  164. goto out;
  165. }
  166. /* Reset disable */
  167. ret = reset_control_deassert(rstc);
  168. if (ret) {
  169. pr_err("Failed to de-assert CPU%d reset\n", cpu);
  170. goto out;
  171. }
  172. ret = meson_smp_finalize_secondary_boot(cpu);
  173. if (ret)
  174. goto out;
  175. out:
  176. reset_control_put(rstc);
  177. return 0;
  178. }
  179. static int meson8b_smp_boot_secondary(unsigned int cpu,
  180. struct task_struct *idle)
  181. {
  182. struct reset_control *rstc;
  183. int ret;
  184. u32 val;
  185. rstc = meson_smp_get_core_reset(cpu);
  186. if (IS_ERR(rstc)) {
  187. pr_err("Couldn't get the reset controller for CPU%d\n", cpu);
  188. return PTR_ERR(rstc);
  189. }
  190. meson_smp_begin_secondary_boot(cpu);
  191. /* CPU power UP */
  192. ret = regmap_update_bits(pmu, MESON_CPU_AO_RTI_PWR_A9_CNTL0,
  193. MESON_CPU_PWR_A9_CNTL0_M(cpu), 0);
  194. if (ret < 0) {
  195. pr_err("Couldn't power up CPU%d\n", cpu);
  196. goto out;
  197. }
  198. udelay(5);
  199. /* Reset enable */
  200. ret = reset_control_assert(rstc);
  201. if (ret) {
  202. pr_err("Failed to assert CPU%d reset\n", cpu);
  203. goto out;
  204. }
  205. /* Memory power UP */
  206. ret = regmap_update_bits(pmu, MESON_CPU_AO_RTI_PWR_A9_MEM_PD0,
  207. MESON_CPU_PWR_A9_MEM_PD0_M(cpu), 0);
  208. if (ret < 0) {
  209. pr_err("Couldn't power up the memory for CPU%d\n", cpu);
  210. goto out;
  211. }
  212. /* Wake up CPU */
  213. ret = regmap_update_bits(pmu, MESON_CPU_AO_RTI_PWR_A9_CNTL1,
  214. MESON_CPU_PWR_A9_CNTL1_M(cpu), 0);
  215. if (ret < 0) {
  216. pr_err("Couldn't wake up CPU%d\n", cpu);
  217. goto out;
  218. }
  219. udelay(10);
  220. ret = regmap_read_poll_timeout(pmu, MESON_CPU_AO_RTI_PWR_A9_CNTL1, val,
  221. val & MESON_CPU_PWR_A9_CNTL1_ST(cpu),
  222. 10, 10000);
  223. if (ret) {
  224. pr_err("Timeout while polling PMU for CPU%d status\n", cpu);
  225. goto out;
  226. }
  227. /* Isolation disable */
  228. ret = regmap_update_bits(pmu, MESON_CPU_AO_RTI_PWR_A9_CNTL0, BIT(cpu),
  229. 0);
  230. if (ret < 0) {
  231. pr_err("Error when disabling isolation of CPU%d\n", cpu);
  232. goto out;
  233. }
  234. /* Reset disable */
  235. ret = reset_control_deassert(rstc);
  236. if (ret) {
  237. pr_err("Failed to de-assert CPU%d reset\n", cpu);
  238. goto out;
  239. }
  240. ret = meson_smp_finalize_secondary_boot(cpu);
  241. if (ret)
  242. goto out;
  243. out:
  244. reset_control_put(rstc);
  245. return 0;
  246. }
  247. #ifdef CONFIG_HOTPLUG_CPU
  248. static void meson8_smp_cpu_die(unsigned int cpu)
  249. {
  250. meson_smp_set_cpu_ctrl(cpu, false);
  251. v7_exit_coherency_flush(louis);
  252. scu_power_mode(scu_base, SCU_PM_POWEROFF);
  253. dsb();
  254. wfi();
  255. /* we should never get here */
  256. WARN_ON(1);
  257. }
  258. static int meson8_smp_cpu_kill(unsigned int cpu)
  259. {
  260. int ret, power_mode;
  261. unsigned long timeout;
  262. timeout = jiffies + (50 * HZ);
  263. do {
  264. power_mode = scu_get_cpu_power_mode(scu_base, cpu);
  265. if (power_mode == SCU_PM_POWEROFF)
  266. break;
  267. usleep_range(10000, 15000);
  268. } while (time_before(jiffies, timeout));
  269. if (power_mode != SCU_PM_POWEROFF) {
  270. pr_err("Error while waiting for SCU power-off on CPU%d\n",
  271. cpu);
  272. return -ETIMEDOUT;
  273. }
  274. msleep(30);
  275. /* Isolation enable */
  276. ret = regmap_update_bits(pmu, MESON_CPU_AO_RTI_PWR_A9_CNTL0, BIT(cpu),
  277. 0x3);
  278. if (ret < 0) {
  279. pr_err("Error when enabling isolation for CPU%d\n", cpu);
  280. return ret;
  281. }
  282. udelay(10);
  283. /* CPU power OFF */
  284. ret = regmap_update_bits(pmu, MESON_CPU_AO_RTI_PWR_A9_CNTL1,
  285. MESON_CPU_PWR_A9_CNTL1_M(cpu), 0x3);
  286. if (ret < 0) {
  287. pr_err("Couldn't change sleep status of CPU%d\n", cpu);
  288. return ret;
  289. }
  290. return 1;
  291. }
  292. static int meson8b_smp_cpu_kill(unsigned int cpu)
  293. {
  294. int ret, power_mode, count = 5000;
  295. do {
  296. power_mode = scu_get_cpu_power_mode(scu_base, cpu);
  297. if (power_mode == SCU_PM_POWEROFF)
  298. break;
  299. udelay(10);
  300. } while (++count);
  301. if (power_mode != SCU_PM_POWEROFF) {
  302. pr_err("Error while waiting for SCU power-off on CPU%d\n",
  303. cpu);
  304. return -ETIMEDOUT;
  305. }
  306. udelay(10);
  307. /* CPU power DOWN */
  308. ret = regmap_update_bits(pmu, MESON_CPU_AO_RTI_PWR_A9_CNTL0,
  309. MESON_CPU_PWR_A9_CNTL0_M(cpu), 0x3);
  310. if (ret < 0) {
  311. pr_err("Couldn't power down CPU%d\n", cpu);
  312. return ret;
  313. }
  314. /* Isolation enable */
  315. ret = regmap_update_bits(pmu, MESON_CPU_AO_RTI_PWR_A9_CNTL0, BIT(cpu),
  316. 0x3);
  317. if (ret < 0) {
  318. pr_err("Error when enabling isolation for CPU%d\n", cpu);
  319. return ret;
  320. }
  321. udelay(10);
  322. /* Sleep status */
  323. ret = regmap_update_bits(pmu, MESON_CPU_AO_RTI_PWR_A9_CNTL1,
  324. MESON_CPU_PWR_A9_CNTL1_M(cpu), 0x3);
  325. if (ret < 0) {
  326. pr_err("Couldn't change sleep status of CPU%d\n", cpu);
  327. return ret;
  328. }
  329. /* Memory power DOWN */
  330. ret = regmap_update_bits(pmu, MESON_CPU_AO_RTI_PWR_A9_MEM_PD0,
  331. MESON_CPU_PWR_A9_MEM_PD0_M(cpu), 0xf);
  332. if (ret < 0) {
  333. pr_err("Couldn't power down the memory of CPU%d\n", cpu);
  334. return ret;
  335. }
  336. return 1;
  337. }
  338. #endif
  339. static struct smp_operations meson8_smp_ops __initdata = {
  340. .smp_prepare_cpus = meson8_smp_prepare_cpus,
  341. .smp_boot_secondary = meson8_smp_boot_secondary,
  342. #ifdef CONFIG_HOTPLUG_CPU
  343. .cpu_die = meson8_smp_cpu_die,
  344. .cpu_kill = meson8_smp_cpu_kill,
  345. #endif
  346. };
  347. static struct smp_operations meson8b_smp_ops __initdata = {
  348. .smp_prepare_cpus = meson8b_smp_prepare_cpus,
  349. .smp_boot_secondary = meson8b_smp_boot_secondary,
  350. #ifdef CONFIG_HOTPLUG_CPU
  351. .cpu_die = meson8_smp_cpu_die,
  352. .cpu_kill = meson8b_smp_cpu_kill,
  353. #endif
  354. };
  355. CPU_METHOD_OF_DECLARE(meson8_smp, "amlogic,meson8-smp", &meson8_smp_ops);
  356. CPU_METHOD_OF_DECLARE(meson8b_smp, "amlogic,meson8b-smp", &meson8b_smp_ops);