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 167D6740045 for ; Mon, 18 Dec 2023 15:12:52 +0000 (UTC) DKIM-Signature: a=rsa-sha256; bh=dphpHtmerIEBveF1Rdqb8QaXRxj5y/yE1l4ZTbN3u40=; c=relaxed/simple; d=groups.io; h=ARC-Seal:ARC-Message-Signature:ARC-Authentication-Results:Received-SPF:ARC-Seal:ARC-Message-Signature:ARC-Authentication-Results:Authentication-Results-Original:Message-ID:Date:User-Agent:Subject:To:Cc:References:From:In-Reply-To:MIME-Version:NoDisclaimer:Original-Authentication-Results:Precedence:List-Subscribe:List-Help:Sender:List-Id:Mailing-List:Delivered-To:Reply-To:List-Unsubscribe-Post:List-Unsubscribe:Content-Language:Content-Type:Content-Transfer-Encoding; s=20140610; t=1702912371; v=1; b=Ew6U9HUxCx6xDQlPeQUeuw6I1S/7+CDkTjD7tNs7MzsygNqj/MmK7SsZapD86UDINz7lMFYU q26H9YTlUA9pQfnsJKW8pwW717CFthn3btx1Z7xTPC96PtH6GNXLdYa4G0eKr5e4QKBi/ltmEWE Cw/MKDA6cOECAMW56cT/BfoU= X-Received: by 127.0.0.2 with SMTP id E9ZvYY7687511xxhhBmooWl9; Mon, 18 Dec 2023 07:12:51 -0800 X-Received: from EUR04-DB3-obe.outbound.protection.outlook.com (EUR04-DB3-obe.outbound.protection.outlook.com [40.107.6.50]) by mx.groups.io with SMTP id smtpd.web10.45725.1702912370143175528 for ; Mon, 18 Dec 2023 07:12:51 -0800 ARC-Seal: i=2; a=rsa-sha256; s=arcselector9901; d=microsoft.com; cv=pass; b=e57HCkVlRpUBdhGa5Y/PZPDitTmSmtI0kbe8gcIFNfWJJfADktd4tHCKzqLbscsg7RrMPGZ6Ng0VINRIYFriiqo12stAexHS8Ja/qLSZNp9k1xvS5CqDCqAAzqYT7asHjJZ7ZO9HYA/fIsh7STnx6kdgAxUF1tYhhLFEFQMGfHh1HxSifCZlkBPqJWygutjrjBDxgU5Uh6rnsqJyNYzebgDNTJrYSnyekXWABtxCPxOfVrKDATkCrLQzN84i1I7C685IqmhJGbFbUBGqzwx5PkkxGThI37bQZnbxORUIZobMALK3fms9qQT9Qs3Xq8t4l4W6Vk74dICs3zXR9a6brQ== ARC-Message-Signature: i=2; a=rsa-sha256; c=relaxed/relaxed; d=microsoft.com; s=arcselector9901; h=From:Date:Subject:Message-ID:Content-Type:MIME-Version:X-MS-Exchange-AntiSpam-MessageData-ChunkCount:X-MS-Exchange-AntiSpam-MessageData-0:X-MS-Exchange-AntiSpam-MessageData-1; bh=xm8xu2ZVgkJPlCilP2nJaFdLuMVxrnubgV43bVbGlcQ=; b=StdWgdayYCwi9Ab3UuWaIriIAaiYZ3btcJ1GcuBLqJi8/TN30Pd8MEH5t1JD1sI8nLvulVIOECYorcot7ulXlQLz3TJSPAq/HAzxa04rysBeL3dirSBmYHj7OPNl3ZAWn/p6kXamujg7jL5YfolSNc7qMHtDdB/I208tt8N3Rur5dDDe0iSdmkEUdZiIzjkFt4ugSh6bnn4MLaZLOvL7jiSlgz1fwJo+VJDcOUUL+pCYaywAj/zcpDM7NsFp+n5CZKXtJMsDkWM/Nt10QS29UVlz6fqzn85vwPn++fDkKuQVU98poaYjLIHThZ36JJe6omGC4dCqvYCwEXdsDeuvRw== ARC-Authentication-Results: i=2; mx.microsoft.com 1; spf=pass (sender ip is 63.35.35.123) smtp.rcpttodomain=edk2.groups.io smtp.mailfrom=arm.com; dmarc=pass (p=none sp=none pct=100) action=none header.from=arm.com; dkim=pass (signature was verified) header.d=armh.onmicrosoft.com; arc=pass (0 oda=1 ltdi=1 spf=[1,1,smtp.mailfrom=arm.com] dkim=[1,1,header.d=arm.com] dmarc=[1,1,header.from=arm.com]) X-Received: from DU2PR04CA0065.eurprd04.prod.outlook.com (2603:10a6:10:232::10) by PA4PR08MB5920.eurprd08.prod.outlook.com (2603:10a6:102:ea::5) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.20.7091.37; Mon, 18 Dec 2023 15:12:40 +0000 X-Received: from DB5PEPF00014B97.eurprd02.prod.outlook.com (2603:10a6:10:232:cafe::63) by DU2PR04CA0065.outlook.office365.com (2603:10a6:10:232::10) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.20.7091.37 via Frontend Transport; Mon, 18 Dec 2023 15:12:40 +0000 X-MS-Exchange-Authentication-Results: spf=pass (sender IP is 63.35.35.123) smtp.mailfrom=arm.com; dkim=pass (signature was verified) header.d=armh.onmicrosoft.com;dmarc=pass action=none header.from=arm.com; Received-SPF: Pass (protection.outlook.com: domain of arm.com designates 63.35.35.123 as permitted sender) receiver=protection.outlook.com; client-ip=63.35.35.123; helo=64aa7808-outbound-1.mta.getcheckrecipient.com; pr=C X-Received: from 64aa7808-outbound-1.mta.getcheckrecipient.com (63.35.35.123) by DB5PEPF00014B97.mail.protection.outlook.com (10.167.8.235) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.20.7113.14 via Frontend Transport; Mon, 18 Dec 2023 15:12:40 +0000 X-Received: ("Tessian outbound 20615a7e7970:v228"); Mon, 18 Dec 2023 15:12:40 +0000 X-CheckRecipientChecked: true X-CR-MTA-CID: 10399887d1319818 X-CR-MTA-TID: 64aa7808 X-Received: from 5bb68b1ba73e.1 by 64aa7808-outbound-1.mta.getcheckrecipient.com id EFBEA982-EEF4-4785-A223-0182B6098BC6.1; Mon, 18 Dec 2023 15:12:30 +0000 X-Received: from EUR03-DBA-obe.outbound.protection.outlook.com by 64aa7808-outbound-1.mta.getcheckrecipient.com with ESMTPS id 5bb68b1ba73e.1 (version=TLSv1.2 cipher=ECDHE-RSA-AES256-GCM-SHA384); Mon, 18 Dec 2023 15:12:30 +0000 ARC-Seal: i=1; a=rsa-sha256; s=arcselector9901; d=microsoft.com; cv=none; b=bHFJ2sMrw7J2qkmXrtVnWzx9CpWHTA9wD/0VbtViDZtIb3qx0e591Fyk7NRvqspQqTNBaUCQXeAZyhDuQNNhUNVntJikfOos4R6PUe0gHabamha6GmhQa3ubroychAJCBodqHrvwIB5qqt9ZYnNoV3j7ksIjJuEmoSlmCoFAJrKKzd/Golkm74XILZP9QBeyA4p+JR/irVw6I4J2/I01UJutZXf/1cdk33X7sQ7HfyRgT8AuIpaL8ShG+mkpReTkT27XJzs/lSe0s8qeL2YbVFGetLSiasSJsqYOwmOF6CclhSFjb7G72zQMOJ3Mja+3aTtSc0JY6Q18A7WQ+4k9fA== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=microsoft.com; s=arcselector9901; h=From:Date:Subject:Message-ID:Content-Type:MIME-Version:X-MS-Exchange-AntiSpam-MessageData-ChunkCount:X-MS-Exchange-AntiSpam-MessageData-0:X-MS-Exchange-AntiSpam-MessageData-1; bh=xm8xu2ZVgkJPlCilP2nJaFdLuMVxrnubgV43bVbGlcQ=; b=foqKs1rT0fF84p43KXRqyVPPMGOowMJUgsiN8K9w2MXayG8qHJsZZ7LhSQpZvLbMVG4JMpzi/Io98ASuCjDSyMb07BBzeNqulfwSa/hAVkwJzXBc3MeFDvE37lRsjaG2CSclCMGh9ZgFDjAJ+t0kHhMYnWdAZswHicZ0MNHPN3SY8fJkj/c05eg1DHs5FbHxVodlisKPDxrrbYtbDFgZHdPr/Bf+3Tt3rXx5haUCyRuREMfr54z5ditctcLrYVQmGA8iDypVjH0A++eTBY/7LeqVn5L9IXTi/Nocq85p1JweK6sePEEG/E2J4/FmpUDwNgL6Sw8wjaY+8jSt1ll6gg== ARC-Authentication-Results: i=1; mx.microsoft.com 1; spf=pass smtp.mailfrom=arm.com; dmarc=pass action=none header.from=arm.com; dkim=pass header.d=arm.com; arc=none Authentication-Results-Original: dkim=none (message not signed) header.d=none;dmarc=none action=none header.from=arm.com; X-Received: from AS8PR08MB6806.eurprd08.prod.outlook.com (2603:10a6:20b:39b::12) by AS8PR08MB8947.eurprd08.prod.outlook.com (2603:10a6:20b:5b3::22) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.20.7091.37; Mon, 18 Dec 2023 15:12:26 +0000 X-Received: from AS8PR08MB6806.eurprd08.prod.outlook.com ([fe80::f36e:3882:2fce:d775]) by AS8PR08MB6806.eurprd08.prod.outlook.com ([fe80::f36e:3882:2fce:d775%4]) with mapi id 15.20.7091.034; Mon, 18 Dec 2023 15:12:25 +0000 Message-ID: <3a92b3cc-0353-4523-9b60-d057c33ac7a9@arm.com> Date: Mon, 18 Dec 2023 15:12:25 +0000 User-Agent: Mozilla Thunderbird Subject: Re: [edk2-devel] [edk2-platforms][PATCH V1 3/5] Platform/ARM/N1Sdp: NOR flash Dxe Driver for N1Sdp To: sahil , devel@edk2.groups.io Cc: Ard Biesheuvel , Leif Lindholm , "nd@arm.com" References: <20231116114554.4055517-1-sahil@arm.com> <20231116114554.4055517-4-sahil@arm.com> From: "Sami Mujawar" In-Reply-To: <20231116114554.4055517-4-sahil@arm.com> X-ClientProxiedBy: LO4P123CA0066.GBRP123.PROD.OUTLOOK.COM (2603:10a6:600:153::17) To AS8PR08MB6806.eurprd08.prod.outlook.com (2603:10a6:20b:39b::12) MIME-Version: 1.0 X-MS-TrafficTypeDiagnostic: AS8PR08MB6806:EE_|AS8PR08MB8947:EE_|DB5PEPF00014B97:EE_|PA4PR08MB5920:EE_ X-MS-Office365-Filtering-Correlation-Id: 62e6610b-1f5c-4e44-d31a-08dbffdbc725 x-checkrecipientrouted: true NoDisclaimer: true X-MS-Exchange-SenderADCheck: 1 X-MS-Exchange-AntiSpam-Relay: 0 X-Microsoft-Antispam-Untrusted: BCL:0; X-Microsoft-Antispam-Message-Info-Original: dPdZhBD/+hyoy3PCrPYnDQvCQIy6mY7KuqXhXzOvhUuxLHDLOP22NyRF9Jl9y8jp032qONAmKyrnccur6w9tPdi+sH5JBuZioEyGhSIJ5wkuD7cfTpOznVi8hV/NrV4HWetNVUjm8tiH1LwlHpb6IE27cMzs95AdlaDvloo4hVwo445I3bK+WVEcAJoFZ6877ABbxS/fnxQj6l5dO1Fb1DQYoJEeK7amKSyAVmwsTmhCh78R6L3ISS/SB4oelYemNbBrPwuIwOt/Xv8zg0xEubrKnYAehTmtapIyDyweSwu/eZewvNrtr8FVJixTGl1zRCTubpqKRWhsA4iRDzCOR/mY8VRJt6TpfgZo7pnzaUvd07ZERLoN0pRYZ6D0TEZCOe7LofeOoSellGkjlNFCInLD6soZYI79IEWhC8o3nHl4tD5dtIq7fZwDdxzll2rsAjfcKooz4m0oF10JfCzAbfdRjoibr1UvIMTmeghmX8eJyZOgTgvuhWCNUy6mz6U3aQmNkLsugDY+z1SdmAmmFEQiB8SqGbz6CC9Z02wWuSAV61peQrOKhJF+xhpxvL2dChba1YQiF/8CHkz5Y6MrQjaKEWEDWMdM3MLVgsTdBykrHskfxWr+0td8qSLFx6Vioai7dJBfoU6Ef3LbkXEiVuc67mvz3dXsVvKnJi+mlOSaboscqHCknuv9dzJNmcr5M6zq3Q95gH8cCOFugdOFVA== X-Forefront-Antispam-Report-Untrusted: CIP:255.255.255.255;CTRY:;LANG:en;SCL:1;SRV:;IPV:NLI;SFV:NSPM;H:AS8PR08MB6806.eurprd08.prod.outlook.com;PTR:;CAT:NONE;SFS:(13230031)(136003)(39860400002)(376002)(396003)(366004)(346002)(230922051799003)(64100799003)(186009)(451199024)(1800799012)(31686004)(26005)(2616005)(2906002)(36756003)(31696002)(86362001)(38100700002)(83380400001)(44832011)(5660300002)(30864003)(6512007)(53546011)(6506007)(8936002)(8676002)(4326008)(66946007)(66556008)(6486002)(54906003)(316002)(66476007)(41300700001)(478600001)(19627235002)(32563001)(45980500001)(43740500002)(559001)(579004)(44824005);DIR:OUT;SFP:1101; X-MS-Exchange-Transport-CrossTenantHeadersStamped: AS8PR08MB8947 Original-Authentication-Results: dkim=none (message not signed) header.d=none;dmarc=none action=none header.from=arm.com; X-EOPAttributedMessage: 0 X-MS-Exchange-Transport-CrossTenantHeadersStripped: DB5PEPF00014B97.eurprd02.prod.outlook.com X-MS-PublicTrafficType: Email X-MS-Office365-Filtering-Correlation-Id-Prvs: e3c76525-c1c9-4b14-9dfc-08dbffdbbe41 X-Microsoft-Antispam-Message-Info: toJ9ZZS36+QIZtc3upEaWWz0Tez63IuVT5bo2aPcz0ONGUxnfWyq/jVzNP37nNimJN2X0iJq6oo1P6vViyhdIjVZ5fI49Cxgpbno6/iUFKYNm0qH1TqTvy7pg2CtbRpna1HKHvYlHFB9i0AZiA9pyGFVg8OmgvKNEDOIvswQHk44naNxSoNqRAp7LqyrVmdk3Un8ERYuyjojm7O2TqzEaQZ2e7igosIOqcXGFFYKbCao/MaEO38AvHLKiW7/DKLaiJnJFB5UcSfi/wMYPhdFWdz5lNssDUVsnKAim8nzhXgOFqeWhrCsFEsHXZl7xMaxnJVFuCwjpDeXznVUaUyeEtOt2pjAmMf0193lwGxYdJCbEi+3YEUCZD8X48+FbllNzTthV7xzGLB9DEFTUBtTG3ebPyPg4NoF1L39AKng8MeX2u9tGvcgnWZI5Inw8tgNIaE0g16L5Gi+KweZ92HUfeS0kEKw/q0v5FJ7fckXUpZ+uApm5mBgEukSCP1Q+PBF8vXBM+xNuFtoaojDIKST4kJTXeaRTX5w7SnNN7hmCWpKFvUivVeQtzdm99aUAlLoCBYU9rVRvwRHpMMAikru0LTAXsSJAuggZiA9cuj5wAfIdIpaGlyEsyWwXwwpYG+qVjOA4HbPRbP49Ohh/RRdHvlEi0n608nBy+oxxmIpFR9sFpssNvdzJCHbS5+e2POOp2MOEyjcyoq21/du1shVOcuWupb93N7svRJfWIz06R9ka+ZHZpv4R4UepJlLRLWDyfKx0Q66gosweI+n3C2wLVyMEz+lNz4OfvKsGOa+kcCaVukv/XTLPvbLUIqP3+aM X-OriginatorOrg: arm.com X-MS-Exchange-CrossTenant-OriginalArrivalTime: 18 Dec 2023 15:12:40.7122 (UTC) X-MS-Exchange-CrossTenant-Network-Message-Id: 62e6610b-1f5c-4e44-d31a-08dbffdbc725 X-MS-Exchange-CrossTenant-Id: f34e5979-57d9-4aaa-ad4d-b122a662184d X-MS-Exchange-CrossTenant-OriginalAttributedTenantConnectingIp: TenantId=f34e5979-57d9-4aaa-ad4d-b122a662184d;Ip=[63.35.35.123];Helo=[64aa7808-outbound-1.mta.getcheckrecipient.com] X-MS-Exchange-CrossTenant-AuthSource: DB5PEPF00014B97.eurprd02.prod.outlook.com X-MS-Exchange-CrossTenant-AuthAs: Anonymous X-MS-Exchange-CrossTenant-FromEntityHeader: HybridOnPrem X-MS-Exchange-Transport-CrossTenantHeadersStamped: PA4PR08MB5920 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 Reply-To: devel@edk2.groups.io,sami.mujawar@arm.com List-Unsubscribe-Post: List-Unsubscribe=One-Click List-Unsubscribe: X-Gm-Message-State: cfkaHH070nus5knTmcL9x8bxx7686176AA= Content-Language: en-GB Content-Type: text/plain; charset=UTF-8; format=flowed Content-Transfer-Encoding: quoted-printable X-GND-Status: LEGIT Authentication-Results: spool.mail.gandi.net; dkim=pass header.d=groups.io header.s=20140610 header.b=Ew6U9HUx; dmarc=fail reason="SPF not aligned (relaxed), DKIM not aligned (relaxed)" header.from=arm.com (policy=none); spf=pass (spool.mail.gandi.net: domain of bounce@groups.io designates 66.175.222.108 as permitted sender) smtp.mailfrom=bounce@groups.io; arc=reject ("signature check failed: fail, {[1] = sig:microsoft.com:reject}") Hi Sahil, Where can I find the documentation for Cadence QSPI? Can you add a link=20 to the relevant file headers, please? Also, this patch is duplicating a lot of the code in=20 edk2-platforms\Platform\ARM\Drivers\NorFlashDxe and I have already=20 spotted some new bugs in this patch. Have you considered splitting the NorFlashDxe to introduce a=20 NorFlashDeviceLib that implements the specifics for the respective flash? i.e. NorFlashDxe links with NorFlashDeviceLib and the platforms can=20 specify the respective NorFlashDeviceLib instances. NorFlashDeviceLib|Platform/Arm/Library/P30NorFlashDeviceLib/P30NorFlashDevi= ceLib.inf NorFlashDeviceLib|Platform/Arm/Library/CadenceQspiNorFlashDeviceLib/Cadence= QspiNorFlashDeviceLib.inf Regards, Sami Mujawar On 16/11/2023 11:45 am, sahil wrote: > Add NOR flash DXE driver, this brings up NV storage on > QSPI's flash device using FVB protocol. > > Signed-off-by: sahil > --- > Platform/ARM/N1Sdp/N1SdpPlatform.dec | 5 +- > Platform/ARM/N1Sdp/Drivers/CadenceQspiDxe/CadenceQspiDxe.inf | 72 ++ > Platform/ARM/N1Sdp/Drivers/CadenceQspiDxe/CadenceQspiReg.h | 33 + > Platform/ARM/N1Sdp/Drivers/CadenceQspiDxe/NorFlash.h | 491 +++= ++++++ > Platform/ARM/N1Sdp/Drivers/CadenceQspiDxe/CadenceQspiDxe.c | 409 +++= +++++ > Platform/ARM/N1Sdp/Drivers/CadenceQspiDxe/NorFlash.c | 1100 +++= +++++++++++++++++ > Platform/ARM/N1Sdp/Drivers/CadenceQspiDxe/NorFlashFvb.c | 647 +++= +++++++++ > 7 files changed, 2756 insertions(+), 1 deletion(-) > > diff --git a/Platform/ARM/N1Sdp/N1SdpPlatform.dec b/Platform/ARM/N1Sdp/N1= SdpPlatform.dec > index 16937197b8e8..67b5f4c871b6 100644 > --- a/Platform/ARM/N1Sdp/N1SdpPlatform.dec > +++ b/Platform/ARM/N1Sdp/N1SdpPlatform.dec > @@ -1,7 +1,7 @@ > ## @file > > # Describes the N1Sdp configuration. > > # > > -# Copyright (c) 2021, ARM Limited. All rights reserved.
> > +# Copyright (c) 2021-2023, ARM Limited. All rights reserved.
> > # > > # SPDX-License-Identifier: BSD-2-Clause-Patent > > ## > > @@ -89,3 +89,6 @@ > # unmapped reserved region results in a DECERR response. > > # > > gArmN1SdpTokenSpaceGuid.PcdCsComponentSize|0x1000|UINT32|0x00000049 > > + > > + # Base address of Cadence QSPI controller configuration registers > > + gArmN1SdpTokenSpaceGuid.PcdCadenceQspiDxeRegBaseAddress|0x1C0C0000|UIN= T32|0x0000004A > > diff --git a/Platform/ARM/N1Sdp/Drivers/CadenceQspiDxe/CadenceQspiDxe.inf= b/Platform/ARM/N1Sdp/Drivers/CadenceQspiDxe/CadenceQspiDxe.inf > new file mode 100644 > index 000000000000..62a4944c95db > --- /dev/null > +++ b/Platform/ARM/N1Sdp/Drivers/CadenceQspiDxe/CadenceQspiDxe.inf > @@ -0,0 +1,72 @@ > +## @file > > +# NOR flash DXE > > +# > > +# Copyright (c) 2023, ARM Limited. All rights reserved.
> > +# > > +# SPDX-License-Identifier: BSD-2-Clause-Patent > > +# > > +## > > + > > +[Defines] > > + INF_VERSION =3D 0x0001001B > > + BASE_NAME =3D CadenceQspiDxe > > + FILE_GUID =3D CC8A9713-4442-4A6C-B389-8B46490A064= 1 > > + MODULE_TYPE =3D DXE_RUNTIME_DRIVER > > + VERSION_STRING =3D 0.1 > > + ENTRY_POINT =3D NorFlashInitialise > > + > > +[Sources] > > + CadenceQspiDxe.c > > + CadenceQspiReg.h > > + NorFlash.c > > + NorFlash.h > > + NorFlashFvb.c > > + > > +[Packages] > > + EmbeddedPkg/EmbeddedPkg.dec > > + MdeModulePkg/MdeModulePkg.dec > > + MdePkg/MdePkg.dec > > + Platform/ARM/ARM.dec > > + Platform/ARM/N1Sdp/N1SdpPlatform.dec > > + > > +[LibraryClasses] > > + BaseLib > > + BaseMemoryLib > > + DebugLib > > + DevicePathLib > > + DxeServicesTableLib > > + HobLib > > + IoLib > > + MemoryAllocationLib > > + NorFlashInfoLib > > + NorFlashPlatformLib > > + TimerLib > > + UefiBootServicesTableLib > > + UefiDriverEntryPoint > > + UefiLib > > + UefiRuntimeLib > > + UefiRuntimeServicesTableLib > > + > > +[Guids] > > + gEdkiiNvVarStoreFormattedGuid > > + gEfiAuthenticatedVariableGuid > > + gEfiEventVirtualAddressChangeGuid > > + gEfiSystemNvDataFvGuid > > + gEfiVariableGuid > > + gEfiGlobalVariableGuid > > + > > +[Protocols] > > + gEfiDevicePathProtocolGuid > > + gEfiFirmwareVolumeBlockProtocolGuid > > + > > +[FixedPcd] > > + gArmN1SdpTokenSpaceGuid.PcdCadenceQspiDxeRegBaseAddress > > + gEfiMdeModulePkgTokenSpaceGuid.PcdFlashNvStorageVariableBase > > + gEfiMdeModulePkgTokenSpaceGuid.PcdFlashNvStorageVariableSize > > + gEfiMdeModulePkgTokenSpaceGuid.PcdFlashNvStorageFtwWorkingBase > > + gEfiMdeModulePkgTokenSpaceGuid.PcdFlashNvStorageFtwWorkingSize > > + gEfiMdeModulePkgTokenSpaceGuid.PcdFlashNvStorageFtwSpareBase > > + gEfiMdeModulePkgTokenSpaceGuid.PcdFlashNvStorageFtwSpareSize > > + > > +[Depex] > > + gEfiCpuArchProtocolGuid > > diff --git a/Platform/ARM/N1Sdp/Drivers/CadenceQspiDxe/CadenceQspiReg.h b= /Platform/ARM/N1Sdp/Drivers/CadenceQspiDxe/CadenceQspiReg.h > new file mode 100644 > index 000000000000..535e6d738d31 > --- /dev/null > +++ b/Platform/ARM/N1Sdp/Drivers/CadenceQspiDxe/CadenceQspiReg.h > @@ -0,0 +1,33 @@ > +/** @file > > + > > + Copyright (c) 2023, ARM Limited. All rights reserved.
> > + > > + SPDX-License-Identifier: BSD-2-Clause-Patent > > + > > +**/ > > + > > +#ifndef CADENCE_QSPI_REG_H_ > > +#define CADENCE_QSPI_REG_H_ > > + > > +// QSPI Controller defines > > +#define CDNS_QSPI_FLASH_CMD_CTRL_REG_OFFSET 0x90 > > +#define CDNS_QSPI_FLASH_CMD_CTRL_REG_EXECUTE 0x01 > > +#define CDNS_QSPI_FLASH_CMD_CTRL_REG_ADDR_ENABLE 0x01 > > +#define CDNS_QSPI_FLASH_CMD_CTRL_REG_ADDR_BIT_POS 19 > > +#define CDNS_QSPI_FLASH_CMD_CTRL_REG_ADDR_BYTE_BIT_POS 16 > > +#define CDNS_QSPI_FLASH_CMD_CTRL_REG_STATUS_BIT 0x02 > > +#define CDNS_QSPI_FLASH_CMD_CTRL_REG_OPCODE_BIT_POS 24 > > +#define CDNS_QSPI_FLASH_CMD_CTRL_REG_READ_ENABLE 0x01 > > +#define CDNS_QSPI_FLASH_CMD_CTRL_REG_READ_BYTE_3B 0x02 > > +#define CDNS_QSPI_FLASH_CMD_CTRL_REG_READEN_BIT_POS 23 > > +#define CDNS_QSPI_FLASH_CMD_CTRL_REG_READBYTE_BIT_POS 20 > > +#define CDNS_QSPI_FLASH_CMD_CTRL_REG_DUMMY_8C 0x8 > > +#define CDNS_QSPI_FLASH_CMD_CTRL_REG_DUMMY_BIT_POS 7 > > +#define CDNS_QSPI_FLASH_CMD_CTRL_REG_NUM_DATA_BYTES(x) ((x - 1) << CDNS= _QSPI_FLASH_CMD_CTRL_REG_READBYTE_BIT_POS) > > +#define CDNS_QSPI_FLASH_CMD_CTRL_REG_NUM_ADDR_BYTES(x) ((x - 1) << CDNS= _QSPI_FLASH_CMD_CTRL_REG_ADDR_BYTE_BIT_POS) > > + > > +#define CDNS_QSPI_FLASH_CMD_READ_DATA_REG_OFFSET 0xA0 > > + > > +#define CDNS_QSPI_FLASH_CMD_ADDR_REG_OFFSET 0x94 > > + > > +#endif /* CADENCE_QSPI_REG_H_ */ > > diff --git a/Platform/ARM/N1Sdp/Drivers/CadenceQspiDxe/NorFlash.h b/Platf= orm/ARM/N1Sdp/Drivers/CadenceQspiDxe/NorFlash.h > new file mode 100644 > index 000000000000..38ae1c2fae89 > --- /dev/null > +++ b/Platform/ARM/N1Sdp/Drivers/CadenceQspiDxe/NorFlash.h > @@ -0,0 +1,491 @@ > +/** @file > > + > > + Copyright (c) 2023, ARM Limited. All rights reserved.
> > + > > + SPDX-License-Identifier: BSD-2-Clause-Patent > > + > > +**/ > > + > > +#ifndef NOR_FLASH_DXE_H_ > > +#define NOR_FLASH_DXE_H_ > > + > > +#include > > +#include > > +#include > > +#include > > +#include > > +#include > > +#include > > +#include > > + > > +#include "CadenceQspiReg.h" > > + > > +#define NOR_FLASH_ERASE_RETRY 10 > > + > > +#define GET_NOR_BLOCK_ADDRESS(BaseAddr, Lba, LbaSize) \ > > + ((BaseAddr) + (UINTN)((Lba) * (Lba= Size))) > > + > > +#define NOR_FLASH_SIGNATURE SIGNATURE_32('S', 'n', 'o', 'r') > > +#define INSTANCE_FROM_FVB_THIS(a) CR(a, NOR_FLASH_INSTANCE, FvbProtocol= , \ > > + NOR_FLASH_SIGNATURE) > > + > > +#define NOR_FLASH_POLL_FSR BIT0 > > + > > +typedef struct _NOR_FLASH_INSTANCE NOR_FLASH_INSTANCE; > > + > > +typedef EFI_STATUS (*NOR_FLASH_INITIALIZE) ( > > + NOR_FLASH_INSTANCE *Instance > > + ); > > + > > +#pragma pack(1) > > +typedef struct { > > + VENDOR_DEVICE_PATH Vendor; > > + UINT8 Index; > > + EFI_DEVICE_PATH_PROTOCOL End; > > +} NOR_FLASH_DEVICE_PATH; > > +#pragma pack() > > + > > +struct _NOR_FLASH_INSTANCE { > > + UINT32 Signature; > > + EFI_HANDLE Handle; > > + > > + BOOLEAN Initialized; > > + NOR_FLASH_INITIALIZE Initialize; > > + > > + UINTN HostRegisterBaseAddress; > > + UINTN DeviceBaseAddress; > > + UINTN RegionBaseAddress; > > + UINTN Size; > > + UINTN BlockSize; > > + UINTN LastBlock; > > + EFI_LBA StartLba; > > + EFI_LBA OffsetLba; > > + > > + EFI_FIRMWARE_VOLUME_BLOCK2_PROTOCOL FvbProtocol; > > + VOID *ShadowBuffer; > > + > > + NOR_FLASH_DEVICE_PATH DevicePath; > > + > > + UINT32 Flags; > > +}; > > + > > +typedef struct { > > + EFI_TPL OriginalTPL; > > + BOOLEAN InterruptsEnabled; > > +} NOR_FLASH_LOCK_CONTEXT; > > + > > +/** > > + Lock all pending read/write to Nor flash device > > + > > + @param[in] Context Nor flash device context structure. > > +**/ > > +VOID > > +EFIAPI > > +NorFlashLock ( > > + IN NOR_FLASH_LOCK_CONTEXT *Context > > + ); > > + > > +/** > > + Unlock all pending read/write to Nor flash device > > + > > + @param[in] Context Nor flash device context structure. > > +**/ > > +VOID > > +EFIAPI > > +NorFlashUnlock ( > > + IN NOR_FLASH_LOCK_CONTEXT *Context > > + ); > > + > > +extern UINTN mFlashNvStorageVariableBase; > > + > > +/** > > + Create Nor flash Instance for given region. > > + > > + @param[in] HostRegisterBase Base address of Nor flash controll= er. > > + @param[in] NorFlashDeviceBase Base address of flash device. > > + @param[in] NorFlashRegionBase Base address of flash region on de= vice. > > + @param[in] NorFlashSize Size of flash region. > > + @param[in] Index Index of given flash region. > > + @param[in] BlockSize Block size of NOR flash device. > > + @param[in] HasVarStore Boolean set for VarStore on given = region. > > + @param[out] NorFlashInstance Instance of given flash region. > > + > > + @retval EFI_SUCCESS On successful creation of NOR flas= h instance. > > +**/ > > +EFI_STATUS > > +NorFlashCreateInstance ( > > + IN UINTN HostRegisterBase, > > + IN UINTN NorFlashDeviceBase, > > + IN UINTN NorFlashRegionBase, > > + IN UINTN NorFlashSize, > > + IN UINT32 Index, > > + IN UINT32 BlockSize, > > + IN BOOLEAN HasVarStore, > > + OUT NOR_FLASH_INSTANCE **NorFlashInstance > > + ); > > + > > +/** > > + Install Fv block on to variable store region > > + > > + @param[in] Instance Instance of Nor flash variable region. > > + > > + @retval EFI_SUCCESS The entry point is executed successfully= . > > +**/ > > +EFI_STATUS > > +EFIAPI > > +NorFlashFvbInitialize ( > > + IN NOR_FLASH_INSTANCE *Instance > > + ); > > + > > +/** > > + Check the integrity of firmware volume header. > > + > > + @param[in] Instance Instance of Nor flash variable region. > > + > > + @retval EFI_SUCCESS The firmware volume is consistent. > > + @retval EFI_NOT_FOUND The firmware volume has been corrupted. > > + > > +**/ > > +EFI_STATUS > > +ValidateFvHeader ( > > + IN NOR_FLASH_INSTANCE *Instance > > + ); > > + > > +/** > > + Initialize the FV Header and Variable Store Header > > + to support variable operations. > > + > > + @param[in] Instance Location to Initialize the headers > > + > > + @retval EFI_SUCCESS Fv init is done > > + > > +**/ > > +EFI_STATUS > > +InitializeFvAndVariableStoreHeaders ( > > + IN NOR_FLASH_INSTANCE *Instance > > + ); > > + > > +/** > > + Retrieves the attributes and current settings of the block. > > + > > + @param[in] This Indicates the EFI_FIRMWARE_VOLUME_BLOCK2_PROT= OCOL instance. > > + > > + @param[out] Attributes Pointer to EFI_FVB_ATTRIBUTES_2 in which the = attributes and > > + current settings are returned. > > + Type EFI_FVB_ATTRIBUTES_2 is defined in > > + EFI_FIRMWARE_VOLUME_HEADER. > > + > > + @retval EFI_SUCCESS The firmware volume attributes were returned. > > + > > +**/ > > +EFI_STATUS > > +EFIAPI > > +FvbGetAttributes ( > > + IN CONST EFI_FIRMWARE_VOLUME_BLOCK2_PROTOCOL *This, > > + OUT EFI_FVB_ATTRIBUTES_2 *Attributes > > + ); > > + > > +/** > > + Sets configurable firmware volume attributes and returns the > > + new settings of the firmware volume. > > + > > + > > + @param[in] This EFI_FIRMWARE_VOLUME_BLOCK2_= PROTOCOL instance. > > + > > + @param[in, out] Attributes On input, Attributes is a p= ointer to > > + EFI_FVB_ATTRIBUTES_2 that c= ontains the desired > > + firmware volume settings. > > + On successful return, it co= ntains the new > > + settings of the firmware vo= lume. > > + > > + @retval EFI_UNSUPPORTED The firmware volume attribu= tes are not supported. > > + > > +**/ > > +EFI_STATUS > > +EFIAPI > > +FvbSetAttributes ( > > + IN CONST EFI_FIRMWARE_VOLUME_BLOCK2_PROTOCOL *This, > > + IN OUT EFI_FVB_ATTRIBUTES_2 *Attributes > > + ); > > + > > +/** > > + Retrieves the base address of a memory-mapped firmware volume. > > + This function should be called only for memory-mapped firmware volumes. > > + > > + @param[in] This EFI_FIRMWARE_VOLUME_BLOCK2_PROTOCOL i= nstance. > > + > > + @param[out] Address Pointer to a caller-allocated > > + EFI_PHYSICAL_ADDRESS that, on success= ful > > + return from GetPhysicalAddress(), con= tains the > > + base address of the firmware volume. > > + > > + @retval EFI_SUCCESS The firmware volume base address was = returned. > > + > > +**/ > > +EFI_STATUS > > +EFIAPI > > +FvbGetPhysicalAddress ( > > + IN CONST EFI_FIRMWARE_VOLUME_BLOCK2_PROTOCOL *This, > > + OUT EFI_PHYSICAL_ADDRESS *Address > > + ); > > + > > +/** > > + Retrieves the size of the requested block. > > + It also returns the number of additional blocks with the identical size= . > > + The GetBlockSize() function is used to retrieve the block map > > + (see EFI_FIRMWARE_VOLUME_HEADER). > > + > > + > > + @param[in] This EFI_FIRMWARE_VOLUME_BLOCK2_PROT= OCOL instance. > > + > > + @param[in] Lba Indicates the block whose size = to return > > + > > + @param[out] BlockSize Pointer to a caller-allocated U= INTN in which > > + the size of the block is return= ed. > > + > > + @param[out] NumberOfBlocks Pointer to a caller-allocated U= INTN in > > + which the number of consecutive= blocks, > > + starting with Lba, is returned.= All > > + blocks in this range have a siz= e of > > + BlockSize. > > + > > + @retval EFI_SUCCESS The firmware volume base addres= s was returned. > > + > > + @retval EFI_INVALID_PARAMETER The requested LBA is out of ran= ge. > > + > > +**/ > > +EFI_STATUS > > +EFIAPI > > +FvbGetBlockSize ( > > + IN CONST EFI_FIRMWARE_VOLUME_BLOCK2_PROTOCOL *This, > > + IN EFI_LBA Lba, > > + OUT UINTN *BlockSize, > > + OUT UINTN *NumberOfBlocks > > + ); > > + > > +/** > > + Reads the specified number of bytes into a buffer from the specified bl= ock. > > + > > + The Read() function reads the requested number of bytes from the > > + requested block and stores them in the provided buffer. > > + > > + @param[in] This EFI_FIRMWARE_VOLUME_BLOCK2_PROTOC= OL instance. > > + > > + @param[in] Lba The starting logical block index = from which to read > > + > > + @param[in] Offset Offset into the block at which to= begin reading. > > + > > + @param[in, out] NumBytes Pointer to a UINTN. > > + At entry, *NumBytes contains the = total size of the > > + buffer. *NumBytes should have a n= on zero value. > > + At exit, *NumBytes contains the t= otal number of > > + bytes read. > > + > > + @param[in out] Buffer Pointer to a caller-allocated buf= fer that will be > > + used to hold the data that is rea= d. > > + > > + @retval EFI_SUCCESS The firmware volume was read succ= essfully, and > > + contents are in Buffer. > > + > > + @retval EFI_BAD_BUFFER_SIZE Read attempted across an LBA boun= dary. > > + > > + @retval EFI_DEVICE_ERROR The block device is not functioni= ng correctly and > > + could not be read. > > + > > +**/ > > +EFI_STATUS > > +EFIAPI > > +FvbRead ( > > + IN CONST EFI_FIRMWARE_VOLUME_BLOCK2_PROTOCOL *This, > > + IN EFI_LBA Lba, > > + IN UINTN Offset, > > + IN OUT UINTN *NumBytes, > > + IN OUT UINT8 *Buffer > > + ); > > + > > +/** > > + Writes the specified number of bytes from the input buffer to the block= . > > + > > + @param[in] This EFI_FIRMWARE_VOLUME_BLOCK2_PROTO= COL instance. > > + > > + @param[in] Lba The starting logical block index= to write to. > > + > > + @param[in] Offset Offset into the block at which t= o begin writing. > > + > > + @param[in, out] NumBytes The pointer to a UINTN. > > + At entry, *NumBytes contains the= total size of the > > + buffer. > > + At exit, *NumBytes contains the = total number of > > + bytes actually written. > > + > > + @param[in] Buffer The pointer to a caller-allocate= d buffer that > > + contains the source for the writ= e. > > + > > + @retval EFI_SUCCESS The firmware volume was written = successfully. > > + > > +**/ > > +EFI_STATUS > > +EFIAPI > > +FvbWrite ( > > + IN CONST EFI_FIRMWARE_VOLUME_BLOCK2_PROTOCOL *This, > > + IN EFI_LBA Lba, > > + IN UINTN Offset, > > + IN OUT UINTN *NumBytes, > > + IN UINT8 *Buffer > > + ); > > + > > +/** > > + Erases and initialises a firmware volume block. > > + > > + @param[in] This EFI_FIRMWARE_VOLUME_BLOCK2_PROTOC= OL > > + > > + @param[in] ... The variable argument list is a l= ist of tuples. > > + Each tuple describes a range of L= BAs to erase > > + and consists of the following: > > + - An EFI_LBA that indicates the s= tarting LBA > > + - A UINTN that indicates the numb= er of blocks > > + to erase. > > + > > + The list is terminated with an > > + EFI_LBA_LIST_TERMINATOR. > > + > > + @retval EFI_SUCCESS The erase request successfully co= mpleted. > > + > > + @retval EFI_ACCESS_DENIED The firmware volume is in the Wri= teDisabled > > + state. > > + > > + @retval EFI_DEVICE_ERROR The block device is not functioni= ng correctly > > + and could not be written. > > + The firmware device may have been= partially > > + erased. > > + > > + @retval EFI_INVALID_PARAMETER One or more of the LBAs listed in= the variable > > + argument list do not exist in the= firmware > > + volume. > > + > > +**/ > > +EFI_STATUS > > +EFIAPI > > +FvbEraseBlocks ( > > + IN CONST EFI_FIRMWARE_VOLUME_BLOCK2_PROTOCOL *This, > > + ... > > + ); > > + > > +/** > > + This function unlock and erase an entire NOR Flash block. > > + > > + @param[in] Instance NOR flash Instance of variable store reg= ion. > > + @param[in] BlockAddress Block address within the variable store = region. > > + > > + @retval EFI_SUCCESS The erase and unlock successfully comple= ted. > > +**/ > > +EFI_STATUS > > +NorFlashUnlockAndEraseSingleBlock ( > > + IN NOR_FLASH_INSTANCE *Instance, > > + IN UINTN BlockAddress > > + ); > > + > > +/** > > + Write a full or portion of a block. > > + > > + @param[in] Instance NOR flash Instance of variable store re= gion. > > + @param[in] Lba The starting logical block index to wri= te to. > > + @param[in] Offset Offset into the block at which to begin= writing. > > + @param[in,out] NumBytes The total size of the buffer. > > + @param[in] Buffer The pointer to a caller-allocated buffe= r that > > + contains the source for the write. > > + > > + @retval EFI_SUCCESS The write is completed. > > +**/ > > +EFI_STATUS > > +NorFlashWriteSingleBlock ( > > + IN NOR_FLASH_INSTANCE *Instance, > > + IN EFI_LBA Lba, > > + IN UINTN Offset, > > + IN OUT UINTN *NumBytes, > > + IN UINT8 *Buffer > > + ); > > + > > +/** > > + Write a full block. > > + > > + @param[in] Instance NOR flash Instance of variable stor= e region. > > + @param[in] Lba The starting logical block index to= write to. > > + @param[in] BufferSizeInBytes The number of bytes to write. > > + @param[in] Buffer The pointer to a caller-allocated b= uffer that > > + contains the source for the write. > > + > > + @retval EFI_SUCCESS The write is completed. > > +**/ > > +EFI_STATUS > > +NorFlashWriteBlocks ( > > + IN NOR_FLASH_INSTANCE *Instance, > > + IN EFI_LBA Lba, > > + IN UINTN BufferSizeInBytes, > > + IN VOID *Buffer > > + ); > > + > > +/** > > + Read a full block. > > + > > + @param[in] Instance NOR flash Instance of variable store= region. > > + @param[in] Lba The starting logical block index to = read from. > > + @param[in] BufferSizeInBytes The number of bytes to read. > > + @param[out] Buffer The pointer to a caller-allocated bu= ffer that > > + should be copied with read data. > > + > > + @retval EFI_SUCCESS The read is completed. > > +**/ > > +EFI_STATUS > > +NorFlashReadBlocks ( > > + IN NOR_FLASH_INSTANCE *Instance, > > + IN EFI_LBA Lba, > > + IN UINTN BufferSizeInBytes, > > + OUT VOID *Buffer > > + ); > > + > > +/** > > + Read from nor flash. > > + > > + @param[in] Instance NOR flash Instance of variable store= region. > > + @param[in] Lba The starting logical block index to = read from. > > + @param[in] Offset Offset into the block at which to be= gin reading. > > + @param[in] BufferSizeInBytes The number of bytes to read. > > + @param[out] Buffer The pointer to a caller-allocated bu= ffer that > > + should copied with read data. > > + > > + @retval EFI_SUCCESS The read is completed. > > +**/ > > +EFI_STATUS > > +NorFlashRead ( > > + IN NOR_FLASH_INSTANCE *Instance, > > + IN EFI_LBA Lba, > > + IN UINTN Offset, > > + IN UINTN BufferSizeInBytes, > > + OUT VOID *Buffer > > + ); > > + > > +/** > > + Read JEDEC ID of NOR flash device. > > + > > + @param[in] Instance NOR flash Instance of variable store regio= n. > > + @param[out] JedecId JEDEC ID of NOR flash device. > > + > > + @retval EFI_SUCCESS The write is completed. > > +**/ > > +EFI_STATUS > > +NorFlashReadID ( > > + IN NOR_FLASH_INSTANCE *Instance, > > + OUT UINT8 JedecId[3] > > + ); > > + > > +#define SPINOR_SR_WIP BIT0 // Write in progress > > + > > +#define SPINOR_OP_WREN 0x06 // Write enable > > +#define SPINOR_OP_BE_4K 0x20 // Erase 4KiB block > > +#define SPINOR_OP_RDID 0x9f // Read JEDEC ID > > +#define SPINOR_OP_RDSR 0x05 // Read status register > > + > > +#define SPINOR_SR_WIP_POLL_TIMEOUT_MS 1000u // Status Register read tim= eout > > + > > +#endif /* NOR_FLASH_DXE_H_ */ > > diff --git a/Platform/ARM/N1Sdp/Drivers/CadenceQspiDxe/CadenceQspiDxe.c b= /Platform/ARM/N1Sdp/Drivers/CadenceQspiDxe/CadenceQspiDxe.c > new file mode 100644 > index 000000000000..fffe689161a6 > --- /dev/null > +++ b/Platform/ARM/N1Sdp/Drivers/CadenceQspiDxe/CadenceQspiDxe.c > @@ -0,0 +1,409 @@ > +/** @file > > + NOR flash DXE > > + > > + Copyright (c) 2023, ARM Limited. All rights reserved.
> > + > > + SPDX-License-Identifier: BSD-2-Clause-Patent > > + > > +**/ > > + > > +#include > > +#include > > +#include > > +#include > > +#include > > +#include > > +#include > > +#include > > +#include > > +#include > > + > > +#include "NorFlash.h" > > + > > +STATIC NOR_FLASH_INSTANCE **mNorFlashInstances; > > +STATIC UINT32 mNorFlashDeviceCount; > > + > > +STATIC EFI_EVENT mNorFlashVirtualAddrChangeEvent; > > + > > +/** > > + Install Fv block onto variable store region > > + > > + @param[in] Instance Instance of Nor flash variable region. > > + > > + @retval EFI_SUCCESS The entry point is executed successfully= . > > +**/ > > +EFI_STATUS > > +EFIAPI > > +NorFlashFvbInitialize ( > > + IN NOR_FLASH_INSTANCE *Instance > > + ) > > +{ > > + EFI_STATUS Status; > > + UINT32 FvbNumLba; > > + EFI_BOOT_MODE BootMode; > > + UINTN RuntimeMmioRegionSize; > > + UINTN RuntimeMmioDeviceSize; > > + UINTN BlockSize; > > + > > + DEBUG ((DEBUG_INFO, "NorFlashFvbInitialize\n")); > > + > > + BlockSize =3D Instance->BlockSize; > > + > > + // FirmwareVolumeHeader->FvLength is declared to have the Variable are= a > > + // AND the FTW working area AND the FTW Spare contiguous. > > + ASSERT ( > > + PcdGet32 (PcdFlashNvStorageVariableBase) + > > + PcdGet32 (PcdFlashNvStorageVariableSize) =3D=3D > > + PcdGet32 (PcdFlashNvStorageFtwWorkingBase) > > + ); > > + ASSERT ( > > + PcdGet32 (PcdFlashNvStorageFtwWorkingBase) + > > + PcdGet32 (PcdFlashNvStorageFtwWorkingSize) =3D=3D > > + PcdGet32 (PcdFlashNvStorageFtwSpareBase) > > + ); > > + > > + // Check if the size of the area is at least one block size. > > + ASSERT ( > > + (PcdGet32 (PcdFlashNvStorageVariableSize) > 0) && > > + (PcdGet32 (PcdFlashNvStorageVariableSize) / BlockSize > 0) > > + ); > > + ASSERT ( > > + (PcdGet32 (PcdFlashNvStorageFtwWorkingSize) > 0) && > > + (PcdGet32 (PcdFlashNvStorageFtwWorkingSize) / BlockSize > 0) > > + ); > > + ASSERT ( > > + (PcdGet32 (PcdFlashNvStorageFtwSpareSize) > 0) && > > + (PcdGet32 (PcdFlashNvStorageFtwSpareSize) / BlockSize > 0) > > + ); > > + > > + // Ensure the Variable areas are aligned on block size boundaries. > > + ASSERT ((PcdGet32 (PcdFlashNvStorageVariableBase) % BlockSize) =3D=3D = 0); > > + ASSERT ((PcdGet32 (PcdFlashNvStorageFtwWorkingBase) % BlockSize) =3D= =3D 0); > > + ASSERT ((PcdGet32 (PcdFlashNvStorageFtwSpareBase) % BlockSize) =3D=3D = 0); > > + > > + Instance->Initialized =3D TRUE; > > + mFlashNvStorageVariableBase =3D FixedPcdGet32 (PcdFlashNvStorageVariab= leBase); > > + > > + // Set the index of the first LBA for the FVB. > > + Instance->StartLba =3D (PcdGet32 (PcdFlashNvStorageVariableBase) - > > + Instance->RegionBaseAddress) / BlockSize; > > + > > + BootMode =3D GetBootModeHob (); > > + if (BootMode =3D=3D BOOT_WITH_DEFAULT_SETTINGS) { > > + Status =3D EFI_INVALID_PARAMETER; > > + } else { > > + // Determine if there is a valid header at the beginning of the NorF= lash. > > + Status =3D ValidateFvHeader (Instance); > > + } > > + > > + // Install the Default FVB header if required. > > + if (EFI_ERROR (Status)) { > > + // There is no valid header, so time to install one. > > + DEBUG ((DEBUG_INFO, "%a: The FVB Header is not valid.\n", __func__))= ; > > + DEBUG (( > > + DEBUG_INFO, > > + "%a: Installing a correct one for this volume.\n", > > + __func__ > > + )); > > + > > + // Erase all the NorFlash that is reserved for variable storage. > > + FvbNumLba =3D (PcdGet32 (PcdFlashNvStorageVariableSize) + > > + PcdGet32 (PcdFlashNvStorageFtwWorkingSize) + > > + PcdGet32 (PcdFlashNvStorageFtwSpareSize)) / > > + Instance->BlockSize; > > + > > + Status =3D FvbEraseBlocks ( > > + &Instance->FvbProtocol, > > + (EFI_LBA)0, > > + FvbNumLba, > > + EFI_LBA_LIST_TERMINATOR > > + ); > > + if (EFI_ERROR (Status)) { > > + return Status; > > + } > > + > > + // Install all appropriate headers. > > + Status =3D InitializeFvAndVariableStoreHeaders (Instance); > > + if (EFI_ERROR (Status)) { > > + return Status; > > + } > > + > > + // validate FV header again if FV was created successfully. > > + Status =3D ValidateFvHeader (Instance); > > + if (EFI_ERROR (Status)) { > > + DEBUG ((DEBUG_ERROR, "ValidateFvHeader is failed \n")); > > + return Status; > > + } > > + } > > + > > + // The driver implementing the variable read service can now be dispat= ched; > > + // the varstore headers are in place. > > + Status =3D gBS->InstallProtocolInterface ( > > + &gImageHandle, > > + &gEdkiiNvVarStoreFormattedGuid, > > + EFI_NATIVE_INTERFACE, > > + NULL > > + ); > > + if (EFI_ERROR (Status)) { > > + DEBUG (( > > + DEBUG_ERROR, > > + "%a: Failed to install gEdkiiNvVarStoreFormattedGuid\n", > > + __func__ > > + )); > > + return Status; > > + } > > + > > + // Declare the Non-Volatile storage as EFI_MEMORY_RUNTIME. > > + RuntimeMmioRegionSize =3D Instance->Size; > > + RuntimeMmioDeviceSize =3D Instance->RegionBaseAddress - Instance->Devi= ceBaseAddress; > > + > > + Status =3D gDS->AddMemorySpace ( > > + EfiGcdMemoryTypeMemoryMappedIo, > > + Instance->RegionBaseAddress, > > + RuntimeMmioRegionSize, > > + EFI_MEMORY_UC | EFI_MEMORY_RUNTIME > > + ); > > + ASSERT_EFI_ERROR (Status); > > + > > + Status =3D gDS->AddMemorySpace ( > > + EfiGcdMemoryTypeMemoryMappedIo, > > + Instance->DeviceBaseAddress, > > + RuntimeMmioDeviceSize, > > + EFI_MEMORY_UC | EFI_MEMORY_RUNTIME > > + ); > > + ASSERT_EFI_ERROR (Status); > > + > > + Status =3D gDS->SetMemorySpaceAttributes ( > > + Instance->RegionBaseAddress, > > + RuntimeMmioRegionSize, > > + EFI_MEMORY_UC | EFI_MEMORY_RUNTIME > > + ); > > + ASSERT_EFI_ERROR (Status); > > + > > + Status =3D gDS->SetMemorySpaceAttributes ( > > + Instance->DeviceBaseAddress, > > + RuntimeMmioDeviceSize, > > + EFI_MEMORY_UC | EFI_MEMORY_RUNTIME > > + ); > > + ASSERT_EFI_ERROR (Status); > > + > > + return Status; > > +} > > + > > +/** > > + Fixup internal data so that EFI can be called in virtual mode. > > + convert any pointers in lib to virtual mode. > > + > > + @param[in] Event The Event that is being processed > > + @param[in] Context Event Context > > +**/ > > +STATIC > > +VOID > > +EFIAPI > > +NorFlashVirtualNotifyEvent ( > > + IN EFI_EVENT Event, > > + IN VOID *Context > > + ) > > +{ > > + UINTN Index; > > + > > + EfiConvertPointer (0x0, (VOID **)&mFlashNvStorageVariableBase); > > + > > + for (Index =3D 0; Index < mNorFlashDeviceCount; Index++) { > > + EfiConvertPointer ( > > + 0x0, > > + (VOID **)&mNorFlashInstances[Index]->HostRegisterBaseAddress > > + ); > > + EfiConvertPointer ( > > + 0x0, > > + (VOID **)&mNorFlashInstances[Index]->DeviceBaseAddress > > + ); > > + EfiConvertPointer ( > > + 0x0, > > + (VOID **)&mNorFlashInstances[Index]->RegionBaseAddress > > + ); > > + > > + // Convert Fvb. > > + EfiConvertPointer ( > > + 0x0, > > + (VOID **)&mNorFlashInstances[Index]->FvbProtocol.EraseBlocks > > + ); > > + EfiConvertPointer ( > > + 0x0, > > + (VOID **)&mNorFlashInstances[Index]->FvbProtocol.GetAttributes > > + ); > > + EfiConvertPointer ( > > + 0x0, > > + (VOID **)&mNorFlashInstances[Index]->FvbProtocol.GetBlockSize > > + ); > > + EfiConvertPointer ( > > + 0x0, > > + (VOID **)&mNorFlashInstances[Index]->FvbProtocol.GetPhysicalAddres= s > > + ); > > + EfiConvertPointer ( > > + 0x0, > > + (VOID **)&mNorFlashInstances[Index]->FvbProtocol.Read > > + ); > > + EfiConvertPointer ( > > + 0x0, > > + (VOID **)&mNorFlashInstances[Index]->FvbProtocol.SetAttributes > > + ); > > + EfiConvertPointer ( > > + 0x0, > > + (VOID **)&mNorFlashInstances[Index]->FvbProtocol.Write > > + ); > > + > > + if (mNorFlashInstances[Index]->ShadowBuffer !=3D NULL) { > > + EfiConvertPointer (0x0, (VOID **)&mNorFlashInstances[Index]->Shado= wBuffer); > > + } > > + } > > +} > > + > > +/** > > + Entrypoint of Platform Nor flash DXE driver > > + > > + @param[in] ImageHandle The firmware allocated handle for the EF= I image. > > + @param[in] SystemTable A pointer to the EFI System Table. > > + > > + @retval EFI_SUCCESS The entry point is executed successfully= . > > +**/ > > +EFI_STATUS > > +EFIAPI > > +NorFlashInitialise ( > > + IN EFI_HANDLE ImageHandle, > > + IN EFI_SYSTEM_TABLE *SystemTable > > + ) > > +{ > > + EFI_STATUS Status; > > + EFI_PHYSICAL_ADDRESS HostRegisterBaseAddress; > > + UINT32 Index; > > + NOR_FLASH_DESCRIPTION *NorFlashDevices; > > + BOOLEAN ContainVariableStorage; > > + > > + HostRegisterBaseAddress =3D PcdGet32 (PcdCadenceQspiDxeRegBaseAddress)= ; > > + > > + Status =3D gDS->AddMemorySpace ( > > + EfiGcdMemoryTypeMemoryMappedIo, > > + HostRegisterBaseAddress, > > + SIZE_64KB, > > + EFI_MEMORY_UC | EFI_MEMORY_RUNTIME > > + ); > > + ASSERT_EFI_ERROR (Status); > > + > > + Status =3D gDS->SetMemorySpaceAttributes ( > > + HostRegisterBaseAddress, > > + SIZE_64KB, > > + EFI_MEMORY_UC | EFI_MEMORY_RUNTIME > > + ); > > + ASSERT_EFI_ERROR (Status); > > + > > + // Initialize NOR flash instances. > > + Status =3D NorFlashPlatformGetDevices (&NorFlashDevices, &mNorFlashDev= iceCount); > > + if (EFI_ERROR (Status)) { > > + DEBUG ((DEBUG_ERROR, "NorFlashInitialise: Fail to get Nor Flash devi= ces\n")); > > + return Status; > > + } > > + > > + mNorFlashInstances =3D AllocateRuntimePool ( > > + sizeof (NOR_FLASH_INSTANCE *) * > > + mNorFlashDeviceCount > > + ); > > + > > + if (mNorFlashInstances =3D=3D NULL) { > > + DEBUG (( > > + DEBUG_ERROR, > > + "NorFlashInitialise: Failed to allocate mem for NorFlashInstance\n= " > > + )); > > + return EFI_OUT_OF_RESOURCES; > > + } > > + > > + for (Index =3D 0; Index < mNorFlashDeviceCount; Index++) { > > + // Check if this NOR Flash device contain the variable storage regio= n. > > + ContainVariableStorage =3D > > + (NorFlashDevices[Index].RegionBaseAddress <=3D > > + PcdGet32 (PcdFlashNvStorageVariableBase)) && > > + (PcdGet32 (PcdFlashNvStorageVariableBase) + > > + PcdGet32 (PcdFlashNvStorageVariableSize) <=3D > > + NorFlashDevices[Index].RegionBaseAddress + NorFlashDevices[Index]= .Size); > > + > > + Status =3D NorFlashCreateInstance ( > > + HostRegisterBaseAddress, > > + NorFlashDevices[Index].DeviceBaseAddress, > > + NorFlashDevices[Index].RegionBaseAddress, > > + NorFlashDevices[Index].Size, > > + Index, > > + NorFlashDevices[Index].BlockSize, > > + ContainVariableStorage, > > + &mNorFlashInstances[Index] > > + ); > > + if (EFI_ERROR (Status)) { > > + DEBUG (( > > + DEBUG_ERROR, > > + "NorFlashInitialise: Fail to create instance for NorFlash[%d]\n"= , > > + Index > > + )); > > + continue; > > + } > > + > > + Status =3D gBS->InstallMultipleProtocolInterfaces ( > > + &mNorFlashInstances[Index]->Handle, > > + &gEfiDevicePathProtocolGuid, > > + &mNorFlashInstances[Index]->DevicePath, > > + &gEfiFirmwareVolumeBlockProtocolGuid, > > + &mNorFlashInstances[Index]->FvbProtocol, > > + NULL > > + ); > > + ASSERT_EFI_ERROR (Status); > > + } > > + > > + // Register for the virtual address change event. > > + Status =3D gBS->CreateEventEx ( > > + EVT_NOTIFY_SIGNAL, > > + TPL_NOTIFY, > > + NorFlashVirtualNotifyEvent, > > + NULL, > > + &gEfiEventVirtualAddressChangeGuid, > > + &mNorFlashVirtualAddrChangeEvent > > + ); > > + ASSERT_EFI_ERROR (Status); > > + > > + return Status; > > +} > > + > > +/** > > + Lock all pending read/write to Nor flash device > > + > > + @param[in] Context Nor flash device context structure. > > +**/ > > +VOID > > +EFIAPI > > +NorFlashLock ( > > + IN NOR_FLASH_LOCK_CONTEXT *Context > > + ) > > +{ > > + if (!EfiAtRuntime ()) { > > + // Raise TPL to TPL_HIGH to stop anyone from interrupting us. > > + Context->OriginalTPL =3D gBS->RaiseTPL (TPL_HIGH_LEVEL); > > + } else { > > + Context->InterruptsEnabled =3D SaveAndDisableInterrupts (); > > + } > > +} > > + > > +/** > > + Unlock all pending read/write to Nor flash device > > + > > + @param[in] Context Nor flash device context structure. > > +**/ > > +VOID > > +EFIAPI > > +NorFlashUnlock ( > > + IN NOR_FLASH_LOCK_CONTEXT *Context > > + ) > > +{ > > + if (!EfiAtRuntime ()) { > > + // Interruptions can resume. > > + gBS->RestoreTPL (Context->OriginalTPL); > > + } else if (Context->InterruptsEnabled) { > > + SetInterruptState (TRUE); > > + } > > +} > > diff --git a/Platform/ARM/N1Sdp/Drivers/CadenceQspiDxe/NorFlash.c b/Platf= orm/ARM/N1Sdp/Drivers/CadenceQspiDxe/NorFlash.c > new file mode 100644 > index 000000000000..be7b626c5697 > --- /dev/null > +++ b/Platform/ARM/N1Sdp/Drivers/CadenceQspiDxe/NorFlash.c > @@ -0,0 +1,1100 @@ > +/** @file > > + > > + Copyright (c) 2023 ARM Limited. All rights reserved.
> > + > > + SPDX-License-Identifier: BSD-2-Clause-Patent > > + > > +**/ > > + > > +#include > > +#include > > +#include > > +#include > > +#include > > +#include > > +#include > > + > > +#include "NorFlash.h" > > + > > +STATIC CONST NOR_FLASH_INSTANCE mNorFlashInstanceTemplate =3D { > > + NOR_FLASH_SIGNATURE, // Signature > > + NULL, // Handle > > + > > + FALSE, // Initialized > > + NULL, // Initialize > > + > > + 0, // HostRegisterBaseAddress > > + 0, // DeviceBaseAddress > > + 0, // RegionBaseAddress > > + 0, // Size > > + 0, // BlockSize > > + 0, // LastBlock > > + 0, // StartLba > > + 0, // OffsetLba > > + > > + { > > + FvbGetAttributes, // GetAttributes > > + FvbSetAttributes, // SetAttributes > > + FvbGetPhysicalAddress, // GetPhysicalAddress > > + FvbGetBlockSize, // GetBlockSize > > + FvbRead, // Read > > + FvbWrite, // Write > > + FvbEraseBlocks, // EraseBlocks > > + NULL, // ParentHandle > > + }, // FvbProtoccol; > > + NULL, // ShadowBuffer > > + > > + { > > + { > > + { > > + HARDWARE_DEVICE_PATH, > > + HW_VENDOR_DP, > > + { > > + (UINT8)(OFFSET_OF (NOR_FLASH_DEVICE_PATH, End)), > > + (UINT8)(OFFSET_OF (NOR_FLASH_DEVICE_PATH, End) >> 8) > > + } > > + }, > > + { 0x0, 0x0, 0x0, { 0x0, 0x0, 0x0, 0x= 0, 0x0, 0x0, 0x0, 0x0 } > > + }, > > + }, > > + 0, // Index > > + > > + { > > + END_DEVICE_PATH_TYPE, > > + END_ENTIRE_DEVICE_PATH_SUBTYPE, > > + { sizeof (EFI_DEVICE_PATH_PROTOCOL), 0 } > > + } > > + }, // DevicePath > > + 0 // Flags > > +}; > > + > > +/** > > + Execute Flash cmd ctrl and Read Status. > > + > > + @param[in] Instance NOR flash Instance. > > + @param[in] Val Value to be written to Flash cmd ctrl= Register. > > + > > + @retval EFI_SUCCESS Request is executed successfully. > > + > > +**/ > > +STATIC > > +EFI_STATUS > > +CdnsQspiExecuteCommand ( > > + IN NOR_FLASH_INSTANCE *Instance, > > + IN UINT32 Val > > + ) > > +{ > > + // Set the command > > + MmioWrite32 ( > > + Instance->HostRegisterBaseAddress + CDNS_QSPI_FLASH_CMD_CTRL_REG_OFF= SET, > > + Val > > + ); > > + // Execute the command > > + MmioWrite32 ( > > + Instance->HostRegisterBaseAddress + CDNS_QSPI_FLASH_CMD_CTRL_REG_OFF= SET, > > + Val | CDNS_QSPI_FLASH_CMD_CTRL_REG_EXECUTE > > + ); > > + > > + // Wait until command has been executed > > + while ((MmioRead32 (Instance->HostRegisterBaseAddress + CDNS_QSPI_FLAS= H_CMD_CTRL_REG_OFFSET) > > + & CDNS_QSPI_FLASH_CMD_CTRL_REG_STATUS_BIT) =3D=3D CDNS_QSPI_FL= ASH_CMD_CTRL_REG_STATUS_BIT) > > + { > > + continue; > > + } > > + > > + return EFI_SUCCESS; > > +} > > + > > +/** > > + Create Nor flash Instance for given region. > > + > > + @param[in] HostRegisterBase Base address of Nor flash controll= er. > > + @param[in] NorFlashDeviceBase Base address of flash device. > > + @param[in] NorFlashRegionBase Base address of flash region on de= vice. > > + @param[in] NorFlashSize Size of flash region. > > + @param[in] Index Index of given flash region. > > + @param[in] BlockSize Block size of NOR flash device. > > + @param[in] HasVarStore Boolean set for VarStore on given = region. > > + @param[out] NorFlashInstance Instance of given flash region. > > + > > + @retval EFI_SUCCESS On successful creation of NOR flas= h instance. > > +**/ > > +EFI_STATUS > > +NorFlashCreateInstance ( > > + IN UINTN HostRegisterBase, > > + IN UINTN NorFlashDeviceBase, > > + IN UINTN NorFlashRegionBase, > > + IN UINTN NorFlashSize, > > + IN UINT32 Index, > > + IN UINT32 BlockSize, > > + IN BOOLEAN HasVarStore, > > + OUT NOR_FLASH_INSTANCE **NorFlashInstance > > + ) > > +{ > > + EFI_STATUS Status; > > + NOR_FLASH_INSTANCE *Instance; > > + NOR_FLASH_INFO *FlashInfo; > > + UINT8 JedecId[3]; > > + > > + ASSERT (NorFlashInstance !=3D NULL); > > + Instance =3D AllocateRuntimeCopyPool ( > > + sizeof (mNorFlashInstanceTemplate), > > + &mNorFlashInstanceTemplate > > + ); > > + if (Instance =3D=3D NULL) { > > + return EFI_OUT_OF_RESOURCES; > > + } > > + > > + Instance->HostRegisterBaseAddress =3D HostRegisterBase; > > + Instance->DeviceBaseAddress =3D NorFlashDeviceBase; > > + Instance->RegionBaseAddress =3D NorFlashRegionBase; > > + Instance->Size =3D NorFlashSize; > > + Instance->BlockSize =3D BlockSize; > > + Instance->LastBlock =3D (NorFlashSize / BlockSize) - 1; > > + > > + Instance->OffsetLba =3D (NorFlashRegionBase - NorFlashDeviceBase) / Bl= ockSize; > > + > > + CopyGuid (&Instance->DevicePath.Vendor.Guid, &gEfiCallerIdGuid); > > + Instance->DevicePath.Index =3D (UINT8)Index; > > + > > + Status =3D NorFlashReadID (Instance, JedecId); > > + if (EFI_ERROR (Status)) { > > + goto FreeInstance; > > + } > > + > > + Status =3D NorFlashGetInfo (JedecId, &FlashInfo, TRUE); > > + if (EFI_ERROR (Status)) { > > + goto FreeInstance; > > + } > > + > > + NorFlashPrintInfo (FlashInfo); > > + > > + Instance->Flags =3D 0; > > + if (FlashInfo->Flags & NOR_FLASH_WRITE_FSR) { > > + Instance->Flags =3D NOR_FLASH_POLL_FSR; > > + } > > + > > + Instance->ShadowBuffer =3D AllocateRuntimePool (BlockSize); > > + if (Instance->ShadowBuffer =3D=3D NULL) { > > + Status =3D EFI_OUT_OF_RESOURCES; > > + goto FreeInstance; > > + } > > + > > + if (HasVarStore) { > > + Instance->Initialize =3D NorFlashFvbInitialize; > > + } > > + > > + *NorFlashInstance =3D Instance; > > + FreePool (FlashInfo); > > + return EFI_SUCCESS; > > + > > +FreeInstance: > > + FreePool (Instance); > > + return Status; > > +} > > + > > +/** > > + Converts milliseconds into number of ticks of the performance counter. > > + > > + @param[in] Milliseconds Milliseconds to convert into ticks. > > + > > + @retval Milliseconds expressed as number of ticks. > > + > > +**/ > > +STATIC > > +UINT64 > > +MilliSecondsToTicks ( > > + IN UINTN Milliseconds > > + ) > > +{ > > + CONST UINT64 NanoSecondsPerTick =3D GetTimeInNanoSecond (1); > > + > > + return (Milliseconds * 1000000) / NanoSecondsPerTick; > > +} > > + > > +/** > > + Poll Status register for NOR flash erase/write completion. > > + > > + @param[in] Instance NOR flash Instance. > > + > > + @retval EFI_SUCCESS Request is executed successfully. > > + @retval EFI_TIMEOUT Operation timed out. > > + @retval EFI_DEVICE_ERROR Controller operartion failed. > > + > > +**/ > > +STATIC > > +EFI_STATUS > > +NorFlashPollStatusRegister ( > > + IN NOR_FLASH_INSTANCE *Instance > > + ) > > +{ > > + BOOLEAN SRegDone; > > + UINT32 val; > > + > > + val =3D SPINOR_OP_RDSR << CDNS_QSPI_FLASH_CMD_CTRL_REG_OPCODE_BIT_POS = | > > + CDNS_QSPI_FLASH_CMD_CTRL_REG_READ_ENABLE << CDNS_QSPI_FLASH_CMD_= CTRL_REG_READEN_BIT_POS | > > + CDNS_QSPI_FLASH_CMD_CTRL_REG_NUM_DATA_BYTES (1) | > > + CDNS_QSPI_FLASH_CMD_CTRL_REG_DUMMY_8C << CDNS_QSPI_FLASH_CMD_CTR= L_REG_DUMMY_BIT_POS; > > + > > + CONST UINT64 TickOut =3D > > + GetPerformanceCounter () + MilliSecondsToTicks (SPINOR_SR_WIP_POLL_T= IMEOUT_MS); > > + > > + do { > > + if (GetPerformanceCounter () > TickOut) { > > + DEBUG (( > > + DEBUG_ERROR, > > + "NorFlashPollStatusRegister: Timeout waiting for erase/write.\n" > > + )); > > + return EFI_TIMEOUT; > > + } > > + > > + if (EFI_ERROR (CdnsQspiExecuteCommand (Instance, val))) { > > + return EFI_DEVICE_ERROR; > > + } > > + > > + SRegDone =3D > > + (MmioRead8 (Instance->HostRegisterBaseAddress + CDNS_QSPI_FLASH_CM= D_READ_DATA_REG_OFFSET) > > + & SPINOR_SR_WIP) =3D=3D 0; > > + } while (!SRegDone); > > + > > + return EFI_SUCCESS; > > +} > > + > > +/** > > + Check whether NOR flash opertions are Locked. > > + > > + @param[in] Instance NOR flash Instance. > > + @param[in] BlockAddress BlockAddress in NOR flash device. > > + > > + @retval FALSE If NOR flash is not locked. > > +**/ > > +STATIC > > +BOOLEAN > > +NorFlashBlockIsLocked ( > > + IN NOR_FLASH_INSTANCE *Instance, > > + IN UINTN BlockAddress > > + ) > > +{ > > + return FALSE; > > +} > > + > > +/** > > + Unlock NOR flash operations on given block. > > + > > + @param[in] Instance NOR flash instance. > > + @param[in] BlockAddress BlockAddress in NOR flash device. > > + > > + @retval EFI_SUCCESS NOR flash operations is unlocked. > > +**/ > > +STATIC > > +EFI_STATUS > > +NorFlashUnlockSingleBlock ( > > + IN NOR_FLASH_INSTANCE *Instance, > > + IN UINTN BlockAddress > > + ) > > +{ > > + return EFI_SUCCESS; > > +} > > + > > +/** > > + Unlock NOR flash operations if it is necessary. > > + > > + @param[in] Instance NOR flash instance. > > + @param[in] BlockAddress BlockAddress in NOR flash device. > > + > > + @retval EFI_SUCCESS Request is executed successfully. > > +**/ > > +STATIC > > +EFI_STATUS > > +NorFlashUnlockSingleBlockIfNecessary ( > > + IN NOR_FLASH_INSTANCE *Instance, > > + IN UINTN BlockAddress > > + ) > > +{ > > + EFI_STATUS Status; > > + > > + Status =3D EFI_SUCCESS; > > + > > + if (!NorFlashBlockIsLocked (Instance, BlockAddress)) { > > + Status =3D NorFlashUnlockSingleBlock (Instance, BlockAddress); > > + } > > + > > + return Status; > > +} > > + > > +/** > > + Enable write to NOR flash device. > > + > > + @param[in] Instance NOR flash instance. > > + > > + @retval EFI_SUCCESS Request is executed successfully. > > +**/ > > +STATIC > > +EFI_STATUS > > +NorFlashEnableWrite ( > > + IN NOR_FLASH_INSTANCE *Instance > > + ) > > +{ > > + UINT32 val; > > + > > + DEBUG ((DEBUG_INFO, "NorFlashEnableWrite()\n")); > > + val =3D (SPINOR_OP_WREN << CDNS_QSPI_FLASH_CMD_CTRL_REG_OPCODE_BIT_POS= ); > > + if (EFI_ERROR (CdnsQspiExecuteCommand (Instance, val))) { > > + return EFI_DEVICE_ERROR; > > + } > > + > > + return EFI_SUCCESS; > > +} > > + > > +/** > > + The following function presumes that the block has already been unlock= ed. > > + > > + @param[in] Instance NOR flash instance. > > + @param[in] BlockAddress Block address within the variable reg= ion. > > + > > + @retval EFI_SUCCESS Request is executed successfully. > > + **/ > > +EFI_STATUS > > +NorFlashEraseSingleBlock ( > > + IN NOR_FLASH_INSTANCE *Instance, > > + IN UINTN BlockAddress > > + ) > > +{ > > + UINT32 DevConfigVal; > > + UINT32 EraseOffset; > > + > > + EraseOffset =3D 0x0; > > + > > + DEBUG (( > > + DEBUG_INFO, > > + "NorFlashEraseSingleBlock(BlockAddress=3D0x%08x)\n", > > + BlockAddress > > + )); > > + > > + if (EFI_ERROR (NorFlashEnableWrite (Instance))) { > > + return EFI_DEVICE_ERROR; > > + } > > + > > + EraseOffset =3D BlockAddress - Instance->DeviceBaseAddress; > > + > > + MmioWrite32 ( > > + Instance->HostRegisterBaseAddress + CDNS_QSPI_FLASH_CMD_ADDR_REG_OFF= SET, > > + EraseOffset > > + ); > > + > > + DevConfigVal =3D SPINOR_OP_BE_4K << CDNS_QSPI_FLASH_CMD_CTRL_REG_OPCOD= E_BIT_POS | > > + CDNS_QSPI_FLASH_CMD_CTRL_REG_ADDR_ENABLE << CDNS_QSPI_F= LASH_CMD_CTRL_REG_ADDR_BIT_POS | > > + CDNS_QSPI_FLASH_CMD_CTRL_REG_NUM_ADDR_BYTES (3); > > + > > + if (EFI_ERROR (CdnsQspiExecuteCommand (Instance, DevConfigVal))) { > > + return EFI_DEVICE_ERROR; > > + } > > + > > + if (EFI_ERROR (NorFlashPollStatusRegister (Instance))) { > > + return EFI_DEVICE_ERROR; > > + } > > + > > + return EFI_SUCCESS; > > +} > > + > > +/** > > + This function unlock and erase an entire NOR Flash block. > > + > > + @param[in] Instance NOR flash Instance of variable store reg= ion. > > + @param[in] BlockAddress Block address within the variable store = region. > > + > > + @retval EFI_SUCCESS The erase and unlock successfully comple= ted. > > +**/ > > +EFI_STATUS > > +NorFlashUnlockAndEraseSingleBlock ( > > + IN NOR_FLASH_INSTANCE *Instance, > > + IN UINTN BlockAddress > > + ) > > +{ > > + EFI_STATUS Status; > > + UINTN Index; > > + NOR_FLASH_LOCK_CONTEXT Lock; > > + > > + NorFlashLock (&Lock); > > + > > + Index =3D 0; > > + do { > > + // Unlock the block if we have to > > + Status =3D NorFlashUnlockSingleBlockIfNecessary (Instance, BlockAddr= ess); > > + if (EFI_ERROR (Status)) { > > + break; > > + } > > + > > + Status =3D NorFlashEraseSingleBlock (Instance, BlockAddress); > > + if (EFI_ERROR (Status)) { > > + break; > > + } > > + > > + Index++; > > + } while ((Index < NOR_FLASH_ERASE_RETRY) && (Status =3D=3D EFI_WRITE_P= ROTECTED)); > > + > > + if (Index =3D=3D NOR_FLASH_ERASE_RETRY) { > > + DEBUG (( > > + DEBUG_ERROR, > > + "EraseSingleBlock(BlockAddress=3D0x%08x: Block Locked Error (try t= o erase %d times)\n", > > + BlockAddress, > > + Index > > + )); > > + } > > + > > + NorFlashUnlock (&Lock); > > + > > + return Status; > > +} > > + > > +/** > > + Write a single word to given location. > > + > > + @param[in] Instance NOR flash Instance of variable store region= . > > + @param[in] WordAddress The address in NOR flash to write given wor= d. > > + @param[in] WriteData The data to write into NOR flash location. > > + > > + @retval EFI_SUCCESS The write is completed. > > +**/ > > +STATIC > > +EFI_STATUS > > +NorFlashWriteSingleWord ( > > + IN NOR_FLASH_INSTANCE *Instance, > > + IN UINTN WordAddress, > > + IN UINT32 WriteData > > + ) > > +{ > > + DEBUG (( > > + DEBUG_INFO, > > + "NorFlashWriteSingleWord(WordAddress=3D0x%08x, WriteData=3D0x%08x)\n= ", > > + WordAddress, > > + WriteData > > + )); > > + > > + if (EFI_ERROR (NorFlashEnableWrite (Instance))) { > > + return EFI_DEVICE_ERROR; > > + } > > + > > + MmioWrite32 (WordAddress, WriteData); > > + if (EFI_ERROR (NorFlashPollStatusRegister (Instance))) { > > + return EFI_DEVICE_ERROR; > > + } > > + > > + return EFI_SUCCESS; > > +} > > + > > +/** > > + Write a full block to given location. > > + > > + @param[in] Instance NOR flash Instance of variable store = region. > > + @param[in] Lba The logical block address in NOR flas= h. > > + @param[in] DataBuffer The data to write into NOR flash loca= tion. > > + @param[in] BlockSizeInWords The number of bytes to write. > > + > > + @retval EFI_SUCCESS The write is completed. > > +**/ > > +STATIC > > +EFI_STATUS > > +NorFlashWriteFullBlock ( > > + IN NOR_FLASH_INSTANCE *Instance, > > + IN EFI_LBA Lba, > > + IN UINT32 *DataBuffer, > > + IN UINT32 BlockSizeInWords > > + ) > > +{ > > + EFI_STATUS Status; > > + UINTN WordAddress; > > + UINT32 WordIndex; > > + UINTN BlockAddress; > > + NOR_FLASH_LOCK_CONTEXT Lock; > > + > > + Status =3D EFI_SUCCESS; > > + > > + // Get the physical address of the block > > + BlockAddress =3D GET_NOR_BLOCK_ADDRESS ( > > + Instance->RegionBaseAddress, > > + Lba, > > + BlockSizeInWords * 4 > > + ); > > + > > + // Start writing from the first address at the start of the block > > + WordAddress =3D BlockAddress; > > + > > + NorFlashLock (&Lock); > > + > > + Status =3D NorFlashUnlockAndEraseSingleBlock (Instance, BlockAddress); > > + if (EFI_ERROR (Status)) { > > + DEBUG (( > > + DEBUG_ERROR, > > + "WriteSingleBlock: ERROR - Failed to Unlock and Erase the single b= lock at 0x%X\n", > > + BlockAddress > > + )); > > + goto EXIT; > > + } > > + > > + for (WordIndex =3D 0; > > + WordIndex < BlockSizeInWords; > > + WordIndex++, DataBuffer++, WordAddress +=3D 4) > > + { > > + Status =3D NorFlashWriteSingleWord (Instance, WordAddress, *DataBuff= er); > > + if (EFI_ERROR (Status)) { > > + goto EXIT; > > + } > > + } > > + > > +EXIT: > > + NorFlashUnlock (&Lock); > > + > > + if (EFI_ERROR (Status)) { > > + DEBUG (( > > + DEBUG_ERROR, > > + "NOR FLASH Programming [WriteSingleBlock] failed at address 0x%08x= . Exit Status =3D %r.\n", > > + WordAddress, > > + Status > > + )); > > + } > > + > > + return Status; > > +} > > + > > +/** > > + Write a full block. > > + > > + @param[in] Instance NOR flash Instance of variable store = region. > > + @param[in] Lba The starting logical block index. > > + @param[in] BufferSizeInBytes The number of bytes to read. > > + @param[in] Buffer The pointer to a caller-allocated buf= fer that > > + contains the source for the write. > > + > > + @retval EFI_SUCCESS The write is completed. > > +**/ > > +EFI_STATUS > > +NorFlashWriteBlocks ( > > + IN NOR_FLASH_INSTANCE *Instance, > > + IN EFI_LBA Lba, > > + IN UINTN BufferSizeInBytes, > > + IN VOID *Buffer > > + ) > > +{ > > + UINT32 *pWriteBuffer; > > + EFI_STATUS Status; > > + EFI_LBA CurrentBlock; > > + UINT32 BlockSizeInWords; > > + UINT32 NumBlocks; > > + UINT32 BlockCount; > > + > > + Status =3D EFI_SUCCESS; > > + // The buffer must be valid > > + if (Buffer =3D=3D NULL) { > > + return EFI_INVALID_PARAMETER; > > + } > > + > > + // We must have some bytes to read > > + DEBUG (( > > + DEBUG_INFO, > > + "NorFlashWriteBlocks: BufferSizeInBytes=3D0x%x\n", > > + BufferSizeInBytes > > + )); > > + if (BufferSizeInBytes =3D=3D 0) { > > + return EFI_BAD_BUFFER_SIZE; > > + } > > + > > + // The size of the buffer must be a multiple of the block size > > + DEBUG (( > > + DEBUG_INFO, > > + "NorFlashWriteBlocks: BlockSize in bytes =3D0x%x\n", > > + Instance->BlockSize > > + )); > > + if ((BufferSizeInBytes % Instance->BlockSize) !=3D 0) { > > + return EFI_BAD_BUFFER_SIZE; > > + } > > + > > + // All blocks must be within the device > > + NumBlocks =3D ((UINT32)BufferSizeInBytes) / Instance->BlockSize; > > + > > + DEBUG (( > > + DEBUG_INFO, > > + "NorFlashWriteBlocks: NumBlocks=3D%d, LastBlock=3D%ld, Lba=3D%ld.\n"= , > > + NumBlocks, > > + Instance->LastBlock, > > + Lba > > + )); > > + > > + if ((Lba + NumBlocks) > (Instance->LastBlock + 1)) { > > + DEBUG (( > > + DEBUG_ERROR, > > + "NorFlashWriteBlocks: ERROR - Write will exceed last block.\n" > > + )); > > + return EFI_INVALID_PARAMETER; > > + } > > + > > + ASSERT (((UINTN)Buffer % sizeof (UINT32)) =3D=3D 0); > > + > > + BlockSizeInWords =3D Instance->BlockSize / 4; > > + > > + // Because the target *Buffer is a pointer to VOID, we must put > > + // all the data into a pointer to a proper data type, so use *ReadBuff= er > > + pWriteBuffer =3D (UINT32 *)Buffer; > > + > > + CurrentBlock =3D Lba; > > + for (BlockCount =3D 0; > > + BlockCount < NumBlocks; > > + BlockCount++, CurrentBlock++, pWriteBuffer +=3D BlockSizeInWords) > > + { > > + DEBUG (( > > + DEBUG_INFO, > > + "NorFlashWriteBlocks: Writing block #%d\n", > > + (UINTN)CurrentBlock > > + )); > > + > > + Status =3D NorFlashWriteFullBlock ( > > + Instance, > > + CurrentBlock, > > + pWriteBuffer, > > + BlockSizeInWords > > + ); > > + > > + if (EFI_ERROR (Status)) { > > + break; > > + } > > + } > > + > > + DEBUG ((DEBUG_INFO, "NorFlashWriteBlocks: Exit Status =3D %r.\n", Stat= us)); > > + return Status; > > +} > > + > > +/** > > + Read a full block. > > + > > + @param[in] Instance NOR flash Instance of variable store= region. > > + @param[in] Lba The starting logical block index to = read from. > > + @param[in] BufferSizeInBytes The number of bytes to read. > > + @param[out] Buffer The pointer to a caller-allocated bu= ffer that > > + should be copied with read data. > > + > > + @retval EFI_SUCCESS The read is completed. > > +**/ > > +EFI_STATUS > > +NorFlashReadBlocks ( > > + IN NOR_FLASH_INSTANCE *Instance, > > + IN EFI_LBA Lba, > > + IN UINTN BufferSizeInBytes, > > + OUT VOID *Buffer > > + ) > > +{ > > + UINT32 NumBlocks; > > + UINTN StartAddress; > > + > > + DEBUG (( > > + DEBUG_INFO, > > + "NorFlashReadBlocks: BufferSize=3D0x%xB BlockSize=3D0x%xB LastBlock= =3D%ld, Lba=3D%ld.\n", > > + BufferSizeInBytes, > > + Instance->BlockSize, > > + Instance->LastBlock, > > + Lba > > + )); > > + > > + // The buffer must be valid > > + if (Buffer =3D=3D NULL) { > > + return EFI_INVALID_PARAMETER; > > + } > > + > > + // Return if we do not have any byte to read > > + if (BufferSizeInBytes =3D=3D 0) { > > + return EFI_SUCCESS; > > + } > > + > > + // The size of the buffer must be a multiple of the block size > > + if ((BufferSizeInBytes % Instance->BlockSize) !=3D 0) { > > + return EFI_BAD_BUFFER_SIZE; > > + } > > + > > + NumBlocks =3D ((UINT32)BufferSizeInBytes) / Instance->BlockSize; > > + > > + if ((Lba + NumBlocks) > (Instance->LastBlock + 1)) { > > + DEBUG (( > > + DEBUG_ERROR, > > + "NorFlashReadBlocks: ERROR - Read will exceed last block\n" > > + )); > > + return EFI_INVALID_PARAMETER; > > + } > > + > > + // Get the address to start reading from > > + StartAddress =3D GET_NOR_BLOCK_ADDRESS ( > > + Instance->RegionBaseAddress, > > + Lba, > > + Instance->BlockSize > > + ); > > + > > + // Readout the data > > + CopyMem (Buffer, (UINTN *)StartAddress, BufferSizeInBytes); > > + > > + return EFI_SUCCESS; > > +} > > + > > +/** > > + Read from nor flash. > > + > > + @param[in] Instance NOR flash Instance of variable store= region. > > + @param[in] Lba The starting logical block index to = read from. > > + @param[in] Offset Offset into the block at which to be= gin reading. > > + @param[in] BufferSizeInBytes The number of bytes to read. > > + @param[out] Buffer The pointer to a caller-allocated bu= ffer that > > + should copied with read data. > > + > > + @retval EFI_SUCCESS The read is completed. > > +**/ > > +EFI_STATUS > > +NorFlashRead ( > > + IN NOR_FLASH_INSTANCE *Instance, > > + IN EFI_LBA Lba, > > + IN UINTN Offset, > > + IN UINTN BufferSizeInBytes, > > + OUT VOID *Buffer > > + ) > > +{ > > + UINTN StartAddress; > > + > > + // The buffer must be valid > > + if (Buffer =3D=3D NULL) { > > + return EFI_INVALID_PARAMETER; > > + } > > + > > + // Return if we do not have any byte to read > > + if (BufferSizeInBytes =3D=3D 0) { > > + return EFI_SUCCESS; > > + } > > + > > + if (((Lba * Instance->BlockSize) + Offset + BufferSizeInBytes) > > > + Instance->Size) > > + { > > + DEBUG (( > > + DEBUG_ERROR, > > + "NorFlashRead: ERROR - Read will exceed device size.\n" > > + )); > > + return EFI_INVALID_PARAMETER; > > + } > > + > > + // Get the address to start reading from > > + StartAddress =3D GET_NOR_BLOCK_ADDRESS ( > > + Instance->RegionBaseAddress, > > + Lba, > > + Instance->BlockSize > > + ); > > + > > + // Readout the data > > + CopyMem (Buffer, (UINTN *)(StartAddress + Offset), BufferSizeInBytes); > > + > > + return EFI_SUCCESS; > > +} > > + > > +/** > > + Write a full or portion of a block. > > + > > + @param[in] Instance NOR flash Instance of variable store r= egion. > > + @param[in] Lba The starting logical block index to wr= ite to. > > + @param[in] Offset Offset into the block at which to begi= n writing. > > + @param[in, out] NumBytes The total size of the buffer. > > + @param[in] Buffer The pointer to a caller-allocated buff= er that > > + contains the source for the write. > > + > > + @retval EFI_SUCCESS The write is completed. > > +**/ > > +EFI_STATUS > > +NorFlashWriteSingleBlock ( > > + IN NOR_FLASH_INSTANCE *Instance, > > + IN EFI_LBA Lba, > > + IN UINTN Offset, > > + IN OUT UINTN *NumBytes, > > + IN UINT8 *Buffer > > + ) > > +{ > > + EFI_STATUS Status; > > + UINT32 Tmp; > > + UINT32 TmpBuf; > > + UINT32 WordToWrite; > > + UINT32 Mask; > > + BOOLEAN DoErase; > > + UINTN BytesToWrite; > > + UINTN CurOffset; > > + UINTN WordAddr; > > + UINTN BlockSize; > > + UINTN BlockAddress; > > + UINTN PrevBlockAddress; > > + > > + if (Buffer =3D=3D NULL) { > > + DEBUG (( > > + DEBUG_ERROR, > > + "NorFlashWriteSingleBlock: ERROR - Buffer is invalid\n" > > + )); > > + return EFI_OUT_OF_RESOURCES; > > + } > > + > > + PrevBlockAddress =3D 0; > > + if (!Instance->Initialized && Instance->Initialize) { > > + Instance->Initialize (Instance); > > + } > > + > > + DEBUG (( > > + DEBUG_INFO, > > + "NorFlashWriteSingleBlock(Parameters: Lba=3D%ld, Offset=3D0x%x, *Num= Bytes=3D0x%x, Buffer @ 0x%08x)\n", > > + Lba, > > + Offset, > > + *NumBytes, > > + Buffer > > + )); > > + > > + // Localise the block size to avoid de-referencing pointers all the ti= me > > + BlockSize =3D Instance->BlockSize; > > + > > + // The write must not span block boundaries. > > + // We need to check each variable individually because adding two larg= e > > + // values together overflows. > > + if ((Offset >=3D BlockSize) || > > + (*NumBytes > BlockSize) || > > + ((Offset + *NumBytes) > BlockSize)) > > + { > > + DEBUG (( > > + DEBUG_ERROR, > > + "NorFlashWriteSingleBlock: ERROR - EFI_BAD_BUFFER_SIZE: (Offset=3D= 0x%x + NumBytes=3D0x%x) > BlockSize=3D0x%x\n", > > + Offset, > > + *NumBytes, > > + BlockSize > > + )); > > + return EFI_BAD_BUFFER_SIZE; > > + } > > + > > + // We must have some bytes to write > > + if (*NumBytes =3D=3D 0) { > > + DEBUG (( > > + DEBUG_ERROR, > > + "NorFlashWriteSingleBlock: ERROR - EFI_BAD_BUFFER_SIZE: (Offset=3D= 0x%x + NumBytes=3D0x%x) > BlockSize=3D0x%x\n", > > + Offset, > > + *NumBytes, > > + BlockSize > > + )); > > + return EFI_BAD_BUFFER_SIZE; > > + } > > + > > + // Pick 128bytes as a good start for word operations as opposed to era= sing the > > + // block and writing the data regardless if an erase is really needed. > > + // It looks like most individual NV variable writes are smaller than 1= 28bytes. > > + if (*NumBytes <=3D 128) { > > + // Check to see if we need to erase before programming the data into= NOR. > > + // If the destination bits are only changing from 1s to 0s we can ju= st write. > > + // After a block is erased all bits in the block is set to 1. > > + // If any byte requires us to erase we just give up and rewrite all = of it. > > + DoErase =3D FALSE; > > + BytesToWrite =3D *NumBytes; > > + CurOffset =3D Offset; > > + > > + while (BytesToWrite > 0) { > > + // Read full word from NOR, splice as required. A word is the smal= lest > > + // unit we can write. > > + Status =3D NorFlashRead ( > > + Instance, > > + Lba, > > + CurOffset & ~(0x3), > > + sizeof (Tmp), > > + &Tmp > > + ); > > + if (EFI_ERROR (Status)) { > > + return EFI_DEVICE_ERROR; > > + } > > + > > + // Physical address of word in NOR to write. > > + WordAddr =3D (CurOffset & ~(0x3)) + > > + GET_NOR_BLOCK_ADDRESS ( > > + Instance->RegionBaseAddress, > > + Lba, > > + BlockSize > > + ); > > + > > + // The word of data that is to be written. > > + TmpBuf =3D ReadUnaligned32 ((UINT32 *)(Buffer + (*NumBytes - Bytes= ToWrite))); > > + > > + // First do word aligned chunks. > > + if ((CurOffset & 0x3) =3D=3D 0) { > > + if (BytesToWrite >=3D 4) { > > + // Is the destination still in 'erased' state? > > + if (~Tmp !=3D 0) { > > + // Check to see if we are only changing bits to zero. > > + if ((Tmp ^ TmpBuf) & TmpBuf) { > > + DoErase =3D TRUE; > > + break; > > + } > > + } > > + > > + // Write this word to NOR > > + WordToWrite =3D TmpBuf; > > + CurOffset +=3D sizeof (TmpBuf); > > + BytesToWrite -=3D sizeof (TmpBuf); > > + } else { > > + // BytesToWrite < 4. Do small writes and left-overs > > + Mask =3D ~((~0) << (BytesToWrite * 8)); > > + // Mask out the bytes we want. > > + TmpBuf &=3D Mask; > > + // Is the destination still in 'erased' state? > > + if ((Tmp & Mask) !=3D Mask) { > > + // Check to see if we are only changing bits to zero. > > + if ((Tmp ^ TmpBuf) & TmpBuf) { > > + DoErase =3D TRUE; > > + break; > > + } > > + } > > + > > + // Merge old and new data. Write merged word to NOR > > + WordToWrite =3D (Tmp & ~Mask) | TmpBuf; > > + CurOffset +=3D BytesToWrite; > > + BytesToWrite =3D 0; > > + } > > + } else { > > + // Do multiple words, but starting unaligned. > > + if (BytesToWrite > (4 - (CurOffset & 0x3))) { > > + Mask =3D ((~0) << ((CurOffset & 0x3) * 8)); > > + // Mask out the bytes we want. > > + TmpBuf &=3D Mask; > > + // Is the destination still in 'erased' state? > > + if ((Tmp & Mask) !=3D Mask) { > > + // Check to see if we are only changing bits to zero. > > + if ((Tmp ^ TmpBuf) & TmpBuf) { > > + DoErase =3D TRUE; > > + break; > > + } > > + } > > + > > + // Merge old and new data. Write merged word to NOR > > + WordToWrite =3D (Tmp & ~Mask) | TmpBuf; > > + BytesToWrite -=3D (4 - (CurOffset & 0x3)); > > + CurOffset +=3D (4 - (CurOffset & 0x3)); > > + } else { > > + // Unaligned and fits in one word. > > + Mask =3D (~((~0) << (BytesToWrite * 8))) << ((CurOffset & 0x3)= * 8); > > + // Mask out the bytes we want. > > + TmpBuf =3D (TmpBuf << ((CurOffset & 0x3) * 8)) & Mask; > > + // Is the destination still in 'erased' state? > > + if ((Tmp & Mask) !=3D Mask) { > > + // Check to see if we are only changing bits to zero. > > + if ((Tmp ^ TmpBuf) & TmpBuf) { > > + DoErase =3D TRUE; > > + break; > > + } > > + } > > + > > + // Merge old and new data. Write merged word to NOR > > + WordToWrite =3D (Tmp & ~Mask) | TmpBuf; > > + CurOffset +=3D BytesToWrite; > > + BytesToWrite =3D 0; > > + } > > + } > > + > > + BlockAddress =3D GET_NOR_BLOCK_ADDRESS ( > > + Instance->RegionBaseAddress, > > + Lba, > > + BlockSize > > + ); > > + if (BlockAddress !=3D PrevBlockAddress) { > > + Status =3D NorFlashUnlockSingleBlockIfNecessary (Instance, Block= Address); > > + if (EFI_ERROR (Status)) { > > + return EFI_DEVICE_ERROR; > > + } > > + > > + PrevBlockAddress =3D BlockAddress; > > + } > > + > > + Status =3D NorFlashWriteSingleWord (Instance, WordAddr, WordToWrit= e); > > + if (EFI_ERROR (Status)) { > > + return EFI_DEVICE_ERROR; > > + } > > + } > > + > > + // Exit if we got here and could write all the data. Otherwise do th= e > > + // Erase-Write cycle. > > + if (!DoErase) { > > + return EFI_SUCCESS; > > + } > > + } > > + > > + // Check we did get some memory. Buffer is BlockSize. > > + if (Instance->ShadowBuffer =3D=3D NULL) { > > + DEBUG ((DEBUG_ERROR, "FvbWrite: ERROR - Buffer not ready\n")); > > + return EFI_DEVICE_ERROR; > > + } > > + > > + // Read NOR Flash data into shadow buffer > > + Status =3D NorFlashReadBlocks ( > > + Instance, > > + Lba, > > + BlockSize, > > + Instance->ShadowBuffer > > + ); > > + if (EFI_ERROR (Status)) { > > + // Return one of the pre-approved error statuses > > + return EFI_DEVICE_ERROR; > > + } > > + > > + // Put the data at the appropriate location inside the buffer area > > + CopyMem ((VOID *)((UINTN)Instance->ShadowBuffer + Offset), Buffer, *Nu= mBytes); > > + > > + // Write the modified buffer back to the NorFlash > > + Status =3D NorFlashWriteBlocks ( > > + Instance, > > + Lba, > > + BlockSize, > > + Instance->ShadowBuffer > > + ); > > + if (EFI_ERROR (Status)) { > > + // Return one of the pre-approved error statuses > > + return EFI_DEVICE_ERROR; > > + } > > + > > + return EFI_SUCCESS; > > +} > > + > > +/** > > + Read JEDEC ID of NOR flash device. > > + > > + @param[in] Instance NOR flash Instance of variable store regio= n. > > + @param[out] JedecId JEDEC ID of NOR flash device. > > + > > + @retval EFI_SUCCESS The write is completed. > > +**/ > > +EFI_STATUS > > +NorFlashReadID ( > > + IN NOR_FLASH_INSTANCE *Instance, > > + OUT UINT8 JedecId[3] > > + ) > > +{ > > + UINT32 val; > > + > > + if ((Instance =3D=3D NULL) || (JedecId =3D=3D NULL)) { > > + return EFI_INVALID_PARAMETER; > > + } > > + > > + val =3D SPINOR_OP_RDID << CDNS_QSPI_FLASH_CMD_CTRL_REG_OPCODE_BIT_POS = | > > + CDNS_QSPI_FLASH_CMD_CTRL_REG_READ_ENABLE << CDNS_QSPI_FLASH_CMD_= CTRL_REG_READEN_BIT_POS | > > + CDNS_QSPI_FLASH_CMD_CTRL_REG_NUM_DATA_BYTES (3); > > + > > + if (EFI_ERROR (CdnsQspiExecuteCommand (Instance, val))) { > > + return EFI_DEVICE_ERROR; > > + } > > + > > + val =3D MmioRead32 (Instance->HostRegisterBaseAddress + CDNS_QSPI_FLAS= H_CMD_READ_DATA_REG_OFFSET); > > + > > + // Manu.ID field > > + JedecId[0] =3D (UINT8)val; > > + // Type field > > + JedecId[1] =3D (UINT8)(val >> 8); > > + // Capacity field > > + JedecId[2] =3D (UINT8)(val >> 16); > > + > > + DEBUG (( > > + DEBUG_INFO, > > + "Nor flash detected, Jedec ID, Manu.Id=3D%x Type=3D%x Capacity=3D%x = \n", > > + JedecId[0], > > + JedecId[1], > > + JedecId[2] > > + )); > > + > > + return EFI_SUCCESS; > > +} > > diff --git a/Platform/ARM/N1Sdp/Drivers/CadenceQspiDxe/NorFlashFvb.c b/Pl= atform/ARM/N1Sdp/Drivers/CadenceQspiDxe/NorFlashFvb.c > new file mode 100644 > index 000000000000..8281d4825dc9 > --- /dev/null > +++ b/Platform/ARM/N1Sdp/Drivers/CadenceQspiDxe/NorFlashFvb.c > @@ -0,0 +1,647 @@ > +/** @file > > + > > + Copyright (c) 2023, ARM Limited. All rights reserved.
> > + > > + SPDX-License-Identifier: BSD-2-Clause-Patent > > + > > +**/ > > + > > +#include > > +#include > > + > > +#include > > +#include > > +#include > > +#include > > +#include > > +#include > > + > > +#include > > + > > +#include "NorFlash.h" > > + > > +UINTN mFlashNvStorageVariableBase; > > + > > +/** > > + Initialize the FV Header and Variable Store Header > > + to support variable operations. > > + > > + @param[in] Instance Location to initialise the headers. > > + > > + @retval EFI_SUCCESS Fv init is done. > > + > > +**/ > > +EFI_STATUS > > +InitializeFvAndVariableStoreHeaders ( > > + IN NOR_FLASH_INSTANCE *Instance > > + ) > > +{ > > + EFI_STATUS Status; > > + VOID *Headers; > > + UINTN HeadersLength; > > + EFI_FIRMWARE_VOLUME_HEADER *FirmwareVolumeHeader; > > + VARIABLE_STORE_HEADER *VariableStoreHeader; > > + > > + if (!Instance->Initialized && Instance->Initialize) { > > + Instance->Initialize (Instance); > > + } > > + > > + HeadersLength =3D sizeof (EFI_FIRMWARE_VOLUME_HEADER) + > > + sizeof (EFI_FV_BLOCK_MAP_ENTRY) + > > + sizeof (VARIABLE_STORE_HEADER); > > + Headers =3D AllocateZeroPool (HeadersLength); > > + > > + FirmwareVolumeHeader =3D (EFI_FIRMWARE_VOLUME_HEADER *)Headers; > > + CopyGuid (&FirmwareVolumeHeader->FileSystemGuid, &gEfiSystemNvDataFvGu= id); > > + FirmwareVolumeHeader->FvLength =3D > > + PcdGet32 (PcdFlashNvStorageVariableSize) + > > + PcdGet32 (PcdFlashNvStorageFtwWorkingSize) + > > + PcdGet32 (PcdFlashNvStorageFtwSpareSize); > > + FirmwareVolumeHeader->Signature =3D EFI_FVH_SIGNATURE; > > + FirmwareVolumeHeader->Attributes =3D EFI_FVB2_READ_ENABLED_CAP | > > + EFI_FVB2_READ_STATUS | > > + EFI_FVB2_STICKY_WRITE | > > + EFI_FVB2_MEMORY_MAPPED | > > + EFI_FVB2_ERASE_POLARITY | > > + EFI_FVB2_WRITE_STATUS | > > + EFI_FVB2_WRITE_ENABLED_CAP; > > + > > + FirmwareVolumeHeader->HeaderLength =3D sizeof (EFI_FIRMWARE_VOLUME_HEA= DER) + > > + sizeof (EFI_FV_BLOCK_MAP_ENTRY); > > + FirmwareVolumeHeader->Revision =3D EFI_FVH_REVISION; > > + FirmwareVolumeHeader->BlockMap[0].NumBlocks =3D Instance->LastBlock + = 1; > > + FirmwareVolumeHeader->BlockMap[0].Length =3D Instance->BlockSize; > > + FirmwareVolumeHeader->BlockMap[1].NumBlocks =3D 0; > > + FirmwareVolumeHeader->BlockMap[1].Length =3D 0; > > + FirmwareVolumeHeader->Checksum =3D CalculateCheckSum16 ( > > + (UINT16 *)FirmwareVolu= meHeader, > > + FirmwareVolumeHeader->= HeaderLength > > + ); > > + > > + VariableStoreHeader =3D (VOID *)((UINTN)Headers + > > + FirmwareVolumeHeader->HeaderLength); > > + CopyGuid (&VariableStoreHeader->Signature, &gEfiAuthenticatedVariableG= uid); > > + VariableStoreHeader->Size =3D PcdGet32 (PcdFlashNvStorageVariableSize)= - > > + FirmwareVolumeHeader->HeaderLength; > > + VariableStoreHeader->Format =3D VARIABLE_STORE_FORMATTED; > > + VariableStoreHeader->State =3D VARIABLE_STORE_HEALTHY; > > + > > + // Install the combined super-header in the NorFlash > > + Status =3D FvbWrite (&Instance->FvbProtocol, 0, 0, &HeadersLength, Hea= ders); > > + > > + FreePool (Headers); > > + return Status; > > +} > > + > > +/** > > + Check the integrity of firmware volume header. > > + > > + @param[in] Instance Instance of Nor flash variable region. > > + > > + @retval EFI_SUCCESS The firmware volume is consistent. > > + @retval EFI_NOT_FOUND The firmware volume has been corrupted. > > + > > +**/ > > +EFI_STATUS > > +ValidateFvHeader ( > > + IN NOR_FLASH_INSTANCE *Instance > > + ) > > +{ > > + EFI_FIRMWARE_VOLUME_HEADER *FwVolHeader; > > + VARIABLE_STORE_HEADER *VariableStoreHeader; > > + UINTN VariableStoreLength; > > + UINTN FvLength; > > + > > + FwVolHeader =3D (EFI_FIRMWARE_VOLUME_HEADER *)Instance->RegionBaseAddr= ess; > > + > > + FvLength =3D PcdGet32 (PcdFlashNvStorageVariableSize) + > > + PcdGet32 (PcdFlashNvStorageFtwWorkingSize) + > > + PcdGet32 (PcdFlashNvStorageFtwSpareSize); > > + > > + if ( (FwVolHeader->Revision !=3D EFI_FVH_REVISION) > > + || (FwVolHeader->Signature !=3D EFI_FVH_SIGNATURE) > > + || (FwVolHeader->FvLength !=3D FvLength) > > + ) > > + { > > + DEBUG (( > > + DEBUG_ERROR, > > + "%a: No Firmware Volume header present\n", > > + __func__ > > + )); > > + return EFI_NOT_FOUND; > > + } > > + > > + // Check the Firmware Volume Guid > > + if (!CompareGuid (&FwVolHeader->FileSystemGuid, &gEfiSystemNvDataFvGui= d)) { > > + DEBUG (( > > + DEBUG_ERROR, > > + "%a: Firmware Volume Guid non-compatible\n", > > + __func__ > > + )); > > + return EFI_NOT_FOUND; > > + } > > + > > + VariableStoreHeader =3D (VOID *)((UINTN)FwVolHeader + > > + FwVolHeader->HeaderLength); > > + > > + // Check the Variable Store Guid > > + if (!CompareGuid (&VariableStoreHeader->Signature, &gEfiVariableGuid) = && > > + !CompareGuid ( > > + &VariableStoreHeader->Signature, > > + &gEfiAuthenticatedVariableGuid > > + )) > > + { > > + DEBUG (( > > + DEBUG_ERROR, > > + "%a: Variable Store Guid non-compatible\n", > > + __func__ > > + )); > > + return EFI_NOT_FOUND; > > + } > > + > > + VariableStoreLength =3D PcdGet32 (PcdFlashNvStorageVariableSize) - > > + FwVolHeader->HeaderLength; > > + if (VariableStoreHeader->Size !=3D VariableStoreLength) { > > + DEBUG (( > > + DEBUG_ERROR, > > + "%a: Variable Store Length does not match\n", > > + __func__ > > + )); > > + return EFI_NOT_FOUND; > > + } > > + > > + return EFI_SUCCESS; > > +} > > + > > +/** > > + Retrieves the attributes and current settings of the block. > > + > > + @param[in] This Indicates the EFI_FIRMWARE_VOLUME_BLOCK2_PROT= OCOL instance. > > + > > + @param[out] Attributes Pointer to EFI_FVB_ATTRIBUTES_2 in which the = attributes and > > + current settings are returned. > > + Type EFI_FVB_ATTRIBUTES_2 is defined in > > + EFI_FIRMWARE_VOLUME_HEADER. > > + > > + @retval EFI_SUCCESS The firmware volume attributes were returned. > > + > > +**/ > > +EFI_STATUS > > +EFIAPI > > +FvbGetAttributes ( > > + IN CONST EFI_FIRMWARE_VOLUME_BLOCK2_PROTOCOL *This, > > + OUT EFI_FVB_ATTRIBUTES_2 *Attributes > > + ) > > +{ > > + EFI_FVB_ATTRIBUTES_2 FlashFvbAttributes; > > + > > + FlashFvbAttributes =3D EFI_FVB2_READ_ENABLED_CAP | EFI_FVB2_READ_STATU= S | > > + EFI_FVB2_WRITE_ENABLED_CAP | EFI_FVB2_WRITE_STATU= S | > > + EFI_FVB2_STICKY_WRITE | EFI_FVB2_MEMORY_MAPPED | > > + EFI_FVB2_ERASE_POLARITY; > > + > > + *Attributes =3D FlashFvbAttributes; > > + > > + DEBUG ((DEBUG_INFO, "FvbGetAttributes(0x%X)\n", *Attributes)); > > + > > + return EFI_SUCCESS; > > +} > > + > > +/** > > + Sets configurable firmware volume attributes and returns the > > + new settings of the firmware volume. > > + > > + > > + @param[in] This EFI_FIRMWARE_VOLUME_BLOCK2_= PROTOCOL instance. > > + > > + @param[in, out] Attributes On input, Attributes is a p= ointer to > > + EFI_FVB_ATTRIBUTES_2 that c= ontains the desired > > + firmware volume settings. > > + On successful return, it co= ntains the new > > + settings of the firmware vo= lume. > > + > > + @retval EFI_UNSUPPORTED The firmware volume attribu= tes are not supported. > > + > > +**/ > > +EFI_STATUS > > +EFIAPI > > +FvbSetAttributes ( > > + IN CONST EFI_FIRMWARE_VOLUME_BLOCK2_PROTOCOL *This, > > + IN OUT EFI_FVB_ATTRIBUTES_2 *Attributes > > + ) > > +{ > > + DEBUG (( > > + DEBUG_INFO, > > + "FvbSetAttributes(0x%X) is not supported\n", > > + *Attributes > > + )); > > + return EFI_UNSUPPORTED; > > +} > > + > > +/** > > + Retrieves the base address of a memory-mapped firmware volume. > > + This function should be called only for memory-mapped firmware volumes. > > + > > + @param[in] This EFI_FIRMWARE_VOLUME_BLOCK2_PROTOCOL i= nstance. > > + > > + @param[out] Address Pointer to a caller-allocated > > + EFI_PHYSICAL_ADDRESS that, on success= ful > > + return from GetPhysicalAddress(), con= tains the > > + base address of the firmware volume. > > + > > + @retval EFI_SUCCESS The firmware volume base address was = returned. > > + > > +**/ > > +EFI_STATUS > > +EFIAPI > > +FvbGetPhysicalAddress ( > > + IN CONST EFI_FIRMWARE_VOLUME_BLOCK2_PROTOCOL *This, > > + OUT EFI_PHYSICAL_ADDRESS *Address > > + ) > > +{ > > + NOR_FLASH_INSTANCE *Instance; > > + > > + Instance =3D INSTANCE_FROM_FVB_THIS (This); > > + > > + DEBUG (( > > + DEBUG_INFO, > > + "FvbGetPhysicalAddress(BaseAddress=3D0x%08x)\n", > > + Instance->RegionBaseAddress > > + )); > > + > > + ASSERT (Address !=3D NULL); > > + > > + *Address =3D Instance->RegionBaseAddress; > > + return EFI_SUCCESS; > > +} > > + > > +/** > > + Retrieves the size of the requested block. > > + It also returns the number of additional blocks with the identical size= . > > + The GetBlockSize() function is used to retrieve the block map > > + (see EFI_FIRMWARE_VOLUME_HEADER). > > + > > + > > + @param[in] This EFI_FIRMWARE_VOLUME_BLOCK2_PROT= OCOL instance. > > + > > + @param[in] Lba Indicates the block whose size = to return > > + > > + @param[out] BlockSize Pointer to a caller-allocated U= INTN in which > > + the size of the block is return= ed. > > + > > + @param[out] NumberOfBlocks Pointer to a caller-allocated U= INTN in > > + which the number of consecutive= blocks, > > + starting with Lba, is returned.= All > > + blocks in this range have a siz= e of > > + BlockSize. > > + > > + @retval EFI_SUCCESS The firmware volume base addres= s was returned. > > + > > + @retval EFI_INVALID_PARAMETER The requested LBA is out of ran= ge. > > + > > +**/ > > +EFI_STATUS > > +EFIAPI > > +FvbGetBlockSize ( > > + IN CONST EFI_FIRMWARE_VOLUME_BLOCK2_PROTOCOL *This, > > + IN EFI_LBA Lba, > > + OUT UINTN *BlockSize, > > + OUT UINTN *NumberOfBlocks > > + ) > > +{ > > + EFI_STATUS Status; > > + NOR_FLASH_INSTANCE *Instance; > > + > > + Instance =3D INSTANCE_FROM_FVB_THIS (This); > > + > > + DEBUG (( > > + DEBUG_INFO, > > + "FvbGetBlockSize(Lba=3D%ld, BlockSize=3D0x%x, LastBlock=3D%ld)\n", > > + Lba, > > + Instance->BlockSize, > > + Instance->LastBlock > > + )); > > + > > + if (Lba > Instance->LastBlock) { > > + DEBUG (( > > + DEBUG_ERROR, > > + "FvbGetBlockSize: ERROR - Parameter LBA %ld is beyond the last Lba= (%ld).\n", > > + Lba, > > + Instance->LastBlock > > + )); > > + Status =3D EFI_INVALID_PARAMETER; > > + } else { > > + // This is easy because in this platform each NorFlash device has eq= ual sized blocks. > > + *BlockSize =3D (UINTN)Instance->BlockSize; > > + *NumberOfBlocks =3D (UINTN)(Instance->LastBlock - Lba + 1); > > + > > + DEBUG (( > > + DEBUG_INFO, > > + "FvbGetBlockSize: *BlockSize=3D0x%x, *NumberOfBlocks=3D0x%x.\n", > > + *BlockSize, > > + *NumberOfBlocks > > + )); > > + > > + Status =3D EFI_SUCCESS; > > + } > > + > > + return Status; > > +} > > + > > +/** > > + Reads the specified number of bytes into a buffer from the specified bl= ock. > > + > > + The Read() function reads the requested number of bytes from the > > + requested block and stores them in the provided buffer. > > + > > + @param[in] This EFI_FIRMWARE_VOLUME_BLOCK2_PROTOC= OL instance. > > + > > + @param[in] Lba The starting logical block index = from which to read > > + > > + @param[in] Offset Offset into the block at which to= begin reading. > > + > > + @param[in, out] NumBytes Pointer to a UINTN. > > + At entry, *NumBytes contains the = total size of the > > + buffer. *NumBytes should have a n= on zero value. > > + At exit, *NumBytes contains the t= otal number of > > + bytes read. > > + > > + @param[in, out] Buffer Pointer to a caller-allocated buf= fer that will be > > + used to hold the data that is rea= d. > > + > > + @retval EFI_SUCCESS The firmware volume was read succ= essfully, and > > + contents are in Buffer. > > + > > + @retval EFI_BAD_BUFFER_SIZE Read attempted across an LBA boun= dary. > > + > > + @retval EFI_DEVICE_ERROR The block device is not functioni= ng correctly and > > + could not be read. > > + > > +**/ > > +EFI_STATUS > > +EFIAPI > > +FvbRead ( > > + IN CONST EFI_FIRMWARE_VOLUME_BLOCK2_PROTOCOL *This, > > + IN EFI_LBA Lba, > > + IN UINTN Offset, > > + IN OUT UINTN *NumBytes, > > + IN OUT UINT8 *Buffer > > + ) > > +{ > > + EFI_STATUS Status; > > + UINTN BlockSize; > > + NOR_FLASH_INSTANCE *Instance; > > + > > + Instance =3D INSTANCE_FROM_FVB_THIS (This); > > + > > + DEBUG (( > > + DEBUG_INFO, > > + "FvbRead(Parameters: Lba=3D%ld, Offset=3D0x%x, *NumBytes=3D0x%x, Buf= fer @ 0x%08x)\n", > > + Instance->StartLba + Lba, > > + Offset, > > + *NumBytes, > > + Buffer > > + )); > > + > > + if (!Instance->Initialized && Instance->Initialize) { > > + Instance->Initialize (Instance); > > + } > > + > > + BlockSize =3D Instance->BlockSize; > > + > > + DEBUG (( > > + DEBUG_INFO, > > + "FvbRead: Check if (Offset=3D0x%x + NumBytes=3D0x%x) <=3D BlockSize= =3D0x%x\n", > > + Offset, > > + *NumBytes, > > + BlockSize > > + )); > > + > > + // The read must not span block boundaries. > > + // We need to check each variable individually because adding two larg= e > > + // values together overflows. > > + if ((Offset >=3D BlockSize) || > > + (*NumBytes > BlockSize) || > > + ((Offset + *NumBytes) > BlockSize)) > > + { > > + DEBUG (( > > + DEBUG_ERROR, > > + "FvbRead: ERROR - EFI_BAD_BUFFER_SIZE: (Offset=3D0x%x + NumBytes= =3D0x%x) > BlockSize=3D0x%x\n", > > + Offset, > > + *NumBytes, > > + BlockSize > > + )); > > + return EFI_BAD_BUFFER_SIZE; > > + } > > + > > + // We must have some bytes to read > > + if (*NumBytes =3D=3D 0) { > > + return EFI_BAD_BUFFER_SIZE; > > + } > > + > > + // Decide if we are doing full block reads or not. > > + if (*NumBytes % BlockSize !=3D 0) { > > + Status =3D NorFlashRead ( > > + Instance, > > + Instance->StartLba + Lba, > > + Offset, > > + *NumBytes, > > + Buffer > > + ); > > + } else { > > + // Read NOR Flash data into shadow buffer > > + Status =3D NorFlashReadBlocks ( > > + Instance, > > + Instance->StartLba + Lba, > > + BlockSize, > > + Buffer > > + ); > > + } > > + > > + if (EFI_ERROR (Status)) { > > + // Return one of the pre-approved error statuses > > + return EFI_DEVICE_ERROR; > > + } > > + > > + return EFI_SUCCESS; > > +} > > + > > +/** > > + Writes the specified number of bytes from the input buffer to the block= . > > + > > + @param[in] This EFI_FIRMWARE_VOLUME_BLOCK2_PROTO= COL instance. > > + > > + @param[in] Lba The starting logical block index= to write to. > > + > > + @param[in] Offset Offset into the block at which t= o begin writing. > > + > > + @param[in, out] NumBytes The pointer to a UINTN. > > + At entry, *NumBytes contains the= total size of the > > + buffer. > > + At exit, *NumBytes contains the = total number of > > + bytes actually written. > > + > > + @param[in] Buffer The pointer to a caller-allocate= d buffer that > > + contains the source for the writ= e. > > + > > + @retval EFI_SUCCESS The firmware volume was written = successfully. > > + > > +**/ > > +EFI_STATUS > > +EFIAPI > > +FvbWrite ( > > + IN CONST EFI_FIRMWARE_VOLUME_BLOCK2_PROTOCOL *This, > > + IN EFI_LBA Lba, > > + IN UINTN Offset, > > + IN OUT UINTN *NumBytes, > > + IN UINT8 *Buffer > > + ) > > +{ > > + NOR_FLASH_INSTANCE *Instance; > > + > > + Instance =3D INSTANCE_FROM_FVB_THIS (This); > > + > > + return NorFlashWriteSingleBlock ( > > + Instance, > > + Instance->StartLba + Lba, > > + Offset, > > + NumBytes, > > + Buffer > > + ); > > +} > > + > > +/** > > + Erases and initialises a firmware volume block. > > + > > + @param[in] This EFI_FIRMWARE_VOLUME_BLOCK2_PROTOC= OL > > + > > + @param[in] ... The variable argument list is a l= ist of tuples. > > + Each tuple describes a range of L= BAs to erase > > + and consists of the following: > > + - An EFI_LBA that indicates the s= tarting LBA > > + - A UINTN that indicates the numb= er of blocks > > + to erase. > > + > > + The list is terminated with an > > + EFI_LBA_LIST_TERMINATOR. > > + > > + @retval EFI_SUCCESS The erase request successfully co= mpleted. > > + > > + @retval EFI_ACCESS_DENIED The firmware volume is in the Wri= teDisabled > > + state. > > + > > + @retval EFI_DEVICE_ERROR The block device is not functioni= ng correctly > > + and could not be written. > > + The firmware device may have been= partially > > + erased. > > + > > + @retval EFI_INVALID_PARAMETER One or more of the LBAs listed in = the variable > > + argument list do not exist in the = firmware > > + volume. > > + > > +**/ > > +EFI_STATUS > > +EFIAPI > > +FvbEraseBlocks ( > > + IN CONST EFI_FIRMWARE_VOLUME_BLOCK2_PROTOCOL *This, > > + ... > > + ) > > +{ > > + EFI_STATUS Status; > > + VA_LIST Args; > > + UINTN BlockAddress; // Physical address of Lba to erase > > + EFI_LBA StartingLba; // Lba from which we start erasing > > + UINTN NumOfLba; // Number of Lba blocks to erase > > + NOR_FLASH_INSTANCE *Instance; > > + > > + Instance =3D INSTANCE_FROM_FVB_THIS (This); > > + > > + DEBUG ((DEBUG_INFO, "FvbEraseBlocks()\n")); > > + > > + Status =3D EFI_SUCCESS; > > + > > + // Before erasing, check the entire list of parameters to ensure > > + // all specified blocks are valid > > + > > + VA_START (Args, This); > > + do { > > + // Get the Lba from which we start erasing > > + StartingLba =3D VA_ARG (Args, EFI_LBA); > > + > > + // Have we reached the end of the list? > > + if (StartingLba =3D=3D EFI_LBA_LIST_TERMINATOR) { > > + break; > > + } > > + > > + // How many Lba blocks are we requested to erase? > > + NumOfLba =3D VA_ARG (Args, UINT32); > > + > > + // All blocks must be within range > > + DEBUG (( > > + DEBUG_INFO, > > + "FvbEraseBlocks: Check if: ( StartingLba=3D%ld + NumOfLba=3D%d - 1= ) > LastBlock=3D%ld.\n", > > + Instance->StartLba + StartingLba, > > + NumOfLba, > > + Instance->LastBlock > > + )); > > + if ((NumOfLba =3D=3D 0) || > > + ((Instance->StartLba + StartingLba + NumOfLba - 1) > > > + Instance->LastBlock)) > > + { > > + VA_END (Args); > > + DEBUG (( > > + DEBUG_ERROR, > > + "FvbEraseBlocks: ERROR - Lba range goes past the last Lba.\n" > > + )); > > + return EFI_INVALID_PARAMETER; > > + } > > + } while (TRUE); > > + > > + VA_END (Args); > > + > > + VA_START (Args, This); > > + do { > > + // Get the Lba from which we start erasing > > + StartingLba =3D VA_ARG (Args, EFI_LBA); > > + > > + // Have we reached the end of the list? > > + if (StartingLba =3D=3D EFI_LBA_LIST_TERMINATOR) { > > + // Exit the while loop > > + break; > > + } > > + > > + // How many Lba blocks are we requested to erase? > > + NumOfLba =3D VA_ARG (Args, UINT32); > > + > > + // Go through each one and erase it > > + while (NumOfLba > 0) { > > + // Get the physical address of Lba to erase > > + BlockAddress =3D GET_NOR_BLOCK_ADDRESS ( > > + Instance->RegionBaseAddress, > > + Instance->StartLba + StartingLba, > > + Instance->BlockSize > > + ); > > + > > + // Erase it > > + DEBUG (( > > + DEBUG_INFO, > > + "FvbEraseBlocks: Erasing Lba=3D%ld @ 0x%08x.\n", > > + Instance->StartLba + StartingLba, > > + BlockAddress > > + )); > > + Status =3D NorFlashUnlockAndEraseSingleBlock (Instance, BlockAddre= ss); > > + if (EFI_ERROR (Status)) { > > + VA_END (Args); > > + return EFI_DEVICE_ERROR; > > + } > > + > > + // Move to the next Lba > > + StartingLba++; > > + NumOfLba--; > > + } > > + } while (TRUE); > > + > > + VA_END (Args); > > + > > + return Status; > > +} > -=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 (#112644): https://edk2.groups.io/g/devel/message/112644 Mute This Topic: https://groups.io/mt/102625036/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-