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