]> git.proxmox.com Git - mirror_edk2.git/blame - DynamicTablesPkg/Library/Common/SsdtSerialPortFixupLib/SsdtSerialPortFixupLib.c
DynamicTablesPkg: Apply uncrustify changes
[mirror_edk2.git] / DynamicTablesPkg / Library / Common / SsdtSerialPortFixupLib / SsdtSerialPortFixupLib.c
CommitLineData
bade7f42
PG
1/** @file\r
2 SSDT Serial Port Fixup Library.\r
3\r
42c0019f 4 Copyright (c) 2019 - 2021, Arm Limited. All rights reserved.<BR>\r
bade7f42
PG
5\r
6 SPDX-License-Identifier: BSD-2-Clause-Patent\r
7\r
8 @par Reference(s):\r
9 - Arm Server Base Boot Requirements (SBBR), s4.2.1.8 "SPCR".\r
10 - Microsoft Debug Port Table 2 (DBG2) Specification - December 10, 2015.\r
11**/\r
12\r
13#include <IndustryStandard/DebugPort2Table.h>\r
14#include <Library/AcpiLib.h>\r
15#include <Library/BaseLib.h>\r
16#include <Library/BaseMemoryLib.h>\r
17#include <Library/DebugLib.h>\r
18#include <Library/MemoryAllocationLib.h>\r
bade7f42
PG
19#include <Protocol/AcpiTable.h>\r
20\r
21// Module specific include files.\r
22#include <AcpiTableGenerator.h>\r
23#include <ConfigurationManagerObject.h>\r
24#include <ConfigurationManagerHelper.h>\r
0875443f 25#include <Library/AcpiHelperLib.h>\r
bade7f42 26#include <Library/AmlLib/AmlLib.h>\r
bade7f42
PG
27#include <Protocol/ConfigurationManagerProtocol.h>\r
28\r
29/** C array containing the compiled AML template.\r
30 This symbol is defined in the auto generated C file\r
31 containing the AML bytecode array.\r
32*/\r
33extern CHAR8 ssdtserialporttemplate_aml_code[];\r
34\r
35/** UART address range length.\r
36*/\r
731c67e1 37#define MIN_UART_ADDRESS_LENGTH 0x1000U\r
bade7f42
PG
38\r
39/** Validate the Serial Port Information.\r
40\r
41 @param [in] SerialPortInfoTable Table of CM_ARM_SERIAL_PORT_INFO.\r
42 @param [in] SerialPortCount Count of SerialPort in the table.\r
43\r
44 @retval EFI_SUCCESS Success.\r
45 @retval EFI_INVALID_PARAMETER Invalid parameter.\r
46**/\r
47EFI_STATUS\r
48EFIAPI\r
49ValidateSerialPortInfo (\r
731c67e1
MK
50 IN CONST CM_ARM_SERIAL_PORT_INFO *SerialPortInfoTable,\r
51 IN UINT32 SerialPortCount\r
bade7f42
PG
52 )\r
53{\r
731c67e1
MK
54 UINT32 Index;\r
55 CONST CM_ARM_SERIAL_PORT_INFO *SerialPortInfo;\r
bade7f42 56\r
731c67e1
MK
57 if ((SerialPortInfoTable == NULL) ||\r
58 (SerialPortCount == 0))\r
59 {\r
bade7f42
PG
60 ASSERT (0);\r
61 return EFI_INVALID_PARAMETER;\r
62 }\r
63\r
64 for (Index = 0; Index < SerialPortCount; Index++) {\r
65 SerialPortInfo = &SerialPortInfoTable[Index];\r
66 ASSERT (SerialPortInfo != NULL);\r
67\r
731c67e1
MK
68 if ((SerialPortInfo == NULL) ||\r
69 (SerialPortInfo->BaseAddress == 0))\r
70 {\r
bade7f42
PG
71 DEBUG ((\r
72 DEBUG_ERROR,\r
73 "ERROR: UART port base address is invalid. BaseAddress = 0x%llx\n",\r
74 SerialPortInfo->BaseAddress\r
75 ));\r
76 return EFI_INVALID_PARAMETER;\r
77 }\r
78\r
79 if ((SerialPortInfo->PortSubtype !=\r
80 EFI_ACPI_DBG2_PORT_SUBTYPE_SERIAL_ARM_PL011_UART) &&\r
81 (SerialPortInfo->PortSubtype !=\r
82 EFI_ACPI_DBG2_PORT_SUBTYPE_SERIAL_ARM_SBSA_GENERIC_UART_2X) &&\r
83 (SerialPortInfo->PortSubtype !=\r
84 EFI_ACPI_DBG2_PORT_SUBTYPE_SERIAL_ARM_SBSA_GENERIC_UART) &&\r
85 (SerialPortInfo->PortSubtype !=\r
86 EFI_ACPI_DBG2_PORT_SUBTYPE_SERIAL_DCC) &&\r
87 (SerialPortInfo->PortSubtype !=\r
731c67e1
MK
88 EFI_ACPI_DBG2_PORT_SUBTYPE_SERIAL_FULL_16550))\r
89 {\r
bade7f42
PG
90 DEBUG ((\r
91 DEBUG_ERROR,\r
92 "ERROR: UART port subtype is invalid."\r
93 " UART Base = 0x%llx, PortSubtype = 0x%x\n",\r
94 SerialPortInfo->BaseAddress,\r
95 SerialPortInfo->PortSubtype\r
96 ));\r
97 return EFI_INVALID_PARAMETER;\r
98 }\r
99\r
100 DEBUG ((DEBUG_INFO, "UART Configuration:\n"));\r
101 DEBUG ((\r
102 DEBUG_INFO,\r
731c67e1
MK
103 " UART Base = 0x%llx\n",\r
104 SerialPortInfo->BaseAddress\r
bade7f42
PG
105 ));\r
106 DEBUG ((\r
107 DEBUG_INFO,\r
108 " Length = 0x%llx\n",\r
109 SerialPortInfo->BaseAddressLength\r
110 ));\r
111 DEBUG ((DEBUG_INFO, " Clock = %lu\n", SerialPortInfo->Clock));\r
112 DEBUG ((DEBUG_INFO, " BaudRate = %llu\n", SerialPortInfo->BaudRate));\r
113 DEBUG ((DEBUG_INFO, " Interrupt = %lu\n", SerialPortInfo->Interrupt));\r
114 } // for\r
115\r
116 return EFI_SUCCESS;\r
117}\r
118\r
119/** Fixup the Serial Port Ids (_UID, _HID, _CID).\r
120\r
121 @param [in] RootNodeHandle Pointer to the root of an AML tree.\r
122 @param [in] Uid UID for the Serial Port.\r
123 @param [in] SerialPortInfo Pointer to a Serial Port Information\r
124 structure.\r
125 Get the Serial Port Information from there.\r
126\r
127 @retval EFI_SUCCESS The function completed successfully.\r
128 @retval EFI_INVALID_PARAMETER Invalid parameter.\r
129 @retval EFI_NOT_FOUND Could not find information.\r
130 @retval EFI_OUT_OF_RESOURCES Out of resources.\r
131**/\r
132STATIC\r
133EFI_STATUS\r
134EFIAPI\r
135FixupIds (\r
731c67e1
MK
136 IN AML_ROOT_NODE_HANDLE RootNodeHandle,\r
137 IN CONST UINT64 Uid,\r
138 IN CONST CM_ARM_SERIAL_PORT_INFO *SerialPortInfo\r
bade7f42
PG
139 )\r
140{\r
731c67e1
MK
141 EFI_STATUS Status;\r
142 AML_OBJECT_NODE_HANDLE NameOpIdNode;\r
143 CONST CHAR8 *HidString;\r
144 CONST CHAR8 *CidString;\r
145 CONST CHAR8 *NonBsaHid;\r
bade7f42
PG
146\r
147 // Get the _CID and _HID value to write.\r
148 switch (SerialPortInfo->PortSubtype) {\r
149 case EFI_ACPI_DBG2_PORT_SUBTYPE_SERIAL_FULL_16550:\r
150 {\r
42c0019f 151 // If there is a non-BSA compliant HID, use that.\r
731c67e1 152 NonBsaHid = (CONST CHAR8 *)PcdGetPtr (PcdNonBsaCompliant16550SerialHid);\r
42c0019f 153 if ((NonBsaHid != NULL) && (AsciiStrLen (NonBsaHid) != 0)) {\r
16136f21
JG
154 if (!(IsValidPnpId (NonBsaHid) || IsValidAcpiId (NonBsaHid))) {\r
155 return EFI_INVALID_PARAMETER;\r
156 }\r
157\r
42c0019f
JG
158 HidString = NonBsaHid;\r
159 CidString = "";\r
160 } else {\r
161 HidString = "PNP0501";\r
162 CidString = "PNP0500";\r
163 }\r
731c67e1 164\r
bade7f42
PG
165 break;\r
166 }\r
167 case EFI_ACPI_DBG2_PORT_SUBTYPE_SERIAL_ARM_PL011_UART:\r
168 {\r
169 HidString = "ARMH0011";\r
170 CidString = "ARMHB000";\r
171 break;\r
172 }\r
173 case EFI_ACPI_DBG2_PORT_SUBTYPE_SERIAL_ARM_SBSA_GENERIC_UART:\r
174 case EFI_ACPI_DBG2_PORT_SUBTYPE_SERIAL_ARM_SBSA_GENERIC_UART_2X:\r
175 {\r
176 HidString = "ARMH0011";\r
177 CidString = "";\r
178 break;\r
179 }\r
180 default:\r
181 {\r
182 return EFI_INVALID_PARAMETER;\r
183 }\r
184 } // switch\r
185\r
186 // Get the _UID NameOp object defined by the "Name ()" statement,\r
187 // and update its value.\r
188 Status = AmlFindNode (\r
189 RootNodeHandle,\r
190 "\\_SB_.COM0._UID",\r
191 &NameOpIdNode\r
192 );\r
193 if (EFI_ERROR (Status)) {\r
194 return Status;\r
195 }\r
196\r
197 Status = AmlNameOpUpdateInteger (NameOpIdNode, (UINT64)Uid);\r
198 if (EFI_ERROR (Status)) {\r
199 return Status;\r
200 }\r
201\r
202 // Get the _HID NameOp object defined by the "Name ()" statement,\r
203 // and update its value.\r
204 Status = AmlFindNode (\r
205 RootNodeHandle,\r
206 "\\_SB_.COM0._HID",\r
207 &NameOpIdNode\r
208 );\r
209 if (EFI_ERROR (Status)) {\r
210 return Status;\r
211 }\r
212\r
213 Status = AmlNameOpUpdateString (NameOpIdNode, HidString);\r
214 if (EFI_ERROR (Status)) {\r
215 return Status;\r
216 }\r
217\r
218 // Get the _CID NameOp object defined by the "Name ()" statement,\r
219 // and update its value.\r
220 Status = AmlFindNode (\r
221 RootNodeHandle,\r
222 "\\_SB_.COM0._CID",\r
223 &NameOpIdNode\r
224 );\r
225 if (EFI_ERROR (Status)) {\r
226 return Status;\r
227 }\r
228\r
229 // If we have a CID then update a _CID node else delete the node.\r
230 if (AsciiStrLen (CidString) != 0) {\r
231 Status = AmlNameOpUpdateString (NameOpIdNode, CidString);\r
232 } else {\r
233 // First detach the node from the tree.\r
234 Status = AmlDetachNode (NameOpIdNode);\r
235 if (EFI_ERROR (Status)) {\r
236 return Status;\r
237 }\r
238\r
239 // Delete the detached node.\r
240 Status = AmlDeleteTree (NameOpIdNode);\r
241 }\r
242\r
243 return Status;\r
244}\r
245\r
246/** Fixup the Serial Port _CRS values (BaseAddress, ...).\r
247\r
248 @param [in] RootNodeHandle Pointer to the root of an AML tree.\r
249 @param [in] SerialPortInfo Pointer to a Serial Port Information\r
250 structure.\r
251 Get the Serial Port Information from there.\r
252\r
253 @retval EFI_SUCCESS The function completed successfully.\r
254 @retval EFI_INVALID_PARAMETER Invalid parameter.\r
255 @retval EFI_NOT_FOUND Could not find information.\r
256 @retval EFI_OUT_OF_RESOURCES Out of resources.\r
257**/\r
258STATIC\r
259EFI_STATUS\r
260EFIAPI\r
261FixupCrs (\r
731c67e1
MK
262 IN AML_ROOT_NODE_HANDLE RootNodeHandle,\r
263 IN CONST CM_ARM_SERIAL_PORT_INFO *SerialPortInfo\r
bade7f42
PG
264 )\r
265{\r
731c67e1
MK
266 EFI_STATUS Status;\r
267 AML_OBJECT_NODE_HANDLE NameOpCrsNode;\r
268 AML_DATA_NODE_HANDLE QWordRdNode;\r
269 AML_DATA_NODE_HANDLE InterruptRdNode;\r
bade7f42
PG
270\r
271 // Get the "_CRS" object defined by the "Name ()" statement.\r
272 Status = AmlFindNode (\r
273 RootNodeHandle,\r
274 "\\_SB_.COM0._CRS",\r
275 &NameOpCrsNode\r
276 );\r
277 if (EFI_ERROR (Status)) {\r
278 return Status;\r
279 }\r
280\r
281 // Get the first Rd node in the "_CRS" object.\r
691c5f77 282 Status = AmlNameOpGetFirstRdNode (NameOpCrsNode, &QWordRdNode);\r
bade7f42
PG
283 if (EFI_ERROR (Status)) {\r
284 return Status;\r
285 }\r
286\r
287 if (QWordRdNode == NULL) {\r
288 return EFI_INVALID_PARAMETER;\r
289 }\r
290\r
291 // Update the Serial Port base address and length.\r
292 Status = AmlUpdateRdQWord (\r
293 QWordRdNode,\r
294 SerialPortInfo->BaseAddress,\r
295 ((SerialPortInfo->BaseAddressLength < MIN_UART_ADDRESS_LENGTH) ?\r
731c67e1 296 MIN_UART_ADDRESS_LENGTH : SerialPortInfo->BaseAddressLength)\r
bade7f42
PG
297 );\r
298 if (EFI_ERROR (Status)) {\r
299 return Status;\r
300 }\r
301\r
302 // Get the Interrupt node.\r
303 // It is the second Resource Data element in the NameOpCrsNode's\r
304 // variable list of arguments.\r
691c5f77 305 Status = AmlNameOpGetNextRdNode (QWordRdNode, &InterruptRdNode);\r
bade7f42
PG
306 if (EFI_ERROR (Status)) {\r
307 return Status;\r
308 }\r
309\r
310 if (InterruptRdNode == NULL) {\r
311 return EFI_INVALID_PARAMETER;\r
312 }\r
313\r
314 // Update the interrupt number.\r
315 return AmlUpdateRdInterrupt (InterruptRdNode, SerialPortInfo->Interrupt);\r
316}\r
317\r
318/** Fixup the Serial Port device name.\r
319\r
320 @param [in] RootNodeHandle Pointer to the root of an AML tree.\r
321 @param [in] SerialPortInfo Pointer to a Serial Port Information\r
322 structure.\r
323 Get the Serial Port Information from there.\r
324 @param [in] Name The Name to give to the Device.\r
325 Must be a NULL-terminated ASL NameString\r
326 e.g.: "DEV0", "DV15.DEV0", etc.\r
327\r
328 @retval EFI_SUCCESS The function completed successfully.\r
329 @retval EFI_INVALID_PARAMETER Invalid parameter.\r
330 @retval EFI_NOT_FOUND Could not find information.\r
331 @retval EFI_OUT_OF_RESOURCES Out of resources.\r
332**/\r
333STATIC\r
334EFI_STATUS\r
335EFIAPI\r
336FixupName (\r
731c67e1
MK
337 IN AML_ROOT_NODE_HANDLE RootNodeHandle,\r
338 IN CONST CM_ARM_SERIAL_PORT_INFO *SerialPortInfo,\r
339 IN CONST CHAR8 *Name\r
bade7f42
PG
340 )\r
341{\r
731c67e1
MK
342 EFI_STATUS Status;\r
343 AML_OBJECT_NODE_HANDLE DeviceNode;\r
bade7f42
PG
344\r
345 // Get the COM0 variable defined by the "Device ()" statement.\r
346 Status = AmlFindNode (RootNodeHandle, "\\_SB_.COM0", &DeviceNode);\r
347 if (EFI_ERROR (Status)) {\r
348 return Status;\r
349 }\r
350\r
351 // Update the Device's name.\r
731c67e1 352 return AmlDeviceOpUpdateName (DeviceNode, (CHAR8 *)Name);\r
bade7f42
PG
353}\r
354\r
355/** Fixup the Serial Port Information in the AML tree.\r
356\r
357 For each template value:\r
358 - find the node to update;\r
359 - update the value.\r
360\r
361 @param [in] RootNodeHandle Pointer to the root of the AML tree.\r
362 @param [in] SerialPortInfo Pointer to a Serial Port Information\r
363 structure.\r
364 Get the Serial Port Information from there.\r
365 @param [in] Name The Name to give to the Device.\r
366 Must be a NULL-terminated ASL NameString\r
367 e.g.: "DEV0", "DV15.DEV0", etc.\r
368 @param [in] Uid UID for the Serial Port.\r
369 @param [out] Table If success, contains the serialized\r
370 SSDT table.\r
371\r
372 @retval EFI_SUCCESS The function completed successfully.\r
373 @retval EFI_INVALID_PARAMETER Invalid parameter.\r
374 @retval EFI_NOT_FOUND Could not find information.\r
375 @retval EFI_OUT_OF_RESOURCES Out of resources.\r
376**/\r
377STATIC\r
378EFI_STATUS\r
379EFIAPI\r
380FixupSerialPortInfo (\r
731c67e1
MK
381 IN AML_ROOT_NODE_HANDLE RootNodeHandle,\r
382 IN CONST CM_ARM_SERIAL_PORT_INFO *SerialPortInfo,\r
383 IN CONST CHAR8 *Name,\r
384 IN CONST UINT64 Uid,\r
385 OUT EFI_ACPI_DESCRIPTION_HEADER **Table\r
bade7f42
PG
386 )\r
387{\r
731c67e1 388 EFI_STATUS Status;\r
bade7f42
PG
389\r
390 ASSERT (RootNodeHandle != NULL);\r
391 ASSERT (SerialPortInfo != NULL);\r
392 ASSERT (Name != NULL);\r
393 ASSERT (Table != NULL);\r
394\r
395 // Fixup the _UID, _HID and _CID values.\r
396 Status = FixupIds (RootNodeHandle, Uid, SerialPortInfo);\r
397 if (EFI_ERROR (Status)) {\r
398 return Status;\r
399 }\r
400\r
401 // Fixup the _CRS values.\r
402 Status = FixupCrs (RootNodeHandle, SerialPortInfo);\r
403 if (EFI_ERROR (Status)) {\r
404 return Status;\r
405 }\r
406\r
407 // Fixup the serial-port name.\r
408 // This MUST be done at the end, otherwise AML paths won't be valid anymore.\r
409 return FixupName (RootNodeHandle, SerialPortInfo, Name);\r
410}\r
411\r
412/** Free an SSDT table previously created by\r
413 the BuildSsdtSerialTable function.\r
414\r
415 @param [in] Table Pointer to a SSDT table allocated by\r
416 the BuildSsdtSerialTable function.\r
417\r
418 @retval EFI_SUCCESS Success.\r
419**/\r
420EFI_STATUS\r
421EFIAPI\r
422FreeSsdtSerialPortTable (\r
731c67e1 423 IN EFI_ACPI_DESCRIPTION_HEADER *Table\r
bade7f42
PG
424 )\r
425{\r
426 ASSERT (Table != NULL);\r
427 FreePool (Table);\r
428 return EFI_SUCCESS;\r
429}\r
430\r
431/** Build a SSDT table describing the input serial port.\r
432\r
433 The table created by this function must be freed by FreeSsdtSerialTable.\r
434\r
435 @param [in] AcpiTableInfo Pointer to the ACPI table information.\r
436 @param [in] SerialPortInfo Serial port to describe in the SSDT table.\r
437 @param [in] Name The Name to give to the Device.\r
438 Must be a NULL-terminated ASL NameString\r
439 e.g.: "DEV0", "DV15.DEV0", etc.\r
440 @param [in] Uid UID for the Serial Port.\r
441 @param [out] Table If success, pointer to the created SSDT table.\r
442\r
443 @retval EFI_SUCCESS Table generated successfully.\r
444 @retval EFI_INVALID_PARAMETER A parameter is invalid.\r
445 @retval EFI_NOT_FOUND Could not find information.\r
446 @retval EFI_OUT_OF_RESOURCES Could not allocate memory.\r
447**/\r
448EFI_STATUS\r
449EFIAPI\r
450BuildSsdtSerialPortTable (\r
731c67e1
MK
451 IN CONST CM_STD_OBJ_ACPI_TABLE_INFO *AcpiTableInfo,\r
452 IN CONST CM_ARM_SERIAL_PORT_INFO *SerialPortInfo,\r
453 IN CONST CHAR8 *Name,\r
454 IN CONST UINT64 Uid,\r
455 OUT EFI_ACPI_DESCRIPTION_HEADER **Table\r
bade7f42
PG
456 )\r
457{\r
731c67e1
MK
458 EFI_STATUS Status;\r
459 EFI_STATUS Status1;\r
460 AML_ROOT_NODE_HANDLE RootNodeHandle;\r
bade7f42
PG
461\r
462 ASSERT (AcpiTableInfo != NULL);\r
463 ASSERT (SerialPortInfo != NULL);\r
464 ASSERT (Name != NULL);\r
465 ASSERT (Table != NULL);\r
466\r
467 // Validate the Serial Port Info.\r
468 Status = ValidateSerialPortInfo (SerialPortInfo, 1);\r
469 if (EFI_ERROR (Status)) {\r
470 return Status;\r
471 }\r
472\r
473 // Parse the SSDT Serial Port Template.\r
474 Status = AmlParseDefinitionBlock (\r
731c67e1 475 (EFI_ACPI_DESCRIPTION_HEADER *)ssdtserialporttemplate_aml_code,\r
bade7f42
PG
476 &RootNodeHandle\r
477 );\r
478 if (EFI_ERROR (Status)) {\r
479 DEBUG ((\r
480 DEBUG_ERROR,\r
481 "ERROR: SSDT-SERIAL-PORT-FIXUP:"\r
482 " Failed to parse SSDT Serial Port Template. Status = %r\n",\r
483 Status\r
484 ));\r
485 return Status;\r
486 }\r
487\r
488 // Fixup the template values.\r
489 Status = FixupSerialPortInfo (\r
490 RootNodeHandle,\r
491 SerialPortInfo,\r
492 Name,\r
493 Uid,\r
494 Table\r
495 );\r
496 if (EFI_ERROR (Status)) {\r
497 DEBUG ((\r
498 DEBUG_ERROR,\r
499 "ERROR: SSDT-SERIAL-PORT-FIXUP: Failed to fixup SSDT Serial Port Table."\r
500 " Status = %r\n",\r
501 Status\r
502 ));\r
503 goto exit_handler;\r
504 }\r
505\r
506 // Serialize the tree.\r
507 Status = AmlSerializeDefinitionBlock (\r
508 RootNodeHandle,\r
509 Table\r
510 );\r
511 if (EFI_ERROR (Status)) {\r
512 DEBUG ((\r
513 DEBUG_ERROR,\r
514 "ERROR: SSDT-SERIAL-PORT-FIXUP: Failed to Serialize SSDT Table Data."\r
515 " Status = %r\n",\r
516 Status\r
517 ));\r
518 }\r
519\r
520exit_handler:\r
521 // Cleanup\r
522 if (RootNodeHandle != NULL) {\r
523 Status1 = AmlDeleteTree (RootNodeHandle);\r
524 if (EFI_ERROR (Status1)) {\r
525 DEBUG ((\r
526 DEBUG_ERROR,\r
527 "ERROR: SSDT-SERIAL-PORT-FIXUP: Failed to cleanup AML tree."\r
528 " Status = %r\n",\r
529 Status1\r
530 ));\r
531 // If Status was success but we failed to delete the AML Tree\r
532 // return Status1 else return the original error code, i.e. Status.\r
533 if (!EFI_ERROR (Status)) {\r
534 return Status1;\r
535 }\r
536 }\r
537 }\r
538\r
539 return Status;\r
540}\r