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 6AF89AC0A93 for ; Tue, 9 Apr 2024 06:45:41 +0000 (UTC) DKIM-Signature: a=rsa-sha256; bh=4pF/yJsNC20kZauAN05Z5tG8Ijw5VFJLSScx6/0LX14=; c=relaxed/simple; d=groups.io; h=From:To:CC:Subject:Thread-Topic:Thread-Index:Date:Message-ID:References:In-Reply-To:Accept-Language:msip_labels: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-Language:Content-Type:Content-Transfer-Encoding; s=20240206; t=1712645140; v=1; b=qGhTh2WhX/NDLLF7feCOhpYdYDUZAFl0YgrPsHLTPb3xgBeU9YhGdpgEvoYhVVu9pdgNQj+g 6PTFFStBkeqEO+BvvBApRmtn60JibEA/b0ffLKzxpfKl0fQ4B2khbhhf+OwTrOiiSUSS7otaRrB X6ZCxs2gZjovvEszSthwMG+1qVMuRHcXBeCblgwX31+gk970wCAGCvvuv46tUlgL5tN1MznumE3 ZvX7U0QFHyCn4Oy1x0CXvzXBTRK0xEU8FjjrFp1QL4/3MRvPnQvpF5W7mugB1VK6O0V4E0xdsef JpKK2FrVoqJq89Dr9iqDRQpTwdISTLA9H/pcsweH2esuA== X-Received: by 127.0.0.2 with SMTP id JpzBYY7687511xFt4UdSzHHG; Mon, 08 Apr 2024 23:45:40 -0700 X-Received: from NAM02-DM3-obe.outbound.protection.outlook.com (NAM02-DM3-obe.outbound.protection.outlook.com [40.107.95.125]) by mx.groups.io with SMTP id smtpd.web11.130364.1712645138961086961 for ; Mon, 08 Apr 2024 23:45:39 -0700 X-Received: from LV8PR12MB9452.namprd12.prod.outlook.com (2603:10b6:408:200::8) by BL1PR12MB5898.namprd12.prod.outlook.com (2603:10b6:208:396::7) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.20.7409.46; Tue, 9 Apr 2024 06:45:32 +0000 X-Received: from LV8PR12MB9452.namprd12.prod.outlook.com ([fe80::e006:4173:de2c:aca0]) by LV8PR12MB9452.namprd12.prod.outlook.com ([fe80::e006:4173:de2c:aca0%5]) with mapi id 15.20.7409.042; Tue, 9 Apr 2024 06:45:31 +0000 From: "Chang, Abner via groups.io" To: "devel@edk2.groups.io" CC: Hao A Wu , Ray Ni , "Attar, AbdulLateef (Abdul Lateef)" , "Chesley, Brit" Subject: Re: [edk2-devel] [PATCH V5 4/6] MdeModulePkg/SpiNorFlashJedecSfdp: SPI NOR Flash JEDEC SFDP Thread-Topic: [edk2-devel] [PATCH V5 4/6] MdeModulePkg/SpiNorFlashJedecSfdp: SPI NOR Flash JEDEC SFDP Thread-Index: AQHahnIu9Kvc7uLJ0kmDBDbK3xhqxrFfgzVA Date: Tue, 9 Apr 2024 06:45:31 +0000 Message-ID: References: <20240404092455.1903-1-abner.chang@amd.com> <17C30980DC7A7234.4513@groups.io> In-Reply-To: <17C30980DC7A7234.4513@groups.io> Accept-Language: en-US, zh-CN X-MS-Has-Attach: X-MS-TNEF-Correlator: msip_labels: MSIP_Label_4342314e-0df4-4b58-84bf-38bed6170a0f_ActionId=8591a0c1-2265-4449-a4b1-e2339f24d556;MSIP_Label_4342314e-0df4-4b58-84bf-38bed6170a0f_ContentBits=0;MSIP_Label_4342314e-0df4-4b58-84bf-38bed6170a0f_Enabled=true;MSIP_Label_4342314e-0df4-4b58-84bf-38bed6170a0f_Method=Standard;MSIP_Label_4342314e-0df4-4b58-84bf-38bed6170a0f_Name=General;MSIP_Label_4342314e-0df4-4b58-84bf-38bed6170a0f_SetDate=2024-04-09T06:35:02Z;MSIP_Label_4342314e-0df4-4b58-84bf-38bed6170a0f_SiteId=3dd8961f-e488-4e60-8e11-a82d994e183d; x-ms-publictraffictype: Email x-ms-traffictypediagnostic: LV8PR12MB9452:EE_|BL1PR12MB5898:EE_ x-ms-exchange-senderadcheck: 1 x-ms-exchange-antispam-relay: 0 x-microsoft-antispam-message-info: 7a4s+aAnToPwkpVlzpI1/fpnWafgTjUxLu8MCq8n+7fqG9V0VtrC3GC50HUktU7IQY9n/IO3iLx6X/jlFLGX6AI6g0y4eOMpwuwtv56Sy7SBGWy0k8eb14rgwieDaYxquYDs0oeS4RZyeXzhMen4rN+UuWk1YaKNpYUQ4ak2/rT3ie/1SWgdo08gBuSVOlk68RaskT2E/Jb+Pcb82HltrJNAcxiXJ9F9aKudYqW2XNO6+9Cuo349c0nzjUB3x595QgFqeLHV34fvqBgcF09t7SZobB9aYPpl6Mxi+5YGkE66c4eQtamHq9B97aBSrCzsK0ePQ1kKbnrXOgubspvMmHsxKY21PLm405loDFOnUVwJDhUF576xu8UxCIgn+SM5JLdgdJUbhRl8m7e1Xztlh3vMoujaYGoBA7BexRzQDcBGjKF6oTK63h7SbODahVKYf7ejT3i7oeLQLNyeVVcxRiTqRZ202QWpDrCPyMfIkF3uuvxZhWGqPWhHNLLWMYlYWIezB1n9l1H5M+fvkzYPl4YP4O/0qHVrFFPcNLk4tHBSqcazcJ7H5DdKKHwn/Sm4pb+I5vZGTQq1jN6CiAHWIuhIhBFMKkIdQPhOUoSuX3U= x-ms-exchange-antispam-messagedata-chunkcount: 1 x-ms-exchange-antispam-messagedata-0: =?us-ascii?Q?6WRBqmqTZ+MLSedI17ZflyLRcU+enX3om8MzF7vDTA+wuk1Hlet5ugWXfrK2?= =?us-ascii?Q?Nk3q9UXm2VW48Va25UfQocayRNyKwChL8wRIQwQpFD7usUXNiZvclHddMKTX?= =?us-ascii?Q?z6I7UkODZbsI4SGgFTtFlXY5gb1rEwqQugvz1TWiT6Ahq2MC7OWBS6NP52tW?= =?us-ascii?Q?7hwnpH50TXhJAzD2Cq4QGKgxakSdQcwp+uaR60xVAx59HD/96PjuyAeitn7I?= =?us-ascii?Q?wEgdQQOiRVWIJ7bbahsSkWVGilnn393l1XJo2bg40UxE6a7JJWb19B/MHZJG?= =?us-ascii?Q?FJeLwgSJseNi/rKtdMscNRrxevvTwmO3IYTtlKiGmS8R6W/PV5FYtcZsU6xT?= =?us-ascii?Q?0OLgIK6ri61UIa0FAmgYCbt0cVeHrdtaFpcMMsk4UP1CWRVjqY1Vt9OeHNvR?= =?us-ascii?Q?Wh4sGGKNgAOZaW4xUK8p6RIIEeWIIXtwD65kcrmTa2gxeFdOUoaMs/RiPhgl?= =?us-ascii?Q?kAIINXan0+Ou0FZvpdaWgWfRVJ78NDa/xtAmJqyW4iGn/A++kJPSm3U/VqDh?= =?us-ascii?Q?2VmIL4N4SqpnL8NPOALaDU+Djd5kKyCW4+9gG8zXpMe0A17oBdax0o9UHMJT?= =?us-ascii?Q?NRn/LkTjb3x+gryyWY+oSFKIT2x2Tyhk5ttlHsVobwpFshjcWC9TYTJYHZTv?= =?us-ascii?Q?Cb9JdnakyEyhOzQDMovhA5prwbLQFdvF+isZuAEISIDATrx8KRup+rjKrXQ0?= =?us-ascii?Q?ZXMzHBDGeQvF+L9VOouFQnUCGFY9iIiRgtXFqBn3GNzpyMR+5FYNJB2mSmOE?= =?us-ascii?Q?Qc3CBUDuDhtV1EVJmkwb5bElK5jjvlDCK5fzUdNgVxVyolQtg5bBS2yJkbmR?= =?us-ascii?Q?gMxFUYe/XxRhy6fq8BkTtwRth+OgYVJ2ZmOMhd6Qj0zYArWqJgY2d4pRU3cb?= =?us-ascii?Q?2GDHw/igSjJxMidn8H5ROPL6RTrLBhnyN+juMk+nFtp0qw4Vfzfia6TJrV2o?= =?us-ascii?Q?fh2zaBm3QDo+Qriq2B6XToleJpibMVJkbBAHZwe/ZAOhw4NbosXXE473+akX?= =?us-ascii?Q?38zDuJ68HhqbOri45d+aZAWsmeVEVZb8WaV8BVNLMyMaqE7fFfIDdfTm4ogb?= =?us-ascii?Q?0/AzdAidh5Z9RdgluvPEv6t2Y9DKexWZOPZiO7dLDX7KJe1X4IxSqulqjM86?= =?us-ascii?Q?12j/tp62KCpxHjoHM0IC5ZerDyERnemCFJPAoDtYzTyCzagn7mQZOb4T6dxW?= =?us-ascii?Q?4Hk4Q3HZ1AXEj76exZ1G3lMzyjnwfMNbsh5TXV272WFyO863K/DBPwVkxkkf?= =?us-ascii?Q?H1ADXiE7zN6AGM4Qi9/ateWQromLh1c2u/TJrv38K5ATDnqVWVoCTozobKn5?= =?us-ascii?Q?279xMh9vQm0Ay1Dw4fl5qumjzFIefNaQ5Y4tJWVIq383cghHdFGw9sBxuHLp?= =?us-ascii?Q?tnQr15rTj3EA27aTn2If2n6QowbZxMlOxPhEVnVRE8ECJ3nI0lujg6jxSSpU?= =?us-ascii?Q?EnLq63wdmsXk75uJ9d/x8L64b1LI3qNTfL/yZLzxWSyGrag8J1vnc1xmFpmE?= =?us-ascii?Q?0L/8uQhR4nXXClVOMw+j3j5SLU/yvMdd2eIkZkg3ldpL3RF7azo8/rQqKNQL?= =?us-ascii?Q?lWUe5iJc26OeRWhAxoU=3D?= MIME-Version: 1.0 X-OriginatorOrg: amd.com X-MS-Exchange-CrossTenant-AuthAs: Internal X-MS-Exchange-CrossTenant-AuthSource: LV8PR12MB9452.namprd12.prod.outlook.com X-MS-Exchange-CrossTenant-Network-Message-Id: 488d6264-5fa3-4a93-b4e7-08dc5860a6d1 X-MS-Exchange-CrossTenant-originalarrivaltime: 09 Apr 2024 06:45:31.8268 (UTC) X-MS-Exchange-CrossTenant-fromentityheader: Hosted X-MS-Exchange-CrossTenant-id: 3dd8961f-e488-4e60-8e11-a82d994e183d X-MS-Exchange-CrossTenant-mailboxtype: HOSTED X-MS-Exchange-CrossTenant-userprincipalname: S2VXOJeY144nMWgl10JJDt5qb+dt25UvogL8SnvzTB/WLEwZXsQQ8RwsZsa96KtUWMe3123rIo5dWM+GW8C22g== X-MS-Exchange-Transport-CrossTenantHeadersStamped: BL1PR12MB5898 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: Mon, 08 Apr 2024 23:45:39 -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: ClR339juwFFGnPnrlKfDEv92x7686176AA= Content-Language: en-US Content-Type: text/plain; charset="us-ascii" Content-Transfer-Encoding: quoted-printable X-GND-Status: LEGIT Authentication-Results: spool.mail.gandi.net; dkim=pass header.d=groups.io header.s=20240206 header.b=qGhTh2Wh; 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 [AMD Official Use Only - General] Hi Ray and Hao, This patch proposes a Spi folder under MdeModulePkg/Bus, AMD will also upst= ream entire SPI BUS driver stack after this patch set got merged and mainta= in the related drivers. Are you agree with this update? Thank you Abner > -----Original Message----- > From: devel@edk2.groups.io On Behalf Of Chang, > Abner via groups.io > Sent: Thursday, April 4, 2024 5:25 PM > To: devel@edk2.groups.io > Cc: Hao A Wu ; Ray Ni ; Attar, > AbdulLateef (Abdul Lateef) ; Chesley, Brit > > Subject: [edk2-devel] [PATCH V5 4/6] MdeModulePkg/SpiNorFlashJedecSfdp: S= PI > NOR Flash JEDEC SFDP > > Caution: This message originated from an External Source. Use proper caut= ion > when opening attachments, clicking links, or responding. > > > 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/SpiNorFlashJedecSfdpDxe.inf > create mode 100644 > MdeModulePkg/Bus/Spi/SpiNorFlashJedecSfdp/SpiNorFlashJedecSfdpSmm.inf > create mode 100644 > MdeModulePkg/Bus/Spi/SpiNorFlashJedecSfdp/SpiNorFlash.h > create mode 100644 > MdeModulePkg/Bus/Spi/SpiNorFlashJedecSfdp/SpiNorFlashJedecSfdpInternal.h > create mode 100644 > MdeModulePkg/Bus/Spi/SpiNorFlashJedecSfdp/SpiNorFlash.c > create mode 100644 > MdeModulePkg/Bus/Spi/SpiNorFlashJedecSfdp/SpiNorFlashJedecSfdp.c > create mode 100644 > MdeModulePkg/Bus/Spi/SpiNorFlashJedecSfdp/SpiNorFlashJedecSfdpDxe.c > create mode 100644 > MdeModulePkg/Bus/Spi/SpiNorFlashJedecSfdp/SpiNorFlashJedecSfdpSmm.c > create mode 100644 > MdeModulePkg/Bus/Spi/SpiNorFlashJedecSfdp/SpiNorFlashJedecSfdpDxe.uni > create mode 100644 > MdeModulePkg/Bus/Spi/SpiNorFlashJedecSfdp/SpiNorFlashJedecSfdpExtra.uni > create mode 100644 > MdeModulePkg/Bus/Spi/SpiNorFlashJedecSfdp/SpiNorFlashJedecSfdpSmm.uni > > diff --git > a/MdeModulePkg/Bus/Spi/SpiNorFlashJedecSfdp/SpiNorFlashJedecSfdpDxe.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=3DJESD216 > +# > +# @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.PcdSpiNorFlashOperationDelayMicrosecond > s > + > +[Guids] > + gEdk2JedecSfdpSpiDxeDriverGuid > + > +[Depex] > + gEdk2JedecSfdpSpiDxeDriverGuid > + > +[UserExtensions.TianoCore."ExtraFiles"] > + SpiNorFlashJedecSfdpExtra.uni > diff --git > a/MdeModulePkg/Bus/Spi/SpiNorFlashJedecSfdp/SpiNorFlashJedecSfdpSmm.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=3DJESD216 > +# > +# @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.PcdSpiNorFlashOperationDelayMicrosecond > s > + > +[Guids] > + gEdk2JedecSfdpSpiSmmDriverGuid > + > +[Depex] > + gEdk2JedecSfdpSpiSmmDriverGuid > + > +[UserExtensions.TianoCore."ExtraFiles"] > + SpiNorFlashJedecSfdpExtra.uni > diff --git a/MdeModulePkg/Bus/Spi/SpiNorFlashJedecSfdp/SpiNorFlash.h > b/MdeModulePkg/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 de= vice > + > + @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 protoco= ls, 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= and > + 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= and > + 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= part > + filling the buffer provided. > + > + @param[in] This Pointer to an EFI_SPI_NOR_FLASH_PROTOCOL data > structure. > + @param[out] Buffer Pointer to a 3 byte buffer to receive the manufact= ure > 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 pa= rt. > + > +**/ > +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 da= ta > + 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 - Flash= Address > + > +**/ > +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 da= ta > + 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 - Flash= Address > + > +**/ > +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 da= ta > + structure. > + @param[in] LengthInBytes Number of status bytes to read. > + @param[out] FlashStatus Pointer to a buffer to receive the flash st= atus. > + > + @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 dat= a > + structure. > + @param[in] LengthInBytes Number of status bytes to write. > + @param[in] FlashStatus Pointer to a buffer containing the new statu= s. > + > + @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 d= ata to > + the SPI part. > + > + @param[in] This Pointer to an EFI_SPI_NOR_FLASH_PROTOCOL dat= a > + 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 - Flash= Address > + @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 th= e > + 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/SpiNorFlashJedecSfdpInternal. > h > b/MdeModulePkg/Bus/Spi/SpiNorFlashJedecSfdp/SpiNorFlashJedecSfdpInternal. > h > new file mode 100644 > index 00000000000..309d8dcea70 > --- /dev/null > +++ > b/MdeModulePkg/Bus/Spi/SpiNorFlashJedecSfdp/SpiNorFlashJedecSfdpInternal. > 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, > Protocol, SPI_NOR_FLASH_SIGNATURE) > + > +typedef struct { > + LIST_ENTRY NextFastReadCap; ///< Link list to next Fast read ca= pability > + 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 su= pports. > + UINT8 EraseInstruction; ///< Erase instruction > + UINT32 EraseSizeInByte; ///< The size of byte in 2^EraseSize= the erase > type command > + ///< can erase. > + UINT32 EraseTypicalTime; ///< Time the device typically takes= to 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; ///< L= ink list to next > detection command. > + UINT32 CommandAddress; ///< A= ddress to issue the > command. > + UINT8 CommandInstruction; ///< D= etection command > instruction. > + UINT8 LatencyInClock; ///< C= ommand latency in > clocks. > + SPDF_CONFIGURATION_COMMAND_ADDR_LENGTH > CommandAddressLength; ///< Adddress length of detection command. > + UINT8 ConfigurationBitMask; ///< T= he interest bit of > the byte data retunred > + ///< a= fter sending the detection > command. > +} SFDP_SECTOR_MAP_DETECTION_RECORD; > + > +typedef struct { > + LIST_ENTRY NextRegion; ///< Li= nk list to the next > region. > + UINT32 RegionAddress; ///< Re= gion starting address. > + UINT32 RegionTotalSize; ///< Re= gion total size in > bytes. > + UINT32 RegionSectors; ///< Se= ctors in this region. > + UINT32 SectorSize; ///< Se= ctor size in byte > (Minimum blcok erase size) > + UINT8 SupportedEraseTypeNum; ///< Nu= mber of erase > type supported. > + UINT8 SupportedEraseType[SFDP_ERASE_TYPES_NUMBER]; ///< Er= ase > types supported. > + UINT32 EraseTypeBySizeBitmap; ///< Th= e bitmap of > supoprted srase block sizes. > + ///< fr= om big to small. > +} SFDP_SECTOR_REGION_RECORD; > + > +typedef struct { > + LIST_ENTRY NextDescriptor; ///< Li= nk list to next flash > map descriptor. > + UINT8 ConfigurationId; ///< Th= e ID of this > configuration. > + UINT8 RegionCount; ///< Th= e regions of this sector > map configuration. > + LIST_ENTRY RegionList; ///< Th= e 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 heade= r. > + UINT32 FlashDeviceSize; ///< The total = size of this flash > device. > + UINT8 CurrentAddressBytes; ///< The curren= t 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 linke= d list of > supported erase types. > + BOOLEAN Uniform4KEraseSupported; ///< The flash= device > supoprts uniform 4K erase. > + BOOLEAN WriteEnableLatchRequired; ///< Wether Wr= ite > Enable Latch is supported. > + UINT8 WriteEnableLatchCommand; ///< Write Ena= ble Latch > command. > + // > + // Below is the linked list of flash device sector > + // map configuration detection command and map descriptors. > + // > + BOOLEAN ConfigurationCommandsNeeded; ///< Indica= tes > whether sector map > + ///< config= uration detection is > + ///< requir= ed. > + LIST_ENTRY ConfigurationCommandList; ///< The li= nked list of > configuration > + ///< detect= ion command sequence. > + LIST_ENTRY ConfigurationMapList; ///< The li= nked list of > configuration > + ///< map de= scriptors. > + SFDP_SECTOR_MAP_RECORD *CurrentSectorMap; ///< The > current activated flash device > + ///< sector= map. > +} SPI_NOR_FLASH_INSTANCE; > + > +/** > + This routine returns the desired Fast Read mode. > + > + @param[in] Instance Spi Nor Flash Instance d= ata with pointer > to > + EFI_SPI_NOR_FLASH_PROTOC= OL and > EFI_SPI_IO_PROTOCOL > + @param[in,out] FastReadInstruction Fast Read instruction, t= he input is > + the default value. > + @param[in,out] FastReadOperationClock Fast Read operation cloc= k, the > input is > + the default value. > + @param[in,out] FastReadDummyClocks Fast Read wait state (Du= mmy > clocks), the > + input is the default val= ue. > + @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 th= e 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 pa= rt. > + > +**/ > +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 th= e SPI > + chip. > + > + @param[in] Instance Spi Nor Flash Instance data with pointe= r 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 pa= rt. > + > +**/ > +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 erro= r. > + > +**/ > +UINT32 > +SfdpGetFlashSize ( > + IN SPI_NOR_FLASH_INSTANCE *Instance > + ); > + > +/** > + Read SFDP > + This routine reads the JEDEC SPI Flash Discoverable Parameters. We jus= t > + 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_PROT= OCOL > + > + @retval EFI_SUCCESS Header is filled in > + @retval EFI_DEVICE_ERROR Invalid data received from SPI flash pa= rt. > + > +**/ > +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_PROT= OCOL > + > + @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= pointer to > + EFI_SPI_NOR_FLASH_PROTOCOL and > EFI_SPI_IO_PROTOCOL > + @param[in] FlashRegion The region the flash address bel= ong. > + @param[in] FlashAddress The target flash address. > + @param[in] RemainingSize Remaining size to erase. > + @param[in, out] BlockSizeToErase Input - The block erase size fo= r this > continious blocks. > + Output - The determined block si= ze for erasing. > + @param[in, out] BlockCountToErase Input - The expected blocks to = erase. > + Output - The determined number o= f blocks to erase. > + @param[out] BlockEraseCommand The erase command used for this > continious blocks. > + @param[out] TypicalTime Pointer to receive the typical t= ime in > millisecond > + to erase this erase type size. > + @param[out] MaximumTimeout Pointer to receive the maximum > timeout 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 = pointer 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 regi= on. > + @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 initial= ized > according to > + SPI NOR Flash SFDP specification. > + @retval Otherwisw Failed to initial SPI_NOR_FLASH_I= NSTANCE > 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/MdeModulePkg/Bus/Spi/SpiNorFlashJedecSfdp/SpiNorFlash.c > new file mode 100644 > index 00000000000..3ac5420fbf6 > --- /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= device > + @param[in] AddressBytesSupported Bytes of address supported by SPI= flash > device > + @param[in] UseAddress Send the address for SPI flash co= mmand > + @param[in] Address SPI Offset Start Address > + @param[in] WriteBytes Number of bytes to write to SPI d= evice > + @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) && > (SfdpAddressBytes !=3D SPI_ADDR_3OR4BYTE)) { > + DEBUG ((DEBUG_ERROR, "%a: Unsupported Address Bytes: 0x%x, SFD= P > 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) && > (SfdpAddressBytes !=3D SPI_ADDR_3OR4BYTE)) { > + DEBUG ((DEBUG_ERROR, "%a: Unsupported Address Bytes: 0x%x, SFD= P > 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, SFD= P > 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 st= atus. > + > + @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, = 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 > + ) > +{ > + 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, &DeviceStat= us); > + 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 > (PcdSpiNorFlashOperationDelayMicroseconds)); > + AlreadyDelayedInMicroseconds +=3D FixedPcdGet32 > (PcdSpiNorFlashOperationDelayMicroseconds); > + } > + > + 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, = etc. > + @param[in] Timeout Timeout in microsecond > + @param[in] RetryCount The retry count > + > + @retval EFI_SUCCESS Device does not have a write in progress= and > + 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, &DeviceStat= us); > + 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 > SPI_FLASH_SR_WEL) { > + return Status; > + } > + > + MicroSecondDelay (FixedPcdGet32 > (PcdSpiNorFlashOperationDelayMicroseconds)); > + AlreadyDelayedInMicroseconds +=3D FixedPcdGet32 > (PcdSpiNorFlashOperationDelayMicroseconds); > + } > + > + 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, = etc. > + @param[in] Timeout Timeout in microsecond > + @param[in] RetryCount The retry count > + > + @retval EFI_SUCCESS Device does not have a write in progress= and > + 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, &DeviceStat= us); > + ASSERT_EFI_ERROR (Status); > + if (EFI_ERROR (Status) || > + ((DeviceStatus & (SPI_FLASH_SR_WIP | SPI_FLASH_SR_WEL)) =3D=3D > SPI_FLASH_SR_NOT_WIP)) > + { > + return Status; > + } > + > + MicroSecondDelay (FixedPcdGet32 > (PcdSpiNorFlashOperationDelayMicroseconds)); > + AlreadyDelayedInMicroseconds +=3D FixedPcdGet32 > (PcdSpiNorFlashOperationDelayMicroseconds); > + } > + > + 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= part > + filling the buffer provided. > + > + @param[in] This Pointer to an EFI_SPI_NOR_FLASH_PROTOCOL data > structure. > + @param[out] Buffer Pointer to a 3 byte buffer to receive the manufact= ure > 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 pa= rt. > + > +**/ > +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 > (PcdSpiNorFlashOperationDelayMicroseconds), 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 da= ta > + 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 - Flash= Address > + > +**/ > +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 > (PcdSpiNorFlashOperationDelayMicroseconds), 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 da= ta > + 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 - Flash= Address > + > +**/ > +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%08x\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 > (PcdSpiNorFlashOperationDelayMicroseconds), FixedPcdGet32 > (PcdSpiNorFlashFixedTimeoutRetryCount)); > + if (EFI_ERROR (Status)) { > + break; > + } > + > + TransactionBufferLength =3D FillWriteBuffer ( > + Instance, > + FastReadInstruction, > + FastReadWaitStateDummyClocks / 8, > + (UINT8)Instance->SfdpBasicFlash->Address= 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 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 da= ta > + structure. > + @param[in] LengthInBytes Number of status bytes to read. > + @param[out] FlashStatus Pointer to a buffer to receive the flash st= atus. > + > + @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 dat= a > + structure. > + @param[in] LengthInBytes Number of status bytes to write. > + @param[in] FlashStatus Pointer to a buffer containing the new statu= s. > + > + @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 > (PcdSpiNorFlashOperationDelayMicroseconds), 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 > (PcdSpiNorFlashOperationDelayMicroseconds), FixedPcdGet32 > (PcdSpiNorFlashFixedTimeoutRetryCount)); > + } > + > + // 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 d= ata to > + the SPI part. > + > + @param[in] This Pointer to an EFI_SPI_NOR_FLASH_PROTOCOL dat= a > + 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 - Flash= Address > + @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 > (PcdSpiNorFlashOperationDelayMicroseconds), 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 > (PcdSpiNorFlashOperationDelayMicroseconds), FixedPcdGet32 > (PcdSpiNorFlashFixedTimeoutRetryCount)); > + 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 > (PcdSpiNorFlashOperationDelayMicroseconds), FixedPcdGet32 > (PcdSpiNorFlashFixedTimeoutRetryCount)); > + if (EFI_ERROR (Status)) { > + break; > + } > + } else { > + Status =3D WaitNotWip (Instance, FixedPcdGet32 > (PcdSpiNorFlashOperationDelayMicroseconds), 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 = the > + 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 > indicated > + in EraseBlockBytes in EFI_SPI_NOR_FLASH_PROTO= COL. > + > + @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, &FlashRegi= on); > + if (EFI_ERROR (Status)) { > + DEBUG ((DEBUG_ERROR, " Failed to get the flash region of this flash > address.\n")); > + ASSERT (FALSE); > + return Status; > + } > + > + CurrentAddress =3D FlashAddress; > + BlockCountToErase =3D BlockCount; > + BlockSizeToErase =3D FlashRegion->SectorSize; // This is also the min= imum > block erase size. > + TotalEraseLength =3D BlockCountToErase * FlashRegion->SectorSize; > + if ((FlashAddress + TotalEraseLength) > (FlashRegion->RegionAddress + > FlashRegion->RegionTotalSize)) { > + DEBUG ((DEBUG_ERROR, " The blocks to erase exceeds the region > boundary.\n")); > + return EFI_INVALID_PARAMETER; > + } > + > + DEBUG ((DEBUG_VERBOSE, " Region starting address: 0x%08x.\n", > FlashRegion->RegionAddress)); > + DEBUG ((DEBUG_VERBOSE, " Region size : 0x%08x.\n", FlashRe= gion- > >RegionTotalSize)); > + DEBUG ((DEBUG_VERBOSE, " Region sector size : 0x%08x.\n", > FlashRegion->SectorSize)); > + 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")); > + > + // 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 > (PcdSpiNorFlashOperationDelayMicroseconds), 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 > (PcdSpiNorFlashOperationDelayMicroseconds), FixedPcdGet32 > (PcdSpiNorFlashFixedTimeoutRetryCount)); > + if (EFI_ERROR (Status)) { > + break; > + } > + } > + > + // Erase Block > + TransactionBufferLength =3D FillWriteBuffer ( > + Instance, > + Opcode, > + Dummy, > + (UINT8)Instance->SfdpBasicFlash->Address= Bytes, > + 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 * 100= 0, > 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..284567d1f4b > --- /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=3DJESD216 > + > + @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 poi= nter 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_RECORD)); > + 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- > >NextFastReadCap); > + DEBUG ((DEBUG_VERBOSE, "%a: Create and link table.\n", __func__)); > + DEBUG ((DEBUG_VERBOSE, " Instruction : 0x%x\n", > FastReadInstruction)); > + DEBUG ((DEBUG_VERBOSE, " Mode bits : 0x%x\n", > FastReadModeClk)); > + DEBUG ((DEBUG_VERBOSE, " Wait States (Dummy Clocks): 0x%x\n", > FastReadDummyClk)); > +} > + > +/** > + Calculate erase type typical time. > + > + @param[in] SfdpEraseTypicalTime Erase type typical time indicate= d in > + Basic Flash Parameter Table. > + EraseTypicalTime [0:4] - Count > + EraseTypicalTime [5:6] - Unit > + 00b: 1= ms > + 01b: 1= 6ms > + 10b: 1= 28ms > + 11b: 1= s > + @param[in] SfdpEraseTimeMultiplier Multiplier from erase typical ti= me. > + @param[out] EraseTypicalTime Pointer to receive Erase typical= time in > milliseconds. > + @param[out] EraseTimeout Pointer to receive Erase timeout= in > 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) >> > ERASE_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) * *EraseTypica= lTime; > + return; > +} > + > +/** > + Print out the erase type information. > + > + @param[in] SupportedEraseType Pointer to > SFDP_SUPPORTED_ERASE_TYPE_RECORD. > +**/ > +VOID > +DebugPrintEraseType ( > + IN SFDP_SUPPORTED_ERASE_TYPE_RECORD *SupportedEraseType > + ) > +{ > + DEBUG ((DEBUG_VERBOSE, " Erase Type %d\n", SupportedEraseType- > >EraseType)); > + DEBUG ((DEBUG_VERBOSE, " Erase Type instruction: 0x%x\n", > SupportedEraseType->EraseInstruction)); > + DEBUG ((DEBUG_VERBOSE, " Erase size: 0x%x bytes\n", > SupportedEraseType->EraseSizeInByte)); > + DEBUG ((DEBUG_VERBOSE, " Erase time: %d Milliseconds\n", > SupportedEraseType->EraseTypicalTime)); > + DEBUG ((DEBUG_VERBOSE, " Erase timeout: %d Milliseconds:\n", > SupportedEraseType->EraseTimeout)); > +} > + > +/** > + Insert supported erase type entry. > + > + @param[in] Instance SPI Nor Flash Instance data with poi= nter to > + EFI_SPI_NOR_FLASH_PROTOCOL and > + EFI_SPI_IO_PROTOCOL. > + @param[in] SupportedEraseType Pointer to > SFDP_SUPPORTED_ERASE_TYPE_RECORD. > +**/ > +VOID > +CreateEraseTypeEntry ( > + IN SPI_NOR_FLASH_INSTANCE *Instance, > + IN SFDP_SUPPORTED_ERASE_TYPE_RECORD *SupportedEraseType > + ) > +{ > + InitializeListHead (&SupportedEraseType->NextEraseType); > + InsertTailList (&Instance->SupportedEraseTypes, &SupportedEraseType- > >NextEraseType); > + > + 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->SfdpBasi= cFlash- > >Erase1Instr; > + SupportedEraseType->EraseSizeInByte =3D (UINT32)1 << Instance- > >SfdpBasicFlash->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->SfdpBasi= cFlash- > >Erase2Instr; > + SupportedEraseType->EraseSizeInByte =3D (UINT32)1 << Instance- > >SfdpBasicFlash->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->SfdpBasi= cFlash- > >Erase3Instr; > + SupportedEraseType->EraseSizeInByte =3D (UINT32)1 << Instance- > >SfdpBasicFlash->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->SfdpBasi= cFlash- > >Erase4Instr; > + SupportedEraseType->EraseSizeInByte =3D (UINT32)1 << Instance- > >SfdpBasicFlash->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 va= lue. > + > + @param[in] Instance SPI Nor Flash Instance data with = pointer 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 = type. > + - For SearchEraseTypeByCommand: > + SearchValue is the erase instru= ction. > + - For SearchEraseTypeBySize: > + SearchValue is the erase block= size. > + - For SearchEraseTypeBySmallestSi= ze: > + SearchValue is not used. > + - For SearchEraseTypeByBiggestSiz= e: > + SearchValue is not used. > + @param[in] SupportedTypeTargetNum Only search the specific erase ty= pes. > + @param[in] SupportedTypeTarget Pointer to SupportedTypeTargetNum= of > + supported erase types. > + @param[out] EraseTypeRecord Pointer to receive the erase type= record. > + > + @retval EFI_SUCCESS Pointer to erase type record is r= eturned. > + 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 > (&Instance->SupportedEraseTypes); > + while (TRUE) { > + if ((SupportedTypeTarget =3D=3D NULL) || IsTargetEraseType (EraseTyp= e- > >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- > >NextEraseType) || ExitSearching) { > + break; > + } > + > + EraseType =3D (SFDP_SUPPORTED_ERASE_TYPE_RECORD *)GetNextNode > (&Instance->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= pointer to > + EFI_SPI_NOR_FLASH_PROTOCOL and > EFI_SPI_IO_PROTOCOL > + @param[in] FlashRegion The region the flash address bel= ong. > + @param[in] FlashAddress The target flash address. > + @param[in] RemainingSize Remaining size to erase. > + @param[in, out] BlockSizeToErase Input - The block erase size fo= r this > continious blocks. > + Output - The determined block si= ze for erasing. > + @param[in, out] BlockCountToErase Input - The expected blocks to = erase. > + Output - The determined number o= f blocks to erase. > + @param[out] BlockEraseCommand The erase command used for this > continious blocks. > + @param[out] TypicalTime Pointer to receive the typical t= ime in > millisecond > + to erase this erase type size. > + @param[out] MaximumTimeout Pointer to receive the maximum > timeout 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, Eras= eSize, 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", > *BlockSizeToErase)); > + DEBUG ((DEBUG_VERBOSE, " - Erase block count : 0x%08x.\n", > *BlockCountToErase)); > + DEBUG ((DEBUG_VERBOSE, " - Erase block command: 0x%02x.\n", > *BlockEraseCommand)); > + DEBUG ((DEBUG_VERBOSE, " - Remaining size to erase: 0x%08x.\n", > RemainingSize)); > + DEBUG ((DEBUG_VERBOSE, " - Erase typical time: %d milliseconds.\n", > *TypicalTime)); > + DEBUG ((DEBUG_VERBOSE, " - Erase timeout: %d milliseconds.\n", > *MaximumTimeout)); > + return EFI_SUCCESS; > +} > + > +/** > + Get the erase block attribute for the target address. > + > + @param[in] Instance Spi Nor Flash Instance data with = pointer 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 regi= on. > + @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 > (&SectorMapRecord->RegionList); > + while (TRUE) { > + if ((FlashAddress >=3D RegionRecord->RegionAddress) && > + (FlashAddress < RegionRecord->RegionAddress + RegionRecord- > >RegionTotalSize)) > + { > + *FlashRegion =3D RegionRecord; > + return EFI_SUCCESS; > + } > + > + if (IsNodeAtEnd (&SectorMapRecord->RegionList, &RegionRecord- > >NextRegion)) { > + break; > + } > + > + RegionRecord =3D (SFDP_SECTOR_REGION_RECORD *)GetNextNode > (&SectorMapRecord->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= to > + EFI_SPI_NOR_FLASH_PROTOCOL and > + EFI_SPI_IO_PROTOCOL. > + @param[in] RegionRecord Pointer to SFDP_SECTOR_REGION_RECORD of > this > + regions. > + @retval EFI_SUCCESS Current sector map configuration is dete= rmined. > + EFI_DEVICE_ERROR Current sector map configuration is not = found. > + > +**/ > +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- > >EraseSizeInByte; > + 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 / > RegionRecord->SectorSize; > + return EFI_SUCCESS; > +} > + > +/** > + Create a single flash sector map. > + > + @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 > determined. > + EFI_DEVICE_ERROR Current sector map configuration is no= t 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_DETECTION_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- > >NextDescriptor); > + DEBUG ((DEBUG_VERBOSE, " Sector map configurations ID : 0x%x\n"= , > SectorMapRecord->ConfigurationId)); > + DEBUG ((DEBUG_VERBOSE, " Sector map configurations regions: %d\n", > SectorMapRecord->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_RECORD.\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->NextRegio= n); > + > + Instance->CurrentSectorMap =3D SectorMapRecord; > + > + DEBUG ((DEBUG_VERBOSE, " Region totoal size : 0x%x\n", > RegionRecord->RegionTotalSize)); > + DEBUG ((DEBUG_VERBOSE, " Region sector size : 0x%x\n", > RegionRecord->SectorSize)); > + DEBUG ((DEBUG_VERBOSE, " Region sectors : 0x%x\n", > RegionRecord->RegionSectors)); > + > + for (EraseIndex =3D 0; EraseIndex < RegionRecord->SupportedEraseTypeNu= m; > EraseIndex++) { > + DEBUG ((DEBUG_VERBOSE, " Region erase type supported: 0x%x\n", > RegionRecord->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_PROT= OCOL > + > + @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->EraseSizeInB= yte; > + DEBUG ((DEBUG_VERBOSE, " Erase block size =3D 0x%08x\n", > EraseTypeRecord->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 > determined. > + EFI_DEVICE_ERROR Current sector map configuration is no= t 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 devi= ce > 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 (&Instance->ConfigurationCommandList); > + while (TRUE) { > + // Check not WIP > + Status =3D WaitNotWip (Instance, FixedPcdGet32 > (PcdSpiNorFlashOperationDelayMicroseconds), FixedPcdGet32 > (PcdSpiNorFlashFixedTimeoutRetryCount)); > + > + // Read configuration byte. > + AddressLength =3D SPI_ADDR_3BYTE_ONLY; > + DummyBytes =3D 1; > + if (CommandEntry->CommandAddressLength =3D=3D > SpdfConfigurationCommandAddress4Byte) { > + AddressLength =3D SPI_ADDR_4BYTE_ONLY; > + DummyBytes =3D 0; > + } > + > + UseAddress =3D TRUE; > + if (CommandEntry->CommandAddress =3D=3D > SpdfConfigurationCommandAddressNone) { > + 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- > >NextCommand)) { > + 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 sec= tor > + // map configuration. > + // > + SectorMap =3D (SFDP_SECTOR_MAP_RECORD *)GetFirstNode (&Instance- > >ConfigurationMapList); > + while (TRUE) { > + if (SectorMap->ConfigurationId =3D=3D ConfigurationId) { > + Instance->CurrentSectorMap =3D SectorMap; > + break; > + } > + > + if (IsNodeAtEnd (&Instance->ConfigurationMapList, &SectorMap- > >NextDescriptor)) { > + break; > + } > + > + SectorMap =3D (SFDP_SECTOR_MAP_RECORD *)GetNextNode (&Instance- > >ConfigurationMapList, &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 = command > 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 > *)AllocateZeroPool (sizeof (SFDP_SECTOR_MAP_DETECTION_RECORD)); > + if (CommandEntry =3D=3D NULL) { > + DEBUG ((DEBUG_ERROR, "%a: No memory resource for > SFDP_SECTOR_MAP_DETECTION_RECORD.\n", __func__)); > + ASSERT (FALSE); > + return EFI_OUT_OF_RESOURCES; > + } > + > + InitializeListHead (&CommandEntry->NextCommand); > + CommandEntry->CommandAddress =3D SfdpDetectionCommand- > >CommandAddress; > + CommandEntry->CommandAddressLength =3D > (SPDF_CONFIGURATION_COMMAND_ADDR_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", > CommandEntry->CommandInstruction)); > + DEBUG ((DEBUG_VERBOSE, " Bit selection : 0x%x\n", > CommandEntry->ConfigurationBitMask)); > + DEBUG ((DEBUG_VERBOSE, " Command address : 0x%x\n", > CommandEntry->CommandAddress)); > + DEBUG ((DEBUG_VERBOSE, " Command address length: %d\n", > CommandEntry->CommandAddressLength)); > + DEBUG ((DEBUG_VERBOSE, " Command latency clocks: %d\n\n", > CommandEntry->LatencyInClock)); > + if (SfdpDetectionCommand->DescriptorEnd =3D=3D > SFDP_SECTOR_MAP_TABLE_ENTRY_LAST) { > + break; > + } > + > + SfdpDetectionCommand++; > + } > + > + SfdpConfigurationMap =3D (SFDP_SECTOR_CONFIGURATION_MAP > *)SfdpDetectionCommand++; > + } > + > + // > + // Go through the region table pointed in SfdpConfigurationMap. > + // > + if (SfdpConfigurationMap->DescriptorType !=3D > SFDP_SECTOR_MAP_TABLE_ENTRY_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_DETECTION_RECORD.\n", __func__)); > + ASSERT (FALSE); > + return EFI_OUT_OF_RESOURCES; > + } > + > + InitializeListHead (&SectorMapRecord->NextDescriptor); > + InitializeListHead (&SectorMapRecord->RegionList); > + SectorMapRecord->ConfigurationId =3D (UINT8)SfdpConfigurationMap- > >ConfigurationID; > + SectorMapRecord->RegionCount =3D (UINT8)SfdpConfigurationMap- > >RegionCount; > + InsertTailList (&Instance->ConfigurationMapList, &SectorMapRecord- > >NextDescriptor); > + 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; > RegionCount++) { > + 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_MAP_DETECTION_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- > >SupportedEraseTypeNum] =3D SFDP_ERASE_TYPE_1; > + RegionRecord->SupportedEraseTypeNum++; > + } > + > + if (SpdfSectorRegion->EraseType2 !=3D 0) { > + RegionRecord->SupportedEraseType[RegionRecord- > >SupportedEraseTypeNum] =3D SFDP_ERASE_TYPE_2; > + RegionRecord->SupportedEraseTypeNum++; > + } > + > + if (SpdfSectorRegion->EraseType3 !=3D 0) { > + RegionRecord->SupportedEraseType[RegionRecord- > >SupportedEraseTypeNum] =3D SFDP_ERASE_TYPE_3; > + RegionRecord->SupportedEraseTypeNum++; > + } > + > + if (SpdfSectorRegion->EraseType4 !=3D 0) { > + RegionRecord->SupportedEraseType[RegionRecord- > >SupportedEraseTypeNum] =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 > device.\n", __func__)); > + ASSERT (FALSE); > + return EFI_DEVICE_ERROR; > + } > + > + MinimumEraseSize =3D (UINT32)-1; > + for (EraseTypeCount =3D 0; EraseTypeCount < RegionRecord- > >SupportedEraseTypeNum++; EraseTypeCount++) { > + // > + // Walk through Instance->SupportedEraseTypes to find the matchi= ng > erase type and > + // Use the minimum erase size as the sector size; > + // > + SupportedEraseType =3D (SFDP_SUPPORTED_ERASE_TYPE_RECORD > *)GetFirstNode (&Instance->SupportedEraseTypes); > + while (TRUE) { > + if (RegionRecord->SupportedEraseType[EraseTypeCount] =3D=3D > SupportedEraseType->EraseType) { > + // Set erase size bitmap. > + RegionRecord->EraseTypeBySizeBitmap |=3D SupportedEraseType- > >EraseSizeInByte; > + > + if (MinimumEraseSize > SupportedEraseType->EraseSizeInByte) = { > + MinimumEraseSize =3D SupportedEraseType->EraseSizeInByte; > + break; > + } > + } > + > + if (IsNodeAtEnd (&Instance->SupportedEraseTypes, > &SupportedEraseType->NextEraseType)) { > + break; > + } > + > + SupportedEraseType =3D (SFDP_SUPPORTED_ERASE_TYPE_RECORD > *)GetNextNode (&Instance->SupportedEraseTypes, &SupportedEraseType- > >NextEraseType); > + } > + } > + > + RegionRecord->SectorSize =3D MinimumEraseSize; > + RegionRecord->RegionSectors =3D RegionRecord->RegionTotalSize / > RegionRecord->SectorSize; > + RegionRecord->RegionAddress =3D RegionAddress; > + > + // Insert to link. > + InsertTailList (&SectorMapRecord->RegionList, &RegionRecord- > >NextRegion); > + DEBUG ((DEBUG_VERBOSE, " Region: %d\n", RegionCount)); > + DEBUG ((DEBUG_VERBOSE, " Region totoal size: 0x%x\n", > RegionRecord->RegionTotalSize)); > + DEBUG ((DEBUG_VERBOSE, " Region sector size: 0x%x\n", > RegionRecord->SectorSize)); > + DEBUG ((DEBUG_VERBOSE, " Region sectors : 0x%x\n", > RegionRecord->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_ENTRY_LAST) { > + break; > + } > + > + SfdpConfigurationMap =3D (SFDP_SECTOR_CONFIGURATION_MAP > *)SpdfSectorRegion; > + } > + > + 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__, Instance->WriteEnableLatchCommand)); > +} > + > +/** > + This routine returns the desired Fast Read mode. > + > + @param[in] Instance Spi Nor Flash Instance d= ata with pointer > to > + EFI_SPI_NOR_FLASH_PROTOC= OL and > EFI_SPI_IO_PROTOCOL > + @param[in,out] FastReadInstruction Fast Read instruction, t= he input is > + the default value. > + @param[in,out] FastReadModeBits The operational mode bit= s. > + @param[in,out] FastReadDummyClocks Fast Read wait state (Du= mmy > clocks), the > + input is the default val= ue. > + > + @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 *)GetFirstNo= de > (&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 Fas= t > Read > + // mode clock operation mode. Which is not cosidered in the implementa= tion > yet. > + // > + return EFI_SUCCESS; > +} > + > +/** > + Return the flash device size from SFDP Basic Flash Parameter Table DWO= RD > 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 erro= r. > + > +**/ > +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_4GBIT) < 32) { > + return 0; > + } > + > + return (UINT32)RShiftU64 (LShiftU64 (1, Instance->SfdpBasicFlash->Dens= ity & > ~SFDP_FLASH_MEMORY_DENSITY_4GBIT), 3); > +} > + > +/** > + Read SFDP Header > + > + This routine reads the JEDEC SPI Flash Discoverable Parameter header f= rom > 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_PROT= OCOL > + > + @retval EFI_SUCCESS Header is filled in > + @retval EFI_DEVICE_ERROR Invalid data received from SPI flash pa= rt. > + > +**/ > +EFI_STATUS > +EFIAPI > +ReadSfdpHeader ( > + IN SPI_NOR_FLASH_INSTANCE *Instance > + ) > +{ > + EFI_STATUS Status; > + UINT32 TransactionBufferLength; > + > + // Check not WIP > + Status =3D WaitNotWip (Instance, FixedPcdGet32 > (PcdSpiNorFlashOperationDelayMicroseconds), 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- > >SfdpHeader.NumParameterHeaders + 1)); > + } > + } > + > + return Status; > +} > + > +/** > + Read SFDP > + This routine reads the JEDEC SPI Flash Discoverable Parameters. We jus= t > + 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_PROT= OCOL > + > + @retval EFI_SUCCESS Header is filled in > + @retval EFI_DEVICE_ERROR Invalid data received from SPI flash pa= rt. > + > +**/ > +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- > >FlashDeviceSize)); > + 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 > Table\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_SUPPORTED) { > + DEBUG ((DEBUG_VERBOSE, "%a: The SPI NOR flash device supports > uniform 4K erase.\n", __func__)); > + > + // Check if 4K erase type supported? > + Status =3D GetEraseTypeRecord (Instance, SearchEraseTypeBySize, SI= ZE_4KB, > 0, NULL, &EraseTypeRecord); > + if (Status =3D=3D EFI_NOT_FOUND) { > + DEBUG ((DEBUG_ERROR, "However, no corresponding 4K size erase ty= pe > 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 suppo= rt > uniform 4K erase.\n", __func__)); > + } > + > + // > + // Build flash map > + // Instance->ConfigurationMapList is an empty list because no FDP Se= ctor > 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 f= rom > the > + SPI chip. Fails if Major Revision is not =3D > SFDP_SUPPORTED_MAJOR_REVISION. > + > + @param[in] Instance Spi Nor Flash Instance data with poin= ter 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 pa= rt. > + @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", > ParameterIdMsb, ParameterIdLsb)); > + > + // > + // Parse Parameter Headers Starting at size eof SFDP_HEADER. > + // SfdpHeader.NumParameterHeaders is zero based, 0 means 1 parameter > header. > + // > + ZeroMem (SfdpParameterHeader, sizeof (SFDP_PARAMETER_HEADER)); > + for (Index =3D 0; Index < Instance->SfdpHeader.NumParameterHeaders + 1= ; > Index++) { > + // Check not WIP > + Status =3D WaitNotWip (Instance, FixedPcdGet32 > (PcdSpiNorFlashOperationDelayMicroseconds), 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, // P= arameter 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 Paramet= ers > + DEBUG (( > + DEBUG_VERBOSE, > + " #%d Parameter Header: %02x:%02x, revision: %d.%d\n", > + Index, > + LocalSfdpParameterHeader.IdMsb, > + LocalSfdpParameterHeader.IdLsb, > + LocalSfdpParameterHeader.MajorRev, > + LocalSfdpParameterHeader.MinorRev >=3D SfdpParameterHeader- > >MinorRev > + )); > + if ((LocalSfdpParameterHeader.IdLsb =3D=3D ParameterIdLsb) && > + (LocalSfdpParameterHeader.IdMsb =3D=3D ParameterIdMsb) && > + (LocalSfdpParameterHeader.MajorRev =3D=3D > (UINT32)SFDP_SUPPORTED_MAJOR_REVISION) && > + (LocalSfdpParameterHeader.MinorRev >=3D SfdpParameterHeader- > >MinorRev)) > + { > + 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 pointe= r 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 pa= rt. > + @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 = Length) { > + 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 > (PcdSpiNorFlashOperationDelayMicroseconds), 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 th= e SPI > + chip. > + > + @param[in] Instance Spi Nor Flash Instance data with pointe= r 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 pa= rt. > + > +**/ > +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_SUPPORTED_MAJOR_REVISION > + Instance->SfdpSectorMapByteCount =3D SfdpParamHeader.Length * sizeof > (UINT32); > + Instance->SfdpFlashSectorMap =3D AllocateZeroPool (Instance- > >SfdpSectorMapByteCount); > + 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 an= d > descriptor.\n", __func__)); > + ASSERT (FALSE); > + Status =3D GetCurrentSectorMapConfiguration (Instance); > + if (EFI_ERROR (Status)) { > + DEBUG ((DEBUG_ERROR, "%a: Fails to get current sector map > configuration.\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 S= FDP > 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 th= e 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 pa= rt. > + @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.Leng= th * > sizeof (UINT32); > + Instance->SfdpBasicFlash =3D AllocateZeroPool (Instance- > >SfdpBasicFlashByteCount); > + 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 siz= e. > + > + // 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 S= FDP > 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 initial= ized > 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->S= piBus =3D=3D NULL or > + Instance->SpiIo->SpiPeripheral->S= piBus- > >ControllerPath. > + @retval Otherwise Failed to initial SPI_NOR_FLASH_I= NSTANCE > 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 > NULL.\n", __func__)); > + return EFI_INVALID_PARAMETER; > + } > + > + Instance->Signature =3D SPI_NOR_FLASH_SIGNATURE; > + > + // Allocate write buffer for SPI IO transactions with extra room for O= pcode > + // 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 *)&= Protocol- > >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- > >FlashSize)); > + 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/SpiNorFlashJedecSfdpDxe.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=3DJESD216 > + > + @par Glossary: > + - SFDP - Serial Flash Discoverable Parameters > + - PTP - Parameter Table Pointer > +**/ > + > +#include > +#include > +#include > +#include > +#include > +#include > +#include > +#include > +#include "SpiNorFlash.h" > +#include "SpiNorFlashJedecSfdpInternal.h" > + > +/** > + Function to create SPI_NOR_FLASH_INSTANCE for this SPI part. > + > + @param[in] SpiIoHandle The handle with SPI I/O protocol installed. > + > + @retval EFI_SUCCESS Succeed. > + @retval EFI_OUT_OF_RESOURCES Not enough resource to create > SPI_NOR_FLASH_INSTANCE. > + @retval otherwise Fail to create SPI NOR Flash SFDP Instan= ce > +**/ > +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 gEfiSpiNorFlashProtoco= lGuid > 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 invok= ed. > + @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 install= ed > + 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 Proto= col > 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 Pro= tocol > installation.", __func__)); > + } else { > + DEBUG ((DEBUG_INFO, "%a: Notification for SPI I/O Protocol installat= ion > was registered.", __func__)); > + } > + > + return Status; > +} > + > +/** > + Entry point of the Macronix SPI NOR Flash driver. > + > + @param ImageHandle Image handle of this driver. > + @param SystemTable Pointer to standard EFI system table. > + > + @retval EFI_SUCCESS Succeed. > + @retval EFI_NOT_FOUND No gEdk2JedecSfdpSpiSmmDriverGuid > installed on > + system yet. > + @retval EFI_OUT_OF_RESOURCES Not enough resource for SPI NOR Flash > JEDEC SFDP > + initialization. > + @retval Otherwise Other errors. > +**/ > +EFI_STATUS > +EFIAPI > +SpiNorFlashJedecSfdpDxeEntry ( > + IN EFI_HANDLE ImageHandle, > + IN EFI_SYSTEM_TABLE *SystemTable > + ) > +{ > + EFI_STATUS Status; > + EFI_HANDLE *InstanceBuffer; > + UINTN InstanceIndex; > + UINTN InstanceBufferSize; > + > + DEBUG ((DEBUG_INFO, "%a - ENTRY\n", __func__)); > + > + // > + // Register notification for the later SPI I/O protocol installation. > + // > + RegisterSpioProtocolNotification (); > + DEBUG ((DEBUG_INFO, "Check if there were already some > gEdk2JedecSfdpSpiDxeDriverGuid handles installed.\n")); > + > + // > + // Check if there were already some gEdk2JedecSfdpSpiDxeDriverGuid > + // handles installed. > + // > + // Locate the SPI I/O Protocol for the SPI flash part > + // that supports JEDEC SFDP specification. > + // > + InstanceBufferSize =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, wa= it > 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 (InstanceBufferSiz= e); > + ASSERT (InstanceBuffer !=3D NULL); > + if (InstanceBuffer =3D=3D NULL) { > + DEBUG ((DEBUG_ERROR, "Not enough resource for > gEdk2JedecSfdpSpiDxeDriverGuid 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 > gEdk2JedecSfdpSpiDxeDriverGuid 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 > (EFI_HANDLE); InstanceIndex++) { > + Status =3D CreateSpiNorFlashSfdpInstance (*(InstanceBuffer + Instanc= eIndex)); > + 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/SpiNorFlashJedecSfdpSmm.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=3DJESD216 > + > + @par Glossary: > + - SFDP - Serial Flash Discoverable Parameters > + - PTP - Parameter Table Pointer > +**/ > +#include > +#include > +#include > +#include > +#include > +#include > +#include > +#include > +#include "SpiNorFlash.h" > +#include "SpiNorFlashJedecSfdpInternal.h" > + > +/** > + Function to create SPI_NOR_FLASH_INSTANCE for this SPI part. > + > + @param[in] SpiIoHandle The handle with SPI I/O protocol installed. > + > + @retval EFI_SUCCESS Succeed. > + @retval EFI_OUT_OF_RESOURCES Not enough resource to create > SPI_NOR_FLASH_INSTANCE. > + @retval otherwise Fail to create SPI NOR Flash SFDP Instan= ce > +**/ > +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 > gEfiSpiSmmNorFlashProtocolGuid protocol.\n", __func__)); > + FreePool (Instance); > + } > + } > + } > + > + return Status; > +} > + > +/** > + Callback function executed when the EFI_SPI_IO_PROTOCOL > + protocol interface is installed. > + > + @param[in] Protocol Points to the protocol's unique identifier. > + @param[in] Interface Points to the interface instance. > + @param[in] Handle The handle on which the interface was installed. > + > + @return Status Code > + > +**/ > +EFI_STATUS > +EFIAPI > +SpiIoProtocolInstalledCallback ( > + IN CONST EFI_GUID *Protocol, > + IN VOID *Interface, > + IN EFI_HANDLE Handle > + ) > +{ > + EFI_STATUS Status; > + > + DEBUG ((DEBUG_INFO, "%a: Entry.\n", __func__)); > + Status =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 Pro= tocol > installation.", __func__)); > + } else { > + DEBUG ((DEBUG_INFO, "%a: Notification for SPI I/O Protocol installat= ion > was registered.", __func__)); > + } > + > + return Status; > +} > + > +/** > + Entry point of the SPI NOR Flash SFDP SMM driver. > + > + @param ImageHandle Image handle of this driver. > + @param SystemTable Pointer to standard EFI system table. > + > + @retval EFI_SUCCESS Succeed. > + @retval EFI_NOT_FOUND No gEdk2JedecSfdpSpiSmmDriverGuid > installed on > + system yet. > + @retval EFI_OUT_OF_RESOURCES Not enough resource for SPI NOR Flash > JEDEC SFDP > + initialization. > + @retval Otherwise Other errors. > +**/ > +EFI_STATUS > +EFIAPI > +SpiNorFlashJedecSfdpSmmEntry ( > + IN EFI_HANDLE ImageHandle, > + IN EFI_SYSTEM_TABLE *SystemTable > + ) > +{ > + EFI_STATUS Status; > + EFI_HANDLE *InstanceBuffer; > + UINTN InstanceIndex; > + UINTN InstanceBufferSize; > + > + DEBUG ((DEBUG_INFO, "%a - ENTRY.\n", __func__)); > + > + // > + // Register notification for the later SPI I/O protocol installation. > + // > + RegisterSpioProtocolNotification (); > + DEBUG ((DEBUG_INFO, "Check if there were already some > gEdk2JedecSfdpSpiSmmDriverGuid handles installed.\n")); > + // > + // Check if there were already some gEdk2JedecSfdpSpiSmmDriverGuid > + // handles installed. > + // > + // Locate the SPI I/O Protocol for the SPI flash part > + // that supports JEDEC SFDP specification. > + // > + InstanceBufferSize =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, wa= it > 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 (InstanceBufferSiz= e); > + ASSERT (InstanceBuffer !=3D NULL); > + if (InstanceBuffer =3D=3D NULL) { > + DEBUG ((DEBUG_ERROR, "Not enough resource for > gEdk2JedecSfdpSpiSmmDriverGuid 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 > gEdk2JedecSfdpSpiSmmDriverGuid handles.\n")); > + DEBUG ((DEBUG_INFO, "%a: EXIT - Status=3D%r\n", __func__, Status)); > + return Status; > + } > + > + DEBUG ((DEBUG_INFO, "%d of gEdk2JedecSfdpSpiSmmDriverGuid handles > are found.\n", InstanceBufferSize / sizeof (EFI_HANDLE))); > + for (InstanceIndex =3D 0; InstanceIndex < InstanceBufferSize / sizeof > (EFI_HANDLE); InstanceIndex++) { > + Status =3D CreateSpiNorFlashSfdpInstance (*(InstanceBuffer + Instanc= eIndex)); > + 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/SpiNorFlashJedecSfdpDxe.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 > FLASH SFDP DXE driver" > + > +#string STR_MODULE_DESCRIPTION #language en-US "This driver > provides SPI NOR FLASH Serial Flash Discoverable Parameter (SFDP) compati= ble > flash device capability discovery." > + > diff --git > a/MdeModulePkg/Bus/Spi/SpiNorFlashJedecSfdp/SpiNorFlashJedecSfdpExtra.uni > b/MdeModulePkg/Bus/Spi/SpiNorFlashJedecSfdp/SpiNorFlashJedecSfdpExtra.uni > new file mode 100644 > index 00000000000..4703cf8b230 > --- /dev/null > +++ > b/MdeModulePkg/Bus/Spi/SpiNorFlashJedecSfdp/SpiNorFlashJedecSfdpExtra.uni > @@ -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 Discovera= ble > Parameters (SFDP) compliant SPI Flash Memory" > diff --git > a/MdeModulePkg/Bus/Spi/SpiNorFlashJedecSfdp/SpiNorFlashJedecSfdpSmm.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 > FLASH SFDP SMM driver" > + > +#string STR_MODULE_DESCRIPTION #language en-US "This driver > provides SPI NOR FLASH Serial Flash Discoverable Parameter (SFDP) compati= ble > flash device capability discovery." > + > -- > 2.37.1.windows.1 > > > >=20 > -=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 (#117542): https://edk2.groups.io/g/devel/message/117542 Mute This Topic: https://groups.io/mt/105417381/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-