[edk2-devel] [PATCH V5 1/1] EmbeddedPkg: DwMmcHcDxe: Add support for Designware SDMMC driver

Loh, Tien Hock tien.hock.loh at intel.com
Tue Apr 27 10:27:56 UTC 2021


Hi Mike,

Just to be sure, I'm referring to refactoring to making functions that make calls that uses EFI_PCI_IO_PROTOCOL a generic function that will be implemented as a separate PciIo Sd driver, and Mmio Designware driver, and in the future other Mmio IP Sd driver.

I'll proceed if that is not a concern. If you have other suggestions on the paths I should pursue, please do inform me. 

Thanks

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



-=-=-=-=-=-=-=-=-=-=-=-
Groups.io Links: You receive all messages sent to this group.
View/Reply Online (#74446): https://edk2.groups.io/g/devel/message/74446
Mute This Topic: https://groups.io/mt/81516685/1813853
Group Owner: devel+owner at edk2.groups.io
Unsubscribe: https://edk2.groups.io/g/devel/unsub [edk2-devel-archive at redhat.com]
-=-=-=-=-=-=-=-=-=-=-=-






More information about the edk2-devel-archive mailing list