/** @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 #include #include #include #include #include #include #include #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; }