/** @file
SPI bus DXE 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 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;
}