From nobody Sun Dec 22 09:22:07 2024 Delivered-To: importer@patchew.org Received-SPF: pass (zohomail.com: domain of groups.io designates 66.175.222.108 as permitted sender) client-ip=66.175.222.108; envelope-from=bounce+27952+108760+1787277+3901457@groups.io; helo=mail02.groups.io; Authentication-Results: mx.zohomail.com; dkim=pass; spf=pass (zohomail.com: domain of groups.io designates 66.175.222.108 as permitted sender) smtp.mailfrom=bounce+27952+108760+1787277+3901457@groups.io; dmarc=fail(p=none dis=none) header.from=163.com ARC-Seal: i=1; a=rsa-sha256; t=1694880075; cv=none; d=zohomail.com; s=zohoarc; b=HWoVUFy3FRdaCYxxuUYiFI/o5oHgh+0dvsoCZxC4BUIuc3x2C0HnkIKZn3CkJyLTFdHS02PaA16DYM5xYTuf94MA1t8HmBF4x1cDvVOM2OQ3lHrMqjlGJibiZFS4oBPWQumfqQ0hwO5VeRnG3gO88IO66CYUm8tRthj1pSO7LUU= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zohomail.com; s=zohoarc; t=1694880075; h=Content-Transfer-Encoding:Cc:Date:From:In-Reply-To:List-Subscribe:List-Id:List-Help:List-Unsubscribe:MIME-Version:Message-ID:Reply-To:References:Sender:Subject:To; bh=n9TICgMV5rxpjuqmpjXIUHC9xrSLrkHikmOgnkBcwx4=; b=Rvz4jbP/NAmugYSC5Pwb07Gb8IZnQfuV4S11uUFSrsd4e7a82LcyLzjmcLtruEa6rH1a6sUPOy+jMN9OJB8ZwLTvbV0rEe70oOfksfaE/OgKpvXWzUeWOraiJmOKZO8IaJHasYnNaBO45Lj/oS48N5Wv3HXhTKgOCBDAaaqkFic= ARC-Authentication-Results: i=1; mx.zohomail.com; dkim=pass; spf=pass (zohomail.com: domain of groups.io designates 66.175.222.108 as permitted sender) smtp.mailfrom=bounce+27952+108760+1787277+3901457@groups.io; dmarc=fail header.from= (p=none dis=none) Received: from mail02.groups.io (mail02.groups.io [66.175.222.108]) by mx.zohomail.com with SMTPS id 1694880075701904.7765756679566; Sat, 16 Sep 2023 09:01:15 -0700 (PDT) Return-Path: DKIM-Signature: a=rsa-sha256; bh=1flz4JDxT2wtAggaA0o1wSQNEqIeeRaGoJ1mT4MT1eE=; 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=1694880075; v=1; b=fOIVRucsN83RO+G9VaSrGCygkRbC33tmvubxr2s4UVFQ/7OiwDLfn6LS6nNgiIyu67VrnbfS u+gdVOM7vBJHp4Lp3v3qfMeTrwOEJj0pq0nUZPrVOxdoVTuEo1TJo4/ucmESWgaFGtonbkSZj+U 70wZTDrfAo69yyArDLu8XcRo= X-Received: by 127.0.0.2 with SMTP id w996YY1788612xuZIrjq4R1P; Sat, 16 Sep 2023 09:01:15 -0700 X-Received: from m15.mail.163.com (m15.mail.163.com [45.254.50.220]) by mx.groups.io with SMTP id smtpd.web11.14372.1694880073854220482 for ; Sat, 16 Sep 2023 09:01:14 -0700 X-Received: from rv-uefi.. (unknown [211.87.236.31]) by zwqz-smtp-mta-g0-0 (Coremail) with SMTP id _____wCHJchC0QVlrSTkCA--.881S2; Sun, 17 Sep 2023 00:01:06 +0800 (CST) From: caiyuqing_hz@163.com To: devel@edk2.groups.io Cc: Sunil V L , Leif Lindholm , Michael D Kinney , USER0FISH , Inochi Amaoto Subject: [edk2-devel] [PATCH edk2-platforms v4 4/8] Sophgo/SG2042Pkg: Add base MMC driver. Date: Sun, 17 Sep 2023 00:01:06 +0800 Message-Id: <03b01fe3dba9ea34b768cd0a6683f1efadd600a0.1694879465.git.caiyuqing_hz@outlook.com> In-Reply-To: References: MIME-Version: 1.0 X-CM-TRANSID: _____wCHJchC0QVlrSTkCA--.881S2 X-Coremail-Antispam: 1Uf129KBjvAXoWkJr4DJr45AF4xurW3uF4fuFg_yoWDAr15uo W3Z34ftw4kJr1xZrsxCrykW3y7ZF1rWrsIqr4Fvryqv3ZIqwn5KFyIya1xGa43JryIvr9x GryIq3s5JFZayF18n29KB7ZKAUJUUUUU529EdanIXcx71UUUUU7v73VFW2AGmfu7bjvjm3 AaLaJ3UbIYCTnIWIevJa73UjIFyTuYvjxUcqg4DUUUU X-Originating-IP: [211.87.236.31] X-CM-SenderInfo: 5fdl535tlqwslk26il2tof0z/1tbiKAfsxV7WNFFmyAAAsF 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: rfYNYki4jRDObRM1ZrMi4o17x1787277AA= Content-Transfer-Encoding: quoted-printable X-ZohoMail-DKIM: pass (identity @groups.io) X-ZM-MESSAGEID: 1694880076672100001 Content-Type: text/plain; charset="utf-8" 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: Sunil V L Cc: Leif Lindholm Cc: Michael D Kinney --- .../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/MmcIdentificati= on.c diff --git a/Silicon/Sophgo/SG2042Pkg/Drivers/MmcDxe/MmcDxe.inf b/Silicon/S= ophgo/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 Univers= iy, China.P.R. All rights reserved.
+# +# SPDX-License-Identifier: BSD-2-Clause-Patent +# +## + +[Defines] + INF_VERSION =3D 0x0001001B + BASE_NAME =3D MmcDxe + FILE_GUID =3D B5A53998-42AD-4C66-8D2D-1C5FBD175F25 + MODULE_TYPE =3D DXE_DRIVER + VERSION_STRING =3D 1.0 + ENTRY_POINT =3D 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 Universi= y, 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) >> (6= 4 - 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) | ((Resp= onse[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 fi= nished 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:2= 1] + 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:2= 1] + 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 spe= cific +} 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_INSTAN= CE, BlockIo, MMC_HOST_INSTANCE_SIGNATURE) +#define MMC_HOST_INSTANCE_FROM_LINK(a) CR (a, MMC_HOST_INSTAN= CE, 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 O= PTIONAL, + 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 contex= t. + @param ExtendedVerification Indicates that the driver may perform a m= ore exhaustive + verification operation of the device duri= ng reset. + + @retval EFI_SUCCESS The block device was reset. + @retval EFI_DEVICE_ERROR The block device is not functioning corre= ctly 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 contex= t. + @param MediaId The media ID that the read request is for. + @param Lba The starting logical block address to rea= d 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 t= he 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 devi= ce. + @retval EFI_DEVICE_ERROR The device reported an error while attemp= ting 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 multipl= e of the intrinsic block size of the device. + @retval EFI_INVALID_PARAMETER The read request contains LBAs that are n= ot 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 contex= t. + @param MediaId The media ID that the write request is fo= r. + @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 de= vice. + @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 attemp= ting to perform the write operation. + @retval EFI_BAD_BUFFER_SIZE The BufferSize parameter is not a multipl= e 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 contex= t. + + @retval EFI_SUCCESS All outstanding data were written correct= ly to the device. + @retval EFI_DEVICE_ERROR The device reported an error while attemp= ting 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/SG= 2042Pkg/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 <=3D 2G= B, 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 =3D 0, + MmcHwInitializationState, + MmcIdleState, + MmcReadyState, + MmcIdentificationState, + MmcStandByState, + MmcTransferState, + MmcSendingDataState, + MmcReceiveDataState, + MmcProgrammingState, + MmcDisconnectState, +} MMC_STATE; + +typedef enum _CARD_DETECT_STATE { + CardDetectRequired =3D 0, + CardDetectInProgress, + CardDetectCompleted +} CARD_DETECT_STATE; + +#define EMMCBACKWARD (0) +#define EMMCHS26 (1 << 0) // High-Speed @26MHz at rated d= evice voltages +#define EMMCHS52 (1 << 1) // High-Speed @52MHz at rated d= evice voltages +#define EMMCHS52DDR1V8 (1 << 2) // High-Speed Dual Data Rate @5= 2MHz 1.8V or 3V I/O +#define EMMCHS52DDR1V2 (1 << 3) // High-Speed Dual Data Rate @5= 2MHz 1.2V I/O +#define EMMCHS200SDR1V8 (1 << 4) // HS200 Single Data Rate @200M= Hz 1.8V I/O +#define EMMCHS200SDR1V2 (1 << 5) // HS200 Single Data Rate @200M= Hz 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 >=3D MMC_HOST_PROT= OCOL_REVISION && \ + Host->SetIos !=3D NULL) +#define MMC_HOST_HAS_ISMULTIBLOCK(Host) (Host->Revision >=3D MMC_HOST_PROT= OCOL_REVISION && \ + Host->IsMultiBlock !=3D NULL) + +#endif /* __MMC_HOST_PROTOCOL_H__ */ diff --git a/Silicon/Sophgo/SG2042Pkg/Drivers/MmcDxe/ComponentName.c b/Sili= con/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 gMmcComponentNa= me =3D { + MmcGetDriverName, + MmcGetControllerName, + "eng" +}; + +// +// EFI Component Name 2 Protocol +// +GLOBAL_REMOVE_IF_UNREFERENCED EFI_COMPONENT_NAME2_PROTOCOL gMmcComponentNa= me2 =3D { + (EFI_COMPONENT_NAME2_GET_DRIVER_NAME)MmcGetDriverName, + (EFI_COMPONENT_NAME2_GET_CONTROLLER_NAME)MmcGetControllerName, + "en" +}; + +GLOBAL_REMOVE_IF_UNREFERENCED EFI_UNICODE_STRING_TABLE +mMmcDriverNameTable[] =3D { + {"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 o= f 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 speci= fied + by This does not support the language specified by Language, + then EFI_UNSUPPORTED is returned. + + @param This A pointer to the EFI_COMPONENT_NAME2_PROTO= COL 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 calle= r 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 for= mat. + @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 specifie= d by + This and the language specified by Languag= e 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 supp= ort + 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 =3D=3D &gMmcComponentName) + ); +} + +/** + Retrieves a Unicode string that is the user readable name of the control= ler + that is being managed by a driver. + + This function retrieves the user readable name of the controller specifi= ed 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 specif= ied by + Language, then a pointer to the controller name is returned in Controlle= rName, + and EFI_SUCCESS is returned. If the driver specified by This is not cur= rently + 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 retu= rned. + + @param This A pointer to the EFI_COMPONENT_NAME2_PROTO= COL 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 retr= ieve + the name of. This is an optional paramete= r that + may be NULL. It will be NULL for device + drivers. It will also be NULL for a bus d= rivers + 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 calle= r 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 specifie= d 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 a= nd + ChildHandle in the language specified by + Language from the point of view of the dri= ver + specified by This. + + @retval EFI_SUCCESS The Unicode string for the user readable n= ame 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 va= lid + 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 curren= tly + managing the controller specified by + ControllerHandle and ChildHandle. + @retval EFI_UNSUPPORTED The driver specified by This does not supp= ort + the language specified by Language. + +**/ +EFI_STATUS +EFIAPI +MmcGetControllerName ( + IN EFI_COMPONENT_NAME_PROTOCOL *This, + IN EFI_HANDLE ControllerHandle, + IN EFI_HANDLE ChildHandle O= PTIONAL, + IN CHAR8 *Language, + OUT CHAR16 **ControllerName + ) +{ + return EFI_UNSUPPORTED; +} diff --git a/Silicon/Sophgo/SG2042Pkg/Drivers/MmcDxe/Diagnostics.c b/Silico= n/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 =3D NULL; +UINTN mLogRemainChar =3D 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 =3D MaxBufferChar; + mLogBuffer =3D 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 =3D StrLen (Str); + if (len < mLogRemainChar) { + StrCpyS (mLogBuffer, mLogRemainChar, Str); + mLogRemainChar -=3D len; + mLogBuffer +=3D 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 wil= l be stored. + @param BufferSize The size of the buffer in bytes. + +**/ +VOID +GenerateRandomBuffer ( + VOID* Buffer, + UINTN BufferSize + ) +{ + UINT64 i; + UINT64* Buffer64 =3D (UINT64*)Buffer; + + for (i =3D 0; i < (BufferSize >> 3); i++) { + *Buffer64 =3D i | (~i << 32); + Buffer64++; + } +} + +/** + + Compares two buffers by iterating through each 64-bit element in the buf= fers. + + @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 =3D (UINT64*)BufferA; + UINT64* BufferB64 =3D (UINT64*)BufferB; + + for (i =3D 0; i < (BufferSize >> 3); i++) { + if (*BufferA64 !=3D *BufferB64) { + DEBUG ((DEBUG_ERROR, "CompareBuffer: Error at %i", i)); + DEBUG ((DEBUG_ERROR, "(0x%lX) !=3D (0x%lX)\n", *BufferA64, *BufferB6= 4)); + 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 o= n. + @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 sta= te. + @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 !=3D MmcTransferState) { + DiagnosticLog (L"ERROR: Not ready for Transfer state\n"); + return EFI_NOT_READY; + } + + BackBuffer =3D AllocatePool (BufferSize); + WriteBuffer =3D AllocatePool (BufferSize); + ReadBuffer =3D AllocatePool (BufferSize); + + // Read (and save) buffer at a specific location + Status =3D MmcReadBlocks (&(MmcHostInstance->BlockIo), + MmcHostInstance->BlockIo.Media->MediaId, Lba, BufferSize, Bac= kBuffer); + if (Status !=3D EFI_SUCCESS) { + DiagnosticLog (L"ERROR: Fail to Read Block (1)\n"); + return Status; + } + + // Write buffer at the same location + GenerateRandomBuffer (WriteBuffer, BufferSize); + Status =3D MmcWriteBlocks (&(MmcHostInstance->BlockIo), + MmcHostInstance->BlockIo.Media->MediaId, Lba, BufferSize, Wri= teBuffer); + if (Status !=3D EFI_SUCCESS) { + DiagnosticLog (L"ERROR: Fail to Write Block (1)\n"); + return Status; + } + + // Read the buffer at the same location + Status =3D MmcReadBlocks (&(MmcHostInstance->BlockIo), + MmcHostInstance->BlockIo.Media->MediaId, Lba, BufferSize, Rea= dBuffer); + if (Status !=3D 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 =3D MmcWriteBlocks (&(MmcHostInstance->BlockIo), + MmcHostInstance->BlockIo.Media->MediaId, Lba, BufferSize, Bac= kBuffer); + if (Status !=3D EFI_SUCCESS) { + DiagnosticLog (L"ERROR: Fail to Write Block (2)\n"); + return Status; + } + + // Read the restored content + Status =3D MmcReadBlocks (&(MmcHostInstance->BlockIo), + MmcHostInstance->BlockIo.Media->MediaId, Lba, BufferSize, Rea= dBuffer); + if (Status !=3D 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 ha= ndle. + + @param This A pointer to the EFI_DRIVER_DIAGNOSTICS_PROTOCO= L instance. + @param ControllerHandle The handle of the controller to run diagnostics= on. + @param ChildHandle The handle of the child controller to run diagn= ostics 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 diagnostic= s (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 n= ot 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 =3D=3D NULL) || + (ErrorType =3D=3D NULL) || + (Buffer =3D=3D NULL) || + (ControllerHandle =3D=3D NULL) || + (BufferSize =3D=3D NULL)) { + return EFI_INVALID_PARAMETER; + } + + // Check Language is supported (i.e. is "en-*" - only English is support= ed) + if (AsciiStrnCmp (Language, "en", 2) !=3D 0) { + return EFI_UNSUPPORTED; + } + + Status =3D EFI_SUCCESS; + *ErrorType =3D NULL; + *BufferSize =3D DIAGNOSTIC_LOGBUFFER_MAXCHAR; + *Buffer =3D DiagnosticInitLog (DIAGNOSTIC_LOGBUFFER_MAXCHAR); + + DiagnosticLog (L"MMC Driver Diagnostics\n"); + + // Find the MMC Host instance on which we have been asked to run diagnos= tics + MmcHostInstance =3D NULL; + CurrentLink =3D mMmcHostPool.ForwardLink; + while (CurrentLink !=3D NULL && CurrentLink !=3D &mMmcHostPool && (Statu= s =3D=3D EFI_SUCCESS)) { + MmcHostInstance =3D MMC_HOST_INSTANCE_FROM_LINK (CurrentLink); + ASSERT (MmcHostInstance !=3D NULL); + if (MmcHostInstance->MmcHandle =3D=3D ControllerHandle) { + break; + } + CurrentLink =3D CurrentLink->ForwardLink; + } + + // If we didn't find the controller, return EFI_UNSUPPORTED + if ((MmcHostInstance =3D=3D NULL) + || (MmcHostInstance->MmcHandle !=3D ControllerHandle)) { + return EFI_UNSUPPORTED; + } + + // LBA=3D1 Size=3DBlockSize + DiagnosticLog (L"MMC Driver Diagnostics - Test: First Block\n"); + Status =3D MmcReadWriteDataTest (MmcHostInstance, 1, MmcHostInstance->Bl= ockIo.Media->BlockSize); + + // LBA=3D2 Size=3DBlockSize + DiagnosticLog (L"MMC Driver Diagnostics - Test: Second Block\n"); + Status =3D MmcReadWriteDataTest (MmcHostInstance, 2, MmcHostInstance->Bl= ockIo.Media->BlockSize); + + // LBA=3D10 Size=3DBlockSize + DiagnosticLog (L"MMC Driver Diagnostics - Test: Any Block\n"); + Status =3D MmcReadWriteDataTest (MmcHostInstance, MmcHostInstance->Block= Io.Media->LastBlock >> 1, + MmcHostInstance->BlockIo.Media->BlockSize); + + // LBA=3DLastBlock Size=3DBlockSize + DiagnosticLog (L"MMC Driver Diagnostics - Test: Last Block\n"); + Status =3D MmcReadWriteDataTest (MmcHostInstance, MmcHostInstance->Block= Io.Media->LastBlock, + MmcHostInstance->BlockIo.Media->BlockSize); + + // LBA=3D1 Size=3D2*BlockSize + DiagnosticLog (L"MMC Driver Diagnostics - Test: First Block / 2 BlockSSi= ze\n"); + Status =3D MmcReadWriteDataTest (MmcHostInstance, 1, 2 * MmcHostInstance= ->BlockIo.Media->BlockSize); + + return Status; +} + +// +// EFI Driver Diagnostics 2 Protocol +// +GLOBAL_REMOVE_IF_UNREFERENCED EFI_DRIVER_DIAGNOSTICS2_PROTOCOL gMmcDriverD= iagnostics2 =3D { + (EFI_DRIVER_DIAGNOSTICS2_RUN_DIAGNOSTICS)MmcDriverDiagnosticsRunDiagnost= ics, + "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 t= his file. + + Copyright (c) 2011-2013, ARM Limited. All rights reserved. + Copyright (c) 2023, Academy of Intelligent Innovation, Shandong Universi= y, China.P.R. All rights reserved.
+ + SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#include + +#include +#include +#include +#include +#include + +#include "Mmc.h" + +EFI_BLOCK_IO_MEDIA mMmcMediaTemplate =3D { + 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 p= ool. + +**/ +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 po= ol. + +**/ +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 MM= C 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 =3D AllocateZeroPool (sizeof (MMC_HOST_INSTANCE)); + if (MmcHostInstance =3D=3D NULL) { + return NULL; + } + + MmcHostInstance->Signature =3D MMC_HOST_INSTANCE_SIGNATURE; + + MmcHostInstance->State =3D MmcHwInitializationState; + + MmcHostInstance->BlockIo.Media =3D AllocateCopyPool (sizeof (EFI_BLOCK_I= O_MEDIA), &mMmcMediaTemplate); + if (MmcHostInstance->BlockIo.Media =3D=3D NULL) { + goto FREE_INSTANCE; + } + + MmcHostInstance->BlockIo.Revision =3D EFI_BLOCK_IO_INTERFACE_REVISION; + MmcHostInstance->BlockIo.Reset =3D MmcReset; + MmcHostInstance->BlockIo.ReadBlocks =3D MmcReadBlocks; + MmcHostInstance->BlockIo.WriteBlocks =3D MmcWriteBlocks; + MmcHostInstance->BlockIo.FlushBlocks =3D MmcFlushBlocks; + + MmcHostInstance->MmcHost =3D MmcHost; + + // Create DevicePath for the new MMC Host + Status =3D MmcHost->BuildDevicePath (MmcHost, &NewDevicePathNode); + if (EFI_ERROR (Status)) { + goto FREE_MEDIA; + } + + DevicePath =3D (EFI_DEVICE_PATH_PROTOCOL*)AllocatePool (END_DEVICE_PATH_= LENGTH); + if (DevicePath =3D=3D NULL) { + goto FREE_MEDIA; + } + + SetDevicePathEndNode (DevicePath); + MmcHostInstance->DevicePath =3D AppendDevicePathNode (DevicePath, NewDev= icePathNode); + + // Publish BlockIO protocol interface + Status =3D 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 M= MC host controller instance, + and frees the memory allocated for the instance and its associated resou= rces. + + @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 =3D 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 (size= of (ECSD))); + } + FreePool (MmcHostInstance); + + return Status; +} + +/** + This function checks if the controller implement the Mmc Host and the De= vice Path Protocols. + + @param This A pointer to the EFI_DRIVER_BINDING_PROTOCO= L instance. + @param Controller The handle of the controller to check for s= upport. + @param RemainingDevicePath A pointer to the remaining portion of the d= evice 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 !=3D 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 =3D RemainingDevicePath; + if (Node.DevPath->Type !=3D HARDWARE_DEVICE_PATH || + Node.DevPath->SubType !=3D HW_VENDOR_DP || + DevicePathNodeLength (Node.DevPath) !=3D sizeof (VENDOR_DEVICE_P= ATH)) { + return EFI_UNSUPPORTED; + } + } + } + + // + // Check if Mmc Host protocol is installed by platform + // + Status =3D gBS->OpenProtocol ( + Controller, + &gSophgoMmcHostProtocolGuid, + (VOID**)&MmcHost, + This->DriverBindingHandle, + Controller, + EFI_OPEN_PROTOCOL_BY_DRIVER + ); + if (Status =3D=3D 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_PROTOCO= L instance. + @param Controller The handle of the controller to start the d= river on. + @param RemainingDevicePath A pointer to the remaining portion of the d= evice 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 !=3D 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 =3D gBS->OpenProtocol ( + Controller, + &gSophgoMmcHostProtocolGuid, + (VOID**)&MmcHost, + This->DriverBindingHandle, + Controller, + EFI_OPEN_PROTOCOL_BY_DRIVER + ); + if (EFI_ERROR (Status)) { + if (Status =3D=3D EFI_ALREADY_STARTED) { + return EFI_SUCCESS; + } + return Status; + } + + MmcHostInstance =3D CreateMmcHostInstance (MmcHost); + + if (MmcHostInstance !=3D NULL) { + // Add the handle to the pool + InsertMmcHost (MmcHostInstance); + + MmcHostInstance->Initialized =3D FALSE; + + // Detect card presence now + CheckCardsCallback (NULL, NULL); + } + + return EFI_SUCCESS; +} + +/** + This function closes the Mmc Host Protocol, removes the MMC_HOST_INSTANC= E 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 driv= er 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 =3D EFI_SUCCESS; + LIST_ENTRY *CurrentLink; + MMC_HOST_INSTANCE *MmcHostInstance; + + MMC_TRACE ("MmcDriverBindingStop()"); + + // For each MMC instance + CurrentLink =3D mMmcHostPool.ForwardLink; + while (CurrentLink !=3D NULL && CurrentLink !=3D &mMmcHostPool && (Statu= s =3D=3D EFI_SUCCESS)) { + MmcHostInstance =3D MMC_HOST_INSTANCE_FROM_LINK (CurrentLink); + ASSERT (MmcHostInstance !=3D NULL); + + // Close gSophgoMmcHostProtocolGuid + Status =3D 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 =3D mMmcHostPool.ForwardLink; + while (CurrentLink !=3D NULL && CurrentLink !=3D &mMmcHostPool) { + MmcHostInstance =3D MMC_HOST_INSTANCE_FROM_LINK (CurrentLink); + ASSERT (MmcHostInstance !=3D NULL); + + if (MmcHostInstance->MmcHost->IsCardPresent (MmcHostInstance->MmcHost)= =3D=3D !MmcHostInstance->Initialized) { + MmcHostInstance->State =3D MmcHwInitializationState; + MmcHostInstance->BlockIo.Media->MediaPresent =3D !MmcHostInstance->I= nitialized; + MmcHostInstance->Initialized =3D !MmcHostInstance->Initialized; + + if (MmcHostInstance->BlockIo.Media->MediaPresent) { + Status =3D InitializeMmcDevice (MmcHostInstance); + if (EFI_ERROR (Status)) { + DEBUG ((DEBUG_ERROR, "CheckCardsCallback: Error InitializeMmcDev= ice, Status=3D%r.\n", Status)); + MmcHostInstance->Initialized =3D !MmcHostInstance->Initialized; + continue; + } + } + + Status =3D gBS->ReinstallProtocolInterface ( + (MmcHostInstance->MmcHandle), + &gEfiBlockIoProtocolGuid, + &(MmcHostInstance->BlockIo), + &(MmcHostInstance->BlockIo) + ); + + if (EFI_ERROR (Status)) { + Print (L"MMC Card: Error reinstalling BlockIo interface\n"); + } + } + + CurrentLink =3D CurrentLink->ForwardLink; + } +} + + +EFI_DRIVER_BINDING_PROTOCOL gMmcDriverBinding =3D { + 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 =3D EfiLibInstallDriverBindingComponentName2 ( + ImageHandle, + SystemTable, + &gMmcDriverBinding, + ImageHandle, + &gMmcComponentName, + &gMmcComponentName2 + ); + ASSERT_EFI_ERROR (Status); + + // Install driver diagnostics + Status =3D 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 =3D gBS->CreateEvent ( + EVT_NOTIFY_SIGNAL | EVT_TIMER, + TPL_CALLBACK, + CheckCardsCallback, + NULL, + &gCheckCardsEvent + ); + ASSERT_EFI_ERROR (Status); + + Status =3D 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 da= ta. + @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) !=3D 0 && MMC_R0_CURRENTSTATE (R= esponse) =3D=3D 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 incorre= ct. + @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 =3D=3D MMC_CARD || + MmcHostInstance->CardInfo.CardType =3D=3D MMC_CARD_HIGH || + MmcHostInstance->CardInfo.CardType =3D=3D EMMC_CARD) { + /* + * Not on MMC. + */ + *TransferredBlocks =3D Count; + return EFI_SUCCESS; + } + + MmcHost =3D MmcHostInstance->MmcHost; + + Status =3D 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 =3D 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 =3D R1TranAndReady (&R1); + if (EFI_ERROR (Status)) { + return Status; + } + + // Read Data + Status =3D 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 =3D ((UINT32)Data[0] << 24) | + ((UINT32)Data[1] << 16) | + ((UINT32)Data[2] << 8) | + ((UINT32)Data[3] << 0); + if (BlocksWritten !=3D Count) { + DEBUG ((DEBUG_ERROR, "%a(%u): expected %u !=3D gotten %u\n", + __func__, __LINE__, Count, BlocksWritten)); + if (BlocksWritten =3D=3D 0) { + return EFI_DEVICE_ERROR; + } + } + + *TransferredBlocks =3D 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 t= imed out. + @retval Other An error occurred during the waiting proce= ss. + +**/ +STATIC +EFI_STATUS +WaitUntilTran ( + IN MMC_HOST_INSTANCE *MmcHostInstance + ) +{ + INTN Timeout; + UINT32 Response[1]; + EFI_STATUS Status; + EFI_MMC_HOST_PROTOCOL *MmcHost; + + Timeout =3D MMCI0_TIMEOUT; + Status =3D EFI_SUCCESS; + MmcHost =3D MmcHostInstance->MmcHost; + + while (Timeout--) { + /* + * We expect CMD13 to timeout while card is programming, + * because the card holds DAT0 low (busy). + */ + Status =3D MmcHost->SendCommand (MmcHost, MMC_CMD13, + MmcHostInstance->CardInfo.RCA << 16, MMC_RESPONSE_= R1, Response); + if (EFI_ERROR (Status) && Status !=3D EFI_TIMEOUT) { + DEBUG ((DEBUG_ERROR, "%a(%u) CMD13 failed: %r\n", __func__, __LINE= __, Status)); + return Status; + } + + if (Status =3D=3D EFI_SUCCESS) { + Status =3D R1TranAndReady (Response); + if (!EFI_ERROR (Status)) { + break; + } + } + gBS->Stall(1000); + } + + if (0 =3D=3D 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 =3D 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 contex= t. + @param ExtendedVerification Indicates that the driver may perform a m= ore exhaustive + verification operation of the device duri= ng reset. + + @retval EFI_SUCCESS The block device was reset. + @retval EFI_DEVICE_ERROR The block device is not functioning corre= ctly and could not be reset. + +**/ +EFI_STATUS +EFIAPI +MmcReset ( + IN EFI_BLOCK_IO_PROTOCOL *This, + IN BOOLEAN ExtendedVerification + ) +{ + MMC_HOST_INSTANCE *MmcHostInstance; + + MmcHostInstance =3D MMC_HOST_INSTANCE_FROM_BLOCK_IO_THIS (This); + + if (MmcHostInstance->MmcHost =3D=3D 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 =3D FALSE; + MmcHostInstance->BlockIo.Media->LastBlock =3D 0; + MmcHostInstance->BlockIo.Media->BlockSize =3D 512; // Should be ze= ro but there is a bug in DiskIo + MmcHostInstance->BlockIo.Media->ReadOnly =3D FALSE; + + // Indicate that the driver requires initialization + MmcHostInstance->State =3D 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 =3D 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 in= stance. + @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 tra= nsfer. + @retval EFI_DEVICE_ERROR An error occurred during the data trans= fer. + @retval Other An error occurred during the data trans= fer. + +**/ +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 =3D MMC_HOST_INSTANCE_FROM_BLOCK_IO_THIS (This); + MmcHost =3D 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)= =3D=3D MMC_OCR_ACCESS_SECTOR) { + CmdArg =3D Lba; + } else { + CmdArg =3D Lba * This->Media->BlockSize; + } + + Status =3D 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 =3D=3D MMC_IOBLOCKS_READ) { + Status =3D MmcHost->ReadBlockData (MmcHost, Lba, BufferSize, Buffer); + } else { + Status =3D MmcHost->WriteBlockData (MmcHost, Lba, BufferSize, Buffer); + if (!EFI_ERROR (Status)) { + Status =3D 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 =3D 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 =3D %r\n", + __func__, Transfer =3D=3D MMC_IOBLOCKS_READ ? "Read" : "Write", St= atus)); + return Status; + } + + ASSERT (Cmd =3D=3D MMC_CMD25 || Cmd =3D=3D MMC_CMD18); + } + + // + // For reads, should be already in TRAN. For writes, wait + // until programming finishes. + // + Status =3D WaitUntilTran (MmcHostInstance); + if (EFI_ERROR (Status)) { + DEBUG ((DEBUG_ERROR, "WaitUntilTran after write failed\n")); + return Status; + } + + Status =3D MmcNotifyState (MmcHostInstance, MmcTransferState); + if (EFI_ERROR (Status)) { + DEBUG ((DEBUG_ERROR, "MmcIoBlocks() : Error MmcTransferState\n")); + return Status; + } + + if (Transfer !=3D MMC_IOBLOCKS_READ) { + UINTN BlocksWritten =3D 0; + + Status =3D ValidateWrittenBlockCount (MmcHostInstance, + BufferSize / + This->Media->BlockSize, + &BlocksWritten); + *TransferredSize =3D BlocksWritten * This->Media->BlockSize; + } else { + *TransferredSize =3D BufferSize; + } + + return Status; +} + +/** + Perform read or write operations on the MMC device. + + @param[in] This Pointer to the EFI_BLOCK_IO_PROTO= COL 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 successfu= lly. + @retval EFI_MEDIA_CHANGED The MediaId is not the current me= dia. + @retval EFI_INVALID_PARAMETER Invalid parameter passed to the f= unction. + @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 m= ultiple 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 =3D 1; + MmcHostInstance =3D MMC_HOST_INSTANCE_FROM_BLOCK_IO_THIS (This); + ASSERT (MmcHostInstance !=3D NULL); + + MmcHost =3D MmcHostInstance->MmcHost; + ASSERT (MmcHost); + + if (This->Media->MediaId !=3D MediaId) { + return EFI_MEDIA_CHANGED; + } + + if ((MmcHost =3D=3D NULL) || (Buffer =3D=3D 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 =3D (BufferSize + This->Media->BlockSize - 1) / This->Media= ->BlockSize; + } + + // All blocks must be within the device + if ((Lba + (BufferSize / This->Media->BlockSize)) > (This->Media->LastBl= ock + 1)) { + return EFI_INVALID_PARAMETER; + } + + if ((Transfer =3D=3D MMC_IOBLOCKS_WRITE) && (This->Media->ReadOnly =3D= =3D TRUE)) { + return EFI_WRITE_PROTECTED; + } + + // Reading 0 Byte is valid + if (BufferSize =3D=3D 0) { + return EFI_SUCCESS; + } + + // The buffer size must be an exact multiple of the block size + if ((BufferSize % This->Media->BlockSize) !=3D 0) { + return EFI_BAD_BUFFER_SIZE; + } + + // Check the alignment + if ((This->Media->IoAlign > 2) && (((UINTN)Buffer & (This->Media->IoAlig= n - 1)) !=3D 0)) { + return EFI_INVALID_PARAMETER; + } + + BytesRemainingToBeTransfered =3D BufferSize; + while (BytesRemainingToBeTransfered > 0) { + Status =3D WaitUntilTran (MmcHostInstance); + if (EFI_ERROR (Status)) { + DEBUG ((DEBUG_ERROR, "WaitUntilTran before IO failed")); + return Status; + } + + if (Transfer =3D=3D MMC_IOBLOCKS_READ) { + if (BlockCount =3D=3D 1) { + // Read a single block + Cmd =3D MMC_CMD17; + } else { + // Read multiple blocks + Cmd =3D MMC_CMD18; + } + } else { + if (BlockCount =3D=3D 1) { + // Write a single block + Cmd =3D MMC_CMD24; + } else { + // Write multiple blocks + Cmd =3D MMC_CMD25; + } + } + + ConsumeSize =3D BlockCount * This->Media->BlockSize; + if (BytesRemainingToBeTransfered < ConsumeSize) { + ConsumeSize =3D BytesRemainingToBeTransfered; + } + + if (ConsumeSize > MAX_BUF_LEN) { + ConsumeSize =3D MAX_BUF_LEN; + BlockCount =3D MAX_BLK_CNT; + } else { + BlockCount =3D ConsumeSize / This->Media->BlockSize; + } + + MmcHost->Prepare (MmcHost, Lba, ConsumeSize, (UINTN)Buffer); + + Status =3D MmcTransferBlock (This, Cmd, Transfer, MediaId, Lba, Consum= eSize, Buffer, &ConsumeSize); + if (EFI_ERROR (Status)) { + DEBUG ((DEBUG_ERROR, "%a(): Failed to transfer block and Status:%r\n= ", __func__, Status)); + return Status; + } + + BytesRemainingToBeTransfered -=3D ConsumeSize; + if (BytesRemainingToBeTransfered > 0) { + Lba +=3D BlockCount; + Buffer =3D (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 contex= t. + @param MediaId The media ID that the read request is for. + @param Lba The starting logical block address to rea= d 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 t= he 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 devi= ce. + @retval EFI_DEVICE_ERROR The device reported an error while attemp= ting 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 multipl= e of the intrinsic block size of the device. + @retval EFI_INVALID_PARAMETER The read request contains LBAs that are n= ot 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, B= uffer); +} + +/** + 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 contex= t. + @param MediaId The media ID that the write request is fo= r. + @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 de= vice. + @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 attemp= ting to perform the write operation. + @retval EFI_BAD_BUFFER_SIZE The BufferSize parameter is not a multipl= e 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 contex= t. + + @retval EFI_SUCCESS All outstanding data were written correct= ly to the device. + @retval EFI_DEVICE_ERROR The device reported an error while attemp= ting 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/S= ophgo/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[] =3D { "100kbit/s", "1Mbit/s", "10Mbit/s", "100MBit= /s", + "Unknown", "Unknown", "Unknown", "Unknown" }; +CONST CHAR8* mStrValue[] =3D { "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] & 0xF= FFFFF, (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) =3D=3D 0) { + DEBUG ((DEBUG_ERROR, "- PrintCSD Version 1.01-1.10/Version 2.00/Standa= rd Capacity\n")); + } else if (((Csd[2] >> 30) & 0x3) =3D=3D 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 =3D MMC_CSD_GET_FILEFORMAT (Csd); + if (Value =3D=3D 0) { + DEBUG ((DEBUG_ERROR, "\t- Format (0): Hard disk-like file system wit= h partition table\n")); + } else if (Value =3D=3D 1) { + DEBUG ((DEBUG_ERROR, "\t- Format (1): DOS FAT (floppy-like) with boo= t sector only (no partition table)\n")); + } else if (Value =3D=3D 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 =3D 36; // 3.6 + MaxV =3D 20; // 2.0 + Volts =3D 20; // 2.0 + + // The MMC register bits [23:8] indicate the working range of the card + for (Loop =3D 8; Loop < 24; Loop++) { + if (Ocr & (1 << Loop)) { + if (MinV > Volts) { + MinV =3D Volts; + } + if (MaxV < Volts) { + MaxV =3D 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", Min= V / 10, MinV % 10, MaxV / 10, MaxV % 10)); + if (((Ocr >> 29) & 3) =3D=3D 0) { + DEBUG ((DEBUG_ERROR, "\t- AccessMode: Byte Mode\n")); + } else { + DEBUG ((DEBUG_ERROR, "\t- AccessMode: Block Mode (0x%X)\n", ((Ocr >> 2= 9) & 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 reserv= ed. + Copyright (c) 2023, Academy of Intelligent Innovation, Shandong Universi= y, China.P.R. All rights reserved.
+ + SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#include +#include +#include +#include +#include +#include +#include + +#include "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))) =3D { 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 =3D { + .MmcDevType =3D MMC_IS_SD_HC, + .OCRVoltage =3D 0x00300000, // OCR 3.2~3.3 3.3~3.4 +}; + +STATIC CONST UINT8 TranSpeedBase[16] =3D { + 0, 10, 12, 13, 15, 20, 26, 30, 35, 40, 45, 52, 55, 60, 70, 80 +}; + +STATIC CONST UINT8 SdTranSpeedBase[16] =3D { + 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 st= ructure. + @param[out] State Pointer to the variable to store th= e device state. + + @retval EFI_SUCCESS The device state was retrieved succ= essfully. + @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 =3D MMC_DEFAULT_MAX_RETRIES; + + do { + if (RetryCount =3D=3D 0) { + DEBUG ((DEBUG_ERROR, "%a: CMD13 failed after %d retries\n", __func__= , MMC_DEFAULT_MAX_RETRIES)); + return EFI_DEVICE_ERROR; + } + + Status =3D MmcHostInstance->MmcHost->SendCommand (MmcHostInstance->Mmc= Host, MMC_CMD13, MmcRCA << RCA_SHIFT_OFFSET, + MMC_RESPONSE_R1, Response); + if (EFI_ERROR (Status)) { + RetryCount--; + continue; + } + + if ((Response[0] & MMC_R0_SWITCH_ERROR) !=3D 0U) { + return EFI_DEVICE_ERROR; + } + + RetryCount--; + } while ((Response[0] & MMC_R0_READY_FOR_DATA) =3D=3D 0U); + + // DEBUG ((DEBUG_INFO, "%a: sd state %x\n", __func__, MMC_R0_CURRENTSTAT= E(Response))); + *State =3D 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 st= ructure. + @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 =3D MmcHostInstance->MmcHost->SendCommand (MmcHostInstance->MmcHo= st, 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 =3D MmcDeviceState (MmcHostInstance, &State); + if (EFI_ERROR (Status)) { + return Status; + } + } while (State =3D=3D 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 st= ructure. + @param[in] BusWidth The desired bus width. + + @retval EFI_SUCCESS The bus width was successfully set. + @retval Other An error occurred while setting th= e bus width. + +**/ +STATIC +EFI_STATUS +MmcSdSwitch ( + IN MMC_HOST_INSTANCE *MmcHostInstance, + IN UINT32 BusWidth + ) +{ + EFI_STATUS Status; + UINT32 State; + INT32 RetryCount; + UINT32 BusWidthArg; + + RetryCount =3D MMC_DEFAULT_MAX_RETRIES; + BusWidthArg =3D 0; + + Status =3D MmcHostInstance->MmcHost->Prepare (MmcHostInstance->MmcHost, = 0, sizeof(MmcSCR), (UINTN)&MmcSCR); + if (EFI_ERROR (Status)) { + return Status; + } + + // CMD55: Application Specific Command + Status =3D MmcHostInstance->MmcHost->SendCommand (MmcHostInstance->MmcHo= st, MMC_CMD55, MmcRCA << RCA_SHIFT_OFFSET, + MMC_RESPONSE_R5, NULL); + if (EFI_ERROR (Status)) { + return Status; + } + + // ACMD51: SEND_SCR + do { + Status =3D MmcHostInstance->MmcHost->SendCommand (MmcHostInstance->Mmc= Host, MMC_ACMD51, 0, MMC_RESPONSE_R1, NULL); + if ((EFI_ERROR (Status)) && (RetryCount =3D=3D 0)) { + DEBUG ((DEBUG_ERROR, "%a: ACMD51 failed after %d retries (Status=3D%= r)\n", __func__, MMC_DEFAULT_MAX_RETRIES, Status)); + return Status; + } + + RetryCount--; + } while (EFI_ERROR (Status)); + + Status =3D MmcHostInstance->MmcHost->ReadBlockData (MmcHostInstance->Mmc= Host, 0, sizeof(MmcSCR), MmcSCR); + if (EFI_ERROR (Status)) { + return Status; + } + + if (((MmcSCR[0] & SD_SCR_BUS_WIDTH_4) !=3D 0U) && (BusWidth =3D=3D MMC_B= US_WIDTH_4)) { + BusWidthArg =3D 2; + } + + // CMD55: Application Specific Command + Status =3D MmcHostInstance->MmcHost->SendCommand (MmcHostInstance->MmcHo= st, MMC_CMD55, MmcRCA << RCA_SHIFT_OFFSET, + MMC_RESPONSE_R5, NULL); + if (EFI_ERROR (Status)) { + return Status; + } + + // ACMD6: SET_BUS_WIDTH + Status =3D MmcHostInstance->MmcHost->SendCommand (MmcHostInstance->MmcHo= st, MMC_CMD6, BusWidthArg, MMC_RESPONSE_R1, NULL); + if (EFI_ERROR (Status)) { + return Status; + } + + do { + Status =3D MmcDeviceState (MmcHostInstance, &State); + if (EFI_ERROR (Status)) { + return Status; + } + } while (State =3D=3D 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 st= ructure. + @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 th= e I/O settings. + +**/ +STATIC +EFI_STATUS +MmcSetIos ( + IN MMC_HOST_INSTANCE *MmcHostInstance, + IN UINT32 Clk, + IN UINT32 BusWidth + ) +{ + EFI_STATUS Status; + UINT32 Width; + + Width =3D BusWidth; + + if (MmcDevInfo.MmcDevType !=3D MMC_IS_EMMC) { + if (Width =3D=3D MMC_BUS_WIDTH_8) { + DEBUG ((DEBUG_INFO, "%a: Wrong bus config for SD-card, force to 4\n"= , __func__)); + Width =3D MMC_BUS_WIDTH_4; + } + + Status =3D MmcSdSwitch (MmcHostInstance, Width); + if (EFI_ERROR (Status)) { + return Status; + } + } else if (MmcCsd.SPEC_VERS =3D=3D 4U) { + Status =3D MmcSetExtCsd (MmcHostInstance, CMD_EXTCSD_BUS_WIDTH, (UINT3= 2)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 st= ructure. + + @retval EFI_SUCCESS The MMC device information was suc= cessfully filled. + @retval EFI_DEVICE_ERROR Failed to fill the MMC device info= rmation. + @retval Other An error occurred while filling th= e 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 =3D EFI_SUCCESS; + + switch (MmcDevInfo.MmcDevType) { + case MMC_IS_EMMC: + MmcDevInfo.BlockSize =3D MMC_BLOCK_SIZE; + + Status =3D MmcHostInstance->MmcHost->Prepare (MmcHostInstance->MmcHo= st, 0, sizeof(MmcExtCsd), (UINTN)&MmcExtCsd); + + if (EFI_ERROR (Status)) { + return Status; + } + + /* MMC CMD8: SEND_EXT_CSD */ + Status =3D MmcHostInstance->MmcHost->SendCommand (MmcHostInstance->M= mcHost, MMC_CMD8, 0, MMC_RESPONSE_R1, NULL); + if (EFI_ERROR (Status)) { + return Status; + } + + Status =3D MmcHostInstance->MmcHost->ReadBlockData (MmcHostInstance-= >MmcHost, 0, sizeof(MmcExtCsd), (UINT32*)MmcExtCsd); + if (EFI_ERROR (Status)) { + return Status; + } + + do { + Status =3D MmcDeviceState (MmcHostInstance, &State); + if (EFI_ERROR (Status)) { + return Status; + } + } while (State !=3D MMC_R0_STATE_TRAN); + + NumBlocks =3D (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 =3D (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 =3D BIT_32(MmcCsd.READ_BL_LEN); + + CardSize =3D ((UINT64)MmcCsd.C_SIZEHigh10 << 2U) | + (UINT64)MmcCsd.C_SIZELow2; + ASSERT(CardSize !=3D 0xFFFU); + + MmcDevInfo.DeviceSize =3D (CardSize + 1U) * + BIT_64(MmcCsd.C_SIZE_MULT + 2U) * + MmcDevInfo.BlockSize; + + break; + + case MMC_IS_SD_HC: + MmcHostInstance->CardInfo.CardType =3D SD_CARD_2_HIGH; + + ASSERT (MmcCsd.CSD_STRUCTURE =3D=3D 1U); + + MmcDevInfo.BlockSize =3D MMC_BLOCK_SIZE; + + /* Need to use ECSD struct */ + CsdSdV2 =3D (ECSD *)&MmcCsd; + CardSize =3D ((UINT64)CsdSdV2->C_SIZEHigh6 << 16) | + (UINT64)CsdSdV2->C_SIZELow16; + + MmcDevInfo.DeviceSize =3D (CardSize + 1U) << MULT_BY_512K_SHIFT; + break; + + default: + Status =3D EFI_DEVICE_ERROR; + break; + } + + if (EFI_ERROR (Status)) { + return Status; + } + + SpeedIdx =3D (MmcCsd.TRAN_SPEED & CSD_TRAN_SPEED_MULT_MASK) >> + CSD_TRAN_SPEED_MULT_SHIFT; + + ASSERT (SpeedIdx > 0U); + + if (MmcDevInfo.MmcDevType =3D=3D MMC_IS_EMMC) { + MmcDevInfo.MaxBusFreq =3D TranSpeedBase[SpeedIdx]; + } else { + MmcDevInfo.MaxBusFreq =3D SdTranSpeedBase[SpeedIdx]; + } + + FreqUnit =3D MmcCsd.TRAN_SPEED & CSD_TRAN_SPEED_UNIT_MASK; + while (FreqUnit !=3D 0U) { + MmcDevInfo.MaxBusFreq *=3D 10U; + --FreqUnit; + } + + MmcDevInfo.MaxBusFreq *=3D 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 st= ructure. + + @retval EFI_SUCCESS The SD_SEND_OP_COND command was su= ccessfully sent. + @retval EFI_DEVICE_ERROR Failed to send the SD_SEND_OP_COND= command. + @retval Other An error occurred while sending th= e SD_SEND_OP_COND command. + +**/ +STATIC +EFI_STATUS +SdSendOpCond ( + IN MMC_HOST_INSTANCE *MmcHostInstance + ) +{ + EFI_STATUS Status; + INT32 I; + UINT32 Response[4]; + + for (I =3D 0; I < SEND_OP_COND_MAX_RETRIES; I++) { + // CMD55: Application Specific Command + Status =3D MmcHostInstance->MmcHost->SendCommand (MmcHostInstance->Mmc= Host, MMC_CMD55, 0, MMC_RESPONSE_R1, NULL); + if (EFI_ERROR (Status)) { + return Status; + } + + // ACMD41: SD_SEND_OP_COND + Status =3D MmcHostInstance->MmcHost->SendCommand (MmcHostInstance->Mmc= Host, MMC_ACMD41, OCR_HCS | + MmcDevInfo.OCRVoltage, MMC_RESPONSE_R3, Response); + if (EFI_ERROR (Status)) { + return Status; + } + + if ((Response[0] & MMC_OCR_POWERUP) !=3D 0U) { + MmcOCR =3D Response[0]; + + if ((MmcOCR & OCR_HCS) !=3D 0U) { + MmcDevInfo.MmcDevType =3D MMC_IS_SD_HC; + MmcHostInstance->CardInfo.OCRData.AccessMode =3D 0x2; + } else { + MmcDevInfo.MmcDevType =3D MMC_IS_SD; + MmcHostInstance->CardInfo.OCRData.AccessMode =3D 0x0; + } + + return EFI_SUCCESS; + } + + gBS->Stall (10000); + } + + DEBUG ((DEBUG_ERROR, "%a: ACMD41 failed after %d retries\n", __func__, S= END_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 st= ructure. + + @retval EFI_SUCCESS The MMC/SD card was successfully r= eset 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 =3D MmcHostInstance->MmcHost->SendCommand (MmcHostInstance->MmcHo= st, 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 st= ructure. + + @retval EFI_SUCCESS The Operation Condition was succes= sfully sent to the MMC/SD card. + @retval EFI_DEVICE_ERROR Failed to send the Operation Condi= tion to the MMC/SD card. + @retval Other An error occurred while sending th= e 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 =3D MmcResetToIdle (MmcHostInstance); + if (EFI_ERROR (Status)) { + return Status; + } + + for (I =3D 0; I < SEND_OP_COND_MAX_RETRIES; I++) { + Status =3D MmcHostInstance->MmcHost->SendCommand (MmcHostInstance->Mmc= Host, 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) !=3D 0U) { + MmcOCR =3D Response[0]; + return EFI_SUCCESS; + } + + gBS->Stall (10000); + } + + DEBUG ((DEBUG_ERROR, "%a: CMD1 failed after %d retries\n", __func__, SEN= D_OP_COND_MAX_RETRIES)); + + return EFI_DEVICE_ERROR; +} + +/** + Enumerate and initialize the MMC/SD card. + + @param[in] MmcHostInstance Pointer to the MMC_HOST_INSTANCE st= ructure. + @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 e= numerated and initialized. + @retval Other An error occurred while enumeratin= g 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 =3D MmcResetToIdle (MmcHostInstance); + if (EFI_ERROR (Status)) { + return Status; + } + + if (MmcDevInfo.MmcDevType =3D=3D MMC_IS_EMMC) { + Status =3D MmcSendOpCond (MmcHostInstance); + } else { + // CMD8: Send Interface Condition Command + Status =3D MmcHostInstance->MmcHost->SendCommand (MmcHostInstance->Mmc= Host, MMC_CMD8, VHS_2_7_3_6_V | CMD8_CHECK_PATTERN, + MMC_RESPONSE_R5, Response); + + if ((Status =3D=3D EFI_SUCCESS) && ((Response[0] & 0xffU) =3D=3D CMD8_= CHECK_PATTERN)) { + Status =3D SdSendOpCond (MmcHostInstance); + } + } + if (EFI_ERROR (Status)) { + return Status; + } + + // CMD2: Card Identification + Status =3D MmcHostInstance->MmcHost->SendCommand (MmcHostInstance->MmcHo= st, MMC_CMD2, 0, MMC_RESPONSE_R2, NULL); + if (EFI_ERROR (Status)) { + return Status; + } + + // CMD3: Set Relative Address + if (MmcDevInfo.MmcDevType =3D=3D MMC_IS_EMMC) { + MmcRCA =3D MMC_FIX_RCA; + Status =3D MmcHostInstance->MmcHost->SendCommand (MmcHostInstance->Mmc= Host, MMC_CMD3, MmcRCA << RCA_SHIFT_OFFSET, + MMC_RESPONSE_R1, NULL); + if (EFI_ERROR (Status)) { + return Status; + } + } else { + Status =3D MmcHostInstance->MmcHost->SendCommand (MmcHostInstance->Mmc= Host, MMC_CMD3, 0, + MMC_RESPONSE_R6, Response); + if (EFI_ERROR (Status)) { + return Status; + } + + MmcRCA =3D (Response[0] & 0xFFFF0000U) >> 16; + } + + // CMD9: CSD Register + Status =3D MmcHostInstance->MmcHost->SendCommand (MmcHostInstance->MmcHo= st, 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 =3D MmcHostInstance->MmcHost->SendCommand (MmcHostInstance->MmcHo= st, MMC_CMD7, MmcRCA << RCA_SHIFT_OFFSET, + MMC_RESPONSE_R1, NULL); + if (EFI_ERROR (Status)) { + return Status; + } + + do { + Status =3D MmcDeviceState (MmcHostInstance, &State); + if (EFI_ERROR (Status)) { + return Status; + } + } while (State !=3D MMC_R0_STATE_TRAN); + + Status =3D 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 st= ructure. + + @retval EFI_SUCCESS The MMC Identification Mode was pe= rformed 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 =3D MmcHostInstance->MmcHost; + CmdArg =3D 0; + IsHCS =3D FALSE; + + if (MmcHost =3D=3D NULL) { + return EFI_INVALID_PARAMETER; + } + + // We can get into this function if we restart the identification mode + if (MmcHostInstance->State =3D=3D MmcHwInitializationState) { + // Initialize the MMC Host HW + Status =3D MmcNotifyState (MmcHostInstance, MmcHwInitializationState); + if (EFI_ERROR (Status)) { + DEBUG ((DEBUG_ERROR, "MmcIdentificationMode() : Error MmcHwInitializ= ationState, Status=3D%r.\n", Status)); + return Status; + } + } + + Status =3D MmcEnumerte (MmcHostInstance, 50 * 1000 * 1000, MMC_BUS_WIDTH= _4); + + if (EFI_ERROR (Status)) { + DEBUG ((DEBUG_ERROR, "MmcIdentificationMode() : Error MmcEnumerte, S= tatus=3D%r.\n", Status)); + return Status; + } + + MmcHostInstance->CardInfo.RCA =3D MmcRCA; + MmcHostInstance->BlockIo.Media->LastBlock =3D ((MmcDevInfo.DeviceSize= >> 9) - 1); + MmcHostInstance->BlockIo.Media->BlockSize =3D MmcDevInfo.BlockSize; + MmcHostInstance->BlockIo.Media->ReadOnly =3D MmcHost->IsReadOnly (Mm= cHost); + MmcHostInstance->BlockIo.Media->MediaPresent =3D 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 =3D 1; + MmcHost =3D MmcHostInstance->MmcHost; + + Status =3D MmcIdentificationMode (MmcHostInstance); + if (EFI_ERROR (Status)) { + DEBUG ((DEBUG_ERROR, "InitializeMmcDevice(): Error in Identification M= ode, Status=3D%r\n", Status)); + return Status; + } + + Status =3D MmcNotifyState (MmcHostInstance, MmcTransferState); + if (EFI_ERROR (Status)) { + DEBUG ((DEBUG_ERROR, "InitializeMmcDevice(): Error MmcTransferState, S= tatus=3D%r\n", Status)); + return Status; + } + + return EFI_SUCCESS; +} --=20 2.34.1 -=3D-=3D-=3D-=3D-=3D-=3D-=3D-=3D-=3D-=3D-=3D- Groups.io Links: You receive all messages sent to this group. View/Reply Online (#108760): https://edk2.groups.io/g/devel/message/108760 Mute This Topic: https://groups.io/mt/101400682/1787277 Group Owner: devel+owner@edk2.groups.io Unsubscribe: https://edk2.groups.io/g/devel/unsub [importer@patchew.org] -=3D-=3D-=3D-=3D-=3D-=3D-=3D-=3D-=3D-=3D-=3D-