/* * 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 #include #include #include #include /* * Kernel mode register usage, see entry.S: * k0 scratch * k1 scratch * k4 scratch */ #define k0 r0 #define k1 r1 #define k4 r4 /* 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) /* save original vbr */ stc vbr, r1 mova saved_vbr, r0 mov.l r1, @r0 /* point vbr to our on-chip memory page */ ldc r5, vbr /* save return address */ mova saved_spc, r0 sts pr, r5 mov.l r5, @r0 /* save sr */ mova saved_sr, r0 stc sr, r5 mov.l r5, @r0 /* save mode flags */ mova saved_mode, r0 mov.l r4, @r0 /* put mode flags in r0 */ mov r4, r0 tst #SUSP_SH_SF, r0 bt skip_set_sf #ifdef CONFIG_CPU_SUBTYPE_SH7724 /* DBSC: put memory in self-refresh mode */ mov.l dben_reg, r4 mov.l dben_data0, r1 mov.l r1, @r4 mov.l dbrfpdn0_reg, r4 mov.l dbrfpdn0_data0, r1 mov.l r1, @r4 mov.l dbcmdcnt_reg, r4 mov.l dbcmdcnt_data0, r1 mov.l r1, @r4 mov.l dbcmdcnt_reg, r4 mov.l dbcmdcnt_data1, r1 mov.l r1, @r4 mov.l dbrfpdn0_reg, r4 mov.l dbrfpdn0_data1, r1 mov.l r1, @r4 #else /* SBSC: 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 #endif skip_set_sf: 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 force_sleep /* set mode to "u-standby mode" */ bra do_sleep mov #0x10, r1 force_sleep: /* set mode to "sleep mode" */ mov #0x00, r1 do_sleep: /* setup and enter selected standby mode */ mov.l 5f, r4 mov.l r1, @r4 again: sleep bra again nop restore_jump_vbr: /* setup spc with return address to c code */ mov.l saved_spc, k0 ldc k0, spc /* restore vbr */ mov.l saved_vbr, k0 ldc k0, vbr /* setup ssr with saved sr */ mov.l saved_sr, k0 ldc k0, ssr /* get mode flags */ mov.l saved_mode, k0 done_sleep: /* reset standby mode to sleep mode */ mov.l 5f, k4 mov #0x00, k1 mov.l k1, @k4 tst #SUSP_SH_SF, k0 bt skip_restore_sf #ifdef CONFIG_CPU_SUBTYPE_SH7724 /* DBSC: put memory in auto-refresh mode */ mov.l dbrfpdn0_reg, k4 mov.l dbrfpdn0_data0, k1 mov.l k1, @k4 nop /* sleep 140 ns */ nop nop nop mov.l dbcmdcnt_reg, k4 mov.l dbcmdcnt_data0, k1 mov.l k1, @k4 mov.l dbcmdcnt_reg, k4 mov.l dbcmdcnt_data1, k1 mov.l k1, @k4 mov.l dben_reg, k4 mov.l dben_data1, k1 mov.l k1, @k4 mov.l dbrfpdn0_reg, k4 mov.l dbrfpdn0_data2, k1 mov.l k1, @k4 #else /* SBSC: set auto-refresh mode */ mov.l 1f, k4 mov.l @k4, k0 mov.l 4f, k1 and k1, k0 mov.l k0, @k4 mov.l 6f, k4 mov.l 8f, k0 mov.l @k4, k1 mov #-1, k4 add k4, k1 or k1, k0 mov.l 7f, k1 mov.l k0, @k1 #endif skip_restore_sf: /* jump to vbr vector */ mov.l saved_vbr, k0 mov.l offset_vbr, k4 add k4, k0 jmp @k0 nop .balign 4 saved_mode: .long 0 saved_spc: .long 0 saved_sr: .long 0 saved_vbr: .long 0 offset_vbr: .long 0x600 #ifdef CONFIG_CPU_SUBTYPE_SH7724 dben_reg: .long 0xfd000010 /* DBEN */ dben_data0: .long 0 dben_data1: .long 1 dbrfpdn0_reg: .long 0xfd000040 /* DBRFPDN0 */ dbrfpdn0_data0: .long 0 dbrfpdn0_data1: .long 1 dbrfpdn0_data2: .long 0x00010000 dbcmdcnt_reg: .long 0xfd000014 /* DBCMDCNT */ dbcmdcnt_data0: .long 2 dbcmdcnt_data1: .long 4 #else 1: .long 0xfe400008 /* SDCR0 */ 2: .long 0x00000400 3: .long 0xffff7fff 4: .long 0xfffffbff #endif 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 bra restore_jump_vbr nop sh_mobile_standby_end: ENTRY(sh_mobile_standby_size) .long sh_mobile_standby_end - sh_mobile_standby