[edk2-devel] [PATCH v2 2/4] StarFive/JH7110Pkg: Add SPI protocol and driver support

John Chew yuinyee.chew at starfivetech.com
Mon Oct 23 07:18:49 UTC 2023


This patch include QSPI driver and Flash driver protocol.
QSPI driver:
	1. Used indirect read/write
	2. Master mode only
	3. Require to setup qspi driver after located protocol
	4. Require to free device if no longer needed
	5. Support command read/write & data read/write
Flash driver:
	1. Require QSPI protocol as prerequisite
	2. Support for flash read/write/update/erase
	3. Require to init flash driver after allocated protocol

Cc: Sunil V L <sunilvl at ventanamicro.com>
Cc: Leif Lindholm <quic_llindhol at quicinc.com>
Cc: Michael D Kinney <michael.d.kinney at intel.com>
Cc: Cc: Li Yong <yong.li at intel.com>
Signed-off-by: John Chew <yuinyee.chew at starfivetech.com>
---
 Silicon/StarFive/JH7110Pkg/Driver/SpiFvbServicesDxe/SpiDxe/SpiDxe.c             | 893 ++++++++++++++++++++
 Silicon/StarFive/JH7110Pkg/Driver/SpiFvbServicesDxe/SpiDxe/SpiDxe.h             | 188 +++++
 Silicon/StarFive/JH7110Pkg/Driver/SpiFvbServicesDxe/SpiDxe/SpiDxe.inf           |  52 ++
 Silicon/StarFive/JH7110Pkg/Driver/SpiFvbServicesDxe/SpiFlashDxe/SpiFlashDxe.c   | 571 +++++++++++++
 Silicon/StarFive/JH7110Pkg/Driver/SpiFvbServicesDxe/SpiFlashDxe/SpiFlashDxe.h   |  35 +
 Silicon/StarFive/JH7110Pkg/Driver/SpiFvbServicesDxe/SpiFlashDxe/SpiFlashDxe.inf |  44 +
 Silicon/StarFive/JH7110Pkg/Include/Protocol/Spi.h                               | 163 ++++
 Silicon/StarFive/JH7110Pkg/Include/Protocol/SpiFlash.h                          |  88 ++
 8 files changed, 2034 insertions(+)

diff --git a/Silicon/StarFive/JH7110Pkg/Driver/SpiFvbServicesDxe/SpiDxe/SpiDxe.c b/Silicon/StarFive/JH7110Pkg/Driver/SpiFvbServicesDxe/SpiDxe/SpiDxe.c
new file mode 100755
index 000000000000..c345556f8abf
--- /dev/null
+++ b/Silicon/StarFive/JH7110Pkg/Driver/SpiFvbServicesDxe/SpiDxe/SpiDxe.c
@@ -0,0 +1,893 @@
+/** @file

+ *

+ *  Copyright (c) 2023, StarFive Technology Co., Ltd. All rights reserved.<BR>

+ *

+ *  SPDX-License-Identifier: BSD-2-Clause-Patent

+ *

+ **/

+

+#include "SpiDxe.h"

+

+SPI_MASTER  *mSpiMasterInstance;

+

+STATIC

+VOID

+SpiControllerEnable (

+  IN UINT32  RegBase

+  )

+{

+  UINT32  Reg;

+

+  Reg  = MmioRead32 (RegBase + SPI_REG_CONFIG);

+  Reg |= SPI_REG_CONFIG_ENABLE;

+  MmioWrite32 (RegBase + SPI_REG_CONFIG, Reg);

+}

+

+STATIC

+VOID

+SpiControllerDisable (

+  IN UINT32  RegBase

+  )

+{

+  UINT32  Reg;

+

+  Reg  = MmioRead32 (RegBase + SPI_REG_CONFIG);

+  Reg &= ~SPI_REG_CONFIG_ENABLE;

+  MmioWrite32 (RegBase + SPI_REG_CONFIG, Reg);

+}

+

+STATIC

+VOID

+SpiWriteSpeed (

+  IN SPI_DEVICE_PARAMS  *Slave,

+  IN UINT32             SclkHz,

+  IN SPI_TIMING_PARAMS  *Timing

+  )

+{

+  UINT32  Reg, Div, RefClkNs, SclkNs;

+  UINT32  Tshsl, Tchsh, Tslch, Tsd2d;

+

+  SpiControllerDisable (Slave->RegBase);

+

+  /* Configure baudrate */

+  Reg  = MmioRead32 (Slave->RegBase + SPI_REG_CONFIG);

+  Reg &= ~(SPI_REG_CONFIG_BAUD_MASK << SPI_REG_CONFIG_BAUD_LSB);

+

+  Div = DIV_ROUND_UP (Timing->RefClkHz, SclkHz * 2) - 1;

+

+  if (Div > SPI_REG_CONFIG_BAUD_MASK) {

+    Div = SPI_REG_CONFIG_BAUD_MASK;

+  }

+

+  DEBUG (

+         (DEBUG_INFO, "%a(): RefClk %dHz sclk %dHz Div 0x%x, actual %dHz\n", __func__,

+          Timing->RefClkHz, SclkHz, Div, Timing->RefClkHz / (2 * (Div + 1)))

+         );

+

+  Reg |= (Div << SPI_REG_CONFIG_BAUD_LSB);

+  MmioWrite32 (Slave->RegBase + SPI_REG_CONFIG, Reg);

+

+  /* Configure delay timing */

+  RefClkNs = DIV_ROUND_UP (1000000000, Timing->RefClkHz);

+  SclkNs = DIV_ROUND_UP (1000000000, SclkHz);

+

+  if (Timing->TshslNs >= SclkNs + RefClkNs) {

+    Timing->TshslNs -= SclkNs + RefClkNs;

+  }

+

+  if (Timing->TchshNs >= SclkNs + 3 * RefClkNs) {

+    Timing->TchshNs -= SclkNs + 3 * RefClkNs;

+  }

+

+  Tshsl = DIV_ROUND_UP (Timing->TshslNs, RefClkNs);

+  Tchsh = DIV_ROUND_UP (Timing->TchshNs, RefClkNs);

+  Tslch = DIV_ROUND_UP (Timing->TslchNs, RefClkNs);

+  Tsd2d = DIV_ROUND_UP (Timing->Tsd2dNs, RefClkNs);

+

+  Reg = ((Tshsl & SPI_REG_DELAY_TSHSL_MASK)

+         << SPI_REG_DELAY_TSHSL_LSB);

+  Reg |= ((Tchsh & SPI_REG_DELAY_TCHSH_MASK)

+          << SPI_REG_DELAY_TCHSH_LSB);

+  Reg |= ((Tslch & SPI_REG_DELAY_TSLCH_MASK)

+          << SPI_REG_DELAY_TSLCH_LSB);

+  Reg |= ((Tsd2d & SPI_REG_DELAY_TSD2D_MASK)

+          << SPI_REG_DELAY_TSD2D_LSB);

+  MmioWrite32 (Slave->RegBase + SPI_REG_DELAY, Reg);

+

+  SpiControllerEnable (Slave->RegBase);

+}

+

+STATIC

+EFI_STATUS

+SpiWaitIdle (

+  IN UINT32  RegBase

+  )

+{

+  BOOLEAN IsIdle;

+  UINT32  Count     = 0;

+  UINT32  TimeoutMs = 5000000;

+

+  do {

+    IsIdle = (BOOLEAN)((MmioRead32(RegBase + SPI_REG_CONFIG) >>

+                        SPI_REG_CONFIG_IDLE_LSB) & 0x1);

+    Count = (IsIdle) ? (Count+1) : 0;

+

+    /*

+     * Make sure the QSPI controller is in really idle

+     * for n period of time before proceed

+     */

+    if (Count >= SPI_POLL_IDLE_RETRY) {

+      return EFI_SUCCESS;

+    }

+

+    gBS->Stall (1);

+  } while (TimeoutMs);

+

+  return EFI_TIMEOUT;

+}

+

+STATIC

+EFI_STATUS

+SpiExecFlashCmd (

+  IN UINT32  RegBase,

+  IN UINT32  Reg

+  )

+{

+  EFI_STATUS  Status;

+  UINT32      Retry = SPI_REG_RETRY;

+

+  /* Write the CMDCTRL without start execution */

+  MmioWrite32 (RegBase + SPI_REG_CMDCTRL, Reg);

+  /* Start execute */

+  Reg |= SPI_REG_CMDCTRL_EXECUTE;

+  MmioWrite32 (RegBase + SPI_REG_CMDCTRL, Reg);

+

+  while (Retry--) {

+    Reg = MmioRead32 (RegBase + SPI_REG_CMDCTRL);

+    if ((Reg & SPI_REG_CMDCTRL_INPROGRESS) == 0) {

+      break;

+    }

+    gBS->Stall (1);

+  }

+

+  if (!Retry) {

+    DEBUG ((DEBUG_ERROR, "%a(): flash command execution Timeout\n", __func__));

+    return EFI_TIMEOUT;

+  }

+

+  /* Polling QSPI idle status */

+  Status = SpiWaitIdle (RegBase);

+  if (EFI_ERROR (Status)) {

+    return EFI_TIMEOUT;

+  }

+

+  return EFI_SUCCESS;

+}

+

+/* For command RDID, RDSR. */

+EFI_STATUS

+SpiCommandRead (

+  IN SPI_MASTER_PROTOCOL *This,

+  IN SPI_DEVICE_PARAMS  *Slave,

+  IN OUT SPI_OP_PARAMS   *Cmds

+  )

+{

+  UINT32      Reg;

+  UINT32      ReadLen;

+  EFI_STATUS  Status;

+  SPI_MASTER *SpiMaster;

+  UINT32      RxLen  = Cmds->Data.NBytes;

+  VOID        *RxBuf = Cmds->Data.Buf.In;

+

+  SpiMaster = SPI_MASTER_FROM_SPI_MASTER_PROTOCOL (This);

+  if (!EfiAtRuntime ()) {

+    EfiAcquireLock (&SpiMaster->Lock);

+  }

+

+  if ((RxLen > SPI_STIG_DATA_LEN_MAX) || !RxBuf) {

+    DEBUG ((DEBUG_ERROR, "%a(): Invalid input arguments RxLen %d\n", __func__, RxLen));

+    Status = EFI_INVALID_PARAMETER;

+    goto Fail;

+  }

+

+  Reg = Cmds->Cmd.OpCode << SPI_REG_CMDCTRL_OPCODE_LSB;

+  Reg |= (0x1 << SPI_REG_CMDCTRL_RD_EN_LSB);

+

+  /* 0 means 1 byte */

+  Reg |= (((RxLen - 1) & SPI_REG_CMDCTRL_RD_BYTES_MASK)

+          << SPI_REG_CMDCTRL_RD_BYTES_LSB);

+  Status = SpiExecFlashCmd (Slave->RegBase, Reg);

+  if (EFI_ERROR (Status)) {

+    goto Fail;

+  }

+

+  Reg = MmioRead32 (Slave->RegBase + SPI_REG_CMDREADDATALOWER);

+

+  /* Put the read value into rx_buf */

+  ReadLen = (RxLen > 4) ? 4 : RxLen;

+  CopyMem (RxBuf, &Reg, ReadLen);

+  RxBuf += ReadLen;

+

+  if (RxLen > 4) {

+    Reg = MmioRead32 (Slave->RegBase + SPI_REG_CMDREADDATAUPPER);

+

+    ReadLen = RxLen - ReadLen;

+    CopyMem (RxBuf, &Reg, ReadLen);

+  }

+

+  if (!EfiAtRuntime ()) {

+    EfiReleaseLock (&SpiMaster->Lock);

+  }

+  return EFI_SUCCESS;

+

+Fail:

+  if (!EfiAtRuntime ()) {

+    EfiReleaseLock (&SpiMaster->Lock);

+  }

+  return Status;

+}

+

+STATIC

+EFI_STATUS

+SpiGetReadSramLevel (

+  IN UINT32   RegBase,

+  OUT UINT16  *SramLvl

+  )

+{

+  UINT32  Reg = MmioRead32 (RegBase + SPI_REG_SDRAMLEVEL);

+  Reg >>= SPI_REG_SDRAMLEVEL_RD_LSB;

+  *SramLvl = (UINT16)(Reg & SPI_REG_SDRAMLEVEL_RD_MASK);

+

+  return EFI_SUCCESS;

+}

+

+STATIC

+EFI_STATUS

+SpiWaitForData (

+  IN UINT32  RegBase,

+  UINT16    *SramLvl

+  )

+{

+  UINT32  Timeout = 10000;

+

+  while (Timeout--) {

+    SpiGetReadSramLevel (RegBase, SramLvl);

+    if (SramLvl != 0) {

+      return EFI_SUCCESS;

+    }

+    gBS->Stall (1);

+  }

+

+  return EFI_TIMEOUT;

+}

+

+STATIC

+EFI_STATUS

+SpiWaitForBitLe32 (

+  IN INT32          Reg,

+  IN CONST UINT32   Mask,

+  IN CONST BOOLEAN  Set,

+  IN CONST UINT32   TimeoutMs

+  )

+{

+  UINT32  Val;

+  UINTN   Start = TimeoutMs*1000;

+

+  while(1) {

+    Val = MmioRead32 (Reg);

+

+    if (!Set) {

+      Val = ~Val;

+    }

+

+    if ((Val & Mask) == Mask) {

+      return EFI_SUCCESS;

+    }

+

+    if (Start == 0) {

+      break;

+    } else {

+      Start--;

+    }

+

+    gBS->Stall (1);

+  }

+

+  DEBUG ((DEBUG_ERROR, "Timeout (Reg=%lx Mask=%x wait_set=%d)\n", Reg, Mask, Set));

+

+  return EFI_TIMEOUT;

+}

+

+STATIC

+VOID

+SpiReadByte (

+  IN VOID  *Addr,

+  IN VOID  *Data,

+  IN UINT16 ByteLen

+  )

+{

+  UINT8  *AddrPtr;

+  UINT8  *DataPtr;

+

+  AddrPtr  = (UINT8 *)Addr;

+  DataPtr = (UINT8 *)Data;

+

+  while (ByteLen) {

+    *DataPtr = *AddrPtr;

+    DataPtr++;

+    ByteLen--;

+  }

+}

+

+STATIC

+VOID

+SpiReadLong (

+  VOID    *Addr,

+  VOID    *Data,

+  UINT16  LongLen

+  )

+{

+  UINT32  *AddrPtr;

+  UINT32  *DataPtr;

+

+  AddrPtr = (UINT32 *)Addr;

+  DataPtr = (UINT32 *)Data;

+

+  while (LongLen) {

+    *DataPtr = *AddrPtr;

+    DataPtr++;

+    LongLen--;

+  }

+}

+

+EFI_STATUS

+SpiDataRead (

+  IN SPI_MASTER_PROTOCOL *This,

+  IN SPI_DEVICE_PARAMS  *Slave,

+  IN OUT SPI_OP_PARAMS  *Cmds

+  )

+{

+  SPI_MASTER  *SpiMaster;

+  UINT8       *RxBuf      = Cmds->Data.Buf.In;

+  UINT32      Remaining   = Cmds->Data.NBytes;

+  UINT16      BytesToRead = 0;

+  EFI_STATUS  Status;

+  UINT32      Reg;

+

+  SpiMaster = SPI_MASTER_FROM_SPI_MASTER_PROTOCOL (This);

+  if (!EfiAtRuntime ()) {

+    EfiAcquireLock (&SpiMaster->Lock);

+  }

+

+  if (!Cmds->Addr.NBytes) {

+    Status = EFI_ABORTED;

+    goto Fail;

+  }

+

+  /* Setup the indirect trigger start address */

+  MmioWrite32 (Slave->RegBase + SPI_REG_INDIRECTRDSTARTADDR, Cmds->Addr.Val);

+

+  /* Register command */

+  Reg  = Cmds->Cmd.OpCode << SPI_REG_RD_INSTR_OPCODE_LSB;

+  MmioWrite32 (Slave->RegBase + SPI_REG_RD_INSTR, Reg);

+

+  /* Set device size */

+  Reg  = MmioRead32 (Slave->RegBase + SPI_REG_SIZE);

+  Reg &= ~SPI_REG_SIZE_ADDRESS_MASK;

+  Reg |= (Cmds->Addr.NBytes - 1);

+  MmioWrite32 (Slave->RegBase + SPI_REG_SIZE, Reg);

+

+  /* Setup indirect read bytes */

+  MmioWrite32 (Slave->RegBase + SPI_REG_INDIRECTRDBYTES, Remaining);

+

+  /* Start the indirect read transfer */

+  MmioWrite32 (Slave->RegBase + SPI_REG_INDIRECTRD, SPI_REG_INDIRECTRD_START);

+

+  while (Remaining > 0) {

+    Status = SpiWaitForData (Slave->RegBase, &BytesToRead);

+    if (EFI_ERROR(Status)) {

+      DEBUG ((DEBUG_ERROR, "%a(): Indirect write timed out\n", __func__));

+      goto Fail;

+    }

+

+    while (BytesToRead != 0) {

+      BytesToRead *= Slave->FifoWidth;

+      if (BytesToRead > Remaining) {

+        BytesToRead = Remaining;

+      }

+

+      if (((UINTN)RxBuf % 4) || (BytesToRead % 4)) {

+        SpiReadByte (Slave->AhbBase, RxBuf, BytesToRead);

+      } else {

+        SpiReadLong (Slave->AhbBase, RxBuf, BytesToRead >> 2);

+      }

+

+      RxBuf        += BytesToRead;

+      Remaining    -= BytesToRead;

+      SpiGetReadSramLevel (Slave->RegBase, &BytesToRead);

+    }

+  }

+

+  /* Check indirect done status */

+  Status = SpiWaitForBitLe32 (

+                              Slave->RegBase + SPI_REG_INDIRECTRD,

+                              SPI_REG_INDIRECTRD_DONE,

+                              1,

+                              10

+                             );

+  if (EFI_ERROR (Status)) {

+    DEBUG ((DEBUG_ERROR, "Indirect read completion error\n"));

+    goto Fail;

+  }

+

+  /* Clear indirect completion status */

+  MmioWrite32 (Slave->RegBase + SPI_REG_INDIRECTRD, SPI_REG_INDIRECTRD_DONE);

+

+  if (!EfiAtRuntime ()) {

+    EfiReleaseLock (&SpiMaster->Lock);

+  }

+  return EFI_SUCCESS;

+

+Fail:

+  MmioWrite32 (Slave->RegBase + SPI_REG_INDIRECTRD, SPI_REG_INDIRECTRD_CANCEL);

+  if (!EfiAtRuntime ()) {

+    EfiReleaseLock (&SpiMaster->Lock);

+  }

+  return EFI_ABORTED;

+}

+

+/* For commands: WRSR, WREN, WRDI, CHIP_ERASE, BE, etc. */

+EFI_STATUS

+SpiCommandWrite (

+  IN SPI_MASTER_PROTOCOL *This,

+  IN SPI_DEVICE_PARAMS  *Slave,

+  IN OUT SPI_OP_PARAMS  *Cmds

+  )

+{

+  UINT32      Reg;

+  UINT32      WriteData;

+  UINT32      WriteLen;

+  SPI_MASTER  *SpiMaster;

+  UINT32      TxLen   = Cmds->Data.NBytes;

+  CONST VOID  *TxBuf  = Cmds->Data.Buf.Out;

+  UINT32      Addr;

+  EFI_STATUS  Status;

+

+  SpiMaster = SPI_MASTER_FROM_SPI_MASTER_PROTOCOL (This);

+  if (!EfiAtRuntime ()) {

+    EfiAcquireLock (&SpiMaster->Lock);

+  }

+

+  /* Reorder address to SPI bus order if only transferring address */

+  if (!TxLen) {

+    Addr = SwapBytes32 (Cmds->Addr.Val);

+    if (Cmds->Addr.NBytes == 3) {

+      Addr >>= 8;

+    }

+

+    TxBuf = &Addr;

+    TxLen = Cmds->Addr.NBytes;

+  }

+

+  if (TxLen > SPI_STIG_DATA_LEN_MAX) {

+    DEBUG ((DEBUG_ERROR, "QSPI: Invalid input arguments TxLen %d\n", TxLen));

+    Status = EFI_INVALID_PARAMETER;

+    goto Fail;

+  }

+

+  Reg = Cmds->Cmd.OpCode << SPI_REG_CMDCTRL_OPCODE_LSB;

+

+  if (TxLen) {

+    Reg |= (0x1 << SPI_REG_CMDCTRL_WR_EN_LSB);

+    Reg |= ((TxLen - 1) & SPI_REG_CMDCTRL_WR_BYTES_MASK)

+           << SPI_REG_CMDCTRL_WR_BYTES_LSB;

+

+    WriteLen = TxLen > 4 ? 4 : TxLen;

+    CopyMem (&WriteData, TxBuf, WriteLen);

+    MmioWrite32 (Slave->RegBase + SPI_REG_CMDWRITEDATALOWER, WriteData);

+

+    if (TxLen > 4) {

+      TxBuf   += WriteLen;

+      WriteLen = TxLen - WriteLen;

+      CopyMem (&WriteData, TxBuf, WriteLen);

+      MmioWrite32 (Slave->RegBase + SPI_REG_CMDWRITEDATAUPPER, WriteData);

+    }

+  }

+

+  Status = SpiExecFlashCmd (Slave->RegBase, Reg);

+  if (EFI_ERROR (Status)) {

+    goto Fail;

+  }

+

+  if (!EfiAtRuntime ()) {

+    EfiReleaseLock (&SpiMaster->Lock);

+  }

+  return EFI_SUCCESS;

+

+Fail:

+  if (!EfiAtRuntime ()) {

+    EfiReleaseLock (&SpiMaster->Lock);

+  }

+  return Status;

+}

+

+STATIC

+VOID

+SpiDelayNanoSec (

+  IN UINTN  nsec

+  )

+{

+  UINT32  Timeout = DIV_ROUND_UP (nsec, 1000);

+

+  do {

+    Timeout--;

+    gBS->Stall (1);

+  } while (Timeout);

+}

+

+STATIC

+VOID

+SpiWriteLong (

+  IN VOID        *Addr,

+  IN CONST VOID  *Data,

+  IN INTN        LongLen

+  )

+{

+  UINT32  *AddrPtr;

+  UINT32  *DataPtr;

+

+  AddrPtr  = (UINT32 *)Addr;

+  DataPtr = (UINT32 *)Data;

+

+  while (LongLen) {

+    *AddrPtr = *DataPtr;

+    DataPtr++;

+    LongLen--;

+  }

+}

+

+STATIC

+VOID

+SpiWriteByte (

+  IN VOID        *Addr,

+  IN CONST VOID  *Data,

+  IN INTN        ByteLen

+  )

+{

+  UINT8  *AddrPtr;

+  UINT8  *DataPtr;

+

+  AddrPtr  = (UINT8 *)Addr;

+  DataPtr  = (UINT8 *)Data;

+

+  while (ByteLen) {

+    *AddrPtr = *DataPtr;

+    DataPtr++;

+    ByteLen--;

+  }

+}

+

+EFI_STATUS

+SpiDataWrite (

+  IN SPI_MASTER_PROTOCOL *This,

+  IN SPI_DEVICE_PARAMS   *Slave,

+  IN OUT SPI_OP_PARAMS  *Cmds

+  )

+{

+  UINT32       Reg;

+  SPI_MASTER   *SpiMaster;

+  UINT32       PageSize  = Slave->Info->PageSize;

+  UINT32       Remaining = Cmds->Data.NBytes;

+  CONST UINT8  *TxBuf = Cmds->Data.Buf.Out;

+  UINT32       WriteBytes;

+  EFI_STATUS   Status;

+

+  SpiMaster = SPI_MASTER_FROM_SPI_MASTER_PROTOCOL (This);

+  if (!EfiAtRuntime ()) {

+    EfiAcquireLock (&SpiMaster->Lock);

+  }

+

+  if (!Cmds->Addr.NBytes) {

+    return EFI_ABORTED;

+  }

+

+  /* Write opcode to write instruction register */

+  Reg  = Cmds->Cmd.OpCode << SPI_REG_WR_INSTR_OPCODE_LSB;

+  MmioWrite32 (Slave->RegBase + SPI_REG_WR_INSTR, Reg);

+

+  /* Set buffer address */

+  MmioWrite32 (Slave->RegBase + SPI_REG_INDIRECTWRSTARTADDR, Cmds->Addr.Val);

+

+  /* Configure device size */

+  Reg  = MmioRead32 (Slave->RegBase + SPI_REG_SIZE);

+  Reg &= ~SPI_REG_SIZE_ADDRESS_MASK;

+  Reg |= (Cmds->Addr.NBytes - 1);

+  MmioWrite32 (Slave->RegBase + SPI_REG_SIZE, Reg);

+

+  /* Configure the indirect read transfer bytes */

+  MmioWrite32 (Slave->RegBase + SPI_REG_INDIRECTWRBYTES, Remaining);

+

+  /* Start the indirect write transfer */

+  MmioWrite32 (Slave->RegBase + SPI_REG_INDIRECTWR, SPI_REG_INDIRECTWR_START);

+

+  /* Delay is required for QSPI module to synchronized internally */

+  SpiDelayNanoSec (Slave->WriteDelay);

+

+  while (Remaining > 0) {

+    WriteBytes = Remaining > PageSize ? PageSize : Remaining;

+    SpiWriteLong (Slave->AhbBase, TxBuf, WriteBytes >> 2);

+    if (WriteBytes % 4) {

+      SpiWriteByte (

+                    Slave->AhbBase,

+                    TxBuf + ROUND_DOWN (WriteBytes, 4),

+                    WriteBytes % 4

+                    );

+    }

+

+    Status = SpiWaitForBitLe32 (

+                                Slave->RegBase + SPI_REG_SDRAMLEVEL,

+                                SPI_REG_SDRAMLEVEL_WR_MASK <<

+                                SPI_REG_SDRAMLEVEL_WR_LSB,

+                                0,

+                                10

+                                );

+    if (EFI_ERROR (Status)) {

+      DEBUG ((DEBUG_ERROR, "%a(): Indirect write timed out (%d)\n", __func__, Status));

+      goto FailWrite;

+    }

+

+    TxBuf  += WriteBytes;

+    Remaining -= WriteBytes;

+  }

+

+  /* Check indirect done status */

+  Status = SpiWaitForBitLe32 (

+                              Slave->RegBase + SPI_REG_INDIRECTWR,

+                              SPI_REG_INDIRECTWR_DONE,

+                              1,

+                              10

+                             );

+  if (EFI_ERROR (Status)) {

+    DEBUG ((DEBUG_ERROR, "Indirect write completion error (%d)\n", Status));

+    goto FailWrite;

+  }

+

+  /* Clear indirect completion status */

+  MmioWrite32 (Slave->RegBase + SPI_REG_INDIRECTWR, SPI_REG_INDIRECTWR_DONE);

+  if (!EfiAtRuntime ()) {

+    EfiReleaseLock (&SpiMaster->Lock);

+  }

+  return EFI_SUCCESS;

+

+FailWrite:

+  MmioWrite32 (Slave->RegBase + SPI_REG_INDIRECTWR, SPI_REG_INDIRECTWR_CANCEL);

+  if (!EfiAtRuntime ()) {

+    EfiReleaseLock (&SpiMaster->Lock);

+  }

+  return Status;

+}

+

+STATIC

+VOID

+SpiConfigGetDataCapture (

+  IN UINT32  RegBase,

+  IN UINT32  ByPass,

+  IN UINT32  Delay

+  )

+{

+  UINT32  Reg;

+

+  SpiControllerDisable (RegBase);

+

+  Reg = MmioRead32 (RegBase + SPI_REG_RD_DATA_CAPTURE);

+

+  if (ByPass) {

+    Reg |= SPI_REG_RD_DATA_CAPTURE_BYPASS;

+  } else {

+    Reg &= ~SPI_REG_RD_DATA_CAPTURE_BYPASS;

+  }

+

+  Reg &= ~(SPI_REG_RD_DATA_CAPTURE_DELAY_MASK

+           << SPI_REG_RD_DATA_CAPTURE_DELAY_LSB);

+

+  Reg |= (Delay & SPI_REG_RD_DATA_CAPTURE_DELAY_MASK)

+         << SPI_REG_RD_DATA_CAPTURE_DELAY_LSB;

+

+  MmioWrite32 (RegBase + SPI_REG_RD_DATA_CAPTURE, Reg);

+

+  SpiControllerEnable (RegBase);

+}

+

+STATIC

+EFI_STATUS

+SpiSpeedCalibration (

+  IN SPI_MASTER_PROTOCOL *This,

+  IN SPI_DEVICE_PARAMS  *Slave,

+  IN SPI_TIMING_PARAMS  *Timing

+  )

+{

+  UINT8         IdLen = 3;

+  UINT32        IdInit = 0, IdCali = 0;

+  INTN          RangeLow = -1, RangeHigh = -1;

+  SPI_OP_PARAMS  CmdsInitialId = SPI_READID_OP ((UINT8 *)&IdInit, IdLen);

+  SPI_OP_PARAMS  CmdsCalibrateId = SPI_READID_OP ((UINT8 *)&IdCali, IdLen);

+  EFI_STATUS    Status;

+

+  /* Start calibration with slowest clock speed at 1 MHz */

+  SpiWriteSpeed (Slave, SPI_MIN_HZ, Timing);

+

+  /* Set the read data capture delay register to 0 */

+  SpiConfigGetDataCapture (Slave->RegBase, 1, 0);

+

+  /* Get flash ID value as reference */

+  Status = SpiCommandRead (This, Slave, &CmdsInitialId);

+  if (EFI_ERROR (Status)) {

+    DEBUG ((DEBUG_ERROR, "Spi: Calibration failed (read id)\n"));

+    return EFI_ABORTED;

+  }

+

+  /* Use the input speed */

+  SpiWriteSpeed (Slave, SPI_MAX_HZ, Timing);

+

+  /* Find high and low range */

+  for (UINT8 i = 0; i < SPI_READ_CAPTURE_MAX_DELAY; i++) {

+    /* Change the read data capture delay register */

+    SpiConfigGetDataCapture (Slave->RegBase, 1, i);

+

+    /* Read flash ID for comparison later */

+    Status = SpiCommandRead (This, Slave, &CmdsCalibrateId);

+    if (EFI_ERROR (Status)) {

+      DEBUG ((DEBUG_ERROR, "Spi: Calibration failed (read)\n"));

+      return EFI_ABORTED;

+    }

+

+    /* Verify low range */

+    if ((RangeLow == -1) && (IdCali == IdInit)) {

+      RangeLow = i;

+      continue;

+    }

+

+    /* Verify high range */

+    if ((RangeLow != -1) && (IdCali != IdInit)) {

+      RangeHigh = i - 1;

+      break;

+    }

+

+    RangeHigh = i;

+  }

+

+  if (RangeLow == -1) {

+    DEBUG ((DEBUG_ERROR, "Spi: Calibration failed\n"));

+    return EFI_ABORTED;

+  }

+

+  /*

+  * Set the final value for read data capture delay register based

+  * on the calibrated value

+  */

+  SpiConfigGetDataCapture (Slave->RegBase, 1, (RangeHigh + RangeLow) / 2);

+  DEBUG (

+         (DEBUG_INFO, "Spi: Read data capture delay calibrated to %d (%d - %d)\n",

+          (RangeHigh + RangeLow) / 2, RangeLow, RangeHigh)

+         );

+

+  return EFI_SUCCESS;

+}

+

+EFI_STATUS

+SpiSetupDevice (

+  IN SPI_MASTER_PROTOCOL *This,

+  OUT SPI_DEVICE_PARAMS  *Slave

+  )

+{

+  SPI_TIMING_PARAMS  *Timing;

+  EFI_STATUS  Status;

+

+  if (!Slave) {

+    Slave = AllocateZeroPool (sizeof (SPI_DEVICE_PARAMS));

+    if (Slave == NULL) {

+      DEBUG ((DEBUG_ERROR, "%a(): Cannot allocate memory Slave\n", __func__));

+      Status = EFI_OUT_OF_RESOURCES;

+      goto Fail;

+    }

+  }

+

+  if (!Slave->Info) {

+    Slave->Info = AllocateZeroPool (sizeof (NOR_FLASH_INFO));

+    if (Slave->Info == NULL) {

+      DEBUG ((DEBUG_ERROR, "%a(): Cannot allocate memory Slave->Info\n", __func__));

+      Status = EFI_OUT_OF_RESOURCES;

+      goto Fail;

+    }

+  }

+

+  Timing = AllocateZeroPool (sizeof (SPI_TIMING_PARAMS));

+  if (Timing == NULL) {

+    DEBUG ((DEBUG_ERROR, "%a(): Cannot allocate memory Timing\n", __func__));

+    FreePool(Slave);

+    Status = EFI_OUT_OF_RESOURCES;

+    goto Fail;

+  }

+

+  Slave->RegBase    = PcdGet32 (PcdSpiFlashRegBase);

+  Slave->AhbBase    = (VOID *)(UINTN)PcdGet64 (PcdSpiFlashAhbBase);

+  Slave->FifoWidth  = PcdGet8 (PcdSpiFlashFifoWidth);

+  Timing->RefClkHz  = PcdGet32 (PcdSpiFlashRefClkHz);

+  Timing->TshslNs   = PcdGet32 (PcdSpiFlashTshslNs);

+  Timing->Tsd2dNs   = PcdGet32 (PcdSpiFlashTsd2dNs);

+  Timing->TchshNs   = PcdGet32 (PcdSpiFlashTchshNs);

+  Timing->TslchNs   = PcdGet32 (PcdSpiFlashTslchNs);

+

+  Slave->WriteDelay = 50 * DIV_ROUND_UP (NSEC_PER_SEC, Timing->RefClkHz);

+

+  Status = SpiSpeedCalibration (This, Slave, Timing);

+  if (EFI_ERROR (Status)) {

+    goto Fail;

+  }

+

+  FreePool(Timing);

+  return EFI_SUCCESS;

+

+Fail:

+  FreePool(Slave);

+  FreePool(Timing);

+  return Status;

+}

+

+EFI_STATUS

+SpiFreeDevice (

+  IN SPI_DEVICE_PARAMS  *Slave

+  )

+{

+  FreePool (Slave);

+

+  return EFI_SUCCESS;

+}

+

+EFI_STATUS

+SpiMasterInitProtocol (

+  IN SPI_MASTER_PROTOCOL  *SpiMasterProtocol

+  )

+{

+  SpiMasterProtocol->SetupDevice = SpiSetupDevice;

+  SpiMasterProtocol->FreeDevice  = SpiFreeDevice;

+  SpiMasterProtocol->CmdRead     = SpiCommandRead;

+  SpiMasterProtocol->DataRead    = SpiDataRead;

+  SpiMasterProtocol->CmdWrite    = SpiCommandWrite;

+  SpiMasterProtocol->DataWrite   = SpiDataWrite;

+

+  return EFI_SUCCESS;

+}

+

+EFI_STATUS

+SpiEntryPoint (

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

+                                                   &gJH7110SpiMasterProtocolGuid,

+                                                   &(mSpiMasterInstance->SpiMasterProtocol),

+                                                   NULL

+                                                   );

+  if (EFI_ERROR (Status)) {

+    FreePool (mSpiMasterInstance);

+    return EFI_DEVICE_ERROR;

+  }

+

+  return EFI_SUCCESS;

+}

diff --git a/Silicon/StarFive/JH7110Pkg/Driver/SpiFvbServicesDxe/SpiDxe/SpiDxe.h b/Silicon/StarFive/JH7110Pkg/Driver/SpiFvbServicesDxe/SpiDxe/SpiDxe.h
new file mode 100644
index 000000000000..804ee29c5ff1
--- /dev/null
+++ b/Silicon/StarFive/JH7110Pkg/Driver/SpiFvbServicesDxe/SpiDxe/SpiDxe.h
@@ -0,0 +1,188 @@
+/** @file

+ *

+ *  Copyright (c) 2023, StarFive Technology Co., Ltd. All rights reserved.<BR>

+ *

+ *  SPDX-License-Identifier: BSD-2-Clause-Patent

+ *

+ **/

+

+#ifndef __SPI_DXE_H__

+#define __SPI_DXE_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)

+

+#ifndef BIT

+#define BIT(nr)  (1 << (nr))

+#endif

+

+#define DIV_ROUND_UP(n, d)  (((n) + (d) - 1) / (d))

+#define ROUND_DOWN(x, y)  (\

+{                         \

+  typeof(x) __x = (x);    \

+  __x - (__x % (y));      \

+}                         \

+)

+#define NSEC_PER_SEC  1000000000L

+

+/* Configs */

+#define SPI_READ_CAPTURE_MAX_DELAY  16

+#define SPI_REG_RETRY               10000

+#define SPI_POLL_IDLE_RETRY         3

+#define SPI_STIG_DATA_LEN_MAX       8

+#define SPI_MIN_HZ                  1000000

+#define SPI_MAX_HZ                  100000000

+

+/*

+* QSPI controller's config and status register (offset from QSPI_BASE)

+*/

+#define SPI_REG_CONFIG                  0x00

+#define SPI_REG_CONFIG_ENABLE           BIT(0)

+#define SPI_REG_CONFIG_CLK_POL          BIT(1)

+#define SPI_REG_CONFIG_CLK_PHA          BIT(2)

+#define SPI_REG_CONFIG_DIRECT           BIT(7)

+#define SPI_REG_CONFIG_DECODE           BIT(9)

+#define SPI_REG_CONFIG_XIP_IMM          BIT(18)

+#define SPI_REG_CONFIG_CHIPSELECT_LSB   10

+#define SPI_REG_CONFIG_BAUD_LSB         19

+#define SPI_REG_CONFIG_DTR_PROTO        BIT(24)

+#define SPI_REG_CONFIG_DUAL_OPCODE      BIT(30)

+#define SPI_REG_CONFIG_IDLE_LSB         31

+#define SPI_REG_CONFIG_CHIPSELECT_MASK  0xF

+#define SPI_REG_CONFIG_BAUD_MASK        0xF

+

+#define SPI_REG_RD_INSTR                  0x04

+#define SPI_REG_RD_INSTR_OPCODE_LSB       0

+#define SPI_REG_RD_INSTR_TYPE_INSTR_LSB   8

+#define SPI_REG_RD_INSTR_TYPE_ADDR_LSB    12

+#define SPI_REG_RD_INSTR_TYPE_DATA_LSB    16

+#define SPI_REG_RD_INSTR_MODE_EN_LSB      20

+#define SPI_REG_RD_INSTR_DUMMY_LSB        24

+#define SPI_REG_RD_INSTR_TYPE_INSTR_MASK  0x3

+#define SPI_REG_RD_INSTR_TYPE_ADDR_MASK   0x3

+#define SPI_REG_RD_INSTR_TYPE_DATA_MASK   0x3

+#define SPI_REG_RD_INSTR_DUMMY_MASK       0x1F

+

+#define SPI_REG_WR_INSTR                0x08

+#define SPI_REG_WR_INSTR_OPCODE_LSB     0

+#define SPI_REG_WR_INSTR_TYPE_ADDR_LSB  12

+#define SPI_REG_WR_INSTR_TYPE_DATA_LSB  16

+

+#define SPI_REG_DELAY             0x0C

+#define SPI_REG_DELAY_TSLCH_LSB   0

+#define SPI_REG_DELAY_TCHSH_LSB   8

+#define SPI_REG_DELAY_TSD2D_LSB   16

+#define SPI_REG_DELAY_TSHSL_LSB   24

+#define SPI_REG_DELAY_TSLCH_MASK  0xFF

+#define SPI_REG_DELAY_TCHSH_MASK  0xFF

+#define SPI_REG_DELAY_TSD2D_MASK  0xFF

+#define SPI_REG_DELAY_TSHSL_MASK  0xFF

+

+#define SPI_REG_RD_DATA_CAPTURE             0x10

+#define SPI_REG_RD_DATA_CAPTURE_BYPASS      BIT(0)

+#define SPI_REG_RD_DATA_CAPTURE_DELAY_LSB   1

+#define SPI_REG_RD_DATA_CAPTURE_DELAY_MASK  0xF

+

+#define SPI_REG_SIZE               0x14

+#define SPI_REG_SIZE_ADDRESS_LSB   0

+#define SPI_REG_SIZE_PAGE_LSB      4

+#define SPI_REG_SIZE_BLOCK_LSB     16

+#define SPI_REG_SIZE_ADDRESS_MASK  0xF

+#define SPI_REG_SIZE_PAGE_MASK     0xFFF

+#define SPI_REG_SIZE_BLOCK_MASK    0x3F

+

+#define SPI_REG_SRAMPARTITION    0x18

+#define SPI_REG_INDIRECTTRIGGER  0x1C

+

+#define SPI_REG_REMAP     0x24

+#define SPI_REG_MODE_BIT  0x28

+

+#define SPI_REG_SDRAMLEVEL          0x2C

+#define SPI_REG_SDRAMLEVEL_RD_LSB   0

+#define SPI_REG_SDRAMLEVEL_WR_LSB   16

+#define SPI_REG_SDRAMLEVEL_RD_MASK  0xFFFF

+#define SPI_REG_SDRAMLEVEL_WR_MASK  0xFFFF

+

+#define SPI_REG_WR_COMPLETION_CTRL    0x38

+#define SPI_REG_WR_DISABLE_AUTO_POLL  BIT(14)

+

+#define SPI_REG_IRQSTATUS  0x40

+#define SPI_REG_IRQMASK    0x44

+

+#define SPI_REG_INDIRECTRD             0x60

+#define SPI_REG_INDIRECTRD_START       BIT(0)

+#define SPI_REG_INDIRECTRD_CANCEL      BIT(1)

+#define SPI_REG_INDIRECTRD_INPROGRESS  BIT(2)

+#define SPI_REG_INDIRECTRD_DONE        BIT(5)

+

+#define SPI_REG_INDIRECTRDWATERMARK  0x64

+#define SPI_REG_INDIRECTRDSTARTADDR  0x68

+#define SPI_REG_INDIRECTRDBYTES      0x6C

+

+#define SPI_REG_CMDCTRL                 0x90

+#define SPI_REG_CMDCTRL_EXECUTE         BIT(0)

+#define SPI_REG_CMDCTRL_INPROGRESS      BIT(1)

+#define SPI_REG_CMDCTRL_DUMMY_LSB       7

+#define SPI_REG_CMDCTRL_WR_BYTES_LSB    12

+#define SPI_REG_CMDCTRL_WR_EN_LSB       15

+#define SPI_REG_CMDCTRL_ADD_BYTES_LSB   16

+#define SPI_REG_CMDCTRL_ADDR_EN_LSB     19

+#define SPI_REG_CMDCTRL_RD_BYTES_LSB    20

+#define SPI_REG_CMDCTRL_RD_EN_LSB       23

+#define SPI_REG_CMDCTRL_OPCODE_LSB      24

+#define SPI_REG_CMDCTRL_DUMMY_MASK      0x1F

+#define SPI_REG_CMDCTRL_WR_BYTES_MASK   0x7

+#define SPI_REG_CMDCTRL_ADD_BYTES_MASK  0x3

+#define SPI_REG_CMDCTRL_RD_BYTES_MASK   0x7

+#define SPI_REG_CMDCTRL_OPCODE_MASK     0xFF

+

+#define SPI_REG_INDIRECTWR             0x70

+#define SPI_REG_INDIRECTWR_START       BIT(0)

+#define SPI_REG_INDIRECTWR_CANCEL      BIT(1)

+#define SPI_REG_INDIRECTWR_INPROGRESS  BIT(2)

+#define SPI_REG_INDIRECTWR_DONE        BIT(5)

+

+#define SPI_REG_INDIRECTWRWATERMARK  0x74

+#define SPI_REG_INDIRECTWRSTARTADDR  0x78

+#define SPI_REG_INDIRECTWRBYTES      0x7C

+

+#define SPI_REG_CMDADDRESS         0x94

+#define SPI_REG_CMDREADDATALOWER   0xA0

+#define SPI_REG_CMDREADDATAUPPER   0xA4

+#define SPI_REG_CMDWRITEDATALOWER  0xA8

+#define SPI_REG_CMDWRITEDATAUPPER  0xAC

+

+#define SPI_REG_OP_EXT_LOWER      0xE0

+#define SPI_REG_OP_EXT_READ_LSB   24

+#define SPI_REG_OP_EXT_WRITE_LSB  16

+#define SPI_REG_OP_EXT_STIG_LSB   0

+

+typedef struct {

+  SPI_MASTER_PROTOCOL  SpiMasterProtocol;

+  UINTN                Signature;

+  EFI_HANDLE           Handle;

+  EFI_LOCK             Lock;

+} SPI_MASTER;

+

+typedef struct {

+  UINT32  RefClkHz;

+  UINT32  TshslNs;

+  UINT32  TchshNs;

+  UINT32  TslchNs;

+  UINT32  Tsd2dNs;

+}SPI_TIMING_PARAMS;

+

+#endif //__SPI_DXE_H__

diff --git a/Silicon/StarFive/JH7110Pkg/Driver/SpiFvbServicesDxe/SpiDxe/SpiDxe.inf b/Silicon/StarFive/JH7110Pkg/Driver/SpiFvbServicesDxe/SpiDxe/SpiDxe.inf
new file mode 100644
index 000000000000..ed3f639346b2
--- /dev/null
+++ b/Silicon/StarFive/JH7110Pkg/Driver/SpiFvbServicesDxe/SpiDxe/SpiDxe.inf
@@ -0,0 +1,52 @@
+## @file

+#

+#  Copyright (c) 2023, StarFive Technology Co., Ltd. All rights reserved.<BR>

+#

+#  SPDX-License-Identifier: BSD-2-Clause-Patent

+#

+##

+

+[Defines]

+  INF_VERSION                    = 0x00010005

+  BASE_NAME                      = SpiDxe

+  FILE_GUID                      = 2FBD9E55-9BC7-4EEF-BF93-0D5582FE647B

+  MODULE_TYPE                    = DXE_RUNTIME_DRIVER

+  VERSION_STRING                 = 1.0

+  ENTRY_POINT                    = SpiEntryPoint

+

+[Sources]

+  SpiDxe.c

+  SpiDxe.h

+

+[Packages]

+  MdePkg/MdePkg.dec

+  EmbeddedPkg/EmbeddedPkg.dec

+  Silicon/StarFive/JH7110Pkg/JH7110Pkg.dec

+

+[LibraryClasses]

+  DebugLib

+  DxeServicesTableLib

+  IoLib

+  MemoryAllocationLib

+  NorFlashInfoLib

+  TimerLib

+  UefiBootServicesTableLib

+  UefiDriverEntryPoint

+  UefiLib

+  UefiRuntimeLib

+

+[FixedPcd]

+  gJH7110TokenSpaceGuid.PcdSpiFlashRegBase

+  gJH7110TokenSpaceGuid.PcdSpiFlashAhbBase

+  gJH7110TokenSpaceGuid.PcdSpiFlashFifoWidth

+  gJH7110TokenSpaceGuid.PcdSpiFlashRefClkHz

+  gJH7110TokenSpaceGuid.PcdSpiFlashTshslNs

+  gJH7110TokenSpaceGuid.PcdSpiFlashTsd2dNs

+  gJH7110TokenSpaceGuid.PcdSpiFlashTchshNs

+  gJH7110TokenSpaceGuid.PcdSpiFlashTslchNs

+

+[Protocols]

+  gJH7110SpiMasterProtocolGuid

+

+[Depex]

+  TRUE

diff --git a/Silicon/StarFive/JH7110Pkg/Driver/SpiFvbServicesDxe/SpiFlashDxe/SpiFlashDxe.c b/Silicon/StarFive/JH7110Pkg/Driver/SpiFvbServicesDxe/SpiFlashDxe/SpiFlashDxe.c
new file mode 100755
index 000000000000..cd508e53eb06
--- /dev/null
+++ b/Silicon/StarFive/JH7110Pkg/Driver/SpiFvbServicesDxe/SpiFlashDxe/SpiFlashDxe.c
@@ -0,0 +1,571 @@
+/** @file

+ *

+ *  Copyright (c) 2023, StarFive Technology Co., Ltd. All rights reserved.<BR>

+ *

+ *  SPDX-License-Identifier: BSD-2-Clause-Patent

+ *

+ **/

+

+#include <Library/NorFlashInfoLib.h>

+#include "SpiFlashDxe.h"

+

+SPI_MASTER_PROTOCOL  *SpiMasterProtocol;

+SPI_FLASH_INSTANCE   *mSpiFlashInstance;

+

+STATIC

+EFI_STATUS

+SpiFlashWriteEnableCmd (

+  IN  SPI_DEVICE_PARAMS  *Slave

+  )

+{

+  EFI_STATUS  Status;

+  SPI_OP_PARAMS  Op = SPI_WRITE_EN_OP();

+

+  /* Send write enable command */

+  Status = SpiMasterProtocol->CmdWrite (SpiMasterProtocol, Slave, &Op);

+

+  return Status;

+}

+

+STATIC

+EFI_STATUS

+SpiFlashWriteDisableCmd (

+  IN  SPI_DEVICE_PARAMS  *Slave

+  )

+{

+  EFI_STATUS  Status;

+  SPI_OP_PARAMS  Op = SPI_WRITE_DIS_OP();

+

+  /* Send write disable command */

+  Status = SpiMasterProtocol->CmdWrite (SpiMasterProtocol, Slave, &Op);

+

+  return Status;

+}

+

+STATIC

+EFI_STATUS

+SpiFlashPoll (

+  IN SPI_DEVICE_PARAMS *Slave

+)

+{

+  EFI_STATUS  Status;

+  UINT16      State;

+  UINT32      Counter     = 0xFFFFF;

+  UINT8       ReadLength  = 2;

+

+  SPI_OP_PARAMS  OpRdSts = SPI_OP (

+                                  SPI_OP_CMD (SPI_CMD_READ_STATUS),

+                                  SPI_OP_NO_ADDR,

+                                  SPI_OP_NO_DUMMY,

+                                  SPI_OP_DATA_IN (ReadLength, (VOID *)&State)

+                                  );

+

+  Status = SpiMasterProtocol->CmdRead (SpiMasterProtocol, Slave, &OpRdSts);

+  if (EFI_ERROR (Status)) {

+    DEBUG ((DEBUG_ERROR, "%a(): Spi error while reading status\n", __func__));

+    return Status;

+  }

+

+  do {

+    Status = SpiMasterProtocol->CmdRead (SpiMasterProtocol, Slave, &OpRdSts);

+    if (EFI_ERROR (Status)) {

+      DEBUG ((DEBUG_ERROR, "%a(): Spi error while reading status\n", __func__));

+      return Status;

+    }

+

+    Counter--;

+    if (!(State & STATUS_REG_POLL_WIP_MSK)) {

+      break;

+    }

+  } while (Counter > 0);

+

+  if (Counter == 0) {

+    DEBUG ((DEBUG_ERROR, "%a(): Timeout while writing to spi flash\n", __func__));

+    return EFI_TIMEOUT;

+  }

+

+  return EFI_SUCCESS;

+}

+

+EFI_STATUS

+SpiFlashErase (

+  IN SPI_DEVICE_PARAMS  *Slave,

+  IN UINT32             Offset,

+  IN UINTN              Length

+  )

+{

+  EFI_STATUS  Status;

+  UINT32      EraseAddr;

+  UINTN      EraseSize;

+  UINT8       EraseCmd;

+

+  if (Slave->Info->Flags & NOR_FLASH_ERASE_4K) {

+    EraseCmd  = SPI_CMD_ERASE_4K;

+    EraseSize = SIZE_4KB;

+  } else if (Slave->Info->Flags & NOR_FLASH_ERASE_32K) {

+    EraseCmd  = SPI_CMD_ERASE_32K;

+    EraseSize = SIZE_32KB;

+  } else {

+    EraseCmd  = SPI_CMD_ERASE_64K;

+    EraseSize = Slave->Info->SectorSize;

+  }

+

+  /* Verify input parameters */

+  if (Offset % EraseSize || Length % EraseSize) {

+    DEBUG (

+           (DEBUG_ERROR, "%a(): Either erase offset or length "

+                         "is not multiple of erase size\n, __func__")

+           );

+    return EFI_DEVICE_ERROR;

+  }

+

+  Status = SpiFlashWriteEnableCmd (Slave);

+  if (EFI_ERROR (Status)) {

+    DEBUG ((DEBUG_ERROR, "%a(): Error while setting write_enable\n", __func__));

+    return Status;

+  }

+

+  while (Length) {

+    EraseAddr = Offset;

+

+    SPI_OP_PARAMS  OpErase = SPI_OP (

+                                        SPI_OP_CMD (EraseCmd),

+                                        SPI_OP_ADDR (3, EraseAddr),

+                                        SPI_OP_NO_DUMMY,

+                                        SPI_OP_NO_DATA

+                                        );

+

+    Status = SpiMasterProtocol->CmdWrite (SpiMasterProtocol, Slave, &OpErase);

+    if (EFI_ERROR (Status)) {

+      DEBUG ((DEBUG_ERROR, "%a(): Spi erase fail\n", __func__));

+      return Status;

+    }

+

+    Status = SpiFlashPoll(Slave);

+    if (EFI_ERROR (Status)) {

+      return Status;

+    }

+

+    Offset += EraseSize;

+    Length -= EraseSize;

+  }

+

+  Status = SpiFlashWriteDisableCmd (Slave);

+  if (EFI_ERROR (Status)) {

+    DEBUG ((DEBUG_ERROR, "%a(): Error while setting write_disable\n", __func__));

+    return Status;

+  }

+

+  return EFI_SUCCESS;

+}

+

+EFI_STATUS

+SpiFlashRead (

+  IN SPI_DEVICE_PARAMS *Slave,

+  IN UINT32 Offset,

+  IN UINTN Length,

+  OUT VOID *Buffer

+  )

+{

+  EFI_STATUS  Status;

+  UINTN      ReadAddr, ReadLength, RemainLength;

+  UINT32      FlashSize;

+

+  FlashSize = Slave->Info->PageSize * Slave->Info->SectorSize;

+

+  /* Current handling is only limit for single flash Bank */

+  while (Length) {

+    ReadAddr = Offset;

+

+    RemainLength = (FlashSize - Offset);

+    if (Length < RemainLength) {

+      ReadLength = Length;

+    } else {

+      ReadLength = RemainLength;

+    }

+

+    /* Send read command */

+    SPI_OP_PARAMS  OpRead = SPI_OP (

+                                SPI_OP_CMD (SPI_CMD_READ_DATA),

+                                SPI_OP_ADDR (Slave->AddrSize, ReadAddr),

+                                SPI_OP_NO_DUMMY,

+                                SPI_OP_DATA_IN (ReadLength, Buffer)

+                                );

+

+    Status = SpiMasterProtocol->DataRead (SpiMasterProtocol, Slave, &OpRead);

+    if (EFI_ERROR (Status)) {

+      DEBUG ((DEBUG_ERROR, "%a(): Spi error while reading data\n", __func__));

+      return Status;

+    }

+

+    Offset += ReadLength;

+    Length -= ReadLength;

+    Buffer = (VOID *)((UINTN)Buffer + ReadLength);

+  }

+

+  return EFI_SUCCESS;

+}

+

+EFI_STATUS

+SpiFlashWrite (

+  IN SPI_DEVICE_PARAMS *Slave,

+  IN UINT32 Offset,

+  IN UINTN Length,

+  IN VOID *Buffer

+  )

+{

+  EFI_STATUS  Status;

+  UINTN       ByteAddr, ChunkLength, ActualIndex, PageSize;

+  UINT32      WriteAddr;

+

+  PageSize = Slave->Info->PageSize;

+

+  Status = SpiFlashWriteEnableCmd (Slave);

+  if (EFI_ERROR (Status)) {

+    DEBUG ((DEBUG_ERROR, "%a(): Error while setting write enable\n", __func__));

+    return Status;

+  }

+

+  for (ActualIndex = 0; ActualIndex < Length; ActualIndex += ChunkLength) {

+    WriteAddr = Offset;

+

+    ByteAddr    = Offset % PageSize;

+    ChunkLength = MIN (Length - ActualIndex, (UINT64)(PageSize - ByteAddr));

+

+    SPI_OP_PARAMS  OpPgProg = SPI_OP (

+                                      SPI_OP_CMD (SPI_CMD_PAGE_PROGRAM),

+                                      SPI_OP_ADDR (3, WriteAddr),

+                                      SPI_OP_NO_DUMMY,

+                                      SPI_OP_DATA_OUT (ChunkLength, (VOID *)((UINTN)Buffer + ActualIndex))

+                                      );

+

+    Status = SpiMasterProtocol->DataWrite (SpiMasterProtocol, Slave, &OpPgProg);

+    if (EFI_ERROR (Status)) {

+      DEBUG ((DEBUG_ERROR, "%a(): Error while programming write address\n", __func__));

+      return Status;

+    }

+

+    Status = SpiFlashPoll(Slave);

+    if (EFI_ERROR (Status)) {

+      return Status;

+    }

+

+    Offset += ChunkLength;

+  }

+

+  Status = SpiFlashWriteDisableCmd (Slave);

+  if (EFI_ERROR (Status)) {

+    DEBUG ((DEBUG_ERROR, "%a(): Error while setting write disable\n", __func__));

+    return Status;

+  }

+

+  return EFI_SUCCESS;

+}

+

+STATIC

+EFI_STATUS

+SpiFlashUpdateBlock (

+  IN SPI_DEVICE_PARAMS *Slave,

+  IN UINT32 Offset,

+  IN UINTN ToUpdate,

+  IN UINT8 *Buffer,

+  IN UINT8 *TmpBuf,

+  IN UINTN EraseSize

+  )

+{

+  EFI_STATUS Status;

+

+  /* Read backup */

+  Status = SpiFlashRead (Slave, Offset, EraseSize, TmpBuf);

+    if (EFI_ERROR (Status)) {

+      DEBUG((DEBUG_ERROR, "%a(): Update: Error while reading old data\n", __func__));

+      return Status;

+    }

+

+  /* Erase entire sector */

+  Status = SpiFlashErase (Slave, Offset, EraseSize);

+  if (EFI_ERROR (Status)) {

+      DEBUG((DEBUG_ERROR, "%a(): Update: Error while erasing block\n", __func__));

+      return Status;

+    }

+

+  /* Write new data */

+  SpiFlashWrite (Slave, Offset, ToUpdate, Buffer);

+  if (EFI_ERROR (Status)) {

+      DEBUG((DEBUG_ERROR, "%a(): Update: Error while writing new data\n", __func__));

+      return Status;

+    }

+

+  /* Write backup */

+  if (ToUpdate != EraseSize) {

+    Status = SpiFlashWrite (Slave, Offset + ToUpdate, EraseSize - ToUpdate,

+      &TmpBuf[ToUpdate]);

+    if (EFI_ERROR (Status)) {

+      DEBUG((DEBUG_ERROR, "%a(): Update: Error while writing backup\n", __func__));

+      return Status;

+    }

+  }

+

+  return EFI_SUCCESS;

+}

+

+EFI_STATUS

+SpiFlashUpdate (

+  IN SPI_DEVICE_PARAMS *Slave,

+  IN UINT32 Offset,

+  IN UINTN ByteCount,

+  IN UINT8 *Buffer

+  )

+{

+  EFI_STATUS Status;

+  UINT64 SectorSize, ToUpdate, Scale = 1;

+  UINT8 *TmpBuf, *End;

+

+  SectorSize = Slave->Info->SectorSize;

+

+  End = Buffer + ByteCount;

+

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

+  if (TmpBuf == NULL) {

+    DEBUG((DEBUG_ERROR, "%a(): Cannot allocate memory\n", __func__));

+    return EFI_OUT_OF_RESOURCES;

+  }

+

+  if (End - Buffer >= 200)

+    Scale = (End - Buffer) / 100;

+

+  for (; Buffer < End; Buffer += ToUpdate, Offset += ToUpdate) {

+    ToUpdate = MIN((UINT64)(End - Buffer), SectorSize);

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

+    Status = SpiFlashUpdateBlock (Slave, Offset, ToUpdate, Buffer, TmpBuf, SectorSize);

+

+    if (EFI_ERROR (Status)) {

+      DEBUG((DEBUG_ERROR, "%a(): Error while updating\n", __func__));

+      return Status;

+    }

+  }

+

+  Print(L"\n");

+  FreePool (TmpBuf);

+

+  return EFI_SUCCESS;

+}

+

+EFI_STATUS

+SpiFlashUpdateWithProgress (

+  IN SPI_DEVICE_PARAMS                             *Slave,

+  IN UINT32                                         Offset,

+  IN UINTN                                          ByteCount,

+  IN UINT8                                         *Buffer,

+  IN EFI_FIRMWARE_MANAGEMENT_UPDATE_IMAGE_PROGRESS  Progress,        OPTIONAL

+  IN UINTN                                          StartPercentage,

+  IN UINTN                                          EndPercentage

+  )

+{

+  EFI_STATUS Status;

+  UINTN SectorSize;

+  UINTN SectorNum;

+  UINTN ToUpdate;

+  UINTN Index;

+  UINT8 *TmpBuf;

+

+  SectorSize = Slave->Info->SectorSize;

+  SectorNum = (ByteCount / SectorSize) + 1;

+  ToUpdate = SectorSize;

+

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

+  if (TmpBuf == NULL) {

+    DEBUG ((DEBUG_ERROR, "%a(): Cannot allocate memory\n", __func__));

+    return EFI_OUT_OF_RESOURCES;

+  }

+

+  for (Index = 0; Index < SectorNum; Index++) {

+    if (Progress != NULL) {

+      Progress (StartPercentage +

+                ((Index * (EndPercentage - StartPercentage)) / SectorNum));

+    }

+

+    /* In the last chunk update only an actual number of remaining bytes */

+    if (Index + 1 == SectorNum) {

+      ToUpdate = ByteCount % SectorSize;

+    }

+

+    Status = SpiFlashUpdateBlock (Slave,

+               Offset + Index * SectorSize,

+               ToUpdate,

+               Buffer + Index * SectorSize,

+               TmpBuf,

+               SectorSize);

+    if (EFI_ERROR (Status)) {

+      DEBUG ((DEBUG_ERROR, "%a(): Error while updating\n", __func__));

+      return Status;

+    }

+  }

+  FreePool (TmpBuf);

+

+  if (Progress != NULL) {

+    Progress (EndPercentage);

+  }

+

+  return EFI_SUCCESS;

+}

+

+EFI_STATUS

+EFIAPI

+SpiFlashReadId (

+  IN SPI_DEVICE_PARAMS  *Slave,

+  IN BOOLEAN            UseInRuntime

+  )

+{

+  EFI_STATUS  Status;

+  UINT8       IdLen = 3;

+  UINT8       Id[IdLen];

+

+  SPI_OP_PARAMS  Op = SPI_READID_OP (Id, IdLen);

+

+  Status = SpiMasterProtocol->CmdRead (SpiMasterProtocol, Slave, &Op);

+  if (EFI_ERROR (Status)) {

+    DEBUG ((DEBUG_ERROR, "%a(): Spi error while reading id\n", __func__));

+    return Status;

+  }

+

+  Status = NorFlashGetInfo (Id, &Slave->Info, UseInRuntime);

+

+  if (EFI_ERROR (Status)) {

+    DEBUG (

+           (DEBUG_ERROR,

+            "%a: Unrecognized JEDEC Id bytes: 0x%02x%02x%02x\n",

+            __func__,

+            Id[0],

+            Id[1],

+            Id[2])

+           );

+    return Status;

+  }

+

+  NorFlashPrintInfo (Slave->Info);

+

+  return EFI_SUCCESS;

+}

+

+EFI_STATUS

+EFIAPI

+SpiFlashInit (

+  IN SPI_FLASH_PROTOCOL  *This,

+  IN SPI_DEVICE_PARAMS   *Slave

+  )

+{

+  EFI_STATUS  Status;

+  UINT8       StatusRegister;

+

+  Slave->AddrSize = (Slave->Info->Flags & NOR_FLASH_4B_ADDR) ? 4 : 3;

+

+  Status = SpiFlashWriteEnableCmd (Slave);

+  if (EFI_ERROR (Status)) {

+    DEBUG ((DEBUG_ERROR, "%a(): Error while setting write enable\n", __func__));

+    return Status;

+  }

+

+  if (Slave->AddrSize == 4) {

+

+    /* Enable 4byte addressing */

+    SPI_OP_PARAMS  Op4BAddEn = SPI_OP (

+                                        SPI_OP_CMD (SPI_CMD_4B_ADDR_ENABLE),

+                                        SPI_OP_NO_ADDR,

+                                        SPI_OP_NO_DUMMY,

+                                        SPI_OP_NO_DATA

+                                        );

+    Status = SpiMasterProtocol->CmdWrite (SpiMasterProtocol, Slave, &Op4BAddEn);

+    if (EFI_ERROR (Status)) {

+      DEBUG ((DEBUG_ERROR, "%a(): Error while setting 4B address\n", __func__));

+      return Status;

+    }

+  }

+

+  /* Initialize flash status register */

+  StatusRegister = 0x0;

+  SPI_OP_PARAMS  OpWrSts = SPI_OP (

+                                    SPI_OP_CMD (SPI_CMD_WRITE_STATUS_REG),

+                                    SPI_OP_NO_ADDR,

+                                    SPI_OP_NO_DUMMY,

+                                    SPI_OP_DATA_OUT (1, (VOID *)&StatusRegister)

+                                    );

+

+  Status = SpiMasterProtocol->CmdWrite (SpiMasterProtocol, Slave, &OpWrSts);

+  if (EFI_ERROR (Status)) {

+    DEBUG ((DEBUG_ERROR, "%a(): Error while writing status register\n", __func__));

+    return Status;

+  }

+

+  Status = SpiFlashWriteDisableCmd (Slave);

+  if (EFI_ERROR (Status)) {

+    DEBUG ((DEBUG_ERROR, "%a(): Error while setting write disable\n", __func__));

+    return Status;

+  }

+

+  return EFI_SUCCESS;

+}

+

+EFI_STATUS

+SpiFlashInitProtocol (

+  IN SPI_FLASH_PROTOCOL  *SpiFlashProtocol

+  )

+{

+  SpiFlashProtocol->Read   = SpiFlashRead;

+  SpiFlashProtocol->Write  = SpiFlashWrite;

+  SpiFlashProtocol->Update = SpiFlashUpdate;

+  SpiFlashProtocol->UpdateWithProgress = SpiFlashUpdateWithProgress;

+  SpiFlashProtocol->Erase  = SpiFlashErase;

+  SpiFlashProtocol->ReadId = SpiFlashReadId;

+  SpiFlashProtocol->Init   = SpiFlashInit;

+

+  return EFI_SUCCESS;

+}

+

+EFI_STATUS

+EFIAPI

+SpiFlashEntryPoint (

+  IN EFI_HANDLE        ImageHandle,

+  IN EFI_SYSTEM_TABLE  *SystemTable

+  )

+{

+  EFI_STATUS  Status;

+

+  Status = gBS->LocateProtocol (

+                                &gJH7110SpiMasterProtocolGuid,

+                                NULL,

+                                (VOID **)&SpiMasterProtocol

+                                );

+  if (EFI_ERROR (Status)) {

+    DEBUG ((DEBUG_ERROR, "%a(): Cannot locate SPI Master protocol\n", __func__));

+    return EFI_DEVICE_ERROR;

+  }

+

+  mSpiFlashInstance = AllocateRuntimeZeroPool (sizeof (SPI_FLASH_INSTANCE));

+  if (mSpiFlashInstance == NULL) {

+    DEBUG ((DEBUG_ERROR, "%a(): Cannot allocate memory\n", __func__));

+    return EFI_OUT_OF_RESOURCES;

+  }

+

+  SpiFlashInitProtocol (&mSpiFlashInstance->SpiFlashProtocol);

+

+  mSpiFlashInstance->Signature = SPI_FLASH_SIGNATURE;

+

+  Status = gBS->InstallMultipleProtocolInterfaces (

+                                                   &(mSpiFlashInstance->Handle),

+                                                   &gJH7110SpiFlashProtocolGuid,

+                                                   &(mSpiFlashInstance->SpiFlashProtocol),

+                                                   NULL

+                                                   );

+  if (EFI_ERROR (Status)) {

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

+    goto ErrorInstallProto;

+  }

+

+  return EFI_SUCCESS;

+

+ErrorInstallProto:

+  FreePool (mSpiFlashInstance);

+

+  return EFI_SUCCESS;

+}

diff --git a/Silicon/StarFive/JH7110Pkg/Driver/SpiFvbServicesDxe/SpiFlashDxe/SpiFlashDxe.h b/Silicon/StarFive/JH7110Pkg/Driver/SpiFvbServicesDxe/SpiFlashDxe/SpiFlashDxe.h
new file mode 100755
index 000000000000..f3bb300334c0
--- /dev/null
+++ b/Silicon/StarFive/JH7110Pkg/Driver/SpiFvbServicesDxe/SpiFlashDxe/SpiFlashDxe.h
@@ -0,0 +1,35 @@
+/** @file

+ *

+ *  Copyright (c) 2023, StarFive Technology Co., Ltd. All rights reserved.<BR>

+ *

+ *  SPDX-License-Identifier: BSD-2-Clause-Patent

+ *

+ **/

+

+#ifndef __SPI_FLASH_DXE_H__

+#define __SPI_FLASH_DXE_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 STATUS_REG_POLL_WIP_MSK  (1 << 0)

+

+typedef struct {

+  SPI_FLASH_PROTOCOL    SpiFlashProtocol;

+  UINTN                 Signature;

+  EFI_HANDLE            Handle;

+} SPI_FLASH_INSTANCE;

+

+#endif //__SPI_FLASH_DXE_H__

diff --git a/Silicon/StarFive/JH7110Pkg/Driver/SpiFvbServicesDxe/SpiFlashDxe/SpiFlashDxe.inf b/Silicon/StarFive/JH7110Pkg/Driver/SpiFvbServicesDxe/SpiFlashDxe/SpiFlashDxe.inf
new file mode 100644
index 000000000000..3ca429fdc2dd
--- /dev/null
+++ b/Silicon/StarFive/JH7110Pkg/Driver/SpiFvbServicesDxe/SpiFlashDxe/SpiFlashDxe.inf
@@ -0,0 +1,44 @@
+## @file

+#

+#  Copyright (c) 2023, StarFive Technology Co., Ltd. All rights reserved.<BR>

+#

+#  SPDX-License-Identifier: BSD-2-Clause-Patent

+#

+##

+

+[Defines]

+  INF_VERSION                    = 0x00010005

+  BASE_NAME                      = SpiFlashDxe

+  FILE_GUID                      = D3DF07BE-3810-4521-89EF-C4E22E0B2484

+  MODULE_TYPE                    = DXE_RUNTIME_DRIVER

+  VERSION_STRING                 = 1.0

+  ENTRY_POINT                    = SpiFlashEntryPoint

+

+[Sources]

+  SpiFlashDxe.c

+  SpiFlashDxe.h

+

+[Packages]

+  EmbeddedPkg/EmbeddedPkg.dec

+  MdePkg/MdePkg.dec

+  Silicon/StarFive/JH7110Pkg/JH7110Pkg.dec

+

+[LibraryClasses]

+  DebugLib

+  MemoryAllocationLib

+  NorFlashInfoLib

+  TimerLib

+  UefiBootServicesTableLib

+  UefiDriverEntryPoint

+  UefiLib

+  UefiRuntimeLib

+

+[Guids]

+  gEfiEventVirtualAddressChangeGuid

+

+[Protocols]

+  gJH7110SpiFlashProtocolGuid

+  gJH7110SpiMasterProtocolGuid

+

+[Depex]

+  gJH7110SpiMasterProtocolGuid

diff --git a/Silicon/StarFive/JH7110Pkg/Include/Protocol/Spi.h b/Silicon/StarFive/JH7110Pkg/Include/Protocol/Spi.h
new file mode 100644
index 000000000000..b8db3ad4c5b0
--- /dev/null
+++ b/Silicon/StarFive/JH7110Pkg/Include/Protocol/Spi.h
@@ -0,0 +1,163 @@
+/** @file

+ *

+ *  Copyright (c) 2023, StarFive Technology Co., Ltd. All rights reserved.<BR>

+ *

+ *  SPDX-License-Identifier: BSD-2-Clause-Patent

+ *

+ **/

+

+#ifndef __SPI_MASTER_PROTOCOL_H__

+#define __SPI_MASTER_PROTOCOL_H__

+

+#include <Library/NorFlashInfoLib.h>

+

+typedef struct _SPI_MASTER_PROTOCOL SPI_MASTER_PROTOCOL;

+

+

+#define SPI_CMD_WRITE_STATUS_REG  0x01

+#define SPI_CMD_PAGE_PROGRAM      0x02

+#define SPI_CMD_READ_DATA         0x03

+#define SPI_CMD_WRITE_DISABLE     0x04

+#define SPI_CMD_READ_STATUS       0x05

+#define SPI_CMD_WRITE_ENABLE      0x06

+#define SPI_CMD_READ_ARRAY_FAST   0x0b

+#define SPI_CMD_BANKADDR_BRWR     0x17

+#define SPI_CMD_ERASE_4K          0x20

+#define SPI_CMD_ERASE_32K         0x52

+#define SPI_CMD_FLAG_STATUS       0x70

+#define SPI_CMD_READ_ID           0x9f

+#define SPI_CMD_4B_ADDR_ENABLE    0xb7

+#define SPI_CMD_BANK_WRITE        0xc5

+#define SPI_CMD_ERASE_64K         0xd8

+

+

+

+#define SPI_OP_CMD(__OpCode)  \

+  {                      \

+    .OpCode = __OpCode,  \

+    .NBytes = 1,         \

+  }

+

+#define SPI_OP_ADDR(__NBytes, __Val)  \

+  {                      \

+    .NBytes = __NBytes,  \

+    .Val = __Val,        \

+  }

+

+#define SPI_OP_NO_ADDR  { }

+

+#define SPI_OP_DUMMY(__NBytes)  \

+  {                      \

+    .NBytes = __NBytes,  \

+  }

+

+#define SPI_OP_NO_DUMMY  { }

+

+#define SPI_OP_DATA_IN(__NBytes, __Buf)  \

+  {                      \

+    .NBytes = __NBytes,  \

+    .Buf.In = __Buf,     \

+  }

+

+#define SPI_OP_DATA_OUT(__NBytes, __Buf)  \

+  {                     \

+    .NBytes = __NBytes, \

+    .Buf.Out = __Buf,   \

+  }

+

+#define SPI_OP_NO_DATA  { }

+

+#define SPI_OP(__Cmd, __Addr, __Dummy, __Data)  \

+  {                    \

+    .Cmd = __Cmd,      \

+    .Addr = __Addr,    \

+    .Dummy = __Dummy,  \

+    .Data = __Data,    \

+  }

+

+/**

+ * Standard SPI NOR flash operations

+ */

+#define SPI_WRITE_EN_OP()    \

+  SPI_OP(SPI_OP_CMD(SPI_CMD_WRITE_ENABLE),  \

+       SPI_OP_NO_ADDR,        \

+       SPI_OP_NO_DUMMY,       \

+       SPI_OP_NO_DATA)

+

+#define SPI_WRITE_DIS_OP()   \

+  SPI_OP(SPI_OP_CMD(SPI_CMD_WRITE_DISABLE),  \

+       SPI_OP_NO_ADDR,        \

+       SPI_OP_NO_DUMMY,       \

+       SPI_OP_NO_DATA)

+

+#define SPI_READID_OP(Buf, Len)  \

+  SPI_OP(SPI_OP_CMD(SPI_CMD_READ_ID),  \

+       SPI_OP_NO_ADDR,        \

+       SPI_OP_NO_DUMMY,       \

+       SPI_OP_DATA_IN(Len, Buf))

+

+typedef struct {

+  struct {

+    UINT8     NBytes;

+    UINT16    OpCode;

+  } Cmd;

+

+  struct {

+    UINT8     NBytes;

+    UINT64    Val;

+  } Addr;

+

+  struct {

+    UINT8    NBytes;

+  } Dummy;

+

+  struct {

+    UINT32          NBytes;

+    union {

+      VOID          *In;

+      CONST VOID    *Out;

+    } Buf;

+  } Data;

+} SPI_OP_PARAMS;

+

+typedef struct {

+  UINT32            AddrSize;

+  NOR_FLASH_INFO    *Info;

+  UINT32            RegBase;

+  VOID              *AhbBase;

+  UINT8             FifoWidth;

+  UINT32            WriteDelay;

+} SPI_DEVICE_PARAMS;

+

+typedef

+  EFI_STATUS

+(EFIAPI *SPI_DEVICE_SETUP)(

+                      IN SPI_MASTER_PROTOCOL *This,

+                      OUT SPI_DEVICE_PARAMS *Slave

+                    );

+

+typedef

+  EFI_STATUS

+(EFIAPI *SPI_DEVICE_FREE)(

+                      IN SPI_DEVICE_PARAMS  *Slave

+                    );

+

+

+typedef

+  EFI_STATUS

+(EFIAPI *SPI_EXECUTE_RW)(

+                          IN SPI_MASTER_PROTOCOL *This,

+                          IN SPI_DEVICE_PARAMS  *Slave,

+                          IN OUT SPI_OP_PARAMS  *Cmds

+                        );

+

+struct _SPI_MASTER_PROTOCOL {

+  SPI_DEVICE_SETUP  SetupDevice;

+  SPI_DEVICE_FREE   FreeDevice;

+  SPI_EXECUTE_RW    CmdRead;

+  SPI_EXECUTE_RW    DataRead;

+  SPI_EXECUTE_RW    CmdWrite;

+  SPI_EXECUTE_RW    DataWrite;

+};

+

+#endif // __SPI_MASTER_PROTOCOL_H__

diff --git a/Silicon/StarFive/JH7110Pkg/Include/Protocol/SpiFlash.h b/Silicon/StarFive/JH7110Pkg/Include/Protocol/SpiFlash.h
new file mode 100644
index 000000000000..cdbe4d0b6b67
--- /dev/null
+++ b/Silicon/StarFive/JH7110Pkg/Include/Protocol/SpiFlash.h
@@ -0,0 +1,88 @@
+/** @file

+ *

+ *  Copyright (c) 2023, StarFive Technology Co., Ltd. All rights reserved.<BR>

+ *

+ *  SPDX-License-Identifier: BSD-2-Clause-Patent

+ *

+ **/

+

+#ifndef __SPI_FLASH_PROTOCOL_H__

+#define __SPI_FLASH_PROTOCOL_H__

+

+#include <Protocol/FirmwareManagement.h>

+#include <Protocol/Spi.h>

+

+typedef struct _SPI_FLASH_PROTOCOL SPI_FLASH_PROTOCOL;

+

+typedef

+  EFI_STATUS

+(EFIAPI *SPI_FLASH_INIT) (

+                         IN SPI_FLASH_PROTOCOL *This,

+                         IN SPI_DEVICE_PARAMS *SpiDev

+                         );

+

+typedef

+  EFI_STATUS

+(EFIAPI *SPI_FLASH_READ_ID) (

+                            IN SPI_DEVICE_PARAMS *Slave,

+                            IN BOOLEAN UseInRuntime

+                            );

+

+typedef

+  EFI_STATUS

+(EFIAPI *SPI_FLASH_READ) (

+                         IN SPI_DEVICE_PARAMS *Slave,

+                         IN UINT32 Offset,

+                         IN UINTN Length,

+                         OUT VOID *Buffer

+                         );

+

+typedef

+  EFI_STATUS

+(EFIAPI *SPI_FLASH_WRITE) (

+                          IN SPI_DEVICE_PARAMS *Slave,

+                          IN UINT32 Offset,

+                          IN UINTN Length,

+                          IN VOID *Buffer

+                          );

+

+typedef

+  EFI_STATUS

+(EFIAPI *SPI_FLASH_ERASE) (

+                          IN SPI_DEVICE_PARAMS *Slave,

+                          IN UINT32 Offset,

+                          IN UINTN Length

+                          );

+

+typedef

+  EFI_STATUS

+(EFIAPI *SPI_FLASH_UPDATE) (

+                          IN SPI_DEVICE_PARAMS *Slave,

+                          IN UINT32     Address,

+                          IN UINTN      DataByteCount,

+                          IN UINT8      *Buffer

+                          );

+

+typedef

+  EFI_STATUS

+(EFIAPI *SPI_FLASH_UPDATE_WITH_PROGRESS) (

+  IN SPI_DEVICE_PARAMS                              *Slave,

+  IN UINT32                                         Offset,

+  IN UINTN                                          ByteCount,

+  IN UINT8                                         *Buffer,

+  IN EFI_FIRMWARE_MANAGEMENT_UPDATE_IMAGE_PROGRESS  Progress, OPTIONAL

+  IN UINTN                                          StartPercentage,

+  IN UINTN                                          EndPercentage

+  );

+

+struct _SPI_FLASH_PROTOCOL {

+  SPI_FLASH_INIT     Init;

+  SPI_FLASH_READ_ID  ReadId;

+  SPI_FLASH_READ     Read;

+  SPI_FLASH_WRITE    Write;

+  SPI_FLASH_ERASE    Erase;

+  SPI_FLASH_UPDATE   Update;

+  SPI_FLASH_UPDATE_WITH_PROGRESS  UpdateWithProgress;

+};

+

+#endif // __SPI_FLASH_PROTOCOL_H__

-- 
2.34.1



-=-=-=-=-=-=-=-=-=-=-=-
Groups.io Links: You receive all messages sent to this group.
View/Reply Online (#109897): https://edk2.groups.io/g/devel/message/109897
Mute This Topic: https://groups.io/mt/102130703/1813853
Group Owner: devel+owner at edk2.groups.io
Unsubscribe: https://edk2.groups.io/g/devel/unsub [edk2-devel-archive at redhat.com]
-=-=-=-=-=-=-=-=-=-=-=-




More information about the edk2-devel-archive mailing list