]> git.proxmox.com Git - mirror_edk2.git/blame - ArmPkg/Drivers/ArmScmiDxe/ScmiClockProtocol.c
ArmPkg: Fix Ecc error 5007 in CpuDxe
[mirror_edk2.git] / ArmPkg / Drivers / ArmScmiDxe / ScmiClockProtocol.c
CommitLineData
4f2494cf
GP
1/** @file\r
2\r
3f0d3dfa 3 Copyright (c) 2017-2021, Arm Limited. All rights reserved.\r
4f2494cf 4\r
4059386c 5 SPDX-License-Identifier: BSD-2-Clause-Patent\r
4f2494cf
GP
6\r
7 System Control and Management Interface V1.0\r
8 http://infocenter.arm.com/help/topic/com.arm.doc.den0056a/\r
9 DEN0056A_System_Control_and_Management_Interface.pdf\r
10**/\r
11\r
12#include <Library/BaseLib.h>\r
13#include <Library/DebugLib.h>\r
14#include <Library/UefiBootServicesTableLib.h>\r
15#include <Protocol/ArmScmiClockProtocol.h>\r
559a07d8 16#include <Protocol/ArmScmiClock2Protocol.h>\r
4f2494cf
GP
17\r
18#include "ArmScmiClockProtocolPrivate.h"\r
19#include "ScmiPrivate.h"\r
20\r
21/** Convert to 64 bit value from two 32 bit words.\r
22\r
23 @param[in] Low Lower 32 bits.\r
24 @param[in] High Higher 32 bits.\r
25\r
26 @retval UINT64 64 bit value.\r
27**/\r
28STATIC\r
29UINT64\r
30ConvertTo64Bit (\r
31 IN UINT32 Low,\r
32 IN UINT32 High\r
33 )\r
34{\r
35 return (Low | ((UINT64)High << 32));\r
36}\r
37\r
38/** Return version of the clock management protocol supported by SCP firmware.\r
39\r
40 @param[in] This A Pointer to SCMI_CLOCK_PROTOCOL Instance.\r
41\r
42 @param[out] Version Version of the supported SCMI Clock management protocol.\r
43\r
44 @retval EFI_SUCCESS The version is returned.\r
45 @retval EFI_DEVICE_ERROR SCP returns an SCMI error.\r
46 @retval !(EFI_SUCCESS) Other errors.\r
47**/\r
48STATIC\r
49EFI_STATUS\r
50ClockGetVersion (\r
51 IN SCMI_CLOCK_PROTOCOL *This,\r
52 OUT UINT32 *Version\r
53 )\r
54{\r
55 return ScmiGetProtocolVersion (SCMI_PROTOCOL_ID_CLOCK, Version);\r
56}\r
57\r
58/** Return total number of clock devices supported by the clock management\r
59 protocol.\r
60\r
61 @param[in] This A Pointer to SCMI_CLOCK_PROTOCOL Instance.\r
62\r
63 @param[out] TotalClocks Total number of clocks supported.\r
64\r
65 @retval EFI_SUCCESS Total number of clocks supported is returned.\r
66 @retval EFI_DEVICE_ERROR SCP returns an SCMI error.\r
67 @retval !(EFI_SUCCESS) Other errors.\r
68**/\r
69STATIC\r
70EFI_STATUS\r
71ClockGetTotalClocks (\r
72 IN SCMI_CLOCK_PROTOCOL *This,\r
73 OUT UINT32 *TotalClocks\r
74 )\r
75{\r
76 EFI_STATUS Status;\r
77 UINT32 *ReturnValues;\r
78\r
79 Status = ScmiGetProtocolAttributes (SCMI_PROTOCOL_ID_CLOCK, &ReturnValues);\r
80 if (EFI_ERROR (Status)) {\r
81 return Status;\r
82 }\r
83\r
84 *TotalClocks = SCMI_CLOCK_PROTOCOL_TOTAL_CLKS (ReturnValues[0]);\r
85\r
86 return EFI_SUCCESS;\r
87}\r
88\r
89/** Return attributes of a clock device.\r
90\r
91 @param[in] This A Pointer to SCMI_CLOCK_PROTOCOL Instance.\r
92 @param[in] ClockId Identifier for the clock device.\r
93\r
94 @param[out] Enabled If TRUE, the clock device is enabled.\r
95 @param[out] ClockAsciiName A NULL terminated ASCII string with the clock\r
96 name, of up to 16 bytes.\r
97\r
98 @retval EFI_SUCCESS Clock device attributes are returned.\r
99 @retval EFI_DEVICE_ERROR SCP returns an SCMI error.\r
100 @retval !(EFI_SUCCESS) Other errors.\r
101**/\r
102STATIC\r
103EFI_STATUS\r
104ClockGetClockAttributes (\r
105 IN SCMI_CLOCK_PROTOCOL *This,\r
106 IN UINT32 ClockId,\r
107 OUT BOOLEAN *Enabled,\r
108 OUT CHAR8 *ClockAsciiName\r
109 )\r
110{\r
111 EFI_STATUS Status;\r
112\r
113 UINT32 *MessageParams;\r
114 CLOCK_ATTRIBUTES *ClockAttributes;\r
115 SCMI_COMMAND Cmd;\r
116 UINT32 PayloadLength;\r
117\r
118 Status = ScmiCommandGetPayload (&MessageParams);\r
119 if (EFI_ERROR (Status)) {\r
120 return Status;\r
121 }\r
122\r
123 *MessageParams = ClockId;\r
124\r
125 Cmd.ProtocolId = SCMI_PROTOCOL_ID_CLOCK;\r
126 Cmd.MessageId = SCMI_MESSAGE_ID_CLOCK_ATTRIBUTES;\r
127\r
128 PayloadLength = sizeof (ClockId);\r
129\r
130 Status = ScmiCommandExecute (\r
131 &Cmd,\r
132 &PayloadLength,\r
133 (UINT32**)&ClockAttributes\r
134 );\r
135 if (EFI_ERROR (Status)) {\r
136 return Status;\r
137 }\r
138 // TRUE if bit 0 of ClockAttributes->Attributes is set.\r
139 *Enabled = CLOCK_ENABLED (ClockAttributes->Attributes);\r
140\r
141 AsciiStrCpyS (\r
142 ClockAsciiName,\r
143 SCMI_MAX_STR_LEN,\r
144 (CONST CHAR8*)ClockAttributes->ClockName\r
145 );\r
146\r
147 return EFI_SUCCESS;\r
148}\r
149\r
150/** Return list of rates supported by a given clock device.\r
151\r
152 @param[in] This A pointer to SCMI_CLOCK_PROTOCOL Instance.\r
153 @param[in] ClockId Identifier for the clock device.\r
154\r
155 @param[out] Format SCMI_CLOCK_RATE_FORMAT_DISCRETE: Clock device\r
156 supports range of clock rates which are non-linear.\r
157\r
158 SCMI_CLOCK_RATE_FORMAT_LINEAR: Clock device supports\r
159 range of linear clock rates from Min to Max in steps.\r
160\r
161 @param[out] TotalRates Total number of rates.\r
162\r
163 @param[in,out] RateArraySize Size of the RateArray.\r
164\r
165 @param[out] RateArray List of clock rates.\r
166\r
167 @retval EFI_SUCCESS List of clock rates is returned.\r
168 @retval EFI_DEVICE_ERROR SCP returns an SCMI error.\r
169 @retval EFI_BUFFER_TOO_SMALL RateArraySize is too small for the result.\r
170 It has been updated to the size needed.\r
171 @retval !(EFI_SUCCESS) Other errors.\r
172**/\r
173STATIC\r
174EFI_STATUS\r
175ClockDescribeRates (\r
176 IN SCMI_CLOCK_PROTOCOL *This,\r
177 IN UINT32 ClockId,\r
178 OUT SCMI_CLOCK_RATE_FORMAT *Format,\r
179 OUT UINT32 *TotalRates,\r
180 IN OUT UINT32 *RateArraySize,\r
181 OUT SCMI_CLOCK_RATE *RateArray\r
182 )\r
183{\r
184 EFI_STATUS Status;\r
185\r
186 UINT32 PayloadLength;\r
187 SCMI_COMMAND Cmd;\r
188 UINT32 *MessageParams;\r
189 CLOCK_DESCRIBE_RATES *DescribeRates;\r
190 CLOCK_RATE_DWORD *Rate;\r
191\r
3f0d3dfa
PG
192 UINT32 RequiredArraySize;\r
193 UINT32 RateIndex;\r
4f2494cf
GP
194 UINT32 RateNo;\r
195 UINT32 RateOffset;\r
196\r
197 *TotalRates = 0;\r
3f0d3dfa
PG
198 RequiredArraySize = 0;\r
199 RateIndex = 0;\r
4f2494cf
GP
200\r
201 Status = ScmiCommandGetPayload (&MessageParams);\r
202 if (EFI_ERROR (Status)) {\r
203 return Status;\r
204 }\r
205\r
206 Cmd.ProtocolId = SCMI_PROTOCOL_ID_CLOCK;\r
207 Cmd.MessageId = SCMI_MESSAGE_ID_CLOCK_DESCRIBE_RATES;\r
208\r
209 *MessageParams++ = ClockId;\r
210\r
211 do {\r
212\r
213 *MessageParams = RateIndex;\r
214\r
215 // Set Payload length, note PayloadLength is a IN/OUT parameter.\r
216 PayloadLength = sizeof (ClockId) + sizeof (RateIndex);\r
217\r
218 // Execute and wait for response on a SCMI channel.\r
219 Status = ScmiCommandExecute (\r
220 &Cmd,\r
221 &PayloadLength,\r
222 (UINT32**)&DescribeRates\r
223 );\r
224 if (EFI_ERROR (Status)) {\r
225 return Status;\r
226 }\r
227\r
228 if (*TotalRates == 0) {\r
229 // In the first iteration we will get number of returned rates and number\r
230 // of remaining rates. With this information calculate required size\r
231 // for rate array. If provided RateArraySize is less, return an\r
232 // error.\r
233\r
234 *Format = RATE_FORMAT (DescribeRates->NumRatesFlags);\r
235\r
236 *TotalRates = NUM_RATES (DescribeRates->NumRatesFlags)\r
237 + NUM_REMAIN_RATES (DescribeRates->NumRatesFlags);\r
238\r
239 if (*Format == SCMI_CLOCK_RATE_FORMAT_DISCRETE) {\r
240 RequiredArraySize = (*TotalRates) * sizeof (UINT64);\r
241 } else {\r
242 // We need to return triplet of 64 bit value for each rate\r
243 RequiredArraySize = (*TotalRates) * 3 * sizeof (UINT64);\r
244 }\r
245\r
246 if (RequiredArraySize > (*RateArraySize)) {\r
247 *RateArraySize = RequiredArraySize;\r
248 return EFI_BUFFER_TOO_SMALL;\r
249 }\r
250 }\r
251\r
252 RateOffset = 0;\r
253\r
254 if (*Format == SCMI_CLOCK_RATE_FORMAT_DISCRETE) {\r
255 for (RateNo = 0; RateNo < NUM_RATES (DescribeRates->NumRatesFlags); RateNo++) {\r
256 Rate = &DescribeRates->Rates[RateOffset++];\r
257 // Non-linear discrete rates.\r
258 RateArray[RateIndex++].Rate = ConvertTo64Bit (Rate->Low, Rate->High);\r
259 }\r
260 } else {\r
261 for (RateNo = 0; RateNo < NUM_RATES (DescribeRates->NumRatesFlags); RateNo++) {\r
262 // Linear clock rates from minimum to maximum in steps\r
263 // Minimum clock rate.\r
264 Rate = &DescribeRates->Rates[RateOffset++];\r
265 RateArray[RateIndex].Min = ConvertTo64Bit (Rate->Low, Rate->High);\r
266\r
267 Rate = &DescribeRates->Rates[RateOffset++];\r
268 // Maximum clock rate.\r
269 RateArray[RateIndex].Max = ConvertTo64Bit (Rate->Low, Rate->High);\r
270\r
271 Rate = &DescribeRates->Rates[RateOffset++];\r
272 // Step.\r
273 RateArray[RateIndex++].Step = ConvertTo64Bit (Rate->Low, Rate->High);\r
274 }\r
275 }\r
276 } while (NUM_REMAIN_RATES (DescribeRates->NumRatesFlags) != 0);\r
277\r
278 // Update RateArraySize with RequiredArraySize.\r
279 *RateArraySize = RequiredArraySize;\r
280\r
281 return EFI_SUCCESS;\r
282}\r
283\r
284/** Get clock rate.\r
285\r
286 @param[in] This A Pointer to SCMI_CLOCK_PROTOCOL Instance.\r
287 @param[in] ClockId Identifier for the clock device.\r
288\r
289 @param[out] Rate Clock rate.\r
290\r
291 @retval EFI_SUCCESS Clock rate is returned.\r
292 @retval EFI_DEVICE_ERROR SCP returns an SCMI error.\r
293 @retval !(EFI_SUCCESS) Other errors.\r
294**/\r
295STATIC\r
296EFI_STATUS\r
297ClockRateGet (\r
298 IN SCMI_CLOCK_PROTOCOL *This,\r
299 IN UINT32 ClockId,\r
300 OUT UINT64 *Rate\r
301 )\r
302{\r
303 EFI_STATUS Status;\r
304\r
305 UINT32 *MessageParams;\r
306 CLOCK_RATE_DWORD *ClockRate;\r
307 SCMI_COMMAND Cmd;\r
308\r
309 UINT32 PayloadLength;\r
310\r
311 Status = ScmiCommandGetPayload (&MessageParams);\r
312 if (EFI_ERROR (Status)) {\r
313 return Status;\r
314 }\r
315\r
316 // Fill arguments for clock protocol command.\r
317 *MessageParams = ClockId;\r
318\r
319 Cmd.ProtocolId = SCMI_PROTOCOL_ID_CLOCK;\r
320 Cmd.MessageId = SCMI_MESSAGE_ID_CLOCK_RATE_GET;\r
321\r
322 PayloadLength = sizeof (ClockId);\r
323\r
324 // Execute and wait for response on a SCMI channel.\r
325 Status = ScmiCommandExecute (\r
326 &Cmd,\r
327 &PayloadLength,\r
328 (UINT32**)&ClockRate\r
329 );\r
330 if (EFI_ERROR (Status)) {\r
331 return Status;\r
332 }\r
333\r
334 *Rate = ConvertTo64Bit (ClockRate->Low, ClockRate->High);\r
335\r
336 return EFI_SUCCESS;\r
337}\r
338\r
339/** Set clock rate.\r
340\r
341 @param[in] This A Pointer to SCMI_CLOCK_PROTOCOL Instance.\r
342 @param[in] ClockId Identifier for the clock device.\r
343 @param[in] Rate Clock rate.\r
344\r
345 @retval EFI_SUCCESS Clock rate set success.\r
346 @retval EFI_DEVICE_ERROR SCP returns an SCMI error.\r
347 @retval !(EFI_SUCCESS) Other errors.\r
348**/\r
349STATIC\r
350EFI_STATUS\r
351ClockRateSet (\r
352 IN SCMI_CLOCK_PROTOCOL *This,\r
353 IN UINT32 ClockId,\r
354 IN UINT64 Rate\r
355 )\r
356{\r
357 EFI_STATUS Status;\r
358 CLOCK_RATE_SET_ATTRIBUTES *ClockRateSetAttributes;\r
359 SCMI_COMMAND Cmd;\r
360 UINT32 PayloadLength;\r
361\r
362 Status = ScmiCommandGetPayload ((UINT32**)&ClockRateSetAttributes);\r
363 if (EFI_ERROR (Status)) {\r
364 return Status;\r
365 }\r
366\r
367 // Fill arguments for clock protocol command.\r
368 ClockRateSetAttributes->ClockId = ClockId;\r
369 ClockRateSetAttributes->Flags = CLOCK_SET_DEFAULT_FLAGS;\r
370 ClockRateSetAttributes->Rate.Low = (UINT32)Rate;\r
371 ClockRateSetAttributes->Rate.High = (UINT32)(Rate >> 32);\r
372\r
373 Cmd.ProtocolId = SCMI_PROTOCOL_ID_CLOCK;\r
374 Cmd.MessageId = SCMI_MESSAGE_ID_CLOCK_RATE_SET;\r
375\r
376 PayloadLength = sizeof (CLOCK_RATE_SET_ATTRIBUTES);\r
377\r
378 // Execute and wait for response on a SCMI channel.\r
379 Status = ScmiCommandExecute (\r
380 &Cmd,\r
381 &PayloadLength,\r
382 NULL\r
383 );\r
384\r
385 return Status;\r
386}\r
387\r
559a07d8
JB
388/** Enable/Disable specified clock.\r
389\r
390 @param[in] This A Pointer to SCMI_CLOCK_PROTOCOL Instance.\r
391 @param[in] ClockId Identifier for the clock device.\r
392 @param[in] Enable TRUE to enable, FALSE to disable.\r
393\r
394 @retval EFI_SUCCESS Clock enable/disable successful.\r
395 @retval EFI_DEVICE_ERROR SCP returns an SCMI error.\r
396 @retval !(EFI_SUCCESS) Other errors.\r
397**/\r
398STATIC\r
399EFI_STATUS\r
400ClockEnable (\r
401 IN SCMI_CLOCK2_PROTOCOL *This,\r
402 IN UINT32 ClockId,\r
403 IN BOOLEAN Enable\r
404 )\r
405{\r
406 EFI_STATUS Status;\r
407 CLOCK_CONFIG_SET_ATTRIBUTES *ClockConfigSetAttributes;\r
408 SCMI_COMMAND Cmd;\r
409 UINT32 PayloadLength;\r
410\r
411 Status = ScmiCommandGetPayload ((UINT32**)&ClockConfigSetAttributes);\r
412 if (EFI_ERROR (Status)) {\r
413 return Status;\r
414 }\r
415\r
416 // Fill arguments for clock protocol command.\r
417 ClockConfigSetAttributes->ClockId = ClockId;\r
418 ClockConfigSetAttributes->Attributes = Enable ? BIT0 : 0;\r
419\r
420 Cmd.ProtocolId = SCMI_PROTOCOL_ID_CLOCK;\r
421 Cmd.MessageId = SCMI_MESSAGE_ID_CLOCK_CONFIG_SET;\r
422\r
423 PayloadLength = sizeof (CLOCK_CONFIG_SET_ATTRIBUTES);\r
424\r
425 // Execute and wait for response on a SCMI channel.\r
426 Status = ScmiCommandExecute (\r
427 &Cmd,\r
428 &PayloadLength,\r
429 NULL\r
430 );\r
431\r
432 return Status;\r
433}\r
434\r
4f2494cf
GP
435// Instance of the SCMI clock management protocol.\r
436STATIC CONST SCMI_CLOCK_PROTOCOL ScmiClockProtocol = {\r
437 ClockGetVersion,\r
438 ClockGetTotalClocks,\r
439 ClockGetClockAttributes,\r
440 ClockDescribeRates,\r
441 ClockRateGet,\r
442 ClockRateSet\r
443 };\r
444\r
559a07d8
JB
445// Instance of the SCMI clock management protocol.\r
446STATIC CONST SCMI_CLOCK2_PROTOCOL ScmiClock2Protocol = {\r
447 (SCMI_CLOCK2_GET_VERSION)ClockGetVersion,\r
448 (SCMI_CLOCK2_GET_TOTAL_CLOCKS)ClockGetTotalClocks,\r
449 (SCMI_CLOCK2_GET_CLOCK_ATTRIBUTES)ClockGetClockAttributes,\r
450 (SCMI_CLOCK2_DESCRIBE_RATES)ClockDescribeRates,\r
451 (SCMI_CLOCK2_RATE_GET)ClockRateGet,\r
452 (SCMI_CLOCK2_RATE_SET)ClockRateSet,\r
453 SCMI_CLOCK2_PROTOCOL_VERSION,\r
454 ClockEnable\r
455 };\r
456\r
4f2494cf
GP
457/** Initialize clock management protocol and install protocol on a given handle.\r
458\r
459 @param[in] Handle Handle to install clock management protocol.\r
460\r
461 @retval EFI_SUCCESS Clock protocol interface installed successfully.\r
462**/\r
463EFI_STATUS\r
464ScmiClockProtocolInit (\r
465 IN EFI_HANDLE* Handle\r
466 )\r
467{\r
468 return gBS->InstallMultipleProtocolInterfaces (\r
469 Handle,\r
470 &gArmScmiClockProtocolGuid,\r
471 &ScmiClockProtocol,\r
559a07d8
JB
472 &gArmScmiClock2ProtocolGuid,\r
473 &ScmiClock2Protocol,\r
4f2494cf
GP
474 NULL\r
475 );\r
476}\r