xref: /arm-trusted-firmware/plat/arm/board/fvp/aarch32/fvp_helpers.S (revision 91f16700b400a8c0651d24a598fc48ee2997a0d7)
1*91f16700Schasinglulu/*
2*91f16700Schasinglulu * Copyright (c) 2016-2017, ARM Limited and Contributors. All rights reserved.
3*91f16700Schasinglulu *
4*91f16700Schasinglulu * SPDX-License-Identifier: BSD-3-Clause
5*91f16700Schasinglulu */
6*91f16700Schasinglulu
7*91f16700Schasinglulu#include <arch.h>
8*91f16700Schasinglulu#include <asm_macros.S>
9*91f16700Schasinglulu#include <drivers/arm/fvp/fvp_pwrc.h>
10*91f16700Schasinglulu#include <platform_def.h>
11*91f16700Schasinglulu
12*91f16700Schasinglulu	.globl	plat_secondary_cold_boot_setup
13*91f16700Schasinglulu	.globl	plat_get_my_entrypoint
14*91f16700Schasinglulu	.globl	plat_is_my_cpu_primary
15*91f16700Schasinglulu	.globl	plat_arm_calc_core_pos
16*91f16700Schasinglulu
17*91f16700Schasinglulu	/* --------------------------------------------------------------------
18*91f16700Schasinglulu	 * void plat_secondary_cold_boot_setup (void);
19*91f16700Schasinglulu	 *
20*91f16700Schasinglulu	 * For AArch32, cold-booting secondary CPUs is not yet
21*91f16700Schasinglulu	 * implemented and they panic.
22*91f16700Schasinglulu	 * --------------------------------------------------------------------
23*91f16700Schasinglulu	 */
24*91f16700Schasinglulufunc plat_secondary_cold_boot_setup
25*91f16700Schasinglulucb_panic:
26*91f16700Schasinglulu	b	cb_panic
27*91f16700Schasingluluendfunc plat_secondary_cold_boot_setup
28*91f16700Schasinglulu
29*91f16700Schasinglulu	/* ---------------------------------------------------------------------
30*91f16700Schasinglulu	 * unsigned long plat_get_my_entrypoint (void);
31*91f16700Schasinglulu	 *
32*91f16700Schasinglulu	 * Main job of this routine is to distinguish between a cold and warm
33*91f16700Schasinglulu	 * boot. On FVP, this information can be queried from the power
34*91f16700Schasinglulu	 * controller. The Power Control SYS Status Register (PSYSR) indicates
35*91f16700Schasinglulu	 * the wake-up reason for the CPU.
36*91f16700Schasinglulu	 *
37*91f16700Schasinglulu	 * For a cold boot, return 0.
38*91f16700Schasinglulu	 * For a warm boot, read the mailbox and return the address it contains.
39*91f16700Schasinglulu	 *
40*91f16700Schasinglulu	 * TODO: PSYSR is a common register and should be
41*91f16700Schasinglulu	 * 	accessed using locks. Since it is not possible
42*91f16700Schasinglulu	 * 	to use locks immediately after a cold reset
43*91f16700Schasinglulu	 * 	we are relying on the fact that after a cold
44*91f16700Schasinglulu	 * 	reset all cpus will read the same WK field
45*91f16700Schasinglulu	 * ---------------------------------------------------------------------
46*91f16700Schasinglulu	 */
47*91f16700Schasinglulufunc plat_get_my_entrypoint
48*91f16700Schasinglulu	/* ---------------------------------------------------------------------
49*91f16700Schasinglulu	 * When bit PSYSR.WK indicates either "Wake by PPONR" or "Wake by GIC
50*91f16700Schasinglulu	 * WakeRequest signal" then it is a warm boot.
51*91f16700Schasinglulu	 * ---------------------------------------------------------------------
52*91f16700Schasinglulu	 */
53*91f16700Schasinglulu	ldcopr	r2, MPIDR
54*91f16700Schasinglulu	ldr	r1, =PWRC_BASE
55*91f16700Schasinglulu	str	r2, [r1, #PSYSR_OFF]
56*91f16700Schasinglulu	ldr	r2, [r1, #PSYSR_OFF]
57*91f16700Schasinglulu	ubfx	r2, r2, #PSYSR_WK_SHIFT, #PSYSR_WK_WIDTH
58*91f16700Schasinglulu	cmp	r2, #WKUP_PPONR
59*91f16700Schasinglulu	beq	warm_reset
60*91f16700Schasinglulu	cmp	r2, #WKUP_GICREQ
61*91f16700Schasinglulu	beq	warm_reset
62*91f16700Schasinglulu
63*91f16700Schasinglulu	/* Cold reset */
64*91f16700Schasinglulu	mov	r0, #0
65*91f16700Schasinglulu	bx	lr
66*91f16700Schasinglulu
67*91f16700Schasingluluwarm_reset:
68*91f16700Schasinglulu	/* ---------------------------------------------------------------------
69*91f16700Schasinglulu	 * A mailbox is maintained in the trusted SRAM. It is flushed out of the
70*91f16700Schasinglulu	 * caches after every update using normal memory so it is safe to read
71*91f16700Schasinglulu	 * it here with SO attributes.
72*91f16700Schasinglulu	 * ---------------------------------------------------------------------
73*91f16700Schasinglulu	 */
74*91f16700Schasinglulu	ldr	r0, =PLAT_ARM_TRUSTED_MAILBOX_BASE
75*91f16700Schasinglulu	ldr	r0, [r0]
76*91f16700Schasinglulu	cmp	r0, #0
77*91f16700Schasinglulu	beq	_panic
78*91f16700Schasinglulu	bx	lr
79*91f16700Schasinglulu
80*91f16700Schasinglulu	/* ---------------------------------------------------------------------
81*91f16700Schasinglulu	 * The power controller indicates this is a warm reset but the mailbox
82*91f16700Schasinglulu	 * is empty. This should never happen!
83*91f16700Schasinglulu	 * ---------------------------------------------------------------------
84*91f16700Schasinglulu	 */
85*91f16700Schasinglulu_panic:
86*91f16700Schasinglulu	b	_panic
87*91f16700Schasingluluendfunc plat_get_my_entrypoint
88*91f16700Schasinglulu
89*91f16700Schasinglulu	/* -----------------------------------------------------
90*91f16700Schasinglulu	 * unsigned int plat_is_my_cpu_primary (void);
91*91f16700Schasinglulu	 *
92*91f16700Schasinglulu	 * Find out whether the current cpu is the primary
93*91f16700Schasinglulu	 * cpu.
94*91f16700Schasinglulu	 * -----------------------------------------------------
95*91f16700Schasinglulu	 */
96*91f16700Schasinglulufunc plat_is_my_cpu_primary
97*91f16700Schasinglulu	ldcopr	r0, MPIDR
98*91f16700Schasinglulu	ldr	r1, =MPIDR_AFFINITY_MASK
99*91f16700Schasinglulu	and	r0, r1
100*91f16700Schasinglulu	cmp	r0, #FVP_PRIMARY_CPU
101*91f16700Schasinglulu	moveq	r0, #1
102*91f16700Schasinglulu	movne	r0, #0
103*91f16700Schasinglulu	bx	lr
104*91f16700Schasingluluendfunc plat_is_my_cpu_primary
105*91f16700Schasinglulu
106*91f16700Schasinglulu	/* ---------------------------------------------------------------------
107*91f16700Schasinglulu	 * unsigned int plat_arm_calc_core_pos(u_register_t mpidr)
108*91f16700Schasinglulu	 *
109*91f16700Schasinglulu	 * Function to calculate the core position on FVP.
110*91f16700Schasinglulu	 *
111*91f16700Schasinglulu	 * (ClusterId * FVP_MAX_CPUS_PER_CLUSTER * FVP_MAX_PE_PER_CPU) +
112*91f16700Schasinglulu	 * (CPUId * FVP_MAX_PE_PER_CPU) +
113*91f16700Schasinglulu	 * ThreadId
114*91f16700Schasinglulu	 *
115*91f16700Schasinglulu	 * which can be simplified as:
116*91f16700Schasinglulu	 *
117*91f16700Schasinglulu	 * ((ClusterId * FVP_MAX_CPUS_PER_CLUSTER + CPUId) * FVP_MAX_PE_PER_CPU)
118*91f16700Schasinglulu	 * + ThreadId
119*91f16700Schasinglulu	 * ---------------------------------------------------------------------
120*91f16700Schasinglulu	 */
121*91f16700Schasinglulufunc plat_arm_calc_core_pos
122*91f16700Schasinglulu	mov	r3, r0
123*91f16700Schasinglulu
124*91f16700Schasinglulu	/*
125*91f16700Schasinglulu	 * Check for MT bit in MPIDR. If not set, shift MPIDR to left to make it
126*91f16700Schasinglulu	 * look as if in a multi-threaded implementation
127*91f16700Schasinglulu	 */
128*91f16700Schasinglulu	tst	r0, #MPIDR_MT_MASK
129*91f16700Schasinglulu	lsleq	r3, r0, #MPIDR_AFFINITY_BITS
130*91f16700Schasinglulu
131*91f16700Schasinglulu	/* Extract individual affinity fields from MPIDR */
132*91f16700Schasinglulu	ubfx	r0, r3, #MPIDR_AFF0_SHIFT, #MPIDR_AFFINITY_BITS
133*91f16700Schasinglulu	ubfx	r1, r3, #MPIDR_AFF1_SHIFT, #MPIDR_AFFINITY_BITS
134*91f16700Schasinglulu	ubfx	r2, r3, #MPIDR_AFF2_SHIFT, #MPIDR_AFFINITY_BITS
135*91f16700Schasinglulu
136*91f16700Schasinglulu	/* Compute linear position */
137*91f16700Schasinglulu	mov	r3, #FVP_MAX_CPUS_PER_CLUSTER
138*91f16700Schasinglulu	mla	r1, r2, r3, r1
139*91f16700Schasinglulu	mov	r3, #FVP_MAX_PE_PER_CPU
140*91f16700Schasinglulu	mla	r0, r1, r3, r0
141*91f16700Schasinglulu
142*91f16700Schasinglulu	bx	lr
143*91f16700Schasingluluendfunc plat_arm_calc_core_pos
144