public inbox for linux-sh@vger.kernel.org
 help / color / mirror / Atom feed
* [PATCH][RFC] sh: suspend interpreter V1
@ 2009-03-23  9:17 Magnus Damm
  2009-03-23 15:35 ` Francesco VIRLINZI
                   ` (25 more replies)
  0 siblings, 26 replies; 27+ messages in thread
From: Magnus Damm @ 2009-03-23  9:17 UTC (permalink / raw)
  To: linux-sh

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

Hi Francesco, everyone,

Here comes my first suspend interpreter attempt. This patch
contains a mix of both generic and superh mobile stuff.
It has only been dry coded so it probably is full of bugs.
The main point of interest are probably the SH_PM_OP_xxx ops.

The code in sleep.S is generic, so it should be moved out of
the shmobile directory in the future. The same goes for the
op defines and the structure, and for sh_pm_op(), sh_pm_run(),
sh_pm_init() and sh_pm_cleanup().

Start looking at sh_mobile_pm_setup(). The setup() callback is
used to build the code. The run callback will be used to execute
the built code, but it is unused so far. The old code in sleep.S
is still used, but with a little bit more of hacking it should be
possible to switch over. Not sure what to do about the VBR table
though.

Comments? Shall I keep on adding code, or start a rewrite? =)

Francesco, I suppose you will need more ops?

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

 arch/sh/kernel/cpu/shmobile/pm.c    |  162 +++++++++++++++++++++++++++++++++++
 arch/sh/kernel/cpu/shmobile/sleep.S |  109 +++++++++++++++++++++++
 2 files changed, 271 insertions(+)

--- 0001/arch/sh/kernel/cpu/shmobile/pm.c
+++ work/arch/sh/kernel/cpu/shmobile/pm.c	2009-03-23 18:00:51.000000000 +0900
@@ -16,6 +16,167 @@
 #include <asm/suspend.h>
 #include <asm/uaccess.h>
 
+#define SH_PM_OP_IMM_OFFS 8
+#define SH_PM_OP_JMP_OFFS 12
+#define SH_PM_OP_SIZE 16
+
+#define SH_PM_OP_MOV_IMM_R0	0
+#define SH_PM_OP_MOV_MEM8_R0	1
+#define SH_PM_OP_MOV_MEM16_R0	2
+#define SH_PM_OP_MOV_MEM32_R0	3
+#define SH_PM_OP_MOV_R0_MEM8	4
+#define SH_PM_OP_MOV_R0_MEM16	5
+#define SH_PM_OP_MOV_R0_MEM32	6
+#define SH_PM_OP_AND_IMM_R0	7
+#define SH_PM_OP_OR_IMM_R0	8
+#define SH_PM_OP_ADD_IMM_R0	9
+#define SH_PM_OP_SLEEP		10
+#define SH_PM_OP_RTS		11
+#define SH_PM_OP_NR		12
+
+extern unsigned char sh_pm_op_base[SH_PM_OP_SIZE * SH_PM_OP_NR];
+
+struct sh_pm_op_info {
+	unsigned char *buf;
+	unsigned int nr_ops;
+	void (*setup)(struct sh_pm_op_info *);
+	void (*run)(struct sh_pm_op_info *);
+};
+
+static void sh_pm_op(struct sh_pm_op_info *info, int op, unsigned int data)
+{
+	unsigned int size = SH_PM_OP_SIZE;
+	unsigned char *buf = info->buf;
+
+	if (buf) {
+		buf += info->nr_ops * size;
+		memcpy(buf, &sh_pm_op_base[op * size], size);
+		*(unsigned int *)(buf + SH_PM_OP_IMM_OFFS) = data;
+	}
+	info->nr_ops++;
+}
+
+static void sh_pm_run(struct sh_pm_op_info *info)
+{
+	void (*snippet)(void);
+
+	/* preload in cache */
+	snippet = (void *)(info->buf + SH_PM_OP_JMP_OFFS);
+	snippet();
+
+	/* execute in cache */
+	snippet = (void *)info->buf;
+	snippet();
+}
+
+int sh_pm_mode_init(struct sh_pm_op_info *info)
+{
+	/* run once without buffer to calculate amount of memory needed */
+	info->buf = NULL;
+	info->nr_ops = 0;
+	info->setup(info);
+
+	info->buf = kmalloc(info->nr_ops * SH_PM_OP_SIZE, GFP_KERNEL);
+	if (!info->buf)
+		return -ENOMEM;
+
+	/* run second time with buffer to generate actual code */
+	info->nr_ops = 0;
+	info->setup(info);
+	return 0;
+}
+
+void sh_pm_mode_cleanup(struct sh_pm_op_info *info)
+{
+	kfree(info->buf);
+}
+
+/* "sleep" mode */
+
+static void sh_mobile_pm_stbcr_setup(struct sh_pm_op_info *info,
+				     unsigned int mode)
+{
+	sh_pm_op(info, SH_PM_OP_MOV_IMM_R0, mode);
+	sh_pm_op(info, SH_PM_OP_MOV_R0_MEM32, 0xa4150020); /* STBCR */
+}
+
+static void sh_mobile_pm_sleep_setup(struct sh_pm_op_info *info)
+{
+	/* make sure STBCR is cleared, execute sleep, return */
+	sh_mobile_pm_stbcr_setup(info, 0);
+	sh_pm_op(info, SH_PM_OP_SLEEP, 0);
+	sh_pm_op(info, SH_PM_OP_RTS, 0);
+}
+
+static struct sh_pm_op_info sh_mobile_pm_sleep = {
+	.setup = sh_mobile_pm_sleep_setup,
+	.run = sh_pm_run,
+};
+
+/* "sleep" mode with system memory in self-refresh */
+
+static void sh_mobile_pm_sf_suspend(struct sh_pm_op_info *info)
+{
+	/* SDRAM: disable power down and put in self-refresh mode */
+	sh_pm_op(info, SH_PM_OP_MOV_MEM32_R0, 0xfe400008); /* SDCR0 */
+	sh_pm_op(info, SH_PM_OP_OR_IMM_R0, 0x00000400);
+	sh_pm_op(info, SH_PM_OP_AND_IMM_R0, 0xffff7fff);
+	sh_pm_op(info, SH_PM_OP_MOV_R0_MEM32, 0xfe400008); /* SDCR0 */
+}
+
+static void sh_mobile_pm_sf_restore(struct sh_pm_op_info *info)
+{
+	/* SDRAM: put back in auto-refresh mode */
+	sh_pm_op(info, SH_PM_OP_MOV_MEM32_R0, 0xfe400008); /* SDCR0 */
+	sh_pm_op(info, SH_PM_OP_AND_IMM_R0, 0xfffffbff);
+	sh_pm_op(info, SH_PM_OP_MOV_R0_MEM32, 0xfe400008); /* SDCR0 */
+	sh_pm_op(info, SH_PM_OP_MOV_MEM32_R0, 0xfe40001c); /* RTCOR */
+	sh_pm_op(info, SH_PM_OP_ADD_IMM_R0, (unsigned int)-1);
+	sh_pm_op(info, SH_PM_OP_OR_IMM_R0, 0xa55a0000);
+	sh_pm_op(info, SH_PM_OP_MOV_R0_MEM32, 0xfe400018); /* RTCNT */
+}
+
+static void sh_mobile_pm_sleep_sf_setup(struct sh_pm_op_info *info)
+{
+	/* setup self-refresh, clear STBCR, execute sleep, restore */
+	sh_mobile_pm_sf_suspend(info);
+	sh_mobile_pm_stbcr_setup(info, 0);
+	sh_pm_op(info, SH_PM_OP_SLEEP, 0);
+	sh_mobile_pm_sf_restore(info);
+	sh_pm_op(info, SH_PM_OP_RTS, 0);
+}
+
+static struct sh_pm_op_info sh_mobile_pm_sleep_sf = {
+	.setup = sh_mobile_pm_sleep_sf_setup,
+	.run = sh_pm_run,
+};
+
+/* "standby" mode with system memory in self-refresh */
+
+static void sh_mobile_pm_standby_sf_setup(struct sh_pm_op_info *info)
+{
+	/* setup self-refresh, set STBCR, execute sleep, restore */
+	sh_mobile_pm_sf_suspend(info);
+	sh_mobile_pm_stbcr_setup(info, 0x80);
+	sh_pm_op(info, SH_PM_OP_SLEEP, 0);
+	sh_mobile_pm_stbcr_setup(info, 0);
+	sh_mobile_pm_sf_restore(info);
+	sh_pm_op(info, SH_PM_OP_RTS, 0);
+}
+
+static struct sh_pm_op_info sh_mobile_pm_standby_sf = {
+	.setup = sh_mobile_pm_standby_sf_setup,
+	.run = sh_pm_run,
+};
+
+
+static void sh_mobile_pm_setup(void)
+{
+	sh_pm_mode_init(&sh_mobile_pm_sleep);
+	sh_pm_mode_init(&sh_mobile_pm_sleep_sf);
+	sh_pm_mode_init(&sh_mobile_pm_standby_sf);
+}
+
 /*
  * Sleep modes available on SuperH Mobile:
  *
@@ -85,6 +246,7 @@ static struct platform_suspend_ops sh_pm
 
 static int __init sh_pm_init(void)
 {
+	sh_mobile_pm_setup();
 	suspend_set_ops(&sh_pm_ops);
 	return 0;
 }
--- 0001/arch/sh/kernel/cpu/shmobile/sleep.S
+++ work/arch/sh/kernel/cpu/shmobile/sleep.S	2009-03-23 17:24:34.000000000 +0900
@@ -123,3 +123,112 @@ sh_mobile_standby_end:
 
 ENTRY(sh_mobile_standby_size)
 	.long sh_mobile_standby_end - sh_mobile_standby
+
+ENTRY(sh_pm_op_base)
+sh_pm_op_mov_imm_r0:		/* @ SH_PM_OP_MOV_IMM_R0 * SH_PM_OP_SIZE */
+	mov.l	0f, r0
+	bra	2f
+	 nop
+	nop
+0:	.long	0
+1:	bra	1f
+	 nop
+
+sh_pm_op_mov_mem8_r0:		/* @ SH_PM_OP_MOV_MEM8_R0 * SH_PM_OP_SIZE */
+2:	mov.l	0f, r1
+	bra	2f
+	 mov.b	@r1, r0
+	nop
+0:	.long	0
+1:	bra	1f
+	 nop
+
+sh_pm_op_mov_mem16_r0:		/* @ SH_PM_OP_MOV_MEM16_R0 * SH_PM_OP_SIZE */
+2:	mov.l	0f, r1
+	bra	2f
+	 mov.w	@r1, r0
+	nop
+0:	.long	0
+1:	bra	1f
+	 nop
+
+sh_pm_op_mov_mem32_r0:		/* @ SH_PM_OP_MOV_MEM32_R0 * SH_PM_OP_SIZE */
+2:	mov.l	0f, r1
+	bra	2f
+	 mov.l	@r1, r0
+	nop
+0:	.long	0
+1:	bra	1f
+	 nop
+
+sh_pm_op_mov_r0_mem8:		/* @ SH_PM_OP_MOV_R0_MEM8 * SH_PM_OP_SIZE */
+2:	mov.l	0f, r1
+	bra	2f
+	 mov.b	r0, @r1
+	nop
+0:	.long	0
+1:	bra	1f
+	 nop
+
+sh_pm_op_mov_r0_mem16:		/* @ SH_PM_OP_MOV_R0_MEM16 * SH_PM_OP_SIZE */
+2:	mov.l	0f, r1
+	bra	2f
+	 mov.w	r0, @r1
+	nop
+0:	.long	0
+1:	bra	1f
+	 nop
+
+sh_pm_op_mov_r0_mem32:		/* @ SH_PM_OP_MOV_R0_MEM32 * SH_PM_OP_SIZE */
+2:	mov.l	0f, r1
+	bra	2f
+	 mov.l	r0, @r1
+	nop
+0:	.long	0
+1:	bra	1f
+	 nop
+
+sh_pm_op_and_imm_r0:		/* @ SH_PM_OP_AND_IMM_R0 * SH_PM_OP_SIZE */
+2:	mov.l	0f, r1
+	bra	2f
+	 and	r1, r0
+	nop
+0:	.long	0
+1:	bra	1f
+	 nop
+
+sh_pm_op_or_imm_r0:		/* @ SH_PM_OP_OR_IMM_R0 * SH_PM_OP_SIZE */
+2:	mov.l	0f, r1
+	bra	2f
+	 or	r1, r0
+	nop
+0:	.long	0
+1:	bra	1f
+	 nop
+
+sh_pm_op_add_imm_r0:		/* @ SH_PM_OP_ADD_IMM_R0 * SH_PM_OP_SIZE */
+2:	mov.l	0f, r1
+	bra	2f
+	 add	r1, r0
+	nop
+0:	.long	0
+1:	bra	1f
+	 nop
+
+sh_pm_op_sleep:			/* @ SH_PM_OP_SLEEP * SH_PM_OP_SIZE */
+2:	sleep
+	bra	2f
+	 nop
+	nop
+0:	.long	0
+1:	bra	1f
+	 nop
+
+sh_pm_op_rts:			/* @ SH_PM_OP_RTS * SH_PM_OP_SIZE */
+2:	rts
+	 nop
+	nop
+	nop
+0:	.long	0
+1:	rts
+	 nop

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

end of thread, other threads:[~2009-04-21  7:17 UTC | newest]

Thread overview: 27+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2009-03-23  9:17 [PATCH][RFC] sh: suspend interpreter V1 Magnus Damm
2009-03-23 15:35 ` Francesco VIRLINZI
2009-03-24  7:00 ` Francesco VIRLINZI
2009-03-24 11:08 ` Magnus Damm
2009-03-24 13:41 ` Francesco VIRLINZI
2009-03-25 10:10 ` Magnus Damm
2009-03-25 14:46 ` takasi-y
2009-03-30  2:45 ` Magnus Damm
2009-03-30  7:02 ` Francesco VIRLINZI
2009-03-31  8:42 ` Paul Mundt
2009-04-15 11:15 ` Magnus Damm
2009-04-15 11:23 ` Paul Mundt
2009-04-16 14:15 ` Francesco VIRLINZI
2009-04-16 14:22 ` Francesco VIRLINZI
2009-04-17  2:07 ` Magnus Damm
2009-04-17  6:44 ` Francesco VIRLINZI
2009-04-17 10:39 ` Magnus Damm
2009-04-17 12:00 ` Francesco VIRLINZI
2009-04-17 21:38 ` Jean-Christophe PLAGNIOL-VILLARD
2009-04-20 10:26 ` Magnus Damm
2009-04-20 12:27 ` Jean-Christophe PLAGNIOL-VILLARD
2009-04-20 12:33 ` Francesco VIRLINZI
2009-04-20 12:55 ` Francesco VIRLINZI
2009-04-20 13:03 ` Jean-Christophe PLAGNIOL-VILLARD
2009-04-20 13:15 ` Jean-Christophe PLAGNIOL-VILLARD
2009-04-20 13:30 ` Michael Trimarchi
2009-04-21  7:17 ` Francesco VIRLINZI

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox