]> git.proxmox.com Git - mirror_edk2.git/blame - ArmPkg/Drivers/ArmScmiDxe/ScmiClockProtocol.c
ArmPkg: Fix Ecc error 8005 for SCMI_CLOCK_RATE_FORMAT
[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
462f95ec 55 return ScmiGetProtocolVersion (ScmiProtocolIdClock, Version);\r
4f2494cf
GP
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
462f95ec 79 Status = ScmiGetProtocolAttributes (ScmiProtocolIdClock, &ReturnValues);\r
4f2494cf
GP
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
462f95ec 125 Cmd.ProtocolId = ScmiProtocolIdClock;\r
bd8efb4f 126 Cmd.MessageId = ScmiMessageIdClockAttributes;\r
4f2494cf
GP
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
063f8483 155 @param[out] Format ScmiClockRateFormatDiscrete: Clock device\r
4f2494cf
GP
156 supports range of clock rates which are non-linear.\r
157\r
063f8483 158 ScmiClockRateFormatLinear: Clock device supports\r
4f2494cf
GP
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
462f95ec 206 Cmd.ProtocolId = ScmiProtocolIdClock;\r
bd8efb4f 207 Cmd.MessageId = ScmiMessageIdClockDescribeRates;\r
4f2494cf
GP
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
063f8483 239 if (*Format == ScmiClockRateFormatDiscrete) {\r
4f2494cf
GP
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
063f8483 254 if (*Format == ScmiClockRateFormatDiscrete) {\r
4f2494cf
GP
255 for (RateNo = 0; RateNo < NUM_RATES (DescribeRates->NumRatesFlags); RateNo++) {\r
256 Rate = &DescribeRates->Rates[RateOffset++];\r
257 // Non-linear discrete rates.\r
39b3e14c
PG
258 RateArray[RateIndex++].DiscreteRate.Rate =\r
259 ConvertTo64Bit (Rate->Low, Rate->High);\r
4f2494cf
GP
260 }\r
261 } else {\r
262 for (RateNo = 0; RateNo < NUM_RATES (DescribeRates->NumRatesFlags); RateNo++) {\r
263 // Linear clock rates from minimum to maximum in steps\r
264 // Minimum clock rate.\r
265 Rate = &DescribeRates->Rates[RateOffset++];\r
39b3e14c
PG
266 RateArray[RateIndex].ContinuousRate.Min =\r
267 ConvertTo64Bit (Rate->Low, Rate->High);\r
4f2494cf
GP
268\r
269 Rate = &DescribeRates->Rates[RateOffset++];\r
270 // Maximum clock rate.\r
39b3e14c
PG
271 RateArray[RateIndex].ContinuousRate.Max =\r
272 ConvertTo64Bit (Rate->Low, Rate->High);\r
4f2494cf
GP
273\r
274 Rate = &DescribeRates->Rates[RateOffset++];\r
275 // Step.\r
39b3e14c
PG
276 RateArray[RateIndex++].ContinuousRate.Step =\r
277 ConvertTo64Bit (Rate->Low, Rate->High);\r
4f2494cf
GP
278 }\r
279 }\r
280 } while (NUM_REMAIN_RATES (DescribeRates->NumRatesFlags) != 0);\r
281\r
282 // Update RateArraySize with RequiredArraySize.\r
283 *RateArraySize = RequiredArraySize;\r
284\r
285 return EFI_SUCCESS;\r
286}\r
287\r
288/** Get clock rate.\r
289\r
290 @param[in] This A Pointer to SCMI_CLOCK_PROTOCOL Instance.\r
291 @param[in] ClockId Identifier for the clock device.\r
292\r
293 @param[out] Rate Clock rate.\r
294\r
295 @retval EFI_SUCCESS Clock rate is returned.\r
296 @retval EFI_DEVICE_ERROR SCP returns an SCMI error.\r
297 @retval !(EFI_SUCCESS) Other errors.\r
298**/\r
299STATIC\r
300EFI_STATUS\r
301ClockRateGet (\r
302 IN SCMI_CLOCK_PROTOCOL *This,\r
303 IN UINT32 ClockId,\r
304 OUT UINT64 *Rate\r
305 )\r
306{\r
307 EFI_STATUS Status;\r
308\r
309 UINT32 *MessageParams;\r
310 CLOCK_RATE_DWORD *ClockRate;\r
311 SCMI_COMMAND Cmd;\r
312\r
313 UINT32 PayloadLength;\r
314\r
315 Status = ScmiCommandGetPayload (&MessageParams);\r
316 if (EFI_ERROR (Status)) {\r
317 return Status;\r
318 }\r
319\r
320 // Fill arguments for clock protocol command.\r
321 *MessageParams = ClockId;\r
322\r
462f95ec 323 Cmd.ProtocolId = ScmiProtocolIdClock;\r
bd8efb4f 324 Cmd.MessageId = ScmiMessageIdClockRateGet;\r
4f2494cf
GP
325\r
326 PayloadLength = sizeof (ClockId);\r
327\r
328 // Execute and wait for response on a SCMI channel.\r
329 Status = ScmiCommandExecute (\r
330 &Cmd,\r
331 &PayloadLength,\r
332 (UINT32**)&ClockRate\r
333 );\r
334 if (EFI_ERROR (Status)) {\r
335 return Status;\r
336 }\r
337\r
338 *Rate = ConvertTo64Bit (ClockRate->Low, ClockRate->High);\r
339\r
340 return EFI_SUCCESS;\r
341}\r
342\r
343/** Set clock rate.\r
344\r
345 @param[in] This A Pointer to SCMI_CLOCK_PROTOCOL Instance.\r
346 @param[in] ClockId Identifier for the clock device.\r
347 @param[in] Rate Clock rate.\r
348\r
349 @retval EFI_SUCCESS Clock rate set success.\r
350 @retval EFI_DEVICE_ERROR SCP returns an SCMI error.\r
351 @retval !(EFI_SUCCESS) Other errors.\r
352**/\r
353STATIC\r
354EFI_STATUS\r
355ClockRateSet (\r
356 IN SCMI_CLOCK_PROTOCOL *This,\r
357 IN UINT32 ClockId,\r
358 IN UINT64 Rate\r
359 )\r
360{\r
361 EFI_STATUS Status;\r
362 CLOCK_RATE_SET_ATTRIBUTES *ClockRateSetAttributes;\r
363 SCMI_COMMAND Cmd;\r
364 UINT32 PayloadLength;\r
365\r
366 Status = ScmiCommandGetPayload ((UINT32**)&ClockRateSetAttributes);\r
367 if (EFI_ERROR (Status)) {\r
368 return Status;\r
369 }\r
370\r
371 // Fill arguments for clock protocol command.\r
372 ClockRateSetAttributes->ClockId = ClockId;\r
373 ClockRateSetAttributes->Flags = CLOCK_SET_DEFAULT_FLAGS;\r
374 ClockRateSetAttributes->Rate.Low = (UINT32)Rate;\r
375 ClockRateSetAttributes->Rate.High = (UINT32)(Rate >> 32);\r
376\r
462f95ec 377 Cmd.ProtocolId = ScmiProtocolIdClock;\r
bd8efb4f 378 Cmd.MessageId = ScmiMessageIdClockRateSet;\r
4f2494cf
GP
379\r
380 PayloadLength = sizeof (CLOCK_RATE_SET_ATTRIBUTES);\r
381\r
382 // Execute and wait for response on a SCMI channel.\r
383 Status = ScmiCommandExecute (\r
384 &Cmd,\r
385 &PayloadLength,\r
386 NULL\r
387 );\r
388\r
389 return Status;\r
390}\r
391\r
559a07d8
JB
392/** Enable/Disable specified clock.\r
393\r
394 @param[in] This A Pointer to SCMI_CLOCK_PROTOCOL Instance.\r
395 @param[in] ClockId Identifier for the clock device.\r
396 @param[in] Enable TRUE to enable, FALSE to disable.\r
397\r
398 @retval EFI_SUCCESS Clock enable/disable successful.\r
399 @retval EFI_DEVICE_ERROR SCP returns an SCMI error.\r
400 @retval !(EFI_SUCCESS) Other errors.\r
401**/\r
402STATIC\r
403EFI_STATUS\r
404ClockEnable (\r
405 IN SCMI_CLOCK2_PROTOCOL *This,\r
406 IN UINT32 ClockId,\r
407 IN BOOLEAN Enable\r
408 )\r
409{\r
410 EFI_STATUS Status;\r
411 CLOCK_CONFIG_SET_ATTRIBUTES *ClockConfigSetAttributes;\r
412 SCMI_COMMAND Cmd;\r
413 UINT32 PayloadLength;\r
414\r
415 Status = ScmiCommandGetPayload ((UINT32**)&ClockConfigSetAttributes);\r
416 if (EFI_ERROR (Status)) {\r
417 return Status;\r
418 }\r
419\r
420 // Fill arguments for clock protocol command.\r
421 ClockConfigSetAttributes->ClockId = ClockId;\r
422 ClockConfigSetAttributes->Attributes = Enable ? BIT0 : 0;\r
423\r
462f95ec 424 Cmd.ProtocolId = ScmiProtocolIdClock;\r
bd8efb4f 425 Cmd.MessageId = ScmiMessageIdClockConfigSet;\r
559a07d8
JB
426\r
427 PayloadLength = sizeof (CLOCK_CONFIG_SET_ATTRIBUTES);\r
428\r
429 // Execute and wait for response on a SCMI channel.\r
430 Status = ScmiCommandExecute (\r
431 &Cmd,\r
432 &PayloadLength,\r
433 NULL\r
434 );\r
435\r
436 return Status;\r
437}\r
438\r
4f2494cf
GP
439// Instance of the SCMI clock management protocol.\r
440STATIC CONST SCMI_CLOCK_PROTOCOL ScmiClockProtocol = {\r
441 ClockGetVersion,\r
442 ClockGetTotalClocks,\r
443 ClockGetClockAttributes,\r
444 ClockDescribeRates,\r
445 ClockRateGet,\r
446 ClockRateSet\r
447 };\r
448\r
559a07d8
JB
449// Instance of the SCMI clock management protocol.\r
450STATIC CONST SCMI_CLOCK2_PROTOCOL ScmiClock2Protocol = {\r
451 (SCMI_CLOCK2_GET_VERSION)ClockGetVersion,\r
452 (SCMI_CLOCK2_GET_TOTAL_CLOCKS)ClockGetTotalClocks,\r
453 (SCMI_CLOCK2_GET_CLOCK_ATTRIBUTES)ClockGetClockAttributes,\r
454 (SCMI_CLOCK2_DESCRIBE_RATES)ClockDescribeRates,\r
455 (SCMI_CLOCK2_RATE_GET)ClockRateGet,\r
456 (SCMI_CLOCK2_RATE_SET)ClockRateSet,\r
457 SCMI_CLOCK2_PROTOCOL_VERSION,\r
458 ClockEnable\r
459 };\r
460\r
4f2494cf
GP
461/** Initialize clock management protocol and install protocol on a given handle.\r
462\r
463 @param[in] Handle Handle to install clock management protocol.\r
464\r
465 @retval EFI_SUCCESS Clock protocol interface installed successfully.\r
466**/\r
467EFI_STATUS\r
468ScmiClockProtocolInit (\r
469 IN EFI_HANDLE* Handle\r
470 )\r
471{\r
472 return gBS->InstallMultipleProtocolInterfaces (\r
473 Handle,\r
474 &gArmScmiClockProtocolGuid,\r
475 &ScmiClockProtocol,\r
559a07d8
JB
476 &gArmScmiClock2ProtocolGuid,\r
477 &ScmiClock2Protocol,\r
4f2494cf
GP
478 NULL\r
479 );\r
480}\r