public inbox for devel@edk2.groups.io
 help / color / mirror / Atom feed
From: "Chang, Abner via groups.io" <abner.chang=amd.com@groups.io>
To: "Chesley, Brit" <Brit.Chesley@amd.com>,
	"devel@edk2.groups.io" <devel@edk2.groups.io>
Cc: "Attar, AbdulLateef (Abdul Lateef)" <AbdulLateef.Attar@amd.com>
Subject: Re: [edk2-devel] [PATCH v1 2/6] MdeModulePkg/Bus/Spi/SpiBus: Adding SpiBus Drivers
Date: Thu, 2 May 2024 04:24:22 +0000	[thread overview]
Message-ID: <LV8PR12MB945232ECE230661EAA02F23FEA182@LV8PR12MB9452.namprd12.prod.outlook.com> (raw)
In-Reply-To: <20240501190527.200937-3-brit.chesley@amd.com>

[AMD Official Use Only - General]

We had reviewed this patch internally before sending this to community.
Reviewed-by: Abner Chang <abner.chang@amd.com>

> -----Original Message-----
> From: Chesley, Brit <Brit.Chesley@amd.com>
> Sent: Thursday, May 2, 2024 3:05 AM
> To: devel@edk2.groups.io
> Cc: Chang, Abner <Abner.Chang@amd.com>; Attar, AbdulLateef (Abdul
> Lateef) <AbdulLateef.Attar@amd.com>
> Subject: [PATCH v1 2/6] MdeModulePkg/Bus/Spi/SpiBus: Adding SpiBus
> Drivers
>
> From: Brit Chesley <brit.chesley@amd.com>
>
> Added SpiBus DXE and SMM drivers. This code translates SPI requests from
> the application layer into SPI Bus transactions on the SPI host
> controller. The code is responsible for checking if the transaction is
> valid, then setting up the SPI clock and chip select properly before
> passing the bus transaction to the host controller.
>
> Platform Initialization Spec 1.7 volume 5 section 18.1.6
>
> 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>
> ---
>  MdeModulePkg/Bus/Spi/SpiBus/SpiBusDxe.inf |  41 ++
>  MdeModulePkg/Bus/Spi/SpiBus/SpiBusSmm.inf |  41 ++
>  MdeModulePkg/Bus/Spi/SpiBus/SpiBus.h      | 167 +++++++++
>  MdeModulePkg/Bus/Spi/SpiBus/SpiBus.c      | 433
> ++++++++++++++++++++++
>  MdeModulePkg/Bus/Spi/SpiBus/SpiBusDxe.c   | 198 ++++++++++
>  MdeModulePkg/Bus/Spi/SpiBus/SpiBusSmm.c   | 162 ++++++++
>  MdeModulePkg/Bus/Spi/SpiBus/SpiBus.uni    |  10 +
>  7 files changed, 1052 insertions(+)
>  create mode 100644 MdeModulePkg/Bus/Spi/SpiBus/SpiBusDxe.inf
>  create mode 100644 MdeModulePkg/Bus/Spi/SpiBus/SpiBusSmm.inf
>  create mode 100644 MdeModulePkg/Bus/Spi/SpiBus/SpiBus.h
>  create mode 100644 MdeModulePkg/Bus/Spi/SpiBus/SpiBus.c
>  create mode 100644 MdeModulePkg/Bus/Spi/SpiBus/SpiBusDxe.c
>  create mode 100644 MdeModulePkg/Bus/Spi/SpiBus/SpiBusSmm.c
>  create mode 100644 MdeModulePkg/Bus/Spi/SpiBus/SpiBus.uni
>
> diff --git a/MdeModulePkg/Bus/Spi/SpiBus/SpiBusDxe.inf
> b/MdeModulePkg/Bus/Spi/SpiBus/SpiBusDxe.inf
> new file mode 100644
> index 000000000000..3e2cc2daba1c
> --- /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.inf
> b/MdeModulePkg/Bus/Spi/SpiBus/SpiBusSmm.inf
> new file mode 100644
> index 000000000000..9e3a5aae7d87
> --- /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/SpiBus/SpiBus.h
> b/MdeModulePkg/Bus/Spi/SpiBus/SpiBus.h
> new file mode 100644
> index 000000000000..7a43f66ac750
> --- /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.c
> b/MdeModulePkg/Bus/Spi/SpiBus/SpiBus.c
> new file mode 100644
> index 000000000000..b183ca182cab
> --- /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/SpiBusDxe.c
> b/MdeModulePkg/Bus/Spi/SpiBus/SpiBusDxe.c
> new file mode 100644
> index 000000000000..cd0a2c99a27b
> --- /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/SpiBusSmm.c
> b/MdeModulePkg/Bus/Spi/SpiBus/SpiBusSmm.c
> new file mode 100644
> index 000000000000..d9189b984835
> --- /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/SpiBus.uni
> b/MdeModulePkg/Bus/Spi/SpiBus/SpiBus.uni
> new file mode 100644
> index 000000000000..0d913bdbae39
> --- /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"
> --
> 2.42.1



-=-=-=-=-=-=-=-=-=-=-=-
Groups.io Links: You receive all messages sent to this group.
View/Reply Online (#118493): https://edk2.groups.io/g/devel/message/118493
Mute This Topic: https://groups.io/mt/105849135/7686176
Group Owner: devel+owner@edk2.groups.io
Unsubscribe: https://edk2.groups.io/g/devel/unsub [rebecca@openfw.io]
-=-=-=-=-=-=-=-=-=-=-=-



  reply	other threads:[~2024-05-02  4:24 UTC|newest]

Thread overview: 19+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2024-05-01 19:05 [edk2-devel] [PATCH v1 0/6] SPI Driver Stack Chesley, Brit via groups.io
2024-05-01 19:05 ` [edk2-devel] [PATCH v1 1/6] MdePkg/SpiConfiguration: Correct the definition spelling Chesley, Brit via groups.io
2024-05-02  4:20   ` Chang, Abner via groups.io
2024-05-01 19:05 ` [edk2-devel] [PATCH v1 2/6] MdeModulePkg/Bus/Spi/SpiBus: Adding SpiBus Drivers Chesley, Brit via groups.io
2024-05-02  4:24   ` Chang, Abner via groups.io [this message]
2024-05-01 19:05 ` [edk2-devel] [PATCH v1 3/6] MdeModulePkg: " Chesley, Brit via groups.io
2024-05-02  4:24   ` Chang, Abner via groups.io
2024-05-06 11:08   ` Chang, Abner via groups.io
2024-05-07  2:50     ` [edk2-devel] 回复: " gaoliming via groups.io
2024-05-01 19:05 ` [edk2-devel] [PATCH v1 4/6] MdeModulePkg:BaseSpiHcPlatformLib: Adding NULL lib instance Chesley, Brit via groups.io
2024-05-02  4:25   ` Chang, Abner via groups.io
2024-05-06 11:08   ` Chang, Abner via groups.io
2024-05-07  2:50     ` [edk2-devel] 回复: " gaoliming via groups.io
2024-05-01 19:05 ` [edk2-devel] [PATCH v1 5/6] MdeModulePkg: SpiHc: SpiHc Drivers Chesley, Brit via groups.io
2024-05-02  4:25   ` Chang, Abner via groups.io
2024-05-01 19:05 ` [edk2-devel] [PATCH v1 6/6] MdeModulePkg: Adding " Chesley, Brit via groups.io
2024-05-02  4:25   ` Chang, Abner via groups.io
2024-05-06 11:08   ` Chang, Abner via groups.io
2024-05-07  2:51     ` [edk2-devel] 回复: " gaoliming via groups.io

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-list from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=LV8PR12MB945232ECE230661EAA02F23FEA182@LV8PR12MB9452.namprd12.prod.outlook.com \
    --to=devel@edk2.groups.io \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox