162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * linux/arch/arm/mach-axxia/platsmp.c 462306a36Sopenharmony_ci * 562306a36Sopenharmony_ci * Copyright (C) 2012 LSI Corporation 662306a36Sopenharmony_ci */ 762306a36Sopenharmony_ci 862306a36Sopenharmony_ci#include <linux/init.h> 962306a36Sopenharmony_ci#include <linux/io.h> 1062306a36Sopenharmony_ci#include <linux/smp.h> 1162306a36Sopenharmony_ci#include <linux/of.h> 1262306a36Sopenharmony_ci#include <linux/of_address.h> 1362306a36Sopenharmony_ci#include <asm/cacheflush.h> 1462306a36Sopenharmony_ci 1562306a36Sopenharmony_ci/* Syscon register offsets for releasing cores from reset */ 1662306a36Sopenharmony_ci#define SC_CRIT_WRITE_KEY 0x1000 1762306a36Sopenharmony_ci#define SC_RST_CPU_HOLD 0x1010 1862306a36Sopenharmony_ci 1962306a36Sopenharmony_ci/* 2062306a36Sopenharmony_ci * Write the kernel entry point for secondary CPUs to the specified address 2162306a36Sopenharmony_ci */ 2262306a36Sopenharmony_cistatic void write_release_addr(u32 release_phys) 2362306a36Sopenharmony_ci{ 2462306a36Sopenharmony_ci u32 *virt = (u32 *) phys_to_virt(release_phys); 2562306a36Sopenharmony_ci writel_relaxed(__pa_symbol(secondary_startup), virt); 2662306a36Sopenharmony_ci /* Make sure this store is visible to other CPUs */ 2762306a36Sopenharmony_ci smp_wmb(); 2862306a36Sopenharmony_ci __cpuc_flush_dcache_area(virt, sizeof(u32)); 2962306a36Sopenharmony_ci} 3062306a36Sopenharmony_ci 3162306a36Sopenharmony_cistatic int axxia_boot_secondary(unsigned int cpu, struct task_struct *idle) 3262306a36Sopenharmony_ci{ 3362306a36Sopenharmony_ci struct device_node *syscon_np; 3462306a36Sopenharmony_ci void __iomem *syscon; 3562306a36Sopenharmony_ci u32 tmp; 3662306a36Sopenharmony_ci 3762306a36Sopenharmony_ci syscon_np = of_find_compatible_node(NULL, NULL, "lsi,axxia-syscon"); 3862306a36Sopenharmony_ci if (!syscon_np) 3962306a36Sopenharmony_ci return -ENOENT; 4062306a36Sopenharmony_ci 4162306a36Sopenharmony_ci syscon = of_iomap(syscon_np, 0); 4262306a36Sopenharmony_ci of_node_put(syscon_np); 4362306a36Sopenharmony_ci if (!syscon) 4462306a36Sopenharmony_ci return -ENOMEM; 4562306a36Sopenharmony_ci 4662306a36Sopenharmony_ci tmp = readl(syscon + SC_RST_CPU_HOLD); 4762306a36Sopenharmony_ci writel(0xab, syscon + SC_CRIT_WRITE_KEY); 4862306a36Sopenharmony_ci tmp &= ~(1 << cpu); 4962306a36Sopenharmony_ci writel(tmp, syscon + SC_RST_CPU_HOLD); 5062306a36Sopenharmony_ci 5162306a36Sopenharmony_ci return 0; 5262306a36Sopenharmony_ci} 5362306a36Sopenharmony_ci 5462306a36Sopenharmony_cistatic void __init axxia_smp_prepare_cpus(unsigned int max_cpus) 5562306a36Sopenharmony_ci{ 5662306a36Sopenharmony_ci int cpu_count = 0; 5762306a36Sopenharmony_ci int cpu; 5862306a36Sopenharmony_ci 5962306a36Sopenharmony_ci /* 6062306a36Sopenharmony_ci * Initialise the present map, which describes the set of CPUs actually 6162306a36Sopenharmony_ci * populated at the present time. 6262306a36Sopenharmony_ci */ 6362306a36Sopenharmony_ci for_each_possible_cpu(cpu) { 6462306a36Sopenharmony_ci struct device_node *np; 6562306a36Sopenharmony_ci u32 release_phys; 6662306a36Sopenharmony_ci 6762306a36Sopenharmony_ci np = of_get_cpu_node(cpu, NULL); 6862306a36Sopenharmony_ci if (!np) 6962306a36Sopenharmony_ci continue; 7062306a36Sopenharmony_ci if (of_property_read_u32(np, "cpu-release-addr", &release_phys)) 7162306a36Sopenharmony_ci continue; 7262306a36Sopenharmony_ci 7362306a36Sopenharmony_ci if (cpu_count < max_cpus) { 7462306a36Sopenharmony_ci set_cpu_present(cpu, true); 7562306a36Sopenharmony_ci cpu_count++; 7662306a36Sopenharmony_ci } 7762306a36Sopenharmony_ci 7862306a36Sopenharmony_ci if (release_phys != 0) 7962306a36Sopenharmony_ci write_release_addr(release_phys); 8062306a36Sopenharmony_ci } 8162306a36Sopenharmony_ci} 8262306a36Sopenharmony_ci 8362306a36Sopenharmony_cistatic const struct smp_operations axxia_smp_ops __initconst = { 8462306a36Sopenharmony_ci .smp_prepare_cpus = axxia_smp_prepare_cpus, 8562306a36Sopenharmony_ci .smp_boot_secondary = axxia_boot_secondary, 8662306a36Sopenharmony_ci}; 8762306a36Sopenharmony_ciCPU_METHOD_OF_DECLARE(axxia_smp, "lsi,syscon-release", &axxia_smp_ops); 88