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/smp_plat.h> 18#include <asm/smp_scu.h> 19 20#define CPU_RESET 0x00 21 22#define RESET_VECT 0x00 23#define SW_RESET_ADDR 0x94 24 25extern u32 boot_inst; 26 27static void __iomem *cpu_ctrl; 28 29static inline void berlin_perform_reset_cpu(unsigned int cpu) 30{ 31 u32 val; 32 33 val = readl(cpu_ctrl + CPU_RESET); 34 val |= BIT(cpu_logical_map(cpu)); 35 writel(val, cpu_ctrl + CPU_RESET); 36} 37 38static int berlin_boot_secondary(unsigned int cpu, struct task_struct *idle) 39{ 40 if (!cpu_ctrl) 41 return -EFAULT; 42 43 /* 44 * Reset the CPU, making it to execute the instruction in the reset 45 * exception vector. 46 */ 47 berlin_perform_reset_cpu(cpu); 48 49 return 0; 50} 51 52static void __init berlin_smp_prepare_cpus(unsigned int max_cpus) 53{ 54 struct device_node *np; 55 void __iomem *scu_base; 56 void __iomem *vectors_base; 57 58 np = of_find_compatible_node(NULL, NULL, "arm,cortex-a9-scu"); 59 scu_base = of_iomap(np, 0); 60 of_node_put(np); 61 if (!scu_base) 62 return; 63 64 np = of_find_compatible_node(NULL, NULL, "marvell,berlin-cpu-ctrl"); 65 cpu_ctrl = of_iomap(np, 0); 66 of_node_put(np); 67 if (!cpu_ctrl) 68 goto unmap_scu; 69 70 vectors_base = ioremap(CONFIG_VECTORS_BASE, SZ_32K); 71 if (!vectors_base) 72 goto unmap_scu; 73 74 scu_enable(scu_base); 75 flush_cache_all(); 76 77 /* 78 * Write the first instruction the CPU will execute after being reset 79 * in the reset exception vector. 80 */ 81 writel(boot_inst, vectors_base + RESET_VECT); 82 83 /* 84 * Write the secondary startup address into the SW reset address 85 * vector. This is used by boot_inst. 86 */ 87 writel(virt_to_phys(secondary_startup), vectors_base + SW_RESET_ADDR); 88 89 iounmap(vectors_base); 90unmap_scu: 91 iounmap(scu_base); 92} 93 94static struct smp_operations berlin_smp_ops __initdata = { 95 .smp_prepare_cpus = berlin_smp_prepare_cpus, 96 .smp_boot_secondary = berlin_boot_secondary, 97}; 98CPU_METHOD_OF_DECLARE(berlin_smp, "marvell,berlin-smp", &berlin_smp_ops); 99