1
0
Fork 0
alistair23-linux/arch/arm/mach-imx/suspend-imx6.S

732 lines
16 KiB
ArmAsm
Raw Normal View History

/* SPDX-License-Identifier: GPL-2.0-or-later */
/*
* Copyright 2014 Freescale Semiconductor, Inc.
*/
#include <linux/linkage.h>
ARM: convert all "mov.* pc, reg" to "bx reg" for ARMv6+ ARMv6 and greater introduced a new instruction ("bx") which can be used to return from function calls. Recent CPUs perform better when the "bx lr" instruction is used rather than the "mov pc, lr" instruction, and this sequence is strongly recommended to be used by the ARM architecture manual (section A.4.1.1). We provide a new macro "ret" with all its variants for the condition code which will resolve to the appropriate instruction. Rather than doing this piecemeal, and miss some instances, change all the "mov pc" instances to use the new macro, with the exception of the "movs" instruction and the kprobes code. This allows us to detect the "mov pc, lr" case and fix it up - and also gives us the possibility of deploying this for other registers depending on the CPU selection. Reported-by: Will Deacon <will.deacon@arm.com> Tested-by: Stephen Warren <swarren@nvidia.com> # Tegra Jetson TK1 Tested-by: Robert Jarzmik <robert.jarzmik@free.fr> # mioa701_bootresume.S Tested-by: Andrew Lunn <andrew@lunn.ch> # Kirkwood Tested-by: Shawn Guo <shawn.guo@freescale.com> Tested-by: Tony Lindgren <tony@atomide.com> # OMAPs Tested-by: Gregory CLEMENT <gregory.clement@free-electrons.com> # Armada XP, 375, 385 Acked-by: Sekhar Nori <nsekhar@ti.com> # DaVinci Acked-by: Christoffer Dall <christoffer.dall@linaro.org> # kvm/hyp Acked-by: Haojian Zhuang <haojian.zhuang@gmail.com> # PXA3xx Acked-by: Stefano Stabellini <stefano.stabellini@eu.citrix.com> # Xen Tested-by: Uwe Kleine-König <u.kleine-koenig@pengutronix.de> # ARMv7M Tested-by: Simon Horman <horms+renesas@verge.net.au> # Shmobile Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
2014-06-30 09:29:12 -06:00
#include <asm/assembler.h>
#include <asm/asm-offsets.h>
#include <asm/hardware/cache-l2x0.h>
#include "hardware.h"
/*
* ==================== low level suspend ====================
*
* Better to follow below rules to use ARM registers:
* r0: pm_info structure address;
* r1 ~ r4: for saving pm_info members;
* r5 ~ r10: free registers;
* r11: io base address.
*
* suspend ocram space layout:
* ======================== high address ======================
* .
* .
* .
* ^
* ^
* ^
* imx6_suspend code
* PM_INFO structure(imx6_cpu_pm_info)
* ======================== low address =======================
*/
/*
* Below offsets are based on struct imx6_cpu_pm_info
* which defined in arch/arm/mach-imx/pm-imx6q.c, this
* structure contains necessary pm info for low level
* suspend related code.
*/
#define PM_INFO_PBASE_OFFSET 0x0
#define PM_INFO_RESUME_ADDR_OFFSET 0x4
#define PM_INFO_DDR_TYPE_OFFSET 0x8
#define PM_INFO_PM_INFO_SIZE_OFFSET 0xC
#define PM_INFO_MX6Q_MMDC0_P_OFFSET 0x10
#define PM_INFO_MX6Q_MMDC0_V_OFFSET 0x14
#define PM_INFO_MX6Q_MMDC1_P_OFFSET 0x18
#define PM_INFO_MX6Q_MMDC1_V_OFFSET 0x1C
#define PM_INFO_MX6Q_SRC_P_OFFSET 0x20
#define PM_INFO_MX6Q_SRC_V_OFFSET 0x24
#define PM_INFO_MX6Q_IOMUXC_P_OFFSET 0x28
#define PM_INFO_MX6Q_IOMUXC_V_OFFSET 0x2C
#define PM_INFO_MX6Q_CCM_P_OFFSET 0x30
#define PM_INFO_MX6Q_CCM_V_OFFSET 0x34
#define PM_INFO_MX6Q_GPC_P_OFFSET 0x38
#define PM_INFO_MX6Q_GPC_V_OFFSET 0x3C
#define PM_INFO_MX6Q_L2_P_OFFSET 0x40
#define PM_INFO_MX6Q_L2_V_OFFSET 0x44
#define PM_INFO_MX6Q_ANATOP_P_OFFSET 0x48
#define PM_INFO_MX6Q_ANATOP_V_OFFSET 0x4C
#define PM_INFO_MX6Q_TTBR1_V_OFFSET 0x50
#define PM_INFO_MMDC_IO_NUM_OFFSET 0x54
#define PM_INFO_MMDC_IO_VAL_OFFSET 0x58
/* below offsets depends on MX6_MAX_MMDC_IO_NUM(36) definition */
#define PM_INFO_MMDC_NUM_OFFSET 0x208
#define PM_INFO_MMDC_VAL_OFFSET 0x20C
#define MX6Q_SRC_GPR1 0x20
#define MX6Q_SRC_GPR2 0x24
#define MX6Q_MMDC_MISC 0x18
#define MX6Q_MMDC_MAPSR 0x404
#define MX6Q_MMDC_MPDGCTRL0 0x83c
#define MX6Q_GPC_IMR1 0x08
#define MX6Q_GPC_IMR2 0x0c
#define MX6Q_GPC_IMR3 0x10
#define MX6Q_GPC_IMR4 0x14
#define MX6Q_CCM_CCR 0x0
#define MX6Q_ANATOP_CORE 0x140
.align 3
/* Check if the cpu is cortex-a7 */
.macro is_cortex_a7
/* Read the primary cpu number is MPIDR */
mrc p15, 0, r5, c0, c0, 0
ldr r6, =0xfff0
and r5, r5, r6
ldr r6, =0xc070
cmp r5, r6
.endm
.macro disable_l1_cache
/*
* Flush all data from the L1 data cache before disabling
* SCTLR.C bit.
*/
push {r0 - r10, lr}
ldr r7, =v7_flush_dcache_all
mov lr, pc
mov pc, r7
pop {r0 - r10, 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 -r10, lr}
ldr r7, = v7_flush_dcache_all
mov lr, pc
mov pc , r7
pop {r0 -r10, lr}
.endm
.macro sync_l2_cache
/* sync L2 cache to drain L2's buffers to DRAM. */
#ifdef CONFIG_CACHE_L2X0
ldr r11, [r0, #PM_INFO_MX6Q_L2_V_OFFSET]
teq r11, #0
beq 6f
mov r6, #0x0
str r6, [r11, #L2X0_CACHE_SYNC]
1:
ldr r6, [r11, #L2X0_CACHE_SYNC]
ands r6, r6, #0x1
bne 1b
6:
#endif
.endm
/* r11 must be MMDC base address */
.macro reset_read_fifo
/* reset read FIFO, RST_RD_FIFO */
ldr r7, =MX6Q_MMDC_MPDGCTRL0
ldr r6, [r11, r7]
orr r6, r6, #(1 << 31)
str r6, [r11, r7]
2:
ldr r6, [r11, r7]
ands r6, r6, #(1 << 31)
bne 2b
/* reset FIFO a second time */
ldr r6, [r11, r7]
orr r6, r6, #(1 << 31)
str r6, [r11, r7]
3:
ldr r6, [r11, r7]
ands r6, r6, #(1 << 31)
bne 3b
/* check if lppdr2 2 channel mode is enabled */
ldr r7, =MX6Q_MMDC_MISC
ldr r6, [r11, r7]
ands r6, r6, #(1 << 2)
beq 6f
ldr r7, =MX6Q_MMDC_MPDGCTRL0
ldr r6, [r12, r7]
orr r6, r6, #(1 << 31)
str r6, [r12, r7]
4:
ldr r6, [r12, r7]
ands r6, r6, #(1 << 31)
bne 4b
ldr r6, [r12, r7]
orr r6, r6, #(1 << 31)
str r6, [r12, r7]
5:
ldr r6, [r12, r7]
ands r6, r6, #(1 << 31)
bne 5b
6:
.endm
/* r11 must be MMDC base address */
.macro mmdc_out_and_auto_self_refresh
/* let DDR out of self-refresh */
ldr r7, [r11, #MX6Q_MMDC_MAPSR]
bic r7, r7, #(1 << 21)
str r7, [r11, #MX6Q_MMDC_MAPSR]
7:
ldr r7, [r11, #MX6Q_MMDC_MAPSR]
ands r7, r7, #(1 << 25)
bne 7b
/* enable DDR auto power saving */
ldr r7, [r11, #MX6Q_MMDC_MAPSR]
bic r7, r7, #0x1
str r7, [r11, #MX6Q_MMDC_MAPSR]
/* check if lppdr2 2 channel mode is enabled */
ldr r7, =MX6Q_MMDC_MISC
ldr r6, [r11, r7]
ands r6, r6, #(1 << 2)
beq 9f
ldr r7, [r12, #MX6Q_MMDC_MAPSR]
bic r7, r7, #(1 << 21)
str r7, [r12, #MX6Q_MMDC_MAPSR]
8:
ldr r7, [r12, #MX6Q_MMDC_MAPSR]
ands r7, r7, #(1 << 25)
bne 8b
ldr r7, [r12, #MX6Q_MMDC_MAPSR]
bic r7, r7, #0x1
str r7, [r12, #MX6Q_MMDC_MAPSR]
9:
.endm
/* r10 must be iomuxc base address */
.macro resume_iomuxc_gpr
add r10, r10, #0x4000
/* IOMUXC GPR DRAM_RESET_BYPASS */
ldr r4, [r10, #0x8]
bic r4, r4, #(0x1 << 27)
str r4, [r10, #0x8]
/* IOMUXC GPR DRAM_CKE_BYPASS */
ldr r4, [r10, #0x8]
bic r4, r4, #(0x1 << 31)
str r4, [r10, #0x8]
.endm
.macro resume_io
/* restore MMDC IO */
cmp r5, #0x0
ldreq r10, [r0, #PM_INFO_MX6Q_IOMUXC_V_OFFSET]
ldrne r10, [r0, #PM_INFO_MX6Q_IOMUXC_P_OFFSET]
ldr r6, [r0, #PM_INFO_MMDC_IO_NUM_OFFSET]
ldr r7, =PM_INFO_MMDC_IO_VAL_OFFSET
add r7, r7, r0
10:
ldr r8, [r7], #0x4
ldr r9, [r7], #0x8
str r9, [r10, r8]
subs r6, r6, #0x1
bne 10b
cmp r5, #0x0
/* Here only MMDC0 is set */
ldreq r11, [r0, #PM_INFO_MX6Q_MMDC0_V_OFFSET]
ldrne r11, [r0, #PM_INFO_MX6Q_MMDC0_P_OFFSET]
ldreq r12, [r0, #PM_INFO_MX6Q_MMDC1_V_OFFSET]
ldrne r12, [r0, #PM_INFO_MX6Q_MMDC1_P_OFFSET]
reset_read_fifo
mmdc_out_and_auto_self_refresh
.endm
.macro resume_mmdc_io
cmp r5, #0x0
ldreq r10, [r0, #PM_INFO_MX6Q_IOMUXC_V_OFFSET]
ldrne r10, [r0, #PM_INFO_MX6Q_IOMUXC_P_OFFSET]
ldreq r11, [r0, #PM_INFO_MX6Q_MMDC0_V_OFFSET]
ldrne r11, [r0, #PM_INFO_MX6Q_MMDC0_P_OFFSET]
/* resume mmdc iomuxc settings */
ldr r6, [r0, #PM_INFO_MMDC_IO_NUM_OFFSET]
ldr r7, =PM_INFO_MMDC_IO_VAL_OFFSET
add r7, r7, r0
11:
ldr r8, [r7], #0x4
ldr r9, [r7], #0x8
str r9, [r10, r8]
subs r6, r6, #0x1
bne 11b
/* check whether we need to restore MMDC */
cmp r5, #0x0
beq 12f
/* check whether last suspend is with M/F mix off */
ldr r9, [r0, #PM_INFO_MX6Q_GPC_P_OFFSET]
ldr r6, [r9, #0x220]
cmp r6, #0x0
bne 13f
12:
resume_iomuxc_gpr
reset_read_fifo
b 17f
13:
/* restore MMDC settings */
ldr r6, [r0, #PM_INFO_MMDC_NUM_OFFSET]
ldr r7, =PM_INFO_MMDC_VAL_OFFSET
add r7, r7, r0
14:
ldr r8, [r7], #0x4
ldr r9, [r7], #0x4
str r9, [r11, r8]
subs r6, r6, #0x1
bne 14b
/* let DDR enter self-refresh */
ldr r7, [r11, #MX6Q_MMDC_MAPSR]
orr r7, r7, #(1 << 20)
str r7, [r11, #MX6Q_MMDC_MAPSR]
15:
ldr r7, [r11, #MX6Q_MMDC_MAPSR]
ands r7, r7, #(1 << 24)
beq 15b
resume_iomuxc_gpr
reset_read_fifo
/* let DDR out of self-refresh */
ldr r7, [r11, #MX6Q_MMDC_MAPSR]
bic r7, r7, #(1 << 20)
str r7, [r11, #MX6Q_MMDC_MAPSR]
16:
ldr r7, [r11, #MX6Q_MMDC_MAPSR]
ands r7, r7, #(1 << 24)
bne 16b
/* kick off MMDC */
ldr r4, =0x0
str r4, [r11, #0x1c]
17:
mmdc_out_and_auto_self_refresh
.endm
.macro store_ttbr1
/* Store TTBR1 to pm_info->ttbr1 */
mrc p15, 0, r7, c2, c0, 1
str r7, [r0, #PM_INFO_MX6Q_TTBR1_V_OFFSET]
/* 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 r6, [r6]
dsb
isb
/* Store the IRAM table in TTBR1 */
mcr p15, 0, r6, 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
/* Disable L1 data cache. */
mrc p15, 0, r6, c1, c0, 0
bic r6, r6, #0x4
mcr p15, 0, r6, c1, c0, 0
dsb
isb
is_cortex_a7
beq 17f
#ifdef CONFIG_CACHE_L2X0
ldr r8, [r0, #PM_INFO_MX6Q_L2_V_OFFSET]
mov r6, #0x0
str r6, [r8, #0x100]
dsb
isb
#endif
17:
.endm
.macro restore_ttbr1
is_cortex_a7
beq 18f
#ifdef CONFIG_CACHE_L2X0
/* Enable L2. */
ldr r8, [r0, #PM_INFO_MX6Q_L2_V_OFFSET]
ldr r7, =0x1
str r7, [r8, #0x100]
#endif
18:
/* Enable L1 data cache. */
mrc p15, 0, r6, c1, c0, 0
orr r6, r6, #0x4
mcr p15, 0, r6, c1, c0, 0
dsb
isb
/* Restore TTBCR */
/* 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 TTBR1, get the origin ttbr1 from pm info */
ldr r7, [r0, #PM_INFO_MX6Q_TTBR1_V_OFFSET]
mcr p15, 0, r7, c2, c0, 1
.endm
ENTRY(imx6_suspend)
ldr r1, [r0, #PM_INFO_PBASE_OFFSET]
ldr r2, [r0, #PM_INFO_RESUME_ADDR_OFFSET]
ldr r3, [r0, #PM_INFO_DDR_TYPE_OFFSET]
ldr r4, [r0, #PM_INFO_PM_INFO_SIZE_OFFSET]
/*
* counting the resume address in iram
* to set it in SRC register.
*/
ldr r6, =imx6_suspend
ldr r7, =resume
sub r7, r7, r6
add r8, r1, r4
add r9, r8, r7
/*
* make sure TLB contain the addr we want,
* as we will access them after MMDC IO floated.
*/
ldr r11, [r0, #PM_INFO_MX6Q_CCM_V_OFFSET]
ldr r6, [r11, #0x0]
ldr r11, [r0, #PM_INFO_MX6Q_GPC_V_OFFSET]
ldr r6, [r11, #0x0]
ldr r11, [r0, #PM_INFO_MX6Q_IOMUXC_V_OFFSET]
ldr r6, [r11, #0x0]
/* use r11 to store the IO address */
ldr r11, [r0, #PM_INFO_MX6Q_SRC_V_OFFSET]
/* store physical resume addr and pm_info address. */
str r9, [r11, #MX6Q_SRC_GPR1]
str r1, [r11, #MX6Q_SRC_GPR2]
/*
* Check if the cpu is Cortex-A7, for Cortex-A7
* the cache implementation is not the same as
* Cortex-A9, so the cache maintenance operation
* is different.
*/
is_cortex_a7
beq a7_dache_flush
/* need to sync L2 cache before DSM. */
sync_l2_cache
b ttbr_store
a7_dache_flush:
disable_l1_cache
ttbr_store:
store_ttbr1
ldr r11, [r0, #PM_INFO_MX6Q_MMDC0_V_OFFSET]
ldr r12, [r0, #PM_INFO_MX6Q_MMDC1_V_OFFSET]
/*
* put DDR explicitly into self-refresh and
* disable automatic power savings.
*/
ldr r7, [r11, #MX6Q_MMDC_MAPSR]
orr r7, r7, #0x1
str r7, [r11, #MX6Q_MMDC_MAPSR]
/* make the DDR explicitly enter self-refresh. */
ldr r7, [r11, #MX6Q_MMDC_MAPSR]
orr r7, r7, #(1 << 21)
str r7, [r11, #MX6Q_MMDC_MAPSR]
poll_dvfs_set:
ldr r7, [r11, #MX6Q_MMDC_MAPSR]
ands r7, r7, #(1 << 25)
beq poll_dvfs_set
/* check if lppdr2 2 channel mode is enabled */
ldr r7, =MX6Q_MMDC_MISC
ldr r6, [r11, r7]
ands r6, r6, #(1 << 2)
beq skip_self_refresh_ch1
ldr r7, [r12, #MX6Q_MMDC_MAPSR]
orr r7, r7, #0x1
str r7, [r12, #MX6Q_MMDC_MAPSR]
ldr r7, [r12, #MX6Q_MMDC_MAPSR]
orr r7, r7, #(1 << 21)
str r7, [r12, #MX6Q_MMDC_MAPSR]
poll_dvfs_set_ch1:
ldr r7, [r12, #MX6Q_MMDC_MAPSR]
ands r7, r7, #(1 << 25)
beq poll_dvfs_set_ch1
skip_self_refresh_ch1:
/* use r11 to store the IO address */
ldr r11, [r0, #PM_INFO_MX6Q_IOMUXC_V_OFFSET]
ldr r6, [r0, #PM_INFO_MMDC_IO_NUM_OFFSET]
ldr r8, =PM_INFO_MMDC_IO_VAL_OFFSET
add r8, r8, r0
set_mmdc_io_lpm:
ldr r7, [r8], #0x8
ldr r9, [r8], #0x4
str r9, [r11, r7]
subs r6, r6, #0x1
bne set_mmdc_io_lpm
/* check whether it supports Mega/Fast off */
ldr r6, [r0, #PM_INFO_MMDC_NUM_OFFSET]
cmp r6, #0x0
beq set_mmdc_lpm_done
/* IOMUXC GPR DRAM_RESET */
add r11, r11, #0x4000
ldr r6, [r11, #0x8]
orr r6, r6, #(0x1 << 28)
str r6, [r11, #0x8]
/* IOMUXC GPR DRAM_RESET_BYPASS */
ldr r6, [r11, #0x8]
orr r6, r6, #(0x1 << 27)
str r6, [r11, #0x8]
/* IOMUXC GPR DRAM_CKE_BYPASS */
ldr r6, [r11, #0x8]
orr r6, r6, #(0x1 << 31)
str r6, [r11, #0x8]
set_mmdc_lpm_done:
/*
* mask all GPC interrupts before
* enabling the RBC counters to
* avoid the counter starting too
* early if an interupt is already
* pending.
*/
ldr r11, [r0, #PM_INFO_MX6Q_GPC_V_OFFSET]
ldr r6, [r11, #MX6Q_GPC_IMR1]
ldr r7, [r11, #MX6Q_GPC_IMR2]
ldr r8, [r11, #MX6Q_GPC_IMR3]
ldr r9, [r11, #MX6Q_GPC_IMR4]
ldr r10, =0xffffffff
str r10, [r11, #MX6Q_GPC_IMR1]
str r10, [r11, #MX6Q_GPC_IMR2]
str r10, [r11, #MX6Q_GPC_IMR3]
str r10, [r11, #MX6Q_GPC_IMR4]
/*
* enable the RBC bypass counter here
* to hold off the interrupts. RBC counter
* = 32 (1ms), Minimum RBC delay should be
* 400us for the analog LDOs to power down.
*/
ldr r11, [r0, #PM_INFO_MX6Q_CCM_V_OFFSET]
ldr r10, [r11, #MX6Q_CCM_CCR]
bic r10, r10, #(0x3f << 21)
orr r10, r10, #(0x20 << 21)
str r10, [r11, #MX6Q_CCM_CCR]
/* enable the counter. */
ldr r10, [r11, #MX6Q_CCM_CCR]
orr r10, r10, #(0x1 << 27)
str r10, [r11, #MX6Q_CCM_CCR]
/* unmask all the GPC interrupts. */
ldr r11, [r0, #PM_INFO_MX6Q_GPC_V_OFFSET]
str r6, [r11, #MX6Q_GPC_IMR1]
str r7, [r11, #MX6Q_GPC_IMR2]
str r8, [r11, #MX6Q_GPC_IMR3]
str r9, [r11, #MX6Q_GPC_IMR4]
/*
* now delay for a short while (3usec)
* ARM is at 1GHz 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 r6, =2000
rbc_loop:
subs r6, r6, #0x1
bne rbc_loop
/*
* ERR005852 Analog: Transition from Deep Sleep Mode to
* LDO Bypass Mode may cause the slow response of the
* VDDARM_CAP output.
*
* Software workaround:
* if internal ldo(VDDARM) bypassed, switch to analog bypass
* mode (0x1E), prio to entering DSM, and then, revert to the
* normal bypass mode, when exiting from DSM.
*/
ldr r11, [r0, #PM_INFO_MX6Q_ANATOP_V_OFFSET]
ldr r10, [r11, #MX6Q_ANATOP_CORE]
and r10, r10, #0x1f
cmp r10, #0x1f
bne ldo_check_done1
ldo_analog_bypass:
ldr r10, [r11, #MX6Q_ANATOP_CORE]
bic r10, r10, #0x1f
orr r10, r10, #0x1e
str r10, [r11, #MX6Q_ANATOP_CORE]
ldo_check_done1:
/* Zzz, enter stop mode */
wfi
nop
nop
nop
nop
/*
* run to here means there is pending
* wakeup source, system should auto
* resume, we need to restore MMDC IO first
*/
/* restore it with 0x1f if use ldo bypass mode.*/
ldr r10, [r11, #MX6Q_ANATOP_CORE]
and r10, r10, #0x1f
cmp r10, #0x1e
bne ldo_check_done2
ldo_bypass_restore:
ldr r10, [r11, #MX6Q_ANATOP_CORE]
orr r10, r10, #0x1f
str r10, [r11, #MX6Q_ANATOP_CORE]
ldo_check_done2:
mov r5, #0x0
/* check whether it supports Mega/Fast off */
ldr r6, [r0, #PM_INFO_MMDC_NUM_OFFSET]
cmp r6, #0x0
beq only_resume_io
resume_mmdc_io
b resume_mmdc_done
only_resume_io:
resume_io
resume_mmdc_done:
restore_ttbr1
/* return to suspend finish */
ARM: convert all "mov.* pc, reg" to "bx reg" for ARMv6+ ARMv6 and greater introduced a new instruction ("bx") which can be used to return from function calls. Recent CPUs perform better when the "bx lr" instruction is used rather than the "mov pc, lr" instruction, and this sequence is strongly recommended to be used by the ARM architecture manual (section A.4.1.1). We provide a new macro "ret" with all its variants for the condition code which will resolve to the appropriate instruction. Rather than doing this piecemeal, and miss some instances, change all the "mov pc" instances to use the new macro, with the exception of the "movs" instruction and the kprobes code. This allows us to detect the "mov pc, lr" case and fix it up - and also gives us the possibility of deploying this for other registers depending on the CPU selection. Reported-by: Will Deacon <will.deacon@arm.com> Tested-by: Stephen Warren <swarren@nvidia.com> # Tegra Jetson TK1 Tested-by: Robert Jarzmik <robert.jarzmik@free.fr> # mioa701_bootresume.S Tested-by: Andrew Lunn <andrew@lunn.ch> # Kirkwood Tested-by: Shawn Guo <shawn.guo@freescale.com> Tested-by: Tony Lindgren <tony@atomide.com> # OMAPs Tested-by: Gregory CLEMENT <gregory.clement@free-electrons.com> # Armada XP, 375, 385 Acked-by: Sekhar Nori <nsekhar@ti.com> # DaVinci Acked-by: Christoffer Dall <christoffer.dall@linaro.org> # kvm/hyp Acked-by: Haojian Zhuang <haojian.zhuang@gmail.com> # PXA3xx Acked-by: Stefano Stabellini <stefano.stabellini@eu.citrix.com> # Xen Tested-by: Uwe Kleine-König <u.kleine-koenig@pengutronix.de> # ARMv7M Tested-by: Simon Horman <horms+renesas@verge.net.au> # Shmobile Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
2014-06-30 09:29:12 -06:00
ret lr
resume:
/* invalidate L1 I-cache first */
mov r6, #0x0
mcr p15, 0, r6, c7, c5, 0
mcr p15, 0, r6, c7, c5, 6
/* enable the Icache and branch prediction */
mov r6, #0x1800
mcr p15, 0, r6, c1, c0, 0
isb
/* restore it with 0x1f if use ldo bypass mode.*/
ldr r11, [r0, #PM_INFO_MX6Q_ANATOP_P_OFFSET]
ldr r7, [r11, #MX6Q_ANATOP_CORE]
and r7, r7, #0x1f
cmp r7, #0x1e
bne ldo_check_done3
ldr r7, [r11, #MX6Q_ANATOP_CORE]
orr r7, r7, #0x1f
str r7, [r11, #MX6Q_ANATOP_CORE]
ldo_check_done3:
/* get physical resume address from pm_info. */
ldr lr, [r0, #PM_INFO_RESUME_ADDR_OFFSET]
/* clear core0's entry and parameter */
ldr r11, [r0, #PM_INFO_MX6Q_SRC_P_OFFSET]
mov r7, #0x0
str r7, [r11, #MX6Q_SRC_GPR1]
str r7, [r11, #MX6Q_SRC_GPR2]
ldr r3, [r0, #PM_INFO_DDR_TYPE_OFFSET]
mov r5, #0x1
/* check whether it supports Mega/Fast off */
ldr r6, [r0, #PM_INFO_MMDC_NUM_OFFSET]
cmp r6, #0x0
beq dsm_only_resume_io
resume_mmdc_io
b dsm_resume_mmdc_done
dsm_only_resume_io:
ldr r3, [r0, #PM_INFO_DDR_TYPE_OFFSET]
resume_io
dsm_resume_mmdc_done:
ARM: convert all "mov.* pc, reg" to "bx reg" for ARMv6+ ARMv6 and greater introduced a new instruction ("bx") which can be used to return from function calls. Recent CPUs perform better when the "bx lr" instruction is used rather than the "mov pc, lr" instruction, and this sequence is strongly recommended to be used by the ARM architecture manual (section A.4.1.1). We provide a new macro "ret" with all its variants for the condition code which will resolve to the appropriate instruction. Rather than doing this piecemeal, and miss some instances, change all the "mov pc" instances to use the new macro, with the exception of the "movs" instruction and the kprobes code. This allows us to detect the "mov pc, lr" case and fix it up - and also gives us the possibility of deploying this for other registers depending on the CPU selection. Reported-by: Will Deacon <will.deacon@arm.com> Tested-by: Stephen Warren <swarren@nvidia.com> # Tegra Jetson TK1 Tested-by: Robert Jarzmik <robert.jarzmik@free.fr> # mioa701_bootresume.S Tested-by: Andrew Lunn <andrew@lunn.ch> # Kirkwood Tested-by: Shawn Guo <shawn.guo@freescale.com> Tested-by: Tony Lindgren <tony@atomide.com> # OMAPs Tested-by: Gregory CLEMENT <gregory.clement@free-electrons.com> # Armada XP, 375, 385 Acked-by: Sekhar Nori <nsekhar@ti.com> # DaVinci Acked-by: Christoffer Dall <christoffer.dall@linaro.org> # kvm/hyp Acked-by: Haojian Zhuang <haojian.zhuang@gmail.com> # PXA3xx Acked-by: Stefano Stabellini <stefano.stabellini@eu.citrix.com> # Xen Tested-by: Uwe Kleine-König <u.kleine-koenig@pengutronix.de> # ARMv7M Tested-by: Simon Horman <horms+renesas@verge.net.au> # Shmobile Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
2014-06-30 09:29:12 -06:00
ret lr
ENDPROC(imx6_suspend)