summaryrefslogtreecommitdiffstats
path: root/MdeModulePkg/Bus/Spi/SpiNorFlashJedecSfdp/SpiNorFlashJedecSfdpDxe.c
diff options
context:
space:
mode:
Diffstat (limited to 'MdeModulePkg/Bus/Spi/SpiNorFlashJedecSfdp/SpiNorFlashJedecSfdpDxe.c')
-rw-r--r--MdeModulePkg/Bus/Spi/SpiNorFlashJedecSfdp/SpiNorFlashJedecSfdpDxe.c261
1 files changed, 261 insertions, 0 deletions
diff --git a/MdeModulePkg/Bus/Spi/SpiNorFlashJedecSfdp/SpiNorFlashJedecSfdpDxe.c b/MdeModulePkg/Bus/Spi/SpiNorFlashJedecSfdp/SpiNorFlashJedecSfdpDxe.c
new file mode 100644
index 0000000000..d8b86ddd8a
--- /dev/null
+++ b/MdeModulePkg/Bus/Spi/SpiNorFlashJedecSfdp/SpiNorFlashJedecSfdpDxe.c
@@ -0,0 +1,261 @@
+/** @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;
+}