1e9edb3feSPaul Mundt/* 2e9edb3feSPaul Mundt * arch/sh/kernel/cpu/sh4a/sleep-sh_mobile.S 3e9edb3feSPaul Mundt * 4e9edb3feSPaul Mundt * Sleep mode and Standby modes support for SuperH Mobile 5e9edb3feSPaul Mundt * 6e9edb3feSPaul Mundt * Copyright (C) 2009 Magnus Damm 7e9edb3feSPaul Mundt * 8e9edb3feSPaul Mundt * This file is subject to the terms and conditions of the GNU General Public 9e9edb3feSPaul Mundt * License. See the file "COPYING" in the main directory of this archive 10e9edb3feSPaul Mundt * for more details. 11e9edb3feSPaul Mundt */ 12e9edb3feSPaul Mundt 13e9edb3feSPaul Mundt#include <linux/sys.h> 14e9edb3feSPaul Mundt#include <linux/errno.h> 15e9edb3feSPaul Mundt#include <linux/linkage.h> 16e9edb3feSPaul Mundt#include <asm/asm-offsets.h> 17e9edb3feSPaul Mundt#include <asm/suspend.h> 18e9edb3feSPaul Mundt 19309214afSMagnus Damm/* 20309214afSMagnus Damm * Kernel mode register usage, see entry.S: 21309214afSMagnus Damm * k0 scratch 22309214afSMagnus Damm * k1 scratch 23309214afSMagnus Damm */ 24309214afSMagnus Damm#define k0 r0 25309214afSMagnus Damm#define k1 r1 26309214afSMagnus Damm 27323ef8dbSMagnus Damm/* manage self-refresh and enter standby mode. must be self-contained. 28e9edb3feSPaul Mundt * this code will be copied to on-chip memory and executed from there. 29e9edb3feSPaul Mundt */ 30323ef8dbSMagnus Damm .balign 4 31323ef8dbSMagnus DammENTRY(sh_mobile_sleep_enter_start) 32e9edb3feSPaul Mundt 33323ef8dbSMagnus Damm /* save mode flags */ 34323ef8dbSMagnus Damm mov.l r4, @(SH_SLEEP_MODE, r5) 35309214afSMagnus Damm 36309214afSMagnus Damm /* save original vbr */ 37323ef8dbSMagnus Damm stc vbr, r0 38323ef8dbSMagnus Damm mov.l r0, @(SH_SLEEP_VBR, r5) 39309214afSMagnus Damm 40309214afSMagnus Damm /* point vbr to our on-chip memory page */ 41309214afSMagnus Damm ldc r5, vbr 42309214afSMagnus Damm 43309214afSMagnus Damm /* save return address */ 44323ef8dbSMagnus Damm sts pr, r0 45323ef8dbSMagnus Damm mov.l r0, @(SH_SLEEP_SPC, r5) 46309214afSMagnus Damm 47309214afSMagnus Damm /* save sr */ 48323ef8dbSMagnus Damm stc sr, r0 49323ef8dbSMagnus Damm mov.l r0, @(SH_SLEEP_SR, r5) 50309214afSMagnus Damm 51bb3e0eedSMagnus Damm /* save sp */ 52bb3e0eedSMagnus Damm mov.l r15, @(SH_SLEEP_SP, r5) 53bb3e0eedSMagnus Damm 54323ef8dbSMagnus Damm /* save stbcr */ 55323ef8dbSMagnus Damm bsr save_register 56323ef8dbSMagnus Damm mov #SH_SLEEP_REG_STBCR, r0 57309214afSMagnus Damm 5899675a7aSMagnus Damm /* save mmu and cache context if needed */ 5999675a7aSMagnus Damm mov.l @(SH_SLEEP_MODE, r5), r0 6099675a7aSMagnus Damm tst #SUSP_SH_MMU, r0 6199675a7aSMagnus Damm bt skip_mmu_save_disable 6299675a7aSMagnus Damm 6399675a7aSMagnus Damm /* save mmu state */ 6499675a7aSMagnus Damm bsr save_register 6599675a7aSMagnus Damm mov #SH_SLEEP_REG_PTEH, r0 6699675a7aSMagnus Damm 6799675a7aSMagnus Damm bsr save_register 6899675a7aSMagnus Damm mov #SH_SLEEP_REG_PTEL, r0 6999675a7aSMagnus Damm 7099675a7aSMagnus Damm bsr save_register 7199675a7aSMagnus Damm mov #SH_SLEEP_REG_TTB, r0 7299675a7aSMagnus Damm 7399675a7aSMagnus Damm bsr save_register 7499675a7aSMagnus Damm mov #SH_SLEEP_REG_TEA, r0 7599675a7aSMagnus Damm 7699675a7aSMagnus Damm bsr save_register 7799675a7aSMagnus Damm mov #SH_SLEEP_REG_MMUCR, r0 7899675a7aSMagnus Damm 7999675a7aSMagnus Damm bsr save_register 8099675a7aSMagnus Damm mov #SH_SLEEP_REG_PTEA, r0 8199675a7aSMagnus Damm 8299675a7aSMagnus Damm bsr save_register 8399675a7aSMagnus Damm mov #SH_SLEEP_REG_PASCR, r0 8499675a7aSMagnus Damm 8599675a7aSMagnus Damm bsr save_register 8699675a7aSMagnus Damm mov #SH_SLEEP_REG_IRMCR, r0 8799675a7aSMagnus Damm 8899675a7aSMagnus Damm /* invalidate TLBs and disable the MMU */ 8999675a7aSMagnus Damm bsr get_register 9099675a7aSMagnus Damm mov #SH_SLEEP_REG_MMUCR, r0 9199675a7aSMagnus Damm mov #4, r1 9299675a7aSMagnus Damm mov.l r1, @r0 9399675a7aSMagnus Damm icbi @r0 9499675a7aSMagnus Damm 9599675a7aSMagnus Damm /* save cache registers and disable caches */ 9699675a7aSMagnus Damm bsr save_register 9799675a7aSMagnus Damm mov #SH_SLEEP_REG_CCR, r0 9899675a7aSMagnus Damm 9999675a7aSMagnus Damm bsr save_register 10099675a7aSMagnus Damm mov #SH_SLEEP_REG_RAMCR, r0 10199675a7aSMagnus Damm 10299675a7aSMagnus Damm bsr get_register 10399675a7aSMagnus Damm mov #SH_SLEEP_REG_CCR, r0 10499675a7aSMagnus Damm mov #0, r1 10599675a7aSMagnus Damm mov.l r1, @r0 10699675a7aSMagnus Damm icbi @r0 10799675a7aSMagnus Damm 10899675a7aSMagnus Dammskip_mmu_save_disable: 109323ef8dbSMagnus Damm /* call self-refresh entering code if needed */ 110323ef8dbSMagnus Damm mov.l @(SH_SLEEP_MODE, r5), r0 111e9edb3feSPaul Mundt tst #SUSP_SH_SF, r0 112e9edb3feSPaul Mundt bt skip_set_sf 113237674e0SMagnus Damm 114323ef8dbSMagnus Damm mov.l @(SH_SLEEP_SF_PRE, r5), r0 115323ef8dbSMagnus Damm jsr @r0 116323ef8dbSMagnus Damm nop 117e9edb3feSPaul Mundt 118e9edb3feSPaul Mundtskip_set_sf: 119323ef8dbSMagnus Damm mov.l @(SH_SLEEP_MODE, r5), r0 120e9edb3feSPaul Mundt tst #SUSP_SH_STANDBY, r0 121e9edb3feSPaul Mundt bt test_rstandby 122e9edb3feSPaul Mundt 123e9edb3feSPaul Mundt /* set mode to "software standby mode" */ 124e9edb3feSPaul Mundt bra do_sleep 125e9edb3feSPaul Mundt mov #0x80, r1 126e9edb3feSPaul Mundt 127e9edb3feSPaul Mundttest_rstandby: 128e9edb3feSPaul Mundt tst #SUSP_SH_RSTANDBY, r0 129e9edb3feSPaul Mundt bt test_ustandby 130e9edb3feSPaul Mundt 131bb3e0eedSMagnus Damm /* setup BAR register */ 132bb3e0eedSMagnus Damm bsr get_register 133bb3e0eedSMagnus Damm mov #SH_SLEEP_REG_BAR, r0 134bb3e0eedSMagnus Damm mov.l @(SH_SLEEP_RESUME, r5), r1 135bb3e0eedSMagnus Damm mov.l r1, @r0 136bb3e0eedSMagnus Damm 137e9edb3feSPaul Mundt /* set mode to "r-standby mode" */ 138e9edb3feSPaul Mundt bra do_sleep 139e9edb3feSPaul Mundt mov #0x20, r1 140e9edb3feSPaul Mundt 141e9edb3feSPaul Mundttest_ustandby: 142e9edb3feSPaul Mundt tst #SUSP_SH_USTANDBY, r0 143309214afSMagnus Damm bt force_sleep 144e9edb3feSPaul Mundt 145e9edb3feSPaul Mundt /* set mode to "u-standby mode" */ 146309214afSMagnus Damm bra do_sleep 147e9edb3feSPaul Mundt mov #0x10, r1 148e9edb3feSPaul Mundt 149309214afSMagnus Dammforce_sleep: 150309214afSMagnus Damm 151309214afSMagnus Damm /* set mode to "sleep mode" */ 152309214afSMagnus Damm mov #0x00, r1 153e9edb3feSPaul Mundt 154e9edb3feSPaul Mundtdo_sleep: 155e9edb3feSPaul Mundt /* setup and enter selected standby mode */ 156323ef8dbSMagnus Damm bsr get_register 157323ef8dbSMagnus Damm mov #SH_SLEEP_REG_STBCR, r0 158323ef8dbSMagnus Damm mov.l r1, @r0 159309214afSMagnus Dammagain: 160e9edb3feSPaul Mundt sleep 161309214afSMagnus Damm bra again 162309214afSMagnus Damm nop 163309214afSMagnus Damm 164323ef8dbSMagnus Dammsave_register: 165323ef8dbSMagnus Damm add #SH_SLEEP_BASE_ADDR, r0 166323ef8dbSMagnus Damm mov.l @(r0, r5), r1 167323ef8dbSMagnus Damm add #-SH_SLEEP_BASE_ADDR, r0 168323ef8dbSMagnus Damm mov.l @r1, r1 169323ef8dbSMagnus Damm add #SH_SLEEP_BASE_DATA, r0 170323ef8dbSMagnus Damm mov.l r1, @(r0, r5) 171323ef8dbSMagnus Damm add #-SH_SLEEP_BASE_DATA, r0 172323ef8dbSMagnus Damm rts 173323ef8dbSMagnus Damm nop 174323ef8dbSMagnus Damm 175323ef8dbSMagnus Dammget_register: 176323ef8dbSMagnus Damm add #SH_SLEEP_BASE_ADDR, r0 177323ef8dbSMagnus Damm mov.l @(r0, r5), r0 178323ef8dbSMagnus Damm rts 179323ef8dbSMagnus Damm nop 180323ef8dbSMagnus DammENTRY(sh_mobile_sleep_enter_end) 181323ef8dbSMagnus Damm 182323ef8dbSMagnus Damm .balign 4 183323ef8dbSMagnus DammENTRY(sh_mobile_sleep_resume_start) 184323ef8dbSMagnus Damm 185323ef8dbSMagnus Damm /* figure out start address */ 186323ef8dbSMagnus Damm bsr 0f 187323ef8dbSMagnus Damm nop 188323ef8dbSMagnus Damm0: 189323ef8dbSMagnus Damm sts pr, k1 190323ef8dbSMagnus Damm mov.l 1f, k0 191323ef8dbSMagnus Damm and k0, k1 192323ef8dbSMagnus Damm 193323ef8dbSMagnus Damm /* store pointer to data area in VBR */ 194323ef8dbSMagnus Damm ldc k1, vbr 195323ef8dbSMagnus Damm 196323ef8dbSMagnus Damm /* setup sr with saved sr */ 197323ef8dbSMagnus Damm mov.l @(SH_SLEEP_SR, k1), k0 198323ef8dbSMagnus Damm ldc k0, sr 199323ef8dbSMagnus Damm 200323ef8dbSMagnus Damm /* now: user register set! */ 201323ef8dbSMagnus Damm stc vbr, r5 202323ef8dbSMagnus Damm 203309214afSMagnus Damm /* setup spc with return address to c code */ 204323ef8dbSMagnus Damm mov.l @(SH_SLEEP_SPC, r5), r0 205323ef8dbSMagnus Damm ldc r0, spc 206309214afSMagnus Damm 207309214afSMagnus Damm /* restore vbr */ 208323ef8dbSMagnus Damm mov.l @(SH_SLEEP_VBR, r5), r0 209323ef8dbSMagnus Damm ldc r0, vbr 210309214afSMagnus Damm 211309214afSMagnus Damm /* setup ssr with saved sr */ 212323ef8dbSMagnus Damm mov.l @(SH_SLEEP_SR, r5), r0 213323ef8dbSMagnus Damm ldc r0, ssr 214309214afSMagnus Damm 215bb3e0eedSMagnus Damm /* restore sp */ 216bb3e0eedSMagnus Damm mov.l @(SH_SLEEP_SP, r5), r15 217bb3e0eedSMagnus Damm 218323ef8dbSMagnus Damm /* restore sleep mode register */ 219323ef8dbSMagnus Damm bsr restore_register 220323ef8dbSMagnus Damm mov #SH_SLEEP_REG_STBCR, r0 221e9edb3feSPaul Mundt 222323ef8dbSMagnus Damm /* call self-refresh resume code if needed */ 223323ef8dbSMagnus Damm mov.l @(SH_SLEEP_MODE, r5), r0 224323ef8dbSMagnus Damm tst #SUSP_SH_SF, r0 225e9edb3feSPaul Mundt bt skip_restore_sf 226e9edb3feSPaul Mundt 227323ef8dbSMagnus Damm mov.l @(SH_SLEEP_SF_POST, r5), r0 228323ef8dbSMagnus Damm jsr @r0 229237674e0SMagnus Damm nop 230237674e0SMagnus Damm 231e9edb3feSPaul Mundtskip_restore_sf: 23299675a7aSMagnus Damm /* restore mmu and cache state if needed */ 23399675a7aSMagnus Damm mov.l @(SH_SLEEP_MODE, r5), r0 23499675a7aSMagnus Damm tst #SUSP_SH_MMU, r0 23599675a7aSMagnus Damm bt skip_restore_mmu 23699675a7aSMagnus Damm 23799675a7aSMagnus Damm /* restore mmu state */ 23899675a7aSMagnus Damm bsr restore_register 23999675a7aSMagnus Damm mov #SH_SLEEP_REG_PTEH, r0 24099675a7aSMagnus Damm 24199675a7aSMagnus Damm bsr restore_register 24299675a7aSMagnus Damm mov #SH_SLEEP_REG_PTEL, r0 24399675a7aSMagnus Damm 24499675a7aSMagnus Damm bsr restore_register 24599675a7aSMagnus Damm mov #SH_SLEEP_REG_TTB, r0 24699675a7aSMagnus Damm 24799675a7aSMagnus Damm bsr restore_register 24899675a7aSMagnus Damm mov #SH_SLEEP_REG_TEA, r0 24999675a7aSMagnus Damm 25099675a7aSMagnus Damm bsr restore_register 25199675a7aSMagnus Damm mov #SH_SLEEP_REG_PTEA, r0 25299675a7aSMagnus Damm 25399675a7aSMagnus Damm bsr restore_register 25499675a7aSMagnus Damm mov #SH_SLEEP_REG_PASCR, r0 25599675a7aSMagnus Damm 25699675a7aSMagnus Damm bsr restore_register 25799675a7aSMagnus Damm mov #SH_SLEEP_REG_IRMCR, r0 25899675a7aSMagnus Damm 25999675a7aSMagnus Damm bsr restore_register 26099675a7aSMagnus Damm mov #SH_SLEEP_REG_MMUCR, r0 26199675a7aSMagnus Damm icbi @r0 26299675a7aSMagnus Damm 26399675a7aSMagnus Damm /* restore cache settings */ 26499675a7aSMagnus Damm bsr restore_register 26599675a7aSMagnus Damm mov #SH_SLEEP_REG_RAMCR, r0 26699675a7aSMagnus Damm icbi @r0 26799675a7aSMagnus Damm 26899675a7aSMagnus Damm bsr restore_register 26999675a7aSMagnus Damm mov #SH_SLEEP_REG_CCR, r0 27099675a7aSMagnus Damm icbi @r0 27199675a7aSMagnus Damm 27299675a7aSMagnus Dammskip_restore_mmu: 273323ef8dbSMagnus Damm rte 274323ef8dbSMagnus Damm nop 275323ef8dbSMagnus Damm 276323ef8dbSMagnus Dammrestore_register: 277323ef8dbSMagnus Damm add #SH_SLEEP_BASE_DATA, r0 278323ef8dbSMagnus Damm mov.l @(r0, r5), r1 279323ef8dbSMagnus Damm add #-SH_SLEEP_BASE_DATA, r0 280323ef8dbSMagnus Damm add #SH_SLEEP_BASE_ADDR, r0 281323ef8dbSMagnus Damm mov.l @(r0, r5), r0 282323ef8dbSMagnus Damm mov.l r1, @r0 283323ef8dbSMagnus Damm rts 284e9edb3feSPaul Mundt nop 285e9edb3feSPaul Mundt 286e9edb3feSPaul Mundt .balign 4 287323ef8dbSMagnus Damm1: .long ~0x7ff 288323ef8dbSMagnus DammENTRY(sh_mobile_sleep_resume_end) 289