From nobody Mon Dec 2 14:40:59 2024 Delivered-To: importer@patchew.org Received-SPF: pass (zohomail.com: domain of groups.io designates 66.175.222.108 as permitted sender) client-ip=66.175.222.108; envelope-from=bounce+27952+109601+1787277+3901457@groups.io; helo=mail02.groups.io; Authentication-Results: mx.zohomail.com; dkim=pass; spf=pass (zohomail.com: domain of groups.io designates 66.175.222.108 as permitted sender) smtp.mailfrom=bounce+27952+109601+1787277+3901457@groups.io; dmarc=fail(p=none dis=none) header.from=163.com ARC-Seal: i=1; a=rsa-sha256; t=1697216169; cv=none; d=zohomail.com; s=zohoarc; b=Hnez0tfrzHu+52uwT6FDAIN9DNLAm8We3UtiVnEEoDxsjUKF95eLj1zBsehJAaALMiIUoWaKInXkt1dXjfqb3Av4uqOUi7L00aEyFgQamK2KgJ9uoTMTh1ExnpUo3tgCUcTnvCfnKK23mCkzYknYirQUwLi5h9S5O5mVI55kLTs= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zohomail.com; s=zohoarc; t=1697216169; h=Content-Transfer-Encoding:Cc:Cc:Date:Date:From:From:In-Reply-To:List-Subscribe:List-Id:List-Help:List-Unsubscribe:MIME-Version:Message-ID:Reply-To:Reply-To:References:Sender:Subject:Subject:To:To:Message-Id; bh=MqcVcMJURJ7+KTmtPMxnQMVv4ewUXI92ZCamJlEonas=; b=lAXQv32aVmwVKCusPnknuIuv/WoI74mZybVpem71ZgAMHFvL6EqhyPdHH7jCx2PVHMBmcLZo5JmQog4Nq8c4UsDBPDyPtcTfjIXhqp8WwWyAD1b9ha/UOlHTKZqjg+EQxbvl+I8eouCT+hhu7sIdO2nntSO955T7eMuzJ27sarA= ARC-Authentication-Results: i=1; mx.zohomail.com; dkim=pass; spf=pass (zohomail.com: domain of groups.io designates 66.175.222.108 as permitted sender) smtp.mailfrom=bounce+27952+109601+1787277+3901457@groups.io; dmarc=fail header.from= (p=none dis=none) Received: from mail02.groups.io (mail02.groups.io [66.175.222.108]) by mx.zohomail.com with SMTPS id 169721616922736.02070534359291; Fri, 13 Oct 2023 09:56:09 -0700 (PDT) Return-Path: DKIM-Signature: a=rsa-sha256; bh=Az/9awdxoAEz8uBbH6gjjMUiBTd5A+Nll8D+RCz+t7o=; c=relaxed/simple; d=groups.io; h=From:To:Cc:Subject:Date:Message-Id:In-Reply-To:References:MIME-Version:Precedence:List-Subscribe:List-Help:Sender:List-Id:Mailing-List:Delivered-To:Reply-To:List-Unsubscribe-Post:List-Unsubscribe:Content-Transfer-Encoding; s=20140610; t=1697216168; v=1; b=pWAxrAiJj5dcF/X1sB66Np4zQkc1auqFztjpydXptVb6jyxRKxWvPGIciad7qxzQDhnT5Nfa ao1taF49c6Af8Po6tZZhmu9V2hYjLva/3rbHaElCEwu45qRxLlsZ/OitZj/EchMMlFoIzONbHT0 cETjfxcFW0xog9LdBm14LSH4= X-Received: by 127.0.0.2 with SMTP id Pw4XYY1788612xLNDSxbz1NJ; Fri, 13 Oct 2023 09:56:08 -0700 X-Received: from m12.mail.163.com (m12.mail.163.com [220.181.12.198]) by mx.groups.io with SMTP id smtpd.web10.30852.1697166137179661463 for ; Thu, 12 Oct 2023 20:02:18 -0700 X-Received: from rv-uefi.. (unknown [211.87.236.31]) by zwqz-smtp-mta-g4-3 (Coremail) with SMTP id _____wDXf98ysyhlyRWnAQ--.9337S2; Fri, 13 Oct 2023 11:02:11 +0800 (CST) From: caiyuqing_hz@163.com To: devel@edk2.groups.io Cc: USER0FISH , sunilvl@ventanamicro.com, Leif Lindholm , Michael D Kinney , Inochi Amaoto Subject: [edk2-devel] [PATCH edk2-platforms v5 2/7] Sophgo/SG2042Pkg: Add Sophgo SDHCI driver. Date: Fri, 13 Oct 2023 11:02:08 +0800 Message-Id: In-Reply-To: References: MIME-Version: 1.0 X-CM-TRANSID: _____wDXf98ysyhlyRWnAQ--.9337S2 X-Coremail-Antispam: 1Uf129KBjvAXoWDJr1rXrW5tr4xuw1DWw1ftFb_yoWrKFy5Co Wjqas3Wwn5Jr4Uur1vkwn2gw47XFnYq395XF4Fqry8KFn7JrnagFW5GrWfC34Fq34jyr98 JryfX3s3JrWSyFWUn29KB7ZKAUJUUUUU529EdanIXcx71UUUUU7v73VFW2AGmfu7bjvjm3 AaLaJ3UbIYCTnIWIevJa73UjIFyTuYvjxUcD73DUUUU X-Originating-IP: [211.87.236.31] X-CM-SenderInfo: 5fdl535tlqwslk26il2tof0z/xtbBlxQIxWI0anqNiwAAsO Precedence: Bulk List-Subscribe: List-Help: Sender: devel@edk2.groups.io List-Id: Mailing-List: list devel@edk2.groups.io; contact devel+owner@edk2.groups.io Reply-To: devel@edk2.groups.io,caiyuqing_hz@163.com List-Unsubscribe-Post: List-Unsubscribe=One-Click List-Unsubscribe: X-Gm-Message-State: JIOm0Bnb2wfPpTel6MqQyLjlx1787277AA= Content-Transfer-Encoding: quoted-printable X-ZohoMail-DKIM: pass (identity @groups.io) X-ZM-MESSAGEID: 1697216170084100003 Content-Type: text/plain; charset="utf-8" From: caiyuqing379 This driver implements Sophgo SDHCI controller, which provides the necessary interfaces for handling communication and data transfer with SD cards. Signed-off-by: caiyuqing379 Co-authored-by: USER0FISH Cc: dahogn Cc: meng-cz Cc: yli147 Cc: ChaiEvan Cc: Leif Lindholm Cc: Michael D Kinney Acked-by: Sunil V L --- .../SG2042Pkg/Drivers/SdHostDxe/SdHostDxe.inf | 48 + .../SG2042Pkg/Drivers/SdHostDxe/SdHci.h | 309 ++++++ .../SG2042Pkg/Drivers/SdHostDxe/SdHci.c | 929 ++++++++++++++++++ .../SG2042Pkg/Drivers/SdHostDxe/SdHostDxe.c | 449 +++++++++ 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/Sil= icon/Sophgo/SG2042Pkg/Drivers/SdHostDxe/SdHostDxe.inf new file mode 100644 index 000000000000..0a49e8a71e61 --- /dev/null +++ b/Silicon/Sophgo/SG2042Pkg/Drivers/SdHostDxe/SdHostDxe.inf @@ -0,0 +1,48 @@ +## @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 +# Copyright (c) Microsoft Corporation. All rights reserved. +# Copyright (c) 2023, Academy of Intelligent Innovation, Shandong Univers= iy, China.P.R. All rights reserved.
+# SPDX-License-Identifier: BSD-2-Clause-Patent +# +# +## + +[Defines] + INF_VERSION =3D 0x0001001B + BASE_NAME =3D SdHostDxe + FILE_GUID =3D 11322596-DD4F-47FA-9E6C-CE787E11E4B1 + MODULE_TYPE =3D UEFI_DRIVER + VERSION_STRING =3D 1.0 + ENTRY_POINT =3D SdHostInitialize + +[Sources] + SdHci.c + SdHci.h + SdHostDxe.c + +[Packages] + EmbeddedPkg/EmbeddedPkg.dec + MdePkg/MdePkg.dec + MdeModulePkg/MdeModulePkg.dec + UefiCpuPkg/UefiCpuPkg.dec + Silicon/Sophgo/SG2042Pkg/SG2042Pkg.dec + +[LibraryClasses] + BaseLib + DebugLib + IoLib + MemoryAllocationLib + UefiBootServicesTableLib + UefiDriverEntryPoint + UefiLib + UefiRuntimeServicesTableLib + +[Protocols] + gSophgoMmcHostProtocolGuid ## PRODUCES + +[FixedPcd] + gSophgoSG2042PlatformPkgTokenSpaceGuid.PcdSG2042SDIOBase ## CONSU= MES + gUefiCpuPkgTokenSpaceGuid.PcdCpuRiscVMmuMaxSatpMode ## CONSU= MES diff --git a/Silicon/Sophgo/SG2042Pkg/Drivers/SdHostDxe/SdHci.h b/Silicon/S= ophgo/SG2042Pkg/Drivers/SdHostDxe/SdHci.h new file mode 100644 index 000000000000..e661124666e2 --- /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 con= trollers. + + Copyright (c) 2016-2017, ARM Limited and Contributors. All rights reserv= ed. + Copyright (c) 2023, Academy of Intelligent Innovation, Shandong Universi= y, China.P.R. All rights reserved.
+ SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#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 t= ransmission or response handling. + @retval EFI_TIMEOUT The command transmission or response ha= ndling 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 unkn= own. + +**/ +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 succe= ssfully. + @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 sen= t successfully. + @retval EFI_TIMEOUT The command transmission or data transf= er 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 se= nt successfully. + @retval EFI_TIMEOUT The command transmission or data transf= er 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 se= ttings. + + @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/S= ophgo/SG2042Pkg/Drivers/SdHostDxe/SdHci.c new file mode 100755 index 000000000000..dc4b27c453db --- /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 Con= troller Interface (SDHCI). + + Copyright (c) 2016-2017, ARM Limited and Contributors. All rights reserv= ed. + Copyright (c) 2023, Academy of Intelligent Innovation, Shandong Universi= y, China.P.R. All rights reserved.
+ SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#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 tr= ansmission or response handling. + @retval EFI_TIMEOUT The command transmission or response han= dling timed out. + +**/ +STATIC +EFI_STATUS +SdSendCmdWithData ( + IN OUT MMC_CMD *Cmd + ) +{ + UINTN Base; + UINT32 Mode; + UINT32 State; + UINT32 DmaAddr; + UINT32 Flags; + UINT32 Timeout; + + Base =3D BmParams.RegBase; + Mode =3D 0; + Flags =3D 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 =3D SDHCI_TRNS_BLK_CNT_EN | SDHCI_TRNS_MULTI | SDHCI_TRNS_READ; + if (!(BmParams.Flags & SD_USE_PIO)) + Mode |=3D SDHCI_TRNS_DMA; + break; + case MMC_CMD24: + case MMC_CMD25: + Mode =3D (SDHCI_TRNS_BLK_CNT_EN | SDHCI_TRNS_MULTI) & ~SDHCI_TRNS_RE= AD; + if (!(BmParams.Flags & SD_USE_PIO)) + Mode |=3D 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 =3D=3D MMC_CMD0) + Flags |=3D SDHCI_CMD_RESP_NONE; + else { + if (Cmd->ResponseType & MMC_RSP_136) + Flags |=3D SDHCI_CMD_RESP_LONG; + else + Flags |=3D SDHCI_CMD_RESP_SHORT; + if (Cmd->ResponseType & MMC_RSP_CRC) + Flags |=3D SDHCI_CMD_CRC; + if (Cmd->ResponseType & MMC_RSP_CMD_IDX) + Flags |=3D SDHCI_CMD_INDEX; + } + + Flags |=3D 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) =3D= =3D 0) { + Timeout =3D 100000; + while (1) { + State =3D 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_COMPLE= TE); + break; + } + + gBS->Stall (1); + if (!Timeout--) { + DEBUG ((DEBUG_ERROR, "%a: Timeout!\n", __func__)); + return EFI_TIMEOUT; + } + } + + // get Cmd respond + if (Flags !=3D SDHCI_CMD_RESP_NONE) + Cmd->Response[0] =3D MmioRead32 (Base + SDHCI_RESPONSE_01); + if (Flags & SDHCI_CMD_RESP_LONG) { + Cmd->Response[1] =3D MmioRead32 (Base + SDHCI_RESPONSE_23); + Cmd->Response[2] =3D MmioRead32 (Base + SDHCI_RESPONSE_45); + Cmd->Response[3] =3D MmioRead32 (Base + SDHCI_RESPONSE_67); + } + } + + // check dma/transfer complete + if (!(BmParams.Flags & SD_USE_PIO)) { + while (1) { + State =3D 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_ENAB= LE) { + DmaAddr =3D MmioRead32 (Base + SDHCI_ADMA_SA_LOW); + MmioWrite32 (Base + SDHCI_ADMA_SA_LOW, DmaAddr); + MmioWrite32 (Base + SDHCI_ADMA_SA_HIGH, 0); + } else { + DmaAddr =3D 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 tr= ansmission or response handling. + @retval EFI_TIMEOUT The command transmission or response han= dling timed out. + +**/ +STATIC +EFI_STATUS +SdSendCmdWithoutData ( + IN OUT MMC_CMD *Cmd + ) +{ + UINTN Base; + UINT32 State; + UINT32 Flags; + UINT32 Timeout; + + Base =3D BmParams.RegBase; + Flags =3D 0x0; + Timeout =3D 10000; + + // make sure Cmd line is clear + while (1) { + if (!(MmioRead32 (Base + SDHCI_PSTATE) & SDHCI_CMD_INHIBIT)) + break; + } + + // set Cmd Flags + if (Cmd->CmdIdx =3D=3D MMC_CMD0) + Flags |=3D SDHCI_CMD_RESP_NONE; + else if (Cmd->CmdIdx =3D=3D MMC_CMD1) + Flags |=3D SDHCI_CMD_RESP_SHORT; + else if (Cmd->CmdIdx =3D=3D MMC_ACMD41) + Flags |=3D SDHCI_CMD_RESP_SHORT; + else { + if (Cmd->ResponseType & MMC_RSP_136) + Flags |=3D SDHCI_CMD_RESP_LONG; + else + Flags |=3D SDHCI_CMD_RESP_SHORT; + if (Cmd->ResponseType & MMC_RSP_CRC) + Flags |=3D SDHCI_CMD_CRC; + if (Cmd->ResponseType & MMC_RSP_CMD_IDX) + Flags |=3D SDHCI_CMD_INDEX; + } + + // make sure dat line is clear if necessary + if (Flags !=3D 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 =3D 100000; + while (1) { + State =3D 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] =3D MmioRead32 (Base + SDHCI_RESPONSE_01); + if (Flags & SDHCI_CMD_RESP_LONG) { + Cmd->Response[1] =3D MmioRead32 (Base + SDHCI_RESPONSE_23); + Cmd->Response[2] =3D MmioRead32 (Base + SDHCI_RESPONSE_45); + Cmd->Response[3] =3D 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 t= ransmission or response handling. + @retval EFI_TIMEOUT The command transmission or response ha= ndling 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=3D%d, Arg=3D0x%x, ResponseTyp= e=3D0x%x\n", __func__, Idx, Arg, RespType)); + + ZeroMem(&Cmd,sizeof(MMC_CMD)); + + Cmd.CmdIdx =3D Idx; + Cmd.CmdArg =3D Arg; + Cmd.ResponseType =3D RespType; + + switch (Cmd.CmdIdx) { + case MMC_CMD17: + case MMC_CMD18: + case MMC_CMD24: + case MMC_CMD25: + case MMC_ACMD51: + Status =3D SdSendCmdWithData(&Cmd); + break; + default: + Status =3D SdSendCmdWithoutData(&Cmd); + } + + if ((Status =3D=3D EFI_SUCCESS) && (Response !=3D NULL)) { + for (INT32 I =3D 0; I < 4; I++) { + *Response =3D 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 <=3D Clk) { + Div =3D 0; + } else { + for (Div =3D 0x1; Div < 0xFF; Div++) { + if (BmParams.ClkRate / (2 * Div) <=3D Clk) + break; + } + } + ASSERT (Div <=3D 0xFF); + + Base =3D BmParams.RegBase; + if (MmioRead16 (Base + SDHCI_HOST_CONTROL2) & (1 << 15)) { + //verbose("Use SDCLK Preset Value\n"); + } else { + //verbose("Set SDCLK by driver. Div=3D0x%x(%d)\n", Div, Div); + MmioWrite16 (Base + SDHCI_CLK_CTRL, + MmioRead16 (Base + SDHCI_CLK_CTRL) & ~0x9); // disable INTERNA= L_CLK_EN and PLL_ENABLE + MmioWrite16 (Base + SDHCI_CLK_CTRL, + (MmioRead16 (Base + SDHCI_CLK_CTRL) & 0xDF) | Div << 8); // se= t Clk Div + MmioWrite16 (Base + SDHCI_CLK_CTRL, + MmioRead16 (Base + SDHCI_CLK_CTRL) | 0x1); // set INTERNAL_CLK= _EN + + for (I =3D 0; I <=3D 150000; I +=3D 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", __f= unc__)); + ASSERT(0); + } + + MmioWrite16 (Base + SDHCI_CLK_CTRL, MmioRead16 (Base + SDHCI_CLK_CTRL)= | 0x8); // set PLL_ENABLE + + for (I =3D 0; I <=3D 150000; I +=3D 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 <=3D Clk) { + Div =3D 0; + } else { + for (Div =3D 0x1; Div < 0xFF; Div++) { + if (BmParams.ClkRate / (2 * Div) <=3D Clk) + break; + } + } + ASSERT (Div <=3D 0xFF); + + Base =3D BmParams.RegBase; + + MmioWrite16 (Base + SDHCI_CLK_CTRL, + MmioRead16 (Base + SDHCI_CLK_CTRL) & ~(0x1 << 2)); // stop SD cl= ock + + MmioWrite16 (Base + SDHCI_CLK_CTRL, + MmioRead16 (Base + SDHCI_CLK_CTRL) & ~0x8); // disable PLL_ENAB= LE + + if (MmioRead16 (Base + SDHCI_HOST_CONTROL2) & (1 << 15)) { + MmioWrite16 (Base + SDHCI_HOST_CONTROL2, + MmioRead16 (Base + SDHCI_HOST_CONTROL2) & ~0x7); // clr UHS_MO= DE_SEL + } else { + MmioWrite16 (Base + SDHCI_CLK_CTRL, + (MmioRead16 (Base + SDHCI_CLK_CTRL) & 0xDF) | Div << 8); // se= t 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 =3D 0; I <=3D 150000; I +=3D 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 unkn= own. + +**/ +INT32 +BmSdCardDetect ( + VOID + ) +{ + UINTN Base; + UINTN Reg; + + Base =3D BmParams.RegBase; + + if (BmParams.CardIn !=3D SDCARD_STATUS_UNKNOWN) + return BmParams.CardIn; + + MmioWrite16 (Base + SDHCI_INT_STATUS_EN, + MmioRead16 (Base + SDHCI_INT_STATUS_EN) | SDHCI_INT_CARD_INSERTI= ON_EN); + + Reg =3D MmioRead32 (Base + SDHCI_PSTATE); + + if (Reg & SDHCI_CARD_INSERTED) + BmParams.CardIn =3D SDCARD_STATUS_INSERTED; + else + BmParams.CardIn =3D SDCARD_STATUS_NOT_INSERTED; + + return BmParams.CardIn; +} + +/** + SD card hardware initialization. + +**/ +STATIC +VOID +SdHwInit ( + VOID + ) +{ + UINTN Base; + + Base =3D BmParams.RegBase; + BmParams.VendorBase =3D Base + (MmioRead16 (Base + P_VENDOR_SPECIFIC_ARE= A) & ((1 << 12) - 1)); + + // deasset reset of phy + MmioWrite32 (Base + SDHCI_P_PHY_CNFG, MmioRead32 (Base + SDHCI_P_PHY_CNF= G) | (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 cmd2= 3 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 HOS= T_VER4_ENABLE + if (MmioRead32 (Base + SDHCI_CAPABILITIES1) & (0x1 << 27)) { + MmioWrite16 (Base + SDHCI_HOST_CONTROL2, + MmioRead16 (Base + SDHCI_HOST_CONTROL2) | 0x1 << 13); // set 6= 4bit addressing + } + + // if support asynchronous int + if (MmioRead32 (Base + SDHCI_CAPABILITIES1) & (0x1 << 29)) + MmioWrite16 (Base + SDHCI_HOST_CONTROL2, + MmioRead16 (Base + SDHCI_HOST_CONTROL2) | (0x1 << 14)); // ena= ble 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 U= HS2_IF_ENABLE + MmioWrite8 (Base + SDHCI_PWR_CONTROL, + MmioRead8 (Base + SDHCI_PWR_CONTROL) | 0x1); // set SD_BUS_PWR_V= DD1 + 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 c= lock + gBS->Stall (400); // wait for voltage ramp up time at least 74 cycle, 40= 0us is 80 cycles for 200Khz + + MmioWrite16 (Base + SDHCI_INT_STATUS, MmioRead16 (Base + SDHCI_INT_STATU= S) | (0x1 << 6)); + + // we enable all interrupt Status here for testing + MmioWrite16 (Base + SDHCI_INT_STATUS_EN, MmioRead16 (Base + SDHCI_INT_ST= ATUS_EN) | 0xFFFF); + MmioWrite16 (Base + SDHCI_ERR_INT_STATUS_EN, MmioRead16 (Base + SDHCI_ER= R_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 succe= ssfully. + @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 =3D Buf; + + if (Size >=3D MMC_BLOCK_SIZE) { + // CMD17, 18, 24, 25 + // ASSERT (((LoadAddr & MMC_BLOCK_MASK) =3D=3D 0) && ((Size % MMC_BLOC= K_SIZE) =3D=3D 0)); + BlockSize =3D MMC_BLOCK_SIZE; + BlockCnt =3D Size / MMC_BLOCK_SIZE; + } else { + // ACMD51 + ASSERT (((LoadAddr & 8) =3D=3D 0) && ((Size % 8) =3D=3D 0)); + BlockSize =3D 8; + BlockCnt =3D Size / 8; + } + + Base =3D 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) =3D=3D 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 =3D MmioRead8 (Base + SDHCI_HOST_CONTROL); + Tmp &=3D ~SDHCI_CTRL_DMA_MASK; + Tmp |=3D 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 sen= t successfully. + @retval EFI_TIMEOUT The command transmission or data transf= er 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 =3D 0; + Base =3D BmParams.RegBase; + Data =3D Buf; + BlockSize =3D 0; + BlockCnt =3D 0; + Status =3D 0; + + if (BmParams.Flags & SD_USE_PIO) { + BlockSize =3D MmioRead16 (Base + SDHCI_BLOCK_SIZE); + BlockCnt =3D Size / BlockSize; + BlockSize /=3D 4; + + for (INT32 I =3D 0; I < BlockCnt; ) { + Status =3D 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 =3D 0; j < BlockSize; j++) { + *(Data++) =3D MmioRead32 (Base + SDHCI_BUF_DATA_R); + } + + Timeout =3D 0; + I++; + } else { + gBS->Stall (1); + Timeout++; + } + + if (Timeout >=3D 10000) { + DEBUG ((DEBUG_INFO, "%a: sdhci read data Timeout\n", __func__)); + goto Timeout; + } + } + + Timeout =3D 0; + while (1) { + Status =3D 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 >=3D 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 se= nt successfully. + @retval EFI_TIMEOUT The command transmission or data transf= er 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 =3D 0; + Base =3D BmParams.RegBase; + Data =3D Buf; + BlockSize =3D 0; + BlockCnt =3D 0; + Status =3D 0; + + if (BmParams.Flags & SD_USE_PIO) { + BlockSize =3D MmioRead16 (Base + SDHCI_BLOCK_SIZE); + BlockCnt =3D Size / BlockSize; + BlockSize /=3D 4; + + for (INT32 j =3D 0; j < BlockSize; j++) { + MmioWrite32 (Base + SDHCI_BUF_DATA_R, *(Data++)); + } + + for (INT32 I =3D 0; I < BlockCnt-1; ) { + Status =3D 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 =3D 0; j < BlockSize; j++) { + MmioWrite32 (Base + SDHCI_BUF_DATA_R, *(Data++)); + } + + Timeout =3D 0; + I++; + } else { + gBS->Stall (1); + Timeout++; + } + + if (Timeout >=3D 10000000) { + DEBUG ((DEBUG_INFO, "%a:sdhci write data Timeout\n", __func__)); + goto Timeout; + } + } + + Timeout =3D 0; + while (1) { + Status =3D 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 >=3D 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 =3D BmParams.RegBase; + RetryCount =3D 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 =3D 100; + while (!(MmioRead32 (Base + SDHCI_P_PHY_CNFG) & (1 << PHY_CNFG_PHY_PWRGO= OD))) { + 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 =3D 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 se= ttings. + + @param[in] Flags Initialization flags. + + @retval EFI_SUCCESS The SD card was initialized successfully. + +**/ +EFI_STATUS +SdInit ( + IN UINT32 Flags +) +{ + BmParams.ClkRate =3D BmGetSdClk (); + + DEBUG ((DEBUG_INFO, "SD initializing %dHz\n", BmParams.ClkRate)); + + BmParams.Flags =3D Flags; + + SdPhyInit (); + + SdHwInit (); + + return EFI_SUCCESS; +} diff --git a/Silicon/Sophgo/SG2042Pkg/Drivers/SdHostDxe/SdHostDxe.c b/Silic= on/Sophgo/SG2042Pkg/Drivers/SdHostDxe/SdHostDxe.c new file mode 100644 index 000000000000..a59dbb12046d --- /dev/null +++ b/Silicon/Sophgo/SG2042Pkg/Drivers/SdHostDxe/SdHostDxe.c @@ -0,0 +1,449 @@ +/** @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 wi= th SD cards. + + Copyright (c) 2017, Andrei Warkentin + Copyright (c) Microsoft Corporation. All rights reserved. + Copyright (c) 2023, Academy of Intelligent Innovation, Shandong Universi= y, China.P.R. All rights reserved.
+ SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#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 =3D FALSE; +STATIC CARD_DETECT_STATE mCardDetectState =3D 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 cr= eated 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 =3D EFI_CALLER_ID_GUID; + + DEBUG ((DEBUG_MMCHOST_SD, "SdHost: SdBuildDevicePath ()\n")); + + NewDevicePathNode =3D CreateDeviceNode (HARDWARE_DEVICE_PATH, HW_VENDOR_= DP, sizeof (VENDOR_DEVICE_PATH)); + CopyGuid (&((VENDOR_DEVICE_PATH*)NewDevicePathNode)->Guid, &DevicePathGu= id); + *DevicePath =3D 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 =3D BmSdSendCmd (MmcCmd, Argument, Type, Buffer); + + if (EFI_ERROR (Status)) { + DEBUG ((DEBUG_MMCHOST_SD_ERROR, "SdSendCommand Error, Status=3D%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 rea= d. + @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 !=3D NULL); + ASSERT (Length % 4 =3D=3D 0); + + Status =3D BmSdRead (Lba, Buffer, Length); + + if (EFI_ERROR (Status)) { + DEBUG ((DEBUG_MMCHOST_SD_ERROR, "SdReadBlockData Error, Status=3D%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 wri= te. + @param[in] Length Number of blocks to write. + @param[in] Buffer Pointer to the buffer containing the data to be wr= itten. + + @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; + + ASSERT (Buffer !=3D NULL); + ASSERT (Length % SDHOST_BLOCK_BYTE_LENGTH =3D=3D 0); + + Status =3D BmSdWrite (Lba, Buffer, Length); + + if (EFI_ERROR (Status)) { + DEBUG ((DEBUG_MMCHOST_SD_ERROR, "SdWriteBlockData Error, Status=3D%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__, Bus= ClockFreq)); + DEBUG ((DEBUG_MMCHOST_SD_INFO, "%a: Setting BusWidth %u\n", __func__, Bu= sWidth)); + + Status =3D BmSdSetIos (BusClockFreq,BusWidth); + + if (EFI_ERROR (Status)) { + DEBUG ((DEBUG_MMCHOST_SD_ERROR, "SdSetIos Error, Status=3D%r.\n", Stat= us)); + 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 pr= epare. + @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 =3D BmSdPrepare (Lba, Buffer, Length); + + if (EFI_ERROR (Status)) { + DEBUG ((DEBUG_MMCHOST_SD_ERROR, "SdPrepare Error, Status=3D%r.\n", Sta= tus)); + 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 !=3D MmcHwInitializationState && mCardDetectState !=3D CardDet= ectCompleted) { + return EFI_NOT_READY; + } + + switch (State) { + case MmcHwInitializationState: + DEBUG ((DEBUG_MMCHOST_SD, "MmcHwInitializationState\n", State)); + + EFI_STATUS Status =3D SdInit (SD_USE_PIO); + if (EFI_ERROR (Status)) { + DEBUG ((DEBUG_MMCHOST_SD_ERROR,"SdHost: SdNotifyState(): Fail to i= nitialize!\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 St= ate: %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 !=3D CardDetectRequired) { + return mCardIsPresent; + } + + mCardDetectState =3D CardDetectInProgress; + mCardIsPresent =3D FALSE; + + if (BmSdCardDetect () =3D=3D 1) { + mCardIsPresent =3D TRUE; + goto out; + } + else { + DEBUG ((DEBUG_MMCHOST_SD_ERROR, "SdIsCardPresent: Error SdCardDetect.\= n")); + mCardDetectState =3D CardDetectRequired; + return FALSE; + } + + DEBUG ((DEBUG_MMCHOST_SD_INFO, "SdIsCardPresent: Not detected.\n")); + +out: + mCardDetectState =3D 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 =3D { + 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 =3D NULL; + Base =3D SDIO_BASE; + + if(PcdGet32 (PcdCpuRiscVMmuMaxSatpMode) > 0UL){ + for (INT32 I =3D 39; I < 64; I++) { + if (Base & (1ULL << 38)) { + Base |=3D (1ULL << I); + } else { + Base &=3D ~(1ULL << I); + } + } + } + + BmParams.RegBase =3D Base; + BmParams.ClkRate =3D 50 * 1000 * 1000; + BmParams.BusWidth =3D MMC_BUS_WIDTH_4; + BmParams.Flags =3D 0; + BmParams.CardIn =3D SDCARD_STATUS_UNKNOWN; + + Status =3D gBS->InstallMultipleProtocolInterfaces ( + &Handle, + &gSophgoMmcHostProtocolGuid, + &gMmcHost, + NULL + ); + ASSERT_EFI_ERROR (Status); + + return Status; +} --=20 2.34.1 -=3D-=3D-=3D-=3D-=3D-=3D-=3D-=3D-=3D-=3D-=3D- Groups.io Links: You receive all messages sent to this group. View/Reply Online (#109601): https://edk2.groups.io/g/devel/message/109601 Mute This Topic: https://groups.io/mt/101944465/1787277 Group Owner: devel+owner@edk2.groups.io Unsubscribe: https://edk2.groups.io/g/devel/unsub [importer@patchew.org] -=3D-=3D-=3D-=3D-=3D-=3D-=3D-=3D-=3D-=3D-=3D-