/** @file
SPI bus SMM driver
Copyright (C) 2024 Advanced Micro Devices, Inc. All rights reserved.
SPDX-License-Identifier: BSD-2-Clause-Patent
**/
#include
#include
#include
#include
#include
#include
#include
#include
#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;
}