All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH] sh: SuperH Mobile suspend support
@ 2009-03-09 10:51 Magnus Damm
  2009-03-09 16:10 ` Paul Mundt
                   ` (2 more replies)
  0 siblings, 3 replies; 9+ messages in thread
From: Magnus Damm @ 2009-03-09 10:51 UTC (permalink / raw)
  To: linux-sh

From: Magnus Damm <damm@igel.co.jp>

This patch adds CONFIG_SUSPEND support to the SuperH
architecture. If enabled, SuperH Mobile processors will
register their suspend callbacks during boot.

To suspend, use "echo mem > /sys/power/state". To allow
wakeup, make sure "/sys/device/platform/../power/wakeup"
contains "enabled". Additional per-device driver patches
are most likely needed.

Signed-off-by: Magnus Damm <damm@igel.co.jp>
---

 arch/sh/Kconfig                           |    1 
 arch/sh/include/asm/suspend.h             |   12 ++
 arch/sh/kernel/cpu/sh4a/Makefile          |    7 +
 arch/sh/kernel/cpu/sh4a/pm-sh_mobile.c    |   76 +++++++++++++++++
 arch/sh/kernel/cpu/sh4a/sleep-sh_mobile.S |  125 +++++++++++++++++++++++++++++
 5 files changed, 221 insertions(+)

--- 0004/arch/sh/Kconfig
+++ work/arch/sh/Kconfig	2009-03-09 19:36:29.000000000 +0900
@@ -159,6 +159,7 @@ config CPU_SH4
 	select CPU_HAS_SR_RB
 	select CPU_HAS_PTEA if !CPU_SH4A || CPU_SHX2
 	select CPU_HAS_FPU if !CPU_SH4AL_DSP
+	select ARCH_SUSPEND_POSSIBLE
 
 config CPU_SH4A
 	bool
--- 0005/arch/sh/include/asm/suspend.h
+++ work/arch/sh/include/asm/suspend.h	2009-03-09 19:36:29.000000000 +0900
@@ -1,6 +1,7 @@
 #ifndef _ASM_SH_SUSPEND_H
 #define _ASM_SH_SUSPEND_H
 
+#ifndef __ASSEMBLY__
 static inline int arch_prepare_suspend(void) { return 0; }
 
 #include <asm/ptrace.h>
@@ -9,5 +10,16 @@ struct swsusp_arch_regs {
 	struct pt_regs user_regs;
 	unsigned long bank1_regs[8];
 };
+#endif
+
+#define SUSP_SH_SLEEP		(1 << 0) /* Regular sleep mode */
+#define SUSP_SH_STANDBY		(1 << 1) /* Software standby mode */
+#define SUSP_SH_RSTANDBY	(1 << 2) /* R-standby mode */
+#define SUSP_SH_USTANDBY	(1 << 3) /* U-standby mode */
+#define SUSP_SH_SF		(1 << 4) /* Enable self-refresh */
+
+#define SUSP_MODE_SLEEP		(SUSP_SH_SLEEP)
+#define SUSP_MODE_SLEEP_SF	(SUSP_SH_SLEEP | SUSP_SH_SF)
+#define SUSP_MODE_STANDBY_SF	(SUSP_SH_STANDBY | SUSP_SH_SF)
 
 #endif /* _ASM_SH_SUSPEND_H */
--- 0001/arch/sh/kernel/cpu/sh4a/Makefile
+++ work/arch/sh/kernel/cpu/sh4a/Makefile	2009-03-09 19:36:29.000000000 +0900
@@ -35,6 +35,13 @@ pinmux-$(CONFIG_CPU_SUBTYPE_SH7723)	:= p
 pinmux-$(CONFIG_CPU_SUBTYPE_SH7785)	:= pinmux-sh7785.o
 pinmux-$(CONFIG_CPU_SUBTYPE_SH7786)	:= pinmux-sh7786.o
 
+# Power Mangement & Sleep mode
+pm-$(CONFIG_CPU_SUBTYPE_SH7343)		:= pm-sh_mobile.o sleep-sh_mobile.o
+pm-$(CONFIG_CPU_SUBTYPE_SH7366)		:= pm-sh_mobile.o sleep-sh_mobile.o
+pm-$(CONFIG_CPU_SUBTYPE_SH7722)		:= pm-sh_mobile.o sleep-sh_mobile.o
+pm-$(CONFIG_CPU_SUBTYPE_SH7723)		:= pm-sh_mobile.o sleep-sh_mobile.o
+
 obj-y			+= $(clock-y)
 obj-$(CONFIG_SMP)	+= $(smp-y)
 obj-$(CONFIG_GENERIC_GPIO)	+= $(pinmux-y)
+obj-$(CONFIG_PM)	+= $(pm-y)
--- /dev/null
+++ work/arch/sh/kernel/cpu/sh4a/pm-sh_mobile.c	2009-03-09 19:36:29.000000000 +0900
@@ -0,0 +1,76 @@
+/*
+ * arch/sh/kernel/cpu/sh4a/pm-sh_mobile.c
+ *
+ * Power management support code for SuperH Mobile
+ *
+ *  Copyright (C) 2009 Magnus Damm
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License.  See the file "COPYING" in the main directory of this archive
+ * for more details.
+ */
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/io.h>
+#include <linux/suspend.h>
+#include <asm/suspend.h>
+#include <asm/uaccess.h>
+
+extern const unsigned char do_standby[];
+extern const unsigned int do_standby_size;
+
+#define ILRAM_ADDR 0xe5200000
+
+static void set_vbr(void *base)
+{
+	asm volatile("ldc	%0, vbr"
+		     : /* no output */
+		     : "r" (base)
+		     : "memory");
+}
+
+static void sh_suspend_mode(unsigned long mode)
+{
+	extern void *vbr_base;
+	void *onchip_memory = (void *)ILRAM_ADDR;
+	void (*do_standby_ilram)(unsigned long) = onchip_memory;
+
+	/* wake up from sleep may generate exceptions
+	 * so setup temporary VBR to point to on-chip ram
+	 * if system ram will be put self-refresh during sleep.
+	 */
+
+	if (mode & SUSP_SH_SF)
+		set_vbr(onchip_memory);
+
+	memcpy(onchip_memory, do_standby, do_standby_size);
+	wmb();
+	ctrl_barrier();
+	do_standby_ilram(mode);
+
+	if (mode & SUSP_SH_SF)
+		set_vbr(&vbr_base);
+}
+
+static int sh_pm_enter(suspend_state_t state)
+{
+	local_irq_disable();
+	set_bl_bit();
+	sh_suspend_mode(SUSP_MODE_STANDBY_SF);
+	local_irq_disable();
+	clear_bl_bit();
+	return 0;
+}
+
+static struct platform_suspend_ops sh_pm_ops = {
+	.enter          = sh_pm_enter,
+	.valid          = suspend_valid_only_mem,
+};
+
+static int __init sh_pm_init(void)
+{
+	suspend_set_ops(&sh_pm_ops);
+	return 0;
+}
+
+late_initcall(sh_pm_init);
--- /dev/null
+++ work/arch/sh/kernel/cpu/sh4a/sleep-sh_mobile.S	2009-03-09 19:36:40.000000000 +0900
@@ -0,0 +1,125 @@
+/*
+ * arch/sh/kernel/cpu/sh4a/sleep-sh_mobile.S
+ *
+ * Sleep mode and Standby modes support for SuperH Mobile
+ *
+ *  Copyright (C) 2009 Magnus Damm
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License.  See the file "COPYING" in the main directory of this archive
+ * for more details.
+ */
+
+#include <linux/sys.h>
+#include <linux/errno.h>
+#include <linux/linkage.h>
+#include <asm/asm-offsets.h>
+#include <asm/suspend.h>
+
+/* manage self-refresh and enter standby mode.
+ * this code will be copied to on-chip memory and executed from there.
+ */
+
+	.balign 	4096,0,4096
+ENTRY(do_standby)
+	mov	r4, r0
+
+	tst	#SUSP_SH_SF, r0
+	bt	skip_set_sf
+
+	/* SDRAM: disable power down and put in self-refresh mode */
+	mov.l	1f, r4
+	mov.l	2f, r1
+	mov.l	@r4, r2
+	or	r1, r2
+	mov.l   3f, r3
+	and	r3, r2
+	mov.l	r2, @r4
+
+skip_set_sf:
+	tst	#SUSP_SH_SLEEP, r0
+	bt	test_standby
+
+	/* set mode to "sleep mode" */
+	bra	do_sleep
+	 mov	#0x00, r1
+
+test_standby:
+	tst	#SUSP_SH_STANDBY, r0
+	bt	test_rstandby
+
+	/* set mode to "software standby mode" */
+	bra	do_sleep
+	 mov	#0x80, r1
+
+test_rstandby:
+	tst	#SUSP_SH_RSTANDBY, r0
+	bt	test_ustandby
+
+	/* set mode to "r-standby mode" */
+	bra	do_sleep
+	 mov	#0x20, r1
+
+test_ustandby:
+	tst	#SUSP_SH_USTANDBY, r0
+	bt	done_sleep
+
+	/* set mode to "u-standby mode" */
+	mov	#0x10, r1
+
+	/* fall-through */
+
+do_sleep:
+	/* setup and enter selected standby mode */
+	mov.l	5f, r4
+	mov.l	r1, @r4
+	sleep
+
+done_sleep:
+	/* reset standby mode to sleep mode */
+	mov.l	5f, r4
+	mov	#0x00, r1
+	mov.l	r1, @r4
+
+	tst	#SUSP_SH_SF, r0
+	bt	skip_restore_sf
+
+	/* SDRAM: set auto-refresh mode */
+	mov.l	1f, r4
+	mov.l	@r4, r2
+	mov.l   4f, r3
+	and	r3, r2
+	mov.l	r2, @r4
+	mov.l	6f, r4
+	mov.l	7f, r1
+	mov.l	8f, r2
+	mov.l	@r4, r3
+	mov	#-1, r4
+	add	r4, r3
+	or	r2, r3
+	mov.l	r3, @r1
+skip_restore_sf:
+	rts
+	 nop
+
+	.balign 4
+1:	.long	0xfe400008 /* SDCR0 */
+2:	.long	0x00000400
+3:	.long	0xffff7fff
+4:	.long	0xfffffbff
+5:	.long	0xa4150020 /* STBCR */
+6:	.long   0xfe40001c /* RTCOR */
+7:	.long   0xfe400018 /* RTCNT */
+8:	.long   0xa55a0000
+
+/* interrupt vector @ 0x600 */
+	.balign 	0x400,0,0x400
+	.long	0xdeadbeef
+	.balign 	0x200,0,0x200
+	/* sh7722 will end up here in sleep mode */
+	rte
+	 nop
+do_standby_end:
+
+ENTRY(do_standby_size)
+	.long do_standby_end - do_standby

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

* Re: [PATCH] sh: SuperH Mobile suspend support
  2009-03-09 10:51 [PATCH] sh: SuperH Mobile suspend support Magnus Damm
@ 2009-03-09 16:10 ` Paul Mundt
  2009-03-12 14:45 ` [PATCH] sh: SuperH Mobile suspend support V2 Magnus Damm
  2009-03-13 15:23 ` [PATCH] sh: SuperH Mobile suspend support V3 Magnus Damm
  2 siblings, 0 replies; 9+ messages in thread
From: Paul Mundt @ 2009-03-09 16:10 UTC (permalink / raw)
  To: linux-sh

On Mon, Mar 09, 2009 at 07:51:43PM +0900, Magnus Damm wrote:
> --- 0004/arch/sh/Kconfig
> +++ work/arch/sh/Kconfig	2009-03-09 19:36:29.000000000 +0900
> @@ -159,6 +159,7 @@ config CPU_SH4
>  	select CPU_HAS_SR_RB
>  	select CPU_HAS_PTEA if !CPU_SH4A || CPU_SHX2
>  	select CPU_HAS_FPU if !CPU_SH4AL_DSP
> +	select ARCH_SUSPEND_POSSIBLE
>  
>  config CPU_SH4A
>  	bool

This is bogus, as this is all SH-Mobile specific. The easiest option is
probably to define a CPU_SHMOBILE that all of these CPUs can select, and
then moving all of this in to arch/sh/kernel/cpu/shmobile/. We've done
similar things on the ARM side for code-sharing between SH-Mobile G3 and
G4 for example.

> --- 0005/arch/sh/include/asm/suspend.h
> +++ work/arch/sh/include/asm/suspend.h	2009-03-09 19:36:29.000000000 +0900
> @@ -1,6 +1,7 @@
>  #ifndef _ASM_SH_SUSPEND_H
>  #define _ASM_SH_SUSPEND_H
>  
> +#ifndef __ASSEMBLY__
>  static inline int arch_prepare_suspend(void) { return 0; }
>  
>  #include <asm/ptrace.h>
> @@ -9,5 +10,16 @@ struct swsusp_arch_regs {
>  	struct pt_regs user_regs;
>  	unsigned long bank1_regs[8];
>  };
> +#endif
> +
> +#define SUSP_SH_SLEEP		(1 << 0) /* Regular sleep mode */
> +#define SUSP_SH_STANDBY		(1 << 1) /* Software standby mode */
> +#define SUSP_SH_RSTANDBY	(1 << 2) /* R-standby mode */
> +#define SUSP_SH_USTANDBY	(1 << 3) /* U-standby mode */
> +#define SUSP_SH_SF		(1 << 4) /* Enable self-refresh */
> +
This probably wants a bit more explanation, as it's not entirely obvious
for folks not familiar with SH-Mobile internals what standby modes are
generic SH vs SH-Mobile specific.

> +extern const unsigned char do_standby[];
> +extern const unsigned int do_standby_size;
> +
These are pretty uninspired globals, please use something more
definitive. (ie, shmobile_enter_standby/shmobile_standby_size or
something similar).

> +static void set_vbr(void *base)
> +{
> +	asm volatile("ldc	%0, vbr"
> +		     : /* no output */
> +		     : "r" (base)
> +		     : "memory");
> +}
> +
Just toss this in an asm/ header somewhere, it's not worth reimplementing
all over the place. Although for a single instruction it doesn't really
add much, you may as well just open-code it.

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

* [PATCH] sh: SuperH Mobile suspend support V2
  2009-03-09 10:51 [PATCH] sh: SuperH Mobile suspend support Magnus Damm
  2009-03-09 16:10 ` Paul Mundt
@ 2009-03-12 14:45 ` Magnus Damm
  2009-03-13 15:23 ` [PATCH] sh: SuperH Mobile suspend support V3 Magnus Damm
  2 siblings, 0 replies; 9+ messages in thread
From: Magnus Damm @ 2009-03-12 14:45 UTC (permalink / raw)
  To: linux-sh

From: Magnus Damm <damm@igel.co.jp>

This patch contains CONFIG_SUSPEND support to the SuperH
architecture V2. If enabled, SuperH Mobile processors will
register their suspend callbacks during boot.

To suspend, use "echo mem > /sys/power/state". To allow
wakeup, make sure "/sys/device/platform/../power/wakeup"
contains "enabled". Additional per-device driver patches
are most likely needed.

Signed-off-by: Magnus Damm <damm@igel.co.jp>
---

 Changes since V1:
 - fixed up issues pointed out by Paul
 - added more comments

 arch/sh/Kconfig                           |    1 
 arch/sh/include/asm/suspend.h             |    9 ++
 arch/sh/kernel/cpu/sh4a/Makefile          |    7 +
 arch/sh/kernel/cpu/sh4a/pm-sh_mobile.c    |   92 +++++++++++++++++++++
 arch/sh/kernel/cpu/sh4a/sleep-sh_mobile.S |  125 +++++++++++++++++++++++++++++
 5 files changed, 234 insertions(+)

--- 0005/arch/sh/Kconfig
+++ work/arch/sh/Kconfig	2009-03-12 23:13:25.000000000 +0900
@@ -181,6 +181,7 @@ config CPU_SHX3
 
 config ARCH_SHMOBILE
 	bool
+	select ARCH_SUSPEND_POSSIBLE
 
 choice
 	prompt "Processor sub-type selection"
--- 0001/arch/sh/include/asm/suspend.h
+++ work/arch/sh/include/asm/suspend.h	2009-03-12 23:16:59.000000000 +0900
@@ -1,6 +1,7 @@
 #ifndef _ASM_SH_SUSPEND_H
 #define _ASM_SH_SUSPEND_H
 
+#ifndef __ASSEMBLY__
 static inline int arch_prepare_suspend(void) { return 0; }
 
 #include <asm/ptrace.h>
@@ -9,5 +10,13 @@ struct swsusp_arch_regs {
 	struct pt_regs user_regs;
 	unsigned long bank1_regs[8];
 };
+#endif
+
+/* flags passed to assembly suspend code */
+#define SUSP_SH_SLEEP		(1 << 0) /* Regular sleep mode */
+#define SUSP_SH_STANDBY		(1 << 1) /* SH-Mobile Software standby mode */
+#define SUSP_SH_RSTANDBY	(1 << 2) /* SH-Mobile R-standby mode */
+#define SUSP_SH_USTANDBY	(1 << 3) /* SH-Mobile U-standby mode */
+#define SUSP_SH_SF		(1 << 4) /* Enable self-refresh */
 
 #endif /* _ASM_SH_SUSPEND_H */
--- 0001/arch/sh/kernel/cpu/sh4a/Makefile
+++ work/arch/sh/kernel/cpu/sh4a/Makefile	2009-03-12 22:15:16.000000000 +0900
@@ -35,6 +35,13 @@ pinmux-$(CONFIG_CPU_SUBTYPE_SH7723)	:= p
 pinmux-$(CONFIG_CPU_SUBTYPE_SH7785)	:= pinmux-sh7785.o
 pinmux-$(CONFIG_CPU_SUBTYPE_SH7786)	:= pinmux-sh7786.o
 
+# Power Mangement & Sleep mode
+pm-$(CONFIG_CPU_SUBTYPE_SH7343)		:= pm-sh_mobile.o sleep-sh_mobile.o
+pm-$(CONFIG_CPU_SUBTYPE_SH7366)		:= pm-sh_mobile.o sleep-sh_mobile.o
+pm-$(CONFIG_CPU_SUBTYPE_SH7722)		:= pm-sh_mobile.o sleep-sh_mobile.o
+pm-$(CONFIG_CPU_SUBTYPE_SH7723)		:= pm-sh_mobile.o sleep-sh_mobile.o
+
 obj-y			+= $(clock-y)
 obj-$(CONFIG_SMP)	+= $(smp-y)
 obj-$(CONFIG_GENERIC_GPIO)	+= $(pinmux-y)
+obj-$(CONFIG_PM)	+= $(pm-y)
--- /dev/null
+++ work/arch/sh/kernel/cpu/sh4a/pm-sh_mobile.c	2009-03-12 23:37:17.000000000 +0900
@@ -0,0 +1,92 @@
+/*
+ * arch/sh/kernel/cpu/sh4a/pm-sh_mobile.c
+ *
+ * Power management support code for SuperH Mobile
+ *
+ *  Copyright (C) 2009 Magnus Damm
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License.  See the file "COPYING" in the main directory of this archive
+ * for more details.
+ */
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/io.h>
+#include <linux/suspend.h>
+#include <asm/suspend.h>
+#include <asm/uaccess.h>
+
+/*
+ * Sleep modes available on SuperH Mobile:
+ *
+ * Sleep mode is just plain "sleep" instruction
+ * Sleep Self-Refresh mode is above plus RAM put in Self-Refresh
+ * Standby Self-Refresh mode is above plus stopped clocks
+ */
+#define SUSP_MODE_SLEEP		(SUSP_SH_SLEEP)
+#define SUSP_MODE_SLEEP_SF	(SUSP_SH_SLEEP | SUSP_SH_SF)
+#define SUSP_MODE_STANDBY_SF	(SUSP_SH_STANDBY | SUSP_SH_SF)
+
+/*
+ * The following modes are not there yet:
+ *
+ * R-standby mode is unsupported, but will be added in the future
+ * U-standby mode is low priority since it needs bootloader hacks
+ *
+ * All modes should be tied in with cpuidle. But before that can
+ * happen we need to keep track of enabled hardware blocks so we
+ * can avoid entering sleep modes that stop clocks to hardware
+ * blocks that are in use even though the cpu core is idle.
+ */
+
+extern const unsigned char sh_mobile_standby[];
+extern const unsigned int sh_mobile_standby_size;
+
+static void sh_mobile_call_standby(unsigned long mode)
+{
+	extern void *vbr_base;
+	void *onchip_mem = (void *)0xe520000; /* ILRAM */
+	void (*standby_onchip_mem)(unsigned long) = onchip_mem;
+
+	/* Note: Wake up from sleep may generate exceptions!
+	 * Setup VBR to point to on-chip ram if self-refresh is
+	 * going to be used.
+	 */
+	if (mode & SUSP_SH_SF)
+		asm volatile("ldc %0, vbr" : : "r" (onchip_mem) : "memory");
+
+	/* Copy the assembly snippet to the otherwise ununsed ILRAM */
+	memcpy(onchip_mem, sh_mobile_standby, sh_mobile_standby_size);
+	wmb();
+	ctrl_barrier();
+
+	/* Let assembly snippet in on-chip memory handle the rest */
+	standby_onchip_mem(mode);
+
+	/* Put VBR back in System RAM again */
+	if (mode & SUSP_SH_SF)
+		asm volatile("ldc %0, vbr" : : "r" (&vbr_base) : "memory");
+}
+
+static int sh_pm_enter(suspend_state_t state)
+{
+	local_irq_disable();
+	set_bl_bit();
+	sh_mobile_call_standby(SUSP_MODE_STANDBY_SF);
+	local_irq_disable();
+	clear_bl_bit();
+	return 0;
+}
+
+static struct platform_suspend_ops sh_pm_ops = {
+	.enter          = sh_pm_enter,
+	.valid          = suspend_valid_only_mem,
+};
+
+static int __init sh_pm_init(void)
+{
+	suspend_set_ops(&sh_pm_ops);
+	return 0;
+}
+
+late_initcall(sh_pm_init);
--- /dev/null
+++ work/arch/sh/kernel/cpu/sh4a/sleep-sh_mobile.S	2009-03-12 23:31:02.000000000 +0900
@@ -0,0 +1,125 @@
+/*
+ * arch/sh/kernel/cpu/sh4a/sleep-sh_mobile.S
+ *
+ * Sleep mode and Standby modes support for SuperH Mobile
+ *
+ *  Copyright (C) 2009 Magnus Damm
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License.  See the file "COPYING" in the main directory of this archive
+ * for more details.
+ */
+
+#include <linux/sys.h>
+#include <linux/errno.h>
+#include <linux/linkage.h>
+#include <asm/asm-offsets.h>
+#include <asm/suspend.h>
+
+/* manage self-refresh and enter standby mode.
+ * this code will be copied to on-chip memory and executed from there.
+ */
+
+	.balign 	4096,0,4096
+ENTRY(sh_mobile_standby)
+	mov	r4, r0
+
+	tst	#SUSP_SH_SF, r0
+	bt	skip_set_sf
+
+	/* SDRAM: disable power down and put in self-refresh mode */
+	mov.l	1f, r4
+	mov.l	2f, r1
+	mov.l	@r4, r2
+	or	r1, r2
+	mov.l   3f, r3
+	and	r3, r2
+	mov.l	r2, @r4
+
+skip_set_sf:
+	tst	#SUSP_SH_SLEEP, r0
+	bt	test_standby
+
+	/* set mode to "sleep mode" */
+	bra	do_sleep
+	 mov	#0x00, r1
+
+test_standby:
+	tst	#SUSP_SH_STANDBY, r0
+	bt	test_rstandby
+
+	/* set mode to "software standby mode" */
+	bra	do_sleep
+	 mov	#0x80, r1
+
+test_rstandby:
+	tst	#SUSP_SH_RSTANDBY, r0
+	bt	test_ustandby
+
+	/* set mode to "r-standby mode" */
+	bra	do_sleep
+	 mov	#0x20, r1
+
+test_ustandby:
+	tst	#SUSP_SH_USTANDBY, r0
+	bt	done_sleep
+
+	/* set mode to "u-standby mode" */
+	mov	#0x10, r1
+
+	/* fall-through */
+
+do_sleep:
+	/* setup and enter selected standby mode */
+	mov.l	5f, r4
+	mov.l	r1, @r4
+	sleep
+
+done_sleep:
+	/* reset standby mode to sleep mode */
+	mov.l	5f, r4
+	mov	#0x00, r1
+	mov.l	r1, @r4
+
+	tst	#SUSP_SH_SF, r0
+	bt	skip_restore_sf
+
+	/* SDRAM: set auto-refresh mode */
+	mov.l	1f, r4
+	mov.l	@r4, r2
+	mov.l   4f, r3
+	and	r3, r2
+	mov.l	r2, @r4
+	mov.l	6f, r4
+	mov.l	7f, r1
+	mov.l	8f, r2
+	mov.l	@r4, r3
+	mov	#-1, r4
+	add	r4, r3
+	or	r2, r3
+	mov.l	r3, @r1
+skip_restore_sf:
+	rts
+	 nop
+
+	.balign 4
+1:	.long	0xfe400008 /* SDCR0 */
+2:	.long	0x00000400
+3:	.long	0xffff7fff
+4:	.long	0xfffffbff
+5:	.long	0xa4150020 /* STBCR */
+6:	.long   0xfe40001c /* RTCOR */
+7:	.long   0xfe400018 /* RTCNT */
+8:	.long   0xa55a0000
+
+/* interrupt vector @ 0x600 */
+	.balign 	0x400,0,0x400
+	.long	0xdeadbeef
+	.balign 	0x200,0,0x200
+	/* sh7722 will end up here in sleep mode */
+	rte
+	 nop
+sh_mobile_standby_end:
+
+ENTRY(sh_mobile_standby_size)
+	.long sh_mobile_standby_end - sh_mobile_standby

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

* [PATCH] sh: SuperH Mobile suspend support V3
  2009-03-09 10:51 [PATCH] sh: SuperH Mobile suspend support Magnus Damm
  2009-03-09 16:10 ` Paul Mundt
  2009-03-12 14:45 ` [PATCH] sh: SuperH Mobile suspend support V2 Magnus Damm
@ 2009-03-13 15:23 ` Magnus Damm
  2009-03-16 11:00     ` Paul Mundt
  2 siblings, 1 reply; 9+ messages in thread
From: Magnus Damm @ 2009-03-13 15:23 UTC (permalink / raw)
  To: linux-sh

From: Magnus Damm <damm@igel.co.jp>

This patch contains CONFIG_SUSPEND support to the SuperH
architecture V3. If enabled, SuperH Mobile processors will
register their suspend callbacks during boot.

To suspend, use "echo mem > /sys/power/state". To allow
wakeup, make sure "/sys/device/platform/../power/wakeup"
contains "enabled". Additional per-device driver patches
are most likely needed.

Signed-off-by: Magnus Damm <damm@igel.co.jp>
---

 Changes since V2:
 - fixed ILRAM typo
 - use CONFIG_ARCH_SHMOBILE in Makefile

 Changes since V1:
 - fixed up issues pointed out by Paul
 - added more comments

 arch/sh/Kconfig                           |    1 
 arch/sh/include/asm/suspend.h             |    9 ++
 arch/sh/kernel/cpu/sh4a/Makefile          |    4 
 arch/sh/kernel/cpu/sh4a/pm-sh_mobile.c    |   92 +++++++++++++++++++++
 arch/sh/kernel/cpu/sh4a/sleep-sh_mobile.S |  125 +++++++++++++++++++++++++++++
 5 files changed, 231 insertions(+)

--- 0005/arch/sh/Kconfig
+++ work/arch/sh/Kconfig	2009-03-13 14:19:50.000000000 +0900
@@ -181,6 +181,7 @@ config CPU_SHX3
 
 config ARCH_SHMOBILE
 	bool
+	select ARCH_SUSPEND_POSSIBLE
 
 choice
 	prompt "Processor sub-type selection"
--- 0001/arch/sh/include/asm/suspend.h
+++ work/arch/sh/include/asm/suspend.h	2009-03-13 14:19:50.000000000 +0900
@@ -1,6 +1,7 @@
 #ifndef _ASM_SH_SUSPEND_H
 #define _ASM_SH_SUSPEND_H
 
+#ifndef __ASSEMBLY__
 static inline int arch_prepare_suspend(void) { return 0; }
 
 #include <asm/ptrace.h>
@@ -9,5 +10,13 @@ struct swsusp_arch_regs {
 	struct pt_regs user_regs;
 	unsigned long bank1_regs[8];
 };
+#endif
+
+/* flags passed to assembly suspend code */
+#define SUSP_SH_SLEEP		(1 << 0) /* Regular sleep mode */
+#define SUSP_SH_STANDBY		(1 << 1) /* SH-Mobile Software standby mode */
+#define SUSP_SH_RSTANDBY	(1 << 2) /* SH-Mobile R-standby mode */
+#define SUSP_SH_USTANDBY	(1 << 3) /* SH-Mobile U-standby mode */
+#define SUSP_SH_SF		(1 << 4) /* Enable self-refresh */
 
 #endif /* _ASM_SH_SUSPEND_H */
--- 0001/arch/sh/kernel/cpu/sh4a/Makefile
+++ work/arch/sh/kernel/cpu/sh4a/Makefile	2009-03-13 15:39:05.000000000 +0900
@@ -35,6 +35,10 @@ pinmux-$(CONFIG_CPU_SUBTYPE_SH7723)	:= p
 pinmux-$(CONFIG_CPU_SUBTYPE_SH7785)	:= pinmux-sh7785.o
 pinmux-$(CONFIG_CPU_SUBTYPE_SH7786)	:= pinmux-sh7786.o
 
+# Power Mangement & Sleep mode
+pm-$(CONFIG_ARCH_SHMOBILE)		:= pm-sh_mobile.o sleep-sh_mobile.o
+
 obj-y			+= $(clock-y)
 obj-$(CONFIG_SMP)	+= $(smp-y)
 obj-$(CONFIG_GENERIC_GPIO)	+= $(pinmux-y)
+obj-$(CONFIG_PM)	+= $(pm-y)
--- /dev/null
+++ work/arch/sh/kernel/cpu/sh4a/pm-sh_mobile.c	2009-03-13 15:38:32.000000000 +0900
@@ -0,0 +1,92 @@
+/*
+ * arch/sh/kernel/cpu/sh4a/pm-sh_mobile.c
+ *
+ * Power management support code for SuperH Mobile
+ *
+ *  Copyright (C) 2009 Magnus Damm
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License.  See the file "COPYING" in the main directory of this archive
+ * for more details.
+ */
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/io.h>
+#include <linux/suspend.h>
+#include <asm/suspend.h>
+#include <asm/uaccess.h>
+
+/*
+ * Sleep modes available on SuperH Mobile:
+ *
+ * Sleep mode is just plain "sleep" instruction
+ * Sleep Self-Refresh mode is above plus RAM put in Self-Refresh
+ * Standby Self-Refresh mode is above plus stopped clocks
+ */
+#define SUSP_MODE_SLEEP		(SUSP_SH_SLEEP)
+#define SUSP_MODE_SLEEP_SF	(SUSP_SH_SLEEP | SUSP_SH_SF)
+#define SUSP_MODE_STANDBY_SF	(SUSP_SH_STANDBY | SUSP_SH_SF)
+
+/*
+ * The following modes are not there yet:
+ *
+ * R-standby mode is unsupported, but will be added in the future
+ * U-standby mode is low priority since it needs bootloader hacks
+ *
+ * All modes should be tied in with cpuidle. But before that can
+ * happen we need to keep track of enabled hardware blocks so we
+ * can avoid entering sleep modes that stop clocks to hardware
+ * blocks that are in use even though the cpu core is idle.
+ */
+
+extern const unsigned char sh_mobile_standby[];
+extern const unsigned int sh_mobile_standby_size;
+
+static void sh_mobile_call_standby(unsigned long mode)
+{
+	extern void *vbr_base;
+	void *onchip_mem = (void *)0xe5200000; /* ILRAM */
+	void (*standby_onchip_mem)(unsigned long) = onchip_mem;
+
+	/* Note: Wake up from sleep may generate exceptions!
+	 * Setup VBR to point to on-chip ram if self-refresh is
+	 * going to be used.
+	 */
+	if (mode & SUSP_SH_SF)
+		asm volatile("ldc %0, vbr" : : "r" (onchip_mem) : "memory");
+
+	/* Copy the assembly snippet to the otherwise ununsed ILRAM */
+	memcpy(onchip_mem, sh_mobile_standby, sh_mobile_standby_size);
+	wmb();
+	ctrl_barrier();
+
+	/* Let assembly snippet in on-chip memory handle the rest */
+	standby_onchip_mem(mode);
+
+	/* Put VBR back in System RAM again */
+	if (mode & SUSP_SH_SF)
+		asm volatile("ldc %0, vbr" : : "r" (&vbr_base) : "memory");
+}
+
+static int sh_pm_enter(suspend_state_t state)
+{
+	local_irq_disable();
+	set_bl_bit();
+	sh_mobile_call_standby(SUSP_MODE_STANDBY_SF);
+	local_irq_disable();
+	clear_bl_bit();
+	return 0;
+}
+
+static struct platform_suspend_ops sh_pm_ops = {
+	.enter          = sh_pm_enter,
+	.valid          = suspend_valid_only_mem,
+};
+
+static int __init sh_pm_init(void)
+{
+	suspend_set_ops(&sh_pm_ops);
+	return 0;
+}
+
+late_initcall(sh_pm_init);
--- /dev/null
+++ work/arch/sh/kernel/cpu/sh4a/sleep-sh_mobile.S	2009-03-13 14:19:50.000000000 +0900
@@ -0,0 +1,125 @@
+/*
+ * arch/sh/kernel/cpu/sh4a/sleep-sh_mobile.S
+ *
+ * Sleep mode and Standby modes support for SuperH Mobile
+ *
+ *  Copyright (C) 2009 Magnus Damm
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License.  See the file "COPYING" in the main directory of this archive
+ * for more details.
+ */
+
+#include <linux/sys.h>
+#include <linux/errno.h>
+#include <linux/linkage.h>
+#include <asm/asm-offsets.h>
+#include <asm/suspend.h>
+
+/* manage self-refresh and enter standby mode.
+ * this code will be copied to on-chip memory and executed from there.
+ */
+
+	.balign 	4096,0,4096
+ENTRY(sh_mobile_standby)
+	mov	r4, r0
+
+	tst	#SUSP_SH_SF, r0
+	bt	skip_set_sf
+
+	/* SDRAM: disable power down and put in self-refresh mode */
+	mov.l	1f, r4
+	mov.l	2f, r1
+	mov.l	@r4, r2
+	or	r1, r2
+	mov.l   3f, r3
+	and	r3, r2
+	mov.l	r2, @r4
+
+skip_set_sf:
+	tst	#SUSP_SH_SLEEP, r0
+	bt	test_standby
+
+	/* set mode to "sleep mode" */
+	bra	do_sleep
+	 mov	#0x00, r1
+
+test_standby:
+	tst	#SUSP_SH_STANDBY, r0
+	bt	test_rstandby
+
+	/* set mode to "software standby mode" */
+	bra	do_sleep
+	 mov	#0x80, r1
+
+test_rstandby:
+	tst	#SUSP_SH_RSTANDBY, r0
+	bt	test_ustandby
+
+	/* set mode to "r-standby mode" */
+	bra	do_sleep
+	 mov	#0x20, r1
+
+test_ustandby:
+	tst	#SUSP_SH_USTANDBY, r0
+	bt	done_sleep
+
+	/* set mode to "u-standby mode" */
+	mov	#0x10, r1
+
+	/* fall-through */
+
+do_sleep:
+	/* setup and enter selected standby mode */
+	mov.l	5f, r4
+	mov.l	r1, @r4
+	sleep
+
+done_sleep:
+	/* reset standby mode to sleep mode */
+	mov.l	5f, r4
+	mov	#0x00, r1
+	mov.l	r1, @r4
+
+	tst	#SUSP_SH_SF, r0
+	bt	skip_restore_sf
+
+	/* SDRAM: set auto-refresh mode */
+	mov.l	1f, r4
+	mov.l	@r4, r2
+	mov.l   4f, r3
+	and	r3, r2
+	mov.l	r2, @r4
+	mov.l	6f, r4
+	mov.l	7f, r1
+	mov.l	8f, r2
+	mov.l	@r4, r3
+	mov	#-1, r4
+	add	r4, r3
+	or	r2, r3
+	mov.l	r3, @r1
+skip_restore_sf:
+	rts
+	 nop
+
+	.balign 4
+1:	.long	0xfe400008 /* SDCR0 */
+2:	.long	0x00000400
+3:	.long	0xffff7fff
+4:	.long	0xfffffbff
+5:	.long	0xa4150020 /* STBCR */
+6:	.long   0xfe40001c /* RTCOR */
+7:	.long   0xfe400018 /* RTCNT */
+8:	.long   0xa55a0000
+
+/* interrupt vector @ 0x600 */
+	.balign 	0x400,0,0x400
+	.long	0xdeadbeef
+	.balign 	0x200,0,0x200
+	/* sh7722 will end up here in sleep mode */
+	rte
+	 nop
+sh_mobile_standby_end:
+
+ENTRY(sh_mobile_standby_size)
+	.long sh_mobile_standby_end - sh_mobile_standby

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

* [PATCH] sh: add ap325 lcd power off support
@ 2009-03-13 15:27 ` Magnus Damm
  0 siblings, 0 replies; 9+ messages in thread
From: Magnus Damm @ 2009-03-13 15:27 UTC (permalink / raw)
  To: linux-sh

From: Magnus Damm <damm@igel.co.jp>

Improve the ap325 board code to allow the lcd panel
and backlight to be powered off.

Signed-off-by: Magnus Damm <damm@igel.co.jp>
---

 arch/sh/boards/board-ap325rxa.c |   11 +++++++++++
 1 file changed, 11 insertions(+)

--- 0001/arch/sh/boards/board-ap325rxa.c
+++ work/arch/sh/boards/board-ap325rxa.c	2009-03-12 22:06:57.000000000 +0900
@@ -166,6 +166,16 @@ static void ap320_wvga_power_on(void *bo
 	ctrl_outw(0x100, FPGA_BKLREG);
 }
 
+static void ap320_wvga_power_off(void *board_data)
+{
+	/* backlight */
+	ctrl_outw(0, FPGA_BKLREG);
+	gpio_set_value(GPIO_PTS3, 1);
+
+	/* ASD AP-320/325 LCD OFF */
+	ctrl_outw(0, FPGA_LCDREG);
+}
+
 static struct sh_mobile_lcdc_info lcdc_info = {
 	.clock_source = LCDC_CLK_EXTERNAL,
 	.ch[0] = {
@@ -191,6 +201,7 @@ static struct sh_mobile_lcdc_info lcdc_i
 		},
 		.board_cfg = {
 			.display_on = ap320_wvga_power_on,
+			.display_off = ap320_wvga_power_off,
 		},
 	}
 };

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

* [PATCH] video: sh_mobile_lcdcfb suspend/resume support
@ 2009-03-13 15:36 ` Magnus Damm
  0 siblings, 0 replies; 9+ messages in thread
From: Magnus Damm @ 2009-03-13 15:36 UTC (permalink / raw)
  To: linux-fbdev-devel; +Cc: Magnus Damm, lethal, linux-sh

From: Magnus Damm <damm@igel.co.jp>

This patch adds suspend/resume support to the LCDC
driver for SuperH Mobile - sh_mobile_lcdcfb.

We simply stop hardware on suspend and start it again
on resume. For RGB panels this is trivial, but for SYS
panels in deferred io mode this becomes a bit more
difficult - we need to wait for a frame end interrupt
to make sure the clocks are balanced before stopping
the actual hardware.

Signed-off-by: Magnus Damm <damm@igel.co.jp>
---

 Tested on ap325 and Migo-R.

 drivers/video/sh_mobile_lcdcfb.c |   66 +++++++++++++++++++++++++++++++++-----
 1 file changed, 59 insertions(+), 7 deletions(-)

--- 0001/drivers/video/sh_mobile_lcdcfb.c
+++ work/drivers/video/sh_mobile_lcdcfb.c	2009-03-14 00:06:47.000000000 +0900
@@ -33,6 +33,8 @@ struct sh_mobile_lcdc_chan {
 	struct fb_info info;
 	dma_addr_t dma_handle;
 	struct fb_deferred_io defio;
+	unsigned long frame_end;
+	wait_queue_head_t frame_end_wait;
 };
 
 struct sh_mobile_lcdc_priv {
@@ -226,7 +228,10 @@ static void sh_mobile_lcdc_deferred_io_t
 static irqreturn_t sh_mobile_lcdc_irq(int irq, void *data)
 {
 	struct sh_mobile_lcdc_priv *priv = data;
+	struct sh_mobile_lcdc_chan *ch;
 	unsigned long tmp;
+	int is_sub;
+	int k;
 
 	/* acknowledge interrupt */
 	tmp = lcdc_read(priv, _LDINTR);
@@ -234,8 +239,24 @@ static irqreturn_t sh_mobile_lcdc_irq(in
 	tmp |= 0x000000ff ^ LDINTR_FS; /* status in low 8 */
 	lcdc_write(priv, _LDINTR, tmp);
 
-	/* disable clocks */
-	sh_mobile_lcdc_clk_off(priv);
+	/* figure out if this interrupt is for main or sub lcd */
+	is_sub = (lcdc_read(priv, _LDSR) & (1 << 10)) ? 1 : 0;
+
+	/* wake up channel and disable clocks*/
+	for (k = 0; k < ARRAY_SIZE(priv->ch); k++) {
+		ch = &priv->ch[k];
+
+		if (!ch->enabled)
+			continue;
+
+		if (is_sub == lcdc_chan_is_sublcd(ch)) {
+			ch->frame_end = 1;
+			wake_up(&ch->frame_end_wait);
+
+			sh_mobile_lcdc_clk_off(priv);
+		}
+	}
+
 	return IRQ_HANDLED;
 }
 
@@ -448,18 +469,27 @@ static void sh_mobile_lcdc_stop(struct s
 	struct sh_mobile_lcdc_board_cfg	*board_cfg;
 	int k;
 
-	/* tell the board code to disable the panel */
+	/* clean up deferred io and ask board code to disable panel */
 	for (k = 0; k < ARRAY_SIZE(priv->ch); k++) {
 		ch = &priv->ch[k];
-		board_cfg = &ch->cfg.board_cfg;
-		if (board_cfg->display_off)
-			board_cfg->display_off(board_cfg->board_data);
 
-		/* cleanup deferred io if enabled */
+		/* deferred io mode:
+		 * flush frame, and wait for frame end interrupt
+		 * clean up deferred io and enable clock
+		 */
 		if (ch->info.fbdefio) {
+			ch->frame_end = 0;
+			schedule_delayed_work(&ch->info.deferred_work, 0);
+			wait_event(ch->frame_end_wait, ch->frame_end);
 			fb_deferred_io_cleanup(&ch->info);
 			ch->info.fbdefio = NULL;
+			sh_mobile_lcdc_clk_on(priv);
 		}
+
+		board_cfg = &ch->cfg.board_cfg;
+		if (board_cfg->display_off)
+			board_cfg->display_off(board_cfg->board_data);
+
 	}
 
 	/* stop the lcdc */
@@ -652,6 +682,26 @@ static int sh_mobile_lcdc_set_bpp(struct
 	return 0;
 }
 
+static int sh_mobile_lcdc_suspend(struct device *dev)
+{
+	struct platform_device *pdev = to_platform_device(dev);
+
+	sh_mobile_lcdc_stop(platform_get_drvdata(pdev));
+	return 0;
+}
+
+static int sh_mobile_lcdc_resume(struct device *dev)
+{
+	struct platform_device *pdev = to_platform_device(dev);
+
+	return sh_mobile_lcdc_start(platform_get_drvdata(pdev));
+}
+
+static struct dev_pm_ops sh_mobile_lcdc_dev_pm_ops = {
+	.suspend = sh_mobile_lcdc_suspend,
+	.resume = sh_mobile_lcdc_resume,
+};
+
 static int sh_mobile_lcdc_remove(struct platform_device *pdev);
 
 static int __init sh_mobile_lcdc_probe(struct platform_device *pdev)
@@ -707,6 +757,7 @@ static int __init sh_mobile_lcdc_probe(s
 			dev_err(&pdev->dev, "unsupported interface type\n");
 			goto err1;
 		}
+		init_waitqueue_head(&priv->ch[i].frame_end_wait);
 
 		switch (pdata->ch[i].chan) {
 		case LCDC_CHAN_MAINLCD:
@@ -860,6 +911,7 @@ static struct platform_driver sh_mobile_
 	.driver		= {
 		.name		= "sh_mobile_lcdc_fb",
 		.owner		= THIS_MODULE,
+		.pm		= &sh_mobile_lcdc_dev_pm_ops,
 	},
 	.probe		= sh_mobile_lcdc_probe,
 	.remove		= sh_mobile_lcdc_remove,

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

* [PATCH] video: sh_mobile_lcdcfb suspend/resume support
@ 2009-03-13 15:36 ` Magnus Damm
  0 siblings, 0 replies; 9+ messages in thread
From: Magnus Damm @ 2009-03-13 15:36 UTC (permalink / raw)
  To: linux-fbdev-devel; +Cc: Magnus Damm, lethal, linux-sh

From: Magnus Damm <damm@igel.co.jp>

This patch adds suspend/resume support to the LCDC
driver for SuperH Mobile - sh_mobile_lcdcfb.

We simply stop hardware on suspend and start it again
on resume. For RGB panels this is trivial, but for SYS
panels in deferred io mode this becomes a bit more
difficult - we need to wait for a frame end interrupt
to make sure the clocks are balanced before stopping
the actual hardware.

Signed-off-by: Magnus Damm <damm@igel.co.jp>
---

 Tested on ap325 and Migo-R.

 drivers/video/sh_mobile_lcdcfb.c |   66 +++++++++++++++++++++++++++++++++-----
 1 file changed, 59 insertions(+), 7 deletions(-)

--- 0001/drivers/video/sh_mobile_lcdcfb.c
+++ work/drivers/video/sh_mobile_lcdcfb.c	2009-03-14 00:06:47.000000000 +0900
@@ -33,6 +33,8 @@ struct sh_mobile_lcdc_chan {
 	struct fb_info info;
 	dma_addr_t dma_handle;
 	struct fb_deferred_io defio;
+	unsigned long frame_end;
+	wait_queue_head_t frame_end_wait;
 };
 
 struct sh_mobile_lcdc_priv {
@@ -226,7 +228,10 @@ static void sh_mobile_lcdc_deferred_io_t
 static irqreturn_t sh_mobile_lcdc_irq(int irq, void *data)
 {
 	struct sh_mobile_lcdc_priv *priv = data;
+	struct sh_mobile_lcdc_chan *ch;
 	unsigned long tmp;
+	int is_sub;
+	int k;
 
 	/* acknowledge interrupt */
 	tmp = lcdc_read(priv, _LDINTR);
@@ -234,8 +239,24 @@ static irqreturn_t sh_mobile_lcdc_irq(in
 	tmp |= 0x000000ff ^ LDINTR_FS; /* status in low 8 */
 	lcdc_write(priv, _LDINTR, tmp);
 
-	/* disable clocks */
-	sh_mobile_lcdc_clk_off(priv);
+	/* figure out if this interrupt is for main or sub lcd */
+	is_sub = (lcdc_read(priv, _LDSR) & (1 << 10)) ? 1 : 0;
+
+	/* wake up channel and disable clocks*/
+	for (k = 0; k < ARRAY_SIZE(priv->ch); k++) {
+		ch = &priv->ch[k];
+
+		if (!ch->enabled)
+			continue;
+
+		if (is_sub = lcdc_chan_is_sublcd(ch)) {
+			ch->frame_end = 1;
+			wake_up(&ch->frame_end_wait);
+
+			sh_mobile_lcdc_clk_off(priv);
+		}
+	}
+
 	return IRQ_HANDLED;
 }
 
@@ -448,18 +469,27 @@ static void sh_mobile_lcdc_stop(struct s
 	struct sh_mobile_lcdc_board_cfg	*board_cfg;
 	int k;
 
-	/* tell the board code to disable the panel */
+	/* clean up deferred io and ask board code to disable panel */
 	for (k = 0; k < ARRAY_SIZE(priv->ch); k++) {
 		ch = &priv->ch[k];
-		board_cfg = &ch->cfg.board_cfg;
-		if (board_cfg->display_off)
-			board_cfg->display_off(board_cfg->board_data);
 
-		/* cleanup deferred io if enabled */
+		/* deferred io mode:
+		 * flush frame, and wait for frame end interrupt
+		 * clean up deferred io and enable clock
+		 */
 		if (ch->info.fbdefio) {
+			ch->frame_end = 0;
+			schedule_delayed_work(&ch->info.deferred_work, 0);
+			wait_event(ch->frame_end_wait, ch->frame_end);
 			fb_deferred_io_cleanup(&ch->info);
 			ch->info.fbdefio = NULL;
+			sh_mobile_lcdc_clk_on(priv);
 		}
+
+		board_cfg = &ch->cfg.board_cfg;
+		if (board_cfg->display_off)
+			board_cfg->display_off(board_cfg->board_data);
+
 	}
 
 	/* stop the lcdc */
@@ -652,6 +682,26 @@ static int sh_mobile_lcdc_set_bpp(struct
 	return 0;
 }
 
+static int sh_mobile_lcdc_suspend(struct device *dev)
+{
+	struct platform_device *pdev = to_platform_device(dev);
+
+	sh_mobile_lcdc_stop(platform_get_drvdata(pdev));
+	return 0;
+}
+
+static int sh_mobile_lcdc_resume(struct device *dev)
+{
+	struct platform_device *pdev = to_platform_device(dev);
+
+	return sh_mobile_lcdc_start(platform_get_drvdata(pdev));
+}
+
+static struct dev_pm_ops sh_mobile_lcdc_dev_pm_ops = {
+	.suspend = sh_mobile_lcdc_suspend,
+	.resume = sh_mobile_lcdc_resume,
+};
+
 static int sh_mobile_lcdc_remove(struct platform_device *pdev);
 
 static int __init sh_mobile_lcdc_probe(struct platform_device *pdev)
@@ -707,6 +757,7 @@ static int __init sh_mobile_lcdc_probe(s
 			dev_err(&pdev->dev, "unsupported interface type\n");
 			goto err1;
 		}
+		init_waitqueue_head(&priv->ch[i].frame_end_wait);
 
 		switch (pdata->ch[i].chan) {
 		case LCDC_CHAN_MAINLCD:
@@ -860,6 +911,7 @@ static struct platform_driver sh_mobile_
 	.driver		= {
 		.name		= "sh_mobile_lcdc_fb",
 		.owner		= THIS_MODULE,
+		.pm		= &sh_mobile_lcdc_dev_pm_ops,
 	},
 	.probe		= sh_mobile_lcdc_probe,
 	.remove		= sh_mobile_lcdc_remove,

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

* Re: [PATCH] sh: SuperH Mobile suspend support V3
  2009-03-13 15:23 ` [PATCH] sh: SuperH Mobile suspend support V3 Magnus Damm
@ 2009-03-16 11:00     ` Paul Mundt
  0 siblings, 0 replies; 9+ messages in thread
From: Paul Mundt @ 2009-03-16 11:00 UTC (permalink / raw)
  To: Magnus Damm; +Cc: linux-sh, francesco.virlinzi, linux-fbdev-devel

On Sat, Mar 14, 2009 at 12:23:04AM +0900, Magnus Damm wrote:
> This patch contains CONFIG_SUSPEND support to the SuperH
> architecture V3. If enabled, SuperH Mobile processors will
> register their suspend callbacks during boot.
> 
> To suspend, use "echo mem > /sys/power/state". To allow
> wakeup, make sure "/sys/device/platform/../power/wakeup"
> contains "enabled". Additional per-device driver patches
> are most likely needed.
> 
> Signed-off-by: Magnus Damm <damm@igel.co.jp>

On Sat, Mar 14, 2009 at 12:27:14AM +0900, Magnus Damm wrote:
> Improve the ap325 board code to allow the lcd panel
> and backlight to be powered off.
> 
> Signed-off-by: Magnus Damm <damm@igel.co.jp>

On Sat, Mar 14, 2009 at 12:36:55AM +0900, Magnus Damm wrote:
> This patch adds suspend/resume support to the LCDC
> driver for SuperH Mobile - sh_mobile_lcdcfb.
> 
> We simply stop hardware on suspend and start it again
> on resume. For RGB panels this is trivial, but for SYS
> panels in deferred io mode this becomes a bit more
> difficult - we need to wait for a frame end interrupt
> to make sure the clocks are balanced before stopping
> the actual hardware.
> 
> Signed-off-by: Magnus Damm <damm@igel.co.jp>

All applied, thanks.

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

* Re: [PATCH] sh: SuperH Mobile suspend support V3
@ 2009-03-16 11:00     ` Paul Mundt
  0 siblings, 0 replies; 9+ messages in thread
From: Paul Mundt @ 2009-03-16 11:00 UTC (permalink / raw)
  To: Magnus Damm; +Cc: linux-sh, francesco.virlinzi, linux-fbdev-devel

On Sat, Mar 14, 2009 at 12:23:04AM +0900, Magnus Damm wrote:
> This patch contains CONFIG_SUSPEND support to the SuperH
> architecture V3. If enabled, SuperH Mobile processors will
> register their suspend callbacks during boot.
> 
> To suspend, use "echo mem > /sys/power/state". To allow
> wakeup, make sure "/sys/device/platform/../power/wakeup"
> contains "enabled". Additional per-device driver patches
> are most likely needed.
> 
> Signed-off-by: Magnus Damm <damm@igel.co.jp>

On Sat, Mar 14, 2009 at 12:27:14AM +0900, Magnus Damm wrote:
> Improve the ap325 board code to allow the lcd panel
> and backlight to be powered off.
> 
> Signed-off-by: Magnus Damm <damm@igel.co.jp>

On Sat, Mar 14, 2009 at 12:36:55AM +0900, Magnus Damm wrote:
> This patch adds suspend/resume support to the LCDC
> driver for SuperH Mobile - sh_mobile_lcdcfb.
> 
> We simply stop hardware on suspend and start it again
> on resume. For RGB panels this is trivial, but for SYS
> panels in deferred io mode this becomes a bit more
> difficult - we need to wait for a frame end interrupt
> to make sure the clocks are balanced before stopping
> the actual hardware.
> 
> Signed-off-by: Magnus Damm <damm@igel.co.jp>

All applied, thanks.

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

end of thread, other threads:[~2009-03-16 11:00 UTC | newest]

Thread overview: 9+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2009-03-09 10:51 [PATCH] sh: SuperH Mobile suspend support Magnus Damm
2009-03-09 16:10 ` Paul Mundt
2009-03-12 14:45 ` [PATCH] sh: SuperH Mobile suspend support V2 Magnus Damm
2009-03-13 15:23 ` [PATCH] sh: SuperH Mobile suspend support V3 Magnus Damm
2009-03-16 11:00   ` Paul Mundt
2009-03-16 11:00     ` Paul Mundt
  -- strict thread matches above, loose matches on Subject: below --
2009-03-13 15:36 [PATCH] video: sh_mobile_lcdcfb suspend/resume support Magnus Damm
2009-03-13 15:36 ` Magnus Damm
2009-03-13 15:27 ` [PATCH] sh: add ap325 lcd power off support Magnus Damm

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.