1 // SPDX-License-Identifier: BSD-2-Clause
2 /*
3  * Copyright (C) 2016 Freescale Semiconductor, Inc.
4  *
5  * Peng Fan <peng.fan@nxp.com>
6  */
7 
8 #include <console.h>
9 #include <drivers/imx_uart.h>
10 #include <drivers/imx_wdog.h>
11 #include <io.h>
12 #include <imx.h>
13 #include <imx_pm.h>
14 #include <imx-regs.h>
15 #include <kernel/boot.h>
16 #include <kernel/misc.h>
17 #include <kernel/panic.h>
18 #include <mm/core_mmu.h>
19 #include <mm/core_memprot.h>
20 #include <platform_config.h>
21 #include <stdint.h>
22 #include <sm/optee_smc.h>
23 #include <sm/psci.h>
24 #include <sm/std_smc.h>
25 #include <tee/entry_std.h>
26 #include <tee/entry_fast.h>
27 
psci_features(uint32_t psci_fid)28 int psci_features(uint32_t psci_fid)
29 {
30 	switch (psci_fid) {
31 	case ARM_SMCCC_VERSION:
32 	case PSCI_PSCI_FEATURES:
33 	case PSCI_VERSION:
34 	case PSCI_CPU_SUSPEND:
35 	case PSCI_CPU_OFF:
36 #ifdef CFG_BOOT_SECONDARY_REQUEST
37 	case PSCI_CPU_ON:
38 #endif
39 	case PSCI_AFFINITY_INFO:
40 	case PSCI_SYSTEM_OFF:
41 	case PSCI_SYSTEM_RESET:
42 	case PSCI_SYSTEM_RESET2:
43 		return PSCI_RET_SUCCESS;
44 	default:
45 		return PSCI_RET_NOT_SUPPORTED;
46 	}
47 }
48 
psci_version(void)49 uint32_t psci_version(void)
50 {
51 	return PSCI_VERSION_1_0;
52 }
53 
54 #ifdef CFG_BOOT_SECONDARY_REQUEST
psci_cpu_on(uint32_t core_idx,uint32_t entry,uint32_t context_id)55 int psci_cpu_on(uint32_t core_idx, uint32_t entry,
56 		uint32_t context_id)
57 {
58 	uint32_t val;
59 	vaddr_t va = core_mmu_get_va(SRC_BASE, MEM_AREA_IO_SEC, 1);
60 
61 	if (!va)
62 		EMSG("No SRC mapping\n");
63 
64 	if ((core_idx == 0) || (core_idx >= CFG_TEE_CORE_NB_CORE))
65 		return PSCI_RET_INVALID_PARAMETERS;
66 
67 	/* set secondary cores' NS entry addresses */
68 	boot_set_core_ns_entry(core_idx, entry, context_id);
69 
70 	val = virt_to_phys((void *)TEE_TEXT_VA_START);
71 
72 #ifdef CFG_MX7
73 	io_write32(va + SRC_GPR1_MX7 + core_idx * 8, val);
74 
75 	imx_gpcv2_set_core1_pup_by_software();
76 
77 	/* release secondary core */
78 	val = io_read32(va + SRC_A7RCR1);
79 	val |=  BIT32(SRC_A7RCR1_A7_CORE1_ENABLE_OFFSET +
80 			(core_idx - 1));
81 	io_write32(va + SRC_A7RCR1, val);
82 #else
83 	/* boot secondary cores from OP-TEE load address */
84 	io_write32(va + SRC_GPR1 + core_idx * 8, val);
85 
86 	/* release secondary core */
87 	val = io_read32(va + SRC_SCR);
88 	val |=  BIT32(SRC_SCR_CORE1_ENABLE_OFFSET + (core_idx - 1));
89 	val |=  BIT32(SRC_SCR_CORE1_RST_OFFSET + (core_idx - 1));
90 	io_write32(va + SRC_SCR, val);
91 
92 	imx_set_src_gpr(core_idx, 0);
93 #endif /* CFG_MX7 */
94 
95 	return PSCI_RET_SUCCESS;
96 }
97 
psci_cpu_off(void)98 int __noreturn psci_cpu_off(void)
99 {
100 	uint32_t core_id;
101 
102 	core_id = get_core_pos();
103 
104 	DMSG("core_id: %" PRIu32, core_id);
105 
106 	psci_armv7_cpu_off();
107 
108 	imx_set_src_gpr(core_id, UINT32_MAX);
109 
110 	thread_mask_exceptions(THREAD_EXCP_ALL);
111 
112 	while (true)
113 		wfi();
114 }
115 
psci_affinity_info(uint32_t affinity,uint32_t lowest_affnity_level __unused)116 int psci_affinity_info(uint32_t affinity,
117 		       uint32_t lowest_affnity_level __unused)
118 {
119 	vaddr_t va = core_mmu_get_va(SRC_BASE, MEM_AREA_IO_SEC, 1);
120 	vaddr_t gpr5 = core_mmu_get_va(IOMUXC_BASE, MEM_AREA_IO_SEC,
121 				       IOMUXC_GPR5_OFFSET + sizeof(uint32_t)) +
122 				       IOMUXC_GPR5_OFFSET;
123 	uint32_t cpu, val;
124 	bool wfi;
125 
126 	cpu = affinity;
127 
128 	if (soc_is_imx7ds())
129 		wfi = true;
130 	else
131 		wfi = io_read32(gpr5) & ARM_WFI_STAT_MASK(cpu);
132 
133 	if ((imx_get_src_gpr(cpu) == 0) || !wfi)
134 		return PSCI_AFFINITY_LEVEL_ON;
135 
136 	DMSG("cpu: %" PRIu32 "GPR: %" PRIx32, cpu, imx_get_src_gpr(cpu));
137 	/*
138 	 * Wait secondary cpus ready to be killed
139 	 * TODO: Change to non dead loop
140 	 */
141 	if (soc_is_imx7ds()) {
142 		while (io_read32(va + SRC_GPR1_MX7 + cpu * 8 + 4) != UINT_MAX)
143 			;
144 
145 		val = io_read32(va + SRC_A7RCR1);
146 		val &=  ~BIT32(SRC_A7RCR1_A7_CORE1_ENABLE_OFFSET + (cpu - 1));
147 		io_write32(va + SRC_A7RCR1, val);
148 	} else {
149 		while (io_read32(va + SRC_GPR1 + cpu * 8 + 4) != UINT32_MAX)
150 			;
151 
152 		/* Kill cpu */
153 		val = io_read32(va + SRC_SCR);
154 		val &= ~BIT32(SRC_SCR_CORE1_ENABLE_OFFSET + cpu - 1);
155 		val |=  BIT32(SRC_SCR_CORE1_RST_OFFSET + cpu - 1);
156 		io_write32(va + SRC_SCR, val);
157 	}
158 
159 	/* Clean arg */
160 	imx_set_src_gpr(cpu, 0);
161 
162 	return PSCI_AFFINITY_LEVEL_OFF;
163 }
164 #endif
165 
psci_system_off(void)166 void __noreturn psci_system_off(void)
167 {
168 #ifndef CFG_MX7ULP
169 	vaddr_t snvs_base = core_mmu_get_va(SNVS_BASE, MEM_AREA_IO_SEC, 1);
170 
171 	io_write32(snvs_base + SNVS_LPCR_OFF,
172 		   SNVS_LPCR_TOP_MASK |
173 		   SNVS_LPCR_DP_EN_MASK |
174 		   SNVS_LPCR_SRTC_ENV_MASK);
175 	dsb();
176 #endif
177 
178 	while (1)
179 		;
180 }
181 
imx7d_lowpower_idle(uint32_t power_state __unused,uintptr_t entry __unused,uint32_t context_id __unused,struct sm_nsec_ctx * nsec __unused)182 __weak int imx7d_lowpower_idle(uint32_t power_state __unused,
183 			uintptr_t entry __unused,
184 			uint32_t context_id __unused,
185 			struct sm_nsec_ctx *nsec __unused)
186 {
187 	return 0;
188 }
189 
imx7_cpu_suspend(uint32_t power_state __unused,uintptr_t entry __unused,uint32_t context_id __unused,struct sm_nsec_ctx * nsec __unused)190 __weak int imx7_cpu_suspend(uint32_t power_state __unused,
191 			    uintptr_t entry __unused,
192 			    uint32_t context_id __unused,
193 			    struct sm_nsec_ctx *nsec __unused)
194 {
195 	return 0;
196 }
197 
psci_cpu_suspend(uint32_t power_state,uintptr_t entry,uint32_t context_id __unused,struct sm_nsec_ctx * nsec)198 int psci_cpu_suspend(uint32_t power_state,
199 		     uintptr_t entry, uint32_t context_id __unused,
200 		     struct sm_nsec_ctx *nsec)
201 {
202 	uint32_t id, type;
203 	int ret = PSCI_RET_INVALID_PARAMETERS;
204 
205 	id = power_state & PSCI_POWER_STATE_ID_MASK;
206 	type = (power_state & PSCI_POWER_STATE_TYPE_MASK) >>
207 		PSCI_POWER_STATE_TYPE_SHIFT;
208 
209 	if ((type != PSCI_POWER_STATE_TYPE_POWER_DOWN) &&
210 	    (type != PSCI_POWER_STATE_TYPE_STANDBY)) {
211 		DMSG("Not supported %x\n", type);
212 		return ret;
213 	}
214 
215 	/*
216 	 * ID 0 means suspend
217 	 * ID 1 means low power idle
218 	 * TODO: follow PSCI StateID sample encoding.
219 	 */
220 	DMSG("ID = %d\n", id);
221 	if (id == 1) {
222 		if (soc_is_imx7ds())
223 			return imx7d_lowpower_idle(power_state, entry,
224 						   context_id, nsec);
225 		return ret;
226 	} else if (id == 0) {
227 		if (soc_is_imx7ds()) {
228 			return imx7_cpu_suspend(power_state, entry,
229 						context_id, nsec);
230 		}
231 		return ret;
232 	}
233 
234 	DMSG("ID %d not supported\n", id);
235 
236 	return ret;
237 }
238 
psci_system_reset(void)239 void __noreturn psci_system_reset(void)
240 {
241 	imx_wdog_restart(true);
242 }
243 
psci_system_reset2(uint32_t reset_type __unused,uint32_t cookie __unused)244 int __noreturn psci_system_reset2(uint32_t reset_type __unused,
245 				  uint32_t cookie __unused)
246 {
247 	/* force WDOG reset */
248 	imx_wdog_restart(false);
249 }
250