ARCH: CSR: basic PM suspend/resume support
Subsystems (2)
v2 cover ARCH: CSR: basic PM suspend/resume support
-v2:
add acked-by Arnd in changelog;
add necessary changelog for every patch;
don't call l2x0_of_init after resuming as Shawn's patch[1] seems not to be applied;
since people still need some time to figure out the best way for l2 resume, we move the l2 re-init to bootloader for the moment to keep things go ahead.
-v1:
it was in thread "ARM: CSR: add rtciobrg and PM support" before. See:
http://www.spinics.net/lists/arm-kernel/msg137375.html
Arnd has pulled rtciobrg into arm-soc next branch. PM should be another series.
This series has been tested on prima2 Linux 3.1-rc6 with log:
# echo mem > /sys/power/state PM: Syncing filesystems ... done. Freezing user space processes ... (elapsed 0.01 seconds) done. Freezing remaining freezable tasks ... (elapsed 0.01 seconds) done. Suspending console(s) (use no_console_suspend to debug) C0PM: suspend of devices complete after 2.083 msecs PM: late suspend of devices complete after 0.697 msecs L310 cache controller enabled l2x0: 8 ways, CACHE_ID 0x410000c7, AUX_CTRL 0x00040000, Cache size: 262144 B PM: early resume of devices complete after 0.628 msecs PM: resume of devices complete after 1.804 msecs Restarting tasks ... done.
Due to L2 cache will lose power and data in suspend cycle, prima2 actually requires the whole l2 cache flushed while suspending and re-initilized after resuming just like code boot.
So the "ARM: CSR: PM: add sleep entry for SiRFprimaII" depends on [1]:
[1] Shawn Guo <[email protected]>'s
[PATCH v2 1/2] ARM: cache-l2x0: remove __init annotation from initialization functions
http://www.spinics.net/lists/arm-kernel/msg139198.html
Barry Song (2):
ARM: CSR: PM: save/restore timer status in suspend cycle
ARM: CSR: PM: save/restore irq status in suspend cycle
Rongjun Ying (1):
ARM: CSR: PM: add sleep entry for SiRFprimaII
arch/arm/mach-prima2/Makefile | 1 + arch/arm/mach-prima2/irq.c | 40 +++++++++++ arch/arm/mach-prima2/pm.c | 149 +++++++++++++++++++++++++++++++++++++++++ arch/arm/mach-prima2/pm.h | 31 +++++++++ arch/arm/mach-prima2/sleep.S | 64 ++++++++++++++++++ arch/arm/mach-prima2/timer.c | 34 +++++++++ 6 files changed, 319 insertions(+), 0 deletions(-) create mode 100644 arch/arm/mach-prima2/pm.c create mode 100644 arch/arm/mach-prima2/pm.h create mode 100644 arch/arm/mach-prima2/sleep.S
PATCH v2 1/3 ARM: CSR: PM: save/restore timer status in suspend cycle
From: Barry Song <[email protected]>
SiRFprimaII will lose power in deepsleep mode except rtc, pmu and sdram self-refresh.
This patch saves timer-related registers while suspending and restore them while resuming.
--- arch/arm/mach-prima2/timer.c | 34 ++++++++++++++++++++++++++++++++++ 1 files changed, 34 insertions(+), 0 deletions(-)
arch/arm/mach-prima2/timer.c +34 -0
@@ -40,6 +40,17 @@#define SIRFSOC_TIMER_LATCH_BIT BIT(0) +#define SIRFSOC_TIMER_REG_CNT 11 + +static const u32 sirfsoc_timer_reg_list[SIRFSOC_TIMER_REG_CNT ] = { +SIRFSOC_TIMER_MATCH_0 ,SIRFSOC_TIMER_MATCH_1 ,SIRFSOC_TIMER_MATCH_2 , +SIRFSOC_TIMER_MATCH_3 ,SIRFSOC_TIMER_MATCH_4 ,SIRFSOC_TIMER_MATCH_5 , +SIRFSOC_TIMER_INT_EN ,SIRFSOC_TIMER_WATCHDOG_EN ,SIRFSOC_TIMER_DIV , +SIRFSOC_TIMER_LATCHED_LO ,SIRFSOC_TIMER_LATCHED_HI , +}; + +static u32 sirfsoc_timer_reg_val[SIRFSOC_TIMER_REG_CNT ]; +static void __iomem *sirfsoc_timer_base;static void __init sirfsoc_of_timer_map (void );
@@ -106,6 +117,27 @@ static void sirfsoc_timer_set_mode(enum clock_event_mode mode, } } +static void sirfsoc_clocksource_suspend (struct clocksource *cs) +{ +int i; + +writel_relaxed (SIRFSOC_TIMER_LATCH_BIT , sirfsoc_timer_base +SIRFSOC_TIMER_LATCH ); + +for (i =0 ; i <SIRFSOC_TIMER_REG_CNT ; i++) + sirfsoc_timer_reg_val[i] =readl_relaxed (sirfsoc_timer_base + sirfsoc_timer_reg_list[i]); +} + +static void sirfsoc_clocksource_resume (struct clocksource *cs) +{ +int i; + +for (i =0 ; i <SIRFSOC_TIMER_REG_CNT ; i++) +writel_relaxed (sirfsoc_timer_reg_val[i], sirfsoc_timer_base + sirfsoc_timer_reg_list[i]); + +writel_relaxed (sirfsoc_timer_reg_val[i -2 ], sirfsoc_timer_base +SIRFSOC_TIMER_COUNTER_LO ); +writel_relaxed (sirfsoc_timer_reg_val[i -1 ], sirfsoc_timer_base +SIRFSOC_TIMER_COUNTER_HI ); +} +static struct clock_event_device sirfsoc_clockevent = { .name ="sirfsoc_clockevent" , .rating =200 ,
@@ -120,6 +152,8 @@ static struct clocksource sirfsoc_clocksource = { .mask = CLOCKSOURCE_MASK(64), .flags = CLOCK_SOURCE_IS_CONTINUOUS, .read = sirfsoc_timer_read, + .suspend = sirfsoc_clocksource_suspend, + .resume = sirfsoc_clocksource_resume, };static struct irqaction sirfsoc_timer_irq = {
Signature · 1 line
1.7.0.4
PATCH v2 2/3 ARM: CSR: PM: save/restore irq status in suspend cycle
In reply to Barry SongFrom: Barry Song <[email protected]>
SiRFprimaII will lose power in deepsleep mode except rtc, pmu and sdram self-refresh. So IRQ controller will lose status in suspend cyle. This patch saves irq mask/level registers while suspending and restore them while resuming.
--- arch/arm/mach-prima2/irq.c | 40 ++++++++++++++++++++++++++++++++++++++++ 1 files changed, 40 insertions(+), 0 deletions(-)
arch/arm/mach-prima2/irq.c +40 -0
@@ -14,6 +14,7 @@#include <linux/of.h> #include <linux/of_address.h> #include <linux/irqdomain.h> +#include <linux/syscore_ops.h> #define SIRFSOC_INT_RISC_MASK0 0x0018#define SIRFSOC_INT_RISC_MASK1 0x001C
@@ -73,3 +74,42 @@ void __init sirfsoc_of_irq_init(void)sirfsoc_irq_init (); } + +struct sirfsoc_irq_status { +u32 mask0; +u32 mask1; +u32 level0; +u32 level1; +}; + +static struct sirfsoc_irq_status sirfsoc_irq_st; + +static int sirfsoc_irq_suspend (void ) +{ + sirfsoc_irq_st.mask0 =readl_relaxed (sirfsoc_intc_base +SIRFSOC_INT_RISC_MASK0 ); + sirfsoc_irq_st.mask1 =readl_relaxed (sirfsoc_intc_base +SIRFSOC_INT_RISC_MASK1 ); + sirfsoc_irq_st.level0 =readl_relaxed (sirfsoc_intc_base +SIRFSOC_INT_RISC_LEVEL0 ); + sirfsoc_irq_st.level1 =readl_relaxed (sirfsoc_intc_base +SIRFSOC_INT_RISC_LEVEL1 ); + +return 0 ; +} + +static void sirfsoc_irq_resume (void ) +{ +writel_relaxed (sirfsoc_irq_st.mask0, sirfsoc_intc_base +SIRFSOC_INT_RISC_MASK0 ); +writel_relaxed (sirfsoc_irq_st.mask1, sirfsoc_intc_base +SIRFSOC_INT_RISC_MASK1 ); +writel_relaxed (sirfsoc_irq_st.level0, sirfsoc_intc_base +SIRFSOC_INT_RISC_LEVEL0 ); +writel_relaxed (sirfsoc_irq_st.level1, sirfsoc_intc_base +SIRFSOC_INT_RISC_LEVEL1 ); +} + +static struct syscore_ops sirfsoc_irq_syscore_ops = { + .suspend = sirfsoc_irq_suspend, + .resume = sirfsoc_irq_resume, +}; + +static int __init sirfsoc_irq_pm_init (void ) +{ +register_syscore_ops (&sirfsoc_irq_syscore_ops); +return 0 ; +} +device_initcall (sirfsoc_irq_pm_init);
Signature · 1 line
1.7.0.4
PATCH v2 3/3 ARM: CSR: PM: add sleep entry for SiRFprimaII
In reply to Barry SongFrom: Rongjun Ying <[email protected]>
This patch adds suspend-to-mem support for prima2. It will make prima2 enter DEEPSLEEP mode while accepting PM_SUSPEND_MEM command.
---
-v2:
don't call l2x0_of_init after resuming as Shawn's patch[1] seems not to be applied;
Since people still need some time to figure out the best way for l2 resume, we move the l2 re-init to bootloader for the moment to keep things go ahead.
arch/arm/mach-prima2/Makefile | 1 + arch/arm/mach-prima2/pm.c | 149 +++++++++++++++++++++++++++++++++++++++++ arch/arm/mach-prima2/pm.h | 31 +++++++++ arch/arm/mach-prima2/sleep.S | 64 ++++++++++++++++++ 4 files changed, 245 insertions(+), 0 deletions(-) create mode 100644 arch/arm/mach-prima2/pm.c create mode 100644 arch/arm/mach-prima2/pm.h create mode 100644 arch/arm/mach-prima2/sleep.S
arch/arm/mach-prima2/Makefile +1 -0
@@ -6,3 +6,4 @@ obj-y += prima2.o obj-y += rtciobrg.o obj-$(CONFIG_DEBUG_LL) += lluart.o obj-$(CONFIG_CACHE_L2X0) += l2x0.o +obj-$(CONFIG_SUSPEND) += pm.o sleep.o
arch/arm/mach-prima2/pm.c new file +149 -0
149 lines not on this page · raw message
arch/arm/mach-prima2/pm.h new file +31 -0
@@ -0,0 +1,31 @@ +/* +* arch/arm/mach-prima2/pm.h +* +* Copyright (C) 2011 CSR +* +* 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 _MACH_PRIMA2_PM_H_ +#define _MACH_PRIMA2_PM_H_ + +#define SIRFSOC_PWR_SLEEPFORCE 0x01 + +#define SIRFSOC_SLEEP_MODE_MASK 0x3 +#define SIRFSOC_DEEP_SLEEP_MODE 0x1 + +#define SIRFSOC_PWRC_PDN_CTRL 0x0 +#define SIRFSOC_PWRC_PON_OFF 0x4 +#define SIRFSOC_PWRC_TRIGGER_EN 0x8 +#define SIRFSOC_PWRC_PIN_STATUS 0x14 +#define SIRFSOC_PWRC_SCRATCH_PAD1 0x18 +#define SIRFSOC_PWRC_SCRATCH_PAD2 0x1C + +#ifndef __ASSEMBLY__ +extern int sirfsoc_finish_suspend (unsigned long ); +#endif + +#endif +
arch/arm/mach-prima2/sleep.S new file +64 -0
64 lines not on this page · raw message
Signature · 1 line
1.7.0.4
PATCH v2 3/3 ARM: CSR: PM: add sleep entry for SiRFprimaII
2011/9/21 Barry Song <[email protected]>:
Quoted 6 lines
From: Rongjun Ying <[email protected]>
This patch adds suspend-to-mem support for prima2. It will make prima2 enter DEEPSLEEP mode while accepting
PM_SUSPEND_MEMcommand.Signed-off-by Rongjun Ying <[email protected]>
sorry for typo. it should be:
this was fixed in repository for pull.
Quoted 294 lines
Signed-off-by Barry Song <[email protected]>Acked-by Arnd Bergmann <[email protected]>---
-v2:
?don't calll2x0_of_initafter resuming as Shawn's patch[1] seems ?not to be applied;
?Since people still need some time to figure out the best way for l2 ?resume, we move the l2 re-init to bootloader for the moment to keep ?things go ahead.?arch/arm/mach-prima2/Makefile | ? ?1 + ?arch/arm/mach-prima2/pm.c ? ? | ?149 +++++++++++++++++++++++++++++++++++++++++ ?arch/arm/mach-prima2/pm.h ? ? | ? 31 +++++++++ ?arch/arm/mach-prima2/sleep.S ?| ? 64 ++++++++++++++++++?4 files changed, 245 insertions(+), 0 deletions(-) ?create mode 100644
arch/arm/mach-prima2/pm.c?create mode 100644arch/arm/mach-prima2/pm.h?create mode 100644arch/arm/mach-prima2/sleep.Sarch/arm/mach-prima2/Makefile +0
-0@@ -6,3 +6,4 @@ obj-y += prima2.o?obj-y += rtciobrg.o
?obj-$(CONFIG_DEBUG_LL) += lluart.o
?obj-$(CONFIG_CACHE_L2X0) += l2x0.oarch/arm/mach-prima2/Makefile +1
-0+obj-$(CONFIG_SUSPEND) += pm.o sleep.oarch/arm/mach-prima2/pm.c new file +149
-0@@ -0,0 +1,149 @@ +/* +* power management entry for CSR SiRFprimaII +* +* Copyright (c) 2011 Cambridge Silicon Radio Limited, a CSR plc group company. +* +* Licensed under GPLv2 or later. +*/ + +#include <linux/kernel.h> +#include <linux/suspend.h> +#include <linux/slab.h> +#include <linux/of.h> +#include <linux/of_address.h> +#include <linux/of_device.h> +#include <linux/of_platform.h> +#include <linux/io.h> +#include <linux/rtc/sirfsoc_rtciobrg.h> +#include <asm/suspend.h> +#include <asm/hardware/cache-l2x0.h> + +#include "pm.h" + +/* +* suspend asm codes will access these to make DRAM become self-refresh and +* system sleep +*/ +u32 sirfsoc_pwrc_base; +void __iomem *sirfsoc_memc_base; + +static void sirfsoc_set_wakeup_source (void ) +{ + ? ? ? u32 pwr_trigger_en_reg; + ? ? ? pwr_trigger_en_reg = sirfsoc_rtc_iobrg_readl(sirfsoc_pwrc_base + + ? ? ? ? ? ? ? SIRFSOC_PWRC_TRIGGER_EN); +#define X_ON_KEY_B (1 << 0) + ? ? ? sirfsoc_rtc_iobrg_writel(pwr_trigger_en_reg | X_ON_KEY_B, + ? ? ? ? ? ? ? sirfsoc_pwrc_base + SIRFSOC_PWRC_TRIGGER_EN); +} + +static void sirfsoc_set_sleep_mode (u32 mode) +{ + ? ? ? u32 sleep_mode = sirfsoc_rtc_iobrg_readl(sirfsoc_pwrc_base + + ? ? ? ? ? ? ? SIRFSOC_PWRC_PDN_CTRL); + ? ? ? sleep_mode &= ~(SIRFSOC_SLEEP_MODE_MASK << 1); + ? ? ? sleep_mode |= mode << 1; + ? ? ? sirfsoc_rtc_iobrg_writel(sleep_mode, sirfsoc_pwrc_base + + ? ? ? ? ? ? ? SIRFSOC_PWRC_PDN_CTRL); +} + +static int sirfsoc_pre_suspend_power_off (void ) +{ + ? ? ? u32 wakeup_entry = virt_to_phys(cpu_resume); + + ? ? ? sirfsoc_rtc_iobrg_writel(wakeup_entry, sirfsoc_pwrc_base + + ? ? ? ? ? ? ? SIRFSOC_PWRC_SCRATCH_PAD1); + + ? ? ? sirfsoc_set_wakeup_source(); + + ? ? ? sirfsoc_set_sleep_mode(SIRFSOC_DEEP_SLEEP_MODE); + + ? ? ? return 0; +} + +static int sirfsoc_pm_enter (suspend_state_t state) +{ + ? ? ? switch (state) { + ? ? ? case PM_SUSPEND_MEM: + ? ? ? ? ? ? ? sirfsoc_pre_suspend_power_off(); + + ? ? ? ? ? ? ? outer_flush_all(); + ? ? ? ? ? ? ? outer_disable(); + ? ? ? ? ? ? ? /* go zzz */ + ? ? ? ? ? ? ? cpu_suspend(0, sirfsoc_finish_suspend); + ? ? ? ? ? ? ? break; + ? ? ? default: + ? ? ? ? ? ? ? return -EINVAL; + ? ? ? } + ? ? ? return 0; +} + +static const struct platform_suspend_ops sirfsoc_pm_ops = { + ? ? ? .enter = sirfsoc_pm_enter, + ? ? ? .valid = suspend_valid_only_mem, +}; + +static int __init sirfsoc_pm_init (void ) +{ + ? ? ? suspend_set_ops(&sirfsoc_pm_ops); + ? ? ? return 0; +} +late_initcall (sirfsoc_pm_init); + +static const struct of_device_id pwrc_ids[] = { + ? ? ? { .compatible = "sirf,prima2-pwrc" }, + ? ? ? {} +}; + +static int __init sirfsoc_of_pwrc_init (void ) +{ + ? ? ? struct device_node *np; + + ? ? ? np = of_find_matching_node(NULL, pwrc_ids); + ? ? ? if (!np) + ? ? ? ? ? ? ? panic("unable to find compatible pwrc node in dtb\n"); + + ? ? ? /* + ? ? ? ?* pwrc behind rtciobrg is not located in memory space + ? ? ? ?* though the property is named reg. reg only means base + ? ? ? ?* offset for pwrc. then of_iomap is not suitable here. + ? ? ? ?*/ + ? ? ? if (of_property_read_u32(np, "reg", &sirfsoc_pwrc_base)) + ? ? ? ? ? ? ? panic("unable to find base address of pwrc node in dtb\n"); + + ? ? ? of_node_put(np); + + ? ? ? return 0; +} +postcore_initcall (sirfsoc_of_pwrc_init); + +static const struct of_device_id memc_ids[] = { + ? ? ? { .compatible = "sirf,prima2-memc" }, + ? ? ? {} +}; + +static int __devinit sirfsoc_memc_probe (struct platform_device *op) +{ + ? ? ? struct device_node *np = op->dev.of_node; + + ? ? ? sirfsoc_memc_base = of_iomap(np, 0); + ? ? ? if (!sirfsoc_memc_base) + ? ? ? ? ? ? ? panic("unable to map memc registers\n"); + + ? ? ? return 0; +} + +static struct platform_driver sirfsoc_memc_driver = { + ? ? ? .probe ? ? ? ? ?= sirfsoc_memc_probe, + ? ? ? .driver = { + ? ? ? ? ? ? ? .name = "sirfsoc-memc", + ? ? ? ? ? ? ? .owner = THIS_MODULE, + ? ? ? ? ? ? ? .of_match_table = memc_ids, + ? ? ? }, +}; + +static int __init sirfsoc_memc_init (void ) +{ + ? ? ? return platform_driver_register(&sirfsoc_memc_driver); +} +postcore_initcall (sirfsoc_memc_init);arch/arm/mach-prima2/pm.h new file +31
-0@@ -0,0 +1,31 @@ +/* +* arch/arm/mach-prima2/pm.h +* +* Copyright (C) 2011 CSR +* +* 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 _MACH_PRIMA2_PM_H_ +#define _MACH_PRIMA2_PM_H_ + +#define SIRFSOC_PWR_SLEEPFORCE ? ? ? ? 0x01 + +#define SIRFSOC_SLEEP_MODE_MASK ? ? ? ? 0x3 +#define SIRFSOC_DEEP_SLEEP_MODE ? ? ? ? 0x1 + +#define SIRFSOC_PWRC_PDN_CTRL ? ? ? ? ? 0x0 +#define SIRFSOC_PWRC_PON_OFF ? ? ? ? ? ?0x4 +#define SIRFSOC_PWRC_TRIGGER_EN ? ? ? ? 0x8 +#define SIRFSOC_PWRC_PIN_STATUS ? ? ? ? 0x14 +#define SIRFSOC_PWRC_SCRATCH_PAD1 ? ? ? 0x18 +#define SIRFSOC_PWRC_SCRATCH_PAD2 ? ? ? 0x1C + +#ifndef __ASSEMBLY__ +extern int sirfsoc_finish_suspend (unsigned long ); +#endif + +#endif +arch/arm/mach-prima2/sleep.S new file +64
-1@@ -0,0 +1,64 @@ +/* + * sleep mode for CSR SiRFprimaII + * + * Copyright (c) 2011 Cambridge Silicon Radio Limited, a CSR plc group company. + * + * Licensed under GPLv2 or later. + */ + +#include <linux/linkage.h> +#include <asm/ptrace.h> +#include <asm/assembler.h> + +#include "pm.h" + +#define DENALI_CTL_22_OFF ? ? ?0x58 +#define DENALI_CTL_112_OFF ? ? 0x1c0 + + ? ? ? .text + +ENTRY(sirfsoc_finish_suspend) + ? ? ? @ r5: ? mem controller + ? ? ? ldr ? ? r0, =sirfsoc_memc_base + ? ? ? ldr ? ? r5, [r0] + ? ? ? @ r6: ? pwrc base offset + ? ? ? ldr ? ? r0, =sirfsoc_pwrc_base + ? ? ? ldr ? ? r6, [r0] + ? ? ? @ r7: ? rtc iobrg controller + ? ? ? ldr ? ? r0, =sirfsoc_rtciobrg_base + ? ? ? ldr ? ? r7, [r0] + + ? ? ? @ Read the power control register and set the + ? ? ? @ sleep force bit. + ? ? ? add ? ? r0, r6, #SIRFSOC_PWRC_PDN_CTRL + ? ? ? bl ? ? ?__sirfsoc_rtc_iobrg_readl + ? ? ? orr ? ? r0,r0,#SIRFSOC_PWR_SLEEPFORCE + ? ? ? add ? ? r1, r6, #SIRFSOC_PWRC_PDN_CTRL + ? ? ? bl ? ? ?sirfsoc_rtc_iobrg_pre_writel + ? ? ? mov ? ? r1, #0x1 + + ? ? ? @ read the MEM ctl register and set the self + ? ? ? @ refresh bit + + ? ? ? ldr ? ? r2, [r5, #DENALI_CTL_22_OFF] + ? ? ? orr ? ? r2, r2, #0x1 + + ? ? ? @ Following code has to run from cache since + ? ? ? @ the RAM is going to self refresh mode + ? ? ? .align 5 + ? ? ? str ? ? r2, [r5, #DENALI_CTL_22_OFF] + +1: + ? ? ? ldr ? ? r4, [r5, #DENALI_CTL_112_OFF] + ? ? ? tst ? ? r4, #0x1 + ? ? ? bne ? ? 1b + + ? ? ? @ write SLEEPFORCE through rtc iobridge + + ? ? ? str ? ? r1, [r7] + ? ? ? @ wait rtc io bridge sync +1: + ? ? ? ldr ? ? r3, [r7] + ? ? ? tst ? ? r3, #0x01 + ? ? ? bne ? ? 1b + ? ? ? b . --1.7.0.4
PATCH v2 3/3 ARM: CSR: PM: add sleep entry for SiRFprimaII
Quoted 6 lines · Barry Song
2011/9/21 Barry Song <[email protected]>:
Quoted 5 lines
From: Rongjun Ying <[email protected]>
This patch adds suspend-to-mem support for prima2. It will make prima2 enter DEEPSLEEP mode while accepting
PM_SUSPEND_MEMcommand.
Quoted 6 lines
Quoted 1 line
Signed-off-by Rongjun Ying <[email protected]>sorry for typo. it should be:
Signed-off-by Rongjun Ying <[email protected]>this was fixed in repository for pull.
Ok, I've made sure I have the right version.
Arnd