1 /*
2 * Copyright : (C) 2023 Phytium Information Technology, Inc.
3 * All Rights Reserved.
4 *
5 * This program is OPEN SOURCE software: you can redistribute it and/or modify it
6 * under the terms of the Phytium Public License as published by the Phytium Technology Co.,Ltd,
7 * either version 1.0 of the License, or (at your option) any later version.
8 *
9 * This program is distributed in the hope that it will be useful,but WITHOUT ANY WARRANTY;
10 * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
11 * See the Phytium Public License for more details.
12 *
13 *
14 * FilePath: fpsci.c
15 * Created Date: 2023-06-21 10:36:53
16 * Last Modified: 2023-06-30 13:32:06
17 * Description: This file is for
18 *
19 * Modify History:
20 * Ver Who Date Changes
21 * ----- ---------- -------- ---------------------------------
22 * 1.0 huanghe 2023-06-21 first release
23 */
24
25
26 #include <stdio.h>
27 #include "fsmcc.h" /* 根据你的平台和编译环境来确定这个路径 */
28 #include "fpsci.h"
29 #include "fassert.h"
30 #include "fcompiler.h"
31 #include "fcpu_info.h"
32 #include "rtdbg.h"
33
34 /* 定义PSCI 函数值 */
35 #define FPSCI_0_2_FN32_BASE 0x84000000
36 #define FPSCI_0_2_FN64_BASE 0xC4000000
37 #define FPSCI_VERSION (FPSCI_0_2_FN32_BASE + 0x000)
38 #define FPSCI_FEATURES (FPSCI_0_2_FN32_BASE + 0x00a)
39 #define FPSCI_CPU_SUSPEND_AARCH32 (FPSCI_0_2_FN32_BASE + 0x001)
40 #define FPSCI_CPU_SUSPEND_AARCH64 (FPSCI_0_2_FN64_BASE + 0x001)
41 #define FPSCI_CPU_OFF (FPSCI_0_2_FN32_BASE + 0x002)
42 #define FPSCI_CPU_ON_AARCH32 (FPSCI_0_2_FN32_BASE + 0x003)
43 #define FPSCI_CPU_ON_AARCH64 (FPSCI_0_2_FN64_BASE + 0x003)
44 #define FPSCI_FAFFINITY_INFO_AARCH32 (FPSCI_0_2_FN32_BASE + 0x004)
45 #define FPSCI_FAFFINITY_INFO_AARCH64 (FPSCI_0_2_FN64_BASE + 0x004)
46 #define FPSCI_SYSTEM_OFF (FPSCI_0_2_FN32_BASE + 0x008)
47 #define FPSCI_SYSTEM_RESET (FPSCI_0_2_FN32_BASE + 0x009)
48 #define FPSCI_SYSTEM_SUSPEND (FPSCI_0_2_FN32_BASE + 0x00E)
49
50 /* 定义每个PSCI函数ID的位标记 */
51 #define FPSCI_PSCI_VERSION_BIT (1 << 0)
52 #define FPSCI_PSCI_FEATURES_BIT (1 << 1)
53 #define FPSCI_CPU_SUSPEND_AARCH32_BIT (1 << 2)
54 #define FPSCI_CPU_SUSPEND_AARCH64_BIT (1 << 3)
55 #define FPSCI_CPU_OFF_BIT (1 << 4)
56 #define FPSCI_CPU_ON_AARCH32_BIT (1 << 5)
57 #define FPSCI_CPU_ON_AARCH64_BIT (1 << 6)
58 #define FPSCI_AFFINITY_INFO_AARCH32_BIT (1 << 7)
59 #define FPSCI_AFFINITY_INFO_AARCH64_BIT (1 << 8)
60 #define FPSCI_SYSTEM_OFF_BIT (1 << 9)
61 #define FPSCI_SYSTEM_RESET_BIT (1 << 10)
62
63
64 static int fpsci_ringt_bit_flg = 0;
65
66 /* 定义函数指针 */
67 typedef void (*FPsciInvokeFun)(unsigned long arg0, unsigned long arg1,
68 unsigned long arg2, unsigned long arg3,
69 unsigned long arg4, unsigned long arg5,
70 unsigned long arg6, unsigned long arg7,
71 struct FSmcccRes *res);
72
73 /* 为函数指针初始化为默认的函数 */
74 FPsciInvokeFun f_psci_invoke = FSmcccSmcCall;
75
76
77 /**
78 * @name: FPsciVersion
79 * @msg: Get the version of the PSCI implementation.
80 * @return {int}: The version information of the PSCI implementation.
81 * @note: This function returns the version information obtained from the PSCI VERSION function.
82 */
FPsciVersion(void)83 int FPsciVersion(void)
84 {
85 struct FSmcccRes res;
86 FASSERT((*f_psci_invoke));
87 (*f_psci_invoke)(FPSCI_VERSION, 0, 0, 0, 0, 0, 0, 0, &res);
88 return res.a0;
89 }
90
91 /**
92 * @name: FPsciFeatures
93 * @msg: Check whether a PSCI function is supported.
94 * @param {u32} psci_fid: The function ID of the PSCI function to be checked.
95 * @return {int}: 1 if the function is supported; 0 otherwise.
96 * @note: This function returns whether the PSCI function represented by psci_fid is supported or not.
97 */
FPsciFeatures(u32 psci_fid)98 int FPsciFeatures(u32 psci_fid)
99 {
100 struct FSmcccRes res;
101 FASSERT((*f_psci_invoke));
102 (*f_psci_invoke)(FPSCI_FEATURES, psci_fid, 0, 0, 0, 0, 0, 0, &res);
103 return res.a0 == FPSCI_SUCCESS ? 1 : 0;
104 }
105
106 /**
107 * @name: FPsciCpuSuspend
108 * @msg: Suspend execution on a particular CPU.
109 * @param {u32} power_state: The power state to be entered.
110 * @param {unsigned long} entry_point_address: The address to be executed upon waking up.
111 * @param {unsigned long} context_id: The context-specific identifier.
112 * @return {int}: The status code of the operation, as defined by the PSCI specification.
113 * @note: This function suspends the execution on a particular CPU and returns a status code indicating whether the operation was successful or not.
114 */
FPsciCpuSuspend(u32 power_state,unsigned long entry_point_address,unsigned long context_id)115 int FPsciCpuSuspend(u32 power_state, unsigned long entry_point_address, unsigned long context_id)
116 {
117 struct FSmcccRes res;
118 FASSERT((fpsci_ringt_bit_flg & FPSCI_CPU_SUSPEND_AARCH32_BIT) != 0);
119 FASSERT((*f_psci_invoke));
120 (*f_psci_invoke)(FPSCI_CPU_SUSPEND_AARCH32, power_state, entry_point_address, context_id, 0, 0, 0, 0, &res);
121 return res.a0;
122 }
123
124
125 /**
126 * @name: FPsciCpuOn
127 * @msg: Power on a particular CPU.
128 * @param {unsigned long} target_cpu: The target CPU to be powered on.
129 * @param {unsigned long} entry_point_address: The address to be executed upon waking up.
130 * @param {unsigned long} context_id: The context-specific identifier.
131 * @return {int}: The status code of the operation, as defined by the PSCI specification.
132 * @note: This function powers on a particular CPU and returns a status code indicating whether the operation was successful or not.
133 */
FPsciCpuOn(unsigned long target_cpu,unsigned long entry_point_address,unsigned long context_id)134 int FPsciCpuOn(unsigned long target_cpu, unsigned long entry_point_address, unsigned long context_id)
135 {
136 struct FSmcccRes res;
137 unsigned long cpu_on_id ;
138
139 #if defined(FAARCH64_USE)
140 cpu_on_id = FPSCI_CPU_ON_AARCH64 ;
141 #else
142 cpu_on_id = FPSCI_CPU_ON_AARCH32;
143 #endif
144
145 FASSERT((fpsci_ringt_bit_flg & (FPSCI_CPU_ON_AARCH32_BIT | FPSCI_CPU_ON_AARCH64_BIT)) != 0);
146 FASSERT((*f_psci_invoke));
147 (*f_psci_invoke)(cpu_on_id, target_cpu, entry_point_address, context_id, 0, 0, 0, 0, &res);
148 return res.a0;
149 }
150
151 /**
152 * @name: FPsciCpuOff
153 * @msg: This is a wrapper for the PSCI CPU Off interface, intended to turn off the current CPU.
154 * @return: Returns the 'a0' field of the 'FSmcccRes' structure, indicating the result of the call. A return value of 0 (PSCI_SUCCESS) indicates success, any other value indicates an error occurred.
155 * @note: A core that is powered down by CPU_OFF can only be powered up again in response to a CPU_ON.
156 */
FPsciCpuOff(void)157 int FPsciCpuOff(void)
158 {
159 struct FSmcccRes res;
160 FASSERT((fpsci_ringt_bit_flg & FPSCI_CPU_OFF_BIT) != 0);
161 FASSERT((*f_psci_invoke));
162 (*f_psci_invoke)(FPSCI_CPU_OFF, 0, 0, 0, 0, 0, 0, 0, &res);
163 return res.a0;
164 }
165
166
167
168 /**
169 * @name: FPsciAffinityInfo
170 * @msg: Get the power state of a particular affinity level.
171 * @param {unsigned long} target_affinity: The target affinity level.
172 * @param {u32} lowest_affinity_level: The lowest affinity level.
173 * @return {int}: The power state of the specified affinity level, as defined by the PSCI specification.
174 * @note: This function returns the power state of a particular affinity level.
175 */
FPsciAffinityInfo(unsigned long target_affinity,u32 lowest_affinity_level)176 int FPsciAffinityInfo(unsigned long target_affinity, u32 lowest_affinity_level)
177 {
178 struct FSmcccRes res;
179 FASSERT((fpsci_ringt_bit_flg & (FPSCI_AFFINITY_INFO_AARCH32_BIT | FPSCI_AFFINITY_INFO_AARCH64_BIT)) != 0);
180 FASSERT((*f_psci_invoke));
181
182 (*f_psci_invoke)(FPSCI_FAFFINITY_INFO_AARCH32, target_affinity, lowest_affinity_level, 0, 0, 0, 0, 0, &res);
183 return res.a0;
184 }
185
186 /**
187 * @name: FPsciSystemReset
188 * @msg: Reset the system.
189 * @param {u32} reset_type: The type of the system reset (cold/warm).
190 * @note: This function resets the system. The reset type is specified by the parameter reset_type.
191 */
FPsciSystemReset(u32 reset_type)192 void FPsciSystemReset(u32 reset_type)
193 {
194 struct FSmcccRes res;
195 FASSERT((fpsci_ringt_bit_flg & FPSCI_SYSTEM_RESET_BIT) != 0);
196 FASSERT((*f_psci_invoke));
197 (*f_psci_invoke)(FPSCI_SYSTEM_RESET, reset_type, 0, 0, 0, 0, 0, 0, &res);
198 }
199
200
201 /**
202 * @name: FPsciCheckFeatures
203 * @msg: This function checks for the availability of various PSCI features and sets the corresponding bits in the 'fpsci_ringt_bit_flg' global flag accordingly.
204 * @return: This function does not return a value.
205 */
FPsciCheckFeatures(void)206 static void FPsciCheckFeatures(void)
207 {
208 LOG_I("Checking PSCI features...\r\n");
209 fpsci_ringt_bit_flg = 0 ;
210 if (FPsciFeatures(FPSCI_CPU_SUSPEND_AARCH32))
211 {
212 fpsci_ringt_bit_flg |= FPSCI_CPU_SUSPEND_AARCH32_BIT;
213 LOG_I("CPU_SUSPEND_AARCH32 supported.\r\n");
214 }
215 else
216 {
217 LOG_E("CPU_SUSPEND_AARCH32 not supported.\r\n");
218 }
219
220 if (FPsciFeatures(FPSCI_CPU_OFF))
221 {
222 fpsci_ringt_bit_flg |= FPSCI_CPU_OFF_BIT;
223 LOG_I("CPU_OFF supported.\r\n");
224 }
225 else
226 {
227 LOG_E("CPU_OFF not supported.\r\n");
228 }
229
230 #if defined(FAARCH64_USE)
231 if (FPsciFeatures(FPSCI_CPU_ON_AARCH64))
232 {
233 fpsci_ringt_bit_flg |= FPSCI_CPU_ON_AARCH64_BIT;
234 LOG_I("CPU_ON_AARCH64 supported.\r\n");
235 }
236 else
237 {
238 LOG_E("CPU_ON_AARCH64 not supported.\r\n");
239 }
240 #else
241 if (FPsciFeatures(FPSCI_CPU_ON_AARCH32))
242 {
243 fpsci_ringt_bit_flg |= FPSCI_CPU_ON_AARCH32_BIT;
244 LOG_I("CPU_ON_AARCH32 supported.\r\n");
245 }
246 else
247 {
248 LOG_E("CPU_ON_AARCH32 not supported.\r\n");
249 }
250 #endif
251
252
253 #if defined(FAARCH64_USE)
254 if (FPsciFeatures(FPSCI_FAFFINITY_INFO_AARCH64))
255 {
256 fpsci_ringt_bit_flg |= FPSCI_AFFINITY_INFO_AARCH64_BIT;
257 LOG_I("AFFINITY_INFO_AARCH64 supported.\r\n");
258 }
259 else
260 {
261 LOG_E("AFFINITY_INFO_AARCH64 not supported.\r\n");
262 }
263
264 #else
265 if (FPsciFeatures(FPSCI_FAFFINITY_INFO_AARCH32))
266 {
267 fpsci_ringt_bit_flg |= FPSCI_AFFINITY_INFO_AARCH32_BIT;
268 LOG_I("FPSCI_AFFINITY_INFO_AARCH32 supported.\r\n");
269 }
270 else
271 {
272 LOG_E("AFFINITY_INFO_AARCH32 not supported.\r\n");
273 }
274 #endif
275
276 if (FPsciFeatures(FPSCI_SYSTEM_OFF))
277 {
278 fpsci_ringt_bit_flg |= FPSCI_SYSTEM_OFF_BIT;
279 LOG_I("SYSTEM_OFF supported.\r\n");
280 }
281 else
282 {
283 LOG_E("SYSTEM_OFF not supported.\r\n");
284 }
285
286 if (FPsciFeatures(FPSCI_SYSTEM_RESET))
287 {
288 fpsci_ringt_bit_flg |= FPSCI_SYSTEM_RESET_BIT;
289 LOG_I("SYSTEM_RESET supported.\r\n");
290 }
291 else
292 {
293 LOG_E("SYSTEM_RESET not supported.\r\n");
294 }
295 }
296
297
298 /**
299 * @name: FPsci_CpuOn
300 * @msg: Power up a core
301 * @in param cpu_id_mask: cpu id mask
302 * @in param bootaddr: a 32-bit entry point physical address (or IPA).
303 * @return int
304 */
FPsciCpuMaskOn(s32 cpu_id_mask,uintptr bootaddr)305 int FPsciCpuMaskOn(s32 cpu_id_mask, uintptr bootaddr)
306 {
307 FError ret ;
308 u64 cluster = 0;
309 ret = GetCpuAffinityByMask(cpu_id_mask, &cluster);
310 if (ret != ERR_SUCCESS)
311 {
312 return FPSCI_INVALID_PARAMS;
313 }
314 return FPsciCpuOn(cluster, (unsigned long)bootaddr, 0) ;
315 }
316
317
FSmccInit(int method)318 static void FSmccInit(int method)
319 {
320 if (method == 1)
321 {
322 f_psci_invoke = FSmcccHvcCall;
323 }
324 else
325 {
326 f_psci_invoke = FSmcccSmcCall;
327 }
328 }
329
FPsciInit(void)330 int FPsciInit(void)
331 {
332 int psci_version = 0;
333 FSmccInit(0);
334 psci_version = FPsciVersion() ;
335 LOG_I("major is 0x%x,minor is 0x%x \r\n", FPSCI_MAJOR_VERSION(psci_version), FPSCI_MINOR_VERSION(psci_version)) ;
336 FPsciCheckFeatures();
337 return 0;
338 }
339
340
341
342