162306a36Sopenharmony_ci/* SPDX-License-Identifier: GPL-2.0-only */
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci * Copyright (C) 2016 Broadcom Corporation
462306a36Sopenharmony_ci */
562306a36Sopenharmony_ci
662306a36Sopenharmony_ci#include <asm/asm.h>
762306a36Sopenharmony_ci#include <asm/regdef.h>
862306a36Sopenharmony_ci#include <asm/mipsregs.h>
962306a36Sopenharmony_ci#include <asm/bmips.h>
1062306a36Sopenharmony_ci
1162306a36Sopenharmony_ci#include "pm.h"
1262306a36Sopenharmony_ci
1362306a36Sopenharmony_ci	.text
1462306a36Sopenharmony_ci	.set		noreorder
1562306a36Sopenharmony_ci	.align		5
1662306a36Sopenharmony_ci	.global		s3_reentry
1762306a36Sopenharmony_ci
1862306a36Sopenharmony_ci/*
1962306a36Sopenharmony_ci * a0: AON_CTRL base register
2062306a36Sopenharmony_ci * a1: D-Cache line size
2162306a36Sopenharmony_ci */
2262306a36Sopenharmony_ciLEAF(brcm_pm_do_s3)
2362306a36Sopenharmony_ci
2462306a36Sopenharmony_ci	/* Get the address of s3_context */
2562306a36Sopenharmony_ci	la	t0, gp_regs
2662306a36Sopenharmony_ci	sw	ra, 0(t0)
2762306a36Sopenharmony_ci	sw	s0, 4(t0)
2862306a36Sopenharmony_ci	sw	s1, 8(t0)
2962306a36Sopenharmony_ci	sw	s2, 12(t0)
3062306a36Sopenharmony_ci	sw	s3, 16(t0)
3162306a36Sopenharmony_ci	sw	s4, 20(t0)
3262306a36Sopenharmony_ci	sw	s5, 24(t0)
3362306a36Sopenharmony_ci	sw	s6, 28(t0)
3462306a36Sopenharmony_ci	sw	s7, 32(t0)
3562306a36Sopenharmony_ci	sw	gp, 36(t0)
3662306a36Sopenharmony_ci	sw	sp, 40(t0)
3762306a36Sopenharmony_ci	sw	fp, 44(t0)
3862306a36Sopenharmony_ci
3962306a36Sopenharmony_ci	/* Save CP0 Status */
4062306a36Sopenharmony_ci	mfc0	t1, CP0_STATUS
4162306a36Sopenharmony_ci	sw	t1, 48(t0)
4262306a36Sopenharmony_ci
4362306a36Sopenharmony_ci	/* Write-back gp registers - cache will be gone */
4462306a36Sopenharmony_ci	addiu	t1, a1, -1
4562306a36Sopenharmony_ci	not	t1
4662306a36Sopenharmony_ci	and	t0, t1
4762306a36Sopenharmony_ci
4862306a36Sopenharmony_ci	/* Flush at least 64 bytes */
4962306a36Sopenharmony_ci	addiu	t2, t0, 64
5062306a36Sopenharmony_ci	and	t2, t1
5162306a36Sopenharmony_ci
5262306a36Sopenharmony_ci1:	cache	0x17, 0(t0)
5362306a36Sopenharmony_ci	bne	t0, t2, 1b
5462306a36Sopenharmony_ci	addu	t0, a1
5562306a36Sopenharmony_ci
5662306a36Sopenharmony_ci	/* Drop to deep standby */
5762306a36Sopenharmony_ci	li	t1, PM_WARM_CONFIG
5862306a36Sopenharmony_ci	sw	zero, AON_CTRL_PM_CTRL(a0)
5962306a36Sopenharmony_ci	lw	zero, AON_CTRL_PM_CTRL(a0)
6062306a36Sopenharmony_ci	sw	t1, AON_CTRL_PM_CTRL(a0)
6162306a36Sopenharmony_ci	lw	t1, AON_CTRL_PM_CTRL(a0)
6262306a36Sopenharmony_ci
6362306a36Sopenharmony_ci	li	t1, (PM_WARM_CONFIG | PM_PWR_DOWN)
6462306a36Sopenharmony_ci	sw	t1, AON_CTRL_PM_CTRL(a0)
6562306a36Sopenharmony_ci	lw	t1, AON_CTRL_PM_CTRL(a0)
6662306a36Sopenharmony_ci
6762306a36Sopenharmony_ci	/* Enable CP0 interrupt 2 and wait for interrupt */
6862306a36Sopenharmony_ci	mfc0	t0, CP0_STATUS
6962306a36Sopenharmony_ci
7062306a36Sopenharmony_ci	li	t1, ~(ST0_IM | ST0_IE)
7162306a36Sopenharmony_ci	and	t0, t1
7262306a36Sopenharmony_ci	ori	t0, STATUSF_IP2
7362306a36Sopenharmony_ci	mtc0	t0, CP0_STATUS
7462306a36Sopenharmony_ci	nop
7562306a36Sopenharmony_ci	nop
7662306a36Sopenharmony_ci	nop
7762306a36Sopenharmony_ci	ori	t0, ST0_IE
7862306a36Sopenharmony_ci	mtc0	t0, CP0_STATUS
7962306a36Sopenharmony_ci
8062306a36Sopenharmony_ci        /* Wait for interrupt */
8162306a36Sopenharmony_ci        wait
8262306a36Sopenharmony_ci        nop
8362306a36Sopenharmony_ci
8462306a36Sopenharmony_cis3_reentry:
8562306a36Sopenharmony_ci
8662306a36Sopenharmony_ci	/* Clear call/return stack */
8762306a36Sopenharmony_ci	li	t0, (0x06 << 16)
8862306a36Sopenharmony_ci	mtc0	t0, $22, 2
8962306a36Sopenharmony_ci	ssnop
9062306a36Sopenharmony_ci	ssnop
9162306a36Sopenharmony_ci	ssnop
9262306a36Sopenharmony_ci
9362306a36Sopenharmony_ci	/* Clear jump target buffer */
9462306a36Sopenharmony_ci	li	t0, (0x04 << 16)
9562306a36Sopenharmony_ci	mtc0	t0, $22, 2
9662306a36Sopenharmony_ci	ssnop
9762306a36Sopenharmony_ci	ssnop
9862306a36Sopenharmony_ci	ssnop
9962306a36Sopenharmony_ci
10062306a36Sopenharmony_ci	sync
10162306a36Sopenharmony_ci	nop
10262306a36Sopenharmony_ci
10362306a36Sopenharmony_ci	/* Setup mmu defaults */
10462306a36Sopenharmony_ci	mtc0	zero, CP0_WIRED
10562306a36Sopenharmony_ci	mtc0	zero, CP0_ENTRYHI
10662306a36Sopenharmony_ci	li	k0, PM_DEFAULT_MASK
10762306a36Sopenharmony_ci	mtc0	k0, CP0_PAGEMASK
10862306a36Sopenharmony_ci
10962306a36Sopenharmony_ci	li	sp, BMIPS_WARM_RESTART_VEC
11062306a36Sopenharmony_ci	la	k0, plat_wired_tlb_setup
11162306a36Sopenharmony_ci	jalr	k0
11262306a36Sopenharmony_ci	nop
11362306a36Sopenharmony_ci
11462306a36Sopenharmony_ci	/* Restore general purpose registers */
11562306a36Sopenharmony_ci	la	t0, gp_regs
11662306a36Sopenharmony_ci	lw	fp, 44(t0)
11762306a36Sopenharmony_ci	lw	sp, 40(t0)
11862306a36Sopenharmony_ci	lw	gp, 36(t0)
11962306a36Sopenharmony_ci	lw	s7, 32(t0)
12062306a36Sopenharmony_ci	lw	s6, 28(t0)
12162306a36Sopenharmony_ci	lw	s5, 24(t0)
12262306a36Sopenharmony_ci	lw	s4, 20(t0)
12362306a36Sopenharmony_ci	lw	s3, 16(t0)
12462306a36Sopenharmony_ci	lw	s2, 12(t0)
12562306a36Sopenharmony_ci	lw	s1, 8(t0)
12662306a36Sopenharmony_ci	lw	s0, 4(t0)
12762306a36Sopenharmony_ci	lw	ra, 0(t0)
12862306a36Sopenharmony_ci
12962306a36Sopenharmony_ci	/* Restore CP0 status */
13062306a36Sopenharmony_ci	lw	t1, 48(t0)
13162306a36Sopenharmony_ci	mtc0	t1, CP0_STATUS
13262306a36Sopenharmony_ci
13362306a36Sopenharmony_ci	/* Return to caller */
13462306a36Sopenharmony_ci	li	v0, 0
13562306a36Sopenharmony_ci	jr      ra
13662306a36Sopenharmony_ci	nop
13762306a36Sopenharmony_ci
13862306a36Sopenharmony_ciEND(brcm_pm_do_s3)
139