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