xref: /rk3399_ARM-atf/plat/nvidia/tegra/common/aarch64/tegra_helpers.S (revision 665e71b8ea28162ec7737c1411bca3ea89e5957e)
1/*
2 * Copyright (c) 2015-2019, ARM Limited and Contributors. All rights reserved.
3 * Copyright (c) 2020, NVIDIA Corporation. All rights reserved.
4 *
5 * SPDX-License-Identifier: BSD-3-Clause
6 */
7#include <arch.h>
8#include <asm_macros.S>
9#include <assert_macros.S>
10#include <cpu_macros.S>
11#include <cortex_a53.h>
12#include <cortex_a57.h>
13#include <platform_def.h>
14#include <tegra_def.h>
15#include <tegra_platform.h>
16
17#define MIDR_PN_CORTEX_A57		0xD07
18
19/*******************************************************************************
20 * Implementation defined ACTLR_EL3 bit definitions
21 ******************************************************************************/
22#define ACTLR_ELx_L2ACTLR_BIT		(U(1) << 6)
23#define ACTLR_ELx_L2ECTLR_BIT		(U(1) << 5)
24#define ACTLR_ELx_L2CTLR_BIT		(U(1) << 4)
25#define ACTLR_ELx_CPUECTLR_BIT		(U(1) << 1)
26#define ACTLR_ELx_CPUACTLR_BIT		(U(1) << 0)
27#define ACTLR_ELx_ENABLE_ALL_ACCESS	(ACTLR_ELx_L2ACTLR_BIT | \
28					 ACTLR_ELx_L2ECTLR_BIT | \
29					 ACTLR_ELx_L2CTLR_BIT | \
30					 ACTLR_ELx_CPUECTLR_BIT | \
31					 ACTLR_ELx_CPUACTLR_BIT)
32
33	/* Global functions */
34	.globl	plat_is_my_cpu_primary
35	.globl	plat_my_core_pos
36	.globl	plat_get_my_entrypoint
37	.globl	plat_secondary_cold_boot_setup
38	.globl	platform_mem_init
39	.globl	plat_crash_console_init
40	.globl	plat_crash_console_putc
41	.globl	plat_crash_console_flush
42	.globl	tegra_secure_entrypoint
43	.globl	plat_reset_handler
44
45	/* Global variables */
46	.globl	tegra_sec_entry_point
47	.globl	ns_image_entrypoint
48	.globl	tegra_bl31_phys_base
49	.globl	tegra_console_base
50
51	/* ---------------------
52	 * Common CPU init code
53	 * ---------------------
54	 */
55.macro	cpu_init_common
56
57	/* ------------------------------------------------
58	 * We enable procesor retention, L2/CPUECTLR NS
59	 * access and ECC/Parity protection for A57 CPUs
60	 * ------------------------------------------------
61	 */
62	mrs	x0, midr_el1
63	mov	x1, #(MIDR_PN_MASK << MIDR_PN_SHIFT)
64	and	x0, x0, x1
65	lsr	x0, x0, #MIDR_PN_SHIFT
66	cmp	x0, #MIDR_PN_CORTEX_A57
67	b.ne	1f
68
69	/* ---------------------------
70	 * Enable processor retention
71	 * ---------------------------
72	 */
73	mrs	x0, CORTEX_A57_L2ECTLR_EL1
74	mov	x1, #RETENTION_ENTRY_TICKS_512
75	bic	x0, x0, #CORTEX_A57_L2ECTLR_RET_CTRL_MASK
76	orr	x0, x0, x1
77	msr	CORTEX_A57_L2ECTLR_EL1, x0
78	isb
79
80	mrs	x0, CORTEX_A57_ECTLR_EL1
81	mov	x1, #RETENTION_ENTRY_TICKS_512
82	bic	x0, x0, #CORTEX_A57_ECTLR_CPU_RET_CTRL_MASK
83	orr	x0, x0, x1
84	msr	CORTEX_A57_ECTLR_EL1, x0
85	isb
86
87	/* -------------------------------------------------------
88	 * Enable L2 and CPU ECTLR RW access from non-secure world
89	 * -------------------------------------------------------
90	 */
91	mrs	x0, actlr_el3
92	mov	x1, #ACTLR_ELx_ENABLE_ALL_ACCESS
93	orr	x0, x0, x1
94	msr	actlr_el3, x0
95	mrs	x0, actlr_el2
96	mov	x1, #ACTLR_ELx_ENABLE_ALL_ACCESS
97	orr	x0, x0, x1
98	msr	actlr_el2, x0
99	isb
100
101	/* --------------------------------
102	 * Enable the cycle count register
103	 * --------------------------------
104	 */
1051:	mrs	x0, pmcr_el0
106	ubfx	x0, x0, #11, #5		// read PMCR.N field
107	mov	x1, #1
108	lsl	x0, x1, x0
109	sub	x0, x0, #1		// mask of event counters
110	orr	x0, x0, #0x80000000	// disable overflow intrs
111	msr	pmintenclr_el1, x0
112	msr	pmuserenr_el0, x1	// enable user mode access
113
114	/* ----------------------------------------------------------------
115	 * Allow non-privileged access to CNTVCT: Set CNTKCTL (Kernel Count
116	 * register), bit 1 (EL0VCTEN) to enable access to CNTVCT/CNTFRQ
117	 * registers from EL0.
118	 * ----------------------------------------------------------------
119	 */
120	mrs	x0, cntkctl_el1
121	orr	x0, x0, #EL0VCTEN_BIT
122	msr	cntkctl_el1, x0
123.endm
124
125	/* -----------------------------------------------------
126	 * unsigned int plat_is_my_cpu_primary(void);
127	 *
128	 * This function checks if this is the Primary CPU
129	 * -----------------------------------------------------
130	 */
131func plat_is_my_cpu_primary
132	mrs	x0, mpidr_el1
133	and	x0, x0, #(MPIDR_CLUSTER_MASK | MPIDR_CPU_MASK)
134	cmp	x0, #TEGRA_PRIMARY_CPU
135	cset	x0, eq
136	ret
137endfunc plat_is_my_cpu_primary
138
139	/* ----------------------------------------------------------
140	 * unsigned int plat_my_core_pos(void);
141	 *
142	 * result: CorePos = CoreId + (ClusterId * cpus per cluster)
143	 * ----------------------------------------------------------
144	 */
145func plat_my_core_pos
146	mrs	x0, mpidr_el1
147	and	x1, x0, #MPIDR_CPU_MASK
148	and	x0, x0, #MPIDR_CLUSTER_MASK
149	lsr	x0, x0, #MPIDR_AFFINITY_BITS
150	mov	x2, #PLATFORM_MAX_CPUS_PER_CLUSTER
151	mul	x0, x0, x2
152	add	x0, x1, x0
153	ret
154endfunc plat_my_core_pos
155
156	/* -----------------------------------------------------
157	 * unsigned long plat_get_my_entrypoint (void);
158	 *
159	 * Main job of this routine is to distinguish between
160	 * a cold and warm boot. If the tegra_sec_entry_point for
161	 * this CPU is present, then it's a warm boot.
162	 *
163	 * -----------------------------------------------------
164	 */
165func plat_get_my_entrypoint
166	adr	x1, tegra_sec_entry_point
167	ldr	x0, [x1]
168	ret
169endfunc plat_get_my_entrypoint
170
171	/* -----------------------------------------------------
172	 * int platform_get_core_pos(int mpidr);
173	 *
174	 * result: CorePos = (ClusterId * cpus per cluster) +
175	 *                   CoreId
176	 * -----------------------------------------------------
177	 */
178func platform_get_core_pos
179	and	x1, x0, #MPIDR_CPU_MASK
180	and	x0, x0, #MPIDR_CLUSTER_MASK
181	lsr	x0, x0, #MPIDR_AFFINITY_BITS
182	mov	x2, #PLATFORM_MAX_CPUS_PER_CLUSTER
183	mul	x0, x0, x2
184	add	x0, x1, x0
185	ret
186endfunc platform_get_core_pos
187
188	/* -----------------------------------------------------
189	 * void plat_secondary_cold_boot_setup (void);
190	 *
191	 * This function performs any platform specific actions
192	 * needed for a secondary cpu after a cold reset. Right
193	 * now this is a stub function.
194	 * -----------------------------------------------------
195	 */
196func plat_secondary_cold_boot_setup
197	mov	x0, #0
198	ret
199endfunc plat_secondary_cold_boot_setup
200
201	/* --------------------------------------------------------
202	 * void platform_mem_init (void);
203	 *
204	 * Any memory init, relocation to be done before the
205	 * platform boots. Called very early in the boot process.
206	 * --------------------------------------------------------
207	 */
208func platform_mem_init
209	mov	x0, #0
210	ret
211endfunc platform_mem_init
212
213	/* ---------------------------------------------------
214	 * Function to handle a platform reset and store
215	 * input parameters passed by BL2.
216	 * ---------------------------------------------------
217	 */
218func plat_reset_handler
219
220	/* ----------------------------------------------------
221	 * Verify if we are running from BL31_BASE address
222	 * ----------------------------------------------------
223	 */
224	adr	x18, bl31_entrypoint
225	mov	x17, #BL31_BASE
226	cmp	x18, x17
227	b.eq	1f
228
229	/* ----------------------------------------------------
230	 * Copy the entire BL31 code to BL31_BASE if we are not
231	 * running from it already
232	 * ----------------------------------------------------
233	 */
234	mov	x0, x17
235	mov	x1, x18
236	mov	x2, #BL31_SIZE
237_loop16:
238	cmp	x2, #16
239	b.lo	_loop1
240	ldp	x3, x4, [x1], #16
241	stp	x3, x4, [x0], #16
242	sub	x2, x2, #16
243	b	_loop16
244	/* copy byte per byte */
245_loop1:
246	cbz	x2, _end
247	ldrb	w3, [x1], #1
248	strb	w3, [x0], #1
249	subs	x2, x2, #1
250	b.ne	_loop1
251
252	/* ----------------------------------------------------
253	 * Jump to BL31_BASE and start execution again
254	 * ----------------------------------------------------
255	 */
256_end:	mov	x0, x20
257	mov	x1, x21
258	br	x17
2591:
260
261	/* -----------------------------------
262	 * derive and save the phys_base addr
263	 * -----------------------------------
264	 */
265	adr	x17, tegra_bl31_phys_base
266	ldr	x18, [x17]
267	cbnz	x18, 1f
268	adr	x18, bl31_entrypoint
269	str	x18, [x17]
270
2711:	cpu_init_common
272
273	ret
274endfunc plat_reset_handler
275
276	/* ----------------------------------------
277	 * Secure entrypoint function for CPU boot
278	 * ----------------------------------------
279	 */
280func tegra_secure_entrypoint _align=6
281
282#if ERRATA_TEGRA_INVALIDATE_BTB_AT_BOOT
283
284	/* --------------------------------------------------------
285	 * Skip the invalidate BTB workaround for Tegra210B01 SKUs.
286	 * --------------------------------------------------------
287	 */
288	mov	x0, #TEGRA_MISC_BASE
289	add	x0, x0, #HARDWARE_REVISION_OFFSET
290	ldr	w1, [x0]
291	lsr	w1, w1, #CHIP_ID_SHIFT
292	and	w1, w1, #CHIP_ID_MASK
293	cmp	w1, #TEGRA_CHIPID_TEGRA21	/* T210? */
294	b.ne	2f
295	ldr	w1, [x0]
296	lsr	w1, w1, #MAJOR_VERSION_SHIFT
297	and	w1, w1, #MAJOR_VERSION_MASK
298	cmp	w1, #0x02			/* T210 B01? */
299	b.eq	2f
300
301	/* -------------------------------------------------------
302	 * Invalidate BTB along with I$ to remove any stale
303	 * entries from the branch predictor array.
304	 * -------------------------------------------------------
305	 */
306	mrs	x0, CORTEX_A57_CPUACTLR_EL1
307	orr	x0, x0, #1
308	msr	CORTEX_A57_CPUACTLR_EL1, x0	/* invalidate BTB and I$ together */
309	dsb	sy
310	isb
311	ic	iallu			/* actual invalidate */
312	dsb	sy
313	isb
314
315	mrs	x0, CORTEX_A57_CPUACTLR_EL1
316	bic	x0, x0, #1
317	msr	CORTEX_A57_CPUACTLR_EL1, X0	/* restore original CPUACTLR_EL1 */
318	dsb	sy
319	isb
320
321	.rept	7
322	nop				/* wait */
323	.endr
324
325	/* -----------------------------------------------
326	 * Extract OSLK bit and check if it is '1'. This
327	 * bit remains '0' for A53 on warm-resets. If '1',
328	 * turn off regional clock gating and request warm
329	 * reset.
330	 * -----------------------------------------------
331	 */
332	mrs	x0, oslsr_el1
333	and	x0, x0, #2
334	mrs	x1, mpidr_el1
335	bics	xzr, x0, x1, lsr #7	/* 0 = slow cluster or warm reset */
336	b.eq	restore_oslock
337	mov	x0, xzr
338	msr	oslar_el1, x0		/* os lock stays 0 across warm reset */
339	mov	x3, #3
340	movz	x4, #0x8000, lsl #48
341	msr	CORTEX_A57_CPUACTLR_EL1, x4	/* turn off RCG */
342	isb
343	msr	rmr_el3, x3		/* request warm reset */
344	isb
345	dsb	sy
3461:	wfi
347	b	1b
348
349	/* --------------------------------------------------
350	 * These nops are here so that speculative execution
351	 * won't harm us before we are done with warm reset.
352	 * --------------------------------------------------
353	 */
354	.rept	65
355	nop
356	.endr
3572:
358	/* --------------------------------------------------
359	 * Do not insert instructions here
360	 * --------------------------------------------------
361	 */
362#endif
363
364	/* --------------------------------------------------
365	 * Restore OS Lock bit
366	 * --------------------------------------------------
367	 */
368restore_oslock:
369	mov	x0, #1
370	msr	oslar_el1, x0
371
372	/* --------------------------------------------------
373	 * Get secure world's entry point and jump to it
374	 * --------------------------------------------------
375	 */
376	bl	plat_get_my_entrypoint
377	br	x0
378endfunc tegra_secure_entrypoint
379
380	.data
381	.align 3
382
383	/* --------------------------------------------------
384	 * CPU Secure entry point - resume from suspend
385	 * --------------------------------------------------
386	 */
387tegra_sec_entry_point:
388	.quad	0
389
390	/* --------------------------------------------------
391	 * NS world's cold boot entry point
392	 * --------------------------------------------------
393	 */
394ns_image_entrypoint:
395	.quad	0
396
397	/* --------------------------------------------------
398	 * BL31's physical base address
399	 * --------------------------------------------------
400	 */
401tegra_bl31_phys_base:
402	.quad	0
403
404	/* --------------------------------------------------
405	 * UART controller base for console init
406	 * --------------------------------------------------
407	 */
408tegra_console_base:
409	.quad	0
410