fvp_helpers.S 6.29 KB
Newer Older
1
/*
2
 * Copyright (c) 2013-2017, ARM Limited and Contributors. All rights reserved.
3
 *
dp-arm's avatar
dp-arm committed
4
 * SPDX-License-Identifier: BSD-3-Clause
5
6
7
 */

#include <arch.h>
8
#include <asm_macros.S>
9
10
#include <gicv2.h>
#include <gicv3.h>
11
#include <platform_def.h>
12
#include <v2m_def.h>
13
#include "../drivers/pwrc/fvp_pwrc.h"
14
#include "../fvp_def.h"
15

16
	.globl	plat_secondary_cold_boot_setup
17
18
	.globl	plat_get_my_entrypoint
	.globl	plat_is_my_cpu_primary
19
	.globl	plat_arm_calc_core_pos
20

21
	.macro	fvp_choose_gicmmap  param1, param2, x_tmp, w_tmp, res
22
	ldr	\x_tmp, =V2M_SYSREGS_BASE + V2M_SYS_ID
23
	ldr	\w_tmp, [\x_tmp]
24
	ubfx	\w_tmp, \w_tmp, #V2M_SYS_ID_BLD_SHIFT, #V2M_SYS_ID_BLD_LENGTH
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
	cmp	\w_tmp, #BLD_GIC_VE_MMAP
	csel	\res, \param1, \param2, eq
	.endm

	/* -----------------------------------------------------
	 * void plat_secondary_cold_boot_setup (void);
	 *
	 * This function performs any platform specific actions
	 * needed for a secondary cpu after a cold reset e.g
	 * mark the cpu's presence, mechanism to place it in a
	 * holding pen etc.
	 * TODO: Should we read the PSYS register to make sure
	 * that the request has gone through.
	 * -----------------------------------------------------
	 */
func plat_secondary_cold_boot_setup
41
#ifndef EL3_PAYLOAD_BASE
42
43
44
45
46
47
48
49
50
51
52
53
54
	/* ---------------------------------------------
	 * Power down this cpu.
	 * TODO: Do we need to worry about powering the
	 * cluster down as well here. That will need
	 * locks which we won't have unless an elf-
	 * loader zeroes out the zi section.
	 * ---------------------------------------------
	 */
	mrs	x0, mpidr_el1
	ldr	x1, =PWRC_BASE
	str	w0, [x1, #PPOFFR_OFF]

	/* ---------------------------------------------
55
	 * Disable GIC bypass as well
56
57
	 * ---------------------------------------------
	 */
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
	/* Check for GICv3 system register access */
	mrs	x0, id_aa64pfr0_el1
	ubfx	x0, x0, #ID_AA64PFR0_GIC_SHIFT, #ID_AA64PFR0_GIC_WIDTH
	cmp	x0, #1
	b.ne	gicv2_bypass_disable

	/* Check for SRE enable */
	mrs	x1, ICC_SRE_EL3
	tst	x1, #ICC_SRE_SRE_BIT
	b.eq	gicv2_bypass_disable

	mrs	x2, ICC_SRE_EL3
	orr	x2, x2, #(ICC_SRE_DIB_BIT | ICC_SRE_DFB_BIT)
	msr	ICC_SRE_EL3, x2
	b	secondary_cold_boot_wait

gicv2_bypass_disable:
75
76
	ldr	x0, =VE_GICC_BASE
	ldr	x1, =BASE_GICC_BASE
77
	fvp_choose_gicmmap	x0, x1, x2, w2, x1
78
79
80
81
	mov	w0, #(IRQ_BYP_DIS_GRP1 | FIQ_BYP_DIS_GRP1)
	orr	w0, w0, #(IRQ_BYP_DIS_GRP0 | FIQ_BYP_DIS_GRP0)
	str	w0, [x1, #GICC_CTLR]

82
secondary_cold_boot_wait:
83
84
85
86
87
88
89
90
	/* ---------------------------------------------
	 * There is no sane reason to come out of this
	 * wfi so panic if we do. This cpu will be pow-
	 * ered on and reset by the cpu_on pm api
	 * ---------------------------------------------
	 */
	dsb	sy
	wfi
91
	no_ret	plat_panic_handler
92
93
94
95
96
97
98
99
100
101
102
103
#else
	mov_imm	x0, PLAT_ARM_TRUSTED_MAILBOX_BASE

	/* Wait until the entrypoint gets populated */
poll_mailbox:
	ldr	x1, [x0]
	cbz	x1, 1f
	br	x1
1:
	wfe
	b	poll_mailbox
#endif /* EL3_PAYLOAD_BASE */
104
endfunc plat_secondary_cold_boot_setup
105

106
	/* ---------------------------------------------------------------------
107
	 * uintptr_t plat_get_my_entrypoint (void);
108
	 *
109
110
111
112
113
114
115
	 * Main job of this routine is to distinguish between a cold and warm
	 * boot. On FVP, this information can be queried from the power
	 * controller. The Power Control SYS Status Register (PSYSR) indicates
	 * the wake-up reason for the CPU.
	 *
	 * For a cold boot, return 0.
	 * For a warm boot, read the mailbox and return the address it contains.
116
117
	 *
	 * TODO: PSYSR is a common register and should be
118
	 * 	accessed using locks. Since it is not possible
119
120
121
	 * 	to use locks immediately after a cold reset
	 * 	we are relying on the fact that after a cold
	 * 	reset all cpus will read the same WK field
122
	 * ---------------------------------------------------------------------
123
	 */
124
func plat_get_my_entrypoint
125
126
127
128
129
	/* ---------------------------------------------------------------------
	 * When bit PSYSR.WK indicates either "Wake by PPONR" or "Wake by GIC
	 * WakeRequest signal" then it is a warm boot.
	 * ---------------------------------------------------------------------
	 */
130
	mrs	x2, mpidr_el1
131
132
133
	ldr	x1, =PWRC_BASE
	str	w2, [x1, #PSYSR_OFF]
	ldr	w2, [x1, #PSYSR_OFF]
134
	ubfx	w2, w2, #PSYSR_WK_SHIFT, #PSYSR_WK_WIDTH
135
136
137
138
	cmp	w2, #WKUP_PPONR
	beq	warm_reset
	cmp	w2, #WKUP_GICREQ
	beq	warm_reset
139
140

	/* Cold reset */
141
	mov	x0, #0
142
143
	ret

144
warm_reset:
145
146
147
148
149
	/* ---------------------------------------------------------------------
	 * A mailbox is maintained in the trusted SRAM. It is flushed out of the
	 * caches after every update using normal memory so it is safe to read
	 * it here with SO attributes.
	 * ---------------------------------------------------------------------
150
	 */
151
	mov_imm	x0, PLAT_ARM_TRUSTED_MAILBOX_BASE
152
	ldr	x0, [x0]
153
	cbz	x0, _panic_handler
154
155
156
157
158
159
160
	ret

	/* ---------------------------------------------------------------------
	 * The power controller indicates this is a warm reset but the mailbox
	 * is empty. This should never happen!
	 * ---------------------------------------------------------------------
	 */
161
_panic_handler:
162
	no_ret	plat_panic_handler
163
endfunc plat_get_my_entrypoint
164

165
166
167
168
169
170
171
	/* -----------------------------------------------------
	 * unsigned int plat_is_my_cpu_primary (void);
	 *
	 * Find out whether the current cpu is the primary
	 * cpu.
	 * -----------------------------------------------------
	 */
172
173
func plat_is_my_cpu_primary
	mrs	x0, mpidr_el1
174
175
	ldr	x1, =MPIDR_AFFINITY_MASK
	and	x0, x0, x1
176
	cmp	x0, #FVP_PRIMARY_CPU
177
	cset	w0, eq
178
	ret
179
endfunc plat_is_my_cpu_primary
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213

	/* -----------------------------------------------------
	 * unsigned int plat_arm_calc_core_pos(u_register_t mpidr)
	 *
	 * Function to calculate the core position on FVP.
	 *
	 * (ClusterId * FVP_MAX_CPUS_PER_CLUSTER) +
	 * (CPUId * FVP_MAX_PE_PER_CPU) +
	 * ThreadId
	 * -----------------------------------------------------
	 */
func plat_arm_calc_core_pos
	mov	x3, x0

	/*
	 * Check for MT bit in MPIDR. If not set, shift MPIDR to left to make it
	 * look as if in a multi-threaded implementation.
	 */
	tst	x0, #MPIDR_MT_MASK
	lsl	x3, x0, #MPIDR_AFFINITY_BITS
	csel	x3, x3, x0, eq

	/* Extract individual affinity fields from MPIDR */
	ubfx	x0, x3, #MPIDR_AFF0_SHIFT, #MPIDR_AFFINITY_BITS
	ubfx	x1, x3, #MPIDR_AFF1_SHIFT, #MPIDR_AFFINITY_BITS
	ubfx	x2, x3, #MPIDR_AFF2_SHIFT, #MPIDR_AFFINITY_BITS

	/* Compute linear position */
	mov	x4, #FVP_MAX_PE_PER_CPU
	madd	x0, x1, x4, x0
	mov	x5, #FVP_MAX_CPUS_PER_CLUSTER
	madd	x0, x2, x5, x0
	ret
endfunc plat_arm_calc_core_pos