From patchwork Fri Jan 4 14:43:31 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Ard Biesheuvel X-Patchwork-Id: 154777 Delivered-To: patch@linaro.org Received: by 2002:a2e:299d:0:0:0:0:0 with SMTP id p29-v6csp690675ljp; Fri, 4 Jan 2019 06:43:54 -0800 (PST) X-Google-Smtp-Source: ALg8bN6F8+Nf+rY4wmjymARDFy9sXQ+brmeTaljLObIyoK/4XUZA66a60+5NDQ0gBCHOF67EFFen X-Received: by 2002:a17:902:bf44:: with SMTP id u4mr41500986pls.5.1546613034656; Fri, 04 Jan 2019 06:43:54 -0800 (PST) ARC-Seal: i=1; a=rsa-sha256; t=1546613034; cv=none; d=google.com; s=arc-20160816; b=dqmMbeTYcNTZ3xma9ALko4RJcoRJQi0YSW+Je/Zl5f8zvi49POyz2LFKISF0mtbIff ktRG9h3Jn6TTw6FSR4B1EH8ltpp7/mIgbytsiPui1IFGqYaOyja9uzwrqa3R1KoS3Ygm ILvGXzZKnS7mibXyPlxJfCKP3rjfDqQW8AlJMA31Mb6XFTmhWr4e2blX4w7YUA2pyYFU FVsSgH2JXtJJPrHd+jpg87JHf6owI4u7lXk0Z7D0jKAzxkzrebSx91TA+JgpWMBd5RWR 1jsKuklUxj7w7C3jEWaFHjBnLglwIvIkD4Blh6KRDCuKgreSDl9fz2UijFxVjfE2rHZq Gvjw== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=sender:errors-to:content-transfer-encoding:mime-version :list-subscribe:list-help:list-post:list-archive:list-unsubscribe :list-id:precedence:subject:references:in-reply-to:message-id:date :to:from:dkim-signature:delivered-to; bh=LA3kXRtCKpG/6QdEDwISnl5obVK7lOFFz8Yhg5nb+Ss=; b=awijHrqwr9XxOVJYOHqTkbvXhXnQ7i4iREbxUrGS+EagzkhNyQrpaUh4Q9UB+XGCNw p8wcER7TrDfAF0js3G5ASnIgu340SGcv528U6Hb/BTG1m/aUvbbMaGg/yB5LMl2Z8qZg Zk5wrTDX66iPrmOJhKs7l19YGIRVc6snRJgjaIQQIZD3QVqJE0kq4j0OXLVdKET1NWKa 6AJjxqN79x683ATmWXsJ+YSyFhc8AYtbD95mw44bXy74Z07tVnQozviipnJcC0w8XS34 E5LGpdz8ftKxixqeZqvslLZb7VHk1icfF6H2RxaEAI7usgwsCsW+ye2Epsp6W+XbK7jb 1Yhg== ARC-Authentication-Results: i=1; mx.google.com; dkim=neutral (body hash did not verify) header.i=@linaro.org header.s=google header.b=A2JQ+Xcg; spf=pass (google.com: best guess record for domain of edk2-devel-bounces@lists.01.org designates 198.145.21.10 as permitted sender) smtp.mailfrom=edk2-devel-bounces@lists.01.org; dmarc=fail (p=NONE sp=NONE dis=NONE) header.from=linaro.org Return-Path: Received: from ml01.01.org (ml01.01.org. [198.145.21.10]) by mx.google.com with ESMTPS id p22si54508752pgl.340.2019.01.04.06.43.54 (version=TLS1_2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128); Fri, 04 Jan 2019 06:43:54 -0800 (PST) Received-SPF: pass (google.com: best guess record for domain of edk2-devel-bounces@lists.01.org designates 198.145.21.10 as permitted sender) client-ip=198.145.21.10; Authentication-Results: mx.google.com; dkim=neutral (body hash did not verify) header.i=@linaro.org header.s=google header.b=A2JQ+Xcg; spf=pass (google.com: best guess record for domain of edk2-devel-bounces@lists.01.org designates 198.145.21.10 as permitted sender) smtp.mailfrom=edk2-devel-bounces@lists.01.org; dmarc=fail (p=NONE sp=NONE dis=NONE) header.from=linaro.org Received: from [127.0.0.1] (localhost [IPv6:::1]) by ml01.01.org (Postfix) with ESMTP id 1A091211AEA41; Fri, 4 Jan 2019 06:43:52 -0800 (PST) X-Original-To: edk2-devel@lists.01.org Delivered-To: edk2-devel@lists.01.org Received-SPF: Pass (sender SPF authorized) identity=mailfrom; client-ip=2a00:1450:4864:20::544; helo=mail-ed1-x544.google.com; envelope-from=ard.biesheuvel@linaro.org; receiver=edk2-devel@lists.01.org Received: from mail-ed1-x544.google.com (mail-ed1-x544.google.com [IPv6:2a00:1450:4864:20::544]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by ml01.01.org (Postfix) with ESMTPS id 1E7C4211AE8D3 for ; Fri, 4 Jan 2019 06:43:49 -0800 (PST) Received: by mail-ed1-x544.google.com with SMTP id b14so31962929edt.6 for ; Fri, 04 Jan 2019 06:43:49 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=linaro.org; s=google; h=from:to:cc:subject:date:message-id:in-reply-to:references; bh=2FP1MryPsjtTU5f+gwXT0gawgNXldFkd1Wk+lqQXmCs=; b=A2JQ+XcgeYLO6THNM7OM7SCzUflQvvSaNxBNEzvLGquKGbhxfWHDLBE6TjXK5Eyn5v 5MqQGSB2Eb/tMPhhYFqr4tfeAn+8nOjq4l1ivIc/VX9+FfZ/kLPSUwo21GoTsY0SPOSk mTA8P3uNU6ZklSM2YdFoESdcKLFWxFiBeMNf4= X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references; bh=2FP1MryPsjtTU5f+gwXT0gawgNXldFkd1Wk+lqQXmCs=; b=HJTFNEkaZBqae4GZIv80kAz3J6ug2jSEeagK7lc9TmYy2lnHOHORHuuKJ3Ic8vAFom Kg9ND3j2UkSXHz1rv5+L4uj/6p/w9jpgjSoAgAr4mtYz46W8XdAFtghOFdPpA8ov/l7z J6wO5oo3eTtQREGvIANVv3g0SHaAgEZHISlQEtlLbhjX75Z8ilqZK9BZyZ4/6/yRku+3 HWlsG0+x9lrGwi2sX/6/XxtYAPgKwDmGFaA/qSb1J8qkPo69yP/fAXNKSerZ/5dj96x2 0paZiaYaVPoAjoZgTwLJQxR246vJ7VgF8LSX1mYQE1zDt36Xv+letU2qPlwWxOQxEg3p WIBw== X-Gm-Message-State: AA+aEWZlxxB7XizIBO1+fs3vRXtc+T+tK4KK4cv8wZ3IKeti4PZQ8rgk OHIWXtBt55iaoQHF6ndcW2FwSgWnMb9/Uw== X-Received: by 2002:a50:bc12:: with SMTP id j18mr46903134edh.50.1546613024455; Fri, 04 Jan 2019 06:43:44 -0800 (PST) Received: from dogfood.home ([2a01:cb1d:112:6f00:183a:9013:d5a3:37a8]) by smtp.gmail.com with ESMTPSA id q16sm21608226eds.60.2019.01.04.06.43.42 (version=TLS1_2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128); Fri, 04 Jan 2019 06:43:42 -0800 (PST) From: Ard Biesheuvel To: edk2-devel@lists.01.org Date: Fri, 4 Jan 2019 15:43:31 +0100 Message-Id: <20190104144336.8941-3-ard.biesheuvel@linaro.org> X-Mailer: git-send-email 2.17.1 In-Reply-To: <20190104144336.8941-1-ard.biesheuvel@linaro.org> References: <20190104144336.8941-1-ard.biesheuvel@linaro.org> Subject: [edk2] [PATCH edk2-platforms 2/7] Silicon/SynQuacer/Fip006Dxe: factor out DXE specific pieces X-BeenThere: edk2-devel@lists.01.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: EDK II Development List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , MIME-Version: 1.0 Errors-To: edk2-devel-bounces@lists.01.org Sender: "edk2-devel" In preparation of creating a SMM version of the FIP006 NOR flash driver, refactor the existing pieces into a core driver, the FVB methods and the DXE instantiation code. Contributed-under: TianoCore Contribution Agreement 1.1 Signed-off-by: Ard Biesheuvel --- Silicon/Socionext/SynQuacer/Drivers/Fip006Dxe/Fip006Dxe.inf | 6 +- Silicon/Socionext/SynQuacer/Drivers/Fip006Dxe/NorFlash.c | 1006 +++++++++++++++++ Silicon/Socionext/SynQuacer/Drivers/Fip006Dxe/{NorFlashDxe.h => NorFlash.h} | 52 +- Silicon/Socionext/SynQuacer/Drivers/Fip006Dxe/NorFlashDxe.c | 1150 +++----------------- Silicon/Socionext/SynQuacer/Drivers/Fip006Dxe/{NorFlashFvbDxe.c => NorFlashFvb.c} | 161 +-- 5 files changed, 1194 insertions(+), 1181 deletions(-) -- 2.17.1 _______________________________________________ edk2-devel mailing list edk2-devel@lists.01.org https://lists.01.org/mailman/listinfo/edk2-devel Acked-by: Leif Lindholm diff --git a/Silicon/Socionext/SynQuacer/Drivers/Fip006Dxe/Fip006Dxe.inf b/Silicon/Socionext/SynQuacer/Drivers/Fip006Dxe/Fip006Dxe.inf index b939aa689eef..603641e0a68f 100644 --- a/Silicon/Socionext/SynQuacer/Drivers/Fip006Dxe/Fip006Dxe.inf +++ b/Silicon/Socionext/SynQuacer/Drivers/Fip006Dxe/Fip006Dxe.inf @@ -2,7 +2,7 @@ # Socionext FIP006 High-Speed SPI Controller with NOR Flash Driver # # Copyright (c) 2017, Socionext Inc. All rights reserved.
-# Copyright (c) 2017, Linaro, Ltd. All rights reserved.
+# Copyright (c) 2017-2018, Linaro, Ltd. All rights reserved.
# # This program and the accompanying materials # are licensed and made available under the terms and conditions of the BSD License @@ -25,7 +25,9 @@ [Defines] [Sources] NorFlashDxe.c - NorFlashFvbDxe.c + NorFlash.c + NorFlash.h + NorFlashFvb.c [Packages] ArmPlatformPkg/ArmPlatformPkg.dec diff --git a/Silicon/Socionext/SynQuacer/Drivers/Fip006Dxe/NorFlash.c b/Silicon/Socionext/SynQuacer/Drivers/Fip006Dxe/NorFlash.c new file mode 100644 index 000000000000..2134739bfba9 --- /dev/null +++ b/Silicon/Socionext/SynQuacer/Drivers/Fip006Dxe/NorFlash.c @@ -0,0 +1,1006 @@ +/** @file NorFlashDxe.c + + Copyright (c) 2011 - 2014, ARM Ltd. All rights reserved.
+ Copyright (c) 2017, Socionext Inc. All rights reserved.
+ Copyright (c) 2017, Linaro, Ltd. All rights reserved.
+ + 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 "NorFlash.h" + +STATIC CONST UINT16 mFip006NullCmdSeq[] = { + CSDC (CSDC_END, CSDC_CONT_NON_CONTINUOUS, CSDC_TRP_MBM, CSDC_DEC_DECODE), + CSDC (CSDC_END, CSDC_CONT_NON_CONTINUOUS, CSDC_TRP_MBM, CSDC_DEC_DECODE), + CSDC (CSDC_END, CSDC_CONT_NON_CONTINUOUS, CSDC_TRP_MBM, CSDC_DEC_DECODE), + CSDC (CSDC_END, CSDC_CONT_NON_CONTINUOUS, CSDC_TRP_MBM, CSDC_DEC_DECODE), + CSDC (CSDC_END, CSDC_CONT_NON_CONTINUOUS, CSDC_TRP_MBM, CSDC_DEC_DECODE), + CSDC (CSDC_END, CSDC_CONT_NON_CONTINUOUS, CSDC_TRP_MBM, CSDC_DEC_DECODE), + CSDC (CSDC_END, CSDC_CONT_NON_CONTINUOUS, CSDC_TRP_MBM, CSDC_DEC_DECODE), + CSDC (CSDC_END, CSDC_CONT_NON_CONTINUOUS, CSDC_TRP_MBM, CSDC_DEC_DECODE), +}; + +STATIC CONST CSDC_DEFINITION mN25qCSDCDefTable[] = { + // Identification Operations + { SPINOR_OP_RDID, FALSE, FALSE, FALSE, FALSE, CS_CFG_MBM_SINGLE, + CSDC_TRP_SINGLE }, + // Register Operations + { SPINOR_OP_RDSR, FALSE, FALSE, FALSE, FALSE, CS_CFG_MBM_SINGLE, + CSDC_TRP_SINGLE }, + { SPINOR_OP_WRSR, FALSE, FALSE, FALSE, TRUE, CS_CFG_MBM_SINGLE, + CSDC_TRP_SINGLE }, + { SPINOR_OP_RD_ARRAY, TRUE, FALSE, FALSE, FALSE, CS_CFG_MBM_SINGLE, + CSDC_TRP_SINGLE }, + { SPINOR_OP_RDFSR, FALSE, FALSE, FALSE, FALSE, CS_CFG_MBM_SINGLE, + CSDC_TRP_SINGLE }, + { SPINOR_OP_RD_NVCFG, FALSE, FALSE, FALSE, FALSE, CS_CFG_MBM_SINGLE, + CSDC_TRP_SINGLE }, + { SPINOR_OP_RD_VCR, FALSE, FALSE, FALSE, FALSE, CS_CFG_MBM_SINGLE, + CSDC_TRP_SINGLE }, + { SPINOR_OP_RD_EVCR, FALSE, FALSE, FALSE, FALSE, CS_CFG_MBM_SINGLE, + CSDC_TRP_SINGLE }, + // Read Operations + { SPINOR_OP_READ_4B, TRUE, TRUE, FALSE, FALSE, CS_CFG_MBM_SINGLE, + CSDC_TRP_SINGLE }, + // Write Operations + { SPINOR_OP_PP, TRUE, FALSE, FALSE, TRUE, CS_CFG_MBM_SINGLE, + CSDC_TRP_SINGLE }, + { SPINOR_OP_PP_1_1_4, TRUE, FALSE, FALSE, TRUE, CS_CFG_MBM_QUAD, + CSDC_TRP_SINGLE }, + // Erase Operations + { SPINOR_OP_SE, FALSE, FALSE, FALSE, TRUE, CS_CFG_MBM_SINGLE, + CSDC_TRP_SINGLE }, +}; + +STATIC CONST NOR_FLASH_INSTANCE mNorFlashInstanceTemplate = { + NOR_FLASH_SIGNATURE, // Signature + NULL, // Handle ... NEED TO BE FILLED + + FALSE, // Initialized + NULL, // Initialize + + 0, // HostRegisterBaseAddress ... NEED TO BE FILLED + 0, // DeviceBaseAddress ... NEED TO BE FILLED + 0, // RegionBaseAddress ... NEED TO BE FILLED + 0, // Size ... NEED TO BE FILLED + 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, 0x0, 0x0, 0x0, 0x0, 0x0 } }, + }, + 0, // Index + { + END_DEVICE_PATH_TYPE, + END_ENTIRE_DEVICE_PATH_SUBTYPE, + { sizeof (EFI_DEVICE_PATH_PROTOCOL), 0 } + } + }, // DevicePath + 0 // Flags +}; + +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 != NULL); + + Instance = AllocateRuntimeCopyPool (sizeof mNorFlashInstanceTemplate, + &mNorFlashInstanceTemplate); + if (Instance == NULL) { + return EFI_OUT_OF_RESOURCES; + } + + Instance->HostRegisterBaseAddress = HostRegisterBase; + Instance->DeviceBaseAddress = NorFlashDeviceBase; + Instance->RegionBaseAddress = NorFlashRegionBase; + Instance->Size = NorFlashSize; + Instance->BlockSize = BlockSize; + Instance->LastBlock = (NorFlashSize / BlockSize) - 1; + + Instance->OffsetLba = (NorFlashRegionBase - NorFlashDeviceBase) / BlockSize; + + CopyGuid (&Instance->DevicePath.Vendor.Guid, &gEfiCallerIdGuid); + Instance->DevicePath.Index = (UINT8)Index; + + NorFlashReset (Instance); + + NorFlashReadID (Instance, JedecId); + Status = NorFlashGetInfo (JedecId, &FlashInfo, FALSE); + if (EFI_ERROR (Status)) { + goto FreeInstance; + } + + NorFlashPrintInfo (FlashInfo); + + Instance->Flags = 0; + if (FlashInfo->Flags & NOR_FLASH_WRITE_FSR) { + Instance->Flags = NOR_FLASH_POLL_FSR; + } + + Instance->ShadowBuffer = AllocateRuntimePool (BlockSize); + if (Instance->ShadowBuffer == NULL) { + Status = EFI_OUT_OF_RESOURCES; + goto FreeInstance; + } + + if (HasVarStore) { + Instance->Initialize = NorFlashFvbInitialize; + } + + *NorFlashInstance = Instance; + FreePool (FlashInfo); + return EFI_SUCCESS; + +FreeInstance: + FreePool (Instance); + return Status; +} + +STATIC +EFI_STATUS +NorFlashSetHostCSDC ( + IN NOR_FLASH_INSTANCE *Instance, + IN BOOLEAN ReadWrite, + IN CONST UINT16 CSDC[ARRAY_SIZE (mFip006NullCmdSeq)] + ) +{ + EFI_PHYSICAL_ADDRESS Dst; + UINTN Index; + + Dst = Instance->HostRegisterBaseAddress + + (ReadWrite ? FIP006_REG_CS_WR : FIP006_REG_CS_RD); + for (Index = 0; Index < ARRAY_SIZE (mFip006NullCmdSeq); Index++) { + MmioWrite16 (Dst + (Index << 1), CSDC[Index]); + } + return EFI_SUCCESS; +} + +STATIC +CONST CSDC_DEFINITION * +NorFlashGetCmdDef ( + IN NOR_FLASH_INSTANCE *Instance, + IN UINT8 Code + ) +{ + CONST CSDC_DEFINITION *Cmd; + UINTN Index; + + Cmd = NULL; + for (Index = 0; Index < ARRAY_SIZE (mN25qCSDCDefTable); Index++) { + if (Code == mN25qCSDCDefTable[Index].Code) { + Cmd = &mN25qCSDCDefTable[Index]; + break; + } + } + return Cmd; +} + +STATIC +EFI_STATUS +GenCSDC ( + IN UINT8 Cmd, + IN BOOLEAN AddrAccess, + IN BOOLEAN AddrMode4Byte, + IN BOOLEAN HighZ, + IN UINT8 TransferMode, + OUT UINT16 *CmdSeq + ) +{ + UINTN Index; + + if (!CmdSeq) { + return EFI_INVALID_PARAMETER; + } + + Index = 0; + CopyMem (CmdSeq, mFip006NullCmdSeq, sizeof (mFip006NullCmdSeq)); + + CmdSeq[Index++] = CSDC (Cmd, CSDC_CONT_NON_CONTINUOUS, TransferMode, + CSDC_DEC_LEAVE_ASIS); + if (AddrAccess) { + if (AddrMode4Byte) { + CmdSeq[Index++] = CSDC (CSDC_ADDRESS_31_24, CSDC_CONT_NON_CONTINUOUS, + TransferMode, CSDC_DEC_DECODE); + } + CmdSeq[Index++] = CSDC (CSDC_ADDRESS_23_16, CSDC_CONT_NON_CONTINUOUS, + TransferMode, CSDC_DEC_DECODE); + CmdSeq[Index++] = CSDC (CSDC_ADDRESS_15_8, CSDC_CONT_NON_CONTINUOUS, + TransferMode, CSDC_DEC_DECODE); + CmdSeq[Index++] = CSDC (CSDC_ADDRESS_7_0, CSDC_CONT_NON_CONTINUOUS, + TransferMode, CSDC_DEC_DECODE); + } + if (HighZ) { + CmdSeq[Index++] = CSDC (CSDC_HIGH_Z, CSDC_CONT_NON_CONTINUOUS, + TransferMode, CSDC_DEC_DECODE); + } + + return EFI_SUCCESS; +} + +STATIC +EFI_STATUS +NorFlashSetHostCommand ( + IN NOR_FLASH_INSTANCE *Instance, + IN UINT8 Code + ) +{ + CONST CSDC_DEFINITION *Cmd; + UINT16 CSDC[ARRAY_SIZE (mFip006NullCmdSeq)]; + + Cmd = NorFlashGetCmdDef (Instance, Code); + if (Cmd == NULL) { + return EFI_INVALID_PARAMETER; + } + GenCSDC ( + Cmd->Code, + Cmd->AddrAccess, + Cmd->AddrMode4Byte, + Cmd->HighZ, + Cmd->CsdcTrp, + CSDC + ); + NorFlashSetHostCSDC (Instance, Cmd->ReadWrite, CSDC); + return EFI_SUCCESS; +} + +STATIC +UINT8 +NorFlashReadStatusRegister ( + IN NOR_FLASH_INSTANCE *Instance + ) +{ + UINT8 StatusRegister; + + NorFlashSetHostCommand (Instance, SPINOR_OP_RDSR); + StatusRegister = MmioRead8 (Instance->RegionBaseAddress); + NorFlashSetHostCommand (Instance, SPINOR_OP_READ_4B); + return StatusRegister; +} + +STATIC +EFI_STATUS +NorFlashWaitProgramErase ( + IN NOR_FLASH_INSTANCE *Instance + ) +{ + BOOLEAN SRegDone; + BOOLEAN FSRegDone; + + DEBUG ((DEBUG_BLKIO, "NorFlashWaitProgramErase()\n")); + + do { + SRegDone = (NorFlashReadStatusRegister (Instance) & SPINOR_SR_WIP) == 0; + FSRegDone = TRUE; + if (Instance->Flags & NOR_FLASH_POLL_FSR) { + NorFlashSetHostCommand (Instance, SPINOR_OP_RDFSR); + FSRegDone = (MmioRead8 (Instance->RegionBaseAddress) & + SPINOR_FSR_READY) != 0; + } + } while (!SRegDone || !FSRegDone); + NorFlashSetHostCommand (Instance, SPINOR_OP_READ_4B); + return EFI_SUCCESS; +} + +// TODO: implement lock checking +STATIC +BOOLEAN +NorFlashBlockIsLocked ( + IN NOR_FLASH_INSTANCE *Instance, + IN UINTN BlockAddress + ) +{ + return FALSE; +} + +// TODO: implement sector unlocking +STATIC +EFI_STATUS +NorFlashUnlockSingleBlock ( + IN NOR_FLASH_INSTANCE *Instance, + IN UINTN BlockAddress + ) +{ + return EFI_SUCCESS; +} + +STATIC +EFI_STATUS +NorFlashUnlockSingleBlockIfNecessary ( + IN NOR_FLASH_INSTANCE *Instance, + IN UINTN BlockAddress + ) +{ + EFI_STATUS Status; + + Status = EFI_SUCCESS; + + if (NorFlashBlockIsLocked (Instance, BlockAddress) == TRUE) { + Status = NorFlashUnlockSingleBlock (Instance, BlockAddress); + } + + return Status; +} + +STATIC +EFI_STATUS +NorFlashEnableWrite ( + IN NOR_FLASH_INSTANCE *Instance + ) +{ + EFI_STATUS Status; + UINT8 StatusRegister; + UINTN Retry; + + DEBUG ((DEBUG_BLKIO, "NorFlashEnableWrite()\n")); + + Status = EFI_DEVICE_ERROR; + Retry = NOR_FLASH_ERASE_RETRY; + + NorFlashSetHostCSDC (Instance, TRUE, mFip006NullCmdSeq); + while (Retry > 0 && EFI_ERROR (Status)) { + MmioWrite8 (Instance->RegionBaseAddress, SPINOR_OP_WREN); + MemoryFence (); + StatusRegister = NorFlashReadStatusRegister (Instance); + Status = (StatusRegister & BIT1) ? EFI_SUCCESS : EFI_DEVICE_ERROR; + Retry--; + } + return Status; +} + +STATIC +EFI_STATUS +NorFlashDisableWrite ( + IN NOR_FLASH_INSTANCE *Instance + ) +{ + EFI_STATUS Status; + UINT8 StatusRegister; + UINTN Retry; + + DEBUG ((DEBUG_BLKIO, "NorFlashDisableWrite()\n")); + + Status = EFI_DEVICE_ERROR; + Retry = NOR_FLASH_ERASE_RETRY; + + NorFlashSetHostCSDC (Instance, TRUE, mFip006NullCmdSeq); + while (Retry > 0 && EFI_ERROR (Status)) { + MmioWrite8 (Instance->RegionBaseAddress, SPINOR_OP_WRDIS); + MemoryFence (); + StatusRegister = NorFlashReadStatusRegister (Instance); + Status = (StatusRegister & BIT1) ? EFI_DEVICE_ERROR : EFI_SUCCESS; + Retry--; + } + return Status; +} + +/** + * The following function presumes that the block has already been unlocked. + **/ +STATIC +EFI_STATUS +NorFlashEraseSingleBlock ( + IN NOR_FLASH_INSTANCE *Instance, + IN UINTN BlockAddress + ) +{ + + DEBUG ((DEBUG_BLKIO, "NorFlashEraseSingleBlock(BlockAddress=0x%08x)\n", + BlockAddress)); + + if (EFI_ERROR (NorFlashEnableWrite (Instance))) { + return EFI_DEVICE_ERROR; + } + + // + // The virtual address chosen by the OS may have a different offset modulo + // 16 MB than the physical address, so we need to subtract the region base + // address before we can mask off a block index. Note that the relative + // offset between device base address and region base address may have changed + // as well, so we cannot use the device base address directly. + // + BlockAddress -= Instance->RegionBaseAddress; + BlockAddress += Instance->OffsetLba * Instance->BlockSize; + + NorFlashSetHostCSDC (Instance, TRUE, mFip006NullCmdSeq); + MmioWrite32 (Instance->DeviceBaseAddress, + SwapBytes32 (BlockAddress & 0x00FFFFFF) | SPINOR_OP_SE); + NorFlashWaitProgramErase (Instance); + NorFlashSetHostCSDC (Instance, TRUE, mFip006NullCmdSeq); + + if (EFI_ERROR (NorFlashDisableWrite (Instance))) { + return EFI_DEVICE_ERROR; + } + return EFI_SUCCESS; +} + +/** + * This function unlock and erase an entire NOR Flash block. + **/ +EFI_STATUS +NorFlashUnlockAndEraseSingleBlock ( + IN NOR_FLASH_INSTANCE *Instance, + IN UINTN BlockAddress + ) +{ + EFI_STATUS Status; + UINTN Index; + NOR_FLASH_LOCK_CONTEXT Lock; + + NorFlashLock (&Lock); + + Index = 0; + // The block erase might fail a first time (SW bug ?). Retry it ... + do { + // Unlock the block if we have to + Status = NorFlashUnlockSingleBlockIfNecessary (Instance, BlockAddress); + if (EFI_ERROR (Status)) { + break; + } + Status = NorFlashEraseSingleBlock (Instance, BlockAddress); + Index++; + } while ((Index < NOR_FLASH_ERASE_RETRY) && (Status == EFI_WRITE_PROTECTED)); + + if (Index == NOR_FLASH_ERASE_RETRY) { + DEBUG ((DEBUG_ERROR, + "EraseSingleBlock(BlockAddress=0x%08x: Block Locked Error (try to erase %d times)\n", + BlockAddress,Index)); + } + + NorFlashUnlock (&Lock); + + return Status; +} + +STATIC +EFI_STATUS +NorFlashWriteSingleWord ( + IN NOR_FLASH_INSTANCE *Instance, + IN UINTN WordAddress, + IN UINT32 WriteData + ) +{ + EFI_STATUS Status; + + DEBUG ((DEBUG_BLKIO, + "NorFlashWriteSingleWord(WordAddress=0x%08x, WriteData=0x%08x)\n", + WordAddress, WriteData)); + + Status = EFI_SUCCESS; + + if (EFI_ERROR (NorFlashEnableWrite (Instance))) { + return EFI_DEVICE_ERROR; + } + NorFlashSetHostCommand (Instance, SPINOR_OP_PP); + MmioWrite32 (WordAddress, WriteData); + NorFlashWaitProgramErase (Instance); + + NorFlashDisableWrite (Instance); + NorFlashSetHostCSDC (Instance, TRUE, mFip006NullCmdSeq); + return Status; +} + +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 = EFI_SUCCESS; + + // Get the physical address of the block + BlockAddress = GET_NOR_BLOCK_ADDRESS (Instance->RegionBaseAddress, Lba, + BlockSizeInWords * 4); + + // Start writing from the first address at the start of the block + WordAddress = BlockAddress; + + NorFlashLock (&Lock); + + Status = NorFlashUnlockAndEraseSingleBlock (Instance, BlockAddress); + if (EFI_ERROR (Status)) { + DEBUG ((DEBUG_ERROR, + "WriteSingleBlock: ERROR - Failed to Unlock and Erase the single block at 0x%X\n", + BlockAddress)); + goto EXIT; + } + + for (WordIndex=0; + WordIndex < BlockSizeInWords; + WordIndex++, DataBuffer++, WordAddress += 4) { + Status = NorFlashWriteSingleWord (Instance, WordAddress, *DataBuffer); + 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 = \"%r\".\n", + WordAddress, Status)); + } + return Status; +} + +EFI_STATUS +NorFlashWriteBlocks ( + IN NOR_FLASH_INSTANCE *Instance, + IN EFI_LBA Lba, + IN UINTN BufferSizeInBytes, + IN VOID *Buffer + ) +{ + UINT32 *pWriteBuffer; + EFI_STATUS Status = EFI_SUCCESS; + EFI_LBA CurrentBlock; + UINT32 BlockSizeInWords; + UINT32 NumBlocks; + UINT32 BlockCount; + + // The buffer must be valid + if (Buffer == NULL) { + return EFI_INVALID_PARAMETER; + } + + // We must have some bytes to read + DEBUG ((DEBUG_BLKIO, "NorFlashWriteBlocks: BufferSizeInBytes=0x%x\n", + BufferSizeInBytes)); + if (BufferSizeInBytes == 0) { + return EFI_BAD_BUFFER_SIZE; + } + + // The size of the buffer must be a multiple of the block size + DEBUG ((DEBUG_BLKIO, "NorFlashWriteBlocks: BlockSize in bytes =0x%x\n", + Instance->BlockSize)); + if ((BufferSizeInBytes % Instance->BlockSize) != 0) { + return EFI_BAD_BUFFER_SIZE; + } + + // All blocks must be within the device + NumBlocks = ((UINT32)BufferSizeInBytes) / Instance->BlockSize ; + + DEBUG ((DEBUG_BLKIO, + "NorFlashWriteBlocks: NumBlocks=%d, LastBlock=%ld, Lba=%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)) == 0); + + BlockSizeInWords = 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 *ReadBuffer + pWriteBuffer = (UINT32 *)Buffer; + + CurrentBlock = Lba; + for (BlockCount = 0; + BlockCount < NumBlocks; + BlockCount++, CurrentBlock++, pWriteBuffer += BlockSizeInWords) { + + DEBUG ((DEBUG_BLKIO, "NorFlashWriteBlocks: Writing block #%d\n", + (UINTN)CurrentBlock)); + + Status = NorFlashWriteFullBlock (Instance, CurrentBlock, pWriteBuffer, + BlockSizeInWords); + + if (EFI_ERROR (Status)) { + break; + } + } + + DEBUG ((DEBUG_BLKIO, "NorFlashWriteBlocks: Exit Status = \"%r\".\n", Status)); + return Status; +} + +EFI_STATUS +NorFlashReadBlocks ( + IN NOR_FLASH_INSTANCE *Instance, + IN EFI_LBA Lba, + IN UINTN BufferSizeInBytes, + OUT VOID *Buffer + ) +{ + UINT32 NumBlocks; + UINTN StartAddress; + + DEBUG ((DEBUG_BLKIO, + "NorFlashReadBlocks: BufferSize=0x%xB BlockSize=0x%xB LastBlock=%ld, Lba=%ld.\n", + BufferSizeInBytes, Instance->BlockSize, Instance->LastBlock, + Lba)); + + // The buffer must be valid + if (Buffer == NULL) { + return EFI_INVALID_PARAMETER; + } + + // Return if we have not any byte to read + if (BufferSizeInBytes == 0) { + return EFI_SUCCESS; + } + + // The size of the buffer must be a multiple of the block size + if ((BufferSizeInBytes % Instance->BlockSize) != 0) { + return EFI_BAD_BUFFER_SIZE; + } + + // All blocks must be within the device + NumBlocks = ((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 = GET_NOR_BLOCK_ADDRESS (Instance->RegionBaseAddress, Lba, + Instance->BlockSize); + + // Put the device into Read Array mode + NorFlashSetHostCommand (Instance, SPINOR_OP_READ_4B); + NorFlashSetHostCSDC (Instance, TRUE, mFip006NullCmdSeq); + + // Readout the data + CopyMem(Buffer, (UINTN *)StartAddress, BufferSizeInBytes); + + return EFI_SUCCESS; +} + +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 == NULL) { + return EFI_INVALID_PARAMETER; + } + + // Return if we have not any byte to read + if (BufferSizeInBytes == 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 = GET_NOR_BLOCK_ADDRESS (Instance->RegionBaseAddress, Lba, + Instance->BlockSize); + + // Put the device into Read Array mode + NorFlashSetHostCommand (Instance, SPINOR_OP_READ_4B); + NorFlashSetHostCSDC (Instance, TRUE, mFip006NullCmdSeq); + + // Readout the data + CopyMem (Buffer, (UINTN *)(StartAddress + Offset), BufferSizeInBytes); + + return EFI_SUCCESS; +} + +/* + Write a full or portion of a block. It must not span block boundaries; + that is, Offset + *NumBytes <= Instance->BlockSize. +*/ +EFI_STATUS +NorFlashWriteSingleBlock ( + IN NOR_FLASH_INSTANCE *Instance, + IN EFI_LBA Lba, + IN UINTN Offset, + IN OUT UINTN *NumBytes, + IN UINT8 *Buffer + ) +{ + EFI_STATUS TempStatus; + UINT32 Tmp; + UINT32 TmpBuf; + UINT32 WordToWrite; + UINT32 Mask; + BOOLEAN DoErase; + UINTN BytesToWrite; + UINTN CurOffset; + UINTN WordAddr; + UINTN BlockSize; + UINTN BlockAddress; + UINTN PrevBlockAddress; + + PrevBlockAddress = 0; + + if (!Instance->Initialized && Instance->Initialize) { + Instance->Initialize(Instance); + } + + DEBUG ((DEBUG_BLKIO, + "NorFlashWriteSingleBlock(Parameters: Lba=%ld, Offset=0x%x, *NumBytes=0x%x, Buffer @ 0x%08x)\n", + Lba, Offset, *NumBytes, Buffer)); + + // Cache the block size to avoid de-referencing pointers all the time + BlockSize = Instance->BlockSize; + + // The write must not span block boundaries. + // We need to check each variable individually because adding two large + // values together overflows. + if (Offset >= BlockSize || + *NumBytes > BlockSize || + (Offset + *NumBytes) > BlockSize) { + DEBUG ((DEBUG_ERROR, + "NorFlashWriteSingleBlock: ERROR - EFI_BAD_BUFFER_SIZE: (Offset=0x%x + NumBytes=0x%x) > BlockSize=0x%x\n", + Offset, *NumBytes, BlockSize )); + return EFI_BAD_BUFFER_SIZE; + } + + // We must have some bytes to write + if (*NumBytes == 0) { + DEBUG ((DEBUG_ERROR, + "NorFlashWriteSingleBlock: ERROR - EFI_BAD_BUFFER_SIZE: (Offset=0x%x + NumBytes=0x%x) > BlockSize=0x%x\n", + Offset, *NumBytes, BlockSize )); + return EFI_BAD_BUFFER_SIZE; + } + + // 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) { + // 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 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 = FALSE; + BytesToWrite = *NumBytes; + CurOffset = Offset; + + while (BytesToWrite > 0) { + // Read full word from NOR, splice as required. A word is the smallest + // unit we can write. + TempStatus = NorFlashRead (Instance, Lba, CurOffset & ~(0x3), sizeof(Tmp), + &Tmp); + if (EFI_ERROR (TempStatus)) { + return EFI_DEVICE_ERROR; + } + + // Physical address of word in NOR to write. + WordAddr = (CurOffset & ~(0x3)) + + GET_NOR_BLOCK_ADDRESS (Instance->RegionBaseAddress, Lba, + BlockSize); + + // The word of data that is to be written. + TmpBuf = *((UINT32*)(Buffer + (*NumBytes - BytesToWrite))); + + // First do word aligned chunks. + if ((CurOffset & 0x3) == 0) { + if (BytesToWrite >= 4) { + // Is the destination still in 'erased' state? + if (~Tmp != 0) { + // Check to see if we are only changing bits to zero. + if ((Tmp ^ TmpBuf) & TmpBuf) { + DoErase = TRUE; + break; + } + } + // Write this word to NOR + WordToWrite = TmpBuf; + CurOffset += sizeof(TmpBuf); + BytesToWrite -= sizeof(TmpBuf); + } else { + // BytesToWrite < 4. Do small writes and left-overs + Mask = ~((~0) << (BytesToWrite * 8)); + // Mask out the bytes we want. + TmpBuf &= Mask; + // Is the destination still in 'erased' state? + if ((Tmp & Mask) != Mask) { + // Check to see if we are only changing bits to zero. + if ((Tmp ^ TmpBuf) & TmpBuf) { + DoErase = TRUE; + break; + } + } + // Merge old and new data. Write merged word to NOR + WordToWrite = (Tmp & ~Mask) | TmpBuf; + CurOffset += BytesToWrite; + BytesToWrite = 0; + } + } else { + // Do multiple words, but starting unaligned. + if (BytesToWrite > (4 - (CurOffset & 0x3))) { + Mask = ((~0) << ((CurOffset & 0x3) * 8)); + // Mask out the bytes we want. + TmpBuf &= Mask; + // Is the destination still in 'erased' state? + if ((Tmp & Mask) != Mask) { + // Check to see if we are only changing bits to zero. + if ((Tmp ^ TmpBuf) & TmpBuf) { + DoErase = TRUE; + break; + } + } + // Merge old and new data. Write merged word to NOR + WordToWrite = (Tmp & ~Mask) | TmpBuf; + BytesToWrite -= (4 - (CurOffset & 0x3)); + CurOffset += (4 - (CurOffset & 0x3)); + } else { + // Unaligned and fits in one word. + Mask = (~((~0) << (BytesToWrite * 8))) << ((CurOffset & 0x3) * 8); + // Mask out the bytes we want. + TmpBuf = (TmpBuf << ((CurOffset & 0x3) * 8)) & Mask; + // Is the destination still in 'erased' state? + if ((Tmp & Mask) != Mask) { + // Check to see if we are only changing bits to zero. + if ((Tmp ^ TmpBuf) & TmpBuf) { + DoErase = TRUE; + break; + } + } + // Merge old and new data. Write merged word to NOR + WordToWrite = (Tmp & ~Mask) | TmpBuf; + CurOffset += BytesToWrite; + BytesToWrite = 0; + } + } + + // + // Write the word to NOR. + // + + BlockAddress = GET_NOR_BLOCK_ADDRESS (Instance->RegionBaseAddress, Lba, + BlockSize); + if (BlockAddress != PrevBlockAddress) { + TempStatus = NorFlashUnlockSingleBlockIfNecessary (Instance, + BlockAddress); + if (EFI_ERROR (TempStatus)) { + return EFI_DEVICE_ERROR; + } + PrevBlockAddress = BlockAddress; + } + TempStatus = NorFlashWriteSingleWord (Instance, WordAddr, WordToWrite); + if (EFI_ERROR (TempStatus)) { + return EFI_DEVICE_ERROR; + } + } + // Exit if we got here and could write all the data. Otherwise do the + // Erase-Write cycle. + if (!DoErase) { + return EFI_SUCCESS; + } + } + + // 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; + } + + // Read NOR Flash data into shadow buffer + TempStatus = NorFlashReadBlocks (Instance, Lba, BlockSize, + Instance->ShadowBuffer); + if (EFI_ERROR (TempStatus)) { + // 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); + + // Write the modified buffer back to the NorFlash + TempStatus = NorFlashWriteBlocks (Instance, Lba, BlockSize, + Instance->ShadowBuffer); + if (EFI_ERROR (TempStatus)) { + // Return one of the pre-approved error statuses + return EFI_DEVICE_ERROR; + } + + return EFI_SUCCESS; +} + +EFI_STATUS +NorFlashReset ( + IN NOR_FLASH_INSTANCE *Instance + ) +{ + FIP006_CS_CFG CsCfg; + + DEBUG ((DEBUG_BLKIO, "NorFlashReset()\n")); + CsCfg.Raw = MmioRead32 (Instance->HostRegisterBaseAddress + + FIP006_REG_CS_CFG); + CsCfg.Reg.MBM = CS_CFG_MBM_SINGLE; + CsCfg.Reg.SRAM = CS_CFG_SRAM_RW; + MmioWrite32 (Instance->HostRegisterBaseAddress + FIP006_REG_CS_CFG, + CsCfg.Raw); + NorFlashSetHostCommand (Instance, SPINOR_OP_READ_4B); + NorFlashSetHostCSDC (Instance, TRUE, mFip006NullCmdSeq); + return EFI_SUCCESS; +} + +EFI_STATUS +NorFlashReadID ( + IN NOR_FLASH_INSTANCE *Instance, + OUT UINT8 JedecId[3] + ) +{ + if (Instance == NULL || JedecId == NULL) { + return EFI_INVALID_PARAMETER; + } + + NorFlashSetHostCommand (Instance, SPINOR_OP_RDID); + JedecId[0] = MmioRead8 (Instance->DeviceBaseAddress); + JedecId[1] = MmioRead8 (Instance->DeviceBaseAddress + 1); + JedecId[2] = MmioRead8 (Instance->DeviceBaseAddress + 2); + NorFlashSetHostCommand (Instance, SPINOR_OP_READ_4B); + return EFI_SUCCESS; +} diff --git a/Silicon/Socionext/SynQuacer/Drivers/Fip006Dxe/NorFlashDxe.h b/Silicon/Socionext/SynQuacer/Drivers/Fip006Dxe/NorFlash.h similarity index 88% rename from Silicon/Socionext/SynQuacer/Drivers/Fip006Dxe/NorFlashDxe.h rename to Silicon/Socionext/SynQuacer/Drivers/Fip006Dxe/NorFlash.h index 20e74b0320ce..61b8e6a08fa0 100644 --- a/Silicon/Socionext/SynQuacer/Drivers/Fip006Dxe/NorFlashDxe.h +++ b/Silicon/Socionext/SynQuacer/Drivers/Fip006Dxe/NorFlash.h @@ -27,11 +27,9 @@ #include #include -#include #include +#include #include -#include -#include #include "Fip006Reg.h" @@ -112,13 +110,27 @@ struct _NOR_FLASH_INSTANCE { NOR_FLASH_DEVICE_PATH DevicePath; - CONST CSDC_DEFINITION *CmdTable; - UINTN CmdTableSize; - UINT32 Flags; #define NOR_FLASH_POLL_FSR BIT0 }; +typedef struct { + EFI_TPL OriginalTPL; + BOOLEAN InterruptsEnabled; +} NOR_FLASH_LOCK_CONTEXT; + +VOID +EFIAPI +NorFlashLock ( + NOR_FLASH_LOCK_CONTEXT *Context + ); + +VOID +EFIAPI +NorFlashUnlock ( + NOR_FLASH_LOCK_CONTEXT *Context + ); + EFI_STATUS NorFlashReadCfiData ( IN UINTN DeviceBaseAddress, @@ -135,14 +147,34 @@ NorFlashWriteBuffer ( IN UINT32 *Buffer ); -// -// NorFlashFvbDxe.c -// +extern UINTN mFlashNvStorageVariableBase; + +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 EFIAPI NorFlashFvbInitialize ( - IN NOR_FLASH_INSTANCE* Instance + IN NOR_FLASH_INSTANCE* Instance + ); + +EFI_STATUS +ValidateFvHeader ( + IN NOR_FLASH_INSTANCE *Instance + ); + +EFI_STATUS +InitializeFvAndVariableStoreHeaders ( + IN NOR_FLASH_INSTANCE *Instance ); EFI_STATUS diff --git a/Silicon/Socionext/SynQuacer/Drivers/Fip006Dxe/NorFlashDxe.c b/Silicon/Socionext/SynQuacer/Drivers/Fip006Dxe/NorFlashDxe.c index e52ab52d8cf7..6c07799b22d8 100644 --- a/Silicon/Socionext/SynQuacer/Drivers/Fip006Dxe/NorFlashDxe.c +++ b/Silicon/Socionext/SynQuacer/Drivers/Fip006Dxe/NorFlashDxe.c @@ -15,15 +15,16 @@ **/ #include +#include +#include #include #include #include #include #include +#include -#include "NorFlashDxe.h" - -STATIC EFI_EVENT mNorFlashVirtualAddrChangeEvent; +#include "NorFlash.h" // // Global variable declarations @@ -31,1035 +32,129 @@ STATIC EFI_EVENT mNorFlashVirtualAddrChangeEvent; STATIC NOR_FLASH_INSTANCE **mNorFlashInstances; STATIC UINT32 mNorFlashDeviceCount; -STATIC CONST UINT16 mFip006NullCmdSeq[] = { - CSDC (CSDC_END, CSDC_CONT_NON_CONTINUOUS, CSDC_TRP_MBM, CSDC_DEC_DECODE), - CSDC (CSDC_END, CSDC_CONT_NON_CONTINUOUS, CSDC_TRP_MBM, CSDC_DEC_DECODE), - CSDC (CSDC_END, CSDC_CONT_NON_CONTINUOUS, CSDC_TRP_MBM, CSDC_DEC_DECODE), - CSDC (CSDC_END, CSDC_CONT_NON_CONTINUOUS, CSDC_TRP_MBM, CSDC_DEC_DECODE), - CSDC (CSDC_END, CSDC_CONT_NON_CONTINUOUS, CSDC_TRP_MBM, CSDC_DEC_DECODE), - CSDC (CSDC_END, CSDC_CONT_NON_CONTINUOUS, CSDC_TRP_MBM, CSDC_DEC_DECODE), - CSDC (CSDC_END, CSDC_CONT_NON_CONTINUOUS, CSDC_TRP_MBM, CSDC_DEC_DECODE), - CSDC (CSDC_END, CSDC_CONT_NON_CONTINUOUS, CSDC_TRP_MBM, CSDC_DEC_DECODE), -}; - -STATIC CONST CSDC_DEFINITION mN25qCSDCDefTable[] = { - // Identification Operations - { SPINOR_OP_RDID, FALSE, FALSE, FALSE, FALSE, CS_CFG_MBM_SINGLE, - CSDC_TRP_SINGLE }, - // Register Operations - { SPINOR_OP_RDSR, FALSE, FALSE, FALSE, FALSE, CS_CFG_MBM_SINGLE, - CSDC_TRP_SINGLE }, - { SPINOR_OP_WRSR, FALSE, FALSE, FALSE, TRUE, CS_CFG_MBM_SINGLE, - CSDC_TRP_SINGLE }, - { SPINOR_OP_RD_ARRAY, TRUE, FALSE, FALSE, FALSE, CS_CFG_MBM_SINGLE, - CSDC_TRP_SINGLE }, - { SPINOR_OP_RDFSR, FALSE, FALSE, FALSE, FALSE, CS_CFG_MBM_SINGLE, - CSDC_TRP_SINGLE }, - { SPINOR_OP_RD_NVCFG, FALSE, FALSE, FALSE, FALSE, CS_CFG_MBM_SINGLE, - CSDC_TRP_SINGLE }, - { SPINOR_OP_RD_VCR, FALSE, FALSE, FALSE, FALSE, CS_CFG_MBM_SINGLE, - CSDC_TRP_SINGLE }, - { SPINOR_OP_RD_EVCR, FALSE, FALSE, FALSE, FALSE, CS_CFG_MBM_SINGLE, - CSDC_TRP_SINGLE }, - // Read Operations - { SPINOR_OP_READ_4B, TRUE, TRUE, FALSE, FALSE, CS_CFG_MBM_SINGLE, - CSDC_TRP_SINGLE }, - // Write Operations - { SPINOR_OP_PP, TRUE, FALSE, FALSE, TRUE, CS_CFG_MBM_SINGLE, - CSDC_TRP_SINGLE }, - { SPINOR_OP_PP_1_1_4, TRUE, FALSE, FALSE, TRUE, CS_CFG_MBM_QUAD, - CSDC_TRP_SINGLE }, - // Erase Operations - { SPINOR_OP_SE, FALSE, FALSE, FALSE, TRUE, CS_CFG_MBM_SINGLE, - CSDC_TRP_SINGLE }, -}; - -STATIC -EFI_STATUS -NorFlashSetHostCSDC ( - IN NOR_FLASH_INSTANCE *Instance, - IN BOOLEAN ReadWrite, - IN CONST UINT16 CSDC[ARRAY_SIZE (mFip006NullCmdSeq)] - ) -{ - EFI_PHYSICAL_ADDRESS Dst; - UINTN Index; - - Dst = Instance->HostRegisterBaseAddress - + (ReadWrite ? FIP006_REG_CS_WR : FIP006_REG_CS_RD); - for (Index = 0; Index < ARRAY_SIZE (mFip006NullCmdSeq); Index++) { - MmioWrite16 (Dst + (Index << 1), CSDC[Index]); - } - return EFI_SUCCESS; -} - -STATIC -CONST CSDC_DEFINITION * -NorFlashGetCmdDef ( - IN NOR_FLASH_INSTANCE *Instance, - IN UINT8 Code - ) -{ - CONST CSDC_DEFINITION *Cmd; - UINTN Index; - - Cmd = NULL; - for (Index = 0; Index < Instance->CmdTableSize; Index++) { - if (Code == Instance->CmdTable[Index].Code) { - Cmd = &Instance->CmdTable[Index]; - break; - } - } - return Cmd; -} - -STATIC -EFI_STATUS -GenCSDC ( - IN UINT8 Cmd, - IN BOOLEAN AddrAccess, - IN BOOLEAN AddrMode4Byte, - IN BOOLEAN HighZ, - IN UINT8 TransferMode, - OUT UINT16 *CmdSeq - ) -{ - UINTN Index; - - if (!CmdSeq) { - return EFI_INVALID_PARAMETER; - } - - Index = 0; - CopyMem (CmdSeq, mFip006NullCmdSeq, sizeof (mFip006NullCmdSeq)); - - CmdSeq[Index++] = CSDC (Cmd, CSDC_CONT_NON_CONTINUOUS, TransferMode, - CSDC_DEC_LEAVE_ASIS); - if (AddrAccess) { - if (AddrMode4Byte) { - CmdSeq[Index++] = CSDC (CSDC_ADDRESS_31_24, CSDC_CONT_NON_CONTINUOUS, - TransferMode, CSDC_DEC_DECODE); - } - CmdSeq[Index++] = CSDC (CSDC_ADDRESS_23_16, CSDC_CONT_NON_CONTINUOUS, - TransferMode, CSDC_DEC_DECODE); - CmdSeq[Index++] = CSDC (CSDC_ADDRESS_15_8, CSDC_CONT_NON_CONTINUOUS, - TransferMode, CSDC_DEC_DECODE); - CmdSeq[Index++] = CSDC (CSDC_ADDRESS_7_0, CSDC_CONT_NON_CONTINUOUS, - TransferMode, CSDC_DEC_DECODE); - } - if (HighZ) { - CmdSeq[Index++] = CSDC (CSDC_HIGH_Z, CSDC_CONT_NON_CONTINUOUS, - TransferMode, CSDC_DEC_DECODE); - } - - return EFI_SUCCESS; -} - -STATIC -EFI_STATUS -NorFlashSetHostCommand ( - IN NOR_FLASH_INSTANCE *Instance, - IN UINT8 Code - ) -{ - CONST CSDC_DEFINITION *Cmd; - UINT16 CSDC[ARRAY_SIZE (mFip006NullCmdSeq)]; - - Cmd = NorFlashGetCmdDef (Instance, Code); - if (Cmd == NULL) { - return EFI_INVALID_PARAMETER; - } - GenCSDC ( - Cmd->Code, - Cmd->AddrAccess, - Cmd->AddrMode4Byte, - Cmd->HighZ, - Cmd->CsdcTrp, - CSDC - ); - NorFlashSetHostCSDC (Instance, Cmd->ReadWrite, CSDC); - return EFI_SUCCESS; -} - -STATIC -UINT8 -NorFlashReadStatusRegister ( - IN NOR_FLASH_INSTANCE *Instance - ) -{ - UINT8 StatusRegister; - - NorFlashSetHostCommand (Instance, SPINOR_OP_RDSR); - StatusRegister = MmioRead8 (Instance->RegionBaseAddress); - NorFlashSetHostCommand (Instance, SPINOR_OP_READ_4B); - return StatusRegister; -} - -STATIC -EFI_STATUS -NorFlashWaitProgramErase ( - IN NOR_FLASH_INSTANCE *Instance - ) -{ - BOOLEAN SRegDone; - BOOLEAN FSRegDone; - - DEBUG ((DEBUG_BLKIO, "NorFlashWaitProgramErase()\n")); - - do { - SRegDone = (NorFlashReadStatusRegister (Instance) & SPINOR_SR_WIP) == 0; - FSRegDone = TRUE; - if (Instance->Flags & NOR_FLASH_POLL_FSR) { - NorFlashSetHostCommand (Instance, SPINOR_OP_RDFSR); - FSRegDone = (MmioRead8 (Instance->RegionBaseAddress) & - SPINOR_FSR_READY) != 0; - } - } while (!SRegDone || !FSRegDone); - NorFlashSetHostCommand (Instance, SPINOR_OP_READ_4B); - return EFI_SUCCESS; -} - -// TODO: implement lock checking -STATIC -BOOLEAN -NorFlashBlockIsLocked ( - IN NOR_FLASH_INSTANCE *Instance, - IN UINTN BlockAddress - ) -{ - return FALSE; -} - -// TODO: implement sector unlocking -STATIC -EFI_STATUS -NorFlashUnlockSingleBlock ( - IN NOR_FLASH_INSTANCE *Instance, - IN UINTN BlockAddress - ) -{ - return EFI_SUCCESS; -} - -STATIC -EFI_STATUS -NorFlashUnlockSingleBlockIfNecessary ( - IN NOR_FLASH_INSTANCE *Instance, - IN UINTN BlockAddress - ) -{ - EFI_STATUS Status; - - Status = EFI_SUCCESS; - - if (NorFlashBlockIsLocked (Instance, BlockAddress) == TRUE) { - Status = NorFlashUnlockSingleBlock (Instance, BlockAddress); - } - - return Status; -} - -STATIC -EFI_STATUS -NorFlashEnableWrite ( - IN NOR_FLASH_INSTANCE *Instance - ) -{ - EFI_STATUS Status; - UINT8 StatusRegister; - UINTN Retry; - - DEBUG ((DEBUG_BLKIO, "NorFlashEnableWrite()\n")); - - Status = EFI_DEVICE_ERROR; - Retry = NOR_FLASH_ERASE_RETRY; - - NorFlashSetHostCSDC (Instance, TRUE, mFip006NullCmdSeq); - while (Retry > 0 && EFI_ERROR (Status)) { - MmioWrite8 (Instance->RegionBaseAddress, SPINOR_OP_WREN); - MemoryFence (); - StatusRegister = NorFlashReadStatusRegister (Instance); - Status = (StatusRegister & BIT1) ? EFI_SUCCESS : EFI_DEVICE_ERROR; - Retry--; - } - return Status; -} +STATIC EFI_EVENT mNorFlashVirtualAddrChangeEvent; -STATIC EFI_STATUS -NorFlashDisableWrite ( - IN NOR_FLASH_INSTANCE *Instance +EFIAPI +NorFlashFvbInitialize ( + IN NOR_FLASH_INSTANCE* Instance ) { EFI_STATUS Status; - UINT8 StatusRegister; - UINTN Retry; - - DEBUG ((DEBUG_BLKIO, "NorFlashDisableWrite()\n")); - - Status = EFI_DEVICE_ERROR; - Retry = NOR_FLASH_ERASE_RETRY; - - NorFlashSetHostCSDC (Instance, TRUE, mFip006NullCmdSeq); - while (Retry > 0 && EFI_ERROR (Status)) { - MmioWrite8 (Instance->RegionBaseAddress, SPINOR_OP_WRDIS); - MemoryFence (); - StatusRegister = NorFlashReadStatusRegister (Instance); - Status = (StatusRegister & BIT1) ? EFI_DEVICE_ERROR : EFI_SUCCESS; - Retry--; - } - return Status; -} - -/** - * The following function presumes that the block has already been unlocked. - **/ -STATIC -EFI_STATUS -NorFlashEraseSingleBlock ( - IN NOR_FLASH_INSTANCE *Instance, - IN UINTN BlockAddress - ) -{ - - DEBUG ((DEBUG_BLKIO, "NorFlashEraseSingleBlock(BlockAddress=0x%08x)\n", - BlockAddress)); - - if (EFI_ERROR (NorFlashEnableWrite (Instance))) { - return EFI_DEVICE_ERROR; - } + UINT32 FvbNumLba; + EFI_BOOT_MODE BootMode; + UINTN RuntimeMmioRegionSize; + UINTN BlockSize; - // - // The virtual address chosen by the OS may have a different offset modulo - // 16 MB than the physical address, so we need to subtract the region base - // address before we can mask off a block index. Note that the relative - // offset between device base address and region base address may have changed - // as well, so we cannot use the device base address directly. - // - if (EfiAtRuntime()) { - BlockAddress -= Instance->RegionBaseAddress; - BlockAddress += Instance->OffsetLba * Instance->BlockSize; - } - - NorFlashSetHostCSDC (Instance, TRUE, mFip006NullCmdSeq); - MmioWrite32 (Instance->DeviceBaseAddress, - SwapBytes32 (BlockAddress & 0x00FFFFFF) | SPINOR_OP_SE); - NorFlashWaitProgramErase (Instance); - NorFlashSetHostCSDC (Instance, TRUE, mFip006NullCmdSeq); - - if (EFI_ERROR (NorFlashDisableWrite (Instance))) { - return EFI_DEVICE_ERROR; - } - return EFI_SUCCESS; -} - -/** - * This function unlock and erase an entire NOR Flash block. - **/ -EFI_STATUS -NorFlashUnlockAndEraseSingleBlock ( - IN NOR_FLASH_INSTANCE *Instance, - IN UINTN BlockAddress - ) -{ - EFI_STATUS Status; - UINTN Index; - EFI_TPL OriginalTPL; - BOOLEAN InterruptsEnabled; + DEBUG ((DEBUG_BLKIO,"NorFlashFvbInitialize\n")); - OriginalTPL = 0; - InterruptsEnabled = FALSE; + BlockSize = Instance->BlockSize; - if (!EfiAtRuntime ()) { - // Raise TPL to TPL_HIGH to stop anyone from interrupting us. - OriginalTPL = gBS->RaiseTPL (TPL_HIGH_LEVEL); + // FirmwareVolumeHeader->FvLength is declared to have the Variable area + // AND the FTW working area AND the FTW Spare contiguous. + ASSERT(PcdGet32(PcdFlashNvStorageVariableBase) + + PcdGet32(PcdFlashNvStorageVariableSize) == + PcdGet32(PcdFlashNvStorageFtwWorkingBase)); + ASSERT(PcdGet32(PcdFlashNvStorageFtwWorkingBase) + + PcdGet32(PcdFlashNvStorageFtwWorkingSize) == + 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) == 0); + ASSERT((PcdGet32(PcdFlashNvStorageFtwWorkingBase) % BlockSize) == 0); + ASSERT((PcdGet32(PcdFlashNvStorageFtwSpareBase) % BlockSize) == 0); + + + Instance->Initialized = TRUE; + mFlashNvStorageVariableBase = FixedPcdGet32 (PcdFlashNvStorageVariableBase); + + // Set the index of the first LBA for the FVB + Instance->StartLba = (PcdGet32 (PcdFlashNvStorageVariableBase) - + Instance->RegionBaseAddress) / BlockSize; + + BootMode = GetBootModeHob (); + if (BootMode == BOOT_WITH_DEFAULT_SETTINGS) { + Status = EFI_INVALID_PARAMETER; } else { - InterruptsEnabled = SaveAndDisableInterrupts (); - } - - Index = 0; - // The block erase might fail a first time (SW bug ?). Retry it ... - do { - // Unlock the block if we have to - Status = NorFlashUnlockSingleBlockIfNecessary (Instance, BlockAddress); - if (EFI_ERROR (Status)) { - break; + // 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->BlockSize; + + Status = FvbEraseBlocks (&Instance->FvbProtocol, (EFI_LBA)0, FvbNumLba, + EFI_LBA_LIST_TERMINATOR); + if (EFI_ERROR(Status)) { + return Status; } - Status = NorFlashEraseSingleBlock (Instance, BlockAddress); - Index++; - } while ((Index < NOR_FLASH_ERASE_RETRY) && (Status == EFI_WRITE_PROTECTED)); - - if (Index == NOR_FLASH_ERASE_RETRY) { - DEBUG ((DEBUG_ERROR, - "EraseSingleBlock(BlockAddress=0x%08x: Block Locked Error (try to erase %d times)\n", - BlockAddress,Index)); - } - if (!EfiAtRuntime ()) { - // Interruptions can resume. - gBS->RestoreTPL (OriginalTPL); - } else if (InterruptsEnabled) { - SetInterruptState (TRUE); - } - - return Status; -} - -STATIC -EFI_STATUS -NorFlashWriteSingleWord ( - IN NOR_FLASH_INSTANCE *Instance, - IN UINTN WordAddress, - IN UINT32 WriteData - ) -{ - EFI_STATUS Status; - - DEBUG ((DEBUG_BLKIO, - "NorFlashWriteSingleWord(WordAddress=0x%08x, WriteData=0x%08x)\n", - WordAddress, WriteData)); - - Status = EFI_SUCCESS; - - if (EFI_ERROR (NorFlashEnableWrite (Instance))) { - return EFI_DEVICE_ERROR; - } - NorFlashSetHostCommand (Instance, SPINOR_OP_PP); - MmioWrite32 (WordAddress, WriteData); - NorFlashWaitProgramErase (Instance); - - NorFlashDisableWrite (Instance); - NorFlashSetHostCSDC (Instance, TRUE, mFip006NullCmdSeq); - return Status; -} - -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; - EFI_TPL OriginalTPL; - BOOLEAN InterruptsEnabled; - - Status = EFI_SUCCESS; - OriginalTPL = 0; - InterruptsEnabled = FALSE; - - // Get the physical address of the block - BlockAddress = GET_NOR_BLOCK_ADDRESS (Instance->RegionBaseAddress, Lba, - BlockSizeInWords * 4); - - // Start writing from the first address at the start of the block - WordAddress = BlockAddress; - - if (!EfiAtRuntime ()) { - // Raise TPL to TPL_HIGH to stop anyone from interrupting us. - OriginalTPL = gBS->RaiseTPL (TPL_HIGH_LEVEL); - } else { - InterruptsEnabled = SaveAndDisableInterrupts (); - } - - Status = NorFlashUnlockAndEraseSingleBlock (Instance, BlockAddress); - if (EFI_ERROR (Status)) { - DEBUG ((DEBUG_ERROR, - "WriteSingleBlock: ERROR - Failed to Unlock and Erase the single block at 0x%X\n", - BlockAddress)); - goto EXIT; - } - - for (WordIndex=0; - WordIndex < BlockSizeInWords; - WordIndex++, DataBuffer++, WordAddress += 4) { - Status = NorFlashWriteSingleWord (Instance, WordAddress, *DataBuffer); - if (EFI_ERROR (Status)) { - goto EXIT; + // Install all appropriate headers + Status = InitializeFvAndVariableStoreHeaders (Instance); + if (EFI_ERROR(Status)) { + return Status; } } -EXIT: - if (!EfiAtRuntime ()) { - // Interruptions can resume. - gBS->RestoreTPL (OriginalTPL); - } else if (InterruptsEnabled) { - SetInterruptState (TRUE); - } - + // + // The driver implementing the variable read service can now be dispatched; + // the varstore headers are in place. + // + Status = gBS->InstallProtocolInterface (&gImageHandle, + &gEdkiiNvVarStoreFormattedGuid, + EFI_NATIVE_INTERFACE, + NULL); if (EFI_ERROR (Status)) { DEBUG ((DEBUG_ERROR, - "NOR FLASH Programming [WriteSingleBlock] failed at address 0x%08x. Exit Status = \"%r\".\n", - WordAddress, Status)); - } - return Status; -} - -EFI_STATUS -NorFlashWriteBlocks ( - IN NOR_FLASH_INSTANCE *Instance, - IN EFI_LBA Lba, - IN UINTN BufferSizeInBytes, - IN VOID *Buffer - ) -{ - UINT32 *pWriteBuffer; - EFI_STATUS Status = EFI_SUCCESS; - EFI_LBA CurrentBlock; - UINT32 BlockSizeInWords; - UINT32 NumBlocks; - UINT32 BlockCount; - - // The buffer must be valid - if (Buffer == NULL) { - return EFI_INVALID_PARAMETER; - } - - // We must have some bytes to read - DEBUG ((DEBUG_BLKIO, "NorFlashWriteBlocks: BufferSizeInBytes=0x%x\n", - BufferSizeInBytes)); - if (BufferSizeInBytes == 0) { - return EFI_BAD_BUFFER_SIZE; - } - - // The size of the buffer must be a multiple of the block size - DEBUG ((DEBUG_BLKIO, "NorFlashWriteBlocks: BlockSize in bytes =0x%x\n", - Instance->BlockSize)); - if ((BufferSizeInBytes % Instance->BlockSize) != 0) { - return EFI_BAD_BUFFER_SIZE; - } - - // All blocks must be within the device - NumBlocks = ((UINT32)BufferSizeInBytes) / Instance->BlockSize ; - - DEBUG ((DEBUG_BLKIO, - "NorFlashWriteBlocks: NumBlocks=%d, LastBlock=%ld, Lba=%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)) == 0); - - BlockSizeInWords = 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 *ReadBuffer - pWriteBuffer = (UINT32 *)Buffer; - - CurrentBlock = Lba; - for (BlockCount = 0; - BlockCount < NumBlocks; - BlockCount++, CurrentBlock++, pWriteBuffer += BlockSizeInWords) { - - DEBUG ((DEBUG_BLKIO, "NorFlashWriteBlocks: Writing block #%d\n", - (UINTN)CurrentBlock)); - - Status = NorFlashWriteFullBlock (Instance, CurrentBlock, pWriteBuffer, - BlockSizeInWords); - - if (EFI_ERROR (Status)) { - break; - } - } - - DEBUG ((DEBUG_BLKIO, "NorFlashWriteBlocks: Exit Status = \"%r\".\n", Status)); - return Status; -} - -EFI_STATUS -NorFlashReadBlocks ( - IN NOR_FLASH_INSTANCE *Instance, - IN EFI_LBA Lba, - IN UINTN BufferSizeInBytes, - OUT VOID *Buffer - ) -{ - UINT32 NumBlocks; - UINTN StartAddress; - - DEBUG ((DEBUG_BLKIO, - "NorFlashReadBlocks: BufferSize=0x%xB BlockSize=0x%xB LastBlock=%ld, Lba=%ld.\n", - BufferSizeInBytes, Instance->BlockSize, Instance->LastBlock, - Lba)); - - // The buffer must be valid - if (Buffer == NULL) { - return EFI_INVALID_PARAMETER; + "%a: Failed to install gEdkiiNvVarStoreFormattedGuid\n", + __FUNCTION__)); + return Status; } - // Return if we have not any byte to read - if (BufferSizeInBytes == 0) { - return EFI_SUCCESS; - } - - // The size of the buffer must be a multiple of the block size - if ((BufferSizeInBytes % Instance->BlockSize) != 0) { - return EFI_BAD_BUFFER_SIZE; - } - - // All blocks must be within the device - NumBlocks = ((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 = GET_NOR_BLOCK_ADDRESS (Instance->RegionBaseAddress, Lba, - Instance->BlockSize); - - // Put the device into Read Array mode - NorFlashSetHostCommand (Instance, SPINOR_OP_READ_4B); - NorFlashSetHostCSDC (Instance, TRUE, mFip006NullCmdSeq); - - // Readout the data - CopyMem(Buffer, (UINTN *)StartAddress, BufferSizeInBytes); - - return EFI_SUCCESS; -} - -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 == NULL) { - return EFI_INVALID_PARAMETER; - } - - // Return if we have not any byte to read - if (BufferSizeInBytes == 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 = GET_NOR_BLOCK_ADDRESS (Instance->RegionBaseAddress, Lba, - Instance->BlockSize); - - // Put the device into Read Array mode - NorFlashSetHostCommand (Instance, SPINOR_OP_READ_4B); - NorFlashSetHostCSDC (Instance, TRUE, mFip006NullCmdSeq); - - // Readout the data - CopyMem (Buffer, (UINTN *)(StartAddress + Offset), BufferSizeInBytes); - - return EFI_SUCCESS; -} - -/* - Write a full or portion of a block. It must not span block boundaries; - that is, Offset + *NumBytes <= Instance->BlockSize. -*/ -EFI_STATUS -NorFlashWriteSingleBlock ( - IN NOR_FLASH_INSTANCE *Instance, - IN EFI_LBA Lba, - IN UINTN Offset, - IN OUT UINTN *NumBytes, - IN UINT8 *Buffer - ) -{ - EFI_STATUS TempStatus; - UINT32 Tmp; - UINT32 TmpBuf; - UINT32 WordToWrite; - UINT32 Mask; - BOOLEAN DoErase; - UINTN BytesToWrite; - UINTN CurOffset; - UINTN WordAddr; - UINTN BlockSize; - UINTN BlockAddress; - UINTN PrevBlockAddress; - - PrevBlockAddress = 0; - - if (!Instance->Initialized && Instance->Initialize) { - Instance->Initialize(Instance); - } - - DEBUG ((DEBUG_BLKIO, - "NorFlashWriteSingleBlock(Parameters: Lba=%ld, Offset=0x%x, *NumBytes=0x%x, Buffer @ 0x%08x)\n", - Lba, Offset, *NumBytes, Buffer)); - - // Cache the block size to avoid de-referencing pointers all the time - BlockSize = Instance->BlockSize; - - // The write must not span block boundaries. - // We need to check each variable individually because adding two large - // values together overflows. - if (Offset >= BlockSize || - *NumBytes > BlockSize || - (Offset + *NumBytes) > BlockSize) { - DEBUG ((DEBUG_ERROR, - "NorFlashWriteSingleBlock: ERROR - EFI_BAD_BUFFER_SIZE: (Offset=0x%x + NumBytes=0x%x) > BlockSize=0x%x\n", - Offset, *NumBytes, BlockSize )); - return EFI_BAD_BUFFER_SIZE; - } - - // We must have some bytes to write - if (*NumBytes == 0) { - DEBUG ((DEBUG_ERROR, - "NorFlashWriteSingleBlock: ERROR - EFI_BAD_BUFFER_SIZE: (Offset=0x%x + NumBytes=0x%x) > BlockSize=0x%x\n", - Offset, *NumBytes, BlockSize )); - return EFI_BAD_BUFFER_SIZE; - } - - // 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) { - // 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 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 = FALSE; - BytesToWrite = *NumBytes; - CurOffset = Offset; - - while (BytesToWrite > 0) { - // Read full word from NOR, splice as required. A word is the smallest - // unit we can write. - TempStatus = NorFlashRead (Instance, Lba, CurOffset & ~(0x3), sizeof(Tmp), - &Tmp); - if (EFI_ERROR (TempStatus)) { - return EFI_DEVICE_ERROR; - } - - // Physical address of word in NOR to write. - WordAddr = (CurOffset & ~(0x3)) + - GET_NOR_BLOCK_ADDRESS (Instance->RegionBaseAddress, Lba, - BlockSize); - - // The word of data that is to be written. - TmpBuf = *((UINT32*)(Buffer + (*NumBytes - BytesToWrite))); - - // First do word aligned chunks. - if ((CurOffset & 0x3) == 0) { - if (BytesToWrite >= 4) { - // Is the destination still in 'erased' state? - if (~Tmp != 0) { - // Check to see if we are only changing bits to zero. - if ((Tmp ^ TmpBuf) & TmpBuf) { - DoErase = TRUE; - break; - } - } - // Write this word to NOR - WordToWrite = TmpBuf; - CurOffset += sizeof(TmpBuf); - BytesToWrite -= sizeof(TmpBuf); - } else { - // BytesToWrite < 4. Do small writes and left-overs - Mask = ~((~0) << (BytesToWrite * 8)); - // Mask out the bytes we want. - TmpBuf &= Mask; - // Is the destination still in 'erased' state? - if ((Tmp & Mask) != Mask) { - // Check to see if we are only changing bits to zero. - if ((Tmp ^ TmpBuf) & TmpBuf) { - DoErase = TRUE; - break; - } - } - // Merge old and new data. Write merged word to NOR - WordToWrite = (Tmp & ~Mask) | TmpBuf; - CurOffset += BytesToWrite; - BytesToWrite = 0; - } - } else { - // Do multiple words, but starting unaligned. - if (BytesToWrite > (4 - (CurOffset & 0x3))) { - Mask = ((~0) << ((CurOffset & 0x3) * 8)); - // Mask out the bytes we want. - TmpBuf &= Mask; - // Is the destination still in 'erased' state? - if ((Tmp & Mask) != Mask) { - // Check to see if we are only changing bits to zero. - if ((Tmp ^ TmpBuf) & TmpBuf) { - DoErase = TRUE; - break; - } - } - // Merge old and new data. Write merged word to NOR - WordToWrite = (Tmp & ~Mask) | TmpBuf; - BytesToWrite -= (4 - (CurOffset & 0x3)); - CurOffset += (4 - (CurOffset & 0x3)); - } else { - // Unaligned and fits in one word. - Mask = (~((~0) << (BytesToWrite * 8))) << ((CurOffset & 0x3) * 8); - // Mask out the bytes we want. - TmpBuf = (TmpBuf << ((CurOffset & 0x3) * 8)) & Mask; - // Is the destination still in 'erased' state? - if ((Tmp & Mask) != Mask) { - // Check to see if we are only changing bits to zero. - if ((Tmp ^ TmpBuf) & TmpBuf) { - DoErase = TRUE; - break; - } - } - // Merge old and new data. Write merged word to NOR - WordToWrite = (Tmp & ~Mask) | TmpBuf; - CurOffset += BytesToWrite; - BytesToWrite = 0; - } - } - - // - // Write the word to NOR. - // - - BlockAddress = GET_NOR_BLOCK_ADDRESS (Instance->RegionBaseAddress, Lba, - BlockSize); - if (BlockAddress != PrevBlockAddress) { - TempStatus = NorFlashUnlockSingleBlockIfNecessary (Instance, - BlockAddress); - if (EFI_ERROR (TempStatus)) { - return EFI_DEVICE_ERROR; - } - PrevBlockAddress = BlockAddress; - } - TempStatus = NorFlashWriteSingleWord (Instance, WordAddr, WordToWrite); - if (EFI_ERROR (TempStatus)) { - return EFI_DEVICE_ERROR; - } - } - // Exit if we got here and could write all the data. Otherwise do the - // Erase-Write cycle. - if (!DoErase) { - return EFI_SUCCESS; - } - } - - // 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; - } - - // Read NOR Flash data into shadow buffer - TempStatus = NorFlashReadBlocks (Instance, Lba, BlockSize, - Instance->ShadowBuffer); - if (EFI_ERROR (TempStatus)) { - // 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); - - // Write the modified buffer back to the NorFlash - TempStatus = NorFlashWriteBlocks (Instance, Lba, BlockSize, - Instance->ShadowBuffer); - if (EFI_ERROR (TempStatus)) { - // Return one of the pre-approved error statuses - return EFI_DEVICE_ERROR; - } - - return EFI_SUCCESS; -} - -STATIC CONST NOR_FLASH_INSTANCE mNorFlashInstanceTemplate = { - NOR_FLASH_SIGNATURE, // Signature - NULL, // Handle ... NEED TO BE FILLED - - FALSE, // Initialized - NULL, // Initialize - - 0, // HostRegisterBaseAddress ... NEED TO BE FILLED - 0, // DeviceBaseAddress ... NEED TO BE FILLED - 0, // RegionBaseAddress ... NEED TO BE FILLED - 0, // Size ... NEED TO BE FILLED - 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, 0x0, 0x0, 0x0, 0x0, 0x0 } }, - }, - 0, // Index - { - END_DEVICE_PATH_TYPE, - END_ENTIRE_DEVICE_PATH_SUBTYPE, - { sizeof (EFI_DEVICE_PATH_PROTOCOL), 0 } - } - }, // DevicePath - - NULL, // CmdTable - 0, // CmdTableSize - 0 // Flags -}; - -STATIC -EFI_STATUS -NorFlashCreateInstance ( - IN UINTN HostRegisterBase, - IN UINTN NorFlashDeviceBase, - IN UINTN NorFlashRegionBase, - IN UINTN NorFlashSize, - IN UINT32 Index, - IN UINT32 BlockSize, - IN BOOLEAN HasVarStore, - IN CONST CSDC_DEFINITION *CommandTable, - IN UINTN CommandTableSize, - OUT NOR_FLASH_INSTANCE** NorFlashInstance - ) -{ - EFI_STATUS Status; - NOR_FLASH_INSTANCE* Instance; - NOR_FLASH_INFO *FlashInfo; - UINT8 JedecId[3]; - - ASSERT(NorFlashInstance != NULL); - - Instance = AllocateRuntimeCopyPool (sizeof mNorFlashInstanceTemplate, - &mNorFlashInstanceTemplate); - if (Instance == NULL) { - return EFI_OUT_OF_RESOURCES; - } - - Instance->HostRegisterBaseAddress = HostRegisterBase; - Instance->DeviceBaseAddress = NorFlashDeviceBase; - Instance->RegionBaseAddress = NorFlashRegionBase; - Instance->Size = NorFlashSize; - Instance->BlockSize = BlockSize; - Instance->LastBlock = (NorFlashSize / BlockSize) - 1; - - Instance->OffsetLba = (NorFlashRegionBase - NorFlashDeviceBase) / BlockSize; - - CopyGuid (&Instance->DevicePath.Vendor.Guid, &gEfiCallerIdGuid); - Instance->DevicePath.Index = (UINT8)Index; - - Instance->CmdTable = CommandTable; - Instance->CmdTableSize = CommandTableSize; - NorFlashReset (Instance); - - NorFlashReadID (Instance, JedecId); - Status = NorFlashGetInfo (JedecId, &FlashInfo, FALSE); - if (EFI_ERROR (Status)) { - goto FreeInstance; - } - - NorFlashPrintInfo (FlashInfo); - - Instance->Flags = 0; - if (FlashInfo->Flags & NOR_FLASH_WRITE_FSR) { - Instance->Flags = NOR_FLASH_POLL_FSR; - } + // + // Declare the Non-Volatile storage as EFI_MEMORY_RUNTIME + // + RuntimeMmioRegionSize = Instance->Size; - Instance->ShadowBuffer = AllocateRuntimePool (BlockSize);; - if (Instance->ShadowBuffer == NULL) { - Status = EFI_OUT_OF_RESOURCES; - goto FreeInstance; - } + Status = gDS->AddMemorySpace (EfiGcdMemoryTypeMemoryMappedIo, + Instance->RegionBaseAddress, RuntimeMmioRegionSize, + EFI_MEMORY_UC | EFI_MEMORY_RUNTIME); + ASSERT_EFI_ERROR (Status); - if (HasVarStore) { - Instance->Initialize = NorFlashFvbInitialize; - } + Status = gDS->AddMemorySpace (EfiGcdMemoryTypeMemoryMappedIo, + Instance->DeviceBaseAddress, SIZE_4KB, + EFI_MEMORY_UC | EFI_MEMORY_RUNTIME); + ASSERT_EFI_ERROR (Status); - Status = gBS->InstallMultipleProtocolInterfaces ( - &Instance->Handle, - &gEfiDevicePathProtocolGuid, &Instance->DevicePath, - &gEfiFirmwareVolumeBlockProtocolGuid, &Instance->FvbProtocol, - NULL - ); - if (EFI_ERROR (Status)) { - goto FreeInstance; - } + Status = gDS->SetMemorySpaceAttributes (Instance->RegionBaseAddress, + RuntimeMmioRegionSize, EFI_MEMORY_UC | EFI_MEMORY_RUNTIME); + ASSERT_EFI_ERROR (Status); - *NorFlashInstance = Instance; - FreePool (FlashInfo); - return EFI_SUCCESS; + Status = gDS->SetMemorySpaceAttributes (Instance->DeviceBaseAddress, + SIZE_4KB, EFI_MEMORY_UC | EFI_MEMORY_RUNTIME); + ASSERT_EFI_ERROR (Status); -FreeInstance: - FreePool (Instance); return Status; } -EFI_STATUS -NorFlashReset ( - IN NOR_FLASH_INSTANCE *Instance - ) -{ - FIP006_CS_CFG CsCfg; - - DEBUG ((DEBUG_BLKIO, "NorFlashReset()\n")); - CsCfg.Raw = MmioRead32 (Instance->HostRegisterBaseAddress + - FIP006_REG_CS_CFG); - CsCfg.Reg.MBM = CS_CFG_MBM_SINGLE; - CsCfg.Reg.SRAM = CS_CFG_SRAM_RW; - MmioWrite32 (Instance->HostRegisterBaseAddress + FIP006_REG_CS_CFG, - CsCfg.Raw); - NorFlashSetHostCommand (Instance, SPINOR_OP_READ_4B); - NorFlashSetHostCSDC (Instance, TRUE, mFip006NullCmdSeq); - return EFI_SUCCESS; -} - -EFI_STATUS -NorFlashReadID ( - IN NOR_FLASH_INSTANCE *Instance, - OUT UINT8 JedecId[3] - ) -{ - if (Instance == NULL || JedecId == NULL) { - return EFI_INVALID_PARAMETER; - } - - NorFlashSetHostCommand (Instance, SPINOR_OP_RDID); - JedecId[0] = MmioRead8 (Instance->DeviceBaseAddress); - JedecId[1] = MmioRead8 (Instance->DeviceBaseAddress + 1); - JedecId[2] = MmioRead8 (Instance->DeviceBaseAddress + 2); - NorFlashSetHostCommand (Instance, SPINOR_OP_READ_4B); - 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 @@ -1078,6 +173,8 @@ NorFlashVirtualNotifyEvent ( { UINTN Index; + EfiConvertPointer (0x0, (VOID**)&mFlashNvStorageVariableBase); + for (Index = 0; Index < mNorFlashDeviceCount; Index++) { EfiConvertPointer (0x0, (VOID**)&mNorFlashInstances[Index]->HostRegisterBaseAddress); @@ -1105,8 +202,6 @@ NorFlashVirtualNotifyEvent ( if (mNorFlashInstances[Index]->ShadowBuffer != NULL) { EfiConvertPointer (0x0, (VOID**)&mNorFlashInstances[Index]->ShadowBuffer); } - - EfiConvertPointer (0x0, (VOID**)&mNorFlashInstances[Index]->CmdTable); } return; @@ -1174,17 +269,24 @@ NorFlashInitialise ( Index, NorFlashDevices[Index].BlockSize, ContainVariableStorage, - mN25qCSDCDefTable, - ARRAY_SIZE (mN25qCSDCDefTable), &mNorFlashInstances[Index] ); if (EFI_ERROR (Status)) { DEBUG ((DEBUG_ERROR, "NorFlashInitialise: Fail to create instance for NorFlash[%d]\n", Index)); + continue; } + Status = 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 // @@ -1196,3 +298,31 @@ NorFlashInitialise ( return Status; } + +VOID +EFIAPI +NorFlashLock ( + NOR_FLASH_LOCK_CONTEXT *Context + ) +{ + if (!EfiAtRuntime ()) { + // Raise TPL to TPL_HIGH to stop anyone from interrupting us. + Context->OriginalTPL = gBS->RaiseTPL (TPL_HIGH_LEVEL); + } else { + Context->InterruptsEnabled = SaveAndDisableInterrupts (); + } +} + +VOID +EFIAPI +NorFlashUnlock ( + NOR_FLASH_LOCK_CONTEXT *Context + ) +{ + if (!EfiAtRuntime ()) { + // Interruptions can resume. + gBS->RestoreTPL (Context->OriginalTPL); + } else if (Context->InterruptsEnabled) { + SetInterruptState (TRUE); + } +} diff --git a/Silicon/Socionext/SynQuacer/Drivers/Fip006Dxe/NorFlashFvbDxe.c b/Silicon/Socionext/SynQuacer/Drivers/Fip006Dxe/NorFlashFvb.c similarity index 80% rename from Silicon/Socionext/SynQuacer/Drivers/Fip006Dxe/NorFlashFvbDxe.c rename to Silicon/Socionext/SynQuacer/Drivers/Fip006Dxe/NorFlashFvb.c index 776ec8a5437c..30b7442d8947 100644 --- a/Silicon/Socionext/SynQuacer/Drivers/Fip006Dxe/NorFlashFvbDxe.c +++ b/Silicon/Socionext/SynQuacer/Drivers/Fip006Dxe/NorFlashFvb.c @@ -21,16 +21,14 @@ #include #include -#include #include #include #include #include -#include "NorFlashDxe.h" +#include "NorFlash.h" -STATIC EFI_EVENT mFvbVirtualAddrChangeEvent; -STATIC UINTN mFlashNvStorageVariableBase; +UINTN mFlashNvStorageVariableBase; /// /// The Firmware Volume Block Protocol is the low-level interface @@ -49,7 +47,6 @@ STATIC UINTN mFlashNvStorageVariableBase; @param[in] Ptr - Location to initialise the headers **/ -STATIC EFI_STATUS InitializeFvAndVariableStoreHeaders ( IN NOR_FLASH_INSTANCE *Instance @@ -700,157 +697,3 @@ FvbEraseBlocks ( 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 -**/ -STATIC -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; - UINTN BlockSize; - - DEBUG ((DEBUG_BLKIO,"NorFlashFvbInitialize\n")); - - BlockSize = Instance->BlockSize; - - // FirmwareVolumeHeader->FvLength is declared to have the Variable area - // AND the FTW working area AND the FTW Spare contiguous. - ASSERT(PcdGet32(PcdFlashNvStorageVariableBase) + - PcdGet32(PcdFlashNvStorageVariableSize) == - PcdGet32(PcdFlashNvStorageFtwWorkingBase)); - ASSERT(PcdGet32(PcdFlashNvStorageFtwWorkingBase) + - PcdGet32(PcdFlashNvStorageFtwWorkingSize) == - 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) == 0); - ASSERT((PcdGet32(PcdFlashNvStorageFtwWorkingBase) % BlockSize) == 0); - ASSERT((PcdGet32(PcdFlashNvStorageFtwSpareBase) % BlockSize) == 0); - - - Instance->Initialized = TRUE; - mFlashNvStorageVariableBase = FixedPcdGet32 (PcdFlashNvStorageVariableBase); - - // Set the index of the first LBA for the FVB - Instance->StartLba = (PcdGet32 (PcdFlashNvStorageVariableBase) - - Instance->RegionBaseAddress) / 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->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; - } - } - - // - // The driver implementing the variable read service can now be dispatched; - // the varstore headers are in place. - // - Status = gBS->InstallProtocolInterface (&gImageHandle, - &gEdkiiNvVarStoreFormattedGuid, - EFI_NATIVE_INTERFACE, - NULL); - if (EFI_ERROR (Status)) { - DEBUG ((DEBUG_ERROR, - "%a: Failed to install gEdkiiNvVarStoreFormattedGuid\n", - __FUNCTION__)); - return Status; - } - - // - // Declare the Non-Volatile storage as EFI_MEMORY_RUNTIME - // - RuntimeMmioRegionSize = Instance->Size; - - Status = gDS->AddMemorySpace (EfiGcdMemoryTypeMemoryMappedIo, - Instance->RegionBaseAddress, RuntimeMmioRegionSize, - EFI_MEMORY_UC | EFI_MEMORY_RUNTIME); - ASSERT_EFI_ERROR (Status); - - Status = gDS->AddMemorySpace (EfiGcdMemoryTypeMemoryMappedIo, - Instance->DeviceBaseAddress, SIZE_4KB, - EFI_MEMORY_UC | EFI_MEMORY_RUNTIME); - ASSERT_EFI_ERROR (Status); - - Status = gDS->SetMemorySpaceAttributes (Instance->RegionBaseAddress, - RuntimeMmioRegionSize, EFI_MEMORY_UC | EFI_MEMORY_RUNTIME); - ASSERT_EFI_ERROR (Status); - - Status = gDS->SetMemorySpaceAttributes (Instance->DeviceBaseAddress, - SIZE_4KB, 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; -}