platsmp.c (2461B)
1// SPDX-License-Identifier: GPL-2.0-only 2/* 3 * Copyright (C) 2016 Neil Armstrong <narmstrong@baylibre.com> 4 * Copyright (C) 2013 Ma Haijun <mahaijuns@gmail.com> 5 * Copyright (C) 2002 ARM Ltd. 6 * All Rights Reserved 7 */ 8#include <linux/io.h> 9#include <linux/delay.h> 10#include <linux/of.h> 11#include <linux/of_address.h> 12 13#include <asm/cacheflush.h> 14#include <asm/cp15.h> 15#include <asm/smp_plat.h> 16#include <asm/smp_scu.h> 17 18extern void ox820_secondary_startup(void); 19 20static void __iomem *cpu_ctrl; 21static void __iomem *gic_cpu_ctrl; 22 23#define HOLDINGPEN_CPU_OFFSET 0xc8 24#define HOLDINGPEN_LOCATION_OFFSET 0xc4 25 26#define GIC_NCPU_OFFSET(cpu) (0x100 + (cpu)*0x100) 27#define GIC_CPU_CTRL 0x00 28#define GIC_CPU_CTRL_ENABLE 1 29 30static int __init ox820_boot_secondary(unsigned int cpu, 31 struct task_struct *idle) 32{ 33 /* 34 * Write the address of secondary startup into the 35 * system-wide flags register. The BootMonitor waits 36 * until it receives a soft interrupt, and then the 37 * secondary CPU branches to this address. 38 */ 39 writel(virt_to_phys(ox820_secondary_startup), 40 cpu_ctrl + HOLDINGPEN_LOCATION_OFFSET); 41 42 writel(cpu, cpu_ctrl + HOLDINGPEN_CPU_OFFSET); 43 44 /* 45 * Enable GIC cpu interface in CPU Interface Control Register 46 */ 47 writel(GIC_CPU_CTRL_ENABLE, 48 gic_cpu_ctrl + GIC_NCPU_OFFSET(cpu) + GIC_CPU_CTRL); 49 50 /* 51 * Send the secondary CPU a soft interrupt, thereby causing 52 * the boot monitor to read the system wide flags register, 53 * and branch to the address found there. 54 */ 55 arch_send_wakeup_ipi_mask(cpumask_of(cpu)); 56 57 return 0; 58} 59 60static void __init ox820_smp_prepare_cpus(unsigned int max_cpus) 61{ 62 struct device_node *np; 63 void __iomem *scu_base; 64 65 np = of_find_compatible_node(NULL, NULL, "arm,arm11mp-scu"); 66 scu_base = of_iomap(np, 0); 67 of_node_put(np); 68 if (!scu_base) 69 return; 70 71 /* Remap CPU Interrupt Interface Registers */ 72 np = of_find_compatible_node(NULL, NULL, "arm,arm11mp-gic"); 73 gic_cpu_ctrl = of_iomap(np, 1); 74 of_node_put(np); 75 if (!gic_cpu_ctrl) 76 goto unmap_scu; 77 78 np = of_find_compatible_node(NULL, NULL, "oxsemi,ox820-sys-ctrl"); 79 cpu_ctrl = of_iomap(np, 0); 80 of_node_put(np); 81 if (!cpu_ctrl) 82 goto unmap_scu; 83 84 scu_enable(scu_base); 85 flush_cache_all(); 86 87unmap_scu: 88 iounmap(scu_base); 89} 90 91static const struct smp_operations ox820_smp_ops __initconst = { 92 .smp_prepare_cpus = ox820_smp_prepare_cpus, 93 .smp_boot_secondary = ox820_boot_secondary, 94}; 95 96CPU_METHOD_OF_DECLARE(ox820_smp, "oxsemi,ox820-smp", &ox820_smp_ops);