audk/MdeModulePkg/Bus/Spi/SpiNorFlashJedecSfdp/SpiNorFlashJedecSfdpDxe.c

262 lines
8.5 KiB
C

/** @file
SPI NOR Flash JEDEC Serial Flash Discoverable Parameters (SFDP)
DXE driver.
Copyright (C) 2024 Advanced Micro Devices, Inc. All rights reserved.
SPDX-License-Identifier: BSD-2-Clause-Patent
@par Revision Reference:
- JEDEC Standard, JESD216F.02
https://www.jedec.org/document_search?search_api_views_fulltext=JESD216
@par Glossary:
- SFDP - Serial Flash Discoverable Parameters
- PTP - Parameter Table Pointer
**/
#include <Base.h>
#include <Library/DebugLib.h>
#include <Library/MemoryAllocationLib.h>
#include <Library/UefiBootServicesTableLib.h>
#include <Protocol/SpiConfiguration.h>
#include <Protocol/SpiNorFlash.h>
#include <Protocol/SpiIo.h>
#include <IndustryStandard/SpiNorFlashJedecSfdp.h>
#include "SpiNorFlash.h"
#include "SpiNorFlashJedecSfdpInternal.h"
/**
Function to create SPI_NOR_FLASH_INSTANCE for this SPI part.
@param[in] SpiIoHandle The handle with SPI I/O protocol installed.
@retval EFI_SUCCESS Succeed.
@retval EFI_OUT_OF_RESOURCES Not enough resource to create SPI_NOR_FLASH_INSTANCE.
@retval otherwise Fail to create SPI NOR Flash SFDP Instance
**/
EFI_STATUS
CreateSpiNorFlashSfdpInstance (
IN EFI_HANDLE SpiIoHandle
)
{
EFI_STATUS Status;
SPI_NOR_FLASH_INSTANCE *Instance;
// Allocate SPI_NOR_FLASH_INSTANCE Instance.
Instance = AllocateZeroPool (sizeof (SPI_NOR_FLASH_INSTANCE));
ASSERT (Instance != NULL);
if (Instance == NULL) {
return EFI_OUT_OF_RESOURCES;
}
// Locate the SPI IO Protocol
Status = gBS->HandleProtocol (
SpiIoHandle,
&gEdk2JedecSfdpSpiDxeDriverGuid,
(VOID **)&Instance->SpiIo
);
ASSERT_EFI_ERROR (Status);
if (EFI_ERROR (Status)) {
DEBUG ((DEBUG_ERROR, "%a: Fail to locate SPI I/O protocol\n", __func__));
FreePool (Instance);
} else {
Status = InitialSpiNorFlashSfdpInstance (Instance);
ASSERT_EFI_ERROR (Status);
if (EFI_ERROR (Status)) {
DEBUG ((DEBUG_ERROR, "%a: Fail to initial SPI_NOR_FLASH_INSTANCE.\n", __func__));
FreePool (Instance);
} else {
// Install SPI NOR Flash Protocol.
Status = gBS->InstallProtocolInterface (
&Instance->Handle,
&gEfiSpiNorFlashProtocolGuid,
EFI_NATIVE_INTERFACE,
&Instance->Protocol
);
if (EFI_ERROR (Status)) {
DEBUG ((DEBUG_ERROR, "%a: Fail to Install gEfiSpiNorFlashProtocolGuid protocol.\n", __func__));
FreePool (Instance);
}
}
}
return Status;
}
/**
Callback function executed when the EFI_SPI_IO_PROTOCOL
protocol interface is installed.
@param[in] Event Event whose notification function is being invoked.
@param[out] Context Pointer to SPI I/O protocol GUID.
**/
VOID
EFIAPI
SpiIoProtocolInstalledCallback (
IN EFI_EVENT Event,
OUT VOID *Context
)
{
EFI_STATUS Status;
UINTN InstanceBufferSize;
EFI_HANDLE InstanceBuffer;
DEBUG ((DEBUG_INFO, "%a: Entry.\n", __func__));
InstanceBufferSize = sizeof (EFI_HANDLE);
Status = gBS->LocateHandle (
ByRegisterNotify,
(EFI_GUID *)Context,
NULL,
&InstanceBufferSize,
&InstanceBuffer
);
if (EFI_ERROR (Status)) {
DEBUG ((DEBUG_ERROR, "Can't locate SPI I/O protocol.\n"));
DEBUG ((DEBUG_INFO, "%a: Exit.\n", __func__));
return;
}
CreateSpiNorFlashSfdpInstance (InstanceBuffer);
DEBUG ((DEBUG_INFO, "%a: Exit.\n", __func__));
return;
}
/**
Register for the later installed SPI I/O protocol notification.
@retval EFI_SUCCESS Succeed.
@retval otherwise Fail to register SPI I/O protocol installed
notification.
**/
EFI_STATUS
RegisterSpioProtocolNotification (
VOID
)
{
EFI_EVENT Event;
EFI_STATUS Status;
VOID *Registration;
Status = gBS->CreateEvent (
EVT_NOTIFY_SIGNAL,
TPL_CALLBACK,
SpiIoProtocolInstalledCallback,
NULL,
&Event
);
if (EFI_ERROR (Status)) {
DEBUG ((DEBUG_ERROR, "%a: Fail to create event for the SPI I/O Protocol installation.", __func__));
return Status;
}
Status = gBS->RegisterProtocolNotify (
&gEdk2JedecSfdpSpiDxeDriverGuid,
Event,
&Registration
);
if (EFI_ERROR (Status)) {
DEBUG ((DEBUG_ERROR, "%a: Fail to register event for the SPI I/O Protocol installation.", __func__));
} else {
DEBUG ((DEBUG_INFO, "%a: Notification for SPI I/O Protocol installation was registered.", __func__));
}
return Status;
}
/**
Entry point of the Macronix SPI NOR Flash driver.
@param ImageHandle Image handle of this driver.
@param SystemTable Pointer to standard EFI system table.
@retval EFI_SUCCESS Succeed.
@retval EFI_NOT_FOUND No gEdk2JedecSfdpSpiSmmDriverGuid installed on
system yet.
@retval EFI_OUT_OF_RESOURCES Not enough resource for SPI NOR Flash JEDEC SFDP
initialization.
@retval Otherwise Other errors.
**/
EFI_STATUS
EFIAPI
SpiNorFlashJedecSfdpDxeEntry (
IN EFI_HANDLE ImageHandle,
IN EFI_SYSTEM_TABLE *SystemTable
)
{
EFI_STATUS Status;
EFI_HANDLE *InstanceBuffer;
UINTN InstanceIndex;
UINTN InstanceBufferSize;
DEBUG ((DEBUG_INFO, "%a - ENTRY\n", __func__));
//
// Register notification for the later SPI I/O protocol installation.
//
RegisterSpioProtocolNotification ();
DEBUG ((DEBUG_INFO, "Check if there were already some gEdk2JedecSfdpSpiDxeDriverGuid handles installed.\n"));
//
// Check if there were already some gEdk2JedecSfdpSpiDxeDriverGuid
// handles installed.
//
// Locate the SPI I/O Protocol for the SPI flash part
// that supports JEDEC SFDP specification.
//
InstanceBufferSize = 0;
InstanceBuffer = NULL;
Status = gBS->LocateHandle (
ByProtocol,
&gEdk2JedecSfdpSpiDxeDriverGuid,
NULL,
&InstanceBufferSize,
InstanceBuffer
);
if (Status == EFI_NOT_FOUND) {
DEBUG ((
DEBUG_INFO,
"No gEdk2JedecSfdpSpiSmmDriverGuid handles found at the moment, wait for the notification of SPI I/O protocol installation.\n"
));
DEBUG ((DEBUG_INFO, "%a: EXIT - Status=%r\n", __func__, Status));
return EFI_SUCCESS;
} else if (Status == EFI_BUFFER_TOO_SMALL) {
InstanceBuffer = (EFI_HANDLE *)AllocateZeroPool (InstanceBufferSize);
ASSERT (InstanceBuffer != NULL);
if (InstanceBuffer == NULL) {
DEBUG ((DEBUG_ERROR, "Not enough resource for gEdk2JedecSfdpSpiDxeDriverGuid handles.\n"));
DEBUG ((DEBUG_INFO, "%a: EXIT - Status=%r\n", __func__, Status));
return EFI_OUT_OF_RESOURCES;
}
} else if (EFI_ERROR (Status)) {
DEBUG ((DEBUG_ERROR, "Error to locate gEdk2JedecSfdpSpiDxeDriverGuid - Status = %r.\n", Status));
DEBUG ((DEBUG_INFO, "%a: EXIT - Status=%r\n", __func__, Status));
return Status;
}
Status = gBS->LocateHandle (
ByProtocol,
&gEdk2JedecSfdpSpiDxeDriverGuid,
NULL,
&InstanceBufferSize,
InstanceBuffer
);
if (EFI_ERROR (Status)) {
DEBUG ((DEBUG_ERROR, "Fail to locate all gEdk2JedecSfdpSpiDxeDriverGuid handles.\n"));
DEBUG ((DEBUG_INFO, "%a: EXIT - Status=%r\n", __func__, Status));
return Status;
}
DEBUG ((DEBUG_INFO, "%d of gEdk2JedecSfdpSpiDxeDriverGuid are found.\n", InstanceBufferSize / sizeof (EFI_HANDLE)));
for (InstanceIndex = 0; InstanceIndex < InstanceBufferSize / sizeof (EFI_HANDLE); InstanceIndex++) {
Status = CreateSpiNorFlashSfdpInstance (*(InstanceBuffer + InstanceIndex));
if (EFI_ERROR (Status)) {
DEBUG ((DEBUG_ERROR, "Fail to create SPI NOR Flash SFDP instance #%d.\n", InstanceIndex));
}
}
DEBUG ((DEBUG_INFO, "%a: EXIT - Status=%r\n", __func__, Status));
return Status;
}