blob: 62f0b768cfa44cc1fb9855123044326ee608e7bb [file] [log] [blame]
Marek Vasuta5385222022-12-22 01:46:43 +01001// SPDX-License-Identifier: GPL-2.0
2/*
3 * This file implements basic PSCI support for i.MX8M
4 *
5 * Copyright (C) 2022 Marek Vasut <marex@denx.de>
6 */
7#include <asm/arch/imx-regs.h>
8#include <asm/cache.h>
9#include <asm/gic.h>
10#include <asm/io.h>
11#include <asm/psci.h>
12#include <asm/secure.h>
13#include <common.h>
14#include <cpu_func.h>
15#include <debug_uart.h>
16#include <fsl_wdog.h>
17#include <linux/bitops.h>
18
19#define SNVS_LPCR 0x38
20#define SNVS_LPCR_TOP BIT(6)
21#define SNVS_LPCR_DP_EN BIT(5)
22#define SNVS_LPCR_SRTC_ENV BIT(0)
23
24#define MPIDR_AFF0 GENMASK(7, 0)
25
26#define GPC_LPCR_A53_AD 0x4
27#define EN_Cn_WFI_PDN(cpu) BIT(((((cpu) & 1) * 2) + (((cpu) & 2) * 8)))
28#define GPC_PGC_nCTRL(cpu) (0x800 + ((cpu) * 0x40))
29#define PGC_PCR BIT(0)
30#define GPC_CPU_PGC_SW_PUP_REQ (IS_ENABLED(CONFIG_IMX8MP) ? 0xd0 : 0xf0)
31#define COREn_A53_SW_PUP_REQ(cpu) BIT(cpu)
32
33#define SRC_A53RCR1 0x8
34#define A53_COREn_ENABLE(n) BIT(n)
35#define SRC_GPR(n) (0x74 + ((n) * 4))
36
37/*
38 * Helper code
39 */
40static u8 psci_state[CONFIG_ARMV8_PSCI_NR_CPUS] __secure_data = {
41 PSCI_AFFINITY_LEVEL_ON,
42 PSCI_AFFINITY_LEVEL_OFF,
43 PSCI_AFFINITY_LEVEL_OFF,
44 PSCI_AFFINITY_LEVEL_OFF
45};
46
47int psci_update_dt(void *fdt)
48{
49 return 0;
50}
51
52__secure static void psci_set_state(int cpu, u8 state)
53{
54 psci_state[cpu] = state;
55 dsb();
56 isb();
57}
58
59__secure static s32 psci_cpu_on_validate_mpidr(u64 mpidr, u32 *cpu)
60{
61 *cpu = mpidr & MPIDR_AFF0;
62
63 if (mpidr & ~MPIDR_AFF0)
64 return ARM_PSCI_RET_INVAL;
65
66 if (*cpu >= CONFIG_ARMV8_PSCI_NR_CPUS)
67 return ARM_PSCI_RET_INVAL;
68
69 if (psci_state[*cpu] == PSCI_AFFINITY_LEVEL_ON)
70 return ARM_PSCI_RET_ALREADY_ON;
71
72 if (psci_state[*cpu] == PSCI_AFFINITY_LEVEL_ON_PENDING)
73 return ARM_PSCI_RET_ON_PENDING;
74
75 return ARM_PSCI_RET_SUCCESS;
76}
77
78__secure static void psci_cpu_on_write_entry_point(const u32 cpu, u64 entry_point)
79{
80 const u64 ep = CONFIG_SPL_TEXT_BASE;
81
82 /* Trampoline target */
83 writeq(entry_point, CPU_RELEASE_ADDR);
84 /* RVBAR address HI */
85 writel((u32)(ep >> 24) & 0xffff,
86 (void *)SRC_BASE_ADDR + SRC_GPR(cpu * 2));
87 /* RVBAR address LO */
88 writel((u32)(ep >> 2) & 0x3fffff,
89 (void *)SRC_BASE_ADDR + SRC_GPR(cpu * 2 + 1));
90}
91
92__secure static void psci_cpu_on_power_on(const u32 cpu)
93{
94 int i;
95
96 clrbits_le32((void *)GPC_BASE_ADDR + GPC_LPCR_A53_AD, EN_Cn_WFI_PDN(cpu));
97 clrbits_le32((void *)SRC_BASE_ADDR + SRC_A53RCR1, A53_COREn_ENABLE(cpu));
98 setbits_le32((void *)GPC_BASE_ADDR + GPC_PGC_nCTRL(cpu), PGC_PCR);
99 setbits_le32((void *)GPC_BASE_ADDR + GPC_CPU_PGC_SW_PUP_REQ, COREn_A53_SW_PUP_REQ(cpu));
100
101 /* If we fail here, the core gets power cycled, hang is OK */
102 while (readl(GPC_BASE_ADDR + GPC_CPU_PGC_SW_PUP_REQ) & COREn_A53_SW_PUP_REQ(cpu))
103 ;
104
105 clrbits_le32((void *)GPC_BASE_ADDR + GPC_PGC_nCTRL(cpu), PGC_PCR);
106 setbits_le32((void *)SRC_BASE_ADDR + SRC_A53RCR1, A53_COREn_ENABLE(cpu));
107
108 /* Give the core a bit of time to boot and start executing code */
109 for (i = 0; i < 100000; i++)
110 asm volatile("nop");
111}
112
113__secure static void psci_cpu_on_power_off(const u32 cpu)
114{
115 setbits_le32((void *)GPC_BASE_ADDR + GPC_LPCR_A53_AD, EN_Cn_WFI_PDN(cpu));
116 setbits_le32((void *)GPC_BASE_ADDR + GPC_PGC_nCTRL(cpu), PGC_PCR);
117}
118
119/*
120 * Common PSCI code
121 */
122/* Return supported PSCI version */
123__secure u32 psci_version(void)
124{
125 return ARM_PSCI_VER_1_0;
126}
127
128/*
129 * 64bit PSCI code
130 */
131__secure s32 psci_cpu_on_64(u32 __always_unused function_id, u64 mpidr,
132 u64 entry_point_address, u64 context_id)
133{
134 u32 cpu = 0;
135 int ret;
136
137 ret = psci_cpu_on_validate_mpidr(mpidr, &cpu);
138 if (ret != ARM_PSCI_RET_SUCCESS)
139 return ret;
140
141 psci_cpu_on_write_entry_point(cpu, entry_point_address);
142
143 psci_set_state(cpu, PSCI_AFFINITY_LEVEL_ON);
144
145 psci_cpu_on_power_on(cpu);
146
147 smp_kick_all_cpus();
148
149 return ARM_PSCI_RET_SUCCESS;
150}
151
152__secure s32 psci_affinity_info_64(u32 __always_unused function_id,
153 u64 target_affinity, u32 lowest_affinity_level)
154{
155 u32 cpu = target_affinity & MPIDR_AFF0;
156
157 if (lowest_affinity_level > 0)
158 return ARM_PSCI_RET_INVAL;
159
160 if (target_affinity & ~MPIDR_AFF0)
161 return ARM_PSCI_RET_INVAL;
162
163 if (cpu >= CONFIG_ARMV8_PSCI_NR_CPUS)
164 return ARM_PSCI_RET_INVAL;
165
166 return psci_state[cpu];
167}
168
169__secure s32 psci_system_reset2_64(u32 __always_unused function_id,
170 u32 reset_type, u64 cookie)
171{
172 psci_system_reset();
173 return 0; /* Not reached */
174}
175
176/*
177 * 32bit PSCI code
178 */
179__secure s32 psci_affinity_info(u32 __always_unused function_id,
180 u32 target_affinity, u32 lowest_affinity_level)
181{
182 return psci_affinity_info_64(function_id, target_affinity, lowest_affinity_level);
183}
184
185__secure s32 psci_cpu_on(u32 __always_unused function_id, u32 mpidr,
186 u32 entry_point_address, u32 context_id)
187{
188 return psci_cpu_on_64(function_id, mpidr, entry_point_address, context_id);
189}
190
191__secure s32 psci_cpu_off(void)
192{
193 u32 cpu = psci_get_cpu_id();
194
195 psci_cpu_on_power_off(cpu);
196 psci_set_state(cpu, PSCI_AFFINITY_LEVEL_OFF);
197
198 while (1)
199 wfi();
200}
201
202__secure u32 psci_migrate_info_type(void)
203{
204 /* Trusted OS is either not present or does not require migration */
205 return 2;
206}
207
208__secure void psci_system_reset(void)
209{
210 struct wdog_regs *wdog = (struct wdog_regs *)WDOG1_BASE_ADDR;
211 bool ext_reset = true;
212
213 u16 wcr = WCR_WDE;
214
215 if (ext_reset)
216 wcr |= WCR_SRS; /* do not assert internal reset */
217 else
218 wcr |= WCR_WDA; /* do not assert external reset */
219
220 /* Write 3 times to ensure it works, due to IMX6Q errata ERR004346 */
221 writew(wcr, &wdog->wcr);
222 writew(wcr, &wdog->wcr);
223 writew(wcr, &wdog->wcr);
224
225 while (1)
226 wfi();
227}
228
229__secure void psci_system_off(void)
230{
231 writel(SNVS_LPCR_TOP | SNVS_LPCR_DP_EN | SNVS_LPCR_SRTC_ENV,
232 SNVS_BASE_ADDR + SNVS_LPCR);
233
234 while (1)
235 wfi();
236}
237
238/*
239 * PSCI jump table
240 */
241__secure s32 psci_features(u32 __always_unused function_id, u32 psci_fid)
242{
243 switch (psci_fid) {
244 case ARM_PSCI_0_2_FN_PSCI_VERSION:
245 case ARM_PSCI_0_2_FN_CPU_OFF:
246 case ARM_PSCI_0_2_FN_CPU_ON:
247 case ARM_PSCI_0_2_FN_AFFINITY_INFO:
248 case ARM_PSCI_0_2_FN_MIGRATE_INFO_TYPE:
249 case ARM_PSCI_0_2_FN_SYSTEM_OFF:
250 case ARM_PSCI_0_2_FN_SYSTEM_RESET:
251 case ARM_PSCI_0_2_FN64_CPU_ON:
252 case ARM_PSCI_0_2_FN64_AFFINITY_INFO:
253
254 /* PSCI 1.0 interface */
255 case ARM_PSCI_1_0_FN_PSCI_FEATURES:
256
257 /* PSCI 1.1 interface */
258 case ARM_PSCI_1_1_FN64_SYSTEM_RESET2:
259 return 0x0;
260
261 /*
262 * Not implemented:
263 * ARM_PSCI_0_2_FN_CPU_SUSPEND
264 * ARM_PSCI_1_0_FN_CPU_FREEZE
265 * ARM_PSCI_1_0_FN_CPU_DEFAULT_SUSPEND
266 * ARM_PSCI_1_0_FN_NODE_HW_STATE
267 * ARM_PSCI_1_0_FN_SYSTEM_SUSPEND
268 * ARM_PSCI_1_0_FN_SET_SUSPEND_MODE
269 * ARM_PSCI_1_0_FN_STAT_RESIDENCY
270 * ARM_PSCI_1_0_FN_STAT_COUNT
271 * ARM_PSCI_0_2_FN64_CPU_SUSPEND
272 * ARM_PSCI_1_0_FN64_CPU_DEFAULT_SUSPEND
273 * ARM_PSCI_1_0_FN64_NODE_HW_STATE
274 * ARM_PSCI_1_0_FN64_SYSTEM_SUSPEND
275 * ARM_PSCI_1_0_FN64_STAT_RESIDENCY
276 * ARM_PSCI_1_0_FN64_STAT_COUNT
277 */
278
279 /* Not required, ARM_PSCI_0_2_FN_MIGRATE_INFO_TYPE returns 2 */
280 case ARM_PSCI_0_2_FN_MIGRATE:
281 case ARM_PSCI_0_2_FN64_MIGRATE:
282 /* Not required */
283 case ARM_PSCI_0_2_FN_MIGRATE_INFO_UP_CPU:
284 case ARM_PSCI_0_2_FN64_MIGRATE_INFO_UP_CPU:
285 default:
286 return ARM_PSCI_RET_NI;
287 }
288}