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

235 lines
7.7 KiB
C

/** @file
SPI NOR Flash JEDEC Serial Flash Discoverable Parameters (SFDP)
SMM 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/SmmServicesTableLib.h>
#include <Protocol/SpiSmmConfiguration.h>
#include <Protocol/SpiSmmNorFlash.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 = gSmst->SmmHandleProtocol (
SpiIoHandle,
&gEdk2JedecSfdpSpiSmmDriverGuid,
(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 = gSmst->SmmInstallProtocolInterface (
&Instance->Handle,
&gEfiSpiSmmNorFlashProtocolGuid,
EFI_NATIVE_INTERFACE,
&Instance->Protocol
);
if (EFI_ERROR (Status)) {
DEBUG ((DEBUG_ERROR, "%a: Fail to Install gEfiSpiSmmNorFlashProtocolGuid protocol.\n", __func__));
FreePool (Instance);
}
}
}
return Status;
}
/**
Callback function executed when the EFI_SPI_IO_PROTOCOL
protocol interface is installed.
@param[in] Protocol Points to the protocol's unique identifier.
@param[in] Interface Points to the interface instance.
@param[in] Handle The handle on which the interface was installed.
@return Status Code
**/
EFI_STATUS
EFIAPI
SpiIoProtocolInstalledCallback (
IN CONST EFI_GUID *Protocol,
IN VOID *Interface,
IN EFI_HANDLE Handle
)
{
EFI_STATUS Status;
DEBUG ((DEBUG_INFO, "%a: Entry.\n", __func__));
Status = CreateSpiNorFlashSfdpInstance (Handle);
return Status;
}
/**
Register notification for the later installed SPI I/O protocol.
@retval EFI_SUCCESS Succeed.
@retval otherwise Fail to register the notification of
SPI I/O protocol installation.
**/
EFI_STATUS
RegisterSpioProtocolNotification (
VOID
)
{
EFI_STATUS Status;
VOID *Registration;
Status = gSmst->SmmRegisterProtocolNotify (
&gEdk2JedecSfdpSpiSmmDriverGuid,
SpiIoProtocolInstalledCallback,
&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 SPI NOR Flash SFDP SMM 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
SpiNorFlashJedecSfdpSmmEntry (
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 gEdk2JedecSfdpSpiSmmDriverGuid handles installed.\n"));
//
// Check if there were already some gEdk2JedecSfdpSpiSmmDriverGuid
// handles installed.
//
// Locate the SPI I/O Protocol for the SPI flash part
// that supports JEDEC SFDP specification.
//
InstanceBufferSize = 0;
InstanceBuffer = NULL;
Status = gSmst->SmmLocateHandle (
ByProtocol,
&gEdk2JedecSfdpSpiSmmDriverGuid,
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 gEdk2JedecSfdpSpiSmmDriverGuid 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 gEdk2JedecSfdpSpiSmmDriverGuid - Status = %r.\n", Status));
DEBUG ((DEBUG_INFO, "%a: EXIT - Status=%r\n", __func__, Status));
return Status;
}
Status = gSmst->SmmLocateHandle (
ByProtocol,
&gEdk2JedecSfdpSpiSmmDriverGuid,
NULL,
&InstanceBufferSize,
InstanceBuffer
);
if (EFI_ERROR (Status)) {
DEBUG ((DEBUG_ERROR, "Fail to locate all gEdk2JedecSfdpSpiSmmDriverGuid handles.\n"));
DEBUG ((DEBUG_INFO, "%a: EXIT - Status=%r\n", __func__, Status));
return Status;
}
DEBUG ((DEBUG_INFO, "%d of gEdk2JedecSfdpSpiSmmDriverGuid handles 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;
}