1 /** @file
2 
3   Copyright (c) 2017-2018, 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/ArmScmiBaseProtocol.h>
16 
17 #include "ArmScmiBaseProtocolPrivate.h"
18 #include "ScmiPrivate.h"
19 
20 /** Return version of the Base protocol supported by SCP firmware.
21 
22   @param[in]  This     A Pointer to SCMI_BASE_PROTOCOL Instance.
23 
24   @param[out] Version  Version of the supported SCMI Base protocol.
25 
26   @retval EFI_SUCCESS       The version of the protocol is returned.
27   @retval EFI_DEVICE_ERROR  SCP returns an SCMI error.
28   @retval !(EFI_SUCCESS)    Other errors.
29 **/
30 STATIC
31 EFI_STATUS
BaseGetVersion(IN SCMI_BASE_PROTOCOL * This,OUT UINT32 * Version)32 BaseGetVersion (
33   IN  SCMI_BASE_PROTOCOL  *This,
34   OUT UINT32              *Version
35   )
36 {
37   return ScmiGetProtocolVersion (SCMI_PROTOCOL_ID_BASE, Version);
38 }
39 
40 /** Return total number of SCMI protocols supported by the SCP firmware.
41 
42   @param[in]  This           A Pointer to SCMI_BASE_PROTOCOL Instance.
43 
44   @param[out] TotalProtocols Total number of SCMI protocols supported.
45 
46   @retval EFI_SUCCESS       Total number of protocols supported are returned.
47   @retval EFI_DEVICE_ERROR  SCP returns a SCMI error.
48   @retval !(EFI_SUCCESS)    Other errors.
49 **/
50 STATIC
51 EFI_STATUS
BaseGetTotalProtocols(IN SCMI_BASE_PROTOCOL * This,OUT UINT32 * TotalProtocols)52 BaseGetTotalProtocols (
53   IN  SCMI_BASE_PROTOCOL  *This,
54   OUT UINT32              *TotalProtocols
55   )
56 {
57   EFI_STATUS  Status;
58   UINT32      *ReturnValues;
59 
60   Status = ScmiGetProtocolAttributes (SCMI_PROTOCOL_ID_BASE, &ReturnValues);
61   if (EFI_ERROR (Status)) {
62     return Status;
63   }
64 
65   *TotalProtocols = SCMI_TOTAL_PROTOCOLS (ReturnValues[0]);
66 
67   return EFI_SUCCESS;
68 }
69 
70 /** Common function which returns vendor details.
71 
72   @param[in] MessageId       SCMI_MESSAGE_ID_BASE_DISCOVER_VENDOR
73                              OR
74                              SCMI_MESSAGE_ID_BASE_DISCOVER_SUB_VENDOR
75 
76   @param[out] VendorIdentifier ASCII name of the vendor/subvendor.
77 
78   @retval EFI_SUCCESS       VendorIdentifier is returned.
79   @retval EFI_DEVICE_ERROR  SCP returns an SCMI error.
80   @retval !(EFI_SUCCESS)    Other errors.
81 **/
82 STATIC
83 EFI_STATUS
BaseDiscoverVendorDetails(IN SCMI_MESSAGE_ID_BASE MessageId,OUT UINT8 VendorIdentifier[SCMI_MAX_STR_LEN])84 BaseDiscoverVendorDetails (
85   IN  SCMI_MESSAGE_ID_BASE  MessageId,
86   OUT UINT8                 VendorIdentifier[SCMI_MAX_STR_LEN]
87   )
88 {
89   EFI_STATUS    Status;
90   UINT32        *ReturnValues;
91   SCMI_COMMAND  Cmd;
92   UINT32        PayloadLength;
93 
94   Cmd.ProtocolId = SCMI_PROTOCOL_ID_BASE;
95   Cmd.MessageId  = MessageId;
96 
97   PayloadLength = 0;
98 
99   Status = ScmiCommandExecute (
100              &Cmd,
101              &PayloadLength,
102              &ReturnValues
103              );
104   if (EFI_ERROR (Status)) {
105     return Status;
106   }
107 
108   AsciiStrCpyS (
109     (CHAR8*)VendorIdentifier,
110     SCMI_MAX_STR_LEN,
111     (CONST CHAR8*)ReturnValues
112     );
113 
114   return EFI_SUCCESS;
115 }
116 
117 /** Return vendor name.
118 
119   @param[in] This           A Pointer to SCMI_BASE_PROTOCOL Instance.
120 
121   @param[out] VendorIdentifier Null terminated ASCII string of up to
122                                16 bytes with a vendor name.
123 
124   @retval EFI_SUCCESS       VendorIdentifier is returned.
125   @retval EFI_DEVICE_ERROR  SCP returns a SCMI error.
126   @retval !(EFI_SUCCESS)    Other errors.
127 **/
128 STATIC
129 EFI_STATUS
BaseDiscoverVendor(IN SCMI_BASE_PROTOCOL * This,OUT UINT8 VendorIdentifier[SCMI_MAX_STR_LEN])130 BaseDiscoverVendor (
131   IN  SCMI_BASE_PROTOCOL  *This,
132   OUT UINT8               VendorIdentifier[SCMI_MAX_STR_LEN]
133   )
134 {
135   return BaseDiscoverVendorDetails (
136            SCMI_MESSAGE_ID_BASE_DISCOVER_VENDOR,
137            VendorIdentifier
138            );
139 }
140 
141 /** Return sub vendor name.
142 
143   @param[in]  This           A Pointer to SCMI_BASE_PROTOCOL Instance.
144 
145   @param[out] VendorIdentifier Null terminated ASCII string of up to
146                                16 bytes with a sub vendor name.
147 
148   @retval EFI_SUCCESS       VendorIdentifier is returned.
149   @retval EFI_DEVICE_ERROR  SCP returns a SCMI error.
150   @retval !(EFI_SUCCESS)    Other errors.
151 **/
152 EFI_STATUS
BaseDiscoverSubVendor(IN SCMI_BASE_PROTOCOL * This,OUT UINT8 VendorIdentifier[SCMI_MAX_STR_LEN])153 BaseDiscoverSubVendor (
154   IN  SCMI_BASE_PROTOCOL  *This,
155   OUT UINT8               VendorIdentifier[SCMI_MAX_STR_LEN]
156   )
157 {
158   return BaseDiscoverVendorDetails (
159            SCMI_MESSAGE_ID_BASE_DISCOVER_SUB_VENDOR,
160            VendorIdentifier
161            );
162 }
163 
164 /** Return implementation version.
165 
166   @param[in] This           A Pointer to SCMI_BASE_PROTOCOL Instance.
167 
168   @param[out] ImplementationVersion Vendor specific implementation version.
169 
170   @retval EFI_SUCCESS       Implementation version is returned.
171   @retval EFI_DEVICE_ERROR  SCP returns a SCMI error.
172   @retval !(EFI_SUCCESS)    Other errors.
173 **/
174 STATIC
175 EFI_STATUS
BaseDiscoverImplVersion(IN SCMI_BASE_PROTOCOL * This,OUT UINT32 * ImplementationVersion)176 BaseDiscoverImplVersion (
177   IN  SCMI_BASE_PROTOCOL  *This,
178   OUT UINT32              *ImplementationVersion
179   )
180 {
181   EFI_STATUS    Status;
182   UINT32        *ReturnValues;
183   SCMI_COMMAND  Cmd;
184   UINT32        PayloadLength;
185 
186   Cmd.ProtocolId = SCMI_PROTOCOL_ID_BASE;
187   Cmd.MessageId  = SCMI_MESSAGE_ID_BASE_DISCOVER_IMPLEMENTATION_VERSION;
188 
189   PayloadLength = 0;
190 
191   Status = ScmiCommandExecute (
192              &Cmd,
193              &PayloadLength,
194              &ReturnValues
195              );
196   if (EFI_ERROR (Status)) {
197     return Status;
198   }
199 
200   *ImplementationVersion = ReturnValues[0];
201 
202   return EFI_SUCCESS;
203 }
204 
205 /** Return list of protocols.
206 
207   @param[in]  This           A Pointer to SCMI_BASE_PROTOCOL Instance.
208 
209   @param[out] ProtocolListSize  Size of the ProtocolList.
210 
211   @param[out] ProtocolList   Protocol list.
212 
213   @retval EFI_SUCCESS          List of protocols is returned.
214   @retval EFI_BUFFER_TOO_SMALL ProtocolListSize is too small for the result.
215                                 It has been updated to the size needed.
216   @retval EFI_DEVICE_ERROR     SCP returns a SCMI error.
217   @retval !(EFI_SUCCESS)       Other errors.
218 **/
219 STATIC
220 EFI_STATUS
BaseDiscoverListProtocols(IN SCMI_BASE_PROTOCOL * This,IN OUT UINT32 * ProtocolListSize,OUT UINT8 * ProtocolList)221 BaseDiscoverListProtocols (
222   IN     SCMI_BASE_PROTOCOL  *This,
223   IN OUT UINT32              *ProtocolListSize,
224   OUT    UINT8               *ProtocolList
225   )
226 {
227   EFI_STATUS          Status;
228   UINT32              TotalProtocols;
229   UINT32              *MessageParams;
230   BASE_DISCOVER_LIST  *DiscoverList;
231   UINT32              Skip;
232   UINT32              Index;
233   SCMI_COMMAND        Cmd;
234   UINT32              PayloadLength;
235   UINT32              RequiredSize;
236 
237   Status = BaseGetTotalProtocols (This, &TotalProtocols);
238   if (EFI_ERROR (Status)) {
239     return Status;
240   }
241 
242   Status = ScmiCommandGetPayload (&MessageParams);
243   if (EFI_ERROR (Status)) {
244     return Status;
245   }
246 
247   RequiredSize = sizeof (UINT8) * TotalProtocols;
248   if (*ProtocolListSize < RequiredSize) {
249     *ProtocolListSize = RequiredSize;
250     return EFI_BUFFER_TOO_SMALL;
251   }
252 
253   Cmd.ProtocolId = SCMI_PROTOCOL_ID_BASE;
254   Cmd.MessageId  = SCMI_MESSAGE_ID_BASE_DISCOVER_LIST_PROTOCOLS;
255 
256   Skip = 0;
257 
258   while (Skip < TotalProtocols) {
259 
260     *MessageParams = Skip;
261 
262     // Note PayloadLength is a IN/OUT parameter.
263     PayloadLength = sizeof (Skip);
264 
265     Status = ScmiCommandExecute (
266                &Cmd,
267                &PayloadLength,
268                (UINT32**)&DiscoverList
269                );
270     if (EFI_ERROR (Status)) {
271       return Status;
272     }
273 
274     for (Index = 0; Index < DiscoverList->NumProtocols; Index++) {
275       ProtocolList[Skip++] = DiscoverList->Protocols[Index];
276     }
277   }
278 
279   *ProtocolListSize = RequiredSize;
280 
281   return EFI_SUCCESS;
282 }
283 
284 // Instance of the SCMI Base protocol.
285 STATIC CONST SCMI_BASE_PROTOCOL BaseProtocol = {
286   BaseGetVersion,
287   BaseGetTotalProtocols,
288   BaseDiscoverVendor,
289   BaseDiscoverSubVendor,
290   BaseDiscoverImplVersion,
291   BaseDiscoverListProtocols
292 };
293 
294 /** Initialize Base protocol and install protocol on a given handle.
295 
296    @param[in] Handle              Handle to install Base protocol.
297 
298    @retval EFI_SUCCESS            Base protocol interface installed
299                                   successfully.
300 **/
301 EFI_STATUS
ScmiBaseProtocolInit(IN OUT EFI_HANDLE * Handle)302 ScmiBaseProtocolInit (
303   IN OUT EFI_HANDLE* Handle
304   )
305 {
306   return gBS->InstallMultipleProtocolInterfaces (
307                 Handle,
308                 &gArmScmiBaseProtocolGuid,
309                 &BaseProtocol,
310                 NULL
311                 );
312 }
313