summaryrefslogtreecommitdiffstats
path: root/MdeModulePkg
diff options
context:
space:
mode:
Diffstat (limited to 'MdeModulePkg')
-rw-r--r--MdeModulePkg/Bus/Pci/XhciDxe/Xhci.c5
-rw-r--r--MdeModulePkg/Bus/Pci/XhciDxe/Xhci.h1
-rw-r--r--MdeModulePkg/Bus/Pci/XhciDxe/XhciDxe.inf5
-rw-r--r--MdeModulePkg/Bus/Pci/XhciDxe/XhciReg.c2
-rw-r--r--MdeModulePkg/Bus/Pci/XhciDxe/XhciSched.c5
-rw-r--r--MdeModulePkg/Bus/Pci/XhciDxe/XhciSched.h7
-rw-r--r--MdeModulePkg/Bus/Spi/SpiBus/SpiBus.c433
-rw-r--r--MdeModulePkg/Bus/Spi/SpiBus/SpiBus.h167
-rw-r--r--MdeModulePkg/Bus/Spi/SpiBus/SpiBus.uni10
-rw-r--r--MdeModulePkg/Bus/Spi/SpiBus/SpiBusDxe.c198
-rw-r--r--MdeModulePkg/Bus/Spi/SpiBus/SpiBusDxe.inf41
-rw-r--r--MdeModulePkg/Bus/Spi/SpiBus/SpiBusSmm.c162
-rw-r--r--MdeModulePkg/Bus/Spi/SpiBus/SpiBusSmm.inf41
-rw-r--r--MdeModulePkg/Bus/Spi/SpiHc/SpiHc.c115
-rw-r--r--MdeModulePkg/Bus/Spi/SpiHc/SpiHc.h117
-rw-r--r--MdeModulePkg/Bus/Spi/SpiHc/SpiHc.uni10
-rw-r--r--MdeModulePkg/Bus/Spi/SpiHc/SpiHcDxe.c101
-rw-r--r--MdeModulePkg/Bus/Spi/SpiHc/SpiHcDxe.inf47
-rw-r--r--MdeModulePkg/Bus/Spi/SpiHc/SpiHcSmm.c79
-rw-r--r--MdeModulePkg/Bus/Spi/SpiHc/SpiHcSmm.inf45
-rw-r--r--MdeModulePkg/Core/Dxe/Gcd/Gcd.c10
-rw-r--r--MdeModulePkg/Core/Dxe/Mem/Page.c38
-rw-r--r--MdeModulePkg/Include/Library/SpiHcPlatformLib.h148
-rw-r--r--MdeModulePkg/Include/Pi/PrePiDxeCis.h25
-rw-r--r--MdeModulePkg/Include/Pi/PrePiHob.h20
-rw-r--r--MdeModulePkg/Library/BaseSpiHcPlatformLibNull/BaseSpiHcPlatformLibNull.c145
-rw-r--r--MdeModulePkg/Library/BaseSpiHcPlatformLibNull/BaseSpiHcPlatformLibNull.inf33
-rw-r--r--MdeModulePkg/Library/BaseSpiHcPlatformLibNull/BaseSpiHcPlatformLibNull.uni11
-rw-r--r--MdeModulePkg/MdeModulePkg.dec10
-rw-r--r--MdeModulePkg/MdeModulePkg.dsc6
-rw-r--r--MdeModulePkg/Universal/Acpi/FirmwarePerformanceDataTablePei/FirmwarePerformancePei.c12
31 files changed, 1973 insertions, 76 deletions
diff --git a/MdeModulePkg/Bus/Pci/XhciDxe/Xhci.c b/MdeModulePkg/Bus/Pci/XhciDxe/Xhci.c
index f4e61d223c..cf6b32959e 100644
--- a/MdeModulePkg/Bus/Pci/XhciDxe/Xhci.c
+++ b/MdeModulePkg/Bus/Pci/XhciDxe/Xhci.c
@@ -825,7 +825,10 @@ XhcTransfer (
*TransferResult = Urb->Result;
*DataLength = Urb->Completed;
- if ((*TransferResult == EFI_USB_ERR_STALL) || (*TransferResult == EFI_USB_ERR_BABBLE)) {
+ //
+ // Based on XHCI spec 4.8.3, software should do the reset endpoint while USB Transaction occur.
+ //
+ if ((*TransferResult == EFI_USB_ERR_STALL) || (*TransferResult == EFI_USB_ERR_BABBLE) || (*TransferResult == EDKII_USB_ERR_TRANSACTION)) {
ASSERT (Status == EFI_DEVICE_ERROR);
RecoveryStatus = XhcRecoverHaltedEndpoint (Xhc, Urb);
if (EFI_ERROR (RecoveryStatus)) {
diff --git a/MdeModulePkg/Bus/Pci/XhciDxe/Xhci.h b/MdeModulePkg/Bus/Pci/XhciDxe/Xhci.h
index 4401675872..c9a12095c2 100644
--- a/MdeModulePkg/Bus/Pci/XhciDxe/Xhci.h
+++ b/MdeModulePkg/Bus/Pci/XhciDxe/Xhci.h
@@ -28,6 +28,7 @@ SPDX-License-Identifier: BSD-2-Clause-Patent
#include <Library/DebugLib.h>
#include <Library/ReportStatusCodeLib.h>
#include <Library/TimerLib.h>
+#include <Library/PcdLib.h>
#include <IndustryStandard/Pci.h>
diff --git a/MdeModulePkg/Bus/Pci/XhciDxe/XhciDxe.inf b/MdeModulePkg/Bus/Pci/XhciDxe/XhciDxe.inf
index 18ef87916a..4ab986a019 100644
--- a/MdeModulePkg/Bus/Pci/XhciDxe/XhciDxe.inf
+++ b/MdeModulePkg/Bus/Pci/XhciDxe/XhciDxe.inf
@@ -45,6 +45,7 @@
[Packages]
MdePkg/MdePkg.dec
+ MdeModulePkg/MdeModulePkg.dec
[LibraryClasses]
MemoryAllocationLib
@@ -56,6 +57,7 @@
DebugLib
ReportStatusCodeLib
TimerLib
+ PcdLib
[Guids]
gEfiEventExitBootServicesGuid ## SOMETIMES_CONSUMES ## Event
@@ -64,6 +66,9 @@
gEfiPciIoProtocolGuid ## TO_START
gEfiUsb2HcProtocolGuid ## BY_START
+[Pcd]
+ gEfiMdeModulePkgTokenSpaceGuid.PcdDelayXhciHCReset ## CONSUMES
+
# [Event]
# EVENT_TYPE_PERIODIC_TIMER ## CONSUMES
#
diff --git a/MdeModulePkg/Bus/Pci/XhciDxe/XhciReg.c b/MdeModulePkg/Bus/Pci/XhciDxe/XhciReg.c
index 40f2f1f227..525942a167 100644
--- a/MdeModulePkg/Bus/Pci/XhciDxe/XhciReg.c
+++ b/MdeModulePkg/Bus/Pci/XhciDxe/XhciReg.c
@@ -864,7 +864,7 @@ XhcResetHC (
// Otherwise there may have the timeout case happened.
// The below is a workaround to solve such problem.
//
- gBS->Stall (XHC_1_MILLISECOND);
+ gBS->Stall (PcdGet16 (PcdDelayXhciHCReset));
Status = XhcWaitOpRegBit (Xhc, XHC_USBCMD_OFFSET, XHC_USBCMD_RESET, FALSE, Timeout);
if (!EFI_ERROR (Status)) {
diff --git a/MdeModulePkg/Bus/Pci/XhciDxe/XhciSched.c b/MdeModulePkg/Bus/Pci/XhciDxe/XhciSched.c
index 5d735008ba..a97ed44dbf 100644
--- a/MdeModulePkg/Bus/Pci/XhciDxe/XhciSched.c
+++ b/MdeModulePkg/Bus/Pci/XhciDxe/XhciSched.c
@@ -1192,8 +1192,11 @@ XhcCheckUrbResult (
DEBUG ((DEBUG_ERROR, "XhcCheckUrbResult: ERR_BUFFER! Completecode = %x\n", EvtTrb->Completecode));
goto EXIT;
+ //
+ // Based on XHCI spec 4.8.3, software should do the reset endpoint while USB Transaction occur.
+ //
case TRB_COMPLETION_USB_TRANSACTION_ERROR:
- CheckedUrb->Result |= EFI_USB_ERR_TIMEOUT;
+ CheckedUrb->Result |= EDKII_USB_ERR_TRANSACTION;
CheckedUrb->Finished = TRUE;
DEBUG ((DEBUG_ERROR, "XhcCheckUrbResult: TRANSACTION_ERROR! Completecode = %x\n", EvtTrb->Completecode));
goto EXIT;
diff --git a/MdeModulePkg/Bus/Pci/XhciDxe/XhciSched.h b/MdeModulePkg/Bus/Pci/XhciDxe/XhciSched.h
index 7c85f7993b..e606e212a1 100644
--- a/MdeModulePkg/Bus/Pci/XhciDxe/XhciSched.h
+++ b/MdeModulePkg/Bus/Pci/XhciDxe/XhciSched.h
@@ -79,6 +79,13 @@ SPDX-License-Identifier: BSD-2-Clause-Patent
#define TRB_COMPLETION_STOPPED_LENGTH_INVALID 27
//
+// USB Transfer Results Internal Definition
+// Based on XHCI spec 4.8.3, software should do the reset endpoint while USB Transaction occur.
+// Add the error code for USB Transaction error since UEFI spec don't have the related definition.
+//
+#define EDKII_USB_ERR_TRANSACTION 0x200
+
+//
// The topology string used to present usb device location
//
typedef struct _USB_DEV_TOPOLOGY {
diff --git a/MdeModulePkg/Bus/Spi/SpiBus/SpiBus.c b/MdeModulePkg/Bus/Spi/SpiBus/SpiBus.c
new file mode 100644
index 0000000000..b183ca182c
--- /dev/null
+++ b/MdeModulePkg/Bus/Spi/SpiBus/SpiBus.c
@@ -0,0 +1,433 @@
+/** @file
+
+ SpiBus driver
+
+ Copyright (C) 2024 Advanced Micro Devices, Inc. All rights reserved.<BR>
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+#include <Library/BaseLib.h>
+#include <Library/DebugLib.h>
+#include <Library/MemoryAllocationLib.h>
+#include <Protocol/SpiConfiguration.h>
+#include <Protocol/SpiHc.h>
+#include <Protocol/SpiIo.h>
+#include "SpiBus.h"
+
+/**
+ Checks if two device paths are the same.
+
+ @param[in] DevicePath1 First device path to compare
+ @param[in] DevicePath2 Second device path to compare
+
+ @retval TRUE The device paths share the same nodes and values
+ @retval FALSE The device paths differ
+**/
+BOOLEAN
+EFIAPI
+DevicePathsAreEqual (
+ IN CONST EFI_DEVICE_PATH_PROTOCOL *DevicePath1,
+ IN CONST EFI_DEVICE_PATH_PROTOCOL *DevicePath2
+ )
+{
+ UINTN Size1;
+ UINTN Size2;
+
+ Size1 = GetDevicePathSize (DevicePath1);
+ Size2 = GetDevicePathSize (DevicePath2);
+
+ if (Size1 != Size2) {
+ return FALSE;
+ }
+
+ if (CompareMem (DevicePath1, DevicePath2, Size1) != 0) {
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+/**
+ Calls the SpiPeripherals ChipSelect if it is not null, otherwise
+ calls the Host Controllers ChipSelect function.
+
+ @param[in] SpiChip The SpiChip to place on the bus via asserting its chip select
+ @param[in] PinValue Value to place on the chip select pin
+
+ @retval EFI_SUCCESS Chip select pin was placed at requested level
+ @retval EFI_INVALID_PARAMETER Invalid parameters passed into ChipSelect function
+**/
+EFI_STATUS
+EFIAPI
+SpiChipSelect (
+ IN CONST SPI_IO_CHIP *SpiChip,
+ IN BOOLEAN PinValue
+ )
+{
+ EFI_STATUS Status;
+
+ // Check which chip select function to use
+ if (SpiChip->Protocol.SpiPeripheral->ChipSelect != NULL) {
+ Status = SpiChip->Protocol.SpiPeripheral->ChipSelect (
+ SpiChip->BusTransaction.SpiPeripheral,
+ PinValue
+ );
+ } else {
+ Status = SpiChip->SpiHc->ChipSelect (
+ SpiChip->SpiHc,
+ SpiChip->BusTransaction.SpiPeripheral,
+ PinValue
+ );
+ }
+
+ return Status;
+}
+
+/**
+ Checks the SpiChip's BusTransaction attributes to ensure its a valid SPI transaction.
+
+ @param[in] SpiChip The SpiChip where a bus transaction is requested
+
+ @retval EFI_SUCCESS This is a valid SPI bus transaction
+ @retval EFI_BAD_BUFFER_SIZE The WriteBytes value was invalid
+ @retval EFI_BAD_BUFFER_SIZE The ReadBytes value was invalid
+ @retval EFI_INVALID_PARAMETER TransactionType is not valid,
+ or BusWidth not supported by SPI peripheral or
+ SPI host controller,
+ or WriteBytes non-zero and WriteBuffer is
+ NULL,
+ or ReadBytes non-zero and ReadBuffer is NULL,
+ or ReadBuffer != WriteBuffer for full-duplex
+ type,
+ or WriteBuffer was NULL,
+ or TPL is too high
+ @retval EFI_OUT_OF_RESOURCES Insufficient memory for SPI transaction
+ @retval EFI_UNSUPPORTED The FrameSize is not supported by the SPI bus
+ layer or the SPI host controller
+ @retval EFI_UNSUPPORTED The SPI controller was not able to support
+**/
+EFI_STATUS
+EFIAPI
+IsValidSpiTransaction (
+ IN SPI_IO_CHIP *SpiChip
+ )
+{
+ // Error checking
+ if (SpiChip->BusTransaction.TransactionType > SPI_TRANSACTION_WRITE_THEN_READ) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if (((SpiChip->BusTransaction.BusWidth != 1) && (SpiChip->BusTransaction.BusWidth != 2) && (SpiChip->BusTransaction.BusWidth != 4) &&
+ (SpiChip->BusTransaction.BusWidth != 8)) || (SpiChip->BusTransaction.FrameSize == 0))
+ {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if ((SpiChip->BusTransaction.BusWidth == 8) && (((SpiChip->Protocol.Attributes & SPI_IO_SUPPORTS_8_BIT_DATA_BUS_WIDTH) != SPI_IO_SUPPORTS_8_BIT_DATA_BUS_WIDTH) ||
+ ((SpiChip->BusTransaction.SpiPeripheral->Attributes & SPI_PART_SUPPORTS_8_BIT_DATA_BUS_WIDTH) != SPI_PART_SUPPORTS_8_BIT_DATA_BUS_WIDTH)))
+ {
+ return EFI_INVALID_PARAMETER;
+ } else if ((SpiChip->BusTransaction.BusWidth == 4) && (((SpiChip->Protocol.Attributes & SPI_IO_SUPPORTS_4_BIT_DATA_BUS_WIDTH) != SPI_IO_SUPPORTS_4_BIT_DATA_BUS_WIDTH) ||
+ ((SpiChip->BusTransaction.SpiPeripheral->Attributes & SPI_PART_SUPPORTS_4_BIT_DATA_BUS_WIDTH) != SPI_PART_SUPPORTS_4_BIT_DATA_BUS_WIDTH)))
+ {
+ return EFI_INVALID_PARAMETER;
+ } else if ((SpiChip->BusTransaction.BusWidth == 2) && (((SpiChip->Protocol.Attributes & SPI_IO_SUPPORTS_4_BIT_DATA_BUS_WIDTH) != SPI_IO_SUPPORTS_4_BIT_DATA_BUS_WIDTH) ||
+ ((SpiChip->BusTransaction.SpiPeripheral->Attributes & SPI_PART_SUPPORTS_2_BIT_DATA_BUS_WIDTH) != SPI_PART_SUPPORTS_2_BIT_DATA_BUS_WIDTH)))
+ {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if (((SpiChip->BusTransaction.WriteBytes > 0) && (SpiChip->BusTransaction.WriteBuffer == NULL)) || ((SpiChip->BusTransaction.ReadBytes > 0) && (SpiChip->BusTransaction.ReadBuffer == NULL))) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if ((SpiChip->BusTransaction.TransactionType == SPI_TRANSACTION_FULL_DUPLEX) && (SpiChip->BusTransaction.ReadBytes != SpiChip->BusTransaction.WriteBytes)) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ // Check frame size, passed parameter is in bits
+ if ((SpiChip->Protocol.FrameSizeSupportMask & (1<<(SpiChip->BusTransaction.FrameSize-1))) == 0) {
+ return EFI_UNSUPPORTED;
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Initiate a SPI transaction between the host and a SPI peripheral.
+
+ This routine must be called at or below TPL_NOTIFY.
+ This routine works with the SPI bus layer to pass the SPI transaction to the
+ SPI controller for execution on the SPI bus. There are four types of
+ supported transactions supported by this routine:
+ * Full Duplex: WriteBuffer and ReadBuffer are the same size.
+ * Write Only: WriteBuffer contains data for SPI peripheral, ReadBytes = 0
+ * Read Only: ReadBuffer to receive data from SPI peripheral, WriteBytes = 0
+ * Write Then Read: WriteBuffer contains control data to write to SPI
+ peripheral before data is placed into the ReadBuffer.
+ Both WriteBytes and ReadBytes must be non-zero.
+
+ @param[in] This Pointer to an EFI_SPI_IO_PROTOCOL structure.
+ @param[in] TransactionType Type of SPI transaction.
+ @param[in] DebugTransaction Set TRUE only when debugging is desired.
+ Debugging may be turned on for a single SPI
+ transaction. Only this transaction will display
+ debugging messages. All other transactions with
+ this value set to FALSE will not display any
+ debugging messages.
+ @param[in] ClockHz Specify the ClockHz value as zero (0) to use
+ the maximum clock frequency supported by the
+ SPI controller and part. Specify a non-zero
+ value only when a specific SPI transaction
+ requires a reduced clock rate.
+ @param[in] BusWidth Width of the SPI bus in bits: 1, 2, 4
+ @param[in] FrameSize Frame size in bits, range: 1 - 32
+ @param[in] WriteBytes The length of the WriteBuffer in bytes.
+ Specify zero for read-only operations.
+ @param[in] WriteBuffer The buffer containing data to be sent from the
+ host to the SPI chip. Specify NULL for read
+ only operations.
+ * Frame sizes 1-8 bits: UINT8 (one byte) per
+ frame
+ * Frame sizes 7-16 bits: UINT16 (two bytes) per
+ frame
+ * Frame sizes 17-32 bits: UINT32 (four bytes)
+ per frame The transmit frame is in the least
+ significant N bits.
+ @param[in] ReadBytes The length of the ReadBuffer in bytes.
+ Specify zero for write-only operations.
+ @param[out] ReadBuffer The buffer to receeive data from the SPI chip
+ during the transaction. Specify NULL for write
+ only operations.
+ * Frame sizes 1-8 bits: UINT8 (one byte) per
+ frame
+ * Frame sizes 7-16 bits: UINT16 (two bytes) per
+ frame
+ * Frame sizes 17-32 bits: UINT32 (four bytes)
+ per frame The received frame is in the least
+ significant N bits.
+
+ @retval EFI_SUCCESS The SPI transaction completed successfully
+ @retval EFI_BAD_BUFFER_SIZE The WriteBytes value was invalid
+ @retval EFI_BAD_BUFFER_SIZE The ReadBytes value was invalid
+ @retval EFI_INVALID_PARAMETER TransactionType is not valid,
+ or BusWidth not supported by SPI peripheral or
+ SPI host controller,
+ or WriteBytes non-zero and WriteBuffer is
+ NULL,
+ or ReadBytes non-zero and ReadBuffer is NULL,
+ or ReadBuffer != WriteBuffer for full-duplex
+ type,
+ or WriteBuffer was NULL,
+ or TPL is too high
+ @retval EFI_OUT_OF_RESOURCES Insufficient memory for SPI transaction
+ @retval EFI_UNSUPPORTED The FrameSize is not supported by the SPI bus
+ layer or the SPI host controller
+ @retval EFI_UNSUPPORTED The SPI controller was not able to support
+
+**/
+EFI_STATUS
+EFIAPI
+Transaction (
+ IN CONST EFI_SPI_IO_PROTOCOL *This,
+ IN EFI_SPI_TRANSACTION_TYPE TransactionType,
+ IN BOOLEAN DebugTransaction,
+ IN UINT32 ClockHz OPTIONAL,
+ IN UINT32 BusWidth,
+ IN UINT32 FrameSize,
+ IN UINT32 WriteBytes,
+ IN UINT8 *WriteBuffer,
+ IN UINT32 ReadBytes,
+ OUT UINT8 *ReadBuffer
+ )
+{
+ EFI_STATUS Status;
+ SPI_IO_CHIP *SpiChip;
+ UINT32 MaxClockHz;
+ UINT8 *DummyReadBuffer;
+ UINT8 *DummyWriteBuffer;
+
+ SpiChip = SPI_IO_CHIP_FROM_THIS (This);
+ SpiChip->BusTransaction.SpiPeripheral =
+ (EFI_SPI_PERIPHERAL *)SpiChip->Protocol.SpiPeripheral;
+ SpiChip->BusTransaction.TransactionType = TransactionType;
+ SpiChip->BusTransaction.DebugTransaction = DebugTransaction;
+ SpiChip->BusTransaction.BusWidth = BusWidth;
+ SpiChip->BusTransaction.FrameSize = FrameSize;
+ SpiChip->BusTransaction.WriteBytes = WriteBytes;
+ SpiChip->BusTransaction.WriteBuffer = WriteBuffer;
+ SpiChip->BusTransaction.ReadBytes = ReadBytes;
+ SpiChip->BusTransaction.ReadBuffer = ReadBuffer;
+
+ // Ensure valid spi transaction parameters
+ Status = IsValidSpiTransaction (SpiChip);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ // Setup the proper clock frequency
+ if (SpiChip->BusTransaction.SpiPeripheral->MaxClockHz != 0) {
+ MaxClockHz = SpiChip->BusTransaction.SpiPeripheral->MaxClockHz;
+ } else {
+ MaxClockHz = SpiChip->BusTransaction.SpiPeripheral->SpiPart->MaxClockHz;
+ }
+
+ // Call proper clock function
+ if (SpiChip->Protocol.SpiPeripheral->SpiBus->Clock != NULL) {
+ Status = SpiChip->Protocol.SpiPeripheral->SpiBus->Clock (
+ SpiChip->BusTransaction.SpiPeripheral,
+ &MaxClockHz
+ );
+ } else {
+ Status = SpiChip->SpiHc->Clock (
+ SpiChip->SpiHc,
+ SpiChip->BusTransaction.SpiPeripheral,
+ &MaxClockHz
+ );
+ }
+
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ Status = SpiChipSelect (SpiChip, SpiChip->BusTransaction.SpiPeripheral->SpiPart->ChipSelectPolarity);
+
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ // Check transaction types and match to HC capabilities
+ if ((TransactionType == SPI_TRANSACTION_WRITE_ONLY) &&
+ ((SpiChip->SpiHc->Attributes & HC_SUPPORTS_WRITE_ONLY_OPERATIONS) != HC_SUPPORTS_WRITE_ONLY_OPERATIONS))
+ {
+ // Convert to full duplex transaction
+ SpiChip->BusTransaction.ReadBytes = SpiChip->BusTransaction.WriteBytes;
+ SpiChip->BusTransaction.ReadBuffer = AllocateZeroPool (SpiChip->BusTransaction.ReadBytes);
+
+ Status = SpiChip->SpiHc->Transaction (
+ SpiChip->SpiHc,
+ &SpiChip->BusTransaction
+ );
+
+ SpiChip->BusTransaction.ReadBytes = ReadBytes; // assign to passed parameter
+ FreePool (SpiChip->BusTransaction.ReadBuffer); // Free temporary buffer
+ } else if ((TransactionType == SPI_TRANSACTION_READ_ONLY) &&
+ ((SpiChip->SpiHc->Attributes & HC_SUPPORTS_READ_ONLY_OPERATIONS) != HC_SUPPORTS_READ_ONLY_OPERATIONS))
+ {
+ // Convert to full duplex transaction
+ SpiChip->BusTransaction.WriteBytes = SpiChip->BusTransaction.WriteBytes;
+ SpiChip->BusTransaction.WriteBuffer = AllocateZeroPool (SpiChip->BusTransaction.WriteBytes);
+
+ Status = SpiChip->SpiHc->Transaction (
+ SpiChip->SpiHc,
+ &SpiChip->BusTransaction
+ );
+
+ SpiChip->BusTransaction.WriteBytes = WriteBytes;
+ FreePool (SpiChip->BusTransaction.WriteBuffer);
+ } else if ((TransactionType == SPI_TRANSACTION_WRITE_THEN_READ) &&
+ ((SpiChip->SpiHc->Attributes & HC_SUPPORTS_WRITE_THEN_READ_OPERATIONS) != HC_SUPPORTS_WRITE_THEN_READ_OPERATIONS))
+ {
+ // Convert to full duplex transaction
+ DummyReadBuffer = AllocateZeroPool (WriteBytes);
+ DummyWriteBuffer = AllocateZeroPool (ReadBytes);
+ SpiChip->BusTransaction.ReadBuffer = DummyReadBuffer;
+ SpiChip->BusTransaction.ReadBytes = WriteBytes;
+
+ Status = SpiChip->SpiHc->Transaction (
+ SpiChip->SpiHc,
+ &SpiChip->BusTransaction
+ );
+
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ // Write is done, now need to read, restore passed in read buffer info
+ SpiChip->BusTransaction.ReadBuffer = ReadBuffer;
+ SpiChip->BusTransaction.ReadBytes = ReadBytes;
+
+ SpiChip->BusTransaction.WriteBuffer = DummyWriteBuffer;
+ SpiChip->BusTransaction.WriteBytes = ReadBytes;
+
+ Status = SpiChip->SpiHc->Transaction (
+ SpiChip->SpiHc,
+ &SpiChip->BusTransaction
+ );
+ // Restore write data
+ SpiChip->BusTransaction.WriteBuffer = WriteBuffer;
+ SpiChip->BusTransaction.WriteBytes = WriteBytes;
+
+ FreePool (DummyReadBuffer);
+ FreePool (DummyWriteBuffer);
+ } else {
+ // Supported transaction type, just pass info the SPI HC Protocol Transaction
+ Status = SpiChip->SpiHc->Transaction (
+ SpiChip->SpiHc,
+ &SpiChip->BusTransaction
+ );
+ }
+
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ Status = SpiChipSelect (SpiChip, !SpiChip->BusTransaction.SpiPeripheral->SpiPart->ChipSelectPolarity);
+
+ return Status;
+}
+
+/**
+ Update the SPI peripheral associated with this SPI 10 SpiChip.
+
+ Support socketed SPI parts by allowing the SPI peripheral driver to replace
+ the SPI peripheral after the connection is made. An example use is socketed
+ SPI NOR flash parts, where the size and parameters change depending upon
+ device is in the socket.
+
+ @param[in] This Pointer to an EFI_SPI_IO_PROTOCOL structure.
+ @param[in] SpiPeripheral Pointer to an EFI_SPI_PERIPHERAL structure.
+
+ @retval EFI_SUCCESS The SPI peripheral was updated successfully
+ @retval EFI_INVALID_PARAMETER The SpiPeripheral value is NULL,
+ or the SpiPeripheral->SpiBus is NULL,
+ or the SpiPeripheral->SpiBus pointing at
+ wrong bus, or the SpiPeripheral->SpiPart is NULL
+**/
+EFI_STATUS
+EFIAPI
+UpdateSpiPeripheral (
+ IN CONST EFI_SPI_IO_PROTOCOL *This,
+ IN CONST EFI_SPI_PERIPHERAL *SpiPeripheral
+ )
+{
+ EFI_STATUS Status;
+ SPI_IO_CHIP *SpiChip;
+
+ DEBUG ((DEBUG_VERBOSE, "%a: SPI Bus - Entry\n", __func__));
+
+ SpiChip = SPI_IO_CHIP_FROM_THIS (This);
+
+ if ((SpiPeripheral == NULL) || (SpiPeripheral->SpiBus == NULL) ||
+ (SpiPeripheral->SpiPart == NULL))
+ {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ // EFI_INVALID_PARAMETER if SpiPeripheral->SpiBus is pointing at wrong bus
+ if (!DevicePathsAreEqual (SpiPeripheral->SpiBus->ControllerPath, SpiChip->SpiBus->ControllerPath)) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ SpiChip->Protocol.OriginalSpiPeripheral = SpiChip->Protocol.SpiPeripheral;
+ SpiChip->Protocol.SpiPeripheral = SpiPeripheral;
+
+ Status = EFI_SUCCESS;
+ DEBUG ((
+ DEBUG_VERBOSE,
+ "%a: SPI Bus - Exit Status=%r\n",
+ __func__,
+ Status
+ ));
+ return Status;
+}
diff --git a/MdeModulePkg/Bus/Spi/SpiBus/SpiBus.h b/MdeModulePkg/Bus/Spi/SpiBus/SpiBus.h
new file mode 100644
index 0000000000..7a43f66ac7
--- /dev/null
+++ b/MdeModulePkg/Bus/Spi/SpiBus/SpiBus.h
@@ -0,0 +1,167 @@
+/** @file
+
+ SPI bus driver
+
+ Copyright (C) 2024 Advanced Micro Devices, Inc. All rights reserved.<BR>
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#ifndef SPI_BUS_H_
+#define SPI_BUS_H_
+
+#include <PiDxe.h>
+#include <Library/BaseLib.h>
+#include <Protocol/DevicePath.h>
+#include <Library/DevicePathLib.h>
+#include <Library/BaseMemoryLib.h>
+#include <Protocol/SpiIo.h>
+#include <Protocol/SpiHc.h>
+#include <Protocol/SpiConfiguration.h>
+
+#define SPI_IO_SIGNATURE SIGNATURE_32 ('s', 'i', 'o', 'c')
+
+typedef struct {
+ UINTN Signature;
+ EFI_HANDLE Handle;
+ EFI_SPI_IO_PROTOCOL Protocol;
+ EFI_SPI_BUS_TRANSACTION BusTransaction;
+ EFI_SPI_CONFIGURATION_PROTOCOL *SpiConfig;
+ EFI_SPI_HC_PROTOCOL *SpiHc;
+ EFI_SPI_BUS *SpiBus;
+} SPI_IO_CHIP;
+
+#define SPI_IO_CHIP_FROM_THIS(a) \
+ CR (a, SPI_IO_CHIP, Protocol, \
+ SPI_IO_SIGNATURE)
+
+/**
+ Checks if two device paths are the same
+
+ @param[in] DevicePath1 First device path to compare
+ @param[in] DevicePath2 Second device path to compare
+
+ @retval TRUE The device paths share the same nodes and values
+ @retval FALSE The device paths differ
+**/
+BOOLEAN
+EFIAPI
+DevicePathsAreEqual (
+ IN CONST EFI_DEVICE_PATH_PROTOCOL *DevicePath1,
+ IN CONST EFI_DEVICE_PATH_PROTOCOL *DevicePath2
+ );
+
+/**
+ Initiate a SPI transaction between the host and a SPI peripheral.
+
+ This routine must be called at or below TPL_NOTIFY.
+ This routine works with the SPI bus layer to pass the SPI transaction to the
+ SPI controller for execution on the SPI bus. There are four types of
+ supported transactions supported by this routine:
+ * Full Duplex: WriteBuffer and ReadBuffer are the same size.
+ * Write Only: WriteBuffer contains data for SPI peripheral, ReadBytes = 0
+ * Read Only: ReadBuffer to receive data from SPI peripheral, WriteBytes = 0
+ * Write Then Read: WriteBuffer contains control data to write to SPI
+ peripheral before data is placed into the ReadBuffer.
+ Both WriteBytes and ReadBytes must be non-zero.
+
+ @param[in] This Pointer to an EFI_SPI_IO_PROTOCOL structure.
+ @param[in] TransactionType Type of SPI transaction.
+ @param[in] DebugTransaction Set TRUE only when debugging is desired.
+ Debugging may be turned on for a single SPI
+ transaction. Only this transaction will display
+ debugging messages. All other transactions with
+ this value set to FALSE will not display any
+ debugging messages.
+ @param[in] ClockHz Specify the ClockHz value as zero (0) to use
+ the maximum clock frequency supported by the
+ SPI controller and part. Specify a non-zero
+ value only when a specific SPI transaction
+ requires a reduced clock rate.
+ @param[in] BusWidth Width of the SPI bus in bits: 1, 2, 4
+ @param[in] FrameSize Frame size in bits, range: 1 - 32
+ @param[in] WriteBytes The length of the WriteBuffer in bytes.
+ Specify zero for read-only operations.
+ @param[in] WriteBuffer The buffer containing data to be sent from the
+ host to the SPI chip. Specify NULL for read
+ only operations.
+ * Frame sizes 1-8 bits: UINT8 (one byte) per
+ frame
+ * Frame sizes 7-16 bits: UINT16 (two bytes) per
+ frame
+ * Frame sizes 17-32 bits: UINT32 (four bytes)
+ per frame The transmit frame is in the least
+ significant N bits.
+ @param[in] ReadBytes The length of the ReadBuffer in bytes.
+ Specify zero for write-only operations.
+ @param[out] ReadBuffer The buffer to receeive data from the SPI chip
+ during the transaction. Specify NULL for write
+ only operations.
+ * Frame sizes 1-8 bits: UINT8 (one byte) per
+ frame
+ * Frame sizes 7-16 bits: UINT16 (two bytes) per
+ frame
+ * Frame sizes 17-32 bits: UINT32 (four bytes)
+ per frame The received frame is in the least
+ significant N bits.
+
+ @retval EFI_SUCCESS The SPI transaction completed successfully
+ @retval EFI_BAD_BUFFER_SIZE The writeBytes value was invalid
+ @retval EFI_BAD_BUFFER_SIZE The ReadBytes value was invalid
+ @retval EFI_INVALID_PARAMETER TransactionType is not valid,
+ or BusWidth not supported by SPI peripheral or
+ SPI host controller,
+ or WriteBytes non-zero and WriteBuffer is
+ NULL,
+ or ReadBytes non-zero and ReadBuffer is NULL,
+ or ReadBuffer != WriteBuffer for full-duplex
+ type,
+ or WriteBuffer was NULL,
+ or TPL is too high
+ @retval EFI_OUT_OF_RESOURCES Insufficient memory for SPI transaction
+ @retval EFI_UNSUPPORTED The FrameSize is not supported by the SPI bus
+ layer or the SPI host controller
+ @retval EFI_UNSUPPORTED The SPI controller was not able to support
+
+**/
+EFI_STATUS
+EFIAPI
+Transaction (
+ IN CONST EFI_SPI_IO_PROTOCOL *This,
+ IN EFI_SPI_TRANSACTION_TYPE TransactionType,
+ IN BOOLEAN DebugTransaction,
+ IN UINT32 ClockHz OPTIONAL,
+ IN UINT32 BusWidth,
+ IN UINT32 FrameSize,
+ IN UINT32 WriteBytes,
+ IN UINT8 *WriteBuffer,
+ IN UINT32 ReadBytes,
+ OUT UINT8 *ReadBuffer
+ );
+
+/**
+ Update the SPI peripheral associated with this SPI 10 instance.
+
+ Support socketed SPI parts by allowing the SPI peripheral driver to replace
+ the SPI peripheral after the connection is made. An example use is socketed
+ SPI NOR flash parts, where the size and parameters change depending upon
+ device is in the socket.
+
+ @param[in] This Pointer to an EFI_SPI_IO_PROTOCOL structure.
+ @param[in] SpiPeripheral Pointer to an EFI_SPI_PERIPHERAL structure.
+
+ @retval EFI_SUCCESS The SPI peripheral was updated successfully
+ @retval EFI_INVALID_PARAMETER The SpiPeripheral value is NULL,
+ or the SpiPeripheral->SpiBus is NULL,
+ or the SpiPeripheral->SpiBus pointing at
+ wrong bus, or the SpiPeripheral->SpiPart is NULL
+
+**/
+EFI_STATUS
+EFIAPI
+UpdateSpiPeripheral (
+ IN CONST EFI_SPI_IO_PROTOCOL *This,
+ IN CONST EFI_SPI_PERIPHERAL *SpiPeripheral
+ );
+
+#endif //SPI_BUS_H_
diff --git a/MdeModulePkg/Bus/Spi/SpiBus/SpiBus.uni b/MdeModulePkg/Bus/Spi/SpiBus/SpiBus.uni
new file mode 100644
index 0000000000..0d913bdbae
--- /dev/null
+++ b/MdeModulePkg/Bus/Spi/SpiBus/SpiBus.uni
@@ -0,0 +1,10 @@
+// /** @file
+//
+// Copyright (C) 2024 Advanced Micro Devices, Inc. All rights reserved.<BR>
+//
+// SPDX-License-Identifier: BSD-2-Clause-Patent
+//
+// **/
+
+#string STR_PROPERTIES_MODULE_NAME
+#language en-US "SPI Bus driver"
diff --git a/MdeModulePkg/Bus/Spi/SpiBus/SpiBusDxe.c b/MdeModulePkg/Bus/Spi/SpiBus/SpiBusDxe.c
new file mode 100644
index 0000000000..cd0a2c99a2
--- /dev/null
+++ b/MdeModulePkg/Bus/Spi/SpiBus/SpiBusDxe.c
@@ -0,0 +1,198 @@
+/** @file
+
+ SPI bus DXE driver
+
+ Copyright (C) 2024 Advanced Micro Devices, Inc. All rights reserved.<BR>
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+#include <Base.h>
+#include <Library/BaseLib.h>
+#include <Library/DebugLib.h>
+#include <Library/MemoryAllocationLib.h>
+#include <Library/UefiBootServicesTableLib.h>
+#include <Protocol/SpiConfiguration.h>
+#include <Protocol/SpiHc.h>
+#include <Protocol/SpiIo.h>
+#include "SpiBus.h"
+
+/**
+ Entry point of the Spi Bus layer
+
+ @param[in] ImageHandle Image handle of this driver.
+ @param[in] SystemTable Pointer to standard EFI system table.
+
+ @retval EFI_SUCCESS Succeed.
+ @retval EFI_DEVICE_ERROR SpiPeripheral is NULL.
+ @retval EFI_NOT_FOUND Fail to locate SpiHcProtocol or SpiIoConfigurationProtocol
+ @retval EFI_OUT_OF_RESOURCES Failed to allocate SpiIoChip
+**/
+EFI_STATUS
+EFIAPI
+SpiBusEntry (
+ IN EFI_HANDLE ImageHandle,
+ IN EFI_SYSTEM_TABLE *SystemTable
+ )
+{
+ EFI_STATUS Status;
+ SPI_IO_CHIP *SpiChip;
+ EFI_SPI_HC_PROTOCOL *SpiHc;
+ EFI_SPI_CONFIGURATION_PROTOCOL *SpiConfiguration;
+ EFI_SPI_PERIPHERAL *SpiPeripheral;
+ EFI_SPI_BUS *Bus;
+ UINTN BusIndex;
+ UINTN HcIndex;
+ EFI_HANDLE *SpiHcHandles;
+ UINTN HandleCount;
+ EFI_DEVICE_PATH_PROTOCOL *SpiHcDevicePath;
+
+ DEBUG ((DEBUG_VERBOSE, "%a - ENTRY\n", __func__));
+
+ // Get all SPI HC protocols, could be multiple SPI HC's on a single platform
+ Status = gBS->LocateHandleBuffer (
+ ByProtocol,
+ &gEfiSpiHcProtocolGuid,
+ NULL,
+ &HandleCount,
+ &SpiHcHandles
+ );
+
+ if (EFI_ERROR (Status)) {
+ DEBUG ((DEBUG_VERBOSE, "No SpiHcProtocol is found\n"));
+ Status = EFI_NOT_FOUND;
+ goto Exit;
+ }
+
+ // Locate the SPI Configuration Protocol
+ Status = gBS->LocateProtocol (
+ &gEfiSpiConfigurationProtocolGuid,
+ NULL,
+ (VOID **)&SpiConfiguration
+ );
+
+ if (EFI_ERROR (Status)) {
+ DEBUG ((DEBUG_VERBOSE, "No SpiConfigurationProtocol is found\n"));
+ Status = EFI_NOT_FOUND;
+ goto Exit;
+ }
+
+ // Parse through Hc protocols, find correct device path
+ for (HcIndex = 0; HcIndex < HandleCount; HcIndex++) {
+ Status = gBS->HandleProtocol (
+ SpiHcHandles[HcIndex],
+ &gEfiDevicePathProtocolGuid,
+ (VOID **)&SpiHcDevicePath
+ );
+
+ if (EFI_ERROR (Status)) {
+ DEBUG ((DEBUG_VERBOSE, "Error locating EFI device path for this SPI controller, status=%r \n", Status));
+ continue; // Continue searching
+ }
+
+ // Parse through SpiConfiguration's SpiBuses, find matching devicepath for SpiHc
+ for (BusIndex = 0; BusIndex < SpiConfiguration->BusCount; BusIndex++) {
+ Bus = (EFI_SPI_BUS *)SpiConfiguration->Buslist[BusIndex];
+ if (!DevicePathsAreEqual (SpiHcDevicePath, Bus->ControllerPath)) {
+ DEBUG ((DEBUG_VERBOSE, "SpiHc and SpiConfig device paths dont match, continue parsing\n"));
+ continue;
+ }
+
+ DEBUG ((
+ DEBUG_VERBOSE,
+ "%a: Found matching device paths, Enumerating SPI BUS: %s with DevicePath: %s\n",
+ __func__,
+ Bus->FriendlyName,
+ ConvertDevicePathToText (SpiHcDevicePath, FALSE, FALSE)
+ ));
+
+ // Get SpiHc from the SpiHcHandles
+ Status = gBS->HandleProtocol (
+ SpiHcHandles[HcIndex],
+ &gEfiDevicePathProtocolGuid,
+ (VOID **)&SpiHc
+ );
+
+ if (EFI_ERROR (Status)) {
+ DEBUG ((DEBUG_VERBOSE, "%a - Error getting SpiHc from Handle\n", __func__));
+ goto Exit;
+ }
+
+ SpiPeripheral = (EFI_SPI_PERIPHERAL *)Bus->Peripherallist;
+ if (SpiPeripheral != NULL) {
+ do {
+ DEBUG ((
+ DEBUG_VERBOSE,
+ "%a: Installing SPI IO protocol for %s, by %s, PN=%s\n",
+ __func__,
+ SpiPeripheral->FriendlyName,
+ SpiPeripheral->SpiPart->Vendor,
+ SpiPeripheral->SpiPart->PartNumber
+ ));
+ // Allocate the SPI IO Device
+ SpiChip = AllocateZeroPool (sizeof (SPI_IO_CHIP));
+ ASSERT (SpiChip != NULL);
+ if (SpiChip != NULL) {
+ // Fill in the SpiChip
+ SpiChip->Signature = SPI_IO_SIGNATURE;
+ SpiChip->SpiConfig = SpiConfiguration;
+ SpiChip->SpiHc = SpiHc;
+ SpiChip->SpiBus = Bus;
+ SpiChip->Protocol.SpiPeripheral = SpiPeripheral;
+ SpiChip->Protocol.OriginalSpiPeripheral = SpiPeripheral;
+ SpiChip->Protocol.FrameSizeSupportMask = SpiHc->FrameSizeSupportMask;
+ SpiChip->Protocol.MaximumTransferBytes = SpiHc->MaximumTransferBytes;
+ if ((SpiHc->Attributes & HC_TRANSFER_SIZE_INCLUDES_ADDRESS) != 0) {
+ SpiChip->Protocol.Attributes |= SPI_IO_TRANSFER_SIZE_INCLUDES_ADDRESS;
+ }
+
+ if ((SpiHc->Attributes & HC_TRANSFER_SIZE_INCLUDES_OPCODE) != 0) {
+ SpiChip->Protocol.Attributes |= SPI_IO_TRANSFER_SIZE_INCLUDES_OPCODE;
+ }
+
+ if ((SpiHc->Attributes & HC_SUPPORTS_8_BIT_DATA_BUS_WIDTH) != 0) {
+ SpiChip->Protocol.Attributes |= SPI_IO_SUPPORTS_8_BIT_DATA_BUS_WIDTH;
+ }
+
+ if ((SpiHc->Attributes & HC_SUPPORTS_4_BIT_DATA_BUS_WIDTH) != 0) {
+ SpiChip->Protocol.Attributes |= SPI_IO_SUPPORTS_4_BIT_DATA_BUS_WIDTH;
+ }
+
+ if ((SpiHc->Attributes & HC_SUPPORTS_2_BIT_DATA_BUS_WIDTH) != 0) {
+ SpiChip->Protocol.Attributes |= SPI_IO_SUPPORTS_2_BIT_DATA_BUS_WIDTH;
+ }
+
+ SpiChip->Protocol.Transaction = Transaction;
+ SpiChip->Protocol.UpdateSpiPeripheral = UpdateSpiPeripheral;
+ // Install the SPI IO Protocol
+ Status = gBS->InstallProtocolInterface (
+ &SpiChip->Handle,
+ (GUID *)SpiPeripheral->SpiPeripheralDriverGuid,
+ EFI_NATIVE_INTERFACE,
+ &SpiChip->Protocol
+ );
+ if (EFI_ERROR (Status)) {
+ DEBUG ((DEBUG_VERBOSE, "%a - Error installing SpiIoProtocol\n", __func__));
+ continue;
+ }
+ } else {
+ Status = EFI_OUT_OF_RESOURCES;
+ DEBUG ((
+ DEBUG_ERROR,
+ "%a: Out of Memory resources\n",
+ __func__
+ ));
+ break;
+ }
+
+ SpiPeripheral = (EFI_SPI_PERIPHERAL *)SpiPeripheral->NextSpiPeripheral;
+ } while (SpiPeripheral != NULL);
+ } else {
+ Status = EFI_DEVICE_ERROR;
+ }
+ }
+ }
+
+Exit:
+ DEBUG ((DEBUG_VERBOSE, "%a - EXIT (Status = %r)\n", __func__, Status));
+ return Status;
+}
diff --git a/MdeModulePkg/Bus/Spi/SpiBus/SpiBusDxe.inf b/MdeModulePkg/Bus/Spi/SpiBus/SpiBusDxe.inf
new file mode 100644
index 0000000000..3e2cc2daba
--- /dev/null
+++ b/MdeModulePkg/Bus/Spi/SpiBus/SpiBusDxe.inf
@@ -0,0 +1,41 @@
+## @file
+# Component description for the SPI BUS DXE module
+#
+# Copyright (C) 2024 Advanced Micro Devices, Inc. All rights reserved.<BR>
+# SPDX-License-Identifier: BSD-2-Clause-Patent
+#
+##
+[Defines]
+ INF_VERSION = 1.27
+ BASE_NAME = SpiBusDxe
+ FILE_GUID = 25CE038C-5C3A-4A9B-A111-90DF5897E058
+ MODULE_TYPE = DXE_DRIVER
+ VERSION_STRING = 0.1
+ PI_SPECIFICATION_VERSION = 0x0001000A
+ ENTRY_POINT = SpiBusEntry
+
+[Packages]
+ MdePkg/MdePkg.dec
+
+[LibraryClasses]
+ DebugLib
+ DevicePathLib
+ MemoryAllocationLib
+ UefiBootServicesTableLib
+ UefiDriverEntryPoint
+
+[Sources]
+ SpiBusDxe.c
+ SpiBus.c
+ SpiBus.h
+
+[Protocols]
+ gEfiSpiConfigurationProtocolGuid ## CONSUMES
+ gEfiSpiHcProtocolGuid ## CONSUMES
+
+[Depex]
+ gEfiSpiConfigurationProtocolGuid AND
+ gEfiSpiHcProtocolGuid
+
+[UserExtensions.TianoCore."ExtraFiles"]
+ SpiBus.uni
diff --git a/MdeModulePkg/Bus/Spi/SpiBus/SpiBusSmm.c b/MdeModulePkg/Bus/Spi/SpiBus/SpiBusSmm.c
new file mode 100644
index 0000000000..d9189b9848
--- /dev/null
+++ b/MdeModulePkg/Bus/Spi/SpiBus/SpiBusSmm.c
@@ -0,0 +1,162 @@
+/** @file
+
+ SPI bus SMM driver
+
+ Copyright (C) 2024 Advanced Micro Devices, Inc. All rights reserved.<BR>
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+#include <Base.h>
+#include <Library/BaseLib.h>
+#include <Library/DebugLib.h>
+#include <Library/MemoryAllocationLib.h>
+#include <Library/MmServicesTableLib.h>
+#include <Protocol/SpiSmmConfiguration.h>
+#include <Protocol/SpiSmmHc.h>
+#include <Protocol/SpiIo.h>
+#include "SpiBus.h"
+
+/**
+ Entry point of the Spi Bus layer
+
+ @param[in] ImageHandle Image handle of this driver.
+ @param[in] SystemTable Pointer to standard EFI system table.
+
+ @retval EFI_SUCCESS Succeed.
+ @retval EFI_DEVICE_ERROR Fail to install EFI_SPI_HC_PROTOCOL protocol.
+ @retval EFI_NOT_FOUND fail to locate SpiHcProtocol or SpiIoConfigurationProtocol
+ @retval EFI_OUT_OF_RESOURCES Failed to allocate SpiIoChip
+**/
+EFI_STATUS
+EFIAPI
+SpiBusEntry (
+ IN EFI_HANDLE ImageHandle,
+ IN EFI_SYSTEM_TABLE *SystemTable
+ )
+{
+ EFI_STATUS Status;
+ SPI_IO_CHIP *SpiChip;
+ EFI_SPI_HC_PROTOCOL *SpiHc;
+ EFI_SPI_CONFIGURATION_PROTOCOL *SpiConfiguration;
+ EFI_SPI_PERIPHERAL *SpiPeripheral;
+ EFI_SPI_BUS *Bus;
+
+ DEBUG ((DEBUG_VERBOSE, "%a - ENTRY\n", __func__));
+
+ // Only a single Spi HC protocol in SMM
+ Status = gMmst->MmLocateProtocol (
+ &gEfiSpiSmmHcProtocolGuid,
+ NULL,
+ (VOID **)&SpiHc
+ );
+
+ if (EFI_ERROR (Status)) {
+ DEBUG ((DEBUG_VERBOSE, "No SpiHcProtocol is found\n"));
+ Status = EFI_NOT_FOUND;
+ goto Exit;
+ }
+
+ // Locate the SPI Configuration Protocol
+ Status = gMmst->MmLocateProtocol (
+ &gEfiSpiSmmConfigurationProtocolGuid,
+ NULL,
+ (VOID **)&SpiConfiguration
+ );
+
+ if (EFI_ERROR (Status)) {
+ DEBUG ((DEBUG_VERBOSE, "No SpiConfigurationProtocol is found\n"));
+ Status = EFI_NOT_FOUND;
+ goto Exit;
+ }
+
+ // Only one SpiBus supported in SMM
+ if (SpiConfiguration->BusCount != 1) {
+ DEBUG ((DEBUG_VERBOSE, "Only one SPI Bus supported in SMM\n"));
+ Status = EFI_UNSUPPORTED;
+ goto Exit;
+ }
+
+ Bus = (EFI_SPI_BUS *)SpiConfiguration->Buslist[0];
+
+ if (EFI_ERROR (Status)) {
+ DEBUG ((DEBUG_VERBOSE, "%a - Error getting SpiHc from Handle\n", __func__));
+ goto Exit;
+ }
+
+ SpiPeripheral = (EFI_SPI_PERIPHERAL *)Bus->Peripherallist;
+ if (SpiPeripheral != NULL) {
+ do {
+ DEBUG ((
+ DEBUG_VERBOSE,
+ "%a: Installing SPI IO protocol for %s, by %s, PN=%s\n",
+ __func__,
+ SpiPeripheral->FriendlyName,
+ SpiPeripheral->SpiPart->Vendor,
+ SpiPeripheral->SpiPart->PartNumber
+ ));
+ // Allocate the SPI IO Device
+ SpiChip = AllocateZeroPool (sizeof (SPI_IO_CHIP));
+ ASSERT (SpiChip != NULL);
+ if (SpiChip != NULL) {
+ // Fill in the SpiChip
+ SpiChip->Signature = SPI_IO_SIGNATURE;
+ SpiChip->SpiConfig = SpiConfiguration;
+ SpiChip->SpiHc = SpiHc;
+ SpiChip->SpiBus = Bus;
+ SpiChip->Protocol.SpiPeripheral = SpiPeripheral;
+ SpiChip->Protocol.OriginalSpiPeripheral = SpiPeripheral;
+ SpiChip->Protocol.FrameSizeSupportMask = SpiHc->FrameSizeSupportMask;
+ SpiChip->Protocol.MaximumTransferBytes = SpiHc->MaximumTransferBytes;
+ if ((SpiHc->Attributes & HC_TRANSFER_SIZE_INCLUDES_ADDRESS) != 0) {
+ SpiChip->Protocol.Attributes |= SPI_IO_TRANSFER_SIZE_INCLUDES_ADDRESS;
+ }
+
+ if ((SpiHc->Attributes & HC_TRANSFER_SIZE_INCLUDES_OPCODE) != 0) {
+ SpiChip->Protocol.Attributes |= SPI_IO_TRANSFER_SIZE_INCLUDES_OPCODE;
+ }
+
+ if ((SpiHc->Attributes & HC_SUPPORTS_8_BIT_DATA_BUS_WIDTH) != 0) {
+ SpiChip->Protocol.Attributes |= SPI_IO_SUPPORTS_8_BIT_DATA_BUS_WIDTH;
+ }
+
+ if ((SpiHc->Attributes & HC_SUPPORTS_4_BIT_DATA_BUS_WIDTH) != 0) {
+ SpiChip->Protocol.Attributes |= SPI_IO_SUPPORTS_4_BIT_DATA_BUS_WIDTH;
+ }
+
+ if ((SpiHc->Attributes & HC_SUPPORTS_2_BIT_DATA_BUS_WIDTH) != 0) {
+ SpiChip->Protocol.Attributes |= SPI_IO_SUPPORTS_2_BIT_DATA_BUS_WIDTH;
+ }
+
+ SpiChip->Protocol.Transaction = Transaction;
+ SpiChip->Protocol.UpdateSpiPeripheral = UpdateSpiPeripheral;
+ // Install the SPI IO Protocol
+ Status = gMmst->MmInstallProtocolInterface (
+ &SpiChip->Handle,
+ (GUID *)SpiPeripheral->SpiPeripheralDriverGuid,
+ EFI_NATIVE_INTERFACE,
+ &SpiChip->Protocol
+ );
+ if (EFI_ERROR (Status)) {
+ DEBUG ((DEBUG_VERBOSE, "%a - Error installing SpiIoProtocol\n", __func__));
+ continue;
+ }
+ } else {
+ Status = EFI_OUT_OF_RESOURCES;
+ DEBUG ((
+ DEBUG_ERROR,
+ "%a: Out of Memory resources\n",
+ __func__
+ ));
+ break;
+ }
+
+ SpiPeripheral = (EFI_SPI_PERIPHERAL *)SpiPeripheral->NextSpiPeripheral;
+ } while (SpiPeripheral != NULL);
+ } else {
+ Status = EFI_DEVICE_ERROR;
+ }
+
+Exit:
+ DEBUG ((DEBUG_VERBOSE, "%a - EXIT (Status = %r)\n", __func__, Status));
+ return Status;
+}
diff --git a/MdeModulePkg/Bus/Spi/SpiBus/SpiBusSmm.inf b/MdeModulePkg/Bus/Spi/SpiBus/SpiBusSmm.inf
new file mode 100644
index 0000000000..9e3a5aae7d
--- /dev/null
+++ b/MdeModulePkg/Bus/Spi/SpiBus/SpiBusSmm.inf
@@ -0,0 +1,41 @@
+## @file
+# Component description for the SPI BUS SMM module
+#
+# Copyright (C) 2024 Advanced Micro Devices, Inc. All rights reserved.<BR>
+# SPDX-License-Identifier: BSD-2-Clause-Patent
+#
+##
+[Defines]
+ INF_VERSION = 1.27
+ BASE_NAME = SpiBusSmm
+ FILE_GUID = 5DBB52E1-3D78-4C9C-A9D7-A43E79E93AC0
+ MODULE_TYPE = DXE_SMM_DRIVER
+ VERSION_STRING = 0.1
+ PI_SPECIFICATION_VERSION = 0x0001000A
+ ENTRY_POINT = SpiBusEntry
+
+[Packages]
+ MdePkg/MdePkg.dec
+
+[LibraryClasses]
+ DebugLib
+ DevicePathLib
+ MemoryAllocationLib
+ MmServicesTableLib
+ UefiDriverEntryPoint
+
+[Sources]
+ SpiBus.h
+ SpiBus.c
+ SpiBusSmm.c
+
+[Protocols]
+ gEfiSpiSmmConfigurationProtocolGuid ## CONSUMES
+ gEfiSpiSmmHcProtocolGuid ## CONSUMES
+
+[Depex]
+ gEfiSpiSmmConfigurationProtocolGuid AND
+ gEfiSpiSmmHcProtocolGuid
+
+[UserExtensions.TianoCore."ExtraFiles"]
+ SpiBus.uni
diff --git a/MdeModulePkg/Bus/Spi/SpiHc/SpiHc.c b/MdeModulePkg/Bus/Spi/SpiHc/SpiHc.c
new file mode 100644
index 0000000000..9d7bf9f542
--- /dev/null
+++ b/MdeModulePkg/Bus/Spi/SpiHc/SpiHc.c
@@ -0,0 +1,115 @@
+/** @file
+
+ SPI Host Controller shell implementation, as host controller code is platform
+ specfic.
+
+ Copyright (C) 2024 Advanced Micro Devices, Inc. All rights reserved.<BR>
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+#include "SpiHc.h"
+
+/**
+ Assert or deassert the SPI chip select.
+
+ This routine is called at TPL_NOTIFY.
+ Update the value of the chip select line for a SPI peripheral. The SPI bus
+ layer calls this routine either in the board layer or in the SPI controller
+ to manipulate the chip select pin at the start and end of a SPI transaction.
+
+ @param[in] This Pointer to an EFI_SPI_HC_PROTOCOL structure.
+ @param[in] SpiPeripheral The address of an EFI_SPI_PERIPHERAL data structure
+ describing the SPI peripheral whose chip select pin
+ is to be manipulated. The routine may access the
+ ChipSelectParameter field to gain sufficient
+ context to complete the operati on.
+ @param[in] PinValue The value to be applied to the chip select line of
+ the SPI peripheral.
+
+ @retval EFI_SUCCESS The chip select was set as requested
+ @retval EFI_NOT_READY Support for the chip select is not properly
+ initialized
+ @retval EFI_INVALID_PARAMETER The ChipSeLect value or its contents are
+ invalid
+
+**/
+EFI_STATUS
+EFIAPI
+ChipSelect (
+ IN CONST EFI_SPI_HC_PROTOCOL *This,
+ IN CONST EFI_SPI_PERIPHERAL *SpiPeripheral,
+ IN BOOLEAN PinValue
+ )
+{
+ return PlatformSpiHcChipSelect (This, SpiPeripheral, PinValue);
+}
+
+/**
+ Set up the clock generator to produce the correct clock frequency, phase and
+ polarity for a SPI chip.
+
+ This routine is called at TPL_NOTIFY.
+ This routine updates the clock generator to generate the correct frequency
+ and polarity for the SPI clock.
+
+ @param[in] This Pointer to an EFI_SPI_HC_PROTOCOL structure.
+ @param[in] SpiPeripheral Pointer to a EFI_SPI_PERIPHERAL data structure from
+ which the routine can access the ClockParameter,
+ ClockPhase and ClockPolarity fields. The routine
+ also has access to the names for the SPI bus and
+ chip which can be used during debugging.
+ @param[in] ClockHz Pointer to the requested clock frequency. The SPI
+ host controller will choose a supported clock
+ frequency which is less then or equal to this
+ value. Specify zero to turn the clock generator
+ off. The actual clock frequency supported by the
+ SPI host controller will be returned.
+
+ @retval EFI_SUCCESS The clock was set up successfully
+ @retval EFI_UNSUPPORTED The SPI controller was not able to support the
+ frequency requested by ClockHz
+
+**/
+EFI_STATUS
+EFIAPI
+Clock (
+ IN CONST EFI_SPI_HC_PROTOCOL *This,
+ IN CONST EFI_SPI_PERIPHERAL *SpiPeripheral,
+ IN UINT32 *ClockHz
+ )
+{
+ return PlatformSpiHcClock (This, SpiPeripheral, ClockHz);
+}
+
+/**
+ Perform the SPI transaction on the SPI peripheral using the SPI host
+ controller.
+
+ This routine is called at TPL_NOTIFY.
+ This routine synchronously returns EFI_SUCCESS indicating that the
+ asynchronous SPI transaction was started. The routine then waits for
+ completion of the SPI transaction prior to returning the final transaction
+ status.
+
+ @param[in] This Pointer to an EFI_SPI_HC_PROTOCOL structure.
+ @param[in] BusTransaction Pointer to a EFI_SPI_BUS_ TRANSACTION containing
+ the description of the SPI transaction to perform.
+
+ @retval EFI_SUCCESS The transaction completed successfully
+ @retval EFI_BAD_BUFFER_SIZE The BusTransaction->WriteBytes value is invalid,
+ or the BusTransaction->ReadinBytes value is
+ invalid
+ @retval EFI_UNSUPPORTED The BusTransaction-> Transaction Type is
+ unsupported
+ @retval EFI_DEVICE_ERROR SPI Host Controller failed transaction
+
+**/
+EFI_STATUS
+EFIAPI
+Transaction (
+ IN CONST EFI_SPI_HC_PROTOCOL *This,
+ IN EFI_SPI_BUS_TRANSACTION *BusTransaction
+ )
+{
+ return PlatformSpiHcTransaction (This, BusTransaction);
+}
diff --git a/MdeModulePkg/Bus/Spi/SpiHc/SpiHc.h b/MdeModulePkg/Bus/Spi/SpiHc/SpiHc.h
new file mode 100644
index 0000000000..c6e4c5893d
--- /dev/null
+++ b/MdeModulePkg/Bus/Spi/SpiHc/SpiHc.h
@@ -0,0 +1,117 @@
+/** @file
+
+ SPI Host Controller function declarations
+
+ Copyright (C) 2024 Advanced Micro Devices, Inc. All rights reserved.<BR>
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#ifndef SPI_HC_H_
+#define SPI_HC_H_
+
+#include <PiDxe.h>
+#include <Library/BaseLib.h>
+#include <Library/BaseMemoryLib.h>
+#include <Library/DebugLib.h>
+#include <Library/IoLib.h>
+#include <Protocol/SpiHc.h>
+#include <Library/SpiHcPlatformLib.h>
+
+/**
+ Assert or deassert the SPI chip select.
+
+ This routine is called at TPL_NOTIFY.
+ Update the value of the chip select line for a SPI peripheral. The SPI bus
+ layer calls this routine either in the board layer or in the SPI controller
+ to manipulate the chip select pin at the start and end of a SPI transaction.
+
+ @param[in] This Pointer to an EFI_SPI_HC_PROTOCOL structure.
+ @param[in] SpiPeripheral The address of an EFI_SPI_PERIPHERAL data structure
+ describing the SPI peripheral whose chip select pin
+ is to be manipulated. The routine may access the
+ ChipSelectParameter field to gain sufficient
+ context to complete the operati on.
+ @param[in] PinValue The value to be applied to the chip select line of
+ the SPI peripheral.
+
+ @retval EFI_SUCCESS The chip select was set as requested
+ @retval EFI_NOT_READY Support for the chip select is not properly
+ initialized
+ @retval EFI_INVALID_PARAMETER The ChipSeLect value or its contents are
+ invalid
+
+**/
+EFI_STATUS
+EFIAPI
+ChipSelect (
+ IN CONST EFI_SPI_HC_PROTOCOL *This,
+ IN CONST EFI_SPI_PERIPHERAL *SpiPeripheral,
+ IN BOOLEAN PinValue
+ );
+
+/**
+ Set up the clock generator to produce the correct clock frequency, phase and
+ polarity for a SPI chip.
+
+ This routine is called at TPL_NOTIFY.
+ This routine updates the clock generator to generate the correct frequency
+ and polarity for the SPI clock.
+
+ @param[in] This Pointer to an EFI_SPI_HC_PROTOCOL structure.
+ @param[in] SpiPeripheral Pointer to a EFI_SPI_PERIPHERAL data structure from
+ which the routine can access the ClockParameter,
+ ClockPhase and ClockPolarity fields. The routine
+ also has access to the names for the SPI bus and
+ chip which can be used during debugging.
+ @param[in] ClockHz Pointer to the requested clock frequency. The SPI
+ host controller will choose a supported clock
+ frequency which is less then or equal to this
+ value. Specify zero to turn the clock generator
+ off. The actual clock frequency supported by the
+ SPI host controller will be returned.
+
+ @retval EFI_SUCCESS The clock was set up successfully
+ @retval EFI_UNSUPPORTED The SPI controller was not able to support the
+ frequency requested by ClockHz
+
+**/
+EFI_STATUS
+EFIAPI
+Clock (
+ IN CONST EFI_SPI_HC_PROTOCOL *This,
+ IN CONST EFI_SPI_PERIPHERAL *SpiPeripheral,
+ IN UINT32 *ClockHz
+ );
+
+/**
+ Perform the SPI transaction on the SPI peripheral using the SPI host
+ controller.
+
+ This routine is called at TPL_NOTIFY.
+ This routine synchronously returns EFI_SUCCESS indicating that the
+ asynchronous SPI transaction was started. The routine then waits for
+ completion of the SPI transaction prior to returning the final transaction
+ status.
+
+ @param[in] This Pointer to an EFI_SPI_HC_PROTOCOL structure.
+ @param[in] BusTransaction Pointer to a EFI_SPI_BUS_ TRANSACTION containing
+ the description of the SPI transaction to perform.
+
+ @retval EFI_SUCCESS The transaction completed successfully
+ @retval EFI_BAD_BUFFER_SIZE The BusTransaction->WriteBytes value is invalid,
+ or the BusTransaction->ReadinBytes value is
+ invalid
+ @retval EFI_UNSUPPORTED The BusTransaction-> Transaction Type is
+ unsupported
+ @retval EFI_DEVICE_ERROR SPI Host Controller failed transaction
+
+**/
+EFI_STATUS
+EFIAPI
+Transaction (
+ IN CONST EFI_SPI_HC_PROTOCOL *This,
+ IN EFI_SPI_BUS_TRANSACTION *BusTransaction
+ );
+
+#endif //SPI_HC_H_
diff --git a/MdeModulePkg/Bus/Spi/SpiHc/SpiHc.uni b/MdeModulePkg/Bus/Spi/SpiHc/SpiHc.uni
new file mode 100644
index 0000000000..9fab0a7433
--- /dev/null
+++ b/MdeModulePkg/Bus/Spi/SpiHc/SpiHc.uni
@@ -0,0 +1,10 @@
+// /** @file
+//
+// Copyright (C) 2024 Advanced Micro Devices, Inc. All rights reserved.<BR>
+//
+// SPDX-License-Identifier: BSD-2-Clause-Patent
+//
+// **/
+
+#string STR_PROPERTIES_MODULE_NAME
+#language en-US "SPI host controller driver"
diff --git a/MdeModulePkg/Bus/Spi/SpiHc/SpiHcDxe.c b/MdeModulePkg/Bus/Spi/SpiHc/SpiHcDxe.c
new file mode 100644
index 0000000000..d0e9827eb6
--- /dev/null
+++ b/MdeModulePkg/Bus/Spi/SpiHc/SpiHcDxe.c
@@ -0,0 +1,101 @@
+/** @file
+
+ SPI Host controller entry point for DXE
+
+ Copyright (C) 2024 Advanced Micro Devices, Inc. All rights reserved.<BR>
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+#include <Base.h>
+#include <Library/BaseLib.h>
+#include <Library/DebugLib.h>
+#include <Library/PcdLib.h>
+#include <Library/UefiLib.h>
+#include <Library/MemoryAllocationLib.h>
+#include <Library/UefiBootServicesTableLib.h>
+#include <Library/UefiRuntimeServicesTableLib.h>
+#include <Library/SpiHcPlatformLib.h>
+#include <Protocol/SpiHc.h>
+#include <IndustryStandard/SpiNorFlashJedecSfdp.h>
+#include "SpiHc.h"
+
+EFI_HANDLE mSpiHcHandle = 0;
+
+/**
+ Entry point of the SPI Host Controller driver. Installs the EFI_SPI_HC_PROTOCOL on mSpiHcHandle.
+ Also installs the EFI_DEVICE_PATH_PROTOCOL corresponding to the SPI Host controller on the same
+ mSpiHcHandle.
+
+ @param[in] ImageHandle Image handle of this driver.
+ @param[in] SystemTable Pointer to standard EFI system table.
+
+ @retval EFI_SUCCESS Succeed.
+ @retval EFI_OUT_RESOURCES If the system has run out of memory
+**/
+EFI_STATUS
+EFIAPI
+SpiHcProtocolEntry (
+ IN EFI_HANDLE ImageHandle,
+ IN EFI_SYSTEM_TABLE *SystemTable
+ )
+{
+ EFI_STATUS Status;
+ EFI_SPI_HC_PROTOCOL *HcProtocol;
+ EFI_DEVICE_PATH_PROTOCOL *HcDevicePath;
+
+ DEBUG ((DEBUG_VERBOSE, "%a - ENTRY\n", __func__));
+
+ // Allocate the SPI Host Controller protocol
+ HcProtocol = AllocateZeroPool (sizeof (EFI_SPI_HC_PROTOCOL));
+ ASSERT (HcProtocol != NULL);
+ if (HcProtocol == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ // Fill in the SPI Host Controller Protocol
+ Status = GetPlatformSpiHcDetails (
+ &HcProtocol->Attributes,
+ &HcProtocol->FrameSizeSupportMask,
+ &HcProtocol->MaximumTransferBytes
+ );
+
+ if (EFI_ERROR (Status)) {
+ DEBUG ((DEBUG_VERBOSE, "Error, no Platform SPI HC details\n"));
+ return Status;
+ }
+
+ HcProtocol->ChipSelect = ChipSelect;
+ HcProtocol->Clock = Clock;
+ HcProtocol->Transaction = Transaction;
+
+ // Install Host Controller protocol
+ Status = gBS->InstallProtocolInterface (
+ &mSpiHcHandle,
+ &gEfiSpiHcProtocolGuid,
+ EFI_NATIVE_INTERFACE,
+ HcProtocol
+ );
+
+ if (EFI_ERROR (Status)) {
+ DEBUG ((DEBUG_VERBOSE, "Error installing gEfiSpiHcProtocolGuid\n"));
+ return Status;
+ }
+
+ Status = GetSpiHcDevicePath (&HcDevicePath);
+
+ // Install HC device path here on this handle as well
+ Status = gBS->InstallProtocolInterface (
+ &mSpiHcHandle,
+ &gEfiDevicePathProtocolGuid,
+ EFI_NATIVE_INTERFACE,
+ HcDevicePath
+ );
+
+ if (EFI_ERROR (Status)) {
+ DEBUG ((DEBUG_VERBOSE, "Error installing gEfiDevicePathProtocolGuid\n"));
+ }
+
+ DEBUG ((DEBUG_VERBOSE, "%a - EXIT Status=%r\n", __func__, Status));
+
+ return Status;
+}
diff --git a/MdeModulePkg/Bus/Spi/SpiHc/SpiHcDxe.inf b/MdeModulePkg/Bus/Spi/SpiHc/SpiHcDxe.inf
new file mode 100644
index 0000000000..b71f1535cd
--- /dev/null
+++ b/MdeModulePkg/Bus/Spi/SpiHc/SpiHcDxe.inf
@@ -0,0 +1,47 @@
+## @file
+# The SPI Host Controller Module DXE driver INF file
+#
+# Copyright (C) 2024 Advanced Micro Devices, Inc. All rights reserved.
+#
+# SPDX-License-Identifier: BSD-2-Clause-Patent
+#
+##
+
+[Defines]
+ INF_VERSION = 1.27
+ BASE_NAME = SpiHcDxe
+ FILE_GUID = 95D148FF-5A23-43B9-9FC4-80AE0DD48D32
+ MODULE_TYPE = DXE_DRIVER
+ VERSION_STRING = 0.1
+ PI_SPECIFICATION_VERSION = 0x0001000A
+ ENTRY_POINT = SpiHcProtocolEntry
+
+[Packages]
+ MdePkg/MdePkg.dec
+ MdeModulePkg/MdeModulePkg.dec
+
+[LibraryClasses]
+ BaseLib
+ BaseMemoryLib
+ DebugLib
+ DevicePathLib
+ MemoryAllocationLib
+ SpiHcPlatformLib
+ UefiBootServicesTableLib
+ UefiDriverEntryPoint
+ UefiLib
+ UefiRuntimeServicesTableLib
+
+[Sources]
+ SpiHc.h
+ SpiHc.c
+ SpiHcDxe.c
+
+[Protocols]
+ gEfiSpiHcProtocolGuid
+
+[Depex]
+ TRUE
+
+[UserExtensions.TianoCore."ExtraFiles"]
+ SpiHc.uni
diff --git a/MdeModulePkg/Bus/Spi/SpiHc/SpiHcSmm.c b/MdeModulePkg/Bus/Spi/SpiHc/SpiHcSmm.c
new file mode 100644
index 0000000000..adebff9763
--- /dev/null
+++ b/MdeModulePkg/Bus/Spi/SpiHc/SpiHcSmm.c
@@ -0,0 +1,79 @@
+/** @file
+
+ SPI Host controller entry point for SMM
+
+ Copyright (C) 2024 Advanced Micro Devices, Inc. All rights reserved.<BR>
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+#include <Base.h>
+#include <Library/BaseLib.h>
+#include <Library/DebugLib.h>
+#include <Library/PcdLib.h>
+#include <Library/UefiLib.h>
+#include <Library/MemoryAllocationLib.h>
+#include <Library/MmServicesTableLib.h>
+#include <Library/UefiRuntimeServicesTableLib.h>
+#include <Library/SpiHcPlatformLib.h>
+#include <Protocol/SpiSmmHc.h>
+#include <IndustryStandard/SpiNorFlashJedecSfdp.h>
+#include "SpiHc.h"
+
+EFI_HANDLE mSpiHcHandle = 0;
+
+/**
+ Entry point of the SPI Host Controller driver. Installs the EFI_SPI_HC_PROTOCOL on mSpiHcHandle.
+ Also installs the EFI_DEVICE_PATH_PROTOCOL corresponding to the SPI Host controller on the same
+ mSpiHcHandle.
+
+ @param[in] ImageHandle Image handle of this driver.
+ @param[in] SystemTable Pointer to standard EFI system table.
+
+ @retval EFI_SUCCESS Succeed.
+ @retval EFI_OUT_RESOURCES If the system has run out of memory
+**/
+EFI_STATUS
+EFIAPI
+SpiHcProtocolEntry (
+ IN EFI_HANDLE ImageHandle,
+ IN EFI_SYSTEM_TABLE *SystemTable
+ )
+{
+ EFI_STATUS Status;
+ EFI_SPI_HC_PROTOCOL *HcProtocol;
+
+ DEBUG ((DEBUG_VERBOSE, "%a - ENTRY\n", __func__));
+
+ // Allocate the SPI Host Controller protocol
+ HcProtocol = AllocateZeroPool (sizeof (EFI_SPI_HC_PROTOCOL));
+ ASSERT (HcProtocol != NULL);
+ if (HcProtocol == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ // Fill in the SPI Host Controller Protocol
+ Status = GetPlatformSpiHcDetails (
+ &HcProtocol->Attributes,
+ &HcProtocol->FrameSizeSupportMask,
+ &HcProtocol->MaximumTransferBytes
+ );
+
+ HcProtocol->ChipSelect = ChipSelect;
+ HcProtocol->Clock = Clock;
+ HcProtocol->Transaction = Transaction;
+
+ Status = gMmst->MmInstallProtocolInterface (
+ &mSpiHcHandle,
+ &gEfiSpiSmmHcProtocolGuid,
+ EFI_NATIVE_INTERFACE,
+ HcProtocol
+ );
+
+ if (EFI_ERROR (Status)) {
+ DEBUG ((DEBUG_VERBOSE, "Error installing gEfiSpiSmmHcProtocolGuid\n"));
+ }
+
+ DEBUG ((DEBUG_VERBOSE, "%a - EXIT Status=%r\n", __func__, Status));
+
+ return Status;
+}
diff --git a/MdeModulePkg/Bus/Spi/SpiHc/SpiHcSmm.inf b/MdeModulePkg/Bus/Spi/SpiHc/SpiHcSmm.inf
new file mode 100644
index 0000000000..95d5466d90
--- /dev/null
+++ b/MdeModulePkg/Bus/Spi/SpiHc/SpiHcSmm.inf
@@ -0,0 +1,45 @@
+## @file
+# The SPI Host Controller Module SMM driver INF file
+#
+# Copyright (C) 2024 Advanced Micro Devices, Inc. All rights reserved.
+#
+# SPDX-License-Identifier: BSD-2-Clause-Patent
+#
+##
+
+[Defines]
+ INF_VERSION = 1.27
+ BASE_NAME = SpiHcSmm
+ FILE_GUID = 0CDAE298-CB3B-480A-BDC4-A6840FFE1F5E
+ MODULE_TYPE = DXE_SMM_DRIVER
+ VERSION_STRING = 0.1
+ PI_SPECIFICATION_VERSION = 0x0001000A
+ ENTRY_POINT = SpiHcProtocolEntry
+
+[Packages]
+ MdePkg/MdePkg.dec
+ MdeModulePkg/MdeModulePkg.dec
+
+[LibraryClasses]
+ BaseLib
+ BaseMemoryLib
+ DebugLib
+ MemoryAllocationLib
+ MmServicesTableLib
+ SpiHcPlatformLib
+ UefiDriverEntryPoint
+ UefiLib
+
+[Sources]
+ SpiHc.h
+ SpiHc.c
+ SpiHcSmm.c
+
+[Protocols]
+ gEfiSpiSmmHcProtocolGuid
+
+[Depex]
+ TRUE
+
+[UserExtensions.TianoCore."ExtraFiles"]
+ SpiHc.uni
diff --git a/MdeModulePkg/Core/Dxe/Gcd/Gcd.c b/MdeModulePkg/Core/Dxe/Gcd/Gcd.c
index c450d1bf25..fe1bbd6974 100644
--- a/MdeModulePkg/Core/Dxe/Gcd/Gcd.c
+++ b/MdeModulePkg/Core/Dxe/Gcd/Gcd.c
@@ -8,8 +8,8 @@ SPDX-License-Identifier: BSD-2-Clause-Patent
**/
-#include <Pi/PrePiDxeCis.h>
-#include <Pi/PrePiHob.h>
+#include <Pi/PiDxeCis.h>
+#include <Pi/PiHob.h>
#include "DxeMain.h"
#include "Gcd.h"
#include "Mem/HeapGuard.h"
@@ -105,7 +105,7 @@ GLOBAL_REMOVE_IF_UNREFERENCED CONST CHAR8 *mGcdMemoryTypeNames[] = {
"MMIO ", // EfiGcdMemoryTypeMemoryMappedIo
"PersisMem", // EfiGcdMemoryTypePersistent
"MoreRelia", // EfiGcdMemoryTypeMoreReliable
- "Unaccepte", // EFI_GCD_MEMORY_TYPE_UNACCEPTED
+ "Unaccepte", // EfiGcdMemoryTypeUnaccepted
"Unknown " // EfiGcdMemoryTypeMaximum
};
@@ -2669,8 +2669,8 @@ CoreInitializeGcdServices (
case EFI_RESOURCE_MEMORY_RESERVED:
GcdMemoryType = EfiGcdMemoryTypeReserved;
break;
- case BZ3937_EFI_RESOURCE_MEMORY_UNACCEPTED:
- GcdMemoryType = EFI_GCD_MEMORY_TYPE_UNACCEPTED;
+ case EFI_RESOURCE_MEMORY_UNACCEPTED:
+ GcdMemoryType = EfiGcdMemoryTypeUnaccepted;
break;
case EFI_RESOURCE_IO:
GcdIoType = EfiGcdIoTypeIo;
diff --git a/MdeModulePkg/Core/Dxe/Mem/Page.c b/MdeModulePkg/Core/Dxe/Mem/Page.c
index 26584648c2..5a51d9df1a 100644
--- a/MdeModulePkg/Core/Dxe/Mem/Page.c
+++ b/MdeModulePkg/Core/Dxe/Mem/Page.c
@@ -9,7 +9,7 @@ SPDX-License-Identifier: BSD-2-Clause-Patent
#include "DxeMain.h"
#include "Imem.h"
#include "HeapGuard.h"
-#include <Pi/PrePiDxeCis.h>
+#include <Pi/PiDxeCis.h>
//
// Entry for tracking the memory regions for each memory type to coalesce similar memory types
@@ -70,23 +70,23 @@ EFI_PHYSICAL_ADDRESS mDefaultMaximumAddress = MAX_ALLOC_ADDRESS;
EFI_PHYSICAL_ADDRESS mDefaultBaseAddress = MAX_ALLOC_ADDRESS;
EFI_MEMORY_TYPE_INFORMATION gMemoryTypeInformation[EfiMaxMemoryType + 1] = {
- { EfiReservedMemoryType, 0 },
- { EfiLoaderCode, 0 },
- { EfiLoaderData, 0 },
- { EfiBootServicesCode, 0 },
- { EfiBootServicesData, 0 },
- { EfiRuntimeServicesCode, 0 },
- { EfiRuntimeServicesData, 0 },
- { EfiConventionalMemory, 0 },
- { EfiUnusableMemory, 0 },
- { EfiACPIReclaimMemory, 0 },
- { EfiACPIMemoryNVS, 0 },
- { EfiMemoryMappedIO, 0 },
- { EfiMemoryMappedIOPortSpace, 0 },
- { EfiPalCode, 0 },
- { EfiPersistentMemory, 0 },
- { EFI_GCD_MEMORY_TYPE_UNACCEPTED, 0 },
- { EfiMaxMemoryType, 0 }
+ { EfiReservedMemoryType, 0 },
+ { EfiLoaderCode, 0 },
+ { EfiLoaderData, 0 },
+ { EfiBootServicesCode, 0 },
+ { EfiBootServicesData, 0 },
+ { EfiRuntimeServicesCode, 0 },
+ { EfiRuntimeServicesData, 0 },
+ { EfiConventionalMemory, 0 },
+ { EfiUnusableMemory, 0 },
+ { EfiACPIReclaimMemory, 0 },
+ { EfiACPIMemoryNVS, 0 },
+ { EfiMemoryMappedIO, 0 },
+ { EfiMemoryMappedIOPortSpace, 0 },
+ { EfiPalCode, 0 },
+ { EfiPersistentMemory, 0 },
+ { EfiGcdMemoryTypeUnaccepted, 0 },
+ { EfiMaxMemoryType, 0 }
};
//
// Only used when load module at fixed address feature is enabled. True means the memory is alreay successfully allocated
@@ -2083,7 +2083,7 @@ CoreGetMemoryMap (
MemoryMap = MergeMemoryMapDescriptor (MemoryMapStart, MemoryMap, Size);
}
- if (MergeGcdMapEntry.GcdMemoryType == EFI_GCD_MEMORY_TYPE_UNACCEPTED) {
+ if (MergeGcdMapEntry.GcdMemoryType == EfiGcdMemoryTypeUnaccepted) {
//
// Page Align GCD range is required. When it is converted to EFI_MEMORY_DESCRIPTOR,
// it will be recorded as page PhysicalStart and NumberOfPages.
diff --git a/MdeModulePkg/Include/Library/SpiHcPlatformLib.h b/MdeModulePkg/Include/Library/SpiHcPlatformLib.h
new file mode 100644
index 0000000000..c68f745537
--- /dev/null
+++ b/MdeModulePkg/Include/Library/SpiHcPlatformLib.h
@@ -0,0 +1,148 @@
+/** @file
+
+ Function declarations for SpiHcPlatformLib
+
+ Copyright (C) 2024 Advanced Micro Devices, Inc. All rights reserved.<BR>
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+**/
+
+#ifndef PLATFORM_SPI_HC_H_
+#define PLATFORM_SPI_HC_H_
+
+#include <Uefi/UefiBaseType.h>
+#include <Protocol/SpiHc.h>
+#include <Protocol/SpiConfiguration.h>
+#include <Protocol/DevicePath.h>
+#include <Library/DevicePathLib.h>
+
+/**
+ This function reports the details of the SPI Host Controller to the SpiHc driver.
+
+ @param[out] Attributes The suported attributes of the SPI host controller
+ @param[out] FrameSizeSupportMask The suported FrameSizeSupportMask of the SPI host controller
+ @param[out] MaximumTransferBytes The suported MaximumTransferBytes of the SPI host controller
+
+ @retval EFI_SUCCESS SPI_HOST_CONTROLLER_INSTANCE was allocated properly
+ @retval EFI_OUT_OF_RESOURCES The SPI_HOST_CONTROLLER_INSTANCE could not be allocated
+*/
+EFI_STATUS
+EFIAPI
+GetPlatformSpiHcDetails (
+ OUT UINT32 *Attributes,
+ OUT UINT32 *FrameSizeSupportMask,
+ OUT UINT32 *MaximumTransferBytes
+ );
+
+/**
+ This function reports the device path of SPI host controller. This is needed in order for the SpiBus
+ to match the correct SPI_BUS to the SPI host controller
+
+ @param[out] DevicePath The device path for this SPI HC is returned in this variable
+
+ @retval EFI_SUCCESS
+*/
+EFI_STATUS
+EFIAPI
+GetSpiHcDevicePath (
+ OUT EFI_DEVICE_PATH_PROTOCOL **DevicePath
+ );
+
+/**
+ This is the platform specific Spi Chip select function.
+ Assert or deassert the SPI chip select.
+
+ This routine is called at TPL_NOTIFY.
+ Update the value of the chip select line for a SPI peripheral. The SPI bus
+ layer calls this routine either in the board layer or in the SPI controller
+ to manipulate the chip select pin at the start and end of a SPI transaction.
+
+ @param[in] This Pointer to an EFI_SPI_HC_PROTOCOL structure.
+ @param[in] SpiPeripheral The address of an EFI_SPI_PERIPHERAL data structure
+ describing the SPI peripheral whose chip select pin
+ is to be manipulated. The routine may access the
+ ChipSelectParameter field to gain sufficient
+ context to complete the operati on.
+ @param[in] PinValue The value to be applied to the chip select line of
+ the SPI peripheral.
+
+ @retval EFI_SUCCESS The chip select was set as requested
+ @retval EFI_NOT_READY Support for the chip select is not properly
+ initialized
+ @retval EFI_INVALID_PARAMETER The ChipSeLect value or its contents are
+ invalid
+
+**/
+EFI_STATUS
+EFIAPI
+PlatformSpiHcChipSelect (
+ IN CONST EFI_SPI_HC_PROTOCOL *This,
+ IN CONST EFI_SPI_PERIPHERAL *SpiPeripheral,
+ IN BOOLEAN PinValue
+ );
+
+/**
+ This function is the platform specific SPI clock function.
+ Set up the clock generator to produce the correct clock frequency, phase and
+ polarity for a SPI chip.
+
+ This routine is called at TPL_NOTIFY.
+ This routine updates the clock generator to generate the correct frequency
+ and polarity for the SPI clock.
+
+ @param[in] This Pointer to an EFI_SPI_HC_PROTOCOL structure.
+ @param[in] SpiPeripheral Pointer to a EFI_SPI_PERIPHERAL data structure from
+ which the routine can access the ClockParameter,
+ ClockPhase and ClockPolarity fields. The routine
+ also has access to the names for the SPI bus and
+ chip which can be used during debugging.
+ @param[in] ClockHz Pointer to the requested clock frequency. The SPI
+ host controller will choose a supported clock
+ frequency which is less then or equal to this
+ value. Specify zero to turn the clock generator
+ off. The actual clock frequency supported by the
+ SPI host controller will be returned.
+
+ @retval EFI_SUCCESS The clock was set up successfully
+ @retval EFI_UNSUPPORTED The SPI controller was not able to support the
+ frequency requested by ClockHz
+
+**/
+EFI_STATUS
+EFIAPI
+PlatformSpiHcClock (
+ IN CONST EFI_SPI_HC_PROTOCOL *This,
+ IN CONST EFI_SPI_PERIPHERAL *SpiPeripheral,
+ IN UINT32 *ClockHz
+ );
+
+/**
+ This function is the platform specific SPI transaction function
+ Perform the SPI transaction on the SPI peripheral using the SPI host
+ controller.
+
+ This routine is called at TPL_NOTIFY.
+ This routine synchronously returns EFI_SUCCESS indicating that the
+ asynchronous SPI transaction was started. The routine then waits for
+ completion of the SPI transaction prior to returning the final transaction
+ status.
+
+ @param[in] This Pointer to an EFI_SPI_HC_PROTOCOL structure.
+ @param[in] BusTransaction Pointer to a EFI_SPI_BUS_ TRANSACTION containing
+ the description of the SPI transaction to perform.
+
+ @retval EFI_SUCCESS The transaction completed successfully
+ @retval EFI_BAD_BUFFER_SIZE The BusTransaction->WriteBytes value is invalid,
+ or the BusTransaction->ReadinBytes value is
+ invalid
+ @retval EFI_UNSUPPORTED The BusTransaction-> Transaction Type is
+ unsupported
+
+**/
+EFI_STATUS
+EFIAPI
+PlatformSpiHcTransaction (
+ IN CONST EFI_SPI_HC_PROTOCOL *This,
+ IN EFI_SPI_BUS_TRANSACTION *BusTransaction
+ );
+
+#endif // PLATFORM_SPI_HC_SMM_PROTOCOL_H_
diff --git a/MdeModulePkg/Include/Pi/PrePiDxeCis.h b/MdeModulePkg/Include/Pi/PrePiDxeCis.h
deleted file mode 100644
index 9be71d2618..0000000000
--- a/MdeModulePkg/Include/Pi/PrePiDxeCis.h
+++ /dev/null
@@ -1,25 +0,0 @@
-/** @file
- Include file matches things in PI.
-
-Copyright (c) 2022, Intel Corporation. All rights reserved.<BR>
-SPDX-License-Identifier: BSD-2-Clause-Patent
-
-**/
-
-#ifndef MDE_MODULEPKG_PRE_PI_DXE_CIS_H_
-#define MDE_MODULEPKG_PRE_PI_DXE_CIS_H_
-
-///
-/// A memory region that describes system memory that has not been accepted
-/// by a corresponding call to the underlying isolation architecture.
-///
-/// This memory region has not been defined in PI spec, so it is defined in
-/// PrePiDxeCis.h. And it is defined in the format of captial letters
-/// because only capital letters are allowed to be used for #define declarations.
-///
-/// After this memory region is defined in PI spec, it should be a value in
-/// EFI_GCD_MEMORY_TYPE in PiDxeCis.h.
-///
-#define EFI_GCD_MEMORY_TYPE_UNACCEPTED 6
-
-#endif
diff --git a/MdeModulePkg/Include/Pi/PrePiHob.h b/MdeModulePkg/Include/Pi/PrePiHob.h
deleted file mode 100644
index ac575e5972..0000000000
--- a/MdeModulePkg/Include/Pi/PrePiHob.h
+++ /dev/null
@@ -1,20 +0,0 @@
-/** @file
- HOB related definitions which has not been officially published in PI.
-
-Copyright (c) 2022, Intel Corporation. All rights reserved.<BR>
-SPDX-License-Identifier: BSD-2-Clause-Patent
-
-**/
-
-#ifndef MDE_MODULEPKG_PRE_PI_HOB_H_
-#define MDE_MODULEPKG_PRE_PI_HOB_H_
-
-//
-// BZ3937_EFI_RESOURCE_MEMORY_UNACCEPTED is defined for unaccepted memory.
-// But this defitinion has not been officially in the PI spec. Base
-// on the code-first we define BZ3937_EFI_RESOURCE_MEMORY_UNACCEPTED at
-// MdeModulePkg/Include/Pi/PrePiHob.h.
-//
-#define BZ3937_EFI_RESOURCE_MEMORY_UNACCEPTED 0x00000007
-
-#endif
diff --git a/MdeModulePkg/Library/BaseSpiHcPlatformLibNull/BaseSpiHcPlatformLibNull.c b/MdeModulePkg/Library/BaseSpiHcPlatformLibNull/BaseSpiHcPlatformLibNull.c
new file mode 100644
index 0000000000..2926e9e248
--- /dev/null
+++ b/MdeModulePkg/Library/BaseSpiHcPlatformLibNull/BaseSpiHcPlatformLibNull.c
@@ -0,0 +1,145 @@
+/** @file
+
+ Null implementation of SpiHcPlatformLib
+
+ Copyright (C) 2024 Advanced Micro Devices, Inc. All rights reserved.<BR>
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+#include <PiDxe.h>
+#include <Protocol/DevicePath.h>
+#include <Protocol/SpiHc.h>
+#include <Library/SpiHcPlatformLib.h>
+
+/**
+ This function reports the details of the SPI Host Controller to the SpiHc driver.
+
+ @param[out] Attributes The suported attributes of the SPI host controller
+ @param[out] FrameSizeSupportMask The suported FrameSizeSupportMask of the SPI host controller
+ @param[out] MaximumTransferBytes The suported MaximumTransferBytes of the SPI host controller
+
+ @retval EFI_UNSUPPORTED
+**/
+EFI_STATUS
+EFIAPI
+GetPlatformSpiHcDetails (
+ OUT UINT32 *Attributes,
+ OUT UINT32 *FrameSizeSupportMask,
+ OUT UINT32 *MaximumTransferBytes
+ )
+{
+ return EFI_UNSUPPORTED;
+}
+
+/**
+ This function reports the device path of SPI host controller. This is needed in order for the SpiBus
+ to match the correct SPI_BUS to the SPI host controller
+
+ @param[out] DevicePath The device path for this SPI HC is returned in this variable
+
+ @retval EFI_UNSUPPORTED
+**/
+EFI_STATUS
+EFIAPI
+GetSpiHcDevicePath (
+ OUT EFI_DEVICE_PATH_PROTOCOL **DevicePath
+ )
+{
+ return EFI_UNSUPPORTED;
+}
+
+/**
+ This is the platform specific Spi Chip select function.
+ Assert or deassert the SPI chip select.
+
+ This routine is called at TPL_NOTIFY.
+ Update the value of the chip select line for a SPI peripheral. The SPI bus
+ layer calls this routine either in the board layer or in the SPI controller
+ to manipulate the chip select pin at the start and end of a SPI transaction.
+
+ @param[in] This Pointer to an EFI_SPI_HC_PROTOCOL structure.
+ @param[in] SpiPeripheral The address of an EFI_SPI_PERIPHERAL data structure
+ describing the SPI peripheral whose chip select pin
+ is to be manipulated. The routine may access the
+ ChipSelectParameter field to gain sufficient
+ context to complete the operati on.
+ @param[in] PinValue The value to be applied to the chip select line of
+ the SPI peripheral.
+
+ @retval EFI_UNSUPPORTED
+
+**/
+EFI_STATUS
+EFIAPI
+PlatformSpiHcChipSelect (
+ IN CONST EFI_SPI_HC_PROTOCOL *This,
+ IN CONST EFI_SPI_PERIPHERAL *SpiPeripheral,
+ IN BOOLEAN PinValue
+ )
+{
+ return EFI_UNSUPPORTED;
+}
+
+/**
+ This function is the platform specific SPI clock function.
+ Set up the clock generator to produce the correct clock frequency, phase and
+ polarity for a SPI chip.
+
+ This routine is called at TPL_NOTIFY.
+ This routine updates the clock generator to generate the correct frequency
+ and polarity for the SPI clock.
+
+ @param[in] This Pointer to an EFI_SPI_HC_PROTOCOL structure.
+ @param[in] SpiPeripheral Pointer to a EFI_SPI_PERIPHERAL data structure from
+ which the routine can access the ClockParameter,
+ ClockPhase and ClockPolarity fields. The routine
+ also has access to the names for the SPI bus and
+ chip which can be used during debugging.
+ @param[in] ClockHz Pointer to the requested clock frequency. The SPI
+ host controller will choose a supported clock
+ frequency which is less then or equal to this
+ value. Specify zero to turn the clock generator
+ off. The actual clock frequency supported by the
+ SPI host controller will be returned.
+
+ @retval EFI_UNSUPPORTED
+
+**/
+EFI_STATUS
+EFIAPI
+PlatformSpiHcClock (
+ IN CONST EFI_SPI_HC_PROTOCOL *This,
+ IN CONST EFI_SPI_PERIPHERAL *SpiPeripheral,
+ IN UINT32 *ClockHz
+ )
+{
+ return EFI_UNSUPPORTED;
+}
+
+/**
+ This function is the platform specific SPI transaction function
+ Perform the SPI transaction on the SPI peripheral using the SPI host
+ controller.
+
+ This routine is called at TPL_NOTIFY.
+ This routine synchronously returns EFI_SUCCESS indicating that the
+ asynchronous SPI transaction was started. The routine then waits for
+ completion of the SPI transaction prior to returning the final transaction
+ status.
+
+ @param[in] This Pointer to an EFI_SPI_HC_PROTOCOL structure.
+ @param[in] BusTransaction Pointer to a EFI_SPI_BUS_ TRANSACTION containing
+ the description of the SPI transaction to perform.
+
+ @retval EFI_UNSUPPORTED
+
+**/
+EFI_STATUS
+EFIAPI
+PlatformSpiHcTransaction (
+ IN CONST EFI_SPI_HC_PROTOCOL *This,
+ IN EFI_SPI_BUS_TRANSACTION *BusTransaction
+ )
+{
+ return EFI_UNSUPPORTED;
+}
diff --git a/MdeModulePkg/Library/BaseSpiHcPlatformLibNull/BaseSpiHcPlatformLibNull.inf b/MdeModulePkg/Library/BaseSpiHcPlatformLibNull/BaseSpiHcPlatformLibNull.inf
new file mode 100644
index 0000000000..805f50b895
--- /dev/null
+++ b/MdeModulePkg/Library/BaseSpiHcPlatformLibNull/BaseSpiHcPlatformLibNull.inf
@@ -0,0 +1,33 @@
+## @file
+# NULL library for platform SPI Host controller, which should be provided
+# by the OEM.
+#
+# Copyright (C) 2024 Advanced Micro Devices, Inc. All rights reserved.<BR>
+#
+# SPDX-License-Identifier: BSD-2-Clause-Patent
+##
+[Defines]
+ INF_VERSION = 1.27
+ BASE_NAME = BaseSpiHcPlatformLibNull
+ FILE_GUID = 3C230948-6DF5-4802-8177-967A190579CF
+ MODULE_TYPE = BASE
+ VERSION_STRING = 0.1
+ PI_SPECIFICATION_VERSION = 0x0001000A
+ LIBRARY_CLASS = SpiHcPlatformLib
+
+[Packages]
+ MdePkg/MdePkg.dec
+ MdeModulePkg/MdeModulePkg.dec
+
+[LibraryClasses]
+ DevicePathLib
+ UefiLib
+
+[Sources]
+ BaseSpiHcPlatformLibNull.c
+
+[Depex]
+ TRUE
+
+[UserExtensions.TianoCore."ExtraFiles"]
+ BaseSpiHcPlatformLibNull.uni
diff --git a/MdeModulePkg/Library/BaseSpiHcPlatformLibNull/BaseSpiHcPlatformLibNull.uni b/MdeModulePkg/Library/BaseSpiHcPlatformLibNull/BaseSpiHcPlatformLibNull.uni
new file mode 100644
index 0000000000..82fa02c31d
--- /dev/null
+++ b/MdeModulePkg/Library/BaseSpiHcPlatformLibNull/BaseSpiHcPlatformLibNull.uni
@@ -0,0 +1,11 @@
+
+// /** @file
+//
+// Copyright (C) 2024 Advanced Micro Devices, Inc. All rights reserved.<BR>
+//
+// SPDX-License-Identifier: BSD-2-Clause-Patent
+//
+// **/
+
+#string STR_PROPERTIES_MODULE_NAME
+#language en-US "Null SPI Host controller library"
diff --git a/MdeModulePkg/MdeModulePkg.dec b/MdeModulePkg/MdeModulePkg.dec
index 085370eae4..f7339f0aec 100644
--- a/MdeModulePkg/MdeModulePkg.dec
+++ b/MdeModulePkg/MdeModulePkg.dec
@@ -169,6 +169,11 @@
#
ImagePropertiesRecordLib|Include/Library/ImagePropertiesRecordLib.h
+ ## @libraryclass Platform SPI Host Controller library which provides low-level
+ # control over the SPI hardware
+ #
+ SpiHcPlatformLib|Include/Library/SpiHcPlatformLib.h
+
[Guids]
## MdeModule package token space guid
# Include/Guid/MdeModulePkgTokenSpace.h
@@ -1154,6 +1159,11 @@
# @Prompt Enable large address image loading.
gEfiMdeModulePkgTokenSpaceGuid.PcdImageLargeAddressLoad|TRUE|BOOLEAN|0x30001059
+ ## Indicates time delay for XHCI registers access after it issues HCRST.
+ # Default is 2000, it represent delay is 2 ms.
+ # @Prompt Delay access XHCI register after it issues HCRST (us)
+ gEfiMdeModulePkgTokenSpaceGuid.PcdDelayXhciHCReset|2000|UINT16|0x30001060
+
[PcdsFixedAtBuild, PcdsPatchableInModule]
## Dynamic type PCD can be registered callback function for Pcd setting action.
# PcdMaxPeiPcdCallBackNumberPerPcdEntry indicates the maximum number of callback function
diff --git a/MdeModulePkg/MdeModulePkg.dsc b/MdeModulePkg/MdeModulePkg.dsc
index 6bed9205ea..a1c8e2f905 100644
--- a/MdeModulePkg/MdeModulePkg.dsc
+++ b/MdeModulePkg/MdeModulePkg.dsc
@@ -107,6 +107,7 @@
MmUnblockMemoryLib|MdePkg/Library/MmUnblockMemoryLib/MmUnblockMemoryLibNull.inf
VariableFlashInfoLib|MdeModulePkg/Library/BaseVariableFlashInfoLib/BaseVariableFlashInfoLib.inf
IpmiCommandLib|MdeModulePkg/Library/BaseIpmiCommandLibNull/BaseIpmiCommandLibNull.inf
+ SpiHcPlatformLib|MdeModulePkg/Library/BaseSpiHcPlatformLibNull/BaseSpiHcPlatformLibNull.inf
[LibraryClasses.EBC.PEIM]
IoLib|MdePkg/Library/PeiIoLibCpuIo/PeiIoLibCpuIo.inf
@@ -287,6 +288,10 @@
MdeModulePkg/Bus/Pci/NonDiscoverablePciDeviceDxe/NonDiscoverablePciDeviceDxe.inf
MdeModulePkg/Bus/Spi/SpiNorFlashJedecSfdp/SpiNorFlashJedecSfdpDxe.inf
MdeModulePkg/Bus/Spi/SpiNorFlashJedecSfdp/SpiNorFlashJedecSfdpSmm.inf
+ MdeModulePkg/Bus/Spi/SpiBus/SpiBusDxe.inf
+ MdeModulePkg/Bus/Spi/SpiBus/SpiBusSmm.inf
+ MdeModulePkg/Bus/Spi/SpiHc/SpiHcDxe.inf
+ MdeModulePkg/Bus/Spi/SpiHc/SpiHcSmm.inf
MdeModulePkg/Core/DxeIplPeim/DxeIpl.inf
MdeModulePkg/Core/Pei/PeiMain.inf
@@ -526,6 +531,7 @@
MdeModulePkg/Library/TraceHubDebugSysTLib/BaseTraceHubDebugSysTLib.inf
MdeModulePkg/Library/TraceHubDebugSysTLib/PeiTraceHubDebugSysTLib.inf
MdeModulePkg/Library/TraceHubDebugSysTLib/DxeSmmTraceHubDebugSysTLib.inf
+ MdeModulePkg/Library/BaseSpiHcPlatformLibNull/BaseSpiHcPlatformLibNull.inf
[Components.X64]
MdeModulePkg/Universal/CapsulePei/CapsuleX64.inf
diff --git a/MdeModulePkg/Universal/Acpi/FirmwarePerformanceDataTablePei/FirmwarePerformancePei.c b/MdeModulePkg/Universal/Acpi/FirmwarePerformanceDataTablePei/FirmwarePerformancePei.c
index 2f2b2a80b2..2ba9215226 100644
--- a/MdeModulePkg/Universal/Acpi/FirmwarePerformanceDataTablePei/FirmwarePerformancePei.c
+++ b/MdeModulePkg/Universal/Acpi/FirmwarePerformanceDataTablePei/FirmwarePerformancePei.c
@@ -112,11 +112,15 @@ FpdtStatusCodeListenerPei (
//
S3ResumeTotal = MultU64x32 (AcpiS3ResumeRecord->AverageResume, AcpiS3ResumeRecord->ResumeCount);
AcpiS3ResumeRecord->ResumeCount++;
- AcpiS3ResumeRecord->AverageResume = DivU64x32 (S3ResumeTotal + AcpiS3ResumeRecord->FullResume, AcpiS3ResumeRecord->ResumeCount);
+ if (AcpiS3ResumeRecord->ResumeCount > 0) {
+ AcpiS3ResumeRecord->AverageResume = DivU64x32 (S3ResumeTotal + AcpiS3ResumeRecord->FullResume, AcpiS3ResumeRecord->ResumeCount);
+ DEBUG ((DEBUG_INFO, "\nFPDT: S3 Resume Performance - AverageResume = 0x%x\n", AcpiS3ResumeRecord->AverageResume));
+ } else {
+ DEBUG ((DEBUG_ERROR, "\nFPDT: S3 ResumeCount reaches the MAX_UINT32 value. S3 ResumeCount record reset to Zero."));
+ }
- DEBUG ((DEBUG_INFO, "FPDT: S3 Resume Performance - ResumeCount = %d\n", AcpiS3ResumeRecord->ResumeCount));
- DEBUG ((DEBUG_INFO, "FPDT: S3 Resume Performance - FullResume = %ld\n", AcpiS3ResumeRecord->FullResume));
- DEBUG ((DEBUG_INFO, "FPDT: S3 Resume Performance - AverageResume = %ld\n", AcpiS3ResumeRecord->AverageResume));
+ DEBUG ((DEBUG_INFO, "FPDT: S3 Resume Performance - ResumeCount = 0x%x\n", AcpiS3ResumeRecord->ResumeCount));
+ DEBUG ((DEBUG_INFO, "FPDT: S3 Resume Performance - FullResume = 0x%x\n", AcpiS3ResumeRecord->FullResume));
//
// Update S3 Suspend Performance Record.