1*1d22924eSAnders Berg /* 2*1d22924eSAnders Berg * linux/arch/arm/mach-axxia/platsmp.c 3*1d22924eSAnders Berg * 4*1d22924eSAnders Berg * Copyright (C) 2012 LSI Corporation 5*1d22924eSAnders Berg * 6*1d22924eSAnders Berg * This program is free software; you can redistribute it and/or modify 7*1d22924eSAnders Berg * it under the terms of the GNU General Public License version 2 as 8*1d22924eSAnders Berg * published by the Free Software Foundation. 9*1d22924eSAnders Berg */ 10*1d22924eSAnders Berg 11*1d22924eSAnders Berg #include <linux/init.h> 12*1d22924eSAnders Berg #include <linux/io.h> 13*1d22924eSAnders Berg #include <linux/smp.h> 14*1d22924eSAnders Berg #include <linux/of.h> 15*1d22924eSAnders Berg #include <linux/of_address.h> 16*1d22924eSAnders Berg #include <asm/cacheflush.h> 17*1d22924eSAnders Berg 18*1d22924eSAnders Berg /* Syscon register offsets for releasing cores from reset */ 19*1d22924eSAnders Berg #define SC_CRIT_WRITE_KEY 0x1000 20*1d22924eSAnders Berg #define SC_RST_CPU_HOLD 0x1010 21*1d22924eSAnders Berg 22*1d22924eSAnders Berg /* 23*1d22924eSAnders Berg * Write the kernel entry point for secondary CPUs to the specified address 24*1d22924eSAnders Berg */ 25*1d22924eSAnders Berg static void write_release_addr(u32 release_phys) 26*1d22924eSAnders Berg { 27*1d22924eSAnders Berg u32 *virt = (u32 *) phys_to_virt(release_phys); 28*1d22924eSAnders Berg writel_relaxed(virt_to_phys(secondary_startup), virt); 29*1d22924eSAnders Berg /* Make sure this store is visible to other CPUs */ 30*1d22924eSAnders Berg smp_wmb(); 31*1d22924eSAnders Berg __cpuc_flush_dcache_area(virt, sizeof(u32)); 32*1d22924eSAnders Berg } 33*1d22924eSAnders Berg 34*1d22924eSAnders Berg static int axxia_boot_secondary(unsigned int cpu, struct task_struct *idle) 35*1d22924eSAnders Berg { 36*1d22924eSAnders Berg struct device_node *syscon_np; 37*1d22924eSAnders Berg void __iomem *syscon; 38*1d22924eSAnders Berg u32 tmp; 39*1d22924eSAnders Berg 40*1d22924eSAnders Berg syscon_np = of_find_compatible_node(NULL, NULL, "lsi,axxia-syscon"); 41*1d22924eSAnders Berg if (!syscon_np) 42*1d22924eSAnders Berg return -ENOENT; 43*1d22924eSAnders Berg 44*1d22924eSAnders Berg syscon = of_iomap(syscon_np, 0); 45*1d22924eSAnders Berg if (!syscon) 46*1d22924eSAnders Berg return -ENOMEM; 47*1d22924eSAnders Berg 48*1d22924eSAnders Berg tmp = readl(syscon + SC_RST_CPU_HOLD); 49*1d22924eSAnders Berg writel(0xab, syscon + SC_CRIT_WRITE_KEY); 50*1d22924eSAnders Berg tmp &= ~(1 << cpu); 51*1d22924eSAnders Berg writel(tmp, syscon + SC_RST_CPU_HOLD); 52*1d22924eSAnders Berg 53*1d22924eSAnders Berg return 0; 54*1d22924eSAnders Berg } 55*1d22924eSAnders Berg 56*1d22924eSAnders Berg static void __init axxia_smp_prepare_cpus(unsigned int max_cpus) 57*1d22924eSAnders Berg { 58*1d22924eSAnders Berg int cpu_count = 0; 59*1d22924eSAnders Berg int cpu; 60*1d22924eSAnders Berg 61*1d22924eSAnders Berg /* 62*1d22924eSAnders Berg * Initialise the present map, which describes the set of CPUs actually 63*1d22924eSAnders Berg * populated at the present time. 64*1d22924eSAnders Berg */ 65*1d22924eSAnders Berg for_each_possible_cpu(cpu) { 66*1d22924eSAnders Berg struct device_node *np; 67*1d22924eSAnders Berg u32 release_phys; 68*1d22924eSAnders Berg 69*1d22924eSAnders Berg np = of_get_cpu_node(cpu, NULL); 70*1d22924eSAnders Berg if (!np) 71*1d22924eSAnders Berg continue; 72*1d22924eSAnders Berg if (of_property_read_u32(np, "cpu-release-addr", &release_phys)) 73*1d22924eSAnders Berg continue; 74*1d22924eSAnders Berg 75*1d22924eSAnders Berg if (cpu_count < max_cpus) { 76*1d22924eSAnders Berg set_cpu_present(cpu, true); 77*1d22924eSAnders Berg cpu_count++; 78*1d22924eSAnders Berg } 79*1d22924eSAnders Berg 80*1d22924eSAnders Berg if (release_phys != 0) 81*1d22924eSAnders Berg write_release_addr(release_phys); 82*1d22924eSAnders Berg } 83*1d22924eSAnders Berg } 84*1d22924eSAnders Berg 85*1d22924eSAnders Berg static struct smp_operations axxia_smp_ops __initdata = { 86*1d22924eSAnders Berg .smp_prepare_cpus = axxia_smp_prepare_cpus, 87*1d22924eSAnders Berg .smp_boot_secondary = axxia_boot_secondary, 88*1d22924eSAnders Berg }; 89*1d22924eSAnders Berg CPU_METHOD_OF_DECLARE(axxia_smp, "lsi,syscon-release", &axxia_smp_ops); 90