aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorOlof Johansson <olof@lixom.net>2014-05-20 00:59:55 -0400
committerOlof Johansson <olof@lixom.net>2014-05-20 00:59:55 -0400
commit5df22a6148d7f073513a61eb306a98654c5a6fe8 (patch)
treed80a90222f36b303eea4f6334a3cbe6e35baeecd
parentc15c1199b0031f2dcc3437e9998e9abe99e2609c (diff)
parent9f0affcf3e21fc56d8bce625bb3d5800b7a7d284 (diff)
Merge tag 'mvebu-soc-3.16' of git://git.infradead.org/linux-mvebu into next/soc
Merge "ARM: mvebu: SoC changes for v3.16" from Jason Cooper: mvebu SoC changes for v3.16 - Armada 375/38x coherency support - Armada 375/38x SMP support - mvebu PMSU and CPU reset support - Armada 370/XP cpuidle support - kirkwood remove platform init of audio device - small fixes and cleanup for new SoC (375/38x) Note: - due to complex deps, cpuidle changes Acked by appropriate maintainer for going though arm-soc tree. * tag 'mvebu-soc-3.16' of git://git.infradead.org/linux-mvebu: (46 commits) ARM: mvebu: Fix pmsu compilation when ARMv6 is selected ARM: mvebu: conditionalize Armada 375 coherency workaround ARM: mvebu: conditionalize Armada 375 SMP workaround ARM: mvebu: add Armada 375 A0 revision definition ARM: mvebu: initialize mvebu-soc-id earlier ARM: mvebu: fix thermal quirk SoC revision check ARM: Kirkwood: t5325: Remove platform device to instantiate audio ARM: Kirkwood: Remove platform driver for codec ARM: mvebu: Add thermal quirk for the Armada 375 DB board ARM: mvebu: Select HAVE_ARM_TWD only if SMP is enabled ARM: mvebu: fix the name of the parameter used in mvebu_get_soc_id ARM: mvebu: remove unnecessary ifdef around l2x0_of_init ARM: mvebu: register the cpuidle driver for the Armada XP SoCs cpuidle: mvebu: Add initial CPU idle support for Armada 370/XP SoC ARM: mvebu: Register notifier callback for the cpuidle transition ARM: mvebu: refine which files are build in mach-mvebu ARM: mvebu: Add the PMSU related part of the cpu idle functions ARM: mvebu: Allow to power down L2 cache controller in idle mode ARM: mvebu: Low level function to disable HW coherency support ARM: mvebu: Split low level functions to manipulate HW coherency ... Signed-off-by: Olof Johansson <olof@lixom.net>
-rw-r--r--Documentation/devicetree/bindings/arm/armada-370-xp-pmsu.txt19
-rw-r--r--Documentation/devicetree/bindings/arm/armada-cpu-reset.txt14
-rw-r--r--Documentation/devicetree/bindings/arm/coherency-fabric.txt32
-rw-r--r--Documentation/devicetree/bindings/arm/cpus.txt3
-rw-r--r--arch/arm/mach-kirkwood/board-dt.c2
-rw-r--r--arch/arm/mach-mvebu/Kconfig14
-rw-r--r--arch/arm/mach-mvebu/Makefile13
-rw-r--r--arch/arm/mach-mvebu/armada-370-xp.h2
-rw-r--r--arch/arm/mach-mvebu/board-t5325.c41
-rw-r--r--arch/arm/mach-mvebu/board-v7.c82
-rw-r--r--arch/arm/mach-mvebu/board.h6
-rw-r--r--arch/arm/mach-mvebu/coherency.c280
-rw-r--r--arch/arm/mach-mvebu/coherency.h3
-rw-r--r--arch/arm/mach-mvebu/coherency_ll.S122
-rw-r--r--arch/arm/mach-mvebu/common.h3
-rw-r--r--arch/arm/mach-mvebu/cpu-reset.c103
-rw-r--r--arch/arm/mach-mvebu/dove.c2
-rw-r--r--arch/arm/mach-mvebu/headsmp-a9.S34
-rw-r--r--arch/arm/mach-mvebu/headsmp.S15
-rw-r--r--arch/arm/mach-mvebu/kirkwood.c5
-rw-r--r--arch/arm/mach-mvebu/mvebu-soc-id.c32
-rw-r--r--arch/arm/mach-mvebu/mvebu-soc-id.h4
-rw-r--r--arch/arm/mach-mvebu/platsmp-a9.c102
-rw-r--r--arch/arm/mach-mvebu/platsmp.c23
-rw-r--r--arch/arm/mach-mvebu/pmsu.c273
-rw-r--r--arch/arm/mach-mvebu/system-controller.c15
-rw-r--r--drivers/bus/mvebu-mbus.c11
-rw-r--r--drivers/cpuidle/Kconfig.arm5
-rw-r--r--drivers/cpuidle/Makefile1
-rw-r--r--drivers/cpuidle/cpuidle-armada-370-xp.c93
-rw-r--r--drivers/irqchip/irq-armada-370-xp.c24
-rw-r--r--drivers/irqchip/irq-orion.c4
-rw-r--r--include/linux/mbus.h2
33 files changed, 1178 insertions, 206 deletions
diff --git a/Documentation/devicetree/bindings/arm/armada-370-xp-pmsu.txt b/Documentation/devicetree/bindings/arm/armada-370-xp-pmsu.txt
index 926b4d6aae7e..26799ef562df 100644
--- a/Documentation/devicetree/bindings/arm/armada-370-xp-pmsu.txt
+++ b/Documentation/devicetree/bindings/arm/armada-370-xp-pmsu.txt
@@ -1,20 +1,21 @@
1Power Management Service Unit(PMSU) 1Power Management Service Unit(PMSU)
2----------------------------------- 2-----------------------------------
3Available on Marvell SOCs: Armada 370 and Armada XP 3Available on Marvell SOCs: Armada 370, Armada 38x and Armada XP
4 4
5Required properties: 5Required properties:
6 6
7- compatible: "marvell,armada-370-xp-pmsu" 7- compatible: should be one of:
8 - "marvell,armada-370-pmsu" for Armada 370 or Armada XP
9 - "marvell,armada-380-pmsu" for Armada 38x
10 - "marvell,armada-370-xp-pmsu" was used for Armada 370/XP but is now
11 deprecated and will be removed
8 12
9- reg: Should contain PMSU registers location and length. First pair 13- reg: Should contain PMSU registers location and length.
10 for the per-CPU SW Reset Control registers, second pair for the
11 Power Management Service Unit.
12 14
13Example: 15Example:
14 16
15armada-370-xp-pmsu@d0022000 { 17armada-370-xp-pmsu@22000 {
16 compatible = "marvell,armada-370-xp-pmsu"; 18 compatible = "marvell,armada-370-pmsu";
17 reg = <0xd0022100 0x430>, 19 reg = <0x22000 0x1000>;
18 <0xd0020800 0x20>;
19}; 20};
20 21
diff --git a/Documentation/devicetree/bindings/arm/armada-cpu-reset.txt b/Documentation/devicetree/bindings/arm/armada-cpu-reset.txt
new file mode 100644
index 000000000000..b63a7b6ab998
--- /dev/null
+++ b/Documentation/devicetree/bindings/arm/armada-cpu-reset.txt
@@ -0,0 +1,14 @@
1Marvell Armada CPU reset controller
2===================================
3
4Required properties:
5
6- compatible: Should be "marvell,armada-370-cpu-reset".
7
8- reg: should be register base and length as documented in the
9 datasheet for the CPU reset registers
10
11cpurst: cpurst@20800 {
12 compatible = "marvell,armada-370-cpu-reset";
13 reg = <0x20800 0x20>;
14};
diff --git a/Documentation/devicetree/bindings/arm/coherency-fabric.txt b/Documentation/devicetree/bindings/arm/coherency-fabric.txt
index 17d8cd107559..8dd46617c889 100644
--- a/Documentation/devicetree/bindings/arm/coherency-fabric.txt
+++ b/Documentation/devicetree/bindings/arm/coherency-fabric.txt
@@ -1,16 +1,33 @@
1Coherency fabric 1Coherency fabric
2---------------- 2----------------
3Available on Marvell SOCs: Armada 370 and Armada XP 3Available on Marvell SOCs: Armada 370, Armada 375, Armada 38x and Armada XP
4 4
5Required properties: 5Required properties:
6 6
7- compatible: "marvell,coherency-fabric" 7- compatible: the possible values are:
8
9 * "marvell,coherency-fabric", to be used for the coherency fabric of
10 the Armada 370 and Armada XP.
11
12 * "marvell,armada-375-coherency-fabric", for the Armada 375 coherency
13 fabric.
14
15 * "marvell,armada-380-coherency-fabric", for the Armada 38x coherency
16 fabric.
8 17
9- reg: Should contain coherency fabric registers location and 18- reg: Should contain coherency fabric registers location and
10 length. First pair for the coherency fabric registers, second pair 19 length.
11 for the per-CPU fabric registers registers. 20
21 * For "marvell,coherency-fabric", the first pair for the coherency
22 fabric registers, second pair for the per-CPU fabric registers.
12 23
13Example: 24 * For "marvell,armada-375-coherency-fabric", only one pair is needed
25 for the per-CPU fabric registers.
26
27 * For "marvell,armada-380-coherency-fabric", only one pair is needed
28 for the per-CPU fabric registers.
29
30Examples:
14 31
15coherency-fabric@d0020200 { 32coherency-fabric@d0020200 {
16 compatible = "marvell,coherency-fabric"; 33 compatible = "marvell,coherency-fabric";
@@ -19,3 +36,8 @@ coherency-fabric@d0020200 {
19 36
20}; 37};
21 38
39coherency-fabric@21810 {
40 compatible = "marvell,armada-375-coherency-fabric";
41 reg = <0x21810 0x1c>;
42};
43
diff --git a/Documentation/devicetree/bindings/arm/cpus.txt b/Documentation/devicetree/bindings/arm/cpus.txt
index 333f4aea3029..4bbcf4fb7583 100644
--- a/Documentation/devicetree/bindings/arm/cpus.txt
+++ b/Documentation/devicetree/bindings/arm/cpus.txt
@@ -185,6 +185,9 @@ nodes to be present and contain the properties described below.
185 "qcom,gcc-msm8660" 185 "qcom,gcc-msm8660"
186 "qcom,kpss-acc-v1" 186 "qcom,kpss-acc-v1"
187 "qcom,kpss-acc-v2" 187 "qcom,kpss-acc-v2"
188 "marvell,armada-375-smp"
189 "marvell,armada-380-smp"
190 "marvell,armada-xp-smp"
188 191
189 - cpu-release-addr 192 - cpu-release-addr
190 Usage: required for systems that have an "enable-method" 193 Usage: required for systems that have an "enable-method"
diff --git a/arch/arm/mach-kirkwood/board-dt.c b/arch/arm/mach-kirkwood/board-dt.c
index 2801da49e2a3..ff18ff20f71f 100644
--- a/arch/arm/mach-kirkwood/board-dt.c
+++ b/arch/arm/mach-kirkwood/board-dt.c
@@ -195,7 +195,7 @@ static void __init kirkwood_dt_init(void)
195{ 195{
196 kirkwood_disable_mbus_error_propagation(); 196 kirkwood_disable_mbus_error_propagation();
197 197
198 BUG_ON(mvebu_mbus_dt_init()); 198 BUG_ON(mvebu_mbus_dt_init(false));
199 199
200#ifdef CONFIG_CACHE_FEROCEON_L2 200#ifdef CONFIG_CACHE_FEROCEON_L2
201 feroceon_of_init(); 201 feroceon_of_init();
diff --git a/arch/arm/mach-mvebu/Kconfig b/arch/arm/mach-mvebu/Kconfig
index 3f73eecbcfb0..d6b0a772a6dd 100644
--- a/arch/arm/mach-mvebu/Kconfig
+++ b/arch/arm/mach-mvebu/Kconfig
@@ -6,6 +6,7 @@ config ARCH_MVEBU
6 select IRQ_DOMAIN 6 select IRQ_DOMAIN
7 select PINCTRL 7 select PINCTRL
8 select PLAT_ORION 8 select PLAT_ORION
9 select SOC_BUS
9 select MVEBU_MBUS 10 select MVEBU_MBUS
10 select ZONE_DMA if ARM_LPAE 11 select ZONE_DMA if ARM_LPAE
11 select ARCH_REQUIRE_GPIOLIB 12 select ARCH_REQUIRE_GPIOLIB
@@ -39,6 +40,9 @@ config MACH_ARMADA_375
39 select ARM_GIC 40 select ARM_GIC
40 select ARMADA_375_CLK 41 select ARMADA_375_CLK
41 select CPU_V7 42 select CPU_V7
43 select HAVE_ARM_SCU
44 select HAVE_ARM_TWD if SMP
45 select HAVE_SMP
42 select MACH_MVEBU_V7 46 select MACH_MVEBU_V7
43 select PINCTRL_ARMADA_375 47 select PINCTRL_ARMADA_375
44 help 48 help
@@ -52,6 +56,9 @@ config MACH_ARMADA_38X
52 select ARM_GIC 56 select ARM_GIC
53 select ARMADA_38X_CLK 57 select ARMADA_38X_CLK
54 select CPU_V7 58 select CPU_V7
59 select HAVE_ARM_SCU
60 select HAVE_ARM_TWD if SMP
61 select HAVE_SMP
55 select MACH_MVEBU_V7 62 select MACH_MVEBU_V7
56 select PINCTRL_ARMADA_38X 63 select PINCTRL_ARMADA_38X
57 help 64 help
@@ -97,13 +104,6 @@ config MACH_KIRKWOOD
97 Say 'Y' here if you want your kernel to support boards based 104 Say 'Y' here if you want your kernel to support boards based
98 on the Marvell Kirkwood device tree. 105 on the Marvell Kirkwood device tree.
99 106
100config MACH_T5325
101 bool "HP T5325 thin client"
102 depends on MACH_KIRKWOOD
103 help
104 Say 'Y' here if you want your kernel to support the
105 HP T5325 Thin client
106
107endmenu 107endmenu
108 108
109endif 109endif
diff --git a/arch/arm/mach-mvebu/Makefile b/arch/arm/mach-mvebu/Makefile
index a63e43b6b451..2ecb828e4a8b 100644
--- a/arch/arm/mach-mvebu/Makefile
+++ b/arch/arm/mach-mvebu/Makefile
@@ -2,12 +2,15 @@ ccflags-$(CONFIG_ARCH_MULTIPLATFORM) := -I$(srctree)/$(src)/include \
2 -I$(srctree)/arch/arm/plat-orion/include 2 -I$(srctree)/arch/arm/plat-orion/include
3 3
4AFLAGS_coherency_ll.o := -Wa,-march=armv7-a 4AFLAGS_coherency_ll.o := -Wa,-march=armv7-a
5CFLAGS_pmsu.o := -march=armv7-a
5 6
6obj-y += system-controller.o mvebu-soc-id.o 7obj-y += system-controller.o mvebu-soc-id.o
7obj-$(CONFIG_MACH_MVEBU_V7) += board-v7.o 8
9ifeq ($(CONFIG_MACH_MVEBU_V7),y)
10obj-y += cpu-reset.o board-v7.o coherency.o coherency_ll.o pmsu.o
11obj-$(CONFIG_SMP) += platsmp.o headsmp.o platsmp-a9.o headsmp-a9.o
12obj-$(CONFIG_HOTPLUG_CPU) += hotplug.o
13endif
14
8obj-$(CONFIG_MACH_DOVE) += dove.o 15obj-$(CONFIG_MACH_DOVE) += dove.o
9obj-$(CONFIG_ARCH_MVEBU) += coherency.o coherency_ll.o pmsu.o
10obj-$(CONFIG_SMP) += platsmp.o headsmp.o
11obj-$(CONFIG_HOTPLUG_CPU) += hotplug.o
12obj-$(CONFIG_MACH_KIRKWOOD) += kirkwood.o kirkwood-pm.o 16obj-$(CONFIG_MACH_KIRKWOOD) += kirkwood.o kirkwood-pm.o
13obj-$(CONFIG_MACH_T5325) += board-t5325.o
diff --git a/arch/arm/mach-mvebu/armada-370-xp.h b/arch/arm/mach-mvebu/armada-370-xp.h
index 237c86b83390..c3465f5b1250 100644
--- a/arch/arm/mach-mvebu/armada-370-xp.h
+++ b/arch/arm/mach-mvebu/armada-370-xp.h
@@ -20,8 +20,6 @@
20 20
21#define ARMADA_XP_MAX_CPUS 4 21#define ARMADA_XP_MAX_CPUS 4
22 22
23void armada_mpic_send_doorbell(const struct cpumask *mask, unsigned int irq);
24void armada_xp_mpic_smp_cpu_init(void);
25void armada_xp_secondary_startup(void); 23void armada_xp_secondary_startup(void);
26extern struct smp_operations armada_xp_smp_ops; 24extern struct smp_operations armada_xp_smp_ops;
27#endif 25#endif
diff --git a/arch/arm/mach-mvebu/board-t5325.c b/arch/arm/mach-mvebu/board-t5325.c
deleted file mode 100644
index 65ace6db9f28..000000000000
--- a/arch/arm/mach-mvebu/board-t5325.c
+++ /dev/null
@@ -1,41 +0,0 @@
1/*
2 * HP T5325 Board Setup
3 *
4 * Copyright (C) 2014
5 *
6 * Andrew Lunn <andrew@lunn.ch>
7 *
8 * This file is licensed under the terms of the GNU General Public
9 * License version 2. This program is licensed "as is" without any
10 * warranty of any kind, whether express or implied.
11 */
12
13#include <linux/kernel.h>
14#include <linux/i2c.h>
15#include <linux/init.h>
16#include <linux/platform_device.h>
17#include <sound/alc5623.h>
18#include "board.h"
19
20static struct platform_device hp_t5325_audio_device = {
21 .name = "t5325-audio",
22 .id = -1,
23};
24
25static struct alc5623_platform_data alc5621_data = {
26 .add_ctrl = 0x3700,
27 .jack_det_ctrl = 0x4810,
28};
29
30static struct i2c_board_info i2c_board_info[] __initdata = {
31 {
32 I2C_BOARD_INFO("alc5621", 0x1a),
33 .platform_data = &alc5621_data,
34 },
35};
36
37void __init t5325_init(void)
38{
39 i2c_register_board_info(0, i2c_board_info, ARRAY_SIZE(i2c_board_info));
40 platform_device_register(&hp_t5325_audio_device);
41}
diff --git a/arch/arm/mach-mvebu/board-v7.c b/arch/arm/mach-mvebu/board-v7.c
index 333fca8fdc41..01cfce6ac20b 100644
--- a/arch/arm/mach-mvebu/board-v7.c
+++ b/arch/arm/mach-mvebu/board-v7.c
@@ -27,12 +27,30 @@
27#include <asm/mach/arch.h> 27#include <asm/mach/arch.h>
28#include <asm/mach/map.h> 28#include <asm/mach/map.h>
29#include <asm/mach/time.h> 29#include <asm/mach/time.h>
30#include <asm/smp_scu.h>
30#include "armada-370-xp.h" 31#include "armada-370-xp.h"
31#include "common.h" 32#include "common.h"
32#include "coherency.h" 33#include "coherency.h"
33#include "mvebu-soc-id.h" 34#include "mvebu-soc-id.h"
34 35
35/* 36/*
37 * Enables the SCU when available. Obviously, this is only useful on
38 * Cortex-A based SOCs, not on PJ4B based ones.
39 */
40static void __init mvebu_scu_enable(void)
41{
42 void __iomem *scu_base;
43
44 struct device_node *np =
45 of_find_compatible_node(NULL, NULL, "arm,cortex-a9-scu");
46 if (np) {
47 scu_base = of_iomap(np, 0);
48 scu_enable(scu_base);
49 of_node_put(np);
50 }
51}
52
53/*
36 * Early versions of Armada 375 SoC have a bug where the BootROM 54 * Early versions of Armada 375 SoC have a bug where the BootROM
37 * leaves an external data abort pending. The kernel is hit by this 55 * leaves an external data abort pending. The kernel is hit by this
38 * data abort as soon as it enters userspace, because it unmasks the 56 * data abort as soon as it enters userspace, because it unmasks the
@@ -57,11 +75,10 @@ static void __init mvebu_timer_and_clk_init(void)
57{ 75{
58 of_clk_init(NULL); 76 of_clk_init(NULL);
59 clocksource_of_init(); 77 clocksource_of_init();
78 mvebu_scu_enable();
60 coherency_init(); 79 coherency_init();
61 BUG_ON(mvebu_mbus_dt_init()); 80 BUG_ON(mvebu_mbus_dt_init(coherency_available()));
62#ifdef CONFIG_CACHE_L2X0
63 l2x0_of_init(0, ~0UL); 81 l2x0_of_init(0, ~0UL);
64#endif
65 82
66 if (of_machine_is_compatible("marvell,armada375")) 83 if (of_machine_is_compatible("marvell,armada375"))
67 hook_fault_code(16 + 6, armada_375_external_abort_wa, SIGBUS, 0, 84 hook_fault_code(16 + 6, armada_375_external_abort_wa, SIGBUS, 0,
@@ -78,7 +95,7 @@ static void __init i2c_quirk(void)
78 * mechanism. We can exit only if we are sure that we can 95 * mechanism. We can exit only if we are sure that we can
79 * get the SoC revision and it is more recent than A0. 96 * get the SoC revision and it is more recent than A0.
80 */ 97 */
81 if (mvebu_get_soc_id(&rev, &dev) == 0 && dev > MV78XX0_A0_REV) 98 if (mvebu_get_soc_id(&dev, &rev) == 0 && rev > MV78XX0_A0_REV)
82 return; 99 return;
83 100
84 for_each_compatible_node(np, NULL, "marvell,mv78230-i2c") { 101 for_each_compatible_node(np, NULL, "marvell,mv78230-i2c") {
@@ -96,10 +113,66 @@ static void __init i2c_quirk(void)
96 return; 113 return;
97} 114}
98 115
116#define A375_Z1_THERMAL_FIXUP_OFFSET 0xc
117
118static void __init thermal_quirk(void)
119{
120 struct device_node *np;
121 u32 dev, rev;
122
123 if (mvebu_get_soc_id(&dev, &rev) == 0 && rev > ARMADA_375_Z1_REV)
124 return;
125
126 for_each_compatible_node(np, NULL, "marvell,armada375-thermal") {
127 struct property *prop;
128 __be32 newval, *newprop, *oldprop;
129 int len;
130
131 /*
132 * The register offset is at a wrong location. This quirk
133 * creates a new reg property as a clone of the previous
134 * one and corrects the offset.
135 */
136 oldprop = (__be32 *)of_get_property(np, "reg", &len);
137 if (!oldprop)
138 continue;
139
140 /* Create a duplicate of the 'reg' property */
141 prop = kzalloc(sizeof(*prop), GFP_KERNEL);
142 prop->length = len;
143 prop->name = kstrdup("reg", GFP_KERNEL);
144 prop->value = kzalloc(len, GFP_KERNEL);
145 memcpy(prop->value, oldprop, len);
146
147 /* Fixup the register offset of the second entry */
148 oldprop += 2;
149 newprop = (__be32 *)prop->value + 2;
150 newval = cpu_to_be32(be32_to_cpu(*oldprop) -
151 A375_Z1_THERMAL_FIXUP_OFFSET);
152 *newprop = newval;
153 of_update_property(np, prop);
154
155 /*
156 * The thermal controller needs some quirk too, so let's change
157 * the compatible string to reflect this.
158 */
159 prop = kzalloc(sizeof(*prop), GFP_KERNEL);
160 prop->name = kstrdup("compatible", GFP_KERNEL);
161 prop->length = sizeof("marvell,armada375-z1-thermal");
162 prop->value = kstrdup("marvell,armada375-z1-thermal",
163 GFP_KERNEL);
164 of_update_property(np, prop);
165 }
166 return;
167}
168
99static void __init mvebu_dt_init(void) 169static void __init mvebu_dt_init(void)
100{ 170{
101 if (of_machine_is_compatible("plathome,openblocks-ax3-4")) 171 if (of_machine_is_compatible("plathome,openblocks-ax3-4"))
102 i2c_quirk(); 172 i2c_quirk();
173 if (of_machine_is_compatible("marvell,a375-db"))
174 thermal_quirk();
175
103 of_platform_populate(NULL, of_default_bus_match_table, NULL, NULL); 176 of_platform_populate(NULL, of_default_bus_match_table, NULL, NULL);
104} 177}
105 178
@@ -123,6 +196,7 @@ static const char * const armada_375_dt_compat[] = {
123 196
124DT_MACHINE_START(ARMADA_375_DT, "Marvell Armada 375 (Device Tree)") 197DT_MACHINE_START(ARMADA_375_DT, "Marvell Armada 375 (Device Tree)")
125 .init_time = mvebu_timer_and_clk_init, 198 .init_time = mvebu_timer_and_clk_init,
199 .init_machine = mvebu_dt_init,
126 .restart = mvebu_restart, 200 .restart = mvebu_restart,
127 .dt_compat = armada_375_dt_compat, 201 .dt_compat = armada_375_dt_compat,
128MACHINE_END 202MACHINE_END
diff --git a/arch/arm/mach-mvebu/board.h b/arch/arm/mach-mvebu/board.h
index de7f0a191394..9c7bb4386f8b 100644
--- a/arch/arm/mach-mvebu/board.h
+++ b/arch/arm/mach-mvebu/board.h
@@ -13,10 +13,4 @@
13#ifndef __ARCH_MVEBU_BOARD_H 13#ifndef __ARCH_MVEBU_BOARD_H
14#define __ARCH_MVEBU_BOARD_H 14#define __ARCH_MVEBU_BOARD_H
15 15
16#ifdef CONFIG_MACH_T5325
17void t5325_init(void);
18#else
19static inline void t5325_init(void) {};
20#endif
21
22#endif 16#endif
diff --git a/arch/arm/mach-mvebu/coherency.c b/arch/arm/mach-mvebu/coherency.c
index 4e9d58148ca7..d5a975b6a590 100644
--- a/arch/arm/mach-mvebu/coherency.c
+++ b/arch/arm/mach-mvebu/coherency.c
@@ -17,6 +17,8 @@
17 * supplies basic routines for configuring and controlling hardware coherency 17 * supplies basic routines for configuring and controlling hardware coherency
18 */ 18 */
19 19
20#define pr_fmt(fmt) "mvebu-coherency: " fmt
21
20#include <linux/kernel.h> 22#include <linux/kernel.h>
21#include <linux/init.h> 23#include <linux/init.h>
22#include <linux/of_address.h> 24#include <linux/of_address.h>
@@ -24,13 +26,17 @@
24#include <linux/smp.h> 26#include <linux/smp.h>
25#include <linux/dma-mapping.h> 27#include <linux/dma-mapping.h>
26#include <linux/platform_device.h> 28#include <linux/platform_device.h>
29#include <linux/slab.h>
30#include <linux/mbus.h>
31#include <linux/clk.h>
27#include <asm/smp_plat.h> 32#include <asm/smp_plat.h>
28#include <asm/cacheflush.h> 33#include <asm/cacheflush.h>
29#include "armada-370-xp.h" 34#include "armada-370-xp.h"
30#include "coherency.h" 35#include "coherency.h"
36#include "mvebu-soc-id.h"
31 37
32unsigned long coherency_phys_base; 38unsigned long coherency_phys_base;
33static void __iomem *coherency_base; 39void __iomem *coherency_base;
34static void __iomem *coherency_cpu_base; 40static void __iomem *coherency_cpu_base;
35 41
36/* Coherency fabric registers */ 42/* Coherency fabric registers */
@@ -38,27 +44,190 @@ static void __iomem *coherency_cpu_base;
38 44
39#define IO_SYNC_BARRIER_CTL_OFFSET 0x0 45#define IO_SYNC_BARRIER_CTL_OFFSET 0x0
40 46
47enum {
48 COHERENCY_FABRIC_TYPE_NONE,
49 COHERENCY_FABRIC_TYPE_ARMADA_370_XP,
50 COHERENCY_FABRIC_TYPE_ARMADA_375,
51 COHERENCY_FABRIC_TYPE_ARMADA_380,
52};
53
41static struct of_device_id of_coherency_table[] = { 54static struct of_device_id of_coherency_table[] = {
42 {.compatible = "marvell,coherency-fabric"}, 55 {.compatible = "marvell,coherency-fabric",
56 .data = (void *) COHERENCY_FABRIC_TYPE_ARMADA_370_XP },
57 {.compatible = "marvell,armada-375-coherency-fabric",
58 .data = (void *) COHERENCY_FABRIC_TYPE_ARMADA_375 },
59 {.compatible = "marvell,armada-380-coherency-fabric",
60 .data = (void *) COHERENCY_FABRIC_TYPE_ARMADA_380 },
43 { /* end of list */ }, 61 { /* end of list */ },
44}; 62};
45 63
46/* Function defined in coherency_ll.S */ 64/* Functions defined in coherency_ll.S */
47int ll_set_cpu_coherent(void __iomem *base_addr, unsigned int hw_cpu_id); 65int ll_enable_coherency(void);
66void ll_add_cpu_to_smp_group(void);
48 67
49int set_cpu_coherent(unsigned int hw_cpu_id, int smp_group_id) 68int set_cpu_coherent(void)
50{ 69{
51 if (!coherency_base) { 70 if (!coherency_base) {
52 pr_warn("Can't make CPU %d cache coherent.\n", hw_cpu_id); 71 pr_warn("Can't make current CPU cache coherent.\n");
53 pr_warn("Coherency fabric is not initialized\n"); 72 pr_warn("Coherency fabric is not initialized\n");
54 return 1; 73 return 1;
55 } 74 }
56 75
57 return ll_set_cpu_coherent(coherency_base, hw_cpu_id); 76 ll_add_cpu_to_smp_group();
77 return ll_enable_coherency();
78}
79
80/*
81 * The below code implements the I/O coherency workaround on Armada
82 * 375. This workaround consists in using the two channels of the
83 * first XOR engine to trigger a XOR transaction that serves as the
84 * I/O coherency barrier.
85 */
86
87static void __iomem *xor_base, *xor_high_base;
88static dma_addr_t coherency_wa_buf_phys[CONFIG_NR_CPUS];
89static void *coherency_wa_buf[CONFIG_NR_CPUS];
90static bool coherency_wa_enabled;
91
92#define XOR_CONFIG(chan) (0x10 + (chan * 4))
93#define XOR_ACTIVATION(chan) (0x20 + (chan * 4))
94#define WINDOW_BAR_ENABLE(chan) (0x240 + ((chan) << 2))
95#define WINDOW_BASE(w) (0x250 + ((w) << 2))
96#define WINDOW_SIZE(w) (0x270 + ((w) << 2))
97#define WINDOW_REMAP_HIGH(w) (0x290 + ((w) << 2))
98#define WINDOW_OVERRIDE_CTRL(chan) (0x2A0 + ((chan) << 2))
99#define XOR_DEST_POINTER(chan) (0x2B0 + (chan * 4))
100#define XOR_BLOCK_SIZE(chan) (0x2C0 + (chan * 4))
101#define XOR_INIT_VALUE_LOW 0x2E0
102#define XOR_INIT_VALUE_HIGH 0x2E4
103
104static inline void mvebu_hwcc_armada375_sync_io_barrier_wa(void)
105{
106 int idx = smp_processor_id();
107
108 /* Write '1' to the first word of the buffer */
109 writel(0x1, coherency_wa_buf[idx]);
110
111 /* Wait until the engine is idle */
112 while ((readl(xor_base + XOR_ACTIVATION(idx)) >> 4) & 0x3)
113 ;
114
115 dmb();
116
117 /* Trigger channel */
118 writel(0x1, xor_base + XOR_ACTIVATION(idx));
119
120 /* Poll the data until it is cleared by the XOR transaction */
121 while (readl(coherency_wa_buf[idx]))
122 ;
123}
124
125static void __init armada_375_coherency_init_wa(void)
126{
127 const struct mbus_dram_target_info *dram;
128 struct device_node *xor_node;
129 struct property *xor_status;
130 struct clk *xor_clk;
131 u32 win_enable = 0;
132 int i;
133
134 pr_warn("enabling coherency workaround for Armada 375 Z1, one XOR engine disabled\n");
135
136 /*
137 * Since the workaround uses one XOR engine, we grab a
138 * reference to its Device Tree node first.
139 */
140 xor_node = of_find_compatible_node(NULL, NULL, "marvell,orion-xor");
141 BUG_ON(!xor_node);
142
143 /*
144 * Then we mark it as disabled so that the real XOR driver
145 * will not use it.
146 */
147 xor_status = kzalloc(sizeof(struct property), GFP_KERNEL);
148 BUG_ON(!xor_status);
149
150 xor_status->value = kstrdup("disabled", GFP_KERNEL);
151 BUG_ON(!xor_status->value);
152
153 xor_status->length = 8;
154 xor_status->name = kstrdup("status", GFP_KERNEL);
155 BUG_ON(!xor_status->name);
156
157 of_update_property(xor_node, xor_status);
158
159 /*
160 * And we remap the registers, get the clock, and do the
161 * initial configuration of the XOR engine.
162 */
163 xor_base = of_iomap(xor_node, 0);
164 xor_high_base = of_iomap(xor_node, 1);
165
166 xor_clk = of_clk_get_by_name(xor_node, NULL);
167 BUG_ON(!xor_clk);
168
169 clk_prepare_enable(xor_clk);
170
171 dram = mv_mbus_dram_info();
172
173 for (i = 0; i < 8; i++) {
174 writel(0, xor_base + WINDOW_BASE(i));
175 writel(0, xor_base + WINDOW_SIZE(i));
176 if (i < 4)
177 writel(0, xor_base + WINDOW_REMAP_HIGH(i));
178 }
179
180 for (i = 0; i < dram->num_cs; i++) {
181 const struct mbus_dram_window *cs = dram->cs + i;
182 writel((cs->base & 0xffff0000) |
183 (cs->mbus_attr << 8) |
184 dram->mbus_dram_target_id, xor_base + WINDOW_BASE(i));
185 writel((cs->size - 1) & 0xffff0000, xor_base + WINDOW_SIZE(i));
186
187 win_enable |= (1 << i);
188 win_enable |= 3 << (16 + (2 * i));
189 }
190
191 writel(win_enable, xor_base + WINDOW_BAR_ENABLE(0));
192 writel(win_enable, xor_base + WINDOW_BAR_ENABLE(1));
193 writel(0, xor_base + WINDOW_OVERRIDE_CTRL(0));
194 writel(0, xor_base + WINDOW_OVERRIDE_CTRL(1));
195
196 for (i = 0; i < CONFIG_NR_CPUS; i++) {
197 coherency_wa_buf[i] = kzalloc(PAGE_SIZE, GFP_KERNEL);
198 BUG_ON(!coherency_wa_buf[i]);
199
200 /*
201 * We can't use the DMA mapping API, since we don't
202 * have a valid 'struct device' pointer
203 */
204 coherency_wa_buf_phys[i] =
205 virt_to_phys(coherency_wa_buf[i]);
206 BUG_ON(!coherency_wa_buf_phys[i]);
207
208 /*
209 * Configure the XOR engine for memset operation, with
210 * a 128 bytes block size
211 */
212 writel(0x444, xor_base + XOR_CONFIG(i));
213 writel(128, xor_base + XOR_BLOCK_SIZE(i));
214 writel(coherency_wa_buf_phys[i],
215 xor_base + XOR_DEST_POINTER(i));
216 }
217
218 writel(0x0, xor_base + XOR_INIT_VALUE_LOW);
219 writel(0x0, xor_base + XOR_INIT_VALUE_HIGH);
220
221 coherency_wa_enabled = true;
58} 222}
59 223
60static inline void mvebu_hwcc_sync_io_barrier(void) 224static inline void mvebu_hwcc_sync_io_barrier(void)
61{ 225{
226 if (coherency_wa_enabled) {
227 mvebu_hwcc_armada375_sync_io_barrier_wa();
228 return;
229 }
230
62 writel(0x1, coherency_cpu_base + IO_SYNC_BARRIER_CTL_OFFSET); 231 writel(0x1, coherency_cpu_base + IO_SYNC_BARRIER_CTL_OFFSET);
63 while (readl(coherency_cpu_base + IO_SYNC_BARRIER_CTL_OFFSET) & 0x1); 232 while (readl(coherency_cpu_base + IO_SYNC_BARRIER_CTL_OFFSET) & 0x1);
64} 233}
@@ -121,42 +290,93 @@ static struct notifier_block mvebu_hwcc_platform_nb = {
121 .notifier_call = mvebu_hwcc_platform_notifier, 290 .notifier_call = mvebu_hwcc_platform_notifier,
122}; 291};
123 292
124int __init coherency_init(void) 293static void __init armada_370_coherency_init(struct device_node *np)
294{
295 struct resource res;
296
297 of_address_to_resource(np, 0, &res);
298 coherency_phys_base = res.start;
299 /*
300 * Ensure secondary CPUs will see the updated value,
301 * which they read before they join the coherency
302 * fabric, and therefore before they are coherent with
303 * the boot CPU cache.
304 */
305 sync_cache_w(&coherency_phys_base);
306 coherency_base = of_iomap(np, 0);
307 coherency_cpu_base = of_iomap(np, 1);
308 set_cpu_coherent();
309}
310
311static void __init armada_375_380_coherency_init(struct device_node *np)
312{
313 coherency_cpu_base = of_iomap(np, 0);
314}
315
316static int coherency_type(void)
125{ 317{
126 struct device_node *np; 318 struct device_node *np;
319 const struct of_device_id *match;
127 320
128 np = of_find_matching_node(NULL, of_coherency_table); 321 np = of_find_matching_node_and_match(NULL, of_coherency_table, &match);
129 if (np) { 322 if (np) {
130 struct resource res; 323 int type = (int) match->data;
131 pr_info("Initializing Coherency fabric\n"); 324
132 of_address_to_resource(np, 0, &res); 325 /* Armada 370/XP coherency works in both UP and SMP */
133 coherency_phys_base = res.start; 326 if (type == COHERENCY_FABRIC_TYPE_ARMADA_370_XP)
134 /* 327 return type;
135 * Ensure secondary CPUs will see the updated value, 328
136 * which they read before they join the coherency 329 /* Armada 375 coherency works only on SMP */
137 * fabric, and therefore before they are coherent with 330 else if (type == COHERENCY_FABRIC_TYPE_ARMADA_375 && is_smp())
138 * the boot CPU cache. 331 return type;
139 */ 332
140 sync_cache_w(&coherency_phys_base); 333 /* Armada 380 coherency works only on SMP */
141 coherency_base = of_iomap(np, 0); 334 else if (type == COHERENCY_FABRIC_TYPE_ARMADA_380 && is_smp())
142 coherency_cpu_base = of_iomap(np, 1); 335 return type;
143 set_cpu_coherent(cpu_logical_map(smp_processor_id()), 0);
144 of_node_put(np);
145 } 336 }
146 337
147 return 0; 338 return COHERENCY_FABRIC_TYPE_NONE;
148} 339}
149 340
150static int __init coherency_late_init(void) 341int coherency_available(void)
342{
343 return coherency_type() != COHERENCY_FABRIC_TYPE_NONE;
344}
345
346int __init coherency_init(void)
151{ 347{
348 int type = coherency_type();
152 struct device_node *np; 349 struct device_node *np;
153 350
154 np = of_find_matching_node(NULL, of_coherency_table); 351 np = of_find_matching_node(NULL, of_coherency_table);
155 if (np) { 352
156 bus_register_notifier(&platform_bus_type, 353 if (type == COHERENCY_FABRIC_TYPE_ARMADA_370_XP)
157 &mvebu_hwcc_platform_nb); 354 armada_370_coherency_init(np);
158 of_node_put(np); 355 else if (type == COHERENCY_FABRIC_TYPE_ARMADA_375 ||
356 type == COHERENCY_FABRIC_TYPE_ARMADA_380)
357 armada_375_380_coherency_init(np);
358
359 return 0;
360}
361
362static int __init coherency_late_init(void)
363{
364 int type = coherency_type();
365
366 if (type == COHERENCY_FABRIC_TYPE_NONE)
367 return 0;
368
369 if (type == COHERENCY_FABRIC_TYPE_ARMADA_375) {
370 u32 dev, rev;
371
372 if (mvebu_get_soc_id(&dev, &rev) == 0 &&
373 rev == ARMADA_375_Z1_REV)
374 armada_375_coherency_init_wa();
159 } 375 }
376
377 bus_register_notifier(&platform_bus_type,
378 &mvebu_hwcc_platform_nb);
379
160 return 0; 380 return 0;
161} 381}
162 382
diff --git a/arch/arm/mach-mvebu/coherency.h b/arch/arm/mach-mvebu/coherency.h
index 760226c41353..54cb7607b526 100644
--- a/arch/arm/mach-mvebu/coherency.h
+++ b/arch/arm/mach-mvebu/coherency.h
@@ -15,8 +15,9 @@
15#define __MACH_370_XP_COHERENCY_H 15#define __MACH_370_XP_COHERENCY_H
16 16
17extern unsigned long coherency_phys_base; 17extern unsigned long coherency_phys_base;
18int set_cpu_coherent(void);
18 19
19int set_cpu_coherent(unsigned int cpu_id, int smp_group_id);
20int coherency_init(void); 20int coherency_init(void);
21int coherency_available(void);
21 22
22#endif /* __MACH_370_XP_COHERENCY_H */ 23#endif /* __MACH_370_XP_COHERENCY_H */
diff --git a/arch/arm/mach-mvebu/coherency_ll.S b/arch/arm/mach-mvebu/coherency_ll.S
index ee7598fe75db..6828f9f157b0 100644
--- a/arch/arm/mach-mvebu/coherency_ll.S
+++ b/arch/arm/mach-mvebu/coherency_ll.S
@@ -21,38 +21,108 @@
21#define ARMADA_XP_CFB_CFG_REG_OFFSET 0x4 21#define ARMADA_XP_CFB_CFG_REG_OFFSET 0x4
22 22
23#include <asm/assembler.h> 23#include <asm/assembler.h>
24#include <asm/cp15.h>
24 25
25 .text 26 .text
26/* 27/* Returns with the coherency address in r1 (r0 is untouched)*/
27 * r0: Coherency fabric base register address 28ENTRY(ll_get_coherency_base)
28 * r1: HW CPU id 29 mrc p15, 0, r1, c1, c0, 0
29 */ 30 tst r1, #CR_M @ Check MMU bit enabled
30ENTRY(ll_set_cpu_coherent) 31 bne 1f
31 /* Create bit by cpu index */
32 mov r3, #(1 << 24)
33 lsl r1, r3, r1
34ARM_BE8(rev r1, r1)
35 32
36 /* Add CPU to SMP group - Atomic */ 33 /* use physical address of the coherency register */
37 add r3, r0, #ARMADA_XP_CFB_CTL_REG_OFFSET 34 adr r1, 3f
35 ldr r3, [r1]
36 ldr r1, [r1, r3]
37 b 2f
381: 381:
39 ldrex r2, [r3] 39 /* use virtual address of the coherency register */
40 orr r2, r2, r1 40 ldr r1, =coherency_base
41 strex r0, r2, [r3] 41 ldr r1, [r1]
42 cmp r0, #0 422:
43 bne 1b 43 mov pc, lr
44 44ENDPROC(ll_get_coherency_base)
45 /* Enable coherency on CPU - Atomic */ 45
46 add r3, r3, #ARMADA_XP_CFB_CFG_REG_OFFSET 46/* Returns with the CPU ID in r3 (r0 is untouched)*/
47ENTRY(ll_get_cpuid)
48 mrc 15, 0, r3, cr0, cr0, 5
49 and r3, r3, #15
50 mov r2, #(1 << 24)
51 lsl r3, r2, r3
52ARM_BE8(rev r1, r1)
53 mov pc, lr
54ENDPROC(ll_get_cpuid)
55
56/* ll_add_cpu_to_smp_group, ll_enable_coherency and
57 * ll_disable_coherency use strex/ldrex whereas MMU can be off. The
58 * Armada XP SoC has an exclusive monitor that can track transactions
59 * to Device and/or SO and as such also when MMU is disabled the
60 * exclusive transactions will be functional
61 */
62
63ENTRY(ll_add_cpu_to_smp_group)
64 /*
65 * r0 being untouched in ll_get_coherency_base and
66 * ll_get_cpuid, we can use it to save lr modifing it with the
67 * following bl
68 */
69 mov r0, lr
70 bl ll_get_coherency_base
71 bl ll_get_cpuid
72 mov lr, r0
73 add r0, r1, #ARMADA_XP_CFB_CFG_REG_OFFSET
471: 741:
48 ldrex r2, [r3] 75 ldrex r2, [r0]
49 orr r2, r2, r1 76 orr r2, r2, r3
50 strex r0, r2, [r3] 77 strex r1, r2, [r0]
51 cmp r0, #0 78 cmp r1, #0
52 bne 1b 79 bne 1b
80 mov pc, lr
81ENDPROC(ll_add_cpu_to_smp_group)
53 82
83ENTRY(ll_enable_coherency)
84 /*
85 * r0 being untouched in ll_get_coherency_base and
86 * ll_get_cpuid, we can use it to save lr modifing it with the
87 * following bl
88 */
89 mov r0, lr
90 bl ll_get_coherency_base
91 bl ll_get_cpuid
92 mov lr, r0
93 add r0, r1, #ARMADA_XP_CFB_CTL_REG_OFFSET
941:
95 ldrex r2, [r0]
96 orr r2, r2, r3
97 strex r1, r2, [r0]
98 cmp r1, #0
99 bne 1b
54 dsb 100 dsb
55
56 mov r0, #0 101 mov r0, #0
57 mov pc, lr 102 mov pc, lr
58ENDPROC(ll_set_cpu_coherent) 103ENDPROC(ll_enable_coherency)
104
105ENTRY(ll_disable_coherency)
106 /*
107 * r0 being untouched in ll_get_coherency_base and
108 * ll_get_cpuid, we can use it to save lr modifing it with the
109 * following bl
110 */
111 mov r0, lr
112 bl ll_get_coherency_base
113 bl ll_get_cpuid
114 mov lr, r0
115 add r0, r1, #ARMADA_XP_CFB_CTL_REG_OFFSET
1161:
117 ldrex r2, [r0]
118 bic r2, r2, r3
119 strex r1, r2, [r0]
120 cmp r1, #0
121 bne 1b
122 dsb
123 mov pc, lr
124ENDPROC(ll_disable_coherency)
125
126 .align 2
1273:
128 .long coherency_phys_base - .
diff --git a/arch/arm/mach-mvebu/common.h b/arch/arm/mach-mvebu/common.h
index 55449c487c9e..b67fb7a10d8b 100644
--- a/arch/arm/mach-mvebu/common.h
+++ b/arch/arm/mach-mvebu/common.h
@@ -18,6 +18,9 @@
18#include <linux/reboot.h> 18#include <linux/reboot.h>
19 19
20void mvebu_restart(enum reboot_mode mode, const char *cmd); 20void mvebu_restart(enum reboot_mode mode, const char *cmd);
21int mvebu_cpu_reset_deassert(int cpu);
22void mvebu_pmsu_set_cpu_boot_addr(int hw_cpu, void *boot_addr);
23void mvebu_system_controller_set_cpu_boot_addr(void *boot_addr);
21 24
22void armada_xp_cpu_die(unsigned int cpu); 25void armada_xp_cpu_die(unsigned int cpu);
23 26
diff --git a/arch/arm/mach-mvebu/cpu-reset.c b/arch/arm/mach-mvebu/cpu-reset.c
new file mode 100644
index 000000000000..4a8f9eebebea
--- /dev/null
+++ b/arch/arm/mach-mvebu/cpu-reset.c
@@ -0,0 +1,103 @@
1/*
2 * Copyright (C) 2014 Marvell
3 *
4 * Thomas Petazzoni <thomas.petazzoni@free-electrons.com>
5 *
6 * This file is licensed under the terms of the GNU General Public
7 * License version 2. This program is licensed "as is" without any
8 * warranty of any kind, whether express or implied.
9 */
10
11#define pr_fmt(fmt) "mvebu-cpureset: " fmt
12
13#include <linux/kernel.h>
14#include <linux/init.h>
15#include <linux/of_address.h>
16#include <linux/io.h>
17#include <linux/resource.h>
18#include "armada-370-xp.h"
19
20static void __iomem *cpu_reset_base;
21static size_t cpu_reset_size;
22
23#define CPU_RESET_OFFSET(cpu) (cpu * 0x8)
24#define CPU_RESET_ASSERT BIT(0)
25
26int mvebu_cpu_reset_deassert(int cpu)
27{
28 u32 reg;
29
30 if (!cpu_reset_base)
31 return -ENODEV;
32
33 if (CPU_RESET_OFFSET(cpu) >= cpu_reset_size)
34 return -EINVAL;
35
36 reg = readl(cpu_reset_base + CPU_RESET_OFFSET(cpu));
37 reg &= ~CPU_RESET_ASSERT;
38 writel(reg, cpu_reset_base + CPU_RESET_OFFSET(cpu));
39
40 return 0;
41}
42
43static int mvebu_cpu_reset_map(struct device_node *np, int res_idx)
44{
45 struct resource res;
46
47 if (of_address_to_resource(np, res_idx, &res)) {
48 pr_err("unable to get resource\n");
49 return -ENOENT;
50 }
51
52 if (!request_mem_region(res.start, resource_size(&res),
53 np->full_name)) {
54 pr_err("unable to request region\n");
55 return -EBUSY;
56 }
57
58 cpu_reset_base = ioremap(res.start, resource_size(&res));
59 if (!cpu_reset_base) {
60 pr_err("unable to map registers\n");
61 release_mem_region(res.start, resource_size(&res));
62 return -ENOMEM;
63 }
64
65 cpu_reset_size = resource_size(&res);
66
67 return 0;
68}
69
70int __init mvebu_cpu_reset_init(void)
71{
72 struct device_node *np;
73 int res_idx;
74 int ret;
75
76 np = of_find_compatible_node(NULL, NULL,
77 "marvell,armada-370-cpu-reset");
78 if (np) {
79 res_idx = 0;
80 } else {
81 /*
82 * This code is kept for backward compatibility with
83 * old Device Trees.
84 */
85 np = of_find_compatible_node(NULL, NULL,
86 "marvell,armada-370-xp-pmsu");
87 if (np) {
88 pr_warn(FW_WARN "deprecated pmsu binding\n");
89 res_idx = 1;
90 }
91 }
92
93 /* No reset node found */
94 if (!np)
95 return -ENODEV;
96
97 ret = mvebu_cpu_reset_map(np, res_idx);
98 of_node_put(np);
99
100 return ret;
101}
102
103early_initcall(mvebu_cpu_reset_init);
diff --git a/arch/arm/mach-mvebu/dove.c b/arch/arm/mach-mvebu/dove.c
index 5e5a43624237..b50464ec1130 100644
--- a/arch/arm/mach-mvebu/dove.c
+++ b/arch/arm/mach-mvebu/dove.c
@@ -23,7 +23,7 @@ static void __init dove_init(void)
23#ifdef CONFIG_CACHE_TAUROS2 23#ifdef CONFIG_CACHE_TAUROS2
24 tauros2_init(0); 24 tauros2_init(0);
25#endif 25#endif
26 BUG_ON(mvebu_mbus_dt_init()); 26 BUG_ON(mvebu_mbus_dt_init(false));
27 of_platform_populate(NULL, of_default_bus_match_table, NULL, NULL); 27 of_platform_populate(NULL, of_default_bus_match_table, NULL, NULL);
28} 28}
29 29
diff --git a/arch/arm/mach-mvebu/headsmp-a9.S b/arch/arm/mach-mvebu/headsmp-a9.S
new file mode 100644
index 000000000000..5925366bc03c
--- /dev/null
+++ b/arch/arm/mach-mvebu/headsmp-a9.S
@@ -0,0 +1,34 @@
1/*
2 * SMP support: Entry point for secondary CPUs of Marvell EBU
3 * Cortex-A9 based SOCs (Armada 375 and Armada 38x).
4 *
5 * Copyright (C) 2014 Marvell
6 *
7 * Gregory CLEMENT <gregory.clement@free-electrons.com>
8 * Thomas Petazzoni <thomas.petazzoni@free-electrons.com>
9 *
10 * This file is licensed under the terms of the GNU General Public
11 * License version 2. This program is licensed "as is" without any
12 * warranty of any kind, whether express or implied.
13 */
14
15#include <linux/linkage.h>
16#include <linux/init.h>
17
18 __CPUINIT
19#define CPU_RESUME_ADDR_REG 0xf10182d4
20
21.global armada_375_smp_cpu1_enable_code_start
22.global armada_375_smp_cpu1_enable_code_end
23
24armada_375_smp_cpu1_enable_code_start:
25 ldr r0, [pc, #4]
26 ldr r1, [r0]
27 mov pc, r1
28 .word CPU_RESUME_ADDR_REG
29armada_375_smp_cpu1_enable_code_end:
30
31ENTRY(mvebu_cortex_a9_secondary_startup)
32 bl v7_invalidate_l1
33 b secondary_startup
34ENDPROC(mvebu_cortex_a9_secondary_startup)
diff --git a/arch/arm/mach-mvebu/headsmp.S b/arch/arm/mach-mvebu/headsmp.S
index 3dd80df428f7..2c4032e368ba 100644
--- a/arch/arm/mach-mvebu/headsmp.S
+++ b/arch/arm/mach-mvebu/headsmp.S
@@ -31,21 +31,10 @@
31ENTRY(armada_xp_secondary_startup) 31ENTRY(armada_xp_secondary_startup)
32 ARM_BE8(setend be ) @ go BE8 if entered LE 32 ARM_BE8(setend be ) @ go BE8 if entered LE
33 33
34 /* Get coherency fabric base physical address */ 34 bl ll_add_cpu_to_smp_group
35 adr r0, 1f
36 ldr r1, [r0]
37 ldr r0, [r0, r1]
38 35
39 /* Read CPU id */ 36 bl ll_enable_coherency
40 mrc p15, 0, r1, c0, c0, 5
41 and r1, r1, #0xF
42 37
43 /* Add CPU to coherency fabric */
44 bl ll_set_cpu_coherent
45 b secondary_startup 38 b secondary_startup
46 39
47ENDPROC(armada_xp_secondary_startup) 40ENDPROC(armada_xp_secondary_startup)
48
49 .align 2
501:
51 .long coherency_phys_base - .
diff --git a/arch/arm/mach-mvebu/kirkwood.c b/arch/arm/mach-mvebu/kirkwood.c
index 120207fc36f1..46f105913c84 100644
--- a/arch/arm/mach-mvebu/kirkwood.c
+++ b/arch/arm/mach-mvebu/kirkwood.c
@@ -169,7 +169,7 @@ static void __init kirkwood_dt_init(void)
169{ 169{
170 kirkwood_disable_mbus_error_propagation(); 170 kirkwood_disable_mbus_error_propagation();
171 171
172 BUG_ON(mvebu_mbus_dt_init()); 172 BUG_ON(mvebu_mbus_dt_init(false));
173 173
174#ifdef CONFIG_CACHE_FEROCEON_L2 174#ifdef CONFIG_CACHE_FEROCEON_L2
175 feroceon_of_init(); 175 feroceon_of_init();
@@ -180,9 +180,6 @@ static void __init kirkwood_dt_init(void)
180 kirkwood_pm_init(); 180 kirkwood_pm_init();
181 kirkwood_dt_eth_fixup(); 181 kirkwood_dt_eth_fixup();
182 182
183 if (of_machine_is_compatible("hp,t5325"))
184 t5325_init();
185
186 of_platform_populate(NULL, of_default_bus_match_table, auxdata, NULL); 183 of_platform_populate(NULL, of_default_bus_match_table, auxdata, NULL);
187} 184}
188 185
diff --git a/arch/arm/mach-mvebu/mvebu-soc-id.c b/arch/arm/mach-mvebu/mvebu-soc-id.c
index f3d4cf53f746..e9119a99a5f3 100644
--- a/arch/arm/mach-mvebu/mvebu-soc-id.c
+++ b/arch/arm/mach-mvebu/mvebu-soc-id.c
@@ -23,6 +23,8 @@
23#include <linux/kernel.h> 23#include <linux/kernel.h>
24#include <linux/of.h> 24#include <linux/of.h>
25#include <linux/of_address.h> 25#include <linux/of_address.h>
26#include <linux/slab.h>
27#include <linux/sys_soc.h>
26#include "mvebu-soc-id.h" 28#include "mvebu-soc-id.h"
27 29
28#define PCIE_DEV_ID_OFF 0x0 30#define PCIE_DEV_ID_OFF 0x0
@@ -116,5 +118,33 @@ clk_err:
116 118
117 return ret; 119 return ret;
118} 120}
119core_initcall(mvebu_soc_id_init); 121early_initcall(mvebu_soc_id_init);
120 122
123static int __init mvebu_soc_device(void)
124{
125 struct soc_device_attribute *soc_dev_attr;
126 struct soc_device *soc_dev;
127
128 /* Also protects against running on non-mvebu systems */
129 if (!is_id_valid)
130 return 0;
131
132 soc_dev_attr = kzalloc(sizeof(*soc_dev_attr), GFP_KERNEL);
133 if (!soc_dev_attr)
134 return -ENOMEM;
135
136 soc_dev_attr->family = kasprintf(GFP_KERNEL, "Marvell");
137 soc_dev_attr->revision = kasprintf(GFP_KERNEL, "%X", soc_rev);
138 soc_dev_attr->soc_id = kasprintf(GFP_KERNEL, "%X", soc_dev_id);
139
140 soc_dev = soc_device_register(soc_dev_attr);
141 if (IS_ERR(soc_dev)) {
142 kfree(soc_dev_attr->family);
143 kfree(soc_dev_attr->revision);
144 kfree(soc_dev_attr->soc_id);
145 kfree(soc_dev_attr);
146 }
147
148 return 0;
149}
150postcore_initcall(mvebu_soc_device);
diff --git a/arch/arm/mach-mvebu/mvebu-soc-id.h b/arch/arm/mach-mvebu/mvebu-soc-id.h
index 31654252fe35..c16bb68ca81f 100644
--- a/arch/arm/mach-mvebu/mvebu-soc-id.h
+++ b/arch/arm/mach-mvebu/mvebu-soc-id.h
@@ -20,6 +20,10 @@
20#define MV78XX0_A0_REV 0x1 20#define MV78XX0_A0_REV 0x1
21#define MV78XX0_B0_REV 0x2 21#define MV78XX0_B0_REV 0x2
22 22
23/* Armada 375 */
24#define ARMADA_375_Z1_REV 0x0
25#define ARMADA_375_A0_REV 0x3
26
23#ifdef CONFIG_ARCH_MVEBU 27#ifdef CONFIG_ARCH_MVEBU
24int mvebu_get_soc_id(u32 *dev, u32 *rev); 28int mvebu_get_soc_id(u32 *dev, u32 *rev);
25#else 29#else
diff --git a/arch/arm/mach-mvebu/platsmp-a9.c b/arch/arm/mach-mvebu/platsmp-a9.c
new file mode 100644
index 000000000000..96c2c59e34b6
--- /dev/null
+++ b/arch/arm/mach-mvebu/platsmp-a9.c
@@ -0,0 +1,102 @@
1/*
2 * Symmetric Multi Processing (SMP) support for Marvell EBU Cortex-A9
3 * based SOCs (Armada 375/38x).
4 *
5 * Copyright (C) 2014 Marvell
6 *
7 * Gregory CLEMENT <gregory.clement@free-electrons.com>
8 * Thomas Petazzoni <thomas.petazzoni@free-electrons.com>
9 *
10 * This file is licensed under the terms of the GNU General Public
11 * License version 2. This program is licensed "as is" without any
12 * warranty of any kind, whether express or implied.
13 */
14
15#include <linux/init.h>
16#include <linux/io.h>
17#include <linux/of.h>
18#include <linux/smp.h>
19#include <linux/mbus.h>
20#include <asm/smp_scu.h>
21#include <asm/smp_plat.h>
22#include "common.h"
23#include "mvebu-soc-id.h"
24#include "pmsu.h"
25
26#define CRYPT0_ENG_ID 41
27#define CRYPT0_ENG_ATTR 0x1
28#define SRAM_PHYS_BASE 0xFFFF0000
29
30#define BOOTROM_BASE 0xFFF00000
31#define BOOTROM_SIZE 0x100000
32
33extern unsigned char armada_375_smp_cpu1_enable_code_end;
34extern unsigned char armada_375_smp_cpu1_enable_code_start;
35
36void armada_375_smp_cpu1_enable_wa(void)
37{
38 void __iomem *sram_virt_base;
39
40 mvebu_mbus_del_window(BOOTROM_BASE, BOOTROM_SIZE);
41 mvebu_mbus_add_window_by_id(CRYPT0_ENG_ID, CRYPT0_ENG_ATTR,
42 SRAM_PHYS_BASE, SZ_64K);
43 sram_virt_base = ioremap(SRAM_PHYS_BASE, SZ_64K);
44
45 memcpy(sram_virt_base, &armada_375_smp_cpu1_enable_code_start,
46 &armada_375_smp_cpu1_enable_code_end
47 - &armada_375_smp_cpu1_enable_code_start);
48}
49
50extern void mvebu_cortex_a9_secondary_startup(void);
51
52static int __cpuinit mvebu_cortex_a9_boot_secondary(unsigned int cpu,
53 struct task_struct *idle)
54{
55 int ret, hw_cpu;
56
57 pr_info("Booting CPU %d\n", cpu);
58
59 /*
60 * Write the address of secondary startup into the system-wide
61 * flags register. The boot monitor waits until it receives a
62 * soft interrupt, and then the secondary CPU branches to this
63 * address.
64 */
65 hw_cpu = cpu_logical_map(cpu);
66
67 if (of_machine_is_compatible("marvell,armada375")) {
68 u32 dev, rev;
69
70 if (mvebu_get_soc_id(&dev, &rev) == 0 &&
71 rev == ARMADA_375_Z1_REV)
72 armada_375_smp_cpu1_enable_wa();
73
74 mvebu_system_controller_set_cpu_boot_addr(mvebu_cortex_a9_secondary_startup);
75 }
76 else {
77 mvebu_pmsu_set_cpu_boot_addr(hw_cpu,
78 mvebu_cortex_a9_secondary_startup);
79 }
80
81 smp_wmb();
82 ret = mvebu_cpu_reset_deassert(hw_cpu);
83 if (ret) {
84 pr_err("Could not start the secondary CPU: %d\n", ret);
85 return ret;
86 }
87 arch_send_wakeup_ipi_mask(cpumask_of(cpu));
88
89 return 0;
90}
91
92static struct smp_operations mvebu_cortex_a9_smp_ops __initdata = {
93 .smp_boot_secondary = mvebu_cortex_a9_boot_secondary,
94#ifdef CONFIG_HOTPLUG_CPU
95 .cpu_die = armada_xp_cpu_die,
96#endif
97};
98
99CPU_METHOD_OF_DECLARE(mvebu_armada_375_smp, "marvell,armada-375-smp",
100 &mvebu_cortex_a9_smp_ops);
101CPU_METHOD_OF_DECLARE(mvebu_armada_380_smp, "marvell,armada-380-smp",
102 &mvebu_cortex_a9_smp_ops);
diff --git a/arch/arm/mach-mvebu/platsmp.c b/arch/arm/mach-mvebu/platsmp.c
index a6da03f5b24e..88b976b31719 100644
--- a/arch/arm/mach-mvebu/platsmp.c
+++ b/arch/arm/mach-mvebu/platsmp.c
@@ -70,16 +70,19 @@ static void __init set_secondary_cpus_clock(void)
70 } 70 }
71} 71}
72 72
73static void armada_xp_secondary_init(unsigned int cpu)
74{
75 armada_xp_mpic_smp_cpu_init();
76}
77
78static int armada_xp_boot_secondary(unsigned int cpu, struct task_struct *idle) 73static int armada_xp_boot_secondary(unsigned int cpu, struct task_struct *idle)
79{ 74{
75 int ret, hw_cpu;
76
80 pr_info("Booting CPU %d\n", cpu); 77 pr_info("Booting CPU %d\n", cpu);
81 78
82 armada_xp_boot_cpu(cpu, armada_xp_secondary_startup); 79 hw_cpu = cpu_logical_map(cpu);
80 mvebu_pmsu_set_cpu_boot_addr(hw_cpu, armada_xp_secondary_startup);
81 ret = mvebu_cpu_reset_deassert(hw_cpu);
82 if (ret) {
83 pr_warn("unable to boot CPU: %d\n", ret);
84 return ret;
85 }
83 86
84 return 0; 87 return 0;
85} 88}
@@ -90,8 +93,6 @@ static void __init armada_xp_smp_init_cpus(void)
90 93
91 if (ncores == 0 || ncores > ARMADA_XP_MAX_CPUS) 94 if (ncores == 0 || ncores > ARMADA_XP_MAX_CPUS)
92 panic("Invalid number of CPUs in DT\n"); 95 panic("Invalid number of CPUs in DT\n");
93
94 set_smp_cross_call(armada_mpic_send_doorbell);
95} 96}
96 97
97static void __init armada_xp_smp_prepare_cpus(unsigned int max_cpus) 98static void __init armada_xp_smp_prepare_cpus(unsigned int max_cpus)
@@ -102,7 +103,7 @@ static void __init armada_xp_smp_prepare_cpus(unsigned int max_cpus)
102 103
103 set_secondary_cpus_clock(); 104 set_secondary_cpus_clock();
104 flush_cache_all(); 105 flush_cache_all();
105 set_cpu_coherent(cpu_logical_map(smp_processor_id()), 0); 106 set_cpu_coherent();
106 107
107 /* 108 /*
108 * In order to boot the secondary CPUs we need to ensure 109 * In order to boot the secondary CPUs we need to ensure
@@ -124,9 +125,11 @@ static void __init armada_xp_smp_prepare_cpus(unsigned int max_cpus)
124struct smp_operations armada_xp_smp_ops __initdata = { 125struct smp_operations armada_xp_smp_ops __initdata = {
125 .smp_init_cpus = armada_xp_smp_init_cpus, 126 .smp_init_cpus = armada_xp_smp_init_cpus,
126 .smp_prepare_cpus = armada_xp_smp_prepare_cpus, 127 .smp_prepare_cpus = armada_xp_smp_prepare_cpus,
127 .smp_secondary_init = armada_xp_secondary_init,
128 .smp_boot_secondary = armada_xp_boot_secondary, 128 .smp_boot_secondary = armada_xp_boot_secondary,
129#ifdef CONFIG_HOTPLUG_CPU 129#ifdef CONFIG_HOTPLUG_CPU
130 .cpu_die = armada_xp_cpu_die, 130 .cpu_die = armada_xp_cpu_die,
131#endif 131#endif
132}; 132};
133
134CPU_METHOD_OF_DECLARE(armada_xp_smp, "marvell,armada-xp-smp",
135 &armada_xp_smp_ops);
diff --git a/arch/arm/mach-mvebu/pmsu.c b/arch/arm/mach-mvebu/pmsu.c
index d71ef53107c4..53a55c8520bf 100644
--- a/arch/arm/mach-mvebu/pmsu.c
+++ b/arch/arm/mach-mvebu/pmsu.c
@@ -16,62 +16,283 @@
16 * other SOC units 16 * other SOC units
17 */ 17 */
18 18
19#define pr_fmt(fmt) "mvebu-pmsu: " fmt
20
21#include <linux/cpu_pm.h>
19#include <linux/kernel.h> 22#include <linux/kernel.h>
20#include <linux/init.h> 23#include <linux/init.h>
21#include <linux/of_address.h> 24#include <linux/of_address.h>
22#include <linux/io.h> 25#include <linux/io.h>
26#include <linux/platform_device.h>
23#include <linux/smp.h> 27#include <linux/smp.h>
28#include <linux/resource.h>
29#include <asm/cacheflush.h>
30#include <asm/cp15.h>
24#include <asm/smp_plat.h> 31#include <asm/smp_plat.h>
25#include "pmsu.h" 32#include <asm/suspend.h>
33#include <asm/tlbflush.h>
34#include "common.h"
26 35
27static void __iomem *pmsu_mp_base; 36static void __iomem *pmsu_mp_base;
28static void __iomem *pmsu_reset_base;
29 37
30#define PMSU_BOOT_ADDR_REDIRECT_OFFSET(cpu) ((cpu * 0x100) + 0x24) 38#define PMSU_BASE_OFFSET 0x100
31#define PMSU_RESET_CTL_OFFSET(cpu) (cpu * 0x8) 39#define PMSU_REG_SIZE 0x1000
40
41/* PMSU MP registers */
42#define PMSU_CONTROL_AND_CONFIG(cpu) ((cpu * 0x100) + 0x104)
43#define PMSU_CONTROL_AND_CONFIG_DFS_REQ BIT(18)
44#define PMSU_CONTROL_AND_CONFIG_PWDDN_REQ BIT(16)
45#define PMSU_CONTROL_AND_CONFIG_L2_PWDDN BIT(20)
46
47#define PMSU_CPU_POWER_DOWN_CONTROL(cpu) ((cpu * 0x100) + 0x108)
48
49#define PMSU_CPU_POWER_DOWN_DIS_SNP_Q_SKIP BIT(0)
50
51#define PMSU_STATUS_AND_MASK(cpu) ((cpu * 0x100) + 0x10c)
52#define PMSU_STATUS_AND_MASK_CPU_IDLE_WAIT BIT(16)
53#define PMSU_STATUS_AND_MASK_SNP_Q_EMPTY_WAIT BIT(17)
54#define PMSU_STATUS_AND_MASK_IRQ_WAKEUP BIT(20)
55#define PMSU_STATUS_AND_MASK_FIQ_WAKEUP BIT(21)
56#define PMSU_STATUS_AND_MASK_DBG_WAKEUP BIT(22)
57#define PMSU_STATUS_AND_MASK_IRQ_MASK BIT(24)
58#define PMSU_STATUS_AND_MASK_FIQ_MASK BIT(25)
59
60#define PMSU_BOOT_ADDR_REDIRECT_OFFSET(cpu) ((cpu * 0x100) + 0x124)
61
62/* PMSU fabric registers */
63#define L2C_NFABRIC_PM_CTL 0x4
64#define L2C_NFABRIC_PM_CTL_PWR_DOWN BIT(20)
65
66extern void ll_disable_coherency(void);
67extern void ll_enable_coherency(void);
68
69static struct platform_device armada_xp_cpuidle_device = {
70 .name = "cpuidle-armada-370-xp",
71};
32 72
33static struct of_device_id of_pmsu_table[] = { 73static struct of_device_id of_pmsu_table[] = {
34 {.compatible = "marvell,armada-370-xp-pmsu"}, 74 { .compatible = "marvell,armada-370-pmsu", },
75 { .compatible = "marvell,armada-370-xp-pmsu", },
76 { .compatible = "marvell,armada-380-pmsu", },
35 { /* end of list */ }, 77 { /* end of list */ },
36}; 78};
37 79
38#ifdef CONFIG_SMP 80void mvebu_pmsu_set_cpu_boot_addr(int hw_cpu, void *boot_addr)
39int armada_xp_boot_cpu(unsigned int cpu_id, void *boot_addr)
40{ 81{
41 int reg, hw_cpu; 82 writel(virt_to_phys(boot_addr), pmsu_mp_base +
83 PMSU_BOOT_ADDR_REDIRECT_OFFSET(hw_cpu));
84}
85
86static int __init armada_370_xp_pmsu_init(void)
87{
88 struct device_node *np;
89 struct resource res;
90 int ret = 0;
91
92 np = of_find_matching_node(NULL, of_pmsu_table);
93 if (!np)
94 return 0;
95
96 pr_info("Initializing Power Management Service Unit\n");
42 97
43 if (!pmsu_mp_base || !pmsu_reset_base) { 98 if (of_address_to_resource(np, 0, &res)) {
44 pr_warn("Can't boot CPU. PMSU is uninitialized\n"); 99 pr_err("unable to get resource\n");
45 return 1; 100 ret = -ENOENT;
101 goto out;
46 } 102 }
47 103
48 hw_cpu = cpu_logical_map(cpu_id); 104 if (of_device_is_compatible(np, "marvell,armada-370-xp-pmsu")) {
105 pr_warn(FW_WARN "deprecated pmsu binding\n");
106 res.start = res.start - PMSU_BASE_OFFSET;
107 res.end = res.start + PMSU_REG_SIZE - 1;
108 }
49 109
50 writel(virt_to_phys(boot_addr), pmsu_mp_base + 110 if (!request_mem_region(res.start, resource_size(&res),
51 PMSU_BOOT_ADDR_REDIRECT_OFFSET(hw_cpu)); 111 np->full_name)) {
112 pr_err("unable to request region\n");
113 ret = -EBUSY;
114 goto out;
115 }
116
117 pmsu_mp_base = ioremap(res.start, resource_size(&res));
118 if (!pmsu_mp_base) {
119 pr_err("unable to map registers\n");
120 release_mem_region(res.start, resource_size(&res));
121 ret = -ENOMEM;
122 goto out;
123 }
124
125 out:
126 of_node_put(np);
127 return ret;
128}
129
130static void armada_370_xp_pmsu_enable_l2_powerdown_onidle(void)
131{
132 u32 reg;
133
134 if (pmsu_mp_base == NULL)
135 return;
136
137 /* Enable L2 & Fabric powerdown in Deep-Idle mode - Fabric */
138 reg = readl(pmsu_mp_base + L2C_NFABRIC_PM_CTL);
139 reg |= L2C_NFABRIC_PM_CTL_PWR_DOWN;
140 writel(reg, pmsu_mp_base + L2C_NFABRIC_PM_CTL);
141}
142
143static void armada_370_xp_cpu_resume(void)
144{
145 asm volatile("bl ll_add_cpu_to_smp_group\n\t"
146 "bl ll_enable_coherency\n\t"
147 "b cpu_resume\n\t");
148}
149
150/* No locking is needed because we only access per-CPU registers */
151void armada_370_xp_pmsu_idle_prepare(bool deepidle)
152{
153 unsigned int hw_cpu = cpu_logical_map(smp_processor_id());
154 u32 reg;
155
156 if (pmsu_mp_base == NULL)
157 return;
52 158
53 /* Release CPU from reset by clearing reset bit*/ 159 /*
54 reg = readl(pmsu_reset_base + PMSU_RESET_CTL_OFFSET(hw_cpu)); 160 * Adjust the PMSU configuration to wait for WFI signal, enable
55 reg &= (~0x1); 161 * IRQ and FIQ as wakeup events, set wait for snoop queue empty
56 writel(reg, pmsu_reset_base + PMSU_RESET_CTL_OFFSET(hw_cpu)); 162 * indication and mask IRQ and FIQ from CPU
163 */
164 reg = readl(pmsu_mp_base + PMSU_STATUS_AND_MASK(hw_cpu));
165 reg |= PMSU_STATUS_AND_MASK_CPU_IDLE_WAIT |
166 PMSU_STATUS_AND_MASK_IRQ_WAKEUP |
167 PMSU_STATUS_AND_MASK_FIQ_WAKEUP |
168 PMSU_STATUS_AND_MASK_SNP_Q_EMPTY_WAIT |
169 PMSU_STATUS_AND_MASK_IRQ_MASK |
170 PMSU_STATUS_AND_MASK_FIQ_MASK;
171 writel(reg, pmsu_mp_base + PMSU_STATUS_AND_MASK(hw_cpu));
172
173 reg = readl(pmsu_mp_base + PMSU_CONTROL_AND_CONFIG(hw_cpu));
174 /* ask HW to power down the L2 Cache if needed */
175 if (deepidle)
176 reg |= PMSU_CONTROL_AND_CONFIG_L2_PWDDN;
177
178 /* request power down */
179 reg |= PMSU_CONTROL_AND_CONFIG_PWDDN_REQ;
180 writel(reg, pmsu_mp_base + PMSU_CONTROL_AND_CONFIG(hw_cpu));
181
182 /* Disable snoop disable by HW - SW is taking care of it */
183 reg = readl(pmsu_mp_base + PMSU_CPU_POWER_DOWN_CONTROL(hw_cpu));
184 reg |= PMSU_CPU_POWER_DOWN_DIS_SNP_Q_SKIP;
185 writel(reg, pmsu_mp_base + PMSU_CPU_POWER_DOWN_CONTROL(hw_cpu));
186}
187
188static noinline int do_armada_370_xp_cpu_suspend(unsigned long deepidle)
189{
190 armada_370_xp_pmsu_idle_prepare(deepidle);
191
192 v7_exit_coherency_flush(all);
193
194 ll_disable_coherency();
195
196 dsb();
197
198 wfi();
199
200 /* If we are here, wfi failed. As processors run out of
201 * coherency for some time, tlbs might be stale, so flush them
202 */
203 local_flush_tlb_all();
204
205 ll_enable_coherency();
206
207 /* Test the CR_C bit and set it if it was cleared */
208 asm volatile(
209 "mrc p15, 0, %0, c1, c0, 0 \n\t"
210 "tst %0, #(1 << 2) \n\t"
211 "orreq %0, %0, #(1 << 2) \n\t"
212 "mcreq p15, 0, %0, c1, c0, 0 \n\t"
213 "isb "
214 : : "r" (0));
215
216 pr_warn("Failed to suspend the system\n");
57 217
58 return 0; 218 return 0;
59} 219}
60#endif
61 220
62static int __init armada_370_xp_pmsu_init(void) 221static int armada_370_xp_cpu_suspend(unsigned long deepidle)
222{
223 return cpu_suspend(deepidle, do_armada_370_xp_cpu_suspend);
224}
225
226/* No locking is needed because we only access per-CPU registers */
227static noinline void armada_370_xp_pmsu_idle_restore(void)
228{
229 unsigned int hw_cpu = cpu_logical_map(smp_processor_id());
230 u32 reg;
231
232 if (pmsu_mp_base == NULL)
233 return;
234
235 /* cancel ask HW to power down the L2 Cache if possible */
236 reg = readl(pmsu_mp_base + PMSU_CONTROL_AND_CONFIG(hw_cpu));
237 reg &= ~PMSU_CONTROL_AND_CONFIG_L2_PWDDN;
238 writel(reg, pmsu_mp_base + PMSU_CONTROL_AND_CONFIG(hw_cpu));
239
240 /* cancel Enable wakeup events and mask interrupts */
241 reg = readl(pmsu_mp_base + PMSU_STATUS_AND_MASK(hw_cpu));
242 reg &= ~(PMSU_STATUS_AND_MASK_IRQ_WAKEUP | PMSU_STATUS_AND_MASK_FIQ_WAKEUP);
243 reg &= ~PMSU_STATUS_AND_MASK_CPU_IDLE_WAIT;
244 reg &= ~PMSU_STATUS_AND_MASK_SNP_Q_EMPTY_WAIT;
245 reg &= ~(PMSU_STATUS_AND_MASK_IRQ_MASK | PMSU_STATUS_AND_MASK_FIQ_MASK);
246 writel(reg, pmsu_mp_base + PMSU_STATUS_AND_MASK(hw_cpu));
247}
248
249static int armada_370_xp_cpu_pm_notify(struct notifier_block *self,
250 unsigned long action, void *hcpu)
251{
252 if (action == CPU_PM_ENTER) {
253 unsigned int hw_cpu = cpu_logical_map(smp_processor_id());
254 mvebu_pmsu_set_cpu_boot_addr(hw_cpu, armada_370_xp_cpu_resume);
255 } else if (action == CPU_PM_EXIT) {
256 armada_370_xp_pmsu_idle_restore();
257 }
258
259 return NOTIFY_OK;
260}
261
262static struct notifier_block armada_370_xp_cpu_pm_notifier = {
263 .notifier_call = armada_370_xp_cpu_pm_notify,
264};
265
266int __init armada_370_xp_cpu_pm_init(void)
63{ 267{
64 struct device_node *np; 268 struct device_node *np;
65 269
270 /*
271 * Check that all the requirements are available to enable
272 * cpuidle. So far, it is only supported on Armada XP, cpuidle
273 * needs the coherency fabric and the PMSU enabled
274 */
275
276 if (!of_machine_is_compatible("marvell,armadaxp"))
277 return 0;
278
279 np = of_find_compatible_node(NULL, NULL, "marvell,coherency-fabric");
280 if (!np)
281 return 0;
282 of_node_put(np);
283
66 np = of_find_matching_node(NULL, of_pmsu_table); 284 np = of_find_matching_node(NULL, of_pmsu_table);
67 if (np) { 285 if (!np)
68 pr_info("Initializing Power Management Service Unit\n"); 286 return 0;
69 pmsu_mp_base = of_iomap(np, 0); 287 of_node_put(np);
70 pmsu_reset_base = of_iomap(np, 1); 288
71 of_node_put(np); 289 armada_370_xp_pmsu_enable_l2_powerdown_onidle();
72 } 290 armada_xp_cpuidle_device.dev.platform_data = armada_370_xp_cpu_suspend;
291 platform_device_register(&armada_xp_cpuidle_device);
292 cpu_pm_register_notifier(&armada_370_xp_cpu_pm_notifier);
73 293
74 return 0; 294 return 0;
75} 295}
76 296
297arch_initcall(armada_370_xp_cpu_pm_init);
77early_initcall(armada_370_xp_pmsu_init); 298early_initcall(armada_370_xp_pmsu_init);
diff --git a/arch/arm/mach-mvebu/system-controller.c b/arch/arm/mach-mvebu/system-controller.c
index 614ba6832ff3..0c5524ac75b7 100644
--- a/arch/arm/mach-mvebu/system-controller.c
+++ b/arch/arm/mach-mvebu/system-controller.c
@@ -37,6 +37,8 @@ struct mvebu_system_controller {
37 37
38 u32 rstoutn_mask_reset_out_en; 38 u32 rstoutn_mask_reset_out_en;
39 u32 system_soft_reset; 39 u32 system_soft_reset;
40
41 u32 resume_boot_addr;
40}; 42};
41static struct mvebu_system_controller *mvebu_sc; 43static struct mvebu_system_controller *mvebu_sc;
42 44
@@ -52,6 +54,7 @@ static const struct mvebu_system_controller armada_375_system_controller = {
52 .system_soft_reset_offset = 0x58, 54 .system_soft_reset_offset = 0x58,
53 .rstoutn_mask_reset_out_en = 0x1, 55 .rstoutn_mask_reset_out_en = 0x1,
54 .system_soft_reset = 0x1, 56 .system_soft_reset = 0x1,
57 .resume_boot_addr = 0xd4,
55}; 58};
56 59
57static const struct mvebu_system_controller orion_system_controller = { 60static const struct mvebu_system_controller orion_system_controller = {
@@ -98,6 +101,16 @@ void mvebu_restart(enum reboot_mode mode, const char *cmd)
98 ; 101 ;
99} 102}
100 103
104#ifdef CONFIG_SMP
105void mvebu_system_controller_set_cpu_boot_addr(void *boot_addr)
106{
107 BUG_ON(system_controller_base == NULL);
108 BUG_ON(mvebu_sc->resume_boot_addr == 0);
109 writel(virt_to_phys(boot_addr), system_controller_base +
110 mvebu_sc->resume_boot_addr);
111}
112#endif
113
101static int __init mvebu_system_controller_init(void) 114static int __init mvebu_system_controller_init(void)
102{ 115{
103 const struct of_device_id *match; 116 const struct of_device_id *match;
@@ -114,4 +127,4 @@ static int __init mvebu_system_controller_init(void)
114 return 0; 127 return 0;
115} 128}
116 129
117arch_initcall(mvebu_system_controller_init); 130early_initcall(mvebu_system_controller_init);
diff --git a/drivers/bus/mvebu-mbus.c b/drivers/bus/mvebu-mbus.c
index 293e2e0a0a87..ff02fc90fc21 100644
--- a/drivers/bus/mvebu-mbus.c
+++ b/drivers/bus/mvebu-mbus.c
@@ -694,7 +694,6 @@ static int __init mvebu_mbus_common_init(struct mvebu_mbus_state *mbus,
694 phys_addr_t sdramwins_phys_base, 694 phys_addr_t sdramwins_phys_base,
695 size_t sdramwins_size) 695 size_t sdramwins_size)
696{ 696{
697 struct device_node *np;
698 int win; 697 int win;
699 698
700 mbus->mbuswins_base = ioremap(mbuswins_phys_base, mbuswins_size); 699 mbus->mbuswins_base = ioremap(mbuswins_phys_base, mbuswins_size);
@@ -707,12 +706,6 @@ static int __init mvebu_mbus_common_init(struct mvebu_mbus_state *mbus,
707 return -ENOMEM; 706 return -ENOMEM;
708 } 707 }
709 708
710 np = of_find_compatible_node(NULL, NULL, "marvell,coherency-fabric");
711 if (np) {
712 mbus->hw_io_coherency = 1;
713 of_node_put(np);
714 }
715
716 for (win = 0; win < mbus->soc->num_wins; win++) 709 for (win = 0; win < mbus->soc->num_wins; win++)
717 mvebu_mbus_disable_window(mbus, win); 710 mvebu_mbus_disable_window(mbus, win);
718 711
@@ -882,7 +875,7 @@ static void __init mvebu_mbus_get_pcie_resources(struct device_node *np,
882 } 875 }
883} 876}
884 877
885int __init mvebu_mbus_dt_init(void) 878int __init mvebu_mbus_dt_init(bool is_coherent)
886{ 879{
887 struct resource mbuswins_res, sdramwins_res; 880 struct resource mbuswins_res, sdramwins_res;
888 struct device_node *np, *controller; 881 struct device_node *np, *controller;
@@ -920,6 +913,8 @@ int __init mvebu_mbus_dt_init(void)
920 return -EINVAL; 913 return -EINVAL;
921 } 914 }
922 915
916 mbus_state.hw_io_coherency = is_coherent;
917
923 /* Get optional pcie-{mem,io}-aperture properties */ 918 /* Get optional pcie-{mem,io}-aperture properties */
924 mvebu_mbus_get_pcie_resources(np, &mbus_state.pcie_mem_aperture, 919 mvebu_mbus_get_pcie_resources(np, &mbus_state.pcie_mem_aperture,
925 &mbus_state.pcie_io_aperture); 920 &mbus_state.pcie_io_aperture);
diff --git a/drivers/cpuidle/Kconfig.arm b/drivers/cpuidle/Kconfig.arm
index 97ccc31dbdd8..5bb94780d377 100644
--- a/drivers/cpuidle/Kconfig.arm
+++ b/drivers/cpuidle/Kconfig.arm
@@ -1,6 +1,11 @@
1# 1#
2# ARM CPU Idle drivers 2# ARM CPU Idle drivers
3# 3#
4config ARM_ARMADA_370_XP_CPUIDLE
5 bool "CPU Idle Driver for Armada 370/XP family processors"
6 depends on ARCH_MVEBU
7 help
8 Select this to enable cpuidle on Armada 370/XP processors.
4 9
5config ARM_BIG_LITTLE_CPUIDLE 10config ARM_BIG_LITTLE_CPUIDLE
6 bool "Support for ARM big.LITTLE processors" 11 bool "Support for ARM big.LITTLE processors"
diff --git a/drivers/cpuidle/Makefile b/drivers/cpuidle/Makefile
index f71ae1b373c5..9902d052bd87 100644
--- a/drivers/cpuidle/Makefile
+++ b/drivers/cpuidle/Makefile
@@ -7,6 +7,7 @@ obj-$(CONFIG_ARCH_NEEDS_CPU_IDLE_COUPLED) += coupled.o
7 7
8################################################################################## 8##################################################################################
9# ARM SoC drivers 9# ARM SoC drivers
10obj-$(CONFIG_ARM_ARMADA_370_XP_CPUIDLE) += cpuidle-armada-370-xp.o
10obj-$(CONFIG_ARM_BIG_LITTLE_CPUIDLE) += cpuidle-big_little.o 11obj-$(CONFIG_ARM_BIG_LITTLE_CPUIDLE) += cpuidle-big_little.o
11obj-$(CONFIG_ARM_HIGHBANK_CPUIDLE) += cpuidle-calxeda.o 12obj-$(CONFIG_ARM_HIGHBANK_CPUIDLE) += cpuidle-calxeda.o
12obj-$(CONFIG_ARM_KIRKWOOD_CPUIDLE) += cpuidle-kirkwood.o 13obj-$(CONFIG_ARM_KIRKWOOD_CPUIDLE) += cpuidle-kirkwood.o
diff --git a/drivers/cpuidle/cpuidle-armada-370-xp.c b/drivers/cpuidle/cpuidle-armada-370-xp.c
new file mode 100644
index 000000000000..28587d0f3947
--- /dev/null
+++ b/drivers/cpuidle/cpuidle-armada-370-xp.c
@@ -0,0 +1,93 @@
1/*
2 * Marvell Armada 370 and Armada XP SoC cpuidle driver
3 *
4 * Copyright (C) 2014 Marvell
5 *
6 * Nadav Haklai <nadavh@marvell.com>
7 * Gregory CLEMENT <gregory.clement@free-electrons.com>
8 *
9 * This file is licensed under the terms of the GNU General Public
10 * License version 2. This program is licensed "as is" without any
11 * warranty of any kind, whether express or implied.
12 *
13 * Maintainer: Gregory CLEMENT <gregory.clement@free-electrons.com>
14 */
15
16#include <linux/cpu_pm.h>
17#include <linux/cpuidle.h>
18#include <linux/module.h>
19#include <linux/of.h>
20#include <linux/suspend.h>
21#include <linux/platform_device.h>
22#include <asm/cpuidle.h>
23
24#define ARMADA_370_XP_MAX_STATES 3
25#define ARMADA_370_XP_FLAG_DEEP_IDLE 0x10000
26
27static int (*armada_370_xp_cpu_suspend)(int);
28
29static int armada_370_xp_enter_idle(struct cpuidle_device *dev,
30 struct cpuidle_driver *drv,
31 int index)
32{
33 int ret;
34 bool deepidle = false;
35 cpu_pm_enter();
36
37 if (drv->states[index].flags & ARMADA_370_XP_FLAG_DEEP_IDLE)
38 deepidle = true;
39
40 ret = armada_370_xp_cpu_suspend(deepidle);
41 if (ret)
42 return ret;
43
44 cpu_pm_exit();
45
46 return index;
47}
48
49static struct cpuidle_driver armada_370_xp_idle_driver = {
50 .name = "armada_370_xp_idle",
51 .states[0] = ARM_CPUIDLE_WFI_STATE,
52 .states[1] = {
53 .enter = armada_370_xp_enter_idle,
54 .exit_latency = 10,
55 .power_usage = 50,
56 .target_residency = 100,
57 .flags = CPUIDLE_FLAG_TIME_VALID,
58 .name = "MV CPU IDLE",
59 .desc = "CPU power down",
60 },
61 .states[2] = {
62 .enter = armada_370_xp_enter_idle,
63 .exit_latency = 100,
64 .power_usage = 5,
65 .target_residency = 1000,
66 .flags = CPUIDLE_FLAG_TIME_VALID |
67 ARMADA_370_XP_FLAG_DEEP_IDLE,
68 .name = "MV CPU DEEP IDLE",
69 .desc = "CPU and L2 Fabric power down",
70 },
71 .state_count = ARMADA_370_XP_MAX_STATES,
72};
73
74static int armada_370_xp_cpuidle_probe(struct platform_device *pdev)
75{
76
77 armada_370_xp_cpu_suspend = (void *)(pdev->dev.platform_data);
78 return cpuidle_register(&armada_370_xp_idle_driver, NULL);
79}
80
81static struct platform_driver armada_370_xp_cpuidle_plat_driver = {
82 .driver = {
83 .name = "cpuidle-armada-370-xp",
84 .owner = THIS_MODULE,
85 },
86 .probe = armada_370_xp_cpuidle_probe,
87};
88
89module_platform_driver(armada_370_xp_cpuidle_plat_driver);
90
91MODULE_AUTHOR("Gregory CLEMENT <gregory.clement@free-electrons.com>");
92MODULE_DESCRIPTION("Armada 370/XP cpu idle driver");
93MODULE_LICENSE("GPL");
diff --git a/drivers/irqchip/irq-armada-370-xp.c b/drivers/irqchip/irq-armada-370-xp.c
index 3899ba7821c5..c887e6eebc41 100644
--- a/drivers/irqchip/irq-armada-370-xp.c
+++ b/drivers/irqchip/irq-armada-370-xp.c
@@ -19,6 +19,7 @@
19#include <linux/irq.h> 19#include <linux/irq.h>
20#include <linux/interrupt.h> 20#include <linux/interrupt.h>
21#include <linux/irqchip/chained_irq.h> 21#include <linux/irqchip/chained_irq.h>
22#include <linux/cpu.h>
22#include <linux/io.h> 23#include <linux/io.h>
23#include <linux/of_address.h> 24#include <linux/of_address.h>
24#include <linux/of_irq.h> 25#include <linux/of_irq.h>
@@ -310,7 +311,8 @@ static int armada_370_xp_mpic_irq_map(struct irq_domain *h,
310} 311}
311 312
312#ifdef CONFIG_SMP 313#ifdef CONFIG_SMP
313void armada_mpic_send_doorbell(const struct cpumask *mask, unsigned int irq) 314static void armada_mpic_send_doorbell(const struct cpumask *mask,
315 unsigned int irq)
314{ 316{
315 int cpu; 317 int cpu;
316 unsigned long map = 0; 318 unsigned long map = 0;
@@ -330,7 +332,7 @@ void armada_mpic_send_doorbell(const struct cpumask *mask, unsigned int irq)
330 ARMADA_370_XP_SW_TRIG_INT_OFFS); 332 ARMADA_370_XP_SW_TRIG_INT_OFFS);
331} 333}
332 334
333void armada_xp_mpic_smp_cpu_init(void) 335static void armada_xp_mpic_smp_cpu_init(void)
334{ 336{
335 /* Clear pending IPIs */ 337 /* Clear pending IPIs */
336 writel(0, per_cpu_int_base + ARMADA_370_XP_IN_DRBEL_CAUSE_OFFS); 338 writel(0, per_cpu_int_base + ARMADA_370_XP_IN_DRBEL_CAUSE_OFFS);
@@ -342,6 +344,20 @@ void armada_xp_mpic_smp_cpu_init(void)
342 /* Unmask IPI interrupt */ 344 /* Unmask IPI interrupt */
343 writel(0, per_cpu_int_base + ARMADA_370_XP_INT_CLEAR_MASK_OFFS); 345 writel(0, per_cpu_int_base + ARMADA_370_XP_INT_CLEAR_MASK_OFFS);
344} 346}
347
348static int armada_xp_mpic_secondary_init(struct notifier_block *nfb,
349 unsigned long action, void *hcpu)
350{
351 if (action == CPU_STARTING || action == CPU_STARTING_FROZEN)
352 armada_xp_mpic_smp_cpu_init();
353 return NOTIFY_OK;
354}
355
356static struct notifier_block armada_370_xp_mpic_cpu_notifier = {
357 .notifier_call = armada_xp_mpic_secondary_init,
358 .priority = 100,
359};
360
345#endif /* CONFIG_SMP */ 361#endif /* CONFIG_SMP */
346 362
347static struct irq_domain_ops armada_370_xp_mpic_irq_ops = { 363static struct irq_domain_ops armada_370_xp_mpic_irq_ops = {
@@ -497,6 +513,10 @@ static int __init armada_370_xp_mpic_of_init(struct device_node *node,
497 if (parent_irq <= 0) { 513 if (parent_irq <= 0) {
498 irq_set_default_host(armada_370_xp_mpic_domain); 514 irq_set_default_host(armada_370_xp_mpic_domain);
499 set_handle_irq(armada_370_xp_handle_irq); 515 set_handle_irq(armada_370_xp_handle_irq);
516#ifdef CONFIG_SMP
517 set_smp_cross_call(armada_mpic_send_doorbell);
518 register_cpu_notifier(&armada_370_xp_mpic_cpu_notifier);
519#endif
500 } else { 520 } else {
501 irq_set_chained_handler(parent_irq, 521 irq_set_chained_handler(parent_irq,
502 armada_370_xp_mpic_handle_cascade_irq); 522 armada_370_xp_mpic_handle_cascade_irq);
diff --git a/drivers/irqchip/irq-orion.c b/drivers/irqchip/irq-orion.c
index e25f246cd2fb..34d18b48bb78 100644
--- a/drivers/irqchip/irq-orion.c
+++ b/drivers/irqchip/irq-orion.c
@@ -42,7 +42,7 @@ __exception_irq_entry orion_handle_irq(struct pt_regs *regs)
42 u32 stat = readl_relaxed(gc->reg_base + ORION_IRQ_CAUSE) & 42 u32 stat = readl_relaxed(gc->reg_base + ORION_IRQ_CAUSE) &
43 gc->mask_cache; 43 gc->mask_cache;
44 while (stat) { 44 while (stat) {
45 u32 hwirq = ffs(stat) - 1; 45 u32 hwirq = __fls(stat);
46 u32 irq = irq_find_mapping(orion_irq_domain, 46 u32 irq = irq_find_mapping(orion_irq_domain,
47 gc->irq_base + hwirq); 47 gc->irq_base + hwirq);
48 handle_IRQ(irq, regs); 48 handle_IRQ(irq, regs);
@@ -117,7 +117,7 @@ static void orion_bridge_irq_handler(unsigned int irq, struct irq_desc *desc)
117 gc->mask_cache; 117 gc->mask_cache;
118 118
119 while (stat) { 119 while (stat) {
120 u32 hwirq = ffs(stat) - 1; 120 u32 hwirq = __fls(stat);
121 121
122 generic_handle_irq(irq_find_mapping(d, gc->irq_base + hwirq)); 122 generic_handle_irq(irq_find_mapping(d, gc->irq_base + hwirq));
123 stat &= ~(1 << hwirq); 123 stat &= ~(1 << hwirq);
diff --git a/include/linux/mbus.h b/include/linux/mbus.h
index 345b8c53b897..550c88fb0267 100644
--- a/include/linux/mbus.h
+++ b/include/linux/mbus.h
@@ -73,6 +73,6 @@ int mvebu_mbus_del_window(phys_addr_t base, size_t size);
73int mvebu_mbus_init(const char *soc, phys_addr_t mbus_phys_base, 73int mvebu_mbus_init(const char *soc, phys_addr_t mbus_phys_base,
74 size_t mbus_size, phys_addr_t sdram_phys_base, 74 size_t mbus_size, phys_addr_t sdram_phys_base,
75 size_t sdram_size); 75 size_t sdram_size);
76int mvebu_mbus_dt_init(void); 76int mvebu_mbus_dt_init(bool is_coherent);
77 77
78#endif /* __LINUX_MBUS_H */ 78#endif /* __LINUX_MBUS_H */