linux-arm-kernel.lists.infradead.org archive mirror
 help / color / mirror / Atom feed
* [PATCH v2 0/3] ARCH: CSR: basic PM suspend/resume support
@ 2011-09-21 15:17 Barry Song
  2011-09-21 15:17 ` [PATCH v2 1/3] ARM: CSR: PM: save/restore timer status in suspend cycle Barry Song
                   ` (2 more replies)
  0 siblings, 3 replies; 6+ messages in thread
From: Barry Song @ 2011-09-21 15:17 UTC (permalink / raw)
  To: linux-arm-kernel

-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 <shawn.guo@linaro.org>'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

^ permalink raw reply	[flat|nested] 6+ messages in thread

* [PATCH v2 1/3] ARM: CSR: PM: save/restore timer status in suspend cycle
  2011-09-21 15:17 [PATCH v2 0/3] ARCH: CSR: basic PM suspend/resume support Barry Song
@ 2011-09-21 15:17 ` Barry Song
  2011-09-21 15:17 ` [PATCH v2 2/3] ARM: CSR: PM: save/restore irq " Barry Song
  2011-09-21 15:17 ` [PATCH v2 3/3] ARM: CSR: PM: add sleep entry for SiRFprimaII Barry Song
  2 siblings, 0 replies; 6+ messages in thread
From: Barry Song @ 2011-09-21 15:17 UTC (permalink / raw)
  To: linux-arm-kernel

From: Barry Song <baohua.song@csr.com>

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.

Signed-off-by: Barry Song <baohua.song@csr.com>
Acked-by: Arnd Bergmann <arnd@arndb.de>
---
 arch/arm/mach-prima2/timer.c |   34 ++++++++++++++++++++++++++++++++++
 1 files changed, 34 insertions(+), 0 deletions(-)

diff --git a/arch/arm/mach-prima2/timer.c b/arch/arm/mach-prima2/timer.c
index ed7ec48..3b15961 100644
--- a/arch/arm/mach-prima2/timer.c
+++ b/arch/arm/mach-prima2/timer.c
@@ -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 = {
-- 
1.7.0.4

^ permalink raw reply related	[flat|nested] 6+ messages in thread

* [PATCH v2 2/3] ARM: CSR: PM: save/restore irq status in suspend cycle
  2011-09-21 15:17 [PATCH v2 0/3] ARCH: CSR: basic PM suspend/resume support Barry Song
  2011-09-21 15:17 ` [PATCH v2 1/3] ARM: CSR: PM: save/restore timer status in suspend cycle Barry Song
@ 2011-09-21 15:17 ` Barry Song
  2011-09-21 15:17 ` [PATCH v2 3/3] ARM: CSR: PM: add sleep entry for SiRFprimaII Barry Song
  2 siblings, 0 replies; 6+ messages in thread
From: Barry Song @ 2011-09-21 15:17 UTC (permalink / raw)
  To: linux-arm-kernel

From: Barry Song <baohua.song@csr.com>

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.

Signed-off-by: Barry Song <baohua.song@csr.com>
Acked-by: Arnd Bergmann <arnd@arndb.de>
---
 arch/arm/mach-prima2/irq.c |   40 ++++++++++++++++++++++++++++++++++++++++
 1 files changed, 40 insertions(+), 0 deletions(-)

diff --git a/arch/arm/mach-prima2/irq.c b/arch/arm/mach-prima2/irq.c
index cf80a72..d93ceef 100644
--- a/arch/arm/mach-prima2/irq.c
+++ b/arch/arm/mach-prima2/irq.c
@@ -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);
-- 
1.7.0.4

^ permalink raw reply related	[flat|nested] 6+ messages in thread

* [PATCH v2 3/3] ARM: CSR: PM: add sleep entry for SiRFprimaII
  2011-09-21 15:17 [PATCH v2 0/3] ARCH: CSR: basic PM suspend/resume support Barry Song
  2011-09-21 15:17 ` [PATCH v2 1/3] ARM: CSR: PM: save/restore timer status in suspend cycle Barry Song
  2011-09-21 15:17 ` [PATCH v2 2/3] ARM: CSR: PM: save/restore irq " Barry Song
@ 2011-09-21 15:17 ` Barry Song
  2011-09-21 23:45   ` Barry Song
  2 siblings, 1 reply; 6+ messages in thread
From: Barry Song @ 2011-09-21 15:17 UTC (permalink / raw)
  To: linux-arm-kernel

From: Rongjun Ying <rongjun.ying@csr.com>

This patch adds suspend-to-mem support for prima2. It will make prima2
enter DEEPSLEEP mode while accepting PM_SUSPEND_MEM command.

Signed-off-by: Rongjun Ying <baohua.song@csr.com>
Signed-off-by: Barry Song <baohua.song@csr.com>
Acked-by: Arnd Bergmann <arnd@arndb.de>
---
-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

diff --git a/arch/arm/mach-prima2/Makefile b/arch/arm/mach-prima2/Makefile
index f49d70b..13dd160 100644
--- a/arch/arm/mach-prima2/Makefile
+++ b/arch/arm/mach-prima2/Makefile
@@ -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
diff --git a/arch/arm/mach-prima2/pm.c b/arch/arm/mach-prima2/pm.c
new file mode 100644
index 0000000..0ba39f3
--- /dev/null
+++ b/arch/arm/mach-prima2/pm.c
@@ -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);
diff --git a/arch/arm/mach-prima2/pm.h b/arch/arm/mach-prima2/pm.h
new file mode 100644
index 0000000..aa2b428
--- /dev/null
+++ b/arch/arm/mach-prima2/pm.h
@@ -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
+
diff --git a/arch/arm/mach-prima2/sleep.S b/arch/arm/mach-prima2/sleep.S
new file mode 100644
index 0000000..0745abc
--- /dev/null
+++ b/arch/arm/mach-prima2/sleep.S
@@ -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

^ permalink raw reply related	[flat|nested] 6+ messages in thread

* [PATCH v2 3/3] ARM: CSR: PM: add sleep entry for SiRFprimaII
  2011-09-21 15:17 ` [PATCH v2 3/3] ARM: CSR: PM: add sleep entry for SiRFprimaII Barry Song
@ 2011-09-21 23:45   ` Barry Song
  2011-09-22 15:19     ` Arnd Bergmann
  0 siblings, 1 reply; 6+ messages in thread
From: Barry Song @ 2011-09-21 23:45 UTC (permalink / raw)
  To: linux-arm-kernel

2011/9/21 Barry Song <21cnbao@gmail.com>:
> From: Rongjun Ying <rongjun.ying@csr.com>
>
> This patch adds suspend-to-mem support for prima2. It will make prima2
> enter DEEPSLEEP mode while accepting PM_SUSPEND_MEM command.
>
> Signed-off-by: Rongjun Ying <baohua.song@csr.com>

sorry for typo. it should be:
Signed-off-by: Rongjun Ying <rongjun.ying@csr.com>

this was fixed in repository for pull.

> Signed-off-by: Barry Song <baohua.song@csr.com>
> Acked-by: Arnd Bergmann <arnd@arndb.de>
> ---
> -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
>
> diff --git a/arch/arm/mach-prima2/Makefile b/arch/arm/mach-prima2/Makefile
> index f49d70b..13dd160 100644
> --- a/arch/arm/mach-prima2/Makefile
> +++ b/arch/arm/mach-prima2/Makefile
> @@ -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
> diff --git a/arch/arm/mach-prima2/pm.c b/arch/arm/mach-prima2/pm.c
> new file mode 100644
> index 0000000..0ba39f3
> --- /dev/null
> +++ b/arch/arm/mach-prima2/pm.c
> @@ -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);
> diff --git a/arch/arm/mach-prima2/pm.h b/arch/arm/mach-prima2/pm.h
> new file mode 100644
> index 0000000..aa2b428
> --- /dev/null
> +++ b/arch/arm/mach-prima2/pm.h
> @@ -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
> +
> diff --git a/arch/arm/mach-prima2/sleep.S b/arch/arm/mach-prima2/sleep.S
> new file mode 100644
> index 0000000..0745abc
> --- /dev/null
> +++ b/arch/arm/mach-prima2/sleep.S
> @@ -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
>
>

^ permalink raw reply	[flat|nested] 6+ messages in thread

* [PATCH v2 3/3] ARM: CSR: PM: add sleep entry for SiRFprimaII
  2011-09-21 23:45   ` Barry Song
@ 2011-09-22 15:19     ` Arnd Bergmann
  0 siblings, 0 replies; 6+ messages in thread
From: Arnd Bergmann @ 2011-09-22 15:19 UTC (permalink / raw)
  To: linux-arm-kernel

On Thursday 22 September 2011, Barry Song wrote:
> 2011/9/21 Barry Song <21cnbao@gmail.com>:
> > From: Rongjun Ying <rongjun.ying@csr.com>
> >
> > This patch adds suspend-to-mem support for prima2. It will make prima2
> > enter DEEPSLEEP mode while accepting PM_SUSPEND_MEM command.
> >
> > Signed-off-by: Rongjun Ying <baohua.song@csr.com>
> 
> sorry for typo. it should be:
> Signed-off-by: Rongjun Ying <rongjun.ying@csr.com>
> 
> this was fixed in repository for pull.

Ok, I've made sure I have the right version.

	Arnd

^ permalink raw reply	[flat|nested] 6+ messages in thread

end of thread, other threads:[~2011-09-22 15:19 UTC | newest]

Thread overview: 6+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2011-09-21 15:17 [PATCH v2 0/3] ARCH: CSR: basic PM suspend/resume support Barry Song
2011-09-21 15:17 ` [PATCH v2 1/3] ARM: CSR: PM: save/restore timer status in suspend cycle Barry Song
2011-09-21 15:17 ` [PATCH v2 2/3] ARM: CSR: PM: save/restore irq " Barry Song
2011-09-21 15:17 ` [PATCH v2 3/3] ARM: CSR: PM: add sleep entry for SiRFprimaII Barry Song
2011-09-21 23:45   ` Barry Song
2011-09-22 15:19     ` Arnd Bergmann

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).