mirror of
https://github.com/brain-hackers/linux-brain.git
synced 2024-06-09 23:36:23 +09:00
![Anson Huang](/assets/img/avatar_default.png)
Current RBC counter value of 0x8(~240us) is NOT enough to block interrupt when entering low power mode, when interrupt arrives during the window of GIC dist disabled and low power mode enter NOT finished, system will stuck at WFI and never wake up, increasing RBC counter can avoid this situation, since the latency introduced by RBC counter is quite trivial, so here just use the MAX value of 0x3f(~2ms) to make it safe enough. Signed-off-by: Anson Huang <Anson.Huang@nxp.com> Reviewed-by: Jacky Bai <ping.bai@nxp.com>
788 lines
15 KiB
ArmAsm
788 lines
15 KiB
ArmAsm
/*
|
|
* Copyright (C) 2015 Freescale Semiconductor, Inc. All Rights Reserved.
|
|
*
|
|
* This program is free software; you can redistribute it and/or modify
|
|
* it under the terms of the GNU General Public License as published by
|
|
* the Free Software Foundation; either version 2 of the License, or
|
|
* (at your option) any later version.
|
|
|
|
* This program is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
* GNU General Public License for more details.
|
|
*/
|
|
|
|
#include <linux/linkage.h>
|
|
|
|
#define PM_INFO_VBASE_OFFSET 0x0
|
|
#define PM_INFO_PBASE_OFFSET 0x4
|
|
#define PM_INFO_RESUME_ADDR_OFFSET 0x8
|
|
#define PM_INFO_PM_INFO_SIZE_OFFSET 0xc
|
|
#define PM_INFO_PM_INFO_TTBR_OFFSET 0x10
|
|
#define PM_INFO_PM_INFO_NUM_ONLINE_CPUS_OFFSET 0x14
|
|
#define PM_INFO_PM_INFO_NUM_LPI_CPUS_OFFSET 0x18
|
|
#define PM_INFO_VAL_OFFSET 0x1c
|
|
#define PM_INFO_FLAG0_OFFSET 0x20
|
|
#define PM_INFO_FLAG1_OFFSET 0x24
|
|
#define PM_INFO_MX7D_DDRC_P_OFFSET 0x28
|
|
#define PM_INFO_MX7D_DDRC_V_OFFSET 0x2c
|
|
#define PM_INFO_MX7D_CCM_P_OFFSET 0x30
|
|
#define PM_INFO_MX7D_CCM_V_OFFSET 0x34
|
|
#define PM_INFO_MX7D_ANATOP_P_OFFSET 0x38
|
|
#define PM_INFO_MX7D_ANATOP_V_OFFSET 0x3c
|
|
#define PM_INFO_MX7D_SRC_P_OFFSET 0x40
|
|
#define PM_INFO_MX7D_SRC_V_OFFSET 0x44
|
|
#define PM_INFO_MX7D_IOMUXC_GPR_P_OFFSET 0x48
|
|
#define PM_INFO_MX7D_IOMUXC_GPR_V_OFFSET 0x4c
|
|
#define PM_INFO_MX7D_GPC_P_OFFSET 0x50
|
|
#define PM_INFO_MX7D_GPC_V_OFFSET 0x54
|
|
#define PM_INFO_MX7D_GIC_DIST_P_OFFSET 0x58
|
|
#define PM_INFO_MX7D_GIC_DIST_V_OFFSET 0x5c
|
|
|
|
#define MX7D_SRC_GPR1 0x74
|
|
#define MX7D_SRC_GPR2 0x78
|
|
#define MX7D_SRC_GPR3 0x7c
|
|
#define MX7D_SRC_GPR4 0x80
|
|
#define MX7D_GPC_IMR1 0x30
|
|
#define MX7D_GPC_IMR2 0x34
|
|
#define MX7D_GPC_IMR3 0x38
|
|
#define MX7D_GPC_IMR4 0x3c
|
|
#define DDRC_STAT 0x4
|
|
#define DDRC_PWRCTL 0x30
|
|
#define DDRC_DBG1 0x304
|
|
#define DDRC_DBGCAM 0x308
|
|
#define DDRC_PSTAT 0x3fc
|
|
#define DDRC_PCTRL_0 0x490
|
|
|
|
/*
|
|
* imx_pen_lock
|
|
*
|
|
* The reference link of Peterson's algorithm:
|
|
* http://en.wikipedia.org/wiki/Peterson's_algorithm
|
|
*
|
|
* val1 = r1 = !turn (inverted from Peterson's algorithm)
|
|
* on cpu 0:
|
|
* r2 = flag[0] (in flag0)
|
|
* r3 = flag[1] (in flag1)
|
|
* on cpu1:
|
|
* r2 = flag[1] (in flag1)
|
|
* r3 = flag[0] (in flag0)
|
|
*
|
|
*/
|
|
.macro imx_pen_lock
|
|
|
|
mov r8, r0
|
|
mrc p15, 0, r5, c0, c0, 5
|
|
and r5, r5, #3
|
|
add r6, r8, #PM_INFO_VAL_OFFSET
|
|
cmp r5, #0
|
|
addeq r7, r8, #PM_INFO_FLAG0_OFFSET
|
|
addeq r8, r8, #PM_INFO_FLAG1_OFFSET
|
|
addne r7, r8, #PM_INFO_FLAG1_OFFSET
|
|
addne r8, r8, #PM_INFO_FLAG0_OFFSET
|
|
|
|
mov r9, #1
|
|
str r9, [r7]
|
|
dsb
|
|
str r5, [r6]
|
|
1:
|
|
dsb
|
|
ldr r9, [r8]
|
|
cmp r9, #1
|
|
ldreq r9, [r6]
|
|
cmpeq r9, r5
|
|
beq 1b
|
|
|
|
.endm
|
|
|
|
.macro imx_pen_unlock
|
|
|
|
dsb
|
|
mrc p15, 0, r6, c0, c0, 5
|
|
and r6, r6, #3
|
|
cmp r6, #0
|
|
addeq r7, r0, #PM_INFO_FLAG0_OFFSET
|
|
addne r7, r0, #PM_INFO_FLAG1_OFFSET
|
|
mov r9, #0
|
|
str r9, [r7]
|
|
|
|
.endm
|
|
|
|
.macro disable_l1_dcache
|
|
|
|
push {r0 - r12, lr}
|
|
ldr r7, =v7_flush_dcache_all
|
|
mov lr, pc
|
|
mov pc, r7
|
|
pop {r0 - r12, lr}
|
|
|
|
/* disable d-cache */
|
|
mrc p15, 0, r7, c1, c0, 0
|
|
bic r7, r7, #(1 << 2)
|
|
mcr p15, 0, r7, c1, c0, 0
|
|
dsb
|
|
isb
|
|
|
|
push {r0 - r12, lr}
|
|
ldr r7, =v7_flush_dcache_all
|
|
mov lr, pc
|
|
mov pc, r7
|
|
pop {r0 - r12, lr}
|
|
|
|
#ifdef CONFIG_SMP
|
|
clrex
|
|
|
|
/* Turn off SMP bit. */
|
|
mrc p15, 0, r8, c1, c0, 1
|
|
bic r8, r8, #0x40
|
|
mcr p15, 0, r8, c1, c0, 1
|
|
|
|
isb
|
|
dsb
|
|
#endif
|
|
|
|
.endm
|
|
|
|
.macro tlb_set_to_ocram
|
|
|
|
/* save ttbr */
|
|
mrc p15, 0, r7, c2, c0, 1
|
|
str r7, [r0, #PM_INFO_PM_INFO_TTBR_OFFSET]
|
|
|
|
/*
|
|
* To ensure no page table walks occur in DDR, we
|
|
* have a another page table stored in IRAM that only
|
|
* contains entries pointing to IRAM, AIPS1 and AIPS2.
|
|
* We need to set the TTBR1 to the new IRAM TLB.
|
|
* Do the following steps:
|
|
* 1. Flush the Branch Target Address Cache (BTAC)
|
|
* 2. Set TTBR1 to point to IRAM page table.
|
|
* 3. Disable page table walks in TTBR0 (PD0 = 1)
|
|
* 4. Set TTBR0.N=1, implying 0-2G is translated by TTBR0
|
|
* and 2-4G is translated by TTBR1.
|
|
*/
|
|
|
|
/* Disable Branch Prediction, Z bit in SCTLR. */
|
|
mrc p15, 0, r6, c1, c0, 0
|
|
bic r6, r6, #0x800
|
|
mcr p15, 0, r6, c1, c0, 0
|
|
|
|
/* Flush the BTAC. */
|
|
ldr r6, =0x0
|
|
mcr p15, 0, r6, c7, c1, 6
|
|
|
|
ldr r6, =iram_tlb_phys_addr
|
|
ldr r7, [r6]
|
|
|
|
dsb
|
|
isb
|
|
|
|
/* Store the IRAM table in TTBR1 */
|
|
mcr p15, 0, r7, c2, c0, 1
|
|
|
|
/* Read TTBCR and set PD0=1, N = 1 */
|
|
mrc p15, 0, r6, c2, c0, 2
|
|
orr r6, r6, #0x11
|
|
mcr p15, 0, r6, c2, c0, 2
|
|
|
|
dsb
|
|
isb
|
|
|
|
/* flush the TLB */
|
|
ldr r6, =0x0
|
|
mcr p15, 0, r6, c8, c3, 0
|
|
|
|
.endm
|
|
|
|
.macro tlb_back_to_ddr
|
|
|
|
/* Read TTBCR and set PD0=0, N = 0 */
|
|
mrc p15, 0, r6, c2, c0, 2
|
|
bic r6, r6, #0x11
|
|
mcr p15, 0, r6, c2, c0, 2
|
|
|
|
dsb
|
|
isb
|
|
|
|
/* flush the TLB */
|
|
ldr r6, =0x0
|
|
mcr p15, 0, r6, c8, c3, 0
|
|
|
|
/* Enable Branch Prediction, Z bit in SCTLR. */
|
|
mrc p15, 0, r6, c1, c0, 0
|
|
orr r6, r6, #0x800
|
|
mcr p15, 0, r6, c1, c0, 0
|
|
|
|
/* Flush the Branch Target Address Cache (BTAC) */
|
|
ldr r6, =0x0
|
|
mcr p15, 0, r6, c7, c1, 6
|
|
|
|
/* restore ttbr */
|
|
ldr r7, [r0, #PM_INFO_PM_INFO_TTBR_OFFSET]
|
|
mcr p15, 0, r7, c2, c0, 1
|
|
|
|
.endm
|
|
|
|
/* r10 must be DDRC base address */
|
|
.macro ddrc_enter_self_refresh
|
|
|
|
ldr r10, [r0, #PM_INFO_MX7D_DDRC_V_OFFSET]
|
|
|
|
/* disable port */
|
|
ldr r7, =0x0
|
|
str r7, [r10, #DDRC_PCTRL_0]
|
|
|
|
/* let DDR out of self-refresh */
|
|
ldr r7, =0x0
|
|
str r7, [r10, #DDRC_PWRCTL]
|
|
|
|
/* wait rw port_busy clear */
|
|
ldr r6, =(0x1 << 16)
|
|
orr r6, r6, #0x1
|
|
2:
|
|
ldr r7, [r10, #DDRC_PSTAT]
|
|
ands r7, r7, r6
|
|
bne 2b
|
|
|
|
ldr r7, =0x1
|
|
str r7, [r10, #DDRC_DBG1]
|
|
|
|
ldr r6, =0x36000000
|
|
11:
|
|
ldr r7, [r10, #DDRC_DBGCAM]
|
|
and r7, r7, r6
|
|
cmp r7, r6
|
|
bne 11b
|
|
|
|
/* enter self-refresh bit 5 */
|
|
ldr r7, =(0x1 << 5)
|
|
str r7, [r10, #DDRC_PWRCTL]
|
|
|
|
/* wait until self-refresh mode entered */
|
|
3:
|
|
ldr r7, [r10, #DDRC_STAT]
|
|
and r7, r7, #0x3
|
|
cmp r7, #0x3
|
|
bne 3b
|
|
4:
|
|
ldr r7, [r10, #DDRC_STAT]
|
|
ands r7, r7, #0x20
|
|
beq 4b
|
|
|
|
/* disable dram clk */
|
|
ldr r7, [r10, #DDRC_PWRCTL]
|
|
orr r7, r7, #(1 << 3)
|
|
str r7, [r10, #DDRC_PWRCTL]
|
|
|
|
/*
|
|
* TO1.1 adds feature of DDR pads power down,
|
|
* although TO1.0 has no such function, but it is
|
|
* NOT harmful to program GPR registers for TO1.0,
|
|
* it can avoid the logic of version check in idle
|
|
* thread.
|
|
*/
|
|
ldr r10, [r0, #PM_INFO_MX7D_IOMUXC_GPR_V_OFFSET]
|
|
ldr r7, =0xf0000
|
|
str r7, [r10]
|
|
|
|
/* delay 20us, measured by gpio */
|
|
ldr r7, =20
|
|
12:
|
|
subs r7, r7, #0x1
|
|
bne 12b
|
|
|
|
.endm
|
|
|
|
/* r10 must be DDRC base address */
|
|
.macro ddrc_exit_self_refresh
|
|
|
|
cmp r5, #0x1
|
|
ldreq r10, [r0, #PM_INFO_MX7D_IOMUXC_GPR_P_OFFSET]
|
|
ldrne r10, [r0, #PM_INFO_MX7D_IOMUXC_GPR_V_OFFSET]
|
|
|
|
ldr r7, =0x0
|
|
str r7, [r10]
|
|
|
|
ldr r7, =20
|
|
13:
|
|
subs r7, r7, #0x1
|
|
bne 13b
|
|
|
|
cmp r5, #0x1
|
|
ldreq r10, [r0, #PM_INFO_MX7D_DDRC_P_OFFSET]
|
|
ldrne r10, [r0, #PM_INFO_MX7D_DDRC_V_OFFSET]
|
|
|
|
ldr r7, =0x0
|
|
str r7, [r10, #DDRC_DBG1]
|
|
|
|
ldr r6, =0x30000000
|
|
14:
|
|
ldr r7, [r10, #DDRC_DBGCAM]
|
|
and r7, r7, r6
|
|
cmp r7, r6
|
|
bne 14b
|
|
|
|
/* let DDR out of self-refresh */
|
|
ldr r7, =0x0
|
|
str r7, [r10, #DDRC_PWRCTL]
|
|
|
|
/* wait until self-refresh mode exited */
|
|
5:
|
|
ldr r7, [r10, #DDRC_STAT]
|
|
and r7, r7, #0x3
|
|
cmp r7, #0x3
|
|
beq 5b
|
|
|
|
/* enable auto self-refresh */
|
|
ldr r7, [r10, #DDRC_PWRCTL]
|
|
orr r7, r7, #(1 << 0)
|
|
str r7, [r10, #DDRC_PWRCTL]
|
|
|
|
ldr r7, =0x1
|
|
str r7, [r10, #DDRC_PCTRL_0]
|
|
|
|
.endm
|
|
|
|
.macro pll_do_wait_lock
|
|
6:
|
|
ldr r7, [r10, r8]
|
|
ands r7, #0x80000000
|
|
beq 6b
|
|
|
|
.endm
|
|
|
|
.macro ccm_enter_idle
|
|
|
|
ldr r10, [r0, #PM_INFO_MX7D_ANATOP_V_OFFSET]
|
|
|
|
/* ungate pfd1 332m for lower axi */
|
|
ldr r7, =0x8000
|
|
str r7, [r10, #0xc8]
|
|
|
|
ldr r10, [r0, #PM_INFO_MX7D_CCM_V_OFFSET]
|
|
|
|
/* switch ARM CLK to OSC */
|
|
ldr r8, =0x8000
|
|
ldr r7, [r10, r8]
|
|
bic r7, r7, #0x7000000
|
|
str r7, [r10, r8]
|
|
|
|
/* lower AXI clk from 24MHz to 3MHz */
|
|
ldr r8, =0x8800
|
|
ldr r7, [r10, r8]
|
|
orr r7, r7, #0x7
|
|
str r7, [r10, r8]
|
|
|
|
/* lower AHB clk from 24MHz to 3MHz */
|
|
ldr r8, =0x9000
|
|
ldr r7, [r10, r8]
|
|
orr r7, r7, #0x7
|
|
str r7, [r10, r8]
|
|
|
|
/* gate dram clk */
|
|
ldr r8, =0x9880
|
|
ldr r7, [r10, r8]
|
|
bic r7, r7, #0x10000000
|
|
str r7, [r10, r8]
|
|
|
|
ldr r10, [r0, #PM_INFO_MX7D_ANATOP_V_OFFSET]
|
|
|
|
/* gate pfd1 332m */
|
|
ldr r7, =0x8000
|
|
str r7, [r10, #0xc4]
|
|
|
|
/* gate system pll pfd div 1 */
|
|
ldr r7, =0x10
|
|
str r7, [r10, #0xb4]
|
|
/* power down ARM, 480 and DRAM PLL */
|
|
ldr r7, =0x1000
|
|
str r7, [r10, #0x64]
|
|
str r7, [r10, #0xb4]
|
|
ldr r7, =0x100000
|
|
str r7, [r10, #0x74]
|
|
|
|
.endm
|
|
|
|
.macro ccm_exit_idle
|
|
|
|
cmp r5, #0x1
|
|
ldreq r10, [r0, #PM_INFO_MX7D_ANATOP_P_OFFSET]
|
|
ldrne r10, [r0, #PM_INFO_MX7D_ANATOP_V_OFFSET]
|
|
|
|
/* power up ARM, 480 and DRAM PLL */
|
|
ldr r7, =0x1000
|
|
str r7, [r10, #0x68]
|
|
ldr r8, =0x60
|
|
pll_do_wait_lock
|
|
|
|
ldr r7, =0x1000
|
|
str r7, [r10, #0xb8]
|
|
ldr r8, =0xb0
|
|
pll_do_wait_lock
|
|
|
|
ldr r7, =0x100000
|
|
str r7, [r10, #0x78]
|
|
ldr r8, =0x70
|
|
pll_do_wait_lock
|
|
|
|
/* ungate pfd1 332m for lower axi */
|
|
ldr r7, =0x8000
|
|
str r7, [r10, #0xc8]
|
|
|
|
/* ungate system pll pfd div 1 */
|
|
ldr r7, =0x10
|
|
str r7, [r10, #0xb8]
|
|
|
|
cmp r5, #0x1
|
|
ldreq r10, [r0, #PM_INFO_MX7D_CCM_P_OFFSET]
|
|
ldrne r10, [r0, #PM_INFO_MX7D_CCM_V_OFFSET]
|
|
|
|
/* switch ARM CLK to PLL */
|
|
ldr r8, =0x8000
|
|
ldr r7, [r10, r8]
|
|
orr r7, r7, #0x1000000
|
|
str r7, [r10, r8]
|
|
|
|
/* restore AXI clk from 3MHz to 24MHz */
|
|
ldr r8, =0x8800
|
|
ldr r7, [r10, r8]
|
|
bic r7, r7, #0x7
|
|
str r7, [r10, r8]
|
|
|
|
/* restore AHB clk from 3MHz to 24MHz */
|
|
ldr r8, =0x9000
|
|
ldr r7, [r10, r8]
|
|
bic r7, r7, #0x7
|
|
str r7, [r10, r8]
|
|
|
|
/* ungate dram clk */
|
|
ldr r8, =0x9880
|
|
ldr r7, [r10, r8]
|
|
orr r7, r7, #0x10000000
|
|
str r7, [r10, r8]
|
|
|
|
cmp r5, #0x1
|
|
ldreq r10, [r0, #PM_INFO_MX7D_ANATOP_P_OFFSET]
|
|
ldrne r10, [r0, #PM_INFO_MX7D_ANATOP_V_OFFSET]
|
|
|
|
/* gate pfd1 332m for lower axi */
|
|
ldr r7, =0x8000
|
|
str r7, [r10, #0xc4]
|
|
|
|
.endm
|
|
|
|
.macro anatop_enter_idle
|
|
|
|
ldr r10, [r0, #PM_INFO_MX7D_ANATOP_V_OFFSET]
|
|
|
|
/* XTAL to RC-OSC switch */
|
|
ldr r7, [r10]
|
|
orr r7, r7, #0x1000
|
|
str r7, [r10]
|
|
/* power down XTAL */
|
|
ldr r7, [r10]
|
|
orr r7, r7, #0x1
|
|
str r7, [r10]
|
|
|
|
/* enable weak 1P0A */
|
|
ldr r7, [r10, #0x200]
|
|
orr r7, r7, #0x40000
|
|
str r7, [r10, #0x200]
|
|
|
|
/* disable LDO 1P0A */
|
|
ldr r7, [r10, #0x200]
|
|
bic r7, r7, #0x1
|
|
str r7, [r10, #0x200]
|
|
|
|
/* disable LDO 1P0D */
|
|
ldr r7, [r10, #0x210]
|
|
bic r7, r7, #0x1
|
|
str r7, [r10, #0x210]
|
|
|
|
/* disable LDO 1P2 */
|
|
ldr r7, [r10, #0x220]
|
|
bic r7, r7, #0x1
|
|
str r7, [r10, #0x220]
|
|
|
|
/* switch to low power bandgap */
|
|
ldr r7, [r10, #0x270]
|
|
orr r7, r7, #0x400
|
|
str r7, [r10, #0x270]
|
|
/* power down normal bandgap */
|
|
orr r7, r7, #0x1
|
|
str r7, [r10, #0x270]
|
|
|
|
.endm
|
|
|
|
.macro anatop_exit_idle
|
|
|
|
cmp r5, #0x1
|
|
ldreq r10, [r0, #PM_INFO_MX7D_ANATOP_P_OFFSET]
|
|
ldrne r10, [r0, #PM_INFO_MX7D_ANATOP_V_OFFSET]
|
|
|
|
/* power on normal bandgap */
|
|
ldr r7, [r10, #0x270]
|
|
bic r7, r7, #0x1
|
|
str r7, [r10, #0x270]
|
|
/* switch to normal bandgap */
|
|
bic r7, r7, #0x400
|
|
str r7, [r10, #0x270]
|
|
|
|
/* enable LDO 1P2 */
|
|
ldr r7, [r10, #0x220]
|
|
orr r7, r7, #0x1
|
|
str r7, [r10, #0x220]
|
|
7:
|
|
ldr r7, [r10, #0x220]
|
|
ands r7, #0x20000
|
|
beq 7b
|
|
|
|
/* enable LDO 1P0D */
|
|
ldr r7, [r10, #0x210]
|
|
orr r7, r7, #0x1
|
|
str r7, [r10, #0x210]
|
|
8:
|
|
ldr r7, [r10, #0x210]
|
|
ands r7, #0x20000
|
|
beq 8b
|
|
|
|
/* enable LDO 1P0A */
|
|
ldr r7, [r10, #0x200]
|
|
orr r7, r7, #0x1
|
|
str r7, [r10, #0x200]
|
|
9:
|
|
ldr r7, [r10, #0x200]
|
|
ands r7, #0x20000
|
|
beq 9b
|
|
/* disable weak 1P0A */
|
|
ldr r7, [r10, #0x200]
|
|
bic r7, r7, #0x40000
|
|
str r7, [r10, #0x200]
|
|
|
|
/* power up XTAL and wait */
|
|
ldr r7, [r10]
|
|
bic r7, r7, #0x1
|
|
str r7, [r10]
|
|
10:
|
|
ldr r7, [r10]
|
|
ands r7, r7, #0x4
|
|
beq 10b
|
|
/* RC-OSC to XTAL switch */
|
|
ldr r7, [r10]
|
|
bic r7, r7, #0x1000
|
|
str r7, [r10]
|
|
|
|
.endm
|
|
|
|
.extern iram_tlb_phys_addr
|
|
|
|
.align 3
|
|
ENTRY(imx7d_low_power_idle)
|
|
push {r0 - r12}
|
|
|
|
/* get necessary info from pm_info */
|
|
ldr r1, [r0, #PM_INFO_PBASE_OFFSET]
|
|
ldr r2, [r0, #PM_INFO_PM_INFO_SIZE_OFFSET]
|
|
|
|
/*
|
|
* counting the resume address in iram
|
|
* to set it in SRC register.
|
|
*/
|
|
ldr r5, =imx7d_low_power_idle
|
|
ldr r6, =wakeup
|
|
sub r6, r6, r5
|
|
add r8, r1, r2
|
|
add r3, r8, r6
|
|
|
|
/* r11 is cpu id */
|
|
mrc p15, 0, r11, c0, c0, 5
|
|
and r11, r11, #3
|
|
cmp r11, #0x0
|
|
ldreq r6, =MX7D_SRC_GPR1
|
|
ldreq r7, =MX7D_SRC_GPR2
|
|
ldrne r6, =MX7D_SRC_GPR3
|
|
ldrne r7, =MX7D_SRC_GPR4
|
|
/* store physical resume addr and pm_info address. */
|
|
ldr r10, [r0, #PM_INFO_MX7D_SRC_V_OFFSET]
|
|
str r3, [r10, r6]
|
|
str r1, [r10, r7]
|
|
|
|
disable_l1_dcache
|
|
|
|
tlb_set_to_ocram
|
|
|
|
/* check last to sleep */
|
|
ldr r6, [r0, #PM_INFO_PM_INFO_NUM_ONLINE_CPUS_OFFSET]
|
|
ldr r7, [r0, #PM_INFO_PM_INFO_NUM_LPI_CPUS_OFFSET]
|
|
cmp r6, r7
|
|
bne lpi_enter_done
|
|
|
|
ddrc_enter_self_refresh
|
|
ccm_enter_idle
|
|
anatop_enter_idle
|
|
|
|
ldr r10, [r0, #PM_INFO_MX7D_GIC_DIST_V_OFFSET]
|
|
ldr r7, =0x0
|
|
ldr r8, =0x1000
|
|
str r7, [r10, r8]
|
|
|
|
ldr r10, [r0, #PM_INFO_MX7D_GPC_V_OFFSET]
|
|
ldr r4, [r10, #MX7D_GPC_IMR1]
|
|
ldr r5, [r10, #MX7D_GPC_IMR2]
|
|
ldr r6, [r10, #MX7D_GPC_IMR3]
|
|
ldr r7, [r10, #MX7D_GPC_IMR4]
|
|
|
|
ldr r8, =0xffffffff
|
|
str r8, [r10, #MX7D_GPC_IMR1]
|
|
str r8, [r10, #MX7D_GPC_IMR2]
|
|
str r8, [r10, #MX7D_GPC_IMR3]
|
|
str r8, [r10, #MX7D_GPC_IMR4]
|
|
|
|
/*
|
|
* enable the RBC bypass counter here
|
|
* to hold off the interrupts. RBC counter
|
|
* = 8 (2ms). With this setting, the latency
|
|
* from wakeup interrupt to ARM power up
|
|
* is ~2ms.
|
|
*/
|
|
ldr r8, [r10, #0x14]
|
|
orr r8, r8, #(0x3f << 24)
|
|
str r8, [r10, #0x14]
|
|
|
|
/* enable the counter. */
|
|
ldr r8, [r10, #0x14]
|
|
orr r8, r8, #(0x1 << 30)
|
|
str r8, [r10, #0x14]
|
|
|
|
/* unmask all the GPC interrupts. */
|
|
str r4, [r10, #MX7D_GPC_IMR1]
|
|
str r5, [r10, #MX7D_GPC_IMR2]
|
|
str r6, [r10, #MX7D_GPC_IMR3]
|
|
str r7, [r10, #MX7D_GPC_IMR4]
|
|
|
|
/*
|
|
* now delay for a short while (30usec)
|
|
* ARM is at 24MHz at this point
|
|
* so a short loop should be enough.
|
|
* this delay is required to ensure that
|
|
* the RBC counter can start counting in
|
|
* case an interrupt is already pending
|
|
* or in case an interrupt arrives just
|
|
* as ARM is about to assert DSM_request.
|
|
*/
|
|
ldr r4, =5
|
|
rbc_loop:
|
|
subs r4, r4, #0x1
|
|
bne rbc_loop
|
|
|
|
lpi_enter_done:
|
|
|
|
imx_pen_unlock
|
|
|
|
wfi
|
|
|
|
nop
|
|
nop
|
|
nop
|
|
nop
|
|
nop
|
|
|
|
nop
|
|
nop
|
|
nop
|
|
nop
|
|
nop
|
|
|
|
nop
|
|
nop
|
|
nop
|
|
nop
|
|
nop
|
|
|
|
nop
|
|
nop
|
|
nop
|
|
nop
|
|
nop
|
|
|
|
nop
|
|
nop
|
|
nop
|
|
nop
|
|
nop
|
|
|
|
imx_pen_lock
|
|
|
|
/* check first to wake */
|
|
ldr r6, [r0, #PM_INFO_PM_INFO_NUM_ONLINE_CPUS_OFFSET]
|
|
ldr r7, [r0, #PM_INFO_PM_INFO_NUM_LPI_CPUS_OFFSET]
|
|
cmp r6, r7
|
|
bne skip_lpi_flow
|
|
|
|
ldr r5, =0x0
|
|
anatop_exit_idle
|
|
ccm_exit_idle
|
|
ddrc_exit_self_refresh
|
|
|
|
ldr r10, [r0, #PM_INFO_MX7D_GIC_DIST_V_OFFSET]
|
|
ldr r7, =0x1
|
|
ldr r8, =0x1000
|
|
str r7, [r10, r8]
|
|
|
|
skip_lpi_flow:
|
|
tlb_back_to_ddr
|
|
|
|
#ifdef CONFIG_SMP
|
|
/* Turn on SMP bit. */
|
|
mrc p15, 0, r7, c1, c0, 1
|
|
orr r7, r7, #0x40
|
|
mcr p15, 0, r7, c1, c0, 1
|
|
|
|
isb
|
|
#endif
|
|
|
|
/* enable d-cache */
|
|
mrc p15, 0, r7, c1, c0, 0
|
|
orr r7, r7, #(1 << 2)
|
|
mcr p15, 0, r7, c1, c0, 0
|
|
dsb
|
|
isb
|
|
|
|
/* Restore registers */
|
|
pop {r0 - r12}
|
|
mov pc, lr
|
|
|
|
wakeup:
|
|
|
|
/* invalidate L1 I-cache first */
|
|
mov r1, #0x0
|
|
mcr p15, 0, r1, c7, c5, 0
|
|
mcr p15, 0, r1, c7, c5, 0
|
|
mcr p15, 0, r1, c7, c5, 6
|
|
/* enable the Icache and branch prediction */
|
|
mov r1, #0x1800
|
|
mcr p15, 0, r1, c1, c0, 0
|
|
isb
|
|
|
|
imx_pen_lock
|
|
|
|
/* check first to wake */
|
|
ldr r6, [r0, #PM_INFO_PM_INFO_NUM_ONLINE_CPUS_OFFSET]
|
|
ldr r7, [r0, #PM_INFO_PM_INFO_NUM_LPI_CPUS_OFFSET]
|
|
cmp r6, r7
|
|
bne wakeup_skip_lpi_flow
|
|
|
|
ldr r5, =0x1
|
|
anatop_exit_idle
|
|
ccm_exit_idle
|
|
ddrc_exit_self_refresh
|
|
|
|
wakeup_skip_lpi_flow:
|
|
/* get physical resume address from pm_info. */
|
|
ldr lr, [r0, #PM_INFO_RESUME_ADDR_OFFSET]
|
|
|
|
/* Restore registers */
|
|
mov pc, lr
|
|
.ltorg
|
|
ENDPROC(imx7d_low_power_idle)
|