aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorArnd Bergmann <arnd@arndb.de>2014-11-28 16:25:11 -0500
committerArnd Bergmann <arnd@arndb.de>2014-11-28 16:25:11 -0500
commit756f80cee766574ae282baa97fdcf9cc6d0cc70c (patch)
tree3d920910511b79b829f1e9e3540fda7d2c48f366
parentd5bd4e8df43ca930ff3892963f6b3bf7984038e3 (diff)
parent626d686487bfd8136c4543bee7b6b2e52c33b3f8 (diff)
Merge tag 'mvebu-soc-3.19' of git://git.infradead.org/linux-mvebu into next/soc
Pull "mvebu SoC changes for v3.19" from Jason Cooper: - Armada 38x - Implement CPU hotplug support - Armada 375 - Remove Z1 stepping support (limited dist. of SoC) * tag 'mvebu-soc-3.19' of git://git.infradead.org/linux-mvebu: ARM: mvebu: Implement the CPU hotplug support for the Armada 38x SoCs ARM: mvebu: Fix the secondary startup for Cortex A9 SoC ARM: mvebu: Move SCU power up in a function ARM: mvebu: Clean-up the Armada XP support ARM: mvebu: update comments in coherency.c ARM: mvebu: remove Armada 375 Z1 workaround for I/O coherency ARM: mvebu: remove unused register offset definition ARM: mvebu: disable I/O coherency on non-SMP situations on Armada 370/375/38x/XP ARM: mvebu: make the coherency_ll.S functions work with no coherency fabric ARM: mvebu: Remove thermal quirk for A375 Z1 revision ARM: mvebu: add missing of_node_put() call in coherency.c ARM: orion: Fix for certain sequence of request_irq can cause irq storm ARM: mvebu: armada xp: Generalize use of i2c quirk Signed-off-by: Arnd Bergmann <arnd@arndb.de>
-rw-r--r--arch/arm/mach-mvebu/armada-370-xp.h6
-rw-r--r--arch/arm/mach-mvebu/board-v7.c73
-rw-r--r--arch/arm/mach-mvebu/coherency.c223
-rw-r--r--arch/arm/mach-mvebu/coherency_ll.S21
-rw-r--r--arch/arm/mach-mvebu/cpu-reset.c1
-rw-r--r--arch/arm/mach-mvebu/headsmp-a9.S1
-rw-r--r--arch/arm/mach-mvebu/platsmp-a9.c53
-rw-r--r--arch/arm/mach-mvebu/platsmp.c2
-rw-r--r--arch/arm/mach-mvebu/pmsu.c3
-rw-r--r--arch/arm/mach-mvebu/pmsu.h2
-rw-r--r--arch/arm/mach-mvebu/pmsu_ll.S20
-rw-r--r--arch/arm/plat-orion/gpio.c36
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
23void armada_xp_secondary_startup(void); 19void armada_xp_secondary_startup(void);
24extern struct smp_operations armada_xp_smp_ops; 20extern struct smp_operations armada_xp_smp_ops;
25#endif 21#endif
26 22
27int 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
129static 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
189static void __init mvebu_dt_init(void) 127static 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[] = {
206DT_MACHINE_START(ARMADA_370_XP_DT, "Marvell Armada 370/XP (Device Tree)") 142DT_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;
42static void __iomem *coherency_cpu_base; 41static 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
49enum { 46enum {
@@ -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
89static void __iomem *xor_base, *xor_high_base;
90static dma_addr_t coherency_wa_buf_phys[CONFIG_NR_CPUS];
91static void *coherency_wa_buf[CONFIG_NR_CPUS];
92static 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
106static 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
127static 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
226static inline void mvebu_hwcc_sync_io_barrier(void) 79static 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
385int coherency_available(void) 249int 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
406static int __init coherency_late_init(void) 272static 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 */
28ENTRY(ll_get_coherency_base) 31ENTRY(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
20static void __iomem *cpu_reset_base; 19static void __iomem *cpu_reset_base;
21static size_t cpu_reset_size; 20static 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 @@
22ENTRY(mvebu_cortex_a9_secondary_startup) 22ENTRY(mvebu_cortex_a9_secondary_startup)
23ARM_BE8(setend be) 23ARM_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
26ENDPROC(mvebu_cortex_a9_secondary_startup) 27ENDPROC(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 */
69static void armada_38x_secondary_init(unsigned int cpu)
70{
71 mvebu_v7_pmsu_idle_exit();
72}
73
74#ifdef CONFIG_HOTPLUG_CPU
75static 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 */
90static int armada_38x_cpu_kill(unsigned int cpu)
91{
92 return 1;
93}
94#endif
55 95
56static struct smp_operations mvebu_cortex_a9_smp_ops __initdata = { 96static 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
100static 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
60CPU_METHOD_OF_DECLARE(mvebu_armada_375_smp, "marvell,armada-375-smp", 109CPU_METHOD_OF_DECLARE(mvebu_armada_375_smp, "marvell,armada-375-smp",
61 &mvebu_cortex_a9_smp_ops); 110 &mvebu_cortex_a9_smp_ops);
62CPU_METHOD_OF_DECLARE(mvebu_armada_380_smp, "marvell,armada-380-smp", 111CPU_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
315static int armada_38x_do_cpu_suspend(unsigned long deepidle) 314int 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
19void mvebu_v7_pmsu_idle_exit(void); 19void mvebu_v7_pmsu_idle_exit(void);
20 20
21int armada_370_xp_pmsu_idle_enter(unsigned long deepidle);
22int 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
16ENTRY(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
25ENDPROC(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*/
28ARM_BE8(setend be ) @ go BE8 if entered LE 40ARM_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
38ENDPROC(armada_38x_cpu_resume) 44ENDPROC(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
500static 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
514static 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
500void __init orion_gpio_init(struct device_node *np, 528void __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;