summaryrefslogtreecommitdiff
path: root/arch/arm/mach-exynos/sleep.S
blob: 31d25834b9c4b04d5e8a57adf39aa9083c38d027 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
/*
 * 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 */