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