root/drivers/soc/bcm/brcmstb/pm/s2-mips.S
/* 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