/* SPDX-License-Identifier: GPL-2.0-only */
/*
* Copyright (C) 2016 Broadcom Corporation
*/
#include <asm/asm.h>
#include <asm/regdef.h>
#include <asm/mipsregs.h>
#include <asm/stackframe.h>
#include "pm.h"
.text
.set noreorder
.align 5
/*
* a0: u32 params array
*/
LEAF(brcm_pm_do_s2)
subu sp, 64
sw ra, 0(sp)
sw s0, 4(sp)
sw s1, 8(sp)
sw s2, 12(sp)
sw s3, 16(sp)
sw s4, 20(sp)
sw s5, 24(sp)
sw s6, 28(sp)
sw s7, 32(sp)
/*
* Dereference the params array
* s0: AON_CTRL base register
* s1: DDR_PHY base register
* s2: TIMERS base register
* s3: I-Cache line size
* s4: Restart vector address
* s5: Restart vector size
*/
move t0, a0
lw s0, 0(t0)
lw s1, 4(t0)
lw s2, 8(t0)
lw s3, 12(t0)
lw s4, 16(t0)
lw s5, 20(t0)
/* Lock this asm section into the I-cache */
addiu t1, s3, -1
not t1
la t0, brcm_pm_do_s2
and t0, t1
la t2, asm_end
and t2, t1
1: cache 0x1c, 0(t0)
bne t0, t2, 1b
addu t0, s3
/* Lock the interrupt vector into the I-cache */
move t0, zero
2: move t1, s4
cache 0x1c, 0(t1)
addu t1, s3
addu t0, s3
ble t0, s5, 2b
nop
sync
/* Power down request */
li t0, PM_S2_COMMAND
sw zero, AON_CTRL_PM_CTRL(s0)
lw zero, AON_CTRL_PM_CTRL(s0)
sw t0, AON_CTRL_PM_CTRL(s0)
lw t0, AON_CTRL_PM_CTRL(s0)
/* Enable CP0 interrupt 2 and wait for interrupt */
mfc0 t0, CP0_STATUS
/* Save cp0 sr for restoring later */
move s6, t0
li t1, ~(ST0_IM | ST0_IE)
and t0, t1
ori t0, STATUSF_IP2
mtc0 t0, CP0_STATUS
nop
nop
nop
ori t0, ST0_IE
mtc0 t0, CP0_STATUS
/* Wait for interrupt */
wait
nop
/* Wait for memc0 */
1: lw t0, DDR40_PHY_CONTROL_REGS_0_PLL_STATUS(s1)
andi t0, 1
beqz t0, 1b
nop
/* 1ms delay needed for stable recovery */
/* Use TIMER1 to count 1 ms */
li t0, RESET_TIMER
sw t0, TIMER_TIMER1_CTRL(s2)
lw t0, TIMER_TIMER1_CTRL(s2)
li t0, START_TIMER
sw t0, TIMER_TIMER1_CTRL(s2)
lw t0, TIMER_TIMER1_CTRL(s2)
/* Prepare delay */
li t0, TIMER_MASK
lw t1, TIMER_TIMER1_STAT(s2)
and t1, t0
/* 1ms delay */
addi t1, 27000
/* Wait for the timer value to exceed t1 */
1: lw t0, TIMER_TIMER1_STAT(s2)
sgtu t2, t1, t0
bnez t2, 1b
nop
/* Power back up */
li t1, 1
sw t1, AON_CTRL_HOST_MISC_CMDS(s0)
lw t1, AON_CTRL_HOST_MISC_CMDS(s0)
sw zero, AON_CTRL_PM_CTRL(s0)
lw zero, AON_CTRL_PM_CTRL(s0)
/* Unlock I-cache */
addiu t1, s3, -1
not t1
la t0, brcm_pm_do_s2
and t0, t1
la t2, asm_end
and t2, t1
1: cache 0x00, 0(t0)
bne t0, t2, 1b
addu t0, s3
/* Unlock interrupt vector */
move t0, zero
2: move t1, s4
cache 0x00, 0(t1)
addu t1, s3
addu t0, s3
ble t0, s5, 2b
nop
/* Restore cp0 sr */
sync
nop
mtc0 s6, CP0_STATUS
nop
/* Set return value to success */
li v0, 0
/* Return to caller */
lw s7, 32(sp)
lw s6, 28(sp)
lw s5, 24(sp)
lw s4, 20(sp)
lw s3, 16(sp)
lw s2, 12(sp)
lw s1, 8(sp)
lw s0, 4(sp)
lw ra, 0(sp)
addiu sp, 64
jr ra
nop
END(brcm_pm_do_s2)
.globl asm_end
asm_end:
nop