aboutsummaryrefslogtreecommitdiffstats
path: root/arch/arm/mach-mvebu
diff options
context:
space:
mode:
authorOlof Johansson <olof@lixom.net>2014-07-08 01:27:00 -0400
committerOlof Johansson <olof@lixom.net>2014-07-08 01:27:00 -0400
commitb3c20e983269667ecce75fa7f4b0353917a8d0d1 (patch)
treeffae8b70f4c1b66791d7b805c427388f28aabfc2 /arch/arm/mach-mvebu
parent98abaf1370c932db38a23b270f86689b66b34cdf (diff)
parente65714740d65237c40878b63acad6bf921481974 (diff)
Merge tag 'mvebu-soc-3.17' of git://git.infradead.org/linux-mvebu into next/soc
Merge "mvebu SoC changes for v3.17" from Jason Cooper: - kirkwood * add setup file for netxbig LEDs (non-trivial DT binding doesn't exist yet) - mvebu * staticize where needed * add CPU hotplug for Armada XP * add public datasheet for Armada 370 * don't apply thermal quirk by default * get SoC ID from the system controller when possible * tag 'mvebu-soc-3.17' of git://git.infradead.org/linux-mvebu: ARM: mvebu: Staticize mvebu_cpu_reset_init ARM: mvebu: Staticize armada_370_xp_cpu_pm_init ARM: mvebu: Staticize armada_375_smp_cpu1_enable_wa ARM: mvebu: Use system controller to get the soc id when possible ARM: mvebu: Use the a standard errno in mvebu_get_soc_id ARM: mvebu: Don't apply the thermal quirk if the SoC revision is unknown Documentation: arm: add URLs to public datasheets for the Marvell Armada 370 SoC ARM: mvebu: implement CPU hotplug support for Armada XP ARM: mvebu: export PMSU idle enter/exit functions ARM: mvebu: slightly refactor/rename PMSU idle related functions ARM: mvebu: remove stub implementation of CPU hotplug on Armada 375/38x ARM: Kirkwood: Add setup file for netxbig LEDs ARM: mvebu: mark armada_370_xp_pmsu_idle_prepare() as static Signed-off-by: Olof Johansson <olof@lixom.net>
Diffstat (limited to 'arch/arm/mach-mvebu')
-rw-r--r--arch/arm/mach-mvebu/Kconfig7
-rw-r--r--arch/arm/mach-mvebu/Makefile2
-rw-r--r--arch/arm/mach-mvebu/armada-370-xp.h3
-rw-r--r--arch/arm/mach-mvebu/board-v7.c13
-rw-r--r--arch/arm/mach-mvebu/board.h5
-rw-r--r--arch/arm/mach-mvebu/common.h3
-rw-r--r--arch/arm/mach-mvebu/cpu-reset.c2
-rw-r--r--arch/arm/mach-mvebu/hotplug.c31
-rw-r--r--arch/arm/mach-mvebu/kirkwood.c3
-rw-r--r--arch/arm/mach-mvebu/mvebu-soc-id.c21
-rw-r--r--arch/arm/mach-mvebu/netxbig.c191
-rw-r--r--arch/arm/mach-mvebu/platsmp-a9.c5
-rw-r--r--arch/arm/mach-mvebu/platsmp.c48
-rw-r--r--arch/arm/mach-mvebu/pmsu.c17
-rw-r--r--arch/arm/mach-mvebu/system-controller.c19
15 files changed, 316 insertions, 54 deletions
diff --git a/arch/arm/mach-mvebu/Kconfig b/arch/arm/mach-mvebu/Kconfig
index b9bc599a5fd0..955d4a3afabd 100644
--- a/arch/arm/mach-mvebu/Kconfig
+++ b/arch/arm/mach-mvebu/Kconfig
@@ -96,4 +96,11 @@ config MACH_KIRKWOOD
96 Say 'Y' here if you want your kernel to support boards based 96 Say 'Y' here if you want your kernel to support boards based
97 on the Marvell Kirkwood device tree. 97 on the Marvell Kirkwood device tree.
98 98
99config MACH_NETXBIG
100 bool "LaCie 2Big and 5Big Network v2"
101 depends on MACH_KIRKWOOD
102 help
103 Say 'Y' here if you want your kernel to support the
104 LaCie 2Big and 5Big Network v2
105
99endif 106endif
diff --git a/arch/arm/mach-mvebu/Makefile b/arch/arm/mach-mvebu/Makefile
index 2ecb828e4a8b..90bcd5327312 100644
--- a/arch/arm/mach-mvebu/Makefile
+++ b/arch/arm/mach-mvebu/Makefile
@@ -9,8 +9,8 @@ obj-y += system-controller.o mvebu-soc-id.o
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 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 11obj-$(CONFIG_SMP) += platsmp.o headsmp.o platsmp-a9.o headsmp-a9.o
12obj-$(CONFIG_HOTPLUG_CPU) += hotplug.o
13endif 12endif
14 13
15obj-$(CONFIG_MACH_DOVE) += dove.o 14obj-$(CONFIG_MACH_DOVE) += dove.o
16obj-$(CONFIG_MACH_KIRKWOOD) += kirkwood.o kirkwood-pm.o 15obj-$(CONFIG_MACH_KIRKWOOD) += kirkwood.o kirkwood-pm.o
16obj-$(CONFIG_MACH_NETXBIG) += netxbig.o
diff --git a/arch/arm/mach-mvebu/armada-370-xp.h b/arch/arm/mach-mvebu/armada-370-xp.h
index c3465f5b1250..52c1603a4f92 100644
--- a/arch/arm/mach-mvebu/armada-370-xp.h
+++ b/arch/arm/mach-mvebu/armada-370-xp.h
@@ -24,4 +24,7 @@ void armada_xp_secondary_startup(void);
24extern struct smp_operations armada_xp_smp_ops; 24extern struct smp_operations armada_xp_smp_ops;
25#endif 25#endif
26 26
27int armada_370_xp_pmsu_idle_enter(unsigned long deepidle);
28void armada_370_xp_pmsu_idle_exit(void);
29
27#endif /* __MACH_ARMADA_370_XP_H */ 30#endif /* __MACH_ARMADA_370_XP_H */
diff --git a/arch/arm/mach-mvebu/board-v7.c b/arch/arm/mach-mvebu/board-v7.c
index 8bb742fdf5ca..a04675e2ec99 100644
--- a/arch/arm/mach-mvebu/board-v7.c
+++ b/arch/arm/mach-mvebu/board-v7.c
@@ -118,8 +118,16 @@ static void __init thermal_quirk(void)
118{ 118{
119 struct device_node *np; 119 struct device_node *np;
120 u32 dev, rev; 120 u32 dev, rev;
121 int res;
121 122
122 if (mvebu_get_soc_id(&dev, &rev) == 0 && rev > ARMADA_375_Z1_REV) 123 /*
124 * The early SoC Z1 revision needs a quirk to be applied in order
125 * for the thermal controller to work properly. This quirk breaks
126 * the thermal support if applied on a SoC that doesn't need it,
127 * so we enforce the SoC revision to be known.
128 */
129 res = mvebu_get_soc_id(&dev, &rev);
130 if (res < 0 || (res == 0 && rev > ARMADA_375_Z1_REV))
123 return; 131 return;
124 132
125 for_each_compatible_node(np, NULL, "marvell,armada375-thermal") { 133 for_each_compatible_node(np, NULL, "marvell,armada375-thermal") {
@@ -153,7 +161,8 @@ static void __init thermal_quirk(void)
153 161
154 /* 162 /*
155 * The thermal controller needs some quirk too, so let's change 163 * The thermal controller needs some quirk too, so let's change
156 * the compatible string to reflect this. 164 * the compatible string to reflect this and allow the driver
165 * the take the necessary action.
157 */ 166 */
158 prop = kzalloc(sizeof(*prop), GFP_KERNEL); 167 prop = kzalloc(sizeof(*prop), GFP_KERNEL);
159 prop->name = kstrdup("compatible", GFP_KERNEL); 168 prop->name = kstrdup("compatible", GFP_KERNEL);
diff --git a/arch/arm/mach-mvebu/board.h b/arch/arm/mach-mvebu/board.h
index 9c7bb4386f8b..98e32cc2ef3d 100644
--- a/arch/arm/mach-mvebu/board.h
+++ b/arch/arm/mach-mvebu/board.h
@@ -13,4 +13,9 @@
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_NETXBIG
17void netxbig_init(void);
18#else
19static inline void netxbig_init(void) {};
20#endif
16#endif 21#endif
diff --git a/arch/arm/mach-mvebu/common.h b/arch/arm/mach-mvebu/common.h
index b67fb7a10d8b..a97778e28bf6 100644
--- a/arch/arm/mach-mvebu/common.h
+++ b/arch/arm/mach-mvebu/common.h
@@ -21,7 +21,6 @@ void mvebu_restart(enum reboot_mode mode, const char *cmd);
21int mvebu_cpu_reset_deassert(int cpu); 21int mvebu_cpu_reset_deassert(int cpu);
22void mvebu_pmsu_set_cpu_boot_addr(int hw_cpu, void *boot_addr); 22void mvebu_pmsu_set_cpu_boot_addr(int hw_cpu, void *boot_addr);
23void mvebu_system_controller_set_cpu_boot_addr(void *boot_addr); 23void mvebu_system_controller_set_cpu_boot_addr(void *boot_addr);
24 24int mvebu_system_controller_get_soc_id(u32 *dev, u32 *rev);
25void armada_xp_cpu_die(unsigned int cpu);
26 25
27#endif 26#endif
diff --git a/arch/arm/mach-mvebu/cpu-reset.c b/arch/arm/mach-mvebu/cpu-reset.c
index 4a8f9eebebea..60fb53787004 100644
--- a/arch/arm/mach-mvebu/cpu-reset.c
+++ b/arch/arm/mach-mvebu/cpu-reset.c
@@ -67,7 +67,7 @@ static int mvebu_cpu_reset_map(struct device_node *np, int res_idx)
67 return 0; 67 return 0;
68} 68}
69 69
70int __init mvebu_cpu_reset_init(void) 70static int __init mvebu_cpu_reset_init(void)
71{ 71{
72 struct device_node *np; 72 struct device_node *np;
73 int res_idx; 73 int res_idx;
diff --git a/arch/arm/mach-mvebu/hotplug.c b/arch/arm/mach-mvebu/hotplug.c
deleted file mode 100644
index d95e91047168..000000000000
--- a/arch/arm/mach-mvebu/hotplug.c
+++ /dev/null
@@ -1,31 +0,0 @@
1/*
2 * Symmetric Multi Processing (SMP) support for Armada XP
3 *
4 * Copyright (C) 2012 Marvell
5 *
6 * Lior Amsalem <alior@marvell.com>
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#include <linux/kernel.h>
15#include <linux/errno.h>
16#include <linux/smp.h>
17#include <asm/proc-fns.h>
18#include "common.h"
19
20/*
21 * platform-specific code to shutdown a CPU
22 *
23 * Called with IRQs disabled
24 */
25void __ref armada_xp_cpu_die(unsigned int cpu)
26{
27 cpu_do_idle();
28
29 /* We should never return from idle */
30 panic("mvebu: cpu %d unexpectedly exit from shutdown\n", cpu);
31}
diff --git a/arch/arm/mach-mvebu/kirkwood.c b/arch/arm/mach-mvebu/kirkwood.c
index 46f105913c84..6b5310828eb2 100644
--- a/arch/arm/mach-mvebu/kirkwood.c
+++ b/arch/arm/mach-mvebu/kirkwood.c
@@ -180,6 +180,9 @@ 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("lacie,netxbig"))
184 netxbig_init();
185
183 of_platform_populate(NULL, of_default_bus_match_table, auxdata, NULL); 186 of_platform_populate(NULL, of_default_bus_match_table, auxdata, NULL);
184} 187}
185 188
diff --git a/arch/arm/mach-mvebu/mvebu-soc-id.c b/arch/arm/mach-mvebu/mvebu-soc-id.c
index d0f35b4d4a23..a99434bcee84 100644
--- a/arch/arm/mach-mvebu/mvebu-soc-id.c
+++ b/arch/arm/mach-mvebu/mvebu-soc-id.c
@@ -25,6 +25,7 @@
25#include <linux/of_address.h> 25#include <linux/of_address.h>
26#include <linux/slab.h> 26#include <linux/slab.h>
27#include <linux/sys_soc.h> 27#include <linux/sys_soc.h>
28#include "common.h"
28#include "mvebu-soc-id.h" 29#include "mvebu-soc-id.h"
29 30
30#define PCIE_DEV_ID_OFF 0x0 31#define PCIE_DEV_ID_OFF 0x0
@@ -51,10 +52,10 @@ int mvebu_get_soc_id(u32 *dev, u32 *rev)
51 *rev = soc_rev; 52 *rev = soc_rev;
52 return 0; 53 return 0;
53 } else 54 } else
54 return -1; 55 return -ENODEV;
55} 56}
56 57
57static int __init mvebu_soc_id_init(void) 58static int __init get_soc_id_by_pci(void)
58{ 59{
59 struct device_node *np; 60 struct device_node *np;
60 int ret = 0; 61 int ret = 0;
@@ -129,6 +130,22 @@ clk_err:
129 130
130 return ret; 131 return ret;
131} 132}
133
134static int __init mvebu_soc_id_init(void)
135{
136
137 /*
138 * First try to get the ID and the revision by the system
139 * register and use PCI registers only if it is not possible
140 */
141 if (!mvebu_system_controller_get_soc_id(&soc_dev_id, &soc_rev)) {
142 is_id_valid = true;
143 pr_info("MVEBU SoC ID=0x%X, Rev=0x%X\n", soc_dev_id, soc_rev);
144 return 0;
145 }
146
147 return get_soc_id_by_pci();
148}
132early_initcall(mvebu_soc_id_init); 149early_initcall(mvebu_soc_id_init);
133 150
134static int __init mvebu_soc_device(void) 151static int __init mvebu_soc_device(void)
diff --git a/arch/arm/mach-mvebu/netxbig.c b/arch/arm/mach-mvebu/netxbig.c
new file mode 100644
index 000000000000..94b11b6585a4
--- /dev/null
+++ b/arch/arm/mach-mvebu/netxbig.c
@@ -0,0 +1,191 @@
1/*
2 * arch/arm/mach-mvbu/board-netxbig.c
3 *
4 * LaCie 2Big and 5Big Network v2 board setup
5 *
6 * Copyright (C) 2010 Simon Guinot <sguinot@lacie.com>
7 *
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2 of the License, or
11 * (at your option) any later version.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
17 */
18
19#include <linux/kernel.h>
20#include <linux/of.h>
21#include <linux/platform_device.h>
22#include <linux/platform_data/leds-kirkwood-netxbig.h>
23#include "common.h"
24
25/*****************************************************************************
26 * GPIO extension LEDs
27 ****************************************************************************/
28
29/*
30 * The LEDs are controlled by a CPLD and can be configured through a GPIO
31 * extension bus:
32 *
33 * - address register : bit [0-2] -> GPIO [47-49]
34 * - data register : bit [0-2] -> GPIO [44-46]
35 * - enable register : GPIO 29
36 */
37
38static int netxbig_v2_gpio_ext_addr[] = { 47, 48, 49 };
39static int netxbig_v2_gpio_ext_data[] = { 44, 45, 46 };
40
41static struct netxbig_gpio_ext netxbig_v2_gpio_ext = {
42 .addr = netxbig_v2_gpio_ext_addr,
43 .num_addr = ARRAY_SIZE(netxbig_v2_gpio_ext_addr),
44 .data = netxbig_v2_gpio_ext_data,
45 .num_data = ARRAY_SIZE(netxbig_v2_gpio_ext_data),
46 .enable = 29,
47};
48
49/*
50 * Address register selection:
51 *
52 * addr | register
53 * ----------------------------
54 * 0 | front LED
55 * 1 | front LED brightness
56 * 2 | SATA LED brightness
57 * 3 | SATA0 LED
58 * 4 | SATA1 LED
59 * 5 | SATA2 LED
60 * 6 | SATA3 LED
61 * 7 | SATA4 LED
62 *
63 * Data register configuration:
64 *
65 * data | LED brightness
66 * -------------------------------------------------
67 * 0 | min (off)
68 * - | -
69 * 7 | max
70 *
71 * data | front LED mode
72 * -------------------------------------------------
73 * 0 | fix off
74 * 1 | fix blue on
75 * 2 | fix red on
76 * 3 | blink blue on=1 sec and blue off=1 sec
77 * 4 | blink red on=1 sec and red off=1 sec
78 * 5 | blink blue on=2.5 sec and red on=0.5 sec
79 * 6 | blink blue on=1 sec and red on=1 sec
80 * 7 | blink blue on=0.5 sec and blue off=2.5 sec
81 *
82 * data | SATA LED mode
83 * -------------------------------------------------
84 * 0 | fix off
85 * 1 | SATA activity blink
86 * 2 | fix red on
87 * 3 | blink blue on=1 sec and blue off=1 sec
88 * 4 | blink red on=1 sec and red off=1 sec
89 * 5 | blink blue on=2.5 sec and red on=0.5 sec
90 * 6 | blink blue on=1 sec and red on=1 sec
91 * 7 | fix blue on
92 */
93
94static int netxbig_v2_red_mled[NETXBIG_LED_MODE_NUM] = {
95 [NETXBIG_LED_OFF] = 0,
96 [NETXBIG_LED_ON] = 2,
97 [NETXBIG_LED_SATA] = NETXBIG_LED_INVALID_MODE,
98 [NETXBIG_LED_TIMER1] = 4,
99 [NETXBIG_LED_TIMER2] = NETXBIG_LED_INVALID_MODE,
100};
101
102static int netxbig_v2_blue_pwr_mled[NETXBIG_LED_MODE_NUM] = {
103 [NETXBIG_LED_OFF] = 0,
104 [NETXBIG_LED_ON] = 1,
105 [NETXBIG_LED_SATA] = NETXBIG_LED_INVALID_MODE,
106 [NETXBIG_LED_TIMER1] = 3,
107 [NETXBIG_LED_TIMER2] = 7,
108};
109
110static int netxbig_v2_blue_sata_mled[NETXBIG_LED_MODE_NUM] = {
111 [NETXBIG_LED_OFF] = 0,
112 [NETXBIG_LED_ON] = 7,
113 [NETXBIG_LED_SATA] = 1,
114 [NETXBIG_LED_TIMER1] = 3,
115 [NETXBIG_LED_TIMER2] = NETXBIG_LED_INVALID_MODE,
116};
117
118static struct netxbig_led_timer netxbig_v2_led_timer[] = {
119 [0] = {
120 .delay_on = 500,
121 .delay_off = 500,
122 .mode = NETXBIG_LED_TIMER1,
123 },
124 [1] = {
125 .delay_on = 500,
126 .delay_off = 1000,
127 .mode = NETXBIG_LED_TIMER2,
128 },
129};
130
131#define NETXBIG_LED(_name, maddr, mval, baddr) \
132 { .name = _name, \
133 .mode_addr = maddr, \
134 .mode_val = mval, \
135 .bright_addr = baddr }
136
137static struct netxbig_led net2big_v2_leds_ctrl[] = {
138 NETXBIG_LED("net2big-v2:blue:power", 0, netxbig_v2_blue_pwr_mled, 1),
139 NETXBIG_LED("net2big-v2:red:power", 0, netxbig_v2_red_mled, 1),
140 NETXBIG_LED("net2big-v2:blue:sata0", 3, netxbig_v2_blue_sata_mled, 2),
141 NETXBIG_LED("net2big-v2:red:sata0", 3, netxbig_v2_red_mled, 2),
142 NETXBIG_LED("net2big-v2:blue:sata1", 4, netxbig_v2_blue_sata_mled, 2),
143 NETXBIG_LED("net2big-v2:red:sata1", 4, netxbig_v2_red_mled, 2),
144};
145
146static struct netxbig_led_platform_data net2big_v2_leds_data = {
147 .gpio_ext = &netxbig_v2_gpio_ext,
148 .timer = netxbig_v2_led_timer,
149 .num_timer = ARRAY_SIZE(netxbig_v2_led_timer),
150 .leds = net2big_v2_leds_ctrl,
151 .num_leds = ARRAY_SIZE(net2big_v2_leds_ctrl),
152};
153
154static struct netxbig_led net5big_v2_leds_ctrl[] = {
155 NETXBIG_LED("net5big-v2:blue:power", 0, netxbig_v2_blue_pwr_mled, 1),
156 NETXBIG_LED("net5big-v2:red:power", 0, netxbig_v2_red_mled, 1),
157 NETXBIG_LED("net5big-v2:blue:sata0", 3, netxbig_v2_blue_sata_mled, 2),
158 NETXBIG_LED("net5big-v2:red:sata0", 3, netxbig_v2_red_mled, 2),
159 NETXBIG_LED("net5big-v2:blue:sata1", 4, netxbig_v2_blue_sata_mled, 2),
160 NETXBIG_LED("net5big-v2:red:sata1", 4, netxbig_v2_red_mled, 2),
161 NETXBIG_LED("net5big-v2:blue:sata2", 5, netxbig_v2_blue_sata_mled, 2),
162 NETXBIG_LED("net5big-v2:red:sata2", 5, netxbig_v2_red_mled, 2),
163 NETXBIG_LED("net5big-v2:blue:sata3", 6, netxbig_v2_blue_sata_mled, 2),
164 NETXBIG_LED("net5big-v2:red:sata3", 6, netxbig_v2_red_mled, 2),
165 NETXBIG_LED("net5big-v2:blue:sata4", 7, netxbig_v2_blue_sata_mled, 2),
166 NETXBIG_LED("net5big-v2:red:sata4", 7, netxbig_v2_red_mled, 2),
167};
168
169static struct netxbig_led_platform_data net5big_v2_leds_data = {
170 .gpio_ext = &netxbig_v2_gpio_ext,
171 .timer = netxbig_v2_led_timer,
172 .num_timer = ARRAY_SIZE(netxbig_v2_led_timer),
173 .leds = net5big_v2_leds_ctrl,
174 .num_leds = ARRAY_SIZE(net5big_v2_leds_ctrl),
175};
176
177static struct platform_device netxbig_v2_leds = {
178 .name = "leds-netxbig",
179 .id = -1,
180 .dev = {
181 .platform_data = &net2big_v2_leds_data,
182 },
183};
184
185void __init netxbig_init(void)
186{
187
188 if (of_machine_is_compatible("lacie,net5big_v2"))
189 netxbig_v2_leds.dev.platform_data = &net5big_v2_leds_data;
190 platform_device_register(&netxbig_v2_leds);
191}
diff --git a/arch/arm/mach-mvebu/platsmp-a9.c b/arch/arm/mach-mvebu/platsmp-a9.c
index 96c2c59e34b6..43aaf3fa75ee 100644
--- a/arch/arm/mach-mvebu/platsmp-a9.c
+++ b/arch/arm/mach-mvebu/platsmp-a9.c
@@ -33,7 +33,7 @@
33extern unsigned char armada_375_smp_cpu1_enable_code_end; 33extern unsigned char armada_375_smp_cpu1_enable_code_end;
34extern unsigned char armada_375_smp_cpu1_enable_code_start; 34extern unsigned char armada_375_smp_cpu1_enable_code_start;
35 35
36void armada_375_smp_cpu1_enable_wa(void) 36static void armada_375_smp_cpu1_enable_wa(void)
37{ 37{
38 void __iomem *sram_virt_base; 38 void __iomem *sram_virt_base;
39 39
@@ -91,9 +91,6 @@ static int __cpuinit mvebu_cortex_a9_boot_secondary(unsigned int cpu,
91 91
92static struct smp_operations mvebu_cortex_a9_smp_ops __initdata = { 92static struct smp_operations mvebu_cortex_a9_smp_ops __initdata = {
93 .smp_boot_secondary = mvebu_cortex_a9_boot_secondary, 93 .smp_boot_secondary = mvebu_cortex_a9_boot_secondary,
94#ifdef CONFIG_HOTPLUG_CPU
95 .cpu_die = armada_xp_cpu_die,
96#endif
97}; 94};
98 95
99CPU_METHOD_OF_DECLARE(mvebu_armada_375_smp, "marvell,armada-375-smp", 96CPU_METHOD_OF_DECLARE(mvebu_armada_375_smp, "marvell,armada-375-smp",
diff --git a/arch/arm/mach-mvebu/platsmp.c b/arch/arm/mach-mvebu/platsmp.c
index 88b976b31719..b6fa9f0c98b8 100644
--- a/arch/arm/mach-mvebu/platsmp.c
+++ b/arch/arm/mach-mvebu/platsmp.c
@@ -78,6 +78,17 @@ static int armada_xp_boot_secondary(unsigned int cpu, struct task_struct *idle)
78 78
79 hw_cpu = cpu_logical_map(cpu); 79 hw_cpu = cpu_logical_map(cpu);
80 mvebu_pmsu_set_cpu_boot_addr(hw_cpu, armada_xp_secondary_startup); 80 mvebu_pmsu_set_cpu_boot_addr(hw_cpu, armada_xp_secondary_startup);
81
82 /*
83 * This is needed to wake up CPUs in the offline state after
84 * using CPU hotplug.
85 */
86 arch_send_wakeup_ipi_mask(cpumask_of(cpu));
87
88 /*
89 * This is needed to take secondary CPUs out of reset on the
90 * initial boot.
91 */
81 ret = mvebu_cpu_reset_deassert(hw_cpu); 92 ret = mvebu_cpu_reset_deassert(hw_cpu);
82 if (ret) { 93 if (ret) {
83 pr_warn("unable to boot CPU: %d\n", ret); 94 pr_warn("unable to boot CPU: %d\n", ret);
@@ -87,6 +98,19 @@ static int armada_xp_boot_secondary(unsigned int cpu, struct task_struct *idle)
87 return 0; 98 return 0;
88} 99}
89 100
101/*
102 * When a CPU is brought back online, either through CPU hotplug, or
103 * because of the boot of a kexec'ed kernel, the PMSU configuration
104 * for this CPU might be in the deep idle state, preventing this CPU
105 * from receiving interrupts. Here, we therefore take out the current
106 * CPU from this state, which was entered by armada_xp_cpu_die()
107 * below.
108 */
109static void armada_xp_secondary_init(unsigned int cpu)
110{
111 armada_370_xp_pmsu_idle_exit();
112}
113
90static void __init armada_xp_smp_init_cpus(void) 114static void __init armada_xp_smp_init_cpus(void)
91{ 115{
92 unsigned int ncores = num_possible_cpus(); 116 unsigned int ncores = num_possible_cpus();
@@ -122,12 +146,36 @@ static void __init armada_xp_smp_prepare_cpus(unsigned int max_cpus)
122 panic("The address for the BootROM is incorrect"); 146 panic("The address for the BootROM is incorrect");
123} 147}
124 148
149#ifdef CONFIG_HOTPLUG_CPU
150static void armada_xp_cpu_die(unsigned int cpu)
151{
152 /*
153 * CPU hotplug is implemented by putting offline CPUs into the
154 * deep idle sleep state.
155 */
156 armada_370_xp_pmsu_idle_enter(true);
157}
158
159/*
160 * We need a dummy function, so that platform_can_cpu_hotplug() knows
161 * we support CPU hotplug. However, the function does not need to do
162 * anything, because CPUs going offline can enter the deep idle state
163 * by themselves, without any help from a still alive CPU.
164 */
165static int armada_xp_cpu_kill(unsigned int cpu)
166{
167 return 1;
168}
169#endif
170
125struct smp_operations armada_xp_smp_ops __initdata = { 171struct smp_operations armada_xp_smp_ops __initdata = {
126 .smp_init_cpus = armada_xp_smp_init_cpus, 172 .smp_init_cpus = armada_xp_smp_init_cpus,
127 .smp_prepare_cpus = armada_xp_smp_prepare_cpus, 173 .smp_prepare_cpus = armada_xp_smp_prepare_cpus,
128 .smp_boot_secondary = armada_xp_boot_secondary, 174 .smp_boot_secondary = armada_xp_boot_secondary,
175 .smp_secondary_init = armada_xp_secondary_init,
129#ifdef CONFIG_HOTPLUG_CPU 176#ifdef CONFIG_HOTPLUG_CPU
130 .cpu_die = armada_xp_cpu_die, 177 .cpu_die = armada_xp_cpu_die,
178 .cpu_kill = armada_xp_cpu_kill,
131#endif 179#endif
132}; 180};
133 181
diff --git a/arch/arm/mach-mvebu/pmsu.c b/arch/arm/mach-mvebu/pmsu.c
index 53a55c8520bf..9c819d65b337 100644
--- a/arch/arm/mach-mvebu/pmsu.c
+++ b/arch/arm/mach-mvebu/pmsu.c
@@ -148,13 +148,13 @@ static void armada_370_xp_cpu_resume(void)
148} 148}
149 149
150/* No locking is needed because we only access per-CPU registers */ 150/* No locking is needed because we only access per-CPU registers */
151void armada_370_xp_pmsu_idle_prepare(bool deepidle) 151int armada_370_xp_pmsu_idle_enter(unsigned long deepidle)
152{ 152{
153 unsigned int hw_cpu = cpu_logical_map(smp_processor_id()); 153 unsigned int hw_cpu = cpu_logical_map(smp_processor_id());
154 u32 reg; 154 u32 reg;
155 155
156 if (pmsu_mp_base == NULL) 156 if (pmsu_mp_base == NULL)
157 return; 157 return -EINVAL;
158 158
159 /* 159 /*
160 * Adjust the PMSU configuration to wait for WFI signal, enable 160 * Adjust the PMSU configuration to wait for WFI signal, enable
@@ -183,11 +183,6 @@ void armada_370_xp_pmsu_idle_prepare(bool deepidle)
183 reg = readl(pmsu_mp_base + PMSU_CPU_POWER_DOWN_CONTROL(hw_cpu)); 183 reg = readl(pmsu_mp_base + PMSU_CPU_POWER_DOWN_CONTROL(hw_cpu));
184 reg |= PMSU_CPU_POWER_DOWN_DIS_SNP_Q_SKIP; 184 reg |= PMSU_CPU_POWER_DOWN_DIS_SNP_Q_SKIP;
185 writel(reg, pmsu_mp_base + PMSU_CPU_POWER_DOWN_CONTROL(hw_cpu)); 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 186
192 v7_exit_coherency_flush(all); 187 v7_exit_coherency_flush(all);
193 188
@@ -220,11 +215,11 @@ static noinline int do_armada_370_xp_cpu_suspend(unsigned long deepidle)
220 215
221static int armada_370_xp_cpu_suspend(unsigned long deepidle) 216static int armada_370_xp_cpu_suspend(unsigned long deepidle)
222{ 217{
223 return cpu_suspend(deepidle, do_armada_370_xp_cpu_suspend); 218 return cpu_suspend(deepidle, armada_370_xp_pmsu_idle_enter);
224} 219}
225 220
226/* No locking is needed because we only access per-CPU registers */ 221/* No locking is needed because we only access per-CPU registers */
227static noinline void armada_370_xp_pmsu_idle_restore(void) 222void armada_370_xp_pmsu_idle_exit(void)
228{ 223{
229 unsigned int hw_cpu = cpu_logical_map(smp_processor_id()); 224 unsigned int hw_cpu = cpu_logical_map(smp_processor_id());
230 u32 reg; 225 u32 reg;
@@ -253,7 +248,7 @@ static int armada_370_xp_cpu_pm_notify(struct notifier_block *self,
253 unsigned int hw_cpu = cpu_logical_map(smp_processor_id()); 248 unsigned int hw_cpu = cpu_logical_map(smp_processor_id());
254 mvebu_pmsu_set_cpu_boot_addr(hw_cpu, armada_370_xp_cpu_resume); 249 mvebu_pmsu_set_cpu_boot_addr(hw_cpu, armada_370_xp_cpu_resume);
255 } else if (action == CPU_PM_EXIT) { 250 } else if (action == CPU_PM_EXIT) {
256 armada_370_xp_pmsu_idle_restore(); 251 armada_370_xp_pmsu_idle_exit();
257 } 252 }
258 253
259 return NOTIFY_OK; 254 return NOTIFY_OK;
@@ -263,7 +258,7 @@ static struct notifier_block armada_370_xp_cpu_pm_notifier = {
263 .notifier_call = armada_370_xp_cpu_pm_notify, 258 .notifier_call = armada_370_xp_cpu_pm_notify,
264}; 259};
265 260
266int __init armada_370_xp_cpu_pm_init(void) 261static int __init armada_370_xp_cpu_pm_init(void)
267{ 262{
268 struct device_node *np; 263 struct device_node *np;
269 264
diff --git a/arch/arm/mach-mvebu/system-controller.c b/arch/arm/mach-mvebu/system-controller.c
index 0c5524ac75b7..b2b4e3d6558c 100644
--- a/arch/arm/mach-mvebu/system-controller.c
+++ b/arch/arm/mach-mvebu/system-controller.c
@@ -39,6 +39,9 @@ struct mvebu_system_controller {
39 u32 system_soft_reset; 39 u32 system_soft_reset;
40 40
41 u32 resume_boot_addr; 41 u32 resume_boot_addr;
42
43 u32 dev_id;
44 u32 rev_id;
42}; 45};
43static struct mvebu_system_controller *mvebu_sc; 46static struct mvebu_system_controller *mvebu_sc;
44 47
@@ -47,6 +50,8 @@ static const struct mvebu_system_controller armada_370_xp_system_controller = {
47 .system_soft_reset_offset = 0x64, 50 .system_soft_reset_offset = 0x64,
48 .rstoutn_mask_reset_out_en = 0x1, 51 .rstoutn_mask_reset_out_en = 0x1,
49 .system_soft_reset = 0x1, 52 .system_soft_reset = 0x1,
53 .dev_id = 0x38,
54 .rev_id = 0x3c,
50}; 55};
51 56
52static const struct mvebu_system_controller armada_375_system_controller = { 57static const struct mvebu_system_controller armada_375_system_controller = {
@@ -55,6 +60,8 @@ static const struct mvebu_system_controller armada_375_system_controller = {
55 .rstoutn_mask_reset_out_en = 0x1, 60 .rstoutn_mask_reset_out_en = 0x1,
56 .system_soft_reset = 0x1, 61 .system_soft_reset = 0x1,
57 .resume_boot_addr = 0xd4, 62 .resume_boot_addr = 0xd4,
63 .dev_id = 0x38,
64 .rev_id = 0x3c,
58}; 65};
59 66
60static const struct mvebu_system_controller orion_system_controller = { 67static const struct mvebu_system_controller orion_system_controller = {
@@ -101,6 +108,18 @@ void mvebu_restart(enum reboot_mode mode, const char *cmd)
101 ; 108 ;
102} 109}
103 110
111int mvebu_system_controller_get_soc_id(u32 *dev, u32 *rev)
112{
113 if (of_machine_is_compatible("marvell,armada380") &&
114 system_controller_base) {
115 *dev = readl(system_controller_base + mvebu_sc->dev_id) >> 16;
116 *rev = (readl(system_controller_base + mvebu_sc->rev_id) >> 8)
117 & 0xF;
118 return 0;
119 } else
120 return -ENODEV;
121}
122
104#ifdef CONFIG_SMP 123#ifdef CONFIG_SMP
105void mvebu_system_controller_set_cpu_boot_addr(void *boot_addr) 124void mvebu_system_controller_set_cpu_boot_addr(void *boot_addr)
106{ 125{