diff options
Diffstat (limited to 'kernel/arch/arm/mach-mvebu')
-rw-r--r-- | kernel/arch/arm/mach-mvebu/Kconfig | 8 | ||||
-rw-r--r-- | kernel/arch/arm/mach-mvebu/Makefile | 1 | ||||
-rw-r--r-- | kernel/arch/arm/mach-mvebu/board-v7.c | 36 | ||||
-rw-r--r-- | kernel/arch/arm/mach-mvebu/board.h | 21 | ||||
-rw-r--r-- | kernel/arch/arm/mach-mvebu/coherency.c | 81 | ||||
-rw-r--r-- | kernel/arch/arm/mach-mvebu/common.h | 4 | ||||
-rw-r--r-- | kernel/arch/arm/mach-mvebu/dove.c | 2 | ||||
-rw-r--r-- | kernel/arch/arm/mach-mvebu/headsmp-a9.S | 3 | ||||
-rw-r--r-- | kernel/arch/arm/mach-mvebu/kirkwood.c | 4 | ||||
-rw-r--r-- | kernel/arch/arm/mach-mvebu/netxbig.c | 191 | ||||
-rw-r--r-- | kernel/arch/arm/mach-mvebu/platsmp-a9.c | 2 | ||||
-rw-r--r-- | kernel/arch/arm/mach-mvebu/pm-board.c | 30 | ||||
-rw-r--r-- | kernel/arch/arm/mach-mvebu/pm.c | 79 | ||||
-rw-r--r-- | kernel/arch/arm/mach-mvebu/pmsu.c | 37 |
14 files changed, 193 insertions, 306 deletions
diff --git a/kernel/arch/arm/mach-mvebu/Kconfig b/kernel/arch/arm/mach-mvebu/Kconfig index 97473168d..e20fc4178 100644 --- a/kernel/arch/arm/mach-mvebu/Kconfig +++ b/kernel/arch/arm/mach-mvebu/Kconfig @@ -96,6 +96,7 @@ config MACH_DOVE select MACH_MVEBU_ANY select ORION_IRQCHIP select ORION_TIMER + select PM_GENERIC_DOMAINS if PM select PINCTRL_DOVE help Say 'Y' here if you want your kernel to support the @@ -116,11 +117,4 @@ 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 - endif diff --git a/kernel/arch/arm/mach-mvebu/Makefile b/kernel/arch/arm/mach-mvebu/Makefile index b4f01497c..ecf9e0c3b 100644 --- a/kernel/arch/arm/mach-mvebu/Makefile +++ b/kernel/arch/arm/mach-mvebu/Makefile @@ -13,4 +13,3 @@ 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/kernel/arch/arm/mach-mvebu/board-v7.c b/kernel/arch/arm/mach-mvebu/board-v7.c index afee9083a..1648edd51 100644 --- a/kernel/arch/arm/mach-mvebu/board-v7.c +++ b/kernel/arch/arm/mach-mvebu/board-v7.c @@ -14,7 +14,6 @@ #include <linux/kernel.h> #include <linux/init.h> -#include <linux/clk-provider.h> #include <linux/of_address.h> #include <linux/of_fdt.h> #include <linux/of_platform.h> @@ -23,7 +22,6 @@ #include <linux/dma-mapping.h> #include <linux/memblock.h> #include <linux/mbus.h> -#include <linux/signal.h> #include <linux/slab.h> #include <linux/irqchip.h> #include <asm/hardware/cache-l2x0.h> @@ -106,27 +104,6 @@ static void __init mvebu_memblock_reserve(void) static void __init mvebu_memblock_reserve(void) {} #endif -/* - * Early versions of Armada 375 SoC have a bug where the BootROM - * leaves an external data abort pending. The kernel is hit by this - * data abort as soon as it enters userspace, because it unmasks the - * data aborts at this moment. We register a custom abort handler - * below to ignore the first data abort to work around this - * problem. - */ -static int armada_375_external_abort_wa(unsigned long addr, unsigned int fsr, - struct pt_regs *regs) -{ - static int ignore_first; - - if (!ignore_first && fsr == 0x1406) { - ignore_first = 1; - return 0; - } - - return 1; -} - static void __init mvebu_init_irq(void) { irqchip_init(); @@ -135,17 +112,6 @@ static void __init mvebu_init_irq(void) BUG_ON(mvebu_mbus_dt_init(coherency_available())); } -static void __init external_abort_quirk(void) -{ - u32 dev, rev; - - if (mvebu_get_soc_id(&dev, &rev) == 0 && rev > ARMADA_375_Z1_REV) - return; - - hook_fault_code(16 + 6, armada_375_external_abort_wa, SIGBUS, 0, - "imprecise external abort"); -} - static void __init i2c_quirk(void) { struct device_node *np; @@ -178,8 +144,6 @@ static void __init mvebu_dt_init(void) { if (of_machine_is_compatible("marvell,armadaxp")) i2c_quirk(); - if (of_machine_is_compatible("marvell,a375-db")) - external_abort_quirk(); of_platform_populate(NULL, of_default_bus_match_table, NULL, NULL); } diff --git a/kernel/arch/arm/mach-mvebu/board.h b/kernel/arch/arm/mach-mvebu/board.h deleted file mode 100644 index 98e32cc2e..000000000 --- a/kernel/arch/arm/mach-mvebu/board.h +++ /dev/null @@ -1,21 +0,0 @@ -/* - * Board functions for Marvell System On Chip - * - * Copyright (C) 2014 - * - * Andrew Lunn <andrew@lunn.ch> - * - * 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. - */ - -#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/kernel/arch/arm/mach-mvebu/coherency.c b/kernel/arch/arm/mach-mvebu/coherency.c index e46e9ea1e..55348ee5a 100644 --- a/kernel/arch/arm/mach-mvebu/coherency.c +++ b/kernel/arch/arm/mach-mvebu/coherency.c @@ -40,6 +40,7 @@ unsigned long coherency_phys_base; void __iomem *coherency_base; static void __iomem *coherency_cpu_base; +static void __iomem *cpu_config_base; /* Coherency fabric registers */ #define IO_SYNC_BARRIER_CTL_OFFSET 0x0 @@ -65,16 +66,29 @@ static const struct of_device_id of_coherency_table[] = { int ll_enable_coherency(void); void ll_add_cpu_to_smp_group(void); -int set_cpu_coherent(void) +#define CPU_CONFIG_SHARED_L2 BIT(16) + +/* + * Disable the "Shared L2 Present" bit in CPU Configuration register + * on Armada XP. + * + * The "Shared L2 Present" bit affects the "level of coherence" value + * in the clidr CP15 register. Cache operation functions such as + * "flush all" and "invalidate all" operate on all the cache levels + * that included in the defined level of coherence. When HW I/O + * coherency is used, this bit causes unnecessary flushes of the L2 + * cache. + */ +static void armada_xp_clear_shared_l2(void) { - if (!coherency_base) { - pr_warn("Can't make current CPU cache coherent.\n"); - pr_warn("Coherency fabric is not initialized\n"); - return 1; - } + u32 reg; + + if (!cpu_config_base) + return; - ll_add_cpu_to_smp_group(); - return ll_enable_coherency(); + reg = readl(cpu_config_base); + reg &= ~CPU_CONFIG_SHARED_L2; + writel(reg, cpu_config_base); } static int mvebu_hwcc_notifier(struct notifier_block *nb, @@ -97,9 +111,24 @@ static struct notifier_block mvebu_hwcc_pci_nb = { .notifier_call = mvebu_hwcc_notifier, }; +static int armada_xp_clear_shared_l2_notifier_func(struct notifier_block *nfb, + unsigned long action, void *hcpu) +{ + if (action == CPU_STARTING || action == CPU_STARTING_FROZEN) + armada_xp_clear_shared_l2(); + + return NOTIFY_OK; +} + +static struct notifier_block armada_xp_clear_shared_l2_notifier = { + .notifier_call = armada_xp_clear_shared_l2_notifier_func, + .priority = 100, +}; + static void __init armada_370_coherency_init(struct device_node *np) { struct resource res; + struct device_node *cpu_config_np; of_address_to_resource(np, 0, &res); coherency_phys_base = res.start; @@ -112,6 +141,23 @@ static void __init armada_370_coherency_init(struct device_node *np) sync_cache_w(&coherency_phys_base); coherency_base = of_iomap(np, 0); coherency_cpu_base = of_iomap(np, 1); + + cpu_config_np = of_find_compatible_node(NULL, NULL, + "marvell,armada-xp-cpu-config"); + if (!cpu_config_np) + goto exit; + + cpu_config_base = of_iomap(cpu_config_np, 0); + if (!cpu_config_base) { + of_node_put(cpu_config_np); + goto exit; + } + + of_node_put(cpu_config_np); + + register_cpu_notifier(&armada_xp_clear_shared_l2_notifier); + +exit: set_cpu_coherent(); } @@ -206,6 +252,25 @@ static int coherency_type(void) return type; } +int set_cpu_coherent(void) +{ + int type = coherency_type(); + + if (type == COHERENCY_FABRIC_TYPE_ARMADA_370_XP) { + if (!coherency_base) { + pr_warn("Can't make current CPU cache coherent.\n"); + pr_warn("Coherency fabric is not initialized\n"); + return 1; + } + + armada_xp_clear_shared_l2(); + ll_add_cpu_to_smp_group(); + return ll_enable_coherency(); + } + + return 0; +} + int coherency_available(void) { return coherency_type() != COHERENCY_FABRIC_TYPE_NONE; diff --git a/kernel/arch/arm/mach-mvebu/common.h b/kernel/arch/arm/mach-mvebu/common.h index 3e0aca1f2..6b775492c 100644 --- a/kernel/arch/arm/mach-mvebu/common.h +++ b/kernel/arch/arm/mach-mvebu/common.h @@ -25,6 +25,6 @@ int mvebu_system_controller_get_soc_id(u32 *dev, u32 *rev); void __iomem *mvebu_get_scu_base(void); -int mvebu_pm_init(void (*board_pm_enter)(void __iomem *sdram_reg, u32 srcmd)); - +int mvebu_pm_suspend_init(void (*board_pm_enter)(void __iomem *sdram_reg, + u32 srcmd)); #endif diff --git a/kernel/arch/arm/mach-mvebu/dove.c b/kernel/arch/arm/mach-mvebu/dove.c index 5a1741500..1aebb82e3 100644 --- a/kernel/arch/arm/mach-mvebu/dove.c +++ b/kernel/arch/arm/mach-mvebu/dove.c @@ -12,6 +12,7 @@ #include <linux/mbus.h> #include <linux/of.h> #include <linux/of_platform.h> +#include <linux/soc/dove/pmu.h> #include <asm/hardware/cache-tauros2.h> #include <asm/mach/arch.h> #include "common.h" @@ -24,6 +25,7 @@ static void __init dove_init(void) tauros2_init(0); #endif BUG_ON(mvebu_mbus_dt_init(false)); + dove_init_pmu(); of_platform_populate(NULL, of_default_bus_match_table, NULL, NULL); } diff --git a/kernel/arch/arm/mach-mvebu/headsmp-a9.S b/kernel/arch/arm/mach-mvebu/headsmp-a9.S index 48e4c4b3c..b093a196e 100644 --- a/kernel/arch/arm/mach-mvebu/headsmp-a9.S +++ b/kernel/arch/arm/mach-mvebu/headsmp-a9.S @@ -13,12 +13,9 @@ */ #include <linux/linkage.h> -#include <linux/init.h> #include <asm/assembler.h> - __CPUINIT - ENTRY(mvebu_cortex_a9_secondary_startup) ARM_BE8(setend be) bl armada_38x_scu_power_up diff --git a/kernel/arch/arm/mach-mvebu/kirkwood.c b/kernel/arch/arm/mach-mvebu/kirkwood.c index 925f75f54..f9d8e1ea7 100644 --- a/kernel/arch/arm/mach-mvebu/kirkwood.c +++ b/kernel/arch/arm/mach-mvebu/kirkwood.c @@ -25,7 +25,6 @@ #include "kirkwood.h" #include "kirkwood-pm.h" #include "common.h" -#include "board.h" static struct resource kirkwood_cpufreq_resources[] = { [0] = { @@ -180,9 +179,6 @@ 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/kernel/arch/arm/mach-mvebu/netxbig.c b/kernel/arch/arm/mach-mvebu/netxbig.c deleted file mode 100644 index 94b11b658..000000000 --- a/kernel/arch/arm/mach-mvebu/netxbig.c +++ /dev/null @@ -1,191 +0,0 @@ -/* - * arch/arm/mach-mvbu/board-netxbig.c - * - * LaCie 2Big and 5Big Network v2 board setup - * - * Copyright (C) 2010 Simon Guinot <sguinot@lacie.com> - * - * 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 <linux/kernel.h> -#include <linux/of.h> -#include <linux/platform_device.h> -#include <linux/platform_data/leds-kirkwood-netxbig.h> -#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); -} diff --git a/kernel/arch/arm/mach-mvebu/platsmp-a9.c b/kernel/arch/arm/mach-mvebu/platsmp-a9.c index df0a9cc5d..3d5000481 100644 --- a/kernel/arch/arm/mach-mvebu/platsmp-a9.c +++ b/kernel/arch/arm/mach-mvebu/platsmp-a9.c @@ -24,7 +24,7 @@ extern void mvebu_cortex_a9_secondary_startup(void); -static int __cpuinit mvebu_cortex_a9_boot_secondary(unsigned int cpu, +static int mvebu_cortex_a9_boot_secondary(unsigned int cpu, struct task_struct *idle) { int ret, hw_cpu; diff --git a/kernel/arch/arm/mach-mvebu/pm-board.c b/kernel/arch/arm/mach-mvebu/pm-board.c index 301ab38d3..db17121d7 100644 --- a/kernel/arch/arm/mach-mvebu/pm-board.c +++ b/kernel/arch/arm/mach-mvebu/pm-board.c @@ -1,7 +1,7 @@ /* * Board-level suspend/resume support. * - * Copyright (C) 2014 Marvell + * Copyright (C) 2014-2015 Marvell * * Thomas Petazzoni <thomas.petazzoni@free-electrons.com> * @@ -20,27 +20,27 @@ #include <linux/slab.h> #include "common.h" -#define ARMADA_XP_GP_PIC_NR_GPIOS 3 +#define ARMADA_PIC_NR_GPIOS 3 static void __iomem *gpio_ctrl; -static int pic_gpios[ARMADA_XP_GP_PIC_NR_GPIOS]; -static int pic_raw_gpios[ARMADA_XP_GP_PIC_NR_GPIOS]; +static int pic_gpios[ARMADA_PIC_NR_GPIOS]; +static int pic_raw_gpios[ARMADA_PIC_NR_GPIOS]; -static void mvebu_armada_xp_gp_pm_enter(void __iomem *sdram_reg, u32 srcmd) +static void mvebu_armada_pm_enter(void __iomem *sdram_reg, u32 srcmd) { u32 reg, ackcmd; int i; /* Put 001 as value on the GPIOs */ reg = readl(gpio_ctrl); - for (i = 0; i < ARMADA_XP_GP_PIC_NR_GPIOS; i++) + for (i = 0; i < ARMADA_PIC_NR_GPIOS; i++) reg &= ~BIT(pic_raw_gpios[i]); reg |= BIT(pic_raw_gpios[0]); writel(reg, gpio_ctrl); /* Prepare writing 111 to the GPIOs */ ackcmd = readl(gpio_ctrl); - for (i = 0; i < ARMADA_XP_GP_PIC_NR_GPIOS; i++) + for (i = 0; i < ARMADA_PIC_NR_GPIOS; i++) ackcmd |= BIT(pic_raw_gpios[i]); srcmd = cpu_to_le32(srcmd); @@ -76,7 +76,7 @@ static void mvebu_armada_xp_gp_pm_enter(void __iomem *sdram_reg, u32 srcmd) [ackcmd] "r" (ackcmd), [gpio_ctrl] "r" (gpio_ctrl) : "r1"); } -static int mvebu_armada_xp_gp_pm_init(void) +static int __init mvebu_armada_pm_init(void) { struct device_node *np; struct device_node *gpio_ctrl_np; @@ -89,7 +89,7 @@ static int mvebu_armada_xp_gp_pm_init(void) if (!np) return -ENODEV; - for (i = 0; i < ARMADA_XP_GP_PIC_NR_GPIOS; i++) { + for (i = 0; i < ARMADA_PIC_NR_GPIOS; i++) { char *name; struct of_phandle_args args; @@ -134,11 +134,19 @@ static int mvebu_armada_xp_gp_pm_init(void) if (!gpio_ctrl) return -ENOMEM; - mvebu_pm_init(mvebu_armada_xp_gp_pm_enter); + mvebu_pm_suspend_init(mvebu_armada_pm_enter); out: of_node_put(np); return ret; } -late_initcall(mvebu_armada_xp_gp_pm_init); +/* + * Registering the mvebu_board_pm_enter callback must be done before + * the platform_suspend_ops will be registered. In the same time we + * also need to have the gpio devices registered. That's why we use a + * device_initcall_sync which is called after all the device_initcall + * (used by the gpio device) but before the late_initcall (used to + * register the platform_suspend_ops) + */ +device_initcall_sync(mvebu_armada_pm_init); diff --git a/kernel/arch/arm/mach-mvebu/pm.c b/kernel/arch/arm/mach-mvebu/pm.c index 6573a8f11..8d32bf762 100644 --- a/kernel/arch/arm/mach-mvebu/pm.c +++ b/kernel/arch/arm/mach-mvebu/pm.c @@ -105,12 +105,10 @@ static phys_addr_t mvebu_internal_reg_base(void) return of_translate_address(np, in_addr); } -static void mvebu_pm_store_bootinfo(void) +static void mvebu_pm_store_armadaxp_bootinfo(u32 *store_addr) { - u32 *store_addr; phys_addr_t resume_pc; - store_addr = phys_to_virt(BOOT_INFO_ADDR); resume_pc = virt_to_phys(armada_370_xp_cpu_resume); /* @@ -151,14 +149,30 @@ static void mvebu_pm_store_bootinfo(void) writel(BOOT_MAGIC_LIST_END, store_addr); } -static int mvebu_pm_enter(suspend_state_t state) +static int mvebu_pm_store_bootinfo(void) { - if (state != PM_SUSPEND_MEM) - return -EINVAL; + u32 *store_addr; + + store_addr = phys_to_virt(BOOT_INFO_ADDR); + + if (of_machine_is_compatible("marvell,armadaxp")) + mvebu_pm_store_armadaxp_bootinfo(store_addr); + else + return -ENODEV; + + return 0; +} + +static int mvebu_enter_suspend(void) +{ + int ret; + + ret = mvebu_pm_store_bootinfo(); + if (ret) + return ret; cpu_pm_enter(); - mvebu_pm_store_bootinfo(); cpu_suspend(0, mvebu_pm_powerdown); outer_resume(); @@ -168,23 +182,62 @@ static int mvebu_pm_enter(suspend_state_t state) set_cpu_coherent(); cpu_pm_exit(); + return 0; +} + +static int mvebu_pm_enter(suspend_state_t state) +{ + switch (state) { + case PM_SUSPEND_STANDBY: + cpu_do_idle(); + break; + case PM_SUSPEND_MEM: + pr_warn("Entering suspend to RAM. Only special wake-up sources will resume the system\n"); + return mvebu_enter_suspend(); + default: + return -EINVAL; + } + return 0; +} + +static int mvebu_pm_valid(suspend_state_t state) +{ + if (state == PM_SUSPEND_STANDBY) + return 1; + + if (state == PM_SUSPEND_MEM && mvebu_board_pm_enter != NULL) + return 1; return 0; } static const struct platform_suspend_ops mvebu_pm_ops = { .enter = mvebu_pm_enter, - .valid = suspend_valid_only_mem, + .valid = mvebu_pm_valid, }; -int mvebu_pm_init(void (*board_pm_enter)(void __iomem *sdram_reg, u32 srcmd)) +static int __init mvebu_pm_init(void) +{ + if (!of_machine_is_compatible("marvell,armadaxp") && + !of_machine_is_compatible("marvell,armada370") && + !of_machine_is_compatible("marvell,armada380") && + !of_machine_is_compatible("marvell,armada390")) + return -ENODEV; + + suspend_set_ops(&mvebu_pm_ops); + + return 0; +} + + +late_initcall(mvebu_pm_init); + +int __init mvebu_pm_suspend_init(void (*board_pm_enter)(void __iomem *sdram_reg, + u32 srcmd)) { struct device_node *np; struct resource res; - if (!of_machine_is_compatible("marvell,armadaxp")) - return -ENODEV; - np = of_find_compatible_node(NULL, NULL, "marvell,armada-xp-sdram-controller"); if (!np) @@ -212,7 +265,5 @@ int mvebu_pm_init(void (*board_pm_enter)(void __iomem *sdram_reg, u32 srcmd)) mvebu_board_pm_enter = board_pm_enter; - suspend_set_ops(&mvebu_pm_ops); - return 0; } diff --git a/kernel/arch/arm/mach-mvebu/pmsu.c b/kernel/arch/arm/mach-mvebu/pmsu.c index 4f4e22206..ed8fda4cd 100644 --- a/kernel/arch/arm/mach-mvebu/pmsu.c +++ b/kernel/arch/arm/mach-mvebu/pmsu.c @@ -296,11 +296,11 @@ int armada_370_xp_pmsu_idle_enter(unsigned long deepidle) /* Test the CR_C bit and set it if it was cleared */ asm volatile( "mrc p15, 0, r0, c1, c0, 0 \n\t" - "tst r0, #(1 << 2) \n\t" + "tst r0, %0 \n\t" "orreq r0, r0, #(1 << 2) \n\t" "mcreq p15, 0, r0, c1, c0, 0 \n\t" "isb " - : : : "r0"); + : : "Ir" (CR_C) : "r0"); pr_debug("Failed to suspend the system\n"); @@ -379,6 +379,16 @@ static struct notifier_block mvebu_v7_cpu_pm_notifier = { static struct platform_device mvebu_v7_cpuidle_device; +static int broken_idle(struct device_node *np) +{ + if (of_property_read_bool(np, "broken-idle")) { + pr_warn("CPU idle is currently broken: disabling\n"); + return 1; + } + + return 0; +} + static __init int armada_370_cpuidle_init(void) { struct device_node *np; @@ -387,7 +397,9 @@ static __init int armada_370_cpuidle_init(void) np = of_find_compatible_node(NULL, NULL, "marvell,coherency-fabric"); if (!np) return -ENODEV; - of_node_put(np); + + if (broken_idle(np)) + goto end; /* * On Armada 370, there is "a slow exit process from the deep @@ -406,6 +418,8 @@ static __init int armada_370_cpuidle_init(void) mvebu_v7_cpuidle_device.dev.platform_data = armada_370_xp_cpu_suspend; mvebu_v7_cpuidle_device.name = "cpuidle-armada-370"; +end: + of_node_put(np); return 0; } @@ -415,13 +429,17 @@ static __init int armada_38x_cpuidle_init(void) void __iomem *mpsoc_base; u32 reg; - pr_warn("CPU idle is currently broken on Armada 38x: disabling"); + pr_warn("CPU idle is currently broken on Armada 38x: disabling\n"); return 0; np = of_find_compatible_node(NULL, NULL, "marvell,armada-380-coherency-fabric"); if (!np) return -ENODEV; + + if (broken_idle(np)) + goto end; + of_node_put(np); np = of_find_compatible_node(NULL, NULL, @@ -430,7 +448,6 @@ static __init int armada_38x_cpuidle_init(void) 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); @@ -450,6 +467,8 @@ static __init int armada_38x_cpuidle_init(void) mvebu_v7_cpuidle_device.dev.platform_data = armada_38x_cpu_suspend; mvebu_v7_cpuidle_device.name = "cpuidle-armada-38x"; +end: + of_node_put(np); return 0; } @@ -460,12 +479,16 @@ static __init int armada_xp_cpuidle_init(void) np = of_find_compatible_node(NULL, NULL, "marvell,coherency-fabric"); if (!np) return -ENODEV; - of_node_put(np); + + if (broken_idle(np)) + goto end; 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"; +end: + of_node_put(np); return 0; } @@ -486,7 +509,7 @@ static int __init mvebu_v7_cpu_pm_init(void) */ if (of_machine_is_compatible("marvell,armada380")) { cpu_hotplug_disable(); - pr_warn("CPU hotplug support is currently broken on Armada 38x: disabling"); + pr_warn("CPU hotplug support is currently broken on Armada 38x: disabling\n"); } if (of_machine_is_compatible("marvell,armadaxp")) |