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>
23 #include "ArmScmiClockProtocolPrivate.h"
24 #include "ScmiPrivate.h"
26 /** Convert to 64 bit value from two 32 bit words.
28 @param[in] Low Lower 32 bits.
29 @param[in] High Higher 32 bits.
31 @retval UINT64 64 bit value.
40 return (Low
| ((UINT64
)High
<< 32));
43 /** Return version of the clock management protocol supported by SCP firmware.
45 @param[in] This A Pointer to SCMI_CLOCK_PROTOCOL Instance.
47 @param[out] Version Version of the supported SCMI Clock management protocol.
49 @retval EFI_SUCCESS The version is returned.
50 @retval EFI_DEVICE_ERROR SCP returns an SCMI error.
51 @retval !(EFI_SUCCESS) Other errors.
56 IN SCMI_CLOCK_PROTOCOL
*This
,
60 return ScmiGetProtocolVersion (SCMI_PROTOCOL_ID_CLOCK
, Version
);
63 /** Return total number of clock devices supported by the clock management
66 @param[in] This A Pointer to SCMI_CLOCK_PROTOCOL Instance.
68 @param[out] TotalClocks Total number of clocks supported.
70 @retval EFI_SUCCESS Total number of clocks supported is returned.
71 @retval EFI_DEVICE_ERROR SCP returns an SCMI error.
72 @retval !(EFI_SUCCESS) Other errors.
77 IN SCMI_CLOCK_PROTOCOL
*This
,
78 OUT UINT32
*TotalClocks
84 Status
= ScmiGetProtocolAttributes (SCMI_PROTOCOL_ID_CLOCK
, &ReturnValues
);
85 if (EFI_ERROR (Status
)) {
89 *TotalClocks
= SCMI_CLOCK_PROTOCOL_TOTAL_CLKS (ReturnValues
[0]);
94 /** Return attributes of a clock device.
96 @param[in] This A Pointer to SCMI_CLOCK_PROTOCOL Instance.
97 @param[in] ClockId Identifier for the clock device.
99 @param[out] Enabled If TRUE, the clock device is enabled.
100 @param[out] ClockAsciiName A NULL terminated ASCII string with the clock
101 name, of up to 16 bytes.
103 @retval EFI_SUCCESS Clock device attributes are returned.
104 @retval EFI_DEVICE_ERROR SCP returns an SCMI error.
105 @retval !(EFI_SUCCESS) Other errors.
109 ClockGetClockAttributes (
110 IN SCMI_CLOCK_PROTOCOL
*This
,
112 OUT BOOLEAN
*Enabled
,
113 OUT CHAR8
*ClockAsciiName
118 UINT32
*MessageParams
;
119 CLOCK_ATTRIBUTES
*ClockAttributes
;
121 UINT32 PayloadLength
;
123 Status
= ScmiCommandGetPayload (&MessageParams
);
124 if (EFI_ERROR (Status
)) {
128 *MessageParams
= ClockId
;
130 Cmd
.ProtocolId
= SCMI_PROTOCOL_ID_CLOCK
;
131 Cmd
.MessageId
= SCMI_MESSAGE_ID_CLOCK_ATTRIBUTES
;
133 PayloadLength
= sizeof (ClockId
);
135 Status
= ScmiCommandExecute (
138 (UINT32
**)&ClockAttributes
140 if (EFI_ERROR (Status
)) {
143 // TRUE if bit 0 of ClockAttributes->Attributes is set.
144 *Enabled
= CLOCK_ENABLED (ClockAttributes
->Attributes
);
149 (CONST CHAR8
*)ClockAttributes
->ClockName
155 /** Return list of rates supported by a given clock device.
157 @param[in] This A pointer to SCMI_CLOCK_PROTOCOL Instance.
158 @param[in] ClockId Identifier for the clock device.
160 @param[out] Format SCMI_CLOCK_RATE_FORMAT_DISCRETE: Clock device
161 supports range of clock rates which are non-linear.
163 SCMI_CLOCK_RATE_FORMAT_LINEAR: Clock device supports
164 range of linear clock rates from Min to Max in steps.
166 @param[out] TotalRates Total number of rates.
168 @param[in,out] RateArraySize Size of the RateArray.
170 @param[out] RateArray List of clock rates.
172 @retval EFI_SUCCESS List of clock rates is returned.
173 @retval EFI_DEVICE_ERROR SCP returns an SCMI error.
174 @retval EFI_BUFFER_TOO_SMALL RateArraySize is too small for the result.
175 It has been updated to the size needed.
176 @retval !(EFI_SUCCESS) Other errors.
181 IN SCMI_CLOCK_PROTOCOL
*This
,
183 OUT SCMI_CLOCK_RATE_FORMAT
*Format
,
184 OUT UINT32
*TotalRates
,
185 IN OUT UINT32
*RateArraySize
,
186 OUT SCMI_CLOCK_RATE
*RateArray
191 UINT32 PayloadLength
;
193 UINT32
*MessageParams
;
194 CLOCK_DESCRIBE_RATES
*DescribeRates
;
195 CLOCK_RATE_DWORD
*Rate
;
197 UINT32 RequiredArraySize
= 0;
198 UINT32 RateIndex
= 0;
204 Status
= ScmiCommandGetPayload (&MessageParams
);
205 if (EFI_ERROR (Status
)) {
209 Cmd
.ProtocolId
= SCMI_PROTOCOL_ID_CLOCK
;
210 Cmd
.MessageId
= SCMI_MESSAGE_ID_CLOCK_DESCRIBE_RATES
;
212 *MessageParams
++ = ClockId
;
216 *MessageParams
= RateIndex
;
218 // Set Payload length, note PayloadLength is a IN/OUT parameter.
219 PayloadLength
= sizeof (ClockId
) + sizeof (RateIndex
);
221 // Execute and wait for response on a SCMI channel.
222 Status
= ScmiCommandExecute (
225 (UINT32
**)&DescribeRates
227 if (EFI_ERROR (Status
)) {
231 if (*TotalRates
== 0) {
232 // In the first iteration we will get number of returned rates and number
233 // of remaining rates. With this information calculate required size
234 // for rate array. If provided RateArraySize is less, return an
237 *Format
= RATE_FORMAT (DescribeRates
->NumRatesFlags
);
239 *TotalRates
= NUM_RATES (DescribeRates
->NumRatesFlags
)
240 + NUM_REMAIN_RATES (DescribeRates
->NumRatesFlags
);
242 if (*Format
== SCMI_CLOCK_RATE_FORMAT_DISCRETE
) {
243 RequiredArraySize
= (*TotalRates
) * sizeof (UINT64
);
245 // We need to return triplet of 64 bit value for each rate
246 RequiredArraySize
= (*TotalRates
) * 3 * sizeof (UINT64
);
249 if (RequiredArraySize
> (*RateArraySize
)) {
250 *RateArraySize
= RequiredArraySize
;
251 return EFI_BUFFER_TOO_SMALL
;
257 if (*Format
== SCMI_CLOCK_RATE_FORMAT_DISCRETE
) {
258 for (RateNo
= 0; RateNo
< NUM_RATES (DescribeRates
->NumRatesFlags
); RateNo
++) {
259 Rate
= &DescribeRates
->Rates
[RateOffset
++];
260 // Non-linear discrete rates.
261 RateArray
[RateIndex
++].Rate
= ConvertTo64Bit (Rate
->Low
, Rate
->High
);
264 for (RateNo
= 0; RateNo
< NUM_RATES (DescribeRates
->NumRatesFlags
); RateNo
++) {
265 // Linear clock rates from minimum to maximum in steps
266 // Minimum clock rate.
267 Rate
= &DescribeRates
->Rates
[RateOffset
++];
268 RateArray
[RateIndex
].Min
= ConvertTo64Bit (Rate
->Low
, Rate
->High
);
270 Rate
= &DescribeRates
->Rates
[RateOffset
++];
271 // Maximum clock rate.
272 RateArray
[RateIndex
].Max
= ConvertTo64Bit (Rate
->Low
, Rate
->High
);
274 Rate
= &DescribeRates
->Rates
[RateOffset
++];
276 RateArray
[RateIndex
++].Step
= ConvertTo64Bit (Rate
->Low
, Rate
->High
);
279 } while (NUM_REMAIN_RATES (DescribeRates
->NumRatesFlags
) != 0);
281 // Update RateArraySize with RequiredArraySize.
282 *RateArraySize
= RequiredArraySize
;
289 @param[in] This A Pointer to SCMI_CLOCK_PROTOCOL Instance.
290 @param[in] ClockId Identifier for the clock device.
292 @param[out] Rate Clock rate.
294 @retval EFI_SUCCESS Clock rate is returned.
295 @retval EFI_DEVICE_ERROR SCP returns an SCMI error.
296 @retval !(EFI_SUCCESS) Other errors.
301 IN SCMI_CLOCK_PROTOCOL
*This
,
308 UINT32
*MessageParams
;
309 CLOCK_RATE_DWORD
*ClockRate
;
312 UINT32 PayloadLength
;
314 Status
= ScmiCommandGetPayload (&MessageParams
);
315 if (EFI_ERROR (Status
)) {
319 // Fill arguments for clock protocol command.
320 *MessageParams
= ClockId
;
322 Cmd
.ProtocolId
= SCMI_PROTOCOL_ID_CLOCK
;
323 Cmd
.MessageId
= SCMI_MESSAGE_ID_CLOCK_RATE_GET
;
325 PayloadLength
= sizeof (ClockId
);
327 // Execute and wait for response on a SCMI channel.
328 Status
= ScmiCommandExecute (
333 if (EFI_ERROR (Status
)) {
337 *Rate
= ConvertTo64Bit (ClockRate
->Low
, ClockRate
->High
);
344 @param[in] This A Pointer to SCMI_CLOCK_PROTOCOL Instance.
345 @param[in] ClockId Identifier for the clock device.
346 @param[in] Rate Clock rate.
348 @retval EFI_SUCCESS Clock rate set success.
349 @retval EFI_DEVICE_ERROR SCP returns an SCMI error.
350 @retval !(EFI_SUCCESS) Other errors.
355 IN SCMI_CLOCK_PROTOCOL
*This
,
361 CLOCK_RATE_SET_ATTRIBUTES
*ClockRateSetAttributes
;
363 UINT32 PayloadLength
;
365 Status
= ScmiCommandGetPayload ((UINT32
**)&ClockRateSetAttributes
);
366 if (EFI_ERROR (Status
)) {
370 // Fill arguments for clock protocol command.
371 ClockRateSetAttributes
->ClockId
= ClockId
;
372 ClockRateSetAttributes
->Flags
= CLOCK_SET_DEFAULT_FLAGS
;
373 ClockRateSetAttributes
->Rate
.Low
= (UINT32
)Rate
;
374 ClockRateSetAttributes
->Rate
.High
= (UINT32
)(Rate
>> 32);
376 Cmd
.ProtocolId
= SCMI_PROTOCOL_ID_CLOCK
;
377 Cmd
.MessageId
= SCMI_MESSAGE_ID_CLOCK_RATE_SET
;
379 PayloadLength
= sizeof (CLOCK_RATE_SET_ATTRIBUTES
);
381 // Execute and wait for response on a SCMI channel.
382 Status
= ScmiCommandExecute (
391 // Instance of the SCMI clock management protocol.
392 STATIC CONST SCMI_CLOCK_PROTOCOL ScmiClockProtocol
= {
395 ClockGetClockAttributes
,
401 /** Initialize clock management protocol and install protocol on a given handle.
403 @param[in] Handle Handle to install clock management protocol.
405 @retval EFI_SUCCESS Clock protocol interface installed successfully.
408 ScmiClockProtocolInit (
409 IN EFI_HANDLE
* Handle
412 return gBS
->InstallMultipleProtocolInterfaces (
414 &gArmScmiClockProtocolGuid
,