aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorArnd Bergmann <arnd@arndb.de>2014-12-04 10:46:43 -0500
committerArnd Bergmann <arnd@arndb.de>2014-12-04 10:46:43 -0500
commitab64920c3742ba992a3bf0b06f9750d1cad9d050 (patch)
tree3391e85b0bb7372d7d34775047e9d8c894042938
parent756f80cee766574ae282baa97fdcf9cc6d0cc70c (diff)
parent6e6db2bea3ea9424a0cb19d89d47664bc13e31bc (diff)
Merge tag 'mvebu-soc-suspend-3.19' of git://git.infradead.org/linux-mvebu into next/soc
Pull "mvebu SoC suspend changes for v3.19" from Jason Cooper: - Armada 370/XP suspend/resume support - mvebu SoC driver suspend/resume support - irqchip - clocksource - mbus - clk * tag 'mvebu-soc-suspend-3.19' of git://git.infradead.org/linux-mvebu: ARM: mvebu: add SDRAM controller description for Armada XP ARM: mvebu: adjust mbus controller description on Armada 370/XP ARM: mvebu: add suspend/resume DT information for Armada XP GP ARM: mvebu: synchronize secondary CPU clocks on resume ARM: mvebu: make sure MMU is disabled in armada_370_xp_cpu_resume ARM: mvebu: Armada XP GP specific suspend/resume code ARM: mvebu: reserve the first 10 KB of each memory bank for suspend/resume ARM: mvebu: implement suspend/resume support for Armada XP clk: mvebu: add suspend/resume for gatable clocks bus: mvebu-mbus: provide a mechanism to save SDRAM window configuration bus: mvebu-mbus: suspend/resume support clocksource: time-armada-370-xp: add suspend/resume support irqchip: armada-370-xp: Add suspend/resume support Documentation: dt-bindings: minimal documentation for MVEBU SDRAM controller Signed-off-by: Arnd Bergmann <arnd@arndb.de>
-rw-r--r--Documentation/devicetree/bindings/bus/mvebu-mbus.txt17
-rw-r--r--Documentation/devicetree/bindings/memory-controllers/mvebu-sdram-controller.txt21
-rw-r--r--arch/arm/boot/dts/armada-370-xp.dtsi3
-rw-r--r--arch/arm/boot/dts/armada-xp-gp.dts19
-rw-r--r--arch/arm/boot/dts/armada-xp.dtsi5
-rw-r--r--arch/arm/mach-mvebu/Makefile2
-rw-r--r--arch/arm/mach-mvebu/board-v7.c51
-rw-r--r--arch/arm/mach-mvebu/common.h2
-rw-r--r--arch/arm/mach-mvebu/platsmp.c31
-rw-r--r--arch/arm/mach-mvebu/pm-board.c141
-rw-r--r--arch/arm/mach-mvebu/pm.c218
-rw-r--r--arch/arm/mach-mvebu/pmsu.h1
-rw-r--r--arch/arm/mach-mvebu/pmsu_ll.S8
-rw-r--r--drivers/bus/mvebu-mbus.c180
-rw-r--r--drivers/clk/mvebu/common.c32
-rw-r--r--drivers/clocksource/time-armada-370-xp.c25
-rw-r--r--drivers/irqchip/irq-armada-370-xp.c52
-rw-r--r--include/linux/mbus.h1
18 files changed, 777 insertions, 32 deletions
diff --git a/Documentation/devicetree/bindings/bus/mvebu-mbus.txt b/Documentation/devicetree/bindings/bus/mvebu-mbus.txt
index 5fa44f52a0b8..5e16c3ccb061 100644
--- a/Documentation/devicetree/bindings/bus/mvebu-mbus.txt
+++ b/Documentation/devicetree/bindings/bus/mvebu-mbus.txt
@@ -48,9 +48,12 @@ Required properties:
48- compatible: Should be set to "marvell,mbus-controller". 48- compatible: Should be set to "marvell,mbus-controller".
49 49
50- reg: Device's register space. 50- reg: Device's register space.
51 Two entries are expected (see the examples below): 51 Two or three entries are expected (see the examples below):
52 the first one controls the devices decoding window and 52 the first one controls the devices decoding window,
53 the second one controls the SDRAM decoding window. 53 the second one controls the SDRAM decoding window and
54 the third controls the MBus bridge (only with the
55 marvell,armada370-mbus and marvell,armadaxp-mbus
56 compatible strings)
54 57
55Example: 58Example:
56 59
@@ -67,7 +70,7 @@ Example:
67 70
68 mbusc: mbus-controller@20000 { 71 mbusc: mbus-controller@20000 {
69 compatible = "marvell,mbus-controller"; 72 compatible = "marvell,mbus-controller";
70 reg = <0x20000 0x100>, <0x20180 0x20>; 73 reg = <0x20000 0x100>, <0x20180 0x20>, <0x20250 0x8>;
71 }; 74 };
72 75
73 /* more children ...*/ 76 /* more children ...*/
@@ -126,7 +129,7 @@ are skipped.
126 129
127 mbusc: mbus-controller@20000 { 130 mbusc: mbus-controller@20000 {
128 compatible = "marvell,mbus-controller"; 131 compatible = "marvell,mbus-controller";
129 reg = <0x20000 0x100>, <0x20180 0x20>; 132 reg = <0x20000 0x100>, <0x20180 0x20>, <0x20250 0x8>;
130 }; 133 };
131 134
132 /* more children ...*/ 135 /* more children ...*/
@@ -170,7 +173,7 @@ Using this macro, the above example would be:
170 173
171 mbusc: mbus-controller@20000 { 174 mbusc: mbus-controller@20000 {
172 compatible = "marvell,mbus-controller"; 175 compatible = "marvell,mbus-controller";
173 reg = <0x20000 0x100>, <0x20180 0x20>; 176 reg = <0x20000 0x100>, <0x20180 0x20>, <0x20250 0x8>;
174 }; 177 };
175 178
176 /* other children */ 179 /* other children */
@@ -266,7 +269,7 @@ See the example below, where a more complete device tree is shown:
266 ranges = <0 MBUS_ID(0xf0, 0x01) 0 0x100000>; 269 ranges = <0 MBUS_ID(0xf0, 0x01) 0 0x100000>;
267 270
268 mbusc: mbus-controller@20000 { 271 mbusc: mbus-controller@20000 {
269 reg = <0x20000 0x100>, <0x20180 0x20>; 272 reg = <0x20000 0x100>, <0x20180 0x20>, <0x20250 0x8>;
270 }; 273 };
271 274
272 interrupt-controller@20000 { 275 interrupt-controller@20000 {
diff --git a/Documentation/devicetree/bindings/memory-controllers/mvebu-sdram-controller.txt b/Documentation/devicetree/bindings/memory-controllers/mvebu-sdram-controller.txt
new file mode 100644
index 000000000000..89657d1d4cd4
--- /dev/null
+++ b/Documentation/devicetree/bindings/memory-controllers/mvebu-sdram-controller.txt
@@ -0,0 +1,21 @@
1Device Tree bindings for MVEBU SDRAM controllers
2
3The Marvell EBU SoCs all have a SDRAM controller. The SDRAM controller
4differs from one SoC variant to another, but they also share a number
5of commonalities.
6
7For now, this Device Tree binding documentation only documents the
8Armada XP SDRAM controller.
9
10Required properties:
11
12 - compatible: for Armada XP, "marvell,armada-xp-sdram-controller"
13 - reg: a resource specifier for the register space, which should
14 include all SDRAM controller registers as per the datasheet.
15
16Example:
17
18sdramc@1400 {
19 compatible = "marvell,armada-xp-sdram-controller";
20 reg = <0x1400 0x500>;
21};
diff --git a/arch/arm/boot/dts/armada-370-xp.dtsi b/arch/arm/boot/dts/armada-370-xp.dtsi
index 83286ec9702c..90dba78554c8 100644
--- a/arch/arm/boot/dts/armada-370-xp.dtsi
+++ b/arch/arm/boot/dts/armada-370-xp.dtsi
@@ -180,7 +180,8 @@
180 180
181 mbusc: mbus-controller@20000 { 181 mbusc: mbus-controller@20000 {
182 compatible = "marvell,mbus-controller"; 182 compatible = "marvell,mbus-controller";
183 reg = <0x20000 0x100>, <0x20180 0x20>; 183 reg = <0x20000 0x100>, <0x20180 0x20>,
184 <0x20250 0x8>;
184 }; 185 };
185 186
186 mpic: interrupt-controller@20000 { 187 mpic: interrupt-controller@20000 {
diff --git a/arch/arm/boot/dts/armada-xp-gp.dts b/arch/arm/boot/dts/armada-xp-gp.dts
index 0478c55ca656..ea8673647494 100644
--- a/arch/arm/boot/dts/armada-xp-gp.dts
+++ b/arch/arm/boot/dts/armada-xp-gp.dts
@@ -23,6 +23,7 @@
23 */ 23 */
24 24
25/dts-v1/; 25/dts-v1/;
26#include <dt-bindings/gpio/gpio.h>
26#include "armada-xp-mv78460.dtsi" 27#include "armada-xp-mv78460.dtsi"
27 28
28/ { 29/ {
@@ -48,6 +49,14 @@
48 <0x00000001 0x00000000 0x00000001 0x00000000>; 49 <0x00000001 0x00000000 0x00000001 0x00000000>;
49 }; 50 };
50 51
52 cpus {
53 pm_pic {
54 ctrl-gpios = <&gpio0 16 GPIO_ACTIVE_LOW>,
55 <&gpio0 17 GPIO_ACTIVE_LOW>,
56 <&gpio0 18 GPIO_ACTIVE_LOW>;
57 };
58 };
59
51 soc { 60 soc {
52 ranges = <MBUS_ID(0xf0, 0x01) 0 0 0xf1000000 0x100000 61 ranges = <MBUS_ID(0xf0, 0x01) 0 0 0xf1000000 0x100000
53 MBUS_ID(0x01, 0x1d) 0 0 0xfff00000 0x100000 62 MBUS_ID(0x01, 0x1d) 0 0 0xfff00000 0x100000
@@ -115,7 +124,15 @@
115 serial@12300 { 124 serial@12300 {
116 status = "okay"; 125 status = "okay";
117 }; 126 };
118 127 pinctrl {
128 pinctrl-0 = <&pic_pins>;
129 pinctrl-names = "default";
130 pic_pins: pic-pins-0 {
131 marvell,pins = "mpp16", "mpp17",
132 "mpp18";
133 marvell,function = "gpio";
134 };
135 };
119 sata@a0000 { 136 sata@a0000 {
120 nr-ports = <2>; 137 nr-ports = <2>;
121 status = "okay"; 138 status = "okay";
diff --git a/arch/arm/boot/dts/armada-xp.dtsi b/arch/arm/boot/dts/armada-xp.dtsi
index bff9f6c18db1..2be244a96edf 100644
--- a/arch/arm/boot/dts/armada-xp.dtsi
+++ b/arch/arm/boot/dts/armada-xp.dtsi
@@ -35,6 +35,11 @@
35 }; 35 };
36 36
37 internal-regs { 37 internal-regs {
38 sdramc@1400 {
39 compatible = "marvell,armada-xp-sdram-controller";
40 reg = <0x1400 0x500>;
41 };
42
38 L2: l2-cache { 43 L2: l2-cache {
39 compatible = "marvell,aurora-system-cache"; 44 compatible = "marvell,aurora-system-cache";
40 reg = <0x08000 0x1000>; 45 reg = <0x08000 0x1000>;
diff --git a/arch/arm/mach-mvebu/Makefile b/arch/arm/mach-mvebu/Makefile
index e24136b42765..b4f01497ce0b 100644
--- a/arch/arm/mach-mvebu/Makefile
+++ b/arch/arm/mach-mvebu/Makefile
@@ -7,7 +7,7 @@ CFLAGS_pmsu.o := -march=armv7-a
7obj-$(CONFIG_MACH_MVEBU_ANY) += system-controller.o mvebu-soc-id.o 7obj-$(CONFIG_MACH_MVEBU_ANY) += system-controller.o mvebu-soc-id.o
8 8
9ifeq ($(CONFIG_MACH_MVEBU_V7),y) 9ifeq ($(CONFIG_MACH_MVEBU_V7),y)
10obj-y += cpu-reset.o board-v7.o coherency.o coherency_ll.o pmsu.o pmsu_ll.o 10obj-y += cpu-reset.o board-v7.o coherency.o coherency_ll.o pmsu.o pmsu_ll.o pm.o pm-board.o
11obj-$(CONFIG_SMP) += platsmp.o headsmp.o platsmp-a9.o headsmp-a9.o 11obj-$(CONFIG_SMP) += platsmp.o headsmp.o platsmp-a9.o headsmp-a9.o
12endif 12endif
13 13
diff --git a/arch/arm/mach-mvebu/board-v7.c b/arch/arm/mach-mvebu/board-v7.c
index e15ead876a48..89a139ed7d5b 100644
--- a/arch/arm/mach-mvebu/board-v7.c
+++ b/arch/arm/mach-mvebu/board-v7.c
@@ -16,10 +16,12 @@
16#include <linux/init.h> 16#include <linux/init.h>
17#include <linux/clk-provider.h> 17#include <linux/clk-provider.h>
18#include <linux/of_address.h> 18#include <linux/of_address.h>
19#include <linux/of_fdt.h>
19#include <linux/of_platform.h> 20#include <linux/of_platform.h>
20#include <linux/io.h> 21#include <linux/io.h>
21#include <linux/clocksource.h> 22#include <linux/clocksource.h>
22#include <linux/dma-mapping.h> 23#include <linux/dma-mapping.h>
24#include <linux/memblock.h>
23#include <linux/mbus.h> 25#include <linux/mbus.h>
24#include <linux/signal.h> 26#include <linux/signal.h>
25#include <linux/slab.h> 27#include <linux/slab.h>
@@ -57,6 +59,54 @@ void __iomem *mvebu_get_scu_base(void)
57} 59}
58 60
59/* 61/*
62 * When returning from suspend, the platform goes through the
63 * bootloader, which executes its DDR3 training code. This code has
64 * the unfortunate idea of using the first 10 KB of each DRAM bank to
65 * exercise the RAM and calculate the optimal timings. Therefore, this
66 * area of RAM is overwritten, and shouldn't be used by the kernel if
67 * suspend/resume is supported.
68 */
69
70#ifdef CONFIG_SUSPEND
71#define MVEBU_DDR_TRAINING_AREA_SZ (10 * SZ_1K)
72static int __init mvebu_scan_mem(unsigned long node, const char *uname,
73 int depth, void *data)
74{
75 const char *type = of_get_flat_dt_prop(node, "device_type", NULL);
76 const __be32 *reg, *endp;
77 int l;
78
79 if (type == NULL || strcmp(type, "memory"))
80 return 0;
81
82 reg = of_get_flat_dt_prop(node, "linux,usable-memory", &l);
83 if (reg == NULL)
84 reg = of_get_flat_dt_prop(node, "reg", &l);
85 if (reg == NULL)
86 return 0;
87
88 endp = reg + (l / sizeof(__be32));
89 while ((endp - reg) >= (dt_root_addr_cells + dt_root_size_cells)) {
90 u64 base, size;
91
92 base = dt_mem_next_cell(dt_root_addr_cells, &reg);
93 size = dt_mem_next_cell(dt_root_size_cells, &reg);
94
95 memblock_reserve(base, MVEBU_DDR_TRAINING_AREA_SZ);
96 }
97
98 return 0;
99}
100
101static void __init mvebu_memblock_reserve(void)
102{
103 of_scan_flat_dt(mvebu_scan_mem, NULL);
104}
105#else
106static void __init mvebu_memblock_reserve(void) {}
107#endif
108
109/*
60 * Early versions of Armada 375 SoC have a bug where the BootROM 110 * Early versions of Armada 375 SoC have a bug where the BootROM
61 * leaves an external data abort pending. The kernel is hit by this 111 * leaves an external data abort pending. The kernel is hit by this
62 * data abort as soon as it enters userspace, because it unmasks the 112 * data abort as soon as it enters userspace, because it unmasks the
@@ -151,6 +201,7 @@ DT_MACHINE_START(ARMADA_370_XP_DT, "Marvell Armada 370/XP (Device Tree)")
151 .init_machine = mvebu_dt_init, 201 .init_machine = mvebu_dt_init,
152 .init_irq = mvebu_init_irq, 202 .init_irq = mvebu_init_irq,
153 .restart = mvebu_restart, 203 .restart = mvebu_restart,
204 .reserve = mvebu_memblock_reserve,
154 .dt_compat = armada_370_xp_dt_compat, 205 .dt_compat = armada_370_xp_dt_compat,
155MACHINE_END 206MACHINE_END
156 207
diff --git a/arch/arm/mach-mvebu/common.h b/arch/arm/mach-mvebu/common.h
index 3ccb40c3bf94..3e0aca1f288a 100644
--- a/arch/arm/mach-mvebu/common.h
+++ b/arch/arm/mach-mvebu/common.h
@@ -25,4 +25,6 @@ int mvebu_system_controller_get_soc_id(u32 *dev, u32 *rev);
25 25
26void __iomem *mvebu_get_scu_base(void); 26void __iomem *mvebu_get_scu_base(void);
27 27
28int mvebu_pm_init(void (*board_pm_enter)(void __iomem *sdram_reg, u32 srcmd));
29
28#endif 30#endif
diff --git a/arch/arm/mach-mvebu/platsmp.c b/arch/arm/mach-mvebu/platsmp.c
index 622315c185b2..58cc8c1575eb 100644
--- a/arch/arm/mach-mvebu/platsmp.c
+++ b/arch/arm/mach-mvebu/platsmp.c
@@ -35,7 +35,7 @@
35#define AXP_BOOTROM_BASE 0xfff00000 35#define AXP_BOOTROM_BASE 0xfff00000
36#define AXP_BOOTROM_SIZE 0x100000 36#define AXP_BOOTROM_SIZE 0x100000
37 37
38static struct clk *__init get_cpu_clk(int cpu) 38static struct clk *get_cpu_clk(int cpu)
39{ 39{
40 struct clk *cpu_clk; 40 struct clk *cpu_clk;
41 struct device_node *np = of_get_cpu_node(cpu, NULL); 41 struct device_node *np = of_get_cpu_node(cpu, NULL);
@@ -48,29 +48,28 @@ static struct clk *__init get_cpu_clk(int cpu)
48 return cpu_clk; 48 return cpu_clk;
49} 49}
50 50
51static void __init set_secondary_cpus_clock(void) 51static void set_secondary_cpu_clock(unsigned int cpu)
52{ 52{
53 int thiscpu, cpu; 53 int thiscpu;
54 unsigned long rate; 54 unsigned long rate;
55 struct clk *cpu_clk; 55 struct clk *cpu_clk;
56 56
57 thiscpu = smp_processor_id(); 57 thiscpu = get_cpu();
58
58 cpu_clk = get_cpu_clk(thiscpu); 59 cpu_clk = get_cpu_clk(thiscpu);
59 if (!cpu_clk) 60 if (!cpu_clk)
60 return; 61 goto out;
61 clk_prepare_enable(cpu_clk); 62 clk_prepare_enable(cpu_clk);
62 rate = clk_get_rate(cpu_clk); 63 rate = clk_get_rate(cpu_clk);
63 64
64 /* set all the other CPU clk to the same rate than the boot CPU */ 65 cpu_clk = get_cpu_clk(cpu);
65 for_each_possible_cpu(cpu) { 66 if (!cpu_clk)
66 if (cpu == thiscpu) 67 goto out;
67 continue; 68 clk_set_rate(cpu_clk, rate);
68 cpu_clk = get_cpu_clk(cpu); 69 clk_prepare_enable(cpu_clk);
69 if (!cpu_clk) 70
70 return; 71out:
71 clk_set_rate(cpu_clk, rate); 72 put_cpu();
72 clk_prepare_enable(cpu_clk);
73 }
74} 73}
75 74
76static int armada_xp_boot_secondary(unsigned int cpu, struct task_struct *idle) 75static int armada_xp_boot_secondary(unsigned int cpu, struct task_struct *idle)
@@ -80,6 +79,7 @@ static int armada_xp_boot_secondary(unsigned int cpu, struct task_struct *idle)
80 pr_info("Booting CPU %d\n", cpu); 79 pr_info("Booting CPU %d\n", cpu);
81 80
82 hw_cpu = cpu_logical_map(cpu); 81 hw_cpu = cpu_logical_map(cpu);
82 set_secondary_cpu_clock(hw_cpu);
83 mvebu_pmsu_set_cpu_boot_addr(hw_cpu, armada_xp_secondary_startup); 83 mvebu_pmsu_set_cpu_boot_addr(hw_cpu, armada_xp_secondary_startup);
84 84
85 /* 85 /*
@@ -128,7 +128,6 @@ static void __init armada_xp_smp_prepare_cpus(unsigned int max_cpus)
128 struct resource res; 128 struct resource res;
129 int err; 129 int err;
130 130
131 set_secondary_cpus_clock();
132 flush_cache_all(); 131 flush_cache_all();
133 set_cpu_coherent(); 132 set_cpu_coherent();
134 133
diff --git a/arch/arm/mach-mvebu/pm-board.c b/arch/arm/mach-mvebu/pm-board.c
new file mode 100644
index 000000000000..6dfd4ab97b2a
--- /dev/null
+++ b/arch/arm/mach-mvebu/pm-board.c
@@ -0,0 +1,141 @@
1/*
2 * Board-level suspend/resume support.
3 *
4 * Copyright (C) 2014 Marvell
5 *
6 * Thomas Petazzoni <thomas.petazzoni@free-electrons.com>
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/delay.h>
14#include <linux/gpio.h>
15#include <linux/init.h>
16#include <linux/io.h>
17#include <linux/of.h>
18#include <linux/of_address.h>
19#include <linux/of_gpio.h>
20#include <linux/slab.h>
21#include "common.h"
22
23#define ARMADA_XP_GP_PIC_NR_GPIOS 3
24
25static void __iomem *gpio_ctrl;
26static int pic_gpios[ARMADA_XP_GP_PIC_NR_GPIOS];
27static int pic_raw_gpios[ARMADA_XP_GP_PIC_NR_GPIOS];
28
29static void mvebu_armada_xp_gp_pm_enter(void __iomem *sdram_reg, u32 srcmd)
30{
31 u32 reg, ackcmd;
32 int i;
33
34 /* Put 001 as value on the GPIOs */
35 reg = readl(gpio_ctrl);
36 for (i = 0; i < ARMADA_XP_GP_PIC_NR_GPIOS; i++)
37 reg &= ~BIT(pic_raw_gpios[i]);
38 reg |= BIT(pic_raw_gpios[0]);
39 writel(reg, gpio_ctrl);
40
41 /* Prepare writing 111 to the GPIOs */
42 ackcmd = readl(gpio_ctrl);
43 for (i = 0; i < ARMADA_XP_GP_PIC_NR_GPIOS; i++)
44 ackcmd |= BIT(pic_raw_gpios[i]);
45
46 /*
47 * Wait a while, the PIC needs quite a bit of time between the
48 * two GPIO commands.
49 */
50 mdelay(3000);
51
52 asm volatile (
53 /* Align to a cache line */
54 ".balign 32\n\t"
55
56 /* Enter self refresh */
57 "str %[srcmd], [%[sdram_reg]]\n\t"
58
59 /*
60 * Wait 100 cycles for DDR to enter self refresh, by
61 * doing 50 times two instructions.
62 */
63 "mov r1, #50\n\t"
64 "1: subs r1, r1, #1\n\t"
65 "bne 1b\n\t"
66
67 /* Issue the command ACK */
68 "str %[ackcmd], [%[gpio_ctrl]]\n\t"
69
70 /* Trap the processor */
71 "b .\n\t"
72 : : [srcmd] "r" (srcmd), [sdram_reg] "r" (sdram_reg),
73 [ackcmd] "r" (ackcmd), [gpio_ctrl] "r" (gpio_ctrl) : "r1");
74}
75
76static int mvebu_armada_xp_gp_pm_init(void)
77{
78 struct device_node *np;
79 struct device_node *gpio_ctrl_np;
80 int ret = 0, i;
81
82 if (!of_machine_is_compatible("marvell,axp-gp"))
83 return -ENODEV;
84
85 np = of_find_node_by_name(NULL, "pm_pic");
86 if (!np)
87 return -ENODEV;
88
89 for (i = 0; i < ARMADA_XP_GP_PIC_NR_GPIOS; i++) {
90 char *name;
91 struct of_phandle_args args;
92
93 pic_gpios[i] = of_get_named_gpio(np, "ctrl-gpios", i);
94 if (pic_gpios[i] < 0) {
95 ret = -ENODEV;
96 goto out;
97 }
98
99 name = kasprintf(GFP_KERNEL, "pic-pin%d", i);
100 if (!name) {
101 ret = -ENOMEM;
102 goto out;
103 }
104
105 ret = gpio_request(pic_gpios[i], name);
106 if (ret < 0) {
107 kfree(name);
108 goto out;
109 }
110
111 ret = gpio_direction_output(pic_gpios[i], 0);
112 if (ret < 0) {
113 gpio_free(pic_gpios[i]);
114 kfree(name);
115 goto out;
116 }
117
118 ret = of_parse_phandle_with_fixed_args(np, "ctrl-gpios", 2,
119 i, &args);
120 if (ret < 0) {
121 gpio_free(pic_gpios[i]);
122 kfree(name);
123 goto out;
124 }
125
126 gpio_ctrl_np = args.np;
127 pic_raw_gpios[i] = args.args[0];
128 }
129
130 gpio_ctrl = of_iomap(gpio_ctrl_np, 0);
131 if (!gpio_ctrl)
132 return -ENOMEM;
133
134 mvebu_pm_init(mvebu_armada_xp_gp_pm_enter);
135
136out:
137 of_node_put(np);
138 return ret;
139}
140
141late_initcall(mvebu_armada_xp_gp_pm_init);
diff --git a/arch/arm/mach-mvebu/pm.c b/arch/arm/mach-mvebu/pm.c
new file mode 100644
index 000000000000..6573a8f11f70
--- /dev/null
+++ b/arch/arm/mach-mvebu/pm.c
@@ -0,0 +1,218 @@
1/*
2 * Suspend/resume support. Currently supporting Armada XP only.
3 *
4 * Copyright (C) 2014 Marvell
5 *
6 * Thomas Petazzoni <thomas.petazzoni@free-electrons.com>
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/cpu_pm.h>
14#include <linux/delay.h>
15#include <linux/gpio.h>
16#include <linux/io.h>
17#include <linux/kernel.h>
18#include <linux/mbus.h>
19#include <linux/of_address.h>
20#include <linux/suspend.h>
21#include <asm/cacheflush.h>
22#include <asm/outercache.h>
23#include <asm/suspend.h>
24
25#include "coherency.h"
26#include "pmsu.h"
27
28#define SDRAM_CONFIG_OFFS 0x0
29#define SDRAM_CONFIG_SR_MODE_BIT BIT(24)
30#define SDRAM_OPERATION_OFFS 0x18
31#define SDRAM_OPERATION_SELF_REFRESH 0x7
32#define SDRAM_DLB_EVICTION_OFFS 0x30c
33#define SDRAM_DLB_EVICTION_THRESHOLD_MASK 0xff
34
35static void (*mvebu_board_pm_enter)(void __iomem *sdram_reg, u32 srcmd);
36static void __iomem *sdram_ctrl;
37
38static int mvebu_pm_powerdown(unsigned long data)
39{
40 u32 reg, srcmd;
41
42 flush_cache_all();
43 outer_flush_all();
44
45 /*
46 * Issue a Data Synchronization Barrier instruction to ensure
47 * that all state saving has been completed.
48 */
49 dsb();
50
51 /* Flush the DLB and wait ~7 usec */
52 reg = readl(sdram_ctrl + SDRAM_DLB_EVICTION_OFFS);
53 reg &= ~SDRAM_DLB_EVICTION_THRESHOLD_MASK;
54 writel(reg, sdram_ctrl + SDRAM_DLB_EVICTION_OFFS);
55
56 udelay(7);
57
58 /* Set DRAM in battery backup mode */
59 reg = readl(sdram_ctrl + SDRAM_CONFIG_OFFS);
60 reg &= ~SDRAM_CONFIG_SR_MODE_BIT;
61 writel(reg, sdram_ctrl + SDRAM_CONFIG_OFFS);
62
63 /* Prepare to go to self-refresh */
64
65 srcmd = readl(sdram_ctrl + SDRAM_OPERATION_OFFS);
66 srcmd &= ~0x1F;
67 srcmd |= SDRAM_OPERATION_SELF_REFRESH;
68
69 mvebu_board_pm_enter(sdram_ctrl + SDRAM_OPERATION_OFFS, srcmd);
70
71 return 0;
72}
73
74#define BOOT_INFO_ADDR 0x3000
75#define BOOT_MAGIC_WORD 0xdeadb002
76#define BOOT_MAGIC_LIST_END 0xffffffff
77
78/*
79 * Those registers are accessed before switching the internal register
80 * base, which is why we hardcode the 0xd0000000 base address, the one
81 * used by the SoC out of reset.
82 */
83#define MBUS_WINDOW_12_CTRL 0xd00200b0
84#define MBUS_INTERNAL_REG_ADDRESS 0xd0020080
85
86#define SDRAM_WIN_BASE_REG(x) (0x20180 + (0x8*x))
87#define SDRAM_WIN_CTRL_REG(x) (0x20184 + (0x8*x))
88
89static phys_addr_t mvebu_internal_reg_base(void)
90{
91 struct device_node *np;
92 __be32 in_addr[2];
93
94 np = of_find_node_by_name(NULL, "internal-regs");
95 BUG_ON(!np);
96
97 /*
98 * Ask the DT what is the internal register address on this
99 * platform. In the mvebu-mbus DT binding, 0xf0010000
100 * corresponds to the internal register window.
101 */
102 in_addr[0] = cpu_to_be32(0xf0010000);
103 in_addr[1] = 0x0;
104
105 return of_translate_address(np, in_addr);
106}
107
108static void mvebu_pm_store_bootinfo(void)
109{
110 u32 *store_addr;
111 phys_addr_t resume_pc;
112
113 store_addr = phys_to_virt(BOOT_INFO_ADDR);
114 resume_pc = virt_to_phys(armada_370_xp_cpu_resume);
115
116 /*
117 * The bootloader expects the first two words to be a magic
118 * value (BOOT_MAGIC_WORD), followed by the address of the
119 * resume code to jump to. Then, it expects a sequence of
120 * (address, value) pairs, which can be used to restore the
121 * value of certain registers. This sequence must end with the
122 * BOOT_MAGIC_LIST_END magic value.
123 */
124
125 writel(BOOT_MAGIC_WORD, store_addr++);
126 writel(resume_pc, store_addr++);
127
128 /*
129 * Some platforms remap their internal register base address
130 * to 0xf1000000. However, out of reset, window 12 starts at
131 * 0xf0000000 and ends at 0xf7ffffff, which would overlap with
132 * the internal registers. Therefore, disable window 12.
133 */
134 writel(MBUS_WINDOW_12_CTRL, store_addr++);
135 writel(0x0, store_addr++);
136
137 /*
138 * Set the internal register base address to the value
139 * expected by Linux, as read from the Device Tree.
140 */
141 writel(MBUS_INTERNAL_REG_ADDRESS, store_addr++);
142 writel(mvebu_internal_reg_base(), store_addr++);
143
144 /*
145 * Ask the mvebu-mbus driver to store the SDRAM window
146 * configuration, which has to be restored by the bootloader
147 * before re-entering the kernel on resume.
148 */
149 store_addr += mvebu_mbus_save_cpu_target(store_addr);
150
151 writel(BOOT_MAGIC_LIST_END, store_addr);
152}
153
154static int mvebu_pm_enter(suspend_state_t state)
155{
156 if (state != PM_SUSPEND_MEM)
157 return -EINVAL;
158
159 cpu_pm_enter();
160
161 mvebu_pm_store_bootinfo();
162 cpu_suspend(0, mvebu_pm_powerdown);
163
164 outer_resume();
165
166 mvebu_v7_pmsu_idle_exit();
167
168 set_cpu_coherent();
169
170 cpu_pm_exit();
171
172 return 0;
173}
174
175static const struct platform_suspend_ops mvebu_pm_ops = {
176 .enter = mvebu_pm_enter,
177 .valid = suspend_valid_only_mem,
178};
179
180int mvebu_pm_init(void (*board_pm_enter)(void __iomem *sdram_reg, u32 srcmd))
181{
182 struct device_node *np;
183 struct resource res;
184
185 if (!of_machine_is_compatible("marvell,armadaxp"))
186 return -ENODEV;
187
188 np = of_find_compatible_node(NULL, NULL,
189 "marvell,armada-xp-sdram-controller");
190 if (!np)
191 return -ENODEV;
192
193 if (of_address_to_resource(np, 0, &res)) {
194 of_node_put(np);
195 return -ENODEV;
196 }
197
198 if (!request_mem_region(res.start, resource_size(&res),
199 np->full_name)) {
200 of_node_put(np);
201 return -EBUSY;
202 }
203
204 sdram_ctrl = ioremap(res.start, resource_size(&res));
205 if (!sdram_ctrl) {
206 release_mem_region(res.start, resource_size(&res));
207 of_node_put(np);
208 return -ENOMEM;
209 }
210
211 of_node_put(np);
212
213 mvebu_board_pm_enter = board_pm_enter;
214
215 suspend_set_ops(&mvebu_pm_ops);
216
217 return 0;
218}
diff --git a/arch/arm/mach-mvebu/pmsu.h b/arch/arm/mach-mvebu/pmsu.h
index c2c95db4f648..ea79269c2702 100644
--- a/arch/arm/mach-mvebu/pmsu.h
+++ b/arch/arm/mach-mvebu/pmsu.h
@@ -17,6 +17,7 @@ int mvebu_setup_boot_addr_wa(unsigned int crypto_eng_target,
17 phys_addr_t resume_addr_reg); 17 phys_addr_t resume_addr_reg);
18 18
19void mvebu_v7_pmsu_idle_exit(void); 19void mvebu_v7_pmsu_idle_exit(void);
20void armada_370_xp_cpu_resume(void);
20 21
21int armada_370_xp_pmsu_idle_enter(unsigned long deepidle); 22int armada_370_xp_pmsu_idle_enter(unsigned long deepidle);
22int armada_38x_do_cpu_suspend(unsigned long deepidle); 23int armada_38x_do_cpu_suspend(unsigned long deepidle);
diff --git a/arch/arm/mach-mvebu/pmsu_ll.S b/arch/arm/mach-mvebu/pmsu_ll.S
index 83d014698314..88651221dbdd 100644
--- a/arch/arm/mach-mvebu/pmsu_ll.S
+++ b/arch/arm/mach-mvebu/pmsu_ll.S
@@ -30,6 +30,14 @@ ENDPROC(armada_38x_scu_power_up)
30 */ 30 */
31ENTRY(armada_370_xp_cpu_resume) 31ENTRY(armada_370_xp_cpu_resume)
32ARM_BE8(setend be ) @ go BE8 if entered LE 32ARM_BE8(setend be ) @ go BE8 if entered LE
33 /*
34 * Disable the MMU that might have been enabled in BootROM if
35 * this code is used in the resume path of a suspend/resume
36 * cycle.
37 */
38 mrc p15, 0, r1, c1, c0, 0
39 bic r1, #1
40 mcr p15, 0, r1, c1, c0, 0
33 bl ll_add_cpu_to_smp_group 41 bl ll_add_cpu_to_smp_group
34 bl ll_enable_coherency 42 bl ll_enable_coherency
35 b cpu_resume 43 b cpu_resume
diff --git a/drivers/bus/mvebu-mbus.c b/drivers/bus/mvebu-mbus.c
index 26c3779d871d..eb7682dc123b 100644
--- a/drivers/bus/mvebu-mbus.c
+++ b/drivers/bus/mvebu-mbus.c
@@ -57,6 +57,7 @@
57#include <linux/of_address.h> 57#include <linux/of_address.h>
58#include <linux/debugfs.h> 58#include <linux/debugfs.h>
59#include <linux/log2.h> 59#include <linux/log2.h>
60#include <linux/syscore_ops.h>
60 61
61/* 62/*
62 * DDR target is the same on all platforms. 63 * DDR target is the same on all platforms.
@@ -94,20 +95,42 @@
94 95
95#define DOVE_DDR_BASE_CS_OFF(n) ((n) << 4) 96#define DOVE_DDR_BASE_CS_OFF(n) ((n) << 4)
96 97
98/* Relative to mbusbridge_base */
99#define MBUS_BRIDGE_CTRL_OFF 0x0
100#define MBUS_BRIDGE_BASE_OFF 0x4
101
102/* Maximum number of windows, for all known platforms */
103#define MBUS_WINS_MAX 20
104
97struct mvebu_mbus_state; 105struct mvebu_mbus_state;
98 106
99struct mvebu_mbus_soc_data { 107struct mvebu_mbus_soc_data {
100 unsigned int num_wins; 108 unsigned int num_wins;
101 unsigned int num_remappable_wins; 109 unsigned int num_remappable_wins;
110 bool has_mbus_bridge;
102 unsigned int (*win_cfg_offset)(const int win); 111 unsigned int (*win_cfg_offset)(const int win);
103 void (*setup_cpu_target)(struct mvebu_mbus_state *s); 112 void (*setup_cpu_target)(struct mvebu_mbus_state *s);
113 int (*save_cpu_target)(struct mvebu_mbus_state *s,
114 u32 *store_addr);
104 int (*show_cpu_target)(struct mvebu_mbus_state *s, 115 int (*show_cpu_target)(struct mvebu_mbus_state *s,
105 struct seq_file *seq, void *v); 116 struct seq_file *seq, void *v);
106}; 117};
107 118
119/*
120 * Used to store the state of one MBus window accross suspend/resume.
121 */
122struct mvebu_mbus_win_data {
123 u32 ctrl;
124 u32 base;
125 u32 remap_lo;
126 u32 remap_hi;
127};
128
108struct mvebu_mbus_state { 129struct mvebu_mbus_state {
109 void __iomem *mbuswins_base; 130 void __iomem *mbuswins_base;
110 void __iomem *sdramwins_base; 131 void __iomem *sdramwins_base;
132 void __iomem *mbusbridge_base;
133 phys_addr_t sdramwins_phys_base;
111 struct dentry *debugfs_root; 134 struct dentry *debugfs_root;
112 struct dentry *debugfs_sdram; 135 struct dentry *debugfs_sdram;
113 struct dentry *debugfs_devs; 136 struct dentry *debugfs_devs;
@@ -115,6 +138,11 @@ struct mvebu_mbus_state {
115 struct resource pcie_io_aperture; 138 struct resource pcie_io_aperture;
116 const struct mvebu_mbus_soc_data *soc; 139 const struct mvebu_mbus_soc_data *soc;
117 int hw_io_coherency; 140 int hw_io_coherency;
141
142 /* Used during suspend/resume */
143 u32 mbus_bridge_ctrl;
144 u32 mbus_bridge_base;
145 struct mvebu_mbus_win_data wins[MBUS_WINS_MAX];
118}; 146};
119 147
120static struct mvebu_mbus_state mbus_state; 148static struct mvebu_mbus_state mbus_state;
@@ -516,6 +544,28 @@ mvebu_mbus_default_setup_cpu_target(struct mvebu_mbus_state *mbus)
516 mvebu_mbus_dram_info.num_cs = cs; 544 mvebu_mbus_dram_info.num_cs = cs;
517} 545}
518 546
547static int
548mvebu_mbus_default_save_cpu_target(struct mvebu_mbus_state *mbus,
549 u32 *store_addr)
550{
551 int i;
552
553 for (i = 0; i < 4; i++) {
554 u32 base = readl(mbus->sdramwins_base + DDR_BASE_CS_OFF(i));
555 u32 size = readl(mbus->sdramwins_base + DDR_SIZE_CS_OFF(i));
556
557 writel(mbus->sdramwins_phys_base + DDR_BASE_CS_OFF(i),
558 store_addr++);
559 writel(base, store_addr++);
560 writel(mbus->sdramwins_phys_base + DDR_SIZE_CS_OFF(i),
561 store_addr++);
562 writel(size, store_addr++);
563 }
564
565 /* We've written 16 words to the store address */
566 return 16;
567}
568
519static void __init 569static void __init
520mvebu_mbus_dove_setup_cpu_target(struct mvebu_mbus_state *mbus) 570mvebu_mbus_dove_setup_cpu_target(struct mvebu_mbus_state *mbus)
521{ 571{
@@ -546,10 +596,35 @@ mvebu_mbus_dove_setup_cpu_target(struct mvebu_mbus_state *mbus)
546 mvebu_mbus_dram_info.num_cs = cs; 596 mvebu_mbus_dram_info.num_cs = cs;
547} 597}
548 598
599static int
600mvebu_mbus_dove_save_cpu_target(struct mvebu_mbus_state *mbus,
601 u32 *store_addr)
602{
603 int i;
604
605 for (i = 0; i < 2; i++) {
606 u32 map = readl(mbus->sdramwins_base + DOVE_DDR_BASE_CS_OFF(i));
607
608 writel(mbus->sdramwins_phys_base + DOVE_DDR_BASE_CS_OFF(i),
609 store_addr++);
610 writel(map, store_addr++);
611 }
612
613 /* We've written 4 words to the store address */
614 return 4;
615}
616
617int mvebu_mbus_save_cpu_target(u32 *store_addr)
618{
619 return mbus_state.soc->save_cpu_target(&mbus_state, store_addr);
620}
621
549static const struct mvebu_mbus_soc_data armada_370_xp_mbus_data = { 622static const struct mvebu_mbus_soc_data armada_370_xp_mbus_data = {
550 .num_wins = 20, 623 .num_wins = 20,
551 .num_remappable_wins = 8, 624 .num_remappable_wins = 8,
625 .has_mbus_bridge = true,
552 .win_cfg_offset = armada_370_xp_mbus_win_offset, 626 .win_cfg_offset = armada_370_xp_mbus_win_offset,
627 .save_cpu_target = mvebu_mbus_default_save_cpu_target,
553 .setup_cpu_target = mvebu_mbus_default_setup_cpu_target, 628 .setup_cpu_target = mvebu_mbus_default_setup_cpu_target,
554 .show_cpu_target = mvebu_sdram_debug_show_orion, 629 .show_cpu_target = mvebu_sdram_debug_show_orion,
555}; 630};
@@ -558,6 +633,7 @@ static const struct mvebu_mbus_soc_data kirkwood_mbus_data = {
558 .num_wins = 8, 633 .num_wins = 8,
559 .num_remappable_wins = 4, 634 .num_remappable_wins = 4,
560 .win_cfg_offset = orion_mbus_win_offset, 635 .win_cfg_offset = orion_mbus_win_offset,
636 .save_cpu_target = mvebu_mbus_default_save_cpu_target,
561 .setup_cpu_target = mvebu_mbus_default_setup_cpu_target, 637 .setup_cpu_target = mvebu_mbus_default_setup_cpu_target,
562 .show_cpu_target = mvebu_sdram_debug_show_orion, 638 .show_cpu_target = mvebu_sdram_debug_show_orion,
563}; 639};
@@ -566,6 +642,7 @@ static const struct mvebu_mbus_soc_data dove_mbus_data = {
566 .num_wins = 8, 642 .num_wins = 8,
567 .num_remappable_wins = 4, 643 .num_remappable_wins = 4,
568 .win_cfg_offset = orion_mbus_win_offset, 644 .win_cfg_offset = orion_mbus_win_offset,
645 .save_cpu_target = mvebu_mbus_dove_save_cpu_target,
569 .setup_cpu_target = mvebu_mbus_dove_setup_cpu_target, 646 .setup_cpu_target = mvebu_mbus_dove_setup_cpu_target,
570 .show_cpu_target = mvebu_sdram_debug_show_dove, 647 .show_cpu_target = mvebu_sdram_debug_show_dove,
571}; 648};
@@ -578,6 +655,7 @@ static const struct mvebu_mbus_soc_data orion5x_4win_mbus_data = {
578 .num_wins = 8, 655 .num_wins = 8,
579 .num_remappable_wins = 4, 656 .num_remappable_wins = 4,
580 .win_cfg_offset = orion_mbus_win_offset, 657 .win_cfg_offset = orion_mbus_win_offset,
658 .save_cpu_target = mvebu_mbus_default_save_cpu_target,
581 .setup_cpu_target = mvebu_mbus_default_setup_cpu_target, 659 .setup_cpu_target = mvebu_mbus_default_setup_cpu_target,
582 .show_cpu_target = mvebu_sdram_debug_show_orion, 660 .show_cpu_target = mvebu_sdram_debug_show_orion,
583}; 661};
@@ -586,6 +664,7 @@ static const struct mvebu_mbus_soc_data orion5x_2win_mbus_data = {
586 .num_wins = 8, 664 .num_wins = 8,
587 .num_remappable_wins = 2, 665 .num_remappable_wins = 2,
588 .win_cfg_offset = orion_mbus_win_offset, 666 .win_cfg_offset = orion_mbus_win_offset,
667 .save_cpu_target = mvebu_mbus_default_save_cpu_target,
589 .setup_cpu_target = mvebu_mbus_default_setup_cpu_target, 668 .setup_cpu_target = mvebu_mbus_default_setup_cpu_target,
590 .show_cpu_target = mvebu_sdram_debug_show_orion, 669 .show_cpu_target = mvebu_sdram_debug_show_orion,
591}; 670};
@@ -594,6 +673,7 @@ static const struct mvebu_mbus_soc_data mv78xx0_mbus_data = {
594 .num_wins = 14, 673 .num_wins = 14,
595 .num_remappable_wins = 8, 674 .num_remappable_wins = 8,
596 .win_cfg_offset = mv78xx0_mbus_win_offset, 675 .win_cfg_offset = mv78xx0_mbus_win_offset,
676 .save_cpu_target = mvebu_mbus_default_save_cpu_target,
597 .setup_cpu_target = mvebu_mbus_default_setup_cpu_target, 677 .setup_cpu_target = mvebu_mbus_default_setup_cpu_target,
598 .show_cpu_target = mvebu_sdram_debug_show_orion, 678 .show_cpu_target = mvebu_sdram_debug_show_orion,
599}; 679};
@@ -698,11 +778,73 @@ static __init int mvebu_mbus_debugfs_init(void)
698} 778}
699fs_initcall(mvebu_mbus_debugfs_init); 779fs_initcall(mvebu_mbus_debugfs_init);
700 780
781static int mvebu_mbus_suspend(void)
782{
783 struct mvebu_mbus_state *s = &mbus_state;
784 int win;
785
786 if (!s->mbusbridge_base)
787 return -ENODEV;
788
789 for (win = 0; win < s->soc->num_wins; win++) {
790 void __iomem *addr = s->mbuswins_base +
791 s->soc->win_cfg_offset(win);
792
793 s->wins[win].base = readl(addr + WIN_BASE_OFF);
794 s->wins[win].ctrl = readl(addr + WIN_CTRL_OFF);
795
796 if (win >= s->soc->num_remappable_wins)
797 continue;
798
799 s->wins[win].remap_lo = readl(addr + WIN_REMAP_LO_OFF);
800 s->wins[win].remap_hi = readl(addr + WIN_REMAP_HI_OFF);
801 }
802
803 s->mbus_bridge_ctrl = readl(s->mbusbridge_base +
804 MBUS_BRIDGE_CTRL_OFF);
805 s->mbus_bridge_base = readl(s->mbusbridge_base +
806 MBUS_BRIDGE_BASE_OFF);
807
808 return 0;
809}
810
811static void mvebu_mbus_resume(void)
812{
813 struct mvebu_mbus_state *s = &mbus_state;
814 int win;
815
816 writel(s->mbus_bridge_ctrl,
817 s->mbusbridge_base + MBUS_BRIDGE_CTRL_OFF);
818 writel(s->mbus_bridge_base,
819 s->mbusbridge_base + MBUS_BRIDGE_BASE_OFF);
820
821 for (win = 0; win < s->soc->num_wins; win++) {
822 void __iomem *addr = s->mbuswins_base +
823 s->soc->win_cfg_offset(win);
824
825 writel(s->wins[win].base, addr + WIN_BASE_OFF);
826 writel(s->wins[win].ctrl, addr + WIN_CTRL_OFF);
827
828 if (win >= s->soc->num_remappable_wins)
829 continue;
830
831 writel(s->wins[win].remap_lo, addr + WIN_REMAP_LO_OFF);
832 writel(s->wins[win].remap_hi, addr + WIN_REMAP_HI_OFF);
833 }
834}
835
836struct syscore_ops mvebu_mbus_syscore_ops = {
837 .suspend = mvebu_mbus_suspend,
838 .resume = mvebu_mbus_resume,
839};
840
701static int __init mvebu_mbus_common_init(struct mvebu_mbus_state *mbus, 841static int __init mvebu_mbus_common_init(struct mvebu_mbus_state *mbus,
702 phys_addr_t mbuswins_phys_base, 842 phys_addr_t mbuswins_phys_base,
703 size_t mbuswins_size, 843 size_t mbuswins_size,
704 phys_addr_t sdramwins_phys_base, 844 phys_addr_t sdramwins_phys_base,
705 size_t sdramwins_size) 845 size_t sdramwins_size,
846 phys_addr_t mbusbridge_phys_base,
847 size_t mbusbridge_size)
706{ 848{
707 int win; 849 int win;
708 850
@@ -716,11 +858,26 @@ static int __init mvebu_mbus_common_init(struct mvebu_mbus_state *mbus,
716 return -ENOMEM; 858 return -ENOMEM;
717 } 859 }
718 860
861 mbus->sdramwins_phys_base = sdramwins_phys_base;
862
863 if (mbusbridge_phys_base) {
864 mbus->mbusbridge_base = ioremap(mbusbridge_phys_base,
865 mbusbridge_size);
866 if (!mbus->mbusbridge_base) {
867 iounmap(mbus->sdramwins_base);
868 iounmap(mbus->mbuswins_base);
869 return -ENOMEM;
870 }
871 } else
872 mbus->mbusbridge_base = NULL;
873
719 for (win = 0; win < mbus->soc->num_wins; win++) 874 for (win = 0; win < mbus->soc->num_wins; win++)
720 mvebu_mbus_disable_window(mbus, win); 875 mvebu_mbus_disable_window(mbus, win);
721 876
722 mbus->soc->setup_cpu_target(mbus); 877 mbus->soc->setup_cpu_target(mbus);
723 878
879 register_syscore_ops(&mvebu_mbus_syscore_ops);
880
724 return 0; 881 return 0;
725} 882}
726 883
@@ -746,7 +903,7 @@ int __init mvebu_mbus_init(const char *soc, phys_addr_t mbuswins_phys_base,
746 mbuswins_phys_base, 903 mbuswins_phys_base,
747 mbuswins_size, 904 mbuswins_size,
748 sdramwins_phys_base, 905 sdramwins_phys_base,
749 sdramwins_size); 906 sdramwins_size, 0, 0);
750} 907}
751 908
752#ifdef CONFIG_OF 909#ifdef CONFIG_OF
@@ -887,7 +1044,7 @@ static void __init mvebu_mbus_get_pcie_resources(struct device_node *np,
887 1044
888int __init mvebu_mbus_dt_init(bool is_coherent) 1045int __init mvebu_mbus_dt_init(bool is_coherent)
889{ 1046{
890 struct resource mbuswins_res, sdramwins_res; 1047 struct resource mbuswins_res, sdramwins_res, mbusbridge_res;
891 struct device_node *np, *controller; 1048 struct device_node *np, *controller;
892 const struct of_device_id *of_id; 1049 const struct of_device_id *of_id;
893 const __be32 *prop; 1050 const __be32 *prop;
@@ -923,6 +1080,19 @@ int __init mvebu_mbus_dt_init(bool is_coherent)
923 return -EINVAL; 1080 return -EINVAL;
924 } 1081 }
925 1082
1083 /*
1084 * Set the resource to 0 so that it can be left unmapped by
1085 * mvebu_mbus_common_init() if the DT doesn't carry the
1086 * necessary information. This is needed to preserve backward
1087 * compatibility.
1088 */
1089 memset(&mbusbridge_res, 0, sizeof(mbusbridge_res));
1090
1091 if (mbus_state.soc->has_mbus_bridge) {
1092 if (of_address_to_resource(controller, 2, &mbusbridge_res))
1093 pr_warn(FW_WARN "deprecated mbus-mvebu Device Tree, suspend/resume will not work\n");
1094 }
1095
926 mbus_state.hw_io_coherency = is_coherent; 1096 mbus_state.hw_io_coherency = is_coherent;
927 1097
928 /* Get optional pcie-{mem,io}-aperture properties */ 1098 /* Get optional pcie-{mem,io}-aperture properties */
@@ -933,7 +1103,9 @@ int __init mvebu_mbus_dt_init(bool is_coherent)
933 mbuswins_res.start, 1103 mbuswins_res.start,
934 resource_size(&mbuswins_res), 1104 resource_size(&mbuswins_res),
935 sdramwins_res.start, 1105 sdramwins_res.start,
936 resource_size(&sdramwins_res)); 1106 resource_size(&sdramwins_res),
1107 mbusbridge_res.start,
1108 resource_size(&mbusbridge_res));
937 if (ret) 1109 if (ret)
938 return ret; 1110 return ret;
939 1111
diff --git a/drivers/clk/mvebu/common.c b/drivers/clk/mvebu/common.c
index b7fcb469c87a..0d4d1216f2dd 100644
--- a/drivers/clk/mvebu/common.c
+++ b/drivers/clk/mvebu/common.c
@@ -19,6 +19,7 @@
19#include <linux/io.h> 19#include <linux/io.h>
20#include <linux/of.h> 20#include <linux/of.h>
21#include <linux/of_address.h> 21#include <linux/of_address.h>
22#include <linux/syscore_ops.h>
22 23
23#include "common.h" 24#include "common.h"
24 25
@@ -177,14 +178,17 @@ struct clk_gating_ctrl {
177 spinlock_t *lock; 178 spinlock_t *lock;
178 struct clk **gates; 179 struct clk **gates;
179 int num_gates; 180 int num_gates;
181 void __iomem *base;
182 u32 saved_reg;
180}; 183};
181 184
182#define to_clk_gate(_hw) container_of(_hw, struct clk_gate, hw) 185#define to_clk_gate(_hw) container_of(_hw, struct clk_gate, hw)
183 186
187static struct clk_gating_ctrl *ctrl;
188
184static struct clk *clk_gating_get_src( 189static struct clk *clk_gating_get_src(
185 struct of_phandle_args *clkspec, void *data) 190 struct of_phandle_args *clkspec, void *data)
186{ 191{
187 struct clk_gating_ctrl *ctrl = (struct clk_gating_ctrl *)data;
188 int n; 192 int n;
189 193
190 if (clkspec->args_count < 1) 194 if (clkspec->args_count < 1)
@@ -199,15 +203,35 @@ static struct clk *clk_gating_get_src(
199 return ERR_PTR(-ENODEV); 203 return ERR_PTR(-ENODEV);
200} 204}
201 205
206static int mvebu_clk_gating_suspend(void)
207{
208 ctrl->saved_reg = readl(ctrl->base);
209 return 0;
210}
211
212static void mvebu_clk_gating_resume(void)
213{
214 writel(ctrl->saved_reg, ctrl->base);
215}
216
217static struct syscore_ops clk_gate_syscore_ops = {
218 .suspend = mvebu_clk_gating_suspend,
219 .resume = mvebu_clk_gating_resume,
220};
221
202void __init mvebu_clk_gating_setup(struct device_node *np, 222void __init mvebu_clk_gating_setup(struct device_node *np,
203 const struct clk_gating_soc_desc *desc) 223 const struct clk_gating_soc_desc *desc)
204{ 224{
205 struct clk_gating_ctrl *ctrl;
206 struct clk *clk; 225 struct clk *clk;
207 void __iomem *base; 226 void __iomem *base;
208 const char *default_parent = NULL; 227 const char *default_parent = NULL;
209 int n; 228 int n;
210 229
230 if (ctrl) {
231 pr_err("mvebu-clk-gating: cannot instantiate more than one gatable clock device\n");
232 return;
233 }
234
211 base = of_iomap(np, 0); 235 base = of_iomap(np, 0);
212 if (WARN_ON(!base)) 236 if (WARN_ON(!base))
213 return; 237 return;
@@ -225,6 +249,8 @@ void __init mvebu_clk_gating_setup(struct device_node *np,
225 /* lock must already be initialized */ 249 /* lock must already be initialized */
226 ctrl->lock = &ctrl_gating_lock; 250 ctrl->lock = &ctrl_gating_lock;
227 251
252 ctrl->base = base;
253
228 /* Count, allocate, and register clock gates */ 254 /* Count, allocate, and register clock gates */
229 for (n = 0; desc[n].name;) 255 for (n = 0; desc[n].name;)
230 n++; 256 n++;
@@ -246,6 +272,8 @@ void __init mvebu_clk_gating_setup(struct device_node *np,
246 272
247 of_clk_add_provider(np, clk_gating_get_src, ctrl); 273 of_clk_add_provider(np, clk_gating_get_src, ctrl);
248 274
275 register_syscore_ops(&clk_gate_syscore_ops);
276
249 return; 277 return;
250gates_out: 278gates_out:
251 kfree(ctrl); 279 kfree(ctrl);
diff --git a/drivers/clocksource/time-armada-370-xp.c b/drivers/clocksource/time-armada-370-xp.c
index 0451e62fac7a..ff37d3abb806 100644
--- a/drivers/clocksource/time-armada-370-xp.c
+++ b/drivers/clocksource/time-armada-370-xp.c
@@ -43,6 +43,7 @@
43#include <linux/module.h> 43#include <linux/module.h>
44#include <linux/sched_clock.h> 44#include <linux/sched_clock.h>
45#include <linux/percpu.h> 45#include <linux/percpu.h>
46#include <linux/syscore_ops.h>
46 47
47/* 48/*
48 * Timer block registers. 49 * Timer block registers.
@@ -223,6 +224,28 @@ static struct notifier_block armada_370_xp_timer_cpu_nb = {
223 .notifier_call = armada_370_xp_timer_cpu_notify, 224 .notifier_call = armada_370_xp_timer_cpu_notify,
224}; 225};
225 226
227static u32 timer0_ctrl_reg, timer0_local_ctrl_reg;
228
229static int armada_370_xp_timer_suspend(void)
230{
231 timer0_ctrl_reg = readl(timer_base + TIMER_CTRL_OFF);
232 timer0_local_ctrl_reg = readl(local_base + TIMER_CTRL_OFF);
233 return 0;
234}
235
236static void armada_370_xp_timer_resume(void)
237{
238 writel(0xffffffff, timer_base + TIMER0_VAL_OFF);
239 writel(0xffffffff, timer_base + TIMER0_RELOAD_OFF);
240 writel(timer0_ctrl_reg, timer_base + TIMER_CTRL_OFF);
241 writel(timer0_local_ctrl_reg, local_base + TIMER_CTRL_OFF);
242}
243
244struct syscore_ops armada_370_xp_timer_syscore_ops = {
245 .suspend = armada_370_xp_timer_suspend,
246 .resume = armada_370_xp_timer_resume,
247};
248
226static void __init armada_370_xp_timer_common_init(struct device_node *np) 249static void __init armada_370_xp_timer_common_init(struct device_node *np)
227{ 250{
228 u32 clr = 0, set = 0; 251 u32 clr = 0, set = 0;
@@ -285,6 +308,8 @@ static void __init armada_370_xp_timer_common_init(struct device_node *np)
285 /* Immediately configure the timer on the boot CPU */ 308 /* Immediately configure the timer on the boot CPU */
286 if (!res) 309 if (!res)
287 armada_370_xp_timer_setup(this_cpu_ptr(armada_370_xp_evt)); 310 armada_370_xp_timer_setup(this_cpu_ptr(armada_370_xp_evt));
311
312 register_syscore_ops(&armada_370_xp_timer_syscore_ops);
288} 313}
289 314
290static void __init armada_xp_timer_init(struct device_node *np) 315static void __init armada_xp_timer_init(struct device_node *np)
diff --git a/drivers/irqchip/irq-armada-370-xp.c b/drivers/irqchip/irq-armada-370-xp.c
index 3e238cd049e6..4ec137bba7f6 100644
--- a/drivers/irqchip/irq-armada-370-xp.c
+++ b/drivers/irqchip/irq-armada-370-xp.c
@@ -26,6 +26,7 @@
26#include <linux/of_pci.h> 26#include <linux/of_pci.h>
27#include <linux/irqdomain.h> 27#include <linux/irqdomain.h>
28#include <linux/slab.h> 28#include <linux/slab.h>
29#include <linux/syscore_ops.h>
29#include <linux/msi.h> 30#include <linux/msi.h>
30#include <asm/mach/arch.h> 31#include <asm/mach/arch.h>
31#include <asm/exception.h> 32#include <asm/exception.h>
@@ -66,6 +67,7 @@
66static void __iomem *per_cpu_int_base; 67static void __iomem *per_cpu_int_base;
67static void __iomem *main_int_base; 68static void __iomem *main_int_base;
68static struct irq_domain *armada_370_xp_mpic_domain; 69static struct irq_domain *armada_370_xp_mpic_domain;
70static u32 doorbell_mask_reg;
69#ifdef CONFIG_PCI_MSI 71#ifdef CONFIG_PCI_MSI
70static struct irq_domain *armada_370_xp_msi_domain; 72static struct irq_domain *armada_370_xp_msi_domain;
71static DECLARE_BITMAP(msi_used, PCI_MSI_DOORBELL_NR); 73static DECLARE_BITMAP(msi_used, PCI_MSI_DOORBELL_NR);
@@ -474,6 +476,54 @@ armada_370_xp_handle_irq(struct pt_regs *regs)
474 } while (1); 476 } while (1);
475} 477}
476 478
479static int armada_370_xp_mpic_suspend(void)
480{
481 doorbell_mask_reg = readl(per_cpu_int_base +
482 ARMADA_370_XP_IN_DRBEL_MSK_OFFS);
483 return 0;
484}
485
486static void armada_370_xp_mpic_resume(void)
487{
488 int nirqs;
489 irq_hw_number_t irq;
490
491 /* Re-enable interrupts */
492 nirqs = (readl(main_int_base + ARMADA_370_XP_INT_CONTROL) >> 2) & 0x3ff;
493 for (irq = 0; irq < nirqs; irq++) {
494 struct irq_data *data;
495 int virq;
496
497 virq = irq_linear_revmap(armada_370_xp_mpic_domain, irq);
498 if (virq == 0)
499 continue;
500
501 if (irq != ARMADA_370_XP_TIMER0_PER_CPU_IRQ)
502 writel(irq, per_cpu_int_base +
503 ARMADA_370_XP_INT_CLEAR_MASK_OFFS);
504 else
505 writel(irq, main_int_base +
506 ARMADA_370_XP_INT_SET_ENABLE_OFFS);
507
508 data = irq_get_irq_data(virq);
509 if (!irqd_irq_disabled(data))
510 armada_370_xp_irq_unmask(data);
511 }
512
513 /* Reconfigure doorbells for IPIs and MSIs */
514 writel(doorbell_mask_reg,
515 per_cpu_int_base + ARMADA_370_XP_IN_DRBEL_MSK_OFFS);
516 if (doorbell_mask_reg & IPI_DOORBELL_MASK)
517 writel(0, per_cpu_int_base + ARMADA_370_XP_INT_CLEAR_MASK_OFFS);
518 if (doorbell_mask_reg & PCI_MSI_DOORBELL_MASK)
519 writel(1, per_cpu_int_base + ARMADA_370_XP_INT_CLEAR_MASK_OFFS);
520}
521
522struct syscore_ops armada_370_xp_mpic_syscore_ops = {
523 .suspend = armada_370_xp_mpic_suspend,
524 .resume = armada_370_xp_mpic_resume,
525};
526
477static int __init armada_370_xp_mpic_of_init(struct device_node *node, 527static int __init armada_370_xp_mpic_of_init(struct device_node *node,
478 struct device_node *parent) 528 struct device_node *parent)
479{ 529{
@@ -530,6 +580,8 @@ static int __init armada_370_xp_mpic_of_init(struct device_node *node,
530 armada_370_xp_mpic_handle_cascade_irq); 580 armada_370_xp_mpic_handle_cascade_irq);
531 } 581 }
532 582
583 register_syscore_ops(&armada_370_xp_mpic_syscore_ops);
584
533 return 0; 585 return 0;
534} 586}
535 587
diff --git a/include/linux/mbus.h b/include/linux/mbus.h
index 550c88fb0267..611b69fa8594 100644
--- a/include/linux/mbus.h
+++ b/include/linux/mbus.h
@@ -61,6 +61,7 @@ static inline const struct mbus_dram_target_info *mv_mbus_dram_info(void)
61} 61}
62#endif 62#endif
63 63
64int mvebu_mbus_save_cpu_target(u32 *store_addr);
64void mvebu_mbus_get_pcie_mem_aperture(struct resource *res); 65void mvebu_mbus_get_pcie_mem_aperture(struct resource *res);
65void mvebu_mbus_get_pcie_io_aperture(struct resource *res); 66void mvebu_mbus_get_pcie_io_aperture(struct resource *res);
66int mvebu_mbus_add_window_remap_by_id(unsigned int target, 67int mvebu_mbus_add_window_remap_by_id(unsigned int target,