diff options
-rw-r--r-- | arch/arm/mach-mvebu/armada-370-xp.h | 6 | ||||
-rw-r--r-- | arch/arm/mach-mvebu/board-v7.c | 73 | ||||
-rw-r--r-- | arch/arm/mach-mvebu/coherency.c | 223 | ||||
-rw-r--r-- | arch/arm/mach-mvebu/coherency_ll.S | 21 | ||||
-rw-r--r-- | arch/arm/mach-mvebu/cpu-reset.c | 1 | ||||
-rw-r--r-- | arch/arm/mach-mvebu/headsmp-a9.S | 1 | ||||
-rw-r--r-- | arch/arm/mach-mvebu/platsmp-a9.c | 53 | ||||
-rw-r--r-- | arch/arm/mach-mvebu/platsmp.c | 2 | ||||
-rw-r--r-- | arch/arm/mach-mvebu/pmsu.c | 3 | ||||
-rw-r--r-- | arch/arm/mach-mvebu/pmsu.h | 2 | ||||
-rw-r--r-- | arch/arm/mach-mvebu/pmsu_ll.S | 20 | ||||
-rw-r--r-- | arch/arm/plat-orion/gpio.c | 36 |
12 files changed, 166 insertions, 275 deletions
diff --git a/arch/arm/mach-mvebu/armada-370-xp.h b/arch/arm/mach-mvebu/armada-370-xp.h index 84cd90d9b860..c55bbf81de0e 100644 --- a/arch/arm/mach-mvebu/armada-370-xp.h +++ b/arch/arm/mach-mvebu/armada-370-xp.h | |||
@@ -16,14 +16,8 @@ | |||
16 | #define __MACH_ARMADA_370_XP_H | 16 | #define __MACH_ARMADA_370_XP_H |
17 | 17 | ||
18 | #ifdef CONFIG_SMP | 18 | #ifdef CONFIG_SMP |
19 | #include <linux/cpumask.h> | ||
20 | |||
21 | #define ARMADA_XP_MAX_CPUS 4 | ||
22 | |||
23 | void armada_xp_secondary_startup(void); | 19 | void armada_xp_secondary_startup(void); |
24 | extern struct smp_operations armada_xp_smp_ops; | 20 | extern struct smp_operations armada_xp_smp_ops; |
25 | #endif | 21 | #endif |
26 | 22 | ||
27 | int armada_370_xp_pmsu_idle_enter(unsigned long deepidle); | ||
28 | |||
29 | #endif /* __MACH_ARMADA_370_XP_H */ | 23 | #endif /* __MACH_ARMADA_370_XP_H */ |
diff --git a/arch/arm/mach-mvebu/board-v7.c b/arch/arm/mach-mvebu/board-v7.c index 6478626e3ff6..e15ead876a48 100644 --- a/arch/arm/mach-mvebu/board-v7.c +++ b/arch/arm/mach-mvebu/board-v7.c | |||
@@ -124,76 +124,12 @@ static void __init i2c_quirk(void) | |||
124 | return; | 124 | return; |
125 | } | 125 | } |
126 | 126 | ||
127 | #define A375_Z1_THERMAL_FIXUP_OFFSET 0xc | ||
128 | |||
129 | static void __init thermal_quirk(void) | ||
130 | { | ||
131 | struct device_node *np; | ||
132 | u32 dev, rev; | ||
133 | int res; | ||
134 | |||
135 | /* | ||
136 | * The early SoC Z1 revision needs a quirk to be applied in order | ||
137 | * for the thermal controller to work properly. This quirk breaks | ||
138 | * the thermal support if applied on a SoC that doesn't need it, | ||
139 | * so we enforce the SoC revision to be known. | ||
140 | */ | ||
141 | res = mvebu_get_soc_id(&dev, &rev); | ||
142 | if (res < 0 || (res == 0 && rev > ARMADA_375_Z1_REV)) | ||
143 | return; | ||
144 | |||
145 | for_each_compatible_node(np, NULL, "marvell,armada375-thermal") { | ||
146 | struct property *prop; | ||
147 | __be32 newval, *newprop, *oldprop; | ||
148 | int len; | ||
149 | |||
150 | /* | ||
151 | * The register offset is at a wrong location. This quirk | ||
152 | * creates a new reg property as a clone of the previous | ||
153 | * one and corrects the offset. | ||
154 | */ | ||
155 | oldprop = (__be32 *)of_get_property(np, "reg", &len); | ||
156 | if (!oldprop) | ||
157 | continue; | ||
158 | |||
159 | /* Create a duplicate of the 'reg' property */ | ||
160 | prop = kzalloc(sizeof(*prop), GFP_KERNEL); | ||
161 | prop->length = len; | ||
162 | prop->name = kstrdup("reg", GFP_KERNEL); | ||
163 | prop->value = kzalloc(len, GFP_KERNEL); | ||
164 | memcpy(prop->value, oldprop, len); | ||
165 | |||
166 | /* Fixup the register offset of the second entry */ | ||
167 | oldprop += 2; | ||
168 | newprop = (__be32 *)prop->value + 2; | ||
169 | newval = cpu_to_be32(be32_to_cpu(*oldprop) - | ||
170 | A375_Z1_THERMAL_FIXUP_OFFSET); | ||
171 | *newprop = newval; | ||
172 | of_update_property(np, prop); | ||
173 | |||
174 | /* | ||
175 | * The thermal controller needs some quirk too, so let's change | ||
176 | * the compatible string to reflect this and allow the driver | ||
177 | * the take the necessary action. | ||
178 | */ | ||
179 | prop = kzalloc(sizeof(*prop), GFP_KERNEL); | ||
180 | prop->name = kstrdup("compatible", GFP_KERNEL); | ||
181 | prop->length = sizeof("marvell,armada375-z1-thermal"); | ||
182 | prop->value = kstrdup("marvell,armada375-z1-thermal", | ||
183 | GFP_KERNEL); | ||
184 | of_update_property(np, prop); | ||
185 | } | ||
186 | return; | ||
187 | } | ||
188 | |||
189 | static void __init mvebu_dt_init(void) | 127 | static void __init mvebu_dt_init(void) |
190 | { | 128 | { |
191 | if (of_machine_is_compatible("plathome,openblocks-ax3-4")) | 129 | if (of_machine_is_compatible("marvell,armadaxp")) |
192 | i2c_quirk(); | 130 | i2c_quirk(); |
193 | if (of_machine_is_compatible("marvell,a375-db")) { | 131 | if (of_machine_is_compatible("marvell,a375-db")) |
194 | external_abort_quirk(); | 132 | external_abort_quirk(); |
195 | thermal_quirk(); | ||
196 | } | ||
197 | 133 | ||
198 | of_platform_populate(NULL, of_default_bus_match_table, NULL, NULL); | 134 | of_platform_populate(NULL, of_default_bus_match_table, NULL, NULL); |
199 | } | 135 | } |
@@ -206,6 +142,11 @@ static const char * const armada_370_xp_dt_compat[] = { | |||
206 | DT_MACHINE_START(ARMADA_370_XP_DT, "Marvell Armada 370/XP (Device Tree)") | 142 | DT_MACHINE_START(ARMADA_370_XP_DT, "Marvell Armada 370/XP (Device Tree)") |
207 | .l2c_aux_val = 0, | 143 | .l2c_aux_val = 0, |
208 | .l2c_aux_mask = ~0, | 144 | .l2c_aux_mask = ~0, |
145 | /* | ||
146 | * The following field (.smp) is still needed to ensure backward | ||
147 | * compatibility with old Device Trees that were not specifying the | ||
148 | * cpus enable-method property. | ||
149 | */ | ||
209 | .smp = smp_ops(armada_xp_smp_ops), | 150 | .smp = smp_ops(armada_xp_smp_ops), |
210 | .init_machine = mvebu_dt_init, | 151 | .init_machine = mvebu_dt_init, |
211 | .init_irq = mvebu_init_irq, | 152 | .init_irq = mvebu_init_irq, |
diff --git a/arch/arm/mach-mvebu/coherency.c b/arch/arm/mach-mvebu/coherency.c index 2bdc3233abe2..3585cb394e9b 100644 --- a/arch/arm/mach-mvebu/coherency.c +++ b/arch/arm/mach-mvebu/coherency.c | |||
@@ -1,5 +1,6 @@ | |||
1 | /* | 1 | /* |
2 | * Coherency fabric (Aurora) support for Armada 370 and XP platforms. | 2 | * Coherency fabric (Aurora) support for Armada 370, 375, 38x and XP |
3 | * platforms. | ||
3 | * | 4 | * |
4 | * Copyright (C) 2012 Marvell | 5 | * Copyright (C) 2012 Marvell |
5 | * | 6 | * |
@@ -11,7 +12,7 @@ | |||
11 | * License version 2. This program is licensed "as is" without any | 12 | * License version 2. This program is licensed "as is" without any |
12 | * warranty of any kind, whether express or implied. | 13 | * warranty of any kind, whether express or implied. |
13 | * | 14 | * |
14 | * The Armada 370 and Armada XP SOCs have a coherency fabric which is | 15 | * The Armada 370, 375, 38x and XP SOCs have a coherency fabric which is |
15 | * responsible for ensuring hardware coherency between all CPUs and between | 16 | * responsible for ensuring hardware coherency between all CPUs and between |
16 | * CPUs and I/O masters. This file initializes the coherency fabric and | 17 | * CPUs and I/O masters. This file initializes the coherency fabric and |
17 | * supplies basic routines for configuring and controlling hardware coherency | 18 | * supplies basic routines for configuring and controlling hardware coherency |
@@ -28,12 +29,10 @@ | |||
28 | #include <linux/platform_device.h> | 29 | #include <linux/platform_device.h> |
29 | #include <linux/slab.h> | 30 | #include <linux/slab.h> |
30 | #include <linux/mbus.h> | 31 | #include <linux/mbus.h> |
31 | #include <linux/clk.h> | ||
32 | #include <linux/pci.h> | 32 | #include <linux/pci.h> |
33 | #include <asm/smp_plat.h> | 33 | #include <asm/smp_plat.h> |
34 | #include <asm/cacheflush.h> | 34 | #include <asm/cacheflush.h> |
35 | #include <asm/mach/map.h> | 35 | #include <asm/mach/map.h> |
36 | #include "armada-370-xp.h" | ||
37 | #include "coherency.h" | 36 | #include "coherency.h" |
38 | #include "mvebu-soc-id.h" | 37 | #include "mvebu-soc-id.h" |
39 | 38 | ||
@@ -42,8 +41,6 @@ void __iomem *coherency_base; | |||
42 | static void __iomem *coherency_cpu_base; | 41 | static void __iomem *coherency_cpu_base; |
43 | 42 | ||
44 | /* Coherency fabric registers */ | 43 | /* Coherency fabric registers */ |
45 | #define COHERENCY_FABRIC_CFG_OFFSET 0x4 | ||
46 | |||
47 | #define IO_SYNC_BARRIER_CTL_OFFSET 0x0 | 44 | #define IO_SYNC_BARRIER_CTL_OFFSET 0x0 |
48 | 45 | ||
49 | enum { | 46 | enum { |
@@ -79,157 +76,8 @@ int set_cpu_coherent(void) | |||
79 | return ll_enable_coherency(); | 76 | return ll_enable_coherency(); |
80 | } | 77 | } |
81 | 78 | ||
82 | /* | ||
83 | * The below code implements the I/O coherency workaround on Armada | ||
84 | * 375. This workaround consists in using the two channels of the | ||
85 | * first XOR engine to trigger a XOR transaction that serves as the | ||
86 | * I/O coherency barrier. | ||
87 | */ | ||
88 | |||
89 | static void __iomem *xor_base, *xor_high_base; | ||
90 | static dma_addr_t coherency_wa_buf_phys[CONFIG_NR_CPUS]; | ||
91 | static void *coherency_wa_buf[CONFIG_NR_CPUS]; | ||
92 | static bool coherency_wa_enabled; | ||
93 | |||
94 | #define XOR_CONFIG(chan) (0x10 + (chan * 4)) | ||
95 | #define XOR_ACTIVATION(chan) (0x20 + (chan * 4)) | ||
96 | #define WINDOW_BAR_ENABLE(chan) (0x240 + ((chan) << 2)) | ||
97 | #define WINDOW_BASE(w) (0x250 + ((w) << 2)) | ||
98 | #define WINDOW_SIZE(w) (0x270 + ((w) << 2)) | ||
99 | #define WINDOW_REMAP_HIGH(w) (0x290 + ((w) << 2)) | ||
100 | #define WINDOW_OVERRIDE_CTRL(chan) (0x2A0 + ((chan) << 2)) | ||
101 | #define XOR_DEST_POINTER(chan) (0x2B0 + (chan * 4)) | ||
102 | #define XOR_BLOCK_SIZE(chan) (0x2C0 + (chan * 4)) | ||
103 | #define XOR_INIT_VALUE_LOW 0x2E0 | ||
104 | #define XOR_INIT_VALUE_HIGH 0x2E4 | ||
105 | |||
106 | static inline void mvebu_hwcc_armada375_sync_io_barrier_wa(void) | ||
107 | { | ||
108 | int idx = smp_processor_id(); | ||
109 | |||
110 | /* Write '1' to the first word of the buffer */ | ||
111 | writel(0x1, coherency_wa_buf[idx]); | ||
112 | |||
113 | /* Wait until the engine is idle */ | ||
114 | while ((readl(xor_base + XOR_ACTIVATION(idx)) >> 4) & 0x3) | ||
115 | ; | ||
116 | |||
117 | dmb(); | ||
118 | |||
119 | /* Trigger channel */ | ||
120 | writel(0x1, xor_base + XOR_ACTIVATION(idx)); | ||
121 | |||
122 | /* Poll the data until it is cleared by the XOR transaction */ | ||
123 | while (readl(coherency_wa_buf[idx])) | ||
124 | ; | ||
125 | } | ||
126 | |||
127 | static void __init armada_375_coherency_init_wa(void) | ||
128 | { | ||
129 | const struct mbus_dram_target_info *dram; | ||
130 | struct device_node *xor_node; | ||
131 | struct property *xor_status; | ||
132 | struct clk *xor_clk; | ||
133 | u32 win_enable = 0; | ||
134 | int i; | ||
135 | |||
136 | pr_warn("enabling coherency workaround for Armada 375 Z1, one XOR engine disabled\n"); | ||
137 | |||
138 | /* | ||
139 | * Since the workaround uses one XOR engine, we grab a | ||
140 | * reference to its Device Tree node first. | ||
141 | */ | ||
142 | xor_node = of_find_compatible_node(NULL, NULL, "marvell,orion-xor"); | ||
143 | BUG_ON(!xor_node); | ||
144 | |||
145 | /* | ||
146 | * Then we mark it as disabled so that the real XOR driver | ||
147 | * will not use it. | ||
148 | */ | ||
149 | xor_status = kzalloc(sizeof(struct property), GFP_KERNEL); | ||
150 | BUG_ON(!xor_status); | ||
151 | |||
152 | xor_status->value = kstrdup("disabled", GFP_KERNEL); | ||
153 | BUG_ON(!xor_status->value); | ||
154 | |||
155 | xor_status->length = 8; | ||
156 | xor_status->name = kstrdup("status", GFP_KERNEL); | ||
157 | BUG_ON(!xor_status->name); | ||
158 | |||
159 | of_update_property(xor_node, xor_status); | ||
160 | |||
161 | /* | ||
162 | * And we remap the registers, get the clock, and do the | ||
163 | * initial configuration of the XOR engine. | ||
164 | */ | ||
165 | xor_base = of_iomap(xor_node, 0); | ||
166 | xor_high_base = of_iomap(xor_node, 1); | ||
167 | |||
168 | xor_clk = of_clk_get_by_name(xor_node, NULL); | ||
169 | BUG_ON(!xor_clk); | ||
170 | |||
171 | clk_prepare_enable(xor_clk); | ||
172 | |||
173 | dram = mv_mbus_dram_info(); | ||
174 | |||
175 | for (i = 0; i < 8; i++) { | ||
176 | writel(0, xor_base + WINDOW_BASE(i)); | ||
177 | writel(0, xor_base + WINDOW_SIZE(i)); | ||
178 | if (i < 4) | ||
179 | writel(0, xor_base + WINDOW_REMAP_HIGH(i)); | ||
180 | } | ||
181 | |||
182 | for (i = 0; i < dram->num_cs; i++) { | ||
183 | const struct mbus_dram_window *cs = dram->cs + i; | ||
184 | writel((cs->base & 0xffff0000) | | ||
185 | (cs->mbus_attr << 8) | | ||
186 | dram->mbus_dram_target_id, xor_base + WINDOW_BASE(i)); | ||
187 | writel((cs->size - 1) & 0xffff0000, xor_base + WINDOW_SIZE(i)); | ||
188 | |||
189 | win_enable |= (1 << i); | ||
190 | win_enable |= 3 << (16 + (2 * i)); | ||
191 | } | ||
192 | |||
193 | writel(win_enable, xor_base + WINDOW_BAR_ENABLE(0)); | ||
194 | writel(win_enable, xor_base + WINDOW_BAR_ENABLE(1)); | ||
195 | writel(0, xor_base + WINDOW_OVERRIDE_CTRL(0)); | ||
196 | writel(0, xor_base + WINDOW_OVERRIDE_CTRL(1)); | ||
197 | |||
198 | for (i = 0; i < CONFIG_NR_CPUS; i++) { | ||
199 | coherency_wa_buf[i] = kzalloc(PAGE_SIZE, GFP_KERNEL); | ||
200 | BUG_ON(!coherency_wa_buf[i]); | ||
201 | |||
202 | /* | ||
203 | * We can't use the DMA mapping API, since we don't | ||
204 | * have a valid 'struct device' pointer | ||
205 | */ | ||
206 | coherency_wa_buf_phys[i] = | ||
207 | virt_to_phys(coherency_wa_buf[i]); | ||
208 | BUG_ON(!coherency_wa_buf_phys[i]); | ||
209 | |||
210 | /* | ||
211 | * Configure the XOR engine for memset operation, with | ||
212 | * a 128 bytes block size | ||
213 | */ | ||
214 | writel(0x444, xor_base + XOR_CONFIG(i)); | ||
215 | writel(128, xor_base + XOR_BLOCK_SIZE(i)); | ||
216 | writel(coherency_wa_buf_phys[i], | ||
217 | xor_base + XOR_DEST_POINTER(i)); | ||
218 | } | ||
219 | |||
220 | writel(0x0, xor_base + XOR_INIT_VALUE_LOW); | ||
221 | writel(0x0, xor_base + XOR_INIT_VALUE_HIGH); | ||
222 | |||
223 | coherency_wa_enabled = true; | ||
224 | } | ||
225 | |||
226 | static inline void mvebu_hwcc_sync_io_barrier(void) | 79 | static inline void mvebu_hwcc_sync_io_barrier(void) |
227 | { | 80 | { |
228 | if (coherency_wa_enabled) { | ||
229 | mvebu_hwcc_armada375_sync_io_barrier_wa(); | ||
230 | return; | ||
231 | } | ||
232 | |||
233 | writel(0x1, coherency_cpu_base + IO_SYNC_BARRIER_CTL_OFFSET); | 81 | writel(0x1, coherency_cpu_base + IO_SYNC_BARRIER_CTL_OFFSET); |
234 | while (readl(coherency_cpu_base + IO_SYNC_BARRIER_CTL_OFFSET) & 0x1); | 82 | while (readl(coherency_cpu_base + IO_SYNC_BARRIER_CTL_OFFSET) & 0x1); |
235 | } | 83 | } |
@@ -361,25 +209,41 @@ static int coherency_type(void) | |||
361 | { | 209 | { |
362 | struct device_node *np; | 210 | struct device_node *np; |
363 | const struct of_device_id *match; | 211 | const struct of_device_id *match; |
212 | int type; | ||
364 | 213 | ||
365 | np = of_find_matching_node_and_match(NULL, of_coherency_table, &match); | 214 | /* |
366 | if (np) { | 215 | * The coherency fabric is needed: |
367 | int type = (int) match->data; | 216 | * - For coherency between processors on Armada XP, so only |
217 | * when SMP is enabled. | ||
218 | * - For coherency between the processor and I/O devices, but | ||
219 | * this coherency requires many pre-requisites (write | ||
220 | * allocate cache policy, shareable pages, SMP bit set) that | ||
221 | * are only meant in SMP situations. | ||
222 | * | ||
223 | * Note that this means that on Armada 370, there is currently | ||
224 | * no way to use hardware I/O coherency, because even when | ||
225 | * CONFIG_SMP is enabled, is_smp() returns false due to the | ||
226 | * Armada 370 being a single-core processor. To lift this | ||
227 | * limitation, we would have to find a way to make the cache | ||
228 | * policy set to write-allocate (on all Armada SoCs), and to | ||
229 | * set the shareable attribute in page tables (on all Armada | ||
230 | * SoCs except the Armada 370). Unfortunately, such decisions | ||
231 | * are taken very early in the kernel boot process, at a point | ||
232 | * where we don't know yet on which SoC we are running. | ||
368 | 233 | ||
369 | /* Armada 370/XP coherency works in both UP and SMP */ | 234 | */ |
370 | if (type == COHERENCY_FABRIC_TYPE_ARMADA_370_XP) | 235 | if (!is_smp()) |
371 | return type; | 236 | return COHERENCY_FABRIC_TYPE_NONE; |
372 | 237 | ||
373 | /* Armada 375 coherency works only on SMP */ | 238 | np = of_find_matching_node_and_match(NULL, of_coherency_table, &match); |
374 | else if (type == COHERENCY_FABRIC_TYPE_ARMADA_375 && is_smp()) | 239 | if (!np) |
375 | return type; | 240 | return COHERENCY_FABRIC_TYPE_NONE; |
376 | 241 | ||
377 | /* Armada 380 coherency works only on SMP */ | 242 | type = (int) match->data; |
378 | else if (type == COHERENCY_FABRIC_TYPE_ARMADA_380 && is_smp()) | ||
379 | return type; | ||
380 | } | ||
381 | 243 | ||
382 | return COHERENCY_FABRIC_TYPE_NONE; | 244 | of_node_put(np); |
245 | |||
246 | return type; | ||
383 | } | 247 | } |
384 | 248 | ||
385 | int coherency_available(void) | 249 | int coherency_available(void) |
@@ -400,27 +264,16 @@ int __init coherency_init(void) | |||
400 | type == COHERENCY_FABRIC_TYPE_ARMADA_380) | 264 | type == COHERENCY_FABRIC_TYPE_ARMADA_380) |
401 | armada_375_380_coherency_init(np); | 265 | armada_375_380_coherency_init(np); |
402 | 266 | ||
267 | of_node_put(np); | ||
268 | |||
403 | return 0; | 269 | return 0; |
404 | } | 270 | } |
405 | 271 | ||
406 | static int __init coherency_late_init(void) | 272 | static int __init coherency_late_init(void) |
407 | { | 273 | { |
408 | int type = coherency_type(); | 274 | if (coherency_available()) |
409 | 275 | bus_register_notifier(&platform_bus_type, | |
410 | if (type == COHERENCY_FABRIC_TYPE_NONE) | 276 | &mvebu_hwcc_nb); |
411 | return 0; | ||
412 | |||
413 | if (type == COHERENCY_FABRIC_TYPE_ARMADA_375) { | ||
414 | u32 dev, rev; | ||
415 | |||
416 | if (mvebu_get_soc_id(&dev, &rev) == 0 && | ||
417 | rev == ARMADA_375_Z1_REV) | ||
418 | armada_375_coherency_init_wa(); | ||
419 | } | ||
420 | |||
421 | bus_register_notifier(&platform_bus_type, | ||
422 | &mvebu_hwcc_nb); | ||
423 | |||
424 | return 0; | 277 | return 0; |
425 | } | 278 | } |
426 | 279 | ||
diff --git a/arch/arm/mach-mvebu/coherency_ll.S b/arch/arm/mach-mvebu/coherency_ll.S index f5d881b5d0f7..8b2fbc8b6bc6 100644 --- a/arch/arm/mach-mvebu/coherency_ll.S +++ b/arch/arm/mach-mvebu/coherency_ll.S | |||
@@ -24,7 +24,10 @@ | |||
24 | #include <asm/cp15.h> | 24 | #include <asm/cp15.h> |
25 | 25 | ||
26 | .text | 26 | .text |
27 | /* Returns the coherency base address in r1 (r0 is untouched) */ | 27 | /* |
28 | * Returns the coherency base address in r1 (r0 is untouched), or 0 if | ||
29 | * the coherency fabric is not enabled. | ||
30 | */ | ||
28 | ENTRY(ll_get_coherency_base) | 31 | ENTRY(ll_get_coherency_base) |
29 | mrc p15, 0, r1, c1, c0, 0 | 32 | mrc p15, 0, r1, c1, c0, 0 |
30 | tst r1, #CR_M @ Check MMU bit enabled | 33 | tst r1, #CR_M @ Check MMU bit enabled |
@@ -32,8 +35,13 @@ ENTRY(ll_get_coherency_base) | |||
32 | 35 | ||
33 | /* | 36 | /* |
34 | * MMU is disabled, use the physical address of the coherency | 37 | * MMU is disabled, use the physical address of the coherency |
35 | * base address. | 38 | * base address. However, if the coherency fabric isn't mapped |
39 | * (i.e its virtual address is zero), it means coherency is | ||
40 | * not enabled, so we return 0. | ||
36 | */ | 41 | */ |
42 | ldr r1, =coherency_base | ||
43 | cmp r1, #0 | ||
44 | beq 2f | ||
37 | adr r1, 3f | 45 | adr r1, 3f |
38 | ldr r3, [r1] | 46 | ldr r3, [r1] |
39 | ldr r1, [r1, r3] | 47 | ldr r1, [r1, r3] |
@@ -85,6 +93,9 @@ ENTRY(ll_add_cpu_to_smp_group) | |||
85 | */ | 93 | */ |
86 | mov r0, lr | 94 | mov r0, lr |
87 | bl ll_get_coherency_base | 95 | bl ll_get_coherency_base |
96 | /* Bail out if the coherency is not enabled */ | ||
97 | cmp r1, #0 | ||
98 | reteq r0 | ||
88 | bl ll_get_coherency_cpumask | 99 | bl ll_get_coherency_cpumask |
89 | mov lr, r0 | 100 | mov lr, r0 |
90 | add r0, r1, #ARMADA_XP_CFB_CFG_REG_OFFSET | 101 | add r0, r1, #ARMADA_XP_CFB_CFG_REG_OFFSET |
@@ -107,6 +118,9 @@ ENTRY(ll_enable_coherency) | |||
107 | */ | 118 | */ |
108 | mov r0, lr | 119 | mov r0, lr |
109 | bl ll_get_coherency_base | 120 | bl ll_get_coherency_base |
121 | /* Bail out if the coherency is not enabled */ | ||
122 | cmp r1, #0 | ||
123 | reteq r0 | ||
110 | bl ll_get_coherency_cpumask | 124 | bl ll_get_coherency_cpumask |
111 | mov lr, r0 | 125 | mov lr, r0 |
112 | add r0, r1, #ARMADA_XP_CFB_CTL_REG_OFFSET | 126 | add r0, r1, #ARMADA_XP_CFB_CTL_REG_OFFSET |
@@ -131,6 +145,9 @@ ENTRY(ll_disable_coherency) | |||
131 | */ | 145 | */ |
132 | mov r0, lr | 146 | mov r0, lr |
133 | bl ll_get_coherency_base | 147 | bl ll_get_coherency_base |
148 | /* Bail out if the coherency is not enabled */ | ||
149 | cmp r1, #0 | ||
150 | reteq r0 | ||
134 | bl ll_get_coherency_cpumask | 151 | bl ll_get_coherency_cpumask |
135 | mov lr, r0 | 152 | mov lr, r0 |
136 | add r0, r1, #ARMADA_XP_CFB_CTL_REG_OFFSET | 153 | add r0, r1, #ARMADA_XP_CFB_CTL_REG_OFFSET |
diff --git a/arch/arm/mach-mvebu/cpu-reset.c b/arch/arm/mach-mvebu/cpu-reset.c index 60fb53787004..4a2cadd6b48e 100644 --- a/arch/arm/mach-mvebu/cpu-reset.c +++ b/arch/arm/mach-mvebu/cpu-reset.c | |||
@@ -15,7 +15,6 @@ | |||
15 | #include <linux/of_address.h> | 15 | #include <linux/of_address.h> |
16 | #include <linux/io.h> | 16 | #include <linux/io.h> |
17 | #include <linux/resource.h> | 17 | #include <linux/resource.h> |
18 | #include "armada-370-xp.h" | ||
19 | 18 | ||
20 | static void __iomem *cpu_reset_base; | 19 | static void __iomem *cpu_reset_base; |
21 | static size_t cpu_reset_size; | 20 | static size_t cpu_reset_size; |
diff --git a/arch/arm/mach-mvebu/headsmp-a9.S b/arch/arm/mach-mvebu/headsmp-a9.S index be51c998c0cd..08d5ed46b996 100644 --- a/arch/arm/mach-mvebu/headsmp-a9.S +++ b/arch/arm/mach-mvebu/headsmp-a9.S | |||
@@ -22,5 +22,6 @@ | |||
22 | ENTRY(mvebu_cortex_a9_secondary_startup) | 22 | ENTRY(mvebu_cortex_a9_secondary_startup) |
23 | ARM_BE8(setend be) | 23 | ARM_BE8(setend be) |
24 | bl v7_invalidate_l1 | 24 | bl v7_invalidate_l1 |
25 | bl armada_38x_scu_power_up | ||
25 | b secondary_startup | 26 | b secondary_startup |
26 | ENDPROC(mvebu_cortex_a9_secondary_startup) | 27 | ENDPROC(mvebu_cortex_a9_secondary_startup) |
diff --git a/arch/arm/mach-mvebu/platsmp-a9.c b/arch/arm/mach-mvebu/platsmp-a9.c index 47a71a924b96..2ec1a42b4321 100644 --- a/arch/arm/mach-mvebu/platsmp-a9.c +++ b/arch/arm/mach-mvebu/platsmp-a9.c | |||
@@ -43,21 +43,70 @@ static int __cpuinit mvebu_cortex_a9_boot_secondary(unsigned int cpu, | |||
43 | else | 43 | else |
44 | mvebu_pmsu_set_cpu_boot_addr(hw_cpu, mvebu_cortex_a9_secondary_startup); | 44 | mvebu_pmsu_set_cpu_boot_addr(hw_cpu, mvebu_cortex_a9_secondary_startup); |
45 | smp_wmb(); | 45 | smp_wmb(); |
46 | |||
47 | /* | ||
48 | * Doing this before deasserting the CPUs is needed to wake up CPUs | ||
49 | * in the offline state after using CPU hotplug. | ||
50 | */ | ||
51 | arch_send_wakeup_ipi_mask(cpumask_of(cpu)); | ||
52 | |||
46 | ret = mvebu_cpu_reset_deassert(hw_cpu); | 53 | ret = mvebu_cpu_reset_deassert(hw_cpu); |
47 | if (ret) { | 54 | if (ret) { |
48 | pr_err("Could not start the secondary CPU: %d\n", ret); | 55 | pr_err("Could not start the secondary CPU: %d\n", ret); |
49 | return ret; | 56 | return ret; |
50 | } | 57 | } |
51 | arch_send_wakeup_ipi_mask(cpumask_of(cpu)); | ||
52 | 58 | ||
53 | return 0; | 59 | return 0; |
54 | } | 60 | } |
61 | /* | ||
62 | * When a CPU is brought back online, either through CPU hotplug, or | ||
63 | * because of the boot of a kexec'ed kernel, the PMSU configuration | ||
64 | * for this CPU might be in the deep idle state, preventing this CPU | ||
65 | * from receiving interrupts. Here, we therefore take out the current | ||
66 | * CPU from this state, which was entered by armada_38x_cpu_die() | ||
67 | * below. | ||
68 | */ | ||
69 | static void armada_38x_secondary_init(unsigned int cpu) | ||
70 | { | ||
71 | mvebu_v7_pmsu_idle_exit(); | ||
72 | } | ||
73 | |||
74 | #ifdef CONFIG_HOTPLUG_CPU | ||
75 | static void armada_38x_cpu_die(unsigned int cpu) | ||
76 | { | ||
77 | /* | ||
78 | * CPU hotplug is implemented by putting offline CPUs into the | ||
79 | * deep idle sleep state. | ||
80 | */ | ||
81 | armada_38x_do_cpu_suspend(true); | ||
82 | } | ||
83 | |||
84 | /* | ||
85 | * We need a dummy function, so that platform_can_cpu_hotplug() knows | ||
86 | * we support CPU hotplug. However, the function does not need to do | ||
87 | * anything, because CPUs going offline can enter the deep idle state | ||
88 | * by themselves, without any help from a still alive CPU. | ||
89 | */ | ||
90 | static int armada_38x_cpu_kill(unsigned int cpu) | ||
91 | { | ||
92 | return 1; | ||
93 | } | ||
94 | #endif | ||
55 | 95 | ||
56 | static struct smp_operations mvebu_cortex_a9_smp_ops __initdata = { | 96 | static struct smp_operations mvebu_cortex_a9_smp_ops __initdata = { |
57 | .smp_boot_secondary = mvebu_cortex_a9_boot_secondary, | 97 | .smp_boot_secondary = mvebu_cortex_a9_boot_secondary, |
58 | }; | 98 | }; |
59 | 99 | ||
100 | static struct smp_operations armada_38x_smp_ops __initdata = { | ||
101 | .smp_boot_secondary = mvebu_cortex_a9_boot_secondary, | ||
102 | .smp_secondary_init = armada_38x_secondary_init, | ||
103 | #ifdef CONFIG_HOTPLUG_CPU | ||
104 | .cpu_die = armada_38x_cpu_die, | ||
105 | .cpu_kill = armada_38x_cpu_kill, | ||
106 | #endif | ||
107 | }; | ||
108 | |||
60 | CPU_METHOD_OF_DECLARE(mvebu_armada_375_smp, "marvell,armada-375-smp", | 109 | CPU_METHOD_OF_DECLARE(mvebu_armada_375_smp, "marvell,armada-375-smp", |
61 | &mvebu_cortex_a9_smp_ops); | 110 | &mvebu_cortex_a9_smp_ops); |
62 | CPU_METHOD_OF_DECLARE(mvebu_armada_380_smp, "marvell,armada-380-smp", | 111 | CPU_METHOD_OF_DECLARE(mvebu_armada_380_smp, "marvell,armada-380-smp", |
63 | &mvebu_cortex_a9_smp_ops); | 112 | &armada_38x_smp_ops); |
diff --git a/arch/arm/mach-mvebu/platsmp.c b/arch/arm/mach-mvebu/platsmp.c index 895dc373c8a1..622315c185b2 100644 --- a/arch/arm/mach-mvebu/platsmp.c +++ b/arch/arm/mach-mvebu/platsmp.c | |||
@@ -30,6 +30,8 @@ | |||
30 | #include "pmsu.h" | 30 | #include "pmsu.h" |
31 | #include "coherency.h" | 31 | #include "coherency.h" |
32 | 32 | ||
33 | #define ARMADA_XP_MAX_CPUS 4 | ||
34 | |||
33 | #define AXP_BOOTROM_BASE 0xfff00000 | 35 | #define AXP_BOOTROM_BASE 0xfff00000 |
34 | #define AXP_BOOTROM_SIZE 0x100000 | 36 | #define AXP_BOOTROM_SIZE 0x100000 |
35 | 37 | ||
diff --git a/arch/arm/mach-mvebu/pmsu.c b/arch/arm/mach-mvebu/pmsu.c index bbd8664d1bac..5a757f929927 100644 --- a/arch/arm/mach-mvebu/pmsu.c +++ b/arch/arm/mach-mvebu/pmsu.c | |||
@@ -39,7 +39,6 @@ | |||
39 | #include <asm/suspend.h> | 39 | #include <asm/suspend.h> |
40 | #include <asm/tlbflush.h> | 40 | #include <asm/tlbflush.h> |
41 | #include "common.h" | 41 | #include "common.h" |
42 | #include "armada-370-xp.h" | ||
43 | 42 | ||
44 | 43 | ||
45 | #define PMSU_BASE_OFFSET 0x100 | 44 | #define PMSU_BASE_OFFSET 0x100 |
@@ -312,7 +311,7 @@ static int armada_370_xp_cpu_suspend(unsigned long deepidle) | |||
312 | return cpu_suspend(deepidle, armada_370_xp_pmsu_idle_enter); | 311 | return cpu_suspend(deepidle, armada_370_xp_pmsu_idle_enter); |
313 | } | 312 | } |
314 | 313 | ||
315 | static int armada_38x_do_cpu_suspend(unsigned long deepidle) | 314 | int armada_38x_do_cpu_suspend(unsigned long deepidle) |
316 | { | 315 | { |
317 | unsigned long flags = 0; | 316 | unsigned long flags = 0; |
318 | 317 | ||
diff --git a/arch/arm/mach-mvebu/pmsu.h b/arch/arm/mach-mvebu/pmsu.h index 6b58c1fe2b0d..c2c95db4f648 100644 --- a/arch/arm/mach-mvebu/pmsu.h +++ b/arch/arm/mach-mvebu/pmsu.h | |||
@@ -18,4 +18,6 @@ int mvebu_setup_boot_addr_wa(unsigned int crypto_eng_target, | |||
18 | 18 | ||
19 | void mvebu_v7_pmsu_idle_exit(void); | 19 | void mvebu_v7_pmsu_idle_exit(void); |
20 | 20 | ||
21 | int armada_370_xp_pmsu_idle_enter(unsigned long deepidle); | ||
22 | int armada_38x_do_cpu_suspend(unsigned long deepidle); | ||
21 | #endif /* __MACH_370_XP_PMSU_H */ | 23 | #endif /* __MACH_370_XP_PMSU_H */ |
diff --git a/arch/arm/mach-mvebu/pmsu_ll.S b/arch/arm/mach-mvebu/pmsu_ll.S index a945756cfb45..83d014698314 100644 --- a/arch/arm/mach-mvebu/pmsu_ll.S +++ b/arch/arm/mach-mvebu/pmsu_ll.S | |||
@@ -12,6 +12,18 @@ | |||
12 | #include <linux/linkage.h> | 12 | #include <linux/linkage.h> |
13 | #include <asm/assembler.h> | 13 | #include <asm/assembler.h> |
14 | 14 | ||
15 | |||
16 | ENTRY(armada_38x_scu_power_up) | ||
17 | mrc p15, 4, r1, c15, c0 @ get SCU base address | ||
18 | orr r1, r1, #0x8 @ SCU CPU Power Status Register | ||
19 | mrc 15, 0, r0, cr0, cr0, 5 @ get the CPU ID | ||
20 | and r0, r0, #15 | ||
21 | add r1, r1, r0 | ||
22 | mov r0, #0x0 | ||
23 | strb r0, [r1] @ switch SCU power state to Normal mode | ||
24 | ret lr | ||
25 | ENDPROC(armada_38x_scu_power_up) | ||
26 | |||
15 | /* | 27 | /* |
16 | * This is the entry point through which CPUs exiting cpuidle deep | 28 | * This is the entry point through which CPUs exiting cpuidle deep |
17 | * idle state are going. | 29 | * idle state are going. |
@@ -27,13 +39,7 @@ ENTRY(armada_38x_cpu_resume) | |||
27 | /* do we need it for Armada 38x*/ | 39 | /* do we need it for Armada 38x*/ |
28 | ARM_BE8(setend be ) @ go BE8 if entered LE | 40 | ARM_BE8(setend be ) @ go BE8 if entered LE |
29 | bl v7_invalidate_l1 | 41 | bl v7_invalidate_l1 |
30 | mrc p15, 4, r1, c15, c0 @ get SCU base address | 42 | bl armada_38x_scu_power_up |
31 | orr r1, r1, #0x8 @ SCU CPU Power Status Register | ||
32 | mrc 15, 0, r0, cr0, cr0, 5 @ get the CPU ID | ||
33 | and r0, r0, #15 | ||
34 | add r1, r1, r0 | ||
35 | mov r0, #0x0 | ||
36 | strb r0, [r1] @ switch SCU power state to Normal mode | ||
37 | b cpu_resume | 43 | b cpu_resume |
38 | ENDPROC(armada_38x_cpu_resume) | 44 | ENDPROC(armada_38x_cpu_resume) |
39 | 45 | ||
diff --git a/arch/arm/plat-orion/gpio.c b/arch/arm/plat-orion/gpio.c index b61a3bcc2fa8..e048f6198d68 100644 --- a/arch/arm/plat-orion/gpio.c +++ b/arch/arm/plat-orion/gpio.c | |||
@@ -497,6 +497,34 @@ static void orion_gpio_dbg_show(struct seq_file *s, struct gpio_chip *chip) | |||
497 | #define orion_gpio_dbg_show NULL | 497 | #define orion_gpio_dbg_show NULL |
498 | #endif | 498 | #endif |
499 | 499 | ||
500 | static void orion_gpio_unmask_irq(struct irq_data *d) | ||
501 | { | ||
502 | struct irq_chip_generic *gc = irq_data_get_irq_chip_data(d); | ||
503 | struct irq_chip_type *ct = irq_data_get_chip_type(d); | ||
504 | u32 reg_val; | ||
505 | u32 mask = d->mask; | ||
506 | |||
507 | irq_gc_lock(gc); | ||
508 | reg_val = irq_reg_readl(gc->reg_base + ct->regs.mask); | ||
509 | reg_val |= mask; | ||
510 | irq_reg_writel(reg_val, gc->reg_base + ct->regs.mask); | ||
511 | irq_gc_unlock(gc); | ||
512 | } | ||
513 | |||
514 | static void orion_gpio_mask_irq(struct irq_data *d) | ||
515 | { | ||
516 | struct irq_chip_generic *gc = irq_data_get_irq_chip_data(d); | ||
517 | struct irq_chip_type *ct = irq_data_get_chip_type(d); | ||
518 | u32 mask = d->mask; | ||
519 | u32 reg_val; | ||
520 | |||
521 | irq_gc_lock(gc); | ||
522 | reg_val = irq_reg_readl(gc->reg_base + ct->regs.mask); | ||
523 | reg_val &= ~mask; | ||
524 | irq_reg_writel(reg_val, gc->reg_base + ct->regs.mask); | ||
525 | irq_gc_unlock(gc); | ||
526 | } | ||
527 | |||
500 | void __init orion_gpio_init(struct device_node *np, | 528 | void __init orion_gpio_init(struct device_node *np, |
501 | int gpio_base, int ngpio, | 529 | int gpio_base, int ngpio, |
502 | void __iomem *base, int mask_offset, | 530 | void __iomem *base, int mask_offset, |
@@ -565,8 +593,8 @@ void __init orion_gpio_init(struct device_node *np, | |||
565 | ct = gc->chip_types; | 593 | ct = gc->chip_types; |
566 | ct->regs.mask = ochip->mask_offset + GPIO_LEVEL_MASK_OFF; | 594 | ct->regs.mask = ochip->mask_offset + GPIO_LEVEL_MASK_OFF; |
567 | ct->type = IRQ_TYPE_LEVEL_HIGH | IRQ_TYPE_LEVEL_LOW; | 595 | ct->type = IRQ_TYPE_LEVEL_HIGH | IRQ_TYPE_LEVEL_LOW; |
568 | ct->chip.irq_mask = irq_gc_mask_clr_bit; | 596 | ct->chip.irq_mask = orion_gpio_mask_irq; |
569 | ct->chip.irq_unmask = irq_gc_mask_set_bit; | 597 | ct->chip.irq_unmask = orion_gpio_unmask_irq; |
570 | ct->chip.irq_set_type = gpio_irq_set_type; | 598 | ct->chip.irq_set_type = gpio_irq_set_type; |
571 | ct->chip.name = ochip->chip.label; | 599 | ct->chip.name = ochip->chip.label; |
572 | 600 | ||
@@ -575,8 +603,8 @@ void __init orion_gpio_init(struct device_node *np, | |||
575 | ct->regs.ack = GPIO_EDGE_CAUSE_OFF; | 603 | ct->regs.ack = GPIO_EDGE_CAUSE_OFF; |
576 | ct->type = IRQ_TYPE_EDGE_RISING | IRQ_TYPE_EDGE_FALLING; | 604 | ct->type = IRQ_TYPE_EDGE_RISING | IRQ_TYPE_EDGE_FALLING; |
577 | ct->chip.irq_ack = irq_gc_ack_clr_bit; | 605 | ct->chip.irq_ack = irq_gc_ack_clr_bit; |
578 | ct->chip.irq_mask = irq_gc_mask_clr_bit; | 606 | ct->chip.irq_mask = orion_gpio_mask_irq; |
579 | ct->chip.irq_unmask = irq_gc_mask_set_bit; | 607 | ct->chip.irq_unmask = orion_gpio_unmask_irq; |
580 | ct->chip.irq_set_type = gpio_irq_set_type; | 608 | ct->chip.irq_set_type = gpio_irq_set_type; |
581 | ct->handler = handle_edge_irq; | 609 | ct->handler = handle_edge_irq; |
582 | ct->chip.name = ochip->chip.label; | 610 | ct->chip.name = ochip->chip.label; |