]> git.proxmox.com Git - mirror_edk2.git/blame - ArmPkg/Drivers/ArmScmiDxe/ScmiClockProtocol.c
ArmPkg: Apply uncrustify changes
[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
429309e0
MK
31 IN UINT32 Low,\r
32 IN UINT32 High\r
4f2494cf
GP
33 )\r
34{\r
429309e0 35 return (Low | ((UINT64)High << 32));\r
4f2494cf
GP
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
429309e0 77 UINT32 *ReturnValues;\r
4f2494cf 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
429309e0 111 EFI_STATUS Status;\r
4f2494cf 112\r
429309e0
MK
113 UINT32 *MessageParams;\r
114 CLOCK_ATTRIBUTES *ClockAttributes;\r
115 SCMI_COMMAND Cmd;\r
116 UINT32 PayloadLength;\r
4f2494cf
GP
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
429309e0 133 (UINT32 **)&ClockAttributes\r
4f2494cf
GP
134 );\r
135 if (EFI_ERROR (Status)) {\r
136 return Status;\r
137 }\r
429309e0
MK
138\r
139 // TRUE if bit 0 of ClockAttributes->Attributes is set.\r
4f2494cf
GP
140 *Enabled = CLOCK_ENABLED (ClockAttributes->Attributes);\r
141\r
142 AsciiStrCpyS (\r
143 ClockAsciiName,\r
144 SCMI_MAX_STR_LEN,\r
429309e0 145 (CONST CHAR8 *)ClockAttributes->ClockName\r
4f2494cf
GP
146 );\r
147\r
148 return EFI_SUCCESS;\r
149}\r
150\r
151/** Return list of rates supported by a given clock device.\r
152\r
153 @param[in] This A pointer to SCMI_CLOCK_PROTOCOL Instance.\r
154 @param[in] ClockId Identifier for the clock device.\r
155\r
063f8483 156 @param[out] Format ScmiClockRateFormatDiscrete: Clock device\r
4f2494cf
GP
157 supports range of clock rates which are non-linear.\r
158\r
063f8483 159 ScmiClockRateFormatLinear: Clock device supports\r
4f2494cf
GP
160 range of linear clock rates from Min to Max in steps.\r
161\r
162 @param[out] TotalRates Total number of rates.\r
163\r
164 @param[in,out] RateArraySize Size of the RateArray.\r
165\r
166 @param[out] RateArray List of clock rates.\r
167\r
168 @retval EFI_SUCCESS List of clock rates is returned.\r
169 @retval EFI_DEVICE_ERROR SCP returns an SCMI error.\r
170 @retval EFI_BUFFER_TOO_SMALL RateArraySize is too small for the result.\r
171 It has been updated to the size needed.\r
172 @retval !(EFI_SUCCESS) Other errors.\r
173**/\r
174STATIC\r
175EFI_STATUS\r
176ClockDescribeRates (\r
177 IN SCMI_CLOCK_PROTOCOL *This,\r
429309e0 178 IN UINT32 ClockId,\r
4f2494cf
GP
179 OUT SCMI_CLOCK_RATE_FORMAT *Format,\r
180 OUT UINT32 *TotalRates,\r
181 IN OUT UINT32 *RateArraySize,\r
182 OUT SCMI_CLOCK_RATE *RateArray\r
183 )\r
184{\r
429309e0 185 EFI_STATUS Status;\r
4f2494cf 186\r
429309e0
MK
187 UINT32 PayloadLength;\r
188 SCMI_COMMAND Cmd;\r
189 UINT32 *MessageParams;\r
190 CLOCK_DESCRIBE_RATES *DescribeRates;\r
191 CLOCK_RATE_DWORD *Rate;\r
4f2494cf 192\r
429309e0
MK
193 UINT32 RequiredArraySize;\r
194 UINT32 RateIndex;\r
195 UINT32 RateNo;\r
196 UINT32 RateOffset;\r
4f2494cf 197\r
429309e0 198 *TotalRates = 0;\r
3f0d3dfa 199 RequiredArraySize = 0;\r
429309e0 200 RateIndex = 0;\r
4f2494cf
GP
201\r
202 Status = ScmiCommandGetPayload (&MessageParams);\r
203 if (EFI_ERROR (Status)) {\r
204 return Status;\r
205 }\r
206\r
462f95ec 207 Cmd.ProtocolId = ScmiProtocolIdClock;\r
bd8efb4f 208 Cmd.MessageId = ScmiMessageIdClockDescribeRates;\r
4f2494cf 209\r
429309e0 210 *MessageParams++ = ClockId;\r
4f2494cf
GP
211\r
212 do {\r
4f2494cf
GP
213 *MessageParams = RateIndex;\r
214\r
215 // Set Payload length, note PayloadLength is a IN/OUT parameter.\r
429309e0 216 PayloadLength = sizeof (ClockId) + sizeof (RateIndex);\r
4f2494cf
GP
217\r
218 // Execute and wait for response on a SCMI channel.\r
219 Status = ScmiCommandExecute (\r
220 &Cmd,\r
221 &PayloadLength,\r
429309e0 222 (UINT32 **)&DescribeRates\r
4f2494cf
GP
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
429309e0 240 RequiredArraySize = (*TotalRates) * sizeof (UINT64);\r
4f2494cf 241 } else {\r
429309e0
MK
242 // We need to return triplet of 64 bit value for each rate\r
243 RequiredArraySize = (*TotalRates) * 3 * sizeof (UINT64);\r
4f2494cf
GP
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
429309e0 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
429309e0 307 EFI_STATUS Status;\r
4f2494cf
GP
308\r
309 UINT32 *MessageParams;\r
310 CLOCK_RATE_DWORD *ClockRate;\r
311 SCMI_COMMAND Cmd;\r
312\r
429309e0 313 UINT32 PayloadLength;\r
4f2494cf
GP
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
429309e0 321 *MessageParams = ClockId;\r
4f2494cf 322\r
429309e0
MK
323 Cmd.ProtocolId = ScmiProtocolIdClock;\r
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
429309e0 332 (UINT32 **)&ClockRate\r
4f2494cf
GP
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
429309e0
MK
361 EFI_STATUS Status;\r
362 CLOCK_RATE_SET_ATTRIBUTES *ClockRateSetAttributes;\r
363 SCMI_COMMAND Cmd;\r
364 UINT32 PayloadLength;\r
4f2494cf 365\r
429309e0 366 Status = ScmiCommandGetPayload ((UINT32 **)&ClockRateSetAttributes);\r
4f2494cf
GP
367 if (EFI_ERROR (Status)) {\r
368 return Status;\r
369 }\r
370\r
371 // Fill arguments for clock protocol command.\r
429309e0
MK
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
4f2494cf 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
429309e0
MK
405 IN SCMI_CLOCK2_PROTOCOL *This,\r
406 IN UINT32 ClockId,\r
407 IN BOOLEAN Enable\r
559a07d8
JB
408 )\r
409{\r
429309e0
MK
410 EFI_STATUS Status;\r
411 CLOCK_CONFIG_SET_ATTRIBUTES *ClockConfigSetAttributes;\r
412 SCMI_COMMAND Cmd;\r
413 UINT32 PayloadLength;\r
559a07d8 414\r
429309e0 415 Status = ScmiCommandGetPayload ((UINT32 **)&ClockConfigSetAttributes);\r
559a07d8
JB
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 439// Instance of the SCMI clock management protocol.\r
429309e0 440STATIC CONST SCMI_CLOCK_PROTOCOL ScmiClockProtocol = {\r
4f2494cf
GP
441 ClockGetVersion,\r
442 ClockGetTotalClocks,\r
443 ClockGetClockAttributes,\r
444 ClockDescribeRates,\r
445 ClockRateGet,\r
446 ClockRateSet\r
429309e0 447};\r
4f2494cf 448\r
559a07d8 449// Instance of the SCMI clock management protocol.\r
429309e0 450STATIC CONST SCMI_CLOCK2_PROTOCOL ScmiClock2Protocol = {\r
559a07d8
JB
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
429309e0 459};\r
559a07d8 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
429309e0 469 IN EFI_HANDLE *Handle\r
4f2494cf
GP
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