From: caiyuqing379 <202235273@mail.sdu.edu.cn>
This driver implements Sophgo SDHCI controller, which provides
the necessary interfaces for handling communication and data
transfer with SD cards.
Signed-off-by: caiyuqing379 <202235273@mail.sdu.edu.cn>
Co-authored-by: USER0FISH <libing1202@outlook.com>
Cc: dahogn <dahogn@hotmail.com>
Cc: meng-cz <mengcz1126@gmail.com>
Cc: yli147 <yong.li@intel.com>
Cc: ChaiEvan <evan.chai@intel.com>
Cc: Sunil V L <sunilvl@ventanamicro.com>
Cc: Leif Lindholm <quic_llindhol@quicinc.com>
---
.../SG2042Pkg/Drivers/SdHostDxe/SdHostDxe.inf | 47 +
.../SG2042Pkg/Drivers/SdHostDxe/SdHci.h | 309 ++++++
.../SG2042Pkg/Drivers/SdHostDxe/SdHci.c | 929 ++++++++++++++++++
.../SG2042Pkg/Drivers/SdHostDxe/SdHostDxe.c | 450 +++++++++
4 files changed, 1735 insertions(+)
create mode 100644 Silicon/Sophgo/SG2042Pkg/Drivers/SdHostDxe/SdHostDxe.inf
create mode 100644 Silicon/Sophgo/SG2042Pkg/Drivers/SdHostDxe/SdHci.h
create mode 100755 Silicon/Sophgo/SG2042Pkg/Drivers/SdHostDxe/SdHci.c
create mode 100644 Silicon/Sophgo/SG2042Pkg/Drivers/SdHostDxe/SdHostDxe.c
diff --git a/Silicon/Sophgo/SG2042Pkg/Drivers/SdHostDxe/SdHostDxe.inf b/Silicon/Sophgo/SG2042Pkg/Drivers/SdHostDxe/SdHostDxe.inf
new file mode 100644
index 000000000000..f4f51d8fde74
--- /dev/null
+++ b/Silicon/Sophgo/SG2042Pkg/Drivers/SdHostDxe/SdHostDxe.inf
@@ -0,0 +1,47 @@
+## @file
+# Component description file for the SD Host Controller DXE driver module.
+#
+# Copyright (c) 2019, ARM Limited. All rights reserved.
+# Copyright (c) 2017, Andrei Warkentin <andrey.warkentin@gmail.com>
+# Copyright (c) Microsoft Corporation. All rights reserved.
+# Copyright (c) 2023, Academy of Intelligent Innovation, Shandong Universiy, China.P.R. All rights reserved.<BR>
+# SPDX-License-Identifier: BSD-2-Clause-Patent
+#
+#
+##
+
+[Defines]
+ INF_VERSION = 0x0001001A
+ BASE_NAME = SdHostDxe
+ FILE_GUID = 11322596-DD4F-47FA-9E6C-CE787E11E4B1
+ MODULE_TYPE = UEFI_DRIVER
+ VERSION_STRING = 1.0
+ ENTRY_POINT = SdHostInitialize
+
+[Sources]
+ SdHci.c
+ SdHci.h
+ SdHostDxe.c
+
+[Packages]
+ EmbeddedPkg/EmbeddedPkg.dec
+ MdePkg/MdePkg.dec
+ MdeModulePkg/MdeModulePkg.dec
+ Silicon/Sophgo/SG2042Pkg/SG2042Pkg.dec
+
+[LibraryClasses]
+ BaseLib
+ DebugLib
+ IoLib
+ MemoryAllocationLib
+ UefiBootServicesTableLib
+ UefiDriverEntryPoint
+ UefiLib
+ UefiRuntimeServicesTableLib
+
+[Protocols]
+ gSophgoMmcHostProtocolGuid ## PRODUCES
+
+[FixedPcd]
+ gSophgoSG2042PlatformPkgTokenSpaceGuid.PcdSG2042SDIOBase ## CONSUMES
+ gSophgoSG2042PlatformPkgTokenSpaceGuid.PcdForceNoMMU ## CONSUMES
diff --git a/Silicon/Sophgo/SG2042Pkg/Drivers/SdHostDxe/SdHci.h b/Silicon/Sophgo/SG2042Pkg/Drivers/SdHostDxe/SdHci.h
new file mode 100644
index 000000000000..d9a9c88674e6
--- /dev/null
+++ b/Silicon/Sophgo/SG2042Pkg/Drivers/SdHostDxe/SdHci.h
@@ -0,0 +1,309 @@
+/** @file
+ The header file that provides definitions and function declarations
+ related to the SD Host Controller Interface (SDHCI) for SD card host controllers.
+
+ Copyright (c) 2016-2017, ARM Limited and Contributors. All rights reserved.
+ Copyright (c) 2023, Academy of Intelligent Innovation, Shandong Universiy, China.P.R. All rights reserved.<BR>
+ SPDX-License-Identifier: BSD-3-Clause
+
+**/
+
+#ifndef _SD_HCI_H_
+#define _SD_HCI_H_
+
+#define SDIO_BASE (FixedPcdGet64(PcdSG2042SDIOBase))
+#define SDHCI_DMA_ADDRESS 0x00
+#define SDHCI_BLOCK_SIZE 0x04
+#define SDHCI_MAKE_BLKSZ(dma, blksz) ((((dma) & 0x7) << 12) | ((blksz) & 0xFFF))
+#define SDHCI_BLOCK_COUNT 0x06
+#define SDHCI_ARGUMENT 0x08
+#define SDHCI_TRANSFER_MODE 0x0C
+#define SDHCI_TRNS_DMA BIT0
+#define SDHCI_TRNS_BLK_CNT_EN BIT1
+#define SDHCI_TRNS_ACMD12 BIT2
+#define SDHCI_TRNS_READ BIT4
+#define SDHCI_TRNS_MULTI BIT5
+#define SDHCI_TRNS_RESP_INT BIT8
+#define SDHCI_COMMAND 0x0E
+#define SDHCI_CMD_RESP_MASK 0x03
+#define SDHCI_CMD_CRC 0x08
+#define SDHCI_CMD_INDEX 0x10
+#define SDHCI_CMD_DATA 0x20
+#define SDHCI_CMD_ABORTCMD 0xC0
+#define SDHCI_CMD_RESP_NONE 0x00
+#define SDHCI_CMD_RESP_LONG 0x01
+#define SDHCI_CMD_RESP_SHORT 0x02
+#define SDHCI_CMD_RESP_SHORT_BUSY 0x03
+#define SDHCI_MAKE_CMD(c, f) ((((c) & 0xff) << 8) | ((f) & 0xff))
+#define SDHCI_RESPONSE_01 0x10
+#define SDHCI_RESPONSE_23 0x14
+#define SDHCI_RESPONSE_45 0x18
+#define SDHCI_RESPONSE_67 0x1C
+#define SDHCI_PSTATE 0x24
+#define SDHCI_CMD_INHIBIT BIT0
+#define SDHCI_CMD_INHIBIT_DAT BIT1
+#define SDHCI_BUF_WR_ENABLE BIT10
+#define SDHCI_BUF_RD_ENABLE BIT11
+#define SDHCI_CARD_INSERTED BIT16
+#define SDHCI_HOST_CONTROL 0x28
+#define SDHCI_DAT_XFER_WIDTH BIT1
+#define SDHCI_EXT_DAT_XFER BIT5
+#define SDHCI_CTRL_DMA_MASK 0x18
+#define SDHCI_CTRL_SDMA 0x00
+#define SDHCI_PWR_CONTROL 0x29
+#define SDHCI_BUS_VOL_VDD1_1_8V 0xC
+#define SDHCI_BUS_VOL_VDD1_3_0V 0xE
+#define SDHCI_BUF_DATA_R 0x20
+#define SDHCI_BLOCK_GAP_CONTROL 0x2A
+#define SDHCI_CLK_CTRL 0x2C
+#define SDHCI_TOUT_CTRL 0x2E
+#define SDHCI_SOFTWARE_RESET 0x2F
+#define SDHCI_RESET_CMD 0x02
+#define SDHCI_RESET_DATA 0x04
+#define SDHCI_INT_STATUS 0x30
+#define SDHCI_ERR_INT_STATUS 0x32
+#define SDHCI_INT_CMD_COMPLETE BIT0
+#define SDHCI_INT_XFER_COMPLETE BIT1
+#define SDHCI_INT_DMA_END BIT3
+#define SDHCI_INT_BUF_WR_READY BIT4
+#define SDHCI_INT_BUF_RD_READY BIT5
+#define SDHCI_INT_ERROR BIT15
+#define SDHCI_INT_STATUS_EN 0x34
+#define SDHCI_ERR_INT_STATUS_EN 0x36
+#define SDHCI_INT_CMD_COMPLETE_EN BIT0
+#define SDHCI_INT_XFER_COMPLETE_EN BIT1
+#define SDHCI_INT_DMA_END_EN BIT3
+#define SDHCI_INT_CARD_INSERTION_EN BIT6
+#define SDHCI_INT_ERROR_EN BIT15
+#define SDHCI_SIGNAL_ENABLE 0x38
+#define SDHCI_HOST_CONTROL2 0x3E
+#define SDHCI_HOST_VER4_ENABLE BIT12
+#define SDHCI_CAPABILITIES1 0x40
+#define SDHCI_CAPABILITIES2 0x44
+#define SDHCI_ADMA_SA_LOW 0x58
+#define SDHCI_ADMA_SA_HIGH 0x5C
+#define SDHCI_HOST_CNTRL_VERS 0xFE
+#define SDHCI_UHS_2_TIMER_CNTRL 0xC2
+
+#define P_VENDOR_SPECIFIC_AREA 0xE8
+#define P_VENDOR2_SPECIFIC_AREA 0xEA
+#define VENDOR_SD_CTRL 0x2C
+
+#define SDHCI_PHY_R_OFFSET 0x300
+
+#define SDHCI_P_PHY_CNFG (SDHCI_PHY_R_OFFSET + 0x00)
+#define SDHCI_P_CMDPAD_CNFG (SDHCI_PHY_R_OFFSET + 0x04)
+#define SDHCI_P_DATPAD_CNFG (SDHCI_PHY_R_OFFSET + 0x06)
+#define SDHCI_P_CLKPAD_CNFG (SDHCI_PHY_R_OFFSET + 0x08)
+#define SDHCI_P_STBPAD_CNFG (SDHCI_PHY_R_OFFSET + 0x0A)
+#define SDHCI_P_RSTNPAD_CNFG (SDHCI_PHY_R_OFFSET + 0x0C)
+#define SDHCI_P_PADTEST_CNFG (SDHCI_PHY_R_OFFSET + 0x0E)
+#define SDHCI_P_PADTEST_OUT (SDHCI_PHY_R_OFFSET + 0x10)
+#define SDHCI_P_PADTEST_IN (SDHCI_PHY_R_OFFSET + 0x12)
+#define SDHCI_P_COMMDL_CNFG (SDHCI_PHY_R_OFFSET + 0x1C)
+#define SDHCI_P_SDCLKDL_CNFG (SDHCI_PHY_R_OFFSET + 0x1D)
+#define SDHCI_P_SDCLKDL_DC (SDHCI_PHY_R_OFFSET + 0x1E)
+#define SDHCI_P_SMPLDL_CNFG (SDHCI_PHY_R_OFFSET + 0x20)
+#define SDHCI_P_ATDL_CNFG (SDHCI_PHY_R_OFFSET + 0x21)
+#define SDHCI_P_DLL_CTRL (SDHCI_PHY_R_OFFSET + 0x24)
+#define SDHCI_P_DLL_CNFG1 (SDHCI_PHY_R_OFFSET + 0x25)
+#define SDHCI_P_DLL_CNFG2 (SDHCI_PHY_R_OFFSET + 0x26)
+#define SDHCI_P_DLLDL_CNFG (SDHCI_PHY_R_OFFSET + 0x28)
+#define SDHCI_P_DLL_OFFST (SDHCI_PHY_R_OFFSET + 0x29)
+#define SDHCI_P_DLLMST_TSTDC (SDHCI_PHY_R_OFFSET + 0x2A)
+#define SDHCI_P_DLLLBT_CNFG (SDHCI_PHY_R_OFFSET + 0x2C)
+#define SDHCI_P_DLL_STATUS (SDHCI_PHY_R_OFFSET + 0x2E)
+#define SDHCI_P_DLLDBG_MLKDC (SDHCI_PHY_R_OFFSET + 0x30)
+#define SDHCI_P_DLLDBG_SLKDC (SDHCI_PHY_R_OFFSET + 0x32)
+
+#define PHY_CNFG_PHY_RSTN 0
+#define PHY_CNFG_PHY_PWRGOOD 1
+#define PHY_CNFG_PAD_SP 16
+#define PHY_CNFG_PAD_SP_MSK 0xf
+#define PHY_CNFG_PAD_SN 20
+#define PHY_CNFG_PAD_SN_MSK 0xf
+
+#define PAD_CNFG_RXSEL 0
+#define PAD_CNFG_RXSEL_MSK 0x7
+#define PAD_CNFG_WEAKPULL_EN 3
+#define PAD_CNFG_WEAKPULL_EN_MSK 0x3
+#define PAD_CNFG_TXSLEW_CTRL_P 5
+#define PAD_CNFG_TXSLEW_CTRL_P_MSK 0xf
+#define PAD_CNFG_TXSLEW_CTRL_N 9
+#define PAD_CNFG_TXSLEW_CTRL_N_MSK 0xf
+
+#define COMMDL_CNFG_DLSTEP_SEL 0
+#define COMMDL_CNFG_DLOUT_EN 1
+
+#define SDCLKDL_CNFG_EXTDLY_EN 0
+#define SDCLKDL_CNFG_BYPASS_EN 1
+#define SDCLKDL_CNFG_INPSEL_CNFG 2
+#define SDCLKDL_CNFG_INPSEL_CNFG_MSK 0x3
+#define SDCLKDL_CNFG_UPDATE_DC 4
+
+#define SMPLDL_CNFG_EXTDLY_EN 0
+#define SMPLDL_CNFG_BYPASS_EN 1
+#define SMPLDL_CNFG_INPSEL_CNFG 2
+#define SMPLDL_CNFG_INPSEL_CNFG_MSK 0x3
+#define SMPLDL_CNFG_INPSEL_OVERRIDE 4
+
+#define ATDL_CNFG_EXTDLY_EN 0
+#define ATDL_CNFG_BYPASS_EN 1
+#define ATDL_CNFG_INPSEL_CNFG 2
+#define ATDL_CNFG_INPSEL_CNFG_MSK 0x3
+
+#define SD_USE_PIO 0x1
+
+/**
+ card detect status
+ -1: haven't check the card detect register
+ 0 : no card detected
+ 1 : card detected
+**/
+#define SDCARD_STATUS_UNKNOWN (-1)
+#define SDCARD_STATUS_INSERTED (1)
+#define SDCARD_STATUS_NOT_INSERTED (0)
+
+typedef struct {
+ UINT32 CmdIdx;
+ UINT32 CmdArg;
+ UINT32 ResponseType;
+ UINT32 Response[4];
+} MMC_CMD;
+
+typedef struct {
+ UINTN RegBase;
+ UINTN VendorBase;
+ UINTN DescBase;
+ UINTN DescSize;
+ INT32 ClkRate;
+ INT32 BusWidth;
+ UINT32 Flags;
+ INT32 CardIn;
+} BM_SD_PARAMS;
+
+extern BM_SD_PARAMS BmParams;
+
+/**
+ SD card sends command.
+
+ @param[in] Idx Command ID.
+ @param[in] Arg Command argument.
+ @param[in] RespType Type of response data.
+ @param[out] Response Response data.
+
+ @retval EFI_SUCCESS The command was sent successfully.
+ @retval EFI_DEVICE_ERROR There was an error during the command transmission or response handling.
+ @retval EFI_TIMEOUT The command transmission or response handling timed out.
+
+**/
+EFI_STATUS
+EFIAPI
+BmSdSendCmd (
+ IN UINT32 Idx,
+ IN UINT32 Arg,
+ IN UINT32 RespType,
+ OUT UINT32 *Response
+ );
+
+/**
+ Detect the status of the SD card.
+
+ @return The status of the SD card:
+ - SDCARD_STATUS_INSERTED: The SD card is inserted.
+ - SDCARD_STATUS_NOT_INSERTED: The SD card is not inserted.
+ - SDCARD_STATUS_UNKNOWN: The status of the SD card is unknown.
+
+**/
+INT32
+BmSdCardDetect (
+ VOID
+ );
+
+/**
+ Set the input/output settings for the SD card.
+
+ @param[in] Clk The clock frequency for the SD card.
+ @param[in] Width The bus width for data transfer.
+
+ @retval EFI_SUCCESS The input/output settings were set successfully.
+ @retval EFI_UNSUPPORTED The specified bus width is not supported.
+
+**/
+EFI_STATUS
+BmSdSetIos (
+ IN UINT32 Clk,
+ IN UINT32 Width
+ );
+
+/**
+ Prepare the SD card for data transfer.
+ Set the number and size of data blocks before sending IO commands to the SD card.
+
+ @param[in] Lba Logical Block Address.
+ @param[in] Buf Buffer Address.
+ @param[in] Size Size of Data Blocks.
+
+ @retval EFI_SUCCESS The SD card was prepared successfully.
+ @retval Other An error occurred during the preparation of the SD card.
+
+**/
+EFI_STATUS
+BmSdPrepare (
+ IN INT32 Lba,
+ IN UINTN Buf,
+ IN UINTN Size
+ );
+
+/**
+ SD card sends command to read data blocks.
+
+ @param[in] Lba Logical Block Address.
+ @param[in] Buf Buffer Address.
+ @param[in] Size Size of Data Blocks.
+
+ @retval EFI_SUCCESS The command to read data blocks was sent successfully.
+ @retval EFI_TIMEOUT The command transmission or data transfer timed out.
+
+**/
+EFI_STATUS
+BmSdRead (
+ IN INT32 Lba,
+ IN UINT32* Buf,
+ IN UINTN Size
+ );
+
+/**
+ SD card sends commands to write data blocks.
+
+ @param[in] Lba Logical Block Address.
+ @param[in] Buf Buffer Address.
+ @param[in] Size Size of Data Blocks.
+
+ @retval EFI_SUCCESS The command to write data blocks was sent successfully.
+ @retval EFI_TIMEOUT The command transmission or data transfer timed out.
+
+**/
+EFI_STATUS
+BmSdWrite (
+ IN INT32 Lba,
+ IN UINT32* Buf,
+ IN UINTN Size
+ );
+
+/**
+ Initialize the SD card.
+
+ This function performs the initialization of the SD card hardware and settings.
+
+ @param[in] Flags Initialization flags.
+
+ @retval EFI_SUCCESS The SD card was initialized successfully.
+
+**/
+EFI_STATUS
+SdInit (
+ IN UINT32 flags
+ );
+
+#endif
diff --git a/Silicon/Sophgo/SG2042Pkg/Drivers/SdHostDxe/SdHci.c b/Silicon/Sophgo/SG2042Pkg/Drivers/SdHostDxe/SdHci.c
new file mode 100755
index 000000000000..efa9f6397a1e
--- /dev/null
+++ b/Silicon/Sophgo/SG2042Pkg/Drivers/SdHostDxe/SdHci.c
@@ -0,0 +1,929 @@
+/** @file
+ The implementation for handling SD card operations using the SD Host Controller Interface (SDHCI).
+
+ Copyright (c) 2016-2017, ARM Limited and Contributors. All rights reserved.
+ Copyright (c) 2023, Academy of Intelligent Innovation, Shandong Universiy, China.P.R. All rights reserved.<BR>
+ SPDX-License-Identifier: BSD-3-Clause
+
+**/
+
+#include <Uefi.h>
+#include <Base.h>
+#include <Library/BaseLib.h>
+#include <Library/MemoryAllocationLib.h>
+#include <Library/DebugLib.h>
+#include <Library/IoLib.h>
+#include <Library/PcdLib.h>
+#include <Library/UefiBootServicesTableLib.h>
+#include <Library/BaseMemoryLib.h>
+#include <Include/MmcHost.h>
+
+#include "SdHci.h"
+
+#define SDCARD_INIT_FREQ (200 * 1000)
+#define SDCARD_TRAN_FREQ (6 * 1000 * 1000)
+
+/**
+ Return the clock rate of SD card.
+
+ @retval the clock rate of SD card.
+
+**/
+INT32
+BmGetSdClk (
+ VOID
+ )
+{
+ return 100*1000*1000;
+}
+
+/**
+ SD card sends command with response block data.
+
+ @param Cmd Command sent by SD card.
+
+ @retval EFI_SUCCESS The command with response block data was sent successfully.
+ @retval EFI_DEVICE_ERROR There was an error during the command transmission or response handling.
+ @retval EFI_TIMEOUT The command transmission or response handling timed out.
+
+**/
+STATIC
+EFI_STATUS
+SdSendCmdWithData (
+ IN OUT MMC_CMD *Cmd
+ )
+{
+ UINTN Base;
+ UINT32 Mode;
+ UINT32 State;
+ UINT32 DmaAddr;
+ UINT32 Flags;
+ UINT32 Timeout;
+
+ Base = BmParams.RegBase;
+ Mode = 0;
+ Flags = 0;
+
+ // Make sure Cmd line is clear
+ while (1) {
+ if (!(MmioRead32 (Base + SDHCI_PSTATE) & SDHCI_CMD_INHIBIT))
+ break;
+ }
+
+ switch (Cmd->CmdIdx) {
+ case MMC_CMD17:
+ case MMC_CMD18:
+ case MMC_ACMD51:
+ Mode = SDHCI_TRNS_BLK_CNT_EN | SDHCI_TRNS_MULTI | SDHCI_TRNS_READ;
+ if (!(BmParams.Flags & SD_USE_PIO))
+ Mode |= SDHCI_TRNS_DMA;
+ break;
+ case MMC_CMD24:
+ case MMC_CMD25:
+ Mode = (SDHCI_TRNS_BLK_CNT_EN | SDHCI_TRNS_MULTI) & ~SDHCI_TRNS_READ;
+ if (!(BmParams.Flags & SD_USE_PIO))
+ Mode |= SDHCI_TRNS_DMA;
+ break;
+ default:
+ ASSERT(0);
+ }
+
+ MmioWrite16 (Base + SDHCI_TRANSFER_MODE, Mode);
+ MmioWrite32 (Base + SDHCI_ARGUMENT, Cmd->CmdArg);
+
+ // set Cmd Flags
+ if (Cmd->CmdIdx == MMC_CMD0)
+ Flags |= SDHCI_CMD_RESP_NONE;
+ else {
+ if (Cmd->ResponseType & MMC_RSP_136)
+ Flags |= SDHCI_CMD_RESP_LONG;
+ else
+ Flags |= SDHCI_CMD_RESP_SHORT;
+ if (Cmd->ResponseType & MMC_RSP_CRC)
+ Flags |= SDHCI_CMD_CRC;
+ if (Cmd->ResponseType & MMC_RSP_CMD_IDX)
+ Flags |= SDHCI_CMD_INDEX;
+ }
+
+ Flags |= SDHCI_CMD_DATA;
+
+ // issue the Cmd
+ MmioWrite16 (Base + SDHCI_COMMAND, SDHCI_MAKE_CMD(Cmd->CmdIdx, Flags));
+
+ // check Cmd complete if necessary
+ if ((MmioRead16 (Base + SDHCI_TRANSFER_MODE) & SDHCI_TRNS_RESP_INT) == 0) {
+ Timeout = 100000;
+ while (1) {
+ State = MmioRead16 (Base + SDHCI_INT_STATUS);
+ if (State & SDHCI_INT_ERROR) {
+ DEBUG ((DEBUG_ERROR, "%a: interrupt error: 0x%x 0x%x\n", __func__, MmioRead16 (Base + SDHCI_INT_STATUS),
+ MmioRead16 (Base + SDHCI_ERR_INT_STATUS)));
+ return EFI_DEVICE_ERROR;
+ }
+ if (State & SDHCI_INT_CMD_COMPLETE) {
+ MmioWrite16 (Base + SDHCI_INT_STATUS, State | SDHCI_INT_CMD_COMPLETE);
+ break;
+ }
+
+ gBS->Stall (1);
+ if (!Timeout--) {
+ DEBUG ((DEBUG_ERROR, "%a: Timeout!\n", __func__));
+ return EFI_TIMEOUT;
+ }
+ }
+
+ // get Cmd respond
+ if (Flags != SDHCI_CMD_RESP_NONE)
+ Cmd->Response[0] = MmioRead32 (Base + SDHCI_RESPONSE_01);
+ if (Flags & SDHCI_CMD_RESP_LONG) {
+ Cmd->Response[1] = MmioRead32 (Base + SDHCI_RESPONSE_23);
+ Cmd->Response[2] = MmioRead32 (Base + SDHCI_RESPONSE_45);
+ Cmd->Response[3] = MmioRead32 (Base + SDHCI_RESPONSE_67);
+ }
+ }
+
+ // check dma/transfer complete
+ if (!(BmParams.Flags & SD_USE_PIO)) {
+ while (1) {
+ State = MmioRead16 (Base + SDHCI_INT_STATUS);
+ if (State & SDHCI_INT_ERROR) {
+ DEBUG ((DEBUG_ERROR, "%a: interrupt error: 0x%x 0x%x\n", __func__, MmioRead16 (Base + SDHCI_INT_STATUS),
+ MmioRead16 (Base + SDHCI_ERR_INT_STATUS)));
+ return EFI_DEVICE_ERROR;
+ }
+
+ if (State & SDHCI_INT_XFER_COMPLETE) {
+ MmioWrite16 (Base + SDHCI_INT_STATUS, State);
+ break;
+ }
+
+ if (State & SDHCI_INT_DMA_END) {
+ MmioWrite16 (Base + SDHCI_INT_STATUS, State);
+ if (MmioRead16 (Base + SDHCI_HOST_CONTROL2) & SDHCI_HOST_VER4_ENABLE) {
+ DmaAddr = MmioRead32 (Base + SDHCI_ADMA_SA_LOW);
+ MmioWrite32 (Base + SDHCI_ADMA_SA_LOW, DmaAddr);
+ MmioWrite32 (Base + SDHCI_ADMA_SA_HIGH, 0);
+ } else {
+ DmaAddr = MmioRead32 (Base + SDHCI_DMA_ADDRESS);
+ MmioWrite32 (Base + SDHCI_DMA_ADDRESS, DmaAddr);
+ }
+ }
+
+ }
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+ SD card sends command without response block data.
+
+ @param Cmd Command sent by SD card.
+
+ @retval EFI_SUCCESS The command without response block data was sent successfully.
+ @retval EFI_DEVICE_ERROR There was an error during the command transmission or response handling.
+ @retval EFI_TIMEOUT The command transmission or response handling timed out.
+
+**/
+STATIC
+EFI_STATUS
+SdSendCmdWithoutData (
+ IN OUT MMC_CMD *Cmd
+ )
+{
+ UINTN Base;
+ UINT32 State;
+ UINT32 Flags;
+ UINT32 Timeout;
+
+ Base = BmParams.RegBase;
+ Flags = 0x0;
+ Timeout = 10000;
+
+ // make sure Cmd line is clear
+ while (1) {
+ if (!(MmioRead32 (Base + SDHCI_PSTATE) & SDHCI_CMD_INHIBIT))
+ break;
+ }
+
+ // set Cmd Flags
+ if (Cmd->CmdIdx == MMC_CMD0)
+ Flags |= SDHCI_CMD_RESP_NONE;
+ else if (Cmd->CmdIdx == MMC_CMD1)
+ Flags |= SDHCI_CMD_RESP_SHORT;
+ else if (Cmd->CmdIdx == MMC_ACMD41)
+ Flags |= SDHCI_CMD_RESP_SHORT;
+ else {
+ if (Cmd->ResponseType & MMC_RSP_136)
+ Flags |= SDHCI_CMD_RESP_LONG;
+ else
+ Flags |= SDHCI_CMD_RESP_SHORT;
+ if (Cmd->ResponseType & MMC_RSP_CRC)
+ Flags |= SDHCI_CMD_CRC;
+ if (Cmd->ResponseType & MMC_RSP_CMD_IDX)
+ Flags |= SDHCI_CMD_INDEX;
+ }
+
+ // make sure dat line is clear if necessary
+ if (Flags != SDHCI_CMD_RESP_NONE) {
+ while (1) {
+ if (!(MmioRead32 (Base + SDHCI_PSTATE) & SDHCI_CMD_INHIBIT_DAT))
+ break;
+ }
+ }
+
+ // issue the Cmd
+ MmioWrite32 (Base + SDHCI_ARGUMENT, Cmd->CmdArg);
+ MmioWrite16 (Base + SDHCI_COMMAND, SDHCI_MAKE_CMD(Cmd->CmdIdx, Flags));
+
+ // check Cmd complete
+ Timeout = 100000;
+ while (1) {
+ State = MmioRead16 (Base + SDHCI_INT_STATUS);
+ if (State & SDHCI_INT_ERROR) {
+ DEBUG ((DEBUG_ERROR, "%a: interrupt error: 0x%x 0x%x\n", __func__, MmioRead16 (Base + SDHCI_INT_STATUS),
+ MmioRead16 (Base + SDHCI_ERR_INT_STATUS)));
+ return EFI_DEVICE_ERROR;
+ }
+ if (State & SDHCI_INT_CMD_COMPLETE) {
+ MmioWrite16 (Base + SDHCI_INT_STATUS, State | SDHCI_INT_CMD_COMPLETE);
+ break;
+ }
+
+ gBS->Stall (1);
+ if (!Timeout--) {
+ DEBUG ((DEBUG_ERROR, "%a: Timeout!\n", __func__));
+ return EFI_TIMEOUT;
+ }
+ }
+
+ // get Cmd respond
+ if (!(Flags & SDHCI_CMD_RESP_NONE))
+ Cmd->Response[0] = MmioRead32 (Base + SDHCI_RESPONSE_01);
+ if (Flags & SDHCI_CMD_RESP_LONG) {
+ Cmd->Response[1] = MmioRead32 (Base + SDHCI_RESPONSE_23);
+ Cmd->Response[2] = MmioRead32 (Base + SDHCI_RESPONSE_45);
+ Cmd->Response[3] = MmioRead32 (Base + SDHCI_RESPONSE_67);
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+ SD card sends command.
+
+ @param[in] Idx Command ID.
+ @param[in] Arg Command argument.
+ @param[in] RespType Type of response data.
+ @param[out] Response Response data.
+
+ @retval EFI_SUCCESS The command was sent successfully.
+ @retval EFI_DEVICE_ERROR There was an error during the command transmission or response handling.
+ @retval EFI_TIMEOUT The command transmission or response handling timed out.
+
+**/
+EFI_STATUS
+EFIAPI
+BmSdSendCmd (
+ IN UINT32 Idx,
+ IN UINT32 Arg,
+ IN UINT32 RespType,
+ OUT UINT32 *Response
+ )
+{
+ EFI_STATUS Status;
+ MMC_CMD Cmd;
+
+ // DEBUG ((DEBUG_INFO, "%a: SDHCI Cmd, Idx=%d, Arg=0x%x, ResponseType=0x%x\n", __func__, Idx, Arg, RespType));
+
+ ZeroMem(&Cmd,sizeof(MMC_CMD));
+
+ Cmd.CmdIdx = Idx;
+ Cmd.CmdArg = Arg;
+ Cmd.ResponseType = RespType;
+
+ switch (Cmd.CmdIdx) {
+ case MMC_CMD17:
+ case MMC_CMD18:
+ case MMC_CMD24:
+ case MMC_CMD25:
+ case MMC_ACMD51:
+ Status = SdSendCmdWithData(&Cmd);
+ break;
+ default:
+ Status = SdSendCmdWithoutData(&Cmd);
+ }
+
+ if ((Status == EFI_SUCCESS) && (Response != NULL)) {
+ for (INT32 I = 0; I < 4; I++) {
+ *Response = Cmd.Response[I];
+ Response++;
+ }
+ }
+ return Status;
+}
+
+/**
+ Set clock frequency of SD card.
+
+ @param[in] Clk The clock frequency of SD card.
+
+**/
+VOID
+SdSetClk (
+ IN INT32 Clk
+ )
+{
+ INT32 I;
+ INT32 Div;
+ UINTN Base;
+
+ ASSERT (Clk > 0);
+
+ if (BmParams.ClkRate <= Clk) {
+ Div = 0;
+ } else {
+ for (Div = 0x1; Div < 0xFF; Div++) {
+ if (BmParams.ClkRate / (2 * Div) <= Clk)
+ break;
+ }
+ }
+ ASSERT (Div <= 0xFF);
+
+ Base = BmParams.RegBase;
+ if (MmioRead16 (Base + SDHCI_HOST_CONTROL2) & (1 << 15)) {
+ //verbose("Use SDCLK Preset Value\n");
+ } else {
+ //verbose("Set SDCLK by driver. Div=0x%x(%d)\n", Div, Div);
+ MmioWrite16 (Base + SDHCI_CLK_CTRL,
+ MmioRead16 (Base + SDHCI_CLK_CTRL) & ~0x9); // disable INTERNAL_CLK_EN and PLL_ENABLE
+ MmioWrite16 (Base + SDHCI_CLK_CTRL,
+ (MmioRead16 (Base + SDHCI_CLK_CTRL) & 0xDF) | Div << 8); // set Clk Div
+ MmioWrite16 (Base + SDHCI_CLK_CTRL,
+ MmioRead16 (Base + SDHCI_CLK_CTRL) | 0x1); // set INTERNAL_CLK_EN
+
+ for (I = 0; I <= 150000; I += 100) {
+ if (MmioRead16 (Base + SDHCI_CLK_CTRL) & 0x2)
+ break;
+ gBS->Stall (100);
+ }
+
+ if (I > 150000) {
+ DEBUG ((DEBUG_ERROR, "%a: SD INTERNAL_CLK_EN setting FAILED!\n", __func__));
+ ASSERT(0);
+ }
+
+ MmioWrite16 (Base + SDHCI_CLK_CTRL, MmioRead16 (Base + SDHCI_CLK_CTRL) | 0x8); // set PLL_ENABLE
+
+ for (I = 0; I <= 150000; I += 100) {
+ if (MmioRead16 (Base + SDHCI_CLK_CTRL) & 0x2)
+ return;
+ gBS->Stall (100);
+ }
+ }
+
+ DEBUG ((DEBUG_INFO, "%a: SD PLL setting FAILED!\n", __func__));
+}
+
+/**
+ Change clock frequency of SD card.
+
+ @param[in] Clk The clock frequency of SD card.
+
+**/
+VOID
+SdChangeClk (
+ IN INT32 Clk
+ )
+{
+ INT32 I;
+ INT32 Div;
+ UINTN Base;
+
+ ASSERT (Clk > 0);
+
+ if (BmParams.ClkRate <= Clk) {
+ Div = 0;
+ } else {
+ for (Div = 0x1; Div < 0xFF; Div++) {
+ if (BmParams.ClkRate / (2 * Div) <= Clk)
+ break;
+ }
+ }
+ ASSERT (Div <= 0xFF);
+
+ Base = BmParams.RegBase;
+
+ MmioWrite16 (Base + SDHCI_CLK_CTRL,
+ MmioRead16 (Base + SDHCI_CLK_CTRL) & ~(0x1 << 2)); // stop SD clock
+
+ MmioWrite16 (Base + SDHCI_CLK_CTRL,
+ MmioRead16 (Base + SDHCI_CLK_CTRL) & ~0x8); // disable PLL_ENABLE
+
+ if (MmioRead16 (Base + SDHCI_HOST_CONTROL2) & (1 << 15)) {
+ MmioWrite16 (Base + SDHCI_HOST_CONTROL2,
+ MmioRead16 (Base + SDHCI_HOST_CONTROL2) & ~0x7); // clr UHS_MODE_SEL
+ } else {
+ MmioWrite16 (Base + SDHCI_CLK_CTRL,
+ (MmioRead16 (Base + SDHCI_CLK_CTRL) & 0xDF) | Div << 8); // set Clk Div
+ MmioWrite16 (Base + SDHCI_CLK_CTRL,
+ MmioRead16 (Base + SDHCI_CLK_CTRL) & ~(0x1 << 5)); // CLK_GEN_SELECT
+ }
+
+ MmioWrite16 (Base + SDHCI_CLK_CTRL,
+ MmioRead16 (Base + SDHCI_CLK_CTRL) | 0xc); // enable PLL_ENABLE
+
+ for (I = 0; I <= 150000; I += 100) {
+ if (MmioRead16 (Base + SDHCI_CLK_CTRL) & 0x2)
+ return;
+ gBS->Stall (100);
+ }
+
+ DEBUG ((DEBUG_INFO, "%a: SD PLL setting FAILED!\n", __func__));
+}
+
+/**
+ Detect the status of the SD card.
+
+ @return The status of the SD card:
+ - SDCARD_STATUS_INSERTED: The SD card is inserted.
+ - SDCARD_STATUS_NOT_INSERTED: The SD card is not inserted.
+ - SDCARD_STATUS_UNKNOWN: The status of the SD card is unknown.
+
+**/
+INT32
+BmSdCardDetect (
+ VOID
+ )
+{
+ UINTN Base;
+ UINTN Reg;
+
+ Base = BmParams.RegBase;
+
+ if (BmParams.CardIn != SDCARD_STATUS_UNKNOWN)
+ return BmParams.CardIn;
+
+ MmioWrite16 (Base + SDHCI_INT_STATUS_EN,
+ MmioRead16 (Base + SDHCI_INT_STATUS_EN) | SDHCI_INT_CARD_INSERTION_EN);
+
+ Reg = MmioRead32 (Base + SDHCI_PSTATE);
+
+ if (Reg & SDHCI_CARD_INSERTED)
+ BmParams.CardIn = SDCARD_STATUS_INSERTED;
+ else
+ BmParams.CardIn = SDCARD_STATUS_NOT_INSERTED;
+
+ return BmParams.CardIn;
+}
+
+/**
+ SD card hardware initialization.
+
+**/
+STATIC
+VOID
+SdHwInit (
+ VOID
+ )
+{
+ UINTN Base;
+
+ Base = BmParams.RegBase;
+ BmParams.VendorBase = Base + (MmioRead16 (Base + P_VENDOR_SPECIFIC_AREA) & ((1 << 12) - 1));
+
+ // deasset reset of phy
+ MmioWrite32 (Base + SDHCI_P_PHY_CNFG, MmioRead32 (Base + SDHCI_P_PHY_CNFG) | (1 << PHY_CNFG_PHY_RSTN));
+
+ // reset data & Cmd
+ MmioWrite8 (Base + SDHCI_SOFTWARE_RESET, 0x6);
+
+ // init common parameters
+ MmioWrite8 (Base + SDHCI_PWR_CONTROL, (0x7 << 1));
+ MmioWrite8 (Base + SDHCI_TOUT_CTRL, 0xe); // for TMCLK 50Khz
+ MmioWrite16 (Base + SDHCI_HOST_CONTROL2,
+ MmioRead16 (Base + SDHCI_HOST_CONTROL2) | 1 << 11); // set cmd23 support
+ MmioWrite16 (Base + SDHCI_CLK_CTRL, MmioRead16 (Base + SDHCI_CLK_CTRL) & ~(0x1 << 5)); // divided clock Mode
+
+ // set host version 4 parameters
+ MmioWrite16 (Base + SDHCI_HOST_CONTROL2,
+ MmioRead16 (Base + SDHCI_HOST_CONTROL2) | (1 << 12)); // set HOST_VER4_ENABLE
+ if (MmioRead32 (Base + SDHCI_CAPABILITIES1) & (0x1 << 27)) {
+ MmioWrite16 (Base + SDHCI_HOST_CONTROL2,
+ MmioRead16 (Base + SDHCI_HOST_CONTROL2) | 0x1 << 13); // set 64bit addressing
+ }
+
+ // if support asynchronous int
+ if (MmioRead32 (Base + SDHCI_CAPABILITIES1) & (0x1 << 29))
+ MmioWrite16 (Base + SDHCI_HOST_CONTROL2,
+ MmioRead16 (Base + SDHCI_HOST_CONTROL2) | (0x1 << 14)); // enable async int
+ // give some time to power down card
+ gBS->Stall (20000);
+
+ MmioWrite16 (Base + SDHCI_HOST_CONTROL2,
+ MmioRead16 (Base + SDHCI_HOST_CONTROL2) & ~(0x1 << 8)); // clr UHS2_IF_ENABLE
+ MmioWrite8 (Base + SDHCI_PWR_CONTROL,
+ MmioRead8 (Base + SDHCI_PWR_CONTROL) | 0x1); // set SD_BUS_PWR_VDD1
+ MmioWrite16 (Base + SDHCI_HOST_CONTROL2,
+ MmioRead16 (Base + SDHCI_HOST_CONTROL2) & ~0x7); // clr UHS_MODE_SEL
+ SdSetClk (SDCARD_INIT_FREQ);
+ gBS->Stall (50000);
+
+ MmioWrite16 (Base + SDHCI_CLK_CTRL,
+ MmioRead16 (Base + SDHCI_CLK_CTRL) | (0x1 << 2)); // supply SD clock
+ gBS->Stall (400); // wait for voltage ramp up time at least 74 cycle, 400us is 80 cycles for 200Khz
+
+ MmioWrite16 (Base + SDHCI_INT_STATUS, MmioRead16 (Base + SDHCI_INT_STATUS) | (0x1 << 6));
+
+ // we enable all interrupt Status here for testing
+ MmioWrite16 (Base + SDHCI_INT_STATUS_EN, MmioRead16 (Base + SDHCI_INT_STATUS_EN) | 0xFFFF);
+ MmioWrite16 (Base + SDHCI_ERR_INT_STATUS_EN, MmioRead16 (Base + SDHCI_ERR_INT_STATUS_EN) | 0xFFFF);
+
+ //verbose("SD init done\n");
+}
+
+/**
+ Set the input/output settings for the SD card.
+
+ @param[in] Clk The clock frequency for the SD card.
+ @param[in] Width The bus width for data transfer.
+
+ @retval EFI_SUCCESS The input/output settings were set successfully.
+ @retval EFI_UNSUPPORTED The specified bus width is not supported.
+
+**/
+EFI_STATUS
+BmSdSetIos (
+ IN UINT32 Clk,
+ IN UINT32 Width
+ )
+{
+ switch (Width) {
+ case MMC_BUS_WIDTH_1:
+ MmioWrite8 (BmParams.RegBase + SDHCI_HOST_CONTROL,
+ MmioRead8 (BmParams.RegBase + SDHCI_HOST_CONTROL) &
+ ~SDHCI_DAT_XFER_WIDTH);
+ break;
+ case MMC_BUS_WIDTH_4:
+ MmioWrite8 (BmParams.RegBase + SDHCI_HOST_CONTROL,
+ MmioRead8 (BmParams.RegBase + SDHCI_HOST_CONTROL) |
+ SDHCI_DAT_XFER_WIDTH);
+ break;
+ default:
+ ASSERT (0);
+ }
+
+ SdChangeClk (Clk);
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Prepare the SD card for data transfer.
+ Set the number and size of data blocks before sending IO commands to the SD card.
+
+ @param[in] Lba Logical Block Address.
+ @param[in] Buf Buffer Address.
+ @param[in] Size Size of Data Blocks.
+
+ @retval EFI_SUCCESS The SD card was prepared successfully.
+ @retval Other An error occurred during the preparation of the SD card.
+
+**/
+EFI_STATUS
+BmSdPrepare (
+ IN INT32 Lba,
+ IN UINTN Buf,
+ IN UINTN Size
+ )
+{
+ UINTN LoadAddr;
+ UINTN Base;
+ UINT32 BlockCnt;
+ UINT32 BlockSize;
+ UINT8 Tmp;
+
+ LoadAddr = Buf;
+
+ if (Size >= MMC_BLOCK_SIZE) {
+ // CMD17, 18, 24, 25
+ // ASSERT (((LoadAddr & MMC_BLOCK_MASK) == 0) && ((Size % MMC_BLOCK_SIZE) == 0));
+ BlockSize = MMC_BLOCK_SIZE;
+ BlockCnt = Size / MMC_BLOCK_SIZE;
+ } else {
+ // ACMD51
+ ASSERT (((LoadAddr & 8) == 0) && ((Size % 8) == 0));
+ BlockSize = 8;
+ BlockCnt = Size / 8;
+ }
+
+ Base = BmParams.RegBase;
+
+ if (!(BmParams.Flags & SD_USE_PIO)) {
+ if (MmioRead16 (Base + SDHCI_HOST_CONTROL2) & SDHCI_HOST_VER4_ENABLE) {
+ MmioWrite32 (Base + SDHCI_ADMA_SA_LOW, LoadAddr);
+ MmioWrite32 (Base + SDHCI_ADMA_SA_HIGH, (LoadAddr >> 32));
+ MmioWrite32 (Base + SDHCI_DMA_ADDRESS, BlockCnt);
+ MmioWrite16 (Base + SDHCI_BLOCK_COUNT, 0);
+ } else {
+ ASSERT((LoadAddr >> 32) == 0);
+ MmioWrite32 (Base + SDHCI_DMA_ADDRESS, LoadAddr);
+ MmioWrite16 (Base + SDHCI_BLOCK_COUNT, BlockCnt);
+ }
+
+ // 512K bytes SDMA buffer boundary
+ MmioWrite16 (Base + SDHCI_BLOCK_SIZE, SDHCI_MAKE_BLKSZ(7, BlockSize));
+
+ // select SDMA
+ Tmp = MmioRead8 (Base + SDHCI_HOST_CONTROL);
+ Tmp &= ~SDHCI_CTRL_DMA_MASK;
+ Tmp |= SDHCI_CTRL_SDMA;
+ MmioWrite8 (Base + SDHCI_HOST_CONTROL, Tmp);
+ } else {
+ MmioWrite16 (Base + SDHCI_BLOCK_SIZE, BlockSize);
+ MmioWrite16 (Base + SDHCI_BLOCK_COUNT, BlockCnt);
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+ SD card sends command to read data blocks.
+
+ @param[in] Lba Logical Block Address.
+ @param[in] Buf Buffer Address.
+ @param[in] Size Size of Data Blocks.
+
+ @retval EFI_SUCCESS The command to read data blocks was sent successfully.
+ @retval EFI_TIMEOUT The command transmission or data transfer timed out.
+
+**/
+EFI_STATUS
+BmSdRead (
+ IN INT32 Lba,
+ IN UINT32* Buf,
+ IN UINTN Size
+ )
+{
+ UINT32 Timeout;
+ UINTN Base;
+ UINT32 *Data;
+ UINT32 BlockSize;
+ UINT32 BlockCnt;
+ UINT32 Status;
+
+ Timeout = 0;
+ Base = BmParams.RegBase;
+ Data = Buf;
+ BlockSize = 0;
+ BlockCnt = 0;
+ Status = 0;
+
+ if (BmParams.Flags & SD_USE_PIO) {
+ BlockSize = MmioRead16 (Base + SDHCI_BLOCK_SIZE);
+ BlockCnt = Size / BlockSize;
+ BlockSize /= 4;
+
+ for (INT32 I = 0; I < BlockCnt; ) {
+ Status = MmioRead16 (Base + SDHCI_INT_STATUS);
+ if ((Status & SDHCI_INT_BUF_RD_READY) &&
+ (MmioRead32 (Base + SDHCI_PSTATE) & SDHCI_BUF_RD_ENABLE)) {
+ MmioWrite16 (Base + SDHCI_INT_STATUS, SDHCI_INT_BUF_RD_READY);
+ for (INT32 j = 0; j < BlockSize; j++) {
+ *(Data++) = MmioRead32 (Base + SDHCI_BUF_DATA_R);
+ }
+
+ Timeout = 0;
+ I++;
+ } else {
+ gBS->Stall (1);
+ Timeout++;
+ }
+
+ if (Timeout >= 10000) {
+ DEBUG ((DEBUG_INFO, "%a: sdhci read data Timeout\n", __func__));
+ goto Timeout;
+ }
+ }
+
+ Timeout = 0;
+ while (1) {
+ Status = MmioRead16 (Base + SDHCI_INT_STATUS);
+ if (Status & SDHCI_INT_XFER_COMPLETE) {
+ MmioWrite16 (Base + SDHCI_INT_STATUS,
+ Status | SDHCI_INT_XFER_COMPLETE);
+
+ return EFI_SUCCESS;
+ } else {
+ gBS->Stall (1);
+ Timeout++;
+ }
+
+ if (Timeout >= 10000) {
+ DEBUG ((DEBUG_INFO, "%a:wait xfer complete Timeout\n", __func__));
+ goto Timeout;
+ }
+ }
+ } else {
+ return EFI_SUCCESS;
+ }
+
+Timeout:
+ return EFI_TIMEOUT;
+
+}
+
+/**
+ SD card sends commands to write data blocks.
+
+ @param[in] Lba Logical Block Address.
+ @param[in] Buf Buffer Address.
+ @param[in] Size Size of Data Blocks.
+
+ @retval EFI_SUCCESS The command to write data blocks was sent successfully.
+ @retval EFI_TIMEOUT The command transmission or data transfer timed out.
+
+**/
+EFI_STATUS
+BmSdWrite (
+ IN INT32 Lba,
+ IN UINT32* Buf,
+ IN UINTN Size
+ )
+{
+ UINT32 Timeout;
+ UINTN Base;
+ UINT32 *Data;
+ UINT32 BlockSize;
+ UINT32 BlockCnt;
+ UINT32 Status;
+
+ Timeout = 0;
+ Base = BmParams.RegBase;
+ Data = Buf;
+ BlockSize = 0;
+ BlockCnt = 0;
+ Status = 0;
+
+ if (BmParams.Flags & SD_USE_PIO) {
+ BlockSize = MmioRead16 (Base + SDHCI_BLOCK_SIZE);
+ BlockCnt = Size / BlockSize;
+ BlockSize /= 4;
+
+ for (INT32 j = 0; j < BlockSize; j++) {
+ MmioWrite32 (Base + SDHCI_BUF_DATA_R, *(Data++));
+ }
+
+ for (INT32 I = 0; I < BlockCnt-1; ) {
+ Status = MmioRead16 (Base + SDHCI_INT_STATUS);
+ if ((Status & SDHCI_INT_BUF_WR_READY) &&
+ (MmioRead32 (Base + SDHCI_PSTATE) &
+ SDHCI_BUF_WR_ENABLE)) {
+ MmioWrite16 (Base + SDHCI_INT_STATUS, SDHCI_INT_BUF_WR_READY);
+ for (INT32 j = 0; j < BlockSize; j++) {
+ MmioWrite32 (Base + SDHCI_BUF_DATA_R, *(Data++));
+ }
+
+ Timeout = 0;
+ I++;
+ } else {
+ gBS->Stall (1);
+ Timeout++;
+ }
+
+ if (Timeout >= 10000000) {
+ DEBUG ((DEBUG_INFO, "%a:sdhci write data Timeout\n", __func__));
+ goto Timeout;
+ }
+ }
+
+ Timeout = 0;
+ while (1) {
+ Status = MmioRead16 (Base + SDHCI_INT_STATUS);
+ if (Status & SDHCI_INT_XFER_COMPLETE) {
+ MmioWrite16 (Base + SDHCI_INT_STATUS,
+ Status | SDHCI_INT_XFER_COMPLETE);
+
+ return EFI_SUCCESS;
+ } else {
+ gBS->Stall (1);
+ Timeout++;
+ }
+
+ if (Timeout >= 10000) {
+ DEBUG ((DEBUG_INFO, "%a:wait xfer complete Timeout\n", __func__));
+ goto Timeout;
+ }
+ }
+ } else
+ return EFI_SUCCESS;
+
+Timeout:
+ return EFI_TIMEOUT;
+}
+
+/**
+ Initialize the SD PHY.
+
+ This function performs the initialization of the SD PHY hardware.
+
+**/
+VOID
+SdPhyInit (
+ VOID
+ )
+{
+ UINTN Base;
+ INT32 RetryCount;
+
+ Base = BmParams.RegBase;
+ RetryCount = 100;
+
+ // reset hardware
+ MmioWrite8 (Base + SDHCI_SOFTWARE_RESET, 0x7);
+ while (MmioRead8 (Base + SDHCI_SOFTWARE_RESET)) {
+ if (RetryCount-- > 0)
+ gBS->Stall (10000);
+ else
+ break;
+ }
+
+ // Wait for the PHY power on ready
+ RetryCount = 100;
+ while (!(MmioRead32 (Base + SDHCI_P_PHY_CNFG) & (1 << PHY_CNFG_PHY_PWRGOOD))) {
+ if (RetryCount-- > 0)
+ gBS->Stall (10000);
+ else
+ break;
+ }
+
+ // Asset reset of phy
+ MmioAnd32 (Base + SDHCI_P_PHY_CNFG, ~(1 << PHY_CNFG_PHY_RSTN));
+
+ // Set PAD_SN PAD_SP
+ MmioWrite32 (Base + SDHCI_P_PHY_CNFG,
+ (1 << PHY_CNFG_PHY_PWRGOOD) | (0x9 << PHY_CNFG_PAD_SP) | (0x8 << PHY_CNFG_PAD_SN));
+
+ // Set CMDPAD
+ MmioWrite16 (Base + SDHCI_P_CMDPAD_CNFG,
+ (0x2 << PAD_CNFG_RXSEL) | (1 << PAD_CNFG_WEAKPULL_EN) |
+ (0x3 << PAD_CNFG_TXSLEW_CTRL_P) | (0x2 << PAD_CNFG_TXSLEW_CTRL_N));
+
+ // Set DATAPAD
+ MmioWrite16 (Base + SDHCI_P_DATPAD_CNFG,
+ (0x2 << PAD_CNFG_RXSEL) | (1 << PAD_CNFG_WEAKPULL_EN) |
+ (0x3 << PAD_CNFG_TXSLEW_CTRL_P) | (0x2 << PAD_CNFG_TXSLEW_CTRL_N));
+
+ // Set CLKPAD
+ MmioWrite16 (Base + SDHCI_P_CLKPAD_CNFG,
+ (0x2 << PAD_CNFG_RXSEL) | (0x3 << PAD_CNFG_TXSLEW_CTRL_P) | (0x2 << PAD_CNFG_TXSLEW_CTRL_N));
+
+ // Set STB_PAD
+ MmioWrite16 (Base + SDHCI_P_STBPAD_CNFG,
+ (0x2 << PAD_CNFG_RXSEL) | (0x2 << PAD_CNFG_WEAKPULL_EN) |
+ (0x3 << PAD_CNFG_TXSLEW_CTRL_P) | (0x2 << PAD_CNFG_TXSLEW_CTRL_N));
+
+ // Set RSTPAD
+ MmioWrite16 (Base + SDHCI_P_RSTNPAD_CNFG,
+ (0x2 << PAD_CNFG_RXSEL) | (1 << PAD_CNFG_WEAKPULL_EN) |
+ (0x3 << PAD_CNFG_TXSLEW_CTRL_P) | (0x2 << PAD_CNFG_TXSLEW_CTRL_N));
+
+ // Set SDCLKDL_CNFG, EXTDLY_EN = 1, fix delay
+ MmioWrite8 (Base + SDHCI_P_SDCLKDL_CNFG, (1 << SDCLKDL_CNFG_EXTDLY_EN));
+
+ // Set SMPLDL_CNFG, Bypass
+ MmioWrite8 (Base + SDHCI_P_SMPLDL_CNFG, (1 << SMPLDL_CNFG_BYPASS_EN));
+
+ // Set ATDL_CNFG, tuning Clk not use for init
+ MmioWrite8 (Base + SDHCI_P_ATDL_CNFG, (2 << ATDL_CNFG_INPSEL_CNFG));
+
+ return;
+}
+
+/**
+ Initialize the SD card.
+
+ This function performs the initialization of the SD card hardware and settings.
+
+ @param[in] Flags Initialization flags.
+
+ @retval EFI_SUCCESS The SD card was initialized successfully.
+
+**/
+EFI_STATUS
+SdInit (
+ IN UINT32 Flags
+)
+{
+ BmParams.ClkRate = BmGetSdClk ();
+
+ DEBUG ((DEBUG_INFO, "SD initializing %dHz\n", BmParams.ClkRate));
+
+ BmParams.Flags = Flags;
+
+ SdPhyInit ();
+
+ SdHwInit ();
+
+ return EFI_SUCCESS;
+}
diff --git a/Silicon/Sophgo/SG2042Pkg/Drivers/SdHostDxe/SdHostDxe.c b/Silicon/Sophgo/SG2042Pkg/Drivers/SdHostDxe/SdHostDxe.c
new file mode 100644
index 000000000000..3bb04344320a
--- /dev/null
+++ b/Silicon/Sophgo/SG2042Pkg/Drivers/SdHostDxe/SdHostDxe.c
@@ -0,0 +1,450 @@
+/** @file
+ This file implements the SD host controller driver for UEFI systems.
+ The file contains the implementation of the EFI_MMC_HOST_PROTOCOL, which provides
+ the necessary interfaces for handling communication and data transfer with SD cards.
+
+ Copyright (c) 2017, Andrei Warkentin <andrey.warkentin@gmail.com>
+ Copyright (c) Microsoft Corporation. All rights reserved.
+ Copyright (c) 2023, Academy of Intelligent Innovation, Shandong Universiy, China.P.R. All rights reserved.<BR>
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include <Uefi.h>
+#include <Library/BaseLib.h>
+#include <Library/MemoryAllocationLib.h>
+#include <Library/DebugLib.h>
+#include <Library/DevicePathLib.h>
+#include <Library/IoLib.h>
+#include <Library/PcdLib.h>
+#include <Library/UefiBootServicesTableLib.h>
+#include <Library/BaseMemoryLib.h>
+#include <Library/DmaLib.h>
+#include <Library/TimerLib.h>
+
+#include <Protocol/EmbeddedExternalDevice.h>
+#include <Protocol/BlockIo.h>
+#include <Protocol/DevicePath.h>
+#include <Include/MmcHost.h>
+
+#include "SdHci.h"
+
+#define SDHOST_BLOCK_BYTE_LENGTH 512
+
+#define DEBUG_MMCHOST_SD DEBUG_VERBOSE
+#define DEBUG_MMCHOST_SD_INFO DEBUG_INFO
+#define DEBUG_MMCHOST_SD_ERROR DEBUG_ERROR
+
+STATIC BOOLEAN mCardIsPresent = FALSE;
+STATIC CARD_DETECT_STATE mCardDetectState = CardDetectRequired;
+BM_SD_PARAMS BmParams;
+
+/**
+ Check if the SD card is read-only.
+
+ @param[in] This Pointer to the EFI_MMC_HOST_PROTOCOL instance.
+
+ @retval FALSE The SD card is not read-only.
+
+**/
+STATIC
+BOOLEAN
+SdIsReadOnly (
+ IN EFI_MMC_HOST_PROTOCOL *This
+ )
+{
+ return FALSE;
+}
+
+/**
+ Build the device path for the SD card.
+
+ @param[in] This Pointer to the EFI_MMC_HOST_PROTOCOL instance.
+ @param[out] DevicePath Pointer to the location to store the newly created device path.
+
+ @retval EFI_SUCCESS The device path is built successfully.
+
+**/
+STATIC
+EFI_STATUS
+SdBuildDevicePath (
+ IN EFI_MMC_HOST_PROTOCOL *This,
+ OUT EFI_DEVICE_PATH_PROTOCOL **DevicePath
+ )
+{
+ EFI_DEVICE_PATH_PROTOCOL *NewDevicePathNode;
+ EFI_GUID DevicePathGuid = EFI_CALLER_ID_GUID;
+
+ DEBUG ((DEBUG_MMCHOST_SD, "SdHost: SdBuildDevicePath ()\n"));
+
+ NewDevicePathNode = CreateDeviceNode (HARDWARE_DEVICE_PATH, HW_VENDOR_DP, sizeof (VENDOR_DEVICE_PATH));
+ CopyGuid (&((VENDOR_DEVICE_PATH*)NewDevicePathNode)->Guid, &DevicePathGuid);
+ *DevicePath = NewDevicePathNode;
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Send a command to the SD card.
+
+ @param[in] This Pointer to the EFI_MMC_HOST_PROTOCOL instance.
+ @param[in] MmcCmd The MMC command to send.
+ @param[in] Argument The argument for the command.
+ @param[in] Type The type of response expected.
+ @param[in] Buffer Pointer to the buffer to store the response.
+
+ @retval EFI_SUCCESS The command was sent successfully and the response was retrieved.
+ @retval Other An error occurred while sending a command.
+**/
+STATIC
+EFI_STATUS
+SdSendCommand (
+ IN EFI_MMC_HOST_PROTOCOL *This,
+ IN MMC_IDX MmcCmd,
+ IN UINT32 Argument,
+ IN MMC_RESPONSE_TYPE Type,
+ IN UINT32* Buffer
+ )
+{
+ EFI_STATUS Status;
+
+ Status = BmSdSendCmd (MmcCmd, Argument, Type, Buffer);
+
+ if (EFI_ERROR (Status)) {
+ DEBUG ((DEBUG_MMCHOST_SD_ERROR, "SdSendCommand Error, Status=%r.\n", Status));
+ return Status;
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Read block data from an SD card.
+
+ @param[in] This Pointer to the EFI_MMC_HOST_PROTOCOL instance.
+ @param[in] Lba Logical Block Address of the starting block to read.
+ @param[in] Length Number of blocks to read.
+ @param[in] Buffer Pointer to the buffer to store the read data.
+
+ @retval EFI_SUCCESS The operation completed successfully.
+ @retval Other The operation failed.
+
+**/
+STATIC
+EFI_STATUS
+SdReadBlockData (
+ IN EFI_MMC_HOST_PROTOCOL *This,
+ IN EFI_LBA Lba,
+ IN UINTN Length,
+ OUT UINT32* Buffer
+ )
+{
+ EFI_STATUS Status;
+
+ ASSERT (Buffer != NULL);
+ ASSERT (Length % 4 == 0);
+
+ Status = BmSdRead (Lba, Buffer, Length);
+
+ if (EFI_ERROR (Status)) {
+ DEBUG ((DEBUG_MMCHOST_SD_ERROR, "SdReadBlockData Error, Status=%r.\n", Status));
+ return Status;
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Write block data to an SD card.
+
+ @param[in] This Pointer to the EFI_MMC_HOST_PROTOCOL instance.
+ @param[in] Lba Logical Block Address of the starting block to write.
+ @param[in] Length Number of blocks to write.
+ @param[in] Buffer Pointer to the buffer containing the data to be written.
+
+ @retval EFI_SUCCESS The operation completed successfully.
+ @retval Other The operation failed.
+
+**/
+STATIC
+EFI_STATUS
+SdWriteBlockData (
+ IN EFI_MMC_HOST_PROTOCOL *This,
+ IN EFI_LBA Lba,
+ IN UINTN Length,
+ IN UINT32* Buffer
+ )
+{
+ EFI_STATUS Status;
+
+ DEBUG ((DEBUG_MMCHOST_SD, "SdHost: SdWriteBlockData(LBA: 0x%x, Length: 0x%x, Buffer: 0x%x)\n",(UINT32)Lba, Length, Buffer));
+
+ ASSERT (Buffer != NULL);
+ ASSERT (Length % SDHOST_BLOCK_BYTE_LENGTH == 0);
+
+ Status = BmSdWrite (Lba, Buffer, Length);
+
+ if (EFI_ERROR (Status)) {
+ DEBUG ((DEBUG_MMCHOST_SD_ERROR, "SdWriteBlockData Error, Status=%r.\n", Status));
+ return Status;
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Set the I/O settings for an SD card.
+
+ @param[in] This Pointer to the EFI_MMC_HOST_PROTOCOL instance.
+ @param[in] BusClockFreq Bus clock frequency in Hz.
+ @param[in] BusWidth Bus width setting.
+
+ @retval EFI_SUCCESS The operation completed successfully.
+ @retval Other The operation failed.
+
+**/
+STATIC
+EFI_STATUS
+SdSetIos (
+ IN EFI_MMC_HOST_PROTOCOL *This,
+ IN UINT32 BusClockFreq,
+ IN UINT32 BusWidth
+ )
+{
+ EFI_STATUS Status;
+
+ DEBUG ((DEBUG_MMCHOST_SD_INFO, "%a: Setting Freq %u Hz\n", __func__, BusClockFreq));
+ DEBUG ((DEBUG_MMCHOST_SD_INFO, "%a: Setting BusWidth %u\n", __func__, BusWidth));
+
+ Status = BmSdSetIos (BusClockFreq,BusWidth);
+
+ if (EFI_ERROR (Status)) {
+ DEBUG ((DEBUG_MMCHOST_SD_ERROR, "SdSetIos Error, Status=%r.\n", Status));
+ return Status;
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Prepare the SD card for data transfer.
+
+ @param[in] This Pointer to the EFI_MMC_HOST_PROTOCOL instance.
+ @param[in] Lba Logical Block Address of the starting block to prepare.
+ @param[in] Length Number of blocks to prepare.
+ @param[in] Buffer Buffer containing the data to be prepared.
+
+ @retval EFI_SUCCESS The operation completed successfully.
+ @retval Other The operation failed.
+
+**/
+STATIC
+EFI_STATUS
+SdPrepare (
+ IN EFI_MMC_HOST_PROTOCOL *This,
+ IN EFI_LBA Lba,
+ IN UINTN Length,
+ IN UINTN Buffer
+ )
+{
+ EFI_STATUS Status;
+
+ Status = BmSdPrepare (Lba, Buffer, Length);
+
+ if (EFI_ERROR (Status)) {
+ DEBUG ((DEBUG_MMCHOST_SD_ERROR, "SdPrepare Error, Status=%r.\n", Status));
+ return Status;
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Notify the state of the SD card.
+
+ @param[in] This Pointer to the EFI_MMC_HOST_PROTOCOL instance.
+ @param[in] State State of the SD card.
+
+ @retval EFI_SUCCESS The operation completed successfully.
+ @retval EFI_NOT_READY The card detection has not completed yet.
+ @retval Other The operation failed.
+
+**/
+STATIC
+EFI_STATUS
+SdNotifyState (
+ IN EFI_MMC_HOST_PROTOCOL *This,
+ IN MMC_STATE State
+ )
+{
+ // Stall all operations except init until card detection has occurred.
+ if (State != MmcHwInitializationState && mCardDetectState != CardDetectCompleted) {
+ return EFI_NOT_READY;
+ }
+
+ switch (State) {
+ case MmcHwInitializationState:
+ DEBUG ((DEBUG_MMCHOST_SD, "MmcHwInitializationState\n", State));
+
+ EFI_STATUS Status = SdInit (SD_USE_PIO);
+ if (EFI_ERROR (Status)) {
+ DEBUG ((DEBUG_MMCHOST_SD_ERROR,"SdHost: SdNotifyState(): Fail to initialize!\n"));
+ return Status;
+ }
+ break;
+ case MmcIdleState:
+ DEBUG ((DEBUG_MMCHOST_SD, "MmcIdleState\n", State));
+ break;
+ case MmcReadyState:
+ DEBUG ((DEBUG_MMCHOST_SD, "MmcReadyState\n", State));
+ break;
+ case MmcIdentificationState:
+ DEBUG ((DEBUG_MMCHOST_SD, "MmcIdentificationState\n", State));
+ break;
+ case MmcStandByState:
+ DEBUG ((DEBUG_MMCHOST_SD, "MmcStandByState\n", State));
+ break;
+ case MmcTransferState:
+ DEBUG ((DEBUG_MMCHOST_SD, "MmcTransferState\n", State));
+ break;
+ case MmcSendingDataState:
+ DEBUG ((DEBUG_MMCHOST_SD, "MmcSendingDataState\n", State));
+ break;
+ case MmcReceiveDataState:
+ DEBUG ((DEBUG_MMCHOST_SD, "MmcReceiveDataState\n", State));
+ break;
+ case MmcProgrammingState:
+ DEBUG ((DEBUG_MMCHOST_SD, "MmcProgrammingState\n", State));
+ break;
+ case MmcDisconnectState:
+ case MmcInvalidState:
+ default:
+ DEBUG ((DEBUG_MMCHOST_SD_ERROR, "SdHost: SdNotifyState(): Invalid State: %d\n", State));
+ ASSERT (0);
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Check if an SD card is present.
+
+ @param[in] This Pointer to the EFI_MMC_HOST_PROTOCOL instance.
+
+ @retval TRUE An SD card is present.
+ @retval FALSE No SD card is present.
+
+**/
+STATIC
+BOOLEAN
+SdIsCardPresent (
+ IN EFI_MMC_HOST_PROTOCOL *This
+ )
+{
+ //
+ // If we are already in progress (we may get concurrent calls)
+ // or completed the detection, just return the current value.
+ //
+ if (mCardDetectState != CardDetectRequired) {
+ return mCardIsPresent;
+ }
+
+ mCardDetectState = CardDetectInProgress;
+ mCardIsPresent = FALSE;
+
+ if (BmSdCardDetect () == 1) {
+ mCardIsPresent = TRUE;
+ goto out;
+ }
+ else {
+ DEBUG ((DEBUG_MMCHOST_SD_ERROR, "SdIsCardPresent: Error SdCardDetect.\n"));
+ mCardDetectState = CardDetectRequired;
+ return FALSE;
+ }
+
+ DEBUG ((DEBUG_MMCHOST_SD_INFO, "SdIsCardPresent: Not detected.\n"));
+
+out:
+ mCardDetectState = CardDetectCompleted;
+ return mCardIsPresent;
+}
+
+/**
+ Check if the SD card supports multi-block transfers.
+
+ @param[in] This Pointer to the EFI_MMC_HOST_PROTOCOL instance.
+
+ @retval TRUE The SD card supports multi-block transfers.
+
+**/
+BOOLEAN
+SdIsMultiBlock (
+ IN EFI_MMC_HOST_PROTOCOL *This
+ )
+{
+ return TRUE;
+}
+
+EFI_MMC_HOST_PROTOCOL gMmcHost = {
+ MMC_HOST_PROTOCOL_REVISION,
+ SdIsCardPresent,
+ SdIsReadOnly,
+ SdBuildDevicePath,
+ SdNotifyState,
+ SdSendCommand,
+ SdReadBlockData,
+ SdWriteBlockData,
+ SdSetIos,
+ SdPrepare,
+ SdIsMultiBlock
+};
+
+/**
+ Initialize the SD host.
+
+ @param[in] ImageHandle The image handle.
+ @param[in] SystemTable The system table.
+
+ @retval EFI_SUCCESS The operation completed successfully.
+ @retval Other The operation failed.
+**/
+EFI_STATUS
+SdHostInitialize (
+ IN EFI_HANDLE ImageHandle,
+ IN EFI_SYSTEM_TABLE *SystemTable
+ )
+{
+ EFI_STATUS Status;
+ EFI_HANDLE Handle;
+ UINTN Base;
+
+ DEBUG ((DEBUG_MMCHOST_SD, "SdHost: Initialize\n"));
+
+ Handle = NULL;
+ Base = SDIO_BASE;
+
+ if(!PcdGetBool (PcdForceNoMMU)){
+ for (INT32 I = 39; I < 64; I++) {
+ if (Base & (1ULL << 38)) {
+ Base |= (1ULL << I);
+ } else {
+ Base &= ~(1ULL << I);
+ }
+ }
+ }
+
+ BmParams.RegBase = Base;
+ BmParams.ClkRate = 50 * 1000 * 1000;
+ BmParams.BusWidth = MMC_BUS_WIDTH_4;
+ BmParams.Flags = 0;
+ BmParams.CardIn = SDCARD_STATUS_UNKNOWN;
+
+ Status = gBS->InstallMultipleProtocolInterfaces (
+ &Handle,
+ &gSophgoMmcHostProtocolGuid,
+ &gMmcHost,
+ NULL
+ );
+ ASSERT_EFI_ERROR (Status);
+ return Status;
+}
--
2.34.1
-=-=-=-=-=-=-=-=-=-=-=-
Groups.io Links: You receive all messages sent to this group.
View/Reply Online (#108378): https://edk2.groups.io/g/devel/message/108378
Mute This Topic: https://groups.io/mt/101213491/1787277
Group Owner: devel+owner@edk2.groups.io
Unsubscribe: https://edk2.groups.io/g/devel/unsub [importer@patchew.org]
-=-=-=-=-=-=-=-=-=-=-=-
On Thu, Sep 07, 2023 at 18:25:46 +0800, caiyuqing_hz@163.com wrote: > From: caiyuqing379 <202235273@mail.sdu.edu.cn> > > This driver implements Sophgo SDHCI controller, which provides > the necessary interfaces for handling communication and data > transfer with SD cards. > > Signed-off-by: caiyuqing379 <202235273@mail.sdu.edu.cn> > Co-authored-by: USER0FISH <libing1202@outlook.com> > Cc: dahogn <dahogn@hotmail.com> > Cc: meng-cz <mengcz1126@gmail.com> > Cc: yli147 <yong.li@intel.com> > Cc: ChaiEvan <evan.chai@intel.com> > Cc: Sunil V L <sunilvl@ventanamicro.com> > Cc: Leif Lindholm <quic_llindhol@quicinc.com> > --- > .../SG2042Pkg/Drivers/SdHostDxe/SdHostDxe.inf | 47 + > .../SG2042Pkg/Drivers/SdHostDxe/SdHci.h | 309 ++++++ > .../SG2042Pkg/Drivers/SdHostDxe/SdHci.c | 929 ++++++++++++++++++ > .../SG2042Pkg/Drivers/SdHostDxe/SdHostDxe.c | 450 +++++++++ > 4 files changed, 1735 insertions(+) > create mode 100644 Silicon/Sophgo/SG2042Pkg/Drivers/SdHostDxe/SdHostDxe.inf > create mode 100644 Silicon/Sophgo/SG2042Pkg/Drivers/SdHostDxe/SdHci.h > create mode 100755 Silicon/Sophgo/SG2042Pkg/Drivers/SdHostDxe/SdHci.c > create mode 100644 Silicon/Sophgo/SG2042Pkg/Drivers/SdHostDxe/SdHostDxe.c > > diff --git a/Silicon/Sophgo/SG2042Pkg/Drivers/SdHostDxe/SdHci.h b/Silicon/Sophgo/SG2042Pkg/Drivers/SdHostDxe/SdHci.h > new file mode 100644 > index 000000000000..d9a9c88674e6 > --- /dev/null > +++ b/Silicon/Sophgo/SG2042Pkg/Drivers/SdHostDxe/SdHci.h > @@ -0,0 +1,309 @@ > +/** @file > + The header file that provides definitions and function declarations > + related to the SD Host Controller Interface (SDHCI) for SD card host controllers. > + > + Copyright (c) 2016-2017, ARM Limited and Contributors. All rights reserved. > + Copyright (c) 2023, Academy of Intelligent Innovation, Shandong Universiy, China.P.R. All rights reserved.<BR> > + SPDX-License-Identifier: BSD-3-Clause The license for this whole repository is BSD-2-Clause-Patent. What is the origin code that this is based on? > + > +**/ > + > +#ifndef _SD_HCI_H_ > +#define _SD_HCI_H_ > + > +#define SDIO_BASE (FixedPcdGet64(PcdSG2042SDIOBase)) > +#define SDHCI_DMA_ADDRESS 0x00 > +#define SDHCI_BLOCK_SIZE 0x04 > +#define SDHCI_MAKE_BLKSZ(dma, blksz) ((((dma) & 0x7) << 12) | ((blksz) & 0xFFF)) > +#define SDHCI_BLOCK_COUNT 0x06 > +#define SDHCI_ARGUMENT 0x08 > +#define SDHCI_TRANSFER_MODE 0x0C > +#define SDHCI_TRNS_DMA BIT0 > +#define SDHCI_TRNS_BLK_CNT_EN BIT1 > +#define SDHCI_TRNS_ACMD12 BIT2 > +#define SDHCI_TRNS_READ BIT4 > +#define SDHCI_TRNS_MULTI BIT5 > +#define SDHCI_TRNS_RESP_INT BIT8 > +#define SDHCI_COMMAND 0x0E > +#define SDHCI_CMD_RESP_MASK 0x03 > +#define SDHCI_CMD_CRC 0x08 > +#define SDHCI_CMD_INDEX 0x10 > +#define SDHCI_CMD_DATA 0x20 > +#define SDHCI_CMD_ABORTCMD 0xC0 > +#define SDHCI_CMD_RESP_NONE 0x00 > +#define SDHCI_CMD_RESP_LONG 0x01 > +#define SDHCI_CMD_RESP_SHORT 0x02 > +#define SDHCI_CMD_RESP_SHORT_BUSY 0x03 > +#define SDHCI_MAKE_CMD(c, f) ((((c) & 0xff) << 8) | ((f) & 0xff)) > +#define SDHCI_RESPONSE_01 0x10 > +#define SDHCI_RESPONSE_23 0x14 > +#define SDHCI_RESPONSE_45 0x18 > +#define SDHCI_RESPONSE_67 0x1C > +#define SDHCI_PSTATE 0x24 > +#define SDHCI_CMD_INHIBIT BIT0 > +#define SDHCI_CMD_INHIBIT_DAT BIT1 > +#define SDHCI_BUF_WR_ENABLE BIT10 > +#define SDHCI_BUF_RD_ENABLE BIT11 > +#define SDHCI_CARD_INSERTED BIT16 > +#define SDHCI_HOST_CONTROL 0x28 > +#define SDHCI_DAT_XFER_WIDTH BIT1 > +#define SDHCI_EXT_DAT_XFER BIT5 > +#define SDHCI_CTRL_DMA_MASK 0x18 > +#define SDHCI_CTRL_SDMA 0x00 > +#define SDHCI_PWR_CONTROL 0x29 > +#define SDHCI_BUS_VOL_VDD1_1_8V 0xC > +#define SDHCI_BUS_VOL_VDD1_3_0V 0xE > +#define SDHCI_BUF_DATA_R 0x20 > +#define SDHCI_BLOCK_GAP_CONTROL 0x2A > +#define SDHCI_CLK_CTRL 0x2C > +#define SDHCI_TOUT_CTRL 0x2E > +#define SDHCI_SOFTWARE_RESET 0x2F > +#define SDHCI_RESET_CMD 0x02 > +#define SDHCI_RESET_DATA 0x04 > +#define SDHCI_INT_STATUS 0x30 > +#define SDHCI_ERR_INT_STATUS 0x32 > +#define SDHCI_INT_CMD_COMPLETE BIT0 > +#define SDHCI_INT_XFER_COMPLETE BIT1 > +#define SDHCI_INT_DMA_END BIT3 > +#define SDHCI_INT_BUF_WR_READY BIT4 > +#define SDHCI_INT_BUF_RD_READY BIT5 > +#define SDHCI_INT_ERROR BIT15 > +#define SDHCI_INT_STATUS_EN 0x34 > +#define SDHCI_ERR_INT_STATUS_EN 0x36 > +#define SDHCI_INT_CMD_COMPLETE_EN BIT0 > +#define SDHCI_INT_XFER_COMPLETE_EN BIT1 > +#define SDHCI_INT_DMA_END_EN BIT3 > +#define SDHCI_INT_CARD_INSERTION_EN BIT6 > +#define SDHCI_INT_ERROR_EN BIT15 > +#define SDHCI_SIGNAL_ENABLE 0x38 > +#define SDHCI_HOST_CONTROL2 0x3E > +#define SDHCI_HOST_VER4_ENABLE BIT12 > +#define SDHCI_CAPABILITIES1 0x40 > +#define SDHCI_CAPABILITIES2 0x44 > +#define SDHCI_ADMA_SA_LOW 0x58 > +#define SDHCI_ADMA_SA_HIGH 0x5C > +#define SDHCI_HOST_CNTRL_VERS 0xFE > +#define SDHCI_UHS_2_TIMER_CNTRL 0xC2 > + > +#define P_VENDOR_SPECIFIC_AREA 0xE8 > +#define P_VENDOR2_SPECIFIC_AREA 0xEA > +#define VENDOR_SD_CTRL 0x2C > + > +#define SDHCI_PHY_R_OFFSET 0x300 > + > +#define SDHCI_P_PHY_CNFG (SDHCI_PHY_R_OFFSET + 0x00) > +#define SDHCI_P_CMDPAD_CNFG (SDHCI_PHY_R_OFFSET + 0x04) > +#define SDHCI_P_DATPAD_CNFG (SDHCI_PHY_R_OFFSET + 0x06) > +#define SDHCI_P_CLKPAD_CNFG (SDHCI_PHY_R_OFFSET + 0x08) > +#define SDHCI_P_STBPAD_CNFG (SDHCI_PHY_R_OFFSET + 0x0A) > +#define SDHCI_P_RSTNPAD_CNFG (SDHCI_PHY_R_OFFSET + 0x0C) > +#define SDHCI_P_PADTEST_CNFG (SDHCI_PHY_R_OFFSET + 0x0E) > +#define SDHCI_P_PADTEST_OUT (SDHCI_PHY_R_OFFSET + 0x10) > +#define SDHCI_P_PADTEST_IN (SDHCI_PHY_R_OFFSET + 0x12) > +#define SDHCI_P_COMMDL_CNFG (SDHCI_PHY_R_OFFSET + 0x1C) > +#define SDHCI_P_SDCLKDL_CNFG (SDHCI_PHY_R_OFFSET + 0x1D) > +#define SDHCI_P_SDCLKDL_DC (SDHCI_PHY_R_OFFSET + 0x1E) > +#define SDHCI_P_SMPLDL_CNFG (SDHCI_PHY_R_OFFSET + 0x20) > +#define SDHCI_P_ATDL_CNFG (SDHCI_PHY_R_OFFSET + 0x21) > +#define SDHCI_P_DLL_CTRL (SDHCI_PHY_R_OFFSET + 0x24) > +#define SDHCI_P_DLL_CNFG1 (SDHCI_PHY_R_OFFSET + 0x25) > +#define SDHCI_P_DLL_CNFG2 (SDHCI_PHY_R_OFFSET + 0x26) > +#define SDHCI_P_DLLDL_CNFG (SDHCI_PHY_R_OFFSET + 0x28) > +#define SDHCI_P_DLL_OFFST (SDHCI_PHY_R_OFFSET + 0x29) > +#define SDHCI_P_DLLMST_TSTDC (SDHCI_PHY_R_OFFSET + 0x2A) > +#define SDHCI_P_DLLLBT_CNFG (SDHCI_PHY_R_OFFSET + 0x2C) > +#define SDHCI_P_DLL_STATUS (SDHCI_PHY_R_OFFSET + 0x2E) > +#define SDHCI_P_DLLDBG_MLKDC (SDHCI_PHY_R_OFFSET + 0x30) > +#define SDHCI_P_DLLDBG_SLKDC (SDHCI_PHY_R_OFFSET + 0x32) > + > +#define PHY_CNFG_PHY_RSTN 0 > +#define PHY_CNFG_PHY_PWRGOOD 1 > +#define PHY_CNFG_PAD_SP 16 > +#define PHY_CNFG_PAD_SP_MSK 0xf > +#define PHY_CNFG_PAD_SN 20 > +#define PHY_CNFG_PAD_SN_MSK 0xf > + > +#define PAD_CNFG_RXSEL 0 > +#define PAD_CNFG_RXSEL_MSK 0x7 > +#define PAD_CNFG_WEAKPULL_EN 3 > +#define PAD_CNFG_WEAKPULL_EN_MSK 0x3 > +#define PAD_CNFG_TXSLEW_CTRL_P 5 > +#define PAD_CNFG_TXSLEW_CTRL_P_MSK 0xf > +#define PAD_CNFG_TXSLEW_CTRL_N 9 > +#define PAD_CNFG_TXSLEW_CTRL_N_MSK 0xf > + > +#define COMMDL_CNFG_DLSTEP_SEL 0 > +#define COMMDL_CNFG_DLOUT_EN 1 > + > +#define SDCLKDL_CNFG_EXTDLY_EN 0 > +#define SDCLKDL_CNFG_BYPASS_EN 1 > +#define SDCLKDL_CNFG_INPSEL_CNFG 2 > +#define SDCLKDL_CNFG_INPSEL_CNFG_MSK 0x3 > +#define SDCLKDL_CNFG_UPDATE_DC 4 > + > +#define SMPLDL_CNFG_EXTDLY_EN 0 > +#define SMPLDL_CNFG_BYPASS_EN 1 > +#define SMPLDL_CNFG_INPSEL_CNFG 2 > +#define SMPLDL_CNFG_INPSEL_CNFG_MSK 0x3 > +#define SMPLDL_CNFG_INPSEL_OVERRIDE 4 > + > +#define ATDL_CNFG_EXTDLY_EN 0 > +#define ATDL_CNFG_BYPASS_EN 1 > +#define ATDL_CNFG_INPSEL_CNFG 2 > +#define ATDL_CNFG_INPSEL_CNFG_MSK 0x3 > + > +#define SD_USE_PIO 0x1 > + > +/** > + card detect status > + -1: haven't check the card detect register > + 0 : no card detected > + 1 : card detected > +**/ > +#define SDCARD_STATUS_UNKNOWN (-1) > +#define SDCARD_STATUS_INSERTED (1) > +#define SDCARD_STATUS_NOT_INSERTED (0) > + > +typedef struct { > + UINT32 CmdIdx; > + UINT32 CmdArg; > + UINT32 ResponseType; > + UINT32 Response[4]; > +} MMC_CMD; > + > +typedef struct { > + UINTN RegBase; > + UINTN VendorBase; > + UINTN DescBase; > + UINTN DescSize; > + INT32 ClkRate; > + INT32 BusWidth; > + UINT32 Flags; > + INT32 CardIn; > +} BM_SD_PARAMS; > + > +extern BM_SD_PARAMS BmParams; > + > +/** > + SD card sends command. > + > + @param[in] Idx Command ID. > + @param[in] Arg Command argument. > + @param[in] RespType Type of response data. > + @param[out] Response Response data. > + > + @retval EFI_SUCCESS The command was sent successfully. > + @retval EFI_DEVICE_ERROR There was an error during the command transmission or response handling. > + @retval EFI_TIMEOUT The command transmission or response handling timed out. > + > +**/ > +EFI_STATUS > +EFIAPI > +BmSdSendCmd ( > + IN UINT32 Idx, > + IN UINT32 Arg, > + IN UINT32 RespType, > + OUT UINT32 *Response > + ); > + > +/** > + Detect the status of the SD card. > + > + @return The status of the SD card: > + - SDCARD_STATUS_INSERTED: The SD card is inserted. > + - SDCARD_STATUS_NOT_INSERTED: The SD card is not inserted. > + - SDCARD_STATUS_UNKNOWN: The status of the SD card is unknown. > + > +**/ > +INT32 > +BmSdCardDetect ( > + VOID > + ); > + > +/** > + Set the input/output settings for the SD card. > + > + @param[in] Clk The clock frequency for the SD card. > + @param[in] Width The bus width for data transfer. > + > + @retval EFI_SUCCESS The input/output settings were set successfully. > + @retval EFI_UNSUPPORTED The specified bus width is not supported. > + > +**/ > +EFI_STATUS > +BmSdSetIos ( > + IN UINT32 Clk, > + IN UINT32 Width > + ); > + > +/** > + Prepare the SD card for data transfer. > + Set the number and size of data blocks before sending IO commands to the SD card. > + > + @param[in] Lba Logical Block Address. > + @param[in] Buf Buffer Address. > + @param[in] Size Size of Data Blocks. > + > + @retval EFI_SUCCESS The SD card was prepared successfully. > + @retval Other An error occurred during the preparation of the SD card. > + > +**/ > +EFI_STATUS > +BmSdPrepare ( > + IN INT32 Lba, > + IN UINTN Buf, > + IN UINTN Size > + ); > + > +/** > + SD card sends command to read data blocks. > + > + @param[in] Lba Logical Block Address. > + @param[in] Buf Buffer Address. > + @param[in] Size Size of Data Blocks. > + > + @retval EFI_SUCCESS The command to read data blocks was sent successfully. > + @retval EFI_TIMEOUT The command transmission or data transfer timed out. > + > +**/ > +EFI_STATUS > +BmSdRead ( > + IN INT32 Lba, > + IN UINT32* Buf, > + IN UINTN Size > + ); > + > +/** > + SD card sends commands to write data blocks. > + > + @param[in] Lba Logical Block Address. > + @param[in] Buf Buffer Address. > + @param[in] Size Size of Data Blocks. > + > + @retval EFI_SUCCESS The command to write data blocks was sent successfully. > + @retval EFI_TIMEOUT The command transmission or data transfer timed out. > + > +**/ > +EFI_STATUS > +BmSdWrite ( > + IN INT32 Lba, > + IN UINT32* Buf, > + IN UINTN Size > + ); > + > +/** > + Initialize the SD card. > + > + This function performs the initialization of the SD card hardware and settings. > + > + @param[in] Flags Initialization flags. > + > + @retval EFI_SUCCESS The SD card was initialized successfully. > + > +**/ > +EFI_STATUS > +SdInit ( > + IN UINT32 flags > + ); > + > +#endif > diff --git a/Silicon/Sophgo/SG2042Pkg/Drivers/SdHostDxe/SdHci.c b/Silicon/Sophgo/SG2042Pkg/Drivers/SdHostDxe/SdHci.c > new file mode 100755 > index 000000000000..efa9f6397a1e > --- /dev/null > +++ b/Silicon/Sophgo/SG2042Pkg/Drivers/SdHostDxe/SdHci.c > @@ -0,0 +1,929 @@ > +/** @file > + The implementation for handling SD card operations using the SD Host Controller Interface (SDHCI). > + > + Copyright (c) 2016-2017, ARM Limited and Contributors. All rights reserved. > + Copyright (c) 2023, Academy of Intelligent Innovation, Shandong Universiy, China.P.R. All rights reserved.<BR> > + SPDX-License-Identifier: BSD-3-Clause Same as above. / Leif > + > +**/ > + > +#include <Uefi.h> > +#include <Base.h> > +#include <Library/BaseLib.h> > +#include <Library/MemoryAllocationLib.h> > +#include <Library/DebugLib.h> > +#include <Library/IoLib.h> > +#include <Library/PcdLib.h> > +#include <Library/UefiBootServicesTableLib.h> > +#include <Library/BaseMemoryLib.h> > +#include <Include/MmcHost.h> > + > +#include "SdHci.h" > + > +#define SDCARD_INIT_FREQ (200 * 1000) > +#define SDCARD_TRAN_FREQ (6 * 1000 * 1000) > + > +/** > + Return the clock rate of SD card. > + > + @retval the clock rate of SD card. > + > +**/ > +INT32 > +BmGetSdClk ( > + VOID > + ) > +{ > + return 100*1000*1000; > +} > + > +/** > + SD card sends command with response block data. > + > + @param Cmd Command sent by SD card. > + > + @retval EFI_SUCCESS The command with response block data was sent successfully. > + @retval EFI_DEVICE_ERROR There was an error during the command transmission or response handling. > + @retval EFI_TIMEOUT The command transmission or response handling timed out. > + > +**/ > +STATIC > +EFI_STATUS > +SdSendCmdWithData ( > + IN OUT MMC_CMD *Cmd > + ) > +{ > + UINTN Base; > + UINT32 Mode; > + UINT32 State; > + UINT32 DmaAddr; > + UINT32 Flags; > + UINT32 Timeout; > + > + Base = BmParams.RegBase; > + Mode = 0; > + Flags = 0; > + > + // Make sure Cmd line is clear > + while (1) { > + if (!(MmioRead32 (Base + SDHCI_PSTATE) & SDHCI_CMD_INHIBIT)) > + break; > + } > + > + switch (Cmd->CmdIdx) { > + case MMC_CMD17: > + case MMC_CMD18: > + case MMC_ACMD51: > + Mode = SDHCI_TRNS_BLK_CNT_EN | SDHCI_TRNS_MULTI | SDHCI_TRNS_READ; > + if (!(BmParams.Flags & SD_USE_PIO)) > + Mode |= SDHCI_TRNS_DMA; > + break; > + case MMC_CMD24: > + case MMC_CMD25: > + Mode = (SDHCI_TRNS_BLK_CNT_EN | SDHCI_TRNS_MULTI) & ~SDHCI_TRNS_READ; > + if (!(BmParams.Flags & SD_USE_PIO)) > + Mode |= SDHCI_TRNS_DMA; > + break; > + default: > + ASSERT(0); > + } > + > + MmioWrite16 (Base + SDHCI_TRANSFER_MODE, Mode); > + MmioWrite32 (Base + SDHCI_ARGUMENT, Cmd->CmdArg); > + > + // set Cmd Flags > + if (Cmd->CmdIdx == MMC_CMD0) > + Flags |= SDHCI_CMD_RESP_NONE; > + else { > + if (Cmd->ResponseType & MMC_RSP_136) > + Flags |= SDHCI_CMD_RESP_LONG; > + else > + Flags |= SDHCI_CMD_RESP_SHORT; > + if (Cmd->ResponseType & MMC_RSP_CRC) > + Flags |= SDHCI_CMD_CRC; > + if (Cmd->ResponseType & MMC_RSP_CMD_IDX) > + Flags |= SDHCI_CMD_INDEX; > + } > + > + Flags |= SDHCI_CMD_DATA; > + > + // issue the Cmd > + MmioWrite16 (Base + SDHCI_COMMAND, SDHCI_MAKE_CMD(Cmd->CmdIdx, Flags)); > + > + // check Cmd complete if necessary > + if ((MmioRead16 (Base + SDHCI_TRANSFER_MODE) & SDHCI_TRNS_RESP_INT) == 0) { > + Timeout = 100000; > + while (1) { > + State = MmioRead16 (Base + SDHCI_INT_STATUS); > + if (State & SDHCI_INT_ERROR) { > + DEBUG ((DEBUG_ERROR, "%a: interrupt error: 0x%x 0x%x\n", __func__, MmioRead16 (Base + SDHCI_INT_STATUS), > + MmioRead16 (Base + SDHCI_ERR_INT_STATUS))); > + return EFI_DEVICE_ERROR; > + } > + if (State & SDHCI_INT_CMD_COMPLETE) { > + MmioWrite16 (Base + SDHCI_INT_STATUS, State | SDHCI_INT_CMD_COMPLETE); > + break; > + } > + > + gBS->Stall (1); > + if (!Timeout--) { > + DEBUG ((DEBUG_ERROR, "%a: Timeout!\n", __func__)); > + return EFI_TIMEOUT; > + } > + } > + > + // get Cmd respond > + if (Flags != SDHCI_CMD_RESP_NONE) > + Cmd->Response[0] = MmioRead32 (Base + SDHCI_RESPONSE_01); > + if (Flags & SDHCI_CMD_RESP_LONG) { > + Cmd->Response[1] = MmioRead32 (Base + SDHCI_RESPONSE_23); > + Cmd->Response[2] = MmioRead32 (Base + SDHCI_RESPONSE_45); > + Cmd->Response[3] = MmioRead32 (Base + SDHCI_RESPONSE_67); > + } > + } > + > + // check dma/transfer complete > + if (!(BmParams.Flags & SD_USE_PIO)) { > + while (1) { > + State = MmioRead16 (Base + SDHCI_INT_STATUS); > + if (State & SDHCI_INT_ERROR) { > + DEBUG ((DEBUG_ERROR, "%a: interrupt error: 0x%x 0x%x\n", __func__, MmioRead16 (Base + SDHCI_INT_STATUS), > + MmioRead16 (Base + SDHCI_ERR_INT_STATUS))); > + return EFI_DEVICE_ERROR; > + } > + > + if (State & SDHCI_INT_XFER_COMPLETE) { > + MmioWrite16 (Base + SDHCI_INT_STATUS, State); > + break; > + } > + > + if (State & SDHCI_INT_DMA_END) { > + MmioWrite16 (Base + SDHCI_INT_STATUS, State); > + if (MmioRead16 (Base + SDHCI_HOST_CONTROL2) & SDHCI_HOST_VER4_ENABLE) { > + DmaAddr = MmioRead32 (Base + SDHCI_ADMA_SA_LOW); > + MmioWrite32 (Base + SDHCI_ADMA_SA_LOW, DmaAddr); > + MmioWrite32 (Base + SDHCI_ADMA_SA_HIGH, 0); > + } else { > + DmaAddr = MmioRead32 (Base + SDHCI_DMA_ADDRESS); > + MmioWrite32 (Base + SDHCI_DMA_ADDRESS, DmaAddr); > + } > + } > + > + } > + } > + > + return EFI_SUCCESS; > +} > + > +/** > + SD card sends command without response block data. > + > + @param Cmd Command sent by SD card. > + > + @retval EFI_SUCCESS The command without response block data was sent successfully. > + @retval EFI_DEVICE_ERROR There was an error during the command transmission or response handling. > + @retval EFI_TIMEOUT The command transmission or response handling timed out. > + > +**/ > +STATIC > +EFI_STATUS > +SdSendCmdWithoutData ( > + IN OUT MMC_CMD *Cmd > + ) > +{ > + UINTN Base; > + UINT32 State; > + UINT32 Flags; > + UINT32 Timeout; > + > + Base = BmParams.RegBase; > + Flags = 0x0; > + Timeout = 10000; > + > + // make sure Cmd line is clear > + while (1) { > + if (!(MmioRead32 (Base + SDHCI_PSTATE) & SDHCI_CMD_INHIBIT)) > + break; > + } > + > + // set Cmd Flags > + if (Cmd->CmdIdx == MMC_CMD0) > + Flags |= SDHCI_CMD_RESP_NONE; > + else if (Cmd->CmdIdx == MMC_CMD1) > + Flags |= SDHCI_CMD_RESP_SHORT; > + else if (Cmd->CmdIdx == MMC_ACMD41) > + Flags |= SDHCI_CMD_RESP_SHORT; > + else { > + if (Cmd->ResponseType & MMC_RSP_136) > + Flags |= SDHCI_CMD_RESP_LONG; > + else > + Flags |= SDHCI_CMD_RESP_SHORT; > + if (Cmd->ResponseType & MMC_RSP_CRC) > + Flags |= SDHCI_CMD_CRC; > + if (Cmd->ResponseType & MMC_RSP_CMD_IDX) > + Flags |= SDHCI_CMD_INDEX; > + } > + > + // make sure dat line is clear if necessary > + if (Flags != SDHCI_CMD_RESP_NONE) { > + while (1) { > + if (!(MmioRead32 (Base + SDHCI_PSTATE) & SDHCI_CMD_INHIBIT_DAT)) > + break; > + } > + } > + > + // issue the Cmd > + MmioWrite32 (Base + SDHCI_ARGUMENT, Cmd->CmdArg); > + MmioWrite16 (Base + SDHCI_COMMAND, SDHCI_MAKE_CMD(Cmd->CmdIdx, Flags)); > + > + // check Cmd complete > + Timeout = 100000; > + while (1) { > + State = MmioRead16 (Base + SDHCI_INT_STATUS); > + if (State & SDHCI_INT_ERROR) { > + DEBUG ((DEBUG_ERROR, "%a: interrupt error: 0x%x 0x%x\n", __func__, MmioRead16 (Base + SDHCI_INT_STATUS), > + MmioRead16 (Base + SDHCI_ERR_INT_STATUS))); > + return EFI_DEVICE_ERROR; > + } > + if (State & SDHCI_INT_CMD_COMPLETE) { > + MmioWrite16 (Base + SDHCI_INT_STATUS, State | SDHCI_INT_CMD_COMPLETE); > + break; > + } > + > + gBS->Stall (1); > + if (!Timeout--) { > + DEBUG ((DEBUG_ERROR, "%a: Timeout!\n", __func__)); > + return EFI_TIMEOUT; > + } > + } > + > + // get Cmd respond > + if (!(Flags & SDHCI_CMD_RESP_NONE)) > + Cmd->Response[0] = MmioRead32 (Base + SDHCI_RESPONSE_01); > + if (Flags & SDHCI_CMD_RESP_LONG) { > + Cmd->Response[1] = MmioRead32 (Base + SDHCI_RESPONSE_23); > + Cmd->Response[2] = MmioRead32 (Base + SDHCI_RESPONSE_45); > + Cmd->Response[3] = MmioRead32 (Base + SDHCI_RESPONSE_67); > + } > + > + return EFI_SUCCESS; > +} > + > +/** > + SD card sends command. > + > + @param[in] Idx Command ID. > + @param[in] Arg Command argument. > + @param[in] RespType Type of response data. > + @param[out] Response Response data. > + > + @retval EFI_SUCCESS The command was sent successfully. > + @retval EFI_DEVICE_ERROR There was an error during the command transmission or response handling. > + @retval EFI_TIMEOUT The command transmission or response handling timed out. > + > +**/ > +EFI_STATUS > +EFIAPI > +BmSdSendCmd ( > + IN UINT32 Idx, > + IN UINT32 Arg, > + IN UINT32 RespType, > + OUT UINT32 *Response > + ) > +{ > + EFI_STATUS Status; > + MMC_CMD Cmd; > + > + // DEBUG ((DEBUG_INFO, "%a: SDHCI Cmd, Idx=%d, Arg=0x%x, ResponseType=0x%x\n", __func__, Idx, Arg, RespType)); > + > + ZeroMem(&Cmd,sizeof(MMC_CMD)); > + > + Cmd.CmdIdx = Idx; > + Cmd.CmdArg = Arg; > + Cmd.ResponseType = RespType; > + > + switch (Cmd.CmdIdx) { > + case MMC_CMD17: > + case MMC_CMD18: > + case MMC_CMD24: > + case MMC_CMD25: > + case MMC_ACMD51: > + Status = SdSendCmdWithData(&Cmd); > + break; > + default: > + Status = SdSendCmdWithoutData(&Cmd); > + } > + > + if ((Status == EFI_SUCCESS) && (Response != NULL)) { > + for (INT32 I = 0; I < 4; I++) { > + *Response = Cmd.Response[I]; > + Response++; > + } > + } > + return Status; > +} > + > +/** > + Set clock frequency of SD card. > + > + @param[in] Clk The clock frequency of SD card. > + > +**/ > +VOID > +SdSetClk ( > + IN INT32 Clk > + ) > +{ > + INT32 I; > + INT32 Div; > + UINTN Base; > + > + ASSERT (Clk > 0); > + > + if (BmParams.ClkRate <= Clk) { > + Div = 0; > + } else { > + for (Div = 0x1; Div < 0xFF; Div++) { > + if (BmParams.ClkRate / (2 * Div) <= Clk) > + break; > + } > + } > + ASSERT (Div <= 0xFF); > + > + Base = BmParams.RegBase; > + if (MmioRead16 (Base + SDHCI_HOST_CONTROL2) & (1 << 15)) { > + //verbose("Use SDCLK Preset Value\n"); > + } else { > + //verbose("Set SDCLK by driver. Div=0x%x(%d)\n", Div, Div); > + MmioWrite16 (Base + SDHCI_CLK_CTRL, > + MmioRead16 (Base + SDHCI_CLK_CTRL) & ~0x9); // disable INTERNAL_CLK_EN and PLL_ENABLE > + MmioWrite16 (Base + SDHCI_CLK_CTRL, > + (MmioRead16 (Base + SDHCI_CLK_CTRL) & 0xDF) | Div << 8); // set Clk Div > + MmioWrite16 (Base + SDHCI_CLK_CTRL, > + MmioRead16 (Base + SDHCI_CLK_CTRL) | 0x1); // set INTERNAL_CLK_EN > + > + for (I = 0; I <= 150000; I += 100) { > + if (MmioRead16 (Base + SDHCI_CLK_CTRL) & 0x2) > + break; > + gBS->Stall (100); > + } > + > + if (I > 150000) { > + DEBUG ((DEBUG_ERROR, "%a: SD INTERNAL_CLK_EN setting FAILED!\n", __func__)); > + ASSERT(0); > + } > + > + MmioWrite16 (Base + SDHCI_CLK_CTRL, MmioRead16 (Base + SDHCI_CLK_CTRL) | 0x8); // set PLL_ENABLE > + > + for (I = 0; I <= 150000; I += 100) { > + if (MmioRead16 (Base + SDHCI_CLK_CTRL) & 0x2) > + return; > + gBS->Stall (100); > + } > + } > + > + DEBUG ((DEBUG_INFO, "%a: SD PLL setting FAILED!\n", __func__)); > +} > + > +/** > + Change clock frequency of SD card. > + > + @param[in] Clk The clock frequency of SD card. > + > +**/ > +VOID > +SdChangeClk ( > + IN INT32 Clk > + ) > +{ > + INT32 I; > + INT32 Div; > + UINTN Base; > + > + ASSERT (Clk > 0); > + > + if (BmParams.ClkRate <= Clk) { > + Div = 0; > + } else { > + for (Div = 0x1; Div < 0xFF; Div++) { > + if (BmParams.ClkRate / (2 * Div) <= Clk) > + break; > + } > + } > + ASSERT (Div <= 0xFF); > + > + Base = BmParams.RegBase; > + > + MmioWrite16 (Base + SDHCI_CLK_CTRL, > + MmioRead16 (Base + SDHCI_CLK_CTRL) & ~(0x1 << 2)); // stop SD clock > + > + MmioWrite16 (Base + SDHCI_CLK_CTRL, > + MmioRead16 (Base + SDHCI_CLK_CTRL) & ~0x8); // disable PLL_ENABLE > + > + if (MmioRead16 (Base + SDHCI_HOST_CONTROL2) & (1 << 15)) { > + MmioWrite16 (Base + SDHCI_HOST_CONTROL2, > + MmioRead16 (Base + SDHCI_HOST_CONTROL2) & ~0x7); // clr UHS_MODE_SEL > + } else { > + MmioWrite16 (Base + SDHCI_CLK_CTRL, > + (MmioRead16 (Base + SDHCI_CLK_CTRL) & 0xDF) | Div << 8); // set Clk Div > + MmioWrite16 (Base + SDHCI_CLK_CTRL, > + MmioRead16 (Base + SDHCI_CLK_CTRL) & ~(0x1 << 5)); // CLK_GEN_SELECT > + } > + > + MmioWrite16 (Base + SDHCI_CLK_CTRL, > + MmioRead16 (Base + SDHCI_CLK_CTRL) | 0xc); // enable PLL_ENABLE > + > + for (I = 0; I <= 150000; I += 100) { > + if (MmioRead16 (Base + SDHCI_CLK_CTRL) & 0x2) > + return; > + gBS->Stall (100); > + } > + > + DEBUG ((DEBUG_INFO, "%a: SD PLL setting FAILED!\n", __func__)); > +} > + > +/** > + Detect the status of the SD card. > + > + @return The status of the SD card: > + - SDCARD_STATUS_INSERTED: The SD card is inserted. > + - SDCARD_STATUS_NOT_INSERTED: The SD card is not inserted. > + - SDCARD_STATUS_UNKNOWN: The status of the SD card is unknown. > + > +**/ > +INT32 > +BmSdCardDetect ( > + VOID > + ) > +{ > + UINTN Base; > + UINTN Reg; > + > + Base = BmParams.RegBase; > + > + if (BmParams.CardIn != SDCARD_STATUS_UNKNOWN) > + return BmParams.CardIn; > + > + MmioWrite16 (Base + SDHCI_INT_STATUS_EN, > + MmioRead16 (Base + SDHCI_INT_STATUS_EN) | SDHCI_INT_CARD_INSERTION_EN); > + > + Reg = MmioRead32 (Base + SDHCI_PSTATE); > + > + if (Reg & SDHCI_CARD_INSERTED) > + BmParams.CardIn = SDCARD_STATUS_INSERTED; > + else > + BmParams.CardIn = SDCARD_STATUS_NOT_INSERTED; > + > + return BmParams.CardIn; > +} > + > +/** > + SD card hardware initialization. > + > +**/ > +STATIC > +VOID > +SdHwInit ( > + VOID > + ) > +{ > + UINTN Base; > + > + Base = BmParams.RegBase; > + BmParams.VendorBase = Base + (MmioRead16 (Base + P_VENDOR_SPECIFIC_AREA) & ((1 << 12) - 1)); > + > + // deasset reset of phy > + MmioWrite32 (Base + SDHCI_P_PHY_CNFG, MmioRead32 (Base + SDHCI_P_PHY_CNFG) | (1 << PHY_CNFG_PHY_RSTN)); > + > + // reset data & Cmd > + MmioWrite8 (Base + SDHCI_SOFTWARE_RESET, 0x6); > + > + // init common parameters > + MmioWrite8 (Base + SDHCI_PWR_CONTROL, (0x7 << 1)); > + MmioWrite8 (Base + SDHCI_TOUT_CTRL, 0xe); // for TMCLK 50Khz > + MmioWrite16 (Base + SDHCI_HOST_CONTROL2, > + MmioRead16 (Base + SDHCI_HOST_CONTROL2) | 1 << 11); // set cmd23 support > + MmioWrite16 (Base + SDHCI_CLK_CTRL, MmioRead16 (Base + SDHCI_CLK_CTRL) & ~(0x1 << 5)); // divided clock Mode > + > + // set host version 4 parameters > + MmioWrite16 (Base + SDHCI_HOST_CONTROL2, > + MmioRead16 (Base + SDHCI_HOST_CONTROL2) | (1 << 12)); // set HOST_VER4_ENABLE > + if (MmioRead32 (Base + SDHCI_CAPABILITIES1) & (0x1 << 27)) { > + MmioWrite16 (Base + SDHCI_HOST_CONTROL2, > + MmioRead16 (Base + SDHCI_HOST_CONTROL2) | 0x1 << 13); // set 64bit addressing > + } > + > + // if support asynchronous int > + if (MmioRead32 (Base + SDHCI_CAPABILITIES1) & (0x1 << 29)) > + MmioWrite16 (Base + SDHCI_HOST_CONTROL2, > + MmioRead16 (Base + SDHCI_HOST_CONTROL2) | (0x1 << 14)); // enable async int > + // give some time to power down card > + gBS->Stall (20000); > + > + MmioWrite16 (Base + SDHCI_HOST_CONTROL2, > + MmioRead16 (Base + SDHCI_HOST_CONTROL2) & ~(0x1 << 8)); // clr UHS2_IF_ENABLE > + MmioWrite8 (Base + SDHCI_PWR_CONTROL, > + MmioRead8 (Base + SDHCI_PWR_CONTROL) | 0x1); // set SD_BUS_PWR_VDD1 > + MmioWrite16 (Base + SDHCI_HOST_CONTROL2, > + MmioRead16 (Base + SDHCI_HOST_CONTROL2) & ~0x7); // clr UHS_MODE_SEL > + SdSetClk (SDCARD_INIT_FREQ); > + gBS->Stall (50000); > + > + MmioWrite16 (Base + SDHCI_CLK_CTRL, > + MmioRead16 (Base + SDHCI_CLK_CTRL) | (0x1 << 2)); // supply SD clock > + gBS->Stall (400); // wait for voltage ramp up time at least 74 cycle, 400us is 80 cycles for 200Khz > + > + MmioWrite16 (Base + SDHCI_INT_STATUS, MmioRead16 (Base + SDHCI_INT_STATUS) | (0x1 << 6)); > + > + // we enable all interrupt Status here for testing > + MmioWrite16 (Base + SDHCI_INT_STATUS_EN, MmioRead16 (Base + SDHCI_INT_STATUS_EN) | 0xFFFF); > + MmioWrite16 (Base + SDHCI_ERR_INT_STATUS_EN, MmioRead16 (Base + SDHCI_ERR_INT_STATUS_EN) | 0xFFFF); > + > + //verbose("SD init done\n"); > +} > + > +/** > + Set the input/output settings for the SD card. > + > + @param[in] Clk The clock frequency for the SD card. > + @param[in] Width The bus width for data transfer. > + > + @retval EFI_SUCCESS The input/output settings were set successfully. > + @retval EFI_UNSUPPORTED The specified bus width is not supported. > + > +**/ > +EFI_STATUS > +BmSdSetIos ( > + IN UINT32 Clk, > + IN UINT32 Width > + ) > +{ > + switch (Width) { > + case MMC_BUS_WIDTH_1: > + MmioWrite8 (BmParams.RegBase + SDHCI_HOST_CONTROL, > + MmioRead8 (BmParams.RegBase + SDHCI_HOST_CONTROL) & > + ~SDHCI_DAT_XFER_WIDTH); > + break; > + case MMC_BUS_WIDTH_4: > + MmioWrite8 (BmParams.RegBase + SDHCI_HOST_CONTROL, > + MmioRead8 (BmParams.RegBase + SDHCI_HOST_CONTROL) | > + SDHCI_DAT_XFER_WIDTH); > + break; > + default: > + ASSERT (0); > + } > + > + SdChangeClk (Clk); > + > + return EFI_SUCCESS; > +} > + > +/** > + Prepare the SD card for data transfer. > + Set the number and size of data blocks before sending IO commands to the SD card. > + > + @param[in] Lba Logical Block Address. > + @param[in] Buf Buffer Address. > + @param[in] Size Size of Data Blocks. > + > + @retval EFI_SUCCESS The SD card was prepared successfully. > + @retval Other An error occurred during the preparation of the SD card. > + > +**/ > +EFI_STATUS > +BmSdPrepare ( > + IN INT32 Lba, > + IN UINTN Buf, > + IN UINTN Size > + ) > +{ > + UINTN LoadAddr; > + UINTN Base; > + UINT32 BlockCnt; > + UINT32 BlockSize; > + UINT8 Tmp; > + > + LoadAddr = Buf; > + > + if (Size >= MMC_BLOCK_SIZE) { > + // CMD17, 18, 24, 25 > + // ASSERT (((LoadAddr & MMC_BLOCK_MASK) == 0) && ((Size % MMC_BLOCK_SIZE) == 0)); > + BlockSize = MMC_BLOCK_SIZE; > + BlockCnt = Size / MMC_BLOCK_SIZE; > + } else { > + // ACMD51 > + ASSERT (((LoadAddr & 8) == 0) && ((Size % 8) == 0)); > + BlockSize = 8; > + BlockCnt = Size / 8; > + } > + > + Base = BmParams.RegBase; > + > + if (!(BmParams.Flags & SD_USE_PIO)) { > + if (MmioRead16 (Base + SDHCI_HOST_CONTROL2) & SDHCI_HOST_VER4_ENABLE) { > + MmioWrite32 (Base + SDHCI_ADMA_SA_LOW, LoadAddr); > + MmioWrite32 (Base + SDHCI_ADMA_SA_HIGH, (LoadAddr >> 32)); > + MmioWrite32 (Base + SDHCI_DMA_ADDRESS, BlockCnt); > + MmioWrite16 (Base + SDHCI_BLOCK_COUNT, 0); > + } else { > + ASSERT((LoadAddr >> 32) == 0); > + MmioWrite32 (Base + SDHCI_DMA_ADDRESS, LoadAddr); > + MmioWrite16 (Base + SDHCI_BLOCK_COUNT, BlockCnt); > + } > + > + // 512K bytes SDMA buffer boundary > + MmioWrite16 (Base + SDHCI_BLOCK_SIZE, SDHCI_MAKE_BLKSZ(7, BlockSize)); > + > + // select SDMA > + Tmp = MmioRead8 (Base + SDHCI_HOST_CONTROL); > + Tmp &= ~SDHCI_CTRL_DMA_MASK; > + Tmp |= SDHCI_CTRL_SDMA; > + MmioWrite8 (Base + SDHCI_HOST_CONTROL, Tmp); > + } else { > + MmioWrite16 (Base + SDHCI_BLOCK_SIZE, BlockSize); > + MmioWrite16 (Base + SDHCI_BLOCK_COUNT, BlockCnt); > + } > + > + return EFI_SUCCESS; > +} > + > +/** > + SD card sends command to read data blocks. > + > + @param[in] Lba Logical Block Address. > + @param[in] Buf Buffer Address. > + @param[in] Size Size of Data Blocks. > + > + @retval EFI_SUCCESS The command to read data blocks was sent successfully. > + @retval EFI_TIMEOUT The command transmission or data transfer timed out. > + > +**/ > +EFI_STATUS > +BmSdRead ( > + IN INT32 Lba, > + IN UINT32* Buf, > + IN UINTN Size > + ) > +{ > + UINT32 Timeout; > + UINTN Base; > + UINT32 *Data; > + UINT32 BlockSize; > + UINT32 BlockCnt; > + UINT32 Status; > + > + Timeout = 0; > + Base = BmParams.RegBase; > + Data = Buf; > + BlockSize = 0; > + BlockCnt = 0; > + Status = 0; > + > + if (BmParams.Flags & SD_USE_PIO) { > + BlockSize = MmioRead16 (Base + SDHCI_BLOCK_SIZE); > + BlockCnt = Size / BlockSize; > + BlockSize /= 4; > + > + for (INT32 I = 0; I < BlockCnt; ) { > + Status = MmioRead16 (Base + SDHCI_INT_STATUS); > + if ((Status & SDHCI_INT_BUF_RD_READY) && > + (MmioRead32 (Base + SDHCI_PSTATE) & SDHCI_BUF_RD_ENABLE)) { > + MmioWrite16 (Base + SDHCI_INT_STATUS, SDHCI_INT_BUF_RD_READY); > + for (INT32 j = 0; j < BlockSize; j++) { > + *(Data++) = MmioRead32 (Base + SDHCI_BUF_DATA_R); > + } > + > + Timeout = 0; > + I++; > + } else { > + gBS->Stall (1); > + Timeout++; > + } > + > + if (Timeout >= 10000) { > + DEBUG ((DEBUG_INFO, "%a: sdhci read data Timeout\n", __func__)); > + goto Timeout; > + } > + } > + > + Timeout = 0; > + while (1) { > + Status = MmioRead16 (Base + SDHCI_INT_STATUS); > + if (Status & SDHCI_INT_XFER_COMPLETE) { > + MmioWrite16 (Base + SDHCI_INT_STATUS, > + Status | SDHCI_INT_XFER_COMPLETE); > + > + return EFI_SUCCESS; > + } else { > + gBS->Stall (1); > + Timeout++; > + } > + > + if (Timeout >= 10000) { > + DEBUG ((DEBUG_INFO, "%a:wait xfer complete Timeout\n", __func__)); > + goto Timeout; > + } > + } > + } else { > + return EFI_SUCCESS; > + } > + > +Timeout: > + return EFI_TIMEOUT; > + > +} > + > +/** > + SD card sends commands to write data blocks. > + > + @param[in] Lba Logical Block Address. > + @param[in] Buf Buffer Address. > + @param[in] Size Size of Data Blocks. > + > + @retval EFI_SUCCESS The command to write data blocks was sent successfully. > + @retval EFI_TIMEOUT The command transmission or data transfer timed out. > + > +**/ > +EFI_STATUS > +BmSdWrite ( > + IN INT32 Lba, > + IN UINT32* Buf, > + IN UINTN Size > + ) > +{ > + UINT32 Timeout; > + UINTN Base; > + UINT32 *Data; > + UINT32 BlockSize; > + UINT32 BlockCnt; > + UINT32 Status; > + > + Timeout = 0; > + Base = BmParams.RegBase; > + Data = Buf; > + BlockSize = 0; > + BlockCnt = 0; > + Status = 0; > + > + if (BmParams.Flags & SD_USE_PIO) { > + BlockSize = MmioRead16 (Base + SDHCI_BLOCK_SIZE); > + BlockCnt = Size / BlockSize; > + BlockSize /= 4; > + > + for (INT32 j = 0; j < BlockSize; j++) { > + MmioWrite32 (Base + SDHCI_BUF_DATA_R, *(Data++)); > + } > + > + for (INT32 I = 0; I < BlockCnt-1; ) { > + Status = MmioRead16 (Base + SDHCI_INT_STATUS); > + if ((Status & SDHCI_INT_BUF_WR_READY) && > + (MmioRead32 (Base + SDHCI_PSTATE) & > + SDHCI_BUF_WR_ENABLE)) { > + MmioWrite16 (Base + SDHCI_INT_STATUS, SDHCI_INT_BUF_WR_READY); > + for (INT32 j = 0; j < BlockSize; j++) { > + MmioWrite32 (Base + SDHCI_BUF_DATA_R, *(Data++)); > + } > + > + Timeout = 0; > + I++; > + } else { > + gBS->Stall (1); > + Timeout++; > + } > + > + if (Timeout >= 10000000) { > + DEBUG ((DEBUG_INFO, "%a:sdhci write data Timeout\n", __func__)); > + goto Timeout; > + } > + } > + > + Timeout = 0; > + while (1) { > + Status = MmioRead16 (Base + SDHCI_INT_STATUS); > + if (Status & SDHCI_INT_XFER_COMPLETE) { > + MmioWrite16 (Base + SDHCI_INT_STATUS, > + Status | SDHCI_INT_XFER_COMPLETE); > + > + return EFI_SUCCESS; > + } else { > + gBS->Stall (1); > + Timeout++; > + } > + > + if (Timeout >= 10000) { > + DEBUG ((DEBUG_INFO, "%a:wait xfer complete Timeout\n", __func__)); > + goto Timeout; > + } > + } > + } else > + return EFI_SUCCESS; > + > +Timeout: > + return EFI_TIMEOUT; > +} > + > +/** > + Initialize the SD PHY. > + > + This function performs the initialization of the SD PHY hardware. > + > +**/ > +VOID > +SdPhyInit ( > + VOID > + ) > +{ > + UINTN Base; > + INT32 RetryCount; > + > + Base = BmParams.RegBase; > + RetryCount = 100; > + > + // reset hardware > + MmioWrite8 (Base + SDHCI_SOFTWARE_RESET, 0x7); > + while (MmioRead8 (Base + SDHCI_SOFTWARE_RESET)) { > + if (RetryCount-- > 0) > + gBS->Stall (10000); > + else > + break; > + } > + > + // Wait for the PHY power on ready > + RetryCount = 100; > + while (!(MmioRead32 (Base + SDHCI_P_PHY_CNFG) & (1 << PHY_CNFG_PHY_PWRGOOD))) { > + if (RetryCount-- > 0) > + gBS->Stall (10000); > + else > + break; > + } > + > + // Asset reset of phy > + MmioAnd32 (Base + SDHCI_P_PHY_CNFG, ~(1 << PHY_CNFG_PHY_RSTN)); > + > + // Set PAD_SN PAD_SP > + MmioWrite32 (Base + SDHCI_P_PHY_CNFG, > + (1 << PHY_CNFG_PHY_PWRGOOD) | (0x9 << PHY_CNFG_PAD_SP) | (0x8 << PHY_CNFG_PAD_SN)); > + > + // Set CMDPAD > + MmioWrite16 (Base + SDHCI_P_CMDPAD_CNFG, > + (0x2 << PAD_CNFG_RXSEL) | (1 << PAD_CNFG_WEAKPULL_EN) | > + (0x3 << PAD_CNFG_TXSLEW_CTRL_P) | (0x2 << PAD_CNFG_TXSLEW_CTRL_N)); > + > + // Set DATAPAD > + MmioWrite16 (Base + SDHCI_P_DATPAD_CNFG, > + (0x2 << PAD_CNFG_RXSEL) | (1 << PAD_CNFG_WEAKPULL_EN) | > + (0x3 << PAD_CNFG_TXSLEW_CTRL_P) | (0x2 << PAD_CNFG_TXSLEW_CTRL_N)); > + > + // Set CLKPAD > + MmioWrite16 (Base + SDHCI_P_CLKPAD_CNFG, > + (0x2 << PAD_CNFG_RXSEL) | (0x3 << PAD_CNFG_TXSLEW_CTRL_P) | (0x2 << PAD_CNFG_TXSLEW_CTRL_N)); > + > + // Set STB_PAD > + MmioWrite16 (Base + SDHCI_P_STBPAD_CNFG, > + (0x2 << PAD_CNFG_RXSEL) | (0x2 << PAD_CNFG_WEAKPULL_EN) | > + (0x3 << PAD_CNFG_TXSLEW_CTRL_P) | (0x2 << PAD_CNFG_TXSLEW_CTRL_N)); > + > + // Set RSTPAD > + MmioWrite16 (Base + SDHCI_P_RSTNPAD_CNFG, > + (0x2 << PAD_CNFG_RXSEL) | (1 << PAD_CNFG_WEAKPULL_EN) | > + (0x3 << PAD_CNFG_TXSLEW_CTRL_P) | (0x2 << PAD_CNFG_TXSLEW_CTRL_N)); > + > + // Set SDCLKDL_CNFG, EXTDLY_EN = 1, fix delay > + MmioWrite8 (Base + SDHCI_P_SDCLKDL_CNFG, (1 << SDCLKDL_CNFG_EXTDLY_EN)); > + > + // Set SMPLDL_CNFG, Bypass > + MmioWrite8 (Base + SDHCI_P_SMPLDL_CNFG, (1 << SMPLDL_CNFG_BYPASS_EN)); > + > + // Set ATDL_CNFG, tuning Clk not use for init > + MmioWrite8 (Base + SDHCI_P_ATDL_CNFG, (2 << ATDL_CNFG_INPSEL_CNFG)); > + > + return; > +} > + > +/** > + Initialize the SD card. > + > + This function performs the initialization of the SD card hardware and settings. > + > + @param[in] Flags Initialization flags. > + > + @retval EFI_SUCCESS The SD card was initialized successfully. > + > +**/ > +EFI_STATUS > +SdInit ( > + IN UINT32 Flags > +) > +{ > + BmParams.ClkRate = BmGetSdClk (); > + > + DEBUG ((DEBUG_INFO, "SD initializing %dHz\n", BmParams.ClkRate)); > + > + BmParams.Flags = Flags; > + > + SdPhyInit (); > + > + SdHwInit (); > + > + return EFI_SUCCESS; > +} > diff --git a/Silicon/Sophgo/SG2042Pkg/Drivers/SdHostDxe/SdHostDxe.c b/Silicon/Sophgo/SG2042Pkg/Drivers/SdHostDxe/SdHostDxe.c > new file mode 100644 > index 000000000000..3bb04344320a > --- /dev/null > +++ b/Silicon/Sophgo/SG2042Pkg/Drivers/SdHostDxe/SdHostDxe.c > @@ -0,0 +1,450 @@ > +/** @file > + This file implements the SD host controller driver for UEFI systems. > + The file contains the implementation of the EFI_MMC_HOST_PROTOCOL, which provides > + the necessary interfaces for handling communication and data transfer with SD cards. > + > + Copyright (c) 2017, Andrei Warkentin <andrey.warkentin@gmail.com> > + Copyright (c) Microsoft Corporation. All rights reserved. > + Copyright (c) 2023, Academy of Intelligent Innovation, Shandong Universiy, China.P.R. All rights reserved.<BR> > + SPDX-License-Identifier: BSD-2-Clause-Patent > + > +**/ > + > +#include <Uefi.h> > +#include <Library/BaseLib.h> > +#include <Library/MemoryAllocationLib.h> > +#include <Library/DebugLib.h> > +#include <Library/DevicePathLib.h> > +#include <Library/IoLib.h> > +#include <Library/PcdLib.h> > +#include <Library/UefiBootServicesTableLib.h> > +#include <Library/BaseMemoryLib.h> > +#include <Library/DmaLib.h> > +#include <Library/TimerLib.h> > + > +#include <Protocol/EmbeddedExternalDevice.h> > +#include <Protocol/BlockIo.h> > +#include <Protocol/DevicePath.h> > +#include <Include/MmcHost.h> > + > +#include "SdHci.h" > + > +#define SDHOST_BLOCK_BYTE_LENGTH 512 > + > +#define DEBUG_MMCHOST_SD DEBUG_VERBOSE > +#define DEBUG_MMCHOST_SD_INFO DEBUG_INFO > +#define DEBUG_MMCHOST_SD_ERROR DEBUG_ERROR > + > +STATIC BOOLEAN mCardIsPresent = FALSE; > +STATIC CARD_DETECT_STATE mCardDetectState = CardDetectRequired; > +BM_SD_PARAMS BmParams; > + > +/** > + Check if the SD card is read-only. > + > + @param[in] This Pointer to the EFI_MMC_HOST_PROTOCOL instance. > + > + @retval FALSE The SD card is not read-only. > + > +**/ > +STATIC > +BOOLEAN > +SdIsReadOnly ( > + IN EFI_MMC_HOST_PROTOCOL *This > + ) > +{ > + return FALSE; > +} > + > +/** > + Build the device path for the SD card. > + > + @param[in] This Pointer to the EFI_MMC_HOST_PROTOCOL instance. > + @param[out] DevicePath Pointer to the location to store the newly created device path. > + > + @retval EFI_SUCCESS The device path is built successfully. > + > +**/ > +STATIC > +EFI_STATUS > +SdBuildDevicePath ( > + IN EFI_MMC_HOST_PROTOCOL *This, > + OUT EFI_DEVICE_PATH_PROTOCOL **DevicePath > + ) > +{ > + EFI_DEVICE_PATH_PROTOCOL *NewDevicePathNode; > + EFI_GUID DevicePathGuid = EFI_CALLER_ID_GUID; > + > + DEBUG ((DEBUG_MMCHOST_SD, "SdHost: SdBuildDevicePath ()\n")); > + > + NewDevicePathNode = CreateDeviceNode (HARDWARE_DEVICE_PATH, HW_VENDOR_DP, sizeof (VENDOR_DEVICE_PATH)); > + CopyGuid (&((VENDOR_DEVICE_PATH*)NewDevicePathNode)->Guid, &DevicePathGuid); > + *DevicePath = NewDevicePathNode; > + > + return EFI_SUCCESS; > +} > + > +/** > + Send a command to the SD card. > + > + @param[in] This Pointer to the EFI_MMC_HOST_PROTOCOL instance. > + @param[in] MmcCmd The MMC command to send. > + @param[in] Argument The argument for the command. > + @param[in] Type The type of response expected. > + @param[in] Buffer Pointer to the buffer to store the response. > + > + @retval EFI_SUCCESS The command was sent successfully and the response was retrieved. > + @retval Other An error occurred while sending a command. > +**/ > +STATIC > +EFI_STATUS > +SdSendCommand ( > + IN EFI_MMC_HOST_PROTOCOL *This, > + IN MMC_IDX MmcCmd, > + IN UINT32 Argument, > + IN MMC_RESPONSE_TYPE Type, > + IN UINT32* Buffer > + ) > +{ > + EFI_STATUS Status; > + > + Status = BmSdSendCmd (MmcCmd, Argument, Type, Buffer); > + > + if (EFI_ERROR (Status)) { > + DEBUG ((DEBUG_MMCHOST_SD_ERROR, "SdSendCommand Error, Status=%r.\n", Status)); > + return Status; > + } > + > + return EFI_SUCCESS; > +} > + > +/** > + Read block data from an SD card. > + > + @param[in] This Pointer to the EFI_MMC_HOST_PROTOCOL instance. > + @param[in] Lba Logical Block Address of the starting block to read. > + @param[in] Length Number of blocks to read. > + @param[in] Buffer Pointer to the buffer to store the read data. > + > + @retval EFI_SUCCESS The operation completed successfully. > + @retval Other The operation failed. > + > +**/ > +STATIC > +EFI_STATUS > +SdReadBlockData ( > + IN EFI_MMC_HOST_PROTOCOL *This, > + IN EFI_LBA Lba, > + IN UINTN Length, > + OUT UINT32* Buffer > + ) > +{ > + EFI_STATUS Status; > + > + ASSERT (Buffer != NULL); > + ASSERT (Length % 4 == 0); > + > + Status = BmSdRead (Lba, Buffer, Length); > + > + if (EFI_ERROR (Status)) { > + DEBUG ((DEBUG_MMCHOST_SD_ERROR, "SdReadBlockData Error, Status=%r.\n", Status)); > + return Status; > + } > + > + return EFI_SUCCESS; > +} > + > +/** > + Write block data to an SD card. > + > + @param[in] This Pointer to the EFI_MMC_HOST_PROTOCOL instance. > + @param[in] Lba Logical Block Address of the starting block to write. > + @param[in] Length Number of blocks to write. > + @param[in] Buffer Pointer to the buffer containing the data to be written. > + > + @retval EFI_SUCCESS The operation completed successfully. > + @retval Other The operation failed. > + > +**/ > +STATIC > +EFI_STATUS > +SdWriteBlockData ( > + IN EFI_MMC_HOST_PROTOCOL *This, > + IN EFI_LBA Lba, > + IN UINTN Length, > + IN UINT32* Buffer > + ) > +{ > + EFI_STATUS Status; > + > + DEBUG ((DEBUG_MMCHOST_SD, "SdHost: SdWriteBlockData(LBA: 0x%x, Length: 0x%x, Buffer: 0x%x)\n",(UINT32)Lba, Length, Buffer)); > + > + ASSERT (Buffer != NULL); > + ASSERT (Length % SDHOST_BLOCK_BYTE_LENGTH == 0); > + > + Status = BmSdWrite (Lba, Buffer, Length); > + > + if (EFI_ERROR (Status)) { > + DEBUG ((DEBUG_MMCHOST_SD_ERROR, "SdWriteBlockData Error, Status=%r.\n", Status)); > + return Status; > + } > + > + return EFI_SUCCESS; > +} > + > +/** > + Set the I/O settings for an SD card. > + > + @param[in] This Pointer to the EFI_MMC_HOST_PROTOCOL instance. > + @param[in] BusClockFreq Bus clock frequency in Hz. > + @param[in] BusWidth Bus width setting. > + > + @retval EFI_SUCCESS The operation completed successfully. > + @retval Other The operation failed. > + > +**/ > +STATIC > +EFI_STATUS > +SdSetIos ( > + IN EFI_MMC_HOST_PROTOCOL *This, > + IN UINT32 BusClockFreq, > + IN UINT32 BusWidth > + ) > +{ > + EFI_STATUS Status; > + > + DEBUG ((DEBUG_MMCHOST_SD_INFO, "%a: Setting Freq %u Hz\n", __func__, BusClockFreq)); > + DEBUG ((DEBUG_MMCHOST_SD_INFO, "%a: Setting BusWidth %u\n", __func__, BusWidth)); > + > + Status = BmSdSetIos (BusClockFreq,BusWidth); > + > + if (EFI_ERROR (Status)) { > + DEBUG ((DEBUG_MMCHOST_SD_ERROR, "SdSetIos Error, Status=%r.\n", Status)); > + return Status; > + } > + > + return EFI_SUCCESS; > +} > + > +/** > + Prepare the SD card for data transfer. > + > + @param[in] This Pointer to the EFI_MMC_HOST_PROTOCOL instance. > + @param[in] Lba Logical Block Address of the starting block to prepare. > + @param[in] Length Number of blocks to prepare. > + @param[in] Buffer Buffer containing the data to be prepared. > + > + @retval EFI_SUCCESS The operation completed successfully. > + @retval Other The operation failed. > + > +**/ > +STATIC > +EFI_STATUS > +SdPrepare ( > + IN EFI_MMC_HOST_PROTOCOL *This, > + IN EFI_LBA Lba, > + IN UINTN Length, > + IN UINTN Buffer > + ) > +{ > + EFI_STATUS Status; > + > + Status = BmSdPrepare (Lba, Buffer, Length); > + > + if (EFI_ERROR (Status)) { > + DEBUG ((DEBUG_MMCHOST_SD_ERROR, "SdPrepare Error, Status=%r.\n", Status)); > + return Status; > + } > + > + return EFI_SUCCESS; > +} > + > +/** > + Notify the state of the SD card. > + > + @param[in] This Pointer to the EFI_MMC_HOST_PROTOCOL instance. > + @param[in] State State of the SD card. > + > + @retval EFI_SUCCESS The operation completed successfully. > + @retval EFI_NOT_READY The card detection has not completed yet. > + @retval Other The operation failed. > + > +**/ > +STATIC > +EFI_STATUS > +SdNotifyState ( > + IN EFI_MMC_HOST_PROTOCOL *This, > + IN MMC_STATE State > + ) > +{ > + // Stall all operations except init until card detection has occurred. > + if (State != MmcHwInitializationState && mCardDetectState != CardDetectCompleted) { > + return EFI_NOT_READY; > + } > + > + switch (State) { > + case MmcHwInitializationState: > + DEBUG ((DEBUG_MMCHOST_SD, "MmcHwInitializationState\n", State)); > + > + EFI_STATUS Status = SdInit (SD_USE_PIO); > + if (EFI_ERROR (Status)) { > + DEBUG ((DEBUG_MMCHOST_SD_ERROR,"SdHost: SdNotifyState(): Fail to initialize!\n")); > + return Status; > + } > + break; > + case MmcIdleState: > + DEBUG ((DEBUG_MMCHOST_SD, "MmcIdleState\n", State)); > + break; > + case MmcReadyState: > + DEBUG ((DEBUG_MMCHOST_SD, "MmcReadyState\n", State)); > + break; > + case MmcIdentificationState: > + DEBUG ((DEBUG_MMCHOST_SD, "MmcIdentificationState\n", State)); > + break; > + case MmcStandByState: > + DEBUG ((DEBUG_MMCHOST_SD, "MmcStandByState\n", State)); > + break; > + case MmcTransferState: > + DEBUG ((DEBUG_MMCHOST_SD, "MmcTransferState\n", State)); > + break; > + case MmcSendingDataState: > + DEBUG ((DEBUG_MMCHOST_SD, "MmcSendingDataState\n", State)); > + break; > + case MmcReceiveDataState: > + DEBUG ((DEBUG_MMCHOST_SD, "MmcReceiveDataState\n", State)); > + break; > + case MmcProgrammingState: > + DEBUG ((DEBUG_MMCHOST_SD, "MmcProgrammingState\n", State)); > + break; > + case MmcDisconnectState: > + case MmcInvalidState: > + default: > + DEBUG ((DEBUG_MMCHOST_SD_ERROR, "SdHost: SdNotifyState(): Invalid State: %d\n", State)); > + ASSERT (0); > + } > + > + return EFI_SUCCESS; > +} > + > +/** > + Check if an SD card is present. > + > + @param[in] This Pointer to the EFI_MMC_HOST_PROTOCOL instance. > + > + @retval TRUE An SD card is present. > + @retval FALSE No SD card is present. > + > +**/ > +STATIC > +BOOLEAN > +SdIsCardPresent ( > + IN EFI_MMC_HOST_PROTOCOL *This > + ) > +{ > + // > + // If we are already in progress (we may get concurrent calls) > + // or completed the detection, just return the current value. > + // > + if (mCardDetectState != CardDetectRequired) { > + return mCardIsPresent; > + } > + > + mCardDetectState = CardDetectInProgress; > + mCardIsPresent = FALSE; > + > + if (BmSdCardDetect () == 1) { > + mCardIsPresent = TRUE; > + goto out; > + } > + else { > + DEBUG ((DEBUG_MMCHOST_SD_ERROR, "SdIsCardPresent: Error SdCardDetect.\n")); > + mCardDetectState = CardDetectRequired; > + return FALSE; > + } > + > + DEBUG ((DEBUG_MMCHOST_SD_INFO, "SdIsCardPresent: Not detected.\n")); > + > +out: > + mCardDetectState = CardDetectCompleted; > + return mCardIsPresent; > +} > + > +/** > + Check if the SD card supports multi-block transfers. > + > + @param[in] This Pointer to the EFI_MMC_HOST_PROTOCOL instance. > + > + @retval TRUE The SD card supports multi-block transfers. > + > +**/ > +BOOLEAN > +SdIsMultiBlock ( > + IN EFI_MMC_HOST_PROTOCOL *This > + ) > +{ > + return TRUE; > +} > + > +EFI_MMC_HOST_PROTOCOL gMmcHost = { > + MMC_HOST_PROTOCOL_REVISION, > + SdIsCardPresent, > + SdIsReadOnly, > + SdBuildDevicePath, > + SdNotifyState, > + SdSendCommand, > + SdReadBlockData, > + SdWriteBlockData, > + SdSetIos, > + SdPrepare, > + SdIsMultiBlock > +}; > + > +/** > + Initialize the SD host. > + > + @param[in] ImageHandle The image handle. > + @param[in] SystemTable The system table. > + > + @retval EFI_SUCCESS The operation completed successfully. > + @retval Other The operation failed. > +**/ > +EFI_STATUS > +SdHostInitialize ( > + IN EFI_HANDLE ImageHandle, > + IN EFI_SYSTEM_TABLE *SystemTable > + ) > +{ > + EFI_STATUS Status; > + EFI_HANDLE Handle; > + UINTN Base; > + > + DEBUG ((DEBUG_MMCHOST_SD, "SdHost: Initialize\n")); > + > + Handle = NULL; > + Base = SDIO_BASE; > + > + if(!PcdGetBool (PcdForceNoMMU)){ > + for (INT32 I = 39; I < 64; I++) { > + if (Base & (1ULL << 38)) { > + Base |= (1ULL << I); > + } else { > + Base &= ~(1ULL << I); > + } > + } > + } > + > + BmParams.RegBase = Base; > + BmParams.ClkRate = 50 * 1000 * 1000; > + BmParams.BusWidth = MMC_BUS_WIDTH_4; > + BmParams.Flags = 0; > + BmParams.CardIn = SDCARD_STATUS_UNKNOWN; > + > + Status = gBS->InstallMultipleProtocolInterfaces ( > + &Handle, > + &gSophgoMmcHostProtocolGuid, > + &gMmcHost, > + NULL > + ); > + ASSERT_EFI_ERROR (Status); > + return Status; > +} > -- > 2.34.1 > -=-=-=-=-=-=-=-=-=-=-=- Groups.io Links: You receive all messages sent to this group. View/Reply Online (#108729): https://edk2.groups.io/g/devel/message/108729 Mute This Topic: https://groups.io/mt/101213491/1787277 Group Owner: devel+owner@edk2.groups.io Unsubscribe: https://edk2.groups.io/g/devel/leave/3901457/1787277/102458076/xyzzy [importer@patchew.org] -=-=-=-=-=-=-=-=-=-=-=-
On Thu, Sep 07, 2023 at 06:25:46PM +0800, caiyuqing_hz@163.com wrote: > From: caiyuqing379 <202235273@mail.sdu.edu.cn> > > This driver implements Sophgo SDHCI controller, which provides > the necessary interfaces for handling communication and data > transfer with SD cards. > > Signed-off-by: caiyuqing379 <202235273@mail.sdu.edu.cn> > Co-authored-by: USER0FISH <libing1202@outlook.com> > Cc: dahogn <dahogn@hotmail.com> > Cc: meng-cz <mengcz1126@gmail.com> > Cc: yli147 <yong.li@intel.com> > Cc: ChaiEvan <evan.chai@intel.com> > Cc: Sunil V L <sunilvl@ventanamicro.com> > Cc: Leif Lindholm <quic_llindhol@quicinc.com> > --- > .../SG2042Pkg/Drivers/SdHostDxe/SdHostDxe.inf | 47 + > .../SG2042Pkg/Drivers/SdHostDxe/SdHci.h | 309 ++++++ > .../SG2042Pkg/Drivers/SdHostDxe/SdHci.c | 929 ++++++++++++++++++ > .../SG2042Pkg/Drivers/SdHostDxe/SdHostDxe.c | 450 +++++++++ > 4 files changed, 1735 insertions(+) > create mode 100644 Silicon/Sophgo/SG2042Pkg/Drivers/SdHostDxe/SdHostDxe.inf > create mode 100644 Silicon/Sophgo/SG2042Pkg/Drivers/SdHostDxe/SdHci.h > create mode 100755 Silicon/Sophgo/SG2042Pkg/Drivers/SdHostDxe/SdHci.c > create mode 100644 Silicon/Sophgo/SG2042Pkg/Drivers/SdHostDxe/SdHostDxe.c > > diff --git a/Silicon/Sophgo/SG2042Pkg/Drivers/SdHostDxe/SdHostDxe.inf b/Silicon/Sophgo/SG2042Pkg/Drivers/SdHostDxe/SdHostDxe.inf > new file mode 100644 > index 000000000000..f4f51d8fde74 > --- /dev/null > +++ b/Silicon/Sophgo/SG2042Pkg/Drivers/SdHostDxe/SdHostDxe.inf > @@ -0,0 +1,47 @@ > +## @file > +# Component description file for the SD Host Controller DXE driver module. > +# > +# Copyright (c) 2019, ARM Limited. All rights reserved. > +# Copyright (c) 2017, Andrei Warkentin <andrey.warkentin@gmail.com> > +# Copyright (c) Microsoft Corporation. All rights reserved. > +# Copyright (c) 2023, Academy of Intelligent Innovation, Shandong Universiy, China.P.R. All rights reserved.<BR> > +# SPDX-License-Identifier: BSD-2-Clause-Patent > +# > +# > +## > + > +[Defines] > + INF_VERSION = 0x0001001A Just Curious. Why is INF_VERSION 0x0001001A? As per [1], I think new INF file should have version 1.27. [1] - https://tianocore-docs.github.io/edk2-InfSpecification/draft/2_inf_overview/24_[defines]_section.html#24-defines-section Otherwise, Acked-by: Sunil V L <sunilvl@ventanamicro.com> -=-=-=-=-=-=-=-=-=-=-=- Groups.io Links: You receive all messages sent to this group. View/Reply Online (#108709): https://edk2.groups.io/g/devel/message/108709 Mute This Topic: https://groups.io/mt/101213491/1787277 Group Owner: devel+owner@edk2.groups.io Unsubscribe: https://edk2.groups.io/g/devel/unsub [importer@patchew.org] -=-=-=-=-=-=-=-=-=-=-=-
© 2016 - 2024 Red Hat, Inc.