From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from mail02.groups.io (mail02.groups.io [66.175.222.108]) by spool.mail.gandi.net (Postfix) with ESMTPS id 8109B7803CE for ; Fri, 27 Oct 2023 03:24:32 +0000 (UTC) DKIM-Signature: a=rsa-sha256; bh=u772eGkT+5PAoU2YfpHF6ZA3Vcc1gD7SaoVcwmJEQd4=; c=relaxed/simple; d=groups.io; h=From:To:CC:Subject:Date:Message-ID:In-Reply-To:References:MIME-Version:Precedence:List-Subscribe:List-Help:Sender:List-Id:Mailing-List:Delivered-To:Reply-To:List-Unsubscribe-Post:List-Unsubscribe:Content-Type:Content-Transfer-Encoding; s=20140610; t=1698377071; v=1; b=aZJtsnlN45634a6sUXL8OqQ8eDw4HreDo2kbrosgR96M9x1Rr7I8tH+uCBJCZE0YIqqBj9fy nRKLR5Q3e5ijOXJlsEWZfdw0NYLjsNqzZoWvwzIgP0lJmjRtSK/79oAbxOArfW+i0piSynRso1w rov9BLqrEzy/tUlOPKWsZOX8= X-Received: by 127.0.0.2 with SMTP id b4vuYY7687511xaeLVuMRvOv; Thu, 26 Oct 2023 20:24:31 -0700 X-Received: from ex01.ufhost.com (ex01.ufhost.com [61.152.239.75]) by mx.groups.io with SMTP id smtpd.web10.218633.1698377057391309831 for ; Thu, 26 Oct 2023 20:24:30 -0700 X-Received: from EXMBX166.cuchost.com (unknown [175.102.18.54]) (using TLSv1 with cipher DHE-RSA-AES256-SHA (256/256 bits)) (Client CN "EXMBX166", Issuer "EXMBX166" (not verified)) by ex01.ufhost.com (Postfix) with ESMTP id F06A924E2A1; Fri, 27 Oct 2023 11:23:56 +0800 (CST) X-Received: from EXMBX073.cuchost.com (172.16.6.83) by EXMBX166.cuchost.com (172.16.6.76) with Microsoft SMTP Server (TLS) id 15.0.1497.42; Fri, 27 Oct 2023 11:23:57 +0800 X-Received: from localhost.localdomain (202.188.176.82) by EXMBX073.cuchost.com (172.16.6.83) with Microsoft SMTP Server (TLS) id 15.0.1497.42; Fri, 27 Oct 2023 11:23:51 +0800 From: "John Chew" To: CC: John Chew , Sunil V L , Leif Lindholm , Michael D Kinney , Li Yong Subject: [edk2-devel] [PATCH v3 2/5] StarFive/JH7110Pkg: Add SPI protocol and driver support Date: Fri, 27 Oct 2023 11:19:03 +0800 Message-ID: <20231027031906.1814-3-yuinyee.chew@starfivetech.com> In-Reply-To: <20231027031906.1814-1-yuinyee.chew@starfivetech.com> References: <20231027031906.1814-1-yuinyee.chew@starfivetech.com> MIME-Version: 1.0 X-Originating-IP: [202.188.176.82] X-ClientProxiedBy: EXCAS062.cuchost.com (172.16.6.22) To EXMBX073.cuchost.com (172.16.6.83) X-YovoleRuleAgent: yovoleflag Precedence: Bulk List-Subscribe: List-Help: Sender: devel@edk2.groups.io List-Id: Mailing-List: list devel@edk2.groups.io; contact devel+owner@edk2.groups.io Reply-To: devel@edk2.groups.io,yuinyee.chew@starfivetech.com List-Unsubscribe-Post: List-Unsubscribe=One-Click List-Unsubscribe: X-Gm-Message-State: YIyPVDBuGK4rbNY24Rc7x1WMx7686176AA= Content-Type: text/plain Content-Transfer-Encoding: quoted-printable X-GND-Status: LEGIT Authentication-Results: spool.mail.gandi.net; dkim=pass header.d=groups.io header.s=20140610 header.b=aZJtsnlN; dmarc=none; spf=pass (spool.mail.gandi.net: domain of bounce@groups.io designates 66.175.222.108 as permitted sender) smtp.mailfrom=bounce@groups.io 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 Cc: Leif Lindholm Cc: Michael D Kinney Cc: Li Yong Signed-off-by: John Chew --- 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/SpiFlashDx= e.c | 571 +++++++++++++ Silicon/StarFive/JH7110Pkg/Driver/SpiFvbServicesDxe/SpiFlashDxe/SpiFlashDx= e.h | 35 + Silicon/StarFive/JH7110Pkg/Driver/SpiFvbServicesDxe/SpiFlashDxe/SpiFlashDx= e.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/Spi= Dxe.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.=
+ * + * SPDX-License-Identifier: BSD-2-Clause-Patent + * + **/ + +#include "SpiDxe.h" + +SPI_MASTER *mSpiMasterInstance; + +STATIC +VOID +SpiControllerEnable ( + IN UINT32 RegBase + ) +{ + UINT32 Reg; + + Reg =3D MmioRead32 (RegBase + SPI_REG_CONFIG); + Reg |=3D SPI_REG_CONFIG_ENABLE; + MmioWrite32 (RegBase + SPI_REG_CONFIG, Reg); +} + +STATIC +VOID +SpiControllerDisable ( + IN UINT32 RegBase + ) +{ + UINT32 Reg; + + Reg =3D MmioRead32 (RegBase + SPI_REG_CONFIG); + Reg &=3D ~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 =3D MmioRead32 (Slave->RegBase + SPI_REG_CONFIG); + Reg &=3D ~(SPI_REG_CONFIG_BAUD_MASK << SPI_REG_CONFIG_BAUD_LSB); + + Div =3D DIV_ROUND_UP (Timing->RefClkHz, SclkHz * 2) - 1; + + if (Div > SPI_REG_CONFIG_BAUD_MASK) { + Div =3D 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 |=3D (Div << SPI_REG_CONFIG_BAUD_LSB); + MmioWrite32 (Slave->RegBase + SPI_REG_CONFIG, Reg); + + /* Configure delay timing */ + RefClkNs =3D DIV_ROUND_UP (1000000000, Timing->RefClkHz); + SclkNs =3D DIV_ROUND_UP (1000000000, SclkHz); + + if (Timing->TshslNs >=3D SclkNs + RefClkNs) { + Timing->TshslNs -=3D SclkNs + RefClkNs; + } + + if (Timing->TchshNs >=3D SclkNs + 3 * RefClkNs) { + Timing->TchshNs -=3D SclkNs + 3 * RefClkNs; + } + + Tshsl =3D DIV_ROUND_UP (Timing->TshslNs, RefClkNs); + Tchsh =3D DIV_ROUND_UP (Timing->TchshNs, RefClkNs); + Tslch =3D DIV_ROUND_UP (Timing->TslchNs, RefClkNs); + Tsd2d =3D DIV_ROUND_UP (Timing->Tsd2dNs, RefClkNs); + + Reg =3D ((Tshsl & SPI_REG_DELAY_TSHSL_MASK) + << SPI_REG_DELAY_TSHSL_LSB); + Reg |=3D ((Tchsh & SPI_REG_DELAY_TCHSH_MASK) + << SPI_REG_DELAY_TCHSH_LSB); + Reg |=3D ((Tslch & SPI_REG_DELAY_TSLCH_MASK) + << SPI_REG_DELAY_TSLCH_LSB); + Reg |=3D ((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 =3D 0; + UINT32 TimeoutMs =3D 5000000; + + do { + IsIdle =3D (BOOLEAN)((MmioRead32(RegBase + SPI_REG_CONFIG) >> + SPI_REG_CONFIG_IDLE_LSB) & 0x1); + Count =3D (IsIdle) ? (Count+1) : 0; + + /* + * Make sure the QSPI controller is in really idle + * for n period of time before proceed + */ + if (Count >=3D 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 =3D SPI_REG_RETRY; + + /* Write the CMDCTRL without start execution */ + MmioWrite32 (RegBase + SPI_REG_CMDCTRL, Reg); + /* Start execute */ + Reg |=3D SPI_REG_CMDCTRL_EXECUTE; + MmioWrite32 (RegBase + SPI_REG_CMDCTRL, Reg); + + while (Retry--) { + Reg =3D MmioRead32 (RegBase + SPI_REG_CMDCTRL); + if ((Reg & SPI_REG_CMDCTRL_INPROGRESS) =3D=3D 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 =3D 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 =3D Cmds->Data.NBytes; + VOID *RxBuf =3D Cmds->Data.Buf.In; + + SpiMaster =3D 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", __fun= c__, RxLen)); + Status =3D EFI_INVALID_PARAMETER; + goto Fail; + } + + Reg =3D Cmds->Cmd.OpCode << SPI_REG_CMDCTRL_OPCODE_LSB; + Reg |=3D (0x1 << SPI_REG_CMDCTRL_RD_EN_LSB); + + /* 0 means 1 byte */ + Reg |=3D (((RxLen - 1) & SPI_REG_CMDCTRL_RD_BYTES_MASK) + << SPI_REG_CMDCTRL_RD_BYTES_LSB); + Status =3D SpiExecFlashCmd (Slave->RegBase, Reg); + if (EFI_ERROR (Status)) { + goto Fail; + } + + Reg =3D MmioRead32 (Slave->RegBase + SPI_REG_CMDREADDATALOWER); + + /* Put the read value into rx_buf */ + ReadLen =3D (RxLen > 4) ? 4 : RxLen; + CopyMem (RxBuf, &Reg, ReadLen); + RxBuf +=3D ReadLen; + + if (RxLen > 4) { + Reg =3D MmioRead32 (Slave->RegBase + SPI_REG_CMDREADDATAUPPER); + + ReadLen =3D 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 =3D MmioRead32 (RegBase + SPI_REG_SDRAMLEVEL); + Reg >>=3D SPI_REG_SDRAMLEVEL_RD_LSB; + *SramLvl =3D (UINT16)(Reg & SPI_REG_SDRAMLEVEL_RD_MASK); + + return EFI_SUCCESS; +} + +STATIC +EFI_STATUS +SpiWaitForData ( + IN UINT32 RegBase, + UINT16 *SramLvl + ) +{ + UINT32 Timeout =3D 10000; + + while (Timeout--) { + SpiGetReadSramLevel (RegBase, SramLvl); + if (SramLvl !=3D 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 =3D TimeoutMs*1000; + + while(1) { + Val =3D MmioRead32 (Reg); + + if (!Set) { + Val =3D ~Val; + } + + if ((Val & Mask) =3D=3D Mask) { + return EFI_SUCCESS; + } + + if (Start =3D=3D 0) { + break; + } else { + Start--; + } + + gBS->Stall (1); + } + + DEBUG ((DEBUG_ERROR, "Timeout (Reg=3D%lx Mask=3D%x wait_set=3D%d)\n", Re= g, Mask, Set)); + + return EFI_TIMEOUT; +} + +STATIC +VOID +SpiReadByte ( + IN VOID *Addr, + IN VOID *Data, + IN UINT16 ByteLen + ) +{ + UINT8 *AddrPtr; + UINT8 *DataPtr; + + AddrPtr =3D (UINT8 *)Addr; + DataPtr =3D (UINT8 *)Data; + + while (ByteLen) { + *DataPtr =3D *AddrPtr; + DataPtr++; + ByteLen--; + } +} + +STATIC +VOID +SpiReadLong ( + VOID *Addr, + VOID *Data, + UINT16 LongLen + ) +{ + UINT32 *AddrPtr; + UINT32 *DataPtr; + + AddrPtr =3D (UINT32 *)Addr; + DataPtr =3D (UINT32 *)Data; + + while (LongLen) { + *DataPtr =3D *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 =3D Cmds->Data.Buf.In; + UINT32 Remaining =3D Cmds->Data.NBytes; + UINT16 BytesToRead =3D 0; + EFI_STATUS Status; + UINT32 Reg; + + SpiMaster =3D SPI_MASTER_FROM_SPI_MASTER_PROTOCOL (This); + if (!EfiAtRuntime ()) { + EfiAcquireLock (&SpiMaster->Lock); + } + + if (!Cmds->Addr.NBytes) { + Status =3D EFI_ABORTED; + goto Fail; + } + + /* Setup the indirect trigger start address */ + MmioWrite32 (Slave->RegBase + SPI_REG_INDIRECTRDSTARTADDR, Cmds->Addr.Va= l); + + /* Register command */ + Reg =3D Cmds->Cmd.OpCode << SPI_REG_RD_INSTR_OPCODE_LSB; + MmioWrite32 (Slave->RegBase + SPI_REG_RD_INSTR, Reg); + + /* Set device size */ + Reg =3D MmioRead32 (Slave->RegBase + SPI_REG_SIZE); + Reg &=3D ~SPI_REG_SIZE_ADDRESS_MASK; + Reg |=3D (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_STA= RT); + + while (Remaining > 0) { + Status =3D SpiWaitForData (Slave->RegBase, &BytesToRead); + if (EFI_ERROR(Status)) { + DEBUG ((DEBUG_ERROR, "%a(): Indirect write timed out\n", __func__)); + goto Fail; + } + + while (BytesToRead !=3D 0) { + BytesToRead *=3D Slave->FifoWidth; + if (BytesToRead > Remaining) { + BytesToRead =3D Remaining; + } + + if (((UINTN)RxBuf % 4) || (BytesToRead % 4)) { + SpiReadByte (Slave->AhbBase, RxBuf, BytesToRead); + } else { + SpiReadLong (Slave->AhbBase, RxBuf, BytesToRead >> 2); + } + + RxBuf +=3D BytesToRead; + Remaining -=3D BytesToRead; + SpiGetReadSramLevel (Slave->RegBase, &BytesToRead); + } + } + + /* Check indirect done status */ + Status =3D 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_DON= E); + + if (!EfiAtRuntime ()) { + EfiReleaseLock (&SpiMaster->Lock); + } + return EFI_SUCCESS; + +Fail: + MmioWrite32 (Slave->RegBase + SPI_REG_INDIRECTRD, SPI_REG_INDIRECTRD_CAN= CEL); + 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 =3D Cmds->Data.NBytes; + CONST VOID *TxBuf =3D Cmds->Data.Buf.Out; + UINT32 Addr; + EFI_STATUS Status; + + SpiMaster =3D 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 =3D SwapBytes32 (Cmds->Addr.Val); + if (Cmds->Addr.NBytes =3D=3D 3) { + Addr >>=3D 8; + } + + TxBuf =3D &Addr; + TxLen =3D Cmds->Addr.NBytes; + } + + if (TxLen > SPI_STIG_DATA_LEN_MAX) { + DEBUG ((DEBUG_ERROR, "QSPI: Invalid input arguments TxLen %d\n", TxLen= )); + Status =3D EFI_INVALID_PARAMETER; + goto Fail; + } + + Reg =3D Cmds->Cmd.OpCode << SPI_REG_CMDCTRL_OPCODE_LSB; + + if (TxLen) { + Reg |=3D (0x1 << SPI_REG_CMDCTRL_WR_EN_LSB); + Reg |=3D ((TxLen - 1) & SPI_REG_CMDCTRL_WR_BYTES_MASK) + << SPI_REG_CMDCTRL_WR_BYTES_LSB; + + WriteLen =3D TxLen > 4 ? 4 : TxLen; + CopyMem (&WriteData, TxBuf, WriteLen); + MmioWrite32 (Slave->RegBase + SPI_REG_CMDWRITEDATALOWER, WriteData); + + if (TxLen > 4) { + TxBuf +=3D WriteLen; + WriteLen =3D TxLen - WriteLen; + CopyMem (&WriteData, TxBuf, WriteLen); + MmioWrite32 (Slave->RegBase + SPI_REG_CMDWRITEDATAUPPER, WriteData); + } + } + + Status =3D 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 =3D 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 =3D (UINT32 *)Addr; + DataPtr =3D (UINT32 *)Data; + + while (LongLen) { + *AddrPtr =3D *DataPtr; + DataPtr++; + LongLen--; + } +} + +STATIC +VOID +SpiWriteByte ( + IN VOID *Addr, + IN CONST VOID *Data, + IN INTN ByteLen + ) +{ + UINT8 *AddrPtr; + UINT8 *DataPtr; + + AddrPtr =3D (UINT8 *)Addr; + DataPtr =3D (UINT8 *)Data; + + while (ByteLen) { + *AddrPtr =3D *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 =3D Slave->Info->PageSize; + UINT32 Remaining =3D Cmds->Data.NBytes; + CONST UINT8 *TxBuf =3D Cmds->Data.Buf.Out; + UINT32 WriteBytes; + EFI_STATUS Status; + + SpiMaster =3D 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 =3D 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.Va= l); + + /* Configure device size */ + Reg =3D MmioRead32 (Slave->RegBase + SPI_REG_SIZE); + Reg &=3D ~SPI_REG_SIZE_ADDRESS_MASK; + Reg |=3D (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_STA= RT); + + /* Delay is required for QSPI module to synchronized internally */ + SpiDelayNanoSec (Slave->WriteDelay); + + while (Remaining > 0) { + WriteBytes =3D Remaining > PageSize ? PageSize : Remaining; + SpiWriteLong (Slave->AhbBase, TxBuf, WriteBytes >> 2); + if (WriteBytes % 4) { + SpiWriteByte ( + Slave->AhbBase, + TxBuf + ROUND_DOWN (WriteBytes, 4), + WriteBytes % 4 + ); + } + + Status =3D 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 +=3D WriteBytes; + Remaining -=3D WriteBytes; + } + + /* Check indirect done status */ + Status =3D 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_DON= E); + if (!EfiAtRuntime ()) { + EfiReleaseLock (&SpiMaster->Lock); + } + return EFI_SUCCESS; + +FailWrite: + MmioWrite32 (Slave->RegBase + SPI_REG_INDIRECTWR, SPI_REG_INDIRECTWR_CAN= CEL); + if (!EfiAtRuntime ()) { + EfiReleaseLock (&SpiMaster->Lock); + } + return Status; +} + +STATIC +VOID +SpiConfigGetDataCapture ( + IN UINT32 RegBase, + IN UINT32 ByPass, + IN UINT32 Delay + ) +{ + UINT32 Reg; + + SpiControllerDisable (RegBase); + + Reg =3D MmioRead32 (RegBase + SPI_REG_RD_DATA_CAPTURE); + + if (ByPass) { + Reg |=3D SPI_REG_RD_DATA_CAPTURE_BYPASS; + } else { + Reg &=3D ~SPI_REG_RD_DATA_CAPTURE_BYPASS; + } + + Reg &=3D ~(SPI_REG_RD_DATA_CAPTURE_DELAY_MASK + << SPI_REG_RD_DATA_CAPTURE_DELAY_LSB); + + Reg |=3D (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 =3D 3; + UINT32 IdInit =3D 0, IdCali =3D 0; + INTN RangeLow =3D -1, RangeHigh =3D -1; + SPI_OP_PARAMS CmdsInitialId =3D SPI_READID_OP ((UINT8 *)&IdInit, IdLen)= ; + SPI_OP_PARAMS CmdsCalibrateId =3D SPI_READID_OP ((UINT8 *)&IdCali, IdLe= n); + 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 =3D 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 =3D 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 =3D SpiCommandRead (This, Slave, &CmdsCalibrateId); + if (EFI_ERROR (Status)) { + DEBUG ((DEBUG_ERROR, "Spi: Calibration failed (read)\n")); + return EFI_ABORTED; + } + + /* Verify low range */ + if ((RangeLow =3D=3D -1) && (IdCali =3D=3D IdInit)) { + RangeLow =3D i; + continue; + } + + /* Verify high range */ + if ((RangeLow !=3D -1) && (IdCali !=3D IdInit)) { + RangeHigh =3D i - 1; + break; + } + + RangeHigh =3D i; + } + + if (RangeLow =3D=3D -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 =3D AllocateZeroPool (sizeof (SPI_DEVICE_PARAMS)); + if (Slave =3D=3D NULL) { + DEBUG ((DEBUG_ERROR, "%a(): Cannot allocate memory Slave\n", __func_= _)); + Status =3D EFI_OUT_OF_RESOURCES; + goto Fail; + } + } + + if (!Slave->Info) { + Slave->Info =3D AllocateZeroPool (sizeof (NOR_FLASH_INFO)); + if (Slave->Info =3D=3D NULL) { + DEBUG ((DEBUG_ERROR, "%a(): Cannot allocate memory Slave->Info\n", _= _func__)); + Status =3D EFI_OUT_OF_RESOURCES; + goto Fail; + } + } + + Timing =3D AllocateZeroPool (sizeof (SPI_TIMING_PARAMS)); + if (Timing =3D=3D NULL) { + DEBUG ((DEBUG_ERROR, "%a(): Cannot allocate memory Timing\n", __func__= )); + FreePool(Slave); + Status =3D EFI_OUT_OF_RESOURCES; + goto Fail; + } + + Slave->RegBase =3D PcdGet32 (PcdSpiFlashRegBase); + Slave->AhbBase =3D (VOID *)(UINTN)PcdGet64 (PcdSpiFlashAhbBase); + Slave->FifoWidth =3D PcdGet8 (PcdSpiFlashFifoWidth); + Timing->RefClkHz =3D PcdGet32 (PcdSpiFlashRefClkHz); + Timing->TshslNs =3D PcdGet32 (PcdSpiFlashTshslNs); + Timing->Tsd2dNs =3D PcdGet32 (PcdSpiFlashTsd2dNs); + Timing->TchshNs =3D PcdGet32 (PcdSpiFlashTchshNs); + Timing->TslchNs =3D PcdGet32 (PcdSpiFlashTslchNs); + + Slave->WriteDelay =3D 50 * DIV_ROUND_UP (NSEC_PER_SEC, Timing->RefClkHz)= ; + + Status =3D 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 =3D SpiSetupDevice; + SpiMasterProtocol->FreeDevice =3D SpiFreeDevice; + SpiMasterProtocol->CmdRead =3D SpiCommandRead; + SpiMasterProtocol->DataRead =3D SpiDataRead; + SpiMasterProtocol->CmdWrite =3D SpiCommandWrite; + SpiMasterProtocol->DataWrite =3D SpiDataWrite; + + return EFI_SUCCESS; +} + +EFI_STATUS +SpiEntryPoint ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ) +{ + EFI_STATUS Status; + + mSpiMasterInstance =3D AllocateRuntimeZeroPool (sizeof (SPI_MASTER)); + if (mSpiMasterInstance =3D=3D NULL) { + return EFI_OUT_OF_RESOURCES; + } + + EfiInitializeLock (&mSpiMasterInstance->Lock, TPL_NOTIFY); + + SpiMasterInitProtocol (&mSpiMasterInstance->SpiMasterProtocol); + + mSpiMasterInstance->Signature =3D SPI_MASTER_SIGNATURE; + + Status =3D gBS->InstallMultipleProtocolInterfaces ( + &(mSpiMasterInstance->H= andle), + &gJH7110SpiMasterProtoc= olGuid, + &(mSpiMasterInstance->S= piMasterProtocol), + NULL + ); + if (EFI_ERROR (Status)) { + FreePool (mSpiMasterInstance); + return EFI_DEVICE_ERROR; + } + + return EFI_SUCCESS; +} diff --git a/Silicon/StarFive/JH7110Pkg/Driver/SpiFvbServicesDxe/SpiDxe/Spi= Dxe.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.=
+ * + * SPDX-License-Identifier: BSD-2-Clause-Patent + * + **/ + +#ifndef __SPI_DXE_H__ +#define __SPI_DXE_H__ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#define SPI_MASTER_SIGNATURE SIGNATURE_32 ('M', 'S', = 'P', 'I') +#define SPI_MASTER_FROM_SPI_MASTER_PROTOCOL(a) CR (a, SPI_MASTER, SpiMast= erProtocol, 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 =3D (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/Spi= Dxe.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 =3D 0x00010005 + BASE_NAME =3D SpiDxe + FILE_GUID =3D 2FBD9E55-9BC7-4EEF-BF93-0D5582FE647B + MODULE_TYPE =3D DXE_RUNTIME_DRIVER + VERSION_STRING =3D 1.0 + ENTRY_POINT =3D 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/SpiFlashDx= e/SpiFlashDxe.c b/Silicon/StarFive/JH7110Pkg/Driver/SpiFvbServicesDxe/SpiFl= ashDxe/SpiFlashDxe.c new file mode 100755 index 000000000000..cd508e53eb06 --- /dev/null +++ b/Silicon/StarFive/JH7110Pkg/Driver/SpiFvbServicesDxe/SpiFlashDxe/SpiFl= ashDxe.c @@ -0,0 +1,571 @@ +/** @file + * + * Copyright (c) 2023, StarFive Technology Co., Ltd. All rights reserved.=
+ * + * SPDX-License-Identifier: BSD-2-Clause-Patent + * + **/ + +#include +#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 =3D SPI_WRITE_EN_OP(); + + /* Send write enable command */ + Status =3D SpiMasterProtocol->CmdWrite (SpiMasterProtocol, Slave, &Op); + + return Status; +} + +STATIC +EFI_STATUS +SpiFlashWriteDisableCmd ( + IN SPI_DEVICE_PARAMS *Slave + ) +{ + EFI_STATUS Status; + SPI_OP_PARAMS Op =3D SPI_WRITE_DIS_OP(); + + /* Send write disable command */ + Status =3D SpiMasterProtocol->CmdWrite (SpiMasterProtocol, Slave, &Op); + + return Status; +} + +STATIC +EFI_STATUS +SpiFlashPoll ( + IN SPI_DEVICE_PARAMS *Slave +) +{ + EFI_STATUS Status; + UINT16 State; + UINT32 Counter =3D 0xFFFFF; + UINT8 ReadLength =3D 2; + + SPI_OP_PARAMS OpRdSts =3D SPI_OP ( + SPI_OP_CMD (SPI_CMD_READ_STATUS), + SPI_OP_NO_ADDR, + SPI_OP_NO_DUMMY, + SPI_OP_DATA_IN (ReadLength, (VOID *)&Sta= te) + ); + + Status =3D SpiMasterProtocol->CmdRead (SpiMasterProtocol, Slave, &OpRdSt= s); + if (EFI_ERROR (Status)) { + DEBUG ((DEBUG_ERROR, "%a(): Spi error while reading status\n", __func_= _)); + return Status; + } + + do { + Status =3D SpiMasterProtocol->CmdRead (SpiMasterProtocol, Slave, &OpRd= Sts); + if (EFI_ERROR (Status)) { + DEBUG ((DEBUG_ERROR, "%a(): Spi error while reading status\n", __fun= c__)); + return Status; + } + + Counter--; + if (!(State & STATUS_REG_POLL_WIP_MSK)) { + break; + } + } while (Counter > 0); + + if (Counter =3D=3D 0) { + DEBUG ((DEBUG_ERROR, "%a(): Timeout while writing to spi flash\n", __f= unc__)); + 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 =3D SPI_CMD_ERASE_4K; + EraseSize =3D SIZE_4KB; + } else if (Slave->Info->Flags & NOR_FLASH_ERASE_32K) { + EraseCmd =3D SPI_CMD_ERASE_32K; + EraseSize =3D SIZE_32KB; + } else { + EraseCmd =3D SPI_CMD_ERASE_64K; + EraseSize =3D 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 =3D SpiFlashWriteEnableCmd (Slave); + if (EFI_ERROR (Status)) { + DEBUG ((DEBUG_ERROR, "%a(): Error while setting write_enable\n", __fun= c__)); + return Status; + } + + while (Length) { + EraseAddr =3D Offset; + + SPI_OP_PARAMS OpErase =3D SPI_OP ( + SPI_OP_CMD (EraseCmd), + SPI_OP_ADDR (3, EraseAddr), + SPI_OP_NO_DUMMY, + SPI_OP_NO_DATA + ); + + Status =3D SpiMasterProtocol->CmdWrite (SpiMasterProtocol, Slave, &OpE= rase); + if (EFI_ERROR (Status)) { + DEBUG ((DEBUG_ERROR, "%a(): Spi erase fail\n", __func__)); + return Status; + } + + Status =3D SpiFlashPoll(Slave); + if (EFI_ERROR (Status)) { + return Status; + } + + Offset +=3D EraseSize; + Length -=3D EraseSize; + } + + Status =3D SpiFlashWriteDisableCmd (Slave); + if (EFI_ERROR (Status)) { + DEBUG ((DEBUG_ERROR, "%a(): Error while setting write_disable\n", __fu= nc__)); + 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 =3D Slave->Info->PageSize * Slave->Info->SectorSize; + + /* Current handling is only limit for single flash Bank */ + while (Length) { + ReadAddr =3D Offset; + + RemainLength =3D (FlashSize - Offset); + if (Length < RemainLength) { + ReadLength =3D Length; + } else { + ReadLength =3D RemainLength; + } + + /* Send read command */ + SPI_OP_PARAMS OpRead =3D 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 =3D SpiMasterProtocol->DataRead (SpiMasterProtocol, Slave, &OpR= ead); + if (EFI_ERROR (Status)) { + DEBUG ((DEBUG_ERROR, "%a(): Spi error while reading data\n", __func_= _)); + return Status; + } + + Offset +=3D ReadLength; + Length -=3D ReadLength; + Buffer =3D (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 =3D Slave->Info->PageSize; + + Status =3D SpiFlashWriteEnableCmd (Slave); + if (EFI_ERROR (Status)) { + DEBUG ((DEBUG_ERROR, "%a(): Error while setting write enable\n", __fun= c__)); + return Status; + } + + for (ActualIndex =3D 0; ActualIndex < Length; ActualIndex +=3D ChunkLeng= th) { + WriteAddr =3D Offset; + + ByteAddr =3D Offset % PageSize; + ChunkLength =3D MIN (Length - ActualIndex, (UINT64)(PageSize - ByteAdd= r)); + + SPI_OP_PARAMS OpPgProg =3D 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 =3D SpiMasterProtocol->DataWrite (SpiMasterProtocol, Slave, &Op= PgProg); + if (EFI_ERROR (Status)) { + DEBUG ((DEBUG_ERROR, "%a(): Error while programming write address\n"= , __func__)); + return Status; + } + + Status =3D SpiFlashPoll(Slave); + if (EFI_ERROR (Status)) { + return Status; + } + + Offset +=3D ChunkLength; + } + + Status =3D SpiFlashWriteDisableCmd (Slave); + if (EFI_ERROR (Status)) { + DEBUG ((DEBUG_ERROR, "%a(): Error while setting write disable\n", __fu= nc__)); + 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 =3D 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 =3D SpiFlashErase (Slave, Offset, EraseSize); + if (EFI_ERROR (Status)) { + DEBUG((DEBUG_ERROR, "%a(): Update: Error while erasing block\n", __f= unc__)); + 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 !=3D EraseSize) { + Status =3D SpiFlashWrite (Slave, Offset + ToUpdate, EraseSize - ToUpda= te, + &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 =3D 1; + UINT8 *TmpBuf, *End; + + SectorSize =3D Slave->Info->SectorSize; + + End =3D Buffer + ByteCount; + + TmpBuf =3D (UINT8 *)AllocateZeroPool (SectorSize); + if (TmpBuf =3D=3D NULL) { + DEBUG((DEBUG_ERROR, "%a(): Cannot allocate memory\n", __func__)); + return EFI_OUT_OF_RESOURCES; + } + + if (End - Buffer >=3D 200) + Scale =3D (End - Buffer) / 100; + + for (; Buffer < End; Buffer +=3D ToUpdate, Offset +=3D ToUpdate) { + ToUpdate =3D MIN((UINT64)(End - Buffer), SectorSize); + Print (L" \rUpdating, %d%%", 100 - (End - Buffer) / Scale); + Status =3D SpiFlashUpdateBlock (Slave, Offset, ToUpdate, Buffer, TmpBu= f, 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, OPTIO= NAL + IN UINTN StartPercentage, + IN UINTN EndPercentage + ) +{ + EFI_STATUS Status; + UINTN SectorSize; + UINTN SectorNum; + UINTN ToUpdate; + UINTN Index; + UINT8 *TmpBuf; + + SectorSize =3D Slave->Info->SectorSize; + SectorNum =3D (ByteCount / SectorSize) + 1; + ToUpdate =3D SectorSize; + + TmpBuf =3D (UINT8 *)AllocateZeroPool (SectorSize); + if (TmpBuf =3D=3D NULL) { + DEBUG ((DEBUG_ERROR, "%a(): Cannot allocate memory\n", __func__)); + return EFI_OUT_OF_RESOURCES; + } + + for (Index =3D 0; Index < SectorNum; Index++) { + if (Progress !=3D NULL) { + Progress (StartPercentage + + ((Index * (EndPercentage - StartPercentage)) / SectorNum))= ; + } + + /* In the last chunk update only an actual number of remaining bytes *= / + if (Index + 1 =3D=3D SectorNum) { + ToUpdate =3D ByteCount % SectorSize; + } + + Status =3D 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 !=3D NULL) { + Progress (EndPercentage); + } + + return EFI_SUCCESS; +} + +EFI_STATUS +EFIAPI +SpiFlashReadId ( + IN SPI_DEVICE_PARAMS *Slave, + IN BOOLEAN UseInRuntime + ) +{ + EFI_STATUS Status; + UINT8 IdLen =3D 3; + UINT8 Id[IdLen]; + + SPI_OP_PARAMS Op =3D SPI_READID_OP (Id, IdLen); + + Status =3D SpiMasterProtocol->CmdRead (SpiMasterProtocol, Slave, &Op); + if (EFI_ERROR (Status)) { + DEBUG ((DEBUG_ERROR, "%a(): Spi error while reading id\n", __func__)); + return Status; + } + + Status =3D 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 =3D (Slave->Info->Flags & NOR_FLASH_4B_ADDR) ? 4 : 3; + + Status =3D SpiFlashWriteEnableCmd (Slave); + if (EFI_ERROR (Status)) { + DEBUG ((DEBUG_ERROR, "%a(): Error while setting write enable\n", __fun= c__)); + return Status; + } + + if (Slave->AddrSize =3D=3D 4) { + + /* Enable 4byte addressing */ + SPI_OP_PARAMS Op4BAddEn =3D SPI_OP ( + SPI_OP_CMD (SPI_CMD_4B_ADDR_ENABLE= ), + SPI_OP_NO_ADDR, + SPI_OP_NO_DUMMY, + SPI_OP_NO_DATA + ); + Status =3D SpiMasterProtocol->CmdWrite (SpiMasterProtocol, Slave, &Op4= BAddEn); + if (EFI_ERROR (Status)) { + DEBUG ((DEBUG_ERROR, "%a(): Error while setting 4B address\n", __fun= c__)); + return Status; + } + } + + /* Initialize flash status register */ + StatusRegister =3D 0x0; + SPI_OP_PARAMS OpWrSts =3D SPI_OP ( + SPI_OP_CMD (SPI_CMD_WRITE_STATUS_REG), + SPI_OP_NO_ADDR, + SPI_OP_NO_DUMMY, + SPI_OP_DATA_OUT (1, (VOID *)&StatusReg= ister) + ); + + Status =3D SpiMasterProtocol->CmdWrite (SpiMasterProtocol, Slave, &OpWrS= ts); + if (EFI_ERROR (Status)) { + DEBUG ((DEBUG_ERROR, "%a(): Error while writing status register\n", __= func__)); + return Status; + } + + Status =3D SpiFlashWriteDisableCmd (Slave); + if (EFI_ERROR (Status)) { + DEBUG ((DEBUG_ERROR, "%a(): Error while setting write disable\n", __fu= nc__)); + return Status; + } + + return EFI_SUCCESS; +} + +EFI_STATUS +SpiFlashInitProtocol ( + IN SPI_FLASH_PROTOCOL *SpiFlashProtocol + ) +{ + SpiFlashProtocol->Read =3D SpiFlashRead; + SpiFlashProtocol->Write =3D SpiFlashWrite; + SpiFlashProtocol->Update =3D SpiFlashUpdate; + SpiFlashProtocol->UpdateWithProgress =3D SpiFlashUpdateWithProgress; + SpiFlashProtocol->Erase =3D SpiFlashErase; + SpiFlashProtocol->ReadId =3D SpiFlashReadId; + SpiFlashProtocol->Init =3D SpiFlashInit; + + return EFI_SUCCESS; +} + +EFI_STATUS +EFIAPI +SpiFlashEntryPoint ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ) +{ + EFI_STATUS Status; + + Status =3D gBS->LocateProtocol ( + &gJH7110SpiMasterProtocolGuid, + NULL, + (VOID **)&SpiMasterProtocol + ); + if (EFI_ERROR (Status)) { + DEBUG ((DEBUG_ERROR, "%a(): Cannot locate SPI Master protocol\n", __fu= nc__)); + return EFI_DEVICE_ERROR; + } + + mSpiFlashInstance =3D AllocateRuntimeZeroPool (sizeof (SPI_FLASH_INSTANC= E)); + if (mSpiFlashInstance =3D=3D NULL) { + DEBUG ((DEBUG_ERROR, "%a(): Cannot allocate memory\n", __func__)); + return EFI_OUT_OF_RESOURCES; + } + + SpiFlashInitProtocol (&mSpiFlashInstance->SpiFlashProtocol); + + mSpiFlashInstance->Signature =3D SPI_FLASH_SIGNATURE; + + Status =3D gBS->InstallMultipleProtocolInterfaces ( + &(mSpiFlashInstance->Ha= ndle), + &gJH7110SpiFlashProtoco= lGuid, + &(mSpiFlashInstance->Sp= iFlashProtocol), + NULL + ); + if (EFI_ERROR (Status)) { + DEBUG ((DEBUG_ERROR, "%a(): Cannot install SPI flash protocol\n", __fu= nc__)); + goto ErrorInstallProto; + } + + return EFI_SUCCESS; + +ErrorInstallProto: + FreePool (mSpiFlashInstance); + + return EFI_SUCCESS; +} diff --git a/Silicon/StarFive/JH7110Pkg/Driver/SpiFvbServicesDxe/SpiFlashDx= e/SpiFlashDxe.h b/Silicon/StarFive/JH7110Pkg/Driver/SpiFvbServicesDxe/SpiFl= ashDxe/SpiFlashDxe.h new file mode 100755 index 000000000000..f3bb300334c0 --- /dev/null +++ b/Silicon/StarFive/JH7110Pkg/Driver/SpiFvbServicesDxe/SpiFlashDxe/SpiFl= ashDxe.h @@ -0,0 +1,35 @@ +/** @file + * + * Copyright (c) 2023, StarFive Technology Co., Ltd. All rights reserved.=
+ * + * SPDX-License-Identifier: BSD-2-Clause-Patent + * + **/ + +#ifndef __SPI_FLASH_DXE_H__ +#define __SPI_FLASH_DXE_H__ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#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/SpiFlashDx= e/SpiFlashDxe.inf b/Silicon/StarFive/JH7110Pkg/Driver/SpiFvbServicesDxe/Spi= FlashDxe/SpiFlashDxe.inf new file mode 100644 index 000000000000..3ca429fdc2dd --- /dev/null +++ b/Silicon/StarFive/JH7110Pkg/Driver/SpiFvbServicesDxe/SpiFlashDxe/SpiFl= ashDxe.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 =3D 0x00010005 + BASE_NAME =3D SpiFlashDxe + FILE_GUID =3D D3DF07BE-3810-4521-89EF-C4E22E0B2484 + MODULE_TYPE =3D DXE_RUNTIME_DRIVER + VERSION_STRING =3D 1.0 + ENTRY_POINT =3D 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/St= arFive/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.=
+ * + * SPDX-License-Identifier: BSD-2-Clause-Patent + * + **/ + +#ifndef __SPI_MASTER_PROTOCOL_H__ +#define __SPI_MASTER_PROTOCOL_H__ + +#include + +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 =3D __OpCode, \ + .NBytes =3D 1, \ + } + +#define SPI_OP_ADDR(__NBytes, __Val) \ + { \ + .NBytes =3D __NBytes, \ + .Val =3D __Val, \ + } + +#define SPI_OP_NO_ADDR { } + +#define SPI_OP_DUMMY(__NBytes) \ + { \ + .NBytes =3D __NBytes, \ + } + +#define SPI_OP_NO_DUMMY { } + +#define SPI_OP_DATA_IN(__NBytes, __Buf) \ + { \ + .NBytes =3D __NBytes, \ + .Buf.In =3D __Buf, \ + } + +#define SPI_OP_DATA_OUT(__NBytes, __Buf) \ + { \ + .NBytes =3D __NBytes, \ + .Buf.Out =3D __Buf, \ + } + +#define SPI_OP_NO_DATA { } + +#define SPI_OP(__Cmd, __Addr, __Dummy, __Data) \ + { \ + .Cmd =3D __Cmd, \ + .Addr =3D __Addr, \ + .Dummy =3D __Dummy, \ + .Data =3D __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/Silic= on/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.=
+ * + * SPDX-License-Identifier: BSD-2-Clause-Patent + * + **/ + +#ifndef __SPI_FLASH_PROTOCOL_H__ +#define __SPI_FLASH_PROTOCOL_H__ + +#include +#include + +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__ --=20 2.34.1 -=3D-=3D-=3D-=3D-=3D-=3D-=3D-=3D-=3D-=3D-=3D- Groups.io Links: You receive all messages sent to this group. View/Reply Online (#110176): https://edk2.groups.io/g/devel/message/110176 Mute This Topic: https://groups.io/mt/102214529/7686176 Group Owner: devel+owner@edk2.groups.io Unsubscribe: https://edk2.groups.io/g/devel/unsub [rebecca@openfw.io] -=3D-=3D-=3D-=3D-=3D-=3D-=3D-=3D-=3D-=3D-=3D-