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