From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received-SPF: Pass (sender SPF authorized) identity=mailfrom; client-ip=104.47.34.60; helo=nam01-by2-obe.outbound.protection.outlook.com; envelope-from=vabhav.sharma@nxp.com; receiver=edk2-devel@lists.01.org Received: from NAM01-BY2-obe.outbound.protection.outlook.com (mail-by2nam01on0060.outbound.protection.outlook.com [104.47.34.60]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-SHA384 (256/256 bits)) (No client certificate requested) by ml01.01.org (Postfix) with ESMTPS id A4106222447B7 for ; Tue, 19 Dec 2017 20:37:20 -0800 (PST) Received: from BN6PR03CA0052.namprd03.prod.outlook.com (10.173.137.14) by CY4PR03MB2693.namprd03.prod.outlook.com (10.173.43.136) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384_P256) id 15.20.323.15; Wed, 20 Dec 2017 04:42:06 +0000 Received: from BL2FFO11FD044.protection.gbl (2a01:111:f400:7c09::189) by BN6PR03CA0052.outlook.office365.com (2603:10b6:404:4c::14) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384) id 15.20.345.14 via Frontend Transport; Wed, 20 Dec 2017 04:42:06 +0000 Authentication-Results: spf=fail (sender IP is 192.88.168.50) smtp.mailfrom=nxp.com; nxp.com; dkim=none (message not signed) header.d=none;nxp.com; dmarc=fail action=none header.from=nxp.com; Received-SPF: Fail (protection.outlook.com: domain of nxp.com does not designate 192.88.168.50 as permitted sender) receiver=protection.outlook.com; client-ip=192.88.168.50; helo=tx30smr01.am.freescale.net; Received: from tx30smr01.am.freescale.net (192.88.168.50) by BL2FFO11FD044.mail.protection.outlook.com (10.173.161.140) with Microsoft SMTP Server (version=TLS1_0, cipher=TLS_RSA_WITH_AES_256_CBC_SHA) id 15.20.302.6 via Frontend Transport; Wed, 20 Dec 2017 04:41:52 +0000 Received: from uefi-OptiPlex-790.ap.freescale.net ([10.232.132.56]) by tx30smr01.am.freescale.net (8.14.3/8.14.0) with ESMTP id vBK4fsdg019373; Tue, 19 Dec 2017 21:42:03 -0700 From: Vabhav To: , , , Date: Tue, 19 Dec 2017 22:10:10 +0530 Message-ID: <1513701611-19990-4-git-send-email-vabhav.sharma@nxp.com> X-Mailer: git-send-email 1.9.1 In-Reply-To: <1513701611-19990-1-git-send-email-vabhav.sharma@nxp.com> References: <1513701611-19990-1-git-send-email-vabhav.sharma@nxp.com> X-EOPAttributedMessage: 0 X-Matching-Connectors: 131582185131494685; (91ab9b29-cfa4-454e-5278-08d120cd25b8); () X-Forefront-Antispam-Report: CIP:192.88.168.50; IPV:NLI; CTRY:US; EFV:NLI; SFV:NSPM; SFS:(10009020)(336005)(7966004)(39380400002)(39860400002)(376002)(346002)(396003)(2980300002)(1110001)(1109001)(339900001)(199004)(189003)(2906002)(36756003)(50466002)(53946003)(47776003)(6306002)(2950100002)(6666003)(53936002)(16200700003)(48376002)(104016004)(53376002)(4326008)(8936002)(51416003)(8656006)(106466001)(105606002)(5660300001)(86362001)(97736004)(81166006)(8676002)(966005)(81156014)(2201001)(76176011)(498600001)(15188155005)(16799955002)(85426001)(77096006)(68736007)(316002)(305945005)(54906003)(110136005)(356003)(16586007)(59450400001)(50226002)(579004)(559001)(569006); DIR:OUT; SFP:1101; SCL:1; SRVR:CY4PR03MB2693; H:tx30smr01.am.freescale.net; FPR:; SPF:Fail; PTR:InfoDomainNonexistent; A:1; MX:1; LANG:en; X-Microsoft-Exchange-Diagnostics: 1; BL2FFO11FD044; 1:mpy5JmW889v4ij6B9OHmHgltaLGVSED9G3QCgs/5EVT10sWQsatMG7pZGzjak/+n82RA2t9xb5rtiiPc+1Bhf9/t61OytLTr79PG2+Uwq5zCbmHct+7CTW+7wew2EkKQ MIME-Version: 1.0 X-MS-PublicTrafficType: Email X-MS-Office365-Filtering-Correlation-Id: 9bc10c8d-1234-4878-4d1d-08d54763fdff X-Microsoft-Antispam: UriScan:; BCL:0; PCL:0; RULEID:(5600026)(4604075)(4534020)(4628075)(201703131517081)(2017052603307); SRVR:CY4PR03MB2693; X-Microsoft-Exchange-Diagnostics: 1; CY4PR03MB2693; 3:8tVM2CdbigoqRZH2gPo/BRbTHZQ0xJFJCdmzXqHqmOcU++16q5zJHE29ktaELHUi2UY1IACoQaweS/7UUkjClVPgj+yX5FuZA/wkIFXK1a2vAzOJTizxZBCIfDmslyuNJ85YQkmdKqtYmAA7KlcgVqAX2d/fSu2+OuJZ4HOLfafiaeVbuCsi9m7Jc0edTbpGt/oSljKJ/HKMuHYWQXjwBikfrJwxVlk0H9e1ous3Y/4j4RRW4Biq1FxbtPpd1cUS/jmBpPxPo2xLWgewEandnBvsp4cLd5J8/+pPlYfdgRAAInetY+8Syy0fm2UmeFF7QPXg8kd45iqcj6x+IvVhyrDud6tO4HtcCIz2rE2iBPY=; 25:FxFBsIdXYo+pYSpD5M6FkV6UxbnUPUOBjtH8F70HaYO8BDPkig0jBrYN6eZbg1iJ7VgMwC6l0MJ0F6W4B+afTi1Lj/r+K7YYUoQvF/kL3YbA/OFquDmScGeS4FK0JsXwQtzSBqEqyaL+sNl/d7px2QNI23A8EItxyfKSXE2UmP62v1GQ8nQ2Se6R1kyUEbSGHuwXWAewd2iJLnveyKeqrdQRwXHfbZ2oHQvxmxO4iN5xCKg9oM+R3MO/QhG9Jl24Sw6o/FIp/6uBNFOzdddlo6u2nwB3az4gb8v0eS8+ZqRr7iskkI0GraZnWawi6tgCwHah8b32YLOtssg3vmrvUg== X-MS-TrafficTypeDiagnostic: CY4PR03MB2693: X-Microsoft-Exchange-Diagnostics: 1; CY4PR03MB2693; 31:3mVMklEuXbjxIVtek3IT8fA0p0cHQOMtC2AJZJpfeM4G+b74rjZbtOEOn52iDpMfVLW8UsldRNw6NKdc6hDlRSAgQi08V3fyGi/dceOU57XYfUUA88CzU89tPjeAMzUeUMhDeadxk6VGvOhHDeL+nOFqDIyIjgfX+j0kHusA4aF8ukk3nv0wLAF7djl/vo38lK3PCFvnQI7kbi9G1dpZmMQsZEyIkqSmija74hny6wk=; 4:ayvFfCxZvH7pTlay3k1lTNfHhgEWWjlbVL+YUdB25kidxhZ9wRbKdYkwzrmzEMpisWnJt+6Q3tZGMa2fV2KWqjS4Y4g7Z2hdQJASjJ5vajHVIVSAIu8w8yknESSIJSDXw66Sk+PM9qKjccd3qoOT6HS1J7CxeYTiHKF12zUJaltVLxPEk+3Vw1BoNk22MB1EQ3bredyvseZvgJWG/8KFbMewEYKUxc9vRb8BldxxAPFRF5YGM1a7EtpdpSQZMf7oDW3kDMRHaCo0Zh5WgaDKVAbSA0wI/+YqaYwmBc8wzP8l1EPCx4m0bINwAYapTVYm4ecV+NS804i2ODPsQimtYO2rJEA7Hf2ffbt7dK0KXqc= X-Microsoft-Antispam-PRVS: X-Exchange-Antispam-Report-Test: UriScan:(185117386973197)(17755550239193); X-Exchange-Antispam-Report-CFA-Test: BCL:0; PCL:0; RULEID:(6095135)(2401047)(5005006)(8121501046)(10201501046)(3002001)(3231023)(93006095)(93001095)(6055026)(6096035)(20161123559100)(201703131430075)(201703131433075)(201703131441075)(201703131448075)(201703161259150)(20161123556025)(20161123565025)(20161123563025)(20161123561025)(201708071742011); SRVR:CY4PR03MB2693; BCL:0; PCL:0; RULEID:(100000803101)(100110400095)(400006); SRVR:CY4PR03MB2693; X-Forefront-PRVS: 0527DFA348 X-Microsoft-Exchange-Diagnostics: =?us-ascii?Q?1; CY4PR03MB2693; 23:EA6y9TEkJpxvzv/2ypG7pxOFAhOn7S42IMVxBQlaD?= =?us-ascii?Q?3bv9qN4wbIJGQ0U7iwDGvzZqYTCLSJQmS21t9AVVPv5kVCbEVp7KAOn2Jybw?= =?us-ascii?Q?G+OQ+w5c0Q2pNpcscgjWV07bn4sw2c+wyINvR/4DtmWKS0RefkzvWIAhlpXS?= =?us-ascii?Q?T5jANsG4X/CyUZ+7AYgi1EEFoUupHm8LCNqNLi18ZMKje3+shMDl5V/E2kYq?= =?us-ascii?Q?ALtz8KjXYllfWBm43lD2nPXhVcK3a8zOY6t72dNbw9U10vfLgf96FRt3x2Q9?= =?us-ascii?Q?o0eeRJgYV1SypqAKVizpDGqalBOkIdEXSPe60VuKoIzis62QUAPPRHMVdinR?= =?us-ascii?Q?ohvCIuV13JmCPlPX6T1iK8Ui+vgLoT2XrJHNLZdQZTuWhb0cLnXkrC2ZZ3VE?= =?us-ascii?Q?z/EW06rTIqp21xr4a/32aDZ/pTb45Ra4B+mL82KkFK9803+FlaKfxoMCMbJi?= =?us-ascii?Q?OVzE3ruScGfQPpF5fc4F+9bOHhotjzgxgAKdoC1pyLJladVrRBdSWHblSU3n?= =?us-ascii?Q?qh4KN/IDUdRp4QNx67AxPIxzozhnuorkIYfMvHkO2cuEJgjOwGPkZ+PtRGKG?= =?us-ascii?Q?E/ImExtJ0/5YyWxAGuH4laX8qcBNwI0xHDtJIYvgwFL+b2lAZoT1XM9oIIxx?= =?us-ascii?Q?+id3xiDBTv+wyttv7r9OKSz0Xpv46KHzrKrouNERvwXuaCRmvXEuF5FncoL2?= =?us-ascii?Q?i3Chh4UkA58fyZkUy62dJC7K4P8ufbMBPKAv2Y2hDZh6+aEu2zlGrBOdOScI?= =?us-ascii?Q?pFDsBZDhUX2EUW1h5t2mdGA2V9zsFqRKAXa+nDi2FsiPdA+jnrvxyWuR18TH?= =?us-ascii?Q?A6qyx6fCbZEH+NCZ+aIJ3wLaOKfFLH0WI6YYH1CeBFFgVhBeJHKDao3MY3yu?= =?us-ascii?Q?K4WUnXJWbsecWY54JrQ3zOI5qzIzihsCSLDDVoRx6gLo+KSyiAljsAoIII+/?= =?us-ascii?Q?Juxa9s6csj1kZV+LV7/bpZUsLHCqIzedfpoJwRrW/REBY7VdXimps9XQPVEe?= =?us-ascii?Q?pJwb0FpTqn8+kOnUhOHVTDFMpirB12OSEKVwgM8PX818V69fHxtkrCg9BWpC?= =?us-ascii?Q?4Xc5FX7AxOk2v1rCCxd/AE2dNXtx4m3ofOfJwuLA56gVtvrs7NY9LfUc3j9m?= =?us-ascii?Q?TjyxfMtHB8e7tcQRu8ZWtJ1x12RFQMEygyo+Brev/RpoVcBJ1q4NsVjPsFCN?= =?us-ascii?Q?JeYkSb2jlsoK9OIAaOXXcYlEyJZptivJX8HvkYN5ERe77SgMoZPoxXEX+P3+?= =?us-ascii?Q?/lD+2L6vEP6q8BzLiXMzkn1F5Kq0AUm+oySLiNIj2AOYsYhkdk+ac9XDyai0?= =?us-ascii?Q?9ttFVhygk5CPxzJmRVoXXHvnIs4ANV7ztQuR23YdcqV?= X-Microsoft-Exchange-Diagnostics: 1; CY4PR03MB2693; 6:WN6imwty5Azlbn/Oe6HbTUL3neeuVORuDbalHO0zyNKvMh7DPkiyBUJgYQkoZuFjFpw2Xv2pV/fjIHs5y3ZNjmRhOxsxw/CY9GTNc70GRErCUrZMQN7F+kr7wcOOEyO+VqN2JyXj0fVkpJ14JcPpg+K8RtEaHPLtKpCfE2RKTJgKTpb6Ih7Fb1Pwer67k3rvCObbiPlraljGLEPSwmibazpbLhYarCVZPJwtzu3bO50XhiZ2KbkzJihOKI6yU/YadzuKasZKfOrI2EdYET/tKkMyVIIceXMWUDn0+qs6EwhZMYIdy7LRpzE9R7vleKQqOAuVrk4G6BgELvi8+UDC18x1DMnOViPUk9Z/LOG0/YU=; 5:FzU9luhmpmzsrPgrMFTY7K/bo3RZoNb4BzjYfju+EHpW5q2wAZqj1OxOt+/QPvl/XkqhPQNPpURPHPFrz3JQFrXXTe9NwS4613WNrJvCEb2JQ4EO3PqPXW2IwkorUyNpUHIOyocNReSDF+hjq3bbhB/Mu1Z/32iWKCTaz+BbHzs=; 24:YdxpRbaaMbRGRGIxc95uPQvyF3tor7VncmBtipNQgnan/Dz76BKjbcJws8AgWQX29C1xs+BWedZni8Am+etThVn/P6taEgrt3/bEWu2GJXM=; 7:KInGeuZ8jwa1g75S4ilts3Dd6/St5qtrIiPJZIPgSKaEJ+47Y4d5L3q9wLtO7d+/dqN7/DJ0rXnRKkRuZFABFoGIy8/Fsnu+0F+FqnlrMr5Qnv9rPebQwRpz5QtKV6DYhevEryRtjY3AHcuh79EHDY9H1QI4FDkamNJY26LzcZ7PYpv9hUIdZE5reE98By1yHTTHe9OcTVPbbW6QRLhsi9hGN7cacqDGscJZQV7m2DEyqZ1l5EXmSZFkBbD9pDEi SpamDiagnosticOutput: 1:99 SpamDiagnosticMetadata: NSPM X-MS-Exchange-CrossTenant-OriginalArrivalTime: 20 Dec 2017 04:41:52.9934 (UTC) X-MS-Exchange-CrossTenant-Network-Message-Id: 9bc10c8d-1234-4878-4d1d-08d54763fdff X-MS-Exchange-CrossTenant-Id: 5afe0b00-7697-4969-b663-5eab37d5f47e X-MS-Exchange-CrossTenant-OriginalAttributedTenantConnectingIp: TenantId=5afe0b00-7697-4969-b663-5eab37d5f47e; Ip=[192.88.168.50]; Helo=[tx30smr01.am.freescale.net] X-MS-Exchange-CrossTenant-FromEntityHeader: HybridOnPrem X-MS-Exchange-Transport-CrossTenantHeadersStamped: CY4PR03MB2693 Subject: [PATCH edk2-platforms v2 3/4] Platform/NXP : Add Support for NOR Flash driver X-BeenThere: edk2-devel@lists.01.org X-Mailman-Version: 2.1.23 Precedence: list List-Id: EDK II Development List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Wed, 20 Dec 2017 04:37:21 -0000 Content-Type: text/plain Adding support for NOR flash Driver Contributed-under: TianoCore Contribution Agreement 1.1 Signed-off-by: Vabhav --- .../NXP/Drivers/NorFlashDxe/NorFlashBlockIoDxe.c | 254 +++++++ Platform/NXP/Drivers/NorFlashDxe/NorFlashDxe.c | 444 +++++++++++ Platform/NXP/Drivers/NorFlashDxe/NorFlashDxe.inf | 65 ++ Platform/NXP/Drivers/NorFlashDxe/NorFlashFvbDxe.c | 814 +++++++++++++++++++++ Platform/NXP/Include/Library/NorFlash.h | 222 ++++++ Silicon/NXP/Chassis/Chassis.c | 15 + Silicon/NXP/Chassis/Chassis.h | 7 + Silicon/NXP/Chassis/Chassis2/Soc.c | 1 + Silicon/NXP/Chassis/LS1043aSocLib.inf | 2 + 9 files changed, 1824 insertions(+) create mode 100644 Platform/NXP/Drivers/NorFlashDxe/NorFlashBlockIoDxe.c create mode 100644 Platform/NXP/Drivers/NorFlashDxe/NorFlashDxe.c create mode 100755 Platform/NXP/Drivers/NorFlashDxe/NorFlashDxe.inf create mode 100644 Platform/NXP/Drivers/NorFlashDxe/NorFlashFvbDxe.c create mode 100644 Platform/NXP/Include/Library/NorFlash.h diff --git a/Platform/NXP/Drivers/NorFlashDxe/NorFlashBlockIoDxe.c b/Platform/NXP/Drivers/NorFlashDxe/NorFlashBlockIoDxe.c new file mode 100644 index 0000000..bad397f --- /dev/null +++ b/Platform/NXP/Drivers/NorFlashDxe/NorFlashBlockIoDxe.c @@ -0,0 +1,254 @@ +/** @NorFlashBlockIoDxe.c + + Based on NorFlash implementation available in ArmPlatformPkg/Drivers/NorFlashDxe/NorFlashBlockIoDxe.c + + Copyright (c) 2011 - 2014, ARM Ltd. All rights reserved. + Copyright 2017 NXP + + This program and the accompanying materials + are licensed and made available under the terms and conditions of the BSD License + which accompanies this distribution. The full text of the license may be found at + http://opensource.org/licenses/bsd-license.php + + THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, + WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +**/ + +#include +#include + +// +// BlockIO Protocol function EFI_BLOCK_IO_PROTOCOL.Reset +// +EFI_STATUS +EFIAPI +NorFlashBlockIoReset ( + IN EFI_BLOCK_IO_PROTOCOL *This, + IN BOOLEAN ExtendedVerification + ) +{ + NOR_FLASH_INSTANCE *Instance; + + Instance = INSTANCE_FROM_BLKIO_THIS (This); + + DEBUG ((DEBUG_INFO, "NorFlashBlockIoReset (MediaId=0x%x)\n", + This->Media->MediaId)); + + return NorFlashPlatformReset (Instance->DeviceBaseAddress); +} + +// +// BlockIO Protocol function EFI_BLOCK_IO_PROTOCOL.ReadBlocks +// +EFI_STATUS +EFIAPI +NorFlashBlockIoReadBlocks ( + IN EFI_BLOCK_IO_PROTOCOL *This, + IN UINT32 MediaId, + IN EFI_LBA Lba, + IN UINTN BufferSizeInBytes, + OUT VOID *Buffer + ) +{ + NOR_FLASH_INSTANCE *Instance; + EFI_STATUS Status; + EFI_BLOCK_IO_MEDIA *Media; + UINTN NumBlocks; + UINT8 *pReadBuffer; + UINTN BlockCount; + UINTN BlockSizeInBytes; + EFI_LBA CurrentBlock; + + Status = EFI_SUCCESS; + + if ((This == NULL) || (Buffer == NULL)) { + return EFI_INVALID_PARAMETER; + } + + Instance = INSTANCE_FROM_BLKIO_THIS (This); + Media = This->Media; + + if (Media == NULL) { + DEBUG ((DEBUG_ERROR, "%a : Media is NULL\n", __FUNCTION__)); + return EFI_INVALID_PARAMETER; + } + + NumBlocks = ((UINTN)BufferSizeInBytes) / Instance->Media.BlockSize ; + + DEBUG ((DEBUG_BLKIO, "%a : (MediaId=0x%x, Lba=%ld, " + "BufferSize=0x%x bytes (%d kB)" + ", BufferPtr @ 0x%p)\n", + __FUNCTION__,MediaId, Lba, + BufferSizeInBytes, Buffer)); + + if (!Media) { + Status = EFI_INVALID_PARAMETER; + } + else if (!Media->MediaPresent) { + Status = EFI_NO_MEDIA; + } + else if (Media->MediaId != MediaId) { + Status = EFI_MEDIA_CHANGED; + } + else if ((Media->IoAlign >= 2) && + (((UINTN)Buffer & (Media->IoAlign - 1)) != 0)) { + Status = EFI_INVALID_PARAMETER; + } + else if (BufferSizeInBytes == 0) { + // Return if we have not any byte to read + Status = EFI_SUCCESS; + } + else if ((BufferSizeInBytes % Media->BlockSize) != 0) { + // The size of the buffer must be a multiple of the block size + DEBUG ((DEBUG_ERROR, "%a : BlockSize in bytes = 0x%x\n",__FUNCTION__, + BufferSizeInBytes)); + Status = EFI_INVALID_PARAMETER; + } else if ((Lba + NumBlocks - 1) > Media->LastBlock) { + // All blocks must be within the device + DEBUG ((DEBUG_ERROR, "%a : Read will exceed last block %d, %d, %d \n", + __FUNCTION__, Lba, NumBlocks, Media->LastBlock)); + Status = EFI_INVALID_PARAMETER; + } else { + BlockSizeInBytes = Instance->Media.BlockSize; + + /* 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 *pReadBuffer */ + pReadBuffer = (UINT8 *)Buffer; + + CurrentBlock = Lba; + // Read data block by Block + for (BlockCount = 0; BlockCount < NumBlocks; BlockCount++, CurrentBlock++, + pReadBuffer = pReadBuffer + BlockSizeInBytes) { + DEBUG ((DEBUG_BLKIO, "%a: Reading block #%d\n", + __FUNCTION__,(UINTN)CurrentBlock)); + + Status = NorFlashPlatformRead (Instance, CurrentBlock, (UINTN)0 , + BlockSizeInBytes,pReadBuffer); + if (EFI_ERROR (Status)) { + break; + } + } + } + DEBUG ((DEBUG_BLKIO,"%a: Exit Status = \"%r\".\n",__FUNCTION__,Status)); + + return Status; +} + +// +// BlockIO Protocol function EFI_BLOCK_IO_PROTOCOL.WriteBlocks +// +EFI_STATUS +EFIAPI +NorFlashBlockIoWriteBlocks ( + IN EFI_BLOCK_IO_PROTOCOL *This, + IN UINT32 MediaId, + IN EFI_LBA Lba, + IN UINTN BufferSizeInBytes, + IN VOID *Buffer + ) +{ + NOR_FLASH_INSTANCE *Instance; + EFI_STATUS Status; + EFI_BLOCK_IO_MEDIA *Media; + UINTN NumBlocks; + EFI_LBA CurrentBlock; + UINTN BlockSizeInBytes; + UINT32 BlockCount; + UINTN SectorAddress; + UINT8 *pWriteBuffer; + + Status = EFI_SUCCESS; + + if ((This == NULL) || (Buffer == NULL)) { + return EFI_INVALID_PARAMETER; + } + + Instance = INSTANCE_FROM_BLKIO_THIS (This); + Media = This->Media; + + if (Media == NULL) { + DEBUG ((DEBUG_ERROR, "%a : Media is NULL\n", __FUNCTION__)); + return EFI_INVALID_PARAMETER; + } + + NumBlocks = ((UINTN)BufferSizeInBytes) / Instance->Media.BlockSize ; + + DEBUG ((DEBUG_BLKIO, "%a : (MediaId=0x%x, Lba=%ld, BufferSize=0x%x " + "bytes (%d kB) BufferPtr @ 0x%08x)\n", + __FUNCTION__,MediaId, Lba,BufferSizeInBytes, Buffer)); + + if (!Media->MediaPresent) { + Status = EFI_NO_MEDIA; + } + else if (Media->MediaId != MediaId) { + Status = EFI_MEDIA_CHANGED; + } + else if (Media->ReadOnly) { + Status = EFI_WRITE_PROTECTED; + } + else if (BufferSizeInBytes == 0) { + Status = EFI_BAD_BUFFER_SIZE; + } + else if ((BufferSizeInBytes % Media->BlockSize) != 0) { + // The size of the buffer must be a multiple of the block size + DEBUG ((DEBUG_ERROR, "%a : BlockSize in bytes = 0x%x\n",__FUNCTION__, + BufferSizeInBytes)); + Status = EFI_INVALID_PARAMETER; + } else if ((Lba + NumBlocks - 1) > Media->LastBlock) { + // All blocks must be within the device + DEBUG ((DEBUG_ERROR, "%a: Write will exceed last block %d, %d, %d \n", + __FUNCTION__,Lba, NumBlocks, Media->LastBlock)); + Status = EFI_INVALID_PARAMETER; + } else { + BlockSizeInBytes = Instance->Media.BlockSize; + + pWriteBuffer = (UINT8 *)Buffer; + + CurrentBlock = Lba; + // Program data block by Block + for (BlockCount = 0; BlockCount < NumBlocks; + BlockCount++, CurrentBlock++, + pWriteBuffer = (pWriteBuffer + BlockSizeInBytes)) { + DEBUG ((DEBUG_BLKIO, "%a: Writing block #%d\n", + __FUNCTION__,(UINTN)CurrentBlock)); + // Erase the Block(Sector) to be written to + SectorAddress = GET_NOR_BLOCK_ADDRESS ( + Instance->RegionBaseAddress, + CurrentBlock, + Instance->Media.BlockSize + ); + Status = NorFlashPlatformEraseSector (Instance, (UINTN)SectorAddress); + if (EFI_ERROR (Status)) { + DEBUG ((DEBUG_ERROR, "%a: Failed to erase Target 0x%x (0x%x) \n", + __FUNCTION__,SectorAddress, Status)); + break; + } + // Program Block(Sector) to be written to + Status = NorFlashWrite (Instance, CurrentBlock, (UINTN)0, + &BlockSizeInBytes, pWriteBuffer); + if (EFI_ERROR (Status)) { + break; + } + } + } + DEBUG ((DEBUG_BLKIO, "%a: Exit Status = \"%r\".\n",__FUNCTION__,Status)); + return Status; +} + +// +// BlockIO Protocol function EFI_BLOCK_IO_PROTOCOL.FlushBlocks +// +EFI_STATUS +EFIAPI +NorFlashBlockIoFlushBlocks ( + IN EFI_BLOCK_IO_PROTOCOL *This + ) +{ + + DEBUG ((DEBUG_BLKIO, "%a NOT IMPLEMENTED (not required)\n", __FUNCTION__)); + + // Nothing to do so just return without error + return EFI_SUCCESS; +} diff --git a/Platform/NXP/Drivers/NorFlashDxe/NorFlashDxe.c b/Platform/NXP/Drivers/NorFlashDxe/NorFlashDxe.c new file mode 100644 index 0000000..ca17001 --- /dev/null +++ b/Platform/NXP/Drivers/NorFlashDxe/NorFlashDxe.c @@ -0,0 +1,444 @@ +/** @file NorFlashDxe.c + + Based on NorFlash implementation available in ArmPlatformPkg/Drivers/NorFlashDxe/NorFlashDxe.c + + Copyright (c) 2011 - 2014, ARM Ltd. All rights reserved. + Copyright 2017 NXP + + This program and the accompanying materials + are licensed and made available under the terms and conditions of the BSD License + which accompanies this distribution. The full text of the license may be found at + http://opensource.org/licenses/bsd-license.php + + THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, + WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +**/ + +#include +#include +#include +#include + +STATIC EFI_EVENT mNorFlashVirtualAddrChangeEvent; + +// +// Global variable declarations +// +NOR_FLASH_INSTANCE **mNorFlashInstances; +UINT32 mNorFlashDeviceCount; + +NOR_FLASH_INSTANCE mNorFlashInstanceTemplate = { + .Signature = NOR_FLASH_SIGNATURE, + .Initialized = FALSE, + .Initialize = NULL, + .StartLba = 0, + .BlockIoProtocol = { + .Revision = EFI_BLOCK_IO_PROTOCOL_REVISION2, + .Reset = NorFlashBlockIoReset, + .ReadBlocks = NorFlashBlockIoReadBlocks, + .WriteBlocks = NorFlashBlockIoWriteBlocks, + .FlushBlocks = NorFlashBlockIoFlushBlocks, + }, + + .Media = { + .RemovableMedia = FALSE, + .MediaPresent = TRUE, + .LogicalPartition = FALSE, + .ReadOnly = FALSE, + .WriteCaching = FALSE, + .IoAlign = 4, + .LowestAlignedLba = 0, + .LogicalBlocksPerPhysicalBlock = 1, + }, + + .FvbProtocol = { + .GetAttributes = FvbGetAttributes, + .SetAttributes = FvbSetAttributes, + .GetPhysicalAddress = FvbGetPhysicalAddress, + .GetBlockSize = FvbGetBlockSize, + .Read = FvbRead, + .Write = FvbWrite, + .EraseBlocks = FvbEraseBlocks, + .ParentHandle = NULL, + }, + .ShadowBuffer = NULL, + .DevicePath = { + .Vendor = { + .Header = { + .Type = HARDWARE_DEVICE_PATH, + .SubType = HW_VENDOR_DP, + .Length = {(UINT8)sizeof (VENDOR_DEVICE_PATH), + (UINT8)((sizeof (VENDOR_DEVICE_PATH)) >> 8) } + }, + .Guid = EFI_CALLER_ID_GUID, // GUID ... NEED TO BE FILLED + }, + .End = { + .Type = END_DEVICE_PATH_TYPE, + .SubType = END_ENTIRE_DEVICE_PATH_SUBTYPE, + .Length = { sizeof (EFI_DEVICE_PATH_PROTOCOL), 0 } + } + } +}; + +EFI_STATUS +NorFlashCreateInstance ( + IN UINTN NorFlashDeviceBase, + IN UINTN NorFlashRegionBase, + IN UINTN NorFlashSize, + IN UINT32 MediaId, + IN UINT32 BlockSize, + IN BOOLEAN SupportFvb, + OUT NOR_FLASH_INSTANCE** NorFlashInstance + ) +{ + EFI_STATUS Status; + NOR_FLASH_INSTANCE* Instance; + + ASSERT(NorFlashInstance != NULL); + + Instance = AllocateRuntimeCopyPool (sizeof (NOR_FLASH_INSTANCE), + &mNorFlashInstanceTemplate); + if (Instance == NULL) { + return EFI_OUT_OF_RESOURCES; + } + + Instance->DeviceBaseAddress = NorFlashDeviceBase; + Instance->RegionBaseAddress = NorFlashRegionBase; + Instance->Size = NorFlashSize; + + Instance->BlockIoProtocol.Media = &Instance->Media; + Instance->Media.MediaId = MediaId; + Instance->Media.BlockSize = BlockSize; + Instance->Media.LastBlock = (NorFlashSize / BlockSize)-1; + + Instance->ShadowBuffer = AllocateRuntimePool (BlockSize); + if (Instance->ShadowBuffer == NULL) { + FreePool (Instance); + return EFI_OUT_OF_RESOURCES; + } + + if (SupportFvb) { + Instance->SupportFvb = TRUE; + Instance->Initialize = NorFlashFvbInitialize; + + Status = gBS->InstallMultipleProtocolInterfaces ( + &Instance->Handle, + &gEfiDevicePathProtocolGuid, &Instance->DevicePath, + &gEfiBlockIoProtocolGuid, &Instance->BlockIoProtocol, + &gEfiFirmwareVolumeBlockProtocolGuid, &Instance->FvbProtocol, + NULL + ); + if (EFI_ERROR (Status)) { + FreePool (Instance->ShadowBuffer); + FreePool (Instance); + return Status; + } + } else { + Instance->Initialized = TRUE; + + Status = gBS->InstallMultipleProtocolInterfaces ( + &Instance->Handle, + &gEfiDevicePathProtocolGuid, &Instance->DevicePath, + &gEfiBlockIoProtocolGuid, &Instance->BlockIoProtocol, + NULL + ); + if (EFI_ERROR (Status)) { + FreePool (Instance->ShadowBuffer); + FreePool (Instance); + return Status; + } + } + + *NorFlashInstance = Instance; + + return Status; +} + +/* + Write a full or portion of a block. + It must not span block boundaries; that is, + Offset + NumBytes <= Instance->Media.BlockSize. + */ +EFI_STATUS +NorFlashWrite ( + IN NOR_FLASH_INSTANCE *Instance, + IN EFI_LBA Lba, + IN UINTN Offset, + IN OUT UINTN *NumBytes, + IN UINT8 *Buffer +) +{ + EFI_STATUS Status; + UINTN BlockSize; + BOOLEAN DoErase; + VOID *Source; + UINTN SectorAddress; + + Status = EFI_SUCCESS; + Source = NULL; + + DEBUG ((DEBUG_BLKIO, "%a(Parameters: Lba=%ld, Offset=0x%x, NumBytes=0x%x, " + "Buffer @ 0x%08x)\n", __FUNCTION__, + Lba, Offset, *NumBytes, Buffer)); + + // The buffer must be valid + if (Buffer == NULL) { + return EFI_INVALID_PARAMETER; + } + + // Detect WriteDisabled state + if (Instance->Media.ReadOnly == TRUE) { + DEBUG ((DEBUG_ERROR, "NorFlashWrite: ERROR - Can not write: " + "Device is in WriteDisabled state.\n")); + // It is in WriteDisabled state, return an error right away + return EFI_ACCESS_DENIED; + } + + // Cache the block size to avoid de-referencing pointers all the time + BlockSize = Instance->Media.BlockSize; + + // We must have some bytes to write + if ((*NumBytes == 0) || (*NumBytes > BlockSize)) { + DEBUG ((DEBUG_ERROR, "NorFlashWrite: ERROR - EFI_BAD_BUFFER_SIZE: " + "(Offset=0x%x + NumBytes=0x%x) > BlockSize=0x%x\n", \ + Offset, *NumBytes, BlockSize )); + return EFI_BAD_BUFFER_SIZE; + } + + if (((Lba * BlockSize) + Offset + *NumBytes) > Instance->Size) { + DEBUG ((DEBUG_ERROR, "%a: ERROR - Write will exceed device size.\n", + __FUNCTION__)); + return EFI_INVALID_PARAMETER; + } + + // Check we did get some memory. Buffer is BlockSize. + if (Instance->ShadowBuffer == NULL) { + DEBUG ((DEBUG_ERROR, "FvbWrite: ERROR - Buffer not ready\n")); + return EFI_DEVICE_ERROR; + } + + SectorAddress = GET_NOR_BLOCK_ADDRESS ( + Instance->RegionBaseAddress, + Lba, + Instance->Media.BlockSize + ); + + // Pick 128bytes as a good start for word operations as opposed to erasing the + // block and writing the data regardless if an erase is really needed. + // It looks like most individual NV variable writes are smaller than 128bytes. + if (*NumBytes <= 128) { + Source = Instance->ShadowBuffer; + //First Read the data into shadow buffer from location where data is to be written + Status = NorFlashPlatformRead ( + Instance, + Lba, + Offset, + *NumBytes, + Source + ); + if (EFI_ERROR (Status)) { + DEBUG ((DEBUG_ERROR, "%a: ERROR - Failed to " + "Read @ %p Status=%d\n", __FUNCTION__, + Offset + SectorAddress, Status)); + return Status; + } + // Check to see if we need to erase before programming the data into NorFlash. + // If the destination bits are only changing from 1s to 0s we can + // just 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 = TestBitSetClear (Source, Buffer, *NumBytes, TRUE); + + // if we got here then write all the data. Otherwise do the + // Erase-Write cycle. + if (!DoErase) { + Status = NorFlashPlatformWriteBuffer ( + Instance, + Lba, + Offset, + NumBytes, + Buffer + ); + if (EFI_ERROR (Status)) { + DEBUG ((DEBUG_ERROR, "%a: ERROR - Failed to " + "Write @ %p Status=%d\n", __FUNCTION__, + Offset + SectorAddress, Status)); + return Status; + } + return EFI_SUCCESS; + } + } + + // If we are not going to write full block, read block and then update bytes in it + if (*NumBytes != BlockSize) { + // Read NorFlash Flash data into shadow buffer + Status = NorFlashBlockIoReadBlocks ( + &(Instance->BlockIoProtocol), + Instance->Media.MediaId, + 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, *NumBytes); + } + //Erase Block + Status = NorFlashPlatformEraseSector (Instance, SectorAddress); + if (EFI_ERROR (Status)) { + // Return one of the pre-approved error statuses + return EFI_DEVICE_ERROR; + } + if (*NumBytes != BlockSize) { + // Write the modified shadow buffer back to the NorFlash + Status = NorFlashPlatformWriteBuffer ( + Instance, + Lba, + 0, + &BlockSize, + Instance->ShadowBuffer + ); + } else { + // Write the Buffer to an entire block in NorFlash + Status = NorFlashPlatformWriteBuffer ( + Instance, + Lba, + 0, + &BlockSize, + Buffer + ); + } + if (EFI_ERROR (Status)) { + // Return one of the pre-approved error statuses + return EFI_DEVICE_ERROR; + } + + return EFI_SUCCESS; +} + +/** + Fixup internal data so that EFI can be call in virtual mode. + Call the passed in Child Notify event and convert any pointers in + lib to virtual mode. + + @param[in] Event The Event that is being processed + @param[in] Context Event Context +**/ +VOID +EFIAPI +NorFlashVirtualNotifyEvent ( + IN EFI_EVENT Event, + IN VOID *Context + ) +{ + UINTN Index; + + for (Index = 0; Index < mNorFlashDeviceCount; Index++) { + EfiConvertPointer (0x0, (VOID**)&mNorFlashInstances[Index]->DeviceBaseAddress); + EfiConvertPointer (0x0, (VOID**)&mNorFlashInstances[Index]->RegionBaseAddress); + + // Convert BlockIo protocol + EfiConvertPointer (0x0, (VOID**)&mNorFlashInstances[Index]->BlockIoProtocol.FlushBlocks); + EfiConvertPointer (0x0, (VOID**)&mNorFlashInstances[Index]->BlockIoProtocol.ReadBlocks); + EfiConvertPointer (0x0, (VOID**)&mNorFlashInstances[Index]->BlockIoProtocol.Reset); + EfiConvertPointer (0x0, (VOID**)&mNorFlashInstances[Index]->BlockIoProtocol.WriteBlocks); + + // 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.GetPhysicalAddress); + 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 != NULL) { + EfiConvertPointer (0x0, (VOID **)&mNorFlashInstances[Index]->ShadowBuffer); + } + } + + return; +} + +EFI_STATUS +EFIAPI +NorFlashInitialise ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ) +{ + EFI_STATUS Status; + UINT32 Index; + NorFlashDescription* NorFlashDevices; + BOOLEAN ContainVariableStorage; + + ContainVariableStorage = 0; + + Status = NorFlashPlatformGetDevices (&NorFlashDevices, &mNorFlashDeviceCount); + if (EFI_ERROR(Status)) { + DEBUG((DEBUG_ERROR,"%a : Failed to get Nor devices (0x%x)\n", + __FUNCTION__, Status)); + return Status; + } + + Status = NorFlashPlatformFlashGetAttributes (NorFlashDevices, + mNorFlashDeviceCount); + if (EFI_ERROR(Status)) { + DEBUG ((DEBUG_ERROR,"%a : Failed to get NOR device attributes (0x%x)\n", + __FUNCTION__, Status)); + ASSERT_EFI_ERROR (Status); /* System becomes unusable if NOR flash is not detected */ + return Status; + } + + mNorFlashInstances = AllocateRuntimePool ( + sizeof(NOR_FLASH_INSTANCE*) * mNorFlashDeviceCount); + if (mNorFlashInstances == NULL) { + DEBUG ((DEBUG_ERROR,"%a : Failed to allocate runtime memory \n")); + return EFI_OUT_OF_RESOURCES; + } + + for (Index = 0; Index < mNorFlashDeviceCount; Index++) { + // Check if this NOR Flash device contain the variable storage region + ContainVariableStorage = + (NorFlashDevices[Index].RegionBaseAddress <= PcdGet64 (PcdFlashNvStorageVariableBase64)) && + (PcdGet64 (PcdFlashNvStorageVariableBase64) + PcdGet32 (PcdFlashNvStorageVariableSize) <= + NorFlashDevices[Index].RegionBaseAddress + NorFlashDevices[Index].Size); + + Status = NorFlashCreateInstance ( + NorFlashDevices[Index].DeviceBaseAddress, + NorFlashDevices[Index].RegionBaseAddress, + NorFlashDevices[Index].Size, + Index, + NorFlashDevices[Index].BlockSize, + ContainVariableStorage, + &mNorFlashInstances[Index] + ); + + if (EFI_ERROR (Status)) { + DEBUG ((DEBUG_ERROR,"%a : Failed to create instance for " + "NorFlash[%d] (0x%x)\n",Index, Status)); + } + + } + + // + // Register for the virtual address change event + // + Status = gBS->CreateEventEx ( + EVT_NOTIFY_SIGNAL, + TPL_NOTIFY, + NorFlashVirtualNotifyEvent, + NULL, + &gEfiEventVirtualAddressChangeGuid, + &mNorFlashVirtualAddrChangeEvent + ); + + if (EFI_ERROR (Status)) { + DEBUG ((DEBUG_ERROR,"Failed to create VirtualAddressChange event 0x%x\n", + Status)); + } + + return Status; +} diff --git a/Platform/NXP/Drivers/NorFlashDxe/NorFlashDxe.inf b/Platform/NXP/Drivers/NorFlashDxe/NorFlashDxe.inf new file mode 100755 index 0000000..2da8a51 --- /dev/null +++ b/Platform/NXP/Drivers/NorFlashDxe/NorFlashDxe.inf @@ -0,0 +1,65 @@ +#/** @file +# +# Component description file for NorFlashDxe module +# +# Copyright 2017 NXP +# +# This program and the accompanying materials +# are licensed and made available under the terms and conditions of the BSD License +# which accompanies this distribution. The full text of the license may be found at +# http://opensource.org/licenses/bsd-license.php +# +# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. +# +#**/ + +[Defines] + INF_VERSION = 0x0001001A + BASE_NAME = NorFlashDxe + FILE_GUID = 616fe8d8-f4aa-42e0-a393-b332bdb2d3c1 + MODULE_TYPE = DXE_RUNTIME_DRIVER + VERSION_STRING = 1.0 + ENTRY_POINT = NorFlashInitialise + +[Sources.common] + NorFlashDxe.c + NorFlashFvbDxe.c + NorFlashBlockIoDxe.c + +[Packages] + ArmPlatformPkg/ArmPlatformPkg.dec + Platform/NXP/NxpQoriqLs.dec + MdeModulePkg/MdeModulePkg.dec + MdePkg/MdePkg.dec + +[LibraryClasses] + DxeServicesTableLib + HobLib + NorFlashLib + UefiDriverEntryPoint + UefiRuntimeLib + +[Guids] + gEfiSystemNvDataFvGuid + gEfiVariableGuid + gEfiAuthenticatedVariableGuid + gEfiEventVirtualAddressChangeGuid + +[Protocols] + gEfiBlockIoProtocolGuid + gEfiFirmwareVolumeBlockProtocolGuid + +[Pcd.common] + gEfiMdeModulePkgTokenSpaceGuid.PcdFlashNvStorageVariableBase64 + gEfiMdeModulePkgTokenSpaceGuid.PcdFlashNvStorageVariableSize + gEfiMdeModulePkgTokenSpaceGuid.PcdFlashNvStorageFtwWorkingBase64 + gEfiMdeModulePkgTokenSpaceGuid.PcdFlashNvStorageFtwWorkingSize + gEfiMdeModulePkgTokenSpaceGuid.PcdFlashNvStorageFtwSpareBase64 + gEfiMdeModulePkgTokenSpaceGuid.PcdFlashNvStorageFtwSpareSize + +[Depex] + # + # NorFlashDxe must be loaded before VariableRuntimeDxe in case empty flash needs populating with default values + # + BEFORE gVariableRuntimeDxeFileGuid diff --git a/Platform/NXP/Drivers/NorFlashDxe/NorFlashFvbDxe.c b/Platform/NXP/Drivers/NorFlashDxe/NorFlashFvbDxe.c new file mode 100644 index 0000000..f74ffc9 --- /dev/null +++ b/Platform/NXP/Drivers/NorFlashDxe/NorFlashFvbDxe.c @@ -0,0 +1,814 @@ +/*@NorFlashFvbDxe.c + + Based on NorFlash implementation available in ArmPlatformPkg/Drivers/NorFlashDxe/NorFlashFvbDxe.c + + Copyright (c) 2011 - 2014, ARM Ltd. All rights reserved. + Copyright 2017 NXP + + This program and the accompanying materials + are licensed and made available under the terms and conditions of the BSD License + which accompanies this distribution. The full text of the license may be found at + http://opensource.org/licenses/bsd-license.php + + THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, + WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + + --*/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +STATIC EFI_EVENT mFvbVirtualAddrChangeEvent; +STATIC UINTN mFlashNvStorageVariableBase; + +/// +/// The Firmware Volume Block Protocol is the low-level interface +/// to a firmware volume. File-level access to a firmware volume +/// should not be done using the Firmware Volume Block Protocol. +/// Normal access to a firmware volume must use the Firmware +/// Volume Protocol. Typically, only the file system driver that +/// produces the Firmware Volume Protocol will bind to the +/// Firmware Volume Block Protocol. +/// + +/** + Initialises the FV Header and Variable Store Header + to support variable operations. + + @param[in] Ptr - Location to initialise the headers + +**/ +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 = sizeof (EFI_FIRMWARE_VOLUME_HEADER) + sizeof (EFI_FV_BLOCK_MAP_ENTRY) + sizeof (VARIABLE_STORE_HEADER); + Headers = AllocateZeroPool (HeadersLength); + if (Headers == NULL) { + DEBUG ((DEBUG_ERROR, "Memory allocation failed for Headers \n")); + return EFI_OUT_OF_RESOURCES; + } + + // FirmwareVolumeHeader->FvLength is declared to have the Variable area AND the FTW working area AND the FTW Spare contiguous. + ASSERT (PcdGet64 (PcdFlashNvStorageVariableBase64) + PcdGet32 (PcdFlashNvStorageVariableSize) == PcdGet64 (PcdFlashNvStorageFtwWorkingBase64)); + ASSERT (PcdGet64 (PcdFlashNvStorageFtwWorkingBase64) + PcdGet32 (PcdFlashNvStorageFtwWorkingSize) == PcdGet64 (PcdFlashNvStorageFtwSpareBase64)); + + // Check if the size of the area is at least one block size + ASSERT ((PcdGet32 (PcdFlashNvStorageVariableSize) > 0) && (PcdGet32 (PcdFlashNvStorageVariableSize) / Instance->Media.BlockSize > 0)); + ASSERT ((PcdGet32 (PcdFlashNvStorageFtwWorkingSize) > 0) && (PcdGet32 (PcdFlashNvStorageFtwWorkingSize) / Instance->Media.BlockSize > 0)); + ASSERT ((PcdGet32 (PcdFlashNvStorageFtwSpareSize) > 0) && (PcdGet32 (PcdFlashNvStorageFtwSpareSize) / Instance->Media.BlockSize > 0)); + + // Ensure the Variable area Base Addresses are aligned on a block size boundaries + ASSERT (PcdGet64 (PcdFlashNvStorageVariableBase64) % Instance->Media.BlockSize == 0); + ASSERT (PcdGet64 (PcdFlashNvStorageFtwWorkingBase64) % Instance->Media.BlockSize == 0); + ASSERT (PcdGet64 (PcdFlashNvStorageFtwSpareBase64) % Instance->Media.BlockSize == 0); + + // + // EFI_FIRMWARE_VOLUME_HEADER + // + FirmwareVolumeHeader = (EFI_FIRMWARE_VOLUME_HEADER*)Headers; + CopyGuid (&FirmwareVolumeHeader->FileSystemGuid, &gEfiSystemNvDataFvGuid); + FirmwareVolumeHeader->FvLength = + PcdGet32 (PcdFlashNvStorageVariableSize) + + PcdGet32 (PcdFlashNvStorageFtwWorkingSize) + + PcdGet32 (PcdFlashNvStorageFtwSpareSize); + FirmwareVolumeHeader->Signature = EFI_FVH_SIGNATURE; + FirmwareVolumeHeader->Attributes = (EFI_FVB_ATTRIBUTES_2) ( + EFI_FVB2_READ_ENABLED_CAP | // Reads may be enabled + EFI_FVB2_READ_STATUS | // Reads are currently enabled + EFI_FVB2_STICKY_WRITE | // A block erase is required to flip bits into EFI_FVB2_ERASE_POLARITY + EFI_FVB2_MEMORY_MAPPED | // It is memory mapped + EFI_FVB2_ERASE_POLARITY | // After erasure all bits take this value (i.e. '1') + EFI_FVB2_WRITE_STATUS | // Writes are currently enabled + EFI_FVB2_WRITE_ENABLED_CAP // Writes may be enabled + ); + FirmwareVolumeHeader->HeaderLength = sizeof (EFI_FIRMWARE_VOLUME_HEADER) + sizeof (EFI_FV_BLOCK_MAP_ENTRY); + FirmwareVolumeHeader->Revision = EFI_FVH_REVISION; + //i.e. if blocks are 0-5 then last block = 5, total blocks = 6 + FirmwareVolumeHeader->BlockMap[0].NumBlocks = Instance->Media.LastBlock + 1; + FirmwareVolumeHeader->BlockMap[0].Length = Instance->Media.BlockSize; + FirmwareVolumeHeader->BlockMap[1].NumBlocks = 0; + FirmwareVolumeHeader->BlockMap[1].Length = 0; + FirmwareVolumeHeader->Checksum = CalculateCheckSum16 ((UINT16*)FirmwareVolumeHeader,FirmwareVolumeHeader->HeaderLength); + + // + // VARIABLE_STORE_HEADER + // + VariableStoreHeader = (VARIABLE_STORE_HEADER*)((UINTN)Headers + FirmwareVolumeHeader->HeaderLength); + CopyGuid (&VariableStoreHeader->Signature, &gEfiAuthenticatedVariableGuid); + VariableStoreHeader->Size = PcdGet32(PcdFlashNvStorageVariableSize) - FirmwareVolumeHeader->HeaderLength; + VariableStoreHeader->Format = VARIABLE_STORE_FORMATTED; + VariableStoreHeader->State = VARIABLE_STORE_HEALTHY; + + // Install the combined super-header in the NorFlash + Status = FvbWrite (&Instance->FvbProtocol, 0, 0, &HeadersLength, Headers); + + FreePool (Headers); + return Status; +} + +/** + Check the integrity of firmware volume header. + + @param[in] FwVolHeader - A pointer to a firmware volume header + + @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 + ) +{ + UINT16 Checksum; + EFI_FIRMWARE_VOLUME_HEADER *FwVolHeader; + VARIABLE_STORE_HEADER *VariableStoreHeader; + UINTN VariableStoreLength; + UINTN FvLength; + + FwVolHeader = (EFI_FIRMWARE_VOLUME_HEADER*)mFlashNvStorageVariableBase; + + FvLength = PcdGet32 (PcdFlashNvStorageVariableSize) + PcdGet32 (PcdFlashNvStorageFtwWorkingSize) + + PcdGet32 (PcdFlashNvStorageFtwSpareSize); + + // + // Verify the header revision, header signature, length + // Length of FvBlock cannot be 2**64-1 + // HeaderLength cannot be an odd number + // + if ( (FwVolHeader->Revision != EFI_FVH_REVISION) + || (FwVolHeader->Signature != EFI_FVH_SIGNATURE) + || (FwVolHeader->FvLength != FvLength) + ) + { + DEBUG ((DEBUG_ERROR, "%a: No Firmware Volume header present\n", + __FUNCTION__)); + return EFI_NOT_FOUND; + } + + // Check the Firmware Volume Guid + if( CompareGuid (&FwVolHeader->FileSystemGuid, &gEfiSystemNvDataFvGuid) == FALSE ) { + DEBUG ((DEBUG_ERROR, "%a: Firmware Volume Guid non-compatible\n", + __FUNCTION__)); + return EFI_NOT_FOUND; + } + + // Verify the header checksum + Checksum = CalculateSum16 ((UINT16*)FwVolHeader, FwVolHeader->HeaderLength); + if (Checksum != 0) { + DEBUG ((DEBUG_ERROR, "%a: FV checksum is invalid (Checksum:0x%X)\n", + __FUNCTION__, Checksum)); + return EFI_NOT_FOUND; + } + + VariableStoreHeader = (VARIABLE_STORE_HEADER*)((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", + __FUNCTION__)); + return EFI_NOT_FOUND; + } + + VariableStoreLength = PcdGet32 (PcdFlashNvStorageVariableSize) - FwVolHeader->HeaderLength; + if (VariableStoreHeader->Size != VariableStoreLength) { + DEBUG ((DEBUG_ERROR, "%a: Variable Store Length does not match\n", + __FUNCTION__)); + return EFI_NOT_FOUND; + } + + return EFI_SUCCESS; +} + +/** + The GetAttributes() function retrieves the attributes and + current settings of the block. + + @param This Indicates the EFI_FIRMWARE_VOLUME_BLOCK2_PROTOCOL instance. + + @param 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; + NOR_FLASH_INSTANCE *Instance; + + Instance = INSTANCE_FROM_FVB_THIS (This); + + FlashFvbAttributes = (EFI_FVB_ATTRIBUTES_2) ( + + EFI_FVB2_READ_ENABLED_CAP | // Reads may be enabled + EFI_FVB2_READ_STATUS | // Reads are currently enabled + EFI_FVB2_STICKY_WRITE | // A block erase is required to flip bits into EFI_FVB2_ERASE_POLARITY + EFI_FVB2_MEMORY_MAPPED | // It is memory mapped + EFI_FVB2_ERASE_POLARITY // After erasure all bits take this value (i.e. '1') + + ); + + // Check if it is write protected + if (Instance->Media.ReadOnly != TRUE) { + + FlashFvbAttributes = FlashFvbAttributes | + EFI_FVB2_WRITE_STATUS | // Writes are currently enabled + EFI_FVB2_WRITE_ENABLED_CAP; // Writes may be enabled + } + + *Attributes = FlashFvbAttributes; + + DEBUG ((DEBUG_BLKIO, "FvbGetAttributes(0x%X)\n", *Attributes)); + + return EFI_SUCCESS; +} + +/** + The SetAttributes() function sets configurable firmware volume attributes + and returns the new settings of the firmware volume. + + + @param This Indicates the EFI_FIRMWARE_VOLUME_BLOCK2_PROTOCOL instance. + + @param Attributes On input, Attributes is a pointer to EFI_FVB_ATTRIBUTES_2 + that contains the desired firmware volume settings. + On successful return, it contains the new settings of + the firmware volume. + Type EFI_FVB_ATTRIBUTES_2 is defined in EFI_FIRMWARE_VOLUME_HEADER. + + @retval EFI_SUCCESS The firmware volume attributes were returned. + + @retval EFI_INVALID_PARAMETER The attributes requested are in conflict with the capabilities + as declared in the firmware volume header. + + **/ +EFI_STATUS +EFIAPI +FvbSetAttributes( + IN CONST EFI_FIRMWARE_VOLUME_BLOCK2_PROTOCOL *This, + IN OUT EFI_FVB_ATTRIBUTES_2 *Attributes + ) +{ + DEBUG ((DEBUG_BLKIO, "FvbSetAttributes(0x%X) is not supported\n",*Attributes)); + return EFI_UNSUPPORTED; +} + +/** + The GetPhysicalAddress() function retrieves the base address of + a memory-mapped firmware volume. This function should be called + only for memory-mapped firmware volumes. + + @param This Indicates the EFI_FIRMWARE_VOLUME_BLOCK2_PROTOCOL instance. + + @param Address Pointer to a caller-allocated + EFI_PHYSICAL_ADDRESS that, on successful + return from GetPhysicalAddress(), contains the + base address of the firmware volume. + + @retval EFI_SUCCESS The firmware volume base address was returned. + + @retval EFI_NOT_SUPPORTED The firmware volume is not memory mapped. + + **/ +EFI_STATUS +EFIAPI +FvbGetPhysicalAddress ( + IN CONST EFI_FIRMWARE_VOLUME_BLOCK2_PROTOCOL *This, + OUT EFI_PHYSICAL_ADDRESS *Address + ) +{ + *Address = mFlashNvStorageVariableBase; + return EFI_SUCCESS; +} + +/** + The GetBlockSize() function 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 This Indicates the EFI_FIRMWARE_VOLUME_BLOCK2_PROTOCOL instance. + + @param Lba Indicates the block for which to return the size. + + @param BlockSize Pointer to a caller-allocated UINTN in which + the size of the block is returned. + + @param NumberOfBlocks Pointer to a caller-allocated UINTN in + which the number of consecutive blocks, + starting with Lba, is returned. All + blocks in this range have a size of + BlockSize. + + + @retval EFI_SUCCESS The firmware volume base address was returned. + + @retval EFI_INVALID_PARAMETER The requested LBA is out of range. + + **/ +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 = INSTANCE_FROM_FVB_THIS(This); + + DEBUG ((DEBUG_BLKIO, "FvbGetBlockSize(Lba=%ld, BlockSize=0x%x, LastBlock=%ld)\n", + Lba, Instance->Media.BlockSize, Instance->Media.LastBlock)); + + if (Lba > Instance->Media.LastBlock) { + DEBUG ((DEBUG_ERROR, "%a : Parameter LBA %ld is beyond the last Lba (%ld)\n", + __FUNCTION__, Lba, Instance->Media.LastBlock)); + Status = EFI_INVALID_PARAMETER; + } else { + // In this platform each NorFlash device has equal sized blocks. + *BlockSize = (UINTN) Instance->Media.BlockSize; + *NumberOfBlocks = (UINTN) (Instance->Media.LastBlock - Lba + 1); + + DEBUG ((DEBUG_BLKIO, "%a : *BlockSize=0x%x, *NumberOfBlocks=0x%x.\n", + __FUNCTION__, *BlockSize, *NumberOfBlocks)); + + Status = EFI_SUCCESS; + } + + return Status; +} + +/** + Reads the specified number of bytes into a buffer from the specified block. + + The Read() function reads the requested number of bytes from the + requested block and stores them in the provided buffer. + Implementations should be mindful that the firmware volume + might be in the ReadDisabled state. If it is in this state, + the Read() function must return the status code + EFI_ACCESS_DENIED without modifying the contents of the + buffer. The Read() function must also prevent spanning block + boundaries. If a read is requested that would span a block + boundary, the read must read up to the boundary but not + beyond. The output parameter NumBytes must be set to correctly + indicate the number of bytes actually read. The caller must be + aware that a read may be partially completed. + + @param This Indicates the EFI_FIRMWARE_VOLUME_BLOCK2_PROTOCOL instance. + + @param Lba The starting logical block index from which to read. + + @param Offset Offset into the block at which to begin reading. + + @param NumBytes Pointer to a UINTN. + At entry, *NumBytes contains the total size of the buffer. + At exit, *NumBytes contains the total number of bytes read. + + @param Buffer Pointer to a caller-allocated buffer that will be used + to hold the data that is read. + + @retval EFI_SUCCESS The firmware volume was read successfully, and contents are + in Buffer. + + @retval EFI_BAD_BUFFER_SIZE Read attempted across an LBA boundary. + On output, NumBytes contains the total number of bytes + returned in Buffer. + + @retval EFI_ACCESS_DENIED The firmware volume is in the ReadDisabled state. + + @retval EFI_DEVICE_ERROR The block device is not functioning 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 + ) +{ + UINTN BlockSize; + NOR_FLASH_INSTANCE *Instance; + + Instance = INSTANCE_FROM_FVB_THIS (This); + + DEBUG ((DEBUG_BLKIO, "FvbRead(Parameters: Lba=%ld, Offset=0x%x, " + "*NumBytes=0x%x, Buffer @ 0x%08x)\n", + Instance->StartLba + Lba, Offset, *NumBytes, Buffer)); + + if (!Instance->Initialized && Instance->Initialize) { + Instance->Initialize(Instance); + } + + // Cache the block size to avoid de-referencing pointers all the time + BlockSize = Instance->Media.BlockSize; + + DEBUG ((DEBUG_BLKIO, "FvbRead: Check if (Offset=0x%x + NumBytes=0x%x) <= " + "BlockSize=0x%x\n", Offset, *NumBytes, BlockSize )); + + // The read must not span block boundaries. + while (Offset >= BlockSize) { + Offset -= BlockSize; + Lba++; + } + + if ((Instance->StartLba + Lba) > Instance->Media.LastBlock) { + DEBUG ((DEBUG_ERROR, "%a : Parameter LBA %ld is beyond the last Lba (%ld)\n", + __FUNCTION__, Lba, Instance->Media.LastBlock)); + return EFI_INVALID_PARAMETER; + } + + if ((Offset + *NumBytes) > BlockSize) { + *NumBytes = BlockSize-Offset; + } + + return NorFlashPlatformRead (Instance, Instance->StartLba + Lba, + Offset, *NumBytes, Buffer); +} + +/** + Writes the specified number of bytes from the input buffer to the block. + + The Write() function writes the specified number of bytes from + the provided buffer to the specified block and offset. If the + firmware volume is sticky write, the caller must ensure that + all the bits of the specified range to write are in the + EFI_FVB_ERASE_POLARITY state before calling the Write() + function, or else the result will be unpredictable. This + unpredictability arises because, for a sticky-write firmware + volume, a write may negate a bit in the EFI_FVB_ERASE_POLARITY + state but cannot flip it back again. Before calling the + Write() function, it is recommended for the caller to first call + the EraseBlocks() function to erase the specified block to + write. A block erase cycle will transition bits from the + (NOT)EFI_FVB_ERASE_POLARITY state back to the + EFI_FVB_ERASE_POLARITY state. Implementations should be + mindful that the firmware volume might be in the WriteDisabled + state. If it is in this state, the Write() function must + return the status code EFI_ACCESS_DENIED without modifying the + contents of the firmware volume. The Write() function must + also prevent spanning block boundaries. If a write is + requested that spans a block boundary, the write must store up + to the boundary but not beyond. The output parameter NumBytes + must be set to correctly indicate the number of bytes actually + written. The caller must be aware that a write may be + partially completed. All writes, partial or otherwise, must be + fully flushed to the hardware before the Write() service + returns. + + @param This Indicates the EFI_FIRMWARE_VOLUME_BLOCK2_PROTOCOL instance. + + @param Lba The starting logical block index to write to. + + @param Offset Offset into the block at which to begin writing. + + @param 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 Buffer The pointer to a caller-allocated buffer that contains the source for the write. + + @retval EFI_SUCCESS The firmware volume was written successfully. + + @retval EFI_BAD_BUFFER_SIZE The write was attempted across an LBA boundary. + On output, NumBytes contains the total number of bytes + actually written. + + @retval EFI_ACCESS_DENIED The firmware volume is in the WriteDisabled state. + + @retval EFI_DEVICE_ERROR The block device is malfunctioning and could not be written. + + + **/ +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; + UINTN BlockSize; + + Instance = INSTANCE_FROM_FVB_THIS (This); + // Cache the block size to avoid de-referencing pointers all the time + BlockSize = Instance->Media.BlockSize; + + if (!Instance->Initialized && Instance->Initialize) { + Instance->Initialize(Instance); + } + + // The write must not span block boundaries. + while(Offset >= BlockSize) { + Offset -= BlockSize; + Lba++; + } + + if ((Instance->StartLba + Lba) > Instance->Media.LastBlock) { + DEBUG ((DEBUG_ERROR, "%a : Parameter LBA %ld is beyond the last Lba (%ld)\n", + __FUNCTION__, Lba, Instance->Media.LastBlock)); + return EFI_INVALID_PARAMETER; + } + + if ((Offset + *NumBytes) > BlockSize) { + *NumBytes = BlockSize-Offset; + } + + return NorFlashWrite (Instance, Instance->StartLba + Lba, + Offset, NumBytes, Buffer); +} + +/** + Erases and initialises a firmware volume block. + + The EraseBlocks() function erases one or more blocks as denoted + by the variable argument list. The entire parameter list of + blocks must be verified before erasing any blocks. If a block is + requested that does not exist within the associated firmware + volume (it has a larger index than the last block of the + firmware volume), the EraseBlocks() function must return the + status code EFI_INVALID_PARAMETER without modifying the contents + of the firmware volume. Implementations should be mindful that + the firmware volume might be in the WriteDisabled state. If it + is in this state, the EraseBlocks() function must return the + status code EFI_ACCESS_DENIED without modifying the contents of + the firmware volume. All calls to EraseBlocks() must be fully + flushed to the hardware before the EraseBlocks() service + returns. + + @param This Indicates the EFI_FIRMWARE_VOLUME_BLOCK2_PROTOCOL + instance. + + @param ... The variable argument list is a list of tuples. + Each tuple describes a range of LBAs to erase + and consists of the following: + - An EFI_LBA that indicates the starting LBA + - A UINTN that indicates the number of blocks to erase. + + The list is terminated with an EFI_LBA_LIST_TERMINATOR. + For example, the following indicates that two ranges of blocks + (5-7 and 10-11) are to be erased: + EraseBlocks (This, 5, 3, 10, 2, EFI_LBA_LIST_TERMINATOR); + + @retval EFI_SUCCESS The erase request successfully completed. + + @retval EFI_ACCESS_DENIED The firmware volume is in the WriteDisabled state. + + @retval EFI_DEVICE_ERROR The block device is not functioning 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 = INSTANCE_FROM_FVB_THIS (This); + + DEBUG ((DEBUG_BLKIO, "FvbEraseBlocks()\n")); + + Status = EFI_SUCCESS; + + // Detect WriteDisabled state + if (Instance->Media.ReadOnly == TRUE) { + // Firmware volume is in WriteDisabled state + DEBUG ((DEBUG_ERROR, "%a : Device is in WriteDisabled state\n")); + return EFI_ACCESS_DENIED; + } + + // 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 = VA_ARG (Args, EFI_LBA); + + // Have we reached the end of the list? + if (StartingLba == EFI_LBA_LIST_TERMINATOR) { + //Exit the while loop + break; + } + + // How many Lba blocks are we requested to erase? + NumOfLba = VA_ARG (Args, UINT32); + + // All blocks must be within range + DEBUG ((DEBUG_BLKIO, "FvbEraseBlocks: Check if: ( StartingLba=%ld + " + "NumOfLba=%d - 1 ) > LastBlock=%ld.\n", + Instance->StartLba + StartingLba, NumOfLba, + Instance->Media.LastBlock)); + if ((NumOfLba == 0) || + ((Instance->StartLba + StartingLba + NumOfLba - 1) > + Instance->Media.LastBlock)) { + VA_END (Args); + DEBUG ((DEBUG_ERROR, "%a : Lba range goes past the last Lba\n")); + Status = EFI_INVALID_PARAMETER; + goto EXIT; + } + } while (TRUE); + VA_END (Args); + + // + // To get here, all must be ok, so start erasing + // + VA_START (Args, This); + do { + // Get the Lba from which we start erasing + StartingLba = VA_ARG (Args, EFI_LBA); + + // Have we reached the end of the list? + if (StartingLba == EFI_LBA_LIST_TERMINATOR) { + // Exit the while loop + break; + } + + // How many Lba blocks are we requested to erase? + NumOfLba = VA_ARG (Args, UINT32); + + // Go through each one and erase it + while (NumOfLba > 0) { + + // Get the physical address of Lba to erase + BlockAddress = GET_NOR_BLOCK_ADDRESS ( + Instance->RegionBaseAddress, + Instance->StartLba + StartingLba, + Instance->Media.BlockSize + ); + + // Erase it + DEBUG ((DEBUG_BLKIO, "FvbEraseBlocks: Erasing Lba=%ld @ 0x%08x.\n", + Instance->StartLba + StartingLba, BlockAddress)); + Status = NorFlashPlatformEraseSector(Instance, BlockAddress); + if (EFI_ERROR (Status)) { + VA_END (Args); + Status = EFI_DEVICE_ERROR; + goto EXIT; + } + + // Move to the next Lba + StartingLba++; + NumOfLba--; + } + } while (TRUE); + VA_END (Args); + +EXIT: + return Status; +} + +/** + Fixup internal data so that EFI can be call in virtual mode. + Call the passed in Child Notify event and convert any pointers in + lib to virtual mode. + + @param[in] Event The Event that is being processed + @param[in] Context Event Context +**/ +VOID +EFIAPI +FvbVirtualNotifyEvent ( + IN EFI_EVENT Event, + IN VOID *Context + ) +{ + EfiConvertPointer (0x0, (VOID**)&mFlashNvStorageVariableBase); + return; +} + +EFI_STATUS +EFIAPI +NorFlashFvbInitialize ( + IN NOR_FLASH_INSTANCE* Instance + ) +{ + EFI_STATUS Status; + UINT32 FvbNumLba; + EFI_BOOT_MODE BootMode; + UINTN RuntimeMmioRegionSize; + + DEBUG ((DEBUG_BLKIO,"NorFlashFvbInitialize\n")); + + Instance->Initialized = TRUE; + mFlashNvStorageVariableBase = FixedPcdGet64 (PcdFlashNvStorageVariableBase64); + + // Set the index of the first LBA for the FVB + Instance->StartLba = (PcdGet64 (PcdFlashNvStorageVariableBase64) - Instance->RegionBaseAddress) / Instance->Media.BlockSize; + + BootMode = GetBootModeHob (); + if (BootMode == BOOT_WITH_DEFAULT_SETTINGS) { + Status = EFI_INVALID_PARAMETER; + } + else { + // Determine if there is a valid header at the beginning of the NorFlash + Status = 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", __FUNCTION__)); + DEBUG ((DEBUG_INFO, "%a: Installing a correct one for this volume.\n", + __FUNCTION__)); + + // Erase all the NorFlash that is reserved for variable storage + FvbNumLba = (PcdGet32 (PcdFlashNvStorageVariableSize) + PcdGet32 (PcdFlashNvStorageFtwWorkingSize) + PcdGet32 (PcdFlashNvStorageFtwSpareSize)) / Instance->Media.BlockSize; + + Status = FvbEraseBlocks (&Instance->FvbProtocol, (EFI_LBA)0, FvbNumLba, EFI_LBA_LIST_TERMINATOR); + if (EFI_ERROR (Status)) + return Status; + + // Install all appropriate headers + Status = InitializeFvAndVariableStoreHeaders (Instance); + if (EFI_ERROR (Status)) { + return Status; + } + } + + // + // Declare the Non-Volatile storage as EFI_MEMORY_RUNTIME + // + + // Note: all the NOR Flash region needs to be reserved into the UEFI Runtime memory; + // even if we only use the small block region at the top of the NOR Flash. + // The reason is when the NOR Flash memory is set into program mode, the command + // is written as the base of the flash region (ie: Instance->DeviceBaseAddress) + RuntimeMmioRegionSize = (Instance->RegionBaseAddress - Instance->DeviceBaseAddress) + Instance->Size; + + Status = gDS->AddMemorySpace ( + EfiGcdMemoryTypeMemoryMappedIo, + Instance->DeviceBaseAddress, RuntimeMmioRegionSize, + EFI_MEMORY_UC | EFI_MEMORY_RUNTIME + ); + ASSERT_EFI_ERROR (Status); + + Status = gDS->SetMemorySpaceAttributes ( + Instance->DeviceBaseAddress, RuntimeMmioRegionSize, + EFI_MEMORY_UC | EFI_MEMORY_RUNTIME); + ASSERT_EFI_ERROR (Status); + + // + // Register for the virtual address change event + // + Status = gBS->CreateEventEx ( + EVT_NOTIFY_SIGNAL, + TPL_NOTIFY, + FvbVirtualNotifyEvent, + NULL, + &gEfiEventVirtualAddressChangeGuid, + &mFvbVirtualAddrChangeEvent + ); + ASSERT_EFI_ERROR (Status); + + return Status; +} diff --git a/Platform/NXP/Include/Library/NorFlash.h b/Platform/NXP/Include/Library/NorFlash.h new file mode 100644 index 0000000..37099ff --- /dev/null +++ b/Platform/NXP/Include/Library/NorFlash.h @@ -0,0 +1,222 @@ +/** @NorFlash.h + + Based on NOR flash access APIs used in ArmPlatformPkg/Drivers/NorFlashDxe/NorFlashDxe.h + + Copyright (c) 2011 - 2014, ARM Ltd. All rights reserved. + Copyright 2017 NXP + + This program and the accompanying materials + are licensed and made available under the terms and conditions of the BSD License + which accompanies this distribution. The full text of the license may be found at + http://opensource.org/licenses/bsd-license.php + + THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, + WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +**/ + +#ifndef __NOR_FLASH_H__ +#define __NOR_FLASH_H__ + +#include +#include + +#define NOR_FLASH_ERASE_RETRY 10 + +#define GET_NOR_BLOCK_ADDRESS(BaseAddr,Lba,LbaSize) ( BaseAddr + (UINTN)((Lba) * LbaSize) ) + +#define NOR_FLASH_SIGNATURE SIGNATURE_32('n', 'o', 'r', '0') +#define INSTANCE_FROM_FVB_THIS(a) CR(a, NOR_FLASH_INSTANCE, FvbProtocol, NOR_FLASH_SIGNATURE) +#define INSTANCE_FROM_BLKIO_THIS(a) CR(a, NOR_FLASH_INSTANCE, BlockIoProtocol, NOR_FLASH_SIGNATURE) + +typedef struct _NOR_FLASH_INSTANCE NOR_FLASH_INSTANCE; + +typedef EFI_STATUS (*NOR_FLASH_INITIALIZE) (NOR_FLASH_INSTANCE* Instance); + +typedef struct { + VENDOR_DEVICE_PATH Vendor; + EFI_DEVICE_PATH_PROTOCOL End; +} NOR_FLASH_DEVICE_PATH; + +struct _NOR_FLASH_INSTANCE { + UINT32 Signature; + EFI_HANDLE Handle; + BOOLEAN Initialized; + NOR_FLASH_INITIALIZE Initialize; + UINTN DeviceBaseAddress; + UINTN RegionBaseAddress; + UINTN Size; + EFI_LBA StartLba; + EFI_BLOCK_IO_PROTOCOL BlockIoProtocol; + EFI_BLOCK_IO_MEDIA Media; + BOOLEAN SupportFvb; + EFI_FIRMWARE_VOLUME_BLOCK2_PROTOCOL FvbProtocol; + VOID* ShadowBuffer; + NOR_FLASH_DEVICE_PATH DevicePath; +}; + +// +// NorFlashLib.c related +// + +EFI_STATUS +NorFlashPlatformWriteBuffer ( + IN NOR_FLASH_INSTANCE *Instance, + IN EFI_LBA Lba, + IN UINTN Offset, + IN OUT UINTN *NumBytes, + IN UINT8 *Buffer + ); + +EFI_STATUS +NorFlashPlatformEraseSector ( + IN NOR_FLASH_INSTANCE *Instance, + IN UINTN SectorAddress + ); + +EFI_STATUS +NorFlashPlatformControllerInitialization ( + VOID + ); + +EFI_STATUS +NorFlashPlatformRead ( + IN NOR_FLASH_INSTANCE *Instance, + IN EFI_LBA Lba, + IN UINTN Offset, + IN UINTN BufferSizeInBytes, + OUT UINT8 *Buffer + ); + +EFI_STATUS +NorFlashPlatformReset ( + IN UINTN Instance + ); + +extern CONST EFI_GUID* CONST mNorFlashVariableGuid; + +// +// NorFlashFvbDxe.c +// + +EFI_STATUS +EFIAPI +NorFlashFvbInitialize ( + IN NOR_FLASH_INSTANCE* Instance + ); + +EFI_STATUS +EFIAPI +FvbGetAttributes( + IN CONST EFI_FIRMWARE_VOLUME_BLOCK2_PROTOCOL *This, + OUT EFI_FVB_ATTRIBUTES_2 *Attributes + ); + +EFI_STATUS +EFIAPI +FvbSetAttributes( + IN CONST EFI_FIRMWARE_VOLUME_BLOCK2_PROTOCOL *This, + IN OUT EFI_FVB_ATTRIBUTES_2 *Attributes + ); + +EFI_STATUS +EFIAPI +FvbGetPhysicalAddress( + IN CONST EFI_FIRMWARE_VOLUME_BLOCK2_PROTOCOL *This, + OUT EFI_PHYSICAL_ADDRESS *Address + ); + +EFI_STATUS +EFIAPI +FvbGetBlockSize( + IN CONST EFI_FIRMWARE_VOLUME_BLOCK2_PROTOCOL *This, + IN EFI_LBA Lba, + OUT UINTN *BlockSize, + OUT UINTN *NumberOfBlocks + ); + +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 +EFIAPI +FvbWrite( + IN CONST EFI_FIRMWARE_VOLUME_BLOCK2_PROTOCOL *This, + IN EFI_LBA Lba, + IN UINTN Offset, + IN OUT UINTN *NumBytes, + IN UINT8 *Buffer + ); + +EFI_STATUS +EFIAPI +FvbEraseBlocks( + IN CONST EFI_FIRMWARE_VOLUME_BLOCK2_PROTOCOL *This, + ... + ); +// +// NorFlashBlockIoDxe.c +// + +// +// BlockIO Protocol function EFI_BLOCK_IO_PROTOCOL.Reset +// +EFI_STATUS +EFIAPI +NorFlashBlockIoReset ( + IN EFI_BLOCK_IO_PROTOCOL *This, + IN BOOLEAN ExtendedVerification + ); + +// +// BlockIO Protocol function EFI_BLOCK_IO_PROTOCOL.ReadBlocks +// +EFI_STATUS +EFIAPI +NorFlashBlockIoReadBlocks ( + IN EFI_BLOCK_IO_PROTOCOL *This, + IN UINT32 MediaId, + IN EFI_LBA Lba, + IN UINTN BufferSizeInBytes, + OUT VOID *Buffer +); + +// +// BlockIO Protocol function EFI_BLOCK_IO_PROTOCOL.WriteBlocks +// +EFI_STATUS +EFIAPI +NorFlashBlockIoWriteBlocks ( + IN EFI_BLOCK_IO_PROTOCOL *This, + IN UINT32 MediaId, + IN EFI_LBA Lba, + IN UINTN BufferSizeInBytes, + IN VOID *Buffer +); + +// +// BlockIO Protocol function EFI_BLOCK_IO_PROTOCOL.FlushBlocks +// +EFI_STATUS +EFIAPI +NorFlashBlockIoFlushBlocks ( + IN EFI_BLOCK_IO_PROTOCOL *This +); + +EFI_STATUS +NorFlashWrite ( + IN NOR_FLASH_INSTANCE *Instance, + IN EFI_LBA Lba, + IN UINTN Offset, + IN OUT UINTN *NumBytes, + IN UINT8 *Buffer +); + +#endif /* __NOR_FLASH_DXE_H__ */ diff --git a/Silicon/NXP/Chassis/Chassis.c b/Silicon/NXP/Chassis/Chassis.c index a6a77c2..ab0076f 100644 --- a/Silicon/NXP/Chassis/Chassis.c +++ b/Silicon/NXP/Chassis/Chassis.c @@ -17,6 +17,7 @@ #include #include #include +#include #include #include #include @@ -411,3 +412,17 @@ CalculateI2cClockRate ( return SocSysInfo.FreqSystemBus; } + +/** + Initialize IFC device timings +**/ +VOID +IfcInit ( + VOID + ) +{ + // NOR Init + if (FixedPcdGet64 (PcdIfcNorEnabled)) { + IfcNorInit (); + } +} diff --git a/Silicon/NXP/Chassis/Chassis.h b/Silicon/NXP/Chassis/Chassis.h index 4bdb4d0..c8057f0 100644 --- a/Silicon/NXP/Chassis/Chassis.h +++ b/Silicon/NXP/Chassis/Chassis.h @@ -141,4 +141,11 @@ CpuNumCores ( VOID ); +/** + Initialize IFC Device timings + **/ +VOID +IfcInit ( + VOID + ); #endif /* __CHASSIS_H__ */ diff --git a/Silicon/NXP/Chassis/Chassis2/Soc.c b/Silicon/NXP/Chassis/Chassis2/Soc.c index 2f57929..847bbc2 100644 --- a/Silicon/NXP/Chassis/Chassis2/Soc.c +++ b/Silicon/NXP/Chassis/Chassis2/Soc.c @@ -140,6 +140,7 @@ SocInit ( PrintCpuInfo (); PrintRCW (); + IfcInit (); return; } diff --git a/Silicon/NXP/Chassis/LS1043aSocLib.inf b/Silicon/NXP/Chassis/LS1043aSocLib.inf index e6e7ac4..b11fdc2 100644 --- a/Silicon/NXP/Chassis/LS1043aSocLib.inf +++ b/Silicon/NXP/Chassis/LS1043aSocLib.inf @@ -32,6 +32,7 @@ BeIoLib DebugLib SerialPortLib + NorFlashLib [Sources.common] Chassis.c @@ -45,3 +46,4 @@ gNxpQoriqLsTokenSpaceGuid.PcdSerdes2Enabled gNxpQoriqLsTokenSpaceGuid.PcdGurBigEndian gNxpQoriqLsTokenSpaceGuid.PcdClkBaseAddr + gNxpQoriqLsTokenSpaceGuid.PcdIfcNorEnabled -- 1.9.1