VirtualBox

source: vbox/trunk/src/VBox/Devices/EFI/Firmware/ArmPkg/Drivers/ArmScmiDxe/ScmiClockProtocol.c@ 100307

Last change on this file since 100307 was 99464, checked in by vboxsync, 2 years ago

Devices/EFI/Firmware: Restore ArmPkg, ArmVirtPkg, ArmPlatformPkg in order to be able to build Aarch64 and Aarch32 firmware images for the virt platform, bugref:10400

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

© 2025 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette