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 31extern u32 boot_inst; 32 33static void __iomem *cpu_ctrl; 34 35static 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 46static 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 60static 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); 98unmap_scu: 99 iounmap(scu_base); 100} 101 102#ifdef CONFIG_HOTPLUG_CPU 103static void berlin_cpu_die(unsigned int cpu) 104{ 105 v7_exit_coherency_flush(louis); 106 while (1) 107 cpu_do_idle(); 108} 109 110static 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 122static struct smp_operations berlin_smp_ops __initdata = { 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}; 130CPU_METHOD_OF_DECLARE(berlin_smp, "marvell,berlin-smp", &berlin_smp_ops); 131