1 // 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  */
40 static 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 
psci_update_dt(void * fdt)47 int psci_update_dt(void *fdt)
48 {
49 	return 0;
50 }
51 
psci_set_state(int cpu,u8 state)52 __secure static void psci_set_state(int cpu, u8 state)
53 {
54 	psci_state[cpu] = state;
55 	dsb();
56 	isb();
57 }
58 
psci_cpu_on_validate_mpidr(u64 mpidr,u32 * cpu)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 
psci_cpu_on_write_entry_point(const u32 cpu,u64 entry_point)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 
psci_cpu_on_power_on(const u32 cpu)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 
psci_cpu_on_power_off(const u32 cpu)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 */
psci_version(void)123 __secure u32 psci_version(void)
124 {
125 	return ARM_PSCI_VER_1_0;
126 }
127 
128 /*
129  * 64bit PSCI code
130  */
psci_cpu_on_64(u32 __always_unused function_id,u64 mpidr,u64 entry_point_address,u64 context_id)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 
psci_affinity_info_64(u32 __always_unused function_id,u64 target_affinity,u32 lowest_affinity_level)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 
psci_system_reset2_64(u32 __always_unused function_id,u32 reset_type,u64 cookie)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  */
psci_affinity_info(u32 __always_unused function_id,u32 target_affinity,u32 lowest_affinity_level)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 
psci_cpu_on(u32 __always_unused function_id,u32 mpidr,u32 entry_point_address,u32 context_id)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 
psci_cpu_off(void)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 
psci_migrate_info_type(void)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 
psci_system_reset(void)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 
psci_system_off(void)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  */
psci_features(u32 __always_unused function_id,u32 psci_fid)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 }
289