Add Suspend-to-disk / swsusp / CONFIG_HIBERNATION support to the SuperH architecture. To suspend, use "swapon /dev/sda2; echo disk > /sys/power/state" To resume, pass "resume=/dev/sda2" on the kernel command line. The patch "pm: rework includes, remove arch ifdefs V2" is needed to allow the generic swsusp code to build properly. Hibernation is not enabled with this patch though, a patch setting ARCH_HIBERNATION_POSSIBLE will be submitted later. Signed-off-by: Magnus Damm <damm@igel.co.jp> Signed-off-by: Paul Mundt <lethal@linux-sh.org>
		
			
				
	
	
		
			147 lines
		
	
	
	
		
			2.9 KiB
			
		
	
	
	
		
			ArmAsm
		
	
	
	
	
	
			
		
		
	
	
			147 lines
		
	
	
	
		
			2.9 KiB
			
		
	
	
	
		
			ArmAsm
		
	
	
	
	
	
/*
 | 
						|
 * arch/sh/kernel/cpu/sh3/swsusp.S
 | 
						|
 *
 | 
						|
 * 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/page.h>
 | 
						|
 | 
						|
#define k0	r0
 | 
						|
#define k1	r1
 | 
						|
#define k2	r2
 | 
						|
#define k3	r3
 | 
						|
#define k4	r4
 | 
						|
 | 
						|
! swsusp_arch_resume()
 | 
						|
! - copy restore_pblist pages
 | 
						|
! - restore registers from swsusp_arch_regs_cpu0
 | 
						|
 | 
						|
ENTRY(swsusp_arch_resume)
 | 
						|
	mov.l	1f, r15
 | 
						|
	mov.l	2f, r4
 | 
						|
	mov.l	@r4, r4
 | 
						|
 | 
						|
swsusp_copy_loop:
 | 
						|
	mov	r4, r0
 | 
						|
	cmp/eq	#0, r0
 | 
						|
	bt	swsusp_restore_regs
 | 
						|
 | 
						|
	mov.l	@(PBE_ADDRESS, r4), r2
 | 
						|
	mov.l	@(PBE_ORIG_ADDRESS, r4), r5
 | 
						|
 | 
						|
	mov	#(PAGE_SIZE >> 10), r3
 | 
						|
	shll8	r3
 | 
						|
	shlr2	r3 /* PAGE_SIZE / 16 */
 | 
						|
swsusp_copy_page:
 | 
						|
	dt	r3
 | 
						|
	mov.l	@r2+,r1   /*  16n+0 */
 | 
						|
	mov.l	r1,@r5
 | 
						|
	add	#4,r5
 | 
						|
	mov.l	@r2+,r1	  /*  16n+4 */
 | 
						|
	mov.l	r1,@r5
 | 
						|
	add	#4,r5
 | 
						|
	mov.l	@r2+,r1   /*  16n+8 */
 | 
						|
	mov.l	r1,@r5
 | 
						|
	add	#4,r5
 | 
						|
	mov.l	@r2+,r1   /*  16n+12 */
 | 
						|
	mov.l	r1,@r5
 | 
						|
	bf/s	swsusp_copy_page
 | 
						|
	 add	#4,r5
 | 
						|
 | 
						|
	bra	swsusp_copy_loop
 | 
						|
	 mov.l	@(PBE_NEXT, r4), r4
 | 
						|
 | 
						|
swsusp_restore_regs:
 | 
						|
	! BL=0: R7->R0 is bank0
 | 
						|
	mov.l	3f, r8
 | 
						|
	mov.l	4f, r5
 | 
						|
	jsr	@r5
 | 
						|
	 nop
 | 
						|
 | 
						|
	! BL=1: R7->R0 is bank1
 | 
						|
	lds	k2, pr
 | 
						|
	ldc	k3, ssr
 | 
						|
 | 
						|
	mov.l	@r15+, r0
 | 
						|
	mov.l	@r15+, r1
 | 
						|
	mov.l	@r15+, r2
 | 
						|
	mov.l	@r15+, r3
 | 
						|
	mov.l	@r15+, r4
 | 
						|
	mov.l	@r15+, r5
 | 
						|
	mov.l	@r15+, r6
 | 
						|
	mov.l	@r15+, r7
 | 
						|
 | 
						|
	rte
 | 
						|
	 nop
 | 
						|
	! BL=0: R7->R0 is bank0
 | 
						|
 | 
						|
	.align	2
 | 
						|
1:	.long	swsusp_arch_regs_cpu0
 | 
						|
2:	.long	restore_pblist
 | 
						|
3:	.long	0x20000000 ! RB=1
 | 
						|
4:	.long	restore_regs
 | 
						|
 | 
						|
! swsusp_arch_suspend()
 | 
						|
! - prepare pc for resume, return from function without swsusp_save on resume
 | 
						|
! - save registers in swsusp_arch_regs_cpu0
 | 
						|
! - call swsusp_save write suspend image
 | 
						|
 | 
						|
ENTRY(swsusp_arch_suspend)
 | 
						|
	sts	pr, r0		! save pr in r0
 | 
						|
	mov	r15, r2		! save sp in r2
 | 
						|
	mov	r8, r5		! save r8 in r5
 | 
						|
	stc	sr, r1
 | 
						|
	ldc	r1, ssr		! save sr in ssr
 | 
						|
	mov.l	1f, r1
 | 
						|
	ldc	r1, spc		! setup pc value for resuming
 | 
						|
	mov.l	5f, r15		! use swsusp_arch_regs_cpu0 as stack
 | 
						|
	mov.l	6f, r3
 | 
						|
	add	r3, r15		! save from top of structure
 | 
						|
 | 
						|
	! BL=0: R7->R0 is bank0
 | 
						|
	mov.l	2f, r3		! get new SR value for bank1
 | 
						|
	mov	#0, r4
 | 
						|
	mov.l	7f, r1
 | 
						|
	jsr	@r1		! switch to bank1 and save bank1 r7->r0
 | 
						|
	 not	r4, r4
 | 
						|
 | 
						|
	! BL=1: R7->R0 is bank1
 | 
						|
	stc	r2_bank, k0	! fetch old sp from r2_bank0
 | 
						|
	mov.l	3f, k4		! SR bits to clear in k4
 | 
						|
	mov.l	8f, k1
 | 
						|
	jsr	@k1		! switch to bank0 and save all regs
 | 
						|
	 stc	r0_bank, k3	! fetch old pr from r0_bank0
 | 
						|
 | 
						|
	! BL=0: R7->R0 is bank0
 | 
						|
	mov	r2, r15		! restore old sp
 | 
						|
	mov	r5, r8		! restore old r8
 | 
						|
	stc	ssr, r1
 | 
						|
	ldc	r1, sr		! restore old sr
 | 
						|
	lds	r0, pr		! restore old pr
 | 
						|
	mov.l	4f, r0
 | 
						|
	jmp	@r0
 | 
						|
	 nop
 | 
						|
 | 
						|
swsusp_call_save:
 | 
						|
	mov	r2, r15		! restore old sp
 | 
						|
	mov	r5, r8		! restore old r8
 | 
						|
	lds	r0, pr		! restore old pr
 | 
						|
	rts
 | 
						|
	 mov	#0, r0
 | 
						|
 | 
						|
	.align	2
 | 
						|
1:	.long	swsusp_call_save
 | 
						|
2:	.long	0x20000000 ! RB=1
 | 
						|
3:	.long	0xdfffffff ! RB=0
 | 
						|
4:	.long	swsusp_save
 | 
						|
5:	.long	swsusp_arch_regs_cpu0
 | 
						|
6:	.long	SWSUSP_ARCH_REGS_SIZE
 | 
						|
7:	.long	save_low_regs
 | 
						|
8:	.long	save_regs
 |