sleep.S 6.9 KB
Newer Older
M
Magnus Damm 已提交
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
/*
 * 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>

19 20 21 22 23 24 25 26
/*
 * Kernel mode register usage, see entry.S:
 *	k0	scratch
 *	k1	scratch
 */
#define k0	r0
#define k1	r1

27
/* manage self-refresh and enter standby mode. must be self-contained.
M
Magnus Damm 已提交
28 29
 * this code will be copied to on-chip memory and executed from there.
 */
30 31
	.balign 4
ENTRY(sh_mobile_sleep_enter_start)
M
Magnus Damm 已提交
32

33 34
	/* save mode flags */
	mov.l	r4, @(SH_SLEEP_MODE, r5)
35 36

	/* save original vbr */
37 38
	stc	vbr, r0
	mov.l	r0, @(SH_SLEEP_VBR, r5)
39 40 41 42 43

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

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

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

51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90
	/* save general purpose registers to stack if needed */
	mov.l	@(SH_SLEEP_MODE, r5), r0
	tst	#SUSP_SH_REGS, r0
	bt	skip_regs_save

	sts.l	pr, @-r15
	mov.l	r14, @-r15
	mov.l	r13, @-r15
	mov.l	r12, @-r15
	mov.l	r11, @-r15
	mov.l	r10, @-r15
	mov.l	r9, @-r15
	mov.l	r8, @-r15

	/* make sure bank0 is selected, save low registers */
	mov.l	rb_bit, r9
	not	r9, r9
	bsr	set_sr
	 mov	#0, r10

	bsr	save_low_regs
	 nop

	/* switch to bank 1, save low registers */
	mov.l	rb_bit, r10
	bsr	set_sr
	 mov	#-1, r9

	bsr	save_low_regs
	 nop

	/* switch back to bank 0 */
	mov.l	rb_bit, r9
	not	r9, r9
	bsr	set_sr
	 mov	#0, r10

skip_regs_save:

	/* save sp, also set to internal ram */
M
Magnus Damm 已提交
91
	mov.l	r15, @(SH_SLEEP_SP, r5)
92
	mov	r5, r15
M
Magnus Damm 已提交
93

94 95 96
	/* save stbcr */
	bsr     save_register
	 mov    #SH_SLEEP_REG_STBCR, r0
M
Magnus Damm 已提交
97

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

103
	/* save mmu state */
104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148
	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:
149 150
	/* call self-refresh entering code if needed */
	mov.l	@(SH_SLEEP_MODE, r5), r0
M
Magnus Damm 已提交
151 152
	tst	#SUSP_SH_SF, r0
	bt	skip_set_sf
153 154 155 156

	mov.l	@(SH_SLEEP_SF_PRE, r5), r0
	jsr	@r0
	 nop
M
Magnus Damm 已提交
157 158

skip_set_sf:
159
	mov.l	@(SH_SLEEP_MODE, r5), r0
M
Magnus Damm 已提交
160 161 162 163 164 165 166 167 168 169 170
	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

M
Magnus Damm 已提交
171 172 173 174 175 176
	/* setup BAR register */
	bsr	get_register
	 mov	#SH_SLEEP_REG_BAR, r0
	mov.l	@(SH_SLEEP_RESUME, r5), r1
	mov.l	r1, @r0

M
Magnus Damm 已提交
177 178 179 180 181 182
	/* set mode to "r-standby mode" */
	bra	do_sleep
	 mov	#0x20, r1

test_ustandby:
	tst	#SUSP_SH_USTANDBY, r0
183
	bt	force_sleep
M
Magnus Damm 已提交
184 185

	/* set mode to "u-standby mode" */
186 187
	bra	do_sleep
	 mov	#0x10, r1
M
Magnus Damm 已提交
188

189 190 191 192
force_sleep:

	/* set mode to "sleep mode" */
	mov	#0x00, r1
M
Magnus Damm 已提交
193 194 195

do_sleep:
	/* setup and enter selected standby mode */
196 197 198
	bsr     get_register
	 mov    #SH_SLEEP_REG_STBCR, r0
	mov.l	r1, @r0
199
again:
M
Magnus Damm 已提交
200
	sleep
201 202 203
	bra	again
	 nop

204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219
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
220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242

set_sr:
	stc	sr, r8
	and	r9, r8
	or	r10, r8
	ldc	r8, sr
	rts
	 nop

save_low_regs:
	mov.l	r7, @-r15
	mov.l	r6, @-r15
	mov.l	r5, @-r15
	mov.l	r4, @-r15
	mov.l	r3, @-r15
	mov.l	r2, @-r15
	mov.l	r1, @-r15
	rts
	 mov.l	r0, @-r15

	.balign 4
rb_bit:	.long	0x20000000 ! RB=1

243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265
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

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

	/* restore vbr */
271 272
	mov.l	@(SH_SLEEP_VBR, r5), r0
	ldc	r0, vbr
273 274

	/* setup ssr with saved sr */
275 276
	mov.l	@(SH_SLEEP_SR, r5), r0
	ldc	r0, ssr
M
Magnus Damm 已提交
277

M
Magnus Damm 已提交
278 279 280
	/* restore sp */
	mov.l   @(SH_SLEEP_SP, r5), r15

281 282 283
	/* restore sleep mode register */
	bsr     restore_register
	 mov    #SH_SLEEP_REG_STBCR, r0
M
Magnus Damm 已提交
284

285 286 287
	/* call self-refresh resume code if needed */
	mov.l	@(SH_SLEEP_MODE, r5), r0
	tst	#SUSP_SH_SF, r0
M
Magnus Damm 已提交
288 289
	bt	skip_restore_sf

290 291 292 293
	mov.l	@(SH_SLEEP_SF_POST, r5), r0
	jsr	@r0
	 nop

M
Magnus Damm 已提交
294
skip_restore_sf:
295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335
	/* 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:
336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369

	/* restore general purpose registers if needed */
	mov.l	@(SH_SLEEP_MODE, r5), r0
	tst	#SUSP_SH_REGS, r0
	bt	skip_restore_regs

	/* switch to bank 1, restore low registers */
	mov.l	_rb_bit, r10
	bsr	_set_sr
	 mov	#-1, r9

	bsr	restore_low_regs
	 nop

	/* switch to bank0, restore low registers */
	mov.l	_rb_bit, r9
	not	r9, r9
	bsr	_set_sr
	 mov	#0, r10

	bsr	restore_low_regs
	 nop

	/* restore the rest of the registers */
	mov.l	@r15+, r8
	mov.l	@r15+, r9
	mov.l	@r15+, r10
	mov.l	@r15+, r11
	mov.l	@r15+, r12
	mov.l	@r15+, r13
	mov.l	@r15+, r14
	lds.l	@r15+, pr

skip_restore_regs:
370
	rte
M
Magnus Damm 已提交
371 372
	 nop

373 374 375 376 377 378 379 380
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
M
Magnus Damm 已提交
381 382
	 nop

383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401
_set_sr:
	stc	sr, r8
	and	r9, r8
	or	r10, r8
	ldc	r8, sr
	rts
	 nop

restore_low_regs:
	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
	rts
	 mov.l	@r15+, r7

402
	.balign 4
403
_rb_bit:	.long	0x20000000 ! RB=1
404 405
1:	.long	~0x7ff
ENTRY(sh_mobile_sleep_resume_end)