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