From patchwork Mon Mar 23 09:17:39 2009 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Magnus Damm X-Patchwork-Id: 13676 Received: from vger.kernel.org (vger.kernel.org [209.132.176.167]) by demeter.kernel.org (8.14.2/8.14.2) with ESMTP id n2N9KK0L020398 for ; Mon, 23 Mar 2009 09:20:20 GMT Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1751995AbZCWJUU (ORCPT ); Mon, 23 Mar 2009 05:20:20 -0400 Received: (majordomo@vger.kernel.org) by vger.kernel.org id S1752964AbZCWJUU (ORCPT ); Mon, 23 Mar 2009 05:20:20 -0400 Received: from rv-out-0506.google.com ([209.85.198.224]:57256 "EHLO rv-out-0506.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1751995AbZCWJUS (ORCPT ); Mon, 23 Mar 2009 05:20:18 -0400 Received: by rv-out-0506.google.com with SMTP id f9so1687052rvb.1 for ; Mon, 23 Mar 2009 02:20:16 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=gamma; h=domainkey-signature:received:received:from:to:cc:date:message-id :subject; bh=q6O4/ylvvbteYB721jBtLxm6oofM6TK2OkIFIq90kgo=; b=m1wZ8F1VCFmT0wMX2IqyaZW1GwCsRucJp6duJwx2BwyCQKG9vd2gkPsEF2Ho5UjOqN lhJ0uHwlUu+9XUBez+mmbQAAdsuf1xyX0t6PNCepfge5cvRkeE5U8jJjr/EycuyNeB0m iPRi8nrSLc9BJM/3uvhy67mLEsb0oMfG4k6Do= DomainKey-Signature: a=rsa-sha1; c=nofws; d=gmail.com; s=gamma; h=from:to:cc:date:message-id:subject; b=YD9at8YXm1Y+NrULeZaVaWGRJ9B7L+2BjCAg/RIDfETq2kbn+Fzb+fHVcpOrBwnFxE 3DqcZu+RCMu/MuEblpXgtJM92GLaw82QhAHWMQRERMiKI4fnVqJ8j1Qi/U2/3ProlG+5 9IKCoFD21BXpCy22IDZq8BlLSOPD2m5cUmHoQ= Received: by 10.141.151.3 with SMTP id d3mr2022635rvo.262.1237800015923; Mon, 23 Mar 2009 02:20:15 -0700 (PDT) Received: from rx1.opensource.se (mailhost.igel.co.jp [219.106.231.130]) by mx.google.com with ESMTPS id f21sm9747719rvb.35.2009.03.23.02.20.13 (version=TLSv1/SSLv3 cipher=RC4-MD5); Mon, 23 Mar 2009 02:20:15 -0700 (PDT) From: Magnus Damm To: linux-sh@vger.kernel.org Cc: francesco.virlinzi@st.com, Magnus Damm , lethal@linux-sh.org Date: Mon, 23 Mar 2009 18:17:39 +0900 Message-Id: <20090323091739.25647.6773.sendpatchset@rx1.opensource.se> Subject: [PATCH][RFC] sh: suspend interpreter V1 Sender: linux-sh-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-sh@vger.kernel.org From: Magnus Damm 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 --- arch/sh/kernel/cpu/shmobile/pm.c | 162 +++++++++++++++++++++++++++++++++++ arch/sh/kernel/cpu/shmobile/sleep.S | 109 +++++++++++++++++++++++ 2 files changed, 271 insertions(+) -- To unsubscribe from this list: send the line "unsubscribe linux-sh" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html --- 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 #include +#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