The purpose of this document is to describe changes commonly made when adding a new Ampere Altra based platform.
Users of this document should have prior firmware development experience with EDKII, including knowledge of UEFI specification.
This document also assumes your new platform meets Ampere(R) Altra(R) Interface Firmware Requirements and is working with the Ampere system firmware and Trusted Firmware-A (TF-A).
The following diagram is the hierarchical structure of the silicon and platform directory. It is designed for easy portability and cross-platform reuse between Ampere Altra based platforms.
flowchart TD
edk2-platforms --> Silicon/Ampere
edk2-platforms --> Platform/Ampere
Silicon/Ampere --> AmpereSiliconPkg
Silicon/Ampere --> AmpereAltraPkg
Platform/Ampere --> JadePkg
All the packages are currently located under Silicon/Ampere and Platform/Ampere directories.
The following table describes the intention of the above package organization:
Directory Name | Description |
---|---|
AmpereSiliconPkg | Ampere silicon common code that can be shared for multiple silicon. |
AmpereAltraPkg | Ampere Altra specific code. |
JadePkg | Ampere Mt. Jade Platform code. Any new platform/board should be based on this package. |
This section describes the common process of adding a new platform based on the Mt. Jade reference platform. First, construct a minimal EDK2 that can boot to UEFI Shell. Then, enable features one-by-one such as PCIe, ACPI, SMBIOS, etc.
- Create a vendor directory and a board directory with the pattern:
edk2-platforms/Platform/<Your Company Name>/<New Board>Pkg
. For the sake of simplicity, the new platform will be underPlatform/Ampere/NewBoardPkg
. - Copy
Platform/Ampere/JadePkg
toPlatform/Ampere/NewBoardPkg
. - Rename the file name under the
NewBoardPkg
like BoardSetting.cfg and DSC/FDF file to match the platform name.
Replace correspondingly the Jade
/JADE
with NewBoard
/NEWBOARD
throughout the files.
The Board Setting is a collection of board and hardware configurations for an Altra-based ARM64 platform.
Modify it appropriately for the new platform configuration.
Please refer to the Ampere Altra Interface Firmware Requirements at the Table 4 for detailed descriptions of each Board Setting fields.
Below modules are generic and can be shared among Ampere Altra-based platforms.
Module Name | Description |
---|---|
Platform/Ampere/JadePkg/Drivers/AcpiPlatformDxe | Patch DSDT and install MCFG, IORT tables |
Platform/Ampere/JadePkg/Drivers/PciPlatformDxe | Install PCI platform protocol for post-initialization phase |
Silicon/Ampere/AmpereAltraPkg/Drivers/PcieInitPei | Install Root Complex Shared HOB consumed by other modules |
Silicon/Ampere/AmpereAltraPkg/Library/Ac01PcieLib | Core library including basic function to initialize the PCIe Root Complex |
Silicon/Ampere/AmpereAltraBinPkg/Library/PciePhyLib | Provide functions to initialize the PCIe PHY |
Silicon/Ampere/AmpereAltraPkg/Library/PciHostbridgeLib | Provide functions to build and free the array of Root Bridge resource |
Silicon/Ampere/AmpereAltraPkg/Library/PciSegmentLib | Provide functions to access the PCIe Configuration space |
The difference between platforms could be the mechanism to control the PERST line for each PCIe controller and the segment number. Platform code must modify the functions below in the Platform/Ampere/JadePkg/Library/BoardPcieLib/BoardPcieLib.c to comply with specific platform hardware.
This BoardPcieAssertPesrt()
function controls the toggling of PERST to release reset to endpoint card.
The Mt. Jade platform uses a combination of GPIO pins to assert PERST to endpoint card.
BoardPcieAssertPerst
/**
Assert PERST of the PCIe controller
@param[in] RootComplex Root Complex instance.
@param[in] PcieIndex PCIe controller index of input Root Complex.
@param[in] IsPullToHigh Target status for the PERST.
@retval RETURN_SUCCESS The operation is successful.
@retval Others An error occurred.
**/
RETURN_STATUS
EFIAPI
BoardPcieAssertPerst (
IN AC01_ROOT_COMPLEX *RootComplex,
IN UINT8 PcieIndex,
IN BOOLEAN IsPullToHigh
);
This BoardPcieGetSegmentNumber()
defines the segment number mapping of PCIe root complexes.
See the content in the inline function for more information about PCIe segment mapping in Ampere Mt. Jade platform.
BoardPcieGetSegmentNumber
/**
Override the segment number for a root complex with a board specific number.
@param[in] RootComplex Root Complex instance with properties.
@retval Segment number corresponding to the input root complex.
Default segment number is 0x0F.
**/
UINT16
BoardPcieGetSegmentNumber (
IN AC01_ROOT_COMPLEX *RootComplex
);
Note: Although the PCIe segment number mapping could be changed but it is not recommended
unless the custom board has to use a different mapping. If using different mapping,
along with the change in BoardPcieGetSegmentNumber()
, the PCIe segment number must be
also updated in ACPI DSDT and MCFG tables.
Silicon/Ampere/AmpereAltraPkg/Library/PcieHotPlugLib
is the base library that
supports the function calls to start PCIe Hot-Plug service including the SPCI callings
to ATF to set hot-plug port map, and GPIO or I2C for PCIe reset. There are two functions
in this library that a custom board can use to change the hot-plug configuration
if it is different from Mt. Jade platform: PcieHotPlugSetPortMap()
and
PcieHotplugSetGpioMap()
. By default, the configuration of Ampere Mt. Jade 2U platform
will be set. In case the new board uses a different configuration, user can override
the default PCDs used by these two functions with the custom configuration in NewBoard.dsc
.
PcieHotplugSetPortMap()
Function PcieHotplugSetPortMap()
passes hot-plug configuration to Trusted Firmware-A (TF-A)
to update/customize port map entries such as I2C address, RCA port, RCA sub-port, etc.
It uses SPCI PORTMAP_SET_CMD to send that information to ATF.
Refer to the document titled Altra ATF Interface Specification for more details on this function.
A custom platform that does not use the same Hot-Plug PortMap configuration with Ampere Mt. Jade 2U platform must define the corresponding PCD below.
#
# Flag to indicate option of using default or specific platform Port Map table
# Set TRUE: if using the default setting in Ampere Mt. Jade 2U platform.
# Set FALSE: if using a custom PCIe Hot-Plug Port Map settings.
#
gAmpereTokenSpaceGuid.PcdPcieHotPlugPortMapTable.UseDefaultConfig|TRUE
#
# Setting Portmap table
#
# * Elements of array:
# - 0: Index of Portmap entry in Portmap table structure (Vport).
# - 1: Socket number (Socket).
# - 2: Root complex port for each Portmap entry (RcaPort).
# - 3: Root complex sub-port for each Portmap entry (RcaSubPort).
# - 4: Select output port of IO expander (PinPort).
# - 5: I2C address of IO expander that CPLD backplane simulates (I2cAddress).
# - 6: Address of I2C switch between CPU and CPLD backplane (MuxAddress).
# - 7: Channel of I2C switch (MuxChannel).
# - 8: It is set from PcieHotPlugSetGpioMap () function to select GPIO[16:21] (PcdPcieHotPlugGpioResetMap) or I2C for PCIe reset purpose.
# - 9: Segment of root complex (Segment).
# - 10: SSD slot index on the front panel of backplane (DriveIndex).
#
# * Caution:
# - The last array ({ 0xFF, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xFF }) require if no fully structured used.
# - Size of Portmap table: PortMap[MAX_PORTMAP_ENTRY][sizeof(PCIE_HOTPLUG_PORTMAP_ENTRY)] <=> PortMap[96][11].
# * Example: Bellow configuration is an example for Portmap table of Mt. Jade 2U platform.
#
gAmpereTokenSpaceGuid.PcdPcieHotPlugPortMapTable.PortMap[0]|{ 0, 0, 2, 0, 0, 0x00, 0x00, 0x0, 0, 1, 0xFF } # S0 RCA2.0
gAmpereTokenSpaceGuid.PcdPcieHotPlugPortMapTable.PortMap[1]|{ 1, 0, 3, 0, 1, 0x00, 0x00, 0x0, 0, 0, 0xFF } # S0 RCA3.0
gAmpereTokenSpaceGuid.PcdPcieHotPlugPortMapTable.PortMap[2]|{ 2, 0, 4, 0, 2, 0x27, 0x70, 0x1, 0, 2, 6 } # S0 RCB0.0 - SSD6
gAmpereTokenSpaceGuid.PcdPcieHotPlugPortMapTable.PortMap[3]|{ 3, 0, 4, 2, 3, 0x27, 0x70, 0x1, 0, 2, 7 } # S0 RCB0.2 - SSD7
gAmpereTokenSpaceGuid.PcdPcieHotPlugPortMapTable.PortMap[4]|{ 4, 0, 4, 4, 0, 0x25, 0x70, 0x1, 0, 2, 2 } # S0 RCB0.4 - SSD2
gAmpereTokenSpaceGuid.PcdPcieHotPlugPortMapTable.PortMap[5]|{ 5, 0, 4, 6, 1, 0x25, 0x70, 0x1, 0, 2, 3 } # S0 RCB0.6 - SSD3
gAmpereTokenSpaceGuid.PcdPcieHotPlugPortMapTable.PortMap[6]|{ 6, 0, 5, 0, 0, 0x24, 0x70, 0x1, 0, 3, 0 } # S0 RCB1.0 - SSD0
gAmpereTokenSpaceGuid.PcdPcieHotPlugPortMapTable.PortMap[7]|{ 7, 0, 5, 2, 1, 0x24, 0x70, 0x1, 0, 3, 1 } # S0 RCB1.2 - SSD1
gAmpereTokenSpaceGuid.PcdPcieHotPlugPortMapTable.PortMap[8]|{ 8, 0, 5, 4, 2, 0x26, 0x70, 0x1, 0, 3, 4 } # S0 RCB1.4 - SSD4
gAmpereTokenSpaceGuid.PcdPcieHotPlugPortMapTable.PortMap[9]|{ 9, 0, 5, 6, 3, 0x26, 0x70, 0x1, 0, 3, 5 } # S0 RCB1.6 - SSD5
gAmpereTokenSpaceGuid.PcdPcieHotPlugPortMapTable.PortMap[10]|{ 10, 0, 6, 0, 2, 0x00, 0x00, 0x0, 0, 4, 0xFF } # S0 RCB2.0
gAmpereTokenSpaceGuid.PcdPcieHotPlugPortMapTable.PortMap[11]|{ 11, 0, 6, 2, 3, 0x00, 0x00, 0x0, 0, 4, 0xFF } # S0 RCB2.2
gAmpereTokenSpaceGuid.PcdPcieHotPlugPortMapTable.PortMap[12]|{ 12, 0, 6, 4, 0, 0x00, 0x00, 0x0, 0, 4, 0xFF } # S0 RCB2.4
gAmpereTokenSpaceGuid.PcdPcieHotPlugPortMapTable.PortMap[13]|{ 13, 0, 7, 0, 1, 0x00, 0x00, 0x0, 0, 5, 0xFF } # S0 RCB3.0
gAmpereTokenSpaceGuid.PcdPcieHotPlugPortMapTable.PortMap[14]|{ 14, 0, 7, 4, 2, 0x00, 0x00, 0x0, 0, 5, 0xFF } # S0 RCB3.4
gAmpereTokenSpaceGuid.PcdPcieHotPlugPortMapTable.PortMap[15]|{ 15, 0, 7, 6, 3, 0x00, 0x00, 0x0, 0, 5, 0xFF } # S0 RCB3.6
gAmpereTokenSpaceGuid.PcdPcieHotPlugPortMapTable.PortMap[16]|{ 16, 1, 2, 0, 0, 0x26, 0x70, 0x2, 0, 6, 20 } # S1 RCA2.0 - SSD20
gAmpereTokenSpaceGuid.PcdPcieHotPlugPortMapTable.PortMap[17]|{ 17, 1, 2, 1, 1, 0x26, 0x70, 0x2, 0, 6, 21 } # S1 RCA2.1 - SSD21
gAmpereTokenSpaceGuid.PcdPcieHotPlugPortMapTable.PortMap[18]|{ 18, 1, 2, 2, 2, 0x27, 0x70, 0x2, 0, 6, 22 } # S1 RCA2.2 - SSD22
gAmpereTokenSpaceGuid.PcdPcieHotPlugPortMapTable.PortMap[19]|{ 19, 1, 2, 3, 3, 0x27, 0x70, 0x2, 0, 6, 23 } # S1 RCA2.3 - SSD23
gAmpereTokenSpaceGuid.PcdPcieHotPlugPortMapTable.PortMap[20]|{ 20, 1, 3, 0, 0, 0x00, 0x00, 0x0, 0, 7, 0xFF } # S1 RCA3.0
gAmpereTokenSpaceGuid.PcdPcieHotPlugPortMapTable.PortMap[21]|{ 21, 1, 3, 2, 1, 0x00, 0x00, 0x0, 0, 7, 0xFF } # S1 RCA3.2
gAmpereTokenSpaceGuid.PcdPcieHotPlugPortMapTable.PortMap[22]|{ 22, 1, 4, 0, 0, 0x00, 0x00, 0x0, 0, 8, 0xFF } # S1 RCB0.0
gAmpereTokenSpaceGuid.PcdPcieHotPlugPortMapTable.PortMap[23]|{ 23, 1, 4, 4, 2, 0x25, 0x70, 0x2, 0, 8, 18 } # S1 RCB0.4 - SSD18
gAmpereTokenSpaceGuid.PcdPcieHotPlugPortMapTable.PortMap[24]|{ 24, 1, 4, 6, 3, 0x25, 0x70, 0x2, 0, 8, 19 } # S1 RCB0.6 - SSD19
gAmpereTokenSpaceGuid.PcdPcieHotPlugPortMapTable.PortMap[25]|{ 25, 1, 5, 0, 0, 0x24, 0x70, 0x2, 0, 9, 16 } # S1 RCB1.0 - SSD16
gAmpereTokenSpaceGuid.PcdPcieHotPlugPortMapTable.PortMap[26]|{ 26, 1, 5, 2, 1, 0x24, 0x70, 0x2, 0, 9, 17 } # S1 RCB1.2 - SSD17
gAmpereTokenSpaceGuid.PcdPcieHotPlugPortMapTable.PortMap[27]|{ 27, 1, 5, 4, 2, 0x00, 0x00, 0x0, 0, 9, 0xFF } # S1 RCB1.4
gAmpereTokenSpaceGuid.PcdPcieHotPlugPortMapTable.PortMap[28]|{ 28, 1, 6, 0, 3, 0x25, 0x70, 0x4, 0, 10, 11 } # S1 RCB2.0 - SSD11
gAmpereTokenSpaceGuid.PcdPcieHotPlugPortMapTable.PortMap[29]|{ 29, 1, 6, 2, 2, 0x25, 0x70, 0x4, 0, 10, 10 } # S1 RCB2.2 - SSD10
gAmpereTokenSpaceGuid.PcdPcieHotPlugPortMapTable.PortMap[30]|{ 30, 1, 6, 4, 1, 0x27, 0x70, 0x4, 0, 10, 15 } # S1 RCB2.4 - SSD15
gAmpereTokenSpaceGuid.PcdPcieHotPlugPortMapTable.PortMap[31]|{ 31, 1, 6, 6, 0, 0x27, 0x70, 0x4, 0, 10, 14 } # S1 RCB2.6 - SSD14
gAmpereTokenSpaceGuid.PcdPcieHotPlugPortMapTable.PortMap[32]|{ 32, 1, 7, 0, 3, 0x26, 0x70, 0x4, 0, 11, 13 } # S1 RCB3.0 - SSD13
gAmpereTokenSpaceGuid.PcdPcieHotPlugPortMapTable.PortMap[33]|{ 33, 1, 7, 2, 2, 0x26, 0x70, 0x4, 0, 11, 12 } # S1 RCB3.2 - SSD12
gAmpereTokenSpaceGuid.PcdPcieHotPlugPortMapTable.PortMap[34]|{ 34, 1, 7, 4, 1, 0x24, 0x70, 0x4, 0, 11, 9 } # S1 RCB3.4 - SSD9
gAmpereTokenSpaceGuid.PcdPcieHotPlugPortMapTable.PortMap[35]|{ 35, 1, 7, 6, 0, 0x24, 0x70, 0x4, 0, 11, 8 } # S1 RCB3.6 - SSD8
gAmpereTokenSpaceGuid.PcdPcieHotPlugPortMapTable.PortMap[36]|{ 0xFF, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xFF } # Require if no fully structure used
PcieHotplugSetGpioMap()
Function PcieHotplugSetGpioMap()
is used to limit the number of GPIO[16:21] pins or
use I2C instead of GPIO for PCIe reset. It uses SPCI GPIOMAP_CMD to send information to ATF.
Ampere EDK2 defines gPcieHotPlugGpioResetMap
PCD to allow user to define a custom GPIO Map.
In NewBoard.dsc
, user should set the new PCD indicating the GPIO Map for PCIe Hot-Plug.
Below is the GPIO Reset Map PCD definition for Ampere Mt. Jade platform.
gAmpereTokenSpaceGuid.PcdPcieHotPlugGpioResetMap|0x3F
The ACPI tables are split into two main parts: common ACPI tables and platform specific ACPI tables. The common tables are under AmpereAltraPkg so that they can be reused by different platforms.
In order to modify the platform specific tables under Platform/Ampere/NewBoardPkg/AcpiTables
,
update correspondingly with the following points:
- DSDT/GED1 Device (Shutdown Button)
- The interrupt number, which is currently set to 327.
- DSDT/I2C4 Device (IPMI SSIF)
- The values of the SSCN (Standard Mode) and FMCN (Fast Mode) based on the new platform's frequency calibration.
- The BMC slave address in the I2cSerialBusV2 () function, which is currently set to 0x0010.
- DSDT/UART Devices
- There are three UART devices that can be used by EDK2:
- UART0 for ACPI SPCR table (CPU main console)
- UART2 for ACPI DBG2 table
- UART3: non-use
- Add or remove UART devices based on the platform configuration.
- There are three UART devices that can be used by EDK2:
- DSDT/MHPP for Memory Hot-Plug Port Mapping
- This is a shared DRAM memory region between ATF and UEFI to indicate a PCIe hot-plug event action. An item of this MHPP region is used to reflect a hot-plug event action of each PCIe port. Whenever there is a PCIe hot-plug event, ATF will update the action value to each item of MHPP region, and UEFI will handle the hot-plug ejection/insertion accordingly
- An item of MHPP is 24-bytes in size and is named by a 4-character word (mnemonic) to represent a PCIe Root Port device. The name format is <root_complex_A/B><root_complex_number><root_complex_port>. For example, if the board has a PCIe Root Port device RCA2.0 on socket 1 the hot-plug event action item must be named A120.
- This MHPP region is declared in the file named
Platform/Ampere/JadePkg/AcpiTable/MHPP.asi
. For Altra Max, this ACPI table is located atPlatform/Ampere/JadePkg/Ac02AcpiTables/MHPP.asi
. If the new board has the list of PCIe devices different than the Ampere Mt. Jade board, these items in MHPP region must be renamed.
- DSDT/PCI for Hot-Plug events
- The files to declare the PCIe Root Port are
Platform/Ampere/JadePkg/AcpiTables/{PCI-S0.asi, PCI-S1.asi}
. Note that the ACPI tables for Altra Max based platform is atPlatform/Ampere/JadePkg/Ac02AcpiTables/
folder. To support full hot-plug feature (software and hardware hot-plug with LED behavior functioning), the Segment:Bus:Device.Function (S:B:D.F) of the Root Port must be declared correctly. Follow the steps listed below to declare them.- List down PCIe devices tree in Linux using lspci -tv command to see all Root Port S:B:D.F values.
- Find out which PCIe device includes the segment that the Root Port has.
- Based on this S:B:D.F, declare Root Port device into the PCIe Device just found.
- Add _STA and _EJ0 instance to handle insertion and ejection events.
- The files to declare the PCIe Root Port are
Two key modules are responsible for producing SMBIOS tables: SmbiosPlatformDxe and OemMiscLib. These modules are essential for defining the platform-specific information derived from hardware characteristics of your platform.
You need to update these modules SmbiosPlatformDxe and OemMiscLib to reflect your platform's hardware.
Most of fields in SMBIOS Type 1, 2, and 3 are fetched from FRU Device via the IPMI SSIF interface.
If the new platform does not support the IPMI SSIF, please drop the support, especially the IpmiFruInfo.c
file.
On Ampere Mt. Jade, the hardware RTC connects to I2C6 on the master socket and validated with PCF85063AT chip. The GPI4 is dedicated for obtaining exclusive access because the RTC is shared between BMC and the SoC.
If you use the same RTC hardware on the new platform, modify appropriately the following macros for the I2C and GPI:
- GPI
I2C_RTC_ACCESS_GPIO_PIN
: RTC Access Lock
- I2C
I2C_RTC_BUS_ADDRESS
: I2C busI2C_RTC_BUS_SPEED
: I2C bus speedI2C_RTC_CHIP_ADDRESS
: I2C slave address of the RTC
If you use a different RTC on the new platform, you will need to port to the new hardware RTC chip.
You can also leverage EmbeddedPkg/Library/VirtualRealTimeClockLib/VirtualRealTimeClockLib.inf
if the hardware RTC has not supported yet.
The IPMI SSIF is used for the communication between the BMC and the SoC. It requires the following platform-specific modules:
-
Silicon/Ampere/AmpereAltraPkg/Drivers/SmbusHc/SmbusHcDxe.inf
: This driver produces the SMBUS protocol at DXE phase. -
Silicon/Ampere/AmpereAltraPkg/Drivers/SmbusHc/SmbusHcPei.inf
: This driver produces the SMBUS protocol at PEI phase. -
Platform/Ampere/NewBoardPkg/Library/PlatformBmcReadyLib/PlatformBmcReadyLib.inf
: This platform-dependent library provides API to check BMC status before executing SMBus commands for IPMI communication. On the Mt. Jade platform, the Altra SoC relies on GPI0 (referred to as BMC_READY GPIO) to determine status of BMC is ready for the IPMI communication. If the custom platform does not support this pin, use a NULL library that assumes BMC is always on and ready to accept IPMI messages. Put below line to NewBoard.dsc.Features/ManageabilityPkg/Library/PlatformBmcReadyLibNull/PlatformBmcReadyLibNull.inf
In order to enable the IPMI SSIF support:
- Ensure that the I2C4 is connected to the BMC and the frequency is operated at 400KHz.
- Update correspondingly the following PCDs if there are different configuration
from the BMC slave address and the BMC_READY GPIO if the custom board uses BMC_READY GPIO to determine the status of BMC.
gAmpereTokenSpaceGuid.PcdBmcReadyGpio
There are two types of the firmware image supported on the Ampere Mt. Jade platform:
- The combination of Ampere Trusted Firmware-A (TF-A) FIP, Board Settings, and EDK2 FD.
- Ampere System Firmware (SCP Firmware)
In order to enable the capsule update feature, update the IMAGE_ID and IMAGE_ID_STRING
to match the platform name in the Platform/Ampere/NewBoardPkg/Capsule/SystemFirmwareDescriptor/SystemFirmwareDescriptor.aslc
file.
Please refer to Capsule Based Firmware Update and Firmware Recovery for detailed porting instructions.
No change is needed.
It's important that the ATF running on the new platform must comply with the Ampere Altra Interface Firmware Requirements.
No change is needed. The new platform can inherit the required libraries and modules to support this feature.
Ampere EDK2 supports UEFI Secure Boot and it complies with UEFI Specifications. User can change the UEFI secure boot keys using UEFI Menu Setup.
If the DBB/DBU secure keys are deployed, requires to boot and update EDK2 firmware via capsule using the signed firmware image.
Users can run firmware update at run-time OS without reboot using amp_fwupgrade utility to update signed ATF-UEFI EDK2 image and signed SCP image.
If you have the patches and want to share with Ampere, use git-send-mail to Ampere EDK2 maintainers/reviewers
- Nhi Pham [email protected]
- Chuong Tran [email protected]
- Rebecca Cran [email protected]
For any technical questions that you want to consult with, send email to Ampere Support [email protected].