aboutsummaryrefslogtreecommitdiffstats
path: root/arch/arm/mach-mvebu
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2014-08-08 14:14:29 -0400
committerLinus Torvalds <torvalds@linux-foundation.org>2014-08-08 14:14:29 -0400
commitb3345d7c57d70e6cb6749af25cdbe80515582e99 (patch)
tree04cce706bc7e944ad1fb257108a8ae735948f97f /arch/arm/mach-mvebu
parent44c916d58b9ef1f2c4aec2def57fa8289c716a60 (diff)
parentc2fff85e21818952aa0ee5778926beee6c03e579 (diff)
Merge tag 'soc-for-3.17' of git://git.kernel.org/pub/scm/linux/kernel/git/arm/arm-soc
Pull ARM SoC platform changes from Olof Johansson: "This is the bulk of new SoC enablement and other platform changes for 3.17: - Samsung S5PV210 has been converted to DT and multiplatform - Clock drivers and bindings for some of the lower-end i.MX 1/2 platforms - Kirkwood, one of the popular Marvell platforms, is folded into the mvebu platform code, removing mach-kirkwood - Hwmod data for TI AM43xx and DRA7 platforms - More additions of Renesas shmobile platform support - Removal of plat-samsung contents that can be removed with S5PV210 being multiplatform/DT-enabled and the other two old platforms being removed New platforms (most with only basic support right now): - Hisilicon X5HD2 settop box chipset is introduced - Mediatek MT6589 (mobile chipset) is introduced - Broadcom BCM7xxx settop box chipset is introduced + as usual a lot other pieces all over the platform code" * tag 'soc-for-3.17' of git://git.kernel.org/pub/scm/linux/kernel/git/arm/arm-soc: (240 commits) ARM: hisi: remove smp from machine descriptor power: reset: move hisilicon reboot code ARM: dts: Add hix5hd2-dkb dts file. ARM: debug: Rename Hi3716 to HIX5HD2 ARM: hisi: enable hix5hd2 SoC ARM: hisi: add ARCH_HISI MAINTAINERS: add entry for Broadcom ARM STB architecture ARM: brcmstb: select GISB arbiter and interrupt drivers ARM: brcmstb: add infrastructure for ARM-based Broadcom STB SoCs ARM: configs: enable SMP in bcm_defconfig ARM: add SMP support for Broadcom mobile SoCs Documentation: arm: misc updates to Marvell EBU SoC status Documentation: arm: add URLs to public datasheets for the Marvell Armada XP SoC ARM: mvebu: fix build without platforms selected ARM: mvebu: add cpuidle support for Armada 38x ARM: mvebu: add cpuidle support for Armada 370 cpuidle: mvebu: add Armada 38x support cpuidle: mvebu: add Armada 370 support cpuidle: mvebu: rename the driver from armada-370-xp to mvebu-v7 ARM: mvebu: export the SCU address ...
Diffstat (limited to 'arch/arm/mach-mvebu')
-rw-r--r--arch/arm/mach-mvebu/Kconfig13
-rw-r--r--arch/arm/mach-mvebu/Makefile4
-rw-r--r--arch/arm/mach-mvebu/armada-370-xp.h2
-rw-r--r--arch/arm/mach-mvebu/board-v7.c22
-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/headsmp-a9.S15
-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.c45
-rw-r--r--arch/arm/mach-mvebu/platsmp.c49
-rw-r--r--arch/arm/mach-mvebu/pmsu.c438
-rw-r--r--arch/arm/mach-mvebu/pmsu.h5
-rw-r--r--arch/arm/mach-mvebu/pmsu_ll.S36
-rw-r--r--arch/arm/mach-mvebu/system-controller.c50
18 files changed, 797 insertions, 138 deletions
diff --git a/arch/arm/mach-mvebu/Kconfig b/arch/arm/mach-mvebu/Kconfig
index b9bc599a5fd0..c1e4567a5ab3 100644
--- a/arch/arm/mach-mvebu/Kconfig
+++ b/arch/arm/mach-mvebu/Kconfig
@@ -14,11 +14,15 @@ menuconfig ARCH_MVEBU
14 14
15if ARCH_MVEBU 15if ARCH_MVEBU
16 16
17config MACH_MVEBU_ANY
18 bool
19
17config MACH_MVEBU_V7 20config MACH_MVEBU_V7
18 bool 21 bool
19 select ARMADA_370_XP_TIMER 22 select ARMADA_370_XP_TIMER
20 select CACHE_L2X0 23 select CACHE_L2X0
21 select ARM_CPU_SUSPEND 24 select ARM_CPU_SUSPEND
25 select MACH_MVEBU_ANY
22 26
23config MACH_ARMADA_370 27config MACH_ARMADA_370
24 bool "Marvell Armada 370 boards" if ARCH_MULTI_V7 28 bool "Marvell Armada 370 boards" if ARCH_MULTI_V7
@@ -75,6 +79,7 @@ config MACH_DOVE
75 select CACHE_L2X0 79 select CACHE_L2X0
76 select CPU_PJ4 80 select CPU_PJ4
77 select DOVE_CLK 81 select DOVE_CLK
82 select MACH_MVEBU_ANY
78 select ORION_IRQCHIP 83 select ORION_IRQCHIP
79 select ORION_TIMER 84 select ORION_TIMER
80 select PINCTRL_DOVE 85 select PINCTRL_DOVE
@@ -87,6 +92,7 @@ config MACH_KIRKWOOD
87 select ARCH_REQUIRE_GPIOLIB 92 select ARCH_REQUIRE_GPIOLIB
88 select CPU_FEROCEON 93 select CPU_FEROCEON
89 select KIRKWOOD_CLK 94 select KIRKWOOD_CLK
95 select MACH_MVEBU_ANY
90 select ORION_IRQCHIP 96 select ORION_IRQCHIP
91 select ORION_TIMER 97 select ORION_TIMER
92 select PCI 98 select PCI
@@ -96,4 +102,11 @@ config MACH_KIRKWOOD
96 Say 'Y' here if you want your kernel to support boards based 102 Say 'Y' here if you want your kernel to support boards based
97 on the Marvell Kirkwood device tree. 103 on the Marvell Kirkwood device tree.
98 104
105config MACH_NETXBIG
106 bool "LaCie 2Big and 5Big Network v2"
107 depends on MACH_KIRKWOOD
108 help
109 Say 'Y' here if you want your kernel to support the
110 LaCie 2Big and 5Big Network v2
111
99endif 112endif
diff --git a/arch/arm/mach-mvebu/Makefile b/arch/arm/mach-mvebu/Makefile
index 1636cdbef01a..e24136b42765 100644
--- a/arch/arm/mach-mvebu/Makefile
+++ b/arch/arm/mach-mvebu/Makefile
@@ -4,13 +4,13 @@ ccflags-$(CONFIG_ARCH_MULTIPLATFORM) := -I$(srctree)/$(src)/include \
4AFLAGS_coherency_ll.o := -Wa,-march=armv7-a 4AFLAGS_coherency_ll.o := -Wa,-march=armv7-a
5CFLAGS_pmsu.o := -march=armv7-a 5CFLAGS_pmsu.o := -march=armv7-a
6 6
7obj-y += 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
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..84cd90d9b860 100644
--- a/arch/arm/mach-mvebu/armada-370-xp.h
+++ b/arch/arm/mach-mvebu/armada-370-xp.h
@@ -24,4 +24,6 @@ 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);
28
27#endif /* __MACH_ARMADA_370_XP_H */ 29#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 b2524d689f21..6478626e3ff6 100644
--- a/arch/arm/mach-mvebu/board-v7.c
+++ b/arch/arm/mach-mvebu/board-v7.c
@@ -34,14 +34,14 @@
34#include "coherency.h" 34#include "coherency.h"
35#include "mvebu-soc-id.h" 35#include "mvebu-soc-id.h"
36 36
37static void __iomem *scu_base;
38
37/* 39/*
38 * Enables the SCU when available. Obviously, this is only useful on 40 * Enables the SCU when available. Obviously, this is only useful on
39 * Cortex-A based SOCs, not on PJ4B based ones. 41 * Cortex-A based SOCs, not on PJ4B based ones.
40 */ 42 */
41static void __init mvebu_scu_enable(void) 43static void __init mvebu_scu_enable(void)
42{ 44{
43 void __iomem *scu_base;
44
45 struct device_node *np = 45 struct device_node *np =
46 of_find_compatible_node(NULL, NULL, "arm,cortex-a9-scu"); 46 of_find_compatible_node(NULL, NULL, "arm,cortex-a9-scu");
47 if (np) { 47 if (np) {
@@ -51,6 +51,11 @@ static void __init mvebu_scu_enable(void)
51 } 51 }
52} 52}
53 53
54void __iomem *mvebu_get_scu_base(void)
55{
56 return scu_base;
57}
58
54/* 59/*
55 * Early versions of Armada 375 SoC have a bug where the BootROM 60 * Early versions of Armada 375 SoC have a bug where the BootROM
56 * leaves an external data abort pending. The kernel is hit by this 61 * leaves an external data abort pending. The kernel is hit by this
@@ -125,8 +130,16 @@ static void __init thermal_quirk(void)
125{ 130{
126 struct device_node *np; 131 struct device_node *np;
127 u32 dev, rev; 132 u32 dev, rev;
133 int res;
128 134
129 if (mvebu_get_soc_id(&dev, &rev) == 0 && rev > ARMADA_375_Z1_REV) 135 /*
136 * The early SoC Z1 revision needs a quirk to be applied in order
137 * for the thermal controller to work properly. This quirk breaks
138 * the thermal support if applied on a SoC that doesn't need it,
139 * so we enforce the SoC revision to be known.
140 */
141 res = mvebu_get_soc_id(&dev, &rev);
142 if (res < 0 || (res == 0 && rev > ARMADA_375_Z1_REV))
130 return; 143 return;
131 144
132 for_each_compatible_node(np, NULL, "marvell,armada375-thermal") { 145 for_each_compatible_node(np, NULL, "marvell,armada375-thermal") {
@@ -160,7 +173,8 @@ static void __init thermal_quirk(void)
160 173
161 /* 174 /*
162 * The thermal controller needs some quirk too, so let's change 175 * The thermal controller needs some quirk too, so let's change
163 * the compatible string to reflect this. 176 * the compatible string to reflect this and allow the driver
177 * the take the necessary action.
164 */ 178 */
165 prop = kzalloc(sizeof(*prop), GFP_KERNEL); 179 prop = kzalloc(sizeof(*prop), GFP_KERNEL);
166 prop->name = kstrdup("compatible", GFP_KERNEL); 180 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..3ccb40c3bf94 100644
--- a/arch/arm/mach-mvebu/common.h
+++ b/arch/arm/mach-mvebu/common.h
@@ -21,7 +21,8 @@ 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);
24int mvebu_system_controller_get_soc_id(u32 *dev, u32 *rev);
24 25
25void armada_xp_cpu_die(unsigned int cpu); 26void __iomem *mvebu_get_scu_base(void);
26 27
27#endif 28#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/headsmp-a9.S b/arch/arm/mach-mvebu/headsmp-a9.S
index 2c3c7fc65e28..be51c998c0cd 100644
--- a/arch/arm/mach-mvebu/headsmp-a9.S
+++ b/arch/arm/mach-mvebu/headsmp-a9.S
@@ -18,21 +18,6 @@
18#include <asm/assembler.h> 18#include <asm/assembler.h>
19 19
20 __CPUINIT 20 __CPUINIT
21#define CPU_RESUME_ADDR_REG 0xf10182d4
22
23.global armada_375_smp_cpu1_enable_code_start
24.global armada_375_smp_cpu1_enable_code_end
25
26armada_375_smp_cpu1_enable_code_start:
27ARM_BE8(setend be)
28 adr r0, 1f
29 ldr r0, [r0]
30 ldr r1, [r0]
31ARM_BE8(rev r1, r1)
32 ret r1
331:
34 .word CPU_RESUME_ADDR_REG
35armada_375_smp_cpu1_enable_code_end:
36 21
37ENTRY(mvebu_cortex_a9_secondary_startup) 22ENTRY(mvebu_cortex_a9_secondary_startup)
38ARM_BE8(setend be) 23ARM_BE8(setend be)
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..47a71a924b96 100644
--- a/arch/arm/mach-mvebu/platsmp-a9.c
+++ b/arch/arm/mach-mvebu/platsmp-a9.c
@@ -20,33 +20,8 @@
20#include <asm/smp_scu.h> 20#include <asm/smp_scu.h>
21#include <asm/smp_plat.h> 21#include <asm/smp_plat.h>
22#include "common.h" 22#include "common.h"
23#include "mvebu-soc-id.h"
24#include "pmsu.h" 23#include "pmsu.h"
25 24
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); 25extern void mvebu_cortex_a9_secondary_startup(void);
51 26
52static int __cpuinit mvebu_cortex_a9_boot_secondary(unsigned int cpu, 27static int __cpuinit mvebu_cortex_a9_boot_secondary(unsigned int cpu,
@@ -63,21 +38,10 @@ static int __cpuinit mvebu_cortex_a9_boot_secondary(unsigned int cpu,
63 * address. 38 * address.
64 */ 39 */
65 hw_cpu = cpu_logical_map(cpu); 40 hw_cpu = cpu_logical_map(cpu);
66 41 if (of_machine_is_compatible("marvell,armada375"))
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); 42 mvebu_system_controller_set_cpu_boot_addr(mvebu_cortex_a9_secondary_startup);
75 } 43 else
76 else { 44 mvebu_pmsu_set_cpu_boot_addr(hw_cpu, mvebu_cortex_a9_secondary_startup);
77 mvebu_pmsu_set_cpu_boot_addr(hw_cpu,
78 mvebu_cortex_a9_secondary_startup);
79 }
80
81 smp_wmb(); 45 smp_wmb();
82 ret = mvebu_cpu_reset_deassert(hw_cpu); 46 ret = mvebu_cpu_reset_deassert(hw_cpu);
83 if (ret) { 47 if (ret) {
@@ -91,9 +55,6 @@ static int __cpuinit mvebu_cortex_a9_boot_secondary(unsigned int cpu,
91 55
92static struct smp_operations mvebu_cortex_a9_smp_ops __initdata = { 56static struct smp_operations mvebu_cortex_a9_smp_ops __initdata = {
93 .smp_boot_secondary = mvebu_cortex_a9_boot_secondary, 57 .smp_boot_secondary = mvebu_cortex_a9_boot_secondary,
94#ifdef CONFIG_HOTPLUG_CPU
95 .cpu_die = armada_xp_cpu_die,
96#endif
97}; 58};
98 59
99CPU_METHOD_OF_DECLARE(mvebu_armada_375_smp, "marvell,armada-375-smp", 60CPU_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..895dc373c8a1 100644
--- a/arch/arm/mach-mvebu/platsmp.c
+++ b/arch/arm/mach-mvebu/platsmp.c
@@ -67,6 +67,7 @@ static void __init set_secondary_cpus_clock(void)
67 if (!cpu_clk) 67 if (!cpu_clk)
68 return; 68 return;
69 clk_set_rate(cpu_clk, rate); 69 clk_set_rate(cpu_clk, rate);
70 clk_prepare_enable(cpu_clk);
70 } 71 }
71} 72}
72 73
@@ -78,6 +79,17 @@ static int armada_xp_boot_secondary(unsigned int cpu, struct task_struct *idle)
78 79
79 hw_cpu = cpu_logical_map(cpu); 80 hw_cpu = cpu_logical_map(cpu);
80 mvebu_pmsu_set_cpu_boot_addr(hw_cpu, armada_xp_secondary_startup); 81 mvebu_pmsu_set_cpu_boot_addr(hw_cpu, armada_xp_secondary_startup);
82
83 /*
84 * This is needed to wake up CPUs in the offline state after
85 * using CPU hotplug.
86 */
87 arch_send_wakeup_ipi_mask(cpumask_of(cpu));
88
89 /*
90 * This is needed to take secondary CPUs out of reset on the
91 * initial boot.
92 */
81 ret = mvebu_cpu_reset_deassert(hw_cpu); 93 ret = mvebu_cpu_reset_deassert(hw_cpu);
82 if (ret) { 94 if (ret) {
83 pr_warn("unable to boot CPU: %d\n", ret); 95 pr_warn("unable to boot CPU: %d\n", ret);
@@ -87,6 +99,19 @@ static int armada_xp_boot_secondary(unsigned int cpu, struct task_struct *idle)
87 return 0; 99 return 0;
88} 100}
89 101
102/*
103 * When a CPU is brought back online, either through CPU hotplug, or
104 * because of the boot of a kexec'ed kernel, the PMSU configuration
105 * for this CPU might be in the deep idle state, preventing this CPU
106 * from receiving interrupts. Here, we therefore take out the current
107 * CPU from this state, which was entered by armada_xp_cpu_die()
108 * below.
109 */
110static void armada_xp_secondary_init(unsigned int cpu)
111{
112 mvebu_v7_pmsu_idle_exit();
113}
114
90static void __init armada_xp_smp_init_cpus(void) 115static void __init armada_xp_smp_init_cpus(void)
91{ 116{
92 unsigned int ncores = num_possible_cpus(); 117 unsigned int ncores = num_possible_cpus();
@@ -122,12 +147,36 @@ static void __init armada_xp_smp_prepare_cpus(unsigned int max_cpus)
122 panic("The address for the BootROM is incorrect"); 147 panic("The address for the BootROM is incorrect");
123} 148}
124 149
150#ifdef CONFIG_HOTPLUG_CPU
151static void armada_xp_cpu_die(unsigned int cpu)
152{
153 /*
154 * CPU hotplug is implemented by putting offline CPUs into the
155 * deep idle sleep state.
156 */
157 armada_370_xp_pmsu_idle_enter(true);
158}
159
160/*
161 * We need a dummy function, so that platform_can_cpu_hotplug() knows
162 * we support CPU hotplug. However, the function does not need to do
163 * anything, because CPUs going offline can enter the deep idle state
164 * by themselves, without any help from a still alive CPU.
165 */
166static int armada_xp_cpu_kill(unsigned int cpu)
167{
168 return 1;
169}
170#endif
171
125struct smp_operations armada_xp_smp_ops __initdata = { 172struct smp_operations armada_xp_smp_ops __initdata = {
126 .smp_init_cpus = armada_xp_smp_init_cpus, 173 .smp_init_cpus = armada_xp_smp_init_cpus,
127 .smp_prepare_cpus = armada_xp_smp_prepare_cpus, 174 .smp_prepare_cpus = armada_xp_smp_prepare_cpus,
128 .smp_boot_secondary = armada_xp_boot_secondary, 175 .smp_boot_secondary = armada_xp_boot_secondary,
176 .smp_secondary_init = armada_xp_secondary_init,
129#ifdef CONFIG_HOTPLUG_CPU 177#ifdef CONFIG_HOTPLUG_CPU
130 .cpu_die = armada_xp_cpu_die, 178 .cpu_die = armada_xp_cpu_die,
179 .cpu_kill = armada_xp_cpu_kill,
131#endif 180#endif
132}; 181};
133 182
diff --git a/arch/arm/mach-mvebu/pmsu.c b/arch/arm/mach-mvebu/pmsu.c
index 25aa8237d668..8a70a51533fd 100644
--- a/arch/arm/mach-mvebu/pmsu.c
+++ b/arch/arm/mach-mvebu/pmsu.c
@@ -18,22 +18,29 @@
18 18
19#define pr_fmt(fmt) "mvebu-pmsu: " fmt 19#define pr_fmt(fmt) "mvebu-pmsu: " fmt
20 20
21#include <linux/clk.h>
21#include <linux/cpu_pm.h> 22#include <linux/cpu_pm.h>
22#include <linux/kernel.h> 23#include <linux/delay.h>
23#include <linux/init.h> 24#include <linux/init.h>
24#include <linux/of_address.h>
25#include <linux/io.h> 25#include <linux/io.h>
26#include <linux/kernel.h>
27#include <linux/mbus.h>
28#include <linux/of_address.h>
29#include <linux/of_device.h>
26#include <linux/platform_device.h> 30#include <linux/platform_device.h>
27#include <linux/smp.h> 31#include <linux/pm_opp.h>
28#include <linux/resource.h> 32#include <linux/resource.h>
33#include <linux/slab.h>
34#include <linux/smp.h>
29#include <asm/cacheflush.h> 35#include <asm/cacheflush.h>
30#include <asm/cp15.h> 36#include <asm/cp15.h>
37#include <asm/smp_scu.h>
31#include <asm/smp_plat.h> 38#include <asm/smp_plat.h>
32#include <asm/suspend.h> 39#include <asm/suspend.h>
33#include <asm/tlbflush.h> 40#include <asm/tlbflush.h>
34#include "common.h" 41#include "common.h"
42#include "armada-370-xp.h"
35 43
36static void __iomem *pmsu_mp_base;
37 44
38#define PMSU_BASE_OFFSET 0x100 45#define PMSU_BASE_OFFSET 0x100
39#define PMSU_REG_SIZE 0x1000 46#define PMSU_REG_SIZE 0x1000
@@ -57,20 +64,45 @@ static void __iomem *pmsu_mp_base;
57#define PMSU_STATUS_AND_MASK_IRQ_MASK BIT(24) 64#define PMSU_STATUS_AND_MASK_IRQ_MASK BIT(24)
58#define PMSU_STATUS_AND_MASK_FIQ_MASK BIT(25) 65#define PMSU_STATUS_AND_MASK_FIQ_MASK BIT(25)
59 66
67#define PMSU_EVENT_STATUS_AND_MASK(cpu) ((cpu * 0x100) + 0x120)
68#define PMSU_EVENT_STATUS_AND_MASK_DFS_DONE BIT(1)
69#define PMSU_EVENT_STATUS_AND_MASK_DFS_DONE_MASK BIT(17)
70
60#define PMSU_BOOT_ADDR_REDIRECT_OFFSET(cpu) ((cpu * 0x100) + 0x124) 71#define PMSU_BOOT_ADDR_REDIRECT_OFFSET(cpu) ((cpu * 0x100) + 0x124)
61 72
62/* PMSU fabric registers */ 73/* PMSU fabric registers */
63#define L2C_NFABRIC_PM_CTL 0x4 74#define L2C_NFABRIC_PM_CTL 0x4
64#define L2C_NFABRIC_PM_CTL_PWR_DOWN BIT(20) 75#define L2C_NFABRIC_PM_CTL_PWR_DOWN BIT(20)
65 76
77/* PMSU delay registers */
78#define PMSU_POWERDOWN_DELAY 0xF04
79#define PMSU_POWERDOWN_DELAY_PMU BIT(1)
80#define PMSU_POWERDOWN_DELAY_MASK 0xFFFE
81#define PMSU_DFLT_ARMADA38X_DELAY 0x64
82
83/* CA9 MPcore SoC Control registers */
84
85#define MPCORE_RESET_CTL 0x64
86#define MPCORE_RESET_CTL_L2 BIT(0)
87#define MPCORE_RESET_CTL_DEBUG BIT(16)
88
89#define SRAM_PHYS_BASE 0xFFFF0000
90#define BOOTROM_BASE 0xFFF00000
91#define BOOTROM_SIZE 0x100000
92
93#define ARMADA_370_CRYPT0_ENG_TARGET 0x9
94#define ARMADA_370_CRYPT0_ENG_ATTR 0x1
95
66extern void ll_disable_coherency(void); 96extern void ll_disable_coherency(void);
67extern void ll_enable_coherency(void); 97extern void ll_enable_coherency(void);
68 98
69extern void armada_370_xp_cpu_resume(void); 99extern void armada_370_xp_cpu_resume(void);
100extern void armada_38x_cpu_resume(void);
70 101
71static struct platform_device armada_xp_cpuidle_device = { 102static phys_addr_t pmsu_mp_phys_base;
72 .name = "cpuidle-armada-370-xp", 103static void __iomem *pmsu_mp_base;
73}; 104
105static void *mvebu_cpu_resume;
74 106
75static struct of_device_id of_pmsu_table[] = { 107static struct of_device_id of_pmsu_table[] = {
76 { .compatible = "marvell,armada-370-pmsu", }, 108 { .compatible = "marvell,armada-370-pmsu", },
@@ -85,7 +117,49 @@ void mvebu_pmsu_set_cpu_boot_addr(int hw_cpu, void *boot_addr)
85 PMSU_BOOT_ADDR_REDIRECT_OFFSET(hw_cpu)); 117 PMSU_BOOT_ADDR_REDIRECT_OFFSET(hw_cpu));
86} 118}
87 119
88static int __init armada_370_xp_pmsu_init(void) 120extern unsigned char mvebu_boot_wa_start;
121extern unsigned char mvebu_boot_wa_end;
122
123/*
124 * This function sets up the boot address workaround needed for SMP
125 * boot on Armada 375 Z1 and cpuidle on Armada 370. It unmaps the
126 * BootROM Mbus window, and instead remaps a crypto SRAM into which a
127 * custom piece of code is copied to replace the problematic BootROM.
128 */
129int mvebu_setup_boot_addr_wa(unsigned int crypto_eng_target,
130 unsigned int crypto_eng_attribute,
131 phys_addr_t resume_addr_reg)
132{
133 void __iomem *sram_virt_base;
134 u32 code_len = &mvebu_boot_wa_end - &mvebu_boot_wa_start;
135
136 mvebu_mbus_del_window(BOOTROM_BASE, BOOTROM_SIZE);
137 mvebu_mbus_add_window_by_id(crypto_eng_target, crypto_eng_attribute,
138 SRAM_PHYS_BASE, SZ_64K);
139
140 sram_virt_base = ioremap(SRAM_PHYS_BASE, SZ_64K);
141 if (!sram_virt_base) {
142 pr_err("Unable to map SRAM to setup the boot address WA\n");
143 return -ENOMEM;
144 }
145
146 memcpy(sram_virt_base, &mvebu_boot_wa_start, code_len);
147
148 /*
149 * The last word of the code copied in SRAM must contain the
150 * physical base address of the PMSU register. We
151 * intentionally store this address in the native endianness
152 * of the system.
153 */
154 __raw_writel((unsigned long)resume_addr_reg,
155 sram_virt_base + code_len - 4);
156
157 iounmap(sram_virt_base);
158
159 return 0;
160}
161
162static int __init mvebu_v7_pmsu_init(void)
89{ 163{
90 struct device_node *np; 164 struct device_node *np;
91 struct resource res; 165 struct resource res;
@@ -116,6 +190,8 @@ static int __init armada_370_xp_pmsu_init(void)
116 goto out; 190 goto out;
117 } 191 }
118 192
193 pmsu_mp_phys_base = res.start;
194
119 pmsu_mp_base = ioremap(res.start, resource_size(&res)); 195 pmsu_mp_base = ioremap(res.start, resource_size(&res));
120 if (!pmsu_mp_base) { 196 if (!pmsu_mp_base) {
121 pr_err("unable to map registers\n"); 197 pr_err("unable to map registers\n");
@@ -129,7 +205,7 @@ static int __init armada_370_xp_pmsu_init(void)
129 return ret; 205 return ret;
130} 206}
131 207
132static void armada_370_xp_pmsu_enable_l2_powerdown_onidle(void) 208static void mvebu_v7_pmsu_enable_l2_powerdown_onidle(void)
133{ 209{
134 u32 reg; 210 u32 reg;
135 211
@@ -142,14 +218,20 @@ static void armada_370_xp_pmsu_enable_l2_powerdown_onidle(void)
142 writel(reg, pmsu_mp_base + L2C_NFABRIC_PM_CTL); 218 writel(reg, pmsu_mp_base + L2C_NFABRIC_PM_CTL);
143} 219}
144 220
221enum pmsu_idle_prepare_flags {
222 PMSU_PREPARE_NORMAL = 0,
223 PMSU_PREPARE_DEEP_IDLE = BIT(0),
224 PMSU_PREPARE_SNOOP_DISABLE = BIT(1),
225};
226
145/* No locking is needed because we only access per-CPU registers */ 227/* No locking is needed because we only access per-CPU registers */
146void armada_370_xp_pmsu_idle_prepare(bool deepidle) 228static int mvebu_v7_pmsu_idle_prepare(unsigned long flags)
147{ 229{
148 unsigned int hw_cpu = cpu_logical_map(smp_processor_id()); 230 unsigned int hw_cpu = cpu_logical_map(smp_processor_id());
149 u32 reg; 231 u32 reg;
150 232
151 if (pmsu_mp_base == NULL) 233 if (pmsu_mp_base == NULL)
152 return; 234 return -EINVAL;
153 235
154 /* 236 /*
155 * Adjust the PMSU configuration to wait for WFI signal, enable 237 * Adjust the PMSU configuration to wait for WFI signal, enable
@@ -167,22 +249,34 @@ void armada_370_xp_pmsu_idle_prepare(bool deepidle)
167 249
168 reg = readl(pmsu_mp_base + PMSU_CONTROL_AND_CONFIG(hw_cpu)); 250 reg = readl(pmsu_mp_base + PMSU_CONTROL_AND_CONFIG(hw_cpu));
169 /* ask HW to power down the L2 Cache if needed */ 251 /* ask HW to power down the L2 Cache if needed */
170 if (deepidle) 252 if (flags & PMSU_PREPARE_DEEP_IDLE)
171 reg |= PMSU_CONTROL_AND_CONFIG_L2_PWDDN; 253 reg |= PMSU_CONTROL_AND_CONFIG_L2_PWDDN;
172 254
173 /* request power down */ 255 /* request power down */
174 reg |= PMSU_CONTROL_AND_CONFIG_PWDDN_REQ; 256 reg |= PMSU_CONTROL_AND_CONFIG_PWDDN_REQ;
175 writel(reg, pmsu_mp_base + PMSU_CONTROL_AND_CONFIG(hw_cpu)); 257 writel(reg, pmsu_mp_base + PMSU_CONTROL_AND_CONFIG(hw_cpu));
176 258
177 /* Disable snoop disable by HW - SW is taking care of it */ 259 if (flags & PMSU_PREPARE_SNOOP_DISABLE) {
178 reg = readl(pmsu_mp_base + PMSU_CPU_POWER_DOWN_CONTROL(hw_cpu)); 260 /* Disable snoop disable by HW - SW is taking care of it */
179 reg |= PMSU_CPU_POWER_DOWN_DIS_SNP_Q_SKIP; 261 reg = readl(pmsu_mp_base + PMSU_CPU_POWER_DOWN_CONTROL(hw_cpu));
180 writel(reg, pmsu_mp_base + PMSU_CPU_POWER_DOWN_CONTROL(hw_cpu)); 262 reg |= PMSU_CPU_POWER_DOWN_DIS_SNP_Q_SKIP;
263 writel(reg, pmsu_mp_base + PMSU_CPU_POWER_DOWN_CONTROL(hw_cpu));
264 }
265
266 return 0;
181} 267}
182 268
183static noinline int do_armada_370_xp_cpu_suspend(unsigned long deepidle) 269int armada_370_xp_pmsu_idle_enter(unsigned long deepidle)
184{ 270{
185 armada_370_xp_pmsu_idle_prepare(deepidle); 271 unsigned long flags = PMSU_PREPARE_SNOOP_DISABLE;
272 int ret;
273
274 if (deepidle)
275 flags |= PMSU_PREPARE_DEEP_IDLE;
276
277 ret = mvebu_v7_pmsu_idle_prepare(flags);
278 if (ret)
279 return ret;
186 280
187 v7_exit_coherency_flush(all); 281 v7_exit_coherency_flush(all);
188 282
@@ -208,25 +302,50 @@ static noinline int do_armada_370_xp_cpu_suspend(unsigned long deepidle)
208 "isb " 302 "isb "
209 : : : "r0"); 303 : : : "r0");
210 304
211 pr_warn("Failed to suspend the system\n"); 305 pr_debug("Failed to suspend the system\n");
212 306
213 return 0; 307 return 0;
214} 308}
215 309
216static int armada_370_xp_cpu_suspend(unsigned long deepidle) 310static int armada_370_xp_cpu_suspend(unsigned long deepidle)
217{ 311{
218 return cpu_suspend(deepidle, do_armada_370_xp_cpu_suspend); 312 return cpu_suspend(deepidle, armada_370_xp_pmsu_idle_enter);
313}
314
315static int armada_38x_do_cpu_suspend(unsigned long deepidle)
316{
317 unsigned long flags = 0;
318
319 if (deepidle)
320 flags |= PMSU_PREPARE_DEEP_IDLE;
321
322 mvebu_v7_pmsu_idle_prepare(flags);
323 /*
324 * Already flushed cache, but do it again as the outer cache
325 * functions dirty the cache with spinlocks
326 */
327 v7_exit_coherency_flush(louis);
328
329 scu_power_mode(mvebu_get_scu_base(), SCU_PM_POWEROFF);
330
331 cpu_do_idle();
332
333 return 1;
334}
335
336static int armada_38x_cpu_suspend(unsigned long deepidle)
337{
338 return cpu_suspend(false, armada_38x_do_cpu_suspend);
219} 339}
220 340
221/* No locking is needed because we only access per-CPU registers */ 341/* No locking is needed because we only access per-CPU registers */
222static noinline void armada_370_xp_pmsu_idle_restore(void) 342void mvebu_v7_pmsu_idle_exit(void)
223{ 343{
224 unsigned int hw_cpu = cpu_logical_map(smp_processor_id()); 344 unsigned int hw_cpu = cpu_logical_map(smp_processor_id());
225 u32 reg; 345 u32 reg;
226 346
227 if (pmsu_mp_base == NULL) 347 if (pmsu_mp_base == NULL)
228 return; 348 return;
229
230 /* cancel ask HW to power down the L2 Cache if possible */ 349 /* cancel ask HW to power down the L2 Cache if possible */
231 reg = readl(pmsu_mp_base + PMSU_CONTROL_AND_CONFIG(hw_cpu)); 350 reg = readl(pmsu_mp_base + PMSU_CONTROL_AND_CONFIG(hw_cpu));
232 reg &= ~PMSU_CONTROL_AND_CONFIG_L2_PWDDN; 351 reg &= ~PMSU_CONTROL_AND_CONFIG_L2_PWDDN;
@@ -241,53 +360,292 @@ static noinline void armada_370_xp_pmsu_idle_restore(void)
241 writel(reg, pmsu_mp_base + PMSU_STATUS_AND_MASK(hw_cpu)); 360 writel(reg, pmsu_mp_base + PMSU_STATUS_AND_MASK(hw_cpu));
242} 361}
243 362
244static int armada_370_xp_cpu_pm_notify(struct notifier_block *self, 363static int mvebu_v7_cpu_pm_notify(struct notifier_block *self,
245 unsigned long action, void *hcpu) 364 unsigned long action, void *hcpu)
246{ 365{
247 if (action == CPU_PM_ENTER) { 366 if (action == CPU_PM_ENTER) {
248 unsigned int hw_cpu = cpu_logical_map(smp_processor_id()); 367 unsigned int hw_cpu = cpu_logical_map(smp_processor_id());
249 mvebu_pmsu_set_cpu_boot_addr(hw_cpu, armada_370_xp_cpu_resume); 368 mvebu_pmsu_set_cpu_boot_addr(hw_cpu, mvebu_cpu_resume);
250 } else if (action == CPU_PM_EXIT) { 369 } else if (action == CPU_PM_EXIT) {
251 armada_370_xp_pmsu_idle_restore(); 370 mvebu_v7_pmsu_idle_exit();
252 } 371 }
253 372
254 return NOTIFY_OK; 373 return NOTIFY_OK;
255} 374}
256 375
257static struct notifier_block armada_370_xp_cpu_pm_notifier = { 376static struct notifier_block mvebu_v7_cpu_pm_notifier = {
258 .notifier_call = armada_370_xp_cpu_pm_notify, 377 .notifier_call = mvebu_v7_cpu_pm_notify,
259}; 378};
260 379
261int __init armada_370_xp_cpu_pm_init(void) 380static struct platform_device mvebu_v7_cpuidle_device;
381
382static __init int armada_370_cpuidle_init(void)
262{ 383{
263 struct device_node *np; 384 struct device_node *np;
385 phys_addr_t redirect_reg;
386
387 np = of_find_compatible_node(NULL, NULL, "marvell,coherency-fabric");
388 if (!np)
389 return -ENODEV;
390 of_node_put(np);
264 391
265 /* 392 /*
266 * Check that all the requirements are available to enable 393 * On Armada 370, there is "a slow exit process from the deep
267 * cpuidle. So far, it is only supported on Armada XP, cpuidle 394 * idle state due to heavy L1/L2 cache cleanup operations
268 * needs the coherency fabric and the PMSU enabled 395 * performed by the BootROM software". To avoid this, we
396 * replace the restart code of the bootrom by a a simple jump
397 * to the boot address. Then the code located at this boot
398 * address will take care of the initialization.
269 */ 399 */
400 redirect_reg = pmsu_mp_phys_base + PMSU_BOOT_ADDR_REDIRECT_OFFSET(0);
401 mvebu_setup_boot_addr_wa(ARMADA_370_CRYPT0_ENG_TARGET,
402 ARMADA_370_CRYPT0_ENG_ATTR,
403 redirect_reg);
270 404
271 if (!of_machine_is_compatible("marvell,armadaxp")) 405 mvebu_cpu_resume = armada_370_xp_cpu_resume;
272 return 0; 406 mvebu_v7_cpuidle_device.dev.platform_data = armada_370_xp_cpu_suspend;
407 mvebu_v7_cpuidle_device.name = "cpuidle-armada-370";
408
409 return 0;
410}
411
412static __init int armada_38x_cpuidle_init(void)
413{
414 struct device_node *np;
415 void __iomem *mpsoc_base;
416 u32 reg;
417
418 np = of_find_compatible_node(NULL, NULL,
419 "marvell,armada-380-coherency-fabric");
420 if (!np)
421 return -ENODEV;
422 of_node_put(np);
423
424 np = of_find_compatible_node(NULL, NULL,
425 "marvell,armada-380-mpcore-soc-ctrl");
426 if (!np)
427 return -ENODEV;
428 mpsoc_base = of_iomap(np, 0);
429 BUG_ON(!mpsoc_base);
430 of_node_put(np);
431
432 /* Set up reset mask when powering down the cpus */
433 reg = readl(mpsoc_base + MPCORE_RESET_CTL);
434 reg |= MPCORE_RESET_CTL_L2;
435 reg |= MPCORE_RESET_CTL_DEBUG;
436 writel(reg, mpsoc_base + MPCORE_RESET_CTL);
437 iounmap(mpsoc_base);
438
439 /* Set up delay */
440 reg = readl(pmsu_mp_base + PMSU_POWERDOWN_DELAY);
441 reg &= ~PMSU_POWERDOWN_DELAY_MASK;
442 reg |= PMSU_DFLT_ARMADA38X_DELAY;
443 reg |= PMSU_POWERDOWN_DELAY_PMU;
444 writel(reg, pmsu_mp_base + PMSU_POWERDOWN_DELAY);
445
446 mvebu_cpu_resume = armada_38x_cpu_resume;
447 mvebu_v7_cpuidle_device.dev.platform_data = armada_38x_cpu_suspend;
448 mvebu_v7_cpuidle_device.name = "cpuidle-armada-38x";
449
450 return 0;
451}
452
453static __init int armada_xp_cpuidle_init(void)
454{
455 struct device_node *np;
273 456
274 np = of_find_compatible_node(NULL, NULL, "marvell,coherency-fabric"); 457 np = of_find_compatible_node(NULL, NULL, "marvell,coherency-fabric");
275 if (!np) 458 if (!np)
276 return 0; 459 return -ENODEV;
277 of_node_put(np); 460 of_node_put(np);
278 461
462 mvebu_cpu_resume = armada_370_xp_cpu_resume;
463 mvebu_v7_cpuidle_device.dev.platform_data = armada_370_xp_cpu_suspend;
464 mvebu_v7_cpuidle_device.name = "cpuidle-armada-xp";
465
466 return 0;
467}
468
469static int __init mvebu_v7_cpu_pm_init(void)
470{
471 struct device_node *np;
472 int ret;
473
279 np = of_find_matching_node(NULL, of_pmsu_table); 474 np = of_find_matching_node(NULL, of_pmsu_table);
280 if (!np) 475 if (!np)
281 return 0; 476 return 0;
282 of_node_put(np); 477 of_node_put(np);
283 478
284 armada_370_xp_pmsu_enable_l2_powerdown_onidle(); 479 if (of_machine_is_compatible("marvell,armadaxp"))
285 armada_xp_cpuidle_device.dev.platform_data = armada_370_xp_cpu_suspend; 480 ret = armada_xp_cpuidle_init();
286 platform_device_register(&armada_xp_cpuidle_device); 481 else if (of_machine_is_compatible("marvell,armada370"))
287 cpu_pm_register_notifier(&armada_370_xp_cpu_pm_notifier); 482 ret = armada_370_cpuidle_init();
483 else if (of_machine_is_compatible("marvell,armada380"))
484 ret = armada_38x_cpuidle_init();
485 else
486 return 0;
487
488 if (ret)
489 return ret;
490
491 mvebu_v7_pmsu_enable_l2_powerdown_onidle();
492 platform_device_register(&mvebu_v7_cpuidle_device);
493 cpu_pm_register_notifier(&mvebu_v7_cpu_pm_notifier);
494
495 return 0;
496}
497
498arch_initcall(mvebu_v7_cpu_pm_init);
499early_initcall(mvebu_v7_pmsu_init);
500
501static void mvebu_pmsu_dfs_request_local(void *data)
502{
503 u32 reg;
504 u32 cpu = smp_processor_id();
505 unsigned long flags;
506
507 local_irq_save(flags);
508
509 /* Prepare to enter idle */
510 reg = readl(pmsu_mp_base + PMSU_STATUS_AND_MASK(cpu));
511 reg |= PMSU_STATUS_AND_MASK_CPU_IDLE_WAIT |
512 PMSU_STATUS_AND_MASK_IRQ_MASK |
513 PMSU_STATUS_AND_MASK_FIQ_MASK;
514 writel(reg, pmsu_mp_base + PMSU_STATUS_AND_MASK(cpu));
515
516 /* Request the DFS transition */
517 reg = readl(pmsu_mp_base + PMSU_CONTROL_AND_CONFIG(cpu));
518 reg |= PMSU_CONTROL_AND_CONFIG_DFS_REQ;
519 writel(reg, pmsu_mp_base + PMSU_CONTROL_AND_CONFIG(cpu));
520
521 /* The fact of entering idle will trigger the DFS transition */
522 wfi();
523
524 /*
525 * We're back from idle, the DFS transition has completed,
526 * clear the idle wait indication.
527 */
528 reg = readl(pmsu_mp_base + PMSU_STATUS_AND_MASK(cpu));
529 reg &= ~PMSU_STATUS_AND_MASK_CPU_IDLE_WAIT;
530 writel(reg, pmsu_mp_base + PMSU_STATUS_AND_MASK(cpu));
531
532 local_irq_restore(flags);
533}
534
535int mvebu_pmsu_dfs_request(int cpu)
536{
537 unsigned long timeout;
538 int hwcpu = cpu_logical_map(cpu);
539 u32 reg;
540
541 /* Clear any previous DFS DONE event */
542 reg = readl(pmsu_mp_base + PMSU_EVENT_STATUS_AND_MASK(hwcpu));
543 reg &= ~PMSU_EVENT_STATUS_AND_MASK_DFS_DONE;
544 writel(reg, pmsu_mp_base + PMSU_EVENT_STATUS_AND_MASK(hwcpu));
545
546 /* Mask the DFS done interrupt, since we are going to poll */
547 reg = readl(pmsu_mp_base + PMSU_EVENT_STATUS_AND_MASK(hwcpu));
548 reg |= PMSU_EVENT_STATUS_AND_MASK_DFS_DONE_MASK;
549 writel(reg, pmsu_mp_base + PMSU_EVENT_STATUS_AND_MASK(hwcpu));
550
551 /* Trigger the DFS on the appropriate CPU */
552 smp_call_function_single(cpu, mvebu_pmsu_dfs_request_local,
553 NULL, false);
554
555 /* Poll until the DFS done event is generated */
556 timeout = jiffies + HZ;
557 while (time_before(jiffies, timeout)) {
558 reg = readl(pmsu_mp_base + PMSU_EVENT_STATUS_AND_MASK(hwcpu));
559 if (reg & PMSU_EVENT_STATUS_AND_MASK_DFS_DONE)
560 break;
561 udelay(10);
562 }
563
564 if (time_after(jiffies, timeout))
565 return -ETIME;
566
567 /* Restore the DFS mask to its original state */
568 reg = readl(pmsu_mp_base + PMSU_EVENT_STATUS_AND_MASK(hwcpu));
569 reg &= ~PMSU_EVENT_STATUS_AND_MASK_DFS_DONE_MASK;
570 writel(reg, pmsu_mp_base + PMSU_EVENT_STATUS_AND_MASK(hwcpu));
571
572 return 0;
573}
574
575static int __init armada_xp_pmsu_cpufreq_init(void)
576{
577 struct device_node *np;
578 struct resource res;
579 int ret, cpu;
580
581 if (!of_machine_is_compatible("marvell,armadaxp"))
582 return 0;
583
584 /*
585 * In order to have proper cpufreq handling, we need to ensure
586 * that the Device Tree description of the CPU clock includes
587 * the definition of the PMU DFS registers. If not, we do not
588 * register the clock notifier and the cpufreq driver. This
589 * piece of code is only for compatibility with old Device
590 * Trees.
591 */
592 np = of_find_compatible_node(NULL, NULL, "marvell,armada-xp-cpu-clock");
593 if (!np)
594 return 0;
595
596 ret = of_address_to_resource(np, 1, &res);
597 if (ret) {
598 pr_warn(FW_WARN "not enabling cpufreq, deprecated armada-xp-cpu-clock binding\n");
599 of_node_put(np);
600 return 0;
601 }
602
603 of_node_put(np);
604
605 /*
606 * For each CPU, this loop registers the operating points
607 * supported (which are the nominal CPU frequency and half of
608 * it), and registers the clock notifier that will take care
609 * of doing the PMSU part of a frequency transition.
610 */
611 for_each_possible_cpu(cpu) {
612 struct device *cpu_dev;
613 struct clk *clk;
614 int ret;
615
616 cpu_dev = get_cpu_device(cpu);
617 if (!cpu_dev) {
618 pr_err("Cannot get CPU %d\n", cpu);
619 continue;
620 }
621
622 clk = clk_get(cpu_dev, 0);
623 if (IS_ERR(clk)) {
624 pr_err("Cannot get clock for CPU %d\n", cpu);
625 return PTR_ERR(clk);
626 }
627
628 /*
629 * In case of a failure of dev_pm_opp_add(), we don't
630 * bother with cleaning up the registered OPP (there's
631 * no function to do so), and simply cancel the
632 * registration of the cpufreq device.
633 */
634 ret = dev_pm_opp_add(cpu_dev, clk_get_rate(clk), 0);
635 if (ret) {
636 clk_put(clk);
637 return ret;
638 }
639
640 ret = dev_pm_opp_add(cpu_dev, clk_get_rate(clk) / 2, 0);
641 if (ret) {
642 clk_put(clk);
643 return ret;
644 }
645 }
288 646
647 platform_device_register_simple("cpufreq-generic", -1, NULL, 0);
289 return 0; 648 return 0;
290} 649}
291 650
292arch_initcall(armada_370_xp_cpu_pm_init); 651device_initcall(armada_xp_pmsu_cpufreq_init);
293early_initcall(armada_370_xp_pmsu_init);
diff --git a/arch/arm/mach-mvebu/pmsu.h b/arch/arm/mach-mvebu/pmsu.h
index 07a737c6b95d..6b58c1fe2b0d 100644
--- a/arch/arm/mach-mvebu/pmsu.h
+++ b/arch/arm/mach-mvebu/pmsu.h
@@ -12,5 +12,10 @@
12#define __MACH_MVEBU_PMSU_H 12#define __MACH_MVEBU_PMSU_H
13 13
14int armada_xp_boot_cpu(unsigned int cpu_id, void *phys_addr); 14int armada_xp_boot_cpu(unsigned int cpu_id, void *phys_addr);
15int mvebu_setup_boot_addr_wa(unsigned int crypto_eng_target,
16 unsigned int crypto_eng_attribute,
17 phys_addr_t resume_addr_reg);
18
19void mvebu_v7_pmsu_idle_exit(void);
15 20
16#endif /* __MACH_370_XP_PMSU_H */ 21#endif /* __MACH_370_XP_PMSU_H */
diff --git a/arch/arm/mach-mvebu/pmsu_ll.S b/arch/arm/mach-mvebu/pmsu_ll.S
index fc3de68d8c54..a945756cfb45 100644
--- a/arch/arm/mach-mvebu/pmsu_ll.S
+++ b/arch/arm/mach-mvebu/pmsu_ll.S
@@ -23,3 +23,39 @@ ARM_BE8(setend be ) @ go BE8 if entered LE
23 b cpu_resume 23 b cpu_resume
24ENDPROC(armada_370_xp_cpu_resume) 24ENDPROC(armada_370_xp_cpu_resume)
25 25
26ENTRY(armada_38x_cpu_resume)
27 /* do we need it for Armada 38x*/
28ARM_BE8(setend be ) @ go BE8 if entered LE
29 bl v7_invalidate_l1
30 mrc p15, 4, r1, c15, c0 @ get SCU base address
31 orr r1, r1, #0x8 @ SCU CPU Power Status Register
32 mrc 15, 0, r0, cr0, cr0, 5 @ get the CPU ID
33 and r0, r0, #15
34 add r1, r1, r0
35 mov r0, #0x0
36 strb r0, [r1] @ switch SCU power state to Normal mode
37 b cpu_resume
38ENDPROC(armada_38x_cpu_resume)
39
40.global mvebu_boot_wa_start
41.global mvebu_boot_wa_end
42
43/* The following code will be executed from SRAM */
44ENTRY(mvebu_boot_wa_start)
45mvebu_boot_wa_start:
46ARM_BE8(setend be)
47 adr r0, 1f
48 ldr r0, [r0] @ load the address of the
49 @ resume register
50 ldr r0, [r0] @ load the value in the
51 @ resume register
52ARM_BE8(rev r0, r0) @ the value is stored LE
53 mov pc, r0 @ jump to this value
54/*
55 * the last word of this piece of code will be filled by the physical
56 * address of the boot address register just after being copied in SRAM
57 */
581:
59 .long .
60mvebu_boot_wa_end:
61ENDPROC(mvebu_boot_wa_end)
diff --git a/arch/arm/mach-mvebu/system-controller.c b/arch/arm/mach-mvebu/system-controller.c
index 0c5524ac75b7..a068cb5c2ce8 100644
--- a/arch/arm/mach-mvebu/system-controller.c
+++ b/arch/arm/mach-mvebu/system-controller.c
@@ -28,8 +28,14 @@
28#include <linux/io.h> 28#include <linux/io.h>
29#include <linux/reboot.h> 29#include <linux/reboot.h>
30#include "common.h" 30#include "common.h"
31#include "mvebu-soc-id.h"
32#include "pmsu.h"
33
34#define ARMADA_375_CRYPT0_ENG_TARGET 41
35#define ARMADA_375_CRYPT0_ENG_ATTR 1
31 36
32static void __iomem *system_controller_base; 37static void __iomem *system_controller_base;
38static phys_addr_t system_controller_phys_base;
33 39
34struct mvebu_system_controller { 40struct mvebu_system_controller {
35 u32 rstoutn_mask_offset; 41 u32 rstoutn_mask_offset;
@@ -39,6 +45,9 @@ struct mvebu_system_controller {
39 u32 system_soft_reset; 45 u32 system_soft_reset;
40 46
41 u32 resume_boot_addr; 47 u32 resume_boot_addr;
48
49 u32 dev_id;
50 u32 rev_id;
42}; 51};
43static struct mvebu_system_controller *mvebu_sc; 52static struct mvebu_system_controller *mvebu_sc;
44 53
@@ -47,6 +56,8 @@ static const struct mvebu_system_controller armada_370_xp_system_controller = {
47 .system_soft_reset_offset = 0x64, 56 .system_soft_reset_offset = 0x64,
48 .rstoutn_mask_reset_out_en = 0x1, 57 .rstoutn_mask_reset_out_en = 0x1,
49 .system_soft_reset = 0x1, 58 .system_soft_reset = 0x1,
59 .dev_id = 0x38,
60 .rev_id = 0x3c,
50}; 61};
51 62
52static const struct mvebu_system_controller armada_375_system_controller = { 63static const struct mvebu_system_controller armada_375_system_controller = {
@@ -55,6 +66,8 @@ static const struct mvebu_system_controller armada_375_system_controller = {
55 .rstoutn_mask_reset_out_en = 0x1, 66 .rstoutn_mask_reset_out_en = 0x1,
56 .system_soft_reset = 0x1, 67 .system_soft_reset = 0x1,
57 .resume_boot_addr = 0xd4, 68 .resume_boot_addr = 0xd4,
69 .dev_id = 0x38,
70 .rev_id = 0x3c,
58}; 71};
59 72
60static const struct mvebu_system_controller orion_system_controller = { 73static const struct mvebu_system_controller orion_system_controller = {
@@ -101,11 +114,45 @@ void mvebu_restart(enum reboot_mode mode, const char *cmd)
101 ; 114 ;
102} 115}
103 116
117int mvebu_system_controller_get_soc_id(u32 *dev, u32 *rev)
118{
119 if (of_machine_is_compatible("marvell,armada380") &&
120 system_controller_base) {
121 *dev = readl(system_controller_base + mvebu_sc->dev_id) >> 16;
122 *rev = (readl(system_controller_base + mvebu_sc->rev_id) >> 8)
123 & 0xF;
124 return 0;
125 } else
126 return -ENODEV;
127}
128
104#ifdef CONFIG_SMP 129#ifdef CONFIG_SMP
130void mvebu_armada375_smp_wa_init(void)
131{
132 u32 dev, rev;
133 phys_addr_t resume_addr_reg;
134
135 if (mvebu_get_soc_id(&dev, &rev) != 0)
136 return;
137
138 if (rev != ARMADA_375_Z1_REV)
139 return;
140
141 resume_addr_reg = system_controller_phys_base +
142 mvebu_sc->resume_boot_addr;
143 mvebu_setup_boot_addr_wa(ARMADA_375_CRYPT0_ENG_TARGET,
144 ARMADA_375_CRYPT0_ENG_ATTR,
145 resume_addr_reg);
146}
147
105void mvebu_system_controller_set_cpu_boot_addr(void *boot_addr) 148void mvebu_system_controller_set_cpu_boot_addr(void *boot_addr)
106{ 149{
107 BUG_ON(system_controller_base == NULL); 150 BUG_ON(system_controller_base == NULL);
108 BUG_ON(mvebu_sc->resume_boot_addr == 0); 151 BUG_ON(mvebu_sc->resume_boot_addr == 0);
152
153 if (of_machine_is_compatible("marvell,armada375"))
154 mvebu_armada375_smp_wa_init();
155
109 writel(virt_to_phys(boot_addr), system_controller_base + 156 writel(virt_to_phys(boot_addr), system_controller_base +
110 mvebu_sc->resume_boot_addr); 157 mvebu_sc->resume_boot_addr);
111} 158}
@@ -119,7 +166,10 @@ static int __init mvebu_system_controller_init(void)
119 np = of_find_matching_node_and_match(NULL, of_system_controller_table, 166 np = of_find_matching_node_and_match(NULL, of_system_controller_table,
120 &match); 167 &match);
121 if (np) { 168 if (np) {
169 struct resource res;
122 system_controller_base = of_iomap(np, 0); 170 system_controller_base = of_iomap(np, 0);
171 of_address_to_resource(np, 0, &res);
172 system_controller_phys_base = res.start;
123 mvebu_sc = (struct mvebu_system_controller *)match->data; 173 mvebu_sc = (struct mvebu_system_controller *)match->data;
124 of_node_put(np); 174 of_node_put(np);
125 } 175 }