]> git.proxmox.com Git - mirror_edk2.git/blame - DynamicTablesPkg/Library/Acpi/Arm/AcpiSsdtCmn600LibArm/SsdtCmn600Generator.c
DynamicTablesPkg: Extract AcpiHelperLib from TableHelperLib
[mirror_edk2.git] / DynamicTablesPkg / Library / Acpi / Arm / AcpiSsdtCmn600LibArm / SsdtCmn600Generator.c
CommitLineData
37568365
PG
1/** @file\r
2 SSDT CMN-600 AML Table Generator.\r
3\r
1f515342 4 Copyright (c) 2020 - 2021, Arm Limited. All rights reserved.<BR>\r
37568365
PG
5\r
6 SPDX-License-Identifier: BSD-2-Clause-Patent\r
7\r
8 @par Reference(s):\r
9 - Arm CoreLink CMN-600 Coherent Mesh Network Technical Reference Manual r3p0\r
10 - Generic ACPI for Arm Components 1.0 Platform Design Document\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
19#include <Library/UefiBootServicesTableLib.h>\r
20#include <Protocol/AcpiTable.h>\r
21\r
22// Module specific include files.\r
23#include <AcpiTableGenerator.h>\r
24#include <ConfigurationManagerObject.h>\r
25#include <ConfigurationManagerHelper.h>\r
0875443f 26#include <Library/AcpiHelperLib.h>\r
37568365 27#include <Library/AmlLib/AmlLib.h>\r
37568365
PG
28#include <Protocol/ConfigurationManagerProtocol.h>\r
29#include "SsdtCmn600Generator.h"\r
30\r
31/** C array containing the compiled AML template.\r
32 This symbol is defined in the auto generated C file\r
33 containing the AML bytecode array.\r
34*/\r
35extern CHAR8 ssdtcmn600template_aml_code[];\r
36\r
37/** SSDT CMN-600 Table Generator.\r
38\r
39 Requirements:\r
40 The following Configuration Manager Object(s) are required by\r
41 this Generator:\r
42 - EArmObjCmn600Info\r
43*/\r
44\r
45/** This macro expands to a function that retrieves the CMN-600\r
46 Information from the Configuration Manager.\r
47*/\r
48GET_OBJECT_LIST (\r
49 EObjNameSpaceArm,\r
50 EArmObjCmn600Info,\r
51 CM_ARM_CMN_600_INFO\r
52 );\r
53\r
54/** Check the CMN-600 Information.\r
55\r
56 @param [in] Cmn600InfoList Array of CMN-600 information structure.\r
57 @param [in] Cmn600Count Count of CMN-600 information structure.\r
58\r
59 @retval EFI_SUCCESS The function completed successfully.\r
60 @retval EFI_INVALID_PARAMETER Invalid parameter.\r
61**/\r
62STATIC\r
63EFI_STATUS\r
64EFIAPI\r
65ValidateCmn600Info (\r
66 IN CONST CM_ARM_CMN_600_INFO * Cmn600InfoList,\r
67 IN CONST UINT32 Cmn600Count\r
68 )\r
69{\r
70 UINT32 Index;\r
71 UINT32 DtcIndex;\r
72 CONST CM_ARM_CMN_600_INFO * Cmn600Info;\r
73 CONST CM_ARM_GENERIC_INTERRUPT * DtcInterrupt;\r
74\r
75 if ((Cmn600InfoList == NULL) ||\r
76 (Cmn600Count == 0)) {\r
77 return EFI_INVALID_PARAMETER;\r
78 }\r
79\r
80 // Validate each Cmn600Info structure.\r
81 for (Index = 0; Index < Cmn600Count; Index++) {\r
82 Cmn600Info = &Cmn600InfoList[Index];\r
83\r
84 // At least one DTC is required.\r
85 if ((Cmn600Info->DtcCount == 0) ||\r
86 (Cmn600Info->DtcCount > MAX_DTC_COUNT)) {\r
87 DEBUG ((\r
88 DEBUG_ERROR,\r
89 "ERROR: SSDT-CMN-600: Invalid DTC configuration:\n"\r
90 ));\r
91 goto error_handler;\r
92 }\r
93\r
94 // Check PERIPHBASE and ROOTNODEBASE address spaces are initialized.\r
95 if ((Cmn600Info->PeriphBaseAddress == 0) ||\r
96 (Cmn600Info->RootNodeBaseAddress == 0)) {\r
97 DEBUG ((\r
98 DEBUG_ERROR,\r
99 "ERROR: SSDT-CMN-600: Invalid PERIPHBASE or ROOTNODEBASE.\n"\r
100 ));\r
101 goto error_handler;\r
102 }\r
103\r
104 // The PERIPHBASE address must be 64MB aligned for a (X < 4) && (Y < 4)\r
105 // dimension mesh, and 256MB aligned otherwise.\r
106 // Check it is a least 64MB aligned.\r
107 if ((Cmn600Info->PeriphBaseAddress &\r
108 (PERIPHBASE_MIN_ADDRESS_LENGTH - 1)) != 0) {\r
109 DEBUG ((\r
110 DEBUG_ERROR,\r
111 "ERROR: SSDT-CMN-600: PERIPHBASE address must be 64MB aligned.\n"\r
112 ));\r
113 goto error_handler;\r
114 }\r
115\r
116 // The PERIPHBASE address is at most 64MB for a (X < 4) && (Y < 4)\r
117 // dimension mesh, and 256MB otherwise. Check it is not more than 256MB.\r
118 if (Cmn600Info->PeriphBaseAddressLength > PERIPHBASE_MAX_ADDRESS_LENGTH) {\r
119 DEBUG ((\r
120 DEBUG_ERROR,\r
121 "ERROR: SSDT-CMN-600: PERIPHBASE address range must be < 256MB.\n"\r
122 ));\r
123 goto error_handler;\r
124 }\r
125\r
126 // Check the 16 KB alignment of the ROOTNODEBASE address.\r
127 if ((Cmn600Info->PeriphBaseAddress &\r
128 (ROOTNODEBASE_ADDRESS_LENGTH - 1)) != 0) {\r
129 DEBUG ((\r
130 DEBUG_ERROR,\r
131 "ERROR: SSDT-CMN-600: Root base address must be 16KB aligned.\n"\r
132 ));\r
133 goto error_handler;\r
134 }\r
135\r
136 // The ROOTNODEBASE address space should be included in the PERIPHBASE\r
137 // address space.\r
138 if ((Cmn600Info->PeriphBaseAddress > Cmn600Info->RootNodeBaseAddress) ||\r
139 ((Cmn600Info->PeriphBaseAddress + Cmn600Info->PeriphBaseAddressLength) <\r
140 (Cmn600Info->RootNodeBaseAddress + ROOTNODEBASE_ADDRESS_LENGTH))) {\r
141 DEBUG ((\r
142 DEBUG_ERROR,\r
143 "ERROR: SSDT-CMN-600:"\r
144 " ROOTNODEBASE address space not in PERIPHBASE address space.\n"\r
145 ));\r
146 goto error_handler;\r
147 }\r
148\r
149 for (DtcIndex = 0; DtcIndex < Cmn600Info->DtcCount; DtcIndex++) {\r
150 DtcInterrupt = &Cmn600Info->DtcInterrupt[DtcIndex];\r
151 if (((DtcInterrupt->Flags &\r
152 EFI_ACPI_EXTENDED_INTERRUPT_FLAG_PRODUCER_CONSUMER_MASK) == 0)) {\r
153 DEBUG ((\r
154 DEBUG_ERROR,\r
155 "ERROR: SSDT-CMN-600: DTC Interrupt must be consumer.\n"\r
156 ));\r
157 goto error_handler;\r
158 }\r
159 } // for DTC Interrupt\r
160\r
161 } //for Cmn600InfoList\r
162\r
163 return EFI_SUCCESS;\r
164\r
165error_handler:\r
166\r
167 DEBUG ((\r
168 DEBUG_ERROR,\r
169 "PeriphBaseAddress = 0x%llx\n"\r
170 "PeriphBaseAddressLength = 0x%llx\n"\r
171 "RootNodeBaseAddress = 0x%llx\n"\r
172 "DtcCount = %u\n",\r
173 Cmn600Info->PeriphBaseAddress,\r
174 Cmn600Info->PeriphBaseAddressLength,\r
175 Cmn600Info->RootNodeBaseAddress,\r
176 Cmn600Info->DtcCount\r
177 ));\r
178\r
179 DEBUG_CODE (\r
180 for (DtcIndex = 0; DtcIndex < Cmn600Info->DtcCount; DtcIndex++) {\r
181 DtcInterrupt = &Cmn600Info->DtcInterrupt[DtcIndex];\r
182 DEBUG ((\r
183 DEBUG_ERROR,\r
184 " DTC[%d]:\n",\r
185 DtcIndex\r
186 ));\r
187 DEBUG ((\r
188 DEBUG_ERROR,\r
189 " Interrupt = 0x%lx\n",\r
190 DtcInterrupt->Interrupt\r
191 ));\r
192 DEBUG ((\r
193 DEBUG_ERROR,\r
194 " Flags = 0x%lx\n",\r
195 DtcInterrupt->Flags\r
196 ));\r
197 } // for\r
198 );\r
199\r
200 return EFI_INVALID_PARAMETER;\r
201}\r
202\r
203/** Build a SSDT table describing the CMN-600 device.\r
204\r
205 The table created by this function must be freed by FreeSsdtCmn600Table.\r
206\r
207 @param [in] Cmn600Info Pointer to a Cmn600 structure.\r
208 @param [in] Name The Name to give to the Device.\r
209 Must be a NULL-terminated ASL NameString\r
210 e.g.: "DEV0", "DV15.DEV0", etc.\r
211 @param [in] Uid UID for the CMN600 device.\r
212 @param [out] Table If success, pointer to the created SSDT table.\r
213\r
214 @retval EFI_SUCCESS Table generated successfully.\r
215 @retval EFI_INVALID_PARAMETER A parameter is invalid.\r
216 @retval EFI_NOT_FOUND Could not find information.\r
217 @retval EFI_OUT_OF_RESOURCES Could not allocate memory.\r
218**/\r
219STATIC\r
220EFI_STATUS\r
221EFIAPI\r
222FixupCmn600Info (\r
223 IN CONST CM_ARM_CMN_600_INFO * Cmn600Info,\r
224 IN CONST CHAR8 * Name,\r
225 IN CONST UINT64 Uid,\r
226 OUT EFI_ACPI_DESCRIPTION_HEADER ** Table\r
227 )\r
228{\r
229 EFI_STATUS Status;\r
230 EFI_STATUS Status1;\r
231 UINT8 Index;\r
232 CONST CM_ARM_GENERIC_INTERRUPT * DtcInt;\r
233\r
234 EFI_ACPI_DESCRIPTION_HEADER * SsdtCmn600Template;\r
235 AML_ROOT_NODE_HANDLE RootNodeHandle;\r
236 AML_OBJECT_NODE_HANDLE NameOpIdNode;\r
237 AML_OBJECT_NODE_HANDLE NameOpCrsNode;\r
238 AML_DATA_NODE_HANDLE CmnPeriphBaseRdNode;\r
239 AML_DATA_NODE_HANDLE CmnRootNodeBaseRdNode;\r
240 AML_OBJECT_NODE_HANDLE DeviceNode;\r
241\r
242 // Parse the Ssdt CMN-600 Template.\r
243 SsdtCmn600Template = (EFI_ACPI_DESCRIPTION_HEADER*)\r
244 ssdtcmn600template_aml_code;\r
245\r
246 RootNodeHandle = NULL;\r
247 Status = AmlParseDefinitionBlock (\r
248 SsdtCmn600Template,\r
249 &RootNodeHandle\r
250 );\r
251 if (EFI_ERROR (Status)) {\r
252 DEBUG ((\r
253 DEBUG_ERROR,\r
254 "ERROR: SSDT-CMN-600: Failed to parse SSDT CMN-600 Template."\r
255 " Status = %r\n",\r
256 Status\r
257 ));\r
258 return Status;\r
259 }\r
260\r
261 // Get the _UID NameOp object defined by the "Name ()" statement,\r
262 // and update its value.\r
263 Status = AmlFindNode (\r
264 RootNodeHandle,\r
265 "\\_SB_.CMN0._UID",\r
266 &NameOpIdNode\r
267 );\r
268 if (EFI_ERROR (Status)) {\r
269 goto error_handler;\r
270 }\r
271\r
272 Status = AmlNameOpUpdateInteger (NameOpIdNode, (UINT64)Uid);\r
273 if (EFI_ERROR (Status)) {\r
274 goto error_handler;\r
275 }\r
276\r
277 // Get the _CRS object defined by the "Name ()" statement.\r
278 Status = AmlFindNode (\r
279 RootNodeHandle,\r
280 "\\_SB.CMN0._CRS",\r
281 &NameOpCrsNode\r
282 );\r
283 if (EFI_ERROR (Status)) {\r
284 goto error_handler;\r
285 }\r
286\r
287 // Get the first Rd node in the "_CRS" object.\r
288 // This is the PERIPHBASE node.\r
289 Status = AmlNameOpCrsGetFirstRdNode (NameOpCrsNode, &CmnPeriphBaseRdNode);\r
290 if (EFI_ERROR (Status)) {\r
291 goto error_handler;\r
292 }\r
293\r
294 if (CmnPeriphBaseRdNode == NULL) {\r
295 Status = EFI_INVALID_PARAMETER;\r
296 goto error_handler;\r
297 }\r
298\r
299 // Update the PERIPHBASE base address and length.\r
300 Status = AmlUpdateRdQWord (\r
301 CmnPeriphBaseRdNode,\r
302 Cmn600Info->PeriphBaseAddress,\r
303 Cmn600Info->PeriphBaseAddressLength\r
304 );\r
305 if (EFI_ERROR (Status)) {\r
306 goto error_handler;\r
307 }\r
308\r
309 // Get the QWord node corresponding to the ROOTNODEBASE.\r
310 // It is the second Resource Data element in the BufferNode's\r
311 // variable list of arguments.\r
312 Status = AmlNameOpCrsGetNextRdNode (\r
313 CmnPeriphBaseRdNode,\r
314 &CmnRootNodeBaseRdNode\r
315 );\r
316 if (EFI_ERROR (Status)) {\r
317 goto error_handler;\r
318 }\r
319\r
320 if (CmnRootNodeBaseRdNode == NULL) {\r
321 Status = EFI_INVALID_PARAMETER;\r
322 goto error_handler;\r
323 }\r
324\r
325 // Update the ROOTNODEBASE base address and length.\r
326 Status = AmlUpdateRdQWord (\r
327 CmnRootNodeBaseRdNode,\r
328 Cmn600Info->RootNodeBaseAddress,\r
329 ROOTNODEBASE_ADDRESS_LENGTH\r
330 );\r
331 if (EFI_ERROR (Status)) {\r
332 goto error_handler;\r
333 }\r
334\r
335 // Add the Interrupt node(s).\r
336 // Generate Resource Data node(s) corresponding to the "Interrupt ()"\r
337 // ASL function and add it at the last position in the list of\r
338 // Resource Data nodes.\r
339 for (Index = 0; Index < Cmn600Info->DtcCount; Index++) {\r
340 DtcInt = &Cmn600Info->DtcInterrupt[Index];\r
341 Status = AmlCodeGenCrsAddRdInterrupt (\r
342 NameOpCrsNode,\r
343 ((DtcInt->Flags &\r
344 EFI_ACPI_EXTENDED_INTERRUPT_FLAG_PRODUCER_CONSUMER_MASK) != 0),\r
345 ((DtcInt->Flags &\r
346 EFI_ACPI_EXTENDED_INTERRUPT_FLAG_MODE_MASK) != 0),\r
347 ((DtcInt->Flags &\r
348 EFI_ACPI_EXTENDED_INTERRUPT_FLAG_POLARITY_MASK) != 0),\r
349 ((DtcInt->Flags &\r
350 EFI_ACPI_EXTENDED_INTERRUPT_FLAG_SHARABLE_MASK) != 0),\r
351 (UINT32*)&DtcInt->Interrupt,\r
352 1\r
353 );\r
354 if (EFI_ERROR (Status)) {\r
355 goto error_handler;\r
356 }\r
357 } // for\r
358\r
359 // Fixup the CMN600 device name.\r
360 // This MUST be done at the end, otherwise AML paths won't be valid anymore.\r
361 // Get the CMN0 variable defined by the "Device ()" statement.\r
362 Status = AmlFindNode (RootNodeHandle, "\\_SB_.CMN0", &DeviceNode);\r
363 if (EFI_ERROR (Status)) {\r
364 goto error_handler;\r
365 }\r
366\r
367 // Update the CMN600 Device's name.\r
368 Status = AmlDeviceOpUpdateName (DeviceNode, (CHAR8*)Name);\r
369 if (EFI_ERROR (Status)) {\r
370 goto error_handler;\r
371 }\r
372\r
373 // Serialise the definition block\r
374 Status = AmlSerializeDefinitionBlock (\r
375 RootNodeHandle,\r
376 Table\r
377 );\r
378 if (EFI_ERROR (Status)) {\r
379 DEBUG ((\r
380 DEBUG_ERROR,\r
381 "ERROR: SSDT-CMN-600: Failed to Serialize SSDT Table Data."\r
382 " Status = %r\n",\r
383 Status\r
384 ));\r
385 }\r
386\r
387error_handler:\r
388 // Cleanup\r
389 if (RootNodeHandle != NULL) {\r
390 Status1 = AmlDeleteTree (RootNodeHandle);\r
391 if (EFI_ERROR (Status1)) {\r
392 DEBUG ((\r
393 DEBUG_ERROR,\r
394 "ERROR: SSDT-CMN-600: Failed to cleanup AML tree."\r
395 " Status = %r\n",\r
396 Status1\r
397 ));\r
398 // If Status was success but we failed to delete the AML Tree\r
399 // return Status1 else return the original error code, i.e. Status.\r
400 if (!EFI_ERROR (Status)) {\r
401 return Status1;\r
402 }\r
403 }\r
404 }\r
405\r
406 return Status;\r
407}\r
408\r
409/** Free any resources allocated for constructing the SSDT tables for CMN-600.\r
410\r
411 @param [in] This Pointer to the ACPI table generator.\r
412 @param [in] AcpiTableInfo Pointer to the ACPI Table Info.\r
413 @param [in] CfgMgrProtocol Pointer to the Configuration Manager\r
414 Protocol Interface.\r
415 @param [in, out] Table Pointer to an array of pointers\r
416 to ACPI Table(s).\r
417 @param [in] TableCount Number of ACPI table(s).\r
418\r
419 @retval EFI_SUCCESS The resources were freed successfully.\r
420 @retval EFI_INVALID_PARAMETER The table pointer is NULL or invalid.\r
421**/\r
422STATIC\r
423EFI_STATUS\r
424EFIAPI\r
425FreeSsdtCmn600TableResourcesEx (\r
426 IN CONST ACPI_TABLE_GENERATOR * CONST This,\r
427 IN CONST CM_STD_OBJ_ACPI_TABLE_INFO * CONST AcpiTableInfo,\r
428 IN CONST EDKII_CONFIGURATION_MANAGER_PROTOCOL * CONST CfgMgrProtocol,\r
429 IN OUT EFI_ACPI_DESCRIPTION_HEADER *** CONST Table,\r
430 IN CONST UINTN TableCount\r
431 )\r
432{\r
433 EFI_ACPI_DESCRIPTION_HEADER ** TableList;\r
434 UINTN Index;\r
435\r
436 ASSERT (This != NULL);\r
437 ASSERT (AcpiTableInfo != NULL);\r
438 ASSERT (CfgMgrProtocol != NULL);\r
439 ASSERT (AcpiTableInfo->TableGeneratorId == This->GeneratorID);\r
440 ASSERT (AcpiTableInfo->AcpiTableSignature == This->AcpiTableSignature);\r
441\r
442 if ((Table == NULL) ||\r
443 (*Table == NULL) ||\r
444 (TableCount == 0)) {\r
445 DEBUG ((DEBUG_ERROR, "ERROR: SSDT-CMN-600: Invalid Table Pointer\n"));\r
446 return EFI_INVALID_PARAMETER;\r
447 }\r
448\r
449 TableList = *Table;\r
450\r
451 for (Index = 0; Index < TableCount; Index++) {\r
452 if ((TableList[Index] != NULL) &&\r
453 (TableList[Index]->Signature ==\r
454 EFI_ACPI_6_3_SECONDARY_SYSTEM_DESCRIPTION_TABLE_SIGNATURE)) {\r
455 FreePool (TableList[Index]);\r
456 } else {\r
457 DEBUG ((\r
458 DEBUG_ERROR,\r
459 "ERROR: SSDT-CMN-600: Could not free SSDT table at index %d."\r
460 " Status = %r\n",\r
461 Index,\r
462 EFI_INVALID_PARAMETER\r
463 ));\r
464 return EFI_INVALID_PARAMETER;\r
465 }\r
466 } //for\r
467\r
468 // Free the table list.\r
469 FreePool (*Table);\r
470 *Table = NULL;\r
471 return EFI_SUCCESS;\r
472}\r
473\r
474/** Construct SSDT tables for describing CMN-600 meshes.\r
475\r
476 This function invokes the Configuration Manager protocol interface\r
477 to get the required hardware information for generating the ACPI\r
478 table.\r
479\r
480 If this function allocates any resources then they must be freed\r
481 in the FreeXXXXTableResourcesEx function.\r
482\r
483 @param [in] This Pointer to the ACPI table generator.\r
484 @param [in] AcpiTableInfo Pointer to the ACPI table information.\r
485 @param [in] CfgMgrProtocol Pointer to the Configuration Manager\r
486 Protocol interface.\r
487 @param [out] Table Pointer to a list of generated ACPI table(s).\r
488 @param [out] TableCount Number of generated ACPI table(s).\r
489\r
490 @retval EFI_SUCCESS Table generated successfully.\r
491 @retval EFI_BAD_BUFFER_SIZE The size returned by the Configuration\r
492 Manager is less than the Object size for\r
493 the requested object.\r
494 @retval EFI_INVALID_PARAMETER A parameter is invalid.\r
495 @retval EFI_NOT_FOUND Could not find information.\r
496 @retval EFI_OUT_OF_RESOURCES Could not allocate memory.\r
497 @retval EFI_UNSUPPORTED Unsupported configuration.\r
498**/\r
499STATIC\r
500EFI_STATUS\r
501EFIAPI\r
502BuildSsdtCmn600TableEx (\r
503 IN CONST ACPI_TABLE_GENERATOR * This,\r
504 IN CONST CM_STD_OBJ_ACPI_TABLE_INFO * CONST AcpiTableInfo,\r
505 IN CONST EDKII_CONFIGURATION_MANAGER_PROTOCOL * CONST CfgMgrProtocol,\r
506 OUT EFI_ACPI_DESCRIPTION_HEADER *** Table,\r
507 OUT UINTN * CONST TableCount\r
508 )\r
509{\r
510 EFI_STATUS Status;\r
511 UINT64 Index;\r
512 CM_ARM_CMN_600_INFO * Cmn600Info;\r
513 UINT32 Cmn600Count;\r
1f515342 514 CHAR8 NewName[AML_NAME_SEG_SIZE + 1];\r
37568365
PG
515 EFI_ACPI_DESCRIPTION_HEADER ** TableList;\r
516\r
517 ASSERT (This != NULL);\r
518 ASSERT (AcpiTableInfo != NULL);\r
519 ASSERT (CfgMgrProtocol != NULL);\r
520 ASSERT (Table != NULL);\r
521 ASSERT (TableCount != NULL);\r
522 ASSERT (AcpiTableInfo->TableGeneratorId == This->GeneratorID);\r
523 ASSERT (AcpiTableInfo->AcpiTableSignature == This->AcpiTableSignature);\r
524\r
525 *Table = NULL;\r
526\r
527 // Get CMN-600 information.\r
528 Status = GetEArmObjCmn600Info (\r
529 CfgMgrProtocol,\r
530 CM_NULL_TOKEN,\r
531 &Cmn600Info,\r
532 &Cmn600Count\r
533 );\r
534 if (EFI_ERROR (Status)) {\r
535 DEBUG ((\r
536 DEBUG_ERROR,\r
537 "ERROR: SSDT-CMN-600: Failed to get the CMN-600 information."\r
538 " Status = %r\n",\r
539 Status\r
540 ));\r
541 return Status;\r
542 }\r
543\r
544 if ((Cmn600Count == 0) || (Cmn600Count > MAX_CMN600_DEVICES_SUPPORTED)) {\r
545 DEBUG ((\r
546 DEBUG_ERROR,\r
547 "ERROR: SSDT-CMN-600: CMN600 peripheral count = %d."\r
548 " This must be between 1 to 16.\n",\r
549 Cmn600Count\r
550 ));\r
551 return EFI_INVALID_PARAMETER;\r
552 }\r
553\r
554 // Validate the CMN-600 Info.\r
555 Status = ValidateCmn600Info (Cmn600Info, Cmn600Count);\r
556 if (EFI_ERROR (Status)) {\r
557 DEBUG ((\r
558 DEBUG_ERROR,\r
559 "ERROR: SSDT-CMN-600: Invalid CMN600 information. Status = %r\n",\r
560 Status\r
561 ));\r
562 return Status;\r
563 }\r
564\r
565 // Allocate a table to store pointers to the SSDT tables.\r
566 TableList = (EFI_ACPI_DESCRIPTION_HEADER**)\r
567 AllocateZeroPool (\r
568 (sizeof (EFI_ACPI_DESCRIPTION_HEADER*) * Cmn600Count)\r
569 );\r
570 if (TableList == NULL) {\r
571 Status = EFI_OUT_OF_RESOURCES;\r
572 DEBUG ((\r
573 DEBUG_ERROR,\r
574 "ERROR: SSDT-CMN-600: Failed to allocate memory for Table List."\r
575 " Status = %r\n",\r
576 Status\r
577 ));\r
578 return Status;\r
579 }\r
580\r
581 // Setup the table list early so that that appropriate cleanup\r
582 // can be done in case of failure.\r
583 *Table = TableList;\r
584\r
585 NewName[0] = 'C';\r
586 NewName[1] = 'M';\r
587 NewName[2] = 'N';\r
588 NewName[4] = '\0';\r
589 for (Index = 0; Index < Cmn600Count; Index++) {\r
590 NewName[3] = AsciiFromHex ((UINT8)(Index));\r
591\r
592 // Build a SSDT table describing the CMN600 device.\r
593 Status = FixupCmn600Info (\r
594 &Cmn600Info[Index],\r
595 NewName,\r
596 Index,\r
597 &TableList[Index]\r
598 );\r
599 if (EFI_ERROR (Status)) {\r
600 DEBUG ((\r
601 DEBUG_ERROR,\r
602 "ERROR: SSDT-CMN-600: Failed to build associated SSDT table."\r
603 " Status = %r\n",\r
604 Status\r
605 ));\r
606 break;\r
607 }\r
608\r
609 // Increment the table count here so that appropriate clean-up\r
610 // can be done in case of failure.\r
611 *TableCount += 1;\r
612 } // for\r
613\r
614 // Note: Table list and CMN600 device count has been setup. The\r
615 // framework will invoke FreeSsdtCmn600TableResourcesEx() even\r
616 // on failure, so appropriate clean-up will be done.\r
617 return Status;\r
618}\r
619\r
620/** This macro defines the Raw Generator revision.\r
621*/\r
622#define SSDT_CMN_600_GENERATOR_REVISION CREATE_REVISION (1, 0)\r
623\r
624/** The interface for the Raw Table Generator.\r
625*/\r
626STATIC\r
627CONST\r
628ACPI_TABLE_GENERATOR SsdtCmn600Generator = {\r
629 // Generator ID\r
630 CREATE_STD_ACPI_TABLE_GEN_ID (EStdAcpiTableIdSsdtCmn600),\r
631 // Generator Description\r
632 L"ACPI.STD.SSDT.CMN600.GENERATOR",\r
633 // ACPI Table Signature\r
634 EFI_ACPI_6_3_SECONDARY_SYSTEM_DESCRIPTION_TABLE_SIGNATURE,\r
635 // ACPI Table Revision - Unused\r
636 0,\r
637 // Minimum ACPI Table Revision - Unused\r
638 0,\r
639 // Creator ID\r
640 TABLE_GENERATOR_CREATOR_ID_ARM,\r
641 // Creator Revision\r
642 SSDT_CMN_600_GENERATOR_REVISION,\r
643 // Build table function. Use the extended version instead.\r
644 NULL,\r
645 // Free table function. Use the extended version instead.\r
646 NULL,\r
647 // Build Table function\r
648 BuildSsdtCmn600TableEx,\r
649 // Free Resource function\r
650 FreeSsdtCmn600TableResourcesEx\r
651};\r
652\r
653/** Register the Generator with the ACPI Table Factory.\r
654\r
655 @param [in] ImageHandle The handle to the image.\r
656 @param [in] SystemTable Pointer to the System Table.\r
657\r
658 @retval EFI_SUCCESS The Generator is registered.\r
659 @retval EFI_INVALID_PARAMETER A parameter is invalid.\r
660 @retval EFI_ALREADY_STARTED The Generator for the Table ID\r
661 is already registered.\r
662**/\r
663EFI_STATUS\r
664EFIAPI\r
665AcpiSsdtCmn600LibConstructor (\r
666 IN EFI_HANDLE ImageHandle,\r
667 IN EFI_SYSTEM_TABLE * SystemTable\r
668 )\r
669{\r
670 EFI_STATUS Status;\r
671\r
672 Status = RegisterAcpiTableGenerator (&SsdtCmn600Generator);\r
673 DEBUG ((\r
674 DEBUG_INFO,\r
675 "SSDT-CMN-600: Register Generator. Status = %r\n",\r
676 Status\r
677 ));\r
678 ASSERT_EFI_ERROR (Status);\r
679 return Status;\r
680}\r
681\r
682/** Deregister the Generator from the ACPI Table Factory.\r
683\r
684 @param [in] ImageHandle The handle to the image.\r
685 @param [in] SystemTable Pointer to the System Table.\r
686\r
687 @retval EFI_SUCCESS The Generator is deregistered.\r
688 @retval EFI_INVALID_PARAMETER A parameter is invalid.\r
689 @retval EFI_NOT_FOUND The Generator is not registered.\r
690**/\r
691EFI_STATUS\r
692EFIAPI\r
693AcpiSsdtCmn600LibDestructor (\r
694 IN EFI_HANDLE ImageHandle,\r
695 IN EFI_SYSTEM_TABLE * SystemTable\r
696 )\r
697{\r
698 EFI_STATUS Status;\r
699\r
700 Status = DeregisterAcpiTableGenerator (&SsdtCmn600Generator);\r
701 DEBUG ((\r
702 DEBUG_INFO,\r
703 "SSDT-CMN-600: Deregister Generator. Status = %r\n",\r
704 Status\r
705 ));\r
706 ASSERT_EFI_ERROR (Status);\r
707 return Status;\r
708}\r