From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from mail02.groups.io (mail02.groups.io [66.175.222.108]) by spool.mail.gandi.net (Postfix) with ESMTPS id 5273B78003C for ; Fri, 13 Oct 2023 16:56:15 +0000 (UTC) DKIM-Signature: a=rsa-sha256; bh=lNQburGYYDfFU+uVgHa6CH3ixors1S0Jv9A1WTjphT8=; 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=1697216174; v=1; b=C1xEk+lzLsJs+5FIngA1NKLH9AJh7B0BTvWGon13gOcAf/ylx+NSy1wHD2JUFoIuq5s5tJB9 WimOxpba2810EeKAZH5wYJXb9mkFS1UGz+WhX3w+gBAVBMTBW03b1+0L/wdTFQ6x4/23qU90jpu 9n46cA0bPvUlI51RHn1D6pxA= X-Received: by 127.0.0.2 with SMTP id HnNyYY7687511xUmNxrwkm9Q; Fri, 13 Oct 2023 09:56:14 -0700 X-Received: from m15.mail.163.com (m15.mail.163.com [45.254.50.219]) by mx.groups.io with SMTP id smtpd.web10.30856.1697166154487013366 for ; Thu, 12 Oct 2023 20:02:35 -0700 X-Received: from rv-uefi.. (unknown [211.87.236.31]) by zwqz-smtp-mta-g2-3 (Coremail) with SMTP id _____wD3fydFsyhl+sOpAQ--.27183S2; Fri, 13 Oct 2023 11:02:29 +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 3/7] Sophgo/SG2042Pkg: Add base MMC driver. Date: Fri, 13 Oct 2023 11:02:29 +0800 Message-Id: <56bdeb9835b24135492aee977d773a47ee30bc87.1697120122.git.caiyuqing_hz@outlook.com> In-Reply-To: References: MIME-Version: 1.0 X-CM-TRANSID: _____wD3fydFsyhl+sOpAQ--.27183S2 X-Coremail-Antispam: 1Uf129KBjvAXoWkJr4DJr45AF4xurW3uF4fuFg_yoWDAr1rWo W3Z34ftw4kJr1xZrsxCrykW3y7ZF1rWrsIqr4Fvryqv3ZIqwn5KFyIya1xGa43JryIvr9x GryIq3s5JFZayF18n29KB7ZKAUJUUUUU529EdanIXcx71UUUUU7v73VFW2AGmfu7bjvjm3 AaLaJ3UbIYCTnIWIevJa73UjIFyTuYvjxUcqg4DUUUU X-Originating-IP: [211.87.236.31] X-CM-SenderInfo: 5fdl535tlqwslk26il2tof0z/1tbiKAYIxV7WNZtyPAAAsL 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: wBwySGJonkmhRwzr6pKFTTp9x7686176AA= Content-Transfer-Encoding: 8bit X-GND-Status: LEGIT Authentication-Results: spool.mail.gandi.net; dkim=pass header.d=groups.io header.s=20140610 header.b=C1xEk+lz; dmarc=fail reason="SPF not aligned (relaxed), DKIM not aligned (relaxed)" header.from=163.com (policy=none); spf=pass (spool.mail.gandi.net: domain of bounce@groups.io designates 66.175.222.108 as permitted sender) smtp.mailfrom=bounce@groups.io From: caiyuqing379 This driver implements the MMC Host protocol, which is used by SD interface driver that the Sophgo SG2042 EVB supports. Add this driver in Sophgo/SG2042Pkg leveraging the one form Embedded Package. 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/MmcDxe/MmcDxe.inf | 46 ++ Silicon/Sophgo/SG2042Pkg/Drivers/MmcDxe/Mmc.h | 513 +++++++++++++ Silicon/Sophgo/SG2042Pkg/Include/MmcHost.h | 225 ++++++ .../SG2042Pkg/Drivers/MmcDxe/ComponentName.c | 156 ++++ .../SG2042Pkg/Drivers/MmcDxe/Diagnostics.c | 323 ++++++++ Silicon/Sophgo/SG2042Pkg/Drivers/MmcDxe/Mmc.c | 527 +++++++++++++ .../SG2042Pkg/Drivers/MmcDxe/MmcBlockIo.c | 646 ++++++++++++++++ .../SG2042Pkg/Drivers/MmcDxe/MmcDebug.c | 194 +++++ .../Drivers/MmcDxe/MmcIdentification.c | 719 ++++++++++++++++++ 9 files changed, 3349 insertions(+) create mode 100644 Silicon/Sophgo/SG2042Pkg/Drivers/MmcDxe/MmcDxe.inf create mode 100644 Silicon/Sophgo/SG2042Pkg/Drivers/MmcDxe/Mmc.h create mode 100644 Silicon/Sophgo/SG2042Pkg/Include/MmcHost.h create mode 100644 Silicon/Sophgo/SG2042Pkg/Drivers/MmcDxe/ComponentName.c create mode 100644 Silicon/Sophgo/SG2042Pkg/Drivers/MmcDxe/Diagnostics.c create mode 100644 Silicon/Sophgo/SG2042Pkg/Drivers/MmcDxe/Mmc.c create mode 100644 Silicon/Sophgo/SG2042Pkg/Drivers/MmcDxe/MmcBlockIo.c create mode 100644 Silicon/Sophgo/SG2042Pkg/Drivers/MmcDxe/MmcDebug.c create mode 100644 Silicon/Sophgo/SG2042Pkg/Drivers/MmcDxe/MmcIdentification.c diff --git a/Silicon/Sophgo/SG2042Pkg/Drivers/MmcDxe/MmcDxe.inf b/Silicon/Sophgo/SG2042Pkg/Drivers/MmcDxe/MmcDxe.inf new file mode 100644 index 000000000000..ab16910160be --- /dev/null +++ b/Silicon/Sophgo/SG2042Pkg/Drivers/MmcDxe/MmcDxe.inf @@ -0,0 +1,46 @@ +## @file +# Component description file for the MMC DXE driver module. +# +# Copyright (c) 2011-2015, ARM Limited. All rights reserved. +# Copyright (c) 2023, Academy of Intelligent Innovation, Shandong Universiy, China.P.R. All rights reserved.
+# +# SPDX-License-Identifier: BSD-2-Clause-Patent +# +## + +[Defines] + INF_VERSION = 0x0001001B + BASE_NAME = MmcDxe + FILE_GUID = B5A53998-42AD-4C66-8D2D-1C5FBD175F25 + MODULE_TYPE = DXE_DRIVER + VERSION_STRING = 1.0 + ENTRY_POINT = MmcDxeInitialize + +[Sources.common] + ComponentName.c + Mmc.h + Mmc.c + MmcBlockIo.c + MmcIdentification.c + MmcDebug.c + Diagnostics.c + +[Packages] + MdePkg/MdePkg.dec + Silicon/Sophgo/SG2042Pkg/SG2042Pkg.dec + +[LibraryClasses] + BaseLib + UefiLib + UefiDriverEntryPoint + BaseMemoryLib + +[Protocols] + gEfiDiskIoProtocolGuid ## CONSUMES + gEfiBlockIoProtocolGuid ## PRODUCES + gEfiDevicePathProtocolGuid ## PRODUCES + gEfiDriverDiagnostics2ProtocolGuid ## SOMETIMES_PRODUCES + gSophgoMmcHostProtocolGuid ## CONSUMES + +[Depex] + TRUE diff --git a/Silicon/Sophgo/SG2042Pkg/Drivers/MmcDxe/Mmc.h b/Silicon/Sophgo/SG2042Pkg/Drivers/MmcDxe/Mmc.h new file mode 100644 index 000000000000..6ac59baa82ef --- /dev/null +++ b/Silicon/Sophgo/SG2042Pkg/Drivers/MmcDxe/Mmc.h @@ -0,0 +1,513 @@ +/** @file + Main Header file for the MMC DXE driver + + Copyright (c) 2011-2015, ARM Limited. All rights reserved. + Copyright (c) 2023, Academy of Intelligent Innovation, Shandong Universiy, China.P.R. All rights reserved.
+ + SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#ifndef __MMC_H +#define __MMC_H + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define BIT_32(nr) (1U << (nr)) +#define BIT_64(nr) (1ULL << (nr)) +#define UINT64_C(c) (c ## UL) +#define GENMASK_64(h,l) (((~UINT64_C(0)) << (l)) & (~UINT64_C(0) >> (64 - 1 - (h)))) +#define GENMASK(h,l) GENMASK_64(h,l) + +#define MMC_TRACE(txt) DEBUG((DEBUG_BLKIO, "MMC: " txt "\n")) + +#define MMC_IOBLOCKS_READ 0 +#define MMC_IOBLOCKS_WRITE 1 + +/* Value randomly chosen for eMMC RCA, it should be > 1 */ +#define MMC_FIX_RCA 6 +#define RCA_SHIFT_OFFSET 16 + +#define MMC_OCR_POWERUP BIT31 +#define MMC_OCR_ACCESS_MASK 0x3 /* bit[30-29] */ +#define MMC_OCR_ACCESS_BYTE 0x1 /* bit[29] */ +#define MMC_OCR_ACCESS_SECTOR 0x2 /* bit[30] */ +#define OCR_HCS BIT30 +#define OCR_BYTE_MODE (0U << 29) +#define OCR_SECTOR_MODE (2U << 29) +#define OCR_ACCESS_MODE_MASK (3U << 29) +#define OCR_VDD_MIN_2V7 GENMASK(23, 15) +#define OCR_VDD_MIN_2V0 GENMASK(14, 8) +#define OCR_VDD_MIN_1V7 BIT7 + +/* Value randomly chosen for eMMC RCA, it should be > 1 */ +#define MMC_FIX_RCA 6 +#define RCA_SHIFT_OFFSET 16 + +#define CMD_EXTCSD_PARTITION_CONFIG 179 +#define CMD_EXTCSD_BUS_WIDTH 183 +#define CMD_EXTCSD_HS_TIMING 185 +#define CMD_EXTCSD_PART_SWITCH_TIME 199 +#define CMD_EXTCSD_SEC_CNT 212 + +#define EXTCSD_SET_CMD (0U << 24) +#define EXTCSD_SET_BITS (1U << 24) +#define EXTCSD_CLR_BITS (2U << 24) +#define EXTCSD_WRITE_BYTES (3U << 24) +#define EXTCSD_CMD(x) (((x) & 0xff) << 16) +#define EXTCSD_VALUE(x) (((x) & 0xff) << 8) +#define EXTCSD_CMD_SET_NORMAL 1U + +#define CSD_TRAN_SPEED_UNIT_MASK GENMASK(2, 0) +#define CSD_TRAN_SPEED_MULT_MASK GENMASK(6, 3) +#define CSD_TRAN_SPEED_MULT_SHIFT 3 + +#define MMC_CSD_GET_CCC(Response) (Response[2] >> 20) +#define MMC_CSD_GET_TRANSPEED(Response) (Response[3] & 0xFF) +#define MMC_CSD_GET_READBLLEN(Response) ((Response[2] >> 16) & 0xF) +#define MMC_CSD_GET_WRITEBLLEN(Response) ((Response[0] >> 22) & 0xF) +#define MMC_CSD_GET_FILEFORMAT(Response) ((Response[0] >> 10) & 0x3) +#define MMC_CSD_GET_FILEFORMATGRP(Response) ((Response[0] >> 15) & 0x1) +#define MMC_CSD_GET_DEVICESIZE(csd) (((Response[1] >> 30) & 0x3) | ((Response[2] & 0x3FF) << 2)) +#define HC_MMC_CSD_GET_DEVICESIZE(Response) ((Response[1] >> 16) | ((Response[2] & 0x3F) << 16)); +#define MMC_CSD_GET_DEVICESIZEMULT(csd) ((Response[1] >> 15) & 0x7) + +#define MMC_R0_READY_FOR_DATA (1U << 8) +#define MMC_R0_SWITCH_ERROR (1U << 7) +#define MMC_R0_CURRENTSTATE(Response) ((Response[0] >> 9) & 0xF) +#define MMC_R0_STATE_IDLE 0 +#define MMC_R0_STATE_READY 1 +#define MMC_R0_STATE_IDENT 2 +#define MMC_R0_STATE_STDBY 3 +#define MMC_R0_STATE_TRAN 4 +#define MMC_R0_STATE_DATA 5 +#define MMC_R0_STATE_RECV 6 +#define MMC_R0_STATE_PROG 7 +#define MMC_R0_STATE_DIS 8 + +#define EMMC_CMD6_ARG_ACCESS(x) (((x) & 0x3) << 24) +#define EMMC_CMD6_ARG_INDEX(x) (((x) & 0xFF) << 16) +#define EMMC_CMD6_ARG_VALUE(x) (((x) & 0xFF) << 8) +#define EMMC_CMD6_ARG_CMD_SET(x) (((x) & 0x7) << 0) + +#define SWITCH_CMD_DATA_LENGTH 64 +#define SD_HIGH_SPEED_SUPPORTED 0x200 +#define SD_DEFAULT_SPEED 25000000 +#define SD_HIGH_SPEED 50000000 +#define SWITCH_CMD_SUCCESS_MASK 0xf +#define CMD8_CHECK_PATTERN 0xAAU +#define VHS_2_7_3_6_V BIT8 + +#define SD_SCR_BUS_WIDTH_1 BIT8 +#define SD_SCR_BUS_WIDTH_4 BIT10 + +typedef enum { + UNKNOWN_CARD, + MMC_CARD, //MMC card + MMC_CARD_HIGH, //MMC Card with High capacity + EMMC_CARD, //eMMC 4.41 card + SD_CARD, //SD 1.1 card + SD_CARD_2, //SD 2.0 or above standard card + SD_CARD_2_HIGH //SD 2.0 or above high capacity card +} CARD_TYPE; + +typedef struct { + UINT32 Reserved0: 7; // 0 + UINT32 V170_V195: 1; // 1.70V - 1.95V + UINT32 V200_V260: 7; // 2.00V - 2.60V + UINT32 V270_V360: 9; // 2.70V - 3.60V + UINT32 RESERVED_1: 5; // Reserved + UINT32 AccessMode: 2; // 00b (byte mode), 10b (sector mode) + UINT32 PowerUp: 1; // This bit is set to LOW if the card has not finished the power up routine +} OCR; + +typedef struct { + UINT8 SD_SPEC: 4; // SD Memory Card - Spec. Version [59:56] + UINT8 SCR_STRUCTURE: 4; // SCR Structure [63:60] + UINT8 SD_BUS_WIDTHS: 4; // DAT Bus widths supported [51:48] + UINT8 DATA_STAT_AFTER_ERASE: 1; // Data Status after erases [55] + UINT8 SD_SECURITY: 3; // CPRM Security Support [54:52] + UINT8 EX_SECURITY_1: 1; // Extended Security Support [43] + UINT8 SD_SPEC4: 1; // Spec. Version 4.00 or higher [42] + UINT8 RESERVED_1: 2; // Reserved [41:40] + UINT8 SD_SPEC3: 1; // Spec. Version 3.00 or higher [47] + UINT8 EX_SECURITY_2: 3; // Extended Security Support [46:44] + UINT8 CMD_SUPPORT: 4; // Command Support bits [35:32] + UINT8 RESERVED_2: 4; // Reserved [39:36] + UINT32 RESERVED_3; // Manufacturer Usage [31:0] +} SCR; + +typedef struct { + UINT32 NOT_USED; // 1 [0:0] + UINT32 CRC; // CRC7 checksum [7:1] + + UINT32 MDT; // Manufacturing date [19:8] + UINT32 RESERVED_1; // Reserved [23:20] + UINT32 PSN; // Product serial number [55:24] + UINT8 PRV; // Product revision [63:56] + UINT8 PNM[5]; // Product name [64:103] + UINT16 OID; // OEM/Application ID [119:104] + UINT8 MID; // Manufacturer ID [127:120] +} CID; + +/* + * designware can't read out response bit 0-7, it only returns + * bit 8-135, so we shift 8 bits here. + */ +typedef struct { +#ifdef FULL_CSD + UINT8 NOT_USED: 1; // Not used, always 1 [0:0] + UINT8 CRC: 7; // CRC [7:1] +#endif + UINT8 RESERVED_1: 2; // Reserved [9:8] + UINT8 FILE_FORMAT: 2; // File format [11:10] + UINT8 TMP_WRITE_PROTECT: 1; // Temporary write protection [12:12] + UINT8 PERM_WRITE_PROTECT: 1; // Permanent write protection [13:13] + UINT8 COPY: 1; // Copy flag (OTP) [14:14] + UINT8 FILE_FORMAT_GRP: 1; // File format group [15:15] + + UINT16 RESERVED_2: 5; // Reserved [20:16] + UINT16 WRITE_BL_PARTIAL: 1; // Partial blocks for write allowed [21:21] + UINT16 WRITE_BL_LEN: 4; // Max. write data block length [25:22] + UINT16 R2W_FACTOR: 3; // Write speed factor [28:26] + UINT16 RESERVED_3: 2; // Reserved [30:29] + UINT16 WP_GRP_ENABLE: 1; // Write protect group enable [31:31] + + UINT32 WP_GRP_SIZE: 7; // Write protect group size [38:32] + UINT32 SECTOR_SIZE: 7; // Erase sector size [45:39] + UINT32 ERASE_BLK_EN: 1; // Erase single block enable [46:46] + UINT32 C_SIZE_MULT: 3; // Device size multiplier [49:47] + UINT32 VDD_W_CURR_MAX: 3; // Max. write current @ VDD max [52:50] + UINT32 VDD_W_CURR_MIN: 3; // Max. write current @ VDD min [55:53] + UINT32 VDD_R_CURR_MAX: 3; // Max. read current @ VDD max [58:56] + UINT32 VDD_R_CURR_MIN: 3; // Max. read current @ VDD min [61:59] + UINT32 C_SIZELow2: 2; // Device size [63:62] + + UINT32 C_SIZEHigh10: 10;// Device size [73:64] + UINT32 RESERVED_4: 2; // Reserved [75:74] + UINT32 DSR_IMP: 1; // DSR implemented [76:76] + UINT32 READ_BLK_MISALIGN: 1; // Read block misalignment [77:77] + UINT32 WRITE_BLK_MISALIGN: 1; // Write block misalignment [78:78] + UINT32 READ_BL_PARTIAL: 1; // Partial blocks for read allowed [79:79] + UINT32 READ_BL_LEN: 4; // Max. read data block length [83:80] + UINT32 CCC: 12;// Card command classes [95:84] + + UINT8 TRAN_SPEED ; // Max. bus clock frequency [103:96] + UINT8 NSAC ; // Data read access-time 2 in CLK cycles (NSAC*100) [111:104] + UINT8 TAAC ; // Data read access-time 1 [119:112] + + UINT8 RESERVED_5: 2; // Reserved [121:120] + UINT8 SPEC_VERS: 4; // System specification version [125:122] + UINT8 CSD_STRUCTURE: 2; // CSD structure [127:126] +} CSD; + +typedef struct { +#ifdef FULL_CSD + UINT8 NOT_USED: 1; // Not used, always 1 [0:0] + UINT8 CRC: 7; // CRC [7:1] +#endif + UINT8 RESERVED_1: 2; // Reserved [9:8] + UINT8 FILE_FORMAT: 2; // File format [11:10] + UINT8 TMP_WRITE_PROTECT: 1; // Temporary write protection [12:12] + UINT8 PERM_WRITE_PROTECT: 1; // Permanent write protection [13:13] + UINT8 COPY: 1; // Copy flag (OTP) [14:14] + UINT8 FILE_FORMAT_GRP: 1; // File format group [15:15] + + UINT16 RESERVED_2: 5; // Reserved [20:16] + UINT16 WRITE_BL_PARTIAL: 1; // Partial blocks for write allowed [21:21] + UINT16 WRITE_BL_LEN: 4; // Max. write data block length [25:22] + UINT16 R2W_FACTOR: 3; // Write speed factor [28:26] + UINT16 RESERVED_3: 2; // Reserved [30:29] + UINT16 WP_GRP_ENABLE: 1; // Write protect group enable [31:31] + + UINT32 WP_GRP_SIZE: 7; // Write protect group size [38:32] + UINT32 SECTOR_SIZE: 7; // Erase sector size [45:39] + UINT32 ERASE_BLK_EN: 1; // Erase single block enable [46:46] + UINT32 RESERVED_4: 1; // Reserved [47] + UINT32 C_SIZELow16: 16; // Device size [63:48] + + UINT32 C_SIZEHigh6: 6; // Device size [69:64] + UINT32 RESERVED_5: 6; // Reserved [75:70] + UINT32 DSR_IMP: 1; // DSR implemented [76:76] + UINT32 READ_BLK_MISALIGN: 1; // Read block misalignment [77:77] + UINT32 WRITE_BLK_MISALIGN: 1; // Write block misalignment [78:78] + UINT32 READ_BL_PARTIAL: 1; // Partial blocks for read allowed [79:79] + UINT32 READ_BL_LEN: 4; // Max. read data block length [83:80] + UINT32 CCC: 12;// Card command classes [95:84] + + UINT8 TRAN_SPEED: 8; // Max. bus clock frequency [103:96] + UINT8 NSAC: 8; // Data read access-time 2 in CLK cycles (NSAC*100) [111:104] + UINT8 TAAC: 8; // Data read access-time 1 [119:112] + + UINT8 RESERVED_6: 6; // Reserved [121:120] + UINT8 CSD_STRUCTURE: 2; // CSD structure [127:126] +} ECSD; + +typedef struct { + UINT16 RCA; + CARD_TYPE CardType; + OCR OCRData; + CID CIDData; + CSD CSDData; + ECSD *ECSDData; // MMC V2 extended card specific +} CARD_INFO; + +typedef struct _MMC_HOST_INSTANCE { + UINTN Signature; + LIST_ENTRY Link; + EFI_HANDLE MmcHandle; + EFI_DEVICE_PATH_PROTOCOL *DevicePath; + + MMC_STATE State; + EFI_BLOCK_IO_PROTOCOL BlockIo; + CARD_INFO CardInfo; + EFI_MMC_HOST_PROTOCOL *MmcHost; + + BOOLEAN Initialized; +} MMC_HOST_INSTANCE; + +#define MMC_HOST_INSTANCE_SIGNATURE SIGNATURE_32('m', 'm', 'c', 'h') +#define MMC_HOST_INSTANCE_FROM_BLOCK_IO_THIS(a) CR (a, MMC_HOST_INSTANCE, BlockIo, MMC_HOST_INSTANCE_SIGNATURE) +#define MMC_HOST_INSTANCE_FROM_LINK(a) CR (a, MMC_HOST_INSTANCE, Link, MMC_HOST_INSTANCE_SIGNATURE) + + +EFI_STATUS +EFIAPI +MmcGetDriverName ( + IN EFI_COMPONENT_NAME_PROTOCOL *This, + IN CHAR8 *Language, + OUT CHAR16 **DriverName + ); + +EFI_STATUS +EFIAPI +MmcGetControllerName ( + IN EFI_COMPONENT_NAME_PROTOCOL *This, + IN EFI_HANDLE ControllerHandle, + IN EFI_HANDLE ChildHandle OPTIONAL, + IN CHAR8 *Language, + OUT CHAR16 **ControllerName + ); + +extern EFI_COMPONENT_NAME_PROTOCOL gMmcComponentName; +extern EFI_COMPONENT_NAME2_PROTOCOL gMmcComponentName2; + +extern EFI_DRIVER_DIAGNOSTICS2_PROTOCOL gMmcDriverDiagnostics2; + +extern LIST_ENTRY mMmcHostPool; + +/** + Reset the block device. + + This function implements EFI_BLOCK_IO_PROTOCOL.Reset(). + It resets the block device hardware. + ExtendedVerification is ignored in this implementation. + + @param This Indicates a pointer to the calling context. + @param ExtendedVerification Indicates that the driver may perform a more exhaustive + verification operation of the device during reset. + + @retval EFI_SUCCESS The block device was reset. + @retval EFI_DEVICE_ERROR The block device is not functioning correctly and could not be reset. + +**/ +EFI_STATUS +EFIAPI +MmcReset ( + IN EFI_BLOCK_IO_PROTOCOL *This, + IN BOOLEAN ExtendedVerification + ); + +/** + Reads the requested number of blocks from the device. + + This function implements EFI_BLOCK_IO_PROTOCOL.ReadBlocks(). + It reads the requested number of blocks from the device. + All the blocks are read, or an error is returned. + + @param This Indicates a pointer to the calling context. + @param MediaId The media ID that the read request is for. + @param Lba The starting logical block address to read from on the device. + @param BufferSize The size of the Buffer in bytes. + This must be a multiple of the intrinsic block size of the device. + @param Buffer A pointer to the destination buffer for the data. The caller is + responsible for either having implicit or explicit ownership of the buffer. + + @retval EFI_SUCCESS The data was read correctly from the device. + @retval EFI_DEVICE_ERROR The device reported an error while attempting to perform the read operation. + @retval EFI_NO_MEDIA There is no media in the device. + @retval EFI_MEDIA_CHANGED The MediaId is not for the current media. + @retval EFI_BAD_BUFFER_SIZE The BufferSize parameter is not a multiple of the intrinsic block size of the device. + @retval EFI_INVALID_PARAMETER The read request contains LBAs that are not valid, + or the buffer is not on proper alignment. + +**/ +EFI_STATUS +EFIAPI +MmcReadBlocks ( + IN EFI_BLOCK_IO_PROTOCOL *This, + IN UINT32 MediaId, + IN EFI_LBA Lba, + IN UINTN BufferSize, + OUT VOID *Buffer + ); + +/** + Writes a specified number of blocks to the device. + + This function implements EFI_BLOCK_IO_PROTOCOL.WriteBlocks(). + It writes a specified number of blocks to the device. + All blocks are written, or an error is returned. + + @param This Indicates a pointer to the calling context. + @param MediaId The media ID that the write request is for. + @param Lba The starting logical block address to be written. + @param BufferSize The size of the Buffer in bytes. + This must be a multiple of the intrinsic block size of the device. + @param Buffer Pointer to the source buffer for the data. + + @retval EFI_SUCCESS The data were written correctly to the device. + @retval EFI_WRITE_PROTECTED The device cannot be written to. + @retval EFI_NO_MEDIA There is no media in the device. + @retval EFI_MEDIA_CHANGED The MediaId is not for the current media. + @retval EFI_DEVICE_ERROR The device reported an error while attempting to perform the write operation. + @retval EFI_BAD_BUFFER_SIZE The BufferSize parameter is not a multiple of the intrinsic + block size of the device. + @retval EFI_INVALID_PARAMETER The write request contains LBAs that are not valid, + or the buffer is not on proper alignment. + +**/ +EFI_STATUS +EFIAPI +MmcWriteBlocks ( + IN EFI_BLOCK_IO_PROTOCOL *This, + IN UINT32 MediaId, + IN EFI_LBA Lba, + IN UINTN BufferSize, + IN VOID *Buffer + ); + +/** + Flushes all modified data to a physical block device. + + @param This Indicates a pointer to the calling context. + + @retval EFI_SUCCESS All outstanding data were written correctly to the device. + @retval EFI_DEVICE_ERROR The device reported an error while attempting to write data. + @retval EFI_NO_MEDIA There is no media in the device. + +**/ +EFI_STATUS +EFIAPI +MmcFlushBlocks ( + IN EFI_BLOCK_IO_PROTOCOL *This + ); + +/** + Sets the state of the MMC host instance and invokes the + NotifyState function of the MMC host, passing the updated state. + + @param MmcHostInstance Pointer to the MMC host instance. + @param State The new state to be set for the MMC host instance. + + @retval EFI_STATUS + +**/ +EFI_STATUS +MmcNotifyState ( + IN MMC_HOST_INSTANCE *MmcHostInstance, + IN MMC_STATE State + ); + +/** + Initialize the MMC device. + + @param[in] MmcHostInstance MMC host instance + + @retval EFI_SUCCESS MMC device initialized successfully + @retval Other MMC device initialization failed + +**/ +EFI_STATUS +InitializeMmcDevice ( + IN MMC_HOST_INSTANCE *MmcHost + ); + +/** + Callback function to check MMC cards. + + @param[in] Event The event that is being triggered + @param[in] Context The context passed to the event + +**/ +VOID +EFIAPI +CheckCardsCallback ( + IN EFI_EVENT Event, + IN VOID *Context + ); + +/** + Print the Card Specific Data (CSD). + + @param[in] Csd Pointer to the CSD array + +**/ +VOID +PrintCSD ( + IN UINT32* Csd + ); + +/** + Print the Relative Card Address (RCA). + + @param[in] Rca The Relative Card Address (RCA) value + +**/ +VOID +PrintRCA ( + IN UINT32 Rca + ); + +/** + Print the Operation Condition Register (OCR). + + @param[in] Ocr The Operation Condition Register (OCR) value. + +**/ +VOID +PrintOCR ( + IN UINT32 Ocr + ); + +/** + Print the R1 response. + + @param[in] Response The R1 response value. + +**/ +VOID +PrintResponseR1 ( + IN UINT32 Response + ); + +/** + Print the Card Identification (CID) register. + + @param[in] Cid Pointer to the CID array. + +**/ +VOID +PrintCID ( + IN UINT32* Cid + ); + +#endif diff --git a/Silicon/Sophgo/SG2042Pkg/Include/MmcHost.h b/Silicon/Sophgo/SG2042Pkg/Include/MmcHost.h new file mode 100644 index 000000000000..d340af155d61 --- /dev/null +++ b/Silicon/Sophgo/SG2042Pkg/Include/MmcHost.h @@ -0,0 +1,225 @@ +/** @file + Definition of the MMC Host Protocol + + Copyright (c) 2011-2014, ARM Limited. All rights reserved. + Copyright (c) Academy of Intelligent Innovation. All rights reserved.
+ + SPDX-License-Identifier: BSD-2-Clause-Patent + + **/ + +#ifndef __MMC_HOST_PROTOCOL_H__ +#define __MMC_HOST_PROTOCOL_H__ + +/* + * Global ID for the MMC Host Protocol + */ +#define MMC_HOST_PROTOCOL_GUID \ + { 0x3e591c00, 0x9e4a, 0x11df, {0x92, 0x44, 0x00, 0x02, 0xA5, 0xF5, 0xF5, 0x1B } } + +#define MMC_BLOCK_SIZE 512U +#define MMC_BLOCK_MASK (MMC_BLOCK_SIZE - 1U) +#define MMC_BOOT_CLK_RATE (400 * 1000) + +/* Values in EXT CSD register */ +#define MMC_BUS_WIDTH_1 0U +#define MMC_BUS_WIDTH_4 1U +#define MMC_BUS_WIDTH_8 2U +#define MMC_BUS_WIDTH_DDR_4 5U +#define MMC_BUS_WIDTH_DDR_8 6U + +#define MMC_RSP_48 BIT0 +#define MMC_RSP_136 BIT1 /* 136 bit response */ +#define MMC_RSP_CRC BIT2 /* expect valid crc */ +#define MMC_RSP_CMD_IDX BIT3 /* response contains cmd idx */ +#define MMC_RSP_BUSY BIT4 /* device may be busy */ + +/* JEDEC 4.51 chapter 6.12 */ +#define MMC_RESPONSE_R1 (MMC_RSP_48 | MMC_RSP_CMD_IDX | MMC_RSP_CRC) +#define MMC_RESPONSE_R1B (MMC_RESPONSE_R1 | MMC_RSP_BUSY) +#define MMC_RESPONSE_R2 (MMC_RSP_48 | MMC_RSP_136 | MMC_RSP_CRC) +#define MMC_RESPONSE_R3 (MMC_RSP_48) +#define MMC_RESPONSE_R4 (MMC_RSP_48) +#define MMC_RESPONSE_R5 (MMC_RSP_48 | MMC_RSP_CRC | MMC_RSP_CMD_IDX) +#define MMC_RESPONSE_R6 (MMC_RSP_48 | MMC_RSP_CRC | MMC_RSP_CMD_IDX) +#define MMC_RESPONSE_R7 (MMC_RSP_48 | MMC_RSP_CRC | MMC_RSP_CMD_IDX) + +typedef UINT32 MMC_RESPONSE_TYPE; + +typedef UINT32 MMC_IDX; + +#define MMC_CMD_WAIT_RESPONSE (1 << 16) +#define MMC_CMD_LONG_RESPONSE (1 << 17) +#define MMC_CMD_NO_CRC_RESPONSE (1 << 18) + +#define MMC_INDX(Index) ((Index) & 0xFFFF) +#define MMC_GET_INDX(MmcCmd) ((MmcCmd) & 0xFFFF) + +#define MMC_CMD0 (MMC_INDX(0)) +#define MMC_CMD1 (MMC_INDX(1)) +#define MMC_CMD2 (MMC_INDX(2)) +#define MMC_CMD3 (MMC_INDX(3)) +#define MMC_CMD5 (MMC_INDX(5)) +#define MMC_CMD6 (MMC_INDX(6)) +#define MMC_CMD7 (MMC_INDX(7)) +#define MMC_CMD8 (MMC_INDX(8)) +#define MMC_CMD9 (MMC_INDX(9)) +#define MMC_CMD11 (MMC_INDX(11)) +#define MMC_CMD12 (MMC_INDX(12)) +#define MMC_CMD13 (MMC_INDX(13)) +#define MMC_CMD16 (MMC_INDX(16)) +#define MMC_CMD17 (MMC_INDX(17)) +#define MMC_CMD18 (MMC_INDX(18)) +#define MMC_CMD20 (MMC_INDX(20)) +#define MMC_CMD23 (MMC_INDX(23)) +#define MMC_CMD24 (MMC_INDX(24)) +#define MMC_CMD25 (MMC_INDX(25)) +#define MMC_CMD55 (MMC_INDX(55)) +#define MMC_ACMD22 (MMC_INDX(22)) +#define MMC_ACMD41 (MMC_INDX(41)) +#define MMC_ACMD51 (MMC_INDX(51)) + +// Valid responses for CMD1 in eMMC +#define EMMC_CMD1_CAPACITY_LESS_THAN_2GB 0x00FF8080 // Capacity <= 2GB, byte addressing used +#define EMMC_CMD1_CAPACITY_GREATER_THAN_2GB 0x40FF8080 // Capacity > 2GB, 512-byte sector addressing used + +#define MMC_STATUS_APP_CMD (1 << 5) + +typedef enum _MMC_STATE { + MmcInvalidState = 0, + MmcHwInitializationState, + MmcIdleState, + MmcReadyState, + MmcIdentificationState, + MmcStandByState, + MmcTransferState, + MmcSendingDataState, + MmcReceiveDataState, + MmcProgrammingState, + MmcDisconnectState, +} MMC_STATE; + +typedef enum _CARD_DETECT_STATE { + CardDetectRequired = 0, + CardDetectInProgress, + CardDetectCompleted +} CARD_DETECT_STATE; + +#define EMMCBACKWARD (0) +#define EMMCHS26 (1 << 0) // High-Speed @26MHz at rated device voltages +#define EMMCHS52 (1 << 1) // High-Speed @52MHz at rated device voltages +#define EMMCHS52DDR1V8 (1 << 2) // High-Speed Dual Data Rate @52MHz 1.8V or 3V I/O +#define EMMCHS52DDR1V2 (1 << 3) // High-Speed Dual Data Rate @52MHz 1.2V I/O +#define EMMCHS200SDR1V8 (1 << 4) // HS200 Single Data Rate @200MHz 1.8V I/O +#define EMMCHS200SDR1V2 (1 << 5) // HS200 Single Data Rate @200MHz 1.2V I/O +#define EMMCHS400DDR1V8 (1 << 6) // HS400 Dual Data Rate @400MHz 1.8V I/O +#define EMMCHS400DDR1V2 (1 << 7) // HS400 Dual Data Rate @400MHz 1.2V I/O + +/// +/// Forward declaration for EFI_MMC_HOST_PROTOCOL +/// +typedef struct _EFI_MMC_HOST_PROTOCOL EFI_MMC_HOST_PROTOCOL; + +typedef +BOOLEAN +(EFIAPI *MMC_ISCARDPRESENT) ( + IN EFI_MMC_HOST_PROTOCOL *This + ); + +typedef +BOOLEAN +(EFIAPI *MMC_ISREADONLY) ( + IN EFI_MMC_HOST_PROTOCOL *This + ); + +typedef +EFI_STATUS +(EFIAPI *MMC_BUILDDEVICEPATH) ( + IN EFI_MMC_HOST_PROTOCOL *This, + OUT EFI_DEVICE_PATH_PROTOCOL **DevicePath + ); + +typedef +EFI_STATUS +(EFIAPI *MMC_NOTIFYSTATE) ( + IN EFI_MMC_HOST_PROTOCOL *This, + IN MMC_STATE State + ); + +typedef +EFI_STATUS +(EFIAPI *MMC_SENDCOMMAND) ( + IN EFI_MMC_HOST_PROTOCOL *This, + IN MMC_IDX Cmd, + IN UINT32 Argument, + IN MMC_RESPONSE_TYPE Type, + IN UINT32 *Buffer + ); + +typedef +EFI_STATUS +(EFIAPI *MMC_READBLOCKDATA) ( + IN EFI_MMC_HOST_PROTOCOL *This, + IN EFI_LBA Lba, + IN UINTN Length, + OUT UINT32 *Buffer + ); + +typedef +EFI_STATUS +(EFIAPI *MMC_WRITEBLOCKDATA) ( + IN EFI_MMC_HOST_PROTOCOL *This, + IN EFI_LBA Lba, + IN UINTN Length, + IN UINT32 *Buffer + ); + +typedef +EFI_STATUS +(EFIAPI *MMC_SETIOS) ( + IN EFI_MMC_HOST_PROTOCOL *This, + IN UINT32 BusClockFreq, + IN UINT32 BusWidth + ); + +typedef +EFI_STATUS +(EFIAPI *MMC_PREPARE) ( + IN EFI_MMC_HOST_PROTOCOL *This, + IN EFI_LBA Lba, + IN UINTN Length, + IN UINTN Buffer + ); + +typedef +BOOLEAN +(EFIAPI *MMC_ISMULTIBLOCK) ( + IN EFI_MMC_HOST_PROTOCOL *This + ); + +struct _EFI_MMC_HOST_PROTOCOL { + UINT32 Revision; + MMC_ISCARDPRESENT IsCardPresent; + MMC_ISREADONLY IsReadOnly; + MMC_BUILDDEVICEPATH BuildDevicePath; + + MMC_NOTIFYSTATE NotifyState; + + MMC_SENDCOMMAND SendCommand; + + MMC_READBLOCKDATA ReadBlockData; + MMC_WRITEBLOCKDATA WriteBlockData; + + MMC_SETIOS SetIos; + MMC_PREPARE Prepare; + MMC_ISMULTIBLOCK IsMultiBlock; +}; + +#define MMC_HOST_PROTOCOL_REVISION 0x00010002 // 1.2 + +#define MMC_HOST_HAS_SETIOS(Host) (Host->Revision >= MMC_HOST_PROTOCOL_REVISION && \ + Host->SetIos != NULL) +#define MMC_HOST_HAS_ISMULTIBLOCK(Host) (Host->Revision >= MMC_HOST_PROTOCOL_REVISION && \ + Host->IsMultiBlock != NULL) + +#endif /* __MMC_HOST_PROTOCOL_H__ */ diff --git a/Silicon/Sophgo/SG2042Pkg/Drivers/MmcDxe/ComponentName.c b/Silicon/Sophgo/SG2042Pkg/Drivers/MmcDxe/ComponentName.c new file mode 100644 index 000000000000..eb66c68a54c7 --- /dev/null +++ b/Silicon/Sophgo/SG2042Pkg/Drivers/MmcDxe/ComponentName.c @@ -0,0 +1,156 @@ +/** @file + Component Name Protocol implementation for the MMC DXE driver + + Copyright (c) 2011, ARM Limited. All rights reserved. + + SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#include "Mmc.h" + +// +// EFI Component Name Protocol +// +GLOBAL_REMOVE_IF_UNREFERENCED EFI_COMPONENT_NAME_PROTOCOL gMmcComponentName = { + MmcGetDriverName, + MmcGetControllerName, + "eng" +}; + +// +// EFI Component Name 2 Protocol +// +GLOBAL_REMOVE_IF_UNREFERENCED EFI_COMPONENT_NAME2_PROTOCOL gMmcComponentName2 = { + (EFI_COMPONENT_NAME2_GET_DRIVER_NAME)MmcGetDriverName, + (EFI_COMPONENT_NAME2_GET_CONTROLLER_NAME)MmcGetControllerName, + "en" +}; + +GLOBAL_REMOVE_IF_UNREFERENCED EFI_UNICODE_STRING_TABLE +mMmcDriverNameTable[] = { + {"eng;en", L"MMC/SD Card Interface Driver"}, + {NULL, NULL} +}; + +/** + Retrieves a Unicode string that is the user readable name of the driver. + + This function retrieves the user readable name of a driver in the form of a + Unicode string. If the driver specified by This has a user readable name in + the language specified by Language, then a pointer to the driver name is + returned in DriverName, and EFI_SUCCESS is returned. If the driver specified + by This does not support the language specified by Language, + then EFI_UNSUPPORTED is returned. + + @param This A pointer to the EFI_COMPONENT_NAME2_PROTOCOL or + EFI_COMPONENT_NAME_PROTOCOL instance. + @param Language A pointer to a Null-terminated ASCII string + array indicating the language. This is the + language of the driver name that the caller is + requesting, and it must match one of the + languages specified in SupportedLanguages. The + number of languages supported by a driver is up + to the driver writer. Language is specified + in RFC 4646 or ISO 639-2 language code format. + @param DriverName A pointer to the Unicode string to return. + This Unicode string is the name of the + driver specified by This in the language + specified by Language. + + @retval EFI_SUCCESS The Unicode string for the Driver specified by + This and the language specified by Language was + returned in DriverName. + @retval EFI_INVALID_PARAMETER Language is NULL. + @retval EFI_INVALID_PARAMETER DriverName is NULL. + @retval EFI_UNSUPPORTED The driver specified by This does not support + the language specified by Language. + +**/ +EFI_STATUS +EFIAPI +MmcGetDriverName ( + IN EFI_COMPONENT_NAME_PROTOCOL *This, + IN CHAR8 *Language, + OUT CHAR16 **DriverName + ) +{ + return LookupUnicodeString2 ( + Language, + This->SupportedLanguages, + mMmcDriverNameTable, + DriverName, + (BOOLEAN)(This == &gMmcComponentName) + ); +} + +/** + Retrieves a Unicode string that is the user readable name of the controller + that is being managed by a driver. + + This function retrieves the user readable name of the controller specified by + ControllerHandle and ChildHandle in the form of a Unicode string. If the + driver specified by This has a user readable name in the language specified by + Language, then a pointer to the controller name is returned in ControllerName, + and EFI_SUCCESS is returned. If the driver specified by This is not currently + managing the controller specified by ControllerHandle and ChildHandle, + then EFI_UNSUPPORTED is returned. If the driver specified by This does not + support the language specified by Language, then EFI_UNSUPPORTED is returned. + + @param This A pointer to the EFI_COMPONENT_NAME2_PROTOCOL or + EFI_COMPONENT_NAME_PROTOCOL instance. + @param ControllerHandle The handle of a controller that the driver + specified by This is managing. This handle + specifies the controller whose name is to be + returned. + @param ChildHandle The handle of the child controller to retrieve + the name of. This is an optional parameter that + may be NULL. It will be NULL for device + drivers. It will also be NULL for a bus drivers + that wish to retrieve the name of the bus + controller. It will not be NULL for a bus + driver that wishes to retrieve the name of a + child controller. + @param Language A pointer to a Null-terminated ASCII string + array indicating the language. This is the + language of the driver name that the caller is + requesting, and it must match one of the + languages specified in SupportedLanguages. The + number of languages supported by a driver is up + to the driver writer. Language is specified in + RFC 4646 or ISO 639-2 language code format. + @param ControllerName A pointer to the Unicode string to return. + This Unicode string is the name of the + controller specified by ControllerHandle and + ChildHandle in the language specified by + Language from the point of view of the driver + specified by This. + + @retval EFI_SUCCESS The Unicode string for the user readable name in + the language specified by Language for the + driver specified by This was returned in + DriverName. + @retval EFI_INVALID_PARAMETER ControllerHandle is not a valid EFI_HANDLE. + @retval EFI_INVALID_PARAMETER ChildHandle is not NULL and it is not a valid + EFI_HANDLE. + @retval EFI_INVALID_PARAMETER Language is NULL. + @retval EFI_INVALID_PARAMETER ControllerName is NULL. + @retval EFI_UNSUPPORTED The driver specified by This is not currently + managing the controller specified by + ControllerHandle and ChildHandle. + @retval EFI_UNSUPPORTED The driver specified by This does not support + the language specified by Language. + +**/ +EFI_STATUS +EFIAPI +MmcGetControllerName ( + IN EFI_COMPONENT_NAME_PROTOCOL *This, + IN EFI_HANDLE ControllerHandle, + IN EFI_HANDLE ChildHandle OPTIONAL, + IN CHAR8 *Language, + OUT CHAR16 **ControllerName + ) +{ + return EFI_UNSUPPORTED; +} diff --git a/Silicon/Sophgo/SG2042Pkg/Drivers/MmcDxe/Diagnostics.c b/Silicon/Sophgo/SG2042Pkg/Drivers/MmcDxe/Diagnostics.c new file mode 100644 index 000000000000..e7ea395a9462 --- /dev/null +++ b/Silicon/Sophgo/SG2042Pkg/Drivers/MmcDxe/Diagnostics.c @@ -0,0 +1,323 @@ +/** @file + Diagnostics Protocol implementation for the MMC DXE driver + + Copyright (c) 2011-2014, ARM Limited. All rights reserved. + + SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#include +#include +#include +#include +#include + +#include "Mmc.h" + +#define DIAGNOSTIC_LOGBUFFER_MAXCHAR 1024 + +CHAR16* mLogBuffer = NULL; +UINTN mLogRemainChar = 0; + +/** + + Initialize the diagnostic log by allocating memory for the log + buffer and setting the maximum buffer size. + + @param MaxBufferChar The maximum number of CHAR16 characters the log buffer can hold. + + @retval A pointer to the allocated log buffer. + +**/ +CHAR16* +DiagnosticInitLog ( + UINTN MaxBufferChar + ) +{ + mLogRemainChar = MaxBufferChar; + mLogBuffer = AllocatePool ((UINTN)MaxBufferChar * sizeof (CHAR16)); + return mLogBuffer; +} + +/** + + Log a diagnostic string by copying it to the log buffer. + + @param Str A pointer to the constant CHAR16 string to be logged. + + @retval The length of the logged string. + +**/ +UINTN +DiagnosticLog ( + CONST CHAR16* Str + ) +{ + UINTN len = StrLen (Str); + if (len < mLogRemainChar) { + StrCpyS (mLogBuffer, mLogRemainChar, Str); + mLogRemainChar -= len; + mLogBuffer += len; + return len; + } else { + return 0; + } +} + +/** + + Generate a random buffer by filling it with pseudo-random data. + + @param Buffer A pointer to the buffer where the generated data will be stored. + @param BufferSize The size of the buffer in bytes. + +**/ +VOID +GenerateRandomBuffer ( + VOID* Buffer, + UINTN BufferSize + ) +{ + UINT64 i; + UINT64* Buffer64 = (UINT64*)Buffer; + + for (i = 0; i < (BufferSize >> 3); i++) { + *Buffer64 = i | (~i << 32); + Buffer64++; + } +} + +/** + + Compares two buffers by iterating through each 64-bit element in the buffers. + + @param BufferA A pointer to the first buffer to compare. + @param BufferB A pointer to the second buffer to compare. + @param BufferSize The size of the buffers in bytes. + + @retval TRUE if the buffers are equal, FALSE if a mismatch is found. + +**/ +BOOLEAN +CompareBuffer ( + VOID *BufferA, + VOID *BufferB, + UINTN BufferSize + ) +{ + UINTN i; + UINT64* BufferA64 = (UINT64*)BufferA; + UINT64* BufferB64 = (UINT64*)BufferB; + + for (i = 0; i < (BufferSize >> 3); i++) { + if (*BufferA64 != *BufferB64) { + DEBUG ((DEBUG_ERROR, "CompareBuffer: Error at %i", i)); + DEBUG ((DEBUG_ERROR, "(0x%lX) != (0x%lX)\n", *BufferA64, *BufferB64)); + return FALSE; + } + BufferA64++; + BufferB64++; + } + return TRUE; +} + +/** + Performs a read/write data test on an MMC device. + + @param MmcHostInstance A pointer to the MMC host instance. + @param Lba The logical block address to perform the test on. + @param BufferSize The size of the buffer in bytes. + + @retval EFI_SUCCESS The test completes successfully. + @retval EFI_NO_MEDIA No media (MMC device) is detected. + @retval EFI_NOT_READY The MMC device is not in the transfer state. + @retval EFI_INVALID_PARAMETER The written data does not match the read data. + +**/ +EFI_STATUS +MmcReadWriteDataTest ( + MMC_HOST_INSTANCE *MmcHostInstance, + EFI_LBA Lba, + UINTN BufferSize + ) +{ + VOID *BackBuffer; + VOID *WriteBuffer; + VOID *ReadBuffer; + EFI_STATUS Status; + + // Check if a Media is Present + if (!MmcHostInstance->BlockIo.Media->MediaPresent) { + DiagnosticLog (L"ERROR: No Media Present\n"); + return EFI_NO_MEDIA; + } + + if (MmcHostInstance->State != MmcTransferState) { + DiagnosticLog (L"ERROR: Not ready for Transfer state\n"); + return EFI_NOT_READY; + } + + BackBuffer = AllocatePool (BufferSize); + WriteBuffer = AllocatePool (BufferSize); + ReadBuffer = AllocatePool (BufferSize); + + // Read (and save) buffer at a specific location + Status = MmcReadBlocks (&(MmcHostInstance->BlockIo), + MmcHostInstance->BlockIo.Media->MediaId, Lba, BufferSize, BackBuffer); + if (Status != EFI_SUCCESS) { + DiagnosticLog (L"ERROR: Fail to Read Block (1)\n"); + return Status; + } + + // Write buffer at the same location + GenerateRandomBuffer (WriteBuffer, BufferSize); + Status = MmcWriteBlocks (&(MmcHostInstance->BlockIo), + MmcHostInstance->BlockIo.Media->MediaId, Lba, BufferSize, WriteBuffer); + if (Status != EFI_SUCCESS) { + DiagnosticLog (L"ERROR: Fail to Write Block (1)\n"); + return Status; + } + + // Read the buffer at the same location + Status = MmcReadBlocks (&(MmcHostInstance->BlockIo), + MmcHostInstance->BlockIo.Media->MediaId, Lba, BufferSize, ReadBuffer); + if (Status != EFI_SUCCESS) { + DiagnosticLog (L"ERROR: Fail to Read Block (2)\n"); + return Status; + } + + // Check that is conform + if (!CompareBuffer (ReadBuffer, WriteBuffer, BufferSize)) { + DiagnosticLog (L"ERROR: Fail to Read/Write Block (1)\n"); + return EFI_INVALID_PARAMETER; + } + + // Restore content at the original location + Status = MmcWriteBlocks (&(MmcHostInstance->BlockIo), + MmcHostInstance->BlockIo.Media->MediaId, Lba, BufferSize, BackBuffer); + if (Status != EFI_SUCCESS) { + DiagnosticLog (L"ERROR: Fail to Write Block (2)\n"); + return Status; + } + + // Read the restored content + Status = MmcReadBlocks (&(MmcHostInstance->BlockIo), + MmcHostInstance->BlockIo.Media->MediaId, Lba, BufferSize, ReadBuffer); + if (Status != EFI_SUCCESS) { + DiagnosticLog (L"ERROR: Fail to Read Block (3)\n"); + return Status; + } + + // Check the content is correct + if (!CompareBuffer (ReadBuffer, BackBuffer, BufferSize)) { + DiagnosticLog (L"ERROR: Fail to Read/Write Block (2)\n"); + return EFI_INVALID_PARAMETER; + } + + return EFI_SUCCESS; +} + +/** + Runs diagnostics tests on the MMC driver for the specified controller handle. + + @param This A pointer to the EFI_DRIVER_DIAGNOSTICS_PROTOCOL instance. + @param ControllerHandle The handle of the controller to run diagnostics on. + @param ChildHandle The handle of the child controller to run diagnostics on (optional). + @param DiagnosticType The type of diagnostics to run. + @param Language The language code (only English is supported). + @param ErrorType The type of error encountered during diagnostics (if any). + @param BufferSize The size of the diagnostic buffer. + @param Buffer The diagnostic buffer. + + @retval EFI_SUCCESS The diagnostics completed successfully. + @retval EFI_INVALID_PARAMETER One or more parameters are invalid. + @retval EFI_UNSUPPORTED The specified language or controller is not supported. +*/ +EFI_STATUS +EFIAPI +MmcDriverDiagnosticsRunDiagnostics ( + IN EFI_DRIVER_DIAGNOSTICS_PROTOCOL *This, + IN EFI_HANDLE ControllerHandle, + IN EFI_HANDLE ChildHandle OPTIONAL, + IN EFI_DRIVER_DIAGNOSTIC_TYPE DiagnosticType, + IN CHAR8 *Language, + OUT EFI_GUID **ErrorType, + OUT UINTN *BufferSize, + OUT CHAR16 **Buffer + ) +{ + LIST_ENTRY *CurrentLink; + MMC_HOST_INSTANCE *MmcHostInstance; + EFI_STATUS Status; + + if ((Language == NULL) || + (ErrorType == NULL) || + (Buffer == NULL) || + (ControllerHandle == NULL) || + (BufferSize == NULL)) { + return EFI_INVALID_PARAMETER; + } + + // Check Language is supported (i.e. is "en-*" - only English is supported) + if (AsciiStrnCmp (Language, "en", 2) != 0) { + return EFI_UNSUPPORTED; + } + + Status = EFI_SUCCESS; + *ErrorType = NULL; + *BufferSize = DIAGNOSTIC_LOGBUFFER_MAXCHAR; + *Buffer = DiagnosticInitLog (DIAGNOSTIC_LOGBUFFER_MAXCHAR); + + DiagnosticLog (L"MMC Driver Diagnostics\n"); + + // Find the MMC Host instance on which we have been asked to run diagnostics + MmcHostInstance = NULL; + CurrentLink = mMmcHostPool.ForwardLink; + while (CurrentLink != NULL && CurrentLink != &mMmcHostPool && (Status == EFI_SUCCESS)) { + MmcHostInstance = MMC_HOST_INSTANCE_FROM_LINK (CurrentLink); + ASSERT (MmcHostInstance != NULL); + if (MmcHostInstance->MmcHandle == ControllerHandle) { + break; + } + CurrentLink = CurrentLink->ForwardLink; + } + + // If we didn't find the controller, return EFI_UNSUPPORTED + if ((MmcHostInstance == NULL) + || (MmcHostInstance->MmcHandle != ControllerHandle)) { + return EFI_UNSUPPORTED; + } + + // LBA=1 Size=BlockSize + DiagnosticLog (L"MMC Driver Diagnostics - Test: First Block\n"); + Status = MmcReadWriteDataTest (MmcHostInstance, 1, MmcHostInstance->BlockIo.Media->BlockSize); + + // LBA=2 Size=BlockSize + DiagnosticLog (L"MMC Driver Diagnostics - Test: Second Block\n"); + Status = MmcReadWriteDataTest (MmcHostInstance, 2, MmcHostInstance->BlockIo.Media->BlockSize); + + // LBA=10 Size=BlockSize + DiagnosticLog (L"MMC Driver Diagnostics - Test: Any Block\n"); + Status = MmcReadWriteDataTest (MmcHostInstance, MmcHostInstance->BlockIo.Media->LastBlock >> 1, + MmcHostInstance->BlockIo.Media->BlockSize); + + // LBA=LastBlock Size=BlockSize + DiagnosticLog (L"MMC Driver Diagnostics - Test: Last Block\n"); + Status = MmcReadWriteDataTest (MmcHostInstance, MmcHostInstance->BlockIo.Media->LastBlock, + MmcHostInstance->BlockIo.Media->BlockSize); + + // LBA=1 Size=2*BlockSize + DiagnosticLog (L"MMC Driver Diagnostics - Test: First Block / 2 BlockSSize\n"); + Status = MmcReadWriteDataTest (MmcHostInstance, 1, 2 * MmcHostInstance->BlockIo.Media->BlockSize); + + return Status; +} + +// +// EFI Driver Diagnostics 2 Protocol +// +GLOBAL_REMOVE_IF_UNREFERENCED EFI_DRIVER_DIAGNOSTICS2_PROTOCOL gMmcDriverDiagnostics2 = { + (EFI_DRIVER_DIAGNOSTICS2_RUN_DIAGNOSTICS)MmcDriverDiagnosticsRunDiagnostics, + "en" +}; diff --git a/Silicon/Sophgo/SG2042Pkg/Drivers/MmcDxe/Mmc.c b/Silicon/Sophgo/SG2042Pkg/Drivers/MmcDxe/Mmc.c new file mode 100644 index 000000000000..401fe698e537 --- /dev/null +++ b/Silicon/Sophgo/SG2042Pkg/Drivers/MmcDxe/Mmc.c @@ -0,0 +1,527 @@ +/** @file + Main file of the MMC Dxe driver. The driver entrypoint is defined into this file. + + Copyright (c) 2011-2013, ARM Limited. All rights reserved. + Copyright (c) 2023, Academy of Intelligent Innovation, Shandong Universiy, China.P.R. All rights reserved.
+ + SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#include + +#include +#include +#include +#include +#include + +#include "Mmc.h" + +EFI_BLOCK_IO_MEDIA mMmcMediaTemplate = { + SIGNATURE_32 ('m','m','c','o'), // MediaId + TRUE, // RemovableMedia + FALSE, // MediaPresent + FALSE, // LogicalPartition + FALSE, // ReadOnly + FALSE, // WriteCaching + 512, // BlockSize + 4, // IoAlign + 0, // Pad + 0 // LastBlock +}; + +// +// This device structure is serviced as a header. +// Its next field points to the first root bridge device node. +// +LIST_ENTRY mMmcHostPool; + +/** + Event triggered by the timer to check if any cards have been removed + or if new ones have been plugged in +**/ + +EFI_EVENT gCheckCardsEvent; + +/** + Initialize the MMC Host Pool to support multiple MMC devices +**/ +VOID +InitializeMmcHostPool ( + VOID + ) +{ + InitializeListHead (&mMmcHostPool); +} + +/** + Insert a new Mmc Host controller to the pool. + + @param MmcHostInstance The MMC_HOST_INSTANCE to be inserted into the pool. + +**/ +VOID +InsertMmcHost ( + IN MMC_HOST_INSTANCE *MmcHostInstance + ) +{ + InsertTailList (&mMmcHostPool, &(MmcHostInstance->Link)); +} + +/** + Remove a new Mmc Host controller to the pool. + + @param MmcHostInstance The MMC_HOST_INSTANCE to be removed from the pool. + +**/ +VOID +RemoveMmcHost ( + IN MMC_HOST_INSTANCE *MmcHostInstance + ) +{ + RemoveEntryList (&(MmcHostInstance->Link)); +} + +/** + This function creates a new MMC host controller instance and initializes its members. + It allocates memory for the instance, sets the necessary fields, + and installs the BlockIO and DevicePath protocols. + + @param MmcHost The EFI_MMC_HOST_PROTOCOL instance representing the MMC host. + + @return A pointer to the created MMC_HOST_INSTANCE on success, or NULL on failure. +**/ +MMC_HOST_INSTANCE* +CreateMmcHostInstance ( + IN EFI_MMC_HOST_PROTOCOL* MmcHost + ) +{ + EFI_STATUS Status; + MMC_HOST_INSTANCE* MmcHostInstance; + EFI_DEVICE_PATH_PROTOCOL *NewDevicePathNode; + EFI_DEVICE_PATH_PROTOCOL *DevicePath; + + MmcHostInstance = AllocateZeroPool (sizeof (MMC_HOST_INSTANCE)); + if (MmcHostInstance == NULL) { + return NULL; + } + + MmcHostInstance->Signature = MMC_HOST_INSTANCE_SIGNATURE; + + MmcHostInstance->State = MmcHwInitializationState; + + MmcHostInstance->BlockIo.Media = AllocateCopyPool (sizeof (EFI_BLOCK_IO_MEDIA), &mMmcMediaTemplate); + if (MmcHostInstance->BlockIo.Media == NULL) { + goto FREE_INSTANCE; + } + + MmcHostInstance->BlockIo.Revision = EFI_BLOCK_IO_INTERFACE_REVISION; + MmcHostInstance->BlockIo.Reset = MmcReset; + MmcHostInstance->BlockIo.ReadBlocks = MmcReadBlocks; + MmcHostInstance->BlockIo.WriteBlocks = MmcWriteBlocks; + MmcHostInstance->BlockIo.FlushBlocks = MmcFlushBlocks; + + MmcHostInstance->MmcHost = MmcHost; + + // Create DevicePath for the new MMC Host + Status = MmcHost->BuildDevicePath (MmcHost, &NewDevicePathNode); + if (EFI_ERROR (Status)) { + goto FREE_MEDIA; + } + + DevicePath = (EFI_DEVICE_PATH_PROTOCOL*)AllocatePool (END_DEVICE_PATH_LENGTH); + if (DevicePath == NULL) { + goto FREE_MEDIA; + } + + SetDevicePathEndNode (DevicePath); + MmcHostInstance->DevicePath = AppendDevicePathNode (DevicePath, NewDevicePathNode); + + // Publish BlockIO protocol interface + Status = gBS->InstallMultipleProtocolInterfaces ( + &MmcHostInstance->MmcHandle, + &gEfiBlockIoProtocolGuid, &MmcHostInstance->BlockIo, + &gEfiDevicePathProtocolGuid, MmcHostInstance->DevicePath, + NULL + ); + if (EFI_ERROR (Status)) { + goto FREE_DEVICE_PATH; + } + + return MmcHostInstance; + +FREE_DEVICE_PATH: + FreePool (DevicePath); + +FREE_MEDIA: + FreePool (MmcHostInstance->BlockIo.Media); + +FREE_INSTANCE: + FreePool (MmcHostInstance); + + return NULL; +} + +/** + This function uninstalls the BlockIO and DevicePath protocols from the MMC host controller instance, + and frees the memory allocated for the instance and its associated resources. + + @param MmcHostInstance The MMC_HOST_INSTANCE to be destroyed. + + @retval EFI_SUCCESS The instance is successfully destroyed. + @retval Other The instance cannot be destroyed. + +**/ +EFI_STATUS +DestroyMmcHostInstance ( + IN MMC_HOST_INSTANCE* MmcHostInstance + ) +{ + EFI_STATUS Status; + + // Uninstall Protocol Interfaces + Status = gBS->UninstallMultipleProtocolInterfaces ( + MmcHostInstance->MmcHandle, + &gEfiBlockIoProtocolGuid, &(MmcHostInstance->BlockIo), + &gEfiDevicePathProtocolGuid, MmcHostInstance->DevicePath, + NULL + ); + ASSERT_EFI_ERROR (Status); + + // Free Memory allocated for the instance + if (MmcHostInstance->BlockIo.Media) { + FreePool (MmcHostInstance->BlockIo.Media); + } + if (MmcHostInstance->CardInfo.ECSDData) { + FreePages (MmcHostInstance->CardInfo.ECSDData, EFI_SIZE_TO_PAGES (sizeof (ECSD))); + } + FreePool (MmcHostInstance); + + return Status; +} + +/** + This function checks if the controller implement the Mmc Host and the Device Path Protocols. + + @param This A pointer to the EFI_DRIVER_BINDING_PROTOCOL instance. + @param Controller The handle of the controller to check for support. + @param RemainingDevicePath A pointer to the remaining portion of the device path. + + @retval EFI_SUCCESS The controller is supported. + @retval EFI_UNSUPPORTED The controller is unsupported. +**/ +EFI_STATUS +EFIAPI +MmcDriverBindingSupported ( + IN EFI_DRIVER_BINDING_PROTOCOL *This, + IN EFI_HANDLE Controller, + IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath + ) +{ + EFI_STATUS Status; + //EFI_DEVICE_PATH_PROTOCOL *ParentDevicePath; + EFI_MMC_HOST_PROTOCOL *MmcHost; + EFI_DEV_PATH_PTR Node; + + // + // Check RemainingDevicePath validation + // + if (RemainingDevicePath != NULL) { + // + // Check if RemainingDevicePath is the End of Device Path Node, + // if yes, go on checking other conditions + // + if (!IsDevicePathEnd (RemainingDevicePath)) { + // + // If RemainingDevicePath isn't the End of Device Path Node, + // check its validation + // + Node.DevPath = RemainingDevicePath; + if (Node.DevPath->Type != HARDWARE_DEVICE_PATH || + Node.DevPath->SubType != HW_VENDOR_DP || + DevicePathNodeLength (Node.DevPath) != sizeof (VENDOR_DEVICE_PATH)) { + return EFI_UNSUPPORTED; + } + } + } + + // + // Check if Mmc Host protocol is installed by platform + // + Status = gBS->OpenProtocol ( + Controller, + &gSophgoMmcHostProtocolGuid, + (VOID**)&MmcHost, + This->DriverBindingHandle, + Controller, + EFI_OPEN_PROTOCOL_BY_DRIVER + ); + if (Status == EFI_ALREADY_STARTED) { + return EFI_SUCCESS; + } + if (EFI_ERROR (Status)) { + return Status; + } + + // + // Close the Mmc Host used to perform the supported test + // + gBS->CloseProtocol ( + Controller, + &gSophgoMmcHostProtocolGuid, + This->DriverBindingHandle, + Controller + ); + + return EFI_SUCCESS; +} + +/** + This function opens the Mmc Host Protocol, creates an MMC_HOST_INSTANCE, and adds it to the MMC host pool. + + @param This A pointer to the EFI_DRIVER_BINDING_PROTOCOL instance. + @param Controller The handle of the controller to start the driver on. + @param RemainingDevicePath A pointer to the remaining portion of the device path. + + @retval EFI_SUCCESS The driver is successfully started. + @retval Other The driver failed to start. + +**/ +EFI_STATUS +EFIAPI +MmcDriverBindingStart ( + IN EFI_DRIVER_BINDING_PROTOCOL *This, + IN EFI_HANDLE Controller, + IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath + ) +{ + EFI_STATUS Status; + MMC_HOST_INSTANCE *MmcHostInstance; + EFI_MMC_HOST_PROTOCOL *MmcHost; + + // + // Check RemainingDevicePath validation + // + if (RemainingDevicePath != NULL) { + // + // Check if RemainingDevicePath is the End of Device Path Node, + // if yes, return EFI_SUCCESS + // + if (IsDevicePathEnd (RemainingDevicePath)) { + return EFI_SUCCESS; + } + } + + // + // Get the Mmc Host protocol + // + Status = gBS->OpenProtocol ( + Controller, + &gSophgoMmcHostProtocolGuid, + (VOID**)&MmcHost, + This->DriverBindingHandle, + Controller, + EFI_OPEN_PROTOCOL_BY_DRIVER + ); + if (EFI_ERROR (Status)) { + if (Status == EFI_ALREADY_STARTED) { + return EFI_SUCCESS; + } + return Status; + } + + MmcHostInstance = CreateMmcHostInstance (MmcHost); + + if (MmcHostInstance != NULL) { + // Add the handle to the pool + InsertMmcHost (MmcHostInstance); + + MmcHostInstance->Initialized = FALSE; + + // Detect card presence now + CheckCardsCallback (NULL, NULL); + } + + return EFI_SUCCESS; +} + +/** + This function closes the Mmc Host Protocol, removes the MMC_HOST_INSTANCE from the pool, and destroys the instance. + + @param This A pointer to the EFI_DRIVER_BINDING_PROTOCOL instance. + @param Controller The handle of the controller to stop the driver on. + @param NumberOfChildren The number of children handles. + @param ChildHandleBuffer An array of child handles. + + @retval EFI_SUCCESS The driver is successfully stopped. + @retval Other The driver failed to stop. + +**/ +EFI_STATUS +EFIAPI +MmcDriverBindingStop ( + IN EFI_DRIVER_BINDING_PROTOCOL *This, + IN EFI_HANDLE Controller, + IN UINTN NumberOfChildren, + IN EFI_HANDLE *ChildHandleBuffer + ) +{ + EFI_STATUS Status = EFI_SUCCESS; + LIST_ENTRY *CurrentLink; + MMC_HOST_INSTANCE *MmcHostInstance; + + MMC_TRACE ("MmcDriverBindingStop()"); + + // For each MMC instance + CurrentLink = mMmcHostPool.ForwardLink; + while (CurrentLink != NULL && CurrentLink != &mMmcHostPool && (Status == EFI_SUCCESS)) { + MmcHostInstance = MMC_HOST_INSTANCE_FROM_LINK (CurrentLink); + ASSERT (MmcHostInstance != NULL); + + // Close gSophgoMmcHostProtocolGuid + Status = gBS->CloseProtocol ( + Controller, + &gSophgoMmcHostProtocolGuid, + (VOID**)&MmcHostInstance->MmcHost, + This->DriverBindingHandle + ); + + // Remove MMC Host Instance from the pool + RemoveMmcHost (MmcHostInstance); + + // Destroy MmcHostInstance + DestroyMmcHostInstance (MmcHostInstance); + } + + return Status; +} + +/** + Callback function to check MMC cards. + + @param[in] Event The event that is being triggered + @param[in] Context The context passed to the event + +**/ +VOID +EFIAPI +CheckCardsCallback ( + IN EFI_EVENT Event, + IN VOID *Context + ) +{ + LIST_ENTRY *CurrentLink; + MMC_HOST_INSTANCE *MmcHostInstance; + EFI_STATUS Status; + + CurrentLink = mMmcHostPool.ForwardLink; + while (CurrentLink != NULL && CurrentLink != &mMmcHostPool) { + MmcHostInstance = MMC_HOST_INSTANCE_FROM_LINK (CurrentLink); + ASSERT (MmcHostInstance != NULL); + + if (MmcHostInstance->MmcHost->IsCardPresent (MmcHostInstance->MmcHost) == !MmcHostInstance->Initialized) { + MmcHostInstance->State = MmcHwInitializationState; + MmcHostInstance->BlockIo.Media->MediaPresent = !MmcHostInstance->Initialized; + MmcHostInstance->Initialized = !MmcHostInstance->Initialized; + + if (MmcHostInstance->BlockIo.Media->MediaPresent) { + Status = InitializeMmcDevice (MmcHostInstance); + if (EFI_ERROR (Status)) { + DEBUG ((DEBUG_ERROR, "CheckCardsCallback: Error InitializeMmcDevice, Status=%r.\n", Status)); + MmcHostInstance->Initialized = !MmcHostInstance->Initialized; + continue; + } + } + + Status = gBS->ReinstallProtocolInterface ( + (MmcHostInstance->MmcHandle), + &gEfiBlockIoProtocolGuid, + &(MmcHostInstance->BlockIo), + &(MmcHostInstance->BlockIo) + ); + + if (EFI_ERROR (Status)) { + Print (L"MMC Card: Error reinstalling BlockIo interface\n"); + } + } + + CurrentLink = CurrentLink->ForwardLink; + } +} + + +EFI_DRIVER_BINDING_PROTOCOL gMmcDriverBinding = { + MmcDriverBindingSupported, + MmcDriverBindingStart, + MmcDriverBindingStop, + 0xa, + NULL, + NULL +}; + +/** + This function is the entry point of the MMC DXE driver. + It initializes the MMC host pool, installs driver model protocols, + driver diagnostics, and sets up a timer for card detection. + + @param ImageHandle The image handle of the driver. + @param SystemTable A pointer to the EFI system table. + + @retval EFI_SUCCESS The driver is successfully initialized. + @retval Other The driver failed to initialize. + +**/ +EFI_STATUS +EFIAPI +MmcDxeInitialize ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ) +{ + EFI_STATUS Status; + + // + // Initializes MMC Host pool + // + InitializeMmcHostPool (); + + // + // Install driver model protocol(s). + // + Status = EfiLibInstallDriverBindingComponentName2 ( + ImageHandle, + SystemTable, + &gMmcDriverBinding, + ImageHandle, + &gMmcComponentName, + &gMmcComponentName2 + ); + ASSERT_EFI_ERROR (Status); + + // Install driver diagnostics + Status = gBS->InstallMultipleProtocolInterfaces ( + &ImageHandle, + &gEfiDriverDiagnostics2ProtocolGuid, + &gMmcDriverDiagnostics2, + NULL + ); + ASSERT_EFI_ERROR (Status); + + // Use a timer to detect if a card has been plugged in or removed + Status = gBS->CreateEvent ( + EVT_NOTIFY_SIGNAL | EVT_TIMER, + TPL_CALLBACK, + CheckCardsCallback, + NULL, + &gCheckCardsEvent + ); + ASSERT_EFI_ERROR (Status); + + Status = gBS->SetTimer (gCheckCardsEvent, + TimerPeriodic, + (UINT64)(10 * 1000 * 200)); // 200 ms + ASSERT_EFI_ERROR (Status); + + return Status; +} diff --git a/Silicon/Sophgo/SG2042Pkg/Drivers/MmcDxe/MmcBlockIo.c b/Silicon/Sophgo/SG2042Pkg/Drivers/MmcDxe/MmcBlockIo.c new file mode 100644 index 000000000000..31d2534402e0 --- /dev/null +++ b/Silicon/Sophgo/SG2042Pkg/Drivers/MmcDxe/MmcBlockIo.c @@ -0,0 +1,646 @@ +/** @file + Block I/O Protocol implementation for MMC/SD cards. + + Copyright (c) 2011-2015, ARM Limited. All rights reserved. + + SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#include + +#include "Mmc.h" + +#define MMCI0_BLOCKLEN 512 +#define MMCI0_TIMEOUT 1000 +#define MAX_BUF_LEN 0x1D00000 +#define MAX_BLK_CNT 0xE800 + +/** + Check if the R1 response indicates that the card is in the "Tran" state and ready for data. + + @param[in] Response Pointer to the R1 response. + + @retval EFI_SUCCESS The card is in the "Tran" state and ready for data. + @retval EFI_NOT_READY The card is not in the expected state. +**/ +STATIC +EFI_STATUS +R1TranAndReady ( + UINT32 *Response + ) +{ + if ((*Response & MMC_R0_READY_FOR_DATA) != 0 && MMC_R0_CURRENTSTATE (Response) == MMC_R0_STATE_TRAN) { + return EFI_SUCCESS; + } + + return EFI_NOT_READY; +} + +/** + Validate the number of blocks written during a write operation. + + @param[in] MmcHostInstance Pointer to the MMC host instance. + @param[in] Count Expected number of blocks written. + @param[out] TransferredBlocks Actual number of blocks written. + + @retval EFI_SUCCESS The number of blocks written is valid. + @retval EFI_NOT_READY The card is not in the expected state. + @retval EFI_DEVICE_ERROR The number of blocks written is incorrect. + @retval Other An error occurred during the validation process. + +**/ +STATIC +EFI_STATUS +ValidateWrittenBlockCount ( + IN MMC_HOST_INSTANCE *MmcHostInstance, + IN UINTN Count, + OUT UINTN *TransferredBlocks + ) +{ + UINT32 R1; + UINT8 Data[4]; + EFI_STATUS Status; + UINT32 BlocksWritten; + EFI_MMC_HOST_PROTOCOL *MmcHost; + + if (MmcHostInstance->CardInfo.CardType == MMC_CARD || + MmcHostInstance->CardInfo.CardType == MMC_CARD_HIGH || + MmcHostInstance->CardInfo.CardType == EMMC_CARD) { + /* + * Not on MMC. + */ + *TransferredBlocks = Count; + return EFI_SUCCESS; + } + + MmcHost = MmcHostInstance->MmcHost; + + Status = MmcHost->SendCommand (MmcHost, MMC_CMD55, + MmcHostInstance->CardInfo.RCA << 16, MMC_RESPONSE_R1, &R1); + if (EFI_ERROR (Status)) { + DEBUG ((DEBUG_ERROR, "%a(%u): error: %r\n", __func__, __LINE__, Status)); + return Status; + } + + Status = MmcHost->SendCommand (MmcHost, MMC_ACMD22, 0, MMC_RESPONSE_R1, &R1); + if (EFI_ERROR (Status)) { + DEBUG ((DEBUG_ERROR, "%a(%u): error: %r\n", + __func__, __LINE__, Status)); + return Status; + } + + Status = R1TranAndReady (&R1); + if (EFI_ERROR (Status)) { + return Status; + } + + // Read Data + Status = MmcHost->ReadBlockData (MmcHost, 0, sizeof (Data), + (VOID*)Data); + if (EFI_ERROR (Status)) { + DEBUG ((DEBUG_ERROR, "%a(%u): error: %r\n", __func__, __LINE__, Status)); + return Status; + } + + /* + * Big Endian. + */ + BlocksWritten = ((UINT32)Data[0] << 24) | + ((UINT32)Data[1] << 16) | + ((UINT32)Data[2] << 8) | + ((UINT32)Data[3] << 0); + if (BlocksWritten != Count) { + DEBUG ((DEBUG_ERROR, "%a(%u): expected %u != gotten %u\n", + __func__, __LINE__, Count, BlocksWritten)); + if (BlocksWritten == 0) { + return EFI_DEVICE_ERROR; + } + } + + *TransferredBlocks = BlocksWritten; + return EFI_SUCCESS; +} + +/** + Wait until the card is in the "Tran" state. + + @param[in] MmcHostInstance Pointer to the MMC host instance. + + @retval EFI_SUCCESS The card is in the "Tran" state. + @retval EFI_NOT_READY The card is not in the expected state or timed out. + @retval Other An error occurred during the waiting process. + +**/ +STATIC +EFI_STATUS +WaitUntilTran ( + IN MMC_HOST_INSTANCE *MmcHostInstance + ) +{ + INTN Timeout; + UINT32 Response[1]; + EFI_STATUS Status; + EFI_MMC_HOST_PROTOCOL *MmcHost; + + Timeout = MMCI0_TIMEOUT; + Status = EFI_SUCCESS; + MmcHost = MmcHostInstance->MmcHost; + + while (Timeout--) { + /* + * We expect CMD13 to timeout while card is programming, + * because the card holds DAT0 low (busy). + */ + Status = MmcHost->SendCommand (MmcHost, MMC_CMD13, + MmcHostInstance->CardInfo.RCA << 16, MMC_RESPONSE_R1, Response); + if (EFI_ERROR (Status) && Status != EFI_TIMEOUT) { + DEBUG ((DEBUG_ERROR, "%a(%u) CMD13 failed: %r\n", __func__, __LINE__, Status)); + return Status; + } + + if (Status == EFI_SUCCESS) { + Status = R1TranAndReady (Response); + if (!EFI_ERROR (Status)) { + break; + } + } + gBS->Stall(1000); + } + + if (0 == Timeout) { + DEBUG ((DEBUG_ERROR, "%a(%u) card is busy\n", __func__, __LINE__)); + return EFI_NOT_READY; + } + + return Status; +} + +/** + Sets the state of the MMC host instance and invokes the + NotifyState function of the MMC host, passing the updated state. + + @param MmcHostInstance Pointer to the MMC host instance. + @param State The new state to be set for the MMC host instance. + + @retval EFI_STATUS + +**/ +EFI_STATUS +MmcNotifyState ( + IN MMC_HOST_INSTANCE *MmcHostInstance, + IN MMC_STATE State + ) +{ + MmcHostInstance->State = State; + return MmcHostInstance->MmcHost->NotifyState (MmcHostInstance->MmcHost, State); +} + +/** + Reset the block device. + + This function implements EFI_BLOCK_IO_PROTOCOL.Reset(). + It resets the block device hardware. + ExtendedVerification is ignored in this implementation. + + @param This Indicates a pointer to the calling context. + @param ExtendedVerification Indicates that the driver may perform a more exhaustive + verification operation of the device during reset. + + @retval EFI_SUCCESS The block device was reset. + @retval EFI_DEVICE_ERROR The block device is not functioning correctly and could not be reset. + +**/ +EFI_STATUS +EFIAPI +MmcReset ( + IN EFI_BLOCK_IO_PROTOCOL *This, + IN BOOLEAN ExtendedVerification + ) +{ + MMC_HOST_INSTANCE *MmcHostInstance; + + MmcHostInstance = MMC_HOST_INSTANCE_FROM_BLOCK_IO_THIS (This); + + if (MmcHostInstance->MmcHost == NULL) { + // Nothing to do + return EFI_SUCCESS; + } + + // If a card is not present then clear all media settings + if (!MmcHostInstance->MmcHost->IsCardPresent (MmcHostInstance->MmcHost)) { + MmcHostInstance->BlockIo.Media->MediaPresent = FALSE; + MmcHostInstance->BlockIo.Media->LastBlock = 0; + MmcHostInstance->BlockIo.Media->BlockSize = 512; // Should be zero but there is a bug in DiskIo + MmcHostInstance->BlockIo.Media->ReadOnly = FALSE; + + // Indicate that the driver requires initialization + MmcHostInstance->State = MmcHwInitializationState; + + return EFI_SUCCESS; + } + + // Implement me. Either send a CMD0 (could not work for some MMC host) + // or just turn off/turn on power and restart Identification mode. + return EFI_SUCCESS; +} + +/** + Detect if an MMC card is present. + + @param[in] MmcHost Pointer to the EFI_MMC_HOST_PROTOCOL instance. + + @retval EFI_NO_MEDIA No MMC card is present. + @retval EFI_SUCCESS An MMC card is present. + +**/ +EFI_STATUS +MmcDetectCard ( + EFI_MMC_HOST_PROTOCOL *MmcHost + ) +{ + if (!MmcHost->IsCardPresent (MmcHost)) { + return EFI_NO_MEDIA; + } else { + return EFI_SUCCESS; + } +} + +/** + Stop the current transmission on the MMC bus. + + @param[in] MmcHost Pointer to the EFI_MMC_HOST_PROTOCOL instance. + + @retval EFI_SUCCESS The transmission was successfully stopped. + @retval Other An error occurred while stopping the transmission. + +**/ +EFI_STATUS +MmcStopTransmission ( + EFI_MMC_HOST_PROTOCOL *MmcHost + ) +{ + EFI_STATUS Status; + UINT32 Response[4]; + // Command 12 - Stop transmission (ends read or write) + // Normally only needed for streaming transfers or after error. + Status = MmcHost->SendCommand (MmcHost, MMC_CMD12, 0, MMC_RESPONSE_R1B, Response); + return Status; +} + +/** + Transfer a block of data to or from the MMC device. + + @param[in] This Pointer to the EFI_BLOCK_IO_PROTOCOL instance. + @param[in] Cmd Command to be sent to the MMC device. + @param[in] Transfer Transfer type (MMC_IOBLOCKS_READ or MMC_IOBLOCKS_WRITE). + @param[in] MediaId Media ID of the MMC device. + @param[in] Lba Logical Block Address. + @param[in] BufferSize Size of the data buffer. + @param[out] Buffer Pointer to the data buffer. + @param[out] TransferredSize Number of bytes transferred. + + @retval EFI_SUCCESS The data transfer was successful. + @retval EFI_NOT_READY The MMC device is not ready for the transfer. + @retval EFI_DEVICE_ERROR An error occurred during the data transfer. + @retval Other An error occurred during the data transfer. + +**/ +STATIC +EFI_STATUS +MmcTransferBlock ( + IN EFI_BLOCK_IO_PROTOCOL *This, + IN UINTN Cmd, + IN UINTN Transfer, + IN UINT32 MediaId, + IN EFI_LBA Lba, + IN UINTN BufferSize, + OUT VOID *Buffer, + OUT UINTN *TransferredSize + ) +{ + EFI_STATUS Status; + MMC_HOST_INSTANCE *MmcHostInstance; + EFI_MMC_HOST_PROTOCOL *MmcHost; + UINTN CmdArg; + + DEBUG ((DEBUG_VERBOSE, "%a(): Lba: %lx\n", __func__, Lba)); + DEBUG ((DEBUG_VERBOSE, "%a(): BufferSize: %lx\n", __func__, BufferSize)); + + MmcHostInstance = MMC_HOST_INSTANCE_FROM_BLOCK_IO_THIS (This); + MmcHost = MmcHostInstance->MmcHost; + + //Set command argument based on the card access mode (Byte mode or Block mode) + if ((MmcHostInstance->CardInfo.OCRData.AccessMode & MMC_OCR_ACCESS_MASK) == MMC_OCR_ACCESS_SECTOR) { + CmdArg = Lba; + } else { + CmdArg = Lba * This->Media->BlockSize; + } + + Status = MmcHost->SendCommand (MmcHost, Cmd, CmdArg, MMC_RESPONSE_R1, NULL); + if (EFI_ERROR (Status)) { + DEBUG ((DEBUG_ERROR, "%a(MMC_CMD%d): Error %r\n", __func__, MMC_INDX (Cmd), Status)); + return Status; + } + + if (Transfer == MMC_IOBLOCKS_READ) { + Status = MmcHost->ReadBlockData (MmcHost, Lba, BufferSize, Buffer); + } else { + Status = MmcHost->WriteBlockData (MmcHost, Lba, BufferSize, Buffer); + if (!EFI_ERROR (Status)) { + Status = MmcNotifyState (MmcHostInstance, MmcProgrammingState); + if (EFI_ERROR (Status)) { + DEBUG ((DEBUG_ERROR, "%a(): Error MmcProgrammingState\n", __func__)); + return Status; + } + } + } + + if (EFI_ERROR (Status) || + BufferSize > This->Media->BlockSize) { + /* + * CMD12 needs to be set for multiblock (to transition from + * RECV to PROG) or for errors. + */ + EFI_STATUS Status2 = MmcStopTransmission (MmcHost); + if (EFI_ERROR (Status2)) { + DEBUG ((DEBUG_ERROR, "MmcIoBlocks(): CMD12 error on Status %r: %r\n", + Status, Status2)); + return Status2; + } + + if (EFI_ERROR (Status)) { + DEBUG ((DEBUG_BLKIO, "%a(): Error %a Block Data and Status = %r\n", + __func__, Transfer == MMC_IOBLOCKS_READ ? "Read" : "Write", Status)); + return Status; + } + + ASSERT (Cmd == MMC_CMD25 || Cmd == MMC_CMD18); + } + + // + // For reads, should be already in TRAN. For writes, wait + // until programming finishes. + // + Status = WaitUntilTran (MmcHostInstance); + if (EFI_ERROR (Status)) { + DEBUG ((DEBUG_ERROR, "WaitUntilTran after write failed\n")); + return Status; + } + + Status = MmcNotifyState (MmcHostInstance, MmcTransferState); + if (EFI_ERROR (Status)) { + DEBUG ((DEBUG_ERROR, "MmcIoBlocks() : Error MmcTransferState\n")); + return Status; + } + + if (Transfer != MMC_IOBLOCKS_READ) { + UINTN BlocksWritten = 0; + + Status = ValidateWrittenBlockCount (MmcHostInstance, + BufferSize / + This->Media->BlockSize, + &BlocksWritten); + *TransferredSize = BlocksWritten * This->Media->BlockSize; + } else { + *TransferredSize = BufferSize; + } + + return Status; +} + +/** + Perform read or write operations on the MMC device. + + @param[in] This Pointer to the EFI_BLOCK_IO_PROTOCOL instance. + @param[in] Transfer Transfer type (MMC_IOBLOCKS_READ or MMC_IOBLOCKS_WRITE). + @param[in] MediaId Media ID of the MMC device. + @param[in] Lba Logical Block Address. + @param[in] BufferSize Size of the data buffer. + @param[out] Buffer Pointer to the data buffer. + + @retval EFI_SUCCESS The operation completed successfully. + @retval EFI_MEDIA_CHANGED The MediaId is not the current media. + @retval EFI_INVALID_PARAMETER Invalid parameter passed to the function. + @retval EFI_NO_MEDIA There is no media present in the MMC device. + @retval EFI_WRITE_PROTECTED The MMC device is write-protected. + @retval EFI_BAD_BUFFER_SIZE The buffer size is not an exact multiple of the block size. + @retval Other An error occurred during the data transfer. + +**/ +EFI_STATUS +MmcIoBlocks ( + IN EFI_BLOCK_IO_PROTOCOL *This, + IN UINTN Transfer, + IN UINT32 MediaId, + IN EFI_LBA Lba, + IN UINTN BufferSize, + OUT VOID *Buffer + ) +{ + EFI_STATUS Status; + UINTN Cmd; + MMC_HOST_INSTANCE *MmcHostInstance; + EFI_MMC_HOST_PROTOCOL *MmcHost; + UINTN BytesRemainingToBeTransfered; + UINTN BlockCount; + UINTN ConsumeSize; + + BlockCount = 1; + MmcHostInstance = MMC_HOST_INSTANCE_FROM_BLOCK_IO_THIS (This); + ASSERT (MmcHostInstance != NULL); + + MmcHost = MmcHostInstance->MmcHost; + ASSERT (MmcHost); + + if (This->Media->MediaId != MediaId) { + return EFI_MEDIA_CHANGED; + } + + if ((MmcHost == NULL) || (Buffer == NULL)) { + return EFI_INVALID_PARAMETER; + } + + // Check if a Card is Present + if (!MmcHostInstance->BlockIo.Media->MediaPresent) { + return EFI_NO_MEDIA; + } + + if (MMC_HOST_HAS_ISMULTIBLOCK (MmcHost) && + MmcHost->IsMultiBlock (MmcHost)) { + BlockCount = (BufferSize + This->Media->BlockSize - 1) / This->Media->BlockSize; + } + + // All blocks must be within the device + if ((Lba + (BufferSize / This->Media->BlockSize)) > (This->Media->LastBlock + 1)) { + return EFI_INVALID_PARAMETER; + } + + if ((Transfer == MMC_IOBLOCKS_WRITE) && (This->Media->ReadOnly == TRUE)) { + return EFI_WRITE_PROTECTED; + } + + // Reading 0 Byte is valid + if (BufferSize == 0) { + return EFI_SUCCESS; + } + + // The buffer size must be an exact multiple of the block size + if ((BufferSize % This->Media->BlockSize) != 0) { + return EFI_BAD_BUFFER_SIZE; + } + + // Check the alignment + if ((This->Media->IoAlign > 2) && (((UINTN)Buffer & (This->Media->IoAlign - 1)) != 0)) { + return EFI_INVALID_PARAMETER; + } + + BytesRemainingToBeTransfered = BufferSize; + while (BytesRemainingToBeTransfered > 0) { + Status = WaitUntilTran (MmcHostInstance); + if (EFI_ERROR (Status)) { + DEBUG ((DEBUG_ERROR, "WaitUntilTran before IO failed")); + return Status; + } + + if (Transfer == MMC_IOBLOCKS_READ) { + if (BlockCount == 1) { + // Read a single block + Cmd = MMC_CMD17; + } else { + // Read multiple blocks + Cmd = MMC_CMD18; + } + } else { + if (BlockCount == 1) { + // Write a single block + Cmd = MMC_CMD24; + } else { + // Write multiple blocks + Cmd = MMC_CMD25; + } + } + + ConsumeSize = BlockCount * This->Media->BlockSize; + if (BytesRemainingToBeTransfered < ConsumeSize) { + ConsumeSize = BytesRemainingToBeTransfered; + } + + if (ConsumeSize > MAX_BUF_LEN) { + ConsumeSize = MAX_BUF_LEN; + BlockCount = MAX_BLK_CNT; + } else { + BlockCount = ConsumeSize / This->Media->BlockSize; + } + + MmcHost->Prepare (MmcHost, Lba, ConsumeSize, (UINTN)Buffer); + + Status = MmcTransferBlock (This, Cmd, Transfer, MediaId, Lba, ConsumeSize, Buffer, &ConsumeSize); + if (EFI_ERROR (Status)) { + DEBUG ((DEBUG_ERROR, "%a(): Failed to transfer block and Status:%r\n", __func__, Status)); + return Status; + } + + BytesRemainingToBeTransfered -= ConsumeSize; + if (BytesRemainingToBeTransfered > 0) { + Lba += BlockCount; + Buffer = (UINT8*)Buffer + ConsumeSize; + } + } + + return EFI_SUCCESS; +} + +/** + Reads the requested number of blocks from the device. + + This function implements EFI_BLOCK_IO_PROTOCOL.ReadBlocks(). + It reads the requested number of blocks from the device. + All the blocks are read, or an error is returned. + + @param This Indicates a pointer to the calling context. + @param MediaId The media ID that the read request is for. + @param Lba The starting logical block address to read from on the device. + @param BufferSize The size of the Buffer in bytes. + This must be a multiple of the intrinsic block size of the device. + @param Buffer A pointer to the destination buffer for the data. The caller is + responsible for either having implicit or explicit ownership of the buffer. + + @retval EFI_SUCCESS The data was read correctly from the device. + @retval EFI_DEVICE_ERROR The device reported an error while attempting to perform the read operation. + @retval EFI_NO_MEDIA There is no media in the device. + @retval EFI_MEDIA_CHANGED The MediaId is not for the current media. + @retval EFI_BAD_BUFFER_SIZE The BufferSize parameter is not a multiple of the intrinsic block size of the device. + @retval EFI_INVALID_PARAMETER The read request contains LBAs that are not valid, + or the buffer is not on proper alignment. + +**/ +EFI_STATUS +EFIAPI +MmcReadBlocks ( + IN EFI_BLOCK_IO_PROTOCOL *This, + IN UINT32 MediaId, + IN EFI_LBA Lba, + IN UINTN BufferSize, + OUT VOID *Buffer + ) +{ + return MmcIoBlocks (This, MMC_IOBLOCKS_READ, MediaId, Lba, BufferSize, Buffer); +} + +/** + Writes a specified number of blocks to the device. + + This function implements EFI_BLOCK_IO_PROTOCOL.WriteBlocks(). + It writes a specified number of blocks to the device. + All blocks are written, or an error is returned. + + @param This Indicates a pointer to the calling context. + @param MediaId The media ID that the write request is for. + @param Lba The starting logical block address to be written. + @param BufferSize The size of the Buffer in bytes. + This must be a multiple of the intrinsic block size of the device. + @param Buffer Pointer to the source buffer for the data. + + @retval EFI_SUCCESS The data were written correctly to the device. + @retval EFI_WRITE_PROTECTED The device cannot be written to. + @retval EFI_NO_MEDIA There is no media in the device. + @retval EFI_MEDIA_CHANGED The MediaId is not for the current media. + @retval EFI_DEVICE_ERROR The device reported an error while attempting to perform the write operation. + @retval EFI_BAD_BUFFER_SIZE The BufferSize parameter is not a multiple of the intrinsic + block size of the device. + @retval EFI_INVALID_PARAMETER The write request contains LBAs that are not valid, + or the buffer is not on proper alignment. + +**/ +EFI_STATUS +EFIAPI +MmcWriteBlocks ( + IN EFI_BLOCK_IO_PROTOCOL *This, + IN UINT32 MediaId, + IN EFI_LBA Lba, + IN UINTN BufferSize, + IN VOID *Buffer + ) +{ + return MmcIoBlocks (This, MMC_IOBLOCKS_WRITE, MediaId, Lba, BufferSize, Buffer); +} + +/** + Flushes all modified data to a physical block device. + + @param This Indicates a pointer to the calling context. + + @retval EFI_SUCCESS All outstanding data were written correctly to the device. + @retval EFI_DEVICE_ERROR The device reported an error while attempting to write data. + @retval EFI_NO_MEDIA There is no media in the device. + +**/ +EFI_STATUS +EFIAPI +MmcFlushBlocks ( + IN EFI_BLOCK_IO_PROTOCOL *This + ) +{ + return EFI_SUCCESS; +} diff --git a/Silicon/Sophgo/SG2042Pkg/Drivers/MmcDxe/MmcDebug.c b/Silicon/Sophgo/SG2042Pkg/Drivers/MmcDxe/MmcDebug.c new file mode 100644 index 000000000000..62386d7b0373 --- /dev/null +++ b/Silicon/Sophgo/SG2042Pkg/Drivers/MmcDxe/MmcDebug.c @@ -0,0 +1,194 @@ +/** @file + Provides debug functions for MMC/SD card operations. + + Copyright (c) 2011-2013, ARM Limited. All rights reserved. + + SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#include "Mmc.h" + +#if !defined(MDEPKG_NDEBUG) +CONST CHAR8* mStrUnit[] = { "100kbit/s", "1Mbit/s", "10Mbit/s", "100MBit/s", + "Unknown", "Unknown", "Unknown", "Unknown" }; +CONST CHAR8* mStrValue[] = { "1.0", "1.2", "1.3", "1.5", "2.0", "2.5", + "3.0", "3.5", "4.0", "4.5", "5.0", "5.5", + "6.0", "7.0", "8.0" }; +#endif + +/** + Print the Card Identification (CID) register. + + @param[in] Cid Pointer to the CID array. + +**/ +VOID +PrintCID ( + IN UINT32* Cid + ) +{ + DEBUG ((DEBUG_ERROR, "- PrintCID\n")); + DEBUG ((DEBUG_ERROR, "\t- Manufacturing date: %d/%d\n", (Cid[0] >> 8) & 0xF, (Cid[0] >> 12) & 0xFF)); + DEBUG ((DEBUG_ERROR, "\t- Product serial number: 0x%X%X\n", Cid[1] & 0xFFFFFF, (Cid[0] >> 24) & 0xFF)); + DEBUG ((DEBUG_ERROR, "\t- Product revision: %d\n", Cid[1] >> 24)); + //DEBUG ((DEBUG_ERROR, "\t- Product name: %s\n", (char*)(Cid + 2))); + DEBUG ((DEBUG_ERROR, "\t- OEM ID: %c%c\n", (Cid[3] >> 8) & 0xFF, (Cid[3] >> 16) & 0xFF)); +} + +/** + Print the Card Specific Data (CSD). + + @param[in] Csd Pointer to the CSD array + +**/ +VOID +PrintCSD ( + IN UINT32* Csd + ) +{ + UINTN Value; + + if (((Csd[2] >> 30) & 0x3) == 0) { + DEBUG ((DEBUG_ERROR, "- PrintCSD Version 1.01-1.10/Version 2.00/Standard Capacity\n")); + } else if (((Csd[2] >> 30) & 0x3) == 1) { + DEBUG ((DEBUG_ERROR, "- PrintCSD Version 2.00/High Capacity\n")); + } else { + DEBUG ((DEBUG_ERROR, "- PrintCSD Version Higher than v3.3\n")); + } + + DEBUG ((DEBUG_ERROR, "\t- Supported card command class: 0x%X\n", MMC_CSD_GET_CCC (Csd))); + DEBUG ((DEBUG_ERROR, "\t- Max Speed: %a * %a\n", mStrValue[(MMC_CSD_GET_TRANSPEED (Csd) >> 3) & 0xF], + mStrUnit[MMC_CSD_GET_TRANSPEED (Csd) & 7])); + DEBUG ((DEBUG_ERROR, "\t- Maximum Read Data Block: %d\n", 2 << (MMC_CSD_GET_READBLLEN (Csd) - 1))); + DEBUG ((DEBUG_ERROR, "\t- Maximum Write Data Block: %d\n", 2 << (MMC_CSD_GET_WRITEBLLEN (Csd) - 1))); + + if (!MMC_CSD_GET_FILEFORMATGRP (Csd)) { + Value = MMC_CSD_GET_FILEFORMAT (Csd); + if (Value == 0) { + DEBUG ((DEBUG_ERROR, "\t- Format (0): Hard disk-like file system with partition table\n")); + } else if (Value == 1) { + DEBUG ((DEBUG_ERROR, "\t- Format (1): DOS FAT (floppy-like) with boot sector only (no partition table)\n")); + } else if (Value == 2) { + DEBUG ((DEBUG_ERROR, "\t- Format (2): Universal File Format\n")); + } else { + DEBUG ((DEBUG_ERROR, "\t- Format (3): Others/Unknown\n")); + } + } else { + DEBUG ((DEBUG_ERROR, "\t- Format: Reserved\n")); + } +} + +/** + Print the Relative Card Address (RCA). + + @param[in] Rca The Relative Card Address (RCA) value + +**/ +VOID +PrintRCA ( + IN UINT32 Rca + ) +{ + DEBUG ((DEBUG_ERROR, "- PrintRCA: 0x%X\n", Rca)); + DEBUG ((DEBUG_ERROR, "\t- Status: 0x%X\n", Rca & 0xFFFF)); + DEBUG ((DEBUG_ERROR, "\t- RCA: 0x%X\n", (Rca >> 16) & 0xFFFF)); +} + +/** + Print the Operation Condition Register (OCR). + + @param[in] Ocr The Operation Condition Register (OCR) value + +**/ +VOID +PrintOCR ( + IN UINT32 Ocr + ) +{ + UINTN MinV; + UINTN MaxV; + UINTN Volts; + UINTN Loop; + + MinV = 36; // 3.6 + MaxV = 20; // 2.0 + Volts = 20; // 2.0 + + // The MMC register bits [23:8] indicate the working range of the card + for (Loop = 8; Loop < 24; Loop++) { + if (Ocr & (1 << Loop)) { + if (MinV > Volts) { + MinV = Volts; + } + if (MaxV < Volts) { + MaxV = Volts + 1; + } + } + Volts++; + } + + DEBUG ((DEBUG_ERROR, "- PrintOCR Ocr (0x%X)\n", Ocr)); + DEBUG ((DEBUG_ERROR, "\t- Card operating voltage: %d.%d to %d.%d\n", MinV / 10, MinV % 10, MaxV / 10, MaxV % 10)); + if (((Ocr >> 29) & 3) == 0) { + DEBUG ((DEBUG_ERROR, "\t- AccessMode: Byte Mode\n")); + } else { + DEBUG ((DEBUG_ERROR, "\t- AccessMode: Block Mode (0x%X)\n", ((Ocr >> 29) & 3))); + } + + if (Ocr & MMC_OCR_POWERUP) { + DEBUG ((DEBUG_ERROR, "\t- PowerUp\n")); + } else { + DEBUG ((DEBUG_ERROR, "\t- Voltage Not Supported\n")); + } +} + +/** + Print the R1 response. + + @param[in] Response The R1 response value. + +**/ +VOID +PrintResponseR1 ( + IN UINT32 Response + ) +{ + DEBUG ((DEBUG_INFO, "Response: 0x%X\n", Response)); + if (Response & MMC_R0_READY_FOR_DATA) { + DEBUG ((DEBUG_INFO, "\t- READY_FOR_DATA\n")); + } + + switch ((Response >> 9) & 0xF) { + case 0: + DEBUG ((DEBUG_INFO, "\t- State: Idle\n")); + break; + case 1: + DEBUG ((DEBUG_INFO, "\t- State: Ready\n")); + break; + case 2: + DEBUG ((DEBUG_INFO, "\t- State: Ident\n")); + break; + case 3: + DEBUG ((DEBUG_INFO, "\t- State: StandBy\n")); + break; + case 4: + DEBUG ((DEBUG_INFO, "\t- State: Tran\n")); + break; + case 5: + DEBUG ((DEBUG_INFO, "\t- State: Data\n")); + break; + case 6: + DEBUG ((DEBUG_INFO, "\t- State: Rcv\n")); + break; + case 7: + DEBUG ((DEBUG_INFO, "\t- State: Prg\n")); + break; + case 8: + DEBUG ((DEBUG_INFO, "\t- State: Dis\n")); + break; + default: + DEBUG ((DEBUG_INFO, "\t- State: Reserved\n")); + break; + } +} diff --git a/Silicon/Sophgo/SG2042Pkg/Drivers/MmcDxe/MmcIdentification.c b/Silicon/Sophgo/SG2042Pkg/Drivers/MmcDxe/MmcIdentification.c new file mode 100644 index 000000000000..67257a3f9755 --- /dev/null +++ b/Silicon/Sophgo/SG2042Pkg/Drivers/MmcDxe/MmcIdentification.c @@ -0,0 +1,719 @@ +/** @file + Define a simple and generic interface to access SD-card devices. + + Copyright (c) 2018-2021, ARM Limited and Contributors. All rights reserved. + Copyright (c) 2023, Academy of Intelligent Innovation, Shandong Universiy, China.P.R. All rights reserved.
+ + SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#include +#include +#include +#include +#include +#include +#include + +#include "Mmc.h" + +#define MMC_DEFAULT_MAX_RETRIES 5 +#define SEND_OP_COND_MAX_RETRIES 100 + +#define MULT_BY_512K_SHIFT 19 + +STATIC UINT32 MmcOCR; +STATIC CSD MmcCsd; +STATIC UINT8 MmcExtCsd[512] __attribute__ ((aligned(16))); +STATIC UINT32 MmcRCA; +STATIC UINT32 MmcSCR[2] __attribute__ ((aligned(16))) = { 0 }; + +typedef enum _MMC_DEVICE_TYPE { + MMC_IS_EMMC, + MMC_IS_SD, + MMC_IS_SD_HC, +} MMC_DEVICE_TYPE; + +typedef struct { + UINT64 DeviceSize; /* Size of device in bytes */ + UINT32 BlockSize; /* Block size in bytes */ + UINT32 MaxBusFreq; /* Max bus freq in Hz */ + UINT32 OCRVoltage; /* OCR voltage */ + MMC_DEVICE_TYPE MmcDevType; /* Type of MMC */ +} MMC_DEVICE_INFO; + +STATIC MMC_DEVICE_INFO MmcDevInfo = { + .MmcDevType = MMC_IS_SD_HC, + .OCRVoltage = 0x00300000, // OCR 3.2~3.3 3.3~3.4 +}; + +STATIC CONST UINT8 TranSpeedBase[16] = { + 0, 10, 12, 13, 15, 20, 26, 30, 35, 40, 45, 52, 55, 60, 70, 80 +}; + +STATIC CONST UINT8 SdTranSpeedBase[16] = { + 0, 10, 12, 13, 15, 20, 25, 30, 35, 40, 45, 50, 55, 60, 70, 80 +}; + +/** + Get the current state of the MMC device. + + @param[in] MmcHostInstance Pointer to the MMC_HOST_INSTANCE structure. + @param[out] State Pointer to the variable to store the device state. + + @retval EFI_SUCCESS The device state was retrieved successfully. + @retval EFI_DEVICE_ERROR Failed to retrieve the device state. + +**/ +STATIC +EFI_STATUS +MmcDeviceState ( + IN MMC_HOST_INSTANCE *MmcHostInstance, + IN UINT32 *State + ) +{ + EFI_STATUS Status; + INT32 RetryCount; + UINT32 Response[4]; + + RetryCount = MMC_DEFAULT_MAX_RETRIES; + + do { + if (RetryCount == 0) { + DEBUG ((DEBUG_ERROR, "%a: CMD13 failed after %d retries\n", __func__, MMC_DEFAULT_MAX_RETRIES)); + return EFI_DEVICE_ERROR; + } + + Status = MmcHostInstance->MmcHost->SendCommand (MmcHostInstance->MmcHost, MMC_CMD13, MmcRCA << RCA_SHIFT_OFFSET, + MMC_RESPONSE_R1, Response); + if (EFI_ERROR (Status)) { + RetryCount--; + continue; + } + + if ((Response[0] & MMC_R0_SWITCH_ERROR) != 0U) { + return EFI_DEVICE_ERROR; + } + + RetryCount--; + } while ((Response[0] & MMC_R0_READY_FOR_DATA) == 0U); + + // DEBUG ((DEBUG_INFO, "%a: sd state %x\n", __func__, MMC_R0_CURRENTSTATE(Response))); + *State = MMC_R0_CURRENTSTATE (Response); + + return EFI_SUCCESS; +} + +/** + Set the value of the specified MMC extended CSD register. + + @param[in] MmcHostInstance Pointer to the MMC_HOST_INSTANCE structure. + @param[in] ExtCmd The extended CSD command. + @param[in] Value The value to set. + + @retval EFI_SUCCESS The value was successfully set. + @retval Other An error occurred while setting the value. + +**/ +STATIC +EFI_STATUS +MmcSetExtCsd ( + IN MMC_HOST_INSTANCE *MmcHostInstance, + IN UINT32 ExtCmd, + IN UINT32 Value + ) +{ + EFI_STATUS Status; + UINT32 State; + + Status = MmcHostInstance->MmcHost->SendCommand (MmcHostInstance->MmcHost, MMC_CMD6, + EXTCSD_WRITE_BYTES | EXTCSD_CMD(ExtCmd) | + EXTCSD_VALUE(Value) | EXTCSD_CMD_SET_NORMAL, + MMC_RESPONSE_R1B, NULL); + if (EFI_ERROR (Status)) { + return Status; + } + + do { + Status = MmcDeviceState (MmcHostInstance, &State); + if (EFI_ERROR (Status)) { + return Status; + } + } while (State == MMC_R0_STATE_PROG); + + return EFI_SUCCESS; +} + +/** + Perform an SD switch to set the bus width for the MMC/SD device. + + @param[in] MmcHostInstance Pointer to the MMC_HOST_INSTANCE structure. + @param[in] BusWidth The desired bus width. + + @retval EFI_SUCCESS The bus width was successfully set. + @retval Other An error occurred while setting the bus width. + +**/ +STATIC +EFI_STATUS +MmcSdSwitch ( + IN MMC_HOST_INSTANCE *MmcHostInstance, + IN UINT32 BusWidth + ) +{ + EFI_STATUS Status; + UINT32 State; + INT32 RetryCount; + UINT32 BusWidthArg; + + RetryCount = MMC_DEFAULT_MAX_RETRIES; + BusWidthArg = 0; + + Status = MmcHostInstance->MmcHost->Prepare (MmcHostInstance->MmcHost, 0, sizeof(MmcSCR), (UINTN)&MmcSCR); + if (EFI_ERROR (Status)) { + return Status; + } + + // CMD55: Application Specific Command + Status = MmcHostInstance->MmcHost->SendCommand (MmcHostInstance->MmcHost, MMC_CMD55, MmcRCA << RCA_SHIFT_OFFSET, + MMC_RESPONSE_R5, NULL); + if (EFI_ERROR (Status)) { + return Status; + } + + // ACMD51: SEND_SCR + do { + Status = MmcHostInstance->MmcHost->SendCommand (MmcHostInstance->MmcHost, MMC_ACMD51, 0, MMC_RESPONSE_R1, NULL); + if ((EFI_ERROR (Status)) && (RetryCount == 0)) { + DEBUG ((DEBUG_ERROR, "%a: ACMD51 failed after %d retries (Status=%r)\n", __func__, MMC_DEFAULT_MAX_RETRIES, Status)); + return Status; + } + + RetryCount--; + } while (EFI_ERROR (Status)); + + Status = MmcHostInstance->MmcHost->ReadBlockData (MmcHostInstance->MmcHost, 0, sizeof(MmcSCR), MmcSCR); + if (EFI_ERROR (Status)) { + return Status; + } + + if (((MmcSCR[0] & SD_SCR_BUS_WIDTH_4) != 0U) && (BusWidth == MMC_BUS_WIDTH_4)) { + BusWidthArg = 2; + } + + // CMD55: Application Specific Command + Status = MmcHostInstance->MmcHost->SendCommand (MmcHostInstance->MmcHost, MMC_CMD55, MmcRCA << RCA_SHIFT_OFFSET, + MMC_RESPONSE_R5, NULL); + if (EFI_ERROR (Status)) { + return Status; + } + + // ACMD6: SET_BUS_WIDTH + Status = MmcHostInstance->MmcHost->SendCommand (MmcHostInstance->MmcHost, MMC_CMD6, BusWidthArg, MMC_RESPONSE_R1, NULL); + if (EFI_ERROR (Status)) { + return Status; + } + + do { + Status = MmcDeviceState (MmcHostInstance, &State); + if (EFI_ERROR (Status)) { + return Status; + } + } while (State == MMC_R0_STATE_PROG); + + return EFI_SUCCESS; +} + +/** + Set the I/O settings for the MMC/SD device. + + @param[in] MmcHostInstance Pointer to the MMC_HOST_INSTANCE structure. + @param[in] Clk The desired clock frequency. + @param[in] BusWidth The desired bus width. + + @retval EFI_SUCCESS The I/O settings were successfully set. + @retval Other An error occurred while setting the I/O settings. + +**/ +STATIC +EFI_STATUS +MmcSetIos ( + IN MMC_HOST_INSTANCE *MmcHostInstance, + IN UINT32 Clk, + IN UINT32 BusWidth + ) +{ + EFI_STATUS Status; + UINT32 Width; + + Width = BusWidth; + + if (MmcDevInfo.MmcDevType != MMC_IS_EMMC) { + if (Width == MMC_BUS_WIDTH_8) { + DEBUG ((DEBUG_INFO, "%a: Wrong bus config for SD-card, force to 4\n", __func__)); + Width = MMC_BUS_WIDTH_4; + } + + Status = MmcSdSwitch (MmcHostInstance, Width); + if (EFI_ERROR (Status)) { + return Status; + } + } else if (MmcCsd.SPEC_VERS == 4U) { + Status = MmcSetExtCsd (MmcHostInstance, CMD_EXTCSD_BUS_WIDTH, (UINT32)Width); + if (EFI_ERROR (Status)) { + return Status; + } + } else { + DEBUG ((DEBUG_INFO, "%a: Wrong MMC type or spec version\n", __func__)); + } + + return MmcHostInstance->MmcHost->SetIos (MmcHostInstance->MmcHost, Clk, Width); +} + +/** + Fill the MMC device information. + + @param[in] MmcHostInstance Pointer to the MMC_HOST_INSTANCE structure. + + @retval EFI_SUCCESS The MMC device information was successfully filled. + @retval EFI_DEVICE_ERROR Failed to fill the MMC device information. + @retval Other An error occurred while filling the MMC device information. + +**/ +STATIC +EFI_STATUS +MmcFillDeviceInfo ( + IN MMC_HOST_INSTANCE *MmcHostInstance + ) +{ + EFI_STATUS Status; + UINTN CardSize; + UINT32 SpeedIdx; + UINT32 NumBlocks; + UINT32 FreqUnit; + UINT32 State; + ECSD *CsdSdV2; + + Status = EFI_SUCCESS; + + switch (MmcDevInfo.MmcDevType) { + case MMC_IS_EMMC: + MmcDevInfo.BlockSize = MMC_BLOCK_SIZE; + + Status = MmcHostInstance->MmcHost->Prepare (MmcHostInstance->MmcHost, 0, sizeof(MmcExtCsd), (UINTN)&MmcExtCsd); + + if (EFI_ERROR (Status)) { + return Status; + } + + /* MMC CMD8: SEND_EXT_CSD */ + Status = MmcHostInstance->MmcHost->SendCommand (MmcHostInstance->MmcHost, MMC_CMD8, 0, MMC_RESPONSE_R1, NULL); + if (EFI_ERROR (Status)) { + return Status; + } + + Status = MmcHostInstance->MmcHost->ReadBlockData (MmcHostInstance->MmcHost, 0, sizeof(MmcExtCsd), (UINT32*)MmcExtCsd); + if (EFI_ERROR (Status)) { + return Status; + } + + do { + Status = MmcDeviceState (MmcHostInstance, &State); + if (EFI_ERROR (Status)) { + return Status; + } + } while (State != MMC_R0_STATE_TRAN); + + NumBlocks = (MmcExtCsd[CMD_EXTCSD_SEC_CNT] << 0) | + (MmcExtCsd[CMD_EXTCSD_SEC_CNT + 1] << 8) | + (MmcExtCsd[CMD_EXTCSD_SEC_CNT + 2] << 16) | + (MmcExtCsd[CMD_EXTCSD_SEC_CNT + 3] << 24); + + MmcDevInfo.DeviceSize = (UINT64)NumBlocks * MmcDevInfo.BlockSize; + + break; + + case MMC_IS_SD: + /* + * Use the same MmcCsd struct, as required fields here + * (READ_BL_LEN, C_SIZE, CSIZE_MULT) are common with eMMC. + */ + MmcDevInfo.BlockSize = BIT_32(MmcCsd.READ_BL_LEN); + + CardSize = ((UINT64)MmcCsd.C_SIZEHigh10 << 2U) | + (UINT64)MmcCsd.C_SIZELow2; + ASSERT(CardSize != 0xFFFU); + + MmcDevInfo.DeviceSize = (CardSize + 1U) * + BIT_64(MmcCsd.C_SIZE_MULT + 2U) * + MmcDevInfo.BlockSize; + + break; + + case MMC_IS_SD_HC: + MmcHostInstance->CardInfo.CardType = SD_CARD_2_HIGH; + + ASSERT (MmcCsd.CSD_STRUCTURE == 1U); + + MmcDevInfo.BlockSize = MMC_BLOCK_SIZE; + + /* Need to use ECSD struct */ + CsdSdV2 = (ECSD *)&MmcCsd; + CardSize = ((UINT64)CsdSdV2->C_SIZEHigh6 << 16) | + (UINT64)CsdSdV2->C_SIZELow16; + + MmcDevInfo.DeviceSize = (CardSize + 1U) << MULT_BY_512K_SHIFT; + break; + + default: + Status = EFI_DEVICE_ERROR; + break; + } + + if (EFI_ERROR (Status)) { + return Status; + } + + SpeedIdx = (MmcCsd.TRAN_SPEED & CSD_TRAN_SPEED_MULT_MASK) >> + CSD_TRAN_SPEED_MULT_SHIFT; + + ASSERT (SpeedIdx > 0U); + + if (MmcDevInfo.MmcDevType == MMC_IS_EMMC) { + MmcDevInfo.MaxBusFreq = TranSpeedBase[SpeedIdx]; + } else { + MmcDevInfo.MaxBusFreq = SdTranSpeedBase[SpeedIdx]; + } + + FreqUnit = MmcCsd.TRAN_SPEED & CSD_TRAN_SPEED_UNIT_MASK; + while (FreqUnit != 0U) { + MmcDevInfo.MaxBusFreq *= 10U; + --FreqUnit; + } + + MmcDevInfo.MaxBusFreq *= 10000U; + + return EFI_SUCCESS; +} + +/** + Send the SD_SEND_OP_COND command to initialize the SD card. + + @param[in] MmcHostInstance Pointer to the MMC_HOST_INSTANCE structure. + + @retval EFI_SUCCESS The SD_SEND_OP_COND command was successfully sent. + @retval EFI_DEVICE_ERROR Failed to send the SD_SEND_OP_COND command. + @retval Other An error occurred while sending the SD_SEND_OP_COND command. + +**/ +STATIC +EFI_STATUS +SdSendOpCond ( + IN MMC_HOST_INSTANCE *MmcHostInstance + ) +{ + EFI_STATUS Status; + INT32 I; + UINT32 Response[4]; + + for (I = 0; I < SEND_OP_COND_MAX_RETRIES; I++) { + // CMD55: Application Specific Command + Status = MmcHostInstance->MmcHost->SendCommand (MmcHostInstance->MmcHost, MMC_CMD55, 0, MMC_RESPONSE_R1, NULL); + if (EFI_ERROR (Status)) { + return Status; + } + + // ACMD41: SD_SEND_OP_COND + Status = MmcHostInstance->MmcHost->SendCommand (MmcHostInstance->MmcHost, MMC_ACMD41, OCR_HCS | + MmcDevInfo.OCRVoltage, MMC_RESPONSE_R3, Response); + if (EFI_ERROR (Status)) { + return Status; + } + + if ((Response[0] & MMC_OCR_POWERUP) != 0U) { + MmcOCR = Response[0]; + + if ((MmcOCR & OCR_HCS) != 0U) { + MmcDevInfo.MmcDevType = MMC_IS_SD_HC; + MmcHostInstance->CardInfo.OCRData.AccessMode = 0x2; + } else { + MmcDevInfo.MmcDevType = MMC_IS_SD; + MmcHostInstance->CardInfo.OCRData.AccessMode = 0x0; + } + + return EFI_SUCCESS; + } + + gBS->Stall (10000); + } + + DEBUG ((DEBUG_ERROR, "%a: ACMD41 failed after %d retries\n", __func__, SEND_OP_COND_MAX_RETRIES)); + + return EFI_DEVICE_ERROR; +} + +/** + Reset the MMC/SD card to the idle state. + + @param[in] MmcHostInstance Pointer to the MMC_HOST_INSTANCE structure. + + @retval EFI_SUCCESS The MMC/SD card was successfully reset to the idle state. + @retval Other An error occurred while resetting the MMC/SD card to the idle state. + +**/ +STATIC +EFI_STATUS +MmcResetToIdle( + IN MMC_HOST_INSTANCE *MmcHostInstance + ) +{ + EFI_STATUS Status; + + /* CMD0: reset to IDLE */ + Status = MmcHostInstance->MmcHost->SendCommand (MmcHostInstance->MmcHost, MMC_CMD0, 0, 0, NULL); + if (EFI_ERROR (Status)) { + return Status; + } + + gBS->Stall (2000); + + return EFI_SUCCESS; +} + +/** + Send the Operation Condition (CMD1) to the MMC/SD card. + + @param[in] MmcHostInstance Pointer to the MMC_HOST_INSTANCE structure. + + @retval EFI_SUCCESS The Operation Condition was successfully sent to the MMC/SD card. + @retval EFI_DEVICE_ERROR Failed to send the Operation Condition to the MMC/SD card. + @retval Other An error occurred while sending the Operation Condition to the MMC/SD card. + +**/ +STATIC +EFI_STATUS +MmcSendOpCond ( + IN MMC_HOST_INSTANCE *MmcHostInstance + ) +{ + INT32 I; + EFI_STATUS Status; + UINT32 Response[4]; + + Status = MmcResetToIdle (MmcHostInstance); + if (EFI_ERROR (Status)) { + return Status; + } + + for (I = 0; I < SEND_OP_COND_MAX_RETRIES; I++) { + Status = MmcHostInstance->MmcHost->SendCommand (MmcHostInstance->MmcHost, MMC_CMD1, OCR_SECTOR_MODE | + OCR_VDD_MIN_2V7 | OCR_VDD_MIN_1V7, + MMC_RESPONSE_R3, Response); + if (EFI_ERROR (Status)) { + return Status; + } + + if ((Response[0] & MMC_OCR_POWERUP) != 0U) { + MmcOCR = Response[0]; + return EFI_SUCCESS; + } + + gBS->Stall (10000); + } + + DEBUG ((DEBUG_ERROR, "%a: CMD1 failed after %d retries\n", __func__, SEND_OP_COND_MAX_RETRIES)); + + return EFI_DEVICE_ERROR; +} + +/** + Enumerate and initialize the MMC/SD card. + + @param[in] MmcHostInstance Pointer to the MMC_HOST_INSTANCE structure. + @param[in] Clk Clock frequency for the MMC/SD card. + @param[in] BusWidth Bus width for the MMC/SD card. + + @retval EFI_SUCCESS The MMC/SD card was successfully enumerated and initialized. + @retval Other An error occurred while enumerating and initializing the MMC/SD card. + +**/ +STATIC +EFI_STATUS +MmcEnumerte ( + IN MMC_HOST_INSTANCE *MmcHostInstance, + IN UINT32 Clk, + IN UINT32 BusWidth + ) +{ + EFI_STATUS Status; + UINT32 State; + UINT32 Response[4]; + + Status = MmcResetToIdle (MmcHostInstance); + if (EFI_ERROR (Status)) { + return Status; + } + + if (MmcDevInfo.MmcDevType == MMC_IS_EMMC) { + Status = MmcSendOpCond (MmcHostInstance); + } else { + // CMD8: Send Interface Condition Command + Status = MmcHostInstance->MmcHost->SendCommand (MmcHostInstance->MmcHost, MMC_CMD8, VHS_2_7_3_6_V | CMD8_CHECK_PATTERN, + MMC_RESPONSE_R5, Response); + + if ((Status == EFI_SUCCESS) && ((Response[0] & 0xffU) == CMD8_CHECK_PATTERN)) { + Status = SdSendOpCond (MmcHostInstance); + } + } + if (EFI_ERROR (Status)) { + return Status; + } + + // CMD2: Card Identification + Status = MmcHostInstance->MmcHost->SendCommand (MmcHostInstance->MmcHost, MMC_CMD2, 0, MMC_RESPONSE_R2, NULL); + if (EFI_ERROR (Status)) { + return Status; + } + + // CMD3: Set Relative Address + if (MmcDevInfo.MmcDevType == MMC_IS_EMMC) { + MmcRCA = MMC_FIX_RCA; + Status = MmcHostInstance->MmcHost->SendCommand (MmcHostInstance->MmcHost, MMC_CMD3, MmcRCA << RCA_SHIFT_OFFSET, + MMC_RESPONSE_R1, NULL); + if (EFI_ERROR (Status)) { + return Status; + } + } else { + Status = MmcHostInstance->MmcHost->SendCommand (MmcHostInstance->MmcHost, MMC_CMD3, 0, + MMC_RESPONSE_R6, Response); + if (EFI_ERROR (Status)) { + return Status; + } + + MmcRCA = (Response[0] & 0xFFFF0000U) >> 16; + } + + // CMD9: CSD Register + Status = MmcHostInstance->MmcHost->SendCommand (MmcHostInstance->MmcHost, MMC_CMD9, MmcRCA << RCA_SHIFT_OFFSET, + MMC_RESPONSE_R2, Response); + if (EFI_ERROR (Status)) { + return Status; + } + + CopyMem(&MmcCsd, &Response, sizeof(Response)); + + // CMD7: Select Card + Status = MmcHostInstance->MmcHost->SendCommand (MmcHostInstance->MmcHost, MMC_CMD7, MmcRCA << RCA_SHIFT_OFFSET, + MMC_RESPONSE_R1, NULL); + if (EFI_ERROR (Status)) { + return Status; + } + + do { + Status = MmcDeviceState (MmcHostInstance, &State); + if (EFI_ERROR (Status)) { + return Status; + } + } while (State != MMC_R0_STATE_TRAN); + + Status = MmcSetIos (MmcHostInstance, Clk, BusWidth); + if (EFI_ERROR (Status)) { + return Status; + } + + return MmcFillDeviceInfo (MmcHostInstance); +} + +/** + Perform the MMC Identification Mode. + + @param[in] MmcHostInstance Pointer to the MMC_HOST_INSTANCE structure. + + @retval EFI_SUCCESS The MMC Identification Mode was performed successfully. + @retval EFI_INVALID_PARAMETER MmcHost is NULL. + @retval Other An error occurred while performing the MMC Identification Mode. + +**/ +STATIC +EFI_STATUS +EFIAPI +MmcIdentificationMode ( + IN MMC_HOST_INSTANCE *MmcHostInstance + ) +{ + EFI_STATUS Status; + UINTN CmdArg; + BOOLEAN IsHCS; + EFI_MMC_HOST_PROTOCOL *MmcHost; + + MmcHost = MmcHostInstance->MmcHost; + CmdArg = 0; + IsHCS = FALSE; + + if (MmcHost == NULL) { + return EFI_INVALID_PARAMETER; + } + + // We can get into this function if we restart the identification mode + if (MmcHostInstance->State == MmcHwInitializationState) { + // Initialize the MMC Host HW + Status = MmcNotifyState (MmcHostInstance, MmcHwInitializationState); + if (EFI_ERROR (Status)) { + DEBUG ((DEBUG_ERROR, "MmcIdentificationMode() : Error MmcHwInitializationState, Status=%r.\n", Status)); + return Status; + } + } + + Status = MmcEnumerte (MmcHostInstance, 50 * 1000 * 1000, MMC_BUS_WIDTH_4); + + if (EFI_ERROR (Status)) { + DEBUG ((DEBUG_ERROR, "MmcIdentificationMode() : Error MmcEnumerte, Status=%r.\n", Status)); + return Status; + } + + MmcHostInstance->CardInfo.RCA = MmcRCA; + MmcHostInstance->BlockIo.Media->LastBlock = ((MmcDevInfo.DeviceSize >> 9) - 1); + MmcHostInstance->BlockIo.Media->BlockSize = MmcDevInfo.BlockSize; + MmcHostInstance->BlockIo.Media->ReadOnly = MmcHost->IsReadOnly (MmcHost); + MmcHostInstance->BlockIo.Media->MediaPresent = TRUE; + MmcHostInstance->BlockIo.Media->MediaId++; + + return EFI_SUCCESS; +} + +/** + Initialize the MMC device. + + @param[in] MmcHostInstance MMC host instance + + @retval EFI_SUCCESS MMC device initialized successfully + @retval Other MMC device initialization failed + +**/ +EFI_STATUS +InitializeMmcDevice ( + IN MMC_HOST_INSTANCE *MmcHostInstance + ) +{ + EFI_STATUS Status; + EFI_MMC_HOST_PROTOCOL *MmcHost; + UINTN BlockCount; + + BlockCount = 1; + MmcHost = MmcHostInstance->MmcHost; + + Status = MmcIdentificationMode (MmcHostInstance); + if (EFI_ERROR (Status)) { + DEBUG ((DEBUG_ERROR, "InitializeMmcDevice(): Error in Identification Mode, Status=%r\n", Status)); + return Status; + } + + Status = MmcNotifyState (MmcHostInstance, MmcTransferState); + if (EFI_ERROR (Status)) { + DEBUG ((DEBUG_ERROR, "InitializeMmcDevice(): Error MmcTransferState, Status=%r\n", Status)); + return Status; + } + + return EFI_SUCCESS; +} -- 2.34.1 -=-=-=-=-=-=-=-=-=-=-=- Groups.io Links: You receive all messages sent to this group. View/Reply Online (#109602): https://edk2.groups.io/g/devel/message/109602 Mute This Topic: https://groups.io/mt/101944466/7686176 Group Owner: devel+owner@edk2.groups.io Unsubscribe: https://edk2.groups.io/g/devel/unsub [rebecca@openfw.io] -=-=-=-=-=-=-=-=-=-=-=-