From adb1d99384c7480886153a97d2ea22e9c0d2e053 Mon Sep 17 00:00:00 2001 From: Thomas Petazzoni Date: Mon, 26 May 2014 17:01:14 +0200 Subject: ARM: mvebu: mark armada_370_xp_pmsu_idle_prepare() as static The armada_370_xp_pmsu_idle_prepare() function is only used internally to pmsu.c, so there's no reason to not use the static qualifier. Signed-off-by: Thomas Petazzoni Link: https://lkml.kernel.org/r/1401116474-31221-1-git-send-email-thomas.petazzoni@free-electrons.com Acked-by: Gregory CLEMENT Signed-off-by: Jason Cooper --- arch/arm/mach-mvebu/pmsu.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'arch/arm/mach-mvebu') diff --git a/arch/arm/mach-mvebu/pmsu.c b/arch/arm/mach-mvebu/pmsu.c index 53a55c8520bf..6e83d32071b1 100644 --- a/arch/arm/mach-mvebu/pmsu.c +++ b/arch/arm/mach-mvebu/pmsu.c @@ -148,7 +148,7 @@ static void armada_370_xp_cpu_resume(void) } /* No locking is needed because we only access per-CPU registers */ -void armada_370_xp_pmsu_idle_prepare(bool deepidle) +static void armada_370_xp_pmsu_idle_prepare(bool deepidle) { unsigned int hw_cpu = cpu_logical_map(smp_processor_id()); u32 reg; -- cgit v1.2.3 From 55fc83023212f940927b9a44e31ad93d7e67d27d Mon Sep 17 00:00:00 2001 From: Andrew Lunn Date: Mon, 26 May 2014 21:29:48 +0200 Subject: ARM: Kirkwood: Add setup file for netxbig LEDs There is currently no DT binding for the CPLD which controls the LEDs on the Net 2Big and Net 5Big. So use a platform device. Signed-off-by: Andrew Lunn Link: https://lkml.kernel.org/r/1401132591-26305-2-git-send-email-andrew@lunn.ch Tested-by: Simon Guinot Signed-off-by: Jason Cooper --- arch/arm/mach-mvebu/Kconfig | 7 ++ arch/arm/mach-mvebu/Makefile | 1 + arch/arm/mach-mvebu/board.h | 5 ++ arch/arm/mach-mvebu/kirkwood.c | 3 + arch/arm/mach-mvebu/netxbig.c | 191 +++++++++++++++++++++++++++++++++++++++++ 5 files changed, 207 insertions(+) create mode 100644 arch/arm/mach-mvebu/netxbig.c (limited to 'arch/arm/mach-mvebu') diff --git a/arch/arm/mach-mvebu/Kconfig b/arch/arm/mach-mvebu/Kconfig index 6090b9eb00c8..e5ab3a7cb3d2 100644 --- a/arch/arm/mach-mvebu/Kconfig +++ b/arch/arm/mach-mvebu/Kconfig @@ -97,6 +97,13 @@ config MACH_KIRKWOOD Say 'Y' here if you want your kernel to support boards based on the Marvell Kirkwood device tree. +config MACH_NETXBIG + bool "LaCie 2Big and 5Big Network v2" + depends on MACH_KIRKWOOD + help + Say 'Y' here if you want your kernel to support the + LaCie 2Big and 5Big Network v2 + endmenu endif diff --git a/arch/arm/mach-mvebu/Makefile b/arch/arm/mach-mvebu/Makefile index 2ecb828e4a8b..db29c1dfe3c5 100644 --- a/arch/arm/mach-mvebu/Makefile +++ b/arch/arm/mach-mvebu/Makefile @@ -14,3 +14,4 @@ endif obj-$(CONFIG_MACH_DOVE) += dove.o obj-$(CONFIG_MACH_KIRKWOOD) += kirkwood.o kirkwood-pm.o +obj-$(CONFIG_MACH_NETXBIG) += netxbig.o 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 @@ #ifndef __ARCH_MVEBU_BOARD_H #define __ARCH_MVEBU_BOARD_H +#ifdef CONFIG_MACH_NETXBIG +void netxbig_init(void); +#else +static inline void netxbig_init(void) {}; +#endif #endif 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) kirkwood_pm_init(); kirkwood_dt_eth_fixup(); + if (of_machine_is_compatible("lacie,netxbig")) + netxbig_init(); + of_platform_populate(NULL, of_default_bus_match_table, auxdata, NULL); } 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 @@ +/* + * arch/arm/mach-mvbu/board-netxbig.c + * + * LaCie 2Big and 5Big Network v2 board setup + * + * Copyright (C) 2010 Simon Guinot + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include +#include +#include +#include +#include "common.h" + +/***************************************************************************** + * GPIO extension LEDs + ****************************************************************************/ + +/* + * The LEDs are controlled by a CPLD and can be configured through a GPIO + * extension bus: + * + * - address register : bit [0-2] -> GPIO [47-49] + * - data register : bit [0-2] -> GPIO [44-46] + * - enable register : GPIO 29 + */ + +static int netxbig_v2_gpio_ext_addr[] = { 47, 48, 49 }; +static int netxbig_v2_gpio_ext_data[] = { 44, 45, 46 }; + +static struct netxbig_gpio_ext netxbig_v2_gpio_ext = { + .addr = netxbig_v2_gpio_ext_addr, + .num_addr = ARRAY_SIZE(netxbig_v2_gpio_ext_addr), + .data = netxbig_v2_gpio_ext_data, + .num_data = ARRAY_SIZE(netxbig_v2_gpio_ext_data), + .enable = 29, +}; + +/* + * Address register selection: + * + * addr | register + * ---------------------------- + * 0 | front LED + * 1 | front LED brightness + * 2 | SATA LED brightness + * 3 | SATA0 LED + * 4 | SATA1 LED + * 5 | SATA2 LED + * 6 | SATA3 LED + * 7 | SATA4 LED + * + * Data register configuration: + * + * data | LED brightness + * ------------------------------------------------- + * 0 | min (off) + * - | - + * 7 | max + * + * data | front LED mode + * ------------------------------------------------- + * 0 | fix off + * 1 | fix blue on + * 2 | fix red on + * 3 | blink blue on=1 sec and blue off=1 sec + * 4 | blink red on=1 sec and red off=1 sec + * 5 | blink blue on=2.5 sec and red on=0.5 sec + * 6 | blink blue on=1 sec and red on=1 sec + * 7 | blink blue on=0.5 sec and blue off=2.5 sec + * + * data | SATA LED mode + * ------------------------------------------------- + * 0 | fix off + * 1 | SATA activity blink + * 2 | fix red on + * 3 | blink blue on=1 sec and blue off=1 sec + * 4 | blink red on=1 sec and red off=1 sec + * 5 | blink blue on=2.5 sec and red on=0.5 sec + * 6 | blink blue on=1 sec and red on=1 sec + * 7 | fix blue on + */ + +static int netxbig_v2_red_mled[NETXBIG_LED_MODE_NUM] = { + [NETXBIG_LED_OFF] = 0, + [NETXBIG_LED_ON] = 2, + [NETXBIG_LED_SATA] = NETXBIG_LED_INVALID_MODE, + [NETXBIG_LED_TIMER1] = 4, + [NETXBIG_LED_TIMER2] = NETXBIG_LED_INVALID_MODE, +}; + +static int netxbig_v2_blue_pwr_mled[NETXBIG_LED_MODE_NUM] = { + [NETXBIG_LED_OFF] = 0, + [NETXBIG_LED_ON] = 1, + [NETXBIG_LED_SATA] = NETXBIG_LED_INVALID_MODE, + [NETXBIG_LED_TIMER1] = 3, + [NETXBIG_LED_TIMER2] = 7, +}; + +static int netxbig_v2_blue_sata_mled[NETXBIG_LED_MODE_NUM] = { + [NETXBIG_LED_OFF] = 0, + [NETXBIG_LED_ON] = 7, + [NETXBIG_LED_SATA] = 1, + [NETXBIG_LED_TIMER1] = 3, + [NETXBIG_LED_TIMER2] = NETXBIG_LED_INVALID_MODE, +}; + +static struct netxbig_led_timer netxbig_v2_led_timer[] = { + [0] = { + .delay_on = 500, + .delay_off = 500, + .mode = NETXBIG_LED_TIMER1, + }, + [1] = { + .delay_on = 500, + .delay_off = 1000, + .mode = NETXBIG_LED_TIMER2, + }, +}; + +#define NETXBIG_LED(_name, maddr, mval, baddr) \ + { .name = _name, \ + .mode_addr = maddr, \ + .mode_val = mval, \ + .bright_addr = baddr } + +static struct netxbig_led net2big_v2_leds_ctrl[] = { + NETXBIG_LED("net2big-v2:blue:power", 0, netxbig_v2_blue_pwr_mled, 1), + NETXBIG_LED("net2big-v2:red:power", 0, netxbig_v2_red_mled, 1), + NETXBIG_LED("net2big-v2:blue:sata0", 3, netxbig_v2_blue_sata_mled, 2), + NETXBIG_LED("net2big-v2:red:sata0", 3, netxbig_v2_red_mled, 2), + NETXBIG_LED("net2big-v2:blue:sata1", 4, netxbig_v2_blue_sata_mled, 2), + NETXBIG_LED("net2big-v2:red:sata1", 4, netxbig_v2_red_mled, 2), +}; + +static struct netxbig_led_platform_data net2big_v2_leds_data = { + .gpio_ext = &netxbig_v2_gpio_ext, + .timer = netxbig_v2_led_timer, + .num_timer = ARRAY_SIZE(netxbig_v2_led_timer), + .leds = net2big_v2_leds_ctrl, + .num_leds = ARRAY_SIZE(net2big_v2_leds_ctrl), +}; + +static struct netxbig_led net5big_v2_leds_ctrl[] = { + NETXBIG_LED("net5big-v2:blue:power", 0, netxbig_v2_blue_pwr_mled, 1), + NETXBIG_LED("net5big-v2:red:power", 0, netxbig_v2_red_mled, 1), + NETXBIG_LED("net5big-v2:blue:sata0", 3, netxbig_v2_blue_sata_mled, 2), + NETXBIG_LED("net5big-v2:red:sata0", 3, netxbig_v2_red_mled, 2), + NETXBIG_LED("net5big-v2:blue:sata1", 4, netxbig_v2_blue_sata_mled, 2), + NETXBIG_LED("net5big-v2:red:sata1", 4, netxbig_v2_red_mled, 2), + NETXBIG_LED("net5big-v2:blue:sata2", 5, netxbig_v2_blue_sata_mled, 2), + NETXBIG_LED("net5big-v2:red:sata2", 5, netxbig_v2_red_mled, 2), + NETXBIG_LED("net5big-v2:blue:sata3", 6, netxbig_v2_blue_sata_mled, 2), + NETXBIG_LED("net5big-v2:red:sata3", 6, netxbig_v2_red_mled, 2), + NETXBIG_LED("net5big-v2:blue:sata4", 7, netxbig_v2_blue_sata_mled, 2), + NETXBIG_LED("net5big-v2:red:sata4", 7, netxbig_v2_red_mled, 2), +}; + +static struct netxbig_led_platform_data net5big_v2_leds_data = { + .gpio_ext = &netxbig_v2_gpio_ext, + .timer = netxbig_v2_led_timer, + .num_timer = ARRAY_SIZE(netxbig_v2_led_timer), + .leds = net5big_v2_leds_ctrl, + .num_leds = ARRAY_SIZE(net5big_v2_leds_ctrl), +}; + +static struct platform_device netxbig_v2_leds = { + .name = "leds-netxbig", + .id = -1, + .dev = { + .platform_data = &net2big_v2_leds_data, + }, +}; + +void __init netxbig_init(void) +{ + + if (of_machine_is_compatible("lacie,net5big_v2")) + netxbig_v2_leds.dev.platform_data = &net5big_v2_leds_data; + platform_device_register(&netxbig_v2_leds); +} -- cgit v1.2.3 From 3169455448ea6d021b1b761b4fd241810de8c335 Mon Sep 17 00:00:00 2001 From: Thomas Petazzoni Date: Fri, 30 May 2014 22:18:14 +0200 Subject: ARM: mvebu: remove stub implementation of CPU hotplug on Armada 375/38x In preparation to the addition of CPU hotplug support for Armada XP, and therefore moving the existing stub functions for hotplug support, this commit removes the reference from the SMP implementation of Armada 375/38x to the armada_xp_cpu_die() function. Proper CPU hotplug support for Armada 375 and 38x will be implemented at a later point. Signed-off-by: Thomas Petazzoni Link: https://lkml.kernel.org/r/1401481098-23326-2-git-send-email-thomas.petazzoni@free-electrons.com Signed-off-by: Jason Cooper --- arch/arm/mach-mvebu/platsmp-a9.c | 3 --- 1 file changed, 3 deletions(-) (limited to 'arch/arm/mach-mvebu') diff --git a/arch/arm/mach-mvebu/platsmp-a9.c b/arch/arm/mach-mvebu/platsmp-a9.c index 96c2c59e34b6..65f532141a30 100644 --- a/arch/arm/mach-mvebu/platsmp-a9.c +++ b/arch/arm/mach-mvebu/platsmp-a9.c @@ -91,9 +91,6 @@ static int __cpuinit mvebu_cortex_a9_boot_secondary(unsigned int cpu, static struct smp_operations mvebu_cortex_a9_smp_ops __initdata = { .smp_boot_secondary = mvebu_cortex_a9_boot_secondary, -#ifdef CONFIG_HOTPLUG_CPU - .cpu_die = armada_xp_cpu_die, -#endif }; CPU_METHOD_OF_DECLARE(mvebu_armada_375_smp, "marvell,armada-375-smp", -- cgit v1.2.3 From bbb92284b6c821e9434223d437fbd10b8a24c294 Mon Sep 17 00:00:00 2001 From: Thomas Petazzoni Date: Fri, 30 May 2014 22:18:15 +0200 Subject: ARM: mvebu: slightly refactor/rename PMSU idle related functions The CPU hotplug code will need to call into PMSU functions to enter and exit from deep idle states. However, the deep idle state is currently entered by a function called do_armada_370_xp_cpu_suspend() whose name really suggests it's an internal function, but we need to export it to other files in mach-mvebu. Therefore, this commit: * Merges the code of do_armada_370_xp_cpu_suspend() into armada_370_xp_pmsu_idle_prepare(), into a single function called armada_370_xp_pmsu_idle_enter(), which prepares the PMSU for deep idle, and then enters the deep idle state. This code will be common to both cpuidle and CPU hotplug. * For symetry, it renames the armada_370_xp_pmsu_idle_restore() function to armada_370_xp_pmsu_idle_exit(). We also remove the 'noinline' qualifier for these functions, which apparently had no reason to be here. Signed-off-by: Thomas Petazzoni Link: https://lkml.kernel.org/r/1401481098-23326-3-git-send-email-thomas.petazzoni@free-electrons.com Signed-off-by: Jason Cooper --- arch/arm/mach-mvebu/pmsu.c | 15 +++++---------- 1 file changed, 5 insertions(+), 10 deletions(-) (limited to 'arch/arm/mach-mvebu') diff --git a/arch/arm/mach-mvebu/pmsu.c b/arch/arm/mach-mvebu/pmsu.c index 6e83d32071b1..73e662971185 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) } /* No locking is needed because we only access per-CPU registers */ -static void armada_370_xp_pmsu_idle_prepare(bool deepidle) +static int armada_370_xp_pmsu_idle_enter(unsigned long deepidle) { unsigned int hw_cpu = cpu_logical_map(smp_processor_id()); u32 reg; if (pmsu_mp_base == NULL) - return; + return -EINVAL; /* * Adjust the PMSU configuration to wait for WFI signal, enable @@ -183,11 +183,6 @@ static void armada_370_xp_pmsu_idle_prepare(bool deepidle) reg = readl(pmsu_mp_base + PMSU_CPU_POWER_DOWN_CONTROL(hw_cpu)); reg |= PMSU_CPU_POWER_DOWN_DIS_SNP_Q_SKIP; writel(reg, pmsu_mp_base + PMSU_CPU_POWER_DOWN_CONTROL(hw_cpu)); -} - -static noinline int do_armada_370_xp_cpu_suspend(unsigned long deepidle) -{ - armada_370_xp_pmsu_idle_prepare(deepidle); v7_exit_coherency_flush(all); @@ -220,11 +215,11 @@ static noinline int do_armada_370_xp_cpu_suspend(unsigned long deepidle) static int armada_370_xp_cpu_suspend(unsigned long deepidle) { - return cpu_suspend(deepidle, do_armada_370_xp_cpu_suspend); + return cpu_suspend(deepidle, armada_370_xp_pmsu_idle_enter); } /* No locking is needed because we only access per-CPU registers */ -static noinline void armada_370_xp_pmsu_idle_restore(void) +static void armada_370_xp_pmsu_idle_exit(void) { unsigned int hw_cpu = cpu_logical_map(smp_processor_id()); u32 reg; @@ -253,7 +248,7 @@ static int armada_370_xp_cpu_pm_notify(struct notifier_block *self, unsigned int hw_cpu = cpu_logical_map(smp_processor_id()); mvebu_pmsu_set_cpu_boot_addr(hw_cpu, armada_370_xp_cpu_resume); } else if (action == CPU_PM_EXIT) { - armada_370_xp_pmsu_idle_restore(); + armada_370_xp_pmsu_idle_exit(); } return NOTIFY_OK; -- cgit v1.2.3 From 8ea875e72d2dd66eea393f22c6bf4707f92f4a50 Mon Sep 17 00:00:00 2001 From: Thomas Petazzoni Date: Fri, 30 May 2014 22:18:16 +0200 Subject: ARM: mvebu: export PMSU idle enter/exit functions The PMSU idle enter/exit functions will be needed for the CPU hotplug implementation on Armada XP, so this commit removes their static qualifier, and adds the appropriate prototypes in armada-370-xp.h. Signed-off-by: Thomas Petazzoni Link: https://lkml.kernel.org/r/1401481098-23326-4-git-send-email-thomas.petazzoni@free-electrons.com Signed-off-by: Jason Cooper --- arch/arm/mach-mvebu/armada-370-xp.h | 3 +++ arch/arm/mach-mvebu/pmsu.c | 4 ++-- 2 files changed, 5 insertions(+), 2 deletions(-) (limited to 'arch/arm/mach-mvebu') 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); extern struct smp_operations armada_xp_smp_ops; #endif +int armada_370_xp_pmsu_idle_enter(unsigned long deepidle); +void armada_370_xp_pmsu_idle_exit(void); + #endif /* __MACH_ARMADA_370_XP_H */ diff --git a/arch/arm/mach-mvebu/pmsu.c b/arch/arm/mach-mvebu/pmsu.c index 73e662971185..27d98e7e7ab8 100644 --- a/arch/arm/mach-mvebu/pmsu.c +++ b/arch/arm/mach-mvebu/pmsu.c @@ -148,7 +148,7 @@ static void armada_370_xp_cpu_resume(void) } /* No locking is needed because we only access per-CPU registers */ -static int armada_370_xp_pmsu_idle_enter(unsigned long deepidle) +int armada_370_xp_pmsu_idle_enter(unsigned long deepidle) { unsigned int hw_cpu = cpu_logical_map(smp_processor_id()); u32 reg; @@ -219,7 +219,7 @@ static int armada_370_xp_cpu_suspend(unsigned long deepidle) } /* No locking is needed because we only access per-CPU registers */ -static void armada_370_xp_pmsu_idle_exit(void) +void armada_370_xp_pmsu_idle_exit(void) { unsigned int hw_cpu = cpu_logical_map(smp_processor_id()); u32 reg; -- cgit v1.2.3 From 26337779465637b761624d9752f52d1ec88f71d9 Mon Sep 17 00:00:00 2001 From: Thomas Petazzoni Date: Fri, 30 May 2014 22:18:17 +0200 Subject: ARM: mvebu: implement CPU hotplug support for Armada XP This commit implements CPU hotplug support for the Marvell Armada XP platform. The CPU hotplug stub functions from hotplug.c are moved into platsmp.c, as it doesn't make much sense to have a separate file just for these two functions. In addition, this commit: * Implements the ->cpu_die() function of SMP operations by calling armada_370_xp_pmsu_idle_enter() to enter the deep idle state for CPUs going offline. * Implements a dummy ->cpu_kill() function, simply needed for the kernel to know we have CPU hotplug support. * The armada_xp_boot_secondary() function makes sure to wake up the CPU if waiting in deep idle state by sending an IPI. This is because armada_xp_boot_secondary() is now used in two different situations: for the initial boot of secondary CPUs (where CPU reset deassert is used to wake up CPUs) and for CPU hotplug (where an IPI is used to take CPU out of deep idle). * At boot time, we exit from the idle state in the ->smp_secondary_init() hook. This commit has been tested using CPU hotplug through sysfs (/sys/devices/system/cpu/cpuX/online) and using kexec. Signed-off-by: Thomas Petazzoni Link: https://lkml.kernel.org/r/1401481098-23326-5-git-send-email-thomas.petazzoni@free-electrons.com Signed-off-by: Jason Cooper --- arch/arm/mach-mvebu/Makefile | 1 - arch/arm/mach-mvebu/common.h | 2 -- arch/arm/mach-mvebu/hotplug.c | 31 ---------------------------- arch/arm/mach-mvebu/platsmp.c | 48 +++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 48 insertions(+), 34 deletions(-) delete mode 100644 arch/arm/mach-mvebu/hotplug.c (limited to 'arch/arm/mach-mvebu') diff --git a/arch/arm/mach-mvebu/Makefile b/arch/arm/mach-mvebu/Makefile index db29c1dfe3c5..90bcd5327312 100644 --- a/arch/arm/mach-mvebu/Makefile +++ b/arch/arm/mach-mvebu/Makefile @@ -9,7 +9,6 @@ obj-y += system-controller.o mvebu-soc-id.o ifeq ($(CONFIG_MACH_MVEBU_V7),y) obj-y += cpu-reset.o board-v7.o coherency.o coherency_ll.o pmsu.o obj-$(CONFIG_SMP) += platsmp.o headsmp.o platsmp-a9.o headsmp-a9.o -obj-$(CONFIG_HOTPLUG_CPU) += hotplug.o endif obj-$(CONFIG_MACH_DOVE) += dove.o diff --git a/arch/arm/mach-mvebu/common.h b/arch/arm/mach-mvebu/common.h index b67fb7a10d8b..0d05eaa10de5 100644 --- a/arch/arm/mach-mvebu/common.h +++ b/arch/arm/mach-mvebu/common.h @@ -22,6 +22,4 @@ int mvebu_cpu_reset_deassert(int cpu); void mvebu_pmsu_set_cpu_boot_addr(int hw_cpu, void *boot_addr); void mvebu_system_controller_set_cpu_boot_addr(void *boot_addr); -void armada_xp_cpu_die(unsigned int cpu); - #endif 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 @@ -/* - * Symmetric Multi Processing (SMP) support for Armada XP - * - * Copyright (C) 2012 Marvell - * - * Lior Amsalem - * Gregory CLEMENT - * Thomas Petazzoni - * - * This file is licensed under the terms of the GNU General Public - * License version 2. This program is licensed "as is" without any - * warranty of any kind, whether express or implied. - */ -#include -#include -#include -#include -#include "common.h" - -/* - * platform-specific code to shutdown a CPU - * - * Called with IRQs disabled - */ -void __ref armada_xp_cpu_die(unsigned int cpu) -{ - cpu_do_idle(); - - /* We should never return from idle */ - panic("mvebu: cpu %d unexpectedly exit from shutdown\n", cpu); -} 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) hw_cpu = cpu_logical_map(cpu); mvebu_pmsu_set_cpu_boot_addr(hw_cpu, armada_xp_secondary_startup); + + /* + * This is needed to wake up CPUs in the offline state after + * using CPU hotplug. + */ + arch_send_wakeup_ipi_mask(cpumask_of(cpu)); + + /* + * This is needed to take secondary CPUs out of reset on the + * initial boot. + */ ret = mvebu_cpu_reset_deassert(hw_cpu); if (ret) { 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) return 0; } +/* + * When a CPU is brought back online, either through CPU hotplug, or + * because of the boot of a kexec'ed kernel, the PMSU configuration + * for this CPU might be in the deep idle state, preventing this CPU + * from receiving interrupts. Here, we therefore take out the current + * CPU from this state, which was entered by armada_xp_cpu_die() + * below. + */ +static void armada_xp_secondary_init(unsigned int cpu) +{ + armada_370_xp_pmsu_idle_exit(); +} + static void __init armada_xp_smp_init_cpus(void) { unsigned int ncores = num_possible_cpus(); @@ -122,12 +146,36 @@ static void __init armada_xp_smp_prepare_cpus(unsigned int max_cpus) panic("The address for the BootROM is incorrect"); } +#ifdef CONFIG_HOTPLUG_CPU +static void armada_xp_cpu_die(unsigned int cpu) +{ + /* + * CPU hotplug is implemented by putting offline CPUs into the + * deep idle sleep state. + */ + armada_370_xp_pmsu_idle_enter(true); +} + +/* + * We need a dummy function, so that platform_can_cpu_hotplug() knows + * we support CPU hotplug. However, the function does not need to do + * anything, because CPUs going offline can enter the deep idle state + * by themselves, without any help from a still alive CPU. + */ +static int armada_xp_cpu_kill(unsigned int cpu) +{ + return 1; +} +#endif + struct smp_operations armada_xp_smp_ops __initdata = { .smp_init_cpus = armada_xp_smp_init_cpus, .smp_prepare_cpus = armada_xp_smp_prepare_cpus, .smp_boot_secondary = armada_xp_boot_secondary, + .smp_secondary_init = armada_xp_secondary_init, #ifdef CONFIG_HOTPLUG_CPU .cpu_die = armada_xp_cpu_die, + .cpu_kill = armada_xp_cpu_kill, #endif }; -- cgit v1.2.3 From 9d6373485c0c3b38de666d8e0af95ee7c692ecbe Mon Sep 17 00:00:00 2001 From: Ezequiel Garcia Date: Tue, 10 Jun 2014 15:34:43 -0300 Subject: ARM: mvebu: Don't apply the thermal quirk if the SoC revision is unknown Currently, the thermal quirk is skipped only if the SoC revision is known to be one that does not need them, but if the SoC revision cannot be obtained, the quirk is applied assuming it's needed. However, this quirk must be applied only we are sure the SoC needs it, for it breaks the thermal support if applied on a SoC that doesn't need it. The reason for this is that the quirk consists in changing the thermal devicetree compatible string and register offsets, to workaround a hardware bug in the early SoC revision. Such changes are wrong if the SoC is a new revision and doesn't need the workaround. Therefore, this commit changes the behavior, by requiring the SoC revision to be known in order to peform a quirk. Signed-off-by: Ezequiel Garcia Link: https://lkml.kernel.org/r/1402425283-24989-1-git-send-email-ezequiel.garcia@free-electrons.com Signed-off-by: Jason Cooper --- arch/arm/mach-mvebu/board-v7.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) (limited to 'arch/arm/mach-mvebu') 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) { struct device_node *np; u32 dev, rev; + int res; - if (mvebu_get_soc_id(&dev, &rev) == 0 && rev > ARMADA_375_Z1_REV) + /* + * The early SoC Z1 revision needs a quirk to be applied in order + * for the thermal controller to work properly. This quirk breaks + * the thermal support if applied on a SoC that doesn't need it, + * so we enforce the SoC revision to be known. + */ + res = mvebu_get_soc_id(&dev, &rev); + if (res < 0 || (res == 0 && rev > ARMADA_375_Z1_REV)) return; for_each_compatible_node(np, NULL, "marvell,armada375-thermal") { @@ -153,7 +161,8 @@ static void __init thermal_quirk(void) /* * The thermal controller needs some quirk too, so let's change - * the compatible string to reflect this. + * the compatible string to reflect this and allow the driver + * the take the necessary action. */ prop = kzalloc(sizeof(*prop), GFP_KERNEL); prop->name = kstrdup("compatible", GFP_KERNEL); -- cgit v1.2.3 From 5e80d81acc420fa33b56078f73f38546ab99be6f Mon Sep 17 00:00:00 2001 From: Gregory CLEMENT Date: Fri, 20 Jun 2014 16:35:52 +0200 Subject: ARM: mvebu: Use the a standard errno in mvebu_get_soc_id Instead of using -1 as error value, use a standard errno. Signed-off-by: Gregory CLEMENT Link: https://lkml.kernel.org/r/1403274953-21790-2-git-send-email-gregory.clement@free-electrons.com Acked-by: Thomas Petazzoni Signed-off-by: Jason Cooper --- arch/arm/mach-mvebu/mvebu-soc-id.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'arch/arm/mach-mvebu') diff --git a/arch/arm/mach-mvebu/mvebu-soc-id.c b/arch/arm/mach-mvebu/mvebu-soc-id.c index d0f35b4d4a23..12c66cac967d 100644 --- a/arch/arm/mach-mvebu/mvebu-soc-id.c +++ b/arch/arm/mach-mvebu/mvebu-soc-id.c @@ -51,7 +51,7 @@ int mvebu_get_soc_id(u32 *dev, u32 *rev) *rev = soc_rev; return 0; } else - return -1; + return -ENODEV; } static int __init mvebu_soc_id_init(void) -- cgit v1.2.3 From 9674d4a3cf4307dda468a0b48e5e43a2fdb56b68 Mon Sep 17 00:00:00 2001 From: Gregory CLEMENT Date: Mon, 23 Jun 2014 17:42:08 +0200 Subject: ARM: mvebu: Use system controller to get the soc id when possible On Armada 38x it is possible to get the SoC Id and the revision without using the PCI register. Accessing the PCI registers implies enabling its clock and, because of the initialization issue, not keeping them enable. So if possible it is better to avoid it. Armada 370 and Armada XP provides the SoC ID values from the system controller but not the revision. Armada 375 provides both but the SoC ID value looks buggy (0x6660 instead of 0x6720). Signed-off-by: Gregory CLEMENT Link: https://lkml.kernel.org/r/1403538128-27859-1-git-send-email-gregory.clement@free-electrons.com Signed-off-by: Jason Cooper --- arch/arm/mach-mvebu/common.h | 1 + arch/arm/mach-mvebu/mvebu-soc-id.c | 19 ++++++++++++++++++- arch/arm/mach-mvebu/system-controller.c | 19 +++++++++++++++++++ 3 files changed, 38 insertions(+), 1 deletion(-) (limited to 'arch/arm/mach-mvebu') diff --git a/arch/arm/mach-mvebu/common.h b/arch/arm/mach-mvebu/common.h index 0d05eaa10de5..a97778e28bf6 100644 --- a/arch/arm/mach-mvebu/common.h +++ b/arch/arm/mach-mvebu/common.h @@ -21,5 +21,6 @@ void mvebu_restart(enum reboot_mode mode, const char *cmd); int mvebu_cpu_reset_deassert(int cpu); void mvebu_pmsu_set_cpu_boot_addr(int hw_cpu, void *boot_addr); void mvebu_system_controller_set_cpu_boot_addr(void *boot_addr); +int mvebu_system_controller_get_soc_id(u32 *dev, u32 *rev); #endif diff --git a/arch/arm/mach-mvebu/mvebu-soc-id.c b/arch/arm/mach-mvebu/mvebu-soc-id.c index 12c66cac967d..a99434bcee84 100644 --- a/arch/arm/mach-mvebu/mvebu-soc-id.c +++ b/arch/arm/mach-mvebu/mvebu-soc-id.c @@ -25,6 +25,7 @@ #include #include #include +#include "common.h" #include "mvebu-soc-id.h" #define PCIE_DEV_ID_OFF 0x0 @@ -54,7 +55,7 @@ int mvebu_get_soc_id(u32 *dev, u32 *rev) return -ENODEV; } -static int __init mvebu_soc_id_init(void) +static int __init get_soc_id_by_pci(void) { struct device_node *np; int ret = 0; @@ -129,6 +130,22 @@ clk_err: return ret; } + +static int __init mvebu_soc_id_init(void) +{ + + /* + * First try to get the ID and the revision by the system + * register and use PCI registers only if it is not possible + */ + if (!mvebu_system_controller_get_soc_id(&soc_dev_id, &soc_rev)) { + is_id_valid = true; + pr_info("MVEBU SoC ID=0x%X, Rev=0x%X\n", soc_dev_id, soc_rev); + return 0; + } + + return get_soc_id_by_pci(); +} early_initcall(mvebu_soc_id_init); static int __init mvebu_soc_device(void) 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 { u32 system_soft_reset; u32 resume_boot_addr; + + u32 dev_id; + u32 rev_id; }; static struct mvebu_system_controller *mvebu_sc; @@ -47,6 +50,8 @@ static const struct mvebu_system_controller armada_370_xp_system_controller = { .system_soft_reset_offset = 0x64, .rstoutn_mask_reset_out_en = 0x1, .system_soft_reset = 0x1, + .dev_id = 0x38, + .rev_id = 0x3c, }; static const struct mvebu_system_controller armada_375_system_controller = { @@ -55,6 +60,8 @@ static const struct mvebu_system_controller armada_375_system_controller = { .rstoutn_mask_reset_out_en = 0x1, .system_soft_reset = 0x1, .resume_boot_addr = 0xd4, + .dev_id = 0x38, + .rev_id = 0x3c, }; static const struct mvebu_system_controller orion_system_controller = { @@ -101,6 +108,18 @@ void mvebu_restart(enum reboot_mode mode, const char *cmd) ; } +int mvebu_system_controller_get_soc_id(u32 *dev, u32 *rev) +{ + if (of_machine_is_compatible("marvell,armada380") && + system_controller_base) { + *dev = readl(system_controller_base + mvebu_sc->dev_id) >> 16; + *rev = (readl(system_controller_base + mvebu_sc->rev_id) >> 8) + & 0xF; + return 0; + } else + return -ENODEV; +} + #ifdef CONFIG_SMP void mvebu_system_controller_set_cpu_boot_addr(void *boot_addr) { -- cgit v1.2.3 From 1440fbd271127c283790063f735afd75f832751d Mon Sep 17 00:00:00 2001 From: Sachin Kamat Date: Tue, 24 Jun 2014 17:13:49 +0530 Subject: ARM: mvebu: Staticize armada_375_smp_cpu1_enable_wa 'armada_375_smp_cpu1_enable_wa' is local to this file. Signed-off-by: Sachin Kamat Link: https://lkml.kernel.org/r/1403610235-22654-2-git-send-email-sachin.kamat@samsung.com Signed-off-by: Sachin Kamat Cc: Jason Cooper Cc: Andrew Lunn Cc: Gregory Clement Cc: Sebastian Hesselbarth Signed-off-by: Jason Cooper --- arch/arm/mach-mvebu/platsmp-a9.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'arch/arm/mach-mvebu') diff --git a/arch/arm/mach-mvebu/platsmp-a9.c b/arch/arm/mach-mvebu/platsmp-a9.c index 65f532141a30..43aaf3fa75ee 100644 --- a/arch/arm/mach-mvebu/platsmp-a9.c +++ b/arch/arm/mach-mvebu/platsmp-a9.c @@ -33,7 +33,7 @@ extern unsigned char armada_375_smp_cpu1_enable_code_end; extern unsigned char armada_375_smp_cpu1_enable_code_start; -void armada_375_smp_cpu1_enable_wa(void) +static void armada_375_smp_cpu1_enable_wa(void) { void __iomem *sram_virt_base; -- cgit v1.2.3 From 6fc770f28d10809474ec3fafb162ba76ac435cd4 Mon Sep 17 00:00:00 2001 From: Sachin Kamat Date: Tue, 24 Jun 2014 17:13:50 +0530 Subject: ARM: mvebu: Staticize armada_370_xp_cpu_pm_init 'armada_370_xp_cpu_pm_init' is local to this file. Signed-off-by: Sachin Kamat Link: https://lkml.kernel.org/r/1403610235-22654-3-git-send-email-sachin.kamat@samsung.com Signed-off-by: Sachin Kamat Cc: Jason Cooper Cc: Andrew Lunn Cc: Gregory Clement Cc: Sebastian Hesselbarth Signed-off-by: Jason Cooper --- arch/arm/mach-mvebu/pmsu.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'arch/arm/mach-mvebu') diff --git a/arch/arm/mach-mvebu/pmsu.c b/arch/arm/mach-mvebu/pmsu.c index 27d98e7e7ab8..9c819d65b337 100644 --- a/arch/arm/mach-mvebu/pmsu.c +++ b/arch/arm/mach-mvebu/pmsu.c @@ -258,7 +258,7 @@ static struct notifier_block armada_370_xp_cpu_pm_notifier = { .notifier_call = armada_370_xp_cpu_pm_notify, }; -int __init armada_370_xp_cpu_pm_init(void) +static int __init armada_370_xp_cpu_pm_init(void) { struct device_node *np; -- cgit v1.2.3 From e65714740d65237c40878b63acad6bf921481974 Mon Sep 17 00:00:00 2001 From: Sachin Kamat Date: Tue, 24 Jun 2014 17:13:51 +0530 Subject: ARM: mvebu: Staticize mvebu_cpu_reset_init 'mvebu_cpu_reset_init' is local to this file. Signed-off-by: Sachin Kamat Link: https://lkml.kernel.org/r/1403610235-22654-4-git-send-email-sachin.kamat@samsung.com Signed-off-by: Sachin Kamat Acked-by: Thomas Petazzoni Cc: Jason Cooper Cc: Andrew Lunn Cc: Gregory Clement Cc: Sebastian Hesselbarth Signed-off-by: Jason Cooper --- arch/arm/mach-mvebu/cpu-reset.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'arch/arm/mach-mvebu') 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) return 0; } -int __init mvebu_cpu_reset_init(void) +static int __init mvebu_cpu_reset_init(void) { struct device_node *np; int res_idx; -- cgit v1.2.3 From 831e2518890f5ffd52706750b1cbf04feb2e7c59 Mon Sep 17 00:00:00 2001 From: Thomas Petazzoni Date: Wed, 9 Jul 2014 17:45:09 +0200 Subject: ARM: mvebu: ensure CPU clocks are enabled In the Armada XP SMP support code, we are reading the clock frequency of the booting CPU, and use that to assign the same frequency to the other CPUs, and we do this while the clocks are disabled. However, the CPU clocks are in fact never prepared/enabled, and to support cpufreq, we now have two code paths to change the frequency of the CPU clocks in the CPU clock driver: one when the clock is enabled (dynamic frequency scaling), one when the clock is disabled (adjusting the CPU frequency before starting the CPU). In order for this to work, the CPU clocks now have to be prepared and enabled after the initial synchronization of the clock frequencies is done, so that all future rate changes of the CPU clocks will trigger a dynamic frequency scaling transition. Signed-off-by: Thomas Petazzoni Link: https://lkml.kernel.org/r/1404920715-19834-2-git-send-email-thomas.petazzoni@free-electrons.com Signed-off-by: Jason Cooper --- arch/arm/mach-mvebu/platsmp.c | 1 + 1 file changed, 1 insertion(+) (limited to 'arch/arm/mach-mvebu') diff --git a/arch/arm/mach-mvebu/platsmp.c b/arch/arm/mach-mvebu/platsmp.c index 88b976b31719..4880b0f70362 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) if (!cpu_clk) return; clk_set_rate(cpu_clk, rate); + clk_prepare_enable(cpu_clk); } } -- cgit v1.2.3 From a509ea840b8e29e512764803e30b805c7ea89038 Mon Sep 17 00:00:00 2001 From: Thomas Petazzoni Date: Wed, 9 Jul 2014 17:45:10 +0200 Subject: ARM: mvebu: extend PMSU code to support dynamic frequency scaling This commit adds the necessary code in the Marvell EBU PMSU driver to support dynamic frequency scaling. In essence, what this new code does is that it: * registers the frequency operating points supported by the CPU; * registers a clock notifier of the CPU clocks. The notifier function listens to the newly introduced APPLY_RATE_CHANGE event, and uses that to finalize the frequency transition by doing the part of the procedure that involves the PMSU; * registers a platform device for the cpufreq-generic driver, which will take care of the CPU frequency transitions. Signed-off-by: Thomas Petazzoni Link: https://lkml.kernel.org/r/1404920715-19834-3-git-send-email-thomas.petazzoni@free-electrons.com Signed-off-by: Jason Cooper --- arch/arm/mach-mvebu/pmsu.c | 162 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 162 insertions(+) (limited to 'arch/arm/mach-mvebu') diff --git a/arch/arm/mach-mvebu/pmsu.c b/arch/arm/mach-mvebu/pmsu.c index 53a55c8520bf..db7d9ab298b6 100644 --- a/arch/arm/mach-mvebu/pmsu.c +++ b/arch/arm/mach-mvebu/pmsu.c @@ -18,20 +18,26 @@ #define pr_fmt(fmt) "mvebu-pmsu: " fmt +#include #include +#include #include #include #include +#include #include #include +#include #include #include +#include #include #include #include #include #include #include "common.h" +#include "armada-370-xp.h" static void __iomem *pmsu_mp_base; @@ -57,6 +63,10 @@ static void __iomem *pmsu_mp_base; #define PMSU_STATUS_AND_MASK_IRQ_MASK BIT(24) #define PMSU_STATUS_AND_MASK_FIQ_MASK BIT(25) +#define PMSU_EVENT_STATUS_AND_MASK(cpu) ((cpu * 0x100) + 0x120) +#define PMSU_EVENT_STATUS_AND_MASK_DFS_DONE BIT(1) +#define PMSU_EVENT_STATUS_AND_MASK_DFS_DONE_MASK BIT(17) + #define PMSU_BOOT_ADDR_REDIRECT_OFFSET(cpu) ((cpu * 0x100) + 0x124) /* PMSU fabric registers */ @@ -296,3 +306,155 @@ int __init armada_370_xp_cpu_pm_init(void) arch_initcall(armada_370_xp_cpu_pm_init); early_initcall(armada_370_xp_pmsu_init); + +static void mvebu_pmsu_dfs_request_local(void *data) +{ + u32 reg; + u32 cpu = smp_processor_id(); + unsigned long flags; + + local_irq_save(flags); + + /* Prepare to enter idle */ + reg = readl(pmsu_mp_base + PMSU_STATUS_AND_MASK(cpu)); + reg |= PMSU_STATUS_AND_MASK_CPU_IDLE_WAIT | + PMSU_STATUS_AND_MASK_IRQ_MASK | + PMSU_STATUS_AND_MASK_FIQ_MASK; + writel(reg, pmsu_mp_base + PMSU_STATUS_AND_MASK(cpu)); + + /* Request the DFS transition */ + reg = readl(pmsu_mp_base + PMSU_CONTROL_AND_CONFIG(cpu)); + reg |= PMSU_CONTROL_AND_CONFIG_DFS_REQ; + writel(reg, pmsu_mp_base + PMSU_CONTROL_AND_CONFIG(cpu)); + + /* The fact of entering idle will trigger the DFS transition */ + wfi(); + + /* + * We're back from idle, the DFS transition has completed, + * clear the idle wait indication. + */ + reg = readl(pmsu_mp_base + PMSU_STATUS_AND_MASK(cpu)); + reg &= ~PMSU_STATUS_AND_MASK_CPU_IDLE_WAIT; + writel(reg, pmsu_mp_base + PMSU_STATUS_AND_MASK(cpu)); + + local_irq_restore(flags); +} + +int mvebu_pmsu_dfs_request(int cpu) +{ + unsigned long timeout; + int hwcpu = cpu_logical_map(cpu); + u32 reg; + + /* Clear any previous DFS DONE event */ + reg = readl(pmsu_mp_base + PMSU_EVENT_STATUS_AND_MASK(hwcpu)); + reg &= ~PMSU_EVENT_STATUS_AND_MASK_DFS_DONE; + writel(reg, pmsu_mp_base + PMSU_EVENT_STATUS_AND_MASK(hwcpu)); + + /* Mask the DFS done interrupt, since we are going to poll */ + reg = readl(pmsu_mp_base + PMSU_EVENT_STATUS_AND_MASK(hwcpu)); + reg |= PMSU_EVENT_STATUS_AND_MASK_DFS_DONE_MASK; + writel(reg, pmsu_mp_base + PMSU_EVENT_STATUS_AND_MASK(hwcpu)); + + /* Trigger the DFS on the appropriate CPU */ + smp_call_function_single(cpu, mvebu_pmsu_dfs_request_local, + NULL, false); + + /* Poll until the DFS done event is generated */ + timeout = jiffies + HZ; + while (time_before(jiffies, timeout)) { + reg = readl(pmsu_mp_base + PMSU_EVENT_STATUS_AND_MASK(hwcpu)); + if (reg & PMSU_EVENT_STATUS_AND_MASK_DFS_DONE) + break; + udelay(10); + } + + if (time_after(jiffies, timeout)) + return -ETIME; + + /* Restore the DFS mask to its original state */ + reg = readl(pmsu_mp_base + PMSU_EVENT_STATUS_AND_MASK(hwcpu)); + reg &= ~PMSU_EVENT_STATUS_AND_MASK_DFS_DONE_MASK; + writel(reg, pmsu_mp_base + PMSU_EVENT_STATUS_AND_MASK(hwcpu)); + + return 0; +} + +static int __init armada_xp_pmsu_cpufreq_init(void) +{ + struct device_node *np; + struct resource res; + int ret, cpu; + + if (!of_machine_is_compatible("marvell,armadaxp")) + return 0; + + /* + * In order to have proper cpufreq handling, we need to ensure + * that the Device Tree description of the CPU clock includes + * the definition of the PMU DFS registers. If not, we do not + * register the clock notifier and the cpufreq driver. This + * piece of code is only for compatibility with old Device + * Trees. + */ + np = of_find_compatible_node(NULL, NULL, "marvell,armada-xp-cpu-clock"); + if (!np) + return 0; + + ret = of_address_to_resource(np, 1, &res); + if (ret) { + pr_warn(FW_WARN "not enabling cpufreq, deprecated armada-xp-cpu-clock binding\n"); + of_node_put(np); + return 0; + } + + of_node_put(np); + + /* + * For each CPU, this loop registers the operating points + * supported (which are the nominal CPU frequency and half of + * it), and registers the clock notifier that will take care + * of doing the PMSU part of a frequency transition. + */ + for_each_possible_cpu(cpu) { + struct device *cpu_dev; + struct clk *clk; + int ret; + + cpu_dev = get_cpu_device(cpu); + if (!cpu_dev) { + pr_err("Cannot get CPU %d\n", cpu); + continue; + } + + clk = clk_get(cpu_dev, 0); + if (!clk) { + pr_err("Cannot get clock for CPU %d\n", cpu); + return -ENODEV; + } + + /* + * In case of a failure of dev_pm_opp_add(), we don't + * bother with cleaning up the registered OPP (there's + * no function to do so), and simply cancel the + * registration of the cpufreq device. + */ + ret = dev_pm_opp_add(cpu_dev, clk_get_rate(clk), 0); + if (ret) { + clk_put(clk); + return ret; + } + + ret = dev_pm_opp_add(cpu_dev, clk_get_rate(clk) / 2, 0); + if (ret) { + clk_put(clk); + return ret; + } + } + + platform_device_register_simple("cpufreq-generic", -1, NULL, 0); + return 0; +} + +device_initcall(armada_xp_pmsu_cpufreq_init); -- cgit v1.2.3 From b03e119fff8a06f55faaaa11c6259829fe81cbb4 Mon Sep 17 00:00:00 2001 From: Wei Yongjun Date: Tue, 22 Jul 2014 22:18:08 +0800 Subject: ARM: mvebu: fix return value check in armada_xp_pmsu_cpufreq_init() In case of error, the function clk_get() returns ERR_PTR() and never returns NULL. The NULL test in the return value check should be replaced with IS_ERR(). Signed-off-by: Wei Yongjun Link: https://lkml.kernel.org/r/1406038688-26417-1-git-send-email-weiyj_lk@163.com Signed-off-by: Jason Cooper --- arch/arm/mach-mvebu/pmsu.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'arch/arm/mach-mvebu') diff --git a/arch/arm/mach-mvebu/pmsu.c b/arch/arm/mach-mvebu/pmsu.c index 0ca285fdd569..0b617ae3ceb9 100644 --- a/arch/arm/mach-mvebu/pmsu.c +++ b/arch/arm/mach-mvebu/pmsu.c @@ -424,9 +424,9 @@ static int __init armada_xp_pmsu_cpufreq_init(void) } clk = clk_get(cpu_dev, 0); - if (!clk) { + if (IS_ERR(clk)) { pr_err("Cannot get clock for CPU %d\n", cpu); - return -ENODEV; + return PTR_ERR(clk); } /* -- cgit v1.2.3 From 9ce35884bd961700d34f8a5d908645be2fd0ba76 Mon Sep 17 00:00:00 2001 From: Gregory CLEMENT Date: Wed, 23 Jul 2014 15:00:38 +0200 Subject: ARM: mvebu: split again armada_370_xp_pmsu_idle_enter() in PMSU code do_armada_370_xp_cpu_suspend() and armada_370_xp_pmsu_idle_prepare(), have been merged into a single function called armada_370_xp_pmsu_idle_enter() by the commit "bbb92284b6c8 ARM: mvebu: slightly refactor/rename PMSU idle related functions", in prepare for the introduction of the CPU hotplug support for Armada XP. But for cpuidle the prepare function will be common to all the mvebu SoCs that use the PMSU, while the suspend function will be specific to each SoC. Keeping the prepare function separate will help reducing code duplication while new SoC support is added. Signed-off-by: Gregory CLEMENT Signed-off-by: Thomas Petazzoni Link: https://lkml.kernel.org/r/1406120453-29291-2-git-send-email-thomas.petazzoni@free-electrons.com Signed-off-by: Jason Cooper --- arch/arm/mach-mvebu/pmsu.c | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) (limited to 'arch/arm/mach-mvebu') diff --git a/arch/arm/mach-mvebu/pmsu.c b/arch/arm/mach-mvebu/pmsu.c index b31a8293a347..5fda549d1c6b 100644 --- a/arch/arm/mach-mvebu/pmsu.c +++ b/arch/arm/mach-mvebu/pmsu.c @@ -143,7 +143,7 @@ static void armada_370_xp_pmsu_enable_l2_powerdown_onidle(void) } /* No locking is needed because we only access per-CPU registers */ -int armada_370_xp_pmsu_idle_enter(unsigned long deepidle) +static int armada_370_xp_prepare(unsigned long deepidle) { unsigned int hw_cpu = cpu_logical_map(smp_processor_id()); u32 reg; @@ -179,6 +179,17 @@ int armada_370_xp_pmsu_idle_enter(unsigned long deepidle) reg |= PMSU_CPU_POWER_DOWN_DIS_SNP_Q_SKIP; writel(reg, pmsu_mp_base + PMSU_CPU_POWER_DOWN_CONTROL(hw_cpu)); + return 0; +} + +int armada_370_xp_pmsu_idle_enter(unsigned long deepidle) +{ + int ret; + + ret = armada_370_xp_prepare(deepidle); + if (ret) + return ret; + v7_exit_coherency_flush(all); ll_disable_coherency(); -- cgit v1.2.3 From 3e328428d4d0abe257ee9342d3e370c6487e9601 Mon Sep 17 00:00:00 2001 From: Gregory CLEMENT Date: Wed, 23 Jul 2014 15:00:39 +0200 Subject: ARM: mvebu: sort the #include of pmsu.c in alphabetic order Sorting the headers in alphabetic order will help to reduce conflicts when adding new headers later. Signed-off-by: Gregory CLEMENT Signed-off-by: Thomas Petazzoni Link: https://lkml.kernel.org/r/1406120453-29291-3-git-send-email-thomas.petazzoni@free-electrons.com Signed-off-by: Jason Cooper --- arch/arm/mach-mvebu/pmsu.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'arch/arm/mach-mvebu') diff --git a/arch/arm/mach-mvebu/pmsu.c b/arch/arm/mach-mvebu/pmsu.c index 5fda549d1c6b..9e18ccee0edd 100644 --- a/arch/arm/mach-mvebu/pmsu.c +++ b/arch/arm/mach-mvebu/pmsu.c @@ -19,13 +19,13 @@ #define pr_fmt(fmt) "mvebu-pmsu: " fmt #include -#include #include -#include #include +#include +#include #include -#include #include +#include #include #include #include -- cgit v1.2.3 From 3076cc58c958090ad50acf50fc855845e3462523 Mon Sep 17 00:00:00 2001 From: Gregory CLEMENT Date: Wed, 23 Jul 2014 15:00:40 +0200 Subject: ARM: mvebu: add a common function for the boot address work around On some of the mvebu SoCs and due to internal BootROM issue, the CPU initial jump code must be placed in the SRAM memory of the SoC. In order to achieve this, we have to unmap the BootROM and at some specific location where the BootROM was placed, create a dedicated MBus window for the SRAM. This SRAM is initialized with a few instructions of code that allows to jump to the real secondary CPU boot address. The SRAM used is the Crypto engine one. This work around is currently needed for booting SMP on Armada 375 Z1 and will be needed for cpuidle support on Armada 370. Instead of duplicating the same code, this commit introduces a common function to handle it: mvebu_setup_boot_addr_wa(). Signed-off-by: Gregory CLEMENT Signed-off-by: Thomas Petazzoni Link: https://lkml.kernel.org/r/1406120453-29291-4-git-send-email-thomas.petazzoni@free-electrons.com Signed-off-by: Jason Cooper --- arch/arm/mach-mvebu/pmsu.c | 47 +++++++++++++++++++++++++++++++++++++++++++ arch/arm/mach-mvebu/pmsu.h | 3 +++ arch/arm/mach-mvebu/pmsu_ll.S | 22 ++++++++++++++++++++ 3 files changed, 72 insertions(+) (limited to 'arch/arm/mach-mvebu') diff --git a/arch/arm/mach-mvebu/pmsu.c b/arch/arm/mach-mvebu/pmsu.c index 9e18ccee0edd..272a9c0565b2 100644 --- a/arch/arm/mach-mvebu/pmsu.c +++ b/arch/arm/mach-mvebu/pmsu.c @@ -22,6 +22,7 @@ #include #include #include +#include #include #include #include @@ -63,6 +64,10 @@ static void __iomem *pmsu_mp_base; #define L2C_NFABRIC_PM_CTL 0x4 #define L2C_NFABRIC_PM_CTL_PWR_DOWN BIT(20) +#define SRAM_PHYS_BASE 0xFFFF0000 +#define BOOTROM_BASE 0xFFF00000 +#define BOOTROM_SIZE 0x100000 + extern void ll_disable_coherency(void); extern void ll_enable_coherency(void); @@ -85,6 +90,48 @@ void mvebu_pmsu_set_cpu_boot_addr(int hw_cpu, void *boot_addr) PMSU_BOOT_ADDR_REDIRECT_OFFSET(hw_cpu)); } +extern unsigned char mvebu_boot_wa_start; +extern unsigned char mvebu_boot_wa_end; + +/* + * This function sets up the boot address workaround needed for SMP + * boot on Armada 375 Z1 and cpuidle on Armada 370. It unmaps the + * BootROM Mbus window, and instead remaps a crypto SRAM into which a + * custom piece of code is copied to replace the problematic BootROM. + */ +int mvebu_setup_boot_addr_wa(unsigned int crypto_eng_target, + unsigned int crypto_eng_attribute, + phys_addr_t resume_addr_reg) +{ + void __iomem *sram_virt_base; + u32 code_len = &mvebu_boot_wa_end - &mvebu_boot_wa_start; + + mvebu_mbus_del_window(BOOTROM_BASE, BOOTROM_SIZE); + mvebu_mbus_add_window_by_id(crypto_eng_target, crypto_eng_attribute, + SRAM_PHYS_BASE, SZ_64K); + + sram_virt_base = ioremap(SRAM_PHYS_BASE, SZ_64K); + if (!sram_virt_base) { + pr_err("Unable to map SRAM to setup the boot address WA\n"); + return -ENOMEM; + } + + memcpy(sram_virt_base, &mvebu_boot_wa_start, code_len); + + /* + * The last word of the code copied in SRAM must contain the + * physical base address of the PMSU register. We + * intentionally store this address in the native endianness + * of the system. + */ + __raw_writel((unsigned long)resume_addr_reg, + sram_virt_base + code_len - 4); + + iounmap(sram_virt_base); + + return 0; +} + static int __init armada_370_xp_pmsu_init(void) { struct device_node *np; diff --git a/arch/arm/mach-mvebu/pmsu.h b/arch/arm/mach-mvebu/pmsu.h index 07a737c6b95d..ae501948ec73 100644 --- a/arch/arm/mach-mvebu/pmsu.h +++ b/arch/arm/mach-mvebu/pmsu.h @@ -12,5 +12,8 @@ #define __MACH_MVEBU_PMSU_H int armada_xp_boot_cpu(unsigned int cpu_id, void *phys_addr); +int mvebu_setup_boot_addr_wa(unsigned int crypto_eng_target, + unsigned int crypto_eng_attribute, + phys_addr_t resume_addr_reg); #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..17d7f3b3976d 100644 --- a/arch/arm/mach-mvebu/pmsu_ll.S +++ b/arch/arm/mach-mvebu/pmsu_ll.S @@ -23,3 +23,25 @@ ARM_BE8(setend be ) @ go BE8 if entered LE b cpu_resume ENDPROC(armada_370_xp_cpu_resume) +.global mvebu_boot_wa_start +.global mvebu_boot_wa_end + +/* The following code will be executed from SRAM */ +ENTRY(mvebu_boot_wa_start) +mvebu_boot_wa_start: +ARM_BE8(setend be) + adr r0, 1f + ldr r0, [r0] @ load the address of the + @ resume register + ldr r0, [r0] @ load the value in the + @ resume register +ARM_BE8(rev r0, r0) @ the value is stored LE + mov pc, r0 @ jump to this value +/* + * the last word of this piece of code will be filled by the physical + * address of the boot address register just after being copied in SRAM + */ +1: + .long . +mvebu_boot_wa_end: +ENDPROC(mvebu_boot_wa_end) -- cgit v1.2.3 From 305969fb629284bcd35065911179a79f41954b9a Mon Sep 17 00:00:00 2001 From: Gregory CLEMENT Date: Wed, 23 Jul 2014 15:00:41 +0200 Subject: ARM: mvebu: use the common function for Armada 375 SMP workaround Use the common function mvebu_setup_boot_addr_wa() introduced in the commit "ARM: mvebu: Add a common function for the boot address work around" instead of the dedicated version for Armada 375. This commit also moves the workaround in the system-controller module. Indeed the workaround on 375 is really related to setting the boot address which is done by the system controller. As a bonus we no longer use an harcoded value to access the register storing the boot address. Signed-off-by: Gregory CLEMENT Signed-off-by: Thomas Petazzoni Link: https://lkml.kernel.org/r/1406120453-29291-5-git-send-email-thomas.petazzoni@free-electrons.com Signed-off-by: Jason Cooper --- arch/arm/mach-mvebu/headsmp-a9.S | 15 ------------ arch/arm/mach-mvebu/platsmp-a9.c | 42 +++------------------------------ arch/arm/mach-mvebu/system-controller.c | 31 ++++++++++++++++++++++++ 3 files changed, 34 insertions(+), 54 deletions(-) (limited to 'arch/arm/mach-mvebu') diff --git a/arch/arm/mach-mvebu/headsmp-a9.S b/arch/arm/mach-mvebu/headsmp-a9.S index da5bb292b91c..be51c998c0cd 100644 --- a/arch/arm/mach-mvebu/headsmp-a9.S +++ b/arch/arm/mach-mvebu/headsmp-a9.S @@ -18,21 +18,6 @@ #include __CPUINIT -#define CPU_RESUME_ADDR_REG 0xf10182d4 - -.global armada_375_smp_cpu1_enable_code_start -.global armada_375_smp_cpu1_enable_code_end - -armada_375_smp_cpu1_enable_code_start: -ARM_BE8(setend be) - adr r0, 1f - ldr r0, [r0] - ldr r1, [r0] -ARM_BE8(rev r1, r1) - mov pc, r1 -1: - .word CPU_RESUME_ADDR_REG -armada_375_smp_cpu1_enable_code_end: ENTRY(mvebu_cortex_a9_secondary_startup) ARM_BE8(setend be) diff --git a/arch/arm/mach-mvebu/platsmp-a9.c b/arch/arm/mach-mvebu/platsmp-a9.c index 43aaf3fa75ee..47a71a924b96 100644 --- a/arch/arm/mach-mvebu/platsmp-a9.c +++ b/arch/arm/mach-mvebu/platsmp-a9.c @@ -20,33 +20,8 @@ #include #include #include "common.h" -#include "mvebu-soc-id.h" #include "pmsu.h" -#define CRYPT0_ENG_ID 41 -#define CRYPT0_ENG_ATTR 0x1 -#define SRAM_PHYS_BASE 0xFFFF0000 - -#define BOOTROM_BASE 0xFFF00000 -#define BOOTROM_SIZE 0x100000 - -extern unsigned char armada_375_smp_cpu1_enable_code_end; -extern unsigned char armada_375_smp_cpu1_enable_code_start; - -static void armada_375_smp_cpu1_enable_wa(void) -{ - void __iomem *sram_virt_base; - - mvebu_mbus_del_window(BOOTROM_BASE, BOOTROM_SIZE); - mvebu_mbus_add_window_by_id(CRYPT0_ENG_ID, CRYPT0_ENG_ATTR, - SRAM_PHYS_BASE, SZ_64K); - sram_virt_base = ioremap(SRAM_PHYS_BASE, SZ_64K); - - memcpy(sram_virt_base, &armada_375_smp_cpu1_enable_code_start, - &armada_375_smp_cpu1_enable_code_end - - &armada_375_smp_cpu1_enable_code_start); -} - extern void mvebu_cortex_a9_secondary_startup(void); static 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, * address. */ hw_cpu = cpu_logical_map(cpu); - - if (of_machine_is_compatible("marvell,armada375")) { - u32 dev, rev; - - if (mvebu_get_soc_id(&dev, &rev) == 0 && - rev == ARMADA_375_Z1_REV) - armada_375_smp_cpu1_enable_wa(); - + if (of_machine_is_compatible("marvell,armada375")) mvebu_system_controller_set_cpu_boot_addr(mvebu_cortex_a9_secondary_startup); - } - else { - mvebu_pmsu_set_cpu_boot_addr(hw_cpu, - mvebu_cortex_a9_secondary_startup); - } - + else + mvebu_pmsu_set_cpu_boot_addr(hw_cpu, mvebu_cortex_a9_secondary_startup); smp_wmb(); ret = mvebu_cpu_reset_deassert(hw_cpu); if (ret) { diff --git a/arch/arm/mach-mvebu/system-controller.c b/arch/arm/mach-mvebu/system-controller.c index b2b4e3d6558c..a068cb5c2ce8 100644 --- a/arch/arm/mach-mvebu/system-controller.c +++ b/arch/arm/mach-mvebu/system-controller.c @@ -28,8 +28,14 @@ #include #include #include "common.h" +#include "mvebu-soc-id.h" +#include "pmsu.h" + +#define ARMADA_375_CRYPT0_ENG_TARGET 41 +#define ARMADA_375_CRYPT0_ENG_ATTR 1 static void __iomem *system_controller_base; +static phys_addr_t system_controller_phys_base; struct mvebu_system_controller { u32 rstoutn_mask_offset; @@ -121,10 +127,32 @@ int mvebu_system_controller_get_soc_id(u32 *dev, u32 *rev) } #ifdef CONFIG_SMP +void mvebu_armada375_smp_wa_init(void) +{ + u32 dev, rev; + phys_addr_t resume_addr_reg; + + if (mvebu_get_soc_id(&dev, &rev) != 0) + return; + + if (rev != ARMADA_375_Z1_REV) + return; + + resume_addr_reg = system_controller_phys_base + + mvebu_sc->resume_boot_addr; + mvebu_setup_boot_addr_wa(ARMADA_375_CRYPT0_ENG_TARGET, + ARMADA_375_CRYPT0_ENG_ATTR, + resume_addr_reg); +} + void mvebu_system_controller_set_cpu_boot_addr(void *boot_addr) { BUG_ON(system_controller_base == NULL); BUG_ON(mvebu_sc->resume_boot_addr == 0); + + if (of_machine_is_compatible("marvell,armada375")) + mvebu_armada375_smp_wa_init(); + writel(virt_to_phys(boot_addr), system_controller_base + mvebu_sc->resume_boot_addr); } @@ -138,7 +166,10 @@ static int __init mvebu_system_controller_init(void) np = of_find_matching_node_and_match(NULL, of_system_controller_table, &match); if (np) { + struct resource res; system_controller_base = of_iomap(np, 0); + of_address_to_resource(np, 0, &res); + system_controller_phys_base = res.start; mvebu_sc = (struct mvebu_system_controller *)match->data; of_node_put(np); } -- cgit v1.2.3 From 898ef3e9bfc7f5c94a1e67d0a540e224e2496909 Mon Sep 17 00:00:00 2001 From: Gregory CLEMENT Date: Wed, 23 Jul 2014 15:00:42 +0200 Subject: ARM: mvebu: rename the armada_370_xp symbols to mvebu_v7 in pmsu.c Most of the function related to the PMSU are not specific to the Armada 370 or Armada XP SoCs. They can also be used for most of the other mvebu ARMv7 SoCs, and will actually be used to support cpuidle on Armada 38x. Signed-off-by: Gregory CLEMENT Signed-off-by: Thomas Petazzoni Link: https://lkml.kernel.org/r/1406120453-29291-6-git-send-email-thomas.petazzoni@free-electrons.com Signed-off-by: Jason Cooper --- arch/arm/mach-mvebu/armada-370-xp.h | 1 - arch/arm/mach-mvebu/platsmp.c | 2 +- arch/arm/mach-mvebu/pmsu.c | 34 +++++++++++++++++----------------- arch/arm/mach-mvebu/pmsu.h | 2 ++ 4 files changed, 20 insertions(+), 19 deletions(-) (limited to 'arch/arm/mach-mvebu') diff --git a/arch/arm/mach-mvebu/armada-370-xp.h b/arch/arm/mach-mvebu/armada-370-xp.h index 52c1603a4f92..84cd90d9b860 100644 --- a/arch/arm/mach-mvebu/armada-370-xp.h +++ b/arch/arm/mach-mvebu/armada-370-xp.h @@ -25,6 +25,5 @@ extern struct smp_operations armada_xp_smp_ops; #endif int armada_370_xp_pmsu_idle_enter(unsigned long deepidle); -void armada_370_xp_pmsu_idle_exit(void); #endif /* __MACH_ARMADA_370_XP_H */ diff --git a/arch/arm/mach-mvebu/platsmp.c b/arch/arm/mach-mvebu/platsmp.c index b6fa9f0c98b8..6da2b723d374 100644 --- a/arch/arm/mach-mvebu/platsmp.c +++ b/arch/arm/mach-mvebu/platsmp.c @@ -108,7 +108,7 @@ static int armada_xp_boot_secondary(unsigned int cpu, struct task_struct *idle) */ static void armada_xp_secondary_init(unsigned int cpu) { - armada_370_xp_pmsu_idle_exit(); + mvebu_v7_pmsu_idle_exit(); } static void __init armada_xp_smp_init_cpus(void) diff --git a/arch/arm/mach-mvebu/pmsu.c b/arch/arm/mach-mvebu/pmsu.c index 272a9c0565b2..501d4503d859 100644 --- a/arch/arm/mach-mvebu/pmsu.c +++ b/arch/arm/mach-mvebu/pmsu.c @@ -73,7 +73,7 @@ extern void ll_enable_coherency(void); extern void armada_370_xp_cpu_resume(void); -static struct platform_device armada_xp_cpuidle_device = { +static struct platform_device mvebu_v7_cpuidle_device = { .name = "cpuidle-armada-370-xp", }; @@ -132,7 +132,7 @@ int mvebu_setup_boot_addr_wa(unsigned int crypto_eng_target, return 0; } -static int __init armada_370_xp_pmsu_init(void) +static int __init mvebu_v7_pmsu_init(void) { struct device_node *np; struct resource res; @@ -176,7 +176,7 @@ static int __init armada_370_xp_pmsu_init(void) return ret; } -static void armada_370_xp_pmsu_enable_l2_powerdown_onidle(void) +static void mvebu_v7_pmsu_enable_l2_powerdown_onidle(void) { u32 reg; @@ -190,7 +190,7 @@ static void armada_370_xp_pmsu_enable_l2_powerdown_onidle(void) } /* No locking is needed because we only access per-CPU registers */ -static int armada_370_xp_prepare(unsigned long deepidle) +static int mvebu_v7_pmsu_idle_prepare(bool deepidle) { unsigned int hw_cpu = cpu_logical_map(smp_processor_id()); u32 reg; @@ -233,7 +233,7 @@ int armada_370_xp_pmsu_idle_enter(unsigned long deepidle) { int ret; - ret = armada_370_xp_prepare(deepidle); + ret = mvebu_v7_pmsu_idle_prepare(deepidle); if (ret) return ret; @@ -272,7 +272,7 @@ static int armada_370_xp_cpu_suspend(unsigned long deepidle) } /* No locking is needed because we only access per-CPU registers */ -void armada_370_xp_pmsu_idle_exit(void) +void mvebu_v7_pmsu_idle_exit(void) { unsigned int hw_cpu = cpu_logical_map(smp_processor_id()); u32 reg; @@ -294,24 +294,24 @@ void armada_370_xp_pmsu_idle_exit(void) writel(reg, pmsu_mp_base + PMSU_STATUS_AND_MASK(hw_cpu)); } -static int armada_370_xp_cpu_pm_notify(struct notifier_block *self, +static int mvebu_v7_cpu_pm_notify(struct notifier_block *self, unsigned long action, void *hcpu) { if (action == CPU_PM_ENTER) { unsigned int hw_cpu = cpu_logical_map(smp_processor_id()); mvebu_pmsu_set_cpu_boot_addr(hw_cpu, armada_370_xp_cpu_resume); } else if (action == CPU_PM_EXIT) { - armada_370_xp_pmsu_idle_exit(); + mvebu_v7_pmsu_idle_exit(); } return NOTIFY_OK; } -static struct notifier_block armada_370_xp_cpu_pm_notifier = { - .notifier_call = armada_370_xp_cpu_pm_notify, +static struct notifier_block mvebu_v7_cpu_pm_notifier = { + .notifier_call = mvebu_v7_cpu_pm_notify, }; -static int __init armada_370_xp_cpu_pm_init(void) +static int __init mvebu_v7_cpu_pm_init(void) { struct device_node *np; @@ -334,13 +334,13 @@ static int __init armada_370_xp_cpu_pm_init(void) return 0; of_node_put(np); - armada_370_xp_pmsu_enable_l2_powerdown_onidle(); - armada_xp_cpuidle_device.dev.platform_data = armada_370_xp_cpu_suspend; - platform_device_register(&armada_xp_cpuidle_device); - cpu_pm_register_notifier(&armada_370_xp_cpu_pm_notifier); + mvebu_v7_pmsu_enable_l2_powerdown_onidle(); + mvebu_v7_cpuidle_device.dev.platform_data = armada_370_xp_cpu_suspend; + platform_device_register(&mvebu_v7_cpuidle_device); + cpu_pm_register_notifier(&mvebu_v7_cpu_pm_notifier); return 0; } -arch_initcall(armada_370_xp_cpu_pm_init); -early_initcall(armada_370_xp_pmsu_init); +arch_initcall(mvebu_v7_cpu_pm_init); +early_initcall(mvebu_v7_pmsu_init); diff --git a/arch/arm/mach-mvebu/pmsu.h b/arch/arm/mach-mvebu/pmsu.h index ae501948ec73..6b58c1fe2b0d 100644 --- a/arch/arm/mach-mvebu/pmsu.h +++ b/arch/arm/mach-mvebu/pmsu.h @@ -16,4 +16,6 @@ int mvebu_setup_boot_addr_wa(unsigned int crypto_eng_target, unsigned int crypto_eng_attribute, phys_addr_t resume_addr_reg); +void mvebu_v7_pmsu_idle_exit(void); + #endif /* __MACH_370_XP_PMSU_H */ -- cgit v1.2.3 From 54a4d1b8d4ca808f46fc3ad3fd9b2c6fd79286a9 Mon Sep 17 00:00:00 2001 From: Gregory CLEMENT Date: Wed, 23 Jul 2014 15:00:43 +0200 Subject: ARM: mvebu: make the cpuidle initialization more generic In preparation to the addition of the cpuidle support for more SoCs, this patch moves the Armada XP specific initialization to a separate function. Signed-off-by: Gregory CLEMENT Signed-off-by: Thomas Petazzoni Link: https://lkml.kernel.org/r/1406120453-29291-7-git-send-email-thomas.petazzoni@free-electrons.com Signed-off-by: Jason Cooper --- arch/arm/mach-mvebu/pmsu.c | 32 ++++++++++++++++++++------------ 1 file changed, 20 insertions(+), 12 deletions(-) (limited to 'arch/arm/mach-mvebu') diff --git a/arch/arm/mach-mvebu/pmsu.c b/arch/arm/mach-mvebu/pmsu.c index 501d4503d859..e976c3e5e1fe 100644 --- a/arch/arm/mach-mvebu/pmsu.c +++ b/arch/arm/mach-mvebu/pmsu.c @@ -311,31 +311,39 @@ static struct notifier_block mvebu_v7_cpu_pm_notifier = { .notifier_call = mvebu_v7_cpu_pm_notify, }; -static int __init mvebu_v7_cpu_pm_init(void) +static int __init armada_xp_cpuidle_init(void) { struct device_node *np; - /* - * Check that all the requirements are available to enable - * cpuidle. So far, it is only supported on Armada XP, cpuidle - * needs the coherency fabric and the PMSU enabled - */ - - if (!of_machine_is_compatible("marvell,armadaxp")) - return 0; - np = of_find_compatible_node(NULL, NULL, "marvell,coherency-fabric"); if (!np) - return 0; + return -ENODEV; of_node_put(np); + mvebu_v7_cpuidle_device.dev.platform_data = armada_370_xp_cpu_suspend; + + return 0; +} + +static int __init mvebu_v7_cpu_pm_init(void) +{ + struct device_node *np; + int ret; + np = of_find_matching_node(NULL, of_pmsu_table); if (!np) return 0; of_node_put(np); + if (of_machine_is_compatible("marvell,armadaxp")) + ret = armada_xp_cpuidle_init(); + else + return 0; + + if (ret) + return ret; + mvebu_v7_pmsu_enable_l2_powerdown_onidle(); - mvebu_v7_cpuidle_device.dev.platform_data = armada_370_xp_cpu_suspend; platform_device_register(&mvebu_v7_cpuidle_device); cpu_pm_register_notifier(&mvebu_v7_cpu_pm_notifier); -- cgit v1.2.3 From 752a99377673cd251517623df138ca3c5b8fe772 Mon Sep 17 00:00:00 2001 From: Gregory CLEMENT Date: Wed, 23 Jul 2014 15:00:44 +0200 Subject: ARM: mvebu: use a local variable to store the resume address The resume address used by the cpuidle code will not always be the same depending on the SoC. Using a local variable to store the resume address allows to keep the same function for the PM notifier but with a different address. This address will be set during the initialization of the cpuidle logic in pmsu.c. Signed-off-by: Gregory CLEMENT Signed-off-by: Thomas Petazzoni Link: https://lkml.kernel.org/r/1406120453-29291-8-git-send-email-thomas.petazzoni@free-electrons.com Signed-off-by: Jason Cooper --- arch/arm/mach-mvebu/pmsu.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) (limited to 'arch/arm/mach-mvebu') diff --git a/arch/arm/mach-mvebu/pmsu.c b/arch/arm/mach-mvebu/pmsu.c index e976c3e5e1fe..ab525b7bfc03 100644 --- a/arch/arm/mach-mvebu/pmsu.c +++ b/arch/arm/mach-mvebu/pmsu.c @@ -73,6 +73,8 @@ extern void ll_enable_coherency(void); extern void armada_370_xp_cpu_resume(void); +static void *mvebu_cpu_resume; + static struct platform_device mvebu_v7_cpuidle_device = { .name = "cpuidle-armada-370-xp", }; @@ -299,7 +301,7 @@ static int mvebu_v7_cpu_pm_notify(struct notifier_block *self, { if (action == CPU_PM_ENTER) { unsigned int hw_cpu = cpu_logical_map(smp_processor_id()); - mvebu_pmsu_set_cpu_boot_addr(hw_cpu, armada_370_xp_cpu_resume); + mvebu_pmsu_set_cpu_boot_addr(hw_cpu, mvebu_cpu_resume); } else if (action == CPU_PM_EXIT) { mvebu_v7_pmsu_idle_exit(); } @@ -320,6 +322,7 @@ static int __init armada_xp_cpuidle_init(void) return -ENODEV; of_node_put(np); + mvebu_cpu_resume = armada_370_xp_cpu_resume; mvebu_v7_cpuidle_device.dev.platform_data = armada_370_xp_cpu_suspend; return 0; -- cgit v1.2.3 From 5da964e0fae05fd96a97a0fcc6bc53dad655f61d Mon Sep 17 00:00:00 2001 From: Gregory CLEMENT Date: Wed, 23 Jul 2014 15:00:45 +0200 Subject: ARM: mvebu: make the snoop disabling optional in mvebu_v7_pmsu_idle_prepare() On some mvebu v7 SoCs (the ones using a Cortex-A9 core and not a PJ4B core), the snoop disabling feature does not exist as the hardware coherency is handled in a different way. Therefore, in preparation to the introduction of the cpuidle support for those SoCs, this commit modifies the mvebu_v7_psmu_idle_prepare() function to take several flags, which allow to decide whether snooping should be disabled, and whether we should use the deep idle mode or not. Signed-off-by: Gregory CLEMENT Signed-off-by: Thomas Petazzoni Link: https://lkml.kernel.org/r/1406120453-29291-9-git-send-email-thomas.petazzoni@free-electrons.com Signed-off-by: Jason Cooper --- arch/arm/mach-mvebu/pmsu.c | 26 +++++++++++++++++++------- 1 file changed, 19 insertions(+), 7 deletions(-) (limited to 'arch/arm/mach-mvebu') diff --git a/arch/arm/mach-mvebu/pmsu.c b/arch/arm/mach-mvebu/pmsu.c index ab525b7bfc03..15e67bf67c1c 100644 --- a/arch/arm/mach-mvebu/pmsu.c +++ b/arch/arm/mach-mvebu/pmsu.c @@ -191,8 +191,14 @@ static void mvebu_v7_pmsu_enable_l2_powerdown_onidle(void) writel(reg, pmsu_mp_base + L2C_NFABRIC_PM_CTL); } +enum pmsu_idle_prepare_flags { + PMSU_PREPARE_NORMAL = 0, + PMSU_PREPARE_DEEP_IDLE = BIT(0), + PMSU_PREPARE_SNOOP_DISABLE = BIT(1), +}; + /* No locking is needed because we only access per-CPU registers */ -static int mvebu_v7_pmsu_idle_prepare(bool deepidle) +static int mvebu_v7_pmsu_idle_prepare(unsigned long flags) { unsigned int hw_cpu = cpu_logical_map(smp_processor_id()); u32 reg; @@ -216,26 +222,32 @@ static int mvebu_v7_pmsu_idle_prepare(bool deepidle) reg = readl(pmsu_mp_base + PMSU_CONTROL_AND_CONFIG(hw_cpu)); /* ask HW to power down the L2 Cache if needed */ - if (deepidle) + if (flags & PMSU_PREPARE_DEEP_IDLE) reg |= PMSU_CONTROL_AND_CONFIG_L2_PWDDN; /* request power down */ reg |= PMSU_CONTROL_AND_CONFIG_PWDDN_REQ; writel(reg, pmsu_mp_base + PMSU_CONTROL_AND_CONFIG(hw_cpu)); - /* Disable snoop disable by HW - SW is taking care of it */ - reg = readl(pmsu_mp_base + PMSU_CPU_POWER_DOWN_CONTROL(hw_cpu)); - reg |= PMSU_CPU_POWER_DOWN_DIS_SNP_Q_SKIP; - writel(reg, pmsu_mp_base + PMSU_CPU_POWER_DOWN_CONTROL(hw_cpu)); + if (flags & PMSU_PREPARE_SNOOP_DISABLE) { + /* Disable snoop disable by HW - SW is taking care of it */ + reg = readl(pmsu_mp_base + PMSU_CPU_POWER_DOWN_CONTROL(hw_cpu)); + reg |= PMSU_CPU_POWER_DOWN_DIS_SNP_Q_SKIP; + writel(reg, pmsu_mp_base + PMSU_CPU_POWER_DOWN_CONTROL(hw_cpu)); + } return 0; } int armada_370_xp_pmsu_idle_enter(unsigned long deepidle) { + unsigned long flags = PMSU_PREPARE_SNOOP_DISABLE; int ret; - ret = mvebu_v7_pmsu_idle_prepare(deepidle); + if (deepidle) + flags |= PMSU_PREPARE_DEEP_IDLE; + + ret = mvebu_v7_pmsu_idle_prepare(flags); if (ret) return ret; -- cgit v1.2.3 From 6a2b5343e23b177e684f97302f30696dfcfe0af4 Mon Sep 17 00:00:00 2001 From: Gregory CLEMENT Date: Wed, 23 Jul 2014 15:00:46 +0200 Subject: ARM: mvebu: export the SCU address The SCU address will be needed in other files than board-v7.c, especially in pmsu.c for cpuidle related activities. So this patch adds a function that allows to retrieve the virtual address at which the SCU has been mapped. Signed-off-by: Gregory CLEMENT Signed-off-by: Thomas Petazzoni Link: https://lkml.kernel.org/r/1406120453-29291-10-git-send-email-thomas.petazzoni@free-electrons.com Signed-off-by: Jason Cooper --- arch/arm/mach-mvebu/board-v7.c | 9 +++++++-- arch/arm/mach-mvebu/common.h | 2 ++ 2 files changed, 9 insertions(+), 2 deletions(-) (limited to 'arch/arm/mach-mvebu') diff --git a/arch/arm/mach-mvebu/board-v7.c b/arch/arm/mach-mvebu/board-v7.c index f244622ffc00..6478626e3ff6 100644 --- a/arch/arm/mach-mvebu/board-v7.c +++ b/arch/arm/mach-mvebu/board-v7.c @@ -34,14 +34,14 @@ #include "coherency.h" #include "mvebu-soc-id.h" +static void __iomem *scu_base; + /* * Enables the SCU when available. Obviously, this is only useful on * Cortex-A based SOCs, not on PJ4B based ones. */ static void __init mvebu_scu_enable(void) { - void __iomem *scu_base; - struct device_node *np = of_find_compatible_node(NULL, NULL, "arm,cortex-a9-scu"); if (np) { @@ -51,6 +51,11 @@ static void __init mvebu_scu_enable(void) } } +void __iomem *mvebu_get_scu_base(void) +{ + return scu_base; +} + /* * Early versions of Armada 375 SoC have a bug where the BootROM * leaves an external data abort pending. The kernel is hit by this diff --git a/arch/arm/mach-mvebu/common.h b/arch/arm/mach-mvebu/common.h index a97778e28bf6..3ccb40c3bf94 100644 --- a/arch/arm/mach-mvebu/common.h +++ b/arch/arm/mach-mvebu/common.h @@ -23,4 +23,6 @@ void mvebu_pmsu_set_cpu_boot_addr(int hw_cpu, void *boot_addr); void mvebu_system_controller_set_cpu_boot_addr(void *boot_addr); int mvebu_system_controller_get_soc_id(u32 *dev, u32 *rev); +void __iomem *mvebu_get_scu_base(void); + #endif -- cgit v1.2.3 From f50ee824713863016dd684fe43c9eb472963f4fd Mon Sep 17 00:00:00 2001 From: Gregory CLEMENT Date: Wed, 23 Jul 2014 15:00:48 +0200 Subject: cpuidle: mvebu: rename the driver from armada-370-xp to mvebu-v7 This driver will be able to manage the cpuidle for more SoCs than just Armada 370 and XP. It will also support Armada 38x and potentially other SoC of the Marvell Armada EBU family. To take this into account, this patch renames the driver and its symbols. It also changes the driver name from cpuidle-armada-370-xp to cpuidle-armada-xp, because separate platform drivers will be registered for the other SoC types. This change must be done simultaneously in the cpuidle driver and in the PMSU code in order to remain bisectable. Signed-off-by: Gregory CLEMENT Signed-off-by: Thomas Petazzoni Acked-by: Daniel Lezcano Link: https://lkml.kernel.org/r/1406120453-29291-12-git-send-email-thomas.petazzoni@free-electrons.com Signed-off-by: Jason Cooper --- arch/arm/mach-mvebu/pmsu.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'arch/arm/mach-mvebu') diff --git a/arch/arm/mach-mvebu/pmsu.c b/arch/arm/mach-mvebu/pmsu.c index 15e67bf67c1c..0cd2d09475aa 100644 --- a/arch/arm/mach-mvebu/pmsu.c +++ b/arch/arm/mach-mvebu/pmsu.c @@ -76,7 +76,7 @@ extern void armada_370_xp_cpu_resume(void); static void *mvebu_cpu_resume; static struct platform_device mvebu_v7_cpuidle_device = { - .name = "cpuidle-armada-370-xp", + .name = "cpuidle-armada-xp", }; static struct of_device_id of_pmsu_table[] = { -- cgit v1.2.3 From 3b9e4b1441aedcb26079f690aa11f3f9f93e5182 Mon Sep 17 00:00:00 2001 From: Gregory CLEMENT Date: Wed, 23 Jul 2014 15:00:51 +0200 Subject: ARM: mvebu: add cpuidle support for Armada 370 This commit introduces the cpuidle support for Armada 370. The main difference compared to the already supported Armada XP is that the Armada 370 has an issue caused by "a slow exit process from the deep idle state due to heavy L1/L2 cache cleanup operations performed by the BootROM software" (cf errata GL-BootROM-10). To work around this issue, we replace the restart code of the BootROM by some custom code located in an internal SRAM. For this purpose, we use the common function mvebu_boot_addr_wa() introduced in the commit "ARM: mvebu: Add a common function for the boot address work around". The message in case of failure to suspend the system was switched from the warn level to the debug level. Indeed due to the "slow exit process from the deep idle state" in Armada 370, this situation happens quite often. Using the debug level avoids spamming the kernel logs, but still allows to enable it if needed. Signed-off-by: Gregory CLEMENT Signed-off-by: Thomas Petazzoni Link: https://lkml.kernel.org/r/1406120453-29291-15-git-send-email-thomas.petazzoni@free-electrons.com Signed-off-by: Jason Cooper --- arch/arm/mach-mvebu/pmsu.c | 51 +++++++++++++++++++++++++++++++++++++++------- 1 file changed, 44 insertions(+), 7 deletions(-) (limited to 'arch/arm/mach-mvebu') diff --git a/arch/arm/mach-mvebu/pmsu.c b/arch/arm/mach-mvebu/pmsu.c index 0cd2d09475aa..9190ae8626cf 100644 --- a/arch/arm/mach-mvebu/pmsu.c +++ b/arch/arm/mach-mvebu/pmsu.c @@ -34,7 +34,6 @@ #include #include "common.h" -static void __iomem *pmsu_mp_base; #define PMSU_BASE_OFFSET 0x100 #define PMSU_REG_SIZE 0x1000 @@ -68,17 +67,18 @@ static void __iomem *pmsu_mp_base; #define BOOTROM_BASE 0xFFF00000 #define BOOTROM_SIZE 0x100000 +#define ARMADA_370_CRYPT0_ENG_TARGET 0x9 +#define ARMADA_370_CRYPT0_ENG_ATTR 0x1 + extern void ll_disable_coherency(void); extern void ll_enable_coherency(void); extern void armada_370_xp_cpu_resume(void); +static phys_addr_t pmsu_mp_phys_base; +static void __iomem *pmsu_mp_base; static void *mvebu_cpu_resume; -static struct platform_device mvebu_v7_cpuidle_device = { - .name = "cpuidle-armada-xp", -}; - static struct of_device_id of_pmsu_table[] = { { .compatible = "marvell,armada-370-pmsu", }, { .compatible = "marvell,armada-370-xp-pmsu", }, @@ -165,6 +165,8 @@ static int __init mvebu_v7_pmsu_init(void) goto out; } + pmsu_mp_phys_base = res.start; + pmsu_mp_base = ioremap(res.start, resource_size(&res)); if (!pmsu_mp_base) { pr_err("unable to map registers\n"); @@ -275,7 +277,7 @@ int armada_370_xp_pmsu_idle_enter(unsigned long deepidle) "isb " : : : "r0"); - pr_warn("Failed to suspend the system\n"); + pr_debug("Failed to suspend the system\n"); return 0; } @@ -325,7 +327,39 @@ static struct notifier_block mvebu_v7_cpu_pm_notifier = { .notifier_call = mvebu_v7_cpu_pm_notify, }; -static int __init armada_xp_cpuidle_init(void) +static struct platform_device mvebu_v7_cpuidle_device; + +static __init int armada_370_cpuidle_init(void) +{ + struct device_node *np; + phys_addr_t redirect_reg; + + np = of_find_compatible_node(NULL, NULL, "marvell,coherency-fabric"); + if (!np) + return -ENODEV; + of_node_put(np); + + /* + * On Armada 370, there is "a slow exit process from the deep + * idle state due to heavy L1/L2 cache cleanup operations + * performed by the BootROM software". To avoid this, we + * replace the restart code of the bootrom by a a simple jump + * to the boot address. Then the code located at this boot + * address will take care of the initialization. + */ + redirect_reg = pmsu_mp_phys_base + PMSU_BOOT_ADDR_REDIRECT_OFFSET(0); + mvebu_setup_boot_addr_wa(ARMADA_370_CRYPT0_ENG_TARGET, + ARMADA_370_CRYPT0_ENG_ATTR, + redirect_reg); + + mvebu_cpu_resume = armada_370_xp_cpu_resume; + mvebu_v7_cpuidle_device.dev.platform_data = armada_370_xp_cpu_suspend; + mvebu_v7_cpuidle_device.name = "cpuidle-armada-370"; + + return 0; +} + +static __init int armada_xp_cpuidle_init(void) { struct device_node *np; @@ -336,6 +370,7 @@ static int __init armada_xp_cpuidle_init(void) mvebu_cpu_resume = armada_370_xp_cpu_resume; mvebu_v7_cpuidle_device.dev.platform_data = armada_370_xp_cpu_suspend; + mvebu_v7_cpuidle_device.name = "cpuidle-armada-xp"; return 0; } @@ -352,6 +387,8 @@ static int __init mvebu_v7_cpu_pm_init(void) if (of_machine_is_compatible("marvell,armadaxp")) ret = armada_xp_cpuidle_init(); + else if (of_machine_is_compatible("marvell,armada370")) + ret = armada_370_cpuidle_init(); else return 0; -- cgit v1.2.3 From e53b1fd432497942a0fdfd0e89c3d30241cb4d2c Mon Sep 17 00:00:00 2001 From: Gregory CLEMENT Date: Wed, 23 Jul 2014 15:00:52 +0200 Subject: ARM: mvebu: add cpuidle support for Armada 38x Unlike the Armada XP and the Armada 370, this SoC uses a Cortex A9 core. Consequently, the procedure to enter the idle state is different: interaction with the SCU, not disabling snooping, etc. Signed-off-by: Gregory CLEMENT Signed-off-by: Thomas Petazzoni Link: https://lkml.kernel.org/r/1406120453-29291-16-git-send-email-thomas.petazzoni@free-electrons.com Signed-off-by: Jason Cooper --- arch/arm/mach-mvebu/pmsu.c | 85 ++++++++++++++++++++++++++++++++++++++++++- arch/arm/mach-mvebu/pmsu_ll.S | 14 +++++++ 2 files changed, 98 insertions(+), 1 deletion(-) (limited to 'arch/arm/mach-mvebu') diff --git a/arch/arm/mach-mvebu/pmsu.c b/arch/arm/mach-mvebu/pmsu.c index 9190ae8626cf..bd7c66a28826 100644 --- a/arch/arm/mach-mvebu/pmsu.c +++ b/arch/arm/mach-mvebu/pmsu.c @@ -29,6 +29,7 @@ #include #include #include +#include #include #include #include @@ -63,6 +64,18 @@ #define L2C_NFABRIC_PM_CTL 0x4 #define L2C_NFABRIC_PM_CTL_PWR_DOWN BIT(20) +/* PMSU delay registers */ +#define PMSU_POWERDOWN_DELAY 0xF04 +#define PMSU_POWERDOWN_DELAY_PMU BIT(1) +#define PMSU_POWERDOWN_DELAY_MASK 0xFFFE +#define PMSU_DFLT_ARMADA38X_DELAY 0x64 + +/* CA9 MPcore SoC Control registers */ + +#define MPCORE_RESET_CTL 0x64 +#define MPCORE_RESET_CTL_L2 BIT(0) +#define MPCORE_RESET_CTL_DEBUG BIT(16) + #define SRAM_PHYS_BASE 0xFFFF0000 #define BOOTROM_BASE 0xFFF00000 #define BOOTROM_SIZE 0x100000 @@ -74,6 +87,8 @@ extern void ll_disable_coherency(void); extern void ll_enable_coherency(void); extern void armada_370_xp_cpu_resume(void); +extern void armada_38x_cpu_resume(void); + static phys_addr_t pmsu_mp_phys_base; static void __iomem *pmsu_mp_base; @@ -287,6 +302,32 @@ static int armada_370_xp_cpu_suspend(unsigned long deepidle) return cpu_suspend(deepidle, armada_370_xp_pmsu_idle_enter); } +static int armada_38x_do_cpu_suspend(unsigned long deepidle) +{ + unsigned long flags = 0; + + if (deepidle) + flags |= PMSU_PREPARE_DEEP_IDLE; + + mvebu_v7_pmsu_idle_prepare(flags); + /* + * Already flushed cache, but do it again as the outer cache + * functions dirty the cache with spinlocks + */ + v7_exit_coherency_flush(louis); + + scu_power_mode(mvebu_get_scu_base(), SCU_PM_POWEROFF); + + cpu_do_idle(); + + return 1; +} + +static int armada_38x_cpu_suspend(unsigned long deepidle) +{ + return cpu_suspend(false, armada_38x_do_cpu_suspend); +} + /* No locking is needed because we only access per-CPU registers */ void mvebu_v7_pmsu_idle_exit(void) { @@ -295,7 +336,6 @@ void mvebu_v7_pmsu_idle_exit(void) if (pmsu_mp_base == NULL) return; - /* cancel ask HW to power down the L2 Cache if possible */ reg = readl(pmsu_mp_base + PMSU_CONTROL_AND_CONFIG(hw_cpu)); reg &= ~PMSU_CONTROL_AND_CONFIG_L2_PWDDN; @@ -359,6 +399,47 @@ static __init int armada_370_cpuidle_init(void) return 0; } +static __init int armada_38x_cpuidle_init(void) +{ + struct device_node *np; + void __iomem *mpsoc_base; + u32 reg; + + np = of_find_compatible_node(NULL, NULL, + "marvell,armada-380-coherency-fabric"); + if (!np) + return -ENODEV; + of_node_put(np); + + np = of_find_compatible_node(NULL, NULL, + "marvell,armada-380-mpcore-soc-ctrl"); + if (!np) + return -ENODEV; + mpsoc_base = of_iomap(np, 0); + BUG_ON(!mpsoc_base); + of_node_put(np); + + /* Set up reset mask when powering down the cpus */ + reg = readl(mpsoc_base + MPCORE_RESET_CTL); + reg |= MPCORE_RESET_CTL_L2; + reg |= MPCORE_RESET_CTL_DEBUG; + writel(reg, mpsoc_base + MPCORE_RESET_CTL); + iounmap(mpsoc_base); + + /* Set up delay */ + reg = readl(pmsu_mp_base + PMSU_POWERDOWN_DELAY); + reg &= ~PMSU_POWERDOWN_DELAY_MASK; + reg |= PMSU_DFLT_ARMADA38X_DELAY; + reg |= PMSU_POWERDOWN_DELAY_PMU; + writel(reg, pmsu_mp_base + PMSU_POWERDOWN_DELAY); + + mvebu_cpu_resume = armada_38x_cpu_resume; + mvebu_v7_cpuidle_device.dev.platform_data = armada_38x_cpu_suspend; + mvebu_v7_cpuidle_device.name = "cpuidle-armada-38x"; + + return 0; +} + static __init int armada_xp_cpuidle_init(void) { struct device_node *np; @@ -389,6 +470,8 @@ static int __init mvebu_v7_cpu_pm_init(void) ret = armada_xp_cpuidle_init(); else if (of_machine_is_compatible("marvell,armada370")) ret = armada_370_cpuidle_init(); + else if (of_machine_is_compatible("marvell,armada380")) + ret = armada_38x_cpuidle_init(); else return 0; diff --git a/arch/arm/mach-mvebu/pmsu_ll.S b/arch/arm/mach-mvebu/pmsu_ll.S index 17d7f3b3976d..a945756cfb45 100644 --- a/arch/arm/mach-mvebu/pmsu_ll.S +++ b/arch/arm/mach-mvebu/pmsu_ll.S @@ -23,6 +23,20 @@ ARM_BE8(setend be ) @ go BE8 if entered LE b cpu_resume ENDPROC(armada_370_xp_cpu_resume) +ENTRY(armada_38x_cpu_resume) + /* do we need it for Armada 38x*/ +ARM_BE8(setend be ) @ go BE8 if entered LE + bl v7_invalidate_l1 + mrc p15, 4, r1, c15, c0 @ get SCU base address + orr r1, r1, #0x8 @ SCU CPU Power Status Register + mrc 15, 0, r0, cr0, cr0, 5 @ get the CPU ID + and r0, r0, #15 + add r1, r1, r0 + mov r0, #0x0 + strb r0, [r1] @ switch SCU power state to Normal mode + b cpu_resume +ENDPROC(armada_38x_cpu_resume) + .global mvebu_boot_wa_start .global mvebu_boot_wa_end -- cgit v1.2.3 From ce800342c80704e5efa4d6440f1c04c83a044499 Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Wed, 23 Jul 2014 23:05:49 +0200 Subject: ARM: mvebu: fix build without platforms selected When building a multiplatform kernel that enables 'ARCH_MVEBU' but none of the individual options under it, we get this link error: arch/arm/mach-mvebu/built-in.o: In function `mvebu_armada375_smp_wa_init': :(.text+0x190): undefined reference to `mvebu_setup_boot_addr_wa' The best solution seems to be to ensure that in this configuration, we don't actually build any of the mvebu code. Signed-off-by: Arnd Bergmann Link: https://lkml.kernel.org/r/7339332.ZE2mWIdyDh@wuerfel Signed-off-by: Jason Cooper --- arch/arm/mach-mvebu/Kconfig | 6 ++++++ arch/arm/mach-mvebu/Makefile | 2 +- 2 files changed, 7 insertions(+), 1 deletion(-) (limited to 'arch/arm/mach-mvebu') diff --git a/arch/arm/mach-mvebu/Kconfig b/arch/arm/mach-mvebu/Kconfig index 8e3b5f12cd7c..ae417607e108 100644 --- a/arch/arm/mach-mvebu/Kconfig +++ b/arch/arm/mach-mvebu/Kconfig @@ -16,11 +16,15 @@ if ARCH_MVEBU menu "Marvell EBU SoC variants" +config MACH_MVEBU_ANY + bool + config MACH_MVEBU_V7 bool select ARMADA_370_XP_TIMER select CACHE_L2X0 select ARM_CPU_SUSPEND + select MACH_MVEBU_ANY config MACH_ARMADA_370 bool "Marvell Armada 370 boards" if ARCH_MULTI_V7 @@ -77,6 +81,7 @@ config MACH_DOVE select CACHE_L2X0 select CPU_PJ4 select DOVE_CLK + select MACH_MVEBU_ANY select ORION_IRQCHIP select ORION_TIMER select PINCTRL_DOVE @@ -90,6 +95,7 @@ config MACH_KIRKWOOD select ARCH_REQUIRE_GPIOLIB select CPU_FEROCEON select KIRKWOOD_CLK + select MACH_MVEBU_ANY select ORION_IRQCHIP select ORION_TIMER select PCI diff --git a/arch/arm/mach-mvebu/Makefile b/arch/arm/mach-mvebu/Makefile index bc7689e530a4..e24136b42765 100644 --- a/arch/arm/mach-mvebu/Makefile +++ b/arch/arm/mach-mvebu/Makefile @@ -4,7 +4,7 @@ ccflags-$(CONFIG_ARCH_MULTIPLATFORM) := -I$(srctree)/$(src)/include \ AFLAGS_coherency_ll.o := -Wa,-march=armv7-a CFLAGS_pmsu.o := -march=armv7-a -obj-y += system-controller.o mvebu-soc-id.o +obj-$(CONFIG_MACH_MVEBU_ANY) += system-controller.o mvebu-soc-id.o ifeq ($(CONFIG_MACH_MVEBU_V7),y) obj-y += cpu-reset.o board-v7.o coherency.o coherency_ll.o pmsu.o pmsu_ll.o -- cgit v1.2.3