Skip to content

Latest commit

 

History

History
366 lines (285 loc) · 20.8 KB

PlatformPortingGuide.md

File metadata and controls

366 lines (285 loc) · 20.8 KB

Ampere Altra Based Platforms Porting Guide

Overview

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).


EDKII Code Organization

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
Loading

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.

Porting TianoCore EDKII to a new platform

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.

  1. 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 under Platform/Ampere/NewBoardPkg.
  2. Copy Platform/Ampere/JadePkg to Platform/Ampere/NewBoardPkg.
  3. Rename the file name under the NewBoardPkg like BoardSetting.cfg and DSC/FDF file to match the platform name.

DSC/FDF

Replace correspondingly the Jade/JADE with NewBoard/NEWBOARD throughout the files.

Board Setting

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.

PCIe Root Complex Configuration

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.

PCIe Hot-Plug

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

ACPI

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.
  • 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 at Platform/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 at Platform/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.

SMBIOS

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.

RTC

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 bus
    • I2C_RTC_BUS_SPEED: I2C bus speed
    • I2C_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.

IPMI/SSIF

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:

  1. Ensure that the I2C4 is connected to the BMC and the frequency is operated at 400KHz.
  2. 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

Signed Capsule Update

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.

Trusted Platform Module (TPM)

No change is needed.

It's important that the ATF running on the new platform must comply with the Ampere Altra Interface Firmware Requirements.

Secure Boot and Update

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.


Contact Information

If you have the patches and want to share with Ampere, use git-send-mail to Ampere EDK2 maintainers/reviewers

For any technical questions that you want to consult with, send email to Ampere Support [email protected].