summaryrefslogtreecommitdiff
path: root/Silicon/Marvell/Drivers/Spi
diff options
context:
space:
mode:
Diffstat (limited to 'Silicon/Marvell/Drivers/Spi')
-rwxr-xr-xSilicon/Marvell/Drivers/Spi/Devices/MvSpiFlash.c599
-rwxr-xr-xSilicon/Marvell/Drivers/Spi/Devices/MvSpiFlash.h138
-rw-r--r--Silicon/Marvell/Drivers/Spi/Devices/MvSpiFlash.inf70
-rwxr-xr-xSilicon/Marvell/Drivers/Spi/MvSpiDxe.c432
-rw-r--r--Silicon/Marvell/Drivers/Spi/MvSpiDxe.h148
-rw-r--r--Silicon/Marvell/Drivers/Spi/MvSpiDxe.inf73
-rw-r--r--Silicon/Marvell/Drivers/Spi/Variables/MvFvbDxe.c1138
-rw-r--r--Silicon/Marvell/Drivers/Spi/Variables/MvFvbDxe.h128
-rw-r--r--Silicon/Marvell/Drivers/Spi/Variables/MvFvbDxe.inf91
9 files changed, 2817 insertions, 0 deletions
diff --git a/Silicon/Marvell/Drivers/Spi/Devices/MvSpiFlash.c b/Silicon/Marvell/Drivers/Spi/Devices/MvSpiFlash.c
new file mode 100755
index 0000000000..6886d0104a
--- /dev/null
+++ b/Silicon/Marvell/Drivers/Spi/Devices/MvSpiFlash.c
@@ -0,0 +1,599 @@
+/*******************************************************************************
+Copyright (C) 2016 Marvell International Ltd.
+
+Marvell BSD License Option
+
+If you received this File from Marvell, you may opt to use, redistribute and/or
+modify this File under the following licensing terms.
+Redistribution and use in source and binary forms, with or without modification,
+are permitted provided that the following conditions are met:
+
+* Redistributions of source code must retain the above copyright notice,
+ this list of conditions and the following disclaimer.
+
+* Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+* Neither the name of Marvell nor the names of its contributors may be
+ used to endorse or promote products derived from this software without
+ specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
+ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+*******************************************************************************/
+#include "MvSpiFlash.h"
+
+STATIC EFI_EVENT mMvSpiFlashVirtualAddrChangeEvent;
+MARVELL_SPI_MASTER_PROTOCOL *SpiMasterProtocol;
+SPI_FLASH_INSTANCE *mSpiFlashInstance;
+
+STATIC
+VOID
+SpiFlashFormatAddress (
+ IN UINT32 Address,
+ IN UINT8 AddrSize,
+ IN OUT UINT8 *Cmd
+ )
+{
+ if (AddrSize == 4) {
+ Cmd[1] = Address >> 24;
+ Cmd[2] = Address >> 16;
+ Cmd[3] = Address >> 8;
+ Cmd[4] = Address;
+ } else {
+ Cmd[1] = Address >> 16;
+ Cmd[2] = Address >> 8;
+ Cmd[3] = Address;
+ }
+}
+
+STATIC
+EFI_STATUS
+MvSpiFlashReadCmd (
+ IN SPI_DEVICE *Slave,
+ IN UINT8 *Cmd,
+ IN UINTN CmdSize,
+ OUT UINT8 *DataIn,
+ IN UINTN DataSize
+ )
+{
+ EFI_STATUS Status;
+
+ // Send command and gather response
+ Status = SpiMasterProtocol->ReadWrite (SpiMasterProtocol, Slave, Cmd,
+ CmdSize, NULL, DataIn, DataSize);
+
+ return Status;
+}
+
+STATIC
+EFI_STATUS
+MvSpiFlashWriteEnableCmd (
+ IN SPI_DEVICE *Slave
+ )
+{
+ EFI_STATUS Status;
+ UINT8 CmdEn = CMD_WRITE_ENABLE;
+
+ // Send write_enable command
+ Status = SpiMasterProtocol->Transfer (SpiMasterProtocol, Slave, 1,
+ &CmdEn, NULL, SPI_TRANSFER_BEGIN | SPI_TRANSFER_END);
+
+ return Status;
+}
+
+STATIC
+EFI_STATUS
+MvSpiFlashWriteCommon (
+ IN SPI_DEVICE *Slave,
+ IN UINT8 *Cmd,
+ IN UINT32 Length,
+ IN UINT8* Buffer,
+ IN UINT32 BufferLength
+ )
+{
+ UINT8 CmdStatus = CMD_READ_STATUS;
+ UINT8 State;
+ UINT32 Counter = 0xFFFFF;
+ UINT8 PollBit = STATUS_REG_POLL_WIP;
+ UINT8 CheckStatus = 0x0;
+
+ if (Slave->Info->Flags & NOR_FLASH_WRITE_FSR) {
+ CmdStatus = CMD_FLAG_STATUS;
+ PollBit = STATUS_REG_POLL_PEC;
+ CheckStatus = STATUS_REG_POLL_PEC;
+ }
+
+ // Send command
+ MvSpiFlashWriteEnableCmd (Slave);
+
+ // Write data
+ SpiMasterProtocol->ReadWrite (SpiMasterProtocol, Slave, Cmd, Length,
+ Buffer, NULL, BufferLength);
+
+ // Poll status register
+ SpiMasterProtocol->Transfer (SpiMasterProtocol, Slave, 1, &CmdStatus,
+ NULL, SPI_TRANSFER_BEGIN);
+ do {
+ SpiMasterProtocol->Transfer (SpiMasterProtocol, Slave, 1, NULL, &State,
+ 0);
+ Counter--;
+ if ((State & PollBit) == CheckStatus)
+ break;
+ } while (Counter > 0);
+ if (Counter == 0) {
+ DEBUG((DEBUG_ERROR, "SpiFlash: Timeout while writing to spi flash\n"));
+ return EFI_DEVICE_ERROR;
+ }
+
+ // Deactivate CS
+ SpiMasterProtocol->Transfer (SpiMasterProtocol, Slave, 0, NULL, NULL, SPI_TRANSFER_END);
+
+ return EFI_SUCCESS;
+}
+
+STATIC
+VOID
+SpiFlashCmdBankaddrWrite (
+ IN SPI_DEVICE *Slave,
+ IN UINT8 BankSel
+ )
+{
+ UINT8 Cmd = CMD_BANK_WRITE;
+
+ /* Update bank selection command for Spansion */
+ if (Slave->Info->Id[0] == NOR_FLASH_ID_SPANSION) {
+ Cmd = CMD_BANKADDR_BRWR;
+ }
+
+ MvSpiFlashWriteCommon (Slave, &Cmd, 1, &BankSel, 1);
+}
+
+STATIC
+UINT8
+SpiFlashBank (
+ IN SPI_DEVICE *Slave,
+ IN UINT32 Offset
+ )
+{
+ UINT8 BankSel;
+
+ BankSel = Offset / SPI_FLASH_16MB_BOUN;
+
+ SpiFlashCmdBankaddrWrite (Slave, BankSel);
+
+ return BankSel;
+}
+
+EFI_STATUS
+MvSpiFlashErase (
+ IN SPI_DEVICE *Slave,
+ IN UINTN Offset,
+ IN UINTN Length
+ )
+{
+ EFI_STATUS Status;
+ UINT32 EraseAddr;
+ UINTN EraseSize;
+ UINT8 Cmd[5];
+
+ if (Slave->Info->Flags & NOR_FLASH_ERASE_4K) {
+ Cmd[0] = CMD_ERASE_4K;
+ EraseSize = SIZE_4KB;
+ } else if (Slave->Info->Flags & NOR_FLASH_ERASE_32K) {
+ Cmd[0] = CMD_ERASE_32K;
+ EraseSize = SIZE_32KB;
+ } else {
+ Cmd[0] = CMD_ERASE_64K;
+ EraseSize = Slave->Info->SectorSize;
+ }
+
+ // Check input parameters
+ if (Offset % EraseSize || Length % EraseSize) {
+ DEBUG((DEBUG_ERROR, "SpiFlash: Either erase offset or length "
+ "is not multiple of erase size\n"));
+ return EFI_DEVICE_ERROR;
+ }
+
+ while (Length) {
+ EraseAddr = Offset;
+
+ SpiFlashBank (Slave, EraseAddr);
+
+ SpiFlashFormatAddress (EraseAddr, Slave->AddrSize, Cmd);
+
+ // Programm proper erase address
+ Status = MvSpiFlashWriteCommon (Slave, Cmd, Slave->AddrSize + 1, NULL, 0);
+ if (EFI_ERROR (Status)) {
+ DEBUG((DEBUG_ERROR, "SpiFlash: Error while programming target address\n"));
+ return Status;
+ }
+
+ Offset += EraseSize;
+ Length -= EraseSize;
+ }
+ return EFI_SUCCESS;
+}
+
+EFI_STATUS
+MvSpiFlashRead (
+ IN SPI_DEVICE *Slave,
+ IN UINT32 Offset,
+ IN UINTN Length,
+ IN VOID *Buf
+ )
+{
+ EFI_STATUS Status = EFI_SUCCESS;
+ UINT8 Cmd[6];
+ UINT32 ReadAddr, ReadLength, RemainLength;
+ UINTN BankSel = 0;
+
+ Cmd[0] = CMD_READ_ARRAY_FAST;
+
+ // Sign end of address with 0 byte
+ Cmd[5] = 0;
+
+ while (Length) {
+ ReadAddr = Offset;
+
+ BankSel = SpiFlashBank (Slave, ReadAddr);
+
+ RemainLength = (SPI_FLASH_16MB_BOUN * (BankSel + 1)) - Offset;
+ if (Length < RemainLength) {
+ ReadLength = Length;
+ } else {
+ ReadLength = RemainLength;
+ }
+ SpiFlashFormatAddress (ReadAddr, Slave->AddrSize, Cmd);
+ // Program proper read address and read data
+ Status = MvSpiFlashReadCmd (Slave, Cmd, Slave->AddrSize + 2, Buf, Length);
+
+ Offset += ReadLength;
+ Length -= ReadLength;
+ Buf += ReadLength;
+ }
+
+ return Status;
+}
+
+EFI_STATUS
+MvSpiFlashWrite (
+ IN SPI_DEVICE *Slave,
+ IN UINT32 Offset,
+ IN UINTN Length,
+ IN VOID *Buf
+ )
+{
+ EFI_STATUS Status;
+ UINTN ByteAddr, ChunkLength, ActualIndex, PageSize;
+ UINT32 WriteAddr;
+ UINT8 Cmd[5];
+
+ PageSize = Slave->Info->PageSize;
+
+ Cmd[0] = CMD_PAGE_PROGRAM;
+
+ for (ActualIndex = 0; ActualIndex < Length; ActualIndex += ChunkLength) {
+ WriteAddr = Offset;
+
+ SpiFlashBank (Slave, WriteAddr);
+
+ ByteAddr = Offset % PageSize;
+
+ ChunkLength = MIN(Length - ActualIndex, (UINT64) (PageSize - ByteAddr));
+
+ SpiFlashFormatAddress (WriteAddr, Slave->AddrSize, Cmd);
+
+ // Program proper write address and write data
+ Status = MvSpiFlashWriteCommon (Slave, Cmd, Slave->AddrSize + 1, Buf + ActualIndex,
+ ChunkLength);
+ if (EFI_ERROR (Status)) {
+ DEBUG((DEBUG_ERROR, "SpiFlash: Error while programming write address\n"));
+ return Status;
+ }
+
+ Offset += ChunkLength;
+ }
+ return EFI_SUCCESS;
+}
+
+STATIC
+EFI_STATUS
+MvSpiFlashUpdateBlock (
+ IN SPI_DEVICE *Slave,
+ IN UINT32 Offset,
+ IN UINTN ToUpdate,
+ IN UINT8 *Buf,
+ IN UINT8 *TmpBuf,
+ IN UINTN EraseSize
+ )
+{
+ EFI_STATUS Status;
+
+ // Read backup
+ Status = MvSpiFlashRead (Slave, Offset, EraseSize, TmpBuf);
+ if (EFI_ERROR (Status)) {
+ DEBUG((DEBUG_ERROR, "SpiFlash: Update: Error while reading old data\n"));
+ return Status;
+ }
+
+ // Erase entire sector
+ Status = MvSpiFlashErase (Slave, Offset, EraseSize);
+ if (EFI_ERROR (Status)) {
+ DEBUG((DEBUG_ERROR, "SpiFlash: Update: Error while erasing block\n"));
+ return Status;
+ }
+
+ // Write new data
+ MvSpiFlashWrite (Slave, Offset, ToUpdate, Buf);
+ if (EFI_ERROR (Status)) {
+ DEBUG((DEBUG_ERROR, "SpiFlash: Update: Error while writing new data\n"));
+ return Status;
+ }
+
+ // Write backup
+ if (ToUpdate != EraseSize) {
+ Status = MvSpiFlashWrite (Slave, Offset + ToUpdate, EraseSize - ToUpdate,
+ &TmpBuf[ToUpdate]);
+ if (EFI_ERROR (Status)) {
+ DEBUG((DEBUG_ERROR, "SpiFlash: Update: Error while writing backup\n"));
+ return Status;
+ }
+ }
+
+ return EFI_SUCCESS;
+}
+
+EFI_STATUS
+MvSpiFlashUpdate (
+ IN SPI_DEVICE *Slave,
+ IN UINT32 Offset,
+ IN UINTN ByteCount,
+ IN UINT8 *Buf
+ )
+{
+ EFI_STATUS Status;
+ UINT64 SectorSize, ToUpdate, Scale = 1;
+ UINT8 *TmpBuf, *End;
+
+ SectorSize = Slave->Info->SectorSize;
+
+ End = Buf + ByteCount;
+
+ TmpBuf = (UINT8 *)AllocateZeroPool (SectorSize);
+ if (TmpBuf == NULL) {
+ DEBUG((DEBUG_ERROR, "SpiFlash: Cannot allocate memory\n"));
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ if (End - Buf >= 200)
+ Scale = (End - Buf) / 100;
+
+ for (; Buf < End; Buf += ToUpdate, Offset += ToUpdate) {
+ ToUpdate = MIN((UINT64)(End - Buf), SectorSize);
+ Print (L" \rUpdating, %d%%", 100 - (End - Buf) / Scale);
+ Status = MvSpiFlashUpdateBlock (Slave, Offset, ToUpdate, Buf, TmpBuf, SectorSize);
+
+ if (EFI_ERROR (Status)) {
+ DEBUG((DEBUG_ERROR, "SpiFlash: Error while updating\n"));
+ return Status;
+ }
+ }
+
+ Print(L"\n");
+ FreePool (TmpBuf);
+
+ return EFI_SUCCESS;
+}
+
+EFI_STATUS
+EFIAPI
+MvSpiFlashReadId (
+ IN SPI_DEVICE *SpiDev,
+ IN BOOLEAN UseInRuntime
+ )
+{
+ EFI_STATUS Status;
+ UINT8 Id[NOR_FLASH_MAX_ID_LEN];
+ UINT8 Cmd;
+
+ Cmd = CMD_READ_ID;
+ Status = SpiMasterProtocol->ReadWrite (SpiMasterProtocol,
+ SpiDev,
+ &Cmd,
+ SPI_CMD_LEN,
+ NULL,
+ Id,
+ NOR_FLASH_MAX_ID_LEN);
+ if (EFI_ERROR (Status)) {
+ DEBUG ((DEBUG_ERROR, "ReadId: Spi transfer error\n"));
+ return Status;
+ }
+
+ Status = NorFlashGetInfo (Id, &SpiDev->Info, UseInRuntime);
+ if (EFI_ERROR (Status)) {
+ DEBUG ((DEBUG_ERROR,
+ "%a: Unrecognized JEDEC Id bytes: 0x%02x%02x%02x\n",
+ __FUNCTION__,
+ Id[0],
+ Id[1],
+ Id[2]));
+ return Status;
+ }
+
+ NorFlashPrintInfo (SpiDev->Info);
+
+ return EFI_SUCCESS;
+}
+
+EFI_STATUS
+EFIAPI
+MvSpiFlashInit (
+ IN MARVELL_SPI_FLASH_PROTOCOL *This,
+ IN SPI_DEVICE *Slave
+ )
+{
+ EFI_STATUS Status;
+ UINT8 Cmd, StatusRegister;
+
+ if (Slave->Info->Flags & NOR_FLASH_4B_ADDR) {
+ Slave->AddrSize = 4;
+ } else {
+ Slave->AddrSize = 3;
+ }
+
+ if (Slave->AddrSize == 4) {
+ // Set 4 byte address mode
+ Status = MvSpiFlashWriteEnableCmd (Slave);
+ if (EFI_ERROR (Status)) {
+ DEBUG((DEBUG_ERROR, "SpiFlash: Error while setting write_enable\n"));
+ return Status;
+ }
+
+ Cmd = CMD_4B_ADDR_ENABLE;
+ Status = SpiMasterProtocol->Transfer (SpiMasterProtocol, Slave, 1, &Cmd, NULL,
+ SPI_TRANSFER_BEGIN | SPI_TRANSFER_END);
+ if (EFI_ERROR (Status)) {
+ DEBUG((DEBUG_ERROR, "SpiFlash: Error while setting 4B address\n"));
+ return Status;
+ }
+ }
+
+ // Write flash status register
+ Status = MvSpiFlashWriteEnableCmd (Slave);
+ if (EFI_ERROR (Status)) {
+ DEBUG((DEBUG_ERROR, "SpiFlash: Error while setting write_enable\n"));
+ return Status;
+ }
+
+ Cmd = CMD_WRITE_STATUS_REG;
+ StatusRegister = 0x0;
+ Status = SpiMasterProtocol->ReadWrite (SpiMasterProtocol, Slave, &Cmd, 1,
+ &StatusRegister, NULL, 1);
+ if (EFI_ERROR (Status)) {
+ DEBUG((DEBUG_ERROR, "SpiFlash: Error with spi transfer\n"));
+ return Status;
+ }
+
+ return EFI_SUCCESS;
+}
+
+EFI_STATUS
+MvSpiFlashInitProtocol (
+ IN MARVELL_SPI_FLASH_PROTOCOL *SpiFlashProtocol
+ )
+{
+
+ SpiFlashProtocol->Init = MvSpiFlashInit;
+ SpiFlashProtocol->ReadId = MvSpiFlashReadId;
+ SpiFlashProtocol->Read = MvSpiFlashRead;
+ SpiFlashProtocol->Write = MvSpiFlashWrite;
+ SpiFlashProtocol->Erase = MvSpiFlashErase;
+ SpiFlashProtocol->Update = MvSpiFlashUpdate;
+
+ 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
+**/
+STATIC
+VOID
+EFIAPI
+MvSpiFlashVirtualNotifyEvent (
+ IN EFI_EVENT Event,
+ IN VOID *Context
+ )
+{
+ //
+ // Convert SpiMasterProtocol callbacks in MvSpiFlashErase and
+ // MvSpiFlashWrite required by runtime variable support.
+ //
+ EfiConvertPointer (0x0, (VOID**)&SpiMasterProtocol->ReadWrite);
+ EfiConvertPointer (0x0, (VOID**)&SpiMasterProtocol->Transfer);
+ EfiConvertPointer (0x0, (VOID**)&SpiMasterProtocol);
+
+ return;
+}
+
+EFI_STATUS
+EFIAPI
+MvSpiFlashEntryPoint (
+ IN EFI_HANDLE ImageHandle,
+ IN EFI_SYSTEM_TABLE *SystemTable
+ )
+{
+ EFI_STATUS Status;
+
+ Status = gBS->LocateProtocol (
+ &gMarvellSpiMasterProtocolGuid,
+ NULL,
+ (VOID **)&SpiMasterProtocol
+ );
+ if (EFI_ERROR (Status)) {
+ DEBUG((DEBUG_ERROR, "SpiFlash: Cannot locate SPI Master protocol\n"));
+ return EFI_DEVICE_ERROR;
+ }
+
+ mSpiFlashInstance = AllocateRuntimeZeroPool (sizeof (SPI_FLASH_INSTANCE));
+ if (mSpiFlashInstance == NULL) {
+ DEBUG((DEBUG_ERROR, "SpiFlash: Cannot allocate memory\n"));
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ MvSpiFlashInitProtocol (&mSpiFlashInstance->SpiFlashProtocol);
+
+ mSpiFlashInstance->Signature = SPI_FLASH_SIGNATURE;
+
+ Status = gBS->InstallMultipleProtocolInterfaces (
+ &(mSpiFlashInstance->Handle),
+ &gMarvellSpiFlashProtocolGuid,
+ &(mSpiFlashInstance->SpiFlashProtocol),
+ NULL
+ );
+ if (EFI_ERROR (Status)) {
+ DEBUG((DEBUG_ERROR, "SpiFlash: Cannot install SPI flash protocol\n"));
+ goto ErrorInstallProto;
+ }
+
+ //
+ // Register for the virtual address change event
+ //
+ Status = gBS->CreateEventEx (EVT_NOTIFY_SIGNAL,
+ TPL_NOTIFY,
+ MvSpiFlashVirtualNotifyEvent,
+ NULL,
+ &gEfiEventVirtualAddressChangeGuid,
+ &mMvSpiFlashVirtualAddrChangeEvent);
+ if (EFI_ERROR (Status)) {
+ DEBUG ((DEBUG_ERROR, "%a: Failed to register VA change event\n", __FUNCTION__));
+ goto ErrorCreateEvent;
+ }
+
+ return EFI_SUCCESS;
+
+ErrorCreateEvent:
+ gBS->UninstallMultipleProtocolInterfaces (&mSpiFlashInstance->Handle,
+ &gMarvellSpiFlashProtocolGuid,
+ NULL);
+
+ErrorInstallProto:
+ FreePool (mSpiFlashInstance);
+
+ return EFI_SUCCESS;
+}
diff --git a/Silicon/Marvell/Drivers/Spi/Devices/MvSpiFlash.h b/Silicon/Marvell/Drivers/Spi/Devices/MvSpiFlash.h
new file mode 100755
index 0000000000..f69c562190
--- /dev/null
+++ b/Silicon/Marvell/Drivers/Spi/Devices/MvSpiFlash.h
@@ -0,0 +1,138 @@
+/*******************************************************************************
+Copyright (C) 2016 Marvell International Ltd.
+
+Marvell BSD License Option
+
+If you received this File from Marvell, you may opt to use, redistribute and/or
+modify this File under the following licensing terms.
+Redistribution and use in source and binary forms, with or without modification,
+are permitted provided that the following conditions are met:
+
+* Redistributions of source code must retain the above copyright notice,
+ this list of conditions and the following disclaimer.
+
+* Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+* Neither the name of Marvell nor the names of its contributors may be
+ used to endorse or promote products derived from this software without
+ specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
+ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+*******************************************************************************/
+#ifndef __MV_SPI_FLASH_H__
+#define __MV_SPI_FLASH_H__
+
+#include <Library/IoLib.h>
+#include <Library/PcdLib.h>
+#include <Library/UefiLib.h>
+#include <Library/DebugLib.h>
+#include <Library/MemoryAllocationLib.h>
+#include <Uefi/UefiBaseType.h>
+#include <Library/BaseMemoryLib.h>
+#include <Library/UefiBootServicesTableLib.h>
+#include <Library/UefiRuntimeLib.h>
+
+#include <Protocol/Spi.h>
+#include <Protocol/SpiFlash.h>
+
+#define SPI_FLASH_SIGNATURE SIGNATURE_32 ('F', 'S', 'P', 'I')
+
+#define CMD_READ_ID 0x9f
+#define READ_STATUS_REG_CMD 0x0b
+#define CMD_WRITE_ENABLE 0x06
+#define CMD_READ_STATUS 0x05
+#define CMD_FLAG_STATUS 0x70
+#define CMD_WRITE_STATUS_REG 0x01
+#define CMD_READ_ARRAY_FAST 0x0b
+#define CMD_PAGE_PROGRAM 0x02
+#define CMD_BANK_WRITE 0xc5
+#define CMD_BANKADDR_BRWR 0x17
+#define CMD_ERASE_4K 0x20
+#define CMD_ERASE_32K 0x52
+#define CMD_ERASE_64K 0xd8
+#define CMD_4B_ADDR_ENABLE 0xb7
+
+#define SPI_CMD_LEN 1
+
+#define STATUS_REG_POLL_WIP (1 << 0)
+#define STATUS_REG_POLL_PEC (1 << 7)
+
+#define SPI_TRANSFER_BEGIN 0x01 // Assert CS before transfer
+#define SPI_TRANSFER_END 0x02 // Deassert CS after transfers
+
+#define SPI_FLASH_16MB_BOUN 0x1000000
+
+typedef enum {
+ SPI_FLASH_READ_ID,
+ SPI_FLASH_READ, // Read from SPI flash with address
+ SPI_FLASH_WRITE, // Write to SPI flash with address
+ SPI_FLASH_ERASE,
+ SPI_FLASH_UPDATE,
+ SPI_COMMAND_MAX
+} SPI_COMMAND;
+
+typedef struct {
+ MARVELL_SPI_FLASH_PROTOCOL SpiFlashProtocol;
+ UINTN Signature;
+ EFI_HANDLE Handle;
+} SPI_FLASH_INSTANCE;
+
+EFI_STATUS
+EFIAPI
+SpiFlashReadId (
+ IN SPI_DEVICE *SpiDev,
+ IN UINT32 DataByteCount,
+ IN OUT UINT8 *Buffer
+ );
+
+EFI_STATUS
+SpiFlashRead (
+ IN SPI_DEVICE *Slave,
+ IN UINT32 Offset,
+ IN UINTN Length,
+ IN VOID *Buf
+ );
+
+EFI_STATUS
+SpiFlashWrite (
+ IN SPI_DEVICE *Slave,
+ IN UINT32 Offset,
+ IN UINTN Length,
+ IN VOID *Buf
+ );
+
+EFI_STATUS
+SpiFlashUpdate (
+ IN SPI_DEVICE *Slave,
+ IN UINT32 Offset,
+ IN UINTN ByteCount,
+ IN UINT8 *Buf
+ );
+
+EFI_STATUS
+SpiFlashErase (
+ IN SPI_DEVICE *SpiDev,
+ IN UINTN Offset,
+ IN UINTN Length
+ );
+
+EFI_STATUS
+EFIAPI
+EfiSpiFlashInit (
+ IN MARVELL_SPI_FLASH_PROTOCOL *This,
+ IN SPI_DEVICE *Slave
+ );
+
+#endif // __MV_SPI_FLASH_H__
diff --git a/Silicon/Marvell/Drivers/Spi/Devices/MvSpiFlash.inf b/Silicon/Marvell/Drivers/Spi/Devices/MvSpiFlash.inf
new file mode 100644
index 0000000000..bc88a7ea98
--- /dev/null
+++ b/Silicon/Marvell/Drivers/Spi/Devices/MvSpiFlash.inf
@@ -0,0 +1,70 @@
+#
+# Marvell BSD License Option
+#
+# If you received this File from Marvell, you may opt to use, redistribute
+# and/or modify this File under the following licensing terms.
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are met:
+#
+# * Redistributions of source code must retain the above copyright notice,
+# this list of conditions and the following disclaimer.
+#
+# * Redistributions in binary form must reproduce the above copyright
+# notice, this list of conditions and the following disclaimer in the
+# documentation and/or other materials provided with the distribution.
+#
+# * Neither the name of Marvell nor the names of its contributors may be
+# used to endorse or promote products derived from this software without
+# specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE
+# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+#
+
+[Defines]
+ INF_VERSION = 0x00010005
+ BASE_NAME = SpiFlashDxe
+ FILE_GUID = 49d7fb74-306d-42bd-94c8-c0c54b181dd7
+ MODULE_TYPE = DXE_RUNTIME_DRIVER
+ VERSION_STRING = 1.0
+ ENTRY_POINT = MvSpiFlashEntryPoint
+
+[Sources]
+ MvSpiFlash.c
+ MvSpiFlash.h
+
+[Packages]
+ EmbeddedPkg/EmbeddedPkg.dec
+ MdePkg/MdePkg.dec
+ Silicon/Marvell/Marvell.dec
+
+[LibraryClasses]
+ NorFlashInfoLib
+ UefiBootServicesTableLib
+ UefiDriverEntryPoint
+ TimerLib
+ UefiLib
+ DebugLib
+ MemoryAllocationLib
+ UefiRuntimeLib
+
+[Guids]
+ gEfiEventVirtualAddressChangeGuid
+
+[Protocols]
+ gMarvellSpiMasterProtocolGuid
+ gMarvellSpiFlashProtocolGuid
+
+[Depex]
+ #
+ # MvSpiFlashDxe must be loaded prior to variables driver MvFvbDxe
+ #
+ BEFORE gMarvellFvbDxeGuid
diff --git a/Silicon/Marvell/Drivers/Spi/MvSpiDxe.c b/Silicon/Marvell/Drivers/Spi/MvSpiDxe.c
new file mode 100755
index 0000000000..bab6cf4d56
--- /dev/null
+++ b/Silicon/Marvell/Drivers/Spi/MvSpiDxe.c
@@ -0,0 +1,432 @@
+/*******************************************************************************
+Copyright (C) 2016 Marvell International Ltd.
+
+Marvell BSD License Option
+
+If you received this File from Marvell, you may opt to use, redistribute and/or
+modify this File under the following licensing terms.
+Redistribution and use in source and binary forms, with or without modification,
+are permitted provided that the following conditions are met:
+
+* Redistributions of source code must retain the above copyright notice,
+ this list of conditions and the following disclaimer.
+
+* Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+* Neither the name of Marvell nor the names of its contributors may be
+ used to endorse or promote products derived from this software without
+ specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
+ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+*******************************************************************************/
+#include "MvSpiDxe.h"
+
+SPI_MASTER *mSpiMasterInstance;
+
+STATIC
+EFI_STATUS
+SpiSetBaudRate (
+ IN SPI_DEVICE *Slave,
+ IN UINT32 CpuClock,
+ IN UINT32 MaxFreq
+ )
+{
+ UINT32 Spr, BestSpr, Sppr, BestSppr, ClockDivider, Match, Reg, MinBaudDiff;
+ UINTN SpiRegBase = Slave->HostRegisterBaseAddress;
+
+ MinBaudDiff = 0xFFFFFFFF;
+ BestSppr = 0;
+
+ //Spr is in range 1-15 and Sppr in range 0-8
+ for (Spr = 1; Spr <= 15; Spr++) {
+ for (Sppr = 0; Sppr <= 7; Sppr++) {
+ ClockDivider = Spr * (1 << Sppr);
+
+ if ((CpuClock / ClockDivider) > MaxFreq) {
+ continue;
+ }
+
+ if ((CpuClock / ClockDivider) == MaxFreq) {
+ BestSpr = Spr;
+ BestSppr = Sppr;
+ Match = 1;
+ break;
+ }
+
+ if ((MaxFreq - (CpuClock / ClockDivider)) < MinBaudDiff) {
+ MinBaudDiff = (MaxFreq - (CpuClock / ClockDivider));
+ BestSpr = Spr;
+ BestSppr = Sppr;
+ }
+ }
+
+ if (Match == 1) {
+ break;
+ }
+ }
+
+ if (BestSpr == 0) {
+ return (EFI_INVALID_PARAMETER);
+ }
+
+ Reg = MmioRead32 (SpiRegBase + SPI_CONF_REG);
+ Reg &= ~(SPI_SPR_MASK | SPI_SPPR_0_MASK | SPI_SPPR_HI_MASK);
+ Reg |= (BestSpr << SPI_SPR_OFFSET) |
+ ((BestSppr & 0x1) << SPI_SPPR_0_OFFSET) |
+ ((BestSppr >> 1) << SPI_SPPR_HI_OFFSET);
+ MmioWrite32 (SpiRegBase + SPI_CONF_REG, Reg);
+
+ return EFI_SUCCESS;
+}
+
+STATIC
+VOID
+SpiSetCs (
+ IN SPI_DEVICE *Slave
+ )
+{
+ UINT32 Reg;
+ UINTN SpiRegBase = Slave->HostRegisterBaseAddress;
+
+ Reg = MmioRead32 (SpiRegBase + SPI_CTRL_REG);
+ Reg &= ~SPI_CS_NUM_MASK;
+ Reg |= (Slave->Cs << SPI_CS_NUM_OFFSET);
+ MmioWrite32 (SpiRegBase + SPI_CTRL_REG, Reg);
+}
+
+STATIC
+VOID
+SpiActivateCs (
+ IN SPI_DEVICE *Slave
+ )
+{
+ UINT32 Reg;
+ UINTN SpiRegBase = Slave->HostRegisterBaseAddress;
+
+ SpiSetCs(Slave);
+ Reg = MmioRead32 (SpiRegBase + SPI_CTRL_REG);
+ Reg |= SPI_CS_EN_MASK;
+ MmioWrite32(SpiRegBase + SPI_CTRL_REG, Reg);
+}
+
+STATIC
+VOID
+SpiDeactivateCs (
+ IN SPI_DEVICE *Slave
+ )
+{
+ UINT32 Reg;
+ UINTN SpiRegBase = Slave->HostRegisterBaseAddress;
+
+ Reg = MmioRead32 (SpiRegBase + SPI_CTRL_REG);
+ Reg &= ~SPI_CS_EN_MASK;
+ MmioWrite32(SpiRegBase + SPI_CTRL_REG, Reg);
+}
+
+STATIC
+VOID
+SpiSetupTransfer (
+ IN MARVELL_SPI_MASTER_PROTOCOL *This,
+ IN SPI_DEVICE *Slave
+ )
+{
+ SPI_MASTER *SpiMaster;
+ UINT32 Reg, CoreClock, SpiMaxFreq;
+ UINTN SpiRegBase;
+
+ SpiMaster = SPI_MASTER_FROM_SPI_MASTER_PROTOCOL (This);
+
+ // Initialize values from PCDs
+ SpiRegBase = Slave->HostRegisterBaseAddress;
+ CoreClock = Slave->CoreClock;
+ SpiMaxFreq = Slave->MaxFreq;
+
+ EfiAcquireLock (&SpiMaster->Lock);
+
+ Reg = MmioRead32 (SpiRegBase + SPI_CONF_REG);
+ Reg |= SPI_BYTE_LENGTH;
+ MmioWrite32 (SpiRegBase + SPI_CONF_REG, Reg);
+
+ SpiSetCs(Slave);
+
+ SpiSetBaudRate (Slave, CoreClock, SpiMaxFreq);
+
+ Reg = MmioRead32 (SpiRegBase + SPI_CONF_REG);
+ Reg &= ~(SPI_CPOL_MASK | SPI_CPHA_MASK | SPI_TXLSBF_MASK | SPI_RXLSBF_MASK);
+
+ switch (Slave->Mode) {
+ case SPI_MODE0:
+ break;
+ case SPI_MODE1:
+ Reg |= SPI_CPHA_MASK;
+ break;
+ case SPI_MODE2:
+ Reg |= SPI_CPOL_MASK;
+ break;
+ case SPI_MODE3:
+ Reg |= SPI_CPOL_MASK;
+ Reg |= SPI_CPHA_MASK;
+ break;
+ }
+
+ MmioWrite32 (SpiRegBase + SPI_CONF_REG, Reg);
+
+ EfiReleaseLock (&SpiMaster->Lock);
+}
+
+EFI_STATUS
+EFIAPI
+MvSpiTransfer (
+ IN MARVELL_SPI_MASTER_PROTOCOL *This,
+ IN SPI_DEVICE *Slave,
+ IN UINTN DataByteCount,
+ IN VOID *DataOut,
+ IN VOID *DataIn,
+ IN UINTN Flag
+ )
+{
+ SPI_MASTER *SpiMaster;
+ UINT64 Length;
+ UINT32 Iterator, Reg;
+ UINT8 *DataOutPtr = (UINT8 *)DataOut;
+ UINT8 *DataInPtr = (UINT8 *)DataIn;
+ UINT8 DataToSend = 0;
+ UINTN SpiRegBase;
+
+ SpiMaster = SPI_MASTER_FROM_SPI_MASTER_PROTOCOL (This);
+
+ SpiRegBase = Slave->HostRegisterBaseAddress;
+
+ Length = 8 * DataByteCount;
+
+ if (!EfiAtRuntime ()) {
+ EfiAcquireLock (&SpiMaster->Lock);
+ }
+
+ if (Flag & SPI_TRANSFER_BEGIN) {
+ SpiActivateCs (Slave);
+ }
+
+ // Set 8-bit mode
+ Reg = MmioRead32 (SpiRegBase + SPI_CONF_REG);
+ Reg &= ~SPI_BYTE_LENGTH;
+ MmioWrite32 (SpiRegBase + SPI_CONF_REG, Reg);
+
+ while (Length > 0) {
+ if (DataOut != NULL) {
+ DataToSend = *DataOutPtr & 0xFF;
+ }
+ // Transmit Data
+ MmioWrite32 (SpiRegBase + SPI_INT_CAUSE_REG, 0x0);
+ MmioWrite32 (SpiRegBase + SPI_DATA_OUT_REG, DataToSend);
+ // Wait for memory ready
+ for (Iterator = 0; Iterator < SPI_TIMEOUT; Iterator++) {
+ if (MmioRead32 (SpiRegBase + SPI_INT_CAUSE_REG)) {
+ if (DataInPtr != NULL) {
+ *DataInPtr = MmioRead32 (SpiRegBase + SPI_DATA_IN_REG);
+ DataInPtr++;
+ }
+ if (DataOutPtr != NULL) {
+ DataOutPtr++;
+ }
+ Length -= 8;
+ break;
+ }
+ }
+
+ if (Iterator >= SPI_TIMEOUT) {
+ DEBUG ((DEBUG_ERROR, "%a: Timeout\n", __FUNCTION__));
+ return EFI_TIMEOUT;
+ }
+ }
+
+ if (Flag & SPI_TRANSFER_END) {
+ SpiDeactivateCs (Slave);
+ }
+
+ if (!EfiAtRuntime ()) {
+ EfiReleaseLock (&SpiMaster->Lock);
+ }
+
+ return EFI_SUCCESS;
+}
+
+EFI_STATUS
+EFIAPI
+MvSpiReadWrite (
+ IN MARVELL_SPI_MASTER_PROTOCOL *This,
+ IN SPI_DEVICE *Slave,
+ IN UINT8 *Cmd,
+ IN UINTN CmdSize,
+ IN UINT8 *DataOut,
+ OUT UINT8 *DataIn,
+ IN UINTN DataSize
+ )
+{
+ EFI_STATUS Status;
+
+ Status = MvSpiTransfer (This, Slave, CmdSize, Cmd, NULL, SPI_TRANSFER_BEGIN);
+ if (EFI_ERROR (Status)) {
+ Print (L"Spi Transfer Error\n");
+ return EFI_DEVICE_ERROR;
+ }
+
+ Status = MvSpiTransfer (This, Slave, DataSize, DataOut, DataIn, SPI_TRANSFER_END);
+ if (EFI_ERROR (Status)) {
+ Print (L"Spi Transfer Error\n");
+ return EFI_DEVICE_ERROR;
+ }
+
+ return EFI_SUCCESS;
+}
+
+EFI_STATUS
+EFIAPI
+MvSpiInit (
+ IN MARVELL_SPI_MASTER_PROTOCOL * This
+ )
+{
+
+ return EFI_SUCCESS;
+}
+
+SPI_DEVICE *
+EFIAPI
+MvSpiSetupSlave (
+ IN MARVELL_SPI_MASTER_PROTOCOL *This,
+ IN SPI_DEVICE *Slave,
+ IN UINTN Cs,
+ IN SPI_MODE Mode
+ )
+{
+ if (!Slave) {
+ Slave = AllocateZeroPool (sizeof(SPI_DEVICE));
+ if (Slave == NULL) {
+ DEBUG((DEBUG_ERROR, "Cannot allocate memory\n"));
+ return NULL;
+ }
+
+ Slave->Cs = Cs;
+ Slave->Mode = Mode;
+ }
+
+ Slave->HostRegisterBaseAddress = PcdGet32 (PcdSpiRegBase);
+ Slave->CoreClock = PcdGet32 (PcdSpiClockFrequency);
+ Slave->MaxFreq = PcdGet32 (PcdSpiMaxFrequency);
+
+ SpiSetupTransfer (This, Slave);
+
+ return Slave;
+}
+
+EFI_STATUS
+EFIAPI
+MvSpiFreeSlave (
+ IN SPI_DEVICE *Slave
+ )
+{
+ FreePool (Slave);
+
+ return EFI_SUCCESS;
+}
+
+EFI_STATUS
+EFIAPI
+MvSpiConfigRuntime (
+ IN SPI_DEVICE *Slave
+ )
+{
+ EFI_STATUS Status;
+ UINTN AlignedAddress;
+
+ //
+ // Host register base may be not aligned to the page size,
+ // which is not accepted when setting memory space attributes.
+ // Add one aligned page of memory space which covers the host
+ // controller registers.
+ //
+ AlignedAddress = Slave->HostRegisterBaseAddress & ~(SIZE_4KB - 1);
+
+ Status = gDS->AddMemorySpace (EfiGcdMemoryTypeMemoryMappedIo,
+ AlignedAddress,
+ SIZE_4KB,
+ EFI_MEMORY_UC | EFI_MEMORY_RUNTIME);
+ if (EFI_ERROR (Status)) {
+ DEBUG ((DEBUG_ERROR, "%a: Failed to add memory space\n", __FUNCTION__));
+ return Status;
+ }
+
+ Status = gDS->SetMemorySpaceAttributes (AlignedAddress,
+ SIZE_4KB,
+ EFI_MEMORY_UC | EFI_MEMORY_RUNTIME);
+ if (EFI_ERROR (Status)) {
+ DEBUG ((DEBUG_ERROR, "%a: Failed to set memory attributes\n", __FUNCTION__));
+ gDS->RemoveMemorySpace (AlignedAddress, SIZE_4KB);
+ return Status;
+ }
+
+ return EFI_SUCCESS;
+}
+
+STATIC
+EFI_STATUS
+SpiMasterInitProtocol (
+ IN MARVELL_SPI_MASTER_PROTOCOL *SpiMasterProtocol
+ )
+{
+
+ SpiMasterProtocol->Init = MvSpiInit;
+ SpiMasterProtocol->SetupDevice = MvSpiSetupSlave;
+ SpiMasterProtocol->FreeDevice = MvSpiFreeSlave;
+ SpiMasterProtocol->Transfer = MvSpiTransfer;
+ SpiMasterProtocol->ReadWrite = MvSpiReadWrite;
+ SpiMasterProtocol->ConfigRuntime = MvSpiConfigRuntime;
+
+ return EFI_SUCCESS;
+}
+
+EFI_STATUS
+EFIAPI
+SpiMasterEntryPoint (
+ IN EFI_HANDLE ImageHandle,
+ IN EFI_SYSTEM_TABLE *SystemTable
+ )
+{
+ EFI_STATUS Status;
+
+ mSpiMasterInstance = AllocateRuntimeZeroPool (sizeof (SPI_MASTER));
+ if (mSpiMasterInstance == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ EfiInitializeLock (&mSpiMasterInstance->Lock, TPL_NOTIFY);
+
+ SpiMasterInitProtocol (&mSpiMasterInstance->SpiMasterProtocol);
+
+ mSpiMasterInstance->Signature = SPI_MASTER_SIGNATURE;
+
+ Status = gBS->InstallMultipleProtocolInterfaces (
+ &(mSpiMasterInstance->Handle),
+ &gMarvellSpiMasterProtocolGuid,
+ &(mSpiMasterInstance->SpiMasterProtocol),
+ NULL
+ );
+ if (EFI_ERROR (Status)) {
+ FreePool (mSpiMasterInstance);
+ return EFI_DEVICE_ERROR;
+ }
+
+ return EFI_SUCCESS;
+}
diff --git a/Silicon/Marvell/Drivers/Spi/MvSpiDxe.h b/Silicon/Marvell/Drivers/Spi/MvSpiDxe.h
new file mode 100644
index 0000000000..50cdc025c7
--- /dev/null
+++ b/Silicon/Marvell/Drivers/Spi/MvSpiDxe.h
@@ -0,0 +1,148 @@
+/*******************************************************************************
+Copyright (C) 2016 Marvell International Ltd.
+
+Marvell BSD License Option
+
+If you received this File from Marvell, you may opt to use, redistribute and/or
+modify this File under the following licensing terms.
+Redistribution and use in source and binary forms, with or without modification,
+are permitted provided that the following conditions are met:
+
+* Redistributions of source code must retain the above copyright notice,
+ this list of conditions and the following disclaimer.
+
+* Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+* Neither the name of Marvell nor the names of its contributors may be
+ used to endorse or promote products derived from this software without
+ specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
+ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+*******************************************************************************/
+#ifndef __SPI_MASTER_H__
+#define __SPI_MASTER_H__
+
+#include <Library/IoLib.h>
+#include <Library/PcdLib.h>
+#include <Library/UefiLib.h>
+#include <Library/DebugLib.h>
+#include <Library/DxeServicesTableLib.h>
+#include <Library/MemoryAllocationLib.h>
+#include <Uefi/UefiBaseType.h>
+#include <Library/BaseMemoryLib.h>
+#include <Library/UefiBootServicesTableLib.h>
+#include <Library/UefiRuntimeLib.h>
+
+#include <Protocol/Spi.h>
+
+#define SPI_MASTER_SIGNATURE SIGNATURE_32 ('M', 'S', 'P', 'I')
+#define SPI_MASTER_FROM_SPI_MASTER_PROTOCOL(a) CR (a, SPI_MASTER, SpiMasterProtocol, SPI_MASTER_SIGNATURE)
+
+// Marvell Flash Device Controller Registers
+#define SPI_CTRL_REG (0x00)
+#define SPI_CONF_REG (0x04)
+#define SPI_DATA_OUT_REG (0x08)
+#define SPI_DATA_IN_REG (0x0c)
+#define SPI_INT_CAUSE_REG (0x10)
+
+// Serial Memory Interface Control Register Masks
+#define SPI_CS_NUM_OFFSET 2
+#define SPI_CS_NUM_MASK (0x7 << SPI_CS_NUM_OFFSET)
+#define SPI_MEM_READY_MASK (0x1 << 1)
+#define SPI_CS_EN_MASK (0x1 << 0)
+
+// Serial Memory Interface Configuration Register Masks
+#define SPI_BYTE_LENGTH_OFFSET 5
+#define SPI_BYTE_LENGTH (0x1 << SPI_BYTE_LENGTH_OFFSET)
+#define SPI_CPOL_OFFSET 11
+#define SPI_CPOL_MASK (0x1 << SPI_CPOL_OFFSET)
+#define SPI_CPHA_OFFSET 12
+#define SPI_CPHA_MASK (0x1 << SPI_CPHA_OFFSET)
+#define SPI_TXLSBF_OFFSET 13
+#define SPI_TXLSBF_MASK (0x1 << SPI_TXLSBF_OFFSET)
+#define SPI_RXLSBF_OFFSET 14
+#define SPI_RXLSBF_MASK (0x1 << SPI_RXLSBF_OFFSET)
+
+#define SPI_SPR_OFFSET 0
+#define SPI_SPR_MASK (0xf << SPI_SPR_OFFSET)
+#define SPI_SPPR_0_OFFSET 4
+#define SPI_SPPR_0_MASK (0x1 << SPI_SPPR_0_OFFSET)
+#define SPI_SPPR_HI_OFFSET 6
+#define SPI_SPPR_HI_MASK (0x3 << SPI_SPPR_HI_OFFSET)
+
+#define SPI_TRANSFER_BEGIN 0x01 // Assert CS before transfer
+#define SPI_TRANSFER_END 0x02 // Deassert CS after transfers
+
+#define SPI_TIMEOUT 100000
+
+typedef struct {
+ MARVELL_SPI_MASTER_PROTOCOL SpiMasterProtocol;
+ UINTN Signature;
+ EFI_HANDLE Handle;
+ EFI_LOCK Lock;
+} SPI_MASTER;
+
+EFI_STATUS
+EFIAPI
+MvSpiTransfer (
+ IN MARVELL_SPI_MASTER_PROTOCOL *This,
+ IN SPI_DEVICE *Slave,
+ IN UINTN DataByteCount,
+ IN VOID *DataOut,
+ IN VOID *DataIn,
+ IN UINTN Flag
+ );
+
+EFI_STATUS
+EFIAPI
+MvSpiReadWrite (
+ IN MARVELL_SPI_MASTER_PROTOCOL *This,
+ IN SPI_DEVICE *Slave,
+ IN UINT8 *Cmd,
+ IN UINTN CmdSize,
+ IN UINT8 *DataOut,
+ OUT UINT8 *DataIn,
+ IN UINTN DataSize
+ );
+
+EFI_STATUS
+EFIAPI
+MvSpiInit (
+ IN MARVELL_SPI_MASTER_PROTOCOL * This
+ );
+
+SPI_DEVICE *
+EFIAPI
+MvSpiSetupSlave (
+ IN MARVELL_SPI_MASTER_PROTOCOL * This,
+ IN SPI_DEVICE *Slave,
+ IN UINTN Cs,
+ IN SPI_MODE Mode
+ );
+
+EFI_STATUS
+EFIAPI
+MvSpiFreeSlave (
+ IN SPI_DEVICE *Slave
+ );
+
+EFI_STATUS
+EFIAPI
+SpiMasterEntryPoint (
+ IN EFI_HANDLE ImageHandle,
+ IN EFI_SYSTEM_TABLE *SystemTable
+ );
+
+#endif // __SPI_MASTER_H__
diff --git a/Silicon/Marvell/Drivers/Spi/MvSpiDxe.inf b/Silicon/Marvell/Drivers/Spi/MvSpiDxe.inf
new file mode 100644
index 0000000000..e7bc170e64
--- /dev/null
+++ b/Silicon/Marvell/Drivers/Spi/MvSpiDxe.inf
@@ -0,0 +1,73 @@
+#
+# Marvell BSD License Option
+#
+# If you received this File from Marvell, you may opt to use, redistribute
+# and/or modify this File under the following licensing terms.
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are met:
+#
+# * Redistributions of source code must retain the above copyright notice,
+# this list of conditions and the following disclaimer.
+#
+# * Redistributions in binary form must reproduce the above copyright
+# notice, this list of conditions and the following disclaimer in the
+# documentation and/or other materials provided with the distribution.
+#
+# * Neither the name of Marvell nor the names of its contributors may be
+# used to endorse or promote products derived from this software without
+# specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE
+# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+#
+
+[Defines]
+ INF_VERSION = 0x00010005
+ BASE_NAME = SpiMasterDxe
+ FILE_GUID = c19dbc8a-f4f9-43b0-aee5-802e3ed03d15
+ MODULE_TYPE = DXE_RUNTIME_DRIVER
+ VERSION_STRING = 1.0
+ ENTRY_POINT = SpiMasterEntryPoint
+
+[Sources]
+ MvSpiDxe.c
+ MvSpiDxe.h
+
+[Packages]
+ EmbeddedPkg/EmbeddedPkg.dec
+ MdePkg/MdePkg.dec
+ Silicon/Marvell/Marvell.dec
+
+[LibraryClasses]
+ NorFlashInfoLib
+ UefiBootServicesTableLib
+ UefiDriverEntryPoint
+ TimerLib
+ UefiLib
+ DebugLib
+ DxeServicesTableLib
+ MemoryAllocationLib
+ IoLib
+ UefiRuntimeLib
+
+[FixedPcd]
+ gMarvellTokenSpaceGuid.PcdSpiRegBase
+ gMarvellTokenSpaceGuid.PcdSpiClockFrequency
+ gMarvellTokenSpaceGuid.PcdSpiMaxFrequency
+
+[Protocols]
+ gMarvellSpiMasterProtocolGuid
+
+[Depex]
+ #
+ # MvSpiDxe must be loaded prior to MvSpiFlash driver
+ #
+ BEFORE gMarvellSpiFlashDxeGuid
diff --git a/Silicon/Marvell/Drivers/Spi/Variables/MvFvbDxe.c b/Silicon/Marvell/Drivers/Spi/Variables/MvFvbDxe.c
new file mode 100644
index 0000000000..252ef67566
--- /dev/null
+++ b/Silicon/Marvell/Drivers/Spi/Variables/MvFvbDxe.c
@@ -0,0 +1,1138 @@
+/*++ @file MvFvbDxe.c
+
+ Copyright (c) 2011 - 2014, ARM Ltd. All rights reserved.<BR>
+ Copyright (c) 2017 Marvell International Ltd.<BR>
+
+ 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 <PiDxe.h>
+
+#include <Library/BaseLib.h>
+#include <Library/BaseMemoryLib.h>
+#include <Library/DebugLib.h>
+#include <Library/DxeServicesTableLib.h>
+#include <Library/HobLib.h>
+#include <Library/MemoryAllocationLib.h>
+#include <Library/PcdLib.h>
+#include <Library/UefiBootServicesTableLib.h>
+#include <Library/UefiLib.h>
+#include <Library/UefiRuntimeLib.h>
+
+#include <Guid/SystemNvDataGuid.h>
+#include <Guid/VariableFormat.h>
+
+#include "MvFvbDxe.h"
+
+STATIC EFI_EVENT mFvbVirtualAddrChangeEvent;
+STATIC FVB_DEVICE *mFvbDevice;
+
+STATIC CONST FVB_DEVICE mMvFvbFlashInstanceTemplate = {
+ {
+ 0, // SpiFlash Chip Select ... NEED TO BE FILLED
+ 0, // SpiFlash Maximum Frequency ... NEED TO BE FILLED
+ 0, // SpiFlash Transfer Mode ... NEED TO BE FILLED
+ 0, // SpiFlash Address Size ... NEED TO BE FILLED
+ NULL, // SpiFlash detailed information ... NEED TO BE FILLED
+ 0, // HostRegisterBaseAddress ... NEED TO BE FILLED
+ 0, // CoreClock ... NEED TO BE FILLED
+ }, // SpiDevice
+
+ NULL, // SpiFlashProtocol ... NEED TO BE FILLED
+ NULL, // SpiMasterProtocol ... NEED TO BE FILLED
+ NULL, // Handle ... NEED TO BE FILLED
+
+ FVB_FLASH_SIGNATURE, // Signature
+
+ 0, // DeviceBaseAddress ... NEED TO BE FILLED
+ 0, // RegionBaseAddress ... NEED TO BE FILLED
+ SIZE_256KB, // Size
+ 0, // FvbOffset ... NEED TO BE FILLED
+ 0, // FvbSize ... NEED TO BE FILLED
+ 0, // StartLba
+
+ {
+ 0, // MediaId ... NEED TO BE FILLED
+ FALSE, // RemovableMedia
+ TRUE, // MediaPresent
+ FALSE, // LogicalPartition
+ FALSE, // ReadOnly
+ FALSE, // WriteCaching;
+ 0, // BlockSize ... NEED TO BE FILLED
+ 4, // IoAlign
+ 0, // LastBlock ... NEED TO BE FILLED
+ 0, // LowestAlignedLba
+ 1, // LogicalBlocksPerPhysicalBlock
+ }, //Media;
+
+ {
+ MvFvbGetAttributes, // GetAttributes
+ MvFvbSetAttributes, // SetAttributes
+ MvFvbGetPhysicalAddress, // GetPhysicalAddress
+ MvFvbGetBlockSize, // GetBlockSize
+ MvFvbRead, // Read
+ MvFvbWrite, // Write
+ MvFvbEraseBlocks, // EraseBlocks
+ NULL, // ParentHandle
+ }, // FvbProtocol;
+
+ {
+ {
+ {
+ HARDWARE_DEVICE_PATH,
+ HW_VENDOR_DP,
+ {
+ (UINT8)sizeof (VENDOR_DEVICE_PATH),
+ (UINT8)((sizeof (VENDOR_DEVICE_PATH)) >> 8)
+ }
+ },
+ { 0xfc0cb972, 0x21df, 0x44d2, { 0x92, 0xa5, 0x78, 0x98, 0x99, 0xcb, 0xf6, 0x61 } }
+ },
+ {
+ END_DEVICE_PATH_TYPE,
+ END_ENTIRE_DEVICE_PATH_SUBTYPE,
+ { sizeof (EFI_DEVICE_PATH_PROTOCOL), 0 }
+ }
+ } // DevicePath
+};
+
+//
+// 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
+
+**/
+STATIC
+EFI_STATUS
+MvFvbInitFvAndVariableStoreHeaders (
+ IN FVB_DEVICE *FlashInstance
+ )
+{
+ EFI_FIRMWARE_VOLUME_HEADER *FirmwareVolumeHeader;
+ VARIABLE_STORE_HEADER *VariableStoreHeader;
+ EFI_STATUS Status;
+ VOID* Headers;
+ UINTN HeadersLength;
+ UINTN BlockSize;
+
+ HeadersLength = sizeof (EFI_FIRMWARE_VOLUME_HEADER) +
+ sizeof (EFI_FV_BLOCK_MAP_ENTRY) +
+ sizeof (VARIABLE_STORE_HEADER);
+ Headers = AllocateZeroPool (HeadersLength);
+
+ BlockSize = FlashInstance->Media.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);
+
+ //
+ // EFI_FIRMWARE_VOLUME_HEADER
+ //
+ FirmwareVolumeHeader = (EFI_FIRMWARE_VOLUME_HEADER*)Headers;
+ CopyGuid (&FirmwareVolumeHeader->FileSystemGuid, &gEfiSystemNvDataFvGuid);
+ FirmwareVolumeHeader->FvLength = FlashInstance->FvbSize;
+ FirmwareVolumeHeader->Signature = EFI_FVH_SIGNATURE;
+ FirmwareVolumeHeader->Attributes = EFI_FVB2_READ_ENABLED_CAP |
+ EFI_FVB2_READ_STATUS |
+ EFI_FVB2_STICKY_WRITE |
+ EFI_FVB2_MEMORY_MAPPED |
+ EFI_FVB2_ERASE_POLARITY |
+ EFI_FVB2_WRITE_STATUS |
+ EFI_FVB2_WRITE_ENABLED_CAP;
+
+ FirmwareVolumeHeader->HeaderLength = sizeof (EFI_FIRMWARE_VOLUME_HEADER) +
+ sizeof (EFI_FV_BLOCK_MAP_ENTRY);
+ FirmwareVolumeHeader->Revision = EFI_FVH_REVISION;
+ FirmwareVolumeHeader->BlockMap[0].NumBlocks = FlashInstance->Media.LastBlock + 1;
+ FirmwareVolumeHeader->BlockMap[0].Length = FlashInstance->Media.BlockSize;
+ FirmwareVolumeHeader->BlockMap[1].NumBlocks = 0;
+ FirmwareVolumeHeader->BlockMap[1].Length = 0;
+ FirmwareVolumeHeader->Checksum = CalculateCheckSum16 (
+ (UINT16 *)FirmwareVolumeHeader,
+ FirmwareVolumeHeader->HeaderLength);
+
+ //
+ // VARIABLE_STORE_HEADER
+ //
+ VariableStoreHeader = (VOID *)((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 flash device
+ Status = MvFvbWrite (&FlashInstance->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.
+
+**/
+STATIC
+EFI_STATUS
+MvFvbValidateFvHeader (
+ IN FVB_DEVICE *FlashInstance
+ )
+{
+ UINT16 Checksum;
+ EFI_FIRMWARE_VOLUME_HEADER *FwVolHeader;
+ VARIABLE_STORE_HEADER *VariableStoreHeader;
+ UINTN VariableStoreLength;
+
+ FwVolHeader = (EFI_FIRMWARE_VOLUME_HEADER *)FlashInstance->RegionBaseAddress;
+
+ // Verify the header revision, header signature, length
+ if ((FwVolHeader->Revision != EFI_FVH_REVISION) ||
+ (FwVolHeader->Signature != EFI_FVH_SIGNATURE) ||
+ (FwVolHeader->FvLength != FlashInstance->FvbSize)) {
+ 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)) {
+ 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 = (VOID *)((UINTN)FwVolHeader + FwVolHeader->HeaderLength);
+
+ // Check the Variable Store Guid
+ if (!CompareGuid (&VariableStoreHeader->Signature, &gEfiVariableGuid) &&
+ !CompareGuid (&VariableStoreHeader->Signature,
+ &gEfiAuthenticatedVariableGuid)) {
+ DEBUG ((DEBUG_ERROR,
+ "%a: Variable Store Guid non-compatible\n",
+ __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
+MvFvbGetAttributes (
+ IN CONST EFI_FIRMWARE_VOLUME_BLOCK2_PROTOCOL *This,
+ OUT EFI_FVB_ATTRIBUTES_2 *Attributes
+ )
+{
+ EFI_FIRMWARE_VOLUME_HEADER *FwVolHeader;
+ EFI_FVB_ATTRIBUTES_2 *FlashFvbAttributes;
+ FVB_DEVICE *FlashInstance;
+
+ FlashInstance = INSTANCE_FROM_FVB_THIS (This);
+
+ FwVolHeader = (EFI_FIRMWARE_VOLUME_HEADER *)FlashInstance->RegionBaseAddress;
+ FlashFvbAttributes = (EFI_FVB_ATTRIBUTES_2 *)&(FwVolHeader->Attributes);
+
+ *Attributes = *FlashFvbAttributes;
+
+ return EFI_SUCCESS;
+}
+
+/**
+ The SetAttributes() function sets configurable firmware volume attributes
+ and returns the new settings of the firmware volume.
+
+
+ @param This 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.
+
+ @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
+MvFvbSetAttributes (
+ IN CONST EFI_FIRMWARE_VOLUME_BLOCK2_PROTOCOL *This,
+ IN OUT EFI_FVB_ATTRIBUTES_2 *Attributes
+ )
+{
+ EFI_FVB_ATTRIBUTES_2 OldAttributes;
+ EFI_FVB_ATTRIBUTES_2 FlashFvbAttributes;
+ EFI_FVB_ATTRIBUTES_2 UnchangedAttributes;
+ UINT32 Capabilities;
+ UINT32 OldStatus;
+ UINT32 NewStatus;
+
+ //
+ // Obtain attributes from FVB header
+ //
+ MvFvbGetAttributes (This, &FlashFvbAttributes);
+
+ OldAttributes = FlashFvbAttributes;
+ Capabilities = OldAttributes & EFI_FVB2_CAPABILITIES;
+ OldStatus = OldAttributes & EFI_FVB2_STATUS;
+ NewStatus = *Attributes & EFI_FVB2_STATUS;
+
+ UnchangedAttributes = EFI_FVB2_READ_DISABLED_CAP | \
+ EFI_FVB2_READ_ENABLED_CAP | \
+ EFI_FVB2_WRITE_DISABLED_CAP | \
+ EFI_FVB2_WRITE_ENABLED_CAP | \
+ EFI_FVB2_LOCK_CAP | \
+ EFI_FVB2_STICKY_WRITE | \
+ EFI_FVB2_MEMORY_MAPPED | \
+ EFI_FVB2_ERASE_POLARITY | \
+ EFI_FVB2_READ_LOCK_CAP | \
+ EFI_FVB2_WRITE_LOCK_CAP | \
+ EFI_FVB2_ALIGNMENT;
+
+ //
+ // Some attributes of FV is read only can *not* be set
+ //
+ if ((OldAttributes & UnchangedAttributes) ^
+ (*Attributes & UnchangedAttributes)) {
+ return EFI_INVALID_PARAMETER;
+ }
+ //
+ // If firmware volume is locked, no status bit can be updated
+ //
+ if (OldAttributes & EFI_FVB2_LOCK_STATUS) {
+ if (OldStatus ^ NewStatus) {
+ return EFI_ACCESS_DENIED;
+ }
+ }
+ //
+ // Test read disable
+ //
+ if ((Capabilities & EFI_FVB2_READ_DISABLED_CAP) == 0) {
+ if ((NewStatus & EFI_FVB2_READ_STATUS) == 0) {
+ return EFI_INVALID_PARAMETER;
+ }
+ }
+ //
+ // Test read enable
+ //
+ if ((Capabilities & EFI_FVB2_READ_ENABLED_CAP) == 0) {
+ if (NewStatus & EFI_FVB2_READ_STATUS) {
+ return EFI_INVALID_PARAMETER;
+ }
+ }
+ //
+ // Test write disable
+ //
+ if ((Capabilities & EFI_FVB2_WRITE_DISABLED_CAP) == 0) {
+ if ((NewStatus & EFI_FVB2_WRITE_STATUS) == 0) {
+ return EFI_INVALID_PARAMETER;
+ }
+ }
+ //
+ // Test write enable
+ //
+ if ((Capabilities & EFI_FVB2_WRITE_ENABLED_CAP) == 0) {
+ if (NewStatus & EFI_FVB2_WRITE_STATUS) {
+ return EFI_INVALID_PARAMETER;
+ }
+ }
+ //
+ // Test lock
+ //
+ if ((Capabilities & EFI_FVB2_LOCK_CAP) == 0) {
+ if (NewStatus & EFI_FVB2_LOCK_STATUS) {
+ return EFI_INVALID_PARAMETER;
+ }
+ }
+
+ FlashFvbAttributes = FlashFvbAttributes & (0xFFFFFFFF & (~EFI_FVB2_STATUS));
+ FlashFvbAttributes = FlashFvbAttributes | NewStatus;
+ *Attributes = FlashFvbAttributes;
+
+ return EFI_SUCCESS;
+}
+
+/**
+ 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 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
+MvFvbGetPhysicalAddress (
+ IN CONST EFI_FIRMWARE_VOLUME_BLOCK2_PROTOCOL *This,
+ OUT EFI_PHYSICAL_ADDRESS *Address
+ )
+{
+ FVB_DEVICE *FlashInstance;
+
+ ASSERT (Address != NULL);
+
+ FlashInstance = INSTANCE_FROM_FVB_THIS (This);
+
+ *Address = FlashInstance->RegionBaseAddress;
+
+ 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 EFI_FIRMWARE_VOLUME_BLOCK2_PROTOCOL instance.
+
+ @param Lba Indicates the block whose size to return
+
+ @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
+MvFvbGetBlockSize (
+ IN CONST EFI_FIRMWARE_VOLUME_BLOCK2_PROTOCOL *This,
+ IN EFI_LBA Lba,
+ OUT UINTN *BlockSize,
+ OUT UINTN *NumberOfBlocks
+ )
+{
+ FVB_DEVICE *FlashInstance;
+
+ FlashInstance = INSTANCE_FROM_FVB_THIS (This);
+
+ if (Lba > FlashInstance->Media.LastBlock) {
+ DEBUG ((DEBUG_ERROR,
+ "%a: Error: Requested LBA %ld is beyond the last available LBA (%ld).\n",
+ __FUNCTION__,
+ Lba,
+ FlashInstance->Media.LastBlock));
+ return EFI_INVALID_PARAMETER;
+ } else {
+ // Assume equal sized blocks in all flash devices
+ *BlockSize = (UINTN)FlashInstance->Media.BlockSize;
+ *NumberOfBlocks = (UINTN)(FlashInstance->Media.LastBlock - Lba + 1);
+
+ return EFI_SUCCESS;
+ }
+}
+
+/**
+ 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 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
+MvFvbRead (
+ IN CONST EFI_FIRMWARE_VOLUME_BLOCK2_PROTOCOL *This,
+ IN EFI_LBA Lba,
+ IN UINTN Offset,
+ IN OUT UINTN *NumBytes,
+ IN OUT UINT8 *Buffer
+ )
+{
+ FVB_DEVICE *FlashInstance;
+ UINTN BlockSize;
+ UINTN DataOffset;
+
+ FlashInstance = INSTANCE_FROM_FVB_THIS (This);
+
+
+ // Cache the block size to avoid de-referencing pointers all the time
+ BlockSize = FlashInstance->Media.BlockSize;
+
+ //
+ // The read 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,
+ "%a: Wrong buffer size: (Offset=0x%x + NumBytes=0x%x) > BlockSize=0x%x\n",
+ __FUNCTION__,
+ Offset,
+ *NumBytes,
+ BlockSize));
+ return EFI_BAD_BUFFER_SIZE;
+ }
+
+ // No bytes to read
+ if (*NumBytes == 0) {
+ return EFI_SUCCESS;
+ }
+
+ DataOffset = GET_DATA_OFFSET (FlashInstance->RegionBaseAddress + Offset,
+ FlashInstance->StartLba + Lba,
+ FlashInstance->Media.BlockSize);
+
+ // Read the memory-mapped data
+ CopyMem (Buffer, (UINTN *)DataOffset, *NumBytes);
+
+ return EFI_SUCCESS;
+}
+
+/**
+ 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 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
+MvFvbWrite (
+ IN CONST EFI_FIRMWARE_VOLUME_BLOCK2_PROTOCOL *This,
+ IN EFI_LBA Lba,
+ IN UINTN Offset,
+ IN OUT UINTN *NumBytes,
+ IN UINT8 *Buffer
+ )
+{
+ FVB_DEVICE *FlashInstance;
+ UINTN DataOffset;
+
+ FlashInstance = INSTANCE_FROM_FVB_THIS (This);
+
+ DataOffset = GET_DATA_OFFSET (FlashInstance->FvbOffset + Offset,
+ FlashInstance->StartLba + Lba,
+ FlashInstance->Media.BlockSize);
+
+ return FlashInstance->SpiFlashProtocol->Write (&FlashInstance->SpiDevice,
+ DataOffset,
+ *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 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.
+
+ @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
+MvFvbEraseBlocks (
+ IN CONST EFI_FIRMWARE_VOLUME_BLOCK2_PROTOCOL *This,
+ ...
+ )
+{
+ EFI_FVB_ATTRIBUTES_2 FlashFvbAttributes;
+ FVB_DEVICE *FlashInstance;
+ 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
+
+ FlashInstance = INSTANCE_FROM_FVB_THIS (This);
+
+ Status = EFI_SUCCESS;
+
+ // Detect WriteDisabled state
+ MvFvbGetAttributes (This, &FlashFvbAttributes);
+ if ((FlashFvbAttributes & EFI_FVB2_WRITE_STATUS) == 0) {
+ DEBUG ((DEBUG_ERROR,
+ "%a: Device is in WriteDisabled state.\n",
+ __FUNCTION__));
+ 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
+ if (NumOfLba == 0 ||
+ (FlashInstance->StartLba + StartingLba + NumOfLba - 1) >
+ FlashInstance->Media.LastBlock) {
+
+ DEBUG ((DEBUG_ERROR,
+ "%a: Error: Requested LBA are beyond the last available LBA (%ld).\n",
+ __FUNCTION__,
+ FlashInstance->Media.LastBlock));
+
+ VA_END (Args);
+
+ return EFI_INVALID_PARAMETER;
+ }
+ } while (TRUE);
+ VA_END (Args);
+
+ //
+ // 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_DATA_OFFSET (FlashInstance->FvbOffset,
+ FlashInstance->StartLba + StartingLba,
+ FlashInstance->Media.BlockSize);
+
+ // Erase single block
+ Status = FlashInstance->SpiFlashProtocol->Erase (&FlashInstance->SpiDevice,
+ BlockAddress,
+ FlashInstance->Media.BlockSize);
+ if (EFI_ERROR (Status)) {
+ VA_END (Args);
+ return EFI_DEVICE_ERROR;
+ }
+
+ // Move to the next Lba
+ StartingLba++;
+ NumOfLba--;
+ }
+ } while (TRUE);
+ VA_END (Args);
+
+ 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
+**/
+STATIC
+VOID
+EFIAPI
+MvFvbVirtualNotifyEvent (
+ IN EFI_EVENT Event,
+ IN VOID *Context
+ )
+{
+ // Convert SPI memory mapped region
+ EfiConvertPointer (0x0, (VOID**)&mFvbDevice->RegionBaseAddress);
+
+ // Convert SPI device description
+ EfiConvertPointer (0x0, (VOID**)&mFvbDevice->SpiDevice.Info);
+ EfiConvertPointer (0x0, (VOID**)&mFvbDevice->SpiDevice.HostRegisterBaseAddress);
+ EfiConvertPointer (0x0, (VOID**)&mFvbDevice->SpiDevice);
+
+ // Convert SpiFlashProtocol
+ EfiConvertPointer (0x0, (VOID**)&mFvbDevice->SpiFlashProtocol->Erase);
+ EfiConvertPointer (0x0, (VOID**)&mFvbDevice->SpiFlashProtocol->Write);
+ EfiConvertPointer (0x0, (VOID**)&mFvbDevice->SpiFlashProtocol);
+
+ return;
+}
+
+STATIC
+EFI_STATUS
+MvFvbFlashProbe (
+ IN FVB_DEVICE *FlashInstance
+ )
+{
+ MARVELL_SPI_FLASH_PROTOCOL *SpiFlashProtocol;
+ EFI_STATUS Status;
+
+ SpiFlashProtocol = FlashInstance->SpiFlashProtocol;
+
+ // Read SPI flash ID
+ Status = SpiFlashProtocol->ReadId (&FlashInstance->SpiDevice, TRUE);
+ if (EFI_ERROR (Status)) {
+ return EFI_NOT_FOUND;
+ }
+
+ Status = SpiFlashProtocol->Init (SpiFlashProtocol, &FlashInstance->SpiDevice);
+ if (EFI_ERROR (Status)) {
+ DEBUG ((DEBUG_ERROR, "%a: Cannot initialize flash device\n", __FUNCTION__));
+ return EFI_DEVICE_ERROR;
+ }
+
+ //
+ // SPI flash may require 20ms interval between enabling it and
+ // accessing in Direct Mode to its memory mapped content.
+ //
+ gBS->Stall (20000);
+
+ return EFI_SUCCESS;
+}
+
+STATIC
+EFI_STATUS
+MvFvbPrepareFvHeader (
+ IN FVB_DEVICE *FlashInstance
+ )
+{
+ EFI_BOOT_MODE BootMode;
+ EFI_STATUS Status;
+
+ // Check if it is required to use default environment
+ BootMode = GetBootModeHob ();
+ if (BootMode == BOOT_WITH_DEFAULT_SETTINGS) {
+ Status = EFI_INVALID_PARAMETER;
+ } else {
+ // Validate header at the beginning of FV region
+ Status = MvFvbValidateFvHeader (FlashInstance);
+ }
+
+ // Install the default FVB header if required
+ if (EFI_ERROR (Status)) {
+ // There is no valid header, so time to install one.
+ DEBUG ((DEBUG_ERROR, "%a: The FVB Header is not valid.\n", __FUNCTION__));
+ DEBUG ((DEBUG_ERROR,
+ "%a: Installing a correct one for this volume.\n",
+ __FUNCTION__));
+
+ // Erase entire region that is reserved for variable storage
+ Status = FlashInstance->SpiFlashProtocol->Erase (&FlashInstance->SpiDevice,
+ FlashInstance->FvbOffset,
+ FlashInstance->FvbSize);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ // Install all appropriate headers
+ Status = MvFvbInitFvAndVariableStoreHeaders (FlashInstance);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ }
+
+ return EFI_SUCCESS;
+}
+
+STATIC
+EFI_STATUS
+MvFvbConfigureFlashInstance (
+ IN OUT FVB_DEVICE *FlashInstance
+ )
+{
+ EFI_STATUS Status;
+
+
+ // Locate SPI protocols
+ Status = gBS->LocateProtocol (&gMarvellSpiFlashProtocolGuid,
+ NULL,
+ (VOID **)&FlashInstance->SpiFlashProtocol);
+ if (EFI_ERROR (Status)) {
+ DEBUG ((DEBUG_ERROR, "%a: Cannot locate SpiFlash protocol\n", __FUNCTION__));
+ return Status;
+ }
+
+ Status = gBS->LocateProtocol (&gMarvellSpiMasterProtocolGuid,
+ NULL,
+ (VOID **)&FlashInstance->SpiMasterProtocol);
+ if (EFI_ERROR (Status)) {
+ DEBUG ((DEBUG_ERROR, "%a: Cannot locate SpiMaster protocol\n", __FUNCTION__));
+ return Status;
+ }
+
+ // Setup and probe SPI flash
+ FlashInstance->SpiMasterProtocol->SetupDevice (FlashInstance->SpiMasterProtocol,
+ &FlashInstance->SpiDevice,
+ 0,
+ 0);
+
+ Status = MvFvbFlashProbe (FlashInstance);
+ if (EFI_ERROR (Status)) {
+ DEBUG ((DEBUG_ERROR,
+ "%a: Error while performing SPI flash probe\n",
+ __FUNCTION__));
+ return Status;
+ }
+
+ // Fill remaining flash description
+ FlashInstance->DeviceBaseAddress = PcdGet32 (PcdSpiMemoryBase);
+ FlashInstance->RegionBaseAddress = FixedPcdGet32 (PcdFlashNvStorageVariableBase);
+ FlashInstance->FvbOffset = FlashInstance->RegionBaseAddress -
+ FlashInstance->DeviceBaseAddress;
+ FlashInstance->FvbSize = PcdGet32(PcdFlashNvStorageVariableSize) +
+ PcdGet32(PcdFlashNvStorageFtwWorkingSize) +
+ PcdGet32(PcdFlashNvStorageFtwSpareSize);
+
+ FlashInstance->Media.MediaId = 0;
+ FlashInstance->Media.BlockSize = FlashInstance->SpiDevice.Info->SectorSize;
+ FlashInstance->Media.LastBlock = FlashInstance->Size /
+ FlashInstance->Media.BlockSize - 1;
+
+ Status = gBS->InstallMultipleProtocolInterfaces (&FlashInstance->Handle,
+ &gEfiDevicePathProtocolGuid, &FlashInstance->DevicePath,
+ &gEfiFirmwareVolumeBlockProtocolGuid, &FlashInstance->FvbProtocol,
+ NULL);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ Status = MvFvbPrepareFvHeader (FlashInstance);
+ if (EFI_ERROR (Status)) {
+ goto ErrorPrepareFvbHeader;
+ }
+
+ return EFI_SUCCESS;
+
+ErrorPrepareFvbHeader:
+ gBS->UninstallMultipleProtocolInterfaces (&FlashInstance->Handle,
+ &gEfiDevicePathProtocolGuid,
+ &gEfiFirmwareVolumeBlockProtocolGuid,
+ NULL);
+
+ return Status;
+}
+
+EFI_STATUS
+EFIAPI
+MvFvbEntryPoint (
+ IN EFI_HANDLE ImageHandle,
+ IN EFI_SYSTEM_TABLE *SystemTable
+ )
+{
+ EFI_STATUS Status;
+ UINTN RuntimeMmioRegionSize;
+ UINTN RegionBaseAddress;
+
+ //
+ // Create FVB flash device
+ //
+ mFvbDevice = AllocateRuntimeCopyPool (sizeof (mMvFvbFlashInstanceTemplate),
+ &mMvFvbFlashInstanceTemplate);
+ if (mFvbDevice == NULL) {
+ DEBUG ((DEBUG_ERROR, "%a: Cannot allocate memory\n", __FUNCTION__));
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ //
+ // Detect and configure flash device
+ //
+ Status = MvFvbConfigureFlashInstance (mFvbDevice);
+ if (EFI_ERROR (Status)) {
+ DEBUG ((DEBUG_ERROR, "%a: Fail to configure Fvb SPI device\n", __FUNCTION__));
+ goto ErrorConfigureFlash;
+ }
+
+ //
+ // Declare the Non-Volatile storage as EFI_MEMORY_RUNTIME
+ //
+ RuntimeMmioRegionSize = mFvbDevice->FvbSize;
+ RegionBaseAddress = mFvbDevice->RegionBaseAddress;
+
+ Status = gDS->AddMemorySpace (EfiGcdMemoryTypeMemoryMappedIo,
+ RegionBaseAddress,
+ RuntimeMmioRegionSize,
+ EFI_MEMORY_UC | EFI_MEMORY_RUNTIME);
+ if (EFI_ERROR (Status)) {
+ DEBUG ((DEBUG_ERROR, "%a: Failed to add memory space\n", __FUNCTION__));
+ goto ErrorAddSpace;
+ }
+
+ Status = gDS->SetMemorySpaceAttributes (RegionBaseAddress,
+ RuntimeMmioRegionSize,
+ EFI_MEMORY_UC | EFI_MEMORY_RUNTIME);
+ if (EFI_ERROR (Status)) {
+ DEBUG ((DEBUG_ERROR, "%a: Failed to set memory attributes\n", __FUNCTION__));
+ goto ErrorSetMemAttr;
+ }
+
+ //
+ // Register for the virtual address change event
+ //
+ Status = gBS->CreateEventEx (EVT_NOTIFY_SIGNAL,
+ TPL_NOTIFY,
+ MvFvbVirtualNotifyEvent,
+ NULL,
+ &gEfiEventVirtualAddressChangeGuid,
+ &mFvbVirtualAddrChangeEvent);
+ if (EFI_ERROR (Status)) {
+ DEBUG ((DEBUG_ERROR, "%a: Failed to register VA change event\n", __FUNCTION__));
+ goto ErrorSetMemAttr;
+ }
+
+ //
+ // Configure runtime access to host controller registers
+ //
+ Status = mFvbDevice->SpiMasterProtocol->ConfigRuntime (&mFvbDevice->SpiDevice);
+ if (EFI_ERROR (Status)) {
+ goto ErrorSetMemAttr;
+ }
+
+ return Status;
+
+ErrorSetMemAttr:
+ gDS->RemoveMemorySpace (RegionBaseAddress, RuntimeMmioRegionSize);
+
+ErrorAddSpace:
+ gBS->UninstallMultipleProtocolInterfaces (&mFvbDevice->Handle,
+ &gEfiDevicePathProtocolGuid,
+ &gEfiFirmwareVolumeBlockProtocolGuid,
+ NULL);
+
+ErrorConfigureFlash:
+ FreePool (mFvbDevice);
+
+ return Status;
+}
diff --git a/Silicon/Marvell/Drivers/Spi/Variables/MvFvbDxe.h b/Silicon/Marvell/Drivers/Spi/Variables/MvFvbDxe.h
new file mode 100644
index 0000000000..31e6e444be
--- /dev/null
+++ b/Silicon/Marvell/Drivers/Spi/Variables/MvFvbDxe.h
@@ -0,0 +1,128 @@
+/** @file MvFvbDxe.h
+
+ Copyright (c) 2011 - 2014, ARM Ltd. All rights reserved.<BR>
+ Copyright (c) 2017 Marvell International Ltd.<BR>
+
+ 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 __FVB_FLASH_DXE_H__
+#define __FVB_FLASH_DXE_H__
+
+#include <Protocol/BlockIo.h>
+#include <Protocol/FirmwareVolumeBlock.h>
+#include <Protocol/Spi.h>
+#include <Protocol/SpiFlash.h>
+
+#define GET_DATA_OFFSET(BaseAddr, Lba, LbaSize) ((BaseAddr) + (UINTN)((Lba) * (LbaSize)))
+
+#define FVB_FLASH_SIGNATURE SIGNATURE_32('S', 'n', 'o', 'r')
+#define INSTANCE_FROM_FVB_THIS(a) CR(a, FVB_DEVICE, FvbProtocol, FVB_FLASH_SIGNATURE)
+
+//
+// Define two helper macro to extract the Capability field or Status field in FVB
+// bit fields.
+//
+#define EFI_FVB2_CAPABILITIES (EFI_FVB2_READ_DISABLED_CAP | \
+ EFI_FVB2_READ_ENABLED_CAP | \
+ EFI_FVB2_WRITE_DISABLED_CAP | \
+ EFI_FVB2_WRITE_ENABLED_CAP | \
+ EFI_FVB2_LOCK_CAP)
+
+#define EFI_FVB2_STATUS (EFI_FVB2_READ_STATUS | \
+ EFI_FVB2_WRITE_STATUS | \
+ EFI_FVB2_LOCK_STATUS)
+
+typedef struct {
+ VENDOR_DEVICE_PATH Vendor;
+ EFI_DEVICE_PATH_PROTOCOL End;
+} FVB_DEVICE_PATH;
+
+typedef struct {
+ SPI_DEVICE SpiDevice;
+
+ MARVELL_SPI_FLASH_PROTOCOL *SpiFlashProtocol;
+ MARVELL_SPI_MASTER_PROTOCOL *SpiMasterProtocol;
+
+ EFI_HANDLE Handle;
+
+ UINT32 Signature;
+
+ UINTN DeviceBaseAddress;
+ UINTN RegionBaseAddress;
+ UINTN Size;
+ UINTN FvbOffset;
+ UINTN FvbSize;
+ EFI_LBA StartLba;
+
+ EFI_BLOCK_IO_MEDIA Media;
+ EFI_FIRMWARE_VOLUME_BLOCK2_PROTOCOL FvbProtocol;
+
+ FVB_DEVICE_PATH DevicePath;
+} FVB_DEVICE;
+
+EFI_STATUS
+EFIAPI
+MvFvbGetAttributes(
+ IN CONST EFI_FIRMWARE_VOLUME_BLOCK2_PROTOCOL* This,
+ OUT EFI_FVB_ATTRIBUTES_2* Attributes
+);
+
+EFI_STATUS
+EFIAPI
+MvFvbSetAttributes(
+ IN CONST EFI_FIRMWARE_VOLUME_BLOCK2_PROTOCOL* This,
+ IN OUT EFI_FVB_ATTRIBUTES_2* Attributes
+);
+
+EFI_STATUS
+EFIAPI
+MvFvbGetPhysicalAddress(
+ IN CONST EFI_FIRMWARE_VOLUME_BLOCK2_PROTOCOL* This,
+ OUT EFI_PHYSICAL_ADDRESS* Address
+);
+
+EFI_STATUS
+EFIAPI
+MvFvbGetBlockSize(
+ IN CONST EFI_FIRMWARE_VOLUME_BLOCK2_PROTOCOL* This,
+ IN EFI_LBA Lba,
+ OUT UINTN* BlockSize,
+ OUT UINTN* NumberOfBlocks
+);
+
+EFI_STATUS
+EFIAPI
+MvFvbRead(
+ 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
+MvFvbWrite(
+ 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
+MvFvbEraseBlocks(
+ IN CONST EFI_FIRMWARE_VOLUME_BLOCK2_PROTOCOL* This,
+ ...
+);
+
+#endif /* __FVB_FLASH_DXE_H__ */
diff --git a/Silicon/Marvell/Drivers/Spi/Variables/MvFvbDxe.inf b/Silicon/Marvell/Drivers/Spi/Variables/MvFvbDxe.inf
new file mode 100644
index 0000000000..117fe8bdd6
--- /dev/null
+++ b/Silicon/Marvell/Drivers/Spi/Variables/MvFvbDxe.inf
@@ -0,0 +1,91 @@
+#
+# Marvell BSD License Option
+#
+# If you received this File from Marvell, you may opt to use, redistribute
+# and/or modify this File under the following licensing terms.
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are met:
+#
+# * Redistributions of source code must retain the above copyright notice,
+# this list of conditions and the following disclaimer.
+#
+# * Redistributions in binary form must reproduce the above copyright
+# notice, this list of conditions and the following disclaimer in the
+# documentation and/or other materials provided with the distribution.
+#
+# * Neither the name of Marvell nor the names of its contributors may be
+# used to endorse or promote products derived from this software without
+# specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE
+# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+#
+
+[Defines]
+ INF_VERSION = 0x0001001A
+ BASE_NAME = MvFvbDxe
+ FILE_GUID = 42903750-7e61-4aaf-8329-bf42364e2485
+ MODULE_TYPE = DXE_RUNTIME_DRIVER
+ VERSION_STRING = 0.1
+ ENTRY_POINT = MvFvbEntryPoint
+
+[Sources]
+ MvFvbDxe.c
+
+[Packages]
+ ArmPlatformPkg/ArmPlatformPkg.dec
+ EmbeddedPkg/EmbeddedPkg.dec
+ MdeModulePkg/MdeModulePkg.dec
+ MdePkg/MdePkg.dec
+ Silicon/Marvell/Marvell.dec
+
+[LibraryClasses]
+ BaseLib
+ BaseMemoryLib
+ DebugLib
+ DevicePathLib
+ DxeServicesTableLib
+ HobLib
+ IoLib
+ MemoryAllocationLib
+ UefiBootServicesTableLib
+ UefiDriverEntryPoint
+ UefiLib
+ UefiRuntimeLib
+ UefiRuntimeServicesTableLib
+
+[Guids]
+ gEfiAuthenticatedVariableGuid
+ gEfiEventVirtualAddressChangeGuid
+ gEfiSystemNvDataFvGuid
+ gEfiVariableGuid
+
+[Protocols]
+ gEfiDevicePathProtocolGuid
+ gEfiFirmwareVolumeBlockProtocolGuid
+ gMarvellSpiFlashProtocolGuid
+ gMarvellSpiMasterProtocolGuid
+
+[FixedPcd]
+ gEfiMdeModulePkgTokenSpaceGuid.PcdFlashNvStorageVariableBase
+ gEfiMdeModulePkgTokenSpaceGuid.PcdFlashNvStorageVariableSize
+ gEfiMdeModulePkgTokenSpaceGuid.PcdFlashNvStorageFtwWorkingBase
+ gEfiMdeModulePkgTokenSpaceGuid.PcdFlashNvStorageFtwWorkingSize
+ gEfiMdeModulePkgTokenSpaceGuid.PcdFlashNvStorageFtwSpareBase
+ gEfiMdeModulePkgTokenSpaceGuid.PcdFlashNvStorageFtwSpareSize
+ gMarvellTokenSpaceGuid.PcdSpiMemoryBase
+
+[Depex]
+ #
+ # MvFvbDxe must be loaded before VariableRuntimeDxe in case empty
+ # flash needs populating with default values.
+ #
+ BEFORE gVariableRuntimeDxeFileGuid