]>
Commit | Line | Data |
---|---|---|
d2912cb1 | 1 | // SPDX-License-Identifier: GPL-2.0-only |
af76e806 NA |
2 | /* |
3 | * Copyright (C) 2016 Neil Armstrong <narmstrong@baylibre.com> | |
4 | * Copyright (C) 2013 Ma Haijun <mahaijuns@gmail.com> | |
5 | * Copyright (C) 2002 ARM Ltd. | |
6 | * All Rights Reserved | |
af76e806 NA |
7 | */ |
8 | #include <linux/io.h> | |
9 | #include <linux/delay.h> | |
10 | #include <linux/of.h> | |
11 | #include <linux/of_address.h> | |
12 | ||
13 | #include <asm/cacheflush.h> | |
14 | #include <asm/cp15.h> | |
15 | #include <asm/smp_plat.h> | |
16 | #include <asm/smp_scu.h> | |
17 | ||
18 | extern void ox820_secondary_startup(void); | |
af76e806 NA |
19 | |
20 | static void __iomem *cpu_ctrl; | |
21 | static void __iomem *gic_cpu_ctrl; | |
22 | ||
23 | #define HOLDINGPEN_CPU_OFFSET 0xc8 | |
24 | #define HOLDINGPEN_LOCATION_OFFSET 0xc4 | |
25 | ||
26 | #define GIC_NCPU_OFFSET(cpu) (0x100 + (cpu)*0x100) | |
27 | #define GIC_CPU_CTRL 0x00 | |
28 | #define GIC_CPU_CTRL_ENABLE 1 | |
29 | ||
bd84dff0 MF |
30 | static int __init ox820_boot_secondary(unsigned int cpu, |
31 | struct task_struct *idle) | |
af76e806 NA |
32 | { |
33 | /* | |
34 | * Write the address of secondary startup into the | |
35 | * system-wide flags register. The BootMonitor waits | |
36 | * until it receives a soft interrupt, and then the | |
37 | * secondary CPU branches to this address. | |
38 | */ | |
39 | writel(virt_to_phys(ox820_secondary_startup), | |
40 | cpu_ctrl + HOLDINGPEN_LOCATION_OFFSET); | |
41 | ||
42 | writel(cpu, cpu_ctrl + HOLDINGPEN_CPU_OFFSET); | |
43 | ||
44 | /* | |
45 | * Enable GIC cpu interface in CPU Interface Control Register | |
46 | */ | |
47 | writel(GIC_CPU_CTRL_ENABLE, | |
48 | gic_cpu_ctrl + GIC_NCPU_OFFSET(cpu) + GIC_CPU_CTRL); | |
49 | ||
50 | /* | |
51 | * Send the secondary CPU a soft interrupt, thereby causing | |
52 | * the boot monitor to read the system wide flags register, | |
53 | * and branch to the address found there. | |
54 | */ | |
55 | arch_send_wakeup_ipi_mask(cpumask_of(cpu)); | |
56 | ||
57 | return 0; | |
58 | } | |
59 | ||
60 | static void __init ox820_smp_prepare_cpus(unsigned int max_cpus) | |
61 | { | |
62 | struct device_node *np; | |
63 | void __iomem *scu_base; | |
64 | ||
65 | np = of_find_compatible_node(NULL, NULL, "arm,arm11mp-scu"); | |
66 | scu_base = of_iomap(np, 0); | |
67 | of_node_put(np); | |
68 | if (!scu_base) | |
69 | return; | |
70 | ||
71 | /* Remap CPU Interrupt Interface Registers */ | |
72 | np = of_find_compatible_node(NULL, NULL, "arm,arm11mp-gic"); | |
73 | gic_cpu_ctrl = of_iomap(np, 1); | |
74 | of_node_put(np); | |
75 | if (!gic_cpu_ctrl) | |
76 | goto unmap_scu; | |
77 | ||
78 | np = of_find_compatible_node(NULL, NULL, "oxsemi,ox820-sys-ctrl"); | |
79 | cpu_ctrl = of_iomap(np, 0); | |
80 | of_node_put(np); | |
81 | if (!cpu_ctrl) | |
82 | goto unmap_scu; | |
83 | ||
84 | scu_enable(scu_base); | |
85 | flush_cache_all(); | |
86 | ||
87 | unmap_scu: | |
88 | iounmap(scu_base); | |
89 | } | |
90 | ||
91 | static const struct smp_operations ox820_smp_ops __initconst = { | |
92 | .smp_prepare_cpus = ox820_smp_prepare_cpus, | |
93 | .smp_boot_secondary = ox820_boot_secondary, | |
af76e806 NA |
94 | }; |
95 | ||
96 | CPU_METHOD_OF_DECLARE(ox820_smp, "oxsemi,ox820-smp", &ox820_smp_ops); |