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/memory.h> 19 #include <asm/smp_plat.h> 20 #include <asm/smp_scu.h> 21 22 /* 23 * There are two reset registers, one with self-clearing (SC) 24 * reset and one with non-self-clearing reset (NON_SC). 25 */ 26 #define CPU_RESET_SC 0x00 27 #define CPU_RESET_NON_SC 0x20 28 29 #define RESET_VECT 0x00 30 #define SW_RESET_ADDR 0x94 31 32 extern u32 boot_inst; 33 34 static void __iomem *cpu_ctrl; 35 36 static inline void berlin_perform_reset_cpu(unsigned int cpu) 37 { 38 u32 val; 39 40 val = readl(cpu_ctrl + CPU_RESET_NON_SC); 41 val &= ~BIT(cpu_logical_map(cpu)); 42 writel(val, cpu_ctrl + CPU_RESET_NON_SC); 43 val |= BIT(cpu_logical_map(cpu)); 44 writel(val, cpu_ctrl + CPU_RESET_NON_SC); 45 } 46 47 static int berlin_boot_secondary(unsigned int cpu, struct task_struct *idle) 48 { 49 if (!cpu_ctrl) 50 return -EFAULT; 51 52 /* 53 * Reset the CPU, making it to execute the instruction in the reset 54 * exception vector. 55 */ 56 berlin_perform_reset_cpu(cpu); 57 58 return 0; 59 } 60 61 static void __init berlin_smp_prepare_cpus(unsigned int max_cpus) 62 { 63 struct device_node *np; 64 void __iomem *scu_base; 65 void __iomem *vectors_base; 66 67 np = of_find_compatible_node(NULL, NULL, "arm,cortex-a9-scu"); 68 scu_base = of_iomap(np, 0); 69 of_node_put(np); 70 if (!scu_base) 71 return; 72 73 np = of_find_compatible_node(NULL, NULL, "marvell,berlin-cpu-ctrl"); 74 cpu_ctrl = of_iomap(np, 0); 75 of_node_put(np); 76 if (!cpu_ctrl) 77 goto unmap_scu; 78 79 vectors_base = ioremap(VECTORS_BASE, SZ_32K); 80 if (!vectors_base) 81 goto unmap_scu; 82 83 scu_enable(scu_base); 84 flush_cache_all(); 85 86 /* 87 * Write the first instruction the CPU will execute after being reset 88 * in the reset exception vector. 89 */ 90 writel(boot_inst, vectors_base + RESET_VECT); 91 92 /* 93 * Write the secondary startup address into the SW reset address 94 * vector. This is used by boot_inst. 95 */ 96 writel(__pa_symbol(secondary_startup), vectors_base + SW_RESET_ADDR); 97 98 iounmap(vectors_base); 99 unmap_scu: 100 iounmap(scu_base); 101 } 102 103 #ifdef CONFIG_HOTPLUG_CPU 104 static void berlin_cpu_die(unsigned int cpu) 105 { 106 v7_exit_coherency_flush(louis); 107 while (1) 108 cpu_do_idle(); 109 } 110 111 static int berlin_cpu_kill(unsigned int cpu) 112 { 113 u32 val; 114 115 val = readl(cpu_ctrl + CPU_RESET_NON_SC); 116 val &= ~BIT(cpu_logical_map(cpu)); 117 writel(val, cpu_ctrl + CPU_RESET_NON_SC); 118 119 return 1; 120 } 121 #endif 122 123 static const struct smp_operations berlin_smp_ops __initconst = { 124 .smp_prepare_cpus = berlin_smp_prepare_cpus, 125 .smp_boot_secondary = berlin_boot_secondary, 126 #ifdef CONFIG_HOTPLUG_CPU 127 .cpu_die = berlin_cpu_die, 128 .cpu_kill = berlin_cpu_kill, 129 #endif 130 }; 131 CPU_METHOD_OF_DECLARE(berlin_smp, "marvell,berlin-smp", &berlin_smp_ops); 132