diff options
-rw-r--r-- | arch/arm/mach-shmobile/Makefile | 1 | ||||
-rw-r--r-- | arch/arm/mach-shmobile/board-ape6evm-reference.c | 2 | ||||
-rw-r--r-- | arch/arm/mach-shmobile/board-ape6evm.c | 2 | ||||
-rw-r--r-- | arch/arm/mach-shmobile/board-lager-reference.c | 3 | ||||
-rw-r--r-- | arch/arm/mach-shmobile/board-lager.c | 3 | ||||
-rw-r--r-- | arch/arm/mach-shmobile/headsmp.S | 3 | ||||
-rw-r--r-- | arch/arm/mach-shmobile/include/mach/common.h | 12 | ||||
-rw-r--r-- | arch/arm/mach-shmobile/include/mach/r8a73a4.h | 2 | ||||
-rw-r--r-- | arch/arm/mach-shmobile/include/mach/r8a7790.h | 3 | ||||
-rw-r--r-- | arch/arm/mach-shmobile/platsmp-apmu.c | 195 | ||||
-rw-r--r-- | arch/arm/mach-shmobile/platsmp-scu.c | 30 | ||||
-rw-r--r-- | arch/arm/mach-shmobile/platsmp.c | 22 | ||||
-rw-r--r-- | arch/arm/mach-shmobile/setup-r8a73a4.c | 4 | ||||
-rw-r--r-- | arch/arm/mach-shmobile/setup-r8a7790.c | 26 | ||||
-rw-r--r-- | arch/arm/mach-shmobile/smp-emev2.c | 6 | ||||
-rw-r--r-- | arch/arm/mach-shmobile/smp-r8a7779.c | 4 | ||||
-rw-r--r-- | arch/arm/mach-shmobile/smp-r8a7790.c | 67 | ||||
-rw-r--r-- | arch/arm/mach-shmobile/smp-sh73a0.c | 14 |
18 files changed, 331 insertions, 68 deletions
diff --git a/arch/arm/mach-shmobile/Makefile b/arch/arm/mach-shmobile/Makefile index 228193cc9a38..d30ec1a427ec 100644 --- a/arch/arm/mach-shmobile/Makefile +++ b/arch/arm/mach-shmobile/Makefile | |||
@@ -36,6 +36,7 @@ endif | |||
36 | smp-y := platsmp.o headsmp.o | 36 | smp-y := platsmp.o headsmp.o |
37 | smp-$(CONFIG_ARCH_SH73A0) += smp-sh73a0.o headsmp-scu.o platsmp-scu.o | 37 | smp-$(CONFIG_ARCH_SH73A0) += smp-sh73a0.o headsmp-scu.o platsmp-scu.o |
38 | smp-$(CONFIG_ARCH_R8A7779) += smp-r8a7779.o headsmp-scu.o platsmp-scu.o | 38 | smp-$(CONFIG_ARCH_R8A7779) += smp-r8a7779.o headsmp-scu.o platsmp-scu.o |
39 | smp-$(CONFIG_ARCH_R8A7790) += smp-r8a7790.o platsmp-apmu.o | ||
39 | smp-$(CONFIG_ARCH_EMEV2) += smp-emev2.o headsmp-scu.o platsmp-scu.o | 40 | smp-$(CONFIG_ARCH_EMEV2) += smp-emev2.o headsmp-scu.o platsmp-scu.o |
40 | 41 | ||
41 | # IRQ objects | 42 | # IRQ objects |
diff --git a/arch/arm/mach-shmobile/board-ape6evm-reference.c b/arch/arm/mach-shmobile/board-ape6evm-reference.c index a23fa714f7ac..3276afcf3cc9 100644 --- a/arch/arm/mach-shmobile/board-ape6evm-reference.c +++ b/arch/arm/mach-shmobile/board-ape6evm-reference.c | |||
@@ -57,7 +57,7 @@ static const char *ape6evm_boards_compat_dt[] __initdata = { | |||
57 | }; | 57 | }; |
58 | 58 | ||
59 | DT_MACHINE_START(APE6EVM_DT, "ape6evm") | 59 | DT_MACHINE_START(APE6EVM_DT, "ape6evm") |
60 | .init_early = r8a73a4_init_delay, | 60 | .init_early = r8a73a4_init_early, |
61 | .init_machine = ape6evm_add_standard_devices, | 61 | .init_machine = ape6evm_add_standard_devices, |
62 | .dt_compat = ape6evm_boards_compat_dt, | 62 | .dt_compat = ape6evm_boards_compat_dt, |
63 | MACHINE_END | 63 | MACHINE_END |
diff --git a/arch/arm/mach-shmobile/board-ape6evm.c b/arch/arm/mach-shmobile/board-ape6evm.c index 24b87eea9da3..d36e23f5d8b7 100644 --- a/arch/arm/mach-shmobile/board-ape6evm.c +++ b/arch/arm/mach-shmobile/board-ape6evm.c | |||
@@ -240,7 +240,7 @@ static const char *ape6evm_boards_compat_dt[] __initdata = { | |||
240 | }; | 240 | }; |
241 | 241 | ||
242 | DT_MACHINE_START(APE6EVM_DT, "ape6evm") | 242 | DT_MACHINE_START(APE6EVM_DT, "ape6evm") |
243 | .init_early = r8a73a4_init_delay, | 243 | .init_early = r8a73a4_init_early, |
244 | .init_machine = ape6evm_add_standard_devices, | 244 | .init_machine = ape6evm_add_standard_devices, |
245 | .dt_compat = ape6evm_boards_compat_dt, | 245 | .dt_compat = ape6evm_boards_compat_dt, |
246 | MACHINE_END | 246 | MACHINE_END |
diff --git a/arch/arm/mach-shmobile/board-lager-reference.c b/arch/arm/mach-shmobile/board-lager-reference.c index 9c316a1b2e32..d39a91b3ba48 100644 --- a/arch/arm/mach-shmobile/board-lager-reference.c +++ b/arch/arm/mach-shmobile/board-lager-reference.c | |||
@@ -38,7 +38,8 @@ static const char *lager_boards_compat_dt[] __initdata = { | |||
38 | }; | 38 | }; |
39 | 39 | ||
40 | DT_MACHINE_START(LAGER_DT, "lager") | 40 | DT_MACHINE_START(LAGER_DT, "lager") |
41 | .init_early = r8a7790_init_delay, | 41 | .smp = smp_ops(r8a7790_smp_ops), |
42 | .init_early = r8a7790_init_early, | ||
42 | .init_machine = lager_add_standard_devices, | 43 | .init_machine = lager_add_standard_devices, |
43 | .init_time = r8a7790_timer_init, | 44 | .init_time = r8a7790_timer_init, |
44 | .dt_compat = lager_boards_compat_dt, | 45 | .dt_compat = lager_boards_compat_dt, |
diff --git a/arch/arm/mach-shmobile/board-lager.c b/arch/arm/mach-shmobile/board-lager.c index ffb6f0ac7606..ef3baaa79e6d 100644 --- a/arch/arm/mach-shmobile/board-lager.c +++ b/arch/arm/mach-shmobile/board-lager.c | |||
@@ -161,7 +161,8 @@ static const char *lager_boards_compat_dt[] __initdata = { | |||
161 | }; | 161 | }; |
162 | 162 | ||
163 | DT_MACHINE_START(LAGER_DT, "lager") | 163 | DT_MACHINE_START(LAGER_DT, "lager") |
164 | .init_early = r8a7790_init_delay, | 164 | .smp = smp_ops(r8a7790_smp_ops), |
165 | .init_early = r8a7790_init_early, | ||
165 | .init_time = r8a7790_timer_init, | 166 | .init_time = r8a7790_timer_init, |
166 | .init_machine = lager_add_standard_devices, | 167 | .init_machine = lager_add_standard_devices, |
167 | .dt_compat = lager_boards_compat_dt, | 168 | .dt_compat = lager_boards_compat_dt, |
diff --git a/arch/arm/mach-shmobile/headsmp.S b/arch/arm/mach-shmobile/headsmp.S index f93751caf5cb..e5be5c88644b 100644 --- a/arch/arm/mach-shmobile/headsmp.S +++ b/arch/arm/mach-shmobile/headsmp.S | |||
@@ -40,6 +40,9 @@ shmobile_boot_fn: | |||
40 | .globl shmobile_boot_arg | 40 | .globl shmobile_boot_arg |
41 | shmobile_boot_arg: | 41 | shmobile_boot_arg: |
42 | 2: .space 4 | 42 | 2: .space 4 |
43 | .globl shmobile_boot_size | ||
44 | shmobile_boot_size: | ||
45 | .long . - shmobile_boot_vector | ||
43 | 46 | ||
44 | /* | 47 | /* |
45 | * Per-CPU SMP boot function/argument selection code based on MPIDR | 48 | * Per-CPU SMP boot function/argument selection code based on MPIDR |
diff --git a/arch/arm/mach-shmobile/include/mach/common.h b/arch/arm/mach-shmobile/include/mach/common.h index 7b938681e756..e31980590eb4 100644 --- a/arch/arm/mach-shmobile/include/mach/common.h +++ b/arch/arm/mach-shmobile/include/mach/common.h | |||
@@ -9,16 +9,23 @@ extern void shmobile_setup_console(void); | |||
9 | extern void shmobile_boot_vector(void); | 9 | extern void shmobile_boot_vector(void); |
10 | extern unsigned long shmobile_boot_fn; | 10 | extern unsigned long shmobile_boot_fn; |
11 | extern unsigned long shmobile_boot_arg; | 11 | extern unsigned long shmobile_boot_arg; |
12 | extern unsigned long shmobile_boot_size; | ||
12 | extern void shmobile_smp_boot(void); | 13 | extern void shmobile_smp_boot(void); |
13 | extern void shmobile_smp_sleep(void); | 14 | extern void shmobile_smp_sleep(void); |
14 | extern void shmobile_smp_hook(unsigned int cpu, unsigned long fn, | 15 | extern void shmobile_smp_hook(unsigned int cpu, unsigned long fn, |
15 | unsigned long arg); | 16 | unsigned long arg); |
17 | extern int shmobile_smp_cpu_disable(unsigned int cpu); | ||
18 | extern void shmobile_invalidate_start(void); | ||
16 | extern void shmobile_boot_scu(void); | 19 | extern void shmobile_boot_scu(void); |
17 | extern void shmobile_smp_scu_prepare_cpus(unsigned int max_cpus); | 20 | extern void shmobile_smp_scu_prepare_cpus(unsigned int max_cpus); |
18 | extern int shmobile_smp_scu_boot_secondary(unsigned int cpu, | ||
19 | struct task_struct *idle); | ||
20 | extern void shmobile_smp_scu_cpu_die(unsigned int cpu); | 21 | extern void shmobile_smp_scu_cpu_die(unsigned int cpu); |
21 | extern int shmobile_smp_scu_cpu_kill(unsigned int cpu); | 22 | extern int shmobile_smp_scu_cpu_kill(unsigned int cpu); |
23 | extern void shmobile_smp_apmu_prepare_cpus(unsigned int max_cpus); | ||
24 | extern int shmobile_smp_apmu_boot_secondary(unsigned int cpu, | ||
25 | struct task_struct *idle); | ||
26 | extern void shmobile_smp_apmu_cpu_die(unsigned int cpu); | ||
27 | extern int shmobile_smp_apmu_cpu_kill(unsigned int cpu); | ||
28 | extern void shmobile_invalidate_start(void); | ||
22 | struct clk; | 29 | struct clk; |
23 | extern int shmobile_clk_init(void); | 30 | extern int shmobile_clk_init(void); |
24 | extern void shmobile_handle_irq_intc(struct pt_regs *); | 31 | extern void shmobile_handle_irq_intc(struct pt_regs *); |
@@ -39,7 +46,6 @@ static inline int shmobile_cpuidle_init(void) { return 0; } | |||
39 | #endif | 46 | #endif |
40 | 47 | ||
41 | extern void __iomem *shmobile_scu_base; | 48 | extern void __iomem *shmobile_scu_base; |
42 | extern void shmobile_smp_init_cpus(unsigned int ncores); | ||
43 | 49 | ||
44 | static inline void __init shmobile_init_late(void) | 50 | static inline void __init shmobile_init_late(void) |
45 | { | 51 | { |
diff --git a/arch/arm/mach-shmobile/include/mach/r8a73a4.h b/arch/arm/mach-shmobile/include/mach/r8a73a4.h index f3a9b702da56..5214338a6a47 100644 --- a/arch/arm/mach-shmobile/include/mach/r8a73a4.h +++ b/arch/arm/mach-shmobile/include/mach/r8a73a4.h | |||
@@ -5,6 +5,6 @@ void r8a73a4_add_standard_devices(void); | |||
5 | void r8a73a4_add_dt_devices(void); | 5 | void r8a73a4_add_dt_devices(void); |
6 | void r8a73a4_clock_init(void); | 6 | void r8a73a4_clock_init(void); |
7 | void r8a73a4_pinmux_init(void); | 7 | void r8a73a4_pinmux_init(void); |
8 | void r8a73a4_init_delay(void); | 8 | void r8a73a4_init_early(void); |
9 | 9 | ||
10 | #endif /* __ASM_R8A73A4_H__ */ | 10 | #endif /* __ASM_R8A73A4_H__ */ |
diff --git a/arch/arm/mach-shmobile/include/mach/r8a7790.h b/arch/arm/mach-shmobile/include/mach/r8a7790.h index 788d55952091..79e731c83e50 100644 --- a/arch/arm/mach-shmobile/include/mach/r8a7790.h +++ b/arch/arm/mach-shmobile/include/mach/r8a7790.h | |||
@@ -5,8 +5,9 @@ void r8a7790_add_standard_devices(void); | |||
5 | void r8a7790_add_dt_devices(void); | 5 | void r8a7790_add_dt_devices(void); |
6 | void r8a7790_clock_init(void); | 6 | void r8a7790_clock_init(void); |
7 | void r8a7790_pinmux_init(void); | 7 | void r8a7790_pinmux_init(void); |
8 | void r8a7790_init_delay(void); | 8 | void r8a7790_init_early(void); |
9 | void r8a7790_timer_init(void); | 9 | void r8a7790_timer_init(void); |
10 | extern struct smp_operations r8a7790_smp_ops; | ||
10 | 11 | ||
11 | #define MD(nr) BIT(nr) | 12 | #define MD(nr) BIT(nr) |
12 | u32 r8a7790_read_mode_pins(void); | 13 | u32 r8a7790_read_mode_pins(void); |
diff --git a/arch/arm/mach-shmobile/platsmp-apmu.c b/arch/arm/mach-shmobile/platsmp-apmu.c new file mode 100644 index 000000000000..1da5a72d9642 --- /dev/null +++ b/arch/arm/mach-shmobile/platsmp-apmu.c | |||
@@ -0,0 +1,195 @@ | |||
1 | /* | ||
2 | * SMP support for SoCs with APMU | ||
3 | * | ||
4 | * Copyright (C) 2013 Magnus Damm | ||
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 | #include <linux/delay.h> | ||
11 | #include <linux/init.h> | ||
12 | #include <linux/io.h> | ||
13 | #include <linux/ioport.h> | ||
14 | #include <linux/of_address.h> | ||
15 | #include <linux/smp.h> | ||
16 | #include <asm/cacheflush.h> | ||
17 | #include <asm/cp15.h> | ||
18 | #include <asm/smp_plat.h> | ||
19 | #include <mach/common.h> | ||
20 | |||
21 | static struct { | ||
22 | void __iomem *iomem; | ||
23 | int bit; | ||
24 | } apmu_cpus[CONFIG_NR_CPUS]; | ||
25 | |||
26 | #define WUPCR_OFFS 0x10 | ||
27 | #define PSTR_OFFS 0x40 | ||
28 | #define CPUNCR_OFFS(n) (0x100 + (0x10 * (n))) | ||
29 | |||
30 | static int apmu_power_on(void __iomem *p, int bit) | ||
31 | { | ||
32 | /* request power on */ | ||
33 | writel_relaxed(BIT(bit), p + WUPCR_OFFS); | ||
34 | |||
35 | /* wait for APMU to finish */ | ||
36 | while (readl_relaxed(p + WUPCR_OFFS) != 0) | ||
37 | ; | ||
38 | |||
39 | return 0; | ||
40 | } | ||
41 | |||
42 | static int apmu_power_off(void __iomem *p, int bit) | ||
43 | { | ||
44 | /* request Core Standby for next WFI */ | ||
45 | writel_relaxed(3, p + CPUNCR_OFFS(bit)); | ||
46 | return 0; | ||
47 | } | ||
48 | |||
49 | static int apmu_power_off_poll(void __iomem *p, int bit) | ||
50 | { | ||
51 | int k; | ||
52 | |||
53 | for (k = 0; k < 1000; k++) { | ||
54 | if (((readl_relaxed(p + PSTR_OFFS) >> (bit * 4)) & 0x03) == 3) | ||
55 | return 1; | ||
56 | |||
57 | mdelay(1); | ||
58 | } | ||
59 | |||
60 | return 0; | ||
61 | } | ||
62 | |||
63 | static int apmu_wrap(int cpu, int (*fn)(void __iomem *p, int cpu)) | ||
64 | { | ||
65 | void __iomem *p = apmu_cpus[cpu].iomem; | ||
66 | |||
67 | return p ? fn(p, apmu_cpus[cpu].bit) : -EINVAL; | ||
68 | } | ||
69 | |||
70 | static void apmu_init_cpu(struct resource *res, int cpu, int bit) | ||
71 | { | ||
72 | if (apmu_cpus[cpu].iomem) | ||
73 | return; | ||
74 | |||
75 | apmu_cpus[cpu].iomem = ioremap_nocache(res->start, resource_size(res)); | ||
76 | apmu_cpus[cpu].bit = bit; | ||
77 | |||
78 | pr_debug("apmu ioremap %d %d 0x%08x 0x%08x\n", cpu, bit, | ||
79 | res->start, resource_size(res)); | ||
80 | } | ||
81 | |||
82 | static struct { | ||
83 | struct resource iomem; | ||
84 | int cpus[4]; | ||
85 | } apmu_config[] = { | ||
86 | { | ||
87 | .iomem = DEFINE_RES_MEM(0xe6152000, 0x88), | ||
88 | .cpus = { 0, 1, 2, 3 }, | ||
89 | }, | ||
90 | { | ||
91 | .iomem = DEFINE_RES_MEM(0xe6151000, 0x88), | ||
92 | .cpus = { 0x100, 0x101, 0x102, 0x103 }, | ||
93 | } | ||
94 | }; | ||
95 | |||
96 | static void apmu_parse_cfg(void (*fn)(struct resource *res, int cpu, int bit)) | ||
97 | { | ||
98 | u32 id; | ||
99 | int k; | ||
100 | int bit, index; | ||
101 | bool is_allowed; | ||
102 | |||
103 | for (k = 0; k < ARRAY_SIZE(apmu_config); k++) { | ||
104 | /* only enable the cluster that includes the boot CPU */ | ||
105 | is_allowed = false; | ||
106 | for (bit = 0; bit < ARRAY_SIZE(apmu_config[k].cpus); bit++) { | ||
107 | id = apmu_config[k].cpus[bit]; | ||
108 | if (id >= 0) { | ||
109 | if (id == cpu_logical_map(0)) | ||
110 | is_allowed = true; | ||
111 | } | ||
112 | } | ||
113 | if (!is_allowed) | ||
114 | continue; | ||
115 | |||
116 | for (bit = 0; bit < ARRAY_SIZE(apmu_config[k].cpus); bit++) { | ||
117 | id = apmu_config[k].cpus[bit]; | ||
118 | if (id >= 0) { | ||
119 | index = get_logical_index(id); | ||
120 | if (index >= 0) | ||
121 | fn(&apmu_config[k].iomem, index, bit); | ||
122 | } | ||
123 | } | ||
124 | } | ||
125 | } | ||
126 | |||
127 | void __init shmobile_smp_apmu_prepare_cpus(unsigned int max_cpus) | ||
128 | { | ||
129 | /* install boot code shared by all CPUs */ | ||
130 | shmobile_boot_fn = virt_to_phys(shmobile_smp_boot); | ||
131 | shmobile_boot_arg = MPIDR_HWID_BITMASK; | ||
132 | |||
133 | /* perform per-cpu setup */ | ||
134 | apmu_parse_cfg(apmu_init_cpu); | ||
135 | } | ||
136 | |||
137 | int shmobile_smp_apmu_boot_secondary(unsigned int cpu, struct task_struct *idle) | ||
138 | { | ||
139 | /* For this particular CPU register boot vector */ | ||
140 | shmobile_smp_hook(cpu, virt_to_phys(shmobile_invalidate_start), 0); | ||
141 | |||
142 | return apmu_wrap(cpu, apmu_power_on); | ||
143 | } | ||
144 | |||
145 | #ifdef CONFIG_HOTPLUG_CPU | ||
146 | /* nicked from arch/arm/mach-exynos/hotplug.c */ | ||
147 | static inline void cpu_enter_lowpower_a15(void) | ||
148 | { | ||
149 | unsigned int v; | ||
150 | |||
151 | asm volatile( | ||
152 | " mrc p15, 0, %0, c1, c0, 0\n" | ||
153 | " bic %0, %0, %1\n" | ||
154 | " mcr p15, 0, %0, c1, c0, 0\n" | ||
155 | : "=&r" (v) | ||
156 | : "Ir" (CR_C) | ||
157 | : "cc"); | ||
158 | |||
159 | flush_cache_louis(); | ||
160 | |||
161 | asm volatile( | ||
162 | /* | ||
163 | * Turn off coherency | ||
164 | */ | ||
165 | " mrc p15, 0, %0, c1, c0, 1\n" | ||
166 | " bic %0, %0, %1\n" | ||
167 | " mcr p15, 0, %0, c1, c0, 1\n" | ||
168 | : "=&r" (v) | ||
169 | : "Ir" (0x40) | ||
170 | : "cc"); | ||
171 | |||
172 | isb(); | ||
173 | dsb(); | ||
174 | } | ||
175 | |||
176 | void shmobile_smp_apmu_cpu_die(unsigned int cpu) | ||
177 | { | ||
178 | /* For this particular CPU deregister boot vector */ | ||
179 | shmobile_smp_hook(cpu, 0, 0); | ||
180 | |||
181 | /* Select next sleep mode using the APMU */ | ||
182 | apmu_wrap(cpu, apmu_power_off); | ||
183 | |||
184 | /* Do ARM specific CPU shutdown */ | ||
185 | cpu_enter_lowpower_a15(); | ||
186 | |||
187 | /* jump to shared mach-shmobile sleep / reset code */ | ||
188 | shmobile_smp_sleep(); | ||
189 | } | ||
190 | |||
191 | int shmobile_smp_apmu_cpu_kill(unsigned int cpu) | ||
192 | { | ||
193 | return apmu_wrap(cpu, apmu_power_off_poll); | ||
194 | } | ||
195 | #endif | ||
diff --git a/arch/arm/mach-shmobile/platsmp-scu.c b/arch/arm/mach-shmobile/platsmp-scu.c index c96f50160be6..673ad6e80869 100644 --- a/arch/arm/mach-shmobile/platsmp-scu.c +++ b/arch/arm/mach-shmobile/platsmp-scu.c | |||
@@ -7,6 +7,7 @@ | |||
7 | * it under the terms of the GNU General Public License version 2 as | 7 | * it under the terms of the GNU General Public License version 2 as |
8 | * published by the Free Software Foundation. | 8 | * published by the Free Software Foundation. |
9 | */ | 9 | */ |
10 | #include <linux/cpu.h> | ||
10 | #include <linux/delay.h> | 11 | #include <linux/delay.h> |
11 | #include <linux/init.h> | 12 | #include <linux/init.h> |
12 | #include <linux/io.h> | 13 | #include <linux/io.h> |
@@ -16,6 +17,26 @@ | |||
16 | #include <asm/smp_scu.h> | 17 | #include <asm/smp_scu.h> |
17 | #include <mach/common.h> | 18 | #include <mach/common.h> |
18 | 19 | ||
20 | static int shmobile_smp_scu_notifier_call(struct notifier_block *nfb, | ||
21 | unsigned long action, void *hcpu) | ||
22 | { | ||
23 | unsigned int cpu = (long)hcpu; | ||
24 | |||
25 | switch (action) { | ||
26 | case CPU_UP_PREPARE: | ||
27 | /* For this particular CPU register SCU SMP boot vector */ | ||
28 | shmobile_smp_hook(cpu, virt_to_phys(shmobile_boot_scu), | ||
29 | (unsigned long)shmobile_scu_base); | ||
30 | break; | ||
31 | }; | ||
32 | |||
33 | return NOTIFY_OK; | ||
34 | } | ||
35 | |||
36 | static struct notifier_block shmobile_smp_scu_notifier = { | ||
37 | .notifier_call = shmobile_smp_scu_notifier_call, | ||
38 | }; | ||
39 | |||
19 | void __init shmobile_smp_scu_prepare_cpus(unsigned int max_cpus) | 40 | void __init shmobile_smp_scu_prepare_cpus(unsigned int max_cpus) |
20 | { | 41 | { |
21 | /* install boot code shared by all CPUs */ | 42 | /* install boot code shared by all CPUs */ |
@@ -25,14 +46,9 @@ void __init shmobile_smp_scu_prepare_cpus(unsigned int max_cpus) | |||
25 | /* enable SCU and cache coherency on booting CPU */ | 46 | /* enable SCU and cache coherency on booting CPU */ |
26 | scu_enable(shmobile_scu_base); | 47 | scu_enable(shmobile_scu_base); |
27 | scu_power_mode(shmobile_scu_base, SCU_PM_NORMAL); | 48 | scu_power_mode(shmobile_scu_base, SCU_PM_NORMAL); |
28 | } | ||
29 | 49 | ||
30 | int shmobile_smp_scu_boot_secondary(unsigned int cpu, struct task_struct *idle) | 50 | /* Use CPU notifier for reset vector control */ |
31 | { | 51 | register_cpu_notifier(&shmobile_smp_scu_notifier); |
32 | /* For this particular CPU register SCU boot vector */ | ||
33 | shmobile_smp_hook(cpu, virt_to_phys(shmobile_boot_scu), | ||
34 | (unsigned long)shmobile_scu_base); | ||
35 | return 0; | ||
36 | } | 52 | } |
37 | 53 | ||
38 | #ifdef CONFIG_HOTPLUG_CPU | 54 | #ifdef CONFIG_HOTPLUG_CPU |
diff --git a/arch/arm/mach-shmobile/platsmp.c b/arch/arm/mach-shmobile/platsmp.c index d4ae616bcedb..9ebc246b8d7d 100644 --- a/arch/arm/mach-shmobile/platsmp.c +++ b/arch/arm/mach-shmobile/platsmp.c | |||
@@ -11,25 +11,10 @@ | |||
11 | * published by the Free Software Foundation. | 11 | * published by the Free Software Foundation. |
12 | */ | 12 | */ |
13 | #include <linux/init.h> | 13 | #include <linux/init.h> |
14 | #include <linux/smp.h> | ||
15 | #include <asm/cacheflush.h> | 14 | #include <asm/cacheflush.h> |
16 | #include <asm/smp_plat.h> | 15 | #include <asm/smp_plat.h> |
17 | #include <mach/common.h> | 16 | #include <mach/common.h> |
18 | 17 | ||
19 | void __init shmobile_smp_init_cpus(unsigned int ncores) | ||
20 | { | ||
21 | unsigned int i; | ||
22 | |||
23 | if (ncores > nr_cpu_ids) { | ||
24 | pr_warn("SMP: %u cores greater than maximum (%u), clipping\n", | ||
25 | ncores, nr_cpu_ids); | ||
26 | ncores = nr_cpu_ids; | ||
27 | } | ||
28 | |||
29 | for (i = 0; i < ncores; i++) | ||
30 | set_cpu_possible(i, true); | ||
31 | } | ||
32 | |||
33 | extern unsigned long shmobile_smp_fn[]; | 18 | extern unsigned long shmobile_smp_fn[]; |
34 | extern unsigned long shmobile_smp_arg[]; | 19 | extern unsigned long shmobile_smp_arg[]; |
35 | extern unsigned long shmobile_smp_mpidr[]; | 20 | extern unsigned long shmobile_smp_mpidr[]; |
@@ -44,3 +29,10 @@ void shmobile_smp_hook(unsigned int cpu, unsigned long fn, unsigned long arg) | |||
44 | shmobile_smp_arg[cpu] = arg; | 29 | shmobile_smp_arg[cpu] = arg; |
45 | flush_cache_all(); | 30 | flush_cache_all(); |
46 | } | 31 | } |
32 | |||
33 | #ifdef CONFIG_HOTPLUG_CPU | ||
34 | int shmobile_smp_cpu_disable(unsigned int cpu) | ||
35 | { | ||
36 | return 0; /* Hotplug of any CPU is supported */ | ||
37 | } | ||
38 | #endif | ||
diff --git a/arch/arm/mach-shmobile/setup-r8a73a4.c b/arch/arm/mach-shmobile/setup-r8a73a4.c index 89491700afb7..53a896275cae 100644 --- a/arch/arm/mach-shmobile/setup-r8a73a4.c +++ b/arch/arm/mach-shmobile/setup-r8a73a4.c | |||
@@ -207,7 +207,7 @@ void __init r8a73a4_add_standard_devices(void) | |||
207 | r8a73a4_register_thermal(); | 207 | r8a73a4_register_thermal(); |
208 | } | 208 | } |
209 | 209 | ||
210 | void __init r8a73a4_init_delay(void) | 210 | void __init r8a73a4_init_early(void) |
211 | { | 211 | { |
212 | #ifndef CONFIG_ARM_ARCH_TIMER | 212 | #ifndef CONFIG_ARM_ARCH_TIMER |
213 | shmobile_setup_delay(1500, 2, 4); /* Cortex-A15 @ 1500MHz */ | 213 | shmobile_setup_delay(1500, 2, 4); /* Cortex-A15 @ 1500MHz */ |
@@ -222,7 +222,7 @@ static const char *r8a73a4_boards_compat_dt[] __initdata = { | |||
222 | }; | 222 | }; |
223 | 223 | ||
224 | DT_MACHINE_START(R8A73A4_DT, "Generic R8A73A4 (Flattened Device Tree)") | 224 | DT_MACHINE_START(R8A73A4_DT, "Generic R8A73A4 (Flattened Device Tree)") |
225 | .init_early = r8a73a4_init_delay, | 225 | .init_early = r8a73a4_init_early, |
226 | .dt_compat = r8a73a4_boards_compat_dt, | 226 | .dt_compat = r8a73a4_boards_compat_dt, |
227 | MACHINE_END | 227 | MACHINE_END |
228 | #endif /* CONFIG_USE_OF */ | 228 | #endif /* CONFIG_USE_OF */ |
diff --git a/arch/arm/mach-shmobile/setup-r8a7790.c b/arch/arm/mach-shmobile/setup-r8a7790.c index d0f5c9f9349a..c7e24eff9ba2 100644 --- a/arch/arm/mach-shmobile/setup-r8a7790.c +++ b/arch/arm/mach-shmobile/setup-r8a7790.c | |||
@@ -31,17 +31,18 @@ | |||
31 | #include <mach/r8a7790.h> | 31 | #include <mach/r8a7790.h> |
32 | #include <asm/mach/arch.h> | 32 | #include <asm/mach/arch.h> |
33 | 33 | ||
34 | static struct resource pfc_resources[] __initdata = { | 34 | static const struct resource pfc_resources[] __initconst = { |
35 | DEFINE_RES_MEM(0xe6060000, 0x250), | 35 | DEFINE_RES_MEM(0xe6060000, 0x250), |
36 | }; | 36 | }; |
37 | 37 | ||
38 | #define R8A7790_GPIO(idx) \ | 38 | #define R8A7790_GPIO(idx) \ |
39 | static struct resource r8a7790_gpio##idx##_resources[] __initdata = { \ | 39 | static const struct resource r8a7790_gpio##idx##_resources[] __initconst = { \ |
40 | DEFINE_RES_MEM(0xe6050000 + 0x1000 * (idx), 0x50), \ | 40 | DEFINE_RES_MEM(0xe6050000 + 0x1000 * (idx), 0x50), \ |
41 | DEFINE_RES_IRQ(gic_spi(4 + (idx))), \ | 41 | DEFINE_RES_IRQ(gic_spi(4 + (idx))), \ |
42 | }; \ | 42 | }; \ |
43 | \ | 43 | \ |
44 | static struct gpio_rcar_config r8a7790_gpio##idx##_platform_data __initdata = { \ | 44 | static const struct gpio_rcar_config \ |
45 | r8a7790_gpio##idx##_platform_data __initconst = { \ | ||
45 | .gpio_base = 32 * (idx), \ | 46 | .gpio_base = 32 * (idx), \ |
46 | .irq_base = 0, \ | 47 | .irq_base = 0, \ |
47 | .number_of_pins = 32, \ | 48 | .number_of_pins = 32, \ |
@@ -112,7 +113,7 @@ void __init r8a7790_pinmux_init(void) | |||
112 | enum { SCIFA0, SCIFA1, SCIFB0, SCIFB1, SCIFB2, SCIFA2, SCIF0, SCIF1, | 113 | enum { SCIFA0, SCIFA1, SCIFB0, SCIFB1, SCIFB2, SCIFA2, SCIF0, SCIF1, |
113 | HSCIF0, HSCIF1 }; | 114 | HSCIF0, HSCIF1 }; |
114 | 115 | ||
115 | static struct plat_sci_port scif[] __initdata = { | 116 | static const struct plat_sci_port scif[] __initconst = { |
116 | SCIFA_DATA(SCIFA0, 0xe6c40000, gic_spi(144)), /* SCIFA0 */ | 117 | SCIFA_DATA(SCIFA0, 0xe6c40000, gic_spi(144)), /* SCIFA0 */ |
117 | SCIFA_DATA(SCIFA1, 0xe6c50000, gic_spi(145)), /* SCIFA1 */ | 118 | SCIFA_DATA(SCIFA1, 0xe6c50000, gic_spi(145)), /* SCIFA1 */ |
118 | SCIFB_DATA(SCIFB0, 0xe6c20000, gic_spi(148)), /* SCIFB0 */ | 119 | SCIFB_DATA(SCIFB0, 0xe6c20000, gic_spi(148)), /* SCIFB0 */ |
@@ -131,11 +132,11 @@ static inline void r8a7790_register_scif(int idx) | |||
131 | sizeof(struct plat_sci_port)); | 132 | sizeof(struct plat_sci_port)); |
132 | } | 133 | } |
133 | 134 | ||
134 | static struct renesas_irqc_config irqc0_data __initdata = { | 135 | static const struct renesas_irqc_config irqc0_data __initconst = { |
135 | .irq_base = irq_pin(0), /* IRQ0 -> IRQ3 */ | 136 | .irq_base = irq_pin(0), /* IRQ0 -> IRQ3 */ |
136 | }; | 137 | }; |
137 | 138 | ||
138 | static struct resource irqc0_resources[] __initdata = { | 139 | static const struct resource irqc0_resources[] __initconst = { |
139 | DEFINE_RES_MEM(0xe61c0000, 0x200), /* IRQC Event Detector Block_0 */ | 140 | DEFINE_RES_MEM(0xe61c0000, 0x200), /* IRQC Event Detector Block_0 */ |
140 | DEFINE_RES_IRQ(gic_spi(0)), /* IRQ0 */ | 141 | DEFINE_RES_IRQ(gic_spi(0)), /* IRQ0 */ |
141 | DEFINE_RES_IRQ(gic_spi(1)), /* IRQ1 */ | 142 | DEFINE_RES_IRQ(gic_spi(1)), /* IRQ1 */ |
@@ -150,7 +151,7 @@ static struct resource irqc0_resources[] __initdata = { | |||
150 | &irqc##idx##_data, \ | 151 | &irqc##idx##_data, \ |
151 | sizeof(struct renesas_irqc_config)) | 152 | sizeof(struct renesas_irqc_config)) |
152 | 153 | ||
153 | static struct resource thermal_resources[] __initdata = { | 154 | static const struct resource thermal_resources[] __initconst = { |
154 | DEFINE_RES_MEM(0xe61f0000, 0x14), | 155 | DEFINE_RES_MEM(0xe61f0000, 0x14), |
155 | DEFINE_RES_MEM(0xe61f0100, 0x38), | 156 | DEFINE_RES_MEM(0xe61f0100, 0x38), |
156 | DEFINE_RES_IRQ(gic_spi(69)), | 157 | DEFINE_RES_IRQ(gic_spi(69)), |
@@ -161,13 +162,13 @@ static struct resource thermal_resources[] __initdata = { | |||
161 | thermal_resources, \ | 162 | thermal_resources, \ |
162 | ARRAY_SIZE(thermal_resources)) | 163 | ARRAY_SIZE(thermal_resources)) |
163 | 164 | ||
164 | static struct sh_timer_config cmt00_platform_data __initdata = { | 165 | static const struct sh_timer_config cmt00_platform_data __initconst = { |
165 | .name = "CMT00", | 166 | .name = "CMT00", |
166 | .timer_bit = 0, | 167 | .timer_bit = 0, |
167 | .clockevent_rating = 80, | 168 | .clockevent_rating = 80, |
168 | }; | 169 | }; |
169 | 170 | ||
170 | static struct resource cmt00_resources[] __initdata = { | 171 | static const struct resource cmt00_resources[] __initconst = { |
171 | DEFINE_RES_MEM(0xffca0510, 0x0c), | 172 | DEFINE_RES_MEM(0xffca0510, 0x0c), |
172 | DEFINE_RES_MEM(0xffca0500, 0x04), | 173 | DEFINE_RES_MEM(0xffca0500, 0x04), |
173 | DEFINE_RES_IRQ(gic_spi(142)), /* CMT0_0 */ | 174 | DEFINE_RES_IRQ(gic_spi(142)), /* CMT0_0 */ |
@@ -267,7 +268,7 @@ void __init r8a7790_timer_init(void) | |||
267 | clocksource_of_init(); | 268 | clocksource_of_init(); |
268 | } | 269 | } |
269 | 270 | ||
270 | void __init r8a7790_init_delay(void) | 271 | void __init r8a7790_init_early(void) |
271 | { | 272 | { |
272 | #ifndef CONFIG_ARM_ARCH_TIMER | 273 | #ifndef CONFIG_ARM_ARCH_TIMER |
273 | shmobile_setup_delay(1300, 2, 4); /* Cortex-A15 @ 1300MHz */ | 274 | shmobile_setup_delay(1300, 2, 4); /* Cortex-A15 @ 1300MHz */ |
@@ -276,13 +277,14 @@ void __init r8a7790_init_delay(void) | |||
276 | 277 | ||
277 | #ifdef CONFIG_USE_OF | 278 | #ifdef CONFIG_USE_OF |
278 | 279 | ||
279 | static const char *r8a7790_boards_compat_dt[] __initdata = { | 280 | static const char * const r8a7790_boards_compat_dt[] __initconst = { |
280 | "renesas,r8a7790", | 281 | "renesas,r8a7790", |
281 | NULL, | 282 | NULL, |
282 | }; | 283 | }; |
283 | 284 | ||
284 | DT_MACHINE_START(R8A7790_DT, "Generic R8A7790 (Flattened Device Tree)") | 285 | DT_MACHINE_START(R8A7790_DT, "Generic R8A7790 (Flattened Device Tree)") |
285 | .init_early = r8a7790_init_delay, | 286 | .smp = smp_ops(r8a7790_smp_ops), |
287 | .init_early = r8a7790_init_early, | ||
286 | .init_time = r8a7790_timer_init, | 288 | .init_time = r8a7790_timer_init, |
287 | .dt_compat = r8a7790_boards_compat_dt, | 289 | .dt_compat = r8a7790_boards_compat_dt, |
288 | MACHINE_END | 290 | MACHINE_END |
diff --git a/arch/arm/mach-shmobile/smp-emev2.c b/arch/arm/mach-shmobile/smp-emev2.c index 522de5ebb55f..f2ca92308f75 100644 --- a/arch/arm/mach-shmobile/smp-emev2.c +++ b/arch/arm/mach-shmobile/smp-emev2.c | |||
@@ -34,12 +34,6 @@ | |||
34 | 34 | ||
35 | static int emev2_boot_secondary(unsigned int cpu, struct task_struct *idle) | 35 | static int emev2_boot_secondary(unsigned int cpu, struct task_struct *idle) |
36 | { | 36 | { |
37 | int ret; | ||
38 | |||
39 | ret = shmobile_smp_scu_boot_secondary(cpu, idle); | ||
40 | if (ret) | ||
41 | return ret; | ||
42 | |||
43 | arch_send_wakeup_ipi_mask(cpumask_of(cpu_logical_map(cpu))); | 37 | arch_send_wakeup_ipi_mask(cpumask_of(cpu_logical_map(cpu))); |
44 | return 0; | 38 | return 0; |
45 | } | 39 | } |
diff --git a/arch/arm/mach-shmobile/smp-r8a7779.c b/arch/arm/mach-shmobile/smp-r8a7779.c index 0f05e9fb722f..627c1f0d9478 100644 --- a/arch/arm/mach-shmobile/smp-r8a7779.c +++ b/arch/arm/mach-shmobile/smp-r8a7779.c | |||
@@ -87,10 +87,6 @@ static int r8a7779_boot_secondary(unsigned int cpu, struct task_struct *idle) | |||
87 | unsigned int lcpu = cpu_logical_map(cpu); | 87 | unsigned int lcpu = cpu_logical_map(cpu); |
88 | int ret; | 88 | int ret; |
89 | 89 | ||
90 | ret = shmobile_smp_scu_boot_secondary(cpu, idle); | ||
91 | if (ret) | ||
92 | return ret; | ||
93 | |||
94 | if (lcpu < ARRAY_SIZE(r8a7779_ch_cpu)) | 90 | if (lcpu < ARRAY_SIZE(r8a7779_ch_cpu)) |
95 | ch = r8a7779_ch_cpu[lcpu]; | 91 | ch = r8a7779_ch_cpu[lcpu]; |
96 | 92 | ||
diff --git a/arch/arm/mach-shmobile/smp-r8a7790.c b/arch/arm/mach-shmobile/smp-r8a7790.c new file mode 100644 index 000000000000..015e2753de1f --- /dev/null +++ b/arch/arm/mach-shmobile/smp-r8a7790.c | |||
@@ -0,0 +1,67 @@ | |||
1 | /* | ||
2 | * SMP support for r8a7790 | ||
3 | * | ||
4 | * Copyright (C) 2012-2013 Renesas Solutions Corp. | ||
5 | * Copyright (C) 2012 Takashi Yoshii <takashi.yoshii.ze@renesas.com> | ||
6 | * | ||
7 | * This program is free software; you can redistribute it and/or modify | ||
8 | * it under the terms of the GNU General Public License as published by | ||
9 | * the Free Software Foundation; version 2 of the License. | ||
10 | * | ||
11 | * This program is distributed in the hope that it will be useful, | ||
12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
14 | * GNU General Public License for more details. | ||
15 | */ | ||
16 | #include <linux/kernel.h> | ||
17 | #include <linux/init.h> | ||
18 | #include <linux/smp.h> | ||
19 | #include <linux/io.h> | ||
20 | #include <asm/smp_plat.h> | ||
21 | #include <mach/common.h> | ||
22 | |||
23 | #define RST 0xe6160000 | ||
24 | #define CA15BAR 0x0020 | ||
25 | #define CA7BAR 0x0030 | ||
26 | #define CA15RESCNT 0x0040 | ||
27 | #define CA7RESCNT 0x0044 | ||
28 | #define MERAM 0xe8080000 | ||
29 | |||
30 | static void __init r8a7790_smp_prepare_cpus(unsigned int max_cpus) | ||
31 | { | ||
32 | void __iomem *p; | ||
33 | u32 bar; | ||
34 | |||
35 | /* let APMU code install data related to shmobile_boot_vector */ | ||
36 | shmobile_smp_apmu_prepare_cpus(max_cpus); | ||
37 | |||
38 | /* MERAM for jump stub, because BAR requires 256KB aligned address */ | ||
39 | p = ioremap_nocache(MERAM, shmobile_boot_size); | ||
40 | memcpy_toio(p, shmobile_boot_vector, shmobile_boot_size); | ||
41 | iounmap(p); | ||
42 | |||
43 | /* setup reset vectors */ | ||
44 | p = ioremap_nocache(RST, 0x63); | ||
45 | bar = (MERAM >> 8) & 0xfffffc00; | ||
46 | writel_relaxed(bar, p + CA15BAR); | ||
47 | writel_relaxed(bar, p + CA7BAR); | ||
48 | writel_relaxed(bar | 0x10, p + CA15BAR); | ||
49 | writel_relaxed(bar | 0x10, p + CA7BAR); | ||
50 | |||
51 | /* enable clocks to all CPUs */ | ||
52 | writel_relaxed((readl_relaxed(p + CA15RESCNT) & ~0x0f) | 0xa5a50000, | ||
53 | p + CA15RESCNT); | ||
54 | writel_relaxed((readl_relaxed(p + CA7RESCNT) & ~0x0f) | 0x5a5a0000, | ||
55 | p + CA7RESCNT); | ||
56 | iounmap(p); | ||
57 | } | ||
58 | |||
59 | struct smp_operations r8a7790_smp_ops __initdata = { | ||
60 | .smp_prepare_cpus = r8a7790_smp_prepare_cpus, | ||
61 | .smp_boot_secondary = shmobile_smp_apmu_boot_secondary, | ||
62 | #ifdef CONFIG_HOTPLUG_CPU | ||
63 | .cpu_disable = shmobile_smp_cpu_disable, | ||
64 | .cpu_die = shmobile_smp_apmu_cpu_die, | ||
65 | .cpu_kill = shmobile_smp_apmu_cpu_kill, | ||
66 | #endif | ||
67 | }; | ||
diff --git a/arch/arm/mach-shmobile/smp-sh73a0.c b/arch/arm/mach-shmobile/smp-sh73a0.c index 0baa24443793..13ba36a6831f 100644 --- a/arch/arm/mach-shmobile/smp-sh73a0.c +++ b/arch/arm/mach-shmobile/smp-sh73a0.c | |||
@@ -46,11 +46,6 @@ void __init sh73a0_register_twd(void) | |||
46 | static int sh73a0_boot_secondary(unsigned int cpu, struct task_struct *idle) | 46 | static int sh73a0_boot_secondary(unsigned int cpu, struct task_struct *idle) |
47 | { | 47 | { |
48 | unsigned int lcpu = cpu_logical_map(cpu); | 48 | unsigned int lcpu = cpu_logical_map(cpu); |
49 | int ret; | ||
50 | |||
51 | ret = shmobile_smp_scu_boot_secondary(cpu, idle); | ||
52 | if (ret) | ||
53 | return ret; | ||
54 | 49 | ||
55 | if (((__raw_readl(PSTR) >> (4 * lcpu)) & 3) == 3) | 50 | if (((__raw_readl(PSTR) >> (4 * lcpu)) & 3) == 3) |
56 | __raw_writel(1 << lcpu, WUPCR); /* wake up */ | 51 | __raw_writel(1 << lcpu, WUPCR); /* wake up */ |
@@ -71,18 +66,11 @@ static void __init sh73a0_smp_prepare_cpus(unsigned int max_cpus) | |||
71 | shmobile_smp_scu_prepare_cpus(max_cpus); | 66 | shmobile_smp_scu_prepare_cpus(max_cpus); |
72 | } | 67 | } |
73 | 68 | ||
74 | #ifdef CONFIG_HOTPLUG_CPU | ||
75 | static int sh73a0_cpu_disable(unsigned int cpu) | ||
76 | { | ||
77 | return 0; /* CPU0 and CPU1 supported */ | ||
78 | } | ||
79 | #endif /* CONFIG_HOTPLUG_CPU */ | ||
80 | |||
81 | struct smp_operations sh73a0_smp_ops __initdata = { | 69 | struct smp_operations sh73a0_smp_ops __initdata = { |
82 | .smp_prepare_cpus = sh73a0_smp_prepare_cpus, | 70 | .smp_prepare_cpus = sh73a0_smp_prepare_cpus, |
83 | .smp_boot_secondary = sh73a0_boot_secondary, | 71 | .smp_boot_secondary = sh73a0_boot_secondary, |
84 | #ifdef CONFIG_HOTPLUG_CPU | 72 | #ifdef CONFIG_HOTPLUG_CPU |
85 | .cpu_disable = sh73a0_cpu_disable, | 73 | .cpu_disable = shmobile_smp_cpu_disable, |
86 | .cpu_die = shmobile_smp_scu_cpu_die, | 74 | .cpu_die = shmobile_smp_scu_cpu_die, |
87 | .cpu_kill = shmobile_smp_scu_cpu_kill, | 75 | .cpu_kill = shmobile_smp_scu_cpu_kill, |
88 | #endif | 76 | #endif |