267 lines
4.9 KiB
ArmAsm
267 lines
4.9 KiB
ArmAsm
/* SPDX-License-Identifier: GPL-2.0-or-later */
|
|
/*
|
|
* Copyright 2002 Embedded Edge, LLC
|
|
* Author: dan@embeddededge.com
|
|
*
|
|
* Sleep helper for Au1xxx sleep mode.
|
|
*/
|
|
|
|
#include <asm/asm.h>
|
|
#include <asm/mipsregs.h>
|
|
#include <asm/regdef.h>
|
|
#include <asm/stackframe.h>
|
|
|
|
.extern __flush_cache_all
|
|
|
|
.text
|
|
.set noreorder
|
|
.set noat
|
|
.align 5
|
|
|
|
|
|
/* preparatory stuff */
|
|
.macro SETUP_SLEEP
|
|
subu sp, PT_SIZE
|
|
sw $1, PT_R1(sp)
|
|
sw $2, PT_R2(sp)
|
|
sw $3, PT_R3(sp)
|
|
sw $4, PT_R4(sp)
|
|
sw $5, PT_R5(sp)
|
|
sw $6, PT_R6(sp)
|
|
sw $7, PT_R7(sp)
|
|
sw $16, PT_R16(sp)
|
|
sw $17, PT_R17(sp)
|
|
sw $18, PT_R18(sp)
|
|
sw $19, PT_R19(sp)
|
|
sw $20, PT_R20(sp)
|
|
sw $21, PT_R21(sp)
|
|
sw $22, PT_R22(sp)
|
|
sw $23, PT_R23(sp)
|
|
sw $26, PT_R26(sp)
|
|
sw $27, PT_R27(sp)
|
|
sw $28, PT_R28(sp)
|
|
sw $30, PT_R30(sp)
|
|
sw $31, PT_R31(sp)
|
|
mfc0 k0, CP0_STATUS
|
|
sw k0, 0x20(sp)
|
|
mfc0 k0, CP0_CONTEXT
|
|
sw k0, 0x1c(sp)
|
|
mfc0 k0, CP0_PAGEMASK
|
|
sw k0, 0x18(sp)
|
|
mfc0 k0, CP0_CONFIG
|
|
sw k0, 0x14(sp)
|
|
|
|
/* flush caches to make sure context is in memory */
|
|
la t1, __flush_cache_all
|
|
lw t0, 0(t1)
|
|
jalr t0
|
|
nop
|
|
|
|
/* Now set up the scratch registers so the boot rom will
|
|
* return to this point upon wakeup.
|
|
* sys_scratch0 : SP
|
|
* sys_scratch1 : RA
|
|
*/
|
|
lui t3, 0xb190 /* sys_xxx */
|
|
sw sp, 0x0018(t3)
|
|
la k0, alchemy_sleep_wakeup /* resume path */
|
|
sw k0, 0x001c(t3)
|
|
.endm
|
|
|
|
.macro DO_SLEEP
|
|
/* put power supply and processor to sleep */
|
|
sw zero, 0x0078(t3) /* sys_slppwr */
|
|
sync
|
|
sw zero, 0x007c(t3) /* sys_sleep */
|
|
sync
|
|
nop
|
|
nop
|
|
nop
|
|
nop
|
|
nop
|
|
nop
|
|
nop
|
|
nop
|
|
.endm
|
|
|
|
/* sleep code for Au1000/Au1100/Au1500 memory controller type */
|
|
LEAF(alchemy_sleep_au1000)
|
|
|
|
SETUP_SLEEP
|
|
|
|
/* cache following instructions, as memory gets put to sleep */
|
|
la t0, 1f
|
|
.set arch=r4000
|
|
cache 0x14, 0(t0)
|
|
cache 0x14, 32(t0)
|
|
cache 0x14, 64(t0)
|
|
cache 0x14, 96(t0)
|
|
.set mips0
|
|
|
|
1: lui a0, 0xb400 /* mem_xxx */
|
|
sw zero, 0x001c(a0) /* Precharge */
|
|
sync
|
|
sw zero, 0x0020(a0) /* Auto Refresh */
|
|
sync
|
|
sw zero, 0x0030(a0) /* Sleep */
|
|
sync
|
|
|
|
DO_SLEEP
|
|
|
|
END(alchemy_sleep_au1000)
|
|
|
|
/* sleep code for Au1550/Au1200 memory controller type */
|
|
LEAF(alchemy_sleep_au1550)
|
|
|
|
SETUP_SLEEP
|
|
|
|
/* cache following instructions, as memory gets put to sleep */
|
|
la t0, 1f
|
|
.set arch=r4000
|
|
cache 0x14, 0(t0)
|
|
cache 0x14, 32(t0)
|
|
cache 0x14, 64(t0)
|
|
cache 0x14, 96(t0)
|
|
.set mips0
|
|
|
|
1: lui a0, 0xb400 /* mem_xxx */
|
|
sw zero, 0x08c0(a0) /* Precharge */
|
|
sync
|
|
sw zero, 0x08d0(a0) /* Self Refresh */
|
|
sync
|
|
|
|
/* wait for sdram to enter self-refresh mode */
|
|
lui t0, 0x0100
|
|
2: lw t1, 0x0850(a0) /* mem_sdstat */
|
|
and t2, t1, t0
|
|
beq t2, zero, 2b
|
|
nop
|
|
|
|
/* disable SDRAM clocks */
|
|
lui t0, 0xcfff
|
|
ori t0, t0, 0xffff
|
|
lw t1, 0x0840(a0) /* mem_sdconfiga */
|
|
and t1, t0, t1 /* clear CE[1:0] */
|
|
sw t1, 0x0840(a0) /* mem_sdconfiga */
|
|
sync
|
|
|
|
DO_SLEEP
|
|
|
|
END(alchemy_sleep_au1550)
|
|
|
|
/* sleepcode for Au1300 memory controller type */
|
|
LEAF(alchemy_sleep_au1300)
|
|
|
|
SETUP_SLEEP
|
|
|
|
/* cache following instructions, as memory gets put to sleep */
|
|
la t0, 2f
|
|
la t1, 4f
|
|
subu t2, t1, t0
|
|
|
|
.set arch=r4000
|
|
|
|
1: cache 0x14, 0(t0)
|
|
subu t2, t2, 32
|
|
bgez t2, 1b
|
|
addu t0, t0, 32
|
|
|
|
.set mips0
|
|
|
|
2: lui a0, 0xb400 /* mem_xxx */
|
|
|
|
/* disable all ports in mem_sdportcfga */
|
|
sw zero, 0x868(a0) /* mem_sdportcfga */
|
|
sync
|
|
|
|
/* disable ODT */
|
|
li t0, 0x03010000
|
|
sw t0, 0x08d8(a0) /* mem_sdcmd0 */
|
|
sw t0, 0x08dc(a0) /* mem_sdcmd1 */
|
|
sync
|
|
|
|
/* precharge */
|
|
li t0, 0x23000400
|
|
sw t0, 0x08dc(a0) /* mem_sdcmd1 */
|
|
sw t0, 0x08d8(a0) /* mem_sdcmd0 */
|
|
sync
|
|
|
|
/* auto refresh */
|
|
sw zero, 0x08c8(a0) /* mem_sdautoref */
|
|
sync
|
|
|
|
/* block access to the DDR */
|
|
lw t0, 0x0848(a0) /* mem_sdconfigb */
|
|
li t1, (1 << 7 | 0x3F)
|
|
or t0, t0, t1
|
|
sw t0, 0x0848(a0) /* mem_sdconfigb */
|
|
sync
|
|
|
|
/* issue the Self Refresh command */
|
|
li t0, 0x10000000
|
|
sw t0, 0x08dc(a0) /* mem_sdcmd1 */
|
|
sw t0, 0x08d8(a0) /* mem_sdcmd0 */
|
|
sync
|
|
|
|
/* wait for sdram to enter self-refresh mode */
|
|
lui t0, 0x0300
|
|
3: lw t1, 0x0850(a0) /* mem_sdstat */
|
|
and t2, t1, t0
|
|
bne t2, t0, 3b
|
|
nop
|
|
|
|
/* disable SDRAM clocks */
|
|
li t0, ~(3<<28)
|
|
lw t1, 0x0840(a0) /* mem_sdconfiga */
|
|
and t1, t1, t0 /* clear CE[1:0] */
|
|
sw t1, 0x0840(a0) /* mem_sdconfiga */
|
|
sync
|
|
|
|
DO_SLEEP
|
|
4:
|
|
|
|
END(alchemy_sleep_au1300)
|
|
|
|
|
|
/* This is where we return upon wakeup.
|
|
* Reload all of the registers and return.
|
|
*/
|
|
LEAF(alchemy_sleep_wakeup)
|
|
lw k0, 0x20(sp)
|
|
mtc0 k0, CP0_STATUS
|
|
lw k0, 0x1c(sp)
|
|
mtc0 k0, CP0_CONTEXT
|
|
lw k0, 0x18(sp)
|
|
mtc0 k0, CP0_PAGEMASK
|
|
lw k0, 0x14(sp)
|
|
mtc0 k0, CP0_CONFIG
|
|
|
|
/* We need to catch the early Alchemy SOCs with
|
|
* the write-only Config[OD] bit and set it back to one...
|
|
*/
|
|
jal au1x00_fixup_config_od
|
|
nop
|
|
lw $1, PT_R1(sp)
|
|
lw $2, PT_R2(sp)
|
|
lw $3, PT_R3(sp)
|
|
lw $4, PT_R4(sp)
|
|
lw $5, PT_R5(sp)
|
|
lw $6, PT_R6(sp)
|
|
lw $7, PT_R7(sp)
|
|
lw $16, PT_R16(sp)
|
|
lw $17, PT_R17(sp)
|
|
lw $18, PT_R18(sp)
|
|
lw $19, PT_R19(sp)
|
|
lw $20, PT_R20(sp)
|
|
lw $21, PT_R21(sp)
|
|
lw $22, PT_R22(sp)
|
|
lw $23, PT_R23(sp)
|
|
lw $26, PT_R26(sp)
|
|
lw $27, PT_R27(sp)
|
|
lw $28, PT_R28(sp)
|
|
lw $30, PT_R30(sp)
|
|
lw $31, PT_R31(sp)
|
|
jr ra
|
|
addiu sp, PT_SIZE
|
|
END(alchemy_sleep_wakeup)
|