1 // SPDX-License-Identifier: GPL-2.0 2 // Copyright (c) 2010-2011 Samsung Electronics Co., Ltd. 3 // http://www.samsung.com 4 // 5 // Cloned from linux/arch/arm/mach-vexpress/platsmp.c 6 // 7 // Copyright (C) 2002 ARM Ltd. 8 // All Rights Reserved 9 10 #include <linux/init.h> 11 #include <linux/errno.h> 12 #include <linux/delay.h> 13 #include <linux/jiffies.h> 14 #include <linux/smp.h> 15 #include <linux/io.h> 16 #include <linux/of_address.h> 17 #include <linux/soc/samsung/exynos-regs-pmu.h> 18 19 #include <asm/cacheflush.h> 20 #include <asm/cp15.h> 21 #include <asm/smp_plat.h> 22 #include <asm/smp_scu.h> 23 #include <asm/firmware.h> 24 25 #include <mach/map.h> 26 27 #include "common.h" 28 29 extern void exynos4_secondary_startup(void); 30 31 /* XXX exynos_pen_release is cargo culted code - DO NOT COPY XXX */ 32 volatile int exynos_pen_release = -1; 33 34 #ifdef CONFIG_HOTPLUG_CPU 35 static inline void cpu_leave_lowpower(u32 core_id) 36 { 37 unsigned int v; 38 39 asm volatile( 40 "mrc p15, 0, %0, c1, c0, 0\n" 41 " orr %0, %0, %1\n" 42 " mcr p15, 0, %0, c1, c0, 0\n" 43 " mrc p15, 0, %0, c1, c0, 1\n" 44 " orr %0, %0, %2\n" 45 " mcr p15, 0, %0, c1, c0, 1\n" 46 : "=&r" (v) 47 : "Ir" (CR_C), "Ir" (0x40) 48 : "cc"); 49 } 50 51 static inline void platform_do_lowpower(unsigned int cpu, int *spurious) 52 { 53 u32 mpidr = cpu_logical_map(cpu); 54 u32 core_id = MPIDR_AFFINITY_LEVEL(mpidr, 0); 55 56 for (;;) { 57 58 /* Turn the CPU off on next WFI instruction. */ 59 exynos_cpu_power_down(core_id); 60 61 wfi(); 62 63 if (exynos_pen_release == core_id) { 64 /* 65 * OK, proper wakeup, we're done 66 */ 67 break; 68 } 69 70 /* 71 * Getting here, means that we have come out of WFI without 72 * having been woken up - this shouldn't happen 73 * 74 * Just note it happening - when we're woken, we can report 75 * its occurrence. 76 */ 77 (*spurious)++; 78 } 79 } 80 #endif /* CONFIG_HOTPLUG_CPU */ 81 82 /** 83 * exynos_core_power_down : power down the specified cpu 84 * @cpu : the cpu to power down 85 * 86 * Power down the specified cpu. The sequence must be finished by a 87 * call to cpu_do_idle() 88 * 89 */ 90 void exynos_cpu_power_down(int cpu) 91 { 92 u32 core_conf; 93 94 if (cpu == 0 && (soc_is_exynos5420() || soc_is_exynos5800())) { 95 /* 96 * Bypass power down for CPU0 during suspend. Check for 97 * the SYS_PWR_REG value to decide if we are suspending 98 * the system. 99 */ 100 int val = pmu_raw_readl(EXYNOS5_ARM_CORE0_SYS_PWR_REG); 101 102 if (!(val & S5P_CORE_LOCAL_PWR_EN)) 103 return; 104 } 105 106 core_conf = pmu_raw_readl(EXYNOS_ARM_CORE_CONFIGURATION(cpu)); 107 core_conf &= ~S5P_CORE_LOCAL_PWR_EN; 108 pmu_raw_writel(core_conf, EXYNOS_ARM_CORE_CONFIGURATION(cpu)); 109 } 110 111 /** 112 * exynos_cpu_power_up : power up the specified cpu 113 * @cpu : the cpu to power up 114 * 115 * Power up the specified cpu 116 */ 117 void exynos_cpu_power_up(int cpu) 118 { 119 u32 core_conf = S5P_CORE_LOCAL_PWR_EN; 120 121 if (soc_is_exynos3250()) 122 core_conf |= S5P_CORE_AUTOWAKEUP_EN; 123 124 pmu_raw_writel(core_conf, 125 EXYNOS_ARM_CORE_CONFIGURATION(cpu)); 126 } 127 128 /** 129 * exynos_cpu_power_state : returns the power state of the cpu 130 * @cpu : the cpu to retrieve the power state from 131 * 132 */ 133 int exynos_cpu_power_state(int cpu) 134 { 135 return (pmu_raw_readl(EXYNOS_ARM_CORE_STATUS(cpu)) & 136 S5P_CORE_LOCAL_PWR_EN); 137 } 138 139 /** 140 * exynos_cluster_power_down : power down the specified cluster 141 * @cluster : the cluster to power down 142 */ 143 void exynos_cluster_power_down(int cluster) 144 { 145 pmu_raw_writel(0, EXYNOS_COMMON_CONFIGURATION(cluster)); 146 } 147 148 /** 149 * exynos_cluster_power_up : power up the specified cluster 150 * @cluster : the cluster to power up 151 */ 152 void exynos_cluster_power_up(int cluster) 153 { 154 pmu_raw_writel(S5P_CORE_LOCAL_PWR_EN, 155 EXYNOS_COMMON_CONFIGURATION(cluster)); 156 } 157 158 /** 159 * exynos_cluster_power_state : returns the power state of the cluster 160 * @cluster : the cluster to retrieve the power state from 161 * 162 */ 163 int exynos_cluster_power_state(int cluster) 164 { 165 return (pmu_raw_readl(EXYNOS_COMMON_STATUS(cluster)) & 166 S5P_CORE_LOCAL_PWR_EN); 167 } 168 169 /** 170 * exynos_scu_enable : enables SCU for Cortex-A9 based system 171 */ 172 void exynos_scu_enable(void) 173 { 174 struct device_node *np; 175 static void __iomem *scu_base; 176 177 if (!scu_base) { 178 np = of_find_compatible_node(NULL, NULL, "arm,cortex-a9-scu"); 179 if (np) { 180 scu_base = of_iomap(np, 0); 181 of_node_put(np); 182 } else { 183 scu_base = ioremap(scu_a9_get_base(), SZ_4K); 184 } 185 } 186 scu_enable(scu_base); 187 } 188 189 static void __iomem *cpu_boot_reg_base(void) 190 { 191 if (soc_is_exynos4210() && samsung_rev() == EXYNOS4210_REV_1_1) 192 return pmu_base_addr + S5P_INFORM5; 193 return sysram_base_addr; 194 } 195 196 static inline void __iomem *cpu_boot_reg(int cpu) 197 { 198 void __iomem *boot_reg; 199 200 boot_reg = cpu_boot_reg_base(); 201 if (!boot_reg) 202 return IOMEM_ERR_PTR(-ENODEV); 203 if (soc_is_exynos4412()) 204 boot_reg += 4*cpu; 205 else if (soc_is_exynos5420() || soc_is_exynos5800()) 206 boot_reg += 4; 207 return boot_reg; 208 } 209 210 /* 211 * Set wake up by local power mode and execute software reset for given core. 212 * 213 * Currently this is needed only when booting secondary CPU on Exynos3250. 214 */ 215 void exynos_core_restart(u32 core_id) 216 { 217 u32 val; 218 219 if (!of_machine_is_compatible("samsung,exynos3250")) 220 return; 221 222 while (!pmu_raw_readl(S5P_PMU_SPARE2)) 223 udelay(10); 224 udelay(10); 225 226 val = pmu_raw_readl(EXYNOS_ARM_CORE_STATUS(core_id)); 227 val |= S5P_CORE_WAKEUP_FROM_LOCAL_CFG; 228 pmu_raw_writel(val, EXYNOS_ARM_CORE_STATUS(core_id)); 229 230 pmu_raw_writel(EXYNOS_CORE_PO_RESET(core_id), EXYNOS_SWRESET); 231 } 232 233 /* 234 * XXX CARGO CULTED CODE - DO NOT COPY XXX 235 * 236 * Write exynos_pen_release in a way that is guaranteed to be visible to 237 * all observers, irrespective of whether they're taking part in coherency 238 * or not. This is necessary for the hotplug code to work reliably. 239 */ 240 static void exynos_write_pen_release(int val) 241 { 242 exynos_pen_release = val; 243 smp_wmb(); 244 sync_cache_w(&exynos_pen_release); 245 } 246 247 static DEFINE_SPINLOCK(boot_lock); 248 249 static void exynos_secondary_init(unsigned int cpu) 250 { 251 /* 252 * let the primary processor know we're out of the 253 * pen, then head off into the C entry point 254 */ 255 exynos_write_pen_release(-1); 256 257 /* 258 * Synchronise with the boot thread. 259 */ 260 spin_lock(&boot_lock); 261 spin_unlock(&boot_lock); 262 } 263 264 int exynos_set_boot_addr(u32 core_id, unsigned long boot_addr) 265 { 266 int ret; 267 268 /* 269 * Try to set boot address using firmware first 270 * and fall back to boot register if it fails. 271 */ 272 ret = call_firmware_op(set_cpu_boot_addr, core_id, boot_addr); 273 if (ret && ret != -ENOSYS) 274 goto fail; 275 if (ret == -ENOSYS) { 276 void __iomem *boot_reg = cpu_boot_reg(core_id); 277 278 if (IS_ERR(boot_reg)) { 279 ret = PTR_ERR(boot_reg); 280 goto fail; 281 } 282 writel_relaxed(boot_addr, boot_reg); 283 ret = 0; 284 } 285 fail: 286 return ret; 287 } 288 289 int exynos_get_boot_addr(u32 core_id, unsigned long *boot_addr) 290 { 291 int ret; 292 293 /* 294 * Try to get boot address using firmware first 295 * and fall back to boot register if it fails. 296 */ 297 ret = call_firmware_op(get_cpu_boot_addr, core_id, boot_addr); 298 if (ret && ret != -ENOSYS) 299 goto fail; 300 if (ret == -ENOSYS) { 301 void __iomem *boot_reg = cpu_boot_reg(core_id); 302 303 if (IS_ERR(boot_reg)) { 304 ret = PTR_ERR(boot_reg); 305 goto fail; 306 } 307 *boot_addr = readl_relaxed(boot_reg); 308 ret = 0; 309 } 310 fail: 311 return ret; 312 } 313 314 static int exynos_boot_secondary(unsigned int cpu, struct task_struct *idle) 315 { 316 unsigned long timeout; 317 u32 mpidr = cpu_logical_map(cpu); 318 u32 core_id = MPIDR_AFFINITY_LEVEL(mpidr, 0); 319 int ret = -ENOSYS; 320 321 /* 322 * Set synchronisation state between this boot processor 323 * and the secondary one 324 */ 325 spin_lock(&boot_lock); 326 327 /* 328 * The secondary processor is waiting to be released from 329 * the holding pen - release it, then wait for it to flag 330 * that it has been released by resetting exynos_pen_release. 331 * 332 * Note that "exynos_pen_release" is the hardware CPU core ID, whereas 333 * "cpu" is Linux's internal ID. 334 */ 335 exynos_write_pen_release(core_id); 336 337 if (!exynos_cpu_power_state(core_id)) { 338 exynos_cpu_power_up(core_id); 339 timeout = 10; 340 341 /* wait max 10 ms until cpu1 is on */ 342 while (exynos_cpu_power_state(core_id) 343 != S5P_CORE_LOCAL_PWR_EN) { 344 if (timeout == 0) 345 break; 346 timeout--; 347 mdelay(1); 348 } 349 350 if (timeout == 0) { 351 printk(KERN_ERR "cpu1 power enable failed"); 352 spin_unlock(&boot_lock); 353 return -ETIMEDOUT; 354 } 355 } 356 357 exynos_core_restart(core_id); 358 359 /* 360 * Send the secondary CPU a soft interrupt, thereby causing 361 * the boot monitor to read the system wide flags register, 362 * and branch to the address found there. 363 */ 364 365 timeout = jiffies + (1 * HZ); 366 while (time_before(jiffies, timeout)) { 367 unsigned long boot_addr; 368 369 smp_rmb(); 370 371 boot_addr = __pa_symbol(exynos4_secondary_startup); 372 373 ret = exynos_set_boot_addr(core_id, boot_addr); 374 if (ret) 375 goto fail; 376 377 call_firmware_op(cpu_boot, core_id); 378 379 if (soc_is_exynos3250()) 380 dsb_sev(); 381 else 382 arch_send_wakeup_ipi_mask(cpumask_of(cpu)); 383 384 if (exynos_pen_release == -1) 385 break; 386 387 udelay(10); 388 } 389 390 if (exynos_pen_release != -1) 391 ret = -ETIMEDOUT; 392 393 /* 394 * now the secondary core is starting up let it run its 395 * calibrations, then wait for it to finish 396 */ 397 fail: 398 spin_unlock(&boot_lock); 399 400 return exynos_pen_release != -1 ? ret : 0; 401 } 402 403 static void __init exynos_smp_prepare_cpus(unsigned int max_cpus) 404 { 405 exynos_sysram_init(); 406 407 exynos_set_delayed_reset_assertion(true); 408 409 if (read_cpuid_part() == ARM_CPU_PART_CORTEX_A9) 410 exynos_scu_enable(); 411 } 412 413 #ifdef CONFIG_HOTPLUG_CPU 414 /* 415 * platform-specific code to shutdown a CPU 416 * 417 * Called with IRQs disabled 418 */ 419 static void exynos_cpu_die(unsigned int cpu) 420 { 421 int spurious = 0; 422 u32 mpidr = cpu_logical_map(cpu); 423 u32 core_id = MPIDR_AFFINITY_LEVEL(mpidr, 0); 424 425 v7_exit_coherency_flush(louis); 426 427 platform_do_lowpower(cpu, &spurious); 428 429 /* 430 * bring this CPU back into the world of cache 431 * coherency, and then restore interrupts 432 */ 433 cpu_leave_lowpower(core_id); 434 435 if (spurious) 436 pr_warn("CPU%u: %u spurious wakeup calls\n", cpu, spurious); 437 } 438 #endif /* CONFIG_HOTPLUG_CPU */ 439 440 const struct smp_operations exynos_smp_ops __initconst = { 441 .smp_prepare_cpus = exynos_smp_prepare_cpus, 442 .smp_secondary_init = exynos_secondary_init, 443 .smp_boot_secondary = exynos_boot_secondary, 444 #ifdef CONFIG_HOTPLUG_CPU 445 .cpu_die = exynos_cpu_die, 446 #endif 447 }; 448