summaryrefslogtreecommitdiffstats
path: root/DynamicTablesPkg
diff options
context:
space:
mode:
Diffstat (limited to 'DynamicTablesPkg')
-rw-r--r--DynamicTablesPkg/DynamicTables.dsc.inc1
-rw-r--r--DynamicTablesPkg/DynamicTablesPkg.ci.yaml3
-rw-r--r--DynamicTablesPkg/DynamicTablesPkg.dec3
-rw-r--r--DynamicTablesPkg/DynamicTablesPkg.dsc1
-rw-r--r--DynamicTablesPkg/Include/AcpiTableGenerator.h7
-rw-r--r--DynamicTablesPkg/Include/ArmNameSpaceObjects.h9
-rw-r--r--DynamicTablesPkg/Include/Library/SsdtSerialPortFixupLib.h68
-rw-r--r--DynamicTablesPkg/Library/Common/SsdtSerialPortFixupLib/SsdtSerialPortFixupLib.c524
-rw-r--r--DynamicTablesPkg/Library/Common/SsdtSerialPortFixupLib/SsdtSerialPortFixupLib.inf30
-rw-r--r--DynamicTablesPkg/Library/Common/SsdtSerialPortFixupLib/SsdtSerialPortTemplate.asl60
10 files changed, 703 insertions, 3 deletions
diff --git a/DynamicTablesPkg/DynamicTables.dsc.inc b/DynamicTablesPkg/DynamicTables.dsc.inc
index 928529f797..0063fc3c67 100644
--- a/DynamicTablesPkg/DynamicTables.dsc.inc
+++ b/DynamicTablesPkg/DynamicTables.dsc.inc
@@ -14,6 +14,7 @@
[LibraryClasses.common]
AmlLib|DynamicTablesPkg/Library/Common/AmlLib/AmlLib.inf
+ SsdtSerialPortFixupLib|DynamicTablesPkg/Library/Common/SsdtSerialPortFixupLib/SsdtSerialPortFixupLib.inf
TableHelperLib|DynamicTablesPkg/Library/Common/TableHelperLib/TableHelperLib.inf
[Components.common]
diff --git a/DynamicTablesPkg/DynamicTablesPkg.ci.yaml b/DynamicTablesPkg/DynamicTablesPkg.ci.yaml
index 5ee2035732..c0d09e79fd 100644
--- a/DynamicTablesPkg/DynamicTablesPkg.ci.yaml
+++ b/DynamicTablesPkg/DynamicTablesPkg.ci.yaml
@@ -69,6 +69,8 @@
"IgnoreFiles": [], # use gitignore syntax to ignore errors
# in matching files
"ExtendWords": [
+ "ARMHB", # ARMHB000
+ "ARMLTD",
"EISAID",
"CCIDX",
"CCSIDR",
@@ -81,6 +83,7 @@
"MPIDR",
"pytool",
"Roadmap",
+ "ssdtserialporttemplate",
"SMMUV",
"standardised",
"TABLEEX",
diff --git a/DynamicTablesPkg/DynamicTablesPkg.dec b/DynamicTablesPkg/DynamicTablesPkg.dec
index 57e6815fa1..f36a6e8bb7 100644
--- a/DynamicTablesPkg/DynamicTablesPkg.dec
+++ b/DynamicTablesPkg/DynamicTablesPkg.dec
@@ -20,6 +20,9 @@
## @libraryclass Defines a set of APIs for Dynamic AML generation.
AmlLib|Include/Library/AmlLib/AmlLib.h
+ ## @libraryclass Defines a set of methods for fixing up a SSDT Serial Port.
+ SsdtSerialPortFixupLib|Include/Library/SsdtSerialPortFixupLib.h
+
## @libraryclass Defines a set of helper methods.
TableHelperLib|Include/Library/TableHelperLib.h
diff --git a/DynamicTablesPkg/DynamicTablesPkg.dsc b/DynamicTablesPkg/DynamicTablesPkg.dsc
index add6b192ad..0232bda459 100644
--- a/DynamicTablesPkg/DynamicTablesPkg.dsc
+++ b/DynamicTablesPkg/DynamicTablesPkg.dsc
@@ -37,6 +37,7 @@
[Components.common]
DynamicTablesPkg/Library/Common/AmlLib/AmlLib.inf
+ DynamicTablesPkg/Library/Common/SsdtSerialPortFixupLib/SsdtSerialPortFixupLib.inf
DynamicTablesPkg/Library/Common/TableHelperLib/TableHelperLib.inf
[BuildOptions]
diff --git a/DynamicTablesPkg/Include/AcpiTableGenerator.h b/DynamicTablesPkg/Include/AcpiTableGenerator.h
index b55feb4e75..ef5018c312 100644
--- a/DynamicTablesPkg/Include/AcpiTableGenerator.h
+++ b/DynamicTablesPkg/Include/AcpiTableGenerator.h
@@ -1,6 +1,6 @@
/** @file
- Copyright (c) 2017 - 2019, ARM Limited. All rights reserved.
+ Copyright (c) 2017 - 2020, Arm Limited. All rights reserved.<BR>
SPDX-License-Identifier: BSD-2-Clause-Patent
@@ -55,6 +55,10 @@ The Dynamic Tables Framework implements the following ACPI table generators:
the Configuration Manager and builds the PPTT table.
- SRAT : The SRAT generator collates the system resource affinity information
from the Configuration Manager and builds the SRAT table.
+ - SSDT Serial-Port:
+ The SSDT Serial generator collates the Serial port information
+ from the Configuration Manager and patches the SSDT Serial Port
+ template to build the SSDT Serial port table.
*/
/** The ACPI_TABLE_GENERATOR_ID type describes ACPI table generator ID.
@@ -78,6 +82,7 @@ typedef enum StdAcpiTableId {
EStdAcpiTableIdIort, ///< IORT Generator
EStdAcpiTableIdPptt, ///< PPTT Generator
EStdAcpiTableIdSrat, ///< SRAT Generator
+ EStdAcpiTableIdSsdtSerialPort, ///< SSDT Serial-Port Generator
EStdAcpiTableIdMax
} ESTD_ACPI_TABLE_ID;
diff --git a/DynamicTablesPkg/Include/ArmNameSpaceObjects.h b/DynamicTablesPkg/Include/ArmNameSpaceObjects.h
index 57a282d5cb..b2534a6505 100644
--- a/DynamicTablesPkg/Include/ArmNameSpaceObjects.h
+++ b/DynamicTablesPkg/Include/ArmNameSpaceObjects.h
@@ -1,6 +1,6 @@
/** @file
- Copyright (c) 2017 - 2020, ARM Limited. All rights reserved.
+ Copyright (c) 2017 - 2020, Arm Limited. All rights reserved.<BR>
SPDX-License-Identifier: BSD-2-Clause-Patent
@@ -56,6 +56,7 @@ typedef enum ArmObjectID {
EArmObjDeviceHandleAcpi, ///< 32 - Device Handle Acpi
EArmObjDeviceHandlePci, ///< 33 - Device Handle Pci
EArmObjGenericInitiatorAffinityInfo, ///< 34 - Generic Initiator Affinity
+ EArmObjSerialPortInfo, ///< 35 - Generic Serial Port Info
EArmObjMax
} EARM_OBJECT_ID;
@@ -270,7 +271,8 @@ typedef struct CmArmGicItsInfo {
Serial Port information for the Platform.
ID: EArmObjSerialConsolePortInfo or
- EArmObjSerialDebugPortInfo
+ EArmObjSerialDebugPortInfo or
+ EArmObjSerialPortInfo
*/
typedef struct CmArmSerialPortInfo {
/// The physical base address for the serial port
@@ -287,6 +289,9 @@ typedef struct CmArmSerialPortInfo {
/// Serial Port subtype
UINT16 PortSubtype;
+
+ /// The Base address length
+ UINT64 BaseAddressLength;
} CM_ARM_SERIAL_PORT_INFO;
/** A structure that describes the
diff --git a/DynamicTablesPkg/Include/Library/SsdtSerialPortFixupLib.h b/DynamicTablesPkg/Include/Library/SsdtSerialPortFixupLib.h
new file mode 100644
index 0000000000..4605f3f34b
--- /dev/null
+++ b/DynamicTablesPkg/Include/Library/SsdtSerialPortFixupLib.h
@@ -0,0 +1,68 @@
+/** @file
+ Ssdt Serial Port Fixup Library
+
+ Copyright (c) 2020, Arm Limited. All rights reserved.<BR>
+
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+**/
+
+#ifndef SSDT_SERIAL_PORT_LIB_H_
+#define SSDT_SERIAL_PORT_LIB_H_
+
+/** Build a SSDT table describing the input serial port.
+
+ The table created by this function must be freed by FreeSsdtSerialTable.
+
+ @param [in] AcpiTableInfo Pointer to the ACPI table information.
+ @param [in] SerialPortInfo Serial port to describe in the SSDT table.
+ @param [in] Name The Name to give to the Device.
+ Must be a NULL-terminated ASL NameString
+ e.g.: "DEV0", "DV15.DEV0", etc.
+ @param [in] Uid UID for the Serial Port.
+ @param [out] Table If success, pointer to the created SSDT table.
+
+ @retval EFI_SUCCESS Table generated successfully.
+ @retval EFI_INVALID_PARAMETER A parameter is invalid.
+ @retval EFI_NOT_FOUND Could not find information.
+ @retval EFI_OUT_OF_RESOURCES Could not allocate memory.
+**/
+EFI_STATUS
+EFIAPI
+BuildSsdtSerialPortTable (
+ IN CONST CM_STD_OBJ_ACPI_TABLE_INFO * AcpiTableInfo,
+ IN CONST CM_ARM_SERIAL_PORT_INFO * SerialPortInfo,
+ IN CONST CHAR8 * Name,
+ IN CONST UINT64 Uid,
+ OUT EFI_ACPI_DESCRIPTION_HEADER ** Table
+ );
+
+/** Free an SSDT table previously created by
+ the BuildSsdtSerialTable function.
+
+ @param [in] Table Pointer to a SSDT table allocated by
+ the BuildSsdtSerialTable function.
+
+ @retval EFI_SUCCESS Success.
+**/
+EFI_STATUS
+EFIAPI
+FreeSsdtSerialPortTable (
+ IN EFI_ACPI_DESCRIPTION_HEADER * Table
+ );
+
+/** Validate the Serial Port Information.
+
+ @param [in] SerialPortInfoTable Table of CM_ARM_SERIAL_PORT_INFO.
+ @param [in] SerialPortCount Count of SerialPort in the table.
+
+ @retval EFI_SUCCESS Success.
+ @retval EFI_INVALID_PARAMETER Invalid parameter.
+**/
+EFI_STATUS
+EFIAPI
+ValidateSerialPortInfo (
+ IN CONST CM_ARM_SERIAL_PORT_INFO * SerialPortInfoTable,
+ IN UINT32 SerialPortCount
+ );
+
+#endif // SSDT_SERIAL_PORT_LIB_H_
diff --git a/DynamicTablesPkg/Library/Common/SsdtSerialPortFixupLib/SsdtSerialPortFixupLib.c b/DynamicTablesPkg/Library/Common/SsdtSerialPortFixupLib/SsdtSerialPortFixupLib.c
new file mode 100644
index 0000000000..944bfd6eaa
--- /dev/null
+++ b/DynamicTablesPkg/Library/Common/SsdtSerialPortFixupLib/SsdtSerialPortFixupLib.c
@@ -0,0 +1,524 @@
+/** @file
+ SSDT Serial Port Fixup Library.
+
+ Copyright (c) 2019 - 2020, Arm Limited. All rights reserved.<BR>
+
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+ @par Reference(s):
+ - Arm Server Base Boot Requirements (SBBR), s4.2.1.8 "SPCR".
+ - Microsoft Debug Port Table 2 (DBG2) Specification - December 10, 2015.
+**/
+
+#include <IndustryStandard/DebugPort2Table.h>
+#include <Library/AcpiLib.h>
+#include <Library/BaseLib.h>
+#include <Library/BaseMemoryLib.h>
+#include <Library/DebugLib.h>
+#include <Library/MemoryAllocationLib.h>
+#include <Library/UefiBootServicesTableLib.h>
+#include <Protocol/AcpiTable.h>
+
+// Module specific include files.
+#include <AcpiTableGenerator.h>
+#include <ConfigurationManagerObject.h>
+#include <ConfigurationManagerHelper.h>
+#include <Library/AmlLib/AmlLib.h>
+#include <Library/TableHelperLib.h>
+#include <Protocol/ConfigurationManagerProtocol.h>
+
+/** C array containing the compiled AML template.
+ This symbol is defined in the auto generated C file
+ containing the AML bytecode array.
+*/
+extern CHAR8 ssdtserialporttemplate_aml_code[];
+
+/** UART address range length.
+*/
+#define MIN_UART_ADDRESS_LENGTH 0x1000U
+
+/** Validate the Serial Port Information.
+
+ @param [in] SerialPortInfoTable Table of CM_ARM_SERIAL_PORT_INFO.
+ @param [in] SerialPortCount Count of SerialPort in the table.
+
+ @retval EFI_SUCCESS Success.
+ @retval EFI_INVALID_PARAMETER Invalid parameter.
+**/
+EFI_STATUS
+EFIAPI
+ValidateSerialPortInfo (
+ IN CONST CM_ARM_SERIAL_PORT_INFO * SerialPortInfoTable,
+ IN UINT32 SerialPortCount
+ )
+{
+ UINT32 Index;
+ CONST CM_ARM_SERIAL_PORT_INFO * SerialPortInfo;
+
+ if ((SerialPortInfoTable == NULL) ||
+ (SerialPortCount == 0)) {
+ ASSERT (0);
+ return EFI_INVALID_PARAMETER;
+ }
+
+ for (Index = 0; Index < SerialPortCount; Index++) {
+ SerialPortInfo = &SerialPortInfoTable[Index];
+ ASSERT (SerialPortInfo != NULL);
+
+ if ((SerialPortInfo == NULL ) ||
+ (SerialPortInfo->BaseAddress == 0)) {
+ DEBUG ((
+ DEBUG_ERROR,
+ "ERROR: UART port base address is invalid. BaseAddress = 0x%llx\n",
+ SerialPortInfo->BaseAddress
+ ));
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if ((SerialPortInfo->PortSubtype !=
+ EFI_ACPI_DBG2_PORT_SUBTYPE_SERIAL_ARM_PL011_UART) &&
+ (SerialPortInfo->PortSubtype !=
+ EFI_ACPI_DBG2_PORT_SUBTYPE_SERIAL_ARM_SBSA_GENERIC_UART_2X) &&
+ (SerialPortInfo->PortSubtype !=
+ EFI_ACPI_DBG2_PORT_SUBTYPE_SERIAL_ARM_SBSA_GENERIC_UART) &&
+ (SerialPortInfo->PortSubtype !=
+ EFI_ACPI_DBG2_PORT_SUBTYPE_SERIAL_DCC) &&
+ (SerialPortInfo->PortSubtype !=
+ EFI_ACPI_DBG2_PORT_SUBTYPE_SERIAL_FULL_16550)) {
+ DEBUG ((
+ DEBUG_ERROR,
+ "ERROR: UART port subtype is invalid."
+ " UART Base = 0x%llx, PortSubtype = 0x%x\n",
+ SerialPortInfo->BaseAddress,
+ SerialPortInfo->PortSubtype
+ ));
+ return EFI_INVALID_PARAMETER;
+ }
+
+ DEBUG ((DEBUG_INFO, "UART Configuration:\n"));
+ DEBUG ((
+ DEBUG_INFO,
+ " UART Base = 0x%llx\n", SerialPortInfo->BaseAddress
+ ));
+ DEBUG ((
+ DEBUG_INFO,
+ " Length = 0x%llx\n",
+ SerialPortInfo->BaseAddressLength
+ ));
+ DEBUG ((DEBUG_INFO, " Clock = %lu\n", SerialPortInfo->Clock));
+ DEBUG ((DEBUG_INFO, " BaudRate = %llu\n", SerialPortInfo->BaudRate));
+ DEBUG ((DEBUG_INFO, " Interrupt = %lu\n", SerialPortInfo->Interrupt));
+ } // for
+
+ return EFI_SUCCESS;
+}
+
+/** Fixup the Serial Port Ids (_UID, _HID, _CID).
+
+ @param [in] RootNodeHandle Pointer to the root of an AML tree.
+ @param [in] Uid UID for the Serial Port.
+ @param [in] SerialPortInfo Pointer to a Serial Port Information
+ structure.
+ Get the Serial Port Information from there.
+
+ @retval EFI_SUCCESS The function completed successfully.
+ @retval EFI_INVALID_PARAMETER Invalid parameter.
+ @retval EFI_NOT_FOUND Could not find information.
+ @retval EFI_OUT_OF_RESOURCES Out of resources.
+**/
+STATIC
+EFI_STATUS
+EFIAPI
+FixupIds (
+ IN OUT AML_ROOT_NODE_HANDLE RootNodeHandle,
+ IN CONST UINT64 Uid,
+ IN CONST CM_ARM_SERIAL_PORT_INFO * SerialPortInfo
+ )
+{
+ EFI_STATUS Status;
+ AML_OBJECT_NODE_HANDLE NameOpIdNode;
+ CONST CHAR8 * HidString;
+ CONST CHAR8 * CidString;
+
+ // Get the _CID and _HID value to write.
+ switch (SerialPortInfo->PortSubtype) {
+ case EFI_ACPI_DBG2_PORT_SUBTYPE_SERIAL_FULL_16550:
+ {
+ HidString = "PNP0501";
+ CidString = "PNP0500";
+ break;
+ }
+ case EFI_ACPI_DBG2_PORT_SUBTYPE_SERIAL_ARM_PL011_UART:
+ {
+ HidString = "ARMH0011";
+ CidString = "ARMHB000";
+ break;
+ }
+ case EFI_ACPI_DBG2_PORT_SUBTYPE_SERIAL_ARM_SBSA_GENERIC_UART:
+ case EFI_ACPI_DBG2_PORT_SUBTYPE_SERIAL_ARM_SBSA_GENERIC_UART_2X:
+ {
+ HidString = "ARMH0011";
+ CidString = "";
+ break;
+ }
+ default:
+ {
+ return EFI_INVALID_PARAMETER;
+ }
+ } // switch
+
+ // Get the _UID NameOp object defined by the "Name ()" statement,
+ // and update its value.
+ Status = AmlFindNode (
+ RootNodeHandle,
+ "\\_SB_.COM0._UID",
+ &NameOpIdNode
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ Status = AmlNameOpUpdateInteger (NameOpIdNode, (UINT64)Uid);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ // Get the _HID NameOp object defined by the "Name ()" statement,
+ // and update its value.
+ Status = AmlFindNode (
+ RootNodeHandle,
+ "\\_SB_.COM0._HID",
+ &NameOpIdNode
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ Status = AmlNameOpUpdateString (NameOpIdNode, HidString);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ // Get the _CID NameOp object defined by the "Name ()" statement,
+ // and update its value.
+ Status = AmlFindNode (
+ RootNodeHandle,
+ "\\_SB_.COM0._CID",
+ &NameOpIdNode
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ // If we have a CID then update a _CID node else delete the node.
+ if (AsciiStrLen (CidString) != 0) {
+ Status = AmlNameOpUpdateString (NameOpIdNode, CidString);
+ } else {
+ // First detach the node from the tree.
+ Status = AmlDetachNode (NameOpIdNode);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ // Delete the detached node.
+ Status = AmlDeleteTree (NameOpIdNode);
+ }
+
+ return Status;
+}
+
+/** Fixup the Serial Port _CRS values (BaseAddress, ...).
+
+ @param [in] RootNodeHandle Pointer to the root of an AML tree.
+ @param [in] SerialPortInfo Pointer to a Serial Port Information
+ structure.
+ Get the Serial Port Information from there.
+
+ @retval EFI_SUCCESS The function completed successfully.
+ @retval EFI_INVALID_PARAMETER Invalid parameter.
+ @retval EFI_NOT_FOUND Could not find information.
+ @retval EFI_OUT_OF_RESOURCES Out of resources.
+**/
+STATIC
+EFI_STATUS
+EFIAPI
+FixupCrs (
+ IN OUT AML_ROOT_NODE_HANDLE RootNodeHandle,
+ IN CONST CM_ARM_SERIAL_PORT_INFO * SerialPortInfo
+ )
+{
+ EFI_STATUS Status;
+ AML_OBJECT_NODE_HANDLE NameOpCrsNode;
+ AML_DATA_NODE_HANDLE QWordRdNode;
+ AML_DATA_NODE_HANDLE InterruptRdNode;
+
+ // Get the "_CRS" object defined by the "Name ()" statement.
+ Status = AmlFindNode (
+ RootNodeHandle,
+ "\\_SB_.COM0._CRS",
+ &NameOpCrsNode
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ // Get the first Rd node in the "_CRS" object.
+ Status = AmlNameOpCrsGetFirstRdNode (NameOpCrsNode, &QWordRdNode);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ if (QWordRdNode == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ // Update the Serial Port base address and length.
+ Status = AmlUpdateRdQWord (
+ QWordRdNode,
+ SerialPortInfo->BaseAddress,
+ ((SerialPortInfo->BaseAddressLength < MIN_UART_ADDRESS_LENGTH) ?
+ MIN_UART_ADDRESS_LENGTH: SerialPortInfo->BaseAddressLength)
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ // Get the Interrupt node.
+ // It is the second Resource Data element in the NameOpCrsNode's
+ // variable list of arguments.
+ Status = AmlNameOpCrsGetNextRdNode (QWordRdNode, &InterruptRdNode);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ if (InterruptRdNode == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ // Update the interrupt number.
+ return AmlUpdateRdInterrupt (InterruptRdNode, SerialPortInfo->Interrupt);
+}
+
+/** Fixup the Serial Port device name.
+
+ @param [in] RootNodeHandle Pointer to the root of an AML tree.
+ @param [in] SerialPortInfo Pointer to a Serial Port Information
+ structure.
+ Get the Serial Port Information from there.
+ @param [in] Name The Name to give to the Device.
+ Must be a NULL-terminated ASL NameString
+ e.g.: "DEV0", "DV15.DEV0", etc.
+
+ @retval EFI_SUCCESS The function completed successfully.
+ @retval EFI_INVALID_PARAMETER Invalid parameter.
+ @retval EFI_NOT_FOUND Could not find information.
+ @retval EFI_OUT_OF_RESOURCES Out of resources.
+**/
+STATIC
+EFI_STATUS
+EFIAPI
+FixupName (
+ IN OUT AML_ROOT_NODE_HANDLE RootNodeHandle,
+ IN CONST CM_ARM_SERIAL_PORT_INFO * SerialPortInfo,
+ IN CONST CHAR8 * Name
+ )
+{
+ EFI_STATUS Status;
+ AML_OBJECT_NODE_HANDLE DeviceNode;
+
+ // Get the COM0 variable defined by the "Device ()" statement.
+ Status = AmlFindNode (RootNodeHandle, "\\_SB_.COM0", &DeviceNode);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ // Update the Device's name.
+ return AmlDeviceOpUpdateName (DeviceNode, (CHAR8*)Name);
+}
+
+/** Fixup the Serial Port Information in the AML tree.
+
+ For each template value:
+ - find the node to update;
+ - update the value.
+
+ @param [in] RootNodeHandle Pointer to the root of the AML tree.
+ @param [in] SerialPortInfo Pointer to a Serial Port Information
+ structure.
+ Get the Serial Port Information from there.
+ @param [in] Name The Name to give to the Device.
+ Must be a NULL-terminated ASL NameString
+ e.g.: "DEV0", "DV15.DEV0", etc.
+ @param [in] Uid UID for the Serial Port.
+ @param [out] Table If success, contains the serialized
+ SSDT table.
+
+ @retval EFI_SUCCESS The function completed successfully.
+ @retval EFI_INVALID_PARAMETER Invalid parameter.
+ @retval EFI_NOT_FOUND Could not find information.
+ @retval EFI_OUT_OF_RESOURCES Out of resources.
+**/
+STATIC
+EFI_STATUS
+EFIAPI
+FixupSerialPortInfo (
+ IN OUT AML_ROOT_NODE_HANDLE RootNodeHandle,
+ IN CONST CM_ARM_SERIAL_PORT_INFO * SerialPortInfo,
+ IN CONST CHAR8 * Name,
+ IN CONST UINT64 Uid,
+ OUT EFI_ACPI_DESCRIPTION_HEADER ** Table
+ )
+{
+ EFI_STATUS Status;
+
+ ASSERT (RootNodeHandle != NULL);
+ ASSERT (SerialPortInfo != NULL);
+ ASSERT (Name != NULL);
+ ASSERT (Table != NULL);
+
+ // Fixup the _UID, _HID and _CID values.
+ Status = FixupIds (RootNodeHandle, Uid, SerialPortInfo);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ // Fixup the _CRS values.
+ Status = FixupCrs (RootNodeHandle, SerialPortInfo);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ // Fixup the serial-port name.
+ // This MUST be done at the end, otherwise AML paths won't be valid anymore.
+ return FixupName (RootNodeHandle, SerialPortInfo, Name);
+}
+
+/** Free an SSDT table previously created by
+ the BuildSsdtSerialTable function.
+
+ @param [in] Table Pointer to a SSDT table allocated by
+ the BuildSsdtSerialTable function.
+
+ @retval EFI_SUCCESS Success.
+**/
+EFI_STATUS
+EFIAPI
+FreeSsdtSerialPortTable (
+ IN EFI_ACPI_DESCRIPTION_HEADER * Table
+ )
+{
+ ASSERT (Table != NULL);
+ FreePool (Table);
+ return EFI_SUCCESS;
+}
+
+/** Build a SSDT table describing the input serial port.
+
+ The table created by this function must be freed by FreeSsdtSerialTable.
+
+ @param [in] AcpiTableInfo Pointer to the ACPI table information.
+ @param [in] SerialPortInfo Serial port to describe in the SSDT table.
+ @param [in] Name The Name to give to the Device.
+ Must be a NULL-terminated ASL NameString
+ e.g.: "DEV0", "DV15.DEV0", etc.
+ @param [in] Uid UID for the Serial Port.
+ @param [out] Table If success, pointer to the created SSDT table.
+
+ @retval EFI_SUCCESS Table generated successfully.
+ @retval EFI_INVALID_PARAMETER A parameter is invalid.
+ @retval EFI_NOT_FOUND Could not find information.
+ @retval EFI_OUT_OF_RESOURCES Could not allocate memory.
+**/
+EFI_STATUS
+EFIAPI
+BuildSsdtSerialPortTable (
+ IN CONST CM_STD_OBJ_ACPI_TABLE_INFO * AcpiTableInfo,
+ IN CONST CM_ARM_SERIAL_PORT_INFO * SerialPortInfo,
+ IN CONST CHAR8 * Name,
+ IN CONST UINT64 Uid,
+ OUT EFI_ACPI_DESCRIPTION_HEADER ** Table
+ )
+{
+ EFI_STATUS Status;
+ EFI_STATUS Status1;
+ AML_ROOT_NODE_HANDLE RootNodeHandle;
+
+ ASSERT (AcpiTableInfo != NULL);
+ ASSERT (SerialPortInfo != NULL);
+ ASSERT (Name != NULL);
+ ASSERT (Table != NULL);
+
+ // Validate the Serial Port Info.
+ Status = ValidateSerialPortInfo (SerialPortInfo, 1);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ // Parse the SSDT Serial Port Template.
+ Status = AmlParseDefinitionBlock (
+ (EFI_ACPI_DESCRIPTION_HEADER*)ssdtserialporttemplate_aml_code,
+ &RootNodeHandle
+ );
+ if (EFI_ERROR (Status)) {
+ DEBUG ((
+ DEBUG_ERROR,
+ "ERROR: SSDT-SERIAL-PORT-FIXUP:"
+ " Failed to parse SSDT Serial Port Template. Status = %r\n",
+ Status
+ ));
+ return Status;
+ }
+
+ // Fixup the template values.
+ Status = FixupSerialPortInfo (
+ RootNodeHandle,
+ SerialPortInfo,
+ Name,
+ Uid,
+ Table
+ );
+ if (EFI_ERROR (Status)) {
+ DEBUG ((
+ DEBUG_ERROR,
+ "ERROR: SSDT-SERIAL-PORT-FIXUP: Failed to fixup SSDT Serial Port Table."
+ " Status = %r\n",
+ Status
+ ));
+ goto exit_handler;
+ }
+
+ // Serialize the tree.
+ Status = AmlSerializeDefinitionBlock (
+ RootNodeHandle,
+ Table
+ );
+ if (EFI_ERROR (Status)) {
+ DEBUG ((
+ DEBUG_ERROR,
+ "ERROR: SSDT-SERIAL-PORT-FIXUP: Failed to Serialize SSDT Table Data."
+ " Status = %r\n",
+ Status
+ ));
+ }
+
+exit_handler:
+ // Cleanup
+ if (RootNodeHandle != NULL) {
+ Status1 = AmlDeleteTree (RootNodeHandle);
+ if (EFI_ERROR (Status1)) {
+ DEBUG ((
+ DEBUG_ERROR,
+ "ERROR: SSDT-SERIAL-PORT-FIXUP: Failed to cleanup AML tree."
+ " Status = %r\n",
+ Status1
+ ));
+ // If Status was success but we failed to delete the AML Tree
+ // return Status1 else return the original error code, i.e. Status.
+ if (!EFI_ERROR (Status)) {
+ return Status1;
+ }
+ }
+ }
+
+ return Status;
+}
diff --git a/DynamicTablesPkg/Library/Common/SsdtSerialPortFixupLib/SsdtSerialPortFixupLib.inf b/DynamicTablesPkg/Library/Common/SsdtSerialPortFixupLib/SsdtSerialPortFixupLib.inf
new file mode 100644
index 0000000000..af3d404393
--- /dev/null
+++ b/DynamicTablesPkg/Library/Common/SsdtSerialPortFixupLib/SsdtSerialPortFixupLib.inf
@@ -0,0 +1,30 @@
+## @file
+# SSDT Serial Port fixup Library
+#
+# Copyright (c) 2020, Arm Limited. All rights reserved.<BR>
+#
+# SPDX-License-Identifier: BSD-2-Clause-Patent
+##
+
+[Defines]
+ INF_VERSION = 0x0001001B
+ BASE_NAME = DynamicSsdtSerialPortFixupLib
+ FILE_GUID = AC5978CC-5B62-4466-AD04-23644C2C38C2
+ VERSION_STRING = 1.0
+ MODULE_TYPE = DXE_DRIVER
+ LIBRARY_CLASS = SsdtSerialPortFixupLib
+
+[Sources]
+ SsdtSerialPortFixupLib.c
+ SsdtSerialPortTemplate.asl
+
+[Packages]
+ MdePkg/MdePkg.dec
+ MdeModulePkg/MdeModulePkg.dec
+ EmbeddedPkg/EmbeddedPkg.dec
+ DynamicTablesPkg/DynamicTablesPkg.dec
+
+[LibraryClasses]
+ AmlLib
+ BaseLib
+
diff --git a/DynamicTablesPkg/Library/Common/SsdtSerialPortFixupLib/SsdtSerialPortTemplate.asl b/DynamicTablesPkg/Library/Common/SsdtSerialPortFixupLib/SsdtSerialPortTemplate.asl
new file mode 100644
index 0000000000..fcae2160ac
--- /dev/null
+++ b/DynamicTablesPkg/Library/Common/SsdtSerialPortFixupLib/SsdtSerialPortTemplate.asl
@@ -0,0 +1,60 @@
+/** @file
+ SSDT Serial Template
+
+ Copyright (c) 2019 - 2020, Arm Limited. All rights reserved.<BR>
+
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+ @par Reference(s):
+ - Arm Server Base Boot Requirements (SBBR), s4.2.1.8 "SPCR".
+
+ @par Glossary:
+ - {template} - Data fixed up using AML Fixup APIs.
+**/
+
+DefinitionBlock ("SsdtSerialPortTemplate.aml", "SSDT", 2, "ARMLTD", "SERIAL", 1) {
+ Scope (_SB) {
+ // UART PL011
+ Device (COM0) { // {template}
+ Name (_UID, 0x0) // {template}
+ Name (_HID, "HID0000") // {template}
+ Name (_CID, "CID0000") // {template}
+
+ Method(_STA) {
+ Return(0xF)
+ }
+
+ Name (_CRS, ResourceTemplate() {
+ QWordMemory (
+ , // ResourceUsage
+ , // Decode
+ , // IsMinFixed
+ , // IsMaxFixed
+ , // Cacheable
+ ReadWrite, // ReadAndWrite
+ 0x0, // AddressGranularity
+ 0xA0000000, // AddressMinimum // {template}
+ 0xAFFFFFFF, // AddressMaximum // {template}
+ 0, // AddressTranslation
+ 0x10000000, // RangeLength // {template}
+ , // ResourceSourceIndex
+ , // ResourceSource
+ , // DescriptorName
+ , // MemoryRangeType
+ // TranslationType
+ ) // QWordMemory
+ Interrupt (
+ ResourceConsumer, // ResourceUsage
+ Level, // EdgeLevel
+ ActiveHigh, // ActiveLevel
+ Exclusive, // Shared
+ , // ResourceSourceIndex
+ , // ResourceSource
+ // DescriptorName
+ ) {
+ 0xA5 // {template}
+ } // Interrupt
+ }) // Name
+ } // Device
+ } // Scope (_SB)
+}