[edk2-devel] [edk2-platforms][PATCH 1/6] AmpereAltraPkg: Add PCIe Hot Plug library

Minh Nguyen via groups.io minhnguyen1=os.amperecomputing.com at groups.io
Thu May 11 08:10:06 UTC 2023


From: Vu Nguyen <vunguyen at os.amperecomputing.com>

This adds PCIe Hot Plug library to support Hot Plug
feature and specific procedures for setting different
Portmap tables (GPIO pins used for PCIe reset).

Signed-off-by: Minh Nguyen <minhnguyen1 at os.amperecomputing.com>
---
 Silicon/Ampere/AmpereAltraPkg/AmpereAltraPkg.dec                        |   8 +-
 Silicon/Ampere/AmpereSiliconPkg/AmpereSiliconPkg.dec                    |  13 +
 Silicon/Ampere/AmpereAltraPkg/AmpereAltraPkg.dsc.inc                    |   1 +
 Platform/Ampere/JadePkg/Jade.dsc                                        |  66 ++++
 Silicon/Ampere/AmpereAltraPkg/Library/PcieHotPlugLib/PcieHotPlugLib.inf |  37 ++
 Silicon/Ampere/AmpereAltraPkg/Include/Library/PcieHotPlugLib.h          | 162 ++++++++
 Silicon/Ampere/AmpereSiliconPkg/Include/Library/PcieHotPlugPortMapLib.h |  81 ++++
 Silicon/Ampere/AmpereAltraPkg/Library/PcieHotPlugLib/PcieHotPlugLib.c   | 397 ++++++++++++++++++++
 8 files changed, 764 insertions(+), 1 deletion(-)

diff --git a/Silicon/Ampere/AmpereAltraPkg/AmpereAltraPkg.dec b/Silicon/Ampere/AmpereAltraPkg/AmpereAltraPkg.dec
index d795c9229691..d4881eaed692 100644
--- a/Silicon/Ampere/AmpereAltraPkg/AmpereAltraPkg.dec
+++ b/Silicon/Ampere/AmpereAltraPkg/AmpereAltraPkg.dec
@@ -1,6 +1,6 @@
 ## @file
 #
-# Copyright (c) 2020-2021, Ampere Computing LLC. All rights reserved.<BR>
+# Copyright (c) 2020-2023, Ampere Computing LLC. All rights reserved.<BR>
 #
 # SPDX-License-Identifier: BSD-2-Clause-Patent
 #
@@ -49,6 +49,9 @@ [LibraryClasses]
   ##  @libraryclass  Defines a set of methods to initialize Pcie
   Ac01PcieLib|Silicon/Ampere/AmpereAltraPkg/Include/Library/Ac01PcieLib.h
 
+  ##  @libraryclass  Defines a set of methods to start Hot plug feature
+  PcieHotPlugLib|Silicon/Ampere/AmpereAltraPkg/Include/Library/PcieHotPlugLib.h
+
 [Guids]
   ## NVParam MM GUID
   gNVParamMmGuid               = { 0xE4AC5024, 0x29BE, 0x4ADC, { 0x93, 0x36, 0x87, 0xB5, 0xA0, 0x76, 0x23, 0x2D } }
@@ -70,3 +73,6 @@ [Guids]
 
   ## Include/Guid/AcpiConfigHii.h
   gAcpiConfigFormSetGuid = { 0x0ceb6764, 0xd415, 0x4b01, { 0xa8, 0x43, 0xd1, 0x01, 0xbc, 0xb0, 0xd8, 0x29 } }
+
+  ## PCIe Hot Plug GUID
+  gPcieHotPlugGuid = { 0x5598273c, 0x11ea, 0xa496, { 0x42, 0x02, 0x37, 0xbb, 0x02, 0x00, 0x13, 0xac } }
diff --git a/Silicon/Ampere/AmpereSiliconPkg/AmpereSiliconPkg.dec b/Silicon/Ampere/AmpereSiliconPkg/AmpereSiliconPkg.dec
index 625a9b2b1e89..9259956c7caa 100644
--- a/Silicon/Ampere/AmpereSiliconPkg/AmpereSiliconPkg.dec
+++ b/Silicon/Ampere/AmpereSiliconPkg/AmpereSiliconPkg.dec
@@ -80,3 +80,16 @@ [PcdsFixedAtBuild, PcdsDynamic, PcdsDynamicEx]
   #
   # SMBIOS Type 0 - BIOS Information
   gAmpereTokenSpaceGuid.PcdSmbiosTables0BiosReleaseDate|"MM/DD/YYYY"|VOID*|0xB0000002 # Must follow this MM/DD/YYYY SMBIOS date format
+
+  # Pcie HotPlug reset map
+  gAmpereTokenSpaceGuid.PcdPcieHotPlugGpioResetMap|0x0|UINT8|0xB000000A
+
+  #
+  # Pcie HotPlug Port Map table
+  #
+  gAmpereTokenSpaceGuid.PcdPcieHotPlugPortMapTable|{0x00}|PCIE_HOT_PLUG_PORT_MAP_TABLE|0xB000000B {
+    <HeaderFiles>
+      Library/PcieHotPlugPortMapLib.h
+    <Packages>
+      Silicon/Ampere/AmpereSiliconPkg/AmpereSiliconPkg.dec
+  }
diff --git a/Silicon/Ampere/AmpereAltraPkg/AmpereAltraPkg.dsc.inc b/Silicon/Ampere/AmpereAltraPkg/AmpereAltraPkg.dsc.inc
index 9275e0053af6..8cb2a3fe6422 100644
--- a/Silicon/Ampere/AmpereAltraPkg/AmpereAltraPkg.dsc.inc
+++ b/Silicon/Ampere/AmpereAltraPkg/AmpereAltraPkg.dsc.inc
@@ -81,6 +81,7 @@ [LibraryClasses.common]
   NVParamLib|Silicon/Ampere/AmpereAltraPkg/Library/NVParamLib/NVParamLib.inf
   MailboxInterfaceLib|Silicon/Ampere/AmpereAltraPkg/Library/MailboxInterfaceLib/MailboxInterfaceLib.inf
   SystemFirmwareInterfaceLib|Silicon/Ampere/AmpereAltraPkg/Library/SystemFirmwareInterfaceLib/SystemFirmwareInterfaceLib.inf
+  PcieHotPlugLib|Silicon/Ampere/AmpereAltraPkg/Library/PcieHotPlugLib/PcieHotPlugLib.inf
   PciePhyLib|Silicon/Ampere/AmpereAltraBinPkg/Library/PciePhyLib/PciePhyLib.inf
   Ac01PcieLib|Silicon/Ampere/AmpereAltraPkg/Library/Ac01PcieLib/Ac01PcieLib.inf
   AmpereCpuLib|Silicon/Ampere/AmpereAltraPkg/Library/AmpereCpuLib/AmpereCpuLib.inf
diff --git a/Platform/Ampere/JadePkg/Jade.dsc b/Platform/Ampere/JadePkg/Jade.dsc
index f14d286cdfb8..a6b5fa3ca2d3 100644
--- a/Platform/Ampere/JadePkg/Jade.dsc
+++ b/Platform/Ampere/JadePkg/Jade.dsc
@@ -100,7 +100,73 @@ [PcdsFeatureFlag.common]
   #
   gEfiMdeModulePkgTokenSpaceGuid.PcdInstallAcpiSdtProtocol|TRUE
 
+  #
+  # Flag to indicate option of using default or specific platform Port Map table
+  #
+  gAmpereTokenSpaceGuid.PcdPcieHotPlugPortMapTable.UseDefaultConfig|TRUE
+
 [PcdsFixedAtBuild]
+  gAmpereTokenSpaceGuid.PcdPcieHotPlugGpioResetMap|0x3F
+
+  #
+  # 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 PcieHotPlugSetGPIOMapCmd () 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_PORT_MAP_ENTRY][sizeof(PCIE_HOT_PLUG_PORTMAP_ENTRY)] <=> PortMap[96][11].
+  #   * Example: Bellow configuration is the configuration 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
+
 !ifdef $(FIRMWARE_VER)
   gEfiMdeModulePkgTokenSpaceGuid.PcdFirmwareVersionString|L"$(FIRMWARE_VER)"
 !endif
diff --git a/Silicon/Ampere/AmpereAltraPkg/Library/PcieHotPlugLib/PcieHotPlugLib.inf b/Silicon/Ampere/AmpereAltraPkg/Library/PcieHotPlugLib/PcieHotPlugLib.inf
new file mode 100644
index 000000000000..faeb74ecc0bf
--- /dev/null
+++ b/Silicon/Ampere/AmpereAltraPkg/Library/PcieHotPlugLib/PcieHotPlugLib.inf
@@ -0,0 +1,37 @@
+## @file
+#
+# Copyright (c) 2023, Ampere Computing LLC. All rights reserved.<BR>
+#
+# SPDX-License-Identifier: BSD-2-Clause-Patent
+#
+##
+
+[Defines]
+  INF_VERSION                    = 0x0001001B
+  BASE_NAME                      = PcieHotPlugLib
+  FILE_GUID                      = 6C0C1D32-CB51-4236-AC33-A7A6D4B638E2
+  MODULE_TYPE                    = BASE
+  VERSION_STRING                 = 1.0
+  LIBRARY_CLASS                  = PcieHotPlugLib
+
+[Sources]
+  PcieHotPlugLib.c
+
+[Packages]
+  ArmPkg/ArmPkg.dec
+  MdePkg/MdePkg.dec
+  Silicon/Ampere/AmpereAltraPkg/AmpereAltraPkg.dec
+  Silicon/Ampere/AmpereSiliconPkg/AmpereSiliconPkg.dec
+
+[LibraryClasses]
+  ArmSmcLib
+  BaseMemoryLib
+  DebugLib
+  PcdLib
+
+[Pcd]
+  gAmpereTokenSpaceGuid.PcdPcieHotPlugGpioResetMap
+  gAmpereTokenSpaceGuid.PcdPcieHotPlugPortMapTable
+
+[Guids]
+  gPcieHotPlugGuid
diff --git a/Silicon/Ampere/AmpereAltraPkg/Include/Library/PcieHotPlugLib.h b/Silicon/Ampere/AmpereAltraPkg/Include/Library/PcieHotPlugLib.h
new file mode 100644
index 000000000000..e2f17d366a58
--- /dev/null
+++ b/Silicon/Ampere/AmpereAltraPkg/Include/Library/PcieHotPlugLib.h
@@ -0,0 +1,162 @@
+/** @file
+
+   Copyright (c) 2023, Ampere Computing LLC. All rights reserved.<BR>
+
+   SPDX-License-Identifier: BSD-2-Clause-Patent
+
+ **/
+
+#ifndef PCIE_HOT_PLUG_H_
+#define PCIE_HOT_PLUG_H_
+
+#define PCIE_HOT_PLUG_SPCI_CMD_ALERT_IRQ       1  // Alert IRQ
+#define PCIE_HOT_PLUG_SPCI_CMD_START           2  // Stat monitor event
+#define PCIE_HOT_PLUG_SPCI_CMD_CHG             3  // Indicate PCIE port change state explicitly
+#define PCIE_HOT_PLUG_SPCI_CMD_LED             4  // Control LED state
+#define PCIE_HOT_PLUG_SPCI_CMD_PORT_MAP_CLR    5  // Clear all port map
+#define PCIE_HOT_PLUG_SPCI_CMD_PORT_MAP_SET    6  // Set port map
+#define PCIE_HOT_PLUG_SPCI_CMD_PORT_MAP_LOCK   7  // Lock port map
+#define PCIE_HOT_PLUG_SPCI_CMD_GPIO_MAP        8  // Set GPIO reset map
+
+#define LED_FAULT      1  // LED_CMD: LED type - Fault
+#define LED_ATT        2  // LED_CMD: LED type - Attention
+
+#define LED_SET_ON     1
+#define LED_SET_OFF    2
+#define LED_SET_BLINK  3
+
+// DEN0077A Arm Secure Partition Client Interface Specification 1.0 Beta_0_0
+
+// Client ID used for SPCI calls
+#define SPCI_CLIENT_ID  0x0000ACAC
+
+// SPCI error codes.
+#define SPCI_SUCCESS            0
+#define SPCI_NOT_SUPPORTED      -1
+#define SPCI_INVALID_PARAMETER  -2
+#define SPCI_NO_MEMORY          -3
+#define SPCI_BUSY               -4
+#define SPCI_QUEUED             -5
+#define SPCI_DENIED             -6
+#define SPCI_NOT_PRESENT        -7
+
+// Bit definitions inside the function id as per the SMC calling convention
+#define FUNCID_CC_SHIFT    30
+#define FUNCID_OEN_SHIFT   24
+
+#define SMC_64         1
+#define SMC_32         0
+
+// Definitions to build the complete SMC ID
+#define SPCI_FID_MISC_FLAG   (0 << 27)
+#define SPCI_FID_MISC_SHIFT  20
+#define SPCI_FID_TUN_FLAG    (1 << 27)
+#define SPCI_FID_TUN_SHIFT   24
+
+#define OEN_SPCI_START  0x30
+#define OEN_SPCI_END    0x3F
+
+#define SPCI_SMC(spci_fid)      ((OEN_SPCI_START << FUNCID_OEN_SHIFT) | \
+                                 (1U << 31) | (spci_fid))
+#define SPCI_MISC_32(misc_fid)  ((SMC_32 << FUNCID_CC_SHIFT) |  \
+                                 SPCI_FID_MISC_FLAG |           \
+                                 SPCI_SMC ((misc_fid) << SPCI_FID_MISC_SHIFT))
+#define SPCI_MISC_64(misc_fid)  ((SMC_64 << FUNCID_CC_SHIFT) |  \
+                                 SPCI_FID_MISC_FLAG |           \
+                                 SPCI_SMC ((misc_fid) << SPCI_FID_MISC_SHIFT))
+#define SPCI_TUN_64(tun_fid)    ((SMC_64 << FUNCID_CC_SHIFT) |  \
+                                 SPCI_FID_TUN_FLAG |            \
+                                 SPCI_SMC ((tun_fid) << SPCI_FID_TUN_SHIFT))
+
+// SPCI miscellaneous functions
+#define SPCI_FID_SERVICE_HANDLE_OPEN         0x2
+#define SPCI_FID_SERVICE_HANDLE_CLOSE        0x3
+#define SPCI_FID_SERVICE_REQUEST_BLOCKING    0x7
+#define SPCI_FID_SERVICE_REQUEST_START       0x8
+
+// SPCI tunneling functions
+#define SPCI_FID_SERVICE_TUN_REQUEST_BLOCKING  0x2
+
+// Complete SMC IDs and associated values
+#define SPCI_SERVICE_HANDLE_OPEN                   \
+                            SPCI_MISC_32 (SPCI_FID_SERVICE_HANDLE_OPEN)
+#define SPCI_SERVICE_HANDLE_CLOSE                  \
+                            SPCI_MISC_32 (SPCI_FID_SERVICE_HANDLE_CLOSE)
+#define SPCI_SERVICE_REQUEST_BLOCKING_AARCH64      \
+                            SPCI_MISC_64 (SPCI_FID_SERVICE_REQUEST_BLOCKING)
+#define SPCI_SERVICE_REQUEST_START_AARCH64         \
+                            SPCI_MISC_64 (SPCI_FID_SERVICE_REQUEST_START)
+#define SPCI_SERVICE_TUN_REQUEST_BLOCKING_AARCH64  \
+                            SPCI_TUN_64 (SPCI_FID_SERVICE_TUN_REQUEST_BLOCKING)
+
+#pragma pack(1)
+
+typedef struct {
+  UINT64    Token;
+  UINT32    HandleId;
+  UINT64    SpciCommand;
+  UINT64    SpciParam1;
+  UINT64    SpciParam2;
+  UINT64    SpciParam3;
+  UINT64    SpciParam4;
+  UINT64    SpciParam5;
+} AMPERE_SPCI_ARGS;
+
+#pragma pack()
+
+/**
+  Set GPIO pins used for PCIe reset. This command
+  limits the number of GPIO[16:21] for reset purpose.
+**/
+VOID
+PcieHotPlugSetGpioMap (
+  VOID
+  );
+
+/**
+  Lock current Portmap table.
+**/
+VOID
+PcieHotPlugSetLockPortMap (
+  VOID
+  );
+
+/**
+  Start Hot plug service.
+**/
+VOID
+PcieHotPlugSetStart (
+  VOID
+  );
+
+/**
+  Clear current configuration of Portmap table.
+**/
+VOID
+PcieHotPlugSetClear (
+  VOID
+  );
+
+/**
+  Set configuration for Portmap table.
+**/
+VOID
+PcieHotPlugSetPortMap (
+  VOID
+  );
+
+/**
+  This function will start Hotplug service after following steps:
+  - Open handle to make a SPCI call.
+  - Set GPIO pins for PCIe reset.
+  - Set configuration for Portmap table.
+  - Lock current Portmap table.
+  - Start Hot plug service.
+  - Close handle.
+**/
+VOID
+PcieHotPlugStart (
+  VOID
+  );
+
+#endif
diff --git a/Silicon/Ampere/AmpereSiliconPkg/Include/Library/PcieHotPlugPortMapLib.h b/Silicon/Ampere/AmpereSiliconPkg/Include/Library/PcieHotPlugPortMapLib.h
new file mode 100644
index 000000000000..4889f0891c47
--- /dev/null
+++ b/Silicon/Ampere/AmpereSiliconPkg/Include/Library/PcieHotPlugPortMapLib.h
@@ -0,0 +1,81 @@
+/** @file
+
+  Copyright (c) 2023, Ampere Computing LLC. All rights reserved.<BR>
+
+  SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#ifndef PCIE_HOT_PLUG_PORT_MAP_H_
+#define PCIE_HOT_PLUG_PORT_MAP_H_
+
+// "PCIe Bifurcation Mapping" spec just reserve 24x48 bytes (48 ports)
+#define MAX_NUMBER_PROCESSORS  2
+#define NUMBER_OF_PCIE_PORTS   48
+#define MAX_PORT_MAP_ENTRY     (NUMBER_OF_PCIE_PORTS * MAX_NUMBER_PROCESSORS)
+
+//
+// - Macro to create value for PCIe Hot Plug configuration from PcieHotPlugPortMapEntry structure.
+// - Value structure:
+//     Bit [0:7]:    Vport
+//     Bit [8:11]:   Socket
+//     Bit [12:15]:  RcaPort
+//     Bit [16:19]:  RcaSubPort
+//     Bit [20:23]:  PinPort
+//     Bit [24:31]:  I2cAddress
+//     Bit [32:39]:  MuxAddress
+//     Bit [40:43]:  MuxChannel
+//     Bit [44:51]:  GpioResetNumber
+//     Bit [52:55]:  Segment
+//     Bit [56: 63]: DriveIndexGpioResetNumber
+//
+#define PCIE_HOT_PLUG_DECODE_VPORT(Value)              ((((UINTN)(Value).Vport)           & 0xFF) << 0)
+#define PCIE_HOT_PLUG_DECODE_SOCKET(Value)             ((((UINTN)(Value).Socket)          & 0x0F) << 8)
+#define PCIE_HOT_PLUG_DECODE_RCA_PORT(Value)           ((((UINTN)(Value).RcaPort)         & 0x0F) << 12)
+#define PCIE_HOT_PLUG_DECODE_RCA_SUB_PORT(Value)       ((((UINTN)(Value).RcaSubPort)      & 0x0F) << 16)
+#define PCIE_HOT_PLUG_DECODE_PIN_PORT(Value)           ((((UINTN)(Value).PinPort)         & 0x0F) << 20)
+#define PCIE_HOT_PLUG_DECODE_I2C_ADDRESS(Value)        ((((UINTN)(Value).I2cAddress)      & 0xFF) << 24)
+#define PCIE_HOT_PLUG_DECODE_MUX_ADDRESS(Value)        ((((UINTN)(Value).MuxAddress)      & 0xFF) << 32)
+#define PCIE_HOT_PLUG_DECODE_MUX_CHANNEL(Value)        ((((UINTN)(Value).MuxChannel)      & 0x0F) << 40)
+#define PCIE_HOT_PLUG_DECODE_GPIO_RESET_NUMBER(Value)  ((((UINTN)(Value).GpioResetNumber) & 0xFF) << 44)
+#define PCIE_HOT_PLUG_DECODE_SEGMENT(Value)            ((((UINTN)(Value).Segment)         & 0x0F) << 52)
+#define PCIE_HOT_PLUG_DECODE_DRIVE_INDEX(Value)        ((((UINTN)(Value).DriveIndex)      & 0xFF) << 56)
+
+#define PCIE_HOT_PLUG_GET_CONFIG_VALUE(Value)  (  \
+  PCIE_HOT_PLUG_DECODE_VPORT(Value)             | \
+  PCIE_HOT_PLUG_DECODE_SOCKET(Value)            | \
+  PCIE_HOT_PLUG_DECODE_RCA_PORT(Value)          | \
+  PCIE_HOT_PLUG_DECODE_RCA_SUB_PORT(Value)      | \
+  PCIE_HOT_PLUG_DECODE_PIN_PORT(Value)          | \
+  PCIE_HOT_PLUG_DECODE_I2C_ADDRESS(Value)       | \
+  PCIE_HOT_PLUG_DECODE_MUX_ADDRESS(Value)       | \
+  PCIE_HOT_PLUG_DECODE_MUX_CHANNEL(Value)       | \
+  PCIE_HOT_PLUG_DECODE_GPIO_RESET_NUMBER(Value) | \
+  PCIE_HOT_PLUG_DECODE_SEGMENT(Value)           | \
+  PCIE_HOT_PLUG_DECODE_DRIVE_INDEX(Value)         \
+)
+
+#pragma pack(1)
+
+typedef struct {
+  UINT8    Vport;
+  UINT8    Socket;
+  UINT8    RcaPort;
+  UINT8    RcaSubPort;
+  UINT8    PinPort;
+  UINT8    I2cAddress;
+  UINT8    MuxAddress;
+  UINT8    MuxChannel;
+  UINT8    GpioResetNumber;
+  UINT8    Segment;
+  UINT8    DriveIndex;
+} PCIE_HOT_PLUG_PORT_MAP_ENTRY;
+
+typedef struct {
+  BOOLEAN    UseDefaultConfig;
+  UINT8      PortMap[MAX_PORT_MAP_ENTRY][sizeof (PCIE_HOT_PLUG_PORT_MAP_ENTRY)];
+} PCIE_HOT_PLUG_PORT_MAP_TABLE;
+
+#pragma pack()
+
+#endif
diff --git a/Silicon/Ampere/AmpereAltraPkg/Library/PcieHotPlugLib/PcieHotPlugLib.c b/Silicon/Ampere/AmpereAltraPkg/Library/PcieHotPlugLib/PcieHotPlugLib.c
new file mode 100644
index 000000000000..10de5d17d2b9
--- /dev/null
+++ b/Silicon/Ampere/AmpereAltraPkg/Library/PcieHotPlugLib/PcieHotPlugLib.c
@@ -0,0 +1,397 @@
+/** @file
+
+   Copyright (c) 2023, Ampere Computing LLC. All rights reserved.<BR>
+
+   SPDX-License-Identifier: BSD-2-Clause-Patent
+
+ **/
+
+#include <Uefi.h>
+
+#include <Library/ArmSmcLib.h>
+#include <Library/BaseMemoryLib.h>
+#include <Library/DebugLib.h>
+#include <Library/PcdLib.h>
+#include <Library/PcieHotPlugLib.h>
+#include <Library/PcieHotPlugPortMapLib.h>
+
+#define END_PORT_MAP_ENTRY  0xFF
+
+// SPM takes up to 4 arguments as value for SPCI call (Args.SpciParam1->Args.SpciParam4).
+#define MAX_MSG_CMD_ARGS  4
+
+UINT32    HandleId;
+
+STATIC
+EFI_STATUS
+SpciStatusMap (
+  UINTN  SpciStatus
+  )
+{
+  switch (SpciStatus) {
+    case SPCI_SUCCESS:
+      return EFI_SUCCESS;
+
+    case SPCI_NOT_SUPPORTED:
+      return EFI_UNSUPPORTED;
+
+    case SPCI_INVALID_PARAMETER:
+      return EFI_INVALID_PARAMETER;
+
+    case SPCI_NO_MEMORY:
+      return EFI_OUT_OF_RESOURCES;
+
+    case SPCI_BUSY:
+    case SPCI_QUEUED:
+      return EFI_NOT_READY;
+
+    case SPCI_DENIED:
+      return EFI_ACCESS_DENIED;
+
+    case SPCI_NOT_PRESENT:
+      return EFI_NOT_FOUND;
+
+    default:
+      return EFI_DEVICE_ERROR;
+  }
+}
+
+EFI_STATUS
+EFIAPI
+SpciServiceHandleOpen (
+  UINT16    ClientId,
+  UINT32    *HandleId,
+  EFI_GUID  Guid
+  )
+{
+  ARM_SMC_ARGS  SmcArgs;
+  EFI_STATUS    Status;
+  UINT32        X1;
+  UINT64        Uuid1, Uuid2, Uuid3, Uuid4;
+
+  if (HandleId == NULL) {
+    DEBUG ((DEBUG_ERROR, "%a HandleId is NULL \n", __func__));
+    return EFI_INVALID_PARAMETER;
+  }
+
+  Uuid1 = Guid.Data1;
+  Uuid2 = Guid.Data3 << 16 | Guid.Data2;
+  Uuid3 = Guid.Data4[3] << 24 | Guid.Data4[2] << 16 | Guid.Data4[1] << 8 | Guid.Data4[0];
+  Uuid4 = Guid.Data4[7] << 24 | Guid.Data4[6] << 16 | Guid.Data4[5] << 8 | Guid.Data4[4];
+
+  SmcArgs.Arg0 = SPCI_SERVICE_HANDLE_OPEN;
+  SmcArgs.Arg1 = Uuid1;
+  SmcArgs.Arg2 = Uuid2;
+  SmcArgs.Arg3 = Uuid3;
+  SmcArgs.Arg4 = Uuid4;
+  SmcArgs.Arg5 = 0;
+  SmcArgs.Arg6 = 0;
+  SmcArgs.Arg7 = ClientId;
+  ArmCallSmc (&SmcArgs);
+
+  Status = SpciStatusMap (SmcArgs.Arg0);
+  if (EFI_ERROR (Status)) {
+    return Status;
+  }
+
+  X1 = SmcArgs.Arg1;
+
+  if ((X1 & 0x0000FFFF) != 0) {
+    DEBUG ((
+      DEBUG_ERROR,
+      "%a: SpciServiceHandleOpen returned X1 = 0x%08x\n",
+      __func__,
+      X1
+      ));
+    return EFI_DEVICE_ERROR;
+  }
+
+  // Combine of returned handle and clientid
+  *HandleId = (UINT32)X1 | ClientId;
+
+  return EFI_SUCCESS;
+}
+
+EFI_STATUS
+EFIAPI
+SpciServiceHandleClose (
+  UINT32  HandleId
+  )
+{
+  ARM_SMC_ARGS  SmcArgs;
+  EFI_STATUS    Status;
+
+  SmcArgs.Arg0 = SPCI_SERVICE_HANDLE_CLOSE;
+  SmcArgs.Arg1 = HandleId;
+  ArmCallSmc (&SmcArgs);
+
+  Status = SpciStatusMap (SmcArgs.Arg0);
+  if (EFI_ERROR (Status)) {
+    return Status;
+  }
+
+  return EFI_SUCCESS;
+}
+
+EFI_STATUS
+EFIAPI
+SpciServiceRequestStart (
+  AMPERE_SPCI_ARGS  *Args
+  )
+{
+  ARM_SMC_ARGS  SmcArgs;
+  EFI_STATUS    Status;
+
+  if (Args == NULL) {
+    DEBUG ((DEBUG_ERROR, "%a: Invalid parameter\n", __func__));
+    return EFI_INVALID_PARAMETER;
+  }
+
+  SmcArgs.Arg0 = SPCI_SERVICE_REQUEST_START_AARCH64;
+  SmcArgs.Arg1 = Args->SpciCommand;
+  SmcArgs.Arg2 = Args->SpciParam1;
+  SmcArgs.Arg3 = Args->SpciParam2;
+  SmcArgs.Arg4 = Args->SpciParam3;
+  SmcArgs.Arg5 = Args->SpciParam4;
+  SmcArgs.Arg6 = Args->SpciParam5;
+  SmcArgs.Arg7 = (UINT64)Args->HandleId;
+  ArmCallSmc (&SmcArgs);
+
+  Status = SpciStatusMap (SmcArgs.Arg0);
+  if (EFI_ERROR (Status)) {
+    return Status;
+  }
+
+  // Return Token
+  Args->Token = SmcArgs.Arg1;
+
+  return EFI_SUCCESS;
+}
+
+EFI_STATUS
+EFIAPI
+SpciServiceRequestBlocking (
+  AMPERE_SPCI_ARGS  *Args
+  )
+{
+  ARM_SMC_ARGS  SmcArgs;
+  EFI_STATUS    Status;
+
+  if (Args == NULL) {
+    DEBUG ((DEBUG_ERROR, "%a: Invalid parameter\n", __func__));
+    return EFI_INVALID_PARAMETER;
+  }
+
+  SmcArgs.Arg0 = SPCI_SERVICE_REQUEST_BLOCKING_AARCH64;
+  SmcArgs.Arg1 = Args->SpciCommand;
+  SmcArgs.Arg2 = Args->SpciParam1;
+  SmcArgs.Arg3 = Args->SpciParam2;
+  SmcArgs.Arg4 = Args->SpciParam3;
+  SmcArgs.Arg5 = Args->SpciParam4;
+  SmcArgs.Arg6 = Args->SpciParam5;
+  SmcArgs.Arg7 = (UINT64)Args->HandleId;
+  ArmCallSmc (&SmcArgs);
+
+  Status = SpciStatusMap (SmcArgs.Arg0);
+  if (EFI_ERROR (Status)) {
+    return Status;
+  }
+
+  Args->SpciCommand = SmcArgs.Arg1;
+  Args->SpciParam1  = SmcArgs.Arg2;
+  Args->SpciParam2  = SmcArgs.Arg3;
+
+  return EFI_SUCCESS;
+}
+
+/**
+  Set GPIO pins used for PCIe reset. This command
+  limits the number of GPIO[16:21] for reset purpose.
+**/
+VOID
+PcieHotPlugSetGpioMap (
+  VOID
+  )
+{
+  AMPERE_SPCI_ARGS  Args;
+  EFI_STATUS        Status;
+
+  Args.HandleId    = HandleId;
+  Args.SpciCommand = PCIE_HOT_PLUG_SPCI_CMD_GPIO_MAP;
+  Args.SpciParam1  = (UINTN)PcdGet8 (PcdPcieHotPlugGpioResetMap);
+
+  Status = SpciServiceRequestBlocking (&Args);
+  if (EFI_ERROR (Status)) {
+    DEBUG ((DEBUG_ERROR, "SPM HotPlug GPIO reset map failed. Returned: %r\n", Status));
+  }
+}
+
+/**
+  Lock current Portmap table.
+**/
+VOID
+PcieHotPlugSetLockPortMap (
+  VOID
+  )
+{
+  AMPERE_SPCI_ARGS  Args;
+  EFI_STATUS        Status;
+
+  Args.HandleId    = HandleId;
+  Args.SpciCommand = PCIE_HOT_PLUG_SPCI_CMD_PORT_MAP_LOCK;
+
+  Status = SpciServiceRequestBlocking (&Args);
+  if (EFI_ERROR (Status)) {
+    DEBUG ((DEBUG_ERROR, "SPM HotPlug port map lock failed. Returned: %r\n", Status));
+  }
+}
+
+/**
+  Start Hot plug service.
+**/
+VOID
+PcieHotPlugSetStart (
+  VOID
+  )
+{
+  AMPERE_SPCI_ARGS  Args;
+  EFI_STATUS        Status;
+
+  Args.HandleId    = HandleId;
+  Args.SpciCommand = PCIE_HOT_PLUG_SPCI_CMD_START;
+
+  Status = SpciServiceRequestBlocking (&Args);
+  if (EFI_ERROR (Status)) {
+    DEBUG ((DEBUG_ERROR, "SPM HotPlug start failed. Returned: %r\n", Status));
+  }
+}
+
+/**
+  Clear current configuration of Portmap table.
+**/
+VOID
+PcieHotPlugSetClear (
+  VOID
+  )
+{
+  AMPERE_SPCI_ARGS  Args;
+  EFI_STATUS        Status;
+
+  Args.HandleId    = HandleId;
+  Args.SpciCommand = PCIE_HOT_PLUG_SPCI_CMD_PORT_MAP_CLR;
+
+  Status = SpciServiceRequestBlocking (&Args);
+  if (EFI_ERROR (Status)) {
+    DEBUG ((DEBUG_ERROR, "SPM HotPlug clear port map failed. Returned: %r\n", Status));
+  }
+}
+
+/**
+  Set configuration for Portmap table.
+**/
+VOID
+PcieHotPlugSetPortMap (
+  VOID
+  )
+{
+  AMPERE_SPCI_ARGS  Args;
+  EFI_STATUS        Status;
+
+  PCIE_HOT_PLUG_PORT_MAP_TABLE  *PortMapTable;
+  PCIE_HOT_PLUG_PORT_MAP_ENTRY  PortMapEntry;
+  UINT8                         Index;
+  UINT8                         PortMapEntryIndex;
+  BOOLEAN                       IsEndPortMapEntry;
+  UINTN                         ConfigValue;
+  UINTN                         *ConfigLegacy;
+
+  // Retrieves PCD of Portmap table.
+  PortMapTable = (PCIE_HOT_PLUG_PORT_MAP_TABLE *)PcdGetPtr (PcdPcieHotPlugPortMapTable);
+
+  //
+  // Check whether specific platform configuration is used?
+  // Otherwise, keep default configuration (Mt. Jade 2U).
+  //
+  if (!PortMapTable->UseDefaultConfig) {
+    IsEndPortMapEntry = FALSE;
+    PortMapEntryIndex = 0;
+
+    // Clear old Port Map table first.
+    PcieHotPlugSetClear ();
+
+    while (!IsEndPortMapEntry) {
+      ZeroMem (&Args, sizeof (Args));
+      Args.HandleId    = HandleId;
+      Args.SpciCommand = PCIE_HOT_PLUG_SPCI_CMD_PORT_MAP_SET;
+
+      // Pointer will get configuration value for Args.SpciParam1->Args.SpciParam5
+      ConfigLegacy = &Args.SpciParam1;
+
+      for (Index = 0; Index < MAX_MSG_CMD_ARGS; Index++) {
+        PortMapEntry  = *((PCIE_HOT_PLUG_PORT_MAP_ENTRY *)PortMapTable->PortMap[PortMapEntryIndex]);
+        ConfigValue   = PCIE_HOT_PLUG_GET_CONFIG_VALUE (PortMapEntry);
+        *ConfigLegacy = ConfigValue;
+
+        if (PortMapTable->PortMap[PortMapEntryIndex][0] == END_PORT_MAP_ENTRY) {
+          IsEndPortMapEntry = TRUE;
+          break;
+        }
+
+        PortMapEntryIndex++;
+        ConfigLegacy++;
+      }
+
+      Status = SpciServiceRequestBlocking (&Args);
+      if (EFI_ERROR (Status)) {
+        DEBUG ((DEBUG_ERROR, "SPM HotPlug set port map failed. Returned: %r\n", Status));
+      }
+    }
+  }
+}
+
+/**
+  This function will start Hotplug service after following steps:
+  - Open handle to make a SPCI call.
+  - Set GPIO pins for PCIe reset.
+  - Set configuration for Portmap table.
+  - Lock current Portmap table.
+  - Start Hot plug service.
+  - Close handle.
+**/
+VOID
+PcieHotPlugStart (
+  VOID
+  )
+{
+  EFI_STATUS  Status;
+
+  // Open handle
+  Status = SpciServiceHandleOpen (SPCI_CLIENT_ID, &HandleId, gPcieHotPlugGuid);
+  if (EFI_ERROR (Status)) {
+    DEBUG ((
+      DEBUG_ERROR,
+      "SPM failed to return invalid handle. Returned: %r\n",
+      Status
+      ));
+
+    return;
+  }
+
+  // Set GPIO pins for PCIe reset
+  PcieHotPlugSetGpioMap ();
+
+  // Set Portmap table
+  PcieHotPlugSetPortMap ();
+
+  // Lock current Portmap table
+  PcieHotPlugSetLockPortMap ();
+
+  // Start Hot plug service
+  PcieHotPlugSetStart ();
+
+  // Close handle
+  Status = SpciServiceHandleClose (HandleId);
+  if (EFI_ERROR (Status)) {
+    DEBUG ((DEBUG_ERROR, "SPM HotPlug close handle failed. Returned: %r\n", Status));
+  }
+}
-- 
2.39.0



-=-=-=-=-=-=-=-=-=-=-=-
Groups.io Links: You receive all messages sent to this group.
View/Reply Online (#104715): https://edk2.groups.io/g/devel/message/104715
Mute This Topic: https://groups.io/mt/98831767/1813853
Group Owner: devel+owner at edk2.groups.io
Unsubscribe: https://edk2.groups.io/g/devel/unsub [edk2-devel-archive at redhat.com]
-=-=-=-=-=-=-=-=-=-=-=-




More information about the edk2-devel-archive mailing list