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