18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * SMP support for SoCs with SCU covered by mach-shmobile 48c2ecf20Sopenharmony_ci * 58c2ecf20Sopenharmony_ci * Copyright (C) 2013 Magnus Damm 68c2ecf20Sopenharmony_ci */ 78c2ecf20Sopenharmony_ci#include <linux/cpu.h> 88c2ecf20Sopenharmony_ci#include <linux/delay.h> 98c2ecf20Sopenharmony_ci#include <linux/init.h> 108c2ecf20Sopenharmony_ci#include <linux/io.h> 118c2ecf20Sopenharmony_ci#include <linux/smp.h> 128c2ecf20Sopenharmony_ci#include <asm/cacheflush.h> 138c2ecf20Sopenharmony_ci#include <asm/smp_plat.h> 148c2ecf20Sopenharmony_ci#include <asm/smp_scu.h> 158c2ecf20Sopenharmony_ci#include "common.h" 168c2ecf20Sopenharmony_ci 178c2ecf20Sopenharmony_ci 188c2ecf20Sopenharmony_cistatic phys_addr_t shmobile_scu_base_phys; 198c2ecf20Sopenharmony_cistatic void __iomem *shmobile_scu_base; 208c2ecf20Sopenharmony_ci 218c2ecf20Sopenharmony_cistatic int shmobile_scu_cpu_prepare(unsigned int cpu) 228c2ecf20Sopenharmony_ci{ 238c2ecf20Sopenharmony_ci /* For this particular CPU register SCU SMP boot vector */ 248c2ecf20Sopenharmony_ci shmobile_smp_hook(cpu, __pa_symbol(shmobile_boot_scu), 258c2ecf20Sopenharmony_ci shmobile_scu_base_phys); 268c2ecf20Sopenharmony_ci return 0; 278c2ecf20Sopenharmony_ci} 288c2ecf20Sopenharmony_ci 298c2ecf20Sopenharmony_civoid __init shmobile_smp_scu_prepare_cpus(phys_addr_t scu_base_phys, 308c2ecf20Sopenharmony_ci unsigned int max_cpus) 318c2ecf20Sopenharmony_ci{ 328c2ecf20Sopenharmony_ci /* install boot code shared by all CPUs */ 338c2ecf20Sopenharmony_ci shmobile_boot_fn = __pa_symbol(shmobile_smp_boot); 348c2ecf20Sopenharmony_ci 358c2ecf20Sopenharmony_ci /* enable SCU and cache coherency on booting CPU */ 368c2ecf20Sopenharmony_ci shmobile_scu_base_phys = scu_base_phys; 378c2ecf20Sopenharmony_ci shmobile_scu_base = ioremap(scu_base_phys, PAGE_SIZE); 388c2ecf20Sopenharmony_ci scu_enable(shmobile_scu_base); 398c2ecf20Sopenharmony_ci scu_power_mode(shmobile_scu_base, SCU_PM_NORMAL); 408c2ecf20Sopenharmony_ci 418c2ecf20Sopenharmony_ci /* Use CPU notifier for reset vector control */ 428c2ecf20Sopenharmony_ci cpuhp_setup_state_nocalls(CPUHP_ARM_SHMOBILE_SCU_PREPARE, 438c2ecf20Sopenharmony_ci "arm/shmobile-scu:prepare", 448c2ecf20Sopenharmony_ci shmobile_scu_cpu_prepare, NULL); 458c2ecf20Sopenharmony_ci} 468c2ecf20Sopenharmony_ci 478c2ecf20Sopenharmony_ci#ifdef CONFIG_HOTPLUG_CPU 488c2ecf20Sopenharmony_civoid shmobile_smp_scu_cpu_die(unsigned int cpu) 498c2ecf20Sopenharmony_ci{ 508c2ecf20Sopenharmony_ci /* For this particular CPU deregister boot vector */ 518c2ecf20Sopenharmony_ci shmobile_smp_hook(cpu, 0, 0); 528c2ecf20Sopenharmony_ci 538c2ecf20Sopenharmony_ci dsb(); 548c2ecf20Sopenharmony_ci flush_cache_all(); 558c2ecf20Sopenharmony_ci 568c2ecf20Sopenharmony_ci /* disable cache coherency */ 578c2ecf20Sopenharmony_ci scu_power_mode(shmobile_scu_base, SCU_PM_POWEROFF); 588c2ecf20Sopenharmony_ci 598c2ecf20Sopenharmony_ci /* jump to shared mach-shmobile sleep / reset code */ 608c2ecf20Sopenharmony_ci shmobile_smp_sleep(); 618c2ecf20Sopenharmony_ci} 628c2ecf20Sopenharmony_ci 638c2ecf20Sopenharmony_cistatic int shmobile_smp_scu_psr_core_disabled(int cpu) 648c2ecf20Sopenharmony_ci{ 658c2ecf20Sopenharmony_ci unsigned long mask = SCU_PM_POWEROFF << (cpu * 8); 668c2ecf20Sopenharmony_ci 678c2ecf20Sopenharmony_ci if ((__raw_readl(shmobile_scu_base + 8) & mask) == mask) 688c2ecf20Sopenharmony_ci return 1; 698c2ecf20Sopenharmony_ci 708c2ecf20Sopenharmony_ci return 0; 718c2ecf20Sopenharmony_ci} 728c2ecf20Sopenharmony_ci 738c2ecf20Sopenharmony_ciint shmobile_smp_scu_cpu_kill(unsigned int cpu) 748c2ecf20Sopenharmony_ci{ 758c2ecf20Sopenharmony_ci int k; 768c2ecf20Sopenharmony_ci 778c2ecf20Sopenharmony_ci /* this function is running on another CPU than the offline target, 788c2ecf20Sopenharmony_ci * here we need wait for shutdown code in platform_cpu_die() to 798c2ecf20Sopenharmony_ci * finish before asking SoC-specific code to power off the CPU core. 808c2ecf20Sopenharmony_ci */ 818c2ecf20Sopenharmony_ci for (k = 0; k < 1000; k++) { 828c2ecf20Sopenharmony_ci if (shmobile_smp_scu_psr_core_disabled(cpu)) 838c2ecf20Sopenharmony_ci return 1; 848c2ecf20Sopenharmony_ci 858c2ecf20Sopenharmony_ci mdelay(1); 868c2ecf20Sopenharmony_ci } 878c2ecf20Sopenharmony_ci 888c2ecf20Sopenharmony_ci return 0; 898c2ecf20Sopenharmony_ci} 908c2ecf20Sopenharmony_ci#endif 91