~funderscore blog cgit wiki get in touch
aboutsummaryrefslogtreecommitdiff
blob: 62f0b768cfa44cc1fb9855123044326ee608e7bb (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
// SPDX-License-Identifier: GPL-2.0
/*
 * This file implements basic PSCI support for i.MX8M
 *
 * Copyright (C) 2022 Marek Vasut <marex@denx.de>
 */
#include <asm/arch/imx-regs.h>
#include <asm/cache.h>
#include <asm/gic.h>
#include <asm/io.h>
#include <asm/psci.h>
#include <asm/secure.h>
#include <common.h>
#include <cpu_func.h>
#include <debug_uart.h>
#include <fsl_wdog.h>
#include <linux/bitops.h>

#define SNVS_LPCR			0x38
#define SNVS_LPCR_TOP			BIT(6)
#define SNVS_LPCR_DP_EN			BIT(5)
#define SNVS_LPCR_SRTC_ENV		BIT(0)

#define MPIDR_AFF0			GENMASK(7, 0)

#define GPC_LPCR_A53_AD			0x4
#define EN_Cn_WFI_PDN(cpu)		BIT(((((cpu) & 1) * 2) + (((cpu) & 2) * 8)))
#define GPC_PGC_nCTRL(cpu)		(0x800 + ((cpu) * 0x40))
#define PGC_PCR				BIT(0)
#define GPC_CPU_PGC_SW_PUP_REQ		(IS_ENABLED(CONFIG_IMX8MP) ? 0xd0 : 0xf0)
#define COREn_A53_SW_PUP_REQ(cpu)	BIT(cpu)

#define SRC_A53RCR1			0x8
#define A53_COREn_ENABLE(n)		BIT(n)
#define SRC_GPR(n)			(0x74 + ((n) * 4))

/*
 * Helper code
 */
static u8 psci_state[CONFIG_ARMV8_PSCI_NR_CPUS] __secure_data = {
	PSCI_AFFINITY_LEVEL_ON,
	PSCI_AFFINITY_LEVEL_OFF,
	PSCI_AFFINITY_LEVEL_OFF,
	PSCI_AFFINITY_LEVEL_OFF
};

int psci_update_dt(void *fdt)
{
	return 0;
}

__secure static void psci_set_state(int cpu, u8 state)
{
	psci_state[cpu] = state;
	dsb();
	isb();
}

__secure static s32 psci_cpu_on_validate_mpidr(u64 mpidr, u32 *cpu)
{
	*cpu = mpidr & MPIDR_AFF0;

	if (mpidr & ~MPIDR_AFF0)
		return ARM_PSCI_RET_INVAL;

	if (*cpu >= CONFIG_ARMV8_PSCI_NR_CPUS)
		return ARM_PSCI_RET_INVAL;

	if (psci_state[*cpu] == PSCI_AFFINITY_LEVEL_ON)
		return ARM_PSCI_RET_ALREADY_ON;

	if (psci_state[*cpu] == PSCI_AFFINITY_LEVEL_ON_PENDING)
		return ARM_PSCI_RET_ON_PENDING;

	return ARM_PSCI_RET_SUCCESS;
}

__secure static void psci_cpu_on_write_entry_point(const u32 cpu, u64 entry_point)
{
	const u64 ep = CONFIG_SPL_TEXT_BASE;

	/* Trampoline target */
	writeq(entry_point, CPU_RELEASE_ADDR);
	/* RVBAR address HI */
	writel((u32)(ep >> 24) & 0xffff,
	       (void *)SRC_BASE_ADDR + SRC_GPR(cpu * 2));
	/* RVBAR address LO */
	writel((u32)(ep >> 2) & 0x3fffff,
	       (void *)SRC_BASE_ADDR + SRC_GPR(cpu * 2 + 1));
}

__secure static void psci_cpu_on_power_on(const u32 cpu)
{
	int i;

	clrbits_le32((void *)GPC_BASE_ADDR + GPC_LPCR_A53_AD, EN_Cn_WFI_PDN(cpu));
	clrbits_le32((void *)SRC_BASE_ADDR + SRC_A53RCR1, A53_COREn_ENABLE(cpu));
	setbits_le32((void *)GPC_BASE_ADDR + GPC_PGC_nCTRL(cpu), PGC_PCR);
	setbits_le32((void *)GPC_BASE_ADDR + GPC_CPU_PGC_SW_PUP_REQ, COREn_A53_SW_PUP_REQ(cpu));

	/* If we fail here, the core gets power cycled, hang is OK */
	while (readl(GPC_BASE_ADDR + GPC_CPU_PGC_SW_PUP_REQ) & COREn_A53_SW_PUP_REQ(cpu))
			;

	clrbits_le32((void *)GPC_BASE_ADDR + GPC_PGC_nCTRL(cpu), PGC_PCR);
	setbits_le32((void *)SRC_BASE_ADDR + SRC_A53RCR1, A53_COREn_ENABLE(cpu));

	/* Give the core a bit of time to boot and start executing code */
	for (i = 0; i < 100000; i++)
		asm volatile("nop");
}

__secure static void psci_cpu_on_power_off(const u32 cpu)
{
	setbits_le32((void *)GPC_BASE_ADDR + GPC_LPCR_A53_AD, EN_Cn_WFI_PDN(cpu));
	setbits_le32((void *)GPC_BASE_ADDR + GPC_PGC_nCTRL(cpu), PGC_PCR);
}

/*
 * Common PSCI code
 */
/* Return supported PSCI version */
__secure u32 psci_version(void)
{
	return ARM_PSCI_VER_1_0;
}

/*
 * 64bit PSCI code
 */
__secure s32 psci_cpu_on_64(u32 __always_unused function_id, u64 mpidr,
			    u64 entry_point_address, u64 context_id)
{
	u32 cpu = 0;
	int ret;

	ret = psci_cpu_on_validate_mpidr(mpidr, &cpu);
	if (ret != ARM_PSCI_RET_SUCCESS)
		return ret;

	psci_cpu_on_write_entry_point(cpu, entry_point_address);

	psci_set_state(cpu, PSCI_AFFINITY_LEVEL_ON);

	psci_cpu_on_power_on(cpu);

	smp_kick_all_cpus();

	return ARM_PSCI_RET_SUCCESS;
}

__secure s32 psci_affinity_info_64(u32 __always_unused function_id,
				   u64 target_affinity, u32 lowest_affinity_level)
{
	u32 cpu = target_affinity & MPIDR_AFF0;

	if (lowest_affinity_level > 0)
		return ARM_PSCI_RET_INVAL;

	if (target_affinity & ~MPIDR_AFF0)
		return ARM_PSCI_RET_INVAL;

	if (cpu >= CONFIG_ARMV8_PSCI_NR_CPUS)
		return ARM_PSCI_RET_INVAL;

	return psci_state[cpu];
}

__secure s32 psci_system_reset2_64(u32 __always_unused function_id,
				   u32 reset_type, u64 cookie)
{
	psci_system_reset();
	return 0;	/* Not reached */
}

/*
 * 32bit PSCI code
 */
__secure s32 psci_affinity_info(u32 __always_unused function_id,
				u32 target_affinity, u32 lowest_affinity_level)
{
	return psci_affinity_info_64(function_id, target_affinity, lowest_affinity_level);
}

__secure s32 psci_cpu_on(u32 __always_unused function_id, u32 mpidr,
			 u32 entry_point_address, u32 context_id)
{
	return psci_cpu_on_64(function_id, mpidr, entry_point_address, context_id);
}

__secure s32 psci_cpu_off(void)
{
	u32 cpu = psci_get_cpu_id();

	psci_cpu_on_power_off(cpu);
	psci_set_state(cpu, PSCI_AFFINITY_LEVEL_OFF);

	while (1)
		wfi();
}

__secure u32 psci_migrate_info_type(void)
{
	/* Trusted OS is either not present or does not require migration */
	return 2;
}

__secure void psci_system_reset(void)
{
	struct wdog_regs *wdog = (struct wdog_regs *)WDOG1_BASE_ADDR;
	bool ext_reset = true;

	u16 wcr = WCR_WDE;

	if (ext_reset)
		wcr |= WCR_SRS; /* do not assert internal reset */
	else
		wcr |= WCR_WDA; /* do not assert external reset */

	/* Write 3 times to ensure it works, due to IMX6Q errata ERR004346 */
	writew(wcr, &wdog->wcr);
	writew(wcr, &wdog->wcr);
	writew(wcr, &wdog->wcr);

	while (1)
		wfi();
}

__secure void psci_system_off(void)
{
	writel(SNVS_LPCR_TOP | SNVS_LPCR_DP_EN | SNVS_LPCR_SRTC_ENV,
	       SNVS_BASE_ADDR + SNVS_LPCR);

	while (1)
		wfi();
}

/*
 * PSCI jump table
 */
__secure s32 psci_features(u32 __always_unused function_id, u32 psci_fid)
{
	switch (psci_fid) {
	case ARM_PSCI_0_2_FN_PSCI_VERSION:
	case ARM_PSCI_0_2_FN_CPU_OFF:
	case ARM_PSCI_0_2_FN_CPU_ON:
	case ARM_PSCI_0_2_FN_AFFINITY_INFO:
	case ARM_PSCI_0_2_FN_MIGRATE_INFO_TYPE:
	case ARM_PSCI_0_2_FN_SYSTEM_OFF:
	case ARM_PSCI_0_2_FN_SYSTEM_RESET:
	case ARM_PSCI_0_2_FN64_CPU_ON:
	case ARM_PSCI_0_2_FN64_AFFINITY_INFO:

	/* PSCI 1.0 interface */
	case ARM_PSCI_1_0_FN_PSCI_FEATURES:

	/* PSCI 1.1 interface */
	case ARM_PSCI_1_1_FN64_SYSTEM_RESET2:
		return 0x0;

	/*
	 * Not implemented:
	 * ARM_PSCI_0_2_FN_CPU_SUSPEND
	 * ARM_PSCI_1_0_FN_CPU_FREEZE
	 * ARM_PSCI_1_0_FN_CPU_DEFAULT_SUSPEND
	 * ARM_PSCI_1_0_FN_NODE_HW_STATE
	 * ARM_PSCI_1_0_FN_SYSTEM_SUSPEND
	 * ARM_PSCI_1_0_FN_SET_SUSPEND_MODE
	 * ARM_PSCI_1_0_FN_STAT_RESIDENCY
	 * ARM_PSCI_1_0_FN_STAT_COUNT
	 * ARM_PSCI_0_2_FN64_CPU_SUSPEND
	 * ARM_PSCI_1_0_FN64_CPU_DEFAULT_SUSPEND
	 * ARM_PSCI_1_0_FN64_NODE_HW_STATE
	 * ARM_PSCI_1_0_FN64_SYSTEM_SUSPEND
	 * ARM_PSCI_1_0_FN64_STAT_RESIDENCY
	 * ARM_PSCI_1_0_FN64_STAT_COUNT
	 */

	/* Not required, ARM_PSCI_0_2_FN_MIGRATE_INFO_TYPE returns 2 */
	case ARM_PSCI_0_2_FN_MIGRATE:
	case ARM_PSCI_0_2_FN64_MIGRATE:
	/* Not required */
	case ARM_PSCI_0_2_FN_MIGRATE_INFO_UP_CPU:
	case ARM_PSCI_0_2_FN64_MIGRATE_INFO_UP_CPU:
	default:
		return ARM_PSCI_RET_NI;
	}
}