xref: /aosp_15_r20/external/coreboot/src/soc/samsung/exynos5420/smp.c (revision b9411a12aaaa7e1e6a6fb7c5e057f44ee179a49c)
1 /* SPDX-License-Identifier: GPL-2.0-only */
2 
3 #include <arch/cpu.h>
4 #include <device/mmio.h>
5 #include <soc/cpu.h>
6 #include <soc/power.h>
7 #include <string.h>
8 #include <types.h>
9 
10 /* ACTLR, L2CTLR L2ACTLR constants used in SMP core power up. */
11 
12 #define ACTLR_SMP					(1 << 6)
13 
14 #define L2CTLR_ECC_PARITY				(1 << 21)
15 #define L2CTLR_DATA_RAM_LATENCY_MASK			(7 << 0)
16 #define L2CTLR_TAG_RAM_LATENCY_MASK			(7 << 6)
17 #define L2CTLR_DATA_RAM_LATENCY_CYCLES_3		(2 << 0)
18 #define L2CTLR_TAG_RAM_LATENCY_CYCLES_3			(2 << 6)
19 
20 #define L2ACTLR_DISABLE_CLEAN_EVICT_PUSH_EXTERNAL	(1 << 3)
21 #define L2ACTLR_ENABLE_HAZARD_DETECT_TIMEOUT		(1 << 7)
22 #define L2ACTLR_FORCE_L2_LOGIC_CLOCK_ENABLE_ACTIVE	(1 << 27)
23 
24 /* Part number in CPU ID (MPIDR). */
25 #define PART_NUMBER_CORTEX_A15				(0xc0f)
26 
27 /* State of CPU cores in Exynos 5420. */
28 #define CORE_STATE_RESET				(1 << 0)
29 #define CORE_STATE_SECONDARY_RESET			(1 << 1)
30 #define CORE_STATE_SWITCH_CLUSTER			(1 << 4)
31 
32 /* The default address to re-power on a code. */
33 #define CORE_RESET_INIT_ADDRESS				((void *)0x00000000)
34 
35 /* Vectors in BL1 (0x02020000 = base of iRAM). */
36 #define VECTOR_CORE_SEV_HANDLER			((void *)(intptr_t)0x02020004)
37 #define VECTOR_LOW_POWER_FLAG			((void *)(intptr_t)0x02020028)
38 #define VECTOR_LOW_POWER_ADDRESS		((void *)(intptr_t)0x0202002C)
39 
40 /* The data structure for the "CPU state" memory page (shared with kernel)
41  * controlling cores in active cluster. Kernel will put starting address for one
42  * core in "hotplug_address" before power on. Note the address is hard-coded in
43  * kernel (EXYNOS5420_PA_SYSRAM_NS = 0x02073000). */
44 volatile struct exynos5420_cpu_states
45 {
46 	uint32_t _reserved[2];		/* RESV, +0x00 */
47 	uint32_t resume_address;	/* REG0, +0x08 */
48 	uint32_t resume_flag;		/* REG1, +0x0C */
49 	uint32_t _reg2;			/* REG2, +0x10 */
50 	uint32_t _reg3;			/* REG3, +0x14 */
51 	uint32_t switch_address;	/* REG4, +0x18, cluster switching */
52 	uint32_t hotplug_address;	/* REG5, +0x1C, core hotplug */
53 	uint32_t _reg6;			/* REG6, +0x20 */
54 	uint32_t c2_address;		/* REG7, +0x24, C2 state change */
55 
56 	/* Managed per core status for active cluster, offset: +0x28~0x38 */
57 	uint32_t cpu_states[4];
58 
59 	/* Managed per core GIC status for active cluster, offset: 0x38~0x48 */
60 	uint32_t cpu_gic_states[4];
61 } *exynos_cpu_states = (volatile struct exynos5420_cpu_states*)0x02073000;
62 
63 /* When leaving core handlers and jump to hot-plug address (or cluster
64  * switching), we are not sure if the destination is Thumb or ARM mode.
65  * So a BX command is required.
66  */
jump_bx(void * address)67 static inline void jump_bx(void *address)
68 {
69 	asm volatile ("bx %0" : : "r"(address));
70 	/* never returns. */
71 }
72 
73 /* Extracts arbitrary bits from a 32-bit unsigned int. */
get_bits(uint32_t value,uint32_t start,uint32_t len)74 static inline uint32_t get_bits(uint32_t value, uint32_t start, uint32_t len)
75 {
76 	return ((value << (sizeof(value) * 8 - len - start)) >>
77 		(sizeof(value) * 8 - len));
78 }
79 
80 /* Waits the referenced address to be ready (non-zero) and then jump into it. */
wait_and_jump(volatile uint32_t * reference)81 static void wait_and_jump(volatile uint32_t *reference)
82 {
83 	while (!*reference) {
84 		wfe();
85 	}
86 	jump_bx((void *)*reference);
87 }
88 
89 /* Configures L2 Control Register to use 3 cycles for DATA/TAG RAM latency. */
configure_l2ctlr(void)90 static void configure_l2ctlr(void)
91 {
92    uint32_t val;
93 
94    val = read_l2ctlr();
95    val &= ~(L2CTLR_DATA_RAM_LATENCY_MASK | L2CTLR_TAG_RAM_LATENCY_MASK);
96    val |= (L2CTLR_DATA_RAM_LATENCY_CYCLES_3 | L2CTLR_TAG_RAM_LATENCY_CYCLES_3 |
97 	   L2CTLR_ECC_PARITY);
98    write_l2ctlr(val);
99 }
100 
101 /* Configures L2 Auxiliary Control Register for Cortex A15. */
configure_l2actlr(void)102 static void configure_l2actlr(void)
103 {
104    uint32_t val;
105 
106    val = read_l2actlr();
107    val |= (L2ACTLR_DISABLE_CLEAN_EVICT_PUSH_EXTERNAL |
108 	   L2ACTLR_ENABLE_HAZARD_DETECT_TIMEOUT |
109 	   L2ACTLR_FORCE_L2_LOGIC_CLOCK_ENABLE_ACTIVE);
110    write_l2actlr(val);
111 }
112 
113 /* Initializes the CPU states to reset state. */
init_exynos_cpu_states(void)114 static void init_exynos_cpu_states(void) {
115 	memset((void *)exynos_cpu_states, 0, sizeof(*exynos_cpu_states));
116 	exynos_cpu_states->cpu_states[0] = CORE_STATE_RESET;
117 	exynos_cpu_states->cpu_states[1] = CORE_STATE_SECONDARY_RESET;
118 	exynos_cpu_states->cpu_states[2] = CORE_STATE_SECONDARY_RESET;
119 	exynos_cpu_states->cpu_states[3] = CORE_STATE_SECONDARY_RESET;
120 }
121 
122 /*
123  * Ensures that the L2 logic has been used within the previous 256 cycles
124  * before modifying the ACTLR.SMP bit. This is required during boot before
125  * MMU has been enabled, or during a specified reset or power down sequence.
126  */
enable_smp(void)127 static void enable_smp(void)
128 {
129 	uint32_t actlr, val;
130 
131 	/* Enable SMP mode */
132 	actlr = read_actlr();
133 	actlr |= ACTLR_SMP;
134 
135 	/* Dummy read to assure L2 access */
136 	val = read32(&exynos_power->inform0);
137 	val &= 0;
138 	actlr |= val;
139 
140 	write_actlr(actlr);
141 	dsb();
142 	isb();
143 }
144 
145 /* Starts the core and jumps to correct location by its state. */
core_start_execution(void)146 static void core_start_execution(void)
147 {
148 	u32 cpu_id, cpu_state;
149 
150 	enable_smp();
151 	set_system_mode();
152 
153 	cpu_id = read_mpidr() & 0x3;  /* up to 4 processors for one cluster. */
154 	cpu_state = exynos_cpu_states->cpu_states[cpu_id];
155 
156 	if (cpu_state & CORE_STATE_SWITCH_CLUSTER) {
157 		wait_and_jump(&exynos_cpu_states->switch_address);
158 		/* never returns. */
159 	}
160 
161 	/* Standard Exynos suspend/resume. */
162 	if (exynos_power->inform1) {
163 		exynos_power->inform1 = 0;
164 		jump_bx((void *)exynos_power->inform0);
165 		/* never returns. */
166 	}
167 
168 	if (cpu_state & CORE_STATE_RESET) {
169 		/* For Reset, U-Boot jumps to its starting address;
170 		 * on coreboot, seems ok to ignore for now. */
171 	}
172 	wait_and_jump(&exynos_cpu_states->hotplug_address);
173 	/* never returns. */
174 }
175 
176 /* The entry point for hotplug-in and cluster switching. */
low_power_start(void)177 static void low_power_start(void)
178 {
179 	uint32_t sctlr, reg_val;
180 
181 	/* On warm reset, because iRAM is not cleared, all cores will enter
182 	 * low_power_start, not the initial address. So we need to check reset
183 	 * status again, and jump to 0x0 in that case. */
184 	reg_val = read32(&exynos_power->spare0);
185 	if (reg_val != RST_FLAG_VAL) {
186 		write32(VECTOR_LOW_POWER_FLAG, 0x0);
187 		jump_bx(CORE_RESET_INIT_ADDRESS);
188 		/* restart CPU execution and never returns. */
189 	}
190 
191 	/* Workaround for iROM EVT1.  A7 core execution may flow into incorrect
192 	 * path, bypassing first jump address and makes final jump address 0x0,
193 	 * so we try to make any core set again low_power_start address, if that
194 	 * becomes zero. */
195 	reg_val = read32(VECTOR_CORE_SEV_HANDLER);
196 	if (reg_val != (intptr_t)low_power_start) {
197 		write32(VECTOR_CORE_SEV_HANDLER, (intptr_t)low_power_start);
198 		dsb();
199 		/* ask all cores to power on again. */
200 		sev();
201 	}
202 
203 	set_system_mode();
204 
205 	/* Whenever a Cortex A-15 core powers on, iROM resets its L2 cache
206 	 * so we need to configure again. */
207 	if (get_bits(read_midr(), 4, 12) == PART_NUMBER_CORTEX_A15) {
208 		configure_l2ctlr();
209 		configure_l2actlr();
210 	}
211 
212 	/* Invalidate L1 & TLB */
213 	tlbiall();
214 	iciallu();
215 
216 	/* Disable MMU stuff and caches */
217 	sctlr = read_sctlr();
218 	sctlr &= ~(SCTLR_V | SCTLR_M | SCTLR_C);
219 	sctlr |= (SCTLR_I | SCTLR_Z | SCTLR_A);
220 	write_sctlr(sctlr);
221 
222 	core_start_execution();
223 	/* The core should not return. But in order to prevent unexpected
224 	 * errors, a WFI command will help to put CPU back to idle state. */
225 	wfi();
226 }
227 
228 /* Callback to shutdown a core, safe to be set as hot-plug address. */
power_down_core(void)229 static void power_down_core(void)
230 {
231 	uint32_t mpidr, core_id;
232 
233 	/* MPIDR: 0~2=ID, 8~11=cluster. On Exynos 5420, cluster will be only 0
234 	 * or 1. */
235 	mpidr = read_mpidr();
236 	core_id = get_bits(mpidr, 0, 2) | (get_bits(mpidr, 8, 4) << 2);
237 
238 	/* Set the status of the core to low.
239 	 * S5E5420A User Manual, 8.8.1.202, ARM_CORE0_CONFIGURATION, two bits to
240 	 * control power state in each power down level.
241 	 */
242 	write32(&exynos_power->arm_core[core_id].config, 0x0);
243 
244 	/* S5E5420A User Manual, 8.4.2.5, after ARM_CORE*_CONFIGURATION has been
245 	 * set to zero, PMU will detect and wait for WFI then run power-down
246 	 * sequence. */
247 	wfi();
248 }
249 
250 /* Configures the CPU states shared memory page and then shutdown all cores. */
configure_secondary_cores(void)251 static void configure_secondary_cores(void)
252 {
253 	if (get_bits(read_midr(), 4, 12) == PART_NUMBER_CORTEX_A15) {
254 		configure_l2ctlr();
255 		configure_l2actlr();
256 	}
257 
258 	/* Currently we use power_down_core as callback for each core to
259 	 * shutdown itself, but it is also ok to directly set ARM_CORE*_CONFIG
260 	 * to zero by CPU0 because every secondary cores should be already in
261 	 * WFI state (in bootblock). The power_down_core will be more helpful
262 	 * when we want to use SMP inside firmware. */
263 
264 	/* Clear boot reg (hotplug address) in CPU states */
265 	write32((void *)&exynos_cpu_states->hotplug_address, 0);
266 
267 	/* set low_power flag and address */
268 	write32(VECTOR_LOW_POWER_ADDRESS, (intptr_t)low_power_start);
269 	write32(VECTOR_LOW_POWER_FLAG, RST_FLAG_VAL);
270 	write32(&exynos_power->spare0, RST_FLAG_VAL);
271 
272 	/* On next SEV, shutdown all cores. */
273 	write32(VECTOR_CORE_SEV_HANDLER, (intptr_t)power_down_core);
274 
275 	/* Ask all cores in WFE mode to shutdown. */
276 	dsb();
277 	sev();
278 }
279 
280 /* Configures the SMP cores on Exynos 5420 SOC (and shutdown all secondary
281  * cores) */
exynos5420_config_smp(void)282 void exynos5420_config_smp(void)
283 {
284 	init_exynos_cpu_states();
285 	configure_secondary_cores();
286 }
287