Staging
v0.7.0
https://github.com/torvalds/linux
Raw File
Tip revision: 29275254caedfedce960cfe6df24b90cb04fe431 authored by Linus Torvalds on 06 February 2010, 22:17:12 UTC
Linux 2.6.33-rc7
Tip revision: 2927525
sleep.S
/*
 * 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 <linux/sys.h>
#include <linux/errno.h>
#include <linux/linkage.h>
#include <asm/asm-offsets.h>
#include <asm/suspend.h>

/*
 * Kernel mode register usage, see entry.S:
 *	k0	scratch
 *	k1	scratch
 */
#define k0	r0
#define k1	r1

/* manage self-refresh and enter standby mode. must be self-contained.
 * this code will be copied to on-chip memory and executed from there.
 */
	.balign 4
ENTRY(sh_mobile_sleep_enter_start)

	/* save mode flags */
	mov.l	r4, @(SH_SLEEP_MODE, r5)

	/* save original vbr */
	stc	vbr, r0
	mov.l	r0, @(SH_SLEEP_VBR, r5)

	/* point vbr to our on-chip memory page */
	ldc	r5, vbr

	/* save return address */
	sts	pr, r0
	mov.l	r0, @(SH_SLEEP_SPC, r5)

	/* save sr */
	stc	sr, r0
	mov.l	r0, @(SH_SLEEP_SR, r5)

	/* save sp */
	mov.l	r15, @(SH_SLEEP_SP, r5)

	/* save stbcr */
	bsr     save_register
	 mov    #SH_SLEEP_REG_STBCR, r0

	/* save mmu and cache context if needed */
	mov.l	@(SH_SLEEP_MODE, r5), r0
	tst	#SUSP_SH_MMU, r0
	bt	skip_mmu_save_disable

       /* save mmu state */
	bsr	save_register
	 mov	#SH_SLEEP_REG_PTEH, r0

	bsr	save_register
	 mov	#SH_SLEEP_REG_PTEL, r0

	bsr	save_register
	 mov	#SH_SLEEP_REG_TTB, r0

	bsr	save_register
	 mov	#SH_SLEEP_REG_TEA, r0

	bsr	save_register
	 mov	#SH_SLEEP_REG_MMUCR, r0

	bsr	save_register
	 mov	#SH_SLEEP_REG_PTEA, r0

	bsr	save_register
	 mov	#SH_SLEEP_REG_PASCR, r0

	bsr	save_register
	 mov	#SH_SLEEP_REG_IRMCR, r0

	/* invalidate TLBs and disable the MMU */
	bsr	get_register
	 mov	#SH_SLEEP_REG_MMUCR, r0
	mov	#4, r1
	mov.l	r1, @r0
	icbi	@r0

	/* save cache registers and disable caches */
	bsr	save_register
	 mov	#SH_SLEEP_REG_CCR, r0

	bsr	save_register
	 mov	#SH_SLEEP_REG_RAMCR, r0

	bsr	get_register
	 mov	#SH_SLEEP_REG_CCR, r0
	mov	#0, r1
	mov.l	r1, @r0
	icbi	@r0

skip_mmu_save_disable:
	/* call self-refresh entering code if needed */
	mov.l	@(SH_SLEEP_MODE, r5), r0
	tst	#SUSP_SH_SF, r0
	bt	skip_set_sf

	mov.l	@(SH_SLEEP_SF_PRE, r5), r0
	jsr	@r0
	 nop

skip_set_sf:
	mov.l	@(SH_SLEEP_MODE, r5), r0
	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

	/* setup BAR register */
	bsr	get_register
	 mov	#SH_SLEEP_REG_BAR, r0
	mov.l	@(SH_SLEEP_RESUME, r5), r1
	mov.l	r1, @r0

	/* 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 */
	bsr     get_register
	 mov    #SH_SLEEP_REG_STBCR, r0
	mov.l	r1, @r0
again:
	sleep
	bra	again
	 nop

save_register:
	add	#SH_SLEEP_BASE_ADDR, r0
	mov.l	@(r0, r5), r1
	add	#-SH_SLEEP_BASE_ADDR, r0
	mov.l	@r1, r1
	add	#SH_SLEEP_BASE_DATA, r0
	mov.l	r1, @(r0, r5)
	add	#-SH_SLEEP_BASE_DATA, r0
	rts
	 nop

get_register:
	add	#SH_SLEEP_BASE_ADDR, r0
	mov.l	@(r0, r5), r0
	rts
	 nop
ENTRY(sh_mobile_sleep_enter_end)

	.balign 4
ENTRY(sh_mobile_sleep_resume_start)

	/* figure out start address */
	bsr	0f
	 nop
0:
	sts	pr, k1
	mov.l	1f, k0
	and	k0, k1

	/* store pointer to data area in VBR */
	ldc	k1, vbr

	/* setup sr with saved sr */
	mov.l	@(SH_SLEEP_SR, k1), k0
	ldc	k0, sr

	/* now: user register set! */
	stc	vbr, r5

	/* setup spc with return address to c code */
	mov.l	@(SH_SLEEP_SPC, r5), r0
	ldc	r0, spc

	/* restore vbr */
	mov.l	@(SH_SLEEP_VBR, r5), r0
	ldc	r0, vbr

	/* setup ssr with saved sr */
	mov.l	@(SH_SLEEP_SR, r5), r0
	ldc	r0, ssr

	/* restore sp */
	mov.l   @(SH_SLEEP_SP, r5), r15

	/* restore sleep mode register */
	bsr     restore_register
	 mov    #SH_SLEEP_REG_STBCR, r0

	/* call self-refresh resume code if needed */
	mov.l	@(SH_SLEEP_MODE, r5), r0
	tst	#SUSP_SH_SF, r0
	bt	skip_restore_sf

	mov.l	@(SH_SLEEP_SF_POST, r5), r0
	jsr	@r0
	 nop

skip_restore_sf:
	/* restore mmu and cache state if needed */
	mov.l	@(SH_SLEEP_MODE, r5), r0
	tst	#SUSP_SH_MMU, r0
	bt	skip_restore_mmu

	/* restore mmu state */
	bsr	restore_register
	 mov	#SH_SLEEP_REG_PTEH, r0

	bsr	restore_register
	 mov	#SH_SLEEP_REG_PTEL, r0

	bsr	restore_register
	 mov	#SH_SLEEP_REG_TTB, r0

	bsr	restore_register
	 mov	#SH_SLEEP_REG_TEA, r0

	bsr	restore_register
	 mov	#SH_SLEEP_REG_PTEA, r0

	bsr	restore_register
	 mov	#SH_SLEEP_REG_PASCR, r0

	bsr	restore_register
	 mov	#SH_SLEEP_REG_IRMCR, r0

	bsr	restore_register
	 mov	#SH_SLEEP_REG_MMUCR, r0
	icbi	@r0

	/* restore cache settings */
	bsr	restore_register
	 mov	#SH_SLEEP_REG_RAMCR, r0
	icbi	@r0

	bsr	restore_register
	 mov	#SH_SLEEP_REG_CCR, r0
	icbi	@r0

skip_restore_mmu:
	rte
	 nop

restore_register:
	add	#SH_SLEEP_BASE_DATA, r0
	mov.l	@(r0, r5), r1
	add	#-SH_SLEEP_BASE_DATA, r0
	add	#SH_SLEEP_BASE_ADDR, r0
	mov.l	@(r0, r5), r0
	mov.l	r1, @r0
	rts
	 nop

	.balign 4
1:	.long	~0x7ff
ENTRY(sh_mobile_sleep_resume_end)
back to top