162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * OMAP4 SMP source file. It contains platform specific functions 462306a36Sopenharmony_ci * needed for the linux smp kernel. 562306a36Sopenharmony_ci * 662306a36Sopenharmony_ci * Copyright (C) 2009 Texas Instruments, Inc. 762306a36Sopenharmony_ci * 862306a36Sopenharmony_ci * Author: 962306a36Sopenharmony_ci * Santosh Shilimkar <santosh.shilimkar@ti.com> 1062306a36Sopenharmony_ci * 1162306a36Sopenharmony_ci * Platform file needed for the OMAP4 SMP. This file is based on arm 1262306a36Sopenharmony_ci * realview smp platform. 1362306a36Sopenharmony_ci * * Copyright (c) 2002 ARM Limited. 1462306a36Sopenharmony_ci */ 1562306a36Sopenharmony_ci#include <linux/init.h> 1662306a36Sopenharmony_ci#include <linux/device.h> 1762306a36Sopenharmony_ci#include <linux/smp.h> 1862306a36Sopenharmony_ci#include <linux/io.h> 1962306a36Sopenharmony_ci#include <linux/irqchip/arm-gic.h> 2062306a36Sopenharmony_ci 2162306a36Sopenharmony_ci#include <asm/sections.h> 2262306a36Sopenharmony_ci#include <asm/smp_scu.h> 2362306a36Sopenharmony_ci#include <asm/virt.h> 2462306a36Sopenharmony_ci 2562306a36Sopenharmony_ci#include "omap-secure.h" 2662306a36Sopenharmony_ci#include "omap-wakeupgen.h" 2762306a36Sopenharmony_ci#include <asm/cputype.h> 2862306a36Sopenharmony_ci 2962306a36Sopenharmony_ci#include "soc.h" 3062306a36Sopenharmony_ci#include "iomap.h" 3162306a36Sopenharmony_ci#include "common.h" 3262306a36Sopenharmony_ci#include "clockdomain.h" 3362306a36Sopenharmony_ci#include "pm.h" 3462306a36Sopenharmony_ci 3562306a36Sopenharmony_ci#define CPU_MASK 0xff0ffff0 3662306a36Sopenharmony_ci#define CPU_CORTEX_A9 0x410FC090 3762306a36Sopenharmony_ci#define CPU_CORTEX_A15 0x410FC0F0 3862306a36Sopenharmony_ci 3962306a36Sopenharmony_ci#define OMAP5_CORE_COUNT 0x2 4062306a36Sopenharmony_ci 4162306a36Sopenharmony_ci#define AUX_CORE_BOOT0_GP_RELEASE 0x020 4262306a36Sopenharmony_ci#define AUX_CORE_BOOT0_HS_RELEASE 0x200 4362306a36Sopenharmony_ci 4462306a36Sopenharmony_cistruct omap_smp_config { 4562306a36Sopenharmony_ci unsigned long cpu1_rstctrl_pa; 4662306a36Sopenharmony_ci void __iomem *cpu1_rstctrl_va; 4762306a36Sopenharmony_ci void __iomem *scu_base; 4862306a36Sopenharmony_ci void __iomem *wakeupgen_base; 4962306a36Sopenharmony_ci void *startup_addr; 5062306a36Sopenharmony_ci}; 5162306a36Sopenharmony_ci 5262306a36Sopenharmony_cistatic struct omap_smp_config cfg; 5362306a36Sopenharmony_ci 5462306a36Sopenharmony_cistatic const struct omap_smp_config omap443x_cfg __initconst = { 5562306a36Sopenharmony_ci .cpu1_rstctrl_pa = 0x4824380c, 5662306a36Sopenharmony_ci .startup_addr = omap4_secondary_startup, 5762306a36Sopenharmony_ci}; 5862306a36Sopenharmony_ci 5962306a36Sopenharmony_cistatic const struct omap_smp_config omap446x_cfg __initconst = { 6062306a36Sopenharmony_ci .cpu1_rstctrl_pa = 0x4824380c, 6162306a36Sopenharmony_ci .startup_addr = omap4460_secondary_startup, 6262306a36Sopenharmony_ci}; 6362306a36Sopenharmony_ci 6462306a36Sopenharmony_cistatic const struct omap_smp_config omap5_cfg __initconst = { 6562306a36Sopenharmony_ci .cpu1_rstctrl_pa = 0x48243810, 6662306a36Sopenharmony_ci .startup_addr = omap5_secondary_startup, 6762306a36Sopenharmony_ci}; 6862306a36Sopenharmony_ci 6962306a36Sopenharmony_civoid __iomem *omap4_get_scu_base(void) 7062306a36Sopenharmony_ci{ 7162306a36Sopenharmony_ci return cfg.scu_base; 7262306a36Sopenharmony_ci} 7362306a36Sopenharmony_ci 7462306a36Sopenharmony_ci#ifdef CONFIG_OMAP5_ERRATA_801819 7562306a36Sopenharmony_cistatic void omap5_erratum_workaround_801819(void) 7662306a36Sopenharmony_ci{ 7762306a36Sopenharmony_ci u32 acr, revidr; 7862306a36Sopenharmony_ci u32 acr_mask; 7962306a36Sopenharmony_ci 8062306a36Sopenharmony_ci /* REVIDR[3] indicates erratum fix available on silicon */ 8162306a36Sopenharmony_ci asm volatile ("mrc p15, 0, %0, c0, c0, 6" : "=r" (revidr)); 8262306a36Sopenharmony_ci if (revidr & (0x1 << 3)) 8362306a36Sopenharmony_ci return; 8462306a36Sopenharmony_ci 8562306a36Sopenharmony_ci asm volatile ("mrc p15, 0, %0, c1, c0, 1" : "=r" (acr)); 8662306a36Sopenharmony_ci /* 8762306a36Sopenharmony_ci * BIT(27) - Disables streaming. All write-allocate lines allocate in 8862306a36Sopenharmony_ci * the L1 or L2 cache. 8962306a36Sopenharmony_ci * BIT(25) - Disables streaming. All write-allocate lines allocate in 9062306a36Sopenharmony_ci * the L1 cache. 9162306a36Sopenharmony_ci */ 9262306a36Sopenharmony_ci acr_mask = (0x3 << 25) | (0x3 << 27); 9362306a36Sopenharmony_ci /* do we already have it done.. if yes, skip expensive smc */ 9462306a36Sopenharmony_ci if ((acr & acr_mask) == acr_mask) 9562306a36Sopenharmony_ci return; 9662306a36Sopenharmony_ci 9762306a36Sopenharmony_ci acr |= acr_mask; 9862306a36Sopenharmony_ci omap_smc1(OMAP5_DRA7_MON_SET_ACR_INDEX, acr); 9962306a36Sopenharmony_ci 10062306a36Sopenharmony_ci pr_debug("%s: ARM erratum workaround 801819 applied on CPU%d\n", 10162306a36Sopenharmony_ci __func__, smp_processor_id()); 10262306a36Sopenharmony_ci} 10362306a36Sopenharmony_ci#else 10462306a36Sopenharmony_cistatic inline void omap5_erratum_workaround_801819(void) { } 10562306a36Sopenharmony_ci#endif 10662306a36Sopenharmony_ci 10762306a36Sopenharmony_ci#ifdef CONFIG_HARDEN_BRANCH_PREDICTOR 10862306a36Sopenharmony_ci/* 10962306a36Sopenharmony_ci * Configure ACR and enable ACTLR[0] (Enable invalidates of BTB with 11062306a36Sopenharmony_ci * ICIALLU) to activate the workaround for secondary Core. 11162306a36Sopenharmony_ci * NOTE: it is assumed that the primary core's configuration is done 11262306a36Sopenharmony_ci * by the boot loader (kernel will detect a misconfiguration and complain 11362306a36Sopenharmony_ci * if this is not done). 11462306a36Sopenharmony_ci * 11562306a36Sopenharmony_ci * In General Purpose(GP) devices, ACR bit settings can only be done 11662306a36Sopenharmony_ci * by ROM code in "secure world" using the smc call and there is no 11762306a36Sopenharmony_ci * option to update the "firmware" on such devices. This also works for 11862306a36Sopenharmony_ci * High security(HS) devices, as a backup option in case the 11962306a36Sopenharmony_ci * "update" is not done in the "security firmware". 12062306a36Sopenharmony_ci */ 12162306a36Sopenharmony_cistatic void omap5_secondary_harden_predictor(void) 12262306a36Sopenharmony_ci{ 12362306a36Sopenharmony_ci u32 acr, acr_mask; 12462306a36Sopenharmony_ci 12562306a36Sopenharmony_ci asm volatile ("mrc p15, 0, %0, c1, c0, 1" : "=r" (acr)); 12662306a36Sopenharmony_ci 12762306a36Sopenharmony_ci /* 12862306a36Sopenharmony_ci * ACTLR[0] (Enable invalidates of BTB with ICIALLU) 12962306a36Sopenharmony_ci */ 13062306a36Sopenharmony_ci acr_mask = BIT(0); 13162306a36Sopenharmony_ci 13262306a36Sopenharmony_ci /* Do we already have it done.. if yes, skip expensive smc */ 13362306a36Sopenharmony_ci if ((acr & acr_mask) == acr_mask) 13462306a36Sopenharmony_ci return; 13562306a36Sopenharmony_ci 13662306a36Sopenharmony_ci acr |= acr_mask; 13762306a36Sopenharmony_ci omap_smc1(OMAP5_DRA7_MON_SET_ACR_INDEX, acr); 13862306a36Sopenharmony_ci 13962306a36Sopenharmony_ci pr_debug("%s: ARM ACR setup for CVE_2017_5715 applied on CPU%d\n", 14062306a36Sopenharmony_ci __func__, smp_processor_id()); 14162306a36Sopenharmony_ci} 14262306a36Sopenharmony_ci#else 14362306a36Sopenharmony_cistatic inline void omap5_secondary_harden_predictor(void) { } 14462306a36Sopenharmony_ci#endif 14562306a36Sopenharmony_ci 14662306a36Sopenharmony_cistatic void omap4_secondary_init(unsigned int cpu) 14762306a36Sopenharmony_ci{ 14862306a36Sopenharmony_ci /* 14962306a36Sopenharmony_ci * Configure ACTRL and enable NS SMP bit access on CPU1 on HS device. 15062306a36Sopenharmony_ci * OMAP44XX EMU/HS devices - CPU0 SMP bit access is enabled in PPA 15162306a36Sopenharmony_ci * init and for CPU1, a secure PPA API provided. CPU0 must be ON 15262306a36Sopenharmony_ci * while executing NS_SMP API on CPU1 and PPA version must be 1.4.0+. 15362306a36Sopenharmony_ci * OMAP443X GP devices- SMP bit isn't accessible. 15462306a36Sopenharmony_ci * OMAP446X GP devices - SMP bit access is enabled on both CPUs. 15562306a36Sopenharmony_ci */ 15662306a36Sopenharmony_ci if (soc_is_omap443x() && (omap_type() != OMAP2_DEVICE_TYPE_GP)) 15762306a36Sopenharmony_ci omap_secure_dispatcher(OMAP4_PPA_CPU_ACTRL_SMP_INDEX, 15862306a36Sopenharmony_ci 4, 0, 0, 0, 0, 0); 15962306a36Sopenharmony_ci 16062306a36Sopenharmony_ci if (soc_is_omap54xx() || soc_is_dra7xx()) { 16162306a36Sopenharmony_ci /* 16262306a36Sopenharmony_ci * Configure the CNTFRQ register for the secondary cpu's which 16362306a36Sopenharmony_ci * indicates the frequency of the cpu local timers. 16462306a36Sopenharmony_ci */ 16562306a36Sopenharmony_ci set_cntfreq(); 16662306a36Sopenharmony_ci /* Configure ACR to disable streaming WA for 801819 */ 16762306a36Sopenharmony_ci omap5_erratum_workaround_801819(); 16862306a36Sopenharmony_ci /* Enable ACR to allow for ICUALLU workaround */ 16962306a36Sopenharmony_ci omap5_secondary_harden_predictor(); 17062306a36Sopenharmony_ci } 17162306a36Sopenharmony_ci} 17262306a36Sopenharmony_ci 17362306a36Sopenharmony_cistatic int omap4_boot_secondary(unsigned int cpu, struct task_struct *idle) 17462306a36Sopenharmony_ci{ 17562306a36Sopenharmony_ci static struct clockdomain *cpu1_clkdm; 17662306a36Sopenharmony_ci static bool booted; 17762306a36Sopenharmony_ci static struct powerdomain *cpu1_pwrdm; 17862306a36Sopenharmony_ci 17962306a36Sopenharmony_ci /* 18062306a36Sopenharmony_ci * Update the AuxCoreBoot0 with boot state for secondary core. 18162306a36Sopenharmony_ci * omap4_secondary_startup() routine will hold the secondary core till 18262306a36Sopenharmony_ci * the AuxCoreBoot1 register is updated with cpu state 18362306a36Sopenharmony_ci * A barrier is added to ensure that write buffer is drained 18462306a36Sopenharmony_ci */ 18562306a36Sopenharmony_ci if (omap_secure_apis_support()) 18662306a36Sopenharmony_ci omap_modify_auxcoreboot0(AUX_CORE_BOOT0_HS_RELEASE, 18762306a36Sopenharmony_ci 0xfffffdff); 18862306a36Sopenharmony_ci else 18962306a36Sopenharmony_ci writel_relaxed(AUX_CORE_BOOT0_GP_RELEASE, 19062306a36Sopenharmony_ci cfg.wakeupgen_base + OMAP_AUX_CORE_BOOT_0); 19162306a36Sopenharmony_ci 19262306a36Sopenharmony_ci if (!cpu1_clkdm && !cpu1_pwrdm) { 19362306a36Sopenharmony_ci cpu1_clkdm = clkdm_lookup("mpu1_clkdm"); 19462306a36Sopenharmony_ci cpu1_pwrdm = pwrdm_lookup("cpu1_pwrdm"); 19562306a36Sopenharmony_ci } 19662306a36Sopenharmony_ci 19762306a36Sopenharmony_ci /* 19862306a36Sopenharmony_ci * The SGI(Software Generated Interrupts) are not wakeup capable 19962306a36Sopenharmony_ci * from low power states. This is known limitation on OMAP4 and 20062306a36Sopenharmony_ci * needs to be worked around by using software forced clockdomain 20162306a36Sopenharmony_ci * wake-up. To wakeup CPU1, CPU0 forces the CPU1 clockdomain to 20262306a36Sopenharmony_ci * software force wakeup. The clockdomain is then put back to 20362306a36Sopenharmony_ci * hardware supervised mode. 20462306a36Sopenharmony_ci * More details can be found in OMAP4430 TRM - Version J 20562306a36Sopenharmony_ci * Section : 20662306a36Sopenharmony_ci * 4.3.4.2 Power States of CPU0 and CPU1 20762306a36Sopenharmony_ci */ 20862306a36Sopenharmony_ci if (booted && cpu1_pwrdm && cpu1_clkdm) { 20962306a36Sopenharmony_ci /* 21062306a36Sopenharmony_ci * GIC distributor control register has changed between 21162306a36Sopenharmony_ci * CortexA9 r1pX and r2pX. The Control Register secure 21262306a36Sopenharmony_ci * banked version is now composed of 2 bits: 21362306a36Sopenharmony_ci * bit 0 == Secure Enable 21462306a36Sopenharmony_ci * bit 1 == Non-Secure Enable 21562306a36Sopenharmony_ci * The Non-Secure banked register has not changed 21662306a36Sopenharmony_ci * Because the ROM Code is based on the r1pX GIC, the CPU1 21762306a36Sopenharmony_ci * GIC restoration will cause a problem to CPU0 Non-Secure SW. 21862306a36Sopenharmony_ci * The workaround must be: 21962306a36Sopenharmony_ci * 1) Before doing the CPU1 wakeup, CPU0 must disable 22062306a36Sopenharmony_ci * the GIC distributor 22162306a36Sopenharmony_ci * 2) CPU1 must re-enable the GIC distributor on 22262306a36Sopenharmony_ci * it's wakeup path. 22362306a36Sopenharmony_ci */ 22462306a36Sopenharmony_ci if (IS_PM44XX_ERRATUM(PM_OMAP4_ROM_SMP_BOOT_ERRATUM_GICD)) { 22562306a36Sopenharmony_ci local_irq_disable(); 22662306a36Sopenharmony_ci gic_dist_disable(); 22762306a36Sopenharmony_ci } 22862306a36Sopenharmony_ci 22962306a36Sopenharmony_ci /* 23062306a36Sopenharmony_ci * Ensure that CPU power state is set to ON to avoid CPU 23162306a36Sopenharmony_ci * powerdomain transition on wfi 23262306a36Sopenharmony_ci */ 23362306a36Sopenharmony_ci clkdm_deny_idle_nolock(cpu1_clkdm); 23462306a36Sopenharmony_ci pwrdm_set_next_pwrst(cpu1_pwrdm, PWRDM_POWER_ON); 23562306a36Sopenharmony_ci clkdm_allow_idle_nolock(cpu1_clkdm); 23662306a36Sopenharmony_ci 23762306a36Sopenharmony_ci if (IS_PM44XX_ERRATUM(PM_OMAP4_ROM_SMP_BOOT_ERRATUM_GICD)) { 23862306a36Sopenharmony_ci while (gic_dist_disabled()) { 23962306a36Sopenharmony_ci udelay(1); 24062306a36Sopenharmony_ci cpu_relax(); 24162306a36Sopenharmony_ci } 24262306a36Sopenharmony_ci gic_timer_retrigger(); 24362306a36Sopenharmony_ci local_irq_enable(); 24462306a36Sopenharmony_ci } 24562306a36Sopenharmony_ci } else { 24662306a36Sopenharmony_ci dsb_sev(); 24762306a36Sopenharmony_ci booted = true; 24862306a36Sopenharmony_ci } 24962306a36Sopenharmony_ci 25062306a36Sopenharmony_ci arch_send_wakeup_ipi_mask(cpumask_of(cpu)); 25162306a36Sopenharmony_ci 25262306a36Sopenharmony_ci return 0; 25362306a36Sopenharmony_ci} 25462306a36Sopenharmony_ci 25562306a36Sopenharmony_ci/* 25662306a36Sopenharmony_ci * Initialise the CPU possible map early - this describes the CPUs 25762306a36Sopenharmony_ci * which may be present or become present in the system. 25862306a36Sopenharmony_ci */ 25962306a36Sopenharmony_cistatic void __init omap4_smp_init_cpus(void) 26062306a36Sopenharmony_ci{ 26162306a36Sopenharmony_ci unsigned int i = 0, ncores = 1, cpu_id; 26262306a36Sopenharmony_ci 26362306a36Sopenharmony_ci /* Use ARM cpuid check here, as SoC detection will not work so early */ 26462306a36Sopenharmony_ci cpu_id = read_cpuid_id() & CPU_MASK; 26562306a36Sopenharmony_ci if (cpu_id == CPU_CORTEX_A9) { 26662306a36Sopenharmony_ci /* 26762306a36Sopenharmony_ci * Currently we can't call ioremap here because 26862306a36Sopenharmony_ci * SoC detection won't work until after init_early. 26962306a36Sopenharmony_ci */ 27062306a36Sopenharmony_ci cfg.scu_base = OMAP2_L4_IO_ADDRESS(scu_a9_get_base()); 27162306a36Sopenharmony_ci BUG_ON(!cfg.scu_base); 27262306a36Sopenharmony_ci ncores = scu_get_core_count(cfg.scu_base); 27362306a36Sopenharmony_ci } else if (cpu_id == CPU_CORTEX_A15) { 27462306a36Sopenharmony_ci ncores = OMAP5_CORE_COUNT; 27562306a36Sopenharmony_ci } 27662306a36Sopenharmony_ci 27762306a36Sopenharmony_ci /* sanity check */ 27862306a36Sopenharmony_ci if (ncores > nr_cpu_ids) { 27962306a36Sopenharmony_ci pr_warn("SMP: %u cores greater than maximum (%u), clipping\n", 28062306a36Sopenharmony_ci ncores, nr_cpu_ids); 28162306a36Sopenharmony_ci ncores = nr_cpu_ids; 28262306a36Sopenharmony_ci } 28362306a36Sopenharmony_ci 28462306a36Sopenharmony_ci for (i = 0; i < ncores; i++) 28562306a36Sopenharmony_ci set_cpu_possible(i, true); 28662306a36Sopenharmony_ci} 28762306a36Sopenharmony_ci 28862306a36Sopenharmony_ci/* 28962306a36Sopenharmony_ci * For now, just make sure the start-up address is not within the booting 29062306a36Sopenharmony_ci * kernel space as that means we just overwrote whatever secondary_startup() 29162306a36Sopenharmony_ci * code there was. 29262306a36Sopenharmony_ci */ 29362306a36Sopenharmony_cistatic bool __init omap4_smp_cpu1_startup_valid(unsigned long addr) 29462306a36Sopenharmony_ci{ 29562306a36Sopenharmony_ci if ((addr >= __pa(PAGE_OFFSET)) && (addr <= __pa(__bss_start))) 29662306a36Sopenharmony_ci return false; 29762306a36Sopenharmony_ci 29862306a36Sopenharmony_ci return true; 29962306a36Sopenharmony_ci} 30062306a36Sopenharmony_ci 30162306a36Sopenharmony_ci/* 30262306a36Sopenharmony_ci * We may need to reset CPU1 before configuring, otherwise kexec boot can end 30362306a36Sopenharmony_ci * up trying to use old kernel startup address or suspend-resume will 30462306a36Sopenharmony_ci * occasionally fail to bring up CPU1 on 4430 if CPU1 fails to enter deeper 30562306a36Sopenharmony_ci * idle states. 30662306a36Sopenharmony_ci */ 30762306a36Sopenharmony_cistatic void __init omap4_smp_maybe_reset_cpu1(struct omap_smp_config *c) 30862306a36Sopenharmony_ci{ 30962306a36Sopenharmony_ci unsigned long cpu1_startup_pa, cpu1_ns_pa_addr; 31062306a36Sopenharmony_ci bool needs_reset = false; 31162306a36Sopenharmony_ci u32 released; 31262306a36Sopenharmony_ci 31362306a36Sopenharmony_ci if (omap_secure_apis_support()) 31462306a36Sopenharmony_ci released = omap_read_auxcoreboot0() & AUX_CORE_BOOT0_HS_RELEASE; 31562306a36Sopenharmony_ci else 31662306a36Sopenharmony_ci released = readl_relaxed(cfg.wakeupgen_base + 31762306a36Sopenharmony_ci OMAP_AUX_CORE_BOOT_0) & 31862306a36Sopenharmony_ci AUX_CORE_BOOT0_GP_RELEASE; 31962306a36Sopenharmony_ci if (released) { 32062306a36Sopenharmony_ci pr_warn("smp: CPU1 not parked?\n"); 32162306a36Sopenharmony_ci 32262306a36Sopenharmony_ci return; 32362306a36Sopenharmony_ci } 32462306a36Sopenharmony_ci 32562306a36Sopenharmony_ci cpu1_startup_pa = readl_relaxed(cfg.wakeupgen_base + 32662306a36Sopenharmony_ci OMAP_AUX_CORE_BOOT_1); 32762306a36Sopenharmony_ci 32862306a36Sopenharmony_ci /* Did the configured secondary_startup() get overwritten? */ 32962306a36Sopenharmony_ci if (!omap4_smp_cpu1_startup_valid(cpu1_startup_pa)) 33062306a36Sopenharmony_ci needs_reset = true; 33162306a36Sopenharmony_ci 33262306a36Sopenharmony_ci /* 33362306a36Sopenharmony_ci * If omap4 or 5 has NS_PA_ADDR configured, CPU1 may be in a 33462306a36Sopenharmony_ci * deeper idle state in WFI and will wake to an invalid address. 33562306a36Sopenharmony_ci */ 33662306a36Sopenharmony_ci if ((soc_is_omap44xx() || soc_is_omap54xx())) { 33762306a36Sopenharmony_ci cpu1_ns_pa_addr = omap4_get_cpu1_ns_pa_addr(); 33862306a36Sopenharmony_ci if (!omap4_smp_cpu1_startup_valid(cpu1_ns_pa_addr)) 33962306a36Sopenharmony_ci needs_reset = true; 34062306a36Sopenharmony_ci } else { 34162306a36Sopenharmony_ci cpu1_ns_pa_addr = 0; 34262306a36Sopenharmony_ci } 34362306a36Sopenharmony_ci 34462306a36Sopenharmony_ci if (!needs_reset || !c->cpu1_rstctrl_va) 34562306a36Sopenharmony_ci return; 34662306a36Sopenharmony_ci 34762306a36Sopenharmony_ci pr_info("smp: CPU1 parked within kernel, needs reset (0x%lx 0x%lx)\n", 34862306a36Sopenharmony_ci cpu1_startup_pa, cpu1_ns_pa_addr); 34962306a36Sopenharmony_ci 35062306a36Sopenharmony_ci writel_relaxed(1, c->cpu1_rstctrl_va); 35162306a36Sopenharmony_ci readl_relaxed(c->cpu1_rstctrl_va); 35262306a36Sopenharmony_ci writel_relaxed(0, c->cpu1_rstctrl_va); 35362306a36Sopenharmony_ci} 35462306a36Sopenharmony_ci 35562306a36Sopenharmony_cistatic void __init omap4_smp_prepare_cpus(unsigned int max_cpus) 35662306a36Sopenharmony_ci{ 35762306a36Sopenharmony_ci const struct omap_smp_config *c = NULL; 35862306a36Sopenharmony_ci 35962306a36Sopenharmony_ci if (soc_is_omap443x()) 36062306a36Sopenharmony_ci c = &omap443x_cfg; 36162306a36Sopenharmony_ci else if (soc_is_omap446x()) 36262306a36Sopenharmony_ci c = &omap446x_cfg; 36362306a36Sopenharmony_ci else if (soc_is_dra74x() || soc_is_omap54xx() || soc_is_dra76x()) 36462306a36Sopenharmony_ci c = &omap5_cfg; 36562306a36Sopenharmony_ci 36662306a36Sopenharmony_ci if (!c) { 36762306a36Sopenharmony_ci pr_err("%s Unknown SMP SoC?\n", __func__); 36862306a36Sopenharmony_ci return; 36962306a36Sopenharmony_ci } 37062306a36Sopenharmony_ci 37162306a36Sopenharmony_ci /* Must preserve cfg.scu_base set earlier */ 37262306a36Sopenharmony_ci cfg.cpu1_rstctrl_pa = c->cpu1_rstctrl_pa; 37362306a36Sopenharmony_ci cfg.startup_addr = c->startup_addr; 37462306a36Sopenharmony_ci cfg.wakeupgen_base = omap_get_wakeupgen_base(); 37562306a36Sopenharmony_ci 37662306a36Sopenharmony_ci if (soc_is_dra74x() || soc_is_omap54xx() || soc_is_dra76x()) { 37762306a36Sopenharmony_ci if ((__boot_cpu_mode & MODE_MASK) == HYP_MODE) 37862306a36Sopenharmony_ci cfg.startup_addr = omap5_secondary_hyp_startup; 37962306a36Sopenharmony_ci omap5_erratum_workaround_801819(); 38062306a36Sopenharmony_ci } 38162306a36Sopenharmony_ci 38262306a36Sopenharmony_ci cfg.cpu1_rstctrl_va = ioremap(cfg.cpu1_rstctrl_pa, 4); 38362306a36Sopenharmony_ci if (!cfg.cpu1_rstctrl_va) 38462306a36Sopenharmony_ci return; 38562306a36Sopenharmony_ci 38662306a36Sopenharmony_ci /* 38762306a36Sopenharmony_ci * Initialise the SCU and wake up the secondary core using 38862306a36Sopenharmony_ci * wakeup_secondary(). 38962306a36Sopenharmony_ci */ 39062306a36Sopenharmony_ci if (cfg.scu_base) 39162306a36Sopenharmony_ci scu_enable(cfg.scu_base); 39262306a36Sopenharmony_ci 39362306a36Sopenharmony_ci omap4_smp_maybe_reset_cpu1(&cfg); 39462306a36Sopenharmony_ci 39562306a36Sopenharmony_ci /* 39662306a36Sopenharmony_ci * Write the address of secondary startup routine into the 39762306a36Sopenharmony_ci * AuxCoreBoot1 where ROM code will jump and start executing 39862306a36Sopenharmony_ci * on secondary core once out of WFE 39962306a36Sopenharmony_ci * A barrier is added to ensure that write buffer is drained 40062306a36Sopenharmony_ci */ 40162306a36Sopenharmony_ci if (omap_secure_apis_support()) 40262306a36Sopenharmony_ci omap_auxcoreboot_addr(__pa_symbol(cfg.startup_addr)); 40362306a36Sopenharmony_ci else 40462306a36Sopenharmony_ci writel_relaxed(__pa_symbol(cfg.startup_addr), 40562306a36Sopenharmony_ci cfg.wakeupgen_base + OMAP_AUX_CORE_BOOT_1); 40662306a36Sopenharmony_ci} 40762306a36Sopenharmony_ci 40862306a36Sopenharmony_ciconst struct smp_operations omap4_smp_ops __initconst = { 40962306a36Sopenharmony_ci .smp_init_cpus = omap4_smp_init_cpus, 41062306a36Sopenharmony_ci .smp_prepare_cpus = omap4_smp_prepare_cpus, 41162306a36Sopenharmony_ci .smp_secondary_init = omap4_secondary_init, 41262306a36Sopenharmony_ci .smp_boot_secondary = omap4_boot_secondary, 41362306a36Sopenharmony_ci#ifdef CONFIG_HOTPLUG_CPU 41462306a36Sopenharmony_ci .cpu_die = omap4_cpu_die, 41562306a36Sopenharmony_ci .cpu_kill = omap4_cpu_kill, 41662306a36Sopenharmony_ci#endif 41762306a36Sopenharmony_ci}; 418