From 01049a5deb1d6b9fc3f2df512af09fddd0db6730 Mon Sep 17 00:00:00 2001 From: Nadav Haklai Date: Wed, 8 Jul 2015 17:02:30 +0200 Subject: [PATCH 1/7] ARM: mvebu: prepare set_cpu_coherent() for future extension This patch prepares the set_cpu_coherent() function in coherency.c to be extended to support other SoCs than Armada XP. It will be needed on Armada 38x to re-enable the coherency after exiting from suspend to RAM. This preparation simply moves the function further down in coherency.c so that it can use coherency_type(), and uses that function to only do the Armada XP specific work if we are on Armada XP. Signed-off-by: Nadav Haklai Signed-off-by: Thomas Petazzoni Acked-by: Gregory CLEMENT Signed-off-by: Gregory CLEMENT --- arch/arm/mach-mvebu/coherency.c | 29 +++++++++++++++++------------ 1 file changed, 17 insertions(+), 12 deletions(-) diff --git a/arch/arm/mach-mvebu/coherency.c b/arch/arm/mach-mvebu/coherency.c index e46e9ea1e187..44eedf331ae7 100644 --- a/arch/arm/mach-mvebu/coherency.c +++ b/arch/arm/mach-mvebu/coherency.c @@ -65,18 +65,6 @@ 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) -{ - if (!coherency_base) { - pr_warn("Can't make current CPU cache coherent.\n"); - pr_warn("Coherency fabric is not initialized\n"); - return 1; - } - - ll_add_cpu_to_smp_group(); - return ll_enable_coherency(); -} - static int mvebu_hwcc_notifier(struct notifier_block *nb, unsigned long event, void *__dev) { @@ -206,6 +194,23 @@ 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; + } + ll_add_cpu_to_smp_group(); + return ll_enable_coherency(); + } + + return 0; +} + int coherency_available(void) { return coherency_type() != COHERENCY_FABRIC_TYPE_NONE; From a101b53d3af16255c0038aad26902be590a96ffa Mon Sep 17 00:00:00 2001 From: Thomas Petazzoni Date: Wed, 8 Jul 2015 17:02:31 +0200 Subject: [PATCH 2/7] ARM: mvebu: do not check machine in mvebu_pm_init() The mvebu_pm_init() initializes the support for suspend/resume, and before doing that, it checks if we are on a board on which suspend/resume is actually supported. However, this check is already done by mvebu_armada_xp_gp_pm_init(), and there is no need to duplicate the check: callers of mvebu_pm_init() should now what they are doing. This commit is done in preparation to the addition of suspend/resume support on Armada 38x. Signed-off-by: Thomas Petazzoni Acked-by: Gregory CLEMENT Signed-off-by: Gregory CLEMENT --- arch/arm/mach-mvebu/pm.c | 3 --- 1 file changed, 3 deletions(-) diff --git a/arch/arm/mach-mvebu/pm.c b/arch/arm/mach-mvebu/pm.c index 6573a8f11f70..eca650b4efc8 100644 --- a/arch/arm/mach-mvebu/pm.c +++ b/arch/arm/mach-mvebu/pm.c @@ -182,9 +182,6 @@ int mvebu_pm_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) From 88ed69f2a1e1e8e5eb9e16d8cdebd9d5f1deef67 Mon Sep 17 00:00:00 2001 From: Thomas Petazzoni Date: Wed, 8 Jul 2015 17:02:32 +0200 Subject: [PATCH 3/7] ARM: mvebu: prepare mvebu_pm_store_bootinfo() to support multiple SoCs As we are going to introduce support for Armada 38x in pm.c, split out the Armada XP part of mvebu_pm_store_bootinfo() into mvebu_pm_store_armadaxp_bootinfo(), and make the former retunr an error when an unsupported SoC is used. Signed-off-by: Thomas Petazzoni Acked-by: Gregory CLEMENT Signed-off-by: Gregory CLEMENT --- arch/arm/mach-mvebu/pm.c | 25 +++++++++++++++++++++---- 1 file changed, 21 insertions(+), 4 deletions(-) diff --git a/arch/arm/mach-mvebu/pm.c b/arch/arm/mach-mvebu/pm.c index eca650b4efc8..02fdf67a4898 100644 --- a/arch/arm/mach-mvebu/pm.c +++ b/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,33 @@ static void mvebu_pm_store_bootinfo(void) writel(BOOT_MAGIC_LIST_END, store_addr); } +static int mvebu_pm_store_bootinfo(void) +{ + 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_pm_enter(suspend_state_t state) { + int ret; + if (state != PM_SUSPEND_MEM) return -EINVAL; + ret = mvebu_pm_store_bootinfo(); + if (ret) + return ret; + cpu_pm_enter(); - mvebu_pm_store_bootinfo(); cpu_suspend(0, mvebu_pm_powerdown); outer_resume(); From 32f9494c9dfd7494721b314897008dcde6415cb3 Mon Sep 17 00:00:00 2001 From: Thomas Petazzoni Date: Wed, 8 Jul 2015 17:02:33 +0200 Subject: [PATCH 4/7] ARM: mvebu: prepare pm-board.c for the introduction of Armada 38x support The pm-board.c code contains the board-specific logic to enter suspend to RAM. Until now, the code supported only the Armada XP GP board, so all functions and symbols were named with armada_xp_gp. However, it turns out that the Armada 388 GP also uses the same 3 GPIOs protocol to talk to the PIC microcontroller that controls the power supply. Since we are going to re-use the same code with no change for Armada 38x, this commit renames the functions and symbols to use just "armada" instead of "armada_xp_gp". Better names can be found if one day other boards having a different protocol/mechanism are supported in the kernel. Signed-off-by: Thomas Petazzoni Acked-by: Gregory CLEMENT Signed-off-by: Gregory CLEMENT --- arch/arm/mach-mvebu/pm-board.c | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/arch/arm/mach-mvebu/pm-board.c b/arch/arm/mach-mvebu/pm-board.c index 301ab38d38ba..b8c26cb3a27f 100644 --- a/arch/arm/mach-mvebu/pm-board.c +++ b/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 * @@ -20,27 +20,27 @@ #include #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 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,11 @@ 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_init(mvebu_armada_pm_enter); out: of_node_put(np); return ret; } -late_initcall(mvebu_armada_xp_gp_pm_init); +late_initcall(mvebu_armada_pm_init); From bb253e743affa9d0053add8d3a1089df82f1c854 Mon Sep 17 00:00:00 2001 From: Gregory CLEMENT Date: Fri, 3 Jul 2015 13:55:50 +0200 Subject: [PATCH 5/7] ARM: mvebu: Use __init for the PM initialization functions mvebu_pm_init and mvebu_armada_pm_init are only called during boot, so flag them with __init and save some memory. Signed-off-by: Gregory CLEMENT Reviewed-by: Thomas Petazzoni --- arch/arm/mach-mvebu/pm-board.c | 2 +- arch/arm/mach-mvebu/pm.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/arch/arm/mach-mvebu/pm-board.c b/arch/arm/mach-mvebu/pm-board.c index b8c26cb3a27f..3ab06e7252c3 100644 --- a/arch/arm/mach-mvebu/pm-board.c +++ b/arch/arm/mach-mvebu/pm-board.c @@ -76,7 +76,7 @@ static void mvebu_armada_pm_enter(void __iomem *sdram_reg, u32 srcmd) [ackcmd] "r" (ackcmd), [gpio_ctrl] "r" (gpio_ctrl) : "r1"); } -static int mvebu_armada_pm_init(void) +static int __init mvebu_armada_pm_init(void) { struct device_node *np; struct device_node *gpio_ctrl_np; diff --git a/arch/arm/mach-mvebu/pm.c b/arch/arm/mach-mvebu/pm.c index 02fdf67a4898..ca94f07407f1 100644 --- a/arch/arm/mach-mvebu/pm.c +++ b/arch/arm/mach-mvebu/pm.c @@ -194,7 +194,7 @@ static const struct platform_suspend_ops mvebu_pm_ops = { .valid = suspend_valid_only_mem, }; -int mvebu_pm_init(void (*board_pm_enter)(void __iomem *sdram_reg, u32 srcmd)) +int __init mvebu_pm_init(void (*board_pm_enter)(void __iomem *sdram_reg, u32 srcmd)) { struct device_node *np; struct resource res; From 3cbd6a6ca81c9e8438b592099495a7c2b72de9e3 Mon Sep 17 00:00:00 2001 From: Gregory CLEMENT Date: Fri, 3 Jul 2015 13:55:51 +0200 Subject: [PATCH 6/7] ARM: mvebu: Add standby support Until now only one Armada XP and one Armada 388 based board supported suspend to ram. However, most of the recent mvebu SoCs can support the standby mode. Unlike for the suspend to ram, nothing special has to be done for these SoCs. This patch allows the system to use the standby mode on Armada 370, 38x, 39x and XP SoCs. There are issues with the Armada 375, and the support might be added (if possible) in a future patch. Signed-off-by: Gregory CLEMENT --- arch/arm/mach-mvebu/common.h | 4 +-- arch/arm/mach-mvebu/pm-board.c | 12 ++++++-- arch/arm/mach-mvebu/pm.c | 52 ++++++++++++++++++++++++++++------ 3 files changed, 56 insertions(+), 12 deletions(-) diff --git a/arch/arm/mach-mvebu/common.h b/arch/arm/mach-mvebu/common.h index 3e0aca1f288a..6b775492cfad 100644 --- a/arch/arm/mach-mvebu/common.h +++ b/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/arch/arm/mach-mvebu/pm-board.c b/arch/arm/mach-mvebu/pm-board.c index 3ab06e7252c3..db17121d7d63 100644 --- a/arch/arm/mach-mvebu/pm-board.c +++ b/arch/arm/mach-mvebu/pm-board.c @@ -134,11 +134,19 @@ static int __init mvebu_armada_pm_init(void) if (!gpio_ctrl) return -ENOMEM; - mvebu_pm_init(mvebu_armada_pm_enter); + mvebu_pm_suspend_init(mvebu_armada_pm_enter); out: of_node_put(np); return ret; } -late_initcall(mvebu_armada_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/arch/arm/mach-mvebu/pm.c b/arch/arm/mach-mvebu/pm.c index ca94f07407f1..b058307088f3 100644 --- a/arch/arm/mach-mvebu/pm.c +++ b/arch/arm/mach-mvebu/pm.c @@ -163,13 +163,10 @@ static int mvebu_pm_store_bootinfo(void) return 0; } -static int mvebu_pm_enter(suspend_state_t state) +static int mvebu_enter_suspend(void) { int ret; - if (state != PM_SUSPEND_MEM) - return -EINVAL; - ret = mvebu_pm_store_bootinfo(); if (ret) return ret; @@ -185,16 +182,57 @@ 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: + 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 __init 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; @@ -226,7 +264,5 @@ int __init mvebu_pm_init(void (*board_pm_enter)(void __iomem *sdram_reg, u32 src mvebu_board_pm_enter = board_pm_enter; - suspend_set_ops(&mvebu_pm_ops); - return 0; } From 482d638f98cc626bf01d4c9f6d6d35fc77d630c8 Mon Sep 17 00:00:00 2001 From: Gregory CLEMENT Date: Fri, 3 Jul 2015 13:55:53 +0200 Subject: [PATCH 7/7] ARM: mvebu: Warn about the wake-up sources not taken into account in suspend On the Armada 370/XP/38x/39x SoCs when the suspend to ram feature is supported, the SoCs are shutdown and will be woken up by an external micro-controller, so there is no possibility to setup wake-up sources from Linux. However, in standby mode, the SoCs stay powered and it is possible to wake-up from any interrupt sources. Since when the users configures the enabled wake-up sources there is no way to know if the user will be doing suspend to RAM or standby, we just allow all wake-up sources to be enabled, and only warn when entering suspend to RAM The purpose of this patch is to inform the user that in suspend to ram mode, the wake-up sources won't be taken into consideration. Signed-off-by: Gregory CLEMENT --- arch/arm/mach-mvebu/pm.c | 1 + 1 file changed, 1 insertion(+) diff --git a/arch/arm/mach-mvebu/pm.c b/arch/arm/mach-mvebu/pm.c index b058307088f3..8d32bf762b86 100644 --- a/arch/arm/mach-mvebu/pm.c +++ b/arch/arm/mach-mvebu/pm.c @@ -192,6 +192,7 @@ static int mvebu_pm_enter(suspend_state_t state) 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;