1 /* 2 * Copyright (C) 2014 Marvell Technology Group Ltd. 3 * 4 * Antoine Ténart <antoine.tenart@free-electrons.com> 5 * 6 * This program is free software; you can redistribute it and/or modify 7 * it under the terms of the GNU General Public License version 2 as 8 * published by the Free Software Foundation. 9 */ 10 11 #include <linux/io.h> 12 #include <linux/delay.h> 13 #include <linux/of.h> 14 #include <linux/of_address.h> 15 16 #include <asm/cacheflush.h> 17 #include <asm/cp15.h> 18 #include <asm/smp_plat.h> 19 #include <asm/smp_scu.h> 20 21 /* 22 * There are two reset registers, one with self-clearing (SC) 23 * reset and one with non-self-clearing reset (NON_SC). 24 */ 25 #define CPU_RESET_SC 0x00 26 #define CPU_RESET_NON_SC 0x20 27 28 #define RESET_VECT 0x00 29 #define SW_RESET_ADDR 0x94 30 31 extern u32 boot_inst; 32 33 static void __iomem *cpu_ctrl; 34 35 static inline void berlin_perform_reset_cpu(unsigned int cpu) 36 { 37 u32 val; 38 39 val = readl(cpu_ctrl + CPU_RESET_NON_SC); 40 val &= ~BIT(cpu_logical_map(cpu)); 41 writel(val, cpu_ctrl + CPU_RESET_NON_SC); 42 val |= BIT(cpu_logical_map(cpu)); 43 writel(val, cpu_ctrl + CPU_RESET_NON_SC); 44 } 45 46 static int berlin_boot_secondary(unsigned int cpu, struct task_struct *idle) 47 { 48 if (!cpu_ctrl) 49 return -EFAULT; 50 51 /* 52 * Reset the CPU, making it to execute the instruction in the reset 53 * exception vector. 54 */ 55 berlin_perform_reset_cpu(cpu); 56 57 return 0; 58 } 59 60 static void __init berlin_smp_prepare_cpus(unsigned int max_cpus) 61 { 62 struct device_node *np; 63 void __iomem *scu_base; 64 void __iomem *vectors_base; 65 66 np = of_find_compatible_node(NULL, NULL, "arm,cortex-a9-scu"); 67 scu_base = of_iomap(np, 0); 68 of_node_put(np); 69 if (!scu_base) 70 return; 71 72 np = of_find_compatible_node(NULL, NULL, "marvell,berlin-cpu-ctrl"); 73 cpu_ctrl = of_iomap(np, 0); 74 of_node_put(np); 75 if (!cpu_ctrl) 76 goto unmap_scu; 77 78 vectors_base = ioremap(CONFIG_VECTORS_BASE, SZ_32K); 79 if (!vectors_base) 80 goto unmap_scu; 81 82 scu_enable(scu_base); 83 flush_cache_all(); 84 85 /* 86 * Write the first instruction the CPU will execute after being reset 87 * in the reset exception vector. 88 */ 89 writel(boot_inst, vectors_base + RESET_VECT); 90 91 /* 92 * Write the secondary startup address into the SW reset address 93 * vector. This is used by boot_inst. 94 */ 95 writel(virt_to_phys(secondary_startup), vectors_base + SW_RESET_ADDR); 96 97 iounmap(vectors_base); 98 unmap_scu: 99 iounmap(scu_base); 100 } 101 102 #ifdef CONFIG_HOTPLUG_CPU 103 static void berlin_cpu_die(unsigned int cpu) 104 { 105 v7_exit_coherency_flush(louis); 106 while (1) 107 cpu_do_idle(); 108 } 109 110 static int berlin_cpu_kill(unsigned int cpu) 111 { 112 u32 val; 113 114 val = readl(cpu_ctrl + CPU_RESET_NON_SC); 115 val &= ~BIT(cpu_logical_map(cpu)); 116 writel(val, cpu_ctrl + CPU_RESET_NON_SC); 117 118 return 1; 119 } 120 #endif 121 122 static const struct smp_operations berlin_smp_ops __initconst = { 123 .smp_prepare_cpus = berlin_smp_prepare_cpus, 124 .smp_boot_secondary = berlin_boot_secondary, 125 #ifdef CONFIG_HOTPLUG_CPU 126 .cpu_die = berlin_cpu_die, 127 .cpu_kill = berlin_cpu_kill, 128 #endif 129 }; 130 CPU_METHOD_OF_DECLARE(berlin_smp, "marvell,berlin-smp", &berlin_smp_ops); 131