2 * This file is part of the coreboot project.
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; version 2 of the License.
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
16 #include <device/mmio.h>
18 #include <soc/power.h>
22 /* ACTLR, L2CTLR L2ACTLR constants used in SMP core power up. */
24 #define ACTLR_SMP (1 << 6)
26 #define L2CTLR_ECC_PARITY (1 << 21)
27 #define L2CTLR_DATA_RAM_LATENCY_MASK (7 << 0)
28 #define L2CTLR_TAG_RAM_LATENCY_MASK (7 << 6)
29 #define L2CTLR_DATA_RAM_LATENCY_CYCLES_3 (2 << 0)
30 #define L2CTLR_TAG_RAM_LATENCY_CYCLES_3 (2 << 6)
32 #define L2ACTLR_DISABLE_CLEAN_EVICT_PUSH_EXTERNAL (1 << 3)
33 #define L2ACTLR_ENABLE_HAZARD_DETECT_TIMEOUT (1 << 7)
34 #define L2ACTLR_FORCE_L2_LOGIC_CLOCK_ENABLE_ACTIVE (1 << 27)
36 /* Part number in CPU ID (MPIDR). */
37 #define PART_NUMBER_CORTEX_A15 (0xc0f)
39 /* State of CPU cores in Exynos 5420. */
40 #define CORE_STATE_RESET (1 << 0)
41 #define CORE_STATE_SECONDARY_RESET (1 << 1)
42 #define CORE_STATE_SWITCH_CLUSTER (1 << 4)
44 /* The default address to re-power on a code. */
45 #define CORE_RESET_INIT_ADDRESS ((void *)0x00000000)
47 /* Vectors in BL1 (0x02020000 = base of iRAM). */
48 #define VECTOR_CORE_SEV_HANDLER ((void *)(intptr_t)0x02020004)
49 #define VECTOR_LOW_POWER_FLAG ((void *)(intptr_t)0x02020028)
50 #define VECTOR_LOW_POWER_ADDRESS ((void *)(intptr_t)0x0202002C)
52 /* The data structure for the "CPU state" memory page (shared with kernel)
53 * controlling cores in active cluster. Kernel will put starting address for one
54 * core in "hotplug_address" before power on. Note the address is hard-coded in
55 * kernel (EXYNOS5420_PA_SYSRAM_NS = 0x02073000). */
56 volatile struct exynos5420_cpu_states
58 uint32_t _reserved
[2]; /* RESV, +0x00 */
59 uint32_t resume_address
; /* REG0, +0x08 */
60 uint32_t resume_flag
; /* REG1, +0x0C */
61 uint32_t _reg2
; /* REG2, +0x10 */
62 uint32_t _reg3
; /* REG3, +0x14 */
63 uint32_t switch_address
; /* REG4, +0x18, cluster switching */
64 uint32_t hotplug_address
; /* REG5, +0x1C, core hotplug */
65 uint32_t _reg6
; /* REG6, +0x20 */
66 uint32_t c2_address
; /* REG7, +0x24, C2 state change */
68 /* Managed per core status for active cluster, offset: +0x28~0x38 */
69 uint32_t cpu_states
[4];
71 /* Managed per core GIC status for active cluster, offset: 0x38~0x48 */
72 uint32_t cpu_gic_states
[4];
73 } *exynos_cpu_states
= (volatile struct exynos5420_cpu_states
*)0x02073000;
75 /* When leaving core handlers and jump to hot-plug address (or cluster
76 * switching), we are not sure if the destination is Thumb or ARM mode.
77 * So a BX command is required.
79 inline static void jump_bx(void *address
)
81 asm volatile ("bx %0" : : "r"(address
));
85 /* Extracts arbitrary bits from a 32-bit unsigned int. */
86 inline static uint32_t get_bits(uint32_t value
, uint32_t start
, uint32_t len
)
88 return ((value
<< (sizeof(value
) * 8 - len
- start
)) >>
89 (sizeof(value
) * 8 - len
));
92 /* Waits the referenced address to be ready (non-zero) and then jump into it. */
93 static void wait_and_jump(volatile uint32_t *reference
)
98 jump_bx((void *)*reference
);
101 /* Configures L2 Control Register to use 3 cycles for DATA/TAG RAM latency. */
102 static void configure_l2ctlr(void)
107 val
&= ~(L2CTLR_DATA_RAM_LATENCY_MASK
| L2CTLR_TAG_RAM_LATENCY_MASK
);
108 val
|= (L2CTLR_DATA_RAM_LATENCY_CYCLES_3
| L2CTLR_TAG_RAM_LATENCY_CYCLES_3
|
113 /* Configures L2 Auxiliary Control Register for Cortex A15. */
114 static void configure_l2actlr(void)
118 val
= read_l2actlr();
119 val
|= (L2ACTLR_DISABLE_CLEAN_EVICT_PUSH_EXTERNAL
|
120 L2ACTLR_ENABLE_HAZARD_DETECT_TIMEOUT
|
121 L2ACTLR_FORCE_L2_LOGIC_CLOCK_ENABLE_ACTIVE
);
125 /* Initializes the CPU states to reset state. */
126 static void init_exynos_cpu_states(void) {
127 memset((void *)exynos_cpu_states
, 0, sizeof(*exynos_cpu_states
));
128 exynos_cpu_states
->cpu_states
[0] = CORE_STATE_RESET
;
129 exynos_cpu_states
->cpu_states
[1] = CORE_STATE_SECONDARY_RESET
;
130 exynos_cpu_states
->cpu_states
[2] = CORE_STATE_SECONDARY_RESET
;
131 exynos_cpu_states
->cpu_states
[3] = CORE_STATE_SECONDARY_RESET
;
135 * Ensures that the L2 logic has been used within the previous 256 cycles
136 * before modifying the ACTLR.SMP bit. This is required during boot before
137 * MMU has been enabled, or during a specified reset or power down sequence.
139 static void enable_smp(void)
143 /* Enable SMP mode */
144 actlr
= read_actlr();
147 /* Dummy read to assure L2 access */
148 val
= read32(&exynos_power
->inform0
);
157 /* Starts the core and jumps to correct location by its state. */
158 static void core_start_execution(void)
160 u32 cpu_id
, cpu_state
;
165 cpu_id
= read_mpidr() & 0x3; /* up to 4 processors for one cluster. */
166 cpu_state
= exynos_cpu_states
->cpu_states
[cpu_id
];
168 if (cpu_state
& CORE_STATE_SWITCH_CLUSTER
) {
169 wait_and_jump(&exynos_cpu_states
->switch_address
);
173 /* Standard Exynos suspend/resume. */
174 if (exynos_power
->inform1
) {
175 exynos_power
->inform1
= 0;
176 jump_bx((void *)exynos_power
->inform0
);
180 if (cpu_state
& CORE_STATE_RESET
) {
181 /* For Reset, U-Boot jumps to its starting address;
182 * on coreboot, seems ok to ignore for now. */
184 wait_and_jump(&exynos_cpu_states
->hotplug_address
);
188 /* The entry point for hotplug-in and cluster switching. */
189 static void low_power_start(void)
191 uint32_t sctlr
, reg_val
;
193 /* On warm reset, because iRAM is not cleared, all cores will enter
194 * low_power_start, not the initial address. So we need to check reset
195 * status again, and jump to 0x0 in that case. */
196 reg_val
= read32(&exynos_power
->spare0
);
197 if (reg_val
!= RST_FLAG_VAL
) {
198 write32(VECTOR_LOW_POWER_FLAG
, 0x0);
199 jump_bx(CORE_RESET_INIT_ADDRESS
);
200 /* restart CPU execution and never returns. */
203 /* Workaround for iROM EVT1. A7 core execution may flow into incorrect
204 * path, bypassing first jump address and makes final jump address 0x0,
205 * so we try to make any core set again low_power_start address, if that
207 reg_val
= read32(VECTOR_CORE_SEV_HANDLER
);
208 if (reg_val
!= (intptr_t)low_power_start
) {
209 write32(VECTOR_CORE_SEV_HANDLER
, (intptr_t)low_power_start
);
211 /* ask all cores to power on again. */
217 /* Whenever a Cortex A-15 core powers on, iROM resets its L2 cache
218 * so we need to configure again. */
219 if (get_bits(read_midr(), 4, 12) == PART_NUMBER_CORTEX_A15
) {
224 /* Invalidate L1 & TLB */
228 /* Disable MMU stuff and caches */
229 sctlr
= read_sctlr();
230 sctlr
&= ~(SCTLR_V
| SCTLR_M
| SCTLR_C
);
231 sctlr
|= (SCTLR_I
| SCTLR_Z
| SCTLR_A
);
234 core_start_execution();
235 /* The core should not return. But in order to prevent unexpected
236 * errors, a WFI command will help to put CPU back to idle state. */
240 /* Callback to shutdown a core, safe to be set as hot-plug address. */
241 static void power_down_core(void)
243 uint32_t mpidr
, core_id
;
245 /* MPIDR: 0~2=ID, 8~11=cluster. On Exynos 5420, cluster will be only 0
247 mpidr
= read_mpidr();
248 core_id
= get_bits(mpidr
, 0, 2) | (get_bits(mpidr
, 8, 4) << 2);
250 /* Set the status of the core to low.
251 * S5E5420A User Manual, 8.8.1.202, ARM_CORE0_CONFIGURATION, two bits to
252 * control power state in each power down level.
254 write32(&exynos_power
->arm_core
[core_id
].config
, 0x0);
256 /* S5E5420A User Manual, 8.4.2.5, after ARM_CORE*_CONFIGURATION has been
257 * set to zero, PMU will detect and wait for WFI then run power-down
262 /* Configures the CPU states shared memory page and then shutdown all cores. */
263 static void configure_secondary_cores(void)
265 if (get_bits(read_midr(), 4, 12) == PART_NUMBER_CORTEX_A15
) {
270 /* Currently we use power_down_core as callback for each core to
271 * shutdown itself, but it is also ok to directly set ARM_CORE*_CONFIG
272 * to zero by CPU0 because every secondary cores should be already in
273 * WFI state (in bootblock). The power_down_core will be more helpful
274 * when we want to use SMP inside firmware. */
276 /* Clear boot reg (hotplug address) in CPU states */
277 write32((void *)&exynos_cpu_states
->hotplug_address
, 0);
279 /* set low_power flag and address */
280 write32(VECTOR_LOW_POWER_ADDRESS
, (intptr_t)low_power_start
);
281 write32(VECTOR_LOW_POWER_FLAG
, RST_FLAG_VAL
);
282 write32(&exynos_power
->spare0
, RST_FLAG_VAL
);
284 /* On next SEV, shutdown all cores. */
285 write32(VECTOR_CORE_SEV_HANDLER
, (intptr_t)power_down_core
);
287 /* Ask all cores in WFE mode to shutdown. */
292 /* Configures the SMP cores on Exynos 5420 SOC (and shutdown all secondary
294 void exynos5420_config_smp(void)
296 init_exynos_cpu_states();
297 configure_secondary_cores();