Message ID | 20090323091739.25647.6773.sendpatchset@rx1.opensource.se (mailing list archive) |
---|---|
State | RFC |
Headers | show |
Hi Magnus I think I understood how your system works. Tell me if I'm wrong... It seems all your instructions accepts zero of at least one argument and all the ' 1: bra 1f' are used to preload. The main issue, I see, is that there is no conditional statement possible. I tryed to build something like: void while_eq(unsigned long *add, unsigned long mask, unsigned long addr) { for (; ((*add) & mask) != value; ); } but sh_pm_op(info, SH_PM_OP_MOV_MEM32_R0, _ADDR_); sh_pm_op(info, SH_PM_OP_AND_IMM_R0, _MASK_); sh_pm_op(info, SH_PM_OP_CMP_R0, _VALUE)); sh_pm_op(info, SH_PM_OP_BT, __LABEL__); On 'SH_PM_OP_CMP_R0' it isn't really a problem... It could be build like the other instruction... While on 'SH_PM_OP_BT' it could be a problem because we don't know the 'label' address... but I think it could be resolved if the sh_pm_op() instead of void returns the address of just assembled operation therefore I should be able to build something like: addr = sh_pm_op(info, SH_PM_OP_MOV_MEM32_R0, _ADDR_); sh_pm_op(info, SH_PM_OP_AND_IMM_R0, _MASK_); sh_pm_op(info, SH_PM_OP_CMP_R0, _VALUE)); sh_pm_op(info, SH_PM_OP_BT, addr); /* to jump backward... */ Something similar could be done to jump forward... also in this case the 'jump' should be marked in a first phase as incomplete... and resolved when all the code is built. At least in a first release the jump forward could be not supported. Let me know if I'm wrong and if do you agree. Ciao Francesco > 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 > -- > 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 > > -- 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
Hi Magnus > Hi Magnus > I think I understood how your system works. > > Tell me if I'm wrong... > > It seems all your instructions accepts zero of at least one argument > and all the ' 1: bra 1f' are used to preload. > > The main issue, I see, is that there is no conditional statement > possible. > > I tryed to build something like: > > void while_eq(unsigned long *add, unsigned long mask, unsigned long addr) > { > for (; ((*add) & mask) != value; ); > } > > but > > sh_pm_op(info, SH_PM_OP_MOV_MEM32_R0, _ADDR_); > sh_pm_op(info, SH_PM_OP_AND_IMM_R0, _MASK_); > sh_pm_op(info, SH_PM_OP_CMP_R0, _VALUE)); > sh_pm_op(info, SH_PM_OP_BT, __LABEL__); > > On 'SH_PM_OP_CMP_R0' it isn't really a problem... It could be build > like the other instruction... > > While on 'SH_PM_OP_BT' it could be a problem because we don't know the > 'label' address... but I think it > could be resolved if the sh_pm_op() instead of void returns the > address of just assembled operation > therefore I should be able to build something like: > > addr = sh_pm_op(info, SH_PM_OP_MOV_MEM32_R0, _ADDR_); > sh_pm_op(info, SH_PM_OP_AND_IMM_R0, _MASK_); > sh_pm_op(info, SH_PM_OP_CMP_R0, _VALUE)); > sh_pm_op(info, SH_PM_OP_BT, addr); /* to jump backward... */ > > Something similar could be done to jump forward... also in this case > the 'jump' should > be marked in a first phase as incomplete... and resolved when all > the code is built. > > At least in a first release the jump forward could be not supported. I was thinking that the jump forward could be closed with a function: void sh_pm_set_data(unsigned long *addr, unsigned long data); /* to set the data field in the instruction*/ In this manner a jump forward could be done with: jump_addr = sh_pm_op(info, SH_PM_OP_BT, 0); /* to jump forward... zero doesn't matter*/ ... ... jump_target = sh_pm_op(info, ....); sh_pm_set_data(jump_addr, jump_target); /* to set the right data value in the previous jump */ In this manner both the jumps are supported. And with an ADD or a SUB instruction also some delay can be built on top of these instructions. Let me know. Regards Francesco -- 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
Hi Francesco! On Tue, Mar 24, 2009 at 4:00 PM, Francesco VIRLINZI <francesco.virlinzi@st.com> wrote: > Hi Magnus >> >> Hi Magnus >> I think I understood how your system works. >> >> Tell me if I'm wrong... You seem correct. >> It seems all your instructions accepts zero of at least one argument and >> all the ' 1: bra 1f' Â are used to preload. >> >> The main issue, I see, is that there is no conditional statement possible. Right, I thought so. Thanks for your input so far. >> I tryed to build something like: >> >> void while_eq(unsigned long *add, unsigned long mask, unsigned long addr) >> { >> Â for (; ((*add) & mask) != value; ); >> } >> >> but >> >> sh_pm_op(info, SH_PM_OP_MOV_MEM32_R0, _ADDR_); >> sh_pm_op(info, SH_PM_OP_AND_IMM_R0, Â _MASK_); >> sh_pm_op(info, SH_PM_OP_CMP_R0, _VALUE)); >> sh_pm_op(info, SH_PM_OP_BT, __LABEL__); >> >> On 'SH_PM_OP_CMP_R0' it isn't really a problem... It could be build like >> the other instruction... Right, no problem. I guess CMP can be ADD together with AND? >> While on 'SH_PM_OP_BT' it could be a problem because we don't know the >> 'label' address... but I think it >> could be resolved if the sh_pm_op() instead of void returns the address of >> just assembled operation >> therefore I should be able to build something like: >> >> addr = sh_pm_op(info, SH_PM_OP_MOV_MEM32_R0, _ADDR_); >> sh_pm_op(info, SH_PM_OP_AND_IMM_R0, Â _MASK_); >> sh_pm_op(info, SH_PM_OP_CMP_R0, _VALUE)); >> sh_pm_op(info, SH_PM_OP_BT, addr); /* to jump backward... */ Looking good! Simple and efficient! >> Something similar could be done to jump forward... also in this case the >> 'jump' should >> Â be marked in a first phase as incomplete... Â and resolved when all the >> code is built. >> >> At least in a first release the jump forward could be not supported. > > I was thinking that the jump forward could be closed with a function: > > void sh_pm_set_data(unsigned long *addr, unsigned long data); /* to set the > data field in the instruction*/ > > In this manner > a jump forward could be done with: > > jump_addr = sh_pm_op(info, SH_PM_OP_BT, 0); /* to jump forward... zero > doesn't matter*/ > ... > ... > jump_target = sh_pm_op(info, ....); > sh_pm_set_data(jump_addr, jump_target); /* to set the right data value in > the previous jump */ > > In this manner both the jumps are supported. Right, I understand. This becomes a bit more complicated but it's not so strange. As long as the two pass setup() is ok (first pass without buffer) then I'm ok. But do we (you!) really need to jump forward? > And with an ADD or a SUB instruction also some delay can be built on top of > these instructions. The opcode SH_PM_OP_ADD_IMM_R0 isn't enough? Which other opcodes do you need? Cheers, / magnus -- 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
Hi Magnus > Right, I understand. This becomes a bit more complicated but it's not > so strange. As long as the two pass setup() is ok (first pass without > buffer) then I'm ok. > > But do we (you!) really need to jump forward? > Not really but I'd like to have no constraint if possible > >> And with an ADD or a SUB instruction also some delay can be built on top of >> these instructions. >> > > The opcode SH_PM_OP_ADD_IMM_R0 isn't enough? > Yes I think so. Have you time to extend your code or is it ok for you if I do the required update? Regards Francesco -- 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
On 3/24/09, Francesco VIRLINZI <francesco.virlinzi@st.com> wrote: > > But do we (you!) really need to jump forward? > > > > > Not really but I'd like to have no constraint if possible Then I vote for adding it later when there is a direct need. You can implement delay using backward jump only, right? > Have you time to extend your code or is it ok for you if I do the required > update? Please write a patch youself for now. And feel free to post it if you'd like. Don't spend too much time at this point though. Other people may come up with better code... Yoshii-san, any comments? Cheers! / magnus -- 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
> Yoshii-san, any comments? I still prefer to write them in _real_ assember (without having any good idea), though. > > > But do we (you!) really need to jump forward? > > Not really but I'd like to have no constraint if possible > Then I vote for adding it later when there is a direct need. You can > implement delay using backward jump only, right? Because this is a kind of assembler, we can use its technique, like making pointer link of undefined labels on its reference, and resolve them following the link when the label is defined. Then the code will be /* forward ref. This make link because label is not resolved */ sh_pm_op(info, SH_PM_OP_BT, sh_pm_ref(info, &label)); /* define label, and resolve above using linked list */ sh_pm_label(info, &label); /* define label, and resolve above */ /* backward ref. This simply use label value */ sh_pm_op(info, SH_PM_OP_BT, sh_pm_ref(info, &label)); But, I don't think we need even backward jump. What we want is conditional wait and delay, isn't it? SH_PM_OP_WAIT_UNTIL_EQ(addr, value) while(read(addr)!=value)/*wait*/; SH_PM_OP_WAIT_UNTIL_SET(addr, mask) while(!(read(addr)&mask))/*wait*/; SH_PM_OP_WAIT_UNTIL_CLR(addr, mask) while(read(addr)&mask)/*wait*/; SH_PM_OP_DELAY_LOOP(count) while(count--)/*wait*/; /yoshii -- 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
On Wed, Mar 25, 2009 at 11:46 PM, <takasi-y@ops.dti.ne.jp> wrote: >> Yoshii-san, any comments? > I still prefer to write them in _real_ assember (without having any good idea), though. I think Francesco has more complex needs. Since his processor lacks instruction cache prefetching opcodes, he is forced to populate the instruction cache "by hand" with jump instructions. That will of course be "_real_" assembly, but with magic jump instructions added in the middle to support instruction cache preload. I prefer to build-in the cache population into the interpreter/JIT code instead. That way we can have the same interpreter regardless if we chose to preload in cache or execute from onchip ram. I think Yoshii-san is proposing breaking up code into board-specific and cpu-specific assembly code, which gets copied and run. Francesco, can you convince yoshii-san why we should add support for an interpreter? =) >> > > But do we (you!) really need to jump forward? >> > Â Not really but I'd like to have no constraint if possible >> Then I vote for adding it later when there is a direct need. You can >> implement delay using backward jump only, right? > > Because this is a kind of assembler, we can use its technique, like > making pointer link of undefined labels on its reference, > Â and resolve them following the link when the label is defined. > Then the code will be > > Â /* forward ref. This make link because label is not resolved */ > Â sh_pm_op(info, SH_PM_OP_BT, sh_pm_ref(info, &label)); > Â /* define label, and resolve above using linked list */ > Â sh_pm_label(info, &label); /* define label, and resolve above */ > Â /* backward ref. This simply use label value */ > Â sh_pm_op(info, SH_PM_OP_BT, sh_pm_ref(info, &label)); Sounds pretty clean. I guess it will become a bit more complex since multiple opcomes may jump to the same label. So we may need to do a linked list with per-opcode allocation. Unless we misuse the IMM field in the opcode for a single linked list somehow. =) > But, I don't think we need even backward jump. > What we want is conditional wait and delay, isn't it? > > SH_PM_OP_WAIT_UNTIL_EQ(addr, value) while(read(addr)!=value)/*wait*/; > SH_PM_OP_WAIT_UNTIL_SET(addr, mask) while(!(read(addr)&mask))/*wait*/; > SH_PM_OP_WAIT_UNTIL_CLR(addr, mask) while(read(addr)&mask)/*wait*/; > SH_PM_OP_DELAY_LOOP(count) while(count--)/*wait*/; I wonder if we can make those opcodes fit with the current format? Maybe no. They look fine with me though, but I'm not sure about Francescos use case. I'll try to find time to post V2 this or next week. Cheers, / magnus -- 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
Hi Magnus, Yoshii-san > Francesco, can you convince yoshii-san why we should add support for > an interpreter? =) > I can try ;-) Than: I would push the interpreter solution because it will allow us to be free in the future. If all the issue on 'cache preload' 'interpreter-instruction' are resolved in 'one-shot' right now in the future for each new SOC we will have only to resolve 'what it has to be done' and not 'how'.... This simplifies our development flow because we don't have to rediscover the wheel with always the same issue. I know the interpreter will not allow 'optimized code' but I think the suspend assembly code doesn't have to be fast, it has to be right and for this reason I think it has to be written one time for ever... Moreover an assembly code SOC oriented can not be seen as 'general purpose' solution while the interpreter can be 'theoretically' used by everybody. > >> But, I don't think we need even backward jump. >> What we want is conditional wait and delay, isn't it? >> >> SH_PM_OP_WAIT_UNTIL_EQ(addr, value) while(read(addr)!=value)/*wait*/; >> SH_PM_OP_WAIT_UNTIL_SET(addr, mask) while(!(read(addr)&mask))/*wait*/; >> SH_PM_OP_WAIT_UNTIL_CLR(addr, mask) while(read(addr)&mask)/*wait*/; >> SH_PM_OP_DELAY_LOOP(count) while(count--)/*wait*/; >> > > I wonder if we can make those opcodes fit with the current format? > Maybe no. They look fine with me though, but I'm not sure about > Francescos use case. > Enough good also for me but with a little change just one is enough: SH_PM_OP_WAIT_UNTIL_EQ(addr, mask, value) while((read(addr) & mask) != value); /*wait*/; In this manner it doesn't matter what each bit does (in the same word some bits could be set and some other could be reset). Regards Francesco -- 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
On Mon, Mar 30, 2009 at 09:02:54AM +0200, Francesco VIRLINZI wrote: > Hi Magnus, Yoshii-san > >Francesco, can you convince yoshii-san why we should add support for > >an interpreter? =) > > > I can try ;-) > Than: I would push the interpreter solution because it will allow us to > be free in the future. > If all the issue on 'cache preload' 'interpreter-instruction' are > resolved in 'one-shot' right now > in the future for each new SOC we will have only to resolve 'what it > has to be done' and not 'how'.... > This simplifies our development flow because we don't have to rediscover > the wheel with always the same > issue. > I know the interpreter will not allow 'optimized code' but I think the > suspend assembly code doesn't have > to be fast, it has to be right and for this reason I think it has to be > written one time for ever... > Moreover an assembly code SOC oriented can not be seen as 'general > purpose' solution while the interpreter > can be 'theoretically' used by everybody. There are trade-offs either way. I tend to agree with Yoshii-san that pushing the interpreter for everyone is a mistake, although I don't disagree that it might be useful for some parts in the future. The real question comes down to how different are the requirements for those parts, and if there is not going to be any effort to push support upstream for them, then there is hardly any reason to make the rest of the in-tree parts suffer the pain of dealing with the interpreter. We need to see hard requirements here, in technical detail, not hand-waving about needing to be flexible for parts and requirements that never materialize. Assembly stubs do work for the vast majority of cases we have today, and the current model fits the CPU/board split pretty well. While I don't mind supporting multiple methods to support suspend (ie, the interpreter for parts that want it, and common assembly stubs for those that don't), we do not want to force all of the existing parts to deal with it if they don't wish to. The burden of proof is on you to point out why we need the interpreter, rather than rationale for keeping it out-of-tree. I am all for keeping the code as flexible and accomodating as possible, but I draw the line at making upstream components suffer to accomodate out-of-tree components that have no effort being put behind them to get them merged. Still, if the interpreter is clean enough, there is no harm in supporting it as an optional component. -- 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
On Tue, Mar 31, 2009 at 5:42 PM, Paul Mundt <lethal@linux-sh.org> wrote: > We need to see hard requirements here, in technical detail, not > hand-waving about needing to be flexible for parts and requirements that > never materialize. Assembly stubs do work for the vast majority of cases > we have today, and the current model fits the CPU/board split pretty > well. Yes, assembly stubs work fine for the SuperH Mobile sleep modes implemented so far. I suspect that upcoming "R-standby mode" will be easier to support with an interpreter though. Time will tell. Francesco, if you feel like it and have time available, please consider submitting support for some ST cpu/board combination upstream. That may make it easier to motivate why an interpreter is needed. Cheers, / magnus -- 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
On Wed, Apr 15, 2009 at 08:15:12PM +0900, Magnus Damm wrote: > On Tue, Mar 31, 2009 at 5:42 PM, Paul Mundt <lethal@linux-sh.org> wrote: > > We need to see hard requirements here, in technical detail, not > > hand-waving about needing to be flexible for parts and requirements that > > never materialize. Assembly stubs do work for the vast majority of cases > > we have today, and the current model fits the CPU/board split pretty > > well. > > Yes, assembly stubs work fine for the SuperH Mobile sleep modes > implemented so far. I suspect that upcoming "R-standby mode" will be > easier to support with an interpreter though. Time will tell. > As long as there are users for it, then we can look at supporting it. The main thing is that it is supported as an optional method for platforms to do finer grained support outside of the assembly stubs, and not making it a requirement for every platform. > Francesco, if you feel like it and have time available, please > consider submitting support for some ST cpu/board combination > upstream. That may make it easier to motivate why an interpreter is > needed. > If the ST CPUs and boards were upstream then making these sorts of decisions is a lot easier. As it is now, while we certainly want to accomodate these CPUs as much as possible, we are likewise not going to introduce undue burden on in-tree platforms for out-of-tree code, especially since it gets very difficult to make any changes in-tree without having any idea what the implications are out-of-tree. So, I'm willing to entertain an interpreter that satisfies the needs of in-tree components. If this is to be extended for ST parts, those parts need to be pushed upstream first. On the other hand, it should be easy to build on top of whatever trivial interpreter gets integrated, and just patch on top of that for out-of-tree use if an upstream merge is never going to happen. -- 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
Hi Paul I understand your point of view. And it's correct! It isn't possible to support something that doesn't exist. Unfortunately I can not merge our tree with the original sh-tree at least now. Therefore fell free to see my request as a "wish" not as a request... The extra stuff our SOC requires will be done internally to ST. In any case I will share all the stuff I can. Regards Francesco -- 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
Hi Magnus > > Yes, assembly stubs work fine for the SuperH Mobile sleep modes > implemented so far. I suspect that upcoming "R-standby mode" will be > easier to support with an interpreter though. Time will tell. > What do you mean with "R-standby mode"? Regards Francesco -- 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
On Thu, Apr 16, 2009 at 11:22 PM, Francesco VIRLINZI <francesco.virlinzi@st.com> wrote: > Hi Magnus >> >> Yes, assembly stubs work fine for the SuperH Mobile sleep modes >> implemented so far. I suspect that upcoming "R-standby mode" will be >> easier to support with an interpreter though. Time will tell. >> > > What do you mean with "R-standby mode"? It's a SuperH Mobile specific standby mode where most hardware blocks are powered off. So we need to restore many registers in the resume path. I suspect some kind of interpeter will make saving and restoring registers easier, especially the memory controller registers that need to be re-initialized before the system memory can be taken out of self-refresh. Have a look at the following presentation for more information about the standby modes on SuperH Mobile: http://www.celinuxforum.org/CelfPubWiki/ELC2009Presentations?action=AttachFile&do=view&target=Runtime-Power-Management-on-SuperH-Mobile-20090407.pdf Cheers, / magnus -- 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
Hi Magnus > Have a look at the following presentation for more information about > the standby modes on SuperH Mobile: > > http://www.celinuxforum.org/CelfPubWiki/ELC2009Presentations?action=AttachFile&do=view&target=Runtime-Power-Management-on-SuperH-Mobile-20090407.pdf > > I just completed something similar on our ST40 (with PMB enabled). We put the DRAM in self refresh an after that we totally turn-off the SOC removing the power. An external little micro has to detect the wakeup event and has to turn-on the SOC. The bootloader "understands" linux is frozen in memory and jump directly on linux. Internally we call that "hibernation on memory" and clearly it needs update in both linux/bootloader... But from the device driver point of view this is a normal hibernation while for the main core this is a special 'boot'. Currently as major change I did are in the TMU/PMB and some asm code to manage the "reboot". Do you think there is something shareable? Ciao Francesco -- 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
Hi Francesco, On Fri, Apr 17, 2009 at 3:44 PM, Francesco VIRLINZI <francesco.virlinzi@st.com> wrote: > I just completed something similar on our ST40 (with PMB enabled). > We put the DRAM in self refresh an after that we totally turn-off the SOC > removing the power. > An external little micro has to detect the wakeup event and has to turn-on > the SOC. > The bootloader "understands" linux is frozen in memory and jump directly on > linux. > > Internally we call that "hibernation on memory" and clearly it needs update > in both linux/bootloader... > But from the device driver point of view this is a normal hibernation while > for the main core this is a special 'boot'. Sounds a bit similar to U-standby mode on SuperH Mobile. > Currently as major change I did are in the TMU/PMB and some asm code to > manage the "reboot". > > Do you think there is something shareable? For boot loader, do you use upstream U-boot? That would be interesting to see. Apart from that, this approach is low on my list. This because it affects a lot of code and it may be difficult to maintain. I want to prioritize R-standby where we can power off most of the CPU but still resume from RAM without boot loader modifications... Do you have a mode similar to R-standby? Thanks for your offer! / magnus -- 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
Hi Magnus > For boot loader, do you use upstream U-boot? That would be interesting to see. > We are moving on an internal light boot-loader. > Apart from that, this approach is low on my list. This because it > affects a lot of code and it may be difficult to maintain. I want to > prioritize R-standby where we can power off most of the CPU but still > resume from RAM without boot loader modifications... This means the main CPU core is still powered. Is it? While in the hibernation on memory the CPU runs from a standard power-on. > Do you have a mode similar to R-standby? > No we haven't. Regards Francesco -- 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
On 19:39 Fri 17 Apr , Magnus Damm wrote: > Hi Francesco, > > On Fri, Apr 17, 2009 at 3:44 PM, Francesco VIRLINZI > <francesco.virlinzi@st.com> wrote: > > I just completed something similar on our ST40 (with PMB enabled). > > We put the DRAM in self refresh an after that we totally turn-off the SOC > > removing the power. > > An external little micro has to detect the wakeup event and has to turn-on > > the SOC. > > The bootloader "understands" linux is frozen in memory and jump directly on > > linux. > > > > Internally we call that "hibernation on memory" and clearly it needs update > > in both linux/bootloader... > > But from the device driver point of view this is a normal hibernation while > > for the main core this is a special 'boot'. > > Sounds a bit similar to U-standby mode on SuperH Mobile. > > > Currently as major change I did are in the TMU/PMB and some asm code to > > manage the "reboot". > > > > Do you think there is something shareable? > > For boot loader, do you use upstream U-boot? That would be interesting to see. no old u-boot version 1.3.1 with a diferrent implemntation as the actual SH4 Mainline support Actually it will be nice to have it, I've this exact hardware design and wish to do it we on a 7105. Francesco do you have any patch or tree were we can take a look on it? Best Regards, J. -- 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
Hi Francesco! On Fri, Apr 17, 2009 at 9:00 PM, Francesco VIRLINZI <francesco.virlinzi@st.com> wrote: > Hi Magnus >> >> For boot loader, do you use upstream U-boot? That would be interesting to >> see. >> > > We are moving on an internal light boot-loader. Sounds lightweight and nice. =) >> Apart from that, this approach is low on my list. This because it >> affects a lot of code and it may be difficult to maintain. I want to >> prioritize R-standby where we can power off most of the CPU but still >> resume from RAM without boot loader modifications... > > This means the main CPU core is still powered. Is it? Some part of the CPU is still powered on. So it remembers a little state and can resume from internal on-chip RAM. > While in the hibernation on memory the CPU runs from a standard power-on. I understand. >> >> Â Do you have a mode similar to R-standby? >> > > No we haven't. Ok. Can you disable power to certain parts of the SoC? Do you have multiple power domains? Do you need functions for saving and restoring hardware state in device drivers? I've been talking a bit about run time device power management. Maybe that would be useful for you guys? Cheers, / magnus -- 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
On 14:33 Mon 20 Apr , Francesco VIRLINZI wrote: > Hi Jean >> >> Actually it will be nice to have it, I've this exact hardware design and wish >> to do it we on a 7105. >> >> Francesco do you have any patch or tree were we can take a look on it? >> > All the STLinux distribution (RPM and SRPM formats) is freely available @ more precisely please Best Regards, J. -- 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
Hi Jean > > Actually it will be nice to have it, I've this exact hardware design and wish > to do it we on a 7105. > > Francesco do you have any patch or tree were we can take a look on it? > All the STLinux distribution (RPM and SRPM formats) is freely available @ www.stlinux.com Regards Francesco -- 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
Jean-Christophe PLAGNIOL-VILLARD ha scritto: > On 14:33 Mon 20 Apr , Francesco VIRLINZI wrote: > >> Hi Jean >> >>> Actually it will be nice to have it, I've this exact hardware design and wish >>> to do it we on a 7105. >>> >>> Francesco do you have any patch or tree were we can take a look on it? >>> >>> >> All the STLinux distribution (RPM and SRPM formats) is freely available @ >> > more precisely please > @ ftp://ftp.stlinux.com/pub/stlinux/2.3/SRPMS/ Regards Francesco -- 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
On 14:55 Mon 20 Apr , Francesco VIRLINZI wrote: > Jean-Christophe PLAGNIOL-VILLARD ha scritto: >> On 14:33 Mon 20 Apr , Francesco VIRLINZI wrote: >> >>> Hi Jean >>> >>>> Actually it will be nice to have it, I've this exact hardware design and wish >>>> to do it we on a 7105. >>>> >>>> Francesco do you have any patch or tree were we can take a look on it? >>>> >>> All the STLinux distribution (RPM and SRPM formats) is freely available @ >>> >> more precisely please >> > @ > ftp://ftp.stlinux.com/pub/stlinux/2.3/SRPMS/ I mean the patch, git tree commit Best Regards, J. -- 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
On 15:30 Mon 20 Apr , Michael Trimarchi wrote: > Jean-Christophe PLAGNIOL-VILLARD wrote: >> On 14:55 Mon 20 Apr , Francesco VIRLINZI wrote: >> >>> Jean-Christophe PLAGNIOL-VILLARD ha scritto: >>> >>>> On 14:33 Mon 20 Apr , Francesco VIRLINZI wrote: >>>> >>>>> Hi Jean >>>>> >>>>>> Actually it will be nice to have it, I've this exact hardware design and wish >>>>>> to do it we on a 7105. >>>>>> >>>>>> Francesco do you have any patch or tree were we can take a look on it? >>>>>> >>>>> All the STLinux distribution (RPM and SRPM formats) is freely available @ >>>>> >>>> more precisely please >>>> >>> @ >>> ftp://ftp.stlinux.com/pub/stlinux/2.3/SRPMS/ >>> >> I mean the patch, git tree commit >> > maybe, they has an internal repository, so maybe the good question can > be, what are the > affected files? no there is a public git tree Best Regards, J. -- 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
Jean-Christophe PLAGNIOL-VILLARD wrote: > On 14:55 Mon 20 Apr , Francesco VIRLINZI wrote: > >> Jean-Christophe PLAGNIOL-VILLARD ha scritto: >> >>> On 14:33 Mon 20 Apr , Francesco VIRLINZI wrote: >>> >>> >>>> Hi Jean >>>> >>>> >>>>> Actually it will be nice to have it, I've this exact hardware design and wish >>>>> to do it we on a 7105. >>>>> >>>>> Francesco do you have any patch or tree were we can take a look on it? >>>>> >>>>> >>>> All the STLinux distribution (RPM and SRPM formats) is freely available @ >>>> >>>> >>> more precisely please >>> >>> >> @ >> ftp://ftp.stlinux.com/pub/stlinux/2.3/SRPMS/ >> > I mean the patch, git tree commit > maybe, they has an internal repository, so maybe the good question can be, what are the affected files? > Best Regards, > J. > -- > 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 > > -- 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
Hi Magnus > Can you disable power to certain parts of the SoC? Do you have > multiple power domains? > Not currently... It should be in the future. But hibernation on memory works with a 'power domain' board based therefore it's easy to implement in the customer board. > Do you need functions for saving and restoring hardware state in > device drivers? For some IP it's required. > I've been talking a bit about run time device power > management. Maybe that would be useful for you guys? > What do you have in mind? Currently we release a kernel tool to leave the customer able to design their our power profile. This means the system is moved from a profile to an other.... A real runtime power management requires a support linux currently doesn't have. Regards Francesco > Cheers, > > / magnus > -- > 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 > > -- 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 <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