Drivers/Spi: Implement Spi flash driver

This patch add driver for managing Spi flash
It consumes MARVELL_SPI_FLASH_PROTOCOL and enables configuration
by PCD entries.

Contributed-under: TianoCore Contribution Agreement 1.0
Signed-off-by: Jan Dabros <jsd@semihalf.com>
Signed-off-by: Marcin Wojtas <mw@semihalf.com>
Reviewed-by: Leif Lindholm <leif.lindholm@linaro.org>
diff --git a/Documentation/Marvell/PortingGuide/SpiFlash.txt b/Documentation/Marvell/PortingGuide/SpiFlash.txt
new file mode 100644
index 0000000..226db40
--- /dev/null
+++ b/Documentation/Marvell/PortingGuide/SpiFlash.txt
@@ -0,0 +1,23 @@
+SpiFlash driver configuration

+-----------------------------

+Folowing PCDs for spi flash driver configuration must be set properly:

+

+ gMarvellTokenSpaceGuid.PcdSpiFlashAddressCycles

+

+Size of SPI flash address in bytes (3 or 4)

+

+ gMarvellTokenSpaceGuid.PcdSpiFlashEraseSize

+

+Size of minimal erase block in bytes

+

+ gMarvellTokenSpaceGuid.PcdSpiFlashPageSize

+

+Size of SPI flash page

+

+ gMarvellTokenSpaceGuid.PcdSpiFlashId

+

+Id of SPI flash

+

+ gMarvellTokenSpaceGuid.PcdSpiFlashPollCmd

+

+Spi flash polling flag

diff --git a/Drivers/Spi/Devices/MvSpiFlash.c b/Drivers/Spi/Devices/MvSpiFlash.c
new file mode 100755
index 0000000..9a04493
--- /dev/null
+++ b/Drivers/Spi/Devices/MvSpiFlash.c
@@ -0,0 +1,531 @@
+/*******************************************************************************

+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"

+

+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 poll_bit = STATUS_REG_POLL_WIP;

+  UINT8 check_status = 0x0;

+

+  CmdStatus = (UINT8)PcdGet32 (PcdSpiFlashPollCmd);

+  if (CmdStatus == CMD_FLAG_STATUS) {

+    poll_bit = STATUS_REG_POLL_PEC;

+    check_status = poll_bit;

+  }

+

+  // 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 & poll_bit) == check_status)

+      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;

+

+  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 AddrSize, EraseAddr;

+  UINTN EraseSize;

+  UINT8 Cmd[5];

+

+  AddrSize  = PcdGet32 (PcdSpiFlashAddressCycles);

+  EraseSize = PcdGet64 (PcdSpiFlashEraseSize);

+

+  // 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;

+  }

+

+  Cmd[0] = CMD_ERASE_64K;

+  while (Length) {

+    EraseAddr = Offset;

+

+    SpiFlashBank (Slave, EraseAddr);

+

+    SpiFlashFormatAddress (EraseAddr, AddrSize, Cmd);

+

+    // Programm proper erase address

+    Status = MvSpiFlashWriteCommon (Slave, Cmd, 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 AddrSize, ReadAddr, ReadLength, RemainLength;

+  UINTN BankSel = 0;

+

+  AddrSize = PcdGet32 (PcdSpiFlashAddressCycles);

+

+  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, AddrSize, Cmd);

+    // Program proper read address and read data

+    Status = MvSpiFlashReadCmd (Slave, Cmd, 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], AddrSize;

+

+  AddrSize = PcdGet32 (PcdSpiFlashAddressCycles);

+  PageSize = PcdGet32 (PcdSpiFlashPageSize);

+

+  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, AddrSize, Cmd);

+

+    // Program proper write address and write data

+    Status = MvSpiFlashWriteCommon (Slave, Cmd, 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 EraseSize, ToUpdate, Scale = 1;

+  UINT8 *TmpBuf, *End;

+

+  EraseSize = PcdGet64 (PcdSpiFlashEraseSize);

+

+  End = Buf + ByteCount;

+

+  TmpBuf = (UINT8 *)AllocateZeroPool (EraseSize);

+  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), EraseSize);

+    Print (L"   \rUpdating, %d%%", 100 - (End - Buf) / Scale);

+    Status = MvSpiFlashUpdateBlock (Slave, Offset, ToUpdate, Buf, TmpBuf, EraseSize);

+

+    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     UINT32     DataByteCount,

+  IN OUT UINT8      *Buffer

+  )

+{

+  EFI_STATUS Status;

+  UINT8 *DataOut;

+

+  DataOut = (UINT8 *) AllocateZeroPool (DataByteCount);

+  if (DataOut == NULL) {

+    DEBUG((DEBUG_ERROR, "SpiFlash: Cannot allocate memory\n"));

+    return EFI_OUT_OF_RESOURCES;

+  }

+  Status = SpiMasterProtocol->Transfer (SpiMasterProtocol, SpiDev,

+    DataByteCount, Buffer, DataOut, SPI_TRANSFER_BEGIN | SPI_TRANSFER_END);

+  if (EFI_ERROR(Status)) {

+    FreePool (DataOut);

+    DEBUG((DEBUG_ERROR, "SpiFlash: Spi transfer error\n"));

+    return Status;

+  }

+

+  // Bytes 1,2 and 3 contain SPI flash ID

+  Buffer[0] = DataOut[1];

+  Buffer[1] = DataOut[2];

+  Buffer[2] = DataOut[3];

+

+  FreePool (DataOut);

+

+  return EFI_SUCCESS;

+}

+

+EFI_STATUS

+EFIAPI

+MvSpiFlashInit (

+  IN MARVELL_SPI_FLASH_PROTOCOL *This,

+  IN SPI_DEVICE *Slave

+  )

+{

+  EFI_STATUS Status;

+  UINT8 Cmd, StatusRegister;

+  UINT32 AddrSize;

+

+  AddrSize = PcdGet32 (PcdSpiFlashAddressCycles);

+

+  if (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;

+}

+

+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 = AllocateZeroPool (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)) {

+    FreePool (mSpiFlashInstance);

+    DEBUG((DEBUG_ERROR, "SpiFlash: Cannot install SPI flash protocol\n"));

+    return EFI_DEVICE_ERROR;

+  }

+

+  return EFI_SUCCESS;

+}

diff --git a/Drivers/Spi/Devices/MvSpiFlash.h b/Drivers/Spi/Devices/MvSpiFlash.h
new file mode 100755
index 0000000..3889643
--- /dev/null
+++ b/Drivers/Spi/Devices/MvSpiFlash.h
@@ -0,0 +1,132 @@
+/*******************************************************************************

+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 <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_ERASE_64K                   0xd8

+#define CMD_4B_ADDR_ENABLE              0xb7

+

+#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/Drivers/Spi/Devices/MvSpiFlash.inf b/Drivers/Spi/Devices/MvSpiFlash.inf
new file mode 100644
index 0000000..85b1728
--- /dev/null
+++ b/Drivers/Spi/Devices/MvSpiFlash.inf
@@ -0,0 +1,67 @@
+#

+# 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_DRIVER

+  VERSION_STRING                 = 1.0

+  ENTRY_POINT                    = MvSpiFlashEntryPoint

+

+[Sources]

+  MvSpiFlash.c

+  MvSpiFlash.h

+

+[Packages]

+  MdePkg/MdePkg.dec

+  OpenPlatformPkg/Platforms/Marvell/Marvell.dec

+

+[LibraryClasses]

+  UefiBootServicesTableLib

+  UefiDriverEntryPoint

+  TimerLib

+  UefiLib

+  DebugLib

+  MemoryAllocationLib

+

+[FixedPcd]

+  gMarvellTokenSpaceGuid.PcdSpiFlashAddressCycles

+  gMarvellTokenSpaceGuid.PcdSpiFlashEraseSize

+  gMarvellTokenSpaceGuid.PcdSpiFlashPageSize

+  gMarvellTokenSpaceGuid.PcdSpiFlashPollCmd

+

+[Protocols]

+  gMarvellSpiMasterProtocolGuid

+  gMarvellSpiFlashProtocolGuid

+

+[Depex]

+  TRUE

diff --git a/Platforms/Marvell/Marvell.dec b/Platforms/Marvell/Marvell.dec
index 7dd3e07..a2d1956 100644
--- a/Platforms/Marvell/Marvell.dec
+++ b/Platforms/Marvell/Marvell.dec
@@ -121,6 +121,12 @@
   gMarvellTokenSpaceGuid.PcdSpiMaxFrequency|0|UINT32|0x30000052

   gMarvellTokenSpaceGuid.PcdSpiClockFrequency|0|UINT32|0x30000053

 

+  gMarvellTokenSpaceGuid.PcdSpiFlashPollCmd|0|UINT32|0x3000052

+  gMarvellTokenSpaceGuid.PcdSpiFlashAddressCycles|0|UINT32|0x3000053

+  gMarvellTokenSpaceGuid.PcdSpiFlashEraseSize|0|UINT64|0x3000054

+  gMarvellTokenSpaceGuid.PcdSpiFlashPageSize|0|UINT32|0x3000055

+  gMarvellTokenSpaceGuid.PcdSpiFlashId|0|UINT32|0x3000056

+

 [Protocols]

   gMarvellEepromProtocolGuid               = { 0xcd728a1f, 0x45b5, 0x4feb, { 0x98, 0xc8, 0x31, 0x3d, 0xa8, 0x11, 0x74, 0x62 }}

   gMarvellSpiMasterProtocolGuid            = { 0x23de66a3, 0xf666, 0x4b3e, { 0xaa, 0xa2, 0x68, 0x9b, 0x18, 0xae, 0x2e, 0x19 }}