diff options
| -rw-r--r-- | arch/sh/include/asm/suspend.h | 15 | ||||
| -rw-r--r-- | arch/sh/kernel/asm-offsets.c | 10 | ||||
| -rw-r--r-- | arch/sh/kernel/cpu/shmobile/pm.c | 15 | ||||
| -rw-r--r-- | arch/sh/kernel/cpu/shmobile/sleep.S | 92 |
4 files changed, 132 insertions, 0 deletions
diff --git a/arch/sh/include/asm/suspend.h b/arch/sh/include/asm/suspend.h index 8eddf236fb85..702025d960a0 100644 --- a/arch/sh/include/asm/suspend.h +++ b/arch/sh/include/asm/suspend.h | |||
| @@ -38,6 +38,20 @@ void sh_mobile_register_self_refresh(unsigned long flags, | |||
| 38 | /* register structure for address/data information */ | 38 | /* register structure for address/data information */ |
| 39 | struct sh_sleep_regs { | 39 | struct sh_sleep_regs { |
| 40 | unsigned long stbcr; | 40 | unsigned long stbcr; |
| 41 | |||
| 42 | /* MMU */ | ||
| 43 | unsigned long pteh; | ||
| 44 | unsigned long ptel; | ||
| 45 | unsigned long ttb; | ||
| 46 | unsigned long tea; | ||
| 47 | unsigned long mmucr; | ||
| 48 | unsigned long ptea; | ||
| 49 | unsigned long pascr; | ||
| 50 | unsigned long irmcr; | ||
| 51 | |||
| 52 | /* Cache */ | ||
| 53 | unsigned long ccr; | ||
| 54 | unsigned long ramcr; | ||
| 41 | }; | 55 | }; |
| 42 | 56 | ||
| 43 | /* data area for low-level sleep code */ | 57 | /* data area for low-level sleep code */ |
| @@ -72,5 +86,6 @@ extern unsigned long sh_mobile_sleep_supported; | |||
| 72 | #define SUSP_SH_RSTANDBY (1 << 2) /* SH-Mobile R-standby mode */ | 86 | #define SUSP_SH_RSTANDBY (1 << 2) /* SH-Mobile R-standby mode */ |
| 73 | #define SUSP_SH_USTANDBY (1 << 3) /* SH-Mobile U-standby mode */ | 87 | #define SUSP_SH_USTANDBY (1 << 3) /* SH-Mobile U-standby mode */ |
| 74 | #define SUSP_SH_SF (1 << 4) /* Enable self-refresh */ | 88 | #define SUSP_SH_SF (1 << 4) /* Enable self-refresh */ |
| 89 | #define SUSP_SH_MMU (1 << 5) /* Save/restore MMU and cache */ | ||
| 75 | 90 | ||
| 76 | #endif /* _ASM_SH_SUSPEND_H */ | 91 | #endif /* _ASM_SH_SUSPEND_H */ |
diff --git a/arch/sh/kernel/asm-offsets.c b/arch/sh/kernel/asm-offsets.c index 9bdeff962e1c..6026b0f849a1 100644 --- a/arch/sh/kernel/asm-offsets.c +++ b/arch/sh/kernel/asm-offsets.c | |||
| @@ -44,5 +44,15 @@ int main(void) | |||
| 44 | DEFINE(SH_SLEEP_BASE_ADDR, offsetof(struct sh_sleep_data, addr)); | 44 | DEFINE(SH_SLEEP_BASE_ADDR, offsetof(struct sh_sleep_data, addr)); |
| 45 | DEFINE(SH_SLEEP_BASE_DATA, offsetof(struct sh_sleep_data, data)); | 45 | DEFINE(SH_SLEEP_BASE_DATA, offsetof(struct sh_sleep_data, data)); |
| 46 | DEFINE(SH_SLEEP_REG_STBCR, offsetof(struct sh_sleep_regs, stbcr)); | 46 | DEFINE(SH_SLEEP_REG_STBCR, offsetof(struct sh_sleep_regs, stbcr)); |
| 47 | DEFINE(SH_SLEEP_REG_PTEH, offsetof(struct sh_sleep_regs, pteh)); | ||
| 48 | DEFINE(SH_SLEEP_REG_PTEL, offsetof(struct sh_sleep_regs, ptel)); | ||
| 49 | DEFINE(SH_SLEEP_REG_TTB, offsetof(struct sh_sleep_regs, ttb)); | ||
| 50 | DEFINE(SH_SLEEP_REG_TEA, offsetof(struct sh_sleep_regs, tea)); | ||
| 51 | DEFINE(SH_SLEEP_REG_MMUCR, offsetof(struct sh_sleep_regs, mmucr)); | ||
| 52 | DEFINE(SH_SLEEP_REG_PTEA, offsetof(struct sh_sleep_regs, ptea)); | ||
| 53 | DEFINE(SH_SLEEP_REG_PASCR, offsetof(struct sh_sleep_regs, pascr)); | ||
| 54 | DEFINE(SH_SLEEP_REG_IRMCR, offsetof(struct sh_sleep_regs, irmcr)); | ||
| 55 | DEFINE(SH_SLEEP_REG_CCR, offsetof(struct sh_sleep_regs, ccr)); | ||
| 56 | DEFINE(SH_SLEEP_REG_RAMCR, offsetof(struct sh_sleep_regs, ramcr)); | ||
| 47 | return 0; | 57 | return 0; |
| 48 | } | 58 | } |
diff --git a/arch/sh/kernel/cpu/shmobile/pm.c b/arch/sh/kernel/cpu/shmobile/pm.c index a94dc480f0c1..ca642f39e2e3 100644 --- a/arch/sh/kernel/cpu/shmobile/pm.c +++ b/arch/sh/kernel/cpu/shmobile/pm.c | |||
| @@ -15,6 +15,7 @@ | |||
| 15 | #include <linux/suspend.h> | 15 | #include <linux/suspend.h> |
| 16 | #include <asm/suspend.h> | 16 | #include <asm/suspend.h> |
| 17 | #include <asm/uaccess.h> | 17 | #include <asm/uaccess.h> |
| 18 | #include <asm/cacheflush.h> | ||
| 18 | 19 | ||
| 19 | /* | 20 | /* |
| 20 | * Notifier lists for pre/post sleep notification | 21 | * Notifier lists for pre/post sleep notification |
| @@ -54,6 +55,10 @@ void sh_mobile_call_standby(unsigned long mode) | |||
| 54 | atomic_notifier_call_chain(&sh_mobile_pre_sleep_notifier_list, | 55 | atomic_notifier_call_chain(&sh_mobile_pre_sleep_notifier_list, |
| 55 | mode, NULL); | 56 | mode, NULL); |
| 56 | 57 | ||
| 58 | /* flush the caches if MMU flag is set */ | ||
| 59 | if (mode & SUSP_SH_MMU) | ||
| 60 | flush_cache_all(); | ||
| 61 | |||
| 57 | /* Let assembly snippet in on-chip memory handle the rest */ | 62 | /* Let assembly snippet in on-chip memory handle the rest */ |
| 58 | standby_onchip_mem(mode, ILRAM_BASE); | 63 | standby_onchip_mem(mode, ILRAM_BASE); |
| 59 | 64 | ||
| @@ -81,6 +86,16 @@ void sh_mobile_register_self_refresh(unsigned long flags, | |||
| 81 | /* part 0: data area */ | 86 | /* part 0: data area */ |
| 82 | sdp = onchip_mem; | 87 | sdp = onchip_mem; |
| 83 | sdp->addr.stbcr = 0xa4150020; /* STBCR */ | 88 | sdp->addr.stbcr = 0xa4150020; /* STBCR */ |
| 89 | sdp->addr.pteh = 0xff000000; /* PTEH */ | ||
| 90 | sdp->addr.ptel = 0xff000004; /* PTEL */ | ||
| 91 | sdp->addr.ttb = 0xff000008; /* TTB */ | ||
| 92 | sdp->addr.tea = 0xff00000c; /* TEA */ | ||
| 93 | sdp->addr.mmucr = 0xff000010; /* MMUCR */ | ||
| 94 | sdp->addr.ptea = 0xff000034; /* PTEA */ | ||
| 95 | sdp->addr.pascr = 0xff000070; /* PASCR */ | ||
| 96 | sdp->addr.irmcr = 0xff000078; /* IRMCR */ | ||
| 97 | sdp->addr.ccr = 0xff00001c; /* CCR */ | ||
| 98 | sdp->addr.ramcr = 0xff000074; /* RAMCR */ | ||
| 84 | vp = sdp + 1; | 99 | vp = sdp + 1; |
| 85 | 100 | ||
| 86 | /* part 1: common code to enter sleep mode */ | 101 | /* part 1: common code to enter sleep mode */ |
diff --git a/arch/sh/kernel/cpu/shmobile/sleep.S b/arch/sh/kernel/cpu/shmobile/sleep.S index d3221d9b88be..e620bf397af5 100644 --- a/arch/sh/kernel/cpu/shmobile/sleep.S +++ b/arch/sh/kernel/cpu/shmobile/sleep.S | |||
| @@ -52,6 +52,57 @@ ENTRY(sh_mobile_sleep_enter_start) | |||
| 52 | bsr save_register | 52 | bsr save_register |
| 53 | mov #SH_SLEEP_REG_STBCR, r0 | 53 | mov #SH_SLEEP_REG_STBCR, r0 |
| 54 | 54 | ||
| 55 | /* save mmu and cache context if needed */ | ||
| 56 | mov.l @(SH_SLEEP_MODE, r5), r0 | ||
| 57 | tst #SUSP_SH_MMU, r0 | ||
| 58 | bt skip_mmu_save_disable | ||
| 59 | |||
| 60 | /* save mmu state */ | ||
| 61 | bsr save_register | ||
| 62 | mov #SH_SLEEP_REG_PTEH, r0 | ||
| 63 | |||
| 64 | bsr save_register | ||
| 65 | mov #SH_SLEEP_REG_PTEL, r0 | ||
| 66 | |||
| 67 | bsr save_register | ||
| 68 | mov #SH_SLEEP_REG_TTB, r0 | ||
| 69 | |||
| 70 | bsr save_register | ||
| 71 | mov #SH_SLEEP_REG_TEA, r0 | ||
| 72 | |||
| 73 | bsr save_register | ||
| 74 | mov #SH_SLEEP_REG_MMUCR, r0 | ||
| 75 | |||
| 76 | bsr save_register | ||
| 77 | mov #SH_SLEEP_REG_PTEA, r0 | ||
| 78 | |||
| 79 | bsr save_register | ||
| 80 | mov #SH_SLEEP_REG_PASCR, r0 | ||
| 81 | |||
| 82 | bsr save_register | ||
| 83 | mov #SH_SLEEP_REG_IRMCR, r0 | ||
| 84 | |||
| 85 | /* invalidate TLBs and disable the MMU */ | ||
| 86 | bsr get_register | ||
| 87 | mov #SH_SLEEP_REG_MMUCR, r0 | ||
| 88 | mov #4, r1 | ||
| 89 | mov.l r1, @r0 | ||
| 90 | icbi @r0 | ||
| 91 | |||
| 92 | /* save cache registers and disable caches */ | ||
| 93 | bsr save_register | ||
| 94 | mov #SH_SLEEP_REG_CCR, r0 | ||
| 95 | |||
| 96 | bsr save_register | ||
| 97 | mov #SH_SLEEP_REG_RAMCR, r0 | ||
| 98 | |||
| 99 | bsr get_register | ||
| 100 | mov #SH_SLEEP_REG_CCR, r0 | ||
| 101 | mov #0, r1 | ||
| 102 | mov.l r1, @r0 | ||
| 103 | icbi @r0 | ||
| 104 | |||
| 105 | skip_mmu_save_disable: | ||
| 55 | /* call self-refresh entering code if needed */ | 106 | /* call self-refresh entering code if needed */ |
| 56 | mov.l @(SH_SLEEP_MODE, r5), r0 | 107 | mov.l @(SH_SLEEP_MODE, r5), r0 |
| 57 | tst #SUSP_SH_SF, r0 | 108 | tst #SUSP_SH_SF, r0 |
| @@ -166,6 +217,47 @@ ENTRY(sh_mobile_sleep_resume_start) | |||
| 166 | nop | 217 | nop |
| 167 | 218 | ||
| 168 | skip_restore_sf: | 219 | skip_restore_sf: |
| 220 | /* restore mmu and cache state if needed */ | ||
| 221 | mov.l @(SH_SLEEP_MODE, r5), r0 | ||
| 222 | tst #SUSP_SH_MMU, r0 | ||
| 223 | bt skip_restore_mmu | ||
| 224 | |||
| 225 | /* restore mmu state */ | ||
| 226 | bsr restore_register | ||
| 227 | mov #SH_SLEEP_REG_PTEH, r0 | ||
| 228 | |||
| 229 | bsr restore_register | ||
| 230 | mov #SH_SLEEP_REG_PTEL, r0 | ||
| 231 | |||
| 232 | bsr restore_register | ||
| 233 | mov #SH_SLEEP_REG_TTB, r0 | ||
| 234 | |||
| 235 | bsr restore_register | ||
| 236 | mov #SH_SLEEP_REG_TEA, r0 | ||
| 237 | |||
| 238 | bsr restore_register | ||
| 239 | mov #SH_SLEEP_REG_PTEA, r0 | ||
| 240 | |||
| 241 | bsr restore_register | ||
| 242 | mov #SH_SLEEP_REG_PASCR, r0 | ||
| 243 | |||
| 244 | bsr restore_register | ||
| 245 | mov #SH_SLEEP_REG_IRMCR, r0 | ||
| 246 | |||
| 247 | bsr restore_register | ||
| 248 | mov #SH_SLEEP_REG_MMUCR, r0 | ||
| 249 | icbi @r0 | ||
| 250 | |||
| 251 | /* restore cache settings */ | ||
| 252 | bsr restore_register | ||
| 253 | mov #SH_SLEEP_REG_RAMCR, r0 | ||
| 254 | icbi @r0 | ||
| 255 | |||
| 256 | bsr restore_register | ||
| 257 | mov #SH_SLEEP_REG_CCR, r0 | ||
| 258 | icbi @r0 | ||
| 259 | |||
| 260 | skip_restore_mmu: | ||
| 169 | rte | 261 | rte |
| 170 | nop | 262 | nop |
| 171 | 263 | ||
