162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * SMP support for SoCs with SCU covered by mach-shmobile 462306a36Sopenharmony_ci * 562306a36Sopenharmony_ci * Copyright (C) 2013 Magnus Damm 662306a36Sopenharmony_ci */ 762306a36Sopenharmony_ci#include <linux/cpu.h> 862306a36Sopenharmony_ci#include <linux/delay.h> 962306a36Sopenharmony_ci#include <linux/init.h> 1062306a36Sopenharmony_ci#include <linux/io.h> 1162306a36Sopenharmony_ci#include <linux/smp.h> 1262306a36Sopenharmony_ci#include <asm/cacheflush.h> 1362306a36Sopenharmony_ci#include <asm/smp_plat.h> 1462306a36Sopenharmony_ci#include <asm/smp_scu.h> 1562306a36Sopenharmony_ci#include "common.h" 1662306a36Sopenharmony_ci 1762306a36Sopenharmony_ci 1862306a36Sopenharmony_cistatic phys_addr_t shmobile_scu_base_phys; 1962306a36Sopenharmony_cistatic void __iomem *shmobile_scu_base; 2062306a36Sopenharmony_ci 2162306a36Sopenharmony_cistatic int shmobile_scu_cpu_prepare(unsigned int cpu) 2262306a36Sopenharmony_ci{ 2362306a36Sopenharmony_ci /* For this particular CPU register SCU SMP boot vector */ 2462306a36Sopenharmony_ci shmobile_smp_hook(cpu, __pa_symbol(shmobile_boot_scu), 2562306a36Sopenharmony_ci shmobile_scu_base_phys); 2662306a36Sopenharmony_ci return 0; 2762306a36Sopenharmony_ci} 2862306a36Sopenharmony_ci 2962306a36Sopenharmony_civoid __init shmobile_smp_scu_prepare_cpus(phys_addr_t scu_base_phys, 3062306a36Sopenharmony_ci unsigned int max_cpus) 3162306a36Sopenharmony_ci{ 3262306a36Sopenharmony_ci /* install boot code shared by all CPUs */ 3362306a36Sopenharmony_ci shmobile_boot_fn = __pa_symbol(shmobile_smp_boot); 3462306a36Sopenharmony_ci 3562306a36Sopenharmony_ci /* enable SCU and cache coherency on booting CPU */ 3662306a36Sopenharmony_ci shmobile_scu_base_phys = scu_base_phys; 3762306a36Sopenharmony_ci shmobile_scu_base = ioremap(scu_base_phys, PAGE_SIZE); 3862306a36Sopenharmony_ci scu_enable(shmobile_scu_base); 3962306a36Sopenharmony_ci scu_power_mode(shmobile_scu_base, SCU_PM_NORMAL); 4062306a36Sopenharmony_ci 4162306a36Sopenharmony_ci /* Use CPU notifier for reset vector control */ 4262306a36Sopenharmony_ci cpuhp_setup_state_nocalls(CPUHP_ARM_SHMOBILE_SCU_PREPARE, 4362306a36Sopenharmony_ci "arm/shmobile-scu:prepare", 4462306a36Sopenharmony_ci shmobile_scu_cpu_prepare, NULL); 4562306a36Sopenharmony_ci} 4662306a36Sopenharmony_ci 4762306a36Sopenharmony_ci#ifdef CONFIG_HOTPLUG_CPU 4862306a36Sopenharmony_civoid shmobile_smp_scu_cpu_die(unsigned int cpu) 4962306a36Sopenharmony_ci{ 5062306a36Sopenharmony_ci /* For this particular CPU deregister boot vector */ 5162306a36Sopenharmony_ci shmobile_smp_hook(cpu, 0, 0); 5262306a36Sopenharmony_ci 5362306a36Sopenharmony_ci dsb(); 5462306a36Sopenharmony_ci flush_cache_all(); 5562306a36Sopenharmony_ci 5662306a36Sopenharmony_ci /* disable cache coherency */ 5762306a36Sopenharmony_ci scu_power_mode(shmobile_scu_base, SCU_PM_POWEROFF); 5862306a36Sopenharmony_ci 5962306a36Sopenharmony_ci /* jump to shared mach-shmobile sleep / reset code */ 6062306a36Sopenharmony_ci shmobile_smp_sleep(); 6162306a36Sopenharmony_ci} 6262306a36Sopenharmony_ci 6362306a36Sopenharmony_cistatic int shmobile_smp_scu_psr_core_disabled(int cpu) 6462306a36Sopenharmony_ci{ 6562306a36Sopenharmony_ci unsigned long mask = SCU_PM_POWEROFF << (cpu * 8); 6662306a36Sopenharmony_ci 6762306a36Sopenharmony_ci if ((readl(shmobile_scu_base + 8) & mask) == mask) 6862306a36Sopenharmony_ci return 1; 6962306a36Sopenharmony_ci 7062306a36Sopenharmony_ci return 0; 7162306a36Sopenharmony_ci} 7262306a36Sopenharmony_ci 7362306a36Sopenharmony_ciint shmobile_smp_scu_cpu_kill(unsigned int cpu) 7462306a36Sopenharmony_ci{ 7562306a36Sopenharmony_ci int k; 7662306a36Sopenharmony_ci 7762306a36Sopenharmony_ci /* this function is running on another CPU than the offline target, 7862306a36Sopenharmony_ci * here we need wait for shutdown code in platform_cpu_die() to 7962306a36Sopenharmony_ci * finish before asking SoC-specific code to power off the CPU core. 8062306a36Sopenharmony_ci */ 8162306a36Sopenharmony_ci for (k = 0; k < 1000; k++) { 8262306a36Sopenharmony_ci if (shmobile_smp_scu_psr_core_disabled(cpu)) 8362306a36Sopenharmony_ci return 1; 8462306a36Sopenharmony_ci 8562306a36Sopenharmony_ci mdelay(1); 8662306a36Sopenharmony_ci } 8762306a36Sopenharmony_ci 8862306a36Sopenharmony_ci return 0; 8962306a36Sopenharmony_ci} 9062306a36Sopenharmony_ci#endif 91