18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * OMAP4 SMP source file. It contains platform specific functions 48c2ecf20Sopenharmony_ci * needed for the linux smp kernel. 58c2ecf20Sopenharmony_ci * 68c2ecf20Sopenharmony_ci * Copyright (C) 2009 Texas Instruments, Inc. 78c2ecf20Sopenharmony_ci * 88c2ecf20Sopenharmony_ci * Author: 98c2ecf20Sopenharmony_ci * Santosh Shilimkar <santosh.shilimkar@ti.com> 108c2ecf20Sopenharmony_ci * 118c2ecf20Sopenharmony_ci * Platform file needed for the OMAP4 SMP. This file is based on arm 128c2ecf20Sopenharmony_ci * realview smp platform. 138c2ecf20Sopenharmony_ci * * Copyright (c) 2002 ARM Limited. 148c2ecf20Sopenharmony_ci */ 158c2ecf20Sopenharmony_ci#include <linux/init.h> 168c2ecf20Sopenharmony_ci#include <linux/device.h> 178c2ecf20Sopenharmony_ci#include <linux/smp.h> 188c2ecf20Sopenharmony_ci#include <linux/io.h> 198c2ecf20Sopenharmony_ci#include <linux/irqchip/arm-gic.h> 208c2ecf20Sopenharmony_ci 218c2ecf20Sopenharmony_ci#include <asm/sections.h> 228c2ecf20Sopenharmony_ci#include <asm/smp_scu.h> 238c2ecf20Sopenharmony_ci#include <asm/virt.h> 248c2ecf20Sopenharmony_ci 258c2ecf20Sopenharmony_ci#include "omap-secure.h" 268c2ecf20Sopenharmony_ci#include "omap-wakeupgen.h" 278c2ecf20Sopenharmony_ci#include <asm/cputype.h> 288c2ecf20Sopenharmony_ci 298c2ecf20Sopenharmony_ci#include "soc.h" 308c2ecf20Sopenharmony_ci#include "iomap.h" 318c2ecf20Sopenharmony_ci#include "common.h" 328c2ecf20Sopenharmony_ci#include "clockdomain.h" 338c2ecf20Sopenharmony_ci#include "pm.h" 348c2ecf20Sopenharmony_ci 358c2ecf20Sopenharmony_ci#define CPU_MASK 0xff0ffff0 368c2ecf20Sopenharmony_ci#define CPU_CORTEX_A9 0x410FC090 378c2ecf20Sopenharmony_ci#define CPU_CORTEX_A15 0x410FC0F0 388c2ecf20Sopenharmony_ci 398c2ecf20Sopenharmony_ci#define OMAP5_CORE_COUNT 0x2 408c2ecf20Sopenharmony_ci 418c2ecf20Sopenharmony_ci#define AUX_CORE_BOOT0_GP_RELEASE 0x020 428c2ecf20Sopenharmony_ci#define AUX_CORE_BOOT0_HS_RELEASE 0x200 438c2ecf20Sopenharmony_ci 448c2ecf20Sopenharmony_cistruct omap_smp_config { 458c2ecf20Sopenharmony_ci unsigned long cpu1_rstctrl_pa; 468c2ecf20Sopenharmony_ci void __iomem *cpu1_rstctrl_va; 478c2ecf20Sopenharmony_ci void __iomem *scu_base; 488c2ecf20Sopenharmony_ci void __iomem *wakeupgen_base; 498c2ecf20Sopenharmony_ci void *startup_addr; 508c2ecf20Sopenharmony_ci}; 518c2ecf20Sopenharmony_ci 528c2ecf20Sopenharmony_cistatic struct omap_smp_config cfg; 538c2ecf20Sopenharmony_ci 548c2ecf20Sopenharmony_cistatic const struct omap_smp_config omap443x_cfg __initconst = { 558c2ecf20Sopenharmony_ci .cpu1_rstctrl_pa = 0x4824380c, 568c2ecf20Sopenharmony_ci .startup_addr = omap4_secondary_startup, 578c2ecf20Sopenharmony_ci}; 588c2ecf20Sopenharmony_ci 598c2ecf20Sopenharmony_cistatic const struct omap_smp_config omap446x_cfg __initconst = { 608c2ecf20Sopenharmony_ci .cpu1_rstctrl_pa = 0x4824380c, 618c2ecf20Sopenharmony_ci .startup_addr = omap4460_secondary_startup, 628c2ecf20Sopenharmony_ci}; 638c2ecf20Sopenharmony_ci 648c2ecf20Sopenharmony_cistatic const struct omap_smp_config omap5_cfg __initconst = { 658c2ecf20Sopenharmony_ci .cpu1_rstctrl_pa = 0x48243810, 668c2ecf20Sopenharmony_ci .startup_addr = omap5_secondary_startup, 678c2ecf20Sopenharmony_ci}; 688c2ecf20Sopenharmony_ci 698c2ecf20Sopenharmony_civoid __iomem *omap4_get_scu_base(void) 708c2ecf20Sopenharmony_ci{ 718c2ecf20Sopenharmony_ci return cfg.scu_base; 728c2ecf20Sopenharmony_ci} 738c2ecf20Sopenharmony_ci 748c2ecf20Sopenharmony_ci#ifdef CONFIG_OMAP5_ERRATA_801819 758c2ecf20Sopenharmony_cistatic void omap5_erratum_workaround_801819(void) 768c2ecf20Sopenharmony_ci{ 778c2ecf20Sopenharmony_ci u32 acr, revidr; 788c2ecf20Sopenharmony_ci u32 acr_mask; 798c2ecf20Sopenharmony_ci 808c2ecf20Sopenharmony_ci /* REVIDR[3] indicates erratum fix available on silicon */ 818c2ecf20Sopenharmony_ci asm volatile ("mrc p15, 0, %0, c0, c0, 6" : "=r" (revidr)); 828c2ecf20Sopenharmony_ci if (revidr & (0x1 << 3)) 838c2ecf20Sopenharmony_ci return; 848c2ecf20Sopenharmony_ci 858c2ecf20Sopenharmony_ci asm volatile ("mrc p15, 0, %0, c1, c0, 1" : "=r" (acr)); 868c2ecf20Sopenharmony_ci /* 878c2ecf20Sopenharmony_ci * BIT(27) - Disables streaming. All write-allocate lines allocate in 888c2ecf20Sopenharmony_ci * the L1 or L2 cache. 898c2ecf20Sopenharmony_ci * BIT(25) - Disables streaming. All write-allocate lines allocate in 908c2ecf20Sopenharmony_ci * the L1 cache. 918c2ecf20Sopenharmony_ci */ 928c2ecf20Sopenharmony_ci acr_mask = (0x3 << 25) | (0x3 << 27); 938c2ecf20Sopenharmony_ci /* do we already have it done.. if yes, skip expensive smc */ 948c2ecf20Sopenharmony_ci if ((acr & acr_mask) == acr_mask) 958c2ecf20Sopenharmony_ci return; 968c2ecf20Sopenharmony_ci 978c2ecf20Sopenharmony_ci acr |= acr_mask; 988c2ecf20Sopenharmony_ci omap_smc1(OMAP5_DRA7_MON_SET_ACR_INDEX, acr); 998c2ecf20Sopenharmony_ci 1008c2ecf20Sopenharmony_ci pr_debug("%s: ARM erratum workaround 801819 applied on CPU%d\n", 1018c2ecf20Sopenharmony_ci __func__, smp_processor_id()); 1028c2ecf20Sopenharmony_ci} 1038c2ecf20Sopenharmony_ci#else 1048c2ecf20Sopenharmony_cistatic inline void omap5_erratum_workaround_801819(void) { } 1058c2ecf20Sopenharmony_ci#endif 1068c2ecf20Sopenharmony_ci 1078c2ecf20Sopenharmony_ci#ifdef CONFIG_HARDEN_BRANCH_PREDICTOR 1088c2ecf20Sopenharmony_ci/* 1098c2ecf20Sopenharmony_ci * Configure ACR and enable ACTLR[0] (Enable invalidates of BTB with 1108c2ecf20Sopenharmony_ci * ICIALLU) to activate the workaround for secondary Core. 1118c2ecf20Sopenharmony_ci * NOTE: it is assumed that the primary core's configuration is done 1128c2ecf20Sopenharmony_ci * by the boot loader (kernel will detect a misconfiguration and complain 1138c2ecf20Sopenharmony_ci * if this is not done). 1148c2ecf20Sopenharmony_ci * 1158c2ecf20Sopenharmony_ci * In General Purpose(GP) devices, ACR bit settings can only be done 1168c2ecf20Sopenharmony_ci * by ROM code in "secure world" using the smc call and there is no 1178c2ecf20Sopenharmony_ci * option to update the "firmware" on such devices. This also works for 1188c2ecf20Sopenharmony_ci * High security(HS) devices, as a backup option in case the 1198c2ecf20Sopenharmony_ci * "update" is not done in the "security firmware". 1208c2ecf20Sopenharmony_ci */ 1218c2ecf20Sopenharmony_cistatic void omap5_secondary_harden_predictor(void) 1228c2ecf20Sopenharmony_ci{ 1238c2ecf20Sopenharmony_ci u32 acr, acr_mask; 1248c2ecf20Sopenharmony_ci 1258c2ecf20Sopenharmony_ci asm volatile ("mrc p15, 0, %0, c1, c0, 1" : "=r" (acr)); 1268c2ecf20Sopenharmony_ci 1278c2ecf20Sopenharmony_ci /* 1288c2ecf20Sopenharmony_ci * ACTLR[0] (Enable invalidates of BTB with ICIALLU) 1298c2ecf20Sopenharmony_ci */ 1308c2ecf20Sopenharmony_ci acr_mask = BIT(0); 1318c2ecf20Sopenharmony_ci 1328c2ecf20Sopenharmony_ci /* Do we already have it done.. if yes, skip expensive smc */ 1338c2ecf20Sopenharmony_ci if ((acr & acr_mask) == acr_mask) 1348c2ecf20Sopenharmony_ci return; 1358c2ecf20Sopenharmony_ci 1368c2ecf20Sopenharmony_ci acr |= acr_mask; 1378c2ecf20Sopenharmony_ci omap_smc1(OMAP5_DRA7_MON_SET_ACR_INDEX, acr); 1388c2ecf20Sopenharmony_ci 1398c2ecf20Sopenharmony_ci pr_debug("%s: ARM ACR setup for CVE_2017_5715 applied on CPU%d\n", 1408c2ecf20Sopenharmony_ci __func__, smp_processor_id()); 1418c2ecf20Sopenharmony_ci} 1428c2ecf20Sopenharmony_ci#else 1438c2ecf20Sopenharmony_cistatic inline void omap5_secondary_harden_predictor(void) { } 1448c2ecf20Sopenharmony_ci#endif 1458c2ecf20Sopenharmony_ci 1468c2ecf20Sopenharmony_cistatic void omap4_secondary_init(unsigned int cpu) 1478c2ecf20Sopenharmony_ci{ 1488c2ecf20Sopenharmony_ci /* 1498c2ecf20Sopenharmony_ci * Configure ACTRL and enable NS SMP bit access on CPU1 on HS device. 1508c2ecf20Sopenharmony_ci * OMAP44XX EMU/HS devices - CPU0 SMP bit access is enabled in PPA 1518c2ecf20Sopenharmony_ci * init and for CPU1, a secure PPA API provided. CPU0 must be ON 1528c2ecf20Sopenharmony_ci * while executing NS_SMP API on CPU1 and PPA version must be 1.4.0+. 1538c2ecf20Sopenharmony_ci * OMAP443X GP devices- SMP bit isn't accessible. 1548c2ecf20Sopenharmony_ci * OMAP446X GP devices - SMP bit access is enabled on both CPUs. 1558c2ecf20Sopenharmony_ci */ 1568c2ecf20Sopenharmony_ci if (soc_is_omap443x() && (omap_type() != OMAP2_DEVICE_TYPE_GP)) 1578c2ecf20Sopenharmony_ci omap_secure_dispatcher(OMAP4_PPA_CPU_ACTRL_SMP_INDEX, 1588c2ecf20Sopenharmony_ci 4, 0, 0, 0, 0, 0); 1598c2ecf20Sopenharmony_ci 1608c2ecf20Sopenharmony_ci if (soc_is_omap54xx() || soc_is_dra7xx()) { 1618c2ecf20Sopenharmony_ci /* 1628c2ecf20Sopenharmony_ci * Configure the CNTFRQ register for the secondary cpu's which 1638c2ecf20Sopenharmony_ci * indicates the frequency of the cpu local timers. 1648c2ecf20Sopenharmony_ci */ 1658c2ecf20Sopenharmony_ci set_cntfreq(); 1668c2ecf20Sopenharmony_ci /* Configure ACR to disable streaming WA for 801819 */ 1678c2ecf20Sopenharmony_ci omap5_erratum_workaround_801819(); 1688c2ecf20Sopenharmony_ci /* Enable ACR to allow for ICUALLU workaround */ 1698c2ecf20Sopenharmony_ci omap5_secondary_harden_predictor(); 1708c2ecf20Sopenharmony_ci } 1718c2ecf20Sopenharmony_ci} 1728c2ecf20Sopenharmony_ci 1738c2ecf20Sopenharmony_cistatic int omap4_boot_secondary(unsigned int cpu, struct task_struct *idle) 1748c2ecf20Sopenharmony_ci{ 1758c2ecf20Sopenharmony_ci static struct clockdomain *cpu1_clkdm; 1768c2ecf20Sopenharmony_ci static bool booted; 1778c2ecf20Sopenharmony_ci static struct powerdomain *cpu1_pwrdm; 1788c2ecf20Sopenharmony_ci 1798c2ecf20Sopenharmony_ci /* 1808c2ecf20Sopenharmony_ci * Update the AuxCoreBoot0 with boot state for secondary core. 1818c2ecf20Sopenharmony_ci * omap4_secondary_startup() routine will hold the secondary core till 1828c2ecf20Sopenharmony_ci * the AuxCoreBoot1 register is updated with cpu state 1838c2ecf20Sopenharmony_ci * A barrier is added to ensure that write buffer is drained 1848c2ecf20Sopenharmony_ci */ 1858c2ecf20Sopenharmony_ci if (omap_secure_apis_support()) 1868c2ecf20Sopenharmony_ci omap_modify_auxcoreboot0(AUX_CORE_BOOT0_HS_RELEASE, 1878c2ecf20Sopenharmony_ci 0xfffffdff); 1888c2ecf20Sopenharmony_ci else 1898c2ecf20Sopenharmony_ci writel_relaxed(AUX_CORE_BOOT0_GP_RELEASE, 1908c2ecf20Sopenharmony_ci cfg.wakeupgen_base + OMAP_AUX_CORE_BOOT_0); 1918c2ecf20Sopenharmony_ci 1928c2ecf20Sopenharmony_ci if (!cpu1_clkdm && !cpu1_pwrdm) { 1938c2ecf20Sopenharmony_ci cpu1_clkdm = clkdm_lookup("mpu1_clkdm"); 1948c2ecf20Sopenharmony_ci cpu1_pwrdm = pwrdm_lookup("cpu1_pwrdm"); 1958c2ecf20Sopenharmony_ci } 1968c2ecf20Sopenharmony_ci 1978c2ecf20Sopenharmony_ci /* 1988c2ecf20Sopenharmony_ci * The SGI(Software Generated Interrupts) are not wakeup capable 1998c2ecf20Sopenharmony_ci * from low power states. This is known limitation on OMAP4 and 2008c2ecf20Sopenharmony_ci * needs to be worked around by using software forced clockdomain 2018c2ecf20Sopenharmony_ci * wake-up. To wakeup CPU1, CPU0 forces the CPU1 clockdomain to 2028c2ecf20Sopenharmony_ci * software force wakeup. The clockdomain is then put back to 2038c2ecf20Sopenharmony_ci * hardware supervised mode. 2048c2ecf20Sopenharmony_ci * More details can be found in OMAP4430 TRM - Version J 2058c2ecf20Sopenharmony_ci * Section : 2068c2ecf20Sopenharmony_ci * 4.3.4.2 Power States of CPU0 and CPU1 2078c2ecf20Sopenharmony_ci */ 2088c2ecf20Sopenharmony_ci if (booted && cpu1_pwrdm && cpu1_clkdm) { 2098c2ecf20Sopenharmony_ci /* 2108c2ecf20Sopenharmony_ci * GIC distributor control register has changed between 2118c2ecf20Sopenharmony_ci * CortexA9 r1pX and r2pX. The Control Register secure 2128c2ecf20Sopenharmony_ci * banked version is now composed of 2 bits: 2138c2ecf20Sopenharmony_ci * bit 0 == Secure Enable 2148c2ecf20Sopenharmony_ci * bit 1 == Non-Secure Enable 2158c2ecf20Sopenharmony_ci * The Non-Secure banked register has not changed 2168c2ecf20Sopenharmony_ci * Because the ROM Code is based on the r1pX GIC, the CPU1 2178c2ecf20Sopenharmony_ci * GIC restoration will cause a problem to CPU0 Non-Secure SW. 2188c2ecf20Sopenharmony_ci * The workaround must be: 2198c2ecf20Sopenharmony_ci * 1) Before doing the CPU1 wakeup, CPU0 must disable 2208c2ecf20Sopenharmony_ci * the GIC distributor 2218c2ecf20Sopenharmony_ci * 2) CPU1 must re-enable the GIC distributor on 2228c2ecf20Sopenharmony_ci * it's wakeup path. 2238c2ecf20Sopenharmony_ci */ 2248c2ecf20Sopenharmony_ci if (IS_PM44XX_ERRATUM(PM_OMAP4_ROM_SMP_BOOT_ERRATUM_GICD)) { 2258c2ecf20Sopenharmony_ci local_irq_disable(); 2268c2ecf20Sopenharmony_ci gic_dist_disable(); 2278c2ecf20Sopenharmony_ci } 2288c2ecf20Sopenharmony_ci 2298c2ecf20Sopenharmony_ci /* 2308c2ecf20Sopenharmony_ci * Ensure that CPU power state is set to ON to avoid CPU 2318c2ecf20Sopenharmony_ci * powerdomain transition on wfi 2328c2ecf20Sopenharmony_ci */ 2338c2ecf20Sopenharmony_ci clkdm_deny_idle_nolock(cpu1_clkdm); 2348c2ecf20Sopenharmony_ci pwrdm_set_next_pwrst(cpu1_pwrdm, PWRDM_POWER_ON); 2358c2ecf20Sopenharmony_ci clkdm_allow_idle_nolock(cpu1_clkdm); 2368c2ecf20Sopenharmony_ci 2378c2ecf20Sopenharmony_ci if (IS_PM44XX_ERRATUM(PM_OMAP4_ROM_SMP_BOOT_ERRATUM_GICD)) { 2388c2ecf20Sopenharmony_ci while (gic_dist_disabled()) { 2398c2ecf20Sopenharmony_ci udelay(1); 2408c2ecf20Sopenharmony_ci cpu_relax(); 2418c2ecf20Sopenharmony_ci } 2428c2ecf20Sopenharmony_ci gic_timer_retrigger(); 2438c2ecf20Sopenharmony_ci local_irq_enable(); 2448c2ecf20Sopenharmony_ci } 2458c2ecf20Sopenharmony_ci } else { 2468c2ecf20Sopenharmony_ci dsb_sev(); 2478c2ecf20Sopenharmony_ci booted = true; 2488c2ecf20Sopenharmony_ci } 2498c2ecf20Sopenharmony_ci 2508c2ecf20Sopenharmony_ci arch_send_wakeup_ipi_mask(cpumask_of(cpu)); 2518c2ecf20Sopenharmony_ci 2528c2ecf20Sopenharmony_ci return 0; 2538c2ecf20Sopenharmony_ci} 2548c2ecf20Sopenharmony_ci 2558c2ecf20Sopenharmony_ci/* 2568c2ecf20Sopenharmony_ci * Initialise the CPU possible map early - this describes the CPUs 2578c2ecf20Sopenharmony_ci * which may be present or become present in the system. 2588c2ecf20Sopenharmony_ci */ 2598c2ecf20Sopenharmony_cistatic void __init omap4_smp_init_cpus(void) 2608c2ecf20Sopenharmony_ci{ 2618c2ecf20Sopenharmony_ci unsigned int i = 0, ncores = 1, cpu_id; 2628c2ecf20Sopenharmony_ci 2638c2ecf20Sopenharmony_ci /* Use ARM cpuid check here, as SoC detection will not work so early */ 2648c2ecf20Sopenharmony_ci cpu_id = read_cpuid_id() & CPU_MASK; 2658c2ecf20Sopenharmony_ci if (cpu_id == CPU_CORTEX_A9) { 2668c2ecf20Sopenharmony_ci /* 2678c2ecf20Sopenharmony_ci * Currently we can't call ioremap here because 2688c2ecf20Sopenharmony_ci * SoC detection won't work until after init_early. 2698c2ecf20Sopenharmony_ci */ 2708c2ecf20Sopenharmony_ci cfg.scu_base = OMAP2_L4_IO_ADDRESS(scu_a9_get_base()); 2718c2ecf20Sopenharmony_ci BUG_ON(!cfg.scu_base); 2728c2ecf20Sopenharmony_ci ncores = scu_get_core_count(cfg.scu_base); 2738c2ecf20Sopenharmony_ci } else if (cpu_id == CPU_CORTEX_A15) { 2748c2ecf20Sopenharmony_ci ncores = OMAP5_CORE_COUNT; 2758c2ecf20Sopenharmony_ci } 2768c2ecf20Sopenharmony_ci 2778c2ecf20Sopenharmony_ci /* sanity check */ 2788c2ecf20Sopenharmony_ci if (ncores > nr_cpu_ids) { 2798c2ecf20Sopenharmony_ci pr_warn("SMP: %u cores greater than maximum (%u), clipping\n", 2808c2ecf20Sopenharmony_ci ncores, nr_cpu_ids); 2818c2ecf20Sopenharmony_ci ncores = nr_cpu_ids; 2828c2ecf20Sopenharmony_ci } 2838c2ecf20Sopenharmony_ci 2848c2ecf20Sopenharmony_ci for (i = 0; i < ncores; i++) 2858c2ecf20Sopenharmony_ci set_cpu_possible(i, true); 2868c2ecf20Sopenharmony_ci} 2878c2ecf20Sopenharmony_ci 2888c2ecf20Sopenharmony_ci/* 2898c2ecf20Sopenharmony_ci * For now, just make sure the start-up address is not within the booting 2908c2ecf20Sopenharmony_ci * kernel space as that means we just overwrote whatever secondary_startup() 2918c2ecf20Sopenharmony_ci * code there was. 2928c2ecf20Sopenharmony_ci */ 2938c2ecf20Sopenharmony_cistatic bool __init omap4_smp_cpu1_startup_valid(unsigned long addr) 2948c2ecf20Sopenharmony_ci{ 2958c2ecf20Sopenharmony_ci if ((addr >= __pa(PAGE_OFFSET)) && (addr <= __pa(__bss_start))) 2968c2ecf20Sopenharmony_ci return false; 2978c2ecf20Sopenharmony_ci 2988c2ecf20Sopenharmony_ci return true; 2998c2ecf20Sopenharmony_ci} 3008c2ecf20Sopenharmony_ci 3018c2ecf20Sopenharmony_ci/* 3028c2ecf20Sopenharmony_ci * We may need to reset CPU1 before configuring, otherwise kexec boot can end 3038c2ecf20Sopenharmony_ci * up trying to use old kernel startup address or suspend-resume will 3048c2ecf20Sopenharmony_ci * occasionally fail to bring up CPU1 on 4430 if CPU1 fails to enter deeper 3058c2ecf20Sopenharmony_ci * idle states. 3068c2ecf20Sopenharmony_ci */ 3078c2ecf20Sopenharmony_cistatic void __init omap4_smp_maybe_reset_cpu1(struct omap_smp_config *c) 3088c2ecf20Sopenharmony_ci{ 3098c2ecf20Sopenharmony_ci unsigned long cpu1_startup_pa, cpu1_ns_pa_addr; 3108c2ecf20Sopenharmony_ci bool needs_reset = false; 3118c2ecf20Sopenharmony_ci u32 released; 3128c2ecf20Sopenharmony_ci 3138c2ecf20Sopenharmony_ci if (omap_secure_apis_support()) 3148c2ecf20Sopenharmony_ci released = omap_read_auxcoreboot0() & AUX_CORE_BOOT0_HS_RELEASE; 3158c2ecf20Sopenharmony_ci else 3168c2ecf20Sopenharmony_ci released = readl_relaxed(cfg.wakeupgen_base + 3178c2ecf20Sopenharmony_ci OMAP_AUX_CORE_BOOT_0) & 3188c2ecf20Sopenharmony_ci AUX_CORE_BOOT0_GP_RELEASE; 3198c2ecf20Sopenharmony_ci if (released) { 3208c2ecf20Sopenharmony_ci pr_warn("smp: CPU1 not parked?\n"); 3218c2ecf20Sopenharmony_ci 3228c2ecf20Sopenharmony_ci return; 3238c2ecf20Sopenharmony_ci } 3248c2ecf20Sopenharmony_ci 3258c2ecf20Sopenharmony_ci cpu1_startup_pa = readl_relaxed(cfg.wakeupgen_base + 3268c2ecf20Sopenharmony_ci OMAP_AUX_CORE_BOOT_1); 3278c2ecf20Sopenharmony_ci 3288c2ecf20Sopenharmony_ci /* Did the configured secondary_startup() get overwritten? */ 3298c2ecf20Sopenharmony_ci if (!omap4_smp_cpu1_startup_valid(cpu1_startup_pa)) 3308c2ecf20Sopenharmony_ci needs_reset = true; 3318c2ecf20Sopenharmony_ci 3328c2ecf20Sopenharmony_ci /* 3338c2ecf20Sopenharmony_ci * If omap4 or 5 has NS_PA_ADDR configured, CPU1 may be in a 3348c2ecf20Sopenharmony_ci * deeper idle state in WFI and will wake to an invalid address. 3358c2ecf20Sopenharmony_ci */ 3368c2ecf20Sopenharmony_ci if ((soc_is_omap44xx() || soc_is_omap54xx())) { 3378c2ecf20Sopenharmony_ci cpu1_ns_pa_addr = omap4_get_cpu1_ns_pa_addr(); 3388c2ecf20Sopenharmony_ci if (!omap4_smp_cpu1_startup_valid(cpu1_ns_pa_addr)) 3398c2ecf20Sopenharmony_ci needs_reset = true; 3408c2ecf20Sopenharmony_ci } else { 3418c2ecf20Sopenharmony_ci cpu1_ns_pa_addr = 0; 3428c2ecf20Sopenharmony_ci } 3438c2ecf20Sopenharmony_ci 3448c2ecf20Sopenharmony_ci if (!needs_reset || !c->cpu1_rstctrl_va) 3458c2ecf20Sopenharmony_ci return; 3468c2ecf20Sopenharmony_ci 3478c2ecf20Sopenharmony_ci pr_info("smp: CPU1 parked within kernel, needs reset (0x%lx 0x%lx)\n", 3488c2ecf20Sopenharmony_ci cpu1_startup_pa, cpu1_ns_pa_addr); 3498c2ecf20Sopenharmony_ci 3508c2ecf20Sopenharmony_ci writel_relaxed(1, c->cpu1_rstctrl_va); 3518c2ecf20Sopenharmony_ci readl_relaxed(c->cpu1_rstctrl_va); 3528c2ecf20Sopenharmony_ci writel_relaxed(0, c->cpu1_rstctrl_va); 3538c2ecf20Sopenharmony_ci} 3548c2ecf20Sopenharmony_ci 3558c2ecf20Sopenharmony_cistatic void __init omap4_smp_prepare_cpus(unsigned int max_cpus) 3568c2ecf20Sopenharmony_ci{ 3578c2ecf20Sopenharmony_ci const struct omap_smp_config *c = NULL; 3588c2ecf20Sopenharmony_ci 3598c2ecf20Sopenharmony_ci if (soc_is_omap443x()) 3608c2ecf20Sopenharmony_ci c = &omap443x_cfg; 3618c2ecf20Sopenharmony_ci else if (soc_is_omap446x()) 3628c2ecf20Sopenharmony_ci c = &omap446x_cfg; 3638c2ecf20Sopenharmony_ci else if (soc_is_dra74x() || soc_is_omap54xx() || soc_is_dra76x()) 3648c2ecf20Sopenharmony_ci c = &omap5_cfg; 3658c2ecf20Sopenharmony_ci 3668c2ecf20Sopenharmony_ci if (!c) { 3678c2ecf20Sopenharmony_ci pr_err("%s Unknown SMP SoC?\n", __func__); 3688c2ecf20Sopenharmony_ci return; 3698c2ecf20Sopenharmony_ci } 3708c2ecf20Sopenharmony_ci 3718c2ecf20Sopenharmony_ci /* Must preserve cfg.scu_base set earlier */ 3728c2ecf20Sopenharmony_ci cfg.cpu1_rstctrl_pa = c->cpu1_rstctrl_pa; 3738c2ecf20Sopenharmony_ci cfg.startup_addr = c->startup_addr; 3748c2ecf20Sopenharmony_ci cfg.wakeupgen_base = omap_get_wakeupgen_base(); 3758c2ecf20Sopenharmony_ci 3768c2ecf20Sopenharmony_ci if (soc_is_dra74x() || soc_is_omap54xx() || soc_is_dra76x()) { 3778c2ecf20Sopenharmony_ci if ((__boot_cpu_mode & MODE_MASK) == HYP_MODE) 3788c2ecf20Sopenharmony_ci cfg.startup_addr = omap5_secondary_hyp_startup; 3798c2ecf20Sopenharmony_ci omap5_erratum_workaround_801819(); 3808c2ecf20Sopenharmony_ci } 3818c2ecf20Sopenharmony_ci 3828c2ecf20Sopenharmony_ci cfg.cpu1_rstctrl_va = ioremap(cfg.cpu1_rstctrl_pa, 4); 3838c2ecf20Sopenharmony_ci if (!cfg.cpu1_rstctrl_va) 3848c2ecf20Sopenharmony_ci return; 3858c2ecf20Sopenharmony_ci 3868c2ecf20Sopenharmony_ci /* 3878c2ecf20Sopenharmony_ci * Initialise the SCU and wake up the secondary core using 3888c2ecf20Sopenharmony_ci * wakeup_secondary(). 3898c2ecf20Sopenharmony_ci */ 3908c2ecf20Sopenharmony_ci if (cfg.scu_base) 3918c2ecf20Sopenharmony_ci scu_enable(cfg.scu_base); 3928c2ecf20Sopenharmony_ci 3938c2ecf20Sopenharmony_ci omap4_smp_maybe_reset_cpu1(&cfg); 3948c2ecf20Sopenharmony_ci 3958c2ecf20Sopenharmony_ci /* 3968c2ecf20Sopenharmony_ci * Write the address of secondary startup routine into the 3978c2ecf20Sopenharmony_ci * AuxCoreBoot1 where ROM code will jump and start executing 3988c2ecf20Sopenharmony_ci * on secondary core once out of WFE 3998c2ecf20Sopenharmony_ci * A barrier is added to ensure that write buffer is drained 4008c2ecf20Sopenharmony_ci */ 4018c2ecf20Sopenharmony_ci if (omap_secure_apis_support()) 4028c2ecf20Sopenharmony_ci omap_auxcoreboot_addr(__pa_symbol(cfg.startup_addr)); 4038c2ecf20Sopenharmony_ci else 4048c2ecf20Sopenharmony_ci writel_relaxed(__pa_symbol(cfg.startup_addr), 4058c2ecf20Sopenharmony_ci cfg.wakeupgen_base + OMAP_AUX_CORE_BOOT_1); 4068c2ecf20Sopenharmony_ci} 4078c2ecf20Sopenharmony_ci 4088c2ecf20Sopenharmony_ciconst struct smp_operations omap4_smp_ops __initconst = { 4098c2ecf20Sopenharmony_ci .smp_init_cpus = omap4_smp_init_cpus, 4108c2ecf20Sopenharmony_ci .smp_prepare_cpus = omap4_smp_prepare_cpus, 4118c2ecf20Sopenharmony_ci .smp_secondary_init = omap4_secondary_init, 4128c2ecf20Sopenharmony_ci .smp_boot_secondary = omap4_boot_secondary, 4138c2ecf20Sopenharmony_ci#ifdef CONFIG_HOTPLUG_CPU 4148c2ecf20Sopenharmony_ci .cpu_die = omap4_cpu_die, 4158c2ecf20Sopenharmony_ci .cpu_kill = omap4_cpu_kill, 4168c2ecf20Sopenharmony_ci#endif 4178c2ecf20Sopenharmony_ci}; 418