]>
Commit | Line | Data |
---|---|---|
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 | |
35 | extern 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 | |
48 | GET_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 | |
62 | STATIC\r | |
63 | EFI_STATUS\r | |
64 | EFIAPI\r | |
65 | ValidateCmn600Info (\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 | |
165 | error_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 | |
219 | STATIC\r | |
220 | EFI_STATUS\r | |
221 | EFIAPI\r | |
222 | FixupCmn600Info (\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 | |
387 | error_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 | |
422 | STATIC\r | |
423 | EFI_STATUS\r | |
424 | EFIAPI\r | |
425 | FreeSsdtCmn600TableResourcesEx (\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 | |
499 | STATIC\r | |
500 | EFI_STATUS\r | |
501 | EFIAPI\r | |
502 | BuildSsdtCmn600TableEx (\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 | |
626 | STATIC\r | |
627 | CONST\r | |
628 | ACPI_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 | |
663 | EFI_STATUS\r | |
664 | EFIAPI\r | |
665 | AcpiSsdtCmn600LibConstructor (\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 | |
691 | EFI_STATUS\r | |
692 | EFIAPI\r | |
693 | AcpiSsdtCmn600LibDestructor (\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 |