| /* 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 | 
 |  |