summaryrefslogtreecommitdiff
path: root/Platform/Marvell/Drivers/Spi
diff options
context:
space:
mode:
Diffstat (limited to 'Platform/Marvell/Drivers/Spi')
-rwxr-xr-xPlatform/Marvell/Drivers/Spi/Devices/MvSpiFlash.c531
-rwxr-xr-xPlatform/Marvell/Drivers/Spi/Devices/MvSpiFlash.h132
-rw-r--r--Platform/Marvell/Drivers/Spi/Devices/MvSpiFlash.inf67
-rwxr-xr-xPlatform/Marvell/Drivers/Spi/MvSpiDxe.c379
-rw-r--r--Platform/Marvell/Drivers/Spi/MvSpiDxe.h145
-rw-r--r--Platform/Marvell/Drivers/Spi/MvSpiDxe.inf66
6 files changed, 1320 insertions, 0 deletions
diff --git a/Platform/Marvell/Drivers/Spi/Devices/MvSpiFlash.c b/Platform/Marvell/Drivers/Spi/Devices/MvSpiFlash.c
new file mode 100755
index 0000000000..9a04493895
--- /dev/null
+++ b/Platform/Marvell/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/Platform/Marvell/Drivers/Spi/Devices/MvSpiFlash.h b/Platform/Marvell/Drivers/Spi/Devices/MvSpiFlash.h
new file mode 100755
index 0000000000..3889643aeb
--- /dev/null
+++ b/Platform/Marvell/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/Platform/Marvell/Drivers/Spi/Devices/MvSpiFlash.inf b/Platform/Marvell/Drivers/Spi/Devices/MvSpiFlash.inf
new file mode 100644
index 0000000000..d035d47137
--- /dev/null
+++ b/Platform/Marvell/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
+ Platform/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/Platform/Marvell/Drivers/Spi/MvSpiDxe.c b/Platform/Marvell/Drivers/Spi/MvSpiDxe.c
new file mode 100755
index 0000000000..aab20fc9ac
--- /dev/null
+++ b/Platform/Marvell/Drivers/Spi/MvSpiDxe.c
@@ -0,0 +1,379 @@
+/*******************************************************************************
+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 UINT32 CpuClock,
+ IN UINT32 MaxFreq
+ )
+{
+ UINT32 Spr, BestSpr, Sppr, BestSppr, ClockDivider, Match, Reg, MinBaudDiff;
+ UINTN SpiRegBase = PcdGet32 (PcdSpiRegBase);
+
+ 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 (
+ UINT8 CsId
+ )
+{
+ UINT32 Reg, SpiRegBase = PcdGet32 (PcdSpiRegBase);
+
+ Reg = MmioRead32 (SpiRegBase + SPI_CTRL_REG);
+ Reg &= ~SPI_CS_NUM_MASK;
+ Reg |= (CsId << SPI_CS_NUM_OFFSET);
+ MmioWrite32 (SpiRegBase + SPI_CTRL_REG, Reg);
+}
+
+STATIC
+VOID
+SpiActivateCs (
+ UINT8 IN CsId
+ )
+{
+ UINT32 Reg, SpiRegBase = PcdGet32 (PcdSpiRegBase);
+
+ SpiSetCs(CsId);
+ Reg = MmioRead32 (SpiRegBase + SPI_CTRL_REG);
+ Reg |= SPI_CS_EN_MASK;
+ MmioWrite32(SpiRegBase + SPI_CTRL_REG, Reg);
+}
+
+STATIC
+VOID
+SpiDeactivateCs (
+ VOID
+ )
+{
+ UINT32 Reg, SpiRegBase = PcdGet32 (PcdSpiRegBase);
+
+ 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, SpiRegBase, CoreClock, SpiMaxFreq;
+
+ SpiMaster = SPI_MASTER_FROM_SPI_MASTER_PROTOCOL (This);
+
+ // Initialize values from PCDs
+ SpiRegBase = PcdGet32 (PcdSpiRegBase);
+ CoreClock = PcdGet32 (PcdSpiClockFrequency);
+ SpiMaxFreq = PcdGet32 (PcdSpiMaxFrequency);
+
+ EfiAcquireLock (&SpiMaster->Lock);
+
+ Reg = MmioRead32 (SpiRegBase + SPI_CONF_REG);
+ Reg |= SPI_BYTE_LENGTH;
+ MmioWrite32 (SpiRegBase + SPI_CONF_REG, Reg);
+
+ SpiSetCs(Slave->Cs);
+
+ SpiSetBaudRate (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, SpiRegBase;
+ UINT8 *DataOutPtr = (UINT8 *)DataOut;
+ UINT8 *DataInPtr = (UINT8 *)DataIn;
+ UINT8 DataToSend = 0;
+
+ SpiMaster = SPI_MASTER_FROM_SPI_MASTER_PROTOCOL (This);
+
+ SpiRegBase = PcdGet32 (PcdSpiRegBase);
+
+ Length = 8 * DataByteCount;
+
+ EfiAcquireLock (&SpiMaster->Lock);
+
+ if (Flag & SPI_TRANSFER_BEGIN) {
+ SpiActivateCs (Slave->Cs);
+ }
+
+ // 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)) {
+ *DataInPtr = MmioRead32 (SpiRegBase + SPI_DATA_IN_REG);
+
+ if (DataInPtr != NULL) {
+ DataInPtr++;
+ }
+ if (DataOutPtr != NULL) {
+ DataOutPtr++;
+ }
+ Length -= 8;
+ break;
+ }
+ }
+
+ if (Iterator >= SPI_TIMEOUT) {
+ DEBUG ((DEBUG_ERROR, "Timeout\n"));
+ }
+ }
+
+ if (Flag & SPI_TRANSFER_END) {
+ SpiDeactivateCs ();
+ }
+
+ 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 UINTN Cs,
+ IN SPI_MODE Mode
+ )
+{
+ SPI_DEVICE *Slave;
+
+ Slave = AllocateZeroPool (sizeof(SPI_DEVICE));
+ if (Slave == NULL) {
+ DEBUG((DEBUG_ERROR, "Cannot allocate memory\n"));
+ return NULL;
+ }
+
+ Slave->Cs = Cs;
+ Slave->Mode = Mode;
+
+ SpiSetupTransfer (This, Slave);
+
+ return Slave;
+}
+
+EFI_STATUS
+EFIAPI
+MvSpiFreeSlave (
+ IN SPI_DEVICE *Slave
+ )
+{
+ FreePool (Slave);
+
+ 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;
+
+ return EFI_SUCCESS;
+}
+
+EFI_STATUS
+EFIAPI
+SpiMasterEntryPoint (
+ IN EFI_HANDLE ImageHandle,
+ IN EFI_SYSTEM_TABLE *SystemTable
+ )
+{
+ EFI_STATUS Status;
+
+ mSpiMasterInstance = AllocateZeroPool (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/Platform/Marvell/Drivers/Spi/MvSpiDxe.h b/Platform/Marvell/Drivers/Spi/MvSpiDxe.h
new file mode 100644
index 0000000000..1401f6207b
--- /dev/null
+++ b/Platform/Marvell/Drivers/Spi/MvSpiDxe.h
@@ -0,0 +1,145 @@
+/*******************************************************************************
+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/MemoryAllocationLib.h>
+#include <Uefi/UefiBaseType.h>
+#include <Library/BaseMemoryLib.h>
+#include <Library/UefiBootServicesTableLib.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 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/Platform/Marvell/Drivers/Spi/MvSpiDxe.inf b/Platform/Marvell/Drivers/Spi/MvSpiDxe.inf
new file mode 100644
index 0000000000..d38d331f7c
--- /dev/null
+++ b/Platform/Marvell/Drivers/Spi/MvSpiDxe.inf
@@ -0,0 +1,66 @@
+#
+# 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_DRIVER
+ VERSION_STRING = 1.0
+ ENTRY_POINT = SpiMasterEntryPoint
+
+[Sources]
+ MvSpiDxe.c
+ MvSpiDxe.h
+
+[Packages]
+ MdePkg/MdePkg.dec
+ Platform/Marvell/Marvell.dec
+
+[LibraryClasses]
+ UefiBootServicesTableLib
+ UefiDriverEntryPoint
+ TimerLib
+ UefiLib
+ DebugLib
+ MemoryAllocationLib
+ IoLib
+
+[FixedPcd]
+ gMarvellTokenSpaceGuid.PcdSpiRegBase
+ gMarvellTokenSpaceGuid.PcdSpiClockFrequency
+ gMarvellTokenSpaceGuid.PcdSpiMaxFrequency
+
+[Protocols]
+ gMarvellSpiMasterProtocolGuid
+
+[Depex]
+ TRUE