public inbox for devel@edk2.groups.io
 help / color / mirror / Atom feed
* [Patch][edk2-platforms/devel-MinnowBoard3-UDK2017] Add eMMC/SD.
@ 2017-06-09  5:26 lushifex
  2017-06-09  5:28 ` Wei, David
  0 siblings, 1 reply; 2+ messages in thread
From: lushifex @ 2017-06-09  5:26 UTC (permalink / raw)
  To: edk2-devel; +Cc: david.wei

Add Platform eMMC/SD driver.
This reverts commit 66d48af2d24645263b8068e261abc58d84cc2b93.

Contributed-under: TianoCore Contribution Agreement 1.0
Signed-off-by: lushifex <shifeix.a.lu@intel.com>
---
 .../BroxtonPlatformPkg/PlatformDsc/Components.dsc  |   11 +-
 Platform/BroxtonPlatformPkg/PlatformPkg.fdf        |   10 +-
 .../Sdio/Dxe/MMC/MmcHostDxe/ComponentName.c        |  162 ++
 .../Sdio/Dxe/MMC/MmcHostDxe/MmcHostController.c    | 1529 ++++++++++++
 .../Sdio/Dxe/MMC/MmcHostDxe/MmcHostDriver.c        |  613 +++++
 .../Sdio/Dxe/MMC/MmcHostDxe/MmcHostDriver.h        |  585 +++++
 .../Sdio/Dxe/MMC/MmcHostDxe/MmcHostDxe.inf         |   59 +
 .../Sdio/Dxe/MMC/MmcMediaDeviceDxe/ComponentName.c |  159 ++
 .../Sdio/Dxe/MMC/MmcMediaDeviceDxe/MMCSDBlockIo.c  |  666 ++++++
 .../Sdio/Dxe/MMC/MmcMediaDeviceDxe/MMCSDTransfer.c | 2524 ++++++++++++++++++++
 .../Dxe/MMC/MmcMediaDeviceDxe/MediaDeviceDriver.c  |  605 +++++
 .../MMC/MmcMediaDeviceDxe/MmcMediaDeviceDxe.inf    |   71 +
 .../Sdio/Dxe/SD/SdControllerDxe/ComponentName.c    |  233 ++
 .../Sdio/Dxe/SD/SdControllerDxe/ComponentName.h    |  145 ++
 .../Sdio/Dxe/SD/SdControllerDxe/SdController.c     | 1804 ++++++++++++++
 .../Sdio/Dxe/SD/SdControllerDxe/SdController.h     |  314 +++
 .../Dxe/SD/SdControllerDxe/SdControllerDxe.inf     |   59 +
 .../Sdio/Dxe/SD/SdMediaDeviceDxe/CEATA.c           |  638 +++++
 .../Sdio/Dxe/SD/SdMediaDeviceDxe/CEATABlockIo.c    |  384 +++
 .../Sdio/Dxe/SD/SdMediaDeviceDxe/ComponentName.c   |  219 ++
 .../Sdio/Dxe/SD/SdMediaDeviceDxe/ComponentName.h   |  145 ++
 .../Sdio/Dxe/SD/SdMediaDeviceDxe/MMCSDBlockIo.c    |  547 +++++
 .../Sdio/Dxe/SD/SdMediaDeviceDxe/MMCSDTransfer.c   | 1661 +++++++++++++
 .../Sdio/Dxe/SD/SdMediaDeviceDxe/SdMediaDevice.c   |  324 +++
 .../Sdio/Dxe/SD/SdMediaDeviceDxe/SdMediaDevice.h   |  466 ++++
 .../Dxe/SD/SdMediaDeviceDxe/SdMediaDeviceDxe.inf   |   64 +
 26 files changed, 13989 insertions(+), 8 deletions(-)
 create mode 100644 Silicon/BroxtonSoC/BroxtonSiPkg/SouthCluster/Sdio/Dxe/MMC/MmcHostDxe/ComponentName.c
 create mode 100644 Silicon/BroxtonSoC/BroxtonSiPkg/SouthCluster/Sdio/Dxe/MMC/MmcHostDxe/MmcHostController.c
 create mode 100644 Silicon/BroxtonSoC/BroxtonSiPkg/SouthCluster/Sdio/Dxe/MMC/MmcHostDxe/MmcHostDriver.c
 create mode 100644 Silicon/BroxtonSoC/BroxtonSiPkg/SouthCluster/Sdio/Dxe/MMC/MmcHostDxe/MmcHostDriver.h
 create mode 100644 Silicon/BroxtonSoC/BroxtonSiPkg/SouthCluster/Sdio/Dxe/MMC/MmcHostDxe/MmcHostDxe.inf
 create mode 100644 Silicon/BroxtonSoC/BroxtonSiPkg/SouthCluster/Sdio/Dxe/MMC/MmcMediaDeviceDxe/ComponentName.c
 create mode 100644 Silicon/BroxtonSoC/BroxtonSiPkg/SouthCluster/Sdio/Dxe/MMC/MmcMediaDeviceDxe/MMCSDBlockIo.c
 create mode 100644 Silicon/BroxtonSoC/BroxtonSiPkg/SouthCluster/Sdio/Dxe/MMC/MmcMediaDeviceDxe/MMCSDTransfer.c
 create mode 100644 Silicon/BroxtonSoC/BroxtonSiPkg/SouthCluster/Sdio/Dxe/MMC/MmcMediaDeviceDxe/MediaDeviceDriver.c
 create mode 100644 Silicon/BroxtonSoC/BroxtonSiPkg/SouthCluster/Sdio/Dxe/MMC/MmcMediaDeviceDxe/MmcMediaDeviceDxe.inf
 create mode 100644 Silicon/BroxtonSoC/BroxtonSiPkg/SouthCluster/Sdio/Dxe/SD/SdControllerDxe/ComponentName.c
 create mode 100644 Silicon/BroxtonSoC/BroxtonSiPkg/SouthCluster/Sdio/Dxe/SD/SdControllerDxe/ComponentName.h
 create mode 100644 Silicon/BroxtonSoC/BroxtonSiPkg/SouthCluster/Sdio/Dxe/SD/SdControllerDxe/SdController.c
 create mode 100644 Silicon/BroxtonSoC/BroxtonSiPkg/SouthCluster/Sdio/Dxe/SD/SdControllerDxe/SdController.h
 create mode 100644 Silicon/BroxtonSoC/BroxtonSiPkg/SouthCluster/Sdio/Dxe/SD/SdControllerDxe/SdControllerDxe.inf
 create mode 100644 Silicon/BroxtonSoC/BroxtonSiPkg/SouthCluster/Sdio/Dxe/SD/SdMediaDeviceDxe/CEATA.c
 create mode 100644 Silicon/BroxtonSoC/BroxtonSiPkg/SouthCluster/Sdio/Dxe/SD/SdMediaDeviceDxe/CEATABlockIo.c
 create mode 100644 Silicon/BroxtonSoC/BroxtonSiPkg/SouthCluster/Sdio/Dxe/SD/SdMediaDeviceDxe/ComponentName.c
 create mode 100644 Silicon/BroxtonSoC/BroxtonSiPkg/SouthCluster/Sdio/Dxe/SD/SdMediaDeviceDxe/ComponentName.h
 create mode 100644 Silicon/BroxtonSoC/BroxtonSiPkg/SouthCluster/Sdio/Dxe/SD/SdMediaDeviceDxe/MMCSDBlockIo.c
 create mode 100644 Silicon/BroxtonSoC/BroxtonSiPkg/SouthCluster/Sdio/Dxe/SD/SdMediaDeviceDxe/MMCSDTransfer.c
 create mode 100644 Silicon/BroxtonSoC/BroxtonSiPkg/SouthCluster/Sdio/Dxe/SD/SdMediaDeviceDxe/SdMediaDevice.c
 create mode 100644 Silicon/BroxtonSoC/BroxtonSiPkg/SouthCluster/Sdio/Dxe/SD/SdMediaDeviceDxe/SdMediaDevice.h
 create mode 100644 Silicon/BroxtonSoC/BroxtonSiPkg/SouthCluster/Sdio/Dxe/SD/SdMediaDeviceDxe/SdMediaDeviceDxe.inf

diff --git a/Platform/BroxtonPlatformPkg/PlatformDsc/Components.dsc b/Platform/BroxtonPlatformPkg/PlatformDsc/Components.dsc
index 7efcdb4..1322576 100644
--- a/Platform/BroxtonPlatformPkg/PlatformDsc/Components.dsc
+++ b/Platform/BroxtonPlatformPkg/PlatformDsc/Components.dsc
@@ -386,11 +386,14 @@
   $(PLATFORM_PACKAGE_COMMON)/Console/LpssUartSerialDxe/LpssUartSerialDxe.inf
 
   #
-  # eMMC/SD Card
+  # SDIO
   #
-  MdeModulePkg/Bus/Pci/SdMmcPciHcDxe/SdMmcPciHcDxe.inf
-  MdeModulePkg/Bus/Sd/EmmcDxe/EmmcDxe.inf
-  MdeModulePkg/Bus/Sd/SdDxe/SdDxe.inf
+  $(PLATFORM_SI_PACKAGE)/SouthCluster/Sdio/Dxe/MMC/MmcHostDxe/MmcHostDxe.inf
+
+  $(PLATFORM_SI_PACKAGE)/SouthCluster/Sdio/Dxe/MMC/MmcMediaDeviceDxe/MmcMediaDeviceDxe.inf
+
+  $(PLATFORM_SI_PACKAGE)/SouthCluster/Sdio/Dxe/SD/SdControllerDxe/SdControllerDxe.inf
+  $(PLATFORM_SI_PACKAGE)/SouthCluster/Sdio/Dxe/SD/SdMediaDeviceDxe/SdMediaDeviceDxe.inf
 
 
   !if $(ACPI50_ENABLE) == TRUE
diff --git a/Platform/BroxtonPlatformPkg/PlatformPkg.fdf b/Platform/BroxtonPlatformPkg/PlatformPkg.fdf
index 73174af..ac09ac3 100644
--- a/Platform/BroxtonPlatformPkg/PlatformPkg.fdf
+++ b/Platform/BroxtonPlatformPkg/PlatformPkg.fdf
@@ -434,14 +434,16 @@ APRIORI DXE {
   INF MdeModulePkg/Bus/Pci/PciBusDxe/PciBusDxe.inf
 
   #
-  # eMMC/SD Card
+  # SDIO
   #
 !if $(EMMC_DRIVER_ENABLE) == TRUE
-  INF MdeModulePkg/Bus/Pci/SdMmcPciHcDxe/SdMmcPciHcDxe.inf
-  INF MdeModulePkg/Bus/Sd/EmmcDxe/EmmcDxe.inf
-  INF MdeModulePkg/Bus/Sd/SdDxe/SdDxe.inf  
+  INF $(PLATFORM_SI_PACKAGE)/SouthCluster/Sdio/Dxe/MMC/MmcHostDxe/MmcHostDxe.inf
+  INF $(PLATFORM_SI_PACKAGE)/SouthCluster/Sdio/Dxe/MMC/MmcMediaDeviceDxe/MmcMediaDeviceDxe.inf
 !endif
 
+  INF $(PLATFORM_SI_PACKAGE)/SouthCluster/Sdio/Dxe/SD/SdControllerDxe/SdControllerDxe.inf
+  INF $(PLATFORM_SI_PACKAGE)/SouthCluster/Sdio/Dxe/SD/SdMediaDeviceDxe/SdMediaDeviceDxe.inf
+
   INF MdeModulePkg/Universal/Acpi/S3SaveStateDxe/S3SaveStateDxe.inf
   INF IntelFrameworkModulePkg/Universal/Acpi/AcpiS3SaveDxe/AcpiS3SaveDxe.inf
 
diff --git a/Silicon/BroxtonSoC/BroxtonSiPkg/SouthCluster/Sdio/Dxe/MMC/MmcHostDxe/ComponentName.c b/Silicon/BroxtonSoC/BroxtonSiPkg/SouthCluster/Sdio/Dxe/MMC/MmcHostDxe/ComponentName.c
new file mode 100644
index 0000000..f099fa8
--- /dev/null
+++ b/Silicon/BroxtonSoC/BroxtonSiPkg/SouthCluster/Sdio/Dxe/MMC/MmcHostDxe/ComponentName.c
@@ -0,0 +1,162 @@
+/** @file
+  Component Name protocol implementation
+
+  Copyright (c) 2012 - 2016, Intel Corporation. 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 "MmcHostDriver.h"
+
+//
+// EFI Component Name Protocol
+//
+EFI_COMPONENT_NAME_PROTOCOL     gMmcHostComponentName = {
+  MmcHostComponentNameGetDriverName,
+  MmcHostComponentNameGetControllerName,
+  "eng"
+};
+
+
+static EFI_UNICODE_STRING_TABLE mMmcHostDriverNameTable[] = {
+  { "eng", L"UEFI MMC Host Controller Driver" },
+  { NULL , NULL }
+};
+
+
+/**
+  Retrieves a Unicode string that is the user readable name of the EFI Driver.
+
+  @param[in]  This                    A pointer to the EFI_COMPONENT_NAME_PROTOCOL instance.
+  @param[in]  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[out] DriverName              A pointer to the Unicode string to return.  This Unicode string
+                                      is the name of the driver specified by This in the language
+                                      specified by Language.
+
+
+  @retval     EFI_SUCCESS             The Unicode string for the Driver specified by This
+                                      and the language specified by Language was returned
+                                      in DriverName.
+  @retval     EFI_INVALID_PARAMETER   Language is NULL.
+  @retval     EFI_INVALID_PARAMETER   DriverName is NULL.
+  @retval     EFI_UNSUPPORTED         The driver specified by This does not support the
+                                      language specified by Language.
+
+**/
+EFI_STATUS
+EFIAPI
+MmcHostComponentNameGetDriverName (
+  IN  EFI_COMPONENT_NAME_PROTOCOL     *This,
+  IN  CHAR8                           *Language,
+  OUT CHAR16                          **DriverName
+  )
+{
+  return LookupUnicodeString (
+           Language,
+           gMmcHostComponentName.SupportedLanguages,
+           mMmcHostDriverNameTable,
+           DriverName
+           );
+}
+
+
+/**
+  Retrieves a Unicode string that is the user readable name of the controller
+  that is being managed by an EFI Driver.
+
+  @param[in]  This                    A pointer to the EFI_COMPONENT_NAME_PROTOCOL instance.
+  @param[in]  ControllerHandle        The handle of a controller that the driver specified by
+                                      This is managing.  This handle specifies the controller
+                                      whose name is to be returned.
+  @param[in]  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[in]  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[out] ControllerName          A pointer to the Unicode string to return.  This Unicode
+                                      string is the name of the controller specified by
+                                      ControllerHandle and ChildHandle in the language
+                                      specified by Language from the point of view of the
+                                      driver specified by This.
+
+
+  @retval     EFI_SUCCESS             The Unicode string for the user readable name in the
+                                      language specified by Language for the driver
+                                      specified by This was returned in DriverName.
+  @retval     EFI_INVALID_PARAMETER   ControllerHandle is not a valid EFI_HANDLE.
+  @retval     EFI_INVALID_PARAMETER   ChildHandle is not NULL and it is not a valid
+                                      EFI_HANDLE.
+  @retval     EFI_INVALID_PARAMETER   Language is NULL.
+  @retval     EFI_INVALID_PARAMETER   ControllerName is NULL.
+  @retval     EFI_UNSUPPORTED          The driver specified by This is not currently
+                                      managing the controller specified by
+                                      ControllerHandle and ChildHandle.
+  @retval     EFI_UNSUPPORTED         The driver specified by This does not support the
+                                      language specified by Language.
+
+**/
+EFI_STATUS
+EFIAPI
+MmcHostComponentNameGetControllerName (
+  IN  EFI_COMPONENT_NAME_PROTOCOL     *This,
+  IN  EFI_HANDLE                      ControllerHandle,
+  IN  EFI_HANDLE                      ChildHandle, OPTIONAL
+  IN  CHAR8                           *Language,
+  OUT CHAR16                          **ControllerName
+  )
+{
+  EFI_STATUS                          Status;
+  EFI_MMC_HOST_IO_PROTOCOL            *MmcHostIo;
+  MMCHOST_DATA                        *MmcHostData;
+
+  //
+  // This is a device driver, so ChildHandle must be NULL.
+  //
+  if (ChildHandle != NULL) {
+    return EFI_UNSUPPORTED;
+  }
+
+  //
+  // Get the device context
+  //
+  Status = gBS->OpenProtocol (
+                  ControllerHandle,
+                  &gEfiMmcHostIoProtocolGuid,
+                  (VOID **) &MmcHostIo,
+                  gMmcHostDriverBinding.DriverBindingHandle,
+                  ControllerHandle,
+                  EFI_OPEN_PROTOCOL_GET_PROTOCOL
+                  );
+
+  if (EFI_ERROR (Status)) {
+    return Status;
+  }
+
+  MmcHostData = MMCHOST_DATA_FROM_THIS (MmcHostIo);
+
+  return LookupUnicodeString (
+           Language,
+           gMmcHostComponentName.SupportedLanguages,
+           MmcHostData->ControllerNameTable,
+           ControllerName
+           );
+}
+
diff --git a/Silicon/BroxtonSoC/BroxtonSiPkg/SouthCluster/Sdio/Dxe/MMC/MmcHostDxe/MmcHostController.c b/Silicon/BroxtonSoC/BroxtonSiPkg/SouthCluster/Sdio/Dxe/MMC/MmcHostDxe/MmcHostController.c
new file mode 100644
index 0000000..f3cd50e
--- /dev/null
+++ b/Silicon/BroxtonSoC/BroxtonSiPkg/SouthCluster/Sdio/Dxe/MMC/MmcHostDxe/MmcHostController.c
@@ -0,0 +1,1529 @@
+/** @file
+  MMC Host I/O protocol implementation
+
+  Copyright (c) 1999 - 2016, Intel Corporation. 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 "MmcHostDriver.h"
+
+#define MMC_HOST_DEBUG(a)    do { \
+                                if (MmcHostData->EnableVerboseDebug) { \
+                                    DEBUG (a); \
+                                  } \
+                                } while (0);
+
+UINT32  gMmcHostDebugLevel = DEBUG_INFO;
+
+/**
+  Get Error Reason
+
+  @param[in]  CommandIndex      The command index to set the command index field of command register
+  @param[in]  ErrorCode         Mmchost specific error code
+
+  @retval     EFI_DEVICE_ERROR
+  @retval     EFI_TIMEOUT
+  @retval     EFI_CRC_ERROR
+
+**/
+STATIC
+EFI_STATUS
+GetErrorReason (
+  IN  UINT16    CommandIndex,
+  IN  UINT16    ErrorCode
+  )
+{
+  EFI_STATUS    Status;
+
+  Status = EFI_DEVICE_ERROR;
+  DEBUG ((gMmcHostDebugLevel, "[%2d] -- ", CommandIndex));
+
+  if (ErrorCode & BIT0) {
+    Status = EFI_TIMEOUT;
+    DEBUG ((gMmcHostDebugLevel, "Command Timeout Error"));
+  }
+
+  if (ErrorCode & BIT1) {
+    Status = EFI_CRC_ERROR;
+    DEBUG ((gMmcHostDebugLevel, "Command CRC Error"));
+  }
+
+  if (ErrorCode & BIT2) {
+    DEBUG ((gMmcHostDebugLevel, "Command End Bit Error"));
+  }
+
+  if (ErrorCode & BIT3) {
+    DEBUG ((gMmcHostDebugLevel, "Command Index Error"));
+  }
+  if (ErrorCode & BIT4) {
+    Status = EFI_TIMEOUT;
+    DEBUG ((gMmcHostDebugLevel, "Data Timeout Error"));
+  }
+
+  if (ErrorCode & BIT5) {
+    Status = EFI_CRC_ERROR;
+    DEBUG ((gMmcHostDebugLevel, "Data CRC Error"));
+  }
+
+  if (ErrorCode & BIT6) {
+    DEBUG ((gMmcHostDebugLevel, "Data End Bit Error"));
+  }
+
+  if (ErrorCode & BIT7) {
+    DEBUG ((gMmcHostDebugLevel, "Current Limit Error"));
+  }
+
+  if (ErrorCode & BIT8) {
+    DEBUG ((gMmcHostDebugLevel, "Auto CMD12 Error"));
+  }
+
+  if (ErrorCode & BIT9) {
+    DEBUG ((gMmcHostDebugLevel, "ADMA Error"));
+  }
+
+  DEBUG ((gMmcHostDebugLevel, "\n"));
+
+  return Status;
+}
+
+
+/**
+  Read MMC host register
+
+  @param[in]      MmcHost                    Pointer to EFI_MMC_HOST_IO_PROTOCOL
+  @param[in]      Width                      Signifies the width of the memory or I/O operations.
+  @param[in]      Offset                     Offset of the MMC Card
+  @param[in, out] Buffer                     Buffer read from MMC Card
+
+  @retval         EFI_INVALID_PARAMETER
+  @retval         EFI_UNSUPPORTED
+  @retval         EFI_SUCCESS
+
+**/
+STATIC
+EFI_STATUS
+MmcHostRead (
+  IN     MMCHOST_DATA                 *MmcHost,
+  IN     EFI_PCI_IO_PROTOCOL_WIDTH    Width,
+  IN     UINTN                        Offset,
+  IN OUT VOID                         *Buffer
+  )
+{
+  return MmcHost->PciIo->Mem.Read (
+                               MmcHost->PciIo,
+                               Width,
+                               0,
+                               (UINT64) Offset,
+                               1,
+                               Buffer
+                               );
+}
+
+
+/**
+  Read MMC host register
+
+  @param[in]  MmcHost      Pointer to EFI_MMC_HOST_IO_PROTOCOL
+  @param[in]  Offset       Offset of the MMC Card
+
+  @retval     Data         Data read from MMC Card
+
+**/
+UINT8
+MmcHostRead8 (
+  IN     MMCHOST_DATA      *MmcHost,
+  IN     UINTN             Offset
+  )
+{
+  UINT8 Data;
+
+  MmcHostRead (MmcHost, EfiPciIoWidthUint8, Offset, &Data);
+
+  return Data;
+}
+
+
+/**
+  Read MMC host register
+
+  @param[in]  MmcHost        Pointer to EFI_MMC_HOST_IO_PROTOCOL
+  @param[in]  Offset         Offset of the MMC Card
+
+  @retval     Data           Data read from MMC Card
+
+**/
+UINT16
+MmcHostRead16 (
+  IN     MMCHOST_DATA        *MmcHost,
+  IN     UINTN               Offset
+  )
+{
+  UINT16 Data;
+
+  MmcHostRead (MmcHost, EfiPciIoWidthUint16, Offset, &Data);
+
+  return Data;
+}
+
+
+/**
+  Read MMC host register
+
+  @param[in]  MmcHost    Pointer to EFI_MMC_HOST_IO_PROTOCOL
+  @param[in]  Offset     Offset of the MMC Card
+
+  @retval     Data       Data read from MMC Card
+
+**/
+UINT32
+MmcHostRead32 (
+  IN     MMCHOST_DATA    *MmcHost,
+  IN     UINTN           Offset
+  )
+{
+  UINT32 Data;
+
+  MmcHostRead (MmcHost, EfiPciIoWidthUint32, Offset, &Data);
+
+  return Data;
+}
+
+
+/**
+  Dump MMC host registers
+
+  @param[in]  MmcHost     Pointer to EFI_MMC_HOST_IO_PROTOCOL
+
+  @retval     None
+
+**/
+VOID
+DebugPrintMmcHostRegisters (
+  IN     MMCHOST_DATA     *MmcHost
+  )
+{
+#ifdef VERBOSE_REGISTER_ACCESS_DEBUG
+  UINTN    Loop;
+
+  if (!MmcHost->EnableVerboseDebug) {
+    return;
+  }
+
+  for (Loop = 0; Loop < 0x40; Loop++) {
+    DEBUG ((EFI_D_INFO, " %02x", MmcHostRead8 (MmcHost, Loop)));
+    if ((Loop % 0x10) == 0xf) {
+      DEBUG ((EFI_D_INFO, "\n"));
+    }
+  }
+
+#endif
+}
+
+
+/**
+  Dump MMC host registers before write
+
+  @param[in]  MmcHost    Pointer to EFI_MMC_HOST_IO_PROTOCOL
+
+  @retval     None
+
+**/
+VOID
+DebugPreMmcHostWrite (
+  IN     MMCHOST_DATA                  *MmcHost
+  )
+{
+#ifdef VERBOSE_REGISTER_ACCESS_DEBUG
+  STATIC UINTN DebugCount = 0;
+
+  if (!MmcHost->EnableVerboseDebug) {
+    return;
+  }
+
+  DebugCount++;
+
+  if (DebugCount < 0x100) {
+    DEBUG ((EFI_D_INFO, "MMC HOST Registers before write:\n"));
+    DebugPrintMmcHostRegisters (MmcHost);
+  }
+#endif
+}
+
+
+/**
+  Dump MMC host registers after write
+
+  @param[in]  MmcHost      Pointer to EFI_MMC_HOST_IO_PROTOCOL
+
+  @retval     None
+
+**/
+VOID
+DebugPostMmcHostWrite (
+  IN     MMCHOST_DATA                  *MmcHost
+  )
+{
+#ifdef VERBOSE_REGISTER_ACCESS_DEBUG
+  STATIC UINTN DebugCount = 0;
+
+  if (!MmcHost->EnableVerboseDebug) {
+    return;
+  }
+
+  DebugCount++;
+
+  if (DebugCount < 0x10) {
+    DEBUG ((EFI_D_INFO, "MMC HOST Registers after write:\n"));
+    DebugPrintMmcHostRegisters (MmcHost);
+  }
+#endif
+}
+
+
+/**
+  Write MMC host register
+
+  @param[in]      MmcHost                Pointer to EFI_MMC_HOST_IO_PROTOCOL
+  @param[in]      Width                  Signifies the width of the memory or I/O operations.
+  @param[in]      Offset                 Offset of the MMC Card
+  @param[in, out] Buffer                 Buffer read from MMC Card
+
+  @retval         EFI_INVALID_PARAMETER
+  @retval         EFI_UNSUPPORTED
+  @retval         EFI_SUCCESS
+
+**/
+STATIC
+EFI_STATUS
+MmcHostWrite (
+  IN     MMCHOST_DATA                 *MmcHost,
+  IN     EFI_PCI_IO_PROTOCOL_WIDTH    Width,
+  IN     UINTN                        Offset,
+  IN OUT VOID                         *Buffer
+  )
+{
+  EFI_STATUS    Status;
+
+  DebugPreMmcHostWrite (MmcHost);
+  Status = MmcHost->PciIo->Mem.Write (
+                                 MmcHost->PciIo,
+                                 Width,
+                                 0,
+                                 (UINT64) Offset,
+                                 1,
+                                 Buffer
+                                 );
+
+  DebugPostMmcHostWrite (MmcHost);
+
+  return Status;
+}
+
+
+/**
+  Write MMC host register
+
+  @param[in]  MmcHost    Pointer to EFI_MMC_HOST_IO_PROTOCOL
+  @param[in]  Offset     Offset of the MMC Card
+  @param[in]  Data       Data write to MMC Card
+
+  @retval     Data       Written to MmcHost
+
+**/
+UINT8
+MmcHostWrite8 (
+  IN     MMCHOST_DATA                 *MmcHost,
+  IN     UINTN                        Offset,
+  IN     UINT8                        Data
+  )
+{
+  MmcHostWrite (MmcHost, EfiPciIoWidthUint8, Offset, &Data);
+
+  return Data;
+}
+
+
+/**
+  Write MMC host register
+
+  @param[in]  MmcHost    Pointer to EFI_MMC_HOST_IO_PROTOCOL
+  @param[in]  Offset     Offset of the MMC Card
+  @param[in]  Data       Data write to MMC Card
+
+  @retval     Data       Data written to MMC Card
+
+**/
+UINT16
+MmcHostWrite16 (
+  IN     MMCHOST_DATA                 *MmcHost,
+  IN     UINTN                        Offset,
+  IN     UINT16                       Data
+  )
+{
+  MmcHostWrite (MmcHost, EfiPciIoWidthUint16, Offset, &Data);
+
+  return Data;
+}
+
+
+/**
+  Write MMC host register
+
+  @param[in]  MmcHost    Pointer to EFI_MMC_HOST_IO_PROTOCOL
+  @param[in]  Offset     Offset of the MMC Card
+  @param[in]  Data       Data write to MMC Card
+
+  @retval     Data       Data written to MMC Card
+
+**/
+UINT32
+MmcHostWrite32 (
+  IN     MMCHOST_DATA                 *MmcHost,
+  IN     UINTN                        Offset,
+  IN     UINT32                       Data
+  )
+{
+  MmcHostWrite (MmcHost, EfiPciIoWidthUint32, Offset, &Data);
+
+  return Data;
+}
+
+
+/**
+  Check Controller Version
+
+  @param[in]  MmcHost      Pointer to EFI_MMC_HOST_IO_PROTOCOL
+
+  @retval     Data         Written to MmcHost
+
+**/
+UINT32
+CheckControllerVersion (
+  IN MMCHOST_DATA          *MmcHost
+  )
+{
+  UINT16     Data16;
+
+  Data16 = MmcHostRead16 (MmcHost, MMIO_CTRLRVER);
+  DEBUG ((EFI_D_INFO, "CheckControllerVersion: %x \n", Data16 & 0xFF));
+
+  return (Data16 & 0xFF);
+}
+
+
+/**
+  Power on/off the LED associated with the slot
+
+  @param[in]  This         Pointer to EFI_MMC_HOST_IO_PROTOCOL
+  @param[in]  Enable       TRUE to set LED on, FALSE to set LED off
+
+  @retval     EFI_SUCCESS
+
+**/
+STATIC
+EFI_STATUS
+HostLEDEnable (
+  IN  EFI_MMC_HOST_IO_PROTOCOL   *This,
+  IN  BOOLEAN                    Enable
+  )
+{
+  MMCHOST_DATA                   *MmcHostData;
+  UINT8                          Data;
+
+  MmcHostData = MMCHOST_DATA_FROM_THIS (This);
+  Data = MmcHostRead8 (MmcHostData, MMIO_HOSTCTL);
+
+  if (Enable) {
+    //
+    //LED On
+    //
+    Data |= BIT0;
+  } else {
+    //
+    //LED Off
+    //
+    Data &= ~BIT0;
+  }
+
+  MmcHostWrite8 (MmcHostData, MMIO_HOSTCTL, Data);
+
+  return EFI_SUCCESS;
+}
+
+
+/**
+  The main function used to send the command to the card inserted into the MMC host
+  slot.
+  It will assemble the arguments to set the command register and wait for the command
+  and transfer completed until timeout. Then it will read the response register to fill
+  the ResponseData
+
+  @param[in]  This                    Pointer to EFI_MMC_HOST_IO_PROTOCOL
+  @param[in]  CommandIndex            The command index to set the command index field of command register
+  @param[in]  Argument                Command argument to set the argument field of command register
+  @param[in]  DataType                TRANSFER_TYPE, indicates no data, data in or data out
+  @param[in]  Buffer                  Contains the data read from / write to the device
+  @param[in]  BufferSize              The size of the buffer
+  @param[in]  ResponseType            RESPONSE_TYPE
+  @param[in]  TimeOut                 Time out value in 1 ms unit
+  @param[out] ResponseData            Depending on the ResponseType, such as CSD or card status
+
+  @retval     EFI_INVALID_PARAMETER
+  @retval     EFI_UNSUPPORTED
+  @retval     EFI_SUCCESS
+
+**/
+EFI_STATUS
+EFIAPI
+SendCommand (
+  IN   EFI_MMC_HOST_IO_PROTOCOL   *This,
+  IN   UINT16                     CommandIndex,
+  IN   UINT32                     Argument,
+  IN   TRANSFER_TYPE              DataType,
+  IN   UINT8                      *Buffer, OPTIONAL
+  IN   UINT32                     BufferSize,
+  IN   RESPONSE_TYPE              ResponseType,
+  IN   UINT32                     TimeOut,
+  OUT  UINT32                     *ResponseData OPTIONAL
+  )
+{
+  EFI_STATUS                      Status;
+  MMCHOST_DATA                    *MmcHostData;
+  UINT32                          ResponseDataCount;
+  UINT16                          Data16;
+  UINT32                          Data32;
+  UINT64                          Data64;
+  UINT8                           Index;
+  BOOLEAN                         CommandCompleted;
+  INT32                           Timeout = 1000;
+
+  Status             = EFI_SUCCESS;
+  ResponseDataCount  = 1;
+  MmcHostData        = MMCHOST_DATA_FROM_THIS (This);
+
+  if (Buffer != NULL && DataType == NoData) {
+    Status = EFI_INVALID_PARAMETER;
+    DEBUG ((gMmcHostDebugLevel, "SendCommand: Invalid parameter -> \n"));
+    goto Exit;
+  }
+
+  if (((UINTN) Buffer & (This->HostCapability.BoundarySize - 1)) != (UINTN) NULL) {
+    Status = EFI_INVALID_PARAMETER;
+    DEBUG ((gMmcHostDebugLevel, "SendCommand: Invalid parameter -> \n"));
+    goto Exit;
+  }
+
+  DEBUG ((DEBUG_INFO, "SendCommand: CMD%d \n", CommandIndex));
+  if (MmcHostData->EnableVerboseDebug) {
+    DEBUG ((EFI_D_INFO, "00 -10:  %08x  %08x  %08x  %08x \n", MmcHostRead32 (MmcHostData, 0x00), MmcHostRead32 (MmcHostData, 0x04), MmcHostRead32 (MmcHostData, 0x08), MmcHostRead32 (MmcHostData, 0x0C)));
+    DEBUG ((EFI_D_INFO, "10 -20:  %08x  %08x  %08x  %08x \n", MmcHostRead32 (MmcHostData, 0x10), MmcHostRead32 (MmcHostData, 0x14), MmcHostRead32 (MmcHostData, 0x18), MmcHostRead32 (MmcHostData, 0x1C)));
+    DEBUG ((EFI_D_INFO, "20 -30:  %08x  %08x  %08x  %08x \n", MmcHostRead32 (MmcHostData, 0x20), MmcHostRead32 (MmcHostData, 0x24), MmcHostRead32 (MmcHostData, 0x28), MmcHostRead32 (MmcHostData, 0x2C)));
+    DEBUG ((EFI_D_INFO, "30 -40:  %08x  %08x  %08x  %08x \n", MmcHostRead32 (MmcHostData, 0x30), MmcHostRead32 (MmcHostData, 0x34), MmcHostRead32 (MmcHostData, 0x38), MmcHostRead32 (MmcHostData, 0x3C)));
+    DEBUG ((EFI_D_INFO, "40 -50:  %08x  %08x  %08x  %08x \n", MmcHostRead32 (MmcHostData, 0x40), MmcHostRead32 (MmcHostData, 0x44), MmcHostRead32 (MmcHostData, 0x48), MmcHostRead32 (MmcHostData, 0x4C)));
+    DEBUG ((EFI_D_INFO, "50 -60:  %08x  %08x  %08x  %08x \n", MmcHostRead32 (MmcHostData, 0x50), MmcHostRead32 (MmcHostData, 0x54), MmcHostRead32 (MmcHostData, 0x58), MmcHostRead32 (MmcHostData, 0x5C)));
+  }
+
+  //
+  // Check CMD INHIBIT and DATA INHIBIT before send command
+  //
+  do {
+    Data32 = MmcHostRead32 (MmcHostData, MMIO_PSTATE);
+    if (MmcHostData->EnableVerboseDebug) {
+      DEBUG ((EFI_D_INFO, "Wait CMD INHIBIT %x\n",Data32 ));
+    }
+  } while (Timeout-- > 0 && Data32 & BIT0);
+
+  Timeout = 1000;
+  do {
+    Data32 = MmcHostRead32 (MmcHostData, MMIO_PSTATE);
+    if (MmcHostData->EnableVerboseDebug) {
+      DEBUG ((EFI_D_INFO, "Wait DATA INHIBIT %x\n",Data32 ));
+    }
+  } while (Timeout-- >0 && Data32 & BIT1);
+
+  //
+  //Clear status bits
+  //
+  MMC_HOST_DEBUG ((EFI_D_INFO, "NINTSTS(0x30) <- 0x%x\n", (UINTN) 0xffff));
+  MmcHostWrite16 (MmcHostData, MMIO_NINTSTS, 0xffff);
+  MMC_HOST_DEBUG ((EFI_D_INFO, "SendCommand: NINTSTS (0x30): 0x%x\n", MmcHostRead16 (MmcHostData, MMIO_NINTSTS)));
+
+  MMC_HOST_DEBUG ((EFI_D_INFO, "ERINTSTS <- 0x%x\n", (UINTN) 0xffff));
+  MmcHostWrite16 (MmcHostData, MMIO_ERINTSTS, 0xffff);
+  MMC_HOST_DEBUG ((EFI_D_INFO, "SendCommand: ERINTSTS (0x32): 0x%x\n", MmcHostRead16 (MmcHostData, MMIO_ERINTSTS)));
+
+  Data16 = MmcHostRead16 (MmcHostData, MMIO_NINTEN);
+  MmcHostWrite16 (MmcHostData, MMIO_NINTEN,  (Data16 | BIT3));
+  MMC_HOST_DEBUG ((DEBUG_INFO, "SendCommand: NINTEN (0x34) <- 0x%x\n", MmcHostRead16 (MmcHostData, MMIO_NINTEN)));
+  MMC_HOST_DEBUG ((DEBUG_INFO, "SendCommand: DMAADR (0x00) <- 0x%x\n", (UINTN) Buffer));
+  MmcHostWrite32 (MmcHostData, MMIO_DMAADR, (UINT32) (UINTN) Buffer);
+
+  if (Buffer != NULL) {
+    Data16 = MmcHostRead16 (MmcHostData, MMIO_BLKSZ);
+    Data16 &= ~(0xFFF);
+    if (BufferSize <= MmcHostData->BlockLength) {
+      Data16 |= BufferSize;
+    } else {
+      Data16 |= MmcHostData->BlockLength;
+    }
+    Data16 |= 0x7000; // Set to 512KB for SDMA block size
+  } else {
+    Data16 = 0;
+  }
+
+  MMC_HOST_DEBUG ((EFI_D_INFO, "SendCommand: BLKSZ(0x04) <- 0x%x\n", Data16));
+  MmcHostWrite16 (MmcHostData, MMIO_BLKSZ, Data16);
+
+  if (Buffer != NULL) {
+    if (BufferSize <= MmcHostData->BlockLength) {
+      Data16 = 1;
+    } else {
+      Data16 = (UINT16) (BufferSize / MmcHostData->BlockLength);
+    }
+  } else {
+    Data16 = 0;
+  }
+
+  MMC_HOST_DEBUG ((EFI_D_INFO, "SendCommand: BLKCNT(0x06) <- 0x%x\n", Data16));
+  MmcHostWrite16 (MmcHostData, MMIO_BLKCNT, Data16);
+
+  //
+  // Argument
+  //
+  MMC_HOST_DEBUG ((EFI_D_INFO, "SendCommand: CMDARG (0x08) <- 0x%x\n", Argument));
+  MmcHostWrite32 (MmcHostData, MMIO_CMDARG, Argument);
+
+  //
+  // Transfer Mode
+  //
+  Data16 = MmcHostRead16 (MmcHostData, MMIO_XFRMODE);
+  MMC_HOST_DEBUG ((EFI_D_INFO, "SendCommand: XFRMODE (0x0C) mode read 0x%x\n", Data16));
+
+  //
+  // BIT0   DMA Enable
+  // BIT2   Auto Cmd12
+  //
+  if (DataType == InData) {
+    Data16 |= BIT4 | BIT0;
+  } else if (DataType == OutData) {
+    Data16 &= ~BIT4;
+    Data16 |= BIT0;
+  } else {
+    Data16 &= ~(BIT4 | BIT0);
+  }
+
+  if (BufferSize <= MmcHostData->BlockLength) {
+    Data16 &= ~ (BIT5 | BIT1 | BIT2);
+  } else {
+    if (MmcHostData->IsAutoStopCmd && !MmcHostData->IsEmmc) {
+      Data16 |= (BIT5 | BIT1 | BIT2);
+    } else {
+      Data16 |= (BIT5 | BIT1);
+    }
+  }
+  if (CommandIndex == SEND_EXT_CSD) {
+    Data16 |= BIT1;
+    MMC_HOST_DEBUG ((EFI_D_INFO, "SendCommand:Enable bit 1, XFRMODE <- 0x%x\n", Data16));
+  }
+
+  MMC_HOST_DEBUG ((EFI_D_INFO, "SendCommand: XFRMODE (0x0C) <- 0x%x\n", Data16));
+  MmcHostWrite16 (MmcHostData, MMIO_XFRMODE, Data16);
+
+  switch (ResponseType) {
+    case ResponseNo:
+      Data16 = (CommandIndex << 8);
+      ResponseDataCount = 0;
+      break;
+
+    case ResponseR1:
+    case ResponseR5:
+    case ResponseR6:
+    case ResponseR7:
+      Data16 = (CommandIndex << 8) | BIT1 | BIT4| BIT3;
+      ResponseDataCount = 1;
+      break;
+
+    case ResponseR1b:
+    case ResponseR5b:
+      Data16 = (CommandIndex << 8) | BIT0 | BIT1 | BIT4| BIT3;
+      ResponseDataCount = 1;
+      break;
+
+    case ResponseR2:
+      Data16 = (CommandIndex << 8) | BIT0 | BIT3;
+      ResponseDataCount = 4;
+      break;
+
+    case ResponseR3:
+    case ResponseR4:
+      Data16 = (CommandIndex << 8) | BIT1;
+      ResponseDataCount = 1;
+      break;
+
+    default:
+      ASSERT (0);
+      Status = EFI_INVALID_PARAMETER;
+      goto Exit;
+  }
+
+  if (DataType != NoData) {
+    Data16 |= BIT5;
+  }
+
+  HostLEDEnable (This, TRUE);
+
+  MMC_HOST_DEBUG ((EFI_D_INFO, "SendCommand: SDCMD(0x0E) <- 0x%x\n", Data16));
+  CommandCompleted = FALSE;
+  MmcHostWrite16 (MmcHostData, MMIO_SDCMD, Data16);
+
+  if (MmcHostData->EnableVerboseDebug) {
+    DEBUG ((EFI_D_INFO, "After write to  Command\n"));
+    DEBUG ((EFI_D_INFO, "00 -10:  %08x  %08x  %08x  %08x \n", MmcHostRead32 (MmcHostData, 0x00), MmcHostRead32 (MmcHostData, 0x04), MmcHostRead32 (MmcHostData, 0x08), MmcHostRead32 (MmcHostData, 0x0C)));
+    DEBUG ((EFI_D_INFO, "10 -20:  %08x  %08x  %08x  %08x \n", MmcHostRead32 (MmcHostData, 0x10), MmcHostRead32 (MmcHostData, 0x14), MmcHostRead32 (MmcHostData, 0x18), MmcHostRead32 (MmcHostData, 0x1C)));
+    DEBUG ((EFI_D_INFO, "20 -30:  %08x  %08x  %08x  %08x \n", MmcHostRead32 (MmcHostData, 0x20), MmcHostRead32 (MmcHostData, 0x24), MmcHostRead32 (MmcHostData, 0x28), MmcHostRead32 (MmcHostData, 0x2C)));
+    DEBUG ((EFI_D_INFO, "30 -40:  %08x  %08x  %08x  %08x \n", MmcHostRead32 (MmcHostData, 0x30), MmcHostRead32 (MmcHostData, 0x34), MmcHostRead32 (MmcHostData, 0x38), MmcHostRead32 (MmcHostData, 0x3C)));
+    DEBUG ((EFI_D_INFO, "40 -50:  %08x  %08x  %08x  %08x \n", MmcHostRead32 (MmcHostData, 0x40), MmcHostRead32 (MmcHostData, 0x44), MmcHostRead32 (MmcHostData, 0x48), MmcHostRead32 (MmcHostData, 0x4C)));
+    DEBUG ((EFI_D_INFO, "50 -60:  %08x  %08x  %08x  %08x \n", MmcHostRead32 (MmcHostData, 0x50), MmcHostRead32 (MmcHostData, 0x54), MmcHostRead32 (MmcHostData, 0x58), MmcHostRead32 (MmcHostData, 0x5C)));
+  }
+
+  TimeOut *= 1000;  //ms to us conversion
+  do {
+    Data16 = MmcHostRead16 (MmcHostData, MMIO_ERINTSTS);
+    if (MmcHostData->EnableVerboseDebug && (Data16 != 0)) {
+      DEBUG ((EFI_D_INFO, "SendCommand: ERINTSTS (0x32): 0x%x\n", Data16));
+      DEBUG ((EFI_D_INFO, "SendCommand: ERINTEN (0x36): 0x%x\n", MmcHostRead16 (MmcHostData, MMIO_ERINTEN)));
+      DEBUG ((EFI_D_INFO, "SendCommand: NINTSTS (0x30): 0x%x\n", MmcHostRead16 (MmcHostData, MMIO_NINTSTS)));
+      DEBUG ((EFI_D_INFO, "SendCommand: NINTEN (0x34): 0x%x\n", MmcHostRead16 (MmcHostData, MMIO_NINTEN)));
+    }
+
+    if ((Data16 & 0x17FF) != 0) {
+      Status = GetErrorReason (CommandIndex, Data16);
+      DEBUG ((EFI_D_INFO, "00 -10:  %08x  %08x  %08x  %08x \n", MmcHostRead32 (MmcHostData, 0x00), MmcHostRead32 (MmcHostData, 0x04), MmcHostRead32 (MmcHostData, 0x08), MmcHostRead32 (MmcHostData, 0x0C)));
+      DEBUG ((EFI_D_INFO, "10 -20:  %08x  %08x  %08x  %08x \n", MmcHostRead32 (MmcHostData, 0x10), MmcHostRead32 (MmcHostData, 0x14), MmcHostRead32 (MmcHostData, 0x18), MmcHostRead32 (MmcHostData, 0x1C)));
+      DEBUG ((EFI_D_INFO, "20 -30:  %08x  %08x  %08x  %08x \n", MmcHostRead32 (MmcHostData, 0x20), MmcHostRead32 (MmcHostData, 0x24), MmcHostRead32 (MmcHostData, 0x28), MmcHostRead32 (MmcHostData, 0x2C)));
+      DEBUG ((EFI_D_INFO, "30 -40:  %08x  %08x  %08x  %08x \n", MmcHostRead32 (MmcHostData, 0x30), MmcHostRead32 (MmcHostData, 0x34), MmcHostRead32 (MmcHostData, 0x38), MmcHostRead32 (MmcHostData, 0x3C)));
+      DEBUG ((EFI_D_INFO, "40 -50:  %08x  %08x  %08x  %08x \n", MmcHostRead32 (MmcHostData, 0x40), MmcHostRead32 (MmcHostData, 0x44), MmcHostRead32 (MmcHostData, 0x48), MmcHostRead32 (MmcHostData, 0x4C)));
+      DEBUG ((EFI_D_INFO, "50 -60:  %08x  %08x  %08x  %08x \n", MmcHostRead32 (MmcHostData, 0x50), MmcHostRead32 (MmcHostData, 0x54), MmcHostRead32 (MmcHostData, 0x58), MmcHostRead32 (MmcHostData, 0x5C)));
+      goto Exit;
+    }
+
+    Data16 = MmcHostRead16 (MmcHostData, MMIO_NINTSTS) & 0x1ff;
+    if (MmcHostData->EnableVerboseDebug && (Data16 > 1)) {
+      DEBUG ((EFI_D_INFO, "SendCommand: NINTSTS (0x30): 0x%x\n", Data16));
+    }
+
+    if ((Data16 & BIT0) == BIT0) {
+      //
+      // Command completed
+      //
+      CommandCompleted = TRUE;
+
+      MmcHostWrite16 (MmcHostData, MMIO_NINTSTS, BIT0);
+
+      if ((DataType == NoData) && (ResponseType != ResponseR1b)) {
+        break;
+      }
+    }
+
+    if (CommandCompleted) {
+      //
+      // DMA interrupted
+      //
+      if ((Data16 & BIT3) == BIT3) {
+        MmcHostWrite16 (MmcHostData, MMIO_NINTSTS, BIT3);
+        Data32 = MmcHostRead32 (MmcHostData, MMIO_DMAADR);
+        MMC_HOST_DEBUG ((DEBUG_INFO, "SendCommand: DMAADR (0x00) <- 0x%x\n", Data32));
+        MmcHostWrite32 (MmcHostData, MMIO_DMAADR, Data32);
+      }
+
+      //
+      // Transfer completed
+      //
+      if ((Data16 & BIT1) == BIT1) {
+        MmcHostWrite16 (MmcHostData, MMIO_NINTSTS, BIT1);
+        break;
+      }
+    }
+
+    gBS->Stall (1);
+    TimeOut --;
+
+  } while (TimeOut > 0);
+
+  if (TimeOut == 0) {
+    Status = EFI_TIMEOUT;
+    DEBUG ((gMmcHostDebugLevel, "SendCommand: Time out \n"));
+    goto Exit;
+  }
+
+  if (ResponseData != NULL) {
+    UINT32 *ResDataPtr = NULL;
+
+    ResDataPtr = ResponseData;
+    for (Index = 0; Index < ResponseDataCount; Index++) {
+      *ResDataPtr = MmcHostRead32 (MmcHostData, MMIO_RESP + Index * 4);
+      ResDataPtr++;
+    }
+    MMC_HOST_DEBUG ((EFI_D_INFO, "Reponse Data 0: RESPONSE (0x10) <- 0x%x\n", *ResponseData));
+
+    if (ResponseType == ResponseR2) {
+      //
+      // Adjustment for R2 response
+      //
+      Data32 = 1;
+      for (Index = 0; Index < ResponseDataCount; Index++) {
+        Data64 = LShiftU64 (*ResponseData, 8);
+        *ResponseData = (UINT32) ((Data64 & 0xFFFFFFFF) | Data32);
+        Data32 =  (UINT32) RShiftU64 (Data64, 32);
+        ResponseData++;
+      }
+    }
+  }
+
+  if (MmcHostData->EnableVerboseDebug) {
+    DEBUG ((EFI_D_INFO, "Before Exit Send Command\n"));
+    DEBUG ((EFI_D_INFO, "00 -10:  %08x  %08x  %08x  %08x \n", MmcHostRead32 (MmcHostData, 0x00), MmcHostRead32 (MmcHostData, 0x04), MmcHostRead32 (MmcHostData, 0x08), MmcHostRead32 (MmcHostData, 0x0C)));
+    DEBUG ((EFI_D_INFO, "10 -20:  %08x  %08x  %08x  %08x \n", MmcHostRead32 (MmcHostData, 0x10), MmcHostRead32 (MmcHostData, 0x14), MmcHostRead32 (MmcHostData, 0x18), MmcHostRead32 (MmcHostData, 0x1C)));
+    DEBUG ((EFI_D_INFO, "20 -30:  %08x  %08x  %08x  %08x \n", MmcHostRead32 (MmcHostData, 0x20), MmcHostRead32 (MmcHostData, 0x24), MmcHostRead32 (MmcHostData, 0x28), MmcHostRead32 (MmcHostData, 0x2C)));
+    DEBUG ((EFI_D_INFO, "30 -40:  %08x  %08x  %08x  %08x \n", MmcHostRead32 (MmcHostData, 0x30), MmcHostRead32 (MmcHostData, 0x34), MmcHostRead32 (MmcHostData, 0x38), MmcHostRead32 (MmcHostData, 0x3C)));
+    DEBUG ((EFI_D_INFO, "40 -50:  %08x  %08x  %08x  %08x \n", MmcHostRead32 (MmcHostData, 0x40), MmcHostRead32 (MmcHostData, 0x44), MmcHostRead32 (MmcHostData, 0x48), MmcHostRead32 (MmcHostData, 0x4C)));
+    DEBUG ((EFI_D_INFO, "50 -60:  %08x  %08x  %08x  %08x \n", MmcHostRead32 (MmcHostData, 0x50), MmcHostRead32 (MmcHostData, 0x54), MmcHostRead32 (MmcHostData, 0x58), MmcHostRead32 (MmcHostData, 0x5C)));
+  }
+
+Exit:
+  HostLEDEnable (This, FALSE);
+  MMC_HOST_DEBUG ((EFI_D_INFO, "SendCommand: Status -> %r\n", Status));
+
+  return Status;
+}
+
+
+/**
+  Set clock frequency of the host, the actual frequency
+  may not be the same as MaxFrequencyInKHz. It depends on
+  the max frequency the host can support, divider, and host
+  speed mode.
+
+  @param[in]  This             Pointer to EFI_MMC_HOST_IO_PROTOCOL
+  @param[in]  MaxFrequency     Max frequency in HZ
+
+  @retval     EFI_SUCCESS
+
+**/
+EFI_STATUS
+EFIAPI
+SetClockFrequency (
+  IN  EFI_MMC_HOST_IO_PROTOCOL    *This,
+  IN  UINT32                      MaxFrequency
+  )
+{
+  UINT16                          Data16;
+  UINT32                          Frequency;
+  UINT32                          Divider = 0;
+  MMCHOST_DATA                    *MmcHostData;
+  UINT32                          TimeOutCount;
+
+  MmcHostData = MMCHOST_DATA_FROM_THIS (This);
+
+  DEBUG ((gMmcHostDebugLevel, "SetClockFrequency: BaseClockInMHz = %d \n", MmcHostData->BaseClockInMHz));
+
+  Frequency = (MmcHostData->BaseClockInMHz * 1000 * 1000) / MaxFrequency;
+  DEBUG ((gMmcHostDebugLevel, "SetClockFrequency: FrequencyInHz = %d \n", Frequency));
+
+  if ((MmcHostData->BaseClockInMHz * 1000 * 1000 % MaxFrequency) != 0) {
+    Frequency += 1;
+  }
+
+  Divider = 1;
+  while (Frequency > Divider) {
+    Divider = Divider * 2;
+  }
+
+  if (Divider >= 0x400) {
+    Divider = 0x200;
+  }
+  DEBUG ((gMmcHostDebugLevel, "SetClockFrequency: before shift: Base Clock Divider = 0x%x \n", Divider));
+  Divider = Divider >> 1;
+  DEBUG ((gMmcHostDebugLevel, "SetClockFrequency: before shift: Base Clock Divider = 0x%x \n", Divider));
+
+  MmcHostData->CurrentClockInKHz = (MmcHostData->BaseClockInMHz * 1000);
+  if (Divider != 0) {
+    MmcHostData->CurrentClockInKHz = MmcHostData->CurrentClockInKHz / (Divider * 2);
+  }
+
+  if (2 == CheckControllerVersion (MmcHostData)) {
+    Data16 = (UINT16) ((Divider & 0xFF) << 8 | (((Divider & 0xFF00) >>8)<<6));
+  } else {
+    Data16 = (UINT16) ( Divider << 8);
+  }
+
+  DEBUG ((gMmcHostDebugLevel,
+    "SetClockFrequency: base=%dMHz, clkctl=0x%04x, f=%dKHz\n",
+    MmcHostData->BaseClockInMHz,
+    Data16,
+    MmcHostData->CurrentClockInKHz
+    ));
+  DEBUG ((gMmcHostDebugLevel, "SetClockFrequency: set MMIO_CLKCTL value = 0x%x \n", Data16));
+  MmcHostWrite16 (MmcHostData, MMIO_CLKCTL, Data16);
+
+  gBS->Stall (10);
+  Data16 |= BIT0;
+  MmcHostWrite16 (MmcHostData, MMIO_CLKCTL, Data16);
+
+  TimeOutCount = TIME_OUT_1S;
+  do {
+    Data16 = MmcHostRead16 (MmcHostData, MMIO_CLKCTL);
+    gBS->Stall (10);
+    TimeOutCount --;
+    if (TimeOutCount == 0) {
+      DEBUG ((gMmcHostDebugLevel, "SetClockFrequency: Timeout\n"));
+      return EFI_TIMEOUT;
+    }
+  } while ((Data16 & BIT1) != BIT1);
+
+  gBS->Stall (10);
+  Data16 |= BIT2;
+  MmcHostWrite16 (MmcHostData, MMIO_CLKCTL, Data16);
+
+  return EFI_SUCCESS;
+}
+
+
+/**
+  Set bus width of the host
+
+  @param[in]  This         Pointer to EFI_MMC_HOST_IO_PROTOCOL
+  @param[in]  BusWidth     Bus width in 1, 4, 8 bits
+
+  @retval     EFI_SUCCESS
+
+**/
+EFI_STATUS
+EFIAPI
+SetBusWidth (
+  IN  EFI_MMC_HOST_IO_PROTOCOL    *This,
+  IN  UINT32                      BusWidth
+  )
+{
+  MMCHOST_DATA                    *MmcHostData;
+  UINT8                           Data;
+
+  MmcHostData = MMCHOST_DATA_FROM_THIS (This);
+
+  if ((BusWidth != 1) && (BusWidth != 4) && (BusWidth != 8)) {
+    DEBUG ((gMmcHostDebugLevel, "SetBusWidth: Invalid parameter \n"));
+    return EFI_INVALID_PARAMETER;
+  }
+
+  if ((MmcHostData->MmcHostIo.HostCapability.BusWidth8 == FALSE) && (BusWidth == 8)) {
+    DEBUG ((gMmcHostDebugLevel, "SetBusWidth: Invalid parameter \r\n"));
+    return EFI_INVALID_PARAMETER;
+  }
+  Data = MmcHostRead8 (MmcHostData, MMIO_HOSTCTL);
+
+  if (BusWidth == 8) {
+    DEBUG ((gMmcHostDebugLevel, "SetBusWidth: Bus Width is 8-bit ... \r\n"));
+    Data |= BIT5;
+  } else if (BusWidth == 4) {
+    DEBUG ((gMmcHostDebugLevel, "SetBusWidth: Bus Width is 4-bit ... \r\n"));
+    Data &= ~BIT5;
+    Data |= BIT1;
+  } else {
+    DEBUG ((gMmcHostDebugLevel, "SetBusWidth: Bus Width is 1-bit ... \r\n"));
+    Data &= ~BIT5;
+    Data &= ~BIT1;
+  }
+  MmcHostWrite8 (MmcHostData, MMIO_HOSTCTL, Data);
+  DEBUG ((gMmcHostDebugLevel, "SetBusWidth: MMIO_HOSTCTL value: 0x%x  \n", MmcHostRead8 (MmcHostData, MMIO_HOSTCTL)));
+
+  return EFI_SUCCESS;
+}
+
+
+/**
+  Set voltage which could supported by the host.
+  Support 0(Power off the host), 1.8V, 3.0V, 3.3V
+
+  @param[in]  This                       Pointer to EFI_MMC_HOST_IO_PROTOCOL
+  @param[in]  Voltage                    Units in 0.1 V
+
+  @retval     EFI_INVALID_PARAMETER
+  @retval     EFI_UNSUPPORTED
+  @retval     EFI_SUCCESS
+
+**/
+EFI_STATUS
+EFIAPI
+SetHostVoltage (
+  IN  EFI_MMC_HOST_IO_PROTOCOL    *This,
+  IN  UINT32                      Voltage
+  )
+{
+  MMCHOST_DATA                    *MmcHostData;
+  UINT8                           Data;
+  EFI_STATUS                      Status;
+
+  MmcHostData = MMCHOST_DATA_FROM_THIS (This);
+  Status = EFI_SUCCESS;
+
+  Data = MmcHostRead8 (MmcHostData, MMIO_PWRCTL);
+
+  if (Voltage == 0) {
+    //
+    //Power Off the host
+    //
+    Data &= ~BIT0;
+  } else if (Voltage <= 18 && This->HostCapability.V18Support) {
+    //
+    //1.8V
+    //
+    Data |= (BIT1 | BIT3 | BIT0);
+  } else if (Voltage > 18 &&  Voltage <= 30 && This->HostCapability.V30Support) {
+    //
+    //3.0V
+    //
+    Data |= (BIT2 | BIT3 | BIT0);
+  } else if (Voltage > 30 && Voltage <= 33 && This->HostCapability.V33Support) {
+    //
+    //3.3V
+    //
+    Data |= (BIT1 | BIT2 | BIT3 | BIT0);
+  } else {
+    Status = EFI_UNSUPPORTED;
+    goto Exit;
+  }
+
+  MmcHostWrite8 (MmcHostData, MMIO_PWRCTL, Data);
+  gBS->Stall (10);
+
+Exit:
+  return Status;
+}
+
+
+/**
+  Set Host High Speed
+
+  @param[in]  This                      Pointer to EFI_MMC_HOST_IO_PROTOCOL
+  @param[in]  HighSpeed                 True for High Speed Mode set, false for normal mode
+
+  @retval     EFI_INVALID_PARAMETER
+  @retval     EFI_SUCCESS
+
+**/
+EFI_STATUS
+EFIAPI
+SetHostSpeedMode(
+  IN  EFI_MMC_HOST_IO_PROTOCOL    *This,
+  IN  UINT32                      HighSpeed
+  )
+{
+  EFI_STATUS                      Status;
+  MMCHOST_DATA                    *MmcHostData;
+  UINT8                           Data8;
+
+  Status = EFI_SUCCESS;
+  MmcHostData = MMCHOST_DATA_FROM_THIS (This);
+
+  if (MmcHostData->IsEmmc) {
+    Data8 = MmcHostRead8 (MmcHostData, MMIO_HOSTCTL);
+    Data8 &= ~(BIT2);
+    if (HighSpeed) {
+      Data8 |= BIT2;
+      DEBUG ((gMmcHostDebugLevel, "High Speed mode: Data8=0x%x \n", Data8));
+    } else {
+      DEBUG ((gMmcHostDebugLevel, "Normal Speed mode: Data8=0x%x \n", Data8));
+    }
+    MmcHostWrite8 (MmcHostData, MMIO_HOSTCTL, Data8);
+    gBS->Stall (10);
+    DEBUG ((gMmcHostDebugLevel, "MMIO_HOSTCTL value: 0x%x  \n", MmcHostRead8 (MmcHostData, MMIO_HOSTCTL)));
+    return EFI_SUCCESS;
+  } else {
+    return EFI_INVALID_PARAMETER;
+  }
+}
+
+
+/**
+  Set Host mode in DDR
+
+  @param[in]  This                        Pointer to EFI_MMC_HOST_IO_PROTOCOL
+  @param[in]  SetHostDdrMode              True for DDR Mode set, false returns EFI_SUCCESS
+
+  @retval     EFI_INVALID_PARAMETER
+  @retval     EFI_SUCCESS
+
+**/
+EFI_STATUS
+EFIAPI
+SetHostDdrMode(
+  IN  EFI_MMC_HOST_IO_PROTOCOL   *This,
+  IN  UINT32                     DdrMode
+  )
+{
+  EFI_STATUS                     Status;
+  MMCHOST_DATA                   *MmcHostData;
+  UINT16                         ModeSet;
+
+  Status = EFI_SUCCESS;
+  MmcHostData = MMCHOST_DATA_FROM_THIS (This);
+
+  if (MmcHostData->IsEmmc) {
+    ModeSet = MmcHostRead16 (MmcHostData, MMIO_HOST_CTL2);
+    ModeSet &= ~(BIT0 | BIT1 | BIT2);
+    if (DdrMode) {
+      ModeSet |= 0x0004;
+      ModeSet |= BIT3;  //1.8v
+      DEBUG ((gMmcHostDebugLevel, "DDR mode: Data16=0x%x \n", ModeSet));
+    } else {
+      if (CheckControllerVersion (MmcHostData) != 2) {
+        ModeSet =  0x0;
+      }
+    }
+
+    MmcHostWrite16 (MmcHostData, MMIO_HOST_CTL2, ModeSet);
+    gBS->Stall (10);
+    DEBUG ((gMmcHostDebugLevel, "MMIO_HOST_CTL2 value: 0x%x  \n", MmcHostRead16 (MmcHostData, MMIO_HOST_CTL2)));
+    return EFI_SUCCESS;
+  } else {
+    return EFI_INVALID_PARAMETER;
+  }
+}
+
+
+/**
+  Set Host SDR Mode
+
+  @param[in] This                    Pointer to EFI_MMC_HOST_IO_PROTOCOL
+  @param[in] DdrMode                 True for SDR Mode set, false for normal mode
+
+  @retval    EFI_SUCCESS             The function completed successfully
+  @retval    EFI_INVALID_PARAMETER   A parameter was incorrect.
+
+**/
+EFI_STATUS
+EFIAPI
+SetHostSdrMode(
+  IN  EFI_MMC_HOST_IO_PROTOCOL    *This,
+  IN  UINT32                      SdrMode
+  )
+{
+  MMCHOST_DATA                    *MmcHostData;
+  UINT16                          ModeSet;
+
+  MmcHostData = MMCHOST_DATA_FROM_THIS (This);
+
+  if (MmcHostData->IsEmmc) {
+    ModeSet = MmcHostRead16 (MmcHostData, MMIO_HOST_CTL2);
+    ModeSet &= ~(BIT0 | BIT1 | BIT2);
+    if (SdrMode) {
+      if (MmcHostData->MmcHostIo.HostCapability.SDR104Support) {
+        ModeSet |= 3;
+      } else if (MmcHostData->MmcHostIo.HostCapability.SDR50Support) {
+        ModeSet |= 2;
+      }
+      ModeSet |= 1;
+      DEBUG ((gMmcHostDebugLevel, "SDR mode: Data16=0x%x \n", ModeSet));
+    } else {
+      if (CheckControllerVersion (MmcHostData) != 2) {
+        ModeSet =  0x0;
+      }
+    }
+
+    MmcHostWrite16 (MmcHostData, MMIO_HOST_CTL2, ModeSet);
+     gBS->Stall (10);
+    DEBUG ((gMmcHostDebugLevel, "MMIO_HOST_CTL2 value: 0x%x  \n", MmcHostRead16 (MmcHostData, MMIO_HOST_CTL2)));
+    return EFI_SUCCESS;
+  } else {
+    return EFI_INVALID_PARAMETER;
+  }
+}
+
+
+/**
+  Reset the host
+
+  @param[in] This                      Pointer to EFI_MMC_HOST_IO_PROTOCOL
+  @param[in] ResetType                 Reset data/cmd all
+
+  @retval    EFI_SUCCESS               The function completed successfully
+  @retval    EFI_TIMEOUT               The timeout time expired.
+
+**/
+EFI_STATUS
+EFIAPI
+ResetMmcHost (
+  IN  EFI_MMC_HOST_IO_PROTOCOL   *This,
+  IN  RESET_TYPE                 ResetType
+  )
+{
+  MMCHOST_DATA                   *MmcHostData;
+  UINT8                          Data8;
+  UINT32                         Data;
+  UINT16                         ErrStatus;
+  UINT8                          Mask;
+  UINT32                         TimeOutCount;
+  UINT16                         SaveClkCtl;
+  UINT16                         SavePwrCtl = 0;
+
+  MmcHostData = MMCHOST_DATA_FROM_THIS (This);
+  MmcHostData->IsEmmc = TRUE;
+  Mask = 0;
+  ErrStatus = 0;
+
+  if (ResetType == Reset_Auto) {
+    ErrStatus = MmcHostRead16 (MmcHostData, MMIO_ERINTSTS);
+    if ((ErrStatus & 0xF) != 0) {
+      //
+      //Command Line
+      //
+      Mask |= BIT1;
+    }
+    if ((ErrStatus & 0x70) != 0) {
+      //
+      //Data Line
+      //
+      Mask |= BIT2;
+    }
+  }
+
+  if (ResetType == Reset_DAT || ResetType == Reset_DAT_CMD) {
+    Mask |= BIT2;
+  }
+  if (ResetType == Reset_CMD || ResetType == Reset_DAT_CMD) {
+    Mask |= BIT1;
+  }
+  if (ResetType == Reset_All) {
+    Mask = BIT0;
+  }
+  if (ResetType == Reset_HW) {
+    SavePwrCtl = MmcHostRead16 (MmcHostData, MMIO_PWRCTL);
+    DEBUG ((gMmcHostDebugLevel, "Write SavePwrCtl: %x \n", (SavePwrCtl | BIT4)));
+
+    MmcHostWrite16 (MmcHostData, MMIO_PWRCTL, SavePwrCtl | BIT4);
+    gBS->Stall (10);
+    DEBUG ((gMmcHostDebugLevel, "Write SavePwrCtl: %x \n", (SavePwrCtl &(~BIT4))));
+    MmcHostWrite16 (MmcHostData, MMIO_PWRCTL, SavePwrCtl &(~BIT4));
+    gBS->Stall (10);
+  }
+
+  if (Mask == 0) {
+    return EFI_SUCCESS;
+  }
+
+  SaveClkCtl = MmcHostRead16 (MmcHostData, MMIO_CLKCTL);
+
+  MmcHostWrite16 (MmcHostData, MMIO_CLKCTL, 0);
+
+  gBS->Stall (10);
+
+  //
+  // Reset the MMC host controller
+  //
+  MmcHostWrite8 (MmcHostData, MMIO_SWRST, Mask);
+
+  Data = 0;
+  TimeOutCount  = TIME_OUT_1S;
+  do {
+    gBS->Stall (10);
+    TimeOutCount --;
+
+    Data8 = MmcHostRead8 (MmcHostData, MMIO_SWRST);
+    if ((Data8 & Mask) == 0) {
+      break;
+    }
+  } while (TimeOutCount > 0);
+
+  //
+  // We now restore the MMIO_CLKCTL register which we set to 0 above.
+  //
+  MmcHostWrite16 (MmcHostData, MMIO_CLKCTL, SaveClkCtl);
+
+  if (TimeOutCount == 0) {
+    DEBUG ((gMmcHostDebugLevel, "ResetMMCHost: Time out \n"));
+    return EFI_TIMEOUT;
+  }
+
+  return EFI_SUCCESS;
+}
+
+
+/**
+  Enable AutoStop Cmd
+
+  @param[in] This                Pointer to EFI_MMC_HOST_IO_PROTOCOL
+  @param[in] Enable              TRUE to enable
+
+  @retval    EFI_SUCCESS         The function completed successfully
+
+**/
+EFI_STATUS
+EFIAPI
+EnableAutoStopCmd (
+  IN  EFI_MMC_HOST_IO_PROTOCOL    *This,
+  IN  BOOLEAN                     Enable
+  )
+{
+  MMCHOST_DATA                    *MmcHostData;
+
+  MmcHostData = MMCHOST_DATA_FROM_THIS (This);
+
+  MmcHostData->IsAutoStopCmd = Enable;
+
+  return EFI_SUCCESS;
+}
+
+
+/**
+  Set the Block length
+
+  @param[in] This           Pointer to EFI_MMC_HOST_IO_PROTOCOL
+  @param[in] BlockLength    card supportes block length
+
+  @retval    EFI_SUCCESS
+
+**/
+EFI_STATUS
+EFIAPI
+SetBlockLength (
+  IN  EFI_MMC_HOST_IO_PROTOCOL   *This,
+  IN  UINT32                     BlockLength
+  )
+{
+  MMCHOST_DATA                   *MmcHostData;
+
+  MmcHostData = MMCHOST_DATA_FROM_THIS (This);
+
+  DEBUG ((gMmcHostDebugLevel, "SetBlockLength: Block length on the host controller: %d \n", BlockLength));
+  MmcHostData->BlockLength = BlockLength;
+
+  return EFI_SUCCESS;
+}
+
+
+/**
+  Detect card and init Sd host
+  Find whether these is a card inserted into the slot. If so
+  init the host. If not, return EFI_NOT_FOUND.
+
+  @param[in] This                    Pointer to EFI_MMC_HOST_IO_PROTOCOL
+
+  @retval    EFI_INVALID_PARAMETER
+  @retval    EFI_UNSUPPORTED
+  @retval    EFI_SUCCESS
+
+**/
+EFI_STATUS
+EFIAPI
+DetectCardAndInitHost (
+  IN  EFI_MMC_HOST_IO_PROTOCOL   *This
+  )
+{
+  MMCHOST_DATA                   *MmcHostData;
+  UINT16                         Data16;
+  UINT32                         Data;
+  EFI_STATUS                     Status;
+  UINT8                          Voltages[] = { 33, 30, 18 };
+  UINTN                          Loop;
+
+  MmcHostData = MMCHOST_DATA_FROM_THIS (This);
+
+  Data = 0;
+  Data = MmcHostRead32 (MmcHostData, MMIO_PSTATE);
+
+  if ((Data & (BIT16 | BIT17 | BIT18)) != (BIT16 | BIT17 | BIT18)) {
+    //
+    // Has no card inserted
+    //
+    DEBUG ((gMmcHostDebugLevel, "DetectCardAndInitHost: No card\n"));
+    Status =  EFI_NOT_FOUND;
+    goto Exit;
+  }
+  DEBUG ((gMmcHostDebugLevel, "DetectCardAndInitHost: Card present\n"));
+
+  //
+  //Enable normal status change
+  //
+  MmcHostWrite16 (MmcHostData, MMIO_NINTEN, BIT1 | BIT0);
+
+  //
+  // Enable error status change
+  //
+  Data16 = MmcHostRead16 (MmcHostData, MMIO_ERINTEN);
+  Data16 |= 0xFFFF; //(BIT0 | BIT1 | BIT2 | BIT3 | BIT4 | BIT5 | BIT6 | BIT7 | BIT8);
+  MmcHostWrite16 (MmcHostData, MMIO_ERINTEN, Data16);
+
+  //
+  // Data transfer Timeout control
+  //
+  MmcHostWrite8 (MmcHostData, MMIO_TOCTL, 0x0E);
+
+  //
+  // Stall 1 milliseconds to increase MMC stability.
+  //
+  gBS->Stall (10);
+
+  Status = SetClockFrequency (This, FREQUENCY_OD);
+  if (EFI_ERROR (Status)) {
+    DEBUG ((gMmcHostDebugLevel, "DetectCardAndInitHost: SetClockFrequency failed\n"));
+    goto Exit;
+  }
+  DEBUG ((gMmcHostDebugLevel, "DetectCardAndInitHost: SetClockFrequency done\n"));
+
+  Status =  EFI_NOT_FOUND;
+  for (Loop = 0; Loop < sizeof (Voltages); Loop++) {
+    DEBUG ((
+      EFI_D_INFO,
+      "DetectCardAndInitHost: SetHostVoltage %d.%dV\n",
+      Voltages[Loop] / 10,
+      Voltages[Loop] % 10
+      ));
+    Status = SetHostVoltage (This, Voltages[Loop]);
+    if (EFI_ERROR (Status)) {
+      DEBUG ((gMmcHostDebugLevel, "DetectCardAndInitHost: SetHostVoltage failed\n"));
+    } else {
+      DEBUG ((gMmcHostDebugLevel, "DetectCardAndInitHost: SetHostVoltage done\n"));
+      break;
+    }
+  }
+  if (EFI_ERROR (Status)) {
+    DEBUG ((gMmcHostDebugLevel, "DetectCardAndInitHost: Failed to SetHostVoltage\n"));
+    goto Exit;
+  }
+
+Exit:
+  return Status;
+}
+
+
+/**
+  Setup the MMC Host Device
+
+  @param[in] This            Pointer to EFI_MMC_HOST_IO_PROTOCOL
+
+  @retval    EFI_SUCCESS
+
+**/
+EFI_STATUS
+EFIAPI
+SetupDevice (
+  IN  EFI_MMC_HOST_IO_PROTOCOL    *This
+  )
+{
+  UINT32                          tempD = 0;
+  INT32                           timeOut = 1000;
+  UINT8                           temp8 = 0;
+  UINT16                          temp16 = 0;
+  MMCHOST_DATA                    *MmcHostData;
+
+  MmcHostData = MMCHOST_DATA_FROM_THIS (This);
+
+  //
+  // Reset HC and wait for self-clear
+  //
+  MmcHostWrite8 (MmcHostData, MMIO_SWRST, 0x7);
+  gBS->Stall (1000);
+  timeOut = 1000;
+  do {
+    temp8 = MmcHostRead8 (MmcHostData, MMIO_SWRST);
+    timeOut--;
+  } while ((temp8 & (1 << 0)) && (timeOut > 0));
+
+  DEBUG ((EFI_D_INFO, "Reset HC and wait for self-clear Done\n"));
+
+  //
+  // Enable all interrupt status bits (NO CARD_INTERRUPT!)
+  //
+  MmcHostWrite16 (MmcHostData, MMIO_NINTEN, 0x3);
+
+  //
+  // Clear all interrupt status bits
+  //
+  MmcHostWrite16 (MmcHostData, MMIO_NINTSTS, 0xFFFF);
+  MmcHostWrite16 (MmcHostData, MMIO_ERINTEN, 0xFFFF);
+
+  if (2 == CheckControllerVersion (MmcHostData))
+    temp16 = (UINT16) (0x1 << 6);
+  else
+    temp16 = (UINT16) (0x80 << 8);
+  //
+  // Set to 400KB, enable internal clock and wait for stability
+  //
+  MmcHostWrite32 (MmcHostData, MMIO_CLKCTL, (1<<0) | temp16);
+
+  gBS->Stall (1000);
+  do {
+    tempD = MmcHostRead32 (MmcHostData, MMIO_CLKCTL);
+    timeOut--;
+  } while ((!(tempD & (1 << 1))) && (timeOut > 0));
+  gBS->Stall (1000);
+
+  //
+  // Enable MMC clock
+  //
+  tempD |= (1 << 2);
+  MmcHostWrite32 (MmcHostData, MMIO_CLKCTL, tempD);
+  gBS->Stall (1000);
+
+  temp8 = MmcHostRead8 (MmcHostData, MMIO_PWRCTL);
+  DEBUG ((DEBUG_INFO, "==========%a, %d, offset=0x%x, PWRCTL = 0x%x================\n", __FUNCTION__, __LINE__, MMIO_PWRCTL, temp8));
+
+  //
+  // Apply 1.8V to the bus
+  //
+  temp8 = (0x5 << (1) );
+  MmcHostWrite8 (MmcHostData, MMIO_PWRCTL, temp8);
+  gBS->Stall (1000);
+  temp8 = MmcHostRead8 (MmcHostData, MMIO_PWRCTL);
+  DEBUG ((DEBUG_INFO, "==========%a, %d, set (0x5 << 1):offset=0x%x, PWRCTL = 0x%x================\n", __FUNCTION__, __LINE__, MMIO_PWRCTL, temp8));
+
+  //
+  // Set 1.8V sigaling Enabled
+  //
+  temp16 = MmcHostRead16 (MmcHostData, MMIO_HOST_CTL2);
+  temp16 &= ~BIT3;
+  MmcHostWrite16 (MmcHostData, MMIO_HOST_CTL2, temp16);
+  DEBUG ((gMmcHostDebugLevel, "Set 1.8 V signaling Enable:0x%x \r\n", MmcHostRead16 (MmcHostData, MMIO_HOST_CTL2)));
+
+  //
+  // Apply power to MMC
+  //
+  temp8 = MmcHostRead8 (MmcHostData, MMIO_PWRCTL);
+  DEBUG ((DEBUG_INFO, "==========%a, %d, read offset=0x%x, PWRCTL = 0x%x================\n", __FUNCTION__, __LINE__, MMIO_PWRCTL, temp8));
+
+  temp8 |= (1 << (0));
+  DEBUG ((DEBUG_INFO, "==========%a, %d, set 1<<0:offset=0x%x, PWRCTL = 0x%x================\n", __FUNCTION__, __LINE__, MMIO_PWRCTL, temp8));
+
+  MmcHostWrite8 (MmcHostData, MMIO_PWRCTL, temp8);
+  gBS->Stall (1000);              ///<synced to byt-cr pei. bxt power on used (50 * 1000)
+  temp8 = MmcHostRead8 (MmcHostData, MMIO_PWRCTL);
+
+  DEBUG ((DEBUG_INFO, "==========%a, %d, read offset=0x%x, PWRCTL = 0x%x================\n", __FUNCTION__, __LINE__, MMIO_PWRCTL, temp8));
+
+  //
+  // MAX out the DATA_TIMEOUT
+  //
+  MmcHostWrite8 (MmcHostData, MMIO_TOCTL, 0xE);
+  gBS->Stall (1000);
+
+  if (MmcHostData->EnableVerboseDebug) {
+    DEBUG ((EFI_D_INFO, "==========%a, Start. RegMap================\n", __FUNCTION__));
+    DEBUG ((DEBUG_INFO, "00 -10:  %08x  %08x  %08x  %08x \n", MmcHostRead32 (MmcHostData, 0x00), MmcHostRead32 (MmcHostData, 0x04), MmcHostRead32 (MmcHostData, 0x08), MmcHostRead32 (MmcHostData, 0x0C)));
+    DEBUG ((DEBUG_INFO, "10 -20:  %08x  %08x  %08x  %08x \n", MmcHostRead32 (MmcHostData, 0x10), MmcHostRead32 (MmcHostData, 0x14), MmcHostRead32 (MmcHostData, 0x18), MmcHostRead32 (MmcHostData, 0x1C)));
+    DEBUG ((DEBUG_INFO, "20 -30:  %08x  %08x  %08x  %08x \n", MmcHostRead32 (MmcHostData, 0x20), MmcHostRead32 (MmcHostData, 0x24), MmcHostRead32 (MmcHostData, 0x28), MmcHostRead32 (MmcHostData, 0x2C)));
+    DEBUG ((DEBUG_INFO, "30 -40:  %08x  %08x  %08x  %08x \n", MmcHostRead32 (MmcHostData, 0x30), MmcHostRead32 (MmcHostData, 0x34), MmcHostRead32 (MmcHostData, 0x38), MmcHostRead32 (MmcHostData, 0x3C)));
+    DEBUG ((DEBUG_INFO, "40 -50:  %08x  %08x  %08x  %08x \n", MmcHostRead32 (MmcHostData, 0x40), MmcHostRead32 (MmcHostData, 0x44), MmcHostRead32 (MmcHostData, 0x48), MmcHostRead32 (MmcHostData, 0x4C)));
+    DEBUG ((DEBUG_INFO, "50 -60:  %08x  %08x  %08x  %08x \n", MmcHostRead32 (MmcHostData, 0x50), MmcHostRead32 (MmcHostData, 0x54), MmcHostRead32 (MmcHostData, 0x58), MmcHostRead32 (MmcHostData, 0x5C)));
+    DEBUG ((DEBUG_INFO, "==========%a, END. RegMap================\n", __FUNCTION__));
+  }
+  return EFI_SUCCESS;
+}
+
diff --git a/Silicon/BroxtonSoC/BroxtonSiPkg/SouthCluster/Sdio/Dxe/MMC/MmcHostDxe/MmcHostDriver.c b/Silicon/BroxtonSoC/BroxtonSiPkg/SouthCluster/Sdio/Dxe/MMC/MmcHostDxe/MmcHostDriver.c
new file mode 100644
index 0000000..f94dc1d
--- /dev/null
+++ b/Silicon/BroxtonSoC/BroxtonSiPkg/SouthCluster/Sdio/Dxe/MMC/MmcHostDxe/MmcHostDriver.c
@@ -0,0 +1,613 @@
+/** @file
+  UEFI Driver Entry and Binding support.
+
+  Copyright (c) 1999 - 2016, Intel Corporation. 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 "MmcHostDriver.h"
+#include <PiDxe.h>
+
+//
+// MMCSDIOController Driver Global Variables
+//
+EFI_DRIVER_BINDING_PROTOCOL gMmcHostDriverBinding = {
+  MmcHostDriverBindingSupported,
+  MmcHostDriverBindingStart,
+  MmcHostDriverBindingStop,
+  0x10,
+  NULL,
+  NULL
+};
+
+
+EFI_MMC_HOST_IO_PROTOCOL  mMmcHostIo = {
+  EFI_MMC_HOST_IO_PROTOCOL_REVISION_01,
+  {
+    0, ///< HighSpeedSupport
+    0, ///< V18Support
+    0, ///< V30Support
+    0, ///< V33Support
+    0, ///< HS400Support
+    0, ///< BusWidth4
+    0, ///< BusWidth8
+    0, ///< Reserved1
+    0,
+    0,
+    0,
+    0,
+    0, ///< ADMA2Support
+    0, ///< DmaMode
+    0, ///< ReTune Timer
+    0, ///< ReTune Mode
+    0, ///< Reserved2
+    (512 * 1024) ///<BoundarySize 512 KB
+  },
+  SendCommand,
+  SetClockFrequency,
+  SetBusWidth,
+  SetHostVoltage,
+  SetHostDdrMode,
+  SetHostSdrMode,
+  ResetMmcHost,
+  EnableAutoStopCmd,
+  DetectCardAndInitHost,
+  SetBlockLength,
+  SetupDevice,
+  SetHostSpeedMode
+};
+
+
+/**
+  Entry point for MMC Host EFI drivers.
+
+  @param[in] ImageHandle          EFI_HANDLE
+  @param[in] SystemTable          EFI_SYSTEM_TABLE
+
+  @retval    EFI_SUCCESS          The function completed successfully
+  @retval    EFI_DEVICE_ERROR     The function failed to complete
+
+**/
+EFI_STATUS
+EFIAPI
+MmcHostDriverEntryPoint (
+  IN EFI_HANDLE           ImageHandle,
+  IN EFI_SYSTEM_TABLE     *SystemTable
+  )
+{
+  return EfiLibInstallAllDriverProtocols (
+           ImageHandle,
+           SystemTable,
+           &gMmcHostDriverBinding,
+           ImageHandle,
+           &gMmcHostComponentName,
+           NULL,
+           NULL
+           );
+}
+
+
+/**
+  Test to see if this MMC Host driver supports ControllerHandle.
+  Any ControllerHandle that has installed will be supported.
+
+  @param[in] This                    Protocol instance pointer
+  @param[in] Controller              Handle of device to test
+  @param[in] RemainingDevicePath     Not used
+
+  @retval    EFI_SUCCESS             This driver supports this device
+  @retval    EFI_UNSUPPORTED         This driver does not support this device
+
+**/
+EFI_STATUS
+EFIAPI
+MmcHostDriverBindingSupported (
+  IN EFI_DRIVER_BINDING_PROTOCOL *This,
+  IN EFI_HANDLE                  Controller,
+  IN EFI_DEVICE_PATH_PROTOCOL    *RemainingDevicePath
+  )
+{
+  EFI_STATUS                     Status;
+  EFI_PCI_IO_PROTOCOL            *PciIo;
+  EFI_MMC_HOST_IO_PROTOCOL       *MmcHostIo;
+  PCI_CLASSC                     PciClass;
+  UINT32                         VidDid;
+  UINT32                         Bar0 = 0;
+  UINT32                         Bar1 = 0;
+  UINTN                          Seg, Bus, Dev, Func;
+
+  //
+  // Verify the MMC IO Protocol, which installed by the
+  // IdeController module.
+  //
+  Status = gBS->OpenProtocol (
+                  Controller,
+                  &gEfiMmcHostIoProtocolGuid,
+                  (VOID **) &MmcHostIo,
+                  This->DriverBindingHandle,
+                  Controller,
+                  EFI_OPEN_PROTOCOL_GET_PROTOCOL
+                  );
+  if (!EFI_ERROR (Status)) {
+    DEBUG ((DEBUG_INFO, "MmcHost controller already started, Controller: 0x%016Lx\r\n",  (UINT64) (UINTN) Controller));
+    Status = EFI_ALREADY_STARTED;
+    return Status;
+  }
+
+  //
+  // Test whether there is PCI IO Protocol attached on the controller handle.
+  //
+  Status = gBS->OpenProtocol (
+                  Controller,
+                  &gEfiPciIoProtocolGuid,
+                  (VOID**) &PciIo,
+                  This->DriverBindingHandle,
+                  Controller,
+                  EFI_OPEN_PROTOCOL_BY_DRIVER
+                  );
+  if (EFI_ERROR (Status)) {
+    return Status;
+  }
+
+  Status = PciIo->Pci.Read (
+                        PciIo,
+                        EfiPciIoWidthUint32,
+                        PCI_VENDOR_ID_OFFSET,
+                        1,
+                        &VidDid
+                        );
+  if (EFI_ERROR (Status)) {
+    goto Exit;
+  }
+
+  Status = PciIo->Pci.Read (
+                        PciIo,
+                        EfiPciIoWidthUint8,
+                        PCI_CLASSCODE_OFFSET,
+                        sizeof (PCI_CLASSC) / sizeof (UINT8),
+                        &PciClass
+                        );
+  if (EFI_ERROR (Status)) {
+    Status = EFI_UNSUPPORTED;
+    goto Exit;
+  }
+
+  Status = PciIo->Pci.Read (
+                        PciIo,
+                        EfiPciIoWidthUint32,
+                        PCI_BASE_ADDRESSREG_OFFSET,
+                        1,
+                        &Bar0
+                        );
+  if (EFI_ERROR (Status)) {
+    Status = EFI_UNSUPPORTED;
+    goto Exit;
+  }
+
+  Status = PciIo->Pci.Read (
+                        PciIo,
+                        EfiPciIoWidthUint32,
+                        PCI_BASE_ADDRESSREG_OFFSET + 4,
+                        1,
+                        &Bar1
+                        );
+  if (EFI_ERROR (Status)) {
+    Status = EFI_UNSUPPORTED;
+    goto Exit;
+  }
+
+  Status = PciIo->GetLocation (
+                    PciIo,
+                    &Seg,
+                    &Bus,
+                    &Dev,
+                    &Func
+                    );
+
+  if (EFI_ERROR (Status)) {
+    Status = EFI_UNSUPPORTED;
+    goto Exit;
+  }
+
+  if ((Seg != 0) || (Bus != 0) || (Dev != 28) || (Func != 0)) {
+    //
+    // This is not the eMMC controller, bail.
+    //
+    Status = EFI_UNSUPPORTED;
+    goto Exit;
+  }
+
+  if ((PciClass.BaseCode != PCI_CLASS_SYSTEM_PERIPHERAL) ||
+     (PciClass.SubClassCode != PCI_SUBCLASS_SD_HOST_CONTROLLER) ||
+     ((PciClass.PI != PCI_IF_STANDARD_HOST_NO_DMA) && (PciClass.PI != PCI_IF_STANDARD_HOST_SUPPORT_DMA))
+     ) {
+    Status = EFI_UNSUPPORTED;
+    goto Exit;
+  }
+
+  DEBUG ((EFI_D_INFO, "MmcHostDriverBindingSupported0: Seg %d, bus:%d, Dev:%d, Func:%d\n", Seg, Bus, Dev, Func));
+  DEBUG ((EFI_D_INFO, "MmcHostDriverBindingSupported1: VidDid %08x\n", VidDid));
+  DEBUG ((EFI_D_INFO, "MmcHostDriverBindingSupported1: Base Code %x\n", PciClass.BaseCode));
+  DEBUG ((EFI_D_INFO, "MmcHostDriverBindingSupported1: SubClassCode %x\n", PciClass.SubClassCode));
+  DEBUG ((EFI_D_INFO, "MmcHostDriverBindingSupported1: PI %x\n", PciClass.PI));
+  DEBUG ((EFI_D_INFO, "MmcHostDriverBindingSupported0: MEMIO Base0 %x\n", Bar0));
+  DEBUG ((EFI_D_INFO, "MmcHostDriverBindingSupported0: MEMIO Base1 %x\n", Bar1));
+
+Exit:
+  gBS->CloseProtocol (
+         Controller,
+         &gEfiPciIoProtocolGuid,
+         This->DriverBindingHandle,
+         Controller
+         );
+  return Status;
+}
+
+
+/**
+  Starting the MMC Host Driver
+
+  @param[in] This                     Protocol instance pointer
+  @param[in] Controller               Handle of device to start
+  @param[in] RemainingDevicePath      Not used
+
+  @retval    EFI_SUCCESS              This driver start this device
+  @retval    EFI_UNSUPPORTED          This driver does not support this device
+  @retval    EFI_DEVICE_ERROR         This driver cannot be started due to device Error
+  @retval    EFI_OUT_OF_RESOURCES     This driver cannot allocate resources
+
+**/
+EFI_STATUS
+EFIAPI
+MmcHostDriverBindingStart (
+  IN EFI_DRIVER_BINDING_PROTOCOL     *This,
+  IN EFI_HANDLE                      Controller,
+  IN EFI_DEVICE_PATH_PROTOCOL        *RemainingDevicePath
+  )
+{
+  EFI_PCI_IO_PROTOCOL                *PciIo;
+  EFI_STATUS                         Status;
+  MMCHOST_DATA                       *MmcHostData;
+  UINT32                             Data;
+  UINT16                             Data16;
+  UINT32                             VidDid;
+  UINT32                             Bar0 = 0;
+  UINT32                             Bar1 = 0;
+  UINTN                              Seg, Bus, Dev, Func;
+
+  MmcHostData = NULL;
+  Data       = 0;
+  DEBUG ((EFI_D_INFO, "MmcHostDriverBindingStart: Start\n"));
+
+  //
+  // Open PCI I/O Protocol and save pointer to open protocol
+  // in private data area.
+  //
+  Status = gBS->OpenProtocol (
+                  Controller,
+                  &gEfiPciIoProtocolGuid,
+                  (VOID **) &PciIo,
+                  This->DriverBindingHandle,
+                  Controller,
+                  EFI_OPEN_PROTOCOL_BY_DRIVER
+                  );
+  if (EFI_ERROR (Status)) {
+    goto Exit;
+  }
+
+  //
+  // Enable the MMC Host Controller MMIO space
+  //
+  Status = PciIo->Attributes (
+                    PciIo,
+                    EfiPciIoAttributeOperationEnable,
+                    EFI_PCI_DEVICE_ENABLE,
+                    NULL
+                    );
+  if (EFI_ERROR (Status)) {
+    Status = EFI_OUT_OF_RESOURCES;
+    goto Exit;
+  }
+
+
+  MmcHostData = (MMCHOST_DATA *) AllocateZeroPool (sizeof (MMCHOST_DATA));
+  if (MmcHostData == NULL) {
+    Status =  EFI_OUT_OF_RESOURCES;
+    goto Exit;
+  }
+
+  MmcHostData->Signature   = MMCHOST_DATA_SIGNATURE;
+  MmcHostData->PciIo       = PciIo;
+
+  CopyMem (&MmcHostData->MmcHostIo, &mMmcHostIo, sizeof (EFI_MMC_HOST_IO_PROTOCOL));
+
+  Status = PciIo->Pci.Read (
+                        PciIo,
+                        EfiPciIoWidthUint32,
+                        PCI_VENDOR_ID_OFFSET,
+                        1,
+                        &VidDid
+                        );
+  if (EFI_ERROR (Status)) {
+    goto Exit;
+  }
+  DEBUG ((EFI_D_INFO, "MmcHostDriverBindingStart: VidDid = 0x%08x\n", VidDid));
+
+  Status = PciIo->GetLocation (
+                    PciIo,
+                    &Seg,
+                    &Bus,
+                    &Dev,
+                    &Func
+                    );
+  DEBUG ((EFI_D_INFO, "MmcHostDriverBindingStart: Seg %d, bus:%d,Dev:%d,Func:%d\n", Seg, Bus, Dev,Func));
+
+  MmcHostData->PciVid = (UINT16) (VidDid & 0xffff);
+  MmcHostData->PciDid = (UINT16) (VidDid >> 16);
+
+  Status = PciIo->Pci.Read (
+                        PciIo,
+                        EfiPciIoWidthUint32,
+                        PCI_BASE_ADDRESSREG_OFFSET,
+                        1,
+                        &Bar0
+                        );
+
+  Status = PciIo->Pci.Read (
+                        PciIo,
+                        EfiPciIoWidthUint32,
+                        PCI_BASE_ADDRESSREG_OFFSET + 4,
+                        1,
+                        &Bar1
+                        );
+
+  DEBUG ((EFI_D_INFO, "MmcHostDriverBindingStart: MEMIO Base0 %x\n", Bar0));
+  DEBUG ((EFI_D_INFO, "MmcHostDriverBindingStart: MEMIO Base1 %x\n", Bar1));
+
+
+  MmcHostData->MmcHostIo.ResetMmcHost (&MmcHostData->MmcHostIo, Reset_All);
+  MmcHostData->EnableVerboseDebug = FALSE;
+
+  PciIo->Mem.Read (
+               PciIo,
+               EfiPciIoWidthUint16,
+               0,
+               (UINT64) MMIO_CTRLRVER,
+               1,
+               &Data16
+               );
+
+  DEBUG ((EFI_D_INFO, "MmcHostDriverBindingStart: MMIO_CTRLRVER = 0x%08x\n", Data16));
+
+  MmcHostData->ControllerVersion = Data16 & 0xFF;
+  switch (MmcHostData->ControllerVersion) {
+    case 0: DEBUG ((EFI_D_INFO, "MmcHostDriverBindingStart: MMC Host Controller Version 1.0\n")); break;
+    case 1: DEBUG ((EFI_D_INFO, "MmcHostDriverBindingStart: MMC Host Controller Version 2.0\n")); break;
+    case 2: DEBUG ((EFI_D_INFO, "MmcHostDriverBindingStart: MMC Host Controller Version 3.0\n")); break;
+    default:
+      DEBUG ((EFI_D_INFO, "MmcHostDriverBindingStart: Unknown MMC Host Controller Version, Stopping Driver!!\n"));
+      goto Exit;
+  }
+
+  PciIo->Mem.Read (
+               PciIo,
+               EfiPciIoWidthUint32,
+               0,
+               (UINT32) MMIO_CAP,
+               1,
+               &Data
+               );
+  DEBUG ((EFI_D_INFO, "MmcHostDriverBindingStart: Low MMIO_CAP = 0x%08x\n", Data));
+
+  if ((Data & BIT18) != 0) {
+    MmcHostData->MmcHostIo.HostCapability.BusWidth8 = TRUE;
+    DEBUG ((EFI_D_INFO, "MmcHostDriverBindingStart: BusWidth8\n"));
+  }
+
+  MmcHostData->MmcHostIo.HostCapability.BusWidth4 = TRUE;
+  DEBUG ((EFI_D_INFO, "MmcHostDriverBindingStart: BusWidth4\n"));
+
+  if ((Data & BIT19) != 0) {
+    MmcHostData->MmcHostIo.HostCapability.ADMA2Support = TRUE;
+    DEBUG ((EFI_D_INFO, "MmcHostDriverBindingStart: ADMA2Support\n"));
+  }
+
+  if ((Data & BIT21) != 0) {
+    MmcHostData->MmcHostIo.HostCapability.HighSpeedSupport = TRUE;
+    DEBUG ((EFI_D_INFO, "MmcHostDriverBindingStart: HighSpeedSupport\n"));
+  }
+
+  if ((Data & BIT22) != 0) {
+    MmcHostData->MmcHostIo.HostCapability.SDMASupport = TRUE;
+    DEBUG ((EFI_D_INFO, "MmcHostDriverBindingStart: SDMASupport\n"));
+  }
+
+  if ((Data & BIT24) != 0) {
+    MmcHostData->MmcHostIo.HostCapability.V33Support = TRUE;
+    DEBUG ((EFI_D_INFO, "MmcHostDriverBindingStart: V33Support\n"));
+  }
+
+  if ((Data & BIT25) != 0) {
+    MmcHostData->MmcHostIo.HostCapability.V30Support = TRUE;
+    DEBUG ((EFI_D_INFO, "MmcHostDriverBindingStart: V30Support\n"));
+  }
+
+  if ((Data & BIT26) != 0) {
+    MmcHostData->MmcHostIo.HostCapability.V18Support = TRUE;
+    DEBUG ((EFI_D_INFO, "MmcHostDriverBindingStart: V18Support\n"));
+  }
+
+  if (((Data) & (BIT30 | BIT31)) == 0) {
+    DEBUG ((EFI_D_INFO, "MmcHostDriverBindingStart: Removable Card Slot\n"));
+  } else if ((Data & BIT30) && (Data & (~BIT31))) {
+    DEBUG ((EFI_D_INFO, "MmcHostDriverBindingStart: Embedded Slot for One Device\n"));
+  }
+  MmcHostData->BaseClockInMHz = (Data >> 8) & 0xFF;
+
+  PciIo->Mem.Read (
+               PciIo,
+               EfiPciIoWidthUint32,
+               0,
+               (UINT32) (MMIO_CAP + 4),
+               1,
+               &Data
+               );
+
+  DEBUG ((EFI_D_INFO, "MmcHostDriverBindingStart: High MMIO_CAP = 0x%08x\n", Data));
+
+
+
+  if ((Data & 0x1<<(32-32)) != 0) {
+    MmcHostData->MmcHostIo.HostCapability.SDR50Support= TRUE;
+    DEBUG ((EFI_D_INFO, "MmcHostDriverBindingStart: SDR50Support\n"));
+  }
+
+  if ((Data & 0x1<<(33-32)) != 0) {
+    MmcHostData->MmcHostIo.HostCapability.SDR104Support= TRUE;
+    DEBUG ((EFI_D_INFO, "MmcHostDriverBindingStart: SDR104Support\n"));
+  }
+
+  if ((Data & 0x1<<(34-32)) != 0) {
+    MmcHostData->MmcHostIo.HostCapability.DDR50Support= TRUE;
+    DEBUG ((EFI_D_INFO, "MmcHostDriverBindingStart: DDR50Support\n"));
+  }
+
+  if ((Data & 0x1<<(63-32)) != 0) {
+    MmcHostData->MmcHostIo.HostCapability.HS400Support = TRUE;
+    DEBUG ((EFI_D_INFO, "MmcHostDriverBindingStart: HS400Support\n"));
+  }
+
+  if (MmcHostData->ControllerVersion >= 2) {
+    MmcHostData->MmcHostIo.HostCapability.ReTuneMode = (Data >> (46-32)) & 0x3;
+    DEBUG ((EFI_D_INFO, "MmcHostDriverBindingStart:  ReTuneMode = 0x%08x\n", MmcHostData->MmcHostIo.HostCapability.ReTuneMode));
+
+    MmcHostData->MmcHostIo.HostCapability.ReTuneTimer = (Data>>(40-32)) & 0xF;
+    DEBUG ((EFI_D_INFO, "MmcHostDriverBindingStart:  ReTuneTimer = 0x%08x\n", MmcHostData->MmcHostIo.HostCapability.ReTuneTimer));
+  }
+
+
+  MmcHostData->BlockLength    = BLOCK_SIZE;
+  MmcHostData->IsAutoStopCmd  = TRUE;
+
+  Status = gBS->InstallProtocolInterface (
+                  &Controller,
+                  &gEfiMmcHostIoProtocolGuid,
+                  EFI_NATIVE_INTERFACE,
+                  &MmcHostData->MmcHostIo
+                  );
+  if (EFI_ERROR (Status)) {
+    goto Exit;
+  }
+
+  //
+  // Component name protocol
+  //
+  Status = AddUnicodeString (
+             "eng",
+             gMmcHostComponentName.SupportedLanguages,
+             &MmcHostData->ControllerNameTable,
+             L"MMC Host Controller"
+             );
+  if (EFI_ERROR (Status)) {
+    Status = EFI_OUT_OF_RESOURCES;
+    gBS->UninstallProtocolInterface (
+           Controller,
+           &gEfiMmcHostIoProtocolGuid,
+           &MmcHostData->MmcHostIo
+           );
+  }
+
+  DEBUG ((EFI_D_INFO, "MmcHostDriverBindingStart: Host Started\n"));
+
+Exit:
+  if (EFI_ERROR (Status)) {
+    if (MmcHostData != NULL) {
+      FreePool (MmcHostData);
+    }
+    gBS->CloseProtocol (
+           Controller,
+           &gEfiPciIoProtocolGuid,
+           This->DriverBindingHandle,
+           Controller
+           );
+  }
+  return Status;
+}
+
+
+/**
+  Stop MMC Host driver on ControllerHandle. Support stoping any child handles
+  created by this driver.
+
+  @param[in] This                  Protocol instance pointer
+  @param[in] Controller            Handle of device to stop driver on
+  @param[in] NumberOfChildren      Number of Children in the ChildHandleBuffer
+  @param[in] ChildHandleBuffer     List of handles for the children we need to stop
+
+  @retval    EFI_SUCCESS           This driver stop this device
+  @retval    EFI_DEVICE_ERROR      This driver cannot be stop due to device Error
+
+**/
+EFI_STATUS
+EFIAPI
+MmcHostDriverBindingStop (
+  IN  EFI_DRIVER_BINDING_PROTOCOL     *This,
+  IN  EFI_HANDLE                      Controller,
+  IN  UINTN                           NumberOfChildren,
+  IN  EFI_HANDLE                      *ChildHandleBuffer
+  )
+{
+  EFI_STATUS                          Status;
+  EFI_MMC_HOST_IO_PROTOCOL            *MmcHostIo;
+  MMCHOST_DATA                        *MmcHostData;
+
+  Status = gBS->OpenProtocol (
+                  Controller,
+                  &gEfiMmcHostIoProtocolGuid,
+                  (VOID **) &MmcHostIo,
+                  This->DriverBindingHandle,
+                  Controller,
+                  EFI_OPEN_PROTOCOL_GET_PROTOCOL
+                  );
+  if (EFI_ERROR (Status)) {
+    goto _exit_MmcHostDriverBindingStop;
+  }
+
+  gBS->CloseProtocol (
+         Controller,
+         &gEfiPciIoProtocolGuid,
+         This->DriverBindingHandle,
+         Controller
+         );
+
+  MmcHostData  = MMCHOST_DATA_FROM_THIS (MmcHostIo);
+
+  //
+  // Uninstall Block I/O protocol from the device handle
+  //
+  Status = gBS->UninstallProtocolInterface (
+                  Controller,
+                  &gEfiMmcHostIoProtocolGuid,
+                  &MmcHostData->MmcHostIo
+                  );
+  if (EFI_ERROR (Status)) {
+    goto _exit_MmcHostDriverBindingStop;
+  }
+
+  FreeUnicodeStringTable (MmcHostData->ControllerNameTable);
+  FreePool (MmcHostData);
+
+_exit_MmcHostDriverBindingStop:
+  DEBUG ((EFI_D_INFO, "MmcHostDriverBindingStop exited with Status %r\n", Status));
+
+  return Status;
+}
+
diff --git a/Silicon/BroxtonSoC/BroxtonSiPkg/SouthCluster/Sdio/Dxe/MMC/MmcHostDxe/MmcHostDriver.h b/Silicon/BroxtonSoC/BroxtonSiPkg/SouthCluster/Sdio/Dxe/MMC/MmcHostDxe/MmcHostDriver.h
new file mode 100644
index 0000000..f724061
--- /dev/null
+++ b/Silicon/BroxtonSoC/BroxtonSiPkg/SouthCluster/Sdio/Dxe/MMC/MmcHostDxe/MmcHostDriver.h
@@ -0,0 +1,585 @@
+/** @file
+  Header file for MMC driver.
+
+  Copyright (c) 1999 - 2016, Intel Corporation. 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 _MMC_HOST_DRIVER_H
+#define _MMC_HOST_DRIVER_H
+
+#include <Uefi.h>
+#include <Library/UefiDriverEntryPoint.h>
+#include <Library/DebugLib.h>
+#include <Library/UefiBootServicesTableLib.h>
+#include <Library/BaseMemoryLib.h>
+#include <Library/MemoryAllocationLib.h>
+#include <Library/UefiLib.h>
+#include <Library/DevicePathLib.h>
+#include <Library/IoLib.h>
+#include <IndustryStandard/Pci.h>
+#include <IndustryStandard/SdCard.h>
+#include <ScAccess.h>
+
+//
+// Driver Consumed Protocol Prototypes
+//
+#include <Protocol/DevicePath.h>
+#include <Protocol/PciIo.h>
+
+//
+// Driver Produced Protocol Prototypes
+//
+#include <Protocol/DriverBinding.h>
+#include <Protocol/ComponentName.h>
+#include <Protocol/ComponentName2.h>
+#include <Protocol/MmcHostIo.h>
+
+extern EFI_COMPONENT_NAME_PROTOCOL  gMmcHostComponentName;
+extern EFI_DRIVER_BINDING_PROTOCOL  gMmcHostDriverBinding;
+
+#define MMCHOST_DATA_SIGNATURE  SIGNATURE_32 ('m', 'c', 'h', 's')
+
+#define MMCHOST_DATA_FROM_THIS(a) \
+    CR (a, MMCHOST_DATA, MmcHostIo, MMCHOST_DATA_SIGNATURE)
+
+#define BLOCK_SIZE          0x200
+#define TIME_OUT_1S         1000
+
+#define INTEL_VENDOR_ID     0x8086
+
+#define BUFFER_CTL_REGISTER 0x84
+
+#pragma pack(1)
+//
+// PCI Class Code structure
+//
+typedef struct {
+  UINT8 PI;
+  UINT8 SubClassCode;
+  UINT8 BaseCode;
+} PCI_CLASSC;
+
+#pragma pack()
+
+//
+// MMCHOST_DATA structure
+//
+typedef struct {
+  UINTN                      Signature;
+  EFI_MMC_HOST_IO_PROTOCOL   MmcHostIo;
+  EFI_PCI_IO_PROTOCOL        *PciIo;
+  UINT16                     PciVid;
+  UINT16                     PciDid;
+  BOOLEAN                    IsAutoStopCmd;
+  BOOLEAN                    IsEmmc;
+  BOOLEAN                    EnableVerboseDebug;
+  UINT32                     BaseClockInMHz;
+  UINT32                     CurrentClockInKHz;
+  UINT32                     BlockLength;
+  EFI_UNICODE_STRING_TABLE   *ControllerNameTable;
+  UINT32                     ControllerVersion;
+} MMCHOST_DATA;
+
+//
+// Prototypes
+// Driver model protocol interface
+//
+/**
+  Entry point for MMC Host EFI drivers.
+
+  @param[in] ImageHandle               EFI_HANDLE
+  @param[in] SystemTable               EFI_SYSTEM_TABLE
+
+  @retval    EFI_SUCCESS               The function completed successfully
+  @retval    EFI_DEVICE_ERROR          The function failed to complete
+
+**/
+EFI_STATUS
+EFIAPI
+MmcHostDriverEntryPoint (
+  IN EFI_HANDLE           ImageHandle,
+  IN EFI_SYSTEM_TABLE     *SystemTable
+  );
+
+/**
+  Test to see if this MMC Host driver supports ControllerHandle.
+  Any ControllerHandle that has installed will be supported.
+
+  @param[in] This                  Protocol instance pointer
+  @param[in] Controller            Handle of device to test
+  @param[in] RemainingDevicePath   Not used
+
+  @retval    EFI_SUCCESS           This driver supports this device
+  @retval    EFI_UNSUPPORTED       This driver does not support this device
+
+**/
+EFI_STATUS
+EFIAPI
+MmcHostDriverBindingSupported (
+  IN EFI_DRIVER_BINDING_PROTOCOL     *This,
+  IN EFI_HANDLE                      Controller,
+  IN EFI_DEVICE_PATH_PROTOCOL        *RemainingDevicePath
+  );
+
+/**
+  Starting the MMC Host Driver
+
+  @param[in] This                     Protocol instance pointer
+  @param[in] Controller               Handle of device to start
+  @param[in] RemainingDevicePath      Not used
+
+  @retval    EFI_SUCCESS              This driver start this device
+  @retval    EFI_UNSUPPORTED          This driver does not support this device
+  @retval    EFI_DEVICE_ERROR         This driver cannot be started due to device Error
+  @retval    EFI_OUT_OF_RESOURCES     This driver cannot allocate resources
+
+**/
+EFI_STATUS
+EFIAPI
+MmcHostDriverBindingStart (
+  IN EFI_DRIVER_BINDING_PROTOCOL      *This,
+  IN EFI_HANDLE                       Controller,
+  IN EFI_DEVICE_PATH_PROTOCOL         *RemainingDevicePath
+  );
+
+/**
+  Stop MMC Host driver on ControllerHandle. Support stopping any child handles
+  created by this driver.
+
+  @param[in] This                     Protocol instance pointer
+  @param[in] Controller               Handle of device to stop driver on
+  @param[in] NumberOfChildren         Number of Children in the ChildHandleBuffer
+  @param[in] ChildHandleBuffer        List of handles for the children we need to stop
+
+  @retval    EFI_SUCCESS              This driver stop this device
+  @retval    EFI_DEVICE_ERROR         This driver cannot be stop due to device Error
+
+**/
+EFI_STATUS
+EFIAPI
+MmcHostDriverBindingStop (
+  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 EFI Driver.
+
+  @param[in]  This                    A pointer to the EFI_COMPONENT_NAME_PROTOCOL instance.
+  @param[in]  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[out] DriverName              A pointer to the Unicode string to return.  This Unicode string
+                                      is the name of the driver specified by This in the language
+                                      specified by Language.
+
+
+  @retval     EFI_SUCCESS             The Unicode string for the Driver specified by This
+                                      and the language specified by Language was returned
+                                      in DriverName.
+  @retval     EFI_INVALID_PARAMETER   Language is NULL.
+  @retval     EFI_INVALID_PARAMETER   DriverName is NULL.
+  @retval     EFI_UNSUPPORTED         The driver specified by This does not support the
+                                      language specified by Language.
+
+**/
+EFI_STATUS
+EFIAPI
+MmcHostComponentNameGetDriverName (
+  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 an EFI Driver.
+
+  @param[in]  This                    A pointer to the EFI_COMPONENT_NAME_PROTOCOL instance.
+  @param[in]  ControllerHandle        The handle of a controller that the driver specified by
+                                      This is managing.  This handle specifies the controller
+                                      whose name is to be returned.
+  @param[in]  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[in]  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[out] ControllerName          A pointer to the Unicode string to return.  This Unicode
+                                      string is the name of the controller specified by
+                                      ControllerHandle and ChildHandle in the language
+                                      specified by Language from the point of view of the
+                                      driver specified by This.
+
+
+  @retval     EFI_SUCCESS             The Unicode string for the user readable name in the
+                                      language specified by Language for the driver
+                                      specified by This was returned in DriverName.
+  @retval     EFI_INVALID_PARAMETER   ControllerHandle is not a valid EFI_HANDLE.
+  @retval     EFI_INVALID_PARAMETER   ChildHandle is not NULL and it is not a valid
+                                      EFI_HANDLE.
+  @retval     EFI_INVALID_PARAMETER   Language is NULL.
+  @retval     EFI_INVALID_PARAMETER   ControllerName is NULL.
+  @retval     EFI_UNSUPPORTED         The driver specified by This is not currently
+                                      managing the controller specified by
+                                      ControllerHandle and ChildHandle.
+  @retval     EFI_UNSUPPORTED         The driver specified by This does not support the
+                                      language specified by Language.
+
+**/
+EFI_STATUS
+EFIAPI
+MmcHostComponentNameGetControllerName (
+  IN  EFI_COMPONENT_NAME_PROTOCOL     *This,
+  IN  EFI_HANDLE                      ControllerHandle,
+  IN  EFI_HANDLE                      ChildHandle, OPTIONAL
+  IN  CHAR8                           *Language,
+  OUT CHAR16                          **ControllerName
+  );
+
+/**
+  The main function used to send the command to the card inserted into the MMC host
+  slot.
+  It will assemble the arguments to set the command register and wait for the command
+  and transfer completed until timeout. Then it will read the response register to fill
+  the ResponseData
+
+  @param[in]  This                      Pointer to the EFI_COMPONENT_NAME_PROTOCOL instance.
+  @param[in]  CommandIndex              The command index to set the command index field of command register
+  @param[in]  Argument                  Command argument to set the argument field of command register
+  @param[in]  DataType                  TRANSFER_TYPE, indicates no data, data in or data out
+  @param[in]  Buffer                    Contains the data read from / write to the device
+  @param[in]  BufferSize                The size of the buffer
+  @param[in]  ResponseType              RESPONSE_TYPE
+  @param[in]  TimeOut                   Time out value in 1 ms unit
+  @param[out] ResponseData              Depending on the ResponseType, such as CSD or card status
+
+  @retval     EFI_SUCCESS
+  @retval     EFI_INVALID_PARAMETER
+  @retval     EFI_OUT_OF_RESOURCES
+  @retval     EFI_TIMEOUT
+  @retval     EFI_DEVICE_ERROR
+
+**/
+EFI_STATUS
+EFIAPI
+SendCommand (
+  IN   EFI_MMC_HOST_IO_PROTOCOL   *This,
+  IN   UINT16                     CommandIndex,
+  IN   UINT32                     Argument,
+  IN   TRANSFER_TYPE              DataType,
+  IN   UINT8                      *Buffer, OPTIONAL
+  IN   UINT32                     BufferSize,
+  IN   RESPONSE_TYPE              ResponseType,
+  IN   UINT32                     TimeOut,
+  OUT  UINT32                     *ResponseData OPTIONAL
+  );
+
+/**
+  Set max clock frequency of the host, the actual frequency
+  may not be the same as MaxFrequencyInKHz. It depends on
+  the max frequency the host can support, divider, and host
+  speed mode.
+
+  @param[in]  This               Pointer to EFI_MMC_HOST_IO_PROTOCOL
+  @param[in]  MaxFrequency       Max frequency in HZ
+
+  @retval     EFI_SUCCESS
+  @retval     EFI_TIMEOUT
+**/
+EFI_STATUS
+EFIAPI
+SetClockFrequency (
+  IN  EFI_MMC_HOST_IO_PROTOCOL   *This,
+  IN  UINT32                     MaxFrequencyInKHz
+  );
+
+/**
+  Set bus width of the host
+
+  @param[in]  This                  Pointer to EFI_MMC_HOST_IO_PROTOCOL
+  @param[in]  BusWidth              Bus width in 1, 4, 8 bits
+
+
+  @retval     EFI_STATUS
+  @retval     EFI_INVALID_PARAMETER
+
+**/
+EFI_STATUS
+EFIAPI
+SetBusWidth (
+  IN  EFI_MMC_HOST_IO_PROTOCOL   *This,
+  IN  UINT32                     BusWidth
+  );
+
+/**
+  Set voltage which could supported by the host.
+  Support 0(Power off the host), 1.8V, 3.0V, 3.3V
+
+  @param[in]  This                   Pointer to EFI_MMC_HOST_IO_PROTOCOL
+  @param[in]  Voltage                Units in 0.1 V
+
+  @retval     EFI_SUCCESS
+  @retval     EFI_INVALID_PARAMETER
+
+**/
+EFI_STATUS
+EFIAPI
+SetHostVoltage (
+  IN  EFI_MMC_HOST_IO_PROTOCOL   *This,
+  IN  UINT32                     Voltage
+  );
+
+/**
+  Set Host mode in DDR
+
+  @param[in]  This              Pointer to EFI_MMC_HOST_IO_PROTOCOL
+  @param[in]  DdrMode           True for DDR Mode set, false returns EFI_SUCCESS
+
+  @retval     EFI_SUCCESS
+  @retval     EFI_INVALID_PARAMETER
+
+**/
+EFI_STATUS
+EFIAPI
+SetHostDdrMode (
+  IN  EFI_MMC_HOST_IO_PROTOCOL   *This,
+  IN UINT32                      DdrMode
+  );
+
+/**
+  Set Host SDR Mode
+
+  @param[in] This                     Pointer to EFI_MMC_HOST_IO_PROTOCOL
+  @param[in] DdrMode                  True for SDR Mode set, false for normal mode
+
+  @retval    EFI_SUCCESS              The function completed successfully
+  @retval    EFI_INVALID_PARAMETER    A parameter was incorrect.
+
+**/
+EFI_STATUS
+EFIAPI
+SetHostSdrMode (
+  IN  EFI_MMC_HOST_IO_PROTOCOL   *This,
+  IN UINT32                      SdrMode
+  );
+
+/**
+  Set Host High Speed
+
+  @param[in] This                     Pointer to EFI_MMC_HOST_IO_PROTOCOL
+  @param[in] HighSpeed                True for High Speed Mode set, false for normal mode
+
+  @retval    EFI_SUCCESS              The function completed successfully
+  @retval    EFI_INVALID_PARAMETER    A parameter was incorrect.
+
+**/
+EFI_STATUS
+EFIAPI
+SetHostSpeedMode (
+  IN  EFI_MMC_HOST_IO_PROTOCOL   *This,
+  IN  UINT32                     HighSpeed
+  );
+
+/**
+  Reset the host
+
+  @param[in] This                    Pointer to EFI_MMC_HOST_IO_PROTOCOL
+  @param[in] ResetAll                TRUE to reset all
+
+  @retval    EFI_SUCCESS             The function completed successfully
+  @retval    EFI_TIMEOUT             The timeout time expired.
+
+**/
+EFI_STATUS
+EFIAPI
+ResetMmcHost (
+  IN  EFI_MMC_HOST_IO_PROTOCOL   *This,
+  IN  RESET_TYPE                 ResetType
+  );
+
+/**
+  Reset the host
+
+  @param[in] This                    Pointer to EFI_MMC_HOST_IO_PROTOCOL
+  @param[in] ResetAll                TRUE to reset all
+
+  @retval    EFI_SUCCESS             The function completed successfully
+  @retval    EFI_TIMEOUT             The timeout time expired.
+
+**/
+EFI_STATUS
+EFIAPI
+EnableAutoStopCmd (
+  IN  EFI_MMC_HOST_IO_PROTOCOL       *This,
+  IN  BOOLEAN                        Enable
+  );
+
+/**
+  Find whether these is a card inserted into the slot. If so
+  init the host. If not, return EFI_NOT_FOUND.
+
+  @param[in]  This                 Pointer to EFI_MMC_HOST_IO_PROTOCOL
+
+  @retval     EFI_SUCCESS          Success
+  @retval     EFI_DEVICE_ERROR     Fail
+
+**/
+EFI_STATUS
+EFIAPI
+DetectCardAndInitHost (
+  IN  EFI_MMC_HOST_IO_PROTOCOL    *This
+  );
+
+/**
+  Set the Block length
+
+  @param[in]  This                Pointer to EFI_MMC_HOST_IO_PROTOCOL
+  @param[in]  BlockLength         card supports block length
+
+  @retval     EFI_SUCCESS         Success
+  @retval     EFI_DEVICE_ERROR    Fail
+
+**/
+EFI_STATUS
+EFIAPI
+SetBlockLength (
+  IN  EFI_MMC_HOST_IO_PROTOCOL   *This,
+  IN  UINT32                     BlockLength
+  );
+
+/**
+  Setup Device
+
+  @param[in]  This                 Pointer to EFI_MMC_HOST_IO_PROTOCOL
+
+  @retval     EFI_SUCCESS          Success
+  @retval     EFI_DEVICE_ERROR     Fail
+
+**/
+EFI_STATUS
+EFIAPI
+SetupDevice(
+  IN  EFI_MMC_HOST_IO_PROTOCOL    *This
+  );
+
+/**
+  Read MMC host register
+
+  @param[in]  MmcHost                Pointer to EFI_MMC_HOST_IO_PROTOCOL
+  @param[in]  Offset                 Offset of the eMMC
+
+  @retval     Data                   Data read from eMMC
+
+**/
+UINT8
+MmcHostRead8 (
+  IN     MMCHOST_DATA                 *MmcHost,
+  IN     UINTN                        Offset
+  );
+
+/**
+  Read MMC host register
+
+  @param[in]  MmcHost       Pointer to EFI_MMC_HOST_IO_PROTOCOL
+  @param[in]  Offset        Offset of the eMMC
+
+  @retval     Data          Data read from eMMC
+
+**/
+UINT16
+MmcHostRead16 (
+  IN     MMCHOST_DATA        *MmcHost,
+  IN     UINTN               Offset
+  );
+
+/**
+  Read MMC host register
+
+  @param[in]  MmcHost        Pointer to EFI_MMC_HOST_IO_PROTOCOL
+  @param[in]  Offset         Offset of the eMMC
+
+  @retval     Data           Data read from eMMC
+
+**/
+UINT32
+MmcHostRead32 (
+  IN     MMCHOST_DATA                 *MmcHost,
+  IN     UINTN                        Offset
+  );
+
+/**
+  Write MMC host register
+
+  @param[in]  MmcHost    Pointer to EFI_MMC_HOST_IO_PROTOCOL
+  @param[in]  Offset     Offset of the eMMC
+  @param[in]  Data       Data write to eMMC
+
+  @retval     Data       Written to MmcHost
+
+**/
+UINT8
+MmcHostWrite8 (
+  IN     MMCHOST_DATA    *MmcHost,
+  IN     UINTN           Offset,
+  IN     UINT8           Data
+  );
+
+/**
+  Write MMC host register
+
+  @param[in]  MmcHost    Pointer to EFI_MMC_HOST_IO_PROTOCOL
+  @param[in]  Offset     Offset of the eMMC
+  @param[in]  Data       Data write to eMMC
+
+  @retval     Data       Data written to eMMC
+
+**/
+UINT16
+MmcHostWrite16 (
+  IN     MMCHOST_DATA    *MmcHost,
+  IN     UINTN           Offset,
+  IN     UINT16          Data
+  );
+
+/**
+  Write MMC host register
+
+  @param[in]  MmcHost        Pointer to EFI_MMC_HOST_IO_PROTOCOL
+  @param[in]  Offset         Offset of the eMMC
+  @param[in]  Data           Data write to eMMC
+
+  @retval     Data           Data written to eMMC
+
+**/
+UINT32
+MmcHostWrite32 (
+  IN     MMCHOST_DATA        *MmcHost,
+  IN     UINTN               Offset,
+  IN     UINT32              Data
+  );
+
+#endif
+
diff --git a/Silicon/BroxtonSoC/BroxtonSiPkg/SouthCluster/Sdio/Dxe/MMC/MmcHostDxe/MmcHostDxe.inf b/Silicon/BroxtonSoC/BroxtonSiPkg/SouthCluster/Sdio/Dxe/MMC/MmcHostDxe/MmcHostDxe.inf
new file mode 100644
index 0000000..0433019
--- /dev/null
+++ b/Silicon/BroxtonSoC/BroxtonSiPkg/SouthCluster/Sdio/Dxe/MMC/MmcHostDxe/MmcHostDxe.inf
@@ -0,0 +1,59 @@
+## @file
+#  MMC Host module
+#
+#  Copyright (c) 1999 - 2016, Intel Corporation. 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                    = 0x00010005
+  BASE_NAME                      = MmcHost
+  FILE_GUID                      = D86DB3C5-57FE-44CF-A82A-74C4AD5B1C2E
+  MODULE_TYPE                    = UEFI_DRIVER
+  VERSION_STRING                 = 1.0
+  ENTRY_POINT                    = MmcHostDriverEntryPoint
+
+#
+# The following information is for reference only and not required by the build tools.
+#
+#  VALID_ARCHITECTURES           = IA32 X64 IPF EBC
+#
+
+[Sources.common]
+  ComponentName.c
+  MmcHostDriver.h
+  MmcHostDriver.c
+  MmcHostController.c
+
+[Packages]
+  MdePkg/MdePkg.dec
+  BroxtonSiPkg/BroxtonSiPkg.dec
+
+[LibraryClasses]
+  UefiDriverEntryPoint
+  DebugLib
+  UefiBootServicesTableLib
+  BaseMemoryLib
+  MemoryAllocationLib
+  UefiLib
+  DevicePathLib
+  IoLib
+  PcdLib
+  HobLib
+
+[Protocols]
+  gEfiPciIoProtocolGuid      ## CONSUMES
+  gEfiMmcHostIoProtocolGuid  ## BY_START
+
+[Guids]
+  gEfiBootMediaHobGuid       ## UNDEFINED
+
+[Pcd]
diff --git a/Silicon/BroxtonSoC/BroxtonSiPkg/SouthCluster/Sdio/Dxe/MMC/MmcMediaDeviceDxe/ComponentName.c b/Silicon/BroxtonSoC/BroxtonSiPkg/SouthCluster/Sdio/Dxe/MMC/MmcMediaDeviceDxe/ComponentName.c
new file mode 100644
index 0000000..a0b0940
--- /dev/null
+++ b/Silicon/BroxtonSoC/BroxtonSiPkg/SouthCluster/Sdio/Dxe/MMC/MmcMediaDeviceDxe/ComponentName.c
@@ -0,0 +1,159 @@
+/** @file
+  Header file for ComponentName.
+
+  Copyright (c) 1999 - 2016, Intel Corporation. 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 <MediaDeviceDriver.h>
+
+//
+// EFI Component Name Protocol
+//
+EFI_COMPONENT_NAME_PROTOCOL     gMediaDeviceComponentName = {
+  MediaDeviceComponentNameGetDriverName,
+  MediaDeviceComponentNameGetControllerName,
+  "eng"
+};
+
+
+static EFI_UNICODE_STRING_TABLE mMediaDeviceDriverNameTable[] = {
+  { "eng", L"UEFI MMC/SD Media Device Driver" },
+  { NULL , NULL }
+};
+
+
+/**
+  Retrieves a Unicode string that is the user readable name of the EFI Driver.
+
+  @param[in]   This                   A pointer to the EFI_COMPONENT_NAME_PROTOCOL instance.
+  @param[in]   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[out]  DriverName             A pointer to the Unicode string to return.  This Unicode string
+                                      is the name of the driver specified by This in the language
+                                      specified by Language.
+
+  @retval      EFI_SUCCESS             The Unicode string for the Driver specified by This
+                                       and the language specified by Language was returned
+                                       in DriverName.
+  @retval      EFI_INVALID_PARAMETER   Language is NULL.
+  @retval      EFI_INVALID_PARAMETER   DriverName is NULL.
+  @retval      EFI_UNSUPPORTED         The driver specified by This does not support the
+                                       language specified by Language.
+
+**/
+EFI_STATUS
+EFIAPI
+MediaDeviceComponentNameGetDriverName (
+  IN  EFI_COMPONENT_NAME_PROTOCOL     *This,
+  IN  CHAR8                           *Language,
+  OUT CHAR16                          **DriverName
+  )
+{
+  return LookupUnicodeString (
+           Language,
+           gMediaDeviceComponentName.SupportedLanguages,
+           mMediaDeviceDriverNameTable,
+           DriverName
+           );
+}
+
+
+/**
+  Retrieves a Unicode string that is the user readable name of the controller
+  that is being managed by an EFI Driver.
+
+  @param[in]   This                   A pointer to the EFI_COMPONENT_NAME_PROTOCOL instance.
+  @param[in]   ControllerHandle       The handle of a controller that the driver specified by
+                                      This is managing.  This handle specifies the controller
+                                      whose name is to be returned.
+  @param[in]   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[in]  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[out] ControllerName         A pointer to the Unicode string to return.  This Unicode
+                                      string is the name of the controller specified by
+                                      ControllerHandle and ChildHandle in the language
+                                      specified by Language from the point of view of the
+                                      driver specified by This.
+
+  @retval     EFI_SUCCESS             The Unicode string for the user readable name in the
+                                      language specified by Language for the driver
+                                      specified by This was returned in DriverName.
+  @retval     EFI_INVALID_PARAMETER   ControllerHandle is not a valid EFI_HANDLE.
+  @retval     EFI_INVALID_PARAMETER   ChildHandle is not NULL and it is not a valid
+                                      EFI_HANDLE.
+  @retval     EFI_INVALID_PARAMETER   Language is NULL.
+  @retval     EFI_INVALID_PARAMETER   ControllerName is NULL.
+  @retval     EFI_UNSUPPORTED         The driver specified by This is not currently
+                                      managing the controller specified by
+                                      ControllerHandle and ChildHandle.
+  @retval     EFI_UNSUPPORTED         The driver specified by This does not support the
+                                      language specified by Language.
+
+**/
+EFI_STATUS
+EFIAPI
+MediaDeviceComponentNameGetControllerName (
+  IN  EFI_COMPONENT_NAME_PROTOCOL     *This,
+  IN  EFI_HANDLE                      ControllerHandle,
+  IN  EFI_HANDLE                      ChildHandle, OPTIONAL
+  IN  CHAR8                           *Language,
+  OUT CHAR16                          **ControllerName
+  )
+{
+  EFI_STATUS               Status;
+  EFI_BLOCK_IO_PROTOCOL    *BlockIo;
+  CARD_DATA                *CardData;
+
+  //
+  // This is a device driver, so ChildHandle must be NULL.
+  //
+  if (ChildHandle != NULL) {
+    return EFI_UNSUPPORTED;
+  }
+
+  //
+  // Get the device context
+  //
+  Status = gBS->OpenProtocol (
+                  ControllerHandle,
+                  &gEfiBlockIoProtocolGuid,
+                  (VOID **) &BlockIo,
+                  gMediaDeviceDriverBinding.DriverBindingHandle,
+                  ControllerHandle,
+                  EFI_OPEN_PROTOCOL_GET_PROTOCOL
+                  );
+
+  if (EFI_ERROR (Status)) {
+    return Status;
+  }
+
+  CardData  = CARD_DATA_FROM_THIS (BlockIo);
+  return LookupUnicodeString (
+           Language,
+           gMediaDeviceComponentName.SupportedLanguages,
+           CardData->ControllerNameTable,
+           ControllerName
+           );
+}
+
diff --git a/Silicon/BroxtonSoC/BroxtonSiPkg/SouthCluster/Sdio/Dxe/MMC/MmcMediaDeviceDxe/MMCSDBlockIo.c b/Silicon/BroxtonSoC/BroxtonSiPkg/SouthCluster/Sdio/Dxe/MMC/MmcMediaDeviceDxe/MMCSDBlockIo.c
new file mode 100644
index 0000000..5c91190
--- /dev/null
+++ b/Silicon/BroxtonSoC/BroxtonSiPkg/SouthCluster/Sdio/Dxe/MMC/MmcMediaDeviceDxe/MMCSDBlockIo.c
@@ -0,0 +1,666 @@
+/** @file
+  Block I/O protocol for MMC/SD device.
+
+  Copyright (c) 2012 - 2017, Intel Corporation. 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 <MediaDeviceDriver.h>
+
+
+/**
+  Implements EFI_BLOCK_IO_PROTOCOL.Reset() function.
+
+  @param[in]  This                    The EFI_BLOCK_IO_PROTOCOL instance.
+  @param[in]  ExtendedVerification    Indicates that the driver may perform a more
+                                      exhaustive verification operation of the device during reset.
+                                      (This parameter is ingored in this driver.)
+
+  @retval     EFI_INVALID_PARAMETER
+  @retval     EFI_UNSUPPORTED
+  @retval     EFI_SUCCESS
+
+**/
+EFI_STATUS
+EFIAPI
+MMCSDBlockReset (
+  IN  EFI_BLOCK_IO_PROTOCOL   *This,
+  IN  BOOLEAN                 ExtendedVerification
+  )
+{
+  CARD_DATA                   *CardData;
+  EFI_MMC_HOST_IO_PROTOCOL    *MmcHostIo;
+
+  CardData  = CARD_DATA_FROM_THIS (This);
+  MmcHostIo = CardData->MmcHostIo;
+
+  DEBUG ((EFI_D_INFO, "MMC SD Block: Resetting host\n"));
+
+  return MmcHostIo->ResetMmcHost (MmcHostIo, Reset_DAT_CMD);
+}
+
+
+/**
+  Implements EFI_BLOCK_IO_PROTOCOL.ReadBlocks() function.
+
+  @param[in]   This                    The EFI_BLOCK_IO_PROTOCOL instance.
+  @param[in]   MediaId                 The media id that the read request is for.
+  @param[in]   LBA                     The starting logical block address to read from on the device.
+  @param[in]   BufferSiz               The size of the Buffer in bytes. This must be a multiple of
+                                       the intrinsic block size of the device.
+  @param[out]  Buffer                  A pointer to the destination buffer for the data. The caller
+                                       is responsible for either having implicit or explicit ownership
+                                       of the buffer.
+
+  @retval      EFI_INVALID_PARAMETER   Parameter is error
+  @retval      EFI_SUCCESS             Success
+  @retval      EFI_DEVICE_ERROR        Hardware Error
+  @retval      EFI_NO_MEDIA            No media
+  @retval      EFI_MEDIA_CHANGED       Media Change
+  @retval      EFI_BAD_BUFFER_SIZE     Buffer size is bad
+
+**/
+EFI_STATUS
+EFIAPI
+MMCSDBlockReadBlocks (
+  IN  EFI_BLOCK_IO_PROTOCOL   *This,
+  IN  UINT32                  MediaId,
+  IN  EFI_LBA                 LBA,
+  IN  UINTN                   BufferSize,
+  OUT VOID                    *Buffer
+  )
+{
+  EFI_STATUS                  Status;
+  UINT32                      Address;
+  CARD_DATA                   *CardData;
+  EFI_MMC_HOST_IO_PROTOCOL     *MmcHostIo;
+  UINT32                      RemainingLength;
+  UINT32                      TransferLength;
+  UINT8                       *BufferPointer;
+  BOOLEAN                     SectorAddressing;
+  UINT64                      CardSize;
+  MMC_PARTITION_DATA          *Partition;
+  UINTN                       TotalBlock;
+
+  Status   = EFI_SUCCESS;
+  Partition = CARD_PARTITION_DATA_FROM_THIS (This);
+  CardData  = Partition->CardData;
+  MmcHostIo = CardData->MmcHostIo;
+
+  //
+  // Media ID has high priority that need to be verify first
+  //
+  if (MediaId != Partition->BlockIoMedia.MediaId) {
+    return EFI_MEDIA_CHANGED;
+  }
+
+  Status = MmcSelectPartition (Partition);
+  if (EFI_ERROR (Status)) {
+    return Status;
+  }
+
+  //
+  // BufferSize must be a multiple of the intrinsic block size of the device.
+  //
+  if (ModU64x32 (BufferSize,Partition->BlockIoMedia.BlockSize) != 0) {
+    return EFI_BAD_BUFFER_SIZE;
+  }
+
+  CardSize = MultU64x32 (CardData->BlockNumber, CardData->BlockLen);
+
+  if ((CardData->CardType == SdMemoryCard2High) || (CardSize >= SIZE_2GB)) {
+    SectorAddressing = TRUE;
+  } else {
+    SectorAddressing = FALSE;
+  }
+
+  if (SectorAddressing) {
+    //
+    // Sector Address
+    //
+    Address = (UINT32) DivU64x32 (MultU64x32 (LBA, Partition->BlockIoMedia.BlockSize), 512);
+  } else {
+    //
+    // Byte Address
+    //
+    Address  = (UINT32) MultU64x32 (LBA, Partition->BlockIoMedia.BlockSize);
+  }
+
+  TotalBlock = (UINTN) DivU64x32 (BufferSize, Partition->BlockIoMedia.BlockSize);
+  //
+  // Make sure the range to read is valid.
+  //
+  if (LBA + TotalBlock > Partition->BlockIoMedia.LastBlock + 1) {
+    return EFI_INVALID_PARAMETER;
+  }
+
+  if (!(Partition->BlockIoMedia.MediaPresent)) {
+    return EFI_NO_MEDIA;
+  }
+
+  if (!Buffer) {
+    Status = EFI_INVALID_PARAMETER;
+    DEBUG ((EFI_D_ERROR, "MMCSDBlockReadBlocks: Invalid parameter \n"));
+    goto Done;
+  }
+
+  if ((BufferSize % Partition->BlockIoMedia.BlockSize) != 0) {
+    Status = EFI_BAD_BUFFER_SIZE;
+    DEBUG ((EFI_D_ERROR, "MMCSDBlockReadBlocks: Bad buffer size \n"));
+    goto Done;
+  }
+
+  if (BufferSize == 0) {
+    Status = EFI_SUCCESS;
+    goto Done;
+  }
+
+  BufferPointer   = Buffer;
+  RemainingLength = (UINT32) BufferSize;
+
+  while (RemainingLength > 0) {
+    if ((BufferSize >= Partition->BlockIoMedia.BlockSize)) {
+      if (RemainingLength > MmcHostIo->HostCapability.BoundarySize) {
+        TransferLength = MmcHostIo->HostCapability.BoundarySize;
+      } else {
+        TransferLength = RemainingLength;
+      }
+
+      if (CardData->CardType == MMCCard) {
+        if (!(CardData->ExtCSDRegister.CARD_TYPE & (BIT2 | BIT3))) {
+          Status = SendCommand (
+                     MmcHostIo,
+                     SET_BLOCKLEN,
+                     Partition->BlockIoMedia.BlockSize,
+                     NoData,
+                     NULL,
+                     0,
+                     ResponseR1,
+                     TIMEOUT_COMMAND,
+                     (UINT32 *) &(CardData->CardStatus)
+                     );
+          if (EFI_ERROR (Status)) {
+            break;
+          }
+        }
+
+        Status = SendCommand (
+                   MmcHostIo,
+                   SET_BLOCK_COUNT,
+                   TransferLength / Partition->BlockIoMedia.BlockSize,
+                   NoData,
+                   NULL,
+                   0,
+                   ResponseR1,
+                   TIMEOUT_COMMAND,
+                   (UINT32 *) &(CardData->CardStatus)
+                   );
+        if (EFI_ERROR (Status)) {
+          break;
+        }
+      }
+
+      Status = SendCommand (
+                 MmcHostIo,
+                 READ_MULTIPLE_BLOCK,
+                 Address,
+                 InData,
+                 CardData->AlignedBuffer,
+                 TransferLength,
+                 ResponseR1,
+                 TIMEOUT_DATA,
+                 (UINT32 *) &(CardData->CardStatus)
+                 );
+
+      if (EFI_ERROR (Status)) {
+        DEBUG ((EFI_D_ERROR, "MMCSDBlockReadBlocks: READ_MULTIPLE_BLOCK -> Fail\n"));
+        break;
+      }
+    } else {
+      if (RemainingLength > Partition->BlockIoMedia.BlockSize) {
+        TransferLength = Partition->BlockIoMedia.BlockSize;
+      } else {
+        TransferLength = RemainingLength;
+      }
+
+      Status = SendCommand (
+                 MmcHostIo,
+                 READ_SINGLE_BLOCK,
+                 Address,
+                 InData,
+                 CardData->AlignedBuffer,
+                 (UINT32) TransferLength,
+                 ResponseR1,
+                 TIMEOUT_DATA,
+                 (UINT32*) &(CardData->CardStatus)
+                 );
+
+      if (EFI_ERROR (Status)) {
+        DEBUG ((EFI_D_ERROR, "MMCSDBlockReadBlocks: READ_SINGLE_BLOCK -> Fail\n"));
+        break;
+      }
+    }
+
+    CopyMem (BufferPointer, CardData->AlignedBuffer, TransferLength);
+
+    if (SectorAddressing) {
+      //
+      // Sector Address
+      //
+      Address += TransferLength / 512;
+    } else {
+      //
+      // Byte Address
+      //
+      Address += TransferLength;
+    }
+    BufferPointer   += TransferLength;
+    RemainingLength -= TransferLength;
+  }
+
+  if (EFI_ERROR (Status)) {
+    if ((CardData->CardType == SdMemoryCard) ||
+        (CardData->CardType == SdMemoryCard2)||
+        (CardData->CardType == SdMemoryCard2High)) {
+      SendCommand (
+        MmcHostIo,
+        STOP_TRANSMISSION,
+        0,
+        NoData,
+        NULL,
+        0,
+        ResponseR1b,
+        TIMEOUT_COMMAND,
+        (UINT32 *) &(CardData->CardStatus)
+        );
+    } else {
+      SendCommand (
+        MmcHostIo,
+        STOP_TRANSMISSION,
+        0,
+        NoData,
+        NULL,
+        0,
+        ResponseR1,
+        TIMEOUT_COMMAND,
+        (UINT32 *) &(CardData->CardStatus)
+        );
+    }
+  }
+
+Done:
+  return Status;
+}
+
+
+/**
+  Implements EFI_BLOCK_IO_PROTOCOL.WriteBlocks() function.
+
+  @param[in]  This                    The EFI_BLOCK_IO_PROTOCOL instance.
+  @param[in]  MediaId                 The media id that the write request is for.
+  @param[in]  LBA                     The starting logical block address to be written.
+                                      The caller is responsible for writing to only
+                                      legitimate locations.
+  @param[in]  BufferSize
+                                      The size of the Buffer in bytes. This must be a multiple of
+                                      the intrinsic block size of the device.
+  @param[in]  Buffer                  A pointer to the source buffer for the data. The caller
+                                      is responsible for either having implicit or explicit ownership
+                                      of the buffer.
+
+  @retval     EFI_INVALID_PARAMETER   Parameter is error
+  @retval     EFI_SUCCESS             Success
+  @retval     EFI_DEVICE_ERROR        Hardware Error
+  @retval     EFI_NO_MEDIA            No media
+  @retval     EFI_MEDIA_CHANGED       Media Change
+  @retval     EFI_BAD_BUFFER_SIZE     Buffer size is bad
+
+**/
+EFI_STATUS
+EFIAPI
+MMCSDBlockWriteBlocks (
+  IN  EFI_BLOCK_IO_PROTOCOL   *This,
+  IN  UINT32                  MediaId,
+  IN  EFI_LBA                 LBA,
+  IN  UINTN                   BufferSize,
+  IN  VOID                    *Buffer
+  )
+{
+  EFI_STATUS                  Status;
+  UINT32                      Address;
+  CARD_DATA                   *CardData;
+  EFI_MMC_HOST_IO_PROTOCOL    *MmcHostIo;
+  UINT32                      RemainingLength;
+  UINT32                      TransferLength;
+  UINT8                       *BufferPointer;
+  BOOLEAN                     SectorAddressing;
+  UINT64                      CardSize;
+  MMC_PARTITION_DATA          *Partition;
+
+  Status   = EFI_SUCCESS;
+  Partition = CARD_PARTITION_DATA_FROM_THIS (This);
+  CardData  = Partition->CardData;
+  MmcHostIo = CardData->MmcHostIo;
+
+  Status = MmcSelectPartition (Partition);
+  if (EFI_ERROR (Status)) {
+    return Status;
+  }
+
+  CardSize = MultU64x32 (CardData->BlockNumber, CardData->BlockLen);
+
+  if ((CardData->CardType == SdMemoryCard2High) || (CardSize >= SIZE_2GB)) {
+    SectorAddressing = TRUE;
+  } else {
+    SectorAddressing = FALSE;
+  }
+
+  if (SectorAddressing) {
+    //
+    // Sector Address
+    //
+    Address = (UINT32) DivU64x32 (MultU64x32 (LBA, Partition->BlockIoMedia.BlockSize), 512);
+  } else {
+    //
+    // Byte Address
+    //
+    Address = (UINT32) MultU64x32 (LBA, Partition->BlockIoMedia.BlockSize);
+  }
+
+  if (!Buffer) {
+    Status = EFI_INVALID_PARAMETER;
+    DEBUG ((EFI_D_ERROR, "MMCSDBlockWriteBlocks: Invalid parameter \n"));
+    goto Done;
+  }
+
+  if ((BufferSize % Partition->BlockIoMedia.BlockSize) != 0) {
+    Status = EFI_BAD_BUFFER_SIZE;
+    DEBUG ((EFI_D_ERROR, "MMCSDBlockWriteBlocks: Bad buffer size \n"));
+    goto Done;
+  }
+
+  if (BufferSize == 0) {
+    Status = EFI_SUCCESS;
+    goto Done;
+  }
+
+  if (This->Media->ReadOnly == TRUE) {
+    Status = EFI_WRITE_PROTECTED;
+    DEBUG ((EFI_D_ERROR, "MMCSDBlockWriteBlocks: Write protected \n"));
+    goto Done;
+  }
+
+  BufferPointer   = Buffer;
+  RemainingLength = (UINT32) BufferSize;
+
+  while (RemainingLength > 0) {
+    if ((BufferSize >= Partition->BlockIoMedia.BlockSize) ) {
+      if (RemainingLength > MmcHostIo->HostCapability.BoundarySize) {
+        TransferLength = MmcHostIo->HostCapability.BoundarySize;
+      } else {
+        TransferLength = RemainingLength;
+      }
+
+      if ((CardData->CardType == SdMemoryCard) ||
+          (CardData->CardType == SdMemoryCard2)||
+          (CardData->CardType == SdMemoryCard2High)) {
+        //
+        // Write performance improvement
+        //
+        if ((TransferLength / Partition->BlockIoMedia.BlockSize) > 64) {
+          Status  = SendAppCommand (
+                      CardData,
+                      SET_WR_BLK_ERASE_COUNT,
+                      (UINT32) (TransferLength / Partition->BlockIoMedia.BlockSize),
+                      NoData,
+                      NULL,
+                      0,
+                      ResponseR1,
+                      TIMEOUT_COMMAND,
+                      (UINT32 *) &(CardData->CardStatus)
+                      );
+        }
+      } else if (CardData->CardType == MMCCard) {
+
+        if (!(CardData->ExtCSDRegister.CARD_TYPE & (BIT2 | BIT3)))  {
+          Status = SendCommand (
+                     MmcHostIo,
+                     SET_BLOCKLEN,
+                     Partition->BlockIoMedia.BlockSize,
+                     NoData,
+                     NULL,
+                     0,
+                     ResponseR1,
+                     TIMEOUT_COMMAND,
+                     (UINT32 *) &(CardData->CardStatus)
+                     );
+
+          if (EFI_ERROR (Status)) {
+            break;
+          }
+        }
+        Status = SendCommand (
+                   MmcHostIo,
+                   SET_BLOCK_COUNT,
+                   TransferLength / Partition->BlockIoMedia.BlockSize,
+                   NoData,
+                   NULL,
+                   0,
+                   ResponseR1,
+                   TIMEOUT_COMMAND,
+                   (UINT32 *) &(CardData->CardStatus)
+                   );
+        if (EFI_ERROR (Status)) {
+          break;
+        }
+      }
+
+      CopyMem (CardData->AlignedBuffer, BufferPointer, TransferLength);
+
+      Status = SendCommand (
+                 MmcHostIo,
+                 WRITE_MULTIPLE_BLOCK,
+                 Address,
+                 OutData,
+                 CardData->AlignedBuffer,
+                 (UINT32) TransferLength,
+                 ResponseR1,
+                 TIMEOUT_DATA,
+                 (UINT32 *) &(CardData->CardStatus)
+                 );
+      if (EFI_ERROR (Status)) {
+        DEBUG ((EFI_D_ERROR, "MMCSDBlockWriteBlocks: WRITE_MULTIPLE_BLOCK -> Fail\n"));
+        break;
+      }
+    } else {
+      if (RemainingLength > Partition->BlockIoMedia.BlockSize) {
+        TransferLength = Partition->BlockIoMedia.BlockSize;
+      } else {
+        TransferLength = RemainingLength;
+      }
+
+      CopyMem (CardData->AlignedBuffer, BufferPointer, TransferLength);
+
+      Status = SendCommand (
+                 MmcHostIo,
+                 WRITE_BLOCK,
+                 Address,
+                 OutData,
+                 CardData->AlignedBuffer,
+                 (UINT32) TransferLength,
+                 ResponseR1,
+                 TIMEOUT_DATA,
+                 (UINT32 *) &(CardData->CardStatus)
+                 );
+    }
+
+    if (SectorAddressing) {
+      //
+      // Sector Address
+      //
+      Address += TransferLength / 512;
+    } else {
+      //
+      // Byte Address
+      //
+      Address += TransferLength;
+    }
+    BufferPointer   += TransferLength;
+    RemainingLength -= TransferLength;
+  }
+
+  if (EFI_ERROR (Status)) {
+    SendCommand (
+      MmcHostIo,
+      STOP_TRANSMISSION,
+      0,
+      NoData,
+      NULL,
+      0,
+      ResponseR1b,
+      TIMEOUT_COMMAND,
+      (UINT32 *) &(CardData->CardStatus)
+      );
+  }
+
+Done:
+  return Status;
+}
+
+
+/**
+  Implements EFI_BLOCK_IO_PROTOCOL.FlushBlocks() function.
+  (In this driver, this function just returns EFI_SUCCESS.)
+
+  @param[in]  This          The EFI_BLOCK_IO_PROTOCOL instance.
+
+  @retval     EFI_SUCCESS   Success
+
+**/
+EFI_STATUS
+EFIAPI
+MMCSDBlockFlushBlocks (
+  IN  EFI_BLOCK_IO_PROTOCOL   *This
+  )
+{
+  return EFI_SUCCESS;
+}
+
+
+/**
+  MMC/SD card BlockIo init function
+
+  @param[in]  CardData       Pointer to CARD_DATA
+
+  @retval     EFI_SUCCESS    Success
+
+**/
+EFI_STATUS
+MMCSDBlockIoInit (
+  IN  CARD_DATA       *CardData
+  )
+{
+  UINTN               Loop;
+  MMC_PARTITION_DATA  *Partition;
+  EXT_CSD             *ExtCsd;
+  UINT64              GP_CHUNK_SIZE;
+  UINT32              GP_SIZE_MULT;
+  UINT64              GppSize;
+  UINTN               GppIndex=0;
+
+  Partition = CardData->Partitions;
+  ExtCsd = &CardData->ExtCSDRegister;
+
+  //
+  // Determine GP partitioning chunk size
+  //
+  GP_CHUNK_SIZE = 0;
+  if (((ExtCsd->PARTITIONING_SUPPORT & BIT0) == BIT0) &&
+      ((ExtCsd->PARTITION_SETTING_COMPLETED & BIT0) == BIT0)) {
+    GP_CHUNK_SIZE = MultU64x32 (ExtCsd->HC_WP_GRP_SIZE, ExtCsd->HC_ERASE_GRP_SIZE);
+    GP_CHUNK_SIZE = MultU64x32 (GP_CHUNK_SIZE, SIZE_512KB);
+  }
+
+  for (Loop = 0; Loop < MAX_NUMBER_OF_PARTITIONS; Partition++, Loop++) {
+    //
+    // BlockIO protocol
+    //
+    Partition->BlockIo.Revision    = EFI_BLOCK_IO_PROTOCOL_REVISION;
+    Partition->BlockIo.Media       = &(Partition->BlockIoMedia);
+    Partition->BlockIo.Reset       = MMCSDBlockReset;
+    Partition->BlockIo.ReadBlocks  = MMCSDBlockReadBlocks ;
+    Partition->BlockIo.WriteBlocks = MMCSDBlockWriteBlocks;
+    Partition->BlockIo.FlushBlocks = MMCSDBlockFlushBlocks;
+
+    Partition->BlockIoMedia.MediaId          = 0;
+    Partition->BlockIoMedia.RemovableMedia   = FALSE;
+    Partition->BlockIoMedia.MediaPresent     = TRUE;
+    Partition->BlockIoMedia.LogicalPartition = FALSE;
+
+    //
+    // Force the User partition to be enabled
+    //
+    if (Loop == 0) {
+      Partition->Present = TRUE;
+    }
+
+    if (CardData->CSDRegister.PERM_WRITE_PROTECT || CardData->CSDRegister.TMP_WRITE_PROTECT) {
+      Partition->BlockIoMedia.ReadOnly       = TRUE;
+    } else {
+      Partition->BlockIoMedia.ReadOnly       = FALSE;
+    }
+
+    Partition->BlockIoMedia.WriteCaching     = FALSE;
+    Partition->BlockIoMedia.BlockSize        = CardData->BlockLen;
+    Partition->BlockIoMedia.IoAlign          = 1;
+    Partition->BlockIoMedia.LastBlock        = (EFI_LBA) (CardData->BlockNumber - 1);
+
+    //
+    // Handle GPP partitions
+    //
+    GppSize = 0;
+    if ((GP_CHUNK_SIZE != 0) && (Loop >= 4)) {
+      Partition->BlockIoMedia.LastBlock = (EFI_LBA) 0;
+      GppIndex = Loop - 4;
+      GP_SIZE_MULT = MmcGetExtCsd24 (
+                       CardData,
+                       OFFSET_OF (EXT_CSD, GP_SIZE_MULT_1) + (3 * GppIndex)
+                       );
+      GppSize = MultU64x32 (GP_SIZE_MULT, (UINT32) GP_CHUNK_SIZE);
+    }
+
+    if (GppSize != 0) {
+      Partition->BlockIoMedia.LastBlock =
+        DivU64x32 (GppSize, Partition->BlockIoMedia.BlockSize) - 1;
+      DEBUG ((EFI_D_INFO,
+        "GPP%d last-block: 0x%lx\n",
+        GppIndex + 1,
+        Partition->BlockIoMedia.LastBlock
+        ));
+      Partition->Present = TRUE;
+    }
+
+    if (CardData->CardType == MMCCard) {
+      //
+      // Handle Boot partitions
+      //
+      if ((Loop == 1) || (Loop == 2)) {
+        Partition->BlockIoMedia.LastBlock = 128 * 1024 * ((UINTN) MmcGetExtCsd8 (CardData, OFFSET_OF (EXT_CSD, BOOT_SIZE_MULTI))) / 512;
+        Partition->Present = TRUE;
+      }
+    }
+  }
+
+  DEBUG ((EFI_D_INFO, "MMC SD Block I/O: Initialized\n"));
+
+  return EFI_SUCCESS;
+}
+
diff --git a/Silicon/BroxtonSoC/BroxtonSiPkg/SouthCluster/Sdio/Dxe/MMC/MmcMediaDeviceDxe/MMCSDTransfer.c b/Silicon/BroxtonSoC/BroxtonSiPkg/SouthCluster/Sdio/Dxe/MMC/MmcMediaDeviceDxe/MMCSDTransfer.c
new file mode 100644
index 0000000..13258de
--- /dev/null
+++ b/Silicon/BroxtonSoC/BroxtonSiPkg/SouthCluster/Sdio/Dxe/MMC/MmcMediaDeviceDxe/MMCSDTransfer.c
@@ -0,0 +1,2524 @@
+/** @file
+  SMMC transfer specific functions.
+
+  Copyright (c) 1999 - 2017, Intel Corporation. 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 <MediaDeviceDriver.h>
+#include <HeciRegs.h>
+#include <Private/Guid/ScPolicyHobGuid.h>
+#include <SeCAccess.h>
+#include <Library/SteppingLib.h>
+#include <Library/ConfigBlockLib.h>
+
+
+/**
+  Set Mmc ExtCsd register
+
+  @param[in]  PeiCardData              Pointer to CARD_DATA
+  @param[in]  Index
+  @param[in]  Value
+
+  @retval     EFI_INVALID_PARAMETER
+  @retval     EFI_UNSUPPORTED
+  @retval     EFI_SUCCESS
+
+**/
+EFI_STATUS
+MmcSetExtCsd8 (
+  IN  CARD_DATA              *CardData,
+  IN  UINT8                  Index,
+  IN  UINT8                  Value
+  );
+
+EFI_EVENT   mSetEmmcWpOnEvent = NULL;
+
+
+/**
+  Check card status, print the debug info and check the error
+
+  @param[in]  Status              Status got from card status register
+
+  @retval     EFI_DEVICE_ERROR
+  @retval     EFI_SUCCESS
+
+**/
+EFI_STATUS
+CheckCardStatus (
+  IN  UINT32    Status
+  )
+{
+  CARD_STATUS    *CardStatus;
+  CardStatus = (CARD_STATUS *) (&Status);
+
+  if (CardStatus->ADDRESS_OUT_OF_RANGE) {
+   DEBUG ((EFI_D_ERROR, "CardStatus: ADDRESS_OUT_OF_RANGE\n"));
+  }
+
+  if (CardStatus->ADDRESS_MISALIGN) {
+   DEBUG ((EFI_D_ERROR, "CardStatus: ADDRESS_MISALIGN\n"));
+  }
+
+  if (CardStatus->BLOCK_LEN_ERROR) {
+   DEBUG ((EFI_D_ERROR, "CardStatus: BLOCK_LEN_ERROR\n"));
+  }
+
+  if (CardStatus->ERASE_SEQ_ERROR) {
+   DEBUG ((EFI_D_ERROR, "CardStatus: ERASE_SEQ_ERROR\n"));
+  }
+
+  if (CardStatus->ERASE_PARAM) {
+   DEBUG ((EFI_D_ERROR, "CardStatus: ERASE_PARAM\n"));
+  }
+
+  if (CardStatus->WP_VIOLATION) {
+   DEBUG ((EFI_D_ERROR, "CardStatus: WP_VIOLATION\n"));
+  }
+
+  if (CardStatus->CARD_IS_LOCKED) {
+   DEBUG ((EFI_D_ERROR, "CardStatus: CARD_IS_LOCKED\n"));
+  }
+
+  if (CardStatus->LOCK_UNLOCK_FAILED) {
+   DEBUG ((EFI_D_ERROR, "CardStatus: LOCK_UNLOCK_FAILED\n"));
+  }
+
+  if (CardStatus->COM_CRC_ERROR) {
+   DEBUG ((EFI_D_ERROR, "CardStatus: COM_CRC_ERROR\n"));
+  }
+
+  if (CardStatus->ILLEGAL_COMMAND) {
+   DEBUG ((EFI_D_ERROR, "CardStatus: ILLEGAL_COMMAND\n"));
+  }
+
+  if (CardStatus->CARD_ECC_FAILED) {
+   DEBUG ((EFI_D_ERROR, "CardStatus: CARD_ECC_FAILED\n"));
+  }
+
+  if (CardStatus->CC_ERROR) {
+   DEBUG ((EFI_D_ERROR, "CardStatus: CC_ERROR\n"));
+  }
+
+  if (CardStatus->ERROR) {
+   DEBUG ((EFI_D_ERROR, "CardStatus: ERROR\n"));
+  }
+
+  if (CardStatus->UNDERRUN) {
+   DEBUG ((EFI_D_ERROR, "CardStatus: UNDERRUN\n"));
+  }
+
+  if (CardStatus->OVERRUN) {
+   DEBUG ((EFI_D_ERROR, "CardStatus: OVERRUN\n"));
+  }
+
+  if (CardStatus->CID_CSD_OVERWRITE) {
+   DEBUG ((EFI_D_ERROR, "CardStatus: CID_CSD_OVERWRITE\n"));
+  }
+
+  if (CardStatus->WP_ERASE_SKIP) {
+   DEBUG ((EFI_D_ERROR, "CardStatus: WP_ERASE_SKIP\n"));
+  }
+
+  if (CardStatus->ERASE_RESET) {
+   DEBUG ((EFI_D_ERROR, "CardStatus: ERASE_RESET\n"));
+  }
+
+  if (CardStatus->SWITCH_ERROR) {
+   DEBUG ((EFI_D_ERROR, "CardStatus: SWITCH_ERROR\n"));
+  }
+
+  if ((Status & 0xFCFFA080) != 0) {
+    return EFI_DEVICE_ERROR;
+  }
+
+  return EFI_SUCCESS;
+}
+
+
+/**
+  Send command by using Host IO protocol
+
+  @param[in]  This                    Pointer to EFI_MMC_HOST_IO_PROTOCOL
+  @param[in]  CommandIndex            The command index to set the command index field of command register
+  @param[in]  Argument                Command argument to set the argument field of command register
+  @param[in]  DataType                TRANSFER_TYPE, indicates no data, data in or data out
+  @param[in]  Buffer                  Contains the data read from / write to the device
+  @param[in]  BufferSize              The size of the buffer
+  @param[in]  ResponseType            RESPONSE_TYPE
+  @param[in]  TimeOut                 Time out value in 1 ms unit
+  @param[out] ResponseData            Depending on the ResponseType, such as CSD or card status
+
+  @retval     EFI_INVALID_PARAMETER
+  @retval     EFI_UNSUPPORTED
+  @retval     EFI_DEVICE_ERROR
+  @retval     EFI_SUCCESS
+
+**/
+EFI_STATUS
+SendCommand (
+  IN   EFI_MMC_HOST_IO_PROTOCOL   *This,
+  IN   UINT16                     CommandIndex,
+  IN   UINT32                     Argument,
+  IN   TRANSFER_TYPE              DataType,
+  IN   UINT8                      *Buffer, OPTIONAL
+  IN   UINT32                     BufferSize,
+  IN   RESPONSE_TYPE              ResponseType,
+  IN   UINT32                     TimeOut,
+  OUT  UINT32                     *ResponseData
+  )
+{
+
+  EFI_STATUS    Status;
+
+  Status = This->SendCommand (
+                   This,
+                   CommandIndex,
+                   Argument,
+                   DataType,
+                   Buffer,
+                   BufferSize,
+                   ResponseType,
+                   TimeOut,
+                   ResponseData
+                   );
+  if (!EFI_ERROR (Status)) {
+    if (ResponseType == ResponseR1 || ResponseType == ResponseR1b) {
+      if (ResponseData == NULL) {
+        ASSERT(ResponseData != NULL);
+        return EFI_OUT_OF_RESOURCES;
+      }
+      Status = CheckCardStatus (*ResponseData);
+    }
+  } else {
+    This->ResetMmcHost (This, Reset_DAT_CMD);
+  }
+
+  return Status;
+}
+
+
+/**
+  Send the card APP_CMD command with the following command indicated
+  by CommandIndex
+
+  @param[in]  CardData                 Pointer to CARD_DATA
+  @param[in]  CommandIndex             The command index to set the command index field of command register
+  @param[in]  Argument                 Command argument to set the argument field of command register
+  @param[in]  DataType                 TRANSFER_TYPE, indicates no data, data in or data out
+  @param[in]  Buffer                   Contains the data read from / write to the device
+  @param[in]  BufferSize               The size of the buffer
+  @param[in]  ResponseType             RESPONSE_TYPE
+  @param[in]  TimeOut                  Time out value in 1 ms unit
+  @param[out] ResponseData             Depending on the ResponseType, such as CSD or card status
+
+  @retval     EFI_INVALID_PARAMETER
+  @retval     EFI_UNSUPPORTED
+  @retval     EFI_DEVICE_ERROR
+  @retval     EFI_SUCCESS
+
+**/
+EFI_STATUS
+SendAppCommand (
+  IN   CARD_DATA                  *CardData,
+  IN   UINT16                     CommandIndex,
+  IN   UINT32                     Argument,
+  IN   TRANSFER_TYPE              DataType,
+  IN   UINT8                      *Buffer, OPTIONAL
+  IN   UINT32                     BufferSize,
+  IN   RESPONSE_TYPE              ResponseType,
+  IN   UINT32                     TimeOut,
+  OUT  UINT32                     *ResponseData
+  )
+{
+
+  EFI_STATUS                 Status;
+  EFI_MMC_HOST_IO_PROTOCOL   *MmcHostIo;
+  UINT8                      Index;
+
+  MmcHostIo = CardData->MmcHostIo;
+  Status = EFI_SUCCESS;
+
+  for (Index = 0; Index < 2; Index++) {
+    Status = MmcHostIo->SendCommand (
+                          MmcHostIo,
+                          APP_CMD,
+                          (CardData->Address << 16),
+                          NoData,
+                          NULL,
+                          0,
+                          ResponseR1,
+                          TIMEOUT_COMMAND,
+                          (UINT32 *) &(CardData->CardStatus)
+                          );
+    if (!EFI_ERROR (Status)) {
+      Status = CheckCardStatus (*(UINT32 *) &(CardData->CardStatus));
+      if (CardData->CardStatus.SAPP_CMD != 1) {
+        Status = EFI_DEVICE_ERROR;
+      }
+      if (!EFI_ERROR (Status)) {
+        break;
+      }
+    } else {
+      MmcHostIo->ResetMmcHost (MmcHostIo, Reset_Auto);
+    }
+  }
+
+  if (EFI_ERROR (Status)) {
+    return Status;
+  }
+
+  Status = MmcHostIo->SendCommand (
+                        MmcHostIo,
+                        CommandIndex,
+                        Argument,
+                        DataType,
+                        Buffer,
+                        BufferSize,
+                        ResponseType,
+                        TimeOut,
+                        ResponseData
+                        );
+  if (!EFI_ERROR (Status)) {
+    if (ResponseType == ResponseR1 || ResponseType == ResponseR1b) {
+       if (ResponseData == NULL) {
+        ASSERT(ResponseData != NULL);
+        return EFI_OUT_OF_RESOURCES;
+      }
+      Status = CheckCardStatus (*ResponseData);
+    }
+  } else {
+    MmcHostIo->ResetMmcHost (MmcHostIo, Reset_Auto);
+  }
+
+  return Status;
+}
+
+
+/**
+  Dump Mmc Decode OCR register
+
+  @param[in]  OCRReg      Pointer to OCR
+
+  @retval     None
+
+**/
+EFI_STATUS
+MmcDecodeOCR (
+  IN OCR  *OCRReg
+  )
+{
+  DEBUG ((DEBUG_INFO, "\n==========DECODE MMC OCR REGISTER==================\n"));
+  DEBUG ((DEBUG_INFO, " OCR = 0x%08X\n", *((UINT32 *) OCRReg)));
+  DEBUG ((DEBUG_INFO, " CARD_NOT_BUSY      = 0x%X\n", OCRReg->Busy));
+  DEBUG ((DEBUG_INFO, " ACCESS_MODE        = 0x%X\n", OCRReg->AccessMode));
+  DEBUG ((DEBUG_INFO, " VDD_270_360        = 0x%X\n", OCRReg->V270_V360));
+  DEBUG ((DEBUG_INFO, " VDD_200_260        = 0x%X\n", OCRReg->V200_V260));
+  DEBUG ((DEBUG_INFO, " VDD_170_195        = 0x%X\n", OCRReg->V170_V195));
+  DEBUG ((DEBUG_INFO, "==================================================\n"));
+  return 0;
+}
+
+
+/**
+  Dump Mmc Decode CID value
+
+  @param[in]  CIDReg      Pointer to CIDReg
+
+  @retval     None
+
+**/
+EFI_STATUS
+MmcDecodeCID (
+  IN CID  *CIDReg
+  )
+{
+  UINT32 i = 0;
+
+  DEBUG ((EFI_D_INFO, "\n==========DECODE MMC CID REGISTER==================\n"));
+  DEBUG ((EFI_D_INFO, " CID = 0x%032X\n", CIDReg));
+  DEBUG ((EFI_D_INFO, " MANUFACTURER_ID     = 0x%X\n", CIDReg->MID));
+  DEBUG ((EFI_D_INFO, " CARD_OR_BGA         = 0x%X\n", (CIDReg->OID & 0xFF00)>>6));
+  DEBUG ((EFI_D_INFO, " OEM_APPLICATION_ID  = 0x%X\n", (CIDReg->OID>>8) &0xFF));
+  DEBUG ((EFI_D_INFO, " PRODUCT_NAME        = "));
+
+  for (i=0; i < 6; i++) {
+   DEBUG ((EFI_D_INFO, "%c", CIDReg->PNM[i]));
+  }
+  DEBUG ((EFI_D_INFO, "\n"));
+  DEBUG ((EFI_D_INFO, " PRODUCT_REVISION    = 0x%X\n", CIDReg->PRV));
+  DEBUG ((EFI_D_INFO, " PRODUCT_SERIAL_NUM  = 0x%X\n", CIDReg->PSN));
+  DEBUG ((EFI_D_INFO, " MANUFACTURE_DATE    = 0x%X\n", CIDReg->MDT));
+  DEBUG ((EFI_D_INFO, "==================================================\n"));
+  return 0;
+}
+
+
+/**
+  Dump Mmc Decode CSD value
+
+  @param[in]  CSDReg      Pointer to CSDReg
+
+  @retval     None
+
+**/
+EFI_STATUS
+MmcDecodeCSD (
+  IN CSD  *CSDReg
+  )
+{
+  DEBUG ((EFI_D_INFO, "\n==========DECODE MMC CSD REGISTER==================\n"));
+  DEBUG ((EFI_D_INFO, "csd_struct        : [0x%0x] \n", CSDReg->CSD_STRUCTURE));
+  DEBUG ((EFI_D_INFO, "specs_ver         : [0x%0x] \n", CSDReg->SPEC_VERS));
+  DEBUG ((EFI_D_INFO, "reserve2          : [0x%0x] \n", CSDReg->Reserved2));
+  DEBUG ((EFI_D_INFO, "taac              : [0x%0x] \n", CSDReg->TAAC));
+  DEBUG ((EFI_D_INFO, "nsac              : [0x%0x] \n", CSDReg->NSAC));
+  DEBUG ((EFI_D_INFO, "tran_speed        : [0x%0x] \n", CSDReg->TRAN_SPEED));
+  DEBUG ((EFI_D_INFO, "ccc               : [0x%0x] \n", CSDReg->CCC));
+  DEBUG ((EFI_D_INFO, "read_bl_len       : [0x%0x] \n", CSDReg->READ_BL_LEN));
+  DEBUG ((EFI_D_INFO, "read_partial      : [0x%0x] \n", CSDReg->READ_BL_PARTIAL));
+  DEBUG ((EFI_D_INFO, "write_misalign    : [0x%0x] \n", CSDReg->WRITE_BLK_MISALIGN));
+  DEBUG ((EFI_D_INFO, "read_misalign     : [0x%0x] \n", CSDReg->READ_BLK_MISALIGN));
+  DEBUG ((EFI_D_INFO, "dsr_imp           : [0x%0x] \n", CSDReg->DSR_IMP));
+  DEBUG ((EFI_D_INFO, "reserve1          : [0x%0x] \n", CSDReg->Reserved1));
+  DEBUG ((EFI_D_INFO, "c_size            : [0x%0x] \n", CSDReg->C_SIZELow2 | CSDReg->C_SIZEHigh10<<2));
+  DEBUG ((EFI_D_INFO, "vdd_r_curr_min    : [0x%0x] \n", CSDReg->VDD_R_CURR_MIN));
+  DEBUG ((EFI_D_INFO, "vdd_r_curr_max    : [0x%0x] \n", CSDReg->VDD_R_CURR_MAX));
+  DEBUG ((EFI_D_INFO, "vdd_w_curr_min    : [0x%0x] \n", CSDReg->VDD_W_CURR_MIN));
+  DEBUG ((EFI_D_INFO, "vdd_w_curr_max    : [0x%0x] \n", CSDReg->VDD_W_CURR_MAX));
+  DEBUG ((EFI_D_INFO, "c_size_mult       : [0x%0x] \n", CSDReg->C_SIZE_MULT));
+  DEBUG ((EFI_D_INFO, "erase_grp_size    : [0x%0x] \n", CSDReg->ERASE_GRP_SIZE));
+  DEBUG ((EFI_D_INFO, "erase_grp_mult    : [0x%0x] \n", CSDReg->ERASE_GRP_MULT));
+  DEBUG ((EFI_D_INFO, "wp_grp_size       : [0x%0x] \n", CSDReg->WP_GRP_SIZE));
+  DEBUG ((EFI_D_INFO, "wp_grp_enable     : [0x%0x] \n", CSDReg->WP_GRP_ENABLE));
+  DEBUG ((EFI_D_INFO, "default_ecc       : [0x%0x] \n", CSDReg->DEFAULT_ECC));
+  DEBUG ((EFI_D_INFO, "r2w_factor        : [0x%0x] \n", CSDReg->R2W_FACTOR));
+  DEBUG ((EFI_D_INFO, "write_bl_len      : [0x%0x] \n", CSDReg->WRITE_BL_LEN));
+  DEBUG ((EFI_D_INFO, "write_partial     : [0x%0x] \n", CSDReg->WRITE_BL_PARTIAL));
+  DEBUG ((EFI_D_INFO, "reserve0          : [0x%0x] \n", CSDReg->Reserved0));
+  DEBUG ((EFI_D_INFO, "content_prot_app  : [0x%0x] \n", CSDReg->CONTENT_PROT_APP));
+  DEBUG ((EFI_D_INFO, "file_format_grp   : [0x%0x] \n", CSDReg->FILE_FORMAT_GRP));
+  DEBUG ((EFI_D_INFO, "copy              : [0x%0x] \n", CSDReg->COPY));
+  DEBUG ((EFI_D_INFO, "perm_write_protect: [0x%0x] \n", CSDReg->PERM_WRITE_PROTECT));
+  DEBUG ((EFI_D_INFO, "tmp_write_prot    : [0x%0x] \n", CSDReg->TMP_WRITE_PROTECT));
+  DEBUG ((EFI_D_INFO, "file_format       : [0x%0x] \n", CSDReg->FILE_FORMAT));
+  DEBUG ((EFI_D_INFO, "ecc               : [0x%0x] \n", CSDReg->ECC));
+  DEBUG ((EFI_D_INFO, "==================================================\n"));
+
+  return 0;
+}
+
+
+/**
+  Dump Mmc Decode Ext CSD value
+
+  @param[in]  ExtCSDReg      Pointer to ExtCSDReg
+
+  @retval     None
+
+**/
+EFI_STATUS
+MmcDecodeExtCSD (
+  IN EXT_CSD  *ExtCSDReg
+  )
+{
+  DEBUG ((EFI_D_INFO, "\n==========DECODE MMC EXT CSD REGISTER==================\n"));
+  DEBUG ((EFI_D_INFO, " SUPPORTED_CMD_SETS        = 0x%X\n", ExtCSDReg->CMD_SET));
+  DEBUG ((EFI_D_INFO, " HPI_FEATURES              = 0x%X\n", ExtCSDReg->HPI_FEATURES));
+  DEBUG ((EFI_D_INFO, " BKOPS_SUPPORT             = 0x%X\n", ExtCSDReg->BKOPS_SUPPORT));
+  DEBUG ((EFI_D_INFO, " BKOPS_STATUS              = 0x%X\n", ExtCSDReg->BKOPS_STATUS));
+  DEBUG ((EFI_D_INFO, " CORRECTLY_PRG_SECTORS_NUM = 0x%X%X%X%X\n", ExtCSDReg->CORRECTLY_PRG_SECTORS_NUM[3], \
+                                                    ExtCSDReg->CORRECTLY_PRG_SECTORS_NUM[2], ExtCSDReg->CORRECTLY_PRG_SECTORS_NUM[1], ExtCSDReg->CORRECTLY_PRG_SECTORS_NUM[0]));
+  DEBUG ((EFI_D_INFO, " INI_TIMEOUT_AP            = 0x%X\n", ExtCSDReg->INI_TIMEOUT_AP));
+  DEBUG ((EFI_D_INFO, " PWR_CL_DDR_52_195         = 0x%X\n", ExtCSDReg->PWR_CL_DDR_52_195));
+  DEBUG ((EFI_D_INFO, " PWR_CL_DDR_52_360         = 0x%X\n", ExtCSDReg->PWR_CL_DDR_52_360));
+  DEBUG ((EFI_D_INFO, " MIN_PRF_DDR_W_8_52        = 0x%X\n", ExtCSDReg->MIN_PERF_DDR_W_8_52));
+  DEBUG ((EFI_D_INFO, " MIN_PRF_DDR_R_8_52        = 0x%X\n", ExtCSDReg->MIN_PERF_DDR_R_8_52));
+  DEBUG ((EFI_D_INFO, " TRIM_MULT                 = 0x%X\n", ExtCSDReg->TRIM_MULT));
+  DEBUG ((EFI_D_INFO, " SEC_FEATURE_SUPP          = 0x%X\n", ExtCSDReg->SEC_FEATURE_SUPPORT));
+  DEBUG ((EFI_D_INFO, " SEC_ERASE_MULT            = 0x%X\n", ExtCSDReg->SEC_ERASE_MULT));
+  DEBUG ((EFI_D_INFO, " SEC_TRIM_MULT             = 0x%X\n", ExtCSDReg->SEC_TRIM_MULT));
+  DEBUG ((EFI_D_INFO, " BOOT_INFO                 = 0x%X\n", ExtCSDReg->BOOT_INFO));
+  DEBUG ((EFI_D_INFO, " BOOT_PART_SIZE            = 0x%X\n", ExtCSDReg->BOOT_SIZE_MULTI));
+  DEBUG ((EFI_D_INFO, " ACCESS_SIZE               = 0x%X\n", ExtCSDReg->ACC_SIZE));
+  DEBUG ((EFI_D_INFO, " HI_CAP_ER_GRP_SIZE        = 0x%X\n", ExtCSDReg->HC_ERASE_GRP_SIZE));
+  DEBUG ((EFI_D_INFO, " HI_CAP_ER_TIMEOUT         = 0x%X\n", ExtCSDReg->ERASE_TIMEOUT_MULT));
+  DEBUG ((EFI_D_INFO, " REL_WR_SECTOR_CNT         = 0x%X\n", ExtCSDReg->REL_WR_SEC_C));
+  DEBUG ((EFI_D_INFO, " HI_CAP_WP_GRP_SIZE        = 0x%X\n", ExtCSDReg->HC_WP_GRP_SIZE));
+  DEBUG ((EFI_D_INFO, " SLEEP_CURRENT_VCC         = 0x%X\n", ExtCSDReg->S_C_VCC));
+  DEBUG ((EFI_D_INFO, " SLEEP_CURRENT_VCCQ        = 0x%X\n", ExtCSDReg->S_C_VCCQ));
+  DEBUG ((EFI_D_INFO, " SLP_AWK_TIMEOUT           = 0x%X\n", ExtCSDReg->S_A_TIMEOUT));
+  DEBUG ((EFI_D_INFO, " SECTOR_COUNT              = 0x%X\n", *(UINT32*) ((UINT8 *) &ExtCSDReg->SEC_COUNT)));
+  DEBUG ((EFI_D_INFO, " MIN_PERF_W_8_52           = 0x%X\n", ExtCSDReg->MIN_PERF_W_8_52));
+  DEBUG ((EFI_D_INFO, " MIN_PERF_R_8_52           = 0x%X\n", ExtCSDReg->MIN_PERF_R_8_52));
+  DEBUG ((EFI_D_INFO, " MIN_PERF_W_8_26_4_52      = 0x%X\n", ExtCSDReg->MIN_PERF_W_8_26_4_52));
+  DEBUG ((EFI_D_INFO, " MIN_PERF_W_8_26_4_52      = 0x%X\n", ExtCSDReg->MIN_PERF_W_8_26_4_52));
+  DEBUG ((EFI_D_INFO, " MIN_PERF_W_4_26           = 0x%X\n", ExtCSDReg->MIN_PERF_W_4_26));
+  DEBUG ((EFI_D_INFO, " MIN_PERF_R_4_26           = 0x%X\n", ExtCSDReg->MIN_PERF_R_4_26));
+  DEBUG ((EFI_D_INFO, " PWR_CLASS_26_360          = 0x%X\n", ExtCSDReg->PWR_CL_26_360));
+  DEBUG ((EFI_D_INFO, " PWR_CLASS_52_360          = 0x%X\n", ExtCSDReg->PWR_CL_52_360));
+  DEBUG ((EFI_D_INFO, " PWR_CLASS_26_195          = 0x%X\n", ExtCSDReg->PWR_CL_26_195));
+  DEBUG ((EFI_D_INFO, " PWR_CLASS_52_195          = 0x%X\n", ExtCSDReg->PWR_CL_52_195));
+  DEBUG ((EFI_D_INFO, " PARTITION_SWITCH_TIME     = 0x%X\n", ExtCSDReg->PARTITION_SWITCH_TIME));
+  DEBUG ((EFI_D_INFO, " OUT_OF_INTERRUPT_TIME     = 0x%X\n", ExtCSDReg->OUT_OF_INTERRUPT_TIME));
+  DEBUG ((EFI_D_INFO, " CARD_TYPE                 = 0x%X\n", ExtCSDReg->CARD_TYPE));
+  DEBUG ((EFI_D_INFO, " CSD_STRUCTURE             = 0x%X\n", ExtCSDReg->CSD_STRUCTURE));
+  DEBUG ((EFI_D_INFO, " EXT_CSD_REV               = 0x%X\n", ExtCSDReg->EXT_CSD_REV));
+  DEBUG ((EFI_D_INFO, " CMD_SET                   = 0x%X\n", ExtCSDReg->CMD_SET));
+  DEBUG ((EFI_D_INFO, " CMD_SET_REV               = 0x%X\n", ExtCSDReg->CMD_SET_REV));
+  DEBUG ((EFI_D_INFO, " PWR_CLASS                 = 0x%X\n", ExtCSDReg->POWER_CLASS));
+  DEBUG ((EFI_D_INFO, " HI_SPEED_TIMING           = 0x%X\n", ExtCSDReg->HS_TIMING));
+  DEBUG ((EFI_D_INFO, " BUS_WIDTH_MODE            = 0x%X\n", ExtCSDReg->BUS_WIDTH));
+  DEBUG ((EFI_D_INFO, " ERASED_MEM_CONTENT        = 0x%X\n", ExtCSDReg->ERASED_MEM_CONT));
+  DEBUG ((EFI_D_INFO, " PARTITION_CONFIG          = 0x%X\n", ExtCSDReg->PARTITION_CONFIG));
+  DEBUG ((EFI_D_INFO, " BOOT_CONFIG_PROT          = 0x%X\n", ExtCSDReg->BOOT_CONFIG_PROT));
+  DEBUG ((EFI_D_INFO, " BOOT_BUS_WIDTH            = 0x%X\n", ExtCSDReg->BOOT_BUS_WIDTH));
+  DEBUG ((EFI_D_INFO, " HI_DEN_ER_GRP_DEF         = 0x%X\n", ExtCSDReg->ERASE_GROUP_DEF));
+  DEBUG ((EFI_D_INFO, " BOOT_WP                   = 0x%X\n", ExtCSDReg->BOOT_WP));
+  DEBUG ((EFI_D_INFO, " USER_WP                   = 0x%X\n", ExtCSDReg->USER_WP));
+  DEBUG ((EFI_D_INFO, " FW_CONFIG                 = 0x%X\n", ExtCSDReg->FW_CONFIG));
+  DEBUG ((EFI_D_INFO, " RPMB_SIZE_MULT            = 0x%X\n", ExtCSDReg->RPMB_SIZE_MULT));
+  DEBUG ((EFI_D_INFO, " RST_N_FUNCTION            = 0x%X\n", ExtCSDReg->RST_n_FUNCTION));
+  DEBUG ((EFI_D_INFO, " PARTITIONING_SUPP         = 0x%X\n", ExtCSDReg->PARTITIONING_SUPPORT));
+  DEBUG ((EFI_D_INFO, " MAX_ENH_SIZE_MULT         = 0x%02X%02X%02X\n", ExtCSDReg->MAX_ENH_SIZE_MULT[2],ExtCSDReg->MAX_ENH_SIZE_MULT[1], ExtCSDReg->MAX_ENH_SIZE_MULT[0]));
+  DEBUG ((EFI_D_INFO, " PART_ATTRIBUTE            = 0x%X\n", ExtCSDReg->PARTITIONS_ATTRIBUTES));
+  DEBUG ((EFI_D_INFO, " PART_SETTING_COMP         = 0x%X\n", ExtCSDReg->PARTITION_SETTING_COMPLETED));
+  DEBUG ((EFI_D_INFO, " GP_SIZE_MULT              = 0x%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X\n", ExtCSDReg->GP_SIZE_MULT_4[2], ExtCSDReg->GP_SIZE_MULT_4[1], ExtCSDReg->GP_SIZE_MULT_4[0],
+                                                  ExtCSDReg->GP_SIZE_MULT_3[2], ExtCSDReg->GP_SIZE_MULT_3[1], ExtCSDReg->GP_SIZE_MULT_3[0],
+                                                  ExtCSDReg->GP_SIZE_MULT_2[2], ExtCSDReg->GP_SIZE_MULT_2[1], ExtCSDReg->GP_SIZE_MULT_2[0],
+                                                  ExtCSDReg->GP_SIZE_MULT_1[2], ExtCSDReg->GP_SIZE_MULT_1[1], ExtCSDReg->GP_SIZE_MULT_1[0]));
+  DEBUG ((EFI_D_INFO, " ENH_SIZE_MULT             = 0x%02X%02X%02X\n", ExtCSDReg->ENH_SIZE_MULT[2], ExtCSDReg->ENH_SIZE_MULT[1], ExtCSDReg->ENH_SIZE_MULT[0]));
+  DEBUG ((EFI_D_INFO, " ENH_START_ADDR            = 0x%02X%02X%02X%02X\n", ExtCSDReg->ENH_START_ADDR[3], ExtCSDReg->ENH_START_ADDR[2], ExtCSDReg->ENH_START_ADDR[1], ExtCSDReg->ENH_START_ADDR[0]));
+  DEBUG ((EFI_D_INFO, " SEC_BAD_BLK_MGMNT         = 0x%X\n", ExtCSDReg->SEC_BAD_BLOCK_MGMNT));
+  DEBUG ((EFI_D_INFO, "==================================================\n"));
+
+  return 0;
+}
+
+
+/**
+  Send the card FAST_IO command
+
+  @param[in]      CardData                 Pointer to CARD_DATA
+  @param[in]      RegisterAddress          Register Address
+  @param[in, out] RegisterData             Pointer to register Data
+  @param[in]      Write                    TRUE for write, FALSE for read
+
+  @retval         EFI_INVALID_PARAMETER
+  @retval         EFI_UNSUPPORTED
+  @retval         EFI_DEVICE_ERROR
+  @retval         EFI_SUCCESS
+
+**/
+EFI_STATUS
+FastIO (
+  IN      CARD_DATA   *CardData,
+  IN      UINT8       RegisterAddress,
+  IN  OUT UINT8       *RegisterData,
+  IN      BOOLEAN     Write
+  )
+{
+  EFI_MMC_HOST_IO_PROTOCOL   *MmcHostIo;
+  EFI_STATUS                 Status;
+  UINT32                     Argument;
+  UINT32                     Data;
+
+  Status   = EFI_SUCCESS;
+  MmcHostIo = CardData->MmcHostIo;
+
+  if (RegisterData == NULL) {
+    Status = EFI_INVALID_PARAMETER;
+    goto Exit;
+  }
+
+  Argument = (CardData->Address << 16) | (RegisterAddress << 8);
+  if (Write) {
+    Argument |= BIT15 | (*RegisterData);
+  }
+
+  Status = SendCommand (
+             MmcHostIo,
+             FAST_IO,
+             Argument,
+             NoData,
+             NULL,
+             0,
+             ResponseR4,
+             TIMEOUT_COMMAND,
+             &Data
+             );
+
+  if (EFI_ERROR (Status)) {
+    goto Exit;
+  }
+
+  if ((Data & BIT15) == 0) {
+    Status = EFI_DEVICE_ERROR;
+    goto Exit;
+  }
+
+  if (!Write) {
+   *RegisterData = (UINT8)Data;
+  }
+
+Exit:
+  return Status;
+}
+
+
+/**
+  Send the card GO_INACTIVE_STATE command
+
+  @param[in]  CardData               Pointer to CARD_DATA
+
+  @retval     EFI_INVALID_PARAMETER
+  @retval     EFI_UNSUPPORTED
+  @retval     EFI_SUCCESS
+
+**/
+EFI_STATUS
+PutCardInactive (
+  IN  CARD_DATA   *CardData
+  )
+{
+  EFI_MMC_HOST_IO_PROTOCOL   *MmcHostIo;
+  EFI_STATUS                 Status;
+
+  MmcHostIo = CardData->MmcHostIo;
+
+  Status = SendCommand (
+             MmcHostIo,
+             GO_INACTIVE_STATE,
+             (CardData->Address << 16),
+             NoData,
+             NULL,
+             0,
+             ResponseNo,
+             TIMEOUT_COMMAND,
+             NULL
+             );
+
+  gBS->Stall(1000);
+
+  return Status;
+}
+
+
+/**
+  Get card interested information for CSD rergister
+
+  @param[in]  CardData                Pointer to CARD_DATA
+
+  @retval     EFI_INVALID_PARAMETER
+  @retval     EFI_UNSUPPORTED
+  @retval     EFI_SUCCESS
+
+**/
+EFI_STATUS
+CalculateCardParameter (
+  IN  CARD_DATA    *CardData
+  )
+{
+  EFI_STATUS     Status;
+  UINT32         Frequency;
+  UINT32         Multiple;
+  UINT32         CSize;
+  CSD_SDV2       *CsdSDV2;
+
+  Status = EFI_SUCCESS;
+
+  switch (CardData->CSDRegister.TRAN_SPEED & 0x7) {
+    case 0:
+      Frequency = 100 * 1000;
+      break;
+
+    case 1:
+      Frequency = 1 * 1000 * 1000;
+      break;
+
+    case 2:
+      Frequency = 10 * 1000 * 1000;
+      break;
+
+    case 3:
+      Frequency = 100 * 1000 * 1000;
+      break;
+
+    default:
+      DEBUG ((EFI_D_ERROR, "Invalid CSD TRAN_SPEED Frequency: 0x%x\n", CardData->CSDRegister.TRAN_SPEED & 0x7));
+      Status = EFI_INVALID_PARAMETER;
+      goto Exit;
+  }
+
+  switch ((CardData->CSDRegister.TRAN_SPEED >> 3) & 0xF) {
+    case 1:
+      Multiple = 10;
+      break;
+
+    case 2:
+      Multiple = 12;
+      break;
+
+    case 3:
+      Multiple = 13;
+      break;
+
+    case 4:
+      Multiple = 15;
+      break;
+
+    case 5:
+      Multiple = 20;
+      break;
+
+    case 6:
+      if (CardData->CardType == MMCCard) {
+        Multiple = 26;
+      } else {
+        Multiple = 25;
+      }
+      break;
+
+    case 7:
+      Multiple = 30;
+      break;
+
+    case 8:
+      Multiple = 35;
+      break;
+
+    case 9:
+      Multiple = 40;
+      break;
+
+    case 10:
+      Multiple = 45;
+      break;
+
+    case 11:
+      if (CardData->CardType == MMCCard) {
+        Multiple = 52;
+      } else {
+        Multiple = 50;
+      }
+      break;
+
+    case 12:
+      Multiple = 55;
+      break;
+
+    case 13:
+      Multiple = 60;
+      break;
+
+    case 14:
+      Multiple = 70;
+      break;
+
+    case 15:
+      Multiple = 80;
+      break;
+
+    default:
+      DEBUG ((EFI_D_ERROR, "CalculateCardParameter: Invalid CSD TRAN_SPEED Multiple: 0x%x\n", CardData->CSDRegister.TRAN_SPEED >> 3));
+      Status = EFI_INVALID_PARAMETER;
+      goto Exit;
+  }
+
+  Frequency = Frequency * Multiple / 10;
+  CardData->MaxFrequency = Frequency;
+
+  if ((CardData->ExtCSDRegister.CARD_TYPE & BIT2) ||
+      (CardData->ExtCSDRegister.CARD_TYPE & BIT3)) {
+    CardData->BlockLen = 512;
+  } else {
+    CardData->BlockLen = 1 << CardData->CSDRegister.READ_BL_LEN;
+  }
+
+  if (CardData->CardType == SdMemoryCard2High) {
+    ASSERT(CardData->CSDRegister.CSD_STRUCTURE == 1);
+    CsdSDV2 = (CSD_SDV2 *) &CardData->CSDRegister;
+    //
+    // the K here means 1024 not 1000
+    //
+    CardData->BlockNumber = DivU64x32 (MultU64x32 (CsdSDV2->C_SIZE + 1, 512 * 1024) , CardData->BlockLen);
+  } else {
+    //
+    // For MMC card > 2G, the block number will be recaculate later
+    //
+    CSize = CardData->CSDRegister.C_SIZELow2 | (CardData->CSDRegister.C_SIZEHigh10 << 2);
+    CardData->BlockNumber = MultU64x32 (LShiftU64 (1, CardData->CSDRegister.C_SIZE_MULT + 2), CSize + 1);
+  }
+
+  //
+  //For >= 2G card, BlockLen may be 1024, but the transfer size is still 512 bytes
+  //
+  if (CardData->BlockLen > 512) {
+    CardData->BlockNumber = DivU64x32 (MultU64x32 (CardData->BlockNumber, CardData->BlockLen), 512);
+    CardData->BlockLen    = 512;
+  }
+
+  DEBUG ((DEBUG_INFO, "CalculateCardParameter: Card Size: 0x%lx\n", MultU64x32 (CardData->BlockNumber, CardData->BlockLen)
+    ));
+
+Exit:
+  return Status;
+}
+
+
+/**
+  Test the bus width setting for MMC card
+  It is used only for verification purpose
+
+  @param[in]  CardData                Pointer to CARD_DATA
+  @param[in]  Width                   1, 4, 8 bits
+
+  @retval     EFI_INVALID_PARAMETER
+  @retval     EFI_UNSUPPORTED
+  @retval     EFI_SUCCESS
+
+**/
+EFI_STATUS
+MMCCardBusWidthTest (
+  IN  CARD_DATA             *CardData,
+  IN  UINT32                Width
+  )
+{
+  EFI_STATUS                 Status;
+  EFI_MMC_HOST_IO_PROTOCOL   *MmcHostIo;
+  UINT64                     Data;
+  UINT64                     Value;
+
+  if (CardData == NULL) {
+    ASSERT(CardData != NULL);
+    return EFI_INVALID_PARAMETER;
+  }
+
+  MmcHostIo = CardData->MmcHostIo;
+  Value = 0;
+
+  switch (Width) {
+    case 1:
+      Data = 0x80;
+      break;
+
+    case 4:
+      Data = 0x5A;
+      break;
+
+    case 8:
+      Data = 0xAA55;
+      break;
+
+    default:
+      Status = EFI_INVALID_PARAMETER;
+      goto Exit;
+  }
+
+  CopyMem (CardData->AlignedBuffer, &Data, Width);
+  Status  = SendCommand (
+              MmcHostIo,
+              BUSTEST_W,
+              0,
+              OutData,
+              CardData->AlignedBuffer,
+              Width,
+              ResponseR1,
+              TIMEOUT_COMMAND,
+              (UINT32 *) &(CardData->CardStatus)
+              );
+
+  if (EFI_ERROR (Status)) {
+    goto Exit;
+  }
+
+  Data = 0;
+  gBS->Stall(10000);
+
+  Status  = SendCommand (
+              MmcHostIo,
+              BUSTEST_R,
+              0,
+              InData,
+              CardData->AlignedBuffer,
+              Width,
+              ResponseR1,
+              TIMEOUT_COMMAND,
+              (UINT32 *) &(CardData->CardStatus)
+              );
+
+  if (EFI_ERROR (Status)) {
+    goto Exit;
+  }
+  CopyMem (&Data, CardData->AlignedBuffer, Width);
+
+  switch (Width) {
+    case 1:
+      Value = (~(Data ^ 0x80)) & 0xC0;
+      break;
+    case 4:
+      Value = (~(Data ^ 0x5A)) & 0xFF;
+      break;
+    case 8:
+      Value = (~(Data ^ 0xAA55)) & 0xFFFF;
+      break;
+  }
+
+  if (Value == 0) {
+    Status = EFI_SUCCESS;
+  } else {
+    Status = EFI_UNSUPPORTED;
+  }
+
+Exit:
+  return Status;
+}
+
+
+/**
+  This function can detect these card types
+  1. MMC card
+  2. SD 1.1 card
+  3. SD 2.0 standard card
+  3. SD 2.0 high capacity card
+
+  @param[in]  CardData               Pointer to CARD_DATA
+
+  @retval     EFI_INVALID_PARAMETER
+  @retval     EFI_UNSUPPORTED
+  @retval     EFI_SUCCESS
+
+**/
+EFI_STATUS
+GetCardType (
+  IN  CARD_DATA              *CardData
+  )
+{
+  EFI_STATUS                 Status;
+  EFI_MMC_HOST_IO_PROTOCOL   *MmcHostIo;
+  UINT32                     TimeOut=5000;
+  MmcHostIo = CardData->MmcHostIo;
+
+  CardData->CardType = MMCCard;
+  MmcHostIo->SetupDevice (MmcHostIo);
+
+  //
+  // To bring back the normal MMC card to work
+  // after sending the SD command. Otherwise some
+  // card could not work
+  //
+  Status  = SendCommand (
+              MmcHostIo,
+              GO_IDLE_STATE,
+              0,
+              NoData,
+              NULL,
+              0,
+              ResponseNo,
+              TIMEOUT_COMMAND,
+              NULL
+              );
+
+  if (EFI_ERROR (Status)) {
+    DEBUG ((EFI_D_ERROR, "GO_IDLE_STATE Fail Status = 0x%x\n", Status));
+  }
+
+  DEBUG (( DEBUG_INFO, "Sending first CMD1.\n"));
+
+  //
+  // CE-ATA device needs long delay
+  //
+  gBS->Stall (1 * 1000);
+
+  //
+  // Get OCR register to check voltage support, first time the OCR is 0
+  //
+  DEBUG (( DEBUG_INFO, "Sending first CMD1  with 0 .\n"));
+  Status  = SendCommand (
+              MmcHostIo,
+              SEND_OP_COND,
+              0x0,
+              NoData,
+              NULL,
+              0,
+              ResponseR3,
+              TIMEOUT_COMMAND,
+              (UINT32 *) &(CardData->OCRRegister)
+              );
+
+  DEBUG ((DEBUG_INFO, "Check OCR register for busy 0x%x\n", *((UINT32 *) &CardData->OCRRegister )));
+
+  gBS->Stall (1 * 1000);
+
+  while (CardData->OCRRegister.Busy != 1) {
+    CardData->OCRRegister.AccessMode = 2;
+    Status  = SendCommand (
+                MmcHostIo,
+                SEND_OP_COND,
+                *(UINT32 *) &(CardData->OCRRegister),
+                NoData,
+                NULL,
+                0,
+                ResponseR3,
+                TIMEOUT_COMMAND,
+                (UINT32 *) &(CardData->OCRRegister)
+                );
+
+    if (EFI_ERROR (Status)) {
+      DEBUG ((EFI_D_ERROR, "SEND_OP_COND Fail Status = 0x%x\n", Status));
+      goto Exit;
+    }
+
+    gBS->Stall (1 * 1000);
+    TimeOut--;
+    if (TimeOut == 0) {
+      DEBUG ((EFI_D_ERROR, "Card is always in busy state\n"));
+      Status = EFI_TIMEOUT;
+      goto Exit;
+    }
+  }
+
+Exit:
+  return Status;
+}
+
+
+/**
+  MMC card high/low voltage selection function
+
+  @param[in]  CardData                 Pointer to CARD_DATA
+
+  @retval     EFI_INVALID_PARAMETER
+  @retval     EFI_UNSUPPORTED
+  @retval     EFI_SUCCESS
+  @retval     EFI_BAD_BUFFER_SIZE
+
+**/
+EFI_STATUS
+MMCCardVoltageSelection (
+  IN  CARD_DATA              *CardData
+  )
+{
+  EFI_STATUS                 Status;
+  EFI_MMC_HOST_IO_PROTOCOL   *MmcHostIo;
+  UINT8                      Index;
+  UINT8                      Retry;
+  UINT32                     TimeOut;
+
+  MmcHostIo = CardData->MmcHostIo;
+  Status   = EFI_SUCCESS;
+
+  if (FALSE) {
+    //
+    //First try the high voltage, then if supported choose the low voltage
+    //
+    for (Index = 0; Index < 2; Index++) {
+      for (Retry = 0; Retry < 3; Retry++) {
+        //
+        // To bring back the normal MMC card to work
+        // after sending the SD command. Otherwise some
+        // card could not work
+        //
+        Status  = SendCommand (
+                    MmcHostIo,
+                    GO_IDLE_STATE,
+                    0,
+                    NoData,
+                    NULL,
+                    0,
+                    ResponseNo,
+                    TIMEOUT_COMMAND,
+                    NULL
+                    );
+
+        if (EFI_ERROR (Status)) {
+          DEBUG ((EFI_D_ERROR, "GO_IDLE_STATE Fail Status = 0x%x\n", Status));
+          continue;
+        }
+        //
+        //CE-ATA device needs long delay
+        //
+        gBS->Stall ((Retry + 1) * 50 * 1000);
+
+        //
+        //Get OCR register to check voltage support, first time the OCR is 0
+        //
+        Status  = SendCommand (
+                    MmcHostIo,
+                    SEND_OP_COND,
+                    0,
+                    NoData,
+                    NULL,
+                    0,
+                    ResponseR3,
+                    TIMEOUT_COMMAND,
+                    (UINT32 *) &(CardData->OCRRegister)
+                    );
+
+        if (!EFI_ERROR (Status)) {
+          break;
+        }
+      }
+
+      if (Retry == 3) {
+        DEBUG ((EFI_D_ERROR, "SEND_OP_COND Fail Status = 0x%x\n", Status));
+        Status = EFI_DEVICE_ERROR;
+        goto Exit;
+      }
+
+      if (CardData->OCRRegister.V170_V195 == 1) {
+        CardData->DualVoltage = TRUE;
+      }
+      if (CardData->OCRRegister.V270_V360 != 0x1F &&
+          CardData->OCRRegister.V200_V260 != 0) {
+        DEBUG ((EFI_D_ERROR, "Incompatiable voltage device\n"));
+        PutCardInactive (CardData);
+        Status = EFI_INCOMPATIBLE_VERSION;
+        goto Exit;
+      }
+
+      if (Index == 0) {
+        //
+        // Choose the high voltage first
+        //
+        CardData->OCRRegister.V170_V195 = 0;
+      } else {
+        //
+        // Choose the low voltage
+        //
+        CardData->OCRRegister.V170_V195 = 1;
+        CardData->OCRRegister.V270_V360 = 0;
+      }
+
+      //
+      // Set sector mode
+      //
+      CardData->OCRRegister.AccessMode |= 2;
+
+      //
+      // TimeOut Value, 5000 * 100 * 1000 = 5 s
+      //
+      TimeOut = 5000;
+
+      do {
+        Status  = SendCommand (
+                    MmcHostIo,
+                    SEND_OP_COND,
+                    *(UINT32 *) &(CardData->OCRRegister),
+                    NoData,
+                    NULL,
+                    0,
+                    ResponseR3,
+                    TIMEOUT_COMMAND,
+                    (UINT32 *) &(CardData->OCRRegister)
+                    );
+
+        if (EFI_ERROR (Status)) {
+          DEBUG ((EFI_D_ERROR, "SEND_OP_COND Fail Status = 0x%x\n", Status));
+          goto Exit;
+        }
+
+        gBS->Stall (1 * 1000);
+        TimeOut--;
+        if (TimeOut == 0) {
+          DEBUG ((EFI_D_ERROR, "Card is always in busy state\n"));
+          Status = EFI_TIMEOUT;
+          goto Exit;
+        }
+      } while (CardData->OCRRegister.Busy != 1);
+
+      if (CardData->DualVoltage == TRUE && MmcHostIo->HostCapability.V18Support == TRUE) {
+        //
+        //Power Off the card and then power on into low voltage
+        //
+        MmcHostIo->SetHostVoltage (MmcHostIo, 0);
+        gBS->Stall (1 * 1000);
+        MmcHostIo->SetHostVoltage (MmcHostIo, 18);
+      } else {
+        //
+        //Not support the low voltage, exit
+        //
+        break;
+      }
+    }
+  }
+
+Exit:
+  return Status;
+}
+
+
+/**
+  This function set the bus and device width for MMC card
+
+  @param[in]  CardData                Pointer to CARD_DATA
+  @param[in]  BusWidth                1, 4, 8 bits
+
+  @retval     EFI_INVALID_PARAMETER
+  @retval     EFI_UNSUPPORTED
+  @retval     EFI_SUCCESS
+
+**/
+EFI_STATUS
+MMCCardSetBusWidth (
+  IN  CARD_DATA              *CardData,
+  IN  UINT8                  BusWidth
+  )
+{
+  EFI_STATUS                 Status;
+  EFI_MMC_HOST_IO_PROTOCOL   *MmcHostIo;
+  SWITCH_ARGUMENT            SwitchArgument;
+  UINT8                      Value;
+
+  MmcHostIo = CardData->MmcHostIo;
+  Value = 0;
+  switch (BusWidth) {
+    case 28:    //20 in 28 indicates DDR in 8 bit bus
+      Value = 6;
+      break;
+
+    case 24:    //20 in 24 indicates DDR in 4 bit bus
+      Value = 5;
+      break;
+
+    case 8:
+      Value = 2;
+      break;
+
+    case 4:
+      Value = 1;
+      break;
+
+    case 1:
+      Value = 0;
+      break;
+
+    default:
+     ASSERT (0);
+  }
+
+  //
+  // HS_TIMING must be set to 0x1 before setting BUS_WIDTH for dual data rate operation (values 5 or 6)
+  //
+  if (Value == 5 || Value == 6 ) {
+    ZeroMem(&SwitchArgument, sizeof (SWITCH_ARGUMENT));
+    SwitchArgument.CmdSet = 0;
+    SwitchArgument.Value  = 0x1;
+    SwitchArgument.Index  = (UINT32) ((UINTN)
+    (&(CardData->ExtCSDRegister.HS_TIMING)) - (UINTN) (&(CardData->ExtCSDRegister)));
+    SwitchArgument.Access = WriteByte_Mode;
+    Status  = SendCommand (
+                MmcHostIo,
+                SWITCH,
+                *(UINT32 *) &SwitchArgument,
+                NoData,
+                NULL,
+                0,
+                ResponseR1b,
+                TIMEOUT_COMMAND,
+                (UINT32 *) &(CardData->CardStatus)
+                );
+
+    if (!EFI_ERROR (Status)) {
+     Status  = SendCommand (
+                 MmcHostIo,
+                 SEND_STATUS,
+                 (CardData->Address << 16),
+                 NoData,
+                 NULL,
+                 0,
+                 ResponseR1,
+                 TIMEOUT_COMMAND,
+                 (UINT32 *) &(CardData->CardStatus)
+                 );
+    } else {
+      DEBUG ((DEBUG_ERROR, "SWITCH Fail in HS Timing setting\n"));
+    }
+  }
+
+  ZeroMem (&SwitchArgument, sizeof (SWITCH_ARGUMENT));
+  SwitchArgument.CmdSet = 0;
+  SwitchArgument.Value  = Value;
+  SwitchArgument.Index  = (UINT32) ((UINTN)
+                          (&(CardData->ExtCSDRegister.BUS_WIDTH)) - (UINTN) (&(CardData->ExtCSDRegister)));
+  SwitchArgument.Access = WriteByte_Mode;
+  Status  = SendCommand (
+              MmcHostIo,
+              SWITCH,
+              *(UINT32 *) &SwitchArgument,
+              NoData,
+              NULL,
+              0,
+              ResponseR1b,
+              TIMEOUT_COMMAND,
+              (UINT32 *) &(CardData->CardStatus)
+              );
+
+  if (!EFI_ERROR (Status)) {
+    Status  = SendCommand (
+                MmcHostIo,
+                SEND_STATUS,
+                (CardData->Address << 16),
+                NoData,
+                NULL,
+                0,
+                ResponseR1,
+                TIMEOUT_COMMAND,
+                (UINT32 *) &(CardData->CardStatus)
+                );
+
+    if (EFI_ERROR (Status)) {
+      DEBUG ((EFI_D_ERROR, "SWITCH %d bits Fail\n", BusWidth));
+      goto Exit;
+    } else {
+      if ((BusWidth == 24) || (BusWidth == 28)) {
+        Status = MmcHostIo->SetBusWidth (MmcHostIo, BusWidth - 20);
+      } else {
+        Status = MmcHostIo->SetBusWidth (MmcHostIo, BusWidth);
+      }
+      if (EFI_ERROR (Status)) {
+        goto Exit;
+      }
+
+      gBS->Stall (5 * 1000);
+    }
+  }
+  if ((BusWidth == 24) || (BusWidth == 28)) {
+    goto Exit;
+  } else {
+    Status = MMCCardBusWidthTest (CardData, BusWidth);
+  }
+  if (EFI_ERROR (Status)) {
+    DEBUG ((EFI_D_ERROR, "MMCCardBusWidthTest %d bit Fail\n", BusWidth));
+    goto Exit;
+  }
+
+  CardData->CurrentBusWidth = BusWidth;
+
+Exit:
+  return Status;
+}
+
+
+/**
+  MMC/SD card init function
+
+  @param[in]  CardData                 Pointer to CARD_DATA
+
+  @retval     EFI_INVALID_PARAMETER
+  @retval     EFI_UNSUPPORTED
+  @retval     EFI_SUCCESS
+  @retval     EFI_BAD_BUFFER_SIZE
+
+**/
+EFI_STATUS
+MMCSDCardInit (
+  IN  CARD_DATA              *CardData
+  )
+{
+  EFI_STATUS                 Status;
+  EFI_MMC_HOST_IO_PROTOCOL   *MmcHostIo;
+  SWITCH_ARGUMENT            SwitchArgument;
+  UINT32                     Data;
+  UINT32                     Argument;
+  UINT32                     HsTimingValue;
+  UINT8                      PowerValue;
+  UINT8                      DoubleSpeed;
+  UINTN                      Offset;
+
+  if (CardData == NULL) {
+    ASSERT (CardData != NULL);
+    return EFI_INVALID_PARAMETER;
+  }
+  MmcHostIo = CardData->MmcHostIo;
+  CardData->CurrentBusWidth = 1;
+
+  Status = GetCardType (CardData);
+  if (EFI_ERROR (Status)) {
+    DEBUG ((EFI_D_ERROR, "GetCardType -> %r\n", Status));
+    goto Exit;
+  }
+
+  ASSERT (CardData->CardType != UnknownCard);
+  //
+  //MMC, SD card need host auto stop command support
+  //
+  MmcHostIo->EnableAutoStopCmd (MmcHostIo, TRUE);
+
+
+  //
+  // Get CID Register, but the info is not used currently
+  //
+  Status  = SendCommand (
+              MmcHostIo,
+              ALL_SEND_CID,
+              0,
+              NoData,
+              NULL,
+              0,
+              ResponseR2,
+              TIMEOUT_COMMAND,
+              (UINT32 *) &(CardData->CIDRegister)
+              );
+
+  PcdSet8S (PcdEmmcManufacturerId, CardData->CIDRegister.MID);
+  PcdSet32S (PcdProductSerialNumber, CardData->CIDRegister.PSN);
+
+  if (EFI_ERROR (Status)) {
+    DEBUG ((EFI_D_ERROR, "ALL_SEND_CID -> %r\n", Status));
+    goto Exit;
+  }
+
+  //
+  //SET_RELATIVE_ADDR
+  //
+  if (CardData->CardType == MMCCard) {
+    CardData->Address = 1;
+    //
+    // Set RCA Register
+    //
+    Status  = SendCommand (
+                MmcHostIo,
+                SET_RELATIVE_ADDR,
+                (CardData->Address << 16),
+                NoData,
+                NULL,
+                0,
+                ResponseR1,
+                TIMEOUT_COMMAND,
+                (UINT32 *) &(CardData->CardStatus)
+                );
+
+    if (EFI_ERROR (Status)) {
+      DEBUG ((EFI_D_ERROR, "SET_RELATIVE_ADDR -> %r\n", Status));
+      goto Exit;
+    }
+  }
+
+  //
+  // Get CSD Register
+  //
+  Status  = SendCommand (
+              MmcHostIo,
+              SEND_CSD,
+              (CardData->Address << 16),
+              NoData,
+              NULL,
+              0,
+              ResponseR2,
+              TIMEOUT_COMMAND,
+              (UINT32 *) &(CardData->CSDRegister)
+              );
+
+  if (EFI_ERROR (Status)) {
+    DEBUG ((EFI_D_ERROR, "SEND_CSD -> %r\n", Status));
+    goto Exit;
+  }
+
+  MmcDecodeCSD(&CardData->CSDRegister);
+
+  Status = CalculateCardParameter (CardData);
+  if (EFI_ERROR (Status)) {
+    DEBUG ((EFI_D_ERROR, "CalculateCardParameter -> %r\n", Status));
+    goto Exit;
+  }
+
+  //
+  // Put the card into tran state
+  //
+  Status = SendCommand (
+             MmcHostIo,
+             SELECT_DESELECT_CARD,
+             (CardData->Address << 16),
+             NoData,
+             NULL,
+             0,
+             ResponseR1,
+             TIMEOUT_COMMAND,
+             (UINT32 *) &(CardData->CardStatus)
+             );
+
+  if (EFI_ERROR (Status)) {
+    DEBUG ((EFI_D_ERROR, "SELECT_DESELECT_CARD -> %r\n", Status));
+    goto Exit;
+  }
+
+  Status  = SendCommand (
+              MmcHostIo,
+              SEND_STATUS,
+              (CardData->Address << 16),
+              NoData,
+              NULL,
+              0,
+              ResponseR1,
+              TIMEOUT_COMMAND,
+              (UINT32 *) &(CardData->CardStatus)
+              );
+
+  if (EFI_ERROR (Status)) {
+    DEBUG ((EFI_D_ERROR, "SELECT_DESELECT_CARD SEND_STATUS Fail Status = 0x%x\n", Status));
+    goto Exit;
+  }
+
+  if (CardData->CardType == MMCCard) {
+    //
+    // Only V4.0 and above supports more than 1 bits and high speed
+    //
+    if (CardData->CSDRegister.SPEC_VERS >= 4) {
+      Offset = OFFSET_OF (EXT_CSD, ERASE_GROUP_DEF);
+      Status = MmcSetExtCsd8 (CardData, (UINT8) Offset, 0x01);
+      //
+      // Get ExtCSDRegister
+      //
+      Status  = SendCommand (
+                  MmcHostIo,
+                  SEND_EXT_CSD,
+                  0,
+                  InData,
+                  CardData->AlignedBuffer,
+                  sizeof (EXT_CSD),
+                  ResponseR1,
+                  TIMEOUT_DATA,
+                  (UINT32 *) &(CardData->CardStatus)
+                  );
+
+      if (EFI_ERROR (Status)) {
+        DEBUG ((EFI_D_ERROR, "SEND_EXT_CSD -> %r\n", Status));
+        goto Exit;
+      }
+
+      CopyMem (&(CardData->ExtCSDRegister), CardData->AlignedBuffer, sizeof (EXT_CSD));
+
+      MmcDecodeExtCSD (&CardData->ExtCSDRegister);
+
+      //
+      // Recaculate the block number for >2G MMC card
+      //
+      Data  = (CardData->ExtCSDRegister.SEC_COUNT[0]) |
+              (CardData->ExtCSDRegister.SEC_COUNT[1] << 8) |
+              (CardData->ExtCSDRegister.SEC_COUNT[2] << 16) |
+              (CardData->ExtCSDRegister.SEC_COUNT[3] << 24);
+
+      if (Data != 0) {
+        CardData->BlockNumber = Data;
+      }
+      DEBUG ((DEBUG_INFO, "CardData->BlockNumber  %d\n", Data));
+
+      //
+      // Check the DDR setting
+      //
+      DoubleSpeed = 0 ;
+      DEBUG ((DEBUG_INFO, "CardData->ExtCSDRegister.CARD_TYPE -> %d\n", (UINTN) CardData->ExtCSDRegister.CARD_TYPE));
+      if (CardData->ExtCSDRegister.CARD_TYPE & BIT0) {
+        DEBUG ((DEBUG_INFO, "High-Speed e MMC @ 26MHz - at rated device voltage(s) supported\n"));
+      }
+      if (CardData->ExtCSDRegister.CARD_TYPE & BIT1) {
+        DEBUG ((DEBUG_INFO, "High-Speed e MMC @ 52MHz - at rated device voltage(s) supported\n"));
+      }
+      if (CardData->ExtCSDRegister.CARD_TYPE & BIT2) {
+        DEBUG ((DEBUG_INFO, "High-Speed Dual Data Rate e MMC @ 52MHz - 1.8V or 3V I/O supported\n"));
+      }
+      if (CardData->ExtCSDRegister.CARD_TYPE & BIT3) {
+        DEBUG ((DEBUG_INFO, "High-Speed Dual Data Rate e MMC @ 52MHz - 1.2V I/O supported\n"));
+      }
+      if (CardData->ExtCSDRegister.CARD_TYPE & BIT4) {
+        DEBUG ((DEBUG_INFO, "HS200 Single Data Rate e MMC @ 200 MHz - 1.8V I/O supported\n"));
+      }
+      if (CardData->ExtCSDRegister.CARD_TYPE & BIT5) {
+        DEBUG ((DEBUG_INFO, "HS200 Single Data Rate e MMC @ 200 MHz - 1.2V I/O supported\n"));
+      }
+      if (CardData->ExtCSDRegister.CARD_TYPE & BIT6) {
+        DEBUG ((DEBUG_INFO, "HS400 Dual Data Rate e MMC @ 200MHz - 1.8V I/O supported\n"));
+      }
+      if (CardData->ExtCSDRegister.CARD_TYPE & BIT7) {
+        DEBUG ((DEBUG_INFO, "HS400 Dual Data Rate e MMC @ 200MHz - 1.2V I/O supported\n"));
+      }
+
+      if ((CardData->ExtCSDRegister.CARD_TYPE & BIT2) || (CardData->ExtCSDRegister.CARD_TYPE & BIT3)) {
+        DEBUG ((DEBUG_INFO, "Card support DDR\n"));
+        DoubleSpeed = 20;   //Add 20 for double speed, decoded in MMCCardSetBusWidth()
+      }
+
+      DEBUG ((EFI_D_INFO, "%a(%d): %a() no more FPGA doublespeed workaround needed\n", __FILE__, __LINE__, __FUNCTION__));
+
+      if (MmcHostIo->HostCapability.HighSpeedSupport) {
+
+        HsTimingValue = 1;
+
+        //
+        // Change to high frequency mode
+        //
+        ZeroMem (&SwitchArgument, sizeof (SWITCH_ARGUMENT));
+        SwitchArgument.CmdSet = 0;
+        SwitchArgument.Value  = HsTimingValue;
+        SwitchArgument.Index  = (UINT32) ((UINTN)
+                                (&(CardData->ExtCSDRegister.HS_TIMING)) - (UINTN) (&(CardData->ExtCSDRegister)));
+        SwitchArgument.Access = WriteByte_Mode;
+        Status  = SendCommand (
+                    CardData->MmcHostIo,
+                    SWITCH,
+                    *(UINT32 *) &SwitchArgument,
+                    NoData,
+                    NULL,
+                    0,
+                    ResponseR1b,
+                    TIMEOUT_COMMAND,
+                    (UINT32 *) &(CardData->CardStatus)
+                    );
+
+        if (EFI_ERROR (Status)) {
+          DEBUG ((EFI_D_ERROR, "SWITCH frequency -> %r\n", Status));
+        }
+
+        if (!EFI_ERROR (Status)) {
+          Status  = SendCommand (
+                      MmcHostIo,
+                      SEND_STATUS,
+                      (CardData->Address << 16),
+                      NoData,
+                      NULL,
+                      0,
+                      ResponseR1,
+                      TIMEOUT_COMMAND,
+                      (UINT32 *) &(CardData->CardStatus)
+                      );
+
+          if (!EFI_ERROR (Status)) {
+            //
+            // Enable the high speed mode
+            //
+             if (DoubleSpeed != 0) {
+               Status = MmcHostIo->SetHostDdrMode (MmcHostIo, TRUE);
+              DEBUG ((DEBUG_INFO, "Set to DDR50 mode \n", Status));
+             } else  {
+                 Status = MmcHostIo->SetHostSpeedMode (MmcHostIo, 1);
+                DEBUG ((DEBUG_ERROR, "Set to HS mode \n", Status));
+               }
+
+             if (EFI_ERROR (Status)) {
+              goto Exit;
+             }
+            //
+            // Change host clock
+            //
+            if ((CardData->ExtCSDRegister.CARD_TYPE & BIT1) != 0) {
+              Status = MmcHostIo->SetClockFrequency (MmcHostIo, FREQUENCY_MMC_PP_HIGH);
+            } else if ((CardData->ExtCSDRegister.CARD_TYPE & BIT0) != 0) {
+              Status = MmcHostIo->SetClockFrequency (MmcHostIo, FREQUENCY_MMC_PP);
+            } else {
+              Status = EFI_UNSUPPORTED;
+            }
+
+            if (EFI_ERROR (Status)) {
+              goto Exit;
+            }
+
+            //
+            // It seems no need to stall after changing bus freqeuncy.
+            // It is said that the freqeuncy can be changed at any time. Just appends 8 clocks after command.
+            // But SetClock alreay has delay.
+            //
+          }
+        }
+      }
+
+      //
+      // Prefer wide bus width for performance
+      //
+      //
+      // Set to BusWidth bits mode, only version 4.0 or above support more than 1 bits
+      //
+      if (MmcHostIo->HostCapability.BusWidth8 == 1) {
+        Status = MMCCardSetBusWidth (CardData, DoubleSpeed + 8);
+        if (EFI_ERROR (Status)) {
+          //
+          // CE-ATA may support 8 bits and 4 bits, but has no software method for detection
+          //
+          Status = MMCCardSetBusWidth (CardData, DoubleSpeed + 4);
+          if (EFI_ERROR (Status)) {
+            goto Exit;
+          }
+        }
+      } else if (MmcHostIo->HostCapability.BusWidth4 == 1) {
+        Status = MMCCardSetBusWidth (CardData, DoubleSpeed + 4);
+        if (EFI_ERROR (Status)) {
+          goto Exit;
+        }
+      }
+
+      PowerValue = 0;
+
+      if (CardData->CurrentBusWidth == 8) {
+        if ((CardData->ExtCSDRegister.CARD_TYPE & BIT1) != 0) {
+          PowerValue = CardData->ExtCSDRegister.PWR_CL_52_360;
+          PowerValue = PowerValue >> 4;
+        } else if ((CardData->ExtCSDRegister.CARD_TYPE & BIT0) != 0) {
+          PowerValue = CardData->ExtCSDRegister.PWR_CL_26_360;
+          PowerValue = PowerValue >> 4;
+        }
+      } else if (CardData->CurrentBusWidth == 4) {
+        if ((CardData->ExtCSDRegister.CARD_TYPE & BIT1) != 0) {
+          PowerValue = CardData->ExtCSDRegister.PWR_CL_52_360;
+          PowerValue = PowerValue & 0xF;
+        } else if ((CardData->ExtCSDRegister.CARD_TYPE & BIT0) != 0) {
+          PowerValue = CardData->ExtCSDRegister.PWR_CL_26_360;
+          PowerValue = PowerValue & 0xF;
+        }
+      }
+
+      if (PowerValue != 0) {
+        //
+        // Update Power Class
+        //
+        ZeroMem (&SwitchArgument, sizeof (SWITCH_ARGUMENT));
+        SwitchArgument.CmdSet = 0;
+        SwitchArgument.Value  = PowerValue;
+        SwitchArgument.Index  = (UINT32) ((UINTN)
+                                (&(CardData->ExtCSDRegister.POWER_CLASS)) - (UINTN) (&(CardData->ExtCSDRegister)));
+        SwitchArgument.Access = WriteByte_Mode;
+        Status  = SendCommand (
+                    MmcHostIo,
+                    SWITCH,
+                    *(UINT32 *) &SwitchArgument,
+                    NoData,
+                    NULL,
+                    0,
+                    ResponseR1b,
+                    TIMEOUT_COMMAND,
+                    (UINT32 *) &(CardData->CardStatus)
+                    );
+
+        if (!EFI_ERROR (Status)) {
+          Status  = SendCommand (
+                      MmcHostIo,
+                      SEND_STATUS,
+                      (CardData->Address << 16),
+                      NoData,
+                      NULL,
+                      0,
+                      ResponseR1,
+                      TIMEOUT_COMMAND,
+                      (UINT32 *) &(CardData->CardStatus)
+                      );
+
+          if (EFI_ERROR (Status)) {
+            DEBUG ((EFI_D_ERROR, "SWITCH Power Class -> %r\n", Status));
+          }
+
+        }
+      }
+    } else {
+      DEBUG ((EFI_D_ERROR, "MMC Card version %d only supportes 1 bits at lower transfer speed\n", CardData->CSDRegister.SPEC_VERS));
+    }
+
+    //
+    // Register for Ready to Boot event to enable Write protection
+    //
+    Status = gBS->CreateEventEx (
+                    EVT_NOTIFY_SIGNAL,
+                    TPL_CALLBACK,
+                    SetEmmcWpOnEvent,
+                    CardData,
+                    &gEfiEventReadyToBootGuid,
+                    &mSetEmmcWpOnEvent
+                    );
+
+  } else {
+    //
+    // Pin 1, at power up this line has a 50KOhm pull up enabled in the card.
+    // This pull-up should be disconnected by the user, during regular data transfer,
+    // with SET_CLR_CARD_DETECT (ACMD42) command
+    //
+    Status  = SendAppCommand (
+                CardData,
+                SET_CLR_CARD_DETECT,
+                0,
+                NoData,
+                NULL,
+                0,
+                ResponseR1,
+                TIMEOUT_COMMAND,
+                (UINT32 *) &(CardData->CardStatus)
+                );
+
+    if (EFI_ERROR (Status)) {
+      DEBUG ((EFI_D_ERROR, "SET_CLR_CARD_DETECT Fail -> %r\n", Status));
+      goto Exit;
+    }
+
+    //
+    // Set Bus Width to 4
+    //
+    Status  = SendAppCommand (
+                CardData,
+                SET_BUS_WIDTH,
+                SD_BUS_WIDTH_4,
+                NoData,
+                NULL,
+                0,
+                ResponseR1,
+                TIMEOUT_COMMAND,
+                (UINT32 *) &(CardData->CardStatus)
+                );
+
+    if (EFI_ERROR (Status)) {
+      DEBUG ((EFI_D_ERROR, "SET_BUS_WIDTH 4 bits -> %r\n", Status));
+      goto Exit;
+    }
+
+    Status = MmcHostIo->SetBusWidth (MmcHostIo, 4);
+    if (EFI_ERROR (Status)) {
+      goto Exit;
+    }
+    CardData->CurrentBusWidth = 4;
+
+    if ((MmcHostIo->HostCapability.HighSpeedSupport == FALSE) ||
+        ((CardData->CSDRegister.CCC & BIT10) != BIT10)) {
+      //
+      // Host must support high speed
+      // Card must support Switch function
+      //
+      goto Exit;
+    }
+
+    //
+    // Mode = 0, group 1, function 1, check operation
+    //
+    Argument = 0xFFFF01;
+    ZeroMem (&CardData->SwitchStatus, sizeof (SWITCH_STATUS));
+
+    Status  = SendCommand (
+                MmcHostIo,
+                SWITCH_FUNC,
+                Argument,
+                InData,
+                CardData->AlignedBuffer,
+                sizeof (SWITCH_STATUS),
+                ResponseR1,
+                TIMEOUT_COMMAND,
+                (UINT32 *) &(CardData->CardStatus)
+                );
+
+    if (EFI_ERROR (Status)) {
+      goto Exit;
+    }
+    CopyMem (&(CardData->SwitchStatus), CardData->AlignedBuffer, sizeof (SWITCH_STATUS));
+
+    if ((CardData->SwitchStatus.DataStructureVersion == 0x0) ||
+        ((CardData->SwitchStatus.Group1BusyStatus & BIT1) != BIT1)) {
+      //
+      // 1. SD 1.1 card does not suppport busy bit
+      // 2. Ready state
+      //
+      //
+      //
+      // Mode = 1, group 1, function 1, BIT31 set means set mode
+      //
+      Argument = 0xFFFF01 | BIT31;
+      ZeroMem (&CardData->SwitchStatus, sizeof (SWITCH_STATUS));
+
+      Status  = SendCommand (
+                  MmcHostIo,
+                  SWITCH_FUNC,
+                  Argument,
+                  InData,
+                  CardData->AlignedBuffer,
+                  sizeof (SWITCH_STATUS),
+                  ResponseR1,
+                  TIMEOUT_COMMAND,
+                  (UINT32 *) &(CardData->CardStatus)
+                  );
+
+      if (EFI_ERROR (Status)) {
+        goto Exit;
+      }
+      CopyMem (&(CardData->SwitchStatus), CardData->AlignedBuffer, sizeof (SWITCH_STATUS));
+
+      if ((CardData->SwitchStatus.DataStructureVersion == 0x0) ||
+          ((CardData->SwitchStatus.Group1BusyStatus & BIT1) != BIT1)) {
+        //
+        // 1. SD 1.1 card does not suppport busy bit
+        // 2. Ready state
+        //
+        //
+        // 8 clocks, (1/ 25M) * 8 ==> 320 us, so 1ms > 0.32 ms
+        //
+        gBS->Stall (1000);
+      }
+    }
+  }
+  if (!((CardData->ExtCSDRegister.CARD_TYPE & BIT2) ||
+        (CardData->ExtCSDRegister.CARD_TYPE & BIT3))) {
+    //
+    // Set Block Length, to improve compatibility in case of some cards
+    //
+    Status  = SendCommand (
+                MmcHostIo,
+                SET_BLOCKLEN,
+                512,
+                NoData,
+                NULL,
+                0,
+                ResponseR1,
+                TIMEOUT_COMMAND,
+                (UINT32 *) &(CardData->CardStatus)
+                );
+
+    if (EFI_ERROR (Status)) {
+      DEBUG ((EFI_D_ERROR, "SET_BLOCKLEN -> %r\n", Status));
+      goto Exit;
+    }
+  }
+  MmcHostIo->SetBlockLength (MmcHostIo, 512);
+
+Exit:
+  if (Status) {
+
+  }
+
+  return Status;
+}
+
+
+/**
+  MmcSelect
+
+  @param[in]  CardData      Pointer to CARD_DATA
+  @param[in]  Select
+
+  @retval     EFI_STATUS
+
+**/
+EFI_STATUS
+MmcSelect (
+  IN CARD_DATA     *CardData,
+  IN BOOLEAN       Select
+  )
+{
+  return SendCommand (
+           CardData->MmcHostIo,
+           SELECT_DESELECT_CARD,
+           Select ? (CardData->Address << 16) : ~(CardData->Address << 16),
+           NoData,
+           NULL,
+           0,
+           ResponseR1,
+           TIMEOUT_COMMAND,
+           (UINT32 *) &(CardData->CardStatus)
+           );
+}
+
+
+/**
+  MmcSendSwitch
+
+  @param[in]  CardData                 Pointer to CARD_DATA
+  @param[in]  SwitchArgument           Pointer to SWITCH_ARGUMENT
+
+  @retval     EFI_INVALID_PARAMETER
+  @retval     EFI_UNSUPPORTED
+  @retval     EFI_SUCCESS
+
+**/
+EFI_STATUS
+MmcSendSwitch (
+  IN  CARD_DATA              *CardData,
+  IN SWITCH_ARGUMENT         *SwitchArgument
+  )
+{
+  EFI_STATUS                 Status;
+  EFI_MMC_HOST_IO_PROTOCOL   *MmcHostIo;
+
+  MmcHostIo = CardData->MmcHostIo;
+
+  Status  = SendCommand (
+              MmcHostIo,
+              SWITCH,
+              *(UINT32 *) SwitchArgument,
+              NoData,
+              NULL,
+              0,
+              ResponseR1b,
+              TIMEOUT_DATA,
+              (UINT32 *) &(CardData->CardStatus)
+              );
+
+  if (!EFI_ERROR (Status)) {
+    Status  = SendCommand (
+                MmcHostIo,
+                SEND_STATUS,
+                (CardData->Address << 16),
+                NoData,
+                NULL,
+                0,
+                ResponseR1,
+                TIMEOUT_COMMAND,
+                (UINT32 *) &(CardData->CardStatus)
+                );
+
+    if (EFI_ERROR (Status)) {
+      DEBUG ((EFI_D_ERROR, "SWITCH FAILURE\n"));
+    }
+  }
+
+  return Status;
+}
+
+
+/**
+  MmcUpdateCardStatus
+
+  @param[in]  CardData                 Pointer to CARD_DATA
+
+  @retval     EFI_INVALID_PARAMETER
+  @retval     EFI_UNSUPPORTED
+  @retval     EFI_SUCCESS
+
+**/
+EFI_STATUS
+MmcUpdateCardStatus (
+  IN CARD_DATA     *CardData
+  )
+{
+  return SendCommand (
+           CardData->MmcHostIo,
+           SEND_STATUS,
+           (CardData->Address << 16),
+           NoData,
+           NULL,
+           0,
+           ResponseR1,
+           TIMEOUT_COMMAND,
+           (UINT32 *) &(CardData->CardStatus)
+           );
+}
+
+
+/**
+  MmcMoveToTranState
+
+  @param[in]  CardData                Pointer to CARD_DATA
+
+  @retval     EFI_INVALID_PARAMETER
+  @retval     EFI_UNSUPPORTED
+  @retval     EFI_SUCCESS
+
+**/
+EFI_STATUS
+MmcMoveToTranState (
+  IN CARD_DATA     *CardData
+  )
+{
+  EFI_STATUS  Status;
+
+  Status = EFI_SUCCESS;
+
+  if (CardData->CardStatus.CURRENT_STATE != Tran_STATE) {
+    //
+    // Put the card into tran state
+    //
+    Status = MmcSelect (CardData, TRUE);
+    MmcUpdateCardStatus (CardData);
+  }
+
+  if (CardData->CardStatus.CURRENT_STATE != Tran_STATE) {
+    DEBUG ((EFI_D_ERROR, "MmcMoveToTranState: Unable to put card into tran state\n"));
+    return EFI_DEVICE_ERROR;
+  }
+
+  return Status;
+}
+
+
+/**
+  MmcReadExtCsd
+
+  @param[in,out]  CardData                  Pointer to CARD_DATA
+
+  @retval         EFI_INVALID_PARAMETER
+  @retval         EFI_UNSUPPORTED
+  @retval         EFI_SUCCESS
+
+**/
+EFI_STATUS
+MmcReadExtCsd (
+  IN OUT CARD_DATA     *CardData
+  )
+{
+  EFI_STATUS  Status;
+
+  Status = MmcMoveToTranState (CardData);
+  if (EFI_ERROR (Status)) {
+    return Status;
+  }
+
+  Status  = SendCommand (
+              CardData->MmcHostIo,
+              SEND_EXT_CSD,
+              0,
+              InData,
+              CardData->AlignedBuffer,
+              sizeof (EXT_CSD),
+              ResponseR1,
+              TIMEOUT_DATA,
+              (UINT32 *) &(CardData->CardStatus)
+              );
+
+  DEBUG ((EFI_D_INFO, "MmcReadExtCsd: SEND_EXT_CSD -> %r\n", Status));
+  if (EFI_ERROR (Status)) {
+    return EFI_DEVICE_ERROR;
+  }
+
+  CopyMem (&(CardData->ExtCSDRegister), CardData->AlignedBuffer, sizeof (EXT_CSD));
+
+  return Status;
+}
+
+
+/**
+  MmcSetExtCsd8
+
+  @param[in]  CardData                Pointer to CARD_DATA
+  @param[in]  Index
+  @param[in]  Value
+
+  @retval     EFI_INVALID_PARAMETER
+  @retval     EFI_UNSUPPORTED
+  @retval     EFI_SUCCESS
+
+**/
+EFI_STATUS
+MmcSetExtCsd8 (
+  IN  CARD_DATA              *CardData,
+  IN  UINT8                  Index,
+  IN  UINT8                  Value
+  )
+{
+  EFI_STATUS                 Status;
+  SWITCH_ARGUMENT            SwitchArgument;
+
+  Status = MmcMoveToTranState (CardData);
+  if (EFI_ERROR (Status)) {
+    return Status;
+  }
+
+  ZeroMem (&SwitchArgument, sizeof (SWITCH_ARGUMENT));
+  SwitchArgument.CmdSet = 0;
+  SwitchArgument.Value  = (UINT8) Value;
+  SwitchArgument.Index  = (UINT8) Index;
+  SwitchArgument.Access = WriteByte_Mode; // SetBits_Mode;
+
+  return MmcSendSwitch (CardData, &SwitchArgument);
+}
+
+
+/**
+  MmcSetExtCsd24
+
+  @param[in]  CardData                Pointer to CARD_DATA
+  @param[in]  Index
+  @param[in]  Value
+
+  @retval     EFI_INVALID_PARAMETER
+  @retval     EFI_UNSUPPORTED
+  @retval     EFI_SUCCESS
+
+**/
+EFI_STATUS
+MmcSetExtCsd24 (
+  IN  CARD_DATA              *CardData,
+  IN  UINT8                  Index,
+  IN  UINT32                 Value
+  )
+{
+  EFI_STATUS                 Status;
+  UINTN                      Loop;
+
+  ASSERT ((Value & 0xff000000ULL) == 0);
+
+  for (Loop = 0; Loop < 3; Loop++) {
+    Status = MmcSetExtCsd8 (CardData, Index + (UINT8) Loop, Value & 0xff);
+    if (EFI_ERROR (Status)) {
+      return Status;
+    }
+    Value = Value >> 8;
+  }
+
+  return Status;
+}
+
+
+/**
+  MmcGetExtCsd8
+
+  @param[in]  CardData             Pointer to CARD_DATA
+  @param[in]  Offset
+
+  @retval     CSD Register value
+
+**/
+UINT32
+MmcGetExtCsd8 (
+  IN CARD_DATA                        *CardData,
+  IN UINTN                            Offset
+  )
+{
+  ASSERT (Offset < sizeof (CardData->ExtCSDRegister));
+  return ((UINT8 *) &CardData->ExtCSDRegister)[Offset];
+}
+
+
+/**
+  MmcGetExtCsd32
+
+  @param[in]  CardData             Pointer to CARD_DATA
+  @param[in]  Offset
+
+  @retval     CSD Register value
+
+**/
+UINT32
+MmcGetExtCsd32 (
+  IN CARD_DATA                        *CardData,
+  IN UINTN                            Offset
+  )
+{
+  return *(UINT32 *) (((UINT8 *) &CardData->ExtCSDRegister) + Offset);
+}
+
+
+/**
+  MmcGetExtCsd24
+
+  @param[in]  CardData             Pointer to CARD_DATA
+  @param[in]  Offset
+
+  @retval     CSD Register value
+
+**/
+UINT32
+MmcGetExtCsd24 (
+  IN CARD_DATA                       *CardData,
+  IN UINTN                           Offset
+  )
+{
+  return MmcGetExtCsd32 (CardData, Offset) & 0xffffff;
+}
+
+
+/**
+  MmcGetCurrentPartitionNum
+
+  @param[in]  CardData              Pointer to CARD_DATA
+
+  @retval     Current Partition Num
+
+**/
+UINTN
+MmcGetCurrentPartitionNum (
+  IN  CARD_DATA              *CardData
+  )
+{
+  return MmcGetExtCsd8 (
+           CardData,
+           OFFSET_OF (EXT_CSD, PARTITION_CONFIG)
+           ) & 0x7;
+}
+
+
+/**
+  SetEmmcWpOnEvent
+
+  @param[in]  Event
+  @param[in]  Context
+
+  @retval     None
+
+**/
+VOID
+EFIAPI
+SetEmmcWpOnEvent(
+  IN EFI_EVENT          Event,
+  IN VOID               *Context
+  )
+{
+  EFI_STATUS            Status;
+  UINTN                 Offset;
+  CARD_DATA             *CardData;
+  UINT8                 TempData;
+  UINTN                 WriteProtectAddress;
+  UINTN                 WriteProtectSize;
+  UINTN                 WriteProtectGroupSize;
+  static BOOLEAN        WriteProtectDone = FALSE;
+  HECI_FWS_REGISTER     SecFwStatus;
+  SC_POLICY_HOB         *ScPolicy;
+  EFI_PEI_HOB_POINTERS  HobList;
+  SC_SCS_CONFIG         *ScsConfig;
+
+  DEBUG ((EFI_D_INFO, "eMMC Write Protection Config Checkpoint\n"));
+
+  CardData = (CARD_DATA *) Context;
+  //
+  // Enable the eMMC protection
+  //
+  if (FALSE) {
+    if (!WriteProtectDone) {
+      Status = MmcReadExtCsd (CardData);
+      if (EFI_ERROR (Status)) {
+        DEBUG ((EFI_D_INFO, "Read EXT_CSD failed\n"));
+      }
+      DEBUG ((EFI_D_INFO, "\nBOOT_WP 0x%02x", (UINT8) (CardData->ExtCSDRegister.BOOT_WP)));
+      DEBUG ((EFI_D_INFO, "\nBOOT_WP_STATUS 0x%02x", (UINT8) (CardData->ExtCSDRegister.BOOT_WP_STATUS)));
+      DEBUG ((EFI_D_INFO, "\nUSER_WP 0x%02x", (UINT8) (CardData->ExtCSDRegister.USER_WP)));
+      DEBUG ((EFI_D_INFO, "\nRST_n_FUNCTION 0x%02x\n", (UINT8) (CardData->ExtCSDRegister.RST_n_FUNCTION)));
+
+      if (BxtStepping() >= BxtPB0) { //For BXTP-B and above, BIOS to toggle rst_n_function from 2'b00 to 2'b01
+        if ((CardData->ExtCSDRegister.RST_n_FUNCTION & 0x3) != 1) {
+          Offset = OFFSET_OF (EXT_CSD, RST_n_FUNCTION);
+          Status = MmcSetExtCsd8 (CardData, (UINT8) Offset, 0x01);
+          if (Status) {
+            DEBUG ((EFI_D_INFO, "Setting RST_n_FUNCTION failed\n"));
+          }
+        }
+      }
+
+      // Protect and BP
+      // Update Power on write protection bit in USER_WP and BP_WP EXT_CSD registers
+      //
+      Offset = OFFSET_OF (EXT_CSD, ERASE_GROUP_DEF);
+      Status = MmcSetExtCsd8 (CardData, (UINT8) Offset, 0x01);
+      if (Status) {
+        DEBUG ((EFI_D_INFO, "Setting ERASE_GROUP_DEF failed\n"));
+      }
+
+      if (BxtStepping() != BxtPA0) { // program WP only if it's not Bxtp-A0
+        Offset = OFFSET_OF (EXT_CSD, BOOT_WP);
+        TempData = (CardData->ExtCSDRegister.BOOT_WP) | B_PWR_WP_EN | B_PERM_WP_DIS;
+        Status = MmcSetExtCsd8 (CardData, (UINT8) Offset, TempData);
+        if (Status) {
+          DEBUG ((EFI_D_INFO, "BP Write protect failed\n"));
+        }
+      }
+
+      HobList.Guid   = GetFirstGuidHob (&gScPolicyHobGuid);
+      ASSERT (HobList.Guid != NULL);
+      ScPolicy  = (SC_POLICY_HOB *) GET_GUID_HOB_DATA (HobList.Guid);
+      Status = GetConfigBlock ((VOID *) ScPolicy, &gScsConfigGuid, (VOID *) &ScsConfig);
+      ASSERT_EFI_ERROR (Status);
+
+      SecFwStatus.ul = HeciPciRead32 (R_SEC_FW_STS0);
+
+      if (SecFwStatus.r.ManufacturingMode == 0) {
+        DEBUG ((EFI_D_INFO, "SEC F/W is not in Manufacturing mode and is ready for production \n"));
+      } else if (SecFwStatus.r.SeCOperationMode != SEC_OPERATION_MODE_SECOVR_JMPR) {
+        DEBUG ((EFI_D_INFO, "Flash Descriptor Override HW strap not set\n"));
+      }
+
+      if (((SecFwStatus.r.ManufacturingMode == 0)                                  // if EOM is set
+          && (SecFwStatus.r.SeCOperationMode != SEC_OPERATION_MODE_SECOVR_JMPR))   // Flash Descriptor Override HW strap not set
+          || (ScsConfig->GppLock == 1)                                             // OR GPP Partition Lock Policy is set
+         ) {
+        //
+        // Protect GPP1
+        //
+        Status = MmcSelectPartitionNum (CardData, 4); // Switch to GPP1 before issuing CMD28
+        if (!EFI_ERROR(Status)) {
+           DEBUG ((EFI_D_INFO, "\nSwitch to GPP Partition Successful\n"));
+            WriteProtectSize = (((UINTN) (CardData->ExtCSDRegister.GP_SIZE_MULT_1[2] *( 0x1<<16)))
+                                      +((UINTN) (CardData->ExtCSDRegister.GP_SIZE_MULT_1[1] *( 0x1<<8)))
+                                      +((UINTN) (CardData->ExtCSDRegister.GP_SIZE_MULT_1[0])))
+                                      * ((UINTN) (CardData->ExtCSDRegister.HC_WP_GRP_SIZE))
+                                      * 512 *  1024 * ((UINTN) (CardData->ExtCSDRegister.HC_ERASE_GRP_SIZE));
+
+           DEBUG ((EFI_D_INFO, "WriteProtectSize = 0x%x\n", WriteProtectSize));
+
+           Offset = OFFSET_OF (EXT_CSD, USER_WP);
+           TempData = (CardData->ExtCSDRegister.USER_WP) | US_PWR_WP_EN | US_PERM_WP_DIS;
+           Status = MmcSetExtCsd8 (CardData, (UINT8) Offset, TempData);
+           if (Status) {
+             DEBUG ((EFI_D_INFO, "GPP Write protect failed\n"));
+           }
+           if (CardData->ExtCSDRegister.ERASE_GROUP_DEF) {
+             WriteProtectGroupSize = ((UINTN) (CardData->ExtCSDRegister.HC_WP_GRP_SIZE))
+                                        * 512 *  1024 * ((UINTN) (CardData->ExtCSDRegister.HC_ERASE_GRP_SIZE));
+           } else {
+             WriteProtectGroupSize = (CardData->CSDRegister.WP_GRP_SIZE + 1)
+                                        * ((UINTN) CardData->CSDRegister.ERASE_GRP_SIZE + 1)
+                                        * ((UINTN) CardData->CSDRegister.ERASE_GRP_MULT + 1)
+                                        * ((UINTN) (CardData->Partitions[4].BlockIoMedia.BlockSize));
+           }
+
+           DEBUG ((EFI_D_INFO, "WriteProtectGroupSize = 0x%x\n", WriteProtectGroupSize));
+
+           for (WriteProtectAddress = 0; WriteProtectAddress < WriteProtectSize; WriteProtectAddress+=WriteProtectGroupSize) {
+             //
+             // Send Write protect command
+             //
+             DEBUG ((EFI_D_INFO, "Send Write protect command Address = 0x%x\n", WriteProtectAddress));
+             Status = SendCommand (
+                        CardData->MmcHostIo,
+                        SET_WRITE_PROT,
+                        (UINT32) (WriteProtectAddress / 0x200),
+                         NoData,
+                         NULL,
+                         0,
+                         ResponseR1b,
+                         TIMEOUT_COMMAND,
+                         (UINT32 *) &(CardData->CardStatus)
+                         );
+
+             if (Status) {
+               DEBUG ((EFI_D_INFO, "GPP1 Write protect failed\n"));
+               break;
+             }
+        }
+
+      }
+
+   }
+ }
+
+   Status = MmcReadExtCsd (CardData);
+   if (EFI_ERROR (Status)) {
+     DEBUG ((EFI_D_INFO, "Read EXT_CSD failed\n"));
+   }
+
+    DEBUG ((EFI_D_INFO, "\nBOOT_WP 0x%02x", (UINT8) (CardData->ExtCSDRegister.BOOT_WP)));
+    DEBUG ((EFI_D_INFO, "\nBOOT_WP_STATUS 0x%02x", (UINT8) (CardData->ExtCSDRegister.BOOT_WP_STATUS)));
+    DEBUG ((EFI_D_INFO, "\nUSER_WP 0x%02x", (UINT8) (CardData->ExtCSDRegister.USER_WP)));
+    DEBUG ((EFI_D_INFO, "\nRST_n_FUNCTION 0x%02x\n", (UINT8) (CardData->ExtCSDRegister.RST_n_FUNCTION)));
+    WriteProtectDone = TRUE;
+  }
+}
+
+
+/**
+  MmcSelectPartitionNum
+
+  @param[in]  CardData                 Pointer to CARD_DATA
+  @param[in]  Partition
+
+  @retval     EFI_INVALID_PARAMETER
+  @retval     EFI_UNSUPPORTED
+  @retval     EFI_SUCCESS
+
+**/
+EFI_STATUS
+MmcSelectPartitionNum (
+  IN  CARD_DATA              *CardData,
+  IN  UINT8                  Partition
+  )
+{
+  EFI_STATUS  Status;
+  UINTN       Offset;
+  UINT8       *ExtByte;
+  UINTN       CurrentPartition;
+
+  if (Partition > 7) {
+    return EFI_INVALID_PARAMETER;
+  }
+
+  CurrentPartition = MmcGetCurrentPartitionNum (CardData);
+  if (Partition == CurrentPartition) {
+    return EFI_SUCCESS;
+  }
+  MmcMoveToTranState (CardData);
+  Status = MmcReadExtCsd (CardData);
+  if (EFI_ERROR (Status)) {
+    return Status;
+  }
+
+  DEBUG ((EFI_D_INFO,
+    "MmcSelectPartitionNum: Switch partition: %d => %d\n",
+    CurrentPartition,
+    Partition
+    ));
+
+  Offset = OFFSET_OF (EXT_CSD, PARTITION_CONFIG);
+  Status = MmcSetExtCsd8 (CardData, (UINT8) Offset, Partition);
+
+#if 1
+  Status = MmcReadExtCsd (CardData);
+  if (EFI_ERROR (Status)) {
+    return Status;
+  }
+
+  CurrentPartition = MmcGetCurrentPartitionNum (CardData);
+  if (Partition != CurrentPartition) {
+    DEBUG ((EFI_D_INFO, "MmcSelectPartitionNum: Switch partition failed!\n"));
+    return EFI_DEVICE_ERROR;
+  }
+
+  ExtByte = NULL;
+#else
+  if (!EFI_ERROR (Status)) {
+    ExtByte = ((UINT8 *) &CardData->ExtCSDRegister) + Offset;
+    *ExtByte = (UINT8) ((*ExtByte & 0xF7) | Partition);
+  }
+#endif
+  MmcMoveToTranState (CardData);
+
+  return Status;
+}
+
+
+/**
+  MmcSelectPartitionNum
+
+  @param[in]  Partition                  Pointer to MMC_PARTITION_DATA
+
+  @retval     EFI_INVALID_PARAMETER
+  @retval     EFI_UNSUPPORTED
+  @retval     EFI_SUCCESS
+
+**/
+EFI_STATUS
+MmcSelectPartition (
+  IN  MMC_PARTITION_DATA     *Partition
+  )
+{
+  return MmcSelectPartitionNum (
+           Partition->CardData,
+           (UINT8) CARD_DATA_PARTITION_NUM (Partition)
+           );
+}
+
+
+/**
+  MmcSetPartition
+
+  @param[in]  CardData                     Pointer to CARD_DATA
+  @param[in]  Value                        0: user partition; 1: boot partition 1; 2:boot partition 2
+
+  @retval     EFI_INVALID_PARAMETER
+  @retval     EFI_UNSUPPORTED
+  @retval     EFI_SUCCESS
+
+**/
+EFI_STATUS
+MmcSetPartition (
+  IN  CARD_DATA              *CardData,
+  IN  UINT8                  Value
+  )
+{
+  EFI_STATUS  Status;
+  UINTN       Offset;
+  UINT32      Data;
+
+  Offset = OFFSET_OF (EXT_CSD, PARTITION_CONFIG);
+  Data = MmcGetExtCsd8 (CardData, Offset);
+  Data &= 0xf8;
+  Data |= Value;
+  Status = MmcSetExtCsd8 (CardData, (UINT8) Offset, (UINT8) Data);
+
+  return Status;
+}
+
diff --git a/Silicon/BroxtonSoC/BroxtonSiPkg/SouthCluster/Sdio/Dxe/MMC/MmcMediaDeviceDxe/MediaDeviceDriver.c b/Silicon/BroxtonSoC/BroxtonSiPkg/SouthCluster/Sdio/Dxe/MMC/MmcMediaDeviceDxe/MediaDeviceDriver.c
new file mode 100644
index 0000000..7f5bd11
--- /dev/null
+++ b/Silicon/BroxtonSoC/BroxtonSiPkg/SouthCluster/Sdio/Dxe/MMC/MmcMediaDeviceDxe/MediaDeviceDriver.c
@@ -0,0 +1,605 @@
+/** @file
+  UEFI Driver Entry and Binding support.
+
+  Copyright (c) 1999 - 2017, Intel Corporation. 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 <MediaDeviceDriver.h>
+#include <Protocol/EmmcCardInfoProtocol.h>
+
+//
+// MMCSDIOController Driver Global Variables
+//
+EFI_DRIVER_BINDING_PROTOCOL gMediaDeviceDriverBinding = {
+  MediaDeviceDriverBindingSupported,
+  MediaDeviceDriverBindingStart,
+  MediaDeviceDriverBindingStop,
+  0x10,
+  NULL,
+  NULL
+};
+
+EFI_EMMC_CARD_INFO_PROTOCOL *gEfiEmmcCardInfo = NULL;
+
+/**
+  Entry point for EFI drivers.
+
+  @param[in]  ImageHandle          EFI_HANDLE
+  @param[in]  SystemTable          EFI_SYSTEM_TABLE
+
+  @retval     EFI_SUCCESS          Success
+  @retval     EFI_DEVICE_ERROR     Fail
+
+**/
+EFI_STATUS
+EFIAPI
+MediaDeviceDriverEntryPoint (
+  IN EFI_HANDLE           ImageHandle,
+  IN EFI_SYSTEM_TABLE     *SystemTable
+  )
+{
+  return EfiLibInstallAllDriverProtocols (
+           ImageHandle,
+           SystemTable,
+           &gMediaDeviceDriverBinding,
+           ImageHandle,
+           &gMediaDeviceComponentName,
+           NULL,
+           NULL
+           );
+}
+
+
+/**
+  Test to see if this driver supports ControllerHandle. Any ControllerHandle
+  that has installed will be supported.
+
+  @param[in]  This                  Protocol instance pointer.
+  @param[in]  Controlle             Handle of device to test
+  @param[in]  RemainingDevicePath   Not used
+
+  @retval     EFI_SUCCESS           This driver supports this device.
+  @retval     EFI_UNSUPPORTED       This driver does not support this device.
+
+**/
+EFI_STATUS
+EFIAPI
+MediaDeviceDriverBindingSupported (
+  IN EFI_DRIVER_BINDING_PROTOCOL *This,
+  IN EFI_HANDLE                  Controller,
+  IN EFI_DEVICE_PATH_PROTOCOL    *RemainingDevicePath
+  )
+{
+  EFI_STATUS                 Status;
+  EFI_MMC_HOST_IO_PROTOCOL   *MmcHostIo;
+
+  //
+  // Test whether there is MMCHostIO Protocol attached on the controller handle.
+  //
+  Status = gBS->OpenProtocol (
+                  Controller,
+                  &gEfiMmcHostIoProtocolGuid,
+                  (VOID **) &MmcHostIo,
+                  This->DriverBindingHandle,
+                  Controller,
+                  EFI_OPEN_PROTOCOL_BY_DRIVER
+                  );
+  if (EFI_ERROR (Status)) {
+    goto Exit;
+  }
+
+  gBS->CloseProtocol (
+         Controller,
+         &gEfiMmcHostIoProtocolGuid,
+         This->DriverBindingHandle,
+         Controller
+         );
+
+Exit:
+  return Status;
+}
+
+
+/**
+  Starting the Media Device Driver
+
+  @param[in]  This                    Protocol instance pointer.
+  @param[in]  Controller              Handle of device to test
+  @param[in]  RemainingDevicePath     Not used
+
+  @retval     EFI_SUCCESS             supports this device.
+  @retval     EFI_UNSUPPORTED         do not support this device.
+  @retval     EFI_DEVICE_ERROR        cannot be started due to device Error
+  @retval     EFI_OUT_OF_RESOURCES    cannot allocate resources
+
+**/
+EFI_STATUS
+EFIAPI
+MediaDeviceDriverBindingStart (
+  IN EFI_DRIVER_BINDING_PROTOCOL     *This,
+  IN EFI_HANDLE                      Controller,
+  IN EFI_DEVICE_PATH_PROTOCOL        *RemainingDevicePath
+  )
+{
+  EFI_STATUS                   Status;
+  EFI_MMC_HOST_IO_PROTOCOL     *MmcHostIo;
+  CARD_DATA                    *CardData;
+  UINTN                        Loop;
+  EFI_EMMC_CARD_INFO_PROTOCOL  *EfiEmmcCardInfoRegister;
+
+  DEBUG ((EFI_D_INFO, "%a(%d): %a()\n", __FILE__, __LINE__, __FUNCTION__));
+
+  EfiEmmcCardInfoRegister = NULL;
+  CardData = NULL;
+  MmcHostIo = NULL;
+
+  //
+  // Alloc memory for EfiEmmcCardInfoRegister variable
+  //
+  EfiEmmcCardInfoRegister = (EFI_EMMC_CARD_INFO_PROTOCOL *) AllocateZeroPool (sizeof (EFI_EMMC_CARD_INFO_PROTOCOL));
+  if (EfiEmmcCardInfoRegister == NULL) {
+    Status = EFI_OUT_OF_RESOURCES;
+    goto Exit;
+  }
+
+  //
+  // Open PCI I/O Protocol and save pointer to open protocol
+  // in private data area.
+  //
+  Status = gBS->OpenProtocol (
+                  Controller,
+                  &gEfiMmcHostIoProtocolGuid,
+                  (VOID **) &MmcHostIo,
+                  This->DriverBindingHandle,
+                  Controller,
+                  EFI_OPEN_PROTOCOL_BY_DRIVER
+                  );
+
+  if (EFI_ERROR (Status)) {
+    DEBUG ((EFI_D_ERROR, "MediaDeviceDriverBindingStart: Fail to open gEfiMmcHostIoProtocolGuid \n"));
+    goto Exit;
+  }
+
+  Status = MmcHostIo->DetectCardAndInitHost (MmcHostIo);
+  if (EFI_ERROR (Status)) {
+    DEBUG ((DEBUG_ERROR, "MediaDeviceDriverBindingStart: Fail to DetectCardAndInitHost %r\n", Status));
+    goto Exit;
+  }
+
+  CardData = (CARD_DATA *) AllocateZeroPool (sizeof (CARD_DATA));
+  if (CardData == NULL) {
+    Status =  EFI_OUT_OF_RESOURCES;
+    DEBUG ((EFI_D_ERROR, "MediaDeviceDriverBindingStart: Fail to AllocateZeroPool(CARD_DATA) \n"));
+    goto Exit;
+  }
+
+  ASSERT (MmcHostIo->HostCapability.BoundarySize >= 4 * 1024);
+
+  CardData->RawBufferPointer = (UINT8*) (UINTN) 0xffffffff;
+
+  DEBUG ((EFI_D_INFO, "CardData->RawBufferPointer = 0x%x \n",CardData->RawBufferPointer));
+  DEBUG ((EFI_D_INFO, "requesting 0x%x pages \n",EFI_SIZE_TO_PAGES(2 * MmcHostIo->HostCapability.BoundarySize)));
+
+  //
+  // Allocated the buffer under 4G
+  //
+  Status = gBS->AllocatePages (
+                  AllocateMaxAddress,
+                  EfiBootServicesData,
+                  EFI_SIZE_TO_PAGES (2 * MmcHostIo->HostCapability.BoundarySize),
+                  (EFI_PHYSICAL_ADDRESS *) (&(CardData->RawBufferPointer))
+                  );
+  DEBUG ((EFI_D_INFO, "CardData->RawBufferPointer = 0x%x \n",CardData->RawBufferPointer));
+  if (!EFI_ERROR (Status)) {
+    CardData->RawBufferPointer = ZeroMem (CardData->RawBufferPointer, EFI_SIZE_TO_PAGES (2 * MmcHostIo->HostCapability.BoundarySize));
+  } else {
+    DEBUG ((DEBUG_ERROR, "MediaDeviceDriverBindingStart: Fail to AllocateZeroPool(2*x) \n"));
+    Status =  EFI_OUT_OF_RESOURCES;
+    goto Exit;
+  }
+  CardData->AlignedBuffer = CardData->RawBufferPointer - ((UINTN) (CardData->RawBufferPointer) & (MmcHostIo->HostCapability.BoundarySize - 1)) + MmcHostIo->HostCapability.BoundarySize;
+
+  CardData->Signature = CARD_DATA_SIGNATURE;
+  CardData->MmcHostIo  = MmcHostIo;
+  CardData->Handle = Controller;
+  for (Loop = 0; Loop < MAX_NUMBER_OF_PARTITIONS; Loop++) {
+    CardData->Partitions[Loop].Signature = CARD_PARTITION_SIGNATURE;
+  }
+  Status = MMCSDCardInit (CardData);
+
+  if (EFI_ERROR (Status)) {
+    DEBUG ((EFI_D_ERROR, "MediaDeviceDriverBindingStart: Fail to MMCSDCardInit \n"));
+    goto Exit;
+  }
+
+  DEBUG ((DEBUG_INFO, "MediaDeviceDriverBindingStart: MMC SD card\n"));
+  Status = MMCSDBlockIoInit (CardData);
+
+  if (EFI_ERROR (Status)) {
+    DEBUG ((DEBUG_ERROR, "MediaDeviceDriverBindingStart: Card BlockIo init failed\n"));
+    goto Exit;
+  }
+
+
+  Status = MediaDeviceDriverInstallBlockIo (This, CardData);
+  if (EFI_ERROR (Status)) {
+    DEBUG ((DEBUG_ERROR, "MediaDeviceDriverBindingStart: Fail to install gEfiBlockIoProtocolGuid \n"));
+    goto Exit;
+  }
+
+  //
+  // Component name protocol
+  //
+  Status = AddUnicodeString (
+             "eng",
+             gMediaDeviceComponentName.SupportedLanguages,
+             &CardData->ControllerNameTable,
+             L"MMC/SD Media Device"
+             );
+  if (EFI_ERROR (Status)) {
+    Status = EFI_OUT_OF_RESOURCES;
+    for (Loop = 0; Loop < MAX_NUMBER_OF_PARTITIONS; Loop++) {
+      if (!CardData->Partitions[Loop].Present) {
+        continue;
+      }
+      gBS->UninstallMultipleProtocolInterfaces (
+             CardData->Partitions[Loop].Handle,
+             &gEfiBlockIoProtocolGuid,
+             &CardData->Partitions[Loop].BlockIo,
+             &gEfiDevicePathProtocolGuid,
+             CardData->Partitions[Loop].DevPath,
+             NULL
+             );
+    }
+    goto Exit;
+  }
+  if (EfiEmmcCardInfoRegister != NULL) {
+
+    //
+    // assign to protocol
+    //
+    EfiEmmcCardInfoRegister->CardData = CardData;
+
+    Status = gBS->InstallMultipleProtocolInterfaces (
+                    &Controller,
+                    &gEfiEmmcCardInfoProtocolGuid,
+                    EfiEmmcCardInfoRegister,
+                    NULL
+                    );
+    if (EFI_ERROR (Status)) {
+      DEBUG ((DEBUG_ERROR, "MediaDeviceDriverBindingStart: Install eMMC Card info protocol failed\n"));
+      for (Loop = 0; Loop < MAX_NUMBER_OF_PARTITIONS; Loop++) {
+        if (!CardData->Partitions[Loop].Present) {
+          continue;
+        }
+        gBS->UninstallMultipleProtocolInterfaces (
+               CardData->Partitions[Loop].Handle,
+               &gEfiBlockIoProtocolGuid,
+               &CardData->Partitions[Loop].BlockIo,
+               &gEfiDevicePathProtocolGuid,
+               CardData->Partitions[Loop].DevPath,
+               NULL
+               );
+      }
+
+      goto Exit;
+    }
+
+    gEfiEmmcCardInfo = EfiEmmcCardInfoRegister;
+  }
+
+  DEBUG ((DEBUG_INFO, "MediaDeviceDriverBindingStart: Started\n"));
+
+Exit:
+  if (EFI_ERROR (Status)) {
+    DEBUG ((EFI_D_ERROR, "MediaDeviceDriverBindingStart: End with failure\n"));
+    if (CardData != NULL && MmcHostIo != NULL) {
+      if (CardData->RawBufferPointer != NULL) {
+        gBS->FreePages ((EFI_PHYSICAL_ADDRESS) (UINTN) CardData->RawBufferPointer, EFI_SIZE_TO_PAGES (MmcHostIo->HostCapability.BoundarySize * 2));
+      }
+      FreePool (CardData);
+    }
+    gBS->CloseProtocol (
+           Controller,
+           &gEfiMmcHostIoProtocolGuid,
+           This->DriverBindingHandle,
+           Controller
+           );
+  }
+  return Status;
+}
+
+
+/**
+  Stop this driver on ControllerHandle. Support stoping any child handles
+  created by this driver.
+
+  @param[in]  This                   Protocol instance pointer.
+  @param[in]  Controller             Handle of device to stop driver on
+  @param[in]  NumberOfChildren       Number of Children in the ChildHandleBuffer
+  @param[in]  ChildHandleBuffer      List of handles for the children we need to stop.
+
+  @retval     EFI_SUCCESS            Success
+  @retval     EFI_DEVICE_ERROR       Fail
+
+**/
+EFI_STATUS
+EFIAPI
+MediaDeviceDriverBindingStop (
+  IN  EFI_DRIVER_BINDING_PROTOCOL     *This,
+  IN  EFI_HANDLE                      Controller,
+  IN  UINTN                           NumberOfChildren,
+  IN  EFI_HANDLE                      *ChildHandleBuffer
+  )
+{
+  EFI_STATUS                Status;
+  CARD_DATA                 *CardData;
+  BOOLEAN                   AllChildrenStopped;
+  UINTN                     Index;
+  UINTN                     Pages = 0;
+
+  Status = EFI_SUCCESS;
+  CardData = gEfiEmmcCardInfo->CardData;
+
+  if (NumberOfChildren == 0) {
+    Status = gBS->UninstallMultipleProtocolInterfaces (
+                    Controller,
+                    &gEfiEmmcCardInfoProtocolGuid,
+                    gEfiEmmcCardInfo,
+                    NULL
+                    );
+    if (EFI_ERROR (Status)) {
+      DEBUG ((EFI_D_ERROR, "MediaDeviceDriverBindingStop: UNINSTALL gEfiEmmcCardInfoProtocolGuid FAILURE\n"));
+      return Status;
+    }
+
+    FreeUnicodeStringTable (CardData->ControllerNameTable);
+
+    Pages = (2 * (CardData->MmcHostIo->HostCapability.BoundarySize));
+    if (CardData->RawBufferPointer != NULL) {
+      FreePages (CardData->RawBufferPointer, EFI_SIZE_TO_PAGES(Pages));
+    }
+
+    Status = gBS->CloseProtocol (
+         Controller,
+         &gEfiMmcHostIoProtocolGuid,
+         This->DriverBindingHandle,
+         Controller
+         );
+
+    if (MediaDeviceDriverAllPartitionNotPresent(CardData)) {
+      FreePool (CardData);
+      FreePool (gEfiEmmcCardInfo);
+      gEfiEmmcCardInfo = NULL;
+    }
+
+    return Status;
+  }
+
+  AllChildrenStopped = TRUE;
+  for (Index = 0; Index < NumberOfChildren; Index++) {
+    Status = MediaDeviceDriverUninstallBlockIo(This, CardData, ChildHandleBuffer[Index]);
+    if (EFI_ERROR (Status)) {
+      DEBUG ((EFI_D_ERROR, "MediaDeviceDriverBindingStop: UNINSTALL block io FAILURE\n"));
+      AllChildrenStopped = FALSE;
+      break;
+    }
+  }
+
+  return Status;
+}
+
+
+BOOLEAN
+MediaDeviceDriverAllPartitionNotPresent (
+  IN  CARD_DATA    *CardData
+  )
+{
+  BOOLEAN             AllPartitionNotPresent;
+  UINTN               Loop;
+  MMC_PARTITION_DATA  *Partition;
+
+  Partition = CardData->Partitions;
+
+  AllPartitionNotPresent = TRUE;
+
+  for (Loop = 0; Loop < MAX_NUMBER_OF_PARTITIONS; Partition++, Loop++) {
+    if (Partition->Present) {
+      AllPartitionNotPresent = FALSE;
+      break;
+    }
+  }
+
+  return AllPartitionNotPresent;
+}
+
+
+STATIC
+struct {
+  DEVICE_LOGICAL_UNIT_DEVICE_PATH  LogicalUnit;
+  EFI_DEVICE_PATH_PROTOCOL  End;
+} EmmcDevPathTemplate = {
+  {
+    {
+      MESSAGING_DEVICE_PATH,
+      MSG_DEVICE_LOGICAL_UNIT_DP,
+      {
+        sizeof (DEVICE_LOGICAL_UNIT_DEVICE_PATH),
+        0
+      },
+    },
+    0
+  },
+  {
+    END_DEVICE_PATH_TYPE,
+    END_ENTIRE_DEVICE_PATH_SUBTYPE,
+    {
+      END_DEVICE_PATH_LENGTH,
+      0
+    }
+  }
+};
+
+
+/**
+  MediaDeviceDriverInstallBlockIo
+
+  @param[in]  This                    Pointer to the EFI_DRIVER_BINDING_PROTOCOL.
+  @param[in]  CardData                Pointer to CARD_DATA
+
+  @retval     EFI_INVALID_PARAMETER
+  @retval     EFI_UNSUPPORTED
+  @retval     EFI_SUCCESS
+
+**/
+EFI_STATUS
+MediaDeviceDriverInstallBlockIo (
+  IN  EFI_DRIVER_BINDING_PROTOCOL     *This,
+  IN  CARD_DATA                       *CardData
+  )
+{
+  EFI_STATUS                Status;
+  UINT8                     Loop;
+  MMC_PARTITION_DATA        *Partition;
+  EFI_DEVICE_PATH_PROTOCOL  *MainPath;
+  EFI_MMC_HOST_IO_PROTOCOL  *MmcHostIo = NULL;
+
+  Partition = CardData->Partitions;
+
+  Status = gBS->HandleProtocol (
+                  CardData->Handle,
+                  &gEfiDevicePathProtocolGuid,
+                  (VOID **) &MainPath
+                  );
+  if (EFI_ERROR (Status)) {
+    return Status;
+  }
+
+  for (Loop = 0; Loop < MAX_NUMBER_OF_PARTITIONS; Partition++, Loop++) {
+    if (!Partition->Present) {
+      continue;
+    }
+
+    DEBUG ((EFI_D_INFO, "MediaDeviceDriverInstallBlockIo: Installing Block I/O for partition %d\n", Loop));
+
+    Partition->Handle = NULL;
+    Partition->CardData = CardData;
+
+    EmmcDevPathTemplate.LogicalUnit.Lun = Loop;
+    Partition->DevPath =
+      AppendDevicePath (
+        MainPath,
+        (EFI_DEVICE_PATH_PROTOCOL *) &EmmcDevPathTemplate
+        );
+    if (Partition->DevPath == NULL) {
+      Status = EFI_OUT_OF_RESOURCES;
+      break;
+    }
+
+    Status = gBS->InstallProtocolInterface (
+                    &(Partition->Handle),
+                    &gEfiDevicePathProtocolGuid,
+                    EFI_NATIVE_INTERFACE,
+                    Partition->DevPath
+                    );
+    if (EFI_ERROR (Status)) {
+      break;
+    }
+
+    Status = gBS->InstallProtocolInterface (
+                    &(Partition->Handle),
+                    &gEfiBlockIoProtocolGuid,
+                    EFI_NATIVE_INTERFACE,
+                    &Partition->BlockIo
+                    );
+
+    //
+    // Open parent controller by child
+    //
+    Status = gBS->OpenProtocol (
+                    CardData->Handle,
+                    &gEfiMmcHostIoProtocolGuid,
+                    (VOID **) &MmcHostIo,
+                    This->DriverBindingHandle,
+                    Partition->Handle,
+                    EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER
+                    );
+  }
+
+  return Status;
+}
+
+
+/**
+  MediaDeviceDriverUninstallBlockIo
+
+  @param[in]  This                     Pointer to the EFI_DRIVER_BINDING_PROTOCOL.
+  @param[in]  CardData                 Pointer to CARD_DATA
+  @param[in]  Handle                   Handle of Partition
+
+  @retval     EFI_INVALID_PARAMETER
+  @retval     EFI_UNSUPPORTED
+  @retval     EFI_SUCCESS
+
+**/
+EFI_STATUS
+MediaDeviceDriverUninstallBlockIo (
+  IN  EFI_DRIVER_BINDING_PROTOCOL  *This,
+  IN  CARD_DATA                    *CardData,
+  IN  EFI_HANDLE                   Handle
+  )
+{
+  EFI_STATUS          Status;
+  UINTN               Loop;
+  MMC_PARTITION_DATA  *Partition;
+
+  Partition = CardData->Partitions;
+  Status = EFI_SUCCESS;
+
+  for (Loop = 0; Loop < MAX_NUMBER_OF_PARTITIONS; Partition++, Loop++) {
+    if (!Partition->Present || Partition->Handle != Handle) {
+     continue;
+    }
+
+    //
+    // Close MmcHostIoProtocol by child
+    //
+    Status = gBS->CloseProtocol (
+                    CardData->Handle,
+                    &gEfiMmcHostIoProtocolGuid,
+                    This->DriverBindingHandle,
+                    Partition->Handle
+                    );
+    if (EFI_ERROR (Status)) {
+      DEBUG ((EFI_D_ERROR, "CloseProtocol gEfiMmcHostIoProtocolGuid FAILURE \n"));
+      return Status;
+    }
+
+    Status = gBS->UninstallMultipleProtocolInterfaces (
+                    Partition->Handle,
+                    &gEfiBlockIoProtocolGuid,
+                    &Partition->BlockIo,
+                    &gEfiDevicePathProtocolGuid,
+                    Partition->DevPath,
+                    NULL
+                    );
+    Partition->Present = FALSE;
+    DEBUG ((EFI_D_ERROR, "MediaDeviceDriverBindingStop gEfiBlockIoProtocolGuid removed.  %x\n", Status));
+    if (EFI_ERROR (Status)) {
+      DEBUG ((EFI_D_ERROR, "MediaDeviceDriverUninstallBlockIo UNISTALL FAILURE \n"));
+    }
+    return Status;
+  }
+
+  return EFI_INVALID_PARAMETER;
+}
+
diff --git a/Silicon/BroxtonSoC/BroxtonSiPkg/SouthCluster/Sdio/Dxe/MMC/MmcMediaDeviceDxe/MmcMediaDeviceDxe.inf b/Silicon/BroxtonSoC/BroxtonSiPkg/SouthCluster/Sdio/Dxe/MMC/MmcMediaDeviceDxe/MmcMediaDeviceDxe.inf
new file mode 100644
index 0000000..500d1de
--- /dev/null
+++ b/Silicon/BroxtonSoC/BroxtonSiPkg/SouthCluster/Sdio/Dxe/MMC/MmcMediaDeviceDxe/MmcMediaDeviceDxe.inf
@@ -0,0 +1,71 @@
+## @file
+#  SD Host module
+#
+#  Copyright (c) 1999 - 2016, Intel Corporation. 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                    = 0x00010005
+  BASE_NAME                      = MmcMediaDevice
+  FILE_GUID                      = 1CFD8F87-355A-4954-859F-DDC5D8876D44
+  MODULE_TYPE                    = UEFI_DRIVER
+  VERSION_STRING                 = 1.0
+  ENTRY_POINT                    = MediaDeviceDriverEntryPoint
+
+#
+# The following information is for reference only and not required by the build tools.
+#
+#  VALID_ARCHITECTURES           = IA32 X64 IPF EBC
+#
+
+[Sources.common]
+  ComponentName.c
+  MediaDeviceDriver.c
+  MMCSDBlockIo.c
+  MMCSDTransfer.c
+
+[Packages]
+  MdePkg/MdePkg.dec
+  BroxtonSiPkg/BroxtonSiPkg.dec
+  BroxtonSiPkg/BroxtonSiPrivate.dec
+
+[LibraryClasses]
+  UefiDriverEntryPoint
+  DebugLib
+  UefiBootServicesTableLib
+  BaseMemoryLib
+  MemoryAllocationLib
+  UefiLib
+  DevicePathLib
+  IoLib
+  PcdLib
+  HobLib
+  PciLib
+  SteppingLib
+  ConfigBlockLib
+
+[Guids]
+  gEfiEventReadyToBootGuid ## UNDEFINED
+  gScPolicyHobGuid
+  gEfiUnbootablePartitionGuid       ## PRODUCE ## GUID
+  gScsConfigGuid
+
+[Protocols]
+  gEfiDevicePathProtocolGuid        ## BY_START
+  gEfiMmcHostIoProtocolGuid         ## CONSUMES
+  gEfiBlockIoProtocolGuid           ## BY_START
+  gEfiEmmcCardInfoProtocolGuid      ## BY_START
+  gEfiEmmcBootPartitionProtocolGuid ## BY_START
+
+[Pcd]
+  gEfiBxtTokenSpaceGuid.PcdEmmcManufacturerId   ## PRODUCES
+  gEfiBxtTokenSpaceGuid.PcdProductSerialNumber  ## PRODUCES
diff --git a/Silicon/BroxtonSoC/BroxtonSiPkg/SouthCluster/Sdio/Dxe/SD/SdControllerDxe/ComponentName.c b/Silicon/BroxtonSoC/BroxtonSiPkg/SouthCluster/Sdio/Dxe/SD/SdControllerDxe/ComponentName.c
new file mode 100644
index 0000000..0bc9861
--- /dev/null
+++ b/Silicon/BroxtonSoC/BroxtonSiPkg/SouthCluster/Sdio/Dxe/SD/SdControllerDxe/ComponentName.c
@@ -0,0 +1,233 @@
+/** @file
+  UEFI Component Name(2) protocol implementation for SD controller driver.
+
+  Copyright (c) 2013 - 2016, Intel Corporation. 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 "SdController.h"
+
+//
+// EFI Component Name Protocol
+//
+GLOBAL_REMOVE_IF_UNREFERENCED EFI_COMPONENT_NAME_PROTOCOL  gSdControllerName = {
+  SdControllerGetDriverName,
+  SdControllerGetControllerName,
+  "eng"
+};
+
+
+//
+// EFI Component Name 2 Protocol
+//
+GLOBAL_REMOVE_IF_UNREFERENCED EFI_COMPONENT_NAME2_PROTOCOL gSdControllerName2 = {
+  (EFI_COMPONENT_NAME2_GET_DRIVER_NAME) SdControllerGetDriverName,
+  (EFI_COMPONENT_NAME2_GET_CONTROLLER_NAME) SdControllerGetControllerName,
+  "en"
+};
+
+
+GLOBAL_REMOVE_IF_UNREFERENCED EFI_UNICODE_STRING_TABLE mSdControllerDriverNameTable[] = {
+  { "eng;en", L"EFI SD Host Controller Driver" },
+  { NULL, NULL }
+};
+
+
+//
+// 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[in]     This                 A pointer to the EFI_COMPONENT_NAME2_PROTOCOL or
+                                      EFI_COMPONENT_NAME_PROTOCOL instance.
+
+  @param[in]    Language              A pointer to a Null-terminated ASCII string
+                                      array indicating the language. This is the
+                                      language of the driver name that the caller is
+                                      requesting, and it must match one of the
+                                      languages specified in SupportedLanguages. The
+                                      number of languages supported by a driver is up
+                                      to the driver writer. Language is specified
+                                      in RFC 3066 or ISO 639-2 language code format.
+
+  @param[out]   DriverName            A pointer to the Unicode string to return.
+                                      This Unicode string is the name of the
+                                      driver specified by This in the language
+                                      specified by Language.
+
+  @retval       EFI_SUCCESS           The Unicode string for the Driver specified by
+                                      This and the language specified by Language was
+                                      returned in DriverName.
+
+  @retval       EFI_INVALID_PARAMETER Language is NULL.
+
+  @retval       EFI_INVALID_PARAMETER DriverName is NULL.
+
+  @retval       EFI_UNSUPPORTED       The driver specified by This does not support
+                                      the language specified by Language.
+
+**/
+EFI_STATUS
+EFIAPI
+SdControllerGetDriverName (
+  IN  EFI_COMPONENT_NAME_PROTOCOL  *This,
+  IN  CHAR8                        *Language,
+  OUT CHAR16                       **DriverName
+  )
+{
+  return LookupUnicodeString2 (
+           Language,
+           This->SupportedLanguages,
+           mSdControllerDriverNameTable,
+           DriverName,
+           (BOOLEAN)(This == &gSdControllerName)
+           );
+}
+
+
+/**
+  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[in]  This                  A pointer to the EFI_COMPONENT_NAME2_PROTOCOL or
+                                    EFI_COMPONENT_NAME_PROTOCOL instance.
+
+  @param[in]  ControllerHandle      The handle of a controller that the driver
+                                    specified by This is managing.  This handle
+                                    specifies the controller whose name is to be
+                                    returned.
+
+  @param[in]  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[in]  Language              A pointer to a Null-terminated ASCII string
+                                    array indicating the language.  This is the
+                                    language of the driver name that the caller is
+                                    requesting, and it must match one of the
+                                    languages specified in SupportedLanguages. The
+                                    number of languages supported by a driver is up
+                                    to the driver writer. Language is specified in
+                                    RFC 3066 or ISO 639-2 language code format.
+
+  @param[out] ControllerName        A pointer to the Unicode string to return.
+                                    This Unicode string is the name of the
+                                    controller specified by ControllerHandle and
+                                    ChildHandle in the language specified by
+                                    Language from the point of view of the driver
+                                    specified by This.
+
+  @retval     EFI_SUCCESS           The Unicode string for the user readable name in
+                                    the language specified by Language for the
+                                    driver specified by This was returned in
+                                    DriverName.
+
+  @retval     EFI_INVALID_PARAMETER ControllerHandle is not a valid EFI_HANDLE.
+
+  @retval     EFI_INVALID_PARAMETER ChildHandle is not NULL and it is not a valid
+                                    EFI_HANDLE.
+
+  @retval     EFI_INVALID_PARAMETER Language is NULL.
+
+  @retval     EFI_INVALID_PARAMETER ControllerName is NULL.
+
+  @retval     EFI_UNSUPPORTED       The driver specified by This is not currently
+                                    managing the controller specified by
+                                    ControllerHandle and ChildHandle.
+
+  @retval     EFI_UNSUPPORTED       The driver specified by This does not support
+                                    the language specified by Language.
+
+**/
+EFI_STATUS
+EFIAPI
+SdControllerGetControllerName (
+  IN  EFI_COMPONENT_NAME_PROTOCOL                     *This,
+  IN  EFI_HANDLE                                      ControllerHandle,
+  IN  EFI_HANDLE                                      ChildHandle        OPTIONAL,
+  IN  CHAR8                                           *Language,
+  OUT CHAR16                                          **ControllerName
+  )
+{
+  EFI_STATUS               Status;
+  EFI_SD_HOST_IO_PROTOCOL  *SdHostIo;
+  SDHOST_DATA              *SdHostData;
+
+  //
+  // 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,
+             gSdControllerDriverBinding.DriverBindingHandle,
+             &gEfiPciIoProtocolGuid
+             );
+
+  if (EFI_ERROR (Status)) {
+    return Status;
+  }
+
+  //
+  // Get the device context
+  //
+  Status = gBS->OpenProtocol (
+                  ControllerHandle,
+                  &gEfiSdHostIoProtocolGuid,
+                  (VOID **) &SdHostIo,
+                  gSdControllerDriverBinding.DriverBindingHandle,
+                  ControllerHandle,
+                  EFI_OPEN_PROTOCOL_GET_PROTOCOL
+                  );
+
+  if (EFI_ERROR (Status)) {
+    return Status;
+  }
+
+  SdHostData = SDHOST_DATA_FROM_THIS (SdHostIo);
+
+  return LookupUnicodeString2 (
+           Language,
+           This->SupportedLanguages,
+           SdHostData->ControllerNameTable,
+           ControllerName,
+           (BOOLEAN)(This == &gSdControllerName)
+           );
+
+}
+
diff --git a/Silicon/BroxtonSoC/BroxtonSiPkg/SouthCluster/Sdio/Dxe/SD/SdControllerDxe/ComponentName.h b/Silicon/BroxtonSoC/BroxtonSiPkg/SouthCluster/Sdio/Dxe/SD/SdControllerDxe/ComponentName.h
new file mode 100644
index 0000000..89d8a27
--- /dev/null
+++ b/Silicon/BroxtonSoC/BroxtonSiPkg/SouthCluster/Sdio/Dxe/SD/SdControllerDxe/ComponentName.h
@@ -0,0 +1,145 @@
+/** @file
+  This file contains the declarations for component name routines.
+
+  Copyright (c) 2013 - 2016, Intel Corporation. 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 _COMPONENT_NAME_H_
+#define _COMPONENT_NAME_H_
+
+/**
+  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[in]  This                  A pointer to the EFI_COMPONENT_NAME2_PROTOCOL or
+                                    EFI_COMPONENT_NAME_PROTOCOL instance.
+
+  @param[in]  Language              A pointer to a Null-terminated ASCII string
+                                    array indicating the language. This is the
+                                    language of the driver name that the caller is
+                                    requesting, and it must match one of the
+                                    languages specified in SupportedLanguages. The
+                                    number of languages supported by a driver is up
+                                    to the driver writer. Language is specified
+                                    in RFC 3066 or ISO 639-2 language code format.
+
+  @param[out] DriverName            A pointer to the Unicode string to return.
+                                    This Unicode string is the name of the
+                                    driver specified by This in the language
+                                    specified by Language.
+
+  @retval     EFI_SUCCESS           The Unicode string for the Driver specified by
+                                    This and the language specified by Language was
+                                    returned in DriverName.
+
+  @retval     EFI_INVALID_PARAMETER Language is NULL.
+
+  @retval     EFI_INVALID_PARAMETER DriverName is NULL.
+
+  @retval     EFI_UNSUPPORTED       The driver specified by This does not support
+                                    the language specified by Language.
+
+**/
+EFI_STATUS
+EFIAPI
+SdControllerGetDriverName (
+  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[in]   This                    A pointer to the EFI_COMPONENT_NAME2_PROTOCOL or
+                                       EFI_COMPONENT_NAME_PROTOCOL instance.
+
+  @param[in]   ControllerHandle        The handle of a controller that the driver
+                                       specified by This is managing.  This handle
+                                       specifies the controller whose name is to be
+                                       returned.
+
+  @param[in]   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[in]   Language                A pointer to a Null-terminated ASCII string
+                                       array indicating the language.  This is the
+                                       language of the driver name that the caller is
+                                       requesting, and it must match one of the
+                                       languages specified in SupportedLanguages. The
+                                       number of languages supported by a driver is up
+                                       to the driver writer. Language is specified in
+                                       RFC 3066 or ISO 639-2 language code format.
+
+  @param[out]  ControllerName          A pointer to the Unicode string to return.
+                                       This Unicode string is the name of the
+                                       controller specified by ControllerHandle and
+                                       ChildHandle in the language specified by
+                                       Language from the point of view of the driver
+                                       specified by This.
+
+  @retval      EFI_SUCCESS             The Unicode string for the user readable name in
+                                       the language specified by Language for the
+                                       driver specified by This was returned in
+                                       DriverName.
+
+  @retval      EFI_INVALID_PARAMETER   ControllerHandle is not a valid EFI_HANDLE.
+
+  @retval      EFI_INVALID_PARAMETER   ChildHandle is not NULL and it is not a valid
+                                       EFI_HANDLE.
+
+  @retval      EFI_INVALID_PARAMETER   Language is NULL.
+
+  @retval      EFI_INVALID_PARAMETER   ControllerName is NULL.
+
+  @retval      EFI_UNSUPPORTED         The driver specified by This is not currently
+                                       managing the controller specified by
+                                       ControllerHandle and ChildHandle.
+
+  @retval     EFI_UNSUPPORTED          The driver specified by This does not support
+                                       the language specified by Language.
+
+**/
+EFI_STATUS
+EFIAPI
+SdControllerGetControllerName (
+  IN  EFI_COMPONENT_NAME_PROTOCOL       *This,
+  IN  EFI_HANDLE                        ControllerHandle,
+  IN  EFI_HANDLE                        ChildHandle        OPTIONAL,
+  IN  CHAR8                             *Language,
+  OUT CHAR16                            **ControllerName
+  );
+
+#endif
+
diff --git a/Silicon/BroxtonSoC/BroxtonSiPkg/SouthCluster/Sdio/Dxe/SD/SdControllerDxe/SdController.c b/Silicon/BroxtonSoC/BroxtonSiPkg/SouthCluster/Sdio/Dxe/SD/SdControllerDxe/SdController.c
new file mode 100644
index 0000000..f481196
--- /dev/null
+++ b/Silicon/BroxtonSoC/BroxtonSiPkg/SouthCluster/Sdio/Dxe/SD/SdControllerDxe/SdController.c
@@ -0,0 +1,1804 @@
+/** @file
+  The SD host controller driver model and HC protocol routines.
+
+  Copyright (c) 2013 - 2017, Intel Corporation. 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 "SdController.h"
+
+EFI_DRIVER_BINDING_PROTOCOL gSdControllerDriverBinding = {
+  SdControllerSupported,
+  SdControllerStart,
+  SdControllerStop,
+  0x20,
+  NULL,
+  NULL
+};
+
+
+EFI_SD_HOST_IO_PROTOCOL  mSdHostIo = {
+  EFI_SD_HOST_IO_PROTOCOL_REVISION_01,
+  {
+    0,           // HighSpeedSupport
+    0,           // V18Support
+    0,           // V30Support
+    0,           // V33Support
+    0,           // Reserved0
+    0,           // BusWidth4
+    0,           // BusWidth8
+    0,           // Reserved1
+    0,           // Reserved1
+    (512 * 1024) // BoundarySize
+  },
+
+  SendCommand,
+  SetClockFrequency,
+  SetBusWidth,
+  SetHostVoltage,
+  ResetSdHost,
+  EnableAutoStopCmd,
+  DetectCardAndInitHost,
+  SetBlockLength,
+  SetHighSpeedMode,
+  SetDDRMode
+};
+
+
+/**
+  Find sdclk_freq_sel and upr_sdclk_freq_sel bits
+  for Clock Control Register (CLK_CTL)Offset 2Ch when using 8bit or 10bit
+  divided clock mode.
+
+  @param[in]   BaseClockFreg        Base Clock Frequency in Hz For SD Clock in the
+                                    Capabilities register.
+  @param[in]   TargetFreq           Target Frequency in Hz to reach.
+  @param[in]   Is8BitMode           True if 8-bit Divided Clock Mode else 10bit mode.
+  @param[out]  Bits                 sdclk_freq_sel and upr_sdclk_freq_sel bits for
+                                    TargetFreq.
+
+  @retval      EFI_SUCCESS          Bits setup.
+  @retval      EFI_UNSUPPORTED      Cannot divide base clock to reach target clock.
+
+**/
+EFI_STATUS
+DividedClockModeBits (
+  IN    CONST UINTN            BaseClockFreg,
+  IN    CONST UINTN            TargetFreq,
+  IN    CONST BOOLEAN          Is8BitMode,
+  OUT   UINT16                 *Bits
+  )
+{
+  UINTN  N;
+  UINTN  CurrFreq;
+
+  *Bits = 0;
+  CurrFreq = BaseClockFreg;
+  N = 0;
+  //
+  // N == 0 same for 8bit & 10bit mode i.e. BaseClockFreg of controller.
+  //
+  if (TargetFreq < CurrFreq) {
+    if (Is8BitMode) {
+      N = 1;
+      do {
+        //
+        // N values for 8bit mode when N > 0.
+        //  Bit[15:8] SDCLK Frequency Select at offset 2Ch
+        //    80h - base clock divided by 256
+        //    40h - base clock divided by 128
+        //    20h - base clock divided by 64
+        //    10h - base clock divided by 32
+        //    08h - base clock divided by 16
+        //    04h - base clock divided by 8
+        //    02h - base clock divided by 4
+        //    01h - base clock divided by 2
+        //
+        CurrFreq = BaseClockFreg / (2 * N);
+        if (TargetFreq >= CurrFreq) {
+          break;
+        }
+        N *= 2;
+        if (N > V_MMIO_CLKCTL_MAX_8BIT_FREQ_SEL) {
+          return EFI_UNSUPPORTED;
+        }
+      } while (TRUE);
+    } else {
+      N = 1;
+      CurrFreq = BaseClockFreg / (2 * N);
+      //
+      // (try N = 0 or 1 first since don't want divide by 0).
+      //
+      if (TargetFreq < CurrFreq) {
+        //
+        // If still no match then calculate it for 10bit.
+        // N values for 10bit mode.
+        // N 1/2N Divided Clock (Duty 50%).
+        // from Spec "The length of divider is extended to 10 bits and all
+        // divider values shall be supported.
+        //
+        N = (BaseClockFreg / TargetFreq) / 2;
+
+        //
+        // Can only be N or N+1;
+        //
+        CurrFreq = BaseClockFreg / (2 * N);
+        if (TargetFreq < CurrFreq) {
+          N++;
+          CurrFreq = BaseClockFreg / (2 * N);
+        }
+
+        if (N > V_MMIO_CLKCTL_MAX_10BIT_FREQ_SEL) {
+          return EFI_UNSUPPORTED;
+        }
+
+        //
+        // Set upper bits of SDCLK Frequency Select (bits 7:6 of reg 0x2c).
+        //
+        *Bits |= ((UINT16) ((N >> 2) & B_MMIO_CLKCTL_UPR_SDCLK_FREQ_SEL_MASK));
+      }
+    }
+  }
+
+  //
+  // Set lower bits of SDCLK Frequency Select (bits 15:8 of reg 0x2c).
+  //
+  *Bits |= ((UINT16) ((UINT8) N) << 8);
+  DEBUG (
+    (EFI_D_INFO,
+    "SDIO:DividedClockModeBits: %dbit mode Want %dHz Got %dHz bits = %04x\r\n",
+    (Is8BitMode) ? 8 : 10,
+    TargetFreq,
+    CurrFreq,
+    (UINTN) *Bits
+    ));
+
+  return EFI_SUCCESS;
+}
+
+
+/**
+  Print type of error and command index
+
+  @param[in]  CommandIndex         Command index to set the command index field of command register.
+  @param[in]  ErrorCode            Error interrupt status read from host controller
+
+  @retval     EFI_DEVICE_ERROR
+  @retval     EFI_TIMEOUT
+  @retval     EFI_CRC_ERROR
+
+**/
+EFI_STATUS
+GetErrorReason (
+  IN  UINT16    CommandIndex,
+  IN  UINT16    ErrorCode
+  )
+{
+  EFI_STATUS    Status;
+
+  Status = EFI_DEVICE_ERROR;
+
+  DEBUG ((EFI_D_ERROR, "[%2d] -- ", CommandIndex));
+
+  if (ErrorCode & BIT0) {
+    Status = EFI_TIMEOUT;
+    DEBUG ((EFI_D_ERROR, "Command Timeout Erro"));
+  }
+
+  if (ErrorCode & BIT1) {
+    Status = EFI_CRC_ERROR;
+    DEBUG ((EFI_D_ERROR, "Command CRC Error"));
+  }
+
+  if (ErrorCode & BIT2) {
+    DEBUG ((EFI_D_ERROR, "Command End Bit Error"));
+  }
+
+  if (ErrorCode & BIT3) {
+    DEBUG ((EFI_D_ERROR, "Command Index Error"));
+  }
+  if (ErrorCode & BIT4) {
+    Status = EFI_TIMEOUT;
+    DEBUG ((EFI_D_ERROR, "Data Timeout Error"));
+  }
+
+  if (ErrorCode & BIT5) {
+    Status = EFI_CRC_ERROR;
+    DEBUG ((EFI_D_ERROR, "Data CRC Error"));
+  }
+
+  if (ErrorCode & BIT6) {
+    DEBUG ((EFI_D_ERROR, "Data End Bit Error"));
+  }
+
+  if (ErrorCode & BIT7) {
+    DEBUG ((EFI_D_ERROR, "Current Limit Error"));
+  }
+
+  if (ErrorCode & BIT8) {
+    DEBUG ((EFI_D_ERROR, "Auto CMD12 Error"));
+  }
+
+  if (ErrorCode & BIT9) {
+    DEBUG ((EFI_D_ERROR, "ADMA Error"));
+  }
+
+  DEBUG ((EFI_D_ERROR, "\n"));
+
+  return Status;
+}
+
+
+/**
+  Enable/Disable High Speed transfer mode
+
+  @param[in]   This                  A pointer to the EFI_SD_HOST_IO_PROTOCOL instance.
+  @param[in]   Enable                TRUE to Enable, FALSE to Disable
+
+  @retval      EFI_SUCCESS
+
+**/
+EFI_STATUS
+EFIAPI
+SetHighSpeedMode (
+  IN  EFI_SD_HOST_IO_PROTOCOL    *This,
+  IN  BOOLEAN                    Enable
+  )
+{
+  UINT32                 Data;
+  SDHOST_DATA            *SdHostData;
+  EFI_PCI_IO_PROTOCOL    *PciIo;
+
+  SdHostData = SDHOST_DATA_FROM_THIS (This);
+  PciIo      = SdHostData->PciIo;
+
+  PciIo->Mem.Read (
+               PciIo,
+               EfiPciIoWidthUint8,
+               0,
+               (UINT64) MMIO_HOSTCTL,
+               1,
+               &Data
+               );
+
+  if (Enable) {
+    DEBUG ((EFI_D_INFO, "Enable High Speed transfer mode ... \r\n"));
+    Data |= BIT2;
+  } else {
+    Data &= ~BIT2;
+  }
+  PciIo->Mem.Write (
+               PciIo,
+               EfiPciIoWidthUint8,
+               0,
+               (UINT64) MMIO_HOSTCTL,
+               1,
+               &Data
+               );
+
+  return EFI_SUCCESS;
+}
+EFI_STATUS
+EFIAPI
+SetDDRMode (
+  IN  EFI_SD_HOST_IO_PROTOCOL    *This,
+  IN  BOOLEAN                    Enable
+  )
+{
+  UINT16                 Data;
+  SDHOST_DATA            *SdHostData;
+  EFI_PCI_IO_PROTOCOL    *PciIo;
+
+  SdHostData = SDHOST_DATA_FROM_THIS (This);
+  PciIo = SdHostData->PciIo;
+  PciIo->Mem.Read (
+               PciIo,
+               EfiPciIoWidthUint16,
+               0,
+               (UINT64) MMIO_HOSTCTL2,
+               1,
+               &Data
+               );
+
+  Data &= 0xFFF0;
+  if (Enable) {
+    Data |= 0x0004; // Enable DDR50 by default, later should enable other mode like HS200/400
+    Data |= BIT3;   // Enable 1.8V Signaling
+  }
+  PciIo->Mem.Write (
+               PciIo,
+               EfiPciIoWidthUint16,
+               0,
+               (UINT64) MMIO_HOSTCTL2,
+               1,
+               &Data
+               );
+
+  return EFI_SUCCESS;
+}
+
+
+/**
+  Power on/off the LED associated with the slot
+
+  @param[in]   This                  A pointer to the EFI_SD_HOST_IO_PROTOCOL instance.
+  @param[in]   Enable                TRUE to set LED on, FALSE to set LED off
+
+  @retval      EFI_SUCCESS
+
+**/
+EFI_STATUS
+HostLEDEnable (
+  IN  EFI_SD_HOST_IO_PROTOCOL    *This,
+  IN  BOOLEAN                    Enable
+  )
+{
+  SDHOST_DATA            *SdHostData;
+  EFI_PCI_IO_PROTOCOL    *PciIo;
+  UINT32                 Data;
+
+  SdHostData = SDHOST_DATA_FROM_THIS (This);
+  PciIo = SdHostData->PciIo;
+
+  PciIo->Mem.Read (
+               PciIo,
+               EfiPciIoWidthUint8,
+               0,
+               (UINT64) MMIO_HOSTCTL,
+               1,
+               &Data
+               );
+
+  if (Enable) {
+    //
+    // LED On
+    //
+    Data |= BIT0;
+  } else {
+    //
+    // LED Off
+    //
+    Data &= ~BIT0;
+  }
+
+  PciIo->Mem.Write (
+               PciIo,
+               EfiPciIoWidthUint8,
+               0,
+               (UINT64) MMIO_HOSTCTL,
+               1,
+               &Data
+               );
+
+  return EFI_SUCCESS;
+}
+
+
+/**
+  The main function used to send the command to the card inserted into the SD host slot.
+  It will assemble the arguments to set the command register and wait for the command
+  and transfer completed until timeout. Then it will read the response register to fill
+  the ResponseData.
+
+  @param[in]   This                  A pointer to the EFI_SD_HOST_IO_PROTOCOL instance.
+  @param[in]   CommandIndex          The command index to set the command index field of command register.
+  @param[in]   Argument              Command argument to set the argument field of command register.
+  @param[in]   DataType              TRANSFER_TYPE, indicates no data, data in or data out.
+  @param[in]   Buffer                Contains the data read from / write to the device.
+  @param[in]   BufferSize            The size of the buffer.
+  @param[in]   ResponseType          RESPONSE_TYPE.
+  @param[in]   TimeOut               Time out value in 1 ms unit.
+  @param[out]  ResponseData          Depending on the ResponseType, such as CSD or card status.
+
+  @retval      EFI_SUCCESS
+  @retval      EFI_INVALID_PARAMETER
+  @retval      EFI_OUT_OF_RESOURCES
+  @retval      EFI_TIMEOUT
+  @retval      EFI_DEVICE_ERROR
+
+**/
+EFI_STATUS
+EFIAPI
+SendCommand (
+  IN   EFI_SD_HOST_IO_PROTOCOL    *This,
+  IN   UINT16                     CommandIndex,
+  IN   UINT32                     Argument,
+  IN   TRANSFER_TYPE              DataType,
+  IN   UINT8                      *Buffer, OPTIONAL
+  IN   UINT32                     BufferSize,
+  IN   RESPONSE_TYPE              ResponseType,
+  IN   UINT32                     TimeOut,
+  OUT  UINT32                     *ResponseData OPTIONAL
+  )
+{
+  EFI_STATUS            Status;
+  SDHOST_DATA           *SdHostData;
+  EFI_PCI_IO_PROTOCOL   *PciIo;
+  UINT32                ResponseDataCount;
+  UINT32                Data;
+  UINT64                Data64;
+  UINT8                 Index;
+  INTN                  TimeOut2;
+  BOOLEAN               AutoCMD12Enable = FALSE;
+
+  Status                = EFI_SUCCESS;
+  ResponseDataCount     = 1;
+  SdHostData            = SDHOST_DATA_FROM_THIS (This);
+  PciIo                 = SdHostData->PciIo;
+  AutoCMD12Enable       = (CommandIndex & AUTO_CMD12_ENABLE) ? TRUE : FALSE;
+  CommandIndex          = CommandIndex & CMD_INDEX_MASK;
+
+  if (Buffer != NULL && DataType == NoData) {
+    Status = EFI_INVALID_PARAMETER;
+    DEBUG ((EFI_D_ERROR, "SendCommand: invalid parameter \r\n"));
+    goto Exit;
+  }
+
+  if (((UINTN) Buffer & (This->HostCapability.BoundarySize - 1)) != (UINTN) NULL) {
+    Status = EFI_INVALID_PARAMETER;
+    DEBUG ((EFI_D_ERROR, "SendCommand: invalid parameter \r\n"));
+    goto Exit;
+  }
+
+  DEBUG ((EFI_D_INFO, "SendCommand: Command Index = %d \r\n", CommandIndex));
+
+  TimeOut2 = 1000; // 10 ms
+  do {
+    PciIo->Mem.Read (
+                 PciIo,
+                 EfiPciIoWidthUint32,
+                 0,
+                 (UINT64) MMIO_PSTATE,
+                 1,
+                 &Data
+                 );
+
+     gBS->Stall (10);
+  } while ((TimeOut2-- > 0) && (Data &BIT0));
+  TimeOut2 = 1000; // 10 ms
+  do {
+    PciIo->Mem.Read (
+                 PciIo,
+                 EfiPciIoWidthUint32,
+                 0,
+                 (UINT64) MMIO_PSTATE,
+                 1,
+                 &Data
+                 );
+
+    gBS->Stall (10);
+  } while ((TimeOut2-- > 0) && (Data & BIT1));
+
+  //
+  // Clear status bits
+  //
+  Data = 0xFFFF;
+  PciIo->Mem.Write (
+               PciIo,
+               EfiPciIoWidthUint16,
+               0,
+               (UINT64) MMIO_NINTSTS,
+               1,
+               &Data
+               );
+
+  Data = 0xFFFF;
+  PciIo->Mem.Write (
+               PciIo,
+               EfiPciIoWidthUint16,
+               0,
+               (UINT64) MMIO_ERINTSTS,
+               1,
+               &Data
+               );
+
+
+  if (Buffer != NULL) {
+     PciIo->Mem.Write (
+                  PciIo,
+                  EfiPciIoWidthUint32,
+                  0,
+                  (UINT64) MMIO_DMAADR,
+                  1,
+                  &Buffer
+                  );
+
+     PciIo->Mem.Read (
+                  PciIo,
+                  EfiPciIoWidthUint16,
+                  0,
+                  (UINT64) MMIO_BLKSZ,
+                  1,
+                  &Data
+                  );
+
+     Data &= ~(0xFFF);
+     if (BufferSize <= SdHostData->BlockLength) {
+       Data |= (BufferSize | 0x7000);
+     } else {
+       Data |= (SdHostData->BlockLength | 0x7000);
+     }
+
+     PciIo->Mem.Write (
+                  PciIo,
+                  EfiPciIoWidthUint16,
+                  0,
+                  (UINT64) MMIO_BLKSZ,
+                  1,
+                  &Data
+                  );
+
+     if (BufferSize <= SdHostData->BlockLength) {
+       Data = 1;
+     } else {
+       Data = BufferSize / SdHostData->BlockLength;
+     }
+     PciIo->Mem.Write (
+                  PciIo,
+                  EfiPciIoWidthUint16,
+                  0,
+                  (UINT64) MMIO_BLKCNT,
+                  1,
+                  &Data
+                  );
+
+  } else {
+    Data = 0;
+    PciIo->Mem.Write (
+                 PciIo,
+                 EfiPciIoWidthUint16,
+                 0,
+                 (UINT64) MMIO_BLKSZ,
+                 1,
+                 &Data
+                 );
+
+    PciIo->Mem.Write (
+                 PciIo,
+                 EfiPciIoWidthUint16,
+                 0,
+                 (UINT64) MMIO_BLKCNT,
+                 1,
+                 &Data
+                 );
+  }
+
+  //
+  // Argument
+  //
+  Data = Argument;
+  PciIo->Mem.Write (
+               PciIo,
+               EfiPciIoWidthUint32,
+               0,
+               (UINT64) MMIO_CMDARG,
+               1,
+               &Data
+               );
+
+  PciIo->Mem.Read (
+               PciIo,
+               EfiPciIoWidthUint16,
+               0,
+               (UINT64) MMIO_XFRMODE,
+               1,
+               &Data
+               );
+
+  DEBUG ((EFI_D_INFO, "Transfer mode read  = 0x%x \r\n", (Data & 0xFFFF)));
+
+  //
+  // BIT0 - DMA Enable
+  // BIT2 - Auto Cmd12
+  //
+  if (DataType == InData) {
+    Data |= BIT4 | BIT0;
+  } else if (DataType == OutData){
+    Data &= ~BIT4;
+    Data |= BIT0;
+  } else {
+    Data &= ~(BIT4 | BIT0);
+  }
+
+  if (BufferSize <= SdHostData->BlockLength) {
+    Data &= ~(BIT5 | BIT1 | BIT2);
+    Data |= BIT1; // Enable block count always
+  } else {
+     if (SdHostData->IsAutoStopCmd && AutoCMD12Enable) {
+     Data |= (BIT5 | BIT1 | BIT2);
+     } else {
+     Data |= (BIT5 | BIT1);
+     }
+  }
+
+  DEBUG ((EFI_D_INFO, "Transfer mode write = 0x%x \r\n", (Data & 0xffff)));
+  PciIo->Mem.Write (
+               PciIo,
+               EfiPciIoWidthUint16,
+               0,
+               (UINT64) MMIO_XFRMODE,
+               1,
+               &Data
+               );
+
+  //
+  //Command
+  //
+  //ResponseTypeSelect    IndexCheck    CRCCheck    ResponseType
+  //  00                     0            0           NoResponse
+  //  01                     0            1           R2
+  //  10                     0            0           R3, R4
+  //  10                     1            1           R1, R5, R6, R7
+  //  11                     1            1           R1b, R5b
+  //
+  switch (ResponseType) {
+    case ResponseNo:
+      Data = (CommandIndex << 8);
+      ResponseDataCount = 0;
+      break;
+
+    case ResponseR1:
+    case ResponseR5:
+    case ResponseR6:
+    case ResponseR7:
+      Data = (CommandIndex << 8) | BIT1 | BIT4| BIT3;
+      ResponseDataCount = 1;
+      break;
+
+    case ResponseR1b:
+    case ResponseR5b:
+      Data = (CommandIndex << 8) | BIT0 | BIT1 | BIT4| BIT3;
+      ResponseDataCount = 1;
+      break;
+
+    case ResponseR2:
+      Data = (CommandIndex << 8) | BIT0 | BIT3;
+      ResponseDataCount = 4;
+      break;
+
+    case ResponseR3:
+    case ResponseR4:
+      Data = (CommandIndex << 8) | BIT1;
+      ResponseDataCount = 1;
+      break;
+
+    default:
+      ASSERT (0);
+      Status = EFI_INVALID_PARAMETER;
+      DEBUG ((EFI_D_ERROR, "SendCommand: invalid parameter \r\n"));
+      goto Exit;
+  }
+
+  if (DataType != NoData) {
+    Data |= BIT5;
+  }
+
+  HostLEDEnable (This, TRUE);
+
+  PciIo->Mem.Write (
+               PciIo,
+               EfiPciIoWidthUint16,
+               0,
+               (UINT64) MMIO_SDCMD,
+               1,
+               &Data
+               );
+
+  Data = 0;
+  do {
+    PciIo->Mem.Read (
+                 PciIo,
+                 EfiPciIoWidthUint16,
+                 0,
+                 (UINT64) MMIO_ERINTSTS,
+                 1,
+                 &Data
+                 );
+
+    if ((Data & 0x07FF) != 0) {
+      Status = GetErrorReason (CommandIndex, (UINT16) Data);
+      DEBUG ((EFI_D_ERROR, "SendCommand: Error happens \r\n"));
+      goto Exit;
+    }
+
+    PciIo->Mem.Read (
+                 PciIo,
+                 EfiPciIoWidthUint16,
+                 0,
+                 (UINT64) MMIO_NINTSTS,
+                 1,
+                 &Data
+                 );
+
+    if ((Data & BIT0) == BIT0) {
+      //
+      //Command completed, can read response
+      //
+      if (DataType == NoData) {
+        break;
+      } else {
+        //
+        // Transfer completed
+        //
+        if ((Data & BIT1) == BIT1) {
+          break;
+        }
+      }
+    }
+
+    gBS->Stall (1 * 1000);
+
+    TimeOut --;
+
+  } while (TimeOut > 0);
+
+  if (TimeOut == 0) {
+    Status = EFI_TIMEOUT;
+    DEBUG ((EFI_D_ERROR, "SendCommand: Time out \r\n"));
+    goto Exit;
+  }
+
+  if (ResponseData != NULL) {
+    PciIo->Mem.Read (
+                 PciIo,
+                 EfiPciIoWidthUint32,
+                 0,
+                 (UINT64) MMIO_RESP,
+                 ResponseDataCount,
+                 ResponseData
+                 );
+
+    if (ResponseType == ResponseR2) {
+      //
+      // Adjustment for R2 response
+      //
+      Data = 1;
+      for (Index = 0; Index < ResponseDataCount; Index++) {
+        Data64 = LShiftU64 (*ResponseData, 8);
+        *ResponseData = (UINT32) ((Data64 & 0xFFFFFFFF) | Data);
+        Data = (UINT32) RShiftU64 (Data64, 32);
+        ResponseData++;
+      }
+    }
+  }
+
+Exit:
+  HostLEDEnable (This, FALSE);
+  return Status;
+}
+
+
+/**
+  Set max clock frequency of the host, the actual frequency may not be the same as MaxFrequency.
+  It depends on the max frequency the host can support, divider, and host speed mode.
+
+  @param[in]  This                  A pointer to the EFI_SD_HOST_IO_PROTOCOL instance.
+  @param[in]  MaxFrequency          Max frequency in HZ.
+
+  @retval     EFI_SUCCESS
+  @retval     EFI_TIMEOUT
+
+**/
+EFI_STATUS
+EFIAPI
+SetClockFrequency (
+  IN  EFI_SD_HOST_IO_PROTOCOL    *This,
+  IN  UINT32                     MaxFrequency
+  )
+{
+  UINT32                 Data;
+  UINT16                 FreqSelBits;
+  EFI_STATUS             Status;
+  SDHOST_DATA            *SdHostData;
+  EFI_PCI_IO_PROTOCOL    *PciIo;
+  UINT32                 TimeOutCount;
+  UINT32                 Revision;
+
+  SdHostData = SDHOST_DATA_FROM_THIS (This);
+  PciIo = SdHostData->PciIo;
+  Data = 0;
+  PciIo->Mem.Write (
+               PciIo,
+               EfiPciIoWidthUint16,
+               0,
+               (UINT64) MMIO_CLKCTL,
+               1,
+               &Data
+               );
+
+  PciIo->Mem.Read (
+               PciIo,
+               EfiPciIoWidthUint8,
+               0,
+               (UINT64) MMIO_CTRLRVER,
+               1,
+               &Revision
+               );
+
+  Revision &= 0x000000FF;
+
+  Status = DividedClockModeBits (
+             SdHostData->BaseClockInMHz * 1000 * 1000,
+             MaxFrequency,
+             (Revision < SDHCI_SPEC_300),
+             &FreqSelBits
+             );
+
+  if (EFI_ERROR (Status)) {
+    //
+    // Cannot reach MaxFrequency with SdHostData->BaseClockInMHz.
+    //
+    ASSERT_EFI_ERROR (Status);
+    return Status;
+  }
+
+  Data = 0;
+
+  //
+  // Enable internal clock and Stop Clock Enable
+  //
+  Data = BIT0;
+  PciIo->Mem.Write (
+               PciIo,
+               EfiPciIoWidthUint16,
+               0,
+               (UINT64) MMIO_CLKCTL,
+               1,
+               &Data
+               );
+
+  TimeOutCount = TIME_OUT_1S;
+  do {
+    PciIo->Mem.Read (
+                 PciIo,
+                 EfiPciIoWidthUint16,
+                 0,
+                 (UINT64) MMIO_CLKCTL,
+                 1,
+                 &Data
+                 );
+
+    gBS->Stall (1 * 1000);
+    TimeOutCount --;
+    if (TimeOutCount == 0) {
+      DEBUG ((EFI_D_ERROR, "SetClockFrequency: Time out \r\n"));
+      return EFI_TIMEOUT;
+    }
+  } while ((Data & BIT1) != BIT1);
+
+  DEBUG ((EFI_D_INFO, "Base Clock In MHz: %d\r\n", SdHostData->BaseClockInMHz));
+
+  Data = (BIT0 | ((UINT32) FreqSelBits));
+  DEBUG ((EFI_D_INFO, "Data write to MMIO_CLKCTL: 0x%04x \r\n", Data));
+  PciIo->Mem.Write (
+               PciIo,
+               EfiPciIoWidthUint16,
+               0,
+               (UINT64) MMIO_CLKCTL,
+               1,
+               &Data
+               );
+
+  TimeOutCount = TIME_OUT_1S;
+  do {
+    PciIo->Mem.Read (
+                 PciIo,
+                 EfiPciIoWidthUint16,
+                 0,
+                 (UINT64) MMIO_CLKCTL,
+                 1,
+                 &Data
+                 );
+
+    gBS->Stall (1 * 1000);
+    TimeOutCount --;
+    if (TimeOutCount == 0) {
+      DEBUG ((EFI_D_ERROR, "SetClockFrequency: Time out \r\n"));
+      return EFI_TIMEOUT;
+    }
+  } while ((Data & BIT1) != BIT1);
+  gBS->Stall (20 * 1000);
+  Data |= BIT2;
+  PciIo->Mem.Write (
+               PciIo,
+               EfiPciIoWidthUint16,
+               0,
+               (UINT64) MMIO_CLKCTL,
+               1,
+               &Data
+               );
+
+  return EFI_SUCCESS;
+}
+
+
+/**
+  Set bus width of the host controller
+
+  @param[in]   This                  A pointer to the EFI_SD_HOST_IO_PROTOCOL instance.
+  @param[in]   BusWidth              Bus width in 1, 4, 8 bits.
+
+  @retval      EFI_SUCCESS
+  @retval      EFI_INVALID_PARAMETER
+
+**/
+EFI_STATUS
+EFIAPI
+SetBusWidth (
+  IN  EFI_SD_HOST_IO_PROTOCOL    *This,
+  IN  UINT32                     BusWidth
+  )
+{
+  SDHOST_DATA            *SdHostData;
+  EFI_PCI_IO_PROTOCOL    *PciIo;
+  UINT8                  Data;
+
+  SdHostData = SDHOST_DATA_FROM_THIS (This);
+
+  if ((BusWidth != 1) && (BusWidth != 4) && (BusWidth != 8)) {
+    DEBUG ((EFI_D_ERROR, "SetBusWidth: Invalid parameter \r\n"));
+    return EFI_INVALID_PARAMETER;
+  }
+
+  if ((SdHostData->SdHostIo.HostCapability.BusWidth8 == FALSE) && (BusWidth == 8)) {
+     DEBUG ((EFI_D_ERROR, "SetBusWidth: Invalid parameter \r\n"));
+     return EFI_INVALID_PARAMETER;
+  }
+
+  PciIo = SdHostData->PciIo;
+
+  PciIo->Mem.Read (
+               PciIo,
+               EfiPciIoWidthUint8,
+               0,
+               (UINT64) MMIO_HOSTCTL,
+               1,
+               &Data
+               );
+  //
+  // BIT5 8-bit MMC Support (MMC8):
+  // If set, IOH supports 8-bit MMC. When cleared, IOH does not support this feature
+  //
+  if (BusWidth == 8) {
+    DEBUG ((EFI_D_INFO, "Bus Width is 8-bit ... \r\n"));
+    Data |= BIT5;
+  } else if (BusWidth == 4) {
+    DEBUG ((EFI_D_INFO, "Bus Width is 4-bit ... \r\n"));
+    Data &= ~BIT5;
+    Data |= BIT1;
+  } else {
+    DEBUG ((EFI_D_INFO, "Bus Width is 1-bit ... \r\n"));
+    Data &= ~BIT5;
+    Data &= ~BIT1;
+  }
+
+  PciIo->Mem.Write (
+               PciIo,
+               EfiPciIoWidthUint8,
+               0,
+               (UINT64) MMIO_HOSTCTL,
+               1,
+               &Data
+               );
+
+  return EFI_SUCCESS;
+}
+
+
+/**
+  Set voltage which could supported by the host controller.
+  Support 0(Power off the host), 1.8V, 3.0V, 3.3V
+
+  @param[in]   This                   A pointer to the EFI_SD_HOST_IO_PROTOCOL instance.
+  @param[in]   Voltage                Units in 0.1 V.
+
+  @retval      EFI_SUCCESS
+  @retval      EFI_INVALID_PARAMETER
+
+**/
+EFI_STATUS
+EFIAPI
+SetHostVoltage (
+  IN  EFI_SD_HOST_IO_PROTOCOL    *This,
+  IN  UINT32                     Voltage
+  )
+{
+  SDHOST_DATA            *SdHostData;
+  EFI_PCI_IO_PROTOCOL    *PciIo;
+  UINT8                  Data;
+  EFI_STATUS             Status;
+
+  SdHostData = SDHOST_DATA_FROM_THIS (This);
+  PciIo      = SdHostData->PciIo;
+  Status     = EFI_SUCCESS;
+
+  PciIo->Mem.Read (
+               PciIo,
+               EfiPciIoWidthUint8,
+               0,
+               (UINT64) MMIO_PWRCTL,
+               1,
+               &Data
+               );
+
+  if (Voltage == 0) {
+    //
+    // Power Off the host
+    //
+    Data &= ~BIT0;
+  } else if (Voltage <= 18 && This->HostCapability.V18Support) {
+    //
+    // 1.8V
+    //
+    Data |= (BIT1 | BIT3 | BIT0);
+  } else if (Voltage > 18 &&  Voltage <= 30 && This->HostCapability.V30Support) {
+    //
+    // 3.0V
+    //
+    Data |= (BIT2 | BIT3 | BIT0);
+  } else if (Voltage > 30 && Voltage <= 33 && This->HostCapability.V33Support) {
+    //
+    // 3.3V
+    //
+    Data |= (BIT1 | BIT2 | BIT3 | BIT0);
+  } else {
+    Status = EFI_UNSUPPORTED;
+    goto Exit;
+  }
+
+  PciIo->Mem.Write (
+               PciIo,
+               EfiPciIoWidthUint8,
+               0,
+               (UINT64) MMIO_PWRCTL,
+               1,
+               &Data
+               );
+
+  gBS->Stall (10 * 1000);
+
+Exit:
+  return Status;
+}
+
+
+/**
+  Reset the host controller.
+
+  @param[in]   This                  A pointer to the EFI_SD_HOST_IO_PROTOCOL instance.
+  @param[in]   ResetAll              TRUE to reset all.
+
+  @retval      EFI_SUCCESS
+  @retval      EFI_TIMEOUT
+
+**/
+EFI_STATUS
+EFIAPI
+ResetSdHost (
+  IN  EFI_SD_HOST_IO_PROTOCOL    *This,
+  IN  RESET_TYPE                 ResetType
+  )
+{
+  SDHOST_DATA            *SdHostData;
+  EFI_PCI_IO_PROTOCOL    *PciIo;
+  UINT32                 Data;
+  UINT16                 ErrStatus;
+  UINT32                 Mask;
+  UINT32                 TimeOutCount;
+  UINT16                 SaveClkCtl;
+  UINT16                 ZeroClkCtl;
+
+  SdHostData = SDHOST_DATA_FROM_THIS (This);
+  PciIo      = SdHostData->PciIo;
+  Mask       = 0;
+  ErrStatus  = 0;
+
+  if (ResetType == Reset_Auto) {
+    PciIo->Mem.Read (
+                 PciIo,
+                 EfiPciIoWidthUint16,
+                 0,
+                 (UINT64) MMIO_ERINTSTS,
+                 1,
+                 &ErrStatus
+                 );
+
+    if ((ErrStatus & 0xF) != 0) {
+      //
+      // Command Line
+      //
+      Mask |= BIT1;
+    }
+    if ((ErrStatus & 0x70) != 0) {
+      //
+      // Data Line
+      //
+      Mask |= BIT2;
+    }
+  }
+
+  if (ResetType == Reset_DAT || ResetType == Reset_DAT_CMD) {
+    Mask |= BIT2;
+  }
+  if (ResetType == Reset_CMD || ResetType == Reset_DAT_CMD) {
+    Mask |= BIT1;
+  }
+  if (ResetType == Reset_All) {
+    Mask = BIT0;
+  }
+
+  if (Mask == 0) {
+    return EFI_SUCCESS;
+  }
+
+  //
+  // To improve SD stability, we zero the MMIO_CLKCTL register and
+  // stall for 50 microseconds before reseting the controller.  We
+  // restore the register setting following the reset operation.
+  //
+  PciIo->Mem.Read (
+               PciIo,
+               EfiPciIoWidthUint16,
+               0,
+               (UINT64) MMIO_CLKCTL,
+               1,
+               &SaveClkCtl
+               );
+
+  ZeroClkCtl = (UINT16) 0;
+  PciIo->Mem.Write (
+               PciIo,
+               EfiPciIoWidthUint16,
+               0,
+               (UINT64) MMIO_CLKCTL,
+               1,
+               &ZeroClkCtl
+               );
+
+  gBS->Stall (50);
+
+  //
+  // Reset the SD host controller
+  //
+  PciIo->Mem.Write (
+               PciIo,
+               EfiPciIoWidthUint8,
+               0,
+               (UINT64) MMIO_SWRST,
+               1,
+               &Mask
+               );
+
+  Data          = 0;
+  TimeOutCount  = TIME_OUT_1S;
+  do {
+
+    gBS->Stall (1 * 1000);
+
+    TimeOutCount --;
+
+    PciIo->Mem.Read (
+                 PciIo,
+                 EfiPciIoWidthUint8,
+                 0,
+                 (UINT64) MMIO_SWRST,
+                 1,
+                 &Data
+                 );
+
+    if ((Data & Mask) == 0) {
+      break;
+    }
+  } while (TimeOutCount > 0);
+
+  //
+  // We now restore the MMIO_CLKCTL register which we set to 0 above.
+  //
+  PciIo->Mem.Write (
+               PciIo,
+               EfiPciIoWidthUint16,
+               0,
+               (UINT64) MMIO_CLKCTL,
+               1,
+               &SaveClkCtl
+               );
+
+  if (TimeOutCount == 0) {
+    DEBUG ((EFI_D_ERROR, "ResetSdHost: Time out \r\n"));
+    return EFI_TIMEOUT;
+  }
+
+  return EFI_SUCCESS;
+}
+
+
+/**
+  Enable auto stop on the host controller.
+
+  @param[in]   This                  A pointer to the EFI_SD_HOST_IO_PROTOCOL instance.
+  @param[in]   Enable                TRUE to enable, FALSE to disable.
+
+  @retval      EFI_SUCCESS
+  @retval      EFI_TIMEOUT
+
+**/
+EFI_STATUS
+EFIAPI
+EnableAutoStopCmd (
+  IN  EFI_SD_HOST_IO_PROTOCOL    *This,
+  IN  BOOLEAN                    Enable
+  )
+{
+  SDHOST_DATA            *SdHostData;
+
+  SdHostData = SDHOST_DATA_FROM_THIS (This);
+
+  SdHostData->IsAutoStopCmd = Enable;
+
+  return EFI_SUCCESS;
+}
+
+
+/**
+  Set the Block length on the host controller.
+
+  @param[in]   This                  A pointer to the EFI_SD_HOST_IO_PROTOCOL instance.
+  @param[in]   BlockLength           card supportes block length.
+
+  @retval      EFI_SUCCESS
+  @retval      EFI_TIMEOUT
+
+**/
+EFI_STATUS
+EFIAPI
+SetBlockLength (
+  IN  EFI_SD_HOST_IO_PROTOCOL    *This,
+  IN  UINT32                     BlockLength
+  )
+{
+  SDHOST_DATA                    *SdHostData;
+
+  SdHostData = SDHOST_DATA_FROM_THIS (This);
+
+  DEBUG ((EFI_D_INFO, "Block length on the host controller: %d \r\n", BlockLength));
+  SdHostData->BlockLength = BlockLength;
+
+  return EFI_SUCCESS;
+}
+
+
+/**
+  Find whether these is a card inserted into the slot. If so init the host.
+  If not, return EFI_NOT_FOUND.
+
+  @param[in]   This                  A pointer to the EFI_SD_HOST_IO_PROTOCOL instance.
+
+  @retval      EFI_SUCCESS
+  @retval      EFI_NOT_FOUND
+
+**/
+EFI_STATUS
+EFIAPI
+DetectCardAndInitHost (
+  IN  EFI_SD_HOST_IO_PROTOCOL    *This
+  )
+{
+  SDHOST_DATA            *SdHostData;
+  EFI_PCI_IO_PROTOCOL    *PciIo;
+  UINT32                 Data;
+  EFI_STATUS             Status;
+  UINT8                  Voltages[] = { 33, 30, 18 };
+  UINTN                  Loop;
+
+  SdHostData = SDHOST_DATA_FROM_THIS (This);
+  PciIo      = SdHostData->PciIo;
+  Status     = EFI_NOT_FOUND;
+
+  Data = 0;
+  PciIo->Mem.Read (
+               PciIo,
+               EfiPciIoWidthUint32,
+               0,
+               (UINT64) MMIO_PSTATE,
+               1,
+               &Data
+               );
+
+  if ((Data & (BIT16 | BIT17 | BIT18)) != (BIT16 | BIT17 | BIT18)) {
+    //
+    // Has no card inserted
+    //
+    DEBUG ((EFI_D_INFO, "DetectCardAndInitHost: No Cards \r\n"));
+    Status = EFI_NOT_FOUND;
+    goto Exit;
+  }
+  DEBUG ((EFI_D_INFO, "DetectCardAndInitHost: Find Cards \r\n"));
+
+  Status =  EFI_NOT_FOUND;
+  for (Loop = 0; Loop < sizeof (Voltages); Loop++) {
+    DEBUG ((
+      EFI_D_INFO,
+      "DetectCardAndInitHost: SetHostVoltage %d.%dV \r\n",
+      Voltages[Loop] / 10,
+      Voltages[Loop] % 10
+      ));
+    Status = SetHostVoltage (This, Voltages[Loop]);
+    if (EFI_ERROR (Status)) {
+      DEBUG ((EFI_D_INFO, "DetectCardAndInitHost set voltages: [failed]\n"));
+    } else {
+      DEBUG ((EFI_D_INFO, "DetectCardAndInitHost set voltages: [success]\n"));
+      break;
+    }
+  }
+  if (EFI_ERROR (Status)) {
+    DEBUG ((EFI_D_ERROR, "DetectCardAndInitHost: Fail to set voltage \r\n"));
+    goto Exit;
+  }
+
+  Status = SetClockFrequency (This, FREQUENCY_OD);
+  if (EFI_ERROR (Status)) {
+    DEBUG ((EFI_D_ERROR, "DetectCardAndInitHost: Fail to set frequency \r\n"));
+    goto Exit;
+  }
+  SetBusWidth (This, 1);
+
+  //
+  // Enable normal status change
+  //
+  Data = (BIT0 | BIT1);
+
+  PciIo->Mem.Write (
+               PciIo,
+               EfiPciIoWidthUint16,
+               0,
+               (UINT64) MMIO_NINTEN,
+               1,
+               &Data
+               );
+
+  //
+  // Enable error status change
+  //
+  PciIo->Mem.Read (
+               PciIo,
+               EfiPciIoWidthUint16,
+               0,
+               (UINT64) MMIO_ERINTEN,
+               1,
+               &Data
+               );
+
+  Data |= (BIT0 | BIT1 | BIT2 | BIT3 | BIT4 | BIT5 | BIT6 | BIT7 | BIT8);
+
+  PciIo->Mem.Write (
+               PciIo,
+               EfiPciIoWidthUint16,
+               0,
+               (UINT64) MMIO_ERINTEN,
+               1,
+               &Data
+               );
+
+  //
+  // Data transfer Timeout control
+  //
+  Data = 0x0E;
+
+  PciIo->Mem.Write (
+               PciIo,
+               EfiPciIoWidthUint8,
+               0,
+               (UINT64) MMIO_TOCTL,
+               1,
+               &Data
+               );
+  //
+  // Set Default Bus width as 1 bit
+  //
+
+Exit:
+  return Status;
+
+}
+
+
+/**
+  Entry point for EFI drivers.
+
+  @param[in]   ImageHandle      EFI_HANDLE.
+  @param[in]   SystemTable      EFI_SYSTEM_TABLE.
+
+  @retval      EFI_SUCCESS      Driver is successfully loaded.
+  @retval      Others           Failed.
+
+**/
+EFI_STATUS
+EFIAPI
+InitializeSdController (
+  IN EFI_HANDLE           ImageHandle,
+  IN EFI_SYSTEM_TABLE     *SystemTable
+  )
+{
+  return EfiLibInstallDriverBindingComponentName2 (
+           ImageHandle,
+           SystemTable,
+           &gSdControllerDriverBinding,
+           ImageHandle,
+           &gSdControllerName,
+           &gSdControllerName2
+           );
+}
+
+
+/**
+  Test to see if this driver supports ControllerHandle. Any
+  ControllerHandle that has SdHostIoProtocol installed will be supported.
+
+  @param[in]   This                 Protocol instance pointer.
+  @param[in]   Controller           Handle of device to test.
+  @param[in]   RemainingDevicePath  Not used.
+
+  @retval      EFI_SUCCESS          This driver supports this device.
+  @retval      EFI_UNSUPPORTED      This driver does not support this device.
+
+**/
+EFI_STATUS
+EFIAPI
+SdControllerSupported (
+  IN EFI_DRIVER_BINDING_PROTOCOL     *This,
+  IN EFI_HANDLE                      Controller,
+  IN EFI_DEVICE_PATH_PROTOCOL        *RemainingDevicePath
+  )
+{
+  EFI_STATUS                OpenStatus;
+  EFI_STATUS                Status;
+  EFI_PCI_IO_PROTOCOL       *PciIo;
+  PCI_CLASSC                PciClass;
+  EFI_SD_HOST_IO_PROTOCOL   *SdHostIo;
+  UINTN                      Seg, Bus, Dev, Func;
+
+  Status = gBS->OpenProtocol (
+                  Controller,
+                  &gEfiSdHostIoProtocolGuid,
+                  (VOID **) &SdHostIo,
+                  This->DriverBindingHandle,
+                  Controller,
+                  EFI_OPEN_PROTOCOL_GET_PROTOCOL
+                  );
+
+  if (!EFI_ERROR (Status)) {
+    DEBUG (( DEBUG_INFO, "SdHost controller is already started\n"));
+    return EFI_ALREADY_STARTED;
+  }
+
+  //
+  // Test whether there is PCI IO Protocol attached on the controller handle.
+  //
+  OpenStatus = gBS->OpenProtocol (
+                      Controller,
+                      &gEfiPciIoProtocolGuid,
+                      (VOID **) &PciIo,
+                      This->DriverBindingHandle,
+                      Controller,
+                      EFI_OPEN_PROTOCOL_BY_DRIVER
+                      );
+
+  if (EFI_ERROR (OpenStatus)) {
+    return OpenStatus;
+  }
+
+  Status = PciIo->Pci.Read (
+                        PciIo,
+                        EfiPciIoWidthUint8,
+                        PCI_CLASSCODE_OFFSET,
+                        sizeof (PCI_CLASSC) / sizeof (UINT8),
+                        &PciClass
+                        );
+
+  if (EFI_ERROR (Status)) {
+    Status = EFI_UNSUPPORTED;
+    goto ON_EXIT;
+  }
+
+  //
+  // Test whether the controller belongs to SD type
+  //
+  if ((PciClass.BaseCode != PCI_CLASS_SYSTEM_PERIPHERAL) ||
+      (PciClass.SubClassCode != PCI_SUBCLASS_SD_HOST_CONTROLLER) ||
+      ((PciClass.PI != PCI_IF_STANDARD_HOST_NO_DMA) && (PciClass.PI != PCI_IF_STANDARD_HOST_SUPPORT_DMA))
+      ) {
+
+    Status = EFI_UNSUPPORTED;
+    goto ON_EXIT;
+  }
+
+  Status = PciIo->GetLocation (
+                    PciIo,
+                    &Seg,
+                    &Bus,
+                    &Dev,
+                    &Func
+                    );
+
+  if (EFI_ERROR (Status)) {
+    Status = EFI_UNSUPPORTED;
+    goto ON_EXIT;
+  }
+
+  if ((Seg != 0) || (Bus != 0) || (Dev != 27) || (Func != 0)) {
+    //
+    // This is not the SD controller, bail.
+    //
+    Status = EFI_UNSUPPORTED;
+    goto ON_EXIT;
+  }
+
+  DEBUG ((EFI_D_INFO, "%a(#%d) - Seg %d, bus:%d, Dev:%d, Func:%d\n", __FUNCTION__, __LINE__, Seg, Bus, Dev, Func));
+
+ON_EXIT:
+  gBS->CloseProtocol (
+         Controller,
+         &gEfiPciIoProtocolGuid,
+         This->DriverBindingHandle,
+         Controller
+         );
+
+  return Status;
+}
+
+
+/**
+  Starting the SD Host Controller Driver.
+
+  @param[in]   This                 Protocol instance pointer.
+  @param[in]   Controller           Handle of device to test.
+  @param[in]   RemainingDevicePath  Not used.
+
+  @retval      EFI_SUCCESS          This driver supports this device.
+  @retval      EFI_UNSUPPORTED      This driver does not support this device.
+  @retval      EFI_DEVICE_ERROR     This driver cannot be started due to device Error.
+                                    EFI_OUT_OF_RESOURCES- Failed due to resource shortage.
+
+**/
+EFI_STATUS
+EFIAPI
+SdControllerStart (
+  IN EFI_DRIVER_BINDING_PROTOCOL     *This,
+  IN EFI_HANDLE                      Controller,
+  IN EFI_DEVICE_PATH_PROTOCOL        *RemainingDevicePath
+  )
+{
+  EFI_STATUS            Status;
+  EFI_PCI_IO_PROTOCOL   *PciIo;
+  SDHOST_DATA           *SdHostData;
+  UINT32                Data;
+
+  SdHostData = NULL;
+  Data = 0;
+
+  //
+  // Open PCI I/O Protocol and save pointer to open protocol
+  // in private data area.
+  //
+  Status = gBS->OpenProtocol (
+                  Controller,
+                  &gEfiPciIoProtocolGuid,
+                  (VOID **) &PciIo,
+                  This->DriverBindingHandle,
+                  Controller,
+                  EFI_OPEN_PROTOCOL_BY_DRIVER
+                  );
+
+  if (EFI_ERROR (Status)) {
+    goto Exit;
+  }
+
+  //
+  // Enable the SD Host Controller MMIO space
+  //
+  Status = PciIo->Attributes (
+                    PciIo,
+                    EfiPciIoAttributeOperationEnable,
+                    EFI_PCI_DEVICE_ENABLE,
+                    NULL
+                    );
+
+  if (EFI_ERROR (Status)) {
+    Status = EFI_OUT_OF_RESOURCES;
+    goto Exit;
+  }
+
+  SdHostData = (SDHOST_DATA *) AllocateZeroPool (sizeof (SDHOST_DATA));
+  if (SdHostData == NULL) {
+    Status =  EFI_OUT_OF_RESOURCES;
+    goto Exit;
+  }
+
+  SdHostData->Signature   = SDHOST_DATA_SIGNATURE;
+  SdHostData->PciIo       = PciIo;
+
+  CopyMem (&SdHostData->SdHostIo, &mSdHostIo, sizeof (EFI_SD_HOST_IO_PROTOCOL));
+
+  ResetSdHost (&SdHostData->SdHostIo, Reset_All);
+
+  PciIo->Mem.Read (
+               PciIo,
+               EfiPciIoWidthUint16,
+               0,
+               (UINT64) MMIO_CTRLRVER,
+               1,
+               &Data
+               );
+
+  SdHostData->SdHostIo.HostCapability.HostVersion = Data & 0xFF;
+  DEBUG ((EFI_D_INFO, "SdHostDriverBindingStart: HostVersion 0x%x \r\n", SdHostData->SdHostIo.HostCapability.HostVersion));
+
+  PciIo->Mem.Read (
+               PciIo,
+               EfiPciIoWidthUint32,
+               0,
+               (UINT64) MMIO_CAP,
+               1,
+               &Data
+               );
+
+  DEBUG ((EFI_D_INFO, "SdHostDriverBindingStart: MMIO_CAP 0x%x \r\n", Data));
+  if ((Data & BIT18) != 0) {
+    SdHostData->SdHostIo.HostCapability.BusWidth8 = TRUE;
+  }
+
+  if ((Data & BIT21) != 0) {
+    SdHostData->SdHostIo.HostCapability.HighSpeedSupport = TRUE;
+  }
+
+  if ((Data & BIT24) != 0) {
+    SdHostData->SdHostIo.HostCapability.V33Support = TRUE;
+  }
+
+  if ((Data & BIT25) != 0) {
+    SdHostData->SdHostIo.HostCapability.V30Support = TRUE;
+  }
+
+  if ((Data & BIT26) != 0) {
+    SdHostData->SdHostIo.HostCapability.V18Support = TRUE;
+  }
+
+  SdHostData->SdHostIo.HostCapability.BusWidth4 = TRUE;
+
+  if (SdHostData->SdHostIo.HostCapability.HostVersion < SDHCI_SPEC_300) {
+    SdHostData->BaseClockInMHz = (Data >> 8) & 0x3F;
+   } else {
+     SdHostData->BaseClockInMHz = (Data >> 8) & 0xFF;
+
+   }
+
+  SdHostData->BlockLength = 512 << ((Data >> 16) & 0x03);
+  DEBUG ((EFI_D_INFO, "SdHostDriverBindingStart: BlockLength 0x%x \r\n", SdHostData->BlockLength));
+  SdHostData->IsAutoStopCmd  = TRUE;
+
+  Status = gBS->InstallProtocolInterface (
+                  &Controller,
+                  &gEfiSdHostIoProtocolGuid,
+                  EFI_NATIVE_INTERFACE,
+                  &SdHostData->SdHostIo
+                  );
+
+  if (EFI_ERROR (Status)) {
+    goto Exit;
+  }
+
+  //
+  // Install the component name protocol
+  //
+  SdHostData->ControllerNameTable = NULL;
+
+  AddUnicodeString2 (
+    "eng",
+    gSdControllerName.SupportedLanguages,
+    &SdHostData->ControllerNameTable,
+    L"SD Host Controller",
+    TRUE
+    );
+
+  AddUnicodeString2 (
+    "en",
+    gSdControllerName2.SupportedLanguages,
+    &SdHostData->ControllerNameTable,
+    L"SD Host Controller",
+    FALSE
+    );
+
+Exit:
+  if (EFI_ERROR (Status)) {
+    if (SdHostData != NULL) {
+      FreePool (SdHostData);
+    }
+  }
+
+  return Status;
+}
+
+
+/**
+  Stop this driver on ControllerHandle. Support stoping any child handles
+  created by this driver.
+
+  @param[in]   This                 Protocol instance pointer.
+  @param[in]   Controller           Handle of device to stop driver on.
+  @param[in]   NumberOfChildren     Number of Children in the ChildHandleBuffer.
+  @param[in]   ChildHandleBuffer    List of handles for the children we need to stop.
+
+  @retval      EFI_SUCCESS
+  @retval      others
+
+**/
+EFI_STATUS
+EFIAPI
+SdControllerStop (
+  IN EFI_DRIVER_BINDING_PROTOCOL     *This,
+  IN EFI_HANDLE                      Controller,
+  IN UINTN                           NumberOfChildren,
+  IN EFI_HANDLE                      *ChildHandleBuffer
+  )
+{
+  EFI_STATUS               Status;
+  EFI_SD_HOST_IO_PROTOCOL  *SdHostIo;
+  SDHOST_DATA              *SdHostData;
+
+  Status = gBS->OpenProtocol (
+                  Controller,
+                  &gEfiSdHostIoProtocolGuid,
+                  (VOID **) &SdHostIo,
+                  This->DriverBindingHandle,
+                  Controller,
+                  EFI_OPEN_PROTOCOL_GET_PROTOCOL
+                  );
+
+  //
+  // Test whether the Controller handler passed in is a valid
+  // Usb controller handle that should be supported, if not,
+  // return the error status directly
+  //
+  if (EFI_ERROR (Status)) {
+    return Status;
+  }
+
+  SetHostVoltage (SdHostIo, 0);
+
+  SdHostData = SDHOST_DATA_FROM_THIS(SdHostIo);
+
+  //
+  // Uninstall Block I/O protocol from the device handle
+  //
+  Status = gBS->UninstallProtocolInterface (
+                  Controller,
+                  &gEfiSdHostIoProtocolGuid,
+                  SdHostIo
+                  );
+
+  if (EFI_ERROR (Status)) {
+    return Status;
+  }
+
+  FreeUnicodeStringTable (SdHostData->ControllerNameTable);
+
+  FreePool (SdHostData);
+
+  gBS->CloseProtocol (
+         Controller,
+         &gEfiPciIoProtocolGuid,
+         This->DriverBindingHandle,
+         Controller
+         );
+
+  return EFI_SUCCESS;
+}
+
diff --git a/Silicon/BroxtonSoC/BroxtonSiPkg/SouthCluster/Sdio/Dxe/SD/SdControllerDxe/SdController.h b/Silicon/BroxtonSoC/BroxtonSiPkg/SouthCluster/Sdio/Dxe/SD/SdControllerDxe/SdController.h
new file mode 100644
index 0000000..a702565
--- /dev/null
+++ b/Silicon/BroxtonSoC/BroxtonSiPkg/SouthCluster/Sdio/Dxe/SD/SdControllerDxe/SdController.h
@@ -0,0 +1,314 @@
+/** @file
+  The definition for SD host controller driver model and HC protocol routines.
+
+  Copyright (c) 2013 - 2016, Intel Corporation. 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 _SD_CONTROLLER_H_
+#define _SD_CONTROLLER_H_
+
+#include <Uefi.h>
+#include <Protocol/PciIo.h>
+#include <Library/DebugLib.h>
+#include <Library/BaseMemoryLib.h>
+#include <Library/UefiDriverEntryPoint.h>
+#include <Library/UefiBootServicesTableLib.h>
+#include <Library/UefiLib.h>
+#include <Library/BaseLib.h>
+#include <Library/MemoryAllocationLib.h>
+#include <Library/PcdLib.h>
+#include <IndustryStandard/Pci22.h>
+#include <Library/GpioLib.h>
+#include "ComponentName.h"
+#include "SdHostIo.h"
+
+extern EFI_DRIVER_BINDING_PROTOCOL   gSdControllerDriverBinding;
+extern EFI_COMPONENT_NAME_PROTOCOL   gSdControllerName;
+extern EFI_COMPONENT_NAME2_PROTOCOL  gSdControllerName2;
+
+#define SDHOST_DATA_SIGNATURE  SIGNATURE_32 ('s', 'd', 'h', 's')
+
+#define BLOCK_SIZE   0x200
+#define TIME_OUT_1S  1000
+
+#pragma pack(1)
+
+//
+// PCI Class Code structure
+//
+typedef struct {
+  UINT8 PI;
+  UINT8 SubClassCode;
+  UINT8 BaseCode;
+} PCI_CLASSC;
+
+#pragma pack()
+
+typedef struct {
+  UINTN                      Signature;
+  EFI_SD_HOST_IO_PROTOCOL    SdHostIo;
+  EFI_PCI_IO_PROTOCOL        *PciIo;
+  BOOLEAN                    IsAutoStopCmd;
+  UINT32                     BaseClockInMHz;
+  UINT32                     CurrentClockInKHz;
+  UINT32                     BlockLength;
+  EFI_UNICODE_STRING_TABLE   *ControllerNameTable;
+} SDHOST_DATA;
+
+#define SDHOST_DATA_FROM_THIS(a) \
+    CR(a, SDHOST_DATA, SdHostIo, SDHOST_DATA_SIGNATURE)
+
+/**
+  Test to see if this driver supports ControllerHandle. Any
+  ControllerHandle that has SdHostIoProtocol installed will be supported.
+
+  @param[in]  This                 Protocol instance pointer.
+  @param[in]  Controller           Handle of device to test.
+  @param[in]  RemainingDevicePath  Not used.
+
+  @retval     EFI_SUCCESS          This driver supports this device.
+  @retval     EFI_UNSUPPORTED      This driver does not support this device.
+
+**/
+EFI_STATUS
+EFIAPI
+SdControllerSupported (
+  IN EFI_DRIVER_BINDING_PROTOCOL     *This,
+  IN EFI_HANDLE                      Controller,
+  IN EFI_DEVICE_PATH_PROTOCOL        *RemainingDevicePath
+  );
+
+/**
+  Starting the SD Host Controller Driver.
+
+  @param[in]  This                 Protocol instance pointer.
+  @param[in]  Controller           Handle of device to test.
+  @param[in]  RemainingDevicePath  Not used.
+
+  @retval     EFI_SUCCESS          This driver supports this device.
+  @retval     EFI_UNSUPPORTED      This driver does not support this device.
+  @retval     EFI_DEVICE_ERROR     This driver cannot be started due to device Error.
+                                   EFI_OUT_OF_RESOURCES- Failed due to resource shortage.
+
+**/
+EFI_STATUS
+EFIAPI
+SdControllerStart (
+  IN EFI_DRIVER_BINDING_PROTOCOL     *This,
+  IN EFI_HANDLE                      Controller,
+  IN EFI_DEVICE_PATH_PROTOCOL        *RemainingDevicePath
+  );
+
+/**
+  Stop this driver on ControllerHandle. Support stoping any child handles
+  created by this driver.
+
+  @param[in]  This                 Protocol instance pointer.
+  @param[in]  Controller           Handle of device to stop driver on.
+  @param[in]  NumberOfChildren     Number of Children in the ChildHandleBuffer.
+  @param[in]  ChildHandleBuffer    List of handles for the children we need to stop.
+
+  @retval     EFI_SUCCESS
+  @retval     others
+
+**/
+EFI_STATUS
+EFIAPI
+SdControllerStop (
+  IN EFI_DRIVER_BINDING_PROTOCOL     *This,
+  IN EFI_HANDLE                      Controller,
+  IN UINTN                           NumberOfChildren,
+  IN EFI_HANDLE                      *ChildHandleBuffer
+  );
+
+/**
+  The main function used to send the command to the card inserted into the SD host slot.
+  It will assemble the arguments to set the command register and wait for the command
+  and transfer completed until timeout. Then it will read the response register to fill
+  the ResponseData.
+
+  @param[in]  This                  A pointer to the EFI_SD_HOST_IO_PROTOCOL instance.
+  @param[in]  CommandIndex          The command index to set the command index field of command register.
+  @param[in]  Argument              Command argument to set the argument field of command register.
+  @param[in]  DataType              TRANSFER_TYPE, indicates no data, data in or data out.
+  @param[in]  Buffer                Contains the data read from / write to the device.
+  @param[in]  BufferSize            The size of the buffer.
+  @param[in]  ResponseType          RESPONSE_TYPE.
+  @param[in]  TimeOut               Time out value in 1 ms unit.
+  @param[out] ResponseData          Depending on the ResponseType, such as CSD or card status.
+
+  @retval     EFI_SUCCESS
+  @retval     EFI_INVALID_PARAMETER
+  @retval     EFI_OUT_OF_RESOURCES
+  @retval     EFI_TIMEOUT
+  @retval     EFI_DEVICE_ERROR
+
+**/
+EFI_STATUS
+EFIAPI
+SendCommand (
+  IN   EFI_SD_HOST_IO_PROTOCOL    *This,
+  IN   UINT16                     CommandIndex,
+  IN   UINT32                     Argument,
+  IN   TRANSFER_TYPE              DataType,
+  IN   UINT8                      *Buffer, OPTIONAL
+  IN   UINT32                     BufferSize,
+  IN   RESPONSE_TYPE              ResponseType,
+  IN   UINT32                     TimeOut,
+  OUT  UINT32                     *ResponseData OPTIONAL
+  );
+
+/**
+  Set max clock frequency of the host, the actual frequency may not be the same as MaxFrequency.
+  It depends on the max frequency the host can support, divider, and host speed mode.
+
+  @param[in]  This                  A pointer to the EFI_SD_HOST_IO_PROTOCOL instance.
+  @param[in]  MaxFrequency          Max frequency in HZ.
+
+  @retval     EFI_SUCCESS
+  @retval     EFI_TIMEOUT
+
+**/
+EFI_STATUS
+EFIAPI
+SetClockFrequency (
+  IN  EFI_SD_HOST_IO_PROTOCOL    *This,
+  IN  UINT32                     MaxFrequencyInKHz
+  );
+
+/**
+  Set bus width of the host controller
+
+  @param[in]  This                  A pointer to the EFI_SD_HOST_IO_PROTOCOL instance.
+  @param[in]  BusWidth              Bus width in 1, 4, 8 bits.
+
+  @retval     EFI_SUCCESS
+  @retval     EFI_INVALID_PARAMETER
+
+**/
+EFI_STATUS
+EFIAPI
+SetBusWidth (
+  IN  EFI_SD_HOST_IO_PROTOCOL    *This,
+  IN  UINT32                     BusWidth
+  );
+
+/**
+  Set voltage which could supported by the host controller.
+  Support 0(Power off the host), 1.8V, 3.0V, 3.3V
+
+  @param[in]  This                  A pointer to the EFI_SD_HOST_IO_PROTOCOL instance.
+  @param[in]  Voltage               Units in 0.1 V.
+
+  @retval     EFI_SUCCESS
+  @retval     EFI_INVALID_PARAMETER
+
+**/
+EFI_STATUS
+EFIAPI
+SetHostVoltage (
+  IN  EFI_SD_HOST_IO_PROTOCOL    *This,
+  IN  UINT32                     Voltage
+  );
+
+/**
+  Reset the host controller.
+
+  @param[in]  This                  A pointer to the EFI_SD_HOST_IO_PROTOCOL instance.
+  @param[in]  ResetAll              TRUE to reset all.
+
+  @retval     EFI_SUCCESS
+  @retval     EFI_TIMEOUT
+
+**/
+EFI_STATUS
+EFIAPI
+ResetSdHost (
+  IN  EFI_SD_HOST_IO_PROTOCOL      *This,
+  IN  RESET_TYPE                   ResetType
+  );
+
+/**
+  Enable auto stop on the host controller.
+
+  @param[in]  This                  A pointer to the EFI_SD_HOST_IO_PROTOCOL instance.
+  @param[in]  Enable                TRUE to enable, FALSE to disable.
+
+  @retval     EFI_SUCCESS
+  @retval     EFI_TIMEOUT
+
+**/
+EFI_STATUS
+EFIAPI
+EnableAutoStopCmd (
+  IN  EFI_SD_HOST_IO_PROTOCOL    *This,
+  IN  BOOLEAN                    Enable
+  );
+
+/**
+  Find whether these is a card inserted into the slot. If so init the host.
+  If not, return EFI_NOT_FOUND.
+
+  @param[in]  This                  A pointer to the EFI_SD_HOST_IO_PROTOCOL instance.
+
+  @retval     EFI_SUCCESS
+  @retval     EFI_NOT_FOUND
+
+**/
+EFI_STATUS
+EFIAPI
+DetectCardAndInitHost (
+  IN  EFI_SD_HOST_IO_PROTOCOL    *This
+  );
+
+/**
+  Set the Block length on the host controller.
+
+  @param[in]  This                  A pointer to the EFI_SD_HOST_IO_PROTOCOL instance.
+  @param[in]  BlockLength           card supportes block length.
+
+  @retval     EFI_SUCCESS
+  @retval     EFI_TIMEOUT
+
+**/
+EFI_STATUS
+EFIAPI
+SetBlockLength (
+  IN  EFI_SD_HOST_IO_PROTOCOL    *This,
+  IN  UINT32                     BlockLength
+  );
+
+/**
+  Enable/Disable High Speed transfer mode
+
+  @param[in]  This                A pointer to the EFI_SD_HOST_IO_PROTOCOL instance.
+  @param[in]  Enable              TRUE to Enable, FALSE to Disable
+
+  @retval     EFI_SUCCESS
+
+**/
+EFI_STATUS
+EFIAPI
+SetHighSpeedMode (
+  IN  EFI_SD_HOST_IO_PROTOCOL    *This,
+  IN  BOOLEAN                    Enable
+  );
+
+EFI_STATUS
+EFIAPI
+SetDDRMode (
+  IN  EFI_SD_HOST_IO_PROTOCOL    *This,
+  IN  BOOLEAN                    Enable
+  );
+
+#endif
+
diff --git a/Silicon/BroxtonSoC/BroxtonSiPkg/SouthCluster/Sdio/Dxe/SD/SdControllerDxe/SdControllerDxe.inf b/Silicon/BroxtonSoC/BroxtonSiPkg/SouthCluster/Sdio/Dxe/SD/SdControllerDxe/SdControllerDxe.inf
new file mode 100644
index 0000000..499c9b7
--- /dev/null
+++ b/Silicon/BroxtonSoC/BroxtonSiPkg/SouthCluster/Sdio/Dxe/SD/SdControllerDxe/SdControllerDxe.inf
@@ -0,0 +1,59 @@
+## @file
+#  Component Description File For SdControllerDxe Module.
+#
+#  Copyright (c) 2013 - 2016, Intel Corporation. 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                    = 0x00010005
+  BASE_NAME                      = SdController
+  FILE_GUID                      = 90A330BD-6F89-4900-933A-C25EB4356348
+  MODULE_TYPE                    = UEFI_DRIVER
+  VERSION_STRING                 = 1.0
+  ENTRY_POINT                    = InitializeSdController
+
+#
+# The following information is for reference only and not required by the build tools.
+#
+#  VALID_ARCHITECTURES           = IA32 X64 IPF EBC
+#
+#  DRIVER_BINDING                = gSdControllerDriverBinding
+#  COMPONENT_NAME                = gSdControllerName
+#  COMPONENT_NAME2               = gSdControllerName2
+#
+
+[Sources]
+  SdController.c
+  SdController.h
+  ComponentName.c
+  ComponentName.h
+
+[Packages]
+  MdePkg/MdePkg.dec
+  MdeModulePkg/MdeModulePkg.dec
+  BroxtonSiPkg/BroxtonSiPkg.dec
+
+[LibraryClasses]
+  MemoryAllocationLib
+  BaseLib
+  UefiLib
+  UefiBootServicesTableLib
+  UefiDriverEntryPoint
+  BaseMemoryLib
+  DebugLib
+  PcdLib
+
+[Protocols]
+  gEfiPciIoProtocolGuid                         ## TO_START
+  gEfiSdHostIoProtocolGuid                      ## BY_START
+
+[FeaturePcd]
diff --git a/Silicon/BroxtonSoC/BroxtonSiPkg/SouthCluster/Sdio/Dxe/SD/SdMediaDeviceDxe/CEATA.c b/Silicon/BroxtonSoC/BroxtonSiPkg/SouthCluster/Sdio/Dxe/SD/SdMediaDeviceDxe/CEATA.c
new file mode 100644
index 0000000..cb7a1bb
--- /dev/null
+++ b/Silicon/BroxtonSoC/BroxtonSiPkg/SouthCluster/Sdio/Dxe/SD/SdMediaDeviceDxe/CEATA.c
@@ -0,0 +1,638 @@
+/** @file
+  CEATA specific functions implementation
+
+  Copyright (c) 2013 - 2016, Intel Corporation. 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 "SdMediaDevice.h"
+
+/**
+  Send RW_MULTIPLE_REGISTER command
+
+  @param[in]  CardData                   Pointer to CARD_DATA.
+  @param[in]  Address                    Register address.
+  @param[in]  ByteCount                  Buffer size.
+  @param[in]  Write                      TRUE means write, FALSE means read.
+  @param[in]  Buffer                     Buffer pointer.
+
+  @retval     EFI_SUCCESS                Success
+  @retval     EFI_DEVICE_ERROR           Hardware Error
+  @retval     EFI_INVALID_PARAMETER      Parameter is error
+  @retval     EFI_NO_MEDIA               No media
+  @retval     EFI_MEDIA_CHANGED          Media Change
+  @retval     EFI_BAD_BUFFER_SIZE        Buffer size is bad
+
+**/
+EFI_STATUS
+ReadWriteMultipleRegister (
+  IN  CARD_DATA   *CardData,
+  IN  UINT16      Address,
+  IN  UINT8       ByteCount,
+  IN  BOOLEAN     Write,
+  IN  UINT8       *Buffer
+  )
+{
+  EFI_STATUS                 Status;
+  UINT32                     Argument;
+
+  Status = EFI_SUCCESS;
+
+  if ((Address % 4 != 0) || (ByteCount % 4 != 0)) {
+    Status = EFI_INVALID_PARAMETER;
+    goto Exit;
+  }
+
+  Argument = (Address << 16) | ByteCount;
+  if (Write) {
+    Argument |= BIT31;
+  }
+
+  if (Write) {
+    CopyMem (CardData->AlignedBuffer, Buffer, ByteCount);
+
+    Status = SendCommand (
+               CardData,
+               RW_MULTIPLE_REGISTER,
+               Argument,
+               OutData,
+               CardData->AlignedBuffer,
+               ByteCount,
+               ResponseR1b,
+               TIMEOUT_DATA,
+               (UINT32 *) &(CardData->CardStatus)
+               );
+
+  } else {
+    Status = SendCommand (
+               CardData,
+               RW_MULTIPLE_REGISTER,
+               Argument,
+               InData,
+               CardData->AlignedBuffer,
+               ByteCount,
+               ResponseR1,
+               TIMEOUT_DATA,
+               (UINT32 *) &(CardData->CardStatus)
+               );
+
+    if (!EFI_ERROR (Status)) {
+      CopyMem (Buffer, CardData->AlignedBuffer, ByteCount);
+    }
+  }
+Exit:
+  return Status;
+}
+
+
+/**
+  Send ReadWriteMultipleBlock command with RW_MULTIPLE_REGISTER command
+
+  @param[in]  CardData                   Pointer to CARD_DATA.
+  @param[in]  DataUnitCount              Buffer size in 512 bytes unit.
+  @param[in]  Write                      TRUE means write, FALSE means read.
+  @param[in]  Buffer                     Buffer pointer.
+
+  @retval     EFI_SUCCESS                Success
+  @retval     EFI_DEVICE_ERROR           Hardware Error
+  @retval     EFI_INVALID_PARAMETER      Parameter is error
+  @retval     EFI_NO_MEDIA               No media
+  @retval     EFI_MEDIA_CHANGED          Media Change
+  @retval     EFI_BAD_BUFFER_SIZE        Buffer size is bad
+
+**/
+EFI_STATUS
+ReadWriteMultipleBlock (
+  IN  CARD_DATA   *CardData,
+  IN  UINT16      DataUnitCount,
+  IN  BOOLEAN     Write,
+  IN  UINT8       *Buffer
+  )
+{
+  EFI_STATUS                 Status;
+  EFI_SD_HOST_IO_PROTOCOL    *SdHostIo;
+  UINT32                     TransferLength;
+
+  Status = EFI_SUCCESS;
+  SdHostIo = CardData->SdHostIo;
+
+  TransferLength = DataUnitCount * DATA_UNIT_SIZE;
+  if (TransferLength > SdHostIo->HostCapability.BoundarySize) {
+    return EFI_INVALID_PARAMETER;
+  }
+
+  if (Write) {
+    CopyMem (CardData->AlignedBuffer, Buffer, TransferLength);
+
+    Status = SendCommand (
+               CardData,
+               RW_MULTIPLE_BLOCK,
+               (DataUnitCount | BIT31),
+               OutData,
+               CardData->AlignedBuffer,
+               TransferLength,
+               ResponseR1b,
+               TIMEOUT_DATA,
+               (UINT32 *) &(CardData->CardStatus)
+               );
+
+   } else {
+      Status = SendCommand (
+                 CardData,
+                 RW_MULTIPLE_BLOCK,
+                 DataUnitCount,
+                 InData,
+                 CardData->AlignedBuffer,
+                 TransferLength,
+                 ResponseR1,
+                 TIMEOUT_DATA,
+                 (UINT32 *) &(CardData->CardStatus)
+                 );
+
+      if (!EFI_ERROR (Status)) {
+        CopyMem (Buffer, CardData->AlignedBuffer, TransferLength);
+      }
+  }
+
+  return Status;
+}
+
+
+/**
+  Send software reset
+
+  @param[in]  CardData                   Pointer to CARD_DATA.
+
+  @retval     EFI_SUCCESS                Success
+  @retval     EFI_DEVICE_ERROR           Hardware Error
+  @retval     EFI_INVALID_PARAMETER      Parameter is error
+  @retval     EFI_NO_MEDIA               No media
+  @retval     EFI_MEDIA_CHANGED          Media Change
+  @retval     EFI_BAD_BUFFER_SIZE        Buffer size is bad
+
+**/
+EFI_STATUS
+SoftwareReset (
+  IN  CARD_DATA    *CardData
+  )
+{
+  EFI_STATUS    Status;
+  UINT8         Data;
+  UINT32        TimeOut;
+
+  Data = BIT2;
+
+  Status = FastIO (CardData, Reg_Control, &Data, TRUE);
+  if (EFI_ERROR (Status)) {
+    goto Exit;
+  }
+
+  TimeOut = 5 * 1000;
+
+  do {
+    gBS->Stall (1 * 1000);
+    Status = FastIO (CardData, Reg_Control, &Data, FALSE);
+    if (EFI_ERROR (Status)) {
+      goto Exit;
+    }
+
+    if ((Data & BIT2) == BIT2) {
+      break;
+    }
+
+    TimeOut--;
+  } while (TimeOut > 0);
+
+  if (TimeOut == 0) {
+   Status = EFI_TIMEOUT;
+   goto Exit;
+  }
+
+  Data &= ~BIT2;
+  Status = FastIO (CardData, Reg_Control, &Data, TRUE);
+
+  TimeOut = 5 * 1000;
+
+  do {
+    gBS->Stall (1 * 1000);
+    Status = FastIO (CardData, Reg_Control, &Data, FALSE);
+    if (EFI_ERROR (Status)) {
+      goto Exit;
+    }
+
+    if ((Data & BIT2) != BIT2) {
+      break;
+    }
+
+    TimeOut--;
+  } while (TimeOut > 0);
+
+  if (TimeOut == 0) {
+   Status = EFI_TIMEOUT;
+   goto Exit;
+  }
+
+Exit:
+  return Status;
+}
+
+
+/**
+  SendATACommand specificed in Taskfile
+
+  @param[in]  CardData                   Pointer to CARD_DATA.
+  @param[in]  TaskFile                   Pointer to TASK_FILE.
+  @param[in]  Write                      TRUE means write, FALSE means read.
+  @param[in]  Buffer                     If NULL, means no data transfer, neither read nor write.
+  @param[in]  SectorCount                Buffer size in 512 bytes unit.
+
+  @retval     EFI_SUCCESS                Success
+  @retval     EFI_DEVICE_ERROR           Hardware Error
+  @retval     EFI_INVALID_PARAMETER      Parameter is error
+  @retval     EFI_NO_MEDIA               No media
+  @retval     EFI_MEDIA_CHANGED          Media Change
+  @retval     EFI_BAD_BUFFER_SIZE        Buffer size is bad
+
+**/
+EFI_STATUS
+SendATACommand (
+  IN  CARD_DATA   *CardData,
+  IN  TASK_FILE   *TaskFile,
+  IN  BOOLEAN     Write,
+  IN  UINT8       *Buffer,
+  IN  UINT16      SectorCount
+  )
+{
+  EFI_STATUS                 Status;
+  UINT8                      Data;
+  UINT32                     TimeOut;
+
+  //
+  // Write register
+  //
+  Status = ReadWriteMultipleRegister (
+             CardData,
+             0,
+             sizeof (TASK_FILE),
+             TRUE,
+             (UINT8 *) TaskFile
+             );
+
+  if (EFI_ERROR (Status)) {
+    DEBUG ((EFI_D_ERROR, "ReadWriteMultipleRegister 0x%x\n", Status));
+    goto Exit;
+  }
+
+  TimeOut = 5000;
+  do {
+    gBS->Stall (1 * 1000);
+    Data = 0;
+    Status = FastIO (
+               CardData,
+               Reg_Command_Status,
+               &Data,
+               FALSE
+               );
+
+    if (EFI_ERROR (Status)) {
+      return Status;
+    }
+
+    if (((Data & BIT7) == 0) && ((Data & BIT6) == BIT6)) {
+      break;
+    }
+
+    TimeOut --;
+  } while (TimeOut > 0);
+
+  if (TimeOut == 0) {
+    DEBUG ((EFI_D_ERROR, "ReadWriteMultipleRegister FastIO EFI_TIMEOUT 0x%x\n", Data));
+    Status = EFI_TIMEOUT;
+    goto Exit;
+  }
+
+  if (Buffer != NULL) {
+    Status = ReadWriteMultipleBlock (
+               CardData,
+               SectorCount,
+               Write,
+               (UINT8 *) Buffer
+               );
+
+    if (EFI_ERROR (Status)) {
+      DEBUG ((EFI_D_ERROR, "ReadWriteMultipleBlock EFI_TIMEOUT 0x%x\n", Status));
+      goto Exit;
+    }
+
+    TimeOut = 5 * 1000;
+    do {
+      gBS->Stall (1 * 1000);
+      Data = 0;
+      Status = FastIO (
+                 CardData,
+                 Reg_Command_Status,
+                 &Data,
+                 FALSE
+                 );
+
+      if (EFI_ERROR (Status)) {
+        return Status;
+      }
+
+      if (((Data & BIT7) == 0) && ((Data & BIT3) == 0)) {
+        break;
+      }
+
+      TimeOut --;
+    } while (TimeOut > 0);
+    if (TimeOut == 0) {
+      DEBUG ((EFI_D_ERROR, "ReadWriteMultipleBlock FastIO EFI_TIMEOUT 0x%x\n", Data));
+      Status = EFI_TIMEOUT;
+      goto Exit;
+    }
+
+    if (((Data & BIT6) == BIT6) && (Data & BIT0) == 0) {
+      Status = EFI_SUCCESS;
+    } else {
+      Status = EFI_DEVICE_ERROR;
+    }
+  }
+
+Exit:
+  if (EFI_ERROR (Status)) {
+    SoftwareReset (CardData);
+  }
+
+  return Status;
+}
+
+
+/**
+  IDENTIFY_DEVICE command
+
+  @param[in]  CardData                   Pointer to CARD_DATA.
+
+  @retval     EFI_SUCCESS                Success
+  @retval     EFI_DEVICE_ERROR           Hardware Error
+  @retval     EFI_INVALID_PARAMETER      Parameter is error
+  @retval     EFI_NO_MEDIA               No media
+  @retval     EFI_MEDIA_CHANGED          Media Change
+  @retval     EFI_BAD_BUFFER_SIZE        Buffer size is bad
+
+**/
+EFI_STATUS
+IndentifyDevice (
+  IN  CARD_DATA    *CardData
+  )
+{
+  EFI_STATUS                 Status;
+
+  ZeroMem (&CardData->TaskFile, sizeof (TASK_FILE));
+
+  //
+  // The host only supports nIEN = 0
+  //
+  CardData->TaskFile.Command_Status = IDENTIFY_DEVICE;
+  Status = SendATACommand (
+             CardData,
+             &CardData->TaskFile,
+             FALSE,
+             (UINT8 *) &(CardData->IndentifyDeviceData),
+             1
+             );
+
+  return Status;
+}
+
+
+/**
+  FLUSH_CACHE_EXT command
+
+  @param[in]  CardData                   Pointer to CARD_DATA.
+
+  @retval     EFI_SUCCESS                Success
+  @retval     EFI_DEVICE_ERROR           Hardware Error
+  @retval     EFI_INVALID_PARAMETER      Parameter is error
+  @retval     EFI_NO_MEDIA               No media
+  @retval     EFI_MEDIA_CHANGED          Media Change
+  @retval     EFI_BAD_BUFFER_SIZE        Buffer size is bad
+
+**/
+EFI_STATUS
+FlushCache (
+  IN  CARD_DATA    *CardData
+  )
+{
+
+  return EFI_SUCCESS;
+}
+
+
+/**
+  STANDBY_IMMEDIATE command
+
+  @param[in]  CardData                   Pointer to CARD_DATA.
+
+  @retval     EFI_SUCCESS                Success
+  @retval     EFI_DEVICE_ERROR           Hardware Error
+  @retval     EFI_INVALID_PARAMETER      Parameter is error
+  @retval     EFI_NO_MEDIA               No media
+  @retval     EFI_MEDIA_CHANGED          Media Change
+  @retval     EFI_BAD_BUFFER_SIZE        Buffer size is bad
+
+**/
+EFI_STATUS
+StandByImmediate (
+  IN  CARD_DATA    *CardData
+  )
+{
+  EFI_STATUS  Status;
+
+  ZeroMem (&CardData->TaskFile, sizeof (TASK_FILE));
+
+  //
+  // The host only supports nIEN = 0
+  //
+  CardData->TaskFile.Command_Status = STANDBY_IMMEDIATE;
+  Status = SendATACommand (
+             CardData,
+             &CardData->TaskFile,
+             FALSE,
+             NULL,
+             0
+             );
+
+  return Status;
+}
+
+
+/**
+  READ_DMA_EXT command
+
+  @param[in]  CardData                   Pointer to CARD_DATA.
+  @param[in]  LBA                        The starting logical block address to read from on the device.
+  @param[in]  Buffer                     A pointer to the destination buffer for the data. The caller
+                                         is responsible for either having implicit or explicit ownership
+                                         of the buffer.
+  @param[in]  SectorCount                Size in 512 bytes unit.
+
+  @retval     EFI_SUCCESS                Success
+  @retval     EFI_DEVICE_ERROR           Hardware Error
+  @retval     EFI_INVALID_PARAMETER      Parameter is error
+  @retval     EFI_NO_MEDIA               No media
+  @retval     EFI_MEDIA_CHANGED          Media Change
+  @retval     EFI_BAD_BUFFER_SIZE        Buffer size is bad
+
+**/
+EFI_STATUS
+ReadDMAExt (
+  IN  CARD_DATA   *CardData,
+  IN  EFI_LBA     LBA,
+  IN  UINT8       *Buffer,
+  IN  UINT16      SectorCount
+  )
+{
+  EFI_STATUS  Status;
+
+  ZeroMem (&CardData->TaskFile, sizeof (TASK_FILE));
+
+  //
+  // The host only supports nIEN = 0
+  //
+  CardData->TaskFile.Command_Status = READ_DMA_EXT;
+
+  CardData->TaskFile.SectorCount     = (UINT8) SectorCount;
+  CardData->TaskFile.SectorCount_Exp = (UINT8) (SectorCount >> 8);
+
+  CardData->TaskFile.LBALow          = (UINT8) LBA;
+  CardData->TaskFile.LBAMid          = (UINT8) RShiftU64 (LBA, 8);
+  CardData->TaskFile.LBAHigh         = (UINT8) RShiftU64 (LBA, 16);
+
+  CardData->TaskFile.LBALow_Exp      = (UINT8) RShiftU64 (LBA, 24);
+  CardData->TaskFile.LBAMid_Exp      = (UINT8) RShiftU64 (LBA, 32);
+  CardData->TaskFile.LBAHigh_Exp     = (UINT8) RShiftU64 (LBA, 40);
+
+  Status = SendATACommand (
+             CardData,
+             &CardData->TaskFile,
+             FALSE,
+             Buffer,
+             SectorCount
+             );
+
+  return Status;
+}
+
+
+/**
+  WRITE_DMA_EXT command
+
+  @param[in]  CardData                   Pointer to CARD_DATA.
+  @param[in]  LBA                        The starting logical block address to read from on the device.
+  @param[in]  Buffer                     A pointer to the destination buffer for the data. The caller
+                                         is responsible for either having implicit or explicit ownership
+                                         of the buffer.
+  @param[in]  SectorCount                Size in 512 bytes unit.
+
+  @retval     EFI_SUCCESS                Success
+  @retval     EFI_DEVICE_ERROR           Hardware Error
+  @retval     EFI_INVALID_PARAMETER      Parameter is error
+  @retval     EFI_NO_MEDIA               No media
+  @retval     EFI_MEDIA_CHANGED          Media Change
+  @retval     EFI_BAD_BUFFER_SIZE        Buffer size is bad
+
+**/
+EFI_STATUS
+WriteDMAExt (
+  IN  CARD_DATA   *CardData,
+  IN  EFI_LBA     LBA,
+  IN  UINT8       *Buffer,
+  IN  UINT16      SectorCount
+  )
+{
+  EFI_STATUS  Status;
+
+  ZeroMem (&CardData->TaskFile, sizeof (TASK_FILE));
+
+  //
+  // The host only supports nIEN = 0
+  //
+  CardData->TaskFile.Command_Status = WRITE_DMA_EXT;
+
+  CardData->TaskFile.SectorCount     = (UINT8) SectorCount;
+  CardData->TaskFile.SectorCount_Exp = (UINT8) (SectorCount >> 8);
+
+  CardData->TaskFile.LBALow          = (UINT8) LBA;
+  CardData->TaskFile.LBAMid          = (UINT8) RShiftU64 (LBA, 8);
+  CardData->TaskFile.LBAHigh         = (UINT8) RShiftU64 (LBA, 16);
+
+  CardData->TaskFile.LBALow_Exp      = (UINT8) RShiftU64 (LBA, 24);
+  CardData->TaskFile.LBAMid_Exp      = (UINT8) RShiftU64 (LBA, 32);
+  CardData->TaskFile.LBAHigh_Exp     = (UINT8) RShiftU64 (LBA, 40);
+
+  Status = SendATACommand (
+             CardData,
+             &CardData->TaskFile,
+             TRUE,
+             Buffer,
+             SectorCount
+             );
+
+  return Status;
+
+}
+
+
+/**
+  Judge whether it is CE-ATA device or not.
+
+  @param[in]  CardData             Pointer to CARD_DATA.
+
+  @retval     TRUE
+  @retval     FALSE
+
+**/
+BOOLEAN
+IsCEATADevice (
+  IN  CARD_DATA    *CardData
+  )
+{
+  EFI_STATUS                 Status;
+
+  Status = ReadWriteMultipleRegister (
+             CardData,
+             0,
+             sizeof (TASK_FILE),
+             FALSE,
+             (UINT8 *) &CardData->TaskFile
+             );
+
+  if (EFI_ERROR (Status)) {
+    //
+    // To bring back the normal MMC card to work
+    //
+    CardData->SdHostIo->ResetSdHost (CardData->SdHostIo, Reset_DAT_CMD);
+    return FALSE;
+  }
+
+  if (CardData->TaskFile.LBAMid == CE_ATA_SIG_CE &&
+      CardData->TaskFile.LBAHigh == CE_ATA_SIG_AA
+    ) {
+    //
+    // Disable Auto CMD for CE-ATA
+    //
+    CardData->SdHostIo->EnableAutoStopCmd (CardData->SdHostIo, FALSE);
+    return TRUE;
+  }
+
+  return FALSE;
+}
+
diff --git a/Silicon/BroxtonSoC/BroxtonSiPkg/SouthCluster/Sdio/Dxe/SD/SdMediaDeviceDxe/CEATABlockIo.c b/Silicon/BroxtonSoC/BroxtonSiPkg/SouthCluster/Sdio/Dxe/SD/SdMediaDeviceDxe/CEATABlockIo.c
new file mode 100644
index 0000000..55fd085
--- /dev/null
+++ b/Silicon/BroxtonSoC/BroxtonSiPkg/SouthCluster/Sdio/Dxe/SD/SdMediaDeviceDxe/CEATABlockIo.c
@@ -0,0 +1,384 @@
+/** @file
+  Block I/O protocol for CE-ATA device
+
+  Copyright (c) 2013 - 2016, Intel Corporation. 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 "SdMediaDevice.h"
+
+
+/**
+  Implements EFI_BLOCK_IO_PROTOCOL.Reset() function.
+
+  @param[in]  This                   The EFI_BLOCK_IO_PROTOCOL instance.
+  @param[in]  ExtendedVerification   Indicates that the driver may perform a more exhaustive.
+                                     verification operation of the device during reset.
+                                     (This parameter is ingored in this driver.)
+
+  @retval     EFI_SUCCESS            Success
+
+**/
+EFI_STATUS
+EFIAPI
+CEATABlockReset (
+  IN  EFI_BLOCK_IO_PROTOCOL   *This,
+  IN  BOOLEAN                 ExtendedVerification
+  )
+{
+  EFI_STATUS                 Status;
+  CARD_DATA                  *CardData;
+  EFI_SD_HOST_IO_PROTOCOL    *SdHostIo;
+
+  CardData = CARD_DATA_FROM_THIS (This);
+  SdHostIo = CardData->SdHostIo;
+
+  if (!ExtendedVerification) {
+    Status = SoftwareReset (CardData);
+  } else {
+    Status = SdHostIo->ResetSdHost (SdHostIo, Reset_DAT_CMD);
+    if (EFI_ERROR (Status)) {
+      DEBUG ((EFI_D_ERROR, "CEATABlockReset: Fail to ResetSDHost\n" ));
+      return Status;
+    }
+    Status = MMCSDCardInit (CardData);
+  }
+
+  return Status;
+}
+
+
+/**
+  Implements EFI_BLOCK_IO_PROTOCOL.ReadBlocks() function.
+
+  @param[in]  This                       The EFI_BLOCK_IO_PROTOCOL instance.
+  @param[in]  MediaId                    The media id that the write request is for.
+  @param[in]  LBA                        The starting logical block address to read from on the device.
+                                         The caller is responsible for writing to only legitimate locations.
+  @param[in]  BufferSize                 The size of the Buffer in bytes. This must be a multiple of the
+                                         intrinsic block size of the device.
+  @param[out] Buffer                     A pointer to the destination buffer for the data. The caller
+                                         is responsible for either having implicit or explicit ownership
+                                         of the buffer.
+
+  @retval     EFI_SUCCESS                Success
+  @retval     EFI_DEVICE_ERROR           Hardware Error
+  @retval     EFI_INVALID_PARAMETER      Parameter is error
+  @retval     EFI_NO_MEDIA               No media
+  @retval     EFI_MEDIA_CHANGED          Media Change
+  @retval     EFI_BAD_BUFFER_SIZE        Buffer size is bad
+
+**/
+EFI_STATUS
+EFIAPI
+CEATABlockReadBlocks (
+  IN  EFI_BLOCK_IO_PROTOCOL   *This,
+  IN  UINT32                  MediaId,
+  IN  EFI_LBA                 LBA,
+  IN  UINTN                   BufferSize,
+  OUT VOID                    *Buffer
+  )
+{
+  EFI_STATUS                  Status;
+  CARD_DATA                   *CardData;
+  UINT32                      TransferSize;
+  UINT8                       *pBuf;
+  UINT32                      Index;
+  UINT64                      Address;
+  UINT32                      Remainder;
+  UINT64                      CEATALBA;
+  UINT32                      BoundarySize;
+
+  Status       = EFI_SUCCESS;
+  CardData     = CARD_DATA_FROM_THIS (This);
+  pBuf         = Buffer;
+  Index        = 0;
+  Address      = MultU64x32 (LBA, CardData->BlockIoMedia.BlockSize);
+  BoundarySize = CardData->SdHostIo->HostCapability.BoundarySize;
+
+  if (!Buffer) {
+    Status = EFI_INVALID_PARAMETER;
+    DEBUG ((EFI_D_ERROR, "CEATABlockReadBlocks:Invalid parameter\n" ));
+    goto Exit;
+  }
+
+  if (MediaId != CardData->BlockIoMedia.MediaId) {
+    Status = EFI_MEDIA_CHANGED;
+    DEBUG ((EFI_D_ERROR, "CEATABlockReadBlocks:Media changed\n" ));
+    goto Exit;
+  }
+
+  if ((BufferSize % CardData->BlockIoMedia.BlockSize) != 0) {
+    Status = EFI_BAD_BUFFER_SIZE;
+    DEBUG ((EFI_D_ERROR, "CEATABlockReadBlocks:Bad buffer size\n" ));
+    goto Exit;
+  }
+
+  if (BufferSize == 0) {
+    Status = EFI_SUCCESS;
+    goto Exit;
+  }
+
+  if ((Address + BufferSize) > MultU64x32 (CardData->BlockIoMedia.LastBlock + 1, CardData->BlockIoMedia.BlockSize)) {
+    Status = EFI_INVALID_PARAMETER;
+    DEBUG ((EFI_D_ERROR, "CEATABlockReadBlocks:Invalid parameter\n" ));
+    goto Exit;
+  }
+
+  do {
+    if (BufferSize < BoundarySize) {
+      TransferSize = (UINT32) BufferSize;
+    } else {
+      TransferSize = BoundarySize;
+    }
+
+    Address += Index * TransferSize;
+    CEATALBA = DivU64x32Remainder (Address, DATA_UNIT_SIZE, &Remainder);
+    ASSERT(Remainder == 0);
+
+    Status = ReadDMAExt (
+               CardData,
+               CEATALBA,
+               pBuf,
+               (UINT16) (TransferSize / DATA_UNIT_SIZE)
+               );
+
+    if (EFI_ERROR (Status)) {
+      DEBUG ((EFI_D_ERROR, "Read Failed at 0x%x, Index %d, Size 0x%x\n", Address, Index, TransferSize));
+      This->Reset (This, TRUE);
+      goto Exit;
+    }
+
+    BufferSize -= TransferSize;
+    pBuf += TransferSize;
+    Index ++;
+  } while (BufferSize != 0);
+
+Exit:
+  return Status;
+}
+
+
+/**
+  Implements EFI_BLOCK_IO_PROTOCOL.WriteBlocks() function.
+
+  @param[in]  This                       The EFI_BLOCK_IO_PROTOCOL instance.
+  @param[in]  MediaId                    The media id that the write request is for.
+  @param[in]  LBA                        The starting logical block address to read from on the device.
+                                         The caller is responsible for writing to only legitimate locations.
+  @param[in]  BufferSize                 The size of the Buffer in bytes. This must be a multiple of the
+                                         intrinsic block size of the device.
+  @param[in]  Buffer                     A pointer to the destination buffer for the data. The caller
+                                         is responsible for either having implicit or explicit ownership
+                                         of the buffer.
+
+  @retval     EFI_SUCCESS                Success
+  @retval     EFI_DEVICE_ERROR           Hardware Error
+  @retval     EFI_INVALID_PARAMETER      Parameter is error
+  @retval     EFI_NO_MEDIA               No media
+  @retval     EFI_MEDIA_CHANGED          Media Change
+  @retval     EFI_BAD_BUFFER_SIZE        Buffer size is bad
+
+**/
+EFI_STATUS
+EFIAPI
+CEATABlockWriteBlocks (
+  IN  EFI_BLOCK_IO_PROTOCOL   *This,
+  IN  UINT32                  MediaId,
+  IN  EFI_LBA                 LBA,
+  IN  UINTN                   BufferSize,
+  IN  VOID                    *Buffer
+  )
+{
+  EFI_STATUS                  Status;
+  CARD_DATA                   *CardData;
+  UINT32                      TransferSize;
+  UINT8                       *pBuf;
+  UINT32                      Index;
+  UINT64                      Address;
+  UINT32                      Remainder;
+  UINT64                      CEATALBA;
+  UINT32                      BoundarySize;
+
+  Status       = EFI_SUCCESS;
+  CardData     = CARD_DATA_FROM_THIS (This);
+  pBuf         = Buffer;
+  Index        = 0;
+  Address      = MultU64x32 (LBA, CardData->BlockIoMedia.BlockSize);
+  BoundarySize = CardData->SdHostIo->HostCapability.BoundarySize;
+
+  if (!Buffer) {
+    Status = EFI_INVALID_PARAMETER;
+    goto Exit;
+  }
+
+  if (MediaId != CardData->BlockIoMedia.MediaId) {
+    Status = EFI_MEDIA_CHANGED;
+    goto Exit;
+  }
+
+  if ((BufferSize % CardData->BlockIoMedia.BlockSize) != 0) {
+    Status = EFI_BAD_BUFFER_SIZE;
+    goto Exit;
+  }
+
+  if (BufferSize == 0) {
+    Status = EFI_SUCCESS;
+    goto Exit;
+  }
+
+  if (CardData->BlockIoMedia.ReadOnly) {
+    Status = EFI_WRITE_PROTECTED;
+    goto Exit;
+  }
+
+  if ((Address + BufferSize) > MultU64x32 (CardData->BlockIoMedia.LastBlock + 1, CardData->BlockIoMedia.BlockSize)) {
+    Status = EFI_INVALID_PARAMETER;
+    goto Exit;
+  }
+
+  CardData->NeedFlush = TRUE;
+
+  do {
+    if (BufferSize < BoundarySize) {
+      TransferSize = (UINT32) BufferSize;
+    } else {
+      TransferSize = BoundarySize;
+    }
+
+    Address += Index * TransferSize;
+    CEATALBA = DivU64x32Remainder (Address, DATA_UNIT_SIZE, &Remainder);
+    ASSERT (Remainder == 0);
+
+    Status = WriteDMAExt (
+               CardData,
+               CEATALBA,
+               pBuf,
+               (UINT16) (TransferSize / DATA_UNIT_SIZE)
+               );
+
+    if (EFI_ERROR (Status)) {
+      DEBUG ((EFI_D_ERROR, "Write Failed at 0x%x, Index %d, Size 0x%x\n", Address, Index, TransferSize));
+      This->Reset (This, TRUE);
+      goto Exit;
+    }
+
+    BufferSize -= TransferSize;
+    pBuf += TransferSize;
+    Index ++;
+  } while (BufferSize != 0);
+
+Exit:
+  return Status;
+}
+
+
+/**
+  Implements EFI_BLOCK_IO_PROTOCOL.FlushBlocks() function.
+  (In this driver, this function just returns EFI_SUCCESS.)
+
+  @param[in]  This                   The EFI_BLOCK_IO_PROTOCOL instance.
+
+  @retval     EFI_SUCCESS
+  @retval     Others
+
+**/
+EFI_STATUS
+EFIAPI
+CEATABlockFlushBlocks (
+  IN  EFI_BLOCK_IO_PROTOCOL   *This
+  )
+{
+
+  CARD_DATA                   *CardData;
+
+  CardData = CARD_DATA_FROM_THIS (This);
+
+  if (CardData->NeedFlush) {
+    CardData->NeedFlush = FALSE;
+    FlushCache (CardData);
+  }
+
+  return EFI_SUCCESS;
+}
+
+
+/**
+  CEATA card BlockIo init function.
+
+  @param[in]  CardData               Pointer to CARD_DATA.
+
+  @retval     EFI_SUCCESS
+  @retval     Others
+
+**/
+EFI_STATUS
+CEATABlockIoInit (
+  IN  CARD_DATA    *CardData
+  )
+{
+  EFI_STATUS   Status;
+  UINT64       MaxSize;
+  UINT32       Remainder;
+
+  //
+  // BlockIO protocol
+  //
+  CardData->BlockIo.Revision    = EFI_BLOCK_IO_PROTOCOL_REVISION;
+  CardData->BlockIo.Media       = &(CardData->BlockIoMedia);
+  CardData->BlockIo.Reset       = CEATABlockReset;
+  CardData->BlockIo.ReadBlocks  = CEATABlockReadBlocks ;
+  CardData->BlockIo.WriteBlocks = CEATABlockWriteBlocks;
+  CardData->BlockIo.FlushBlocks = CEATABlockFlushBlocks;
+
+  CardData->BlockIoMedia.MediaId          = 0;
+  CardData->BlockIoMedia.RemovableMedia   = FALSE;
+  CardData->BlockIoMedia.MediaPresent     = TRUE;
+  CardData->BlockIoMedia.LogicalPartition = FALSE;
+
+  if (CardData->CSDRegister.PERM_WRITE_PROTECT | CardData->CSDRegister.TMP_WRITE_PROTECT) {
+    CardData->BlockIoMedia.ReadOnly       = TRUE;
+  } else {
+    CardData->BlockIoMedia.ReadOnly       = FALSE;
+  }
+
+  CardData->BlockIoMedia.WriteCaching     = FALSE;
+  CardData->BlockIoMedia.IoAlign          = 1;
+
+  Status = IndentifyDevice (CardData);
+  if (EFI_ERROR (Status)) {
+   goto Exit;
+  }
+
+  //
+  //Some device does not support this feature
+  //
+  if (CardData->IndentifyDeviceData.MaxWritesPerAddress == 0) {
+    CardData->BlockIoMedia.ReadOnly       = TRUE;
+  }
+
+  CardData->BlockIoMedia.BlockSize        = (1 << CardData->IndentifyDeviceData.Sectorsize);
+  ASSERT (CardData->BlockIoMedia.BlockSize >= 12);
+
+
+  MaxSize = *(UINT64 *) (CardData->IndentifyDeviceData.MaximumLBA);
+  MaxSize = MultU64x32 (MaxSize, 512);
+
+  Remainder = 0;
+  CardData->BlockNumber = DivU64x32Remainder (MaxSize, CardData->BlockIoMedia.BlockSize, &Remainder);
+  ASSERT (Remainder == 0);
+
+  CardData->BlockIoMedia.LastBlock = (EFI_LBA) (CardData->BlockNumber - 1);
+
+Exit:
+  return Status;
+}
+
diff --git a/Silicon/BroxtonSoC/BroxtonSiPkg/SouthCluster/Sdio/Dxe/SD/SdMediaDeviceDxe/ComponentName.c b/Silicon/BroxtonSoC/BroxtonSiPkg/SouthCluster/Sdio/Dxe/SD/SdMediaDeviceDxe/ComponentName.c
new file mode 100644
index 0000000..15fdaf6
--- /dev/null
+++ b/Silicon/BroxtonSoC/BroxtonSiPkg/SouthCluster/Sdio/Dxe/SD/SdMediaDeviceDxe/ComponentName.c
@@ -0,0 +1,219 @@
+/** @file
+  UEFI Component Name(2) protocol implementation for SD media device driver.
+
+  Copyright (c) 2013 - 2016, Intel Corporation. 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 "SdMediaDevice.h"
+
+//
+// EFI Component Name Protocol
+//
+GLOBAL_REMOVE_IF_UNREFERENCED EFI_COMPONENT_NAME_PROTOCOL  gSdMediaDeviceName = {
+  SdMediaDeviceGetDriverName,
+  SdMediaDeviceGetControllerName,
+  "eng"
+};
+
+//
+// EFI Component Name 2 Protocol
+//
+GLOBAL_REMOVE_IF_UNREFERENCED EFI_COMPONENT_NAME2_PROTOCOL gSdMediaDeviceName2 = {
+  (EFI_COMPONENT_NAME2_GET_DRIVER_NAME) SdMediaDeviceGetDriverName,
+  (EFI_COMPONENT_NAME2_GET_CONTROLLER_NAME) SdMediaDeviceGetControllerName,
+  "en"
+};
+
+
+GLOBAL_REMOVE_IF_UNREFERENCED EFI_UNICODE_STRING_TABLE mSdMediaDeviceDriverNameTable[] = {
+  { "eng;en", L"UEFI MMC/SD Media Device Driver" },
+  { NULL, NULL }
+};
+
+
+//
+// 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[in]  This                    A pointer to the EFI_COMPONENT_NAME2_PROTOCOL or
+                                      EFI_COMPONENT_NAME_PROTOCOL instance.
+
+  @param[in]  Language                A pointer to a Null-terminated ASCII string
+                                      array indicating the language. This is the
+                                      language of the driver name that the caller is
+                                      requesting, and it must match one of the
+                                      languages specified in SupportedLanguages. The
+                                      number of languages supported by a driver is up
+                                      to the driver writer. Language is specified
+                                      in RFC 3066 or ISO 639-2 language code format.
+
+  @param[out] DriverName              A pointer to the Unicode string to return.
+                                      This Unicode string is the name of the
+                                      driver specified by This in the language
+                                      specified by Language.
+
+  @retval     EFI_SUCCESS             The Unicode string for the Driver specified by
+                                      This and the language specified by Language was
+                                      returned in DriverName.
+
+  @retval     EFI_INVALID_PARAMETER   Language is NULL.
+
+  @retval     EFI_INVALID_PARAMETER   DriverName is NULL.
+
+  @retval     EFI_UNSUPPORTED         The driver specified by This does not support
+                                      the language specified by Language.
+
+**/
+EFI_STATUS
+EFIAPI
+SdMediaDeviceGetDriverName (
+  IN  EFI_COMPONENT_NAME_PROTOCOL  *This,
+  IN  CHAR8                        *Language,
+  OUT CHAR16                       **DriverName
+  )
+{
+  return LookupUnicodeString2 (
+           Language,
+           This->SupportedLanguages,
+           mSdMediaDeviceDriverNameTable,
+           DriverName,
+           (BOOLEAN) (This == &gSdMediaDeviceName)
+           );
+}
+
+
+/**
+  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[in]  This                  A pointer to the EFI_COMPONENT_NAME2_PROTOCOL or
+                                    EFI_COMPONENT_NAME_PROTOCOL instance.
+
+  @param[in]  ControllerHandle      The handle of a controller that the driver
+                                    specified by This is managing.  This handle
+                                    specifies the controller whose name is to be
+                                    returned.
+
+  @param[in]  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[in]  Language              A pointer to a Null-terminated ASCII string
+                                    array indicating the language.  This is the
+                                    language of the driver name that the caller is
+                                    requesting, and it must match one of the
+                                    languages specified in SupportedLanguages. The
+                                    number of languages supported by a driver is up
+                                    to the driver writer. Language is specified in
+                                    RFC 3066 or ISO 639-2 language code format.
+
+  @param[out] ControllerName        A pointer to the Unicode string to return.
+                                    This Unicode string is the name of the
+                                    controller specified by ControllerHandle and
+                                    ChildHandle in the language specified by
+                                    Language from the point of view of the driver
+                                    specified by This.
+
+  @retval     EFI_SUCCESS           The Unicode string for the user readable name in
+                                    the language specified by Language for the
+                                    driver specified by This was returned in
+                                    DriverName.
+
+  @retval     EFI_INVALID_PARAMETER ControllerHandle is not a valid EFI_HANDLE.
+
+  @retval     EFI_INVALID_PARAMETER ChildHandle is not NULL and it is not a valid
+                                    EFI_HANDLE.
+
+  @retval     EFI_INVALID_PARAMETER Language is NULL.
+
+  @retval     EFI_INVALID_PARAMETER ControllerName is NULL.
+
+  @retval     EFI_UNSUPPORTED       The driver specified by This is not currently
+                                    managing the controller specified by
+                                    ControllerHandle and ChildHandle.
+
+  @retval     EFI_UNSUPPORTED       The driver specified by This does not support
+                                    the language specified by Language.
+
+**/
+EFI_STATUS
+EFIAPI
+SdMediaDeviceGetControllerName (
+  IN  EFI_COMPONENT_NAME_PROTOCOL                     *This,
+  IN  EFI_HANDLE                                      ControllerHandle,
+  IN  EFI_HANDLE                                      ChildHandle        OPTIONAL,
+  IN  CHAR8                                           *Language,
+  OUT CHAR16                                          **ControllerName
+  )
+{
+  EFI_STATUS               Status;
+  EFI_BLOCK_IO_PROTOCOL    *BlockIo;
+  CARD_DATA                *CardData;
+
+  //
+  // This is a device driver, so ChildHandle must be NULL.
+  //
+  if (ChildHandle != NULL) {
+    return EFI_UNSUPPORTED;
+  }
+
+  //
+  // Get the device context
+  //
+  Status = gBS->OpenProtocol (
+                  ControllerHandle,
+                  &gEfiBlockIoProtocolGuid,
+                  (VOID **) &BlockIo,
+                  gSdMediaDeviceDriverBinding.DriverBindingHandle,
+                  ControllerHandle,
+                  EFI_OPEN_PROTOCOL_GET_PROTOCOL
+                  );
+
+  if (EFI_ERROR (Status)) {
+    return Status;
+  }
+
+  CardData  = CARD_DATA_FROM_THIS (BlockIo);
+
+  return LookupUnicodeString2 (
+           Language,
+           This->SupportedLanguages,
+           CardData->ControllerNameTable,
+           ControllerName,
+           (BOOLEAN) (This == &gSdMediaDeviceName)
+           );
+
+}
+
diff --git a/Silicon/BroxtonSoC/BroxtonSiPkg/SouthCluster/Sdio/Dxe/SD/SdMediaDeviceDxe/ComponentName.h b/Silicon/BroxtonSoC/BroxtonSiPkg/SouthCluster/Sdio/Dxe/SD/SdMediaDeviceDxe/ComponentName.h
new file mode 100644
index 0000000..3dea441
--- /dev/null
+++ b/Silicon/BroxtonSoC/BroxtonSiPkg/SouthCluster/Sdio/Dxe/SD/SdMediaDeviceDxe/ComponentName.h
@@ -0,0 +1,145 @@
+/** @file
+  This file contains the declarations for component name routines.
+
+  Copyright (c) 2013 - 2016, Intel Corporation. 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 _COMPONENT_NAME_H_
+#define _COMPONENT_NAME_H_
+
+/**
+  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[in]   This                    A pointer to the EFI_COMPONENT_NAME2_PROTOCOL or
+                                       EFI_COMPONENT_NAME_PROTOCOL instance.
+
+  @param[in]   Language                A pointer to a Null-terminated ASCII string
+                                       array indicating the language. This is the
+                                       language of the driver name that the caller is
+                                       requesting, and it must match one of the
+                                       languages specified in SupportedLanguages. The
+                                       number of languages supported by a driver is up
+                                       to the driver writer. Language is specified
+                                       in RFC 3066 or ISO 639-2 language code format.
+
+  @param[out]  DriverName              A pointer to the Unicode string to return.
+                                       This Unicode string is the name of the
+                                       driver specified by This in the language
+                                       specified by Language.
+
+  @retval      EFI_SUCCESS             The Unicode string for the Driver specified by
+                                       This and the language specified by Language was
+                                       returned in DriverName.
+
+  @retval      EFI_INVALID_PARAMETER   Language is NULL.
+
+  @retval      EFI_INVALID_PARAMETER   DriverName is NULL.
+
+  @retval      EFI_UNSUPPORTED         The driver specified by This does not support
+                                       the language specified by Language.
+
+**/
+EFI_STATUS
+EFIAPI
+SdMediaDeviceGetDriverName (
+  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[in]   This                    A pointer to the EFI_COMPONENT_NAME2_PROTOCOL or
+                                       EFI_COMPONENT_NAME_PROTOCOL instance.
+
+  @param[in]   ControllerHandle        The handle of a controller that the driver
+                                       specified by This is managing.  This handle
+                                       specifies the controller whose name is to be
+                                       returned.
+
+  @param[in]   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[in]   Language                A pointer to a Null-terminated ASCII string
+                                       array indicating the language.  This is the
+                                       language of the driver name that the caller is
+                                       requesting, and it must match one of the
+                                       languages specified in SupportedLanguages. The
+                                       number of languages supported by a driver is up
+                                       to the driver writer. Language is specified in
+                                       RFC 3066 or ISO 639-2 language code format.
+
+  @param[out]  ControllerName          A pointer to the Unicode string to return.
+                                       This Unicode string is the name of the
+                                       controller specified by ControllerHandle and
+                                       ChildHandle in the language specified by
+                                       Language from the point of view of the driver
+                                       specified by This.
+
+  @retval      EFI_SUCCESS             The Unicode string for the user readable name in
+                                       the language specified by Language for the
+                                       driver specified by This was returned in
+                                       DriverName.
+
+  @retval      EFI_INVALID_PARAMETER   ControllerHandle is not a valid EFI_HANDLE.
+
+  @retval      EFI_INVALID_PARAMETER   ChildHandle is not NULL and it is not a valid
+                                       EFI_HANDLE.
+
+  @retval      EFI_INVALID_PARAMETER   Language is NULL.
+
+  @retval      EFI_INVALID_PARAMETER   ControllerName is NULL.
+
+  @retval      EFI_UNSUPPORTED         The driver specified by This is not currently
+                                       managing the controller specified by
+                                       ControllerHandle and ChildHandle.
+
+  @retval      EFI_UNSUPPORTED         The driver specified by This does not support
+                                       the language specified by Language.
+
+**/
+EFI_STATUS
+EFIAPI
+SdMediaDeviceGetControllerName (
+  IN  EFI_COMPONENT_NAME_PROTOCOL                     *This,
+  IN  EFI_HANDLE                                      ControllerHandle,
+  IN  EFI_HANDLE                                      ChildHandle        OPTIONAL,
+  IN  CHAR8                                           *Language,
+  OUT CHAR16                                          **ControllerName
+  );
+
+#endif
+
diff --git a/Silicon/BroxtonSoC/BroxtonSiPkg/SouthCluster/Sdio/Dxe/SD/SdMediaDeviceDxe/MMCSDBlockIo.c b/Silicon/BroxtonSoC/BroxtonSiPkg/SouthCluster/Sdio/Dxe/SD/SdMediaDeviceDxe/MMCSDBlockIo.c
new file mode 100644
index 0000000..6180a25
--- /dev/null
+++ b/Silicon/BroxtonSoC/BroxtonSiPkg/SouthCluster/Sdio/Dxe/SD/SdMediaDeviceDxe/MMCSDBlockIo.c
@@ -0,0 +1,547 @@
+/** @file
+  Block I/O protocol for MMC/SD device.
+
+  Copyright (c) 2013 - 2016, Intel Corporation. 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 "SdMediaDevice.h"
+
+/**
+  Implements EFI_BLOCK_IO_PROTOCOL.Reset() function.
+
+  @param[in]   This                   The EFI_BLOCK_IO_PROTOCOL instance.
+  @param[in]   ExtendedVerification   Indicates that the driver may perform a more exhaustive.
+                                      verification operation of the device during reset.
+                                      (This parameter is ignored in this driver.)
+
+  @retval      EFI_SUCCESS            Success
+
+**/
+EFI_STATUS
+EFIAPI
+MMCSDBlockReset (
+  IN  EFI_BLOCK_IO_PROTOCOL   *This,
+  IN  BOOLEAN                 ExtendedVerification
+  )
+{
+  CARD_DATA                  *CardData;
+  EFI_SD_HOST_IO_PROTOCOL    *SdHostIo;
+
+  CardData  = CARD_DATA_FROM_THIS (This);
+  SdHostIo = CardData->SdHostIo;
+
+  return SdHostIo->ResetSdHost (SdHostIo, Reset_DAT_CMD);
+ }
+
+
+/**
+  Implements EFI_BLOCK_IO_PROTOCOL.ReadBlocks() function.
+
+  @param[in]  This                       The EFI_BLOCK_IO_PROTOCOL instance.
+  @param[in]  MediaId                    The media id that the write request is for.
+  @param[in]  LBA                        The starting logical block address to read from on the device.
+                                         The caller is responsible for writing to only legitimate locations.
+  @param[in]  BufferSize                 The size of the Buffer in bytes. This must be a multiple of the
+                                         intrinsic block size of the device.
+  @param[out] Buffer                     A pointer to the destination buffer for the data. The caller
+                                         is responsible for either having implicit or explicit ownership
+                                         of the buffer.
+
+  @retval     EFI_SUCCESS                Success
+  @retval     EFI_DEVICE_ERROR           Hardware Error
+  @retval     EFI_INVALID_PARAMETER      Parameter is error
+  @retval     EFI_NO_MEDIA               No media
+  @retval     EFI_MEDIA_CHANGED          Media Change
+  @retval     EFI_BAD_BUFFER_SIZE        Buffer size is bad
+
+**/
+EFI_STATUS
+EFIAPI
+MMCSDBlockReadBlocks (
+  IN  EFI_BLOCK_IO_PROTOCOL   *This,
+  IN  UINT32                  MediaId,
+  IN  EFI_LBA                 LBA,
+  IN  UINTN                   BufferSize,
+  OUT VOID                    *Buffer
+  )
+{
+  EFI_STATUS                  Status;
+  UINT32                      Address;
+  CARD_DATA                   *CardData;
+  EFI_SD_HOST_IO_PROTOCOL     *SdHostIo;
+  UINT32                      RemainingLength;
+  UINT32                      TransferLength;
+  UINT8                       *BufferPointer;
+  BOOLEAN                     SectorAddressing;
+  UINTN                       TotalBlock;
+
+  DEBUG ((EFI_D_INFO, "Read(LBA=%08lx, Buffer=%08x, Size=%08x)\n", LBA, Buffer, BufferSize));
+  Status = EFI_SUCCESS;
+  CardData = CARD_DATA_FROM_THIS (This);
+  SdHostIo = CardData->SdHostIo;
+
+  if (MediaId != CardData->BlockIoMedia.MediaId) {
+    return EFI_MEDIA_CHANGED;
+  }
+
+  if (ModU64x32 (BufferSize, CardData->BlockIoMedia.BlockSize) != 0) {
+    return EFI_BAD_BUFFER_SIZE;
+  }
+  if ((CardData->CardType == SdMemoryCard2High) || (CardData->CardType == MMCCardHighCap)) {
+    SectorAddressing = TRUE;
+  } else {
+    SectorAddressing = FALSE;
+  }
+  if (SectorAddressing) {
+    //
+    //Block Address
+    //
+    Address = (UINT32) DivU64x32 (MultU64x32 (LBA, CardData->BlockIoMedia.BlockSize), 512);
+  } else {
+    //
+    //Byte Address
+    //
+    Address  = (UINT32) MultU64x32 (LBA, CardData->BlockIoMedia.BlockSize);
+  }
+  TotalBlock = (UINTN) DivU64x32 (BufferSize, CardData->BlockIoMedia.BlockSize);
+  if (LBA + TotalBlock > CardData->BlockIoMedia.LastBlock + 1) {
+    return EFI_INVALID_PARAMETER;
+  }
+
+  if (!Buffer) {
+    Status = EFI_INVALID_PARAMETER;
+    DEBUG ((EFI_D_ERROR, "MMCSDBlockReadBlocks:Invalid parameter \r\n"));
+    goto Done;
+  }
+
+  if ((BufferSize % CardData->BlockIoMedia.BlockSize) != 0) {
+    Status = EFI_BAD_BUFFER_SIZE;
+    DEBUG ((EFI_D_ERROR, "MMCSDBlockReadBlocks: Bad buffer size \r\n"));
+    goto Done;
+  }
+
+  if (BufferSize == 0) {
+    Status = EFI_SUCCESS;
+    goto Done;
+  }
+
+    BufferPointer   = Buffer;
+    RemainingLength = (UINT32) BufferSize;
+
+    while (RemainingLength > 0) {
+    if ((BufferSize > CardData->BlockIoMedia.BlockSize)) {
+      if (RemainingLength > SdHostIo->HostCapability.BoundarySize) {
+        TransferLength = SdHostIo->HostCapability.BoundarySize;
+      } else {
+        TransferLength = RemainingLength;
+      }
+
+      if (CardData->CardType == MMCCard || CardData->CardType == MMCCardHighCap) {
+        if (!(CardData->ExtCSDRegister.CARD_TYPE & (BIT2 | BIT3))) {
+          Status = SendCommand (
+                     CardData,
+                     SET_BLOCKLEN,
+                     CardData->BlockIoMedia.BlockSize,
+                     NoData,
+                     NULL,
+                     0,
+                     ResponseR1,
+                     TIMEOUT_COMMAND,
+                     (UINT32 *) &(CardData->CardStatus)
+                     );
+
+          if (EFI_ERROR (Status)) {
+            break;
+          }
+        }
+        Status = SendCommand (
+                   CardData,
+                   SET_BLOCK_COUNT,
+                   TransferLength / CardData->BlockIoMedia.BlockSize,
+                   NoData,
+                   NULL,
+                   0,
+                   ResponseR1,
+                   TIMEOUT_COMMAND,
+                   (UINT32 *) &(CardData->CardStatus)
+                   );
+
+        if (EFI_ERROR (Status)) {
+          break;
+        }
+      }
+      Status = SendCommand (
+                 CardData,
+                 READ_MULTIPLE_BLOCK,
+                 Address,
+                 InData,
+                 CardData->AlignedBuffer,
+                 TransferLength,
+                 ResponseR1,
+                 TIMEOUT_DATA,
+                 (UINT32 *) &(CardData->CardStatus)
+                 );
+
+      if (EFI_ERROR (Status)) {
+        DEBUG ((EFI_D_ERROR, "MMCSDBlockReadBlocks: READ_MULTIPLE_BLOCK -> Fail\n"));
+        break;
+      }
+    } else {
+      if (RemainingLength > CardData->BlockIoMedia.BlockSize) {
+        TransferLength = CardData->BlockIoMedia.BlockSize;
+      } else {
+        TransferLength = RemainingLength;
+      }
+
+      Status = SendCommand (
+                 CardData,
+                 READ_SINGLE_BLOCK,
+                 Address,
+                 InData,
+                 CardData->AlignedBuffer,
+                 (UINT32) TransferLength,
+                 ResponseR1,
+                 TIMEOUT_DATA,
+                 (UINT32 *) &(CardData->CardStatus)
+                 );
+
+      if (EFI_ERROR (Status)) {
+        DEBUG ((EFI_D_ERROR, "MMCSDBlockReadBlocks: READ_SINGLE_BLOCK -> Fail\n"));
+        break;
+      }
+    }
+    CopyMem (BufferPointer, CardData->AlignedBuffer, TransferLength);
+    if (SectorAddressing) {
+      //
+      //Block Address
+      //
+      Address += TransferLength / 512;
+    } else {
+      //
+      //Byte Address
+      //
+      Address += TransferLength;
+    }
+    BufferPointer += TransferLength;
+    RemainingLength -= TransferLength;
+   }
+
+  if (EFI_ERROR (Status)) {
+    if ((CardData->CardType == SdMemoryCard) ||
+        (CardData->CardType == SdMemoryCard2)||
+        (CardData->CardType == SdMemoryCard2High)) {
+         SendCommand (
+           CardData,
+           STOP_TRANSMISSION,
+           0,
+           NoData,
+           NULL,
+           0,
+           ResponseR1b,
+           TIMEOUT_COMMAND,
+           (UINT32 *) &(CardData->CardStatus)
+           );
+
+    } else {
+       SendCommand (
+         CardData,
+         STOP_TRANSMISSION,
+         0,
+         NoData,
+         NULL,
+         0,
+         ResponseR1,
+         TIMEOUT_COMMAND,
+         (UINT32 *) &(CardData->CardStatus)
+         );
+    }
+
+  }
+
+Done:
+  DEBUG ((EFI_D_INFO, "MMCSDBlockReadBlocks: Status = %r\n", Status));
+  return Status;
+}
+
+
+/**
+  Implements EFI_BLOCK_IO_PROTOCOL.WriteBlocks() function.
+
+  @param[in]  This                       The EFI_BLOCK_IO_PROTOCOL instance.
+  @param[in]  MediaId                    The media id that the write request is for.
+  @param[in]  LBA                        The starting logical block address to read from on the device.
+                                         The caller is responsible for writing to only legitimate locations.
+  @param[in]  BufferSize                 The size of the Buffer in bytes. This must be a multiple of the
+                                         intrinsic block size of the device.
+  @param[in]  Buffer                     A pointer to the destination buffer for the data. The caller
+                                         is responsible for either having implicit or explicit ownership
+                                         of the buffer.
+
+  @retval     EFI_SUCCESS                Success
+  @retval     EFI_DEVICE_ERROR           Hardware Error
+  @retval     EFI_INVALID_PARAMETER      Parameter is error
+  @retval     EFI_NO_MEDIA               No media
+  @retval     EFI_MEDIA_CHANGED          Media Change
+  @retval     EFI_BAD_BUFFER_SIZE        Buffer size is bad
+
+**/
+EFI_STATUS
+EFIAPI
+MMCSDBlockWriteBlocks (
+  IN  EFI_BLOCK_IO_PROTOCOL   *This,
+  IN  UINT32                  MediaId,
+  IN  EFI_LBA                 LBA,
+  IN  UINTN                   BufferSize,
+  IN  VOID                    *Buffer
+  )
+{
+  EFI_STATUS                  Status;
+  UINT32                      Address;
+  CARD_DATA                   *CardData;
+  EFI_SD_HOST_IO_PROTOCOL     *SdHostIo;
+  UINT32                      RemainingLength;
+  UINT32                      TransferLength;
+  UINT8                       *BufferPointer;
+  BOOLEAN                     SectorAddressing;
+
+  DEBUG ((EFI_D_INFO, "Write(LBA=%08lx, Buffer=%08x, Size=%08x)\n", LBA, Buffer, BufferSize));
+  Status = EFI_SUCCESS;
+  CardData = CARD_DATA_FROM_THIS (This);
+  SdHostIo = CardData->SdHostIo;
+  if ((CardData->CardType == SdMemoryCard2High) || (CardData->CardType == MMCCardHighCap)) {
+    SectorAddressing = TRUE;
+  } else {
+    SectorAddressing = FALSE;
+  }
+  if (SectorAddressing) {
+    //
+    //Block Address
+    //
+    Address = (UINT32) DivU64x32 (MultU64x32 (LBA, CardData->BlockIoMedia.BlockSize), 512);
+  } else {
+    //
+    //Byte Address
+    //
+    Address = (UINT32) MultU64x32 (LBA, CardData->BlockIoMedia.BlockSize);
+  }
+
+  if (!Buffer) {
+    Status = EFI_INVALID_PARAMETER;
+    DEBUG ((EFI_D_ERROR, "MMCSDBlockWriteBlocks: Invalid parameter \r\n"));
+    goto Done;
+  }
+
+  if ((BufferSize % CardData->BlockIoMedia.BlockSize) != 0) {
+    Status = EFI_BAD_BUFFER_SIZE;
+    DEBUG ((EFI_D_ERROR, "MMCSDBlockWriteBlocks: Bad buffer size \r\n"));
+    goto Done;
+  }
+
+  if (BufferSize == 0) {
+    Status = EFI_SUCCESS;
+    goto Done;
+  }
+
+  if (This->Media->ReadOnly == TRUE) {
+    Status = EFI_WRITE_PROTECTED;
+    DEBUG ((EFI_D_ERROR, "MMCSDBlockWriteBlocks: Write protected \r\n"));
+    goto Done;
+  }
+
+    BufferPointer = Buffer;
+    RemainingLength = (UINT32) BufferSize;
+
+    while (RemainingLength > 0) {
+    if ((BufferSize > CardData->BlockIoMedia.BlockSize) ) {
+      if (RemainingLength > SdHostIo->HostCapability.BoundarySize) {
+        TransferLength = SdHostIo->HostCapability.BoundarySize;
+      } else {
+        TransferLength = RemainingLength;
+      }
+
+      if (CardData->CardType == MMCCard || CardData->CardType == MMCCardHighCap) {
+
+        if (!(CardData->ExtCSDRegister.CARD_TYPE & (BIT2 | BIT3)))  {
+            Status = SendCommand (
+                       CardData,
+                       SET_BLOCKLEN,
+                       CardData->BlockIoMedia.BlockSize,
+                       NoData,
+                       NULL,
+                       0,
+                       ResponseR1,
+                       TIMEOUT_COMMAND,
+                       (UINT32 *) &(CardData->CardStatus)
+                       );
+
+            if (EFI_ERROR (Status)) {
+              break;
+            }
+        }
+        Status = SendCommand (
+                   CardData,
+                   SET_BLOCK_COUNT,
+                   TransferLength / CardData->BlockIoMedia.BlockSize,
+                   NoData,
+                   NULL,
+                   0,
+                   ResponseR1,
+                   TIMEOUT_COMMAND,
+                   (UINT32 *) &(CardData->CardStatus)
+                   );
+
+        if (EFI_ERROR (Status)) {
+          break;
+        }
+      }
+
+      CopyMem (CardData->AlignedBuffer, BufferPointer, TransferLength);
+
+      Status = SendCommand (
+                 CardData,
+                 WRITE_MULTIPLE_BLOCK,
+                 Address,
+                 OutData,
+                 CardData->AlignedBuffer,
+                 (UINT32) TransferLength,
+                 ResponseR1,
+                 TIMEOUT_DATA,
+                 (UINT32 *) &(CardData->CardStatus)
+                 );
+
+      if (EFI_ERROR (Status)) {
+        DEBUG ((EFI_D_ERROR, "MMCSDBlockWriteBlocks: WRITE_MULTIPLE_BLOCK -> Fail\n"));
+        break;
+      }
+    } else {
+      if (RemainingLength > CardData->BlockIoMedia.BlockSize) {
+        TransferLength = CardData->BlockIoMedia.BlockSize;
+      } else {
+        TransferLength = RemainingLength;
+      }
+
+      CopyMem (CardData->AlignedBuffer, BufferPointer, TransferLength);
+
+      Status = SendCommand (
+                 CardData,
+                 WRITE_BLOCK,
+                 Address,
+                 OutData,
+                 CardData->AlignedBuffer,
+                 (UINT32) TransferLength,
+                 ResponseR1,
+                 TIMEOUT_DATA,
+                 (UINT32 *) &(CardData->CardStatus)
+                 );
+
+    }
+
+    if (SectorAddressing) {
+        //
+        //Block Address
+        //
+        Address += TransferLength / 512;
+      } else {
+        //
+        //Byte Address
+        //
+        Address += TransferLength;
+      }
+      BufferPointer   += TransferLength;
+      RemainingLength -= TransferLength;
+
+  }
+
+  if (EFI_ERROR (Status)) {
+    SendCommand (
+      CardData,
+      STOP_TRANSMISSION,
+      0,
+      NoData,
+      NULL,
+      0,
+      ResponseR1b,
+      TIMEOUT_COMMAND,
+      (UINT32 *) &(CardData->CardStatus)
+      );
+
+  }
+
+Done:
+  return EFI_SUCCESS;
+}
+
+
+/**
+  Implements EFI_BLOCK_IO_PROTOCOL.FlushBlocks() function.
+  (In this driver, this function just returns EFI_SUCCESS.)
+
+  @param[in]  This                   The EFI_BLOCK_IO_PROTOCOL instance.
+
+  @retval     EFI_SUCCESS
+  @retval     Others
+
+**/
+EFI_STATUS
+EFIAPI
+MMCSDBlockFlushBlocks (
+  IN  EFI_BLOCK_IO_PROTOCOL   *This
+  )
+{
+  return EFI_SUCCESS;
+}
+
+
+/**
+  MMC/SD card BlockIo init function.
+
+  @param[in]  CardData               Pointer to CARD_DATA.
+
+  @retval     EFI_SUCCESS
+  @retval     Others
+
+**/
+EFI_STATUS
+MMCSDBlockIoInit (
+  IN  CARD_DATA    *CardData
+  )
+{
+
+  //
+  // BlockIO protocol
+  //
+  CardData->BlockIo.Revision    = EFI_BLOCK_IO_PROTOCOL_REVISION;
+  CardData->BlockIo.Media       = &(CardData->BlockIoMedia);
+  CardData->BlockIo.Reset       = MMCSDBlockReset;
+  CardData->BlockIo.ReadBlocks  = MMCSDBlockReadBlocks ;
+  CardData->BlockIo.WriteBlocks = MMCSDBlockWriteBlocks;
+  CardData->BlockIo.FlushBlocks = MMCSDBlockFlushBlocks;
+
+  CardData->BlockIoMedia.MediaId          = 0;
+  CardData->BlockIoMedia.RemovableMedia   = FALSE;
+  CardData->BlockIoMedia.MediaPresent     = TRUE;
+  CardData->BlockIoMedia.LogicalPartition = FALSE;
+
+  if (CardData->CSDRegister.PERM_WRITE_PROTECT || CardData->CSDRegister.TMP_WRITE_PROTECT) {
+    CardData->BlockIoMedia.ReadOnly         = TRUE;
+  } else {
+    CardData->BlockIoMedia.ReadOnly         = FALSE;
+  }
+
+  CardData->BlockIoMedia.WriteCaching     = FALSE;
+  CardData->BlockIoMedia.BlockSize        = CardData->BlockLen;
+  CardData->BlockIoMedia.IoAlign          = 1;
+  CardData->BlockIoMedia.LastBlock        = (EFI_LBA) (CardData->BlockNumber - 1);
+
+  return EFI_SUCCESS;
+}
+
diff --git a/Silicon/BroxtonSoC/BroxtonSiPkg/SouthCluster/Sdio/Dxe/SD/SdMediaDeviceDxe/MMCSDTransfer.c b/Silicon/BroxtonSoC/BroxtonSiPkg/SouthCluster/Sdio/Dxe/SD/SdMediaDeviceDxe/MMCSDTransfer.c
new file mode 100644
index 0000000..e0304de
--- /dev/null
+++ b/Silicon/BroxtonSoC/BroxtonSiPkg/SouthCluster/Sdio/Dxe/SD/SdMediaDeviceDxe/MMCSDTransfer.c
@@ -0,0 +1,1661 @@
+/** @file
+  MMC/SD transfer specific functions
+
+  Copyright (c) 2013 - 2016, Intel Corporation. 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 "SdMediaDevice.h"
+
+
+/**
+  Check card status, print the debug info and check the error
+
+  @param[in]  Status                Status got from card status register.
+
+  @retval     EFI_SUCCESS
+  @retval     EFI_DEVICE_ERROR
+
+**/
+EFI_STATUS
+CheckCardStatus (
+  IN  UINT32    Status
+  )
+{
+  CARD_STATUS    *CardStatus;
+  CardStatus = (CARD_STATUS *) (&Status);
+
+  if (CardStatus->ADDRESS_OUT_OF_RANGE) {
+    DEBUG ((EFI_D_ERROR, "CardStatus: ADDRESS_OUT_OF_RANGE\n"));
+  }
+
+  if (CardStatus->ADDRESS_MISALIGN) {
+    DEBUG ((EFI_D_ERROR, "CardStatus: ADDRESS_MISALIGN\n"));
+  }
+
+  if (CardStatus->BLOCK_LEN_ERROR) {
+    DEBUG ((EFI_D_ERROR, "CardStatus: BLOCK_LEN_ERROR\n"));
+  }
+
+  if (CardStatus->ERASE_SEQ_ERROR) {
+    DEBUG ((EFI_D_ERROR, "CardStatus: ERASE_SEQ_ERROR\n"));
+  }
+
+  if (CardStatus->ERASE_PARAM) {
+    DEBUG ((EFI_D_ERROR, "CardStatus: ERASE_PARAM\n"));
+  }
+
+  if (CardStatus->WP_VIOLATION) {
+    DEBUG ((EFI_D_ERROR, "CardStatus: WP_VIOLATION\n"));
+  }
+
+  if (CardStatus->CARD_IS_LOCKED) {
+    DEBUG ((EFI_D_ERROR, "CardStatus: CARD_IS_LOCKED\n"));
+  }
+
+  if (CardStatus->LOCK_UNLOCK_FAILED) {
+    DEBUG ((EFI_D_ERROR, "CardStatus: LOCK_UNLOCK_FAILED\n"));
+  }
+
+  if (CardStatus->COM_CRC_ERROR) {
+    DEBUG ((EFI_D_ERROR, "CardStatus: COM_CRC_ERROR\n"));
+  }
+
+  if (CardStatus->ILLEGAL_COMMAND) {
+    DEBUG ((EFI_D_ERROR, "CardStatus: ILLEGAL_COMMAND\n"));
+  }
+
+  if (CardStatus->CARD_ECC_FAILED) {
+    DEBUG ((EFI_D_ERROR, "CardStatus: CARD_ECC_FAILED\n"));
+  }
+
+  if (CardStatus->CC_ERROR) {
+    DEBUG ((EFI_D_ERROR, "CardStatus: CC_ERROR\n"));
+  }
+
+  if (CardStatus->ERROR) {
+    DEBUG ((EFI_D_ERROR, "CardStatus: ERROR\n"));
+  }
+
+  if (CardStatus->UNDERRUN) {
+    DEBUG ((EFI_D_ERROR, "CardStatus: UNDERRUN\n"));
+  }
+
+  if (CardStatus->OVERRUN) {
+    DEBUG ((EFI_D_ERROR, "CardStatus: OVERRUN\n"));
+  }
+
+  if (CardStatus->CID_CSD_OVERWRITE) {
+    DEBUG ((EFI_D_ERROR, "CardStatus: CID_CSD_OVERWRITE\n"));
+  }
+
+  if (CardStatus->WP_ERASE_SKIP) {
+    DEBUG ((EFI_D_ERROR, "CardStatus: WP_ERASE_SKIP\n"));
+  }
+
+  if (CardStatus->ERASE_RESET) {
+    DEBUG ((EFI_D_ERROR, "CardStatus: ERASE_RESET\n"));
+  }
+
+  if (CardStatus->SWITCH_ERROR) {
+    DEBUG ((EFI_D_ERROR, "CardStatus: SWITCH_ERROR\n"));
+  }
+
+  if ((Status & 0xFCFFA080) != 0) {
+    return EFI_DEVICE_ERROR;
+  }
+
+  return EFI_SUCCESS;
+}
+
+
+/**
+  Send command by using Host IO protocol
+
+  @param[in]  This                  A pointer to the EFI_SD_HOST_IO_PROTOCOL instance.
+  @param[in]  CommandIndex          The command index to set the command index field of command register.
+  @param[in]  Argument              Command argument to set the argument field of command register.
+  @param[in]  DataType              TRANSFER_TYPE, indicates no data, data in or data out.
+  @param[in]  Buffer                Contains the data read from / write to the device.
+  @param[in]  BufferSize            The size of the buffer.
+  @param[in]  ResponseType          RESPONSE_TYPE.
+  @param[in]  TimeOut               Time out value in 1 ms unit.
+  @param[out] ResponseData          Depending on the ResponseType, such as CSD or card status.
+
+  @retval     EFI_SUCCESS
+  @retval     EFI_INVALID_PARAMETER
+  @retval     EFI_UNSUPPORTED
+  @retval     EFI_DEVICE_ERROR
+
+**/
+EFI_STATUS
+SendCommand (
+  IN   CARD_DATA                  *CardData,
+  IN   UINT16                     CommandIndex,
+  IN   UINT32                     Argument,
+  IN   TRANSFER_TYPE              DataType,
+  IN   UINT8                      *Buffer, OPTIONAL
+  IN   UINT32                     BufferSize,
+  IN   RESPONSE_TYPE              ResponseType,
+  IN   UINT32                     TimeOut,
+  OUT  UINT32                     *ResponseData
+  )
+{
+
+  EFI_STATUS                 Status;
+  EFI_SD_HOST_IO_PROTOCOL    *SdHostIo;
+
+  SdHostIo = CardData->SdHostIo;
+  if (CardData->CardType != MMCCard && CardData->CardType != MMCCardHighCap) {
+    CommandIndex |= AUTO_CMD12_ENABLE;
+  }
+  Status = SdHostIo->SendCommand (
+                       SdHostIo,
+                       CommandIndex,
+                       Argument,
+                       DataType,
+                       Buffer,
+                       BufferSize,
+                       ResponseType,
+                       TimeOut,
+                       ResponseData
+                       );
+
+  if (!EFI_ERROR (Status)) {
+    if (ResponseType == ResponseR1 || ResponseType == ResponseR1b) {
+      ASSERT (ResponseData != NULL);
+      Status = CheckCardStatus (*ResponseData);
+    }
+  } else {
+    SdHostIo->ResetSdHost (SdHostIo, Reset_DAT_CMD);
+  }
+
+  return Status;
+}
+
+
+/**
+  Send the card APP_CMD command with the following command indicated by CommandIndex
+
+  @param[in]  CardData              Pointer to CARD_DATA.
+  @param[in]  CommandIndex          The command index to set the command index field of command register.
+  @param[in]  Argument              Command argument to set the argument field of command register.
+  @param[in]  DataType              TRANSFER_TYPE, indicates no data, data in or data out.
+  @param[in]  Buffer                Contains the data read from / write to the device.
+  @param[in]  BufferSize            The size of the buffer.
+  @param[in]  ResponseType          RESPONSE_TYPE.
+  @param[in]  TimeOut               Time out value in 1 ms unit.
+  @param[out] ResponseData          Depending on the ResponseType, such as CSD or card status.
+
+  @retval     EFI_SUCCESS
+  @retval     EFI_INVALID_PARAMETER
+  @retval     EFI_UNSUPPORTED
+  @retval     EFI_DEVICE_ERROR
+
+**/
+EFI_STATUS
+SendAppCommand (
+  IN   CARD_DATA                  *CardData,
+  IN   UINT16                     CommandIndex,
+  IN   UINT32                     Argument,
+  IN   TRANSFER_TYPE              DataType,
+  IN   UINT8                      *Buffer, OPTIONAL
+  IN   UINT32                     BufferSize,
+  IN   RESPONSE_TYPE              ResponseType,
+  IN   UINT32                     TimeOut,
+  OUT  UINT32                     *ResponseData
+  )
+{
+
+  EFI_STATUS                 Status;
+  EFI_SD_HOST_IO_PROTOCOL    *SdHostIo;
+  UINT8                      Index;
+
+  SdHostIo = CardData->SdHostIo;
+  Status = EFI_SUCCESS;
+
+  for (Index = 0; Index < 2; Index++) {
+    Status = SdHostIo->SendCommand (
+                         SdHostIo,
+                         APP_CMD,
+                         (CardData->Address << 16),
+                         NoData,
+                         NULL,
+                         0,
+                         ResponseR1,
+                         TIMEOUT_COMMAND,
+                         (UINT32 *) &(CardData->CardStatus)
+                         );
+
+    if (!EFI_ERROR (Status)) {
+        Status = CheckCardStatus (*(UINT32 *) &(CardData->CardStatus));
+        if (CardData->CardStatus.SAPP_CMD != 1) {
+          Status = EFI_DEVICE_ERROR;
+        }
+        if (!EFI_ERROR (Status)) {
+          break;
+        }
+    } else {
+      SdHostIo->ResetSdHost (SdHostIo, Reset_Auto);
+    }
+  }
+
+  if (EFI_ERROR (Status)) {
+    return Status;
+  }
+  if (CardData->CardType != MMCCard && CardData->CardType != MMCCardHighCap) {
+    CommandIndex |= AUTO_CMD12_ENABLE;
+  }
+
+  Status = SdHostIo->SendCommand (
+                       SdHostIo,
+                       CommandIndex,
+                       Argument,
+                       DataType,
+                       Buffer,
+                       BufferSize,
+                       ResponseType,
+                       TimeOut,
+                       ResponseData
+                       );
+
+  if (!EFI_ERROR (Status)) {
+    if (ResponseType == ResponseR1 || ResponseType == ResponseR1b) {
+      ASSERT (ResponseData != NULL);
+      Status = CheckCardStatus (*ResponseData);
+    }
+  } else {
+    SdHostIo->ResetSdHost (SdHostIo, Reset_Auto);
+  }
+
+  return Status;
+}
+
+
+/**
+  Send the card FAST_IO command
+
+  @param[in]      CardData               Pointer to CARD_DATA.
+  @param[in]      RegisterAddress        Register Address.
+  @param[in, out] RegisterData           Pointer to register Data.
+  @param[in]      Write                  TRUE for write, FALSE for read.
+
+  @retval         EFI_SUCCESS
+  @retval         EFI_UNSUPPORTED
+  @retval         EFI_INVALID_PARAMETER
+  @retval         EFI_DEVICE_ERROR
+
+**/
+EFI_STATUS
+FastIO (
+  IN      CARD_DATA   *CardData,
+  IN      UINT8       RegisterAddress,
+  IN  OUT UINT8       *RegisterData,
+  IN      BOOLEAN     Write
+  )
+{
+  EFI_STATUS                 Status;
+  UINT32                     Argument;
+  UINT32                     Data;
+
+  Status = EFI_SUCCESS;
+
+  if (RegisterData == NULL) {
+    Status = EFI_INVALID_PARAMETER;
+    goto Exit;
+  }
+
+  Argument = (CardData->Address << 16) | (RegisterAddress << 8);
+  if (Write) {
+    Argument |= BIT15 | (*RegisterData);
+  }
+
+  Status = SendCommand (
+             CardData,
+             FAST_IO,
+             Argument,
+             NoData,
+             NULL,
+             0,
+             ResponseR4,
+             TIMEOUT_COMMAND,
+             &Data
+             );
+
+  if (EFI_ERROR (Status)) {
+    goto Exit;
+  }
+
+  if ((Data & BIT15) == 0) {
+    Status = EFI_DEVICE_ERROR;
+    goto Exit;
+  }
+
+  if (!Write) {
+   *RegisterData = (UINT8) Data;
+  }
+
+Exit:
+  return Status;
+}
+
+
+/**
+  Send the card GO_INACTIVE_STATE command.
+
+  @param[in]  CardData             Pointer to CARD_DATA.
+
+  @retval     EFI_SUCCESS
+  @retval     others
+
+**/
+EFI_STATUS
+PutCardInactive (
+  IN  CARD_DATA   *CardData
+  )
+{
+  EFI_STATUS                 Status;
+
+
+  Status = SendCommand (
+             CardData,
+             GO_INACTIVE_STATE,
+             (CardData->Address << 16),
+             NoData,
+             NULL,
+             0,
+             ResponseNo,
+             TIMEOUT_COMMAND,
+             NULL
+             );
+
+  return Status;
+
+}
+
+
+/**
+  Get card interested information for CSD rergister
+
+  @param[in]  CardData               Pointer to CARD_DATA.
+
+  @retval     EFI_SUCCESS
+  @retval     EFI_UNSUPPORTED
+  @retval     EFI_INVALID_PARAMETER
+
+**/
+EFI_STATUS
+CaculateCardParameter (
+  IN  CARD_DATA    *CardData
+  )
+{
+  EFI_STATUS     Status;
+  UINT32         Frequency;
+  UINT32         Multiple;
+  UINT32         CSize;
+  CSD_SDV2       *CsdSDV2;
+
+  Status = EFI_SUCCESS;
+
+  switch (CardData->CSDRegister.TRAN_SPEED & 0x7) {
+    case 0:
+      Frequency = 100 * 1000;
+      break;
+
+    case 1:
+      Frequency = 1 * 1000 * 1000;
+      break;
+
+    case 2:
+      Frequency = 10 * 1000 * 1000;
+      break;
+
+    case 3:
+      Frequency = 100 * 1000 * 1000;
+      break;
+
+    default:
+      Status = EFI_INVALID_PARAMETER;
+      goto Exit;
+  }
+
+  switch ((CardData->CSDRegister.TRAN_SPEED >> 3) & 0xF) {
+    case 1:
+      Multiple = 10;
+      break;
+
+    case 2:
+      Multiple = 12;
+      break;
+
+    case 3:
+      Multiple = 13;
+      break;
+
+    case 4:
+      Multiple = 15;
+      break;
+
+    case 5:
+      Multiple = 20;
+      break;
+
+    case 6:
+      if (CardData->CardType == MMCCard  || CardData->CardType == MMCCardHighCap) {
+        Multiple = 26;
+      } else {
+        Multiple = 25;
+      }
+      break;
+
+    case 7:
+      Multiple = 30;
+      break;
+
+    case 8:
+      Multiple = 35;
+      break;
+
+    case 9:
+      Multiple = 40;
+      break;
+
+    case 10:
+      Multiple = 45;
+      break;
+
+    case 11:
+      if (CardData->CardType == MMCCard  || CardData->CardType == MMCCardHighCap) {
+        Multiple = 52;
+      } else {
+        Multiple = 50;
+      }
+      break;
+
+    case 12:
+      Multiple = 55;
+      break;
+
+    case 13:
+      Multiple = 60;
+      break;
+
+    case 14:
+      Multiple = 70;
+      break;
+
+    case 15:
+      Multiple = 80;
+      break;
+
+    default:
+      Status = EFI_INVALID_PARAMETER;
+      goto Exit;
+  }
+
+  Frequency = Frequency * Multiple / 10;
+  CardData->MaxFrequency = Frequency;
+
+  CardData->BlockLen = 1 << CardData->CSDRegister.READ_BL_LEN;
+
+  if (CardData->CardType == SdMemoryCard2High) {
+    ASSERT (CardData->CSDRegister.CSD_STRUCTURE == 1);
+    CsdSDV2 = (CSD_SDV2 *) &CardData->CSDRegister;
+
+    //
+    // the K here means 1024 not 1000
+    //
+    CardData->BlockNumber = DivU64x32 (MultU64x32 (CsdSDV2->C_SIZE + 1, 512 * 1024) , CardData->BlockLen);
+  } else {
+    //
+    // For MMC card > 2G, the block number will be recaculate later
+    //
+    CSize = CardData->CSDRegister.C_SIZELow2 | (CardData->CSDRegister.C_SIZEHigh10 << 2);
+    CardData->BlockNumber = MultU64x32 (LShiftU64 (1, CardData->CSDRegister.C_SIZE_MULT + 2), CSize + 1);
+  }
+
+  //
+  //For >= 2G card, BlockLen may be 1024, but the transfer size is still 512 bytes
+  //
+  if (CardData->BlockLen > 512) {
+    CardData->BlockNumber = DivU64x32 (MultU64x32 (CardData->BlockNumber, CardData->BlockLen), 512);
+    CardData->BlockLen = 512;
+  }
+
+  DEBUG ((
+    EFI_D_INFO,
+    "CalculateCardParameter: Card Size: 0x%lx\n", MultU64x32 (CardData->BlockNumber, CardData->BlockLen)
+    ));
+
+Exit:
+  return Status;
+}
+
+
+/**
+  Test the bus width setting for MMC card.It is used only for verification purpose.
+
+  @param[in]  CardData               Pointer to CARD_DATA.
+  @param[in]  Width                  1, 4, 8 bits.
+
+  @retval     EFI_SUCCESS
+  @retval     EFI_UNSUPPORTED
+  @retval     EFI_INVALID_PARAMETER
+
+**/
+EFI_STATUS
+MMCCardBusWidthTest (
+  IN  CARD_DATA             *CardData,
+  IN  UINT32                Width
+  )
+{
+  EFI_STATUS                 Status;
+  UINT64                     Data;
+  UINT64                     Value;
+
+  ASSERT(CardData != NULL);
+
+  Value = 0;
+
+  switch (Width) {
+    case 1:
+      Data = 0x80;
+      break;
+
+    case 4:
+      Data = 0x5A;
+      break;
+
+    case 8:
+      Data = 0xAA55;
+      break;
+
+    default:
+      Status = EFI_INVALID_PARAMETER;
+      goto Exit;
+  }
+
+  CopyMem (CardData->AlignedBuffer, &Data, Width);
+  Status  = SendCommand (
+              CardData,
+              BUSTEST_W,
+              0,
+              OutData,
+              CardData->AlignedBuffer,
+              Width,
+              ResponseR1,
+              TIMEOUT_COMMAND,
+              (UINT32 *) &(CardData->CardStatus)
+              );
+
+  if (EFI_ERROR (Status)) {
+    DEBUG ((EFI_D_ERROR, "MMCCardBusWidthTest:SendCommand BUSTEST_W 0x%x\n", *(UINT32*)&(CardData->CardStatus)));
+    goto Exit;
+  }
+
+  gBS->Stall (10 * 1000);
+
+  Data = 0;
+
+  Status  = SendCommand (
+              CardData,
+              BUSTEST_R,
+              0,
+              InData,
+              CardData->AlignedBuffer,
+              Width,
+              ResponseR1,
+              TIMEOUT_COMMAND,
+              (UINT32 *) &(CardData->CardStatus)
+              );
+
+  if (EFI_ERROR (Status)) {
+    DEBUG ((EFI_D_ERROR, "MMCCardBusWidthTest:SendCommand BUSTEST_R 0x%x\n", *(UINT32 *) &(CardData->CardStatus)));
+    goto Exit;
+  }
+  CopyMem (&Data, CardData->AlignedBuffer, Width);
+
+  switch (Width) {
+    case 1:
+      Value = (~(Data ^ 0x80)) & 0xC0;
+      break;
+
+    case 4:
+      Value = (~(Data ^ 0x5A)) & 0xFF;
+      break;
+
+    case 8:
+      Value = (~(Data ^ 0xAA55)) & 0xFFFF;
+      break;
+  }
+
+  if (Value == 0) {
+    Status = EFI_SUCCESS;
+  } else {
+    Status = EFI_UNSUPPORTED;
+  }
+
+Exit:
+  return Status;
+}
+
+
+/**
+  This function can detect these card types:
+    1. MMC card
+    2. SD 1.1 card
+    3. SD 2.0 standard card
+    3. SD 2.0 high capacity card
+
+  @param[in]  CardData             Pointer to CARD_DATA.
+
+  @retval     EFI_SUCCESS
+  @retval     others
+
+**/
+EFI_STATUS
+GetCardType (
+  IN  CARD_DATA              *CardData
+  )
+{
+  EFI_STATUS                 Status;
+  EFI_SD_HOST_IO_PROTOCOL    *SdHostIo;
+  UINT32                     Argument;
+  UINT32                     ResponseData;
+  UINT32                     Count;
+  BOOLEAN                    SdCommand8Support;
+
+  SdHostIo = CardData->SdHostIo;
+
+  //
+  // Reset the card
+  //
+  Status  = SendCommand (
+              CardData,
+              GO_IDLE_STATE,
+              0,
+              NoData,
+              NULL,
+              0,
+              ResponseNo,
+              TIMEOUT_COMMAND,
+              NULL
+              );
+
+  if (EFI_ERROR (Status)) {
+    DEBUG ((EFI_D_ERROR, "GO_IDLE_STATE Fail Status = 0x%x\n", Status));
+    goto Exit;
+  }
+  gBS->Stall (10 * 1000);
+
+  //
+  // Only 2.7V - 3.6V is supported for SD2.0, only SD 2.0 card can pass
+  // MMC and SD1.1 card will fail this command
+  //
+  Argument          = (VOLTAGE_27_36 << 8) | CHECK_PATTERN;
+  ResponseData      = 0;
+  SdCommand8Support = FALSE;
+
+  Status  = SendCommand (
+              CardData,
+              SEND_IF_COND,
+              Argument,
+              NoData,
+              NULL,
+              0,
+              ResponseR7,
+              TIMEOUT_COMMAND,
+              &ResponseData
+              );
+
+  if (EFI_ERROR (Status)) {
+    if (Status != EFI_TIMEOUT) {
+       DEBUG ((EFI_D_ERROR, "SEND_IF_COND Fail, none time out error\n"));
+       goto Exit;
+    }
+  } else {
+     if (ResponseData != Argument) {
+       DEBUG ((EFI_D_ERROR, "SEND_IF_COND Fail, respond data does not match send data\n"));
+       Status = EFI_DEVICE_ERROR;
+       goto Exit;
+    }
+    SdCommand8Support = TRUE;
+  }
+
+  Argument = 0;
+
+  if (SdHostIo->HostCapability.V30Support == TRUE) {
+    Argument |= BIT17 | BIT18;
+  } else if (SdHostIo->HostCapability.V33Support == TRUE) {
+    Argument |= BIT20 | BIT21;
+  }
+
+  if (SdCommand8Support) {
+    Argument |= BIT30;
+  }
+
+  Count = 20;
+  do {
+    Status  = SendAppCommand (
+                CardData,
+                SD_SEND_OP_COND,
+                Argument,
+                NoData,
+                NULL,
+                0,
+                ResponseR3,
+                TIMEOUT_COMMAND,
+                (UINT32 *) &(CardData->OCRRegister)
+                );
+
+    if (EFI_ERROR (Status)) {
+      if ((Status == EFI_TIMEOUT) && (!SdCommand8Support)) {
+        CardData->CardType = MMCCard;
+        Status = EFI_SUCCESS;
+        DEBUG ((EFI_D_INFO, "SD_SEND_OP_COND, MMC card was identified\n"));
+      } else {
+        DEBUG ((EFI_D_ERROR, "SD_SEND_OP_COND Fail, check whether it is neither a MMC card nor a SD card\n"));
+      }
+      goto Exit;
+    }
+    //
+    // Avoid waiting if sucess. Busy bit 0 means not ready
+    //
+    if (CardData->OCRRegister.Busy == 1) {
+      break;
+    }
+
+    gBS->Stall (50 * 1000);
+    Count--;
+    if (Count == 0) {
+      DEBUG ((EFI_D_ERROR, "Card is always in busy state\n"));
+      Status = EFI_TIMEOUT;
+      goto Exit;
+    }
+  } while (1);
+
+  //
+  // Check supported voltage
+  //
+  Argument = 0;
+  if (SdHostIo->HostCapability.V30Support == TRUE) {
+    if ((CardData->OCRRegister.V270_V360 & BIT2) == BIT2) {
+      Argument |= BIT17;
+    } else if ((CardData->OCRRegister.V270_V360 & BIT3) == BIT3) {
+      Argument |= BIT18;
+    }
+  } else if (SdHostIo->HostCapability.V33Support == TRUE) {
+     if ((CardData->OCRRegister.V270_V360 & BIT5) == BIT5) {
+       Argument |= BIT20;
+     } else if ((CardData->OCRRegister.V270_V360 & BIT6) == BIT6) {
+       Argument |= BIT21;
+     }
+  }
+
+  if (Argument == 0) {
+     //
+     // No matched support voltage
+     //
+     PutCardInactive (CardData);
+     DEBUG ((EFI_D_ERROR, "No matched voltage for this card\n"));
+     Status = EFI_UNSUPPORTED;
+     goto Exit;
+  }
+
+  CardData->CardType = SdMemoryCard;
+  if (SdCommand8Support == TRUE) {
+   CardData->CardType = SdMemoryCard2;
+   DEBUG ((EFI_D_INFO, "SD_SEND_OP_COND, SD 2.0 or above standard card was identified\n"));
+  }
+
+  if ((CardData->OCRRegister.AccessMode & BIT1) == BIT1) {
+    CardData->CardType = SdMemoryCard2High;
+    DEBUG ((EFI_D_INFO, "SD_SEND_OP_COND, SD 2.0 or above high capacity card was identified\n"));
+  }
+
+Exit:
+  return Status;
+}
+
+
+/**
+  MMC card high/low voltage selection function
+
+  @param[in]  CardData               Pointer to CARD_DATA.
+
+  @retval     EFI_SUCCESS
+  @retval     EFI_INVALID_PARAMETER
+  @retval     EFI_UNSUPPORTED
+  @retval     EFI_BAD_BUFFER_SIZE
+
+**/
+EFI_STATUS
+MMCCardVoltageSelection (
+  IN  CARD_DATA              *CardData
+  )
+{
+  EFI_STATUS                 Status;
+  UINT8                      Retry;
+  UINT32                     TimeOut;
+
+  Status = EFI_SUCCESS;
+
+  //
+  // First try the high voltage, then if supported choose the low voltage
+  //
+  for (Retry = 0; Retry < 3; Retry++) {
+    //
+    // To bring back the normal MMC card to work
+    // after sending the SD command. Otherwise some
+    // card could not work
+
+    Status  = SendCommand (
+                CardData,
+                GO_IDLE_STATE,
+                0,
+                NoData,
+                NULL,
+                0,
+                ResponseNo,
+                TIMEOUT_COMMAND,
+                NULL
+                );
+
+    if (EFI_ERROR (Status)) {
+      DEBUG ((EFI_D_ERROR, "GO_IDLE_STATE Fail Status = 0x%x\n", Status));
+      continue;
+    }
+    //
+    //CE-ATA device needs long delay
+    //
+    gBS->Stall ((Retry + 1) * 50 * 1000);
+
+    //
+    // Get OCR register to check voltage support, first time the OCR is 0
+    //
+    Status  = SendCommand (
+                CardData,
+                SEND_OP_COND,
+                0,
+                NoData,
+                NULL,
+                0,
+                ResponseR3,
+                TIMEOUT_COMMAND,
+                (UINT32 *) &(CardData->OCRRegister)
+                );
+
+    if (!EFI_ERROR (Status)) {
+      break;
+    }
+  }
+
+  if (Retry == 3) {
+    DEBUG ((EFI_D_ERROR, "SEND_OP_COND Fail Status = 0x%x\n", Status));
+    Status = EFI_DEVICE_ERROR;
+    goto Exit;
+  }
+
+  //
+  // TimeOut Value, 5000 * 100 * 1000 = 5 s
+  //
+  TimeOut = 5000;
+
+  do {
+    Status  = SendCommand (
+                CardData,
+                SEND_OP_COND,
+                0x40300000,
+                NoData,
+                NULL,
+                0,
+                ResponseR3,
+                TIMEOUT_COMMAND,
+                (UINT32 *) &(CardData->OCRRegister)
+                );
+
+    if (EFI_ERROR (Status)) {
+      DEBUG ((EFI_D_ERROR, "SEND_OP_COND Fail Status = 0x%x\n", Status));
+      goto Exit;
+    }
+
+    gBS->Stall (1 * 1000);
+    TimeOut--;
+    if (TimeOut == 0) {
+      Status = EFI_TIMEOUT;
+      DEBUG ((EFI_D_ERROR, "Card is always in busy state\n"));
+      goto Exit;
+    }
+  } while (CardData->OCRRegister.Busy != 1);
+
+  if (CardData->OCRRegister.AccessMode == 2) {
+    DEBUG ((EFI_D_INFO, "eMMC Card is High Capacity\n"));
+    CardData->CardType = MMCCardHighCap;
+  }
+
+Exit:
+  return Status;
+}
+
+
+/**
+  This function set the bus and device width for MMC card.
+
+  @param[in]  CardData               Pointer to CARD_DATA.
+  @param[in]  BusWidth               1, 4, 8 bits.
+  @param[in]  EnableDDRMode          Enable DDR Mode.
+
+  @retval     EFI_SUCCESS
+  @retval     EFI_UNSUPPORTED
+  @retval     EFI_INVALID_PARAMETER
+
+**/
+EFI_STATUS
+MMCCardSetBusWidth (
+  IN  CARD_DATA              *CardData,
+  IN  UINT8                  BusWidth,
+  IN  BOOLEAN                EnableDDRMode
+  )
+{
+  EFI_STATUS                 Status;
+  EFI_SD_HOST_IO_PROTOCOL    *SdHostIo;
+  SWITCH_ARGUMENT            SwitchArgument;
+  UINT8                      Value;
+
+  SdHostIo = CardData->SdHostIo;
+  Value = 0;
+  switch (BusWidth) {
+    case 8:
+      if (EnableDDRMode)
+        Value = 6;
+      else
+      Value = 2;
+      break;
+
+    case 4:
+      if (EnableDDRMode)
+        Value = 5;
+      else
+      Value = 1;
+      break;
+
+    case 1:
+      if (EnableDDRMode)    // Bus width 1 is not supported in ddr mode
+        return EFI_UNSUPPORTED;
+      Value = 0;
+      break;
+
+    default:
+     ASSERT (0);
+  }
+
+  ZeroMem (&SwitchArgument, sizeof (SWITCH_ARGUMENT));
+  SwitchArgument.CmdSet = 0;
+  SwitchArgument.Value  = Value;
+  SwitchArgument.Index  = (UINT32) ((UINTN)
+  (&(CardData->ExtCSDRegister.BUS_WIDTH)) - (UINTN) (&(CardData->ExtCSDRegister)));
+  SwitchArgument.Access = WriteByte_Mode;
+  Status  = SendCommand (
+              CardData,
+              SWITCH,
+              *(UINT32 *) &SwitchArgument,
+              NoData,
+              NULL,
+              0,
+              ResponseR1b,
+              TIMEOUT_COMMAND,
+              (UINT32 *) &(CardData->CardStatus)
+              );
+
+  if (!EFI_ERROR (Status)) {
+     Status  = SendCommand (
+                 CardData,
+                 SEND_STATUS,
+                 (CardData->Address << 16),
+                 NoData,
+                 NULL,
+                 0,
+                 ResponseR1,
+                 TIMEOUT_COMMAND,
+                 (UINT32 *) &(CardData->CardStatus)
+                 );
+
+    if (EFI_ERROR (Status)) {
+      DEBUG ((EFI_D_ERROR, "SWITCH %d bits Fail\n", BusWidth));
+      goto Exit;
+    } else {
+      DEBUG ((EFI_D_ERROR, "MMCCardSetBusWidth:SWITCH Card Status:0x%x\n", *(UINT32 *) &(CardData->CardStatus)));
+      Status = SdHostIo->SetBusWidth (SdHostIo, BusWidth);
+      if (EFI_ERROR (Status)) {
+         DEBUG ((EFI_D_ERROR, "SWITCH set %d bits Fail\n", BusWidth));
+         goto Exit;
+      }
+      gBS->Stall (5 * 1000);
+    }
+  }
+
+  if (!EnableDDRMode) {     // CMD19 and CMD14 are illegal commands in ddr mode
+
+  Status = MMCCardBusWidthTest (CardData, BusWidth);
+  if (EFI_ERROR (Status)) {
+    DEBUG ((EFI_D_ERROR, "MMCCardBusWidthTest %d bit Fail\n", BusWidth));
+    goto Exit;
+    }
+  }
+
+  CardData->CurrentBusWidth = BusWidth;
+
+Exit:
+  return Status;
+}
+
+
+/**
+  MMC/SD card init function
+
+  @param[in]  CardData             Pointer to CARD_DATA.
+
+  @retval     EFI_SUCCESS
+  @retval     others
+
+**/
+EFI_STATUS
+MMCSDCardInit (
+  IN  CARD_DATA              *CardData
+  )
+{
+  EFI_STATUS                 Status;
+  EFI_SD_HOST_IO_PROTOCOL    *SdHostIo;
+  SWITCH_ARGUMENT            SwitchArgument;
+  UINT32                     Data;
+  UINT32                     Argument;
+  UINT32                     nIndex;
+  UINT8                      PowerValue;
+  BOOLEAN                    EnableDDRMode;
+
+  ASSERT (CardData != NULL);
+  SdHostIo = CardData->SdHostIo;
+  EnableDDRMode = FALSE;
+
+  CardData->CardType = UnknownCard;
+  Status = GetCardType (CardData);
+  if (EFI_ERROR (Status)) {
+    goto Exit;
+  }
+  DEBUG ((DEBUG_INFO, "CardData->CardType  0x%x\n", CardData->CardType));
+
+  ASSERT (CardData->CardType != UnknownCard);
+
+  //
+  // MMC, SD card need host auto stop command support
+  //
+  SdHostIo->EnableAutoStopCmd (SdHostIo, TRUE);
+
+  if (CardData->CardType == MMCCard) {
+    Status = MMCCardVoltageSelection (CardData);
+    if (EFI_ERROR (Status)) {
+      goto Exit;
+    }
+  }
+
+  //
+  // Get CID Register
+  //
+  Status  = SendCommand (
+              CardData,
+              ALL_SEND_CID,
+              0,
+              NoData,
+              NULL,
+              0,
+              ResponseR2,
+              TIMEOUT_COMMAND,
+              (UINT32 *) &(CardData->CIDRegister)
+              );
+
+  if (EFI_ERROR (Status)) {
+    DEBUG ((EFI_D_ERROR, "ALL_SEND_CID Fail Status = 0x%x\n", Status));
+    goto Exit;
+  } else {
+    //
+    // Dump out the Card ID data
+    //
+    DEBUG ((EFI_D_INFO, "Product Name: "));
+    for (nIndex=0; nIndex<6; nIndex++ ) {
+      DEBUG ((EFI_D_INFO, "%c", CardData->CIDRegister.PNM[nIndex]));
+    }
+    DEBUG ((EFI_D_INFO, "\nApplication ID : %d\n", CardData->CIDRegister.OID));
+    DEBUG ((EFI_D_INFO, "Manufacturer ID  : %d\n", CardData->CIDRegister.MID));
+    DEBUG ((EFI_D_INFO, "Revision ID      : %d\n", CardData->CIDRegister.PRV));
+    DEBUG ((EFI_D_INFO, "Serial Number    : %d\n", CardData->CIDRegister.PSN));
+  }
+
+  //
+  // SET_RELATIVE_ADDR
+  //
+  if (CardData->CardType == MMCCard  || CardData->CardType == MMCCardHighCap) {
+    //
+    // Hard code the RCA address
+    //
+    CardData->Address = 1;
+
+    //
+    // Set RCA Register
+    //
+    Status  = SendCommand (
+                CardData,
+                SET_RELATIVE_ADDR,
+                (CardData->Address << 16),
+                NoData,
+                NULL,
+                0,
+                ResponseR1,
+                TIMEOUT_COMMAND,
+                (UINT32 *) &(CardData->CardStatus)
+                );
+
+    if (EFI_ERROR (Status)) {
+      DEBUG ((EFI_D_ERROR, "SET_RELATIVE_ADDR Fail Status = 0x%x\n", Status));
+      goto Exit;
+    }
+  } else {
+    Data = 0;
+    Status  = SendCommand (
+                CardData,
+                SET_RELATIVE_ADDR,
+                0,
+                NoData,
+                NULL,
+                0,
+                ResponseR6,
+                TIMEOUT_COMMAND,
+                &Data
+                );
+
+    if (EFI_ERROR (Status)) {
+      DEBUG ((EFI_D_ERROR, "SET_RELATIVE_ADDR Fail Status = 0x%x\n", Status));
+      goto Exit;
+    }
+
+    CardData->Address = (UINT16) (Data >> 16);
+    *(UINT32 *) &CardData->CardStatus      = Data & 0x1FFF;
+    CardData->CardStatus.ERROR             = (Data >> 13) & 0x1;
+    CardData->CardStatus.ILLEGAL_COMMAND   = (Data >> 14) & 0x1;
+    CardData->CardStatus.COM_CRC_ERROR     = (Data >> 15) & 0x1;
+    Status = CheckCardStatus (*(UINT32 *) &CardData->CardStatus);
+    if (EFI_ERROR (Status)) {
+      DEBUG ((EFI_D_ERROR, "SET_RELATIVE_ADDR Fail Status = 0x%x\n", Status));
+      goto Exit;
+    }
+  }
+
+  //
+  // Get CSD Register
+  //
+  Status  = SendCommand (
+              CardData,
+              SEND_CSD,
+              (CardData->Address << 16),
+              NoData,
+              NULL,
+              0,
+              ResponseR2,
+              TIMEOUT_COMMAND,
+              (UINT32 *) &(CardData->CSDRegister)
+              );
+
+  if (EFI_ERROR (Status)) {
+    DEBUG ((EFI_D_ERROR, "SEND_CSD Fail Status = 0x%x\n", Status));
+    goto Exit;
+  }
+
+  DEBUG ((EFI_D_INFO, "CardData->CSDRegister.SPEC_VERS = 0x%x\n", CardData->CSDRegister.SPEC_VERS));
+  DEBUG ((EFI_D_INFO, "CardData->CSDRegister.CSD_STRUCTURE = 0x%x\n", CardData->CSDRegister.CSD_STRUCTURE));
+
+  Status = CaculateCardParameter (CardData);
+  if (EFI_ERROR (Status)) {
+    goto Exit;
+  }
+
+
+  //
+  // It is platform and hardware specific, need hadrware engineer input
+  //
+  if (CardData->CSDRegister.DSR_IMP == 1) {
+    //
+    // Default is 0x404
+    //
+    Status  = SendCommand (
+                CardData,
+                SET_DSR,
+                (DEFAULT_DSR_VALUE << 16),
+                NoData,
+                NULL,
+                0,
+                ResponseNo,
+                TIMEOUT_COMMAND,
+                NULL
+                );
+
+    if (EFI_ERROR (Status)) {
+      DEBUG ((EFI_D_ERROR, "SET_DSR Fail Status = 0x%x\n", Status));
+      //
+      // Assume can operate even fail
+      //
+    }
+  }
+  //
+  // Change clock frequency from 400KHz to max supported when not in high speed mode
+  //
+  Status = SdHostIo->SetClockFrequency (SdHostIo, CardData->MaxFrequency);
+  if (EFI_ERROR (Status)) {
+    DEBUG ((EFI_D_ERROR, "MMCSDCardInit:Fail to SetClockFrequency \n"));
+    goto Exit;
+  }
+
+  //
+  // Put the card into tran state
+  //
+  Status = SendCommand (
+             CardData,
+             SELECT_DESELECT_CARD,
+             (CardData->Address << 16),
+             NoData,
+             NULL,
+             0,
+             ResponseR1,
+             TIMEOUT_COMMAND,
+             (UINT32 *) &(CardData->CardStatus)
+             );
+
+  if (EFI_ERROR (Status)) {
+    DEBUG ((EFI_D_ERROR, "SELECT_DESELECT_CARD Fail Status = 0x%x\n", Status));
+    goto Exit;
+  }
+  gBS->Stall (5 * 1000);
+  //
+  // No need to do so
+  //
+  //
+  Status  = SendCommand (
+              CardData,
+              SEND_STATUS,
+              (CardData->Address << 16),
+              NoData,
+              NULL,
+              0,
+              ResponseR1,
+              TIMEOUT_COMMAND,
+              (UINT32 *) &(CardData->CardStatus)
+              );
+
+  if (EFI_ERROR (Status)) {
+    DEBUG ((EFI_D_ERROR, "SELECT_DESELECT_CARD SEND_STATUS Fail Status = 0x%x\n", Status));
+    goto Exit;
+  }
+  if (CardData->CardType == MMCCard  || CardData->CardType == MMCCardHighCap) {
+    //
+    // Only V4.0 and above supports more than 1 bits and high speed
+    //
+    if (CardData->CSDRegister.SPEC_VERS >= 4) {
+      //
+      // Get ExtCSDRegister
+      //
+      Status  = SendCommand (
+                  CardData,
+                  SEND_EXT_CSD,
+                  0x0,
+                  InData,
+                  CardData->AlignedBuffer,
+                  sizeof (EXT_CSD),
+                  ResponseR1,
+                  TIMEOUT_DATA,
+                  (UINT32 *) &(CardData->CardStatus)
+                  );
+
+      if (EFI_ERROR (Status)) {
+        DEBUG ((EFI_D_ERROR, "SEND_EXT_CSD Fail Status = 0x%x\n", Status));
+        goto Exit;
+      }
+
+      CopyMem (&(CardData->ExtCSDRegister), CardData->AlignedBuffer, sizeof(EXT_CSD));
+
+      //
+      // Recaculate the block number for >2G MMC card
+      //
+      Data  = (CardData->ExtCSDRegister.SEC_COUNT[0]) |
+              (CardData->ExtCSDRegister.SEC_COUNT[1] << 8) |
+              (CardData->ExtCSDRegister.SEC_COUNT[2] << 16) |
+              (CardData->ExtCSDRegister.SEC_COUNT[3] << 24);
+
+      if (Data != 0) {
+        CardData->BlockNumber = Data;
+      }
+      DEBUG ((DEBUG_INFO, "CardData->BlockNumber  %d\n", Data));
+      DEBUG ((EFI_D_ERROR, "CardData->ExtCSDRegister.CARD_TYPE -> %d\n", (UINTN)CardData->ExtCSDRegister.CARD_TYPE));
+      if ((CardData->ExtCSDRegister.CARD_TYPE & BIT2)||
+          (CardData->ExtCSDRegister.CARD_TYPE & BIT3)) {
+
+      }
+      //
+      // Check current chipset capability and the plugged-in card
+      // whether supports HighSpeed
+      //
+      if (SdHostIo->HostCapability.HighSpeedSupport) {
+
+        //
+        // Change card timing to high speed interface timing
+        //
+        ZeroMem (&SwitchArgument, sizeof (SWITCH_ARGUMENT));
+        SwitchArgument.CmdSet = 0;
+        SwitchArgument.Value  = 1;
+        SwitchArgument.Index  = (UINT32) ((UINTN)
+        (&(CardData->ExtCSDRegister.HS_TIMING)) - (UINTN) (&(CardData->ExtCSDRegister)));
+        SwitchArgument.Access = WriteByte_Mode;
+        Status  = SendCommand (
+                    CardData,
+                    SWITCH,
+                    *(UINT32 *) &SwitchArgument,
+                    NoData,
+                    NULL,
+                    0,
+                    ResponseR1b,
+                    TIMEOUT_COMMAND,
+                    (UINT32 *) &(CardData->CardStatus)
+                    );
+
+        if (EFI_ERROR (Status)) {
+          DEBUG ((EFI_D_ERROR, "MMCSDCardInit:SWITCH frequency Fail Status = 0x%x\n", Status));
+        }
+
+        gBS->Stall (5 * 1000);
+
+        if (!EFI_ERROR (Status)) {
+          Status  = SendCommand (
+                      CardData,
+                      SEND_STATUS,
+                      (CardData->Address << 16),
+                      NoData,
+                      NULL,
+                      0,
+                      ResponseR1,
+                      TIMEOUT_COMMAND,
+                      (UINT32 *) &(CardData->CardStatus)
+                      );
+
+          if (!EFI_ERROR (Status)) {
+            if (EnableDDRMode) {
+              DEBUG ((EFI_D_ERROR, "Enable ddr mode on host controller\n"));
+              SdHostIo->SetDDRMode (SdHostIo, TRUE);
+            } else  {
+              DEBUG ((EFI_D_ERROR, "Enable high speed mode on host controller\n"));
+              SdHostIo->SetHighSpeedMode (SdHostIo, TRUE);
+            }
+            //
+            // Change host clock to support high speed and enable chispet to
+            // support speed
+            //
+            if ((CardData->ExtCSDRegister.CARD_TYPE & BIT1) != 0) {
+              Status = SdHostIo->SetClockFrequency (SdHostIo, FREQUENCY_MMC_PP_HIGH);
+            } else if ((CardData->ExtCSDRegister.CARD_TYPE & BIT0) != 0) {
+              Status = SdHostIo->SetClockFrequency (SdHostIo, FREQUENCY_MMC_PP);
+            } else {
+              Status = EFI_UNSUPPORTED;
+            }
+            if (EFI_ERROR (Status)) {
+              DEBUG ((EFI_D_ERROR, "MMCSDCardInit:Fail to SetClockFrequency \n"));
+              goto Exit;
+            }
+            //
+            // It seems no need to stall after changing bus freqeuncy.
+            // It is said that the freqeuncy can be changed at any time. Just appends 8 clocks after command.
+            // But SetClock alreay has delay.
+            //
+          }
+        }
+
+      }
+
+      //
+      // Prefer wide bus width for performance
+      //
+      //
+      // Set to BusWidth bits mode, only version 4.0 or above support more than 1 bits
+      //
+      if (SdHostIo->HostCapability.BusWidth8 == TRUE) {
+         Status = MMCCardSetBusWidth (CardData, 8, EnableDDRMode);
+         if (EFI_ERROR (Status)) {
+            //
+            // CE-ATA may support 8 bits and 4 bits, but has no software method for detection
+            //
+            Status = MMCCardSetBusWidth (CardData, 4, EnableDDRMode);
+            if (EFI_ERROR (Status)) {
+              goto Exit;
+            }
+         }
+      } else if (SdHostIo->HostCapability.BusWidth4 == TRUE) {
+         Status = MMCCardSetBusWidth (CardData, 4, EnableDDRMode);
+         if (EFI_ERROR (Status)) {
+           goto Exit;
+         }
+      }
+
+      PowerValue = 0;
+
+      if (CardData->CurrentBusWidth == 8) {
+        if ((CardData->ExtCSDRegister.CARD_TYPE & BIT1) != 0) {
+          PowerValue = CardData->ExtCSDRegister.PWR_CL_52_360;
+          PowerValue = PowerValue >> 4;
+        } else if ((CardData->ExtCSDRegister.CARD_TYPE & BIT0) != 0) {
+          PowerValue = CardData->ExtCSDRegister.PWR_CL_26_360;
+          PowerValue = PowerValue >> 4;
+        }
+      } else if (CardData->CurrentBusWidth == 4) {
+         if ((CardData->ExtCSDRegister.CARD_TYPE & BIT1) != 0) {
+          PowerValue = CardData->ExtCSDRegister.PWR_CL_52_360;
+          PowerValue = PowerValue & 0xF;
+         } else if ((CardData->ExtCSDRegister.CARD_TYPE & BIT0) != 0) {
+           PowerValue = CardData->ExtCSDRegister.PWR_CL_26_360;
+           PowerValue = PowerValue & 0xF;
+         }
+      }
+
+      if (PowerValue != 0) {
+        //
+        // Update Power Class
+        //
+        ZeroMem (&SwitchArgument, sizeof (SWITCH_ARGUMENT));
+        SwitchArgument.CmdSet = 0;
+        SwitchArgument.Value  = PowerValue;
+        SwitchArgument.Index  = (UINT32) ((UINTN)
+        (&(CardData->ExtCSDRegister.POWER_CLASS)) - (UINTN) (&(CardData->ExtCSDRegister)));
+        SwitchArgument.Access = WriteByte_Mode;
+        Status  = SendCommand (
+                    CardData,
+                    SWITCH,
+                    *(UINT32 *) &SwitchArgument,
+                    NoData,
+                    NULL,
+                    0,
+                    ResponseR1b,
+                    TIMEOUT_COMMAND,
+                    (UINT32 *) &(CardData->CardStatus)
+                    );
+
+         if (!EFI_ERROR (Status)) {
+           Status  = SendCommand (
+                       CardData,
+                       SEND_STATUS,
+                       (CardData->Address << 16),
+                       NoData,
+                       NULL,
+                       0,
+                       ResponseR1,
+                       TIMEOUT_COMMAND,
+                       (UINT32 *) &(CardData->CardStatus)
+                       );
+
+           if (EFI_ERROR (Status)) {
+             DEBUG ((EFI_D_ERROR, "SWITCH Power Class Fail Status = 0x%x\n", Status));
+           }
+         }
+      }
+
+    } else {
+      DEBUG ((EFI_D_ERROR, "MMC Card version %d only supportes 1 bits at lower transfer speed\n",CardData->CSDRegister.SPEC_VERS));
+    }
+  } else {
+      //
+      // Pin 1, at power up this line has a 50KOhm pull up enabled in the card.
+      // This pull-up should be disconnected by the user, during regular data transfer,
+      // with SET_CLR_CARD_DETECT (ACMD42) command
+      //
+      Status  = SendAppCommand (
+                  CardData,
+                  SET_CLR_CARD_DETECT,
+                  0,
+                  NoData,
+                  NULL,
+                  0,
+                  ResponseR1,
+                  TIMEOUT_COMMAND,
+                  (UINT32 *) &(CardData->CardStatus)
+                  );
+
+      if (EFI_ERROR (Status)) {
+        DEBUG ((EFI_D_ERROR, "SET_CLR_CARD_DETECT Fail Status = 0x%x\n", Status));
+        goto Exit;
+      }
+
+      //
+      // Set Bus Width to 4
+      //
+      Status  = SendAppCommand (
+                  CardData,
+                  SET_BUS_WIDTH,
+                  SD_BUS_WIDTH_4,
+                  NoData,
+                  NULL,
+                  0,
+                  ResponseR1,
+                  TIMEOUT_COMMAND,
+                  (UINT32 *) &(CardData->CardStatus)
+                  );
+
+      if (EFI_ERROR (Status)) {
+        DEBUG ((EFI_D_ERROR, "SET_BUS_WIDTH 4 bits Fail Status = 0x%x\n", Status));
+        goto Exit;
+      }
+
+      Status = SdHostIo->SetBusWidth (SdHostIo, 4);
+      if (EFI_ERROR (Status)) {
+        goto Exit;
+      }
+      CardData->CurrentBusWidth = 4;
+
+      if ((SdHostIo->HostCapability.HighSpeedSupport == FALSE) ||
+          ((CardData->CSDRegister.CCC & BIT10) != BIT10)) {
+        //
+        // Host must support high speed
+        // Card must support Switch function
+        //
+        goto Exit;
+      }
+
+      //
+      // Mode = 0, group 1, function 1, check operation
+      //
+      Argument = 0xFFFF01;
+      ZeroMem (&CardData->SwitchStatus, sizeof (SWITCH_STATUS));
+
+      Status  = SendCommand (
+                  CardData,
+                  SWITCH_FUNC,
+                  Argument,
+                  InData,
+                  CardData->AlignedBuffer,
+                  sizeof (SWITCH_STATUS),
+                  ResponseR1,
+                  TIMEOUT_COMMAND,
+                  (UINT32 *) &(CardData->CardStatus)
+                  );
+
+      if (EFI_ERROR (Status)) {
+        goto Exit;
+      }
+      CopyMem (&(CardData->SwitchStatus), CardData->AlignedBuffer, sizeof (SWITCH_STATUS));
+
+      if ((CardData->SwitchStatus.DataStructureVersion == 0x0) ||
+          ((CardData->SwitchStatus.Group1BusyStatus & BIT1) != BIT1)) {
+        Argument = 0xFFFF01 | BIT31;
+        ZeroMem (&CardData->SwitchStatus, sizeof (SWITCH_STATUS));
+
+        Status  = SendCommand (
+                    CardData,
+                    SWITCH_FUNC,
+                    Argument,
+                    InData,
+                    CardData->AlignedBuffer,
+                    sizeof (SWITCH_STATUS),
+                    ResponseR1,
+                    TIMEOUT_COMMAND,
+                   (UINT32 *) &(CardData->CardStatus)
+                   );
+
+         if (EFI_ERROR (Status)) {
+            goto Exit;
+         }
+         CopyMem (&(CardData->SwitchStatus), CardData->AlignedBuffer, sizeof (SWITCH_STATUS));
+
+         if ((CardData->SwitchStatus.DataStructureVersion == 0x0) ||
+            ((CardData->SwitchStatus.Group1BusyStatus & BIT1) != BIT1)) {
+          gBS->Stall (1000);
+
+          //
+          // Change host clock
+          //
+          Status = SdHostIo->SetClockFrequency (SdHostIo, FREQUENCY_SD_PP_HIGH);
+          if (EFI_ERROR (Status)) {
+            goto Exit;
+          }
+
+         }
+      }
+  }
+  if (!((CardData->ExtCSDRegister.CARD_TYPE & BIT2) ||
+      (CardData->ExtCSDRegister.CARD_TYPE & BIT3))) {
+
+    //
+    // Set Block Length, to improve compatibility in case of some cards
+    //
+    Status  = SendCommand (
+                CardData,
+                SET_BLOCKLEN,
+                512,
+                NoData,
+                NULL,
+                0,
+                ResponseR1,
+                TIMEOUT_COMMAND,
+                (UINT32 *) &(CardData->CardStatus)
+                );
+
+    if (EFI_ERROR (Status)) {
+      DEBUG ((EFI_D_ERROR, "SET_BLOCKLEN Fail Status = 0x%x\n", Status));
+      goto Exit;
+    }
+  }
+  SdHostIo->SetBlockLength (SdHostIo, 512);
+
+Exit:
+  return Status;
+}
+
diff --git a/Silicon/BroxtonSoC/BroxtonSiPkg/SouthCluster/Sdio/Dxe/SD/SdMediaDeviceDxe/SdMediaDevice.c b/Silicon/BroxtonSoC/BroxtonSiPkg/SouthCluster/Sdio/Dxe/SD/SdMediaDeviceDxe/SdMediaDevice.c
new file mode 100644
index 0000000..ad0eb2c
--- /dev/null
+++ b/Silicon/BroxtonSoC/BroxtonSiPkg/SouthCluster/Sdio/Dxe/SD/SdMediaDeviceDxe/SdMediaDevice.c
@@ -0,0 +1,324 @@
+/** @file
+  The definition for SD media device driver model and blkio protocol routines.
+
+  Copyright (c) 2013 - 2016, Intel Corporation. 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 "SdMediaDevice.h"
+
+EFI_DRIVER_BINDING_PROTOCOL gSdMediaDeviceDriverBinding = {
+  SdMediaDeviceSupported,
+  SdMediaDeviceStart,
+  SdMediaDeviceStop,
+  0x20,
+  NULL,
+  NULL
+};
+
+
+/**
+  Entry point for EFI drivers.
+
+  @param[in]  ImageHandle      EFI_HANDLE.
+  @param[in]  SystemTable      EFI_SYSTEM_TABLE.
+
+  @retval     EFI_SUCCESS      Driver is successfully loaded.
+  @retval     Others           Failed.
+
+**/
+EFI_STATUS
+EFIAPI
+InitializeSdMediaDevice (
+  IN EFI_HANDLE           ImageHandle,
+  IN EFI_SYSTEM_TABLE     *SystemTable
+  )
+{
+  return EfiLibInstallDriverBindingComponentName2 (
+           ImageHandle,
+           SystemTable,
+           &gSdMediaDeviceDriverBinding,
+           ImageHandle,
+           &gSdMediaDeviceName,
+           &gSdMediaDeviceName2
+           );
+}
+
+
+/**
+  Test to see if this driver supports ControllerHandle. Any
+  ControllerHandle that has BlockIoProtocol installed will be supported.
+
+  @param[in]  This                 Protocol instance pointer.
+  @param[in]  Controller           Handle of device to test.
+  @param[in]  RemainingDevicePath  Not used.
+
+  @retval     EFI_SUCCESS          This driver supports this device.
+  @retval     EFI_UNSUPPORTED      This driver does not support this device.
+
+**/
+EFI_STATUS
+EFIAPI
+SdMediaDeviceSupported (
+  IN EFI_DRIVER_BINDING_PROTOCOL     *This,
+  IN EFI_HANDLE                      Controller,
+  IN EFI_DEVICE_PATH_PROTOCOL        *RemainingDevicePath
+  )
+{
+  EFI_STATUS                Status;
+  EFI_SD_HOST_IO_PROTOCOL   *SdHostIo;
+
+  //
+  // Test whether there is PCI IO Protocol attached on the controller handle.
+  //
+  Status = gBS->OpenProtocol (
+                  Controller,
+                  &gEfiSdHostIoProtocolGuid,
+                  (VOID **) &SdHostIo,
+                  This->DriverBindingHandle,
+                  Controller,
+                  EFI_OPEN_PROTOCOL_BY_DRIVER
+                  );
+
+  if (EFI_ERROR (Status)) {
+    goto Exit;
+  }
+
+  gBS->CloseProtocol (
+         Controller,
+         &gEfiSdHostIoProtocolGuid,
+         This->DriverBindingHandle,
+         Controller
+         );
+
+Exit:
+  return Status;
+}
+
+
+/**
+  Starting the SD Media Device Driver.
+
+  @param[in]  This                 Protocol instance pointer.
+  @param[in]  Controller           Handle of device to test.
+  @param[in]  RemainingDevicePath  Not used.
+
+  @retval     EFI_SUCCESS          This driver supports this device.
+  @retval     EFI_UNSUPPORTED      This driver does not support this device.
+  @retval     EFI_DEVICE_ERROR     This driver cannot be started due to device Error.
+                                   EFI_OUT_OF_RESOURCES- Failed due to resource shortage.
+
+**/
+EFI_STATUS
+EFIAPI
+SdMediaDeviceStart (
+  IN EFI_DRIVER_BINDING_PROTOCOL     *This,
+  IN EFI_HANDLE                      Controller,
+  IN EFI_DEVICE_PATH_PROTOCOL        *RemainingDevicePath
+  )
+{
+  EFI_STATUS                Status;
+  EFI_SD_HOST_IO_PROTOCOL   *SdHostIo;
+  CARD_DATA                 *CardData;
+
+  CardData = NULL;
+
+  //
+  // Open PCI I/O Protocol and save pointer to open protocol
+  // in private data area.
+  //
+  Status = gBS->OpenProtocol (
+                  Controller,
+                  &gEfiSdHostIoProtocolGuid,
+                  (VOID **) &SdHostIo,
+                  This->DriverBindingHandle,
+                  Controller,
+                  EFI_OPEN_PROTOCOL_BY_DRIVER
+                  );
+
+  if (EFI_ERROR (Status)) {
+    DEBUG ((EFI_D_ERROR, "SDMediaDeviceStart: Fail to open gEfiSdHostIoProtocolGuid \r\n"));
+    goto Exit;
+  }
+
+  Status = SdHostIo->DetectCardAndInitHost (SdHostIo);
+  if (EFI_ERROR (Status)) {
+    DEBUG ((EFI_D_INFO, "SdMediaDeviceStart: Fail to DetectCardAndInitHost \r\n"));
+    goto Exit;
+  }
+
+  CardData = (CARD_DATA *) AllocateZeroPool (sizeof (CARD_DATA));
+  if (CardData == NULL) {
+    Status =  EFI_OUT_OF_RESOURCES;
+    DEBUG ((EFI_D_ERROR, "SdMediaDeviceStart: Fail to AllocateZeroPool(CARD_DATA) \r\n"));
+    goto Exit;
+  }
+
+  ASSERT (SdHostIo->HostCapability.BoundarySize >= 4 * 1024);
+  CardData->RawBufferPointer = (UINT8 *) ((UINTN) DMA_MEMORY_TOP);
+  Status = gBS->AllocatePages (
+                  AllocateMaxAddress,
+                  EfiBootServicesData,
+                  EFI_SIZE_TO_PAGES (2 * SdHostIo->HostCapability.BoundarySize),
+                  (EFI_PHYSICAL_ADDRESS *) (&CardData->RawBufferPointer)
+                  );
+
+  if (CardData->RawBufferPointer == NULL) {
+    DEBUG ((EFI_D_ERROR, "SdMediaDeviceStart: Fail to AllocateZeroPool(2*x) \r\n"));
+    Status = EFI_OUT_OF_RESOURCES;
+    goto Exit;
+  }
+  CardData->AlignedBuffer = CardData->RawBufferPointer - ((UINTN) (CardData->RawBufferPointer) & (SdHostIo->HostCapability.BoundarySize - 1)) + SdHostIo->HostCapability.BoundarySize;
+
+  CardData->Signature = CARD_DATA_SIGNATURE;
+  CardData->SdHostIo  = SdHostIo;
+
+  Status = MMCSDCardInit (CardData);
+  if (EFI_ERROR (Status)) {
+    DEBUG ((EFI_D_ERROR, "SdMediaDeviceStart: Fail to MMCSDCardInit \r\n"));
+    goto Exit;
+  }
+  DEBUG ((EFI_D_INFO, "SdMediaDeviceStart: MMCSDCardInit SuccessFul\n"));
+
+  if (CardData->CardType == CEATACard) {
+    Status = CEATABlockIoInit (CardData);
+  } else {
+    Status = MMCSDBlockIoInit (CardData);
+  }
+
+  if (EFI_ERROR (Status)) {
+    DEBUG ((EFI_D_ERROR, "SdMediaDeviceStart: Fail to BlockIoInit \r\n"));
+    goto Exit;
+  }
+  DEBUG ((EFI_D_INFO, "SdMediaDeviceStart: BlockIo is successfully installed\n"));
+
+  Status = gBS->InstallProtocolInterface (
+                  &Controller,
+                  &gEfiBlockIoProtocolGuid,
+                  EFI_NATIVE_INTERFACE,
+                  &CardData->BlockIo
+                  );
+  if (EFI_ERROR (Status)) {
+    DEBUG ((EFI_D_ERROR, "SdMediaDeviceStart: Fail to install gEfiBlockIoProtocolGuid \r\n"));
+    goto Exit;
+  }
+
+  //
+  // Install the component name protocol
+  //
+  CardData->ControllerNameTable = NULL;
+
+  AddUnicodeString2 (
+    "eng",
+    gSdMediaDeviceName.SupportedLanguages,
+    &CardData->ControllerNameTable,
+    L"MMC/SD Media Device",
+    TRUE
+    );
+
+  AddUnicodeString2 (
+    "en",
+    gSdMediaDeviceName2.SupportedLanguages,
+    &CardData->ControllerNameTable,
+    L"MMC/Sd Media Device",
+    FALSE
+    );
+
+Exit:
+  if (EFI_ERROR (Status)) {
+    DEBUG ((EFI_D_INFO, "SdMediaDeviceStart: End with failure\r\n"));
+    if (CardData != NULL) {
+      if (CardData->RawBufferPointer != NULL) {
+        gBS->FreePages ((EFI_PHYSICAL_ADDRESS) (UINTN) CardData->RawBufferPointer, EFI_SIZE_TO_PAGES (2 * SdHostIo->HostCapability.BoundarySize));
+      }
+      FreePool (CardData);
+    }
+  }
+
+  return Status;
+}
+
+
+/**
+  Stop this driver on ControllerHandle. Support stoping any child handles
+  created by this driver.
+
+  @param[in]  This                 Protocol instance pointer.
+  @param[in]  Controller           Handle of device to stop driver on.
+  @param[in]  NumberOfChildren     Number of Children in the ChildHandleBuffer.
+  @param[in]  ChildHandleBuffer    List of handles for the children we need to stop.
+
+  @retval     EFI_SUCCESS
+  @retval     others
+
+**/
+EFI_STATUS
+EFIAPI
+SdMediaDeviceStop (
+  IN EFI_DRIVER_BINDING_PROTOCOL     *This,
+  IN EFI_HANDLE                      Controller,
+  IN UINTN                           NumberOfChildren,
+  IN EFI_HANDLE                      *ChildHandleBuffer
+  )
+{
+  EFI_STATUS                Status;
+  CARD_DATA                 *CardData;
+  EFI_BLOCK_IO_PROTOCOL     *BlockIo;
+
+  //
+  // First find BlockIo Protocol
+  //
+  Status = gBS->OpenProtocol (
+                  Controller,
+                  &gEfiBlockIoProtocolGuid,
+                  (VOID **) &BlockIo,
+                  This->DriverBindingHandle,
+                  Controller,
+                  EFI_OPEN_PROTOCOL_GET_PROTOCOL
+                  );
+
+  if (EFI_ERROR (Status)) {
+    return Status;
+  }
+
+  CardData  = CARD_DATA_FROM_THIS (BlockIo);
+
+  //
+  // Uninstall Block I/O protocol from the device handle
+  //
+  Status = gBS->UninstallProtocolInterface (
+                  Controller,
+                  &gEfiBlockIoProtocolGuid,
+                  BlockIo
+                  );
+
+  if (EFI_ERROR (Status)) {
+    return Status;
+  }
+
+  if (CardData != NULL) {
+    if (CardData->RawBufferPointer != NULL) {
+      gBS->FreePages ((EFI_PHYSICAL_ADDRESS) (UINTN) CardData->RawBufferPointer, EFI_SIZE_TO_PAGES (2 * CardData->SdHostIo->HostCapability.BoundarySize));
+    }
+    FreeUnicodeStringTable (CardData->ControllerNameTable);
+    FreePool (CardData);
+  }
+
+  gBS->CloseProtocol (
+         Controller,
+         &gEfiSdHostIoProtocolGuid,
+         This->DriverBindingHandle,
+         Controller
+         );
+
+  return EFI_SUCCESS;
+}
+
diff --git a/Silicon/BroxtonSoC/BroxtonSiPkg/SouthCluster/Sdio/Dxe/SD/SdMediaDeviceDxe/SdMediaDevice.h b/Silicon/BroxtonSoC/BroxtonSiPkg/SouthCluster/Sdio/Dxe/SD/SdMediaDeviceDxe/SdMediaDevice.h
new file mode 100644
index 0000000..fe3c4fa
--- /dev/null
+++ b/Silicon/BroxtonSoC/BroxtonSiPkg/SouthCluster/Sdio/Dxe/SD/SdMediaDeviceDxe/SdMediaDevice.h
@@ -0,0 +1,466 @@
+/** @file
+  The definition for SD media device driver model and blkio protocol routines.
+
+  Copyright (c) 2013 - 2016, Intel Corporation. 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 _SD_MEDIA_DEVICE_H_
+#define _SD_MEDIA_DEVICE_H_
+
+#include <Uefi.h>
+#include <Protocol/PciIo.h>
+#include <Protocol/BlockIo.h>
+#include <Library/DebugLib.h>
+#include <Library/BaseMemoryLib.h>
+#include <Library/UefiDriverEntryPoint.h>
+#include <Library/UefiBootServicesTableLib.h>
+#include <Library/UefiLib.h>
+#include <Library/BaseLib.h>
+#include <Library/MemoryAllocationLib.h>
+#include <Library/PcdLib.h>
+#include <IndustryStandard/Pci22.h>
+#include "ComponentName.h"
+#include "SdHostIo.h"
+
+extern EFI_DRIVER_BINDING_PROTOCOL   gSdMediaDeviceDriverBinding;
+extern EFI_COMPONENT_NAME_PROTOCOL   gSdMediaDeviceName;
+extern EFI_COMPONENT_NAME2_PROTOCOL  gSdMediaDeviceName2;
+
+//
+// Define the region of memory used for DMA memory
+//
+#define DMA_MEMORY_TOP          0x0000000001FFFFFFULL
+#define CARD_DATA_SIGNATURE  SIGNATURE_32 ('c', 'a', 'r', 'd')
+
+//
+// Command timeout will be max 100 ms
+//
+#define  TIMEOUT_COMMAND     100
+#define  TIMEOUT_DATA        5000
+
+typedef enum{
+  UnknownCard = 0,
+  MMCCard,                // MMC card
+  MMCCardHighCap,         // MMC Card High Capacity
+  CEATACard,              // CE-ATA device
+  SdMemoryCard,           // SD 1.1 card
+  SdMemoryCard2,          // SD 2.0 or above standard card
+  SdMemoryCard2High       // SD 2.0 or above high capacity card
+} CARD_TYPE;
+
+typedef struct {
+  //
+  // BlockIO
+  //
+  UINTN                     Signature;
+  EFI_BLOCK_IO_PROTOCOL     BlockIo;
+  EFI_BLOCK_IO_MEDIA        BlockIoMedia;
+
+  EFI_SD_HOST_IO_PROTOCOL   *SdHostIo;
+  EFI_UNICODE_STRING_TABLE  *ControllerNameTable;
+  CARD_TYPE                 CardType;
+
+  UINT8                     CurrentBusWidth;
+  BOOLEAN                   DualVoltage;
+  BOOLEAN                   NeedFlush;
+  UINT8                     Reserved[3];
+
+  UINT16                    Address;
+  UINT32                    BlockLen;
+  UINT32                    MaxFrequency;
+  UINT64                    BlockNumber;
+
+  //
+  // Common used
+  //
+  CARD_STATUS               CardStatus;
+  OCR                       OCRRegister;
+  CID                       CIDRegister;
+  CSD                       CSDRegister;
+  EXT_CSD                   ExtCSDRegister;
+  UINT8                     *RawBufferPointer;
+  UINT8                     *AlignedBuffer;
+
+  //
+  // CE-ATA specific
+  //
+  TASK_FILE                 TaskFile;
+  IDENTIFY_DEVICE_DATA      IndentifyDeviceData;
+
+  //
+  //SD specific
+  //
+  SCR                       SCRRegister;
+  SD_STATUS_REG             SdSattus;
+  SWITCH_STATUS             SwitchStatus;
+} CARD_DATA;
+
+#define CARD_DATA_FROM_THIS(a) \
+    CR(a, CARD_DATA, BlockIo, CARD_DATA_SIGNATURE)
+
+/**
+  Test to see if this driver supports ControllerHandle. Any
+  ControllerHandle that has BlockIoProtocol installed will be supported.
+
+  @param[in]  This                 Protocol instance pointer.
+  @param[in]  Controller           Handle of device to test.
+  @param[in]  RemainingDevicePath  Not used.
+
+  @return     EFI_SUCCESS          This driver supports this device.
+  @return     EFI_UNSUPPORTED      This driver does not support this device.
+
+**/
+EFI_STATUS
+EFIAPI
+SdMediaDeviceSupported (
+  IN EFI_DRIVER_BINDING_PROTOCOL     *This,
+  IN EFI_HANDLE                      Controller,
+  IN EFI_DEVICE_PATH_PROTOCOL        *RemainingDevicePath
+  );
+
+/**
+  Starting the SD Media Device Driver.
+
+  @param[in]  This                 Protocol instance pointer.
+  @param[in]  Controller           Handle of device to test.
+  @param[in]  RemainingDevicePath  Not used.
+
+  @retval     EFI_SUCCESS          This driver supports this device.
+  @retval     EFI_UNSUPPORTED      This driver does not support this device.
+  @retval     EFI_DEVICE_ERROR     This driver cannot be started due to device Error.
+                                   EFI_OUT_OF_RESOURCES- Failed due to resource shortage.
+
+**/
+EFI_STATUS
+EFIAPI
+SdMediaDeviceStart (
+  IN EFI_DRIVER_BINDING_PROTOCOL     *This,
+  IN EFI_HANDLE                      Controller,
+  IN EFI_DEVICE_PATH_PROTOCOL        *RemainingDevicePath
+  );
+
+/**
+  Stop this driver on ControllerHandle. Support stoping any child handles
+  created by this driver.
+
+  @param[in]  This                 Protocol instance pointer.
+  @param[in]  Controller           Handle of device to stop driver on.
+  @param[in]  NumberOfChildren     Number of Children in the ChildHandleBuffer.
+  @param[in]  ChildHandleBuffer    List of handles for the children we need to stop.
+
+  @return     EFI_SUCCESS
+  @return     others
+
+**/
+EFI_STATUS
+EFIAPI
+SdMediaDeviceStop (
+  IN EFI_DRIVER_BINDING_PROTOCOL     *This,
+  IN EFI_HANDLE                      Controller,
+  IN UINTN                           NumberOfChildren,
+  IN EFI_HANDLE                      *ChildHandleBuffer
+  );
+
+/**
+  MMC/SD card init function
+
+  @param[in]  CardData             Pointer to CARD_DATA.
+
+  @return     EFI_SUCCESS
+  @return     others
+
+**/
+EFI_STATUS
+MMCSDCardInit (
+  IN  CARD_DATA    *CardData
+  );
+
+/**
+  Send command by using Host IO protocol
+
+  @param[in]  This                  A pointer to the EFI_SD_HOST_IO_PROTOCOL instance.
+  @param[in]  CommandIndex          The command index to set the command index field of command register.
+  @param[in]  Argument              Command argument to set the argument field of command register.
+  @param[in]  DataType              TRANSFER_TYPE, indicates no data, data in or data out.
+  @param[in]  Buffer                Contains the data read from / write to the device.
+  @param[in]  BufferSize            The size of the buffer.
+  @param[in]  ResponseType          RESPONSE_TYPE.
+  @param[in]  TimeOut               Time out value in 1 ms unit.
+  @param[out] ResponseData          Depending on the ResponseType, such as CSD or card status.
+
+  @retval     EFI_SUCCESS
+  @retval     EFI_INVALID_PARAMETER
+  @retval     EFI_UNSUPPORTED
+  @retval     EFI_DEVICE_ERROR
+
+**/
+EFI_STATUS
+SendCommand (
+  IN   CARD_DATA                  *CardData,
+  IN   UINT16                     CommandIndex,
+  IN   UINT32                     Argument,
+  IN   TRANSFER_TYPE              DataType,
+  IN   UINT8                      *Buffer, OPTIONAL
+  IN   UINT32                     BufferSize,
+  IN   RESPONSE_TYPE              ResponseType,
+  IN   UINT32                     TimeOut,
+  OUT  UINT32                     *ResponseData
+  );
+
+/**
+  Send the card APP_CMD command with the following command indicated by CommandIndex
+
+  @param[in]  CardData              Pointer to CARD_DATA.
+  @param[in]  CommandIndex          The command index to set the command index field of command register.
+  @param[in]  Argument              Command argument to set the argument field of command register.
+  @param[in]  DataType              TRANSFER_TYPE, indicates no data, data in or data out.
+  @param[in]  Buffer                Contains the data read from / write to the device.
+  @param[in]  BufferSize            The size of the buffer.
+  @param[in]  ResponseType          RESPONSE_TYPE.
+  @param[in]  TimeOut               Time out value in 1 ms unit.
+  @param[out] ResponseData          Depending on the ResponseType, such as CSD or card status.
+
+  @retval     EFI_SUCCESS
+  @retval     EFI_INVALID_PARAMETER
+  @retval     EFI_UNSUPPORTED
+  @retval     EFI_DEVICE_ERROR
+
+**/
+EFI_STATUS
+SendAppCommand (
+  IN   CARD_DATA                  *CardData,
+  IN   UINT16                     CommandIndex,
+  IN   UINT32                     Argument,
+  IN   TRANSFER_TYPE              DataType,
+  IN   UINT8                      *Buffer, OPTIONAL
+  IN   UINT32                     BufferSize,
+  IN   RESPONSE_TYPE              ResponseType,
+  IN   UINT32                     TimeOut,
+  OUT  UINT32                     *ResponseData
+  );
+
+/**
+  Send the card FAST_IO command
+
+  @param[in]      CardData               Pointer to CARD_DATA.
+  @param[in]      RegisterAddress        Register Address.
+  @param[in, out] RegisterData           Pointer to register Data.
+  @param[in]      Write                  TRUE for write, FALSE for read.
+
+  @retval         EFI_SUCCESS
+  @retval         EFI_UNSUPPORTED
+  @retval         EFI_INVALID_PARAMETER
+  @retval         EFI_DEVICE_ERROR
+
+**/
+EFI_STATUS
+FastIO (
+  IN      CARD_DATA   *CardData,
+  IN      UINT8       RegisterAddress,
+  IN  OUT UINT8       *RegisterData,
+  IN      BOOLEAN     Write
+  );
+
+/**
+  Judge whether it is CE-ATA device or not.
+
+  @param[in]  CardData             Pointer to CARD_DATA.
+
+  @retval     TRUE
+  @retval     FALSE
+
+**/
+BOOLEAN
+IsCEATADevice (
+  IN  CARD_DATA    *CardData
+  );
+
+/**
+  Send software reset
+
+  @param[in]  CardData                   Pointer to CARD_DATA.
+
+  @retval     EFI_SUCCESS                Success
+  @retval     EFI_DEVICE_ERROR           Hardware Error
+  @retval     EFI_INVALID_PARAMETER      Parameter is error
+  @retval     EFI_NO_MEDIA               No media
+  @retval     EFI_MEDIA_CHANGED          Media Change
+  @retval     EFI_BAD_BUFFER_SIZE        Buffer size is bad
+
+**/
+EFI_STATUS
+SoftwareReset (
+  IN  CARD_DATA    *CardData
+  );
+
+/**
+  SendATACommand specificed in Taskfile
+
+  @param[in]  CardData                  Pointer to CARD_DATA.
+  @param[in]  TaskFile                  Pointer to TASK_FILE.
+  @param[in]  Write                     TRUE means write, FALSE means read.
+  @param[in]  Buffer                    If NULL, means no data transfer, neither read nor write.
+  @param[in]  SectorCount               Buffer size in 512 bytes unit.
+
+  @retval     EFI_SUCCESS                Success
+  @retval     EFI_DEVICE_ERROR           Hardware Error
+  @retval     EFI_INVALID_PARAMETER      Parameter is error
+  @retval     EFI_NO_MEDIA               No media
+  @retval     EFI_MEDIA_CHANGED          Media Change
+  @retval     EFI_BAD_BUFFER_SIZE        Buffer size is bad
+
+**/
+EFI_STATUS
+SendATACommand (
+  IN  CARD_DATA   *CardData,
+  IN  TASK_FILE   *TaskFile,
+  IN  BOOLEAN     Write,
+  IN  UINT8       *Buffer,
+  IN  UINT16      SectorCount
+  );
+
+/**
+  IDENTIFY_DEVICE command
+
+  @param[in] CardData                   Pointer to CARD_DATA.
+
+  @retval    EFI_SUCCESS                Success
+  @retval    EFI_DEVICE_ERROR           Hardware Error
+  @retval    EFI_INVALID_PARAMETER      Parameter is error
+  @retval    EFI_NO_MEDIA               No media
+  @retval    EFI_MEDIA_CHANGED          Media Change
+  @retval    EFI_BAD_BUFFER_SIZE        Buffer size is bad
+
+**/
+EFI_STATUS
+IndentifyDevice (
+  IN  CARD_DATA    *CardData
+  );
+
+/**
+  FLUSH_CACHE_EXT command
+
+  @param[in]  CardData                   Pointer to CARD_DATA.
+
+  @retval     EFI_SUCCESS                Success
+  @retval     EFI_DEVICE_ERROR           Hardware Error
+  @retval     EFI_INVALID_PARAMETER      Parameter is error
+  @retval     EFI_NO_MEDIA               No media
+  @retval     EFI_MEDIA_CHANGED          Media Change
+  @retval     EFI_BAD_BUFFER_SIZE        Buffer size is bad
+
+**/
+EFI_STATUS
+FlushCache (
+  IN  CARD_DATA    *CardData
+  );
+
+/**
+  STANDBY_IMMEDIATE command
+
+  @param[in]  CardData                   Pointer to CARD_DATA.
+
+  @retval     EFI_SUCCESS                Success
+  @retval     EFI_DEVICE_ERROR           Hardware Error
+  @retval     EFI_INVALID_PARAMETER      Parameter is error
+  @retval     EFI_NO_MEDIA               No media
+  @retval     EFI_MEDIA_CHANGED          Media Change
+  @retval     EFI_BAD_BUFFER_SIZE        Buffer size is bad
+
+**/
+EFI_STATUS
+StandByImmediate (
+  IN  CARD_DATA    *CardData
+  );
+
+/**
+  READ_DMA_EXT command
+
+  @param[in]  CardData                   Pointer to CARD_DATA.
+  @param[in]  LBA                        The starting logical block address to read from on the device.
+  @param[in]  Buffer                     A pointer to the destination buffer for the data. The caller
+                                         is responsible for either having implicit or explicit ownership
+                                         of the buffer.
+  @param[in]  SectorCount                Size in 512 bytes unit.
+
+  @retval     EFI_SUCCESS                Success
+  @retval     EFI_DEVICE_ERROR           Hardware Error
+  @retval     EFI_INVALID_PARAMETER      Parameter is error
+  @retval     EFI_NO_MEDIA               No media
+  @retval     EFI_MEDIA_CHANGED          Media Change
+  @retval     EFI_BAD_BUFFER_SIZE        Buffer size is bad
+
+**/
+EFI_STATUS
+ReadDMAExt (
+  IN  CARD_DATA   *CardData,
+  IN  EFI_LBA     LBA,
+  IN  UINT8       *Buffer,
+  IN  UINT16      SectorCount
+  );
+
+/**
+  WRITE_DMA_EXT command
+
+  @param[in]  CardData                   Pointer to CARD_DATA.
+  @param[in]  LBA                        The starting logical block address to read from on the device.
+  @param[in]  Buffer                     A pointer to the destination buffer for the data. The caller
+                                         is responsible for either having implicit or explicit ownership
+                                         of the buffer.
+  @param[in]  SectorCount                Size in 512 bytes unit.
+
+  @retval     EFI_SUCCESS                Success
+  @retval     EFI_DEVICE_ERROR           Hardware Error
+  @retval     EFI_INVALID_PARAMETER      Parameter is error
+  @retval     EFI_NO_MEDIA               No media
+  @retval     EFI_MEDIA_CHANGED          Media Change
+  @retval     EFI_BAD_BUFFER_SIZE        Buffer size is bad
+
+**/
+EFI_STATUS
+WriteDMAExt (
+  IN  CARD_DATA   *CardData,
+  IN  EFI_LBA     LBA,
+  IN  UINT8       *Buffer,
+  IN  UINT16      SectorCount
+  );
+
+/**
+  CEATA card BlockIo init function.
+
+  @param[in]  CardData               Pointer to CARD_DATA.
+
+  @retval     EFI_SUCCESS
+  @retval     Others
+
+**/
+EFI_STATUS
+CEATABlockIoInit (
+  IN  CARD_DATA    *CardData
+  );
+
+/**
+  MMC/SD card BlockIo init function.
+
+  @param[in]  CardData               Pointer to CARD_DATA.
+
+  @retval     EFI_SUCCESS
+  @retval     Others
+
+**/
+EFI_STATUS
+MMCSDBlockIoInit (
+  IN  CARD_DATA    *CardData
+  );
+
+#endif
+
diff --git a/Silicon/BroxtonSoC/BroxtonSiPkg/SouthCluster/Sdio/Dxe/SD/SdMediaDeviceDxe/SdMediaDeviceDxe.inf b/Silicon/BroxtonSoC/BroxtonSiPkg/SouthCluster/Sdio/Dxe/SD/SdMediaDeviceDxe/SdMediaDeviceDxe.inf
new file mode 100644
index 0000000..e352b1d
--- /dev/null
+++ b/Silicon/BroxtonSoC/BroxtonSiPkg/SouthCluster/Sdio/Dxe/SD/SdMediaDeviceDxe/SdMediaDeviceDxe.inf
@@ -0,0 +1,64 @@
+## @file
+#  Component Description File For SdMediaDeviceDxe Module.
+#
+#  Copyright (c) 2013 - 2016, Intel Corporation. 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                    = 0x00010005
+  BASE_NAME                      = SdMediaDevice
+  FILE_GUID                      = E076205A-6EDC-4F68-A535-93C5D790B1DA
+  MODULE_TYPE                    = UEFI_DRIVER
+  VERSION_STRING                 = 1.0
+  ENTRY_POINT                    = InitializeSdMediaDevice
+
+#
+#  The following information is for reference only and not required by the build tools.
+#
+#  VALID_ARCHITECTURES           = IA32 X64 IPF EBC
+#
+#  DRIVER_BINDING                = gSdMediaDeviceDriverBinding
+#  COMPONENT_NAME                = gSdMediaDeviceName
+#  COMPONENT_NAME2               = gSdMediaDeviceName2
+#
+
+[Sources]
+  SdMediaDevice.c
+  SdMediaDevice.h
+  MMCSDTransfer.c
+  CEATA.c
+  CEATABlockIo.c
+  MMCSDBlockIo.c
+  ComponentName.c
+  ComponentName.h
+
+[Packages]
+  MdePkg/MdePkg.dec
+  MdeModulePkg/MdeModulePkg.dec
+  BroxtonSiPkg/BroxtonSiPkg.dec
+
+[LibraryClasses]
+  MemoryAllocationLib
+  BaseLib
+  UefiLib
+  UefiBootServicesTableLib
+  UefiDriverEntryPoint
+  BaseMemoryLib
+  DebugLib
+  PcdLib
+
+[Protocols]
+  gEfiPciIoProtocolGuid                         ## TO_START
+  gEfiSdHostIoProtocolGuid                      ## TO_START
+  gEfiBlockIoProtocolGuid                       ## BY_START
+
+[Pcd.common]
-- 
2.7.0.windows.1




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

* Re: [Patch][edk2-platforms/devel-MinnowBoard3-UDK2017] Add eMMC/SD.
  2017-06-09  5:26 [Patch][edk2-platforms/devel-MinnowBoard3-UDK2017] Add eMMC/SD lushifex
@ 2017-06-09  5:28 ` Wei, David
  0 siblings, 0 replies; 2+ messages in thread
From: Wei, David @ 2017-06-09  5:28 UTC (permalink / raw)
  To: Lu, ShifeiX A, edk2-devel@lists.01.org

Reviewed-by: zwei4 <david.wei@intel.com> 

Thanks,
David  Wei                                 


-----Original Message-----
From: Lu, ShifeiX A 
Sent: Friday, June 09, 2017 1:26 PM
To: edk2-devel@lists.01.org
Cc: Wei, David <david.wei@intel.com>
Subject: [Patch][edk2-platforms/devel-MinnowBoard3-UDK2017] Add eMMC/SD.

Add Platform eMMC/SD driver.
This reverts commit 66d48af2d24645263b8068e261abc58d84cc2b93.

Contributed-under: TianoCore Contribution Agreement 1.0
Signed-off-by: lushifex <shifeix.a.lu@intel.com>
---
 .../BroxtonPlatformPkg/PlatformDsc/Components.dsc  |   11 +-
 Platform/BroxtonPlatformPkg/PlatformPkg.fdf        |   10 +-
 .../Sdio/Dxe/MMC/MmcHostDxe/ComponentName.c        |  162 ++
 .../Sdio/Dxe/MMC/MmcHostDxe/MmcHostController.c    | 1529 ++++++++++++
 .../Sdio/Dxe/MMC/MmcHostDxe/MmcHostDriver.c        |  613 +++++
 .../Sdio/Dxe/MMC/MmcHostDxe/MmcHostDriver.h        |  585 +++++
 .../Sdio/Dxe/MMC/MmcHostDxe/MmcHostDxe.inf         |   59 +
 .../Sdio/Dxe/MMC/MmcMediaDeviceDxe/ComponentName.c |  159 ++
 .../Sdio/Dxe/MMC/MmcMediaDeviceDxe/MMCSDBlockIo.c  |  666 ++++++
 .../Sdio/Dxe/MMC/MmcMediaDeviceDxe/MMCSDTransfer.c | 2524 ++++++++++++++++++++
 .../Dxe/MMC/MmcMediaDeviceDxe/MediaDeviceDriver.c  |  605 +++++
 .../MMC/MmcMediaDeviceDxe/MmcMediaDeviceDxe.inf    |   71 +
 .../Sdio/Dxe/SD/SdControllerDxe/ComponentName.c    |  233 ++
 .../Sdio/Dxe/SD/SdControllerDxe/ComponentName.h    |  145 ++
 .../Sdio/Dxe/SD/SdControllerDxe/SdController.c     | 1804 ++++++++++++++
 .../Sdio/Dxe/SD/SdControllerDxe/SdController.h     |  314 +++
 .../Dxe/SD/SdControllerDxe/SdControllerDxe.inf     |   59 +
 .../Sdio/Dxe/SD/SdMediaDeviceDxe/CEATA.c           |  638 +++++
 .../Sdio/Dxe/SD/SdMediaDeviceDxe/CEATABlockIo.c    |  384 +++
 .../Sdio/Dxe/SD/SdMediaDeviceDxe/ComponentName.c   |  219 ++
 .../Sdio/Dxe/SD/SdMediaDeviceDxe/ComponentName.h   |  145 ++
 .../Sdio/Dxe/SD/SdMediaDeviceDxe/MMCSDBlockIo.c    |  547 +++++
 .../Sdio/Dxe/SD/SdMediaDeviceDxe/MMCSDTransfer.c   | 1661 +++++++++++++
 .../Sdio/Dxe/SD/SdMediaDeviceDxe/SdMediaDevice.c   |  324 +++
 .../Sdio/Dxe/SD/SdMediaDeviceDxe/SdMediaDevice.h   |  466 ++++
 .../Dxe/SD/SdMediaDeviceDxe/SdMediaDeviceDxe.inf   |   64 +
 26 files changed, 13989 insertions(+), 8 deletions(-)
 create mode 100644 Silicon/BroxtonSoC/BroxtonSiPkg/SouthCluster/Sdio/Dxe/MMC/MmcHostDxe/ComponentName.c
 create mode 100644 Silicon/BroxtonSoC/BroxtonSiPkg/SouthCluster/Sdio/Dxe/MMC/MmcHostDxe/MmcHostController.c
 create mode 100644 Silicon/BroxtonSoC/BroxtonSiPkg/SouthCluster/Sdio/Dxe/MMC/MmcHostDxe/MmcHostDriver.c
 create mode 100644 Silicon/BroxtonSoC/BroxtonSiPkg/SouthCluster/Sdio/Dxe/MMC/MmcHostDxe/MmcHostDriver.h
 create mode 100644 Silicon/BroxtonSoC/BroxtonSiPkg/SouthCluster/Sdio/Dxe/MMC/MmcHostDxe/MmcHostDxe.inf
 create mode 100644 Silicon/BroxtonSoC/BroxtonSiPkg/SouthCluster/Sdio/Dxe/MMC/MmcMediaDeviceDxe/ComponentName.c
 create mode 100644 Silicon/BroxtonSoC/BroxtonSiPkg/SouthCluster/Sdio/Dxe/MMC/MmcMediaDeviceDxe/MMCSDBlockIo.c
 create mode 100644 Silicon/BroxtonSoC/BroxtonSiPkg/SouthCluster/Sdio/Dxe/MMC/MmcMediaDeviceDxe/MMCSDTransfer.c
 create mode 100644 Silicon/BroxtonSoC/BroxtonSiPkg/SouthCluster/Sdio/Dxe/MMC/MmcMediaDeviceDxe/MediaDeviceDriver.c
 create mode 100644 Silicon/BroxtonSoC/BroxtonSiPkg/SouthCluster/Sdio/Dxe/MMC/MmcMediaDeviceDxe/MmcMediaDeviceDxe.inf
 create mode 100644 Silicon/BroxtonSoC/BroxtonSiPkg/SouthCluster/Sdio/Dxe/SD/SdControllerDxe/ComponentName.c
 create mode 100644 Silicon/BroxtonSoC/BroxtonSiPkg/SouthCluster/Sdio/Dxe/SD/SdControllerDxe/ComponentName.h
 create mode 100644 Silicon/BroxtonSoC/BroxtonSiPkg/SouthCluster/Sdio/Dxe/SD/SdControllerDxe/SdController.c
 create mode 100644 Silicon/BroxtonSoC/BroxtonSiPkg/SouthCluster/Sdio/Dxe/SD/SdControllerDxe/SdController.h
 create mode 100644 Silicon/BroxtonSoC/BroxtonSiPkg/SouthCluster/Sdio/Dxe/SD/SdControllerDxe/SdControllerDxe.inf
 create mode 100644 Silicon/BroxtonSoC/BroxtonSiPkg/SouthCluster/Sdio/Dxe/SD/SdMediaDeviceDxe/CEATA.c
 create mode 100644 Silicon/BroxtonSoC/BroxtonSiPkg/SouthCluster/Sdio/Dxe/SD/SdMediaDeviceDxe/CEATABlockIo.c
 create mode 100644 Silicon/BroxtonSoC/BroxtonSiPkg/SouthCluster/Sdio/Dxe/SD/SdMediaDeviceDxe/ComponentName.c
 create mode 100644 Silicon/BroxtonSoC/BroxtonSiPkg/SouthCluster/Sdio/Dxe/SD/SdMediaDeviceDxe/ComponentName.h
 create mode 100644 Silicon/BroxtonSoC/BroxtonSiPkg/SouthCluster/Sdio/Dxe/SD/SdMediaDeviceDxe/MMCSDBlockIo.c
 create mode 100644 Silicon/BroxtonSoC/BroxtonSiPkg/SouthCluster/Sdio/Dxe/SD/SdMediaDeviceDxe/MMCSDTransfer.c
 create mode 100644 Silicon/BroxtonSoC/BroxtonSiPkg/SouthCluster/Sdio/Dxe/SD/SdMediaDeviceDxe/SdMediaDevice.c
 create mode 100644 Silicon/BroxtonSoC/BroxtonSiPkg/SouthCluster/Sdio/Dxe/SD/SdMediaDeviceDxe/SdMediaDevice.h
 create mode 100644 Silicon/BroxtonSoC/BroxtonSiPkg/SouthCluster/Sdio/Dxe/SD/SdMediaDeviceDxe/SdMediaDeviceDxe.inf

diff --git a/Platform/BroxtonPlatformPkg/PlatformDsc/Components.dsc b/Platform/BroxtonPlatformPkg/PlatformDsc/Components.dsc
index 7efcdb4..1322576 100644
--- a/Platform/BroxtonPlatformPkg/PlatformDsc/Components.dsc
+++ b/Platform/BroxtonPlatformPkg/PlatformDsc/Components.dsc
@@ -386,11 +386,14 @@
   $(PLATFORM_PACKAGE_COMMON)/Console/LpssUartSerialDxe/LpssUartSerialDxe.inf
 
   #
-  # eMMC/SD Card
+  # SDIO
   #
-  MdeModulePkg/Bus/Pci/SdMmcPciHcDxe/SdMmcPciHcDxe.inf
-  MdeModulePkg/Bus/Sd/EmmcDxe/EmmcDxe.inf
-  MdeModulePkg/Bus/Sd/SdDxe/SdDxe.inf
+  $(PLATFORM_SI_PACKAGE)/SouthCluster/Sdio/Dxe/MMC/MmcHostDxe/MmcHostDxe.inf
+
+  $(PLATFORM_SI_PACKAGE)/SouthCluster/Sdio/Dxe/MMC/MmcMediaDeviceDxe/MmcMediaDeviceDxe.inf
+
+  $(PLATFORM_SI_PACKAGE)/SouthCluster/Sdio/Dxe/SD/SdControllerDxe/SdControllerDxe.inf
+  $(PLATFORM_SI_PACKAGE)/SouthCluster/Sdio/Dxe/SD/SdMediaDeviceDxe/SdMediaDeviceDxe.inf
 
 
   !if $(ACPI50_ENABLE) == TRUE
diff --git a/Platform/BroxtonPlatformPkg/PlatformPkg.fdf b/Platform/BroxtonPlatformPkg/PlatformPkg.fdf
index 73174af..ac09ac3 100644
--- a/Platform/BroxtonPlatformPkg/PlatformPkg.fdf
+++ b/Platform/BroxtonPlatformPkg/PlatformPkg.fdf
@@ -434,14 +434,16 @@ APRIORI DXE {
   INF MdeModulePkg/Bus/Pci/PciBusDxe/PciBusDxe.inf
 
   #
-  # eMMC/SD Card
+  # SDIO
   #
 !if $(EMMC_DRIVER_ENABLE) == TRUE
-  INF MdeModulePkg/Bus/Pci/SdMmcPciHcDxe/SdMmcPciHcDxe.inf
-  INF MdeModulePkg/Bus/Sd/EmmcDxe/EmmcDxe.inf
-  INF MdeModulePkg/Bus/Sd/SdDxe/SdDxe.inf  
+  INF $(PLATFORM_SI_PACKAGE)/SouthCluster/Sdio/Dxe/MMC/MmcHostDxe/MmcHostDxe.inf
+  INF $(PLATFORM_SI_PACKAGE)/SouthCluster/Sdio/Dxe/MMC/MmcMediaDeviceDxe/MmcMediaDeviceDxe.inf
 !endif
 
+  INF $(PLATFORM_SI_PACKAGE)/SouthCluster/Sdio/Dxe/SD/SdControllerDxe/SdControllerDxe.inf
+  INF $(PLATFORM_SI_PACKAGE)/SouthCluster/Sdio/Dxe/SD/SdMediaDeviceDxe/SdMediaDeviceDxe.inf
+
   INF MdeModulePkg/Universal/Acpi/S3SaveStateDxe/S3SaveStateDxe.inf
   INF IntelFrameworkModulePkg/Universal/Acpi/AcpiS3SaveDxe/AcpiS3SaveDxe.inf
 
diff --git a/Silicon/BroxtonSoC/BroxtonSiPkg/SouthCluster/Sdio/Dxe/MMC/MmcHostDxe/ComponentName.c b/Silicon/BroxtonSoC/BroxtonSiPkg/SouthCluster/Sdio/Dxe/MMC/MmcHostDxe/ComponentName.c
new file mode 100644
index 0000000..f099fa8
--- /dev/null
+++ b/Silicon/BroxtonSoC/BroxtonSiPkg/SouthCluster/Sdio/Dxe/MMC/MmcHostDxe/ComponentName.c
@@ -0,0 +1,162 @@
+/** @file
+  Component Name protocol implementation
+
+  Copyright (c) 2012 - 2016, Intel Corporation. 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 "MmcHostDriver.h"
+
+//
+// EFI Component Name Protocol
+//
+EFI_COMPONENT_NAME_PROTOCOL     gMmcHostComponentName = {
+  MmcHostComponentNameGetDriverName,
+  MmcHostComponentNameGetControllerName,
+  "eng"
+};
+
+
+static EFI_UNICODE_STRING_TABLE mMmcHostDriverNameTable[] = {
+  { "eng", L"UEFI MMC Host Controller Driver" },
+  { NULL , NULL }
+};
+
+
+/**
+  Retrieves a Unicode string that is the user readable name of the EFI Driver.
+
+  @param[in]  This                    A pointer to the EFI_COMPONENT_NAME_PROTOCOL instance.
+  @param[in]  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[out] DriverName              A pointer to the Unicode string to return.  This Unicode string
+                                      is the name of the driver specified by This in the language
+                                      specified by Language.
+
+
+  @retval     EFI_SUCCESS             The Unicode string for the Driver specified by This
+                                      and the language specified by Language was returned
+                                      in DriverName.
+  @retval     EFI_INVALID_PARAMETER   Language is NULL.
+  @retval     EFI_INVALID_PARAMETER   DriverName is NULL.
+  @retval     EFI_UNSUPPORTED         The driver specified by This does not support the
+                                      language specified by Language.
+
+**/
+EFI_STATUS
+EFIAPI
+MmcHostComponentNameGetDriverName (
+  IN  EFI_COMPONENT_NAME_PROTOCOL     *This,
+  IN  CHAR8                           *Language,
+  OUT CHAR16                          **DriverName
+  )
+{
+  return LookupUnicodeString (
+           Language,
+           gMmcHostComponentName.SupportedLanguages,
+           mMmcHostDriverNameTable,
+           DriverName
+           );
+}
+
+
+/**
+  Retrieves a Unicode string that is the user readable name of the controller
+  that is being managed by an EFI Driver.
+
+  @param[in]  This                    A pointer to the EFI_COMPONENT_NAME_PROTOCOL instance.
+  @param[in]  ControllerHandle        The handle of a controller that the driver specified by
+                                      This is managing.  This handle specifies the controller
+                                      whose name is to be returned.
+  @param[in]  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[in]  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[out] ControllerName          A pointer to the Unicode string to return.  This Unicode
+                                      string is the name of the controller specified by
+                                      ControllerHandle and ChildHandle in the language
+                                      specified by Language from the point of view of the
+                                      driver specified by This.
+
+
+  @retval     EFI_SUCCESS             The Unicode string for the user readable name in the
+                                      language specified by Language for the driver
+                                      specified by This was returned in DriverName.
+  @retval     EFI_INVALID_PARAMETER   ControllerHandle is not a valid EFI_HANDLE.
+  @retval     EFI_INVALID_PARAMETER   ChildHandle is not NULL and it is not a valid
+                                      EFI_HANDLE.
+  @retval     EFI_INVALID_PARAMETER   Language is NULL.
+  @retval     EFI_INVALID_PARAMETER   ControllerName is NULL.
+  @retval     EFI_UNSUPPORTED          The driver specified by This is not currently
+                                      managing the controller specified by
+                                      ControllerHandle and ChildHandle.
+  @retval     EFI_UNSUPPORTED         The driver specified by This does not support the
+                                      language specified by Language.
+
+**/
+EFI_STATUS
+EFIAPI
+MmcHostComponentNameGetControllerName (
+  IN  EFI_COMPONENT_NAME_PROTOCOL     *This,
+  IN  EFI_HANDLE                      ControllerHandle,
+  IN  EFI_HANDLE                      ChildHandle, OPTIONAL
+  IN  CHAR8                           *Language,
+  OUT CHAR16                          **ControllerName
+  )
+{
+  EFI_STATUS                          Status;
+  EFI_MMC_HOST_IO_PROTOCOL            *MmcHostIo;
+  MMCHOST_DATA                        *MmcHostData;
+
+  //
+  // This is a device driver, so ChildHandle must be NULL.
+  //
+  if (ChildHandle != NULL) {
+    return EFI_UNSUPPORTED;
+  }
+
+  //
+  // Get the device context
+  //
+  Status = gBS->OpenProtocol (
+                  ControllerHandle,
+                  &gEfiMmcHostIoProtocolGuid,
+                  (VOID **) &MmcHostIo,
+                  gMmcHostDriverBinding.DriverBindingHandle,
+                  ControllerHandle,
+                  EFI_OPEN_PROTOCOL_GET_PROTOCOL
+                  );
+
+  if (EFI_ERROR (Status)) {
+    return Status;
+  }
+
+  MmcHostData = MMCHOST_DATA_FROM_THIS (MmcHostIo);
+
+  return LookupUnicodeString (
+           Language,
+           gMmcHostComponentName.SupportedLanguages,
+           MmcHostData->ControllerNameTable,
+           ControllerName
+           );
+}
+
diff --git a/Silicon/BroxtonSoC/BroxtonSiPkg/SouthCluster/Sdio/Dxe/MMC/MmcHostDxe/MmcHostController.c b/Silicon/BroxtonSoC/BroxtonSiPkg/SouthCluster/Sdio/Dxe/MMC/MmcHostDxe/MmcHostController.c
new file mode 100644
index 0000000..f3cd50e
--- /dev/null
+++ b/Silicon/BroxtonSoC/BroxtonSiPkg/SouthCluster/Sdio/Dxe/MMC/MmcHostDxe/MmcHostController.c
@@ -0,0 +1,1529 @@
+/** @file
+  MMC Host I/O protocol implementation
+
+  Copyright (c) 1999 - 2016, Intel Corporation. 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 "MmcHostDriver.h"
+
+#define MMC_HOST_DEBUG(a)    do { \
+                                if (MmcHostData->EnableVerboseDebug) { \
+                                    DEBUG (a); \
+                                  } \
+                                } while (0);
+
+UINT32  gMmcHostDebugLevel = DEBUG_INFO;
+
+/**
+  Get Error Reason
+
+  @param[in]  CommandIndex      The command index to set the command index field of command register
+  @param[in]  ErrorCode         Mmchost specific error code
+
+  @retval     EFI_DEVICE_ERROR
+  @retval     EFI_TIMEOUT
+  @retval     EFI_CRC_ERROR
+
+**/
+STATIC
+EFI_STATUS
+GetErrorReason (
+  IN  UINT16    CommandIndex,
+  IN  UINT16    ErrorCode
+  )
+{
+  EFI_STATUS    Status;
+
+  Status = EFI_DEVICE_ERROR;
+  DEBUG ((gMmcHostDebugLevel, "[%2d] -- ", CommandIndex));
+
+  if (ErrorCode & BIT0) {
+    Status = EFI_TIMEOUT;
+    DEBUG ((gMmcHostDebugLevel, "Command Timeout Error"));
+  }
+
+  if (ErrorCode & BIT1) {
+    Status = EFI_CRC_ERROR;
+    DEBUG ((gMmcHostDebugLevel, "Command CRC Error"));
+  }
+
+  if (ErrorCode & BIT2) {
+    DEBUG ((gMmcHostDebugLevel, "Command End Bit Error"));
+  }
+
+  if (ErrorCode & BIT3) {
+    DEBUG ((gMmcHostDebugLevel, "Command Index Error"));
+  }
+  if (ErrorCode & BIT4) {
+    Status = EFI_TIMEOUT;
+    DEBUG ((gMmcHostDebugLevel, "Data Timeout Error"));
+  }
+
+  if (ErrorCode & BIT5) {
+    Status = EFI_CRC_ERROR;
+    DEBUG ((gMmcHostDebugLevel, "Data CRC Error"));
+  }
+
+  if (ErrorCode & BIT6) {
+    DEBUG ((gMmcHostDebugLevel, "Data End Bit Error"));
+  }
+
+  if (ErrorCode & BIT7) {
+    DEBUG ((gMmcHostDebugLevel, "Current Limit Error"));
+  }
+
+  if (ErrorCode & BIT8) {
+    DEBUG ((gMmcHostDebugLevel, "Auto CMD12 Error"));
+  }
+
+  if (ErrorCode & BIT9) {
+    DEBUG ((gMmcHostDebugLevel, "ADMA Error"));
+  }
+
+  DEBUG ((gMmcHostDebugLevel, "\n"));
+
+  return Status;
+}
+
+
+/**
+  Read MMC host register
+
+  @param[in]      MmcHost                    Pointer to EFI_MMC_HOST_IO_PROTOCOL
+  @param[in]      Width                      Signifies the width of the memory or I/O operations.
+  @param[in]      Offset                     Offset of the MMC Card
+  @param[in, out] Buffer                     Buffer read from MMC Card
+
+  @retval         EFI_INVALID_PARAMETER
+  @retval         EFI_UNSUPPORTED
+  @retval         EFI_SUCCESS
+
+**/
+STATIC
+EFI_STATUS
+MmcHostRead (
+  IN     MMCHOST_DATA                 *MmcHost,
+  IN     EFI_PCI_IO_PROTOCOL_WIDTH    Width,
+  IN     UINTN                        Offset,
+  IN OUT VOID                         *Buffer
+  )
+{
+  return MmcHost->PciIo->Mem.Read (
+                               MmcHost->PciIo,
+                               Width,
+                               0,
+                               (UINT64) Offset,
+                               1,
+                               Buffer
+                               );
+}
+
+
+/**
+  Read MMC host register
+
+  @param[in]  MmcHost      Pointer to EFI_MMC_HOST_IO_PROTOCOL
+  @param[in]  Offset       Offset of the MMC Card
+
+  @retval     Data         Data read from MMC Card
+
+**/
+UINT8
+MmcHostRead8 (
+  IN     MMCHOST_DATA      *MmcHost,
+  IN     UINTN             Offset
+  )
+{
+  UINT8 Data;
+
+  MmcHostRead (MmcHost, EfiPciIoWidthUint8, Offset, &Data);
+
+  return Data;
+}
+
+
+/**
+  Read MMC host register
+
+  @param[in]  MmcHost        Pointer to EFI_MMC_HOST_IO_PROTOCOL
+  @param[in]  Offset         Offset of the MMC Card
+
+  @retval     Data           Data read from MMC Card
+
+**/
+UINT16
+MmcHostRead16 (
+  IN     MMCHOST_DATA        *MmcHost,
+  IN     UINTN               Offset
+  )
+{
+  UINT16 Data;
+
+  MmcHostRead (MmcHost, EfiPciIoWidthUint16, Offset, &Data);
+
+  return Data;
+}
+
+
+/**
+  Read MMC host register
+
+  @param[in]  MmcHost    Pointer to EFI_MMC_HOST_IO_PROTOCOL
+  @param[in]  Offset     Offset of the MMC Card
+
+  @retval     Data       Data read from MMC Card
+
+**/
+UINT32
+MmcHostRead32 (
+  IN     MMCHOST_DATA    *MmcHost,
+  IN     UINTN           Offset
+  )
+{
+  UINT32 Data;
+
+  MmcHostRead (MmcHost, EfiPciIoWidthUint32, Offset, &Data);
+
+  return Data;
+}
+
+
+/**
+  Dump MMC host registers
+
+  @param[in]  MmcHost     Pointer to EFI_MMC_HOST_IO_PROTOCOL
+
+  @retval     None
+
+**/
+VOID
+DebugPrintMmcHostRegisters (
+  IN     MMCHOST_DATA     *MmcHost
+  )
+{
+#ifdef VERBOSE_REGISTER_ACCESS_DEBUG
+  UINTN    Loop;
+
+  if (!MmcHost->EnableVerboseDebug) {
+    return;
+  }
+
+  for (Loop = 0; Loop < 0x40; Loop++) {
+    DEBUG ((EFI_D_INFO, " %02x", MmcHostRead8 (MmcHost, Loop)));
+    if ((Loop % 0x10) == 0xf) {
+      DEBUG ((EFI_D_INFO, "\n"));
+    }
+  }
+
+#endif
+}
+
+
+/**
+  Dump MMC host registers before write
+
+  @param[in]  MmcHost    Pointer to EFI_MMC_HOST_IO_PROTOCOL
+
+  @retval     None
+
+**/
+VOID
+DebugPreMmcHostWrite (
+  IN     MMCHOST_DATA                  *MmcHost
+  )
+{
+#ifdef VERBOSE_REGISTER_ACCESS_DEBUG
+  STATIC UINTN DebugCount = 0;
+
+  if (!MmcHost->EnableVerboseDebug) {
+    return;
+  }
+
+  DebugCount++;
+
+  if (DebugCount < 0x100) {
+    DEBUG ((EFI_D_INFO, "MMC HOST Registers before write:\n"));
+    DebugPrintMmcHostRegisters (MmcHost);
+  }
+#endif
+}
+
+
+/**
+  Dump MMC host registers after write
+
+  @param[in]  MmcHost      Pointer to EFI_MMC_HOST_IO_PROTOCOL
+
+  @retval     None
+
+**/
+VOID
+DebugPostMmcHostWrite (
+  IN     MMCHOST_DATA                  *MmcHost
+  )
+{
+#ifdef VERBOSE_REGISTER_ACCESS_DEBUG
+  STATIC UINTN DebugCount = 0;
+
+  if (!MmcHost->EnableVerboseDebug) {
+    return;
+  }
+
+  DebugCount++;
+
+  if (DebugCount < 0x10) {
+    DEBUG ((EFI_D_INFO, "MMC HOST Registers after write:\n"));
+    DebugPrintMmcHostRegisters (MmcHost);
+  }
+#endif
+}
+
+
+/**
+  Write MMC host register
+
+  @param[in]      MmcHost                Pointer to EFI_MMC_HOST_IO_PROTOCOL
+  @param[in]      Width                  Signifies the width of the memory or I/O operations.
+  @param[in]      Offset                 Offset of the MMC Card
+  @param[in, out] Buffer                 Buffer read from MMC Card
+
+  @retval         EFI_INVALID_PARAMETER
+  @retval         EFI_UNSUPPORTED
+  @retval         EFI_SUCCESS
+
+**/
+STATIC
+EFI_STATUS
+MmcHostWrite (
+  IN     MMCHOST_DATA                 *MmcHost,
+  IN     EFI_PCI_IO_PROTOCOL_WIDTH    Width,
+  IN     UINTN                        Offset,
+  IN OUT VOID                         *Buffer
+  )
+{
+  EFI_STATUS    Status;
+
+  DebugPreMmcHostWrite (MmcHost);
+  Status = MmcHost->PciIo->Mem.Write (
+                                 MmcHost->PciIo,
+                                 Width,
+                                 0,
+                                 (UINT64) Offset,
+                                 1,
+                                 Buffer
+                                 );
+
+  DebugPostMmcHostWrite (MmcHost);
+
+  return Status;
+}
+
+
+/**
+  Write MMC host register
+
+  @param[in]  MmcHost    Pointer to EFI_MMC_HOST_IO_PROTOCOL
+  @param[in]  Offset     Offset of the MMC Card
+  @param[in]  Data       Data write to MMC Card
+
+  @retval     Data       Written to MmcHost
+
+**/
+UINT8
+MmcHostWrite8 (
+  IN     MMCHOST_DATA                 *MmcHost,
+  IN     UINTN                        Offset,
+  IN     UINT8                        Data
+  )
+{
+  MmcHostWrite (MmcHost, EfiPciIoWidthUint8, Offset, &Data);
+
+  return Data;
+}
+
+
+/**
+  Write MMC host register
+
+  @param[in]  MmcHost    Pointer to EFI_MMC_HOST_IO_PROTOCOL
+  @param[in]  Offset     Offset of the MMC Card
+  @param[in]  Data       Data write to MMC Card
+
+  @retval     Data       Data written to MMC Card
+
+**/
+UINT16
+MmcHostWrite16 (
+  IN     MMCHOST_DATA                 *MmcHost,
+  IN     UINTN                        Offset,
+  IN     UINT16                       Data
+  )
+{
+  MmcHostWrite (MmcHost, EfiPciIoWidthUint16, Offset, &Data);
+
+  return Data;
+}
+
+
+/**
+  Write MMC host register
+
+  @param[in]  MmcHost    Pointer to EFI_MMC_HOST_IO_PROTOCOL
+  @param[in]  Offset     Offset of the MMC Card
+  @param[in]  Data       Data write to MMC Card
+
+  @retval     Data       Data written to MMC Card
+
+**/
+UINT32
+MmcHostWrite32 (
+  IN     MMCHOST_DATA                 *MmcHost,
+  IN     UINTN                        Offset,
+  IN     UINT32                       Data
+  )
+{
+  MmcHostWrite (MmcHost, EfiPciIoWidthUint32, Offset, &Data);
+
+  return Data;
+}
+
+
+/**
+  Check Controller Version
+
+  @param[in]  MmcHost      Pointer to EFI_MMC_HOST_IO_PROTOCOL
+
+  @retval     Data         Written to MmcHost
+
+**/
+UINT32
+CheckControllerVersion (
+  IN MMCHOST_DATA          *MmcHost
+  )
+{
+  UINT16     Data16;
+
+  Data16 = MmcHostRead16 (MmcHost, MMIO_CTRLRVER);
+  DEBUG ((EFI_D_INFO, "CheckControllerVersion: %x \n", Data16 & 0xFF));
+
+  return (Data16 & 0xFF);
+}
+
+
+/**
+  Power on/off the LED associated with the slot
+
+  @param[in]  This         Pointer to EFI_MMC_HOST_IO_PROTOCOL
+  @param[in]  Enable       TRUE to set LED on, FALSE to set LED off
+
+  @retval     EFI_SUCCESS
+
+**/
+STATIC
+EFI_STATUS
+HostLEDEnable (
+  IN  EFI_MMC_HOST_IO_PROTOCOL   *This,
+  IN  BOOLEAN                    Enable
+  )
+{
+  MMCHOST_DATA                   *MmcHostData;
+  UINT8                          Data;
+
+  MmcHostData = MMCHOST_DATA_FROM_THIS (This);
+  Data = MmcHostRead8 (MmcHostData, MMIO_HOSTCTL);
+
+  if (Enable) {
+    //
+    //LED On
+    //
+    Data |= BIT0;
+  } else {
+    //
+    //LED Off
+    //
+    Data &= ~BIT0;
+  }
+
+  MmcHostWrite8 (MmcHostData, MMIO_HOSTCTL, Data);
+
+  return EFI_SUCCESS;
+}
+
+
+/**
+  The main function used to send the command to the card inserted into the MMC host
+  slot.
+  It will assemble the arguments to set the command register and wait for the command
+  and transfer completed until timeout. Then it will read the response register to fill
+  the ResponseData
+
+  @param[in]  This                    Pointer to EFI_MMC_HOST_IO_PROTOCOL
+  @param[in]  CommandIndex            The command index to set the command index field of command register
+  @param[in]  Argument                Command argument to set the argument field of command register
+  @param[in]  DataType                TRANSFER_TYPE, indicates no data, data in or data out
+  @param[in]  Buffer                  Contains the data read from / write to the device
+  @param[in]  BufferSize              The size of the buffer
+  @param[in]  ResponseType            RESPONSE_TYPE
+  @param[in]  TimeOut                 Time out value in 1 ms unit
+  @param[out] ResponseData            Depending on the ResponseType, such as CSD or card status
+
+  @retval     EFI_INVALID_PARAMETER
+  @retval     EFI_UNSUPPORTED
+  @retval     EFI_SUCCESS
+
+**/
+EFI_STATUS
+EFIAPI
+SendCommand (
+  IN   EFI_MMC_HOST_IO_PROTOCOL   *This,
+  IN   UINT16                     CommandIndex,
+  IN   UINT32                     Argument,
+  IN   TRANSFER_TYPE              DataType,
+  IN   UINT8                      *Buffer, OPTIONAL
+  IN   UINT32                     BufferSize,
+  IN   RESPONSE_TYPE              ResponseType,
+  IN   UINT32                     TimeOut,
+  OUT  UINT32                     *ResponseData OPTIONAL
+  )
+{
+  EFI_STATUS                      Status;
+  MMCHOST_DATA                    *MmcHostData;
+  UINT32                          ResponseDataCount;
+  UINT16                          Data16;
+  UINT32                          Data32;
+  UINT64                          Data64;
+  UINT8                           Index;
+  BOOLEAN                         CommandCompleted;
+  INT32                           Timeout = 1000;
+
+  Status             = EFI_SUCCESS;
+  ResponseDataCount  = 1;
+  MmcHostData        = MMCHOST_DATA_FROM_THIS (This);
+
+  if (Buffer != NULL && DataType == NoData) {
+    Status = EFI_INVALID_PARAMETER;
+    DEBUG ((gMmcHostDebugLevel, "SendCommand: Invalid parameter -> \n"));
+    goto Exit;
+  }
+
+  if (((UINTN) Buffer & (This->HostCapability.BoundarySize - 1)) != (UINTN) NULL) {
+    Status = EFI_INVALID_PARAMETER;
+    DEBUG ((gMmcHostDebugLevel, "SendCommand: Invalid parameter -> \n"));
+    goto Exit;
+  }
+
+  DEBUG ((DEBUG_INFO, "SendCommand: CMD%d \n", CommandIndex));
+  if (MmcHostData->EnableVerboseDebug) {
+    DEBUG ((EFI_D_INFO, "00 -10:  %08x  %08x  %08x  %08x \n", MmcHostRead32 (MmcHostData, 0x00), MmcHostRead32 (MmcHostData, 0x04), MmcHostRead32 (MmcHostData, 0x08), MmcHostRead32 (MmcHostData, 0x0C)));
+    DEBUG ((EFI_D_INFO, "10 -20:  %08x  %08x  %08x  %08x \n", MmcHostRead32 (MmcHostData, 0x10), MmcHostRead32 (MmcHostData, 0x14), MmcHostRead32 (MmcHostData, 0x18), MmcHostRead32 (MmcHostData, 0x1C)));
+    DEBUG ((EFI_D_INFO, "20 -30:  %08x  %08x  %08x  %08x \n", MmcHostRead32 (MmcHostData, 0x20), MmcHostRead32 (MmcHostData, 0x24), MmcHostRead32 (MmcHostData, 0x28), MmcHostRead32 (MmcHostData, 0x2C)));
+    DEBUG ((EFI_D_INFO, "30 -40:  %08x  %08x  %08x  %08x \n", MmcHostRead32 (MmcHostData, 0x30), MmcHostRead32 (MmcHostData, 0x34), MmcHostRead32 (MmcHostData, 0x38), MmcHostRead32 (MmcHostData, 0x3C)));
+    DEBUG ((EFI_D_INFO, "40 -50:  %08x  %08x  %08x  %08x \n", MmcHostRead32 (MmcHostData, 0x40), MmcHostRead32 (MmcHostData, 0x44), MmcHostRead32 (MmcHostData, 0x48), MmcHostRead32 (MmcHostData, 0x4C)));
+    DEBUG ((EFI_D_INFO, "50 -60:  %08x  %08x  %08x  %08x \n", MmcHostRead32 (MmcHostData, 0x50), MmcHostRead32 (MmcHostData, 0x54), MmcHostRead32 (MmcHostData, 0x58), MmcHostRead32 (MmcHostData, 0x5C)));
+  }
+
+  //
+  // Check CMD INHIBIT and DATA INHIBIT before send command
+  //
+  do {
+    Data32 = MmcHostRead32 (MmcHostData, MMIO_PSTATE);
+    if (MmcHostData->EnableVerboseDebug) {
+      DEBUG ((EFI_D_INFO, "Wait CMD INHIBIT %x\n",Data32 ));
+    }
+  } while (Timeout-- > 0 && Data32 & BIT0);
+
+  Timeout = 1000;
+  do {
+    Data32 = MmcHostRead32 (MmcHostData, MMIO_PSTATE);
+    if (MmcHostData->EnableVerboseDebug) {
+      DEBUG ((EFI_D_INFO, "Wait DATA INHIBIT %x\n",Data32 ));
+    }
+  } while (Timeout-- >0 && Data32 & BIT1);
+
+  //
+  //Clear status bits
+  //
+  MMC_HOST_DEBUG ((EFI_D_INFO, "NINTSTS(0x30) <- 0x%x\n", (UINTN) 0xffff));
+  MmcHostWrite16 (MmcHostData, MMIO_NINTSTS, 0xffff);
+  MMC_HOST_DEBUG ((EFI_D_INFO, "SendCommand: NINTSTS (0x30): 0x%x\n", MmcHostRead16 (MmcHostData, MMIO_NINTSTS)));
+
+  MMC_HOST_DEBUG ((EFI_D_INFO, "ERINTSTS <- 0x%x\n", (UINTN) 0xffff));
+  MmcHostWrite16 (MmcHostData, MMIO_ERINTSTS, 0xffff);
+  MMC_HOST_DEBUG ((EFI_D_INFO, "SendCommand: ERINTSTS (0x32): 0x%x\n", MmcHostRead16 (MmcHostData, MMIO_ERINTSTS)));
+
+  Data16 = MmcHostRead16 (MmcHostData, MMIO_NINTEN);
+  MmcHostWrite16 (MmcHostData, MMIO_NINTEN,  (Data16 | BIT3));
+  MMC_HOST_DEBUG ((DEBUG_INFO, "SendCommand: NINTEN (0x34) <- 0x%x\n", MmcHostRead16 (MmcHostData, MMIO_NINTEN)));
+  MMC_HOST_DEBUG ((DEBUG_INFO, "SendCommand: DMAADR (0x00) <- 0x%x\n", (UINTN) Buffer));
+  MmcHostWrite32 (MmcHostData, MMIO_DMAADR, (UINT32) (UINTN) Buffer);
+
+  if (Buffer != NULL) {
+    Data16 = MmcHostRead16 (MmcHostData, MMIO_BLKSZ);
+    Data16 &= ~(0xFFF);
+    if (BufferSize <= MmcHostData->BlockLength) {
+      Data16 |= BufferSize;
+    } else {
+      Data16 |= MmcHostData->BlockLength;
+    }
+    Data16 |= 0x7000; // Set to 512KB for SDMA block size
+  } else {
+    Data16 = 0;
+  }
+
+  MMC_HOST_DEBUG ((EFI_D_INFO, "SendCommand: BLKSZ(0x04) <- 0x%x\n", Data16));
+  MmcHostWrite16 (MmcHostData, MMIO_BLKSZ, Data16);
+
+  if (Buffer != NULL) {
+    if (BufferSize <= MmcHostData->BlockLength) {
+      Data16 = 1;
+    } else {
+      Data16 = (UINT16) (BufferSize / MmcHostData->BlockLength);
+    }
+  } else {
+    Data16 = 0;
+  }
+
+  MMC_HOST_DEBUG ((EFI_D_INFO, "SendCommand: BLKCNT(0x06) <- 0x%x\n", Data16));
+  MmcHostWrite16 (MmcHostData, MMIO_BLKCNT, Data16);
+
+  //
+  // Argument
+  //
+  MMC_HOST_DEBUG ((EFI_D_INFO, "SendCommand: CMDARG (0x08) <- 0x%x\n", Argument));
+  MmcHostWrite32 (MmcHostData, MMIO_CMDARG, Argument);
+
+  //
+  // Transfer Mode
+  //
+  Data16 = MmcHostRead16 (MmcHostData, MMIO_XFRMODE);
+  MMC_HOST_DEBUG ((EFI_D_INFO, "SendCommand: XFRMODE (0x0C) mode read 0x%x\n", Data16));
+
+  //
+  // BIT0   DMA Enable
+  // BIT2   Auto Cmd12
+  //
+  if (DataType == InData) {
+    Data16 |= BIT4 | BIT0;
+  } else if (DataType == OutData) {
+    Data16 &= ~BIT4;
+    Data16 |= BIT0;
+  } else {
+    Data16 &= ~(BIT4 | BIT0);
+  }
+
+  if (BufferSize <= MmcHostData->BlockLength) {
+    Data16 &= ~ (BIT5 | BIT1 | BIT2);
+  } else {
+    if (MmcHostData->IsAutoStopCmd && !MmcHostData->IsEmmc) {
+      Data16 |= (BIT5 | BIT1 | BIT2);
+    } else {
+      Data16 |= (BIT5 | BIT1);
+    }
+  }
+  if (CommandIndex == SEND_EXT_CSD) {
+    Data16 |= BIT1;
+    MMC_HOST_DEBUG ((EFI_D_INFO, "SendCommand:Enable bit 1, XFRMODE <- 0x%x\n", Data16));
+  }
+
+  MMC_HOST_DEBUG ((EFI_D_INFO, "SendCommand: XFRMODE (0x0C) <- 0x%x\n", Data16));
+  MmcHostWrite16 (MmcHostData, MMIO_XFRMODE, Data16);
+
+  switch (ResponseType) {
+    case ResponseNo:
+      Data16 = (CommandIndex << 8);
+      ResponseDataCount = 0;
+      break;
+
+    case ResponseR1:
+    case ResponseR5:
+    case ResponseR6:
+    case ResponseR7:
+      Data16 = (CommandIndex << 8) | BIT1 | BIT4| BIT3;
+      ResponseDataCount = 1;
+      break;
+
+    case ResponseR1b:
+    case ResponseR5b:
+      Data16 = (CommandIndex << 8) | BIT0 | BIT1 | BIT4| BIT3;
+      ResponseDataCount = 1;
+      break;
+
+    case ResponseR2:
+      Data16 = (CommandIndex << 8) | BIT0 | BIT3;
+      ResponseDataCount = 4;
+      break;
+
+    case ResponseR3:
+    case ResponseR4:
+      Data16 = (CommandIndex << 8) | BIT1;
+      ResponseDataCount = 1;
+      break;
+
+    default:
+      ASSERT (0);
+      Status = EFI_INVALID_PARAMETER;
+      goto Exit;
+  }
+
+  if (DataType != NoData) {
+    Data16 |= BIT5;
+  }
+
+  HostLEDEnable (This, TRUE);
+
+  MMC_HOST_DEBUG ((EFI_D_INFO, "SendCommand: SDCMD(0x0E) <- 0x%x\n", Data16));
+  CommandCompleted = FALSE;
+  MmcHostWrite16 (MmcHostData, MMIO_SDCMD, Data16);
+
+  if (MmcHostData->EnableVerboseDebug) {
+    DEBUG ((EFI_D_INFO, "After write to  Command\n"));
+    DEBUG ((EFI_D_INFO, "00 -10:  %08x  %08x  %08x  %08x \n", MmcHostRead32 (MmcHostData, 0x00), MmcHostRead32 (MmcHostData, 0x04), MmcHostRead32 (MmcHostData, 0x08), MmcHostRead32 (MmcHostData, 0x0C)));
+    DEBUG ((EFI_D_INFO, "10 -20:  %08x  %08x  %08x  %08x \n", MmcHostRead32 (MmcHostData, 0x10), MmcHostRead32 (MmcHostData, 0x14), MmcHostRead32 (MmcHostData, 0x18), MmcHostRead32 (MmcHostData, 0x1C)));
+    DEBUG ((EFI_D_INFO, "20 -30:  %08x  %08x  %08x  %08x \n", MmcHostRead32 (MmcHostData, 0x20), MmcHostRead32 (MmcHostData, 0x24), MmcHostRead32 (MmcHostData, 0x28), MmcHostRead32 (MmcHostData, 0x2C)));
+    DEBUG ((EFI_D_INFO, "30 -40:  %08x  %08x  %08x  %08x \n", MmcHostRead32 (MmcHostData, 0x30), MmcHostRead32 (MmcHostData, 0x34), MmcHostRead32 (MmcHostData, 0x38), MmcHostRead32 (MmcHostData, 0x3C)));
+    DEBUG ((EFI_D_INFO, "40 -50:  %08x  %08x  %08x  %08x \n", MmcHostRead32 (MmcHostData, 0x40), MmcHostRead32 (MmcHostData, 0x44), MmcHostRead32 (MmcHostData, 0x48), MmcHostRead32 (MmcHostData, 0x4C)));
+    DEBUG ((EFI_D_INFO, "50 -60:  %08x  %08x  %08x  %08x \n", MmcHostRead32 (MmcHostData, 0x50), MmcHostRead32 (MmcHostData, 0x54), MmcHostRead32 (MmcHostData, 0x58), MmcHostRead32 (MmcHostData, 0x5C)));
+  }
+
+  TimeOut *= 1000;  //ms to us conversion
+  do {
+    Data16 = MmcHostRead16 (MmcHostData, MMIO_ERINTSTS);
+    if (MmcHostData->EnableVerboseDebug && (Data16 != 0)) {
+      DEBUG ((EFI_D_INFO, "SendCommand: ERINTSTS (0x32): 0x%x\n", Data16));
+      DEBUG ((EFI_D_INFO, "SendCommand: ERINTEN (0x36): 0x%x\n", MmcHostRead16 (MmcHostData, MMIO_ERINTEN)));
+      DEBUG ((EFI_D_INFO, "SendCommand: NINTSTS (0x30): 0x%x\n", MmcHostRead16 (MmcHostData, MMIO_NINTSTS)));
+      DEBUG ((EFI_D_INFO, "SendCommand: NINTEN (0x34): 0x%x\n", MmcHostRead16 (MmcHostData, MMIO_NINTEN)));
+    }
+
+    if ((Data16 & 0x17FF) != 0) {
+      Status = GetErrorReason (CommandIndex, Data16);
+      DEBUG ((EFI_D_INFO, "00 -10:  %08x  %08x  %08x  %08x \n", MmcHostRead32 (MmcHostData, 0x00), MmcHostRead32 (MmcHostData, 0x04), MmcHostRead32 (MmcHostData, 0x08), MmcHostRead32 (MmcHostData, 0x0C)));
+      DEBUG ((EFI_D_INFO, "10 -20:  %08x  %08x  %08x  %08x \n", MmcHostRead32 (MmcHostData, 0x10), MmcHostRead32 (MmcHostData, 0x14), MmcHostRead32 (MmcHostData, 0x18), MmcHostRead32 (MmcHostData, 0x1C)));
+      DEBUG ((EFI_D_INFO, "20 -30:  %08x  %08x  %08x  %08x \n", MmcHostRead32 (MmcHostData, 0x20), MmcHostRead32 (MmcHostData, 0x24), MmcHostRead32 (MmcHostData, 0x28), MmcHostRead32 (MmcHostData, 0x2C)));
+      DEBUG ((EFI_D_INFO, "30 -40:  %08x  %08x  %08x  %08x \n", MmcHostRead32 (MmcHostData, 0x30), MmcHostRead32 (MmcHostData, 0x34), MmcHostRead32 (MmcHostData, 0x38), MmcHostRead32 (MmcHostData, 0x3C)));
+      DEBUG ((EFI_D_INFO, "40 -50:  %08x  %08x  %08x  %08x \n", MmcHostRead32 (MmcHostData, 0x40), MmcHostRead32 (MmcHostData, 0x44), MmcHostRead32 (MmcHostData, 0x48), MmcHostRead32 (MmcHostData, 0x4C)));
+      DEBUG ((EFI_D_INFO, "50 -60:  %08x  %08x  %08x  %08x \n", MmcHostRead32 (MmcHostData, 0x50), MmcHostRead32 (MmcHostData, 0x54), MmcHostRead32 (MmcHostData, 0x58), MmcHostRead32 (MmcHostData, 0x5C)));
+      goto Exit;
+    }
+
+    Data16 = MmcHostRead16 (MmcHostData, MMIO_NINTSTS) & 0x1ff;
+    if (MmcHostData->EnableVerboseDebug && (Data16 > 1)) {
+      DEBUG ((EFI_D_INFO, "SendCommand: NINTSTS (0x30): 0x%x\n", Data16));
+    }
+
+    if ((Data16 & BIT0) == BIT0) {
+      //
+      // Command completed
+      //
+      CommandCompleted = TRUE;
+
+      MmcHostWrite16 (MmcHostData, MMIO_NINTSTS, BIT0);
+
+      if ((DataType == NoData) && (ResponseType != ResponseR1b)) {
+        break;
+      }
+    }
+
+    if (CommandCompleted) {
+      //
+      // DMA interrupted
+      //
+      if ((Data16 & BIT3) == BIT3) {
+        MmcHostWrite16 (MmcHostData, MMIO_NINTSTS, BIT3);
+        Data32 = MmcHostRead32 (MmcHostData, MMIO_DMAADR);
+        MMC_HOST_DEBUG ((DEBUG_INFO, "SendCommand: DMAADR (0x00) <- 0x%x\n", Data32));
+        MmcHostWrite32 (MmcHostData, MMIO_DMAADR, Data32);
+      }
+
+      //
+      // Transfer completed
+      //
+      if ((Data16 & BIT1) == BIT1) {
+        MmcHostWrite16 (MmcHostData, MMIO_NINTSTS, BIT1);
+        break;
+      }
+    }
+
+    gBS->Stall (1);
+    TimeOut --;
+
+  } while (TimeOut > 0);
+
+  if (TimeOut == 0) {
+    Status = EFI_TIMEOUT;
+    DEBUG ((gMmcHostDebugLevel, "SendCommand: Time out \n"));
+    goto Exit;
+  }
+
+  if (ResponseData != NULL) {
+    UINT32 *ResDataPtr = NULL;
+
+    ResDataPtr = ResponseData;
+    for (Index = 0; Index < ResponseDataCount; Index++) {
+      *ResDataPtr = MmcHostRead32 (MmcHostData, MMIO_RESP + Index * 4);
+      ResDataPtr++;
+    }
+    MMC_HOST_DEBUG ((EFI_D_INFO, "Reponse Data 0: RESPONSE (0x10) <- 0x%x\n", *ResponseData));
+
+    if (ResponseType == ResponseR2) {
+      //
+      // Adjustment for R2 response
+      //
+      Data32 = 1;
+      for (Index = 0; Index < ResponseDataCount; Index++) {
+        Data64 = LShiftU64 (*ResponseData, 8);
+        *ResponseData = (UINT32) ((Data64 & 0xFFFFFFFF) | Data32);
+        Data32 =  (UINT32) RShiftU64 (Data64, 32);
+        ResponseData++;
+      }
+    }
+  }
+
+  if (MmcHostData->EnableVerboseDebug) {
+    DEBUG ((EFI_D_INFO, "Before Exit Send Command\n"));
+    DEBUG ((EFI_D_INFO, "00 -10:  %08x  %08x  %08x  %08x \n", MmcHostRead32 (MmcHostData, 0x00), MmcHostRead32 (MmcHostData, 0x04), MmcHostRead32 (MmcHostData, 0x08), MmcHostRead32 (MmcHostData, 0x0C)));
+    DEBUG ((EFI_D_INFO, "10 -20:  %08x  %08x  %08x  %08x \n", MmcHostRead32 (MmcHostData, 0x10), MmcHostRead32 (MmcHostData, 0x14), MmcHostRead32 (MmcHostData, 0x18), MmcHostRead32 (MmcHostData, 0x1C)));
+    DEBUG ((EFI_D_INFO, "20 -30:  %08x  %08x  %08x  %08x \n", MmcHostRead32 (MmcHostData, 0x20), MmcHostRead32 (MmcHostData, 0x24), MmcHostRead32 (MmcHostData, 0x28), MmcHostRead32 (MmcHostData, 0x2C)));
+    DEBUG ((EFI_D_INFO, "30 -40:  %08x  %08x  %08x  %08x \n", MmcHostRead32 (MmcHostData, 0x30), MmcHostRead32 (MmcHostData, 0x34), MmcHostRead32 (MmcHostData, 0x38), MmcHostRead32 (MmcHostData, 0x3C)));
+    DEBUG ((EFI_D_INFO, "40 -50:  %08x  %08x  %08x  %08x \n", MmcHostRead32 (MmcHostData, 0x40), MmcHostRead32 (MmcHostData, 0x44), MmcHostRead32 (MmcHostData, 0x48), MmcHostRead32 (MmcHostData, 0x4C)));
+    DEBUG ((EFI_D_INFO, "50 -60:  %08x  %08x  %08x  %08x \n", MmcHostRead32 (MmcHostData, 0x50), MmcHostRead32 (MmcHostData, 0x54), MmcHostRead32 (MmcHostData, 0x58), MmcHostRead32 (MmcHostData, 0x5C)));
+  }
+
+Exit:
+  HostLEDEnable (This, FALSE);
+  MMC_HOST_DEBUG ((EFI_D_INFO, "SendCommand: Status -> %r\n", Status));
+
+  return Status;
+}
+
+
+/**
+  Set clock frequency of the host, the actual frequency
+  may not be the same as MaxFrequencyInKHz. It depends on
+  the max frequency the host can support, divider, and host
+  speed mode.
+
+  @param[in]  This             Pointer to EFI_MMC_HOST_IO_PROTOCOL
+  @param[in]  MaxFrequency     Max frequency in HZ
+
+  @retval     EFI_SUCCESS
+
+**/
+EFI_STATUS
+EFIAPI
+SetClockFrequency (
+  IN  EFI_MMC_HOST_IO_PROTOCOL    *This,
+  IN  UINT32                      MaxFrequency
+  )
+{
+  UINT16                          Data16;
+  UINT32                          Frequency;
+  UINT32                          Divider = 0;
+  MMCHOST_DATA                    *MmcHostData;
+  UINT32                          TimeOutCount;
+
+  MmcHostData = MMCHOST_DATA_FROM_THIS (This);
+
+  DEBUG ((gMmcHostDebugLevel, "SetClockFrequency: BaseClockInMHz = %d \n", MmcHostData->BaseClockInMHz));
+
+  Frequency = (MmcHostData->BaseClockInMHz * 1000 * 1000) / MaxFrequency;
+  DEBUG ((gMmcHostDebugLevel, "SetClockFrequency: FrequencyInHz = %d \n", Frequency));
+
+  if ((MmcHostData->BaseClockInMHz * 1000 * 1000 % MaxFrequency) != 0) {
+    Frequency += 1;
+  }
+
+  Divider = 1;
+  while (Frequency > Divider) {
+    Divider = Divider * 2;
+  }
+
+  if (Divider >= 0x400) {
+    Divider = 0x200;
+  }
+  DEBUG ((gMmcHostDebugLevel, "SetClockFrequency: before shift: Base Clock Divider = 0x%x \n", Divider));
+  Divider = Divider >> 1;
+  DEBUG ((gMmcHostDebugLevel, "SetClockFrequency: before shift: Base Clock Divider = 0x%x \n", Divider));
+
+  MmcHostData->CurrentClockInKHz = (MmcHostData->BaseClockInMHz * 1000);
+  if (Divider != 0) {
+    MmcHostData->CurrentClockInKHz = MmcHostData->CurrentClockInKHz / (Divider * 2);
+  }
+
+  if (2 == CheckControllerVersion (MmcHostData)) {
+    Data16 = (UINT16) ((Divider & 0xFF) << 8 | (((Divider & 0xFF00) >>8)<<6));
+  } else {
+    Data16 = (UINT16) ( Divider << 8);
+  }
+
+  DEBUG ((gMmcHostDebugLevel,
+    "SetClockFrequency: base=%dMHz, clkctl=0x%04x, f=%dKHz\n",
+    MmcHostData->BaseClockInMHz,
+    Data16,
+    MmcHostData->CurrentClockInKHz
+    ));
+  DEBUG ((gMmcHostDebugLevel, "SetClockFrequency: set MMIO_CLKCTL value = 0x%x \n", Data16));
+  MmcHostWrite16 (MmcHostData, MMIO_CLKCTL, Data16);
+
+  gBS->Stall (10);
+  Data16 |= BIT0;
+  MmcHostWrite16 (MmcHostData, MMIO_CLKCTL, Data16);
+
+  TimeOutCount = TIME_OUT_1S;
+  do {
+    Data16 = MmcHostRead16 (MmcHostData, MMIO_CLKCTL);
+    gBS->Stall (10);
+    TimeOutCount --;
+    if (TimeOutCount == 0) {
+      DEBUG ((gMmcHostDebugLevel, "SetClockFrequency: Timeout\n"));
+      return EFI_TIMEOUT;
+    }
+  } while ((Data16 & BIT1) != BIT1);
+
+  gBS->Stall (10);
+  Data16 |= BIT2;
+  MmcHostWrite16 (MmcHostData, MMIO_CLKCTL, Data16);
+
+  return EFI_SUCCESS;
+}
+
+
+/**
+  Set bus width of the host
+
+  @param[in]  This         Pointer to EFI_MMC_HOST_IO_PROTOCOL
+  @param[in]  BusWidth     Bus width in 1, 4, 8 bits
+
+  @retval     EFI_SUCCESS
+
+**/
+EFI_STATUS
+EFIAPI
+SetBusWidth (
+  IN  EFI_MMC_HOST_IO_PROTOCOL    *This,
+  IN  UINT32                      BusWidth
+  )
+{
+  MMCHOST_DATA                    *MmcHostData;
+  UINT8                           Data;
+
+  MmcHostData = MMCHOST_DATA_FROM_THIS (This);
+
+  if ((BusWidth != 1) && (BusWidth != 4) && (BusWidth != 8)) {
+    DEBUG ((gMmcHostDebugLevel, "SetBusWidth: Invalid parameter \n"));
+    return EFI_INVALID_PARAMETER;
+  }
+
+  if ((MmcHostData->MmcHostIo.HostCapability.BusWidth8 == FALSE) && (BusWidth == 8)) {
+    DEBUG ((gMmcHostDebugLevel, "SetBusWidth: Invalid parameter \r\n"));
+    return EFI_INVALID_PARAMETER;
+  }
+  Data = MmcHostRead8 (MmcHostData, MMIO_HOSTCTL);
+
+  if (BusWidth == 8) {
+    DEBUG ((gMmcHostDebugLevel, "SetBusWidth: Bus Width is 8-bit ... \r\n"));
+    Data |= BIT5;
+  } else if (BusWidth == 4) {
+    DEBUG ((gMmcHostDebugLevel, "SetBusWidth: Bus Width is 4-bit ... \r\n"));
+    Data &= ~BIT5;
+    Data |= BIT1;
+  } else {
+    DEBUG ((gMmcHostDebugLevel, "SetBusWidth: Bus Width is 1-bit ... \r\n"));
+    Data &= ~BIT5;
+    Data &= ~BIT1;
+  }
+  MmcHostWrite8 (MmcHostData, MMIO_HOSTCTL, Data);
+  DEBUG ((gMmcHostDebugLevel, "SetBusWidth: MMIO_HOSTCTL value: 0x%x  \n", MmcHostRead8 (MmcHostData, MMIO_HOSTCTL)));
+
+  return EFI_SUCCESS;
+}
+
+
+/**
+  Set voltage which could supported by the host.
+  Support 0(Power off the host), 1.8V, 3.0V, 3.3V
+
+  @param[in]  This                       Pointer to EFI_MMC_HOST_IO_PROTOCOL
+  @param[in]  Voltage                    Units in 0.1 V
+
+  @retval     EFI_INVALID_PARAMETER
+  @retval     EFI_UNSUPPORTED
+  @retval     EFI_SUCCESS
+
+**/
+EFI_STATUS
+EFIAPI
+SetHostVoltage (
+  IN  EFI_MMC_HOST_IO_PROTOCOL    *This,
+  IN  UINT32                      Voltage
+  )
+{
+  MMCHOST_DATA                    *MmcHostData;
+  UINT8                           Data;
+  EFI_STATUS                      Status;
+
+  MmcHostData = MMCHOST_DATA_FROM_THIS (This);
+  Status = EFI_SUCCESS;
+
+  Data = MmcHostRead8 (MmcHostData, MMIO_PWRCTL);
+
+  if (Voltage == 0) {
+    //
+    //Power Off the host
+    //
+    Data &= ~BIT0;
+  } else if (Voltage <= 18 && This->HostCapability.V18Support) {
+    //
+    //1.8V
+    //
+    Data |= (BIT1 | BIT3 | BIT0);
+  } else if (Voltage > 18 &&  Voltage <= 30 && This->HostCapability.V30Support) {
+    //
+    //3.0V
+    //
+    Data |= (BIT2 | BIT3 | BIT0);
+  } else if (Voltage > 30 && Voltage <= 33 && This->HostCapability.V33Support) {
+    //
+    //3.3V
+    //
+    Data |= (BIT1 | BIT2 | BIT3 | BIT0);
+  } else {
+    Status = EFI_UNSUPPORTED;
+    goto Exit;
+  }
+
+  MmcHostWrite8 (MmcHostData, MMIO_PWRCTL, Data);
+  gBS->Stall (10);
+
+Exit:
+  return Status;
+}
+
+
+/**
+  Set Host High Speed
+
+  @param[in]  This                      Pointer to EFI_MMC_HOST_IO_PROTOCOL
+  @param[in]  HighSpeed                 True for High Speed Mode set, false for normal mode
+
+  @retval     EFI_INVALID_PARAMETER
+  @retval     EFI_SUCCESS
+
+**/
+EFI_STATUS
+EFIAPI
+SetHostSpeedMode(
+  IN  EFI_MMC_HOST_IO_PROTOCOL    *This,
+  IN  UINT32                      HighSpeed
+  )
+{
+  EFI_STATUS                      Status;
+  MMCHOST_DATA                    *MmcHostData;
+  UINT8                           Data8;
+
+  Status = EFI_SUCCESS;
+  MmcHostData = MMCHOST_DATA_FROM_THIS (This);
+
+  if (MmcHostData->IsEmmc) {
+    Data8 = MmcHostRead8 (MmcHostData, MMIO_HOSTCTL);
+    Data8 &= ~(BIT2);
+    if (HighSpeed) {
+      Data8 |= BIT2;
+      DEBUG ((gMmcHostDebugLevel, "High Speed mode: Data8=0x%x \n", Data8));
+    } else {
+      DEBUG ((gMmcHostDebugLevel, "Normal Speed mode: Data8=0x%x \n", Data8));
+    }
+    MmcHostWrite8 (MmcHostData, MMIO_HOSTCTL, Data8);
+    gBS->Stall (10);
+    DEBUG ((gMmcHostDebugLevel, "MMIO_HOSTCTL value: 0x%x  \n", MmcHostRead8 (MmcHostData, MMIO_HOSTCTL)));
+    return EFI_SUCCESS;
+  } else {
+    return EFI_INVALID_PARAMETER;
+  }
+}
+
+
+/**
+  Set Host mode in DDR
+
+  @param[in]  This                        Pointer to EFI_MMC_HOST_IO_PROTOCOL
+  @param[in]  SetHostDdrMode              True for DDR Mode set, false returns EFI_SUCCESS
+
+  @retval     EFI_INVALID_PARAMETER
+  @retval     EFI_SUCCESS
+
+**/
+EFI_STATUS
+EFIAPI
+SetHostDdrMode(
+  IN  EFI_MMC_HOST_IO_PROTOCOL   *This,
+  IN  UINT32                     DdrMode
+  )
+{
+  EFI_STATUS                     Status;
+  MMCHOST_DATA                   *MmcHostData;
+  UINT16                         ModeSet;
+
+  Status = EFI_SUCCESS;
+  MmcHostData = MMCHOST_DATA_FROM_THIS (This);
+
+  if (MmcHostData->IsEmmc) {
+    ModeSet = MmcHostRead16 (MmcHostData, MMIO_HOST_CTL2);
+    ModeSet &= ~(BIT0 | BIT1 | BIT2);
+    if (DdrMode) {
+      ModeSet |= 0x0004;
+      ModeSet |= BIT3;  //1.8v
+      DEBUG ((gMmcHostDebugLevel, "DDR mode: Data16=0x%x \n", ModeSet));
+    } else {
+      if (CheckControllerVersion (MmcHostData) != 2) {
+        ModeSet =  0x0;
+      }
+    }
+
+    MmcHostWrite16 (MmcHostData, MMIO_HOST_CTL2, ModeSet);
+    gBS->Stall (10);
+    DEBUG ((gMmcHostDebugLevel, "MMIO_HOST_CTL2 value: 0x%x  \n", MmcHostRead16 (MmcHostData, MMIO_HOST_CTL2)));
+    return EFI_SUCCESS;
+  } else {
+    return EFI_INVALID_PARAMETER;
+  }
+}
+
+
+/**
+  Set Host SDR Mode
+
+  @param[in] This                    Pointer to EFI_MMC_HOST_IO_PROTOCOL
+  @param[in] DdrMode                 True for SDR Mode set, false for normal mode
+
+  @retval    EFI_SUCCESS             The function completed successfully
+  @retval    EFI_INVALID_PARAMETER   A parameter was incorrect.
+
+**/
+EFI_STATUS
+EFIAPI
+SetHostSdrMode(
+  IN  EFI_MMC_HOST_IO_PROTOCOL    *This,
+  IN  UINT32                      SdrMode
+  )
+{
+  MMCHOST_DATA                    *MmcHostData;
+  UINT16                          ModeSet;
+
+  MmcHostData = MMCHOST_DATA_FROM_THIS (This);
+
+  if (MmcHostData->IsEmmc) {
+    ModeSet = MmcHostRead16 (MmcHostData, MMIO_HOST_CTL2);
+    ModeSet &= ~(BIT0 | BIT1 | BIT2);
+    if (SdrMode) {
+      if (MmcHostData->MmcHostIo.HostCapability.SDR104Support) {
+        ModeSet |= 3;
+      } else if (MmcHostData->MmcHostIo.HostCapability.SDR50Support) {
+        ModeSet |= 2;
+      }
+      ModeSet |= 1;
+      DEBUG ((gMmcHostDebugLevel, "SDR mode: Data16=0x%x \n", ModeSet));
+    } else {
+      if (CheckControllerVersion (MmcHostData) != 2) {
+        ModeSet =  0x0;
+      }
+    }
+
+    MmcHostWrite16 (MmcHostData, MMIO_HOST_CTL2, ModeSet);
+     gBS->Stall (10);
+    DEBUG ((gMmcHostDebugLevel, "MMIO_HOST_CTL2 value: 0x%x  \n", MmcHostRead16 (MmcHostData, MMIO_HOST_CTL2)));
+    return EFI_SUCCESS;
+  } else {
+    return EFI_INVALID_PARAMETER;
+  }
+}
+
+
+/**
+  Reset the host
+
+  @param[in] This                      Pointer to EFI_MMC_HOST_IO_PROTOCOL
+  @param[in] ResetType                 Reset data/cmd all
+
+  @retval    EFI_SUCCESS               The function completed successfully
+  @retval    EFI_TIMEOUT               The timeout time expired.
+
+**/
+EFI_STATUS
+EFIAPI
+ResetMmcHost (
+  IN  EFI_MMC_HOST_IO_PROTOCOL   *This,
+  IN  RESET_TYPE                 ResetType
+  )
+{
+  MMCHOST_DATA                   *MmcHostData;
+  UINT8                          Data8;
+  UINT32                         Data;
+  UINT16                         ErrStatus;
+  UINT8                          Mask;
+  UINT32                         TimeOutCount;
+  UINT16                         SaveClkCtl;
+  UINT16                         SavePwrCtl = 0;
+
+  MmcHostData = MMCHOST_DATA_FROM_THIS (This);
+  MmcHostData->IsEmmc = TRUE;
+  Mask = 0;
+  ErrStatus = 0;
+
+  if (ResetType == Reset_Auto) {
+    ErrStatus = MmcHostRead16 (MmcHostData, MMIO_ERINTSTS);
+    if ((ErrStatus & 0xF) != 0) {
+      //
+      //Command Line
+      //
+      Mask |= BIT1;
+    }
+    if ((ErrStatus & 0x70) != 0) {
+      //
+      //Data Line
+      //
+      Mask |= BIT2;
+    }
+  }
+
+  if (ResetType == Reset_DAT || ResetType == Reset_DAT_CMD) {
+    Mask |= BIT2;
+  }
+  if (ResetType == Reset_CMD || ResetType == Reset_DAT_CMD) {
+    Mask |= BIT1;
+  }
+  if (ResetType == Reset_All) {
+    Mask = BIT0;
+  }
+  if (ResetType == Reset_HW) {
+    SavePwrCtl = MmcHostRead16 (MmcHostData, MMIO_PWRCTL);
+    DEBUG ((gMmcHostDebugLevel, "Write SavePwrCtl: %x \n", (SavePwrCtl | BIT4)));
+
+    MmcHostWrite16 (MmcHostData, MMIO_PWRCTL, SavePwrCtl | BIT4);
+    gBS->Stall (10);
+    DEBUG ((gMmcHostDebugLevel, "Write SavePwrCtl: %x \n", (SavePwrCtl &(~BIT4))));
+    MmcHostWrite16 (MmcHostData, MMIO_PWRCTL, SavePwrCtl &(~BIT4));
+    gBS->Stall (10);
+  }
+
+  if (Mask == 0) {
+    return EFI_SUCCESS;
+  }
+
+  SaveClkCtl = MmcHostRead16 (MmcHostData, MMIO_CLKCTL);
+
+  MmcHostWrite16 (MmcHostData, MMIO_CLKCTL, 0);
+
+  gBS->Stall (10);
+
+  //
+  // Reset the MMC host controller
+  //
+  MmcHostWrite8 (MmcHostData, MMIO_SWRST, Mask);
+
+  Data = 0;
+  TimeOutCount  = TIME_OUT_1S;
+  do {
+    gBS->Stall (10);
+    TimeOutCount --;
+
+    Data8 = MmcHostRead8 (MmcHostData, MMIO_SWRST);
+    if ((Data8 & Mask) == 0) {
+      break;
+    }
+  } while (TimeOutCount > 0);
+
+  //
+  // We now restore the MMIO_CLKCTL register which we set to 0 above.
+  //
+  MmcHostWrite16 (MmcHostData, MMIO_CLKCTL, SaveClkCtl);
+
+  if (TimeOutCount == 0) {
+    DEBUG ((gMmcHostDebugLevel, "ResetMMCHost: Time out \n"));
+    return EFI_TIMEOUT;
+  }
+
+  return EFI_SUCCESS;
+}
+
+
+/**
+  Enable AutoStop Cmd
+
+  @param[in] This                Pointer to EFI_MMC_HOST_IO_PROTOCOL
+  @param[in] Enable              TRUE to enable
+
+  @retval    EFI_SUCCESS         The function completed successfully
+
+**/
+EFI_STATUS
+EFIAPI
+EnableAutoStopCmd (
+  IN  EFI_MMC_HOST_IO_PROTOCOL    *This,
+  IN  BOOLEAN                     Enable
+  )
+{
+  MMCHOST_DATA                    *MmcHostData;
+
+  MmcHostData = MMCHOST_DATA_FROM_THIS (This);
+
+  MmcHostData->IsAutoStopCmd = Enable;
+
+  return EFI_SUCCESS;
+}
+
+
+/**
+  Set the Block length
+
+  @param[in] This           Pointer to EFI_MMC_HOST_IO_PROTOCOL
+  @param[in] BlockLength    card supportes block length
+
+  @retval    EFI_SUCCESS
+
+**/
+EFI_STATUS
+EFIAPI
+SetBlockLength (
+  IN  EFI_MMC_HOST_IO_PROTOCOL   *This,
+  IN  UINT32                     BlockLength
+  )
+{
+  MMCHOST_DATA                   *MmcHostData;
+
+  MmcHostData = MMCHOST_DATA_FROM_THIS (This);
+
+  DEBUG ((gMmcHostDebugLevel, "SetBlockLength: Block length on the host controller: %d \n", BlockLength));
+  MmcHostData->BlockLength = BlockLength;
+
+  return EFI_SUCCESS;
+}
+
+
+/**
+  Detect card and init Sd host
+  Find whether these is a card inserted into the slot. If so
+  init the host. If not, return EFI_NOT_FOUND.
+
+  @param[in] This                    Pointer to EFI_MMC_HOST_IO_PROTOCOL
+
+  @retval    EFI_INVALID_PARAMETER
+  @retval    EFI_UNSUPPORTED
+  @retval    EFI_SUCCESS
+
+**/
+EFI_STATUS
+EFIAPI
+DetectCardAndInitHost (
+  IN  EFI_MMC_HOST_IO_PROTOCOL   *This
+  )
+{
+  MMCHOST_DATA                   *MmcHostData;
+  UINT16                         Data16;
+  UINT32                         Data;
+  EFI_STATUS                     Status;
+  UINT8                          Voltages[] = { 33, 30, 18 };
+  UINTN                          Loop;
+
+  MmcHostData = MMCHOST_DATA_FROM_THIS (This);
+
+  Data = 0;
+  Data = MmcHostRead32 (MmcHostData, MMIO_PSTATE);
+
+  if ((Data & (BIT16 | BIT17 | BIT18)) != (BIT16 | BIT17 | BIT18)) {
+    //
+    // Has no card inserted
+    //
+    DEBUG ((gMmcHostDebugLevel, "DetectCardAndInitHost: No card\n"));
+    Status =  EFI_NOT_FOUND;
+    goto Exit;
+  }
+  DEBUG ((gMmcHostDebugLevel, "DetectCardAndInitHost: Card present\n"));
+
+  //
+  //Enable normal status change
+  //
+  MmcHostWrite16 (MmcHostData, MMIO_NINTEN, BIT1 | BIT0);
+
+  //
+  // Enable error status change
+  //
+  Data16 = MmcHostRead16 (MmcHostData, MMIO_ERINTEN);
+  Data16 |= 0xFFFF; //(BIT0 | BIT1 | BIT2 | BIT3 | BIT4 | BIT5 | BIT6 | BIT7 | BIT8);
+  MmcHostWrite16 (MmcHostData, MMIO_ERINTEN, Data16);
+
+  //
+  // Data transfer Timeout control
+  //
+  MmcHostWrite8 (MmcHostData, MMIO_TOCTL, 0x0E);
+
+  //
+  // Stall 1 milliseconds to increase MMC stability.
+  //
+  gBS->Stall (10);
+
+  Status = SetClockFrequency (This, FREQUENCY_OD);
+  if (EFI_ERROR (Status)) {
+    DEBUG ((gMmcHostDebugLevel, "DetectCardAndInitHost: SetClockFrequency failed\n"));
+    goto Exit;
+  }
+  DEBUG ((gMmcHostDebugLevel, "DetectCardAndInitHost: SetClockFrequency done\n"));
+
+  Status =  EFI_NOT_FOUND;
+  for (Loop = 0; Loop < sizeof (Voltages); Loop++) {
+    DEBUG ((
+      EFI_D_INFO,
+      "DetectCardAndInitHost: SetHostVoltage %d.%dV\n",
+      Voltages[Loop] / 10,
+      Voltages[Loop] % 10
+      ));
+    Status = SetHostVoltage (This, Voltages[Loop]);
+    if (EFI_ERROR (Status)) {
+      DEBUG ((gMmcHostDebugLevel, "DetectCardAndInitHost: SetHostVoltage failed\n"));
+    } else {
+      DEBUG ((gMmcHostDebugLevel, "DetectCardAndInitHost: SetHostVoltage done\n"));
+      break;
+    }
+  }
+  if (EFI_ERROR (Status)) {
+    DEBUG ((gMmcHostDebugLevel, "DetectCardAndInitHost: Failed to SetHostVoltage\n"));
+    goto Exit;
+  }
+
+Exit:
+  return Status;
+}
+
+
+/**
+  Setup the MMC Host Device
+
+  @param[in] This            Pointer to EFI_MMC_HOST_IO_PROTOCOL
+
+  @retval    EFI_SUCCESS
+
+**/
+EFI_STATUS
+EFIAPI
+SetupDevice (
+  IN  EFI_MMC_HOST_IO_PROTOCOL    *This
+  )
+{
+  UINT32                          tempD = 0;
+  INT32                           timeOut = 1000;
+  UINT8                           temp8 = 0;
+  UINT16                          temp16 = 0;
+  MMCHOST_DATA                    *MmcHostData;
+
+  MmcHostData = MMCHOST_DATA_FROM_THIS (This);
+
+  //
+  // Reset HC and wait for self-clear
+  //
+  MmcHostWrite8 (MmcHostData, MMIO_SWRST, 0x7);
+  gBS->Stall (1000);
+  timeOut = 1000;
+  do {
+    temp8 = MmcHostRead8 (MmcHostData, MMIO_SWRST);
+    timeOut--;
+  } while ((temp8 & (1 << 0)) && (timeOut > 0));
+
+  DEBUG ((EFI_D_INFO, "Reset HC and wait for self-clear Done\n"));
+
+  //
+  // Enable all interrupt status bits (NO CARD_INTERRUPT!)
+  //
+  MmcHostWrite16 (MmcHostData, MMIO_NINTEN, 0x3);
+
+  //
+  // Clear all interrupt status bits
+  //
+  MmcHostWrite16 (MmcHostData, MMIO_NINTSTS, 0xFFFF);
+  MmcHostWrite16 (MmcHostData, MMIO_ERINTEN, 0xFFFF);
+
+  if (2 == CheckControllerVersion (MmcHostData))
+    temp16 = (UINT16) (0x1 << 6);
+  else
+    temp16 = (UINT16) (0x80 << 8);
+  //
+  // Set to 400KB, enable internal clock and wait for stability
+  //
+  MmcHostWrite32 (MmcHostData, MMIO_CLKCTL, (1<<0) | temp16);
+
+  gBS->Stall (1000);
+  do {
+    tempD = MmcHostRead32 (MmcHostData, MMIO_CLKCTL);
+    timeOut--;
+  } while ((!(tempD & (1 << 1))) && (timeOut > 0));
+  gBS->Stall (1000);
+
+  //
+  // Enable MMC clock
+  //
+  tempD |= (1 << 2);
+  MmcHostWrite32 (MmcHostData, MMIO_CLKCTL, tempD);
+  gBS->Stall (1000);
+
+  temp8 = MmcHostRead8 (MmcHostData, MMIO_PWRCTL);
+  DEBUG ((DEBUG_INFO, "==========%a, %d, offset=0x%x, PWRCTL = 0x%x================\n", __FUNCTION__, __LINE__, MMIO_PWRCTL, temp8));
+
+  //
+  // Apply 1.8V to the bus
+  //
+  temp8 = (0x5 << (1) );
+  MmcHostWrite8 (MmcHostData, MMIO_PWRCTL, temp8);
+  gBS->Stall (1000);
+  temp8 = MmcHostRead8 (MmcHostData, MMIO_PWRCTL);
+  DEBUG ((DEBUG_INFO, "==========%a, %d, set (0x5 << 1):offset=0x%x, PWRCTL = 0x%x================\n", __FUNCTION__, __LINE__, MMIO_PWRCTL, temp8));
+
+  //
+  // Set 1.8V sigaling Enabled
+  //
+  temp16 = MmcHostRead16 (MmcHostData, MMIO_HOST_CTL2);
+  temp16 &= ~BIT3;
+  MmcHostWrite16 (MmcHostData, MMIO_HOST_CTL2, temp16);
+  DEBUG ((gMmcHostDebugLevel, "Set 1.8 V signaling Enable:0x%x \r\n", MmcHostRead16 (MmcHostData, MMIO_HOST_CTL2)));
+
+  //
+  // Apply power to MMC
+  //
+  temp8 = MmcHostRead8 (MmcHostData, MMIO_PWRCTL);
+  DEBUG ((DEBUG_INFO, "==========%a, %d, read offset=0x%x, PWRCTL = 0x%x================\n", __FUNCTION__, __LINE__, MMIO_PWRCTL, temp8));
+
+  temp8 |= (1 << (0));
+  DEBUG ((DEBUG_INFO, "==========%a, %d, set 1<<0:offset=0x%x, PWRCTL = 0x%x================\n", __FUNCTION__, __LINE__, MMIO_PWRCTL, temp8));
+
+  MmcHostWrite8 (MmcHostData, MMIO_PWRCTL, temp8);
+  gBS->Stall (1000);              ///<synced to byt-cr pei. bxt power on used (50 * 1000)
+  temp8 = MmcHostRead8 (MmcHostData, MMIO_PWRCTL);
+
+  DEBUG ((DEBUG_INFO, "==========%a, %d, read offset=0x%x, PWRCTL = 0x%x================\n", __FUNCTION__, __LINE__, MMIO_PWRCTL, temp8));
+
+  //
+  // MAX out the DATA_TIMEOUT
+  //
+  MmcHostWrite8 (MmcHostData, MMIO_TOCTL, 0xE);
+  gBS->Stall (1000);
+
+  if (MmcHostData->EnableVerboseDebug) {
+    DEBUG ((EFI_D_INFO, "==========%a, Start. RegMap================\n", __FUNCTION__));
+    DEBUG ((DEBUG_INFO, "00 -10:  %08x  %08x  %08x  %08x \n", MmcHostRead32 (MmcHostData, 0x00), MmcHostRead32 (MmcHostData, 0x04), MmcHostRead32 (MmcHostData, 0x08), MmcHostRead32 (MmcHostData, 0x0C)));
+    DEBUG ((DEBUG_INFO, "10 -20:  %08x  %08x  %08x  %08x \n", MmcHostRead32 (MmcHostData, 0x10), MmcHostRead32 (MmcHostData, 0x14), MmcHostRead32 (MmcHostData, 0x18), MmcHostRead32 (MmcHostData, 0x1C)));
+    DEBUG ((DEBUG_INFO, "20 -30:  %08x  %08x  %08x  %08x \n", MmcHostRead32 (MmcHostData, 0x20), MmcHostRead32 (MmcHostData, 0x24), MmcHostRead32 (MmcHostData, 0x28), MmcHostRead32 (MmcHostData, 0x2C)));
+    DEBUG ((DEBUG_INFO, "30 -40:  %08x  %08x  %08x  %08x \n", MmcHostRead32 (MmcHostData, 0x30), MmcHostRead32 (MmcHostData, 0x34), MmcHostRead32 (MmcHostData, 0x38), MmcHostRead32 (MmcHostData, 0x3C)));
+    DEBUG ((DEBUG_INFO, "40 -50:  %08x  %08x  %08x  %08x \n", MmcHostRead32 (MmcHostData, 0x40), MmcHostRead32 (MmcHostData, 0x44), MmcHostRead32 (MmcHostData, 0x48), MmcHostRead32 (MmcHostData, 0x4C)));
+    DEBUG ((DEBUG_INFO, "50 -60:  %08x  %08x  %08x  %08x \n", MmcHostRead32 (MmcHostData, 0x50), MmcHostRead32 (MmcHostData, 0x54), MmcHostRead32 (MmcHostData, 0x58), MmcHostRead32 (MmcHostData, 0x5C)));
+    DEBUG ((DEBUG_INFO, "==========%a, END. RegMap================\n", __FUNCTION__));
+  }
+  return EFI_SUCCESS;
+}
+
diff --git a/Silicon/BroxtonSoC/BroxtonSiPkg/SouthCluster/Sdio/Dxe/MMC/MmcHostDxe/MmcHostDriver.c b/Silicon/BroxtonSoC/BroxtonSiPkg/SouthCluster/Sdio/Dxe/MMC/MmcHostDxe/MmcHostDriver.c
new file mode 100644
index 0000000..f94dc1d
--- /dev/null
+++ b/Silicon/BroxtonSoC/BroxtonSiPkg/SouthCluster/Sdio/Dxe/MMC/MmcHostDxe/MmcHostDriver.c
@@ -0,0 +1,613 @@
+/** @file
+  UEFI Driver Entry and Binding support.
+
+  Copyright (c) 1999 - 2016, Intel Corporation. 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 "MmcHostDriver.h"
+#include <PiDxe.h>
+
+//
+// MMCSDIOController Driver Global Variables
+//
+EFI_DRIVER_BINDING_PROTOCOL gMmcHostDriverBinding = {
+  MmcHostDriverBindingSupported,
+  MmcHostDriverBindingStart,
+  MmcHostDriverBindingStop,
+  0x10,
+  NULL,
+  NULL
+};
+
+
+EFI_MMC_HOST_IO_PROTOCOL  mMmcHostIo = {
+  EFI_MMC_HOST_IO_PROTOCOL_REVISION_01,
+  {
+    0, ///< HighSpeedSupport
+    0, ///< V18Support
+    0, ///< V30Support
+    0, ///< V33Support
+    0, ///< HS400Support
+    0, ///< BusWidth4
+    0, ///< BusWidth8
+    0, ///< Reserved1
+    0,
+    0,
+    0,
+    0,
+    0, ///< ADMA2Support
+    0, ///< DmaMode
+    0, ///< ReTune Timer
+    0, ///< ReTune Mode
+    0, ///< Reserved2
+    (512 * 1024) ///<BoundarySize 512 KB
+  },
+  SendCommand,
+  SetClockFrequency,
+  SetBusWidth,
+  SetHostVoltage,
+  SetHostDdrMode,
+  SetHostSdrMode,
+  ResetMmcHost,
+  EnableAutoStopCmd,
+  DetectCardAndInitHost,
+  SetBlockLength,
+  SetupDevice,
+  SetHostSpeedMode
+};
+
+
+/**
+  Entry point for MMC Host EFI drivers.
+
+  @param[in] ImageHandle          EFI_HANDLE
+  @param[in] SystemTable          EFI_SYSTEM_TABLE
+
+  @retval    EFI_SUCCESS          The function completed successfully
+  @retval    EFI_DEVICE_ERROR     The function failed to complete
+
+**/
+EFI_STATUS
+EFIAPI
+MmcHostDriverEntryPoint (
+  IN EFI_HANDLE           ImageHandle,
+  IN EFI_SYSTEM_TABLE     *SystemTable
+  )
+{
+  return EfiLibInstallAllDriverProtocols (
+           ImageHandle,
+           SystemTable,
+           &gMmcHostDriverBinding,
+           ImageHandle,
+           &gMmcHostComponentName,
+           NULL,
+           NULL
+           );
+}
+
+
+/**
+  Test to see if this MMC Host driver supports ControllerHandle.
+  Any ControllerHandle that has installed will be supported.
+
+  @param[in] This                    Protocol instance pointer
+  @param[in] Controller              Handle of device to test
+  @param[in] RemainingDevicePath     Not used
+
+  @retval    EFI_SUCCESS             This driver supports this device
+  @retval    EFI_UNSUPPORTED         This driver does not support this device
+
+**/
+EFI_STATUS
+EFIAPI
+MmcHostDriverBindingSupported (
+  IN EFI_DRIVER_BINDING_PROTOCOL *This,
+  IN EFI_HANDLE                  Controller,
+  IN EFI_DEVICE_PATH_PROTOCOL    *RemainingDevicePath
+  )
+{
+  EFI_STATUS                     Status;
+  EFI_PCI_IO_PROTOCOL            *PciIo;
+  EFI_MMC_HOST_IO_PROTOCOL       *MmcHostIo;
+  PCI_CLASSC                     PciClass;
+  UINT32                         VidDid;
+  UINT32                         Bar0 = 0;
+  UINT32                         Bar1 = 0;
+  UINTN                          Seg, Bus, Dev, Func;
+
+  //
+  // Verify the MMC IO Protocol, which installed by the
+  // IdeController module.
+  //
+  Status = gBS->OpenProtocol (
+                  Controller,
+                  &gEfiMmcHostIoProtocolGuid,
+                  (VOID **) &MmcHostIo,
+                  This->DriverBindingHandle,
+                  Controller,
+                  EFI_OPEN_PROTOCOL_GET_PROTOCOL
+                  );
+  if (!EFI_ERROR (Status)) {
+    DEBUG ((DEBUG_INFO, "MmcHost controller already started, Controller: 0x%016Lx\r\n",  (UINT64) (UINTN) Controller));
+    Status = EFI_ALREADY_STARTED;
+    return Status;
+  }
+
+  //
+  // Test whether there is PCI IO Protocol attached on the controller handle.
+  //
+  Status = gBS->OpenProtocol (
+                  Controller,
+                  &gEfiPciIoProtocolGuid,
+                  (VOID**) &PciIo,
+                  This->DriverBindingHandle,
+                  Controller,
+                  EFI_OPEN_PROTOCOL_BY_DRIVER
+                  );
+  if (EFI_ERROR (Status)) {
+    return Status;
+  }
+
+  Status = PciIo->Pci.Read (
+                        PciIo,
+                        EfiPciIoWidthUint32,
+                        PCI_VENDOR_ID_OFFSET,
+                        1,
+                        &VidDid
+                        );
+  if (EFI_ERROR (Status)) {
+    goto Exit;
+  }
+
+  Status = PciIo->Pci.Read (
+                        PciIo,
+                        EfiPciIoWidthUint8,
+                        PCI_CLASSCODE_OFFSET,
+                        sizeof (PCI_CLASSC) / sizeof (UINT8),
+                        &PciClass
+                        );
+  if (EFI_ERROR (Status)) {
+    Status = EFI_UNSUPPORTED;
+    goto Exit;
+  }
+
+  Status = PciIo->Pci.Read (
+                        PciIo,
+                        EfiPciIoWidthUint32,
+                        PCI_BASE_ADDRESSREG_OFFSET,
+                        1,
+                        &Bar0
+                        );
+  if (EFI_ERROR (Status)) {
+    Status = EFI_UNSUPPORTED;
+    goto Exit;
+  }
+
+  Status = PciIo->Pci.Read (
+                        PciIo,
+                        EfiPciIoWidthUint32,
+                        PCI_BASE_ADDRESSREG_OFFSET + 4,
+                        1,
+                        &Bar1
+                        );
+  if (EFI_ERROR (Status)) {
+    Status = EFI_UNSUPPORTED;
+    goto Exit;
+  }
+
+  Status = PciIo->GetLocation (
+                    PciIo,
+                    &Seg,
+                    &Bus,
+                    &Dev,
+                    &Func
+                    );
+
+  if (EFI_ERROR (Status)) {
+    Status = EFI_UNSUPPORTED;
+    goto Exit;
+  }
+
+  if ((Seg != 0) || (Bus != 0) || (Dev != 28) || (Func != 0)) {
+    //
+    // This is not the eMMC controller, bail.
+    //
+    Status = EFI_UNSUPPORTED;
+    goto Exit;
+  }
+
+  if ((PciClass.BaseCode != PCI_CLASS_SYSTEM_PERIPHERAL) ||
+     (PciClass.SubClassCode != PCI_SUBCLASS_SD_HOST_CONTROLLER) ||
+     ((PciClass.PI != PCI_IF_STANDARD_HOST_NO_DMA) && (PciClass.PI != PCI_IF_STANDARD_HOST_SUPPORT_DMA))
+     ) {
+    Status = EFI_UNSUPPORTED;
+    goto Exit;
+  }
+
+  DEBUG ((EFI_D_INFO, "MmcHostDriverBindingSupported0: Seg %d, bus:%d, Dev:%d, Func:%d\n", Seg, Bus, Dev, Func));
+  DEBUG ((EFI_D_INFO, "MmcHostDriverBindingSupported1: VidDid %08x\n", VidDid));
+  DEBUG ((EFI_D_INFO, "MmcHostDriverBindingSupported1: Base Code %x\n", PciClass.BaseCode));
+  DEBUG ((EFI_D_INFO, "MmcHostDriverBindingSupported1: SubClassCode %x\n", PciClass.SubClassCode));
+  DEBUG ((EFI_D_INFO, "MmcHostDriverBindingSupported1: PI %x\n", PciClass.PI));
+  DEBUG ((EFI_D_INFO, "MmcHostDriverBindingSupported0: MEMIO Base0 %x\n", Bar0));
+  DEBUG ((EFI_D_INFO, "MmcHostDriverBindingSupported0: MEMIO Base1 %x\n", Bar1));
+
+Exit:
+  gBS->CloseProtocol (
+         Controller,
+         &gEfiPciIoProtocolGuid,
+         This->DriverBindingHandle,
+         Controller
+         );
+  return Status;
+}
+
+
+/**
+  Starting the MMC Host Driver
+
+  @param[in] This                     Protocol instance pointer
+  @param[in] Controller               Handle of device to start
+  @param[in] RemainingDevicePath      Not used
+
+  @retval    EFI_SUCCESS              This driver start this device
+  @retval    EFI_UNSUPPORTED          This driver does not support this device
+  @retval    EFI_DEVICE_ERROR         This driver cannot be started due to device Error
+  @retval    EFI_OUT_OF_RESOURCES     This driver cannot allocate resources
+
+**/
+EFI_STATUS
+EFIAPI
+MmcHostDriverBindingStart (
+  IN EFI_DRIVER_BINDING_PROTOCOL     *This,
+  IN EFI_HANDLE                      Controller,
+  IN EFI_DEVICE_PATH_PROTOCOL        *RemainingDevicePath
+  )
+{
+  EFI_PCI_IO_PROTOCOL                *PciIo;
+  EFI_STATUS                         Status;
+  MMCHOST_DATA                       *MmcHostData;
+  UINT32                             Data;
+  UINT16                             Data16;
+  UINT32                             VidDid;
+  UINT32                             Bar0 = 0;
+  UINT32                             Bar1 = 0;
+  UINTN                              Seg, Bus, Dev, Func;
+
+  MmcHostData = NULL;
+  Data       = 0;
+  DEBUG ((EFI_D_INFO, "MmcHostDriverBindingStart: Start\n"));
+
+  //
+  // Open PCI I/O Protocol and save pointer to open protocol
+  // in private data area.
+  //
+  Status = gBS->OpenProtocol (
+                  Controller,
+                  &gEfiPciIoProtocolGuid,
+                  (VOID **) &PciIo,
+                  This->DriverBindingHandle,
+                  Controller,
+                  EFI_OPEN_PROTOCOL_BY_DRIVER
+                  );
+  if (EFI_ERROR (Status)) {
+    goto Exit;
+  }
+
+  //
+  // Enable the MMC Host Controller MMIO space
+  //
+  Status = PciIo->Attributes (
+                    PciIo,
+                    EfiPciIoAttributeOperationEnable,
+                    EFI_PCI_DEVICE_ENABLE,
+                    NULL
+                    );
+  if (EFI_ERROR (Status)) {
+    Status = EFI_OUT_OF_RESOURCES;
+    goto Exit;
+  }
+
+
+  MmcHostData = (MMCHOST_DATA *) AllocateZeroPool (sizeof (MMCHOST_DATA));
+  if (MmcHostData == NULL) {
+    Status =  EFI_OUT_OF_RESOURCES;
+    goto Exit;
+  }
+
+  MmcHostData->Signature   = MMCHOST_DATA_SIGNATURE;
+  MmcHostData->PciIo       = PciIo;
+
+  CopyMem (&MmcHostData->MmcHostIo, &mMmcHostIo, sizeof (EFI_MMC_HOST_IO_PROTOCOL));
+
+  Status = PciIo->Pci.Read (
+                        PciIo,
+                        EfiPciIoWidthUint32,
+                        PCI_VENDOR_ID_OFFSET,
+                        1,
+                        &VidDid
+                        );
+  if (EFI_ERROR (Status)) {
+    goto Exit;
+  }
+  DEBUG ((EFI_D_INFO, "MmcHostDriverBindingStart: VidDid = 0x%08x\n", VidDid));
+
+  Status = PciIo->GetLocation (
+                    PciIo,
+                    &Seg,
+                    &Bus,
+                    &Dev,
+                    &Func
+                    );
+  DEBUG ((EFI_D_INFO, "MmcHostDriverBindingStart: Seg %d, bus:%d,Dev:%d,Func:%d\n", Seg, Bus, Dev,Func));
+
+  MmcHostData->PciVid = (UINT16) (VidDid & 0xffff);
+  MmcHostData->PciDid = (UINT16) (VidDid >> 16);
+
+  Status = PciIo->Pci.Read (
+                        PciIo,
+                        EfiPciIoWidthUint32,
+                        PCI_BASE_ADDRESSREG_OFFSET,
+                        1,
+                        &Bar0
+                        );
+
+  Status = PciIo->Pci.Read (
+                        PciIo,
+                        EfiPciIoWidthUint32,
+                        PCI_BASE_ADDRESSREG_OFFSET + 4,
+                        1,
+                        &Bar1
+                        );
+
+  DEBUG ((EFI_D_INFO, "MmcHostDriverBindingStart: MEMIO Base0 %x\n", Bar0));
+  DEBUG ((EFI_D_INFO, "MmcHostDriverBindingStart: MEMIO Base1 %x\n", Bar1));
+
+
+  MmcHostData->MmcHostIo.ResetMmcHost (&MmcHostData->MmcHostIo, Reset_All);
+  MmcHostData->EnableVerboseDebug = FALSE;
+
+  PciIo->Mem.Read (
+               PciIo,
+               EfiPciIoWidthUint16,
+               0,
+               (UINT64) MMIO_CTRLRVER,
+               1,
+               &Data16
+               );
+
+  DEBUG ((EFI_D_INFO, "MmcHostDriverBindingStart: MMIO_CTRLRVER = 0x%08x\n", Data16));
+
+  MmcHostData->ControllerVersion = Data16 & 0xFF;
+  switch (MmcHostData->ControllerVersion) {
+    case 0: DEBUG ((EFI_D_INFO, "MmcHostDriverBindingStart: MMC Host Controller Version 1.0\n")); break;
+    case 1: DEBUG ((EFI_D_INFO, "MmcHostDriverBindingStart: MMC Host Controller Version 2.0\n")); break;
+    case 2: DEBUG ((EFI_D_INFO, "MmcHostDriverBindingStart: MMC Host Controller Version 3.0\n")); break;
+    default:
+      DEBUG ((EFI_D_INFO, "MmcHostDriverBindingStart: Unknown MMC Host Controller Version, Stopping Driver!!\n"));
+      goto Exit;
+  }
+
+  PciIo->Mem.Read (
+               PciIo,
+               EfiPciIoWidthUint32,
+               0,
+               (UINT32) MMIO_CAP,
+               1,
+               &Data
+               );
+  DEBUG ((EFI_D_INFO, "MmcHostDriverBindingStart: Low MMIO_CAP = 0x%08x\n", Data));
+
+  if ((Data & BIT18) != 0) {
+    MmcHostData->MmcHostIo.HostCapability.BusWidth8 = TRUE;
+    DEBUG ((EFI_D_INFO, "MmcHostDriverBindingStart: BusWidth8\n"));
+  }
+
+  MmcHostData->MmcHostIo.HostCapability.BusWidth4 = TRUE;
+  DEBUG ((EFI_D_INFO, "MmcHostDriverBindingStart: BusWidth4\n"));
+
+  if ((Data & BIT19) != 0) {
+    MmcHostData->MmcHostIo.HostCapability.ADMA2Support = TRUE;
+    DEBUG ((EFI_D_INFO, "MmcHostDriverBindingStart: ADMA2Support\n"));
+  }
+
+  if ((Data & BIT21) != 0) {
+    MmcHostData->MmcHostIo.HostCapability.HighSpeedSupport = TRUE;
+    DEBUG ((EFI_D_INFO, "MmcHostDriverBindingStart: HighSpeedSupport\n"));
+  }
+
+  if ((Data & BIT22) != 0) {
+    MmcHostData->MmcHostIo.HostCapability.SDMASupport = TRUE;
+    DEBUG ((EFI_D_INFO, "MmcHostDriverBindingStart: SDMASupport\n"));
+  }
+
+  if ((Data & BIT24) != 0) {
+    MmcHostData->MmcHostIo.HostCapability.V33Support = TRUE;
+    DEBUG ((EFI_D_INFO, "MmcHostDriverBindingStart: V33Support\n"));
+  }
+
+  if ((Data & BIT25) != 0) {
+    MmcHostData->MmcHostIo.HostCapability.V30Support = TRUE;
+    DEBUG ((EFI_D_INFO, "MmcHostDriverBindingStart: V30Support\n"));
+  }
+
+  if ((Data & BIT26) != 0) {
+    MmcHostData->MmcHostIo.HostCapability.V18Support = TRUE;
+    DEBUG ((EFI_D_INFO, "MmcHostDriverBindingStart: V18Support\n"));
+  }
+
+  if (((Data) & (BIT30 | BIT31)) == 0) {
+    DEBUG ((EFI_D_INFO, "MmcHostDriverBindingStart: Removable Card Slot\n"));
+  } else if ((Data & BIT30) && (Data & (~BIT31))) {
+    DEBUG ((EFI_D_INFO, "MmcHostDriverBindingStart: Embedded Slot for One Device\n"));
+  }
+  MmcHostData->BaseClockInMHz = (Data >> 8) & 0xFF;
+
+  PciIo->Mem.Read (
+               PciIo,
+               EfiPciIoWidthUint32,
+               0,
+               (UINT32) (MMIO_CAP + 4),
+               1,
+               &Data
+               );
+
+  DEBUG ((EFI_D_INFO, "MmcHostDriverBindingStart: High MMIO_CAP = 0x%08x\n", Data));
+
+
+
+  if ((Data & 0x1<<(32-32)) != 0) {
+    MmcHostData->MmcHostIo.HostCapability.SDR50Support= TRUE;
+    DEBUG ((EFI_D_INFO, "MmcHostDriverBindingStart: SDR50Support\n"));
+  }
+
+  if ((Data & 0x1<<(33-32)) != 0) {
+    MmcHostData->MmcHostIo.HostCapability.SDR104Support= TRUE;
+    DEBUG ((EFI_D_INFO, "MmcHostDriverBindingStart: SDR104Support\n"));
+  }
+
+  if ((Data & 0x1<<(34-32)) != 0) {
+    MmcHostData->MmcHostIo.HostCapability.DDR50Support= TRUE;
+    DEBUG ((EFI_D_INFO, "MmcHostDriverBindingStart: DDR50Support\n"));
+  }
+
+  if ((Data & 0x1<<(63-32)) != 0) {
+    MmcHostData->MmcHostIo.HostCapability.HS400Support = TRUE;
+    DEBUG ((EFI_D_INFO, "MmcHostDriverBindingStart: HS400Support\n"));
+  }
+
+  if (MmcHostData->ControllerVersion >= 2) {
+    MmcHostData->MmcHostIo.HostCapability.ReTuneMode = (Data >> (46-32)) & 0x3;
+    DEBUG ((EFI_D_INFO, "MmcHostDriverBindingStart:  ReTuneMode = 0x%08x\n", MmcHostData->MmcHostIo.HostCapability.ReTuneMode));
+
+    MmcHostData->MmcHostIo.HostCapability.ReTuneTimer = (Data>>(40-32)) & 0xF;
+    DEBUG ((EFI_D_INFO, "MmcHostDriverBindingStart:  ReTuneTimer = 0x%08x\n", MmcHostData->MmcHostIo.HostCapability.ReTuneTimer));
+  }
+
+
+  MmcHostData->BlockLength    = BLOCK_SIZE;
+  MmcHostData->IsAutoStopCmd  = TRUE;
+
+  Status = gBS->InstallProtocolInterface (
+                  &Controller,
+                  &gEfiMmcHostIoProtocolGuid,
+                  EFI_NATIVE_INTERFACE,
+                  &MmcHostData->MmcHostIo
+                  );
+  if (EFI_ERROR (Status)) {
+    goto Exit;
+  }
+
+  //
+  // Component name protocol
+  //
+  Status = AddUnicodeString (
+             "eng",
+             gMmcHostComponentName.SupportedLanguages,
+             &MmcHostData->ControllerNameTable,
+             L"MMC Host Controller"
+             );
+  if (EFI_ERROR (Status)) {
+    Status = EFI_OUT_OF_RESOURCES;
+    gBS->UninstallProtocolInterface (
+           Controller,
+           &gEfiMmcHostIoProtocolGuid,
+           &MmcHostData->MmcHostIo
+           );
+  }
+
+  DEBUG ((EFI_D_INFO, "MmcHostDriverBindingStart: Host Started\n"));
+
+Exit:
+  if (EFI_ERROR (Status)) {
+    if (MmcHostData != NULL) {
+      FreePool (MmcHostData);
+    }
+    gBS->CloseProtocol (
+           Controller,
+           &gEfiPciIoProtocolGuid,
+           This->DriverBindingHandle,
+           Controller
+           );
+  }
+  return Status;
+}
+
+
+/**
+  Stop MMC Host driver on ControllerHandle. Support stoping any child handles
+  created by this driver.
+
+  @param[in] This                  Protocol instance pointer
+  @param[in] Controller            Handle of device to stop driver on
+  @param[in] NumberOfChildren      Number of Children in the ChildHandleBuffer
+  @param[in] ChildHandleBuffer     List of handles for the children we need to stop
+
+  @retval    EFI_SUCCESS           This driver stop this device
+  @retval    EFI_DEVICE_ERROR      This driver cannot be stop due to device Error
+
+**/
+EFI_STATUS
+EFIAPI
+MmcHostDriverBindingStop (
+  IN  EFI_DRIVER_BINDING_PROTOCOL     *This,
+  IN  EFI_HANDLE                      Controller,
+  IN  UINTN                           NumberOfChildren,
+  IN  EFI_HANDLE                      *ChildHandleBuffer
+  )
+{
+  EFI_STATUS                          Status;
+  EFI_MMC_HOST_IO_PROTOCOL            *MmcHostIo;
+  MMCHOST_DATA                        *MmcHostData;
+
+  Status = gBS->OpenProtocol (
+                  Controller,
+                  &gEfiMmcHostIoProtocolGuid,
+                  (VOID **) &MmcHostIo,
+                  This->DriverBindingHandle,
+                  Controller,
+                  EFI_OPEN_PROTOCOL_GET_PROTOCOL
+                  );
+  if (EFI_ERROR (Status)) {
+    goto _exit_MmcHostDriverBindingStop;
+  }
+
+  gBS->CloseProtocol (
+         Controller,
+         &gEfiPciIoProtocolGuid,
+         This->DriverBindingHandle,
+         Controller
+         );
+
+  MmcHostData  = MMCHOST_DATA_FROM_THIS (MmcHostIo);
+
+  //
+  // Uninstall Block I/O protocol from the device handle
+  //
+  Status = gBS->UninstallProtocolInterface (
+                  Controller,
+                  &gEfiMmcHostIoProtocolGuid,
+                  &MmcHostData->MmcHostIo
+                  );
+  if (EFI_ERROR (Status)) {
+    goto _exit_MmcHostDriverBindingStop;
+  }
+
+  FreeUnicodeStringTable (MmcHostData->ControllerNameTable);
+  FreePool (MmcHostData);
+
+_exit_MmcHostDriverBindingStop:
+  DEBUG ((EFI_D_INFO, "MmcHostDriverBindingStop exited with Status %r\n", Status));
+
+  return Status;
+}
+
diff --git a/Silicon/BroxtonSoC/BroxtonSiPkg/SouthCluster/Sdio/Dxe/MMC/MmcHostDxe/MmcHostDriver.h b/Silicon/BroxtonSoC/BroxtonSiPkg/SouthCluster/Sdio/Dxe/MMC/MmcHostDxe/MmcHostDriver.h
new file mode 100644
index 0000000..f724061
--- /dev/null
+++ b/Silicon/BroxtonSoC/BroxtonSiPkg/SouthCluster/Sdio/Dxe/MMC/MmcHostDxe/MmcHostDriver.h
@@ -0,0 +1,585 @@
+/** @file
+  Header file for MMC driver.
+
+  Copyright (c) 1999 - 2016, Intel Corporation. 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 _MMC_HOST_DRIVER_H
+#define _MMC_HOST_DRIVER_H
+
+#include <Uefi.h>
+#include <Library/UefiDriverEntryPoint.h>
+#include <Library/DebugLib.h>
+#include <Library/UefiBootServicesTableLib.h>
+#include <Library/BaseMemoryLib.h>
+#include <Library/MemoryAllocationLib.h>
+#include <Library/UefiLib.h>
+#include <Library/DevicePathLib.h>
+#include <Library/IoLib.h>
+#include <IndustryStandard/Pci.h>
+#include <IndustryStandard/SdCard.h>
+#include <ScAccess.h>
+
+//
+// Driver Consumed Protocol Prototypes
+//
+#include <Protocol/DevicePath.h>
+#include <Protocol/PciIo.h>
+
+//
+// Driver Produced Protocol Prototypes
+//
+#include <Protocol/DriverBinding.h>
+#include <Protocol/ComponentName.h>
+#include <Protocol/ComponentName2.h>
+#include <Protocol/MmcHostIo.h>
+
+extern EFI_COMPONENT_NAME_PROTOCOL  gMmcHostComponentName;
+extern EFI_DRIVER_BINDING_PROTOCOL  gMmcHostDriverBinding;
+
+#define MMCHOST_DATA_SIGNATURE  SIGNATURE_32 ('m', 'c', 'h', 's')
+
+#define MMCHOST_DATA_FROM_THIS(a) \
+    CR (a, MMCHOST_DATA, MmcHostIo, MMCHOST_DATA_SIGNATURE)
+
+#define BLOCK_SIZE          0x200
+#define TIME_OUT_1S         1000
+
+#define INTEL_VENDOR_ID     0x8086
+
+#define BUFFER_CTL_REGISTER 0x84
+
+#pragma pack(1)
+//
+// PCI Class Code structure
+//
+typedef struct {
+  UINT8 PI;
+  UINT8 SubClassCode;
+  UINT8 BaseCode;
+} PCI_CLASSC;
+
+#pragma pack()
+
+//
+// MMCHOST_DATA structure
+//
+typedef struct {
+  UINTN                      Signature;
+  EFI_MMC_HOST_IO_PROTOCOL   MmcHostIo;
+  EFI_PCI_IO_PROTOCOL        *PciIo;
+  UINT16                     PciVid;
+  UINT16                     PciDid;
+  BOOLEAN                    IsAutoStopCmd;
+  BOOLEAN                    IsEmmc;
+  BOOLEAN                    EnableVerboseDebug;
+  UINT32                     BaseClockInMHz;
+  UINT32                     CurrentClockInKHz;
+  UINT32                     BlockLength;
+  EFI_UNICODE_STRING_TABLE   *ControllerNameTable;
+  UINT32                     ControllerVersion;
+} MMCHOST_DATA;
+
+//
+// Prototypes
+// Driver model protocol interface
+//
+/**
+  Entry point for MMC Host EFI drivers.
+
+  @param[in] ImageHandle               EFI_HANDLE
+  @param[in] SystemTable               EFI_SYSTEM_TABLE
+
+  @retval    EFI_SUCCESS               The function completed successfully
+  @retval    EFI_DEVICE_ERROR          The function failed to complete
+
+**/
+EFI_STATUS
+EFIAPI
+MmcHostDriverEntryPoint (
+  IN EFI_HANDLE           ImageHandle,
+  IN EFI_SYSTEM_TABLE     *SystemTable
+  );
+
+/**
+  Test to see if this MMC Host driver supports ControllerHandle.
+  Any ControllerHandle that has installed will be supported.
+
+  @param[in] This                  Protocol instance pointer
+  @param[in] Controller            Handle of device to test
+  @param[in] RemainingDevicePath   Not used
+
+  @retval    EFI_SUCCESS           This driver supports this device
+  @retval    EFI_UNSUPPORTED       This driver does not support this device
+
+**/
+EFI_STATUS
+EFIAPI
+MmcHostDriverBindingSupported (
+  IN EFI_DRIVER_BINDING_PROTOCOL     *This,
+  IN EFI_HANDLE                      Controller,
+  IN EFI_DEVICE_PATH_PROTOCOL        *RemainingDevicePath
+  );
+
+/**
+  Starting the MMC Host Driver
+
+  @param[in] This                     Protocol instance pointer
+  @param[in] Controller               Handle of device to start
+  @param[in] RemainingDevicePath      Not used
+
+  @retval    EFI_SUCCESS              This driver start this device
+  @retval    EFI_UNSUPPORTED          This driver does not support this device
+  @retval    EFI_DEVICE_ERROR         This driver cannot be started due to device Error
+  @retval    EFI_OUT_OF_RESOURCES     This driver cannot allocate resources
+
+**/
+EFI_STATUS
+EFIAPI
+MmcHostDriverBindingStart (
+  IN EFI_DRIVER_BINDING_PROTOCOL      *This,
+  IN EFI_HANDLE                       Controller,
+  IN EFI_DEVICE_PATH_PROTOCOL         *RemainingDevicePath
+  );
+
+/**
+  Stop MMC Host driver on ControllerHandle. Support stopping any child handles
+  created by this driver.
+
+  @param[in] This                     Protocol instance pointer
+  @param[in] Controller               Handle of device to stop driver on
+  @param[in] NumberOfChildren         Number of Children in the ChildHandleBuffer
+  @param[in] ChildHandleBuffer        List of handles for the children we need to stop
+
+  @retval    EFI_SUCCESS              This driver stop this device
+  @retval    EFI_DEVICE_ERROR         This driver cannot be stop due to device Error
+
+**/
+EFI_STATUS
+EFIAPI
+MmcHostDriverBindingStop (
+  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 EFI Driver.
+
+  @param[in]  This                    A pointer to the EFI_COMPONENT_NAME_PROTOCOL instance.
+  @param[in]  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[out] DriverName              A pointer to the Unicode string to return.  This Unicode string
+                                      is the name of the driver specified by This in the language
+                                      specified by Language.
+
+
+  @retval     EFI_SUCCESS             The Unicode string for the Driver specified by This
+                                      and the language specified by Language was returned
+                                      in DriverName.
+  @retval     EFI_INVALID_PARAMETER   Language is NULL.
+  @retval     EFI_INVALID_PARAMETER   DriverName is NULL.
+  @retval     EFI_UNSUPPORTED         The driver specified by This does not support the
+                                      language specified by Language.
+
+**/
+EFI_STATUS
+EFIAPI
+MmcHostComponentNameGetDriverName (
+  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 an EFI Driver.
+
+  @param[in]  This                    A pointer to the EFI_COMPONENT_NAME_PROTOCOL instance.
+  @param[in]  ControllerHandle        The handle of a controller that the driver specified by
+                                      This is managing.  This handle specifies the controller
+                                      whose name is to be returned.
+  @param[in]  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[in]  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[out] ControllerName          A pointer to the Unicode string to return.  This Unicode
+                                      string is the name of the controller specified by
+                                      ControllerHandle and ChildHandle in the language
+                                      specified by Language from the point of view of the
+                                      driver specified by This.
+
+
+  @retval     EFI_SUCCESS             The Unicode string for the user readable name in the
+                                      language specified by Language for the driver
+                                      specified by This was returned in DriverName.
+  @retval     EFI_INVALID_PARAMETER   ControllerHandle is not a valid EFI_HANDLE.
+  @retval     EFI_INVALID_PARAMETER   ChildHandle is not NULL and it is not a valid
+                                      EFI_HANDLE.
+  @retval     EFI_INVALID_PARAMETER   Language is NULL.
+  @retval     EFI_INVALID_PARAMETER   ControllerName is NULL.
+  @retval     EFI_UNSUPPORTED         The driver specified by This is not currently
+                                      managing the controller specified by
+                                      ControllerHandle and ChildHandle.
+  @retval     EFI_UNSUPPORTED         The driver specified by This does not support the
+                                      language specified by Language.
+
+**/
+EFI_STATUS
+EFIAPI
+MmcHostComponentNameGetControllerName (
+  IN  EFI_COMPONENT_NAME_PROTOCOL     *This,
+  IN  EFI_HANDLE                      ControllerHandle,
+  IN  EFI_HANDLE                      ChildHandle, OPTIONAL
+  IN  CHAR8                           *Language,
+  OUT CHAR16                          **ControllerName
+  );
+
+/**
+  The main function used to send the command to the card inserted into the MMC host
+  slot.
+  It will assemble the arguments to set the command register and wait for the command
+  and transfer completed until timeout. Then it will read the response register to fill
+  the ResponseData
+
+  @param[in]  This                      Pointer to the EFI_COMPONENT_NAME_PROTOCOL instance.
+  @param[in]  CommandIndex              The command index to set the command index field of command register
+  @param[in]  Argument                  Command argument to set the argument field of command register
+  @param[in]  DataType                  TRANSFER_TYPE, indicates no data, data in or data out
+  @param[in]  Buffer                    Contains the data read from / write to the device
+  @param[in]  BufferSize                The size of the buffer
+  @param[in]  ResponseType              RESPONSE_TYPE
+  @param[in]  TimeOut                   Time out value in 1 ms unit
+  @param[out] ResponseData              Depending on the ResponseType, such as CSD or card status
+
+  @retval     EFI_SUCCESS
+  @retval     EFI_INVALID_PARAMETER
+  @retval     EFI_OUT_OF_RESOURCES
+  @retval     EFI_TIMEOUT
+  @retval     EFI_DEVICE_ERROR
+
+**/
+EFI_STATUS
+EFIAPI
+SendCommand (
+  IN   EFI_MMC_HOST_IO_PROTOCOL   *This,
+  IN   UINT16                     CommandIndex,
+  IN   UINT32                     Argument,
+  IN   TRANSFER_TYPE              DataType,
+  IN   UINT8                      *Buffer, OPTIONAL
+  IN   UINT32                     BufferSize,
+  IN   RESPONSE_TYPE              ResponseType,
+  IN   UINT32                     TimeOut,
+  OUT  UINT32                     *ResponseData OPTIONAL
+  );
+
+/**
+  Set max clock frequency of the host, the actual frequency
+  may not be the same as MaxFrequencyInKHz. It depends on
+  the max frequency the host can support, divider, and host
+  speed mode.
+
+  @param[in]  This               Pointer to EFI_MMC_HOST_IO_PROTOCOL
+  @param[in]  MaxFrequency       Max frequency in HZ
+
+  @retval     EFI_SUCCESS
+  @retval     EFI_TIMEOUT
+**/
+EFI_STATUS
+EFIAPI
+SetClockFrequency (
+  IN  EFI_MMC_HOST_IO_PROTOCOL   *This,
+  IN  UINT32                     MaxFrequencyInKHz
+  );
+
+/**
+  Set bus width of the host
+
+  @param[in]  This                  Pointer to EFI_MMC_HOST_IO_PROTOCOL
+  @param[in]  BusWidth              Bus width in 1, 4, 8 bits
+
+
+  @retval     EFI_STATUS
+  @retval     EFI_INVALID_PARAMETER
+
+**/
+EFI_STATUS
+EFIAPI
+SetBusWidth (
+  IN  EFI_MMC_HOST_IO_PROTOCOL   *This,
+  IN  UINT32                     BusWidth
+  );
+
+/**
+  Set voltage which could supported by the host.
+  Support 0(Power off the host), 1.8V, 3.0V, 3.3V
+
+  @param[in]  This                   Pointer to EFI_MMC_HOST_IO_PROTOCOL
+  @param[in]  Voltage                Units in 0.1 V
+
+  @retval     EFI_SUCCESS
+  @retval     EFI_INVALID_PARAMETER
+
+**/
+EFI_STATUS
+EFIAPI
+SetHostVoltage (
+  IN  EFI_MMC_HOST_IO_PROTOCOL   *This,
+  IN  UINT32                     Voltage
+  );
+
+/**
+  Set Host mode in DDR
+
+  @param[in]  This              Pointer to EFI_MMC_HOST_IO_PROTOCOL
+  @param[in]  DdrMode           True for DDR Mode set, false returns EFI_SUCCESS
+
+  @retval     EFI_SUCCESS
+  @retval     EFI_INVALID_PARAMETER
+
+**/
+EFI_STATUS
+EFIAPI
+SetHostDdrMode (
+  IN  EFI_MMC_HOST_IO_PROTOCOL   *This,
+  IN UINT32                      DdrMode
+  );
+
+/**
+  Set Host SDR Mode
+
+  @param[in] This                     Pointer to EFI_MMC_HOST_IO_PROTOCOL
+  @param[in] DdrMode                  True for SDR Mode set, false for normal mode
+
+  @retval    EFI_SUCCESS              The function completed successfully
+  @retval    EFI_INVALID_PARAMETER    A parameter was incorrect.
+
+**/
+EFI_STATUS
+EFIAPI
+SetHostSdrMode (
+  IN  EFI_MMC_HOST_IO_PROTOCOL   *This,
+  IN UINT32                      SdrMode
+  );
+
+/**
+  Set Host High Speed
+
+  @param[in] This                     Pointer to EFI_MMC_HOST_IO_PROTOCOL
+  @param[in] HighSpeed                True for High Speed Mode set, false for normal mode
+
+  @retval    EFI_SUCCESS              The function completed successfully
+  @retval    EFI_INVALID_PARAMETER    A parameter was incorrect.
+
+**/
+EFI_STATUS
+EFIAPI
+SetHostSpeedMode (
+  IN  EFI_MMC_HOST_IO_PROTOCOL   *This,
+  IN  UINT32                     HighSpeed
+  );
+
+/**
+  Reset the host
+
+  @param[in] This                    Pointer to EFI_MMC_HOST_IO_PROTOCOL
+  @param[in] ResetAll                TRUE to reset all
+
+  @retval    EFI_SUCCESS             The function completed successfully
+  @retval    EFI_TIMEOUT             The timeout time expired.
+
+**/
+EFI_STATUS
+EFIAPI
+ResetMmcHost (
+  IN  EFI_MMC_HOST_IO_PROTOCOL   *This,
+  IN  RESET_TYPE                 ResetType
+  );
+
+/**
+  Reset the host
+
+  @param[in] This                    Pointer to EFI_MMC_HOST_IO_PROTOCOL
+  @param[in] ResetAll                TRUE to reset all
+
+  @retval    EFI_SUCCESS             The function completed successfully
+  @retval    EFI_TIMEOUT             The timeout time expired.
+
+**/
+EFI_STATUS
+EFIAPI
+EnableAutoStopCmd (
+  IN  EFI_MMC_HOST_IO_PROTOCOL       *This,
+  IN  BOOLEAN                        Enable
+  );
+
+/**
+  Find whether these is a card inserted into the slot. If so
+  init the host. If not, return EFI_NOT_FOUND.
+
+  @param[in]  This                 Pointer to EFI_MMC_HOST_IO_PROTOCOL
+
+  @retval     EFI_SUCCESS          Success
+  @retval     EFI_DEVICE_ERROR     Fail
+
+**/
+EFI_STATUS
+EFIAPI
+DetectCardAndInitHost (
+  IN  EFI_MMC_HOST_IO_PROTOCOL    *This
+  );
+
+/**
+  Set the Block length
+
+  @param[in]  This                Pointer to EFI_MMC_HOST_IO_PROTOCOL
+  @param[in]  BlockLength         card supports block length
+
+  @retval     EFI_SUCCESS         Success
+  @retval     EFI_DEVICE_ERROR    Fail
+
+**/
+EFI_STATUS
+EFIAPI
+SetBlockLength (
+  IN  EFI_MMC_HOST_IO_PROTOCOL   *This,
+  IN  UINT32                     BlockLength
+  );
+
+/**
+  Setup Device
+
+  @param[in]  This                 Pointer to EFI_MMC_HOST_IO_PROTOCOL
+
+  @retval     EFI_SUCCESS          Success
+  @retval     EFI_DEVICE_ERROR     Fail
+
+**/
+EFI_STATUS
+EFIAPI
+SetupDevice(
+  IN  EFI_MMC_HOST_IO_PROTOCOL    *This
+  );
+
+/**
+  Read MMC host register
+
+  @param[in]  MmcHost                Pointer to EFI_MMC_HOST_IO_PROTOCOL
+  @param[in]  Offset                 Offset of the eMMC
+
+  @retval     Data                   Data read from eMMC
+
+**/
+UINT8
+MmcHostRead8 (
+  IN     MMCHOST_DATA                 *MmcHost,
+  IN     UINTN                        Offset
+  );
+
+/**
+  Read MMC host register
+
+  @param[in]  MmcHost       Pointer to EFI_MMC_HOST_IO_PROTOCOL
+  @param[in]  Offset        Offset of the eMMC
+
+  @retval     Data          Data read from eMMC
+
+**/
+UINT16
+MmcHostRead16 (
+  IN     MMCHOST_DATA        *MmcHost,
+  IN     UINTN               Offset
+  );
+
+/**
+  Read MMC host register
+
+  @param[in]  MmcHost        Pointer to EFI_MMC_HOST_IO_PROTOCOL
+  @param[in]  Offset         Offset of the eMMC
+
+  @retval     Data           Data read from eMMC
+
+**/
+UINT32
+MmcHostRead32 (
+  IN     MMCHOST_DATA                 *MmcHost,
+  IN     UINTN                        Offset
+  );
+
+/**
+  Write MMC host register
+
+  @param[in]  MmcHost    Pointer to EFI_MMC_HOST_IO_PROTOCOL
+  @param[in]  Offset     Offset of the eMMC
+  @param[in]  Data       Data write to eMMC
+
+  @retval     Data       Written to MmcHost
+
+**/
+UINT8
+MmcHostWrite8 (
+  IN     MMCHOST_DATA    *MmcHost,
+  IN     UINTN           Offset,
+  IN     UINT8           Data
+  );
+
+/**
+  Write MMC host register
+
+  @param[in]  MmcHost    Pointer to EFI_MMC_HOST_IO_PROTOCOL
+  @param[in]  Offset     Offset of the eMMC
+  @param[in]  Data       Data write to eMMC
+
+  @retval     Data       Data written to eMMC
+
+**/
+UINT16
+MmcHostWrite16 (
+  IN     MMCHOST_DATA    *MmcHost,
+  IN     UINTN           Offset,
+  IN     UINT16          Data
+  );
+
+/**
+  Write MMC host register
+
+  @param[in]  MmcHost        Pointer to EFI_MMC_HOST_IO_PROTOCOL
+  @param[in]  Offset         Offset of the eMMC
+  @param[in]  Data           Data write to eMMC
+
+  @retval     Data           Data written to eMMC
+
+**/
+UINT32
+MmcHostWrite32 (
+  IN     MMCHOST_DATA        *MmcHost,
+  IN     UINTN               Offset,
+  IN     UINT32              Data
+  );
+
+#endif
+
diff --git a/Silicon/BroxtonSoC/BroxtonSiPkg/SouthCluster/Sdio/Dxe/MMC/MmcHostDxe/MmcHostDxe.inf b/Silicon/BroxtonSoC/BroxtonSiPkg/SouthCluster/Sdio/Dxe/MMC/MmcHostDxe/MmcHostDxe.inf
new file mode 100644
index 0000000..0433019
--- /dev/null
+++ b/Silicon/BroxtonSoC/BroxtonSiPkg/SouthCluster/Sdio/Dxe/MMC/MmcHostDxe/MmcHostDxe.inf
@@ -0,0 +1,59 @@
+## @file
+#  MMC Host module
+#
+#  Copyright (c) 1999 - 2016, Intel Corporation. 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                    = 0x00010005
+  BASE_NAME                      = MmcHost
+  FILE_GUID                      = D86DB3C5-57FE-44CF-A82A-74C4AD5B1C2E
+  MODULE_TYPE                    = UEFI_DRIVER
+  VERSION_STRING                 = 1.0
+  ENTRY_POINT                    = MmcHostDriverEntryPoint
+
+#
+# The following information is for reference only and not required by the build tools.
+#
+#  VALID_ARCHITECTURES           = IA32 X64 IPF EBC
+#
+
+[Sources.common]
+  ComponentName.c
+  MmcHostDriver.h
+  MmcHostDriver.c
+  MmcHostController.c
+
+[Packages]
+  MdePkg/MdePkg.dec
+  BroxtonSiPkg/BroxtonSiPkg.dec
+
+[LibraryClasses]
+  UefiDriverEntryPoint
+  DebugLib
+  UefiBootServicesTableLib
+  BaseMemoryLib
+  MemoryAllocationLib
+  UefiLib
+  DevicePathLib
+  IoLib
+  PcdLib
+  HobLib
+
+[Protocols]
+  gEfiPciIoProtocolGuid      ## CONSUMES
+  gEfiMmcHostIoProtocolGuid  ## BY_START
+
+[Guids]
+  gEfiBootMediaHobGuid       ## UNDEFINED
+
+[Pcd]
diff --git a/Silicon/BroxtonSoC/BroxtonSiPkg/SouthCluster/Sdio/Dxe/MMC/MmcMediaDeviceDxe/ComponentName.c b/Silicon/BroxtonSoC/BroxtonSiPkg/SouthCluster/Sdio/Dxe/MMC/MmcMediaDeviceDxe/ComponentName.c
new file mode 100644
index 0000000..a0b0940
--- /dev/null
+++ b/Silicon/BroxtonSoC/BroxtonSiPkg/SouthCluster/Sdio/Dxe/MMC/MmcMediaDeviceDxe/ComponentName.c
@@ -0,0 +1,159 @@
+/** @file
+  Header file for ComponentName.
+
+  Copyright (c) 1999 - 2016, Intel Corporation. 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 <MediaDeviceDriver.h>
+
+//
+// EFI Component Name Protocol
+//
+EFI_COMPONENT_NAME_PROTOCOL     gMediaDeviceComponentName = {
+  MediaDeviceComponentNameGetDriverName,
+  MediaDeviceComponentNameGetControllerName,
+  "eng"
+};
+
+
+static EFI_UNICODE_STRING_TABLE mMediaDeviceDriverNameTable[] = {
+  { "eng", L"UEFI MMC/SD Media Device Driver" },
+  { NULL , NULL }
+};
+
+
+/**
+  Retrieves a Unicode string that is the user readable name of the EFI Driver.
+
+  @param[in]   This                   A pointer to the EFI_COMPONENT_NAME_PROTOCOL instance.
+  @param[in]   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[out]  DriverName             A pointer to the Unicode string to return.  This Unicode string
+                                      is the name of the driver specified by This in the language
+                                      specified by Language.
+
+  @retval      EFI_SUCCESS             The Unicode string for the Driver specified by This
+                                       and the language specified by Language was returned
+                                       in DriverName.
+  @retval      EFI_INVALID_PARAMETER   Language is NULL.
+  @retval      EFI_INVALID_PARAMETER   DriverName is NULL.
+  @retval      EFI_UNSUPPORTED         The driver specified by This does not support the
+                                       language specified by Language.
+
+**/
+EFI_STATUS
+EFIAPI
+MediaDeviceComponentNameGetDriverName (
+  IN  EFI_COMPONENT_NAME_PROTOCOL     *This,
+  IN  CHAR8                           *Language,
+  OUT CHAR16                          **DriverName
+  )
+{
+  return LookupUnicodeString (
+           Language,
+           gMediaDeviceComponentName.SupportedLanguages,
+           mMediaDeviceDriverNameTable,
+           DriverName
+           );
+}
+
+
+/**
+  Retrieves a Unicode string that is the user readable name of the controller
+  that is being managed by an EFI Driver.
+
+  @param[in]   This                   A pointer to the EFI_COMPONENT_NAME_PROTOCOL instance.
+  @param[in]   ControllerHandle       The handle of a controller that the driver specified by
+                                      This is managing.  This handle specifies the controller
+                                      whose name is to be returned.
+  @param[in]   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[in]  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[out] ControllerName         A pointer to the Unicode string to return.  This Unicode
+                                      string is the name of the controller specified by
+                                      ControllerHandle and ChildHandle in the language
+                                      specified by Language from the point of view of the
+                                      driver specified by This.
+
+  @retval     EFI_SUCCESS             The Unicode string for the user readable name in the
+                                      language specified by Language for the driver
+                                      specified by This was returned in DriverName.
+  @retval     EFI_INVALID_PARAMETER   ControllerHandle is not a valid EFI_HANDLE.
+  @retval     EFI_INVALID_PARAMETER   ChildHandle is not NULL and it is not a valid
+                                      EFI_HANDLE.
+  @retval     EFI_INVALID_PARAMETER   Language is NULL.
+  @retval     EFI_INVALID_PARAMETER   ControllerName is NULL.
+  @retval     EFI_UNSUPPORTED         The driver specified by This is not currently
+                                      managing the controller specified by
+                                      ControllerHandle and ChildHandle.
+  @retval     EFI_UNSUPPORTED         The driver specified by This does not support the
+                                      language specified by Language.
+
+**/
+EFI_STATUS
+EFIAPI
+MediaDeviceComponentNameGetControllerName (
+  IN  EFI_COMPONENT_NAME_PROTOCOL     *This,
+  IN  EFI_HANDLE                      ControllerHandle,
+  IN  EFI_HANDLE                      ChildHandle, OPTIONAL
+  IN  CHAR8                           *Language,
+  OUT CHAR16                          **ControllerName
+  )
+{
+  EFI_STATUS               Status;
+  EFI_BLOCK_IO_PROTOCOL    *BlockIo;
+  CARD_DATA                *CardData;
+
+  //
+  // This is a device driver, so ChildHandle must be NULL.
+  //
+  if (ChildHandle != NULL) {
+    return EFI_UNSUPPORTED;
+  }
+
+  //
+  // Get the device context
+  //
+  Status = gBS->OpenProtocol (
+                  ControllerHandle,
+                  &gEfiBlockIoProtocolGuid,
+                  (VOID **) &BlockIo,
+                  gMediaDeviceDriverBinding.DriverBindingHandle,
+                  ControllerHandle,
+                  EFI_OPEN_PROTOCOL_GET_PROTOCOL
+                  );
+
+  if (EFI_ERROR (Status)) {
+    return Status;
+  }
+
+  CardData  = CARD_DATA_FROM_THIS (BlockIo);
+  return LookupUnicodeString (
+           Language,
+           gMediaDeviceComponentName.SupportedLanguages,
+           CardData->ControllerNameTable,
+           ControllerName
+           );
+}
+
diff --git a/Silicon/BroxtonSoC/BroxtonSiPkg/SouthCluster/Sdio/Dxe/MMC/MmcMediaDeviceDxe/MMCSDBlockIo.c b/Silicon/BroxtonSoC/BroxtonSiPkg/SouthCluster/Sdio/Dxe/MMC/MmcMediaDeviceDxe/MMCSDBlockIo.c
new file mode 100644
index 0000000..5c91190
--- /dev/null
+++ b/Silicon/BroxtonSoC/BroxtonSiPkg/SouthCluster/Sdio/Dxe/MMC/MmcMediaDeviceDxe/MMCSDBlockIo.c
@@ -0,0 +1,666 @@
+/** @file
+  Block I/O protocol for MMC/SD device.
+
+  Copyright (c) 2012 - 2017, Intel Corporation. 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 <MediaDeviceDriver.h>
+
+
+/**
+  Implements EFI_BLOCK_IO_PROTOCOL.Reset() function.
+
+  @param[in]  This                    The EFI_BLOCK_IO_PROTOCOL instance.
+  @param[in]  ExtendedVerification    Indicates that the driver may perform a more
+                                      exhaustive verification operation of the device during reset.
+                                      (This parameter is ingored in this driver.)
+
+  @retval     EFI_INVALID_PARAMETER
+  @retval     EFI_UNSUPPORTED
+  @retval     EFI_SUCCESS
+
+**/
+EFI_STATUS
+EFIAPI
+MMCSDBlockReset (
+  IN  EFI_BLOCK_IO_PROTOCOL   *This,
+  IN  BOOLEAN                 ExtendedVerification
+  )
+{
+  CARD_DATA                   *CardData;
+  EFI_MMC_HOST_IO_PROTOCOL    *MmcHostIo;
+
+  CardData  = CARD_DATA_FROM_THIS (This);
+  MmcHostIo = CardData->MmcHostIo;
+
+  DEBUG ((EFI_D_INFO, "MMC SD Block: Resetting host\n"));
+
+  return MmcHostIo->ResetMmcHost (MmcHostIo, Reset_DAT_CMD);
+}
+
+
+/**
+  Implements EFI_BLOCK_IO_PROTOCOL.ReadBlocks() function.
+
+  @param[in]   This                    The EFI_BLOCK_IO_PROTOCOL instance.
+  @param[in]   MediaId                 The media id that the read request is for.
+  @param[in]   LBA                     The starting logical block address to read from on the device.
+  @param[in]   BufferSiz               The size of the Buffer in bytes. This must be a multiple of
+                                       the intrinsic block size of the device.
+  @param[out]  Buffer                  A pointer to the destination buffer for the data. The caller
+                                       is responsible for either having implicit or explicit ownership
+                                       of the buffer.
+
+  @retval      EFI_INVALID_PARAMETER   Parameter is error
+  @retval      EFI_SUCCESS             Success
+  @retval      EFI_DEVICE_ERROR        Hardware Error
+  @retval      EFI_NO_MEDIA            No media
+  @retval      EFI_MEDIA_CHANGED       Media Change
+  @retval      EFI_BAD_BUFFER_SIZE     Buffer size is bad
+
+**/
+EFI_STATUS
+EFIAPI
+MMCSDBlockReadBlocks (
+  IN  EFI_BLOCK_IO_PROTOCOL   *This,
+  IN  UINT32                  MediaId,
+  IN  EFI_LBA                 LBA,
+  IN  UINTN                   BufferSize,
+  OUT VOID                    *Buffer
+  )
+{
+  EFI_STATUS                  Status;
+  UINT32                      Address;
+  CARD_DATA                   *CardData;
+  EFI_MMC_HOST_IO_PROTOCOL     *MmcHostIo;
+  UINT32                      RemainingLength;
+  UINT32                      TransferLength;
+  UINT8                       *BufferPointer;
+  BOOLEAN                     SectorAddressing;
+  UINT64                      CardSize;
+  MMC_PARTITION_DATA          *Partition;
+  UINTN                       TotalBlock;
+
+  Status   = EFI_SUCCESS;
+  Partition = CARD_PARTITION_DATA_FROM_THIS (This);
+  CardData  = Partition->CardData;
+  MmcHostIo = CardData->MmcHostIo;
+
+  //
+  // Media ID has high priority that need to be verify first
+  //
+  if (MediaId != Partition->BlockIoMedia.MediaId) {
+    return EFI_MEDIA_CHANGED;
+  }
+
+  Status = MmcSelectPartition (Partition);
+  if (EFI_ERROR (Status)) {
+    return Status;
+  }
+
+  //
+  // BufferSize must be a multiple of the intrinsic block size of the device.
+  //
+  if (ModU64x32 (BufferSize,Partition->BlockIoMedia.BlockSize) != 0) {
+    return EFI_BAD_BUFFER_SIZE;
+  }
+
+  CardSize = MultU64x32 (CardData->BlockNumber, CardData->BlockLen);
+
+  if ((CardData->CardType == SdMemoryCard2High) || (CardSize >= SIZE_2GB)) {
+    SectorAddressing = TRUE;
+  } else {
+    SectorAddressing = FALSE;
+  }
+
+  if (SectorAddressing) {
+    //
+    // Sector Address
+    //
+    Address = (UINT32) DivU64x32 (MultU64x32 (LBA, Partition->BlockIoMedia.BlockSize), 512);
+  } else {
+    //
+    // Byte Address
+    //
+    Address  = (UINT32) MultU64x32 (LBA, Partition->BlockIoMedia.BlockSize);
+  }
+
+  TotalBlock = (UINTN) DivU64x32 (BufferSize, Partition->BlockIoMedia.BlockSize);
+  //
+  // Make sure the range to read is valid.
+  //
+  if (LBA + TotalBlock > Partition->BlockIoMedia.LastBlock + 1) {
+    return EFI_INVALID_PARAMETER;
+  }
+
+  if (!(Partition->BlockIoMedia.MediaPresent)) {
+    return EFI_NO_MEDIA;
+  }
+
+  if (!Buffer) {
+    Status = EFI_INVALID_PARAMETER;
+    DEBUG ((EFI_D_ERROR, "MMCSDBlockReadBlocks: Invalid parameter \n"));
+    goto Done;
+  }
+
+  if ((BufferSize % Partition->BlockIoMedia.BlockSize) != 0) {
+    Status = EFI_BAD_BUFFER_SIZE;
+    DEBUG ((EFI_D_ERROR, "MMCSDBlockReadBlocks: Bad buffer size \n"));
+    goto Done;
+  }
+
+  if (BufferSize == 0) {
+    Status = EFI_SUCCESS;
+    goto Done;
+  }
+
+  BufferPointer   = Buffer;
+  RemainingLength = (UINT32) BufferSize;
+
+  while (RemainingLength > 0) {
+    if ((BufferSize >= Partition->BlockIoMedia.BlockSize)) {
+      if (RemainingLength > MmcHostIo->HostCapability.BoundarySize) {
+        TransferLength = MmcHostIo->HostCapability.BoundarySize;
+      } else {
+        TransferLength = RemainingLength;
+      }
+
+      if (CardData->CardType == MMCCard) {
+        if (!(CardData->ExtCSDRegister.CARD_TYPE & (BIT2 | BIT3))) {
+          Status = SendCommand (
+                     MmcHostIo,
+                     SET_BLOCKLEN,
+                     Partition->BlockIoMedia.BlockSize,
+                     NoData,
+                     NULL,
+                     0,
+                     ResponseR1,
+                     TIMEOUT_COMMAND,
+                     (UINT32 *) &(CardData->CardStatus)
+                     );
+          if (EFI_ERROR (Status)) {
+            break;
+          }
+        }
+
+        Status = SendCommand (
+                   MmcHostIo,
+                   SET_BLOCK_COUNT,
+                   TransferLength / Partition->BlockIoMedia.BlockSize,
+                   NoData,
+                   NULL,
+                   0,
+                   ResponseR1,
+                   TIMEOUT_COMMAND,
+                   (UINT32 *) &(CardData->CardStatus)
+                   );
+        if (EFI_ERROR (Status)) {
+          break;
+        }
+      }
+
+      Status = SendCommand (
+                 MmcHostIo,
+                 READ_MULTIPLE_BLOCK,
+                 Address,
+                 InData,
+                 CardData->AlignedBuffer,
+                 TransferLength,
+                 ResponseR1,
+                 TIMEOUT_DATA,
+                 (UINT32 *) &(CardData->CardStatus)
+                 );
+
+      if (EFI_ERROR (Status)) {
+        DEBUG ((EFI_D_ERROR, "MMCSDBlockReadBlocks: READ_MULTIPLE_BLOCK -> Fail\n"));
+        break;
+      }
+    } else {
+      if (RemainingLength > Partition->BlockIoMedia.BlockSize) {
+        TransferLength = Partition->BlockIoMedia.BlockSize;
+      } else {
+        TransferLength = RemainingLength;
+      }
+
+      Status = SendCommand (
+                 MmcHostIo,
+                 READ_SINGLE_BLOCK,
+                 Address,
+                 InData,
+                 CardData->AlignedBuffer,
+                 (UINT32) TransferLength,
+                 ResponseR1,
+                 TIMEOUT_DATA,
+                 (UINT32*) &(CardData->CardStatus)
+                 );
+
+      if (EFI_ERROR (Status)) {
+        DEBUG ((EFI_D_ERROR, "MMCSDBlockReadBlocks: READ_SINGLE_BLOCK -> Fail\n"));
+        break;
+      }
+    }
+
+    CopyMem (BufferPointer, CardData->AlignedBuffer, TransferLength);
+
+    if (SectorAddressing) {
+      //
+      // Sector Address
+      //
+      Address += TransferLength / 512;
+    } else {
+      //
+      // Byte Address
+      //
+      Address += TransferLength;
+    }
+    BufferPointer   += TransferLength;
+    RemainingLength -= TransferLength;
+  }
+
+  if (EFI_ERROR (Status)) {
+    if ((CardData->CardType == SdMemoryCard) ||
+        (CardData->CardType == SdMemoryCard2)||
+        (CardData->CardType == SdMemoryCard2High)) {
+      SendCommand (
+        MmcHostIo,
+        STOP_TRANSMISSION,
+        0,
+        NoData,
+        NULL,
+        0,
+        ResponseR1b,
+        TIMEOUT_COMMAND,
+        (UINT32 *) &(CardData->CardStatus)
+        );
+    } else {
+      SendCommand (
+        MmcHostIo,
+        STOP_TRANSMISSION,
+        0,
+        NoData,
+        NULL,
+        0,
+        ResponseR1,
+        TIMEOUT_COMMAND,
+        (UINT32 *) &(CardData->CardStatus)
+        );
+    }
+  }
+
+Done:
+  return Status;
+}
+
+
+/**
+  Implements EFI_BLOCK_IO_PROTOCOL.WriteBlocks() function.
+
+  @param[in]  This                    The EFI_BLOCK_IO_PROTOCOL instance.
+  @param[in]  MediaId                 The media id that the write request is for.
+  @param[in]  LBA                     The starting logical block address to be written.
+                                      The caller is responsible for writing to only
+                                      legitimate locations.
+  @param[in]  BufferSize
+                                      The size of the Buffer in bytes. This must be a multiple of
+                                      the intrinsic block size of the device.
+  @param[in]  Buffer                  A pointer to the source buffer for the data. The caller
+                                      is responsible for either having implicit or explicit ownership
+                                      of the buffer.
+
+  @retval     EFI_INVALID_PARAMETER   Parameter is error
+  @retval     EFI_SUCCESS             Success
+  @retval     EFI_DEVICE_ERROR        Hardware Error
+  @retval     EFI_NO_MEDIA            No media
+  @retval     EFI_MEDIA_CHANGED       Media Change
+  @retval     EFI_BAD_BUFFER_SIZE     Buffer size is bad
+
+**/
+EFI_STATUS
+EFIAPI
+MMCSDBlockWriteBlocks (
+  IN  EFI_BLOCK_IO_PROTOCOL   *This,
+  IN  UINT32                  MediaId,
+  IN  EFI_LBA                 LBA,
+  IN  UINTN                   BufferSize,
+  IN  VOID                    *Buffer
+  )
+{
+  EFI_STATUS                  Status;
+  UINT32                      Address;
+  CARD_DATA                   *CardData;
+  EFI_MMC_HOST_IO_PROTOCOL    *MmcHostIo;
+  UINT32                      RemainingLength;
+  UINT32                      TransferLength;
+  UINT8                       *BufferPointer;
+  BOOLEAN                     SectorAddressing;
+  UINT64                      CardSize;
+  MMC_PARTITION_DATA          *Partition;
+
+  Status   = EFI_SUCCESS;
+  Partition = CARD_PARTITION_DATA_FROM_THIS (This);
+  CardData  = Partition->CardData;
+  MmcHostIo = CardData->MmcHostIo;
+
+  Status = MmcSelectPartition (Partition);
+  if (EFI_ERROR (Status)) {
+    return Status;
+  }
+
+  CardSize = MultU64x32 (CardData->BlockNumber, CardData->BlockLen);
+
+  if ((CardData->CardType == SdMemoryCard2High) || (CardSize >= SIZE_2GB)) {
+    SectorAddressing = TRUE;
+  } else {
+    SectorAddressing = FALSE;
+  }
+
+  if (SectorAddressing) {
+    //
+    // Sector Address
+    //
+    Address = (UINT32) DivU64x32 (MultU64x32 (LBA, Partition->BlockIoMedia.BlockSize), 512);
+  } else {
+    //
+    // Byte Address
+    //
+    Address = (UINT32) MultU64x32 (LBA, Partition->BlockIoMedia.BlockSize);
+  }
+
+  if (!Buffer) {
+    Status = EFI_INVALID_PARAMETER;
+    DEBUG ((EFI_D_ERROR, "MMCSDBlockWriteBlocks: Invalid parameter \n"));
+    goto Done;
+  }
+
+  if ((BufferSize % Partition->BlockIoMedia.BlockSize) != 0) {
+    Status = EFI_BAD_BUFFER_SIZE;
+    DEBUG ((EFI_D_ERROR, "MMCSDBlockWriteBlocks: Bad buffer size \n"));
+    goto Done;
+  }
+
+  if (BufferSize == 0) {
+    Status = EFI_SUCCESS;
+    goto Done;
+  }
+
+  if (This->Media->ReadOnly == TRUE) {
+    Status = EFI_WRITE_PROTECTED;
+    DEBUG ((EFI_D_ERROR, "MMCSDBlockWriteBlocks: Write protected \n"));
+    goto Done;
+  }
+
+  BufferPointer   = Buffer;
+  RemainingLength = (UINT32) BufferSize;
+
+  while (RemainingLength > 0) {
+    if ((BufferSize >= Partition->BlockIoMedia.BlockSize) ) {
+      if (RemainingLength > MmcHostIo->HostCapability.BoundarySize) {
+        TransferLength = MmcHostIo->HostCapability.BoundarySize;
+      } else {
+        TransferLength = RemainingLength;
+      }
+
+      if ((CardData->CardType == SdMemoryCard) ||
+          (CardData->CardType == SdMemoryCard2)||
+          (CardData->CardType == SdMemoryCard2High)) {
+        //
+        // Write performance improvement
+        //
+        if ((TransferLength / Partition->BlockIoMedia.BlockSize) > 64) {
+          Status  = SendAppCommand (
+                      CardData,
+                      SET_WR_BLK_ERASE_COUNT,
+                      (UINT32) (TransferLength / Partition->BlockIoMedia.BlockSize),
+                      NoData,
+                      NULL,
+                      0,
+                      ResponseR1,
+                      TIMEOUT_COMMAND,
+                      (UINT32 *) &(CardData->CardStatus)
+                      );
+        }
+      } else if (CardData->CardType == MMCCard) {
+
+        if (!(CardData->ExtCSDRegister.CARD_TYPE & (BIT2 | BIT3)))  {
+          Status = SendCommand (
+                     MmcHostIo,
+                     SET_BLOCKLEN,
+                     Partition->BlockIoMedia.BlockSize,
+                     NoData,
+                     NULL,
+                     0,
+                     ResponseR1,
+                     TIMEOUT_COMMAND,
+                     (UINT32 *) &(CardData->CardStatus)
+                     );
+
+          if (EFI_ERROR (Status)) {
+            break;
+          }
+        }
+        Status = SendCommand (
+                   MmcHostIo,
+                   SET_BLOCK_COUNT,
+                   TransferLength / Partition->BlockIoMedia.BlockSize,
+                   NoData,
+                   NULL,
+                   0,
+                   ResponseR1,
+                   TIMEOUT_COMMAND,
+                   (UINT32 *) &(CardData->CardStatus)
+                   );
+        if (EFI_ERROR (Status)) {
+          break;
+        }
+      }
+
+      CopyMem (CardData->AlignedBuffer, BufferPointer, TransferLength);
+
+      Status = SendCommand (
+                 MmcHostIo,
+                 WRITE_MULTIPLE_BLOCK,
+                 Address,
+                 OutData,
+                 CardData->AlignedBuffer,
+                 (UINT32) TransferLength,
+                 ResponseR1,
+                 TIMEOUT_DATA,
+                 (UINT32 *) &(CardData->CardStatus)
+                 );
+      if (EFI_ERROR (Status)) {
+        DEBUG ((EFI_D_ERROR, "MMCSDBlockWriteBlocks: WRITE_MULTIPLE_BLOCK -> Fail\n"));
+        break;
+      }
+    } else {
+      if (RemainingLength > Partition->BlockIoMedia.BlockSize) {
+        TransferLength = Partition->BlockIoMedia.BlockSize;
+      } else {
+        TransferLength = RemainingLength;
+      }
+
+      CopyMem (CardData->AlignedBuffer, BufferPointer, TransferLength);
+
+      Status = SendCommand (
+                 MmcHostIo,
+                 WRITE_BLOCK,
+                 Address,
+                 OutData,
+                 CardData->AlignedBuffer,
+                 (UINT32) TransferLength,
+                 ResponseR1,
+                 TIMEOUT_DATA,
+                 (UINT32 *) &(CardData->CardStatus)
+                 );
+    }
+
+    if (SectorAddressing) {
+      //
+      // Sector Address
+      //
+      Address += TransferLength / 512;
+    } else {
+      //
+      // Byte Address
+      //
+      Address += TransferLength;
+    }
+    BufferPointer   += TransferLength;
+    RemainingLength -= TransferLength;
+  }
+
+  if (EFI_ERROR (Status)) {
+    SendCommand (
+      MmcHostIo,
+      STOP_TRANSMISSION,
+      0,
+      NoData,
+      NULL,
+      0,
+      ResponseR1b,
+      TIMEOUT_COMMAND,
+      (UINT32 *) &(CardData->CardStatus)
+      );
+  }
+
+Done:
+  return Status;
+}
+
+
+/**
+  Implements EFI_BLOCK_IO_PROTOCOL.FlushBlocks() function.
+  (In this driver, this function just returns EFI_SUCCESS.)
+
+  @param[in]  This          The EFI_BLOCK_IO_PROTOCOL instance.
+
+  @retval     EFI_SUCCESS   Success
+
+**/
+EFI_STATUS
+EFIAPI
+MMCSDBlockFlushBlocks (
+  IN  EFI_BLOCK_IO_PROTOCOL   *This
+  )
+{
+  return EFI_SUCCESS;
+}
+
+
+/**
+  MMC/SD card BlockIo init function
+
+  @param[in]  CardData       Pointer to CARD_DATA
+
+  @retval     EFI_SUCCESS    Success
+
+**/
+EFI_STATUS
+MMCSDBlockIoInit (
+  IN  CARD_DATA       *CardData
+  )
+{
+  UINTN               Loop;
+  MMC_PARTITION_DATA  *Partition;
+  EXT_CSD             *ExtCsd;
+  UINT64              GP_CHUNK_SIZE;
+  UINT32              GP_SIZE_MULT;
+  UINT64              GppSize;
+  UINTN               GppIndex=0;
+
+  Partition = CardData->Partitions;
+  ExtCsd = &CardData->ExtCSDRegister;
+
+  //
+  // Determine GP partitioning chunk size
+  //
+  GP_CHUNK_SIZE = 0;
+  if (((ExtCsd->PARTITIONING_SUPPORT & BIT0) == BIT0) &&
+      ((ExtCsd->PARTITION_SETTING_COMPLETED & BIT0) == BIT0)) {
+    GP_CHUNK_SIZE = MultU64x32 (ExtCsd->HC_WP_GRP_SIZE, ExtCsd->HC_ERASE_GRP_SIZE);
+    GP_CHUNK_SIZE = MultU64x32 (GP_CHUNK_SIZE, SIZE_512KB);
+  }
+
+  for (Loop = 0; Loop < MAX_NUMBER_OF_PARTITIONS; Partition++, Loop++) {
+    //
+    // BlockIO protocol
+    //
+    Partition->BlockIo.Revision    = EFI_BLOCK_IO_PROTOCOL_REVISION;
+    Partition->BlockIo.Media       = &(Partition->BlockIoMedia);
+    Partition->BlockIo.Reset       = MMCSDBlockReset;
+    Partition->BlockIo.ReadBlocks  = MMCSDBlockReadBlocks ;
+    Partition->BlockIo.WriteBlocks = MMCSDBlockWriteBlocks;
+    Partition->BlockIo.FlushBlocks = MMCSDBlockFlushBlocks;
+
+    Partition->BlockIoMedia.MediaId          = 0;
+    Partition->BlockIoMedia.RemovableMedia   = FALSE;
+    Partition->BlockIoMedia.MediaPresent     = TRUE;
+    Partition->BlockIoMedia.LogicalPartition = FALSE;
+
+    //
+    // Force the User partition to be enabled
+    //
+    if (Loop == 0) {
+      Partition->Present = TRUE;
+    }
+
+    if (CardData->CSDRegister.PERM_WRITE_PROTECT || CardData->CSDRegister.TMP_WRITE_PROTECT) {
+      Partition->BlockIoMedia.ReadOnly       = TRUE;
+    } else {
+      Partition->BlockIoMedia.ReadOnly       = FALSE;
+    }
+
+    Partition->BlockIoMedia.WriteCaching     = FALSE;
+    Partition->BlockIoMedia.BlockSize        = CardData->BlockLen;
+    Partition->BlockIoMedia.IoAlign          = 1;
+    Partition->BlockIoMedia.LastBlock        = (EFI_LBA) (CardData->BlockNumber - 1);
+
+    //
+    // Handle GPP partitions
+    //
+    GppSize = 0;
+    if ((GP_CHUNK_SIZE != 0) && (Loop >= 4)) {
+      Partition->BlockIoMedia.LastBlock = (EFI_LBA) 0;
+      GppIndex = Loop - 4;
+      GP_SIZE_MULT = MmcGetExtCsd24 (
+                       CardData,
+                       OFFSET_OF (EXT_CSD, GP_SIZE_MULT_1) + (3 * GppIndex)
+                       );
+      GppSize = MultU64x32 (GP_SIZE_MULT, (UINT32) GP_CHUNK_SIZE);
+    }
+
+    if (GppSize != 0) {
+      Partition->BlockIoMedia.LastBlock =
+        DivU64x32 (GppSize, Partition->BlockIoMedia.BlockSize) - 1;
+      DEBUG ((EFI_D_INFO,
+        "GPP%d last-block: 0x%lx\n",
+        GppIndex + 1,
+        Partition->BlockIoMedia.LastBlock
+        ));
+      Partition->Present = TRUE;
+    }
+
+    if (CardData->CardType == MMCCard) {
+      //
+      // Handle Boot partitions
+      //
+      if ((Loop == 1) || (Loop == 2)) {
+        Partition->BlockIoMedia.LastBlock = 128 * 1024 * ((UINTN) MmcGetExtCsd8 (CardData, OFFSET_OF (EXT_CSD, BOOT_SIZE_MULTI))) / 512;
+        Partition->Present = TRUE;
+      }
+    }
+  }
+
+  DEBUG ((EFI_D_INFO, "MMC SD Block I/O: Initialized\n"));
+
+  return EFI_SUCCESS;
+}
+
diff --git a/Silicon/BroxtonSoC/BroxtonSiPkg/SouthCluster/Sdio/Dxe/MMC/MmcMediaDeviceDxe/MMCSDTransfer.c b/Silicon/BroxtonSoC/BroxtonSiPkg/SouthCluster/Sdio/Dxe/MMC/MmcMediaDeviceDxe/MMCSDTransfer.c
new file mode 100644
index 0000000..13258de
--- /dev/null
+++ b/Silicon/BroxtonSoC/BroxtonSiPkg/SouthCluster/Sdio/Dxe/MMC/MmcMediaDeviceDxe/MMCSDTransfer.c
@@ -0,0 +1,2524 @@
+/** @file
+  SMMC transfer specific functions.
+
+  Copyright (c) 1999 - 2017, Intel Corporation. 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 <MediaDeviceDriver.h>
+#include <HeciRegs.h>
+#include <Private/Guid/ScPolicyHobGuid.h>
+#include <SeCAccess.h>
+#include <Library/SteppingLib.h>
+#include <Library/ConfigBlockLib.h>
+
+
+/**
+  Set Mmc ExtCsd register
+
+  @param[in]  PeiCardData              Pointer to CARD_DATA
+  @param[in]  Index
+  @param[in]  Value
+
+  @retval     EFI_INVALID_PARAMETER
+  @retval     EFI_UNSUPPORTED
+  @retval     EFI_SUCCESS
+
+**/
+EFI_STATUS
+MmcSetExtCsd8 (
+  IN  CARD_DATA              *CardData,
+  IN  UINT8                  Index,
+  IN  UINT8                  Value
+  );
+
+EFI_EVENT   mSetEmmcWpOnEvent = NULL;
+
+
+/**
+  Check card status, print the debug info and check the error
+
+  @param[in]  Status              Status got from card status register
+
+  @retval     EFI_DEVICE_ERROR
+  @retval     EFI_SUCCESS
+
+**/
+EFI_STATUS
+CheckCardStatus (
+  IN  UINT32    Status
+  )
+{
+  CARD_STATUS    *CardStatus;
+  CardStatus = (CARD_STATUS *) (&Status);
+
+  if (CardStatus->ADDRESS_OUT_OF_RANGE) {
+   DEBUG ((EFI_D_ERROR, "CardStatus: ADDRESS_OUT_OF_RANGE\n"));
+  }
+
+  if (CardStatus->ADDRESS_MISALIGN) {
+   DEBUG ((EFI_D_ERROR, "CardStatus: ADDRESS_MISALIGN\n"));
+  }
+
+  if (CardStatus->BLOCK_LEN_ERROR) {
+   DEBUG ((EFI_D_ERROR, "CardStatus: BLOCK_LEN_ERROR\n"));
+  }
+
+  if (CardStatus->ERASE_SEQ_ERROR) {
+   DEBUG ((EFI_D_ERROR, "CardStatus: ERASE_SEQ_ERROR\n"));
+  }
+
+  if (CardStatus->ERASE_PARAM) {
+   DEBUG ((EFI_D_ERROR, "CardStatus: ERASE_PARAM\n"));
+  }
+
+  if (CardStatus->WP_VIOLATION) {
+   DEBUG ((EFI_D_ERROR, "CardStatus: WP_VIOLATION\n"));
+  }
+
+  if (CardStatus->CARD_IS_LOCKED) {
+   DEBUG ((EFI_D_ERROR, "CardStatus: CARD_IS_LOCKED\n"));
+  }
+
+  if (CardStatus->LOCK_UNLOCK_FAILED) {
+   DEBUG ((EFI_D_ERROR, "CardStatus: LOCK_UNLOCK_FAILED\n"));
+  }
+
+  if (CardStatus->COM_CRC_ERROR) {
+   DEBUG ((EFI_D_ERROR, "CardStatus: COM_CRC_ERROR\n"));
+  }
+
+  if (CardStatus->ILLEGAL_COMMAND) {
+   DEBUG ((EFI_D_ERROR, "CardStatus: ILLEGAL_COMMAND\n"));
+  }
+
+  if (CardStatus->CARD_ECC_FAILED) {
+   DEBUG ((EFI_D_ERROR, "CardStatus: CARD_ECC_FAILED\n"));
+  }
+
+  if (CardStatus->CC_ERROR) {
+   DEBUG ((EFI_D_ERROR, "CardStatus: CC_ERROR\n"));
+  }
+
+  if (CardStatus->ERROR) {
+   DEBUG ((EFI_D_ERROR, "CardStatus: ERROR\n"));
+  }
+
+  if (CardStatus->UNDERRUN) {
+   DEBUG ((EFI_D_ERROR, "CardStatus: UNDERRUN\n"));
+  }
+
+  if (CardStatus->OVERRUN) {
+   DEBUG ((EFI_D_ERROR, "CardStatus: OVERRUN\n"));
+  }
+
+  if (CardStatus->CID_CSD_OVERWRITE) {
+   DEBUG ((EFI_D_ERROR, "CardStatus: CID_CSD_OVERWRITE\n"));
+  }
+
+  if (CardStatus->WP_ERASE_SKIP) {
+   DEBUG ((EFI_D_ERROR, "CardStatus: WP_ERASE_SKIP\n"));
+  }
+
+  if (CardStatus->ERASE_RESET) {
+   DEBUG ((EFI_D_ERROR, "CardStatus: ERASE_RESET\n"));
+  }
+
+  if (CardStatus->SWITCH_ERROR) {
+   DEBUG ((EFI_D_ERROR, "CardStatus: SWITCH_ERROR\n"));
+  }
+
+  if ((Status & 0xFCFFA080) != 0) {
+    return EFI_DEVICE_ERROR;
+  }
+
+  return EFI_SUCCESS;
+}
+
+
+/**
+  Send command by using Host IO protocol
+
+  @param[in]  This                    Pointer to EFI_MMC_HOST_IO_PROTOCOL
+  @param[in]  CommandIndex            The command index to set the command index field of command register
+  @param[in]  Argument                Command argument to set the argument field of command register
+  @param[in]  DataType                TRANSFER_TYPE, indicates no data, data in or data out
+  @param[in]  Buffer                  Contains the data read from / write to the device
+  @param[in]  BufferSize              The size of the buffer
+  @param[in]  ResponseType            RESPONSE_TYPE
+  @param[in]  TimeOut                 Time out value in 1 ms unit
+  @param[out] ResponseData            Depending on the ResponseType, such as CSD or card status
+
+  @retval     EFI_INVALID_PARAMETER
+  @retval     EFI_UNSUPPORTED
+  @retval     EFI_DEVICE_ERROR
+  @retval     EFI_SUCCESS
+
+**/
+EFI_STATUS
+SendCommand (
+  IN   EFI_MMC_HOST_IO_PROTOCOL   *This,
+  IN   UINT16                     CommandIndex,
+  IN   UINT32                     Argument,
+  IN   TRANSFER_TYPE              DataType,
+  IN   UINT8                      *Buffer, OPTIONAL
+  IN   UINT32                     BufferSize,
+  IN   RESPONSE_TYPE              ResponseType,
+  IN   UINT32                     TimeOut,
+  OUT  UINT32                     *ResponseData
+  )
+{
+
+  EFI_STATUS    Status;
+
+  Status = This->SendCommand (
+                   This,
+                   CommandIndex,
+                   Argument,
+                   DataType,
+                   Buffer,
+                   BufferSize,
+                   ResponseType,
+                   TimeOut,
+                   ResponseData
+                   );
+  if (!EFI_ERROR (Status)) {
+    if (ResponseType == ResponseR1 || ResponseType == ResponseR1b) {
+      if (ResponseData == NULL) {
+        ASSERT(ResponseData != NULL);
+        return EFI_OUT_OF_RESOURCES;
+      }
+      Status = CheckCardStatus (*ResponseData);
+    }
+  } else {
+    This->ResetMmcHost (This, Reset_DAT_CMD);
+  }
+
+  return Status;
+}
+
+
+/**
+  Send the card APP_CMD command with the following command indicated
+  by CommandIndex
+
+  @param[in]  CardData                 Pointer to CARD_DATA
+  @param[in]  CommandIndex             The command index to set the command index field of command register
+  @param[in]  Argument                 Command argument to set the argument field of command register
+  @param[in]  DataType                 TRANSFER_TYPE, indicates no data, data in or data out
+  @param[in]  Buffer                   Contains the data read from / write to the device
+  @param[in]  BufferSize               The size of the buffer
+  @param[in]  ResponseType             RESPONSE_TYPE
+  @param[in]  TimeOut                  Time out value in 1 ms unit
+  @param[out] ResponseData             Depending on the ResponseType, such as CSD or card status
+
+  @retval     EFI_INVALID_PARAMETER
+  @retval     EFI_UNSUPPORTED
+  @retval     EFI_DEVICE_ERROR
+  @retval     EFI_SUCCESS
+
+**/
+EFI_STATUS
+SendAppCommand (
+  IN   CARD_DATA                  *CardData,
+  IN   UINT16                     CommandIndex,
+  IN   UINT32                     Argument,
+  IN   TRANSFER_TYPE              DataType,
+  IN   UINT8                      *Buffer, OPTIONAL
+  IN   UINT32                     BufferSize,
+  IN   RESPONSE_TYPE              ResponseType,
+  IN   UINT32                     TimeOut,
+  OUT  UINT32                     *ResponseData
+  )
+{
+
+  EFI_STATUS                 Status;
+  EFI_MMC_HOST_IO_PROTOCOL   *MmcHostIo;
+  UINT8                      Index;
+
+  MmcHostIo = CardData->MmcHostIo;
+  Status = EFI_SUCCESS;
+
+  for (Index = 0; Index < 2; Index++) {
+    Status = MmcHostIo->SendCommand (
+                          MmcHostIo,
+                          APP_CMD,
+                          (CardData->Address << 16),
+                          NoData,
+                          NULL,
+                          0,
+                          ResponseR1,
+                          TIMEOUT_COMMAND,
+                          (UINT32 *) &(CardData->CardStatus)
+                          );
+    if (!EFI_ERROR (Status)) {
+      Status = CheckCardStatus (*(UINT32 *) &(CardData->CardStatus));
+      if (CardData->CardStatus.SAPP_CMD != 1) {
+        Status = EFI_DEVICE_ERROR;
+      }
+      if (!EFI_ERROR (Status)) {
+        break;
+      }
+    } else {
+      MmcHostIo->ResetMmcHost (MmcHostIo, Reset_Auto);
+    }
+  }
+
+  if (EFI_ERROR (Status)) {
+    return Status;
+  }
+
+  Status = MmcHostIo->SendCommand (
+                        MmcHostIo,
+                        CommandIndex,
+                        Argument,
+                        DataType,
+                        Buffer,
+                        BufferSize,
+                        ResponseType,
+                        TimeOut,
+                        ResponseData
+                        );
+  if (!EFI_ERROR (Status)) {
+    if (ResponseType == ResponseR1 || ResponseType == ResponseR1b) {
+       if (ResponseData == NULL) {
+        ASSERT(ResponseData != NULL);
+        return EFI_OUT_OF_RESOURCES;
+      }
+      Status = CheckCardStatus (*ResponseData);
+    }
+  } else {
+    MmcHostIo->ResetMmcHost (MmcHostIo, Reset_Auto);
+  }
+
+  return Status;
+}
+
+
+/**
+  Dump Mmc Decode OCR register
+
+  @param[in]  OCRReg      Pointer to OCR
+
+  @retval     None
+
+**/
+EFI_STATUS
+MmcDecodeOCR (
+  IN OCR  *OCRReg
+  )
+{
+  DEBUG ((DEBUG_INFO, "\n==========DECODE MMC OCR REGISTER==================\n"));
+  DEBUG ((DEBUG_INFO, " OCR = 0x%08X\n", *((UINT32 *) OCRReg)));
+  DEBUG ((DEBUG_INFO, " CARD_NOT_BUSY      = 0x%X\n", OCRReg->Busy));
+  DEBUG ((DEBUG_INFO, " ACCESS_MODE        = 0x%X\n", OCRReg->AccessMode));
+  DEBUG ((DEBUG_INFO, " VDD_270_360        = 0x%X\n", OCRReg->V270_V360));
+  DEBUG ((DEBUG_INFO, " VDD_200_260        = 0x%X\n", OCRReg->V200_V260));
+  DEBUG ((DEBUG_INFO, " VDD_170_195        = 0x%X\n", OCRReg->V170_V195));
+  DEBUG ((DEBUG_INFO, "==================================================\n"));
+  return 0;
+}
+
+
+/**
+  Dump Mmc Decode CID value
+
+  @param[in]  CIDReg      Pointer to CIDReg
+
+  @retval     None
+
+**/
+EFI_STATUS
+MmcDecodeCID (
+  IN CID  *CIDReg
+  )
+{
+  UINT32 i = 0;
+
+  DEBUG ((EFI_D_INFO, "\n==========DECODE MMC CID REGISTER==================\n"));
+  DEBUG ((EFI_D_INFO, " CID = 0x%032X\n", CIDReg));
+  DEBUG ((EFI_D_INFO, " MANUFACTURER_ID     = 0x%X\n", CIDReg->MID));
+  DEBUG ((EFI_D_INFO, " CARD_OR_BGA         = 0x%X\n", (CIDReg->OID & 0xFF00)>>6));
+  DEBUG ((EFI_D_INFO, " OEM_APPLICATION_ID  = 0x%X\n", (CIDReg->OID>>8) &0xFF));
+  DEBUG ((EFI_D_INFO, " PRODUCT_NAME        = "));
+
+  for (i=0; i < 6; i++) {
+   DEBUG ((EFI_D_INFO, "%c", CIDReg->PNM[i]));
+  }
+  DEBUG ((EFI_D_INFO, "\n"));
+  DEBUG ((EFI_D_INFO, " PRODUCT_REVISION    = 0x%X\n", CIDReg->PRV));
+  DEBUG ((EFI_D_INFO, " PRODUCT_SERIAL_NUM  = 0x%X\n", CIDReg->PSN));
+  DEBUG ((EFI_D_INFO, " MANUFACTURE_DATE    = 0x%X\n", CIDReg->MDT));
+  DEBUG ((EFI_D_INFO, "==================================================\n"));
+  return 0;
+}
+
+
+/**
+  Dump Mmc Decode CSD value
+
+  @param[in]  CSDReg      Pointer to CSDReg
+
+  @retval     None
+
+**/
+EFI_STATUS
+MmcDecodeCSD (
+  IN CSD  *CSDReg
+  )
+{
+  DEBUG ((EFI_D_INFO, "\n==========DECODE MMC CSD REGISTER==================\n"));
+  DEBUG ((EFI_D_INFO, "csd_struct        : [0x%0x] \n", CSDReg->CSD_STRUCTURE));
+  DEBUG ((EFI_D_INFO, "specs_ver         : [0x%0x] \n", CSDReg->SPEC_VERS));
+  DEBUG ((EFI_D_INFO, "reserve2          : [0x%0x] \n", CSDReg->Reserved2));
+  DEBUG ((EFI_D_INFO, "taac              : [0x%0x] \n", CSDReg->TAAC));
+  DEBUG ((EFI_D_INFO, "nsac              : [0x%0x] \n", CSDReg->NSAC));
+  DEBUG ((EFI_D_INFO, "tran_speed        : [0x%0x] \n", CSDReg->TRAN_SPEED));
+  DEBUG ((EFI_D_INFO, "ccc               : [0x%0x] \n", CSDReg->CCC));
+  DEBUG ((EFI_D_INFO, "read_bl_len       : [0x%0x] \n", CSDReg->READ_BL_LEN));
+  DEBUG ((EFI_D_INFO, "read_partial      : [0x%0x] \n", CSDReg->READ_BL_PARTIAL));
+  DEBUG ((EFI_D_INFO, "write_misalign    : [0x%0x] \n", CSDReg->WRITE_BLK_MISALIGN));
+  DEBUG ((EFI_D_INFO, "read_misalign     : [0x%0x] \n", CSDReg->READ_BLK_MISALIGN));
+  DEBUG ((EFI_D_INFO, "dsr_imp           : [0x%0x] \n", CSDReg->DSR_IMP));
+  DEBUG ((EFI_D_INFO, "reserve1          : [0x%0x] \n", CSDReg->Reserved1));
+  DEBUG ((EFI_D_INFO, "c_size            : [0x%0x] \n", CSDReg->C_SIZELow2 | CSDReg->C_SIZEHigh10<<2));
+  DEBUG ((EFI_D_INFO, "vdd_r_curr_min    : [0x%0x] \n", CSDReg->VDD_R_CURR_MIN));
+  DEBUG ((EFI_D_INFO, "vdd_r_curr_max    : [0x%0x] \n", CSDReg->VDD_R_CURR_MAX));
+  DEBUG ((EFI_D_INFO, "vdd_w_curr_min    : [0x%0x] \n", CSDReg->VDD_W_CURR_MIN));
+  DEBUG ((EFI_D_INFO, "vdd_w_curr_max    : [0x%0x] \n", CSDReg->VDD_W_CURR_MAX));
+  DEBUG ((EFI_D_INFO, "c_size_mult       : [0x%0x] \n", CSDReg->C_SIZE_MULT));
+  DEBUG ((EFI_D_INFO, "erase_grp_size    : [0x%0x] \n", CSDReg->ERASE_GRP_SIZE));
+  DEBUG ((EFI_D_INFO, "erase_grp_mult    : [0x%0x] \n", CSDReg->ERASE_GRP_MULT));
+  DEBUG ((EFI_D_INFO, "wp_grp_size       : [0x%0x] \n", CSDReg->WP_GRP_SIZE));
+  DEBUG ((EFI_D_INFO, "wp_grp_enable     : [0x%0x] \n", CSDReg->WP_GRP_ENABLE));
+  DEBUG ((EFI_D_INFO, "default_ecc       : [0x%0x] \n", CSDReg->DEFAULT_ECC));
+  DEBUG ((EFI_D_INFO, "r2w_factor        : [0x%0x] \n", CSDReg->R2W_FACTOR));
+  DEBUG ((EFI_D_INFO, "write_bl_len      : [0x%0x] \n", CSDReg->WRITE_BL_LEN));
+  DEBUG ((EFI_D_INFO, "write_partial     : [0x%0x] \n", CSDReg->WRITE_BL_PARTIAL));
+  DEBUG ((EFI_D_INFO, "reserve0          : [0x%0x] \n", CSDReg->Reserved0));
+  DEBUG ((EFI_D_INFO, "content_prot_app  : [0x%0x] \n", CSDReg->CONTENT_PROT_APP));
+  DEBUG ((EFI_D_INFO, "file_format_grp   : [0x%0x] \n", CSDReg->FILE_FORMAT_GRP));
+  DEBUG ((EFI_D_INFO, "copy              : [0x%0x] \n", CSDReg->COPY));
+  DEBUG ((EFI_D_INFO, "perm_write_protect: [0x%0x] \n", CSDReg->PERM_WRITE_PROTECT));
+  DEBUG ((EFI_D_INFO, "tmp_write_prot    : [0x%0x] \n", CSDReg->TMP_WRITE_PROTECT));
+  DEBUG ((EFI_D_INFO, "file_format       : [0x%0x] \n", CSDReg->FILE_FORMAT));
+  DEBUG ((EFI_D_INFO, "ecc               : [0x%0x] \n", CSDReg->ECC));
+  DEBUG ((EFI_D_INFO, "==================================================\n"));
+
+  return 0;
+}
+
+
+/**
+  Dump Mmc Decode Ext CSD value
+
+  @param[in]  ExtCSDReg      Pointer to ExtCSDReg
+
+  @retval     None
+
+**/
+EFI_STATUS
+MmcDecodeExtCSD (
+  IN EXT_CSD  *ExtCSDReg
+  )
+{
+  DEBUG ((EFI_D_INFO, "\n==========DECODE MMC EXT CSD REGISTER==================\n"));
+  DEBUG ((EFI_D_INFO, " SUPPORTED_CMD_SETS        = 0x%X\n", ExtCSDReg->CMD_SET));
+  DEBUG ((EFI_D_INFO, " HPI_FEATURES              = 0x%X\n", ExtCSDReg->HPI_FEATURES));
+  DEBUG ((EFI_D_INFO, " BKOPS_SUPPORT             = 0x%X\n", ExtCSDReg->BKOPS_SUPPORT));
+  DEBUG ((EFI_D_INFO, " BKOPS_STATUS              = 0x%X\n", ExtCSDReg->BKOPS_STATUS));
+  DEBUG ((EFI_D_INFO, " CORRECTLY_PRG_SECTORS_NUM = 0x%X%X%X%X\n", ExtCSDReg->CORRECTLY_PRG_SECTORS_NUM[3], \
+                                                    ExtCSDReg->CORRECTLY_PRG_SECTORS_NUM[2], ExtCSDReg->CORRECTLY_PRG_SECTORS_NUM[1], ExtCSDReg->CORRECTLY_PRG_SECTORS_NUM[0]));
+  DEBUG ((EFI_D_INFO, " INI_TIMEOUT_AP            = 0x%X\n", ExtCSDReg->INI_TIMEOUT_AP));
+  DEBUG ((EFI_D_INFO, " PWR_CL_DDR_52_195         = 0x%X\n", ExtCSDReg->PWR_CL_DDR_52_195));
+  DEBUG ((EFI_D_INFO, " PWR_CL_DDR_52_360         = 0x%X\n", ExtCSDReg->PWR_CL_DDR_52_360));
+  DEBUG ((EFI_D_INFO, " MIN_PRF_DDR_W_8_52        = 0x%X\n", ExtCSDReg->MIN_PERF_DDR_W_8_52));
+  DEBUG ((EFI_D_INFO, " MIN_PRF_DDR_R_8_52        = 0x%X\n", ExtCSDReg->MIN_PERF_DDR_R_8_52));
+  DEBUG ((EFI_D_INFO, " TRIM_MULT                 = 0x%X\n", ExtCSDReg->TRIM_MULT));
+  DEBUG ((EFI_D_INFO, " SEC_FEATURE_SUPP          = 0x%X\n", ExtCSDReg->SEC_FEATURE_SUPPORT));
+  DEBUG ((EFI_D_INFO, " SEC_ERASE_MULT            = 0x%X\n", ExtCSDReg->SEC_ERASE_MULT));
+  DEBUG ((EFI_D_INFO, " SEC_TRIM_MULT             = 0x%X\n", ExtCSDReg->SEC_TRIM_MULT));
+  DEBUG ((EFI_D_INFO, " BOOT_INFO                 = 0x%X\n", ExtCSDReg->BOOT_INFO));
+  DEBUG ((EFI_D_INFO, " BOOT_PART_SIZE            = 0x%X\n", ExtCSDReg->BOOT_SIZE_MULTI));
+  DEBUG ((EFI_D_INFO, " ACCESS_SIZE               = 0x%X\n", ExtCSDReg->ACC_SIZE));
+  DEBUG ((EFI_D_INFO, " HI_CAP_ER_GRP_SIZE        = 0x%X\n", ExtCSDReg->HC_ERASE_GRP_SIZE));
+  DEBUG ((EFI_D_INFO, " HI_CAP_ER_TIMEOUT         = 0x%X\n", ExtCSDReg->ERASE_TIMEOUT_MULT));
+  DEBUG ((EFI_D_INFO, " REL_WR_SECTOR_CNT         = 0x%X\n", ExtCSDReg->REL_WR_SEC_C));
+  DEBUG ((EFI_D_INFO, " HI_CAP_WP_GRP_SIZE        = 0x%X\n", ExtCSDReg->HC_WP_GRP_SIZE));
+  DEBUG ((EFI_D_INFO, " SLEEP_CURRENT_VCC         = 0x%X\n", ExtCSDReg->S_C_VCC));
+  DEBUG ((EFI_D_INFO, " SLEEP_CURRENT_VCCQ        = 0x%X\n", ExtCSDReg->S_C_VCCQ));
+  DEBUG ((EFI_D_INFO, " SLP_AWK_TIMEOUT           = 0x%X\n", ExtCSDReg->S_A_TIMEOUT));
+  DEBUG ((EFI_D_INFO, " SECTOR_COUNT              = 0x%X\n", *(UINT32*) ((UINT8 *) &ExtCSDReg->SEC_COUNT)));
+  DEBUG ((EFI_D_INFO, " MIN_PERF_W_8_52           = 0x%X\n", ExtCSDReg->MIN_PERF_W_8_52));
+  DEBUG ((EFI_D_INFO, " MIN_PERF_R_8_52           = 0x%X\n", ExtCSDReg->MIN_PERF_R_8_52));
+  DEBUG ((EFI_D_INFO, " MIN_PERF_W_8_26_4_52      = 0x%X\n", ExtCSDReg->MIN_PERF_W_8_26_4_52));
+  DEBUG ((EFI_D_INFO, " MIN_PERF_W_8_26_4_52      = 0x%X\n", ExtCSDReg->MIN_PERF_W_8_26_4_52));
+  DEBUG ((EFI_D_INFO, " MIN_PERF_W_4_26           = 0x%X\n", ExtCSDReg->MIN_PERF_W_4_26));
+  DEBUG ((EFI_D_INFO, " MIN_PERF_R_4_26           = 0x%X\n", ExtCSDReg->MIN_PERF_R_4_26));
+  DEBUG ((EFI_D_INFO, " PWR_CLASS_26_360          = 0x%X\n", ExtCSDReg->PWR_CL_26_360));
+  DEBUG ((EFI_D_INFO, " PWR_CLASS_52_360          = 0x%X\n", ExtCSDReg->PWR_CL_52_360));
+  DEBUG ((EFI_D_INFO, " PWR_CLASS_26_195          = 0x%X\n", ExtCSDReg->PWR_CL_26_195));
+  DEBUG ((EFI_D_INFO, " PWR_CLASS_52_195          = 0x%X\n", ExtCSDReg->PWR_CL_52_195));
+  DEBUG ((EFI_D_INFO, " PARTITION_SWITCH_TIME     = 0x%X\n", ExtCSDReg->PARTITION_SWITCH_TIME));
+  DEBUG ((EFI_D_INFO, " OUT_OF_INTERRUPT_TIME     = 0x%X\n", ExtCSDReg->OUT_OF_INTERRUPT_TIME));
+  DEBUG ((EFI_D_INFO, " CARD_TYPE                 = 0x%X\n", ExtCSDReg->CARD_TYPE));
+  DEBUG ((EFI_D_INFO, " CSD_STRUCTURE             = 0x%X\n", ExtCSDReg->CSD_STRUCTURE));
+  DEBUG ((EFI_D_INFO, " EXT_CSD_REV               = 0x%X\n", ExtCSDReg->EXT_CSD_REV));
+  DEBUG ((EFI_D_INFO, " CMD_SET                   = 0x%X\n", ExtCSDReg->CMD_SET));
+  DEBUG ((EFI_D_INFO, " CMD_SET_REV               = 0x%X\n", ExtCSDReg->CMD_SET_REV));
+  DEBUG ((EFI_D_INFO, " PWR_CLASS                 = 0x%X\n", ExtCSDReg->POWER_CLASS));
+  DEBUG ((EFI_D_INFO, " HI_SPEED_TIMING           = 0x%X\n", ExtCSDReg->HS_TIMING));
+  DEBUG ((EFI_D_INFO, " BUS_WIDTH_MODE            = 0x%X\n", ExtCSDReg->BUS_WIDTH));
+  DEBUG ((EFI_D_INFO, " ERASED_MEM_CONTENT        = 0x%X\n", ExtCSDReg->ERASED_MEM_CONT));
+  DEBUG ((EFI_D_INFO, " PARTITION_CONFIG          = 0x%X\n", ExtCSDReg->PARTITION_CONFIG));
+  DEBUG ((EFI_D_INFO, " BOOT_CONFIG_PROT          = 0x%X\n", ExtCSDReg->BOOT_CONFIG_PROT));
+  DEBUG ((EFI_D_INFO, " BOOT_BUS_WIDTH            = 0x%X\n", ExtCSDReg->BOOT_BUS_WIDTH));
+  DEBUG ((EFI_D_INFO, " HI_DEN_ER_GRP_DEF         = 0x%X\n", ExtCSDReg->ERASE_GROUP_DEF));
+  DEBUG ((EFI_D_INFO, " BOOT_WP                   = 0x%X\n", ExtCSDReg->BOOT_WP));
+  DEBUG ((EFI_D_INFO, " USER_WP                   = 0x%X\n", ExtCSDReg->USER_WP));
+  DEBUG ((EFI_D_INFO, " FW_CONFIG                 = 0x%X\n", ExtCSDReg->FW_CONFIG));
+  DEBUG ((EFI_D_INFO, " RPMB_SIZE_MULT            = 0x%X\n", ExtCSDReg->RPMB_SIZE_MULT));
+  DEBUG ((EFI_D_INFO, " RST_N_FUNCTION            = 0x%X\n", ExtCSDReg->RST_n_FUNCTION));
+  DEBUG ((EFI_D_INFO, " PARTITIONING_SUPP         = 0x%X\n", ExtCSDReg->PARTITIONING_SUPPORT));
+  DEBUG ((EFI_D_INFO, " MAX_ENH_SIZE_MULT         = 0x%02X%02X%02X\n", ExtCSDReg->MAX_ENH_SIZE_MULT[2],ExtCSDReg->MAX_ENH_SIZE_MULT[1], ExtCSDReg->MAX_ENH_SIZE_MULT[0]));
+  DEBUG ((EFI_D_INFO, " PART_ATTRIBUTE            = 0x%X\n", ExtCSDReg->PARTITIONS_ATTRIBUTES));
+  DEBUG ((EFI_D_INFO, " PART_SETTING_COMP         = 0x%X\n", ExtCSDReg->PARTITION_SETTING_COMPLETED));
+  DEBUG ((EFI_D_INFO, " GP_SIZE_MULT              = 0x%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X\n", ExtCSDReg->GP_SIZE_MULT_4[2], ExtCSDReg->GP_SIZE_MULT_4[1], ExtCSDReg->GP_SIZE_MULT_4[0],
+                                                  ExtCSDReg->GP_SIZE_MULT_3[2], ExtCSDReg->GP_SIZE_MULT_3[1], ExtCSDReg->GP_SIZE_MULT_3[0],
+                                                  ExtCSDReg->GP_SIZE_MULT_2[2], ExtCSDReg->GP_SIZE_MULT_2[1], ExtCSDReg->GP_SIZE_MULT_2[0],
+                                                  ExtCSDReg->GP_SIZE_MULT_1[2], ExtCSDReg->GP_SIZE_MULT_1[1], ExtCSDReg->GP_SIZE_MULT_1[0]));
+  DEBUG ((EFI_D_INFO, " ENH_SIZE_MULT             = 0x%02X%02X%02X\n", ExtCSDReg->ENH_SIZE_MULT[2], ExtCSDReg->ENH_SIZE_MULT[1], ExtCSDReg->ENH_SIZE_MULT[0]));
+  DEBUG ((EFI_D_INFO, " ENH_START_ADDR            = 0x%02X%02X%02X%02X\n", ExtCSDReg->ENH_START_ADDR[3], ExtCSDReg->ENH_START_ADDR[2], ExtCSDReg->ENH_START_ADDR[1], ExtCSDReg->ENH_START_ADDR[0]));
+  DEBUG ((EFI_D_INFO, " SEC_BAD_BLK_MGMNT         = 0x%X\n", ExtCSDReg->SEC_BAD_BLOCK_MGMNT));
+  DEBUG ((EFI_D_INFO, "==================================================\n"));
+
+  return 0;
+}
+
+
+/**
+  Send the card FAST_IO command
+
+  @param[in]      CardData                 Pointer to CARD_DATA
+  @param[in]      RegisterAddress          Register Address
+  @param[in, out] RegisterData             Pointer to register Data
+  @param[in]      Write                    TRUE for write, FALSE for read
+
+  @retval         EFI_INVALID_PARAMETER
+  @retval         EFI_UNSUPPORTED
+  @retval         EFI_DEVICE_ERROR
+  @retval         EFI_SUCCESS
+
+**/
+EFI_STATUS
+FastIO (
+  IN      CARD_DATA   *CardData,
+  IN      UINT8       RegisterAddress,
+  IN  OUT UINT8       *RegisterData,
+  IN      BOOLEAN     Write
+  )
+{
+  EFI_MMC_HOST_IO_PROTOCOL   *MmcHostIo;
+  EFI_STATUS                 Status;
+  UINT32                     Argument;
+  UINT32                     Data;
+
+  Status   = EFI_SUCCESS;
+  MmcHostIo = CardData->MmcHostIo;
+
+  if (RegisterData == NULL) {
+    Status = EFI_INVALID_PARAMETER;
+    goto Exit;
+  }
+
+  Argument = (CardData->Address << 16) | (RegisterAddress << 8);
+  if (Write) {
+    Argument |= BIT15 | (*RegisterData);
+  }
+
+  Status = SendCommand (
+             MmcHostIo,
+             FAST_IO,
+             Argument,
+             NoData,
+             NULL,
+             0,
+             ResponseR4,
+             TIMEOUT_COMMAND,
+             &Data
+             );
+
+  if (EFI_ERROR (Status)) {
+    goto Exit;
+  }
+
+  if ((Data & BIT15) == 0) {
+    Status = EFI_DEVICE_ERROR;
+    goto Exit;
+  }
+
+  if (!Write) {
+   *RegisterData = (UINT8)Data;
+  }
+
+Exit:
+  return Status;
+}
+
+
+/**
+  Send the card GO_INACTIVE_STATE command
+
+  @param[in]  CardData               Pointer to CARD_DATA
+
+  @retval     EFI_INVALID_PARAMETER
+  @retval     EFI_UNSUPPORTED
+  @retval     EFI_SUCCESS
+
+**/
+EFI_STATUS
+PutCardInactive (
+  IN  CARD_DATA   *CardData
+  )
+{
+  EFI_MMC_HOST_IO_PROTOCOL   *MmcHostIo;
+  EFI_STATUS                 Status;
+
+  MmcHostIo = CardData->MmcHostIo;
+
+  Status = SendCommand (
+             MmcHostIo,
+             GO_INACTIVE_STATE,
+             (CardData->Address << 16),
+             NoData,
+             NULL,
+             0,
+             ResponseNo,
+             TIMEOUT_COMMAND,
+             NULL
+             );
+
+  gBS->Stall(1000);
+
+  return Status;
+}
+
+
+/**
+  Get card interested information for CSD rergister
+
+  @param[in]  CardData                Pointer to CARD_DATA
+
+  @retval     EFI_INVALID_PARAMETER
+  @retval     EFI_UNSUPPORTED
+  @retval     EFI_SUCCESS
+
+**/
+EFI_STATUS
+CalculateCardParameter (
+  IN  CARD_DATA    *CardData
+  )
+{
+  EFI_STATUS     Status;
+  UINT32         Frequency;
+  UINT32         Multiple;
+  UINT32         CSize;
+  CSD_SDV2       *CsdSDV2;
+
+  Status = EFI_SUCCESS;
+
+  switch (CardData->CSDRegister.TRAN_SPEED & 0x7) {
+    case 0:
+      Frequency = 100 * 1000;
+      break;
+
+    case 1:
+      Frequency = 1 * 1000 * 1000;
+      break;
+
+    case 2:
+      Frequency = 10 * 1000 * 1000;
+      break;
+
+    case 3:
+      Frequency = 100 * 1000 * 1000;
+      break;
+
+    default:
+      DEBUG ((EFI_D_ERROR, "Invalid CSD TRAN_SPEED Frequency: 0x%x\n", CardData->CSDRegister.TRAN_SPEED & 0x7));
+      Status = EFI_INVALID_PARAMETER;
+      goto Exit;
+  }
+
+  switch ((CardData->CSDRegister.TRAN_SPEED >> 3) & 0xF) {
+    case 1:
+      Multiple = 10;
+      break;
+
+    case 2:
+      Multiple = 12;
+      break;
+
+    case 3:
+      Multiple = 13;
+      break;
+
+    case 4:
+      Multiple = 15;
+      break;
+
+    case 5:
+      Multiple = 20;
+      break;
+
+    case 6:
+      if (CardData->CardType == MMCCard) {
+        Multiple = 26;
+      } else {
+        Multiple = 25;
+      }
+      break;
+
+    case 7:
+      Multiple = 30;
+      break;
+
+    case 8:
+      Multiple = 35;
+      break;
+
+    case 9:
+      Multiple = 40;
+      break;
+
+    case 10:
+      Multiple = 45;
+      break;
+
+    case 11:
+      if (CardData->CardType == MMCCard) {
+        Multiple = 52;
+      } else {
+        Multiple = 50;
+      }
+      break;
+
+    case 12:
+      Multiple = 55;
+      break;
+
+    case 13:
+      Multiple = 60;
+      break;
+
+    case 14:
+      Multiple = 70;
+      break;
+
+    case 15:
+      Multiple = 80;
+      break;
+
+    default:
+      DEBUG ((EFI_D_ERROR, "CalculateCardParameter: Invalid CSD TRAN_SPEED Multiple: 0x%x\n", CardData->CSDRegister.TRAN_SPEED >> 3));
+      Status = EFI_INVALID_PARAMETER;
+      goto Exit;
+  }
+
+  Frequency = Frequency * Multiple / 10;
+  CardData->MaxFrequency = Frequency;
+
+  if ((CardData->ExtCSDRegister.CARD_TYPE & BIT2) ||
+      (CardData->ExtCSDRegister.CARD_TYPE & BIT3)) {
+    CardData->BlockLen = 512;
+  } else {
+    CardData->BlockLen = 1 << CardData->CSDRegister.READ_BL_LEN;
+  }
+
+  if (CardData->CardType == SdMemoryCard2High) {
+    ASSERT(CardData->CSDRegister.CSD_STRUCTURE == 1);
+    CsdSDV2 = (CSD_SDV2 *) &CardData->CSDRegister;
+    //
+    // the K here means 1024 not 1000
+    //
+    CardData->BlockNumber = DivU64x32 (MultU64x32 (CsdSDV2->C_SIZE + 1, 512 * 1024) , CardData->BlockLen);
+  } else {
+    //
+    // For MMC card > 2G, the block number will be recaculate later
+    //
+    CSize = CardData->CSDRegister.C_SIZELow2 | (CardData->CSDRegister.C_SIZEHigh10 << 2);
+    CardData->BlockNumber = MultU64x32 (LShiftU64 (1, CardData->CSDRegister.C_SIZE_MULT + 2), CSize + 1);
+  }
+
+  //
+  //For >= 2G card, BlockLen may be 1024, but the transfer size is still 512 bytes
+  //
+  if (CardData->BlockLen > 512) {
+    CardData->BlockNumber = DivU64x32 (MultU64x32 (CardData->BlockNumber, CardData->BlockLen), 512);
+    CardData->BlockLen    = 512;
+  }
+
+  DEBUG ((DEBUG_INFO, "CalculateCardParameter: Card Size: 0x%lx\n", MultU64x32 (CardData->BlockNumber, CardData->BlockLen)
+    ));
+
+Exit:
+  return Status;
+}
+
+
+/**
+  Test the bus width setting for MMC card
+  It is used only for verification purpose
+
+  @param[in]  CardData                Pointer to CARD_DATA
+  @param[in]  Width                   1, 4, 8 bits
+
+  @retval     EFI_INVALID_PARAMETER
+  @retval     EFI_UNSUPPORTED
+  @retval     EFI_SUCCESS
+
+**/
+EFI_STATUS
+MMCCardBusWidthTest (
+  IN  CARD_DATA             *CardData,
+  IN  UINT32                Width
+  )
+{
+  EFI_STATUS                 Status;
+  EFI_MMC_HOST_IO_PROTOCOL   *MmcHostIo;
+  UINT64                     Data;
+  UINT64                     Value;
+
+  if (CardData == NULL) {
+    ASSERT(CardData != NULL);
+    return EFI_INVALID_PARAMETER;
+  }
+
+  MmcHostIo = CardData->MmcHostIo;
+  Value = 0;
+
+  switch (Width) {
+    case 1:
+      Data = 0x80;
+      break;
+
+    case 4:
+      Data = 0x5A;
+      break;
+
+    case 8:
+      Data = 0xAA55;
+      break;
+
+    default:
+      Status = EFI_INVALID_PARAMETER;
+      goto Exit;
+  }
+
+  CopyMem (CardData->AlignedBuffer, &Data, Width);
+  Status  = SendCommand (
+              MmcHostIo,
+              BUSTEST_W,
+              0,
+              OutData,
+              CardData->AlignedBuffer,
+              Width,
+              ResponseR1,
+              TIMEOUT_COMMAND,
+              (UINT32 *) &(CardData->CardStatus)
+              );
+
+  if (EFI_ERROR (Status)) {
+    goto Exit;
+  }
+
+  Data = 0;
+  gBS->Stall(10000);
+
+  Status  = SendCommand (
+              MmcHostIo,
+              BUSTEST_R,
+              0,
+              InData,
+              CardData->AlignedBuffer,
+              Width,
+              ResponseR1,
+              TIMEOUT_COMMAND,
+              (UINT32 *) &(CardData->CardStatus)
+              );
+
+  if (EFI_ERROR (Status)) {
+    goto Exit;
+  }
+  CopyMem (&Data, CardData->AlignedBuffer, Width);
+
+  switch (Width) {
+    case 1:
+      Value = (~(Data ^ 0x80)) & 0xC0;
+      break;
+    case 4:
+      Value = (~(Data ^ 0x5A)) & 0xFF;
+      break;
+    case 8:
+      Value = (~(Data ^ 0xAA55)) & 0xFFFF;
+      break;
+  }
+
+  if (Value == 0) {
+    Status = EFI_SUCCESS;
+  } else {
+    Status = EFI_UNSUPPORTED;
+  }
+
+Exit:
+  return Status;
+}
+
+
+/**
+  This function can detect these card types
+  1. MMC card
+  2. SD 1.1 card
+  3. SD 2.0 standard card
+  3. SD 2.0 high capacity card
+
+  @param[in]  CardData               Pointer to CARD_DATA
+
+  @retval     EFI_INVALID_PARAMETER
+  @retval     EFI_UNSUPPORTED
+  @retval     EFI_SUCCESS
+
+**/
+EFI_STATUS
+GetCardType (
+  IN  CARD_DATA              *CardData
+  )
+{
+  EFI_STATUS                 Status;
+  EFI_MMC_HOST_IO_PROTOCOL   *MmcHostIo;
+  UINT32                     TimeOut=5000;
+  MmcHostIo = CardData->MmcHostIo;
+
+  CardData->CardType = MMCCard;
+  MmcHostIo->SetupDevice (MmcHostIo);
+
+  //
+  // To bring back the normal MMC card to work
+  // after sending the SD command. Otherwise some
+  // card could not work
+  //
+  Status  = SendCommand (
+              MmcHostIo,
+              GO_IDLE_STATE,
+              0,
+              NoData,
+              NULL,
+              0,
+              ResponseNo,
+              TIMEOUT_COMMAND,
+              NULL
+              );
+
+  if (EFI_ERROR (Status)) {
+    DEBUG ((EFI_D_ERROR, "GO_IDLE_STATE Fail Status = 0x%x\n", Status));
+  }
+
+  DEBUG (( DEBUG_INFO, "Sending first CMD1.\n"));
+
+  //
+  // CE-ATA device needs long delay
+  //
+  gBS->Stall (1 * 1000);
+
+  //
+  // Get OCR register to check voltage support, first time the OCR is 0
+  //
+  DEBUG (( DEBUG_INFO, "Sending first CMD1  with 0 .\n"));
+  Status  = SendCommand (
+              MmcHostIo,
+              SEND_OP_COND,
+              0x0,
+              NoData,
+              NULL,
+              0,
+              ResponseR3,
+              TIMEOUT_COMMAND,
+              (UINT32 *) &(CardData->OCRRegister)
+              );
+
+  DEBUG ((DEBUG_INFO, "Check OCR register for busy 0x%x\n", *((UINT32 *) &CardData->OCRRegister )));
+
+  gBS->Stall (1 * 1000);
+
+  while (CardData->OCRRegister.Busy != 1) {
+    CardData->OCRRegister.AccessMode = 2;
+    Status  = SendCommand (
+                MmcHostIo,
+                SEND_OP_COND,
+                *(UINT32 *) &(CardData->OCRRegister),
+                NoData,
+                NULL,
+                0,
+                ResponseR3,
+                TIMEOUT_COMMAND,
+                (UINT32 *) &(CardData->OCRRegister)
+                );
+
+    if (EFI_ERROR (Status)) {
+      DEBUG ((EFI_D_ERROR, "SEND_OP_COND Fail Status = 0x%x\n", Status));
+      goto Exit;
+    }
+
+    gBS->Stall (1 * 1000);
+    TimeOut--;
+    if (TimeOut == 0) {
+      DEBUG ((EFI_D_ERROR, "Card is always in busy state\n"));
+      Status = EFI_TIMEOUT;
+      goto Exit;
+    }
+  }
+
+Exit:
+  return Status;
+}
+
+
+/**
+  MMC card high/low voltage selection function
+
+  @param[in]  CardData                 Pointer to CARD_DATA
+
+  @retval     EFI_INVALID_PARAMETER
+  @retval     EFI_UNSUPPORTED
+  @retval     EFI_SUCCESS
+  @retval     EFI_BAD_BUFFER_SIZE
+
+**/
+EFI_STATUS
+MMCCardVoltageSelection (
+  IN  CARD_DATA              *CardData
+  )
+{
+  EFI_STATUS                 Status;
+  EFI_MMC_HOST_IO_PROTOCOL   *MmcHostIo;
+  UINT8                      Index;
+  UINT8                      Retry;
+  UINT32                     TimeOut;
+
+  MmcHostIo = CardData->MmcHostIo;
+  Status   = EFI_SUCCESS;
+
+  if (FALSE) {
+    //
+    //First try the high voltage, then if supported choose the low voltage
+    //
+    for (Index = 0; Index < 2; Index++) {
+      for (Retry = 0; Retry < 3; Retry++) {
+        //
+        // To bring back the normal MMC card to work
+        // after sending the SD command. Otherwise some
+        // card could not work
+        //
+        Status  = SendCommand (
+                    MmcHostIo,
+                    GO_IDLE_STATE,
+                    0,
+                    NoData,
+                    NULL,
+                    0,
+                    ResponseNo,
+                    TIMEOUT_COMMAND,
+                    NULL
+                    );
+
+        if (EFI_ERROR (Status)) {
+          DEBUG ((EFI_D_ERROR, "GO_IDLE_STATE Fail Status = 0x%x\n", Status));
+          continue;
+        }
+        //
+        //CE-ATA device needs long delay
+        //
+        gBS->Stall ((Retry + 1) * 50 * 1000);
+
+        //
+        //Get OCR register to check voltage support, first time the OCR is 0
+        //
+        Status  = SendCommand (
+                    MmcHostIo,
+                    SEND_OP_COND,
+                    0,
+                    NoData,
+                    NULL,
+                    0,
+                    ResponseR3,
+                    TIMEOUT_COMMAND,
+                    (UINT32 *) &(CardData->OCRRegister)
+                    );
+
+        if (!EFI_ERROR (Status)) {
+          break;
+        }
+      }
+
+      if (Retry == 3) {
+        DEBUG ((EFI_D_ERROR, "SEND_OP_COND Fail Status = 0x%x\n", Status));
+        Status = EFI_DEVICE_ERROR;
+        goto Exit;
+      }
+
+      if (CardData->OCRRegister.V170_V195 == 1) {
+        CardData->DualVoltage = TRUE;
+      }
+      if (CardData->OCRRegister.V270_V360 != 0x1F &&
+          CardData->OCRRegister.V200_V260 != 0) {
+        DEBUG ((EFI_D_ERROR, "Incompatiable voltage device\n"));
+        PutCardInactive (CardData);
+        Status = EFI_INCOMPATIBLE_VERSION;
+        goto Exit;
+      }
+
+      if (Index == 0) {
+        //
+        // Choose the high voltage first
+        //
+        CardData->OCRRegister.V170_V195 = 0;
+      } else {
+        //
+        // Choose the low voltage
+        //
+        CardData->OCRRegister.V170_V195 = 1;
+        CardData->OCRRegister.V270_V360 = 0;
+      }
+
+      //
+      // Set sector mode
+      //
+      CardData->OCRRegister.AccessMode |= 2;
+
+      //
+      // TimeOut Value, 5000 * 100 * 1000 = 5 s
+      //
+      TimeOut = 5000;
+
+      do {
+        Status  = SendCommand (
+                    MmcHostIo,
+                    SEND_OP_COND,
+                    *(UINT32 *) &(CardData->OCRRegister),
+                    NoData,
+                    NULL,
+                    0,
+                    ResponseR3,
+                    TIMEOUT_COMMAND,
+                    (UINT32 *) &(CardData->OCRRegister)
+                    );
+
+        if (EFI_ERROR (Status)) {
+          DEBUG ((EFI_D_ERROR, "SEND_OP_COND Fail Status = 0x%x\n", Status));
+          goto Exit;
+        }
+
+        gBS->Stall (1 * 1000);
+        TimeOut--;
+        if (TimeOut == 0) {
+          DEBUG ((EFI_D_ERROR, "Card is always in busy state\n"));
+          Status = EFI_TIMEOUT;
+          goto Exit;
+        }
+      } while (CardData->OCRRegister.Busy != 1);
+
+      if (CardData->DualVoltage == TRUE && MmcHostIo->HostCapability.V18Support == TRUE) {
+        //
+        //Power Off the card and then power on into low voltage
+        //
+        MmcHostIo->SetHostVoltage (MmcHostIo, 0);
+        gBS->Stall (1 * 1000);
+        MmcHostIo->SetHostVoltage (MmcHostIo, 18);
+      } else {
+        //
+        //Not support the low voltage, exit
+        //
+        break;
+      }
+    }
+  }
+
+Exit:
+  return Status;
+}
+
+
+/**
+  This function set the bus and device width for MMC card
+
+  @param[in]  CardData                Pointer to CARD_DATA
+  @param[in]  BusWidth                1, 4, 8 bits
+
+  @retval     EFI_INVALID_PARAMETER
+  @retval     EFI_UNSUPPORTED
+  @retval     EFI_SUCCESS
+
+**/
+EFI_STATUS
+MMCCardSetBusWidth (
+  IN  CARD_DATA              *CardData,
+  IN  UINT8                  BusWidth
+  )
+{
+  EFI_STATUS                 Status;
+  EFI_MMC_HOST_IO_PROTOCOL   *MmcHostIo;
+  SWITCH_ARGUMENT            SwitchArgument;
+  UINT8                      Value;
+
+  MmcHostIo = CardData->MmcHostIo;
+  Value = 0;
+  switch (BusWidth) {
+    case 28:    //20 in 28 indicates DDR in 8 bit bus
+      Value = 6;
+      break;
+
+    case 24:    //20 in 24 indicates DDR in 4 bit bus
+      Value = 5;
+      break;
+
+    case 8:
+      Value = 2;
+      break;
+
+    case 4:
+      Value = 1;
+      break;
+
+    case 1:
+      Value = 0;
+      break;
+
+    default:
+     ASSERT (0);
+  }
+
+  //
+  // HS_TIMING must be set to 0x1 before setting BUS_WIDTH for dual data rate operation (values 5 or 6)
+  //
+  if (Value == 5 || Value == 6 ) {
+    ZeroMem(&SwitchArgument, sizeof (SWITCH_ARGUMENT));
+    SwitchArgument.CmdSet = 0;
+    SwitchArgument.Value  = 0x1;
+    SwitchArgument.Index  = (UINT32) ((UINTN)
+    (&(CardData->ExtCSDRegister.HS_TIMING)) - (UINTN) (&(CardData->ExtCSDRegister)));
+    SwitchArgument.Access = WriteByte_Mode;
+    Status  = SendCommand (
+                MmcHostIo,
+                SWITCH,
+                *(UINT32 *) &SwitchArgument,
+                NoData,
+                NULL,
+                0,
+                ResponseR1b,
+                TIMEOUT_COMMAND,
+                (UINT32 *) &(CardData->CardStatus)
+                );
+
+    if (!EFI_ERROR (Status)) {
+     Status  = SendCommand (
+                 MmcHostIo,
+                 SEND_STATUS,
+                 (CardData->Address << 16),
+                 NoData,
+                 NULL,
+                 0,
+                 ResponseR1,
+                 TIMEOUT_COMMAND,
+                 (UINT32 *) &(CardData->CardStatus)
+                 );
+    } else {
+      DEBUG ((DEBUG_ERROR, "SWITCH Fail in HS Timing setting\n"));
+    }
+  }
+
+  ZeroMem (&SwitchArgument, sizeof (SWITCH_ARGUMENT));
+  SwitchArgument.CmdSet = 0;
+  SwitchArgument.Value  = Value;
+  SwitchArgument.Index  = (UINT32) ((UINTN)
+                          (&(CardData->ExtCSDRegister.BUS_WIDTH)) - (UINTN) (&(CardData->ExtCSDRegister)));
+  SwitchArgument.Access = WriteByte_Mode;
+  Status  = SendCommand (
+              MmcHostIo,
+              SWITCH,
+              *(UINT32 *) &SwitchArgument,
+              NoData,
+              NULL,
+              0,
+              ResponseR1b,
+              TIMEOUT_COMMAND,
+              (UINT32 *) &(CardData->CardStatus)
+              );
+
+  if (!EFI_ERROR (Status)) {
+    Status  = SendCommand (
+                MmcHostIo,
+                SEND_STATUS,
+                (CardData->Address << 16),
+                NoData,
+                NULL,
+                0,
+                ResponseR1,
+                TIMEOUT_COMMAND,
+                (UINT32 *) &(CardData->CardStatus)
+                );
+
+    if (EFI_ERROR (Status)) {
+      DEBUG ((EFI_D_ERROR, "SWITCH %d bits Fail\n", BusWidth));
+      goto Exit;
+    } else {
+      if ((BusWidth == 24) || (BusWidth == 28)) {
+        Status = MmcHostIo->SetBusWidth (MmcHostIo, BusWidth - 20);
+      } else {
+        Status = MmcHostIo->SetBusWidth (MmcHostIo, BusWidth);
+      }
+      if (EFI_ERROR (Status)) {
+        goto Exit;
+      }
+
+      gBS->Stall (5 * 1000);
+    }
+  }
+  if ((BusWidth == 24) || (BusWidth == 28)) {
+    goto Exit;
+  } else {
+    Status = MMCCardBusWidthTest (CardData, BusWidth);
+  }
+  if (EFI_ERROR (Status)) {
+    DEBUG ((EFI_D_ERROR, "MMCCardBusWidthTest %d bit Fail\n", BusWidth));
+    goto Exit;
+  }
+
+  CardData->CurrentBusWidth = BusWidth;
+
+Exit:
+  return Status;
+}
+
+
+/**
+  MMC/SD card init function
+
+  @param[in]  CardData                 Pointer to CARD_DATA
+
+  @retval     EFI_INVALID_PARAMETER
+  @retval     EFI_UNSUPPORTED
+  @retval     EFI_SUCCESS
+  @retval     EFI_BAD_BUFFER_SIZE
+
+**/
+EFI_STATUS
+MMCSDCardInit (
+  IN  CARD_DATA              *CardData
+  )
+{
+  EFI_STATUS                 Status;
+  EFI_MMC_HOST_IO_PROTOCOL   *MmcHostIo;
+  SWITCH_ARGUMENT            SwitchArgument;
+  UINT32                     Data;
+  UINT32                     Argument;
+  UINT32                     HsTimingValue;
+  UINT8                      PowerValue;
+  UINT8                      DoubleSpeed;
+  UINTN                      Offset;
+
+  if (CardData == NULL) {
+    ASSERT (CardData != NULL);
+    return EFI_INVALID_PARAMETER;
+  }
+  MmcHostIo = CardData->MmcHostIo;
+  CardData->CurrentBusWidth = 1;
+
+  Status = GetCardType (CardData);
+  if (EFI_ERROR (Status)) {
+    DEBUG ((EFI_D_ERROR, "GetCardType -> %r\n", Status));
+    goto Exit;
+  }
+
+  ASSERT (CardData->CardType != UnknownCard);
+  //
+  //MMC, SD card need host auto stop command support
+  //
+  MmcHostIo->EnableAutoStopCmd (MmcHostIo, TRUE);
+
+
+  //
+  // Get CID Register, but the info is not used currently
+  //
+  Status  = SendCommand (
+              MmcHostIo,
+              ALL_SEND_CID,
+              0,
+              NoData,
+              NULL,
+              0,
+              ResponseR2,
+              TIMEOUT_COMMAND,
+              (UINT32 *) &(CardData->CIDRegister)
+              );
+
+  PcdSet8S (PcdEmmcManufacturerId, CardData->CIDRegister.MID);
+  PcdSet32S (PcdProductSerialNumber, CardData->CIDRegister.PSN);
+
+  if (EFI_ERROR (Status)) {
+    DEBUG ((EFI_D_ERROR, "ALL_SEND_CID -> %r\n", Status));
+    goto Exit;
+  }
+
+  //
+  //SET_RELATIVE_ADDR
+  //
+  if (CardData->CardType == MMCCard) {
+    CardData->Address = 1;
+    //
+    // Set RCA Register
+    //
+    Status  = SendCommand (
+                MmcHostIo,
+                SET_RELATIVE_ADDR,
+                (CardData->Address << 16),
+                NoData,
+                NULL,
+                0,
+                ResponseR1,
+                TIMEOUT_COMMAND,
+                (UINT32 *) &(CardData->CardStatus)
+                );
+
+    if (EFI_ERROR (Status)) {
+      DEBUG ((EFI_D_ERROR, "SET_RELATIVE_ADDR -> %r\n", Status));
+      goto Exit;
+    }
+  }
+
+  //
+  // Get CSD Register
+  //
+  Status  = SendCommand (
+              MmcHostIo,
+              SEND_CSD,
+              (CardData->Address << 16),
+              NoData,
+              NULL,
+              0,
+              ResponseR2,
+              TIMEOUT_COMMAND,
+              (UINT32 *) &(CardData->CSDRegister)
+              );
+
+  if (EFI_ERROR (Status)) {
+    DEBUG ((EFI_D_ERROR, "SEND_CSD -> %r\n", Status));
+    goto Exit;
+  }
+
+  MmcDecodeCSD(&CardData->CSDRegister);
+
+  Status = CalculateCardParameter (CardData);
+  if (EFI_ERROR (Status)) {
+    DEBUG ((EFI_D_ERROR, "CalculateCardParameter -> %r\n", Status));
+    goto Exit;
+  }
+
+  //
+  // Put the card into tran state
+  //
+  Status = SendCommand (
+             MmcHostIo,
+             SELECT_DESELECT_CARD,
+             (CardData->Address << 16),
+             NoData,
+             NULL,
+             0,
+             ResponseR1,
+             TIMEOUT_COMMAND,
+             (UINT32 *) &(CardData->CardStatus)
+             );
+
+  if (EFI_ERROR (Status)) {
+    DEBUG ((EFI_D_ERROR, "SELECT_DESELECT_CARD -> %r\n", Status));
+    goto Exit;
+  }
+
+  Status  = SendCommand (
+              MmcHostIo,
+              SEND_STATUS,
+              (CardData->Address << 16),
+              NoData,
+              NULL,
+              0,
+              ResponseR1,
+              TIMEOUT_COMMAND,
+              (UINT32 *) &(CardData->CardStatus)
+              );
+
+  if (EFI_ERROR (Status)) {
+    DEBUG ((EFI_D_ERROR, "SELECT_DESELECT_CARD SEND_STATUS Fail Status = 0x%x\n", Status));
+    goto Exit;
+  }
+
+  if (CardData->CardType == MMCCard) {
+    //
+    // Only V4.0 and above supports more than 1 bits and high speed
+    //
+    if (CardData->CSDRegister.SPEC_VERS >= 4) {
+      Offset = OFFSET_OF (EXT_CSD, ERASE_GROUP_DEF);
+      Status = MmcSetExtCsd8 (CardData, (UINT8) Offset, 0x01);
+      //
+      // Get ExtCSDRegister
+      //
+      Status  = SendCommand (
+                  MmcHostIo,
+                  SEND_EXT_CSD,
+                  0,
+                  InData,
+                  CardData->AlignedBuffer,
+                  sizeof (EXT_CSD),
+                  ResponseR1,
+                  TIMEOUT_DATA,
+                  (UINT32 *) &(CardData->CardStatus)
+                  );
+
+      if (EFI_ERROR (Status)) {
+        DEBUG ((EFI_D_ERROR, "SEND_EXT_CSD -> %r\n", Status));
+        goto Exit;
+      }
+
+      CopyMem (&(CardData->ExtCSDRegister), CardData->AlignedBuffer, sizeof (EXT_CSD));
+
+      MmcDecodeExtCSD (&CardData->ExtCSDRegister);
+
+      //
+      // Recaculate the block number for >2G MMC card
+      //
+      Data  = (CardData->ExtCSDRegister.SEC_COUNT[0]) |
+              (CardData->ExtCSDRegister.SEC_COUNT[1] << 8) |
+              (CardData->ExtCSDRegister.SEC_COUNT[2] << 16) |
+              (CardData->ExtCSDRegister.SEC_COUNT[3] << 24);
+
+      if (Data != 0) {
+        CardData->BlockNumber = Data;
+      }
+      DEBUG ((DEBUG_INFO, "CardData->BlockNumber  %d\n", Data));
+
+      //
+      // Check the DDR setting
+      //
+      DoubleSpeed = 0 ;
+      DEBUG ((DEBUG_INFO, "CardData->ExtCSDRegister.CARD_TYPE -> %d\n", (UINTN) CardData->ExtCSDRegister.CARD_TYPE));
+      if (CardData->ExtCSDRegister.CARD_TYPE & BIT0) {
+        DEBUG ((DEBUG_INFO, "High-Speed e MMC @ 26MHz - at rated device voltage(s) supported\n"));
+      }
+      if (CardData->ExtCSDRegister.CARD_TYPE & BIT1) {
+        DEBUG ((DEBUG_INFO, "High-Speed e MMC @ 52MHz - at rated device voltage(s) supported\n"));
+      }
+      if (CardData->ExtCSDRegister.CARD_TYPE & BIT2) {
+        DEBUG ((DEBUG_INFO, "High-Speed Dual Data Rate e MMC @ 52MHz - 1.8V or 3V I/O supported\n"));
+      }
+      if (CardData->ExtCSDRegister.CARD_TYPE & BIT3) {
+        DEBUG ((DEBUG_INFO, "High-Speed Dual Data Rate e MMC @ 52MHz - 1.2V I/O supported\n"));
+      }
+      if (CardData->ExtCSDRegister.CARD_TYPE & BIT4) {
+        DEBUG ((DEBUG_INFO, "HS200 Single Data Rate e MMC @ 200 MHz - 1.8V I/O supported\n"));
+      }
+      if (CardData->ExtCSDRegister.CARD_TYPE & BIT5) {
+        DEBUG ((DEBUG_INFO, "HS200 Single Data Rate e MMC @ 200 MHz - 1.2V I/O supported\n"));
+      }
+      if (CardData->ExtCSDRegister.CARD_TYPE & BIT6) {
+        DEBUG ((DEBUG_INFO, "HS400 Dual Data Rate e MMC @ 200MHz - 1.8V I/O supported\n"));
+      }
+      if (CardData->ExtCSDRegister.CARD_TYPE & BIT7) {
+        DEBUG ((DEBUG_INFO, "HS400 Dual Data Rate e MMC @ 200MHz - 1.2V I/O supported\n"));
+      }
+
+      if ((CardData->ExtCSDRegister.CARD_TYPE & BIT2) || (CardData->ExtCSDRegister.CARD_TYPE & BIT3)) {
+        DEBUG ((DEBUG_INFO, "Card support DDR\n"));
+        DoubleSpeed = 20;   //Add 20 for double speed, decoded in MMCCardSetBusWidth()
+      }
+
+      DEBUG ((EFI_D_INFO, "%a(%d): %a() no more FPGA doublespeed workaround needed\n", __FILE__, __LINE__, __FUNCTION__));
+
+      if (MmcHostIo->HostCapability.HighSpeedSupport) {
+
+        HsTimingValue = 1;
+
+        //
+        // Change to high frequency mode
+        //
+        ZeroMem (&SwitchArgument, sizeof (SWITCH_ARGUMENT));
+        SwitchArgument.CmdSet = 0;
+        SwitchArgument.Value  = HsTimingValue;
+        SwitchArgument.Index  = (UINT32) ((UINTN)
+                                (&(CardData->ExtCSDRegister.HS_TIMING)) - (UINTN) (&(CardData->ExtCSDRegister)));
+        SwitchArgument.Access = WriteByte_Mode;
+        Status  = SendCommand (
+                    CardData->MmcHostIo,
+                    SWITCH,
+                    *(UINT32 *) &SwitchArgument,
+                    NoData,
+                    NULL,
+                    0,
+                    ResponseR1b,
+                    TIMEOUT_COMMAND,
+                    (UINT32 *) &(CardData->CardStatus)
+                    );
+
+        if (EFI_ERROR (Status)) {
+          DEBUG ((EFI_D_ERROR, "SWITCH frequency -> %r\n", Status));
+        }
+
+        if (!EFI_ERROR (Status)) {
+          Status  = SendCommand (
+                      MmcHostIo,
+                      SEND_STATUS,
+                      (CardData->Address << 16),
+                      NoData,
+                      NULL,
+                      0,
+                      ResponseR1,
+                      TIMEOUT_COMMAND,
+                      (UINT32 *) &(CardData->CardStatus)
+                      );
+
+          if (!EFI_ERROR (Status)) {
+            //
+            // Enable the high speed mode
+            //
+             if (DoubleSpeed != 0) {
+               Status = MmcHostIo->SetHostDdrMode (MmcHostIo, TRUE);
+              DEBUG ((DEBUG_INFO, "Set to DDR50 mode \n", Status));
+             } else  {
+                 Status = MmcHostIo->SetHostSpeedMode (MmcHostIo, 1);
+                DEBUG ((DEBUG_ERROR, "Set to HS mode \n", Status));
+               }
+
+             if (EFI_ERROR (Status)) {
+              goto Exit;
+             }
+            //
+            // Change host clock
+            //
+            if ((CardData->ExtCSDRegister.CARD_TYPE & BIT1) != 0) {
+              Status = MmcHostIo->SetClockFrequency (MmcHostIo, FREQUENCY_MMC_PP_HIGH);
+            } else if ((CardData->ExtCSDRegister.CARD_TYPE & BIT0) != 0) {
+              Status = MmcHostIo->SetClockFrequency (MmcHostIo, FREQUENCY_MMC_PP);
+            } else {
+              Status = EFI_UNSUPPORTED;
+            }
+
+            if (EFI_ERROR (Status)) {
+              goto Exit;
+            }
+
+            //
+            // It seems no need to stall after changing bus freqeuncy.
+            // It is said that the freqeuncy can be changed at any time. Just appends 8 clocks after command.
+            // But SetClock alreay has delay.
+            //
+          }
+        }
+      }
+
+      //
+      // Prefer wide bus width for performance
+      //
+      //
+      // Set to BusWidth bits mode, only version 4.0 or above support more than 1 bits
+      //
+      if (MmcHostIo->HostCapability.BusWidth8 == 1) {
+        Status = MMCCardSetBusWidth (CardData, DoubleSpeed + 8);
+        if (EFI_ERROR (Status)) {
+          //
+          // CE-ATA may support 8 bits and 4 bits, but has no software method for detection
+          //
+          Status = MMCCardSetBusWidth (CardData, DoubleSpeed + 4);
+          if (EFI_ERROR (Status)) {
+            goto Exit;
+          }
+        }
+      } else if (MmcHostIo->HostCapability.BusWidth4 == 1) {
+        Status = MMCCardSetBusWidth (CardData, DoubleSpeed + 4);
+        if (EFI_ERROR (Status)) {
+          goto Exit;
+        }
+      }
+
+      PowerValue = 0;
+
+      if (CardData->CurrentBusWidth == 8) {
+        if ((CardData->ExtCSDRegister.CARD_TYPE & BIT1) != 0) {
+          PowerValue = CardData->ExtCSDRegister.PWR_CL_52_360;
+          PowerValue = PowerValue >> 4;
+        } else if ((CardData->ExtCSDRegister.CARD_TYPE & BIT0) != 0) {
+          PowerValue = CardData->ExtCSDRegister.PWR_CL_26_360;
+          PowerValue = PowerValue >> 4;
+        }
+      } else if (CardData->CurrentBusWidth == 4) {
+        if ((CardData->ExtCSDRegister.CARD_TYPE & BIT1) != 0) {
+          PowerValue = CardData->ExtCSDRegister.PWR_CL_52_360;
+          PowerValue = PowerValue & 0xF;
+        } else if ((CardData->ExtCSDRegister.CARD_TYPE & BIT0) != 0) {
+          PowerValue = CardData->ExtCSDRegister.PWR_CL_26_360;
+          PowerValue = PowerValue & 0xF;
+        }
+      }
+
+      if (PowerValue != 0) {
+        //
+        // Update Power Class
+        //
+        ZeroMem (&SwitchArgument, sizeof (SWITCH_ARGUMENT));
+        SwitchArgument.CmdSet = 0;
+        SwitchArgument.Value  = PowerValue;
+        SwitchArgument.Index  = (UINT32) ((UINTN)
+                                (&(CardData->ExtCSDRegister.POWER_CLASS)) - (UINTN) (&(CardData->ExtCSDRegister)));
+        SwitchArgument.Access = WriteByte_Mode;
+        Status  = SendCommand (
+                    MmcHostIo,
+                    SWITCH,
+                    *(UINT32 *) &SwitchArgument,
+                    NoData,
+                    NULL,
+                    0,
+                    ResponseR1b,
+                    TIMEOUT_COMMAND,
+                    (UINT32 *) &(CardData->CardStatus)
+                    );
+
+        if (!EFI_ERROR (Status)) {
+          Status  = SendCommand (
+                      MmcHostIo,
+                      SEND_STATUS,
+                      (CardData->Address << 16),
+                      NoData,
+                      NULL,
+                      0,
+                      ResponseR1,
+                      TIMEOUT_COMMAND,
+                      (UINT32 *) &(CardData->CardStatus)
+                      );
+
+          if (EFI_ERROR (Status)) {
+            DEBUG ((EFI_D_ERROR, "SWITCH Power Class -> %r\n", Status));
+          }
+
+        }
+      }
+    } else {
+      DEBUG ((EFI_D_ERROR, "MMC Card version %d only supportes 1 bits at lower transfer speed\n", CardData->CSDRegister.SPEC_VERS));
+    }
+
+    //
+    // Register for Ready to Boot event to enable Write protection
+    //
+    Status = gBS->CreateEventEx (
+                    EVT_NOTIFY_SIGNAL,
+                    TPL_CALLBACK,
+                    SetEmmcWpOnEvent,
+                    CardData,
+                    &gEfiEventReadyToBootGuid,
+                    &mSetEmmcWpOnEvent
+                    );
+
+  } else {
+    //
+    // Pin 1, at power up this line has a 50KOhm pull up enabled in the card.
+    // This pull-up should be disconnected by the user, during regular data transfer,
+    // with SET_CLR_CARD_DETECT (ACMD42) command
+    //
+    Status  = SendAppCommand (
+                CardData,
+                SET_CLR_CARD_DETECT,
+                0,
+                NoData,
+                NULL,
+                0,
+                ResponseR1,
+                TIMEOUT_COMMAND,
+                (UINT32 *) &(CardData->CardStatus)
+                );
+
+    if (EFI_ERROR (Status)) {
+      DEBUG ((EFI_D_ERROR, "SET_CLR_CARD_DETECT Fail -> %r\n", Status));
+      goto Exit;
+    }
+
+    //
+    // Set Bus Width to 4
+    //
+    Status  = SendAppCommand (
+                CardData,
+                SET_BUS_WIDTH,
+                SD_BUS_WIDTH_4,
+                NoData,
+                NULL,
+                0,
+                ResponseR1,
+                TIMEOUT_COMMAND,
+                (UINT32 *) &(CardData->CardStatus)
+                );
+
+    if (EFI_ERROR (Status)) {
+      DEBUG ((EFI_D_ERROR, "SET_BUS_WIDTH 4 bits -> %r\n", Status));
+      goto Exit;
+    }
+
+    Status = MmcHostIo->SetBusWidth (MmcHostIo, 4);
+    if (EFI_ERROR (Status)) {
+      goto Exit;
+    }
+    CardData->CurrentBusWidth = 4;
+
+    if ((MmcHostIo->HostCapability.HighSpeedSupport == FALSE) ||
+        ((CardData->CSDRegister.CCC & BIT10) != BIT10)) {
+      //
+      // Host must support high speed
+      // Card must support Switch function
+      //
+      goto Exit;
+    }
+
+    //
+    // Mode = 0, group 1, function 1, check operation
+    //
+    Argument = 0xFFFF01;
+    ZeroMem (&CardData->SwitchStatus, sizeof (SWITCH_STATUS));
+
+    Status  = SendCommand (
+                MmcHostIo,
+                SWITCH_FUNC,
+                Argument,
+                InData,
+                CardData->AlignedBuffer,
+                sizeof (SWITCH_STATUS),
+                ResponseR1,
+                TIMEOUT_COMMAND,
+                (UINT32 *) &(CardData->CardStatus)
+                );
+
+    if (EFI_ERROR (Status)) {
+      goto Exit;
+    }
+    CopyMem (&(CardData->SwitchStatus), CardData->AlignedBuffer, sizeof (SWITCH_STATUS));
+
+    if ((CardData->SwitchStatus.DataStructureVersion == 0x0) ||
+        ((CardData->SwitchStatus.Group1BusyStatus & BIT1) != BIT1)) {
+      //
+      // 1. SD 1.1 card does not suppport busy bit
+      // 2. Ready state
+      //
+      //
+      //
+      // Mode = 1, group 1, function 1, BIT31 set means set mode
+      //
+      Argument = 0xFFFF01 | BIT31;
+      ZeroMem (&CardData->SwitchStatus, sizeof (SWITCH_STATUS));
+
+      Status  = SendCommand (
+                  MmcHostIo,
+                  SWITCH_FUNC,
+                  Argument,
+                  InData,
+                  CardData->AlignedBuffer,
+                  sizeof (SWITCH_STATUS),
+                  ResponseR1,
+                  TIMEOUT_COMMAND,
+                  (UINT32 *) &(CardData->CardStatus)
+                  );
+
+      if (EFI_ERROR (Status)) {
+        goto Exit;
+      }
+      CopyMem (&(CardData->SwitchStatus), CardData->AlignedBuffer, sizeof (SWITCH_STATUS));
+
+      if ((CardData->SwitchStatus.DataStructureVersion == 0x0) ||
+          ((CardData->SwitchStatus.Group1BusyStatus & BIT1) != BIT1)) {
+        //
+        // 1. SD 1.1 card does not suppport busy bit
+        // 2. Ready state
+        //
+        //
+        // 8 clocks, (1/ 25M) * 8 ==> 320 us, so 1ms > 0.32 ms
+        //
+        gBS->Stall (1000);
+      }
+    }
+  }
+  if (!((CardData->ExtCSDRegister.CARD_TYPE & BIT2) ||
+        (CardData->ExtCSDRegister.CARD_TYPE & BIT3))) {
+    //
+    // Set Block Length, to improve compatibility in case of some cards
+    //
+    Status  = SendCommand (
+                MmcHostIo,
+                SET_BLOCKLEN,
+                512,
+                NoData,
+                NULL,
+                0,
+                ResponseR1,
+                TIMEOUT_COMMAND,
+                (UINT32 *) &(CardData->CardStatus)
+                );
+
+    if (EFI_ERROR (Status)) {
+      DEBUG ((EFI_D_ERROR, "SET_BLOCKLEN -> %r\n", Status));
+      goto Exit;
+    }
+  }
+  MmcHostIo->SetBlockLength (MmcHostIo, 512);
+
+Exit:
+  if (Status) {
+
+  }
+
+  return Status;
+}
+
+
+/**
+  MmcSelect
+
+  @param[in]  CardData      Pointer to CARD_DATA
+  @param[in]  Select
+
+  @retval     EFI_STATUS
+
+**/
+EFI_STATUS
+MmcSelect (
+  IN CARD_DATA     *CardData,
+  IN BOOLEAN       Select
+  )
+{
+  return SendCommand (
+           CardData->MmcHostIo,
+           SELECT_DESELECT_CARD,
+           Select ? (CardData->Address << 16) : ~(CardData->Address << 16),
+           NoData,
+           NULL,
+           0,
+           ResponseR1,
+           TIMEOUT_COMMAND,
+           (UINT32 *) &(CardData->CardStatus)
+           );
+}
+
+
+/**
+  MmcSendSwitch
+
+  @param[in]  CardData                 Pointer to CARD_DATA
+  @param[in]  SwitchArgument           Pointer to SWITCH_ARGUMENT
+
+  @retval     EFI_INVALID_PARAMETER
+  @retval     EFI_UNSUPPORTED
+  @retval     EFI_SUCCESS
+
+**/
+EFI_STATUS
+MmcSendSwitch (
+  IN  CARD_DATA              *CardData,
+  IN SWITCH_ARGUMENT         *SwitchArgument
+  )
+{
+  EFI_STATUS                 Status;
+  EFI_MMC_HOST_IO_PROTOCOL   *MmcHostIo;
+
+  MmcHostIo = CardData->MmcHostIo;
+
+  Status  = SendCommand (
+              MmcHostIo,
+              SWITCH,
+              *(UINT32 *) SwitchArgument,
+              NoData,
+              NULL,
+              0,
+              ResponseR1b,
+              TIMEOUT_DATA,
+              (UINT32 *) &(CardData->CardStatus)
+              );
+
+  if (!EFI_ERROR (Status)) {
+    Status  = SendCommand (
+                MmcHostIo,
+                SEND_STATUS,
+                (CardData->Address << 16),
+                NoData,
+                NULL,
+                0,
+                ResponseR1,
+                TIMEOUT_COMMAND,
+                (UINT32 *) &(CardData->CardStatus)
+                );
+
+    if (EFI_ERROR (Status)) {
+      DEBUG ((EFI_D_ERROR, "SWITCH FAILURE\n"));
+    }
+  }
+
+  return Status;
+}
+
+
+/**
+  MmcUpdateCardStatus
+
+  @param[in]  CardData                 Pointer to CARD_DATA
+
+  @retval     EFI_INVALID_PARAMETER
+  @retval     EFI_UNSUPPORTED
+  @retval     EFI_SUCCESS
+
+**/
+EFI_STATUS
+MmcUpdateCardStatus (
+  IN CARD_DATA     *CardData
+  )
+{
+  return SendCommand (
+           CardData->MmcHostIo,
+           SEND_STATUS,
+           (CardData->Address << 16),
+           NoData,
+           NULL,
+           0,
+           ResponseR1,
+           TIMEOUT_COMMAND,
+           (UINT32 *) &(CardData->CardStatus)
+           );
+}
+
+
+/**
+  MmcMoveToTranState
+
+  @param[in]  CardData                Pointer to CARD_DATA
+
+  @retval     EFI_INVALID_PARAMETER
+  @retval     EFI_UNSUPPORTED
+  @retval     EFI_SUCCESS
+
+**/
+EFI_STATUS
+MmcMoveToTranState (
+  IN CARD_DATA     *CardData
+  )
+{
+  EFI_STATUS  Status;
+
+  Status = EFI_SUCCESS;
+
+  if (CardData->CardStatus.CURRENT_STATE != Tran_STATE) {
+    //
+    // Put the card into tran state
+    //
+    Status = MmcSelect (CardData, TRUE);
+    MmcUpdateCardStatus (CardData);
+  }
+
+  if (CardData->CardStatus.CURRENT_STATE != Tran_STATE) {
+    DEBUG ((EFI_D_ERROR, "MmcMoveToTranState: Unable to put card into tran state\n"));
+    return EFI_DEVICE_ERROR;
+  }
+
+  return Status;
+}
+
+
+/**
+  MmcReadExtCsd
+
+  @param[in,out]  CardData                  Pointer to CARD_DATA
+
+  @retval         EFI_INVALID_PARAMETER
+  @retval         EFI_UNSUPPORTED
+  @retval         EFI_SUCCESS
+
+**/
+EFI_STATUS
+MmcReadExtCsd (
+  IN OUT CARD_DATA     *CardData
+  )
+{
+  EFI_STATUS  Status;
+
+  Status = MmcMoveToTranState (CardData);
+  if (EFI_ERROR (Status)) {
+    return Status;
+  }
+
+  Status  = SendCommand (
+              CardData->MmcHostIo,
+              SEND_EXT_CSD,
+              0,
+              InData,
+              CardData->AlignedBuffer,
+              sizeof (EXT_CSD),
+              ResponseR1,
+              TIMEOUT_DATA,
+              (UINT32 *) &(CardData->CardStatus)
+              );
+
+  DEBUG ((EFI_D_INFO, "MmcReadExtCsd: SEND_EXT_CSD -> %r\n", Status));
+  if (EFI_ERROR (Status)) {
+    return EFI_DEVICE_ERROR;
+  }
+
+  CopyMem (&(CardData->ExtCSDRegister), CardData->AlignedBuffer, sizeof (EXT_CSD));
+
+  return Status;
+}
+
+
+/**
+  MmcSetExtCsd8
+
+  @param[in]  CardData                Pointer to CARD_DATA
+  @param[in]  Index
+  @param[in]  Value
+
+  @retval     EFI_INVALID_PARAMETER
+  @retval     EFI_UNSUPPORTED
+  @retval     EFI_SUCCESS
+
+**/
+EFI_STATUS
+MmcSetExtCsd8 (
+  IN  CARD_DATA              *CardData,
+  IN  UINT8                  Index,
+  IN  UINT8                  Value
+  )
+{
+  EFI_STATUS                 Status;
+  SWITCH_ARGUMENT            SwitchArgument;
+
+  Status = MmcMoveToTranState (CardData);
+  if (EFI_ERROR (Status)) {
+    return Status;
+  }
+
+  ZeroMem (&SwitchArgument, sizeof (SWITCH_ARGUMENT));
+  SwitchArgument.CmdSet = 0;
+  SwitchArgument.Value  = (UINT8) Value;
+  SwitchArgument.Index  = (UINT8) Index;
+  SwitchArgument.Access = WriteByte_Mode; // SetBits_Mode;
+
+  return MmcSendSwitch (CardData, &SwitchArgument);
+}
+
+
+/**
+  MmcSetExtCsd24
+
+  @param[in]  CardData                Pointer to CARD_DATA
+  @param[in]  Index
+  @param[in]  Value
+
+  @retval     EFI_INVALID_PARAMETER
+  @retval     EFI_UNSUPPORTED
+  @retval     EFI_SUCCESS
+
+**/
+EFI_STATUS
+MmcSetExtCsd24 (
+  IN  CARD_DATA              *CardData,
+  IN  UINT8                  Index,
+  IN  UINT32                 Value
+  )
+{
+  EFI_STATUS                 Status;
+  UINTN                      Loop;
+
+  ASSERT ((Value & 0xff000000ULL) == 0);
+
+  for (Loop = 0; Loop < 3; Loop++) {
+    Status = MmcSetExtCsd8 (CardData, Index + (UINT8) Loop, Value & 0xff);
+    if (EFI_ERROR (Status)) {
+      return Status;
+    }
+    Value = Value >> 8;
+  }
+
+  return Status;
+}
+
+
+/**
+  MmcGetExtCsd8
+
+  @param[in]  CardData             Pointer to CARD_DATA
+  @param[in]  Offset
+
+  @retval     CSD Register value
+
+**/
+UINT32
+MmcGetExtCsd8 (
+  IN CARD_DATA                        *CardData,
+  IN UINTN                            Offset
+  )
+{
+  ASSERT (Offset < sizeof (CardData->ExtCSDRegister));
+  return ((UINT8 *) &CardData->ExtCSDRegister)[Offset];
+}
+
+
+/**
+  MmcGetExtCsd32
+
+  @param[in]  CardData             Pointer to CARD_DATA
+  @param[in]  Offset
+
+  @retval     CSD Register value
+
+**/
+UINT32
+MmcGetExtCsd32 (
+  IN CARD_DATA                        *CardData,
+  IN UINTN                            Offset
+  )
+{
+  return *(UINT32 *) (((UINT8 *) &CardData->ExtCSDRegister) + Offset);
+}
+
+
+/**
+  MmcGetExtCsd24
+
+  @param[in]  CardData             Pointer to CARD_DATA
+  @param[in]  Offset
+
+  @retval     CSD Register value
+
+**/
+UINT32
+MmcGetExtCsd24 (
+  IN CARD_DATA                       *CardData,
+  IN UINTN                           Offset
+  )
+{
+  return MmcGetExtCsd32 (CardData, Offset) & 0xffffff;
+}
+
+
+/**
+  MmcGetCurrentPartitionNum
+
+  @param[in]  CardData              Pointer to CARD_DATA
+
+  @retval     Current Partition Num
+
+**/
+UINTN
+MmcGetCurrentPartitionNum (
+  IN  CARD_DATA              *CardData
+  )
+{
+  return MmcGetExtCsd8 (
+           CardData,
+           OFFSET_OF (EXT_CSD, PARTITION_CONFIG)
+           ) & 0x7;
+}
+
+
+/**
+  SetEmmcWpOnEvent
+
+  @param[in]  Event
+  @param[in]  Context
+
+  @retval     None
+
+**/
+VOID
+EFIAPI
+SetEmmcWpOnEvent(
+  IN EFI_EVENT          Event,
+  IN VOID               *Context
+  )
+{
+  EFI_STATUS            Status;
+  UINTN                 Offset;
+  CARD_DATA             *CardData;
+  UINT8                 TempData;
+  UINTN                 WriteProtectAddress;
+  UINTN                 WriteProtectSize;
+  UINTN                 WriteProtectGroupSize;
+  static BOOLEAN        WriteProtectDone = FALSE;
+  HECI_FWS_REGISTER     SecFwStatus;
+  SC_POLICY_HOB         *ScPolicy;
+  EFI_PEI_HOB_POINTERS  HobList;
+  SC_SCS_CONFIG         *ScsConfig;
+
+  DEBUG ((EFI_D_INFO, "eMMC Write Protection Config Checkpoint\n"));
+
+  CardData = (CARD_DATA *) Context;
+  //
+  // Enable the eMMC protection
+  //
+  if (FALSE) {
+    if (!WriteProtectDone) {
+      Status = MmcReadExtCsd (CardData);
+      if (EFI_ERROR (Status)) {
+        DEBUG ((EFI_D_INFO, "Read EXT_CSD failed\n"));
+      }
+      DEBUG ((EFI_D_INFO, "\nBOOT_WP 0x%02x", (UINT8) (CardData->ExtCSDRegister.BOOT_WP)));
+      DEBUG ((EFI_D_INFO, "\nBOOT_WP_STATUS 0x%02x", (UINT8) (CardData->ExtCSDRegister.BOOT_WP_STATUS)));
+      DEBUG ((EFI_D_INFO, "\nUSER_WP 0x%02x", (UINT8) (CardData->ExtCSDRegister.USER_WP)));
+      DEBUG ((EFI_D_INFO, "\nRST_n_FUNCTION 0x%02x\n", (UINT8) (CardData->ExtCSDRegister.RST_n_FUNCTION)));
+
+      if (BxtStepping() >= BxtPB0) { //For BXTP-B and above, BIOS to toggle rst_n_function from 2'b00 to 2'b01
+        if ((CardData->ExtCSDRegister.RST_n_FUNCTION & 0x3) != 1) {
+          Offset = OFFSET_OF (EXT_CSD, RST_n_FUNCTION);
+          Status = MmcSetExtCsd8 (CardData, (UINT8) Offset, 0x01);
+          if (Status) {
+            DEBUG ((EFI_D_INFO, "Setting RST_n_FUNCTION failed\n"));
+          }
+        }
+      }
+
+      // Protect and BP
+      // Update Power on write protection bit in USER_WP and BP_WP EXT_CSD registers
+      //
+      Offset = OFFSET_OF (EXT_CSD, ERASE_GROUP_DEF);
+      Status = MmcSetExtCsd8 (CardData, (UINT8) Offset, 0x01);
+      if (Status) {
+        DEBUG ((EFI_D_INFO, "Setting ERASE_GROUP_DEF failed\n"));
+      }
+
+      if (BxtStepping() != BxtPA0) { // program WP only if it's not Bxtp-A0
+        Offset = OFFSET_OF (EXT_CSD, BOOT_WP);
+        TempData = (CardData->ExtCSDRegister.BOOT_WP) | B_PWR_WP_EN | B_PERM_WP_DIS;
+        Status = MmcSetExtCsd8 (CardData, (UINT8) Offset, TempData);
+        if (Status) {
+          DEBUG ((EFI_D_INFO, "BP Write protect failed\n"));
+        }
+      }
+
+      HobList.Guid   = GetFirstGuidHob (&gScPolicyHobGuid);
+      ASSERT (HobList.Guid != NULL);
+      ScPolicy  = (SC_POLICY_HOB *) GET_GUID_HOB_DATA (HobList.Guid);
+      Status = GetConfigBlock ((VOID *) ScPolicy, &gScsConfigGuid, (VOID *) &ScsConfig);
+      ASSERT_EFI_ERROR (Status);
+
+      SecFwStatus.ul = HeciPciRead32 (R_SEC_FW_STS0);
+
+      if (SecFwStatus.r.ManufacturingMode == 0) {
+        DEBUG ((EFI_D_INFO, "SEC F/W is not in Manufacturing mode and is ready for production \n"));
+      } else if (SecFwStatus.r.SeCOperationMode != SEC_OPERATION_MODE_SECOVR_JMPR) {
+        DEBUG ((EFI_D_INFO, "Flash Descriptor Override HW strap not set\n"));
+      }
+
+      if (((SecFwStatus.r.ManufacturingMode == 0)                                  // if EOM is set
+          && (SecFwStatus.r.SeCOperationMode != SEC_OPERATION_MODE_SECOVR_JMPR))   // Flash Descriptor Override HW strap not set
+          || (ScsConfig->GppLock == 1)                                             // OR GPP Partition Lock Policy is set
+         ) {
+        //
+        // Protect GPP1
+        //
+        Status = MmcSelectPartitionNum (CardData, 4); // Switch to GPP1 before issuing CMD28
+        if (!EFI_ERROR(Status)) {
+           DEBUG ((EFI_D_INFO, "\nSwitch to GPP Partition Successful\n"));
+            WriteProtectSize = (((UINTN) (CardData->ExtCSDRegister.GP_SIZE_MULT_1[2] *( 0x1<<16)))
+                                      +((UINTN) (CardData->ExtCSDRegister.GP_SIZE_MULT_1[1] *( 0x1<<8)))
+                                      +((UINTN) (CardData->ExtCSDRegister.GP_SIZE_MULT_1[0])))
+                                      * ((UINTN) (CardData->ExtCSDRegister.HC_WP_GRP_SIZE))
+                                      * 512 *  1024 * ((UINTN) (CardData->ExtCSDRegister.HC_ERASE_GRP_SIZE));
+
+           DEBUG ((EFI_D_INFO, "WriteProtectSize = 0x%x\n", WriteProtectSize));
+
+           Offset = OFFSET_OF (EXT_CSD, USER_WP);
+           TempData = (CardData->ExtCSDRegister.USER_WP) | US_PWR_WP_EN | US_PERM_WP_DIS;
+           Status = MmcSetExtCsd8 (CardData, (UINT8) Offset, TempData);
+           if (Status) {
+             DEBUG ((EFI_D_INFO, "GPP Write protect failed\n"));
+           }
+           if (CardData->ExtCSDRegister.ERASE_GROUP_DEF) {
+             WriteProtectGroupSize = ((UINTN) (CardData->ExtCSDRegister.HC_WP_GRP_SIZE))
+                                        * 512 *  1024 * ((UINTN) (CardData->ExtCSDRegister.HC_ERASE_GRP_SIZE));
+           } else {
+             WriteProtectGroupSize = (CardData->CSDRegister.WP_GRP_SIZE + 1)
+                                        * ((UINTN) CardData->CSDRegister.ERASE_GRP_SIZE + 1)
+                                        * ((UINTN) CardData->CSDRegister.ERASE_GRP_MULT + 1)
+                                        * ((UINTN) (CardData->Partitions[4].BlockIoMedia.BlockSize));
+           }
+
+           DEBUG ((EFI_D_INFO, "WriteProtectGroupSize = 0x%x\n", WriteProtectGroupSize));
+
+           for (WriteProtectAddress = 0; WriteProtectAddress < WriteProtectSize; WriteProtectAddress+=WriteProtectGroupSize) {
+             //
+             // Send Write protect command
+             //
+             DEBUG ((EFI_D_INFO, "Send Write protect command Address = 0x%x\n", WriteProtectAddress));
+             Status = SendCommand (
+                        CardData->MmcHostIo,
+                        SET_WRITE_PROT,
+                        (UINT32) (WriteProtectAddress / 0x200),
+                         NoData,
+                         NULL,
+                         0,
+                         ResponseR1b,
+                         TIMEOUT_COMMAND,
+                         (UINT32 *) &(CardData->CardStatus)
+                         );
+
+             if (Status) {
+               DEBUG ((EFI_D_INFO, "GPP1 Write protect failed\n"));
+               break;
+             }
+        }
+
+      }
+
+   }
+ }
+
+   Status = MmcReadExtCsd (CardData);
+   if (EFI_ERROR (Status)) {
+     DEBUG ((EFI_D_INFO, "Read EXT_CSD failed\n"));
+   }
+
+    DEBUG ((EFI_D_INFO, "\nBOOT_WP 0x%02x", (UINT8) (CardData->ExtCSDRegister.BOOT_WP)));
+    DEBUG ((EFI_D_INFO, "\nBOOT_WP_STATUS 0x%02x", (UINT8) (CardData->ExtCSDRegister.BOOT_WP_STATUS)));
+    DEBUG ((EFI_D_INFO, "\nUSER_WP 0x%02x", (UINT8) (CardData->ExtCSDRegister.USER_WP)));
+    DEBUG ((EFI_D_INFO, "\nRST_n_FUNCTION 0x%02x\n", (UINT8) (CardData->ExtCSDRegister.RST_n_FUNCTION)));
+    WriteProtectDone = TRUE;
+  }
+}
+
+
+/**
+  MmcSelectPartitionNum
+
+  @param[in]  CardData                 Pointer to CARD_DATA
+  @param[in]  Partition
+
+  @retval     EFI_INVALID_PARAMETER
+  @retval     EFI_UNSUPPORTED
+  @retval     EFI_SUCCESS
+
+**/
+EFI_STATUS
+MmcSelectPartitionNum (
+  IN  CARD_DATA              *CardData,
+  IN  UINT8                  Partition
+  )
+{
+  EFI_STATUS  Status;
+  UINTN       Offset;
+  UINT8       *ExtByte;
+  UINTN       CurrentPartition;
+
+  if (Partition > 7) {
+    return EFI_INVALID_PARAMETER;
+  }
+
+  CurrentPartition = MmcGetCurrentPartitionNum (CardData);
+  if (Partition == CurrentPartition) {
+    return EFI_SUCCESS;
+  }
+  MmcMoveToTranState (CardData);
+  Status = MmcReadExtCsd (CardData);
+  if (EFI_ERROR (Status)) {
+    return Status;
+  }
+
+  DEBUG ((EFI_D_INFO,
+    "MmcSelectPartitionNum: Switch partition: %d => %d\n",
+    CurrentPartition,
+    Partition
+    ));
+
+  Offset = OFFSET_OF (EXT_CSD, PARTITION_CONFIG);
+  Status = MmcSetExtCsd8 (CardData, (UINT8) Offset, Partition);
+
+#if 1
+  Status = MmcReadExtCsd (CardData);
+  if (EFI_ERROR (Status)) {
+    return Status;
+  }
+
+  CurrentPartition = MmcGetCurrentPartitionNum (CardData);
+  if (Partition != CurrentPartition) {
+    DEBUG ((EFI_D_INFO, "MmcSelectPartitionNum: Switch partition failed!\n"));
+    return EFI_DEVICE_ERROR;
+  }
+
+  ExtByte = NULL;
+#else
+  if (!EFI_ERROR (Status)) {
+    ExtByte = ((UINT8 *) &CardData->ExtCSDRegister) + Offset;
+    *ExtByte = (UINT8) ((*ExtByte & 0xF7) | Partition);
+  }
+#endif
+  MmcMoveToTranState (CardData);
+
+  return Status;
+}
+
+
+/**
+  MmcSelectPartitionNum
+
+  @param[in]  Partition                  Pointer to MMC_PARTITION_DATA
+
+  @retval     EFI_INVALID_PARAMETER
+  @retval     EFI_UNSUPPORTED
+  @retval     EFI_SUCCESS
+
+**/
+EFI_STATUS
+MmcSelectPartition (
+  IN  MMC_PARTITION_DATA     *Partition
+  )
+{
+  return MmcSelectPartitionNum (
+           Partition->CardData,
+           (UINT8) CARD_DATA_PARTITION_NUM (Partition)
+           );
+}
+
+
+/**
+  MmcSetPartition
+
+  @param[in]  CardData                     Pointer to CARD_DATA
+  @param[in]  Value                        0: user partition; 1: boot partition 1; 2:boot partition 2
+
+  @retval     EFI_INVALID_PARAMETER
+  @retval     EFI_UNSUPPORTED
+  @retval     EFI_SUCCESS
+
+**/
+EFI_STATUS
+MmcSetPartition (
+  IN  CARD_DATA              *CardData,
+  IN  UINT8                  Value
+  )
+{
+  EFI_STATUS  Status;
+  UINTN       Offset;
+  UINT32      Data;
+
+  Offset = OFFSET_OF (EXT_CSD, PARTITION_CONFIG);
+  Data = MmcGetExtCsd8 (CardData, Offset);
+  Data &= 0xf8;
+  Data |= Value;
+  Status = MmcSetExtCsd8 (CardData, (UINT8) Offset, (UINT8) Data);
+
+  return Status;
+}
+
diff --git a/Silicon/BroxtonSoC/BroxtonSiPkg/SouthCluster/Sdio/Dxe/MMC/MmcMediaDeviceDxe/MediaDeviceDriver.c b/Silicon/BroxtonSoC/BroxtonSiPkg/SouthCluster/Sdio/Dxe/MMC/MmcMediaDeviceDxe/MediaDeviceDriver.c
new file mode 100644
index 0000000..7f5bd11
--- /dev/null
+++ b/Silicon/BroxtonSoC/BroxtonSiPkg/SouthCluster/Sdio/Dxe/MMC/MmcMediaDeviceDxe/MediaDeviceDriver.c
@@ -0,0 +1,605 @@
+/** @file
+  UEFI Driver Entry and Binding support.
+
+  Copyright (c) 1999 - 2017, Intel Corporation. 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 <MediaDeviceDriver.h>
+#include <Protocol/EmmcCardInfoProtocol.h>
+
+//
+// MMCSDIOController Driver Global Variables
+//
+EFI_DRIVER_BINDING_PROTOCOL gMediaDeviceDriverBinding = {
+  MediaDeviceDriverBindingSupported,
+  MediaDeviceDriverBindingStart,
+  MediaDeviceDriverBindingStop,
+  0x10,
+  NULL,
+  NULL
+};
+
+EFI_EMMC_CARD_INFO_PROTOCOL *gEfiEmmcCardInfo = NULL;
+
+/**
+  Entry point for EFI drivers.
+
+  @param[in]  ImageHandle          EFI_HANDLE
+  @param[in]  SystemTable          EFI_SYSTEM_TABLE
+
+  @retval     EFI_SUCCESS          Success
+  @retval     EFI_DEVICE_ERROR     Fail
+
+**/
+EFI_STATUS
+EFIAPI
+MediaDeviceDriverEntryPoint (
+  IN EFI_HANDLE           ImageHandle,
+  IN EFI_SYSTEM_TABLE     *SystemTable
+  )
+{
+  return EfiLibInstallAllDriverProtocols (
+           ImageHandle,
+           SystemTable,
+           &gMediaDeviceDriverBinding,
+           ImageHandle,
+           &gMediaDeviceComponentName,
+           NULL,
+           NULL
+           );
+}
+
+
+/**
+  Test to see if this driver supports ControllerHandle. Any ControllerHandle
+  that has installed will be supported.
+
+  @param[in]  This                  Protocol instance pointer.
+  @param[in]  Controlle             Handle of device to test
+  @param[in]  RemainingDevicePath   Not used
+
+  @retval     EFI_SUCCESS           This driver supports this device.
+  @retval     EFI_UNSUPPORTED       This driver does not support this device.
+
+**/
+EFI_STATUS
+EFIAPI
+MediaDeviceDriverBindingSupported (
+  IN EFI_DRIVER_BINDING_PROTOCOL *This,
+  IN EFI_HANDLE                  Controller,
+  IN EFI_DEVICE_PATH_PROTOCOL    *RemainingDevicePath
+  )
+{
+  EFI_STATUS                 Status;
+  EFI_MMC_HOST_IO_PROTOCOL   *MmcHostIo;
+
+  //
+  // Test whether there is MMCHostIO Protocol attached on the controller handle.
+  //
+  Status = gBS->OpenProtocol (
+                  Controller,
+                  &gEfiMmcHostIoProtocolGuid,
+                  (VOID **) &MmcHostIo,
+                  This->DriverBindingHandle,
+                  Controller,
+                  EFI_OPEN_PROTOCOL_BY_DRIVER
+                  );
+  if (EFI_ERROR (Status)) {
+    goto Exit;
+  }
+
+  gBS->CloseProtocol (
+         Controller,
+         &gEfiMmcHostIoProtocolGuid,
+         This->DriverBindingHandle,
+         Controller
+         );
+
+Exit:
+  return Status;
+}
+
+
+/**
+  Starting the Media Device Driver
+
+  @param[in]  This                    Protocol instance pointer.
+  @param[in]  Controller              Handle of device to test
+  @param[in]  RemainingDevicePath     Not used
+
+  @retval     EFI_SUCCESS             supports this device.
+  @retval     EFI_UNSUPPORTED         do not support this device.
+  @retval     EFI_DEVICE_ERROR        cannot be started due to device Error
+  @retval     EFI_OUT_OF_RESOURCES    cannot allocate resources
+
+**/
+EFI_STATUS
+EFIAPI
+MediaDeviceDriverBindingStart (
+  IN EFI_DRIVER_BINDING_PROTOCOL     *This,
+  IN EFI_HANDLE                      Controller,
+  IN EFI_DEVICE_PATH_PROTOCOL        *RemainingDevicePath
+  )
+{
+  EFI_STATUS                   Status;
+  EFI_MMC_HOST_IO_PROTOCOL     *MmcHostIo;
+  CARD_DATA                    *CardData;
+  UINTN                        Loop;
+  EFI_EMMC_CARD_INFO_PROTOCOL  *EfiEmmcCardInfoRegister;
+
+  DEBUG ((EFI_D_INFO, "%a(%d): %a()\n", __FILE__, __LINE__, __FUNCTION__));
+
+  EfiEmmcCardInfoRegister = NULL;
+  CardData = NULL;
+  MmcHostIo = NULL;
+
+  //
+  // Alloc memory for EfiEmmcCardInfoRegister variable
+  //
+  EfiEmmcCardInfoRegister = (EFI_EMMC_CARD_INFO_PROTOCOL *) AllocateZeroPool (sizeof (EFI_EMMC_CARD_INFO_PROTOCOL));
+  if (EfiEmmcCardInfoRegister == NULL) {
+    Status = EFI_OUT_OF_RESOURCES;
+    goto Exit;
+  }
+
+  //
+  // Open PCI I/O Protocol and save pointer to open protocol
+  // in private data area.
+  //
+  Status = gBS->OpenProtocol (
+                  Controller,
+                  &gEfiMmcHostIoProtocolGuid,
+                  (VOID **) &MmcHostIo,
+                  This->DriverBindingHandle,
+                  Controller,
+                  EFI_OPEN_PROTOCOL_BY_DRIVER
+                  );
+
+  if (EFI_ERROR (Status)) {
+    DEBUG ((EFI_D_ERROR, "MediaDeviceDriverBindingStart: Fail to open gEfiMmcHostIoProtocolGuid \n"));
+    goto Exit;
+  }
+
+  Status = MmcHostIo->DetectCardAndInitHost (MmcHostIo);
+  if (EFI_ERROR (Status)) {
+    DEBUG ((DEBUG_ERROR, "MediaDeviceDriverBindingStart: Fail to DetectCardAndInitHost %r\n", Status));
+    goto Exit;
+  }
+
+  CardData = (CARD_DATA *) AllocateZeroPool (sizeof (CARD_DATA));
+  if (CardData == NULL) {
+    Status =  EFI_OUT_OF_RESOURCES;
+    DEBUG ((EFI_D_ERROR, "MediaDeviceDriverBindingStart: Fail to AllocateZeroPool(CARD_DATA) \n"));
+    goto Exit;
+  }
+
+  ASSERT (MmcHostIo->HostCapability.BoundarySize >= 4 * 1024);
+
+  CardData->RawBufferPointer = (UINT8*) (UINTN) 0xffffffff;
+
+  DEBUG ((EFI_D_INFO, "CardData->RawBufferPointer = 0x%x \n",CardData->RawBufferPointer));
+  DEBUG ((EFI_D_INFO, "requesting 0x%x pages \n",EFI_SIZE_TO_PAGES(2 * MmcHostIo->HostCapability.BoundarySize)));
+
+  //
+  // Allocated the buffer under 4G
+  //
+  Status = gBS->AllocatePages (
+                  AllocateMaxAddress,
+                  EfiBootServicesData,
+                  EFI_SIZE_TO_PAGES (2 * MmcHostIo->HostCapability.BoundarySize),
+                  (EFI_PHYSICAL_ADDRESS *) (&(CardData->RawBufferPointer))
+                  );
+  DEBUG ((EFI_D_INFO, "CardData->RawBufferPointer = 0x%x \n",CardData->RawBufferPointer));
+  if (!EFI_ERROR (Status)) {
+    CardData->RawBufferPointer = ZeroMem (CardData->RawBufferPointer, EFI_SIZE_TO_PAGES (2 * MmcHostIo->HostCapability.BoundarySize));
+  } else {
+    DEBUG ((DEBUG_ERROR, "MediaDeviceDriverBindingStart: Fail to AllocateZeroPool(2*x) \n"));
+    Status =  EFI_OUT_OF_RESOURCES;
+    goto Exit;
+  }
+  CardData->AlignedBuffer = CardData->RawBufferPointer - ((UINTN) (CardData->RawBufferPointer) & (MmcHostIo->HostCapability.BoundarySize - 1)) + MmcHostIo->HostCapability.BoundarySize;
+
+  CardData->Signature = CARD_DATA_SIGNATURE;
+  CardData->MmcHostIo  = MmcHostIo;
+  CardData->Handle = Controller;
+  for (Loop = 0; Loop < MAX_NUMBER_OF_PARTITIONS; Loop++) {
+    CardData->Partitions[Loop].Signature = CARD_PARTITION_SIGNATURE;
+  }
+  Status = MMCSDCardInit (CardData);
+
+  if (EFI_ERROR (Status)) {
+    DEBUG ((EFI_D_ERROR, "MediaDeviceDriverBindingStart: Fail to MMCSDCardInit \n"));
+    goto Exit;
+  }
+
+  DEBUG ((DEBUG_INFO, "MediaDeviceDriverBindingStart: MMC SD card\n"));
+  Status = MMCSDBlockIoInit (CardData);
+
+  if (EFI_ERROR (Status)) {
+    DEBUG ((DEBUG_ERROR, "MediaDeviceDriverBindingStart: Card BlockIo init failed\n"));
+    goto Exit;
+  }
+
+
+  Status = MediaDeviceDriverInstallBlockIo (This, CardData);
+  if (EFI_ERROR (Status)) {
+    DEBUG ((DEBUG_ERROR, "MediaDeviceDriverBindingStart: Fail to install gEfiBlockIoProtocolGuid \n"));
+    goto Exit;
+  }
+
+  //
+  // Component name protocol
+  //
+  Status = AddUnicodeString (
+             "eng",
+             gMediaDeviceComponentName.SupportedLanguages,
+             &CardData->ControllerNameTable,
+             L"MMC/SD Media Device"
+             );
+  if (EFI_ERROR (Status)) {
+    Status = EFI_OUT_OF_RESOURCES;
+    for (Loop = 0; Loop < MAX_NUMBER_OF_PARTITIONS; Loop++) {
+      if (!CardData->Partitions[Loop].Present) {
+        continue;
+      }
+      gBS->UninstallMultipleProtocolInterfaces (
+             CardData->Partitions[Loop].Handle,
+             &gEfiBlockIoProtocolGuid,
+             &CardData->Partitions[Loop].BlockIo,
+             &gEfiDevicePathProtocolGuid,
+             CardData->Partitions[Loop].DevPath,
+             NULL
+             );
+    }
+    goto Exit;
+  }
+  if (EfiEmmcCardInfoRegister != NULL) {
+
+    //
+    // assign to protocol
+    //
+    EfiEmmcCardInfoRegister->CardData = CardData;
+
+    Status = gBS->InstallMultipleProtocolInterfaces (
+                    &Controller,
+                    &gEfiEmmcCardInfoProtocolGuid,
+                    EfiEmmcCardInfoRegister,
+                    NULL
+                    );
+    if (EFI_ERROR (Status)) {
+      DEBUG ((DEBUG_ERROR, "MediaDeviceDriverBindingStart: Install eMMC Card info protocol failed\n"));
+      for (Loop = 0; Loop < MAX_NUMBER_OF_PARTITIONS; Loop++) {
+        if (!CardData->Partitions[Loop].Present) {
+          continue;
+        }
+        gBS->UninstallMultipleProtocolInterfaces (
+               CardData->Partitions[Loop].Handle,
+               &gEfiBlockIoProtocolGuid,
+               &CardData->Partitions[Loop].BlockIo,
+               &gEfiDevicePathProtocolGuid,
+               CardData->Partitions[Loop].DevPath,
+               NULL
+               );
+      }
+
+      goto Exit;
+    }
+
+    gEfiEmmcCardInfo = EfiEmmcCardInfoRegister;
+  }
+
+  DEBUG ((DEBUG_INFO, "MediaDeviceDriverBindingStart: Started\n"));
+
+Exit:
+  if (EFI_ERROR (Status)) {
+    DEBUG ((EFI_D_ERROR, "MediaDeviceDriverBindingStart: End with failure\n"));
+    if (CardData != NULL && MmcHostIo != NULL) {
+      if (CardData->RawBufferPointer != NULL) {
+        gBS->FreePages ((EFI_PHYSICAL_ADDRESS) (UINTN) CardData->RawBufferPointer, EFI_SIZE_TO_PAGES (MmcHostIo->HostCapability.BoundarySize * 2));
+      }
+      FreePool (CardData);
+    }
+    gBS->CloseProtocol (
+           Controller,
+           &gEfiMmcHostIoProtocolGuid,
+           This->DriverBindingHandle,
+           Controller
+           );
+  }
+  return Status;
+}
+
+
+/**
+  Stop this driver on ControllerHandle. Support stoping any child handles
+  created by this driver.
+
+  @param[in]  This                   Protocol instance pointer.
+  @param[in]  Controller             Handle of device to stop driver on
+  @param[in]  NumberOfChildren       Number of Children in the ChildHandleBuffer
+  @param[in]  ChildHandleBuffer      List of handles for the children we need to stop.
+
+  @retval     EFI_SUCCESS            Success
+  @retval     EFI_DEVICE_ERROR       Fail
+
+**/
+EFI_STATUS
+EFIAPI
+MediaDeviceDriverBindingStop (
+  IN  EFI_DRIVER_BINDING_PROTOCOL     *This,
+  IN  EFI_HANDLE                      Controller,
+  IN  UINTN                           NumberOfChildren,
+  IN  EFI_HANDLE                      *ChildHandleBuffer
+  )
+{
+  EFI_STATUS                Status;
+  CARD_DATA                 *CardData;
+  BOOLEAN                   AllChildrenStopped;
+  UINTN                     Index;
+  UINTN                     Pages = 0;
+
+  Status = EFI_SUCCESS;
+  CardData = gEfiEmmcCardInfo->CardData;
+
+  if (NumberOfChildren == 0) {
+    Status = gBS->UninstallMultipleProtocolInterfaces (
+                    Controller,
+                    &gEfiEmmcCardInfoProtocolGuid,
+                    gEfiEmmcCardInfo,
+                    NULL
+                    );
+    if (EFI_ERROR (Status)) {
+      DEBUG ((EFI_D_ERROR, "MediaDeviceDriverBindingStop: UNINSTALL gEfiEmmcCardInfoProtocolGuid FAILURE\n"));
+      return Status;
+    }
+
+    FreeUnicodeStringTable (CardData->ControllerNameTable);
+
+    Pages = (2 * (CardData->MmcHostIo->HostCapability.BoundarySize));
+    if (CardData->RawBufferPointer != NULL) {
+      FreePages (CardData->RawBufferPointer, EFI_SIZE_TO_PAGES(Pages));
+    }
+
+    Status = gBS->CloseProtocol (
+         Controller,
+         &gEfiMmcHostIoProtocolGuid,
+         This->DriverBindingHandle,
+         Controller
+         );
+
+    if (MediaDeviceDriverAllPartitionNotPresent(CardData)) {
+      FreePool (CardData);
+      FreePool (gEfiEmmcCardInfo);
+      gEfiEmmcCardInfo = NULL;
+    }
+
+    return Status;
+  }
+
+  AllChildrenStopped = TRUE;
+  for (Index = 0; Index < NumberOfChildren; Index++) {
+    Status = MediaDeviceDriverUninstallBlockIo(This, CardData, ChildHandleBuffer[Index]);
+    if (EFI_ERROR (Status)) {
+      DEBUG ((EFI_D_ERROR, "MediaDeviceDriverBindingStop: UNINSTALL block io FAILURE\n"));
+      AllChildrenStopped = FALSE;
+      break;
+    }
+  }
+
+  return Status;
+}
+
+
+BOOLEAN
+MediaDeviceDriverAllPartitionNotPresent (
+  IN  CARD_DATA    *CardData
+  )
+{
+  BOOLEAN             AllPartitionNotPresent;
+  UINTN               Loop;
+  MMC_PARTITION_DATA  *Partition;
+
+  Partition = CardData->Partitions;
+
+  AllPartitionNotPresent = TRUE;
+
+  for (Loop = 0; Loop < MAX_NUMBER_OF_PARTITIONS; Partition++, Loop++) {
+    if (Partition->Present) {
+      AllPartitionNotPresent = FALSE;
+      break;
+    }
+  }
+
+  return AllPartitionNotPresent;
+}
+
+
+STATIC
+struct {
+  DEVICE_LOGICAL_UNIT_DEVICE_PATH  LogicalUnit;
+  EFI_DEVICE_PATH_PROTOCOL  End;
+} EmmcDevPathTemplate = {
+  {
+    {
+      MESSAGING_DEVICE_PATH,
+      MSG_DEVICE_LOGICAL_UNIT_DP,
+      {
+        sizeof (DEVICE_LOGICAL_UNIT_DEVICE_PATH),
+        0
+      },
+    },
+    0
+  },
+  {
+    END_DEVICE_PATH_TYPE,
+    END_ENTIRE_DEVICE_PATH_SUBTYPE,
+    {
+      END_DEVICE_PATH_LENGTH,
+      0
+    }
+  }
+};
+
+
+/**
+  MediaDeviceDriverInstallBlockIo
+
+  @param[in]  This                    Pointer to the EFI_DRIVER_BINDING_PROTOCOL.
+  @param[in]  CardData                Pointer to CARD_DATA
+
+  @retval     EFI_INVALID_PARAMETER
+  @retval     EFI_UNSUPPORTED
+  @retval     EFI_SUCCESS
+
+**/
+EFI_STATUS
+MediaDeviceDriverInstallBlockIo (
+  IN  EFI_DRIVER_BINDING_PROTOCOL     *This,
+  IN  CARD_DATA                       *CardData
+  )
+{
+  EFI_STATUS                Status;
+  UINT8                     Loop;
+  MMC_PARTITION_DATA        *Partition;
+  EFI_DEVICE_PATH_PROTOCOL  *MainPath;
+  EFI_MMC_HOST_IO_PROTOCOL  *MmcHostIo = NULL;
+
+  Partition = CardData->Partitions;
+
+  Status = gBS->HandleProtocol (
+                  CardData->Handle,
+                  &gEfiDevicePathProtocolGuid,
+                  (VOID **) &MainPath
+                  );
+  if (EFI_ERROR (Status)) {
+    return Status;
+  }
+
+  for (Loop = 0; Loop < MAX_NUMBER_OF_PARTITIONS; Partition++, Loop++) {
+    if (!Partition->Present) {
+      continue;
+    }
+
+    DEBUG ((EFI_D_INFO, "MediaDeviceDriverInstallBlockIo: Installing Block I/O for partition %d\n", Loop));
+
+    Partition->Handle = NULL;
+    Partition->CardData = CardData;
+
+    EmmcDevPathTemplate.LogicalUnit.Lun = Loop;
+    Partition->DevPath =
+      AppendDevicePath (
+        MainPath,
+        (EFI_DEVICE_PATH_PROTOCOL *) &EmmcDevPathTemplate
+        );
+    if (Partition->DevPath == NULL) {
+      Status = EFI_OUT_OF_RESOURCES;
+      break;
+    }
+
+    Status = gBS->InstallProtocolInterface (
+                    &(Partition->Handle),
+                    &gEfiDevicePathProtocolGuid,
+                    EFI_NATIVE_INTERFACE,
+                    Partition->DevPath
+                    );
+    if (EFI_ERROR (Status)) {
+      break;
+    }
+
+    Status = gBS->InstallProtocolInterface (
+                    &(Partition->Handle),
+                    &gEfiBlockIoProtocolGuid,
+                    EFI_NATIVE_INTERFACE,
+                    &Partition->BlockIo
+                    );
+
+    //
+    // Open parent controller by child
+    //
+    Status = gBS->OpenProtocol (
+                    CardData->Handle,
+                    &gEfiMmcHostIoProtocolGuid,
+                    (VOID **) &MmcHostIo,
+                    This->DriverBindingHandle,
+                    Partition->Handle,
+                    EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER
+                    );
+  }
+
+  return Status;
+}
+
+
+/**
+  MediaDeviceDriverUninstallBlockIo
+
+  @param[in]  This                     Pointer to the EFI_DRIVER_BINDING_PROTOCOL.
+  @param[in]  CardData                 Pointer to CARD_DATA
+  @param[in]  Handle                   Handle of Partition
+
+  @retval     EFI_INVALID_PARAMETER
+  @retval     EFI_UNSUPPORTED
+  @retval     EFI_SUCCESS
+
+**/
+EFI_STATUS
+MediaDeviceDriverUninstallBlockIo (
+  IN  EFI_DRIVER_BINDING_PROTOCOL  *This,
+  IN  CARD_DATA                    *CardData,
+  IN  EFI_HANDLE                   Handle
+  )
+{
+  EFI_STATUS          Status;
+  UINTN               Loop;
+  MMC_PARTITION_DATA  *Partition;
+
+  Partition = CardData->Partitions;
+  Status = EFI_SUCCESS;
+
+  for (Loop = 0; Loop < MAX_NUMBER_OF_PARTITIONS; Partition++, Loop++) {
+    if (!Partition->Present || Partition->Handle != Handle) {
+     continue;
+    }
+
+    //
+    // Close MmcHostIoProtocol by child
+    //
+    Status = gBS->CloseProtocol (
+                    CardData->Handle,
+                    &gEfiMmcHostIoProtocolGuid,
+                    This->DriverBindingHandle,
+                    Partition->Handle
+                    );
+    if (EFI_ERROR (Status)) {
+      DEBUG ((EFI_D_ERROR, "CloseProtocol gEfiMmcHostIoProtocolGuid FAILURE \n"));
+      return Status;
+    }
+
+    Status = gBS->UninstallMultipleProtocolInterfaces (
+                    Partition->Handle,
+                    &gEfiBlockIoProtocolGuid,
+                    &Partition->BlockIo,
+                    &gEfiDevicePathProtocolGuid,
+                    Partition->DevPath,
+                    NULL
+                    );
+    Partition->Present = FALSE;
+    DEBUG ((EFI_D_ERROR, "MediaDeviceDriverBindingStop gEfiBlockIoProtocolGuid removed.  %x\n", Status));
+    if (EFI_ERROR (Status)) {
+      DEBUG ((EFI_D_ERROR, "MediaDeviceDriverUninstallBlockIo UNISTALL FAILURE \n"));
+    }
+    return Status;
+  }
+
+  return EFI_INVALID_PARAMETER;
+}
+
diff --git a/Silicon/BroxtonSoC/BroxtonSiPkg/SouthCluster/Sdio/Dxe/MMC/MmcMediaDeviceDxe/MmcMediaDeviceDxe.inf b/Silicon/BroxtonSoC/BroxtonSiPkg/SouthCluster/Sdio/Dxe/MMC/MmcMediaDeviceDxe/MmcMediaDeviceDxe.inf
new file mode 100644
index 0000000..500d1de
--- /dev/null
+++ b/Silicon/BroxtonSoC/BroxtonSiPkg/SouthCluster/Sdio/Dxe/MMC/MmcMediaDeviceDxe/MmcMediaDeviceDxe.inf
@@ -0,0 +1,71 @@
+## @file
+#  SD Host module
+#
+#  Copyright (c) 1999 - 2016, Intel Corporation. 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                    = 0x00010005
+  BASE_NAME                      = MmcMediaDevice
+  FILE_GUID                      = 1CFD8F87-355A-4954-859F-DDC5D8876D44
+  MODULE_TYPE                    = UEFI_DRIVER
+  VERSION_STRING                 = 1.0
+  ENTRY_POINT                    = MediaDeviceDriverEntryPoint
+
+#
+# The following information is for reference only and not required by the build tools.
+#
+#  VALID_ARCHITECTURES           = IA32 X64 IPF EBC
+#
+
+[Sources.common]
+  ComponentName.c
+  MediaDeviceDriver.c
+  MMCSDBlockIo.c
+  MMCSDTransfer.c
+
+[Packages]
+  MdePkg/MdePkg.dec
+  BroxtonSiPkg/BroxtonSiPkg.dec
+  BroxtonSiPkg/BroxtonSiPrivate.dec
+
+[LibraryClasses]
+  UefiDriverEntryPoint
+  DebugLib
+  UefiBootServicesTableLib
+  BaseMemoryLib
+  MemoryAllocationLib
+  UefiLib
+  DevicePathLib
+  IoLib
+  PcdLib
+  HobLib
+  PciLib
+  SteppingLib
+  ConfigBlockLib
+
+[Guids]
+  gEfiEventReadyToBootGuid ## UNDEFINED
+  gScPolicyHobGuid
+  gEfiUnbootablePartitionGuid       ## PRODUCE ## GUID
+  gScsConfigGuid
+
+[Protocols]
+  gEfiDevicePathProtocolGuid        ## BY_START
+  gEfiMmcHostIoProtocolGuid         ## CONSUMES
+  gEfiBlockIoProtocolGuid           ## BY_START
+  gEfiEmmcCardInfoProtocolGuid      ## BY_START
+  gEfiEmmcBootPartitionProtocolGuid ## BY_START
+
+[Pcd]
+  gEfiBxtTokenSpaceGuid.PcdEmmcManufacturerId   ## PRODUCES
+  gEfiBxtTokenSpaceGuid.PcdProductSerialNumber  ## PRODUCES
diff --git a/Silicon/BroxtonSoC/BroxtonSiPkg/SouthCluster/Sdio/Dxe/SD/SdControllerDxe/ComponentName.c b/Silicon/BroxtonSoC/BroxtonSiPkg/SouthCluster/Sdio/Dxe/SD/SdControllerDxe/ComponentName.c
new file mode 100644
index 0000000..0bc9861
--- /dev/null
+++ b/Silicon/BroxtonSoC/BroxtonSiPkg/SouthCluster/Sdio/Dxe/SD/SdControllerDxe/ComponentName.c
@@ -0,0 +1,233 @@
+/** @file
+  UEFI Component Name(2) protocol implementation for SD controller driver.
+
+  Copyright (c) 2013 - 2016, Intel Corporation. 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 "SdController.h"
+
+//
+// EFI Component Name Protocol
+//
+GLOBAL_REMOVE_IF_UNREFERENCED EFI_COMPONENT_NAME_PROTOCOL  gSdControllerName = {
+  SdControllerGetDriverName,
+  SdControllerGetControllerName,
+  "eng"
+};
+
+
+//
+// EFI Component Name 2 Protocol
+//
+GLOBAL_REMOVE_IF_UNREFERENCED EFI_COMPONENT_NAME2_PROTOCOL gSdControllerName2 = {
+  (EFI_COMPONENT_NAME2_GET_DRIVER_NAME) SdControllerGetDriverName,
+  (EFI_COMPONENT_NAME2_GET_CONTROLLER_NAME) SdControllerGetControllerName,
+  "en"
+};
+
+
+GLOBAL_REMOVE_IF_UNREFERENCED EFI_UNICODE_STRING_TABLE mSdControllerDriverNameTable[] = {
+  { "eng;en", L"EFI SD Host Controller Driver" },
+  { NULL, NULL }
+};
+
+
+//
+// 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[in]     This                 A pointer to the EFI_COMPONENT_NAME2_PROTOCOL or
+                                      EFI_COMPONENT_NAME_PROTOCOL instance.
+
+  @param[in]    Language              A pointer to a Null-terminated ASCII string
+                                      array indicating the language. This is the
+                                      language of the driver name that the caller is
+                                      requesting, and it must match one of the
+                                      languages specified in SupportedLanguages. The
+                                      number of languages supported by a driver is up
+                                      to the driver writer. Language is specified
+                                      in RFC 3066 or ISO 639-2 language code format.
+
+  @param[out]   DriverName            A pointer to the Unicode string to return.
+                                      This Unicode string is the name of the
+                                      driver specified by This in the language
+                                      specified by Language.
+
+  @retval       EFI_SUCCESS           The Unicode string for the Driver specified by
+                                      This and the language specified by Language was
+                                      returned in DriverName.
+
+  @retval       EFI_INVALID_PARAMETER Language is NULL.
+
+  @retval       EFI_INVALID_PARAMETER DriverName is NULL.
+
+  @retval       EFI_UNSUPPORTED       The driver specified by This does not support
+                                      the language specified by Language.
+
+**/
+EFI_STATUS
+EFIAPI
+SdControllerGetDriverName (
+  IN  EFI_COMPONENT_NAME_PROTOCOL  *This,
+  IN  CHAR8                        *Language,
+  OUT CHAR16                       **DriverName
+  )
+{
+  return LookupUnicodeString2 (
+           Language,
+           This->SupportedLanguages,
+           mSdControllerDriverNameTable,
+           DriverName,
+           (BOOLEAN)(This == &gSdControllerName)
+           );
+}
+
+
+/**
+  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[in]  This                  A pointer to the EFI_COMPONENT_NAME2_PROTOCOL or
+                                    EFI_COMPONENT_NAME_PROTOCOL instance.
+
+  @param[in]  ControllerHandle      The handle of a controller that the driver
+                                    specified by This is managing.  This handle
+                                    specifies the controller whose name is to be
+                                    returned.
+
+  @param[in]  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[in]  Language              A pointer to a Null-terminated ASCII string
+                                    array indicating the language.  This is the
+                                    language of the driver name that the caller is
+                                    requesting, and it must match one of the
+                                    languages specified in SupportedLanguages. The
+                                    number of languages supported by a driver is up
+                                    to the driver writer. Language is specified in
+                                    RFC 3066 or ISO 639-2 language code format.
+
+  @param[out] ControllerName        A pointer to the Unicode string to return.
+                                    This Unicode string is the name of the
+                                    controller specified by ControllerHandle and
+                                    ChildHandle in the language specified by
+                                    Language from the point of view of the driver
+                                    specified by This.
+
+  @retval     EFI_SUCCESS           The Unicode string for the user readable name in
+                                    the language specified by Language for the
+                                    driver specified by This was returned in
+                                    DriverName.
+
+  @retval     EFI_INVALID_PARAMETER ControllerHandle is not a valid EFI_HANDLE.
+
+  @retval     EFI_INVALID_PARAMETER ChildHandle is not NULL and it is not a valid
+                                    EFI_HANDLE.
+
+  @retval     EFI_INVALID_PARAMETER Language is NULL.
+
+  @retval     EFI_INVALID_PARAMETER ControllerName is NULL.
+
+  @retval     EFI_UNSUPPORTED       The driver specified by This is not currently
+                                    managing the controller specified by
+                                    ControllerHandle and ChildHandle.
+
+  @retval     EFI_UNSUPPORTED       The driver specified by This does not support
+                                    the language specified by Language.
+
+**/
+EFI_STATUS
+EFIAPI
+SdControllerGetControllerName (
+  IN  EFI_COMPONENT_NAME_PROTOCOL                     *This,
+  IN  EFI_HANDLE                                      ControllerHandle,
+  IN  EFI_HANDLE                                      ChildHandle        OPTIONAL,
+  IN  CHAR8                                           *Language,
+  OUT CHAR16                                          **ControllerName
+  )
+{
+  EFI_STATUS               Status;
+  EFI_SD_HOST_IO_PROTOCOL  *SdHostIo;
+  SDHOST_DATA              *SdHostData;
+
+  //
+  // 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,
+             gSdControllerDriverBinding.DriverBindingHandle,
+             &gEfiPciIoProtocolGuid
+             );
+
+  if (EFI_ERROR (Status)) {
+    return Status;
+  }
+
+  //
+  // Get the device context
+  //
+  Status = gBS->OpenProtocol (
+                  ControllerHandle,
+                  &gEfiSdHostIoProtocolGuid,
+                  (VOID **) &SdHostIo,
+                  gSdControllerDriverBinding.DriverBindingHandle,
+                  ControllerHandle,
+                  EFI_OPEN_PROTOCOL_GET_PROTOCOL
+                  );
+
+  if (EFI_ERROR (Status)) {
+    return Status;
+  }
+
+  SdHostData = SDHOST_DATA_FROM_THIS (SdHostIo);
+
+  return LookupUnicodeString2 (
+           Language,
+           This->SupportedLanguages,
+           SdHostData->ControllerNameTable,
+           ControllerName,
+           (BOOLEAN)(This == &gSdControllerName)
+           );
+
+}
+
diff --git a/Silicon/BroxtonSoC/BroxtonSiPkg/SouthCluster/Sdio/Dxe/SD/SdControllerDxe/ComponentName.h b/Silicon/BroxtonSoC/BroxtonSiPkg/SouthCluster/Sdio/Dxe/SD/SdControllerDxe/ComponentName.h
new file mode 100644
index 0000000..89d8a27
--- /dev/null
+++ b/Silicon/BroxtonSoC/BroxtonSiPkg/SouthCluster/Sdio/Dxe/SD/SdControllerDxe/ComponentName.h
@@ -0,0 +1,145 @@
+/** @file
+  This file contains the declarations for component name routines.
+
+  Copyright (c) 2013 - 2016, Intel Corporation. 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 _COMPONENT_NAME_H_
+#define _COMPONENT_NAME_H_
+
+/**
+  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[in]  This                  A pointer to the EFI_COMPONENT_NAME2_PROTOCOL or
+                                    EFI_COMPONENT_NAME_PROTOCOL instance.
+
+  @param[in]  Language              A pointer to a Null-terminated ASCII string
+                                    array indicating the language. This is the
+                                    language of the driver name that the caller is
+                                    requesting, and it must match one of the
+                                    languages specified in SupportedLanguages. The
+                                    number of languages supported by a driver is up
+                                    to the driver writer. Language is specified
+                                    in RFC 3066 or ISO 639-2 language code format.
+
+  @param[out] DriverName            A pointer to the Unicode string to return.
+                                    This Unicode string is the name of the
+                                    driver specified by This in the language
+                                    specified by Language.
+
+  @retval     EFI_SUCCESS           The Unicode string for the Driver specified by
+                                    This and the language specified by Language was
+                                    returned in DriverName.
+
+  @retval     EFI_INVALID_PARAMETER Language is NULL.
+
+  @retval     EFI_INVALID_PARAMETER DriverName is NULL.
+
+  @retval     EFI_UNSUPPORTED       The driver specified by This does not support
+                                    the language specified by Language.
+
+**/
+EFI_STATUS
+EFIAPI
+SdControllerGetDriverName (
+  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[in]   This                    A pointer to the EFI_COMPONENT_NAME2_PROTOCOL or
+                                       EFI_COMPONENT_NAME_PROTOCOL instance.
+
+  @param[in]   ControllerHandle        The handle of a controller that the driver
+                                       specified by This is managing.  This handle
+                                       specifies the controller whose name is to be
+                                       returned.
+
+  @param[in]   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[in]   Language                A pointer to a Null-terminated ASCII string
+                                       array indicating the language.  This is the
+                                       language of the driver name that the caller is
+                                       requesting, and it must match one of the
+                                       languages specified in SupportedLanguages. The
+                                       number of languages supported by a driver is up
+                                       to the driver writer. Language is specified in
+                                       RFC 3066 or ISO 639-2 language code format.
+
+  @param[out]  ControllerName          A pointer to the Unicode string to return.
+                                       This Unicode string is the name of the
+                                       controller specified by ControllerHandle and
+                                       ChildHandle in the language specified by
+                                       Language from the point of view of the driver
+                                       specified by This.
+
+  @retval      EFI_SUCCESS             The Unicode string for the user readable name in
+                                       the language specified by Language for the
+                                       driver specified by This was returned in
+                                       DriverName.
+
+  @retval      EFI_INVALID_PARAMETER   ControllerHandle is not a valid EFI_HANDLE.
+
+  @retval      EFI_INVALID_PARAMETER   ChildHandle is not NULL and it is not a valid
+                                       EFI_HANDLE.
+
+  @retval      EFI_INVALID_PARAMETER   Language is NULL.
+
+  @retval      EFI_INVALID_PARAMETER   ControllerName is NULL.
+
+  @retval      EFI_UNSUPPORTED         The driver specified by This is not currently
+                                       managing the controller specified by
+                                       ControllerHandle and ChildHandle.
+
+  @retval     EFI_UNSUPPORTED          The driver specified by This does not support
+                                       the language specified by Language.
+
+**/
+EFI_STATUS
+EFIAPI
+SdControllerGetControllerName (
+  IN  EFI_COMPONENT_NAME_PROTOCOL       *This,
+  IN  EFI_HANDLE                        ControllerHandle,
+  IN  EFI_HANDLE                        ChildHandle        OPTIONAL,
+  IN  CHAR8                             *Language,
+  OUT CHAR16                            **ControllerName
+  );
+
+#endif
+
diff --git a/Silicon/BroxtonSoC/BroxtonSiPkg/SouthCluster/Sdio/Dxe/SD/SdControllerDxe/SdController.c b/Silicon/BroxtonSoC/BroxtonSiPkg/SouthCluster/Sdio/Dxe/SD/SdControllerDxe/SdController.c
new file mode 100644
index 0000000..f481196
--- /dev/null
+++ b/Silicon/BroxtonSoC/BroxtonSiPkg/SouthCluster/Sdio/Dxe/SD/SdControllerDxe/SdController.c
@@ -0,0 +1,1804 @@
+/** @file
+  The SD host controller driver model and HC protocol routines.
+
+  Copyright (c) 2013 - 2017, Intel Corporation. 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 "SdController.h"
+
+EFI_DRIVER_BINDING_PROTOCOL gSdControllerDriverBinding = {
+  SdControllerSupported,
+  SdControllerStart,
+  SdControllerStop,
+  0x20,
+  NULL,
+  NULL
+};
+
+
+EFI_SD_HOST_IO_PROTOCOL  mSdHostIo = {
+  EFI_SD_HOST_IO_PROTOCOL_REVISION_01,
+  {
+    0,           // HighSpeedSupport
+    0,           // V18Support
+    0,           // V30Support
+    0,           // V33Support
+    0,           // Reserved0
+    0,           // BusWidth4
+    0,           // BusWidth8
+    0,           // Reserved1
+    0,           // Reserved1
+    (512 * 1024) // BoundarySize
+  },
+
+  SendCommand,
+  SetClockFrequency,
+  SetBusWidth,
+  SetHostVoltage,
+  ResetSdHost,
+  EnableAutoStopCmd,
+  DetectCardAndInitHost,
+  SetBlockLength,
+  SetHighSpeedMode,
+  SetDDRMode
+};
+
+
+/**
+  Find sdclk_freq_sel and upr_sdclk_freq_sel bits
+  for Clock Control Register (CLK_CTL)Offset 2Ch when using 8bit or 10bit
+  divided clock mode.
+
+  @param[in]   BaseClockFreg        Base Clock Frequency in Hz For SD Clock in the
+                                    Capabilities register.
+  @param[in]   TargetFreq           Target Frequency in Hz to reach.
+  @param[in]   Is8BitMode           True if 8-bit Divided Clock Mode else 10bit mode.
+  @param[out]  Bits                 sdclk_freq_sel and upr_sdclk_freq_sel bits for
+                                    TargetFreq.
+
+  @retval      EFI_SUCCESS          Bits setup.
+  @retval      EFI_UNSUPPORTED      Cannot divide base clock to reach target clock.
+
+**/
+EFI_STATUS
+DividedClockModeBits (
+  IN    CONST UINTN            BaseClockFreg,
+  IN    CONST UINTN            TargetFreq,
+  IN    CONST BOOLEAN          Is8BitMode,
+  OUT   UINT16                 *Bits
+  )
+{
+  UINTN  N;
+  UINTN  CurrFreq;
+
+  *Bits = 0;
+  CurrFreq = BaseClockFreg;
+  N = 0;
+  //
+  // N == 0 same for 8bit & 10bit mode i.e. BaseClockFreg of controller.
+  //
+  if (TargetFreq < CurrFreq) {
+    if (Is8BitMode) {
+      N = 1;
+      do {
+        //
+        // N values for 8bit mode when N > 0.
+        //  Bit[15:8] SDCLK Frequency Select at offset 2Ch
+        //    80h - base clock divided by 256
+        //    40h - base clock divided by 128
+        //    20h - base clock divided by 64
+        //    10h - base clock divided by 32
+        //    08h - base clock divided by 16
+        //    04h - base clock divided by 8
+        //    02h - base clock divided by 4
+        //    01h - base clock divided by 2
+        //
+        CurrFreq = BaseClockFreg / (2 * N);
+        if (TargetFreq >= CurrFreq) {
+          break;
+        }
+        N *= 2;
+        if (N > V_MMIO_CLKCTL_MAX_8BIT_FREQ_SEL) {
+          return EFI_UNSUPPORTED;
+        }
+      } while (TRUE);
+    } else {
+      N = 1;
+      CurrFreq = BaseClockFreg / (2 * N);
+      //
+      // (try N = 0 or 1 first since don't want divide by 0).
+      //
+      if (TargetFreq < CurrFreq) {
+        //
+        // If still no match then calculate it for 10bit.
+        // N values for 10bit mode.
+        // N 1/2N Divided Clock (Duty 50%).
+        // from Spec "The length of divider is extended to 10 bits and all
+        // divider values shall be supported.
+        //
+        N = (BaseClockFreg / TargetFreq) / 2;
+
+        //
+        // Can only be N or N+1;
+        //
+        CurrFreq = BaseClockFreg / (2 * N);
+        if (TargetFreq < CurrFreq) {
+          N++;
+          CurrFreq = BaseClockFreg / (2 * N);
+        }
+
+        if (N > V_MMIO_CLKCTL_MAX_10BIT_FREQ_SEL) {
+          return EFI_UNSUPPORTED;
+        }
+
+        //
+        // Set upper bits of SDCLK Frequency Select (bits 7:6 of reg 0x2c).
+        //
+        *Bits |= ((UINT16) ((N >> 2) & B_MMIO_CLKCTL_UPR_SDCLK_FREQ_SEL_MASK));
+      }
+    }
+  }
+
+  //
+  // Set lower bits of SDCLK Frequency Select (bits 15:8 of reg 0x2c).
+  //
+  *Bits |= ((UINT16) ((UINT8) N) << 8);
+  DEBUG (
+    (EFI_D_INFO,
+    "SDIO:DividedClockModeBits: %dbit mode Want %dHz Got %dHz bits = %04x\r\n",
+    (Is8BitMode) ? 8 : 10,
+    TargetFreq,
+    CurrFreq,
+    (UINTN) *Bits
+    ));
+
+  return EFI_SUCCESS;
+}
+
+
+/**
+  Print type of error and command index
+
+  @param[in]  CommandIndex         Command index to set the command index field of command register.
+  @param[in]  ErrorCode            Error interrupt status read from host controller
+
+  @retval     EFI_DEVICE_ERROR
+  @retval     EFI_TIMEOUT
+  @retval     EFI_CRC_ERROR
+
+**/
+EFI_STATUS
+GetErrorReason (
+  IN  UINT16    CommandIndex,
+  IN  UINT16    ErrorCode
+  )
+{
+  EFI_STATUS    Status;
+
+  Status = EFI_DEVICE_ERROR;
+
+  DEBUG ((EFI_D_ERROR, "[%2d] -- ", CommandIndex));
+
+  if (ErrorCode & BIT0) {
+    Status = EFI_TIMEOUT;
+    DEBUG ((EFI_D_ERROR, "Command Timeout Erro"));
+  }
+
+  if (ErrorCode & BIT1) {
+    Status = EFI_CRC_ERROR;
+    DEBUG ((EFI_D_ERROR, "Command CRC Error"));
+  }
+
+  if (ErrorCode & BIT2) {
+    DEBUG ((EFI_D_ERROR, "Command End Bit Error"));
+  }
+
+  if (ErrorCode & BIT3) {
+    DEBUG ((EFI_D_ERROR, "Command Index Error"));
+  }
+  if (ErrorCode & BIT4) {
+    Status = EFI_TIMEOUT;
+    DEBUG ((EFI_D_ERROR, "Data Timeout Error"));
+  }
+
+  if (ErrorCode & BIT5) {
+    Status = EFI_CRC_ERROR;
+    DEBUG ((EFI_D_ERROR, "Data CRC Error"));
+  }
+
+  if (ErrorCode & BIT6) {
+    DEBUG ((EFI_D_ERROR, "Data End Bit Error"));
+  }
+
+  if (ErrorCode & BIT7) {
+    DEBUG ((EFI_D_ERROR, "Current Limit Error"));
+  }
+
+  if (ErrorCode & BIT8) {
+    DEBUG ((EFI_D_ERROR, "Auto CMD12 Error"));
+  }
+
+  if (ErrorCode & BIT9) {
+    DEBUG ((EFI_D_ERROR, "ADMA Error"));
+  }
+
+  DEBUG ((EFI_D_ERROR, "\n"));
+
+  return Status;
+}
+
+
+/**
+  Enable/Disable High Speed transfer mode
+
+  @param[in]   This                  A pointer to the EFI_SD_HOST_IO_PROTOCOL instance.
+  @param[in]   Enable                TRUE to Enable, FALSE to Disable
+
+  @retval      EFI_SUCCESS
+
+**/
+EFI_STATUS
+EFIAPI
+SetHighSpeedMode (
+  IN  EFI_SD_HOST_IO_PROTOCOL    *This,
+  IN  BOOLEAN                    Enable
+  )
+{
+  UINT32                 Data;
+  SDHOST_DATA            *SdHostData;
+  EFI_PCI_IO_PROTOCOL    *PciIo;
+
+  SdHostData = SDHOST_DATA_FROM_THIS (This);
+  PciIo      = SdHostData->PciIo;
+
+  PciIo->Mem.Read (
+               PciIo,
+               EfiPciIoWidthUint8,
+               0,
+               (UINT64) MMIO_HOSTCTL,
+               1,
+               &Data
+               );
+
+  if (Enable) {
+    DEBUG ((EFI_D_INFO, "Enable High Speed transfer mode ... \r\n"));
+    Data |= BIT2;
+  } else {
+    Data &= ~BIT2;
+  }
+  PciIo->Mem.Write (
+               PciIo,
+               EfiPciIoWidthUint8,
+               0,
+               (UINT64) MMIO_HOSTCTL,
+               1,
+               &Data
+               );
+
+  return EFI_SUCCESS;
+}
+EFI_STATUS
+EFIAPI
+SetDDRMode (
+  IN  EFI_SD_HOST_IO_PROTOCOL    *This,
+  IN  BOOLEAN                    Enable
+  )
+{
+  UINT16                 Data;
+  SDHOST_DATA            *SdHostData;
+  EFI_PCI_IO_PROTOCOL    *PciIo;
+
+  SdHostData = SDHOST_DATA_FROM_THIS (This);
+  PciIo = SdHostData->PciIo;
+  PciIo->Mem.Read (
+               PciIo,
+               EfiPciIoWidthUint16,
+               0,
+               (UINT64) MMIO_HOSTCTL2,
+               1,
+               &Data
+               );
+
+  Data &= 0xFFF0;
+  if (Enable) {
+    Data |= 0x0004; // Enable DDR50 by default, later should enable other mode like HS200/400
+    Data |= BIT3;   // Enable 1.8V Signaling
+  }
+  PciIo->Mem.Write (
+               PciIo,
+               EfiPciIoWidthUint16,
+               0,
+               (UINT64) MMIO_HOSTCTL2,
+               1,
+               &Data
+               );
+
+  return EFI_SUCCESS;
+}
+
+
+/**
+  Power on/off the LED associated with the slot
+
+  @param[in]   This                  A pointer to the EFI_SD_HOST_IO_PROTOCOL instance.
+  @param[in]   Enable                TRUE to set LED on, FALSE to set LED off
+
+  @retval      EFI_SUCCESS
+
+**/
+EFI_STATUS
+HostLEDEnable (
+  IN  EFI_SD_HOST_IO_PROTOCOL    *This,
+  IN  BOOLEAN                    Enable
+  )
+{
+  SDHOST_DATA            *SdHostData;
+  EFI_PCI_IO_PROTOCOL    *PciIo;
+  UINT32                 Data;
+
+  SdHostData = SDHOST_DATA_FROM_THIS (This);
+  PciIo = SdHostData->PciIo;
+
+  PciIo->Mem.Read (
+               PciIo,
+               EfiPciIoWidthUint8,
+               0,
+               (UINT64) MMIO_HOSTCTL,
+               1,
+               &Data
+               );
+
+  if (Enable) {
+    //
+    // LED On
+    //
+    Data |= BIT0;
+  } else {
+    //
+    // LED Off
+    //
+    Data &= ~BIT0;
+  }
+
+  PciIo->Mem.Write (
+               PciIo,
+               EfiPciIoWidthUint8,
+               0,
+               (UINT64) MMIO_HOSTCTL,
+               1,
+               &Data
+               );
+
+  return EFI_SUCCESS;
+}
+
+
+/**
+  The main function used to send the command to the card inserted into the SD host slot.
+  It will assemble the arguments to set the command register and wait for the command
+  and transfer completed until timeout. Then it will read the response register to fill
+  the ResponseData.
+
+  @param[in]   This                  A pointer to the EFI_SD_HOST_IO_PROTOCOL instance.
+  @param[in]   CommandIndex          The command index to set the command index field of command register.
+  @param[in]   Argument              Command argument to set the argument field of command register.
+  @param[in]   DataType              TRANSFER_TYPE, indicates no data, data in or data out.
+  @param[in]   Buffer                Contains the data read from / write to the device.
+  @param[in]   BufferSize            The size of the buffer.
+  @param[in]   ResponseType          RESPONSE_TYPE.
+  @param[in]   TimeOut               Time out value in 1 ms unit.
+  @param[out]  ResponseData          Depending on the ResponseType, such as CSD or card status.
+
+  @retval      EFI_SUCCESS
+  @retval      EFI_INVALID_PARAMETER
+  @retval      EFI_OUT_OF_RESOURCES
+  @retval      EFI_TIMEOUT
+  @retval      EFI_DEVICE_ERROR
+
+**/
+EFI_STATUS
+EFIAPI
+SendCommand (
+  IN   EFI_SD_HOST_IO_PROTOCOL    *This,
+  IN   UINT16                     CommandIndex,
+  IN   UINT32                     Argument,
+  IN   TRANSFER_TYPE              DataType,
+  IN   UINT8                      *Buffer, OPTIONAL
+  IN   UINT32                     BufferSize,
+  IN   RESPONSE_TYPE              ResponseType,
+  IN   UINT32                     TimeOut,
+  OUT  UINT32                     *ResponseData OPTIONAL
+  )
+{
+  EFI_STATUS            Status;
+  SDHOST_DATA           *SdHostData;
+  EFI_PCI_IO_PROTOCOL   *PciIo;
+  UINT32                ResponseDataCount;
+  UINT32                Data;
+  UINT64                Data64;
+  UINT8                 Index;
+  INTN                  TimeOut2;
+  BOOLEAN               AutoCMD12Enable = FALSE;
+
+  Status                = EFI_SUCCESS;
+  ResponseDataCount     = 1;
+  SdHostData            = SDHOST_DATA_FROM_THIS (This);
+  PciIo                 = SdHostData->PciIo;
+  AutoCMD12Enable       = (CommandIndex & AUTO_CMD12_ENABLE) ? TRUE : FALSE;
+  CommandIndex          = CommandIndex & CMD_INDEX_MASK;
+
+  if (Buffer != NULL && DataType == NoData) {
+    Status = EFI_INVALID_PARAMETER;
+    DEBUG ((EFI_D_ERROR, "SendCommand: invalid parameter \r\n"));
+    goto Exit;
+  }
+
+  if (((UINTN) Buffer & (This->HostCapability.BoundarySize - 1)) != (UINTN) NULL) {
+    Status = EFI_INVALID_PARAMETER;
+    DEBUG ((EFI_D_ERROR, "SendCommand: invalid parameter \r\n"));
+    goto Exit;
+  }
+
+  DEBUG ((EFI_D_INFO, "SendCommand: Command Index = %d \r\n", CommandIndex));
+
+  TimeOut2 = 1000; // 10 ms
+  do {
+    PciIo->Mem.Read (
+                 PciIo,
+                 EfiPciIoWidthUint32,
+                 0,
+                 (UINT64) MMIO_PSTATE,
+                 1,
+                 &Data
+                 );
+
+     gBS->Stall (10);
+  } while ((TimeOut2-- > 0) && (Data &BIT0));
+  TimeOut2 = 1000; // 10 ms
+  do {
+    PciIo->Mem.Read (
+                 PciIo,
+                 EfiPciIoWidthUint32,
+                 0,
+                 (UINT64) MMIO_PSTATE,
+                 1,
+                 &Data
+                 );
+
+    gBS->Stall (10);
+  } while ((TimeOut2-- > 0) && (Data & BIT1));
+
+  //
+  // Clear status bits
+  //
+  Data = 0xFFFF;
+  PciIo->Mem.Write (
+               PciIo,
+               EfiPciIoWidthUint16,
+               0,
+               (UINT64) MMIO_NINTSTS,
+               1,
+               &Data
+               );
+
+  Data = 0xFFFF;
+  PciIo->Mem.Write (
+               PciIo,
+               EfiPciIoWidthUint16,
+               0,
+               (UINT64) MMIO_ERINTSTS,
+               1,
+               &Data
+               );
+
+
+  if (Buffer != NULL) {
+     PciIo->Mem.Write (
+                  PciIo,
+                  EfiPciIoWidthUint32,
+                  0,
+                  (UINT64) MMIO_DMAADR,
+                  1,
+                  &Buffer
+                  );
+
+     PciIo->Mem.Read (
+                  PciIo,
+                  EfiPciIoWidthUint16,
+                  0,
+                  (UINT64) MMIO_BLKSZ,
+                  1,
+                  &Data
+                  );
+
+     Data &= ~(0xFFF);
+     if (BufferSize <= SdHostData->BlockLength) {
+       Data |= (BufferSize | 0x7000);
+     } else {
+       Data |= (SdHostData->BlockLength | 0x7000);
+     }
+
+     PciIo->Mem.Write (
+                  PciIo,
+                  EfiPciIoWidthUint16,
+                  0,
+                  (UINT64) MMIO_BLKSZ,
+                  1,
+                  &Data
+                  );
+
+     if (BufferSize <= SdHostData->BlockLength) {
+       Data = 1;
+     } else {
+       Data = BufferSize / SdHostData->BlockLength;
+     }
+     PciIo->Mem.Write (
+                  PciIo,
+                  EfiPciIoWidthUint16,
+                  0,
+                  (UINT64) MMIO_BLKCNT,
+                  1,
+                  &Data
+                  );
+
+  } else {
+    Data = 0;
+    PciIo->Mem.Write (
+                 PciIo,
+                 EfiPciIoWidthUint16,
+                 0,
+                 (UINT64) MMIO_BLKSZ,
+                 1,
+                 &Data
+                 );
+
+    PciIo->Mem.Write (
+                 PciIo,
+                 EfiPciIoWidthUint16,
+                 0,
+                 (UINT64) MMIO_BLKCNT,
+                 1,
+                 &Data
+                 );
+  }
+
+  //
+  // Argument
+  //
+  Data = Argument;
+  PciIo->Mem.Write (
+               PciIo,
+               EfiPciIoWidthUint32,
+               0,
+               (UINT64) MMIO_CMDARG,
+               1,
+               &Data
+               );
+
+  PciIo->Mem.Read (
+               PciIo,
+               EfiPciIoWidthUint16,
+               0,
+               (UINT64) MMIO_XFRMODE,
+               1,
+               &Data
+               );
+
+  DEBUG ((EFI_D_INFO, "Transfer mode read  = 0x%x \r\n", (Data & 0xFFFF)));
+
+  //
+  // BIT0 - DMA Enable
+  // BIT2 - Auto Cmd12
+  //
+  if (DataType == InData) {
+    Data |= BIT4 | BIT0;
+  } else if (DataType == OutData){
+    Data &= ~BIT4;
+    Data |= BIT0;
+  } else {
+    Data &= ~(BIT4 | BIT0);
+  }
+
+  if (BufferSize <= SdHostData->BlockLength) {
+    Data &= ~(BIT5 | BIT1 | BIT2);
+    Data |= BIT1; // Enable block count always
+  } else {
+     if (SdHostData->IsAutoStopCmd && AutoCMD12Enable) {
+     Data |= (BIT5 | BIT1 | BIT2);
+     } else {
+     Data |= (BIT5 | BIT1);
+     }
+  }
+
+  DEBUG ((EFI_D_INFO, "Transfer mode write = 0x%x \r\n", (Data & 0xffff)));
+  PciIo->Mem.Write (
+               PciIo,
+               EfiPciIoWidthUint16,
+               0,
+               (UINT64) MMIO_XFRMODE,
+               1,
+               &Data
+               );
+
+  //
+  //Command
+  //
+  //ResponseTypeSelect    IndexCheck    CRCCheck    ResponseType
+  //  00                     0            0           NoResponse
+  //  01                     0            1           R2
+  //  10                     0            0           R3, R4
+  //  10                     1            1           R1, R5, R6, R7
+  //  11                     1            1           R1b, R5b
+  //
+  switch (ResponseType) {
+    case ResponseNo:
+      Data = (CommandIndex << 8);
+      ResponseDataCount = 0;
+      break;
+
+    case ResponseR1:
+    case ResponseR5:
+    case ResponseR6:
+    case ResponseR7:
+      Data = (CommandIndex << 8) | BIT1 | BIT4| BIT3;
+      ResponseDataCount = 1;
+      break;
+
+    case ResponseR1b:
+    case ResponseR5b:
+      Data = (CommandIndex << 8) | BIT0 | BIT1 | BIT4| BIT3;
+      ResponseDataCount = 1;
+      break;
+
+    case ResponseR2:
+      Data = (CommandIndex << 8) | BIT0 | BIT3;
+      ResponseDataCount = 4;
+      break;
+
+    case ResponseR3:
+    case ResponseR4:
+      Data = (CommandIndex << 8) | BIT1;
+      ResponseDataCount = 1;
+      break;
+
+    default:
+      ASSERT (0);
+      Status = EFI_INVALID_PARAMETER;
+      DEBUG ((EFI_D_ERROR, "SendCommand: invalid parameter \r\n"));
+      goto Exit;
+  }
+
+  if (DataType != NoData) {
+    Data |= BIT5;
+  }
+
+  HostLEDEnable (This, TRUE);
+
+  PciIo->Mem.Write (
+               PciIo,
+               EfiPciIoWidthUint16,
+               0,
+               (UINT64) MMIO_SDCMD,
+               1,
+               &Data
+               );
+
+  Data = 0;
+  do {
+    PciIo->Mem.Read (
+                 PciIo,
+                 EfiPciIoWidthUint16,
+                 0,
+                 (UINT64) MMIO_ERINTSTS,
+                 1,
+                 &Data
+                 );
+
+    if ((Data & 0x07FF) != 0) {
+      Status = GetErrorReason (CommandIndex, (UINT16) Data);
+      DEBUG ((EFI_D_ERROR, "SendCommand: Error happens \r\n"));
+      goto Exit;
+    }
+
+    PciIo->Mem.Read (
+                 PciIo,
+                 EfiPciIoWidthUint16,
+                 0,
+                 (UINT64) MMIO_NINTSTS,
+                 1,
+                 &Data
+                 );
+
+    if ((Data & BIT0) == BIT0) {
+      //
+      //Command completed, can read response
+      //
+      if (DataType == NoData) {
+        break;
+      } else {
+        //
+        // Transfer completed
+        //
+        if ((Data & BIT1) == BIT1) {
+          break;
+        }
+      }
+    }
+
+    gBS->Stall (1 * 1000);
+
+    TimeOut --;
+
+  } while (TimeOut > 0);
+
+  if (TimeOut == 0) {
+    Status = EFI_TIMEOUT;
+    DEBUG ((EFI_D_ERROR, "SendCommand: Time out \r\n"));
+    goto Exit;
+  }
+
+  if (ResponseData != NULL) {
+    PciIo->Mem.Read (
+                 PciIo,
+                 EfiPciIoWidthUint32,
+                 0,
+                 (UINT64) MMIO_RESP,
+                 ResponseDataCount,
+                 ResponseData
+                 );
+
+    if (ResponseType == ResponseR2) {
+      //
+      // Adjustment for R2 response
+      //
+      Data = 1;
+      for (Index = 0; Index < ResponseDataCount; Index++) {
+        Data64 = LShiftU64 (*ResponseData, 8);
+        *ResponseData = (UINT32) ((Data64 & 0xFFFFFFFF) | Data);
+        Data = (UINT32) RShiftU64 (Data64, 32);
+        ResponseData++;
+      }
+    }
+  }
+
+Exit:
+  HostLEDEnable (This, FALSE);
+  return Status;
+}
+
+
+/**
+  Set max clock frequency of the host, the actual frequency may not be the same as MaxFrequency.
+  It depends on the max frequency the host can support, divider, and host speed mode.
+
+  @param[in]  This                  A pointer to the EFI_SD_HOST_IO_PROTOCOL instance.
+  @param[in]  MaxFrequency          Max frequency in HZ.
+
+  @retval     EFI_SUCCESS
+  @retval     EFI_TIMEOUT
+
+**/
+EFI_STATUS
+EFIAPI
+SetClockFrequency (
+  IN  EFI_SD_HOST_IO_PROTOCOL    *This,
+  IN  UINT32                     MaxFrequency
+  )
+{
+  UINT32                 Data;
+  UINT16                 FreqSelBits;
+  EFI_STATUS             Status;
+  SDHOST_DATA            *SdHostData;
+  EFI_PCI_IO_PROTOCOL    *PciIo;
+  UINT32                 TimeOutCount;
+  UINT32                 Revision;
+
+  SdHostData = SDHOST_DATA_FROM_THIS (This);
+  PciIo = SdHostData->PciIo;
+  Data = 0;
+  PciIo->Mem.Write (
+               PciIo,
+               EfiPciIoWidthUint16,
+               0,
+               (UINT64) MMIO_CLKCTL,
+               1,
+               &Data
+               );
+
+  PciIo->Mem.Read (
+               PciIo,
+               EfiPciIoWidthUint8,
+               0,
+               (UINT64) MMIO_CTRLRVER,
+               1,
+               &Revision
+               );
+
+  Revision &= 0x000000FF;
+
+  Status = DividedClockModeBits (
+             SdHostData->BaseClockInMHz * 1000 * 1000,
+             MaxFrequency,
+             (Revision < SDHCI_SPEC_300),
+             &FreqSelBits
+             );
+
+  if (EFI_ERROR (Status)) {
+    //
+    // Cannot reach MaxFrequency with SdHostData->BaseClockInMHz.
+    //
+    ASSERT_EFI_ERROR (Status);
+    return Status;
+  }
+
+  Data = 0;
+
+  //
+  // Enable internal clock and Stop Clock Enable
+  //
+  Data = BIT0;
+  PciIo->Mem.Write (
+               PciIo,
+               EfiPciIoWidthUint16,
+               0,
+               (UINT64) MMIO_CLKCTL,
+               1,
+               &Data
+               );
+
+  TimeOutCount = TIME_OUT_1S;
+  do {
+    PciIo->Mem.Read (
+                 PciIo,
+                 EfiPciIoWidthUint16,
+                 0,
+                 (UINT64) MMIO_CLKCTL,
+                 1,
+                 &Data
+                 );
+
+    gBS->Stall (1 * 1000);
+    TimeOutCount --;
+    if (TimeOutCount == 0) {
+      DEBUG ((EFI_D_ERROR, "SetClockFrequency: Time out \r\n"));
+      return EFI_TIMEOUT;
+    }
+  } while ((Data & BIT1) != BIT1);
+
+  DEBUG ((EFI_D_INFO, "Base Clock In MHz: %d\r\n", SdHostData->BaseClockInMHz));
+
+  Data = (BIT0 | ((UINT32) FreqSelBits));
+  DEBUG ((EFI_D_INFO, "Data write to MMIO_CLKCTL: 0x%04x \r\n", Data));
+  PciIo->Mem.Write (
+               PciIo,
+               EfiPciIoWidthUint16,
+               0,
+               (UINT64) MMIO_CLKCTL,
+               1,
+               &Data
+               );
+
+  TimeOutCount = TIME_OUT_1S;
+  do {
+    PciIo->Mem.Read (
+                 PciIo,
+                 EfiPciIoWidthUint16,
+                 0,
+                 (UINT64) MMIO_CLKCTL,
+                 1,
+                 &Data
+                 );
+
+    gBS->Stall (1 * 1000);
+    TimeOutCount --;
+    if (TimeOutCount == 0) {
+      DEBUG ((EFI_D_ERROR, "SetClockFrequency: Time out \r\n"));
+      return EFI_TIMEOUT;
+    }
+  } while ((Data & BIT1) != BIT1);
+  gBS->Stall (20 * 1000);
+  Data |= BIT2;
+  PciIo->Mem.Write (
+               PciIo,
+               EfiPciIoWidthUint16,
+               0,
+               (UINT64) MMIO_CLKCTL,
+               1,
+               &Data
+               );
+
+  return EFI_SUCCESS;
+}
+
+
+/**
+  Set bus width of the host controller
+
+  @param[in]   This                  A pointer to the EFI_SD_HOST_IO_PROTOCOL instance.
+  @param[in]   BusWidth              Bus width in 1, 4, 8 bits.
+
+  @retval      EFI_SUCCESS
+  @retval      EFI_INVALID_PARAMETER
+
+**/
+EFI_STATUS
+EFIAPI
+SetBusWidth (
+  IN  EFI_SD_HOST_IO_PROTOCOL    *This,
+  IN  UINT32                     BusWidth
+  )
+{
+  SDHOST_DATA            *SdHostData;
+  EFI_PCI_IO_PROTOCOL    *PciIo;
+  UINT8                  Data;
+
+  SdHostData = SDHOST_DATA_FROM_THIS (This);
+
+  if ((BusWidth != 1) && (BusWidth != 4) && (BusWidth != 8)) {
+    DEBUG ((EFI_D_ERROR, "SetBusWidth: Invalid parameter \r\n"));
+    return EFI_INVALID_PARAMETER;
+  }
+
+  if ((SdHostData->SdHostIo.HostCapability.BusWidth8 == FALSE) && (BusWidth == 8)) {
+     DEBUG ((EFI_D_ERROR, "SetBusWidth: Invalid parameter \r\n"));
+     return EFI_INVALID_PARAMETER;
+  }
+
+  PciIo = SdHostData->PciIo;
+
+  PciIo->Mem.Read (
+               PciIo,
+               EfiPciIoWidthUint8,
+               0,
+               (UINT64) MMIO_HOSTCTL,
+               1,
+               &Data
+               );
+  //
+  // BIT5 8-bit MMC Support (MMC8):
+  // If set, IOH supports 8-bit MMC. When cleared, IOH does not support this feature
+  //
+  if (BusWidth == 8) {
+    DEBUG ((EFI_D_INFO, "Bus Width is 8-bit ... \r\n"));
+    Data |= BIT5;
+  } else if (BusWidth == 4) {
+    DEBUG ((EFI_D_INFO, "Bus Width is 4-bit ... \r\n"));
+    Data &= ~BIT5;
+    Data |= BIT1;
+  } else {
+    DEBUG ((EFI_D_INFO, "Bus Width is 1-bit ... \r\n"));
+    Data &= ~BIT5;
+    Data &= ~BIT1;
+  }
+
+  PciIo->Mem.Write (
+               PciIo,
+               EfiPciIoWidthUint8,
+               0,
+               (UINT64) MMIO_HOSTCTL,
+               1,
+               &Data
+               );
+
+  return EFI_SUCCESS;
+}
+
+
+/**
+  Set voltage which could supported by the host controller.
+  Support 0(Power off the host), 1.8V, 3.0V, 3.3V
+
+  @param[in]   This                   A pointer to the EFI_SD_HOST_IO_PROTOCOL instance.
+  @param[in]   Voltage                Units in 0.1 V.
+
+  @retval      EFI_SUCCESS
+  @retval      EFI_INVALID_PARAMETER
+
+**/
+EFI_STATUS
+EFIAPI
+SetHostVoltage (
+  IN  EFI_SD_HOST_IO_PROTOCOL    *This,
+  IN  UINT32                     Voltage
+  )
+{
+  SDHOST_DATA            *SdHostData;
+  EFI_PCI_IO_PROTOCOL    *PciIo;
+  UINT8                  Data;
+  EFI_STATUS             Status;
+
+  SdHostData = SDHOST_DATA_FROM_THIS (This);
+  PciIo      = SdHostData->PciIo;
+  Status     = EFI_SUCCESS;
+
+  PciIo->Mem.Read (
+               PciIo,
+               EfiPciIoWidthUint8,
+               0,
+               (UINT64) MMIO_PWRCTL,
+               1,
+               &Data
+               );
+
+  if (Voltage == 0) {
+    //
+    // Power Off the host
+    //
+    Data &= ~BIT0;
+  } else if (Voltage <= 18 && This->HostCapability.V18Support) {
+    //
+    // 1.8V
+    //
+    Data |= (BIT1 | BIT3 | BIT0);
+  } else if (Voltage > 18 &&  Voltage <= 30 && This->HostCapability.V30Support) {
+    //
+    // 3.0V
+    //
+    Data |= (BIT2 | BIT3 | BIT0);
+  } else if (Voltage > 30 && Voltage <= 33 && This->HostCapability.V33Support) {
+    //
+    // 3.3V
+    //
+    Data |= (BIT1 | BIT2 | BIT3 | BIT0);
+  } else {
+    Status = EFI_UNSUPPORTED;
+    goto Exit;
+  }
+
+  PciIo->Mem.Write (
+               PciIo,
+               EfiPciIoWidthUint8,
+               0,
+               (UINT64) MMIO_PWRCTL,
+               1,
+               &Data
+               );
+
+  gBS->Stall (10 * 1000);
+
+Exit:
+  return Status;
+}
+
+
+/**
+  Reset the host controller.
+
+  @param[in]   This                  A pointer to the EFI_SD_HOST_IO_PROTOCOL instance.
+  @param[in]   ResetAll              TRUE to reset all.
+
+  @retval      EFI_SUCCESS
+  @retval      EFI_TIMEOUT
+
+**/
+EFI_STATUS
+EFIAPI
+ResetSdHost (
+  IN  EFI_SD_HOST_IO_PROTOCOL    *This,
+  IN  RESET_TYPE                 ResetType
+  )
+{
+  SDHOST_DATA            *SdHostData;
+  EFI_PCI_IO_PROTOCOL    *PciIo;
+  UINT32                 Data;
+  UINT16                 ErrStatus;
+  UINT32                 Mask;
+  UINT32                 TimeOutCount;
+  UINT16                 SaveClkCtl;
+  UINT16                 ZeroClkCtl;
+
+  SdHostData = SDHOST_DATA_FROM_THIS (This);
+  PciIo      = SdHostData->PciIo;
+  Mask       = 0;
+  ErrStatus  = 0;
+
+  if (ResetType == Reset_Auto) {
+    PciIo->Mem.Read (
+                 PciIo,
+                 EfiPciIoWidthUint16,
+                 0,
+                 (UINT64) MMIO_ERINTSTS,
+                 1,
+                 &ErrStatus
+                 );
+
+    if ((ErrStatus & 0xF) != 0) {
+      //
+      // Command Line
+      //
+      Mask |= BIT1;
+    }
+    if ((ErrStatus & 0x70) != 0) {
+      //
+      // Data Line
+      //
+      Mask |= BIT2;
+    }
+  }
+
+  if (ResetType == Reset_DAT || ResetType == Reset_DAT_CMD) {
+    Mask |= BIT2;
+  }
+  if (ResetType == Reset_CMD || ResetType == Reset_DAT_CMD) {
+    Mask |= BIT1;
+  }
+  if (ResetType == Reset_All) {
+    Mask = BIT0;
+  }
+
+  if (Mask == 0) {
+    return EFI_SUCCESS;
+  }
+
+  //
+  // To improve SD stability, we zero the MMIO_CLKCTL register and
+  // stall for 50 microseconds before reseting the controller.  We
+  // restore the register setting following the reset operation.
+  //
+  PciIo->Mem.Read (
+               PciIo,
+               EfiPciIoWidthUint16,
+               0,
+               (UINT64) MMIO_CLKCTL,
+               1,
+               &SaveClkCtl
+               );
+
+  ZeroClkCtl = (UINT16) 0;
+  PciIo->Mem.Write (
+               PciIo,
+               EfiPciIoWidthUint16,
+               0,
+               (UINT64) MMIO_CLKCTL,
+               1,
+               &ZeroClkCtl
+               );
+
+  gBS->Stall (50);
+
+  //
+  // Reset the SD host controller
+  //
+  PciIo->Mem.Write (
+               PciIo,
+               EfiPciIoWidthUint8,
+               0,
+               (UINT64) MMIO_SWRST,
+               1,
+               &Mask
+               );
+
+  Data          = 0;
+  TimeOutCount  = TIME_OUT_1S;
+  do {
+
+    gBS->Stall (1 * 1000);
+
+    TimeOutCount --;
+
+    PciIo->Mem.Read (
+                 PciIo,
+                 EfiPciIoWidthUint8,
+                 0,
+                 (UINT64) MMIO_SWRST,
+                 1,
+                 &Data
+                 );
+
+    if ((Data & Mask) == 0) {
+      break;
+    }
+  } while (TimeOutCount > 0);
+
+  //
+  // We now restore the MMIO_CLKCTL register which we set to 0 above.
+  //
+  PciIo->Mem.Write (
+               PciIo,
+               EfiPciIoWidthUint16,
+               0,
+               (UINT64) MMIO_CLKCTL,
+               1,
+               &SaveClkCtl
+               );
+
+  if (TimeOutCount == 0) {
+    DEBUG ((EFI_D_ERROR, "ResetSdHost: Time out \r\n"));
+    return EFI_TIMEOUT;
+  }
+
+  return EFI_SUCCESS;
+}
+
+
+/**
+  Enable auto stop on the host controller.
+
+  @param[in]   This                  A pointer to the EFI_SD_HOST_IO_PROTOCOL instance.
+  @param[in]   Enable                TRUE to enable, FALSE to disable.
+
+  @retval      EFI_SUCCESS
+  @retval      EFI_TIMEOUT
+
+**/
+EFI_STATUS
+EFIAPI
+EnableAutoStopCmd (
+  IN  EFI_SD_HOST_IO_PROTOCOL    *This,
+  IN  BOOLEAN                    Enable
+  )
+{
+  SDHOST_DATA            *SdHostData;
+
+  SdHostData = SDHOST_DATA_FROM_THIS (This);
+
+  SdHostData->IsAutoStopCmd = Enable;
+
+  return EFI_SUCCESS;
+}
+
+
+/**
+  Set the Block length on the host controller.
+
+  @param[in]   This                  A pointer to the EFI_SD_HOST_IO_PROTOCOL instance.
+  @param[in]   BlockLength           card supportes block length.
+
+  @retval      EFI_SUCCESS
+  @retval      EFI_TIMEOUT
+
+**/
+EFI_STATUS
+EFIAPI
+SetBlockLength (
+  IN  EFI_SD_HOST_IO_PROTOCOL    *This,
+  IN  UINT32                     BlockLength
+  )
+{
+  SDHOST_DATA                    *SdHostData;
+
+  SdHostData = SDHOST_DATA_FROM_THIS (This);
+
+  DEBUG ((EFI_D_INFO, "Block length on the host controller: %d \r\n", BlockLength));
+  SdHostData->BlockLength = BlockLength;
+
+  return EFI_SUCCESS;
+}
+
+
+/**
+  Find whether these is a card inserted into the slot. If so init the host.
+  If not, return EFI_NOT_FOUND.
+
+  @param[in]   This                  A pointer to the EFI_SD_HOST_IO_PROTOCOL instance.
+
+  @retval      EFI_SUCCESS
+  @retval      EFI_NOT_FOUND
+
+**/
+EFI_STATUS
+EFIAPI
+DetectCardAndInitHost (
+  IN  EFI_SD_HOST_IO_PROTOCOL    *This
+  )
+{
+  SDHOST_DATA            *SdHostData;
+  EFI_PCI_IO_PROTOCOL    *PciIo;
+  UINT32                 Data;
+  EFI_STATUS             Status;
+  UINT8                  Voltages[] = { 33, 30, 18 };
+  UINTN                  Loop;
+
+  SdHostData = SDHOST_DATA_FROM_THIS (This);
+  PciIo      = SdHostData->PciIo;
+  Status     = EFI_NOT_FOUND;
+
+  Data = 0;
+  PciIo->Mem.Read (
+               PciIo,
+               EfiPciIoWidthUint32,
+               0,
+               (UINT64) MMIO_PSTATE,
+               1,
+               &Data
+               );
+
+  if ((Data & (BIT16 | BIT17 | BIT18)) != (BIT16 | BIT17 | BIT18)) {
+    //
+    // Has no card inserted
+    //
+    DEBUG ((EFI_D_INFO, "DetectCardAndInitHost: No Cards \r\n"));
+    Status = EFI_NOT_FOUND;
+    goto Exit;
+  }
+  DEBUG ((EFI_D_INFO, "DetectCardAndInitHost: Find Cards \r\n"));
+
+  Status =  EFI_NOT_FOUND;
+  for (Loop = 0; Loop < sizeof (Voltages); Loop++) {
+    DEBUG ((
+      EFI_D_INFO,
+      "DetectCardAndInitHost: SetHostVoltage %d.%dV \r\n",
+      Voltages[Loop] / 10,
+      Voltages[Loop] % 10
+      ));
+    Status = SetHostVoltage (This, Voltages[Loop]);
+    if (EFI_ERROR (Status)) {
+      DEBUG ((EFI_D_INFO, "DetectCardAndInitHost set voltages: [failed]\n"));
+    } else {
+      DEBUG ((EFI_D_INFO, "DetectCardAndInitHost set voltages: [success]\n"));
+      break;
+    }
+  }
+  if (EFI_ERROR (Status)) {
+    DEBUG ((EFI_D_ERROR, "DetectCardAndInitHost: Fail to set voltage \r\n"));
+    goto Exit;
+  }
+
+  Status = SetClockFrequency (This, FREQUENCY_OD);
+  if (EFI_ERROR (Status)) {
+    DEBUG ((EFI_D_ERROR, "DetectCardAndInitHost: Fail to set frequency \r\n"));
+    goto Exit;
+  }
+  SetBusWidth (This, 1);
+
+  //
+  // Enable normal status change
+  //
+  Data = (BIT0 | BIT1);
+
+  PciIo->Mem.Write (
+               PciIo,
+               EfiPciIoWidthUint16,
+               0,
+               (UINT64) MMIO_NINTEN,
+               1,
+               &Data
+               );
+
+  //
+  // Enable error status change
+  //
+  PciIo->Mem.Read (
+               PciIo,
+               EfiPciIoWidthUint16,
+               0,
+               (UINT64) MMIO_ERINTEN,
+               1,
+               &Data
+               );
+
+  Data |= (BIT0 | BIT1 | BIT2 | BIT3 | BIT4 | BIT5 | BIT6 | BIT7 | BIT8);
+
+  PciIo->Mem.Write (
+               PciIo,
+               EfiPciIoWidthUint16,
+               0,
+               (UINT64) MMIO_ERINTEN,
+               1,
+               &Data
+               );
+
+  //
+  // Data transfer Timeout control
+  //
+  Data = 0x0E;
+
+  PciIo->Mem.Write (
+               PciIo,
+               EfiPciIoWidthUint8,
+               0,
+               (UINT64) MMIO_TOCTL,
+               1,
+               &Data
+               );
+  //
+  // Set Default Bus width as 1 bit
+  //
+
+Exit:
+  return Status;
+
+}
+
+
+/**
+  Entry point for EFI drivers.
+
+  @param[in]   ImageHandle      EFI_HANDLE.
+  @param[in]   SystemTable      EFI_SYSTEM_TABLE.
+
+  @retval      EFI_SUCCESS      Driver is successfully loaded.
+  @retval      Others           Failed.
+
+**/
+EFI_STATUS
+EFIAPI
+InitializeSdController (
+  IN EFI_HANDLE           ImageHandle,
+  IN EFI_SYSTEM_TABLE     *SystemTable
+  )
+{
+  return EfiLibInstallDriverBindingComponentName2 (
+           ImageHandle,
+           SystemTable,
+           &gSdControllerDriverBinding,
+           ImageHandle,
+           &gSdControllerName,
+           &gSdControllerName2
+           );
+}
+
+
+/**
+  Test to see if this driver supports ControllerHandle. Any
+  ControllerHandle that has SdHostIoProtocol installed will be supported.
+
+  @param[in]   This                 Protocol instance pointer.
+  @param[in]   Controller           Handle of device to test.
+  @param[in]   RemainingDevicePath  Not used.
+
+  @retval      EFI_SUCCESS          This driver supports this device.
+  @retval      EFI_UNSUPPORTED      This driver does not support this device.
+
+**/
+EFI_STATUS
+EFIAPI
+SdControllerSupported (
+  IN EFI_DRIVER_BINDING_PROTOCOL     *This,
+  IN EFI_HANDLE                      Controller,
+  IN EFI_DEVICE_PATH_PROTOCOL        *RemainingDevicePath
+  )
+{
+  EFI_STATUS                OpenStatus;
+  EFI_STATUS                Status;
+  EFI_PCI_IO_PROTOCOL       *PciIo;
+  PCI_CLASSC                PciClass;
+  EFI_SD_HOST_IO_PROTOCOL   *SdHostIo;
+  UINTN                      Seg, Bus, Dev, Func;
+
+  Status = gBS->OpenProtocol (
+                  Controller,
+                  &gEfiSdHostIoProtocolGuid,
+                  (VOID **) &SdHostIo,
+                  This->DriverBindingHandle,
+                  Controller,
+                  EFI_OPEN_PROTOCOL_GET_PROTOCOL
+                  );
+
+  if (!EFI_ERROR (Status)) {
+    DEBUG (( DEBUG_INFO, "SdHost controller is already started\n"));
+    return EFI_ALREADY_STARTED;
+  }
+
+  //
+  // Test whether there is PCI IO Protocol attached on the controller handle.
+  //
+  OpenStatus = gBS->OpenProtocol (
+                      Controller,
+                      &gEfiPciIoProtocolGuid,
+                      (VOID **) &PciIo,
+                      This->DriverBindingHandle,
+                      Controller,
+                      EFI_OPEN_PROTOCOL_BY_DRIVER
+                      );
+
+  if (EFI_ERROR (OpenStatus)) {
+    return OpenStatus;
+  }
+
+  Status = PciIo->Pci.Read (
+                        PciIo,
+                        EfiPciIoWidthUint8,
+                        PCI_CLASSCODE_OFFSET,
+                        sizeof (PCI_CLASSC) / sizeof (UINT8),
+                        &PciClass
+                        );
+
+  if (EFI_ERROR (Status)) {
+    Status = EFI_UNSUPPORTED;
+    goto ON_EXIT;
+  }
+
+  //
+  // Test whether the controller belongs to SD type
+  //
+  if ((PciClass.BaseCode != PCI_CLASS_SYSTEM_PERIPHERAL) ||
+      (PciClass.SubClassCode != PCI_SUBCLASS_SD_HOST_CONTROLLER) ||
+      ((PciClass.PI != PCI_IF_STANDARD_HOST_NO_DMA) && (PciClass.PI != PCI_IF_STANDARD_HOST_SUPPORT_DMA))
+      ) {
+
+    Status = EFI_UNSUPPORTED;
+    goto ON_EXIT;
+  }
+
+  Status = PciIo->GetLocation (
+                    PciIo,
+                    &Seg,
+                    &Bus,
+                    &Dev,
+                    &Func
+                    );
+
+  if (EFI_ERROR (Status)) {
+    Status = EFI_UNSUPPORTED;
+    goto ON_EXIT;
+  }
+
+  if ((Seg != 0) || (Bus != 0) || (Dev != 27) || (Func != 0)) {
+    //
+    // This is not the SD controller, bail.
+    //
+    Status = EFI_UNSUPPORTED;
+    goto ON_EXIT;
+  }
+
+  DEBUG ((EFI_D_INFO, "%a(#%d) - Seg %d, bus:%d, Dev:%d, Func:%d\n", __FUNCTION__, __LINE__, Seg, Bus, Dev, Func));
+
+ON_EXIT:
+  gBS->CloseProtocol (
+         Controller,
+         &gEfiPciIoProtocolGuid,
+         This->DriverBindingHandle,
+         Controller
+         );
+
+  return Status;
+}
+
+
+/**
+  Starting the SD Host Controller Driver.
+
+  @param[in]   This                 Protocol instance pointer.
+  @param[in]   Controller           Handle of device to test.
+  @param[in]   RemainingDevicePath  Not used.
+
+  @retval      EFI_SUCCESS          This driver supports this device.
+  @retval      EFI_UNSUPPORTED      This driver does not support this device.
+  @retval      EFI_DEVICE_ERROR     This driver cannot be started due to device Error.
+                                    EFI_OUT_OF_RESOURCES- Failed due to resource shortage.
+
+**/
+EFI_STATUS
+EFIAPI
+SdControllerStart (
+  IN EFI_DRIVER_BINDING_PROTOCOL     *This,
+  IN EFI_HANDLE                      Controller,
+  IN EFI_DEVICE_PATH_PROTOCOL        *RemainingDevicePath
+  )
+{
+  EFI_STATUS            Status;
+  EFI_PCI_IO_PROTOCOL   *PciIo;
+  SDHOST_DATA           *SdHostData;
+  UINT32                Data;
+
+  SdHostData = NULL;
+  Data = 0;
+
+  //
+  // Open PCI I/O Protocol and save pointer to open protocol
+  // in private data area.
+  //
+  Status = gBS->OpenProtocol (
+                  Controller,
+                  &gEfiPciIoProtocolGuid,
+                  (VOID **) &PciIo,
+                  This->DriverBindingHandle,
+                  Controller,
+                  EFI_OPEN_PROTOCOL_BY_DRIVER
+                  );
+
+  if (EFI_ERROR (Status)) {
+    goto Exit;
+  }
+
+  //
+  // Enable the SD Host Controller MMIO space
+  //
+  Status = PciIo->Attributes (
+                    PciIo,
+                    EfiPciIoAttributeOperationEnable,
+                    EFI_PCI_DEVICE_ENABLE,
+                    NULL
+                    );
+
+  if (EFI_ERROR (Status)) {
+    Status = EFI_OUT_OF_RESOURCES;
+    goto Exit;
+  }
+
+  SdHostData = (SDHOST_DATA *) AllocateZeroPool (sizeof (SDHOST_DATA));
+  if (SdHostData == NULL) {
+    Status =  EFI_OUT_OF_RESOURCES;
+    goto Exit;
+  }
+
+  SdHostData->Signature   = SDHOST_DATA_SIGNATURE;
+  SdHostData->PciIo       = PciIo;
+
+  CopyMem (&SdHostData->SdHostIo, &mSdHostIo, sizeof (EFI_SD_HOST_IO_PROTOCOL));
+
+  ResetSdHost (&SdHostData->SdHostIo, Reset_All);
+
+  PciIo->Mem.Read (
+               PciIo,
+               EfiPciIoWidthUint16,
+               0,
+               (UINT64) MMIO_CTRLRVER,
+               1,
+               &Data
+               );
+
+  SdHostData->SdHostIo.HostCapability.HostVersion = Data & 0xFF;
+  DEBUG ((EFI_D_INFO, "SdHostDriverBindingStart: HostVersion 0x%x \r\n", SdHostData->SdHostIo.HostCapability.HostVersion));
+
+  PciIo->Mem.Read (
+               PciIo,
+               EfiPciIoWidthUint32,
+               0,
+               (UINT64) MMIO_CAP,
+               1,
+               &Data
+               );
+
+  DEBUG ((EFI_D_INFO, "SdHostDriverBindingStart: MMIO_CAP 0x%x \r\n", Data));
+  if ((Data & BIT18) != 0) {
+    SdHostData->SdHostIo.HostCapability.BusWidth8 = TRUE;
+  }
+
+  if ((Data & BIT21) != 0) {
+    SdHostData->SdHostIo.HostCapability.HighSpeedSupport = TRUE;
+  }
+
+  if ((Data & BIT24) != 0) {
+    SdHostData->SdHostIo.HostCapability.V33Support = TRUE;
+  }
+
+  if ((Data & BIT25) != 0) {
+    SdHostData->SdHostIo.HostCapability.V30Support = TRUE;
+  }
+
+  if ((Data & BIT26) != 0) {
+    SdHostData->SdHostIo.HostCapability.V18Support = TRUE;
+  }
+
+  SdHostData->SdHostIo.HostCapability.BusWidth4 = TRUE;
+
+  if (SdHostData->SdHostIo.HostCapability.HostVersion < SDHCI_SPEC_300) {
+    SdHostData->BaseClockInMHz = (Data >> 8) & 0x3F;
+   } else {
+     SdHostData->BaseClockInMHz = (Data >> 8) & 0xFF;
+
+   }
+
+  SdHostData->BlockLength = 512 << ((Data >> 16) & 0x03);
+  DEBUG ((EFI_D_INFO, "SdHostDriverBindingStart: BlockLength 0x%x \r\n", SdHostData->BlockLength));
+  SdHostData->IsAutoStopCmd  = TRUE;
+
+  Status = gBS->InstallProtocolInterface (
+                  &Controller,
+                  &gEfiSdHostIoProtocolGuid,
+                  EFI_NATIVE_INTERFACE,
+                  &SdHostData->SdHostIo
+                  );
+
+  if (EFI_ERROR (Status)) {
+    goto Exit;
+  }
+
+  //
+  // Install the component name protocol
+  //
+  SdHostData->ControllerNameTable = NULL;
+
+  AddUnicodeString2 (
+    "eng",
+    gSdControllerName.SupportedLanguages,
+    &SdHostData->ControllerNameTable,
+    L"SD Host Controller",
+    TRUE
+    );
+
+  AddUnicodeString2 (
+    "en",
+    gSdControllerName2.SupportedLanguages,
+    &SdHostData->ControllerNameTable,
+    L"SD Host Controller",
+    FALSE
+    );
+
+Exit:
+  if (EFI_ERROR (Status)) {
+    if (SdHostData != NULL) {
+      FreePool (SdHostData);
+    }
+  }
+
+  return Status;
+}
+
+
+/**
+  Stop this driver on ControllerHandle. Support stoping any child handles
+  created by this driver.
+
+  @param[in]   This                 Protocol instance pointer.
+  @param[in]   Controller           Handle of device to stop driver on.
+  @param[in]   NumberOfChildren     Number of Children in the ChildHandleBuffer.
+  @param[in]   ChildHandleBuffer    List of handles for the children we need to stop.
+
+  @retval      EFI_SUCCESS
+  @retval      others
+
+**/
+EFI_STATUS
+EFIAPI
+SdControllerStop (
+  IN EFI_DRIVER_BINDING_PROTOCOL     *This,
+  IN EFI_HANDLE                      Controller,
+  IN UINTN                           NumberOfChildren,
+  IN EFI_HANDLE                      *ChildHandleBuffer
+  )
+{
+  EFI_STATUS               Status;
+  EFI_SD_HOST_IO_PROTOCOL  *SdHostIo;
+  SDHOST_DATA              *SdHostData;
+
+  Status = gBS->OpenProtocol (
+                  Controller,
+                  &gEfiSdHostIoProtocolGuid,
+                  (VOID **) &SdHostIo,
+                  This->DriverBindingHandle,
+                  Controller,
+                  EFI_OPEN_PROTOCOL_GET_PROTOCOL
+                  );
+
+  //
+  // Test whether the Controller handler passed in is a valid
+  // Usb controller handle that should be supported, if not,
+  // return the error status directly
+  //
+  if (EFI_ERROR (Status)) {
+    return Status;
+  }
+
+  SetHostVoltage (SdHostIo, 0);
+
+  SdHostData = SDHOST_DATA_FROM_THIS(SdHostIo);
+
+  //
+  // Uninstall Block I/O protocol from the device handle
+  //
+  Status = gBS->UninstallProtocolInterface (
+                  Controller,
+                  &gEfiSdHostIoProtocolGuid,
+                  SdHostIo
+                  );
+
+  if (EFI_ERROR (Status)) {
+    return Status;
+  }
+
+  FreeUnicodeStringTable (SdHostData->ControllerNameTable);
+
+  FreePool (SdHostData);
+
+  gBS->CloseProtocol (
+         Controller,
+         &gEfiPciIoProtocolGuid,
+         This->DriverBindingHandle,
+         Controller
+         );
+
+  return EFI_SUCCESS;
+}
+
diff --git a/Silicon/BroxtonSoC/BroxtonSiPkg/SouthCluster/Sdio/Dxe/SD/SdControllerDxe/SdController.h b/Silicon/BroxtonSoC/BroxtonSiPkg/SouthCluster/Sdio/Dxe/SD/SdControllerDxe/SdController.h
new file mode 100644
index 0000000..a702565
--- /dev/null
+++ b/Silicon/BroxtonSoC/BroxtonSiPkg/SouthCluster/Sdio/Dxe/SD/SdControllerDxe/SdController.h
@@ -0,0 +1,314 @@
+/** @file
+  The definition for SD host controller driver model and HC protocol routines.
+
+  Copyright (c) 2013 - 2016, Intel Corporation. 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 _SD_CONTROLLER_H_
+#define _SD_CONTROLLER_H_
+
+#include <Uefi.h>
+#include <Protocol/PciIo.h>
+#include <Library/DebugLib.h>
+#include <Library/BaseMemoryLib.h>
+#include <Library/UefiDriverEntryPoint.h>
+#include <Library/UefiBootServicesTableLib.h>
+#include <Library/UefiLib.h>
+#include <Library/BaseLib.h>
+#include <Library/MemoryAllocationLib.h>
+#include <Library/PcdLib.h>
+#include <IndustryStandard/Pci22.h>
+#include <Library/GpioLib.h>
+#include "ComponentName.h"
+#include "SdHostIo.h"
+
+extern EFI_DRIVER_BINDING_PROTOCOL   gSdControllerDriverBinding;
+extern EFI_COMPONENT_NAME_PROTOCOL   gSdControllerName;
+extern EFI_COMPONENT_NAME2_PROTOCOL  gSdControllerName2;
+
+#define SDHOST_DATA_SIGNATURE  SIGNATURE_32 ('s', 'd', 'h', 's')
+
+#define BLOCK_SIZE   0x200
+#define TIME_OUT_1S  1000
+
+#pragma pack(1)
+
+//
+// PCI Class Code structure
+//
+typedef struct {
+  UINT8 PI;
+  UINT8 SubClassCode;
+  UINT8 BaseCode;
+} PCI_CLASSC;
+
+#pragma pack()
+
+typedef struct {
+  UINTN                      Signature;
+  EFI_SD_HOST_IO_PROTOCOL    SdHostIo;
+  EFI_PCI_IO_PROTOCOL        *PciIo;
+  BOOLEAN                    IsAutoStopCmd;
+  UINT32                     BaseClockInMHz;
+  UINT32                     CurrentClockInKHz;
+  UINT32                     BlockLength;
+  EFI_UNICODE_STRING_TABLE   *ControllerNameTable;
+} SDHOST_DATA;
+
+#define SDHOST_DATA_FROM_THIS(a) \
+    CR(a, SDHOST_DATA, SdHostIo, SDHOST_DATA_SIGNATURE)
+
+/**
+  Test to see if this driver supports ControllerHandle. Any
+  ControllerHandle that has SdHostIoProtocol installed will be supported.
+
+  @param[in]  This                 Protocol instance pointer.
+  @param[in]  Controller           Handle of device to test.
+  @param[in]  RemainingDevicePath  Not used.
+
+  @retval     EFI_SUCCESS          This driver supports this device.
+  @retval     EFI_UNSUPPORTED      This driver does not support this device.
+
+**/
+EFI_STATUS
+EFIAPI
+SdControllerSupported (
+  IN EFI_DRIVER_BINDING_PROTOCOL     *This,
+  IN EFI_HANDLE                      Controller,
+  IN EFI_DEVICE_PATH_PROTOCOL        *RemainingDevicePath
+  );
+
+/**
+  Starting the SD Host Controller Driver.
+
+  @param[in]  This                 Protocol instance pointer.
+  @param[in]  Controller           Handle of device to test.
+  @param[in]  RemainingDevicePath  Not used.
+
+  @retval     EFI_SUCCESS          This driver supports this device.
+  @retval     EFI_UNSUPPORTED      This driver does not support this device.
+  @retval     EFI_DEVICE_ERROR     This driver cannot be started due to device Error.
+                                   EFI_OUT_OF_RESOURCES- Failed due to resource shortage.
+
+**/
+EFI_STATUS
+EFIAPI
+SdControllerStart (
+  IN EFI_DRIVER_BINDING_PROTOCOL     *This,
+  IN EFI_HANDLE                      Controller,
+  IN EFI_DEVICE_PATH_PROTOCOL        *RemainingDevicePath
+  );
+
+/**
+  Stop this driver on ControllerHandle. Support stoping any child handles
+  created by this driver.
+
+  @param[in]  This                 Protocol instance pointer.
+  @param[in]  Controller           Handle of device to stop driver on.
+  @param[in]  NumberOfChildren     Number of Children in the ChildHandleBuffer.
+  @param[in]  ChildHandleBuffer    List of handles for the children we need to stop.
+
+  @retval     EFI_SUCCESS
+  @retval     others
+
+**/
+EFI_STATUS
+EFIAPI
+SdControllerStop (
+  IN EFI_DRIVER_BINDING_PROTOCOL     *This,
+  IN EFI_HANDLE                      Controller,
+  IN UINTN                           NumberOfChildren,
+  IN EFI_HANDLE                      *ChildHandleBuffer
+  );
+
+/**
+  The main function used to send the command to the card inserted into the SD host slot.
+  It will assemble the arguments to set the command register and wait for the command
+  and transfer completed until timeout. Then it will read the response register to fill
+  the ResponseData.
+
+  @param[in]  This                  A pointer to the EFI_SD_HOST_IO_PROTOCOL instance.
+  @param[in]  CommandIndex          The command index to set the command index field of command register.
+  @param[in]  Argument              Command argument to set the argument field of command register.
+  @param[in]  DataType              TRANSFER_TYPE, indicates no data, data in or data out.
+  @param[in]  Buffer                Contains the data read from / write to the device.
+  @param[in]  BufferSize            The size of the buffer.
+  @param[in]  ResponseType          RESPONSE_TYPE.
+  @param[in]  TimeOut               Time out value in 1 ms unit.
+  @param[out] ResponseData          Depending on the ResponseType, such as CSD or card status.
+
+  @retval     EFI_SUCCESS
+  @retval     EFI_INVALID_PARAMETER
+  @retval     EFI_OUT_OF_RESOURCES
+  @retval     EFI_TIMEOUT
+  @retval     EFI_DEVICE_ERROR
+
+**/
+EFI_STATUS
+EFIAPI
+SendCommand (
+  IN   EFI_SD_HOST_IO_PROTOCOL    *This,
+  IN   UINT16                     CommandIndex,
+  IN   UINT32                     Argument,
+  IN   TRANSFER_TYPE              DataType,
+  IN   UINT8                      *Buffer, OPTIONAL
+  IN   UINT32                     BufferSize,
+  IN   RESPONSE_TYPE              ResponseType,
+  IN   UINT32                     TimeOut,
+  OUT  UINT32                     *ResponseData OPTIONAL
+  );
+
+/**
+  Set max clock frequency of the host, the actual frequency may not be the same as MaxFrequency.
+  It depends on the max frequency the host can support, divider, and host speed mode.
+
+  @param[in]  This                  A pointer to the EFI_SD_HOST_IO_PROTOCOL instance.
+  @param[in]  MaxFrequency          Max frequency in HZ.
+
+  @retval     EFI_SUCCESS
+  @retval     EFI_TIMEOUT
+
+**/
+EFI_STATUS
+EFIAPI
+SetClockFrequency (
+  IN  EFI_SD_HOST_IO_PROTOCOL    *This,
+  IN  UINT32                     MaxFrequencyInKHz
+  );
+
+/**
+  Set bus width of the host controller
+
+  @param[in]  This                  A pointer to the EFI_SD_HOST_IO_PROTOCOL instance.
+  @param[in]  BusWidth              Bus width in 1, 4, 8 bits.
+
+  @retval     EFI_SUCCESS
+  @retval     EFI_INVALID_PARAMETER
+
+**/
+EFI_STATUS
+EFIAPI
+SetBusWidth (
+  IN  EFI_SD_HOST_IO_PROTOCOL    *This,
+  IN  UINT32                     BusWidth
+  );
+
+/**
+  Set voltage which could supported by the host controller.
+  Support 0(Power off the host), 1.8V, 3.0V, 3.3V
+
+  @param[in]  This                  A pointer to the EFI_SD_HOST_IO_PROTOCOL instance.
+  @param[in]  Voltage               Units in 0.1 V.
+
+  @retval     EFI_SUCCESS
+  @retval     EFI_INVALID_PARAMETER
+
+**/
+EFI_STATUS
+EFIAPI
+SetHostVoltage (
+  IN  EFI_SD_HOST_IO_PROTOCOL    *This,
+  IN  UINT32                     Voltage
+  );
+
+/**
+  Reset the host controller.
+
+  @param[in]  This                  A pointer to the EFI_SD_HOST_IO_PROTOCOL instance.
+  @param[in]  ResetAll              TRUE to reset all.
+
+  @retval     EFI_SUCCESS
+  @retval     EFI_TIMEOUT
+
+**/
+EFI_STATUS
+EFIAPI
+ResetSdHost (
+  IN  EFI_SD_HOST_IO_PROTOCOL      *This,
+  IN  RESET_TYPE                   ResetType
+  );
+
+/**
+  Enable auto stop on the host controller.
+
+  @param[in]  This                  A pointer to the EFI_SD_HOST_IO_PROTOCOL instance.
+  @param[in]  Enable                TRUE to enable, FALSE to disable.
+
+  @retval     EFI_SUCCESS
+  @retval     EFI_TIMEOUT
+
+**/
+EFI_STATUS
+EFIAPI
+EnableAutoStopCmd (
+  IN  EFI_SD_HOST_IO_PROTOCOL    *This,
+  IN  BOOLEAN                    Enable
+  );
+
+/**
+  Find whether these is a card inserted into the slot. If so init the host.
+  If not, return EFI_NOT_FOUND.
+
+  @param[in]  This                  A pointer to the EFI_SD_HOST_IO_PROTOCOL instance.
+
+  @retval     EFI_SUCCESS
+  @retval     EFI_NOT_FOUND
+
+**/
+EFI_STATUS
+EFIAPI
+DetectCardAndInitHost (
+  IN  EFI_SD_HOST_IO_PROTOCOL    *This
+  );
+
+/**
+  Set the Block length on the host controller.
+
+  @param[in]  This                  A pointer to the EFI_SD_HOST_IO_PROTOCOL instance.
+  @param[in]  BlockLength           card supportes block length.
+
+  @retval     EFI_SUCCESS
+  @retval     EFI_TIMEOUT
+
+**/
+EFI_STATUS
+EFIAPI
+SetBlockLength (
+  IN  EFI_SD_HOST_IO_PROTOCOL    *This,
+  IN  UINT32                     BlockLength
+  );
+
+/**
+  Enable/Disable High Speed transfer mode
+
+  @param[in]  This                A pointer to the EFI_SD_HOST_IO_PROTOCOL instance.
+  @param[in]  Enable              TRUE to Enable, FALSE to Disable
+
+  @retval     EFI_SUCCESS
+
+**/
+EFI_STATUS
+EFIAPI
+SetHighSpeedMode (
+  IN  EFI_SD_HOST_IO_PROTOCOL    *This,
+  IN  BOOLEAN                    Enable
+  );
+
+EFI_STATUS
+EFIAPI
+SetDDRMode (
+  IN  EFI_SD_HOST_IO_PROTOCOL    *This,
+  IN  BOOLEAN                    Enable
+  );
+
+#endif
+
diff --git a/Silicon/BroxtonSoC/BroxtonSiPkg/SouthCluster/Sdio/Dxe/SD/SdControllerDxe/SdControllerDxe.inf b/Silicon/BroxtonSoC/BroxtonSiPkg/SouthCluster/Sdio/Dxe/SD/SdControllerDxe/SdControllerDxe.inf
new file mode 100644
index 0000000..499c9b7
--- /dev/null
+++ b/Silicon/BroxtonSoC/BroxtonSiPkg/SouthCluster/Sdio/Dxe/SD/SdControllerDxe/SdControllerDxe.inf
@@ -0,0 +1,59 @@
+## @file
+#  Component Description File For SdControllerDxe Module.
+#
+#  Copyright (c) 2013 - 2016, Intel Corporation. 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                    = 0x00010005
+  BASE_NAME                      = SdController
+  FILE_GUID                      = 90A330BD-6F89-4900-933A-C25EB4356348
+  MODULE_TYPE                    = UEFI_DRIVER
+  VERSION_STRING                 = 1.0
+  ENTRY_POINT                    = InitializeSdController
+
+#
+# The following information is for reference only and not required by the build tools.
+#
+#  VALID_ARCHITECTURES           = IA32 X64 IPF EBC
+#
+#  DRIVER_BINDING                = gSdControllerDriverBinding
+#  COMPONENT_NAME                = gSdControllerName
+#  COMPONENT_NAME2               = gSdControllerName2
+#
+
+[Sources]
+  SdController.c
+  SdController.h
+  ComponentName.c
+  ComponentName.h
+
+[Packages]
+  MdePkg/MdePkg.dec
+  MdeModulePkg/MdeModulePkg.dec
+  BroxtonSiPkg/BroxtonSiPkg.dec
+
+[LibraryClasses]
+  MemoryAllocationLib
+  BaseLib
+  UefiLib
+  UefiBootServicesTableLib
+  UefiDriverEntryPoint
+  BaseMemoryLib
+  DebugLib
+  PcdLib
+
+[Protocols]
+  gEfiPciIoProtocolGuid                         ## TO_START
+  gEfiSdHostIoProtocolGuid                      ## BY_START
+
+[FeaturePcd]
diff --git a/Silicon/BroxtonSoC/BroxtonSiPkg/SouthCluster/Sdio/Dxe/SD/SdMediaDeviceDxe/CEATA.c b/Silicon/BroxtonSoC/BroxtonSiPkg/SouthCluster/Sdio/Dxe/SD/SdMediaDeviceDxe/CEATA.c
new file mode 100644
index 0000000..cb7a1bb
--- /dev/null
+++ b/Silicon/BroxtonSoC/BroxtonSiPkg/SouthCluster/Sdio/Dxe/SD/SdMediaDeviceDxe/CEATA.c
@@ -0,0 +1,638 @@
+/** @file
+  CEATA specific functions implementation
+
+  Copyright (c) 2013 - 2016, Intel Corporation. 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 "SdMediaDevice.h"
+
+/**
+  Send RW_MULTIPLE_REGISTER command
+
+  @param[in]  CardData                   Pointer to CARD_DATA.
+  @param[in]  Address                    Register address.
+  @param[in]  ByteCount                  Buffer size.
+  @param[in]  Write                      TRUE means write, FALSE means read.
+  @param[in]  Buffer                     Buffer pointer.
+
+  @retval     EFI_SUCCESS                Success
+  @retval     EFI_DEVICE_ERROR           Hardware Error
+  @retval     EFI_INVALID_PARAMETER      Parameter is error
+  @retval     EFI_NO_MEDIA               No media
+  @retval     EFI_MEDIA_CHANGED          Media Change
+  @retval     EFI_BAD_BUFFER_SIZE        Buffer size is bad
+
+**/
+EFI_STATUS
+ReadWriteMultipleRegister (
+  IN  CARD_DATA   *CardData,
+  IN  UINT16      Address,
+  IN  UINT8       ByteCount,
+  IN  BOOLEAN     Write,
+  IN  UINT8       *Buffer
+  )
+{
+  EFI_STATUS                 Status;
+  UINT32                     Argument;
+
+  Status = EFI_SUCCESS;
+
+  if ((Address % 4 != 0) || (ByteCount % 4 != 0)) {
+    Status = EFI_INVALID_PARAMETER;
+    goto Exit;
+  }
+
+  Argument = (Address << 16) | ByteCount;
+  if (Write) {
+    Argument |= BIT31;
+  }
+
+  if (Write) {
+    CopyMem (CardData->AlignedBuffer, Buffer, ByteCount);
+
+    Status = SendCommand (
+               CardData,
+               RW_MULTIPLE_REGISTER,
+               Argument,
+               OutData,
+               CardData->AlignedBuffer,
+               ByteCount,
+               ResponseR1b,
+               TIMEOUT_DATA,
+               (UINT32 *) &(CardData->CardStatus)
+               );
+
+  } else {
+    Status = SendCommand (
+               CardData,
+               RW_MULTIPLE_REGISTER,
+               Argument,
+               InData,
+               CardData->AlignedBuffer,
+               ByteCount,
+               ResponseR1,
+               TIMEOUT_DATA,
+               (UINT32 *) &(CardData->CardStatus)
+               );
+
+    if (!EFI_ERROR (Status)) {
+      CopyMem (Buffer, CardData->AlignedBuffer, ByteCount);
+    }
+  }
+Exit:
+  return Status;
+}
+
+
+/**
+  Send ReadWriteMultipleBlock command with RW_MULTIPLE_REGISTER command
+
+  @param[in]  CardData                   Pointer to CARD_DATA.
+  @param[in]  DataUnitCount              Buffer size in 512 bytes unit.
+  @param[in]  Write                      TRUE means write, FALSE means read.
+  @param[in]  Buffer                     Buffer pointer.
+
+  @retval     EFI_SUCCESS                Success
+  @retval     EFI_DEVICE_ERROR           Hardware Error
+  @retval     EFI_INVALID_PARAMETER      Parameter is error
+  @retval     EFI_NO_MEDIA               No media
+  @retval     EFI_MEDIA_CHANGED          Media Change
+  @retval     EFI_BAD_BUFFER_SIZE        Buffer size is bad
+
+**/
+EFI_STATUS
+ReadWriteMultipleBlock (
+  IN  CARD_DATA   *CardData,
+  IN  UINT16      DataUnitCount,
+  IN  BOOLEAN     Write,
+  IN  UINT8       *Buffer
+  )
+{
+  EFI_STATUS                 Status;
+  EFI_SD_HOST_IO_PROTOCOL    *SdHostIo;
+  UINT32                     TransferLength;
+
+  Status = EFI_SUCCESS;
+  SdHostIo = CardData->SdHostIo;
+
+  TransferLength = DataUnitCount * DATA_UNIT_SIZE;
+  if (TransferLength > SdHostIo->HostCapability.BoundarySize) {
+    return EFI_INVALID_PARAMETER;
+  }
+
+  if (Write) {
+    CopyMem (CardData->AlignedBuffer, Buffer, TransferLength);
+
+    Status = SendCommand (
+               CardData,
+               RW_MULTIPLE_BLOCK,
+               (DataUnitCount | BIT31),
+               OutData,
+               CardData->AlignedBuffer,
+               TransferLength,
+               ResponseR1b,
+               TIMEOUT_DATA,
+               (UINT32 *) &(CardData->CardStatus)
+               );
+
+   } else {
+      Status = SendCommand (
+                 CardData,
+                 RW_MULTIPLE_BLOCK,
+                 DataUnitCount,
+                 InData,
+                 CardData->AlignedBuffer,
+                 TransferLength,
+                 ResponseR1,
+                 TIMEOUT_DATA,
+                 (UINT32 *) &(CardData->CardStatus)
+                 );
+
+      if (!EFI_ERROR (Status)) {
+        CopyMem (Buffer, CardData->AlignedBuffer, TransferLength);
+      }
+  }
+
+  return Status;
+}
+
+
+/**
+  Send software reset
+
+  @param[in]  CardData                   Pointer to CARD_DATA.
+
+  @retval     EFI_SUCCESS                Success
+  @retval     EFI_DEVICE_ERROR           Hardware Error
+  @retval     EFI_INVALID_PARAMETER      Parameter is error
+  @retval     EFI_NO_MEDIA               No media
+  @retval     EFI_MEDIA_CHANGED          Media Change
+  @retval     EFI_BAD_BUFFER_SIZE        Buffer size is bad
+
+**/
+EFI_STATUS
+SoftwareReset (
+  IN  CARD_DATA    *CardData
+  )
+{
+  EFI_STATUS    Status;
+  UINT8         Data;
+  UINT32        TimeOut;
+
+  Data = BIT2;
+
+  Status = FastIO (CardData, Reg_Control, &Data, TRUE);
+  if (EFI_ERROR (Status)) {
+    goto Exit;
+  }
+
+  TimeOut = 5 * 1000;
+
+  do {
+    gBS->Stall (1 * 1000);
+    Status = FastIO (CardData, Reg_Control, &Data, FALSE);
+    if (EFI_ERROR (Status)) {
+      goto Exit;
+    }
+
+    if ((Data & BIT2) == BIT2) {
+      break;
+    }
+
+    TimeOut--;
+  } while (TimeOut > 0);
+
+  if (TimeOut == 0) {
+   Status = EFI_TIMEOUT;
+   goto Exit;
+  }
+
+  Data &= ~BIT2;
+  Status = FastIO (CardData, Reg_Control, &Data, TRUE);
+
+  TimeOut = 5 * 1000;
+
+  do {
+    gBS->Stall (1 * 1000);
+    Status = FastIO (CardData, Reg_Control, &Data, FALSE);
+    if (EFI_ERROR (Status)) {
+      goto Exit;
+    }
+
+    if ((Data & BIT2) != BIT2) {
+      break;
+    }
+
+    TimeOut--;
+  } while (TimeOut > 0);
+
+  if (TimeOut == 0) {
+   Status = EFI_TIMEOUT;
+   goto Exit;
+  }
+
+Exit:
+  return Status;
+}
+
+
+/**
+  SendATACommand specificed in Taskfile
+
+  @param[in]  CardData                   Pointer to CARD_DATA.
+  @param[in]  TaskFile                   Pointer to TASK_FILE.
+  @param[in]  Write                      TRUE means write, FALSE means read.
+  @param[in]  Buffer                     If NULL, means no data transfer, neither read nor write.
+  @param[in]  SectorCount                Buffer size in 512 bytes unit.
+
+  @retval     EFI_SUCCESS                Success
+  @retval     EFI_DEVICE_ERROR           Hardware Error
+  @retval     EFI_INVALID_PARAMETER      Parameter is error
+  @retval     EFI_NO_MEDIA               No media
+  @retval     EFI_MEDIA_CHANGED          Media Change
+  @retval     EFI_BAD_BUFFER_SIZE        Buffer size is bad
+
+**/
+EFI_STATUS
+SendATACommand (
+  IN  CARD_DATA   *CardData,
+  IN  TASK_FILE   *TaskFile,
+  IN  BOOLEAN     Write,
+  IN  UINT8       *Buffer,
+  IN  UINT16      SectorCount
+  )
+{
+  EFI_STATUS                 Status;
+  UINT8                      Data;
+  UINT32                     TimeOut;
+
+  //
+  // Write register
+  //
+  Status = ReadWriteMultipleRegister (
+             CardData,
+             0,
+             sizeof (TASK_FILE),
+             TRUE,
+             (UINT8 *) TaskFile
+             );
+
+  if (EFI_ERROR (Status)) {
+    DEBUG ((EFI_D_ERROR, "ReadWriteMultipleRegister 0x%x\n", Status));
+    goto Exit;
+  }
+
+  TimeOut = 5000;
+  do {
+    gBS->Stall (1 * 1000);
+    Data = 0;
+    Status = FastIO (
+               CardData,
+               Reg_Command_Status,
+               &Data,
+               FALSE
+               );
+
+    if (EFI_ERROR (Status)) {
+      return Status;
+    }
+
+    if (((Data & BIT7) == 0) && ((Data & BIT6) == BIT6)) {
+      break;
+    }
+
+    TimeOut --;
+  } while (TimeOut > 0);
+
+  if (TimeOut == 0) {
+    DEBUG ((EFI_D_ERROR, "ReadWriteMultipleRegister FastIO EFI_TIMEOUT 0x%x\n", Data));
+    Status = EFI_TIMEOUT;
+    goto Exit;
+  }
+
+  if (Buffer != NULL) {
+    Status = ReadWriteMultipleBlock (
+               CardData,
+               SectorCount,
+               Write,
+               (UINT8 *) Buffer
+               );
+
+    if (EFI_ERROR (Status)) {
+      DEBUG ((EFI_D_ERROR, "ReadWriteMultipleBlock EFI_TIMEOUT 0x%x\n", Status));
+      goto Exit;
+    }
+
+    TimeOut = 5 * 1000;
+    do {
+      gBS->Stall (1 * 1000);
+      Data = 0;
+      Status = FastIO (
+                 CardData,
+                 Reg_Command_Status,
+                 &Data,
+                 FALSE
+                 );
+
+      if (EFI_ERROR (Status)) {
+        return Status;
+      }
+
+      if (((Data & BIT7) == 0) && ((Data & BIT3) == 0)) {
+        break;
+      }
+
+      TimeOut --;
+    } while (TimeOut > 0);
+    if (TimeOut == 0) {
+      DEBUG ((EFI_D_ERROR, "ReadWriteMultipleBlock FastIO EFI_TIMEOUT 0x%x\n", Data));
+      Status = EFI_TIMEOUT;
+      goto Exit;
+    }
+
+    if (((Data & BIT6) == BIT6) && (Data & BIT0) == 0) {
+      Status = EFI_SUCCESS;
+    } else {
+      Status = EFI_DEVICE_ERROR;
+    }
+  }
+
+Exit:
+  if (EFI_ERROR (Status)) {
+    SoftwareReset (CardData);
+  }
+
+  return Status;
+}
+
+
+/**
+  IDENTIFY_DEVICE command
+
+  @param[in]  CardData                   Pointer to CARD_DATA.
+
+  @retval     EFI_SUCCESS                Success
+  @retval     EFI_DEVICE_ERROR           Hardware Error
+  @retval     EFI_INVALID_PARAMETER      Parameter is error
+  @retval     EFI_NO_MEDIA               No media
+  @retval     EFI_MEDIA_CHANGED          Media Change
+  @retval     EFI_BAD_BUFFER_SIZE        Buffer size is bad
+
+**/
+EFI_STATUS
+IndentifyDevice (
+  IN  CARD_DATA    *CardData
+  )
+{
+  EFI_STATUS                 Status;
+
+  ZeroMem (&CardData->TaskFile, sizeof (TASK_FILE));
+
+  //
+  // The host only supports nIEN = 0
+  //
+  CardData->TaskFile.Command_Status = IDENTIFY_DEVICE;
+  Status = SendATACommand (
+             CardData,
+             &CardData->TaskFile,
+             FALSE,
+             (UINT8 *) &(CardData->IndentifyDeviceData),
+             1
+             );
+
+  return Status;
+}
+
+
+/**
+  FLUSH_CACHE_EXT command
+
+  @param[in]  CardData                   Pointer to CARD_DATA.
+
+  @retval     EFI_SUCCESS                Success
+  @retval     EFI_DEVICE_ERROR           Hardware Error
+  @retval     EFI_INVALID_PARAMETER      Parameter is error
+  @retval     EFI_NO_MEDIA               No media
+  @retval     EFI_MEDIA_CHANGED          Media Change
+  @retval     EFI_BAD_BUFFER_SIZE        Buffer size is bad
+
+**/
+EFI_STATUS
+FlushCache (
+  IN  CARD_DATA    *CardData
+  )
+{
+
+  return EFI_SUCCESS;
+}
+
+
+/**
+  STANDBY_IMMEDIATE command
+
+  @param[in]  CardData                   Pointer to CARD_DATA.
+
+  @retval     EFI_SUCCESS                Success
+  @retval     EFI_DEVICE_ERROR           Hardware Error
+  @retval     EFI_INVALID_PARAMETER      Parameter is error
+  @retval     EFI_NO_MEDIA               No media
+  @retval     EFI_MEDIA_CHANGED          Media Change
+  @retval     EFI_BAD_BUFFER_SIZE        Buffer size is bad
+
+**/
+EFI_STATUS
+StandByImmediate (
+  IN  CARD_DATA    *CardData
+  )
+{
+  EFI_STATUS  Status;
+
+  ZeroMem (&CardData->TaskFile, sizeof (TASK_FILE));
+
+  //
+  // The host only supports nIEN = 0
+  //
+  CardData->TaskFile.Command_Status = STANDBY_IMMEDIATE;
+  Status = SendATACommand (
+             CardData,
+             &CardData->TaskFile,
+             FALSE,
+             NULL,
+             0
+             );
+
+  return Status;
+}
+
+
+/**
+  READ_DMA_EXT command
+
+  @param[in]  CardData                   Pointer to CARD_DATA.
+  @param[in]  LBA                        The starting logical block address to read from on the device.
+  @param[in]  Buffer                     A pointer to the destination buffer for the data. The caller
+                                         is responsible for either having implicit or explicit ownership
+                                         of the buffer.
+  @param[in]  SectorCount                Size in 512 bytes unit.
+
+  @retval     EFI_SUCCESS                Success
+  @retval     EFI_DEVICE_ERROR           Hardware Error
+  @retval     EFI_INVALID_PARAMETER      Parameter is error
+  @retval     EFI_NO_MEDIA               No media
+  @retval     EFI_MEDIA_CHANGED          Media Change
+  @retval     EFI_BAD_BUFFER_SIZE        Buffer size is bad
+
+**/
+EFI_STATUS
+ReadDMAExt (
+  IN  CARD_DATA   *CardData,
+  IN  EFI_LBA     LBA,
+  IN  UINT8       *Buffer,
+  IN  UINT16      SectorCount
+  )
+{
+  EFI_STATUS  Status;
+
+  ZeroMem (&CardData->TaskFile, sizeof (TASK_FILE));
+
+  //
+  // The host only supports nIEN = 0
+  //
+  CardData->TaskFile.Command_Status = READ_DMA_EXT;
+
+  CardData->TaskFile.SectorCount     = (UINT8) SectorCount;
+  CardData->TaskFile.SectorCount_Exp = (UINT8) (SectorCount >> 8);
+
+  CardData->TaskFile.LBALow          = (UINT8) LBA;
+  CardData->TaskFile.LBAMid          = (UINT8) RShiftU64 (LBA, 8);
+  CardData->TaskFile.LBAHigh         = (UINT8) RShiftU64 (LBA, 16);
+
+  CardData->TaskFile.LBALow_Exp      = (UINT8) RShiftU64 (LBA, 24);
+  CardData->TaskFile.LBAMid_Exp      = (UINT8) RShiftU64 (LBA, 32);
+  CardData->TaskFile.LBAHigh_Exp     = (UINT8) RShiftU64 (LBA, 40);
+
+  Status = SendATACommand (
+             CardData,
+             &CardData->TaskFile,
+             FALSE,
+             Buffer,
+             SectorCount
+             );
+
+  return Status;
+}
+
+
+/**
+  WRITE_DMA_EXT command
+
+  @param[in]  CardData                   Pointer to CARD_DATA.
+  @param[in]  LBA                        The starting logical block address to read from on the device.
+  @param[in]  Buffer                     A pointer to the destination buffer for the data. The caller
+                                         is responsible for either having implicit or explicit ownership
+                                         of the buffer.
+  @param[in]  SectorCount                Size in 512 bytes unit.
+
+  @retval     EFI_SUCCESS                Success
+  @retval     EFI_DEVICE_ERROR           Hardware Error
+  @retval     EFI_INVALID_PARAMETER      Parameter is error
+  @retval     EFI_NO_MEDIA               No media
+  @retval     EFI_MEDIA_CHANGED          Media Change
+  @retval     EFI_BAD_BUFFER_SIZE        Buffer size is bad
+
+**/
+EFI_STATUS
+WriteDMAExt (
+  IN  CARD_DATA   *CardData,
+  IN  EFI_LBA     LBA,
+  IN  UINT8       *Buffer,
+  IN  UINT16      SectorCount
+  )
+{
+  EFI_STATUS  Status;
+
+  ZeroMem (&CardData->TaskFile, sizeof (TASK_FILE));
+
+  //
+  // The host only supports nIEN = 0
+  //
+  CardData->TaskFile.Command_Status = WRITE_DMA_EXT;
+
+  CardData->TaskFile.SectorCount     = (UINT8) SectorCount;
+  CardData->TaskFile.SectorCount_Exp = (UINT8) (SectorCount >> 8);
+
+  CardData->TaskFile.LBALow          = (UINT8) LBA;
+  CardData->TaskFile.LBAMid          = (UINT8) RShiftU64 (LBA, 8);
+  CardData->TaskFile.LBAHigh         = (UINT8) RShiftU64 (LBA, 16);
+
+  CardData->TaskFile.LBALow_Exp      = (UINT8) RShiftU64 (LBA, 24);
+  CardData->TaskFile.LBAMid_Exp      = (UINT8) RShiftU64 (LBA, 32);
+  CardData->TaskFile.LBAHigh_Exp     = (UINT8) RShiftU64 (LBA, 40);
+
+  Status = SendATACommand (
+             CardData,
+             &CardData->TaskFile,
+             TRUE,
+             Buffer,
+             SectorCount
+             );
+
+  return Status;
+
+}
+
+
+/**
+  Judge whether it is CE-ATA device or not.
+
+  @param[in]  CardData             Pointer to CARD_DATA.
+
+  @retval     TRUE
+  @retval     FALSE
+
+**/
+BOOLEAN
+IsCEATADevice (
+  IN  CARD_DATA    *CardData
+  )
+{
+  EFI_STATUS                 Status;
+
+  Status = ReadWriteMultipleRegister (
+             CardData,
+             0,
+             sizeof (TASK_FILE),
+             FALSE,
+             (UINT8 *) &CardData->TaskFile
+             );
+
+  if (EFI_ERROR (Status)) {
+    //
+    // To bring back the normal MMC card to work
+    //
+    CardData->SdHostIo->ResetSdHost (CardData->SdHostIo, Reset_DAT_CMD);
+    return FALSE;
+  }
+
+  if (CardData->TaskFile.LBAMid == CE_ATA_SIG_CE &&
+      CardData->TaskFile.LBAHigh == CE_ATA_SIG_AA
+    ) {
+    //
+    // Disable Auto CMD for CE-ATA
+    //
+    CardData->SdHostIo->EnableAutoStopCmd (CardData->SdHostIo, FALSE);
+    return TRUE;
+  }
+
+  return FALSE;
+}
+
diff --git a/Silicon/BroxtonSoC/BroxtonSiPkg/SouthCluster/Sdio/Dxe/SD/SdMediaDeviceDxe/CEATABlockIo.c b/Silicon/BroxtonSoC/BroxtonSiPkg/SouthCluster/Sdio/Dxe/SD/SdMediaDeviceDxe/CEATABlockIo.c
new file mode 100644
index 0000000..55fd085
--- /dev/null
+++ b/Silicon/BroxtonSoC/BroxtonSiPkg/SouthCluster/Sdio/Dxe/SD/SdMediaDeviceDxe/CEATABlockIo.c
@@ -0,0 +1,384 @@
+/** @file
+  Block I/O protocol for CE-ATA device
+
+  Copyright (c) 2013 - 2016, Intel Corporation. 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 "SdMediaDevice.h"
+
+
+/**
+  Implements EFI_BLOCK_IO_PROTOCOL.Reset() function.
+
+  @param[in]  This                   The EFI_BLOCK_IO_PROTOCOL instance.
+  @param[in]  ExtendedVerification   Indicates that the driver may perform a more exhaustive.
+                                     verification operation of the device during reset.
+                                     (This parameter is ingored in this driver.)
+
+  @retval     EFI_SUCCESS            Success
+
+**/
+EFI_STATUS
+EFIAPI
+CEATABlockReset (
+  IN  EFI_BLOCK_IO_PROTOCOL   *This,
+  IN  BOOLEAN                 ExtendedVerification
+  )
+{
+  EFI_STATUS                 Status;
+  CARD_DATA                  *CardData;
+  EFI_SD_HOST_IO_PROTOCOL    *SdHostIo;
+
+  CardData = CARD_DATA_FROM_THIS (This);
+  SdHostIo = CardData->SdHostIo;
+
+  if (!ExtendedVerification) {
+    Status = SoftwareReset (CardData);
+  } else {
+    Status = SdHostIo->ResetSdHost (SdHostIo, Reset_DAT_CMD);
+    if (EFI_ERROR (Status)) {
+      DEBUG ((EFI_D_ERROR, "CEATABlockReset: Fail to ResetSDHost\n" ));
+      return Status;
+    }
+    Status = MMCSDCardInit (CardData);
+  }
+
+  return Status;
+}
+
+
+/**
+  Implements EFI_BLOCK_IO_PROTOCOL.ReadBlocks() function.
+
+  @param[in]  This                       The EFI_BLOCK_IO_PROTOCOL instance.
+  @param[in]  MediaId                    The media id that the write request is for.
+  @param[in]  LBA                        The starting logical block address to read from on the device.
+                                         The caller is responsible for writing to only legitimate locations.
+  @param[in]  BufferSize                 The size of the Buffer in bytes. This must be a multiple of the
+                                         intrinsic block size of the device.
+  @param[out] Buffer                     A pointer to the destination buffer for the data. The caller
+                                         is responsible for either having implicit or explicit ownership
+                                         of the buffer.
+
+  @retval     EFI_SUCCESS                Success
+  @retval     EFI_DEVICE_ERROR           Hardware Error
+  @retval     EFI_INVALID_PARAMETER      Parameter is error
+  @retval     EFI_NO_MEDIA               No media
+  @retval     EFI_MEDIA_CHANGED          Media Change
+  @retval     EFI_BAD_BUFFER_SIZE        Buffer size is bad
+
+**/
+EFI_STATUS
+EFIAPI
+CEATABlockReadBlocks (
+  IN  EFI_BLOCK_IO_PROTOCOL   *This,
+  IN  UINT32                  MediaId,
+  IN  EFI_LBA                 LBA,
+  IN  UINTN                   BufferSize,
+  OUT VOID                    *Buffer
+  )
+{
+  EFI_STATUS                  Status;
+  CARD_DATA                   *CardData;
+  UINT32                      TransferSize;
+  UINT8                       *pBuf;
+  UINT32                      Index;
+  UINT64                      Address;
+  UINT32                      Remainder;
+  UINT64                      CEATALBA;
+  UINT32                      BoundarySize;
+
+  Status       = EFI_SUCCESS;
+  CardData     = CARD_DATA_FROM_THIS (This);
+  pBuf         = Buffer;
+  Index        = 0;
+  Address      = MultU64x32 (LBA, CardData->BlockIoMedia.BlockSize);
+  BoundarySize = CardData->SdHostIo->HostCapability.BoundarySize;
+
+  if (!Buffer) {
+    Status = EFI_INVALID_PARAMETER;
+    DEBUG ((EFI_D_ERROR, "CEATABlockReadBlocks:Invalid parameter\n" ));
+    goto Exit;
+  }
+
+  if (MediaId != CardData->BlockIoMedia.MediaId) {
+    Status = EFI_MEDIA_CHANGED;
+    DEBUG ((EFI_D_ERROR, "CEATABlockReadBlocks:Media changed\n" ));
+    goto Exit;
+  }
+
+  if ((BufferSize % CardData->BlockIoMedia.BlockSize) != 0) {
+    Status = EFI_BAD_BUFFER_SIZE;
+    DEBUG ((EFI_D_ERROR, "CEATABlockReadBlocks:Bad buffer size\n" ));
+    goto Exit;
+  }
+
+  if (BufferSize == 0) {
+    Status = EFI_SUCCESS;
+    goto Exit;
+  }
+
+  if ((Address + BufferSize) > MultU64x32 (CardData->BlockIoMedia.LastBlock + 1, CardData->BlockIoMedia.BlockSize)) {
+    Status = EFI_INVALID_PARAMETER;
+    DEBUG ((EFI_D_ERROR, "CEATABlockReadBlocks:Invalid parameter\n" ));
+    goto Exit;
+  }
+
+  do {
+    if (BufferSize < BoundarySize) {
+      TransferSize = (UINT32) BufferSize;
+    } else {
+      TransferSize = BoundarySize;
+    }
+
+    Address += Index * TransferSize;
+    CEATALBA = DivU64x32Remainder (Address, DATA_UNIT_SIZE, &Remainder);
+    ASSERT(Remainder == 0);
+
+    Status = ReadDMAExt (
+               CardData,
+               CEATALBA,
+               pBuf,
+               (UINT16) (TransferSize / DATA_UNIT_SIZE)
+               );
+
+    if (EFI_ERROR (Status)) {
+      DEBUG ((EFI_D_ERROR, "Read Failed at 0x%x, Index %d, Size 0x%x\n", Address, Index, TransferSize));
+      This->Reset (This, TRUE);
+      goto Exit;
+    }
+
+    BufferSize -= TransferSize;
+    pBuf += TransferSize;
+    Index ++;
+  } while (BufferSize != 0);
+
+Exit:
+  return Status;
+}
+
+
+/**
+  Implements EFI_BLOCK_IO_PROTOCOL.WriteBlocks() function.
+
+  @param[in]  This                       The EFI_BLOCK_IO_PROTOCOL instance.
+  @param[in]  MediaId                    The media id that the write request is for.
+  @param[in]  LBA                        The starting logical block address to read from on the device.
+                                         The caller is responsible for writing to only legitimate locations.
+  @param[in]  BufferSize                 The size of the Buffer in bytes. This must be a multiple of the
+                                         intrinsic block size of the device.
+  @param[in]  Buffer                     A pointer to the destination buffer for the data. The caller
+                                         is responsible for either having implicit or explicit ownership
+                                         of the buffer.
+
+  @retval     EFI_SUCCESS                Success
+  @retval     EFI_DEVICE_ERROR           Hardware Error
+  @retval     EFI_INVALID_PARAMETER      Parameter is error
+  @retval     EFI_NO_MEDIA               No media
+  @retval     EFI_MEDIA_CHANGED          Media Change
+  @retval     EFI_BAD_BUFFER_SIZE        Buffer size is bad
+
+**/
+EFI_STATUS
+EFIAPI
+CEATABlockWriteBlocks (
+  IN  EFI_BLOCK_IO_PROTOCOL   *This,
+  IN  UINT32                  MediaId,
+  IN  EFI_LBA                 LBA,
+  IN  UINTN                   BufferSize,
+  IN  VOID                    *Buffer
+  )
+{
+  EFI_STATUS                  Status;
+  CARD_DATA                   *CardData;
+  UINT32                      TransferSize;
+  UINT8                       *pBuf;
+  UINT32                      Index;
+  UINT64                      Address;
+  UINT32                      Remainder;
+  UINT64                      CEATALBA;
+  UINT32                      BoundarySize;
+
+  Status       = EFI_SUCCESS;
+  CardData     = CARD_DATA_FROM_THIS (This);
+  pBuf         = Buffer;
+  Index        = 0;
+  Address      = MultU64x32 (LBA, CardData->BlockIoMedia.BlockSize);
+  BoundarySize = CardData->SdHostIo->HostCapability.BoundarySize;
+
+  if (!Buffer) {
+    Status = EFI_INVALID_PARAMETER;
+    goto Exit;
+  }
+
+  if (MediaId != CardData->BlockIoMedia.MediaId) {
+    Status = EFI_MEDIA_CHANGED;
+    goto Exit;
+  }
+
+  if ((BufferSize % CardData->BlockIoMedia.BlockSize) != 0) {
+    Status = EFI_BAD_BUFFER_SIZE;
+    goto Exit;
+  }
+
+  if (BufferSize == 0) {
+    Status = EFI_SUCCESS;
+    goto Exit;
+  }
+
+  if (CardData->BlockIoMedia.ReadOnly) {
+    Status = EFI_WRITE_PROTECTED;
+    goto Exit;
+  }
+
+  if ((Address + BufferSize) > MultU64x32 (CardData->BlockIoMedia.LastBlock + 1, CardData->BlockIoMedia.BlockSize)) {
+    Status = EFI_INVALID_PARAMETER;
+    goto Exit;
+  }
+
+  CardData->NeedFlush = TRUE;
+
+  do {
+    if (BufferSize < BoundarySize) {
+      TransferSize = (UINT32) BufferSize;
+    } else {
+      TransferSize = BoundarySize;
+    }
+
+    Address += Index * TransferSize;
+    CEATALBA = DivU64x32Remainder (Address, DATA_UNIT_SIZE, &Remainder);
+    ASSERT (Remainder == 0);
+
+    Status = WriteDMAExt (
+               CardData,
+               CEATALBA,
+               pBuf,
+               (UINT16) (TransferSize / DATA_UNIT_SIZE)
+               );
+
+    if (EFI_ERROR (Status)) {
+      DEBUG ((EFI_D_ERROR, "Write Failed at 0x%x, Index %d, Size 0x%x\n", Address, Index, TransferSize));
+      This->Reset (This, TRUE);
+      goto Exit;
+    }
+
+    BufferSize -= TransferSize;
+    pBuf += TransferSize;
+    Index ++;
+  } while (BufferSize != 0);
+
+Exit:
+  return Status;
+}
+
+
+/**
+  Implements EFI_BLOCK_IO_PROTOCOL.FlushBlocks() function.
+  (In this driver, this function just returns EFI_SUCCESS.)
+
+  @param[in]  This                   The EFI_BLOCK_IO_PROTOCOL instance.
+
+  @retval     EFI_SUCCESS
+  @retval     Others
+
+**/
+EFI_STATUS
+EFIAPI
+CEATABlockFlushBlocks (
+  IN  EFI_BLOCK_IO_PROTOCOL   *This
+  )
+{
+
+  CARD_DATA                   *CardData;
+
+  CardData = CARD_DATA_FROM_THIS (This);
+
+  if (CardData->NeedFlush) {
+    CardData->NeedFlush = FALSE;
+    FlushCache (CardData);
+  }
+
+  return EFI_SUCCESS;
+}
+
+
+/**
+  CEATA card BlockIo init function.
+
+  @param[in]  CardData               Pointer to CARD_DATA.
+
+  @retval     EFI_SUCCESS
+  @retval     Others
+
+**/
+EFI_STATUS
+CEATABlockIoInit (
+  IN  CARD_DATA    *CardData
+  )
+{
+  EFI_STATUS   Status;
+  UINT64       MaxSize;
+  UINT32       Remainder;
+
+  //
+  // BlockIO protocol
+  //
+  CardData->BlockIo.Revision    = EFI_BLOCK_IO_PROTOCOL_REVISION;
+  CardData->BlockIo.Media       = &(CardData->BlockIoMedia);
+  CardData->BlockIo.Reset       = CEATABlockReset;
+  CardData->BlockIo.ReadBlocks  = CEATABlockReadBlocks ;
+  CardData->BlockIo.WriteBlocks = CEATABlockWriteBlocks;
+  CardData->BlockIo.FlushBlocks = CEATABlockFlushBlocks;
+
+  CardData->BlockIoMedia.MediaId          = 0;
+  CardData->BlockIoMedia.RemovableMedia   = FALSE;
+  CardData->BlockIoMedia.MediaPresent     = TRUE;
+  CardData->BlockIoMedia.LogicalPartition = FALSE;
+
+  if (CardData->CSDRegister.PERM_WRITE_PROTECT | CardData->CSDRegister.TMP_WRITE_PROTECT) {
+    CardData->BlockIoMedia.ReadOnly       = TRUE;
+  } else {
+    CardData->BlockIoMedia.ReadOnly       = FALSE;
+  }
+
+  CardData->BlockIoMedia.WriteCaching     = FALSE;
+  CardData->BlockIoMedia.IoAlign          = 1;
+
+  Status = IndentifyDevice (CardData);
+  if (EFI_ERROR (Status)) {
+   goto Exit;
+  }
+
+  //
+  //Some device does not support this feature
+  //
+  if (CardData->IndentifyDeviceData.MaxWritesPerAddress == 0) {
+    CardData->BlockIoMedia.ReadOnly       = TRUE;
+  }
+
+  CardData->BlockIoMedia.BlockSize        = (1 << CardData->IndentifyDeviceData.Sectorsize);
+  ASSERT (CardData->BlockIoMedia.BlockSize >= 12);
+
+
+  MaxSize = *(UINT64 *) (CardData->IndentifyDeviceData.MaximumLBA);
+  MaxSize = MultU64x32 (MaxSize, 512);
+
+  Remainder = 0;
+  CardData->BlockNumber = DivU64x32Remainder (MaxSize, CardData->BlockIoMedia.BlockSize, &Remainder);
+  ASSERT (Remainder == 0);
+
+  CardData->BlockIoMedia.LastBlock = (EFI_LBA) (CardData->BlockNumber - 1);
+
+Exit:
+  return Status;
+}
+
diff --git a/Silicon/BroxtonSoC/BroxtonSiPkg/SouthCluster/Sdio/Dxe/SD/SdMediaDeviceDxe/ComponentName.c b/Silicon/BroxtonSoC/BroxtonSiPkg/SouthCluster/Sdio/Dxe/SD/SdMediaDeviceDxe/ComponentName.c
new file mode 100644
index 0000000..15fdaf6
--- /dev/null
+++ b/Silicon/BroxtonSoC/BroxtonSiPkg/SouthCluster/Sdio/Dxe/SD/SdMediaDeviceDxe/ComponentName.c
@@ -0,0 +1,219 @@
+/** @file
+  UEFI Component Name(2) protocol implementation for SD media device driver.
+
+  Copyright (c) 2013 - 2016, Intel Corporation. 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 "SdMediaDevice.h"
+
+//
+// EFI Component Name Protocol
+//
+GLOBAL_REMOVE_IF_UNREFERENCED EFI_COMPONENT_NAME_PROTOCOL  gSdMediaDeviceName = {
+  SdMediaDeviceGetDriverName,
+  SdMediaDeviceGetControllerName,
+  "eng"
+};
+
+//
+// EFI Component Name 2 Protocol
+//
+GLOBAL_REMOVE_IF_UNREFERENCED EFI_COMPONENT_NAME2_PROTOCOL gSdMediaDeviceName2 = {
+  (EFI_COMPONENT_NAME2_GET_DRIVER_NAME) SdMediaDeviceGetDriverName,
+  (EFI_COMPONENT_NAME2_GET_CONTROLLER_NAME) SdMediaDeviceGetControllerName,
+  "en"
+};
+
+
+GLOBAL_REMOVE_IF_UNREFERENCED EFI_UNICODE_STRING_TABLE mSdMediaDeviceDriverNameTable[] = {
+  { "eng;en", L"UEFI MMC/SD Media Device Driver" },
+  { NULL, NULL }
+};
+
+
+//
+// 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[in]  This                    A pointer to the EFI_COMPONENT_NAME2_PROTOCOL or
+                                      EFI_COMPONENT_NAME_PROTOCOL instance.
+
+  @param[in]  Language                A pointer to a Null-terminated ASCII string
+                                      array indicating the language. This is the
+                                      language of the driver name that the caller is
+                                      requesting, and it must match one of the
+                                      languages specified in SupportedLanguages. The
+                                      number of languages supported by a driver is up
+                                      to the driver writer. Language is specified
+                                      in RFC 3066 or ISO 639-2 language code format.
+
+  @param[out] DriverName              A pointer to the Unicode string to return.
+                                      This Unicode string is the name of the
+                                      driver specified by This in the language
+                                      specified by Language.
+
+  @retval     EFI_SUCCESS             The Unicode string for the Driver specified by
+                                      This and the language specified by Language was
+                                      returned in DriverName.
+
+  @retval     EFI_INVALID_PARAMETER   Language is NULL.
+
+  @retval     EFI_INVALID_PARAMETER   DriverName is NULL.
+
+  @retval     EFI_UNSUPPORTED         The driver specified by This does not support
+                                      the language specified by Language.
+
+**/
+EFI_STATUS
+EFIAPI
+SdMediaDeviceGetDriverName (
+  IN  EFI_COMPONENT_NAME_PROTOCOL  *This,
+  IN  CHAR8                        *Language,
+  OUT CHAR16                       **DriverName
+  )
+{
+  return LookupUnicodeString2 (
+           Language,
+           This->SupportedLanguages,
+           mSdMediaDeviceDriverNameTable,
+           DriverName,
+           (BOOLEAN) (This == &gSdMediaDeviceName)
+           );
+}
+
+
+/**
+  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[in]  This                  A pointer to the EFI_COMPONENT_NAME2_PROTOCOL or
+                                    EFI_COMPONENT_NAME_PROTOCOL instance.
+
+  @param[in]  ControllerHandle      The handle of a controller that the driver
+                                    specified by This is managing.  This handle
+                                    specifies the controller whose name is to be
+                                    returned.
+
+  @param[in]  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[in]  Language              A pointer to a Null-terminated ASCII string
+                                    array indicating the language.  This is the
+                                    language of the driver name that the caller is
+                                    requesting, and it must match one of the
+                                    languages specified in SupportedLanguages. The
+                                    number of languages supported by a driver is up
+                                    to the driver writer. Language is specified in
+                                    RFC 3066 or ISO 639-2 language code format.
+
+  @param[out] ControllerName        A pointer to the Unicode string to return.
+                                    This Unicode string is the name of the
+                                    controller specified by ControllerHandle and
+                                    ChildHandle in the language specified by
+                                    Language from the point of view of the driver
+                                    specified by This.
+
+  @retval     EFI_SUCCESS           The Unicode string for the user readable name in
+                                    the language specified by Language for the
+                                    driver specified by This was returned in
+                                    DriverName.
+
+  @retval     EFI_INVALID_PARAMETER ControllerHandle is not a valid EFI_HANDLE.
+
+  @retval     EFI_INVALID_PARAMETER ChildHandle is not NULL and it is not a valid
+                                    EFI_HANDLE.
+
+  @retval     EFI_INVALID_PARAMETER Language is NULL.
+
+  @retval     EFI_INVALID_PARAMETER ControllerName is NULL.
+
+  @retval     EFI_UNSUPPORTED       The driver specified by This is not currently
+                                    managing the controller specified by
+                                    ControllerHandle and ChildHandle.
+
+  @retval     EFI_UNSUPPORTED       The driver specified by This does not support
+                                    the language specified by Language.
+
+**/
+EFI_STATUS
+EFIAPI
+SdMediaDeviceGetControllerName (
+  IN  EFI_COMPONENT_NAME_PROTOCOL                     *This,
+  IN  EFI_HANDLE                                      ControllerHandle,
+  IN  EFI_HANDLE                                      ChildHandle        OPTIONAL,
+  IN  CHAR8                                           *Language,
+  OUT CHAR16                                          **ControllerName
+  )
+{
+  EFI_STATUS               Status;
+  EFI_BLOCK_IO_PROTOCOL    *BlockIo;
+  CARD_DATA                *CardData;
+
+  //
+  // This is a device driver, so ChildHandle must be NULL.
+  //
+  if (ChildHandle != NULL) {
+    return EFI_UNSUPPORTED;
+  }
+
+  //
+  // Get the device context
+  //
+  Status = gBS->OpenProtocol (
+                  ControllerHandle,
+                  &gEfiBlockIoProtocolGuid,
+                  (VOID **) &BlockIo,
+                  gSdMediaDeviceDriverBinding.DriverBindingHandle,
+                  ControllerHandle,
+                  EFI_OPEN_PROTOCOL_GET_PROTOCOL
+                  );
+
+  if (EFI_ERROR (Status)) {
+    return Status;
+  }
+
+  CardData  = CARD_DATA_FROM_THIS (BlockIo);
+
+  return LookupUnicodeString2 (
+           Language,
+           This->SupportedLanguages,
+           CardData->ControllerNameTable,
+           ControllerName,
+           (BOOLEAN) (This == &gSdMediaDeviceName)
+           );
+
+}
+
diff --git a/Silicon/BroxtonSoC/BroxtonSiPkg/SouthCluster/Sdio/Dxe/SD/SdMediaDeviceDxe/ComponentName.h b/Silicon/BroxtonSoC/BroxtonSiPkg/SouthCluster/Sdio/Dxe/SD/SdMediaDeviceDxe/ComponentName.h
new file mode 100644
index 0000000..3dea441
--- /dev/null
+++ b/Silicon/BroxtonSoC/BroxtonSiPkg/SouthCluster/Sdio/Dxe/SD/SdMediaDeviceDxe/ComponentName.h
@@ -0,0 +1,145 @@
+/** @file
+  This file contains the declarations for component name routines.
+
+  Copyright (c) 2013 - 2016, Intel Corporation. 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 _COMPONENT_NAME_H_
+#define _COMPONENT_NAME_H_
+
+/**
+  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[in]   This                    A pointer to the EFI_COMPONENT_NAME2_PROTOCOL or
+                                       EFI_COMPONENT_NAME_PROTOCOL instance.
+
+  @param[in]   Language                A pointer to a Null-terminated ASCII string
+                                       array indicating the language. This is the
+                                       language of the driver name that the caller is
+                                       requesting, and it must match one of the
+                                       languages specified in SupportedLanguages. The
+                                       number of languages supported by a driver is up
+                                       to the driver writer. Language is specified
+                                       in RFC 3066 or ISO 639-2 language code format.
+
+  @param[out]  DriverName              A pointer to the Unicode string to return.
+                                       This Unicode string is the name of the
+                                       driver specified by This in the language
+                                       specified by Language.
+
+  @retval      EFI_SUCCESS             The Unicode string for the Driver specified by
+                                       This and the language specified by Language was
+                                       returned in DriverName.
+
+  @retval      EFI_INVALID_PARAMETER   Language is NULL.
+
+  @retval      EFI_INVALID_PARAMETER   DriverName is NULL.
+
+  @retval      EFI_UNSUPPORTED         The driver specified by This does not support
+                                       the language specified by Language.
+
+**/
+EFI_STATUS
+EFIAPI
+SdMediaDeviceGetDriverName (
+  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[in]   This                    A pointer to the EFI_COMPONENT_NAME2_PROTOCOL or
+                                       EFI_COMPONENT_NAME_PROTOCOL instance.
+
+  @param[in]   ControllerHandle        The handle of a controller that the driver
+                                       specified by This is managing.  This handle
+                                       specifies the controller whose name is to be
+                                       returned.
+
+  @param[in]   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[in]   Language                A pointer to a Null-terminated ASCII string
+                                       array indicating the language.  This is the
+                                       language of the driver name that the caller is
+                                       requesting, and it must match one of the
+                                       languages specified in SupportedLanguages. The
+                                       number of languages supported by a driver is up
+                                       to the driver writer. Language is specified in
+                                       RFC 3066 or ISO 639-2 language code format.
+
+  @param[out]  ControllerName          A pointer to the Unicode string to return.
+                                       This Unicode string is the name of the
+                                       controller specified by ControllerHandle and
+                                       ChildHandle in the language specified by
+                                       Language from the point of view of the driver
+                                       specified by This.
+
+  @retval      EFI_SUCCESS             The Unicode string for the user readable name in
+                                       the language specified by Language for the
+                                       driver specified by This was returned in
+                                       DriverName.
+
+  @retval      EFI_INVALID_PARAMETER   ControllerHandle is not a valid EFI_HANDLE.
+
+  @retval      EFI_INVALID_PARAMETER   ChildHandle is not NULL and it is not a valid
+                                       EFI_HANDLE.
+
+  @retval      EFI_INVALID_PARAMETER   Language is NULL.
+
+  @retval      EFI_INVALID_PARAMETER   ControllerName is NULL.
+
+  @retval      EFI_UNSUPPORTED         The driver specified by This is not currently
+                                       managing the controller specified by
+                                       ControllerHandle and ChildHandle.
+
+  @retval      EFI_UNSUPPORTED         The driver specified by This does not support
+                                       the language specified by Language.
+
+**/
+EFI_STATUS
+EFIAPI
+SdMediaDeviceGetControllerName (
+  IN  EFI_COMPONENT_NAME_PROTOCOL                     *This,
+  IN  EFI_HANDLE                                      ControllerHandle,
+  IN  EFI_HANDLE                                      ChildHandle        OPTIONAL,
+  IN  CHAR8                                           *Language,
+  OUT CHAR16                                          **ControllerName
+  );
+
+#endif
+
diff --git a/Silicon/BroxtonSoC/BroxtonSiPkg/SouthCluster/Sdio/Dxe/SD/SdMediaDeviceDxe/MMCSDBlockIo.c b/Silicon/BroxtonSoC/BroxtonSiPkg/SouthCluster/Sdio/Dxe/SD/SdMediaDeviceDxe/MMCSDBlockIo.c
new file mode 100644
index 0000000..6180a25
--- /dev/null
+++ b/Silicon/BroxtonSoC/BroxtonSiPkg/SouthCluster/Sdio/Dxe/SD/SdMediaDeviceDxe/MMCSDBlockIo.c
@@ -0,0 +1,547 @@
+/** @file
+  Block I/O protocol for MMC/SD device.
+
+  Copyright (c) 2013 - 2016, Intel Corporation. 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 "SdMediaDevice.h"
+
+/**
+  Implements EFI_BLOCK_IO_PROTOCOL.Reset() function.
+
+  @param[in]   This                   The EFI_BLOCK_IO_PROTOCOL instance.
+  @param[in]   ExtendedVerification   Indicates that the driver may perform a more exhaustive.
+                                      verification operation of the device during reset.
+                                      (This parameter is ignored in this driver.)
+
+  @retval      EFI_SUCCESS            Success
+
+**/
+EFI_STATUS
+EFIAPI
+MMCSDBlockReset (
+  IN  EFI_BLOCK_IO_PROTOCOL   *This,
+  IN  BOOLEAN                 ExtendedVerification
+  )
+{
+  CARD_DATA                  *CardData;
+  EFI_SD_HOST_IO_PROTOCOL    *SdHostIo;
+
+  CardData  = CARD_DATA_FROM_THIS (This);
+  SdHostIo = CardData->SdHostIo;
+
+  return SdHostIo->ResetSdHost (SdHostIo, Reset_DAT_CMD);
+ }
+
+
+/**
+  Implements EFI_BLOCK_IO_PROTOCOL.ReadBlocks() function.
+
+  @param[in]  This                       The EFI_BLOCK_IO_PROTOCOL instance.
+  @param[in]  MediaId                    The media id that the write request is for.
+  @param[in]  LBA                        The starting logical block address to read from on the device.
+                                         The caller is responsible for writing to only legitimate locations.
+  @param[in]  BufferSize                 The size of the Buffer in bytes. This must be a multiple of the
+                                         intrinsic block size of the device.
+  @param[out] Buffer                     A pointer to the destination buffer for the data. The caller
+                                         is responsible for either having implicit or explicit ownership
+                                         of the buffer.
+
+  @retval     EFI_SUCCESS                Success
+  @retval     EFI_DEVICE_ERROR           Hardware Error
+  @retval     EFI_INVALID_PARAMETER      Parameter is error
+  @retval     EFI_NO_MEDIA               No media
+  @retval     EFI_MEDIA_CHANGED          Media Change
+  @retval     EFI_BAD_BUFFER_SIZE        Buffer size is bad
+
+**/
+EFI_STATUS
+EFIAPI
+MMCSDBlockReadBlocks (
+  IN  EFI_BLOCK_IO_PROTOCOL   *This,
+  IN  UINT32                  MediaId,
+  IN  EFI_LBA                 LBA,
+  IN  UINTN                   BufferSize,
+  OUT VOID                    *Buffer
+  )
+{
+  EFI_STATUS                  Status;
+  UINT32                      Address;
+  CARD_DATA                   *CardData;
+  EFI_SD_HOST_IO_PROTOCOL     *SdHostIo;
+  UINT32                      RemainingLength;
+  UINT32                      TransferLength;
+  UINT8                       *BufferPointer;
+  BOOLEAN                     SectorAddressing;
+  UINTN                       TotalBlock;
+
+  DEBUG ((EFI_D_INFO, "Read(LBA=%08lx, Buffer=%08x, Size=%08x)\n", LBA, Buffer, BufferSize));
+  Status = EFI_SUCCESS;
+  CardData = CARD_DATA_FROM_THIS (This);
+  SdHostIo = CardData->SdHostIo;
+
+  if (MediaId != CardData->BlockIoMedia.MediaId) {
+    return EFI_MEDIA_CHANGED;
+  }
+
+  if (ModU64x32 (BufferSize, CardData->BlockIoMedia.BlockSize) != 0) {
+    return EFI_BAD_BUFFER_SIZE;
+  }
+  if ((CardData->CardType == SdMemoryCard2High) || (CardData->CardType == MMCCardHighCap)) {
+    SectorAddressing = TRUE;
+  } else {
+    SectorAddressing = FALSE;
+  }
+  if (SectorAddressing) {
+    //
+    //Block Address
+    //
+    Address = (UINT32) DivU64x32 (MultU64x32 (LBA, CardData->BlockIoMedia.BlockSize), 512);
+  } else {
+    //
+    //Byte Address
+    //
+    Address  = (UINT32) MultU64x32 (LBA, CardData->BlockIoMedia.BlockSize);
+  }
+  TotalBlock = (UINTN) DivU64x32 (BufferSize, CardData->BlockIoMedia.BlockSize);
+  if (LBA + TotalBlock > CardData->BlockIoMedia.LastBlock + 1) {
+    return EFI_INVALID_PARAMETER;
+  }
+
+  if (!Buffer) {
+    Status = EFI_INVALID_PARAMETER;
+    DEBUG ((EFI_D_ERROR, "MMCSDBlockReadBlocks:Invalid parameter \r\n"));
+    goto Done;
+  }
+
+  if ((BufferSize % CardData->BlockIoMedia.BlockSize) != 0) {
+    Status = EFI_BAD_BUFFER_SIZE;
+    DEBUG ((EFI_D_ERROR, "MMCSDBlockReadBlocks: Bad buffer size \r\n"));
+    goto Done;
+  }
+
+  if (BufferSize == 0) {
+    Status = EFI_SUCCESS;
+    goto Done;
+  }
+
+    BufferPointer   = Buffer;
+    RemainingLength = (UINT32) BufferSize;
+
+    while (RemainingLength > 0) {
+    if ((BufferSize > CardData->BlockIoMedia.BlockSize)) {
+      if (RemainingLength > SdHostIo->HostCapability.BoundarySize) {
+        TransferLength = SdHostIo->HostCapability.BoundarySize;
+      } else {
+        TransferLength = RemainingLength;
+      }
+
+      if (CardData->CardType == MMCCard || CardData->CardType == MMCCardHighCap) {
+        if (!(CardData->ExtCSDRegister.CARD_TYPE & (BIT2 | BIT3))) {
+          Status = SendCommand (
+                     CardData,
+                     SET_BLOCKLEN,
+                     CardData->BlockIoMedia.BlockSize,
+                     NoData,
+                     NULL,
+                     0,
+                     ResponseR1,
+                     TIMEOUT_COMMAND,
+                     (UINT32 *) &(CardData->CardStatus)
+                     );
+
+          if (EFI_ERROR (Status)) {
+            break;
+          }
+        }
+        Status = SendCommand (
+                   CardData,
+                   SET_BLOCK_COUNT,
+                   TransferLength / CardData->BlockIoMedia.BlockSize,
+                   NoData,
+                   NULL,
+                   0,
+                   ResponseR1,
+                   TIMEOUT_COMMAND,
+                   (UINT32 *) &(CardData->CardStatus)
+                   );
+
+        if (EFI_ERROR (Status)) {
+          break;
+        }
+      }
+      Status = SendCommand (
+                 CardData,
+                 READ_MULTIPLE_BLOCK,
+                 Address,
+                 InData,
+                 CardData->AlignedBuffer,
+                 TransferLength,
+                 ResponseR1,
+                 TIMEOUT_DATA,
+                 (UINT32 *) &(CardData->CardStatus)
+                 );
+
+      if (EFI_ERROR (Status)) {
+        DEBUG ((EFI_D_ERROR, "MMCSDBlockReadBlocks: READ_MULTIPLE_BLOCK -> Fail\n"));
+        break;
+      }
+    } else {
+      if (RemainingLength > CardData->BlockIoMedia.BlockSize) {
+        TransferLength = CardData->BlockIoMedia.BlockSize;
+      } else {
+        TransferLength = RemainingLength;
+      }
+
+      Status = SendCommand (
+                 CardData,
+                 READ_SINGLE_BLOCK,
+                 Address,
+                 InData,
+                 CardData->AlignedBuffer,
+                 (UINT32) TransferLength,
+                 ResponseR1,
+                 TIMEOUT_DATA,
+                 (UINT32 *) &(CardData->CardStatus)
+                 );
+
+      if (EFI_ERROR (Status)) {
+        DEBUG ((EFI_D_ERROR, "MMCSDBlockReadBlocks: READ_SINGLE_BLOCK -> Fail\n"));
+        break;
+      }
+    }
+    CopyMem (BufferPointer, CardData->AlignedBuffer, TransferLength);
+    if (SectorAddressing) {
+      //
+      //Block Address
+      //
+      Address += TransferLength / 512;
+    } else {
+      //
+      //Byte Address
+      //
+      Address += TransferLength;
+    }
+    BufferPointer += TransferLength;
+    RemainingLength -= TransferLength;
+   }
+
+  if (EFI_ERROR (Status)) {
+    if ((CardData->CardType == SdMemoryCard) ||
+        (CardData->CardType == SdMemoryCard2)||
+        (CardData->CardType == SdMemoryCard2High)) {
+         SendCommand (
+           CardData,
+           STOP_TRANSMISSION,
+           0,
+           NoData,
+           NULL,
+           0,
+           ResponseR1b,
+           TIMEOUT_COMMAND,
+           (UINT32 *) &(CardData->CardStatus)
+           );
+
+    } else {
+       SendCommand (
+         CardData,
+         STOP_TRANSMISSION,
+         0,
+         NoData,
+         NULL,
+         0,
+         ResponseR1,
+         TIMEOUT_COMMAND,
+         (UINT32 *) &(CardData->CardStatus)
+         );
+    }
+
+  }
+
+Done:
+  DEBUG ((EFI_D_INFO, "MMCSDBlockReadBlocks: Status = %r\n", Status));
+  return Status;
+}
+
+
+/**
+  Implements EFI_BLOCK_IO_PROTOCOL.WriteBlocks() function.
+
+  @param[in]  This                       The EFI_BLOCK_IO_PROTOCOL instance.
+  @param[in]  MediaId                    The media id that the write request is for.
+  @param[in]  LBA                        The starting logical block address to read from on the device.
+                                         The caller is responsible for writing to only legitimate locations.
+  @param[in]  BufferSize                 The size of the Buffer in bytes. This must be a multiple of the
+                                         intrinsic block size of the device.
+  @param[in]  Buffer                     A pointer to the destination buffer for the data. The caller
+                                         is responsible for either having implicit or explicit ownership
+                                         of the buffer.
+
+  @retval     EFI_SUCCESS                Success
+  @retval     EFI_DEVICE_ERROR           Hardware Error
+  @retval     EFI_INVALID_PARAMETER      Parameter is error
+  @retval     EFI_NO_MEDIA               No media
+  @retval     EFI_MEDIA_CHANGED          Media Change
+  @retval     EFI_BAD_BUFFER_SIZE        Buffer size is bad
+
+**/
+EFI_STATUS
+EFIAPI
+MMCSDBlockWriteBlocks (
+  IN  EFI_BLOCK_IO_PROTOCOL   *This,
+  IN  UINT32                  MediaId,
+  IN  EFI_LBA                 LBA,
+  IN  UINTN                   BufferSize,
+  IN  VOID                    *Buffer
+  )
+{
+  EFI_STATUS                  Status;
+  UINT32                      Address;
+  CARD_DATA                   *CardData;
+  EFI_SD_HOST_IO_PROTOCOL     *SdHostIo;
+  UINT32                      RemainingLength;
+  UINT32                      TransferLength;
+  UINT8                       *BufferPointer;
+  BOOLEAN                     SectorAddressing;
+
+  DEBUG ((EFI_D_INFO, "Write(LBA=%08lx, Buffer=%08x, Size=%08x)\n", LBA, Buffer, BufferSize));
+  Status = EFI_SUCCESS;
+  CardData = CARD_DATA_FROM_THIS (This);
+  SdHostIo = CardData->SdHostIo;
+  if ((CardData->CardType == SdMemoryCard2High) || (CardData->CardType == MMCCardHighCap)) {
+    SectorAddressing = TRUE;
+  } else {
+    SectorAddressing = FALSE;
+  }
+  if (SectorAddressing) {
+    //
+    //Block Address
+    //
+    Address = (UINT32) DivU64x32 (MultU64x32 (LBA, CardData->BlockIoMedia.BlockSize), 512);
+  } else {
+    //
+    //Byte Address
+    //
+    Address = (UINT32) MultU64x32 (LBA, CardData->BlockIoMedia.BlockSize);
+  }
+
+  if (!Buffer) {
+    Status = EFI_INVALID_PARAMETER;
+    DEBUG ((EFI_D_ERROR, "MMCSDBlockWriteBlocks: Invalid parameter \r\n"));
+    goto Done;
+  }
+
+  if ((BufferSize % CardData->BlockIoMedia.BlockSize) != 0) {
+    Status = EFI_BAD_BUFFER_SIZE;
+    DEBUG ((EFI_D_ERROR, "MMCSDBlockWriteBlocks: Bad buffer size \r\n"));
+    goto Done;
+  }
+
+  if (BufferSize == 0) {
+    Status = EFI_SUCCESS;
+    goto Done;
+  }
+
+  if (This->Media->ReadOnly == TRUE) {
+    Status = EFI_WRITE_PROTECTED;
+    DEBUG ((EFI_D_ERROR, "MMCSDBlockWriteBlocks: Write protected \r\n"));
+    goto Done;
+  }
+
+    BufferPointer = Buffer;
+    RemainingLength = (UINT32) BufferSize;
+
+    while (RemainingLength > 0) {
+    if ((BufferSize > CardData->BlockIoMedia.BlockSize) ) {
+      if (RemainingLength > SdHostIo->HostCapability.BoundarySize) {
+        TransferLength = SdHostIo->HostCapability.BoundarySize;
+      } else {
+        TransferLength = RemainingLength;
+      }
+
+      if (CardData->CardType == MMCCard || CardData->CardType == MMCCardHighCap) {
+
+        if (!(CardData->ExtCSDRegister.CARD_TYPE & (BIT2 | BIT3)))  {
+            Status = SendCommand (
+                       CardData,
+                       SET_BLOCKLEN,
+                       CardData->BlockIoMedia.BlockSize,
+                       NoData,
+                       NULL,
+                       0,
+                       ResponseR1,
+                       TIMEOUT_COMMAND,
+                       (UINT32 *) &(CardData->CardStatus)
+                       );
+
+            if (EFI_ERROR (Status)) {
+              break;
+            }
+        }
+        Status = SendCommand (
+                   CardData,
+                   SET_BLOCK_COUNT,
+                   TransferLength / CardData->BlockIoMedia.BlockSize,
+                   NoData,
+                   NULL,
+                   0,
+                   ResponseR1,
+                   TIMEOUT_COMMAND,
+                   (UINT32 *) &(CardData->CardStatus)
+                   );
+
+        if (EFI_ERROR (Status)) {
+          break;
+        }
+      }
+
+      CopyMem (CardData->AlignedBuffer, BufferPointer, TransferLength);
+
+      Status = SendCommand (
+                 CardData,
+                 WRITE_MULTIPLE_BLOCK,
+                 Address,
+                 OutData,
+                 CardData->AlignedBuffer,
+                 (UINT32) TransferLength,
+                 ResponseR1,
+                 TIMEOUT_DATA,
+                 (UINT32 *) &(CardData->CardStatus)
+                 );
+
+      if (EFI_ERROR (Status)) {
+        DEBUG ((EFI_D_ERROR, "MMCSDBlockWriteBlocks: WRITE_MULTIPLE_BLOCK -> Fail\n"));
+        break;
+      }
+    } else {
+      if (RemainingLength > CardData->BlockIoMedia.BlockSize) {
+        TransferLength = CardData->BlockIoMedia.BlockSize;
+      } else {
+        TransferLength = RemainingLength;
+      }
+
+      CopyMem (CardData->AlignedBuffer, BufferPointer, TransferLength);
+
+      Status = SendCommand (
+                 CardData,
+                 WRITE_BLOCK,
+                 Address,
+                 OutData,
+                 CardData->AlignedBuffer,
+                 (UINT32) TransferLength,
+                 ResponseR1,
+                 TIMEOUT_DATA,
+                 (UINT32 *) &(CardData->CardStatus)
+                 );
+
+    }
+
+    if (SectorAddressing) {
+        //
+        //Block Address
+        //
+        Address += TransferLength / 512;
+      } else {
+        //
+        //Byte Address
+        //
+        Address += TransferLength;
+      }
+      BufferPointer   += TransferLength;
+      RemainingLength -= TransferLength;
+
+  }
+
+  if (EFI_ERROR (Status)) {
+    SendCommand (
+      CardData,
+      STOP_TRANSMISSION,
+      0,
+      NoData,
+      NULL,
+      0,
+      ResponseR1b,
+      TIMEOUT_COMMAND,
+      (UINT32 *) &(CardData->CardStatus)
+      );
+
+  }
+
+Done:
+  return EFI_SUCCESS;
+}
+
+
+/**
+  Implements EFI_BLOCK_IO_PROTOCOL.FlushBlocks() function.
+  (In this driver, this function just returns EFI_SUCCESS.)
+
+  @param[in]  This                   The EFI_BLOCK_IO_PROTOCOL instance.
+
+  @retval     EFI_SUCCESS
+  @retval     Others
+
+**/
+EFI_STATUS
+EFIAPI
+MMCSDBlockFlushBlocks (
+  IN  EFI_BLOCK_IO_PROTOCOL   *This
+  )
+{
+  return EFI_SUCCESS;
+}
+
+
+/**
+  MMC/SD card BlockIo init function.
+
+  @param[in]  CardData               Pointer to CARD_DATA.
+
+  @retval     EFI_SUCCESS
+  @retval     Others
+
+**/
+EFI_STATUS
+MMCSDBlockIoInit (
+  IN  CARD_DATA    *CardData
+  )
+{
+
+  //
+  // BlockIO protocol
+  //
+  CardData->BlockIo.Revision    = EFI_BLOCK_IO_PROTOCOL_REVISION;
+  CardData->BlockIo.Media       = &(CardData->BlockIoMedia);
+  CardData->BlockIo.Reset       = MMCSDBlockReset;
+  CardData->BlockIo.ReadBlocks  = MMCSDBlockReadBlocks ;
+  CardData->BlockIo.WriteBlocks = MMCSDBlockWriteBlocks;
+  CardData->BlockIo.FlushBlocks = MMCSDBlockFlushBlocks;
+
+  CardData->BlockIoMedia.MediaId          = 0;
+  CardData->BlockIoMedia.RemovableMedia   = FALSE;
+  CardData->BlockIoMedia.MediaPresent     = TRUE;
+  CardData->BlockIoMedia.LogicalPartition = FALSE;
+
+  if (CardData->CSDRegister.PERM_WRITE_PROTECT || CardData->CSDRegister.TMP_WRITE_PROTECT) {
+    CardData->BlockIoMedia.ReadOnly         = TRUE;
+  } else {
+    CardData->BlockIoMedia.ReadOnly         = FALSE;
+  }
+
+  CardData->BlockIoMedia.WriteCaching     = FALSE;
+  CardData->BlockIoMedia.BlockSize        = CardData->BlockLen;
+  CardData->BlockIoMedia.IoAlign          = 1;
+  CardData->BlockIoMedia.LastBlock        = (EFI_LBA) (CardData->BlockNumber - 1);
+
+  return EFI_SUCCESS;
+}
+
diff --git a/Silicon/BroxtonSoC/BroxtonSiPkg/SouthCluster/Sdio/Dxe/SD/SdMediaDeviceDxe/MMCSDTransfer.c b/Silicon/BroxtonSoC/BroxtonSiPkg/SouthCluster/Sdio/Dxe/SD/SdMediaDeviceDxe/MMCSDTransfer.c
new file mode 100644
index 0000000..e0304de
--- /dev/null
+++ b/Silicon/BroxtonSoC/BroxtonSiPkg/SouthCluster/Sdio/Dxe/SD/SdMediaDeviceDxe/MMCSDTransfer.c
@@ -0,0 +1,1661 @@
+/** @file
+  MMC/SD transfer specific functions
+
+  Copyright (c) 2013 - 2016, Intel Corporation. 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 "SdMediaDevice.h"
+
+
+/**
+  Check card status, print the debug info and check the error
+
+  @param[in]  Status                Status got from card status register.
+
+  @retval     EFI_SUCCESS
+  @retval     EFI_DEVICE_ERROR
+
+**/
+EFI_STATUS
+CheckCardStatus (
+  IN  UINT32    Status
+  )
+{
+  CARD_STATUS    *CardStatus;
+  CardStatus = (CARD_STATUS *) (&Status);
+
+  if (CardStatus->ADDRESS_OUT_OF_RANGE) {
+    DEBUG ((EFI_D_ERROR, "CardStatus: ADDRESS_OUT_OF_RANGE\n"));
+  }
+
+  if (CardStatus->ADDRESS_MISALIGN) {
+    DEBUG ((EFI_D_ERROR, "CardStatus: ADDRESS_MISALIGN\n"));
+  }
+
+  if (CardStatus->BLOCK_LEN_ERROR) {
+    DEBUG ((EFI_D_ERROR, "CardStatus: BLOCK_LEN_ERROR\n"));
+  }
+
+  if (CardStatus->ERASE_SEQ_ERROR) {
+    DEBUG ((EFI_D_ERROR, "CardStatus: ERASE_SEQ_ERROR\n"));
+  }
+
+  if (CardStatus->ERASE_PARAM) {
+    DEBUG ((EFI_D_ERROR, "CardStatus: ERASE_PARAM\n"));
+  }
+
+  if (CardStatus->WP_VIOLATION) {
+    DEBUG ((EFI_D_ERROR, "CardStatus: WP_VIOLATION\n"));
+  }
+
+  if (CardStatus->CARD_IS_LOCKED) {
+    DEBUG ((EFI_D_ERROR, "CardStatus: CARD_IS_LOCKED\n"));
+  }
+
+  if (CardStatus->LOCK_UNLOCK_FAILED) {
+    DEBUG ((EFI_D_ERROR, "CardStatus: LOCK_UNLOCK_FAILED\n"));
+  }
+
+  if (CardStatus->COM_CRC_ERROR) {
+    DEBUG ((EFI_D_ERROR, "CardStatus: COM_CRC_ERROR\n"));
+  }
+
+  if (CardStatus->ILLEGAL_COMMAND) {
+    DEBUG ((EFI_D_ERROR, "CardStatus: ILLEGAL_COMMAND\n"));
+  }
+
+  if (CardStatus->CARD_ECC_FAILED) {
+    DEBUG ((EFI_D_ERROR, "CardStatus: CARD_ECC_FAILED\n"));
+  }
+
+  if (CardStatus->CC_ERROR) {
+    DEBUG ((EFI_D_ERROR, "CardStatus: CC_ERROR\n"));
+  }
+
+  if (CardStatus->ERROR) {
+    DEBUG ((EFI_D_ERROR, "CardStatus: ERROR\n"));
+  }
+
+  if (CardStatus->UNDERRUN) {
+    DEBUG ((EFI_D_ERROR, "CardStatus: UNDERRUN\n"));
+  }
+
+  if (CardStatus->OVERRUN) {
+    DEBUG ((EFI_D_ERROR, "CardStatus: OVERRUN\n"));
+  }
+
+  if (CardStatus->CID_CSD_OVERWRITE) {
+    DEBUG ((EFI_D_ERROR, "CardStatus: CID_CSD_OVERWRITE\n"));
+  }
+
+  if (CardStatus->WP_ERASE_SKIP) {
+    DEBUG ((EFI_D_ERROR, "CardStatus: WP_ERASE_SKIP\n"));
+  }
+
+  if (CardStatus->ERASE_RESET) {
+    DEBUG ((EFI_D_ERROR, "CardStatus: ERASE_RESET\n"));
+  }
+
+  if (CardStatus->SWITCH_ERROR) {
+    DEBUG ((EFI_D_ERROR, "CardStatus: SWITCH_ERROR\n"));
+  }
+
+  if ((Status & 0xFCFFA080) != 0) {
+    return EFI_DEVICE_ERROR;
+  }
+
+  return EFI_SUCCESS;
+}
+
+
+/**
+  Send command by using Host IO protocol
+
+  @param[in]  This                  A pointer to the EFI_SD_HOST_IO_PROTOCOL instance.
+  @param[in]  CommandIndex          The command index to set the command index field of command register.
+  @param[in]  Argument              Command argument to set the argument field of command register.
+  @param[in]  DataType              TRANSFER_TYPE, indicates no data, data in or data out.
+  @param[in]  Buffer                Contains the data read from / write to the device.
+  @param[in]  BufferSize            The size of the buffer.
+  @param[in]  ResponseType          RESPONSE_TYPE.
+  @param[in]  TimeOut               Time out value in 1 ms unit.
+  @param[out] ResponseData          Depending on the ResponseType, such as CSD or card status.
+
+  @retval     EFI_SUCCESS
+  @retval     EFI_INVALID_PARAMETER
+  @retval     EFI_UNSUPPORTED
+  @retval     EFI_DEVICE_ERROR
+
+**/
+EFI_STATUS
+SendCommand (
+  IN   CARD_DATA                  *CardData,
+  IN   UINT16                     CommandIndex,
+  IN   UINT32                     Argument,
+  IN   TRANSFER_TYPE              DataType,
+  IN   UINT8                      *Buffer, OPTIONAL
+  IN   UINT32                     BufferSize,
+  IN   RESPONSE_TYPE              ResponseType,
+  IN   UINT32                     TimeOut,
+  OUT  UINT32                     *ResponseData
+  )
+{
+
+  EFI_STATUS                 Status;
+  EFI_SD_HOST_IO_PROTOCOL    *SdHostIo;
+
+  SdHostIo = CardData->SdHostIo;
+  if (CardData->CardType != MMCCard && CardData->CardType != MMCCardHighCap) {
+    CommandIndex |= AUTO_CMD12_ENABLE;
+  }
+  Status = SdHostIo->SendCommand (
+                       SdHostIo,
+                       CommandIndex,
+                       Argument,
+                       DataType,
+                       Buffer,
+                       BufferSize,
+                       ResponseType,
+                       TimeOut,
+                       ResponseData
+                       );
+
+  if (!EFI_ERROR (Status)) {
+    if (ResponseType == ResponseR1 || ResponseType == ResponseR1b) {
+      ASSERT (ResponseData != NULL);
+      Status = CheckCardStatus (*ResponseData);
+    }
+  } else {
+    SdHostIo->ResetSdHost (SdHostIo, Reset_DAT_CMD);
+  }
+
+  return Status;
+}
+
+
+/**
+  Send the card APP_CMD command with the following command indicated by CommandIndex
+
+  @param[in]  CardData              Pointer to CARD_DATA.
+  @param[in]  CommandIndex          The command index to set the command index field of command register.
+  @param[in]  Argument              Command argument to set the argument field of command register.
+  @param[in]  DataType              TRANSFER_TYPE, indicates no data, data in or data out.
+  @param[in]  Buffer                Contains the data read from / write to the device.
+  @param[in]  BufferSize            The size of the buffer.
+  @param[in]  ResponseType          RESPONSE_TYPE.
+  @param[in]  TimeOut               Time out value in 1 ms unit.
+  @param[out] ResponseData          Depending on the ResponseType, such as CSD or card status.
+
+  @retval     EFI_SUCCESS
+  @retval     EFI_INVALID_PARAMETER
+  @retval     EFI_UNSUPPORTED
+  @retval     EFI_DEVICE_ERROR
+
+**/
+EFI_STATUS
+SendAppCommand (
+  IN   CARD_DATA                  *CardData,
+  IN   UINT16                     CommandIndex,
+  IN   UINT32                     Argument,
+  IN   TRANSFER_TYPE              DataType,
+  IN   UINT8                      *Buffer, OPTIONAL
+  IN   UINT32                     BufferSize,
+  IN   RESPONSE_TYPE              ResponseType,
+  IN   UINT32                     TimeOut,
+  OUT  UINT32                     *ResponseData
+  )
+{
+
+  EFI_STATUS                 Status;
+  EFI_SD_HOST_IO_PROTOCOL    *SdHostIo;
+  UINT8                      Index;
+
+  SdHostIo = CardData->SdHostIo;
+  Status = EFI_SUCCESS;
+
+  for (Index = 0; Index < 2; Index++) {
+    Status = SdHostIo->SendCommand (
+                         SdHostIo,
+                         APP_CMD,
+                         (CardData->Address << 16),
+                         NoData,
+                         NULL,
+                         0,
+                         ResponseR1,
+                         TIMEOUT_COMMAND,
+                         (UINT32 *) &(CardData->CardStatus)
+                         );
+
+    if (!EFI_ERROR (Status)) {
+        Status = CheckCardStatus (*(UINT32 *) &(CardData->CardStatus));
+        if (CardData->CardStatus.SAPP_CMD != 1) {
+          Status = EFI_DEVICE_ERROR;
+        }
+        if (!EFI_ERROR (Status)) {
+          break;
+        }
+    } else {
+      SdHostIo->ResetSdHost (SdHostIo, Reset_Auto);
+    }
+  }
+
+  if (EFI_ERROR (Status)) {
+    return Status;
+  }
+  if (CardData->CardType != MMCCard && CardData->CardType != MMCCardHighCap) {
+    CommandIndex |= AUTO_CMD12_ENABLE;
+  }
+
+  Status = SdHostIo->SendCommand (
+                       SdHostIo,
+                       CommandIndex,
+                       Argument,
+                       DataType,
+                       Buffer,
+                       BufferSize,
+                       ResponseType,
+                       TimeOut,
+                       ResponseData
+                       );
+
+  if (!EFI_ERROR (Status)) {
+    if (ResponseType == ResponseR1 || ResponseType == ResponseR1b) {
+      ASSERT (ResponseData != NULL);
+      Status = CheckCardStatus (*ResponseData);
+    }
+  } else {
+    SdHostIo->ResetSdHost (SdHostIo, Reset_Auto);
+  }
+
+  return Status;
+}
+
+
+/**
+  Send the card FAST_IO command
+
+  @param[in]      CardData               Pointer to CARD_DATA.
+  @param[in]      RegisterAddress        Register Address.
+  @param[in, out] RegisterData           Pointer to register Data.
+  @param[in]      Write                  TRUE for write, FALSE for read.
+
+  @retval         EFI_SUCCESS
+  @retval         EFI_UNSUPPORTED
+  @retval         EFI_INVALID_PARAMETER
+  @retval         EFI_DEVICE_ERROR
+
+**/
+EFI_STATUS
+FastIO (
+  IN      CARD_DATA   *CardData,
+  IN      UINT8       RegisterAddress,
+  IN  OUT UINT8       *RegisterData,
+  IN      BOOLEAN     Write
+  )
+{
+  EFI_STATUS                 Status;
+  UINT32                     Argument;
+  UINT32                     Data;
+
+  Status = EFI_SUCCESS;
+
+  if (RegisterData == NULL) {
+    Status = EFI_INVALID_PARAMETER;
+    goto Exit;
+  }
+
+  Argument = (CardData->Address << 16) | (RegisterAddress << 8);
+  if (Write) {
+    Argument |= BIT15 | (*RegisterData);
+  }
+
+  Status = SendCommand (
+             CardData,
+             FAST_IO,
+             Argument,
+             NoData,
+             NULL,
+             0,
+             ResponseR4,
+             TIMEOUT_COMMAND,
+             &Data
+             );
+
+  if (EFI_ERROR (Status)) {
+    goto Exit;
+  }
+
+  if ((Data & BIT15) == 0) {
+    Status = EFI_DEVICE_ERROR;
+    goto Exit;
+  }
+
+  if (!Write) {
+   *RegisterData = (UINT8) Data;
+  }
+
+Exit:
+  return Status;
+}
+
+
+/**
+  Send the card GO_INACTIVE_STATE command.
+
+  @param[in]  CardData             Pointer to CARD_DATA.
+
+  @retval     EFI_SUCCESS
+  @retval     others
+
+**/
+EFI_STATUS
+PutCardInactive (
+  IN  CARD_DATA   *CardData
+  )
+{
+  EFI_STATUS                 Status;
+
+
+  Status = SendCommand (
+             CardData,
+             GO_INACTIVE_STATE,
+             (CardData->Address << 16),
+             NoData,
+             NULL,
+             0,
+             ResponseNo,
+             TIMEOUT_COMMAND,
+             NULL
+             );
+
+  return Status;
+
+}
+
+
+/**
+  Get card interested information for CSD rergister
+
+  @param[in]  CardData               Pointer to CARD_DATA.
+
+  @retval     EFI_SUCCESS
+  @retval     EFI_UNSUPPORTED
+  @retval     EFI_INVALID_PARAMETER
+
+**/
+EFI_STATUS
+CaculateCardParameter (
+  IN  CARD_DATA    *CardData
+  )
+{
+  EFI_STATUS     Status;
+  UINT32         Frequency;
+  UINT32         Multiple;
+  UINT32         CSize;
+  CSD_SDV2       *CsdSDV2;
+
+  Status = EFI_SUCCESS;
+
+  switch (CardData->CSDRegister.TRAN_SPEED & 0x7) {
+    case 0:
+      Frequency = 100 * 1000;
+      break;
+
+    case 1:
+      Frequency = 1 * 1000 * 1000;
+      break;
+
+    case 2:
+      Frequency = 10 * 1000 * 1000;
+      break;
+
+    case 3:
+      Frequency = 100 * 1000 * 1000;
+      break;
+
+    default:
+      Status = EFI_INVALID_PARAMETER;
+      goto Exit;
+  }
+
+  switch ((CardData->CSDRegister.TRAN_SPEED >> 3) & 0xF) {
+    case 1:
+      Multiple = 10;
+      break;
+
+    case 2:
+      Multiple = 12;
+      break;
+
+    case 3:
+      Multiple = 13;
+      break;
+
+    case 4:
+      Multiple = 15;
+      break;
+
+    case 5:
+      Multiple = 20;
+      break;
+
+    case 6:
+      if (CardData->CardType == MMCCard  || CardData->CardType == MMCCardHighCap) {
+        Multiple = 26;
+      } else {
+        Multiple = 25;
+      }
+      break;
+
+    case 7:
+      Multiple = 30;
+      break;
+
+    case 8:
+      Multiple = 35;
+      break;
+
+    case 9:
+      Multiple = 40;
+      break;
+
+    case 10:
+      Multiple = 45;
+      break;
+
+    case 11:
+      if (CardData->CardType == MMCCard  || CardData->CardType == MMCCardHighCap) {
+        Multiple = 52;
+      } else {
+        Multiple = 50;
+      }
+      break;
+
+    case 12:
+      Multiple = 55;
+      break;
+
+    case 13:
+      Multiple = 60;
+      break;
+
+    case 14:
+      Multiple = 70;
+      break;
+
+    case 15:
+      Multiple = 80;
+      break;
+
+    default:
+      Status = EFI_INVALID_PARAMETER;
+      goto Exit;
+  }
+
+  Frequency = Frequency * Multiple / 10;
+  CardData->MaxFrequency = Frequency;
+
+  CardData->BlockLen = 1 << CardData->CSDRegister.READ_BL_LEN;
+
+  if (CardData->CardType == SdMemoryCard2High) {
+    ASSERT (CardData->CSDRegister.CSD_STRUCTURE == 1);
+    CsdSDV2 = (CSD_SDV2 *) &CardData->CSDRegister;
+
+    //
+    // the K here means 1024 not 1000
+    //
+    CardData->BlockNumber = DivU64x32 (MultU64x32 (CsdSDV2->C_SIZE + 1, 512 * 1024) , CardData->BlockLen);
+  } else {
+    //
+    // For MMC card > 2G, the block number will be recaculate later
+    //
+    CSize = CardData->CSDRegister.C_SIZELow2 | (CardData->CSDRegister.C_SIZEHigh10 << 2);
+    CardData->BlockNumber = MultU64x32 (LShiftU64 (1, CardData->CSDRegister.C_SIZE_MULT + 2), CSize + 1);
+  }
+
+  //
+  //For >= 2G card, BlockLen may be 1024, but the transfer size is still 512 bytes
+  //
+  if (CardData->BlockLen > 512) {
+    CardData->BlockNumber = DivU64x32 (MultU64x32 (CardData->BlockNumber, CardData->BlockLen), 512);
+    CardData->BlockLen = 512;
+  }
+
+  DEBUG ((
+    EFI_D_INFO,
+    "CalculateCardParameter: Card Size: 0x%lx\n", MultU64x32 (CardData->BlockNumber, CardData->BlockLen)
+    ));
+
+Exit:
+  return Status;
+}
+
+
+/**
+  Test the bus width setting for MMC card.It is used only for verification purpose.
+
+  @param[in]  CardData               Pointer to CARD_DATA.
+  @param[in]  Width                  1, 4, 8 bits.
+
+  @retval     EFI_SUCCESS
+  @retval     EFI_UNSUPPORTED
+  @retval     EFI_INVALID_PARAMETER
+
+**/
+EFI_STATUS
+MMCCardBusWidthTest (
+  IN  CARD_DATA             *CardData,
+  IN  UINT32                Width
+  )
+{
+  EFI_STATUS                 Status;
+  UINT64                     Data;
+  UINT64                     Value;
+
+  ASSERT(CardData != NULL);
+
+  Value = 0;
+
+  switch (Width) {
+    case 1:
+      Data = 0x80;
+      break;
+
+    case 4:
+      Data = 0x5A;
+      break;
+
+    case 8:
+      Data = 0xAA55;
+      break;
+
+    default:
+      Status = EFI_INVALID_PARAMETER;
+      goto Exit;
+  }
+
+  CopyMem (CardData->AlignedBuffer, &Data, Width);
+  Status  = SendCommand (
+              CardData,
+              BUSTEST_W,
+              0,
+              OutData,
+              CardData->AlignedBuffer,
+              Width,
+              ResponseR1,
+              TIMEOUT_COMMAND,
+              (UINT32 *) &(CardData->CardStatus)
+              );
+
+  if (EFI_ERROR (Status)) {
+    DEBUG ((EFI_D_ERROR, "MMCCardBusWidthTest:SendCommand BUSTEST_W 0x%x\n", *(UINT32*)&(CardData->CardStatus)));
+    goto Exit;
+  }
+
+  gBS->Stall (10 * 1000);
+
+  Data = 0;
+
+  Status  = SendCommand (
+              CardData,
+              BUSTEST_R,
+              0,
+              InData,
+              CardData->AlignedBuffer,
+              Width,
+              ResponseR1,
+              TIMEOUT_COMMAND,
+              (UINT32 *) &(CardData->CardStatus)
+              );
+
+  if (EFI_ERROR (Status)) {
+    DEBUG ((EFI_D_ERROR, "MMCCardBusWidthTest:SendCommand BUSTEST_R 0x%x\n", *(UINT32 *) &(CardData->CardStatus)));
+    goto Exit;
+  }
+  CopyMem (&Data, CardData->AlignedBuffer, Width);
+
+  switch (Width) {
+    case 1:
+      Value = (~(Data ^ 0x80)) & 0xC0;
+      break;
+
+    case 4:
+      Value = (~(Data ^ 0x5A)) & 0xFF;
+      break;
+
+    case 8:
+      Value = (~(Data ^ 0xAA55)) & 0xFFFF;
+      break;
+  }
+
+  if (Value == 0) {
+    Status = EFI_SUCCESS;
+  } else {
+    Status = EFI_UNSUPPORTED;
+  }
+
+Exit:
+  return Status;
+}
+
+
+/**
+  This function can detect these card types:
+    1. MMC card
+    2. SD 1.1 card
+    3. SD 2.0 standard card
+    3. SD 2.0 high capacity card
+
+  @param[in]  CardData             Pointer to CARD_DATA.
+
+  @retval     EFI_SUCCESS
+  @retval     others
+
+**/
+EFI_STATUS
+GetCardType (
+  IN  CARD_DATA              *CardData
+  )
+{
+  EFI_STATUS                 Status;
+  EFI_SD_HOST_IO_PROTOCOL    *SdHostIo;
+  UINT32                     Argument;
+  UINT32                     ResponseData;
+  UINT32                     Count;
+  BOOLEAN                    SdCommand8Support;
+
+  SdHostIo = CardData->SdHostIo;
+
+  //
+  // Reset the card
+  //
+  Status  = SendCommand (
+              CardData,
+              GO_IDLE_STATE,
+              0,
+              NoData,
+              NULL,
+              0,
+              ResponseNo,
+              TIMEOUT_COMMAND,
+              NULL
+              );
+
+  if (EFI_ERROR (Status)) {
+    DEBUG ((EFI_D_ERROR, "GO_IDLE_STATE Fail Status = 0x%x\n", Status));
+    goto Exit;
+  }
+  gBS->Stall (10 * 1000);
+
+  //
+  // Only 2.7V - 3.6V is supported for SD2.0, only SD 2.0 card can pass
+  // MMC and SD1.1 card will fail this command
+  //
+  Argument          = (VOLTAGE_27_36 << 8) | CHECK_PATTERN;
+  ResponseData      = 0;
+  SdCommand8Support = FALSE;
+
+  Status  = SendCommand (
+              CardData,
+              SEND_IF_COND,
+              Argument,
+              NoData,
+              NULL,
+              0,
+              ResponseR7,
+              TIMEOUT_COMMAND,
+              &ResponseData
+              );
+
+  if (EFI_ERROR (Status)) {
+    if (Status != EFI_TIMEOUT) {
+       DEBUG ((EFI_D_ERROR, "SEND_IF_COND Fail, none time out error\n"));
+       goto Exit;
+    }
+  } else {
+     if (ResponseData != Argument) {
+       DEBUG ((EFI_D_ERROR, "SEND_IF_COND Fail, respond data does not match send data\n"));
+       Status = EFI_DEVICE_ERROR;
+       goto Exit;
+    }
+    SdCommand8Support = TRUE;
+  }
+
+  Argument = 0;
+
+  if (SdHostIo->HostCapability.V30Support == TRUE) {
+    Argument |= BIT17 | BIT18;
+  } else if (SdHostIo->HostCapability.V33Support == TRUE) {
+    Argument |= BIT20 | BIT21;
+  }
+
+  if (SdCommand8Support) {
+    Argument |= BIT30;
+  }
+
+  Count = 20;
+  do {
+    Status  = SendAppCommand (
+                CardData,
+                SD_SEND_OP_COND,
+                Argument,
+                NoData,
+                NULL,
+                0,
+                ResponseR3,
+                TIMEOUT_COMMAND,
+                (UINT32 *) &(CardData->OCRRegister)
+                );
+
+    if (EFI_ERROR (Status)) {
+      if ((Status == EFI_TIMEOUT) && (!SdCommand8Support)) {
+        CardData->CardType = MMCCard;
+        Status = EFI_SUCCESS;
+        DEBUG ((EFI_D_INFO, "SD_SEND_OP_COND, MMC card was identified\n"));
+      } else {
+        DEBUG ((EFI_D_ERROR, "SD_SEND_OP_COND Fail, check whether it is neither a MMC card nor a SD card\n"));
+      }
+      goto Exit;
+    }
+    //
+    // Avoid waiting if sucess. Busy bit 0 means not ready
+    //
+    if (CardData->OCRRegister.Busy == 1) {
+      break;
+    }
+
+    gBS->Stall (50 * 1000);
+    Count--;
+    if (Count == 0) {
+      DEBUG ((EFI_D_ERROR, "Card is always in busy state\n"));
+      Status = EFI_TIMEOUT;
+      goto Exit;
+    }
+  } while (1);
+
+  //
+  // Check supported voltage
+  //
+  Argument = 0;
+  if (SdHostIo->HostCapability.V30Support == TRUE) {
+    if ((CardData->OCRRegister.V270_V360 & BIT2) == BIT2) {
+      Argument |= BIT17;
+    } else if ((CardData->OCRRegister.V270_V360 & BIT3) == BIT3) {
+      Argument |= BIT18;
+    }
+  } else if (SdHostIo->HostCapability.V33Support == TRUE) {
+     if ((CardData->OCRRegister.V270_V360 & BIT5) == BIT5) {
+       Argument |= BIT20;
+     } else if ((CardData->OCRRegister.V270_V360 & BIT6) == BIT6) {
+       Argument |= BIT21;
+     }
+  }
+
+  if (Argument == 0) {
+     //
+     // No matched support voltage
+     //
+     PutCardInactive (CardData);
+     DEBUG ((EFI_D_ERROR, "No matched voltage for this card\n"));
+     Status = EFI_UNSUPPORTED;
+     goto Exit;
+  }
+
+  CardData->CardType = SdMemoryCard;
+  if (SdCommand8Support == TRUE) {
+   CardData->CardType = SdMemoryCard2;
+   DEBUG ((EFI_D_INFO, "SD_SEND_OP_COND, SD 2.0 or above standard card was identified\n"));
+  }
+
+  if ((CardData->OCRRegister.AccessMode & BIT1) == BIT1) {
+    CardData->CardType = SdMemoryCard2High;
+    DEBUG ((EFI_D_INFO, "SD_SEND_OP_COND, SD 2.0 or above high capacity card was identified\n"));
+  }
+
+Exit:
+  return Status;
+}
+
+
+/**
+  MMC card high/low voltage selection function
+
+  @param[in]  CardData               Pointer to CARD_DATA.
+
+  @retval     EFI_SUCCESS
+  @retval     EFI_INVALID_PARAMETER
+  @retval     EFI_UNSUPPORTED
+  @retval     EFI_BAD_BUFFER_SIZE
+
+**/
+EFI_STATUS
+MMCCardVoltageSelection (
+  IN  CARD_DATA              *CardData
+  )
+{
+  EFI_STATUS                 Status;
+  UINT8                      Retry;
+  UINT32                     TimeOut;
+
+  Status = EFI_SUCCESS;
+
+  //
+  // First try the high voltage, then if supported choose the low voltage
+  //
+  for (Retry = 0; Retry < 3; Retry++) {
+    //
+    // To bring back the normal MMC card to work
+    // after sending the SD command. Otherwise some
+    // card could not work
+
+    Status  = SendCommand (
+                CardData,
+                GO_IDLE_STATE,
+                0,
+                NoData,
+                NULL,
+                0,
+                ResponseNo,
+                TIMEOUT_COMMAND,
+                NULL
+                );
+
+    if (EFI_ERROR (Status)) {
+      DEBUG ((EFI_D_ERROR, "GO_IDLE_STATE Fail Status = 0x%x\n", Status));
+      continue;
+    }
+    //
+    //CE-ATA device needs long delay
+    //
+    gBS->Stall ((Retry + 1) * 50 * 1000);
+
+    //
+    // Get OCR register to check voltage support, first time the OCR is 0
+    //
+    Status  = SendCommand (
+                CardData,
+                SEND_OP_COND,
+                0,
+                NoData,
+                NULL,
+                0,
+                ResponseR3,
+                TIMEOUT_COMMAND,
+                (UINT32 *) &(CardData->OCRRegister)
+                );
+
+    if (!EFI_ERROR (Status)) {
+      break;
+    }
+  }
+
+  if (Retry == 3) {
+    DEBUG ((EFI_D_ERROR, "SEND_OP_COND Fail Status = 0x%x\n", Status));
+    Status = EFI_DEVICE_ERROR;
+    goto Exit;
+  }
+
+  //
+  // TimeOut Value, 5000 * 100 * 1000 = 5 s
+  //
+  TimeOut = 5000;
+
+  do {
+    Status  = SendCommand (
+                CardData,
+                SEND_OP_COND,
+                0x40300000,
+                NoData,
+                NULL,
+                0,
+                ResponseR3,
+                TIMEOUT_COMMAND,
+                (UINT32 *) &(CardData->OCRRegister)
+                );
+
+    if (EFI_ERROR (Status)) {
+      DEBUG ((EFI_D_ERROR, "SEND_OP_COND Fail Status = 0x%x\n", Status));
+      goto Exit;
+    }
+
+    gBS->Stall (1 * 1000);
+    TimeOut--;
+    if (TimeOut == 0) {
+      Status = EFI_TIMEOUT;
+      DEBUG ((EFI_D_ERROR, "Card is always in busy state\n"));
+      goto Exit;
+    }
+  } while (CardData->OCRRegister.Busy != 1);
+
+  if (CardData->OCRRegister.AccessMode == 2) {
+    DEBUG ((EFI_D_INFO, "eMMC Card is High Capacity\n"));
+    CardData->CardType = MMCCardHighCap;
+  }
+
+Exit:
+  return Status;
+}
+
+
+/**
+  This function set the bus and device width for MMC card.
+
+  @param[in]  CardData               Pointer to CARD_DATA.
+  @param[in]  BusWidth               1, 4, 8 bits.
+  @param[in]  EnableDDRMode          Enable DDR Mode.
+
+  @retval     EFI_SUCCESS
+  @retval     EFI_UNSUPPORTED
+  @retval     EFI_INVALID_PARAMETER
+
+**/
+EFI_STATUS
+MMCCardSetBusWidth (
+  IN  CARD_DATA              *CardData,
+  IN  UINT8                  BusWidth,
+  IN  BOOLEAN                EnableDDRMode
+  )
+{
+  EFI_STATUS                 Status;
+  EFI_SD_HOST_IO_PROTOCOL    *SdHostIo;
+  SWITCH_ARGUMENT            SwitchArgument;
+  UINT8                      Value;
+
+  SdHostIo = CardData->SdHostIo;
+  Value = 0;
+  switch (BusWidth) {
+    case 8:
+      if (EnableDDRMode)
+        Value = 6;
+      else
+      Value = 2;
+      break;
+
+    case 4:
+      if (EnableDDRMode)
+        Value = 5;
+      else
+      Value = 1;
+      break;
+
+    case 1:
+      if (EnableDDRMode)    // Bus width 1 is not supported in ddr mode
+        return EFI_UNSUPPORTED;
+      Value = 0;
+      break;
+
+    default:
+     ASSERT (0);
+  }
+
+  ZeroMem (&SwitchArgument, sizeof (SWITCH_ARGUMENT));
+  SwitchArgument.CmdSet = 0;
+  SwitchArgument.Value  = Value;
+  SwitchArgument.Index  = (UINT32) ((UINTN)
+  (&(CardData->ExtCSDRegister.BUS_WIDTH)) - (UINTN) (&(CardData->ExtCSDRegister)));
+  SwitchArgument.Access = WriteByte_Mode;
+  Status  = SendCommand (
+              CardData,
+              SWITCH,
+              *(UINT32 *) &SwitchArgument,
+              NoData,
+              NULL,
+              0,
+              ResponseR1b,
+              TIMEOUT_COMMAND,
+              (UINT32 *) &(CardData->CardStatus)
+              );
+
+  if (!EFI_ERROR (Status)) {
+     Status  = SendCommand (
+                 CardData,
+                 SEND_STATUS,
+                 (CardData->Address << 16),
+                 NoData,
+                 NULL,
+                 0,
+                 ResponseR1,
+                 TIMEOUT_COMMAND,
+                 (UINT32 *) &(CardData->CardStatus)
+                 );
+
+    if (EFI_ERROR (Status)) {
+      DEBUG ((EFI_D_ERROR, "SWITCH %d bits Fail\n", BusWidth));
+      goto Exit;
+    } else {
+      DEBUG ((EFI_D_ERROR, "MMCCardSetBusWidth:SWITCH Card Status:0x%x\n", *(UINT32 *) &(CardData->CardStatus)));
+      Status = SdHostIo->SetBusWidth (SdHostIo, BusWidth);
+      if (EFI_ERROR (Status)) {
+         DEBUG ((EFI_D_ERROR, "SWITCH set %d bits Fail\n", BusWidth));
+         goto Exit;
+      }
+      gBS->Stall (5 * 1000);
+    }
+  }
+
+  if (!EnableDDRMode) {     // CMD19 and CMD14 are illegal commands in ddr mode
+
+  Status = MMCCardBusWidthTest (CardData, BusWidth);
+  if (EFI_ERROR (Status)) {
+    DEBUG ((EFI_D_ERROR, "MMCCardBusWidthTest %d bit Fail\n", BusWidth));
+    goto Exit;
+    }
+  }
+
+  CardData->CurrentBusWidth = BusWidth;
+
+Exit:
+  return Status;
+}
+
+
+/**
+  MMC/SD card init function
+
+  @param[in]  CardData             Pointer to CARD_DATA.
+
+  @retval     EFI_SUCCESS
+  @retval     others
+
+**/
+EFI_STATUS
+MMCSDCardInit (
+  IN  CARD_DATA              *CardData
+  )
+{
+  EFI_STATUS                 Status;
+  EFI_SD_HOST_IO_PROTOCOL    *SdHostIo;
+  SWITCH_ARGUMENT            SwitchArgument;
+  UINT32                     Data;
+  UINT32                     Argument;
+  UINT32                     nIndex;
+  UINT8                      PowerValue;
+  BOOLEAN                    EnableDDRMode;
+
+  ASSERT (CardData != NULL);
+  SdHostIo = CardData->SdHostIo;
+  EnableDDRMode = FALSE;
+
+  CardData->CardType = UnknownCard;
+  Status = GetCardType (CardData);
+  if (EFI_ERROR (Status)) {
+    goto Exit;
+  }
+  DEBUG ((DEBUG_INFO, "CardData->CardType  0x%x\n", CardData->CardType));
+
+  ASSERT (CardData->CardType != UnknownCard);
+
+  //
+  // MMC, SD card need host auto stop command support
+  //
+  SdHostIo->EnableAutoStopCmd (SdHostIo, TRUE);
+
+  if (CardData->CardType == MMCCard) {
+    Status = MMCCardVoltageSelection (CardData);
+    if (EFI_ERROR (Status)) {
+      goto Exit;
+    }
+  }
+
+  //
+  // Get CID Register
+  //
+  Status  = SendCommand (
+              CardData,
+              ALL_SEND_CID,
+              0,
+              NoData,
+              NULL,
+              0,
+              ResponseR2,
+              TIMEOUT_COMMAND,
+              (UINT32 *) &(CardData->CIDRegister)
+              );
+
+  if (EFI_ERROR (Status)) {
+    DEBUG ((EFI_D_ERROR, "ALL_SEND_CID Fail Status = 0x%x\n", Status));
+    goto Exit;
+  } else {
+    //
+    // Dump out the Card ID data
+    //
+    DEBUG ((EFI_D_INFO, "Product Name: "));
+    for (nIndex=0; nIndex<6; nIndex++ ) {
+      DEBUG ((EFI_D_INFO, "%c", CardData->CIDRegister.PNM[nIndex]));
+    }
+    DEBUG ((EFI_D_INFO, "\nApplication ID : %d\n", CardData->CIDRegister.OID));
+    DEBUG ((EFI_D_INFO, "Manufacturer ID  : %d\n", CardData->CIDRegister.MID));
+    DEBUG ((EFI_D_INFO, "Revision ID      : %d\n", CardData->CIDRegister.PRV));
+    DEBUG ((EFI_D_INFO, "Serial Number    : %d\n", CardData->CIDRegister.PSN));
+  }
+
+  //
+  // SET_RELATIVE_ADDR
+  //
+  if (CardData->CardType == MMCCard  || CardData->CardType == MMCCardHighCap) {
+    //
+    // Hard code the RCA address
+    //
+    CardData->Address = 1;
+
+    //
+    // Set RCA Register
+    //
+    Status  = SendCommand (
+                CardData,
+                SET_RELATIVE_ADDR,
+                (CardData->Address << 16),
+                NoData,
+                NULL,
+                0,
+                ResponseR1,
+                TIMEOUT_COMMAND,
+                (UINT32 *) &(CardData->CardStatus)
+                );
+
+    if (EFI_ERROR (Status)) {
+      DEBUG ((EFI_D_ERROR, "SET_RELATIVE_ADDR Fail Status = 0x%x\n", Status));
+      goto Exit;
+    }
+  } else {
+    Data = 0;
+    Status  = SendCommand (
+                CardData,
+                SET_RELATIVE_ADDR,
+                0,
+                NoData,
+                NULL,
+                0,
+                ResponseR6,
+                TIMEOUT_COMMAND,
+                &Data
+                );
+
+    if (EFI_ERROR (Status)) {
+      DEBUG ((EFI_D_ERROR, "SET_RELATIVE_ADDR Fail Status = 0x%x\n", Status));
+      goto Exit;
+    }
+
+    CardData->Address = (UINT16) (Data >> 16);
+    *(UINT32 *) &CardData->CardStatus      = Data & 0x1FFF;
+    CardData->CardStatus.ERROR             = (Data >> 13) & 0x1;
+    CardData->CardStatus.ILLEGAL_COMMAND   = (Data >> 14) & 0x1;
+    CardData->CardStatus.COM_CRC_ERROR     = (Data >> 15) & 0x1;
+    Status = CheckCardStatus (*(UINT32 *) &CardData->CardStatus);
+    if (EFI_ERROR (Status)) {
+      DEBUG ((EFI_D_ERROR, "SET_RELATIVE_ADDR Fail Status = 0x%x\n", Status));
+      goto Exit;
+    }
+  }
+
+  //
+  // Get CSD Register
+  //
+  Status  = SendCommand (
+              CardData,
+              SEND_CSD,
+              (CardData->Address << 16),
+              NoData,
+              NULL,
+              0,
+              ResponseR2,
+              TIMEOUT_COMMAND,
+              (UINT32 *) &(CardData->CSDRegister)
+              );
+
+  if (EFI_ERROR (Status)) {
+    DEBUG ((EFI_D_ERROR, "SEND_CSD Fail Status = 0x%x\n", Status));
+    goto Exit;
+  }
+
+  DEBUG ((EFI_D_INFO, "CardData->CSDRegister.SPEC_VERS = 0x%x\n", CardData->CSDRegister.SPEC_VERS));
+  DEBUG ((EFI_D_INFO, "CardData->CSDRegister.CSD_STRUCTURE = 0x%x\n", CardData->CSDRegister.CSD_STRUCTURE));
+
+  Status = CaculateCardParameter (CardData);
+  if (EFI_ERROR (Status)) {
+    goto Exit;
+  }
+
+
+  //
+  // It is platform and hardware specific, need hadrware engineer input
+  //
+  if (CardData->CSDRegister.DSR_IMP == 1) {
+    //
+    // Default is 0x404
+    //
+    Status  = SendCommand (
+                CardData,
+                SET_DSR,
+                (DEFAULT_DSR_VALUE << 16),
+                NoData,
+                NULL,
+                0,
+                ResponseNo,
+                TIMEOUT_COMMAND,
+                NULL
+                );
+
+    if (EFI_ERROR (Status)) {
+      DEBUG ((EFI_D_ERROR, "SET_DSR Fail Status = 0x%x\n", Status));
+      //
+      // Assume can operate even fail
+      //
+    }
+  }
+  //
+  // Change clock frequency from 400KHz to max supported when not in high speed mode
+  //
+  Status = SdHostIo->SetClockFrequency (SdHostIo, CardData->MaxFrequency);
+  if (EFI_ERROR (Status)) {
+    DEBUG ((EFI_D_ERROR, "MMCSDCardInit:Fail to SetClockFrequency \n"));
+    goto Exit;
+  }
+
+  //
+  // Put the card into tran state
+  //
+  Status = SendCommand (
+             CardData,
+             SELECT_DESELECT_CARD,
+             (CardData->Address << 16),
+             NoData,
+             NULL,
+             0,
+             ResponseR1,
+             TIMEOUT_COMMAND,
+             (UINT32 *) &(CardData->CardStatus)
+             );
+
+  if (EFI_ERROR (Status)) {
+    DEBUG ((EFI_D_ERROR, "SELECT_DESELECT_CARD Fail Status = 0x%x\n", Status));
+    goto Exit;
+  }
+  gBS->Stall (5 * 1000);
+  //
+  // No need to do so
+  //
+  //
+  Status  = SendCommand (
+              CardData,
+              SEND_STATUS,
+              (CardData->Address << 16),
+              NoData,
+              NULL,
+              0,
+              ResponseR1,
+              TIMEOUT_COMMAND,
+              (UINT32 *) &(CardData->CardStatus)
+              );
+
+  if (EFI_ERROR (Status)) {
+    DEBUG ((EFI_D_ERROR, "SELECT_DESELECT_CARD SEND_STATUS Fail Status = 0x%x\n", Status));
+    goto Exit;
+  }
+  if (CardData->CardType == MMCCard  || CardData->CardType == MMCCardHighCap) {
+    //
+    // Only V4.0 and above supports more than 1 bits and high speed
+    //
+    if (CardData->CSDRegister.SPEC_VERS >= 4) {
+      //
+      // Get ExtCSDRegister
+      //
+      Status  = SendCommand (
+                  CardData,
+                  SEND_EXT_CSD,
+                  0x0,
+                  InData,
+                  CardData->AlignedBuffer,
+                  sizeof (EXT_CSD),
+                  ResponseR1,
+                  TIMEOUT_DATA,
+                  (UINT32 *) &(CardData->CardStatus)
+                  );
+
+      if (EFI_ERROR (Status)) {
+        DEBUG ((EFI_D_ERROR, "SEND_EXT_CSD Fail Status = 0x%x\n", Status));
+        goto Exit;
+      }
+
+      CopyMem (&(CardData->ExtCSDRegister), CardData->AlignedBuffer, sizeof(EXT_CSD));
+
+      //
+      // Recaculate the block number for >2G MMC card
+      //
+      Data  = (CardData->ExtCSDRegister.SEC_COUNT[0]) |
+              (CardData->ExtCSDRegister.SEC_COUNT[1] << 8) |
+              (CardData->ExtCSDRegister.SEC_COUNT[2] << 16) |
+              (CardData->ExtCSDRegister.SEC_COUNT[3] << 24);
+
+      if (Data != 0) {
+        CardData->BlockNumber = Data;
+      }
+      DEBUG ((DEBUG_INFO, "CardData->BlockNumber  %d\n", Data));
+      DEBUG ((EFI_D_ERROR, "CardData->ExtCSDRegister.CARD_TYPE -> %d\n", (UINTN)CardData->ExtCSDRegister.CARD_TYPE));
+      if ((CardData->ExtCSDRegister.CARD_TYPE & BIT2)||
+          (CardData->ExtCSDRegister.CARD_TYPE & BIT3)) {
+
+      }
+      //
+      // Check current chipset capability and the plugged-in card
+      // whether supports HighSpeed
+      //
+      if (SdHostIo->HostCapability.HighSpeedSupport) {
+
+        //
+        // Change card timing to high speed interface timing
+        //
+        ZeroMem (&SwitchArgument, sizeof (SWITCH_ARGUMENT));
+        SwitchArgument.CmdSet = 0;
+        SwitchArgument.Value  = 1;
+        SwitchArgument.Index  = (UINT32) ((UINTN)
+        (&(CardData->ExtCSDRegister.HS_TIMING)) - (UINTN) (&(CardData->ExtCSDRegister)));
+        SwitchArgument.Access = WriteByte_Mode;
+        Status  = SendCommand (
+                    CardData,
+                    SWITCH,
+                    *(UINT32 *) &SwitchArgument,
+                    NoData,
+                    NULL,
+                    0,
+                    ResponseR1b,
+                    TIMEOUT_COMMAND,
+                    (UINT32 *) &(CardData->CardStatus)
+                    );
+
+        if (EFI_ERROR (Status)) {
+          DEBUG ((EFI_D_ERROR, "MMCSDCardInit:SWITCH frequency Fail Status = 0x%x\n", Status));
+        }
+
+        gBS->Stall (5 * 1000);
+
+        if (!EFI_ERROR (Status)) {
+          Status  = SendCommand (
+                      CardData,
+                      SEND_STATUS,
+                      (CardData->Address << 16),
+                      NoData,
+                      NULL,
+                      0,
+                      ResponseR1,
+                      TIMEOUT_COMMAND,
+                      (UINT32 *) &(CardData->CardStatus)
+                      );
+
+          if (!EFI_ERROR (Status)) {
+            if (EnableDDRMode) {
+              DEBUG ((EFI_D_ERROR, "Enable ddr mode on host controller\n"));
+              SdHostIo->SetDDRMode (SdHostIo, TRUE);
+            } else  {
+              DEBUG ((EFI_D_ERROR, "Enable high speed mode on host controller\n"));
+              SdHostIo->SetHighSpeedMode (SdHostIo, TRUE);
+            }
+            //
+            // Change host clock to support high speed and enable chispet to
+            // support speed
+            //
+            if ((CardData->ExtCSDRegister.CARD_TYPE & BIT1) != 0) {
+              Status = SdHostIo->SetClockFrequency (SdHostIo, FREQUENCY_MMC_PP_HIGH);
+            } else if ((CardData->ExtCSDRegister.CARD_TYPE & BIT0) != 0) {
+              Status = SdHostIo->SetClockFrequency (SdHostIo, FREQUENCY_MMC_PP);
+            } else {
+              Status = EFI_UNSUPPORTED;
+            }
+            if (EFI_ERROR (Status)) {
+              DEBUG ((EFI_D_ERROR, "MMCSDCardInit:Fail to SetClockFrequency \n"));
+              goto Exit;
+            }
+            //
+            // It seems no need to stall after changing bus freqeuncy.
+            // It is said that the freqeuncy can be changed at any time. Just appends 8 clocks after command.
+            // But SetClock alreay has delay.
+            //
+          }
+        }
+
+      }
+
+      //
+      // Prefer wide bus width for performance
+      //
+      //
+      // Set to BusWidth bits mode, only version 4.0 or above support more than 1 bits
+      //
+      if (SdHostIo->HostCapability.BusWidth8 == TRUE) {
+         Status = MMCCardSetBusWidth (CardData, 8, EnableDDRMode);
+         if (EFI_ERROR (Status)) {
+            //
+            // CE-ATA may support 8 bits and 4 bits, but has no software method for detection
+            //
+            Status = MMCCardSetBusWidth (CardData, 4, EnableDDRMode);
+            if (EFI_ERROR (Status)) {
+              goto Exit;
+            }
+         }
+      } else if (SdHostIo->HostCapability.BusWidth4 == TRUE) {
+         Status = MMCCardSetBusWidth (CardData, 4, EnableDDRMode);
+         if (EFI_ERROR (Status)) {
+           goto Exit;
+         }
+      }
+
+      PowerValue = 0;
+
+      if (CardData->CurrentBusWidth == 8) {
+        if ((CardData->ExtCSDRegister.CARD_TYPE & BIT1) != 0) {
+          PowerValue = CardData->ExtCSDRegister.PWR_CL_52_360;
+          PowerValue = PowerValue >> 4;
+        } else if ((CardData->ExtCSDRegister.CARD_TYPE & BIT0) != 0) {
+          PowerValue = CardData->ExtCSDRegister.PWR_CL_26_360;
+          PowerValue = PowerValue >> 4;
+        }
+      } else if (CardData->CurrentBusWidth == 4) {
+         if ((CardData->ExtCSDRegister.CARD_TYPE & BIT1) != 0) {
+          PowerValue = CardData->ExtCSDRegister.PWR_CL_52_360;
+          PowerValue = PowerValue & 0xF;
+         } else if ((CardData->ExtCSDRegister.CARD_TYPE & BIT0) != 0) {
+           PowerValue = CardData->ExtCSDRegister.PWR_CL_26_360;
+           PowerValue = PowerValue & 0xF;
+         }
+      }
+
+      if (PowerValue != 0) {
+        //
+        // Update Power Class
+        //
+        ZeroMem (&SwitchArgument, sizeof (SWITCH_ARGUMENT));
+        SwitchArgument.CmdSet = 0;
+        SwitchArgument.Value  = PowerValue;
+        SwitchArgument.Index  = (UINT32) ((UINTN)
+        (&(CardData->ExtCSDRegister.POWER_CLASS)) - (UINTN) (&(CardData->ExtCSDRegister)));
+        SwitchArgument.Access = WriteByte_Mode;
+        Status  = SendCommand (
+                    CardData,
+                    SWITCH,
+                    *(UINT32 *) &SwitchArgument,
+                    NoData,
+                    NULL,
+                    0,
+                    ResponseR1b,
+                    TIMEOUT_COMMAND,
+                    (UINT32 *) &(CardData->CardStatus)
+                    );
+
+         if (!EFI_ERROR (Status)) {
+           Status  = SendCommand (
+                       CardData,
+                       SEND_STATUS,
+                       (CardData->Address << 16),
+                       NoData,
+                       NULL,
+                       0,
+                       ResponseR1,
+                       TIMEOUT_COMMAND,
+                       (UINT32 *) &(CardData->CardStatus)
+                       );
+
+           if (EFI_ERROR (Status)) {
+             DEBUG ((EFI_D_ERROR, "SWITCH Power Class Fail Status = 0x%x\n", Status));
+           }
+         }
+      }
+
+    } else {
+      DEBUG ((EFI_D_ERROR, "MMC Card version %d only supportes 1 bits at lower transfer speed\n",CardData->CSDRegister.SPEC_VERS));
+    }
+  } else {
+      //
+      // Pin 1, at power up this line has a 50KOhm pull up enabled in the card.
+      // This pull-up should be disconnected by the user, during regular data transfer,
+      // with SET_CLR_CARD_DETECT (ACMD42) command
+      //
+      Status  = SendAppCommand (
+                  CardData,
+                  SET_CLR_CARD_DETECT,
+                  0,
+                  NoData,
+                  NULL,
+                  0,
+                  ResponseR1,
+                  TIMEOUT_COMMAND,
+                  (UINT32 *) &(CardData->CardStatus)
+                  );
+
+      if (EFI_ERROR (Status)) {
+        DEBUG ((EFI_D_ERROR, "SET_CLR_CARD_DETECT Fail Status = 0x%x\n", Status));
+        goto Exit;
+      }
+
+      //
+      // Set Bus Width to 4
+      //
+      Status  = SendAppCommand (
+                  CardData,
+                  SET_BUS_WIDTH,
+                  SD_BUS_WIDTH_4,
+                  NoData,
+                  NULL,
+                  0,
+                  ResponseR1,
+                  TIMEOUT_COMMAND,
+                  (UINT32 *) &(CardData->CardStatus)
+                  );
+
+      if (EFI_ERROR (Status)) {
+        DEBUG ((EFI_D_ERROR, "SET_BUS_WIDTH 4 bits Fail Status = 0x%x\n", Status));
+        goto Exit;
+      }
+
+      Status = SdHostIo->SetBusWidth (SdHostIo, 4);
+      if (EFI_ERROR (Status)) {
+        goto Exit;
+      }
+      CardData->CurrentBusWidth = 4;
+
+      if ((SdHostIo->HostCapability.HighSpeedSupport == FALSE) ||
+          ((CardData->CSDRegister.CCC & BIT10) != BIT10)) {
+        //
+        // Host must support high speed
+        // Card must support Switch function
+        //
+        goto Exit;
+      }
+
+      //
+      // Mode = 0, group 1, function 1, check operation
+      //
+      Argument = 0xFFFF01;
+      ZeroMem (&CardData->SwitchStatus, sizeof (SWITCH_STATUS));
+
+      Status  = SendCommand (
+                  CardData,
+                  SWITCH_FUNC,
+                  Argument,
+                  InData,
+                  CardData->AlignedBuffer,
+                  sizeof (SWITCH_STATUS),
+                  ResponseR1,
+                  TIMEOUT_COMMAND,
+                  (UINT32 *) &(CardData->CardStatus)
+                  );
+
+      if (EFI_ERROR (Status)) {
+        goto Exit;
+      }
+      CopyMem (&(CardData->SwitchStatus), CardData->AlignedBuffer, sizeof (SWITCH_STATUS));
+
+      if ((CardData->SwitchStatus.DataStructureVersion == 0x0) ||
+          ((CardData->SwitchStatus.Group1BusyStatus & BIT1) != BIT1)) {
+        Argument = 0xFFFF01 | BIT31;
+        ZeroMem (&CardData->SwitchStatus, sizeof (SWITCH_STATUS));
+
+        Status  = SendCommand (
+                    CardData,
+                    SWITCH_FUNC,
+                    Argument,
+                    InData,
+                    CardData->AlignedBuffer,
+                    sizeof (SWITCH_STATUS),
+                    ResponseR1,
+                    TIMEOUT_COMMAND,
+                   (UINT32 *) &(CardData->CardStatus)
+                   );
+
+         if (EFI_ERROR (Status)) {
+            goto Exit;
+         }
+         CopyMem (&(CardData->SwitchStatus), CardData->AlignedBuffer, sizeof (SWITCH_STATUS));
+
+         if ((CardData->SwitchStatus.DataStructureVersion == 0x0) ||
+            ((CardData->SwitchStatus.Group1BusyStatus & BIT1) != BIT1)) {
+          gBS->Stall (1000);
+
+          //
+          // Change host clock
+          //
+          Status = SdHostIo->SetClockFrequency (SdHostIo, FREQUENCY_SD_PP_HIGH);
+          if (EFI_ERROR (Status)) {
+            goto Exit;
+          }
+
+         }
+      }
+  }
+  if (!((CardData->ExtCSDRegister.CARD_TYPE & BIT2) ||
+      (CardData->ExtCSDRegister.CARD_TYPE & BIT3))) {
+
+    //
+    // Set Block Length, to improve compatibility in case of some cards
+    //
+    Status  = SendCommand (
+                CardData,
+                SET_BLOCKLEN,
+                512,
+                NoData,
+                NULL,
+                0,
+                ResponseR1,
+                TIMEOUT_COMMAND,
+                (UINT32 *) &(CardData->CardStatus)
+                );
+
+    if (EFI_ERROR (Status)) {
+      DEBUG ((EFI_D_ERROR, "SET_BLOCKLEN Fail Status = 0x%x\n", Status));
+      goto Exit;
+    }
+  }
+  SdHostIo->SetBlockLength (SdHostIo, 512);
+
+Exit:
+  return Status;
+}
+
diff --git a/Silicon/BroxtonSoC/BroxtonSiPkg/SouthCluster/Sdio/Dxe/SD/SdMediaDeviceDxe/SdMediaDevice.c b/Silicon/BroxtonSoC/BroxtonSiPkg/SouthCluster/Sdio/Dxe/SD/SdMediaDeviceDxe/SdMediaDevice.c
new file mode 100644
index 0000000..ad0eb2c
--- /dev/null
+++ b/Silicon/BroxtonSoC/BroxtonSiPkg/SouthCluster/Sdio/Dxe/SD/SdMediaDeviceDxe/SdMediaDevice.c
@@ -0,0 +1,324 @@
+/** @file
+  The definition for SD media device driver model and blkio protocol routines.
+
+  Copyright (c) 2013 - 2016, Intel Corporation. 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 "SdMediaDevice.h"
+
+EFI_DRIVER_BINDING_PROTOCOL gSdMediaDeviceDriverBinding = {
+  SdMediaDeviceSupported,
+  SdMediaDeviceStart,
+  SdMediaDeviceStop,
+  0x20,
+  NULL,
+  NULL
+};
+
+
+/**
+  Entry point for EFI drivers.
+
+  @param[in]  ImageHandle      EFI_HANDLE.
+  @param[in]  SystemTable      EFI_SYSTEM_TABLE.
+
+  @retval     EFI_SUCCESS      Driver is successfully loaded.
+  @retval     Others           Failed.
+
+**/
+EFI_STATUS
+EFIAPI
+InitializeSdMediaDevice (
+  IN EFI_HANDLE           ImageHandle,
+  IN EFI_SYSTEM_TABLE     *SystemTable
+  )
+{
+  return EfiLibInstallDriverBindingComponentName2 (
+           ImageHandle,
+           SystemTable,
+           &gSdMediaDeviceDriverBinding,
+           ImageHandle,
+           &gSdMediaDeviceName,
+           &gSdMediaDeviceName2
+           );
+}
+
+
+/**
+  Test to see if this driver supports ControllerHandle. Any
+  ControllerHandle that has BlockIoProtocol installed will be supported.
+
+  @param[in]  This                 Protocol instance pointer.
+  @param[in]  Controller           Handle of device to test.
+  @param[in]  RemainingDevicePath  Not used.
+
+  @retval     EFI_SUCCESS          This driver supports this device.
+  @retval     EFI_UNSUPPORTED      This driver does not support this device.
+
+**/
+EFI_STATUS
+EFIAPI
+SdMediaDeviceSupported (
+  IN EFI_DRIVER_BINDING_PROTOCOL     *This,
+  IN EFI_HANDLE                      Controller,
+  IN EFI_DEVICE_PATH_PROTOCOL        *RemainingDevicePath
+  )
+{
+  EFI_STATUS                Status;
+  EFI_SD_HOST_IO_PROTOCOL   *SdHostIo;
+
+  //
+  // Test whether there is PCI IO Protocol attached on the controller handle.
+  //
+  Status = gBS->OpenProtocol (
+                  Controller,
+                  &gEfiSdHostIoProtocolGuid,
+                  (VOID **) &SdHostIo,
+                  This->DriverBindingHandle,
+                  Controller,
+                  EFI_OPEN_PROTOCOL_BY_DRIVER
+                  );
+
+  if (EFI_ERROR (Status)) {
+    goto Exit;
+  }
+
+  gBS->CloseProtocol (
+         Controller,
+         &gEfiSdHostIoProtocolGuid,
+         This->DriverBindingHandle,
+         Controller
+         );
+
+Exit:
+  return Status;
+}
+
+
+/**
+  Starting the SD Media Device Driver.
+
+  @param[in]  This                 Protocol instance pointer.
+  @param[in]  Controller           Handle of device to test.
+  @param[in]  RemainingDevicePath  Not used.
+
+  @retval     EFI_SUCCESS          This driver supports this device.
+  @retval     EFI_UNSUPPORTED      This driver does not support this device.
+  @retval     EFI_DEVICE_ERROR     This driver cannot be started due to device Error.
+                                   EFI_OUT_OF_RESOURCES- Failed due to resource shortage.
+
+**/
+EFI_STATUS
+EFIAPI
+SdMediaDeviceStart (
+  IN EFI_DRIVER_BINDING_PROTOCOL     *This,
+  IN EFI_HANDLE                      Controller,
+  IN EFI_DEVICE_PATH_PROTOCOL        *RemainingDevicePath
+  )
+{
+  EFI_STATUS                Status;
+  EFI_SD_HOST_IO_PROTOCOL   *SdHostIo;
+  CARD_DATA                 *CardData;
+
+  CardData = NULL;
+
+  //
+  // Open PCI I/O Protocol and save pointer to open protocol
+  // in private data area.
+  //
+  Status = gBS->OpenProtocol (
+                  Controller,
+                  &gEfiSdHostIoProtocolGuid,
+                  (VOID **) &SdHostIo,
+                  This->DriverBindingHandle,
+                  Controller,
+                  EFI_OPEN_PROTOCOL_BY_DRIVER
+                  );
+
+  if (EFI_ERROR (Status)) {
+    DEBUG ((EFI_D_ERROR, "SDMediaDeviceStart: Fail to open gEfiSdHostIoProtocolGuid \r\n"));
+    goto Exit;
+  }
+
+  Status = SdHostIo->DetectCardAndInitHost (SdHostIo);
+  if (EFI_ERROR (Status)) {
+    DEBUG ((EFI_D_INFO, "SdMediaDeviceStart: Fail to DetectCardAndInitHost \r\n"));
+    goto Exit;
+  }
+
+  CardData = (CARD_DATA *) AllocateZeroPool (sizeof (CARD_DATA));
+  if (CardData == NULL) {
+    Status =  EFI_OUT_OF_RESOURCES;
+    DEBUG ((EFI_D_ERROR, "SdMediaDeviceStart: Fail to AllocateZeroPool(CARD_DATA) \r\n"));
+    goto Exit;
+  }
+
+  ASSERT (SdHostIo->HostCapability.BoundarySize >= 4 * 1024);
+  CardData->RawBufferPointer = (UINT8 *) ((UINTN) DMA_MEMORY_TOP);
+  Status = gBS->AllocatePages (
+                  AllocateMaxAddress,
+                  EfiBootServicesData,
+                  EFI_SIZE_TO_PAGES (2 * SdHostIo->HostCapability.BoundarySize),
+                  (EFI_PHYSICAL_ADDRESS *) (&CardData->RawBufferPointer)
+                  );
+
+  if (CardData->RawBufferPointer == NULL) {
+    DEBUG ((EFI_D_ERROR, "SdMediaDeviceStart: Fail to AllocateZeroPool(2*x) \r\n"));
+    Status = EFI_OUT_OF_RESOURCES;
+    goto Exit;
+  }
+  CardData->AlignedBuffer = CardData->RawBufferPointer - ((UINTN) (CardData->RawBufferPointer) & (SdHostIo->HostCapability.BoundarySize - 1)) + SdHostIo->HostCapability.BoundarySize;
+
+  CardData->Signature = CARD_DATA_SIGNATURE;
+  CardData->SdHostIo  = SdHostIo;
+
+  Status = MMCSDCardInit (CardData);
+  if (EFI_ERROR (Status)) {
+    DEBUG ((EFI_D_ERROR, "SdMediaDeviceStart: Fail to MMCSDCardInit \r\n"));
+    goto Exit;
+  }
+  DEBUG ((EFI_D_INFO, "SdMediaDeviceStart: MMCSDCardInit SuccessFul\n"));
+
+  if (CardData->CardType == CEATACard) {
+    Status = CEATABlockIoInit (CardData);
+  } else {
+    Status = MMCSDBlockIoInit (CardData);
+  }
+
+  if (EFI_ERROR (Status)) {
+    DEBUG ((EFI_D_ERROR, "SdMediaDeviceStart: Fail to BlockIoInit \r\n"));
+    goto Exit;
+  }
+  DEBUG ((EFI_D_INFO, "SdMediaDeviceStart: BlockIo is successfully installed\n"));
+
+  Status = gBS->InstallProtocolInterface (
+                  &Controller,
+                  &gEfiBlockIoProtocolGuid,
+                  EFI_NATIVE_INTERFACE,
+                  &CardData->BlockIo
+                  );
+  if (EFI_ERROR (Status)) {
+    DEBUG ((EFI_D_ERROR, "SdMediaDeviceStart: Fail to install gEfiBlockIoProtocolGuid \r\n"));
+    goto Exit;
+  }
+
+  //
+  // Install the component name protocol
+  //
+  CardData->ControllerNameTable = NULL;
+
+  AddUnicodeString2 (
+    "eng",
+    gSdMediaDeviceName.SupportedLanguages,
+    &CardData->ControllerNameTable,
+    L"MMC/SD Media Device",
+    TRUE
+    );
+
+  AddUnicodeString2 (
+    "en",
+    gSdMediaDeviceName2.SupportedLanguages,
+    &CardData->ControllerNameTable,
+    L"MMC/Sd Media Device",
+    FALSE
+    );
+
+Exit:
+  if (EFI_ERROR (Status)) {
+    DEBUG ((EFI_D_INFO, "SdMediaDeviceStart: End with failure\r\n"));
+    if (CardData != NULL) {
+      if (CardData->RawBufferPointer != NULL) {
+        gBS->FreePages ((EFI_PHYSICAL_ADDRESS) (UINTN) CardData->RawBufferPointer, EFI_SIZE_TO_PAGES (2 * SdHostIo->HostCapability.BoundarySize));
+      }
+      FreePool (CardData);
+    }
+  }
+
+  return Status;
+}
+
+
+/**
+  Stop this driver on ControllerHandle. Support stoping any child handles
+  created by this driver.
+
+  @param[in]  This                 Protocol instance pointer.
+  @param[in]  Controller           Handle of device to stop driver on.
+  @param[in]  NumberOfChildren     Number of Children in the ChildHandleBuffer.
+  @param[in]  ChildHandleBuffer    List of handles for the children we need to stop.
+
+  @retval     EFI_SUCCESS
+  @retval     others
+
+**/
+EFI_STATUS
+EFIAPI
+SdMediaDeviceStop (
+  IN EFI_DRIVER_BINDING_PROTOCOL     *This,
+  IN EFI_HANDLE                      Controller,
+  IN UINTN                           NumberOfChildren,
+  IN EFI_HANDLE                      *ChildHandleBuffer
+  )
+{
+  EFI_STATUS                Status;
+  CARD_DATA                 *CardData;
+  EFI_BLOCK_IO_PROTOCOL     *BlockIo;
+
+  //
+  // First find BlockIo Protocol
+  //
+  Status = gBS->OpenProtocol (
+                  Controller,
+                  &gEfiBlockIoProtocolGuid,
+                  (VOID **) &BlockIo,
+                  This->DriverBindingHandle,
+                  Controller,
+                  EFI_OPEN_PROTOCOL_GET_PROTOCOL
+                  );
+
+  if (EFI_ERROR (Status)) {
+    return Status;
+  }
+
+  CardData  = CARD_DATA_FROM_THIS (BlockIo);
+
+  //
+  // Uninstall Block I/O protocol from the device handle
+  //
+  Status = gBS->UninstallProtocolInterface (
+                  Controller,
+                  &gEfiBlockIoProtocolGuid,
+                  BlockIo
+                  );
+
+  if (EFI_ERROR (Status)) {
+    return Status;
+  }
+
+  if (CardData != NULL) {
+    if (CardData->RawBufferPointer != NULL) {
+      gBS->FreePages ((EFI_PHYSICAL_ADDRESS) (UINTN) CardData->RawBufferPointer, EFI_SIZE_TO_PAGES (2 * CardData->SdHostIo->HostCapability.BoundarySize));
+    }
+    FreeUnicodeStringTable (CardData->ControllerNameTable);
+    FreePool (CardData);
+  }
+
+  gBS->CloseProtocol (
+         Controller,
+         &gEfiSdHostIoProtocolGuid,
+         This->DriverBindingHandle,
+         Controller
+         );
+
+  return EFI_SUCCESS;
+}
+
diff --git a/Silicon/BroxtonSoC/BroxtonSiPkg/SouthCluster/Sdio/Dxe/SD/SdMediaDeviceDxe/SdMediaDevice.h b/Silicon/BroxtonSoC/BroxtonSiPkg/SouthCluster/Sdio/Dxe/SD/SdMediaDeviceDxe/SdMediaDevice.h
new file mode 100644
index 0000000..fe3c4fa
--- /dev/null
+++ b/Silicon/BroxtonSoC/BroxtonSiPkg/SouthCluster/Sdio/Dxe/SD/SdMediaDeviceDxe/SdMediaDevice.h
@@ -0,0 +1,466 @@
+/** @file
+  The definition for SD media device driver model and blkio protocol routines.
+
+  Copyright (c) 2013 - 2016, Intel Corporation. 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 _SD_MEDIA_DEVICE_H_
+#define _SD_MEDIA_DEVICE_H_
+
+#include <Uefi.h>
+#include <Protocol/PciIo.h>
+#include <Protocol/BlockIo.h>
+#include <Library/DebugLib.h>
+#include <Library/BaseMemoryLib.h>
+#include <Library/UefiDriverEntryPoint.h>
+#include <Library/UefiBootServicesTableLib.h>
+#include <Library/UefiLib.h>
+#include <Library/BaseLib.h>
+#include <Library/MemoryAllocationLib.h>
+#include <Library/PcdLib.h>
+#include <IndustryStandard/Pci22.h>
+#include "ComponentName.h"
+#include "SdHostIo.h"
+
+extern EFI_DRIVER_BINDING_PROTOCOL   gSdMediaDeviceDriverBinding;
+extern EFI_COMPONENT_NAME_PROTOCOL   gSdMediaDeviceName;
+extern EFI_COMPONENT_NAME2_PROTOCOL  gSdMediaDeviceName2;
+
+//
+// Define the region of memory used for DMA memory
+//
+#define DMA_MEMORY_TOP          0x0000000001FFFFFFULL
+#define CARD_DATA_SIGNATURE  SIGNATURE_32 ('c', 'a', 'r', 'd')
+
+//
+// Command timeout will be max 100 ms
+//
+#define  TIMEOUT_COMMAND     100
+#define  TIMEOUT_DATA        5000
+
+typedef enum{
+  UnknownCard = 0,
+  MMCCard,                // MMC card
+  MMCCardHighCap,         // MMC Card High Capacity
+  CEATACard,              // CE-ATA device
+  SdMemoryCard,           // SD 1.1 card
+  SdMemoryCard2,          // SD 2.0 or above standard card
+  SdMemoryCard2High       // SD 2.0 or above high capacity card
+} CARD_TYPE;
+
+typedef struct {
+  //
+  // BlockIO
+  //
+  UINTN                     Signature;
+  EFI_BLOCK_IO_PROTOCOL     BlockIo;
+  EFI_BLOCK_IO_MEDIA        BlockIoMedia;
+
+  EFI_SD_HOST_IO_PROTOCOL   *SdHostIo;
+  EFI_UNICODE_STRING_TABLE  *ControllerNameTable;
+  CARD_TYPE                 CardType;
+
+  UINT8                     CurrentBusWidth;
+  BOOLEAN                   DualVoltage;
+  BOOLEAN                   NeedFlush;
+  UINT8                     Reserved[3];
+
+  UINT16                    Address;
+  UINT32                    BlockLen;
+  UINT32                    MaxFrequency;
+  UINT64                    BlockNumber;
+
+  //
+  // Common used
+  //
+  CARD_STATUS               CardStatus;
+  OCR                       OCRRegister;
+  CID                       CIDRegister;
+  CSD                       CSDRegister;
+  EXT_CSD                   ExtCSDRegister;
+  UINT8                     *RawBufferPointer;
+  UINT8                     *AlignedBuffer;
+
+  //
+  // CE-ATA specific
+  //
+  TASK_FILE                 TaskFile;
+  IDENTIFY_DEVICE_DATA      IndentifyDeviceData;
+
+  //
+  //SD specific
+  //
+  SCR                       SCRRegister;
+  SD_STATUS_REG             SdSattus;
+  SWITCH_STATUS             SwitchStatus;
+} CARD_DATA;
+
+#define CARD_DATA_FROM_THIS(a) \
+    CR(a, CARD_DATA, BlockIo, CARD_DATA_SIGNATURE)
+
+/**
+  Test to see if this driver supports ControllerHandle. Any
+  ControllerHandle that has BlockIoProtocol installed will be supported.
+
+  @param[in]  This                 Protocol instance pointer.
+  @param[in]  Controller           Handle of device to test.
+  @param[in]  RemainingDevicePath  Not used.
+
+  @return     EFI_SUCCESS          This driver supports this device.
+  @return     EFI_UNSUPPORTED      This driver does not support this device.
+
+**/
+EFI_STATUS
+EFIAPI
+SdMediaDeviceSupported (
+  IN EFI_DRIVER_BINDING_PROTOCOL     *This,
+  IN EFI_HANDLE                      Controller,
+  IN EFI_DEVICE_PATH_PROTOCOL        *RemainingDevicePath
+  );
+
+/**
+  Starting the SD Media Device Driver.
+
+  @param[in]  This                 Protocol instance pointer.
+  @param[in]  Controller           Handle of device to test.
+  @param[in]  RemainingDevicePath  Not used.
+
+  @retval     EFI_SUCCESS          This driver supports this device.
+  @retval     EFI_UNSUPPORTED      This driver does not support this device.
+  @retval     EFI_DEVICE_ERROR     This driver cannot be started due to device Error.
+                                   EFI_OUT_OF_RESOURCES- Failed due to resource shortage.
+
+**/
+EFI_STATUS
+EFIAPI
+SdMediaDeviceStart (
+  IN EFI_DRIVER_BINDING_PROTOCOL     *This,
+  IN EFI_HANDLE                      Controller,
+  IN EFI_DEVICE_PATH_PROTOCOL        *RemainingDevicePath
+  );
+
+/**
+  Stop this driver on ControllerHandle. Support stoping any child handles
+  created by this driver.
+
+  @param[in]  This                 Protocol instance pointer.
+  @param[in]  Controller           Handle of device to stop driver on.
+  @param[in]  NumberOfChildren     Number of Children in the ChildHandleBuffer.
+  @param[in]  ChildHandleBuffer    List of handles for the children we need to stop.
+
+  @return     EFI_SUCCESS
+  @return     others
+
+**/
+EFI_STATUS
+EFIAPI
+SdMediaDeviceStop (
+  IN EFI_DRIVER_BINDING_PROTOCOL     *This,
+  IN EFI_HANDLE                      Controller,
+  IN UINTN                           NumberOfChildren,
+  IN EFI_HANDLE                      *ChildHandleBuffer
+  );
+
+/**
+  MMC/SD card init function
+
+  @param[in]  CardData             Pointer to CARD_DATA.
+
+  @return     EFI_SUCCESS
+  @return     others
+
+**/
+EFI_STATUS
+MMCSDCardInit (
+  IN  CARD_DATA    *CardData
+  );
+
+/**
+  Send command by using Host IO protocol
+
+  @param[in]  This                  A pointer to the EFI_SD_HOST_IO_PROTOCOL instance.
+  @param[in]  CommandIndex          The command index to set the command index field of command register.
+  @param[in]  Argument              Command argument to set the argument field of command register.
+  @param[in]  DataType              TRANSFER_TYPE, indicates no data, data in or data out.
+  @param[in]  Buffer                Contains the data read from / write to the device.
+  @param[in]  BufferSize            The size of the buffer.
+  @param[in]  ResponseType          RESPONSE_TYPE.
+  @param[in]  TimeOut               Time out value in 1 ms unit.
+  @param[out] ResponseData          Depending on the ResponseType, such as CSD or card status.
+
+  @retval     EFI_SUCCESS
+  @retval     EFI_INVALID_PARAMETER
+  @retval     EFI_UNSUPPORTED
+  @retval     EFI_DEVICE_ERROR
+
+**/
+EFI_STATUS
+SendCommand (
+  IN   CARD_DATA                  *CardData,
+  IN   UINT16                     CommandIndex,
+  IN   UINT32                     Argument,
+  IN   TRANSFER_TYPE              DataType,
+  IN   UINT8                      *Buffer, OPTIONAL
+  IN   UINT32                     BufferSize,
+  IN   RESPONSE_TYPE              ResponseType,
+  IN   UINT32                     TimeOut,
+  OUT  UINT32                     *ResponseData
+  );
+
+/**
+  Send the card APP_CMD command with the following command indicated by CommandIndex
+
+  @param[in]  CardData              Pointer to CARD_DATA.
+  @param[in]  CommandIndex          The command index to set the command index field of command register.
+  @param[in]  Argument              Command argument to set the argument field of command register.
+  @param[in]  DataType              TRANSFER_TYPE, indicates no data, data in or data out.
+  @param[in]  Buffer                Contains the data read from / write to the device.
+  @param[in]  BufferSize            The size of the buffer.
+  @param[in]  ResponseType          RESPONSE_TYPE.
+  @param[in]  TimeOut               Time out value in 1 ms unit.
+  @param[out] ResponseData          Depending on the ResponseType, such as CSD or card status.
+
+  @retval     EFI_SUCCESS
+  @retval     EFI_INVALID_PARAMETER
+  @retval     EFI_UNSUPPORTED
+  @retval     EFI_DEVICE_ERROR
+
+**/
+EFI_STATUS
+SendAppCommand (
+  IN   CARD_DATA                  *CardData,
+  IN   UINT16                     CommandIndex,
+  IN   UINT32                     Argument,
+  IN   TRANSFER_TYPE              DataType,
+  IN   UINT8                      *Buffer, OPTIONAL
+  IN   UINT32                     BufferSize,
+  IN   RESPONSE_TYPE              ResponseType,
+  IN   UINT32                     TimeOut,
+  OUT  UINT32                     *ResponseData
+  );
+
+/**
+  Send the card FAST_IO command
+
+  @param[in]      CardData               Pointer to CARD_DATA.
+  @param[in]      RegisterAddress        Register Address.
+  @param[in, out] RegisterData           Pointer to register Data.
+  @param[in]      Write                  TRUE for write, FALSE for read.
+
+  @retval         EFI_SUCCESS
+  @retval         EFI_UNSUPPORTED
+  @retval         EFI_INVALID_PARAMETER
+  @retval         EFI_DEVICE_ERROR
+
+**/
+EFI_STATUS
+FastIO (
+  IN      CARD_DATA   *CardData,
+  IN      UINT8       RegisterAddress,
+  IN  OUT UINT8       *RegisterData,
+  IN      BOOLEAN     Write
+  );
+
+/**
+  Judge whether it is CE-ATA device or not.
+
+  @param[in]  CardData             Pointer to CARD_DATA.
+
+  @retval     TRUE
+  @retval     FALSE
+
+**/
+BOOLEAN
+IsCEATADevice (
+  IN  CARD_DATA    *CardData
+  );
+
+/**
+  Send software reset
+
+  @param[in]  CardData                   Pointer to CARD_DATA.
+
+  @retval     EFI_SUCCESS                Success
+  @retval     EFI_DEVICE_ERROR           Hardware Error
+  @retval     EFI_INVALID_PARAMETER      Parameter is error
+  @retval     EFI_NO_MEDIA               No media
+  @retval     EFI_MEDIA_CHANGED          Media Change
+  @retval     EFI_BAD_BUFFER_SIZE        Buffer size is bad
+
+**/
+EFI_STATUS
+SoftwareReset (
+  IN  CARD_DATA    *CardData
+  );
+
+/**
+  SendATACommand specificed in Taskfile
+
+  @param[in]  CardData                  Pointer to CARD_DATA.
+  @param[in]  TaskFile                  Pointer to TASK_FILE.
+  @param[in]  Write                     TRUE means write, FALSE means read.
+  @param[in]  Buffer                    If NULL, means no data transfer, neither read nor write.
+  @param[in]  SectorCount               Buffer size in 512 bytes unit.
+
+  @retval     EFI_SUCCESS                Success
+  @retval     EFI_DEVICE_ERROR           Hardware Error
+  @retval     EFI_INVALID_PARAMETER      Parameter is error
+  @retval     EFI_NO_MEDIA               No media
+  @retval     EFI_MEDIA_CHANGED          Media Change
+  @retval     EFI_BAD_BUFFER_SIZE        Buffer size is bad
+
+**/
+EFI_STATUS
+SendATACommand (
+  IN  CARD_DATA   *CardData,
+  IN  TASK_FILE   *TaskFile,
+  IN  BOOLEAN     Write,
+  IN  UINT8       *Buffer,
+  IN  UINT16      SectorCount
+  );
+
+/**
+  IDENTIFY_DEVICE command
+
+  @param[in] CardData                   Pointer to CARD_DATA.
+
+  @retval    EFI_SUCCESS                Success
+  @retval    EFI_DEVICE_ERROR           Hardware Error
+  @retval    EFI_INVALID_PARAMETER      Parameter is error
+  @retval    EFI_NO_MEDIA               No media
+  @retval    EFI_MEDIA_CHANGED          Media Change
+  @retval    EFI_BAD_BUFFER_SIZE        Buffer size is bad
+
+**/
+EFI_STATUS
+IndentifyDevice (
+  IN  CARD_DATA    *CardData
+  );
+
+/**
+  FLUSH_CACHE_EXT command
+
+  @param[in]  CardData                   Pointer to CARD_DATA.
+
+  @retval     EFI_SUCCESS                Success
+  @retval     EFI_DEVICE_ERROR           Hardware Error
+  @retval     EFI_INVALID_PARAMETER      Parameter is error
+  @retval     EFI_NO_MEDIA               No media
+  @retval     EFI_MEDIA_CHANGED          Media Change
+  @retval     EFI_BAD_BUFFER_SIZE        Buffer size is bad
+
+**/
+EFI_STATUS
+FlushCache (
+  IN  CARD_DATA    *CardData
+  );
+
+/**
+  STANDBY_IMMEDIATE command
+
+  @param[in]  CardData                   Pointer to CARD_DATA.
+
+  @retval     EFI_SUCCESS                Success
+  @retval     EFI_DEVICE_ERROR           Hardware Error
+  @retval     EFI_INVALID_PARAMETER      Parameter is error
+  @retval     EFI_NO_MEDIA               No media
+  @retval     EFI_MEDIA_CHANGED          Media Change
+  @retval     EFI_BAD_BUFFER_SIZE        Buffer size is bad
+
+**/
+EFI_STATUS
+StandByImmediate (
+  IN  CARD_DATA    *CardData
+  );
+
+/**
+  READ_DMA_EXT command
+
+  @param[in]  CardData                   Pointer to CARD_DATA.
+  @param[in]  LBA                        The starting logical block address to read from on the device.
+  @param[in]  Buffer                     A pointer to the destination buffer for the data. The caller
+                                         is responsible for either having implicit or explicit ownership
+                                         of the buffer.
+  @param[in]  SectorCount                Size in 512 bytes unit.
+
+  @retval     EFI_SUCCESS                Success
+  @retval     EFI_DEVICE_ERROR           Hardware Error
+  @retval     EFI_INVALID_PARAMETER      Parameter is error
+  @retval     EFI_NO_MEDIA               No media
+  @retval     EFI_MEDIA_CHANGED          Media Change
+  @retval     EFI_BAD_BUFFER_SIZE        Buffer size is bad
+
+**/
+EFI_STATUS
+ReadDMAExt (
+  IN  CARD_DATA   *CardData,
+  IN  EFI_LBA     LBA,
+  IN  UINT8       *Buffer,
+  IN  UINT16      SectorCount
+  );
+
+/**
+  WRITE_DMA_EXT command
+
+  @param[in]  CardData                   Pointer to CARD_DATA.
+  @param[in]  LBA                        The starting logical block address to read from on the device.
+  @param[in]  Buffer                     A pointer to the destination buffer for the data. The caller
+                                         is responsible for either having implicit or explicit ownership
+                                         of the buffer.
+  @param[in]  SectorCount                Size in 512 bytes unit.
+
+  @retval     EFI_SUCCESS                Success
+  @retval     EFI_DEVICE_ERROR           Hardware Error
+  @retval     EFI_INVALID_PARAMETER      Parameter is error
+  @retval     EFI_NO_MEDIA               No media
+  @retval     EFI_MEDIA_CHANGED          Media Change
+  @retval     EFI_BAD_BUFFER_SIZE        Buffer size is bad
+
+**/
+EFI_STATUS
+WriteDMAExt (
+  IN  CARD_DATA   *CardData,
+  IN  EFI_LBA     LBA,
+  IN  UINT8       *Buffer,
+  IN  UINT16      SectorCount
+  );
+
+/**
+  CEATA card BlockIo init function.
+
+  @param[in]  CardData               Pointer to CARD_DATA.
+
+  @retval     EFI_SUCCESS
+  @retval     Others
+
+**/
+EFI_STATUS
+CEATABlockIoInit (
+  IN  CARD_DATA    *CardData
+  );
+
+/**
+  MMC/SD card BlockIo init function.
+
+  @param[in]  CardData               Pointer to CARD_DATA.
+
+  @retval     EFI_SUCCESS
+  @retval     Others
+
+**/
+EFI_STATUS
+MMCSDBlockIoInit (
+  IN  CARD_DATA    *CardData
+  );
+
+#endif
+
diff --git a/Silicon/BroxtonSoC/BroxtonSiPkg/SouthCluster/Sdio/Dxe/SD/SdMediaDeviceDxe/SdMediaDeviceDxe.inf b/Silicon/BroxtonSoC/BroxtonSiPkg/SouthCluster/Sdio/Dxe/SD/SdMediaDeviceDxe/SdMediaDeviceDxe.inf
new file mode 100644
index 0000000..e352b1d
--- /dev/null
+++ b/Silicon/BroxtonSoC/BroxtonSiPkg/SouthCluster/Sdio/Dxe/SD/SdMediaDeviceDxe/SdMediaDeviceDxe.inf
@@ -0,0 +1,64 @@
+## @file
+#  Component Description File For SdMediaDeviceDxe Module.
+#
+#  Copyright (c) 2013 - 2016, Intel Corporation. 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                    = 0x00010005
+  BASE_NAME                      = SdMediaDevice
+  FILE_GUID                      = E076205A-6EDC-4F68-A535-93C5D790B1DA
+  MODULE_TYPE                    = UEFI_DRIVER
+  VERSION_STRING                 = 1.0
+  ENTRY_POINT                    = InitializeSdMediaDevice
+
+#
+#  The following information is for reference only and not required by the build tools.
+#
+#  VALID_ARCHITECTURES           = IA32 X64 IPF EBC
+#
+#  DRIVER_BINDING                = gSdMediaDeviceDriverBinding
+#  COMPONENT_NAME                = gSdMediaDeviceName
+#  COMPONENT_NAME2               = gSdMediaDeviceName2
+#
+
+[Sources]
+  SdMediaDevice.c
+  SdMediaDevice.h
+  MMCSDTransfer.c
+  CEATA.c
+  CEATABlockIo.c
+  MMCSDBlockIo.c
+  ComponentName.c
+  ComponentName.h
+
+[Packages]
+  MdePkg/MdePkg.dec
+  MdeModulePkg/MdeModulePkg.dec
+  BroxtonSiPkg/BroxtonSiPkg.dec
+
+[LibraryClasses]
+  MemoryAllocationLib
+  BaseLib
+  UefiLib
+  UefiBootServicesTableLib
+  UefiDriverEntryPoint
+  BaseMemoryLib
+  DebugLib
+  PcdLib
+
+[Protocols]
+  gEfiPciIoProtocolGuid                         ## TO_START
+  gEfiSdHostIoProtocolGuid                      ## TO_START
+  gEfiBlockIoProtocolGuid                       ## BY_START
+
+[Pcd.common]
-- 
2.7.0.windows.1




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

end of thread, other threads:[~2017-06-09  5:27 UTC | newest]

Thread overview: 2+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2017-06-09  5:26 [Patch][edk2-platforms/devel-MinnowBoard3-UDK2017] Add eMMC/SD lushifex
2017-06-09  5:28 ` Wei, David

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