diff mbox series

[edk2,v1,2/2] EmbeddedPkg: add DwMmcHcDxe driver

Message ID 1533890955-13005-3-git-send-email-haojian.zhuang@linaro.org
State Superseded
Headers show
Series add DwMmcHcDxe driver | expand

Commit Message

Haojian Zhuang Aug. 10, 2018, 8:49 a.m. UTC
DwMmcHcDxe driver is for Designware SD and MMMC controller.

Cc: Leif Lindholm <leif.lindholm@linaro.org>
Cc: Ard Biesheuvel <ard.biesheuvel@linaro.org>
Contributed-under: TianoCore Contribution Agreement 1.1
Signed-off-by: Haojian Zhuang <haojian.zhuang@linaro.org>

---
 EmbeddedPkg/Drivers/DwMmcHcDxe/DwMmcHcDxe.dec  |   40 +
 EmbeddedPkg/Drivers/DwMmcHcDxe/DwMmcHcDxe.inf  |   69 +
 EmbeddedPkg/Drivers/DwMmcHcDxe/DwMmcHcDxe.h    |  815 +++++++
 EmbeddedPkg/Drivers/DwMmcHcDxe/DwMmcHci.h      |  983 ++++++++
 EmbeddedPkg/Include/Protocol/PlatformDwMmc.h   |   79 +
 EmbeddedPkg/Drivers/DwMmcHcDxe/ComponentName.c |  214 ++
 EmbeddedPkg/Drivers/DwMmcHcDxe/DwMmcHcDxe.c    | 1295 +++++++++++
 EmbeddedPkg/Drivers/DwMmcHcDxe/DwMmcHci.c      | 2366 ++++++++++++++++++++
 EmbeddedPkg/Drivers/DwMmcHcDxe/EmmcDevice.c    | 1042 +++++++++
 EmbeddedPkg/Drivers/DwMmcHcDxe/SdDevice.c      | 1104 +++++++++
 10 files changed, 8007 insertions(+)

-- 
2.7.4

_______________________________________________
edk2-devel mailing list
edk2-devel@lists.01.org
https://lists.01.org/mailman/listinfo/edk2-devel
diff mbox series

Patch

diff --git a/EmbeddedPkg/Drivers/DwMmcHcDxe/DwMmcHcDxe.dec b/EmbeddedPkg/Drivers/DwMmcHcDxe/DwMmcHcDxe.dec
new file mode 100644
index 000000000000..cf85ccb1a030
--- /dev/null
+++ b/EmbeddedPkg/Drivers/DwMmcHcDxe/DwMmcHcDxe.dec
@@ -0,0 +1,40 @@ 
+#/** @file
+# Framework Module Development Environment Industry Standards
+#
+# This Package provides headers and libraries that conform to EFI/PI Industry standards.
+# Copyright (c) 2007, Intel Corporation. All rights reserved.<BR>
+# Copyright (c) 2012-2014, ARM Ltd. All rights reserved.<BR>
+# Copyright (c) 2018, Linaro. All rights reserved.<BR>
+#
+#    This program and the accompanying materials are licensed and made available under
+#    the terms and conditions of the BSD License which accompanies this distribution.
+#    The full text of the license may be found at
+#    http://opensource.org/licenses/bsd-license.php
+#
+#    THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+#    WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+#
+#**/
+
+[Defines]
+  DEC_SPECIFICATION              = 0x00010019
+  PACKAGE_NAME                   = DwMmcHcDxePkg
+  PACKAGE_GUID                   = e73097ce-1fe2-41a6-a930-3136bc6d23ef
+  PACKAGE_VERSION                = 0.1
+
+
+################################################################################
+#
+# Include Section - list of Include Paths that are provided by this package.
+#                   Comments are used for Keywords and Module Types.
+#
+# Supported Module Types:
+#  BASE SEC PEI_CORE PEIM DXE_CORE DXE_DRIVER DXE_RUNTIME_DRIVER DXE_SMM_DRIVER DXE_SAL_DRIVER UEFI_DRIVER UEFI_APPLICATION
+#
+################################################################################
+
+[Guids.common]
+  gDwMmcHcDxeTokenSpaceGuid     = { 0x576c132e, 0x7d51, 0x4abb, { 0xbc, 0x60, 0x13, 0x08, 0x04, 0x0e, 0x90, 0x92 }}
+
+[Protocols.common]
+  gPlatformDwMmcProtocolGuid    = { 0x1d6dfde5, 0x76a7, 0x4404, { 0x85, 0x74, 0x7a, 0xdf, 0x1a, 0x8a, 0xa2, 0x0d }}
diff --git a/EmbeddedPkg/Drivers/DwMmcHcDxe/DwMmcHcDxe.inf b/EmbeddedPkg/Drivers/DwMmcHcDxe/DwMmcHcDxe.inf
new file mode 100644
index 000000000000..699de99e22b1
--- /dev/null
+++ b/EmbeddedPkg/Drivers/DwMmcHcDxe/DwMmcHcDxe.inf
@@ -0,0 +1,69 @@ 
+## @file
+#  DwSdMmcHcDxe driver is used to manage those host controllers which comply with
+#  Designware SD Host Controller.
+#
+#  It will produce EFI_SD_MMC_PASS_THRU_PROTOCOL to allow sending SD/MMC/eMMC cmds
+#  to specified devices from upper layer.
+#
+#  Copyright (c) 2015, Intel Corporation. All rights reserved.<BR>
+#  Copyright (C) 2016, Marvell International Ltd. All rights reserved.<BR>
+#  Copyright (c) 2018, Linaro Ltd. All rights reserved.<BR>
+#
+#  This program and the accompanying materials
+#  are licensed and made available under the terms and conditions of the BSD License
+#  which accompanies this distribution. The full text of the license may be found at
+#  http://opensource.org/licenses/bsd-license.php
+#  THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+#  WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+#
+#
+##
+
+[Defines]
+  INF_VERSION                    = 0x00010019
+  BASE_NAME                      = DwMmcHcDxe
+  MODULE_UNI_FILE                = DwMmcHcDxe.uni
+  FILE_GUID                      = 9be4d260-208c-4efe-a524-0b5d3bf77f9d
+  MODULE_TYPE                    = UEFI_DRIVER
+  VERSION_STRING                 = 1.0
+  ENTRY_POINT                    = InitializeDwMmcHcDxe
+
+[Sources]
+  ComponentName.c
+  DwMmcHcDxe.c
+  DwMmcHcDxe.h
+  DwMmcHci.c
+  DwMmcHci.h
+  EmmcDevice.c
+  SdDevice.c
+
+[Packages]
+  ArmPkg/ArmPkg.dec
+  EmbeddedPkg/Drivers/DwMmcHcDxe/DwMmcHcDxe.dec
+  EmbeddedPkg/EmbeddedPkg.dec
+  MdeModulePkg/MdeModulePkg.dec
+  MdePkg/MdePkg.dec
+
+[LibraryClasses]
+  ArmLib
+  BaseLib
+  BaseMemoryLib
+  CacheMaintenanceLib
+  DebugLib
+  DevicePathLib
+  MemoryAllocationLib
+  TimerLib
+  UefiBootServicesTableLib
+  UefiDriverEntryPoint
+  UefiLib
+  UefiRuntimeServicesTableLib
+
+[Protocols]
+  gEfiDevicePathProtocolGuid                    ## TO_START
+  gEfiPciIoProtocolGuid                         ## TO_START
+  gEfiSdMmcPassThruProtocolGuid                 ## BY_START
+  gEmbeddedNonDiscoverableIoProtocolGuid
+  gPlatformDwMmcProtocolGuid
+
+[UserExtensions.TianoCore."ExtraFiles"]
+  DwMmcHcDxeExtra.uni
diff --git a/EmbeddedPkg/Drivers/DwMmcHcDxe/DwMmcHcDxe.h b/EmbeddedPkg/Drivers/DwMmcHcDxe/DwMmcHcDxe.h
new file mode 100644
index 000000000000..d17604d51304
--- /dev/null
+++ b/EmbeddedPkg/Drivers/DwMmcHcDxe/DwMmcHcDxe.h
@@ -0,0 +1,815 @@ 
+/** @file
+
+  Provides some data structure definitions used by the Designware SD/MMC
+  host controller driver.
+
+  Copyright (c) 2015, Intel Corporation. All rights reserved.<BR>
+  Copyright (C) 2018, Linaro Ltd. All rigths reserved.<BR>
+
+  This program and the accompanying materials are licensed and made available
+  under the terms and conditions of the BSD License which accompanies this
+  distribution.  The full text of the license may be found at
+  http://opensource.org/licenses/bsd-license.php
+
+  THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+  WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#ifndef _DW_MMC_HC_DXE_H_
+#define _DW_MMC_HC_DXE_H_
+
+#include <Uefi.h>
+
+#include <Library/UefiLib.h>
+
+#include <Protocol/ComponentName.h>
+#include <Protocol/ComponentName2.h>
+#include <Protocol/DeviceIo.h>
+#include <Protocol/DriverBinding.h>
+#include <Protocol/SdMmcPassThru.h>
+
+#include "DwMmcHci.h"
+
+extern EFI_COMPONENT_NAME_PROTOCOL  gDwMmcHcComponentName;
+extern EFI_COMPONENT_NAME2_PROTOCOL gDwMmcHcComponentName2;
+extern EFI_DRIVER_BINDING_PROTOCOL  gDwMmcHcDriverBinding;
+
+#define DW_MMC_HC_PRIVATE_SIGNATURE  SIGNATURE_32 ('d', 'w', 's', 'd')
+
+#define DW_MMC_HC_PRIVATE_FROM_THIS(a) \
+    CR(a, DW_MMC_HC_PRIVATE_DATA, PassThru, DW_MMC_HC_PRIVATE_SIGNATURE)
+
+//
+// Generic time out value, 1 microsecond as unit.
+//
+#define DW_MMC_HC_GENERIC_TIMEOUT     (1 * 1000 * 1000)
+
+//
+// SD/MMC async transfer timer interval, set by experience.
+// The unit is 100us, takes 1ms as interval.
+//
+#define DW_MMC_HC_ASYNC_TIMER         EFI_TIMER_PERIOD_MILLISECONDS(1)
+//
+// SD/MMC removable device enumeration timer interval, set by experience.
+// The unit is 100us, takes 100ms as interval.
+//
+#define DW_MMC_HC_ENUM_TIMER          EFI_TIMER_PERIOD_MILLISECONDS(100)
+
+typedef struct {
+  BOOLEAN                             Enable;
+  EFI_SD_MMC_SLOT_TYPE                SlotType;
+  BOOLEAN                             MediaPresent;
+  BOOLEAN                             Initialized;
+  SD_MMC_CARD_TYPE                    CardType;
+} DW_MMC_HC_SLOT;
+
+typedef struct {
+  UINTN                               Signature;
+
+  EFI_HANDLE                          ControllerHandle;
+  EFI_DEVICE_IO_PROTOCOL              *DevIo;
+
+  EFI_SD_MMC_PASS_THRU_PROTOCOL       PassThru;
+
+  PLATFORM_DW_MMC_PROTOCOL            *PlatformDwMmc;
+  //
+  // The field is used to record the previous slot in GetNextSlot().
+  //
+  UINT8                               PreviousSlot;
+  //
+  // For Non-blocking operation.
+  //
+  EFI_EVENT                           TimerEvent;
+  //
+  // For Sd removable device enumeration.
+  //
+  EFI_EVENT                           ConnectEvent;
+  LIST_ENTRY                          Queue;
+
+  DW_MMC_HC_SLOT                      Slot[DW_MMC_HC_MAX_SLOT];
+  DW_MMC_HC_SLOT_CAP                  Capability[DW_MMC_HC_MAX_SLOT];
+  UINT64                              MaxCurrent[DW_MMC_HC_MAX_SLOT];
+
+  UINT32                              ControllerVersion;
+} DW_MMC_HC_PRIVATE_DATA;
+
+#define DW_MMC_HC_TRB_SIG             SIGNATURE_32 ('D', 'T', 'R', 'B')
+
+//
+// TRB (Transfer Request Block) contains information for the cmd request.
+//
+typedef struct {
+  UINT32                              Signature;
+  LIST_ENTRY                          TrbList;
+
+  UINT8                               Slot;
+  UINT16                              BlockSize;
+
+  EFI_SD_MMC_PASS_THRU_COMMAND_PACKET *Packet;
+  VOID                                *Data;
+  UINT32                              DataLen;
+  BOOLEAN                             Read;
+  EFI_PHYSICAL_ADDRESS                DataPhy;
+  VOID                                *DataMap;
+  DW_MMC_HC_TRANSFER_MODE             Mode;
+
+  EFI_EVENT                           Event;
+  BOOLEAN                             Started;
+  UINT64                              Timeout;
+
+  DW_MMC_HC_DMA_DESC_LINE             *DmaDesc;
+  EFI_PHYSICAL_ADDRESS                DmaDescPhy;
+  UINT32                              DmaDescPages;
+  VOID                                *DmaMap;
+
+  BOOLEAN                             UseFifo;
+  BOOLEAN                             UseBE;                  // Big-endian
+
+  DW_MMC_HC_PRIVATE_DATA              *Private;
+} DW_MMC_HC_TRB;
+
+#define DW_MMC_HC_TRB_FROM_THIS(a) \
+    CR(a, DW_MMC_HC_TRB, TrbList, DW_MMC_HC_TRB_SIG)
+
+//
+// Task for Non-blocking mode.
+//
+typedef struct {
+  UINT32                              Signature;
+  LIST_ENTRY                          Link;
+
+  UINT8                               Slot;
+  EFI_SD_MMC_PASS_THRU_COMMAND_PACKET *Packet;
+  BOOLEAN                             IsStart;
+  EFI_EVENT                           Event;
+  UINT64                              RetryTimes;
+  BOOLEAN                             InfiniteWait;
+  VOID                                *Map;
+  VOID                                *MapAddress;
+} DW_MMC_HC_QUEUE;
+
+//
+// Prototypes
+//
+/**
+  Execute card identification procedure.
+
+  @param[in] Private        A pointer to the DW_MMC_HC_PRIVATE_DATA instance.
+
+  @retval EFI_SUCCESS       The card is identified correctly.
+  @retval Others            The card can't be identified.
+
+**/
+typedef
+EFI_STATUS
+(*DWMMC_CARD_TYPE_DETECT_ROUTINE) (
+  IN DW_MMC_HC_PRIVATE_DATA             *Private
+  );
+
+/**
+  Sends SD command to an SD card that is attached to the SD controller.
+
+  The PassThru() function sends the SD command specified by Packet to the SD
+  card specified by Slot.
+
+  If Packet is successfully sent to the SD card, then EFI_SUCCESS is returned.
+
+  If a device error occurs while sending the Packet, then EFI_DEVICE_ERROR is
+  returned.
+
+  If Slot is not in a valid range for the SD controller, then
+  EFI_INVALID_PARAMETER is returned.
+
+  If Packet defines a data command but both InDataBuffer and OutDataBuffer are
+  NULL, EFI_INVALID_PARAMETER is returned.
+
+  @param[in]     This           A pointer to the EFI_SD_MMC_PASS_THRU_PROTOCOL
+                                instance.
+  @param[in]     Slot           The slot number of the SD card to send the
+                                command to.
+  @param[in,out] Packet         A pointer to the SD command data structure.
+  @param[in]     Event          If Event is NULL, blocking I/O is performed. If
+                                Event is not NULL, then nonblocking I/O is
+                                performed, and Event will be signaled when the
+                                Packet completes.
+
+  @retval EFI_SUCCESS           The SD Command Packet was sent by the host.
+  @retval EFI_DEVICE_ERROR      A device error occurred while attempting to send
+                                the SD command Packet.
+  @retval EFI_INVALID_PARAMETER Packet, Slot, or the contents of the Packet is
+                                invalid.
+  @retval EFI_INVALID_PARAMETER Packet defines a data command but both
+                                InDataBuffer and OutDataBuffer are NULL.
+  @retval EFI_NO_MEDIA          SD Device not present in the Slot.
+  @retval EFI_UNSUPPORTED       The command described by the SD Command Packet
+                                is not supported by the host controller.
+  @retval EFI_BAD_BUFFER_SIZE   The InTransferLength or OutTransferLength
+                                exceeds the limit supported by SD card ( i.e. if
+                                the number of bytes exceed the Last LBA).
+
+**/
+EFI_STATUS
+EFIAPI
+DwMmcPassThruPassThru (
+  IN     EFI_SD_MMC_PASS_THRU_PROTOCOL         *This,
+  IN     UINT8                                 Slot,
+  IN OUT EFI_SD_MMC_PASS_THRU_COMMAND_PACKET   *Packet,
+  IN     EFI_EVENT                             Event    OPTIONAL
+  );
+
+/**
+  Used to retrieve next slot numbers supported by the SD controller. The
+  function returns information about all available slots (populated or
+  not-populated).
+
+  The GetNextSlot() function retrieves the next slot number on an SD controller.
+  If on input Slot is 0xFF, then the slot number of the first slot on the SD
+  controller is returned.
+
+  If Slot is a slot number that was returned on a previous call to
+  GetNextSlot(), then the slot number of the next slot on the SD controller is
+  returned.
+
+  If Slot is not 0xFF and Slot was not returned on a previous call to
+  GetNextSlot(), EFI_INVALID_PARAMETER is returned.
+
+  If Slot is the slot number of the last slot on the SD controller, then
+  EFI_NOT_FOUND is returned.
+
+  @param[in]     This           A pointer to the EFI_SD_MMMC_PASS_THRU_PROTOCOL
+                                instance.
+  @param[in,out] Slot           On input, a pointer to a slot number on the SD
+                                controller.
+                                On output, a pointer to the next slot number on
+                                the SD controller.
+                                An input value of 0xFF retrieves the first slot
+                                number on the SD controller.
+
+  @retval EFI_SUCCESS           The next slot number on the SD controller was
+                                returned in Slot.
+  @retval EFI_NOT_FOUND         There are no more slots on this SD controller.
+  @retval EFI_INVALID_PARAMETER Slot is not 0xFF and Slot was not returned on a
+                                previous call to GetNextSlot().
+
+**/
+EFI_STATUS
+EFIAPI
+DwMmcPassThruGetNextSlot (
+  IN     EFI_SD_MMC_PASS_THRU_PROTOCOL        *This,
+  IN OUT UINT8                                *Slot
+  );
+
+/**
+  Used to allocate and build a device path node for an SD card on the SD
+  controller.
+
+  The BuildDevicePath() function allocates and builds a single device node
+  for the SD
+  card specified by Slot.
+
+  If the SD card specified by Slot is not present on the SD controller, then
+  EFI_NOT_FOUND is returned.
+
+  If DevicePath is NULL, then EFI_INVALID_PARAMETER is returned.
+
+  If there are not enough resources to allocate the device path node, then
+  EFI_OUT_OF_RESOURCES is returned.
+
+  Otherwise, DevicePath is allocated with the boot service AllocatePool(), the
+  contents of DevicePath are initialized to describe the SD card specified by
+  Slot, and EFI_SUCCESS is returned.
+
+  @param[in]     This           A pointer to the EFI_SD_MMMC_PASS_THRU_PROTOCOL
+                                instance.
+  @param[in]     Slot           Specifies the slot number of the SD card for
+                                which a device path node is to be allocated and
+                                built.
+  @param[in,out] DevicePath     A pointer to a single device path node that
+                                describes the SD card specified by Slot. This
+                                function is responsible for allocating the
+                                buffer DevicePath with the boot service
+                                AllocatePool(). It is the caller's responsibi-
+                                lity to free DevicePath when the caller is
+                                finished with DevicePath.
+
+  @retval EFI_SUCCESS           The device path node that describes the SD card
+                                specified by Slot was allocated and returned in
+                                DevicePath.
+  @retval EFI_NOT_FOUND         The SD card specified by Slot does not exist on
+                                the SD controller.
+  @retval EFI_INVALID_PARAMETER DevicePath is NULL.
+  @retval EFI_OUT_OF_RESOURCES  There are not enough resources to allocate
+                                DevicePath.
+
+**/
+EFI_STATUS
+EFIAPI
+DwMmcPassThruBuildDevicePath (
+  IN     EFI_SD_MMC_PASS_THRU_PROTOCOL       *This,
+  IN     UINT8                               Slot,
+  IN OUT EFI_DEVICE_PATH_PROTOCOL            **DevicePath
+  );
+
+/**
+  This function retrieves an SD card slot number based on the input device path.
+
+  The GetSlotNumber() function retrieves slot number for the SD card specified
+  by the DevicePath node. If DevicePath is NULL, EFI_INVALID_PARAMETER is
+  returned.
+
+  If DevicePath is not a device path node type that the SD Pass Thru driver
+  supports, EFI_UNSUPPORTED is returned.
+
+  @param[in]  This              A pointer to the EFI_SD_MMC_PASS_THRU_PROTOCOL
+                                instance.
+  @param[in]  DevicePath        A pointer to the device path node that describes
+                                a SD card on the SD controller.
+  @param[out] Slot              On return, points to the slot number of an SD
+                                card on the SD controller.
+
+  @retval EFI_SUCCESS           SD card slot number is returned in Slot.
+  @retval EFI_INVALID_PARAMETER Slot or DevicePath is NULL.
+  @retval EFI_UNSUPPORTED       DevicePath is not a device path node type that
+                                the SD Pass Thru driver supports.
+
+**/
+EFI_STATUS
+EFIAPI
+DwMmcPassThruGetSlotNumber (
+  IN  EFI_SD_MMC_PASS_THRU_PROTOCOL          *This,
+  IN  EFI_DEVICE_PATH_PROTOCOL               *DevicePath,
+  OUT UINT8                                  *Slot
+  );
+
+/**
+  Resets an SD card that is connected to the SD controller.
+
+  The ResetDevice() function resets the SD card specified by Slot.
+
+  If this SD controller does not support a device reset operation,
+  EFI_UNSUPPORTED is returned.
+
+  If Slot is not in a valid slot number for this SD controller,
+  EFI_INVALID_PARAMETER is returned.
+
+  If the device reset operation is completed, EFI_SUCCESS is returned.
+
+  @param[in]  This              A pointer to the EFI_SD_MMC_PASS_THRU_PROTOCOL
+                                instance.
+  @param[in]  Slot              Specifies the slot number of the SD card to be
+                                reset.
+
+  @retval EFI_SUCCESS           The SD card specified by Slot was reset.
+  @retval EFI_UNSUPPORTED       The SD controller does not support a device
+                                reset operation.
+  @retval EFI_INVALID_PARAMETER Slot number is invalid.
+  @retval EFI_NO_MEDIA          SD Device not present in the Slot.
+  @retval EFI_DEVICE_ERROR      The reset command failed due to a device error
+
+**/
+EFI_STATUS
+EFIAPI
+DwMmcPassThruResetDevice (
+  IN EFI_SD_MMC_PASS_THRU_PROTOCOL           *This,
+  IN UINT8                                   Slot
+  );
+
+//
+// Driver model protocol interfaces
+//
+/**
+  Tests to see if this driver supports a given controller. If a child device is
+  provided, it further tests to see if this driver supports creating a handle
+  for the specified child device.
+
+  This function checks to see if the driver specified by This supports the
+  device specified by ControllerHandle. Drivers will typically use the device
+  path attached to ControllerHandle and/or the services from the bus I/O
+  abstraction attached to ControllerHandle to determine if the driver supports
+  ControllerHandle. This function may be called many times during platform
+  initialization. In order to reduce boot times, the tests performed by this
+  function must be very small, and take as little time as possible to execute.
+  This function must not change the state of any hardware devices, and this
+  function must be aware that the device specified by ControllerHandle may
+  already be managed by the same driver or a different driver. This function
+  must match its calls to AllocatePages() with FreePages(), AllocatePool() with
+  FreePool(), and OpenProtocol() with CloseProtocol().
+  Since ControllerHandle may have been previously started by the same driver, if
+  a protocol is already in the opened state, then it must not be closed with
+  CloseProtocol(). This is required to guarantee the state of ControllerHandle
+  is not modified by this function.
+
+  @param[in]  This                 A pointer to the EFI_DRIVER_BINDING_PROTOCOL
+                                   instance.
+  @param[in]  ControllerHandle     The handle of the controller to test. This
+                                   handle must support a protocol interface that
+                                   supplies an I/O abstraction to the driver.
+  @param[in]  RemainingDevicePath  A pointer to the remaining portion of a
+                                   device path.  This parameter is ignored by
+                                   device drivers, and is optional for bus
+                                   drivers. For bus drivers, if this parameter
+                                   is not NULL, then the bus driver must deter-
+                                   mine if the bus controller specified by
+                                   ControllerHandle and the child controller
+                                   specified by RemainingDevicePath are both
+                                   supported by this bus driver.
+
+  @retval EFI_SUCCESS              The device specified by ControllerHandle and
+                                   RemainingDevicePath is supported by the
+                                   driver specified by This.
+  @retval EFI_ALREADY_STARTED      The device specified by ControllerHandle and
+                                   RemainingDevicePath is already being managed
+                                   by the driver specified by This.
+  @retval EFI_ACCESS_DENIED        The device specified by ControllerHandle and
+                                   RemainingDevicePath is already being managed
+                                   by a different driver or an application that
+                                   requires exclusive access.
+                                   Currently not implemented.
+  @retval EFI_UNSUPPORTED          The device specified by ControllerHandle and
+                                   RemainingDevicePath is not supported by the
+                                   driver specified by This.
+**/
+EFI_STATUS
+EFIAPI
+DwMmcHcDriverBindingSupported (
+  IN EFI_DRIVER_BINDING_PROTOCOL *This,
+  IN EFI_HANDLE                  Controller,
+  IN EFI_DEVICE_PATH_PROTOCOL    *RemainingDevicePath
+  );
+
+/**
+  Starts a device controller or a bus controller.
+
+  The Start() function is designed to be invoked from the EFI boot service
+  ConnectController().
+  As a result, much of the error checking on the parameters to Start() has been
+  moved into this common boot service. It is legal to call Start() from other
+  locations,
+  but the following calling restrictions must be followed or the system behavior
+  will not be deterministic.
+  1. ControllerHandle must be a valid EFI_HANDLE.
+  2. If RemainingDevicePath is not NULL, then it must be a pointer to a natural-
+     ly aligned EFI_DEVICE_PATH_PROTOCOL.
+  3. Prior to calling Start(), the Supported() function for the driver specified
+     by This must have been called with the same calling parameters, and
+     Supported() must have returned EFI_SUCCESS.
+
+  @param[in]  This                 A pointer to the EFI_DRIVER_BINDING_PROTOCOL
+                                   instance.
+  @param[in]  ControllerHandle     The handle of the controller to start. This
+                                   handle must support a protocol interface that
+                                   supplies an I/O abstraction to the driver.
+  @param[in]  RemainingDevicePath  A pointer to the remaining portion of a
+                                   device path.  This parameter is ignored by
+                                   device drivers, and is optional for bus dri-
+                                   vers. For a bus driver, if this parameter is
+                                   NULL, then handles for all the children of
+                                   Controller are created by this driver.
+                                   If this parameter is not NULL and the first
+                                   Device Path Node is not the End of Device
+                                   Path Node, then only the handle for the
+                                   child device specified by the first Device
+                                   Path Node of RemainingDevicePath is created
+                                   by this driver.
+                                   If the first Device Path Node of
+                                   RemainingDevicePath is the End of Device Path
+                                   Node, no child handle is created by this
+                                   driver.
+
+  @retval EFI_SUCCESS              The device was started.
+  @retval EFI_DEVICE_ERROR         The device could not be started due to a
+                                   device error. Currently not implemented.
+  @retval EFI_OUT_OF_RESOURCES     The request could not be completed due to a
+                                   lack of resources.
+  @retval Others                   The driver failded to start the device.
+
+**/
+EFI_STATUS
+EFIAPI
+DwMmcHcDriverBindingStart (
+  IN EFI_DRIVER_BINDING_PROTOCOL     *This,
+  IN EFI_HANDLE                      Controller,
+  IN EFI_DEVICE_PATH_PROTOCOL        *RemainingDevicePath
+  );
+
+/**
+  Stops a device controller or a bus controller.
+
+  The Stop() function is designed to be invoked from the EFI boot service
+  DisconnectController().
+  As a result, much of the error checking on the parameters to Stop() has been
+  moved into this common boot service. It is legal to call Stop() from other
+  locations, but the following calling restrictions must be followed or the
+  system behavior will not be deterministic.
+  1. ControllerHandle must be a valid EFI_HANDLE that was used on a previous
+     call to this same driver's Start() function.
+  2. The first NumberOfChildren handles of ChildHandleBuffer must all be a valid
+     EFI_HANDLE. In addition, all of these handles must have been created in
+     this driver's Start() function, and the Start() function must have called
+     OpenProtocol() on ControllerHandle with an Attribute of
+     EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER.
+
+  @param[in]  This              A pointer to the EFI_DRIVER_BINDING_PROTOCOL
+                                instance.
+  @param[in]  ControllerHandle  A handle to the device being stopped. The handle
+                                must support a bus specific I/O protocol for the
+                                driver to use to stop the device.
+  @param[in]  NumberOfChildren  The number of child device handles in
+                                ChildHandleBuffer.
+  @param[in]  ChildHandleBuffer An array of child handles to be freed. May be
+                                NULL if NumberOfChildren is 0.
+
+  @retval EFI_SUCCESS           The device was stopped.
+  @retval EFI_DEVICE_ERROR      The device could not be stopped due to a device
+                                error.
+
+**/
+EFI_STATUS
+EFIAPI
+DwMmcHcDriverBindingStop (
+  IN  EFI_DRIVER_BINDING_PROTOCOL     *This,
+  IN  EFI_HANDLE                      Controller,
+  IN  UINTN                           NumberOfChildren,
+  IN  EFI_HANDLE                      *ChildHandleBuffer
+  );
+
+//
+// EFI Component Name Functions
+//
+/**
+  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[in]              A pointer to the EFI_COMPONENT_NAME2_PROTOCOL or
+                                EFI_COMPONENT_NAME_PROTOCOL instance.
+
+  @param  Language[in]          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[out]       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
+DwMmcHcComponentNameGetDriverName (
+  IN  EFI_COMPONENT_NAME_PROTOCOL     *This,
+  IN  CHAR8                           *Language,
+  OUT CHAR16                          **DriverName
+  );
+
+/**
+  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[in]              A pointer to the EFI_COMPONENT_NAME2_PROTOCOL or
+                                EFI_COMPONENT_NAME_PROTOCOL instance.
+
+  @param  ControllerHandle[in]  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[in]       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[in]          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[out]   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
+DwMmcHcComponentNameGetControllerName (
+  IN  EFI_COMPONENT_NAME_PROTOCOL     *This,
+  IN  EFI_HANDLE                      ControllerHandle,
+  IN  EFI_HANDLE                      ChildHandle, OPTIONAL
+  IN  CHAR8                           *Language,
+  OUT CHAR16                          **ControllerName
+  );
+
+/**
+  Create a new TRB for the SD/MMC cmd request.
+
+  @param[in] Private        A pointer to the DW_MMC_HC_PRIVATE_DATA instance.
+  @param[in] Slot           The slot number of the SD card to send the command
+                            to.
+  @param[in] Packet         A pointer to the SD command data structure.
+  @param[in] Event          If Event is NULL, blocking I/O is performed.
+                            If Event is not NULL, then nonblocking I/O is
+                            performed, and Event will be signaled when the
+                            Packet completes.
+
+  @return Created Trb or NULL.
+
+**/
+DW_MMC_HC_TRB *
+DwMmcCreateTrb (
+  IN DW_MMC_HC_PRIVATE_DATA              *Private,
+  IN UINT8                               Slot,
+  IN EFI_SD_MMC_PASS_THRU_COMMAND_PACKET *Packet,
+  IN EFI_EVENT                           Event
+  );
+
+/**
+  Free the resource used by the TRB.
+
+  @param[in] Trb            The pointer to the DW_MMC_HC_TRB instance.
+
+**/
+VOID
+DwMmcFreeTrb (
+  IN DW_MMC_HC_TRB           *Trb
+  );
+
+/**
+  Check if the env is ready for execute specified TRB.
+
+  @param[in] Private        A pointer to the DW_MMC_HC_PRIVATE_DATA instance.
+  @param[in] Trb            The pointer to the DW_MMC_HC_TRB instance.
+
+  @retval EFI_SUCCESS       The env is ready for TRB execution.
+  @retval EFI_NOT_READY     The env is not ready for TRB execution.
+  @retval Others            Some erros happen.
+
+**/
+EFI_STATUS
+DwMmcCheckTrbEnv (
+  IN DW_MMC_HC_PRIVATE_DATA           *Private,
+  IN DW_MMC_HC_TRB                    *Trb
+  );
+
+/**
+  Wait for the env to be ready for execute specified TRB.
+
+  @param[in] Private        A pointer to the DW_MMC_HC_PRIVATE_DATA instance.
+  @param[in] Trb            The pointer to the DW_MMC_HC_TRB instance.
+
+  @retval EFI_SUCCESS       The env is ready for TRB execution.
+  @retval EFI_TIMEOUT       The env is not ready for TRB execution in time.
+  @retval Others            Some erros happen.
+
+**/
+EFI_STATUS
+DwMmcWaitTrbEnv (
+  IN DW_MMC_HC_PRIVATE_DATA           *Private,
+  IN DW_MMC_HC_TRB                    *Trb
+  );
+
+/**
+  Execute the specified TRB.
+
+  @param[in] Private        A pointer to the DW_MMC_HC_PRIVATE_DATA instance.
+  @param[in] Trb            The pointer to the DW_MMC_HC_TRB instance.
+
+  @retval EFI_SUCCESS       The TRB is sent to host controller successfully.
+  @retval Others            Some erros happen when sending this request to the
+                            host controller.
+
+**/
+EFI_STATUS
+DwMmcExecTrb (
+  IN DW_MMC_HC_PRIVATE_DATA           *Private,
+  IN DW_MMC_HC_TRB                    *Trb
+  );
+
+/**
+  Check the TRB execution result.
+
+  @param[in] Private        A pointer to the DW_MMC_HC_PRIVATE_DATA instance.
+  @param[in] Trb            The pointer to the DW_MMC_HC_TRB instance.
+
+  @retval EFI_SUCCESS       The TRB is executed successfully.
+  @retval EFI_NOT_READY     The TRB is not completed for execution.
+  @retval Others            Some erros happen when executing this request.
+
+**/
+EFI_STATUS
+DwMmcCheckTrbResult (
+  IN DW_MMC_HC_PRIVATE_DATA           *Private,
+  IN DW_MMC_HC_TRB                    *Trb
+  );
+
+/**
+  Wait for the TRB execution result.
+
+  @param[in] Private        A pointer to the DW_MMC_HC_PRIVATE_DATA instance.
+  @param[in] Trb            The pointer to the DW_MMC_HC_TRB instance.
+
+  @retval EFI_SUCCESS       The TRB is executed successfully.
+  @retval Others            Some erros happen when executing this request.
+
+**/
+EFI_STATUS
+DwMmcWaitTrbResult (
+  IN DW_MMC_HC_PRIVATE_DATA           *Private,
+  IN DW_MMC_HC_TRB                    *Trb
+  );
+
+/**
+  Execute EMMC device identification procedure.
+
+  Refer to EMMC Electrical Standard Spec 5.1 Section 6.4 for details.
+
+  @param[in] Private        A pointer to the DW_MMC_HC_PRIVATE_DATA instance.
+
+  @retval EFI_SUCCESS       There is a EMMC card.
+  @retval Others            There is not a EMMC card.
+
+**/
+EFI_STATUS
+EmmcIdentification (
+  IN DW_MMC_HC_PRIVATE_DATA             *Private
+  );
+
+/**
+  Execute EMMC device identification procedure.
+
+  Refer to EMMC Electrical Standard Spec 5.1 Section 6.4 for details.
+
+  @param[in] Private        A pointer to the DW_MMC_HC_PRIVATE_DATA instance.
+
+  @retval EFI_SUCCESS       There is a EMMC card.
+  @retval Others            There is not a EMMC card.
+
+**/
+EFI_STATUS
+SdCardIdentification (
+  IN DW_MMC_HC_PRIVATE_DATA             *Private
+  );
+
+#endif /* _DW_MMC_HC_DXE_H_ */
diff --git a/EmbeddedPkg/Drivers/DwMmcHcDxe/DwMmcHci.h b/EmbeddedPkg/Drivers/DwMmcHcDxe/DwMmcHci.h
new file mode 100644
index 000000000000..e4fe26e7d2e8
--- /dev/null
+++ b/EmbeddedPkg/Drivers/DwMmcHcDxe/DwMmcHci.h
@@ -0,0 +1,983 @@ 
+/** @file
+
+  Provides some data structure definitions used by the SD/MMC host controller
+  driver.
+
+  Copyright (c) 2015, Intel Corporation. All rights reserved.<BR>
+  Copyright (c) 2018, Linaro Ltd. All rights reserved.<BR>
+
+  This program and the accompanying materials are licensed and made available
+  under the terms and conditions of the BSD License which accompanies this
+  distribution.  The full text of the license may be found at
+  http://opensource.org/licenses/bsd-license.php
+
+  THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+  WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#ifndef _DW_MMC_HCI_H_
+#define _DW_MMC_HCI_H_
+
+#include <Library/CacheMaintenanceLib.h>
+#include <Library/TimerLib.h>
+
+#include <Protocol/PlatformDwMmc.h>
+
+//
+// SD Host Controller SlotInfo Register Offset
+//
+#define DW_MMC_HC_SLOT_OFFSET         0x40
+
+#define DW_MMC_HC_MAX_SLOT            1
+
+//
+// SD Host Controller MMIO Register Offset
+//
+#define DW_MMC_CTRL                   0x000
+#define DW_MMC_PWREN                  0x004
+#define DW_MMC_CLKDIV                 0x008
+#define DW_MMC_CLKSRC                 0x00c
+#define DW_MMC_CLKENA                 0x010
+#define DW_MMC_TMOUT                  0x014
+#define DW_MMC_CTYPE                  0x018
+#define DW_MMC_BLKSIZ                 0x01c
+#define DW_MMC_BYTCNT                 0x020
+#define DW_MMC_INTMASK                0x024
+#define DW_MMC_CMDARG                 0x028
+#define DW_MMC_CMD                    0x02c
+#define DW_MMC_RESP0                  0x030
+#define DW_MMC_RESP1                  0x034
+#define DW_MMC_RESP2                  0x038
+#define DW_MMC_RESP3                  0x03c
+#define DW_MMC_RINTSTS                0x044
+#define DW_MMC_STATUS                 0x048
+#define DW_MMC_FIFOTH                 0x04c
+#define DW_MMC_GPIO                   0x058
+#define DW_MMC_DEBNCE                 0x064
+#define DW_MMC_USRID                  0x068
+#define DW_MMC_VERID                  0x06c
+#define DW_MMC_HCON                   0x070
+#define DW_MMC_UHSREG                 0x074
+#define DW_MMC_BMOD                   0x080
+#define DW_MMC_DBADDR                 0x088
+#define DW_MMC_IDSTS                  0x08c
+#define DW_MMC_IDINTEN                0x090
+#define DW_MMC_DSCADDR                0x094
+#define DW_MMC_BUFADDR                0x098
+#define DW_MMC_CARDTHRCTL             0x100
+#define DW_MMC_UHSREG_EXT             0x108
+#define DW_MMC_ENABLE_SHIFT           0x110
+#define DW_MMC_FIFO_START             0x200
+
+#define GET_IDSTS_DMAC_FSM(x)                   (((x) >> 13) & 0xf)
+#define IDSTS_FSM_DMA_IDLE                      0
+#define IDSTS_FSM_DMA_SUSPEND                   1
+#define IDSTS_FSM_DESC_RD                       2
+#define IDSTS_FSM_DESC_CHK                      3
+#define IDSTS_FSM_DMA_RD_REQ_WAIT               4
+#define IDSTS_FSM_DMA_WR_REQ_WAIT               5
+#define IDSTS_FSM_DMA_RD                        6
+#define IDSTS_FSM_DMA_WR                        7
+#define IDSTS_FSM_DESC_CLOSE                    8
+#define IDSTS_FSM_MASK                          0xf
+
+#define CMD_UPDATE_CLK                          0x80202000
+#define CMD_START_BIT                           (1 << 31)
+
+#define MMC_8BIT_MODE                           (1 << 16)
+#define MMC_4BIT_MODE                           (1 << 0)
+#define MMC_1BIT_MODE                           0
+
+#define DW_MMC_BLOCK_SIZE                       512
+
+#define CMD_INDEX_MASK                          0x3F
+#define BIT_CMD_RESPONSE_EXPECT                 (1 << 6)
+#define BIT_CMD_LONG_RESPONSE                   (1 << 7)
+#define BIT_CMD_CHECK_RESPONSE_CRC              (1 << 8)
+#define BIT_CMD_DATA_EXPECTED                   (1 << 9)
+#define BIT_CMD_READ                            (0 << 10)
+#define BIT_CMD_WRITE                           (1 << 10)
+#define BIT_CMD_BLOCK_TRANSFER                  (0 << 11)
+#define BIT_CMD_STREAM_TRANSFER                 (1 << 11)
+#define BIT_CMD_SEND_AUTO_STOP                  (1 << 12)
+#define BIT_CMD_WAIT_PRVDATA_COMPLETE           (1 << 13)
+#define BIT_CMD_STOP_ABORT_CMD                  (1 << 14)
+#define BIT_CMD_SEND_INIT                       (1 << 15)
+#define BIT_CMD_UPDATE_CLOCK_ONLY               (1 << 21)
+#define BIT_CMD_READ_CEATA_DEVICE               (1 << 22)
+#define BIT_CMD_CCS_EXPECTED                    (1 << 23)
+#define BIT_CMD_ENABLE_BOOT                     (1 << 24)
+#define BIT_CMD_EXPECT_BOOT_ACK                 (1 << 25)
+#define BIT_CMD_DISABLE_BOOT                    (1 << 26)
+#define BIT_CMD_MANDATORY_BOOT                  (0 << 27)
+#define BIT_CMD_ALTERNATE_BOOT                  (1 << 27)
+#define BIT_CMD_VOLT_SWITCH                     (1 << 28)
+#define BIT_CMD_USE_HOLD_REG                    (1 << 29)
+#define BIT_CMD_START                           (1 << 31)
+
+#define CMD_INDEX(x)                            ((x) & CMD_INDEX_MASK)
+
+#define DW_MMC_INT_EBE                          (1 << 15)       /* End-bit Err */
+#define DW_MMC_INT_SBE                          (1 << 13)       /* Start-bit  Err */
+#define DW_MMC_INT_HLE                          (1 << 12)       /* Hardware-lock Err */
+#define DW_MMC_INT_FRUN                         (1 << 11)       /* FIFO UN/OV RUN */
+#define DW_MMC_INT_DRT                          (1 << 9)        /* Data timeout */
+#define DW_MMC_INT_RTO                          (1 << 8)        /* Response timeout */
+#define DW_MMC_INT_DCRC                         (1 << 7)        /* Data CRC err */
+#define DW_MMC_INT_RCRC                         (1 << 6)        /* Response CRC err */
+#define DW_MMC_INT_RXDR                         (1 << 5)        /* Receive FIFO data request */
+#define DW_MMC_INT_TXDR                         (1 << 4)        /* Transmit FIFO data request */
+#define DW_MMC_INT_DTO                          (1 << 3)        /* Data trans over */
+#define DW_MMC_INT_CMD_DONE                     (1 << 2)        /* Command done */
+#define DW_MMC_INT_RE                           (1 << 1)        /* Response error */
+
+#define DW_MMC_IDMAC_DES0_DIC                   (1 << 1)
+#define DW_MMC_IDMAC_DES0_LD                    (1 << 2)
+#define DW_MMC_IDMAC_DES0_FS                    (1 << 3)
+#define DW_MMC_IDMAC_DES0_CH                    (1 << 4)
+#define DW_MMC_IDMAC_DES0_ER                    (1 << 5)
+#define DW_MMC_IDMAC_DES0_CES                   (1 << 30)
+#define DW_MMC_IDMAC_DES0_OWN                   (1 << 31)
+#define DW_MMC_IDMAC_DES1_BS1(x)                ((x) & 0x1fff)
+#define DW_MMC_IDMAC_DES2_BS2(x)                (((x) & 0x1fff) << 13)
+#define DW_MMC_IDMAC_SWRESET                    (1 << 0)
+#define DW_MMC_IDMAC_FB                         (1 << 1)
+#define DW_MMC_IDMAC_ENABLE                     (1 << 7)
+
+#define DW_MMC_CTRL_RESET                       (1 << 0)
+#define DW_MMC_CTRL_FIFO_RESET                  (1 << 1)
+#define DW_MMC_CTRL_DMA_RESET                   (1 << 2)
+#define DW_MMC_CTRL_INT_EN                      (1 << 4)
+#define DW_MMC_CTRL_DMA_EN                      (1 << 5)
+#define DW_MMC_CTRL_IDMAC_EN                    (1 << 25)
+#define DW_MMC_CTRL_RESET_ALL                   (DW_MMC_CTRL_RESET | DW_MMC_CTRL_FIFO_RESET | DW_MMC_CTRL_DMA_RESET)
+
+#define DW_MMC_STS_DATA_BUSY                    (1 << 9)
+#define DW_MMC_STS_FIFO_COUNT(x)                (((x) & 0x1fff) << 17)   /* Number of filled locations in FIFO */
+#define GET_STS_FIFO_COUNT(x)                   (((x) >> 17) & 0x1fff)
+
+#define DW_MMC_BMOD_SWR                         (1 << 0)         /* Software Reset */
+#define DW_MMC_BMOD_FB                          (1 << 1)         /* Fix Burst */
+#define DW_MMC_BMOD_DE                          (1 << 7)         /* IDMAC Enable */
+
+#define DW_MMC_IDSTS_TI                         (1 << 0)         /* Transmit Interrupt */
+#define DW_MMC_IDSTS_RI                         (1 << 1)         /* Receive Interrupt */
+
+#define DW_MMC_FIFO_TWMARK(x)                   ((x) & 0xfff)
+#define DW_MMC_FIFO_RWMARK(x)                   (((x) & 0x1ff) << 16)
+#define DW_MMC_DMA_BURST_SIZE(x)                (((x) & 0x7) << 28)
+
+#define DW_MMC_CARD_RD_THR(x)                   (((x) & 0xfff) << 16)
+#define DW_MMC_CARD_RD_THR_EN                   (1 << 0)
+
+#define UHS_DDR_MODE                            (1 << 16)
+
+#define GENCLK_DIV                              7
+
+#define DW_MMC_GPIO_CLK_DIV(x)                  (((x) & 0xf) << 8)
+#define DW_MMC_GPIO_USE_SAMPLE_DLY(x)           (((x) & 1) << 13)
+#define DW_MMC_GPIO_CLK_ENABLE                  BIT16
+
+#define UHSEXT_SAMPLE_PHASE(x)                  (((x) & 0x1f) << 16)
+#define UHSEXT_SAMPLE_DRVPHASE(x)               (((x) & 0x1f) << 21)
+#define UHSEXT_SAMPLE_DLY(x)                    (((x) & 0x1f) << 26)
+
+#define DWMMC_DMA_BUF_SIZE                      (512 * 8)
+#define DWMMC_FIFO_THRESHOLD                    16
+
+#define DWMMC_INIT_CLOCK_FREQ                   400              /* KHz */
+
+//
+// The transfer modes supported by SD Host Controller
+// Simplified Spec 3.0 Table 1-2
+//
+typedef enum {
+  SdMmcNoData,
+  SdMmcPioMode,
+  SdMmcSdmaMode,
+  SdMmcAdmaMode
+} DW_MMC_HC_TRANSFER_MODE;
+
+//
+// The maximum data length of each descriptor line
+//
+#define ADMA_MAX_DATA_PER_LINE     0x10000
+
+typedef struct {
+  UINT32   Des0;
+  UINT32   Des1;
+  UINT32   Des2;
+  UINT32   Des3;
+} DW_MMC_HC_DMA_DESC_LINE;
+
+#define SD_MMC_SDMA_BOUNDARY          512 * 1024
+#define SD_MMC_SDMA_ROUND_UP(x, n)    (((x) + n) & ~(n - 1))
+
+typedef struct {
+  UINT8    FirstBar:3;        // bit 0:2
+  UINT8    Reserved:1;        // bit 3
+  UINT8    SlotNum:3;         // bit 4:6
+  UINT8    Reserved1:1;       // bit 7
+} DW_MMC_HC_SLOT_INFO;
+
+/**
+  Dump the content of SD/MMC host controller's Capability Register.
+
+  @param[in]  Slot            The slot number of the SD card to send the command to.
+  @param[in]  Capability      The buffer to store the capability data.
+
+**/
+VOID
+DumpCapabilityReg (
+  IN UINT8                Slot,
+  IN DW_MMC_HC_SLOT_CAP   *Capability
+  );
+
+#if 0
+/**
+  Read SlotInfo register from SD/MMC host controller pci config space.
+
+  @param[in]  PciIo        The PCI IO protocol instance.
+  @param[out] FirstBar     The buffer to store the first BAR value.
+  @param[out] SlotNum      The buffer to store the supported slot number.
+
+  @retval EFI_SUCCESS      The operation succeeds.
+  @retval Others           The operation fails.
+
+**/
+EFI_STATUS
+EFIAPI
+DwMmcHcGetSlotInfo (
+  IN     EFI_PCI_IO_PROTOCOL   *PciIo,
+     OUT UINT8                 *FirstBar,
+     OUT UINT8                 *SlotNum
+  );
+#endif
+
+#ifdef DWMMC_PCI
+/**
+  Read/Write specified SD/MMC host controller mmio register.
+
+  @param[in]      PciIo        The PCI IO protocol instance.
+  @param[in]      BarIndex     The BAR index of the standard PCI Configuration
+                               header to use as the base address for the memory
+                               operation to perform.
+  @param[in]      Offset       The offset within the selected BAR to start the
+                               memory operation.
+  @param[in]      Read         A boolean to indicate it's read or write operation.
+  @param[in]      Count        The width of the mmio register in bytes.
+                               Must be 1, 2 , 4 or 8 bytes.
+  @param[in, out] Data         For read operations, the destination buffer to store
+                               the results. For write operations, the source buffer
+                               to write data from. The caller is responsible for
+                               having ownership of the data buffer and ensuring its
+                               size not less than Count bytes.
+
+  @retval EFI_INVALID_PARAMETER The PciIo or Data is NULL or the Count is not valid.
+  @retval EFI_SUCCESS           The read/write operation succeeds.
+  @retval Others                The read/write operation fails.
+
+**/
+EFI_STATUS
+EFIAPI
+DwMmcHcRwMmio (
+  IN     EFI_PCI_IO_PROTOCOL   *PciIo,
+  IN     UINT8                 BarIndex,
+  IN     UINT32                Offset,
+  IN     BOOLEAN               Read,
+  IN     UINT8                 Count,
+  IN OUT VOID                  *Data
+  );
+#else
+/**
+  Read/Write specified SD/MMC host controller mmio register.
+
+  @param[in]      DevIo        The DEVICE IO protocol instance.
+  @param[in]      Offset       The offset within the selected BAR to start the
+                               memory operation.
+  @param[in]      Read         A boolean to indicate it's read or write operation.
+  @param[in]      Count        The width of the mmio register in bytes.
+                               Must be 1, 2 , 4 or 8 bytes.
+  @param[in, out] Data         For read operations, the destination buffer to store
+                               the results. For write operations, the source buffer
+                               to write data from. The caller is responsible for
+                               having ownership of the data buffer and ensuring its
+                               size not less than Count bytes.
+
+  @retval EFI_INVALID_PARAMETER The PciIo or Data is NULL or the Count is not valid.
+  @retval EFI_SUCCESS           The read/write operation succeeds.
+  @retval Others                The read/write operation fails.
+
+**/
+EFI_STATUS
+EFIAPI
+DwMmcHcRwMmio (
+  IN     EFI_DEVICE_IO_PROTOCOL   *DevIo,
+  IN     UINT32                   Offset,
+  IN     BOOLEAN                  Read,
+  IN     UINT8                    Count,
+  IN OUT VOID                     *Data
+  );
+#endif
+
+#ifdef DWMMC_PCI
+/**
+  Do OR operation with the value of the specified SD/MMC host controller mmio register.
+
+  @param[in] PciIo             The PCI IO protocol instance.
+  @param[in] BarIndex          The BAR index of the standard PCI Configuration
+                               header to use as the base address for the memory
+                               operation to perform.
+  @param[in] Offset            The offset within the selected BAR to start the
+                               memory operation.
+  @param[in] Count             The width of the mmio register in bytes.
+                               Must be 1, 2 , 4 or 8 bytes.
+  @param[in] OrData            The pointer to the data used to do OR operation.
+                               The caller is responsible for having ownership of
+                               the data buffer and ensuring its size not less than
+                               Count bytes.
+
+  @retval EFI_INVALID_PARAMETER The PciIo or OrData is NULL or the Count is not valid.
+  @retval EFI_SUCCESS           The OR operation succeeds.
+  @retval Others                The OR operation fails.
+
+**/
+EFI_STATUS
+EFIAPI
+DwMmcHcOrMmio (
+  IN  EFI_PCI_IO_PROTOCOL      *PciIo,
+  IN  UINT8                    BarIndex,
+  IN  UINT32                   Offset,
+  IN  UINT8                    Count,
+  IN  VOID                     *OrData
+  );
+#else
+/**
+  Do OR operation with the value of the specified SD/MMC host controller mmio register.
+
+  @param[in] DevIo             The DEVICE IO protocol instance.
+  @param[in] BarIndex          The BAR index of the standard PCI Configuration
+                               header to use as the base address for the memory
+                               operation to perform.
+  @param[in] Offset            The offset within the selected BAR to start the
+                               memory operation.
+  @param[in] Count             The width of the mmio register in bytes.
+                               Must be 1, 2 , 4 or 8 bytes.
+  @param[in] OrData            The pointer to the data used to do OR operation.
+                               The caller is responsible for having ownership of
+                               the data buffer and ensuring its size not less than
+                               Count bytes.
+
+  @retval EFI_INVALID_PARAMETER The PciIo or OrData is NULL or the Count is not valid.
+  @retval EFI_SUCCESS           The OR operation succeeds.
+  @retval Others                The OR operation fails.
+
+**/
+EFI_STATUS
+EFIAPI
+DwMmcHcOrMmio (
+  IN  EFI_DEVICE_IO_PROTOCOL   *DevIo,
+  IN  UINT32                   Offset,
+  IN  UINT8                    Count,
+  IN  VOID                     *OrData
+  );
+#endif
+
+#ifdef DWMMC_PCI
+/**
+  Do AND operation with the value of the specified SD/MMC host controller mmio register.
+
+  @param[in] PciIo             The PCI IO protocol instance.
+  @param[in] BarIndex          The BAR index of the standard PCI Configuration
+                               header to use as the base address for the memory
+                               operation to perform.
+  @param[in] Offset            The offset within the selected BAR to start the
+                               memory operation.
+  @param[in] Count             The width of the mmio register in bytes.
+                               Must be 1, 2 , 4 or 8 bytes.
+  @param[in] AndData           The pointer to the data used to do AND operation.
+                               The caller is responsible for having ownership of
+                               the data buffer and ensuring its size not less than
+                               Count bytes.
+
+  @retval EFI_INVALID_PARAMETER The PciIo or AndData is NULL or the Count is not valid.
+  @retval EFI_SUCCESS           The AND operation succeeds.
+  @retval Others                The AND operation fails.
+
+**/
+EFI_STATUS
+EFIAPI
+DwMmcHcAndMmio (
+  IN  EFI_PCI_IO_PROTOCOL      *PciIo,
+  IN  UINT8                    BarIndex,
+  IN  UINT32                   Offset,
+  IN  UINT8                    Count,
+  IN  VOID                     *AndData
+  );
+#else
+/**
+  Do AND operation with the value of the specified SD/MMC host controller mmio register.
+
+  @param[in] DevIo             The DEVICE IO protocol instance.
+  @param[in] Offset            The offset within the selected BAR to start the
+                               memory operation.
+  @param[in] Count             The width of the mmio register in bytes.
+                               Must be 1, 2 , 4 or 8 bytes.
+  @param[in] AndData           The pointer to the data used to do AND operation.
+                               The caller is responsible for having ownership of
+                               the data buffer and ensuring its size not less than
+                               Count bytes.
+
+  @retval EFI_INVALID_PARAMETER The PciIo or AndData is NULL or the Count is not valid.
+  @retval EFI_SUCCESS           The AND operation succeeds.
+  @retval Others                The AND operation fails.
+
+**/
+EFI_STATUS
+EFIAPI
+DwMmcHcAndMmio (
+  IN  EFI_DEVICE_IO_PROTOCOL   *DevIo,
+  IN  UINT32                   Offset,
+  IN  UINT8                    Count,
+  IN  VOID                     *AndData
+  );
+#endif
+
+#ifdef DWMMC_PCI
+/**
+  Wait for the value of the specified MMIO register set to the test value.
+
+  @param[in]  PciIo         The PCI IO protocol instance.
+  @param[in]  BarIndex      The BAR index of the standard PCI Configuration
+                            header to use as the base address for the memory
+                            operation to perform.
+  @param[in]  Offset        The offset within the selected BAR to start the
+                            memory operation.
+  @param[in]  Count         The width of the mmio register in bytes.
+                            Must be 1, 2, 4 or 8 bytes.
+  @param[in]  MaskValue     The mask value of memory.
+  @param[in]  TestValue     The test value of memory.
+  @param[in]  Timeout       The time out value for wait memory set, uses 1
+                            microsecond as a unit.
+
+  @retval EFI_TIMEOUT       The MMIO register hasn't expected value in timeout
+                            range.
+  @retval EFI_SUCCESS       The MMIO register has expected value.
+  @retval Others            The MMIO operation fails.
+
+**/
+EFI_STATUS
+EFIAPI
+DwMmcHcWaitMmioSet (
+  IN  EFI_PCI_IO_PROTOCOL       *PciIo,
+  IN  UINT8                     BarIndex,
+  IN  UINT32                    Offset,
+  IN  UINT8                     Count,
+  IN  UINT64                    MaskValue,
+  IN  UINT64                    TestValue,
+  IN  UINT64                    Timeout
+  );
+#else
+/**
+  Wait for the value of the specified MMIO register set to the test value.
+
+  @param[in]  DevIo         The DEVICE IO protocol instance.
+  @param[in]  Offset        The offset within the selected BAR to start the
+                            memory operation.
+  @param[in]  Count         The width of the mmio register in bytes.
+                            Must be 1, 2, 4 or 8 bytes.
+  @param[in]  MaskValue     The mask value of memory.
+  @param[in]  TestValue     The test value of memory.
+  @param[in]  Timeout       The time out value for wait memory set, uses 1
+                            microsecond as a unit.
+
+  @retval EFI_TIMEOUT       The MMIO register hasn't expected value in timeout
+                            range.
+  @retval EFI_SUCCESS       The MMIO register has expected value.
+  @retval Others            The MMIO operation fails.
+
+**/
+EFI_STATUS
+EFIAPI
+DwMmcHcWaitMmioSet (
+  IN  EFI_DEVICE_IO_PROTOCOL    *DevIo,
+  IN  UINT32                    Offset,
+  IN  UINT8                     Count,
+  IN  UINT64                    MaskValue,
+  IN  UINT64                    TestValue,
+  IN  UINT64                    Timeout
+  );
+#endif
+
+#ifdef DWMMC_PCI
+/**
+  Software reset the specified SD/MMC host controller.
+
+  @param[in] PciIo          The PCI IO protocol instance.
+  @param[in] Slot           The slot number of the SD card to send the command to.
+
+  @retval EFI_SUCCESS       The software reset executes successfully.
+  @retval Others            The software reset fails.
+
+**/
+EFI_STATUS
+DwMmcHcReset (
+  IN EFI_PCI_IO_PROTOCOL    *PciIo,
+  IN UINT8                  Slot,
+  IN DW_MMC_HC_SLOT_CAP     Capability
+  );
+#else
+/**
+  Software reset the specified SD/MMC host controller.
+
+  @param[in] DevIo          The DEVICE IO protocol instance.
+
+  @retval EFI_SUCCESS       The software reset executes successfully.
+  @retval Others            The software reset fails.
+
+**/
+EFI_STATUS
+DwMmcHcReset (
+  IN EFI_DEVICE_IO_PROTOCOL *DevIo,
+  IN DW_MMC_HC_SLOT_CAP     Capability
+  );
+#endif
+
+#ifdef DWMMC_PCI
+/**
+  Set all interrupt status bits in Normal and Error Interrupt Status Enable
+  register.
+
+  @param[in] PciIo          The PCI IO protocol instance.
+  @param[in] Slot           The slot number of the SD card to send the command to.
+
+  @retval EFI_SUCCESS       The operation executes successfully.
+  @retval Others            The operation fails.
+
+**/
+EFI_STATUS
+DwMmcHcEnableInterrupt (
+  IN EFI_PCI_IO_PROTOCOL    *PciIo,
+  IN UINT8                  Slot
+  );
+#else
+/**
+  Set all interrupt status bits in Normal and Error Interrupt Status Enable
+  register.
+
+  @param[in] DevIo          The DEVICE IO protocol instance.
+  @param[in] Slot           The slot number of the SD card to send the command to.
+
+  @retval EFI_SUCCESS       The operation executes successfully.
+  @retval Others            The operation fails.
+
+**/
+EFI_STATUS
+DwMmcHcEnableInterrupt (
+  IN EFI_DEVICE_IO_PROTOCOL *DevIo
+  );
+#endif
+
+#ifdef DWMMC_PCI
+/**
+  Get the capability data from the specified slot.
+
+  @param[in]  PciIo           The PCI IO protocol instance.
+  @param[in]  Slot            The slot number of the SD card to send the command to.
+  @param[out] Capability      The buffer to store the capability data.
+
+  @retval EFI_SUCCESS         The operation executes successfully.
+  @retval Others              The operation fails.
+
+**/
+EFI_STATUS
+DwMmcHcGetCapability (
+  IN     EFI_PCI_IO_PROTOCOL  *PciIo,
+  IN     EFI_HANDLE           Controller,
+  IN     UINT8                Slot,
+     OUT DW_MMC_HC_SLOT_CAP   *Capability
+  );
+#else
+/**
+  Get the capability data from the specified slot.
+
+  @param[in]  DevIo           The DEVICE IO protocol instance.
+  @param[in]  Slot            The slot number of the SD card to send the command to.
+  @param[out] Capability      The buffer to store the capability data.
+
+  @retval EFI_SUCCESS         The operation executes successfully.
+  @retval Others              The operation fails.
+
+**/
+EFI_STATUS
+DwMmcHcGetCapability (
+  IN     EFI_DEVICE_IO_PROTOCOL  *DevIo,
+  IN     EFI_HANDLE              Controller,
+  IN     UINT8                   Slot,
+     OUT DW_MMC_HC_SLOT_CAP      *Capability
+  );
+#endif
+
+#if 0
+/**
+  Get the maximum current capability data from the specified slot.
+
+  @param[in]  PciIo           The PCI IO protocol instance.
+  @param[in]  Slot            The slot number of the SD card to send the command to.
+  @param[out] MaxCurrent      The buffer to store the maximum current capability data.
+
+  @retval EFI_SUCCESS         The operation executes successfully.
+  @retval Others              The operation fails.
+
+**/
+EFI_STATUS
+DwMmcHcGetMaxCurrent (
+  IN     EFI_PCI_IO_PROTOCOL  *PciIo,
+  IN     UINT8                Slot,
+     OUT UINT64               *MaxCurrent
+  );
+#endif
+
+#ifdef DWMMC_PCI
+/**
+  Detect whether there is a SD/MMC card attached at the specified SD/MMC host controller
+  slot.
+
+  Refer to SD Host Controller Simplified spec 3.0 Section 3.1 for details.
+
+  @param[in]  PciIo         The PCI IO protocol instance.
+  @param[in]  Slot          The slot number of the SD card to send the command to.
+  @param[out] MediaPresent  The pointer to the media present boolean value.
+
+  @retval EFI_SUCCESS       There is no media change happened.
+  @retval EFI_MEDIA_CHANGED There is media change happened.
+  @retval Others            The detection fails.
+
+**/
+EFI_STATUS
+DwMmcHcCardDetect (
+  IN     EFI_PCI_IO_PROTOCOL  *PciIo,
+  IN     EFI_HANDLE           Controller,
+  IN     UINT8                Slot,
+     OUT BOOLEAN              *MediaPresent
+  );
+#else
+/**
+  Detect whether there is a SD/MMC card attached at the specified SD/MMC host controller
+  slot.
+
+  Refer to SD Host Controller Simplified spec 3.0 Section 3.1 for details.
+
+  @param[in]  DevIo         The DEVICE IO protocol instance.
+  @param[in]  Slot          The slot number of the SD card to send the command to.
+  @param[out] MediaPresent  The pointer to the media present boolean value.
+
+  @retval EFI_SUCCESS       There is no media change happened.
+  @retval EFI_MEDIA_CHANGED There is media change happened.
+  @retval Others            The detection fails.
+
+**/
+EFI_STATUS
+DwMmcHcCardDetect (
+  IN     EFI_DEVICE_IO_PROTOCOL  *DevIo,
+  IN     EFI_HANDLE              Controller,
+  IN     UINT8                   Slot,
+     OUT BOOLEAN                 *MediaPresent
+  );
+#endif
+
+#ifdef DWMMC_PCI
+/**
+  Stop SD/MMC card clock.
+
+  Refer to SD Host Controller Simplified spec 3.0 Section 3.2.2 for details.
+
+  @param[in] PciIo          The PCI IO protocol instance.
+  @param[in] Slot           The slot number of the SD card to send the command to.
+
+  @retval EFI_SUCCESS       Succeed to stop SD/MMC clock.
+  @retval Others            Fail to stop SD/MMC clock.
+
+**/
+EFI_STATUS
+DwMmcHcStopClock (
+  IN EFI_PCI_IO_PROTOCOL    *PciIo,
+  IN UINT8                  Slot
+  );
+
+/**
+  SD/MMC card clock supply.
+
+  Refer to SD Host Controller Simplified spec 3.0 Section 3.2.1 for details.
+
+  @param[in] PciIo          The PCI IO protocol instance.
+  @param[in] Slot           The slot number of the SD card to send the command to.
+  @param[in] ClockFreq      The max clock frequency to be set. The unit is KHz.
+  @param[in] Capability     The capability of the slot.
+
+  @retval EFI_SUCCESS       The clock is supplied successfully.
+  @retval Others            The clock isn't supplied successfully.
+
+**/
+EFI_STATUS
+DwMmcHcClockSupply (
+  IN EFI_PCI_IO_PROTOCOL    *PciIo,
+  IN UINT8                  Slot,
+  IN UINT64                 ClockFreq,
+  IN DW_MMC_HC_SLOT_CAP     Capability
+  );
+#else
+/**
+  Stop SD/MMC card clock.
+
+  Refer to SD Host Controller Simplified spec 3.0 Section 3.2.2 for details.
+
+  @param[in] DevIo          The DEVICE IO protocol instance.
+
+  @retval EFI_SUCCESS       Succeed to stop SD/MMC clock.
+  @retval Others            Fail to stop SD/MMC clock.
+
+**/
+EFI_STATUS
+DwMmcHcStopClock (
+  IN EFI_DEVICE_IO_PROTOCOL *DevIo
+  );
+
+/**
+  SD/MMC card clock supply.
+
+  Refer to SD Host Controller Simplified spec 3.0 Section 3.2.1 for details.
+
+  @param[in] DevIo          The DEVICE IO protocol instance.
+  @param[in] ClockFreq      The max clock frequency to be set. The unit is KHz.
+  @param[in] Capability     The capability of the slot.
+
+  @retval EFI_SUCCESS       The clock is supplied successfully.
+  @retval Others            The clock isn't supplied successfully.
+
+**/
+EFI_STATUS
+DwMmcHcClockSupply (
+  IN EFI_DEVICE_IO_PROTOCOL *DevIo,
+  IN UINT64                 ClockFreq,
+  IN DW_MMC_HC_SLOT_CAP     Capability
+  );
+#endif
+
+#if 0
+/**
+  SD/MMC bus power control.
+
+  Refer to SD Host Controller Simplified spec 3.0 Section 3.3 for details.
+
+  @param[in] PciIo          The PCI IO protocol instance.
+  @param[in] Slot           The slot number of the SD card to send the command to.
+  @param[in] PowerCtrl      The value setting to the power control register.
+
+  @retval TRUE              There is a SD/MMC card attached.
+  @retval FALSE             There is no a SD/MMC card attached.
+
+**/
+EFI_STATUS
+DwMmcHcPowerControl (
+  IN EFI_PCI_IO_PROTOCOL    *PciIo,
+  IN UINT8                  Slot,
+  IN UINT8                  PowerCtrl
+  );
+#endif
+
+#ifdef DWMMC_PCI
+/**
+  Set the SD/MMC bus width.
+
+  Refer to SD Host Controller Simplified spec 3.0 Section 3.4 for details.
+
+  @param[in] PciIo          The PCI IO protocol instance.
+  @param[in] Slot           The slot number of the SD card to send the command to.
+  @param[in] BusWidth       The bus width used by the SD/MMC device, it must be 1, 4 or 8.
+
+  @retval EFI_SUCCESS       The bus width is set successfully.
+  @retval Others            The bus width isn't set successfully.
+
+**/
+EFI_STATUS
+DwMmcHcSetBusWidth (
+  IN EFI_PCI_IO_PROTOCOL    *PciIo,
+  IN UINT8                  Slot,
+  IN BOOLEAN                IsDdr,
+  IN UINT16                 BusWidth
+  );
+#else
+/**
+  Set the SD/MMC bus width.
+
+  Refer to SD Host Controller Simplified spec 3.0 Section 3.4 for details.
+
+  @param[in] DevIo          The DEVICE IO protocol instance.
+  @param[in] BusWidth       The bus width used by the SD/MMC device, it must be 1, 4 or 8.
+
+  @retval EFI_SUCCESS       The bus width is set successfully.
+  @retval Others            The bus width isn't set successfully.
+
+**/
+EFI_STATUS
+DwMmcHcSetBusWidth (
+  IN EFI_DEVICE_IO_PROTOCOL *DevIo,
+  IN BOOLEAN                IsDdr,
+  IN UINT16                 BusWidth
+  );
+#endif
+
+#ifdef DWMMC_PCI
+/**
+  Supply SD/MMC card with lowest clock frequency at initialization.
+
+  @param[in] PciIo          The PCI IO protocol instance.
+  @param[in] Slot           The slot number of the SD card to send the command to.
+  @param[in] Capability     The capability of the slot.
+
+  @retval EFI_SUCCESS       The clock is supplied successfully.
+  @retval Others            The clock isn't supplied successfully.
+
+**/
+EFI_STATUS
+DwMmcHcInitClockFreq (
+  IN EFI_PCI_IO_PROTOCOL    *PciIo,
+  IN UINT8                  Slot,
+  IN DW_MMC_HC_SLOT_CAP     Capability
+  );
+#else
+/**
+  Supply SD/MMC card with lowest clock frequency at initialization.
+
+  @param[in] DevIo          The DEVICE IO protocol instance.
+  @param[in] Capability     The capability of the slot.
+
+  @retval EFI_SUCCESS       The clock is supplied successfully.
+  @retval Others            The clock isn't supplied successfully.
+
+**/
+EFI_STATUS
+DwMmcHcInitClockFreq (
+  IN EFI_DEVICE_IO_PROTOCOL *PciIo,
+  IN DW_MMC_HC_SLOT_CAP     Capability
+  );
+#endif
+
+#ifdef DWMMC_PCI
+/**
+  Supply SD/MMC card with maximum voltage at initialization.
+
+  Refer to SD Host Controller Simplified spec 3.0 Section 3.3 for details.
+
+  @param[in] PciIo          The PCI IO protocol instance.
+  @param[in] Slot           The slot number of the SD card to send the command to.
+  @param[in] Capability     The capability of the slot.
+
+  @retval EFI_SUCCESS       The voltage is supplied successfully.
+  @retval Others            The voltage isn't supplied successfully.
+
+**/
+EFI_STATUS
+DwMmcHcInitPowerVoltage (
+  IN EFI_PCI_IO_PROTOCOL    *PciIo,
+  IN UINT8                  Slot,
+  IN DW_MMC_HC_SLOT_CAP     Capability
+  );
+#else
+/**
+  Supply SD/MMC card with maximum voltage at initialization.
+
+  Refer to SD Host Controller Simplified spec 3.0 Section 3.3 for details.
+
+  @param[in] DevIo          The DEVICE IO protocol instance.
+  @param[in] Capability     The capability of the slot.
+
+  @retval EFI_SUCCESS       The voltage is supplied successfully.
+  @retval Others            The voltage isn't supplied successfully.
+
+**/
+EFI_STATUS
+DwMmcHcInitPowerVoltage (
+  IN EFI_DEVICE_IO_PROTOCOL *PciIo,
+  IN DW_MMC_HC_SLOT_CAP     Capability
+  );
+#endif
+
+#ifdef DWMMC_PCI
+/**
+  Initialize the Timeout Control register with most conservative value at initialization.
+
+  Refer to SD Host Controller Simplified spec 3.0 Section 2.2.15 for details.
+
+  @param[in] PciIo          The PCI IO protocol instance.
+  @param[in] Slot           The slot number of the SD card to send the command to.
+
+  @retval EFI_SUCCESS       The timeout control register is configured successfully.
+  @retval Others            The timeout control register isn't configured successfully.
+
+**/
+EFI_STATUS
+DwMmcHcInitTimeoutCtrl (
+  IN EFI_PCI_IO_PROTOCOL    *PciIo,
+  IN UINT8                  Slot
+  );
+#else
+/**
+  Initialize the Timeout Control register with most conservative value at initialization.
+
+  Refer to SD Host Controller Simplified spec 3.0 Section 2.2.15 for details.
+
+  @param[in] DevIo          The DEVICE IO protocol instance.
+  @param[in] Slot           The slot number of the SD card to send the command to.
+
+  @retval EFI_SUCCESS       The timeout control register is configured successfully.
+  @retval Others            The timeout control register isn't configured successfully.
+
+**/
+EFI_STATUS
+DwMmcHcInitTimeoutCtrl (
+  IN EFI_DEVICE_IO_PROTOCOL *DevIo
+  );
+#endif
+
+#ifdef DWMMC_PCI
+/**
+  Initial SD/MMC host controller with lowest clock frequency, max power and max timeout value
+  at initialization.
+
+  @param[in] PciIo          The PCI IO protocol instance.
+  @param[in] Slot           The slot number of the SD card to send the command to.
+  @param[in] Capability     The capability of the slot.
+
+  @retval EFI_SUCCESS       The host controller is initialized successfully.
+  @retval Others            The host controller isn't initialized successfully.
+
+**/
+EFI_STATUS
+DwMmcHcInitHost (
+  IN EFI_PCI_IO_PROTOCOL    *PciIo,
+  IN UINT8                  Slot,
+  IN DW_MMC_HC_SLOT_CAP     Capability
+  );
+#else
+/**
+  Initial SD/MMC host controller with lowest clock frequency, max power and
+  max timeout value at initialization.
+
+  @param[in] DevIo          The DEVICE IO protocol instance.
+  @param[in] Capability     The capability of the slot.
+
+  @retval EFI_SUCCESS       The host controller is initialized successfully.
+  @retval Others            The host controller isn't initialized successfully.
+
+**/
+EFI_STATUS
+DwMmcHcInitHost (
+  IN EFI_DEVICE_IO_PROTOCOL    *DevIo,
+  IN DW_MMC_HC_SLOT_CAP        Capability
+  );
+#endif
+
+#endif /* _DW_MMC_HCI_H_ */
diff --git a/EmbeddedPkg/Include/Protocol/PlatformDwMmc.h b/EmbeddedPkg/Include/Protocol/PlatformDwMmc.h
new file mode 100644
index 000000000000..54a44928a7e1
--- /dev/null
+++ b/EmbeddedPkg/Include/Protocol/PlatformDwMmc.h
@@ -0,0 +1,79 @@ 
+/** @file
+
+  Copyright (c) 2018, Linaro. All rights reserved.
+
+  This program and the accompanying materials are licensed and made available
+  under the terms and conditions of the BSD License which accompanies this
+  distribution.  The full text of the license may be found at
+  http://opensource.org/licenses/bsd-license.php
+
+  THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+  WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#ifndef __PLATFORM_DW_MMC_H__
+#define __PLATFORM_DW_MMC_H__
+
+typedef enum {
+  RemovableSlot,
+  EmbeddedSlot,
+  SharedBusSlot,
+  UnknownSlot
+} EFI_SD_MMC_SLOT_TYPE;
+
+typedef enum {
+  UnknownCardType,
+  SdCardType,
+  SdioCardType,
+  MmcCardType,
+  EmmcCardType
+} SD_MMC_CARD_TYPE;
+
+typedef struct {
+  UINT32        DefaultSpeed:1;    // bit 0
+  UINT32        HighSpeed:1;       // bit 1
+  UINT32        Sdr12:1;           // bit 2
+  UINT32        Sdr25:1;           // bit 3
+  UINT32        Sdr50:1;           // bit 4
+  UINT32        Sdr104:1;          // bit 5
+  UINT32        Ddr50:1;           // bit 6
+  UINT32        SysBus64:1;        // bit 7
+  UINT32        BusWidth:4;        // bit 11:8
+  UINT32        SlotType:2;        // bit 13:12
+  UINT32        CardType:3;        // bit 16:14
+  UINT32        Voltage18:1;       // bit 17
+  UINT32        Voltage30:1;       // bit 18
+  UINT32        Voltage33:1;       // bit 19
+  UINT32        BaseClkFreq;
+  EFI_HANDLE    Controller;
+} DW_MMC_HC_SLOT_CAP;
+
+//
+// Protocol interface structure
+//
+typedef struct _PLATFORM_DW_MMC_PROTOCOL       PLATFORM_DW_MMC_PROTOCOL;
+
+typedef
+EFI_STATUS
+(EFIAPI *PLATFORM_DW_MMC_GET_CAPABILITY) (
+  IN     EFI_HANDLE             Controller,
+  IN     UINT8                  Slot,
+     OUT DW_MMC_HC_SLOT_CAP     *Capability
+  );
+
+typedef
+BOOLEAN
+(EFIAPI *PLATFORM_DW_MMC_CARD_DETECT) (
+  IN EFI_HANDLE                 Controller,
+  IN UINT8                      Slot
+  );
+
+struct _PLATFORM_DW_MMC_PROTOCOL {
+  PLATFORM_DW_MMC_GET_CAPABILITY               GetCapability;
+  PLATFORM_DW_MMC_CARD_DETECT                  CardDetect;
+};
+
+extern EFI_GUID gPlatformDwMmcProtocolGuid;
+
+#endif /* __PLATFORM_DW_MMC_H__ */
diff --git a/EmbeddedPkg/Drivers/DwMmcHcDxe/ComponentName.c b/EmbeddedPkg/Drivers/DwMmcHcDxe/ComponentName.c
new file mode 100644
index 000000000000..1edade69d091
--- /dev/null
+++ b/EmbeddedPkg/Drivers/DwMmcHcDxe/ComponentName.c
@@ -0,0 +1,214 @@ 
+/** @file
+  UEFI Component Name(2) protocol implementation for Designware SD/MMC host
+  controller driver.
+
+  Copyright (c) 2015, Intel Corporation. All rights reserved.<BR>
+  Copyright (c) 2018, Linaro Ltd. All rights reserved.<BR>
+
+  This program and the accompanying materials are licensed and made available
+  under the terms and conditions of the BSD License which accompanies this
+  distribution.  The full text of the license may be found at
+  http://opensource.org/licenses/bsd-license.php
+
+  THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+  WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#include "DwMmcHcDxe.h"
+
+//
+// EFI Component Name Protocol
+//
+GLOBAL_REMOVE_IF_UNREFERENCED EFI_COMPONENT_NAME_PROTOCOL gDwMmcHcComponentName = {
+  DwMmcHcComponentNameGetDriverName,
+  DwMmcHcComponentNameGetControllerName,
+  "eng"
+};
+
+//
+// EFI Component Name 2 Protocol
+//
+GLOBAL_REMOVE_IF_UNREFERENCED EFI_COMPONENT_NAME2_PROTOCOL gDwMmcHcComponentName2 = {
+  (EFI_COMPONENT_NAME2_GET_DRIVER_NAME)     DwMmcHcComponentNameGetDriverName,
+  (EFI_COMPONENT_NAME2_GET_CONTROLLER_NAME) DwMmcHcComponentNameGetControllerName,
+  "en"
+};
+
+GLOBAL_REMOVE_IF_UNREFERENCED EFI_UNICODE_STRING_TABLE mDwMmcHcDriverNameTable[] = {
+  { "eng;en", L"Designware Sd/Mmc Host Controller Driver" },
+  { NULL , NULL }
+};
+
+GLOBAL_REMOVE_IF_UNREFERENCED EFI_UNICODE_STRING_TABLE mDwMmcHcControllerNameTable[] = {
+  { "eng;en", L"Designware Sd/Mmc Host Controller" },
+  { 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[in]              A pointer to the EFI_COMPONENT_NAME2_PROTOCOL or
+                                EFI_COMPONENT_NAME_PROTOCOL instance.
+
+  @param  Language[in]          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[out]       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
+DwMmcHcComponentNameGetDriverName (
+  IN  EFI_COMPONENT_NAME_PROTOCOL     *This,
+  IN  CHAR8                           *Language,
+  OUT CHAR16                          **DriverName
+  )
+{
+  return LookupUnicodeString2 (
+           Language,
+           This->SupportedLanguages,
+           mDwMmcHcDriverNameTable,
+           DriverName,
+           (BOOLEAN)(This == &gDwMmcHcComponentName)
+           );
+}
+
+/**
+  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[in]              A pointer to the EFI_COMPONENT_NAME2_PROTOCOL or
+                                EFI_COMPONENT_NAME_PROTOCOL instance.
+
+  @param  ControllerHandle[in]  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[in]       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[in]          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[out]   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
+DwMmcHcComponentNameGetControllerName (
+  IN  EFI_COMPONENT_NAME_PROTOCOL     *This,
+  IN  EFI_HANDLE                      ControllerHandle,
+  IN  EFI_HANDLE                      ChildHandle, OPTIONAL
+  IN  CHAR8                           *Language,
+  OUT CHAR16                          **ControllerName
+  )
+{
+  EFI_STATUS         Status;
+
+  if (Language == NULL || ControllerName == NULL) {
+    return EFI_INVALID_PARAMETER;
+  }
+
+  //
+  // This is a device driver, so ChildHandle must be NULL.
+  //
+  if (ChildHandle != NULL) {
+    return EFI_UNSUPPORTED;
+  }
+
+  //
+  // Make sure this driver is currently managing ControllerHandle
+  //
+  Status = EfiTestManagedDevice (
+             ControllerHandle,
+             gDwMmcHcDriverBinding.DriverBindingHandle,
+             &gEfiPciIoProtocolGuid
+             );
+  if (EFI_ERROR (Status)) {
+    return Status;
+  }
+
+  return LookupUnicodeString2 (
+           Language,
+           This->SupportedLanguages,
+           mDwMmcHcControllerNameTable,
+           ControllerName,
+           (BOOLEAN)(This == &gDwMmcHcComponentName)
+           );
+}
diff --git a/EmbeddedPkg/Drivers/DwMmcHcDxe/DwMmcHcDxe.c b/EmbeddedPkg/Drivers/DwMmcHcDxe/DwMmcHcDxe.c
new file mode 100644
index 000000000000..6e8e3fac8d75
--- /dev/null
+++ b/EmbeddedPkg/Drivers/DwMmcHcDxe/DwMmcHcDxe.c
@@ -0,0 +1,1295 @@ 
+/** @file
+  This driver is used to manage Designware SD/MMC host controller.
+
+  It would expose EFI_SD_MMC_PASS_THRU_PROTOCOL for upper layer use.
+
+  Copyright (c) 2015 - 2016, Intel Corporation. All rights reserved.<BR>
+  Copyright (C) 2016 Marvell International Ltd. All rigths reserved.<BR>
+  Copyright (C) 2018, Linaro Ltd. All rigths reserved.<BR>
+
+  This program and the accompanying materials
+  are licensed and made available under the terms and conditions of the BSD License
+  which accompanies this distribution.  The full text of the license may be found at
+  http://opensource.org/licenses/bsd-license.php
+
+  THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+  WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#include <Library/BaseMemoryLib.h>
+#include <Library/DebugLib.h>
+#include <Library/DevicePathLib.h>
+#include <Library/MemoryAllocationLib.h>
+#include <Library/UefiBootServicesTableLib.h>
+#include <Library/UefiDriverEntryPoint.h>
+
+#include <Protocol/DevicePath.h>
+#include <Protocol/PlatformDwMmc.h>
+
+#include "DwMmcHcDxe.h"
+
+//
+// Driver Global Variables
+//
+EFI_DRIVER_BINDING_PROTOCOL gDwMmcHcDriverBinding = {
+  DwMmcHcDriverBindingSupported,
+  DwMmcHcDriverBindingStart,
+  DwMmcHcDriverBindingStop,
+  0x10,
+  NULL,
+  NULL
+};
+
+//
+// Template for Designware SD/MMC host controller private data.
+//
+DW_MMC_HC_PRIVATE_DATA gDwMmcHcTemplate = {
+  DW_MMC_HC_PRIVATE_SIGNATURE,      // Signature
+  NULL,                             // ControllerHandle
+  NULL,                             // DevIo
+  {                                 // PassThru
+    sizeof (UINT32),
+    DwMmcPassThruPassThru,
+    DwMmcPassThruGetNextSlot,
+    DwMmcPassThruBuildDevicePath,
+    DwMmcPassThruGetSlotNumber,
+    DwMmcPassThruResetDevice
+  },
+  NULL,                             // PlatformDwMmc
+  0,                                // PreviousSlot
+  NULL,                             // TimerEvent
+  NULL,                             // ConnectEvent
+                                    // Queue
+  INITIALIZE_LIST_HEAD_VARIABLE (gDwMmcHcTemplate.Queue),
+  {                                 // Slot
+    {0, UnknownSlot, 0, 0, 0}
+  },
+  {                                 // Capability
+    {0}
+  },
+  {                                 // MaxCurrent
+    0
+  },
+  0                                 // ControllerVersion
+};
+
+SD_DEVICE_PATH    mSdDpTemplate = {
+  {
+    MESSAGING_DEVICE_PATH,
+    MSG_SD_DP,
+    {
+      (UINT8) (sizeof (SD_DEVICE_PATH)),
+      (UINT8) ((sizeof (SD_DEVICE_PATH)) >> 8)
+    }
+  },
+  0
+};
+
+EMMC_DEVICE_PATH    mEmmcDpTemplate = {
+  {
+    MESSAGING_DEVICE_PATH,
+    MSG_EMMC_DP,
+    {
+      (UINT8) (sizeof (EMMC_DEVICE_PATH)),
+      (UINT8) ((sizeof (EMMC_DEVICE_PATH)) >> 8)
+    }
+  },
+  0
+};
+
+//
+// Prioritized function list to detect card type.
+// User could add other card detection logic here.
+//
+DWMMC_CARD_TYPE_DETECT_ROUTINE mCardTypeDetectRoutineTable[] = {
+  EmmcIdentification,
+  SdCardIdentification,
+  NULL
+};
+
+/**
+  The entry point for SD host controller driver, used to install this driver on the ImageHandle.
+
+  @param[in]  ImageHandle   The firmware allocated handle for this driver image.
+  @param[in]  SystemTable   Pointer to the EFI system table.
+
+  @retval EFI_SUCCESS   Driver loaded.
+  @retval other         Driver not loaded.
+
+**/
+EFI_STATUS
+EFIAPI
+InitializeDwMmcHcDxe (
+  IN EFI_HANDLE        ImageHandle,
+  IN EFI_SYSTEM_TABLE  *SystemTable
+  )
+{
+  EFI_STATUS           Status;
+
+  Status = EfiLibInstallDriverBindingComponentName2 (
+             ImageHandle,
+             SystemTable,
+             &gDwMmcHcDriverBinding,
+             ImageHandle,
+             &gDwMmcHcComponentName,
+             &gDwMmcHcComponentName2
+             );
+  ASSERT_EFI_ERROR (Status);
+
+  return Status;
+}
+
+/**
+  Call back function when the timer event is signaled.
+
+  @param[in]  Event     The Event this notify function registered to.
+  @param[in]  Context   Pointer to the context data registered to the
+                        Event.
+
+**/
+VOID
+EFIAPI
+ProcessAsyncTaskList (
+  IN EFI_EVENT          Event,
+  IN VOID*              Context
+  )
+{
+  DW_MMC_HC_PRIVATE_DATA              *Private;
+  LIST_ENTRY                          *Link;
+  DW_MMC_HC_TRB                       *Trb;
+  EFI_STATUS                          Status;
+  EFI_SD_MMC_PASS_THRU_COMMAND_PACKET *Packet;
+  BOOLEAN                             InfiniteWait;
+  EFI_EVENT                           TrbEvent;
+
+  Private = (DW_MMC_HC_PRIVATE_DATA *)Context;
+
+  //
+  // Check if the first entry in the async I/O queue is done or not.
+  //
+  Status = EFI_SUCCESS;
+  Trb    = NULL;
+  Link   = GetFirstNode (&Private->Queue);
+  if (!IsNull (&Private->Queue, Link)) {
+    Trb = DW_MMC_HC_TRB_FROM_THIS (Link);
+    if (!Private->Slot[Trb->Slot].MediaPresent) {
+      Status = EFI_NO_MEDIA;
+      goto Done;
+    }
+    if (!Trb->Started) {
+      //
+      // Check whether the cmd/data line is ready for transfer.
+      //
+      Status = DwMmcCheckTrbEnv (Private, Trb);
+      if (!EFI_ERROR (Status)) {
+        Trb->Started = TRUE;
+        Status = DwMmcExecTrb (Private, Trb);
+        if (EFI_ERROR (Status)) {
+          goto Done;
+        }
+      } else {
+        goto Done;
+      }
+    }
+    Status = DwMmcCheckTrbResult (Private, Trb);
+  }
+
+Done:
+  if ((Trb != NULL) && (Status == EFI_NOT_READY)) {
+    Packet = Trb->Packet;
+    if (Packet->Timeout == 0) {
+      InfiniteWait = TRUE;
+    } else {
+      InfiniteWait = FALSE;
+    }
+    if ((!InfiniteWait) && (Trb->Timeout-- == 0)) {
+      RemoveEntryList (Link);
+      Trb->Packet->TransactionStatus = EFI_TIMEOUT;
+      TrbEvent = Trb->Event;
+      DwMmcFreeTrb (Trb);
+      DEBUG ((
+        DEBUG_VERBOSE,
+        "ProcessAsyncTaskList(): Signal Event %p EFI_TIMEOUT\n",
+        TrbEvent
+        ));
+      gBS->SignalEvent (TrbEvent);
+      return;
+    }
+  }
+  if ((Trb != NULL) && (Status != EFI_NOT_READY)) {
+    RemoveEntryList (Link);
+    Trb->Packet->TransactionStatus = Status;
+    TrbEvent = Trb->Event;
+    DwMmcFreeTrb (Trb);
+    DEBUG ((
+      DEBUG_VERBOSE,
+      "ProcessAsyncTaskList(): Signal Event %p with %r\n",
+      TrbEvent,
+      Status
+      ));
+    gBS->SignalEvent (TrbEvent);
+  }
+  return;
+}
+
+/**
+  Sd removable device enumeration callback function when the timer event is signaled.
+
+  @param[in]  Event     The Event this notify function registered to.
+  @param[in]  Context   Pointer to the context data registered to the
+                        Event.
+
+**/
+VOID
+EFIAPI
+DwMmcHcEnumerateDevice (
+  IN EFI_EVENT          Event,
+  IN VOID*              Context
+  )
+{
+  DW_MMC_HC_PRIVATE_DATA              *Private;
+  EFI_STATUS                          Status;
+  BOOLEAN                             MediaPresent;
+  UINT32                              RoutineNum;
+  DWMMC_CARD_TYPE_DETECT_ROUTINE      *Routine;
+  UINTN                               Index;
+  LIST_ENTRY                          *Link;
+  LIST_ENTRY                          *NextLink;
+  DW_MMC_HC_TRB                       *Trb;
+  EFI_TPL                             OldTpl;
+
+  Private = (DW_MMC_HC_PRIVATE_DATA *)Context;
+
+  if ((Private->Slot[0].Enable) &&
+      (Private->Slot[0].SlotType == RemovableSlot)) {
+    Status = DwMmcHcCardDetect (
+               Private->DevIo,
+               Private->ControllerHandle,
+               0,
+               &MediaPresent
+               );
+    if ((Status == EFI_MEDIA_CHANGED) && !MediaPresent) {
+      DEBUG ((
+        DEBUG_INFO,
+        "DwMmcHcEnumerateDevice: device disconnected at %p\n",
+        Private->DevIo
+        ));
+      Private->Slot[0].MediaPresent = FALSE;
+      //
+      // Signal all async task events at the slot with EFI_NO_MEDIA status.
+      //
+      OldTpl = gBS->RaiseTPL (TPL_NOTIFY);
+      for (Link = GetFirstNode (&Private->Queue);
+           !IsNull (&Private->Queue, Link);
+           Link = NextLink) {
+        NextLink = GetNextNode (&Private->Queue, Link);
+        Trb = DW_MMC_HC_TRB_FROM_THIS (Link);
+        if (Trb->Slot == 0) {
+          RemoveEntryList (Link);
+          Trb->Packet->TransactionStatus = EFI_NO_MEDIA;
+          gBS->SignalEvent (Trb->Event);
+          DwMmcFreeTrb (Trb);
+        }
+      }
+      gBS->RestoreTPL (OldTpl);
+      //
+      // Notify the upper layer the connect state change through
+      // ReinstallProtocolInterface.
+      //
+      gBS->ReinstallProtocolInterface (
+            Private->ControllerHandle,
+            &gEfiSdMmcPassThruProtocolGuid,
+            &Private->PassThru,
+            &Private->PassThru
+            );
+    }
+    if ((Status == EFI_MEDIA_CHANGED) && MediaPresent) {
+      DEBUG ((
+        DEBUG_INFO,
+        "DwMmcHcEnumerateDevice: device connected at %p\n",
+        Private->DevIo
+        ));
+      //
+      // Initialize slot and start identification process for the new
+      // attached device
+      //
+      Status = DwMmcHcInitHost (Private->DevIo, Private->Capability[0]);
+      if (EFI_ERROR (Status)) {
+        return;
+      }
+      //
+      // Reset the specified slot of the SD/MMC Pci Host Controller
+      //
+      Status = DwMmcHcReset (Private->DevIo, Private->Capability[0]);
+      if (EFI_ERROR (Status)) {
+        return;
+      }
+
+      Private->Slot[0].MediaPresent = TRUE;
+      RoutineNum = sizeof (mCardTypeDetectRoutineTable) /
+                   sizeof (DWMMC_CARD_TYPE_DETECT_ROUTINE);
+      for (Index = 0; Index < RoutineNum; Index++) {
+        Routine = &mCardTypeDetectRoutineTable[Index];
+        if (*Routine != NULL) {
+          Status = (*Routine) (Private);
+          if (!EFI_ERROR (Status)) {
+            break;
+          }
+        }
+      }
+      //
+      // This card doesn't get initialized correctly.
+      //
+      if (Index == RoutineNum) {
+        return;
+      }
+
+      //
+      // Notify the upper layer the connect state change through
+      // ReinstallProtocolInterface.
+      //
+      gBS->ReinstallProtocolInterface (
+             Private->ControllerHandle,
+             &gEfiSdMmcPassThruProtocolGuid,
+             &Private->PassThru,
+             &Private->PassThru
+             );
+    }
+  }
+
+  return;
+}
+
+/**
+  Reset the specified SD/MMC host controller and enable all interrupts.
+
+  @param[in] DevIo          The DEVICE IO protocol instance.
+
+  @retval EFI_SUCCESS       The software reset executes successfully.
+  @retval Others            The software reset fails.
+
+**/
+EFI_STATUS
+DwMmcHcReset (
+  IN EFI_DEVICE_IO_PROTOCOL    *DevIo,
+  IN DW_MMC_HC_SLOT_CAP        Capability
+  )
+{
+  EFI_STATUS                Status;
+  UINT32                    BlkSize;
+
+  //
+  // Enable all interrupt after reset all.
+  //
+  Status = DwMmcHcEnableInterrupt (DevIo);
+  if (EFI_ERROR (Status)) {
+    DEBUG ((DEBUG_ERROR, "DwMmcHcReset: enable interrupts fail: %r\n", Status));
+    return Status;
+  }
+  Status = DwMmcHcInitTimeoutCtrl (DevIo);
+  if (EFI_ERROR (Status)) {
+    return Status;
+  }
+
+  BlkSize = DW_MMC_BLOCK_SIZE;
+  Status = DwMmcHcRwMmio (
+             DevIo,
+             DW_MMC_BLKSIZ,
+             FALSE,
+             sizeof (BlkSize),
+             &BlkSize);
+  if (EFI_ERROR (Status)) {
+    DEBUG ((DEBUG_ERROR, "DwMmcHcReset: set block size fails: %r\n", Status));
+    return Status;
+  }
+
+  Status = DwMmcHcInitClockFreq (DevIo, Capability);
+  if (EFI_ERROR (Status)) {
+    return Status;
+  }
+
+  Status = DwMmcHcSetBusWidth (DevIo, FALSE, 1);
+
+  return Status;
+}
+
+/**
+  Tests to see if this driver supports a given controller. If a child device
+  is provided, it further tests to see if this driver supports creating a
+  handle for the specified child device.
+
+  This function checks to see if the driver specified by This supports the
+  device specified by ControllerHandle. Drivers will typically use the device
+  path attached to ControllerHandle and/or the services from the bus I/O
+  abstraction attached to ControllerHandle to determine if the driver supports
+  ControllerHandle. This function may be called many times during platform
+  initialization. In order to reduce boot times, the tests performed by this
+  function must be very small, and take as little time as possible to execute.
+  This function must not change the state of any hardware devices, and this
+  function must be aware that the device specified by ControllerHandle may
+  already be managed by the same driver or a different driver. This function
+  must match its calls to AllocatePages() with FreePages(), AllocatePool() with
+  FreePool(), and OpenProtocol() with CloseProtocol(). Since ControllerHandle
+  may have been previously started by the same driver, if a protocol is already
+  in the opened state, then it must not be closed with CloseProtocol(). This is
+  required to guarantee the state of ControllerHandle is not modified by this
+  function.
+
+  @param[in]  This                 A pointer to the EFI_DRIVER_BINDING_PROTOCOL
+                                   instance.
+  @param[in]  ControllerHandle     The handle of the controller to test. This
+                                   handle must support a protocol interface that
+                                   supplies an I/O abstraction to the driver.
+  @param[in]  RemainingDevicePath  A pointer to the remaining portion of a
+                                   device path.  This parameter is ignored by
+                                   device drivers, and is optional for bus
+                                   drivers. For bus drivers, if this parameter
+                                   is not NULL, then the bus driver must deter-
+                                   mine if the bus controller specified by
+                                   ControllerHandle and the child controller
+                                   specified by RemainingDevicePath are both
+                                   supported by this bus driver.
+
+  @retval EFI_SUCCESS              The device specified by ControllerHandle and
+                                   RemainingDevicePath is supported by the
+                                   driver specified by This.
+  @retval EFI_ALREADY_STARTED      The device specified by ControllerHandle and
+                                   RemainingDevicePath is already being managed
+                                   by the driver specified by This.
+  @retval EFI_ACCESS_DENIED        The device specified by ControllerHandle and
+                                   RemainingDevicePath is already being managed
+                                   by a different driver or an application that
+                                   requires exclusive access.
+                                   Currently not implemented.
+  @retval EFI_UNSUPPORTED          The device specified by ControllerHandle and
+                                   RemainingDevicePath is not supported by the
+                                   driver specified by This.
+**/
+EFI_STATUS
+EFIAPI
+DwMmcHcDriverBindingSupported (
+  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_DEVICE_IO_PROTOCOL    *DevIo;
+  PLATFORM_DW_MMC_PROTOCOL  *PlatformDwMmc;
+
+  ParentDevicePath = NULL;
+
+  Status = gBS->LocateProtocol (
+                  &gPlatformDwMmcProtocolGuid,
+                  NULL,
+                  (VOID **) &PlatformDwMmc
+                  );
+  if (EFI_ERROR (Status)) {
+    return Status;
+  }
+
+  Status = gBS->OpenProtocol (
+                  Controller,
+                  &gEfiDevicePathProtocolGuid,
+                  (VOID *) &ParentDevicePath,
+                  This->DriverBindingHandle,
+                  Controller,
+                  EFI_OPEN_PROTOCOL_BY_DRIVER
+                  );
+  if (EFI_ERROR (Status)) {
+    //
+    // EFI_ALREADY_STARTED is also an error.
+    //
+    return Status;
+  }
+  //
+  // Close the protocol because we don't use it here.
+  //
+  gBS->CloseProtocol (
+        Controller,
+        &gEfiDevicePathProtocolGuid,
+        This->DriverBindingHandle,
+        Controller
+        );
+
+  //
+  // Now test the EmbeddedNonDiscoverableIoProtocol.
+  //
+  Status = gBS->OpenProtocol (
+                  Controller,
+                  &gEmbeddedNonDiscoverableIoProtocolGuid,
+                  (VOID **) &DevIo,
+                  This->DriverBindingHandle,
+                  Controller,
+                  EFI_OPEN_PROTOCOL_BY_DRIVER
+                  );
+  if (EFI_ERROR (Status)) {
+    return Status;
+  }
+  gBS->CloseProtocol (
+         Controller,
+         &gEmbeddedNonDiscoverableIoProtocolGuid,
+         This->DriverBindingHandle,
+         Controller
+         );
+  return EFI_SUCCESS;
+}
+
+/**
+  Starts a device controller or a bus controller.
+
+  The Start() function is designed to be invoked from the EFI boot service
+  ConnectController().
+  As a result, much of the error checking on the parameters to Start() has
+  been moved into this
+  common boot service. It is legal to call Start() from other locations,
+  but the following calling restrictions must be followed or the system
+  behavior will not be deterministic.
+  1. ControllerHandle must be a valid EFI_HANDLE.
+  2. If RemainingDevicePath is not NULL, then it must be a pointer to a
+     naturally aligned EFI_DEVICE_PATH_PROTOCOL.
+  3. Prior to calling Start(), the Supported() function for the driver
+     specified by This must have been called with the same calling parameters,
+     and Supported() must have returned EFI_SUCCESS.
+
+  @param[in]  This                 A pointer to the EFI_DRIVER_BINDING_PROTOCOL
+                                   instance.
+  @param[in]  ControllerHandle     The handle of the controller to start. This
+                                   handle must support a protocol interface
+                                   that supplies an I/O abstraction to the
+                                   driver.
+  @param[in]  RemainingDevicePath  A pointer to the remaining portion of a
+                                   device path.  This parameter is ignored by
+                                   device drivers, and is optional for bus
+                                   drivers.
+                                   For a bus driver, if this parameter is NULL,
+                                   then handles for all the children of
+                                   Controller are created by this driver.
+                                   If this parameter is not NULL and the first
+                                   Device Path Node is not the End of Device
+                                   Path Node, then only the handle for the
+                                   child device specified by the first Device
+                                   Path Node of RemainingDevicePath is created
+                                   by this driver.
+                                   If the first Device Path Node of
+                                   RemainingDevicePath is the End of Device Path
+                                   Node, no child handle is created by this
+                                   driver.
+
+  @retval EFI_SUCCESS              The device was started.
+  @retval EFI_DEVICE_ERROR         The device could not be started due to a
+                                   device error. Currently not implemented.
+  @retval EFI_OUT_OF_RESOURCES     The request could not be completed due to a
+                                   lack of resources.
+  @retval Others                   The driver failded to start the device.
+
+**/
+EFI_STATUS
+EFIAPI
+DwMmcHcDriverBindingStart (
+  IN EFI_DRIVER_BINDING_PROTOCOL     *This,
+  IN EFI_HANDLE                      Controller,
+  IN EFI_DEVICE_PATH_PROTOCOL        *RemainingDevicePath
+  )
+{
+  EFI_STATUS                      Status;
+  DW_MMC_HC_PRIVATE_DATA          *Private;
+  EFI_DEVICE_IO_PROTOCOL          *DevIo;
+  BOOLEAN                         MediaPresent;
+  DWMMC_CARD_TYPE_DETECT_ROUTINE  *Routine;
+  UINT8                           Index;
+  UINT32                          RoutineNum;
+  PLATFORM_DW_MMC_PROTOCOL        *PlatformDwMmc;
+
+  Status = gBS->LocateProtocol (
+                  &gPlatformDwMmcProtocolGuid,
+                  NULL,
+                  (VOID **) &PlatformDwMmc
+                  );
+  if (EFI_ERROR (Status)) {
+    return Status;
+  }
+
+  Status = gBS->OpenProtocol (
+                  Controller,
+                  &gEmbeddedNonDiscoverableIoProtocolGuid,
+                  (VOID **) &DevIo,
+                  This->DriverBindingHandle,
+                  Controller,
+                  EFI_OPEN_PROTOCOL_BY_DRIVER
+                  );
+  if (EFI_ERROR (Status)) {
+    return Status;
+  }
+
+  Private = AllocateCopyPool (sizeof (DW_MMC_HC_PRIVATE_DATA), &gDwMmcHcTemplate);
+  if (Private == NULL) {
+    Status = EFI_OUT_OF_RESOURCES;
+    goto Done;
+  }
+
+  Private->ControllerHandle = Controller;
+  Private->DevIo            = DevIo;
+  Private->PlatformDwMmc    = PlatformDwMmc;
+  InitializeListHead (&Private->Queue);
+
+  Status = DwMmcHcGetCapability (DevIo, Controller, 0, &Private->Capability[0]);
+  if (EFI_ERROR (Status)) {
+    goto Done;
+  }
+
+  if (Private->Capability[0].BaseClkFreq == 0) {
+    goto Done;
+  }
+
+  DumpCapabilityReg (0, &Private->Capability[0]);
+
+  MediaPresent = FALSE;
+  Status = DwMmcHcCardDetect (Private->DevIo, Controller, 0, &MediaPresent);
+  if (MediaPresent == FALSE) {
+    goto Done;
+  }
+
+  //
+  // Initialize slot and start identification process for the new attached device
+  //
+  Status = DwMmcHcInitHost (DevIo, Private->Capability[0]);
+  if (EFI_ERROR (Status)) {
+    goto Done;
+  }
+
+  //
+  // Reset HC
+  //
+  Status = DwMmcHcReset (DevIo, Private->Capability[0]);
+  if (EFI_ERROR (Status)) {
+    goto Done;
+  }
+
+  Private->Slot[0].CardType = Private->Capability[0].CardType;
+  Private->Slot[0].Enable = TRUE;
+  Private->Slot[0].MediaPresent = TRUE;
+
+  RoutineNum = sizeof (mCardTypeDetectRoutineTable) / sizeof (DWMMC_CARD_TYPE_DETECT_ROUTINE);
+  for (Index = 0; Index < RoutineNum; Index++) {
+    Routine = &mCardTypeDetectRoutineTable[Index];
+    if (*Routine != NULL) {
+      Status = (*Routine) (Private);
+      if (!EFI_ERROR (Status)) {
+        break;
+      }
+    }
+  }
+
+  //
+  // Start the asynchronous I/O monitor
+  //
+  Status = gBS->CreateEvent (
+                  EVT_TIMER | EVT_NOTIFY_SIGNAL,
+                  TPL_NOTIFY,
+                  ProcessAsyncTaskList,
+                  Private,
+                  &Private->TimerEvent
+                  );
+  if (EFI_ERROR (Status)) {
+    goto Done;
+  }
+
+  Status = gBS->SetTimer (Private->TimerEvent, TimerPeriodic, DW_MMC_HC_ASYNC_TIMER);
+  if (EFI_ERROR (Status)) {
+    goto Done;
+  }
+
+  //
+  // Start the Sd removable device connection enumeration
+  //
+  Status = gBS->CreateEvent (
+                  EVT_TIMER | EVT_NOTIFY_SIGNAL,
+                  TPL_CALLBACK,
+                  DwMmcHcEnumerateDevice,
+                  Private,
+                  &Private->ConnectEvent
+                  );
+  if (EFI_ERROR (Status)) {
+    goto Done;
+  }
+
+  Status = gBS->SetTimer (Private->ConnectEvent, TimerPeriodic, DW_MMC_HC_ENUM_TIMER);
+  if (EFI_ERROR (Status)) {
+    goto Done;
+  }
+
+  Status = gBS->InstallMultipleProtocolInterfaces (
+                  &Controller,
+                  &gEfiSdMmcPassThruProtocolGuid,
+                  &(Private->PassThru),
+                  NULL
+                  );
+
+  DEBUG ((DEBUG_INFO, "DwMmcHcDriverBindingStart: %r End on %x\n", Status, Controller));
+
+Done:
+  if (EFI_ERROR (Status)) {
+    if ((Private != NULL) && (Private->TimerEvent != NULL)) {
+      gBS->CloseEvent (Private->TimerEvent);
+    }
+
+    if ((Private != NULL) && (Private->ConnectEvent != NULL)) {
+      gBS->CloseEvent (Private->ConnectEvent);
+    }
+
+    if (Private != NULL) {
+      FreePool (Private);
+    }
+  }
+
+  return Status;
+}
+
+/**
+  Stops a device controller or a bus controller.
+
+  The Stop() function is designed to be invoked from the EFI boot service
+  DisconnectController().
+  As a result, much of the error checking on the parameters to Stop() has been
+  moved into this common boot service. It is legal to call Stop() from other
+  locations, but the following calling restrictions must be followed or the
+  system behavior will not be deterministic.
+  1. ControllerHandle must be a valid EFI_HANDLE that was used on a previous
+     call to this same driver's Start() function.
+  2. The first NumberOfChildren handles of ChildHandleBuffer must all be a valid
+     EFI_HANDLE. In addition, all of these handles must have been created in
+     this driver's Start() function, and the Start() function must have called
+     OpenProtocol() on ControllerHandle with an Attribute of
+     EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER.
+
+  @param[in]  This              A pointer to the EFI_DRIVER_BINDING_PROTOCOL
+                                instance.
+  @param[in]  ControllerHandle  A handle to the device being stopped. The handle
+                                must support a bus specific I/O protocol for the
+                                driver to use to stop the device.
+  @param[in]  NumberOfChildren  The number of child device handles in
+                                ChildHandleBuffer.
+  @param[in]  ChildHandleBuffer An array of child handles to be freed. May be
+                                NULL if NumberOfChildren is 0.
+
+  @retval EFI_SUCCESS           The device was stopped.
+  @retval EFI_DEVICE_ERROR      The device could not be stopped due to a device
+                                error.
+
+**/
+EFI_STATUS
+EFIAPI
+DwMmcHcDriverBindingStop (
+  IN  EFI_DRIVER_BINDING_PROTOCOL     *This,
+  IN  EFI_HANDLE                      Controller,
+  IN  UINTN                           NumberOfChildren,
+  IN  EFI_HANDLE                      *ChildHandleBuffer
+  )
+{
+  EFI_STATUS                          Status;
+  EFI_SD_MMC_PASS_THRU_PROTOCOL       *PassThru;
+  DW_MMC_HC_PRIVATE_DATA              *Private;
+  LIST_ENTRY                          *Link;
+  LIST_ENTRY                          *NextLink;
+  DW_MMC_HC_TRB                       *Trb;
+
+  DEBUG ((DEBUG_INFO, "DwMmcHcDriverBindingStop: Start\n"));
+
+  Status = gBS->OpenProtocol (
+                  Controller,
+                  &gEfiSdMmcPassThruProtocolGuid,
+                  (VOID**) &PassThru,
+                  This->DriverBindingHandle,
+                  Controller,
+                  EFI_OPEN_PROTOCOL_GET_PROTOCOL
+                  );
+  if (EFI_ERROR (Status)) {
+    return Status;
+  }
+
+  Private = DW_MMC_HC_PRIVATE_FROM_THIS (PassThru);
+  //
+  // Close Non-Blocking timer and free Task list.
+  //
+  if (Private->TimerEvent != NULL) {
+    gBS->CloseEvent (Private->TimerEvent);
+    Private->TimerEvent = NULL;
+  }
+  if (Private->ConnectEvent != NULL) {
+    gBS->CloseEvent (Private->ConnectEvent);
+    Private->ConnectEvent = NULL;
+  }
+  //
+  // As the timer is closed, there is no needs to use TPL lock to
+  // protect the critical region "queue".
+  //
+  for (Link = GetFirstNode (&Private->Queue);
+       !IsNull (&Private->Queue, Link);
+       Link = NextLink) {
+    NextLink = GetNextNode (&Private->Queue, Link);
+    RemoveEntryList (Link);
+    Trb = DW_MMC_HC_TRB_FROM_THIS (Link);
+    Trb->Packet->TransactionStatus = EFI_ABORTED;
+    gBS->SignalEvent (Trb->Event);
+    DwMmcFreeTrb (Trb);
+  }
+
+  //
+  // Uninstall Block I/O protocol from the device handle
+  //
+  Status = gBS->UninstallProtocolInterface (
+                  Controller,
+                  &gEfiSdMmcPassThruProtocolGuid,
+                  &(Private->PassThru)
+                  );
+
+  if (EFI_ERROR (Status)) {
+    return Status;
+  }
+
+  gBS->CloseProtocol (
+         Controller,
+         &gEfiPciIoProtocolGuid,
+         This->DriverBindingHandle,
+         Controller
+         );
+
+  FreePool (Private);
+
+  DEBUG ((DEBUG_INFO, "DwMmcHcDriverBindingStop: End with %r\n", Status));
+
+  return Status;
+}
+
+/**
+  Sends SD command to an SD card that is attached to the SD controller.
+
+  The PassThru() function sends the SD command specified by Packet to the SD
+  card specified by Slot.
+
+  If Packet is successfully sent to the SD card, then EFI_SUCCESS is returned.
+
+  If a device error occurs while sending the Packet, then EFI_DEVICE_ERROR is
+  returned.
+
+  If Slot is not in a valid range for the SD controller, then
+  EFI_INVALID_PARAMETER is returned.
+
+  If Packet defines a data command but both InDataBuffer and OutDataBuffer are
+  NULL, EFI_INVALID_PARAMETER is returned.
+
+  @param[in]     This           A pointer to the EFI_SD_MMC_PASS_THRU_PROTOCOL
+                                instance.
+  @param[in]     Slot           The slot number of the SD card to send the
+                                command to.
+  @param[in,out] Packet         A pointer to the SD command data structure.
+  @param[in]     Event          If Event is NULL, blocking I/O is performed. If
+                                Event is not NULL, then nonblocking I/O is
+                                performed, and Event will be signaled when the
+                                Packet completes.
+
+  @retval EFI_SUCCESS           The SD Command Packet was sent by the host.
+  @retval EFI_DEVICE_ERROR      A device error occurred while attempting to send
+                                the SD command Packet.
+  @retval EFI_INVALID_PARAMETER Packet, Slot, or the contents of the Packet is
+                                invalid.
+  @retval EFI_INVALID_PARAMETER Packet defines a data command but both
+                                InDataBuffer and OutDataBuffer are NULL.
+  @retval EFI_NO_MEDIA          SD Device not present in the Slot.
+  @retval EFI_UNSUPPORTED       The command described by the SD Command Packet
+                                is not supported by the host controller.
+  @retval EFI_BAD_BUFFER_SIZE   The InTransferLength or OutTransferLength
+                                exceeds the limit supported by SD card
+                                ( i.e. if the number of bytes exceed the Last
+                                LBA).
+
+**/
+EFI_STATUS
+EFIAPI
+DwMmcPassThruPassThru (
+  IN     EFI_SD_MMC_PASS_THRU_PROTOCOL         *This,
+  IN     UINT8                                 Slot,
+  IN OUT EFI_SD_MMC_PASS_THRU_COMMAND_PACKET   *Packet,
+  IN     EFI_EVENT                             Event    OPTIONAL
+  )
+{
+  EFI_STATUS                      Status;
+  DW_MMC_HC_PRIVATE_DATA          *Private;
+  DW_MMC_HC_TRB                   *Trb;
+  EFI_TPL                         OldTpl;
+
+  if ((This == NULL) || (Packet == NULL)) {
+    return EFI_INVALID_PARAMETER;
+  }
+
+  if ((Packet->SdMmcCmdBlk == NULL) || (Packet->SdMmcStatusBlk == NULL)) {
+    return EFI_INVALID_PARAMETER;
+  }
+
+  if ((Packet->OutDataBuffer == NULL) && (Packet->OutTransferLength != 0)) {
+    return EFI_INVALID_PARAMETER;
+  }
+
+  if ((Packet->InDataBuffer == NULL) && (Packet->InTransferLength != 0)) {
+    return EFI_INVALID_PARAMETER;
+  }
+
+  Private = DW_MMC_HC_PRIVATE_FROM_THIS (This);
+
+  if (!Private->Slot[Slot].Enable) {
+    return EFI_INVALID_PARAMETER;
+  }
+
+  if (!Private->Slot[Slot].MediaPresent) {
+    return EFI_NO_MEDIA;
+  }
+
+  Trb = DwMmcCreateTrb (Private, Slot, Packet, Event);
+  if (Trb == NULL) {
+    return EFI_OUT_OF_RESOURCES;
+  }
+  //
+  // Immediately return for async I/O.
+  //
+  if (Event != NULL) {
+    return EFI_SUCCESS;
+  }
+
+  //
+  // Wait async I/O list is empty before execute sync I/O operation.
+  //
+  while (TRUE) {
+    OldTpl = gBS->RaiseTPL (TPL_NOTIFY);
+    if (IsListEmpty (&Private->Queue)) {
+      gBS->RestoreTPL (OldTpl);
+      break;
+    }
+    gBS->RestoreTPL (OldTpl);
+  }
+
+  Status = DwMmcWaitTrbEnv (Private, Trb);
+  if (EFI_ERROR (Status)) {
+    goto Done;
+  }
+
+  Status = DwMmcExecTrb (Private, Trb);
+  if (EFI_ERROR (Status)) {
+    goto Done;
+  }
+
+  Status = DwMmcWaitTrbResult (Private, Trb);
+  if (EFI_ERROR (Status)) {
+    goto Done;
+  }
+
+Done:
+  if (Trb != NULL) {
+    DwMmcFreeTrb (Trb);
+  }
+
+  return Status;
+}
+
+/**
+  Used to retrieve next slot numbers supported by the SD controller. The
+  function returns information about all available slots (populated or
+  not-populated).
+
+  The GetNextSlot() function retrieves the next slot number on an SD controller.
+  If on input Slot is 0xFF, then the slot number of the first slot on the SD
+  controller is returned.
+
+  If Slot is a slot number that was returned on a previous call to
+  GetNextSlot(), then the slot number of the next slot on the SD controller is
+  returned.
+
+  If Slot is not 0xFF and Slot was not returned on a previous call to
+  GetNextSlot(), EFI_INVALID_PARAMETER is returned.
+
+  If Slot is the slot number of the last slot on the SD controller, then
+  EFI_NOT_FOUND is returned.
+
+  @param[in]     This           A pointer to the EFI_SD_MMMC_PASS_THRU_PROTOCOL
+                                instance.
+  @param[in,out] Slot           On input, a pointer to a slot number on the SD
+                                controller.
+                                On output, a pointer to the next slot number on
+                                the SD controller.
+                                An input value of 0xFF retrieves the first slot
+                                number on the SD controller.
+
+  @retval EFI_SUCCESS           The next slot number on the SD controller was
+                                returned in Slot.
+  @retval EFI_NOT_FOUND         There are no more slots on this SD controller.
+  @retval EFI_INVALID_PARAMETER Slot is not 0xFF and Slot was not returned on a
+                                previous call to GetNextSlot().
+
+**/
+EFI_STATUS
+EFIAPI
+DwMmcPassThruGetNextSlot (
+  IN     EFI_SD_MMC_PASS_THRU_PROTOCOL        *This,
+  IN OUT UINT8                                *Slot
+  )
+{
+  DW_MMC_HC_PRIVATE_DATA          *Private;
+
+  if ((This == NULL) || (Slot == NULL)) {
+    return EFI_INVALID_PARAMETER;
+  }
+
+  Private = DW_MMC_HC_PRIVATE_FROM_THIS (This);
+
+  if (*Slot == 0xFF) {
+    if (Private->Slot[0].Enable) {
+      *Slot = 0;
+      Private->PreviousSlot = 0;
+      return EFI_SUCCESS;
+    }
+    return EFI_NOT_FOUND;
+  } else if (*Slot == Private->PreviousSlot) {
+    return EFI_NOT_FOUND;
+  } else {
+    return EFI_INVALID_PARAMETER;
+  }
+}
+
+/**
+  Used to allocate and build a device path node for an SD card on the SD
+  controller.
+
+  The BuildDevicePath() function allocates and builds a single device node
+  for the SD card specified by Slot.
+
+  If the SD card specified by Slot is not present on the SD controller, then
+  EFI_NOT_FOUND is returned.
+
+  If DevicePath is NULL, then EFI_INVALID_PARAMETER is returned.
+
+  If there are not enough resources to allocate the device path node, then
+  EFI_OUT_OF_RESOURCES is returned.
+
+  Otherwise, DevicePath is allocated with the boot service AllocatePool(),
+  the contents of DevicePath are initialized to describe the SD card specified
+  by Slot, and EFI_SUCCESS is returned.
+
+  @param[in]     This           A pointer to the EFI_SD_MMMC_PASS_THRU_PROTOCOL
+                                instance.
+  @param[in]     Slot           Specifies the slot number of the SD card for
+                                which a device path node is to be allocated and
+                                built.
+  @param[in,out] DevicePath     A pointer to a single device path node that
+                                describes the SD card specified by Slot. This
+                                function is responsible for allocating the
+                                buffer DevicePath with the boot service
+                                AllocatePool(). It is the caller's responsi-
+                                bility to free DevicePath when the caller is
+                                finished with DevicePath.
+
+  @retval EFI_SUCCESS           The device path node that describes the SD card
+                                specified by Slot was allocated and returned in
+                                DevicePath.
+  @retval EFI_NOT_FOUND         The SD card specified by Slot does not exist on
+                                the SD controller.
+  @retval EFI_INVALID_PARAMETER DevicePath is NULL.
+  @retval EFI_OUT_OF_RESOURCES  There are not enough resources to allocate
+                                DevicePath.
+
+**/
+EFI_STATUS
+EFIAPI
+DwMmcPassThruBuildDevicePath (
+  IN     EFI_SD_MMC_PASS_THRU_PROTOCOL       *This,
+  IN     UINT8                               Slot,
+  IN OUT EFI_DEVICE_PATH_PROTOCOL            **DevicePath
+  )
+{
+  DW_MMC_HC_PRIVATE_DATA          *Private;
+  SD_DEVICE_PATH                  *SdNode;
+  EMMC_DEVICE_PATH                *EmmcNode;
+
+  if ((This == NULL) || (DevicePath == NULL) || (Slot >= DW_MMC_HC_MAX_SLOT)) {
+    return EFI_INVALID_PARAMETER;
+  }
+
+  Private = DW_MMC_HC_PRIVATE_FROM_THIS (This);
+
+  if ((!Private->Slot[Slot].Enable) || (!Private->Slot[Slot].MediaPresent)) {
+    return EFI_NOT_FOUND;
+  }
+
+  if (Private->Slot[Slot].CardType == SdCardType) {
+    SdNode = AllocateCopyPool (sizeof (SD_DEVICE_PATH), &mSdDpTemplate);
+    if (SdNode == NULL) {
+      return EFI_OUT_OF_RESOURCES;
+    }
+    SdNode->SlotNumber = Slot;
+
+    *DevicePath = (EFI_DEVICE_PATH_PROTOCOL *) SdNode;
+  } else if (Private->Slot[Slot].CardType == EmmcCardType) {
+    EmmcNode = AllocateCopyPool (sizeof (EMMC_DEVICE_PATH), &mEmmcDpTemplate);
+    if (EmmcNode == NULL) {
+      return EFI_OUT_OF_RESOURCES;
+    }
+    EmmcNode->SlotNumber = Slot;
+
+    *DevicePath = (EFI_DEVICE_PATH_PROTOCOL *) EmmcNode;
+  } else {
+    //
+    // Currently we only support SD and EMMC two device nodes.
+    //
+    return EFI_NOT_FOUND;
+  }
+
+  return EFI_SUCCESS;
+}
+
+/**
+  This function retrieves an SD card slot number based on the input device path.
+
+  The GetSlotNumber() function retrieves slot number for the SD card specified
+  by the DevicePath node. If DevicePath is NULL, EFI_INVALID_PARAMETER is
+  returned.
+
+  If DevicePath is not a device path node type that the SD Pass Thru driver
+  supports, EFI_UNSUPPORTED is returned.
+
+  @param[in]  This              A pointer to the EFI_SD_MMC_PASS_THRU_PROTOCOL
+                                instance.
+  @param[in]  DevicePath        A pointer to the device path node that describes
+                                a SD card on the SD controller.
+  @param[out] Slot              On return, points to the slot number of an SD
+                                card on the SD controller.
+
+  @retval EFI_SUCCESS           SD card slot number is returned in Slot.
+  @retval EFI_INVALID_PARAMETER Slot or DevicePath is NULL.
+  @retval EFI_UNSUPPORTED       DevicePath is not a device path node type that
+                                the SD Pass Thru driver supports.
+
+**/
+EFI_STATUS
+EFIAPI
+DwMmcPassThruGetSlotNumber (
+  IN  EFI_SD_MMC_PASS_THRU_PROTOCOL          *This,
+  IN  EFI_DEVICE_PATH_PROTOCOL               *DevicePath,
+  OUT UINT8                                  *Slot
+  )
+{
+  DW_MMC_HC_PRIVATE_DATA          *Private;
+  SD_DEVICE_PATH                  *SdNode;
+  EMMC_DEVICE_PATH                *EmmcNode;
+  UINT8                           SlotNumber;
+
+  if ((This == NULL) || (DevicePath == NULL) || (Slot == NULL)) {
+    return EFI_INVALID_PARAMETER;
+  }
+
+  Private = DW_MMC_HC_PRIVATE_FROM_THIS (This);
+
+  //
+  // Check whether the DevicePath belongs to SD_DEVICE_PATH or EMMC_DEVICE_PATH
+  //
+  if ((DevicePath->Type != MESSAGING_DEVICE_PATH) ||
+      ((DevicePath->SubType != MSG_SD_DP) &&
+       (DevicePath->SubType != MSG_EMMC_DP)) ||
+      (DevicePathNodeLength(DevicePath) != sizeof(SD_DEVICE_PATH)) ||
+      (DevicePathNodeLength(DevicePath) != sizeof(EMMC_DEVICE_PATH))) {
+    return EFI_UNSUPPORTED;
+  }
+
+  if (DevicePath->SubType == MSG_SD_DP) {
+    SdNode = (SD_DEVICE_PATH *) DevicePath;
+    SlotNumber = SdNode->SlotNumber;
+  } else {
+    EmmcNode = (EMMC_DEVICE_PATH *) DevicePath;
+    SlotNumber = EmmcNode->SlotNumber;
+  }
+
+  if (SlotNumber >= DW_MMC_HC_MAX_SLOT) {
+    return EFI_NOT_FOUND;
+  }
+
+  if (Private->Slot[SlotNumber].Enable) {
+    *Slot = SlotNumber;
+    return EFI_SUCCESS;
+  } else {
+    return EFI_NOT_FOUND;
+  }
+}
+
+/**
+  Resets an SD card that is connected to the SD controller.
+
+  The ResetDevice() function resets the SD card specified by Slot.
+
+  If this SD controller does not support a device reset operation,
+  EFI_UNSUPPORTED is returned.
+
+  If Slot is not in a valid slot number for this SD controller,
+  EFI_INVALID_PARAMETER is returned.
+
+  If the device reset operation is completed, EFI_SUCCESS is returned.
+
+  @param[in]  This              A pointer to the EFI_SD_MMC_PASS_THRU_PROTOCOL
+                                instance.
+  @param[in]  Slot              Specifies the slot number of the SD card to be
+                                reset.
+
+  @retval EFI_SUCCESS           The SD card specified by Slot was reset.
+  @retval EFI_UNSUPPORTED       The SD controller does not support a device
+                                reset operation.
+  @retval EFI_INVALID_PARAMETER Slot number is invalid.
+  @retval EFI_NO_MEDIA          SD Device not present in the Slot.
+  @retval EFI_DEVICE_ERROR      The reset command failed due to a device error
+
+**/
+EFI_STATUS
+EFIAPI
+DwMmcPassThruResetDevice (
+  IN EFI_SD_MMC_PASS_THRU_PROTOCOL           *This,
+  IN UINT8                                   Slot
+  )
+{
+  DW_MMC_HC_PRIVATE_DATA          *Private;
+  LIST_ENTRY                      *Link;
+  LIST_ENTRY                      *NextLink;
+  DW_MMC_HC_TRB                   *Trb;
+  EFI_TPL                         OldTpl;
+
+  if (This == NULL) {
+    return EFI_INVALID_PARAMETER;
+  }
+
+  Private = DW_MMC_HC_PRIVATE_FROM_THIS (This);
+
+  if (!Private->Slot[Slot].Enable) {
+    return EFI_INVALID_PARAMETER;
+  }
+
+  if (!Private->Slot[Slot].MediaPresent) {
+    return EFI_NO_MEDIA;
+  }
+
+  //
+  // Free all async I/O requests in the queue
+  //
+  OldTpl = gBS->RaiseTPL (TPL_NOTIFY);
+
+  for (Link = GetFirstNode (&Private->Queue);
+       !IsNull (&Private->Queue, Link);
+       Link = NextLink) {
+    NextLink = GetNextNode (&Private->Queue, Link);
+    RemoveEntryList (Link);
+    Trb = DW_MMC_HC_TRB_FROM_THIS (Link);
+    Trb->Packet->TransactionStatus = EFI_ABORTED;
+    gBS->SignalEvent (Trb->Event);
+    DwMmcFreeTrb (Trb);
+  }
+
+  gBS->RestoreTPL (OldTpl);
+
+  return EFI_SUCCESS;
+}
diff --git a/EmbeddedPkg/Drivers/DwMmcHcDxe/DwMmcHci.c b/EmbeddedPkg/Drivers/DwMmcHcDxe/DwMmcHci.c
new file mode 100644
index 000000000000..c261495387e6
--- /dev/null
+++ b/EmbeddedPkg/Drivers/DwMmcHcDxe/DwMmcHci.c
@@ -0,0 +1,2366 @@ 
+/** @file
+  This driver is used to manage Designware SD/MMC PCI host controllers.
+
+  It would expose EFI_SD_MMC_PASS_THRU_PROTOCOL for upper layer use.
+
+  Copyright (c) 2015 - 2016, Intel Corporation. All rights reserved.<BR>
+  Copyright (c) 2018, Linaro Ltd. All rights reserved.<BR>
+
+  This program and the accompanying materials are licensed and made available
+  under the terms and conditions of the BSD License which accompanies this
+  distribution.  The full text of the license may be found at
+  http://opensource.org/licenses/bsd-license.php
+
+  THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+  WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#include <IndustryStandard/Emmc.h>
+#include <IndustryStandard/Sd.h>
+
+#include <Library/ArmLib.h>
+#include <Library/BaseMemoryLib.h>
+#include <Library/DebugLib.h>
+#include <Library/MemoryAllocationLib.h>
+#include <Library/UefiBootServicesTableLib.h>
+
+#include "DwMmcHcDxe.h"
+
+/**
+  Dump the content of SD/MMC host controller's Capability Register.
+
+  @param[in]  Slot            The slot number of the SD card to send the
+                              command to.
+  @param[in]  Capability      The buffer to store the capability data.
+
+**/
+VOID
+DumpCapabilityReg (
+  IN UINT8                Slot,
+  IN DW_MMC_HC_SLOT_CAP   *Capability
+  )
+{
+  //
+  // Dump Capability Data
+  //
+  DEBUG ((
+    DEBUG_INFO,
+    " == Slot [%d] Capability is 0x%x ==\n",
+    Slot,
+    Capability
+    ));
+  DEBUG ((
+    DEBUG_INFO,
+    "   Base Clk Freq     %dKHz\n",
+    Capability->BaseClkFreq
+    ));
+  DEBUG ((
+    DEBUG_INFO,
+    "   BusWidth          %d\n",
+    Capability->BusWidth
+    ));
+  DEBUG ((
+    DEBUG_INFO,
+    "   HighSpeed Support %a\n",
+    Capability->HighSpeed ? "TRUE" : "FALSE"
+    ));
+  DEBUG ((
+    DEBUG_INFO,
+    "   Voltage 1.8       %a\n",
+    Capability->Voltage18 ? "TRUE" : "FALSE"
+    ));
+  DEBUG ((
+    DEBUG_INFO,
+    "   64-bit Sys Bus    %a\n",
+    Capability->SysBus64 ? "TRUE" : "FALSE"
+    ));
+  DEBUG ((DEBUG_INFO, "   SlotType          "));
+  if (Capability->SlotType == 0x00) {
+    DEBUG ((DEBUG_INFO, "%a\n", "Removable Slot"));
+  } else if (Capability->SlotType == 0x01) {
+    DEBUG ((DEBUG_INFO, "%a\n", "Embedded Slot"));
+  } else if (Capability->SlotType == 0x02) {
+    DEBUG ((DEBUG_INFO, "%a\n", "Shared Bus Slot"));
+  } else {
+    DEBUG ((DEBUG_INFO, "%a\n", "Reserved"));
+  }
+  DEBUG ((
+    DEBUG_INFO,
+    "   SDR50  Support    %a\n",
+    Capability->Sdr50 ? "TRUE" : "FALSE"
+    ));
+  DEBUG ((
+    DEBUG_INFO,
+    "   SDR104 Support    %a\n",
+    Capability->Sdr104 ? "TRUE" : "FALSE"
+    ));
+  DEBUG ((
+    DEBUG_INFO,
+    "   DDR50  Support    %a\n",
+    Capability->Ddr50 ? "TRUE" : "FALSE"
+    ));
+  return;
+}
+
+/**
+  Read/Write specified SD/MMC host controller mmio register.
+
+  @param[in]      DevIo         The DEVICE IO protocol instance.
+  @param[in]      Offset        The offset to start the memory operation.
+  @param[in]      Read          A boolean to indicate it's read or write
+                                operation.
+  @param[in]      Count         The width of the mmio register in bytes.
+                                Must be 1, 2 , 4 or 8 bytes.
+  @param[in, out] Data          For read operations, the destination buffer to
+                                store the results. For write operations, the
+                                source buffer to write data from. The caller is
+                                responsible for having ownership of the data
+                                buffer and ensuring its size not less than
+                                Count bytes.
+
+  @retval EFI_INVALID_PARAMETER The DevIo or Data is NULL or the Count is not
+                                valid.
+  @retval EFI_SUCCESS           The read/write operation succeeds.
+  @retval Others                The read/write operation fails.
+
+**/
+EFI_STATUS
+EFIAPI
+DwMmcHcRwMmio (
+  IN     EFI_DEVICE_IO_PROTOCOL   *DevIo,
+  IN     UINT32                   Offset,
+  IN     BOOLEAN                  Read,
+  IN     UINT8                    Count,
+  IN OUT VOID                     *Data
+  )
+{
+  EFI_STATUS                   Status;
+
+  if ((DevIo == NULL) || (Data == NULL))  {
+    return EFI_INVALID_PARAMETER;
+  }
+
+  if ((Count != 4) && (Count != 8)) {
+    return EFI_INVALID_PARAMETER;
+  }
+
+  //
+  // Since there's FIFO in Designware controller, map it to 32-bit word only.
+  //
+  Count = Count / sizeof (UINT32);
+  if (Read) {
+    Status = DevIo->Mem.Read (
+                          DevIo,
+                          IO_UINT32,
+                          (UINT64) Offset,
+                          Count,
+                          Data
+                          );
+  } else {
+    Status = DevIo->Mem.Write (
+                          DevIo,
+                          IO_UINT32,
+                          (UINT64) Offset,
+                          Count,
+                          Data
+                          );
+  }
+
+  return Status;
+}
+
+/**
+  Do OR operation with the value of the specified SD/MMC host controller mmio
+  register.
+
+  @param[in] DevIo             The DEVICE IO protocol instance.
+  @param[in] Offset            The offset to start the memory operation.
+  @param[in] Count             The width of the mmio register in bytes.
+                               Must be 1, 2 , 4 or 8 bytes.
+  @param[in] OrData            The pointer to the data used to do OR operation.
+                               The caller is responsible for having ownership of
+                               the data buffer and ensuring its size not less
+                               than Count bytes.
+
+  @retval EFI_INVALID_PARAMETER The DevIo or OrData is NULL or the Count is not
+                                valid.
+  @retval EFI_SUCCESS           The OR operation succeeds.
+  @retval Others                The OR operation fails.
+
+**/
+EFI_STATUS
+EFIAPI
+DwMmcHcOrMmio (
+  IN  EFI_DEVICE_IO_PROTOCOL   *DevIo,
+  IN  UINT32                   Offset,
+  IN  UINT8                    Count,
+  IN  VOID                     *OrData
+  )
+{
+  EFI_STATUS                   Status;
+  UINT64                       Data;
+  UINT64                       Or;
+
+  Status = DwMmcHcRwMmio (DevIo, Offset, TRUE, Count, &Data);
+  if (EFI_ERROR (Status)) {
+    return Status;
+  }
+
+  if (Count == 1) {
+    Or = *(UINT8*) OrData;
+  } else if (Count == 2) {
+    Or = *(UINT16*) OrData;
+  } else if (Count == 4) {
+    Or = *(UINT32*) OrData;
+  } else if (Count == 8) {
+    Or = *(UINT64*) OrData;
+  } else {
+    return EFI_INVALID_PARAMETER;
+  }
+
+  Data  |= Or;
+  Status = DwMmcHcRwMmio (DevIo, Offset, FALSE, Count, &Data);
+
+  return Status;
+}
+
+/**
+  Do AND operation with the value of the specified SD/MMC host controller mmio
+  register.
+
+  @param[in] DevIo             The DEVICE IO protocol instance.
+  @param[in] Offset            The offset to start the memory operation.
+  @param[in] Count             The width of the mmio register in bytes.
+                               Must be 1, 2 , 4 or 8 bytes.
+  @param[in] AndData           The pointer to the data used to do AND operation.
+                               The caller is responsible for having ownership of
+                               the data buffer and ensuring its size not less
+                               than Count bytes.
+
+  @retval EFI_INVALID_PARAMETER The DevIo or AndData is NULL or the Count is
+                                not valid.
+  @retval EFI_SUCCESS           The AND operation succeeds.
+  @retval Others                The AND operation fails.
+
+**/
+EFI_STATUS
+EFIAPI
+DwMmcHcAndMmio (
+  IN  EFI_DEVICE_IO_PROTOCOL   *DevIo,
+  IN  UINT32                   Offset,
+  IN  UINT8                    Count,
+  IN  VOID                     *AndData
+  )
+{
+  EFI_STATUS                   Status;
+  UINT64                       Data;
+  UINT64                       And;
+
+  Status = DwMmcHcRwMmio (DevIo, Offset, TRUE, Count, &Data);
+  if (EFI_ERROR (Status)) {
+    return Status;
+  }
+
+  if (Count == 1) {
+    And = *(UINT8*) AndData;
+  } else if (Count == 2) {
+    And = *(UINT16*) AndData;
+  } else if (Count == 4) {
+    And = *(UINT32*) AndData;
+  } else if (Count == 8) {
+    And = *(UINT64*) AndData;
+  } else {
+    return EFI_INVALID_PARAMETER;
+  }
+
+  Data  &= And;
+  Status = DwMmcHcRwMmio (DevIo, Offset, FALSE, Count, &Data);
+
+  return Status;
+}
+
+/**
+  Wait for the value of the specified MMIO register set to the test value.
+
+  @param[in]  DevIo         The DEVICE IO protocol instance.
+  @param[in]  Offset        The offset to start the memory operation.
+  @param[in]  Count         The width of the mmio register in bytes.
+                            Must be 1, 2, 4 or 8 bytes.
+  @param[in]  MaskValue     The mask value of memory.
+  @param[in]  TestValue     The test value of memory.
+
+  @retval EFI_NOT_READY     The MMIO register hasn't set to the expected value.
+  @retval EFI_SUCCESS       The MMIO register has expected value.
+  @retval Others            The MMIO operation fails.
+
+**/
+EFI_STATUS
+EFIAPI
+DwMmcHcCheckMmioSet (
+  IN  EFI_DEVICE_IO_PROTOCOL    *DevIo,
+  IN  UINT32                    Offset,
+  IN  UINT8                     Count,
+  IN  UINT64                    MaskValue,
+  IN  UINT64                    TestValue
+  )
+{
+  EFI_STATUS            Status;
+  UINT64                Value;
+
+  Value  = 0;
+  Status = DwMmcHcRwMmio (DevIo, Offset, TRUE, Count, &Value);
+  if (EFI_ERROR (Status)) {
+    return Status;
+  }
+
+  Value &= MaskValue;
+
+  if (Value == TestValue) {
+    return EFI_SUCCESS;
+  }
+
+  return EFI_NOT_READY;
+}
+
+/**
+  Wait for the value of the specified MMIO register set to the test value.
+
+  @param[in]  DevIo         The DEVICE IO protocol instance.
+  @param[in]  Offset        The offset to start the memory operation.
+  @param[in]  Count         The width of the mmio register in bytes.
+                            Must be 1, 2, 4 or 8 bytes.
+  @param[in]  MaskValue     The mask value of memory.
+  @param[in]  TestValue     The test value of memory.
+  @param[in]  Timeout       The time out value for wait memory set, uses 1
+                            microsecond as a unit.
+
+  @retval EFI_TIMEOUT       The MMIO register hasn't expected value in timeout
+                            range.
+  @retval EFI_SUCCESS       The MMIO register has expected value.
+  @retval Others            The MMIO operation fails.
+
+**/
+EFI_STATUS
+EFIAPI
+DwMmcHcWaitMmioSet (
+  IN  EFI_DEVICE_IO_PROTOCOL    *DevIo,
+  IN  UINT32                    Offset,
+  IN  UINT8                     Count,
+  IN  UINT64                    MaskValue,
+  IN  UINT64                    TestValue,
+  IN  UINT64                    Timeout
+  )
+{
+  EFI_STATUS            Status;
+  BOOLEAN               InfiniteWait;
+
+  if (Timeout == 0) {
+    InfiniteWait = TRUE;
+  } else {
+    InfiniteWait = FALSE;
+  }
+
+  while (InfiniteWait || (Timeout > 0)) {
+    Status = DwMmcHcCheckMmioSet (
+               DevIo,
+               Offset,
+               Count,
+               MaskValue,
+               TestValue
+               );
+    if (Status != EFI_NOT_READY) {
+      return Status;
+    }
+
+    //
+    // Stall for 1 microsecond.
+    //
+    gBS->Stall (1);
+
+    Timeout--;
+  }
+
+  return EFI_TIMEOUT;
+}
+
+/**
+  Set all interrupt status bits in Normal and Error Interrupt Status Enable
+  register.
+
+  @param[in] DevIo          The DEVICE IO protocol instance.
+
+  @retval EFI_SUCCESS       The operation executes successfully.
+  @retval Others            The operation fails.
+
+**/
+EFI_STATUS
+DwMmcHcEnableInterrupt (
+  IN EFI_DEVICE_IO_PROTOCOL *DevIo
+  )
+{
+  EFI_STATUS                Status;
+  UINT32                    IntStatus;
+  UINT32                    IdIntEn;
+  UINT32                    IdSts;
+
+  //
+  // Enable all bits in Interrupt Mask Register
+  //
+  IntStatus = 0;
+  Status = DwMmcHcRwMmio (
+             DevIo,
+             DW_MMC_INTMASK,
+             FALSE,
+             sizeof (IntStatus),
+             &IntStatus
+             );
+  if (EFI_ERROR (Status)) {
+    return Status;
+  }
+
+  //
+  // Clear status in Interrupt Status Register
+  //
+  IntStatus = ~0;
+  Status = DwMmcHcRwMmio (
+             DevIo,
+             DW_MMC_RINTSTS,
+             FALSE,
+             sizeof (IntStatus),
+             &IntStatus
+             );
+  if (EFI_ERROR (Status)) {
+    return Status;
+  }
+
+  IdIntEn = ~0;
+  Status = DwMmcHcRwMmio (
+             DevIo,
+             DW_MMC_IDINTEN,
+             FALSE,
+             sizeof (IdIntEn),
+             &IdIntEn
+             );
+  if (EFI_ERROR (Status)) {
+    DEBUG ((
+      DEBUG_ERROR,
+      "DwMmcHcEnableInterrupt: init dma interrupts fail: %r\n",
+      Status
+      ));
+    return Status;
+  }
+
+  IdSts = ~0;
+  Status = DwMmcHcRwMmio (
+             DevIo,
+             DW_MMC_IDSTS,
+             FALSE,
+             sizeof (IdSts),
+             &IdSts
+             );
+  return Status;
+}
+
+EFI_STATUS
+DwMmcHcGetCapability (
+  IN     EFI_DEVICE_IO_PROTOCOL  *DevIo,
+  IN     EFI_HANDLE              Controller,
+  IN     UINT8                   Slot,
+     OUT DW_MMC_HC_SLOT_CAP      *Capacity
+  )
+{
+  PLATFORM_DW_MMC_PROTOCOL       *PlatformDwMmc;
+  EFI_STATUS                     Status;
+
+  if (Capacity == NULL) {
+    return EFI_INVALID_PARAMETER;
+  }
+  Status = gBS->LocateProtocol (
+                  &gPlatformDwMmcProtocolGuid,
+                  NULL,
+                  (VOID **) &PlatformDwMmc
+                  );
+  if (EFI_ERROR (Status)) {
+    return Status;
+  }
+  Status = PlatformDwMmc->GetCapability (Controller, Slot, Capacity);
+  return Status;
+}
+
+/**
+  Detect whether there is a SD/MMC card attached at the specified SD/MMC host
+  controller slot.
+
+  Refer to SD Host Controller Simplified spec 3.0 Section 3.1 for details.
+
+  @param[in]  DevIo         The DEVICE IO protocol instance.
+  @param[in]  Slot          The slot number of the SD card to send the command
+                            to.
+  @param[out] MediaPresent  The pointer to the media present boolean value.
+
+  @retval EFI_SUCCESS       There is no media change happened.
+  @retval EFI_MEDIA_CHANGED There is media change happened.
+  @retval Others            The detection fails.
+
+**/
+EFI_STATUS
+DwMmcHcCardDetect (
+  IN     EFI_DEVICE_IO_PROTOCOL *DevIo,
+  IN     EFI_HANDLE             Controller,
+  IN     UINT8                  Slot,
+     OUT BOOLEAN                *MediaPresent
+  )
+{
+  PLATFORM_DW_MMC_PROTOCOL  *PlatformDwMmc;
+  EFI_STATUS                Status;
+
+  if (MediaPresent == NULL) {
+    return EFI_INVALID_PARAMETER;
+  }
+  Status = gBS->LocateProtocol (
+                  &gPlatformDwMmcProtocolGuid,
+                  NULL,
+                  (VOID **) &PlatformDwMmc
+                  );
+  if (EFI_ERROR (Status)) {
+    return Status;
+  }
+  *MediaPresent = PlatformDwMmc->CardDetect (Controller, Slot);
+  return EFI_SUCCESS;
+}
+
+STATIC
+EFI_STATUS
+DwMmcHcUpdateClock (
+  IN EFI_DEVICE_IO_PROTOCOL *DevIo
+  )
+{
+  EFI_STATUS                Status;
+  UINT32                    Cmd;
+  UINT32                    IntStatus;
+
+  Cmd = BIT_CMD_WAIT_PRVDATA_COMPLETE | BIT_CMD_UPDATE_CLOCK_ONLY |
+        BIT_CMD_START;
+  Status = DwMmcHcRwMmio (DevIo, DW_MMC_CMD, FALSE, sizeof (Cmd), &Cmd);
+  if (EFI_ERROR (Status)) {
+    return Status;
+  }
+  while (1) {
+    Status = DwMmcHcRwMmio (DevIo, DW_MMC_CMD, TRUE, sizeof (Cmd), &Cmd);
+    if (EFI_ERROR (Status)) {
+      return Status;
+    }
+    if (!(Cmd & CMD_START_BIT)) {
+      break;
+    }
+    Status = DwMmcHcRwMmio (
+               DevIo,
+               DW_MMC_RINTSTS,
+               TRUE,
+               sizeof (IntStatus),
+               &IntStatus
+               );
+    if (EFI_ERROR (Status)) {
+      return Status;
+    }
+    if (IntStatus & DW_MMC_INT_HLE) {
+      DEBUG ((
+        DEBUG_ERROR,
+        "DwMmcHcUpdateClock: failed to update mmc clock frequency\n"
+        ));
+      return EFI_DEVICE_ERROR;
+    }
+  }
+  return EFI_SUCCESS;
+
+}
+
+/**
+  Stop SD/MMC card clock.
+
+  @param[in] DevIo          The DEVICE IO protocol instance.
+
+  @retval EFI_SUCCESS       Succeed to stop SD/MMC clock.
+  @retval Others            Fail to stop SD/MMC clock.
+
+**/
+EFI_STATUS
+DwMmcHcStopClock (
+  IN EFI_DEVICE_IO_PROTOCOL *DevIo
+  )
+{
+  EFI_STATUS                Status;
+  UINT32                    ClkEna;
+
+  //
+  // Disable MMC clock first
+  //
+  ClkEna = 0;
+  Status = DwMmcHcRwMmio (
+             DevIo,
+             DW_MMC_CLKENA,
+             FALSE,
+             sizeof (ClkEna),
+             &ClkEna
+             );
+  if (EFI_ERROR (Status)) {
+    return Status;
+  }
+  Status = DwMmcHcUpdateClock (DevIo);
+  if (EFI_ERROR (Status)) {
+    return Status;
+  }
+  return Status;
+}
+
+/**
+  SD/MMC card clock supply.
+
+  @param[in] DevIo          The DEVICE IO protocol instance.
+  @param[in] ClockFreq      The max clock frequency to be set. The unit is KHz.
+  @param[in] Capability     The capability of the slot.
+
+  @retval EFI_SUCCESS       The clock is supplied successfully.
+  @retval Others            The clock isn't supplied successfully.
+
+**/
+EFI_STATUS
+DwMmcHcClockSupply (
+  IN EFI_DEVICE_IO_PROTOCOL *DevIo,
+  IN UINT64                 ClockFreq,
+  IN DW_MMC_HC_SLOT_CAP     Capability
+  )
+{
+  EFI_STATUS                Status;
+  UINT32                    BaseClkFreq;
+  UINT32                    SettingFreq;
+  UINT32                    Divisor;
+  UINT32                    Remainder;
+  UINT32                    MmcStatus;
+  UINT32                    ClkEna;
+  UINT32                    ClkSrc;
+
+  //
+  // Calculate a divisor for SD clock frequency
+  //
+  ASSERT (Capability.BaseClkFreq != 0);
+
+  BaseClkFreq = Capability.BaseClkFreq;
+  if (ClockFreq == 0) {
+    return EFI_INVALID_PARAMETER;
+  }
+
+  if (ClockFreq > BaseClkFreq) {
+    ClockFreq = BaseClkFreq;
+  }
+
+  //
+  // Calculate the divisor of base frequency.
+  //
+  Divisor     = 0;
+  SettingFreq = BaseClkFreq;
+  while (ClockFreq < SettingFreq) {
+    Divisor++;
+
+    SettingFreq = BaseClkFreq / (2 * Divisor);
+    Remainder   = BaseClkFreq % (2 * Divisor);
+    if ((ClockFreq == SettingFreq) && (Remainder == 0)) {
+      break;
+    }
+    if ((ClockFreq == SettingFreq) && (Remainder != 0)) {
+      SettingFreq ++;
+    }
+  }
+
+  DEBUG ((
+    DEBUG_INFO,
+    "BaseClkFreq %dKHz Divisor %d ClockFreq %dKhz\n",
+    BaseClkFreq,
+    Divisor,
+    ClockFreq
+    ));
+
+  //
+  // Wait until MMC is idle
+  //
+  do {
+    Status = DwMmcHcRwMmio (
+               DevIo,
+               DW_MMC_STATUS,
+               TRUE,
+               sizeof (MmcStatus),
+               &MmcStatus
+               );
+    if (EFI_ERROR (Status)) {
+      return Status;
+    }
+  } while (MmcStatus & DW_MMC_STS_DATA_BUSY);
+
+  do {
+    Status = DwMmcHcStopClock (DevIo);
+  } while (EFI_ERROR (Status));
+
+  do {
+    ClkSrc = 0;
+    Status = DwMmcHcRwMmio (
+               DevIo,
+               DW_MMC_CLKSRC,
+               FALSE,
+               sizeof (ClkSrc),
+               &ClkSrc
+               );
+    if (EFI_ERROR (Status)) {
+      continue;
+    }
+    //
+    // Set clock divisor
+    //
+    Status = DwMmcHcRwMmio (
+               DevIo,
+               DW_MMC_CLKDIV,
+               FALSE,
+               sizeof (Divisor),
+               &Divisor
+               );
+    if (EFI_ERROR (Status)) {
+      continue;
+    }
+    //
+    // Enable MMC clock
+    //
+    ClkEna = 1;
+    Status = DwMmcHcRwMmio (
+               DevIo,
+               DW_MMC_CLKENA,
+               FALSE,
+               sizeof (ClkEna),
+               &ClkEna
+               );
+    if (EFI_ERROR (Status)) {
+      continue;
+    }
+    Status = DwMmcHcUpdateClock (DevIo);
+  } while (EFI_ERROR (Status));
+
+  return EFI_SUCCESS;
+}
+
+/**
+  Set the SD/MMC bus width.
+
+  Refer to SD Host Controller Simplified spec 3.0 Section 3.4 for details.
+
+  @param[in] DevIo          The DEVICE IO protocol instance.
+  @param[in] IsDdr          A boolean to indicate it's dual data rate or not.
+  @param[in] BusWidth       The bus width used by the SD/MMC device, it must be
+                            1, 4 or 8.
+
+  @retval EFI_SUCCESS       The bus width is set successfully.
+  @retval Others            The bus width isn't set successfully.
+
+**/
+EFI_STATUS
+DwMmcHcSetBusWidth (
+  IN EFI_DEVICE_IO_PROTOCOL *DevIo,
+  IN BOOLEAN                IsDdr,
+  IN UINT16                 BusWidth
+  )
+{
+  EFI_STATUS                Status;
+  UINT32                    Ctype;
+  UINT32                    Uhs;
+
+  switch (BusWidth) {
+  case 1:
+    Ctype = MMC_1BIT_MODE;
+    break;
+  case 4:
+    Ctype = MMC_4BIT_MODE;
+    break;
+  case 8:
+    Ctype = MMC_8BIT_MODE;
+    break;
+  default:
+    return EFI_INVALID_PARAMETER;
+  }
+  Status = DwMmcHcRwMmio (
+             DevIo,
+             DW_MMC_CTYPE,
+             FALSE,
+             sizeof (Ctype),
+             &Ctype
+             );
+  if (EFI_ERROR (Status)) {
+    return Status;
+  }
+  Status = DwMmcHcRwMmio (DevIo, DW_MMC_UHSREG, TRUE, sizeof (Uhs), &Uhs);
+  if (EFI_ERROR (Status)) {
+    return Status;
+  }
+  if (IsDdr) {
+    Uhs |= UHS_DDR_MODE;
+  } else {
+    Uhs &= ~(UHS_DDR_MODE);
+  }
+  Status = DwMmcHcRwMmio (
+             DevIo,
+             DW_MMC_UHSREG,
+             FALSE,
+             sizeof (Uhs),
+             &Uhs
+             );
+  return Status;
+}
+
+/**
+  Supply SD/MMC card with lowest clock frequency at initialization.
+
+  @param[in] DevIo          The DEVICE IO protocol instance.
+  @param[in] Capability     The capability of the slot.
+
+  @retval EFI_SUCCESS       The clock is supplied successfully.
+  @retval Others            The clock isn't supplied successfully.
+
+**/
+EFI_STATUS
+DwMmcHcInitClockFreq (
+  IN EFI_DEVICE_IO_PROTOCOL    *DevIo,
+  IN DW_MMC_HC_SLOT_CAP        Capability
+  )
+{
+  EFI_STATUS                Status;
+  UINT32                    InitFreq;
+
+  //
+  // Calculate a divisor for SD clock frequency
+  //
+  if (Capability.BaseClkFreq == 0) {
+    //
+    // Don't support get Base Clock Frequency information via another method
+    //
+    return EFI_UNSUPPORTED;
+  }
+  //
+  // Supply 400KHz clock frequency at initialization phase.
+  //
+  InitFreq = DWMMC_INIT_CLOCK_FREQ;
+  Status = DwMmcHcClockSupply (DevIo, InitFreq, Capability);
+  if (EFI_ERROR (Status)) {
+    return Status;
+  }
+  MicroSecondDelay (100);
+  return Status;
+}
+
+/**
+  Supply SD/MMC card with maximum voltage at initialization.
+
+  @param[in] DevIo          The DEVICE IO protocol instance.
+  @param[in] Capability     The capability of the slot.
+
+  @retval EFI_SUCCESS       The voltage is supplied successfully.
+  @retval Others            The voltage isn't supplied successfully.
+
+**/
+EFI_STATUS
+DwMmcHcInitPowerVoltage (
+  IN EFI_DEVICE_IO_PROTOCOL *DevIo,
+  IN DW_MMC_HC_SLOT_CAP     Capability
+  )
+{
+  EFI_STATUS                Status;
+  UINT32                    Data;
+
+  Data = 0x1;
+  Status  = DwMmcHcRwMmio (
+              DevIo,
+              DW_MMC_PWREN,
+              FALSE,
+              sizeof (Data),
+              &Data
+              );
+  if (EFI_ERROR (Status)) {
+    DEBUG ((
+      DEBUG_ERROR,
+      "DwMmcHcInitPowerVoltage: enable power fails: %r\n",
+      Status
+      ));
+    return Status;
+  }
+
+  Data = DW_MMC_CTRL_RESET_ALL;
+  Status = DwMmcHcRwMmio (
+             DevIo,
+             DW_MMC_CTRL,
+             FALSE,
+             sizeof (Data),
+             &Data
+             );
+  if (EFI_ERROR (Status)) {
+    DEBUG ((DEBUG_ERROR, "DwMmcHcInitPowerVoltage: reset fails: %r\n", Status));
+    return Status;
+  }
+  Status = DwMmcHcWaitMmioSet (
+             DevIo,
+             DW_MMC_CTRL,
+             sizeof (Data),
+             DW_MMC_CTRL_RESET_ALL,
+             0x00,
+             DW_MMC_HC_GENERIC_TIMEOUT
+             );
+  if (EFI_ERROR (Status)) {
+    DEBUG ((
+      DEBUG_INFO,
+      "DwMmcHcInitPowerVoltage: reset done with %r\n",
+      Status
+      ));
+    return Status;
+  }
+
+  Data = DW_MMC_CTRL_INT_EN;
+  Status = DwMmcHcRwMmio (
+             DevIo,
+             DW_MMC_CTRL,
+             FALSE,
+             sizeof (Data),
+             &Data
+             );
+  return Status;
+}
+
+/**
+  Initialize the Timeout Control register with most conservative value at
+  initialization.
+
+  @param[in] DevIo          The DEVICE IO protocol instance.
+
+  @retval EFI_SUCCESS       The timeout control register is configured
+                            successfully.
+  @retval Others            The timeout control register isn't configured
+                            successfully.
+
+**/
+EFI_STATUS
+DwMmcHcInitTimeoutCtrl (
+  IN EFI_DEVICE_IO_PROTOCOL *DevIo
+  )
+{
+  EFI_STATUS                Status;
+  UINT32                    Data;
+
+  Data = ~0;
+  Status = DwMmcHcRwMmio (
+             DevIo,
+             DW_MMC_TMOUT,
+             FALSE,
+             sizeof (Data),
+             &Data
+             );
+  if (EFI_ERROR (Status)) {
+    DEBUG ((
+      DEBUG_ERROR,
+      "DwMmcHcInitTimeoutCtrl: set timeout fails: %r\n",
+      Status
+      ));
+    return Status;
+  }
+
+  Data = 0x00FFFFFF;
+  Status = DwMmcHcRwMmio (
+             DevIo,
+             DW_MMC_DEBNCE,
+             FALSE,
+             sizeof (Data),
+             &Data
+             );
+  return Status;
+}
+
+/**
+  Initial SD/MMC host controller with lowest clock frequency, max power and
+  max timeout value at initialization.
+
+  @param[in] DevIo          The DEVICE IO protocol instance.
+  @param[in] Slot           The slot number of the SD card to send the command
+                            to.
+  @param[in] Capability     The capability of the slot.
+
+  @retval EFI_SUCCESS       The host controller is initialized successfully.
+  @retval Others            The host controller isn't initialized successfully.
+
+**/
+EFI_STATUS
+DwMmcHcInitHost (
+  IN EFI_DEVICE_IO_PROTOCOL    *DevIo,
+  IN DW_MMC_HC_SLOT_CAP        Capability
+  )
+{
+  EFI_STATUS       Status;
+
+  Status = DwMmcHcInitPowerVoltage (DevIo, Capability);
+  if (EFI_ERROR (Status)) {
+    return Status;
+  }
+  return Status;
+}
+
+EFI_STATUS
+DwMmcHcStartDma (
+  IN DW_MMC_HC_PRIVATE_DATA           *Private,
+  IN DW_MMC_HC_TRB                    *Trb
+  )
+{
+  EFI_STATUS                          Status;
+  EFI_DEVICE_IO_PROTOCOL              *DevIo;
+  UINT32                              Ctrl;
+  UINT32                              Bmod;
+
+  DevIo  = Trb->Private->DevIo;
+
+  //
+  // Reset DMA
+  //
+  Ctrl = DW_MMC_CTRL_DMA_RESET;
+  Status = DwMmcHcRwMmio (
+             DevIo,
+             DW_MMC_CTRL,
+             FALSE,
+             sizeof (Ctrl),
+             &Ctrl
+             );
+  if (EFI_ERROR (Status)) {
+    DEBUG ((DEBUG_ERROR, "DwMmcHcStartDma: reset fails: %r\n", Status));
+    return Status;
+  }
+  Status = DwMmcHcWaitMmioSet (
+             DevIo,
+             DW_MMC_CTRL,
+             sizeof (Ctrl),
+             DW_MMC_CTRL_DMA_RESET,
+             0x00,
+             DW_MMC_HC_GENERIC_TIMEOUT
+             );
+  if (EFI_ERROR (Status)) {
+    DEBUG ((DEBUG_INFO, "DwMmcHcStartDma: reset done with %r\n", Status));
+    return Status;
+  }
+  Bmod = DW_MMC_IDMAC_SWRESET;
+  Status = DwMmcHcOrMmio (DevIo, DW_MMC_BMOD, sizeof (Bmod), &Bmod);
+  if (EFI_ERROR (Status)) {
+    DEBUG ((DEBUG_ERROR, "DwMmcHcStartDma: set BMOD fail: %r\n", Status));
+    return Status;
+  }
+
+  //
+  // Select IDMAC
+  //
+  Ctrl = DW_MMC_CTRL_IDMAC_EN;
+  Status = DwMmcHcOrMmio (DevIo, DW_MMC_CTRL, sizeof (Ctrl), &Ctrl);
+  if (EFI_ERROR (Status)) {
+    DEBUG ((DEBUG_ERROR, "DwMmcHcStartDma: init IDMAC fail: %r\n", Status));
+    return Status;
+  }
+
+  //
+  // Enable IDMAC
+  //
+  Bmod = DW_MMC_IDMAC_ENABLE | DW_MMC_IDMAC_FB;
+  Status = DwMmcHcOrMmio (DevIo, DW_MMC_BMOD, sizeof (Bmod), &Bmod);
+  if (EFI_ERROR (Status)) {
+    DEBUG ((DEBUG_ERROR, "DwMmcHcStartDma: set BMOD failure: %r\n", Status));
+    return Status;
+  }
+  return Status;
+}
+
+EFI_STATUS
+DwMmcHcStopDma (
+  IN DW_MMC_HC_PRIVATE_DATA           *Private,
+  IN DW_MMC_HC_TRB                    *Trb
+  )
+{
+  EFI_STATUS                          Status;
+  EFI_DEVICE_IO_PROTOCOL              *DevIo;
+  UINT32                              Ctrl;
+  UINT32                              Bmod;
+
+  DevIo  = Trb->Private->DevIo;
+
+  //
+  // Disable and reset IDMAC
+  //
+  Status = DwMmcHcRwMmio (
+             DevIo,
+             DW_MMC_CTRL,
+             TRUE,
+             sizeof (Ctrl),
+             &Ctrl
+             );
+  if (EFI_ERROR (Status)) {
+    return Status;
+  }
+  Ctrl &= ~DW_MMC_CTRL_IDMAC_EN;
+  Ctrl |= DW_MMC_CTRL_DMA_RESET;
+  Status = DwMmcHcRwMmio (
+             DevIo,
+             DW_MMC_CTRL,
+             FALSE,
+             sizeof (Ctrl),
+             &Ctrl
+             );
+  if (EFI_ERROR (Status)) {
+    return Status;
+  }
+  //
+  // Stop IDMAC
+  //
+  Status = DwMmcHcRwMmio (
+             DevIo,
+             DW_MMC_BMOD,
+             TRUE,
+             sizeof (Bmod),
+             &Bmod
+             );
+  if (EFI_ERROR (Status)) {
+    return Status;
+  }
+  Bmod &= ~(DW_MMC_BMOD_FB | DW_MMC_BMOD_DE);
+  Bmod |= DW_MMC_BMOD_SWR;
+  Status = DwMmcHcRwMmio (
+             DevIo,
+             DW_MMC_BMOD,
+             FALSE,
+             sizeof (Bmod),
+             &Bmod
+             );
+  if (EFI_ERROR (Status)) {
+    return Status;
+  }
+  return Status;
+}
+
+/**
+  Build DMA descriptor table for transfer.
+
+  @param[in] Trb            The pointer to the DW_MMC_HC_TRB instance.
+
+  @retval EFI_SUCCESS       The DMA descriptor table is created successfully.
+  @retval Others            The DMA descriptor table isn't created successfully.
+
+**/
+EFI_STATUS
+BuildDmaDescTable (
+  IN DW_MMC_HC_TRB          *Trb
+  )
+{
+  EFI_PHYSICAL_ADDRESS      Data;
+  UINT64                    DataLen;
+  UINT64                    Entries;
+  UINT32                    Index;
+  UINT64                    Remaining;
+  UINTN                     TableSize;
+  EFI_DEVICE_IO_PROTOCOL    *DevIo;
+  EFI_STATUS                Status;
+  UINTN                     Bytes;
+  UINTN                     Blocks;
+  DW_MMC_HC_DMA_DESC_LINE   *DmaDesc;
+  UINT32                    DmaDescPhy;
+  UINT32                    Idsts;
+  UINT32                    BytCnt;
+  UINT32                    BlkSize;
+
+  Data    = Trb->DataPhy;
+  DataLen = Trb->DataLen;
+  DevIo   = Trb->Private->DevIo;
+  //
+  // Only support 32bit DMA Descriptor Table
+  //
+  if ((Data >= 0x100000000ul) || ((Data + DataLen) > 0x100000000ul)) {
+    return EFI_INVALID_PARAMETER;
+  }
+  //
+  // Address field shall be set on 32-bit boundary (Lower 2-bit is always set
+  // to 0) for 32-bit address descriptor table.
+  //
+  if ((Data & (BIT0 | BIT1)) != 0) {
+    DEBUG ((
+      DEBUG_INFO,
+      "The buffer [0x%x] to construct DMA desc is not aligned to 4 bytes!\n",
+      Data
+      ));
+  }
+
+  Entries   = (DataLen + DWMMC_DMA_BUF_SIZE - 1) / DWMMC_DMA_BUF_SIZE;
+  TableSize = Entries * sizeof (DW_MMC_HC_DMA_DESC_LINE);
+  Blocks    = (DataLen + DW_MMC_BLOCK_SIZE - 1) / DW_MMC_BLOCK_SIZE;
+
+  Trb->DmaDescPages = (UINT32)EFI_SIZE_TO_PAGES (Entries * DWMMC_DMA_BUF_SIZE);
+  Status = DevIo->AllocateBuffer (
+                    DevIo,
+                    AllocateAnyPages,
+                    EfiBootServicesData,
+                    EFI_SIZE_TO_PAGES (TableSize),
+                    (EFI_PHYSICAL_ADDRESS *)&Trb->DmaDesc
+                    );
+  if (EFI_ERROR (Status)) {
+    return EFI_OUT_OF_RESOURCES;
+  }
+  ZeroMem (Trb->DmaDesc, TableSize);
+  Bytes  = TableSize;
+  Status = DevIo->Map (
+                    DevIo,
+                    EfiBusMasterCommonBuffer,
+                    (EFI_PHYSICAL_ADDRESS *)Trb->DmaDesc,
+                    &Bytes,
+                    &Trb->DmaDescPhy,
+                    &Trb->DmaMap
+                    );
+
+  if (EFI_ERROR (Status) || (Bytes != TableSize)) {
+    //
+    // Map error or unable to map the whole RFis buffer into a contiguous
+    // region.
+    //
+    DevIo->FreeBuffer (
+             DevIo,
+             EFI_SIZE_TO_PAGES (TableSize),
+             (EFI_PHYSICAL_ADDRESS)Trb->DmaDesc
+             );
+    return EFI_OUT_OF_RESOURCES;
+  }
+
+  if ((UINT64)(UINTN)Trb->DmaDescPhy > 0x100000000ul) {
+    //
+    // The DMA doesn't support 64bit addressing.
+    //
+    DevIo->Unmap (
+      DevIo,
+      Trb->DmaMap
+    );
+    return EFI_DEVICE_ERROR;
+  }
+
+  if (DataLen < DW_MMC_BLOCK_SIZE) {
+    BlkSize = DataLen;
+    BytCnt = DataLen;
+    Remaining = DataLen;
+  } else {
+    BlkSize = DW_MMC_BLOCK_SIZE;
+    BytCnt = DW_MMC_BLOCK_SIZE * Blocks;
+    Remaining = DW_MMC_BLOCK_SIZE * Blocks;
+  }
+  Status = DwMmcHcRwMmio (
+             DevIo,
+             DW_MMC_BLKSIZ,
+             FALSE,
+             sizeof (BlkSize),
+             &BlkSize
+             );
+  if (EFI_ERROR (Status)) {
+    DEBUG ((
+      DEBUG_ERROR,
+      "BuildDmaDescTable: set block size fails: %r\n",
+      Status
+      ));
+    return Status;
+  }
+  Status = DwMmcHcRwMmio (
+             DevIo,
+             DW_MMC_BYTCNT,
+             FALSE,
+             sizeof (BytCnt),
+             &BytCnt
+             );
+  if (EFI_ERROR (Status)) {
+    return Status;
+  }
+  DmaDesc = Trb->DmaDesc;
+  for (Index = 0; Index < Entries; Index++, DmaDesc++) {
+    DmaDesc->Des0 = DW_MMC_IDMAC_DES0_OWN | DW_MMC_IDMAC_DES0_CH |
+                    DW_MMC_IDMAC_DES0_DIC;
+    DmaDesc->Des1 = DW_MMC_IDMAC_DES1_BS1 (DWMMC_DMA_BUF_SIZE);
+    //
+    // Buffer Address
+    //
+    DmaDesc->Des2 = (UINT32)((UINTN)Trb->DataPhy +
+                    (DWMMC_DMA_BUF_SIZE * Index));
+    //
+    // Next Descriptor Address
+    //
+    DmaDesc->Des3 = (UINT32)((UINTN)Trb->DmaDescPhy +
+                    sizeof (DW_MMC_HC_DMA_DESC_LINE) * (Index + 1));
+    Remaining = Remaining - DWMMC_DMA_BUF_SIZE;
+  }
+  //
+  // First Descriptor
+  //
+  Trb->DmaDesc[0].Des0 |= DW_MMC_IDMAC_DES0_FS;
+  //
+  // Last Descriptor
+  //
+  Trb->DmaDesc[Entries - 1].Des0 &= ~(DW_MMC_IDMAC_DES0_CH |
+                                    DW_MMC_IDMAC_DES0_DIC);
+  Trb->DmaDesc[Entries - 1].Des0 |= DW_MMC_IDMAC_DES0_OWN |
+                                    DW_MMC_IDMAC_DES0_LD;
+  Trb->DmaDesc[Entries - 1].Des1 = DW_MMC_IDMAC_DES1_BS1 (Remaining +
+                                   DWMMC_DMA_BUF_SIZE);
+  //
+  // Set the next field of the Last Descriptor
+  //
+  Trb->DmaDesc[Entries - 1].Des3 = 0;
+  DmaDescPhy = (UINT32)Trb->DmaDescPhy;
+  Status = DwMmcHcRwMmio (
+             DevIo,
+             DW_MMC_DBADDR,
+             FALSE,
+             sizeof (DmaDescPhy),
+             &DmaDescPhy
+             );
+  if (EFI_ERROR (Status)) {
+    return Status;
+  }
+  ArmDataSynchronizationBarrier ();
+  ArmInstructionSynchronizationBarrier ();
+  //
+  // Clear interrupts
+  //
+  Idsts = ~0;
+  Status = DwMmcHcRwMmio (
+             DevIo,
+             DW_MMC_IDSTS,
+             FALSE,
+             sizeof (Idsts),
+             &Idsts
+             );
+  return Status;
+}
+
+EFI_STATUS
+ReadFifo (
+  IN DW_MMC_HC_TRB          *Trb
+  )
+{
+  EFI_STATUS                Status;
+  EFI_DEVICE_IO_PROTOCOL    *DevIo;
+  UINT32                    Data;
+  UINT32                    Received;
+  UINT32                    Count;
+  UINT32                    Intsts;
+  UINT32                    Sts;
+  UINT32                    FifoCount;
+  UINT32                    Index;     /* count with bytes */
+  UINT32                    Ascending;
+  UINT32                    Descending;
+
+  DevIo   = Trb->Private->DevIo;
+  Received = 0;
+  Count = 0;
+  Index = 0;
+  Ascending = 0;
+  Descending = ((Trb->DataLen + 3) & ~3) - 4;
+  do {
+    Status = DwMmcHcRwMmio (
+               DevIo,
+               DW_MMC_RINTSTS,
+               TRUE,
+               sizeof (Intsts),
+               &Intsts
+               );
+    if (EFI_ERROR (Status)) {
+      DEBUG ((
+        DEBUG_ERROR,
+        "ReadFifo: failed to read RINTSTS, Status:%r\n",
+        Status
+        ));
+      return Status;
+    }
+    if (Trb->DataLen && ((Intsts & DW_MMC_INT_RXDR) ||
+       (Intsts & DW_MMC_INT_DTO))) {
+      Status = DwMmcHcRwMmio (
+                 DevIo,
+                 DW_MMC_STATUS,
+                 TRUE,
+                 sizeof (Sts),
+                 &Sts
+                 );
+      if (EFI_ERROR (Status)) {
+        DEBUG ((
+          DEBUG_ERROR,
+          "ReadFifo: failed to read STATUS, Status:%r\n",
+          Status
+          ));
+        return Status;
+      }
+      //
+      // Convert to bytes
+      //
+      FifoCount = GET_STS_FIFO_COUNT (Sts) << 2;
+      if ((FifoCount == 0) && (Received < Trb->DataLen)) {
+        continue;
+      }
+      Index = 0;
+      Count = (MIN (FifoCount, Trb->DataLen) + 3) & ~3;
+      while (Index < Count) {
+        Status = DwMmcHcRwMmio (
+                   DevIo,
+                   DW_MMC_FIFO_START,
+                   TRUE,
+                   sizeof (Data),
+                   &Data
+                   );
+        if (EFI_ERROR (Status)) {
+          DEBUG ((
+            DEBUG_ERROR,
+            "ReadFifo: failed to read FIFO, Status:%r\n",
+            Status
+            ));
+          return Status;
+        }
+        if (Trb->UseBE) {
+          *(UINT32 *)((UINTN)Trb->Data + Descending) = SwapBytes32 (Data);
+          Descending = Descending - 4;
+        } else {
+          *(UINT32 *)((UINTN)Trb->Data + Ascending) = Data;
+          Ascending += 4;
+        }
+        Index += 4;
+        Received += 4;
+      } /* while */
+    } /* if */
+  } while (((Intsts & DW_MMC_INT_CMD_DONE) == 0) || (Received < Trb->DataLen));
+  //
+  // Clear RINTSTS
+  //
+  Intsts = ~0;
+  Status = DwMmcHcRwMmio (
+             DevIo,
+             DW_MMC_RINTSTS,
+             FALSE,
+             sizeof (Intsts),
+             &Intsts
+             );
+  if (EFI_ERROR (Status)) {
+    DEBUG ((
+      DEBUG_ERROR,
+      "ReadFifo: failed to write RINTSTS, Status:%r\n",
+      Status
+      ));
+    return Status;
+  }
+  return EFI_SUCCESS;
+}
+
+/**
+  Create a new TRB for the SD/MMC cmd request.
+
+  @param[in] Private        A pointer to the DW_MMC_HC_PRIVATE_DATA instance.
+  @param[in] Slot           The slot number of the SD card to send the command
+                            to.
+  @param[in] Packet         A pointer to the SD command data structure.
+  @param[in] Event          If Event is NULL, blocking I/O is performed. If
+                            Event is not NULL, then nonblocking I/O is
+                            performed, and Event will be signaled when the
+                            Packet completes.
+
+  @return Created Trb or NULL.
+
+**/
+DW_MMC_HC_TRB *
+DwMmcCreateTrb (
+  IN DW_MMC_HC_PRIVATE_DATA              *Private,
+  IN UINT8                               Slot,
+  IN EFI_SD_MMC_PASS_THRU_COMMAND_PACKET *Packet,
+  IN EFI_EVENT                           Event
+  )
+{
+  DW_MMC_HC_TRB                 *Trb;
+  EFI_STATUS                    Status;
+  EFI_TPL                       OldTpl;
+  EFI_IO_OPERATION_TYPE         Flag;
+  EFI_DEVICE_IO_PROTOCOL        *DevIo;
+  UINTN                         MapLength;
+
+  Trb = AllocateZeroPool (sizeof (DW_MMC_HC_TRB));
+  if (Trb == NULL) {
+    return NULL;
+  }
+
+  Trb->Signature = DW_MMC_HC_TRB_SIG;
+  Trb->Slot      = Slot;
+  Trb->BlockSize = 0x200;
+  Trb->Packet    = Packet;
+  Trb->Event     = Event;
+  Trb->Started   = FALSE;
+  Trb->Timeout   = Packet->Timeout;
+  Trb->Private   = Private;
+
+  if ((Packet->InTransferLength != 0) && (Packet->InDataBuffer != NULL)) {
+    Trb->Data    = Packet->InDataBuffer;
+    Trb->DataLen = Packet->InTransferLength;
+    Trb->Read    = TRUE;
+    ZeroMem (Trb->Data, Trb->DataLen);
+  } else if (Packet->OutTransferLength && (Packet->OutDataBuffer != NULL)) {
+    Trb->Data    = Packet->OutDataBuffer;
+    Trb->DataLen = Packet->OutTransferLength;
+    Trb->Read    = FALSE;
+  } else if (!Packet->InTransferLength && !Packet->OutTransferLength) {
+    Trb->Data    = NULL;
+    Trb->DataLen = 0;
+  } else {
+    goto Error;
+  }
+
+  if (((Private->Slot[Trb->Slot].CardType == EmmcCardType) &&
+       (Packet->SdMmcCmdBlk->CommandIndex == EMMC_SEND_TUNING_BLOCK)) ||
+      ((Private->Slot[Trb->Slot].CardType == SdCardType) &&
+       (Packet->SdMmcCmdBlk->CommandIndex == SD_SEND_TUNING_BLOCK))) {
+    Trb->Mode = SdMmcPioMode;
+  } else {
+    if (Trb->Read) {
+      Flag = EfiBusMasterWrite;
+    } else {
+      Flag = EfiBusMasterRead;
+    }
+
+    DevIo = Private->DevIo;
+    if (Private->Slot[Trb->Slot].CardType == SdCardType) {
+      Trb->UseFifo = TRUE;
+    } else {
+      Trb->UseFifo = FALSE;
+      if (Trb->DataLen) {
+        MapLength = Trb->DataLen;
+        Status = DevIo->Map (
+                          DevIo,
+                          Flag,
+                          Trb->Data,
+                          &MapLength,
+                          &Trb->DataPhy,
+                          &Trb->DataMap
+                          );
+        if (EFI_ERROR (Status) || (Trb->DataLen != MapLength)) {
+          Status = EFI_BAD_BUFFER_SIZE;
+          goto Error;
+        }
+
+        Status = BuildDmaDescTable (Trb);
+        if (EFI_ERROR (Status)) {
+          DevIo->Unmap (DevIo, Trb->DataMap);
+          goto Error;
+        }
+        Status = DwMmcHcStartDma (Private, Trb);
+        if (EFI_ERROR (Status)) {
+          DevIo->Unmap (DevIo, Trb->DataMap);
+          goto Error;
+        }
+      }
+    }
+  } /* TuningBlock */
+
+  if (Event != NULL) {
+    OldTpl = gBS->RaiseTPL (TPL_NOTIFY);
+    InsertTailList (&Private->Queue, &Trb->TrbList);
+    gBS->RestoreTPL (OldTpl);
+  }
+
+  return Trb;
+
+Error:
+  return NULL;
+}
+
+/**
+  Free the resource used by the TRB.
+
+  @param[in] Trb            The pointer to the DW_MMC_HC_TRB instance.
+
+**/
+VOID
+DwMmcFreeTrb (
+  IN DW_MMC_HC_TRB           *Trb
+  )
+{
+  EFI_DEVICE_IO_PROTOCOL     *DevIo;
+
+  DevIo = Trb->Private->DevIo;
+
+  if (Trb->DmaMap != NULL) {
+    DevIo->Unmap (DevIo, Trb->DmaMap);
+  }
+  if (Trb->DataMap != NULL) {
+    DevIo->Unmap (DevIo, Trb->DataMap);
+  }
+  FreePool (Trb);
+}
+
+/**
+  Check if the env is ready for execute specified TRB.
+
+  @param[in] Private        A pointer to the DW_MMC_HC_PRIVATE_DATA instance.
+  @param[in] Trb            The pointer to the DW_MMC_HC_TRB instance.
+
+  @retval EFI_SUCCESS       The env is ready for TRB execution.
+  @retval EFI_NOT_READY     The env is not ready for TRB execution.
+  @retval Others            Some erros happen.
+
+**/
+EFI_STATUS
+DwMmcCheckTrbEnv (
+  IN DW_MMC_HC_PRIVATE_DATA           *Private,
+  IN DW_MMC_HC_TRB                    *Trb
+  )
+{
+  return EFI_SUCCESS;
+}
+
+/**
+  Wait for the env to be ready for execute specified TRB.
+
+  @param[in] Private        A pointer to the DW_MMC_HC_PRIVATE_DATA instance.
+  @param[in] Trb            The pointer to the DW_MMC_HC_TRB instance.
+
+  @retval EFI_SUCCESS       The env is ready for TRB execution.
+  @retval EFI_TIMEOUT       The env is not ready for TRB execution in time.
+  @retval Others            Some erros happen.
+
+**/
+EFI_STATUS
+DwMmcWaitTrbEnv (
+  IN DW_MMC_HC_PRIVATE_DATA           *Private,
+  IN DW_MMC_HC_TRB                    *Trb
+  )
+{
+  EFI_STATUS                          Status;
+  EFI_SD_MMC_PASS_THRU_COMMAND_PACKET *Packet;
+  UINT64                              Timeout;
+  BOOLEAN                             InfiniteWait;
+
+  //
+  // Wait Command Complete Interrupt Status bit in Normal Interrupt Status
+  // Register
+  //
+  Packet  = Trb->Packet;
+  Timeout = Packet->Timeout;
+  if (Timeout == 0) {
+    InfiniteWait = TRUE;
+  } else {
+    InfiniteWait = FALSE;
+  }
+
+  while (InfiniteWait || (Timeout > 0)) {
+    //
+    // Check Trb execution result by reading Normal Interrupt Status register.
+    //
+    Status = DwMmcCheckTrbEnv (Private, Trb);
+    if (Status != EFI_NOT_READY) {
+      return Status;
+    }
+    //
+    // Stall for 1 microsecond.
+    //
+    gBS->Stall (1);
+
+    Timeout--;
+  }
+
+  return EFI_TIMEOUT;
+}
+
+EFI_STATUS
+DwEmmcExecTrb (
+  IN DW_MMC_HC_PRIVATE_DATA           *Private,
+  IN DW_MMC_HC_TRB                    *Trb
+  )
+{
+  EFI_STATUS                          Status;
+  EFI_SD_MMC_PASS_THRU_COMMAND_PACKET *Packet;
+  EFI_DEVICE_IO_PROTOCOL              *DevIo;
+  UINT32                              Cmd;
+  UINT32                              MmcStatus;
+  UINT32                              IntStatus;
+  UINT32                              Argument;
+  UINT32                              ErrMask;
+  UINT32                              Timeout;
+
+  Packet = Trb->Packet;
+  DevIo  = Trb->Private->DevIo;
+
+  ArmDataSynchronizationBarrier ();
+  ArmInstructionSynchronizationBarrier ();
+  //
+  // Wait until MMC is idle
+  //
+  do {
+    Status = DwMmcHcRwMmio (
+               DevIo,
+               DW_MMC_STATUS,
+               TRUE,
+               sizeof (MmcStatus),
+               &MmcStatus
+               );
+    if (EFI_ERROR (Status)) {
+      return Status;
+    }
+  } while (MmcStatus & DW_MMC_STS_DATA_BUSY);
+
+  IntStatus = ~0;
+  Status = DwMmcHcRwMmio (
+             DevIo,
+             DW_MMC_RINTSTS,
+             FALSE,
+             sizeof (IntStatus),
+             &IntStatus
+             );
+  if (EFI_ERROR (Status)) {
+    return Status;
+  }
+  Cmd = CMD_INDEX (Packet->SdMmcCmdBlk->CommandIndex);
+  if ((Packet->SdMmcCmdBlk->CommandType == SdMmcCommandTypeAc) ||
+      (Packet->SdMmcCmdBlk->CommandType == SdMmcCommandTypeAdtc)) {
+    switch (Packet->SdMmcCmdBlk->CommandIndex) {
+    case EMMC_SET_RELATIVE_ADDR:
+      Cmd |= BIT_CMD_SEND_INIT;
+      break;
+    case EMMC_SEND_STATUS:
+      Cmd |= BIT_CMD_WAIT_PRVDATA_COMPLETE;
+      break;
+    case EMMC_STOP_TRANSMISSION:
+      Cmd |= BIT_CMD_STOP_ABORT_CMD;
+      break;
+    }
+    if (Packet->InTransferLength) {
+      Cmd |= BIT_CMD_WAIT_PRVDATA_COMPLETE | BIT_CMD_DATA_EXPECTED |
+             BIT_CMD_READ;
+    } else if (Packet->OutTransferLength) {
+      Cmd |= BIT_CMD_WAIT_PRVDATA_COMPLETE | BIT_CMD_DATA_EXPECTED |
+             BIT_CMD_WRITE;
+    }
+    Cmd |= BIT_CMD_RESPONSE_EXPECT | BIT_CMD_CHECK_RESPONSE_CRC;
+  } else {
+    switch (Packet->SdMmcCmdBlk->CommandIndex) {
+    case EMMC_GO_IDLE_STATE:
+      Cmd |= BIT_CMD_SEND_INIT;
+      break;
+    case EMMC_SEND_OP_COND:
+      Cmd |= BIT_CMD_RESPONSE_EXPECT;
+      break;
+    case EMMC_ALL_SEND_CID:
+      Cmd |= BIT_CMD_RESPONSE_EXPECT | BIT_CMD_LONG_RESPONSE |
+             BIT_CMD_CHECK_RESPONSE_CRC | BIT_CMD_SEND_INIT;
+      break;
+    }
+  }
+  switch (Packet->SdMmcCmdBlk->ResponseType) {
+  case SdMmcResponseTypeR2:
+    Cmd |= BIT_CMD_RESPONSE_EXPECT | BIT_CMD_CHECK_RESPONSE_CRC |
+           BIT_CMD_LONG_RESPONSE;
+    break;
+  case SdMmcResponseTypeR3:
+    Cmd |= BIT_CMD_RESPONSE_EXPECT;
+    break;
+  }
+  Cmd |= BIT_CMD_USE_HOLD_REG | BIT_CMD_START;
+
+  Argument = Packet->SdMmcCmdBlk->CommandArgument;
+  Status = DwMmcHcRwMmio (
+             DevIo,
+             DW_MMC_CMDARG,
+             FALSE,
+             sizeof (Argument),
+             &Argument
+             );
+  if (EFI_ERROR (Status)) {
+    return Status;
+  }
+  ArmDataSynchronizationBarrier ();
+  ArmInstructionSynchronizationBarrier ();
+  Status = DwMmcHcRwMmio (
+             DevIo,
+             DW_MMC_CMD,
+             FALSE,
+             sizeof (Cmd),
+             &Cmd
+             );
+  if (EFI_ERROR (Status)) {
+    return Status;
+  }
+  ArmDataSynchronizationBarrier ();
+  ArmInstructionSynchronizationBarrier ();
+
+  ErrMask = DW_MMC_INT_EBE | DW_MMC_INT_HLE | DW_MMC_INT_RTO |
+            DW_MMC_INT_RCRC | DW_MMC_INT_RE;
+  ErrMask |= DW_MMC_INT_DCRC | DW_MMC_INT_DRT | DW_MMC_INT_SBE;
+  do {
+    Timeout = 10000;
+    if (--Timeout == 0) {
+      break;
+    }
+    Status = DwMmcHcRwMmio (
+               DevIo,
+               DW_MMC_RINTSTS,
+               TRUE,
+               sizeof (IntStatus),
+               &IntStatus
+               );
+    if (EFI_ERROR (Status)) {
+      return Status;
+    }
+    if (IntStatus & ErrMask) {
+      return EFI_DEVICE_ERROR;
+    }
+    if (Trb->DataLen && ((IntStatus & DW_MMC_INT_DTO) == 0)) {
+      //
+      // Transfer Not Done
+      //
+      MicroSecondDelay (10);
+      continue;
+    }
+    MicroSecondDelay (10);
+  } while (!(IntStatus & DW_MMC_INT_CMD_DONE));
+  switch (Packet->SdMmcCmdBlk->ResponseType) {
+    case SdMmcResponseTypeR1:
+    case SdMmcResponseTypeR1b:
+    case SdMmcResponseTypeR3:
+    case SdMmcResponseTypeR4:
+    case SdMmcResponseTypeR5:
+      Status = DwMmcHcRwMmio (
+                 DevIo,
+                 DW_MMC_RESP0,
+                 TRUE,
+                 sizeof (Packet->SdMmcStatusBlk->Resp0),
+                 &Packet->SdMmcStatusBlk->Resp0
+                 );
+      if (EFI_ERROR (Status)) {
+        return Status;
+      }
+      break;
+    case SdMmcResponseTypeR2:
+      Status = DwMmcHcRwMmio (
+                 DevIo,
+                 DW_MMC_RESP0,
+                 TRUE,
+                 sizeof (Packet->SdMmcStatusBlk->Resp0),
+                 &Packet->SdMmcStatusBlk->Resp0
+                 );
+      if (EFI_ERROR (Status)) {
+        return Status;
+      }
+      Status = DwMmcHcRwMmio (
+                 DevIo,
+                 DW_MMC_RESP1,
+                 TRUE,
+                 sizeof (Packet->SdMmcStatusBlk->Resp1),
+                 &Packet->SdMmcStatusBlk->Resp1
+                 );
+      if (EFI_ERROR (Status)) {
+        return Status;
+      }
+      Status = DwMmcHcRwMmio (
+                 DevIo,
+                 DW_MMC_RESP2,
+                 TRUE,
+                 sizeof (Packet->SdMmcStatusBlk->Resp2),
+                 &Packet->SdMmcStatusBlk->Resp2
+                 );
+      if (EFI_ERROR (Status)) {
+        return Status;
+      }
+      Status = DwMmcHcRwMmio (
+                 DevIo,
+                 DW_MMC_RESP3,
+                 TRUE,
+                 sizeof (Packet->SdMmcStatusBlk->Resp3),
+                 &Packet->SdMmcStatusBlk->Resp3
+                 );
+      if (EFI_ERROR (Status)) {
+        return Status;
+      }
+      break;
+  }
+
+  //
+  // The workaround on EMMC_SEND_CSD is used to be compatible with SDHC.
+  //
+  if (Packet->SdMmcCmdBlk->CommandIndex == EMMC_SEND_CSD) {
+    {
+      UINT32   Buf[4];
+      ZeroMem (Buf, sizeof (Buf));
+      CopyMem (
+        (UINT8 *)Buf,
+        (UINT8 *)&Packet->SdMmcStatusBlk->Resp0 + 1,
+        sizeof (Buf) - 1
+        );
+      CopyMem (
+        (UINT8 *)&Packet->SdMmcStatusBlk->Resp0,
+        (UINT8 *)Buf,
+        sizeof (Buf) - 1
+        );
+    }
+  }
+
+  return EFI_SUCCESS;
+}
+
+EFI_STATUS
+DwSdExecTrb (
+  IN DW_MMC_HC_PRIVATE_DATA           *Private,
+  IN DW_MMC_HC_TRB                    *Trb
+  )
+{
+  EFI_STATUS                          Status;
+  EFI_SD_MMC_PASS_THRU_COMMAND_PACKET *Packet;
+  EFI_DEVICE_IO_PROTOCOL              *DevIo;
+  UINT32                              Cmd;
+  UINT32                              MmcStatus;
+  UINT32                              IntStatus;
+  UINT32                              Argument;
+  UINT32                              ErrMask;
+  UINT32                              Timeout;
+  UINT32                              Idsts;
+  UINT32                              BytCnt;
+  UINT32                              BlkSize;
+
+  Packet = Trb->Packet;
+  DevIo  = Trb->Private->DevIo;
+
+  ArmDataSynchronizationBarrier ();
+  ArmInstructionSynchronizationBarrier ();
+  //
+  // Wait until MMC is idle
+  //
+  do {
+    Status = DwMmcHcRwMmio (
+               DevIo,
+               DW_MMC_STATUS,
+               TRUE,
+               sizeof (MmcStatus),
+               &MmcStatus
+               );
+    if (EFI_ERROR (Status)) {
+      return Status;
+    }
+  } while (MmcStatus & DW_MMC_STS_DATA_BUSY);
+
+  IntStatus = ~0;
+  Status = DwMmcHcRwMmio (
+             DevIo,
+             DW_MMC_RINTSTS,
+             FALSE,
+             sizeof (IntStatus),
+             &IntStatus
+             );
+  if (EFI_ERROR (Status)) {
+    return Status;
+  }
+  Cmd = CMD_INDEX (Packet->SdMmcCmdBlk->CommandIndex);
+  if ((Packet->SdMmcCmdBlk->CommandType == SdMmcCommandTypeAc) ||
+      (Packet->SdMmcCmdBlk->CommandType == SdMmcCommandTypeAdtc)) {
+    switch (Packet->SdMmcCmdBlk->CommandIndex) {
+    case SD_SET_RELATIVE_ADDR:
+      Cmd |= BIT_CMD_SEND_INIT;
+      break;
+    case SD_STOP_TRANSMISSION:
+      Cmd |= BIT_CMD_STOP_ABORT_CMD;
+      break;
+    case SD_SEND_SCR:
+      Trb->UseBE = TRUE;
+      break;
+    }
+    if (Packet->InTransferLength) {
+      Cmd |= BIT_CMD_WAIT_PRVDATA_COMPLETE | BIT_CMD_DATA_EXPECTED |
+             BIT_CMD_READ;
+    } else if (Packet->OutTransferLength) {
+      Cmd |= BIT_CMD_WAIT_PRVDATA_COMPLETE | BIT_CMD_DATA_EXPECTED |
+             BIT_CMD_WRITE;
+    }
+    Cmd |= BIT_CMD_RESPONSE_EXPECT | BIT_CMD_CHECK_RESPONSE_CRC |
+           BIT_CMD_SEND_AUTO_STOP;
+  } else {
+    switch (Packet->SdMmcCmdBlk->CommandIndex) {
+    case SD_GO_IDLE_STATE:
+      Cmd |= BIT_CMD_SEND_INIT;
+      break;
+    }
+  }
+  switch (Packet->SdMmcCmdBlk->ResponseType) {
+  case SdMmcResponseTypeR2:
+    Cmd |= BIT_CMD_RESPONSE_EXPECT | BIT_CMD_CHECK_RESPONSE_CRC |
+           BIT_CMD_LONG_RESPONSE;
+    break;
+  case SdMmcResponseTypeR3:
+    Cmd |= BIT_CMD_RESPONSE_EXPECT;
+    break;
+  case SdMmcResponseTypeR1b:
+  case SdMmcResponseTypeR4:
+  case SdMmcResponseTypeR6:
+  case SdMmcResponseTypeR7:
+    Cmd |= BIT_CMD_RESPONSE_EXPECT | BIT_CMD_CHECK_RESPONSE_CRC;
+    break;
+  }
+  Cmd |= BIT_CMD_USE_HOLD_REG | BIT_CMD_START;
+
+  if (Trb->UseFifo == TRUE) {
+    BytCnt = Packet->InTransferLength;
+    Status = DwMmcHcRwMmio (
+               DevIo,
+               DW_MMC_BYTCNT,
+               FALSE,
+               sizeof (BytCnt),
+               &BytCnt
+               );
+    if (EFI_ERROR (Status)) {
+      return Status;
+    }
+    if (Packet->InTransferLength > DW_MMC_BLOCK_SIZE) {
+      BlkSize = DW_MMC_BLOCK_SIZE;
+    } else {
+      BlkSize = Packet->InTransferLength;
+    }
+    Status = DwMmcHcRwMmio (
+               DevIo,
+               DW_MMC_BLKSIZ,
+               FALSE,
+               sizeof (BlkSize),
+               &BlkSize
+               );
+    if (EFI_ERROR (Status)) {
+      DEBUG ((DEBUG_ERROR, "DwSdExecTrb: set block size fails: %r\n", Status));
+      return Status;
+    }
+  }
+
+  Argument = Packet->SdMmcCmdBlk->CommandArgument;
+  Status = DwMmcHcRwMmio (
+             DevIo,
+             DW_MMC_CMDARG,
+             FALSE,
+             sizeof (Argument),
+             &Argument
+             );
+  if (EFI_ERROR (Status)) {
+    return Status;
+  }
+  ArmDataSynchronizationBarrier ();
+  ArmInstructionSynchronizationBarrier ();
+  Status = DwMmcHcRwMmio (
+             DevIo,
+             DW_MMC_CMD,
+             FALSE,
+             sizeof (Cmd),
+             &Cmd
+             );
+  if (EFI_ERROR (Status)) {
+    return Status;
+  }
+  ArmDataSynchronizationBarrier ();
+  ArmInstructionSynchronizationBarrier ();
+
+  ErrMask = DW_MMC_INT_EBE | DW_MMC_INT_HLE | DW_MMC_INT_RTO |
+            DW_MMC_INT_RCRC | DW_MMC_INT_RE;
+  ErrMask |= DW_MMC_INT_DRT | DW_MMC_INT_SBE;
+  if (Packet->InTransferLength || Packet->OutTransferLength) {
+    ErrMask |= DW_MMC_INT_DCRC;
+  }
+  if (Trb->UseFifo == TRUE) {
+    Status = ReadFifo (Trb);
+    if (EFI_ERROR (Status)) {
+      return Status;
+    }
+  } else {
+    Timeout = 10000;
+    do {
+      if (--Timeout == 0) {
+        break;
+      }
+      Status = DwMmcHcRwMmio (
+                 DevIo,
+                 DW_MMC_RINTSTS,
+                 TRUE,
+                 sizeof (IntStatus),
+                 &IntStatus
+                 );
+      if (EFI_ERROR (Status)) {
+        return Status;
+      }
+      if (IntStatus & ErrMask) {
+        return EFI_DEVICE_ERROR;
+      }
+      if (Trb->DataLen && ((IntStatus & DW_MMC_INT_DTO) == 0)) {
+        //
+        // Transfer not Done
+        //
+        MicroSecondDelay (10);
+        continue;
+      }
+      MicroSecondDelay (10);
+    } while (!(IntStatus & DW_MMC_INT_CMD_DONE));
+    if (Packet->InTransferLength) {
+      do {
+        Status = DwMmcHcRwMmio (
+                   DevIo,
+                   DW_MMC_IDSTS,
+                   TRUE,
+                   sizeof (Idsts),
+                   &Idsts
+                   );
+        if (EFI_ERROR (Status)) {
+          return Status;
+        }
+      } while ((Idsts & DW_MMC_IDSTS_RI) == 0);
+      Status = DwMmcHcStopDma (Private, Trb);
+      if (EFI_ERROR (Status)) {
+        return Status;
+      }
+    } else if (Packet->OutTransferLength) {
+      do {
+        Status = DwMmcHcRwMmio (
+                   DevIo,
+                   DW_MMC_IDSTS,
+                   TRUE,
+                   sizeof (Idsts),
+                   &Idsts
+                   );
+        if (EFI_ERROR (Status)) {
+          return Status;
+        }
+      } while ((Idsts & DW_MMC_IDSTS_TI) == 0);
+      Status = DwMmcHcStopDma (Private, Trb);
+      if (EFI_ERROR (Status)) {
+        return Status;
+      }
+    } /* Packet->InTransferLength */
+  } /* UseFifo */
+  switch (Packet->SdMmcCmdBlk->ResponseType) {
+    case SdMmcResponseTypeR1:
+    case SdMmcResponseTypeR1b:
+    case SdMmcResponseTypeR3:
+    case SdMmcResponseTypeR4:
+    case SdMmcResponseTypeR5:
+    case SdMmcResponseTypeR6:
+    case SdMmcResponseTypeR7:
+      Status = DwMmcHcRwMmio (
+                 DevIo,
+                 DW_MMC_RESP0,
+                 TRUE,
+                 sizeof (Packet->SdMmcStatusBlk->Resp0),
+                 &Packet->SdMmcStatusBlk->Resp0
+                 );
+      if (EFI_ERROR (Status)) {
+        return Status;
+      }
+      break;
+    case SdMmcResponseTypeR2:
+      Status = DwMmcHcRwMmio (
+                 DevIo,
+                 DW_MMC_RESP0,
+                 TRUE,
+                 sizeof (Packet->SdMmcStatusBlk->Resp0),
+                 &Packet->SdMmcStatusBlk->Resp0
+                 );
+      if (EFI_ERROR (Status)) {
+        return Status;
+      }
+      Status = DwMmcHcRwMmio (
+                 DevIo,
+                 DW_MMC_RESP1,
+                 TRUE,
+                 sizeof (Packet->SdMmcStatusBlk->Resp1),
+                 &Packet->SdMmcStatusBlk->Resp1
+                 );
+      if (EFI_ERROR (Status)) {
+        return Status;
+      }
+      Status = DwMmcHcRwMmio (
+                 DevIo,
+                 DW_MMC_RESP2,
+                 TRUE,
+                 sizeof (Packet->SdMmcStatusBlk->Resp2),
+                 &Packet->SdMmcStatusBlk->Resp2
+                 );
+      if (EFI_ERROR (Status)) {
+        return Status;
+      }
+      Status = DwMmcHcRwMmio (
+                 DevIo,
+                 DW_MMC_RESP3,
+                 TRUE,
+                 sizeof (Packet->SdMmcStatusBlk->Resp3),
+                 &Packet->SdMmcStatusBlk->Resp3
+                 );
+      if (EFI_ERROR (Status)) {
+        return Status;
+      }
+      break;
+  }
+
+  //
+  // The workaround on SD_SEND_CSD is used to be compatible with SDHC.
+  //
+  if (Packet->SdMmcCmdBlk->CommandIndex == SD_SEND_CSD) {
+    {
+      UINT32   Buf[4];
+      ZeroMem (Buf, sizeof (Buf));
+      CopyMem (
+        (UINT8 *)Buf,
+        (UINT8 *)&Packet->SdMmcStatusBlk->Resp0 + 1,
+        sizeof (Buf) - 1
+        );
+      CopyMem (
+        (UINT8 *)&Packet->SdMmcStatusBlk->Resp0,
+        (UINT8 *)Buf,
+        sizeof (Buf) - 1
+        );
+    }
+  }
+
+  return EFI_SUCCESS;
+}
+
+/**
+  Execute the specified TRB.
+
+  @param[in] Private        A pointer to the DW_MMC_HC_PRIVATE_DATA instance.
+  @param[in] Trb            The pointer to the DW_MMC_HC_TRB instance.
+
+  @retval EFI_SUCCESS       The TRB is sent to host controller successfully.
+  @retval Others            Some erros happen when sending this request to the
+                            host controller.
+
+**/
+EFI_STATUS
+DwMmcExecTrb (
+  IN DW_MMC_HC_PRIVATE_DATA           *Private,
+  IN DW_MMC_HC_TRB                    *Trb
+  )
+{
+  EFI_STATUS                          Status = EFI_SUCCESS;
+  UINT32                              Slot;
+
+  Slot = Trb->Slot;
+  if (Private->Slot[Slot].CardType == EmmcCardType) {
+    Status = DwEmmcExecTrb (Private, Trb);
+  } else if (Private->Slot[Slot].CardType == SdCardType) {
+    Status = DwSdExecTrb (Private, Trb);
+  } else {
+    ASSERT (0);
+  }
+  return Status;
+}
+
+/**
+  Check the TRB execution result.
+
+  @param[in] Private        A pointer to the DW_MMC_HC_PRIVATE_DATA instance.
+  @param[in] Trb            The pointer to the DW_MMC_HC_TRB instance.
+
+  @retval EFI_SUCCESS       The TRB is executed successfully.
+  @retval EFI_NOT_READY     The TRB is not completed for execution.
+  @retval Others            Some erros happen when executing this request.
+
+**/
+EFI_STATUS
+DwMmcCheckTrbResult (
+  IN DW_MMC_HC_PRIVATE_DATA           *Private,
+  IN DW_MMC_HC_TRB                    *Trb
+  )
+{
+  EFI_STATUS                          Status;
+  EFI_SD_MMC_PASS_THRU_COMMAND_PACKET *Packet;
+  UINT32                              Idsts;
+
+  Packet  = Trb->Packet;
+  if (Trb->UseFifo == TRUE) {
+    return EFI_SUCCESS;
+  }
+  if (Packet->InTransferLength) {
+    do {
+      Status = DwMmcHcRwMmio (
+                 Private->DevIo,
+                 DW_MMC_IDSTS,
+                 TRUE,
+                 sizeof (Idsts),
+                 &Idsts
+                 );
+      if (EFI_ERROR (Status)) {
+        return Status;
+      }
+    } while ((Idsts & BIT1) == 0);
+  } else if (Packet->OutTransferLength) {
+    do {
+      Status = DwMmcHcRwMmio (
+                 Private->DevIo,
+                 DW_MMC_IDSTS,
+                 TRUE,
+                 sizeof (Idsts),
+                 &Idsts
+                 );
+      if (EFI_ERROR (Status)) {
+        return Status;
+      }
+    } while ((Idsts & BIT0) == 0);
+  } else {
+    return EFI_SUCCESS;
+  }
+  Idsts = ~0;
+  Status = DwMmcHcRwMmio (
+             Private->DevIo,
+             DW_MMC_IDSTS,
+             FALSE,
+             sizeof (Idsts), &Idsts);
+  if (EFI_ERROR (Status)) {
+    return Status;
+  }
+  return EFI_SUCCESS;
+}
+
+/**
+  Wait for the TRB execution result.
+
+  @param[in] Private        A pointer to the DW_MMC_HC_PRIVATE_DATA instance.
+  @param[in] Trb            The pointer to the DW_MMC_HC_TRB instance.
+
+  @retval EFI_SUCCESS       The TRB is executed successfully.
+  @retval Others            Some erros happen when executing this request.
+
+**/
+EFI_STATUS
+DwMmcWaitTrbResult (
+  IN DW_MMC_HC_PRIVATE_DATA           *Private,
+  IN DW_MMC_HC_TRB                    *Trb
+  )
+{
+  EFI_STATUS                          Status;
+  EFI_SD_MMC_PASS_THRU_COMMAND_PACKET *Packet;
+  UINT64                              Timeout;
+  BOOLEAN                             InfiniteWait;
+
+  Packet = Trb->Packet;
+  //
+  // Wait Command Complete Interrupt Status bit in Normal Interrupt Status
+  // Register
+  //
+  Timeout = Packet->Timeout;
+  if (Timeout == 0) {
+    InfiniteWait = TRUE;
+  } else {
+    InfiniteWait = FALSE;
+  }
+
+  while (InfiniteWait || (Timeout > 0)) {
+    //
+    // Check Trb execution result by reading Normal Interrupt Status register.
+    //
+    Status = DwMmcCheckTrbResult (Private, Trb);
+    if (Status != EFI_NOT_READY) {
+      return Status;
+    }
+    //
+    // Stall for 1 microsecond.
+    //
+    gBS->Stall (1);
+
+    Timeout--;
+  }
+
+  return EFI_TIMEOUT;
+}
diff --git a/EmbeddedPkg/Drivers/DwMmcHcDxe/EmmcDevice.c b/EmbeddedPkg/Drivers/DwMmcHcDxe/EmmcDevice.c
new file mode 100644
index 000000000000..cf7c7195a569
--- /dev/null
+++ b/EmbeddedPkg/Drivers/DwMmcHcDxe/EmmcDevice.c
@@ -0,0 +1,1042 @@ 
+/** @file
+  This file provides some helper functions which are specific for EMMC device.
+
+  Copyright (c) 2015 - 2016, Intel Corporation. All rights reserved.<BR>
+  Copyright (c) 2018, Linaro. All rights reserved.<BR>
+
+  This program and the accompanying materials are licensed and made available
+  under the terms and conditions of the BSD License which accompanies this
+  distribution.  The full text of the license may be found at
+  http://opensource.org/licenses/bsd-license.php
+
+  THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+  WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#include <IndustryStandard/Emmc.h>
+
+#include <Library/BaseMemoryLib.h>
+#include <Library/DebugLib.h>
+#include <Library/UefiBootServicesTableLib.h>
+
+#include "DwMmcHcDxe.h"
+
+#define EMMC_GET_STATE(x)                   (((x) >> 9) & 0xf)
+#define EMMC_STATE_IDLE                     0
+#define EMMC_STATE_READY                    1
+#define EMMC_STATE_IDENT                    2
+#define EMMC_STATE_STBY                     3
+#define EMMC_STATE_TRAN                     4
+#define EMMC_STATE_DATA                     5
+#define EMMC_STATE_RCV                      6
+#define EMMC_STATE_PRG                      7
+#define EMMC_STATE_DIS                      8
+#define EMMC_STATE_BTST                     9
+#define EMMC_STATE_SLP                      10
+
+#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
+
+/**
+  Send command GO_IDLE_STATE (CMD0 with argument of 0x00000000) to the device to
+  make it go to Idle State.
+
+  Refer to EMMC Electrical Standard Spec 5.1 Section 6.4 for details.
+
+  @param[in] PassThru       A pointer to the EFI_SD_MMC_PASS_THRU_PROTOCOL
+                            instance.
+  @param[in] Slot           The slot number of the SD card to send the command
+                            to.
+
+  @retval EFI_SUCCESS       The EMMC device is reset correctly.
+  @retval Others            The device reset fails.
+
+**/
+EFI_STATUS
+EmmcReset (
+  IN EFI_SD_MMC_PASS_THRU_PROTOCOL      *PassThru
+  )
+{
+  EFI_SD_MMC_COMMAND_BLOCK              SdMmcCmdBlk;
+  EFI_SD_MMC_STATUS_BLOCK               SdMmcStatusBlk;
+  EFI_SD_MMC_PASS_THRU_COMMAND_PACKET   Packet;
+  EFI_STATUS                            Status;
+
+  ZeroMem (&SdMmcCmdBlk, sizeof (SdMmcCmdBlk));
+  ZeroMem (&SdMmcStatusBlk, sizeof (SdMmcStatusBlk));
+  ZeroMem (&Packet, sizeof (Packet));
+
+  Packet.SdMmcCmdBlk    = &SdMmcCmdBlk;
+  Packet.SdMmcStatusBlk = &SdMmcStatusBlk;
+  Packet.Timeout        = DW_MMC_HC_GENERIC_TIMEOUT;
+
+  SdMmcCmdBlk.CommandIndex = EMMC_GO_IDLE_STATE;
+  SdMmcCmdBlk.CommandType  = SdMmcCommandTypeBc;
+  SdMmcCmdBlk.ResponseType = 0;
+  SdMmcCmdBlk.CommandArgument = 0;
+
+  gBS->Stall (1000);
+
+  Status = DwMmcPassThruPassThru (PassThru, 0, &Packet, NULL);
+
+  return Status;
+}
+
+/**
+  Send command SEND_OP_COND to the EMMC device to get the data of the OCR
+  register.
+
+  Refer to EMMC Electrical Standard Spec 5.1 Section 6.4 for details.
+
+  @param[in]      PassThru  A pointer to the EFI_SD_MMC_PASS_THRU_PROTOCOL
+                            instance.
+  @param[in, out] Argument  On input, the argument of SEND_OP_COND is to send
+                            to the device.
+                            On output, the argument is the value of OCR
+                            register.
+
+  @retval EFI_SUCCESS       The operation is done correctly.
+  @retval Others            The operation fails.
+
+**/
+EFI_STATUS
+EmmcGetOcr (
+  IN     EFI_SD_MMC_PASS_THRU_PROTOCOL  *PassThru,
+  IN OUT UINT32                         *Argument
+  )
+{
+  EFI_SD_MMC_COMMAND_BLOCK              SdMmcCmdBlk;
+  EFI_SD_MMC_STATUS_BLOCK               SdMmcStatusBlk;
+  EFI_SD_MMC_PASS_THRU_COMMAND_PACKET   Packet;
+  EFI_STATUS                            Status;
+
+  ZeroMem (&SdMmcCmdBlk, sizeof (SdMmcCmdBlk));
+  ZeroMem (&SdMmcStatusBlk, sizeof (SdMmcStatusBlk));
+  ZeroMem (&Packet, sizeof (Packet));
+
+  Packet.SdMmcCmdBlk    = &SdMmcCmdBlk;
+  Packet.SdMmcStatusBlk = &SdMmcStatusBlk;
+  Packet.Timeout        = DW_MMC_HC_GENERIC_TIMEOUT;
+
+  SdMmcCmdBlk.CommandIndex = EMMC_SEND_OP_COND;
+  SdMmcCmdBlk.CommandType  = SdMmcCommandTypeBcr;
+  SdMmcCmdBlk.ResponseType = SdMmcResponseTypeR3;
+  SdMmcCmdBlk.CommandArgument = *Argument;
+
+  Status = DwMmcPassThruPassThru (PassThru, 0, &Packet, NULL);
+  if (!EFI_ERROR (Status)) {
+    //
+    // For details, refer to SD Host Controller Simplified Spec 3.0 Table 2-12.
+    //
+    *Argument = SdMmcStatusBlk.Resp0;
+  }
+
+  return Status;
+}
+
+/**
+  Broadcast command ALL_SEND_CID to the bus to ask all the EMMC devices to send
+  the data of their CID registers.
+
+  Refer to EMMC Electrical Standard Spec 5.1 Section 6.4 for details.
+
+  @param[in] PassThru       A pointer to the EFI_SD_MMC_PASS_THRU_PROTOCOL
+                            instance.
+
+  @retval EFI_SUCCESS       The operation is done correctly.
+  @retval Others            The operation fails.
+
+**/
+EFI_STATUS
+EmmcGetAllCid (
+  IN EFI_SD_MMC_PASS_THRU_PROTOCOL      *PassThru
+  )
+{
+  EFI_SD_MMC_COMMAND_BLOCK              SdMmcCmdBlk;
+  EFI_SD_MMC_STATUS_BLOCK               SdMmcStatusBlk;
+  EFI_SD_MMC_PASS_THRU_COMMAND_PACKET   Packet;
+  EFI_STATUS                            Status;
+
+  ZeroMem (&SdMmcCmdBlk, sizeof (SdMmcCmdBlk));
+  ZeroMem (&SdMmcStatusBlk, sizeof (SdMmcStatusBlk));
+  ZeroMem (&Packet, sizeof (Packet));
+
+  Packet.SdMmcCmdBlk    = &SdMmcCmdBlk;
+  Packet.SdMmcStatusBlk = &SdMmcStatusBlk;
+  Packet.Timeout        = DW_MMC_HC_GENERIC_TIMEOUT;
+
+  SdMmcCmdBlk.CommandIndex = EMMC_ALL_SEND_CID;
+  SdMmcCmdBlk.CommandType  = SdMmcCommandTypeBcr;
+  SdMmcCmdBlk.ResponseType = SdMmcResponseTypeR2;
+  SdMmcCmdBlk.CommandArgument = 0;
+
+  Status = DwMmcPassThruPassThru (PassThru, 0, &Packet, NULL);
+
+  return Status;
+}
+
+/**
+  Send command SET_RELATIVE_ADDR to the EMMC device to assign a Relative device
+  Address (RCA).
+
+  Refer to EMMC Electrical Standard Spec 5.1 Section 6.4 for details.
+
+  @param[in] PassThru       A pointer to the EFI_SD_MMC_PASS_THRU_PROTOCOL
+                            instance.
+  @param[in] Rca            The relative device address to be assigned.
+
+  @retval EFI_SUCCESS       The operation is done correctly.
+  @retval Others            The operation fails.
+
+**/
+EFI_STATUS
+EmmcSetRca (
+  IN EFI_SD_MMC_PASS_THRU_PROTOCOL      *PassThru,
+  IN UINT16                             Rca
+  )
+{
+  EFI_SD_MMC_COMMAND_BLOCK              SdMmcCmdBlk;
+  EFI_SD_MMC_STATUS_BLOCK               SdMmcStatusBlk;
+  EFI_SD_MMC_PASS_THRU_COMMAND_PACKET   Packet;
+  EFI_STATUS                            Status;
+
+  ZeroMem (&SdMmcCmdBlk, sizeof (SdMmcCmdBlk));
+  ZeroMem (&SdMmcStatusBlk, sizeof (SdMmcStatusBlk));
+  ZeroMem (&Packet, sizeof (Packet));
+
+  Packet.SdMmcCmdBlk    = &SdMmcCmdBlk;
+  Packet.SdMmcStatusBlk = &SdMmcStatusBlk;
+  Packet.Timeout        = DW_MMC_HC_GENERIC_TIMEOUT;
+
+  SdMmcCmdBlk.CommandIndex = EMMC_SET_RELATIVE_ADDR;
+  SdMmcCmdBlk.CommandType  = SdMmcCommandTypeAc;
+  SdMmcCmdBlk.ResponseType = SdMmcResponseTypeR1;
+  SdMmcCmdBlk.CommandArgument = (UINT32)Rca << 16;
+
+  Status = DwMmcPassThruPassThru (PassThru, 0, &Packet, NULL);
+
+  return Status;
+}
+
+/**
+  Send command SEND_CSD to the EMMC device to get the data of the CSD register.
+
+  Refer to EMMC Electrical Standard Spec 5.1 Section 6.10.4 for details.
+
+  @param[in]  PassThru      A pointer to the EFI_SD_MMC_PASS_THRU_PROTOCOL
+                            instance.
+  @param[in]  Rca           The relative device address of selected device.
+  @param[out] Csd           The buffer to store the content of the CSD register.
+                            Note the caller should ignore the lowest byte of
+                            this buffer as the content of this byte is
+                            meaningless even if the operation succeeds.
+
+  @retval EFI_SUCCESS       The operation is done correctly.
+  @retval Others            The operation fails.
+
+**/
+EFI_STATUS
+EmmcGetCsd (
+  IN     EFI_SD_MMC_PASS_THRU_PROTOCOL  *PassThru,
+  IN     UINT16                         Rca,
+     OUT EMMC_CSD                       *Csd
+  )
+{
+  EFI_SD_MMC_COMMAND_BLOCK              SdMmcCmdBlk;
+  EFI_SD_MMC_STATUS_BLOCK               SdMmcStatusBlk;
+  EFI_SD_MMC_PASS_THRU_COMMAND_PACKET   Packet;
+  EFI_STATUS                            Status;
+
+  ZeroMem (&SdMmcCmdBlk, sizeof (SdMmcCmdBlk));
+  ZeroMem (&SdMmcStatusBlk, sizeof (SdMmcStatusBlk));
+  ZeroMem (&Packet, sizeof (Packet));
+
+  Packet.SdMmcCmdBlk    = &SdMmcCmdBlk;
+  Packet.SdMmcStatusBlk = &SdMmcStatusBlk;
+  Packet.Timeout        = DW_MMC_HC_GENERIC_TIMEOUT;
+
+  SdMmcCmdBlk.CommandIndex = EMMC_SEND_CSD;
+  SdMmcCmdBlk.CommandType  = SdMmcCommandTypeAc;
+  SdMmcCmdBlk.ResponseType = SdMmcResponseTypeR2;
+  SdMmcCmdBlk.CommandArgument = (UINT32)Rca << 16;
+
+  Status = DwMmcPassThruPassThru (PassThru, 0, &Packet, NULL);
+  if (!EFI_ERROR (Status)) {
+    //
+    // Copy 128bit data for CSD structure.
+    //
+    CopyMem ((VOID *)Csd + 1, &SdMmcStatusBlk.Resp0, sizeof (EMMC_CSD) - 1);
+  }
+
+  return Status;
+}
+
+/**
+  Send command SELECT_DESELECT_CARD to the EMMC device to select/deselect it.
+
+  Refer to EMMC Electrical Standard Spec 5.1 Section 6.10.4 for details.
+
+  @param[in]  PassThru      A pointer to the EFI_SD_MMC_PASS_THRU_PROTOCOL
+                            instance.
+  @param[in]  Rca           The relative device address of selected device.
+
+  @retval EFI_SUCCESS       The operation is done correctly.
+  @retval Others            The operation fails.
+
+**/
+EFI_STATUS
+EmmcSelect (
+  IN EFI_SD_MMC_PASS_THRU_PROTOCOL      *PassThru,
+  IN UINT16                             Rca
+  )
+{
+  EFI_SD_MMC_COMMAND_BLOCK              SdMmcCmdBlk;
+  EFI_SD_MMC_STATUS_BLOCK               SdMmcStatusBlk;
+  EFI_SD_MMC_PASS_THRU_COMMAND_PACKET   Packet;
+  EFI_STATUS                            Status;
+
+  ZeroMem (&SdMmcCmdBlk, sizeof (SdMmcCmdBlk));
+  ZeroMem (&SdMmcStatusBlk, sizeof (SdMmcStatusBlk));
+  ZeroMem (&Packet, sizeof (Packet));
+
+  Packet.SdMmcCmdBlk    = &SdMmcCmdBlk;
+  Packet.SdMmcStatusBlk = &SdMmcStatusBlk;
+  Packet.Timeout        = DW_MMC_HC_GENERIC_TIMEOUT;
+
+  SdMmcCmdBlk.CommandIndex = EMMC_SELECT_DESELECT_CARD;
+  SdMmcCmdBlk.CommandType  = SdMmcCommandTypeAc;
+  SdMmcCmdBlk.ResponseType = SdMmcResponseTypeR1;
+  SdMmcCmdBlk.CommandArgument = (UINT32)Rca << 16;
+
+  Status = DwMmcPassThruPassThru (PassThru, 0, &Packet, NULL);
+
+  return Status;
+}
+
+/**
+  Send command SEND_EXT_CSD to the EMMC device to get the data of the EXT_CSD
+  register.
+
+  Refer to EMMC Electrical Standard Spec 5.1 Section 6.10.4 for details.
+
+  @param[in]  PassThru      A pointer to the EFI_SD_MMC_PASS_THRU_PROTOCOL
+                            instance.
+  @param[out] ExtCsd        The buffer to store the content of the EXT_CSD
+                            register.
+
+  @retval EFI_SUCCESS       The operation is done correctly.
+  @retval Others            The operation fails.
+
+**/
+EFI_STATUS
+EmmcGetExtCsd (
+  IN     EFI_SD_MMC_PASS_THRU_PROTOCOL  *PassThru,
+     OUT EMMC_EXT_CSD                   *ExtCsd
+  )
+{
+  EFI_SD_MMC_COMMAND_BLOCK              SdMmcCmdBlk;
+  EFI_SD_MMC_STATUS_BLOCK               SdMmcStatusBlk;
+  EFI_SD_MMC_PASS_THRU_COMMAND_PACKET   Packet;
+  EFI_STATUS                            Status;
+
+  ZeroMem (&SdMmcCmdBlk, sizeof (SdMmcCmdBlk));
+  ZeroMem (&SdMmcStatusBlk, sizeof (SdMmcStatusBlk));
+  ZeroMem (&Packet, sizeof (Packet));
+
+  Packet.SdMmcCmdBlk    = &SdMmcCmdBlk;
+  Packet.SdMmcStatusBlk = &SdMmcStatusBlk;
+  Packet.Timeout        = DW_MMC_HC_GENERIC_TIMEOUT;
+
+  SdMmcCmdBlk.CommandIndex = EMMC_SEND_EXT_CSD;
+  SdMmcCmdBlk.CommandType  = SdMmcCommandTypeAdtc;
+  SdMmcCmdBlk.ResponseType = SdMmcResponseTypeR1;
+  SdMmcCmdBlk.CommandArgument = 0x00000000;
+
+  Packet.InDataBuffer     = ExtCsd;
+  Packet.InTransferLength = sizeof (EMMC_EXT_CSD);
+
+  Status = DwMmcPassThruPassThru (PassThru, 0, &Packet, NULL);
+  return Status;
+}
+
+/**
+  Send command SWITCH to the EMMC device to switch the mode of operation of the
+  selected Device or modifies the EXT_CSD registers.
+
+  Refer to EMMC Electrical Standard Spec 5.1 Section 6.10.4 for details.
+
+  @param[in]  PassThru      A pointer to the EFI_SD_MMC_PASS_THRU_PROTOCOL
+                            instance.
+  @param[in]  Access        The access mode of SWTICH command.
+  @param[in]  Index         The offset of the field to be access.
+  @param[in]  Value         The value to be set to the specified field of
+                            EXT_CSD register.
+  @param[in]  CmdSet        The value of CmdSet field of EXT_CSD register.
+
+  @retval EFI_SUCCESS       The operation is done correctly.
+  @retval Others            The operation fails.
+
+**/
+EFI_STATUS
+EmmcSwitch (
+  IN EFI_SD_MMC_PASS_THRU_PROTOCOL      *PassThru,
+  IN UINT8                              Access,
+  IN UINT8                              Index,
+  IN UINT8                              Value,
+  IN UINT8                              CmdSet
+  )
+{
+  EFI_SD_MMC_COMMAND_BLOCK              SdMmcCmdBlk;
+  EFI_SD_MMC_STATUS_BLOCK               SdMmcStatusBlk;
+  EFI_SD_MMC_PASS_THRU_COMMAND_PACKET   Packet;
+  EFI_STATUS                            Status;
+
+  ZeroMem (&SdMmcCmdBlk, sizeof (SdMmcCmdBlk));
+  ZeroMem (&SdMmcStatusBlk, sizeof (SdMmcStatusBlk));
+  ZeroMem (&Packet, sizeof (Packet));
+
+  Packet.SdMmcCmdBlk    = &SdMmcCmdBlk;
+  Packet.SdMmcStatusBlk = &SdMmcStatusBlk;
+  Packet.Timeout        = DW_MMC_HC_GENERIC_TIMEOUT;
+
+  SdMmcCmdBlk.CommandIndex = EMMC_SWITCH;
+  SdMmcCmdBlk.CommandType  = SdMmcCommandTypeAc;
+  SdMmcCmdBlk.ResponseType = SdMmcResponseTypeR1b;
+  SdMmcCmdBlk.CommandArgument = (Access << 24) | (Index << 16) | \
+                                (Value << 8) | CmdSet;
+
+  Status = DwMmcPassThruPassThru (PassThru, 0, &Packet, NULL);
+
+  return Status;
+}
+
+/**
+  Send command SEND_STATUS to the addressed EMMC device to get its status
+  register.
+
+  Refer to EMMC Electrical Standard Spec 5.1 Section 6.10.4 for details.
+
+  @param[in]  PassThru      A pointer to the EFI_SD_MMC_PASS_THRU_PROTOCOL
+                            instance.
+  @param[in]  Rca           The relative device address of addressed device.
+  @param[out] DevStatus     The returned device status.
+
+  @retval EFI_SUCCESS       The operation is done correctly.
+  @retval Others            The operation fails.
+
+**/
+EFI_STATUS
+EmmcSendStatus (
+  IN     EFI_SD_MMC_PASS_THRU_PROTOCOL  *PassThru,
+  IN     UINT16                         Rca,
+     OUT UINT32                         *DevStatus
+  )
+{
+  EFI_SD_MMC_COMMAND_BLOCK              SdMmcCmdBlk;
+  EFI_SD_MMC_STATUS_BLOCK               SdMmcStatusBlk;
+  EFI_SD_MMC_PASS_THRU_COMMAND_PACKET   Packet;
+  EFI_STATUS                            Status;
+
+  ZeroMem (&SdMmcCmdBlk, sizeof (SdMmcCmdBlk));
+  ZeroMem (&SdMmcStatusBlk, sizeof (SdMmcStatusBlk));
+  ZeroMem (&Packet, sizeof (Packet));
+
+  Packet.SdMmcCmdBlk    = &SdMmcCmdBlk;
+  Packet.SdMmcStatusBlk = &SdMmcStatusBlk;
+  Packet.Timeout        = DW_MMC_HC_GENERIC_TIMEOUT;
+
+  SdMmcCmdBlk.CommandIndex = EMMC_SEND_STATUS;
+  SdMmcCmdBlk.CommandType  = SdMmcCommandTypeAc;
+  SdMmcCmdBlk.ResponseType = SdMmcResponseTypeR1;
+  SdMmcCmdBlk.CommandArgument = (UINT32)Rca << 16;
+
+  Status = DwMmcPassThruPassThru (PassThru, 0, &Packet, NULL);
+  if (!EFI_ERROR (Status)) {
+    *DevStatus = SdMmcStatusBlk.Resp0;
+  }
+
+  return Status;
+}
+
+/**
+  Send command SEND_TUNING_BLOCK to the EMMC device for HS200 optimal sampling
+  point detection.
+
+  It may be sent up to 40 times until the host finishes the tuning procedure.
+
+  Refer to EMMC Electrical Standard Spec 5.1 Section 6.6.8 for details.
+
+  @param[in] PassThru       A pointer to the EFI_SD_MMC_PASS_THRU_PROTOCOL
+                            instance.
+  @param[in] BusWidth       The bus width to work.
+
+  @retval EFI_SUCCESS       The operation is done correctly.
+  @retval Others            The operation fails.
+
+**/
+EFI_STATUS
+EmmcSendTuningBlk (
+  IN EFI_SD_MMC_PASS_THRU_PROTOCOL      *PassThru,
+  IN UINT8                              BusWidth
+  )
+{
+  EFI_SD_MMC_COMMAND_BLOCK              SdMmcCmdBlk;
+  EFI_SD_MMC_STATUS_BLOCK               SdMmcStatusBlk;
+  EFI_SD_MMC_PASS_THRU_COMMAND_PACKET   Packet;
+  EFI_STATUS                            Status;
+  UINT8                                 TuningBlock[128];
+
+  ZeroMem (&SdMmcCmdBlk, sizeof (SdMmcCmdBlk));
+  ZeroMem (&SdMmcStatusBlk, sizeof (SdMmcStatusBlk));
+  ZeroMem (&Packet, sizeof (Packet));
+
+  Packet.SdMmcCmdBlk    = &SdMmcCmdBlk;
+  Packet.SdMmcStatusBlk = &SdMmcStatusBlk;
+  Packet.Timeout        = DW_MMC_HC_GENERIC_TIMEOUT;
+
+  SdMmcCmdBlk.CommandIndex = EMMC_SEND_TUNING_BLOCK;
+  SdMmcCmdBlk.CommandType  = SdMmcCommandTypeAdtc;
+  SdMmcCmdBlk.ResponseType = SdMmcResponseTypeR1;
+  SdMmcCmdBlk.CommandArgument = 0;
+
+  Packet.InDataBuffer = TuningBlock;
+  if (BusWidth == 8) {
+    Packet.InTransferLength = sizeof (TuningBlock);
+  } else {
+    Packet.InTransferLength = 64;
+  }
+
+  Status = DwMmcPassThruPassThru (PassThru, 0, &Packet, NULL);
+
+  return Status;
+}
+
+/**
+  Tunning the clock to get HS200 optimal sampling point.
+
+  Command SEND_TUNING_BLOCK may be sent up to 40 times until the host finishes
+  the tuning procedure.
+
+  Refer to EMMC Electrical Standard Spec 5.1 Section 6.6.8.
+
+  @param[in] DevIo          A pointer to the EFI_DEVICE_IO_PROTOCOL instance.
+  @param[in] PassThru       A pointer to the EFI_SD_MMC_PASS_THRU_PROTOCOL
+                            instance.
+  @param[in] BusWidth       The bus width to work.
+
+  @retval EFI_SUCCESS       The operation is done correctly.
+  @retval Others            The operation fails.
+
+**/
+EFI_STATUS
+EmmcTuningClkForHs200 (
+  IN EFI_DEVICE_IO_PROTOCOL             *DevIo,
+  IN EFI_SD_MMC_PASS_THRU_PROTOCOL      *PassThru,
+  IN UINT8                              BusWidth
+  )
+{
+  return EFI_SUCCESS;
+}
+
+/**
+  Switch the bus width to specified width.
+
+  Refer to EMMC Electrical Standard Spec 5.1 Section 6.6.9.
+
+  @param[in] DevIo          A pointer to the EFI_DEVICE_IO_PROTOCOL instance.
+  @param[in] PassThru       A pointer to the EFI_SD_MMC_PASS_THRU_PROTOCOL
+                            instance.
+  @param[in] Rca            The relative device address to be assigned.
+  @param[in] IsDdr          If TRUE, use dual data rate data simpling method.
+                            Otherwise use single data rate data simpling method.
+  @param[in] BusWidth       The bus width to be set, it could be 4 or 8.
+
+  @retval EFI_SUCCESS       The operation is done correctly.
+  @retval Others            The operation fails.
+
+**/
+EFI_STATUS
+EmmcSwitchBusWidth (
+  IN EFI_DEVICE_IO_PROTOCOL             *DevIo,
+  IN EFI_SD_MMC_PASS_THRU_PROTOCOL      *PassThru,
+  IN UINT16                             Rca,
+  IN BOOLEAN                            IsDdr,
+  IN UINT8                              BusWidth
+  )
+{
+  EFI_STATUS          Status;
+  UINT8               Access;
+  UINT8               Index;
+  UINT8               Value;
+  UINT8               CmdSet;
+  UINT32              DevStatus;
+
+  //
+  // Write Byte, the Value field is written into the byte pointed by Index.
+  //
+  Access = 0x03;
+  Index  = OFFSET_OF (EMMC_EXT_CSD, BusWidth);
+  if (BusWidth == 1) {
+    Value = 0;
+  } else {
+    if (BusWidth == 4) {
+      Value = 1;
+    } else if (BusWidth == 8) {
+      Value = 2;
+    } else {
+      return EFI_INVALID_PARAMETER;
+    }
+
+    if (IsDdr) {
+      Value += 4;
+    }
+  }
+
+  CmdSet = 0;
+  Status = EmmcSwitch (PassThru, Access, Index, Value, CmdSet);
+  if (EFI_ERROR (Status)) {
+    DEBUG ((
+      DEBUG_ERROR,
+      "EmmcSwitchBusWidth: Switch to bus width %d fails with %r\n",
+      BusWidth,
+      Status
+      ));
+    return Status;
+  }
+
+  do {
+    Status = EmmcSendStatus (PassThru, Rca, &DevStatus);
+    if (EFI_ERROR (Status)) {
+      DEBUG ((
+        DEBUG_ERROR,
+        "EmmcSwitchBusWidth: Send status fails with %r\n",
+        Status
+        ));
+      return Status;
+    }
+    //
+    // Check the switch operation is really successful or not.
+    //
+  } while ((DevStatus & 0xf) == EMMC_STATE_PRG);
+
+  Status = DwMmcHcSetBusWidth (DevIo, IsDdr, BusWidth);
+  if (EFI_ERROR (Status)) {
+    return Status;
+  }
+
+  return Status;
+}
+
+/**
+  Switch the clock frequency to the specified value.
+
+  Refer to EMMC Electrical Standard Spec 5.1 Section 6.6.
+
+  @param[in] DevIo          A pointer to the EFI_DEVICE_IO_PROTOCOL instance.
+  @param[in] PassThru       A pointer to the EFI_SD_MMC_PASS_THRU_PROTOCOL
+                            instance.
+  @param[in] Rca            The relative device address to be assigned.
+  @param[in] HsTiming       The value to be written to HS_TIMING field of
+                            EXT_CSD register.
+  @param[in] ClockFreq      The max clock frequency to be set, the unit is MHz.
+
+  @retval EFI_SUCCESS       The operation is done correctly.
+  @retval Others            The operation fails.
+
+**/
+EFI_STATUS
+EmmcSwitchClockFreq (
+  IN EFI_DEVICE_IO_PROTOCOL             *DevIo,
+  IN EFI_SD_MMC_PASS_THRU_PROTOCOL      *PassThru,
+  IN UINT16                             Rca,
+  IN UINT8                              HsTiming,
+  IN UINT32                             ClockFreq
+  )
+{
+  EFI_STATUS                Status;
+  UINT8                     Access;
+  UINT8                     Index;
+  UINT8                     Value;
+  UINT8                     CmdSet;
+  UINT32                    DevStatus;
+  DW_MMC_HC_PRIVATE_DATA    *Private;
+
+  Private = DW_MMC_HC_PRIVATE_FROM_THIS (PassThru);
+  //
+  // Write Byte, the Value field is written into the byte pointed by Index.
+  //
+  Access = 0x03;
+  Index  = OFFSET_OF (EMMC_EXT_CSD, HsTiming);
+  Value  = HsTiming;
+  CmdSet = 0;
+
+  Status = EmmcSwitch (PassThru, Access, Index, Value, CmdSet);
+  if (EFI_ERROR (Status)) {
+    DEBUG ((
+      DEBUG_ERROR,
+      "EmmcSwitchClockFreq: Switch to hstiming %d fails with %r\n",
+      HsTiming,
+      Status
+      ));
+    return Status;
+  }
+
+  Status = EmmcSendStatus (PassThru, Rca, &DevStatus);
+  if (EFI_ERROR (Status)) {
+    DEBUG ((
+      DEBUG_ERROR,
+      "EmmcSwitchClockFreq: Send status fails with %r\n",
+      Status
+      ));
+    return Status;
+  }
+  //
+  // Check the switch operation is really successful or not.
+  //
+  if ((DevStatus & BIT7) != 0) {
+    DEBUG ((
+      DEBUG_ERROR,
+      "EmmcSwitchClockFreq: The switch operation fails as DevStatus 0x%08x\n",
+      DevStatus
+      ));
+    return EFI_DEVICE_ERROR;
+  }
+  //
+  // Convert the clock freq unit from MHz to KHz.
+  //
+  Status = DwMmcHcClockSupply (DevIo, ClockFreq * 1000, Private->Capability[0]);
+
+  return Status;
+}
+
+/**
+  Switch to the High Speed timing according to request.
+
+  Refer to EMMC Electrical Standard Spec 5.1 Section 6.6.8.
+
+  @param[in] DevIo          A pointer to the EFI_DEVICE_IO_PROTOCOL instance.
+  @param[in] PassThru       A pointer to the EFI_SD_MMC_PASS_THRU_PROTOCOL
+                            instance.
+  @param[in] Rca            The relative device address to be assigned.
+  @param[in] ClockFreq      The max clock frequency to be set.
+  @param[in] IsDdr          If TRUE, use dual data rate data simpling method.
+                            Otherwise use single data rate data simpling method.
+  @param[in] BusWidth       The bus width to be set, it could be 4 or 8.
+
+  @retval EFI_SUCCESS       The operation is done correctly.
+  @retval Others            The operation fails.
+
+**/
+EFI_STATUS
+EmmcSwitchToHighSpeed (
+  IN EFI_DEVICE_IO_PROTOCOL             *DevIo,
+  IN EFI_SD_MMC_PASS_THRU_PROTOCOL      *PassThru,
+  IN UINT16                             Rca,
+  IN UINT32                             ClockFreq,
+  IN BOOLEAN                            IsDdr,
+  IN UINT8                              BusWidth
+  )
+{
+  EFI_STATUS          Status;
+  UINT8               HsTiming;
+
+  HsTiming = 1;
+  Status = EmmcSwitchClockFreq (DevIo, PassThru, Rca, HsTiming, ClockFreq);
+  if (EFI_ERROR (Status)) {
+    return Status;
+  }
+  Status = EmmcSwitchBusWidth (DevIo, PassThru, Rca, IsDdr, BusWidth);
+  if (EFI_ERROR (Status)) {
+    return Status;
+  }
+  return EFI_SUCCESS;
+}
+
+/**
+  Switch to the HS200 timing according to request.
+
+  Refer to EMMC Electrical Standard Spec 5.1 Section 6.6.8.
+
+  @param[in] DevIo          A pointer to the EFI_DEVICE_IO_PROTOCOL instance.
+  @param[in] PassThru       A pointer to the EFI_SD_MMC_PASS_THRU_PROTOCOL
+                            instance.
+  @param[in] Rca            The relative device address to be assigned.
+  @param[in] ClockFreq      The max clock frequency to be set.
+  @param[in] BusWidth       The bus width to be set, it could be 4 or 8.
+
+  @retval EFI_SUCCESS       The operation is done correctly.
+  @retval Others            The operation fails.
+
+**/
+EFI_STATUS
+EmmcSwitchToHS200 (
+  IN EFI_DEVICE_IO_PROTOCOL             *DevIo,
+  IN EFI_SD_MMC_PASS_THRU_PROTOCOL      *PassThru,
+  IN UINT16                             Rca,
+  IN UINT32                             ClockFreq,
+  IN UINT8                              BusWidth
+  )
+{
+  return EFI_SUCCESS;
+}
+
+/**
+  Switch the high speed timing according to request.
+
+  Refer to EMMC Electrical Standard Spec 5.1 Section 6.6.8.
+
+  @param[in] DevIo          A pointer to the EFI_DEVICE_IO_PROTOCOL instance.
+  @param[in] PassThru       A pointer to the EFI_SD_MMC_PASS_THRU_PROTOCOL
+                            instance.
+  @param[in] Rca            The relative device address to be assigned.
+
+  @retval EFI_SUCCESS       The operation is done correctly.
+  @retval Others            The operation fails.
+
+**/
+EFI_STATUS
+EmmcSetBusMode (
+  IN EFI_DEVICE_IO_PROTOCOL             *DevIo,
+  IN EFI_SD_MMC_PASS_THRU_PROTOCOL      *PassThru,
+  IN UINT16                             Rca
+  )
+{
+  EFI_STATUS                    Status;
+  EMMC_CSD                      Csd;
+  EMMC_EXT_CSD                  ExtCsd;
+  UINT8                         HsTiming;
+  BOOLEAN                       IsDdr;
+  UINT32                        DevStatus;
+  UINT32                        ClockFreq;
+  UINT8                         BusWidth;
+  DW_MMC_HC_PRIVATE_DATA        *Private;
+
+  Private = DW_MMC_HC_PRIVATE_FROM_THIS (PassThru);
+  ASSERT (Private->Capability[0].BaseClkFreq != 0);
+
+  Status = EmmcGetCsd (PassThru, Rca, &Csd);
+  if (EFI_ERROR (Status)) {
+    DEBUG ((DEBUG_ERROR, "EmmcSetBusMode: GetCsd fails with %r\n", Status));
+    return Status;
+  }
+
+  Status = EmmcSelect (PassThru, Rca);
+  if (EFI_ERROR (Status)) {
+    DEBUG ((DEBUG_ERROR, "EmmcSetBusMode: Select fails with %r\n", Status));
+    return Status;
+  }
+
+  do {
+    Status = EmmcSendStatus (PassThru, Rca, &DevStatus);
+    if (EFI_ERROR (Status)) {
+      DEBUG ((
+        DEBUG_ERROR,
+        "EmmcSetBusMode: Get Status fails with %r\n",
+        Status
+        ));
+      return Status;
+    }
+  } while (EMMC_GET_STATE (DevStatus) != EMMC_STATE_TRAN);
+
+  BusWidth = 1;
+  Status = EmmcSwitchBusWidth (DevIo, PassThru, Rca, FALSE, BusWidth);
+  if (EFI_ERROR (Status)) {
+    return Status;
+  }
+
+  BusWidth = Private->Capability[0].BusWidth;
+  //
+  // Get Deivce_Type from EXT_CSD register.
+  //
+  Status = EmmcGetExtCsd (PassThru, &ExtCsd);
+  if (EFI_ERROR (Status)) {
+    DEBUG ((DEBUG_ERROR, "EmmcSetBusMode: GetExtCsd fails with %r\n", Status));
+    return Status;
+  }
+
+  //
+  // Calculate supported bus speed/bus width/clock frequency.
+  //
+  HsTiming  = 0;
+  IsDdr     = FALSE;
+  ClockFreq = 0;
+  if (((ExtCsd.DeviceType & (BIT4 | BIT5)) != 0) &&
+      (Private->Capability[0].Sdr104 != 0)) {
+    HsTiming  = 2;
+    IsDdr     = FALSE;
+    ClockFreq = 200;
+  } else if (((ExtCsd.DeviceType & (BIT2 | BIT3)) != 0) &&
+             (Private->Capability[0].Ddr50 != 0)) {
+    HsTiming  = 1;
+    IsDdr     = TRUE;
+    ClockFreq = 52;
+  } else if (((ExtCsd.DeviceType & BIT1) != 0) &&
+             (Private->Capability[0].HighSpeed != 0)) {
+    HsTiming  = 1;
+    IsDdr     = FALSE;
+    ClockFreq = 52;
+  } else if (((ExtCsd.DeviceType & BIT0) != 0) &&
+             (Private->Capability[0].HighSpeed != 0)) {
+    HsTiming  = 1;
+    IsDdr     = FALSE;
+    ClockFreq = 26;
+  }
+
+  if ((ClockFreq == 0) || (HsTiming == 0)) {
+    //
+    // Continue using default setting.
+    //
+    return EFI_SUCCESS;
+  }
+
+  DEBUG ((
+    DEBUG_INFO,
+    "EmmcSetBusMode: HsTiming %d ClockFreq %d BusWidth %d Ddr %a\n",
+    HsTiming,
+    ClockFreq,
+    BusWidth,
+    IsDdr ? "TRUE" : "FALSE"
+    ));
+
+  if (HsTiming == 2) {
+    //
+    // Execute HS200 timing switch procedure
+    //
+    Status = EmmcSwitchToHS200 (DevIo, PassThru, Rca, ClockFreq, BusWidth);
+  } else {
+    //
+    // Execute High Speed timing switch procedure
+    //
+    Status = EmmcSwitchToHighSpeed (
+               DevIo,
+               PassThru,
+               Rca,
+               ClockFreq,
+               IsDdr,
+               BusWidth
+               );
+  }
+
+  DEBUG ((
+    DEBUG_INFO,
+    "EmmcSetBusMode: Switch to %a %r\n",
+    (HsTiming == 3) ? "HS400" : ((HsTiming == 2) ? "HS200" : "HighSpeed"),
+    Status
+    ));
+
+  return Status;
+}
+
+/**
+  Execute EMMC device identification procedure.
+
+  Refer to EMMC Electrical Standard Spec 5.1 Section 6.4 for details.
+
+  @param[in] Private        A pointer to the DW_MMC_HC_PRIVATE_DATA instance.
+
+  @retval EFI_SUCCESS       There is a EMMC card.
+  @retval Others            There is not a EMMC card.
+
+**/
+EFI_STATUS
+EmmcIdentification (
+  IN DW_MMC_HC_PRIVATE_DATA             *Private
+  )
+{
+  EFI_STATUS                     Status;
+  EFI_DEVICE_IO_PROTOCOL         *DevIo;
+  EFI_SD_MMC_PASS_THRU_PROTOCOL  *PassThru;
+  UINT32                         Ocr;
+  UINT16                         Rca;
+  UINT32                         DevStatus;
+  UINT32                         Timeout;
+
+  DevIo    = Private->DevIo;
+  PassThru = &Private->PassThru;
+
+  Status = EmmcReset (PassThru);
+  if (EFI_ERROR (Status)) {
+    DEBUG ((
+      DEBUG_INFO,
+      "EmmcIdentification: Executing Cmd0 fails with %r\n",
+      Status
+      ));
+    return Status;
+  }
+
+  Timeout = 100;
+  do {
+    Ocr = EMMC_CMD1_CAPACITY_GREATER_THAN_2GB;
+    Status = EmmcGetOcr (PassThru, &Ocr);
+    if (EFI_ERROR (Status)) {
+      DEBUG ((
+        DEBUG_INFO,
+        "EmmcIdentification: Executing Cmd1 fails with %r\n",
+        Status
+        ));
+      return Status;
+    }
+    if (--Timeout <= 0) {
+      return EFI_DEVICE_ERROR;
+    }
+    MicroSecondDelay (100);
+  } while ((Ocr & BIT31) == 0);
+
+  Status = EmmcGetAllCid (PassThru);
+  if (EFI_ERROR (Status)) {
+    DEBUG ((
+      DEBUG_INFO,
+      "EmmcIdentification: Executing Cmd2 fails with %r\n",
+      Status
+      ));
+    return Status;
+  }
+  //
+  // valid RCA starts from 1.
+  // Here we takes a simple formula to calculate the RCA.
+  // Don't support multiple devices on the slot, that is
+  // shared bus slot feature.
+  //
+  Rca    = 1;
+  Status = EmmcSetRca (PassThru, Rca);
+  if (EFI_ERROR (Status)) {
+    DEBUG ((
+      DEBUG_INFO,
+      "EmmcIdentification: Executing Cmd3 fails with %r\n",
+      Status
+      ));
+    return Status;
+  }
+  //
+  // Enter Data Tranfer Mode.
+  //
+  DEBUG ((
+    DEBUG_INFO,
+    "EmmcIdentification: Found a EMMC device at RCA [%d]\n",
+    Rca
+    ));
+  Private->Slot[0].CardType = EmmcCardType;
+
+  Status = EmmcSetBusMode (DevIo, PassThru, Rca);
+  if (EFI_ERROR (Status)) {
+    return Status;
+  }
+
+  //
+  // Exit DATA Mode.
+  //
+  do {
+    Status = EmmcSendStatus (PassThru, Rca, &DevStatus);
+    if (EFI_ERROR (Status)) {
+      DEBUG ((
+        DEBUG_INFO,
+        "EmmcSwitchBusWidth: Send status fails with %r\n",
+        Status
+        ));
+      return Status;
+    }
+  } while ((DevStatus & 0xf) == EMMC_STATE_DATA);
+
+  return Status;
+}
diff --git a/EmbeddedPkg/Drivers/DwMmcHcDxe/SdDevice.c b/EmbeddedPkg/Drivers/DwMmcHcDxe/SdDevice.c
new file mode 100644
index 000000000000..58900b03417f
--- /dev/null
+++ b/EmbeddedPkg/Drivers/DwMmcHcDxe/SdDevice.c
@@ -0,0 +1,1104 @@ 
+/** @file
+  This file provides some helper functions which are specific for SD card
+  device.
+
+  Copyright (c) 2015 - 2016, Intel Corporation. All rights reserved.<BR>
+  Copyright (c) 2018, Linaro. All rights reserved.<BR>
+
+  This program and the accompanying materials are licensed and made available
+  under the terms and conditions of the BSD License which accompanies this
+  distribution.  The full text of the license may be found at
+  http://opensource.org/licenses/bsd-license.php
+
+  THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+  WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#include <IndustryStandard/Sd.h>
+
+#include <Library/BaseMemoryLib.h>
+#include <Library/DebugLib.h>
+
+#include "DwMmcHcDxe.h"
+
+/**
+  Send command GO_IDLE_STATE to the device to make it go to Idle State.
+
+  Refer to SD Physical Layer Simplified Spec 4.1 Section 4.7 for details.
+
+  @param[in] PassThru       A pointer to the EFI_SD_MMC_PASS_THRU_PROTOCOL
+                            instance.
+
+  @retval EFI_SUCCESS       The SD device is reset correctly.
+  @retval Others            The device reset fails.
+
+**/
+EFI_STATUS
+SdCardReset (
+  IN EFI_SD_MMC_PASS_THRU_PROTOCOL      *PassThru
+  )
+{
+  EFI_SD_MMC_COMMAND_BLOCK              SdMmcCmdBlk;
+  EFI_SD_MMC_STATUS_BLOCK               SdMmcStatusBlk;
+  EFI_SD_MMC_PASS_THRU_COMMAND_PACKET   Packet;
+  EFI_STATUS                            Status;
+
+  ZeroMem (&SdMmcCmdBlk, sizeof (SdMmcCmdBlk));
+  ZeroMem (&SdMmcStatusBlk, sizeof (SdMmcStatusBlk));
+  ZeroMem (&Packet, sizeof (Packet));
+
+  Packet.SdMmcCmdBlk    = &SdMmcCmdBlk;
+  Packet.SdMmcStatusBlk = &SdMmcStatusBlk;
+  Packet.Timeout        = DW_MMC_HC_GENERIC_TIMEOUT;
+
+  SdMmcCmdBlk.CommandIndex = SD_GO_IDLE_STATE;
+  SdMmcCmdBlk.CommandType  = SdMmcCommandTypeBc;
+
+  Status = DwMmcPassThruPassThru (PassThru, 0, &Packet, NULL);
+
+  return Status;
+}
+
+/**
+  Send command SEND_IF_COND to the device to inquiry the SD Memory Card
+  interface condition.
+
+  Refer to SD Physical Layer Simplified Spec 4.1 Section 4.7 for details.
+
+  @param[in] PassThru       A pointer to the EFI_SD_MMC_PASS_THRU_PROTOCOL
+                            instance.
+  @param[in] SupplyVoltage  The supplied voltage by the host.
+  @param[in] CheckPattern   The check pattern to be sent to the device.
+
+  @retval EFI_SUCCESS       The operation is done correctly.
+  @retval Others            The operation fails.
+
+**/
+EFI_STATUS
+SdCardVoltageCheck (
+  IN EFI_SD_MMC_PASS_THRU_PROTOCOL      *PassThru,
+  IN UINT8                              SupplyVoltage,
+  IN UINT8                              CheckPattern
+  )
+{
+  EFI_SD_MMC_COMMAND_BLOCK              SdMmcCmdBlk;
+  EFI_SD_MMC_STATUS_BLOCK               SdMmcStatusBlk;
+  EFI_SD_MMC_PASS_THRU_COMMAND_PACKET   Packet;
+  EFI_STATUS                            Status;
+
+  ZeroMem (&SdMmcCmdBlk, sizeof (SdMmcCmdBlk));
+  ZeroMem (&SdMmcStatusBlk, sizeof (SdMmcStatusBlk));
+  ZeroMem (&Packet, sizeof (Packet));
+
+  Packet.SdMmcCmdBlk    = &SdMmcCmdBlk;
+  Packet.SdMmcStatusBlk = &SdMmcStatusBlk;
+  Packet.Timeout        = DW_MMC_HC_GENERIC_TIMEOUT;
+
+  SdMmcCmdBlk.CommandIndex = SD_SEND_IF_COND;
+  SdMmcCmdBlk.CommandType  = SdMmcCommandTypeBcr;
+  SdMmcCmdBlk.ResponseType = SdMmcResponseTypeR7;
+  SdMmcCmdBlk.CommandArgument = (SupplyVoltage << 8) | CheckPattern;
+
+  Status = DwMmcPassThruPassThru (PassThru, 0, &Packet, NULL);
+
+  if (!EFI_ERROR (Status)) {
+    if (SdMmcStatusBlk.Resp0 != SdMmcCmdBlk.CommandArgument) {
+      return EFI_DEVICE_ERROR;
+    }
+  }
+
+  return Status;
+}
+
+/**
+  Send command SDIO_SEND_OP_COND to the device to see whether it is SDIO device.
+
+  Refer to SDIO Simplified Spec 3 Section 3.2 for details.
+
+  @param[in] PassThru       A pointer to the EFI_SD_MMC_PASS_THRU_PROTOCOL
+                            instance.
+  @param[in] VoltageWindow  The supply voltage window.
+  @param[in] S18R           The boolean to show if it should switch to 1.8v.
+
+  @retval EFI_SUCCESS       The operation is done correctly.
+  @retval Others            The operation fails.
+
+**/
+EFI_STATUS
+SdioSendOpCond (
+  IN EFI_SD_MMC_PASS_THRU_PROTOCOL      *PassThru,
+  IN UINT32                             VoltageWindow,
+  IN BOOLEAN                            S18R
+  )
+{
+  EFI_SD_MMC_COMMAND_BLOCK              SdMmcCmdBlk;
+  EFI_SD_MMC_STATUS_BLOCK               SdMmcStatusBlk;
+  EFI_SD_MMC_PASS_THRU_COMMAND_PACKET   Packet;
+  EFI_STATUS                            Status;
+  UINT32                                Switch;
+
+  ZeroMem (&SdMmcCmdBlk, sizeof (SdMmcCmdBlk));
+  ZeroMem (&SdMmcStatusBlk, sizeof (SdMmcStatusBlk));
+  ZeroMem (&Packet, sizeof (Packet));
+
+  Packet.SdMmcCmdBlk    = &SdMmcCmdBlk;
+  Packet.SdMmcStatusBlk = &SdMmcStatusBlk;
+  Packet.Timeout        = DW_MMC_HC_GENERIC_TIMEOUT;
+
+  SdMmcCmdBlk.CommandIndex = SDIO_SEND_OP_COND;
+  SdMmcCmdBlk.CommandType  = SdMmcCommandTypeBcr;
+  SdMmcCmdBlk.ResponseType = SdMmcResponseTypeR4;
+
+  Switch = S18R ? BIT24 : 0;
+
+  SdMmcCmdBlk.CommandArgument = (VoltageWindow & 0xFFFFFF) | Switch;
+
+  Status = DwMmcPassThruPassThru (PassThru, 0, &Packet, NULL);
+
+  return Status;
+}
+
+/**
+  Send command SD_SEND_OP_COND to the device to see whether it is SDIO device.
+
+  Refer to SD Physical Layer Simplified Spec 4.1 Section 4.7 for details.
+
+  @param[in]  PassThru       A pointer to the EFI_SD_MMC_PASS_THRU_PROTOCOL
+                             instance.
+  @param[in]  Rca            The relative device address of addressed device.
+  @param[in]  VoltageWindow  The supply voltage window.
+  @param[in]  S18R           The boolean to show if it should switch to 1.8v.
+  @param[in]  Xpc            The boolean to show if it should provide 0.36w
+                             power control.
+  @param[in]  Hcs            The boolean to show if it support host capacity
+                             info.
+  @param[out] Ocr            The buffer to store returned OCR register value.
+
+  @retval EFI_SUCCESS        The operation is done correctly.
+  @retval Others             The operation fails.
+
+**/
+EFI_STATUS
+SdCardSendOpCond (
+  IN     EFI_SD_MMC_PASS_THRU_PROTOCOL  *PassThru,
+  IN     UINT16                         Rca,
+  IN     UINT32                         VoltageWindow,
+  IN     BOOLEAN                        S18R,
+  IN     BOOLEAN                        Xpc,
+  IN     BOOLEAN                        Hcs,
+     OUT UINT32                         *Ocr
+  )
+{
+  EFI_SD_MMC_COMMAND_BLOCK              SdMmcCmdBlk;
+  EFI_SD_MMC_STATUS_BLOCK               SdMmcStatusBlk;
+  EFI_SD_MMC_PASS_THRU_COMMAND_PACKET   Packet;
+  EFI_STATUS                            Status;
+  UINT32                                Switch;
+  UINT32                                MaxPower;
+  UINT32                                HostCapacity;
+
+  ZeroMem (&SdMmcCmdBlk, sizeof (SdMmcCmdBlk));
+  ZeroMem (&SdMmcStatusBlk, sizeof (SdMmcStatusBlk));
+  ZeroMem (&Packet, sizeof (Packet));
+
+  Packet.SdMmcCmdBlk    = &SdMmcCmdBlk;
+  Packet.SdMmcStatusBlk = &SdMmcStatusBlk;
+  Packet.Timeout        = DW_MMC_HC_GENERIC_TIMEOUT;
+
+  SdMmcCmdBlk.CommandIndex = SD_APP_CMD;
+  SdMmcCmdBlk.CommandType  = SdMmcCommandTypeAc;
+  SdMmcCmdBlk.ResponseType = SdMmcResponseTypeR1;
+  SdMmcCmdBlk.CommandArgument = (UINT32)Rca << 16;
+
+  Status = DwMmcPassThruPassThru (PassThru, 0, &Packet, NULL);
+  if (EFI_ERROR (Status)) {
+    return Status;
+  }
+
+  SdMmcCmdBlk.CommandIndex = SD_SEND_OP_COND;
+  SdMmcCmdBlk.CommandType  = SdMmcCommandTypeBcr;
+  SdMmcCmdBlk.ResponseType = SdMmcResponseTypeR3;
+
+  Switch       = S18R ? BIT24 : 0;
+  MaxPower     = Xpc ? BIT28 : 0;
+  HostCapacity = Hcs ? BIT30 : 0;
+
+  SdMmcCmdBlk.CommandArgument = (VoltageWindow & 0xFFFFFF) | Switch | \
+                                MaxPower | HostCapacity;
+
+  Status = DwMmcPassThruPassThru (PassThru, 0, &Packet, NULL);
+  if (!EFI_ERROR (Status)) {
+    *Ocr = SdMmcStatusBlk.Resp0;
+  }
+
+  return Status;
+}
+
+/**
+  Broadcast command ALL_SEND_CID to the bus to ask all the SD devices to send
+  the data of their CID registers.
+
+  Refer to SD Physical Layer Simplified Spec 4.1 Section 4.7 for details.
+
+  @param[in] PassThru       A pointer to the EFI_SD_MMC_PASS_THRU_PROTOCOL
+                            instance.
+
+  @retval EFI_SUCCESS       The operation is done correctly.
+  @retval Others            The operation fails.
+
+**/
+EFI_STATUS
+SdCardAllSendCid (
+  IN EFI_SD_MMC_PASS_THRU_PROTOCOL      *PassThru
+  )
+{
+  EFI_SD_MMC_COMMAND_BLOCK              SdMmcCmdBlk;
+  EFI_SD_MMC_STATUS_BLOCK               SdMmcStatusBlk;
+  EFI_SD_MMC_PASS_THRU_COMMAND_PACKET   Packet;
+  EFI_STATUS                            Status;
+
+  ZeroMem (&SdMmcCmdBlk, sizeof (SdMmcCmdBlk));
+  ZeroMem (&SdMmcStatusBlk, sizeof (SdMmcStatusBlk));
+  ZeroMem (&Packet, sizeof (Packet));
+
+  Packet.SdMmcCmdBlk    = &SdMmcCmdBlk;
+  Packet.SdMmcStatusBlk = &SdMmcStatusBlk;
+  Packet.Timeout        = DW_MMC_HC_GENERIC_TIMEOUT;
+
+  SdMmcCmdBlk.CommandIndex = SD_ALL_SEND_CID;
+  SdMmcCmdBlk.CommandType  = SdMmcCommandTypeBcr;
+  SdMmcCmdBlk.ResponseType = SdMmcResponseTypeR2;
+
+  Status = DwMmcPassThruPassThru (PassThru, 0, &Packet, NULL);
+
+  return Status;
+}
+
+/**
+  Send command SET_RELATIVE_ADDR to the SD device to assign a Relative device
+  Address (RCA).
+
+  Refer to SD Physical Layer Simplified Spec 4.1 Section 4.7 for details.
+
+  @param[in]  PassThru      A pointer to the EFI_SD_MMC_PASS_THRU_PROTOCOL
+                            instance.
+  @param[out] Rca           The relative device address to assign.
+
+  @retval EFI_SUCCESS       The operation is done correctly.
+  @retval Others            The operation fails.
+
+**/
+EFI_STATUS
+SdCardSetRca (
+  IN     EFI_SD_MMC_PASS_THRU_PROTOCOL  *PassThru,
+     OUT UINT16                         *Rca
+  )
+{
+  EFI_SD_MMC_COMMAND_BLOCK              SdMmcCmdBlk;
+  EFI_SD_MMC_STATUS_BLOCK               SdMmcStatusBlk;
+  EFI_SD_MMC_PASS_THRU_COMMAND_PACKET   Packet;
+  EFI_STATUS                            Status;
+
+  ZeroMem (&SdMmcCmdBlk, sizeof (SdMmcCmdBlk));
+  ZeroMem (&SdMmcStatusBlk, sizeof (SdMmcStatusBlk));
+  ZeroMem (&Packet, sizeof (Packet));
+
+  Packet.SdMmcCmdBlk    = &SdMmcCmdBlk;
+  Packet.SdMmcStatusBlk = &SdMmcStatusBlk;
+  Packet.Timeout        = DW_MMC_HC_GENERIC_TIMEOUT;
+
+  SdMmcCmdBlk.CommandIndex = SD_SET_RELATIVE_ADDR;
+  SdMmcCmdBlk.CommandType  = SdMmcCommandTypeBcr;
+  SdMmcCmdBlk.ResponseType = SdMmcResponseTypeR6;
+
+  Status = DwMmcPassThruPassThru (PassThru, 0, &Packet, NULL);
+  if (!EFI_ERROR (Status)) {
+    *Rca = (UINT16)(SdMmcStatusBlk.Resp0 >> 16);
+  }
+
+  return Status;
+}
+
+/**
+  Send command SEND_CSD to the SD device to get the data of the CSD register.
+
+  Refer to SD Physical Layer Simplified Spec 4.1 Section 4.7 for details.
+
+  @param[in]  PassThru      A pointer to the EFI_SD_MMC_PASS_THRU_PROTOCOL
+                            instance.
+  @param[in]  Rca           The relative device address of selected device.
+  @param[out] Csd           The buffer to store the content of the CSD register.
+                            Note the caller should ignore the lowest byte of
+                            this buffer as the content of this byte is meaning-
+                            less even if the operation succeeds.
+
+  @retval EFI_SUCCESS       The operation is done correctly.
+  @retval Others            The operation fails.
+
+**/
+EFI_STATUS
+SdCardGetCsd (
+  IN     EFI_SD_MMC_PASS_THRU_PROTOCOL  *PassThru,
+  IN     UINT16                         Rca,
+     OUT SD_CSD                         *Csd
+  )
+{
+  EFI_SD_MMC_COMMAND_BLOCK              SdMmcCmdBlk;
+  EFI_SD_MMC_STATUS_BLOCK               SdMmcStatusBlk;
+  EFI_SD_MMC_PASS_THRU_COMMAND_PACKET   Packet;
+  EFI_STATUS                            Status;
+
+  ZeroMem (&SdMmcCmdBlk, sizeof (SdMmcCmdBlk));
+  ZeroMem (&SdMmcStatusBlk, sizeof (SdMmcStatusBlk));
+  ZeroMem (&Packet, sizeof (Packet));
+
+  Packet.SdMmcCmdBlk    = &SdMmcCmdBlk;
+  Packet.SdMmcStatusBlk = &SdMmcStatusBlk;
+  Packet.Timeout        = DW_MMC_HC_GENERIC_TIMEOUT;
+
+  SdMmcCmdBlk.CommandIndex = SD_SEND_CSD;
+  SdMmcCmdBlk.CommandType  = SdMmcCommandTypeAc;
+  SdMmcCmdBlk.ResponseType = SdMmcResponseTypeR2;
+  SdMmcCmdBlk.CommandArgument = (UINT32)Rca << 16;
+
+  Status = DwMmcPassThruPassThru (PassThru, 0, &Packet, NULL);
+  if (!EFI_ERROR (Status)) {
+    CopyMem (((UINT8*)Csd) + 1, &SdMmcStatusBlk.Resp0, sizeof (SD_CSD) - 1);
+  }
+
+  return Status;
+}
+
+/**
+  Send command SEND_CSD to the SD device to get the data of the CSD register.
+
+  Refer to SD Physical Layer Simplified Spec 4.1 Section 4.7 for details.
+
+  @param[in]  PassThru      A pointer to the EFI_SD_MMC_PASS_THRU_PROTOCOL
+                            instance.
+  @param[in]  Rca           The relative device address of selected device.
+  @param[out] Scr           The buffer to store the content of the SCR register.
+
+  @retval EFI_SUCCESS       The operation is done correctly.
+  @retval Others            The operation fails.
+
+**/
+EFI_STATUS
+SdCardGetScr (
+  IN     EFI_SD_MMC_PASS_THRU_PROTOCOL  *PassThru,
+  IN     UINT16                         Rca,
+     OUT SD_SCR                         *Scr
+  )
+{
+  EFI_SD_MMC_COMMAND_BLOCK              SdMmcCmdBlk;
+  EFI_SD_MMC_STATUS_BLOCK               SdMmcStatusBlk;
+  EFI_SD_MMC_PASS_THRU_COMMAND_PACKET   Packet;
+  EFI_STATUS                            Status;
+
+  ZeroMem (&SdMmcCmdBlk, sizeof (SdMmcCmdBlk));
+  ZeroMem (&SdMmcStatusBlk, sizeof (SdMmcStatusBlk));
+  ZeroMem (&Packet, sizeof (Packet));
+
+  Packet.SdMmcCmdBlk    = &SdMmcCmdBlk;
+  Packet.SdMmcStatusBlk = &SdMmcStatusBlk;
+  Packet.Timeout        = DW_MMC_HC_GENERIC_TIMEOUT;
+
+  SdMmcCmdBlk.CommandIndex = SD_APP_CMD;
+  SdMmcCmdBlk.CommandType  = SdMmcCommandTypeAc;
+  SdMmcCmdBlk.ResponseType = SdMmcResponseTypeR1;
+  SdMmcCmdBlk.CommandArgument = (UINT32)Rca << 16;
+
+  Status = DwMmcPassThruPassThru (PassThru, 0, &Packet, NULL);
+  if (EFI_ERROR (Status)) {
+    return Status;
+  }
+
+  SdMmcCmdBlk.CommandIndex = SD_SEND_SCR;
+  SdMmcCmdBlk.CommandType  = SdMmcCommandTypeAdtc;
+  SdMmcCmdBlk.ResponseType = SdMmcResponseTypeR1;
+
+  Packet.InDataBuffer     = Scr;
+  Packet.InTransferLength = sizeof (SD_SCR);
+
+  Status = DwMmcPassThruPassThru (PassThru, 0, &Packet, NULL);
+
+  return Status;
+}
+
+/**
+  Send command SELECT_DESELECT_CARD to the SD device to select/deselect it.
+
+  Refer to SD Physical Layer Simplified Spec 4.1 Section 4.7 for details.
+
+  @param[in]  PassThru      A pointer to the EFI_SD_MMC_PASS_THRU_PROTOCOL
+                            instance.
+  @param[in]  Rca           The relative device address of selected device.
+
+  @retval EFI_SUCCESS       The operation is done correctly.
+  @retval Others            The operation fails.
+
+**/
+EFI_STATUS
+SdCardSelect (
+  IN EFI_SD_MMC_PASS_THRU_PROTOCOL      *PassThru,
+  IN UINT16                             Rca
+  )
+{
+  EFI_SD_MMC_COMMAND_BLOCK              SdMmcCmdBlk;
+  EFI_SD_MMC_STATUS_BLOCK               SdMmcStatusBlk;
+  EFI_SD_MMC_PASS_THRU_COMMAND_PACKET   Packet;
+  EFI_STATUS                            Status;
+
+  ZeroMem (&SdMmcCmdBlk, sizeof (SdMmcCmdBlk));
+  ZeroMem (&SdMmcStatusBlk, sizeof (SdMmcStatusBlk));
+  ZeroMem (&Packet, sizeof (Packet));
+
+  Packet.SdMmcCmdBlk    = &SdMmcCmdBlk;
+  Packet.SdMmcStatusBlk = &SdMmcStatusBlk;
+  Packet.Timeout        = DW_MMC_HC_GENERIC_TIMEOUT;
+
+  SdMmcCmdBlk.CommandIndex = SD_SELECT_DESELECT_CARD;
+  SdMmcCmdBlk.CommandType  = SdMmcCommandTypeAc;
+  if (Rca != 0) {
+    SdMmcCmdBlk.ResponseType = SdMmcResponseTypeR1b;
+  }
+  SdMmcCmdBlk.CommandArgument = (UINT32)Rca << 16;
+
+  Status = DwMmcPassThruPassThru (PassThru, 0, &Packet, NULL);
+
+  return Status;
+}
+
+/**
+  Send command VOLTAGE_SWITCH to the SD device to switch the voltage of the
+  device.
+
+  Refer to SD Physical Layer Simplified Spec 4.1 Section 4.7 for details.
+
+  @param[in]  PassThru      A pointer to the EFI_SD_MMC_PASS_THRU_PROTOCOL
+                            instance.
+
+  @retval EFI_SUCCESS       The operation is done correctly.
+  @retval Others            The operation fails.
+
+**/
+EFI_STATUS
+SdCardVoltageSwitch (
+  IN EFI_SD_MMC_PASS_THRU_PROTOCOL      *PassThru
+  )
+{
+  EFI_SD_MMC_COMMAND_BLOCK              SdMmcCmdBlk;
+  EFI_SD_MMC_STATUS_BLOCK               SdMmcStatusBlk;
+  EFI_SD_MMC_PASS_THRU_COMMAND_PACKET   Packet;
+  EFI_STATUS                            Status;
+
+  ZeroMem (&SdMmcCmdBlk, sizeof (SdMmcCmdBlk));
+  ZeroMem (&SdMmcStatusBlk, sizeof (SdMmcStatusBlk));
+  ZeroMem (&Packet, sizeof (Packet));
+
+  Packet.SdMmcCmdBlk    = &SdMmcCmdBlk;
+  Packet.SdMmcStatusBlk = &SdMmcStatusBlk;
+  Packet.Timeout        = DW_MMC_HC_GENERIC_TIMEOUT;
+
+  SdMmcCmdBlk.CommandIndex = SD_VOLTAGE_SWITCH;
+  SdMmcCmdBlk.CommandType  = SdMmcCommandTypeAc;
+  SdMmcCmdBlk.ResponseType = SdMmcResponseTypeR1;
+  SdMmcCmdBlk.CommandArgument = 0;
+
+  Status = DwMmcPassThruPassThru (PassThru, 0, &Packet, NULL);
+
+  return Status;
+}
+
+/**
+  Send command SET_BUS_WIDTH to the SD device to set the bus width.
+
+  Refer to SD Physical Layer Simplified Spec 4.1 Section 4.7 for details.
+
+  @param[in] PassThru       A pointer to the EFI_SD_MMC_PASS_THRU_PROTOCOL
+                            instance.
+  @param[in] Rca            The relative device address of addressed device.
+  @param[in] BusWidth       The bus width to be set, it could be 1 or 4.
+
+  @retval EFI_SUCCESS       The operation is done correctly.
+  @retval Others            The operation fails.
+
+**/
+EFI_STATUS
+SdCardSetBusWidth (
+  IN EFI_SD_MMC_PASS_THRU_PROTOCOL      *PassThru,
+  IN UINT16                             Rca,
+  IN UINT8                              BusWidth
+  )
+{
+  EFI_SD_MMC_COMMAND_BLOCK              SdMmcCmdBlk;
+  EFI_SD_MMC_STATUS_BLOCK               SdMmcStatusBlk;
+  EFI_SD_MMC_PASS_THRU_COMMAND_PACKET   Packet;
+  EFI_STATUS                            Status;
+  UINT8                                 Value;
+
+  ZeroMem (&SdMmcCmdBlk, sizeof (SdMmcCmdBlk));
+  ZeroMem (&SdMmcStatusBlk, sizeof (SdMmcStatusBlk));
+  ZeroMem (&Packet, sizeof (Packet));
+
+  Packet.SdMmcCmdBlk    = &SdMmcCmdBlk;
+  Packet.SdMmcStatusBlk = &SdMmcStatusBlk;
+  Packet.Timeout        = DW_MMC_HC_GENERIC_TIMEOUT;
+
+  SdMmcCmdBlk.CommandIndex = SD_APP_CMD;
+  SdMmcCmdBlk.CommandType  = SdMmcCommandTypeAc;
+  SdMmcCmdBlk.ResponseType = SdMmcResponseTypeR1;
+  SdMmcCmdBlk.CommandArgument = (UINT32)Rca << 16;
+
+  Status = DwMmcPassThruPassThru (PassThru, 0, &Packet, NULL);
+  if (EFI_ERROR (Status)) {
+    return Status;
+  }
+
+  SdMmcCmdBlk.CommandIndex = SD_SET_BUS_WIDTH;
+  SdMmcCmdBlk.CommandType  = SdMmcCommandTypeAc;
+  SdMmcCmdBlk.ResponseType = SdMmcResponseTypeR1;
+
+  if (BusWidth == 1) {
+    Value = 0;
+  } else if (BusWidth == 4) {
+    Value = 2;
+  } else {
+    return EFI_INVALID_PARAMETER;
+  }
+
+  SdMmcCmdBlk.CommandArgument = Value & 0x3;
+
+  Status = DwMmcPassThruPassThru (PassThru, 0, &Packet, NULL);
+  return Status;
+}
+
+/**
+  Send command SWITCH_FUNC to the SD device to check switchable function or
+  switch card function.
+
+  Refer to SD Physical Layer Simplified Spec 4.1 Section 4.7 for details.
+
+  @param[in]  PassThru      A pointer to the EFI_SD_MMC_PASS_THRU_PROTOCOL
+                            instance.
+  @param[in]  AccessMode    The value for access mode group.
+  @param[in]  CommandSystem The value for command set group.
+  @param[in]  DriveStrength The value for drive length group.
+  @param[in]  PowerLimit    The value for power limit group.
+  @param[in]  Mode          Switch or check function.
+  @param[out] SwitchResp    The return switch function status.
+
+  @retval EFI_SUCCESS       The operation is done correctly.
+  @retval Others            The operation fails.
+
+**/
+EFI_STATUS
+SdCardSwitch (
+  IN     EFI_SD_MMC_PASS_THRU_PROTOCOL  *PassThru,
+  IN     UINT8                          AccessMode,
+  IN     UINT8                          CommandSystem,
+  IN     UINT8                          DriveStrength,
+  IN     UINT8                          PowerLimit,
+  IN     BOOLEAN                        Mode,
+     OUT UINT8                          *SwitchResp
+  )
+{
+  EFI_SD_MMC_COMMAND_BLOCK              SdMmcCmdBlk;
+  EFI_SD_MMC_STATUS_BLOCK               SdMmcStatusBlk;
+  EFI_SD_MMC_PASS_THRU_COMMAND_PACKET   Packet;
+  EFI_STATUS                            Status;
+  UINT32                                ModeValue;
+
+  ZeroMem (&SdMmcCmdBlk, sizeof (SdMmcCmdBlk));
+  ZeroMem (&SdMmcStatusBlk, sizeof (SdMmcStatusBlk));
+  ZeroMem (&Packet, sizeof (Packet));
+
+  Packet.SdMmcCmdBlk    = &SdMmcCmdBlk;
+  Packet.SdMmcStatusBlk = &SdMmcStatusBlk;
+  Packet.Timeout        = DW_MMC_HC_GENERIC_TIMEOUT;
+
+  SdMmcCmdBlk.CommandIndex = SD_SWITCH_FUNC;
+  SdMmcCmdBlk.CommandType  = SdMmcCommandTypeAdtc;
+  SdMmcCmdBlk.ResponseType = SdMmcResponseTypeR1;
+
+  ModeValue = Mode ? BIT31 : 0;
+  SdMmcCmdBlk.CommandArgument = (AccessMode & 0xF) |            \
+                                ((PowerLimit & 0xF) << 4) |     \
+                                ((DriveStrength & 0xF) << 8) |  \
+                                ((DriveStrength & 0xF) << 12) | \
+                                ModeValue;
+
+  Packet.InDataBuffer     = SwitchResp;
+  Packet.InTransferLength = 64;
+
+  Status = DwMmcPassThruPassThru (PassThru, 0, &Packet, NULL);
+
+  return Status;
+}
+
+/**
+  Send command SEND_STATUS to the addressed SD device to get its status
+  register.
+
+  Refer to SD Physical Layer Simplified Spec 4.1 Section 4.7 for details.
+
+  @param[in]  PassThru      A pointer to the EFI_SD_MMC_PASS_THRU_PROTOCOL
+                            instance.
+  @param[in]  Rca           The relative device address of addressed device.
+  @param[out] DevStatus     The returned device status.
+
+  @retval EFI_SUCCESS       The operation is done correctly.
+  @retval Others            The operation fails.
+
+**/
+EFI_STATUS
+SdCardSendStatus (
+  IN     EFI_SD_MMC_PASS_THRU_PROTOCOL  *PassThru,
+  IN     UINT16                         Rca,
+     OUT UINT32                         *DevStatus
+  )
+{
+  EFI_SD_MMC_COMMAND_BLOCK              SdMmcCmdBlk;
+  EFI_SD_MMC_STATUS_BLOCK               SdMmcStatusBlk;
+  EFI_SD_MMC_PASS_THRU_COMMAND_PACKET   Packet;
+  EFI_STATUS                            Status;
+
+  ZeroMem (&SdMmcCmdBlk, sizeof (SdMmcCmdBlk));
+  ZeroMem (&SdMmcStatusBlk, sizeof (SdMmcStatusBlk));
+  ZeroMem (&Packet, sizeof (Packet));
+
+  Packet.SdMmcCmdBlk    = &SdMmcCmdBlk;
+  Packet.SdMmcStatusBlk = &SdMmcStatusBlk;
+  Packet.Timeout        = DW_MMC_HC_GENERIC_TIMEOUT;
+
+  SdMmcCmdBlk.CommandIndex = SD_SEND_STATUS;
+  SdMmcCmdBlk.CommandType  = SdMmcCommandTypeAc;
+  SdMmcCmdBlk.ResponseType = SdMmcResponseTypeR1;
+  SdMmcCmdBlk.CommandArgument = (UINT32)Rca << 16;
+
+  Status = DwMmcPassThruPassThru (PassThru, 0, &Packet, NULL);
+  if (!EFI_ERROR (Status)) {
+    *DevStatus = SdMmcStatusBlk.Resp0;
+  }
+
+  return Status;
+}
+
+/**
+  Send command SEND_TUNING_BLOCK to the SD device for HS200 optimal sampling
+  point detection.
+
+  It may be sent up to 40 times until the host finishes the tuning procedure.
+
+  Refer to SD Physical Layer Simplified Spec 4.1 Section 4.7 for details.
+
+  @param[in] PassThru       A pointer to the EFI_SD_MMC_PASS_THRU_PROTOCOL
+                            instance.
+
+  @retval EFI_SUCCESS       The operation is done correctly.
+  @retval Others            The operation fails.
+
+**/
+EFI_STATUS
+SdCardSendTuningBlk (
+  IN EFI_SD_MMC_PASS_THRU_PROTOCOL      *PassThru
+  )
+{
+  EFI_SD_MMC_COMMAND_BLOCK              SdMmcCmdBlk;
+  EFI_SD_MMC_STATUS_BLOCK               SdMmcStatusBlk;
+  EFI_SD_MMC_PASS_THRU_COMMAND_PACKET   Packet;
+  EFI_STATUS                            Status;
+  UINT8                                 TuningBlock[64];
+
+  ZeroMem (&SdMmcCmdBlk, sizeof (SdMmcCmdBlk));
+  ZeroMem (&SdMmcStatusBlk, sizeof (SdMmcStatusBlk));
+  ZeroMem (&Packet, sizeof (Packet));
+
+  Packet.SdMmcCmdBlk    = &SdMmcCmdBlk;
+  Packet.SdMmcStatusBlk = &SdMmcStatusBlk;
+  Packet.Timeout        = DW_MMC_HC_GENERIC_TIMEOUT;
+
+  SdMmcCmdBlk.CommandIndex = SD_SEND_TUNING_BLOCK;
+  SdMmcCmdBlk.CommandType  = SdMmcCommandTypeAdtc;
+  SdMmcCmdBlk.ResponseType = SdMmcResponseTypeR1;
+  SdMmcCmdBlk.CommandArgument = 0;
+
+  Packet.InDataBuffer     = TuningBlock;
+  Packet.InTransferLength = sizeof (TuningBlock);
+
+  Status = DwMmcPassThruPassThru (PassThru, 0, &Packet, NULL);
+
+  return Status;
+}
+
+/**
+  Switch the bus width to specified width.
+
+  Refer to SD Physical Layer Simplified Spec 4.1 Section 4.7 and
+  SD Host Controller Simplified Spec 3.0 section Figure 3-7 for details.
+
+  @param[in] PciIo          A pointer to the EFI_PCI_IO_PROTOCOL instance.
+  @param[in] PassThru       A pointer to the EFI_SD_MMC_PASS_THRU_PROTOCOL
+                            instance.
+  @param[in] Rca            The relative device address to be assigned.
+  @param[in] BusWidth       The bus width to be set, it could be 4 or 8.
+
+  @retval EFI_SUCCESS       The operation is done correctly.
+  @retval Others            The operation fails.
+
+**/
+EFI_STATUS
+SdCardSwitchBusWidth (
+  IN EFI_DEVICE_IO_PROTOCOL             *DevIo,
+  IN EFI_SD_MMC_PASS_THRU_PROTOCOL      *PassThru,
+  IN UINT16                             Rca,
+  IN BOOLEAN                            IsDdr,
+  IN UINT8                              BusWidth
+  )
+{
+  EFI_STATUS          Status;
+  UINT32              DevStatus;
+
+  Status = SdCardSetBusWidth (PassThru, Rca, BusWidth);
+  if (EFI_ERROR (Status)) {
+    DEBUG ((
+      DEBUG_ERROR,
+      "SdCardSwitchBusWidth: Switch to bus width %d fails with %r\n",
+      BusWidth,
+      Status
+      ));
+    return Status;
+  }
+
+  Status = SdCardSendStatus (PassThru, Rca, &DevStatus);
+  if (EFI_ERROR (Status)) {
+    DEBUG ((
+      DEBUG_ERROR,
+      "SdCardSwitchBusWidth: Send status fails with %r\n",
+      Status
+      ));
+    return Status;
+  }
+  //
+  // Check the switch operation is really successful or not.
+  //
+  if ((DevStatus >> 16) != 0) {
+    DEBUG ((
+      DEBUG_ERROR,
+      "SdCardSwitchBusWidth: The switch operation fails as DevStatus 0x%08x\n",
+      DevStatus
+      ));
+    return EFI_DEVICE_ERROR;
+  }
+
+  Status = DwMmcHcSetBusWidth (DevIo, IsDdr, BusWidth);
+
+  return Status;
+}
+
+/**
+  Switch the high speed timing according to request.
+
+  Refer to SD Physical Layer Simplified Spec 4.1 Section 4.7 for details.
+
+  @param[in] PciIo          A pointer to the EFI_PCI_IO_PROTOCOL instance.
+  @param[in] PassThru       A pointer to the EFI_SD_MMC_PASS_THRU_PROTOCOL
+                            instance.
+  @param[in] Rca            The relative device address to be assigned.
+  @param[in] S18A           The boolean to show if it's a UHS-I SD card.
+  @param[in] BusWidths      The bus width of the SD card.
+
+  @retval EFI_SUCCESS       The operation is done correctly.
+  @retval Others            The operation fails.
+
+**/
+EFI_STATUS
+SdCardSetBusMode (
+  IN EFI_DEVICE_IO_PROTOCOL             *DevIo,
+  IN EFI_SD_MMC_PASS_THRU_PROTOCOL      *PassThru,
+  IN UINT16                             Rca,
+  IN BOOLEAN                            S18A,
+  IN UINT32                             BusWidths
+  )
+{
+  EFI_STATUS                   Status;
+  DW_MMC_HC_SLOT_CAP           *Capability;
+  UINT32                       ClockFreq;
+  UINT8                        AccessMode;
+  UINT8                        SwitchResp[64];
+  DW_MMC_HC_PRIVATE_DATA       *Private;
+  BOOLEAN                      IsDdr;
+
+  Private = DW_MMC_HC_PRIVATE_FROM_THIS (PassThru);
+
+  Capability = &Private->Capability[0];
+
+  if ((Capability->BusWidth == 1) || (Capability->BusWidth == 4)) {
+    BusWidths &= Capability[0].BusWidth;
+  } else {
+    DEBUG ((
+      DEBUG_ERROR,
+      "SdCardSetBusMode: BusWidths (%d) in capability are wrong\n",
+      Capability->BusWidth
+      ));
+    return EFI_INVALID_PARAMETER;
+  }
+
+  if (BusWidths == 0) {
+    DEBUG ((
+      DEBUG_ERROR,
+      "SdCardSetBusMode: Get wrong BusWidths:%d\n",
+      BusWidths
+      ));
+    return EFI_INVALID_PARAMETER;
+  }
+
+  if (Private->Capability[0].Ddr50) {
+    IsDdr = TRUE;
+  } else {
+    IsDdr = FALSE;
+  }
+
+  Status = SdCardSwitchBusWidth (DevIo, PassThru, Rca, IsDdr, BusWidths);
+  if (EFI_ERROR (Status)) {
+    DEBUG ((
+      DEBUG_ERROR,
+      "SdCardSetBusMode: Executing SdCardSwitchBusWidth fails with %r\n",
+      Status
+      ));
+    return Status;
+  }
+
+  //
+  // Get the supported bus speed from SWITCH cmd return data group #1.
+  //
+  Status = SdCardSwitch (PassThru, 0xF, 0xF, 0xF, 0xF, FALSE, SwitchResp);
+  if (EFI_ERROR (Status)) {
+    return Status;
+  }
+  //
+  // Calculate supported bus speed/bus width/clock frequency by host and device
+  // capability.
+  //
+  ClockFreq = 0;
+  if (S18A && (Capability->Sdr104 != 0) && ((SwitchResp[13] & BIT3) != 0)) {
+    ClockFreq = 208;
+    AccessMode = 3;
+  } else if (S18A && (Capability->Sdr50 != 0) &&
+             ((SwitchResp[13] & BIT2) != 0)) {
+    ClockFreq = 100;
+    AccessMode = 2;
+  } else if (S18A && (Capability->Ddr50 != 0) &&
+             ((SwitchResp[13] & BIT4) != 0)) {
+    ClockFreq = 50;
+    AccessMode = 4;
+  } else if ((SwitchResp[13] & BIT1) != 0) {
+    ClockFreq = 50;
+    AccessMode = 1;
+  } else {
+    ClockFreq = 25;
+    AccessMode = 0;
+  }
+
+  Status = SdCardSwitch (PassThru, AccessMode, 0xF, 0xF, 0xF, TRUE, SwitchResp);
+  if (EFI_ERROR (Status)) {
+    return Status;
+  }
+
+  if ((SwitchResp[16] & 0xF) != AccessMode) {
+    DEBUG ((
+      DEBUG_ERROR,
+      "SdCardSetBusMode: Switch to AccessMode %d ClockFreq %d fails! The Switch response is 0x%1x\n",
+      AccessMode,
+      ClockFreq,
+      SwitchResp[16] & 0xF
+      ));
+    return EFI_DEVICE_ERROR;
+  }
+
+  DEBUG ((
+    DEBUG_INFO,
+    "SdCardSetBusMode: Switch to AccessMode %d ClockFreq %d \n",
+    AccessMode,
+    ClockFreq
+    ));
+
+  Status = DwMmcHcClockSupply (DevIo, ClockFreq * 1000, *Capability);
+  if (EFI_ERROR (Status)) {
+    return Status;
+  }
+
+  return Status;
+}
+
+EFI_STATUS
+SdCardIdentification (
+  IN DW_MMC_HC_PRIVATE_DATA             *Private
+  )
+{
+  EFI_STATUS                     Status;
+  EFI_DEVICE_IO_PROTOCOL         *DevIo;
+  EFI_SD_MMC_PASS_THRU_PROTOCOL  *PassThru;
+  UINT32                         Ocr;
+  UINT16                         Rca;
+  BOOLEAN                        Xpc;
+  BOOLEAN                        S18r;
+  UINT64                         MaxCurrent;
+  SD_SCR                         Scr;
+  SD_CSD                         Csd;
+
+  DevIo    = Private->DevIo;
+  PassThru = &Private->PassThru;
+  //
+  // 1. Send Cmd0 to the device
+  //
+  Status = SdCardReset (PassThru);
+  if (EFI_ERROR (Status)) {
+    DEBUG ((
+      DEBUG_INFO,
+      "SdCardIdentification: Executing Cmd0 fails with %r\n",
+      Status
+      ));
+    return Status;
+  }
+  MicroSecondDelay (10000);
+  //
+  // 2. Send Cmd8 to the device
+  //
+  Status = SdCardVoltageCheck (PassThru, 0x1, 0xFF);
+  if (EFI_ERROR (Status)) {
+    DEBUG ((
+      DEBUG_INFO,
+      "SdCardIdentification: Executing Cmd8 fails with %r\n",
+      Status
+      ));
+    return Status;
+  }
+  //
+  // 3. Send Acmd41 with voltage window 0 to the device
+  //
+  Status = SdCardSendOpCond (PassThru, 0, 0, FALSE, FALSE, FALSE, &Ocr);
+  if (EFI_ERROR (Status)) {
+    DEBUG ((
+      DEBUG_INFO,
+      "SdCardIdentification: Executing SdCardSendOpCond fails with %r\n",
+      Status
+      ));
+    return EFI_DEVICE_ERROR;
+  }
+
+  if (Private->Capability[0].Voltage33 != 0) {
+    //
+    // Support 3.3V
+    //
+    MaxCurrent = ((UINT32)Private->MaxCurrent[0] & 0xFF) * 4;
+    S18r = FALSE;
+  } else if (Private->Capability[0].Voltage30 != 0) {
+    //
+    // Support 3.0V
+    //
+    MaxCurrent = (((UINT32)Private->MaxCurrent[0] >> 8) & 0xFF) * 4;
+    S18r = FALSE;
+  } else if (Private->Capability[0].Voltage18 != 0) {
+    //
+    // Support 1.8V
+    //
+    MaxCurrent = (((UINT32)Private->MaxCurrent[0] >> 16) & 0xFF) * 4;
+    S18r = TRUE;
+  } else {
+    ASSERT (FALSE);
+    return EFI_DEVICE_ERROR;
+  }
+
+  if (MaxCurrent >= 150) {
+    Xpc = TRUE;
+  } else {
+    Xpc = FALSE;
+  }
+
+  //
+  // 4. Repeatly send Acmd41 with supply voltage window to the device.
+  //    Note here we only support the cards complied with SD physical
+  //    layer simplified spec version 2.0 and version 3.0 and above.
+  //
+  do {
+    Status = SdCardSendOpCond (PassThru, 0, Ocr, S18r, Xpc, TRUE, &Ocr);
+    if (EFI_ERROR (Status)) {
+      DEBUG ((
+        DEBUG_ERROR,
+        "SdCardIdentification: SdCardSendOpCond fails with %r Ocr %x, S18r %x, Xpc %x\n",
+        Status,
+        Ocr,
+        S18r,
+        Xpc
+        ));
+      return EFI_DEVICE_ERROR;
+    }
+  } while ((Ocr & BIT31) == 0);
+
+  Status = SdCardAllSendCid (PassThru);
+  if (EFI_ERROR (Status)) {
+    DEBUG ((
+      DEBUG_ERROR,
+      "SdCardIdentification: Executing SdCardAllSendCid fails with %r\n",
+      Status
+      ));
+    return Status;
+  }
+
+  Status = SdCardSetRca (PassThru, &Rca);
+  if (EFI_ERROR (Status)) {
+    DEBUG ((
+      DEBUG_ERROR,
+      "SdCardIdentification: Executing SdCardSetRca fails with %r\n",
+      Status
+      ));
+    return Status;
+  }
+
+  Status = SdCardGetCsd (PassThru, Rca, &Csd);
+  if (EFI_ERROR (Status)) {
+    DEBUG ((
+      DEBUG_ERROR,
+      "SdCardIdentification: Executing SdCardGetCsd fails with %r\n",
+      Status
+      ));
+    return Status;
+  }
+
+  Status = SdCardSelect (PassThru, Rca);
+  if (EFI_ERROR (Status)) {
+    DEBUG ((
+      DEBUG_ERROR,
+      "SdCardIdentification: Selecting card fails with %r\n",
+      Status
+      ));
+    return Status;
+  }
+
+  Status = SdCardGetScr (PassThru, Rca, &Scr);
+  if (EFI_ERROR (Status)) {
+    DEBUG ((
+      DEBUG_ERROR,
+      "SdCardIdentification: Executing SdCardGetScr fails with %r\n",
+      Status
+      ));
+    return Status;
+  }
+
+  //
+  // Enter Data Tranfer Mode.
+  //
+  DEBUG ((DEBUG_INFO, "SdCardIdentification: Found a SD device\n"));
+  Private->Slot[0].CardType = SdCardType;
+
+  Status = SdCardSetBusMode (DevIo, PassThru, Rca, S18r, Scr.SdBusWidths);
+  if (EFI_ERROR (Status)) {
+    return Status;
+  }
+
+  Private->Slot[0].Initialized = TRUE;
+
+  return Status;
+}