From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from mail02.groups.io (mail02.groups.io [66.175.222.108]) by spool.mail.gandi.net (Postfix) with ESMTPS id 8B3409413EC for ; Thu, 4 Apr 2024 09:11:30 +0000 (UTC) DKIM-Signature: a=rsa-sha256; bh=H/q5gTm8EpM6A8TEEAj6SqMsRl1HtXzap8pvkFmulBg=; c=relaxed/simple; d=groups.io; h=Received-SPF:From:To:CC:Subject:Date:Message-ID:In-Reply-To:References:MIME-Version:Precedence:List-Subscribe:List-Help:Sender:List-Id:Mailing-List:Delivered-To:Resent-Date:Resent-From:Reply-To:List-Unsubscribe-Post:List-Unsubscribe:Content-Transfer-Encoding:Content-Type; s=20240206; t=1712221889; v=1; b=UWmI2avzwj83Xl5Tz+h1sAQwHyolQbTeZ23ACuP2VCkw9L3n3hf8TrIac/TxbnLhxy/tOzAr x/Wsa8/ohh8j/BLAKwrHECpj/wzLNZTqWZ5RQ8d4BGihkYyCj3c4/1v3gNR5gW4kZ6oFUfUorg0 up2MJJOoTeOXuPZD/r2igOuDhxXeGfO4YfIX+/Gj8oEgdVxQKFiBAIOcSdjeEkkSuECj1PCTpBk FsL6OtuIU9ukOkgU1yXajgPzoCOcNG9FBEMiM5D19huDRE0FZbf7yeVJFu+73CAuqO8a4jG1JA4 I1YIzKi6ryLkvdwEmNej5a9jdtXWAbF/1nKM6G7J3YG0w== X-Received: by 127.0.0.2 with SMTP id RAXiYY7687511xkUByFJTYp6; Thu, 04 Apr 2024 02:11:29 -0700 X-Received: from NAM12-BN8-obe.outbound.protection.outlook.com (NAM12-BN8-obe.outbound.protection.outlook.com [40.107.237.44]) by mx.groups.io with SMTP id smtpd.web11.33683.1712221888027610119 for ; Thu, 04 Apr 2024 02:11:28 -0700 X-Received: from MN2PR19CA0022.namprd19.prod.outlook.com (2603:10b6:208:178::35) by SJ2PR12MB8740.namprd12.prod.outlook.com (2603:10b6:a03:53f::16) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.20.7409.46; Thu, 4 Apr 2024 09:11:23 +0000 X-Received: from BN2PEPF000044AC.namprd04.prod.outlook.com (2603:10b6:208:178:cafe::a1) by MN2PR19CA0022.outlook.office365.com (2603:10b6:208:178::35) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.20.7409.46 via Frontend Transport; Thu, 4 Apr 2024 09:11:23 +0000 X-MS-Exchange-Authentication-Results: spf=pass (sender IP is 165.204.84.17) smtp.mailfrom=amd.com; dkim=none (message not signed) header.d=none;dmarc=pass action=none header.from=amd.com; Received-SPF: Pass (protection.outlook.com: domain of amd.com designates 165.204.84.17 as permitted sender) receiver=protection.outlook.com; client-ip=165.204.84.17; helo=SATLEXMB04.amd.com; pr=C X-Received: from SATLEXMB04.amd.com (165.204.84.17) by BN2PEPF000044AC.mail.protection.outlook.com (10.167.243.107) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256) id 15.20.7452.22 via Frontend Transport; Thu, 4 Apr 2024 09:11:22 +0000 X-Received: from TPE-L1-ABNCHANG.amd.com (10.180.168.240) by SATLEXMB04.amd.com (10.181.40.145) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256) id 15.1.2507.35; Thu, 4 Apr 2024 04:11:19 -0500 From: "Chang, Abner via groups.io" To: CC: Hao A Wu , Ray Ni , "Abdul Lateef Attar" , Brit Chesley Subject: [edk2-devel] [PATCH RESEND V4 4/6] MdeModulePkg/SpiNorFlashJedecSfdp: SPI NOR Flash JEDEC SFDP Date: Thu, 4 Apr 2024 17:10:50 +0800 Message-ID: <20240404091052.794-5-abner.chang@amd.com> In-Reply-To: <20240404091052.794-1-abner.chang@amd.com> References: <20240404091052.794-1-abner.chang@amd.com> MIME-Version: 1.0 X-Originating-IP: [10.180.168.240] X-ClientProxiedBy: SATLEXMB04.amd.com (10.181.40.145) To SATLEXMB04.amd.com (10.181.40.145) X-EOPAttributedMessage: 0 X-MS-PublicTrafficType: Email X-MS-TrafficTypeDiagnostic: BN2PEPF000044AC:EE_|SJ2PR12MB8740:EE_ X-MS-Office365-Filtering-Correlation-Id: 221785da-56d2-4a78-dea8-08dc548732e2 X-MS-Exchange-SenderADCheck: 1 X-MS-Exchange-AntiSpam-Relay: 0 X-Microsoft-Antispam-Message-Info: essSJdypgyuEcDkJ/KgD84Oc8GFifH9G7arV/Nrcy9ubuLa9KEo7cLIL//sQy32MlEeF+K8+ymKDRK8WM9T1cyQIV65tJKn5BBaYZLaskrW4TkunSZgjAXVKOleqAxtfDvBuzstLJ5uXvas582ROTTEq9Y4oTHy668PFZFUaRtSpmRr9CqdzyWMKBQ85FLT3CpMV/vPssGOQr8ZHlkn8ZtPSImSLZ/uiLeJffiV0nQA7tBbTrbWz9bOvQW/X23BrkFNxVv6kk3zNkkzIQ3ygX0HertC4Gl6QJAKGrFnM2p4J8gXIocN0gaM3Yj/NF1xf0YAduQqaw9tlXuJkPmhBssLU9jy6wgbMHKsgvNHITNaf1VIvXP/mUrpg8/jRBNyFhNRvcTyu4/4MnZLMDdsWHtMGO7/kujlMOykKTJI0j8zrkybgG0NcJ4hPMA5UEYkt7wby9Ka9yjuybhMWAlr2Ekt0Oo4D6ITnrYZEDoU/m1DY2vFVE6O9KthZdkjlSNjcBPTv5Kvu4HCEiHl/Do/M6nwSQOiWQWyVL4mMTP8h2GVV8lJkjsaG+xIlLnBKm9vMtG30P+604EcuFHwFo0hnwcQfkswFo0E1aRs6SO8318yMU9eHfcbUKOZdtpDTVH5ZyFzwYUl24SLIWUt13BRNj1HqTzCLmSyOqjm1/uohIaeawepiqB8Z/KNvmZQATnSDo7zNkfOBqSfXr9gbBAzZsA== X-OriginatorOrg: amd.com X-MS-Exchange-CrossTenant-OriginalArrivalTime: 04 Apr 2024 09:11:22.8471 (UTC) X-MS-Exchange-CrossTenant-Network-Message-Id: 221785da-56d2-4a78-dea8-08dc548732e2 X-MS-Exchange-CrossTenant-Id: 3dd8961f-e488-4e60-8e11-a82d994e183d X-MS-Exchange-CrossTenant-OriginalAttributedTenantConnectingIp: TenantId=3dd8961f-e488-4e60-8e11-a82d994e183d;Ip=[165.204.84.17];Helo=[SATLEXMB04.amd.com] X-MS-Exchange-CrossTenant-AuthSource: BN2PEPF000044AC.namprd04.prod.outlook.com X-MS-Exchange-CrossTenant-AuthAs: Anonymous X-MS-Exchange-CrossTenant-FromEntityHeader: HybridOnPrem X-MS-Exchange-Transport-CrossTenantHeadersStamped: SJ2PR12MB8740 Precedence: Bulk List-Subscribe: List-Help: Sender: devel@edk2.groups.io List-Id: Mailing-List: list devel@edk2.groups.io; contact devel+owner@edk2.groups.io Resent-Date: Thu, 04 Apr 2024 02:11:28 -0700 Resent-From: abner.chang@amd.com Reply-To: devel@edk2.groups.io,abner.chang@amd.com List-Unsubscribe-Post: List-Unsubscribe=One-Click List-Unsubscribe: X-Gm-Message-State: MvnRse6y4PsOZH28xe7h2wcTx7686176AA= Content-Transfer-Encoding: quoted-printable Content-Type: text/plain X-GND-Status: LEGIT Authentication-Results: spool.mail.gandi.net; dkim=pass header.d=groups.io header.s=20240206 header.b=UWmI2avz; dmarc=pass (policy=none) header.from=groups.io; spf=pass (spool.mail.gandi.net: domain of bounce@groups.io designates 66.175.222.108 as permitted sender) smtp.mailfrom=bounce@groups.io From: abnchang BZ#: 4471 SPI NOR Flash JEDEC Serial Flash Discoverable Driver implementation. Signed-off-by: Abner Chang Cc: Hao A Wu Cc: Ray Ni Cc: Abdul Lateef Attar Cc: Brit Chesley --- .../SpiNorFlashJedecSfdpDxe.inf | 64 + .../SpiNorFlashJedecSfdpSmm.inf | 64 + .../Spi/SpiNorFlashJedecSfdp/SpiNorFlash.h | 286 +++ .../SpiNorFlashJedecSfdpInternal.h | 299 +++ .../Spi/SpiNorFlashJedecSfdp/SpiNorFlash.c | 1141 +++++++++++ .../SpiNorFlashJedecSfdp.c | 1780 +++++++++++++++++ .../SpiNorFlashJedecSfdpDxe.c | 261 +++ .../SpiNorFlashJedecSfdpSmm.c | 234 +++ .../SpiNorFlashJedecSfdpDxe.uni | 13 + .../SpiNorFlashJedecSfdpExtra.uni | 11 + .../SpiNorFlashJedecSfdpSmm.uni | 13 + 11 files changed, 4166 insertions(+) create mode 100644 MdeModulePkg/Bus/Spi/SpiNorFlashJedecSfdp/SpiNorFlashJe= decSfdpDxe.inf create mode 100644 MdeModulePkg/Bus/Spi/SpiNorFlashJedecSfdp/SpiNorFlashJe= decSfdpSmm.inf create mode 100644 MdeModulePkg/Bus/Spi/SpiNorFlashJedecSfdp/SpiNorFlash.h create mode 100644 MdeModulePkg/Bus/Spi/SpiNorFlashJedecSfdp/SpiNorFlashJe= decSfdpInternal.h create mode 100644 MdeModulePkg/Bus/Spi/SpiNorFlashJedecSfdp/SpiNorFlash.c create mode 100644 MdeModulePkg/Bus/Spi/SpiNorFlashJedecSfdp/SpiNorFlashJe= decSfdp.c create mode 100644 MdeModulePkg/Bus/Spi/SpiNorFlashJedecSfdp/SpiNorFlashJe= decSfdpDxe.c create mode 100644 MdeModulePkg/Bus/Spi/SpiNorFlashJedecSfdp/SpiNorFlashJe= decSfdpSmm.c create mode 100644 MdeModulePkg/Bus/Spi/SpiNorFlashJedecSfdp/SpiNorFlashJe= decSfdpDxe.uni create mode 100644 MdeModulePkg/Bus/Spi/SpiNorFlashJedecSfdp/SpiNorFlashJe= decSfdpExtra.uni create mode 100644 MdeModulePkg/Bus/Spi/SpiNorFlashJedecSfdp/SpiNorFlashJe= decSfdpSmm.uni diff --git a/MdeModulePkg/Bus/Spi/SpiNorFlashJedecSfdp/SpiNorFlashJedecSfdp= Dxe.inf b/MdeModulePkg/Bus/Spi/SpiNorFlashJedecSfdp/SpiNorFlashJedecSfdpDxe= .inf new file mode 100644 index 00000000000..26dbff3c8da --- /dev/null +++ b/MdeModulePkg/Bus/Spi/SpiNorFlashJedecSfdp/SpiNorFlashJedecSfdpDxe.inf @@ -0,0 +1,64 @@ +## @file +# The SPI NOR Flash JEDEC Serial Flash Discoverable Parameters (SFDP) +# DXE driver INF file. +# +# 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=3DJE= SD216 +# +# @par Glossary: +# - SFDP - Serial Flash Discoverable Parameters +# - PTP - Parameter Table Pointer +## + +[Defines] + INF_VERSION =3D 1.25 + BASE_NAME =3D SpiNorFlashJedecSfdpDxe + FILE_GUID =3D 0DC9C2C7-D450-41BA-9CF7-D2090C35A797 + MODULE_TYPE =3D DXE_DRIVER + VERSION_STRING =3D 0.1 + PI_SPECIFICATION_VERSION =3D 1.10 + ENTRY_POINT =3D SpiNorFlashJedecSfdpDxeEntry + MODULE_UNI_FILE =3D SpiNorFlashJedecSfdpDxe.uni + +[Packages] + MdePkg/MdePkg.dec + MdeModulePkg/MdeModulePkg.dec + +[LibraryClasses] + BaseLib + BaseMemoryLib + DebugLib + DevicePathLib + MemoryAllocationLib + TimerLib + UefiDriverEntryPoint + UefiBootServicesTableLib + +[Sources] + SpiNorFlashJedecSfdpDxe.c + SpiNorFlash.c + SpiNorFlashJedecSfdp.c + SpiNorFlashJedecSfdpInternal.h + SpiNorFlash.h + +[Protocols] + gEfiSpiNorFlashProtocolGuid ## PROCUDES + +[FixedPcd] + gEfiMdeModulePkgTokenSpaceGuid.PcdSpiNorFlashOperationRetryCount + gEfiMdeModulePkgTokenSpaceGuid.PcdSpiNorFlashFixedTimeoutRetryCount + gEfiMdeModulePkgTokenSpaceGuid.PcdSpiNorFlashOperationDelayMicroseconds + +[Guids] + gEdk2JedecSfdpSpiDxeDriverGuid + +[Depex] + gEdk2JedecSfdpSpiDxeDriverGuid + +[UserExtensions.TianoCore."ExtraFiles"] + SpiNorFlashJedecSfdpExtra.uni diff --git a/MdeModulePkg/Bus/Spi/SpiNorFlashJedecSfdp/SpiNorFlashJedecSfdp= Smm.inf b/MdeModulePkg/Bus/Spi/SpiNorFlashJedecSfdp/SpiNorFlashJedecSfdpSmm= .inf new file mode 100644 index 00000000000..89aceb0684d --- /dev/null +++ b/MdeModulePkg/Bus/Spi/SpiNorFlashJedecSfdp/SpiNorFlashJedecSfdpSmm.inf @@ -0,0 +1,64 @@ +## @file +# The SPI NOR Flash JEDEC Serial Flash Discoverable Parameters (SFDP) +# SMM driver INF file. +# +# 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=3DJE= SD216 +# +# @par Glossary: +# - SFDP - Serial Flash Discoverable Parameters +# - PTP - Parameter Table Pointer +## + +[Defines] + INF_VERSION =3D 1.25 + BASE_NAME =3D SpiNorFlashJedecSfdpSmm + FILE_GUID =3D AC7884C7-35A2-40AC-B9E0-AD67298E3BBA + MODULE_TYPE =3D DXE_SMM_DRIVER + VERSION_STRING =3D 0.1 + PI_SPECIFICATION_VERSION =3D 1.10 + ENTRY_POINT =3D SpiNorFlashJedecSfdpSmmEntry + MODULE_UNI_FILE =3D SpiNorFlashJedecSfdpSmm.uni + +[Packages] + MdePkg/MdePkg.dec + MdeModulePkg/MdeModulePkg.dec + +[LibraryClasses] + BaseLib + BaseMemoryLib + DebugLib + DevicePathLib + MemoryAllocationLib + SmmServicesTableLib + TimerLib + UefiDriverEntryPoint + +[Sources] + SpiNorFlashJedecSfdpSmm.c + SpiNorFlash.c + SpiNorFlashJedecSfdp.c + SpiNorFlashJedecSfdpInternal.h + SpiNorFlash.h + +[Protocols] + gEfiSpiSmmNorFlashProtocolGuid ## PROCUDES + +[FixedPcd] + gEfiMdeModulePkgTokenSpaceGuid.PcdSpiNorFlashOperationRetryCount + gEfiMdeModulePkgTokenSpaceGuid.PcdSpiNorFlashFixedTimeoutRetryCount + gEfiMdeModulePkgTokenSpaceGuid.PcdSpiNorFlashOperationDelayMicroseconds + +[Guids] + gEdk2JedecSfdpSpiSmmDriverGuid + +[Depex] + gEdk2JedecSfdpSpiSmmDriverGuid + +[UserExtensions.TianoCore."ExtraFiles"] + SpiNorFlashJedecSfdpExtra.uni diff --git a/MdeModulePkg/Bus/Spi/SpiNorFlashJedecSfdp/SpiNorFlash.h b/MdeM= odulePkg/Bus/Spi/SpiNorFlashJedecSfdp/SpiNorFlash.h new file mode 100644 index 00000000000..fb71e8d56f4 --- /dev/null +++ b/MdeModulePkg/Bus/Spi/SpiNorFlashJedecSfdp/SpiNorFlash.h @@ -0,0 +1,286 @@ +/** @file + Definitions of SPI NOR flash operation functions. + + Copyright (C) 2024 Advanced Micro Devices, Inc. All rights reserved. + + SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#ifndef SPI_NOR_FLASH_H_ +#define SPI_NOR_FLASH_H_ + +#include +#include +#include +#include "SpiNorFlashJedecSfdpInternal.h" + +/** + Fill Write Buffer with Opcode, Address, Dummy Bytes, and Data + + @param[in] Opcode - Opcode for transaction + @param[in] Address - SPI Offset Start Address + @param[in] WriteBytes - Number of bytes to write to SPI device + @param[in] WriteBuffer - Buffer containing bytes to write to SPI devi= ce + + @retval Size of Data in Buffer +**/ +UINT32 +FillWriteBuffer ( + IN SPI_NOR_FLASH_INSTANCE *SpiNorFlashInstance, + IN UINT8 Opcode, + IN UINT32 DummyBytes, + IN UINT8 AddressBytesSupported, + IN BOOLEAN UseAddress, + IN UINT32 Address, + IN UINT32 WriteBytes, + IN UINT8 *WriteBuffer + ); + +/** + Set Write Enable Latch + + @param[in] Instance SPI NOR instance with all protocols= , etc. + + @retval EFI_SUCCESS SPI Write Enable succeeded + @retval EFI_DEVICE_ERROR SPI Flash part did not respond properly +**/ +EFI_STATUS +SetWel ( + IN SPI_NOR_FLASH_INSTANCE *SpiNorFlashInstance + ); + +/** + Check for not device write in progress + + @param[in] Instance SPI NOR instance with all protocols, etc. + @param[in] Timeout Timeout in microsecond + @param[in] RetryCount The retry count + + @retval EFI_SUCCESS Device does not have a write in progress + @retval EFI_DEVICE_ERROR SPI Flash part did not respond properly +**/ +EFI_STATUS +WaitNotWip ( + IN SPI_NOR_FLASH_INSTANCE *SpiNorFlashInstance, + IN UINT32 Timeout, + IN UINT32 RetryCount + ); + +/** + Check for write enable latch set and not device write in progress + + @param[in] Instance SPI NOR instance with all protocols, etc. + @param[in] Timeout Timeout in microsecond + @param[in] RetryCount The retry count + + @retval EFI_SUCCESS Device does not have a write in progress a= nd + write enable latch is set + @retval EFI_DEVICE_ERROR SPI Flash part did not respond properly +**/ +EFI_STATUS +WaitWelNotWip ( + IN SPI_NOR_FLASH_INSTANCE *SpiNorFlashInstance, + IN UINT32 Timeout, + IN UINT32 RetryCount + ); + +/** + Check for not write enable latch set and not device write in progress + + @param[in] Instance SPI NOR instance with all protocols, etc. + @param[in] Timeout Timeout in microsecond + @param[in] RetryCount The retry count + + @retval EFI_SUCCESS Device does not have a write in progress a= nd + write enable latch is not set + @retval EFI_DEVICE_ERROR SPI Flash part did not respond properly +**/ +EFI_STATUS +WaitNotWelNotWip ( + IN SPI_NOR_FLASH_INSTANCE *SpiNorFlashInstance, + IN UINT32 Timeout, + IN UINT32 RetryCount + ); + +/** + Read the 3 byte manufacture and device ID from the SPI flash. + + This routine must be called at or below TPL_NOTIFY. + This routine reads the 3 byte manufacture and device ID from the flash p= art + filling the buffer provided. + + @param[in] This Pointer to an EFI_SPI_NOR_FLASH_PROTOCOL data struct= ure. + @param[out] Buffer Pointer to a 3 byte buffer to receive the manufactur= e and + device ID. + + + + @retval EFI_SUCCESS The manufacture and device ID was read + successfully. + @retval EFI_INVALID_PARAMETER Buffer is NULL + @retval EFI_DEVICE_ERROR Invalid data received from SPI flash part= . + +**/ +EFI_STATUS +EFIAPI +GetFlashId ( + IN CONST EFI_SPI_NOR_FLASH_PROTOCOL *This, + OUT UINT8 *Buffer + ); + +/** + Read data from the SPI flash. + + This routine must be called at or below TPL_NOTIFY. + This routine reads data from the SPI part in the buffer provided. + + @param[in] This Pointer to an EFI_SPI_NOR_FLASH_PROTOCOL data + structure. + @param[in] FlashAddress Address in the flash to start reading + @param[in] LengthInBytes Read length in bytes + @param[out] Buffer Address of a buffer to receive the data + + @retval EFI_SUCCESS The data was read successfully. + @retval EFI_INVALID_PARAMETER Buffer is NULL, or + FlashAddress >=3D This->FlashSize, or + LengthInBytes > This->FlashSize - FlashAd= dress + +**/ +EFI_STATUS +EFIAPI +ReadData ( + IN CONST EFI_SPI_NOR_FLASH_PROTOCOL *This, + IN UINT32 FlashAddress, + IN UINT32 LengthInBytes, + OUT UINT8 *Buffer + ); + +/** + Read data from the SPI flash at not fast speed + + This routine must be called at or below TPL_NOTIFY. + This routine reads data from the SPI part in the buffer provided. + + @param[in] This Pointer to an EFI_SPI_NOR_FLASH_PROTOCOL data + structure. + @param[in] FlashAddress Address in the flash to start reading + @param[in] LengthInBytes Read length in bytes + @param[out] Buffer Address of a buffer to receive the data + + @retval EFI_SUCCESS The data was read successfully. + @retval EFI_INVALID_PARAMETER Buffer is NULL, or + FlashAddress >=3D This->FlashSize, or + LengthInBytes > This->FlashSize - FlashAd= dress + +**/ +EFI_STATUS +EFIAPI +LfReadData ( + IN CONST EFI_SPI_NOR_FLASH_PROTOCOL *This, + IN UINT32 FlashAddress, + IN UINT32 LengthInBytes, + OUT UINT8 *Buffer + ); + +/** + Read the flash status register. + + This routine must be called at or below TPL_NOTIFY. + This routine reads the flash part status register. + + @param[in] This Pointer to an EFI_SPI_NOR_FLASH_PROTOCOL data + structure. + @param[in] LengthInBytes Number of status bytes to read. + @param[out] FlashStatus Pointer to a buffer to receive the flash stat= us. + + @retval EFI_SUCCESS The status register was read successfully. + +**/ +EFI_STATUS +EFIAPI +ReadStatus ( + IN CONST EFI_SPI_NOR_FLASH_PROTOCOL *This, + IN UINT32 LengthInBytes, + OUT UINT8 *FlashStatus + ); + +/** + Write the flash status register. + + This routine must be called at or below TPL_N OTIFY. + This routine writes the flash part status register. + + @param[in] This Pointer to an EFI_SPI_NOR_FLASH_PROTOCOL data + structure. + @param[in] LengthInBytes Number of status bytes to write. + @param[in] FlashStatus Pointer to a buffer containing the new status. + + @retval EFI_SUCCESS The status write was successful. + @retval EFI_OUT_OF_RESOURCES Failed to allocate the write buffer. + +**/ +EFI_STATUS +EFIAPI +WriteStatus ( + IN CONST EFI_SPI_NOR_FLASH_PROTOCOL *This, + IN UINT32 LengthInBytes, + IN UINT8 *FlashStatus + ); + +/** + Write data to the SPI flash. + + This routine must be called at or below TPL_NOTIFY. + This routine breaks up the write operation as necessary to write the dat= a to + the SPI part. + + @param[in] This Pointer to an EFI_SPI_NOR_FLASH_PROTOCOL data + structure. + @param[in] FlashAddress Address in the flash to start writing + @param[in] LengthInBytes Write length in bytes + @param[in] Buffer Address of a buffer containing the data + + @retval EFI_SUCCESS The data was written successfully. + @retval EFI_INVALID_PARAMETER Buffer is NULL, or + FlashAddress >=3D This->FlashSize, or + LengthInBytes > This->FlashSize - FlashAd= dress + @retval EFI_OUT_OF_RESOURCES Insufficient memory to copy buffer. + +**/ +EFI_STATUS +EFIAPI +WriteData ( + IN CONST EFI_SPI_NOR_FLASH_PROTOCOL *This, + IN UINT32 FlashAddress, + IN UINT32 LengthInBytes, + IN UINT8 *Buffer + ); + +/** + Efficiently erases one or more 4KiB regions in the SPI flash. + + This routine must be called at or below TPL_NOTIFY. + This routine uses a combination of 4 KiB and larger blocks to erase the + specified area. + + @param[in] This Pointer to an EFI_SPI_NOR_FLASH_PROTOCOL data + structure. + @param[in] FlashAddress Address within a 4 KiB block to start erasing + @param[in] BlockCount Number of 4 KiB blocks to erase + + @retval EFI_SUCCESS The erase was completed successfully. + @retval EFI_INVALID_PARAMETER FlashAddress >=3D This->FlashSize, or + BlockCount * 4 KiB + > This->FlashSize - FlashAddress + +**/ +EFI_STATUS +EFIAPI +Erase ( + IN CONST EFI_SPI_NOR_FLASH_PROTOCOL *This, + IN UINT32 FlashAddress, + IN UINT32 BlockCount + ); + +#endif // SPI_NOR_FLASH_H_ diff --git a/MdeModulePkg/Bus/Spi/SpiNorFlashJedecSfdp/SpiNorFlashJedecSfdp= Internal.h b/MdeModulePkg/Bus/Spi/SpiNorFlashJedecSfdp/SpiNorFlashJedecSfdp= Internal.h new file mode 100644 index 00000000000..309d8dcea70 --- /dev/null +++ b/MdeModulePkg/Bus/Spi/SpiNorFlashJedecSfdp/SpiNorFlashJedecSfdpInterna= l.h @@ -0,0 +1,299 @@ +/** @file + SPI NOR flash driver internal definitions. + + Copyright (C) 2024 Advanced Micro Devices, Inc. All rights reserved. + + SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#ifndef SPI_NOR_FLASH_INSTANCE_H_ +#define SPI_NOR_FLASH_INSTANCE_H_ + +#include +#include +#include +#include + +#define SPI_NOR_FLASH_SIGNATURE SIGNATURE_32 ('s', 'n', 'f', 'm') + +#define SPI_NOR_FLASH_FROM_THIS(a) CR (a, SPI_NOR_FLASH_INSTANCE, Protoco= l, SPI_NOR_FLASH_SIGNATURE) + +typedef struct { + LIST_ENTRY NextFastReadCap; ///< Link list to next Fast read capa= bility + UINT8 FastReadInstruction; ///< Fast read instruction. + UINT8 ModeClocks; ///< Fast read clock. + UINT8 WaitStates; ///< Fast read wait dummy clocks +} SFPD_FAST_READ_CAPBILITY_RECORD; + +typedef struct { + LIST_ENTRY NextEraseType; ///< Link list to next erase type. + UINT16 EraseType; ///< Erase type this flash device supp= orts. + UINT8 EraseInstruction; ///< Erase instruction + UINT32 EraseSizeInByte; ///< The size of byte in 2^EraseSize t= he erase type command + ///< can erase. + UINT32 EraseTypicalTime; ///< Time the device typically takes t= o erase this type + ///< size. + UINT64 EraseTimeout; ///< Maximum typical erase timeout. +} SFDP_SUPPORTED_ERASE_TYPE_RECORD; + +typedef enum { + SearchEraseTypeByType =3D 1, + SearchEraseTypeByCommand, + SearchEraseTypeBySize, + SearchEraseTypeBySmallestSize, + SearchEraseTypeByBiggestSize +} SFDP_SEARCH_ERASE_TYPE; + +typedef struct { + LIST_ENTRY NextCommand; ///< Lin= k list to next detection command. + UINT32 CommandAddress; ///< Add= ress to issue the command. + UINT8 CommandInstruction; ///< Det= ection command instruction. + UINT8 LatencyInClock; ///< Com= mand latency in clocks. + SPDF_CONFIGURATION_COMMAND_ADDR_LENGTH CommandAddressLength; ///< Add= dress length of detection command. + UINT8 ConfigurationBitMask; ///< The= interest bit of the byte data retunred + ///< aft= er sending the detection command. +} SFDP_SECTOR_MAP_DETECTION_RECORD; + +typedef struct { + LIST_ENTRY NextRegion; ///< Link= list to the next region. + UINT32 RegionAddress; ///< Regi= on starting address. + UINT32 RegionTotalSize; ///< Regi= on total size in bytes. + UINT32 RegionSectors; ///< Sect= ors in this region. + UINT32 SectorSize; ///< Sect= or size in byte (Minimum blcok erase size) + UINT8 SupportedEraseTypeNum; ///< Numb= er of erase type supported. + UINT8 SupportedEraseType[SFDP_ERASE_TYPES_NUMBER]; ///< Eras= e types supported. + UINT32 EraseTypeBySizeBitmap; ///< The = bitmap of supoprted srase block sizes. + ///< from= big to small. +} SFDP_SECTOR_REGION_RECORD; + +typedef struct { + LIST_ENTRY NextDescriptor; ///< Link= list to next flash map descriptor. + UINT8 ConfigurationId; ///< The = ID of this configuration. + UINT8 RegionCount; ///< The = regions of this sector map configuration. + LIST_ENTRY RegionList; ///< The = linked list of the regions. +} SFDP_SECTOR_MAP_RECORD; + +typedef struct { + UINTN Signature; + EFI_HANDLE Handle; + EFI_SPI_NOR_FLASH_PROTOCOL Protocol; + EFI_SPI_IO_PROTOCOL *SpiIo; + UINT32 SfdpBasicFlashByteCount; + UINT32 SfdpSectorMapByteCount; + SFDP_BASIC_FLASH_PARAMETER *SfdpBasicFlash; + SFDP_SECTOR_MAP_TABLE *SfdpFlashSectorMap; + UINT8 *SpiTransactionWriteBuffer; + UINT32 SpiTransactionWriteBufferIndex; + // + // SFDP information. + // + SFDP_HEADER SfdpHeader; ///< SFDP header. + UINT32 FlashDeviceSize; ///< The total si= ze of this flash device. + UINT8 CurrentAddressBytes; ///< The current = address bytes. + + // + // This is a linked list in which the Fast Read capability tables + // are linked from the low performance transfer to higher performance + // transfer. The SPI read would use the first Fast Read entry for + // SPI read operation. + // + LIST_ENTRY FastReadTableList; + + LIST_ENTRY SupportedEraseTypes; ///< The linked = list of supported erase types. + BOOLEAN Uniform4KEraseSupported; ///< The flash d= evice supoprts uniform 4K erase. + BOOLEAN WriteEnableLatchRequired; ///< Wether Writ= e Enable Latch is supported. + UINT8 WriteEnableLatchCommand; ///< Write Enabl= e Latch command. + // + // Below is the linked list of flash device sector + // map configuration detection command and map descriptors. + // + BOOLEAN ConfigurationCommandsNeeded; ///< Indicate= s whether sector map + ///< configur= ation detection is + ///< required= . + LIST_ENTRY ConfigurationCommandList; ///< The link= ed list of configuration + ///< detectio= n command sequence. + LIST_ENTRY ConfigurationMapList; ///< The link= ed list of configuration + ///< map desc= riptors. + SFDP_SECTOR_MAP_RECORD *CurrentSectorMap; ///< The curr= ent activated flash device + ///< sector m= ap. +} SPI_NOR_FLASH_INSTANCE; + +/** + This routine returns the desired Fast Read mode. + + @param[in] Instance Spi Nor Flash Instance dat= a with pointer to + EFI_SPI_NOR_FLASH_PROTOCOL= and EFI_SPI_IO_PROTOCOL + @param[in,out] FastReadInstruction Fast Read instruction, the= input is + the default value. + @param[in,out] FastReadOperationClock Fast Read operation clock,= the input is + the default value. + @param[in,out] FastReadDummyClocks Fast Read wait state (Dumm= y clocks), the + input is the default value= . + @retval EFI_SUCCESS The parameters are updated. + @retval EFI_NOT_FOUND No desired Fas Read mode found. + +**/ +EFI_STATUS +GetFastReadParameter ( + IN SPI_NOR_FLASH_INSTANCE *Instance, + IN OUT UINT8 *FastReadInstruction, + IN OUT UINT8 *FastReadOperationClock, + IN OUT UINT8 *FastReadDummyClocks + ); + +/** + Read SFDP parameters into buffer + + This routine reads the JEDEC SPI Flash Discoverable Parameters from the = SPI + chip. + + @param[in] Instance Spi Nor Flash Instance data with pointer to + EFI_SPI_NOR_FLASH_PROTOCOL and EFI_SPI_IO_PROTOCOL + + @retval EFI_SUCCESS The SPI part size is filled. + @retval EFI_DEVICE_ERROR Invalid data received from SPI flash part= . + +**/ +EFI_STATUS +ReadSfdpBasicParameterTable ( + IN SPI_NOR_FLASH_INSTANCE *Instance + ); + +/** + Read SFDP Sector Map Parameter into buffer + + This routine reads the JEDEC SPI Flash Discoverable Parameters from the = SPI + chip. + + @param[in] Instance Spi Nor Flash Instance data with pointer = to + EFI_SPI_NOR_FLASH_PROTOCOL and EFI_SPI_IO= _PROTOCOL + + @retval EFI_SUCCESS The SPI part size is filled. + @retval EFI_DEVICE_ERROR Invalid data received from SPI flash part= . + +**/ +EFI_STATUS +ReadSfdpSectorMapParameterTable ( + IN SPI_NOR_FLASH_INSTANCE *Instance + ); + +/** + Return flash device size from SFDP Basic Flash Parameter Table DWORD 2 + + @param[in] Instance Spi Nor Flash Instance data with pointer to + EFI_SPI_NOR_FLASH_PROTOCOL and + EFI_SPI_IO_PROTOCOL. + +* @retval UINT32 Flash device size in byte, zero indicates error. + +**/ +UINT32 +SfdpGetFlashSize ( + IN SPI_NOR_FLASH_INSTANCE *Instance + ); + +/** + Read SFDP + This routine reads the JEDEC SPI Flash Discoverable Parameters. We just + read the necessary tables in this routine. + + @param[in] Instance Spi Nor Flash Instance data with pointer to + EFI_SPI_NOR_FLASH_PROTOCOL and EFI_SPI_IO_PROTOC= OL + + @retval EFI_SUCCESS Header is filled in + @retval EFI_DEVICE_ERROR Invalid data received from SPI flash part= . + +**/ +EFI_STATUS +ReadSfdp ( + IN SPI_NOR_FLASH_INSTANCE *Instance + ); + +/** + Set EraseBlockBytes in SPI NOR Flash Protocol + + @param[in] Instance Spi Nor Flash Instance data with pointer to + EFI_SPI_NOR_FLASH_PROTOCOL and EFI_SPI_IO_PROTOC= OL + + @retval EFI_SUCCESS The erase block size is returned. + @retval Otherwise Failed to get erase block size. + +**/ +EFI_STATUS +SetSectorEraseBlockSize ( + IN SPI_NOR_FLASH_INSTANCE *Instance + ); + +/** + Get the erase block attribute for the target address. + + @param[in] Instance Spi Nor Flash Instance data with p= ointer to + EFI_SPI_NOR_FLASH_PROTOCOL and EFI= _SPI_IO_PROTOCOL + @param[in] FlashRegion The region the flash address belon= g. + @param[in] FlashAddress The target flash address. + @param[in] RemainingSize Remaining size to erase. + @param[in, out] BlockSizeToErase Input - The block erase size for = this continious blocks. + Output - The determined block size= for erasing. + @param[in, out] BlockCountToErase Input - The expected blocks to er= ase. + Output - The determined number of = blocks to erase. + @param[out] BlockEraseCommand The erase command used for this co= ntinious blocks. + @param[out] TypicalTime Pointer to receive the typical tim= e in millisecond + to erase this erase type size. + @param[out] MaximumTimeout Pointer to receive the maximum tim= eout in millisecond + to erase this erase type size. + @retval EFI_SUCCESS The erase block attribute is returned. + @retval EFI_DEVICE_ERROR No valid SFDP discovered. + @retval EFI_NOT_FOUND No valud erase block attribute found. + +**/ +EFI_STATUS +GetEraseBlockAttribute ( + IN SPI_NOR_FLASH_INSTANCE *Instance, + IN SFDP_SECTOR_REGION_RECORD *FlashRegion, + IN UINT32 FlashAddress, + IN UINT32 RemainingSize, + IN OUT UINT32 *BlockSizeToErase, + IN OUT UINT32 *BlockCountToErase, + OUT UINT8 *BlockEraseCommand, + OUT UINT32 *TypicalTime, + OUT UINT64 *MaximumTimeout + ); + +/** + Get the erase block attribute for the target address. + + @param[in] Instance Spi Nor Flash Instance data with po= inter to + EFI_SPI_NOR_FLASH_PROTOCOL and EFI_= SPI_IO_PROTOCOL + @param[in] FlashAddress The target flash address. + @param[out] FlashRegion The target flash address. + + @retval EFI_SUCCESS The region is returned. + @retval EFI_INVALID_PARAMETER FlashAddress is not belong to any region= . + @retval EFI_INVALID_PARAMETER Other errors. + +**/ +EFI_STATUS +GetRegionByFlashAddress ( + IN SPI_NOR_FLASH_INSTANCE *Instance, + IN UINT32 FlashAddress, + OUT SFDP_SECTOR_REGION_RECORD **FlashRegion + ); + +/** + Initial SPI_NOR_FLASH_INSTANCE structure. + + @param[in] Instance Pointer to SPI_NOR_FLASH_INSTANCE. + EFI_SPI_NOR_FLASH_PROTOCOL and EFI_= SPI_IO_PROTOCOL + + @retval EFI_SUCCESS SPI_NOR_FLASH_INSTANCE is initializ= ed according to + SPI NOR Flash SFDP specification. + @retval Otherwisw Failed to initial SPI_NOR_FLASH_INS= TANCE structure. + +**/ +EFI_STATUS +InitialSpiNorFlashSfdpInstance ( + IN SPI_NOR_FLASH_INSTANCE *Instance + ); + +#endif // SPI_NOR_FLASH_INSTANCE_H_ diff --git a/MdeModulePkg/Bus/Spi/SpiNorFlashJedecSfdp/SpiNorFlash.c b/MdeM= odulePkg/Bus/Spi/SpiNorFlashJedecSfdp/SpiNorFlash.c new file mode 100644 index 00000000000..066a827bf49 --- /dev/null +++ b/MdeModulePkg/Bus/Spi/SpiNorFlashJedecSfdp/SpiNorFlash.c @@ -0,0 +1,1141 @@ +/** @file + SPI NOR Flash operation functions. + + Copyright (C) 2024 Advanced Micro Devices, Inc. All rights reserved. + + SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include "SpiNorFlash.h" + +/** + Fill Write Buffer with Opcode, Address, Dummy Bytes, and Data + + @param[in] Instance The instance of SPI_NOR_FLASH + @param[in] Opcode Opcode for transaction + @param[in] DummyBytes The dummy bytes send to SPI flash d= evice + @param[in] AddressBytesSupported Bytes of address supported by SPI f= lash device + @param[in] UseAddress Send the address for SPI flash comm= and + @param[in] Address SPI Offset Start Address + @param[in] WriteBytes Number of bytes to write to SPI dev= ice + @param[in] WriteBuffer Buffer containing bytes to write to= SPI device + + @retval Size of Data in Buffer +**/ +UINT32 +FillWriteBuffer ( + IN SPI_NOR_FLASH_INSTANCE *Instance, + IN UINT8 Opcode, + IN UINT32 DummyBytes, + IN UINT8 AddressBytesSupported, + IN BOOLEAN UseAddress, + IN UINT32 Address, + IN UINT32 WriteBytes, + IN UINT8 *WriteBuffer + ) +{ + UINT32 AddressSize; + UINT32 BigEndianAddress; + UINT32 Index; + UINT8 SfdpAddressBytes; + + SfdpAddressBytes =3D (UINT8)Instance->SfdpBasicFlash->AddressBytes; + + // Copy Opcode into Write Buffer + Instance->SpiTransactionWriteBuffer[0] =3D Opcode; + Index =3D 1; + if (UseAddress) { + if (AddressBytesSupported =3D=3D SPI_ADDR_3BYTE_ONLY) { + if (SfdpAddressBytes !=3D 0) { + // Check if the supported address length is already initiated. + if ((SfdpAddressBytes !=3D SPI_ADDR_3BYTE_ONLY) && (SfdpAddressByt= es !=3D SPI_ADDR_3OR4BYTE)) { + DEBUG ((DEBUG_ERROR, "%a: Unsupported Address Bytes: 0x%x, SFDP = is: 0x%x\n", __func__, AddressBytesSupported, SfdpAddressBytes)); + ASSERT (FALSE); + } + } + + AddressSize =3D 3; + } else if (AddressBytesSupported =3D=3D SPI_ADDR_4BYTE_ONLY) { + if (SfdpAddressBytes !=3D 0) { + // Check if the supported address length is already initiated. + if ((SfdpAddressBytes !=3D SPI_ADDR_4BYTE_ONLY) && (SfdpAddressByt= es !=3D SPI_ADDR_3OR4BYTE)) { + DEBUG ((DEBUG_ERROR, "%a: Unsupported Address Bytes: 0x%x, SFDP = is: 0x%x\n", __func__, AddressBytesSupported, SfdpAddressBytes)); + ASSERT (FALSE); + } + } + + AddressSize =3D 4; + } else if (AddressBytesSupported =3D=3D SPI_ADDR_3OR4BYTE) { + if (SfdpAddressBytes !=3D 0) { + // Check if the supported address length is already initiated. + if (SfdpAddressBytes !=3D SPI_ADDR_3OR4BYTE) { + DEBUG ((DEBUG_ERROR, "%a: Unsupported Address Bytes: 0x%x, SFDP = is: 0x%x\n", __func__, AddressBytesSupported, SfdpAddressBytes)); + ASSERT (FALSE); + } + } + + if (Instance->Protocol.FlashSize <=3D SIZE_16MB) { + AddressSize =3D 3; + } else { + // SPI part is > 16MB use 4-byte addressing. + AddressSize =3D 4; + } + } else { + DEBUG ((DEBUG_ERROR, "%a: Invalid Address Bytes\n", __func__)); + ASSERT (FALSE); + } + + BigEndianAddress =3D SwapBytes32 ((UINT32)Address); + BigEndianAddress >>=3D ((sizeof (UINT32) - AddressSize) * 8); + CopyMem ( + &Instance->SpiTransactionWriteBuffer[Index], + &BigEndianAddress, + AddressSize + ); + Index +=3D AddressSize; + } + + if (SfdpAddressBytes =3D=3D SPI_ADDR_3OR4BYTE) { + // + // TODO: + // We may need to enter/exit 4-Byte mode if SPI flash + // device is currently operated in 3-Bytes mode. + // + } + + // Fill DummyBytes + if (DummyBytes !=3D 0) { + SetMem ( + &Instance->SpiTransactionWriteBuffer[Index], + DummyBytes, + 0 + ); + Index +=3D DummyBytes; + } + + // Fill Data + if (WriteBytes > 0) { + CopyMem ( + &Instance->SpiTransactionWriteBuffer[Index], + WriteBuffer, + WriteBytes + ); + Index +=3D WriteBytes; + } + + return Index; +} + +/** + Internal Read the flash status register. + + This routine reads the flash part status register. + + @param[in] Instance SPI_NOR_FLASH_INSTANCE + structure. + @param[in] LengthInBytes Number of status bytes to read. + @param[out] FlashStatus Pointer to a buffer to receive the flash stat= us. + + @retval EFI_SUCCESS The status register was read successfully. + +**/ +EFI_STATUS +EFIAPI +InternalReadStatus ( + IN SPI_NOR_FLASH_INSTANCE *Instance, + IN UINT32 LengthInBytes, + OUT UINT8 *FlashStatus + ) +{ + EFI_STATUS Status; + UINT32 TransactionBufferLength; + + // Read Status register + TransactionBufferLength =3D FillWriteBuffer ( + Instance, + SPI_FLASH_RDSR, + SPI_FLASH_RDSR_DUMMY, + SPI_FLASH_RDSR_ADDR_BYTES, + FALSE, + 0, + 0, + NULL + ); + Status =3D Instance->SpiIo->Transaction ( + Instance->SpiIo, + SPI_TRANSACTION_WRITE_THEN_READ, + FALSE, + 0, + 1, + 8, + TransactionBufferLength, + Instance->SpiTransactionWriteBuffer, + 1, + FlashStatus + ); + ASSERT_EFI_ERROR (Status); + return Status; +} + +/** + Set Write Enable Latch + + @param[in] Instance SPI NOR instance with all protocols, etc. + + @retval EFI_SUCCESS SPI Write Enable succeeded + @retval EFI_DEVICE_ERROR SPI Flash part did not respond properly +**/ +EFI_STATUS +SetWel ( + IN SPI_NOR_FLASH_INSTANCE *Instance + ) +{ + EFI_STATUS Status; + UINT32 TransactionBufferLength; + + TransactionBufferLength =3D FillWriteBuffer ( + Instance, + Instance->WriteEnableLatchCommand, + SPI_FLASH_WREN_DUMMY, + SPI_FLASH_WREN_ADDR_BYTES, + FALSE, + 0, + 0, + NULL + ); + Status =3D Instance->SpiIo->Transaction ( + Instance->SpiIo, + SPI_TRANSACTION_WRITE_ONLY, + FALSE, + 0, + 1, + 8, + TransactionBufferLength, + Instance->SpiTransactionWriteBuffer, + 0, + NULL + ); + if (EFI_ERROR (Status)) { + DEBUG ((DEBUG_ERROR, "%a: Set WEL fail.\n", __func__)); + ASSERT (FALSE); + } + + return Status; +} + +/** + Check for not device write in progress + + @param[in] SpiNorFlashInstance SPI NOR instance with all protocols, et= c. + @param[in] Timeout Timeout in microsecond + @param[in] RetryCount The retry count + + @retval EFI_SUCCESS Device does not have a write in progress + @retval EFI_DEVICE_ERROR SPI Flash part did not respond properly +**/ +EFI_STATUS +WaitNotWip ( + IN SPI_NOR_FLASH_INSTANCE *SpiNorFlashInstance, + IN UINT32 Timeout, + IN UINT32 RetryCount + ) +{ + EFI_STATUS Status; + UINT8 DeviceStatus; + UINT32 AlreadyDelayedInMicroseconds; + + if (Timeout =3D=3D 0) { + return EFI_SUCCESS; + } + + if (RetryCount =3D=3D 0) { + RetryCount =3D 1; + } + + do { + AlreadyDelayedInMicroseconds =3D 0; + while (AlreadyDelayedInMicroseconds < Timeout) { + Status =3D InternalReadStatus (SpiNorFlashInstance, 1, &DeviceStatus= ); + if (EFI_ERROR (Status)) { + DEBUG ((DEBUG_ERROR, "%a: Read status error\n", __func__)); + ASSERT (FALSE); + return Status; + } + + if ((DeviceStatus & SPI_FLASH_SR_WIP) =3D=3D SPI_FLASH_SR_NOT_WIP) { + return Status; + } + + MicroSecondDelay (FixedPcdGet32 (PcdSpiNorFlashOperationDelayMicrose= conds)); + AlreadyDelayedInMicroseconds +=3D FixedPcdGet32 (PcdSpiNorFlashOpera= tionDelayMicroseconds); + } + + RetryCount--; + } while (RetryCount > 0); + + DEBUG ((DEBUG_ERROR, "%a: Timeout error\n", __func__)); + return EFI_DEVICE_ERROR; +} + +/** + Check for write enable latch set and not device write in progress + + @param[in] SpiNorFlashInstance SPI NOR instance with all protocols, et= c. + @param[in] Timeout Timeout in microsecond + @param[in] RetryCount The retry count + + @retval EFI_SUCCESS Device does not have a write in progress a= nd + write enable latch is set + @retval EFI_DEVICE_ERROR SPI Flash part did not respond properly +**/ +EFI_STATUS +WaitWelNotWip ( + IN SPI_NOR_FLASH_INSTANCE *SpiNorFlashInstance, + IN UINT32 Timeout, + IN UINT32 RetryCount + ) +{ + EFI_STATUS Status; + UINT8 DeviceStatus; + UINT32 AlreadyDelayedInMicroseconds; + + if (Timeout =3D=3D 0) { + return EFI_SUCCESS; + } + + if (RetryCount =3D=3D 0) { + RetryCount =3D 1; + } + + do { + AlreadyDelayedInMicroseconds =3D 0; + while (AlreadyDelayedInMicroseconds < Timeout) { + Status =3D InternalReadStatus (SpiNorFlashInstance, 1, &DeviceStatus= ); + if (EFI_ERROR (Status)) { + DEBUG ((DEBUG_ERROR, "%a: Fail to read WEL.\n", __func__)); + ASSERT_EFI_ERROR (Status); + return Status; + } + + if ((DeviceStatus & (SPI_FLASH_SR_WIP | SPI_FLASH_SR_WEL)) =3D=3D SP= I_FLASH_SR_WEL) { + return Status; + } + + MicroSecondDelay (FixedPcdGet32 (PcdSpiNorFlashOperationDelayMicrose= conds)); + AlreadyDelayedInMicroseconds +=3D FixedPcdGet32 (PcdSpiNorFlashOpera= tionDelayMicroseconds); + } + + RetryCount--; + } while (RetryCount > 0); + + DEBUG ((DEBUG_ERROR, "%a: Timeout error\n", __func__)); + return EFI_DEVICE_ERROR; +} + +/** + Check for not write enable latch set and not device write in progress + + @param[in] SpiNorFlashInstance SPI NOR instance with all protocols, et= c. + @param[in] Timeout Timeout in microsecond + @param[in] RetryCount The retry count + + @retval EFI_SUCCESS Device does not have a write in progress a= nd + write enable latch is not set + @retval EFI_DEVICE_ERROR SPI Flash part did not respond properly +**/ +EFI_STATUS +WaitNotWelNotWip ( + IN SPI_NOR_FLASH_INSTANCE *SpiNorFlashInstance, + IN UINT32 Timeout, + IN UINT32 RetryCount + ) +{ + EFI_STATUS Status; + UINT8 DeviceStatus; + UINT32 AlreadyDelayedInMicroseconds; + + if (Timeout =3D=3D 0) { + return EFI_SUCCESS; + } + + if (RetryCount =3D=3D 0) { + RetryCount =3D 1; + } + + do { + AlreadyDelayedInMicroseconds =3D 0; + while (AlreadyDelayedInMicroseconds < Timeout) { + Status =3D InternalReadStatus (SpiNorFlashInstance, 1, &DeviceStatus= ); + ASSERT_EFI_ERROR (Status); + if (EFI_ERROR (Status) || + ((DeviceStatus & (SPI_FLASH_SR_WIP | SPI_FLASH_SR_WEL)) =3D=3D S= PI_FLASH_SR_NOT_WIP)) + { + return Status; + } + + MicroSecondDelay (FixedPcdGet32 (PcdSpiNorFlashOperationDelayMicrose= conds)); + AlreadyDelayedInMicroseconds +=3D FixedPcdGet32 (PcdSpiNorFlashOpera= tionDelayMicroseconds); + } + + RetryCount--; + } while (RetryCount > 0); + + DEBUG ((DEBUG_ERROR, "SpiNorFlash:%a: Timeout error\n", __func__)); + return EFI_DEVICE_ERROR; +} + +/** + Read the 3 byte manufacture and device ID from the SPI flash. + + This routine must be called at or below TPL_NOTIFY. + This routine reads the 3 byte manufacture and device ID from the flash p= art + filling the buffer provided. + + @param[in] This Pointer to an EFI_SPI_NOR_FLASH_PROTOCOL data struct= ure. + @param[out] Buffer Pointer to a 3 byte buffer to receive the manufactur= e and + device ID. + + @retval EFI_SUCCESS The manufacture and device ID was read + successfully. + @retval EFI_INVALID_PARAMETER Buffer is NULL + @retval EFI_DEVICE_ERROR Invalid data received from SPI flash part= . + +**/ +EFI_STATUS +EFIAPI +GetFlashId ( + IN CONST EFI_SPI_NOR_FLASH_PROTOCOL *This, + OUT UINT8 *Buffer + ) +{ + EFI_STATUS Status; + SPI_NOR_FLASH_INSTANCE *Instance; + UINT32 TransactionBufferLength; + + DEBUG ((DEBUG_INFO, "%a: Entry\n", __func__)); + + if (Buffer =3D=3D NULL) { + return EFI_INVALID_PARAMETER; + } + + Instance =3D SPI_NOR_FLASH_FROM_THIS (This); + + // Check not WIP + Status =3D WaitNotWip (Instance, FixedPcdGet32 (PcdSpiNorFlashOperationD= elayMicroseconds), FixedPcdGet32 (PcdSpiNorFlashFixedTimeoutRetryCount)); + + if (!EFI_ERROR (Status)) { + TransactionBufferLength =3D FillWriteBuffer ( + Instance, + SPI_FLASH_RDID, + SPI_FLASH_RDID_DUMMY, + SPI_FLASH_RDID_ADDR_BYTES, + FALSE, + 0, + 0, + NULL + ); + Status =3D Instance->SpiIo->Transaction ( + Instance->SpiIo, + SPI_TRANSACTION_WRITE_THEN_READ, + FALSE, + 0, + 1, + 8, + TransactionBufferLength, + Instance->SpiTransactionWriteBuffer, + 3, + Buffer + ); + ASSERT_EFI_ERROR (Status); + } + + return Status; +} + +/** + Read data from the SPI flash at not fast speed + + This routine must be called at or below TPL_NOTIFY. + This routine reads data from the SPI part in the buffer provided. + + @param[in] This Pointer to an EFI_SPI_NOR_FLASH_PROTOCOL data + structure. + @param[in] FlashAddress Address in the flash to start reading + @param[in] LengthInBytes Read length in bytes + @param[out] Buffer Address of a buffer to receive the data + + @retval EFI_SUCCESS The data was read successfully. + @retval EFI_INVALID_PARAMETER Buffer is NULL, or + FlashAddress >=3D This->FlashSize, or + LengthInBytes > This->FlashSize - FlashAd= dress + +**/ +EFI_STATUS +EFIAPI +LfReadData ( + IN CONST EFI_SPI_NOR_FLASH_PROTOCOL *This, + IN UINT32 FlashAddress, + IN UINT32 LengthInBytes, + OUT UINT8 *Buffer + ) +{ + EFI_STATUS Status; + SPI_NOR_FLASH_INSTANCE *Instance; + UINT32 ByteCounter; + UINT32 CurrentAddress; + UINT8 *CurrentBuffer; + UINT32 Length; + UINT32 TransactionBufferLength; + UINT32 MaximumTransferBytes; + + DEBUG ((DEBUG_INFO, "%a: Entry\n", __func__)); + + Status =3D EFI_DEVICE_ERROR; + if ((Buffer =3D=3D NULL) || + (FlashAddress >=3D This->FlashSize) || + (LengthInBytes > This->FlashSize - FlashAddress)) + { + return EFI_INVALID_PARAMETER; + } + + Instance =3D SPI_NOR_FLASH_FROM_THIS (This); + MaximumTransferBytes =3D Instance->SpiIo->MaximumTransferBytes; + + CurrentBuffer =3D Buffer; + Length =3D 0; + for (ByteCounter =3D 0; ByteCounter < LengthInBytes;) { + CurrentAddress =3D FlashAddress + ByteCounter; + CurrentBuffer =3D Buffer + ByteCounter; + Length =3D LengthInBytes - ByteCounter; + // Length must be MaximumTransferBytes or less + if (Length > MaximumTransferBytes) { + Length =3D MaximumTransferBytes; + } + + // Check not WIP + Status =3D WaitNotWip (Instance, FixedPcdGet32 (PcdSpiNorFlashOperatio= nDelayMicroseconds), FixedPcdGet32 (PcdSpiNorFlashFixedTimeoutRetryCount)); + if (EFI_ERROR (Status)) { + break; + } + + TransactionBufferLength =3D FillWriteBuffer ( + Instance, + SPI_FLASH_READ, + SPI_FLASH_READ_DUMMY, + SPI_FLASH_READ_ADDR_BYTES, + TRUE, + CurrentAddress, + 0, + NULL + ); + Status =3D Instance->SpiIo->Transaction ( + Instance->SpiIo, + SPI_TRANSACTION_WRITE_THEN_READ, + FALSE, + 0, + 1, + 8, + TransactionBufferLength, + Instance->SpiTransactionWriteBuffer, + Length, + CurrentBuffer + ); + ASSERT_EFI_ERROR (Status); + ByteCounter +=3D Length; + } + + return Status; +} + +/** + Read data from the SPI flash. + + This routine must be called at or below TPL_NOTIFY. + This routine reads data from the SPI part in the buffer provided. + + @param[in] This Pointer to an EFI_SPI_NOR_FLASH_PROTOCOL data + structure. + @param[in] FlashAddress Address in the flash to start reading + @param[in] LengthInBytes Read length in bytes + @param[out] Buffer Address of a buffer to receive the data + + @retval EFI_SUCCESS The data was read successfully. + @retval EFI_INVALID_PARAMETER Buffer is NULL, or + FlashAddress >=3D This->FlashSize, or + LengthInBytes > This->FlashSize - FlashAd= dress + +**/ +EFI_STATUS +EFIAPI +ReadData ( + IN CONST EFI_SPI_NOR_FLASH_PROTOCOL *This, + IN UINT32 FlashAddress, + IN UINT32 LengthInBytes, + OUT UINT8 *Buffer + ) +{ + EFI_STATUS Status; + SPI_NOR_FLASH_INSTANCE *Instance; + UINT32 ByteCounter; + UINT32 CurrentAddress; + UINT8 *CurrentBuffer; + UINT32 Length; + UINT32 TransactionBufferLength; + UINT32 MaximumTransferBytes; + UINT8 FastReadInstruction; + UINT8 FastReadWaitStateDummyClocks; + UINT8 FastReadModeClock; + + DEBUG ((DEBUG_INFO, "%a: Entry, Read address =3D 0x%08x, Length =3D 0x%0= 8x\n", __func__, FlashAddress, LengthInBytes)); + + Status =3D EFI_DEVICE_ERROR; + if ((Buffer =3D=3D NULL) || + (FlashAddress >=3D This->FlashSize) || + (LengthInBytes > This->FlashSize - FlashAddress)) + { + return EFI_INVALID_PARAMETER; + } + + Instance =3D SPI_NOR_FLASH_FROM_THIS (This); + MaximumTransferBytes =3D Instance->SpiIo->MaximumTransferBytes; + + // + // Initial the default read operation parameters. + // + FastReadInstruction =3D SPI_FLASH_FAST_READ; + FastReadWaitStateDummyClocks =3D SPI_FLASH_FAST_READ_DUMMY * 8; + FastReadModeClock =3D 0; + // + // Override by the Fast Read capabiity table. + // + // Get the first supported fast read comamnd. + // This will be the standard fast read command (0x0b), + // which is the first fast read command added to the + // supported list. + // TODO: The mechanism to choose the advanced fast read + // is not determined yet in this version of + // SpiNorFlash driver. + Status =3D GetFastReadParameter ( + Instance, + &FastReadInstruction, + &FastReadModeClock, + &FastReadWaitStateDummyClocks + ); + if (!EFI_ERROR (Status)) { + DEBUG ((DEBUG_VERBOSE, " Use below Fast Read mode:\n")); + } else { + DEBUG ((DEBUG_VERBOSE, " Use the default Fast Read mode:\n")); + } + + DEBUG ((DEBUG_VERBOSE, " Instruction : 0x%x\n"= , FastReadInstruction)); + DEBUG ((DEBUG_VERBOSE, " Mode Clock : 0x%x\n"= , FastReadModeClock)); + DEBUG ((DEBUG_VERBOSE, " Wait States (Dummy Clocks) in clock: 0x%x\n"= , FastReadWaitStateDummyClocks)); + DEBUG ((DEBUG_VERBOSE, " Supported erase address bytes by device: 0x= %02x.\n", Instance->SfdpBasicFlash->AddressBytes)); + DEBUG ((DEBUG_VERBOSE, " (00: 3-Byte, 01: 3 or 4-Byte. 10: 4-Byte= )\n")); + + CurrentBuffer =3D Buffer; + Length =3D 0; + for (ByteCounter =3D 0; ByteCounter < LengthInBytes;) { + CurrentAddress =3D FlashAddress + ByteCounter; + CurrentBuffer =3D Buffer + ByteCounter; + Length =3D LengthInBytes - ByteCounter; + // Length must be MaximumTransferBytes or less + if (Length > MaximumTransferBytes) { + Length =3D MaximumTransferBytes; + } + + // Check not WIP + Status =3D WaitNotWip (Instance, FixedPcdGet32 (PcdSpiNorFlashOperatio= nDelayMicroseconds), FixedPcdGet32 (PcdSpiNorFlashFixedTimeoutRetryCount)); + if (EFI_ERROR (Status)) { + break; + } + + TransactionBufferLength =3D FillWriteBuffer ( + Instance, + FastReadInstruction, + FastReadWaitStateDummyClocks / 8, + (UINT8)Instance->SfdpBasicFlash->AddressBy= tes, + TRUE, + CurrentAddress, + 0, + NULL + ); + Status =3D Instance->SpiIo->Transaction ( + Instance->SpiIo, + SPI_TRANSACTION_WRITE_THEN_READ, + FALSE, + 0, + 1, + 8, + TransactionBufferLength, + Instance->SpiTransactionWriteBuffer, + Length, + CurrentBuffer + ); + ASSERT_EFI_ERROR (Status); + ByteCounter +=3D Length; + } + + return Status; +} + +/** + Read the flash status register. + + This routine must be called at or below TPL_NOTIFY. + This routine reads the flash part status register. + + @param[in] This Pointer to an EFI_SPI_NOR_FLASH_PROTOCOL data + structure. + @param[in] LengthInBytes Number of status bytes to read. + @param[out] FlashStatus Pointer to a buffer to receive the flash stat= us. + + @retval EFI_SUCCESS The status register was read successfully. + +**/ +EFI_STATUS +EFIAPI +ReadStatus ( + IN CONST EFI_SPI_NOR_FLASH_PROTOCOL *This, + IN UINT32 LengthInBytes, + OUT UINT8 *FlashStatus + ) +{ + EFI_STATUS Status; + SPI_NOR_FLASH_INSTANCE *Instance; + + if (LengthInBytes !=3D 1) { + return EFI_INVALID_PARAMETER; + } + + Instance =3D SPI_NOR_FLASH_FROM_THIS (This); + + Status =3D InternalReadStatus (Instance, LengthInBytes, FlashStatus); + + return Status; +} + +/** + Write the flash status register. + + This routine must be called at or below TPL_N OTIFY. + This routine writes the flash part status register. + + @param[in] This Pointer to an EFI_SPI_NOR_FLASH_PROTOCOL data + structure. + @param[in] LengthInBytes Number of status bytes to write. + @param[in] FlashStatus Pointer to a buffer containing the new status. + + @retval EFI_SUCCESS The status write was successful. + @retval EFI_OUT_OF_RESOURCES Failed to allocate the write buffer. + +**/ +EFI_STATUS +EFIAPI +WriteStatus ( + IN CONST EFI_SPI_NOR_FLASH_PROTOCOL *This, + IN UINT32 LengthInBytes, + IN UINT8 *FlashStatus + ) +{ + EFI_STATUS Status; + SPI_NOR_FLASH_INSTANCE *Instance; + UINT32 TransactionBufferLength; + + if (LengthInBytes !=3D 1) { + return EFI_INVALID_PARAMETER; + } + + Instance =3D SPI_NOR_FLASH_FROM_THIS (This); + + // Check not WIP + Status =3D WaitNotWip (Instance, FixedPcdGet32 (PcdSpiNorFlashOperationD= elayMicroseconds), FixedPcdGet32 (PcdSpiNorFlashFixedTimeoutRetryCount)); + + // Set Write Enable + if (!EFI_ERROR (Status)) { + if (Instance->WriteEnableLatchRequired) { + Status =3D SetWel (Instance); + DEBUG ((DEBUG_ERROR, "%a: set Write Enable Error.\n", __func__)); + ASSERT_EFI_ERROR (Status); + // Check not WIP & WEL enabled + Status =3D WaitWelNotWip (Instance, FixedPcdGet32 (PcdSpiNorFlashOpe= rationDelayMicroseconds), FixedPcdGet32 (PcdSpiNorFlashFixedTimeoutRetryCou= nt)); + } + + // Write the Status Register + if (!EFI_ERROR (Status)) { + TransactionBufferLength =3D FillWriteBuffer ( + Instance, + SPI_FLASH_WRSR, + SPI_FLASH_WRSR_DUMMY, + SPI_FLASH_WRSR_ADDR_BYTES, + FALSE, + 0, + 0, + NULL + ); + Status =3D Instance->SpiIo->Transaction ( + Instance->SpiIo, + SPI_TRANSACTION_WRITE_ONLY, + FALSE, + 0, + 1, + 8, + TransactionBufferLength, + Instance->SpiTransactionWriteBuffer, + 0, + NULL + ); + ASSERT_EFI_ERROR (Status); + } + } + + return Status; +} + +/** + Write data to the SPI flash. + + This routine must be called at or below TPL_NOTIFY. + This routine breaks up the write operation as necessary to write the dat= a to + the SPI part. + + @param[in] This Pointer to an EFI_SPI_NOR_FLASH_PROTOCOL data + structure. + @param[in] FlashAddress Address in the flash to start writing + @param[in] LengthInBytes Write length in bytes + @param[in] Buffer Address of a buffer containing the data + + @retval EFI_SUCCESS The data was written successfully. + @retval EFI_INVALID_PARAMETER Buffer is NULL, or + FlashAddress >=3D This->FlashSize, or + LengthInBytes > This->FlashSize - FlashAd= dress + @retval EFI_OUT_OF_RESOURCES Insufficient memory to copy buffer. + +**/ +EFI_STATUS +EFIAPI +WriteData ( + IN CONST EFI_SPI_NOR_FLASH_PROTOCOL *This, + IN UINT32 FlashAddress, + IN UINT32 LengthInBytes, + IN UINT8 *Buffer + ) +{ + EFI_STATUS Status; + SPI_NOR_FLASH_INSTANCE *Instance; + UINT32 ByteCounter; + UINT32 CurrentAddress; + UINT32 Length; + UINT32 BytesUntilBoundary; + UINT8 *CurrentBuffer; + UINT32 TransactionBufferLength; + UINT32 MaximumTransferBytes; + UINT32 SpiFlashPageSize; + + DEBUG ((DEBUG_INFO, "%a: Entry: Write address =3D 0x%08x, Length =3D 0x%= 08x\n", __func__, FlashAddress, LengthInBytes)); + + Status =3D EFI_DEVICE_ERROR; + if ((Buffer =3D=3D NULL) || + (LengthInBytes =3D=3D 0) || + (FlashAddress >=3D This->FlashSize) || + (LengthInBytes > This->FlashSize - FlashAddress)) + { + return EFI_INVALID_PARAMETER; + } + + Instance =3D SPI_NOR_FLASH_FROM_THIS (This); + MaximumTransferBytes =3D Instance->SpiIo->MaximumTransferBytes; + if (Instance->SfdpBasicFlashByteCount >=3D 11 * 4) { + // JESD216C spec DWORD 11 + SpiFlashPageSize =3D 1 << Instance->SfdpBasicFlash->PageSize; + } else { + SpiFlashPageSize =3D 256; + } + + CurrentBuffer =3D Buffer; + Length =3D 0; + for (ByteCounter =3D 0; ByteCounter < LengthInBytes;) { + CurrentAddress =3D FlashAddress + ByteCounter; + CurrentBuffer =3D Buffer + ByteCounter; + Length =3D LengthInBytes - ByteCounter; + // Length must be MaximumTransferBytes or less + if (Length > MaximumTransferBytes) { + Length =3D MaximumTransferBytes; + } + + // Cannot cross SpiFlashPageSize boundary + BytesUntilBoundary =3D SpiFlashPageSize + - (CurrentAddress % SpiFlashPageSize); + if ((BytesUntilBoundary !=3D 0) && (Length > BytesUntilBoundary)) { + Length =3D BytesUntilBoundary; + } + + // Check not WIP + Status =3D WaitNotWip (Instance, FixedPcdGet32 (PcdSpiNorFlashOperatio= nDelayMicroseconds), FixedPcdGet32 (PcdSpiNorFlashFixedTimeoutRetryCount)); + if (EFI_ERROR (Status)) { + break; + } + + if (Instance->WriteEnableLatchRequired) { + // Set Write Enable + Status =3D SetWel (Instance); + ASSERT_EFI_ERROR (Status); + if (EFI_ERROR (Status)) { + break; + } + + // Check not WIP & WEL enabled + Status =3D WaitWelNotWip (Instance, FixedPcdGet32 (PcdSpiNorFlashOpe= rationDelayMicroseconds), FixedPcdGet32 (PcdSpiNorFlashFixedTimeoutRetryCou= nt)); + if (EFI_ERROR (Status)) { + break; + } + } + + // Write Data + TransactionBufferLength =3D FillWriteBuffer ( + Instance, + SPI_FLASH_PP, + SPI_FLASH_PP_DUMMY, + SPI_FLASH_PP_ADDR_BYTES, + TRUE, + CurrentAddress, + Length, + CurrentBuffer + ); + Status =3D Instance->SpiIo->Transaction ( + Instance->SpiIo, + SPI_TRANSACTION_WRITE_ONLY, + FALSE, + 0, + 1, + 8, + TransactionBufferLength, + Instance->SpiTransactionWriteBuffer, + 0, + NULL + ); + ASSERT_EFI_ERROR (Status); + if (EFI_ERROR (Status)) { + break; + } + + if (Instance->WriteEnableLatchRequired) { + // Check not WIP & not WEL + Status =3D WaitNotWelNotWip (Instance, FixedPcdGet32 (PcdSpiNorFlash= OperationDelayMicroseconds), FixedPcdGet32 (PcdSpiNorFlashFixedTimeoutRetry= Count)); + if (EFI_ERROR (Status)) { + break; + } + } else { + Status =3D WaitNotWip (Instance, FixedPcdGet32 (PcdSpiNorFlashOperat= ionDelayMicroseconds), FixedPcdGet32 (PcdSpiNorFlashFixedTimeoutRetryCount)= ); + if (EFI_ERROR (Status)) { + break; + } + } + + ByteCounter +=3D Length; + } + + return Status; +} + +/** + Efficiently erases blocks in the SPI flash. + + This routine must be called at or below TPL_NOTIFY. + This routine may use the combination of variable earse sizes to erase th= e + specified area accroding to the flash region. + + @param[in] This Pointer to an EFI_SPI_NOR_FLASH_PROTOCOL data + structure. + @param[in] FlashAddress Address to start erasing + @param[in] BlockCount Number of blocks to erase. The block size is in= dicated + in EraseBlockBytes in EFI_SPI_NOR_FLASH_PROTOCO= L. + + @retval EFI_SUCCESS The erase was completed successfully. + @retval EFI_DEVICE_ERROR The flash devices has problems. + @retval EFI_INVALID_PARAMETER The given FlashAddress and/or BlockCount + is invalid. + +**/ +EFI_STATUS +EFIAPI +Erase ( + IN CONST EFI_SPI_NOR_FLASH_PROTOCOL *This, + IN UINT32 FlashAddress, + IN UINT32 BlockCount + ) +{ + EFI_STATUS Status; + SPI_NOR_FLASH_INSTANCE *Instance; + UINT8 Opcode; + UINT32 Dummy; + UINT32 ByteCounter; + UINT32 EraseLength; + UINT32 TotalEraseLength; + UINT32 CurrentAddress; + UINT32 TransactionBufferLength; + UINT32 BlockCountToErase; + UINT32 BlockSizeToErase; + UINT8 BlockEraseCommand; + UINT32 TypicalEraseTime; + UINT64 MaximumEraseTimeout; + SFDP_SECTOR_REGION_RECORD *FlashRegion; + + DEBUG ((DEBUG_INFO, "%a: Entry: Erase address =3D 0x%08x, Block count = =3D 0x%x\n", __func__, FlashAddress, BlockCount)); + + Status =3D EFI_DEVICE_ERROR; + Instance =3D SPI_NOR_FLASH_FROM_THIS (This); + + // Get the region of this flash address. + Status =3D GetRegionByFlashAddress (Instance, FlashAddress, &FlashRegion= ); + if (EFI_ERROR (Status)) { + DEBUG ((DEBUG_ERROR, " Failed to get the flash region of this flash a= ddress.\n")); + ASSERT (FALSE); + return Status; + } + + CurrentAddress =3D FlashAddress; + BlockCountToErase =3D BlockCount; + BlockSizeToErase =3D FlashRegion->SectorSize; // This is also the minim= um block erase size. + TotalEraseLength =3D BlockCountToErase * FlashRegion->SectorSize; + if ((FlashAddress + TotalEraseLength) > (FlashRegion->RegionAddress + Fl= ashRegion->RegionTotalSize)) { + DEBUG ((DEBUG_ERROR, " The blocks to erase exceeds the region boundar= y.\n")); + return EFI_INVALID_PARAMETER; + } + + DEBUG ((DEBUG_VERBOSE, " Region starting address: 0x%08x.\n", FlashRegi= on->RegionAddress)); + DEBUG ((DEBUG_VERBOSE, " Region size : 0x%08x.\n", FlashRegi= on->RegionTotalSize)); + DEBUG ((DEBUG_VERBOSE, " Region sector size : 0x%08x.\n", FlashRegi= on->SectorSize)); + DEBUG ((DEBUG_VERBOSE, " Supported erase address bytes by device: 0x%02= x.\n", Instance->SfdpBasicFlash->AddressBytes)); + DEBUG ((DEBUG_VERBOSE, " (00: 3-Byte, 01: 3 or 4-Byte. 10: 4-Byte)\n"= )); + + // Loop until all blocks are erased. + ByteCounter =3D 0; + while (ByteCounter < TotalEraseLength) { + CurrentAddress =3D FlashAddress + ByteCounter; + + // Is this the whole device erase. + if (TotalEraseLength =3D=3D This->FlashSize) { + Opcode =3D SPI_FLASH_CE; + Dummy =3D SPI_FLASH_CE_DUMMY; + EraseLength =3D TotalEraseLength; + DEBUG ((DEBUG_VERBOSE, " This is the chip erase.\n")); + } else { + // + // Get the erase block attributes. + // + Status =3D GetEraseBlockAttribute ( + Instance, + FlashRegion, + CurrentAddress, + TotalEraseLength - ByteCounter, + &BlockSizeToErase, + &BlockCountToErase, + &BlockEraseCommand, + &TypicalEraseTime, + &MaximumEraseTimeout + ); + if (EFI_ERROR (Status)) { + DEBUG ((DEBUG_ERROR, " Failed to get erase block attribute.\n")); + ASSERT (FALSE); + } + + Opcode =3D BlockEraseCommand; + Dummy =3D SPI_FLASH_BE_DUMMY; + EraseLength =3D BlockCountToErase * BlockSizeToErase; + DEBUG (( + DEBUG_VERBOSE, + " Erase command 0x%02x at adddress 0x%08x for length 0x%08x.\n", + BlockEraseCommand, + CurrentAddress, + EraseLength + )); + } + + // + // Process the erase command. + // + + // Check not WIP + Status =3D WaitNotWip (Instance, FixedPcdGet32 (PcdSpiNorFlashOperatio= nDelayMicroseconds), FixedPcdGet32 (PcdSpiNorFlashFixedTimeoutRetryCount)); + if (EFI_ERROR (Status)) { + break; + } + + if (Instance->WriteEnableLatchRequired) { + // Set Write Enable + Status =3D SetWel (Instance); + if (EFI_ERROR (Status)) { + break; + } + + // Check not WIP & WEL enabled + Status =3D WaitWelNotWip (Instance, FixedPcdGet32 (PcdSpiNorFlashOpe= rationDelayMicroseconds), FixedPcdGet32 (PcdSpiNorFlashFixedTimeoutRetryCou= nt)); + if (EFI_ERROR (Status)) { + break; + } + } + + // Erase Block + TransactionBufferLength =3D FillWriteBuffer ( + Instance, + Opcode, + Dummy, + (UINT8)Instance->SfdpBasicFlash->AddressBy= tes, + TRUE, + CurrentAddress, + 0, + NULL + ); + Status =3D Instance->SpiIo->Transaction ( + Instance->SpiIo, + SPI_TRANSACTION_WRITE_ONLY, + FALSE, + 0, + 1, + 8, + TransactionBufferLength, + Instance->SpiTransactionWriteBuffer, + 0, + NULL + ); + ASSERT_EFI_ERROR (Status); + if (EFI_ERROR (Status)) { + break; + } else { + DEBUG ((DEBUG_VERBOSE, "Erase command sucessfully.\n")); + } + + if (Instance->WriteEnableLatchRequired) { + // + // Check not WIP & not WEL + // Use the timeout value calculated by SPI NOR flash SFDP. + // + Status =3D WaitNotWelNotWip (Instance, (UINT32)MaximumEraseTimeout *= 1000, FixedPcdGet32 (PcdSpiNorFlashOperationRetryCount)); + if (EFI_ERROR (Status)) { + break; + } + } else { + // + // Use the timeout value calculated by SPI NOR flash SFDP. + // + Status =3D WaitNotWip (Instance, (UINT32)MaximumEraseTimeout * 1000,= FixedPcdGet32 (PcdSpiNorFlashOperationRetryCount)); + if (EFI_ERROR (Status)) { + break; + } + } + + ByteCounter +=3D EraseLength; + } + + return Status; +} diff --git a/MdeModulePkg/Bus/Spi/SpiNorFlashJedecSfdp/SpiNorFlashJedecSfdp= .c b/MdeModulePkg/Bus/Spi/SpiNorFlashJedecSfdp/SpiNorFlashJedecSfdp.c new file mode 100644 index 00000000000..78327d37ff0 --- /dev/null +++ b/MdeModulePkg/Bus/Spi/SpiNorFlashJedecSfdp/SpiNorFlashJedecSfdp.c @@ -0,0 +1,1780 @@ +/** @file + SPI NOR Flash JEDEC Serial Flash Discoverable Parameters (SFDP) + common functions. + + 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=3DJE= SD216 + + @par Glossary: + - SFDP - Serial Flash Discoverable Parameters + - PTP - Parameter Table Pointer +**/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "SpiNorFlash.h" +#include "SpiNorFlashJedecSfdpInternal.h" + +/** + Build up the Fast Read capability entry and link it to + the linked list. + + @param[in] Instance SPI Nor Flash Instance data with point= er to + EFI_SPI_NOR_FLASH_PROTOCOL and + EFI_SPI_IO_PROTOCOL. + @param[in] FastReadInstruction The string of fast read instruction. + @param[in] FastReadModeClk The string of fast read mode clock. + @param[in] FastReadDummyClk The string of fast read dummy clock. + +**/ +VOID +CreateSpiFastReadTableEntry ( + IN SPI_NOR_FLASH_INSTANCE *Instance, + IN UINT32 FastReadInstruction, + IN UINT32 FastReadModeClk, + IN UINT32 FastReadDummyClk + ) +{ + SFPD_FAST_READ_CAPBILITY_RECORD *CapabilityEntry; + + CapabilityEntry =3D AllocateZeroPool (sizeof (SFPD_FAST_READ_CAPBILITY_R= ECORD)); + if (CapabilityEntry =3D=3D NULL) { + DEBUG ((DEBUG_ERROR, "%a: Failed to create fast read table\n", __func_= _)); + ASSERT (FALSE); + return; + } + + InitializeListHead (&CapabilityEntry->NextFastReadCap); + CapabilityEntry->FastReadInstruction =3D (UINT8)FastReadInstruction; + CapabilityEntry->ModeClocks =3D (UINT8)FastReadModeClk; + CapabilityEntry->WaitStates =3D (UINT8)FastReadDummyClk; + InsertTailList (&Instance->FastReadTableList, &CapabilityEntry->NextFast= ReadCap); + DEBUG ((DEBUG_VERBOSE, "%a: Create and link table.\n", __func__)); + DEBUG ((DEBUG_VERBOSE, " Instruction : 0x%x\n", FastReadI= nstruction)); + DEBUG ((DEBUG_VERBOSE, " Mode bits : 0x%x\n", FastReadM= odeClk)); + DEBUG ((DEBUG_VERBOSE, " Wait States (Dummy Clocks): 0x%x\n", FastReadD= ummyClk)); +} + +/** + Calculate erase type typical time. + + @param[in] SfdpEraseTypicalTime Erase type typical time indicated = in + Basic Flash Parameter Table. + EraseTypicalTime [0:4] - Count + EraseTypicalTime [5:6] - Unit + 00b: 1ms + 01b: 16m= s + 10b: 128= ms + 11b: 1s + @param[in] SfdpEraseTimeMultiplier Multiplier from erase typical time= . + @param[out] EraseTypicalTime Pointer to receive Erase typical t= ime in milliseconds. + @param[out] EraseTimeout Pointer to receive Erase timeout i= n milliseconds. + +**/ +VOID +CalculateEraseTiming ( + IN UINT32 SfdpEraseTypicalTime, + IN UINT32 SfdpEraseTimeMultiplier, + OUT UINT32 *EraseTypicalTime, + OUT UINT64 *EraseTimeout + ) +{ + UINT32 UnitInMs; + + UnitInMs =3D (SfdpEraseTypicalTime & ERASE_TYPICAL_TIME_UNITS_MASK) >> E= RASE_TYPICAL_TIME_BIT_POSITION; + switch (UnitInMs) { + case ERASE_TYPICAL_TIME_UNIT_1_MS_BITMAP: + UnitInMs =3D ERASE_TYPICAL_TIME_UNIT_1_MS; + break; + + case ERASE_TYPICAL_TIME_UNIT_16_MS_BITMAP: + UnitInMs =3D ERASE_TYPICAL_TIME_UNIT_16_MS; + break; + + case ERASE_TYPICAL_TIME_UNIT_128_MS_BITMAP: + UnitInMs =3D ERASE_TYPICAL_TIME_UNIT_128_MS; + break; + + case ERASE_TYPICAL_TIME_UNIT_1000_MS_BITMAP: + UnitInMs =3D ERASE_TYPICAL_TIME_UNIT_1000_MS; + break; + default: + DEBUG ((DEBUG_ERROR, "%a: Unsupported Erase Typical time.\n", __func= __)); + ASSERT (FALSE); + } + + *EraseTypicalTime =3D UnitInMs * ((SfdpEraseTypicalTime & ERASE_TYPICAL_= TIME_COUNT_MASK) + 1); + *EraseTimeout =3D 2 * (SfdpEraseTimeMultiplier + 1) * *EraseTypicalT= ime; + return; +} + +/** + Print out the erase type information. + + @param[in] SupportedEraseType Pointer to SFDP_SUPPORTED_ERASE_TYPE_R= ECORD. +**/ +VOID +DebugPrintEraseType ( + IN SFDP_SUPPORTED_ERASE_TYPE_RECORD *SupportedEraseType + ) +{ + DEBUG ((DEBUG_VERBOSE, " Erase Type %d\n", SupportedEraseType->EraseTyp= e)); + DEBUG ((DEBUG_VERBOSE, " Erase Type instruction: 0x%x\n", SupportedEras= eType->EraseInstruction)); + DEBUG ((DEBUG_VERBOSE, " Erase size: 0x%x bytes\n", SupportedEraseType-= >EraseSizeInByte)); + DEBUG ((DEBUG_VERBOSE, " Erase time: %d Milliseconds\n", SupportedErase= Type->EraseTypicalTime)); + DEBUG ((DEBUG_VERBOSE, " Erase timeout: %d Milliseconds:\n", Supported= EraseType->EraseTimeout)); +} + +/** + Insert supported erase type entry. + + @param[in] Instance SPI Nor Flash Instance data with point= er to + EFI_SPI_NOR_FLASH_PROTOCOL and + EFI_SPI_IO_PROTOCOL. + @param[in] SupportedEraseType Pointer to SFDP_SUPPORTED_ERASE_TYPE_R= ECORD. +**/ +VOID +CreateEraseTypeEntry ( + IN SPI_NOR_FLASH_INSTANCE *Instance, + IN SFDP_SUPPORTED_ERASE_TYPE_RECORD *SupportedEraseType + ) +{ + InitializeListHead (&SupportedEraseType->NextEraseType); + InsertTailList (&Instance->SupportedEraseTypes, &SupportedEraseType->Nex= tEraseType); + + DEBUG ((DEBUG_VERBOSE, "%a: Erase Type 0x%x is supported:\n", __func__, = SupportedEraseType->EraseType)); + DebugPrintEraseType (SupportedEraseType); +} + +/** + Build up the erase type tables. + + @param[in] Instance SPI Nor Flash Instance data with pointer to + EFI_SPI_NOR_FLASH_PROTOCOL and + EFI_SPI_IO_PROTOCOL. + +**/ +VOID +BuildUpEraseTypeTable ( + IN SPI_NOR_FLASH_INSTANCE *Instance + ) +{ + SFDP_SUPPORTED_ERASE_TYPE_RECORD *SupportedEraseType; + + // Build up erase type 1 entry. + if (Instance->SfdpBasicFlash->Erase1Size !=3D 0) { + SupportedEraseType =3D AllocateZeroPool (sizeof (SFDP_SUPPORTED_ERASE_= TYPE_RECORD)); + if (SupportedEraseType !=3D NULL) { + SupportedEraseType->EraseType =3D SFDP_ERASE_TYPE_1; + SupportedEraseType->EraseInstruction =3D (UINT8)Instance->SfdpBasicF= lash->Erase1Instr; + SupportedEraseType->EraseSizeInByte =3D (UINT32)1 << Instance->Sfdp= BasicFlash->Erase1Size; + CalculateEraseTiming ( + Instance->SfdpBasicFlash->Erase1Time, + Instance->SfdpBasicFlash->EraseMultiplier, + &SupportedEraseType->EraseTypicalTime, + &SupportedEraseType->EraseTimeout + ); + CreateEraseTypeEntry (Instance, SupportedEraseType); + } else { + DEBUG ((DEBUG_ERROR, "%a: Memory allocated failed for SFDP_SUPPORTED= _ERASE_TYPE_RECORD (Type 1).\n", __func__)); + ASSERT (FALSE); + } + } + + // Build up erase type 2 entry. + if (Instance->SfdpBasicFlash->Erase2Size !=3D 0) { + SupportedEraseType =3D AllocateZeroPool (sizeof (SFDP_SUPPORTED_ERASE_= TYPE_RECORD)); + if (SupportedEraseType !=3D NULL) { + SupportedEraseType->EraseType =3D SFDP_ERASE_TYPE_2; + SupportedEraseType->EraseInstruction =3D (UINT8)Instance->SfdpBasicF= lash->Erase2Instr; + SupportedEraseType->EraseSizeInByte =3D (UINT32)1 << Instance->Sfdp= BasicFlash->Erase2Size; + CalculateEraseTiming ( + Instance->SfdpBasicFlash->Erase2Time, + Instance->SfdpBasicFlash->EraseMultiplier, + &SupportedEraseType->EraseTypicalTime, + &SupportedEraseType->EraseTimeout + ); + CreateEraseTypeEntry (Instance, SupportedEraseType); + } else { + DEBUG ((DEBUG_ERROR, "%a: Memory allocated failed for SFDP_SUPPORTED= _ERASE_TYPE_RECORD (Type 2).\n", __func__)); + ASSERT (FALSE); + } + } + + // Build up erase type 3 entry. + if (Instance->SfdpBasicFlash->Erase3Size !=3D 0) { + SupportedEraseType =3D AllocateZeroPool (sizeof (SFDP_SUPPORTED_ERASE_= TYPE_RECORD)); + if (SupportedEraseType !=3D NULL) { + SupportedEraseType->EraseType =3D SFDP_ERASE_TYPE_3; + SupportedEraseType->EraseInstruction =3D (UINT8)Instance->SfdpBasicF= lash->Erase3Instr; + SupportedEraseType->EraseSizeInByte =3D (UINT32)1 << Instance->Sfdp= BasicFlash->Erase3Size; + CalculateEraseTiming ( + Instance->SfdpBasicFlash->Erase3Time, + Instance->SfdpBasicFlash->EraseMultiplier, + &SupportedEraseType->EraseTypicalTime, + &SupportedEraseType->EraseTimeout + ); + CreateEraseTypeEntry (Instance, SupportedEraseType); + } else { + DEBUG ((DEBUG_ERROR, "%a: Memory allocated failed for SFDP_SUPPORTED= _ERASE_TYPE_RECORD (Type 3).\n", __func__)); + ASSERT (FALSE); + } + } + + // Build up erase type 4 entry. + if (Instance->SfdpBasicFlash->Erase4Size !=3D 0) { + SupportedEraseType =3D AllocateZeroPool (sizeof (SFDP_SUPPORTED_ERASE_= TYPE_RECORD)); + if (SupportedEraseType !=3D NULL) { + SupportedEraseType->EraseType =3D SFDP_ERASE_TYPE_4; + SupportedEraseType->EraseInstruction =3D (UINT8)Instance->SfdpBasicF= lash->Erase4Instr; + SupportedEraseType->EraseSizeInByte =3D (UINT32)1 << Instance->Sfdp= BasicFlash->Erase4Size; + CalculateEraseTiming ( + Instance->SfdpBasicFlash->Erase4Time, + Instance->SfdpBasicFlash->EraseMultiplier, + &SupportedEraseType->EraseTypicalTime, + &SupportedEraseType->EraseTimeout + ); + CreateEraseTypeEntry (Instance, SupportedEraseType); + } else { + DEBUG ((DEBUG_ERROR, "%a: Memory allocated failed for SFDP_SUPPORTED= _ERASE_TYPE_RECORD (Type 4).\n", __func__)); + ASSERT (FALSE); + } + } +} + +/** + This function check if the erase type is one of the target erase types. + + @param[in] EraseType The erase type. + @param[in] TargetTypeNum Number of target search types. + @param[in] TargetTypes Target types. + + + @retval TRUE Yes, this is the target erase type. + @retval FALSE No, this is not the target erase type. + +**/ +BOOLEAN +IsTargetEraseType ( + IN UINT16 EraseType, + IN UINT8 TargetTypeNum, + IN UINT8 *TargetTypes + ) +{ + UINT8 Index; + + for (Index =3D 0; Index < TargetTypeNum; Index++) { + if (EraseType =3D=3D *(TargetTypes + Index)) { + return TRUE; + } + } + + return FALSE; +} + +/** + Search the erase type record according to the given search type and valu= e. + + @param[in] Instance SPI Nor Flash Instance data with po= inter to + EFI_SPI_NOR_FLASH_PROTOCOL and + EFI_SPI_IO_PROTOCOL. + @param[in] SearchType Search type. + @param[in] SearchValue The value of according to search ty= pe. + - For SearchEraseTypeByCommand: + SearchValue is the erase instruct= ion. + - For SearchEraseTypeBySize: + SearchValue is the erase block s= ize. + - For SearchEraseTypeBySmallestSize= : + SearchValue is not used. + - For SearchEraseTypeByBiggestSize: + SearchValue is not used. + @param[in] SupportedTypeTargetNum Only search the specific erase type= s. + @param[in] SupportedTypeTarget Pointer to SupportedTypeTargetNum o= f + supported erase types. + @param[out] EraseTypeRecord Pointer to receive the erase type r= ecord. + + @retval EFI_SUCCESS Pointer to erase type record is ret= urned. + EFI_INVALID_PARAMETER Invalid SearchType. + EFI_NOT_FOUND Erase type not found. +**/ +EFI_STATUS +GetEraseTypeRecord ( + IN SPI_NOR_FLASH_INSTANCE *Instance, + IN SFDP_SEARCH_ERASE_TYPE SearchType, + IN UINT32 SearchValue, + IN UINT8 SupportedTypeTargetNum, + IN UINT8 *SupportedTypeTarget OPTIONAL, + OUT SFDP_SUPPORTED_ERASE_TYPE_RECORD **EraseTypeRecord + ) +{ + SFDP_SUPPORTED_ERASE_TYPE_RECORD *EraseType; + UINT32 ValueToCompare; + BOOLEAN ExitSearching; + + if (IsListEmpty (&Instance->SupportedEraseTypes)) { + return EFI_NOT_FOUND; + } + + *EraseTypeRecord =3D NULL; + + // + // Initial the comapre value. + // + switch (SearchType) { + case SearchEraseTypeByType: + case SearchEraseTypeByCommand: + case SearchEraseTypeBySize: + break; + case SearchEraseTypeBySmallestSize: + ValueToCompare =3D (UINT32)-1; + break; + case SearchEraseTypeByBiggestSize: + ValueToCompare =3D 0; + break; + default: + return EFI_INVALID_PARAMETER; + } + + ExitSearching =3D FALSE; + EraseType =3D (SFDP_SUPPORTED_ERASE_TYPE_RECORD *)GetFirstNode (&Ins= tance->SupportedEraseTypes); + while (TRUE) { + if ((SupportedTypeTarget =3D=3D NULL) || IsTargetEraseType (EraseType-= >EraseType, SupportedTypeTargetNum, SupportedTypeTarget)) { + switch (SearchType) { + case SearchEraseTypeByType: + if (EraseType->EraseType =3D=3D SearchValue) { + *EraseTypeRecord =3D EraseType; + ExitSearching =3D TRUE; + } + + break; + + case SearchEraseTypeBySize: + if (EraseType->EraseSizeInByte =3D=3D SearchValue) { + *EraseTypeRecord =3D EraseType; + ExitSearching =3D TRUE; + } + + break; + + case SearchEraseTypeByCommand: + if (EraseType->EraseInstruction =3D=3D (UINT8)SearchValue) { + *EraseTypeRecord =3D EraseType; + ExitSearching =3D TRUE; + } + + break; + + case SearchEraseTypeBySmallestSize: + if (EraseType->EraseSizeInByte < ValueToCompare) { + ValueToCompare =3D EraseType->EraseSizeInByte; + *EraseTypeRecord =3D EraseType; + } + + break; + + case SearchEraseTypeByBiggestSize: + if (EraseType->EraseSizeInByte > ValueToCompare) { + ValueToCompare =3D EraseType->EraseSizeInByte; + *EraseTypeRecord =3D EraseType; + } + + break; + + default: + return EFI_INVALID_PARAMETER; + } + } + + if (IsNodeAtEnd (&Instance->SupportedEraseTypes, &EraseType->NextErase= Type) || ExitSearching) { + break; + } + + EraseType =3D (SFDP_SUPPORTED_ERASE_TYPE_RECORD *)GetNextNode (&Instan= ce->SupportedEraseTypes, &EraseType->NextEraseType); + } + + if (*EraseTypeRecord =3D=3D NULL) { + return EFI_NOT_FOUND; + } + + return EFI_SUCCESS; +} + +/** + Get the erase block attribute for the target address. + + @param[in] Instance Spi Nor Flash Instance data with p= ointer to + EFI_SPI_NOR_FLASH_PROTOCOL and EFI= _SPI_IO_PROTOCOL + @param[in] FlashRegion The region the flash address belon= g. + @param[in] FlashAddress The target flash address. + @param[in] RemainingSize Remaining size to erase. + @param[in, out] BlockSizeToErase Input - The block erase size for = this continious blocks. + Output - The determined block size= for erasing. + @param[in, out] BlockCountToErase Input - The expected blocks to er= ase. + Output - The determined number of = blocks to erase. + @param[out] BlockEraseCommand The erase command used for this co= ntinious blocks. + @param[out] TypicalTime Pointer to receive the typical tim= e in millisecond + to erase this erase type size. + @param[out] MaximumTimeout Pointer to receive the maximum tim= eout in millisecond + to erase this erase type size. + + @retval EFI_SUCCESS The erase block attribute is returned. + @retval EFI_DEVICE_ERROR No valid SFDP discovered. + @retval EFI_NOT_FOUND No valud erase block attribute found. + +**/ +EFI_STATUS +GetEraseBlockAttribute ( + IN SPI_NOR_FLASH_INSTANCE *Instance, + IN SFDP_SECTOR_REGION_RECORD *FlashRegion, + IN UINT32 FlashAddress, + IN UINT32 RemainingSize, + IN OUT UINT32 *BlockSizeToErase, + IN OUT UINT32 *BlockCountToErase, + OUT UINT8 *BlockEraseCommand, + OUT UINT32 *TypicalTime, + OUT UINT64 *MaximumTimeout + ) +{ + EFI_STATUS Status; + SFDP_SUPPORTED_ERASE_TYPE_RECORD *EraseType; + UINT32 EraseSize; + + DEBUG ((DEBUG_VERBOSE, "%a: Entry\n", __func__)); + + for (EraseSize =3D SIZE_2GB; EraseSize !=3D 0; EraseSize =3D EraseSize >= > 1) { + Status =3D GetEraseTypeRecord (Instance, SearchEraseTypeBySize, EraseS= ize, 0, NULL, &EraseType); + if (!EFI_ERROR (Status)) { + // Validate this erase type. + if (((FlashAddress & (EraseType->EraseSizeInByte - 1)) =3D=3D 0) && + (RemainingSize >=3D EraseType->EraseSizeInByte)) + { + *BlockSizeToErase =3D EraseType->EraseSizeInByte; + *BlockCountToErase =3D 1; + *BlockEraseCommand =3D EraseType->EraseInstruction; + *TypicalTime =3D EraseType->EraseTypicalTime; + *MaximumTimeout =3D EraseType->EraseTimeout; + Status =3D EFI_SUCCESS; + break; + } + } + } + + if (EraseType =3D=3D NULL) { + return EFI_DEVICE_ERROR; + } + + DEBUG ((DEBUG_VERBOSE, " Erase address at 0x%08x.\n", FlashAddress)); + DEBUG ((DEBUG_VERBOSE, " - Erase block size : 0x%08x.\n", *BlockSiz= eToErase)); + DEBUG ((DEBUG_VERBOSE, " - Erase block count : 0x%08x.\n", *BlockCou= ntToErase)); + DEBUG ((DEBUG_VERBOSE, " - Erase block command: 0x%02x.\n", *BlockEra= seCommand)); + DEBUG ((DEBUG_VERBOSE, " - Remaining size to erase: 0x%08x.\n", Remai= ningSize)); + DEBUG ((DEBUG_VERBOSE, " - Erase typical time: %d milliseconds.\n", *= TypicalTime)); + DEBUG ((DEBUG_VERBOSE, " - Erase timeout: %d milliseconds.\n", *Maxim= umTimeout)); + return EFI_SUCCESS; +} + +/** + Get the erase block attribute for the target address. + + @param[in] Instance Spi Nor Flash Instance data with po= inter to + EFI_SPI_NOR_FLASH_PROTOCOL and EFI_= SPI_IO_PROTOCOL + @param[in] FlashAddress The target flash address. + @param[out] FlashRegion The target flash address. + + @retval EFI_SUCCESS The region is returned. + @retval EFI_INVALID_PARAMETER FlashAddress is not belong to any region= . + @retval Otherwise Other errors. + +**/ +EFI_STATUS +GetRegionByFlashAddress ( + IN SPI_NOR_FLASH_INSTANCE *Instance, + IN UINT32 FlashAddress, + OUT SFDP_SECTOR_REGION_RECORD **FlashRegion + ) +{ + SFDP_SECTOR_MAP_RECORD *SectorMapRecord; + SFDP_SECTOR_REGION_RECORD *RegionRecord; + + DEBUG ((DEBUG_VERBOSE, "%a: Entry\n", __func__)); + + SectorMapRecord =3D Instance->CurrentSectorMap; + if (SectorMapRecord =3D=3D NULL) { + return EFI_DEVICE_ERROR; + } + + RegionRecord =3D (SFDP_SECTOR_REGION_RECORD *)GetFirstNode (&SectorMapRe= cord->RegionList); + while (TRUE) { + if ((FlashAddress >=3D RegionRecord->RegionAddress) && + (FlashAddress < RegionRecord->RegionAddress + RegionRecord->Region= TotalSize)) + { + *FlashRegion =3D RegionRecord; + return EFI_SUCCESS; + } + + if (IsNodeAtEnd (&SectorMapRecord->RegionList, &RegionRecord->NextRegi= on)) { + break; + } + + RegionRecord =3D (SFDP_SECTOR_REGION_RECORD *)GetNextNode (&SectorMapR= ecord->RegionList, &RegionRecord->NextRegion); + } + + return EFI_INVALID_PARAMETER; +} + +/** + Build up the Fast Read capability tables. The earlier linked table + in the linked list has the faster transfer. + NOTE: 1. The Quad input instructions mentioned in 21th DWOWRD + are not considered yet. + 2. Maximum speed options for certain Fast Read modes are + not considered yet. (e.g., 8D-8D-8D or 4S-4D-4D) + + @param[in] Instance SPI Nor Flash Instance data with pointer to + EFI_SPI_NOR_FLASH_PROTOCOL and + EFI_SPI_IO_PROTOCOL. + +**/ +VOID +BuildUpFastReadTable ( + IN SPI_NOR_FLASH_INSTANCE *Instance + ) +{ + // Build up the standard Fast Read + // This will be first picked for the ReadData. + // TODO: The mechanism to choose the advance fast read + // is not determined yet in this version of + // SpiNorFlash driver. + CreateSpiFastReadTableEntry ( + Instance, + SPI_FLASH_FAST_READ, + 0, + SPI_FLASH_FAST_READ_DUMMY * 8 + ); + + // Build up Fast Read table 1S-1S-4S + if (Instance->SfdpBasicFlash->FastRead114 !=3D 0) { + CreateSpiFastReadTableEntry ( + Instance, + Instance->SfdpBasicFlash->FastRead114Instr, + Instance->SfdpBasicFlash->FastRead114ModeClk, + Instance->SfdpBasicFlash->FastRead114Dummy + ); + } + + // Build up Fast Read table 1S-2S-2S + if (Instance->SfdpBasicFlash->FastRead122 !=3D 0) { + CreateSpiFastReadTableEntry ( + Instance, + Instance->SfdpBasicFlash->FastRead122Instr, + Instance->SfdpBasicFlash->FastRead122ModeClk, + Instance->SfdpBasicFlash->FastRead122Dummy + ); + } + + // Build up Fast Read table 2S-2S-2S + if (Instance->SfdpBasicFlash->FastRead222 !=3D 0) { + CreateSpiFastReadTableEntry ( + Instance, + Instance->SfdpBasicFlash->FastRead222Instr, + Instance->SfdpBasicFlash->FastRead222ModeClk, + Instance->SfdpBasicFlash->FastRead222Dummy + ); + } + + // Build up Fast Read table 1S-4S-4S + if (Instance->SfdpBasicFlash->FastRead144 !=3D 0) { + CreateSpiFastReadTableEntry ( + Instance, + Instance->SfdpBasicFlash->FastRead144Instr, + Instance->SfdpBasicFlash->FastRead144ModeClk, + Instance->SfdpBasicFlash->FastRead144Dummy + ); + } + + // Build up Fast Read table 4S-4S-4S + if (Instance->SfdpBasicFlash->FastRead444 !=3D 0) { + CreateSpiFastReadTableEntry ( + Instance, + Instance->SfdpBasicFlash->FastRead444Instr, + Instance->SfdpBasicFlash->FastRead444ModeClk, + Instance->SfdpBasicFlash->FastRead444Dummy + ); + } + + // Build up Fast Read table 1S-1S-8S + if (Instance->SfdpBasicFlash->FastRead118Instr !=3D 0) { + CreateSpiFastReadTableEntry ( + Instance, + Instance->SfdpBasicFlash->FastRead118Instr, + Instance->SfdpBasicFlash->FastRead118ModeClk, + Instance->SfdpBasicFlash->FastRead118Dummy + ); + } + + // Build up Fast Read table 1S-8S-8S + if (Instance->SfdpBasicFlash->FastRead188Instr !=3D 0) { + CreateSpiFastReadTableEntry ( + Instance, + Instance->SfdpBasicFlash->FastRead188Instr, + Instance->SfdpBasicFlash->FastRead188ModeClk, + Instance->SfdpBasicFlash->FastRead188Dummy + ); + } +} + +/** + This function sets up the erase types supported + by this region. + + @param[in] Instance SPI Nor Flash Instance data with pointer t= o + EFI_SPI_NOR_FLASH_PROTOCOL and + EFI_SPI_IO_PROTOCOL. + @param[in] RegionRecord Pointer to SFDP_SECTOR_REGION_RECORD of th= is + regions. + @retval EFI_SUCCESS Current sector map configuration is determ= ined. + EFI_DEVICE_ERROR Current sector map configuration is not fo= und. + +**/ +EFI_STATUS +SetupRegionEraseInfo ( + IN SPI_NOR_FLASH_INSTANCE *Instance, + IN SFDP_SECTOR_REGION_RECORD *RegionRecord + ) +{ + SFDP_SUPPORTED_ERASE_TYPE_RECORD *SupportedEraseType; + UINT32 MinimumEraseSize; + + if (IsListEmpty (&Instance->SupportedEraseTypes)) { + DEBUG ((DEBUG_ERROR, "%a: No erase type suppoted on the flash device.\= n", __func__)); + ASSERT (FALSE); + return EFI_DEVICE_ERROR; + } + + MinimumEraseSize =3D (UINT32)-1; + SupportedEraseType =3D (SFDP_SUPPORTED_ERASE_TYPE_RECORD *)GetFirstNode = (&Instance->SupportedEraseTypes); + while (TRUE) { + RegionRecord->SupportedEraseType[RegionRecord->SupportedEraseTypeNum] = =3D (UINT8)SupportedEraseType->EraseType; + RegionRecord->SupportedEraseTypeNum++; + RegionRecord->EraseTypeBySizeBitmap |=3D SupportedEraseType->EraseSize= InByte; + if (MinimumEraseSize > SupportedEraseType->EraseSizeInByte) { + MinimumEraseSize =3D SupportedEraseType->EraseSizeInByte; + } + + if (IsNodeAtEnd (&Instance->SupportedEraseTypes, &SupportedEraseType->= NextEraseType)) { + break; + } + + SupportedEraseType =3D (SFDP_SUPPORTED_ERASE_TYPE_RECORD *)GetNextNode= (&Instance->SupportedEraseTypes, &SupportedEraseType->NextEraseType); + } + + RegionRecord->SectorSize =3D MinimumEraseSize; + RegionRecord->RegionTotalSize =3D Instance->FlashDeviceSize; + RegionRecord->RegionSectors =3D RegionRecord->RegionTotalSize / Region= Record->SectorSize; + return EFI_SUCCESS; +} + +/** + Create a single flash sector map. + + @param[in] Instance SPI Nor Flash Instance data with pointer t= o + EFI_SPI_NOR_FLASH_PROTOCOL and + EFI_SPI_IO_PROTOCOL. + @retval EFI_SUCCESS Current sector map configuration is dete= rmined. + EFI_DEVICE_ERROR Current sector map configuration is not = found. + +**/ +EFI_STATUS +CreateSingleFlashSectorMap ( + IN SPI_NOR_FLASH_INSTANCE *Instance + ) +{ + SFDP_SECTOR_MAP_RECORD *SectorMapRecord; + SFDP_SECTOR_REGION_RECORD *RegionRecord; + UINTN EraseIndex; + + DEBUG ((DEBUG_VERBOSE, "%a: Entry:\n", __func__)); + SectorMapRecord =3D (SFDP_SECTOR_MAP_RECORD *)AllocateZeroPool (sizeof (= SFDP_SECTOR_MAP_RECORD)); + if (SectorMapRecord =3D=3D NULL) { + DEBUG ((DEBUG_ERROR, "%a: No memory resource for SFDP_SECTOR_MAP_DETEC= TION_RECORD.\n", __func__)); + ASSERT (FALSE); + return EFI_OUT_OF_RESOURCES; + } + + // Create SFDP_SECTOR_MAP_RECORD. + InitializeListHead (&SectorMapRecord->NextDescriptor); + InitializeListHead (&SectorMapRecord->RegionList); + SectorMapRecord->ConfigurationId =3D 0; + SectorMapRecord->RegionCount =3D 1; + InsertTailList (&Instance->ConfigurationMapList, &SectorMapRecord->NextD= escriptor); + DEBUG ((DEBUG_VERBOSE, " Sector map configurations ID : 0x%x\n", = SectorMapRecord->ConfigurationId)); + DEBUG ((DEBUG_VERBOSE, " Sector map configurations regions: %d\n", Se= ctorMapRecord->RegionCount)); + + // Create SFDP_SECTOR_MAP_RECORD region record. + RegionRecord =3D (SFDP_SECTOR_REGION_RECORD *)AllocateZeroPool (sizeof (= SFDP_SECTOR_REGION_RECORD)); + if (RegionRecord =3D=3D NULL) { + DEBUG ((DEBUG_ERROR, "%a: No memory resource for SFDP_SECTOR_REGION_RE= CORD.\n", __func__)); + ASSERT (FALSE); + return EFI_OUT_OF_RESOURCES; + } + + InitializeListHead (&RegionRecord->NextRegion); + + RegionRecord->RegionAddress =3D 0; + // + // Setup erase information in the region record. + // + SetupRegionEraseInfo (Instance, RegionRecord); + + InsertTailList (&SectorMapRecord->RegionList, &RegionRecord->NextRegion)= ; + + Instance->CurrentSectorMap =3D SectorMapRecord; + + DEBUG ((DEBUG_VERBOSE, " Region totoal size : 0x%x\n", Region= Record->RegionTotalSize)); + DEBUG ((DEBUG_VERBOSE, " Region sector size : 0x%x\n", Region= Record->SectorSize)); + DEBUG ((DEBUG_VERBOSE, " Region sectors : 0x%x\n", Region= Record->RegionSectors)); + + for (EraseIndex =3D 0; EraseIndex < RegionRecord->SupportedEraseTypeNum;= EraseIndex++) { + DEBUG ((DEBUG_VERBOSE, " Region erase type supported: 0x%x\n", Regi= onRecord->SupportedEraseType[EraseIndex])); + } + + return EFI_SUCCESS; +} + +/** + Set EraseBlockBytes in SPI NOR Flash Protocol + + @param[in] Instance Spi Nor Flash Instance data with pointer to + EFI_SPI_NOR_FLASH_PROTOCOL and EFI_SPI_IO_PROTOC= OL + + @retval EFI_SUCCESS The erase block size is returned. + @retval Otherwise Failed to get erase block size. + +**/ +EFI_STATUS +SetSectorEraseBlockSize ( + IN SPI_NOR_FLASH_INSTANCE *Instance + ) +{ + EFI_STATUS Status; + SFDP_SUPPORTED_ERASE_TYPE_RECORD *EraseTypeRecord; + + // Use the smallest size for the sector erase. + Status =3D GetEraseTypeRecord (Instance, SearchEraseTypeBySmallestSize, = 0, 0, NULL, &EraseTypeRecord); + if (!EFI_ERROR (Status)) { + Instance->Protocol.EraseBlockBytes =3D EraseTypeRecord->EraseSizeInByt= e; + DEBUG ((DEBUG_VERBOSE, " Erase block size =3D 0x%08x\n", EraseTypeRec= ord->EraseSizeInByte)); + } + + return Status; +} + +/** + Get the current sector map configuration. + + @param[in] Instance SPI Nor Flash Instance data with pointer to + EFI_SPI_NOR_FLASH_PROTOCOL and + EFI_SPI_IO_PROTOCOL. + + @retval EFI_SUCCESS Current sector map configuration is dete= rmined. + EFI_DEVICE_ERROR Current sector map configuration is not = found. + +**/ +EFI_STATUS +GetCurrentSectorMapConfiguration ( + IN SPI_NOR_FLASH_INSTANCE *Instance + ) +{ + EFI_STATUS Status; + UINT32 TransactionBufferLength; + UINT8 AddressLength; + BOOLEAN UseAddress; + UINT32 DummyBytes; + UINT8 ReturnByte; + UINT8 ConfigurationId; + SFDP_SECTOR_MAP_RECORD *SectorMap; + SFDP_SECTOR_MAP_DETECTION_RECORD *CommandEntry; + + Instance->CurrentSectorMap =3D NULL; + if (!Instance->ConfigurationCommandsNeeded) { + // No command needed measn only one configuration for the flash device= sector map. + Instance->CurrentSectorMap =3D (SFDP_SECTOR_MAP_RECORD *)GetFirstNode = (&Instance->ConfigurationMapList); + return EFI_SUCCESS; + } + + // + // Send the command to collect interest bit. + // + ConfigurationId =3D 0; + CommandEntry =3D (SFDP_SECTOR_MAP_DETECTION_RECORD *)GetFirstNode (&I= nstance->ConfigurationCommandList); + while (TRUE) { + // Check not WIP + Status =3D WaitNotWip (Instance, FixedPcdGet32 (PcdSpiNorFlashOperatio= nDelayMicroseconds), FixedPcdGet32 (PcdSpiNorFlashFixedTimeoutRetryCount)); + + // Read configuration byte. + AddressLength =3D SPI_ADDR_3BYTE_ONLY; + DummyBytes =3D 1; + if (CommandEntry->CommandAddressLength =3D=3D SpdfConfigurationCommand= Address4Byte) { + AddressLength =3D SPI_ADDR_4BYTE_ONLY; + DummyBytes =3D 0; + } + + UseAddress =3D TRUE; + if (CommandEntry->CommandAddress =3D=3D SpdfConfigurationCommandAddres= sNone) { + UseAddress =3D FALSE; + } + + TransactionBufferLength =3D FillWriteBuffer ( + Instance, + CommandEntry->CommandInstruction, + DummyBytes, + AddressLength, + UseAddress, + CommandEntry->CommandAddress, + 0, + NULL + ); + Status =3D Instance->SpiIo->Transaction ( + Instance->SpiIo, + SPI_TRANSACTION_WRITE_THEN_READ, + FALSE, + 0, + 1, + 8, + TransactionBufferLength, + Instance->SpiTransactionWriteBuffer, + 1, + &ReturnByte + ); + ASSERT_EFI_ERROR (Status); + if (EFI_ERROR (Status)) { + DEBUG ((DEBUG_ERROR, "%a: Fails to read the configuration byte.\n", = __func__)); + ASSERT (FALSE); + return EFI_DEVICE_ERROR; + } + + // + // Retrieve the interest bit. + // + if ((ReturnByte & CommandEntry->ConfigurationBitMask) !=3D 0) { + ConfigurationId |=3D 0x01; + } + + if (IsNodeAtEnd (&Instance->ConfigurationCommandList, &CommandEntry->N= extCommand)) { + break; + } + + CommandEntry =3D (SFDP_SECTOR_MAP_DETECTION_RECORD *)GetNextNode (&= Instance->ConfigurationCommandList, &CommandEntry->NextCommand); + ConfigurationId =3D ConfigurationId << 1; + } + + // + // Now we have current activated configuration ID in ConfigurationId. + // Walk through ConfigurationMapList to record the activated flash secto= r + // map configuration. + // + SectorMap =3D (SFDP_SECTOR_MAP_RECORD *)GetFirstNode (&Instance->Configu= rationMapList); + while (TRUE) { + if (SectorMap->ConfigurationId =3D=3D ConfigurationId) { + Instance->CurrentSectorMap =3D SectorMap; + break; + } + + if (IsNodeAtEnd (&Instance->ConfigurationMapList, &SectorMap->NextDesc= riptor)) { + break; + } + + SectorMap =3D (SFDP_SECTOR_MAP_RECORD *)GetNextNode (&Instance->Config= urationMapList, &SectorMap->NextDescriptor); + } + + if (Instance->CurrentSectorMap =3D=3D NULL) { + DEBUG ((DEBUG_ERROR, "%a: Activated flash sector map is not found!\n",= __func__)); + ASSERT (FALSE); + return EFI_DEVICE_ERROR; + } + + return EFI_SUCCESS; +} + +/** + Build sector map configurations. + + @param[in] Instance SPI Nor Flash Instance data with pointer to + EFI_SPI_NOR_FLASH_PROTOCOL and + EFI_SPI_IO_PROTOCOL. + + @retval EFI_SUCCESS Records of sector map configuration co= mmand and map + descriptor are built up successfully. + EFI_OUT_OF_RESOURCES Not enough memory resource. + EFI_DEVICE_ERROR SFDP Sector Map Parameter is not + constructed correctly. + +**/ +EFI_STATUS +BuildSectorMapCommandAndMap ( + IN SPI_NOR_FLASH_INSTANCE *Instance + ) +{ + SFDP_SECTOR_MAP_TABLE *SfdpSectorMapTable; + SFDP_SECTOR_CONFIGURATION_COMMAND *SfdpDetectionCommand; + SFDP_SECTOR_MAP_DETECTION_RECORD *CommandEntry; + SFDP_SECTOR_CONFIGURATION_MAP *SfdpConfigurationMap; + SFDP_SECTOR_MAP_RECORD *SectorMapRecord; + SFDP_SECTOR_REGION *SpdfSectorRegion; + SFDP_SECTOR_REGION_RECORD *RegionRecord; + SFDP_SUPPORTED_ERASE_TYPE_RECORD *SupportedEraseType; + UINT8 RegionCount; + UINT8 EraseTypeCount; + UINT32 MinimumEraseSize; + UINT32 RegionAddress; + + SfdpSectorMapTable =3D Instance->SfdpFlashSectorMap; + SfdpConfigurationMap =3D &SfdpSectorMapTable->ConfigurationMap; + SfdpDetectionCommand =3D &SfdpSectorMapTable->ConfigurationCommand; + + if (SfdpSectorMapTable->GenericHeader.DescriptorType =3D=3D SFDP_SECTOR_= MAP_TABLE_ENTRY_TYPE_MAP) { + // No configuration detection commands are needs. + Instance->ConfigurationCommandsNeeded =3D FALSE; + } else { + DEBUG ((DEBUG_VERBOSE, "%a: Sector map configuration detection command= is needed\n", __func__)); + Instance->ConfigurationCommandsNeeded =3D TRUE; + + // Go through the section map detection commands. + while (TRUE) { + CommandEntry =3D (SFDP_SECTOR_MAP_DETECTION_RECORD *)AllocateZeroPoo= l (sizeof (SFDP_SECTOR_MAP_DETECTION_RECORD)); + if (CommandEntry =3D=3D NULL) { + DEBUG ((DEBUG_ERROR, "%a: No memory resource for SFDP_SECTOR_MAP_D= ETECTION_RECORD.\n", __func__)); + ASSERT (FALSE); + return EFI_OUT_OF_RESOURCES; + } + + InitializeListHead (&CommandEntry->NextCommand); + CommandEntry->CommandAddress =3D SfdpDetectionCommand->Command= Address; + CommandEntry->CommandAddressLength =3D (SPDF_CONFIGURATION_COMMAND_A= DDR_LENGTH)SfdpDetectionCommand->DetectionCommandAddressLen; + CommandEntry->CommandInstruction =3D (UINT8)SfdpDetectionCommand->= DetectionInstruction; + CommandEntry->ConfigurationBitMask =3D (UINT8)SfdpDetectionCommand->= ReadDataMask; + CommandEntry->LatencyInClock =3D (UINT8)SfdpDetectionCommand->= DetectionLatency; + InsertTailList (&Instance->ConfigurationCommandList, &CommandEntry->= NextCommand); + DEBUG ((DEBUG_VERBOSE, " Command instruction : 0x%x\n", CommandEn= try->CommandInstruction)); + DEBUG ((DEBUG_VERBOSE, " Bit selection : 0x%x\n", CommandEn= try->ConfigurationBitMask)); + DEBUG ((DEBUG_VERBOSE, " Command address : 0x%x\n", CommandEn= try->CommandAddress)); + DEBUG ((DEBUG_VERBOSE, " Command address length: %d\n", CommandEntr= y->CommandAddressLength)); + DEBUG ((DEBUG_VERBOSE, " Command latency clocks: %d\n\n", CommandEn= try->LatencyInClock)); + if (SfdpDetectionCommand->DescriptorEnd =3D=3D SFDP_SECTOR_MAP_TABLE= _ENTRY_LAST) { + break; + } + + SfdpDetectionCommand++; + } + + SfdpConfigurationMap =3D (SFDP_SECTOR_CONFIGURATION_MAP *)SfdpDetectio= nCommand++; + } + + // + // Go through the region table pointed in SfdpConfigurationMap. + // + if (SfdpConfigurationMap->DescriptorType !=3D SFDP_SECTOR_MAP_TABLE_ENTR= Y_TYPE_MAP) { + DEBUG ((DEBUG_ERROR, "%a: Incorrect format of Sector Map Parameter.\n"= , __func__)); + ASSERT (FALSE); + return EFI_DEVICE_ERROR; + } + + while (TRUE) { + DEBUG ((DEBUG_VERBOSE, "%a: Sector map configurations:\n", __func__)); + SectorMapRecord =3D (SFDP_SECTOR_MAP_RECORD *)AllocateZeroPool (sizeof= (SFDP_SECTOR_MAP_RECORD)); + if (SectorMapRecord =3D=3D NULL) { + DEBUG ((DEBUG_ERROR, "%a: No memory resource for SFDP_SECTOR_MAP_DET= ECTION_RECORD.\n", __func__)); + ASSERT (FALSE); + return EFI_OUT_OF_RESOURCES; + } + + InitializeListHead (&SectorMapRecord->NextDescriptor); + InitializeListHead (&SectorMapRecord->RegionList); + SectorMapRecord->ConfigurationId =3D (UINT8)SfdpConfigurationMap->Conf= igurationID; + SectorMapRecord->RegionCount =3D (UINT8)SfdpConfigurationMap->Regi= onCount; + InsertTailList (&Instance->ConfigurationMapList, &SectorMapRecord->Nex= tDescriptor); + DEBUG ((DEBUG_VERBOSE, " Sector map configurations ID : 0x%x\n"= , SectorMapRecord->ConfigurationId)); + DEBUG ((DEBUG_VERBOSE, " Sector map configurations regions: %d\n", = SectorMapRecord->RegionCount)); + SpdfSectorRegion =3D (SFDP_SECTOR_REGION *)SfdpConfigurationMap + 1; + RegionAddress =3D 0; + for (RegionCount =3D 0; RegionCount < SectorMapRecord->RegionCount; Re= gionCount++) { + RegionRecord =3D (SFDP_SECTOR_REGION_RECORD *)AllocateZeroPool (size= of (SFDP_SECTOR_REGION_RECORD)); + if (RegionRecord =3D=3D NULL) { + DEBUG ((DEBUG_ERROR, "%a: No memory resource for SFDP_SECTOR_MAP_D= ETECTION_RECORD.\n", __func__)); + ASSERT (FALSE); + return EFI_OUT_OF_RESOURCES; + } + + InitializeListHead (&RegionRecord->NextRegion); + RegionRecord->RegionTotalSize =3D (SpdfSectorRegion->RegionSize + 1)= * SFDP_SECTOR_REGION_SIZE_UNIT; + // + // Construct erase type supported for this region. + // + if (SpdfSectorRegion->EraseType1 !=3D 0) { + RegionRecord->SupportedEraseType[RegionRecord->SupportedEraseTypeN= um] =3D SFDP_ERASE_TYPE_1; + RegionRecord->SupportedEraseTypeNum++; + } + + if (SpdfSectorRegion->EraseType2 !=3D 0) { + RegionRecord->SupportedEraseType[RegionRecord->SupportedEraseTypeN= um] =3D SFDP_ERASE_TYPE_2; + RegionRecord->SupportedEraseTypeNum++; + } + + if (SpdfSectorRegion->EraseType3 !=3D 0) { + RegionRecord->SupportedEraseType[RegionRecord->SupportedEraseTypeN= um] =3D SFDP_ERASE_TYPE_3; + RegionRecord->SupportedEraseTypeNum++; + } + + if (SpdfSectorRegion->EraseType4 !=3D 0) { + RegionRecord->SupportedEraseType[RegionRecord->SupportedEraseTypeN= um] =3D SFDP_ERASE_TYPE_4; + RegionRecord->SupportedEraseTypeNum++; + } + + // + // Calculate the sector size and total sectors. + // + if (IsListEmpty (&Instance->SupportedEraseTypes)) { + DEBUG ((DEBUG_ERROR, "%a: No erase type suppoted on the flash devi= ce.\n", __func__)); + ASSERT (FALSE); + return EFI_DEVICE_ERROR; + } + + MinimumEraseSize =3D (UINT32)-1; + for (EraseTypeCount =3D 0; EraseTypeCount < RegionRecord->SupportedE= raseTypeNum++; EraseTypeCount++) { + // + // Walk through Instance->SupportedEraseTypes to find the matching= erase type and + // Use the minimum erase size as the sector size; + // + SupportedEraseType =3D (SFDP_SUPPORTED_ERASE_TYPE_RECORD *)GetFirs= tNode (&Instance->SupportedEraseTypes); + while (TRUE) { + if (RegionRecord->SupportedEraseType[EraseTypeCount] =3D=3D Supp= ortedEraseType->EraseType) { + // Set erase size bitmap. + RegionRecord->EraseTypeBySizeBitmap |=3D SupportedEraseType->E= raseSizeInByte; + + if (MinimumEraseSize > SupportedEraseType->EraseSizeInByte) { + MinimumEraseSize =3D SupportedEraseType->EraseSizeInByte; + break; + } + } + + if (IsNodeAtEnd (&Instance->SupportedEraseTypes, &SupportedErase= Type->NextEraseType)) { + break; + } + + SupportedEraseType =3D (SFDP_SUPPORTED_ERASE_TYPE_RECORD *)GetNe= xtNode (&Instance->SupportedEraseTypes, &SupportedEraseType->NextEraseType)= ; + } + } + + RegionRecord->SectorSize =3D MinimumEraseSize; + RegionRecord->RegionSectors =3D RegionRecord->RegionTotalSize / Regi= onRecord->SectorSize; + RegionRecord->RegionAddress =3D RegionAddress; + + // Insert to link. + InsertTailList (&SectorMapRecord->RegionList, &RegionRecord->NextReg= ion); + DEBUG ((DEBUG_VERBOSE, " Region: %d\n", RegionCount)); + DEBUG ((DEBUG_VERBOSE, " Region totoal size: 0x%x\n", Regio= nRecord->RegionTotalSize)); + DEBUG ((DEBUG_VERBOSE, " Region sector size: 0x%x\n", Regio= nRecord->SectorSize)); + DEBUG ((DEBUG_VERBOSE, " Region sectors : 0x%x\n", Regio= nRecord->RegionSectors)); + DEBUG ((DEBUG_VERBOSE, " Region erase supported bitmap: 0x%= x\n", RegionRecord->EraseTypeBySizeBitmap)); + + SpdfSectorRegion++; + RegionAddress +=3D RegionRecord->RegionTotalSize; + } + + if (SfdpConfigurationMap->DescriptorEnd =3D=3D SFDP_SECTOR_MAP_TABLE_E= NTRY_LAST) { + break; + } + + SfdpConfigurationMap =3D (SFDP_SECTOR_CONFIGURATION_MAP *)SpdfSectorRe= gion; + } + + return EFI_SUCCESS; +} + +/** + This routine get Write Enable latch command. + + @param[in] Instance SPI Nor Flash Instance data with pointer to + EFI_SPI_NOR_FLASH_PROTOCOL and + EFI_SPI_IO_PROTOCOL. + +**/ +VOID +GetWriteEnableCommand ( + IN SPI_NOR_FLASH_INSTANCE *Instance + ) +{ + // + // Set Wrtie Enable command. + // + Instance->WriteEnableLatchRequired =3D TRUE; + Instance->WriteEnableLatchCommand =3D SPI_FLASH_WREN; + if (Instance->SfdpBasicFlash->VolatileStatusBlockProtect =3D=3D 1) { + if (Instance->SfdpBasicFlash->WriteEnableVolatileStatus =3D=3D 0) { + Instance->WriteEnableLatchCommand =3D SPI_FLASH_WREN_50H; + } + } + + DEBUG ((DEBUG_ERROR, "%a: Use Write Enable Command 0x%x.\n", __func__, I= nstance->WriteEnableLatchCommand)); +} + +/** + This routine returns the desired Fast Read mode. + + @param[in] Instance Spi Nor Flash Instance dat= a with pointer to + EFI_SPI_NOR_FLASH_PROTOCOL= and EFI_SPI_IO_PROTOCOL + @param[in,out] FastReadInstruction Fast Read instruction, the= input is + the default value. + @param[in,out] FastReadModeBits The operational mode bits. + @param[in,out] FastReadDummyClocks Fast Read wait state (Dumm= y clocks), the + input is the default value= . + + @retval EFI_SUCCESS The parameters are updated. + @retval EFI_NOT_FOUND No desired Fas Read mode found. + +**/ +EFI_STATUS +GetFastReadParameter ( + IN SPI_NOR_FLASH_INSTANCE *Instance, + IN OUT UINT8 *FastReadInstruction, + IN OUT UINT8 *FastReadModeBits, + IN OUT UINT8 *FastReadDummyClocks + ) +{ + SFPD_FAST_READ_CAPBILITY_RECORD *FastReadEntry; + + if (IsListEmpty (&Instance->FastReadTableList)) { + return EFI_NOT_FOUND; + } + + FastReadEntry =3D (SFPD_FAST_READ_CAPBILITY_RECORD *)GetFirstNode= (&Instance->FastReadTableList); + *FastReadInstruction =3D FastReadEntry->FastReadInstruction; + *FastReadDummyClocks =3D FastReadEntry->WaitStates; + *FastReadModeBits =3D FastReadEntry->ModeClocks; + + // + // *FastReadOperationClock may be replaced by 8D-8D-8D or 4S-4D-4D Fast = Read + // mode clock operation mode. Which is not cosidered in the implementati= on yet. + // + return EFI_SUCCESS; +} + +/** + Return the flash device size from SFDP Basic Flash Parameter Table DWORD= 2 + + @param[in] Instance Spi Nor Flash Instance data with pointer to + EFI_SPI_NOR_FLASH_PROTOCOL and + EFI_SPI_IO_PROTOCOL. + + @retval UINT32 Flash device size in byte, zero indicates error. + +**/ +UINT32 +SfdpGetFlashSize ( + IN SPI_NOR_FLASH_INSTANCE *Instance + ) +{ + if (Instance =3D=3D NULL) { + return 0; + } + + if ((Instance->SfdpBasicFlash->Density & SFDP_FLASH_MEMORY_DENSITY_4GBIT= ) =3D=3D 0) { + // + // The flash device size is <=3D 256MB. + // + return (Instance->SfdpBasicFlash->Density + 1) / 8; + } + + // + // The flash deivce size is >=3D 512MB. + // Bit [0:30] defines 'N' where the density is computed as 2^N bits. + // N must be >=3D32 according to the SFDP specification. + // + if ((Instance->SfdpBasicFlash->Density & ~SFDP_FLASH_MEMORY_DENSITY_4GBI= T) < 32) { + return 0; + } + + return (UINT32)RShiftU64 (LShiftU64 (1, Instance->SfdpBasicFlash->Densit= y & ~SFDP_FLASH_MEMORY_DENSITY_4GBIT), 3); +} + +/** + Read SFDP Header + + This routine reads the JEDEC SPI Flash Discoverable Parameter header fro= m the + SPI chip. Fails if Major Revision is not =3D 1 + + @param[in] Instance Spi Nor Flash Instance data with pointer to + EFI_SPI_NOR_FLASH_PROTOCOL and EFI_SPI_IO_PROTOC= OL + + @retval EFI_SUCCESS Header is filled in + @retval EFI_DEVICE_ERROR Invalid data received from SPI flash part= . + +**/ +EFI_STATUS +EFIAPI +ReadSfdpHeader ( + IN SPI_NOR_FLASH_INSTANCE *Instance + ) +{ + EFI_STATUS Status; + UINT32 TransactionBufferLength; + + // Check not WIP + Status =3D WaitNotWip (Instance, FixedPcdGet32 (PcdSpiNorFlashOperationD= elayMicroseconds), FixedPcdGet32 (PcdSpiNorFlashFixedTimeoutRetryCount)); + + // Read SFDP Header + TransactionBufferLength =3D FillWriteBuffer ( + Instance, + SPI_FLASH_RDSFDP, + SPI_FLASH_RDSFDP_DUMMY, + SPI_FLASH_RDSFDP_ADDR_BYTES, + TRUE, + 0, + 0, + NULL + ); + Status =3D Instance->SpiIo->Transaction ( + Instance->SpiIo, + SPI_TRANSACTION_WRITE_THEN_READ, + FALSE, + 0, + 1, + 8, + TransactionBufferLength, + Instance->SpiTransactionWriteBuffer, + sizeof (SFDP_HEADER), + (UINT8 *)&Instance->SfdpHeader + ); + ASSERT_EFI_ERROR (Status); + if (!EFI_ERROR (Status)) { + // Read Basic Flash Parameter Header + if ((Instance->SfdpHeader.Signature !=3D SFDP_HEADER_SIGNATURE) || + (Instance->SfdpHeader.MajorRev !=3D SFDP_SUPPORTED_MAJOR_REVISION)= ) + { + Status =3D EFI_DEVICE_ERROR; + } else { + DEBUG ((DEBUG_VERBOSE, "Total %d parameter headers\n", Instance->Sfd= pHeader.NumParameterHeaders + 1)); + } + } + + return Status; +} + +/** + Read SFDP + This routine reads the JEDEC SPI Flash Discoverable Parameters. We just + read the necessary tables in this routine. + + @param[in] Instance Spi Nor Flash Instance data with pointer to + EFI_SPI_NOR_FLASH_PROTOCOL and EFI_SPI_IO_PROTOC= OL + + @retval EFI_SUCCESS Header is filled in + @retval EFI_DEVICE_ERROR Invalid data received from SPI flash part= . + +**/ +EFI_STATUS +ReadSfdp ( + IN SPI_NOR_FLASH_INSTANCE *Instance + ) +{ + EFI_STATUS Status; + SFDP_SUPPORTED_ERASE_TYPE_RECORD *EraseTypeRecord; + + InitializeListHead (&Instance->FastReadTableList); + InitializeListHead (&Instance->SupportedEraseTypes); + InitializeListHead (&Instance->ConfigurationCommandList); + InitializeListHead (&Instance->ConfigurationMapList); + + DEBUG ((DEBUG_VERBOSE, "%a: Entry\n", __func__)); + + Status =3D ReadSfdpHeader (Instance); + if (EFI_ERROR (Status)) { + DEBUG ((DEBUG_ERROR, "%a: Failed to read SFDP header\n", __func__)); + ASSERT (FALSE); + return Status; + } + + Status =3D ReadSfdpBasicParameterTable (Instance); + if (EFI_ERROR (Status) && (Status !=3D EFI_NOT_FOUND)) { + DEBUG ((DEBUG_ERROR, "%a: Failed to read SFDP Basic Parameter Table\n"= , __func__)); + ASSERT (FALSE); + return Status; + } + + Instance->FlashDeviceSize =3D SfdpGetFlashSize (Instance); + DEBUG ((DEBUG_VERBOSE, "%a: Flash Size=3D0x%X\n", __func__, Instance->Fl= ashDeviceSize)); + if (Instance->FlashDeviceSize =3D=3D 0) { + ASSERT (FALSE); + return Status; + } + + Status =3D ReadSfdpSectorMapParameterTable (Instance); + if (EFI_ERROR (Status) && (Status !=3D EFI_NOT_FOUND)) { + DEBUG ((DEBUG_ERROR, "%a: Failed to read SFDP Sector Map Parameter Tab= le\n", __func__)); + ASSERT (FALSE); + } else if (Status =3D=3D EFI_NOT_FOUND) { + DEBUG ((DEBUG_VERBOSE, "%a: The SPI NOR flash device doesn't have SFDP= Sector Map Parameter Table implemented:\n", __func__)); + + // + // No SFDP Sector Map Parameter Table exist. + // Check if device support the uniform 4K erase size. + // + Instance->Uniform4KEraseSupported =3D FALSE; + if (Instance->SfdpBasicFlash->EraseSizes =3D=3D SPI_UNIFORM_4K_ERASE_S= UPPORTED) { + DEBUG ((DEBUG_VERBOSE, "%a: The SPI NOR flash device supports unifor= m 4K erase.\n", __func__)); + + // Check if 4K erase type supported? + Status =3D GetEraseTypeRecord (Instance, SearchEraseTypeBySize, SIZE= _4KB, 0, NULL, &EraseTypeRecord); + if (Status =3D=3D EFI_NOT_FOUND) { + DEBUG ((DEBUG_ERROR, "However, no corresponding 4K size erase type= found.\n")); + ASSERT (FALSE); + } + + Instance->Uniform4KEraseSupported =3D TRUE; + } else { + // Uniform 4K erase unsupported, get the smallest erase block size. + DEBUG ((DEBUG_VERBOSE, "%a: The SPI NOR flash device doesn't support= uniform 4K erase.\n", __func__)); + } + + // + // Build flash map + // Instance->ConfigurationMapList is an empty list because no FDP Sect= or Map Parameter Table. + // + CreateSingleFlashSectorMap (Instance); + Status =3D EFI_SUCCESS; + } + + return Status; +} + +/** + Read SFDP Specific Parameter Header + + This routine reads the JEDEC SPI Flash Discoverable Parameter header fro= m the + SPI chip. Fails if Major Revision is not =3D SFDP_SUPPORTED_MAJOR_REVIS= ION. + + @param[in] Instance Spi Nor Flash Instance data with pointe= r to + EFI_SPI_NOR_FLASH_PROTOCOL and EFI_SPI_= IO_PROTOCOL + @param[in] SfdpParameterHeader SFDP Header Buffer Pointer + @param[in] ParameterIdMsb Most significant byte of parameter ID. + @param[in] ParameterIdLsb Lowest significant byte of parameter ID= . + + @retval EFI_SUCCESS Header is filled in + @retval EFI_DEVICE_ERROR Invalid data received from SPI flash part= . + @retval EFI_NOT_FOUND Unsupported Parameter Header. + +**/ +EFI_STATUS +EFIAPI +ReadSfdpParameterHeader ( + IN SPI_NOR_FLASH_INSTANCE *Instance, + IN SFDP_PARAMETER_HEADER *SfdpParameterHeader, + IN UINT8 ParameterIdMsb, + IN UINT8 ParameterIdLsb + ) +{ + EFI_STATUS Status; + UINT32 Index; + SFDP_PARAMETER_HEADER LocalSfdpParameterHeader; + UINT32 TransactionBufferLength; + + DEBUG ((DEBUG_VERBOSE, "%a: Entry\n", __func__)); + DEBUG ((DEBUG_VERBOSE, " Looking for Parameter Header %02x:%02x\n", Par= ameterIdMsb, ParameterIdLsb)); + + // + // Parse Parameter Headers Starting at size eof SFDP_HEADER. + // SfdpHeader.NumParameterHeaders is zero based, 0 means 1 parameter hea= der. + // + ZeroMem (SfdpParameterHeader, sizeof (SFDP_PARAMETER_HEADER)); + for (Index =3D 0; Index < Instance->SfdpHeader.NumParameterHeaders + 1; = Index++) { + // Check not WIP + Status =3D WaitNotWip (Instance, FixedPcdGet32 (PcdSpiNorFlashOperatio= nDelayMicroseconds), FixedPcdGet32 (PcdSpiNorFlashFixedTimeoutRetryCount)); + if (!EFI_ERROR (Status)) { + TransactionBufferLength =3D FillWriteBuffer ( + Instance, + SPI_FLASH_RDSFDP, + SPI_FLASH_RDSFDP_DUMMY, + SPI_FLASH_RDSFDP_ADDR_BYTES, + TRUE, + sizeof (SFDP_HEADER) + Index * 8, // Par= ameter Header Index + 0, + NULL + ); + Status =3D Instance->SpiIo->Transaction ( + Instance->SpiIo, + SPI_TRANSACTION_WRITE_THEN_READ, + FALSE, + 0, + 1, + 8, + TransactionBufferLength, + Instance->SpiTransactionWriteBuffer, + sizeof (LocalSfdpParameterHeader), + (UINT8 *)&LocalSfdpParameterHeader + ); + ASSERT_EFI_ERROR (Status); + if (!EFI_ERROR (Status)) { + // Break if SfdParamHeader is Type 0, Basic SPI Protocol Parameter= s + DEBUG (( + DEBUG_VERBOSE, + " #%d Parameter Header: %02x:%02x, revision: %d.%d\n", + Index, + LocalSfdpParameterHeader.IdMsb, + LocalSfdpParameterHeader.IdLsb, + LocalSfdpParameterHeader.MajorRev, + LocalSfdpParameterHeader.MinorRev >=3D SfdpParameterHeader->Mino= rRev + )); + if ((LocalSfdpParameterHeader.IdLsb =3D=3D ParameterIdLsb) && + (LocalSfdpParameterHeader.IdMsb =3D=3D ParameterIdMsb) && + (LocalSfdpParameterHeader.MajorRev =3D=3D (UINT32)SFDP_SUPPORT= ED_MAJOR_REVISION) && + (LocalSfdpParameterHeader.MinorRev >=3D SfdpParameterHeader->M= inorRev)) + { + CopyMem ( + (VOID **)SfdpParameterHeader, + (VOID **)&LocalSfdpParameterHeader, + sizeof (SFDP_PARAMETER_HEADER) + ); + } + } else { + break; + } + } else { + break; + } + } + + if (Status !=3D EFI_DEVICE_ERROR) { + if ((SfdpParameterHeader->IdLsb !=3D ParameterIdLsb) || + (SfdpParameterHeader->IdMsb !=3D ParameterIdMsb)) + { + DEBUG ((DEBUG_ERROR, " Parameter Header: %02x:%02x is not found.\n"= , ParameterIdMsb, ParameterIdLsb)); + Status =3D EFI_NOT_FOUND; + } + } + + return Status; +} + +/** + Read from SFDP table pointer + + This routine sends SPI_FLASH_RDSFDP command and reads parameter from the + given TablePointer. + + @param[in] Instance Spi Nor Flash Instance data with pointer = to + EFI_SPI_NOR_FLASH_PROTOCOL and EFI_SPI_IO= _PROTOCOL + @param[in] TablePointer Pointer to read data from SFDP. + @param[in] DestBuffer Destination buffer. + @param[in] LengthInBytes Length to read. + + @retval EFI_SUCCESS The SPI part size is filled. + @retval EFI_DEVICE_ERROR Invalid data received from SPI flash part= . + @retval Other errors + +**/ +EFI_STATUS +EFIAPI +SpiReadSfdpPtp ( + IN SPI_NOR_FLASH_INSTANCE *Instance, + IN UINT32 TablePointer, + IN VOID *DestBuffer, + IN UINT32 LengthInBytes + ) +{ + EFI_STATUS Status; + UINT32 Length; + UINT8 *CurrentBuffer; + UINT32 ByteCounter; + UINT32 CurrentAddress; + UINT32 MaximumTransferBytes; + UINT32 TransactionBufferLength; + + Length =3D 0; + MaximumTransferBytes =3D Instance->SpiIo->MaximumTransferBytes; + CurrentBuffer =3D (UINT8 *)DestBuffer; + for (ByteCounter =3D 0; ByteCounter < LengthInBytes; ByteCounter +=3D Le= ngth) { + CurrentAddress =3D TablePointer + ByteCounter; + Length =3D LengthInBytes - ByteCounter; + + // Length must be MaximumTransferBytes or less + if (Length > MaximumTransferBytes) { + Length =3D MaximumTransferBytes; + } + + // Check not WIP + Status =3D WaitNotWip (Instance, FixedPcdGet32 (PcdSpiNorFlashOperatio= nDelayMicroseconds), FixedPcdGet32 (PcdSpiNorFlashFixedTimeoutRetryCount)); + + // Read Data + if (!EFI_ERROR (Status)) { + TransactionBufferLength =3D FillWriteBuffer ( + Instance, + SPI_FLASH_RDSFDP, + SPI_FLASH_RDSFDP_DUMMY, + SPI_FLASH_RDSFDP_ADDR_BYTES, + TRUE, + CurrentAddress, + 0, + NULL + ); + Status =3D Instance->SpiIo->Transaction ( + Instance->SpiIo, + SPI_TRANSACTION_WRITE_THEN_READ, + FALSE, + 0, + 1, + 8, + TransactionBufferLength, + Instance->SpiTransactionWriteBuffer, + Length, + CurrentBuffer + ); + if (EFI_ERROR (Status)) { + DEBUG ((DEBUG_ERROR, "%a: Fails to read SFDP parameter.\n", __func= __)); + ASSERT_EFI_ERROR (Status); + } + + CurrentBuffer +=3D Length; + } else { + break; + } + } + + return Status; +} + +/** + Read SFDP Sector Map Parameter into buffer + + This routine reads the JEDEC SPI Flash Discoverable Parameters from the = SPI + chip. + + @param[in] Instance Spi Nor Flash Instance data with pointer = to + EFI_SPI_NOR_FLASH_PROTOCOL and EFI_SPI_IO= _PROTOCOL + + @retval EFI_SUCCESS The SPI part size is filled. + @retval EFI_DEVICE_ERROR Invalid data received from SPI flash part= . + +**/ +EFI_STATUS +ReadSfdpSectorMapParameterTable ( + IN SPI_NOR_FLASH_INSTANCE *Instance + ) +{ + EFI_STATUS Status; + SFDP_PARAMETER_HEADER SfdpParamHeader; + + Status =3D ReadSfdpParameterHeader ( + Instance, + &SfdpParamHeader, + SFDP_SECTOR_MAP_PARAMETER_ID_MSB, + SFDP_SECTOR_MAP_PARAMETER_ID_LSB + ); + if (!EFI_ERROR (Status)) { + // Read Sector Map Parameters. Already know it is MajorRev =3D SFDP_S= UPPORTED_MAJOR_REVISION + Instance->SfdpSectorMapByteCount =3D SfdpParamHeader.Length * sizeof (= UINT32); + Instance->SfdpFlashSectorMap =3D AllocateZeroPool (Instance->SfdpS= ectorMapByteCount); + if (Instance->SfdpFlashSectorMap !=3D NULL) { + // Read from SFDP Parameter Table Pointer (PTP). + Status =3D SpiReadSfdpPtp ( + Instance, + SfdpParamHeader.TablePointer, + (VOID *)Instance->SfdpFlashSectorMap, + Instance->SfdpSectorMapByteCount + ); + if (!EFI_ERROR (Status)) { + Status =3D BuildSectorMapCommandAndMap (Instance); + if (EFI_ERROR (Status)) { + DEBUG ((DEBUG_ERROR, "%a: Fails to build sector map command and = descriptor.\n", __func__)); + ASSERT (FALSE); + Status =3D GetCurrentSectorMapConfiguration (Instance); + if (EFI_ERROR (Status)) { + DEBUG ((DEBUG_ERROR, "%a: Fails to get current sector map conf= iguration.\n", __func__)); + ASSERT (FALSE); + } + } + } else { + FreePool (Instance->SfdpFlashSectorMap); + Instance->SfdpFlashSectorMap =3D NULL; + DEBUG ((DEBUG_ERROR, "%a: Fails to read SFDP Sector Map Parameter.= \n", __func__)); + ASSERT (FALSE); + } + } else { + if (EFI_ERROR (Status)) { + DEBUG ((DEBUG_ERROR, "%a: Fails to allocate memory for reading SFD= P Sector Map Parameter.\n", __func__)); + ASSERT (FALSE); + } + } + } + + return Status; +} + +/** + Read SFDP Basic Parameters into buffer + + This routine reads the JEDEC SPI Flash Discoverable Parameters from the = SPI + chip. + + @param[in] Instance Spi Nor Flash Instance data with pointer to + EFI_SPI_NOR_FLASH_PROTOCOL and EFI_SPI_IO_PROTOCOL + + @retval EFI_SUCCESS The SPI part size is filled. + @retval EFI_DEVICE_ERROR Invalid data received from SPI flash part= . + @retval EFI_NOT_FOUND Parameter header is not found. + +**/ +EFI_STATUS +ReadSfdpBasicParameterTable ( + IN SPI_NOR_FLASH_INSTANCE *Instance + ) +{ + EFI_STATUS Status; + SFDP_PARAMETER_HEADER SfdpBasicFlashParamHeader; + + Status =3D ReadSfdpParameterHeader ( + Instance, + &SfdpBasicFlashParamHeader, + SFDP_BASIC_PARAMETER_ID_MSB, + SFDP_BASIC_PARAMETER_ID_LSB + ); + if (!EFI_ERROR (Status)) { + // Read Basic Flash Parameters. Already know it is MajorRev =3D SFDP_= SUPPORTED_MAJOR_REVISION + Instance->SfdpBasicFlashByteCount =3D SfdpBasicFlashParamHeader.Length= * sizeof (UINT32); + Instance->SfdpBasicFlash =3D AllocateZeroPool (Instance->Sfdp= BasicFlashByteCount); + if (Instance->SfdpBasicFlash !=3D NULL) { + // Read from SFDP Parameter Table Pointer (PTP). + Status =3D SpiReadSfdpPtp ( + Instance, + SfdpBasicFlashParamHeader.TablePointer, + (VOID *)Instance->SfdpBasicFlash, + Instance->SfdpBasicFlashByteCount + ); + if (!EFI_ERROR (Status)) { + GetWriteEnableCommand (Instance); + // + // Build the Fast Read capability table according to + // the Basic Flash Parameter Table. + // + BuildUpFastReadTable (Instance); + BuildUpEraseTypeTable (Instance); // Build up erase type and size. + + // Set current address bytes to 3-Bytes. + Instance->CurrentAddressBytes =3D 3; + } else { + FreePool (Instance->SfdpBasicFlash); + Instance->SfdpBasicFlash =3D NULL; + DEBUG ((DEBUG_ERROR, "%a: Fails to read SFDP Basic Parameter.\n", = __func__)); + ASSERT (FALSE); + } + } else { + if (EFI_ERROR (Status)) { + DEBUG ((DEBUG_ERROR, "%a: Fails to allocate memory for reading SFD= P Basic Parameter.\n", __func__)); + ASSERT (FALSE); + } + } + } + + return Status; +} + +/** + Initial SPI_NOR_FLASH_INSTANCE structure. + + @param[in] Instance Pointer to SPI_NOR_FLASH_INSTANCE. + EFI_SPI_NOR_FLASH_PROTOCOL and EFI_= SPI_IO_PROTOCOL + + @retval EFI_SUCCESS SPI_NOR_FLASH_INSTANCE is initializ= ed according to + SPI NOR Flash SFDP specification. + @retval EFI_INVALID_PARAMETER Instance =3D NULL or + Instance->SpiIo =3D=3D NULL or + Instance->SpiIo->SpiPeripheral =3D= =3D NULL or + Instance->SpiIo->SpiPeripheral->Spi= Bus =3D=3D NULL or + Instance->SpiIo->SpiPeripheral->Spi= Bus->ControllerPath. + @retval Otherwise Failed to initial SPI_NOR_FLASH_INS= TANCE structure. + +**/ +EFI_STATUS +InitialSpiNorFlashSfdpInstance ( + IN SPI_NOR_FLASH_INSTANCE *Instance + ) +{ + EFI_STATUS Status; + EFI_SPI_NOR_FLASH_PROTOCOL *Protocol; + + if (Instance =3D=3D NULL) { + DEBUG ((DEBUG_ERROR, "%a: Instance is NULL.\n", __func__)); + return EFI_INVALID_PARAMETER; + } + + if ((Instance->SpiIo =3D=3D NULL) || + (Instance->SpiIo->SpiPeripheral =3D=3D NULL) || + (Instance->SpiIo->SpiPeripheral->SpiBus =3D=3D NULL) + ) + { + DEBUG ((DEBUG_ERROR, "%a: One of SpiIo, SpiPeripheral and SpiBus is NU= LL.\n", __func__)); + return EFI_INVALID_PARAMETER; + } + + Instance->Signature =3D SPI_NOR_FLASH_SIGNATURE; + + // Allocate write buffer for SPI IO transactions with extra room for Opc= ode + // and Address with 10 bytes extra room. + Instance->SpiTransactionWriteBuffer =3D + AllocatePool (Instance->SpiIo->MaximumTransferBytes + 10); + + Protocol =3D &Instance->Protocol; + Protocol->SpiPeripheral =3D Instance->SpiIo->SpiPeripheral; + Protocol->GetFlashid =3D GetFlashId; + Protocol->ReadData =3D ReadData; // Fast Read transfer + Protocol->LfReadData =3D LfReadData; // Normal Read transfer + Protocol->ReadStatus =3D ReadStatus; + Protocol->WriteStatus =3D WriteStatus; + Protocol->WriteData =3D WriteData; + Protocol->Erase =3D Erase; + Status =3D Protocol->GetFlashid (Protocol, (UINT8 *)&Pr= otocol->Deviceid); + ASSERT_EFI_ERROR (Status); + DEBUG (( + DEBUG_VERBOSE, + "%a: Flash ID: Manufacturer=3D0x%02X, Device=3D0x%02X%02X\n", + __func__, + Protocol->Deviceid[0], + Protocol->Deviceid[1], + Protocol->Deviceid[2] + ) + ); + + Status =3D ReadSfdp (Instance); + if (EFI_ERROR (Status)) { + DEBUG ((DEBUG_ERROR, "%a: Failed to Read SFDP\n", __func__)); + ASSERT (FALSE); + } + + // Get flash deivce size from SFDP. + Protocol->FlashSize =3D SfdpGetFlashSize (Instance); + DEBUG ((DEBUG_VERBOSE, "%a: Flash Size=3D0x%X\n", __func__, Protocol->Fl= ashSize)); + if (Protocol->FlashSize =3D=3D 0) { + ASSERT_EFI_ERROR (Status); + } + + // Set flash erase block size. + Status =3D SetSectorEraseBlockSize (Instance); + if (EFI_ERROR (Status)) { + DEBUG ((DEBUG_ERROR, "%a: Fails to get the smallest erase block size.\= n", __func__)); + ASSERT (FALSE); + } + + return Status; +} diff --git a/MdeModulePkg/Bus/Spi/SpiNorFlashJedecSfdp/SpiNorFlashJedecSfdp= Dxe.c b/MdeModulePkg/Bus/Spi/SpiNorFlashJedecSfdp/SpiNorFlashJedecSfdpDxe.c new file mode 100644 index 00000000000..d8b86ddd8a3 --- /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=3DJE= SD216 + + @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_FLAS= H_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 =3D AllocateZeroPool (sizeof (SPI_NOR_FLASH_INSTANCE)); + ASSERT (Instance !=3D NULL); + if (Instance =3D=3D NULL) { + return EFI_OUT_OF_RESOURCES; + } + + // Locate the SPI IO Protocol + Status =3D 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 =3D 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 =3D gBS->InstallProtocolInterface ( + &Instance->Handle, + &gEfiSpiNorFlashProtocolGuid, + EFI_NATIVE_INTERFACE, + &Instance->Protocol + ); + if (EFI_ERROR (Status)) { + DEBUG ((DEBUG_ERROR, "%a: Fail to Install gEfiSpiNorFlashProtocolG= uid 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 =3D sizeof (EFI_HANDLE); + Status =3D 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 =3D 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 Protoco= l installation.", __func__)); + return Status; + } + + Status =3D gBS->RegisterProtocolNotify ( + &gEdk2JedecSfdpSpiDxeDriverGuid, + Event, + &Registration + ); + if (EFI_ERROR (Status)) { + DEBUG ((DEBUG_ERROR, "%a: Fail to register event for the SPI I/O Proto= col installation.", __func__)); + } else { + DEBUG ((DEBUG_INFO, "%a: Notification for SPI I/O Protocol installatio= n 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 installe= d on + system yet. + @retval EFI_OUT_OF_RESOURCES Not enough resource for SPI NOR Flash JEDE= C 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 gEdk2JedecSfdpSpiD= xeDriverGuid 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 =3D 0; + InstanceBuffer =3D NULL; + Status =3D gBS->LocateHandle ( + ByProtocol, + &gEdk2JedecSfdpSpiDxeDriverGuid, + NULL, + &InstanceBufferSize, + InstanceBuffer + ); + if (Status =3D=3D 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=3D%r\n", __func__, Status)); + return EFI_SUCCESS; + } else if (Status =3D=3D EFI_BUFFER_TOO_SMALL) { + InstanceBuffer =3D (EFI_HANDLE *)AllocateZeroPool (InstanceBufferSize)= ; + ASSERT (InstanceBuffer !=3D NULL); + if (InstanceBuffer =3D=3D NULL) { + DEBUG ((DEBUG_ERROR, "Not enough resource for gEdk2JedecSfdpSpiDxeDr= iverGuid handles.\n")); + DEBUG ((DEBUG_INFO, "%a: EXIT - Status=3D%r\n", __func__, Status)); + return EFI_OUT_OF_RESOURCES; + } + } else if (EFI_ERROR (Status)) { + DEBUG ((DEBUG_ERROR, "Error to locate gEdk2JedecSfdpSpiDxeDriverGuid -= Status =3D %r.\n", Status)); + DEBUG ((DEBUG_INFO, "%a: EXIT - Status=3D%r\n", __func__, Status)); + return Status; + } + + Status =3D gBS->LocateHandle ( + ByProtocol, + &gEdk2JedecSfdpSpiDxeDriverGuid, + NULL, + &InstanceBufferSize, + InstanceBuffer + ); + if (EFI_ERROR (Status)) { + DEBUG ((DEBUG_ERROR, "Fail to locate all gEdk2JedecSfdpSpiDxeDriverGui= d handles.\n")); + DEBUG ((DEBUG_INFO, "%a: EXIT - Status=3D%r\n", __func__, Status)); + return Status; + } + + DEBUG ((DEBUG_INFO, "%d of gEdk2JedecSfdpSpiDxeDriverGuid are found.\n",= InstanceBufferSize / sizeof (EFI_HANDLE))); + for (InstanceIndex =3D 0; InstanceIndex < InstanceBufferSize / sizeof (E= FI_HANDLE); InstanceIndex++) { + Status =3D CreateSpiNorFlashSfdpInstance (*(InstanceBuffer + InstanceI= ndex)); + if (EFI_ERROR (Status)) { + DEBUG ((DEBUG_ERROR, "Fail to create SPI NOR Flash SFDP instance #%d= .\n", InstanceIndex)); + } + } + + DEBUG ((DEBUG_INFO, "%a: EXIT - Status=3D%r\n", __func__, Status)); + return Status; +} diff --git a/MdeModulePkg/Bus/Spi/SpiNorFlashJedecSfdp/SpiNorFlashJedecSfdp= Smm.c b/MdeModulePkg/Bus/Spi/SpiNorFlashJedecSfdp/SpiNorFlashJedecSfdpSmm.c new file mode 100644 index 00000000000..c9fe44704fd --- /dev/null +++ b/MdeModulePkg/Bus/Spi/SpiNorFlashJedecSfdp/SpiNorFlashJedecSfdpSmm.c @@ -0,0 +1,234 @@ +/** @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=3DJE= SD216 + + @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_FLAS= H_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 =3D AllocateZeroPool (sizeof (SPI_NOR_FLASH_INSTANCE)); + ASSERT (Instance !=3D NULL); + if (Instance =3D=3D NULL) { + return EFI_OUT_OF_RESOURCES; + } + + // Locate the SPI IO Protocol. + Status =3D 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 =3D 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 =3D gSmst->SmmInstallProtocolInterface ( + &Instance->Handle, + &gEfiSpiSmmNorFlashProtocolGuid, + EFI_NATIVE_INTERFACE, + &Instance->Protocol + ); + if (EFI_ERROR (Status)) { + DEBUG ((DEBUG_ERROR, "%a: Fail to Install gEfiSpiSmmNorFlashProtoc= olGuid 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 =3D 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 =3D gSmst->SmmRegisterProtocolNotify ( + &gEdk2JedecSfdpSpiSmmDriverGuid, + SpiIoProtocolInstalledCallback, + &Registration + ); + if (EFI_ERROR (Status)) { + DEBUG ((DEBUG_ERROR, "%a: Fail to register event for the SPI I/O Proto= col installation.", __func__)); + } else { + DEBUG ((DEBUG_INFO, "%a: Notification for SPI I/O Protocol installatio= n 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 installe= d on + system yet. + @retval EFI_OUT_OF_RESOURCES Not enough resource for SPI NOR Flash JEDE= C 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 gEdk2JedecSfdpSpiS= mmDriverGuid 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 =3D 0; + InstanceBuffer =3D NULL; + Status =3D gSmst->SmmLocateHandle ( + ByProtocol, + &gEdk2JedecSfdpSpiSmmDriverGuid, + NULL, + &InstanceBufferSize, + InstanceBuffer + ); + if (Status =3D=3D 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=3D%r\n", __func__, Status)); + return EFI_SUCCESS; + } else if (Status =3D=3D EFI_BUFFER_TOO_SMALL) { + InstanceBuffer =3D (EFI_HANDLE *)AllocateZeroPool (InstanceBufferSize)= ; + ASSERT (InstanceBuffer !=3D NULL); + if (InstanceBuffer =3D=3D NULL) { + DEBUG ((DEBUG_ERROR, "Not enough resource for gEdk2JedecSfdpSpiSmmDr= iverGuid handles.\n")); + DEBUG ((DEBUG_INFO, "%a: EXIT - Status=3D%r\n", __func__, Status)); + return EFI_OUT_OF_RESOURCES; + } + } else if (EFI_ERROR (Status)) { + DEBUG ((DEBUG_ERROR, "Error to locate gEdk2JedecSfdpSpiSmmDriverGuid -= Status =3D %r.\n", Status)); + DEBUG ((DEBUG_INFO, "%a: EXIT - Status=3D%r\n", __func__, Status)); + return Status; + } + + Status =3D gSmst->SmmLocateHandle ( + ByProtocol, + &gEdk2JedecSfdpSpiSmmDriverGuid, + NULL, + &InstanceBufferSize, + InstanceBuffer + ); + if (EFI_ERROR (Status)) { + DEBUG ((DEBUG_ERROR, "Fail to locate all gEdk2JedecSfdpSpiSmmDriverGui= d handles.\n")); + DEBUG ((DEBUG_INFO, "%a: EXIT - Status=3D%r\n", __func__, Status)); + return Status; + } + + DEBUG ((DEBUG_INFO, "%d of gEdk2JedecSfdpSpiSmmDriverGuid handles are fo= und.\n", InstanceBufferSize / sizeof (EFI_HANDLE))); + for (InstanceIndex =3D 0; InstanceIndex < InstanceBufferSize / sizeof (E= FI_HANDLE); InstanceIndex++) { + Status =3D CreateSpiNorFlashSfdpInstance (*(InstanceBuffer + InstanceI= ndex)); + if (EFI_ERROR (Status)) { + DEBUG ((DEBUG_ERROR, "Fail to create SPI NOR Flash SFDP instance #%d= .\n", InstanceIndex)); + } + } + + DEBUG ((DEBUG_INFO, "%a: EXIT - Status=3D%r\n", __func__, Status)); + return Status; +} diff --git a/MdeModulePkg/Bus/Spi/SpiNorFlashJedecSfdp/SpiNorFlashJedecSfdp= Dxe.uni b/MdeModulePkg/Bus/Spi/SpiNorFlashJedecSfdp/SpiNorFlashJedecSfdpDxe= .uni new file mode 100644 index 00000000000..130e958cdba --- /dev/null +++ b/MdeModulePkg/Bus/Spi/SpiNorFlashJedecSfdp/SpiNorFlashJedecSfdpDxe.uni @@ -0,0 +1,13 @@ +// /** @file +// SPI NOR Flash SFDP Localized Strings and Content. +// +// Copyright (C) 2024 Advanced Micro Devices, Inc. All rights reserved. +// +// SPDX-License-Identifier: BSD-2-Clause-Patent +// +// **/ + +#string STR_MODULE_ABSTRACT #language en-US "EDK2 SPI NOR FLAS= H SFDP DXE driver" + +#string STR_MODULE_DESCRIPTION #language en-US "This driver provi= des SPI NOR FLASH Serial Flash Discoverable Parameter (SFDP) compatible fla= sh device capability discovery." + diff --git a/MdeModulePkg/Bus/Spi/SpiNorFlashJedecSfdp/SpiNorFlashJedecSfdp= Extra.uni b/MdeModulePkg/Bus/Spi/SpiNorFlashJedecSfdp/SpiNorFlashJedecSfdpE= xtra.uni new file mode 100644 index 00000000000..4703cf8b230 --- /dev/null +++ b/MdeModulePkg/Bus/Spi/SpiNorFlashJedecSfdp/SpiNorFlashJedecSfdpExtra.u= ni @@ -0,0 +1,11 @@ +// /** @file +// SPI NOR Flash SFDP Localized Strings and Content. +// +// Copyright (C) 2024 Advanced Micro Devices, Inc. All rights reserved. +// +// SPDX-License-Identifier: BSD-2-Clause-Patent +// +// **/ + +#string STR_PROPERTIES_MODULE_NAME +#language en-US "SPI NOR Flash driver for JEDEC Serial Flash Discoverabl= e Parameters (SFDP) compliant SPI Flash Memory" diff --git a/MdeModulePkg/Bus/Spi/SpiNorFlashJedecSfdp/SpiNorFlashJedecSfdp= Smm.uni b/MdeModulePkg/Bus/Spi/SpiNorFlashJedecSfdp/SpiNorFlashJedecSfdpSmm= .uni new file mode 100644 index 00000000000..757da3ddbd6 --- /dev/null +++ b/MdeModulePkg/Bus/Spi/SpiNorFlashJedecSfdp/SpiNorFlashJedecSfdpSmm.uni @@ -0,0 +1,13 @@ +// /** @file +// SPI NOR Flash SFDP Localized Strings and Content. +// +// Copyright (C) 2024 Advanced Micro Devices, Inc. All rights reserved. +// +// SPDX-License-Identifier: BSD-2-Clause-Patent +// +// **/ + +#string STR_MODULE_ABSTRACT #language en-US "EDK2 SPI NOR FLAS= H SFDP SMM driver" + +#string STR_MODULE_DESCRIPTION #language en-US "This driver provi= des SPI NOR FLASH Serial Flash Discoverable Parameter (SFDP) compatible fla= sh device capability discovery." + --=20 2.37.1.windows.1 -=3D-=3D-=3D-=3D-=3D-=3D-=3D-=3D-=3D-=3D-=3D- Groups.io Links: You receive all messages sent to this group. View/Reply Online (#117411): https://edk2.groups.io/g/devel/message/117411 Mute This Topic: https://groups.io/mt/105325630/7686176 Group Owner: devel+owner@edk2.groups.io Unsubscribe: https://edk2.groups.io/g/devel/unsub [rebecca@openfw.io] -=3D-=3D-=3D-=3D-=3D-=3D-=3D-=3D-=3D-=3D-=3D-