Commit | Line | Data |
---|---|---|
7b7dfdd2 AT |
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 | ||
7b7dfdd2 AT |
25 | extern u32 boot_inst; |
26 | ||
27 | static void __iomem *cpu_ctrl; | |
28 | ||
29 | static 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 | ||
38 | static 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 | ||
52 | static 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 | */ | |
02b4e275 | 87 | writel(virt_to_phys(secondary_startup), vectors_base + SW_RESET_ADDR); |
7b7dfdd2 AT |
88 | |
89 | iounmap(vectors_base); | |
90 | unmap_scu: | |
91 | iounmap(scu_base); | |
92 | } | |
93 | ||
94 | static struct smp_operations berlin_smp_ops __initdata = { | |
95 | .smp_prepare_cpus = berlin_smp_prepare_cpus, | |
96 | .smp_boot_secondary = berlin_boot_secondary, | |
97 | }; | |
98 | CPU_METHOD_OF_DECLARE(berlin_smp, "marvell,berlin-smp", &berlin_smp_ops); |