| /* SPDX-License-Identifier: GPL-2.0+ */ | 
 | /* | 
 |  * Copyright (c) 2013 Samsung Electronics Co., Ltd. | 
 |  *		http://www.samsung.com | 
 |  * | 
 |  * Exynos low-level resume code | 
 |  */ | 
 |  | 
 | #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 | 
 |  | 
 | 	.text | 
 | 	.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] | 
 | 	ldr	r1, [r0, r1] | 
 | 	adr	r0, _cp15_save_diag | 
 | 	ldr	r2, [r0] | 
 | 	ldr	r2, [r0, r2] | 
 | 	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) | 
 |  | 
 | 	.align | 
 | _cp15_save_power: | 
 | 	.long	cp15_save_power - . | 
 | _cp15_save_diag: | 
 | 	.long	cp15_save_diag - . | 
 | #ifdef CONFIG_CACHE_L2X0 | 
 | 1:	.long	l2x0_saved_regs - . | 
 | #endif /* CONFIG_CACHE_L2X0 */ | 
 |  | 
 | 	.data | 
 | 	.align	2 | 
 | 	.globl cp15_save_diag | 
 | cp15_save_diag: | 
 | 	.long	0	@ cp15 diagnostic | 
 | 	.globl cp15_save_power | 
 | cp15_save_power: | 
 | 	.long	0	@ cp15 power control |