blob: f7a04d8bc5102aee0706c37283971ba5d488dbd2 [file] [log] [blame]
laurenw-arm7c7b1982020-10-21 13:34:40 -05001/*
2 * Copyright (c) 2021, ARM Limited and Contributors. All rights reserved.
3 *
4 * SPDX-License-Identifier: BSD-3-Clause
5 */
6
7#include <arch.h>
8#include <asm_macros.S>
9#include <drivers/arm/fvp/fvp_pwrc.h>
10#include <drivers/arm/gicv2.h>
11#include <drivers/arm/gicv3.h>
12
13#include <platform_def.h>
14
15
16 .globl plat_secondary_cold_boot_setup
17 .globl plat_get_my_entrypoint
18 .globl plat_is_my_cpu_primary
19 .globl plat_arm_calc_core_pos
20
21 /* -----------------------------------------------------
22 * void plat_secondary_cold_boot_setup (void);
23 *
24 * This function performs any platform specific actions
25 * needed for a secondary cpu after a cold reset e.g
26 * mark the cpu's presence, mechanism to place it in a
27 * holding pen etc.
28 * TODO: Should we read the PSYS register to make sure
29 * that the request has gone through.
30 * -----------------------------------------------------
31 */
32func plat_secondary_cold_boot_setup
33 /* ---------------------------------------------
34 * Power down this cpu.
35 * TODO: Do we need to worry about powering the
36 * cluster down as well here? That will need
37 * locks which we won't have unless an elf-
38 * loader zeroes out the zi section.
39 * ---------------------------------------------
40 */
41 mrs x0, mpidr_el1
42 mov_imm x1, PWRC_BASE
43 str w0, [x1, #PPOFFR_OFF]
44
45 /* ---------------------------------------------
46 * There is no sane reason to come out of this
47 * wfi so panic if we do. This cpu will be pow-
48 * ered on and reset by the cpu_on pm api
49 * ---------------------------------------------
50 */
51 dsb sy
52 wfi
53 no_ret plat_panic_handler
54endfunc plat_secondary_cold_boot_setup
55
56 /* ---------------------------------------------------------------------
57 * uintptr_t plat_get_my_entrypoint (void);
58 *
59 * Main job of this routine is to distinguish between a cold and warm
60 * boot. On FVP_R, this information can be queried from the power
61 * controller. The Power Control SYS Status Register (PSYSR) indicates
62 * the wake-up reason for the CPU.
63 *
64 * For a cold boot, return 0.
65 * For a warm boot, read the mailbox and return the address it contains.
66 *
67 * TODO: PSYSR is a common register and should be
68 * accessed using locks. Since it is not possible
69 * to use locks immediately after a cold reset
70 * we are relying on the fact that after a cold
71 * reset all cpus will read the same WK field
72 * ---------------------------------------------------------------------
73 */
74func plat_get_my_entrypoint
75 /* ---------------------------------------------------------------------
76 * When bit PSYSR.WK indicates either "Wake by PPONR" or "Wake by GIC
77 * WakeRequest signal" then it is a warm boot.
78 * ---------------------------------------------------------------------
79 */
80 mrs x2, mpidr_el1
81 mov_imm x1, PWRC_BASE
82 str w2, [x1, #PSYSR_OFF]
83 ldr w2, [x1, #PSYSR_OFF]
84 ubfx w2, w2, #PSYSR_WK_SHIFT, #PSYSR_WK_WIDTH
85 cmp w2, #WKUP_PPONR
86 beq warm_reset
87 cmp w2, #WKUP_GICREQ
88 beq warm_reset
89
90 /* Cold reset */
91 mov x0, #0
92 ret
93
94warm_reset:
95 /* ---------------------------------------------------------------------
96 * A mailbox is maintained in the trusted SRAM. It is flushed out of the
97 * caches after every update using normal memory so it is safe to read
98 * it here with SO attributes.
99 * ---------------------------------------------------------------------
100 */
101 mov_imm x0, PLAT_ARM_TRUSTED_MAILBOX_BASE
102 ldr x0, [x0]
103 cbz x0, _panic_handler
104 ret
105
106 /* ---------------------------------------------------------------------
107 * The power controller indicates this is a warm reset but the mailbox
108 * is empty. This should never happen!
109 * ---------------------------------------------------------------------
110 */
111_panic_handler:
112 no_ret plat_panic_handler
113endfunc plat_get_my_entrypoint
114
115 /* -----------------------------------------------------
116 * unsigned int plat_is_my_cpu_primary (void);
117 *
118 * Find out whether the current cpu is the primary
119 * cpu.
120 * -----------------------------------------------------
121 */
122func plat_is_my_cpu_primary
123 mrs x0, mpidr_el1
124 mov_imm x1, MPIDR_AFFINITY_MASK
125 and x0, x0, x1
126 cmp x0, #FVP_R_PRIMARY_CPU
127 cset w0, eq
128 ret
129endfunc plat_is_my_cpu_primary
130
131 /* ---------------------------------------------------------------------
132 * unsigned int plat_arm_calc_core_pos(u_register_t mpidr)
133 *
134 * Function to calculate the core position on FVP_R.
135 *
136 * (ClusterId * FVP_R_MAX_CPUS_PER_CLUSTER * FVP_R_MAX_PE_PER_CPU) +
137 * (CPUId * FVP_R_MAX_PE_PER_CPU) +
138 * ThreadId
139 *
140 * which can be simplified as:
141 *
142 * ((ClusterId * FVP_R_MAX_CPUS_PER_CLUSTER + CPUId) * FVP_R_MAX_PE_PER_CPU)
143 * + ThreadId
144 * ---------------------------------------------------------------------
145 */
146func plat_arm_calc_core_pos
147 /*
148 * Check for MT bit in MPIDR. If not set, shift MPIDR to left to make it
149 * look as if in a multi-threaded implementation.
150 */
151 tst x0, #MPIDR_MT_MASK
152 lsl x3, x0, #MPIDR_AFFINITY_BITS
153 csel x3, x3, x0, eq
154
155 /* Extract individual affinity fields from MPIDR */
156 ubfx x0, x3, #MPIDR_AFF0_SHIFT, #MPIDR_AFFINITY_BITS
157 ubfx x1, x3, #MPIDR_AFF1_SHIFT, #MPIDR_AFFINITY_BITS
158 ubfx x2, x3, #MPIDR_AFF2_SHIFT, #MPIDR_AFFINITY_BITS
159
160 /* Compute linear position */
161 mov x4, #FVP_R_MAX_CPUS_PER_CLUSTER
162 madd x1, x2, x4, x1
163 mov x5, #FVP_R_MAX_PE_PER_CPU
164 madd x0, x1, x5, x0
165 ret
166endfunc plat_arm_calc_core_pos