linux/arch/arm/mach-exynos/sleep.S
Tomasz Figa 30ad527a64 ARM: 8264/1: EXYNOS: Add support for non-secure L2X0 resume
On Exynos SoCs it is necessary to resume operation of L2C early in
assembly code, because otherwise certain systems will crash. This patch
adds necessary code to non-secure resume handler.

[rewrote the code accessing l2x0_saved_regs]

Signed-off-by: Tomasz Figa <t.figa@samsung.com>
Signed-off-by: Marek Szyprowski <m.szyprowski@samsung.com>
Acked-by: Arnd Bergmann <arnd@arndb.de>
Acked-by: Kukjin Kim <kgene.kim@samsung.com>
Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
2015-01-16 14:35:39 +00:00

132 lines
2.9 KiB
ArmAsm

/*
* Copyright (c) 2013 Samsung Electronics Co., Ltd.
* http://www.samsung.com
*
* Exynos low-level resume code
*
* 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>
#include <asm/asm-offsets.h>
#include <asm/hardware/cache-l2x0.h>
#include "smc.h"
#define CPU_MASK 0xff0ffff0
#define CPU_CORTEX_A9 0x410fc090
/*
* The following code is located into the .data section. This is to
* allow l2x0_regs_phys to be accessed with a relative load while we
* can't rely on any MMU translation. We could have put l2x0_regs_phys
* in the .text section as well, but some setups might insist on it to
* be truly read-only. (Reference from: arch/arm/kernel/sleep.S)
*/
.data
.align
/*
* sleep magic, to allow the bootloader to check for an valid
* image to resume to. Must be the first word before the
* exynos_cpu_resume entry.
*/
.word 0x2bedf00d
/*
* exynos_cpu_resume
*
* resume code entry for bootloader to call
*/
ENTRY(exynos_cpu_resume)
#ifdef CONFIG_CACHE_L2X0
mrc p15, 0, r0, c0, c0, 0
ldr r1, =CPU_MASK
and r0, r0, r1
ldr r1, =CPU_CORTEX_A9
cmp r0, r1
bleq l2c310_early_resume
#endif
b cpu_resume
ENDPROC(exynos_cpu_resume)
.align
ENTRY(exynos_cpu_resume_ns)
mrc p15, 0, r0, c0, c0, 0
ldr r1, =CPU_MASK
and r0, r0, r1
ldr r1, =CPU_CORTEX_A9
cmp r0, r1
bne skip_cp15
adr r0, cp15_save_power
ldr r1, [r0]
adr r0, cp15_save_diag
ldr r2, [r0]
mov r0, #SMC_CMD_C15RESUME
dsb
smc #0
#ifdef CONFIG_CACHE_L2X0
adr r0, 1f
ldr r2, [r0]
add r0, r2, r0
/* Check that the address has been initialised. */
ldr r1, [r0, #L2X0_R_PHY_BASE]
teq r1, #0
beq skip_l2x0
/* Check if controller has been enabled. */
ldr r2, [r1, #L2X0_CTRL]
tst r2, #0x1
bne skip_l2x0
ldr r1, [r0, #L2X0_R_TAG_LATENCY]
ldr r2, [r0, #L2X0_R_DATA_LATENCY]
ldr r3, [r0, #L2X0_R_PREFETCH_CTRL]
mov r0, #SMC_CMD_L2X0SETUP1
smc #0
/* Reload saved regs pointer because smc corrupts registers. */
adr r0, 1f
ldr r2, [r0]
add r0, r2, r0
ldr r1, [r0, #L2X0_R_PWR_CTRL]
ldr r2, [r0, #L2X0_R_AUX_CTRL]
mov r0, #SMC_CMD_L2X0SETUP2
smc #0
mov r0, #SMC_CMD_L2X0INVALL
smc #0
mov r1, #1
mov r0, #SMC_CMD_L2X0CTRL
smc #0
skip_l2x0:
#endif /* CONFIG_CACHE_L2X0 */
skip_cp15:
b cpu_resume
ENDPROC(exynos_cpu_resume_ns)
.globl cp15_save_diag
cp15_save_diag:
.long 0 @ cp15 diagnostic
.globl cp15_save_power
cp15_save_power:
.long 0 @ cp15 power control
#ifdef CONFIG_CACHE_L2X0
.align
1: .long l2x0_saved_regs - .
#endif /* CONFIG_CACHE_L2X0 */