[edk2-devel] [PATCH edk2-platforms 4/8] Sophgo/SG2042Pkg: Add base MMC driver.

caiyuqing_hz at 163.com caiyuqing_hz at 163.com
Sat Aug 19 08:37:00 UTC 2023


From: caiyuqing379 <202235273 at mail.sdu.edu.cn>

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.

Cc: dahogn <dahogn at hotmail.com>
Cc: inochisa <inochiama at outlook.com>
Cc: meng-cz <mengcz1126 at gmail.com>
Signed-off-by: caiyuqing379 <202235273 at mail.sdu.edu.cn>
Co-authored-by: USER0FISH <libing1202 at outlook.com>
Reviewed-by: yli147 <yong.li at intel.com>
Reviewed-by: ChaiEvan <evan.chai at intel.com>
---
 .../SG2042Pkg/Universal/Dxe/MmcDxe/MmcDxe.inf |  47 ++
 Platform/Sophgo/SG2042Pkg/Include/MmcHost.h   | 225 ++++++
 .../SG2042Pkg/Universal/Dxe/MmcDxe/Mmc.h      | 513 ++++++++++++
 .../Universal/Dxe/MmcDxe/ComponentName.c      | 156 ++++
 .../Universal/Dxe/MmcDxe/Diagnostics.c        | 323 ++++++++
 .../SG2042Pkg/Universal/Dxe/MmcDxe/Mmc.c      | 527 +++++++++++++
 .../Universal/Dxe/MmcDxe/MmcBlockIo.c         | 643 +++++++++++++++
 .../SG2042Pkg/Universal/Dxe/MmcDxe/MmcDebug.c | 194 +++++
 .../Universal/Dxe/MmcDxe/MmcIdentification.c  | 738 ++++++++++++++++++
 9 files changed, 3366 insertions(+)
 create mode 100644 Platform/Sophgo/SG2042Pkg/Universal/Dxe/MmcDxe/MmcDxe.inf
 create mode 100644 Platform/Sophgo/SG2042Pkg/Include/MmcHost.h
 create mode 100644 Platform/Sophgo/SG2042Pkg/Universal/Dxe/MmcDxe/Mmc.h
 create mode 100644 Platform/Sophgo/SG2042Pkg/Universal/Dxe/MmcDxe/ComponentName.c
 create mode 100644 Platform/Sophgo/SG2042Pkg/Universal/Dxe/MmcDxe/Diagnostics.c
 create mode 100644 Platform/Sophgo/SG2042Pkg/Universal/Dxe/MmcDxe/Mmc.c
 create mode 100644 Platform/Sophgo/SG2042Pkg/Universal/Dxe/MmcDxe/MmcBlockIo.c
 create mode 100644 Platform/Sophgo/SG2042Pkg/Universal/Dxe/MmcDxe/MmcDebug.c
 create mode 100644 Platform/Sophgo/SG2042Pkg/Universal/Dxe/MmcDxe/MmcIdentification.c

diff --git a/Platform/Sophgo/SG2042Pkg/Universal/Dxe/MmcDxe/MmcDxe.inf b/Platform/Sophgo/SG2042Pkg/Universal/Dxe/MmcDxe/MmcDxe.inf
new file mode 100644
index 000000000000..afb36859ad75
--- /dev/null
+++ b/Platform/Sophgo/SG2042Pkg/Universal/Dxe/MmcDxe/MmcDxe.inf
@@ -0,0 +1,47 @@
+## @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                    = 0x0001001A
+  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
+  Platform/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/Platform/Sophgo/SG2042Pkg/Include/MmcHost.h b/Platform/Sophgo/SG2042Pkg/Include/MmcHost.h
new file mode 100644
index 000000000000..d340af155d61
--- /dev/null
+++ b/Platform/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/Platform/Sophgo/SG2042Pkg/Universal/Dxe/MmcDxe/Mmc.h b/Platform/Sophgo/SG2042Pkg/Universal/Dxe/MmcDxe/Mmc.h
new file mode 100644
index 000000000000..6ac59baa82ef
--- /dev/null
+++ b/Platform/Sophgo/SG2042Pkg/Universal/Dxe/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/Platform/Sophgo/SG2042Pkg/Universal/Dxe/MmcDxe/ComponentName.c b/Platform/Sophgo/SG2042Pkg/Universal/Dxe/MmcDxe/ComponentName.c
new file mode 100644
index 000000000000..eb66c68a54c7
--- /dev/null
+++ b/Platform/Sophgo/SG2042Pkg/Universal/Dxe/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/Platform/Sophgo/SG2042Pkg/Universal/Dxe/MmcDxe/Diagnostics.c b/Platform/Sophgo/SG2042Pkg/Universal/Dxe/MmcDxe/Diagnostics.c
new file mode 100644
index 000000000000..e7ea395a9462
--- /dev/null
+++ b/Platform/Sophgo/SG2042Pkg/Universal/Dxe/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/Platform/Sophgo/SG2042Pkg/Universal/Dxe/MmcDxe/Mmc.c b/Platform/Sophgo/SG2042Pkg/Universal/Dxe/MmcDxe/Mmc.c
new file mode 100644
index 000000000000..ffe25c7fbb2b
--- /dev/null
+++ b/Platform/Sophgo/SG2042Pkg/Universal/Dxe/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 gRaspberryPiMmcHostProtocolGuid
+    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/Platform/Sophgo/SG2042Pkg/Universal/Dxe/MmcDxe/MmcBlockIo.c b/Platform/Sophgo/SG2042Pkg/Universal/Dxe/MmcDxe/MmcBlockIo.c
new file mode 100644
index 000000000000..92be2c88c303
--- /dev/null
+++ b/Platform/Sophgo/SG2042Pkg/Universal/Dxe/MmcDxe/MmcBlockIo.c
@@ -0,0 +1,643 @@
+/** @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;
+
+  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/Platform/Sophgo/SG2042Pkg/Universal/Dxe/MmcDxe/MmcDebug.c b/Platform/Sophgo/SG2042Pkg/Universal/Dxe/MmcDxe/MmcDebug.c
new file mode 100644
index 000000000000..62386d7b0373
--- /dev/null
+++ b/Platform/Sophgo/SG2042Pkg/Universal/Dxe/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/Platform/Sophgo/SG2042Pkg/Universal/Dxe/MmcDxe/MmcIdentification.c b/Platform/Sophgo/SG2042Pkg/Universal/Dxe/MmcDxe/MmcIdentification.c
new file mode 100644
index 000000000000..f00ee758f97b
--- /dev/null
+++ b/Platform/Sophgo/SG2042Pkg/Universal/Dxe/MmcDxe/MmcIdentification.c
@@ -0,0 +1,738 @@
+/** @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-3-Clause
+
+**/
+
+#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 = (unsigned long long)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 = ((unsigned long long)MmcCsd.C_SIZEHigh10 << 2U) |
+        (unsigned long long)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 = ((unsigned long long)CsdSdV2->C_SIZEHigh6 << 16) |
+        (unsigned long long)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;
+  }
+
+  // Set Block Length
+  Status = MmcHost->SendCommand (MmcHost, MMC_CMD16, MmcHostInstance->BlockIo.Media->BlockSize, MMC_RESPONSE_R1, NULL);
+  if (EFI_ERROR (Status)) {
+    DEBUG ((DEBUG_ERROR,
+      "InitializeMmcDevice(MMC_CMD16): Error MmcHostInstance->BlockIo.Media->BlockSize: %d and Error = %r\n",
+      MmcHostInstance->BlockIo.Media->BlockSize, Status));
+    return Status;
+  }
+
+  // Block Count (not used). Could return an error for SD card
+  if (MmcHostInstance->CardInfo.CardType == MMC_CARD) {
+    Status = MmcHost->SendCommand (MmcHost, MMC_CMD23, BlockCount, MMC_RESPONSE_R1, NULL);
+    if (EFI_ERROR (Status)) {
+      DEBUG ((DEBUG_ERROR, "InitializeMmcDevice(MMC_CMD23): Error, 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 (#107889): https://edk2.groups.io/g/devel/message/107889
Mute This Topic: https://groups.io/mt/100840193/1813853
Group Owner: devel+owner at edk2.groups.io
Unsubscribe: https://edk2.groups.io/g/devel/unsub [edk2-devel-archive at redhat.com]
-=-=-=-=-=-=-=-=-=-=-=-




More information about the edk2-devel-archive mailing list