3 Copyright (c) 2017-2018, Arm Limited. All rights reserved.
5 This program and the accompanying materials
6 are licensed and made available under the terms and conditions of the BSD License
7 which accompanies this distribution. The full text of the license may be found at
8 http://opensource.org/licenses/bsd-license.php
10 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
11 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
13 System Control and Management Interface V1.0
14 http://infocenter.arm.com/help/topic/com.arm.doc.den0056a/
15 DEN0056A_System_Control_and_Management_Interface.pdf
18 #include <Library/BaseLib.h>
19 #include <Library/DebugLib.h>
20 #include <Library/UefiBootServicesTableLib.h>
21 #include <Protocol/ArmScmiClockProtocol.h>
22 #include <Protocol/ArmScmiClock2Protocol.h>
24 #include "ArmScmiClockProtocolPrivate.h"
25 #include "ScmiPrivate.h"
27 /** Convert to 64 bit value from two 32 bit words.
29 @param[in] Low Lower 32 bits.
30 @param[in] High Higher 32 bits.
32 @retval UINT64 64 bit value.
41 return (Low
| ((UINT64
)High
<< 32));
44 /** Return version of the clock management protocol supported by SCP firmware.
46 @param[in] This A Pointer to SCMI_CLOCK_PROTOCOL Instance.
48 @param[out] Version Version of the supported SCMI Clock management protocol.
50 @retval EFI_SUCCESS The version is returned.
51 @retval EFI_DEVICE_ERROR SCP returns an SCMI error.
52 @retval !(EFI_SUCCESS) Other errors.
57 IN SCMI_CLOCK_PROTOCOL
*This
,
61 return ScmiGetProtocolVersion (SCMI_PROTOCOL_ID_CLOCK
, Version
);
64 /** Return total number of clock devices supported by the clock management
67 @param[in] This A Pointer to SCMI_CLOCK_PROTOCOL Instance.
69 @param[out] TotalClocks Total number of clocks supported.
71 @retval EFI_SUCCESS Total number of clocks supported is returned.
72 @retval EFI_DEVICE_ERROR SCP returns an SCMI error.
73 @retval !(EFI_SUCCESS) Other errors.
78 IN SCMI_CLOCK_PROTOCOL
*This
,
79 OUT UINT32
*TotalClocks
85 Status
= ScmiGetProtocolAttributes (SCMI_PROTOCOL_ID_CLOCK
, &ReturnValues
);
86 if (EFI_ERROR (Status
)) {
90 *TotalClocks
= SCMI_CLOCK_PROTOCOL_TOTAL_CLKS (ReturnValues
[0]);
95 /** Return attributes of a clock device.
97 @param[in] This A Pointer to SCMI_CLOCK_PROTOCOL Instance.
98 @param[in] ClockId Identifier for the clock device.
100 @param[out] Enabled If TRUE, the clock device is enabled.
101 @param[out] ClockAsciiName A NULL terminated ASCII string with the clock
102 name, of up to 16 bytes.
104 @retval EFI_SUCCESS Clock device attributes are returned.
105 @retval EFI_DEVICE_ERROR SCP returns an SCMI error.
106 @retval !(EFI_SUCCESS) Other errors.
110 ClockGetClockAttributes (
111 IN SCMI_CLOCK_PROTOCOL
*This
,
113 OUT BOOLEAN
*Enabled
,
114 OUT CHAR8
*ClockAsciiName
119 UINT32
*MessageParams
;
120 CLOCK_ATTRIBUTES
*ClockAttributes
;
122 UINT32 PayloadLength
;
124 Status
= ScmiCommandGetPayload (&MessageParams
);
125 if (EFI_ERROR (Status
)) {
129 *MessageParams
= ClockId
;
131 Cmd
.ProtocolId
= SCMI_PROTOCOL_ID_CLOCK
;
132 Cmd
.MessageId
= SCMI_MESSAGE_ID_CLOCK_ATTRIBUTES
;
134 PayloadLength
= sizeof (ClockId
);
136 Status
= ScmiCommandExecute (
139 (UINT32
**)&ClockAttributes
141 if (EFI_ERROR (Status
)) {
144 // TRUE if bit 0 of ClockAttributes->Attributes is set.
145 *Enabled
= CLOCK_ENABLED (ClockAttributes
->Attributes
);
150 (CONST CHAR8
*)ClockAttributes
->ClockName
156 /** Return list of rates supported by a given clock device.
158 @param[in] This A pointer to SCMI_CLOCK_PROTOCOL Instance.
159 @param[in] ClockId Identifier for the clock device.
161 @param[out] Format SCMI_CLOCK_RATE_FORMAT_DISCRETE: Clock device
162 supports range of clock rates which are non-linear.
164 SCMI_CLOCK_RATE_FORMAT_LINEAR: Clock device supports
165 range of linear clock rates from Min to Max in steps.
167 @param[out] TotalRates Total number of rates.
169 @param[in,out] RateArraySize Size of the RateArray.
171 @param[out] RateArray List of clock rates.
173 @retval EFI_SUCCESS List of clock rates is returned.
174 @retval EFI_DEVICE_ERROR SCP returns an SCMI error.
175 @retval EFI_BUFFER_TOO_SMALL RateArraySize is too small for the result.
176 It has been updated to the size needed.
177 @retval !(EFI_SUCCESS) Other errors.
182 IN SCMI_CLOCK_PROTOCOL
*This
,
184 OUT SCMI_CLOCK_RATE_FORMAT
*Format
,
185 OUT UINT32
*TotalRates
,
186 IN OUT UINT32
*RateArraySize
,
187 OUT SCMI_CLOCK_RATE
*RateArray
192 UINT32 PayloadLength
;
194 UINT32
*MessageParams
;
195 CLOCK_DESCRIBE_RATES
*DescribeRates
;
196 CLOCK_RATE_DWORD
*Rate
;
198 UINT32 RequiredArraySize
= 0;
199 UINT32 RateIndex
= 0;
205 Status
= ScmiCommandGetPayload (&MessageParams
);
206 if (EFI_ERROR (Status
)) {
210 Cmd
.ProtocolId
= SCMI_PROTOCOL_ID_CLOCK
;
211 Cmd
.MessageId
= SCMI_MESSAGE_ID_CLOCK_DESCRIBE_RATES
;
213 *MessageParams
++ = ClockId
;
217 *MessageParams
= RateIndex
;
219 // Set Payload length, note PayloadLength is a IN/OUT parameter.
220 PayloadLength
= sizeof (ClockId
) + sizeof (RateIndex
);
222 // Execute and wait for response on a SCMI channel.
223 Status
= ScmiCommandExecute (
226 (UINT32
**)&DescribeRates
228 if (EFI_ERROR (Status
)) {
232 if (*TotalRates
== 0) {
233 // In the first iteration we will get number of returned rates and number
234 // of remaining rates. With this information calculate required size
235 // for rate array. If provided RateArraySize is less, return an
238 *Format
= RATE_FORMAT (DescribeRates
->NumRatesFlags
);
240 *TotalRates
= NUM_RATES (DescribeRates
->NumRatesFlags
)
241 + NUM_REMAIN_RATES (DescribeRates
->NumRatesFlags
);
243 if (*Format
== SCMI_CLOCK_RATE_FORMAT_DISCRETE
) {
244 RequiredArraySize
= (*TotalRates
) * sizeof (UINT64
);
246 // We need to return triplet of 64 bit value for each rate
247 RequiredArraySize
= (*TotalRates
) * 3 * sizeof (UINT64
);
250 if (RequiredArraySize
> (*RateArraySize
)) {
251 *RateArraySize
= RequiredArraySize
;
252 return EFI_BUFFER_TOO_SMALL
;
258 if (*Format
== SCMI_CLOCK_RATE_FORMAT_DISCRETE
) {
259 for (RateNo
= 0; RateNo
< NUM_RATES (DescribeRates
->NumRatesFlags
); RateNo
++) {
260 Rate
= &DescribeRates
->Rates
[RateOffset
++];
261 // Non-linear discrete rates.
262 RateArray
[RateIndex
++].Rate
= ConvertTo64Bit (Rate
->Low
, Rate
->High
);
265 for (RateNo
= 0; RateNo
< NUM_RATES (DescribeRates
->NumRatesFlags
); RateNo
++) {
266 // Linear clock rates from minimum to maximum in steps
267 // Minimum clock rate.
268 Rate
= &DescribeRates
->Rates
[RateOffset
++];
269 RateArray
[RateIndex
].Min
= ConvertTo64Bit (Rate
->Low
, Rate
->High
);
271 Rate
= &DescribeRates
->Rates
[RateOffset
++];
272 // Maximum clock rate.
273 RateArray
[RateIndex
].Max
= ConvertTo64Bit (Rate
->Low
, Rate
->High
);
275 Rate
= &DescribeRates
->Rates
[RateOffset
++];
277 RateArray
[RateIndex
++].Step
= ConvertTo64Bit (Rate
->Low
, Rate
->High
);
280 } while (NUM_REMAIN_RATES (DescribeRates
->NumRatesFlags
) != 0);
282 // Update RateArraySize with RequiredArraySize.
283 *RateArraySize
= RequiredArraySize
;
290 @param[in] This A Pointer to SCMI_CLOCK_PROTOCOL Instance.
291 @param[in] ClockId Identifier for the clock device.
293 @param[out] Rate Clock rate.
295 @retval EFI_SUCCESS Clock rate is returned.
296 @retval EFI_DEVICE_ERROR SCP returns an SCMI error.
297 @retval !(EFI_SUCCESS) Other errors.
302 IN SCMI_CLOCK_PROTOCOL
*This
,
309 UINT32
*MessageParams
;
310 CLOCK_RATE_DWORD
*ClockRate
;
313 UINT32 PayloadLength
;
315 Status
= ScmiCommandGetPayload (&MessageParams
);
316 if (EFI_ERROR (Status
)) {
320 // Fill arguments for clock protocol command.
321 *MessageParams
= ClockId
;
323 Cmd
.ProtocolId
= SCMI_PROTOCOL_ID_CLOCK
;
324 Cmd
.MessageId
= SCMI_MESSAGE_ID_CLOCK_RATE_GET
;
326 PayloadLength
= sizeof (ClockId
);
328 // Execute and wait for response on a SCMI channel.
329 Status
= ScmiCommandExecute (
334 if (EFI_ERROR (Status
)) {
338 *Rate
= ConvertTo64Bit (ClockRate
->Low
, ClockRate
->High
);
345 @param[in] This A Pointer to SCMI_CLOCK_PROTOCOL Instance.
346 @param[in] ClockId Identifier for the clock device.
347 @param[in] Rate Clock rate.
349 @retval EFI_SUCCESS Clock rate set success.
350 @retval EFI_DEVICE_ERROR SCP returns an SCMI error.
351 @retval !(EFI_SUCCESS) Other errors.
356 IN SCMI_CLOCK_PROTOCOL
*This
,
362 CLOCK_RATE_SET_ATTRIBUTES
*ClockRateSetAttributes
;
364 UINT32 PayloadLength
;
366 Status
= ScmiCommandGetPayload ((UINT32
**)&ClockRateSetAttributes
);
367 if (EFI_ERROR (Status
)) {
371 // Fill arguments for clock protocol command.
372 ClockRateSetAttributes
->ClockId
= ClockId
;
373 ClockRateSetAttributes
->Flags
= CLOCK_SET_DEFAULT_FLAGS
;
374 ClockRateSetAttributes
->Rate
.Low
= (UINT32
)Rate
;
375 ClockRateSetAttributes
->Rate
.High
= (UINT32
)(Rate
>> 32);
377 Cmd
.ProtocolId
= SCMI_PROTOCOL_ID_CLOCK
;
378 Cmd
.MessageId
= SCMI_MESSAGE_ID_CLOCK_RATE_SET
;
380 PayloadLength
= sizeof (CLOCK_RATE_SET_ATTRIBUTES
);
382 // Execute and wait for response on a SCMI channel.
383 Status
= ScmiCommandExecute (
392 /** Enable/Disable specified clock.
394 @param[in] This A Pointer to SCMI_CLOCK_PROTOCOL Instance.
395 @param[in] ClockId Identifier for the clock device.
396 @param[in] Enable TRUE to enable, FALSE to disable.
398 @retval EFI_SUCCESS Clock enable/disable successful.
399 @retval EFI_DEVICE_ERROR SCP returns an SCMI error.
400 @retval !(EFI_SUCCESS) Other errors.
405 IN SCMI_CLOCK2_PROTOCOL
*This
,
411 CLOCK_CONFIG_SET_ATTRIBUTES
*ClockConfigSetAttributes
;
413 UINT32 PayloadLength
;
415 Status
= ScmiCommandGetPayload ((UINT32
**)&ClockConfigSetAttributes
);
416 if (EFI_ERROR (Status
)) {
420 // Fill arguments for clock protocol command.
421 ClockConfigSetAttributes
->ClockId
= ClockId
;
422 ClockConfigSetAttributes
->Attributes
= Enable
? BIT0
: 0;
424 Cmd
.ProtocolId
= SCMI_PROTOCOL_ID_CLOCK
;
425 Cmd
.MessageId
= SCMI_MESSAGE_ID_CLOCK_CONFIG_SET
;
427 PayloadLength
= sizeof (CLOCK_CONFIG_SET_ATTRIBUTES
);
429 // Execute and wait for response on a SCMI channel.
430 Status
= ScmiCommandExecute (
439 // Instance of the SCMI clock management protocol.
440 STATIC CONST SCMI_CLOCK_PROTOCOL ScmiClockProtocol
= {
443 ClockGetClockAttributes
,
449 // Instance of the SCMI clock management protocol.
450 STATIC CONST SCMI_CLOCK2_PROTOCOL ScmiClock2Protocol
= {
451 (SCMI_CLOCK2_GET_VERSION
)ClockGetVersion
,
452 (SCMI_CLOCK2_GET_TOTAL_CLOCKS
)ClockGetTotalClocks
,
453 (SCMI_CLOCK2_GET_CLOCK_ATTRIBUTES
)ClockGetClockAttributes
,
454 (SCMI_CLOCK2_DESCRIBE_RATES
)ClockDescribeRates
,
455 (SCMI_CLOCK2_RATE_GET
)ClockRateGet
,
456 (SCMI_CLOCK2_RATE_SET
)ClockRateSet
,
457 SCMI_CLOCK2_PROTOCOL_VERSION
,
461 /** Initialize clock management protocol and install protocol on a given handle.
463 @param[in] Handle Handle to install clock management protocol.
465 @retval EFI_SUCCESS Clock protocol interface installed successfully.
468 ScmiClockProtocolInit (
469 IN EFI_HANDLE
* Handle
472 return gBS
->InstallMultipleProtocolInterfaces (
474 &gArmScmiClockProtocolGuid
,
476 &gArmScmiClock2ProtocolGuid
,