mirror of https://github.com/acidanthera/audk.git
235 lines
7.7 KiB
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;
|
|
}
|