]> git.proxmox.com Git - mirror_edk2.git/blame - ArmPkg/Drivers/ArmScmiDxe/Scmi.c
ArmPkg: Introduce SCMI protocol
[mirror_edk2.git] / ArmPkg / Drivers / ArmScmiDxe / Scmi.c
CommitLineData
4f2494cf
GP
1/** @file\r
2\r
3 Copyright (c) 2017-2018, Arm Limited. All rights reserved.\r
4\r
5 This program and the accompanying materials\r
6 are licensed and made available under the terms and conditions of the BSD License\r
7 which accompanies this distribution. The full text of the license may be found at\r
8 http://opensource.org/licenses/bsd-license.php\r
9\r
10 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
11 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
12\r
13 System Control and Management Interface V1.0\r
14 http://infocenter.arm.com/help/topic/com.arm.doc.den0056a/\r
15 DEN0056A_System_Control_and_Management_Interface.pdf\r
16**/\r
17\r
18#include <Library/ArmMtlLib.h>\r
19#include <Library/DebugLib.h>\r
20#include <Library/MemoryAllocationLib.h>\r
21#include <Library/UefiBootServicesTableLib.h>\r
22\r
23#include "ScmiPrivate.h"\r
24\r
25// SCMI Specification 1.0\r
26#define MAX_PROTOCOLS 6\r
27\r
28#define PROTOCOL_MASK 0xF\r
29\r
30// Arbitrary timeout value 20ms.\r
31#define RESPONSE_TIMEOUT 20000\r
32\r
33/** Return a pointer to the message payload.\r
34\r
35 @param[out] Payload Holds pointer to the message payload.\r
36\r
37 @retval EFI_SUCCESS Payload holds a valid message payload pointer.\r
38 @retval EFI_TIMEOUT Time out error if MTL channel is busy.\r
39 @retval EFI_UNSUPPORTED If MTL channel is unsupported.\r
40**/\r
41EFI_STATUS\r
42ScmiCommandGetPayload (\r
43 OUT UINT32** Payload\r
44 )\r
45{\r
46 EFI_STATUS Status;\r
47 MTL_CHANNEL *Channel;\r
48\r
49 // Get handle to the Channel.\r
50 Status = MtlGetChannel (MTL_CHANNEL_TYPE_LOW, &Channel);\r
51 if (EFI_ERROR (Status)) {\r
52 return Status;\r
53 }\r
54\r
55 // Payload will not be populated until channel is free.\r
56 Status = MtlWaitUntilChannelFree (Channel, RESPONSE_TIMEOUT);\r
57 if (EFI_ERROR (Status)) {\r
58 return Status;\r
59 }\r
60\r
61 // Get the address of the payload.\r
62 *Payload = MtlGetChannelPayload (Channel);\r
63\r
64 return EFI_SUCCESS;\r
65}\r
66\r
67/** Execute a SCMI command and receive a response.\r
68\r
69 This function uses a MTL channel to transfer message to SCP\r
70 and waits for a response.\r
71\r
72 @param[in] Command Pointer to the SCMI command (Protocol ID\r
73 and Message ID)\r
74\r
75 @param[in,out] PayloadLength SCMI command message length.\r
76\r
77 @param[out] OPTIONAL ReturnValues Pointer to SCMI response.\r
78\r
79 @retval OUT EFI_SUCCESS Command sent and message received successfully.\r
80 @retval OUT EFI_UNSUPPORTED Channel not supported.\r
81 @retval OUT EFI_TIMEOUT Timeout on the channel.\r
82 @retval OUT EFI_DEVICE_ERROR Channel not ready.\r
83 @retval OUT EFI_DEVICE_ERROR Message Header corrupted.\r
84 @retval OUT EFI_DEVICE_ERROR SCMI error.\r
85**/\r
86EFI_STATUS\r
87ScmiCommandExecute (\r
88 IN SCMI_COMMAND *Command,\r
89 IN OUT UINT32 *PayloadLength,\r
90 OUT UINT32 **ReturnValues OPTIONAL\r
91 )\r
92{\r
93 EFI_STATUS Status;\r
94 SCMI_MESSAGE_RESPONSE *Response;\r
95 UINT32 MessageHeader;\r
96 UINT32 ResponseHeader;\r
97 MTL_CHANNEL *Channel;\r
98\r
99 ASSERT (PayloadLength != NULL);\r
100\r
101 Status = MtlGetChannel (MTL_CHANNEL_TYPE_LOW, &Channel);\r
102 if (EFI_ERROR (Status)) {\r
103 return Status;\r
104 }\r
105\r
106 // Fill in message header.\r
107 MessageHeader = SCMI_MESSAGE_HEADER (\r
108 Command->MessageId,\r
109 SCMI_MESSAGE_TYPE_COMMAND,\r
110 Command->ProtocolId\r
111 );\r
112\r
113 // Send payload using MTL channel.\r
114 Status = MtlSendMessage (\r
115 Channel,\r
116 MessageHeader,\r
117 *PayloadLength\r
118 );\r
119 if (EFI_ERROR (Status)) {\r
120 return Status;\r
121 }\r
122\r
123 // Wait for the response on the channel.\r
124 Status = MtlReceiveMessage (Channel, &ResponseHeader, PayloadLength);\r
125 if (EFI_ERROR (Status)) {\r
126 return Status;\r
127 }\r
128\r
129 // SCMI must return MessageHeader unmodified.\r
130 if (MessageHeader != ResponseHeader) {\r
131 ASSERT (FALSE);\r
132 return EFI_DEVICE_ERROR;\r
133 }\r
134\r
135 Response = (SCMI_MESSAGE_RESPONSE*)MtlGetChannelPayload (Channel);\r
136\r
137 if (Response->Status != SCMI_SUCCESS) {\r
138 DEBUG ((DEBUG_ERROR, "SCMI error: ProtocolId = 0x%x, MessageId = 0x%x, error = %d\n",\r
139 Command->ProtocolId,\r
140 Command->MessageId,\r
141 Response->Status\r
142 ));\r
143\r
144 ASSERT (FALSE);\r
145 return EFI_DEVICE_ERROR;\r
146 }\r
147\r
148 if (ReturnValues != NULL) {\r
149 *ReturnValues = Response->ReturnValues;\r
150 }\r
151\r
152 return EFI_SUCCESS;\r
153}\r
154\r
155/** Internal common function useful for common protocol discovery messages.\r
156\r
157 @param[in] ProtocolId Protocol Id of the the protocol.\r
158 @param[in] MesaageId Message Id of the message.\r
159\r
160 @param[out] ReturnValues SCMI response return values.\r
161\r
162 @retval EFI_SUCCESS Success with valid return values.\r
163 @retval EFI_DEVICE_ERROR SCMI error.\r
164 @retval !(EFI_SUCCESS) Other errors.\r
165**/\r
166STATIC\r
167EFI_STATUS\r
168ScmiProtocolDiscoveryCommon (\r
169 IN SCMI_PROTOCOL_ID ProtocolId,\r
170 IN SCMI_MESSAGE_ID MessageId,\r
171 OUT UINT32 **ReturnValues\r
172 )\r
173{\r
174 SCMI_COMMAND Command;\r
175 UINT32 PayloadLength = 0;\r
176\r
177 Command.ProtocolId = ProtocolId;\r
178 Command.MessageId = MessageId;\r
179\r
180 return ScmiCommandExecute (\r
181 &Command,\r
182 &PayloadLength,\r
183 ReturnValues\r
184 );\r
185}\r
186\r
187/** Return protocol version from SCP for a given protocol ID.\r
188\r
189 @param[in] Protocol ID Protocol ID.\r
190 @param[out] Version Pointer to version of the protocol.\r
191\r
192 @retval EFI_SUCCESS Version holds a valid version received\r
193 from the SCP.\r
194 @retval EFI_DEVICE_ERROR SCMI error.\r
195 @retval !(EFI_SUCCESS) Other errors.\r
196**/\r
197EFI_STATUS\r
198ScmiGetProtocolVersion (\r
199 IN SCMI_PROTOCOL_ID ProtocolId,\r
200 OUT UINT32 *Version\r
201 )\r
202{\r
203 EFI_STATUS Status;\r
204 UINT32 *ProtocolVersion;\r
205\r
206 Status = ScmiProtocolDiscoveryCommon (\r
207 ProtocolId,\r
208 SCMI_MESSAGE_ID_PROTOCOL_VERSION,\r
209 (UINT32**)&ProtocolVersion\r
210 );\r
211 if (EFI_ERROR (Status)) {\r
212 return Status;\r
213 }\r
214\r
215 *Version = *ProtocolVersion;\r
216\r
217 return EFI_SUCCESS;\r
218}\r
219\r
220/** Return protocol attributes from SCP for a given protocol ID.\r
221\r
222 @param[in] Protocol ID Protocol ID.\r
223 @param[out] ReturnValues Pointer to attributes of the protocol.\r
224\r
225 @retval EFI_SUCCESS ReturnValues points to protocol attributes.\r
226 @retval EFI_DEVICE_ERROR SCMI error.\r
227 @retval !(EFI_SUCCESS) Other errors.\r
228**/\r
229EFI_STATUS\r
230ScmiGetProtocolAttributes (\r
231 IN SCMI_PROTOCOL_ID ProtocolId,\r
232 OUT UINT32 **ReturnValues\r
233 )\r
234{\r
235 return ScmiProtocolDiscoveryCommon (\r
236 ProtocolId,\r
237 SCMI_MESSAGE_ID_PROTOCOL_ATTRIBUTES,\r
238 ReturnValues\r
239 );\r
240}\r
241\r
242/** Return protocol message attributes from SCP for a given protocol ID.\r
243\r
244 @param[in] Protocol ID Protocol ID.\r
245 @param[out] Attributes Pointer to attributes of the protocol.\r
246\r
247 @retval EFI_SUCCESS ReturnValues points to protocol message attributes.\r
248 @retval EFI_DEVICE_ERROR SCMI error.\r
249 @retval !(EFI_SUCCESS) Other errors.\r
250**/\r
251EFI_STATUS\r
252ScmiGetProtocolMessageAttributes (\r
253 IN SCMI_PROTOCOL_ID ProtocolId,\r
254 OUT UINT32 **ReturnValues\r
255 )\r
256{\r
257 return ScmiProtocolDiscoveryCommon (\r
258 ProtocolId,\r
259 SCMI_MESSAGE_ID_PROTOCOL_MESSAGE_ATTRIBUTES,\r
260 ReturnValues\r
261 );\r
262}\r