1 // SPDX-License-Identifier: GPL-2.0-or-later 1 2 /* 3 * Copyright (C) 2015 Carlo Caione <carlo@endl 4 * Copyright (C) 2017 Martin Blumenstingl <mar 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 23 #define MESON_SMP_SRAM_CPU_CTRL_ADDR_REG(c) 24 25 #define MESON_CPU_AO_RTI_PWR_A9_CNTL0 26 #define MESON_CPU_AO_RTI_PWR_A9_CNTL1 27 #define MESON_CPU_AO_RTI_PWR_A9_MEM_PD0 28 29 #define MESON_CPU_PWR_A9_CNTL0_M(c) 30 #define MESON_CPU_PWR_A9_CNTL1_M(c) 31 #define MESON_CPU_PWR_A9_MEM_PD0_M(c) 32 #define MESON_CPU_PWR_A9_CNTL1_ST(c) 33 34 static void __iomem *sram_base; 35 static void __iomem *scu_base; 36 static struct regmap *pmu; 37 38 static struct reset_control *meson_smp_get_cor 39 { 40 struct device_node *np = of_get_cpu_no 41 42 return of_reset_control_get_exclusive( 43 } 44 45 static void meson_smp_set_cpu_ctrl(int cpu, bo 46 { 47 u32 val = readl(sram_base + MESON_SMP_ 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 58 } 59 60 static void __init meson_smp_prepare_cpus(cons 61 cons 62 cons 63 { 64 static struct device_node *node; 65 66 /* SMP SRAM */ 67 node = of_find_compatible_node(NULL, N 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 regi 77 return; 78 } 79 80 /* PMU */ 81 pmu = syscon_regmap_lookup_by_compatib 82 if (IS_ERR(pmu)) { 83 pr_err("Couldn't map PMU regis 84 return; 85 } 86 87 /* SCU */ 88 node = of_find_compatible_node(NULL, N 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 regis 98 return; 99 } 100 101 scu_enable(scu_base); 102 } 103 104 static void __init meson8b_smp_prepare_cpus(un 105 { 106 meson_smp_prepare_cpus("arm,cortex-a5- 107 "amlogic,meson8 108 } 109 110 static void __init meson8_smp_prepare_cpus(uns 111 { 112 meson_smp_prepare_cpus("arm,cortex-a9- 113 "amlogic,meson8 114 } 115 116 static void meson_smp_begin_secondary_boot(uns 117 { 118 /* 119 * Set the entry point before powering 120 * is needed if the CPU is in "warm" s 121 * system without power-cycling, or wh 122 * then taking it online again. 123 */ 124 writel(__pa_symbol(secondary_startup), 125 sram_base + MESON_SMP_SRAM_CPU_ 126 127 /* 128 * SCU Power on CPU (needs to be done 129 * otherwise the secondary CPU will no 130 */ 131 scu_cpu_power_enable(scu_base, cpu); 132 } 133 134 static int meson_smp_finalize_secondary_boot(u 135 { 136 unsigned long timeout; 137 138 timeout = jiffies + (10 * HZ); 139 while (readl(sram_base + MESON_SMP_SRA 140 if (!time_before(jiffies, time 141 pr_err("Timeout while 142 cpu); 143 return -ETIMEDOUT; 144 } 145 } 146 147 writel(__pa_symbol(secondary_startup), 148 sram_base + MESON_SMP_SRAM_CPU_ 149 150 meson_smp_set_cpu_ctrl(cpu, true); 151 152 return 0; 153 } 154 155 static int meson8_smp_boot_secondary(unsigned 156 struct ta 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 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 173 goto out; 174 } 175 176 /* CPU power ON */ 177 ret = regmap_update_bits(pmu, MESON_CP 178 MESON_CPU_PWR 179 if (ret < 0) { 180 pr_err("Couldn't wake up CPU%d 181 goto out; 182 } 183 184 udelay(10); 185 186 /* Isolation disable */ 187 ret = regmap_update_bits(pmu, MESON_CP 188 0); 189 if (ret < 0) { 190 pr_err("Error when disabling i 191 goto out; 192 } 193 194 /* Reset disable */ 195 ret = reset_control_deassert(rstc); 196 if (ret) { 197 pr_err("Failed to de-assert CP 198 goto out; 199 } 200 201 ret = meson_smp_finalize_secondary_boo 202 if (ret) 203 goto out; 204 205 out: 206 reset_control_put(rstc); 207 208 return 0; 209 } 210 211 static int meson8b_smp_boot_secondary(unsigned 212 struct ta 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 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_CP 228 MESON_CPU_PWR 229 if (ret < 0) { 230 pr_err("Couldn't power up 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 240 goto out; 241 } 242 243 /* Memory power UP */ 244 ret = regmap_update_bits(pmu, MESON_CP 245 MESON_CPU_PWR 246 if (ret < 0) { 247 pr_err("Couldn't power up the 248 goto out; 249 } 250 251 /* Wake up CPU */ 252 ret = regmap_update_bits(pmu, MESON_CP 253 MESON_CPU_PWR 254 if (ret < 0) { 255 pr_err("Couldn't wake up CPU%d 256 goto out; 257 } 258 259 udelay(10); 260 261 ret = regmap_read_poll_timeout(pmu, ME 262 val & M 263 10, 100 264 if (ret) { 265 pr_err("Timeout while polling 266 goto out; 267 } 268 269 /* Isolation disable */ 270 ret = regmap_update_bits(pmu, MESON_CP 271 0); 272 if (ret < 0) { 273 pr_err("Error when disabling i 274 goto out; 275 } 276 277 /* Reset disable */ 278 ret = reset_control_deassert(rstc); 279 if (ret) { 280 pr_err("Failed to de-assert CP 281 goto out; 282 } 283 284 ret = meson_smp_finalize_secondary_boo 285 if (ret) 286 goto out; 287 288 out: 289 reset_control_put(rstc); 290 291 return 0; 292 } 293 294 #ifdef CONFIG_HOTPLUG_CPU 295 static void meson8_smp_cpu_die(unsigned int cp 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_POWERO 302 303 dsb(); 304 wfi(); 305 306 /* we should never get here */ 307 WARN_ON(1); 308 } 309 310 static int meson8_smp_cpu_kill(unsigned int cp 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 318 319 if (power_mode == SCU_PM_POWER 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 fo 327 cpu); 328 return -ETIMEDOUT; 329 } 330 331 msleep(30); 332 333 /* Isolation enable */ 334 ret = regmap_update_bits(pmu, MESON_CP 335 0x3); 336 if (ret < 0) { 337 pr_err("Error when enabling is 338 return ret; 339 } 340 341 udelay(10); 342 343 /* CPU power OFF */ 344 ret = regmap_update_bits(pmu, MESON_CP 345 MESON_CPU_PWR 346 if (ret < 0) { 347 pr_err("Couldn't change sleep 348 return ret; 349 } 350 351 return 1; 352 } 353 354 static int meson8b_smp_cpu_kill(unsigned int c 355 { 356 int ret, power_mode, count = 5000; 357 358 do { 359 power_mode = scu_get_cpu_power 360 361 if (power_mode == SCU_PM_POWER 362 break; 363 364 udelay(10); 365 } while (++count); 366 367 if (power_mode != SCU_PM_POWEROFF) { 368 pr_err("Error while waiting fo 369 cpu); 370 return -ETIMEDOUT; 371 } 372 373 udelay(10); 374 375 /* CPU power DOWN */ 376 ret = regmap_update_bits(pmu, MESON_CP 377 MESON_CPU_PWR 378 if (ret < 0) { 379 pr_err("Couldn't power down CP 380 return ret; 381 } 382 383 /* Isolation enable */ 384 ret = regmap_update_bits(pmu, MESON_CP 385 0x3); 386 if (ret < 0) { 387 pr_err("Error when enabling is 388 return ret; 389 } 390 391 udelay(10); 392 393 /* Sleep status */ 394 ret = regmap_update_bits(pmu, MESON_CP 395 MESON_CPU_PWR 396 if (ret < 0) { 397 pr_err("Couldn't change sleep 398 return ret; 399 } 400 401 /* Memory power DOWN */ 402 ret = regmap_update_bits(pmu, MESON_CP 403 MESON_CPU_PWR 404 if (ret < 0) { 405 pr_err("Couldn't power down th 406 return ret; 407 } 408 409 return 1; 410 } 411 #endif 412 413 static struct smp_operations meson8_smp_ops __ 414 .smp_prepare_cpus = meson8_smp_p 415 .smp_boot_secondary = meson8_smp_b 416 #ifdef CONFIG_HOTPLUG_CPU 417 .cpu_die = meson8_smp_c 418 .cpu_kill = meson8_smp_c 419 #endif 420 }; 421 422 static struct smp_operations meson8b_smp_ops _ 423 .smp_prepare_cpus = meson8b_smp_ 424 .smp_boot_secondary = meson8b_smp_ 425 #ifdef CONFIG_HOTPLUG_CPU 426 .cpu_die = meson8_smp_c 427 .cpu_kill = meson8b_smp_ 428 #endif 429 }; 430 431 CPU_METHOD_OF_DECLARE(meson8_smp, "amlogic,mes 432 CPU_METHOD_OF_DECLARE(meson8b_smp, "amlogic,me 433
Linux® is a registered trademark of Linus Torvalds in the United States and other countries.
TOMOYO® is a registered trademark of NTT DATA CORPORATION.