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