MdeModulePkg: SpiHc: SpiHc Drivers

Added SpiHc DXE and SMM drivers. This code receives bus transactions
from the SpiBus layer and passes them onto the SpiHcPlatformLib

Platform Initialization Spec 1.7 volume 5 section 18.1.7

Bugzilla #4753

Cc: Abner Chang <abner.chang@amd.com>
Cc: Abdul Lateef Attar <AbdulLateef.Attar@amd.com>
Signed-off-by: Brit Chesley <brit.chesley@amd.com>
Reviewed-by: Abner Chang <abner.chang@amd.com>
diff --git a/MdeModulePkg/Bus/Spi/SpiHc/SpiHc.c b/MdeModulePkg/Bus/Spi/SpiHc/SpiHc.c
new file mode 100644
index 0000000..9d7bf9f
--- /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 0000000..c6e4c58
--- /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 0000000..9fab0a7
--- /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 0000000..d0e9827
--- /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 0000000..b71f153
--- /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 0000000..adebff9
--- /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 0000000..95d5466
--- /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