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
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
|
/*
* Copyright : (C) 2023 Phytium Information Technology, Inc.
* All Rights Reserved.
*
* This program is OPEN SOURCE software: you can redistribute it and/or modify it
* under the terms of the Phytium Public License as published by the Phytium Technology Co.,Ltd,
* either version 1.0 of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,but WITHOUT ANY WARRANTY;
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
* See the Phytium Public License for more details.
*
*
* FilePath: fpsci.c
* Created Date: 2023-06-21 10:36:53
* Last Modified: 2023-06-30 13:32:06
* Description: This file is for
*
* Modify History:
* Ver Who Date Changes
* ----- ---------- -------- ---------------------------------
* 1.0 huanghe 2023-06-21 first release
*/
#include <stdio.h>
#include "fsmcc.h" /* 根据你的平台和编译环境来确定这个路径 */
#include "fpsci.h"
#include "fassert.h"
#include "fcompiler.h"
#include "fcpu_info.h"
#include "rtdbg.h"
/* 定义PSCI 函数值 */
#define FPSCI_0_2_FN32_BASE 0x84000000
#define FPSCI_0_2_FN64_BASE 0xC4000000
#define FPSCI_VERSION (FPSCI_0_2_FN32_BASE + 0x000)
#define FPSCI_FEATURES (FPSCI_0_2_FN32_BASE + 0x00a)
#define FPSCI_CPU_SUSPEND_AARCH32 (FPSCI_0_2_FN32_BASE + 0x001)
#define FPSCI_CPU_SUSPEND_AARCH64 (FPSCI_0_2_FN64_BASE + 0x001)
#define FPSCI_CPU_OFF (FPSCI_0_2_FN32_BASE + 0x002)
#define FPSCI_CPU_ON_AARCH32 (FPSCI_0_2_FN32_BASE + 0x003)
#define FPSCI_CPU_ON_AARCH64 (FPSCI_0_2_FN64_BASE + 0x003)
#define FPSCI_FAFFINITY_INFO_AARCH32 (FPSCI_0_2_FN32_BASE + 0x004)
#define FPSCI_FAFFINITY_INFO_AARCH64 (FPSCI_0_2_FN64_BASE + 0x004)
#define FPSCI_SYSTEM_OFF (FPSCI_0_2_FN32_BASE + 0x008)
#define FPSCI_SYSTEM_RESET (FPSCI_0_2_FN32_BASE + 0x009)
#define FPSCI_SYSTEM_SUSPEND (FPSCI_0_2_FN32_BASE + 0x00E)
/* 定义每个PSCI函数ID的位标记 */
#define FPSCI_PSCI_VERSION_BIT (1 << 0)
#define FPSCI_PSCI_FEATURES_BIT (1 << 1)
#define FPSCI_CPU_SUSPEND_AARCH32_BIT (1 << 2)
#define FPSCI_CPU_SUSPEND_AARCH64_BIT (1 << 3)
#define FPSCI_CPU_OFF_BIT (1 << 4)
#define FPSCI_CPU_ON_AARCH32_BIT (1 << 5)
#define FPSCI_CPU_ON_AARCH64_BIT (1 << 6)
#define FPSCI_AFFINITY_INFO_AARCH32_BIT (1 << 7)
#define FPSCI_AFFINITY_INFO_AARCH64_BIT (1 << 8)
#define FPSCI_SYSTEM_OFF_BIT (1 << 9)
#define FPSCI_SYSTEM_RESET_BIT (1 << 10)
static int fpsci_ringt_bit_flg = 0;
/* 定义函数指针 */
typedef void (*FPsciInvokeFun)(unsigned long arg0, unsigned long arg1,
unsigned long arg2, unsigned long arg3,
unsigned long arg4, unsigned long arg5,
unsigned long arg6, unsigned long arg7,
struct FSmcccRes *res);
/* 为函数指针初始化为默认的函数 */
FPsciInvokeFun f_psci_invoke = FSmcccSmcCall;
/**
* @name: FPsciVersion
* @msg: Get the version of the PSCI implementation.
* @return {int}: The version information of the PSCI implementation.
* @note: This function returns the version information obtained from the PSCI VERSION function.
*/
int FPsciVersion(void)
{
struct FSmcccRes res;
FASSERT((*f_psci_invoke));
(*f_psci_invoke)(FPSCI_VERSION, 0, 0, 0, 0, 0, 0, 0, &res);
return res.a0;
}
/**
* @name: FPsciFeatures
* @msg: Check whether a PSCI function is supported.
* @param {u32} psci_fid: The function ID of the PSCI function to be checked.
* @return {int}: 1 if the function is supported; 0 otherwise.
* @note: This function returns whether the PSCI function represented by psci_fid is supported or not.
*/
int FPsciFeatures(u32 psci_fid)
{
struct FSmcccRes res;
FASSERT((*f_psci_invoke));
(*f_psci_invoke)(FPSCI_FEATURES, psci_fid, 0, 0, 0, 0, 0, 0, &res);
return res.a0 == FPSCI_SUCCESS ? 1 : 0;
}
/**
* @name: FPsciCpuSuspend
* @msg: Suspend execution on a particular CPU.
* @param {u32} power_state: The power state to be entered.
* @param {unsigned long} entry_point_address: The address to be executed upon waking up.
* @param {unsigned long} context_id: The context-specific identifier.
* @return {int}: The status code of the operation, as defined by the PSCI specification.
* @note: This function suspends the execution on a particular CPU and returns a status code indicating whether the operation was successful or not.
*/
int FPsciCpuSuspend(u32 power_state, unsigned long entry_point_address, unsigned long context_id)
{
struct FSmcccRes res;
FASSERT((fpsci_ringt_bit_flg & FPSCI_CPU_SUSPEND_AARCH32_BIT) != 0);
FASSERT((*f_psci_invoke));
(*f_psci_invoke)(FPSCI_CPU_SUSPEND_AARCH32, power_state, entry_point_address, context_id, 0, 0, 0, 0, &res);
return res.a0;
}
/**
* @name: FPsciCpuOn
* @msg: Power on a particular CPU.
* @param {unsigned long} target_cpu: The target CPU to be powered on.
* @param {unsigned long} entry_point_address: The address to be executed upon waking up.
* @param {unsigned long} context_id: The context-specific identifier.
* @return {int}: The status code of the operation, as defined by the PSCI specification.
* @note: This function powers on a particular CPU and returns a status code indicating whether the operation was successful or not.
*/
int FPsciCpuOn(unsigned long target_cpu, unsigned long entry_point_address, unsigned long context_id)
{
struct FSmcccRes res;
unsigned long cpu_on_id ;
#if defined(FAARCH64_USE)
cpu_on_id = FPSCI_CPU_ON_AARCH64 ;
#else
cpu_on_id = FPSCI_CPU_ON_AARCH32;
#endif
FASSERT((fpsci_ringt_bit_flg & (FPSCI_CPU_ON_AARCH32_BIT | FPSCI_CPU_ON_AARCH64_BIT)) != 0);
FASSERT((*f_psci_invoke));
(*f_psci_invoke)(cpu_on_id, target_cpu, entry_point_address, context_id, 0, 0, 0, 0, &res);
return res.a0;
}
/**
* @name: FPsciCpuOff
* @msg: This is a wrapper for the PSCI CPU Off interface, intended to turn off the current CPU.
* @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.
* @note: A core that is powered down by CPU_OFF can only be powered up again in response to a CPU_ON.
*/
int FPsciCpuOff(void)
{
struct FSmcccRes res;
FASSERT((fpsci_ringt_bit_flg & FPSCI_CPU_OFF_BIT) != 0);
FASSERT((*f_psci_invoke));
(*f_psci_invoke)(FPSCI_CPU_OFF, 0, 0, 0, 0, 0, 0, 0, &res);
return res.a0;
}
/**
* @name: FPsciAffinityInfo
* @msg: Get the power state of a particular affinity level.
* @param {unsigned long} target_affinity: The target affinity level.
* @param {u32} lowest_affinity_level: The lowest affinity level.
* @return {int}: The power state of the specified affinity level, as defined by the PSCI specification.
* @note: This function returns the power state of a particular affinity level.
*/
int FPsciAffinityInfo(unsigned long target_affinity, u32 lowest_affinity_level)
{
struct FSmcccRes res;
FASSERT((fpsci_ringt_bit_flg & (FPSCI_AFFINITY_INFO_AARCH32_BIT | FPSCI_AFFINITY_INFO_AARCH64_BIT)) != 0);
FASSERT((*f_psci_invoke));
(*f_psci_invoke)(FPSCI_FAFFINITY_INFO_AARCH32, target_affinity, lowest_affinity_level, 0, 0, 0, 0, 0, &res);
return res.a0;
}
/**
* @name: FPsciSystemReset
* @msg: Reset the system.
* @param {u32} reset_type: The type of the system reset (cold/warm).
* @note: This function resets the system. The reset type is specified by the parameter reset_type.
*/
void FPsciSystemReset(u32 reset_type)
{
struct FSmcccRes res;
FASSERT((fpsci_ringt_bit_flg & FPSCI_SYSTEM_RESET_BIT) != 0);
FASSERT((*f_psci_invoke));
(*f_psci_invoke)(FPSCI_SYSTEM_RESET, reset_type, 0, 0, 0, 0, 0, 0, &res);
}
/**
* @name: FPsciCheckFeatures
* @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.
* @return: This function does not return a value.
*/
static void FPsciCheckFeatures(void)
{
LOG_I("Checking PSCI features...\r\n");
fpsci_ringt_bit_flg = 0 ;
if (FPsciFeatures(FPSCI_CPU_SUSPEND_AARCH32))
{
fpsci_ringt_bit_flg |= FPSCI_CPU_SUSPEND_AARCH32_BIT;
LOG_I("CPU_SUSPEND_AARCH32 supported.\r\n");
}
else
{
LOG_E("CPU_SUSPEND_AARCH32 not supported.\r\n");
}
if (FPsciFeatures(FPSCI_CPU_OFF))
{
fpsci_ringt_bit_flg |= FPSCI_CPU_OFF_BIT;
LOG_I("CPU_OFF supported.\r\n");
}
else
{
LOG_E("CPU_OFF not supported.\r\n");
}
#if defined(FAARCH64_USE)
if (FPsciFeatures(FPSCI_CPU_ON_AARCH64))
{
fpsci_ringt_bit_flg |= FPSCI_CPU_ON_AARCH64_BIT;
LOG_I("CPU_ON_AARCH64 supported.\r\n");
}
else
{
LOG_E("CPU_ON_AARCH64 not supported.\r\n");
}
#else
if (FPsciFeatures(FPSCI_CPU_ON_AARCH32))
{
fpsci_ringt_bit_flg |= FPSCI_CPU_ON_AARCH32_BIT;
LOG_I("CPU_ON_AARCH32 supported.\r\n");
}
else
{
LOG_E("CPU_ON_AARCH32 not supported.\r\n");
}
#endif
#if defined(FAARCH64_USE)
if (FPsciFeatures(FPSCI_FAFFINITY_INFO_AARCH64))
{
fpsci_ringt_bit_flg |= FPSCI_AFFINITY_INFO_AARCH64_BIT;
LOG_I("AFFINITY_INFO_AARCH64 supported.\r\n");
}
else
{
LOG_E("AFFINITY_INFO_AARCH64 not supported.\r\n");
}
#else
if (FPsciFeatures(FPSCI_FAFFINITY_INFO_AARCH32))
{
fpsci_ringt_bit_flg |= FPSCI_AFFINITY_INFO_AARCH32_BIT;
LOG_I("FPSCI_AFFINITY_INFO_AARCH32 supported.\r\n");
}
else
{
LOG_E("AFFINITY_INFO_AARCH32 not supported.\r\n");
}
#endif
if (FPsciFeatures(FPSCI_SYSTEM_OFF))
{
fpsci_ringt_bit_flg |= FPSCI_SYSTEM_OFF_BIT;
LOG_I("SYSTEM_OFF supported.\r\n");
}
else
{
LOG_E("SYSTEM_OFF not supported.\r\n");
}
if (FPsciFeatures(FPSCI_SYSTEM_RESET))
{
fpsci_ringt_bit_flg |= FPSCI_SYSTEM_RESET_BIT;
LOG_I("SYSTEM_RESET supported.\r\n");
}
else
{
LOG_E("SYSTEM_RESET not supported.\r\n");
}
}
/**
* @name: FPsci_CpuOn
* @msg: Power up a core
* @in param cpu_id_mask: cpu id mask
* @in param bootaddr: a 32-bit entry point physical address (or IPA).
* @return int
*/
int FPsciCpuMaskOn(s32 cpu_id_mask, uintptr bootaddr)
{
FError ret ;
u64 cluster = 0;
ret = GetCpuAffinityByMask(cpu_id_mask, &cluster);
if (ret != ERR_SUCCESS)
{
return FPSCI_INVALID_PARAMS;
}
return FPsciCpuOn(cluster, (unsigned long)bootaddr, 0) ;
}
static void FSmccInit(int method)
{
if (method == 1)
{
f_psci_invoke = FSmcccHvcCall;
}
else
{
f_psci_invoke = FSmcccSmcCall;
}
}
int FPsciInit(void)
{
int psci_version = 0;
FSmccInit(0);
psci_version = FPsciVersion() ;
LOG_I("major is 0x%x,minor is 0x%x \r\n", FPSCI_MAJOR_VERSION(psci_version), FPSCI_MINOR_VERSION(psci_version)) ;
FPsciCheckFeatures();
return 0;
}
|