public inbox for devel@edk2.groups.io
 help / color / mirror / Atom feed
* [PATCH v2 2/3] EmbeddedPkg: add PlatformDwMmc protocol
  2018-08-15  7:36 Haojian Zhuang
@ 2018-08-15  7:36 ` Haojian Zhuang
  0 siblings, 0 replies; 12+ messages in thread
From: Haojian Zhuang @ 2018-08-15  7:36 UTC (permalink / raw)
  To: edk2-devel

Add PlatformDwMmc protocol. It's used to set properties of DwMmc
device in platform driver.

Cc: Leif Lindholm <leif.lindholm@linaro.org>
Cc: Ard Biesheuvel <ard.biesheuvel@linaro.org>
Cc: Chris Co <Christopher.Co@microsoft.com>
Contributed-under: TianoCore Contribution Agreement 1.1
Signed-off-by: Haojian Zhuang <haojian.zhuang@linaro.org>
---
 EmbeddedPkg/Include/Protocol/PlatformDwMmc.h | 79 ++++++++++++++++++++
 1 file changed, 79 insertions(+)

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__ */
-- 
2.7.4



^ permalink raw reply related	[flat|nested] 12+ messages in thread

* [PATCH v2 0/3] add DwMmcHcDxe driver
@ 2019-07-24  9:26 Loh, Tien Hock
  2019-07-24  9:26 ` [PATCH v2 1/3] EmbeddedPkg: add NonDiscoverableDeviceDxe driver Loh, Tien Hock
                   ` (4 more replies)
  0 siblings, 5 replies; 12+ messages in thread
From: Loh, Tien Hock @ 2019-07-24  9:26 UTC (permalink / raw)
  To: devel, thloh85, haojian.zhuang; +Cc: Tien Hock, Loh

From: "Tien Hock, Loh" <tien.hock.loh@intel.com>

Changelog:
v3:
  * Fix an issue in NonDiscoverableDeviceDxe driver where it did not invalidate
    cache before copying the memory.
v2:
  *Split DwMmcHcDxe driver into two patches. One is for PlatformDwMmc protocol,
   and the other is for DwMmcHcDxe driver.
v1:
  *Add NonDiscoverableDeviceDxe for embedded platform. Make DwMmcHcDxe driver
   to support both eMMC and SD controller.

Haojian Zhuang (3):
  EmbeddedPkg: add NonDiscoverableDeviceDxe driver
  EmbeddedPkg: add PlatformDwMmc protocol
  EmbeddedPkg/Drivers: add DwMmcHcDxe driver

 .../Drivers/DwMmcHcDxe/ComponentName.c        |  214 ++
 EmbeddedPkg/Drivers/DwMmcHcDxe/DwMmcHcDxe.c   | 1295 +++++++++
 EmbeddedPkg/Drivers/DwMmcHcDxe/DwMmcHcDxe.dec |   40 +
 EmbeddedPkg/Drivers/DwMmcHcDxe/DwMmcHcDxe.h   |  815 ++++++
 EmbeddedPkg/Drivers/DwMmcHcDxe/DwMmcHcDxe.inf |   69 +
 EmbeddedPkg/Drivers/DwMmcHcDxe/DwMmcHci.c     | 2366 +++++++++++++++++
 EmbeddedPkg/Drivers/DwMmcHcDxe/DwMmcHci.h     |  983 +++++++
 EmbeddedPkg/Drivers/DwMmcHcDxe/EmmcDevice.c   | 1042 ++++++++
 EmbeddedPkg/Drivers/DwMmcHcDxe/SdDevice.c     | 1104 ++++++++
 EmbeddedPkg/EmbeddedPkg.dec                   |    1 +
 EmbeddedPkg/Include/Protocol/PlatformDwMmc.h  |   79 +
 .../NonDiscoverableDeviceDxe/ComponentName.c  |  124 +
 .../NonDiscoverableDeviceDxe.c                |  243 ++
 .../NonDiscoverableDeviceDxe.inf              |   52 +
 .../NonDiscoverableDeviceIo.c                 |  976 +++++++
 .../NonDiscoverableDeviceIo.h                 |   92 +
 16 files changed, 9495 insertions(+)
 create mode 100644 EmbeddedPkg/Drivers/DwMmcHcDxe/ComponentName.c
 create mode 100644 EmbeddedPkg/Drivers/DwMmcHcDxe/DwMmcHcDxe.c
 create mode 100644 EmbeddedPkg/Drivers/DwMmcHcDxe/DwMmcHcDxe.dec
 create mode 100644 EmbeddedPkg/Drivers/DwMmcHcDxe/DwMmcHcDxe.h
 create mode 100644 EmbeddedPkg/Drivers/DwMmcHcDxe/DwMmcHcDxe.inf
 create mode 100644 EmbeddedPkg/Drivers/DwMmcHcDxe/DwMmcHci.c
 create mode 100644 EmbeddedPkg/Drivers/DwMmcHcDxe/DwMmcHci.h
 create mode 100644 EmbeddedPkg/Drivers/DwMmcHcDxe/EmmcDevice.c
 create mode 100644 EmbeddedPkg/Drivers/DwMmcHcDxe/SdDevice.c
 create mode 100644 EmbeddedPkg/Include/Protocol/PlatformDwMmc.h
 create mode 100644 EmbeddedPkg/Universal/NonDiscoverableDeviceDxe/ComponentName.c
 create mode 100644 EmbeddedPkg/Universal/NonDiscoverableDeviceDxe/NonDiscoverableDeviceDxe.c
 create mode 100644 EmbeddedPkg/Universal/NonDiscoverableDeviceDxe/NonDiscoverableDeviceDxe.inf
 create mode 100644 EmbeddedPkg/Universal/NonDiscoverableDeviceDxe/NonDiscoverableDeviceIo.c
 create mode 100644 EmbeddedPkg/Universal/NonDiscoverableDeviceDxe/NonDiscoverableDeviceIo.h

-- 
2.19.0


^ permalink raw reply	[flat|nested] 12+ messages in thread

* [PATCH v2 1/3] EmbeddedPkg: add NonDiscoverableDeviceDxe driver
  2019-07-24  9:26 [PATCH v2 0/3] add DwMmcHcDxe driver Loh, Tien Hock
@ 2019-07-24  9:26 ` Loh, Tien Hock
  2019-07-24  9:26 ` [PATCH v2 2/3] EmbeddedPkg: add PlatformDwMmc protocol Loh, Tien Hock
                   ` (3 subsequent siblings)
  4 siblings, 0 replies; 12+ messages in thread
From: Loh, Tien Hock @ 2019-07-24  9:26 UTC (permalink / raw)
  To: devel, thloh85, haojian.zhuang
  Cc: Leif Lindholm, Ard Biesheuvel, Chris Co, Tien, Hock, Loh

From: Haojian Zhuang <haojian.zhuang@linaro.org>

It's used to create NonDiscoverableDevice in embedded platform. Since
there's no PCI bus.

Cc: Leif Lindholm <leif.lindholm@linaro.org>
Cc: Ard Biesheuvel <ard.biesheuvel@linaro.org>
Cc: Chris Co <Christopher.Co@microsoft.com>
Contributed-under: TianoCore Contribution Agreement 1.1
Signed-off-by: Haojian Zhuang <haojian.zhuang@linaro.org>
Signed-off-by: Tien Hock, Loh <tien.hock.loh@intel.com>
---
 EmbeddedPkg/EmbeddedPkg.dec                                                 |   1 +
 EmbeddedPkg/Universal/NonDiscoverableDeviceDxe/ComponentName.c              | 124 +++
 EmbeddedPkg/Universal/NonDiscoverableDeviceDxe/NonDiscoverableDeviceDxe.c   | 243 +++++
 EmbeddedPkg/Universal/NonDiscoverableDeviceDxe/NonDiscoverableDeviceDxe.inf |  52 ++
 EmbeddedPkg/Universal/NonDiscoverableDeviceDxe/NonDiscoverableDeviceIo.c    | 976 ++++++++++++++++++++
 EmbeddedPkg/Universal/NonDiscoverableDeviceDxe/NonDiscoverableDeviceIo.h    |  92 ++
 6 files changed, 1488 insertions(+)

diff --git a/EmbeddedPkg/EmbeddedPkg.dec b/EmbeddedPkg/EmbeddedPkg.dec
index bbaadc5a17ab..8f051c76c51f 100644
--- a/EmbeddedPkg/EmbeddedPkg.dec
+++ b/EmbeddedPkg/EmbeddedPkg.dec
@@ -79,6 +79,7 @@
   gPlatformGpioProtocolGuid = { 0x52ce9845, 0x5af4, 0x43e2, {0xba, 0xfd, 0x23, 0x08, 0x12, 0x54, 0x7a, 0xc2 }}
   gPlatformVirtualKeyboardProtocolGuid = { 0x0e3606d2, 0x1dc3, 0x4e6f, { 0xbe, 0x65, 0x39, 0x49, 0x82, 0xa2, 0x65, 0x47 }}
   gAndroidBootImgProtocolGuid = { 0x9859bb19, 0x407c, 0x4f8b, {0xbc, 0xe1, 0xf8, 0xda, 0x65, 0x65, 0xf4, 0xa5 }}
+  gEmbeddedNonDiscoverableIoProtocolGuid = { 0x6937742f, 0xf611, 0x4a40, { 0xb1, 0xc6, 0xe7, 0xb4, 0x6e, 0x3c, 0x6e, 0x32 }}
 
 [Ppis]
   gEdkiiEmbeddedGpioPpiGuid = { 0x21c3b115, 0x4e0b, 0x470c, { 0x85, 0xc7, 0xe1, 0x05, 0xa5, 0x75, 0xc9, 0x7b }}
diff --git a/EmbeddedPkg/Universal/NonDiscoverableDeviceDxe/ComponentName.c b/EmbeddedPkg/Universal/NonDiscoverableDeviceDxe/ComponentName.c
new file mode 100644
index 000000000000..613938697ee4
--- /dev/null
+++ b/EmbeddedPkg/Universal/NonDiscoverableDeviceDxe/ComponentName.c
@@ -0,0 +1,124 @@
+/** @file
+
+  Copyright (C) 2016-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 <Library/UefiLib.h>
+
+#include "NonDiscoverableDeviceIo.h"
+
+//
+// The purpose of the following scaffolding (EFI_COMPONENT_NAME_PROTOCOL and
+// EFI_COMPONENT_NAME2_PROTOCOL implementation) is to format the driver's name
+// in English, for display on standard console devices. This is recommended for
+// UEFI drivers that follow the UEFI Driver Model. Refer to the Driver Writer's
+// Guide for UEFI 2.3.1 v1.01, 11 UEFI Driver and Controller Names.
+//
+
+STATIC
+EFI_UNICODE_STRING_TABLE mDriverNameTable[] = {
+  { "eng;en", L"I/O protocol emulation driver for non-discoverable devices" },
+  { NULL,     NULL                   }
+};
+
+EFI_COMPONENT_NAME_PROTOCOL gComponentName;
+
+/**
+  Retrieves a Unicode string that is the user readable name of the UEFI Driver.
+
+  @param This           A pointer to the EFI_COMPONENT_NAME_PROTOCOL instance.
+  @param Language       A pointer to a three character ISO 639-2 language identifier.
+                        This is the language of the driver name that 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.
+  @param DriverName     A pointer to the Unicode string to return.  This Unicode string
+                        is the name of the driver specified by This in the language
+                        specified by Language.
+
+  @retval EFI_SUCCESS           The Unicode string for the Driver specified by This
+                                and the language specified by Language was returned
+                                in DriverName.
+  @retval EFI_INVALID_PARAMETER Language is NULL.
+  @retval EFI_INVALID_PARAMETER DriverName is NULL.
+  @retval EFI_UNSUPPORTED       The driver specified by This does not support the
+                                language specified by Language.
+**/
+STATIC
+EFI_STATUS
+EFIAPI
+NonDiscoverableGetDriverName (
+  IN  EFI_COMPONENT_NAME_PROTOCOL *This,
+  IN  CHAR8                       *Language,
+  OUT CHAR16                      **DriverName
+  )
+{
+  return LookupUnicodeString2 (
+           Language,
+           This->SupportedLanguages,
+           mDriverNameTable,
+           DriverName,
+           (BOOLEAN)(This == &gComponentName) // Iso639Language
+           );
+}
+
+/**
+  Retrieves a Unicode string that is the user readable name of the controller
+  that is being managed by an UEFI Driver.
+
+  @param This                   A pointer to the EFI_COMPONENT_NAME_PROTOCOL instance.
+  @param DeviceHandle           The handle of a controller that the driver specified by
+                                This is managing.  This handle specifies the controller
+                                whose name is to be returned.
+  @param ChildHandle            The handle of the child controller to retrieve the name
+                                of.  This is an optional parameter that may be NULL.  It
+                                will be NULL for device drivers.  It will also be NULL
+                                for a bus drivers that wish to retrieve the name of the
+                                bus controller.  It will not be NULL for a bus driver
+                                that wishes to retrieve the name of a child controller.
+  @param Language               A pointer to a three character ISO 639-2 language
+                                identifier.  This is the language of the controller name
+                                that 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.
+  @param ControllerName         A pointer to the Unicode string to return.  This Unicode
+                                string is the name of the controller specified by
+                                ControllerHandle and ChildHandle in the language
+                                specified by Language from the point of view of the
+                                driver specified by This.
+**/
+STATIC
+EFI_STATUS
+EFIAPI
+NonDiscoverableGetDeviceName (
+  IN  EFI_COMPONENT_NAME_PROTOCOL *This,
+  IN  EFI_HANDLE                  DeviceHandle,
+  IN  EFI_HANDLE                  ChildHandle,
+  IN  CHAR8                       *Language,
+  OUT CHAR16                      **ControllerName
+  )
+{
+  return EFI_UNSUPPORTED;
+}
+
+EFI_COMPONENT_NAME_PROTOCOL gComponentName = {
+  &NonDiscoverableGetDriverName,
+  &NonDiscoverableGetDeviceName,
+  "eng" // SupportedLanguages, ISO 639-2 language codes
+};
+
+EFI_COMPONENT_NAME2_PROTOCOL gComponentName2 = {
+  (EFI_COMPONENT_NAME2_GET_DRIVER_NAME)     &NonDiscoverableGetDriverName,
+  (EFI_COMPONENT_NAME2_GET_CONTROLLER_NAME) &NonDiscoverableGetDeviceName,
+  "en" // SupportedLanguages, RFC 4646 language codes
+};
diff --git a/EmbeddedPkg/Universal/NonDiscoverableDeviceDxe/NonDiscoverableDeviceDxe.c b/EmbeddedPkg/Universal/NonDiscoverableDeviceDxe/NonDiscoverableDeviceDxe.c
new file mode 100644
index 000000000000..654b33002346
--- /dev/null
+++ b/EmbeddedPkg/Universal/NonDiscoverableDeviceDxe/NonDiscoverableDeviceDxe.c
@@ -0,0 +1,243 @@
+/** @file
+
+  Copyright (C) 2016-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 <Library/BaseMemoryLib.h>
+#include <Library/DebugLib.h>
+#include <Library/MemoryAllocationLib.h>
+#include <Library/UefiBootServicesTableLib.h>
+#include <Library/UefiLib.h>
+
+#include <Protocol/DriverBinding.h>
+
+#include "NonDiscoverableDeviceIo.h"
+
+
+EFI_CPU_ARCH_PROTOCOL      *mCpu;
+
+//
+// We only support the following device types
+//
+STATIC
+CONST EFI_GUID * CONST
+SupportedNonDiscoverableDevices[] = {
+  &gEdkiiNonDiscoverableSdhciDeviceGuid,
+  &gEdkiiNonDiscoverableUfsDeviceGuid,
+};
+
+//
+// Probe, start and stop functions of this driver, called by the DXE core for
+// specific devices.
+//
+// The following specifications document these interfaces:
+// - Driver Writer's Guide for UEFI 2.3.1 v1.01, 9 Driver Binding Protocol
+// - UEFI Spec 2.3.1 + Errata C, 10.1 EFI Driver Binding Protocol
+//
+// The implementation follows:
+// - Driver Writer's Guide for UEFI 2.3.1 v1.01
+//   - 5.1.3.4 OpenProtocol() and CloseProtocol()
+// - UEFI Spec 2.3.1 + Errata C
+//   -  6.3 Protocol Handler Services
+//
+
+/**
+  Supported function of Driver Binding protocol for this driver.
+  Test to see if this driver supports ControllerHandle.
+
+  @param This                   Protocol instance pointer.
+  @param DeviceHandle           Handle of device to test.
+  @param RemainingDevicePath    A pointer to the device path.
+                                it should be ignored by device driver.
+
+  @retval EFI_SUCCESS           This driver supports this device.
+  @retval other                 This driver does not support this device.
+
+**/
+STATIC
+EFI_STATUS
+EFIAPI
+NonDiscoverableIoDeviceSupported (
+  IN EFI_DRIVER_BINDING_PROTOCOL *This,
+  IN EFI_HANDLE                  DeviceHandle,
+  IN EFI_DEVICE_PATH_PROTOCOL    *RemainingDevicePath
+  )
+{
+  NON_DISCOVERABLE_DEVICE             *Device;
+  EFI_STATUS                          Status;
+  INTN                                Idx;
+
+  Status = gBS->OpenProtocol (DeviceHandle,
+                  &gEdkiiNonDiscoverableDeviceProtocolGuid, (VOID **)&Device,
+                  This->DriverBindingHandle, DeviceHandle,
+                  EFI_OPEN_PROTOCOL_BY_DRIVER);
+  if (EFI_ERROR (Status)) {
+    return Status;
+  }
+
+  Status = EFI_UNSUPPORTED;
+  for (Idx = 0; Idx < ARRAY_SIZE (SupportedNonDiscoverableDevices); Idx++) {
+    if (CompareGuid (Device->Type, SupportedNonDiscoverableDevices [Idx])) {
+      Status = EFI_SUCCESS;
+      break;
+    }
+  }
+
+  if (EFI_ERROR (Status)) {
+    goto CloseProtocol;
+  }
+
+CloseProtocol:
+  gBS->CloseProtocol (DeviceHandle, &gEdkiiNonDiscoverableDeviceProtocolGuid,
+         This->DriverBindingHandle, DeviceHandle);
+
+  return Status;
+}
+
+/**
+  This routine is called right after the .Supported() called and
+  Start this driver on ControllerHandle.
+
+  @param This                   Protocol instance pointer.
+  @param DeviceHandle           Handle of device to bind driver to.
+  @param RemainingDevicePath    A pointer to the device path.
+                                it should be ignored by device driver.
+
+  @retval EFI_SUCCESS           This driver is added to this device.
+  @retval other                 Some error occurs when binding this driver to this device.
+
+**/
+STATIC
+EFI_STATUS
+EFIAPI
+NonDiscoverableIoDeviceStart (
+  IN EFI_DRIVER_BINDING_PROTOCOL *This,
+  IN EFI_HANDLE                  DeviceHandle,
+  IN EFI_DEVICE_PATH_PROTOCOL    *RemainingDevicePath
+  )
+{
+  EFI_STATUS                     Status;
+  NON_DISCOVERABLE_IO_DEVICE     *Dev;
+
+  Dev = AllocateZeroPool (sizeof *Dev);
+  if (Dev == NULL) {
+    return EFI_OUT_OF_RESOURCES;
+  }
+
+  Status = gBS->OpenProtocol (DeviceHandle,
+                  &gEdkiiNonDiscoverableDeviceProtocolGuid,
+                  (VOID **)&Dev->Device, This->DriverBindingHandle,
+                  DeviceHandle, EFI_OPEN_PROTOCOL_BY_DRIVER);
+  if (EFI_ERROR (Status)) {
+    goto FreeDev;
+  }
+
+  Dev->Signature = NON_DISCOVERABLE_IO_DEVICE_SIG;
+
+  InitializeIoProtocol (Dev);
+
+  Status = gBS->InstallProtocolInterface (
+                  &DeviceHandle,
+                  &gEmbeddedNonDiscoverableIoProtocolGuid,
+                  EFI_NATIVE_INTERFACE,
+                  &Dev->Io
+                  );
+  if (EFI_ERROR (Status)) {
+    goto CloseProtocol;
+  }
+  return EFI_SUCCESS;
+
+CloseProtocol:
+  gBS->CloseProtocol (DeviceHandle, &gEdkiiNonDiscoverableDeviceProtocolGuid,
+         This->DriverBindingHandle, DeviceHandle);
+FreeDev:
+  FreePool (Dev);
+
+  return Status;
+}
+
+/**
+  Stop this driver on ControllerHandle.
+
+  @param This               Protocol instance pointer.
+  @param DeviceHandle       Handle of device to stop driver on.
+  @param NumberOfChildren   Not used.
+  @param ChildHandleBuffer  Not used.
+
+  @retval EFI_SUCCESS   This driver is removed from this device.
+  @retval other         Some error occurs when removing this driver from this
+                        device.
+
+**/
+STATIC
+EFI_STATUS
+EFIAPI
+NonDiscoverableIoDeviceStop (
+  IN EFI_DRIVER_BINDING_PROTOCOL *This,
+  IN EFI_HANDLE                  DeviceHandle,
+  IN UINTN                       NumberOfChildren,
+  IN EFI_HANDLE                  *ChildHandleBuffer
+  )
+{
+
+  gBS->CloseProtocol (DeviceHandle, &gEdkiiNonDiscoverableDeviceProtocolGuid,
+         This->DriverBindingHandle, DeviceHandle);
+
+  return EFI_SUCCESS;
+}
+
+
+//
+// The static object that groups the Supported() (ie. probe), Start() and
+// Stop() functions of the driver together. Refer to UEFI Spec 2.3.1 + Errata
+// C, 10.1 EFI Driver Binding Protocol.
+//
+STATIC EFI_DRIVER_BINDING_PROTOCOL gDriverBinding = {
+  &NonDiscoverableIoDeviceSupported,
+  &NonDiscoverableIoDeviceStart,
+  &NonDiscoverableIoDeviceStop,
+  0x10, // Version, must be in [0x10 .. 0xFFFFFFEF] for IHV-developed drivers
+  NULL,
+  NULL
+};
+
+/**
+  Entry point of this driver.
+
+  @param  ImageHandle     Image handle this driver.
+  @param  SystemTable     Pointer to the System Table.
+
+  @retval EFI_SUCCESS     The entry point is executed successfully.
+  @retval other           Some error occurred when executing this entry point.
+
+**/
+EFI_STATUS
+EFIAPI
+NonDiscoverableDeviceDxeEntryPoint (
+  IN EFI_HANDLE       ImageHandle,
+  IN EFI_SYSTEM_TABLE *SystemTable
+  )
+{
+  EFI_STATUS      Status;
+
+  Status = gBS->LocateProtocol (&gEfiCpuArchProtocolGuid, NULL, (VOID **)&mCpu);
+  ASSERT_EFI_ERROR(Status);
+
+  return EfiLibInstallDriverBindingComponentName2 (
+           ImageHandle,
+           SystemTable,
+           &gDriverBinding,
+           ImageHandle,
+           &gComponentName,
+           &gComponentName2
+           );
+}
diff --git a/EmbeddedPkg/Universal/NonDiscoverableDeviceDxe/NonDiscoverableDeviceDxe.inf b/EmbeddedPkg/Universal/NonDiscoverableDeviceDxe/NonDiscoverableDeviceDxe.inf
new file mode 100644
index 000000000000..b3f7c8bc2976
--- /dev/null
+++ b/EmbeddedPkg/Universal/NonDiscoverableDeviceDxe/NonDiscoverableDeviceDxe.inf
@@ -0,0 +1,52 @@
+## @file
+# I/O driver for non-discoverable devices.
+#
+# Copyright (C) 2016-2018, Linaro Ltd.
+#
+# 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                    = 0x0001001a
+  BASE_NAME                      = NonDiscoverableDeviceDxe
+  FILE_GUID                      = 66c8ca38-4c1e-4730-8c77-6c248ad89abd
+  MODULE_TYPE                    = UEFI_DRIVER
+  VERSION_STRING                 = 1.0
+  ENTRY_POINT                    = NonDiscoverableDeviceDxeEntryPoint
+
+[Sources]
+  ComponentName.c
+  NonDiscoverableDeviceDxe.c
+  NonDiscoverableDeviceIo.c
+  NonDiscoverableDeviceIo.h
+
+[Packages]
+  EmbeddedPkg/EmbeddedPkg.dec
+  MdePkg/MdePkg.dec
+  MdeModulePkg/MdeModulePkg.dec
+
+[LibraryClasses]
+  BaseMemoryLib
+  DebugLib
+  DxeServicesTableLib
+  MemoryAllocationLib
+  UefiBootServicesTableLib
+  UefiDriverEntryPoint
+  UefiLib
+
+[Protocols]
+  gEdkiiNonDiscoverableDeviceProtocolGuid       ## TO_START
+  gEfiCpuArchProtocolGuid                       ## CONSUMES
+  gEmbeddedNonDiscoverableIoProtocolGuid
+
+[Guids]
+  gEdkiiNonDiscoverableNvmeDeviceGuid       ## CONSUMES ## GUID
+  gEdkiiNonDiscoverableSdhciDeviceGuid      ## CONSUMES ## GUID
+  gEdkiiNonDiscoverableUfsDeviceGuid        ## CONSUMES ## GUID
diff --git a/EmbeddedPkg/Universal/NonDiscoverableDeviceDxe/NonDiscoverableDeviceIo.c b/EmbeddedPkg/Universal/NonDiscoverableDeviceDxe/NonDiscoverableDeviceIo.c
new file mode 100644
index 000000000000..3533e2458144
--- /dev/null
+++ b/EmbeddedPkg/Universal/NonDiscoverableDeviceDxe/NonDiscoverableDeviceIo.c
@@ -0,0 +1,976 @@
+/** @file
+
+  Copyright (c) 2008 - 2009, Apple Inc. All rights reserved.<BR>
+  Copyright (c) 2016-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 <PiDxe.h>
+
+#include <Library/BaseMemoryLib.h>
+#include <Library/DxeServicesTableLib.h>
+#include <Library/MemoryAllocationLib.h>
+#include <Library/UefiBootServicesTableLib.h>
+#include <Library/UefiLib.h>
+
+#include <Protocol/IoMmu.h>
+#include <Protocol/NonDiscoverableDevice.h>
+
+#include "NonDiscoverableDeviceIo.h"
+
+typedef struct {
+  EFI_PHYSICAL_ADDRESS            AllocAddress;
+  VOID                            *HostAddress;
+  EFI_IO_OPERATION_TYPE           Operation;
+  UINTN                           NumberOfBytes;
+} NON_DISCOVERABLE_IO_DEVICE_MAP_INFO;
+
+/**
+  Enable a driver to access controller registers in the memory or I/O space.
+
+  @param  Width         Signifies the width of the memory or I/O operations.
+  @param  Count         The number of memory or I/O operations to perform.
+  @param  DstStride     The stride of the destination buffer.
+  @param  Dst           For read operations, the destination buffer to store
+                        the results. For write operations, the destination
+                        buffer to write data to.
+  @param  SrcStride     The stride of the source buffer.
+  @param  Src           For read operations, the source buffer to read data
+                        from. For write operations, the source buffer to write
+                        data from.
+
+  @retval EFI_SUCCESS            The data was read from or written to the
+                                 controller.
+  @retval EFI_INVALID_PARAMETER  One or more parameters are invalid.
+
+**/
+STATIC
+EFI_STATUS
+EFIAPI
+IoMemRW (
+  IN     EFI_IO_WIDTH                  Width,
+  IN     UINTN                         Count,
+  IN     UINTN                         DstStride,
+  IN     VOID                          *Dst,
+  IN     UINTN                         SrcStride,
+     OUT CONST VOID                    *Src
+  )
+{
+  volatile UINT8             *Dst8;
+  volatile UINT16            *Dst16;
+  volatile UINT32            *Dst32;
+  volatile CONST UINT8       *Src8;
+  volatile CONST UINT16      *Src16;
+  volatile CONST UINT32      *Src32;
+
+  //
+  // Loop for each iteration and move the data
+  //
+  switch (Width & 0x3) {
+  case IO_UINT8:
+    Dst8 = (UINT8 *)Dst;
+    Src8 = (UINT8 *)Src;
+    for (;Count > 0; Count--, Dst8 += DstStride, Src8 += SrcStride) {
+      *Dst8 = *Src8;
+    }
+    break;
+  case IO_UINT16:
+    Dst16 = (UINT16 *)Dst;
+    Src16 = (UINT16 *)Src;
+    for (;Count > 0; Count--, Dst16 += DstStride, Src16 += SrcStride) {
+      *Dst16 = *Src16;
+    }
+    break;
+  case IO_UINT32:
+    Dst32 = (UINT32 *)Dst;
+    Src32 = (UINT32 *)Src;
+    for (;Count > 0; Count--, Dst32 += DstStride, Src32 += SrcStride) {
+      *Dst32 = *Src32;
+    }
+    break;
+  default:
+    return EFI_INVALID_PARAMETER;
+  }
+
+  return EFI_SUCCESS;
+}
+
+/**
+  Enable a driver to access controller registers in the memory or I/O space.
+
+  @param  This                  A pointer to the EFI_DEVICE_IO_PROTOCOL
+                                instance.
+  @param  Width                 Signifies the width of the memory or I/O
+                                operations.
+  @param  Offset                The offset to start the memory or I/O operation.
+  @param  Count                 The number of memory or I/O operations to
+                                perform.
+  @param  Buffer                For read operations, the destination buffer to
+                                store the results. For write operations, the
+                                source buffer to write data from.
+
+  @retval EFI_SUCCESS           The data was read from or written to the
+                                controller.
+  @retval EFI_UNSUPPORTED       The address range specified by Offset, Width,
+                                and Count is not valid.
+  @retval EFI_INVALID_PARAMETER One or more parameters are invalid.
+
+**/
+STATIC
+EFI_STATUS
+EFIAPI
+IoMemRead (
+  IN     EFI_DEVICE_IO_PROTOCOL        *This,
+  IN     EFI_IO_WIDTH                  Width,
+  IN     UINT64                        Offset,
+  IN     UINTN                         Count,
+  IN OUT VOID                          *Buffer
+  )
+{
+  NON_DISCOVERABLE_IO_DEVICE           *Dev;
+  UINTN                                AlignMask;
+  UINT64                               Address;
+  EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR    *Desc;
+
+  if (Buffer == NULL) {
+    return EFI_INVALID_PARAMETER;
+  }
+
+  Dev = NON_DISCOVERABLE_IO_DEVICE_FROM_IO(This);
+
+  Desc = Dev->Device->Resources;
+  Address = Desc->AddrRangeMin + Offset;
+
+  if (Address + (Count << (Width & 0x3)) > Desc->AddrRangeMax) {
+    return EFI_UNSUPPORTED;
+  }
+
+  AlignMask = (1 << (Width & 0x03)) - 1;
+  if ((UINTN)Address & AlignMask) {
+    return EFI_INVALID_PARAMETER;
+  }
+
+  switch (Width) {
+  case IO_UINT8:
+  case IO_UINT16:
+  case IO_UINT32:
+  case IO_UINT64:
+    return IoMemRW (Width, Count, 1, Buffer, 1, (VOID *)Address);
+  default:
+    break;
+  }
+  return EFI_INVALID_PARAMETER;
+}
+
+/**
+  Enable a driver to access controller registers in the memory or I/O space.
+
+  @param  This                  A pointer to the EFI_DEVICE_IO_PROTOCOL
+                                instance.
+  @param  Width                 Signifies the width of the memory or I/O
+                                operations.
+  @param  Offset                The offset to start the memory or I/O operation.
+  @param  Count                 The number of memory or I/O operations to
+                                perform.
+  @param  Buffer                For read operations, the destination buffer to
+                                store the results. For write operations, the
+                                source buffer to write data from.
+
+  @retval EFI_SUCCESS           The data was read from or written to the
+                                controller.
+  @retval EFI_UNSUPPORTED       The address range specified by Offset, Width,
+                                and Count is not valid.
+  @retval EFI_INVALID_PARAMETER One or more parameters are invalid.
+
+**/
+STATIC
+EFI_STATUS
+EFIAPI
+IoMemWrite (
+  IN     EFI_DEVICE_IO_PROTOCOL        *This,
+  IN     EFI_IO_WIDTH                  Width,
+  IN     UINT64                        Offset,
+  IN     UINTN                         Count,
+  IN OUT VOID                          *Buffer
+  )
+{
+  NON_DISCOVERABLE_IO_DEVICE           *Dev;
+  UINTN                                AlignMask;
+  UINT64                               Address;
+  EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR    *Desc;
+
+  if (Buffer == NULL) {
+    return EFI_INVALID_PARAMETER;
+  }
+
+  Dev = NON_DISCOVERABLE_IO_DEVICE_FROM_IO(This);
+
+  Desc = Dev->Device->Resources;
+
+  Address = Desc->AddrRangeMin + Offset;
+  if (Address + (Count << (Width & 0x3)) > Desc->AddrRangeMax) {
+    return EFI_UNSUPPORTED;
+  }
+
+  AlignMask = (1 << (Width & 0x03)) - 1;
+  if ((UINTN)Address & AlignMask) {
+    return EFI_INVALID_PARAMETER;
+  }
+
+  switch (Width) {
+  case IO_UINT8:
+  case IO_UINT16:
+  case IO_UINT32:
+  case IO_UINT64:
+    return IoMemRW (Width, Count, 1, (VOID *)Address, 1, Buffer);
+  default:
+    break;
+  }
+  return EFI_INVALID_PARAMETER;
+}
+
+/**
+  Enable a driver to access controller registers in the memory or I/O space.
+
+  @param  This                  A pointer to the EFI_DEVICE_IO_PROTOCOL
+                                instance.
+  @param  Width                 Signifies the width of the memory or I/O
+                                operations.
+  @param  Offset                The offset to start the memory or I/O operation.
+  @param  Count                 The number of memory or I/O operations to
+                                perform.
+  @param  Buffer                For read operations, the destination buffer
+                                to store the results. For write operations,
+                                the source buffer to write data from.
+
+**/
+STATIC
+EFI_STATUS
+EFIAPI
+IoIoRead (
+  IN     EFI_DEVICE_IO_PROTOCOL       *This,
+  IN     EFI_IO_WIDTH                 Width,
+  IN     UINT64                       Offset,
+  IN     UINTN                        Count,
+  IN OUT VOID                         *Buffer
+  )
+{
+  ASSERT (FALSE);
+  return EFI_UNSUPPORTED;
+}
+
+/**
+  Enable a driver to access controller registers in the memory or I/O space.
+
+  @param  This                  A pointer to the EFI_DEVICE_IO_PROTOCOL
+                                instance.
+  @param  Width                 Signifies the width of the memory or I/O
+                                operations.
+  @param  Offset                The offset to start the memory or I/O operation.
+  @param  Count                 The number of memory or I/O operations to
+                                perform.
+  @param  Buffer                For read operations, the destination buffer to
+                                store the results. For write operations, the
+                                source buffer to write data from.
+
+**/
+STATIC
+EFI_STATUS
+EFIAPI
+IoIoWrite (
+  IN     EFI_DEVICE_IO_PROTOCOL       *This,
+  IN     EFI_IO_WIDTH                 Width,
+  IN     UINT64                       Address,
+  IN     UINTN                        Count,
+  IN OUT VOID                         *Buffer
+  )
+{
+  ASSERT (FALSE);
+  return EFI_UNSUPPORTED;
+}
+
+/**
+  Provides the controller-specific addresses needed to access system memory.
+
+  @param  This                  A pointer to the EFI_DEVICE_IO_PROTOCOL
+                                instance.
+  @param  Operation             Indicates if the bus master is going to read
+                                or write to system memory.
+  @param  HostAddress           The system memory address to map to the
+                                controller.
+  @param  NumberOfBytes         On input the number of bytes to map. On output
+                                the number of bytes that were mapped.
+  @param  DeviceAddress         The resulting map address for the bus master
+                                controller to use to access the hosts
+                                HostAddress.
+  @param  Mapping               A resulting value to pass to Unmap().
+
+  @retval EFI_SUCCESS           The range was mapped for the returned
+                                NumberOfBytes.
+  @retval EFI_UNSUPPORTED       The HostAddress cannot be mapped as a common
+                                buffer.
+  @retval EFI_INVALID_PARAMETER One or more parameters are invalid.
+  @retval EFI_OUT_OF_RESOURCES  The request could not be completed due to a
+                                lack of resources.
+  @retval EFI_DEVICE_ERROR      The system hardware could not map the requested
+                                address.
+
+**/
+STATIC
+EFI_STATUS
+EFIAPI
+CoherentIoMap (
+  IN     EFI_DEVICE_IO_PROTOCOL        *This,
+  IN     EFI_IO_OPERATION_TYPE         Operation,
+  IN     EFI_PHYSICAL_ADDRESS          *HostAddress,
+  IN OUT UINTN                         *NumberOfBytes,
+     OUT EFI_PHYSICAL_ADDRESS          *DeviceAddress,
+     OUT VOID                          **Mapping
+  )
+{
+  EFI_STATUS                           Status;
+  NON_DISCOVERABLE_IO_DEVICE_MAP_INFO  *MapInfo;
+
+  //
+  // If HostAddress exceeds 4 GB, and this device does not support 64-bit DMA
+  // addressing, we need to allocate a bounce buffer and copy over the data.
+  //
+  if ((EFI_PHYSICAL_ADDRESS)(UINTN)HostAddress + *NumberOfBytes > SIZE_4GB) {
+    //
+    // Bounce buffering is not possible for consistent mappings
+    //
+    if (Operation == EfiBusMasterCommonBuffer) {
+      return EFI_UNSUPPORTED;
+    }
+
+    MapInfo = AllocatePool (sizeof *MapInfo);
+    if (MapInfo == NULL) {
+      return EFI_OUT_OF_RESOURCES;
+    }
+
+    MapInfo->AllocAddress = MAX_UINT32;
+    MapInfo->HostAddress = HostAddress;
+    MapInfo->Operation = Operation;
+    MapInfo->NumberOfBytes = *NumberOfBytes;
+
+    Status = gBS->AllocatePages (
+                    AllocateMaxAddress,
+                    EfiBootServicesData,
+                    EFI_SIZE_TO_PAGES (MapInfo->NumberOfBytes),
+                    &MapInfo->AllocAddress
+                    );
+    if (EFI_ERROR (Status)) {
+      //
+      // If we fail here, it is likely because the system has no memory below
+      // 4 GB to begin with. There is not much we can do about that other than
+      // fail the map request.
+      //
+      FreePool (MapInfo);
+      return EFI_DEVICE_ERROR;
+    }
+    if (Operation == EfiBusMasterRead) {
+      gBS->CopyMem (
+             (VOID *)(UINTN)MapInfo->AllocAddress,
+             HostAddress,
+             *NumberOfBytes
+             );
+    }
+    *DeviceAddress = MapInfo->AllocAddress;
+    *Mapping = MapInfo;
+  } else {
+    *DeviceAddress = (EFI_PHYSICAL_ADDRESS)(UINTN)HostAddress;
+    *Mapping = NULL;
+  }
+  return EFI_SUCCESS;
+}
+
+/**
+  Completes the Map() operation and releases any corresponding resources.
+
+  @param  This                  A pointer to the EFI_DEVICE_IO_PROTOCOL
+                                instance.
+  @param  Mapping               The mapping value returned from Map().
+
+  @retval EFI_SUCCESS           The range was unmapped.
+
+**/
+STATIC
+EFI_STATUS
+EFIAPI
+CoherentIoUnmap (
+  IN EFI_DEVICE_IO_PROTOCOL            *This,
+  IN VOID                              *Mapping
+  )
+{
+  NON_DISCOVERABLE_IO_DEVICE_MAP_INFO  *MapInfo;
+
+  MapInfo = Mapping;
+  if (MapInfo != NULL) {
+    if (MapInfo->Operation == EfiBusMasterWrite) {
+      gBS->CopyMem (
+             MapInfo->HostAddress,
+             (VOID *)(UINTN)MapInfo->AllocAddress,
+             MapInfo->NumberOfBytes
+             );
+    }
+    gBS->FreePages (
+           MapInfo->AllocAddress,
+           EFI_SIZE_TO_PAGES (MapInfo->NumberOfBytes)
+           );
+    FreePool (MapInfo);
+  }
+  return EFI_SUCCESS;
+}
+
+/**
+  Allocates pages.
+
+  @param  This                  A pointer to the EFI_PCI_IO_PROTOCOL instance.
+  @param  Type                  This parameter is not used and must be ignored.
+  @param  MemoryType            The type of memory to allocate,
+                                EfiBootServicesData or EfiRuntimeServicesData.
+  @param  Pages                 The number of pages to allocate.
+  @param  HostAddress           A pointer to store the base system memory
+                                address of the allocated range.
+  @param  Attributes            The requested bit mask of attributes for the
+                                allocated range.
+
+  @retval EFI_SUCCESS           The requested memory pages were allocated.
+  @retval EFI_UNSUPPORTED       Attributes is unsupported. The only legal
+                                attribute bits are MEMORY_WRITE_COMBINE and
+                                MEMORY_CACHED.
+  @retval EFI_INVALID_PARAMETER One or more parameters are invalid.
+  @retval EFI_OUT_OF_RESOURCES  The memory pages could not be allocated.
+
+**/
+STATIC
+EFI_STATUS
+EFIAPI
+CoherentIoAllocateBuffer (
+  IN     EFI_DEVICE_IO_PROTOCOL        *This,
+  IN     EFI_ALLOCATE_TYPE             Type,
+  IN     EFI_MEMORY_TYPE               MemoryType,
+  IN     UINTN                         Pages,
+  IN OUT EFI_PHYSICAL_ADDRESS          *HostAddress
+  )
+{
+  EFI_STATUS                           Status;
+  NON_DISCOVERABLE_IO_DEVICE           *Dev;
+  EFI_ALLOCATE_TYPE                    AllocType;
+  EFI_PHYSICAL_ADDRESS                 AllocAddress;
+
+  //
+  // Allocate below 4 GB if the dual address cycle attribute has not
+  // been set. If the system has no memory available below 4 GB, there
+  // is little we can do except propagate the error.
+  //
+  Dev = NON_DISCOVERABLE_IO_DEVICE_FROM_IO(This);
+  if ((Dev->Attributes & EDKII_IOMMU_ATTRIBUTE_DUAL_ADDRESS_CYCLE) == 0) {
+    AllocAddress = MAX_UINT32;
+    AllocType = AllocateMaxAddress;
+  } else {
+    AllocType = AllocateAnyPages;
+  }
+
+  Status = gBS->AllocatePages (AllocType, MemoryType, Pages, &AllocAddress);
+  if (!EFI_ERROR (Status)) {
+    *HostAddress = AllocAddress;
+  }
+  return Status;
+}
+
+/**
+  Frees memory that was allocated in function CoherentIoAllocateBuffer ().
+
+  @param  This                  A pointer to the EFI_DEVICE_IO_PROTOCOL
+                                instance.
+  @param  Pages                 The number of pages to free.
+  @param  HostAddress           The base system memory address of the
+                                allocated range.
+
+  @retval EFI_SUCCESS           The requested memory pages were freed.
+
+**/
+STATIC
+EFI_STATUS
+EFIAPI
+CoherentIoFreeBuffer (
+  IN EFI_DEVICE_IO_PROTOCOL            *This,
+  IN UINTN                             Pages,
+  IN EFI_PHYSICAL_ADDRESS              HostAddress
+  )
+{
+  FreePages ((VOID *)HostAddress, Pages);
+  return EFI_SUCCESS;
+}
+
+/**
+  Frees memory that was allocated in function NonCoherentIoAllocateBuffer ().
+
+  @param  This                  A pointer to the EFI_DEVICE_IO_PROTOCOL
+                                instance.
+  @param  Pages                 The number of pages to free.
+  @param  HostAddress           The base system memory address of the allocated
+                                range.
+
+  @retval EFI_SUCCESS           The requested memory pages were freed.
+  @retval others                The operation contain some errors.
+
+**/
+STATIC
+EFI_STATUS
+EFIAPI
+NonCoherentIoFreeBuffer (
+  IN EFI_DEVICE_IO_PROTOCOL            *This,
+  IN UINTN                             Pages,
+  IN EFI_PHYSICAL_ADDRESS              HostAddress
+  )
+{
+  NON_DISCOVERABLE_IO_DEVICE                    *Dev;
+  LIST_ENTRY                                    *Entry;
+  EFI_STATUS                                    Status;
+  NON_DISCOVERABLE_DEVICE_UNCACHED_ALLOCATION   *Alloc;
+  BOOLEAN                                       Found;
+
+  Dev = NON_DISCOVERABLE_IO_DEVICE_FROM_IO(This);
+
+  Found = FALSE;
+  Alloc = NULL;
+
+  //
+  // Find the uncached allocation list entry associated
+  // with this allocation
+  //
+  for (Entry = Dev->UncachedAllocationList.ForwardLink;
+       Entry != &Dev->UncachedAllocationList;
+       Entry = Entry->ForwardLink) {
+
+    Alloc = BASE_CR (Entry, NON_DISCOVERABLE_DEVICE_UNCACHED_ALLOCATION, List);
+    if (Alloc->HostAddress == (VOID *)HostAddress && Alloc->NumPages == Pages) {
+      //
+      // We are freeing the exact allocation we were given
+      // before by AllocateBuffer()
+      //
+      Found = TRUE;
+      break;
+    }
+  }
+
+  if (!Found) {
+    ASSERT_EFI_ERROR (EFI_NOT_FOUND);
+    return EFI_NOT_FOUND;
+  }
+
+  RemoveEntryList (&Alloc->List);
+
+  Status = gDS->SetMemorySpaceAttributes (
+                  (EFI_PHYSICAL_ADDRESS)(UINTN)HostAddress,
+                  EFI_PAGES_TO_SIZE (Pages),
+                  Alloc->Attributes);
+  if (EFI_ERROR (Status)) {
+    goto FreeAlloc;
+  }
+
+  //
+  // If we fail to restore the original attributes, it is better to leak the
+  // memory than to return it to the heap
+  //
+  FreePages ((VOID *)HostAddress, Pages);
+
+FreeAlloc:
+  FreePool (Alloc);
+  return Status;
+}
+
+/**
+  Allocates pages.
+
+  @param  This                  A pointer to the EFI_DEVICE_IO_PROTOCOL
+                                instance.
+  @param  Type                  This parameter is not used and must be ignored.
+  @param  MemoryType            The type of memory to allocate,
+                                EfiBootServicesData or EfiRuntimeServicesData.
+  @param  Pages                 The number of pages to allocate.
+  @param  HostAddress           A pointer to store the base system memory
+                                address of the allocated range.
+  @param  Attributes            The requested bit mask of attributes for the
+                                allocated range.
+
+  @retval EFI_SUCCESS           The requested memory pages were allocated.
+  @retval EFI_UNSUPPORTED       Attributes is unsupported. The only legal
+                                attribute bits are MEMORY_WRITE_COMBINE and
+                                MEMORY_CACHED.
+  @retval EFI_INVALID_PARAMETER One or more parameters are invalid.
+  @retval EFI_OUT_OF_RESOURCES  The memory pages could not be allocated.
+
+**/
+STATIC
+EFI_STATUS
+EFIAPI
+NonCoherentIoAllocateBuffer (
+  IN     EFI_DEVICE_IO_PROTOCOL        *This,
+  IN     EFI_ALLOCATE_TYPE             Type,
+  IN     EFI_MEMORY_TYPE               MemoryType,
+  IN     UINTN                         Pages,
+  IN OUT EFI_PHYSICAL_ADDRESS          *HostAddress
+  )
+{
+  NON_DISCOVERABLE_IO_DEVICE                  *Dev;
+  EFI_GCD_MEMORY_SPACE_DESCRIPTOR             GcdDescriptor;
+  EFI_STATUS                                  Status;
+  UINT64                                      MemType;
+  NON_DISCOVERABLE_DEVICE_UNCACHED_ALLOCATION *Alloc;
+  EFI_PHYSICAL_ADDRESS                        AllocAddress;
+
+  Dev = NON_DISCOVERABLE_IO_DEVICE_FROM_IO(This);
+
+  Status = CoherentIoAllocateBuffer (
+             This,
+             Type,
+             MemoryType,
+             Pages,
+             &AllocAddress
+             );
+  if (EFI_ERROR (Status)) {
+    return Status;
+  }
+
+  Status = gDS->GetMemorySpaceDescriptor (
+                  (EFI_PHYSICAL_ADDRESS)(UINTN)AllocAddress,
+                  &GcdDescriptor
+                  );
+  if (EFI_ERROR (Status)) {
+    goto FreeBuffer;
+  }
+
+  if ((GcdDescriptor.Capabilities & (EFI_MEMORY_WC | EFI_MEMORY_UC)) == 0) {
+    Status = EFI_UNSUPPORTED;
+    goto FreeBuffer;
+  }
+
+  //
+  // Set the preferred memory attributes
+  //
+  if ((GcdDescriptor.Capabilities & EFI_MEMORY_UC) == 0) {
+    //
+    // Use write combining if it was requested, or if it is the only
+    // type supported by the region.
+    //
+    MemType = EFI_MEMORY_WC;
+  } else {
+    MemType = EFI_MEMORY_UC;
+  }
+
+  Alloc = AllocatePool (sizeof *Alloc);
+  if (Alloc == NULL) {
+    goto FreeBuffer;
+  }
+
+  Alloc->HostAddress = (VOID *)AllocAddress;
+  Alloc->NumPages = Pages;
+  Alloc->Attributes = GcdDescriptor.Attributes;
+
+  //
+  // Record this allocation in the linked list, so we
+  // can restore the memory space attributes later
+  //
+  InsertHeadList (&Dev->UncachedAllocationList, &Alloc->List);
+
+  Status = gDS->SetMemorySpaceAttributes (
+                  (EFI_PHYSICAL_ADDRESS)(UINTN)AllocAddress,
+                  EFI_PAGES_TO_SIZE (Pages),
+                  MemType
+                  );
+  if (EFI_ERROR (Status)) {
+    goto RemoveList;
+  }
+
+  Status = mCpu->FlushDataCache (
+                   mCpu,
+                   (EFI_PHYSICAL_ADDRESS)(UINTN)AllocAddress,
+                   EFI_PAGES_TO_SIZE (Pages),
+                   EfiCpuFlushTypeInvalidate);
+  if (EFI_ERROR (Status)) {
+    goto RemoveList;
+  }
+
+  *HostAddress = AllocAddress;
+
+  return EFI_SUCCESS;
+
+RemoveList:
+  RemoveEntryList (&Alloc->List);
+  FreePool (Alloc);
+
+FreeBuffer:
+  CoherentIoFreeBuffer (This, Pages, AllocAddress);
+  return Status;
+}
+
+/**
+  Provides the controller-specific addresses needed to access system memory.
+
+  @param  This                  A pointer to the EFI_DEVICE_IO_PROTOCOL
+                                instance.
+  @param  Operation             Indicates if the bus master is going to read or
+                                write to system memory.
+  @param  HostAddress           The system memory address to map to the
+                                controller.
+  @param  NumberOfBytes         On input the number of bytes to map. On output
+                                the number of bytes that were mapped.
+  @param  DeviceAddress         The resulting map address for the bus master
+                                controller to use to access the hosts
+                                HostAddress.
+  @param  Mapping               A resulting value to pass to Unmap().
+
+  @retval EFI_SUCCESS           The range was mapped for the returned
+                                NumberOfBytes.
+  @retval EFI_UNSUPPORTED       The HostAddress cannot be mapped as a common
+                                buffer.
+  @retval EFI_INVALID_PARAMETER One or more parameters are invalid.
+  @retval EFI_OUT_OF_RESOURCES  The request could not be completed due to a
+                                lack of resources.
+  @retval EFI_DEVICE_ERROR      The system hardware could not map the requested
+                                address.
+
+**/
+STATIC
+EFI_STATUS
+EFIAPI
+NonCoherentIoMap (
+  IN     EFI_DEVICE_IO_PROTOCOL        *This,
+  IN     EFI_IO_OPERATION_TYPE         Operation,
+  IN     EFI_PHYSICAL_ADDRESS          *HostAddress,
+  IN OUT UINTN                         *NumberOfBytes,
+     OUT EFI_PHYSICAL_ADDRESS          *DeviceAddress,
+     OUT VOID                          **Mapping
+  )
+{
+  NON_DISCOVERABLE_IO_DEVICE           *Dev;
+  EFI_STATUS                           Status;
+  NON_DISCOVERABLE_IO_DEVICE_MAP_INFO  *MapInfo;
+  UINTN                                AlignMask;
+  EFI_PHYSICAL_ADDRESS                 AllocAddress;
+  EFI_GCD_MEMORY_SPACE_DESCRIPTOR      GcdDescriptor;
+  BOOLEAN                              Bounce;
+
+  MapInfo = AllocatePool (sizeof *MapInfo);
+  if (MapInfo == NULL) {
+    return EFI_OUT_OF_RESOURCES;
+  }
+
+  MapInfo->HostAddress = HostAddress;
+  MapInfo->Operation = Operation;
+  MapInfo->NumberOfBytes = *NumberOfBytes;
+
+  Dev = NON_DISCOVERABLE_IO_DEVICE_FROM_IO(This);
+
+  //
+  // If this device does not support 64-bit DMA addressing, we need to allocate
+  // a bounce buffer and copy over the data in case HostAddress >= 4 GB.
+  //
+  Bounce = ((Dev->Attributes & EDKII_IOMMU_ATTRIBUTE_DUAL_ADDRESS_CYCLE) == 0 &&
+            (EFI_PHYSICAL_ADDRESS)(UINTN)HostAddress + *NumberOfBytes > SIZE_4GB);
+
+  if (!Bounce) {
+    switch (Operation) {
+    case EfiBusMasterRead:
+    case EfiBusMasterWrite:
+      //
+      // For streaming DMA, it is sufficient if the buffer is aligned to
+      // the CPUs DMA buffer alignment.
+      //
+      AlignMask = mCpu->DmaBufferAlignment - 1;
+      if ((((UINTN) HostAddress | *NumberOfBytes) & AlignMask) == 0) {
+        break;
+      }
+      // fall through
+
+    case EfiBusMasterCommonBuffer:
+      //
+      // Check whether the host address refers to an uncached mapping.
+      //
+      Status = gDS->GetMemorySpaceDescriptor (
+                      (EFI_PHYSICAL_ADDRESS)(UINTN)HostAddress,
+                      &GcdDescriptor
+                      );
+      if (EFI_ERROR (Status) ||
+          (GcdDescriptor.Attributes & (EFI_MEMORY_WB|EFI_MEMORY_WT)) != 0) {
+        Bounce = TRUE;
+      }
+      break;
+
+    default:
+      ASSERT (FALSE);
+    }
+  }
+
+  if (Bounce) {
+    if (Operation == EfiBusMasterCommonBuffer) {
+      Status = EFI_DEVICE_ERROR;
+      goto FreeMapInfo;
+    }
+
+    Status = NonCoherentIoAllocateBuffer (
+               This,
+               AllocateAnyPages,
+               EfiBootServicesData,
+               EFI_SIZE_TO_PAGES (MapInfo->NumberOfBytes),
+               &AllocAddress);
+    if (EFI_ERROR (Status)) {
+      goto FreeMapInfo;
+    }
+    MapInfo->AllocAddress = AllocAddress;
+    if (Operation == EfiBusMasterRead) {
+      gBS->CopyMem ((VOID *)AllocAddress, HostAddress, *NumberOfBytes);
+    }
+    *DeviceAddress = MapInfo->AllocAddress;
+  } else {
+    MapInfo->AllocAddress = 0;
+    *DeviceAddress = (EFI_PHYSICAL_ADDRESS)(UINTN)HostAddress;
+
+    //
+    // We are not using a bounce buffer: the mapping is sufficiently
+    // aligned to allow us to simply flush the caches. Note that cleaning
+    // the caches is necessary for both data directions:
+    // - for bus master read, we want the latest data to be present
+    //   in main memory
+    // - for bus master write, we don't want any stale dirty cachelines that
+    //   may be written back unexpectedly, and clobber the data written to
+    //   main memory by the device.
+    //
+    mCpu->FlushDataCache (
+            mCpu,
+            (EFI_PHYSICAL_ADDRESS)(UINTN)HostAddress,
+            *NumberOfBytes,
+            EfiCpuFlushTypeWriteBack
+            );
+  }
+
+  *Mapping = MapInfo;
+  return EFI_SUCCESS;
+
+FreeMapInfo:
+  FreePool (MapInfo);
+
+  return Status;
+}
+
+/**
+  Completes the Map() operation and releases any corresponding resources.
+
+  @param  This                  A pointer to the EFI_DEVICE_IO_PROTOCOL
+                                instance.
+  @param  Mapping               The mapping value returned from Map().
+
+  @retval EFI_SUCCESS           The range was unmapped.
+
+**/
+STATIC
+EFI_STATUS
+EFIAPI
+NonCoherentIoUnmap (
+  IN  EFI_DEVICE_IO_PROTOCOL           *This,
+  IN  VOID                             *Mapping
+  )
+{
+  NON_DISCOVERABLE_IO_DEVICE_MAP_INFO  *MapInfo;
+
+  if (Mapping == NULL) {
+    return EFI_DEVICE_ERROR;
+  }
+
+  MapInfo = Mapping;
+  if (MapInfo->AllocAddress != 0) {
+    //
+    // We are using a bounce buffer: copy back the data if necessary,
+    // and free the buffer.
+    //
+    if (MapInfo->Operation == EfiBusMasterWrite) {
+      mCpu->FlushDataCache (
+              mCpu,
+              (EFI_PHYSICAL_ADDRESS)(UINTN)MapInfo->HostAddress,
+              MapInfo->NumberOfBytes,
+              EfiCpuFlushTypeInvalidate
+              );
+      gBS->CopyMem (
+             MapInfo->HostAddress,
+             (VOID *)(UINTN)MapInfo->AllocAddress,
+             MapInfo->NumberOfBytes
+             );
+    }
+    NonCoherentIoFreeBuffer (
+      This,
+      EFI_SIZE_TO_PAGES (MapInfo->NumberOfBytes),
+      MapInfo->AllocAddress
+      );
+  } else {
+    //
+    // We are *not* using a bounce buffer: if this is a bus master write,
+    // we have to invalidate the caches so the CPU will see the uncached
+    // data written by the device.
+    //
+    if (MapInfo->Operation == EfiBusMasterWrite) {
+      mCpu->FlushDataCache (
+              mCpu,
+              (EFI_PHYSICAL_ADDRESS)(UINTN)MapInfo->HostAddress,
+              MapInfo->NumberOfBytes,
+              EfiCpuFlushTypeInvalidate
+              );
+    }
+  }
+  FreePool (MapInfo);
+  return EFI_SUCCESS;
+}
+
+STATIC CONST EFI_DEVICE_IO_PROTOCOL IoTemplate =
+{
+  { IoMemRead, IoMemWrite },
+  { IoIoRead,  IoIoWrite },
+  { 0, 0 },
+  CoherentIoMap,
+  0,
+  CoherentIoUnmap,
+  CoherentIoAllocateBuffer,
+  0,
+  CoherentIoFreeBuffer,
+};
+
+/**
+  Initialize DevIo Protocol.
+
+  @param  Dev      Point to NON_DISCOVERABLE_IO_DEVICE instance.
+
+**/
+VOID
+InitializeIoProtocol (
+  NON_DISCOVERABLE_IO_DEVICE           *Dev
+  )
+{
+  InitializeListHead (&Dev->UncachedAllocationList);
+
+  //
+  // Copy protocol structure
+  //
+  CopyMem(&Dev->Io, &IoTemplate, sizeof (IoTemplate));
+
+  if (Dev->Device->DmaType == NonDiscoverableDeviceDmaTypeNonCoherent) {
+    Dev->Io.AllocateBuffer  = NonCoherentIoAllocateBuffer;
+    Dev->Io.FreeBuffer      = NonCoherentIoFreeBuffer;
+    Dev->Io.Map             = NonCoherentIoMap;
+    Dev->Io.Unmap           = NonCoherentIoUnmap;
+  } else {
+    Dev->Io.AllocateBuffer  = CoherentIoAllocateBuffer;
+    Dev->Io.FreeBuffer      = CoherentIoFreeBuffer;
+    Dev->Io.Map             = CoherentIoMap;
+    Dev->Io.Unmap           = CoherentIoUnmap;
+  }
+}
diff --git a/EmbeddedPkg/Universal/NonDiscoverableDeviceDxe/NonDiscoverableDeviceIo.h b/EmbeddedPkg/Universal/NonDiscoverableDeviceDxe/NonDiscoverableDeviceIo.h
new file mode 100644
index 000000000000..faa0bfcc17d4
--- /dev/null
+++ b/EmbeddedPkg/Universal/NonDiscoverableDeviceDxe/NonDiscoverableDeviceIo.h
@@ -0,0 +1,92 @@
+/** @file
+
+  Copyright (C) 2016-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 __NON_DISCOVERABLE_DEVICE_IO_H__
+#define __NON_DISCOVERABLE_DEVICE_IO_H__
+
+#include <Library/DebugLib.h>
+
+#include <Protocol/ComponentName.h>
+#include <Protocol/ComponentName2.h>
+#include <Protocol/Cpu.h>
+#include <Protocol/DeviceIo.h>
+#include <Protocol/NonDiscoverableDevice.h>
+
+#define NON_DISCOVERABLE_IO_DEVICE_SIG SIGNATURE_32 ('N', 'D', 'I', 'D')
+
+#define NON_DISCOVERABLE_IO_DEVICE_FROM_IO(IoPointer)      \
+        CR (IoPointer, NON_DISCOVERABLE_IO_DEVICE, Io,     \
+            NON_DISCOVERABLE_IO_DEVICE_SIG)
+
+extern EFI_CPU_ARCH_PROTOCOL      *mCpu;
+
+typedef struct {
+  //
+  // The linked-list next pointer
+  //
+  LIST_ENTRY          List;
+  //
+  // The address of the uncached allocation
+  //
+  VOID                *HostAddress;
+  //
+  // The number of pages in the allocation
+  //
+  UINTN               NumPages;
+  //
+  // The attributes of the allocation
+  //
+  UINT64              Attributes;
+} NON_DISCOVERABLE_DEVICE_UNCACHED_ALLOCATION;
+
+typedef struct {
+  UINT32                    Signature;
+  //
+  // The bound non-discoverable device protocol instance
+  //
+  NON_DISCOVERABLE_DEVICE   *Device;
+  //
+  // The exposed I/O protocol instance.
+  //
+  EFI_DEVICE_IO_PROTOCOL    Io;
+  //
+  // The I/O attributes for this device
+  //
+  UINT64                    Attributes;
+  //
+  // Whether this device has been enabled
+  //
+  BOOLEAN                   Enabled;
+  //
+  // Linked list to keep track of uncached allocations performed
+  // on behalf of this device
+  //
+  LIST_ENTRY                UncachedAllocationList;
+} NON_DISCOVERABLE_IO_DEVICE;
+
+/**
+  Initialize Io Protocol.
+
+  @param  Device      Point to NON_DISCOVERABLE_IO_DEVICE instance.
+
+**/
+VOID
+InitializeIoProtocol (
+  NON_DISCOVERABLE_IO_DEVICE     *Device
+  );
+
+extern EFI_COMPONENT_NAME_PROTOCOL gComponentName;
+extern EFI_COMPONENT_NAME2_PROTOCOL gComponentName2;
+
+#endif /* __NON_DISCOVERABLE_DEVICE_IO_H__ */
-- 
2.19.0


^ permalink raw reply related	[flat|nested] 12+ messages in thread

* [PATCH v2 2/3] EmbeddedPkg: add PlatformDwMmc protocol
  2019-07-24  9:26 [PATCH v2 0/3] add DwMmcHcDxe driver Loh, Tien Hock
  2019-07-24  9:26 ` [PATCH v2 1/3] EmbeddedPkg: add NonDiscoverableDeviceDxe driver Loh, Tien Hock
@ 2019-07-24  9:26 ` Loh, Tien Hock
  2019-07-24  9:26 ` [PATCH v2 3/3] EmbeddedPkg/Drivers: add DwMmcHcDxe driver Loh, Tien Hock
                   ` (2 subsequent siblings)
  4 siblings, 0 replies; 12+ messages in thread
From: Loh, Tien Hock @ 2019-07-24  9:26 UTC (permalink / raw)
  To: devel, thloh85, haojian.zhuang; +Cc: Leif Lindholm, Ard Biesheuvel, Chris Co

From: Haojian Zhuang <haojian.zhuang@linaro.org>

Add PlatformDwMmc protocol. It's used to set properties of DwMmc
device in platform driver.

Cc: Leif Lindholm <leif.lindholm@linaro.org>
Cc: Ard Biesheuvel <ard.biesheuvel@linaro.org>
Cc: Chris Co <Christopher.Co@microsoft.com>
Contributed-under: TianoCore Contribution Agreement 1.1
Signed-off-by: Haojian Zhuang <haojian.zhuang@linaro.org>
---
 EmbeddedPkg/Include/Protocol/PlatformDwMmc.h | 79 ++++++++++++++++++++
 1 file changed, 79 insertions(+)

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__ */
-- 
2.19.0


^ permalink raw reply related	[flat|nested] 12+ messages in thread

* [PATCH v2 3/3] EmbeddedPkg/Drivers: add DwMmcHcDxe driver
  2019-07-24  9:26 [PATCH v2 0/3] add DwMmcHcDxe driver Loh, Tien Hock
  2019-07-24  9:26 ` [PATCH v2 1/3] EmbeddedPkg: add NonDiscoverableDeviceDxe driver Loh, Tien Hock
  2019-07-24  9:26 ` [PATCH v2 2/3] EmbeddedPkg: add PlatformDwMmc protocol Loh, Tien Hock
@ 2019-07-24  9:26 ` Loh, Tien Hock
  2019-07-25  5:09 ` [PATCH v2 0/3] " haojian.zhuang
  2019-07-30  7:33 ` Haojian Zhuang
  4 siblings, 0 replies; 12+ messages in thread
From: Loh, Tien Hock @ 2019-07-24  9:26 UTC (permalink / raw)
  To: devel, thloh85, haojian.zhuang; +Cc: Leif Lindholm, Ard Biesheuvel, Chris Co

From: Haojian Zhuang <haojian.zhuang@linaro.org>

Add the driver of Designware eMMC/SD controller. It's based on
NonDiscoverableDeviceDxe driver.

Cc: Leif Lindholm <leif.lindholm@linaro.org>
Cc: Ard Biesheuvel <ard.biesheuvel@linaro.org>
Cc: Chris Co <Christopher.Co@microsoft.com>
Contributed-under: TianoCore Contribution Agreement 1.1
Signed-off-by: Haojian Zhuang <haojian.zhuang@linaro.org>
---
 EmbeddedPkg/Drivers/DwMmcHcDxe/ComponentName.c |  214 ++
 EmbeddedPkg/Drivers/DwMmcHcDxe/DwMmcHcDxe.c    | 1295 +++++++++++
 EmbeddedPkg/Drivers/DwMmcHcDxe/DwMmcHcDxe.dec  |   40 +
 EmbeddedPkg/Drivers/DwMmcHcDxe/DwMmcHcDxe.h    |  815 +++++++
 EmbeddedPkg/Drivers/DwMmcHcDxe/DwMmcHcDxe.inf  |   69 +
 EmbeddedPkg/Drivers/DwMmcHcDxe/DwMmcHci.c      | 2366 ++++++++++++++++++++
 EmbeddedPkg/Drivers/DwMmcHcDxe/DwMmcHci.h      |  983 ++++++++
 EmbeddedPkg/Drivers/DwMmcHcDxe/EmmcDevice.c    | 1042 +++++++++
 EmbeddedPkg/Drivers/DwMmcHcDxe/SdDevice.c      | 1104 +++++++++
 9 files changed, 7928 insertions(+)

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/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.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/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/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/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/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;
+}
-- 
2.19.0


^ permalink raw reply related	[flat|nested] 12+ messages in thread

* Re: [PATCH v2 0/3] add DwMmcHcDxe driver
  2019-07-24  9:26 [PATCH v2 0/3] add DwMmcHcDxe driver Loh, Tien Hock
                   ` (2 preceding siblings ...)
  2019-07-24  9:26 ` [PATCH v2 3/3] EmbeddedPkg/Drivers: add DwMmcHcDxe driver Loh, Tien Hock
@ 2019-07-25  5:09 ` haojian.zhuang
  2019-07-30  7:33 ` Haojian Zhuang
  4 siblings, 0 replies; 12+ messages in thread
From: haojian.zhuang @ 2019-07-25  5:09 UTC (permalink / raw)
  To: tien.hock.loh; +Cc: devel, thloh85

On Wed, Jul 24, 2019 at 05:26:03PM +0800, tien.hock.loh@intel.com wrote:
> From: "Tien Hock, Loh" <tien.hock.loh@intel.com>
> 
> Changelog:
> v3:
>   * Fix an issue in NonDiscoverableDeviceDxe driver where it did not invalidate
>     cache before copying the memory.
> v2:
>   *Split DwMmcHcDxe driver into two patches. One is for PlatformDwMmc protocol,
>    and the other is for DwMmcHcDxe driver.
> v1:
>   *Add NonDiscoverableDeviceDxe for embedded platform. Make DwMmcHcDxe driver
>    to support both eMMC and SD controller.
> 
> Haojian Zhuang (3):
>   EmbeddedPkg: add NonDiscoverableDeviceDxe driver
>   EmbeddedPkg: add PlatformDwMmc protocol
>   EmbeddedPkg/Drivers: add DwMmcHcDxe driver
> 
>  .../Drivers/DwMmcHcDxe/ComponentName.c        |  214 ++
>  EmbeddedPkg/Drivers/DwMmcHcDxe/DwMmcHcDxe.c   | 1295 +++++++++
>  EmbeddedPkg/Drivers/DwMmcHcDxe/DwMmcHcDxe.dec |   40 +
>  EmbeddedPkg/Drivers/DwMmcHcDxe/DwMmcHcDxe.h   |  815 ++++++
>  EmbeddedPkg/Drivers/DwMmcHcDxe/DwMmcHcDxe.inf |   69 +
>  EmbeddedPkg/Drivers/DwMmcHcDxe/DwMmcHci.c     | 2366 +++++++++++++++++
>  EmbeddedPkg/Drivers/DwMmcHcDxe/DwMmcHci.h     |  983 +++++++
>  EmbeddedPkg/Drivers/DwMmcHcDxe/EmmcDevice.c   | 1042 ++++++++
>  EmbeddedPkg/Drivers/DwMmcHcDxe/SdDevice.c     | 1104 ++++++++
>  EmbeddedPkg/EmbeddedPkg.dec                   |    1 +
>  EmbeddedPkg/Include/Protocol/PlatformDwMmc.h  |   79 +
>  .../NonDiscoverableDeviceDxe/ComponentName.c  |  124 +
>  .../NonDiscoverableDeviceDxe.c                |  243 ++
>  .../NonDiscoverableDeviceDxe.inf              |   52 +
>  .../NonDiscoverableDeviceIo.c                 |  976 +++++++
>  .../NonDiscoverableDeviceIo.h                 |   92 +
>  16 files changed, 9495 insertions(+)
>  create mode 100644 EmbeddedPkg/Drivers/DwMmcHcDxe/ComponentName.c
>  create mode 100644 EmbeddedPkg/Drivers/DwMmcHcDxe/DwMmcHcDxe.c
>  create mode 100644 EmbeddedPkg/Drivers/DwMmcHcDxe/DwMmcHcDxe.dec
>  create mode 100644 EmbeddedPkg/Drivers/DwMmcHcDxe/DwMmcHcDxe.h
>  create mode 100644 EmbeddedPkg/Drivers/DwMmcHcDxe/DwMmcHcDxe.inf
>  create mode 100644 EmbeddedPkg/Drivers/DwMmcHcDxe/DwMmcHci.c
>  create mode 100644 EmbeddedPkg/Drivers/DwMmcHcDxe/DwMmcHci.h
>  create mode 100644 EmbeddedPkg/Drivers/DwMmcHcDxe/EmmcDevice.c
>  create mode 100644 EmbeddedPkg/Drivers/DwMmcHcDxe/SdDevice.c
>  create mode 100644 EmbeddedPkg/Include/Protocol/PlatformDwMmc.h
>  create mode 100644 EmbeddedPkg/Universal/NonDiscoverableDeviceDxe/ComponentName.c
>  create mode 100644 EmbeddedPkg/Universal/NonDiscoverableDeviceDxe/NonDiscoverableDeviceDxe.c
>  create mode 100644 EmbeddedPkg/Universal/NonDiscoverableDeviceDxe/NonDiscoverableDeviceDxe.inf
>  create mode 100644 EmbeddedPkg/Universal/NonDiscoverableDeviceDxe/NonDiscoverableDeviceIo.c
>  create mode 100644 EmbeddedPkg/Universal/NonDiscoverableDeviceDxe/NonDiscoverableDeviceIo.h
> 
> -- 
> 2.19.0
> 

Tested on HiKey platform.

Best Regards
Haojian

^ permalink raw reply	[flat|nested] 12+ messages in thread

* Re: [PATCH v2 0/3] add DwMmcHcDxe driver
  2019-07-24  9:26 [PATCH v2 0/3] add DwMmcHcDxe driver Loh, Tien Hock
                   ` (3 preceding siblings ...)
  2019-07-25  5:09 ` [PATCH v2 0/3] " haojian.zhuang
@ 2019-07-30  7:33 ` Haojian Zhuang
  2019-08-15  9:09   ` Loh, Tien Hock
  4 siblings, 1 reply; 12+ messages in thread
From: Haojian Zhuang @ 2019-07-30  7:33 UTC (permalink / raw)
  To: tien.hock.loh, leif.lindholm, ard.biesheuvel, christopher.Co
  Cc: devel, thloh85

On Wed, Jul 24, 2019 at 05:26:03PM +0800, tien.hock.loh@intel.com wrote:
> From: "Tien Hock, Loh" <tien.hock.loh@intel.com>
> 
> Changelog:
> v3:
>   * Fix an issue in NonDiscoverableDeviceDxe driver where it did not invalidate
>     cache before copying the memory.
> v2:
>   *Split DwMmcHcDxe driver into two patches. One is for PlatformDwMmc protocol,
>    and the other is for DwMmcHcDxe driver.
> v1:
>   *Add NonDiscoverableDeviceDxe for embedded platform. Make DwMmcHcDxe driver
>    to support both eMMC and SD controller.
> 
> Haojian Zhuang (3):
>   EmbeddedPkg: add NonDiscoverableDeviceDxe driver
>   EmbeddedPkg: add PlatformDwMmc protocol
>   EmbeddedPkg/Drivers: add DwMmcHcDxe driver
> 
>  .../Drivers/DwMmcHcDxe/ComponentName.c        |  214 ++
>  EmbeddedPkg/Drivers/DwMmcHcDxe/DwMmcHcDxe.c   | 1295 +++++++++
>  EmbeddedPkg/Drivers/DwMmcHcDxe/DwMmcHcDxe.dec |   40 +
>  EmbeddedPkg/Drivers/DwMmcHcDxe/DwMmcHcDxe.h   |  815 ++++++
>  EmbeddedPkg/Drivers/DwMmcHcDxe/DwMmcHcDxe.inf |   69 +
>  EmbeddedPkg/Drivers/DwMmcHcDxe/DwMmcHci.c     | 2366 +++++++++++++++++
>  EmbeddedPkg/Drivers/DwMmcHcDxe/DwMmcHci.h     |  983 +++++++
>  EmbeddedPkg/Drivers/DwMmcHcDxe/EmmcDevice.c   | 1042 ++++++++
>  EmbeddedPkg/Drivers/DwMmcHcDxe/SdDevice.c     | 1104 ++++++++
>  EmbeddedPkg/EmbeddedPkg.dec                   |    1 +
>  EmbeddedPkg/Include/Protocol/PlatformDwMmc.h  |   79 +
>  .../NonDiscoverableDeviceDxe/ComponentName.c  |  124 +
>  .../NonDiscoverableDeviceDxe.c                |  243 ++
>  .../NonDiscoverableDeviceDxe.inf              |   52 +
>  .../NonDiscoverableDeviceIo.c                 |  976 +++++++
>  .../NonDiscoverableDeviceIo.h                 |   92 +
>  16 files changed, 9495 insertions(+)
>  create mode 100644 EmbeddedPkg/Drivers/DwMmcHcDxe/ComponentName.c
>  create mode 100644 EmbeddedPkg/Drivers/DwMmcHcDxe/DwMmcHcDxe.c
>  create mode 100644 EmbeddedPkg/Drivers/DwMmcHcDxe/DwMmcHcDxe.dec
>  create mode 100644 EmbeddedPkg/Drivers/DwMmcHcDxe/DwMmcHcDxe.h
>  create mode 100644 EmbeddedPkg/Drivers/DwMmcHcDxe/DwMmcHcDxe.inf
>  create mode 100644 EmbeddedPkg/Drivers/DwMmcHcDxe/DwMmcHci.c
>  create mode 100644 EmbeddedPkg/Drivers/DwMmcHcDxe/DwMmcHci.h
>  create mode 100644 EmbeddedPkg/Drivers/DwMmcHcDxe/EmmcDevice.c
>  create mode 100644 EmbeddedPkg/Drivers/DwMmcHcDxe/SdDevice.c
>  create mode 100644 EmbeddedPkg/Include/Protocol/PlatformDwMmc.h
>  create mode 100644 EmbeddedPkg/Universal/NonDiscoverableDeviceDxe/ComponentName.c
>  create mode 100644 EmbeddedPkg/Universal/NonDiscoverableDeviceDxe/NonDiscoverableDeviceDxe.c
>  create mode 100644 EmbeddedPkg/Universal/NonDiscoverableDeviceDxe/NonDiscoverableDeviceDxe.inf
>  create mode 100644 EmbeddedPkg/Universal/NonDiscoverableDeviceDxe/NonDiscoverableDeviceIo.c
>  create mode 100644 EmbeddedPkg/Universal/NonDiscoverableDeviceDxe/NonDiscoverableDeviceIo.h
> 
> -- 
> 2.19.0
> 

Hi Leif, Ard & Chris,

Could you help to share your comments on this patch set?

Best Regards
Haojian

^ permalink raw reply	[flat|nested] 12+ messages in thread

* Re: [PATCH v2 0/3] add DwMmcHcDxe driver
  2019-07-30  7:33 ` Haojian Zhuang
@ 2019-08-15  9:09   ` Loh, Tien Hock
  2019-09-02  9:31     ` Haojian Zhuang
  0 siblings, 1 reply; 12+ messages in thread
From: Loh, Tien Hock @ 2019-08-15  9:09 UTC (permalink / raw)
  To: Haojian Zhuang, leif.lindholm@linaro.org,
	ard.biesheuvel@linaro.org, christopher.Co@microsoft.com
  Cc: devel@edk2.groups.io, thloh85@gmail.com

Hi Leif, Ard, Christopher,

Haojian and I have tested the driver on 2 platforms, any further comments on this?

Thanks
Tien Hock

> -----Original Message-----
> From: Haojian Zhuang <haojian.zhuang@linaro.org>
> Sent: Tuesday, July 30, 2019 3:33 PM
> To: Loh, Tien Hock <tien.hock.loh@intel.com>; leif.lindholm@linaro.org;
> ard.biesheuvel@linaro.org; christopher.Co@microsoft.com
> Cc: devel@edk2.groups.io; thloh85@gmail.com
> Subject: Re: [PATCH v2 0/3] add DwMmcHcDxe driver
> 
> On Wed, Jul 24, 2019 at 05:26:03PM +0800, tien.hock.loh@intel.com wrote:
> > From: "Tien Hock, Loh" <tien.hock.loh@intel.com>
> >
> > Changelog:
> > v3:
> >   * Fix an issue in NonDiscoverableDeviceDxe driver where it did not
> invalidate
> >     cache before copying the memory.
> > v2:
> >   *Split DwMmcHcDxe driver into two patches. One is for PlatformDwMmc
> protocol,
> >    and the other is for DwMmcHcDxe driver.
> > v1:
> >   *Add NonDiscoverableDeviceDxe for embedded platform. Make
> DwMmcHcDxe driver
> >    to support both eMMC and SD controller.
> >
> > Haojian Zhuang (3):
> >   EmbeddedPkg: add NonDiscoverableDeviceDxe driver
> >   EmbeddedPkg: add PlatformDwMmc protocol
> >   EmbeddedPkg/Drivers: add DwMmcHcDxe driver
> >
> >  .../Drivers/DwMmcHcDxe/ComponentName.c        |  214 ++
> >  EmbeddedPkg/Drivers/DwMmcHcDxe/DwMmcHcDxe.c   | 1295
> +++++++++
> >  EmbeddedPkg/Drivers/DwMmcHcDxe/DwMmcHcDxe.dec |   40 +
> >  EmbeddedPkg/Drivers/DwMmcHcDxe/DwMmcHcDxe.h   |  815 ++++++
> >  EmbeddedPkg/Drivers/DwMmcHcDxe/DwMmcHcDxe.inf |   69 +
> >  EmbeddedPkg/Drivers/DwMmcHcDxe/DwMmcHci.c     | 2366
> +++++++++++++++++
> >  EmbeddedPkg/Drivers/DwMmcHcDxe/DwMmcHci.h     |  983 +++++++
> >  EmbeddedPkg/Drivers/DwMmcHcDxe/EmmcDevice.c   | 1042 ++++++++
> >  EmbeddedPkg/Drivers/DwMmcHcDxe/SdDevice.c     | 1104 ++++++++
> >  EmbeddedPkg/EmbeddedPkg.dec                   |    1 +
> >  EmbeddedPkg/Include/Protocol/PlatformDwMmc.h  |   79 +
> >  .../NonDiscoverableDeviceDxe/ComponentName.c  |  124 +
> >  .../NonDiscoverableDeviceDxe.c                |  243 ++
> >  .../NonDiscoverableDeviceDxe.inf              |   52 +
> >  .../NonDiscoverableDeviceIo.c                 |  976 +++++++
> >  .../NonDiscoverableDeviceIo.h                 |   92 +
> >  16 files changed, 9495 insertions(+)
> >  create mode 100644
> EmbeddedPkg/Drivers/DwMmcHcDxe/ComponentName.c
> >  create mode 100644
> EmbeddedPkg/Drivers/DwMmcHcDxe/DwMmcHcDxe.c
> >  create mode 100644
> EmbeddedPkg/Drivers/DwMmcHcDxe/DwMmcHcDxe.dec
> >  create mode 100644
> EmbeddedPkg/Drivers/DwMmcHcDxe/DwMmcHcDxe.h
> >  create mode 100644
> EmbeddedPkg/Drivers/DwMmcHcDxe/DwMmcHcDxe.inf
> >  create mode 100644 EmbeddedPkg/Drivers/DwMmcHcDxe/DwMmcHci.c
> >  create mode 100644 EmbeddedPkg/Drivers/DwMmcHcDxe/DwMmcHci.h
> >  create mode 100644 EmbeddedPkg/Drivers/DwMmcHcDxe/EmmcDevice.c
> >  create mode 100644 EmbeddedPkg/Drivers/DwMmcHcDxe/SdDevice.c
> >  create mode 100644 EmbeddedPkg/Include/Protocol/PlatformDwMmc.h
> >  create mode 100644
> > EmbeddedPkg/Universal/NonDiscoverableDeviceDxe/ComponentName.c
> >  create mode 100644
> >
> EmbeddedPkg/Universal/NonDiscoverableDeviceDxe/NonDiscoverableDevic
> eDx
> > e.c  create mode 100644
> >
> EmbeddedPkg/Universal/NonDiscoverableDeviceDxe/NonDiscoverableDevic
> eDx
> > e.inf  create mode 100644
> >
> EmbeddedPkg/Universal/NonDiscoverableDeviceDxe/NonDiscoverableDevic
> eIo
> > .c  create mode 100644
> >
> EmbeddedPkg/Universal/NonDiscoverableDeviceDxe/NonDiscoverableDevic
> eIo
> > .h
> >
> > --
> > 2.19.0
> >
> 
> Hi Leif, Ard & Chris,
> 
> Could you help to share your comments on this patch set?
> 
> Best Regards
> Haojian

^ permalink raw reply	[flat|nested] 12+ messages in thread

* Re: [PATCH v2 0/3] add DwMmcHcDxe driver
  2019-08-15  9:09   ` Loh, Tien Hock
@ 2019-09-02  9:31     ` Haojian Zhuang
  2019-09-12  4:59       ` Loh, Tien Hock
  0 siblings, 1 reply; 12+ messages in thread
From: Haojian Zhuang @ 2019-09-02  9:31 UTC (permalink / raw)
  To: Loh, Tien Hock
  Cc: leif.lindholm@linaro.org, ard.biesheuvel@linaro.org,
	christopher.Co@microsoft.com, devel@edk2.groups.io,
	thloh85@gmail.com

Hi Leif, Ard, Christopher,

Could you help to share the comments on this patch set? Thanks a lot.

Best Regards
Haojian

On Thu, Aug 15, 2019 at 09:09:19AM +0000, Loh, Tien Hock wrote:
> Hi Leif, Ard, Christopher,
> 
> Haojian and I have tested the driver on 2 platforms, any further comments on this?
> 
> Thanks
> Tien Hock
> 
> > -----Original Message-----
> > From: Haojian Zhuang <haojian.zhuang@linaro.org>
> > Sent: Tuesday, July 30, 2019 3:33 PM
> > To: Loh, Tien Hock <tien.hock.loh@intel.com>; leif.lindholm@linaro.org;
> > ard.biesheuvel@linaro.org; christopher.Co@microsoft.com
> > Cc: devel@edk2.groups.io; thloh85@gmail.com
> > Subject: Re: [PATCH v2 0/3] add DwMmcHcDxe driver
> > 
> > On Wed, Jul 24, 2019 at 05:26:03PM +0800, tien.hock.loh@intel.com wrote:
> > > From: "Tien Hock, Loh" <tien.hock.loh@intel.com>
> > >
> > > Changelog:
> > > v3:
> > >   * Fix an issue in NonDiscoverableDeviceDxe driver where it did not
> > invalidate
> > >     cache before copying the memory.
> > > v2:
> > >   *Split DwMmcHcDxe driver into two patches. One is for PlatformDwMmc
> > protocol,
> > >    and the other is for DwMmcHcDxe driver.
> > > v1:
> > >   *Add NonDiscoverableDeviceDxe for embedded platform. Make
> > DwMmcHcDxe driver
> > >    to support both eMMC and SD controller.
> > >
> > > Haojian Zhuang (3):
> > >   EmbeddedPkg: add NonDiscoverableDeviceDxe driver
> > >   EmbeddedPkg: add PlatformDwMmc protocol
> > >   EmbeddedPkg/Drivers: add DwMmcHcDxe driver
> > >
> > >  .../Drivers/DwMmcHcDxe/ComponentName.c        |  214 ++
> > >  EmbeddedPkg/Drivers/DwMmcHcDxe/DwMmcHcDxe.c   | 1295
> > +++++++++
> > >  EmbeddedPkg/Drivers/DwMmcHcDxe/DwMmcHcDxe.dec |   40 +
> > >  EmbeddedPkg/Drivers/DwMmcHcDxe/DwMmcHcDxe.h   |  815 ++++++
> > >  EmbeddedPkg/Drivers/DwMmcHcDxe/DwMmcHcDxe.inf |   69 +
> > >  EmbeddedPkg/Drivers/DwMmcHcDxe/DwMmcHci.c     | 2366
> > +++++++++++++++++
> > >  EmbeddedPkg/Drivers/DwMmcHcDxe/DwMmcHci.h     |  983 +++++++
> > >  EmbeddedPkg/Drivers/DwMmcHcDxe/EmmcDevice.c   | 1042 ++++++++
> > >  EmbeddedPkg/Drivers/DwMmcHcDxe/SdDevice.c     | 1104 ++++++++
> > >  EmbeddedPkg/EmbeddedPkg.dec                   |    1 +
> > >  EmbeddedPkg/Include/Protocol/PlatformDwMmc.h  |   79 +
> > >  .../NonDiscoverableDeviceDxe/ComponentName.c  |  124 +
> > >  .../NonDiscoverableDeviceDxe.c                |  243 ++
> > >  .../NonDiscoverableDeviceDxe.inf              |   52 +
> > >  .../NonDiscoverableDeviceIo.c                 |  976 +++++++
> > >  .../NonDiscoverableDeviceIo.h                 |   92 +
> > >  16 files changed, 9495 insertions(+)
> > >  create mode 100644
> > EmbeddedPkg/Drivers/DwMmcHcDxe/ComponentName.c
> > >  create mode 100644
> > EmbeddedPkg/Drivers/DwMmcHcDxe/DwMmcHcDxe.c
> > >  create mode 100644
> > EmbeddedPkg/Drivers/DwMmcHcDxe/DwMmcHcDxe.dec
> > >  create mode 100644
> > EmbeddedPkg/Drivers/DwMmcHcDxe/DwMmcHcDxe.h
> > >  create mode 100644
> > EmbeddedPkg/Drivers/DwMmcHcDxe/DwMmcHcDxe.inf
> > >  create mode 100644 EmbeddedPkg/Drivers/DwMmcHcDxe/DwMmcHci.c
> > >  create mode 100644 EmbeddedPkg/Drivers/DwMmcHcDxe/DwMmcHci.h
> > >  create mode 100644 EmbeddedPkg/Drivers/DwMmcHcDxe/EmmcDevice.c
> > >  create mode 100644 EmbeddedPkg/Drivers/DwMmcHcDxe/SdDevice.c
> > >  create mode 100644 EmbeddedPkg/Include/Protocol/PlatformDwMmc.h
> > >  create mode 100644
> > > EmbeddedPkg/Universal/NonDiscoverableDeviceDxe/ComponentName.c
> > >  create mode 100644
> > >
> > EmbeddedPkg/Universal/NonDiscoverableDeviceDxe/NonDiscoverableDevic
> > eDx
> > > e.c  create mode 100644
> > >
> > EmbeddedPkg/Universal/NonDiscoverableDeviceDxe/NonDiscoverableDevic
> > eDx
> > > e.inf  create mode 100644
> > >
> > EmbeddedPkg/Universal/NonDiscoverableDeviceDxe/NonDiscoverableDevic
> > eIo
> > > .c  create mode 100644
> > >
> > EmbeddedPkg/Universal/NonDiscoverableDeviceDxe/NonDiscoverableDevic
> > eIo
> > > .h
> > >
> > > --
> > > 2.19.0
> > >
> > 
> > Hi Leif, Ard & Chris,
> > 
> > Could you help to share your comments on this patch set?
> > 
> > Best Regards
> > Haojian

^ permalink raw reply	[flat|nested] 12+ messages in thread

* Re: [PATCH v2 0/3] add DwMmcHcDxe driver
  2019-09-02  9:31     ` Haojian Zhuang
@ 2019-09-12  4:59       ` Loh, Tien Hock
  2020-06-16  8:38         ` Loh, Tien Hock
  0 siblings, 1 reply; 12+ messages in thread
From: Loh, Tien Hock @ 2019-09-12  4:59 UTC (permalink / raw)
  To: Haojian Zhuang, leif.lindholm@linaro.org,
	ard.biesheuvel@linaro.org, christopher.Co@microsoft.com
  Cc: devel@edk2.groups.io, thloh85@gmail.com

Hi Ard, Leif, Christopher,

Any comments on the patches?

Thanks!
Tien Hock 
> -----Original Message-----
> From: Haojian Zhuang <haojian.zhuang@linaro.org>
> Sent: Monday, September 2, 2019 5:31 PM
> To: Loh, Tien Hock <tien.hock.loh@intel.com>
> Cc: leif.lindholm@linaro.org; ard.biesheuvel@linaro.org;
> christopher.Co@microsoft.com; devel@edk2.groups.io; thloh85@gmail.com
> Subject: Re: [PATCH v2 0/3] add DwMmcHcDxe driver
> 
> Hi Leif, Ard, Christopher,
> 
> Could you help to share the comments on this patch set? Thanks a lot.
> 
> Best Regards
> Haojian
> 
> On Thu, Aug 15, 2019 at 09:09:19AM +0000, Loh, Tien Hock wrote:
> > Hi Leif, Ard, Christopher,
> >
> > Haojian and I have tested the driver on 2 platforms, any further comments
> on this?
> >
> > Thanks
> > Tien Hock
> >
> > > -----Original Message-----
> > > From: Haojian Zhuang <haojian.zhuang@linaro.org>
> > > Sent: Tuesday, July 30, 2019 3:33 PM
> > > To: Loh, Tien Hock <tien.hock.loh@intel.com>;
> > > leif.lindholm@linaro.org; ard.biesheuvel@linaro.org;
> > > christopher.Co@microsoft.com
> > > Cc: devel@edk2.groups.io; thloh85@gmail.com
> > > Subject: Re: [PATCH v2 0/3] add DwMmcHcDxe driver
> > >
> > > On Wed, Jul 24, 2019 at 05:26:03PM +0800, tien.hock.loh@intel.com
> wrote:
> > > > From: "Tien Hock, Loh" <tien.hock.loh@intel.com>
> > > >
> > > > Changelog:
> > > > v3:
> > > >   * Fix an issue in NonDiscoverableDeviceDxe driver where it did
> > > > not
> > > invalidate
> > > >     cache before copying the memory.
> > > > v2:
> > > >   *Split DwMmcHcDxe driver into two patches. One is for
> > > > PlatformDwMmc
> > > protocol,
> > > >    and the other is for DwMmcHcDxe driver.
> > > > v1:
> > > >   *Add NonDiscoverableDeviceDxe for embedded platform. Make
> > > DwMmcHcDxe driver
> > > >    to support both eMMC and SD controller.
> > > >
> > > > Haojian Zhuang (3):
> > > >   EmbeddedPkg: add NonDiscoverableDeviceDxe driver
> > > >   EmbeddedPkg: add PlatformDwMmc protocol
> > > >   EmbeddedPkg/Drivers: add DwMmcHcDxe driver
> > > >
> > > >  .../Drivers/DwMmcHcDxe/ComponentName.c        |  214 ++
> > > >  EmbeddedPkg/Drivers/DwMmcHcDxe/DwMmcHcDxe.c   | 1295
> > > +++++++++
> > > >  EmbeddedPkg/Drivers/DwMmcHcDxe/DwMmcHcDxe.dec |   40 +
> > > >  EmbeddedPkg/Drivers/DwMmcHcDxe/DwMmcHcDxe.h   |  815
> ++++++
> > > >  EmbeddedPkg/Drivers/DwMmcHcDxe/DwMmcHcDxe.inf |   69 +
> > > >  EmbeddedPkg/Drivers/DwMmcHcDxe/DwMmcHci.c     | 2366
> > > +++++++++++++++++
> > > >  EmbeddedPkg/Drivers/DwMmcHcDxe/DwMmcHci.h     |  983 +++++++
> > > >  EmbeddedPkg/Drivers/DwMmcHcDxe/EmmcDevice.c   | 1042
> ++++++++
> > > >  EmbeddedPkg/Drivers/DwMmcHcDxe/SdDevice.c     | 1104 ++++++++
> > > >  EmbeddedPkg/EmbeddedPkg.dec                   |    1 +
> > > >  EmbeddedPkg/Include/Protocol/PlatformDwMmc.h  |   79 +
> > > >  .../NonDiscoverableDeviceDxe/ComponentName.c  |  124 +
> > > >  .../NonDiscoverableDeviceDxe.c                |  243 ++
> > > >  .../NonDiscoverableDeviceDxe.inf              |   52 +
> > > >  .../NonDiscoverableDeviceIo.c                 |  976 +++++++
> > > >  .../NonDiscoverableDeviceIo.h                 |   92 +
> > > >  16 files changed, 9495 insertions(+)  create mode 100644
> > > EmbeddedPkg/Drivers/DwMmcHcDxe/ComponentName.c
> > > >  create mode 100644
> > > EmbeddedPkg/Drivers/DwMmcHcDxe/DwMmcHcDxe.c
> > > >  create mode 100644
> > > EmbeddedPkg/Drivers/DwMmcHcDxe/DwMmcHcDxe.dec
> > > >  create mode 100644
> > > EmbeddedPkg/Drivers/DwMmcHcDxe/DwMmcHcDxe.h
> > > >  create mode 100644
> > > EmbeddedPkg/Drivers/DwMmcHcDxe/DwMmcHcDxe.inf
> > > >  create mode 100644
> EmbeddedPkg/Drivers/DwMmcHcDxe/DwMmcHci.c
> > > >  create mode 100644
> EmbeddedPkg/Drivers/DwMmcHcDxe/DwMmcHci.h
> > > >  create mode 100644
> EmbeddedPkg/Drivers/DwMmcHcDxe/EmmcDevice.c
> > > >  create mode 100644 EmbeddedPkg/Drivers/DwMmcHcDxe/SdDevice.c
> > > >  create mode 100644
> EmbeddedPkg/Include/Protocol/PlatformDwMmc.h
> > > >  create mode 100644
> > > >
> EmbeddedPkg/Universal/NonDiscoverableDeviceDxe/ComponentName.c
> > > >  create mode 100644
> > > >
> > >
> EmbeddedPkg/Universal/NonDiscoverableDeviceDxe/NonDiscoverableDevic
> > > eDx
> > > > e.c  create mode 100644
> > > >
> > >
> EmbeddedPkg/Universal/NonDiscoverableDeviceDxe/NonDiscoverableDevic
> > > eDx
> > > > e.inf  create mode 100644
> > > >
> > >
> EmbeddedPkg/Universal/NonDiscoverableDeviceDxe/NonDiscoverableDevic
> > > eIo
> > > > .c  create mode 100644
> > > >
> > >
> EmbeddedPkg/Universal/NonDiscoverableDeviceDxe/NonDiscoverableDevic
> > > eIo
> > > > .h
> > > >
> > > > --
> > > > 2.19.0
> > > >
> > >
> > > Hi Leif, Ard & Chris,
> > >
> > > Could you help to share your comments on this patch set?
> > >
> > > Best Regards
> > > Haojian

^ permalink raw reply	[flat|nested] 12+ messages in thread

* Re: [PATCH v2 0/3] add DwMmcHcDxe driver
  2019-09-12  4:59       ` Loh, Tien Hock
@ 2020-06-16  8:38         ` Loh, Tien Hock
  2020-06-19  8:48           ` Loh, Tien Hock
  0 siblings, 1 reply; 12+ messages in thread
From: Loh, Tien Hock @ 2020-06-16  8:38 UTC (permalink / raw)
  To: Haojian Zhuang, leif.lindholm@linaro.org,
	ard.biesheuvel@linaro.org, christopher.Co@microsoft.com
  Cc: devel@edk2.groups.io, thloh85@gmail.com

Hi Leif, Ard,

I talked to Haojian and got to know that you wanted the patch to go into the MdeModulePkg. 
I don't have a lot of context on it, do you have specific requirement?
The driver at its current state already uses the MdeModulePkg's SdDxe's API, so some more specific changes would help me understand and fix the concern you have.

Thanks

> -----Original Message-----
> From: Loh, Tien Hock
> Sent: Thursday, September 12, 2019 12:59 PM
> To: Haojian Zhuang <haojian.zhuang@linaro.org>; leif.lindholm@linaro.org;
> ard.biesheuvel@linaro.org; christopher.Co@microsoft.com
> Cc: devel@edk2.groups.io; thloh85@gmail.com
> Subject: RE: [PATCH v2 0/3] add DwMmcHcDxe driver
> 
> Hi Ard, Leif, Christopher,
> 
> Any comments on the patches?
> 
> Thanks!
> Tien Hock
> > -----Original Message-----
> > From: Haojian Zhuang <haojian.zhuang@linaro.org>
> > Sent: Monday, September 2, 2019 5:31 PM
> > To: Loh, Tien Hock <tien.hock.loh@intel.com>
> > Cc: leif.lindholm@linaro.org; ard.biesheuvel@linaro.org;
> > christopher.Co@microsoft.com; devel@edk2.groups.io; thloh85@gmail.com
> > Subject: Re: [PATCH v2 0/3] add DwMmcHcDxe driver
> >
> > Hi Leif, Ard, Christopher,
> >
> > Could you help to share the comments on this patch set? Thanks a lot.
> >
> > Best Regards
> > Haojian
> >
> > On Thu, Aug 15, 2019 at 09:09:19AM +0000, Loh, Tien Hock wrote:
> > > Hi Leif, Ard, Christopher,
> > >
> > > Haojian and I have tested the driver on 2 platforms, any further
> > > comments
> > on this?
> > >
> > > Thanks
> > > Tien Hock
> > >
> > > > -----Original Message-----
> > > > From: Haojian Zhuang <haojian.zhuang@linaro.org>
> > > > Sent: Tuesday, July 30, 2019 3:33 PM
> > > > To: Loh, Tien Hock <tien.hock.loh@intel.com>;
> > > > leif.lindholm@linaro.org; ard.biesheuvel@linaro.org;
> > > > christopher.Co@microsoft.com
> > > > Cc: devel@edk2.groups.io; thloh85@gmail.com
> > > > Subject: Re: [PATCH v2 0/3] add DwMmcHcDxe driver
> > > >
> > > > On Wed, Jul 24, 2019 at 05:26:03PM +0800, tien.hock.loh@intel.com
> > wrote:
> > > > > From: "Tien Hock, Loh" <tien.hock.loh@intel.com>
> > > > >
> > > > > Changelog:
> > > > > v3:
> > > > >   * Fix an issue in NonDiscoverableDeviceDxe driver where it did
> > > > > not
> > > > invalidate
> > > > >     cache before copying the memory.
> > > > > v2:
> > > > >   *Split DwMmcHcDxe driver into two patches. One is for
> > > > > PlatformDwMmc
> > > > protocol,
> > > > >    and the other is for DwMmcHcDxe driver.
> > > > > v1:
> > > > >   *Add NonDiscoverableDeviceDxe for embedded platform. Make
> > > > DwMmcHcDxe driver
> > > > >    to support both eMMC and SD controller.
> > > > >
> > > > > Haojian Zhuang (3):
> > > > >   EmbeddedPkg: add NonDiscoverableDeviceDxe driver
> > > > >   EmbeddedPkg: add PlatformDwMmc protocol
> > > > >   EmbeddedPkg/Drivers: add DwMmcHcDxe driver
> > > > >
> > > > >  .../Drivers/DwMmcHcDxe/ComponentName.c        |  214 ++
> > > > >  EmbeddedPkg/Drivers/DwMmcHcDxe/DwMmcHcDxe.c   | 1295
> > > > +++++++++
> > > > >  EmbeddedPkg/Drivers/DwMmcHcDxe/DwMmcHcDxe.dec |   40 +
> > > > >  EmbeddedPkg/Drivers/DwMmcHcDxe/DwMmcHcDxe.h   |  815
> > ++++++
> > > > >  EmbeddedPkg/Drivers/DwMmcHcDxe/DwMmcHcDxe.inf |   69 +
> > > > >  EmbeddedPkg/Drivers/DwMmcHcDxe/DwMmcHci.c     | 2366
> > > > +++++++++++++++++
> > > > >  EmbeddedPkg/Drivers/DwMmcHcDxe/DwMmcHci.h     |  983 +++++++
> > > > >  EmbeddedPkg/Drivers/DwMmcHcDxe/EmmcDevice.c   | 1042
> > ++++++++
> > > > >  EmbeddedPkg/Drivers/DwMmcHcDxe/SdDevice.c     | 1104 ++++++++
> > > > >  EmbeddedPkg/EmbeddedPkg.dec                   |    1 +
> > > > >  EmbeddedPkg/Include/Protocol/PlatformDwMmc.h  |   79 +
> > > > >  .../NonDiscoverableDeviceDxe/ComponentName.c  |  124 +
> > > > >  .../NonDiscoverableDeviceDxe.c                |  243 ++
> > > > >  .../NonDiscoverableDeviceDxe.inf              |   52 +
> > > > >  .../NonDiscoverableDeviceIo.c                 |  976 +++++++
> > > > >  .../NonDiscoverableDeviceIo.h                 |   92 +
> > > > >  16 files changed, 9495 insertions(+)  create mode 100644
> > > > EmbeddedPkg/Drivers/DwMmcHcDxe/ComponentName.c
> > > > >  create mode 100644
> > > > EmbeddedPkg/Drivers/DwMmcHcDxe/DwMmcHcDxe.c
> > > > >  create mode 100644
> > > > EmbeddedPkg/Drivers/DwMmcHcDxe/DwMmcHcDxe.dec
> > > > >  create mode 100644
> > > > EmbeddedPkg/Drivers/DwMmcHcDxe/DwMmcHcDxe.h
> > > > >  create mode 100644
> > > > EmbeddedPkg/Drivers/DwMmcHcDxe/DwMmcHcDxe.inf
> > > > >  create mode 100644
> > EmbeddedPkg/Drivers/DwMmcHcDxe/DwMmcHci.c
> > > > >  create mode 100644
> > EmbeddedPkg/Drivers/DwMmcHcDxe/DwMmcHci.h
> > > > >  create mode 100644
> > EmbeddedPkg/Drivers/DwMmcHcDxe/EmmcDevice.c
> > > > >  create mode 100644 EmbeddedPkg/Drivers/DwMmcHcDxe/SdDevice.c
> > > > >  create mode 100644
> > EmbeddedPkg/Include/Protocol/PlatformDwMmc.h
> > > > >  create mode 100644
> > > > >
> > EmbeddedPkg/Universal/NonDiscoverableDeviceDxe/ComponentName.c
> > > > >  create mode 100644
> > > > >
> > > >
> > EmbeddedPkg/Universal/NonDiscoverableDeviceDxe/NonDiscoverableDevic
> > > > eDx
> > > > > e.c  create mode 100644
> > > > >
> > > >
> > EmbeddedPkg/Universal/NonDiscoverableDeviceDxe/NonDiscoverableDevic
> > > > eDx
> > > > > e.inf  create mode 100644
> > > > >
> > > >
> > EmbeddedPkg/Universal/NonDiscoverableDeviceDxe/NonDiscoverableDevic
> > > > eIo
> > > > > .c  create mode 100644
> > > > >
> > > >
> > EmbeddedPkg/Universal/NonDiscoverableDeviceDxe/NonDiscoverableDevic
> > > > eIo
> > > > > .h
> > > > >
> > > > > --
> > > > > 2.19.0
> > > > >
> > > >
> > > > Hi Leif, Ard & Chris,
> > > >
> > > > Could you help to share your comments on this patch set?
> > > >
> > > > Best Regards
> > > > Haojian

^ permalink raw reply	[flat|nested] 12+ messages in thread

* Re: [PATCH v2 0/3] add DwMmcHcDxe driver
  2020-06-16  8:38         ` Loh, Tien Hock
@ 2020-06-19  8:48           ` Loh, Tien Hock
  0 siblings, 0 replies; 12+ messages in thread
From: Loh, Tien Hock @ 2020-06-19  8:48 UTC (permalink / raw)
  To: Haojian Zhuang, leif.lindholm@linaro.org,
	ard.biesheuvel@linaro.org, christopher.Co@microsoft.com
  Cc: devel@edk2.groups.io, thloh85@gmail.com

Hi Leif, Ard,

Can you help on the questions I have below?

Thanks! 

> -----Original Message-----
> From: Loh, Tien Hock
> Sent: Tuesday, June 16, 2020 4:39 PM
> To: 'Haojian Zhuang' <haojian.zhuang@linaro.org>; 'leif.lindholm@linaro.org'
> <leif.lindholm@linaro.org>; 'ard.biesheuvel@linaro.org'
> <ard.biesheuvel@linaro.org>; 'christopher.Co@microsoft.com'
> <christopher.Co@microsoft.com>
> Cc: 'devel@edk2.groups.io' <devel@edk2.groups.io>; 'thloh85@gmail.com'
> <thloh85@gmail.com>
> Subject: RE: [PATCH v2 0/3] add DwMmcHcDxe driver
> 
> Hi Leif, Ard,
> 
> I talked to Haojian and got to know that you wanted the patch to go into the
> MdeModulePkg.
> I don't have a lot of context on it, do you have specific requirement?
> The driver at its current state already uses the MdeModulePkg's SdDxe's API, so
> some more specific changes would help me understand and fix the concern you
> have.
> 
> Thanks
> 
> > -----Original Message-----
> > From: Loh, Tien Hock
> > Sent: Thursday, September 12, 2019 12:59 PM
> > To: Haojian Zhuang <haojian.zhuang@linaro.org>;
> > leif.lindholm@linaro.org; ard.biesheuvel@linaro.org;
> > christopher.Co@microsoft.com
> > Cc: devel@edk2.groups.io; thloh85@gmail.com
> > Subject: RE: [PATCH v2 0/3] add DwMmcHcDxe driver
> >
> > Hi Ard, Leif, Christopher,
> >
> > Any comments on the patches?
> >
> > Thanks!
> > Tien Hock
> > > -----Original Message-----
> > > From: Haojian Zhuang <haojian.zhuang@linaro.org>
> > > Sent: Monday, September 2, 2019 5:31 PM
> > > To: Loh, Tien Hock <tien.hock.loh@intel.com>
> > > Cc: leif.lindholm@linaro.org; ard.biesheuvel@linaro.org;
> > > christopher.Co@microsoft.com; devel@edk2.groups.io;
> > > thloh85@gmail.com
> > > Subject: Re: [PATCH v2 0/3] add DwMmcHcDxe driver
> > >
> > > Hi Leif, Ard, Christopher,
> > >
> > > Could you help to share the comments on this patch set? Thanks a lot.
> > >
> > > Best Regards
> > > Haojian
> > >
> > > On Thu, Aug 15, 2019 at 09:09:19AM +0000, Loh, Tien Hock wrote:
> > > > Hi Leif, Ard, Christopher,
> > > >
> > > > Haojian and I have tested the driver on 2 platforms, any further
> > > > comments
> > > on this?
> > > >
> > > > Thanks
> > > > Tien Hock
> > > >
> > > > > -----Original Message-----
> > > > > From: Haojian Zhuang <haojian.zhuang@linaro.org>
> > > > > Sent: Tuesday, July 30, 2019 3:33 PM
> > > > > To: Loh, Tien Hock <tien.hock.loh@intel.com>;
> > > > > leif.lindholm@linaro.org; ard.biesheuvel@linaro.org;
> > > > > christopher.Co@microsoft.com
> > > > > Cc: devel@edk2.groups.io; thloh85@gmail.com
> > > > > Subject: Re: [PATCH v2 0/3] add DwMmcHcDxe driver
> > > > >
> > > > > On Wed, Jul 24, 2019 at 05:26:03PM +0800,
> > > > > tien.hock.loh@intel.com
> > > wrote:
> > > > > > From: "Tien Hock, Loh" <tien.hock.loh@intel.com>
> > > > > >
> > > > > > Changelog:
> > > > > > v3:
> > > > > >   * Fix an issue in NonDiscoverableDeviceDxe driver where it
> > > > > > did not
> > > > > invalidate
> > > > > >     cache before copying the memory.
> > > > > > v2:
> > > > > >   *Split DwMmcHcDxe driver into two patches. One is for
> > > > > > PlatformDwMmc
> > > > > protocol,
> > > > > >    and the other is for DwMmcHcDxe driver.
> > > > > > v1:
> > > > > >   *Add NonDiscoverableDeviceDxe for embedded platform. Make
> > > > > DwMmcHcDxe driver
> > > > > >    to support both eMMC and SD controller.
> > > > > >
> > > > > > Haojian Zhuang (3):
> > > > > >   EmbeddedPkg: add NonDiscoverableDeviceDxe driver
> > > > > >   EmbeddedPkg: add PlatformDwMmc protocol
> > > > > >   EmbeddedPkg/Drivers: add DwMmcHcDxe driver
> > > > > >
> > > > > >  .../Drivers/DwMmcHcDxe/ComponentName.c        |  214 ++
> > > > > >  EmbeddedPkg/Drivers/DwMmcHcDxe/DwMmcHcDxe.c   | 1295
> > > > > +++++++++
> > > > > >  EmbeddedPkg/Drivers/DwMmcHcDxe/DwMmcHcDxe.dec |   40 +
> > > > > >  EmbeddedPkg/Drivers/DwMmcHcDxe/DwMmcHcDxe.h   |  815
> > > ++++++
> > > > > >  EmbeddedPkg/Drivers/DwMmcHcDxe/DwMmcHcDxe.inf |   69 +
> > > > > >  EmbeddedPkg/Drivers/DwMmcHcDxe/DwMmcHci.c     | 2366
> > > > > +++++++++++++++++
> > > > > >  EmbeddedPkg/Drivers/DwMmcHcDxe/DwMmcHci.h     |  983
> +++++++
> > > > > >  EmbeddedPkg/Drivers/DwMmcHcDxe/EmmcDevice.c   | 1042
> > > ++++++++
> > > > > >  EmbeddedPkg/Drivers/DwMmcHcDxe/SdDevice.c     | 1104 ++++++++
> > > > > >  EmbeddedPkg/EmbeddedPkg.dec                   |    1 +
> > > > > >  EmbeddedPkg/Include/Protocol/PlatformDwMmc.h  |   79 +
> > > > > >  .../NonDiscoverableDeviceDxe/ComponentName.c  |  124 +
> > > > > >  .../NonDiscoverableDeviceDxe.c                |  243 ++
> > > > > >  .../NonDiscoverableDeviceDxe.inf              |   52 +
> > > > > >  .../NonDiscoverableDeviceIo.c                 |  976 +++++++
> > > > > >  .../NonDiscoverableDeviceIo.h                 |   92 +
> > > > > >  16 files changed, 9495 insertions(+)  create mode 100644
> > > > > EmbeddedPkg/Drivers/DwMmcHcDxe/ComponentName.c
> > > > > >  create mode 100644
> > > > > EmbeddedPkg/Drivers/DwMmcHcDxe/DwMmcHcDxe.c
> > > > > >  create mode 100644
> > > > > EmbeddedPkg/Drivers/DwMmcHcDxe/DwMmcHcDxe.dec
> > > > > >  create mode 100644
> > > > > EmbeddedPkg/Drivers/DwMmcHcDxe/DwMmcHcDxe.h
> > > > > >  create mode 100644
> > > > > EmbeddedPkg/Drivers/DwMmcHcDxe/DwMmcHcDxe.inf
> > > > > >  create mode 100644
> > > EmbeddedPkg/Drivers/DwMmcHcDxe/DwMmcHci.c
> > > > > >  create mode 100644
> > > EmbeddedPkg/Drivers/DwMmcHcDxe/DwMmcHci.h
> > > > > >  create mode 100644
> > > EmbeddedPkg/Drivers/DwMmcHcDxe/EmmcDevice.c
> > > > > >  create mode 100644
> EmbeddedPkg/Drivers/DwMmcHcDxe/SdDevice.c
> > > > > >  create mode 100644
> > > EmbeddedPkg/Include/Protocol/PlatformDwMmc.h
> > > > > >  create mode 100644
> > > > > >
> > > EmbeddedPkg/Universal/NonDiscoverableDeviceDxe/ComponentName.c
> > > > > >  create mode 100644
> > > > > >
> > > > >
> > >
> EmbeddedPkg/Universal/NonDiscoverableDeviceDxe/NonDiscoverableDevic
> > > > > eDx
> > > > > > e.c  create mode 100644
> > > > > >
> > > > >
> > >
> EmbeddedPkg/Universal/NonDiscoverableDeviceDxe/NonDiscoverableDevic
> > > > > eDx
> > > > > > e.inf  create mode 100644
> > > > > >
> > > > >
> > >
> EmbeddedPkg/Universal/NonDiscoverableDeviceDxe/NonDiscoverableDevic
> > > > > eIo
> > > > > > .c  create mode 100644
> > > > > >
> > > > >
> > >
> EmbeddedPkg/Universal/NonDiscoverableDeviceDxe/NonDiscoverableDevic
> > > > > eIo
> > > > > > .h
> > > > > >
> > > > > > --
> > > > > > 2.19.0
> > > > > >
> > > > >
> > > > > Hi Leif, Ard & Chris,
> > > > >
> > > > > Could you help to share your comments on this patch set?
> > > > >
> > > > > Best Regards
> > > > > Haojian

^ permalink raw reply	[flat|nested] 12+ messages in thread

end of thread, other threads:[~2020-06-19  8:48 UTC | newest]

Thread overview: 12+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2019-07-24  9:26 [PATCH v2 0/3] add DwMmcHcDxe driver Loh, Tien Hock
2019-07-24  9:26 ` [PATCH v2 1/3] EmbeddedPkg: add NonDiscoverableDeviceDxe driver Loh, Tien Hock
2019-07-24  9:26 ` [PATCH v2 2/3] EmbeddedPkg: add PlatformDwMmc protocol Loh, Tien Hock
2019-07-24  9:26 ` [PATCH v2 3/3] EmbeddedPkg/Drivers: add DwMmcHcDxe driver Loh, Tien Hock
2019-07-25  5:09 ` [PATCH v2 0/3] " haojian.zhuang
2019-07-30  7:33 ` Haojian Zhuang
2019-08-15  9:09   ` Loh, Tien Hock
2019-09-02  9:31     ` Haojian Zhuang
2019-09-12  4:59       ` Loh, Tien Hock
2020-06-16  8:38         ` Loh, Tien Hock
2020-06-19  8:48           ` Loh, Tien Hock
  -- strict thread matches above, loose matches on Subject: below --
2018-08-15  7:36 Haojian Zhuang
2018-08-15  7:36 ` [PATCH v2 2/3] EmbeddedPkg: add PlatformDwMmc protocol Haojian Zhuang

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox