]> git.proxmox.com Git - mirror_edk2.git/commitdiff
MdeModulePkg/SdMmc: Add EDKII SD/MMC stack
authorFeng Tian <feng.tian@intel.com>
Wed, 23 Mar 2016 02:47:05 +0000 (10:47 +0800)
committerFeng Tian <feng.tian@intel.com>
Wed, 30 Mar 2016 03:27:41 +0000 (11:27 +0800)
This stack includes:
1. Dxe phase support by:
   1) SdMmcPciHcDxe driver to consume PciIo and produce
      SdMmcPassThru.
   2) SdDxe driver to consume SdMmcPassThru to produce
      BlkIo1/BlkIo2.
   3) EmmcDxe driver to consume SdMmcPassThru to produce
      BlkIo1/BlkIo2/SSP.

2. Pei phase support
   1) SdBlockIoPei driver to consume SdMmcHostController
      Ppi and produce VirutalBlkIo1&2.
   2) EmmcBlockIoPei driver to consume SdMmcHostController
      Ppi and produce VirutalBlkIo1&2.
   3) SdMmcPciHcPei driver to produce SdMmcHostController
      Ppi.

Contributed-under: TianoCore Contribution Agreement 1.0
Signed-off-by: Feng Tian <feng.tian@intel.com>
Reviewed-by: Hao Wu <hao.a.wu@intel.com>
52 files changed:
MdeModulePkg/Bus/Pci/SdMmcPciHcDxe/ComponentName.c [new file with mode: 0644]
MdeModulePkg/Bus/Pci/SdMmcPciHcDxe/EmmcDevice.c [new file with mode: 0644]
MdeModulePkg/Bus/Pci/SdMmcPciHcDxe/SdDevice.c [new file with mode: 0644]
MdeModulePkg/Bus/Pci/SdMmcPciHcDxe/SdMmcPciHcDxe.c [new file with mode: 0644]
MdeModulePkg/Bus/Pci/SdMmcPciHcDxe/SdMmcPciHcDxe.h [new file with mode: 0644]
MdeModulePkg/Bus/Pci/SdMmcPciHcDxe/SdMmcPciHcDxe.inf [new file with mode: 0644]
MdeModulePkg/Bus/Pci/SdMmcPciHcDxe/SdMmcPciHcDxe.uni [new file with mode: 0644]
MdeModulePkg/Bus/Pci/SdMmcPciHcDxe/SdMmcPciHcDxeExtra.uni [new file with mode: 0644]
MdeModulePkg/Bus/Pci/SdMmcPciHcDxe/SdMmcPciHci.c [new file with mode: 0644]
MdeModulePkg/Bus/Pci/SdMmcPciHcDxe/SdMmcPciHci.h [new file with mode: 0644]
MdeModulePkg/Bus/Pci/SdMmcPciHcPei/SdMmcPciHcPei.c [new file with mode: 0644]
MdeModulePkg/Bus/Pci/SdMmcPciHcPei/SdMmcPciHcPei.h [new file with mode: 0644]
MdeModulePkg/Bus/Pci/SdMmcPciHcPei/SdMmcPciHcPei.inf [new file with mode: 0644]
MdeModulePkg/Bus/Pci/SdMmcPciHcPei/SdMmcPciHcPei.uni [new file with mode: 0644]
MdeModulePkg/Bus/Pci/SdMmcPciHcPei/SdMmcPciHcPeiExtra.uni [new file with mode: 0644]
MdeModulePkg/Bus/Sd/EmmcBlockIoPei/EmmcBlockIoPei.c [new file with mode: 0644]
MdeModulePkg/Bus/Sd/EmmcBlockIoPei/EmmcBlockIoPei.h [new file with mode: 0644]
MdeModulePkg/Bus/Sd/EmmcBlockIoPei/EmmcBlockIoPei.inf [new file with mode: 0644]
MdeModulePkg/Bus/Sd/EmmcBlockIoPei/EmmcBlockIoPei.uni [new file with mode: 0644]
MdeModulePkg/Bus/Sd/EmmcBlockIoPei/EmmcBlockIoPeiExtra.uni [new file with mode: 0644]
MdeModulePkg/Bus/Sd/EmmcBlockIoPei/EmmcHcMem.c [new file with mode: 0644]
MdeModulePkg/Bus/Sd/EmmcBlockIoPei/EmmcHcMem.h [new file with mode: 0644]
MdeModulePkg/Bus/Sd/EmmcBlockIoPei/EmmcHci.c [new file with mode: 0644]
MdeModulePkg/Bus/Sd/EmmcBlockIoPei/EmmcHci.h [new file with mode: 0644]
MdeModulePkg/Bus/Sd/EmmcDxe/ComponentName.c [new file with mode: 0644]
MdeModulePkg/Bus/Sd/EmmcDxe/EmmcBlockIo.c [new file with mode: 0644]
MdeModulePkg/Bus/Sd/EmmcDxe/EmmcBlockIo.h [new file with mode: 0644]
MdeModulePkg/Bus/Sd/EmmcDxe/EmmcDxe.c [new file with mode: 0644]
MdeModulePkg/Bus/Sd/EmmcDxe/EmmcDxe.h [new file with mode: 0644]
MdeModulePkg/Bus/Sd/EmmcDxe/EmmcDxe.inf [new file with mode: 0644]
MdeModulePkg/Bus/Sd/EmmcDxe/EmmcDxe.uni [new file with mode: 0644]
MdeModulePkg/Bus/Sd/EmmcDxe/EmmcDxeExtra.uni [new file with mode: 0644]
MdeModulePkg/Bus/Sd/SdBlockIoPei/SdBlockIoPei.c [new file with mode: 0644]
MdeModulePkg/Bus/Sd/SdBlockIoPei/SdBlockIoPei.h [new file with mode: 0644]
MdeModulePkg/Bus/Sd/SdBlockIoPei/SdBlockIoPei.inf [new file with mode: 0644]
MdeModulePkg/Bus/Sd/SdBlockIoPei/SdBlockIoPei.uni [new file with mode: 0644]
MdeModulePkg/Bus/Sd/SdBlockIoPei/SdBlockIoPeiExtra.uni [new file with mode: 0644]
MdeModulePkg/Bus/Sd/SdBlockIoPei/SdHcMem.c [new file with mode: 0644]
MdeModulePkg/Bus/Sd/SdBlockIoPei/SdHcMem.h [new file with mode: 0644]
MdeModulePkg/Bus/Sd/SdBlockIoPei/SdHci.c [new file with mode: 0644]
MdeModulePkg/Bus/Sd/SdBlockIoPei/SdHci.h [new file with mode: 0644]
MdeModulePkg/Bus/Sd/SdDxe/ComponentName.c [new file with mode: 0644]
MdeModulePkg/Bus/Sd/SdDxe/SdBlockIo.c [new file with mode: 0644]
MdeModulePkg/Bus/Sd/SdDxe/SdBlockIo.h [new file with mode: 0644]
MdeModulePkg/Bus/Sd/SdDxe/SdDxe.c [new file with mode: 0644]
MdeModulePkg/Bus/Sd/SdDxe/SdDxe.h [new file with mode: 0644]
MdeModulePkg/Bus/Sd/SdDxe/SdDxe.inf [new file with mode: 0644]
MdeModulePkg/Bus/Sd/SdDxe/SdDxe.uni [new file with mode: 0644]
MdeModulePkg/Bus/Sd/SdDxe/SdDxeExtra.uni [new file with mode: 0644]
MdeModulePkg/Include/Ppi/SdMmcHostController.h [new file with mode: 0644]
MdeModulePkg/MdeModulePkg.dec
MdeModulePkg/MdeModulePkg.dsc

diff --git a/MdeModulePkg/Bus/Pci/SdMmcPciHcDxe/ComponentName.c b/MdeModulePkg/Bus/Pci/SdMmcPciHcDxe/ComponentName.c
new file mode 100644 (file)
index 0000000..3329929
--- /dev/null
@@ -0,0 +1,211 @@
+/** @file\r
+  UEFI Component Name(2) protocol implementation for SD/MMC host controller driver.\r
+\r
+  Copyright (c) 2015, Intel Corporation. All rights reserved.<BR>\r
+  This program and the accompanying materials\r
+  are licensed and made available under the terms and conditions of the BSD License\r
+  which accompanies this distribution.  The full text of the license may be found at\r
+  http://opensource.org/licenses/bsd-license.php\r
+\r
+  THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+  WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+\r
+**/\r
+\r
+#include "SdMmcPciHcDxe.h"\r
+\r
+//\r
+// EFI Component Name Protocol\r
+//\r
+GLOBAL_REMOVE_IF_UNREFERENCED EFI_COMPONENT_NAME_PROTOCOL gSdMmcPciHcComponentName = {\r
+  SdMmcPciHcComponentNameGetDriverName,\r
+  SdMmcPciHcComponentNameGetControllerName,\r
+  "eng"\r
+};\r
+\r
+//\r
+// EFI Component Name 2 Protocol\r
+//\r
+GLOBAL_REMOVE_IF_UNREFERENCED EFI_COMPONENT_NAME2_PROTOCOL gSdMmcPciHcComponentName2 = {\r
+  (EFI_COMPONENT_NAME2_GET_DRIVER_NAME)     SdMmcPciHcComponentNameGetDriverName,\r
+  (EFI_COMPONENT_NAME2_GET_CONTROLLER_NAME) SdMmcPciHcComponentNameGetControllerName,\r
+  "en"\r
+};\r
+\r
+GLOBAL_REMOVE_IF_UNREFERENCED EFI_UNICODE_STRING_TABLE mSdMmcPciHcDriverNameTable[] = {\r
+  { "eng;en", L"Edkii Sd/Mmc Host Controller Driver" },\r
+  { NULL , NULL }\r
+};\r
+\r
+GLOBAL_REMOVE_IF_UNREFERENCED EFI_UNICODE_STRING_TABLE mSdMmcPciHcControllerNameTable[] = {\r
+  { "eng;en", L"Edkii Sd/Mmc Host Controller" },\r
+  { NULL , NULL }\r
+};\r
+\r
+/**\r
+  Retrieves a Unicode string that is the user readable name of the driver.\r
+\r
+  This function retrieves the user readable name of a driver in the form of a\r
+  Unicode string. If the driver specified by This has a user readable name in\r
+  the language specified by Language, then a pointer to the driver name is\r
+  returned in DriverName, and EFI_SUCCESS is returned. If the driver specified\r
+  by This does not support the language specified by Language,\r
+  then EFI_UNSUPPORTED is returned.\r
+\r
+  @param  This[in]              A pointer to the EFI_COMPONENT_NAME2_PROTOCOL or\r
+                                EFI_COMPONENT_NAME_PROTOCOL instance.\r
+\r
+  @param  Language[in]          A pointer to a Null-terminated ASCII string\r
+                                array indicating the language. This is the\r
+                                language of the driver name that the caller is\r
+                                requesting, and it must match one of the\r
+                                languages specified in SupportedLanguages. The\r
+                                number of languages supported by a driver is up\r
+                                to the driver writer. Language is specified\r
+                                in RFC 4646 or ISO 639-2 language code format.\r
+\r
+  @param  DriverName[out]       A pointer to the Unicode string to return.\r
+                                This Unicode string is the name of the\r
+                                driver specified by This in the language\r
+                                specified by Language.\r
+\r
+  @retval EFI_SUCCESS           The Unicode string for the Driver specified by\r
+                                This and the language specified by Language was\r
+                                returned in DriverName.\r
+\r
+  @retval EFI_INVALID_PARAMETER Language is NULL.\r
+\r
+  @retval EFI_INVALID_PARAMETER DriverName is NULL.\r
+\r
+  @retval EFI_UNSUPPORTED       The driver specified by This does not support\r
+                                the language specified by Language.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+SdMmcPciHcComponentNameGetDriverName (\r
+  IN  EFI_COMPONENT_NAME_PROTOCOL     *This,\r
+  IN  CHAR8                           *Language,\r
+  OUT CHAR16                          **DriverName\r
+  )\r
+{\r
+  return LookupUnicodeString2 (\r
+           Language,\r
+           This->SupportedLanguages,\r
+           mSdMmcPciHcDriverNameTable,\r
+           DriverName,\r
+           (BOOLEAN)(This == &gSdMmcPciHcComponentName)\r
+           );\r
+}\r
+\r
+/**\r
+  Retrieves a Unicode string that is the user readable name of the controller\r
+  that is being managed by a driver.\r
+\r
+  This function retrieves the user readable name of the controller specified by\r
+  ControllerHandle and ChildHandle in the form of a Unicode string. If the\r
+  driver specified by This has a user readable name in the language specified by\r
+  Language, then a pointer to the controller name is returned in ControllerName,\r
+  and EFI_SUCCESS is returned.  If the driver specified by This is not currently\r
+  managing the controller specified by ControllerHandle and ChildHandle,\r
+  then EFI_UNSUPPORTED is returned.  If the driver specified by This does not\r
+  support the language specified by Language, then EFI_UNSUPPORTED is returned.\r
+\r
+  @param  This[in]              A pointer to the EFI_COMPONENT_NAME2_PROTOCOL or\r
+                                EFI_COMPONENT_NAME_PROTOCOL instance.\r
+\r
+  @param  ControllerHandle[in]  The handle of a controller that the driver\r
+                                specified by This is managing.  This handle\r
+                                specifies the controller whose name is to be\r
+                                returned.\r
+\r
+  @param  ChildHandle[in]       The handle of the child controller to retrieve\r
+                                the name of.  This is an optional parameter that\r
+                                may be NULL.  It will be NULL for device\r
+                                drivers.  It will also be NULL for a bus drivers\r
+                                that wish to retrieve the name of the bus\r
+                                controller.  It will not be NULL for a bus\r
+                                driver that wishes to retrieve the name of a\r
+                                child controller.\r
+\r
+  @param  Language[in]          A pointer to a Null-terminated ASCII string\r
+                                array indicating the language.  This is the\r
+                                language of the driver name that the caller is\r
+                                requesting, and it must match one of the\r
+                                languages specified in SupportedLanguages. The\r
+                                number of languages supported by a driver is up\r
+                                to the driver writer. Language is specified in\r
+                                RFC 4646 or ISO 639-2 language code format.\r
+\r
+  @param  ControllerName[out]   A pointer to the Unicode string to return.\r
+                                This Unicode string is the name of the\r
+                                controller specified by ControllerHandle and\r
+                                ChildHandle in the language specified by\r
+                                Language from the point of view of the driver\r
+                                specified by This.\r
+\r
+  @retval EFI_SUCCESS           The Unicode string for the user readable name in\r
+                                the language specified by Language for the\r
+                                driver specified by This was returned in\r
+                                DriverName.\r
+\r
+  @retval EFI_INVALID_PARAMETER ControllerHandle is not a valid EFI_HANDLE.\r
+\r
+  @retval EFI_INVALID_PARAMETER ChildHandle is not NULL and it is not a valid\r
+                                EFI_HANDLE.\r
+\r
+  @retval EFI_INVALID_PARAMETER Language is NULL.\r
+\r
+  @retval EFI_INVALID_PARAMETER ControllerName is NULL.\r
+\r
+  @retval EFI_UNSUPPORTED       The driver specified by This is not currently\r
+                                managing the controller specified by\r
+                                ControllerHandle and ChildHandle.\r
+\r
+  @retval EFI_UNSUPPORTED       The driver specified by This does not support\r
+                                the language specified by Language.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+SdMmcPciHcComponentNameGetControllerName (\r
+  IN  EFI_COMPONENT_NAME_PROTOCOL     *This,\r
+  IN  EFI_HANDLE                      ControllerHandle,\r
+  IN  EFI_HANDLE                      ChildHandle, OPTIONAL\r
+  IN  CHAR8                           *Language,\r
+  OUT CHAR16                          **ControllerName\r
+  )\r
+{\r
+  EFI_STATUS         Status;\r
+\r
+  if (Language == NULL || ControllerName == NULL) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  //\r
+  // This is a device driver, so ChildHandle must be NULL.\r
+  //\r
+  if (ChildHandle != NULL) {\r
+    return EFI_UNSUPPORTED;\r
+  }\r
+\r
+  //\r
+  // Make sure this driver is currently managing ControllerHandle\r
+  //\r
+  Status = EfiTestManagedDevice (\r
+             ControllerHandle,\r
+             gSdMmcPciHcDriverBinding.DriverBindingHandle,\r
+             &gEfiPciIoProtocolGuid\r
+             );\r
+  if (EFI_ERROR (Status)) {\r
+    return Status;\r
+  }\r
+\r
+  return LookupUnicodeString2 (\r
+           Language,\r
+           This->SupportedLanguages,\r
+           mSdMmcPciHcControllerNameTable,\r
+           ControllerName,\r
+           (BOOLEAN)(This == &gSdMmcPciHcComponentName)\r
+           );\r
+}\r
diff --git a/MdeModulePkg/Bus/Pci/SdMmcPciHcDxe/EmmcDevice.c b/MdeModulePkg/Bus/Pci/SdMmcPciHcDxe/EmmcDevice.c
new file mode 100644 (file)
index 0000000..443f93f
--- /dev/null
@@ -0,0 +1,1152 @@
+/** @file\r
+  This file provides some helper functions which are specific for EMMC device.\r
+\r
+  Copyright (c) 2015, Intel Corporation. All rights reserved.<BR>\r
+  This program and the accompanying materials\r
+  are licensed and made available under the terms and conditions of the BSD License\r
+  which accompanies this distribution.  The full text of the license may be found at\r
+  http://opensource.org/licenses/bsd-license.php\r
+\r
+  THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+  WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+\r
+**/\r
+\r
+#include "SdMmcPciHcDxe.h"\r
+\r
+/**\r
+  Send command GO_IDLE_STATE (CMD0 with argument of 0x00000000) to the device to\r
+  make it go to Idle State.\r
+\r
+  Refer to EMMC Electrical Standard Spec 5.1 Section 6.4 for details.\r
+\r
+  @param[in] PassThru       A pointer to the EFI_SD_MMC_PASS_THRU_PROTOCOL instance.\r
+  @param[in] Slot           The slot number of the SD card to send the command to.\r
+\r
+  @retval EFI_SUCCESS       The EMMC device is reset correctly.\r
+  @retval Others            The device reset fails.\r
+\r
+**/\r
+EFI_STATUS\r
+EmmcReset (\r
+  IN EFI_SD_MMC_PASS_THRU_PROTOCOL      *PassThru,\r
+  IN UINT8                              Slot\r
+  )\r
+{\r
+  EFI_SD_MMC_COMMAND_BLOCK              SdMmcCmdBlk;\r
+  EFI_SD_MMC_STATUS_BLOCK               SdMmcStatusBlk;\r
+  EFI_SD_MMC_PASS_THRU_COMMAND_PACKET   Packet;\r
+  EFI_STATUS                            Status;\r
+\r
+  ZeroMem (&SdMmcCmdBlk, sizeof (SdMmcCmdBlk));\r
+  ZeroMem (&SdMmcStatusBlk, sizeof (SdMmcStatusBlk));\r
+  ZeroMem (&Packet, sizeof (Packet));\r
+\r
+  Packet.SdMmcCmdBlk    = &SdMmcCmdBlk;\r
+  Packet.SdMmcStatusBlk = &SdMmcStatusBlk;\r
+  Packet.Timeout        = SD_MMC_HC_GENERIC_TIMEOUT;\r
+\r
+  SdMmcCmdBlk.CommandIndex = EMMC_GO_IDLE_STATE;\r
+  SdMmcCmdBlk.CommandType  = SdMmcCommandTypeBc;\r
+  SdMmcCmdBlk.ResponseType = 0;\r
+  SdMmcCmdBlk.CommandArgument = 0;\r
+\r
+  Status = SdMmcPassThruPassThru (PassThru, Slot, &Packet, NULL);\r
+\r
+  return Status;\r
+}\r
+\r
+/**\r
+  Send command SEND_OP_COND to the EMMC device to get the data of the OCR register.\r
+\r
+  Refer to EMMC Electrical Standard Spec 5.1 Section 6.4 for details.\r
+\r
+  @param[in]      PassThru  A pointer to the EFI_SD_MMC_PASS_THRU_PROTOCOL instance.\r
+  @param[in]      Slot      The slot number of the SD card to send the command to.\r
+  @param[in, out] Argument  On input, the argument of SEND_OP_COND is to send to the device.\r
+                            On output, the argument is the value of OCR register.\r
+\r
+  @retval EFI_SUCCESS       The operation is done correctly.\r
+  @retval Others            The operation fails.\r
+\r
+**/\r
+EFI_STATUS\r
+EmmcGetOcr (\r
+  IN     EFI_SD_MMC_PASS_THRU_PROTOCOL  *PassThru,\r
+  IN     UINT8                          Slot,\r
+  IN OUT UINT32                         *Argument\r
+  )\r
+{\r
+  EFI_SD_MMC_COMMAND_BLOCK              SdMmcCmdBlk;\r
+  EFI_SD_MMC_STATUS_BLOCK               SdMmcStatusBlk;\r
+  EFI_SD_MMC_PASS_THRU_COMMAND_PACKET   Packet;\r
+  EFI_STATUS                            Status;\r
+\r
+  ZeroMem (&SdMmcCmdBlk, sizeof (SdMmcCmdBlk));\r
+  ZeroMem (&SdMmcStatusBlk, sizeof (SdMmcStatusBlk));\r
+  ZeroMem (&Packet, sizeof (Packet));\r
+\r
+  Packet.SdMmcCmdBlk    = &SdMmcCmdBlk;\r
+  Packet.SdMmcStatusBlk = &SdMmcStatusBlk;\r
+  Packet.Timeout        = SD_MMC_HC_GENERIC_TIMEOUT;\r
+\r
+  SdMmcCmdBlk.CommandIndex = EMMC_SEND_OP_COND;\r
+  SdMmcCmdBlk.CommandType  = SdMmcCommandTypeBcr;\r
+  SdMmcCmdBlk.ResponseType = SdMmcResponseTypeR3;\r
+  SdMmcCmdBlk.CommandArgument = *Argument;\r
+\r
+  Status = SdMmcPassThruPassThru (PassThru, Slot, &Packet, NULL);\r
+  if (!EFI_ERROR (Status)) {\r
+    //\r
+    // For details, refer to SD Host Controller Simplified Spec 3.0 Table 2-12.\r
+    //\r
+    *Argument = SdMmcStatusBlk.Resp0;\r
+  }\r
+\r
+  return Status;\r
+}\r
+\r
+/**\r
+  Broadcast command ALL_SEND_CID to the bus to ask all the EMMC devices to send the\r
+  data of their CID registers.\r
+\r
+  Refer to EMMC Electrical Standard Spec 5.1 Section 6.4 for details.\r
+\r
+  @param[in] PassThru       A pointer to the EFI_SD_MMC_PASS_THRU_PROTOCOL instance.\r
+  @param[in] Slot           The slot number of the SD card to send the command to.\r
+\r
+  @retval EFI_SUCCESS       The operation is done correctly.\r
+  @retval Others            The operation fails.\r
+\r
+**/\r
+EFI_STATUS\r
+EmmcGetAllCid (\r
+  IN EFI_SD_MMC_PASS_THRU_PROTOCOL      *PassThru,\r
+  IN UINT8                              Slot\r
+  )\r
+{\r
+  EFI_SD_MMC_COMMAND_BLOCK              SdMmcCmdBlk;\r
+  EFI_SD_MMC_STATUS_BLOCK               SdMmcStatusBlk;\r
+  EFI_SD_MMC_PASS_THRU_COMMAND_PACKET   Packet;\r
+  EFI_STATUS                            Status;\r
+\r
+  ZeroMem (&SdMmcCmdBlk, sizeof (SdMmcCmdBlk));\r
+  ZeroMem (&SdMmcStatusBlk, sizeof (SdMmcStatusBlk));\r
+  ZeroMem (&Packet, sizeof (Packet));\r
+\r
+  Packet.SdMmcCmdBlk    = &SdMmcCmdBlk;\r
+  Packet.SdMmcStatusBlk = &SdMmcStatusBlk;\r
+  Packet.Timeout        = SD_MMC_HC_GENERIC_TIMEOUT;\r
+\r
+  SdMmcCmdBlk.CommandIndex = EMMC_ALL_SEND_CID;\r
+  SdMmcCmdBlk.CommandType  = SdMmcCommandTypeBcr;\r
+  SdMmcCmdBlk.ResponseType = SdMmcResponseTypeR2;\r
+  SdMmcCmdBlk.CommandArgument = 0;\r
+\r
+  Status = SdMmcPassThruPassThru (PassThru, Slot, &Packet, NULL);\r
+\r
+  return Status;\r
+}\r
+\r
+/**\r
+  Send command SET_RELATIVE_ADDR to the EMMC device to assign a Relative device\r
+  Address (RCA).\r
+\r
+  Refer to EMMC Electrical Standard Spec 5.1 Section 6.4 for details.\r
+\r
+  @param[in] PassThru       A pointer to the EFI_SD_MMC_PASS_THRU_PROTOCOL instance.\r
+  @param[in] Slot           The slot number of the SD card to send the command to.\r
+  @param[in] Rca            The relative device address to be assigned.\r
+\r
+  @retval EFI_SUCCESS       The operation is done correctly.\r
+  @retval Others            The operation fails.\r
+\r
+**/\r
+EFI_STATUS\r
+EmmcSetRca (\r
+  IN EFI_SD_MMC_PASS_THRU_PROTOCOL      *PassThru,\r
+  IN UINT8                              Slot,\r
+  IN UINT16                             Rca\r
+  )\r
+{\r
+  EFI_SD_MMC_COMMAND_BLOCK              SdMmcCmdBlk;\r
+  EFI_SD_MMC_STATUS_BLOCK               SdMmcStatusBlk;\r
+  EFI_SD_MMC_PASS_THRU_COMMAND_PACKET   Packet;\r
+  EFI_STATUS                            Status;\r
+\r
+  ZeroMem (&SdMmcCmdBlk, sizeof (SdMmcCmdBlk));\r
+  ZeroMem (&SdMmcStatusBlk, sizeof (SdMmcStatusBlk));\r
+  ZeroMem (&Packet, sizeof (Packet));\r
+\r
+  Packet.SdMmcCmdBlk    = &SdMmcCmdBlk;\r
+  Packet.SdMmcStatusBlk = &SdMmcStatusBlk;\r
+  Packet.Timeout        = SD_MMC_HC_GENERIC_TIMEOUT;\r
+\r
+  SdMmcCmdBlk.CommandIndex = EMMC_SET_RELATIVE_ADDR;\r
+  SdMmcCmdBlk.CommandType  = SdMmcCommandTypeAc;\r
+  SdMmcCmdBlk.ResponseType = SdMmcResponseTypeR1;\r
+  SdMmcCmdBlk.CommandArgument = (UINT32)Rca << 16;\r
+\r
+  Status = SdMmcPassThruPassThru (PassThru, Slot, &Packet, NULL);\r
+\r
+  return Status;\r
+}\r
+\r
+/**\r
+  Send command SEND_CSD to the EMMC device to get the data of the CSD register.\r
+\r
+  Refer to EMMC Electrical Standard Spec 5.1 Section 6.10.4 for details.\r
+\r
+  @param[in]  PassThru      A pointer to the EFI_SD_MMC_PASS_THRU_PROTOCOL instance.\r
+  @param[in]  Slot          The slot number of the SD card to send the command to.\r
+  @param[in]  Rca           The relative device address of selected device.\r
+  @param[out] Csd           The buffer to store the content of the CSD register.\r
+                            Note the caller should ignore the lowest byte of this\r
+                            buffer as the content of this byte is meaningless even\r
+                            if the operation succeeds.\r
+\r
+  @retval EFI_SUCCESS       The operation is done correctly.\r
+  @retval Others            The operation fails.\r
+\r
+**/\r
+EFI_STATUS\r
+EmmcGetCsd (\r
+  IN     EFI_SD_MMC_PASS_THRU_PROTOCOL  *PassThru,\r
+  IN     UINT8                          Slot,\r
+  IN     UINT16                         Rca,\r
+     OUT EMMC_CSD                       *Csd\r
+  )\r
+{\r
+  EFI_SD_MMC_COMMAND_BLOCK              SdMmcCmdBlk;\r
+  EFI_SD_MMC_STATUS_BLOCK               SdMmcStatusBlk;\r
+  EFI_SD_MMC_PASS_THRU_COMMAND_PACKET   Packet;\r
+  EFI_STATUS                            Status;\r
+\r
+  ZeroMem (&SdMmcCmdBlk, sizeof (SdMmcCmdBlk));\r
+  ZeroMem (&SdMmcStatusBlk, sizeof (SdMmcStatusBlk));\r
+  ZeroMem (&Packet, sizeof (Packet));\r
+\r
+  Packet.SdMmcCmdBlk    = &SdMmcCmdBlk;\r
+  Packet.SdMmcStatusBlk = &SdMmcStatusBlk;\r
+  Packet.Timeout        = SD_MMC_HC_GENERIC_TIMEOUT;\r
+\r
+  SdMmcCmdBlk.CommandIndex = EMMC_SEND_CSD;\r
+  SdMmcCmdBlk.CommandType  = SdMmcCommandTypeAc;\r
+  SdMmcCmdBlk.ResponseType = SdMmcResponseTypeR2;\r
+  SdMmcCmdBlk.CommandArgument = (UINT32)Rca << 16;\r
+\r
+  Status = SdMmcPassThruPassThru (PassThru, Slot, &Packet, NULL);\r
+  if (!EFI_ERROR (Status)) {\r
+    //\r
+    // For details, refer to SD Host Controller Simplified Spec 3.0 Table 2-12.\r
+    //\r
+    CopyMem (((UINT8*)Csd) + 1, &SdMmcStatusBlk.Resp0, sizeof (EMMC_CSD) - 1);\r
+  }\r
+\r
+  return Status;\r
+}\r
+\r
+/**\r
+  Send command SELECT_DESELECT_CARD to the EMMC device to select/deselect it.\r
+\r
+  Refer to EMMC Electrical Standard Spec 5.1 Section 6.10.4 for details.\r
+\r
+  @param[in]  PassThru      A pointer to the EFI_SD_MMC_PASS_THRU_PROTOCOL instance.\r
+  @param[in]  Slot          The slot number of the SD card to send the command to.\r
+  @param[in]  Rca           The relative device address of selected device.\r
+\r
+  @retval EFI_SUCCESS       The operation is done correctly.\r
+  @retval Others            The operation fails.\r
+\r
+**/\r
+EFI_STATUS\r
+EmmcSelect (\r
+  IN EFI_SD_MMC_PASS_THRU_PROTOCOL      *PassThru,\r
+  IN UINT8                              Slot,\r
+  IN UINT16                             Rca\r
+  )\r
+{\r
+  EFI_SD_MMC_COMMAND_BLOCK              SdMmcCmdBlk;\r
+  EFI_SD_MMC_STATUS_BLOCK               SdMmcStatusBlk;\r
+  EFI_SD_MMC_PASS_THRU_COMMAND_PACKET   Packet;\r
+  EFI_STATUS                            Status;\r
+\r
+  ZeroMem (&SdMmcCmdBlk, sizeof (SdMmcCmdBlk));\r
+  ZeroMem (&SdMmcStatusBlk, sizeof (SdMmcStatusBlk));\r
+  ZeroMem (&Packet, sizeof (Packet));\r
+\r
+  Packet.SdMmcCmdBlk    = &SdMmcCmdBlk;\r
+  Packet.SdMmcStatusBlk = &SdMmcStatusBlk;\r
+  Packet.Timeout        = SD_MMC_HC_GENERIC_TIMEOUT;\r
+\r
+  SdMmcCmdBlk.CommandIndex = EMMC_SELECT_DESELECT_CARD;\r
+  SdMmcCmdBlk.CommandType  = SdMmcCommandTypeAc;\r
+  SdMmcCmdBlk.ResponseType = SdMmcResponseTypeR1;\r
+  SdMmcCmdBlk.CommandArgument = (UINT32)Rca << 16;\r
+\r
+  Status = SdMmcPassThruPassThru (PassThru, Slot, &Packet, NULL);\r
+\r
+  return Status;\r
+}\r
+\r
+/**\r
+  Send command SEND_EXT_CSD to the EMMC device to get the data of the EXT_CSD register.\r
+\r
+  Refer to EMMC Electrical Standard Spec 5.1 Section 6.10.4 for details.\r
+\r
+  @param[in]  PassThru      A pointer to the EFI_SD_MMC_PASS_THRU_PROTOCOL instance.\r
+  @param[in]  Slot          The slot number of the SD card to send the command to.\r
+  @param[out] ExtCsd        The buffer to store the content of the EXT_CSD register.\r
+\r
+  @retval EFI_SUCCESS       The operation is done correctly.\r
+  @retval Others            The operation fails.\r
+\r
+**/\r
+EFI_STATUS\r
+EmmcGetExtCsd (\r
+  IN     EFI_SD_MMC_PASS_THRU_PROTOCOL  *PassThru,\r
+  IN     UINT8                          Slot,\r
+     OUT EMMC_EXT_CSD                   *ExtCsd\r
+  )\r
+{\r
+  EFI_SD_MMC_COMMAND_BLOCK              SdMmcCmdBlk;\r
+  EFI_SD_MMC_STATUS_BLOCK               SdMmcStatusBlk;\r
+  EFI_SD_MMC_PASS_THRU_COMMAND_PACKET   Packet;\r
+  EFI_STATUS                            Status;\r
+\r
+  ZeroMem (&SdMmcCmdBlk, sizeof (SdMmcCmdBlk));\r
+  ZeroMem (&SdMmcStatusBlk, sizeof (SdMmcStatusBlk));\r
+  ZeroMem (&Packet, sizeof (Packet));\r
+\r
+  Packet.SdMmcCmdBlk    = &SdMmcCmdBlk;\r
+  Packet.SdMmcStatusBlk = &SdMmcStatusBlk;\r
+  Packet.Timeout        = SD_MMC_HC_GENERIC_TIMEOUT;\r
+\r
+  SdMmcCmdBlk.CommandIndex = EMMC_SEND_EXT_CSD;\r
+  SdMmcCmdBlk.CommandType  = SdMmcCommandTypeAdtc;\r
+  SdMmcCmdBlk.ResponseType = SdMmcResponseTypeR1;\r
+  SdMmcCmdBlk.CommandArgument = 0x00000000;\r
+\r
+  Packet.InDataBuffer     = ExtCsd;\r
+  Packet.InTransferLength = sizeof (EMMC_EXT_CSD);\r
+\r
+  Status = SdMmcPassThruPassThru (PassThru, Slot, &Packet, NULL);\r
+  return Status;\r
+}\r
+\r
+/**\r
+  Send command SWITCH to the EMMC device to switch the mode of operation of the\r
+  selected Device or modifies the EXT_CSD registers.\r
+\r
+  Refer to EMMC Electrical Standard Spec 5.1 Section 6.10.4 for details.\r
+\r
+  @param[in]  PassThru      A pointer to the EFI_SD_MMC_PASS_THRU_PROTOCOL instance.\r
+  @param[in]  Slot          The slot number of the SD card to send the command to.\r
+  @param[in]  Access        The access mode of SWTICH command.\r
+  @param[in]  Index         The offset of the field to be access.\r
+  @param[in]  Value         The value to be set to the specified field of EXT_CSD register.\r
+  @param[in]  CmdSet        The value of CmdSet field of EXT_CSD register.\r
+\r
+  @retval EFI_SUCCESS       The operation is done correctly.\r
+  @retval Others            The operation fails.\r
+\r
+**/\r
+EFI_STATUS\r
+EmmcSwitch (\r
+  IN EFI_SD_MMC_PASS_THRU_PROTOCOL      *PassThru,\r
+  IN UINT8                              Slot,\r
+  IN UINT8                              Access,\r
+  IN UINT8                              Index,\r
+  IN UINT8                              Value,\r
+  IN UINT8                              CmdSet\r
+  )\r
+{\r
+  EFI_SD_MMC_COMMAND_BLOCK              SdMmcCmdBlk;\r
+  EFI_SD_MMC_STATUS_BLOCK               SdMmcStatusBlk;\r
+  EFI_SD_MMC_PASS_THRU_COMMAND_PACKET   Packet;\r
+  EFI_STATUS                            Status;\r
+\r
+  ZeroMem (&SdMmcCmdBlk, sizeof (SdMmcCmdBlk));\r
+  ZeroMem (&SdMmcStatusBlk, sizeof (SdMmcStatusBlk));\r
+  ZeroMem (&Packet, sizeof (Packet));\r
+\r
+  Packet.SdMmcCmdBlk    = &SdMmcCmdBlk;\r
+  Packet.SdMmcStatusBlk = &SdMmcStatusBlk;\r
+  Packet.Timeout        = SD_MMC_HC_GENERIC_TIMEOUT;\r
+\r
+  SdMmcCmdBlk.CommandIndex = EMMC_SWITCH;\r
+  SdMmcCmdBlk.CommandType  = SdMmcCommandTypeAc;\r
+  SdMmcCmdBlk.ResponseType = SdMmcResponseTypeR1b;\r
+  SdMmcCmdBlk.CommandArgument = (Access << 24) | (Index << 16) | (Value << 8) | CmdSet;\r
+\r
+  Status = SdMmcPassThruPassThru (PassThru, Slot, &Packet, NULL);\r
+\r
+  return Status;\r
+}\r
+\r
+/**\r
+  Send command SEND_STATUS to the addressed EMMC device to get its status register.\r
+\r
+  Refer to EMMC Electrical Standard Spec 5.1 Section 6.10.4 for details.\r
+\r
+  @param[in]  PassThru      A pointer to the EFI_SD_MMC_PASS_THRU_PROTOCOL instance.\r
+  @param[in]  Slot          The slot number of the SD card to send the command to.\r
+  @param[in]  Rca           The relative device address of addressed device.\r
+  @param[out] DevStatus     The returned device status.\r
+\r
+  @retval EFI_SUCCESS       The operation is done correctly.\r
+  @retval Others            The operation fails.\r
+\r
+**/\r
+EFI_STATUS\r
+EmmcSendStatus (\r
+  IN     EFI_SD_MMC_PASS_THRU_PROTOCOL  *PassThru,\r
+  IN     UINT8                          Slot,\r
+  IN     UINT16                         Rca,\r
+     OUT UINT32                         *DevStatus\r
+  )\r
+{\r
+  EFI_SD_MMC_COMMAND_BLOCK              SdMmcCmdBlk;\r
+  EFI_SD_MMC_STATUS_BLOCK               SdMmcStatusBlk;\r
+  EFI_SD_MMC_PASS_THRU_COMMAND_PACKET   Packet;\r
+  EFI_STATUS                            Status;\r
+\r
+  ZeroMem (&SdMmcCmdBlk, sizeof (SdMmcCmdBlk));\r
+  ZeroMem (&SdMmcStatusBlk, sizeof (SdMmcStatusBlk));\r
+  ZeroMem (&Packet, sizeof (Packet));\r
+\r
+  Packet.SdMmcCmdBlk    = &SdMmcCmdBlk;\r
+  Packet.SdMmcStatusBlk = &SdMmcStatusBlk;\r
+  Packet.Timeout        = SD_MMC_HC_GENERIC_TIMEOUT;\r
+\r
+  SdMmcCmdBlk.CommandIndex = EMMC_SEND_STATUS;\r
+  SdMmcCmdBlk.CommandType  = SdMmcCommandTypeAc;\r
+  SdMmcCmdBlk.ResponseType = SdMmcResponseTypeR1;\r
+  SdMmcCmdBlk.CommandArgument = (UINT32)Rca << 16;\r
+\r
+  Status = SdMmcPassThruPassThru (PassThru, Slot, &Packet, NULL);\r
+  if (!EFI_ERROR (Status)) {\r
+    *DevStatus = SdMmcStatusBlk.Resp0;\r
+  }\r
+\r
+  return Status;\r
+}\r
+\r
+/**\r
+  Send command SEND_TUNING_BLOCK to the EMMC device for HS200 optimal sampling point\r
+  detection.\r
+\r
+  It may be sent up to 40 times until the host finishes the tuning procedure.\r
+\r
+  Refer to EMMC Electrical Standard Spec 5.1 Section 6.6.8 for details.\r
+\r
+  @param[in] PassThru       A pointer to the EFI_SD_MMC_PASS_THRU_PROTOCOL instance.\r
+  @param[in] Slot           The slot number of the SD card to send the command to.\r
+  @param[in] BusWidth       The bus width to work.\r
+\r
+  @retval EFI_SUCCESS       The operation is done correctly.\r
+  @retval Others            The operation fails.\r
+\r
+**/\r
+EFI_STATUS\r
+EmmcSendTuningBlk (\r
+  IN EFI_SD_MMC_PASS_THRU_PROTOCOL      *PassThru,\r
+  IN UINT8                              Slot,\r
+  IN UINT8                              BusWidth\r
+  )\r
+{\r
+  EFI_SD_MMC_COMMAND_BLOCK              SdMmcCmdBlk;\r
+  EFI_SD_MMC_STATUS_BLOCK               SdMmcStatusBlk;\r
+  EFI_SD_MMC_PASS_THRU_COMMAND_PACKET   Packet;\r
+  EFI_STATUS                            Status;\r
+  UINT8                                 TuningBlock[128];\r
+\r
+  ZeroMem (&SdMmcCmdBlk, sizeof (SdMmcCmdBlk));\r
+  ZeroMem (&SdMmcStatusBlk, sizeof (SdMmcStatusBlk));\r
+  ZeroMem (&Packet, sizeof (Packet));\r
+\r
+  Packet.SdMmcCmdBlk    = &SdMmcCmdBlk;\r
+  Packet.SdMmcStatusBlk = &SdMmcStatusBlk;\r
+  Packet.Timeout        = SD_MMC_HC_GENERIC_TIMEOUT;\r
+\r
+  SdMmcCmdBlk.CommandIndex = EMMC_SEND_TUNING_BLOCK;\r
+  SdMmcCmdBlk.CommandType  = SdMmcCommandTypeAdtc;\r
+  SdMmcCmdBlk.ResponseType = SdMmcResponseTypeR1;\r
+  SdMmcCmdBlk.CommandArgument = 0;\r
+\r
+  Packet.InDataBuffer = TuningBlock;\r
+  if (BusWidth == 8) {\r
+    Packet.InTransferLength = sizeof (TuningBlock);\r
+  } else {\r
+    Packet.InTransferLength = 64;\r
+  }\r
+\r
+  Status = SdMmcPassThruPassThru (PassThru, Slot, &Packet, NULL);\r
+\r
+  return Status;\r
+}\r
+\r
+/**\r
+  Tunning the clock to get HS200 optimal sampling point.\r
+\r
+  Command SEND_TUNING_BLOCK may be sent up to 40 times until the host finishes the\r
+  tuning procedure.\r
+\r
+  Refer to EMMC Electrical Standard Spec 5.1 Section 6.6.8 and SD Host Controller\r
+  Simplified Spec 3.0 Figure 2-29 for details.\r
+\r
+  @param[in] PciIo          A pointer to the EFI_PCI_IO_PROTOCOL instance.\r
+  @param[in] PassThru       A pointer to the EFI_SD_MMC_PASS_THRU_PROTOCOL instance.\r
+  @param[in] Slot           The slot number of the SD card to send the command to.\r
+  @param[in] BusWidth       The bus width to work.\r
+\r
+  @retval EFI_SUCCESS       The operation is done correctly.\r
+  @retval Others            The operation fails.\r
+\r
+**/\r
+EFI_STATUS\r
+EmmcTuningClkForHs200 (\r
+  IN EFI_PCI_IO_PROTOCOL                *PciIo,\r
+  IN EFI_SD_MMC_PASS_THRU_PROTOCOL      *PassThru,\r
+  IN UINT8                              Slot,\r
+  IN UINT8                              BusWidth\r
+  )\r
+{\r
+  EFI_STATUS          Status;\r
+  UINT8               HostCtrl2;\r
+  UINT8               Retry;\r
+\r
+  //\r
+  // Notify the host that the sampling clock tuning procedure starts.\r
+  //\r
+  HostCtrl2 = BIT6;\r
+  Status = SdMmcHcOrMmio (PciIo, Slot, SD_MMC_HC_HOST_CTRL2, sizeof (HostCtrl2), &HostCtrl2);\r
+  if (EFI_ERROR (Status)) {\r
+    return Status;\r
+  }\r
+  //\r
+  // Ask the device to send a sequence of tuning blocks till the tuning procedure is done.\r
+  //\r
+  Retry = 0;\r
+  do {\r
+    Status = EmmcSendTuningBlk (PassThru, Slot, BusWidth);\r
+    if (EFI_ERROR (Status)) {\r
+      DEBUG ((EFI_D_ERROR, "EmmcTuningClkForHs200: Send tuning block fails with %r\n", Status));\r
+      return Status;\r
+    }\r
+\r
+    Status = SdMmcHcRwMmio (PciIo, Slot, SD_MMC_HC_HOST_CTRL2, TRUE, sizeof (HostCtrl2), &HostCtrl2);\r
+    if (EFI_ERROR (Status)) {\r
+      return Status;\r
+    }\r
+\r
+    if ((HostCtrl2 & (BIT6 | BIT7)) == BIT7) {\r
+      break;\r
+    }\r
+  } while (++Retry < 40);\r
+\r
+  if (Retry == 40) {\r
+    Status = EFI_TIMEOUT;\r
+    DEBUG ((EFI_D_ERROR, "EmmcTuningClkForHs200: Send tuning block exceeds 40 times\n"));\r
+  }\r
+\r
+  return Status;\r
+}\r
+\r
+/**\r
+  Switch the bus width to specified width.\r
+\r
+  Refer to EMMC Electrical Standard Spec 5.1 Section 6.6.9 and SD Host Controller\r
+  Simplified Spec 3.0 Figure 3-7 for details.\r
+\r
+  @param[in] PciIo          A pointer to the EFI_PCI_IO_PROTOCOL instance.\r
+  @param[in] PassThru       A pointer to the EFI_SD_MMC_PASS_THRU_PROTOCOL instance.\r
+  @param[in] Slot           The slot number of the SD card to send the command to.\r
+  @param[in] Rca            The relative device address to be assigned.\r
+  @param[in] IsDdr          If TRUE, use dual data rate data simpling method. Otherwise\r
+                            use single data rate data simpling method.\r
+  @param[in] BusWidth       The bus width to be set, it could be 4 or 8.\r
+\r
+  @retval EFI_SUCCESS       The operation is done correctly.\r
+  @retval Others            The operation fails.\r
+\r
+**/\r
+EFI_STATUS\r
+EmmcSwitchBusWidth (\r
+  IN EFI_PCI_IO_PROTOCOL                *PciIo,\r
+  IN EFI_SD_MMC_PASS_THRU_PROTOCOL      *PassThru,\r
+  IN UINT8                              Slot,\r
+  IN UINT16                             Rca,\r
+  IN BOOLEAN                            IsDdr,\r
+  IN UINT8                              BusWidth\r
+  )\r
+{\r
+  EFI_STATUS          Status;\r
+  UINT8               Access;\r
+  UINT8               Index;\r
+  UINT8               Value;\r
+  UINT8               CmdSet;\r
+  UINT32              DevStatus;\r
+\r
+  //\r
+  // Write Byte, the Value field is written into the byte pointed by Index.\r
+  //\r
+  Access = 0x03;\r
+  Index  = OFFSET_OF (EMMC_EXT_CSD, BusWidth);\r
+  if (BusWidth == 4) {\r
+    Value = 1;\r
+  } else if (BusWidth == 8) {\r
+    Value = 2;\r
+  } else {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  if (IsDdr) {\r
+    Value += 4;\r
+  }\r
+\r
+  CmdSet = 0;\r
+  Status = EmmcSwitch (PassThru, Slot, Access, Index, Value, CmdSet);\r
+  if (EFI_ERROR (Status)) {\r
+    DEBUG ((EFI_D_ERROR, "EmmcSwitchBusWidth: Switch to bus width %d fails with %r\n", BusWidth, Status));\r
+    return Status;\r
+  }\r
+\r
+  Status = EmmcSendStatus (PassThru, Slot, Rca, &DevStatus);\r
+  if (EFI_ERROR (Status)) {\r
+    DEBUG ((EFI_D_ERROR, "EmmcSwitchBusWidth: Send status fails with %r\n", Status));\r
+    return Status;\r
+  }\r
+  //\r
+  // Check the switch operation is really successful or not.\r
+  //\r
+  if ((DevStatus & BIT7) != 0) {\r
+    DEBUG ((EFI_D_ERROR, "EmmcSwitchBusWidth: The switch operation fails as DevStatus is 0x%08x\n", DevStatus));\r
+    return EFI_DEVICE_ERROR;\r
+  }\r
+\r
+  Status = SdMmcHcSetBusWidth (PciIo, Slot, BusWidth);\r
+\r
+  return Status;\r
+}\r
+\r
+/**\r
+  Switch the clock frequency to the specified value.\r
+\r
+  Refer to EMMC Electrical Standard Spec 5.1 Section 6.6 and SD Host Controller\r
+  Simplified Spec 3.0 Figure 3-3 for details.\r
+\r
+  @param[in] PciIo          A pointer to the EFI_PCI_IO_PROTOCOL instance.\r
+  @param[in] PassThru       A pointer to the EFI_SD_MMC_PASS_THRU_PROTOCOL instance.\r
+  @param[in] Slot           The slot number of the SD card to send the command to.\r
+  @param[in] Rca            The relative device address to be assigned.\r
+  @param[in] HsTiming       The value to be written to HS_TIMING field of EXT_CSD register.\r
+  @param[in] ClockFreq      The max clock frequency to be set, the unit is MHz.\r
+\r
+  @retval EFI_SUCCESS       The operation is done correctly.\r
+  @retval Others            The operation fails.\r
+\r
+**/\r
+EFI_STATUS\r
+EmmcSwitchClockFreq (\r
+  IN EFI_PCI_IO_PROTOCOL                *PciIo,\r
+  IN EFI_SD_MMC_PASS_THRU_PROTOCOL      *PassThru,\r
+  IN UINT8                              Slot,\r
+  IN UINT16                             Rca,\r
+  IN UINT8                              HsTiming,\r
+  IN UINT32                             ClockFreq\r
+  )\r
+{\r
+  EFI_STATUS                Status;\r
+  UINT8                     Access;\r
+  UINT8                     Index;\r
+  UINT8                     Value;\r
+  UINT8                     CmdSet;\r
+  UINT32                    DevStatus;\r
+  SD_MMC_HC_PRIVATE_DATA    *Private;\r
+\r
+  Private = SD_MMC_HC_PRIVATE_FROM_THIS (PassThru);\r
+  //\r
+  // Write Byte, the Value field is written into the byte pointed by Index.\r
+  //\r
+  Access = 0x03;\r
+  Index  = OFFSET_OF (EMMC_EXT_CSD, HsTiming);\r
+  Value  = HsTiming;\r
+  CmdSet = 0;\r
+\r
+  Status = EmmcSwitch (PassThru, Slot, Access, Index, Value, CmdSet);\r
+  if (EFI_ERROR (Status)) {\r
+    DEBUG ((EFI_D_ERROR, "EmmcSwitchClockFreq: Switch to hstiming %d fails with %r\n", HsTiming, Status));\r
+    return Status;\r
+  }\r
+\r
+  Status = EmmcSendStatus (PassThru, Slot, Rca, &DevStatus);\r
+  if (EFI_ERROR (Status)) {\r
+    DEBUG ((EFI_D_ERROR, "EmmcSwitchClockFreq: Send status fails with %r\n", Status));\r
+    return Status;\r
+  }\r
+  //\r
+  // Check the switch operation is really successful or not.\r
+  //\r
+  if ((DevStatus & BIT7) != 0) {\r
+    DEBUG ((EFI_D_ERROR, "EmmcSwitchClockFreq: The switch operation fails as DevStatus is 0x%08x\n", DevStatus));\r
+    return EFI_DEVICE_ERROR;\r
+  }\r
+  //\r
+  // Convert the clock freq unit from MHz to KHz.\r
+  //\r
+  Status = SdMmcHcClockSupply (PciIo, Slot, ClockFreq * 1000, Private->Capability[Slot]);\r
+\r
+  return Status;\r
+}\r
+\r
+/**\r
+  Switch to the High Speed timing according to request.\r
+\r
+  Refer to EMMC Electrical Standard Spec 5.1 Section 6.6.8 and SD Host Controller\r
+  Simplified Spec 3.0 Figure 2-29 for details.\r
+\r
+  @param[in] PciIo          A pointer to the EFI_PCI_IO_PROTOCOL instance.\r
+  @param[in] PassThru       A pointer to the EFI_SD_MMC_PASS_THRU_PROTOCOL instance.\r
+  @param[in] Slot           The slot number of the SD card to send the command to.\r
+  @param[in] Rca            The relative device address to be assigned.\r
+  @param[in] ClockFreq      The max clock frequency to be set.\r
+  @param[in] IsDdr          If TRUE, use dual data rate data simpling method. Otherwise\r
+                            use single data rate data simpling method.\r
+  @param[in] BusWidth       The bus width to be set, it could be 4 or 8.\r
+\r
+  @retval EFI_SUCCESS       The operation is done correctly.\r
+  @retval Others            The operation fails.\r
+\r
+**/\r
+EFI_STATUS\r
+EmmcSwitchToHighSpeed (\r
+  IN EFI_PCI_IO_PROTOCOL                *PciIo,\r
+  IN EFI_SD_MMC_PASS_THRU_PROTOCOL      *PassThru,\r
+  IN UINT8                              Slot,\r
+  IN UINT16                             Rca,\r
+  IN UINT32                             ClockFreq,\r
+  IN BOOLEAN                            IsDdr,\r
+  IN UINT8                              BusWidth\r
+  )\r
+{\r
+  EFI_STATUS          Status;\r
+  UINT8               HsTiming;\r
+  UINT8               HostCtrl1;\r
+  UINT8               HostCtrl2;\r
+\r
+  Status = EmmcSwitchBusWidth (PciIo, PassThru, Slot, Rca, IsDdr, BusWidth);\r
+  if (EFI_ERROR (Status)) {\r
+    return Status;\r
+  }\r
+  //\r
+  // Set to Hight Speed timing\r
+  //\r
+  HostCtrl1 = BIT2;\r
+  Status = SdMmcHcOrMmio (PciIo, Slot, SD_MMC_HC_HOST_CTRL1, sizeof (HostCtrl1), &HostCtrl1);\r
+  if (EFI_ERROR (Status)) {\r
+    return Status;\r
+  }\r
+\r
+  //\r
+  // Clean UHS Mode Select field of Host Control 2 reigster before update\r
+  //\r
+  HostCtrl2 = (UINT8)~0x7;\r
+  Status = SdMmcHcAndMmio (PciIo, Slot, SD_MMC_HC_HOST_CTRL2, sizeof (HostCtrl2), &HostCtrl2);\r
+  if (EFI_ERROR (Status)) {\r
+    return Status;\r
+  }\r
+  //\r
+  // Set UHS Mode Select field of Host Control 2 reigster to SDR12/25/50\r
+  //\r
+  if (IsDdr) {\r
+    HostCtrl2 = BIT2;\r
+  } else if (ClockFreq == 52) {\r
+    HostCtrl2 = BIT0;\r
+  } else {\r
+    HostCtrl2 = 0;\r
+  }\r
+  Status = SdMmcHcOrMmio (PciIo, Slot, SD_MMC_HC_HOST_CTRL2, sizeof (HostCtrl2), &HostCtrl2);\r
+  if (EFI_ERROR (Status)) {\r
+    return Status;\r
+  }\r
+\r
+  HsTiming = 1;\r
+  Status = EmmcSwitchClockFreq (PciIo, PassThru, Slot, Rca, HsTiming, ClockFreq);\r
+  if (EFI_ERROR (Status)) {\r
+    return Status;\r
+  }\r
+\r
+  return Status;\r
+}\r
+\r
+/**\r
+  Switch to the HS200 timing according to request.\r
+\r
+  Refer to EMMC Electrical Standard Spec 5.1 Section 6.6.8 and SD Host Controller\r
+  Simplified Spec 3.0 Figure 2-29 for details.\r
+\r
+  @param[in] PciIo          A pointer to the EFI_PCI_IO_PROTOCOL instance.\r
+  @param[in] PassThru       A pointer to the EFI_SD_MMC_PASS_THRU_PROTOCOL instance.\r
+  @param[in] Slot           The slot number of the SD card to send the command to.\r
+  @param[in] Rca            The relative device address to be assigned.\r
+  @param[in] ClockFreq      The max clock frequency to be set.\r
+  @param[in] BusWidth       The bus width to be set, it could be 4 or 8.\r
+\r
+  @retval EFI_SUCCESS       The operation is done correctly.\r
+  @retval Others            The operation fails.\r
+\r
+**/\r
+EFI_STATUS\r
+EmmcSwitchToHS200 (\r
+  IN EFI_PCI_IO_PROTOCOL                *PciIo,\r
+  IN EFI_SD_MMC_PASS_THRU_PROTOCOL      *PassThru,\r
+  IN UINT8                              Slot,\r
+  IN UINT16                             Rca,\r
+  IN UINT32                             ClockFreq,\r
+  IN UINT8                              BusWidth\r
+  )\r
+{\r
+  EFI_STATUS          Status;\r
+  UINT8               HsTiming;\r
+  UINT8               HostCtrl2;\r
+  UINT16              ClockCtrl;\r
+\r
+  if ((BusWidth != 4) && (BusWidth != 8)) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  Status = EmmcSwitchBusWidth (PciIo, PassThru, Slot, Rca, FALSE, BusWidth);\r
+  if (EFI_ERROR (Status)) {\r
+    return Status;\r
+  }\r
+  //\r
+  // Set to HS200/SDR104 timing\r
+  //\r
+  //\r
+  // Stop bus clock at first\r
+  //\r
+  Status = SdMmcHcStopClock (PciIo, Slot);\r
+  if (EFI_ERROR (Status)) {\r
+    return Status;\r
+  }\r
+  //\r
+  // Clean UHS Mode Select field of Host Control 2 reigster before update\r
+  //\r
+  HostCtrl2 = (UINT8)~0x7;\r
+  Status = SdMmcHcAndMmio (PciIo, Slot, SD_MMC_HC_HOST_CTRL2, sizeof (HostCtrl2), &HostCtrl2);\r
+  if (EFI_ERROR (Status)) {\r
+    return Status;\r
+  }\r
+  //\r
+  // Set UHS Mode Select field of Host Control 2 reigster to SDR104\r
+  //\r
+  HostCtrl2 = BIT0 | BIT1;\r
+  Status = SdMmcHcOrMmio (PciIo, Slot, SD_MMC_HC_HOST_CTRL2, sizeof (HostCtrl2), &HostCtrl2);\r
+  if (EFI_ERROR (Status)) {\r
+    return Status;\r
+  }\r
+  //\r
+  // Wait Internal Clock Stable in the Clock Control register to be 1 before set SD Clock Enable bit\r
+  //\r
+  Status = SdMmcHcWaitMmioSet (\r
+             PciIo,\r
+             Slot,\r
+             SD_MMC_HC_CLOCK_CTRL,\r
+             sizeof (ClockCtrl),\r
+             BIT1,\r
+             BIT1,\r
+             SD_MMC_HC_GENERIC_TIMEOUT\r
+             );\r
+  if (EFI_ERROR (Status)) {\r
+    return Status;\r
+  }\r
+  //\r
+  // Set SD Clock Enable in the Clock Control register to 1\r
+  //\r
+  ClockCtrl = BIT2;\r
+  Status = SdMmcHcOrMmio (PciIo, Slot, SD_MMC_HC_CLOCK_CTRL, sizeof (ClockCtrl), &ClockCtrl);\r
+\r
+  HsTiming = 2;\r
+  Status = EmmcSwitchClockFreq (PciIo, PassThru, Slot, Rca, HsTiming, ClockFreq);\r
+  if (EFI_ERROR (Status)) {\r
+    return Status;\r
+  }\r
+\r
+  Status = EmmcTuningClkForHs200 (PciIo, PassThru, Slot, BusWidth);\r
+\r
+  return Status;\r
+}\r
+\r
+/**\r
+  Switch to the HS400 timing according to request.\r
+\r
+  Refer to EMMC Electrical Standard Spec 5.1 Section 6.6.8 and SD Host Controller\r
+  Simplified Spec 3.0 Figure 2-29 for details.\r
+\r
+  @param[in] PciIo          A pointer to the EFI_PCI_IO_PROTOCOL instance.\r
+  @param[in] PassThru       A pointer to the EFI_SD_MMC_PASS_THRU_PROTOCOL instance.\r
+  @param[in] Slot           The slot number of the SD card to send the command to.\r
+  @param[in] Rca            The relative device address to be assigned.\r
+  @param[in] ClockFreq      The max clock frequency to be set.\r
+\r
+  @retval EFI_SUCCESS       The operation is done correctly.\r
+  @retval Others            The operation fails.\r
+\r
+**/\r
+EFI_STATUS\r
+EmmcSwitchToHS400 (\r
+  IN EFI_PCI_IO_PROTOCOL                *PciIo,\r
+  IN EFI_SD_MMC_PASS_THRU_PROTOCOL      *PassThru,\r
+  IN UINT8                              Slot,\r
+  IN UINT16                             Rca,\r
+  IN UINT32                             ClockFreq\r
+  )\r
+{\r
+  EFI_STATUS          Status;\r
+  UINT8               HsTiming;\r
+  UINT8               HostCtrl2;\r
+\r
+  Status = EmmcSwitchToHS200 (PciIo, PassThru, Slot, Rca, ClockFreq, 8);\r
+  if (EFI_ERROR (Status)) {\r
+    return Status;\r
+  }\r
+  //\r
+  // Set to Hight Speed timing and set the clock frequency to a value less than 52MHz.\r
+  //\r
+  HsTiming = 1;\r
+  Status = EmmcSwitchClockFreq (PciIo, PassThru, Slot, Rca, HsTiming, 52);\r
+  if (EFI_ERROR (Status)) {\r
+    return Status;\r
+  }\r
+  //\r
+  // HS400 mode must use 8 data lines.\r
+  //\r
+  Status = EmmcSwitchBusWidth (PciIo, PassThru, Slot, Rca, TRUE, 8);\r
+  if (EFI_ERROR (Status)) {\r
+    return Status;\r
+  }\r
+  //\r
+  // Clean UHS Mode Select field of Host Control 2 reigster before update\r
+  //\r
+  HostCtrl2 = (UINT8)~0x7;\r
+  Status = SdMmcHcAndMmio (PciIo, Slot, SD_MMC_HC_HOST_CTRL2, sizeof (HostCtrl2), &HostCtrl2);\r
+  if (EFI_ERROR (Status)) {\r
+    return Status;\r
+  }\r
+  //\r
+  // Set UHS Mode Select field of Host Control 2 reigster to HS400\r
+  //\r
+  HostCtrl2 = BIT0 | BIT2;\r
+  Status = SdMmcHcOrMmio (PciIo, Slot, SD_MMC_HC_HOST_CTRL2, sizeof (HostCtrl2), &HostCtrl2);\r
+  if (EFI_ERROR (Status)) {\r
+    return Status;\r
+  }\r
+\r
+  HsTiming = 3;\r
+  Status = EmmcSwitchClockFreq (PciIo, PassThru, Slot, Rca, HsTiming, ClockFreq);\r
+\r
+  return Status;\r
+}\r
+\r
+/**\r
+  Switch the high speed timing according to request.\r
+\r
+  Refer to EMMC Electrical Standard Spec 5.1 Section 6.6.8 and SD Host Controller\r
+  Simplified Spec 3.0 Figure 2-29 for details.\r
+\r
+  @param[in] PciIo          A pointer to the EFI_PCI_IO_PROTOCOL instance.\r
+  @param[in] PassThru       A pointer to the EFI_SD_MMC_PASS_THRU_PROTOCOL instance.\r
+  @param[in] Slot           The slot number of the SD card to send the command to.\r
+  @param[in] Rca            The relative device address to be assigned.\r
+\r
+  @retval EFI_SUCCESS       The operation is done correctly.\r
+  @retval Others            The operation fails.\r
+\r
+**/\r
+EFI_STATUS\r
+EmmcSetBusMode (\r
+  IN EFI_PCI_IO_PROTOCOL                *PciIo,\r
+  IN EFI_SD_MMC_PASS_THRU_PROTOCOL      *PassThru,\r
+  IN UINT8                              Slot,\r
+  IN UINT16                             Rca\r
+  )\r
+{\r
+  EFI_STATUS                    Status;\r
+  EMMC_CSD                      Csd;\r
+  EMMC_EXT_CSD                  ExtCsd;\r
+  UINT8                         HsTiming;\r
+  BOOLEAN                       IsDdr;\r
+  UINT32                        ClockFreq;\r
+  UINT8                         BusWidth;\r
+  SD_MMC_HC_PRIVATE_DATA        *Private;\r
+\r
+  Private = SD_MMC_HC_PRIVATE_FROM_THIS (PassThru);\r
+\r
+  Status = EmmcGetCsd (PassThru, Slot, Rca, &Csd);\r
+  if (EFI_ERROR (Status)) {\r
+    DEBUG ((EFI_D_ERROR, "EmmcSetBusMode: GetCsd fails with %r\n", Status));\r
+    return Status;\r
+  }\r
+\r
+  Status = EmmcSelect (PassThru, Slot, Rca);\r
+  if (EFI_ERROR (Status)) {\r
+    DEBUG ((EFI_D_ERROR, "EmmcSetBusMode: Select fails with %r\n", Status));\r
+    return Status;\r
+  }\r
+\r
+  ASSERT (Private->Capability[Slot].BaseClkFreq != 0);\r
+  //\r
+  // Check if the Host Controller support 8bits bus width.\r
+  //\r
+  if (Private->Capability[Slot].BusWidth8 != 0) {\r
+    BusWidth = 8;\r
+  } else {\r
+    BusWidth = 4;\r
+  }\r
+  //\r
+  // Get Deivce_Type from EXT_CSD register.\r
+  //\r
+  Status = EmmcGetExtCsd (PassThru, Slot, &ExtCsd);\r
+  if (EFI_ERROR (Status)) {\r
+    DEBUG ((EFI_D_ERROR, "EmmcSetBusMode: GetExtCsd fails with %r\n", Status));\r
+    return Status;\r
+  }\r
+  //\r
+  // Calculate supported bus speed/bus width/clock frequency.\r
+  //\r
+  HsTiming  = 0;\r
+  IsDdr     = FALSE;\r
+  ClockFreq = 0;\r
+  if (((ExtCsd.DeviceType & (BIT4 | BIT5))  != 0) && (Private->Capability[Slot].Sdr104 != 0)) {\r
+    HsTiming  = 2;\r
+    IsDdr     = FALSE;\r
+    ClockFreq = 200;\r
+  } else if (((ExtCsd.DeviceType & (BIT2 | BIT3))  != 0) && (Private->Capability[Slot].Ddr50 != 0)) {\r
+    HsTiming  = 1;\r
+    IsDdr     = TRUE;\r
+    ClockFreq = 52;\r
+  } else if (((ExtCsd.DeviceType & BIT1)  != 0) && (Private->Capability[Slot].HighSpeed != 0)) {\r
+    HsTiming  = 1;\r
+    IsDdr     = FALSE;\r
+    ClockFreq = 52;\r
+  } else if (((ExtCsd.DeviceType & BIT0)  != 0) && (Private->Capability[Slot].HighSpeed != 0)) {\r
+    HsTiming  = 1;\r
+    IsDdr     = FALSE;\r
+    ClockFreq = 26;\r
+  }\r
+  //\r
+  // Check if both of the device and the host controller support HS400 DDR mode.\r
+  //\r
+  if (((ExtCsd.DeviceType & (BIT6 | BIT7))  != 0) && (Private->Capability[Slot].Hs400 != 0)) {\r
+    //\r
+    // The host controller supports 8bits bus.\r
+    //\r
+    ASSERT (BusWidth == 8);\r
+    HsTiming  = 3;\r
+    IsDdr     = TRUE;\r
+    ClockFreq = 200;\r
+  }\r
+\r
+  if ((ClockFreq == 0) || (HsTiming == 0)) {\r
+    //\r
+    // Continue using default setting.\r
+    //\r
+    return EFI_SUCCESS;\r
+  }\r
+\r
+  DEBUG ((EFI_D_INFO, "EmmcSetBusMode: HsTiming %d ClockFreq %d BusWidth %d Ddr %a\n", HsTiming, ClockFreq, BusWidth, IsDdr ? "TRUE":"FALSE"));\r
+\r
+  if (HsTiming == 3) {\r
+    //\r
+    // Execute HS400 timing switch procedure\r
+    //\r
+    Status = EmmcSwitchToHS400 (PciIo, PassThru, Slot, Rca, ClockFreq);\r
+  } else if (HsTiming == 2) {\r
+    //\r
+    // Execute HS200 timing switch procedure\r
+    //\r
+    Status = EmmcSwitchToHS200 (PciIo, PassThru, Slot, Rca, ClockFreq, BusWidth);\r
+  } else {\r
+    //\r
+    // Execute High Speed timing switch procedure\r
+    //\r
+    Status = EmmcSwitchToHighSpeed (PciIo, PassThru, Slot, Rca, ClockFreq, BusWidth, IsDdr);\r
+  }\r
+\r
+  DEBUG ((EFI_D_INFO, "EmmcSetBusMode: Switch to %a %r\n", (HsTiming == 3) ? "HS400" : ((HsTiming == 2) ? "HS200" : "HighSpeed"), Status));\r
+\r
+  return Status;\r
+}\r
+\r
+/**\r
+  Execute EMMC device identification procedure.\r
+\r
+  Refer to EMMC Electrical Standard Spec 5.1 Section 6.4 for details.\r
+\r
+  @param[in] Private        A pointer to the SD_MMC_HC_PRIVATE_DATA instance.\r
+  @param[in] Slot           The slot number of the SD card to send the command to.\r
+\r
+  @retval EFI_SUCCESS       There is a EMMC card.\r
+  @retval Others            There is not a EMMC card.\r
+\r
+**/\r
+EFI_STATUS\r
+EmmcIdentification (\r
+  IN SD_MMC_HC_PRIVATE_DATA             *Private,\r
+  IN UINT8                              Slot\r
+  )\r
+{\r
+  EFI_STATUS                     Status;\r
+  EFI_PCI_IO_PROTOCOL            *PciIo;\r
+  EFI_SD_MMC_PASS_THRU_PROTOCOL  *PassThru;\r
+  UINT32                         Ocr;\r
+  UINT16                         Rca;\r
+\r
+  PciIo    = Private->PciIo;\r
+  PassThru = &Private->PassThru;\r
+\r
+  Status = EmmcReset (PassThru, Slot);\r
+  if (EFI_ERROR (Status)) {\r
+    DEBUG ((EFI_D_VERBOSE, "EmmcIdentification: Executing Cmd0 fails with %r\n", Status));\r
+    return Status;\r
+  }\r
+\r
+  Ocr = 0;\r
+  do {\r
+    Status = EmmcGetOcr (PassThru, Slot, &Ocr);\r
+    if (EFI_ERROR (Status)) {\r
+      DEBUG ((EFI_D_VERBOSE, "EmmcIdentification: Executing Cmd1 fails with %r\n", Status));\r
+      return Status;\r
+    }\r
+    Ocr |= BIT30;\r
+  } while ((Ocr & BIT31) == 0);\r
+\r
+  Status = EmmcGetAllCid (PassThru, Slot);\r
+  if (EFI_ERROR (Status)) {\r
+    DEBUG ((EFI_D_VERBOSE, "EmmcIdentification: Executing Cmd2 fails with %r\n", Status));\r
+    return Status;\r
+  }\r
+  //\r
+  // Slot starts from 0 and valid RCA starts from 1.\r
+  // Here we takes a simple formula to calculate the RCA.\r
+  // Don't support multiple devices on the slot, that is\r
+  // shared bus slot feature.\r
+  //\r
+  Rca    = Slot + 1;\r
+  Status = EmmcSetRca (PassThru, Slot, Rca);\r
+  if (EFI_ERROR (Status)) {\r
+    DEBUG ((EFI_D_ERROR, "EmmcIdentification: Executing Cmd3 fails with %r\n", Status));\r
+    return Status;\r
+  }\r
+  //\r
+  // Enter Data Tranfer Mode.\r
+  //\r
+  DEBUG ((EFI_D_INFO, "EmmcIdentification: Found a EMMC device at slot [%d], RCA [%d]\n", Slot, Rca));\r
+  Private->Slot[Slot].CardType = EmmcCardType;\r
+\r
+  Status = EmmcSetBusMode (PciIo, PassThru, Slot, Rca);\r
+\r
+  return Status;\r
+}\r
+\r
diff --git a/MdeModulePkg/Bus/Pci/SdMmcPciHcDxe/SdDevice.c b/MdeModulePkg/Bus/Pci/SdMmcPciHcDxe/SdDevice.c
new file mode 100644 (file)
index 0000000..07bd07a
--- /dev/null
@@ -0,0 +1,1165 @@
+/** @file\r
+  This file provides some helper functions which are specific for SD card device.\r
+\r
+  Copyright (c) 2015, Intel Corporation. All rights reserved.<BR>\r
+  This program and the accompanying materials\r
+  are licensed and made available under the terms and conditions of the BSD License\r
+  which accompanies this distribution.  The full text of the license may be found at\r
+  http://opensource.org/licenses/bsd-license.php\r
+\r
+  THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+  WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+\r
+**/\r
+\r
+#include "SdMmcPciHcDxe.h"\r
+\r
+/**\r
+  Send command GO_IDLE_STATE to the device to make it go to Idle State.\r
+\r
+  Refer to SD Physical Layer Simplified Spec 4.1 Section 4.7 for details.\r
+\r
+  @param[in] PassThru       A pointer to the EFI_SD_MMC_PASS_THRU_PROTOCOL instance.\r
+  @param[in] Slot           The slot number of the SD card to send the command to.\r
+\r
+  @retval EFI_SUCCESS       The SD device is reset correctly.\r
+  @retval Others            The device reset fails.\r
+\r
+**/\r
+EFI_STATUS\r
+SdCardReset (\r
+  IN EFI_SD_MMC_PASS_THRU_PROTOCOL      *PassThru,\r
+  IN UINT8                              Slot\r
+  )\r
+{\r
+  EFI_SD_MMC_COMMAND_BLOCK              SdMmcCmdBlk;\r
+  EFI_SD_MMC_STATUS_BLOCK               SdMmcStatusBlk;\r
+  EFI_SD_MMC_PASS_THRU_COMMAND_PACKET   Packet;\r
+  EFI_STATUS                            Status;\r
+\r
+  ZeroMem (&SdMmcCmdBlk, sizeof (SdMmcCmdBlk));\r
+  ZeroMem (&SdMmcStatusBlk, sizeof (SdMmcStatusBlk));\r
+  ZeroMem (&Packet, sizeof (Packet));\r
+\r
+  Packet.SdMmcCmdBlk    = &SdMmcCmdBlk;\r
+  Packet.SdMmcStatusBlk = &SdMmcStatusBlk;\r
+  Packet.Timeout        = SD_MMC_HC_GENERIC_TIMEOUT;\r
+\r
+  SdMmcCmdBlk.CommandIndex = SD_GO_IDLE_STATE;\r
+  SdMmcCmdBlk.CommandType  = SdMmcCommandTypeBc;\r
+\r
+  Status = SdMmcPassThruPassThru (PassThru, Slot, &Packet, NULL);\r
+\r
+  return Status;\r
+}\r
+\r
+/**\r
+  Send command SEND_IF_COND to the device to inquiry the SD Memory Card interface\r
+  condition.\r
+\r
+  Refer to SD Physical Layer Simplified Spec 4.1 Section 4.7 for details.\r
+\r
+  @param[in] PassThru       A pointer to the EFI_SD_MMC_PASS_THRU_PROTOCOL instance.\r
+  @param[in] Slot           The slot number of the SD card to send the command to.\r
+  @param[in] SupplyVoltage  The supplied voltage by the host.\r
+  @param[in] CheckPattern   The check pattern to be sent to the device.\r
+\r
+  @retval EFI_SUCCESS       The operation is done correctly.\r
+  @retval Others            The operation fails.\r
+\r
+**/\r
+EFI_STATUS\r
+SdCardVoltageCheck (\r
+  IN EFI_SD_MMC_PASS_THRU_PROTOCOL      *PassThru,\r
+  IN UINT8                              Slot,\r
+  IN UINT8                              SupplyVoltage,\r
+  IN UINT8                              CheckPattern\r
+  )\r
+{\r
+  EFI_SD_MMC_COMMAND_BLOCK              SdMmcCmdBlk;\r
+  EFI_SD_MMC_STATUS_BLOCK               SdMmcStatusBlk;\r
+  EFI_SD_MMC_PASS_THRU_COMMAND_PACKET   Packet;\r
+  EFI_STATUS                            Status;\r
+\r
+  ZeroMem (&SdMmcCmdBlk, sizeof (SdMmcCmdBlk));\r
+  ZeroMem (&SdMmcStatusBlk, sizeof (SdMmcStatusBlk));\r
+  ZeroMem (&Packet, sizeof (Packet));\r
+\r
+  Packet.SdMmcCmdBlk    = &SdMmcCmdBlk;\r
+  Packet.SdMmcStatusBlk = &SdMmcStatusBlk;\r
+  Packet.Timeout        = SD_MMC_HC_GENERIC_TIMEOUT;\r
+\r
+  SdMmcCmdBlk.CommandIndex = SD_SEND_IF_COND;\r
+  SdMmcCmdBlk.CommandType  = SdMmcCommandTypeBcr;\r
+  SdMmcCmdBlk.ResponseType = SdMmcResponseTypeR7;\r
+  SdMmcCmdBlk.CommandArgument = (SupplyVoltage << 8) | CheckPattern;\r
+\r
+  Status = SdMmcPassThruPassThru (PassThru, Slot, &Packet, NULL);\r
+\r
+  if (!EFI_ERROR (Status)) {\r
+    if (SdMmcStatusBlk.Resp0 != SdMmcCmdBlk.CommandArgument) {\r
+      return EFI_DEVICE_ERROR;\r
+    }\r
+  }\r
+\r
+  return Status;\r
+}\r
+\r
+/**\r
+  Send command SDIO_SEND_OP_COND to the device to see whether it is SDIO device.\r
+\r
+  Refer to SDIO Simplified Spec 3 Section 3.2 for details.\r
+\r
+  @param[in] PassThru       A pointer to the EFI_SD_MMC_PASS_THRU_PROTOCOL instance.\r
+  @param[in] Slot           The slot number of the SD card to send the command to.\r
+  @param[in] VoltageWindow  The supply voltage window.\r
+  @param[in] S18R           The boolean to show if it should switch to 1.8v.\r
+\r
+  @retval EFI_SUCCESS       The operation is done correctly.\r
+  @retval Others            The operation fails.\r
+\r
+**/\r
+EFI_STATUS\r
+SdioSendOpCond (\r
+  IN EFI_SD_MMC_PASS_THRU_PROTOCOL      *PassThru,\r
+  IN UINT8                              Slot,\r
+  IN UINT32                             VoltageWindow,\r
+  IN BOOLEAN                            S18R\r
+  )\r
+{\r
+  EFI_SD_MMC_COMMAND_BLOCK              SdMmcCmdBlk;\r
+  EFI_SD_MMC_STATUS_BLOCK               SdMmcStatusBlk;\r
+  EFI_SD_MMC_PASS_THRU_COMMAND_PACKET   Packet;\r
+  EFI_STATUS                            Status;\r
+  UINT32                                Switch;\r
+\r
+  ZeroMem (&SdMmcCmdBlk, sizeof (SdMmcCmdBlk));\r
+  ZeroMem (&SdMmcStatusBlk, sizeof (SdMmcStatusBlk));\r
+  ZeroMem (&Packet, sizeof (Packet));\r
+\r
+  Packet.SdMmcCmdBlk    = &SdMmcCmdBlk;\r
+  Packet.SdMmcStatusBlk = &SdMmcStatusBlk;\r
+  Packet.Timeout        = SD_MMC_HC_GENERIC_TIMEOUT;\r
+\r
+  SdMmcCmdBlk.CommandIndex = SDIO_SEND_OP_COND;\r
+  SdMmcCmdBlk.CommandType  = SdMmcCommandTypeBcr;\r
+  SdMmcCmdBlk.ResponseType = SdMmcResponseTypeR4;\r
+\r
+  Switch = S18R ? BIT24 : 0;\r
+\r
+  SdMmcCmdBlk.CommandArgument = (VoltageWindow & 0xFFFFFF) | Switch;\r
+\r
+  Status = SdMmcPassThruPassThru (PassThru, Slot, &Packet, NULL);\r
+\r
+  return Status;\r
+}\r
+\r
+/**\r
+  Send command SD_SEND_OP_COND to the device to see whether it is SDIO device.\r
+\r
+  Refer to SD Physical Layer Simplified Spec 4.1 Section 4.7 for details.\r
+\r
+  @param[in]  PassThru       A pointer to the EFI_SD_MMC_PASS_THRU_PROTOCOL instance.\r
+  @param[in]  Slot           The slot number of the SD card to send the command to.\r
+  @param[in]  Rca            The relative device address of addressed device.\r
+  @param[in]  VoltageWindow  The supply voltage window.\r
+  @param[in]  S18R           The boolean to show if it should switch to 1.8v.\r
+  @param[in]  Xpc            The boolean to show if it should provide 0.36w power control.\r
+  @param[in]  Hcs            The boolean to show if it support host capacity info.\r
+  @param[out] Ocr            The buffer to store returned OCR register value.\r
+\r
+  @retval EFI_SUCCESS        The operation is done correctly.\r
+  @retval Others             The operation fails.\r
+\r
+**/\r
+EFI_STATUS\r
+SdCardSendOpCond (\r
+  IN     EFI_SD_MMC_PASS_THRU_PROTOCOL  *PassThru,\r
+  IN     UINT8                          Slot,\r
+  IN     UINT16                         Rca,\r
+  IN     UINT32                         VoltageWindow,\r
+  IN     BOOLEAN                        S18R,\r
+  IN     BOOLEAN                        Xpc,\r
+  IN     BOOLEAN                        Hcs,\r
+     OUT UINT32                         *Ocr\r
+  )\r
+{\r
+  EFI_SD_MMC_COMMAND_BLOCK              SdMmcCmdBlk;\r
+  EFI_SD_MMC_STATUS_BLOCK               SdMmcStatusBlk;\r
+  EFI_SD_MMC_PASS_THRU_COMMAND_PACKET   Packet;\r
+  EFI_STATUS                            Status;\r
+  UINT32                                Switch;\r
+  UINT32                                MaxPower;\r
+  UINT32                                HostCapacity;\r
+\r
+  ZeroMem (&SdMmcCmdBlk, sizeof (SdMmcCmdBlk));\r
+  ZeroMem (&SdMmcStatusBlk, sizeof (SdMmcStatusBlk));\r
+  ZeroMem (&Packet, sizeof (Packet));\r
+\r
+  Packet.SdMmcCmdBlk    = &SdMmcCmdBlk;\r
+  Packet.SdMmcStatusBlk = &SdMmcStatusBlk;\r
+  Packet.Timeout        = SD_MMC_HC_GENERIC_TIMEOUT;\r
+\r
+  SdMmcCmdBlk.CommandIndex = SD_APP_CMD;\r
+  SdMmcCmdBlk.CommandType  = SdMmcCommandTypeAc;\r
+  SdMmcCmdBlk.ResponseType = SdMmcResponseTypeR1;\r
+  SdMmcCmdBlk.CommandArgument = (UINT32)Rca << 16;\r
+\r
+  Status = SdMmcPassThruPassThru (PassThru, Slot, &Packet, NULL);\r
+  if (EFI_ERROR (Status)) {\r
+    return Status;\r
+  }\r
+\r
+  SdMmcCmdBlk.CommandIndex = SD_SEND_OP_COND;\r
+  SdMmcCmdBlk.CommandType  = SdMmcCommandTypeBcr;\r
+  SdMmcCmdBlk.ResponseType = SdMmcResponseTypeR3;\r
+\r
+  Switch       = S18R ? BIT24 : 0;\r
+  MaxPower     = Xpc ? BIT28 : 0;\r
+  HostCapacity = Hcs ? BIT30 : 0;\r
+\r
+  SdMmcCmdBlk.CommandArgument = (VoltageWindow & 0xFFFFFF) | Switch | MaxPower | HostCapacity;\r
+\r
+  Status = SdMmcPassThruPassThru (PassThru, Slot, &Packet, NULL);\r
+  if (!EFI_ERROR (Status)) {\r
+    //\r
+    // For details, refer to SD Host Controller Simplified Spec 3.0 Table 2-12.\r
+    //\r
+    *Ocr = SdMmcStatusBlk.Resp0;\r
+  }\r
+\r
+  return Status;\r
+}\r
+\r
+/**\r
+  Broadcast command ALL_SEND_CID to the bus to ask all the SD devices to send the\r
+  data of their CID registers.\r
+\r
+  Refer to SD Physical Layer Simplified Spec 4.1 Section 4.7 for details.\r
+\r
+  @param[in] PassThru       A pointer to the EFI_SD_MMC_PASS_THRU_PROTOCOL instance.\r
+  @param[in] Slot           The slot number of the SD card to send the command to.\r
+\r
+  @retval EFI_SUCCESS       The operation is done correctly.\r
+  @retval Others            The operation fails.\r
+\r
+**/\r
+EFI_STATUS\r
+SdCardAllSendCid (\r
+  IN EFI_SD_MMC_PASS_THRU_PROTOCOL      *PassThru,\r
+  IN UINT8                              Slot\r
+  )\r
+{\r
+  EFI_SD_MMC_COMMAND_BLOCK              SdMmcCmdBlk;\r
+  EFI_SD_MMC_STATUS_BLOCK               SdMmcStatusBlk;\r
+  EFI_SD_MMC_PASS_THRU_COMMAND_PACKET   Packet;\r
+  EFI_STATUS                            Status;\r
+\r
+  ZeroMem (&SdMmcCmdBlk, sizeof (SdMmcCmdBlk));\r
+  ZeroMem (&SdMmcStatusBlk, sizeof (SdMmcStatusBlk));\r
+  ZeroMem (&Packet, sizeof (Packet));\r
+\r
+  Packet.SdMmcCmdBlk    = &SdMmcCmdBlk;\r
+  Packet.SdMmcStatusBlk = &SdMmcStatusBlk;\r
+  Packet.Timeout        = SD_MMC_HC_GENERIC_TIMEOUT;\r
+\r
+  SdMmcCmdBlk.CommandIndex = SD_ALL_SEND_CID;\r
+  SdMmcCmdBlk.CommandType  = SdMmcCommandTypeBcr;\r
+  SdMmcCmdBlk.ResponseType = SdMmcResponseTypeR2;\r
+\r
+  Status = SdMmcPassThruPassThru (PassThru, Slot, &Packet, NULL);\r
+\r
+  return Status;\r
+}\r
+\r
+/**\r
+  Send command SET_RELATIVE_ADDR to the SD device to assign a Relative device\r
+  Address (RCA).\r
+\r
+  Refer to SD Physical Layer Simplified Spec 4.1 Section 4.7 for details.\r
+\r
+  @param[in]  PassThru      A pointer to the EFI_SD_MMC_PASS_THRU_PROTOCOL instance.\r
+  @param[in]  Slot          The slot number of the SD card to send the command to.\r
+  @param[out] Rca           The relative device address to assign.\r
+\r
+  @retval EFI_SUCCESS       The operation is done correctly.\r
+  @retval Others            The operation fails.\r
+\r
+**/\r
+EFI_STATUS\r
+SdCardSetRca (\r
+  IN     EFI_SD_MMC_PASS_THRU_PROTOCOL  *PassThru,\r
+  IN     UINT8                          Slot,\r
+     OUT UINT16                         *Rca\r
+  )\r
+{\r
+  EFI_SD_MMC_COMMAND_BLOCK              SdMmcCmdBlk;\r
+  EFI_SD_MMC_STATUS_BLOCK               SdMmcStatusBlk;\r
+  EFI_SD_MMC_PASS_THRU_COMMAND_PACKET   Packet;\r
+  EFI_STATUS                            Status;\r
+\r
+  ZeroMem (&SdMmcCmdBlk, sizeof (SdMmcCmdBlk));\r
+  ZeroMem (&SdMmcStatusBlk, sizeof (SdMmcStatusBlk));\r
+  ZeroMem (&Packet, sizeof (Packet));\r
+\r
+  Packet.SdMmcCmdBlk    = &SdMmcCmdBlk;\r
+  Packet.SdMmcStatusBlk = &SdMmcStatusBlk;\r
+  Packet.Timeout        = SD_MMC_HC_GENERIC_TIMEOUT;\r
+\r
+  SdMmcCmdBlk.CommandIndex = SD_SET_RELATIVE_ADDR;\r
+  SdMmcCmdBlk.CommandType  = SdMmcCommandTypeBcr;\r
+  SdMmcCmdBlk.ResponseType = SdMmcResponseTypeR6;\r
+\r
+  Status = SdMmcPassThruPassThru (PassThru, Slot, &Packet, NULL);\r
+  if (!EFI_ERROR (Status)) {\r
+    *Rca = (UINT16)(SdMmcStatusBlk.Resp0 >> 16);\r
+  }\r
+\r
+  return Status;\r
+}\r
+\r
+/**\r
+  Send command SEND_CSD to the SD device to get the data of the CSD register.\r
+\r
+  Refer to SD Physical Layer Simplified Spec 4.1 Section 4.7 for details.\r
+\r
+  @param[in]  PassThru      A pointer to the EFI_SD_MMC_PASS_THRU_PROTOCOL instance.\r
+  @param[in]  Slot          The slot number of the SD card to send the command to.\r
+  @param[in]  Rca           The relative device address of selected device.\r
+  @param[out] Csd           The buffer to store the content of the CSD register.\r
+                            Note the caller should ignore the lowest byte of this\r
+                            buffer as the content of this byte is meaningless even\r
+                            if the operation succeeds.\r
+\r
+  @retval EFI_SUCCESS       The operation is done correctly.\r
+  @retval Others            The operation fails.\r
+\r
+**/\r
+EFI_STATUS\r
+SdCardGetCsd (\r
+  IN     EFI_SD_MMC_PASS_THRU_PROTOCOL  *PassThru,\r
+  IN     UINT8                          Slot,\r
+  IN     UINT16                         Rca,\r
+     OUT SD_CSD                         *Csd\r
+  )\r
+{\r
+  EFI_SD_MMC_COMMAND_BLOCK              SdMmcCmdBlk;\r
+  EFI_SD_MMC_STATUS_BLOCK               SdMmcStatusBlk;\r
+  EFI_SD_MMC_PASS_THRU_COMMAND_PACKET   Packet;\r
+  EFI_STATUS                            Status;\r
+\r
+  ZeroMem (&SdMmcCmdBlk, sizeof (SdMmcCmdBlk));\r
+  ZeroMem (&SdMmcStatusBlk, sizeof (SdMmcStatusBlk));\r
+  ZeroMem (&Packet, sizeof (Packet));\r
+\r
+  Packet.SdMmcCmdBlk    = &SdMmcCmdBlk;\r
+  Packet.SdMmcStatusBlk = &SdMmcStatusBlk;\r
+  Packet.Timeout        = SD_MMC_HC_GENERIC_TIMEOUT;\r
+\r
+  SdMmcCmdBlk.CommandIndex = SD_SEND_CSD;\r
+  SdMmcCmdBlk.CommandType  = SdMmcCommandTypeAc;\r
+  SdMmcCmdBlk.ResponseType = SdMmcResponseTypeR2;\r
+  SdMmcCmdBlk.CommandArgument = (UINT32)Rca << 16;\r
+\r
+  Status = SdMmcPassThruPassThru (PassThru, Slot, &Packet, NULL);\r
+  if (!EFI_ERROR (Status)) {\r
+    //\r
+    // For details, refer to SD Host Controller Simplified Spec 3.0 Table 2-12.\r
+    //\r
+    CopyMem (((UINT8*)Csd) + 1, &SdMmcStatusBlk.Resp0, sizeof (SD_CSD) - 1);\r
+  }\r
+\r
+  return Status;\r
+}\r
+\r
+/**\r
+  Send command SEND_CSD to the SD device to get the data of the CSD register.\r
+\r
+  Refer to SD Physical Layer Simplified Spec 4.1 Section 4.7 for details.\r
+\r
+  @param[in]  PassThru      A pointer to the EFI_SD_MMC_PASS_THRU_PROTOCOL instance.\r
+  @param[in]  Slot          The slot number of the SD card to send the command to.\r
+  @param[in]  Rca           The relative device address of selected device.\r
+  @param[out] Scr           The buffer to store the content of the SCR register.\r
+\r
+  @retval EFI_SUCCESS       The operation is done correctly.\r
+  @retval Others            The operation fails.\r
+\r
+**/\r
+EFI_STATUS\r
+SdCardGetScr (\r
+  IN     EFI_SD_MMC_PASS_THRU_PROTOCOL  *PassThru,\r
+  IN     UINT8                          Slot,\r
+  IN     UINT16                         Rca,\r
+     OUT SD_SCR                         *Scr\r
+  )\r
+{\r
+  EFI_SD_MMC_COMMAND_BLOCK              SdMmcCmdBlk;\r
+  EFI_SD_MMC_STATUS_BLOCK               SdMmcStatusBlk;\r
+  EFI_SD_MMC_PASS_THRU_COMMAND_PACKET   Packet;\r
+  EFI_STATUS                            Status;\r
+\r
+  ZeroMem (&SdMmcCmdBlk, sizeof (SdMmcCmdBlk));\r
+  ZeroMem (&SdMmcStatusBlk, sizeof (SdMmcStatusBlk));\r
+  ZeroMem (&Packet, sizeof (Packet));\r
+\r
+  Packet.SdMmcCmdBlk    = &SdMmcCmdBlk;\r
+  Packet.SdMmcStatusBlk = &SdMmcStatusBlk;\r
+  Packet.Timeout        = SD_MMC_HC_GENERIC_TIMEOUT;\r
+\r
+  SdMmcCmdBlk.CommandIndex = SD_APP_CMD;\r
+  SdMmcCmdBlk.CommandType  = SdMmcCommandTypeAc;\r
+  SdMmcCmdBlk.ResponseType = SdMmcResponseTypeR1;\r
+  SdMmcCmdBlk.CommandArgument = (UINT32)Rca << 16;\r
+\r
+  Status = SdMmcPassThruPassThru (PassThru, Slot, &Packet, NULL);\r
+  if (EFI_ERROR (Status)) {\r
+    return Status;\r
+  }\r
+\r
+  SdMmcCmdBlk.CommandIndex = SD_SEND_SCR;\r
+  SdMmcCmdBlk.CommandType  = SdMmcCommandTypeAdtc;\r
+  SdMmcCmdBlk.ResponseType = SdMmcResponseTypeR1;\r
+\r
+  Packet.InDataBuffer     = Scr;\r
+  Packet.InTransferLength = sizeof (SD_SCR);\r
+\r
+  Status = SdMmcPassThruPassThru (PassThru, Slot, &Packet, NULL);\r
+\r
+  return Status;\r
+}\r
+\r
+/**\r
+  Send command SELECT_DESELECT_CARD to the SD device to select/deselect it.\r
+\r
+  Refer to SD Physical Layer Simplified Spec 4.1 Section 4.7 for details.\r
+\r
+  @param[in]  PassThru      A pointer to the EFI_SD_MMC_PASS_THRU_PROTOCOL instance.\r
+  @param[in]  Slot          The slot number of the SD card to send the command to.\r
+  @param[in]  Rca           The relative device address of selected device.\r
+\r
+  @retval EFI_SUCCESS       The operation is done correctly.\r
+  @retval Others            The operation fails.\r
+\r
+**/\r
+EFI_STATUS\r
+SdCardSelect (\r
+  IN EFI_SD_MMC_PASS_THRU_PROTOCOL      *PassThru,\r
+  IN UINT8                              Slot,\r
+  IN UINT16                             Rca\r
+  )\r
+{\r
+  EFI_SD_MMC_COMMAND_BLOCK              SdMmcCmdBlk;\r
+  EFI_SD_MMC_STATUS_BLOCK               SdMmcStatusBlk;\r
+  EFI_SD_MMC_PASS_THRU_COMMAND_PACKET   Packet;\r
+  EFI_STATUS                            Status;\r
+\r
+  ZeroMem (&SdMmcCmdBlk, sizeof (SdMmcCmdBlk));\r
+  ZeroMem (&SdMmcStatusBlk, sizeof (SdMmcStatusBlk));\r
+  ZeroMem (&Packet, sizeof (Packet));\r
+\r
+  Packet.SdMmcCmdBlk    = &SdMmcCmdBlk;\r
+  Packet.SdMmcStatusBlk = &SdMmcStatusBlk;\r
+  Packet.Timeout        = SD_MMC_HC_GENERIC_TIMEOUT;\r
+\r
+  SdMmcCmdBlk.CommandIndex = SD_SELECT_DESELECT_CARD;\r
+  SdMmcCmdBlk.CommandType  = SdMmcCommandTypeAc;\r
+  SdMmcCmdBlk.ResponseType = SdMmcResponseTypeR1b;\r
+  SdMmcCmdBlk.CommandArgument = (UINT32)Rca << 16;\r
+\r
+  Status = SdMmcPassThruPassThru (PassThru, Slot, &Packet, NULL);\r
+\r
+  return Status;\r
+}\r
+\r
+/**\r
+  Send command VOLTAGE_SWITCH to the SD device to switch the voltage of the device.\r
+\r
+  Refer to SD Physical Layer Simplified Spec 4.1 Section 4.7 for details.\r
+\r
+  @param[in]  PassThru      A pointer to the EFI_SD_MMC_PASS_THRU_PROTOCOL instance.\r
+  @param[in]  Slot          The slot number of the SD card to send the command to.\r
+\r
+  @retval EFI_SUCCESS       The operation is done correctly.\r
+  @retval Others            The operation fails.\r
+\r
+**/\r
+EFI_STATUS\r
+SdCardVoltageSwitch (\r
+  IN EFI_SD_MMC_PASS_THRU_PROTOCOL      *PassThru,\r
+  IN UINT8                              Slot\r
+  )\r
+{\r
+  EFI_SD_MMC_COMMAND_BLOCK              SdMmcCmdBlk;\r
+  EFI_SD_MMC_STATUS_BLOCK               SdMmcStatusBlk;\r
+  EFI_SD_MMC_PASS_THRU_COMMAND_PACKET   Packet;\r
+  EFI_STATUS                            Status;\r
+\r
+  ZeroMem (&SdMmcCmdBlk, sizeof (SdMmcCmdBlk));\r
+  ZeroMem (&SdMmcStatusBlk, sizeof (SdMmcStatusBlk));\r
+  ZeroMem (&Packet, sizeof (Packet));\r
+\r
+  Packet.SdMmcCmdBlk    = &SdMmcCmdBlk;\r
+  Packet.SdMmcStatusBlk = &SdMmcStatusBlk;\r
+  Packet.Timeout        = SD_MMC_HC_GENERIC_TIMEOUT;\r
+\r
+  SdMmcCmdBlk.CommandIndex = SD_VOLTAGE_SWITCH;\r
+  SdMmcCmdBlk.CommandType  = SdMmcCommandTypeAc;\r
+  SdMmcCmdBlk.ResponseType = SdMmcResponseTypeR1;\r
+  SdMmcCmdBlk.CommandArgument = 0;\r
+\r
+  Status = SdMmcPassThruPassThru (PassThru, Slot, &Packet, NULL);\r
+\r
+  return Status;\r
+}\r
+\r
+/**\r
+  Send command SET_BUS_WIDTH to the SD device to set the bus width.\r
+\r
+  Refer to SD Physical Layer Simplified Spec 4.1 Section 4.7 for details.\r
+\r
+  @param[in] PassThru       A pointer to the EFI_SD_MMC_PASS_THRU_PROTOCOL instance.\r
+  @param[in] Slot           The slot number of the SD card to send the command to.\r
+  @param[in] Rca            The relative device address of addressed device.\r
+  @param[in] BusWidth       The bus width to be set, it could be 1 or 4.\r
+\r
+  @retval EFI_SUCCESS       The operation is done correctly.\r
+  @retval Others            The operation fails.\r
+\r
+**/\r
+EFI_STATUS\r
+SdCardSetBusWidth (\r
+  IN EFI_SD_MMC_PASS_THRU_PROTOCOL      *PassThru,\r
+  IN UINT8                              Slot,\r
+  IN UINT16                             Rca,\r
+  IN UINT8                              BusWidth\r
+  )\r
+{\r
+  EFI_SD_MMC_COMMAND_BLOCK              SdMmcCmdBlk;\r
+  EFI_SD_MMC_STATUS_BLOCK               SdMmcStatusBlk;\r
+  EFI_SD_MMC_PASS_THRU_COMMAND_PACKET   Packet;\r
+  EFI_STATUS                            Status;\r
+  UINT8                                 Value;\r
+\r
+  ZeroMem (&SdMmcCmdBlk, sizeof (SdMmcCmdBlk));\r
+  ZeroMem (&SdMmcStatusBlk, sizeof (SdMmcStatusBlk));\r
+  ZeroMem (&Packet, sizeof (Packet));\r
+\r
+  Packet.SdMmcCmdBlk    = &SdMmcCmdBlk;\r
+  Packet.SdMmcStatusBlk = &SdMmcStatusBlk;\r
+  Packet.Timeout        = SD_MMC_HC_GENERIC_TIMEOUT;\r
+\r
+  SdMmcCmdBlk.CommandIndex = SD_APP_CMD;\r
+  SdMmcCmdBlk.CommandType  = SdMmcCommandTypeAc;\r
+  SdMmcCmdBlk.ResponseType = SdMmcResponseTypeR1;\r
+  SdMmcCmdBlk.CommandArgument = (UINT32)Rca << 16;\r
+\r
+  Status = SdMmcPassThruPassThru (PassThru, Slot, &Packet, NULL);\r
+  if (EFI_ERROR (Status)) {\r
+    return Status;\r
+  }\r
+\r
+  SdMmcCmdBlk.CommandIndex = SD_SET_BUS_WIDTH;\r
+  SdMmcCmdBlk.CommandType  = SdMmcCommandTypeAc;\r
+  SdMmcCmdBlk.ResponseType = SdMmcResponseTypeR1;\r
+\r
+  if (BusWidth == 1) {\r
+    Value = 0;\r
+  } else if (BusWidth == 4) {\r
+    Value = 2;\r
+  } else {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  SdMmcCmdBlk.CommandArgument = Value & 0x3;\r
+\r
+  Status = SdMmcPassThruPassThru (PassThru, Slot, &Packet, NULL);\r
+  return Status;\r
+}\r
+\r
+/**\r
+  Send command SWITCH_FUNC to the SD device to check switchable function or switch card function.\r
+\r
+  Refer to SD Physical Layer Simplified Spec 4.1 Section 4.7 for details.\r
+\r
+  @param[in]  PassThru      A pointer to the EFI_SD_MMC_PASS_THRU_PROTOCOL instance.\r
+  @param[in]  Slot          The slot number of the SD card to send the command to.\r
+  @param[in]  AccessMode    The value for access mode group.\r
+  @param[in]  CommandSystem The value for command set group.\r
+  @param[in]  DriveStrength The value for drive length group.\r
+  @param[in]  PowerLimit    The value for power limit group.\r
+  @param[in]  Mode          Switch or check function.\r
+\r
+  @retval EFI_SUCCESS       The operation is done correctly.\r
+  @retval Others            The operation fails.\r
+\r
+**/\r
+EFI_STATUS\r
+SdCardSwitch (\r
+  IN EFI_SD_MMC_PASS_THRU_PROTOCOL      *PassThru,\r
+  IN UINT8                              Slot,\r
+  IN UINT8                              AccessMode,\r
+  IN UINT8                              CommandSystem,\r
+  IN UINT8                              DriveStrength,\r
+  IN UINT8                              PowerLimit,\r
+  IN BOOLEAN                            Mode\r
+  )\r
+{\r
+  EFI_SD_MMC_COMMAND_BLOCK              SdMmcCmdBlk;\r
+  EFI_SD_MMC_STATUS_BLOCK               SdMmcStatusBlk;\r
+  EFI_SD_MMC_PASS_THRU_COMMAND_PACKET   Packet;\r
+  EFI_STATUS                            Status;\r
+  UINT32                                ModeValue;\r
+  UINT8                                 Data[64];\r
+\r
+  ZeroMem (&SdMmcCmdBlk, sizeof (SdMmcCmdBlk));\r
+  ZeroMem (&SdMmcStatusBlk, sizeof (SdMmcStatusBlk));\r
+  ZeroMem (&Packet, sizeof (Packet));\r
+\r
+  Packet.SdMmcCmdBlk    = &SdMmcCmdBlk;\r
+  Packet.SdMmcStatusBlk = &SdMmcStatusBlk;\r
+  Packet.Timeout        = SD_MMC_HC_GENERIC_TIMEOUT;\r
+\r
+  SdMmcCmdBlk.CommandIndex = SD_SWITCH_FUNC;\r
+  SdMmcCmdBlk.CommandType  = SdMmcCommandTypeAdtc;\r
+  SdMmcCmdBlk.ResponseType = SdMmcResponseTypeR1;\r
+\r
+  ModeValue = Mode ? BIT31 : 0;\r
+  SdMmcCmdBlk.CommandArgument = (AccessMode & 0xF) | ((PowerLimit & 0xF) << 4) | \\r
+                                ((DriveStrength & 0xF) << 8) | ((DriveStrength & 0xF) << 12) | \\r
+                                ModeValue;\r
+\r
+  Packet.InDataBuffer     = Data;\r
+  Packet.InTransferLength = sizeof (Data);\r
+\r
+  Status = SdMmcPassThruPassThru (PassThru, Slot, &Packet, NULL);\r
+\r
+  return Status;\r
+}\r
+\r
+/**\r
+  Send command SEND_STATUS to the addressed SD device to get its status register.\r
+\r
+  Refer to SD Physical Layer Simplified Spec 4.1 Section 4.7 for details.\r
+\r
+  @param[in]  PassThru      A pointer to the EFI_SD_MMC_PASS_THRU_PROTOCOL instance.\r
+  @param[in]  Slot          The slot number of the SD card to send the command to.\r
+  @param[in]  Rca           The relative device address of addressed device.\r
+  @param[out] DevStatus     The returned device status.\r
+\r
+  @retval EFI_SUCCESS       The operation is done correctly.\r
+  @retval Others            The operation fails.\r
+\r
+**/\r
+EFI_STATUS\r
+SdCardSendStatus (\r
+  IN     EFI_SD_MMC_PASS_THRU_PROTOCOL  *PassThru,\r
+  IN     UINT8                          Slot,\r
+  IN     UINT16                         Rca,\r
+     OUT UINT32                         *DevStatus\r
+  )\r
+{\r
+  EFI_SD_MMC_COMMAND_BLOCK              SdMmcCmdBlk;\r
+  EFI_SD_MMC_STATUS_BLOCK               SdMmcStatusBlk;\r
+  EFI_SD_MMC_PASS_THRU_COMMAND_PACKET   Packet;\r
+  EFI_STATUS                            Status;\r
+\r
+  ZeroMem (&SdMmcCmdBlk, sizeof (SdMmcCmdBlk));\r
+  ZeroMem (&SdMmcStatusBlk, sizeof (SdMmcStatusBlk));\r
+  ZeroMem (&Packet, sizeof (Packet));\r
+\r
+  Packet.SdMmcCmdBlk    = &SdMmcCmdBlk;\r
+  Packet.SdMmcStatusBlk = &SdMmcStatusBlk;\r
+  Packet.Timeout        = SD_MMC_HC_GENERIC_TIMEOUT;\r
+\r
+  SdMmcCmdBlk.CommandIndex = SD_SEND_STATUS;\r
+  SdMmcCmdBlk.CommandType  = SdMmcCommandTypeAc;\r
+  SdMmcCmdBlk.ResponseType = SdMmcResponseTypeR1;\r
+  SdMmcCmdBlk.CommandArgument = (UINT32)Rca << 16;\r
+\r
+  Status = SdMmcPassThruPassThru (PassThru, Slot, &Packet, NULL);\r
+  if (!EFI_ERROR (Status)) {\r
+    *DevStatus = SdMmcStatusBlk.Resp0;\r
+  }\r
+\r
+  return Status;\r
+}\r
+\r
+/**\r
+  Send command SEND_TUNING_BLOCK to the SD device for HS200 optimal sampling point\r
+  detection.\r
+\r
+  It may be sent up to 40 times until the host finishes the tuning procedure.\r
+\r
+  Refer to SD Physical Layer Simplified Spec 4.1 Section 4.7 for details.\r
+\r
+  @param[in] PassThru       A pointer to the EFI_SD_MMC_PASS_THRU_PROTOCOL instance.\r
+  @param[in] Slot           The slot number of the SD card to send the command to.\r
+\r
+  @retval EFI_SUCCESS       The operation is done correctly.\r
+  @retval Others            The operation fails.\r
+\r
+**/\r
+EFI_STATUS\r
+SdCardSendTuningBlk (\r
+  IN EFI_SD_MMC_PASS_THRU_PROTOCOL      *PassThru,\r
+  IN UINT8                              Slot\r
+  )\r
+{\r
+  EFI_SD_MMC_COMMAND_BLOCK              SdMmcCmdBlk;\r
+  EFI_SD_MMC_STATUS_BLOCK               SdMmcStatusBlk;\r
+  EFI_SD_MMC_PASS_THRU_COMMAND_PACKET   Packet;\r
+  EFI_STATUS                            Status;\r
+  UINT8                                 TuningBlock[64];\r
+\r
+  ZeroMem (&SdMmcCmdBlk, sizeof (SdMmcCmdBlk));\r
+  ZeroMem (&SdMmcStatusBlk, sizeof (SdMmcStatusBlk));\r
+  ZeroMem (&Packet, sizeof (Packet));\r
+\r
+  Packet.SdMmcCmdBlk    = &SdMmcCmdBlk;\r
+  Packet.SdMmcStatusBlk = &SdMmcStatusBlk;\r
+  Packet.Timeout        = SD_MMC_HC_GENERIC_TIMEOUT;\r
+\r
+  SdMmcCmdBlk.CommandIndex = SD_SEND_TUNING_BLOCK;\r
+  SdMmcCmdBlk.CommandType  = SdMmcCommandTypeAdtc;\r
+  SdMmcCmdBlk.ResponseType = SdMmcResponseTypeR1;\r
+  SdMmcCmdBlk.CommandArgument = 0;\r
+\r
+  Packet.InDataBuffer     = TuningBlock;\r
+  Packet.InTransferLength = sizeof (TuningBlock);\r
+\r
+  Status = SdMmcPassThruPassThru (PassThru, Slot, &Packet, NULL);\r
+\r
+  return Status;\r
+}\r
+\r
+/**\r
+  Tunning the sampling point of SDR104 or SDR50 bus speed mode.\r
+\r
+  Command SD_SEND_TUNING_BLOCK may be sent up to 40 times until the host finishes the\r
+  tuning procedure.\r
+\r
+  Refer to SD Physical Layer Simplified Spec 4.1 Section 4.7 and\r
+  SD Host Controller Simplified Spec 3.0 section Figure 3-7 for details.\r
+\r
+  @param[in] PciIo          A pointer to the EFI_PCI_IO_PROTOCOL instance.\r
+  @param[in] PassThru       A pointer to the EFI_SD_MMC_PASS_THRU_PROTOCOL instance.\r
+  @param[in] Slot           The slot number of the SD card to send the command to.\r
+\r
+  @retval EFI_SUCCESS       The operation is done correctly.\r
+  @retval Others            The operation fails.\r
+\r
+**/\r
+EFI_STATUS\r
+SdCardTuningClock (\r
+  IN EFI_PCI_IO_PROTOCOL                *PciIo,\r
+  IN EFI_SD_MMC_PASS_THRU_PROTOCOL      *PassThru,\r
+  IN UINT8                              Slot\r
+  )\r
+{\r
+  EFI_STATUS          Status;\r
+  UINT8               HostCtrl2;\r
+  UINT8               Retry;\r
+\r
+  //\r
+  // Notify the host that the sampling clock tuning procedure starts.\r
+  //\r
+  HostCtrl2 = BIT6;\r
+  Status = SdMmcHcOrMmio (PciIo, Slot, SD_MMC_HC_HOST_CTRL2, sizeof (HostCtrl2), &HostCtrl2);\r
+  if (EFI_ERROR (Status)) {\r
+    return Status;\r
+  }\r
+  //\r
+  // Ask the device to send a sequence of tuning blocks till the tuning procedure is done.\r
+  //\r
+  Retry = 0;\r
+  do {\r
+    Status = SdCardSendTuningBlk (PassThru, Slot);\r
+    if (EFI_ERROR (Status)) {\r
+      DEBUG ((EFI_D_ERROR, "SdCardSendTuningBlk: Send tuning block fails with %r\n", Status));\r
+      return Status;\r
+    }\r
+\r
+    Status = SdMmcHcRwMmio (PciIo, Slot, SD_MMC_HC_HOST_CTRL2, TRUE, sizeof (HostCtrl2), &HostCtrl2);\r
+    if (EFI_ERROR (Status)) {\r
+      return Status;\r
+    }\r
+\r
+    if ((HostCtrl2 & (BIT6 | BIT7)) == BIT7) {\r
+      break;\r
+    }\r
+  } while (++Retry < 40);\r
+\r
+  if (Retry == 40) {\r
+    Status = EFI_TIMEOUT;\r
+    DEBUG ((EFI_D_ERROR, "SdCardTuningClock: Send tuning block exceeds 40 times\n"));\r
+  }\r
+\r
+  return Status;\r
+}\r
+\r
+/**\r
+  Switch the bus width to specified width.\r
+\r
+  Refer to SD Physical Layer Simplified Spec 4.1 Section 4.7 and\r
+  SD Host Controller Simplified Spec 3.0 section Figure 3-7 for details.\r
+\r
+  @param[in] PciIo          A pointer to the EFI_PCI_IO_PROTOCOL instance.\r
+  @param[in] PassThru       A pointer to the EFI_SD_MMC_PASS_THRU_PROTOCOL instance.\r
+  @param[in] Slot           The slot number of the SD card to send the command to.\r
+  @param[in] Rca            The relative device address to be assigned.\r
+  @param[in] BusWidth       The bus width to be set, it could be 4 or 8.\r
+\r
+  @retval EFI_SUCCESS       The operation is done correctly.\r
+  @retval Others            The operation fails.\r
+\r
+**/\r
+EFI_STATUS\r
+SdCardSwitchBusWidth (\r
+  IN EFI_PCI_IO_PROTOCOL                *PciIo,\r
+  IN EFI_SD_MMC_PASS_THRU_PROTOCOL      *PassThru,\r
+  IN UINT8                              Slot,\r
+  IN UINT16                             Rca,\r
+  IN UINT8                              BusWidth\r
+  )\r
+{\r
+  EFI_STATUS          Status;\r
+  UINT32              DevStatus;\r
+\r
+  Status = SdCardSetBusWidth (PassThru, Slot, Rca, BusWidth);\r
+  if (EFI_ERROR (Status)) {\r
+    DEBUG ((EFI_D_ERROR, "SdCardSwitchBusWidth: Switch to bus width %d fails with %r\n", BusWidth, Status));\r
+    return Status;\r
+  }\r
+\r
+  Status = SdCardSendStatus (PassThru, Slot, Rca, &DevStatus);\r
+  if (EFI_ERROR (Status)) {\r
+    DEBUG ((EFI_D_ERROR, "SdCardSwitchBusWidth: Send status fails with %r\n", Status));\r
+    return Status;\r
+  }\r
+  //\r
+  // Check the switch operation is really successful or not.\r
+  //\r
+  if ((DevStatus >> 16) != 0) {\r
+    DEBUG ((EFI_D_ERROR, "SdCardSwitchBusWidth: The switch operation fails as DevStatus is 0x%08x\n", DevStatus));\r
+    return EFI_DEVICE_ERROR;\r
+  }\r
+\r
+  Status = SdMmcHcSetBusWidth (PciIo, Slot, BusWidth);\r
+\r
+  return Status;\r
+}\r
+\r
+/**\r
+  Switch the high speed timing according to request.\r
+\r
+  Refer to SD Physical Layer Simplified Spec 4.1 Section 4.7 and\r
+  SD Host Controller Simplified Spec 3.0 section Figure 2-29 for details.\r
+\r
+  @param[in] PciIo          A pointer to the EFI_PCI_IO_PROTOCOL instance.\r
+  @param[in] PassThru       A pointer to the EFI_SD_MMC_PASS_THRU_PROTOCOL instance.\r
+  @param[in] Slot           The slot number of the SD card to send the command to.\r
+  @param[in] Rca            The relative device address to be assigned.\r
+  @param[in] S18A           The boolean to show if it's a UHS-I SD card.\r
+\r
+  @retval EFI_SUCCESS       The operation is done correctly.\r
+  @retval Others            The operation fails.\r
+\r
+**/\r
+EFI_STATUS\r
+SdCardSetBusMode (\r
+  IN EFI_PCI_IO_PROTOCOL                *PciIo,\r
+  IN EFI_SD_MMC_PASS_THRU_PROTOCOL      *PassThru,\r
+  IN UINT8                              Slot,\r
+  IN UINT16                             Rca,\r
+  IN BOOLEAN                            S18A\r
+  )\r
+{\r
+  EFI_STATUS                   Status;\r
+  SD_MMC_HC_SLOT_CAP           *Capability;\r
+  UINT32                       ClockFreq;\r
+  UINT8                        BusWidth;\r
+  UINT8                        AccessMode;\r
+  UINT8                        HostCtrl1;\r
+  UINT8                        HostCtrl2;\r
+  SD_MMC_HC_PRIVATE_DATA       *Private;\r
+\r
+  Private = SD_MMC_HC_PRIVATE_FROM_THIS (PassThru);\r
+\r
+  Capability = &Private->Capability[Slot];\r
+\r
+  Status = SdCardSelect (PassThru, Slot, Rca);\r
+  if (EFI_ERROR (Status)) {\r
+    return Status;\r
+  }\r
+\r
+  BusWidth = 4;\r
+\r
+  Status = SdCardSwitchBusWidth (PciIo, PassThru, Slot, Rca, BusWidth);\r
+  if (EFI_ERROR (Status)) {\r
+    return Status;\r
+  }\r
+\r
+  //\r
+  // Calculate supported bus speed/bus width/clock frequency.\r
+  //\r
+  ClockFreq = 0;\r
+  if (S18A && (Capability->Sdr104 != 0)) {\r
+    ClockFreq = 208;\r
+    AccessMode = 3;\r
+  } else if (S18A && (Capability->Sdr50 != 0)) {\r
+    ClockFreq = 100;\r
+    AccessMode = 2;\r
+  } else if (S18A && (Capability->Ddr50 != 0)) {\r
+    ClockFreq = 50;\r
+    AccessMode = 4;\r
+  } else {\r
+    ClockFreq = 50;\r
+    AccessMode = 1;\r
+  }\r
+\r
+  DEBUG ((EFI_D_INFO, "SdCardSetBusMode: AccessMode %d ClockFreq %d BusWidth %d\n", AccessMode, ClockFreq, BusWidth));\r
+\r
+  Status = SdCardSwitch (PassThru, Slot, AccessMode, 0, 0, 0, TRUE);\r
+  if (EFI_ERROR (Status)) {\r
+    return Status;\r
+  }\r
+\r
+  //\r
+  // Set to Hight Speed timing\r
+  //\r
+  if (AccessMode == 1) {\r
+    HostCtrl1 = BIT2;\r
+    Status = SdMmcHcOrMmio (PciIo, Slot, SD_MMC_HC_HOST_CTRL1, sizeof (HostCtrl1), &HostCtrl1);\r
+    if (EFI_ERROR (Status)) {\r
+      return Status;\r
+    }\r
+  }\r
+\r
+  HostCtrl2 = (UINT8)~0x7;\r
+  Status = SdMmcHcAndMmio (PciIo, Slot, SD_MMC_HC_HOST_CTRL2, sizeof (HostCtrl2), &HostCtrl2);\r
+  if (EFI_ERROR (Status)) {\r
+    return Status;\r
+  }\r
+  HostCtrl2 = AccessMode;\r
+  Status = SdMmcHcOrMmio (PciIo, Slot, SD_MMC_HC_HOST_CTRL2, sizeof (HostCtrl2), &HostCtrl2);\r
+  if (EFI_ERROR (Status)) {\r
+    return Status;\r
+  }\r
+\r
+  Status = SdMmcHcClockSupply (PciIo, Slot, ClockFreq * 1000, *Capability);\r
+  if (EFI_ERROR (Status)) {\r
+    return Status;\r
+  }\r
+\r
+  if ((AccessMode == 3) || ((AccessMode == 2) && (Capability->TuningSDR50 != 0))) {\r
+    Status = SdCardTuningClock (PciIo, PassThru, Slot);\r
+    if (EFI_ERROR (Status)) {\r
+      return Status;\r
+    }\r
+  }\r
+\r
+  return Status;\r
+}\r
+\r
+/**\r
+  Execute SD device identification procedure.\r
+\r
+  Refer to SD Physical Layer Simplified Spec 4.1 Section 3.6 for details.\r
+\r
+  @param[in] Private        A pointer to the SD_MMC_HC_PRIVATE_DATA instance.\r
+  @param[in] Slot           The slot number of the SD card to send the command to.\r
+\r
+  @retval EFI_SUCCESS       There is a SD card.\r
+  @retval Others            There is not a SD card.\r
+\r
+**/\r
+EFI_STATUS\r
+SdCardIdentification (\r
+  IN SD_MMC_HC_PRIVATE_DATA             *Private,\r
+  IN UINT8                              Slot\r
+  )\r
+{\r
+  EFI_STATUS                     Status;\r
+  EFI_PCI_IO_PROTOCOL            *PciIo;\r
+  EFI_SD_MMC_PASS_THRU_PROTOCOL  *PassThru;\r
+  UINT32                         Ocr;\r
+  UINT16                         Rca;\r
+  BOOLEAN                        Xpc;\r
+  BOOLEAN                        S18r;\r
+  UINT64                         MaxCurrent;\r
+  UINT16                         ControllerVer;\r
+  UINT8                          PowerCtrl;\r
+  UINT32                         PresentState;\r
+  UINT8                          HostCtrl2;\r
+\r
+  PciIo    = Private->PciIo;\r
+  PassThru = &Private->PassThru;\r
+  //\r
+  // 1. Send Cmd0 to the device\r
+  //\r
+  Status = SdCardReset (PassThru, Slot);\r
+  if (EFI_ERROR (Status)) {\r
+    DEBUG ((EFI_D_INFO, "SdCardIdentification: Executing Cmd0 fails with %r\n", Status));\r
+    return Status;\r
+  }\r
+  //\r
+  // 2. Send Cmd8 to the device\r
+  //\r
+  Status = SdCardVoltageCheck (PassThru, Slot, 0x1, 0xFF);\r
+  if (EFI_ERROR (Status)) {\r
+    DEBUG ((EFI_D_INFO, "SdCardIdentification: Executing Cmd8 fails with %r\n", Status));\r
+    return Status;\r
+  }\r
+  //\r
+  // 3. Send SDIO Cmd5 to the device to the SDIO device OCR register.\r
+  //\r
+  Status = SdioSendOpCond (PassThru, Slot, 0, FALSE);\r
+  if (!EFI_ERROR (Status)) {\r
+    DEBUG ((EFI_D_INFO, "SdCardIdentification: Found SDIO device, ignore it as we don't support\n"));\r
+    return EFI_DEVICE_ERROR;\r
+  }\r
+  //\r
+  // 4. Send Acmd41 with voltage window 0 to the device\r
+  //\r
+  Status = SdCardSendOpCond (PassThru, Slot, 0, 0, FALSE, FALSE, FALSE, &Ocr);\r
+  if (EFI_ERROR (Status)) {\r
+    DEBUG ((EFI_D_INFO, "SdCardIdentification: Executing SdCardSendOpCond fails with %r\n", Status));\r
+    return EFI_DEVICE_ERROR;\r
+  }\r
+\r
+  if (Private->Capability[Slot].Voltage33 != 0) {\r
+    //\r
+    // Support 3.3V\r
+    //\r
+    MaxCurrent = ((UINT32)Private->MaxCurrent[Slot] & 0xFF) * 4;\r
+  } else if (Private->Capability[Slot].Voltage30 != 0) {\r
+    //\r
+    // Support 3.0V\r
+    //\r
+    MaxCurrent = (((UINT32)Private->MaxCurrent[Slot] >> 8) & 0xFF) * 4;\r
+  } else if (Private->Capability[Slot].Voltage18 != 0) {\r
+    //\r
+    // Support 1.8V\r
+    //\r
+    MaxCurrent = (((UINT32)Private->MaxCurrent[Slot] >> 16) & 0xFF) * 4;\r
+  } else {\r
+    ASSERT (FALSE);\r
+    return EFI_DEVICE_ERROR;\r
+  }\r
+\r
+  if (MaxCurrent >= 150) {\r
+    Xpc = TRUE;\r
+  } else {\r
+    Xpc = FALSE;\r
+  }\r
+\r
+  Status = SdMmcHcRwMmio (PciIo, Slot, SD_MMC_HC_CTRL_VER, TRUE, sizeof (ControllerVer), &ControllerVer);\r
+  if (EFI_ERROR (Status)) {\r
+    return Status;\r
+  }\r
+\r
+  if ((ControllerVer & 0xFF) == 2) {\r
+    S18r = TRUE;\r
+  } else if (((ControllerVer & 0xFF) == 0) || ((ControllerVer & 0xFF) == 1)) {\r
+    S18r = FALSE;\r
+  } else {\r
+    ASSERT (FALSE);\r
+    return EFI_UNSUPPORTED;\r
+  }\r
+  //\r
+  // 5. Repeatly send Acmd41 with supply voltage window to the device.\r
+  //    Note here we only support the cards complied with SD physical\r
+  //    layer simplified spec version 2.0 and version 3.0 and above.\r
+  //\r
+  do {\r
+    Status = SdCardSendOpCond (PassThru, Slot, 0, Ocr, S18r, Xpc, TRUE, &Ocr);\r
+    if (EFI_ERROR (Status)) {\r
+      DEBUG ((EFI_D_ERROR, "SdCardIdentification: SdCardSendOpCond fails with %r Ocr %x, S18r %x, Xpc %x\n", Status, Ocr, S18r, Xpc));\r
+      return EFI_DEVICE_ERROR;\r
+    }\r
+  } while ((Ocr & BIT31) == 0);\r
+\r
+  //\r
+  // 6. If the S18A bit is set and the Host Controller supports 1.8V signaling\r
+  //    (One of support bits is set to 1: SDR50, SDR104 or DDR50 in the\r
+  //    Capabilities register), switch its voltage to 1.8V.\r
+  //\r
+  if ((Private->Capability[Slot].Sdr50 != 0 ||\r
+       Private->Capability[Slot].Sdr104 != 0 ||\r
+       Private->Capability[Slot].Ddr50 != 0) &&\r
+       ((Ocr & BIT24) != 0)) {\r
+    Status = SdCardVoltageSwitch (PassThru, Slot);\r
+    if (EFI_ERROR (Status)) {\r
+      DEBUG ((EFI_D_ERROR, "SdCardIdentification: Executing SdCardVoltageSwitch fails with %r\n", Status));\r
+      Status = EFI_DEVICE_ERROR;\r
+      goto Error;\r
+    } else {\r
+      Status = SdMmcHcStopClock (PciIo, Slot);\r
+      if (EFI_ERROR (Status)) {\r
+        Status = EFI_DEVICE_ERROR;\r
+        goto Error;\r
+      }\r
+\r
+      SdMmcHcRwMmio (PciIo, Slot, SD_MMC_HC_PRESENT_STATE, TRUE, sizeof (PresentState), &PresentState);\r
+      if (((PresentState >> 20) & 0xF) != 0) {\r
+        DEBUG ((EFI_D_ERROR, "SdCardIdentification: SwitchVoltage fails with PresentState = 0x%x\n", PresentState));\r
+        Status = EFI_DEVICE_ERROR;\r
+        goto Error;\r
+      }\r
+      HostCtrl2  = BIT3;\r
+      SdMmcHcOrMmio (PciIo, Slot, SD_MMC_HC_HOST_CTRL2, sizeof (HostCtrl2), &HostCtrl2);\r
+\r
+      gBS->Stall (5000);\r
+\r
+      SdMmcHcRwMmio (PciIo, Slot, SD_MMC_HC_HOST_CTRL2, TRUE, sizeof (HostCtrl2), &HostCtrl2);\r
+      if ((HostCtrl2 & BIT3) == 0) {\r
+        DEBUG ((EFI_D_ERROR, "SdCardIdentification: SwitchVoltage fails with HostCtrl2 = 0x%x\n", HostCtrl2));\r
+        Status = EFI_DEVICE_ERROR;\r
+        goto Error;\r
+      }\r
+\r
+      SdMmcHcInitClockFreq (PciIo, Slot, Private->Capability[Slot]);\r
+\r
+      gBS->Stall (1);\r
+\r
+      SdMmcHcRwMmio (PciIo, Slot, SD_MMC_HC_PRESENT_STATE, TRUE, sizeof (PresentState), &PresentState);\r
+      if (((PresentState >> 20) & 0xF) != 0xF) {\r
+        DEBUG ((EFI_D_ERROR, "SdCardIdentification: SwitchVoltage fails with PresentState = 0x%x, It should be 0xF\n", PresentState));\r
+        Status = EFI_DEVICE_ERROR;\r
+        goto Error;\r
+      }\r
+    }\r
+    DEBUG ((EFI_D_INFO, "SdCardIdentification: Switch to 1.8v signal voltage success\n"));\r
+  }\r
+\r
+  Status = SdCardAllSendCid (PassThru, Slot);\r
+  if (EFI_ERROR (Status)) {\r
+    DEBUG ((EFI_D_ERROR, "SdCardIdentification: Executing SdCardAllSendCid fails with %r\n", Status));\r
+    return Status;\r
+  }\r
+\r
+  Status = SdCardSetRca (PassThru, Slot, &Rca);\r
+  if (EFI_ERROR (Status)) {\r
+    DEBUG ((EFI_D_ERROR, "SdCardIdentification: Executing SdCardSetRca fails with %r\n", Status));\r
+    return Status;\r
+  }\r
+  //\r
+  // Enter Data Tranfer Mode.\r
+  //\r
+  DEBUG ((EFI_D_INFO, "SdCardIdentification: Found a SD device at slot [%d]\n", Slot));\r
+  Private->Slot[Slot].CardType = SdCardType;\r
+\r
+  Status = SdCardSetBusMode (PciIo, PassThru, Slot, Rca, ((Ocr & BIT24) != 0));\r
+\r
+  return Status;\r
+\r
+Error:\r
+  //\r
+  // Set SD Bus Power = 0\r
+  //\r
+  PowerCtrl = (UINT8)~BIT0;\r
+  Status = SdMmcHcAndMmio (PciIo, Slot, SD_MMC_HC_POWER_CTRL, sizeof (PowerCtrl), &PowerCtrl);\r
+  return EFI_DEVICE_ERROR;\r
+}\r
+\r
diff --git a/MdeModulePkg/Bus/Pci/SdMmcPciHcDxe/SdMmcPciHcDxe.c b/MdeModulePkg/Bus/Pci/SdMmcPciHcDxe/SdMmcPciHcDxe.c
new file mode 100644 (file)
index 0000000..0a2f034
--- /dev/null
@@ -0,0 +1,1261 @@
+/** @file\r
+  This driver is used to manage SD/MMC PCI host controllers which are compliance\r
+  with SD Host Controller Simplified Specification version 3.00.\r
+\r
+  It would expose EFI_SD_MMC_PASS_THRU_PROTOCOL for upper layer use.\r
+\r
+  Copyright (c) 2015, Intel Corporation. All rights reserved.<BR>\r
+  This program and the accompanying materials\r
+  are licensed and made available under the terms and conditions of the BSD License\r
+  which accompanies this distribution.  The full text of the license may be found at\r
+  http://opensource.org/licenses/bsd-license.php\r
+\r
+  THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+  WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+\r
+**/\r
+\r
+#include "SdMmcPciHcDxe.h"\r
+\r
+//\r
+// Driver Global Variables\r
+//\r
+EFI_DRIVER_BINDING_PROTOCOL gSdMmcPciHcDriverBinding = {\r
+  SdMmcPciHcDriverBindingSupported,\r
+  SdMmcPciHcDriverBindingStart,\r
+  SdMmcPciHcDriverBindingStop,\r
+  0x10,\r
+  NULL,\r
+  NULL\r
+};\r
+\r
+//\r
+// Template for SD/MMC host controller private data.\r
+//\r
+SD_MMC_HC_PRIVATE_DATA gSdMmcPciHcTemplate = {\r
+  SD_MMC_HC_PRIVATE_SIGNATURE,      // Signature\r
+  NULL,                             // ControllerHandle\r
+  NULL,                             // PciIo\r
+  {                                 // PassThru\r
+    sizeof (UINT32),\r
+    SdMmcPassThruPassThru,\r
+    SdMmcPassThruGetNextSlot,\r
+    SdMmcPassThruBuildDevicePath,\r
+    SdMmcPassThruGetSlotNumber,\r
+    SdMmcPassThruResetDevice\r
+  },\r
+  0,                                // PciAttributes\r
+  0,                                // PreviousSlot\r
+  NULL,                             // TimerEvent\r
+  NULL,                             // ConnectEvent\r
+                                    // Queue\r
+  INITIALIZE_LIST_HEAD_VARIABLE (gSdMmcPciHcTemplate.Queue),\r
+  {                                 // Slot\r
+    {0, UnknownSlot, 0, 0}, {0, UnknownSlot, 0, 0}, {0, UnknownSlot, 0, 0},\r
+    {0, UnknownSlot, 0, 0}, {0, UnknownSlot, 0, 0}, {0, UnknownSlot, 0, 0}\r
+  },\r
+  {                                 // Capability\r
+    {0},\r
+  },\r
+  {                                 // MaxCurrent\r
+    0,\r
+  },\r
+  0                                 // ControllerVersion\r
+};\r
+\r
+SD_DEVICE_PATH    mSdDpTemplate = {\r
+  {\r
+    MESSAGING_DEVICE_PATH,\r
+    MSG_SD_DP,\r
+    {\r
+      (UINT8) (sizeof (SD_DEVICE_PATH)),\r
+      (UINT8) ((sizeof (SD_DEVICE_PATH)) >> 8)\r
+    }\r
+  },\r
+  0\r
+};\r
+\r
+EMMC_DEVICE_PATH    mEmmcDpTemplate = {\r
+  {\r
+    MESSAGING_DEVICE_PATH,\r
+    MSG_EMMC_DP,\r
+    {\r
+      (UINT8) (sizeof (EMMC_DEVICE_PATH)),\r
+      (UINT8) ((sizeof (EMMC_DEVICE_PATH)) >> 8)\r
+    }\r
+  },\r
+  0\r
+};\r
+\r
+//\r
+// Prioritized function list to detect card type.\r
+// User could add other card detection logic here.\r
+//\r
+CARD_TYPE_DETECT_ROUTINE mCardTypeDetectRoutineTable[] = {\r
+  EmmcIdentification,\r
+  SdCardIdentification,\r
+  NULL\r
+};\r
+\r
+/**\r
+  The entry point for SD host controller driver, used to install this driver on the ImageHandle.\r
+\r
+  @param[in]  ImageHandle   The firmware allocated handle for this driver image.\r
+  @param[in]  SystemTable   Pointer to the EFI system table.\r
+\r
+  @retval EFI_SUCCESS   Driver loaded.\r
+  @retval other         Driver not loaded.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+InitializeSdMmcPciHcDxe (\r
+  IN EFI_HANDLE        ImageHandle,\r
+  IN EFI_SYSTEM_TABLE  *SystemTable\r
+  )\r
+{\r
+  EFI_STATUS           Status;\r
+\r
+  Status = EfiLibInstallDriverBindingComponentName2 (\r
+             ImageHandle,\r
+             SystemTable,\r
+             &gSdMmcPciHcDriverBinding,\r
+             ImageHandle,\r
+             &gSdMmcPciHcComponentName,\r
+             &gSdMmcPciHcComponentName2\r
+             );\r
+  ASSERT_EFI_ERROR (Status);\r
+\r
+  return Status;\r
+}\r
+\r
+/**\r
+  Call back function when the timer event is signaled.\r
+\r
+  @param[in]  Event     The Event this notify function registered to.\r
+  @param[in]  Context   Pointer to the context data registered to the\r
+                        Event.\r
+\r
+**/\r
+VOID\r
+EFIAPI\r
+ProcessAsyncTaskList (\r
+  IN EFI_EVENT          Event,\r
+  IN VOID*              Context\r
+  )\r
+{\r
+  SD_MMC_HC_PRIVATE_DATA              *Private;\r
+  LIST_ENTRY                          *Link;\r
+  SD_MMC_HC_TRB                       *Trb;\r
+  EFI_STATUS                          Status;\r
+  EFI_SD_MMC_PASS_THRU_COMMAND_PACKET *Packet;\r
+  BOOLEAN                             InfiniteWait;\r
+  EFI_EVENT                           TrbEvent;\r
+\r
+  Private = (SD_MMC_HC_PRIVATE_DATA*)Context;\r
+\r
+  //\r
+  // Check if the first entry in the async I/O queue is done or not.\r
+  //\r
+  Status = EFI_SUCCESS;\r
+  Trb    = NULL;\r
+  Link   = GetFirstNode (&Private->Queue);\r
+  if (!IsNull (&Private->Queue, Link)) {\r
+    Trb = SD_MMC_HC_TRB_FROM_THIS (Link);\r
+    if (Private->Slot[Trb->Slot].MediaPresent == FALSE) {\r
+      Status = EFI_NO_MEDIA;\r
+      goto Done;\r
+    }\r
+    if (!Trb->Started) {\r
+      //\r
+      // Check whether the cmd/data line is ready for transfer.\r
+      //\r
+      Status = SdMmcCheckTrbEnv (Private, Trb);\r
+      if (!EFI_ERROR (Status)) {\r
+        Trb->Started = TRUE;\r
+        Status = SdMmcExecTrb (Private, Trb);\r
+        if (EFI_ERROR (Status)) {\r
+          goto Done;\r
+        }\r
+      } else {\r
+        goto Done;\r
+      }\r
+    }\r
+    Status = SdMmcCheckTrbResult (Private, Trb);\r
+  }\r
+\r
+Done:\r
+  if ((Trb != NULL) && (Status == EFI_NOT_READY)) {\r
+    Packet = Trb->Packet;\r
+    if (Packet->Timeout == 0) {\r
+      InfiniteWait = TRUE;\r
+    } else {\r
+      InfiniteWait = FALSE;\r
+    }\r
+    if ((!InfiniteWait) && (Trb->Timeout-- == 0)) {\r
+      RemoveEntryList (Link);\r
+      Trb->Packet->TransactionStatus = EFI_TIMEOUT;\r
+      TrbEvent = Trb->Event;\r
+      SdMmcFreeTrb (Trb);\r
+      DEBUG ((EFI_D_VERBOSE, "ProcessAsyncTaskList(): Signal Event %p EFI_TIMEOUT\n", TrbEvent));\r
+      gBS->SignalEvent (TrbEvent);\r
+      return;\r
+    }\r
+  }\r
+  if ((Trb != NULL) && (Status != EFI_NOT_READY)) {\r
+    RemoveEntryList (Link);\r
+    Trb->Packet->TransactionStatus = Status;\r
+    TrbEvent = Trb->Event;\r
+    SdMmcFreeTrb (Trb);\r
+    DEBUG ((EFI_D_VERBOSE, "ProcessAsyncTaskList(): Signal Event %p with %r\n", TrbEvent, Status));\r
+    gBS->SignalEvent (TrbEvent);\r
+  }\r
+  return;\r
+}\r
+\r
+/**\r
+  Sd removable device enumeration callback function when the timer event is signaled.\r
+\r
+  @param[in]  Event     The Event this notify function registered to.\r
+  @param[in]  Context   Pointer to the context data registered to the\r
+                        Event.\r
+\r
+**/\r
+VOID\r
+EFIAPI\r
+SdMmcPciHcEnumerateDevice (\r
+  IN EFI_EVENT          Event,\r
+  IN VOID*              Context\r
+  )\r
+{\r
+  SD_MMC_HC_PRIVATE_DATA              *Private;\r
+  EFI_STATUS                          Status;\r
+  UINT8                               Slot;\r
+  BOOLEAN                             MediaPresent;\r
+  UINT32                              RoutineNum;\r
+  CARD_TYPE_DETECT_ROUTINE            *Routine;\r
+  UINTN                               Index;\r
+  LIST_ENTRY                          *Link;\r
+  LIST_ENTRY                          *NextLink;\r
+  SD_MMC_HC_TRB                       *Trb;\r
+\r
+  Private = (SD_MMC_HC_PRIVATE_DATA*)Context;\r
+\r
+  for (Slot = 0; Slot < SD_MMC_HC_MAX_SLOT; Slot++) {\r
+    if ((Private->Slot[Slot].Enable) && (Private->Slot[Slot].SlotType == RemovableSlot)) {\r
+      Status = SdMmcHcCardDetect (Private->PciIo, Slot, &MediaPresent);\r
+      if ((Status == EFI_MEDIA_CHANGED) && (MediaPresent == FALSE)) {\r
+        DEBUG ((EFI_D_INFO, "SdMmcPciHcEnumerateDevice: device disconnected at slot %d of pci %p\n", Slot, Private->PciIo));\r
+        Private->Slot[Slot].MediaPresent = FALSE;\r
+        //\r
+        // Signal all async task events at the slot with EFI_NO_MEDIA status.\r
+        //\r
+        for (Link = GetFirstNode (&Private->Queue);\r
+             !IsNull (&Private->Queue, Link);\r
+             Link = NextLink) {\r
+          NextLink = GetNextNode (&Private->Queue, Link);\r
+          Trb = SD_MMC_HC_TRB_FROM_THIS (Link);\r
+          if (Trb->Slot == Slot) {\r
+            RemoveEntryList (Link);\r
+            Trb->Packet->TransactionStatus = EFI_NO_MEDIA;\r
+            gBS->SignalEvent (Trb->Event);\r
+            SdMmcFreeTrb (Trb);\r
+          }\r
+        }\r
+        //\r
+        // Notify the upper layer the connect state change through ReinstallProtocolInterface.\r
+        //\r
+        gBS->ReinstallProtocolInterface (\r
+              Private->ControllerHandle,\r
+              &gEfiSdMmcPassThruProtocolGuid,\r
+              &Private->PassThru,\r
+              &Private->PassThru\r
+              );\r
+      }\r
+      if ((Status == EFI_MEDIA_CHANGED) && (MediaPresent == TRUE)) {\r
+        DEBUG ((EFI_D_INFO, "SdMmcPciHcEnumerateDevice: device connected at slot %d of pci %p\n", Slot, Private->PciIo));\r
+        //\r
+        // Reinitialize slot and restart identification process for the new attached device\r
+        //\r
+        Status = SdMmcHcInitHost (Private->PciIo, Slot, Private->Capability[Slot]);\r
+        if (EFI_ERROR (Status)) {\r
+          continue;\r
+        }\r
+\r
+        Private->Slot[Slot].MediaPresent = TRUE;\r
+        RoutineNum = sizeof (mCardTypeDetectRoutineTable) / sizeof (CARD_TYPE_DETECT_ROUTINE);\r
+        for (Index = 0; Index < RoutineNum; Index++) {\r
+          Routine = &mCardTypeDetectRoutineTable[Index];\r
+          if (*Routine != NULL) {\r
+            Status = (*Routine) (Private, Slot);\r
+            if (!EFI_ERROR (Status)) {\r
+              break;\r
+            }\r
+          }\r
+        }\r
+\r
+        //\r
+        // Notify the upper layer the connect state change through ReinstallProtocolInterface.\r
+        //\r
+        gBS->ReinstallProtocolInterface (\r
+               Private->ControllerHandle,\r
+               &gEfiSdMmcPassThruProtocolGuid,\r
+               &Private->PassThru,\r
+               &Private->PassThru\r
+               );\r
+      }\r
+    }\r
+  }\r
+\r
+  return;\r
+}\r
+/**\r
+  Tests to see if this driver supports a given controller. If a child device is provided,\r
+  it further tests to see if this driver supports creating a handle for the specified child device.\r
+\r
+  This function checks to see if the driver specified by This supports the device specified by\r
+  ControllerHandle. Drivers will typically use the device path attached to\r
+  ControllerHandle and/or the services from the bus I/O abstraction attached to\r
+  ControllerHandle to determine if the driver supports ControllerHandle. This function\r
+  may be called many times during platform initialization. In order to reduce boot times, the tests\r
+  performed by this function must be very small, and take as little time as possible to execute. This\r
+  function must not change the state of any hardware devices, and this function must be aware that the\r
+  device specified by ControllerHandle may already be managed by the same driver or a\r
+  different driver. This function must match its calls to AllocatePages() with FreePages(),\r
+  AllocatePool() with FreePool(), and OpenProtocol() with CloseProtocol().\r
+  Since ControllerHandle may have been previously started by the same driver, if a protocol is\r
+  already in the opened state, then it must not be closed with CloseProtocol(). This is required\r
+  to guarantee the state of ControllerHandle is not modified by this function.\r
+\r
+  @param[in]  This                 A pointer to the EFI_DRIVER_BINDING_PROTOCOL instance.\r
+  @param[in]  ControllerHandle     The handle of the controller to test. This handle\r
+                                   must support a protocol interface that supplies\r
+                                   an I/O abstraction to the driver.\r
+  @param[in]  RemainingDevicePath  A pointer to the remaining portion of a device path.  This\r
+                                   parameter is ignored by device drivers, and is optional for bus\r
+                                   drivers. For bus drivers, if this parameter is not NULL, then\r
+                                   the bus driver must determine if the bus controller specified\r
+                                   by ControllerHandle and the child controller specified\r
+                                   by RemainingDevicePath are both supported by this\r
+                                   bus driver.\r
+\r
+  @retval EFI_SUCCESS              The device specified by ControllerHandle and\r
+                                   RemainingDevicePath is supported by the driver specified by This.\r
+  @retval EFI_ALREADY_STARTED      The device specified by ControllerHandle and\r
+                                   RemainingDevicePath is already being managed by the driver\r
+                                   specified by This.\r
+  @retval EFI_ACCESS_DENIED        The device specified by ControllerHandle and\r
+                                   RemainingDevicePath is already being managed by a different\r
+                                   driver or an application that requires exclusive access.\r
+                                   Currently not implemented.\r
+  @retval EFI_UNSUPPORTED          The device specified by ControllerHandle and\r
+                                   RemainingDevicePath is not supported by the driver specified by This.\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+SdMmcPciHcDriverBindingSupported (\r
+  IN EFI_DRIVER_BINDING_PROTOCOL *This,\r
+  IN EFI_HANDLE                  Controller,\r
+  IN EFI_DEVICE_PATH_PROTOCOL    *RemainingDevicePath\r
+  )\r
+{\r
+  EFI_STATUS                Status;\r
+  EFI_DEVICE_PATH_PROTOCOL  *ParentDevicePath;\r
+  EFI_PCI_IO_PROTOCOL       *PciIo;\r
+  PCI_TYPE00                PciData;\r
+\r
+  PciIo            = NULL;\r
+  ParentDevicePath = NULL;\r
+\r
+  //\r
+  // SdPciHcDxe is a device driver, and should ingore the\r
+  // "RemainingDevicePath" according to EFI spec.\r
+  //\r
+  Status = gBS->OpenProtocol (\r
+                  Controller,\r
+                  &gEfiDevicePathProtocolGuid,\r
+                  (VOID *) &ParentDevicePath,\r
+                  This->DriverBindingHandle,\r
+                  Controller,\r
+                  EFI_OPEN_PROTOCOL_BY_DRIVER\r
+                  );\r
+  if (EFI_ERROR (Status)) {\r
+    //\r
+    // EFI_ALREADY_STARTED is also an error.\r
+    //\r
+    return Status;\r
+  }\r
+  //\r
+  // Close the protocol because we don't use it here.\r
+  //\r
+  gBS->CloseProtocol (\r
+        Controller,\r
+        &gEfiDevicePathProtocolGuid,\r
+        This->DriverBindingHandle,\r
+        Controller\r
+        );\r
+\r
+  //\r
+  // Now test the EfiPciIoProtocol.\r
+  //\r
+  Status = gBS->OpenProtocol (\r
+                  Controller,\r
+                  &gEfiPciIoProtocolGuid,\r
+                  (VOID **) &PciIo,\r
+                  This->DriverBindingHandle,\r
+                  Controller,\r
+                  EFI_OPEN_PROTOCOL_BY_DRIVER\r
+                  );\r
+  if (EFI_ERROR (Status)) {\r
+    return Status;\r
+  }\r
+\r
+  //\r
+  // Now further check the PCI header: Base class (offset 0x08) and\r
+  // Sub Class (offset 0x05). This controller should be an SD/MMC PCI\r
+  // Host Controller.\r
+  //\r
+  Status = PciIo->Pci.Read (\r
+                        PciIo,\r
+                        EfiPciIoWidthUint8,\r
+                        0,\r
+                        sizeof (PciData),\r
+                        &PciData\r
+                        );\r
+  if (EFI_ERROR (Status)) {\r
+    gBS->CloseProtocol (\r
+          Controller,\r
+          &gEfiPciIoProtocolGuid,\r
+          This->DriverBindingHandle,\r
+          Controller\r
+          );\r
+    return EFI_UNSUPPORTED;\r
+  }\r
+  //\r
+  // Since we already got the PciData, we can close protocol to avoid to carry it\r
+  // on for multiple exit points.\r
+  //\r
+  gBS->CloseProtocol (\r
+        Controller,\r
+        &gEfiPciIoProtocolGuid,\r
+        This->DriverBindingHandle,\r
+        Controller\r
+        );\r
+\r
+  //\r
+  // Examine SD PCI Host Controller PCI Configuration table fields.\r
+  //\r
+  if ((PciData.Hdr.ClassCode[2] == PCI_CLASS_SYSTEM_PERIPHERAL) &&\r
+      (PciData.Hdr.ClassCode[1] == PCI_SUBCLASS_SD_HOST_CONTROLLER) &&\r
+      ((PciData.Hdr.ClassCode[0] == 0x00) || (PciData.Hdr.ClassCode[0] == 0x01))) {\r
+    return EFI_SUCCESS;\r
+  }\r
+\r
+  return EFI_UNSUPPORTED;\r
+}\r
+\r
+/**\r
+  Starts a device controller or a bus controller.\r
+\r
+  The Start() function is designed to be invoked from the EFI boot service ConnectController().\r
+  As a result, much of the error checking on the parameters to Start() has been moved into this\r
+  common boot service. It is legal to call Start() from other locations,\r
+  but the following calling restrictions must be followed or the system behavior will not be deterministic.\r
+  1. ControllerHandle must be a valid EFI_HANDLE.\r
+  2. If RemainingDevicePath is not NULL, then it must be a pointer to a naturally aligned\r
+     EFI_DEVICE_PATH_PROTOCOL.\r
+  3. Prior to calling Start(), the Supported() function for the driver specified by This must\r
+     have been called with the same calling parameters, and Supported() must have returned EFI_SUCCESS.\r
+\r
+  @param[in]  This                 A pointer to the EFI_DRIVER_BINDING_PROTOCOL instance.\r
+  @param[in]  ControllerHandle     The handle of the controller to start. This handle\r
+                                   must support a protocol interface that supplies\r
+                                   an I/O abstraction to the driver.\r
+  @param[in]  RemainingDevicePath  A pointer to the remaining portion of a device path.  This\r
+                                   parameter is ignored by device drivers, and is optional for bus\r
+                                   drivers. For a bus driver, if this parameter is NULL, then handles\r
+                                   for all the children of Controller are created by this driver.\r
+                                   If this parameter is not NULL and the first Device Path Node is\r
+                                   not the End of Device Path Node, then only the handle for the\r
+                                   child device specified by the first Device Path Node of\r
+                                   RemainingDevicePath is created by this driver.\r
+                                   If the first Device Path Node of RemainingDevicePath is\r
+                                   the End of Device Path Node, no child handle is created by this\r
+                                   driver.\r
+\r
+  @retval EFI_SUCCESS              The device was started.\r
+  @retval EFI_DEVICE_ERROR         The device could not be started due to a device error.Currently not implemented.\r
+  @retval EFI_OUT_OF_RESOURCES     The request could not be completed due to a lack of resources.\r
+  @retval Others                   The driver failded to start the device.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+SdMmcPciHcDriverBindingStart (\r
+  IN EFI_DRIVER_BINDING_PROTOCOL     *This,\r
+  IN EFI_HANDLE                      Controller,\r
+  IN EFI_DEVICE_PATH_PROTOCOL        *RemainingDevicePath\r
+  )\r
+{\r
+  EFI_STATUS                      Status;\r
+  SD_MMC_HC_PRIVATE_DATA          *Private;\r
+  EFI_PCI_IO_PROTOCOL             *PciIo;\r
+  UINT64                          Supports;\r
+  UINT64                          PciAttributes;\r
+  UINT8                           SlotNum;\r
+  UINT8                           FirstBar;\r
+  UINT8                           Slot;\r
+  UINT8                           Index;\r
+  CARD_TYPE_DETECT_ROUTINE        *Routine;\r
+  UINT32                          RoutineNum;\r
+  BOOLEAN                         MediaPresent;\r
+\r
+  DEBUG ((EFI_D_INFO, "SdMmcPciHcDriverBindingStart: Start\n"));\r
+\r
+  //\r
+  // Open PCI I/O Protocol and save pointer to open protocol\r
+  // in private data area.\r
+  //\r
+  PciIo  = NULL;\r
+  Status = gBS->OpenProtocol (\r
+                  Controller,\r
+                  &gEfiPciIoProtocolGuid,\r
+                  (VOID **) &PciIo,\r
+                  This->DriverBindingHandle,\r
+                  Controller,\r
+                  EFI_OPEN_PROTOCOL_BY_DRIVER\r
+                  );\r
+  if (EFI_ERROR (Status)) {\r
+    return Status;\r
+  }\r
+\r
+  //\r
+  // Enable the SD Host Controller MMIO space\r
+  //\r
+  Private = NULL;\r
+  Status  = PciIo->Attributes (\r
+                     PciIo,\r
+                     EfiPciIoAttributeOperationGet,\r
+                     0,\r
+                     &PciAttributes\r
+                     );\r
+\r
+  if (EFI_ERROR (Status)) {\r
+    goto Done;\r
+  }\r
+\r
+  Status = PciIo->Attributes (\r
+                    PciIo,\r
+                    EfiPciIoAttributeOperationSupported,\r
+                    0,\r
+                    &Supports\r
+                    );\r
+\r
+  if (!EFI_ERROR (Status)) {\r
+    Supports &= (UINT64)EFI_PCI_DEVICE_ENABLE;\r
+    Status    = PciIo->Attributes (\r
+                         PciIo,\r
+                         EfiPciIoAttributeOperationEnable,\r
+                         Supports,\r
+                         NULL\r
+                         );\r
+  } else {\r
+    goto Done;\r
+  }\r
+\r
+  Private = AllocateCopyPool (sizeof (SD_MMC_HC_PRIVATE_DATA), &gSdMmcPciHcTemplate);\r
+  if (Private == NULL) {\r
+    Status = EFI_OUT_OF_RESOURCES;\r
+    goto Done;\r
+  }\r
+\r
+  Private->ControllerHandle = Controller;\r
+  Private->PciIo            = PciIo;\r
+  Private->PciAttributes    = PciAttributes;\r
+  InitializeListHead (&Private->Queue);\r
+\r
+  //\r
+  // Get SD/MMC Pci Host Controller Slot info\r
+  //\r
+  Status = SdMmcHcGetSlotInfo (PciIo, &FirstBar, &SlotNum);\r
+  if (EFI_ERROR (Status)) {\r
+    goto Done;\r
+  }\r
+\r
+  for (Slot = FirstBar; Slot < (FirstBar + SlotNum); Slot++) {\r
+    Private->Slot[Slot].Enable = TRUE;\r
+\r
+    Status = SdMmcHcGetCapability (PciIo, Slot, &Private->Capability[Slot]);\r
+    if (EFI_ERROR (Status)) {\r
+      continue;\r
+    }\r
+    DumpCapabilityReg (Slot, &Private->Capability[Slot]);\r
+\r
+    Status = SdMmcHcGetMaxCurrent (PciIo, Slot, &Private->MaxCurrent[Slot]);\r
+    if (EFI_ERROR (Status)) {\r
+      continue;\r
+    }\r
+\r
+    Private->Slot[Slot].SlotType = Private->Capability[Slot].SlotType;\r
+    if ((Private->Slot[Slot].SlotType != RemovableSlot) && (Private->Slot[Slot].SlotType != EmbeddedSlot)) {\r
+      DEBUG ((EFI_D_INFO, "SdMmcPciHcDxe doesn't support the slot type [%d]!!!\n", Private->Slot[Slot].SlotType));\r
+      continue;\r
+    }\r
+\r
+    //\r
+    // Reset the specified slot of the SD/MMC Pci Host Controller\r
+    //\r
+    Status = SdMmcHcReset (PciIo, Slot);\r
+    if (EFI_ERROR (Status)) {\r
+      continue;\r
+    }\r
+    //\r
+    // Check whether there is a SD/MMC card attached\r
+    //\r
+    Status = SdMmcHcCardDetect (PciIo, Slot, &MediaPresent);\r
+    if ((Status == EFI_MEDIA_CHANGED) && (MediaPresent == FALSE)) {\r
+      DEBUG ((EFI_D_ERROR, "SdMmcHcCardDetect: No device attached in Slot[%d]!!!\n", Slot));\r
+      continue;\r
+    }\r
+\r
+    Status = SdMmcHcInitHost (PciIo, Slot, Private->Capability[Slot]);\r
+    if (EFI_ERROR (Status)) {\r
+      continue;\r
+    }\r
+\r
+    Private->Slot[Slot].MediaPresent = TRUE;\r
+    RoutineNum = sizeof (mCardTypeDetectRoutineTable) / sizeof (CARD_TYPE_DETECT_ROUTINE);\r
+    for (Index = 0; Index < RoutineNum; Index++) {\r
+      Routine = &mCardTypeDetectRoutineTable[Index];\r
+      if (*Routine != NULL) {\r
+        Status = (*Routine) (Private, Slot);\r
+        if (!EFI_ERROR (Status)) {\r
+          break;\r
+        }\r
+      }\r
+    }\r
+  }\r
+\r
+  //\r
+  // Start the asynchronous I/O monitor\r
+  //\r
+  Status = gBS->CreateEvent (\r
+                  EVT_TIMER | EVT_NOTIFY_SIGNAL,\r
+                  TPL_CALLBACK,\r
+                  ProcessAsyncTaskList,\r
+                  Private,\r
+                  &Private->TimerEvent\r
+                  );\r
+  if (EFI_ERROR (Status)) {\r
+    goto Done;\r
+  }\r
+\r
+  Status = gBS->SetTimer (Private->TimerEvent, TimerPeriodic, SD_MMC_HC_ASYNC_TIMER);\r
+  if (EFI_ERROR (Status)) {\r
+    goto Done;\r
+  }\r
+\r
+  //\r
+  // Start the Sd removable device connection enumeration\r
+  //\r
+  Status = gBS->CreateEvent (\r
+                  EVT_TIMER | EVT_NOTIFY_SIGNAL,\r
+                  TPL_CALLBACK,\r
+                  SdMmcPciHcEnumerateDevice,\r
+                  Private,\r
+                  &Private->ConnectEvent\r
+                  );\r
+  if (EFI_ERROR (Status)) {\r
+    goto Done;\r
+  }\r
+\r
+  Status = gBS->SetTimer (Private->ConnectEvent, TimerPeriodic, SD_MMC_HC_ENUM_TIMER);\r
+  if (EFI_ERROR (Status)) {\r
+    goto Done;\r
+  }\r
+\r
+  Status = gBS->InstallMultipleProtocolInterfaces (\r
+                  &Controller,\r
+                  &gEfiSdMmcPassThruProtocolGuid,\r
+                  &(Private->PassThru),\r
+                  NULL\r
+                  );\r
+\r
+  DEBUG ((EFI_D_INFO, "SdMmcPciHcDriverBindingStart: %r End on %x\n", Status, Controller));\r
+\r
+Done:\r
+  if (EFI_ERROR (Status)) {\r
+    if ((Private != NULL) && (Private->PciAttributes != 0)) {\r
+      //\r
+      // Restore original PCI attributes\r
+      //\r
+      PciIo->Attributes (\r
+               PciIo,\r
+               EfiPciIoAttributeOperationSet,\r
+               Private->PciAttributes,\r
+               NULL\r
+               );\r
+    }\r
+    gBS->CloseProtocol (\r
+          Controller,\r
+          &gEfiPciIoProtocolGuid,\r
+          This->DriverBindingHandle,\r
+          Controller\r
+          );\r
+\r
+    if ((Private != NULL) && (Private->TimerEvent != NULL)) {\r
+      gBS->CloseEvent (Private->TimerEvent);\r
+    }\r
+\r
+    if ((Private != NULL) && (Private->ConnectEvent != NULL)) {\r
+      gBS->CloseEvent (Private->ConnectEvent);\r
+    }\r
+\r
+    if (Private != NULL) {\r
+      FreePool (Private);\r
+    }\r
+  }\r
+\r
+  return Status;\r
+}\r
+\r
+/**\r
+  Stops a device controller or a bus controller.\r
+\r
+  The Stop() function is designed to be invoked from the EFI boot service DisconnectController().\r
+  As a result, much of the error checking on the parameters to Stop() has been moved\r
+  into this common boot service. It is legal to call Stop() from other locations,\r
+  but the following calling restrictions must be followed or the system behavior will not be deterministic.\r
+  1. ControllerHandle must be a valid EFI_HANDLE that was used on a previous call to this\r
+     same driver's Start() function.\r
+  2. The first NumberOfChildren handles of ChildHandleBuffer must all be a valid\r
+     EFI_HANDLE. In addition, all of these handles must have been created in this driver's\r
+     Start() function, and the Start() function must have called OpenProtocol() on\r
+     ControllerHandle with an Attribute of EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER.\r
+\r
+  @param[in]  This              A pointer to the EFI_DRIVER_BINDING_PROTOCOL instance.\r
+  @param[in]  ControllerHandle  A handle to the device being stopped. The handle must\r
+                                support a bus specific I/O protocol for the driver\r
+                                to use to stop the device.\r
+  @param[in]  NumberOfChildren  The number of child device handles in ChildHandleBuffer.\r
+  @param[in]  ChildHandleBuffer An array of child handles to be freed. May be NULL\r
+                                if NumberOfChildren is 0.\r
+\r
+  @retval EFI_SUCCESS           The device was stopped.\r
+  @retval EFI_DEVICE_ERROR      The device could not be stopped due to a device error.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+SdMmcPciHcDriverBindingStop (\r
+  IN  EFI_DRIVER_BINDING_PROTOCOL     *This,\r
+  IN  EFI_HANDLE                      Controller,\r
+  IN  UINTN                           NumberOfChildren,\r
+  IN  EFI_HANDLE                      *ChildHandleBuffer\r
+  )\r
+{\r
+  EFI_STATUS                          Status;\r
+  EFI_SD_MMC_PASS_THRU_PROTOCOL       *PassThru;\r
+  SD_MMC_HC_PRIVATE_DATA              *Private;\r
+  EFI_PCI_IO_PROTOCOL                 *PciIo;\r
+  LIST_ENTRY                          *Link;\r
+  LIST_ENTRY                          *NextLink;\r
+  SD_MMC_HC_TRB                       *Trb;\r
+\r
+  DEBUG ((EFI_D_INFO, "SdMmcPciHcDriverBindingStop: Start\n"));\r
+\r
+  Status = gBS->OpenProtocol (\r
+                  Controller,\r
+                  &gEfiSdMmcPassThruProtocolGuid,\r
+                  (VOID**) &PassThru,\r
+                  This->DriverBindingHandle,\r
+                  Controller,\r
+                  EFI_OPEN_PROTOCOL_GET_PROTOCOL\r
+                  );\r
+  if (EFI_ERROR (Status)) {\r
+    return Status;\r
+  }\r
+\r
+  Private = SD_MMC_HC_PRIVATE_FROM_THIS (PassThru);\r
+  //\r
+  // Close Non-Blocking timer and free Task list.\r
+  //\r
+  if (Private->TimerEvent != NULL) {\r
+    gBS->CloseEvent (Private->TimerEvent);\r
+    Private->TimerEvent = NULL;\r
+  }\r
+  if (Private->ConnectEvent != NULL) {\r
+    gBS->CloseEvent (Private->ConnectEvent);\r
+    Private->ConnectEvent = NULL;\r
+  }\r
+  //\r
+  // As the timer is closed, there is no needs to use TPL lock to\r
+  // protect the critical region "queue".\r
+  //\r
+  for (Link = GetFirstNode (&Private->Queue);\r
+       !IsNull (&Private->Queue, Link);\r
+       Link = NextLink) {\r
+    NextLink = GetNextNode (&Private->Queue, Link);\r
+    RemoveEntryList (Link);\r
+    Trb = SD_MMC_HC_TRB_FROM_THIS (Link);\r
+    Trb->Packet->TransactionStatus = EFI_ABORTED;\r
+    gBS->SignalEvent (Trb->Event);\r
+    SdMmcFreeTrb (Trb);\r
+  }\r
+\r
+  //\r
+  // Uninstall Block I/O protocol from the device handle\r
+  //\r
+  Status = gBS->UninstallProtocolInterface (\r
+                  Controller,\r
+                  &gEfiSdMmcPassThruProtocolGuid,\r
+                  &(Private->PassThru)\r
+                  );\r
+\r
+  if (EFI_ERROR (Status)) {\r
+    return Status;\r
+  }\r
+\r
+  gBS->CloseProtocol (\r
+         Controller,\r
+         &gEfiPciIoProtocolGuid,\r
+         This->DriverBindingHandle,\r
+         Controller\r
+         );\r
+  //\r
+  // Restore original PCI attributes\r
+  //\r
+  PciIo  = Private->PciIo;\r
+  Status = PciIo->Attributes (\r
+                    PciIo,\r
+                    EfiPciIoAttributeOperationSet,\r
+                    Private->PciAttributes,\r
+                    NULL\r
+                    );\r
+  ASSERT_EFI_ERROR (Status);\r
+\r
+  FreePool (Private);\r
+\r
+  DEBUG ((EFI_D_INFO, "SdMmcPciHcDriverBindingStop: End with %r\n", Status));\r
+\r
+  return Status;\r
+}\r
+\r
+/**\r
+  Sends SD command to an SD card that is attached to the SD controller.\r
+\r
+  The PassThru() function sends the SD command specified by Packet to the SD card\r
+  specified by Slot.\r
+\r
+  If Packet is successfully sent to the SD card, then EFI_SUCCESS is returned.\r
+\r
+  If a device error occurs while sending the Packet, then EFI_DEVICE_ERROR is returned.\r
+\r
+  If Slot is not in a valid range for the SD controller, then EFI_INVALID_PARAMETER\r
+  is returned.\r
+\r
+  If Packet defines a data command but both InDataBuffer and OutDataBuffer are NULL,\r
+  EFI_INVALID_PARAMETER is returned.\r
+\r
+  @param[in]     This           A pointer to the EFI_SD_MMC_PASS_THRU_PROTOCOL instance.\r
+  @param[in]     Slot           The slot number of the SD card to send the command to.\r
+  @param[in,out] Packet         A pointer to the SD command data structure.\r
+  @param[in]     Event          If Event is NULL, blocking I/O is performed. If Event is\r
+                                not NULL, then nonblocking I/O is performed, and Event\r
+                                will be signaled when the Packet completes.\r
+\r
+  @retval EFI_SUCCESS           The SD Command Packet was sent by the host.\r
+  @retval EFI_DEVICE_ERROR      A device error occurred while attempting to send the SD\r
+                                command Packet.\r
+  @retval EFI_INVALID_PARAMETER Packet, Slot, or the contents of the Packet is invalid.\r
+  @retval EFI_INVALID_PARAMETER Packet defines a data command but both InDataBuffer and\r
+                                OutDataBuffer are NULL.\r
+  @retval EFI_NO_MEDIA          SD Device not present in the Slot.\r
+  @retval EFI_UNSUPPORTED       The command described by the SD Command Packet is not\r
+                                supported by the host controller.\r
+  @retval EFI_BAD_BUFFER_SIZE   The InTransferLength or OutTransferLength exceeds the\r
+                                limit supported by SD card ( i.e. if the number of bytes\r
+                                exceed the Last LBA).\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+SdMmcPassThruPassThru (\r
+  IN     EFI_SD_MMC_PASS_THRU_PROTOCOL         *This,\r
+  IN     UINT8                                 Slot,\r
+  IN OUT EFI_SD_MMC_PASS_THRU_COMMAND_PACKET   *Packet,\r
+  IN     EFI_EVENT                             Event    OPTIONAL\r
+  )\r
+{\r
+  EFI_STATUS                      Status;\r
+  SD_MMC_HC_PRIVATE_DATA          *Private;\r
+  SD_MMC_HC_TRB                   *Trb;\r
+  EFI_TPL                         OldTpl;\r
+\r
+  if ((This == NULL) || (Packet == NULL)) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  if ((Packet->SdMmcCmdBlk == NULL) || (Packet->SdMmcStatusBlk == NULL)) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  if ((Packet->OutDataBuffer == NULL) && (Packet->OutTransferLength != 0)) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  if ((Packet->InDataBuffer == NULL) && (Packet->InTransferLength != 0)) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  Private = SD_MMC_HC_PRIVATE_FROM_THIS (This);\r
+\r
+  if (!Private->Slot[Slot].Enable) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  if (!Private->Slot[Slot].MediaPresent) {\r
+    return EFI_NO_MEDIA;\r
+  }\r
+\r
+  Trb = SdMmcCreateTrb (Private, Slot, Packet, Event);\r
+  if (Trb == NULL) {\r
+    return EFI_OUT_OF_RESOURCES;\r
+  }\r
+  //\r
+  // Immediately return for async I/O.\r
+  //\r
+  if (Event != NULL) {\r
+    return EFI_SUCCESS;\r
+  }\r
+\r
+  //\r
+  // Wait async I/O list is empty before execute sync I/O operation.\r
+  //\r
+  while (TRUE) {\r
+    OldTpl = gBS->RaiseTPL (TPL_CALLBACK);\r
+    if (IsListEmpty (&Private->Queue)) {\r
+      gBS->RestoreTPL (OldTpl);\r
+      break;\r
+    }\r
+    gBS->RestoreTPL (OldTpl);\r
+  }\r
+\r
+  Status = SdMmcWaitTrbEnv (Private, Trb);\r
+  if (EFI_ERROR (Status)) {\r
+    goto Done;\r
+  }\r
+\r
+  Status = SdMmcExecTrb (Private, Trb);\r
+  if (EFI_ERROR (Status)) {\r
+    goto Done;\r
+  }\r
+\r
+  Status = SdMmcWaitTrbResult (Private, Trb);\r
+  if (EFI_ERROR (Status)) {\r
+    goto Done;\r
+  }\r
+\r
+Done:\r
+  if ((Trb != NULL) && (Trb->AdmaDesc != NULL)) {\r
+    FreePages (Trb->AdmaDesc, Trb->AdmaPages);\r
+  }\r
+\r
+  if (Trb != NULL) {\r
+    FreePool (Trb);\r
+  }\r
+\r
+  return Status;\r
+}\r
+\r
+/**\r
+  Used to retrieve next slot numbers supported by the SD controller. The function\r
+  returns information about all available slots (populated or not-populated).\r
+\r
+  The GetNextSlot() function retrieves the next slot number on an SD controller.\r
+  If on input Slot is 0xFF, then the slot number of the first slot on the SD controller\r
+  is returned.\r
+\r
+  If Slot is a slot number that was returned on a previous call to GetNextSlot(), then\r
+  the slot number of the next slot on the SD controller is returned.\r
+\r
+  If Slot is not 0xFF and Slot was not returned on a previous call to GetNextSlot(),\r
+  EFI_INVALID_PARAMETER is returned.\r
+\r
+  If Slot is the slot number of the last slot on the SD controller, then EFI_NOT_FOUND\r
+  is returned.\r
+\r
+  @param[in]     This           A pointer to the EFI_SD_MMMC_PASS_THRU_PROTOCOL instance.\r
+  @param[in,out] Slot           On input, a pointer to a slot number on the SD controller.\r
+                                On output, a pointer to the next slot number on the SD controller.\r
+                                An input value of 0xFF retrieves the first slot number on the SD\r
+                                controller.\r
+\r
+  @retval EFI_SUCCESS           The next slot number on the SD controller was returned in Slot.\r
+  @retval EFI_NOT_FOUND         There are no more slots on this SD controller.\r
+  @retval EFI_INVALID_PARAMETER Slot is not 0xFF and Slot was not returned on a previous call\r
+                                to GetNextSlot().\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+SdMmcPassThruGetNextSlot (\r
+  IN     EFI_SD_MMC_PASS_THRU_PROTOCOL        *This,\r
+  IN OUT UINT8                                *Slot\r
+  )\r
+{\r
+  SD_MMC_HC_PRIVATE_DATA          *Private;\r
+  UINT8                           Index;\r
+\r
+  if ((This == NULL) || (Slot == NULL)) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  Private = SD_MMC_HC_PRIVATE_FROM_THIS (This);\r
+\r
+  if (*Slot == 0xFF) {\r
+    for (Index = 0; Index < SD_MMC_HC_MAX_SLOT; Index++) {\r
+      if (Private->Slot[Index].Enable) {\r
+        *Slot = Index;\r
+        Private->PreviousSlot = Index;\r
+        return EFI_SUCCESS;\r
+      }\r
+    }\r
+    return EFI_NOT_FOUND;\r
+  } else if (*Slot == Private->PreviousSlot) {\r
+    for (Index = *Slot + 1; Index < SD_MMC_HC_MAX_SLOT; Index++) {\r
+      if (Private->Slot[Index].Enable) {\r
+        *Slot = Index;\r
+        Private->PreviousSlot = Index;\r
+        return EFI_SUCCESS;\r
+      }\r
+    }\r
+    return EFI_NOT_FOUND;\r
+  } else {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+}\r
+\r
+/**\r
+  Used to allocate and build a device path node for an SD card on the SD controller.\r
+\r
+  The BuildDevicePath() function allocates and builds a single device node for the SD\r
+  card specified by Slot.\r
+\r
+  If the SD card specified by Slot is not present on the SD controller, then EFI_NOT_FOUND\r
+  is returned.\r
+\r
+  If DevicePath is NULL, then EFI_INVALID_PARAMETER is returned.\r
+\r
+  If there are not enough resources to allocate the device path node, then EFI_OUT_OF_RESOURCES\r
+  is returned.\r
+\r
+  Otherwise, DevicePath is allocated with the boot service AllocatePool(), the contents of\r
+  DevicePath are initialized to describe the SD card specified by Slot, and EFI_SUCCESS is\r
+  returned.\r
+\r
+  @param[in]     This           A pointer to the EFI_SD_MMMC_PASS_THRU_PROTOCOL instance.\r
+  @param[in]     Slot           Specifies the slot number of the SD card for which a device\r
+                                path node is to be allocated and built.\r
+  @param[in,out] DevicePath     A pointer to a single device path node that describes the SD\r
+                                card specified by Slot. This function is responsible for\r
+                                allocating the buffer DevicePath with the boot service\r
+                                AllocatePool(). It is the caller's responsibility to free\r
+                                DevicePath when the caller is finished with DevicePath.\r
+\r
+  @retval EFI_SUCCESS           The device path node that describes the SD card specified by\r
+                                Slot was allocated and returned in DevicePath.\r
+  @retval EFI_NOT_FOUND         The SD card specified by Slot does not exist on the SD controller.\r
+  @retval EFI_INVALID_PARAMETER DevicePath is NULL.\r
+  @retval EFI_OUT_OF_RESOURCES  There are not enough resources to allocate DevicePath.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+SdMmcPassThruBuildDevicePath (\r
+  IN     EFI_SD_MMC_PASS_THRU_PROTOCOL       *This,\r
+  IN     UINT8                               Slot,\r
+  IN OUT EFI_DEVICE_PATH_PROTOCOL            **DevicePath\r
+  )\r
+{\r
+  SD_MMC_HC_PRIVATE_DATA          *Private;\r
+  SD_DEVICE_PATH                  *SdNode;\r
+  EMMC_DEVICE_PATH                *EmmcNode;\r
+\r
+  if ((This == NULL) || (DevicePath == NULL) || (Slot >= SD_MMC_HC_MAX_SLOT)) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  Private = SD_MMC_HC_PRIVATE_FROM_THIS (This);\r
+\r
+  if ((!Private->Slot[Slot].Enable) || (!Private->Slot[Slot].MediaPresent)) {\r
+    return EFI_NOT_FOUND;\r
+  }\r
+\r
+  if (Private->Slot[Slot].CardType == SdCardType) {\r
+    SdNode = AllocateCopyPool (sizeof (SD_DEVICE_PATH), &mSdDpTemplate);\r
+    if (SdNode == NULL) {\r
+      return EFI_OUT_OF_RESOURCES;\r
+    }\r
+    SdNode->SlotNumber = Slot;\r
+\r
+    *DevicePath = (EFI_DEVICE_PATH_PROTOCOL *) SdNode;\r
+  } else if (Private->Slot[Slot].CardType == EmmcCardType) {\r
+    EmmcNode = AllocateCopyPool (sizeof (EMMC_DEVICE_PATH), &mEmmcDpTemplate);\r
+    if (EmmcNode == NULL) {\r
+      return EFI_OUT_OF_RESOURCES;\r
+    }\r
+    EmmcNode->SlotNumber = Slot;\r
+\r
+    *DevicePath = (EFI_DEVICE_PATH_PROTOCOL *) EmmcNode;\r
+  } else {\r
+    //\r
+    // Currently we only support SD and EMMC two device nodes.\r
+    //\r
+    return EFI_NOT_FOUND;\r
+  }\r
+\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+  This function retrieves an SD card slot number based on the input device path.\r
+\r
+  The GetSlotNumber() function retrieves slot number for the SD card specified by\r
+  the DevicePath node. If DevicePath is NULL, EFI_INVALID_PARAMETER is returned.\r
+\r
+  If DevicePath is not a device path node type that the SD Pass Thru driver supports,\r
+  EFI_UNSUPPORTED is returned.\r
+\r
+  @param[in]  This              A pointer to the EFI_SD_MMC_PASS_THRU_PROTOCOL instance.\r
+  @param[in]  DevicePath        A pointer to the device path node that describes a SD\r
+                                card on the SD controller.\r
+  @param[out] Slot              On return, points to the slot number of an SD card on\r
+                                the SD controller.\r
+\r
+  @retval EFI_SUCCESS           SD card slot number is returned in Slot.\r
+  @retval EFI_INVALID_PARAMETER Slot or DevicePath is NULL.\r
+  @retval EFI_UNSUPPORTED       DevicePath is not a device path node type that the SD\r
+                                Pass Thru driver supports.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+SdMmcPassThruGetSlotNumber (\r
+  IN  EFI_SD_MMC_PASS_THRU_PROTOCOL          *This,\r
+  IN  EFI_DEVICE_PATH_PROTOCOL               *DevicePath,\r
+  OUT UINT8                                  *Slot\r
+  )\r
+{\r
+  SD_MMC_HC_PRIVATE_DATA          *Private;\r
+  SD_DEVICE_PATH                  *SdNode;\r
+  EMMC_DEVICE_PATH                *EmmcNode;\r
+  UINT8                           SlotNumber;\r
+\r
+  if ((This == NULL) || (DevicePath == NULL) || (Slot == NULL)) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  Private = SD_MMC_HC_PRIVATE_FROM_THIS (This);\r
+\r
+  //\r
+  // Check whether the DevicePath belongs to SD_DEVICE_PATH or EMMC_DEVICE_PATH\r
+  //\r
+  if ((DevicePath->Type != MESSAGING_DEVICE_PATH) ||\r
+      ((DevicePath->SubType != MSG_SD_DP) &&\r
+       (DevicePath->SubType != MSG_EMMC_DP)) ||\r
+      (DevicePathNodeLength(DevicePath) != sizeof(SD_DEVICE_PATH)) ||\r
+      (DevicePathNodeLength(DevicePath) != sizeof(EMMC_DEVICE_PATH))) {\r
+    return EFI_UNSUPPORTED;\r
+  }\r
+\r
+  if (DevicePath->SubType == MSG_SD_DP) {\r
+    SdNode = (SD_DEVICE_PATH *) DevicePath;\r
+    SlotNumber = SdNode->SlotNumber;\r
+  } else {\r
+    EmmcNode = (EMMC_DEVICE_PATH *) DevicePath;\r
+    SlotNumber = EmmcNode->SlotNumber;\r
+  }\r
+\r
+  if (SlotNumber >= SD_MMC_HC_MAX_SLOT) {\r
+    return EFI_NOT_FOUND;\r
+  }\r
+\r
+  if (Private->Slot[SlotNumber].Enable) {\r
+    *Slot = SlotNumber;\r
+    return EFI_SUCCESS;\r
+  } else {\r
+    return EFI_NOT_FOUND;\r
+  }\r
+}\r
+\r
+/**\r
+  Resets an SD card that is connected to the SD controller.\r
+\r
+  The ResetDevice() function resets the SD card specified by Slot.\r
+\r
+  If this SD controller does not support a device reset operation, EFI_UNSUPPORTED is\r
+  returned.\r
+\r
+  If Slot is not in a valid slot number for this SD controller, EFI_INVALID_PARAMETER\r
+  is returned.\r
+\r
+  If the device reset operation is completed, EFI_SUCCESS is returned.\r
+\r
+  @param[in]  This              A pointer to the EFI_SD_MMC_PASS_THRU_PROTOCOL instance.\r
+  @param[in]  Slot              Specifies the slot number of the SD card to be reset.\r
+\r
+  @retval EFI_SUCCESS           The SD card specified by Slot was reset.\r
+  @retval EFI_UNSUPPORTED       The SD controller does not support a device reset operation.\r
+  @retval EFI_INVALID_PARAMETER Slot number is invalid.\r
+  @retval EFI_NO_MEDIA          SD Device not present in the Slot.\r
+  @retval EFI_DEVICE_ERROR      The reset command failed due to a device error\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+SdMmcPassThruResetDevice (\r
+  IN EFI_SD_MMC_PASS_THRU_PROTOCOL           *This,\r
+  IN UINT8                                   Slot\r
+  )\r
+{\r
+  SD_MMC_HC_PRIVATE_DATA          *Private;\r
+  LIST_ENTRY                      *Link;\r
+  LIST_ENTRY                      *NextLink;\r
+  SD_MMC_HC_TRB                   *Trb;\r
+  EFI_TPL                         OldTpl;\r
+\r
+  if (This == NULL) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  Private = SD_MMC_HC_PRIVATE_FROM_THIS (This);\r
+\r
+  if (!Private->Slot[Slot].Enable) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+    if (!Private->Slot[Slot].MediaPresent) {\r
+      return EFI_NO_MEDIA;\r
+    }\r
+  //\r
+  // Free all async I/O requests in the queue\r
+  //\r
+  OldTpl = gBS->RaiseTPL (TPL_CALLBACK);\r
+\r
+  for (Link = GetFirstNode (&Private->Queue);\r
+       !IsNull (&Private->Queue, Link);\r
+       Link = NextLink) {\r
+    NextLink = GetNextNode (&Private->Queue, Link);\r
+    RemoveEntryList (Link);\r
+    Trb = SD_MMC_HC_TRB_FROM_THIS (Link);\r
+    Trb->Packet->TransactionStatus = EFI_ABORTED;\r
+    gBS->SignalEvent (Trb->Event);\r
+    SdMmcFreeTrb (Trb);\r
+  }\r
+\r
+  gBS->RestoreTPL (OldTpl);\r
+\r
+  return EFI_SUCCESS;\r
+}\r
+\r
diff --git a/MdeModulePkg/Bus/Pci/SdMmcPciHcDxe/SdMmcPciHcDxe.h b/MdeModulePkg/Bus/Pci/SdMmcPciHcDxe/SdMmcPciHcDxe.h
new file mode 100644 (file)
index 0000000..2cca823
--- /dev/null
@@ -0,0 +1,784 @@
+/** @file\r
+\r
+  Provides some data structure definitions used by the SD/MMC host controller driver.\r
+\r
+Copyright (c) 2015, Intel Corporation. All rights reserved.<BR>\r
+This program and the accompanying materials\r
+are licensed and made available under the terms and conditions of the BSD License\r
+which accompanies this distribution.  The full text of the license may be found at\r
+http://opensource.org/licenses/bsd-license.php\r
+\r
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+\r
+**/\r
+\r
+#ifndef _SD_MMC_PCI_HC_DXE_H_\r
+#define _SD_MMC_PCI_HC_DXE_H_\r
+\r
+#include <Uefi.h>\r
+\r
+#include <IndustryStandard/Pci.h>\r
+#include <IndustryStandard/Emmc.h>\r
+#include <IndustryStandard/Sd.h>\r
+\r
+#include <Library/UefiDriverEntryPoint.h>\r
+#include <Library/DebugLib.h>\r
+#include <Library/UefiBootServicesTableLib.h>\r
+#include <Library/BaseMemoryLib.h>\r
+#include <Library/MemoryAllocationLib.h>\r
+#include <Library/UefiLib.h>\r
+#include <Library/DevicePathLib.h>\r
+\r
+#include <Protocol/DevicePath.h>\r
+#include <Protocol/PciIo.h>\r
+#include <Protocol/DriverBinding.h>\r
+#include <Protocol/ComponentName.h>\r
+#include <Protocol/ComponentName2.h>\r
+#include <Protocol/SdMmcPassThru.h>\r
+\r
+#include "SdMmcPciHci.h"\r
+\r
+extern EFI_COMPONENT_NAME_PROTOCOL  gSdMmcPciHcComponentName;\r
+extern EFI_COMPONENT_NAME2_PROTOCOL gSdMmcPciHcComponentName2;\r
+extern EFI_DRIVER_BINDING_PROTOCOL  gSdMmcPciHcDriverBinding;\r
+\r
+#define SD_MMC_HC_PRIVATE_SIGNATURE  SIGNATURE_32 ('s', 'd', 't', 'f')\r
+\r
+#define SD_MMC_HC_PRIVATE_FROM_THIS(a) \\r
+    CR(a, SD_MMC_HC_PRIVATE_DATA, PassThru, SD_MMC_HC_PRIVATE_SIGNATURE)\r
+\r
+//\r
+// Generic time out value, 1 microsecond as unit.\r
+//\r
+#define SD_MMC_HC_GENERIC_TIMEOUT     1 * 1000 * 1000\r
+\r
+//\r
+// SD/MMC async transfer timer interval, set by experience.\r
+// The unit is 100us, takes 1ms as interval.\r
+//\r
+#define SD_MMC_HC_ASYNC_TIMER   EFI_TIMER_PERIOD_MILLISECONDS(1)\r
+//\r
+// SD/MMC removable device enumeration timer interval, set by experience.\r
+// The unit is 100us, takes 100ms as interval.\r
+//\r
+#define SD_MMC_HC_ENUM_TIMER    EFI_TIMER_PERIOD_MILLISECONDS(100)\r
+\r
+typedef enum {\r
+  UnknownCardType,\r
+  SdCardType,\r
+  SdioCardType,\r
+  MmcCardType,\r
+  EmmcCardType\r
+} SD_MMC_CARD_TYPE;\r
+\r
+typedef enum {\r
+  RemovableSlot,\r
+  EmbeddedSlot,\r
+  SharedBusSlot,\r
+  UnknownSlot\r
+} EFI_SD_MMC_SLOT_TYPE;\r
+\r
+typedef struct {\r
+  BOOLEAN                           Enable;\r
+  EFI_SD_MMC_SLOT_TYPE              SlotType;\r
+  BOOLEAN                           MediaPresent;\r
+  SD_MMC_CARD_TYPE                  CardType;\r
+} SD_MMC_HC_SLOT;\r
+\r
+typedef struct {\r
+  UINTN                               Signature;\r
+\r
+  EFI_HANDLE                          ControllerHandle;\r
+  EFI_PCI_IO_PROTOCOL                 *PciIo;\r
+\r
+  EFI_SD_MMC_PASS_THRU_PROTOCOL       PassThru;\r
+\r
+  UINT64                              PciAttributes;\r
+  //\r
+  // The field is used to record the previous slot in GetNextSlot().\r
+  //\r
+  UINT8                               PreviousSlot;\r
+  //\r
+  // For Non-blocking operation.\r
+  //\r
+  EFI_EVENT                           TimerEvent;\r
+  //\r
+  // For Sd removable device enumeration.\r
+  //\r
+  EFI_EVENT                           ConnectEvent;\r
+  LIST_ENTRY                          Queue;\r
+\r
+  SD_MMC_HC_SLOT                      Slot[SD_MMC_HC_MAX_SLOT];\r
+  SD_MMC_HC_SLOT_CAP                  Capability[SD_MMC_HC_MAX_SLOT];\r
+  UINT64                              MaxCurrent[SD_MMC_HC_MAX_SLOT];\r
+\r
+  UINT32                              ControllerVersion;\r
+} SD_MMC_HC_PRIVATE_DATA;\r
+\r
+#define SD_MMC_HC_TRB_SIG             SIGNATURE_32 ('T', 'R', 'B', 'T')\r
+\r
+//\r
+// TRB (Transfer Request Block) contains information for the cmd request.\r
+//\r
+typedef struct {\r
+  UINT32                              Signature;\r
+  LIST_ENTRY                          TrbList;\r
+\r
+  UINT8                               Slot;\r
+  UINT16                              BlockSize;\r
+\r
+  EFI_SD_MMC_PASS_THRU_COMMAND_PACKET *Packet;\r
+  VOID                                *Data;\r
+  UINT32                              DataLen;\r
+  BOOLEAN                             Read;\r
+  EFI_PHYSICAL_ADDRESS                DataPhy;\r
+  VOID                                *DataMap;\r
+  SD_MMC_HC_TRANSFER_MODE             Mode;\r
+\r
+  EFI_EVENT                           Event;\r
+  BOOLEAN                             Started;\r
+  UINT64                              Timeout;\r
+\r
+  SD_MMC_HC_ADMA_DESC_LINE            *AdmaDesc;\r
+  EFI_PHYSICAL_ADDRESS                AdmaDescPhy;\r
+  VOID                                *AdmaMap;\r
+  UINT32                              AdmaPages;\r
+\r
+  SD_MMC_HC_PRIVATE_DATA              *Private;\r
+} SD_MMC_HC_TRB;\r
+\r
+#define SD_MMC_HC_TRB_FROM_THIS(a) \\r
+    CR(a, SD_MMC_HC_TRB, TrbList, SD_MMC_HC_TRB_SIG)\r
+\r
+//\r
+// Task for Non-blocking mode.\r
+//\r
+typedef struct {\r
+  UINT32                              Signature;\r
+  LIST_ENTRY                          Link;\r
+\r
+  UINT8                               Slot;\r
+  EFI_SD_MMC_PASS_THRU_COMMAND_PACKET *Packet;\r
+  BOOLEAN                             IsStart;\r
+  EFI_EVENT                           Event;\r
+  UINT64                              RetryTimes;\r
+  BOOLEAN                             InfiniteWait;\r
+  VOID                                *Map;\r
+  VOID                                *MapAddress;\r
+} SD_MMC_HC_QUEUE;\r
+\r
+//\r
+// Prototypes\r
+//\r
+/**\r
+  Execute card identification procedure.\r
+\r
+  @param[in] Private        A pointer to the SD_MMC_HC_PRIVATE_DATA instance.\r
+  @param[in] Slot           The slot number of the SD card to send the command to.\r
+\r
+  @retval EFI_SUCCESS       The card is identified correctly.\r
+  @retval Others            The card can't be identified.\r
+\r
+**/\r
+typedef\r
+EFI_STATUS\r
+(*CARD_TYPE_DETECT_ROUTINE) (\r
+  IN SD_MMC_HC_PRIVATE_DATA             *Private,\r
+  IN UINT8                              Slot\r
+  );\r
+\r
+/**\r
+  Sends SD command to an SD card that is attached to the SD controller.\r
+\r
+  The PassThru() function sends the SD command specified by Packet to the SD card\r
+  specified by Slot.\r
+\r
+  If Packet is successfully sent to the SD card, then EFI_SUCCESS is returned.\r
+\r
+  If a device error occurs while sending the Packet, then EFI_DEVICE_ERROR is returned.\r
+\r
+  If Slot is not in a valid range for the SD controller, then EFI_INVALID_PARAMETER\r
+  is returned.\r
+\r
+  If Packet defines a data command but both InDataBuffer and OutDataBuffer are NULL,\r
+  EFI_INVALID_PARAMETER is returned.\r
+\r
+  @param[in]     This           A pointer to the EFI_SD_MMC_PASS_THRU_PROTOCOL instance.\r
+  @param[in]     Slot           The slot number of the SD card to send the command to.\r
+  @param[in,out] Packet         A pointer to the SD command data structure.\r
+  @param[in]     Event          If Event is NULL, blocking I/O is performed. If Event is\r
+                                not NULL, then nonblocking I/O is performed, and Event\r
+                                will be signaled when the Packet completes.\r
+\r
+  @retval EFI_SUCCESS           The SD Command Packet was sent by the host.\r
+  @retval EFI_DEVICE_ERROR      A device error occurred while attempting to send the SD\r
+                                command Packet.\r
+  @retval EFI_INVALID_PARAMETER Packet, Slot, or the contents of the Packet is invalid.\r
+  @retval EFI_INVALID_PARAMETER Packet defines a data command but both InDataBuffer and\r
+                                OutDataBuffer are NULL.\r
+  @retval EFI_NO_MEDIA          SD Device not present in the Slot.\r
+  @retval EFI_UNSUPPORTED       The command described by the SD Command Packet is not\r
+                                supported by the host controller.\r
+  @retval EFI_BAD_BUFFER_SIZE   The InTransferLength or OutTransferLength exceeds the\r
+                                limit supported by SD card ( i.e. if the number of bytes\r
+                                exceed the Last LBA).\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+SdMmcPassThruPassThru (\r
+  IN     EFI_SD_MMC_PASS_THRU_PROTOCOL         *This,\r
+  IN     UINT8                                 Slot,\r
+  IN OUT EFI_SD_MMC_PASS_THRU_COMMAND_PACKET   *Packet,\r
+  IN     EFI_EVENT                             Event    OPTIONAL\r
+  );\r
+\r
+/**\r
+  Used to retrieve next slot numbers supported by the SD controller. The function\r
+  returns information about all available slots (populated or not-populated).\r
+\r
+  The GetNextSlot() function retrieves the next slot number on an SD controller.\r
+  If on input Slot is 0xFF, then the slot number of the first slot on the SD controller\r
+  is returned.\r
+\r
+  If Slot is a slot number that was returned on a previous call to GetNextSlot(), then\r
+  the slot number of the next slot on the SD controller is returned.\r
+\r
+  If Slot is not 0xFF and Slot was not returned on a previous call to GetNextSlot(),\r
+  EFI_INVALID_PARAMETER is returned.\r
+\r
+  If Slot is the slot number of the last slot on the SD controller, then EFI_NOT_FOUND\r
+  is returned.\r
+\r
+  @param[in]     This           A pointer to the EFI_SD_MMMC_PASS_THRU_PROTOCOL instance.\r
+  @param[in,out] Slot           On input, a pointer to a slot number on the SD controller.\r
+                                On output, a pointer to the next slot number on the SD controller.\r
+                                An input value of 0xFF retrieves the first slot number on the SD\r
+                                controller.\r
+\r
+  @retval EFI_SUCCESS           The next slot number on the SD controller was returned in Slot.\r
+  @retval EFI_NOT_FOUND         There are no more slots on this SD controller.\r
+  @retval EFI_INVALID_PARAMETER Slot is not 0xFF and Slot was not returned on a previous call\r
+                                to GetNextSlot().\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+SdMmcPassThruGetNextSlot (\r
+  IN     EFI_SD_MMC_PASS_THRU_PROTOCOL        *This,\r
+  IN OUT UINT8                                *Slot\r
+  );\r
+\r
+/**\r
+  Used to allocate and build a device path node for an SD card on the SD controller.\r
+\r
+  The BuildDevicePath() function allocates and builds a single device node for the SD\r
+  card specified by Slot.\r
+\r
+  If the SD card specified by Slot is not present on the SD controller, then EFI_NOT_FOUND\r
+  is returned.\r
+\r
+  If DevicePath is NULL, then EFI_INVALID_PARAMETER is returned.\r
+\r
+  If there are not enough resources to allocate the device path node, then EFI_OUT_OF_RESOURCES\r
+  is returned.\r
+\r
+  Otherwise, DevicePath is allocated with the boot service AllocatePool(), the contents of\r
+  DevicePath are initialized to describe the SD card specified by Slot, and EFI_SUCCESS is\r
+  returned.\r
+\r
+  @param[in]     This           A pointer to the EFI_SD_MMMC_PASS_THRU_PROTOCOL instance.\r
+  @param[in]     Slot           Specifies the slot number of the SD card for which a device\r
+                                path node is to be allocated and built.\r
+  @param[in,out] DevicePath     A pointer to a single device path node that describes the SD\r
+                                card specified by Slot. This function is responsible for\r
+                                allocating the buffer DevicePath with the boot service\r
+                                AllocatePool(). It is the caller's responsibility to free\r
+                                DevicePath when the caller is finished with DevicePath.\r
+\r
+  @retval EFI_SUCCESS           The device path node that describes the SD card specified by\r
+                                Slot was allocated and returned in DevicePath.\r
+  @retval EFI_NOT_FOUND         The SD card specified by Slot does not exist on the SD controller.\r
+  @retval EFI_INVALID_PARAMETER DevicePath is NULL.\r
+  @retval EFI_OUT_OF_RESOURCES  There are not enough resources to allocate DevicePath.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+SdMmcPassThruBuildDevicePath (\r
+  IN     EFI_SD_MMC_PASS_THRU_PROTOCOL       *This,\r
+  IN     UINT8                               Slot,\r
+  IN OUT EFI_DEVICE_PATH_PROTOCOL            **DevicePath\r
+  );\r
+\r
+/**\r
+  This function retrieves an SD card slot number based on the input device path.\r
+\r
+  The GetSlotNumber() function retrieves slot number for the SD card specified by\r
+  the DevicePath node. If DevicePath is NULL, EFI_INVALID_PARAMETER is returned.\r
+\r
+  If DevicePath is not a device path node type that the SD Pass Thru driver supports,\r
+  EFI_UNSUPPORTED is returned.\r
+\r
+  @param[in]  This              A pointer to the EFI_SD_MMC_PASS_THRU_PROTOCOL instance.\r
+  @param[in]  DevicePath        A pointer to the device path node that describes a SD\r
+                                card on the SD controller.\r
+  @param[out] Slot              On return, points to the slot number of an SD card on\r
+                                the SD controller.\r
+\r
+  @retval EFI_SUCCESS           SD card slot number is returned in Slot.\r
+  @retval EFI_INVALID_PARAMETER Slot or DevicePath is NULL.\r
+  @retval EFI_UNSUPPORTED       DevicePath is not a device path node type that the SD\r
+                                Pass Thru driver supports.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+SdMmcPassThruGetSlotNumber (\r
+  IN  EFI_SD_MMC_PASS_THRU_PROTOCOL          *This,\r
+  IN  EFI_DEVICE_PATH_PROTOCOL               *DevicePath,\r
+  OUT UINT8                                  *Slot\r
+  );\r
+\r
+/**\r
+  Resets an SD card that is connected to the SD controller.\r
+\r
+  The ResetDevice() function resets the SD card specified by Slot.\r
+\r
+  If this SD controller does not support a device reset operation, EFI_UNSUPPORTED is\r
+  returned.\r
+\r
+  If Slot is not in a valid slot number for this SD controller, EFI_INVALID_PARAMETER\r
+  is returned.\r
+\r
+  If the device reset operation is completed, EFI_SUCCESS is returned.\r
+\r
+  @param[in]  This              A pointer to the EFI_SD_MMC_PASS_THRU_PROTOCOL instance.\r
+  @param[in]  Slot              Specifies the slot number of the SD card to be reset.\r
+\r
+  @retval EFI_SUCCESS           The SD card specified by Slot was reset.\r
+  @retval EFI_UNSUPPORTED       The SD controller does not support a device reset operation.\r
+  @retval EFI_INVALID_PARAMETER Slot number is invalid.\r
+  @retval EFI_NO_MEDIA          SD Device not present in the Slot.\r
+  @retval EFI_DEVICE_ERROR      The reset command failed due to a device error\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+SdMmcPassThruResetDevice (\r
+  IN EFI_SD_MMC_PASS_THRU_PROTOCOL           *This,\r
+  IN UINT8                                   Slot\r
+  );\r
+\r
+//\r
+// Driver model protocol interfaces\r
+//\r
+/**\r
+  Tests to see if this driver supports a given controller. If a child device is provided,\r
+  it further tests to see if this driver supports creating a handle for the specified child device.\r
+\r
+  This function checks to see if the driver specified by This supports the device specified by\r
+  ControllerHandle. Drivers will typically use the device path attached to\r
+  ControllerHandle and/or the services from the bus I/O abstraction attached to\r
+  ControllerHandle to determine if the driver supports ControllerHandle. This function\r
+  may be called many times during platform initialization. In order to reduce boot times, the tests\r
+  performed by this function must be very small, and take as little time as possible to execute. This\r
+  function must not change the state of any hardware devices, and this function must be aware that the\r
+  device specified by ControllerHandle may already be managed by the same driver or a\r
+  different driver. This function must match its calls to AllocatePages() with FreePages(),\r
+  AllocatePool() with FreePool(), and OpenProtocol() with CloseProtocol().\r
+  Since ControllerHandle may have been previously started by the same driver, if a protocol is\r
+  already in the opened state, then it must not be closed with CloseProtocol(). This is required\r
+  to guarantee the state of ControllerHandle is not modified by this function.\r
+\r
+  @param[in]  This                 A pointer to the EFI_DRIVER_BINDING_PROTOCOL instance.\r
+  @param[in]  ControllerHandle     The handle of the controller to test. This handle\r
+                                   must support a protocol interface that supplies\r
+                                   an I/O abstraction to the driver.\r
+  @param[in]  RemainingDevicePath  A pointer to the remaining portion of a device path.  This\r
+                                   parameter is ignored by device drivers, and is optional for bus\r
+                                   drivers. For bus drivers, if this parameter is not NULL, then\r
+                                   the bus driver must determine if the bus controller specified\r
+                                   by ControllerHandle and the child controller specified\r
+                                   by RemainingDevicePath are both supported by this\r
+                                   bus driver.\r
+\r
+  @retval EFI_SUCCESS              The device specified by ControllerHandle and\r
+                                   RemainingDevicePath is supported by the driver specified by This.\r
+  @retval EFI_ALREADY_STARTED      The device specified by ControllerHandle and\r
+                                   RemainingDevicePath is already being managed by the driver\r
+                                   specified by This.\r
+  @retval EFI_ACCESS_DENIED        The device specified by ControllerHandle and\r
+                                   RemainingDevicePath is already being managed by a different\r
+                                   driver or an application that requires exclusive access.\r
+                                   Currently not implemented.\r
+  @retval EFI_UNSUPPORTED          The device specified by ControllerHandle and\r
+                                   RemainingDevicePath is not supported by the driver specified by This.\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+SdMmcPciHcDriverBindingSupported (\r
+  IN EFI_DRIVER_BINDING_PROTOCOL *This,\r
+  IN EFI_HANDLE                  Controller,\r
+  IN EFI_DEVICE_PATH_PROTOCOL    *RemainingDevicePath\r
+  );\r
+\r
+/**\r
+  Starts a device controller or a bus controller.\r
+\r
+  The Start() function is designed to be invoked from the EFI boot service ConnectController().\r
+  As a result, much of the error checking on the parameters to Start() has been moved into this\r
+  common boot service. It is legal to call Start() from other locations,\r
+  but the following calling restrictions must be followed or the system behavior will not be deterministic.\r
+  1. ControllerHandle must be a valid EFI_HANDLE.\r
+  2. If RemainingDevicePath is not NULL, then it must be a pointer to a naturally aligned\r
+     EFI_DEVICE_PATH_PROTOCOL.\r
+  3. Prior to calling Start(), the Supported() function for the driver specified by This must\r
+     have been called with the same calling parameters, and Supported() must have returned EFI_SUCCESS.\r
+\r
+  @param[in]  This                 A pointer to the EFI_DRIVER_BINDING_PROTOCOL instance.\r
+  @param[in]  ControllerHandle     The handle of the controller to start. This handle\r
+                                   must support a protocol interface that supplies\r
+                                   an I/O abstraction to the driver.\r
+  @param[in]  RemainingDevicePath  A pointer to the remaining portion of a device path.  This\r
+                                   parameter is ignored by device drivers, and is optional for bus\r
+                                   drivers. For a bus driver, if this parameter is NULL, then handles\r
+                                   for all the children of Controller are created by this driver.\r
+                                   If this parameter is not NULL and the first Device Path Node is\r
+                                   not the End of Device Path Node, then only the handle for the\r
+                                   child device specified by the first Device Path Node of\r
+                                   RemainingDevicePath is created by this driver.\r
+                                   If the first Device Path Node of RemainingDevicePath is\r
+                                   the End of Device Path Node, no child handle is created by this\r
+                                   driver.\r
+\r
+  @retval EFI_SUCCESS              The device was started.\r
+  @retval EFI_DEVICE_ERROR         The device could not be started due to a device error.Currently not implemented.\r
+  @retval EFI_OUT_OF_RESOURCES     The request could not be completed due to a lack of resources.\r
+  @retval Others                   The driver failded to start the device.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+SdMmcPciHcDriverBindingStart (\r
+  IN EFI_DRIVER_BINDING_PROTOCOL     *This,\r
+  IN EFI_HANDLE                      Controller,\r
+  IN EFI_DEVICE_PATH_PROTOCOL        *RemainingDevicePath\r
+  );\r
+\r
+/**\r
+  Stops a device controller or a bus controller.\r
+\r
+  The Stop() function is designed to be invoked from the EFI boot service DisconnectController().\r
+  As a result, much of the error checking on the parameters to Stop() has been moved\r
+  into this common boot service. It is legal to call Stop() from other locations,\r
+  but the following calling restrictions must be followed or the system behavior will not be deterministic.\r
+  1. ControllerHandle must be a valid EFI_HANDLE that was used on a previous call to this\r
+     same driver's Start() function.\r
+  2. The first NumberOfChildren handles of ChildHandleBuffer must all be a valid\r
+     EFI_HANDLE. In addition, all of these handles must have been created in this driver's\r
+     Start() function, and the Start() function must have called OpenProtocol() on\r
+     ControllerHandle with an Attribute of EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER.\r
+\r
+  @param[in]  This              A pointer to the EFI_DRIVER_BINDING_PROTOCOL instance.\r
+  @param[in]  ControllerHandle  A handle to the device being stopped. The handle must\r
+                                support a bus specific I/O protocol for the driver\r
+                                to use to stop the device.\r
+  @param[in]  NumberOfChildren  The number of child device handles in ChildHandleBuffer.\r
+  @param[in]  ChildHandleBuffer An array of child handles to be freed. May be NULL\r
+                                if NumberOfChildren is 0.\r
+\r
+  @retval EFI_SUCCESS           The device was stopped.\r
+  @retval EFI_DEVICE_ERROR      The device could not be stopped due to a device error.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+SdMmcPciHcDriverBindingStop (\r
+  IN  EFI_DRIVER_BINDING_PROTOCOL     *This,\r
+  IN  EFI_HANDLE                      Controller,\r
+  IN  UINTN                           NumberOfChildren,\r
+  IN  EFI_HANDLE                      *ChildHandleBuffer\r
+  );\r
+\r
+//\r
+// EFI Component Name Functions\r
+//\r
+/**\r
+  Retrieves a Unicode string that is the user readable name of the driver.\r
+\r
+  This function retrieves the user readable name of a driver in the form of a\r
+  Unicode string. If the driver specified by This has a user readable name in\r
+  the language specified by Language, then a pointer to the driver name is\r
+  returned in DriverName, and EFI_SUCCESS is returned. If the driver specified\r
+  by This does not support the language specified by Language,\r
+  then EFI_UNSUPPORTED is returned.\r
+\r
+  @param  This[in]              A pointer to the EFI_COMPONENT_NAME2_PROTOCOL or\r
+                                EFI_COMPONENT_NAME_PROTOCOL instance.\r
+\r
+  @param  Language[in]          A pointer to a Null-terminated ASCII string\r
+                                array indicating the language. This is the\r
+                                language of the driver name that the caller is\r
+                                requesting, and it must match one of the\r
+                                languages specified in SupportedLanguages. The\r
+                                number of languages supported by a driver is up\r
+                                to the driver writer. Language is specified\r
+                                in RFC 4646 or ISO 639-2 language code format.\r
+\r
+  @param  DriverName[out]       A pointer to the Unicode string to return.\r
+                                This Unicode string is the name of the\r
+                                driver specified by This in the language\r
+                                specified by Language.\r
+\r
+  @retval EFI_SUCCESS           The Unicode string for the Driver specified by\r
+                                This and the language specified by Language was\r
+                                returned in DriverName.\r
+\r
+  @retval EFI_INVALID_PARAMETER Language is NULL.\r
+\r
+  @retval EFI_INVALID_PARAMETER DriverName is NULL.\r
+\r
+  @retval EFI_UNSUPPORTED       The driver specified by This does not support\r
+                                the language specified by Language.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+SdMmcPciHcComponentNameGetDriverName (\r
+  IN  EFI_COMPONENT_NAME_PROTOCOL     *This,\r
+  IN  CHAR8                           *Language,\r
+  OUT CHAR16                          **DriverName\r
+  );\r
+\r
+/**\r
+  Retrieves a Unicode string that is the user readable name of the controller\r
+  that is being managed by a driver.\r
+\r
+  This function retrieves the user readable name of the controller specified by\r
+  ControllerHandle and ChildHandle in the form of a Unicode string. If the\r
+  driver specified by This has a user readable name in the language specified by\r
+  Language, then a pointer to the controller name is returned in ControllerName,\r
+  and EFI_SUCCESS is returned.  If the driver specified by This is not currently\r
+  managing the controller specified by ControllerHandle and ChildHandle,\r
+  then EFI_UNSUPPORTED is returned.  If the driver specified by This does not\r
+  support the language specified by Language, then EFI_UNSUPPORTED is returned.\r
+\r
+  @param  This[in]              A pointer to the EFI_COMPONENT_NAME2_PROTOCOL or\r
+                                EFI_COMPONENT_NAME_PROTOCOL instance.\r
+\r
+  @param  ControllerHandle[in]  The handle of a controller that the driver\r
+                                specified by This is managing.  This handle\r
+                                specifies the controller whose name is to be\r
+                                returned.\r
+\r
+  @param  ChildHandle[in]       The handle of the child controller to retrieve\r
+                                the name of.  This is an optional parameter that\r
+                                may be NULL.  It will be NULL for device\r
+                                drivers.  It will also be NULL for a bus drivers\r
+                                that wish to retrieve the name of the bus\r
+                                controller.  It will not be NULL for a bus\r
+                                driver that wishes to retrieve the name of a\r
+                                child controller.\r
+\r
+  @param  Language[in]          A pointer to a Null-terminated ASCII string\r
+                                array indicating the language.  This is the\r
+                                language of the driver name that the caller is\r
+                                requesting, and it must match one of the\r
+                                languages specified in SupportedLanguages. The\r
+                                number of languages supported by a driver is up\r
+                                to the driver writer. Language is specified in\r
+                                RFC 4646 or ISO 639-2 language code format.\r
+\r
+  @param  ControllerName[out]   A pointer to the Unicode string to return.\r
+                                This Unicode string is the name of the\r
+                                controller specified by ControllerHandle and\r
+                                ChildHandle in the language specified by\r
+                                Language from the point of view of the driver\r
+                                specified by This.\r
+\r
+  @retval EFI_SUCCESS           The Unicode string for the user readable name in\r
+                                the language specified by Language for the\r
+                                driver specified by This was returned in\r
+                                DriverName.\r
+\r
+  @retval EFI_INVALID_PARAMETER ControllerHandle is not a valid EFI_HANDLE.\r
+\r
+  @retval EFI_INVALID_PARAMETER ChildHandle is not NULL and it is not a valid\r
+                                EFI_HANDLE.\r
+\r
+  @retval EFI_INVALID_PARAMETER Language is NULL.\r
+\r
+  @retval EFI_INVALID_PARAMETER ControllerName is NULL.\r
+\r
+  @retval EFI_UNSUPPORTED       The driver specified by This is not currently\r
+                                managing the controller specified by\r
+                                ControllerHandle and ChildHandle.\r
+\r
+  @retval EFI_UNSUPPORTED       The driver specified by This does not support\r
+                                the language specified by Language.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+SdMmcPciHcComponentNameGetControllerName (\r
+  IN  EFI_COMPONENT_NAME_PROTOCOL     *This,\r
+  IN  EFI_HANDLE                      ControllerHandle,\r
+  IN  EFI_HANDLE                      ChildHandle, OPTIONAL\r
+  IN  CHAR8                           *Language,\r
+  OUT CHAR16                          **ControllerName\r
+  );\r
+\r
+/**\r
+  Create a new TRB for the SD/MMC cmd request.\r
+\r
+  @param[in] Private        A pointer to the SD_MMC_HC_PRIVATE_DATA instance.\r
+  @param[in] Slot           The slot number of the SD card to send the command to.\r
+  @param[in] Packet         A pointer to the SD command data structure.\r
+  @param[in] Event          If Event is NULL, blocking I/O is performed. If Event is\r
+                            not NULL, then nonblocking I/O is performed, and Event\r
+                            will be signaled when the Packet completes.\r
+\r
+  @return Created Trb or NULL.\r
+\r
+**/\r
+SD_MMC_HC_TRB *\r
+SdMmcCreateTrb (\r
+  IN SD_MMC_HC_PRIVATE_DATA              *Private,\r
+  IN UINT8                               Slot,\r
+  IN EFI_SD_MMC_PASS_THRU_COMMAND_PACKET *Packet,\r
+  IN EFI_EVENT                           Event\r
+  );\r
+\r
+/**\r
+  Free the resource used by the TRB.\r
+\r
+  @param[in] Trb            The pointer to the SD_MMC_HC_TRB instance.\r
+\r
+**/\r
+VOID\r
+SdMmcFreeTrb (\r
+  IN SD_MMC_HC_TRB           *Trb\r
+  );\r
+\r
+/**\r
+  Check if the env is ready for execute specified TRB.\r
+\r
+  @param[in] Private        A pointer to the SD_MMC_HC_PRIVATE_DATA instance.\r
+  @param[in] Trb            The pointer to the SD_MMC_HC_TRB instance.\r
+\r
+  @retval EFI_SUCCESS       The env is ready for TRB execution.\r
+  @retval EFI_NOT_READY     The env is not ready for TRB execution.\r
+  @retval Others            Some erros happen.\r
+\r
+**/\r
+EFI_STATUS\r
+SdMmcCheckTrbEnv (\r
+  IN SD_MMC_HC_PRIVATE_DATA           *Private,\r
+  IN SD_MMC_HC_TRB                    *Trb\r
+  );\r
+\r
+/**\r
+  Wait for the env to be ready for execute specified TRB.\r
+\r
+  @param[in] Private        A pointer to the SD_MMC_HC_PRIVATE_DATA instance.\r
+  @param[in] Trb            The pointer to the SD_MMC_HC_TRB instance.\r
+\r
+  @retval EFI_SUCCESS       The env is ready for TRB execution.\r
+  @retval EFI_TIMEOUT       The env is not ready for TRB execution in time.\r
+  @retval Others            Some erros happen.\r
+\r
+**/\r
+EFI_STATUS\r
+SdMmcWaitTrbEnv (\r
+  IN SD_MMC_HC_PRIVATE_DATA           *Private,\r
+  IN SD_MMC_HC_TRB                    *Trb\r
+  );\r
+\r
+/**\r
+  Execute the specified TRB.\r
+\r
+  @param[in] Private        A pointer to the SD_MMC_HC_PRIVATE_DATA instance.\r
+  @param[in] Trb            The pointer to the SD_MMC_HC_TRB instance.\r
+\r
+  @retval EFI_SUCCESS       The TRB is sent to host controller successfully.\r
+  @retval Others            Some erros happen when sending this request to the host controller.\r
+\r
+**/\r
+EFI_STATUS\r
+SdMmcExecTrb (\r
+  IN SD_MMC_HC_PRIVATE_DATA           *Private,\r
+  IN SD_MMC_HC_TRB                    *Trb\r
+  );\r
+\r
+/**\r
+  Check the TRB execution result.\r
+\r
+  @param[in] Private        A pointer to the SD_MMC_HC_PRIVATE_DATA instance.\r
+  @param[in] Trb            The pointer to the SD_MMC_HC_TRB instance.\r
+\r
+  @retval EFI_SUCCESS       The TRB is executed successfully.\r
+  @retval EFI_NOT_READY     The TRB is not completed for execution.\r
+  @retval Others            Some erros happen when executing this request.\r
+\r
+**/\r
+EFI_STATUS\r
+SdMmcCheckTrbResult (\r
+  IN SD_MMC_HC_PRIVATE_DATA           *Private,\r
+  IN SD_MMC_HC_TRB                    *Trb\r
+  );\r
+\r
+/**\r
+  Wait for the TRB execution result.\r
+\r
+  @param[in] Private        A pointer to the SD_MMC_HC_PRIVATE_DATA instance.\r
+  @param[in] Trb            The pointer to the SD_MMC_HC_TRB instance.\r
+\r
+  @retval EFI_SUCCESS       The TRB is executed successfully.\r
+  @retval Others            Some erros happen when executing this request.\r
+\r
+**/\r
+EFI_STATUS\r
+SdMmcWaitTrbResult (\r
+  IN SD_MMC_HC_PRIVATE_DATA           *Private,\r
+  IN SD_MMC_HC_TRB                    *Trb\r
+  );\r
+\r
+/**\r
+  Execute EMMC device identification procedure.\r
+\r
+  Refer to EMMC Electrical Standard Spec 5.1 Section 6.4 for details.\r
+\r
+  @param[in] Private        A pointer to the SD_MMC_HC_PRIVATE_DATA instance.\r
+  @param[in] Slot           The slot number of the SD card to send the command to.\r
+\r
+  @retval EFI_SUCCESS       There is a EMMC card.\r
+  @retval Others            There is not a EMMC card.\r
+\r
+**/\r
+EFI_STATUS\r
+EmmcIdentification (\r
+  IN SD_MMC_HC_PRIVATE_DATA             *Private,\r
+  IN UINT8                              Slot\r
+  );\r
+\r
+/**\r
+  Execute EMMC device identification procedure.\r
+\r
+  Refer to EMMC Electrical Standard Spec 5.1 Section 6.4 for details.\r
+\r
+  @param[in] Private        A pointer to the SD_MMC_HC_PRIVATE_DATA instance.\r
+  @param[in] Slot           The slot number of the SD card to send the command to.\r
+\r
+  @retval EFI_SUCCESS       There is a EMMC card.\r
+  @retval Others            There is not a EMMC card.\r
+\r
+**/\r
+EFI_STATUS\r
+SdCardIdentification (\r
+  IN SD_MMC_HC_PRIVATE_DATA             *Private,\r
+  IN UINT8                              Slot\r
+  );\r
+\r
+#endif\r
diff --git a/MdeModulePkg/Bus/Pci/SdMmcPciHcDxe/SdMmcPciHcDxe.inf b/MdeModulePkg/Bus/Pci/SdMmcPciHcDxe/SdMmcPciHcDxe.inf
new file mode 100644 (file)
index 0000000..e26e6a0
--- /dev/null
@@ -0,0 +1,72 @@
+## @file\r
+#  SdMmcPciHcDxe driver is used to manage those host controllers which comply with SD\r
+#  Host Controller Simplified Specifiction version 3.0.\r
+#\r
+#  It will produce EFI_SD_MMC_PASS_THRU_PROTOCOL to allow sending SD/MMC/eMMC cmds\r
+#  to specified devices from upper layer.\r
+#\r
+#  Copyright (c) 2015, Intel Corporation. All rights reserved.<BR>\r
+#\r
+#  This program and the accompanying materials\r
+#  are licensed and made available under the terms and conditions of the BSD License\r
+#  which accompanies this distribution. The full text of the license may be found at\r
+#  http://opensource.org/licenses/bsd-license.php\r
+#  THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+#  WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+#\r
+#\r
+##\r
+\r
+[Defines]\r
+  INF_VERSION                    = 0x00010005\r
+  BASE_NAME                      = SdMmcPciHcDxe\r
+  MODULE_UNI_FILE                = SdMmcPciHcDxe.uni\r
+  FILE_GUID                      = 8E325979-3FE1-4927-AAE2-8F5C4BD2AF0D\r
+  MODULE_TYPE                    = UEFI_DRIVER\r
+  VERSION_STRING                 = 1.0\r
+  ENTRY_POINT                    = InitializeSdMmcPciHcDxe\r
+\r
+#\r
+# The following information is for reference only and not required by the build tools.\r
+#\r
+#  VALID_ARCHITECTURES           = IA32 X64 IPF EBC\r
+#\r
+#  DRIVER_BINDING                =  gSdMmcPciHcDxeDriverBinding\r
+#  COMPONENT_NAME                =  gSdMmcPciHcDxeComponentName\r
+#  COMPONENT_NAME2               =  gSdMmcPciHcDxeComponentName2\r
+#\r
+#\r
+\r
+[Sources]\r
+  SdMmcPciHcDxe.h\r
+  SdMmcPciHcDxe.c\r
+  EmmcDevice.c\r
+  SdDevice.c\r
+  SdMmcPciHci.h\r
+  SdMmcPciHci.c\r
+  ComponentName.c\r
+\r
+[Packages]\r
+  MdePkg/MdePkg.dec\r
+\r
+[LibraryClasses]\r
+  DevicePathLib\r
+  UefiBootServicesTableLib\r
+  UefiRuntimeServicesTableLib\r
+  MemoryAllocationLib\r
+  BaseMemoryLib\r
+  UefiLib\r
+  BaseLib\r
+  UefiDriverEntryPoint\r
+  DebugLib\r
+\r
+[Protocols]\r
+  gEfiDevicePathProtocolGuid                    ## TO_START\r
+  gEfiPciIoProtocolGuid                         ## TO_START\r
+  gEfiSdMmcPassThruProtocolGuid                 ## BY_START\r
+\r
+# [Event]\r
+# EVENT_TYPE_PERIODIC_TIMER ## SOMETIMES_CONSUMES\r
+\r
+[UserExtensions.TianoCore."ExtraFiles"]\r
+  SdMmcPciHcDxeExtra.uni\r
diff --git a/MdeModulePkg/Bus/Pci/SdMmcPciHcDxe/SdMmcPciHcDxe.uni b/MdeModulePkg/Bus/Pci/SdMmcPciHcDxe/SdMmcPciHcDxe.uni
new file mode 100644 (file)
index 0000000..57f9fa7
--- /dev/null
@@ -0,0 +1,23 @@
+// /** @file\r
+// SdMmcPciHcDxe driver is used to manage those host controllers which comply with SD\r
+// Host Controller Simplified Specifiction version 3.0.\r
+//\r
+// It will produce EFI_SD_MMC_PASS_THRU_PROTOCOL to allow sending SD/MMC/eMMC cmds\r
+// to specified devices from upper layer.\r
+//\r
+// Copyright (c) 2015, Intel Corporation. All rights reserved.<BR>\r
+//\r
+// This program and the accompanying materials\r
+// are licensed and made available under the terms and conditions of the BSD License\r
+// which accompanies this distribution. The full text of the license may be found at\r
+// http://opensource.org/licenses/bsd-license.php\r
+// THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+// WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+//\r
+// **/\r
+\r
+\r
+#string STR_MODULE_ABSTRACT             #language en-US "SD/MMC Pci Host Controller driver to manage SD/MMC host controllers"\r
+\r
+#string STR_MODULE_DESCRIPTION          #language en-US "This driver follows the UEFI driver model and produces SD/MMC Pass Thru protocol for upper layer bus driver."\r
+\r
diff --git a/MdeModulePkg/Bus/Pci/SdMmcPciHcDxe/SdMmcPciHcDxeExtra.uni b/MdeModulePkg/Bus/Pci/SdMmcPciHcDxe/SdMmcPciHcDxeExtra.uni
new file mode 100644 (file)
index 0000000..c7aedb4
--- /dev/null
@@ -0,0 +1,19 @@
+// /** @file\r
+// SdMmcPciHcDxe Localized Strings and Content\r
+//\r
+// Copyright (c) 2015, Intel Corporation. All rights reserved.<BR>\r
+//\r
+// This program and the accompanying materials\r
+// are licensed and made available under the terms and conditions of the BSD License\r
+// which accompanies this distribution. The full text of the license may be found at\r
+// http://opensource.org/licenses/bsd-license.php\r
+// THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+// WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+//\r
+// **/\r
+\r
+#string STR_PROPERTIES_MODULE_NAME\r
+#language en-US\r
+"SD/MMC Pci Host Controller Driver"\r
+\r
+\r
diff --git a/MdeModulePkg/Bus/Pci/SdMmcPciHcDxe/SdMmcPciHci.c b/MdeModulePkg/Bus/Pci/SdMmcPciHcDxe/SdMmcPciHci.c
new file mode 100644 (file)
index 0000000..d2bd112
--- /dev/null
@@ -0,0 +1,1901 @@
+/** @file\r
+  This driver is used to manage SD/MMC PCI host controllers which are compliance\r
+  with SD Host Controller Simplified Specification version 3.00.\r
+\r
+  It would expose EFI_SD_MMC_PASS_THRU_PROTOCOL for upper layer use.\r
+\r
+  Copyright (c) 2015 - 2016, Intel Corporation. All rights reserved.<BR>\r
+  This program and the accompanying materials\r
+  are licensed and made available under the terms and conditions of the BSD License\r
+  which accompanies this distribution.  The full text of the license may be found at\r
+  http://opensource.org/licenses/bsd-license.php\r
+\r
+  THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+  WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+\r
+**/\r
+\r
+#include "SdMmcPciHcDxe.h"\r
+\r
+/**\r
+  Dump the content of SD/MMC host controller's Capability Register.\r
+\r
+  @param[in]  Slot            The slot number of the SD card to send the command to.\r
+  @param[in]  Capability      The buffer to store the capability data.\r
+\r
+**/\r
+VOID\r
+DumpCapabilityReg (\r
+  IN UINT8                Slot,\r
+  IN SD_MMC_HC_SLOT_CAP   *Capability\r
+  )\r
+{\r
+  //\r
+  // Dump Capability Data\r
+  //\r
+  DEBUG ((EFI_D_INFO, " == Slot [%d] Capability is 0x%x ==\n", Slot, Capability));\r
+  DEBUG ((EFI_D_INFO, "   Timeout Clk Freq  %d%a\n", Capability->TimeoutFreq, (Capability->TimeoutUnit) ? "MHz" : "KHz"));\r
+  DEBUG ((EFI_D_INFO, "   Base Clk Freq     %dMHz\n", Capability->BaseClkFreq));\r
+  DEBUG ((EFI_D_INFO, "   Max Blk Len       %dbytes\n", 512 * (1 << Capability->MaxBlkLen)));\r
+  DEBUG ((EFI_D_INFO, "   8-bit Support     %a\n", Capability->BusWidth8 ? "TRUE" : "FALSE"));\r
+  DEBUG ((EFI_D_INFO, "   ADMA2 Support     %a\n", Capability->Adma2 ? "TRUE" : "FALSE"));\r
+  DEBUG ((EFI_D_INFO, "   HighSpeed Support %a\n", Capability->HighSpeed ? "TRUE" : "FALSE"));\r
+  DEBUG ((EFI_D_INFO, "   SDMA Support      %a\n", Capability->Sdma ? "TRUE" : "FALSE"));\r
+  DEBUG ((EFI_D_INFO, "   Suspend/Resume    %a\n", Capability->SuspRes ? "TRUE" : "FALSE"));\r
+  DEBUG ((EFI_D_INFO, "   Voltage 3.3       %a\n", Capability->Voltage33 ? "TRUE" : "FALSE"));\r
+  DEBUG ((EFI_D_INFO, "   Voltage 3.0       %a\n", Capability->Voltage30 ? "TRUE" : "FALSE"));\r
+  DEBUG ((EFI_D_INFO, "   Voltage 1.8       %a\n", Capability->Voltage18 ? "TRUE" : "FALSE"));\r
+  DEBUG ((EFI_D_INFO, "   64-bit Sys Bus    %a\n", Capability->SysBus64 ? "TRUE" : "FALSE"));\r
+  DEBUG ((EFI_D_INFO, "   Async Interrupt   %a\n", Capability->AsyncInt ? "TRUE" : "FALSE"));\r
+  DEBUG ((EFI_D_INFO, "   SlotType          "));\r
+  if (Capability->SlotType == 0x00) {\r
+    DEBUG ((EFI_D_INFO, "%a\n", "Removable Slot"));\r
+  } else if (Capability->SlotType == 0x01) {\r
+    DEBUG ((EFI_D_INFO, "%a\n", "Embedded Slot"));\r
+  } else if (Capability->SlotType == 0x02) {\r
+    DEBUG ((EFI_D_INFO, "%a\n", "Shared Bus Slot"));\r
+  } else {\r
+    DEBUG ((EFI_D_INFO, "%a\n", "Reserved"));\r
+  }\r
+  DEBUG ((EFI_D_INFO, "   SDR50  Support    %a\n", Capability->Sdr50 ? "TRUE" : "FALSE"));\r
+  DEBUG ((EFI_D_INFO, "   SDR104 Support    %a\n", Capability->Sdr104 ? "TRUE" : "FALSE"));\r
+  DEBUG ((EFI_D_INFO, "   DDR50  Support    %a\n", Capability->Ddr50 ? "TRUE" : "FALSE"));\r
+  DEBUG ((EFI_D_INFO, "   Driver Type A     %a\n", Capability->DriverTypeA ? "TRUE" : "FALSE"));\r
+  DEBUG ((EFI_D_INFO, "   Driver Type C     %a\n", Capability->DriverTypeC ? "TRUE" : "FALSE"));\r
+  DEBUG ((EFI_D_INFO, "   Driver Type D     %a\n", Capability->DriverTypeD ? "TRUE" : "FALSE"));\r
+  DEBUG ((EFI_D_INFO, "   Driver Type 4     %a\n", Capability->DriverType4 ? "TRUE" : "FALSE"));\r
+  if (Capability->TimerCount == 0) {\r
+    DEBUG ((EFI_D_INFO, "   Retuning TimerCnt Disabled\n", 2 * (Capability->TimerCount - 1)));\r
+  } else {\r
+    DEBUG ((EFI_D_INFO, "   Retuning TimerCnt %dseconds\n", 2 * (Capability->TimerCount - 1)));\r
+  }\r
+  DEBUG ((EFI_D_INFO, "   SDR50 Tuning      %a\n", Capability->TuningSDR50 ? "TRUE" : "FALSE"));\r
+  DEBUG ((EFI_D_INFO, "   Retuning Mode     Mode %d\n", Capability->RetuningMod + 1));\r
+  DEBUG ((EFI_D_INFO, "   Clock Multiplier  M = %d\n", Capability->ClkMultiplier + 1));\r
+  DEBUG ((EFI_D_INFO, "   HS 400            %a\n", Capability->Hs400 ? "TRUE" : "FALSE"));\r
+  return;\r
+}\r
+\r
+/**\r
+  Read SlotInfo register from SD/MMC host controller pci config space.\r
+\r
+  @param[in]  PciIo        The PCI IO protocol instance.\r
+  @param[out] FirstBar     The buffer to store the first BAR value.\r
+  @param[out] SlotNum      The buffer to store the supported slot number.\r
+\r
+  @retval EFI_SUCCESS      The operation succeeds.\r
+  @retval Others           The operation fails.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+SdMmcHcGetSlotInfo (\r
+  IN     EFI_PCI_IO_PROTOCOL   *PciIo,\r
+     OUT UINT8                 *FirstBar,\r
+     OUT UINT8                 *SlotNum\r
+  )\r
+{\r
+  EFI_STATUS                   Status;\r
+  SD_MMC_HC_SLOT_INFO          SlotInfo;\r
+\r
+  Status = PciIo->Pci.Read (\r
+                        PciIo,\r
+                        EfiPciIoWidthUint8,\r
+                        SD_MMC_HC_SLOT_OFFSET,\r
+                        sizeof (SlotInfo),\r
+                        &SlotInfo\r
+                        );\r
+  if (EFI_ERROR (Status)) {\r
+    return Status;\r
+  }\r
+\r
+  *FirstBar = SlotInfo.FirstBar;\r
+  *SlotNum  = SlotInfo.SlotNum + 1;\r
+  ASSERT ((*FirstBar + *SlotNum) < SD_MMC_HC_MAX_SLOT);\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+  Read/Write specified SD/MMC host controller mmio register.\r
+\r
+  @param[in]      PciIo        The PCI IO protocol instance.\r
+  @param[in]      BarIndex     The BAR index of the standard PCI Configuration\r
+                               header to use as the base address for the memory\r
+                               operation to perform.\r
+  @param[in]      Offset       The offset within the selected BAR to start the\r
+                               memory operation.\r
+  @param[in]      Read         A boolean to indicate it's read or write operation.\r
+  @param[in]      Count        The width of the mmio register in bytes.\r
+                               Must be 1, 2 , 4 or 8 bytes.\r
+  @param[in, out] Data         For read operations, the destination buffer to store\r
+                               the results. For write operations, the source buffer\r
+                               to write data from. The caller is responsible for\r
+                               having ownership of the data buffer and ensuring its\r
+                               size not less than Count bytes.\r
+\r
+  @retval EFI_INVALID_PARAMETER The PciIo or Data is NULL or the Count is not valid.\r
+  @retval EFI_SUCCESS           The read/write operation succeeds.\r
+  @retval Others                The read/write operation fails.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+SdMmcHcRwMmio (\r
+  IN     EFI_PCI_IO_PROTOCOL   *PciIo,\r
+  IN     UINT8                 BarIndex,\r
+  IN     UINT32                Offset,\r
+  IN     BOOLEAN               Read,\r
+  IN     UINT8                 Count,\r
+  IN OUT VOID                  *Data\r
+  )\r
+{\r
+  EFI_STATUS                   Status;\r
+\r
+  if ((PciIo == NULL) || (Data == NULL))  {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  if ((Count != 1) && (Count != 2) && (Count != 4) && (Count != 8)) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  if (Read) {\r
+    Status = PciIo->Mem.Read (\r
+                          PciIo,\r
+                          EfiPciIoWidthUint8,\r
+                          BarIndex,\r
+                          (UINT64) Offset,\r
+                          Count,\r
+                          Data\r
+                          );\r
+  } else {\r
+    Status = PciIo->Mem.Write (\r
+                          PciIo,\r
+                          EfiPciIoWidthUint8,\r
+                          BarIndex,\r
+                          (UINT64) Offset,\r
+                          Count,\r
+                          Data\r
+                          );\r
+  }\r
+\r
+  return Status;\r
+}\r
+\r
+/**\r
+  Do OR operation with the value of the specified SD/MMC host controller mmio register.\r
+\r
+  @param[in] PciIo             The PCI IO protocol instance.\r
+  @param[in] BarIndex          The BAR index of the standard PCI Configuration\r
+                               header to use as the base address for the memory\r
+                               operation to perform.\r
+  @param[in] Offset            The offset within the selected BAR to start the\r
+                               memory operation.\r
+  @param[in] Count             The width of the mmio register in bytes.\r
+                               Must be 1, 2 , 4 or 8 bytes.\r
+  @param[in] OrData            The pointer to the data used to do OR operation.\r
+                               The caller is responsible for having ownership of\r
+                               the data buffer and ensuring its size not less than\r
+                               Count bytes.\r
+\r
+  @retval EFI_INVALID_PARAMETER The PciIo or OrData is NULL or the Count is not valid.\r
+  @retval EFI_SUCCESS           The OR operation succeeds.\r
+  @retval Others                The OR operation fails.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+SdMmcHcOrMmio (\r
+  IN  EFI_PCI_IO_PROTOCOL      *PciIo,\r
+  IN  UINT8                    BarIndex,\r
+  IN  UINT32                   Offset,\r
+  IN  UINT8                    Count,\r
+  IN  VOID                     *OrData\r
+  )\r
+{\r
+  EFI_STATUS                   Status;\r
+  UINT64                       Data;\r
+  UINT64                       Or;\r
+\r
+  Status = SdMmcHcRwMmio (PciIo, BarIndex, Offset, TRUE, Count, &Data);\r
+  if (EFI_ERROR (Status)) {\r
+    return Status;\r
+  }\r
+\r
+  if (Count == 1) {\r
+    Or = *(UINT8*) OrData;\r
+  } else if (Count == 2) {\r
+    Or = *(UINT16*) OrData;\r
+  } else if (Count == 4) {\r
+    Or = *(UINT32*) OrData;\r
+  } else if (Count == 8) {\r
+    Or = *(UINT64*) OrData;\r
+  } else {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  Data  |= Or;\r
+  Status = SdMmcHcRwMmio (PciIo, BarIndex, Offset, FALSE, Count, &Data);\r
+\r
+  return Status;\r
+}\r
+\r
+/**\r
+  Do AND operation with the value of the specified SD/MMC host controller mmio register.\r
+\r
+  @param[in] PciIo             The PCI IO protocol instance.\r
+  @param[in] BarIndex          The BAR index of the standard PCI Configuration\r
+                               header to use as the base address for the memory\r
+                               operation to perform.\r
+  @param[in] Offset            The offset within the selected BAR to start the\r
+                               memory operation.\r
+  @param[in] Count             The width of the mmio register in bytes.\r
+                               Must be 1, 2 , 4 or 8 bytes.\r
+  @param[in] AndData           The pointer to the data used to do AND operation.\r
+                               The caller is responsible for having ownership of\r
+                               the data buffer and ensuring its size not less than\r
+                               Count bytes.\r
+\r
+  @retval EFI_INVALID_PARAMETER The PciIo or AndData is NULL or the Count is not valid.\r
+  @retval EFI_SUCCESS           The AND operation succeeds.\r
+  @retval Others                The AND operation fails.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+SdMmcHcAndMmio (\r
+  IN  EFI_PCI_IO_PROTOCOL      *PciIo,\r
+  IN  UINT8                    BarIndex,\r
+  IN  UINT32                   Offset,\r
+  IN  UINT8                    Count,\r
+  IN  VOID                     *AndData\r
+  )\r
+{\r
+  EFI_STATUS                   Status;\r
+  UINT64                       Data;\r
+  UINT64                       And;\r
+\r
+  Status = SdMmcHcRwMmio (PciIo, BarIndex, Offset, TRUE, Count, &Data);\r
+  if (EFI_ERROR (Status)) {\r
+    return Status;\r
+  }\r
+\r
+  if (Count == 1) {\r
+    And = *(UINT8*) AndData;\r
+  } else if (Count == 2) {\r
+    And = *(UINT16*) AndData;\r
+  } else if (Count == 4) {\r
+    And = *(UINT32*) AndData;\r
+  } else if (Count == 8) {\r
+    And = *(UINT64*) AndData;\r
+  } else {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  Data  &= And;\r
+  Status = SdMmcHcRwMmio (PciIo, BarIndex, Offset, FALSE, Count, &Data);\r
+\r
+  return Status;\r
+}\r
+\r
+/**\r
+  Wait for the value of the specified MMIO register set to the test value.\r
+\r
+  @param[in]  PciIo         The PCI IO protocol instance.\r
+  @param[in]  BarIndex      The BAR index of the standard PCI Configuration\r
+                            header to use as the base address for the memory\r
+                            operation to perform.\r
+  @param[in]  Offset        The offset within the selected BAR to start the\r
+                            memory operation.\r
+  @param[in]  Count         The width of the mmio register in bytes.\r
+                            Must be 1, 2, 4 or 8 bytes.\r
+  @param[in]  MaskValue     The mask value of memory.\r
+  @param[in]  TestValue     The test value of memory.\r
+\r
+  @retval EFI_NOT_READY     The MMIO register hasn't set to the expected value.\r
+  @retval EFI_SUCCESS       The MMIO register has expected value.\r
+  @retval Others            The MMIO operation fails.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+SdMmcHcCheckMmioSet (\r
+  IN  EFI_PCI_IO_PROTOCOL       *PciIo,\r
+  IN  UINT8                     BarIndex,\r
+  IN  UINT32                    Offset,\r
+  IN  UINT8                     Count,\r
+  IN  UINT64                    MaskValue,\r
+  IN  UINT64                    TestValue\r
+  )\r
+{\r
+  EFI_STATUS            Status;\r
+  UINT64                Value;\r
+\r
+  //\r
+  // Access PCI MMIO space to see if the value is the tested one.\r
+  //\r
+  Value  = 0;\r
+  Status = SdMmcHcRwMmio (PciIo, BarIndex, Offset, TRUE, Count, &Value);\r
+  if (EFI_ERROR (Status)) {\r
+    return Status;\r
+  }\r
+\r
+  Value &= MaskValue;\r
+\r
+  if (Value == TestValue) {\r
+    return EFI_SUCCESS;\r
+  }\r
+\r
+  return EFI_NOT_READY;\r
+}\r
+\r
+/**\r
+  Wait for the value of the specified MMIO register set to the test value.\r
+\r
+  @param[in]  PciIo         The PCI IO protocol instance.\r
+  @param[in]  BarIndex      The BAR index of the standard PCI Configuration\r
+                            header to use as the base address for the memory\r
+                            operation to perform.\r
+  @param[in]  Offset        The offset within the selected BAR to start the\r
+                            memory operation.\r
+  @param[in]  Count         The width of the mmio register in bytes.\r
+                            Must be 1, 2, 4 or 8 bytes.\r
+  @param[in]  MaskValue     The mask value of memory.\r
+  @param[in]  TestValue     The test value of memory.\r
+  @param[in]  Timeout       The time out value for wait memory set, uses 1\r
+                            microsecond as a unit.\r
+\r
+  @retval EFI_TIMEOUT       The MMIO register hasn't expected value in timeout\r
+                            range.\r
+  @retval EFI_SUCCESS       The MMIO register has expected value.\r
+  @retval Others            The MMIO operation fails.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+SdMmcHcWaitMmioSet (\r
+  IN  EFI_PCI_IO_PROTOCOL       *PciIo,\r
+  IN  UINT8                     BarIndex,\r
+  IN  UINT32                    Offset,\r
+  IN  UINT8                     Count,\r
+  IN  UINT64                    MaskValue,\r
+  IN  UINT64                    TestValue,\r
+  IN  UINT64                    Timeout\r
+  )\r
+{\r
+  EFI_STATUS            Status;\r
+  BOOLEAN               InfiniteWait;\r
+\r
+  if (Timeout == 0) {\r
+    InfiniteWait = TRUE;\r
+  } else {\r
+    InfiniteWait = FALSE;\r
+  }\r
+\r
+  while (InfiniteWait || (Timeout > 0)) {\r
+    Status = SdMmcHcCheckMmioSet (\r
+               PciIo,\r
+               BarIndex,\r
+               Offset,\r
+               Count,\r
+               MaskValue,\r
+               TestValue\r
+               );\r
+    if (Status != EFI_NOT_READY) {\r
+      return Status;\r
+    }\r
+\r
+    //\r
+    // Stall for 1 microsecond.\r
+    //\r
+    gBS->Stall (1);\r
+\r
+    Timeout--;\r
+  }\r
+\r
+  return EFI_TIMEOUT;\r
+}\r
+\r
+/**\r
+  Software reset the specified SD/MMC host controller and enable all interrupts.\r
+\r
+  @param[in] PciIo          The PCI IO protocol instance.\r
+  @param[in] Slot           The slot number of the SD card to send the command to.\r
+\r
+  @retval EFI_SUCCESS       The software reset executes successfully.\r
+  @retval Others            The software reset fails.\r
+\r
+**/\r
+EFI_STATUS\r
+SdMmcHcReset (\r
+  IN EFI_PCI_IO_PROTOCOL    *PciIo,\r
+  IN UINT8                  Slot\r
+  )\r
+{\r
+  EFI_STATUS                Status;\r
+  UINT8                     SwReset;\r
+\r
+  SwReset = 0xFF;\r
+  Status  = SdMmcHcRwMmio (PciIo, Slot, SD_MMC_HC_SW_RST, FALSE, sizeof (SwReset), &SwReset);\r
+\r
+  if (EFI_ERROR (Status)) {\r
+    DEBUG ((EFI_D_ERROR, "SdMmcHcReset: write full 1 fails: %r\n", Status));\r
+    return Status;\r
+  }\r
+\r
+  Status = SdMmcHcWaitMmioSet (\r
+             PciIo,\r
+             Slot,\r
+             SD_MMC_HC_SW_RST,\r
+             sizeof (SwReset),\r
+             0xFF,\r
+             0x00,\r
+             SD_MMC_HC_GENERIC_TIMEOUT\r
+             );\r
+  if (EFI_ERROR (Status)) {\r
+    DEBUG ((EFI_D_INFO, "SdMmcHcReset: reset done with %r\n", Status));\r
+    return Status;\r
+  }\r
+  //\r
+  // Enable all interrupt after reset all.\r
+  //\r
+  Status = SdMmcHcEnableInterrupt (PciIo, Slot);\r
+\r
+  return Status;\r
+}\r
+\r
+/**\r
+  Set all interrupt status bits in Normal and Error Interrupt Status Enable\r
+  register.\r
+\r
+  @param[in] PciIo          The PCI IO protocol instance.\r
+  @param[in] Slot           The slot number of the SD card to send the command to.\r
+\r
+  @retval EFI_SUCCESS       The operation executes successfully.\r
+  @retval Others            The operation fails.\r
+\r
+**/\r
+EFI_STATUS\r
+SdMmcHcEnableInterrupt (\r
+  IN EFI_PCI_IO_PROTOCOL    *PciIo,\r
+  IN UINT8                  Slot\r
+  )\r
+{\r
+  EFI_STATUS                Status;\r
+  UINT16                    IntStatus;\r
+\r
+  //\r
+  // Enable all bits in Error Interrupt Status Enable Register\r
+  //\r
+  IntStatus = 0xFFFF;\r
+  Status = SdMmcHcRwMmio (PciIo, Slot, SD_MMC_HC_ERR_INT_STS_EN, FALSE, sizeof (IntStatus), &IntStatus);\r
+  if (EFI_ERROR (Status)) {\r
+    return Status;\r
+  }\r
+  //\r
+  // Enable all bits in Normal Interrupt Status Enable Register\r
+  //\r
+  IntStatus = 0xFFFF;\r
+  Status = SdMmcHcRwMmio (PciIo, Slot, SD_MMC_HC_NOR_INT_STS_EN, FALSE, sizeof (IntStatus), &IntStatus);\r
+\r
+  return Status;\r
+}\r
+\r
+/**\r
+  Get the capability data from the specified slot.\r
+\r
+  @param[in]  PciIo           The PCI IO protocol instance.\r
+  @param[in]  Slot            The slot number of the SD card to send the command to.\r
+  @param[out] Capability      The buffer to store the capability data.\r
+\r
+  @retval EFI_SUCCESS         The operation executes successfully.\r
+  @retval Others              The operation fails.\r
+\r
+**/\r
+EFI_STATUS\r
+SdMmcHcGetCapability (\r
+  IN     EFI_PCI_IO_PROTOCOL  *PciIo,\r
+  IN     UINT8                Slot,\r
+     OUT SD_MMC_HC_SLOT_CAP   *Capability\r
+  )\r
+{\r
+  EFI_STATUS                Status;\r
+  UINT64                    Cap;\r
+\r
+  Status = SdMmcHcRwMmio (PciIo, Slot, SD_MMC_HC_CAP, TRUE, sizeof (Cap), &Cap);\r
+  if (EFI_ERROR (Status)) {\r
+    return Status;\r
+  }\r
+\r
+  CopyMem (Capability, &Cap, sizeof (Cap));\r
+\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+  Get the maximum current capability data from the specified slot.\r
+\r
+  @param[in]  PciIo           The PCI IO protocol instance.\r
+  @param[in]  Slot            The slot number of the SD card to send the command to.\r
+  @param[out] MaxCurrent      The buffer to store the maximum current capability data.\r
+\r
+  @retval EFI_SUCCESS         The operation executes successfully.\r
+  @retval Others              The operation fails.\r
+\r
+**/\r
+EFI_STATUS\r
+SdMmcHcGetMaxCurrent (\r
+  IN     EFI_PCI_IO_PROTOCOL  *PciIo,\r
+  IN     UINT8                Slot,\r
+     OUT UINT64               *MaxCurrent\r
+  )\r
+{\r
+  EFI_STATUS          Status;\r
+\r
+  Status = SdMmcHcRwMmio (PciIo, Slot, SD_MMC_HC_MAX_CURRENT_CAP, TRUE, sizeof (UINT64), MaxCurrent);\r
+\r
+  return Status;\r
+}\r
+\r
+/**\r
+  Detect whether there is a SD/MMC card attached at the specified SD/MMC host controller\r
+  slot.\r
+\r
+  Refer to SD Host Controller Simplified spec 3.0 Section 3.1 for details.\r
+\r
+  @param[in]  PciIo         The PCI IO protocol instance.\r
+  @param[in]  Slot          The slot number of the SD card to send the command to.\r
+  @param[out] MediaPresent  The pointer to the media present boolean value.\r
+\r
+  @retval EFI_SUCCESS       There is no media change happened.\r
+  @retval EFI_MEDIA_CHANGED There is media change happened.\r
+  @retval Others            The detection fails.\r
+\r
+**/\r
+EFI_STATUS\r
+SdMmcHcCardDetect (\r
+  IN EFI_PCI_IO_PROTOCOL    *PciIo,\r
+  IN UINT8                  Slot,\r
+     OUT BOOLEAN            *MediaPresent\r
+  )\r
+{\r
+  EFI_STATUS                Status;\r
+  UINT16                    Data;\r
+  UINT32                    PresentState;\r
+\r
+  //\r
+  // Check Normal Interrupt Status Register\r
+  //\r
+  Status = SdMmcHcRwMmio (PciIo, Slot, SD_MMC_HC_NOR_INT_STS, TRUE, sizeof (Data), &Data);\r
+  if (EFI_ERROR (Status)) {\r
+    return Status;\r
+  }\r
+\r
+  if ((Data & (BIT6 | BIT7)) != 0) {\r
+    //\r
+    // Clear BIT6 and BIT7 by writing 1 to these two bits if set.\r
+    //\r
+    Data  &= BIT6 | BIT7;\r
+    Status = SdMmcHcRwMmio (PciIo, Slot, SD_MMC_HC_NOR_INT_STS, FALSE, sizeof (Data), &Data);\r
+    if (EFI_ERROR (Status)) {\r
+      return Status;\r
+    }\r
+\r
+    //\r
+    // Check Present State Register to see if there is a card presented.\r
+    //\r
+    Status = SdMmcHcRwMmio (PciIo, Slot, SD_MMC_HC_PRESENT_STATE, TRUE, sizeof (PresentState), &PresentState);\r
+    if (EFI_ERROR (Status)) {\r
+      return Status;\r
+    }\r
+\r
+    if ((PresentState & BIT16) != 0) {\r
+      *MediaPresent = TRUE;\r
+    } else {\r
+      *MediaPresent = FALSE;\r
+    }\r
+    return EFI_MEDIA_CHANGED;\r
+  }\r
+\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+  Stop SD/MMC card clock.\r
+\r
+  Refer to SD Host Controller Simplified spec 3.0 Section 3.2.2 for details.\r
+\r
+  @param[in] PciIo          The PCI IO protocol instance.\r
+  @param[in] Slot           The slot number of the SD card to send the command to.\r
+\r
+  @retval EFI_SUCCESS       Succeed to stop SD/MMC clock.\r
+  @retval Others            Fail to stop SD/MMC clock.\r
+\r
+**/\r
+EFI_STATUS\r
+SdMmcHcStopClock (\r
+  IN EFI_PCI_IO_PROTOCOL    *PciIo,\r
+  IN UINT8                  Slot\r
+  )\r
+{\r
+  EFI_STATUS                Status;\r
+  UINT32                    PresentState;\r
+  UINT16                    ClockCtrl;\r
+\r
+  //\r
+  // Ensure no SD transactions are occurring on the SD Bus by\r
+  // waiting for Command Inhibit (DAT) and Command Inhibit (CMD)\r
+  // in the Present State register to be 0.\r
+  //\r
+  Status = SdMmcHcWaitMmioSet (\r
+             PciIo,\r
+             Slot,\r
+             SD_MMC_HC_PRESENT_STATE,\r
+             sizeof (PresentState),\r
+             BIT0 | BIT1,\r
+             0,\r
+             SD_MMC_HC_GENERIC_TIMEOUT\r
+             );\r
+  if (EFI_ERROR (Status)) {\r
+    return Status;\r
+  }\r
+\r
+  //\r
+  // Set SD Clock Enable in the Clock Control register to 0\r
+  //\r
+  ClockCtrl = (UINT16)~BIT2;\r
+  Status = SdMmcHcAndMmio (PciIo, Slot, SD_MMC_HC_CLOCK_CTRL, sizeof (ClockCtrl), &ClockCtrl);\r
+\r
+  return Status;\r
+}\r
+\r
+/**\r
+  SD/MMC card clock supply.\r
+\r
+  Refer to SD Host Controller Simplified spec 3.0 Section 3.2.1 for details.\r
+\r
+  @param[in] PciIo          The PCI IO protocol instance.\r
+  @param[in] Slot           The slot number of the SD card to send the command to.\r
+  @param[in] ClockFreq      The max clock frequency to be set. The unit is KHz.\r
+  @param[in] Capability     The capability of the slot.\r
+\r
+  @retval EFI_SUCCESS       The clock is supplied successfully.\r
+  @retval Others            The clock isn't supplied successfully.\r
+\r
+**/\r
+EFI_STATUS\r
+SdMmcHcClockSupply (\r
+  IN EFI_PCI_IO_PROTOCOL    *PciIo,\r
+  IN UINT8                  Slot,\r
+  IN UINT64                 ClockFreq,\r
+  IN SD_MMC_HC_SLOT_CAP     Capability\r
+  )\r
+{\r
+  EFI_STATUS                Status;\r
+  UINT32                    BaseClkFreq;\r
+  UINT32                    SettingFreq;\r
+  UINT32                    Divisor;\r
+  UINT32                    Remainder;\r
+  UINT16                    ControllerVer;\r
+  UINT16                    ClockCtrl;\r
+\r
+  //\r
+  // Calculate a divisor for SD clock frequency\r
+  //\r
+  ASSERT (Capability.BaseClkFreq != 0);\r
+\r
+  BaseClkFreq = Capability.BaseClkFreq;\r
+  if ((ClockFreq > (BaseClkFreq * 1000)) || (ClockFreq == 0)) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+  //\r
+  // Calculate the divisor of base frequency.\r
+  //\r
+  Divisor     = 0;\r
+  SettingFreq = BaseClkFreq * 1000;\r
+  while (ClockFreq < SettingFreq) {\r
+    Divisor++;\r
+\r
+    SettingFreq = (BaseClkFreq * 1000) / (2 * Divisor);\r
+    Remainder   = (BaseClkFreq * 1000) % (2 * Divisor);\r
+    if ((ClockFreq == SettingFreq) && (Remainder == 0)) {\r
+      break;\r
+    }\r
+    if ((ClockFreq == SettingFreq) && (Remainder != 0)) {\r
+      SettingFreq ++;\r
+    }\r
+  }\r
+\r
+  DEBUG ((EFI_D_INFO, "BaseClkFreq %dMHz Divisor %d ClockFreq %dKhz\n", BaseClkFreq, Divisor, ClockFreq));\r
+\r
+  Status = SdMmcHcRwMmio (PciIo, Slot, SD_MMC_HC_CTRL_VER, TRUE, sizeof (ControllerVer), &ControllerVer);\r
+  if (EFI_ERROR (Status)) {\r
+    return Status;\r
+  }\r
+  //\r
+  // Set SDCLK Frequency Select and Internal Clock Enable fields in Clock Control register.\r
+  //\r
+  if ((ControllerVer & 0xFF) == 2) {\r
+    ASSERT (Divisor <= 0x3FF);\r
+    ClockCtrl = ((Divisor & 0xFF) << 8) | ((Divisor & 0x300) >> 2);\r
+  } else if (((ControllerVer & 0xFF) == 0) || ((ControllerVer & 0xFF) == 1)) {\r
+    //\r
+    // Only the most significant bit can be used as divisor.\r
+    //\r
+    if (((Divisor - 1) & Divisor) != 0) {\r
+      Divisor = 1 << (HighBitSet32 (Divisor) + 1);\r
+    }\r
+    ASSERT (Divisor <= 0x80);\r
+    ClockCtrl = (Divisor & 0xFF) << 8;\r
+  } else {\r
+    DEBUG ((EFI_D_ERROR, "Unknown SD Host Controller Spec version [0x%x]!!!\n", ControllerVer));\r
+    return EFI_UNSUPPORTED;\r
+  }\r
+\r
+  //\r
+  // Stop bus clock at first\r
+  //\r
+  Status = SdMmcHcStopClock (PciIo, Slot);\r
+  if (EFI_ERROR (Status)) {\r
+    return Status;\r
+  }\r
+\r
+  //\r
+  // Supply clock frequency with specified divisor\r
+  //\r
+  ClockCtrl |= BIT0;\r
+  Status = SdMmcHcRwMmio (PciIo, Slot, SD_MMC_HC_CLOCK_CTRL, FALSE, sizeof (ClockCtrl), &ClockCtrl);\r
+  if (EFI_ERROR (Status)) {\r
+    DEBUG ((EFI_D_ERROR, "Set SDCLK Frequency Select and Internal Clock Enable fields fails\n"));\r
+    return Status;\r
+  }\r
+\r
+  //\r
+  // Wait Internal Clock Stable in the Clock Control register to be 1\r
+  //\r
+  Status = SdMmcHcWaitMmioSet (\r
+             PciIo,\r
+             Slot,\r
+             SD_MMC_HC_CLOCK_CTRL,\r
+             sizeof (ClockCtrl),\r
+             BIT1,\r
+             BIT1,\r
+             SD_MMC_HC_GENERIC_TIMEOUT\r
+             );\r
+  if (EFI_ERROR (Status)) {\r
+    return Status;\r
+  }\r
+\r
+  //\r
+  // Set SD Clock Enable in the Clock Control register to 1\r
+  //\r
+  ClockCtrl = BIT2;\r
+  Status = SdMmcHcOrMmio (PciIo, Slot, SD_MMC_HC_CLOCK_CTRL, sizeof (ClockCtrl), &ClockCtrl);\r
+\r
+  return Status;\r
+}\r
+\r
+/**\r
+  SD/MMC bus power control.\r
+\r
+  Refer to SD Host Controller Simplified spec 3.0 Section 3.3 for details.\r
+\r
+  @param[in] PciIo          The PCI IO protocol instance.\r
+  @param[in] Slot           The slot number of the SD card to send the command to.\r
+  @param[in] PowerCtrl      The value setting to the power control register.\r
+\r
+  @retval TRUE              There is a SD/MMC card attached.\r
+  @retval FALSE             There is no a SD/MMC card attached.\r
+\r
+**/\r
+EFI_STATUS\r
+SdMmcHcPowerControl (\r
+  IN EFI_PCI_IO_PROTOCOL    *PciIo,\r
+  IN UINT8                  Slot,\r
+  IN UINT8                  PowerCtrl\r
+  )\r
+{\r
+  EFI_STATUS                Status;\r
+\r
+  //\r
+  // Clr SD Bus Power\r
+  //\r
+  PowerCtrl &= (UINT8)~BIT0;\r
+  Status = SdMmcHcRwMmio (PciIo, Slot, SD_MMC_HC_POWER_CTRL, FALSE, sizeof (PowerCtrl), &PowerCtrl);\r
+  if (EFI_ERROR (Status)) {\r
+    return Status;\r
+  }\r
+\r
+  //\r
+  // Set SD Bus Voltage Select and SD Bus Power fields in Power Control Register\r
+  //\r
+  PowerCtrl |= BIT0;\r
+  Status = SdMmcHcRwMmio (PciIo, Slot, SD_MMC_HC_POWER_CTRL, FALSE, sizeof (PowerCtrl), &PowerCtrl);\r
+\r
+  return Status;\r
+}\r
+\r
+/**\r
+  Set the SD/MMC bus width.\r
+\r
+  Refer to SD Host Controller Simplified spec 3.0 Section 3.4 for details.\r
+\r
+  @param[in] PciIo          The PCI IO protocol instance.\r
+  @param[in] Slot           The slot number of the SD card to send the command to.\r
+  @param[in] BusWidth       The bus width used by the SD/MMC device, it must be 1, 4 or 8.\r
+\r
+  @retval EFI_SUCCESS       The bus width is set successfully.\r
+  @retval Others            The bus width isn't set successfully.\r
+\r
+**/\r
+EFI_STATUS\r
+SdMmcHcSetBusWidth (\r
+  IN EFI_PCI_IO_PROTOCOL    *PciIo,\r
+  IN UINT8                  Slot,\r
+  IN UINT16                 BusWidth\r
+  )\r
+{\r
+  EFI_STATUS                Status;\r
+  UINT8                     HostCtrl1;\r
+\r
+  if (BusWidth == 1) {\r
+    HostCtrl1 = (UINT8)~(BIT5 | BIT1);\r
+    Status = SdMmcHcAndMmio (PciIo, Slot, SD_MMC_HC_HOST_CTRL1, sizeof (HostCtrl1), &HostCtrl1);\r
+  } else if (BusWidth == 4) {\r
+    Status = SdMmcHcRwMmio (PciIo, Slot, SD_MMC_HC_HOST_CTRL1, TRUE, sizeof (HostCtrl1), &HostCtrl1);\r
+    if (EFI_ERROR (Status)) {\r
+      return Status;\r
+    }\r
+    HostCtrl1 |= BIT1;\r
+    HostCtrl1 &= (UINT8)~BIT5;\r
+    Status = SdMmcHcRwMmio (PciIo, Slot, SD_MMC_HC_HOST_CTRL1, FALSE, sizeof (HostCtrl1), &HostCtrl1);\r
+  } else if (BusWidth == 8) {\r
+    Status = SdMmcHcRwMmio (PciIo, Slot, SD_MMC_HC_HOST_CTRL1, TRUE, sizeof (HostCtrl1), &HostCtrl1);\r
+    if (EFI_ERROR (Status)) {\r
+      return Status;\r
+    }\r
+    HostCtrl1 &= (UINT8)~BIT1;\r
+    HostCtrl1 |= BIT5;\r
+    Status = SdMmcHcRwMmio (PciIo, Slot, SD_MMC_HC_HOST_CTRL1, FALSE, sizeof (HostCtrl1), &HostCtrl1);\r
+  } else {\r
+    ASSERT (FALSE);\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  return Status;\r
+}\r
+\r
+/**\r
+  Supply SD/MMC card with lowest clock frequency at initialization.\r
+\r
+  @param[in] PciIo          The PCI IO protocol instance.\r
+  @param[in] Slot           The slot number of the SD card to send the command to.\r
+  @param[in] Capability     The capability of the slot.\r
+\r
+  @retval EFI_SUCCESS       The clock is supplied successfully.\r
+  @retval Others            The clock isn't supplied successfully.\r
+\r
+**/\r
+EFI_STATUS\r
+SdMmcHcInitClockFreq (\r
+  IN EFI_PCI_IO_PROTOCOL    *PciIo,\r
+  IN UINT8                  Slot,\r
+  IN SD_MMC_HC_SLOT_CAP     Capability\r
+  )\r
+{\r
+  EFI_STATUS                Status;\r
+  UINT32                    InitFreq;\r
+\r
+  //\r
+  // Calculate a divisor for SD clock frequency\r
+  //\r
+  if (Capability.BaseClkFreq == 0) {\r
+    //\r
+    // Don't support get Base Clock Frequency information via another method\r
+    //\r
+    return EFI_UNSUPPORTED;\r
+  }\r
+  //\r
+  // Supply 400KHz clock frequency at initialization phase.\r
+  //\r
+  InitFreq = 400;\r
+  Status = SdMmcHcClockSupply (PciIo, Slot, InitFreq, Capability);\r
+  return Status;\r
+}\r
+\r
+/**\r
+  Supply SD/MMC card with maximum voltage at initialization.\r
+\r
+  Refer to SD Host Controller Simplified spec 3.0 Section 3.3 for details.\r
+\r
+  @param[in] PciIo          The PCI IO protocol instance.\r
+  @param[in] Slot           The slot number of the SD card to send the command to.\r
+  @param[in] Capability     The capability of the slot.\r
+\r
+  @retval EFI_SUCCESS       The voltage is supplied successfully.\r
+  @retval Others            The voltage isn't supplied successfully.\r
+\r
+**/\r
+EFI_STATUS\r
+SdMmcHcInitPowerVoltage (\r
+  IN EFI_PCI_IO_PROTOCOL    *PciIo,\r
+  IN UINT8                  Slot,\r
+  IN SD_MMC_HC_SLOT_CAP     Capability\r
+  )\r
+{\r
+  EFI_STATUS                Status;\r
+  UINT8                     MaxVoltage;\r
+  UINT8                     HostCtrl2;\r
+\r
+  //\r
+  // Calculate supported maximum voltage according to SD Bus Voltage Select\r
+  //\r
+  if (Capability.Voltage33 != 0) {\r
+    //\r
+    // Support 3.3V\r
+    //\r
+    MaxVoltage = 0x0E;\r
+  } else if (Capability.Voltage30 != 0) {\r
+    //\r
+    // Support 3.0V\r
+    //\r
+    MaxVoltage = 0x0C;\r
+  } else if (Capability.Voltage18 != 0) {\r
+    //\r
+    // Support 1.8V\r
+    //\r
+    MaxVoltage = 0x0A;\r
+    HostCtrl2  = BIT3;\r
+    Status = SdMmcHcOrMmio (PciIo, Slot, SD_MMC_HC_HOST_CTRL2, sizeof (HostCtrl2), &HostCtrl2);\r
+    gBS->Stall (5000);\r
+    if (EFI_ERROR (Status)) {\r
+      return Status;\r
+    }\r
+  } else {\r
+    ASSERT (FALSE);\r
+    return EFI_DEVICE_ERROR;\r
+  }\r
+\r
+  //\r
+  // Set SD Bus Voltage Select and SD Bus Power fields in Power Control Register\r
+  //\r
+  Status = SdMmcHcPowerControl (PciIo, Slot, MaxVoltage);\r
+\r
+  return Status;\r
+}\r
+\r
+/**\r
+  Initialize the Timeout Control register with most conservative value at initialization.\r
+\r
+  Refer to SD Host Controller Simplified spec 3.0 Section 2.2.15 for details.\r
+\r
+  @param[in] PciIo          The PCI IO protocol instance.\r
+  @param[in] Slot           The slot number of the SD card to send the command to.\r
+\r
+  @retval EFI_SUCCESS       The timeout control register is configured successfully.\r
+  @retval Others            The timeout control register isn't configured successfully.\r
+\r
+**/\r
+EFI_STATUS\r
+SdMmcHcInitTimeoutCtrl (\r
+  IN EFI_PCI_IO_PROTOCOL    *PciIo,\r
+  IN UINT8                  Slot\r
+  )\r
+{\r
+  EFI_STATUS                Status;\r
+  UINT8                     Timeout;\r
+\r
+  Timeout = 0x0E;\r
+  Status  = SdMmcHcRwMmio (PciIo, Slot, SD_MMC_HC_TIMEOUT_CTRL, FALSE, sizeof (Timeout), &Timeout);\r
+\r
+  return Status;\r
+}\r
+\r
+/**\r
+  Initial SD/MMC host controller with lowest clock frequency, max power and max timeout value\r
+  at initialization.\r
+\r
+  @param[in] PciIo          The PCI IO protocol instance.\r
+  @param[in] Slot           The slot number of the SD card to send the command to.\r
+  @param[in] Capability     The capability of the slot.\r
+\r
+  @retval EFI_SUCCESS       The host controller is initialized successfully.\r
+  @retval Others            The host controller isn't initialized successfully.\r
+\r
+**/\r
+EFI_STATUS\r
+SdMmcHcInitHost (\r
+  IN EFI_PCI_IO_PROTOCOL    *PciIo,\r
+  IN UINT8                  Slot,\r
+  IN SD_MMC_HC_SLOT_CAP     Capability\r
+  )\r
+{\r
+  EFI_STATUS       Status;\r
+\r
+  Status = SdMmcHcInitClockFreq (PciIo, Slot, Capability);\r
+  if (EFI_ERROR (Status)) {\r
+    return Status;\r
+  }\r
+\r
+  Status = SdMmcHcInitPowerVoltage (PciIo, Slot, Capability);\r
+  if (EFI_ERROR (Status)) {\r
+    return Status;\r
+  }\r
+\r
+  Status = SdMmcHcInitTimeoutCtrl (PciIo, Slot);\r
+  return Status;\r
+}\r
+\r
+/**\r
+  Turn on/off LED.\r
+\r
+  @param[in] PciIo          The PCI IO protocol instance.\r
+  @param[in] Slot           The slot number of the SD card to send the command to.\r
+  @param[in] On             The boolean to turn on/off LED.\r
+\r
+  @retval EFI_SUCCESS       The LED is turned on/off successfully.\r
+  @retval Others            The LED isn't turned on/off successfully.\r
+\r
+**/\r
+EFI_STATUS\r
+SdMmcHcLedOnOff (\r
+  IN EFI_PCI_IO_PROTOCOL    *PciIo,\r
+  IN UINT8                  Slot,\r
+  IN BOOLEAN                On\r
+  )\r
+{\r
+  EFI_STATUS                Status;\r
+  UINT8                     HostCtrl1;\r
+\r
+  if (On) {\r
+    HostCtrl1 = BIT0;\r
+    Status    = SdMmcHcOrMmio (PciIo, Slot, SD_MMC_HC_HOST_CTRL1, sizeof (HostCtrl1), &HostCtrl1);\r
+  } else {\r
+    HostCtrl1 = (UINT8)~BIT0;\r
+    Status    = SdMmcHcAndMmio (PciIo, Slot, SD_MMC_HC_HOST_CTRL1, sizeof (HostCtrl1), &HostCtrl1);\r
+  }\r
+\r
+  return Status;\r
+}\r
+\r
+/**\r
+  Build ADMA descriptor table for transfer.\r
+\r
+  Refer to SD Host Controller Simplified spec 3.0 Section 1.13 for details.\r
+\r
+  @param[in] Trb            The pointer to the SD_MMC_HC_TRB instance.\r
+\r
+  @retval EFI_SUCCESS       The ADMA descriptor table is created successfully.\r
+  @retval Others            The ADMA descriptor table isn't created successfully.\r
+\r
+**/\r
+EFI_STATUS\r
+BuildAdmaDescTable (\r
+  IN SD_MMC_HC_TRB          *Trb\r
+  )\r
+{\r
+  EFI_PHYSICAL_ADDRESS      Data;\r
+  UINT64                    DataLen;\r
+  UINT64                    Entries;\r
+  UINT32                    Index;\r
+  UINT64                    Remaining;\r
+  UINT32                    Address;\r
+  UINTN                     TableSize;\r
+  EFI_PCI_IO_PROTOCOL       *PciIo;\r
+  EFI_STATUS                Status;\r
+  UINTN                     Bytes;\r
+\r
+  Data    = Trb->DataPhy;\r
+  DataLen = Trb->DataLen;\r
+  PciIo   = Trb->Private->PciIo;\r
+  //\r
+  // Only support 32bit ADMA Descriptor Table\r
+  //\r
+  if ((Data >= 0x100000000ul) || ((Data + DataLen) > 0x100000000ul)) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+  //\r
+  // Address field shall be set on 32-bit boundary (Lower 2-bit is always set to 0)\r
+  // for 32-bit address descriptor table.\r
+  //\r
+  if ((Data & (BIT0 | BIT1)) != 0) {\r
+    DEBUG ((EFI_D_INFO, "The buffer [0x%x] to construct ADMA desc is not aligned to 4 bytes boundary!\n", Data));\r
+  }\r
+\r
+  Entries   = DivU64x32 ((DataLen + ADMA_MAX_DATA_PER_LINE - 1), ADMA_MAX_DATA_PER_LINE);\r
+  TableSize = (UINTN)MultU64x32 (Entries, sizeof (SD_MMC_HC_ADMA_DESC_LINE));\r
+  Trb->AdmaPages = (UINT32)EFI_SIZE_TO_PAGES (TableSize);\r
+  Status = PciIo->AllocateBuffer (\r
+                    PciIo,\r
+                    AllocateAnyPages,\r
+                    EfiBootServicesData,\r
+                    EFI_SIZE_TO_PAGES (TableSize),\r
+                    (VOID **)&Trb->AdmaDesc,\r
+                    0\r
+                    );\r
+  if (EFI_ERROR (Status)) {\r
+    return EFI_OUT_OF_RESOURCES;\r
+  }\r
+  ZeroMem (Trb->AdmaDesc, TableSize);\r
+  Bytes  = TableSize;\r
+  Status = PciIo->Map (\r
+                    PciIo,\r
+                    EfiPciIoOperationBusMasterCommonBuffer,\r
+                    Trb->AdmaDesc,\r
+                    &Bytes,\r
+                    &Trb->AdmaDescPhy,\r
+                    &Trb->AdmaMap\r
+                    );\r
+\r
+  if (EFI_ERROR (Status) || (Bytes != TableSize)) {\r
+    //\r
+    // Map error or unable to map the whole RFis buffer into a contiguous region.\r
+    //\r
+    PciIo->FreeBuffer (\r
+             PciIo,\r
+             EFI_SIZE_TO_PAGES (TableSize),\r
+             Trb->AdmaDesc\r
+             );\r
+    return EFI_OUT_OF_RESOURCES;\r
+  }\r
+\r
+  if ((UINT64)(UINTN)Trb->AdmaDescPhy > 0x100000000ul) {\r
+    //\r
+    // The ADMA doesn't support 64bit addressing.\r
+    //\r
+    PciIo->Unmap (\r
+      PciIo,\r
+      Trb->AdmaMap\r
+    );\r
+    PciIo->FreeBuffer (\r
+      PciIo,\r
+      EFI_SIZE_TO_PAGES (TableSize),\r
+      Trb->AdmaDesc\r
+    );\r
+    return EFI_DEVICE_ERROR;\r
+  }\r
+\r
+  Remaining = DataLen;\r
+  Address   = (UINT32)Data;\r
+  for (Index = 0; Index < Entries; Index++) {\r
+    if (Remaining <= ADMA_MAX_DATA_PER_LINE) {\r
+      Trb->AdmaDesc[Index].Valid = 1;\r
+      Trb->AdmaDesc[Index].Act   = 2;\r
+      Trb->AdmaDesc[Index].Length  = (UINT16)Remaining;\r
+      Trb->AdmaDesc[Index].Address = Address;\r
+      break;\r
+    } else {\r
+      Trb->AdmaDesc[Index].Valid = 1;\r
+      Trb->AdmaDesc[Index].Act   = 2;\r
+      Trb->AdmaDesc[Index].Length  = 0;\r
+      Trb->AdmaDesc[Index].Address = Address;\r
+    }\r
+\r
+    Remaining -= ADMA_MAX_DATA_PER_LINE;\r
+    Address   += ADMA_MAX_DATA_PER_LINE;\r
+  }\r
+\r
+  //\r
+  // Set the last descriptor line as end of descriptor table\r
+  //\r
+  Trb->AdmaDesc[Index].End = 1;\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+  Create a new TRB for the SD/MMC cmd request.\r
+\r
+  @param[in] Private        A pointer to the SD_MMC_HC_PRIVATE_DATA instance.\r
+  @param[in] Slot           The slot number of the SD card to send the command to.\r
+  @param[in] Packet         A pointer to the SD command data structure.\r
+  @param[in] Event          If Event is NULL, blocking I/O is performed. If Event is\r
+                            not NULL, then nonblocking I/O is performed, and Event\r
+                            will be signaled when the Packet completes.\r
+\r
+  @return Created Trb or NULL.\r
+\r
+**/\r
+SD_MMC_HC_TRB *\r
+SdMmcCreateTrb (\r
+  IN SD_MMC_HC_PRIVATE_DATA              *Private,\r
+  IN UINT8                               Slot,\r
+  IN EFI_SD_MMC_PASS_THRU_COMMAND_PACKET *Packet,\r
+  IN EFI_EVENT                           Event\r
+  )\r
+{\r
+  SD_MMC_HC_TRB                 *Trb;\r
+  EFI_STATUS                    Status;\r
+  EFI_TPL                       OldTpl;\r
+  EFI_PCI_IO_PROTOCOL_OPERATION Flag;\r
+  EFI_PCI_IO_PROTOCOL           *PciIo;\r
+  UINTN                         MapLength;\r
+\r
+  Trb = AllocateZeroPool (sizeof (SD_MMC_HC_TRB));\r
+  if (Trb == NULL) {\r
+    return NULL;\r
+  }\r
+\r
+  Trb->Signature = SD_MMC_HC_TRB_SIG;\r
+  Trb->Slot      = Slot;\r
+  Trb->BlockSize = 0x200;\r
+  Trb->Packet    = Packet;\r
+  Trb->Event     = Event;\r
+  Trb->Started   = FALSE;\r
+  Trb->Timeout   = Packet->Timeout;\r
+  Trb->Private   = Private;\r
+\r
+  if ((Packet->InTransferLength != 0) && (Packet->InDataBuffer != NULL)) {\r
+    Trb->Data    = Packet->InDataBuffer;\r
+    Trb->DataLen = Packet->InTransferLength;\r
+    Trb->Read    = TRUE;\r
+  } else if ((Packet->OutTransferLength != 0) && (Packet->OutDataBuffer != NULL)) {\r
+    Trb->Data    = Packet->OutDataBuffer;\r
+    Trb->DataLen = Packet->OutTransferLength;\r
+    Trb->Read    = FALSE;\r
+  } else if ((Packet->InTransferLength == 0) && (Packet->OutTransferLength == 0)) {\r
+    Trb->Data    = NULL;\r
+    Trb->DataLen = 0;\r
+  } else {\r
+    goto Error;\r
+  }\r
+\r
+  if (Trb->Read) {\r
+    Flag = EfiPciIoOperationBusMasterWrite;\r
+  } else {\r
+    Flag = EfiPciIoOperationBusMasterRead;\r
+  }\r
+\r
+  PciIo = Private->PciIo;\r
+  if (Trb->DataLen != 0) {\r
+    MapLength = Trb->DataLen;\r
+    Status = PciIo->Map (\r
+                      PciIo,\r
+                      Flag,\r
+                      Trb->Data,\r
+                      &MapLength,\r
+                      &Trb->DataPhy,\r
+                      &Trb->DataMap\r
+                      );\r
+    if (EFI_ERROR (Status) || (Trb->DataLen != MapLength)) {\r
+      Status = EFI_BAD_BUFFER_SIZE;\r
+      goto Error;\r
+    }\r
+  }\r
+\r
+  if ((Trb->DataLen % Trb->BlockSize) != 0) {\r
+    if (Trb->DataLen < Trb->BlockSize) {\r
+      Trb->BlockSize = (UINT16)Trb->DataLen;\r
+    }\r
+  }\r
+\r
+  if (Trb->DataLen == 0) {\r
+    Trb->Mode = SdMmcNoData;\r
+  } else if (Private->Capability[Slot].Adma2 != 0) {\r
+    Trb->Mode = SdMmcAdmaMode;\r
+    Status = BuildAdmaDescTable (Trb);\r
+    if (EFI_ERROR (Status)) {\r
+      PciIo->Unmap (PciIo, Trb->DataMap);\r
+      goto Error;\r
+    }\r
+  } else if (Private->Capability[Slot].Sdma != 0) {\r
+    Trb->Mode = SdMmcSdmaMode;\r
+  } else {\r
+    Trb->Mode = SdMmcPioMode;\r
+  }\r
+\r
+  if (Event != NULL) {\r
+    OldTpl = gBS->RaiseTPL (TPL_CALLBACK);\r
+    InsertTailList (&Private->Queue, &Trb->TrbList);\r
+    gBS->RestoreTPL (OldTpl);\r
+  }\r
+\r
+  return Trb;\r
+\r
+Error:\r
+  SdMmcFreeTrb (Trb);\r
+  return NULL;\r
+}\r
+\r
+/**\r
+  Free the resource used by the TRB.\r
+\r
+  @param[in] Trb            The pointer to the SD_MMC_HC_TRB instance.\r
+\r
+**/\r
+VOID\r
+SdMmcFreeTrb (\r
+  IN SD_MMC_HC_TRB           *Trb\r
+  )\r
+{\r
+  EFI_PCI_IO_PROTOCOL        *PciIo;\r
+\r
+  PciIo = Trb->Private->PciIo;\r
+\r
+  if (Trb->AdmaMap != NULL) {\r
+    PciIo->Unmap (\r
+      PciIo,\r
+      Trb->AdmaMap\r
+    );\r
+  }\r
+  if (Trb->AdmaDesc != NULL) {\r
+    PciIo->FreeBuffer (\r
+      PciIo,\r
+      Trb->AdmaPages,\r
+      Trb->AdmaDesc\r
+    );\r
+  }\r
+  if (Trb->DataMap != NULL) {\r
+    PciIo->Unmap (\r
+      PciIo,\r
+      Trb->DataMap\r
+    );\r
+  }\r
+  FreePool (Trb);\r
+  return;\r
+}\r
+\r
+/**\r
+  Check if the env is ready for execute specified TRB.\r
+\r
+  @param[in] Private        A pointer to the SD_MMC_HC_PRIVATE_DATA instance.\r
+  @param[in] Trb            The pointer to the SD_MMC_HC_TRB instance.\r
+\r
+  @retval EFI_SUCCESS       The env is ready for TRB execution.\r
+  @retval EFI_NOT_READY     The env is not ready for TRB execution.\r
+  @retval Others            Some erros happen.\r
+\r
+**/\r
+EFI_STATUS\r
+SdMmcCheckTrbEnv (\r
+  IN SD_MMC_HC_PRIVATE_DATA           *Private,\r
+  IN SD_MMC_HC_TRB                    *Trb\r
+  )\r
+{\r
+  EFI_STATUS                          Status;\r
+  EFI_SD_MMC_PASS_THRU_COMMAND_PACKET *Packet;\r
+  EFI_PCI_IO_PROTOCOL                 *PciIo;\r
+  UINT32                              PresentState;\r
+\r
+  Packet = Trb->Packet;\r
+\r
+  if ((Packet->SdMmcCmdBlk->CommandType == SdMmcCommandTypeAdtc) ||\r
+      (Packet->SdMmcCmdBlk->ResponseType == SdMmcResponseTypeR1b) ||\r
+      (Packet->SdMmcCmdBlk->ResponseType == SdMmcResponseTypeR5b)) {\r
+    //\r
+    // Wait Command Inhibit (CMD) and Command Inhibit (DAT) in\r
+    // the Present State register to be 0\r
+    //\r
+    PresentState = BIT0 | BIT1;\r
+    //\r
+    // For Send Tuning Block cmd, just wait for Command Inhibit (CMD) to be 0\r
+    //\r
+    if (((Private->Slot[Trb->Slot].CardType == EmmcCardType) &&\r
+         (Packet->SdMmcCmdBlk->CommandIndex == EMMC_SEND_TUNING_BLOCK)) ||\r
+        ((Private->Slot[Trb->Slot].CardType == SdCardType) &&\r
+         (Packet->SdMmcCmdBlk->CommandIndex == SD_SEND_TUNING_BLOCK))) {\r
+      PresentState = BIT0;\r
+    }\r
+  } else {\r
+    //\r
+    // Wait Command Inhibit (CMD) in the Present State register\r
+    // to be 0\r
+    //\r
+    PresentState = BIT0;\r
+  }\r
+\r
+  PciIo  = Private->PciIo;\r
+  Status = SdMmcHcCheckMmioSet (\r
+             PciIo,\r
+             Trb->Slot,\r
+             SD_MMC_HC_PRESENT_STATE,\r
+             sizeof (PresentState),\r
+             PresentState,\r
+             0\r
+             );\r
+\r
+  return Status;\r
+}\r
+\r
+/**\r
+  Wait for the env to be ready for execute specified TRB.\r
+\r
+  @param[in] Private        A pointer to the SD_MMC_HC_PRIVATE_DATA instance.\r
+  @param[in] Trb            The pointer to the SD_MMC_HC_TRB instance.\r
+\r
+  @retval EFI_SUCCESS       The env is ready for TRB execution.\r
+  @retval EFI_TIMEOUT       The env is not ready for TRB execution in time.\r
+  @retval Others            Some erros happen.\r
+\r
+**/\r
+EFI_STATUS\r
+SdMmcWaitTrbEnv (\r
+  IN SD_MMC_HC_PRIVATE_DATA           *Private,\r
+  IN SD_MMC_HC_TRB                    *Trb\r
+  )\r
+{\r
+  EFI_STATUS                          Status;\r
+  EFI_SD_MMC_PASS_THRU_COMMAND_PACKET *Packet;\r
+  UINT64                              Timeout;\r
+  BOOLEAN                             InfiniteWait;\r
+\r
+  //\r
+  // Wait Command Complete Interrupt Status bit in Normal Interrupt Status Register\r
+  //\r
+  Packet  = Trb->Packet;\r
+  Timeout = Packet->Timeout;\r
+  if (Timeout == 0) {\r
+    InfiniteWait = TRUE;\r
+  } else {\r
+    InfiniteWait = FALSE;\r
+  }\r
+\r
+  while (InfiniteWait || (Timeout > 0)) {\r
+    //\r
+    // Check Trb execution result by reading Normal Interrupt Status register.\r
+    //\r
+    Status = SdMmcCheckTrbEnv (Private, Trb);\r
+    if (Status != EFI_NOT_READY) {\r
+      return Status;\r
+    }\r
+    //\r
+    // Stall for 1 microsecond.\r
+    //\r
+    gBS->Stall (1);\r
+\r
+    Timeout--;\r
+  }\r
+\r
+  return EFI_TIMEOUT;\r
+}\r
+\r
+/**\r
+  Execute the specified TRB.\r
+\r
+  @param[in] Private        A pointer to the SD_MMC_HC_PRIVATE_DATA instance.\r
+  @param[in] Trb            The pointer to the SD_MMC_HC_TRB instance.\r
+\r
+  @retval EFI_SUCCESS       The TRB is sent to host controller successfully.\r
+  @retval Others            Some erros happen when sending this request to the host controller.\r
+\r
+**/\r
+EFI_STATUS\r
+SdMmcExecTrb (\r
+  IN SD_MMC_HC_PRIVATE_DATA           *Private,\r
+  IN SD_MMC_HC_TRB                    *Trb\r
+  )\r
+{\r
+  EFI_STATUS                          Status;\r
+  EFI_SD_MMC_PASS_THRU_COMMAND_PACKET *Packet;\r
+  EFI_PCI_IO_PROTOCOL                 *PciIo;\r
+  UINT16                              Cmd;\r
+  UINT16                              IntStatus;\r
+  UINT32                              Argument;\r
+  UINT16                              BlkCount;\r
+  UINT16                              BlkSize;\r
+  UINT16                              TransMode;\r
+  UINT8                               HostCtrl1;\r
+  UINT32                              SdmaAddr;\r
+  UINT64                              AdmaAddr;\r
+\r
+  Packet = Trb->Packet;\r
+  PciIo  = Trb->Private->PciIo;\r
+  //\r
+  // Clear all bits in Error Interrupt Status Register\r
+  //\r
+  IntStatus = 0xFFFF;\r
+  Status    = SdMmcHcRwMmio (PciIo, Trb->Slot, SD_MMC_HC_ERR_INT_STS, FALSE, sizeof (IntStatus), &IntStatus);\r
+  if (EFI_ERROR (Status)) {\r
+    return Status;\r
+  }\r
+  //\r
+  // Clear all bits in Normal Interrupt Status Register excepts for Card Removal & Card Insertion bits.\r
+  //\r
+  IntStatus = 0xFF3F;\r
+  Status    = SdMmcHcRwMmio (PciIo, Trb->Slot, SD_MMC_HC_NOR_INT_STS, FALSE, sizeof (IntStatus), &IntStatus);\r
+  if (EFI_ERROR (Status)) {\r
+    return Status;\r
+  }\r
+  //\r
+  // Set Host Control 1 register DMA Select field\r
+  //\r
+  if (Trb->Mode == SdMmcAdmaMode) {\r
+    HostCtrl1 = BIT4;\r
+    Status = SdMmcHcOrMmio (PciIo, Trb->Slot, SD_MMC_HC_HOST_CTRL1, sizeof (HostCtrl1), &HostCtrl1);\r
+    if (EFI_ERROR (Status)) {\r
+      return Status;\r
+    }\r
+  }\r
+\r
+  SdMmcHcLedOnOff (PciIo, Trb->Slot, TRUE);\r
+\r
+  if (Trb->Mode == SdMmcSdmaMode) {\r
+    if ((UINT64)(UINTN)Trb->DataPhy >= 0x100000000ul) {\r
+      return EFI_INVALID_PARAMETER;\r
+    }\r
+\r
+    SdmaAddr = (UINT32)(UINTN)Trb->DataPhy;\r
+    Status   = SdMmcHcRwMmio (PciIo, Trb->Slot, SD_MMC_HC_SDMA_ADDR, FALSE, sizeof (SdmaAddr), &SdmaAddr);\r
+    if (EFI_ERROR (Status)) {\r
+      return Status;\r
+    }\r
+  } else if (Trb->Mode == SdMmcAdmaMode) {\r
+    AdmaAddr = (UINT64)(UINTN)Trb->AdmaDescPhy;\r
+    Status   = SdMmcHcRwMmio (PciIo, Trb->Slot, SD_MMC_HC_ADMA_SYS_ADDR, FALSE, sizeof (AdmaAddr), &AdmaAddr);\r
+    if (EFI_ERROR (Status)) {\r
+      return Status;\r
+    }\r
+  }\r
+\r
+  BlkSize = Trb->BlockSize;\r
+  if (Trb->Mode == SdMmcSdmaMode) {\r
+    //\r
+    // Set SDMA boundary to be 512K bytes.\r
+    //\r
+    BlkSize |= 0x7000;\r
+  }\r
+\r
+  Status = SdMmcHcRwMmio (PciIo, Trb->Slot, SD_MMC_HC_BLK_SIZE, FALSE, sizeof (BlkSize), &BlkSize);\r
+  if (EFI_ERROR (Status)) {\r
+    return Status;\r
+  }\r
+\r
+  BlkCount = (UINT16)(Trb->DataLen / Trb->BlockSize);\r
+  Status   = SdMmcHcRwMmio (PciIo, Trb->Slot, SD_MMC_HC_BLK_COUNT, FALSE, sizeof (BlkCount), &BlkCount);\r
+  if (EFI_ERROR (Status)) {\r
+    return Status;\r
+  }\r
+\r
+  Argument = Packet->SdMmcCmdBlk->CommandArgument;\r
+  Status   = SdMmcHcRwMmio (PciIo, Trb->Slot, SD_MMC_HC_ARG1, FALSE, sizeof (Argument), &Argument);\r
+  if (EFI_ERROR (Status)) {\r
+    return Status;\r
+  }\r
+\r
+  TransMode = 0;\r
+  if (Trb->Mode != SdMmcNoData) {\r
+    if (Trb->Mode != SdMmcPioMode) {\r
+      TransMode |= BIT0;\r
+    }\r
+    if (Trb->Read) {\r
+      TransMode |= BIT4;\r
+    }\r
+    if (BlkCount != 0) {\r
+      TransMode |= BIT5 | BIT1;\r
+    }\r
+    //\r
+    // Only SD memory card needs to use AUTO CMD12 feature.\r
+    //\r
+    if (Private->Slot[Trb->Slot].CardType == SdCardType) {\r
+      if (BlkCount > 1) {\r
+        TransMode |= BIT2;\r
+      }\r
+    }\r
+  }\r
+\r
+  Status = SdMmcHcRwMmio (PciIo, Trb->Slot, SD_MMC_HC_TRANS_MOD, FALSE, sizeof (TransMode), &TransMode);\r
+  if (EFI_ERROR (Status)) {\r
+    return Status;\r
+  }\r
+\r
+  Cmd = (UINT16)LShiftU64(Packet->SdMmcCmdBlk->CommandIndex, 8);\r
+  if (Packet->SdMmcCmdBlk->CommandType == SdMmcCommandTypeAdtc) {\r
+    Cmd |= BIT5;\r
+  }\r
+  //\r
+  // Convert ResponseType to value\r
+  //\r
+  if (Packet->SdMmcCmdBlk->CommandType != SdMmcCommandTypeBc) {\r
+    switch (Packet->SdMmcCmdBlk->ResponseType) {\r
+      case SdMmcResponseTypeR1:\r
+      case SdMmcResponseTypeR5:\r
+      case SdMmcResponseTypeR6:\r
+      case SdMmcResponseTypeR7:\r
+        Cmd |= (BIT1 | BIT3 | BIT4);\r
+        break;\r
+      case SdMmcResponseTypeR2:\r
+        Cmd |= (BIT0 | BIT3);\r
+       break;\r
+      case SdMmcResponseTypeR3:\r
+      case SdMmcResponseTypeR4:\r
+        Cmd |= BIT1;\r
+        break;\r
+      case SdMmcResponseTypeR1b:\r
+      case SdMmcResponseTypeR5b:\r
+        Cmd |= (BIT0 | BIT1 | BIT3 | BIT4);\r
+        break;\r
+      default:\r
+        ASSERT (FALSE);\r
+        break;\r
+    }\r
+  }\r
+  //\r
+  // Execute cmd\r
+  //\r
+  Status = SdMmcHcRwMmio (PciIo, Trb->Slot, SD_MMC_HC_COMMAND, FALSE, sizeof (Cmd), &Cmd);\r
+  return Status;\r
+}\r
+\r
+/**\r
+  Check the TRB execution result.\r
+\r
+  @param[in] Private        A pointer to the SD_MMC_HC_PRIVATE_DATA instance.\r
+  @param[in] Trb            The pointer to the SD_MMC_HC_TRB instance.\r
+\r
+  @retval EFI_SUCCESS       The TRB is executed successfully.\r
+  @retval EFI_NOT_READY     The TRB is not completed for execution.\r
+  @retval Others            Some erros happen when executing this request.\r
+\r
+**/\r
+EFI_STATUS\r
+SdMmcCheckTrbResult (\r
+  IN SD_MMC_HC_PRIVATE_DATA           *Private,\r
+  IN SD_MMC_HC_TRB                    *Trb\r
+  )\r
+{\r
+  EFI_STATUS                          Status;\r
+  EFI_SD_MMC_PASS_THRU_COMMAND_PACKET *Packet;\r
+  UINT16                              IntStatus;\r
+  UINT32                              Response[4];\r
+  UINT32                              SdmaAddr;\r
+  UINT8                               Index;\r
+  UINT8                               SwReset;\r
+\r
+  SwReset = 0;\r
+  Packet  = Trb->Packet;\r
+  //\r
+  // Check Trb execution result by reading Normal Interrupt Status register.\r
+  //\r
+  Status = SdMmcHcRwMmio (\r
+             Private->PciIo,\r
+             Trb->Slot,\r
+             SD_MMC_HC_NOR_INT_STS,\r
+             TRUE,\r
+             sizeof (IntStatus),\r
+             &IntStatus\r
+             );\r
+  if (EFI_ERROR (Status)) {\r
+    goto Done;\r
+  }\r
+  //\r
+  // Check Transfer Complete bit is set or not.\r
+  //\r
+  if ((IntStatus & BIT1) == BIT1) {\r
+    if ((IntStatus & BIT15) == BIT15) {\r
+      //\r
+      // Read Error Interrupt Status register to check if the error is\r
+      // Data Timeout Error.\r
+      // If yes, treat it as success as Transfer Complete has higher\r
+      // priority than Data Timeout Error.\r
+      //\r
+      Status = SdMmcHcRwMmio (\r
+                 Private->PciIo,\r
+                 Trb->Slot,\r
+                 SD_MMC_HC_ERR_INT_STS,\r
+                 TRUE,\r
+                 sizeof (IntStatus),\r
+                 &IntStatus\r
+                 );\r
+      if (!EFI_ERROR (Status)) {\r
+        if ((IntStatus & BIT4) == BIT4) {\r
+          Status = EFI_SUCCESS;\r
+        } else {\r
+          Status = EFI_DEVICE_ERROR;\r
+        }\r
+      }\r
+    }\r
+\r
+    goto Done;\r
+  }\r
+  //\r
+  // Check if there is a error happened during cmd execution.\r
+  // If yes, then do error recovery procedure to follow SD Host Controller\r
+  // Simplified Spec 3.0 section 3.10.1.\r
+  //\r
+  if ((IntStatus & BIT15) == BIT15) {\r
+    Status = SdMmcHcRwMmio (\r
+               Private->PciIo,\r
+               Trb->Slot,\r
+               SD_MMC_HC_ERR_INT_STS,\r
+               TRUE,\r
+               sizeof (IntStatus),\r
+               &IntStatus\r
+               );\r
+    if (EFI_ERROR (Status)) {\r
+      goto Done;\r
+    }\r
+    if ((IntStatus & 0x0F) != 0) {\r
+      SwReset |= BIT1;\r
+    }\r
+    if ((IntStatus & 0xF0) != 0) {\r
+      SwReset |= BIT2;\r
+    }\r
+\r
+    Status  = SdMmcHcRwMmio (\r
+                Private->PciIo,\r
+                Trb->Slot,\r
+                SD_MMC_HC_SW_RST,\r
+                FALSE,\r
+                sizeof (SwReset),\r
+                &SwReset\r
+                );\r
+    if (EFI_ERROR (Status)) {\r
+      goto Done;\r
+    }\r
+    Status = SdMmcHcWaitMmioSet (\r
+               Private->PciIo,\r
+               Trb->Slot,\r
+               SD_MMC_HC_SW_RST,\r
+               sizeof (SwReset),\r
+               0xFF,\r
+               0,\r
+               SD_MMC_HC_GENERIC_TIMEOUT\r
+               );\r
+    if (EFI_ERROR (Status)) {\r
+      goto Done;\r
+    }\r
+\r
+    Status = EFI_DEVICE_ERROR;\r
+    goto Done;\r
+  }\r
+  //\r
+  // Check if DMA interrupt is signalled for the SDMA transfer.\r
+  //\r
+  if ((Trb->Mode == SdMmcSdmaMode) && ((IntStatus & BIT3) == BIT3)) {\r
+    //\r
+    // Clear DMA interrupt bit.\r
+    //\r
+    IntStatus = BIT3;\r
+    Status    = SdMmcHcRwMmio (\r
+                  Private->PciIo,\r
+                  Trb->Slot,\r
+                  SD_MMC_HC_NOR_INT_STS,\r
+                  FALSE,\r
+                  sizeof (IntStatus),\r
+                  &IntStatus\r
+                  );\r
+    if (EFI_ERROR (Status)) {\r
+      goto Done;\r
+    }\r
+    //\r
+    // Update SDMA Address register.\r
+    //\r
+    SdmaAddr = SD_MMC_SDMA_ROUND_UP ((UINT32)(UINTN)Trb->DataPhy, SD_MMC_SDMA_BOUNDARY);\r
+    Status   = SdMmcHcRwMmio (\r
+                 Private->PciIo,\r
+                 Trb->Slot,\r
+                 SD_MMC_HC_SDMA_ADDR,\r
+                 FALSE,\r
+                 sizeof (UINT32),\r
+                 &SdmaAddr\r
+                 );\r
+    if (EFI_ERROR (Status)) {\r
+      goto Done;\r
+    }\r
+    Trb->DataPhy = (UINT32)(UINTN)SdmaAddr;\r
+  }\r
+\r
+  if ((Packet->SdMmcCmdBlk->CommandType != SdMmcCommandTypeAdtc) &&\r
+      (Packet->SdMmcCmdBlk->ResponseType != SdMmcResponseTypeR1b) &&\r
+      (Packet->SdMmcCmdBlk->ResponseType != SdMmcResponseTypeR5b)) {\r
+    if ((IntStatus & BIT0) == BIT0) {\r
+      Status = EFI_SUCCESS;\r
+      goto Done;\r
+    }\r
+  }\r
+\r
+  if (((Private->Slot[Trb->Slot].CardType == EmmcCardType) &&\r
+       (Packet->SdMmcCmdBlk->CommandIndex == EMMC_SEND_TUNING_BLOCK)) ||\r
+      ((Private->Slot[Trb->Slot].CardType == SdCardType) &&\r
+       (Packet->SdMmcCmdBlk->CommandIndex == SD_SEND_TUNING_BLOCK))) {\r
+    //\r
+    // While performing tuning procedure (Execute Tuning is set to 1),\r
+    // Transfer Completeis not set to 1\r
+    // Refer to SD Host Controller Simplified Specification 3.0 table 2-23 for details.\r
+    //\r
+    Status = EFI_SUCCESS;\r
+    goto Done;\r
+  }\r
+\r
+  Status = EFI_NOT_READY;\r
+Done:\r
+  //\r
+  // Get response data when the cmd is executed successfully.\r
+  //\r
+  if (!EFI_ERROR (Status)) {\r
+    if (Packet->SdMmcCmdBlk->CommandType != SdMmcCommandTypeBc) {\r
+      for (Index = 0; Index < 4; Index++) {\r
+        Status = SdMmcHcRwMmio (\r
+                   Private->PciIo,\r
+                   Trb->Slot,\r
+                   SD_MMC_HC_RESPONSE + Index * 4,\r
+                   TRUE,\r
+                   sizeof (UINT32),\r
+                   &Response[Index]\r
+                   );\r
+        if (EFI_ERROR (Status)) {\r
+          SdMmcHcLedOnOff (Private->PciIo, Trb->Slot, FALSE);\r
+          return Status;\r
+        }\r
+      }\r
+      CopyMem (Packet->SdMmcStatusBlk, Response, sizeof (Response));\r
+    }\r
+  }\r
+\r
+  if (Status != EFI_NOT_READY) {\r
+    SdMmcHcLedOnOff (Private->PciIo, Trb->Slot, FALSE);\r
+  }\r
+\r
+  return Status;\r
+}\r
+\r
+/**\r
+  Wait for the TRB execution result.\r
+\r
+  @param[in] Private        A pointer to the SD_MMC_HC_PRIVATE_DATA instance.\r
+  @param[in] Trb            The pointer to the SD_MMC_HC_TRB instance.\r
+\r
+  @retval EFI_SUCCESS       The TRB is executed successfully.\r
+  @retval Others            Some erros happen when executing this request.\r
+\r
+**/\r
+EFI_STATUS\r
+SdMmcWaitTrbResult (\r
+  IN SD_MMC_HC_PRIVATE_DATA           *Private,\r
+  IN SD_MMC_HC_TRB                    *Trb\r
+  )\r
+{\r
+  EFI_STATUS                          Status;\r
+  EFI_SD_MMC_PASS_THRU_COMMAND_PACKET *Packet;\r
+  UINT64                              Timeout;\r
+  BOOLEAN                             InfiniteWait;\r
+\r
+  Packet = Trb->Packet;\r
+  //\r
+  // Wait Command Complete Interrupt Status bit in Normal Interrupt Status Register\r
+  //\r
+  Timeout = Packet->Timeout;\r
+  if (Timeout == 0) {\r
+    InfiniteWait = TRUE;\r
+  } else {\r
+    InfiniteWait = FALSE;\r
+  }\r
+\r
+  while (InfiniteWait || (Timeout > 0)) {\r
+    //\r
+    // Check Trb execution result by reading Normal Interrupt Status register.\r
+    //\r
+    Status = SdMmcCheckTrbResult (Private, Trb);\r
+    if (Status != EFI_NOT_READY) {\r
+      return Status;\r
+    }\r
+    //\r
+    // Stall for 1 microsecond.\r
+    //\r
+    gBS->Stall (1);\r
+\r
+    Timeout--;\r
+  }\r
+\r
+  return EFI_TIMEOUT;\r
+}\r
+\r
diff --git a/MdeModulePkg/Bus/Pci/SdMmcPciHcDxe/SdMmcPciHci.h b/MdeModulePkg/Bus/Pci/SdMmcPciHcDxe/SdMmcPciHci.h
new file mode 100644 (file)
index 0000000..fb62758
--- /dev/null
@@ -0,0 +1,546 @@
+/** @file\r
+\r
+  Provides some data structure definitions used by the SD/MMC host controller driver.\r
+\r
+Copyright (c) 2015, Intel Corporation. All rights reserved.<BR>\r
+This program and the accompanying materials\r
+are licensed and made available under the terms and conditions of the BSD License\r
+which accompanies this distribution.  The full text of the license may be found at\r
+http://opensource.org/licenses/bsd-license.php\r
+\r
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+\r
+**/\r
+\r
+#ifndef _SD_MMC_PCI_HCI_H_\r
+#define _SD_MMC_PCI_HCI_H_\r
+\r
+//\r
+// SD Host Controller SlotInfo Register Offset\r
+//\r
+#define SD_MMC_HC_SLOT_OFFSET         0x40\r
+\r
+#define SD_MMC_HC_MAX_SLOT            6\r
+\r
+//\r
+// SD Host Controller MMIO Register Offset\r
+//\r
+#define SD_MMC_HC_SDMA_ADDR           0x00\r
+#define SD_MMC_HC_ARG2                0x00\r
+#define SD_MMC_HC_BLK_SIZE            0x04\r
+#define SD_MMC_HC_BLK_COUNT           0x06\r
+#define SD_MMC_HC_ARG1                0x08\r
+#define SD_MMC_HC_TRANS_MOD           0x0C\r
+#define SD_MMC_HC_COMMAND             0x0E\r
+#define SD_MMC_HC_RESPONSE            0x10\r
+#define SD_MMC_HC_BUF_DAT_PORT        0x20\r
+#define SD_MMC_HC_PRESENT_STATE       0x24\r
+#define SD_MMC_HC_HOST_CTRL1          0x28\r
+#define SD_MMC_HC_POWER_CTRL          0x29\r
+#define SD_MMC_HC_BLK_GAP_CTRL        0x2A\r
+#define SD_MMC_HC_WAKEUP_CTRL         0x2B\r
+#define SD_MMC_HC_CLOCK_CTRL          0x2C\r
+#define SD_MMC_HC_TIMEOUT_CTRL        0x2E\r
+#define SD_MMC_HC_SW_RST              0x2F\r
+#define SD_MMC_HC_NOR_INT_STS         0x30\r
+#define SD_MMC_HC_ERR_INT_STS         0x32\r
+#define SD_MMC_HC_NOR_INT_STS_EN      0x34\r
+#define SD_MMC_HC_ERR_INT_STS_EN      0x36\r
+#define SD_MMC_HC_NOR_INT_SIG_EN      0x38\r
+#define SD_MMC_HC_ERR_INT_SIG_EN      0x3A\r
+#define SD_MMC_HC_AUTO_CMD_ERR_STS    0x3C\r
+#define SD_MMC_HC_HOST_CTRL2          0x3E\r
+#define SD_MMC_HC_CAP                 0x40\r
+#define SD_MMC_HC_MAX_CURRENT_CAP     0x48\r
+#define SD_MMC_HC_FORCE_EVT_AUTO_CMD  0x50\r
+#define SD_MMC_HC_FORCE_EVT_ERR_INT   0x52\r
+#define SD_MMC_HC_ADMA_ERR_STS        0x54\r
+#define SD_MMC_HC_ADMA_SYS_ADDR       0x58\r
+#define SD_MMC_HC_PRESET_VAL          0x60\r
+#define SD_MMC_HC_SHARED_BUS_CTRL     0xE0\r
+#define SD_MMC_HC_SLOT_INT_STS        0xFC\r
+#define SD_MMC_HC_CTRL_VER            0xFE\r
+\r
+//\r
+// The transfer modes supported by SD Host Controller\r
+// Simplified Spec 3.0 Table 1-2\r
+//\r
+typedef enum {\r
+  SdMmcNoData,\r
+  SdMmcPioMode,\r
+  SdMmcSdmaMode,\r
+  SdMmcAdmaMode\r
+} SD_MMC_HC_TRANSFER_MODE;\r
+\r
+//\r
+// The maximum data length of each descriptor line\r
+//\r
+#define ADMA_MAX_DATA_PER_LINE     0x10000\r
+\r
+typedef struct {\r
+  UINT32 Valid:1;\r
+  UINT32 End:1;\r
+  UINT32 Int:1;\r
+  UINT32 Reserved:1;\r
+  UINT32 Act:2;\r
+  UINT32 Reserved1:10;\r
+  UINT32 Length:16;\r
+  UINT32 Address;\r
+} SD_MMC_HC_ADMA_DESC_LINE;\r
+\r
+#define SD_MMC_SDMA_BOUNDARY          512 * 1024\r
+#define SD_MMC_SDMA_ROUND_UP(x, n)    (((x) + n) & ~(n - 1))\r
+\r
+typedef struct {\r
+  UINT8    FirstBar:3;        // bit 0:2\r
+  UINT8    Reserved:1;        // bit 3\r
+  UINT8    SlotNum:3;         // bit 4:6\r
+  UINT8    Reserved1:1;       // bit 7\r
+} SD_MMC_HC_SLOT_INFO;\r
+\r
+typedef struct {\r
+  UINT32   TimeoutFreq:6;     // bit 0:5\r
+  UINT32   Reserved:1;        // bit 6\r
+  UINT32   TimeoutUnit:1;     // bit 7\r
+  UINT32   BaseClkFreq:8;     // bit 8:15\r
+  UINT32   MaxBlkLen:2;       // bit 16:17\r
+  UINT32   BusWidth8:1;       // bit 18\r
+  UINT32   Adma2:1;           // bit 19\r
+  UINT32   Reserved2:1;       // bit 20\r
+  UINT32   HighSpeed:1;       // bit 21\r
+  UINT32   Sdma:1;            // bit 22\r
+  UINT32   SuspRes:1;         // bit 23\r
+  UINT32   Voltage33:1;       // bit 24\r
+  UINT32   Voltage30:1;       // bit 25\r
+  UINT32   Voltage18:1;       // bit 26\r
+  UINT32   Reserved3:1;       // bit 27\r
+  UINT32   SysBus64:1;        // bit 28\r
+  UINT32   AsyncInt:1;        // bit 29\r
+  UINT32   SlotType:2;        // bit 30:31\r
+  UINT32   Sdr50:1;           // bit 32\r
+  UINT32   Sdr104:1;          // bit 33\r
+  UINT32   Ddr50:1;           // bit 34\r
+  UINT32   Reserved4:1;       // bit 35\r
+  UINT32   DriverTypeA:1;     // bit 36\r
+  UINT32   DriverTypeC:1;     // bit 37\r
+  UINT32   DriverTypeD:1;     // bit 38\r
+  UINT32   DriverType4:1;     // bit 39\r
+  UINT32   TimerCount:4;      // bit 40:43\r
+  UINT32   Reserved5:1;       // bit 44\r
+  UINT32   TuningSDR50:1;     // bit 45\r
+  UINT32   RetuningMod:2;     // bit 46:47\r
+  UINT32   ClkMultiplier:8;   // bit 48:55\r
+  UINT32   Reserved6:7;       // bit 56:62\r
+  UINT32   Hs400:1;           // bit 63\r
+} SD_MMC_HC_SLOT_CAP;\r
+\r
+/**\r
+  Dump the content of SD/MMC host controller's Capability Register.\r
+\r
+  @param[in]  Slot            The slot number of the SD card to send the command to.\r
+  @param[in]  Capability      The buffer to store the capability data.\r
+\r
+**/\r
+VOID\r
+DumpCapabilityReg (\r
+  IN UINT8                Slot,\r
+  IN SD_MMC_HC_SLOT_CAP   *Capability\r
+  );\r
+\r
+/**\r
+  Read SlotInfo register from SD/MMC host controller pci config space.\r
+\r
+  @param[in]  PciIo        The PCI IO protocol instance.\r
+  @param[out] FirstBar     The buffer to store the first BAR value.\r
+  @param[out] SlotNum      The buffer to store the supported slot number.\r
+\r
+  @retval EFI_SUCCESS      The operation succeeds.\r
+  @retval Others           The operation fails.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+SdMmcHcGetSlotInfo (\r
+  IN     EFI_PCI_IO_PROTOCOL   *PciIo,\r
+     OUT UINT8                 *FirstBar,\r
+     OUT UINT8                 *SlotNum\r
+  );\r
+\r
+/**\r
+  Read/Write specified SD/MMC host controller mmio register.\r
+\r
+  @param[in]      PciIo        The PCI IO protocol instance.\r
+  @param[in]      BarIndex     The BAR index of the standard PCI Configuration\r
+                               header to use as the base address for the memory\r
+                               operation to perform.\r
+  @param[in]      Offset       The offset within the selected BAR to start the\r
+                               memory operation.\r
+  @param[in]      Read         A boolean to indicate it's read or write operation.\r
+  @param[in]      Count        The width of the mmio register in bytes.\r
+                               Must be 1, 2 , 4 or 8 bytes.\r
+  @param[in, out] Data         For read operations, the destination buffer to store\r
+                               the results. For write operations, the source buffer\r
+                               to write data from. The caller is responsible for\r
+                               having ownership of the data buffer and ensuring its\r
+                               size not less than Count bytes.\r
+\r
+  @retval EFI_INVALID_PARAMETER The PciIo or Data is NULL or the Count is not valid.\r
+  @retval EFI_SUCCESS           The read/write operation succeeds.\r
+  @retval Others                The read/write operation fails.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+SdMmcHcRwMmio (\r
+  IN     EFI_PCI_IO_PROTOCOL   *PciIo,\r
+  IN     UINT8                 BarIndex,\r
+  IN     UINT32                Offset,\r
+  IN     BOOLEAN               Read,\r
+  IN     UINT8                 Count,\r
+  IN OUT VOID                  *Data\r
+  );\r
+\r
+/**\r
+  Do OR operation with the value of the specified SD/MMC host controller mmio register.\r
+\r
+  @param[in] PciIo             The PCI IO protocol instance.\r
+  @param[in] BarIndex          The BAR index of the standard PCI Configuration\r
+                               header to use as the base address for the memory\r
+                               operation to perform.\r
+  @param[in] Offset            The offset within the selected BAR to start the\r
+                               memory operation.\r
+  @param[in] Count             The width of the mmio register in bytes.\r
+                               Must be 1, 2 , 4 or 8 bytes.\r
+  @param[in] OrData            The pointer to the data used to do OR operation.\r
+                               The caller is responsible for having ownership of\r
+                               the data buffer and ensuring its size not less than\r
+                               Count bytes.\r
+\r
+  @retval EFI_INVALID_PARAMETER The PciIo or OrData is NULL or the Count is not valid.\r
+  @retval EFI_SUCCESS           The OR operation succeeds.\r
+  @retval Others                The OR operation fails.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+SdMmcHcOrMmio (\r
+  IN  EFI_PCI_IO_PROTOCOL      *PciIo,\r
+  IN  UINT8                    BarIndex,\r
+  IN  UINT32                   Offset,\r
+  IN  UINT8                    Count,\r
+  IN  VOID                     *OrData\r
+  );\r
+\r
+/**\r
+  Do AND operation with the value of the specified SD/MMC host controller mmio register.\r
+\r
+  @param[in] PciIo             The PCI IO protocol instance.\r
+  @param[in] BarIndex          The BAR index of the standard PCI Configuration\r
+                               header to use as the base address for the memory\r
+                               operation to perform.\r
+  @param[in] Offset            The offset within the selected BAR to start the\r
+                               memory operation.\r
+  @param[in] Count             The width of the mmio register in bytes.\r
+                               Must be 1, 2 , 4 or 8 bytes.\r
+  @param[in] AndData           The pointer to the data used to do AND operation.\r
+                               The caller is responsible for having ownership of\r
+                               the data buffer and ensuring its size not less than\r
+                               Count bytes.\r
+\r
+  @retval EFI_INVALID_PARAMETER The PciIo or AndData is NULL or the Count is not valid.\r
+  @retval EFI_SUCCESS           The AND operation succeeds.\r
+  @retval Others                The AND operation fails.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+SdMmcHcAndMmio (\r
+  IN  EFI_PCI_IO_PROTOCOL      *PciIo,\r
+  IN  UINT8                    BarIndex,\r
+  IN  UINT32                   Offset,\r
+  IN  UINT8                    Count,\r
+  IN  VOID                     *AndData\r
+  );\r
+\r
+/**\r
+  Wait for the value of the specified MMIO register set to the test value.\r
+\r
+  @param[in]  PciIo         The PCI IO protocol instance.\r
+  @param[in]  BarIndex      The BAR index of the standard PCI Configuration\r
+                            header to use as the base address for the memory\r
+                            operation to perform.\r
+  @param[in]  Offset        The offset within the selected BAR to start the\r
+                            memory operation.\r
+  @param[in]  Count         The width of the mmio register in bytes.\r
+                            Must be 1, 2, 4 or 8 bytes.\r
+  @param[in]  MaskValue     The mask value of memory.\r
+  @param[in]  TestValue     The test value of memory.\r
+  @param[in]  Timeout       The time out value for wait memory set, uses 1\r
+                            microsecond as a unit.\r
+\r
+  @retval EFI_TIMEOUT       The MMIO register hasn't expected value in timeout\r
+                            range.\r
+  @retval EFI_SUCCESS       The MMIO register has expected value.\r
+  @retval Others            The MMIO operation fails.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+SdMmcHcWaitMmioSet (\r
+  IN  EFI_PCI_IO_PROTOCOL       *PciIo,\r
+  IN  UINT8                     BarIndex,\r
+  IN  UINT32                    Offset,\r
+  IN  UINT8                     Count,\r
+  IN  UINT64                    MaskValue,\r
+  IN  UINT64                    TestValue,\r
+  IN  UINT64                    Timeout\r
+  );\r
+\r
+/**\r
+  Software reset the specified SD/MMC host controller.\r
+\r
+  @param[in] PciIo          The PCI IO protocol instance.\r
+  @param[in] Slot           The slot number of the SD card to send the command to.\r
+\r
+  @retval EFI_SUCCESS       The software reset executes successfully.\r
+  @retval Others            The software reset fails.\r
+\r
+**/\r
+EFI_STATUS\r
+SdMmcHcReset (\r
+  IN EFI_PCI_IO_PROTOCOL    *PciIo,\r
+  IN UINT8                  Slot\r
+  );\r
+\r
+/**\r
+  Set all interrupt status bits in Normal and Error Interrupt Status Enable\r
+  register.\r
+\r
+  @param[in] PciIo          The PCI IO protocol instance.\r
+  @param[in] Slot           The slot number of the SD card to send the command to.\r
+\r
+  @retval EFI_SUCCESS       The operation executes successfully.\r
+  @retval Others            The operation fails.\r
+\r
+**/\r
+EFI_STATUS\r
+SdMmcHcEnableInterrupt (\r
+  IN EFI_PCI_IO_PROTOCOL    *PciIo,\r
+  IN UINT8                  Slot\r
+  );\r
+\r
+/**\r
+  Get the capability data from the specified slot.\r
+\r
+  @param[in]  PciIo           The PCI IO protocol instance.\r
+  @param[in]  Slot            The slot number of the SD card to send the command to.\r
+  @param[out] Capability      The buffer to store the capability data.\r
+\r
+  @retval EFI_SUCCESS         The operation executes successfully.\r
+  @retval Others              The operation fails.\r
+\r
+**/\r
+EFI_STATUS\r
+SdMmcHcGetCapability (\r
+  IN     EFI_PCI_IO_PROTOCOL  *PciIo,\r
+  IN     UINT8                Slot,\r
+     OUT SD_MMC_HC_SLOT_CAP   *Capability\r
+  );\r
+\r
+/**\r
+  Get the maximum current capability data from the specified slot.\r
+\r
+  @param[in]  PciIo           The PCI IO protocol instance.\r
+  @param[in]  Slot            The slot number of the SD card to send the command to.\r
+  @param[out] MaxCurrent      The buffer to store the maximum current capability data.\r
+\r
+  @retval EFI_SUCCESS         The operation executes successfully.\r
+  @retval Others              The operation fails.\r
+\r
+**/\r
+EFI_STATUS\r
+SdMmcHcGetMaxCurrent (\r
+  IN     EFI_PCI_IO_PROTOCOL  *PciIo,\r
+  IN     UINT8                Slot,\r
+     OUT UINT64               *MaxCurrent\r
+  );\r
+\r
+/**\r
+  Detect whether there is a SD/MMC card attached at the specified SD/MMC host controller\r
+  slot.\r
+\r
+  Refer to SD Host Controller Simplified spec 3.0 Section 3.1 for details.\r
+\r
+  @param[in]  PciIo         The PCI IO protocol instance.\r
+  @param[in]  Slot          The slot number of the SD card to send the command to.\r
+  @param[out] MediaPresent  The pointer to the media present boolean value.\r
+\r
+  @retval EFI_SUCCESS       There is no media change happened.\r
+  @retval EFI_MEDIA_CHANGED There is media change happened.\r
+  @retval Others            The detection fails.\r
+\r
+**/\r
+EFI_STATUS\r
+SdMmcHcCardDetect (\r
+  IN EFI_PCI_IO_PROTOCOL    *PciIo,\r
+  IN UINT8                  Slot,\r
+     OUT BOOLEAN            *MediaPresent\r
+  );\r
+\r
+/**\r
+  Stop SD/MMC card clock.\r
+\r
+  Refer to SD Host Controller Simplified spec 3.0 Section 3.2.2 for details.\r
+\r
+  @param[in] PciIo          The PCI IO protocol instance.\r
+  @param[in] Slot           The slot number of the SD card to send the command to.\r
+\r
+  @retval EFI_SUCCESS       Succeed to stop SD/MMC clock.\r
+  @retval Others            Fail to stop SD/MMC clock.\r
+\r
+**/\r
+EFI_STATUS\r
+SdMmcHcStopClock (\r
+  IN EFI_PCI_IO_PROTOCOL    *PciIo,\r
+  IN UINT8                  Slot\r
+  );\r
+\r
+/**\r
+  SD/MMC card clock supply.\r
+\r
+  Refer to SD Host Controller Simplified spec 3.0 Section 3.2.1 for details.\r
+\r
+  @param[in] PciIo          The PCI IO protocol instance.\r
+  @param[in] Slot           The slot number of the SD card to send the command to.\r
+  @param[in] ClockFreq      The max clock frequency to be set. The unit is KHz.\r
+  @param[in] Capability     The capability of the slot.\r
+\r
+  @retval EFI_SUCCESS       The clock is supplied successfully.\r
+  @retval Others            The clock isn't supplied successfully.\r
+\r
+**/\r
+EFI_STATUS\r
+SdMmcHcClockSupply (\r
+  IN EFI_PCI_IO_PROTOCOL    *PciIo,\r
+  IN UINT8                  Slot,\r
+  IN UINT64                 ClockFreq,\r
+  IN SD_MMC_HC_SLOT_CAP     Capability\r
+  );\r
+\r
+/**\r
+  SD/MMC bus power control.\r
+\r
+  Refer to SD Host Controller Simplified spec 3.0 Section 3.3 for details.\r
+\r
+  @param[in] PciIo          The PCI IO protocol instance.\r
+  @param[in] Slot           The slot number of the SD card to send the command to.\r
+  @param[in] PowerCtrl      The value setting to the power control register.\r
+\r
+  @retval TRUE              There is a SD/MMC card attached.\r
+  @retval FALSE             There is no a SD/MMC card attached.\r
+\r
+**/\r
+EFI_STATUS\r
+SdMmcHcPowerControl (\r
+  IN EFI_PCI_IO_PROTOCOL    *PciIo,\r
+  IN UINT8                  Slot,\r
+  IN UINT8                  PowerCtrl\r
+  );\r
+\r
+/**\r
+  Set the SD/MMC bus width.\r
+\r
+  Refer to SD Host Controller Simplified spec 3.0 Section 3.4 for details.\r
+\r
+  @param[in] PciIo          The PCI IO protocol instance.\r
+  @param[in] Slot           The slot number of the SD card to send the command to.\r
+  @param[in] BusWidth       The bus width used by the SD/MMC device, it must be 1, 4 or 8.\r
+\r
+  @retval EFI_SUCCESS       The bus width is set successfully.\r
+  @retval Others            The bus width isn't set successfully.\r
+\r
+**/\r
+EFI_STATUS\r
+SdMmcHcSetBusWidth (\r
+  IN EFI_PCI_IO_PROTOCOL    *PciIo,\r
+  IN UINT8                  Slot,\r
+  IN UINT16                 BusWidth\r
+  );\r
+\r
+/**\r
+  Supply SD/MMC card with lowest clock frequency at initialization.\r
+\r
+  @param[in] PciIo          The PCI IO protocol instance.\r
+  @param[in] Slot           The slot number of the SD card to send the command to.\r
+  @param[in] Capability     The capability of the slot.\r
+\r
+  @retval EFI_SUCCESS       The clock is supplied successfully.\r
+  @retval Others            The clock isn't supplied successfully.\r
+\r
+**/\r
+EFI_STATUS\r
+SdMmcHcInitClockFreq (\r
+  IN EFI_PCI_IO_PROTOCOL    *PciIo,\r
+  IN UINT8                  Slot,\r
+  IN SD_MMC_HC_SLOT_CAP     Capability\r
+  );\r
+\r
+/**\r
+  Supply SD/MMC card with maximum voltage at initialization.\r
+\r
+  Refer to SD Host Controller Simplified spec 3.0 Section 3.3 for details.\r
+\r
+  @param[in] PciIo          The PCI IO protocol instance.\r
+  @param[in] Slot           The slot number of the SD card to send the command to.\r
+  @param[in] Capability     The capability of the slot.\r
+\r
+  @retval EFI_SUCCESS       The voltage is supplied successfully.\r
+  @retval Others            The voltage isn't supplied successfully.\r
+\r
+**/\r
+EFI_STATUS\r
+SdMmcHcInitPowerVoltage (\r
+  IN EFI_PCI_IO_PROTOCOL    *PciIo,\r
+  IN UINT8                  Slot,\r
+  IN SD_MMC_HC_SLOT_CAP     Capability\r
+  );\r
+\r
+/**\r
+  Initialize the Timeout Control register with most conservative value at initialization.\r
+\r
+  Refer to SD Host Controller Simplified spec 3.0 Section 2.2.15 for details.\r
+\r
+  @param[in] PciIo          The PCI IO protocol instance.\r
+  @param[in] Slot           The slot number of the SD card to send the command to.\r
+\r
+  @retval EFI_SUCCESS       The timeout control register is configured successfully.\r
+  @retval Others            The timeout control register isn't configured successfully.\r
+\r
+**/\r
+EFI_STATUS\r
+SdMmcHcInitTimeoutCtrl (\r
+  IN EFI_PCI_IO_PROTOCOL    *PciIo,\r
+  IN UINT8                  Slot\r
+  );\r
+\r
+/**\r
+  Initial SD/MMC host controller with lowest clock frequency, max power and max timeout value\r
+  at initialization.\r
+\r
+  @param[in] PciIo          The PCI IO protocol instance.\r
+  @param[in] Slot           The slot number of the SD card to send the command to.\r
+  @param[in] Capability     The capability of the slot.\r
+\r
+  @retval EFI_SUCCESS       The host controller is initialized successfully.\r
+  @retval Others            The host controller isn't initialized successfully.\r
+\r
+**/\r
+EFI_STATUS\r
+SdMmcHcInitHost (\r
+  IN EFI_PCI_IO_PROTOCOL    *PciIo,\r
+  IN UINT8                  Slot,\r
+  IN SD_MMC_HC_SLOT_CAP     Capability\r
+  );\r
+\r
+#endif\r
diff --git a/MdeModulePkg/Bus/Pci/SdMmcPciHcPei/SdMmcPciHcPei.c b/MdeModulePkg/Bus/Pci/SdMmcPciHcPei/SdMmcPciHcPei.c
new file mode 100644 (file)
index 0000000..3f4ebc4
--- /dev/null
@@ -0,0 +1,212 @@
+/** @file\r
+  SdMmcPciHcPei driver is used to provide platform-dependent info, mainly SD/MMC\r
+  host controller MMIO base, to upper layer SD/MMC drivers.\r
+\r
+  Copyright (c) 2015, Intel Corporation. All rights reserved.<BR>\r
+  This program and the accompanying materials\r
+  are licensed and made available under the terms and conditions of the BSD License\r
+  which accompanies this distribution.  The full text of the license may be found at\r
+  http://opensource.org/licenses/bsd-license.php.\r
+\r
+  THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+  WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+\r
+**/\r
+\r
+#include "SdMmcPciHcPei.h"\r
+\r
+EDKII_SD_MMC_HOST_CONTROLLER_PPI  mSdMmcHostControllerPpi = { GetSdMmcHcMmioBar };\r
+\r
+EFI_PEI_PPI_DESCRIPTOR   mPpiList = {\r
+  (EFI_PEI_PPI_DESCRIPTOR_PPI | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST),\r
+  &gEdkiiPeiSdMmcHostControllerPpiGuid,\r
+  &mSdMmcHostControllerPpi\r
+};\r
+\r
+/**\r
+  Get the MMIO base address of SD/MMC host controller.\r
+\r
+  @param[in]     This            The protocol instance pointer.\r
+  @param[in]     ControllerId    The ID of the SD/MMC host controller.\r
+  @param[in,out] MmioBar         The pointer to store the array of available\r
+                                 SD/MMC host controller slot MMIO base addresses.\r
+                                 The entry number of the array is specified by BarNum.\r
+  @param[out]    BarNum          The pointer to store the supported bar number.\r
+\r
+  @retval EFI_SUCCESS            The operation succeeds.\r
+  @retval EFI_INVALID_PARAMETER  The parameters are invalid.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+GetSdMmcHcMmioBar (\r
+  IN     EDKII_SD_MMC_HOST_CONTROLLER_PPI *This,\r
+  IN     UINT8                            ControllerId,\r
+  IN OUT UINTN                            **MmioBar,\r
+     OUT UINT8                            *BarNum\r
+  )\r
+{\r
+  SD_MMC_HC_PEI_PRIVATE_DATA  *Private;\r
+\r
+  if ((This == NULL) || (MmioBar == NULL) || (BarNum == NULL)) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  Private = SD_MMC_HC_PEI_PRIVATE_DATA_FROM_THIS (This);\r
+\r
+  if (ControllerId >= Private->TotalSdMmcHcs) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  *MmioBar = &Private->MmioBar[ControllerId].MmioBarAddr[0];\r
+  *BarNum  = (UINT8)Private->MmioBar[ControllerId].SlotNum;\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+  The user code starts with this function.\r
+\r
+  @param  FileHandle             Handle of the file being invoked.\r
+  @param  PeiServices            Describes the list of possible PEI Services.\r
+\r
+  @retval EFI_SUCCESS            The driver is successfully initialized.\r
+  @retval Others                 Can't initialize the driver.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+InitializeSdMmcHcPeim (\r
+  IN EFI_PEI_FILE_HANDLE       FileHandle,\r
+  IN CONST EFI_PEI_SERVICES    **PeiServices\r
+  )\r
+{\r
+  EFI_BOOT_MODE                BootMode;\r
+  EFI_STATUS                   Status;\r
+  UINT16                       Bus;\r
+  UINT16                       Device;\r
+  UINT16                       Function;\r
+  UINT32                       Size;\r
+  UINT64                       MmioSize;\r
+  UINT8                        SubClass;\r
+  UINT8                        BaseClass;\r
+  UINT8                        SlotInfo;\r
+  UINT8                        SlotNum;\r
+  UINT8                        FirstBar;\r
+  UINT8                        Index;\r
+  UINT8                        Slot;\r
+  UINT32                       BarAddr;\r
+  SD_MMC_HC_PEI_PRIVATE_DATA   *Private;\r
+\r
+  //\r
+  // Shadow this PEIM to run from memory\r
+  //\r
+  if (!EFI_ERROR (PeiServicesRegisterForShadow (FileHandle))) {\r
+    return EFI_SUCCESS;\r
+  }\r
+\r
+  Status = PeiServicesGetBootMode (&BootMode);\r
+  ///\r
+  /// We do not expose this in S3 boot path, because it is only for recovery.\r
+  ///\r
+  if (BootMode == BOOT_ON_S3_RESUME) {\r
+    return EFI_SUCCESS;\r
+  }\r
+\r
+  Private = (SD_MMC_HC_PEI_PRIVATE_DATA *) AllocateZeroPool (sizeof (SD_MMC_HC_PEI_PRIVATE_DATA));\r
+  if (Private == NULL) {\r
+    DEBUG ((EFI_D_ERROR, "Failed to allocate memory for SD_MMC_HC_PEI_PRIVATE_DATA! \n"));\r
+    return EFI_OUT_OF_RESOURCES;\r
+  }\r
+\r
+  Private->Signature              = SD_MMC_HC_PEI_SIGNATURE;\r
+  Private->SdMmcHostControllerPpi = mSdMmcHostControllerPpi;\r
+  Private->PpiList                = mPpiList;\r
+  Private->PpiList.Ppi            = &Private->SdMmcHostControllerPpi;\r
+\r
+  BarAddr = PcdGet32 (PcdSdMmcPciHostControllerMmioBase);\r
+  for (Bus = 0; Bus < 256; Bus++) {\r
+    for (Device = 0; Device < 32; Device++) {\r
+      for (Function = 0; Function < 8; Function++) {\r
+        SubClass  = PciRead8 (PCI_LIB_ADDRESS (Bus, Device, Function, 0x0A));\r
+        BaseClass = PciRead8 (PCI_LIB_ADDRESS (Bus, Device, Function, 0x0B));\r
+\r
+        if ((SubClass == PCI_SUBCLASS_SD_HOST_CONTROLLER) && (BaseClass == PCI_CLASS_SYSTEM_PERIPHERAL)) {\r
+          //\r
+          // Get the SD/MMC Pci host controller's Slot Info.\r
+          //\r
+          SlotInfo = PciRead8 (PCI_LIB_ADDRESS (Bus, Device, Function, SD_MMC_HC_PEI_SLOT_OFFSET));\r
+          FirstBar = (*(SD_MMC_HC_PEI_SLOT_INFO*)&SlotInfo).FirstBar;\r
+          SlotNum  = (*(SD_MMC_HC_PEI_SLOT_INFO*)&SlotInfo).SlotNum + 1;\r
+          ASSERT ((FirstBar + SlotNum) < MAX_SD_MMC_SLOTS);\r
+\r
+          for (Index = 0, Slot = FirstBar; Slot < (FirstBar + SlotNum); Index++, Slot++) {\r
+            //\r
+            // Get the SD/MMC Pci host controller's MMIO region size.\r
+            //\r
+            PciAnd16 (PCI_LIB_ADDRESS (Bus, Device, Function, PCI_COMMAND_OFFSET), (UINT16)~(EFI_PCI_COMMAND_BUS_MASTER | EFI_PCI_COMMAND_MEMORY_SPACE));\r
+            PciWrite32 (PCI_LIB_ADDRESS (Bus, Device, Function, PCI_BASE_ADDRESSREG_OFFSET + 4 * Slot), 0xFFFFFFFF);\r
+            Size = PciRead32 (PCI_LIB_ADDRESS (Bus, Device, Function, PCI_BASE_ADDRESSREG_OFFSET + 4 * Slot));\r
+\r
+            switch (Size & 0x07) {\r
+              case 0x0:\r
+                //\r
+                // Memory space: anywhere in 32 bit address space\r
+                //\r
+                MmioSize = (~(Size & 0xFFFFFFF0)) + 1;\r
+                break;\r
+              case 0x4:\r
+                //\r
+                // Memory space: anywhere in 64 bit address space\r
+                //\r
+                MmioSize = Size & 0xFFFFFFF0;\r
+                PciWrite32 (PCI_LIB_ADDRESS(Bus, Device, Function, PCI_BASE_ADDRESSREG_OFFSET + 4), 0xFFFFFFFF);\r
+                Size = PciRead32 (PCI_LIB_ADDRESS(Bus, Device, Function, PCI_BASE_ADDRESSREG_OFFSET + 4));      \r
+                //\r
+                // Fix the length to support some spefic 64 bit BAR\r
+                //\r
+                Size |= ((UINT32)(-1) << HighBitSet32 (Size));\r
+                //\r
+                // Calculate the size of 64bit bar\r
+                //\r
+                MmioSize  |= LShiftU64 ((UINT64) Size, 32);\r
+                MmioSize  = (~(MmioSize)) + 1;\r
+                //\r
+                // Clean the high 32bits of this 64bit BAR to 0 as we only allow a 32bit BAR.\r
+                //\r
+                PciWrite32 (PCI_LIB_ADDRESS (Bus, Device, Function, PCI_BASE_ADDRESSREG_OFFSET + 4 * Slot + 4), 0);\r
+                break;\r
+              default:\r
+                //\r
+                // Unknown BAR type\r
+                //\r
+                ASSERT (FALSE);\r
+                continue;\r
+            };\r
+            //\r
+            // Assign resource to the SdMmc Pci host controller's MMIO BAR.\r
+            // Enable the SdMmc Pci host controller by setting BME and MSE bits of PCI_CMD register.\r
+            //\r
+            PciWrite32 (PCI_LIB_ADDRESS (Bus, Device, Function, PCI_BASE_ADDRESSREG_OFFSET + 4 * Slot), BarAddr);\r
+            PciOr16 (PCI_LIB_ADDRESS (Bus, Device, Function, PCI_COMMAND_OFFSET), (EFI_PCI_COMMAND_BUS_MASTER | EFI_PCI_COMMAND_MEMORY_SPACE));\r
+            //\r
+            // Record the allocated Mmio base address.\r
+            //\r
+            Private->MmioBar[Private->TotalSdMmcHcs].SlotNum++;\r
+            Private->MmioBar[Private->TotalSdMmcHcs].MmioBarAddr[Index] = BarAddr;\r
+            BarAddr += (UINT32)MmioSize;\r
+          }\r
+          Private->TotalSdMmcHcs++;\r
+          ASSERT (Private->TotalSdMmcHcs < MAX_SD_MMC_HCS);\r
+        }\r
+      }\r
+    }\r
+  }\r
+\r
+  ///\r
+  /// Install SdMmc Host Controller PPI\r
+  ///\r
+  Status = PeiServicesInstallPpi (&Private->PpiList);\r
+\r
+  ASSERT_EFI_ERROR (Status);\r
+  return Status;\r
+}\r
diff --git a/MdeModulePkg/Bus/Pci/SdMmcPciHcPei/SdMmcPciHcPei.h b/MdeModulePkg/Bus/Pci/SdMmcPciHcPei/SdMmcPciHcPei.h
new file mode 100644 (file)
index 0000000..1fbd2ca
--- /dev/null
@@ -0,0 +1,86 @@
+/** @file\r
+\r
+  Copyright (c) 2015, Intel Corporation. All rights reserved.<BR>\r
+  This program and the accompanying materials\r
+  are licensed and made available under the terms and conditions of the BSD License\r
+  which accompanies this distribution.  The full text of the license may be found at\r
+  http://opensource.org/licenses/bsd-license.php.\r
+\r
+  THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+  WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+\r
+**/\r
+\r
+#ifndef _SD_MMC_PCI_HOST_CONTROLLER_PEI_H_\r
+#define _SD_MMC_PCI_HOST_CONTROLLER_PEI_H_\r
+\r
+#include <PiPei.h>\r
+\r
+#include <Ppi/MasterBootMode.h>\r
+#include <Ppi/SdMmcHostController.h>\r
+\r
+#include <IndustryStandard/Pci.h>\r
+\r
+#include <Library/DebugLib.h>\r
+#include <Library/BaseLib.h>\r
+#include <Library/BaseMemoryLib.h>\r
+#include <Library/PciLib.h>\r
+#include <Library/PeiServicesLib.h>\r
+#include <Library/MemoryAllocationLib.h>\r
+\r
+#define SD_MMC_HC_PEI_SIGNATURE    SIGNATURE_32 ('S', 'D', 'M', 'C')\r
+\r
+#define MAX_SD_MMC_HCS             8\r
+#define MAX_SD_MMC_SLOTS           6\r
+\r
+//\r
+// SD Host Controller SlotInfo Register Offset\r
+//\r
+#define SD_MMC_HC_PEI_SLOT_OFFSET  0x40\r
+\r
+typedef struct {\r
+  UINT8    FirstBar:3;        // bit 0:2\r
+  UINT8    Reserved:1;        // bit 3\r
+  UINT8    SlotNum:3;         // bit 4:6\r
+  UINT8    Reserved1:1;       // bit 7\r
+} SD_MMC_HC_PEI_SLOT_INFO;\r
+\r
+typedef struct {\r
+  UINTN                            SlotNum;\r
+  UINTN                            MmioBarAddr[MAX_SD_MMC_SLOTS];\r
+} SD_MMC_HC_PEI_BAR;\r
+\r
+typedef struct {\r
+  UINTN                            Signature;\r
+  EDKII_SD_MMC_HOST_CONTROLLER_PPI SdMmcHostControllerPpi;\r
+  EFI_PEI_PPI_DESCRIPTOR           PpiList;\r
+  UINTN                            TotalSdMmcHcs;\r
+  SD_MMC_HC_PEI_BAR                MmioBar[MAX_SD_MMC_HCS];\r
+} SD_MMC_HC_PEI_PRIVATE_DATA;\r
+\r
+#define SD_MMC_HC_PEI_PRIVATE_DATA_FROM_THIS(a)  CR (a, SD_MMC_HC_PEI_PRIVATE_DATA, SdMmcHostControllerPpi, SD_MMC_HC_PEI_SIGNATURE)\r
+\r
+/**\r
+  Get the MMIO base address of SD/MMC host controller.\r
+\r
+  @param[in]     This            The protocol instance pointer.\r
+  @param[in]     ControllerId    The ID of the SD/MMC host controller.\r
+  @param[in,out] MmioBar         The pointer to store the array of available\r
+                                 SD/MMC host controller slot MMIO base addresses.\r
+                                 The entry number of the array is specified by BarNum.\r
+  @param[out]    BarNum          The pointer to store the supported bar number.\r
+\r
+  @retval EFI_SUCCESS            The operation succeeds.\r
+  @retval EFI_INVALID_PARAMETER  The parameters are invalid.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+GetSdMmcHcMmioBar (\r
+  IN     EDKII_SD_MMC_HOST_CONTROLLER_PPI *This,\r
+  IN     UINT8                            ControllerId,\r
+  IN OUT UINTN                            **MmioBar,\r
+     OUT UINT8                            *BarNum\r
+  );\r
+\r
+#endif\r
diff --git a/MdeModulePkg/Bus/Pci/SdMmcPciHcPei/SdMmcPciHcPei.inf b/MdeModulePkg/Bus/Pci/SdMmcPciHcPei/SdMmcPciHcPei.inf
new file mode 100644 (file)
index 0000000..bc6ea60
--- /dev/null
@@ -0,0 +1,56 @@
+## @file\r
+#  Component Description File For SD/MMC Pci Host Controller Pei Module.\r
+#\r
+#  Copyright (c) 2015, Intel Corporation. All rights reserved.<BR>\r
+#\r
+#  This program and the accompanying materials\r
+#  are licensed and made available under the terms and conditions of the BSD License\r
+#  which accompanies this distribution. The full text of the license may be found at\r
+#  http://opensource.org/licenses/bsd-license.php.\r
+#  THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+#  WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+#\r
+##\r
+\r
+[Defines]\r
+  INF_VERSION                    = 0x00010005\r
+  BASE_NAME                      = SdMmcPciHcPei\r
+  MODULE_UNI_FILE                = SdMmcPciHcPei.uni\r
+  FILE_GUID                      = 1BB737EF-427A-4144-8B3B-B76EF38515E6\r
+  MODULE_TYPE                    = PEIM\r
+  VERSION_STRING                 = 1.0\r
+\r
+  ENTRY_POINT                    = InitializeSdMmcHcPeim\r
+\r
+#\r
+# The following information is for reference only and not required by the build tools.\r
+#\r
+#  VALID_ARCHITECTURES           = IA32 X64 IPF EBC\r
+#\r
+\r
+[Sources]\r
+  SdMmcPciHcPei.c\r
+  SdMmcPciHcPei.h\r
+\r
+[Packages]\r
+  MdePkg/MdePkg.dec\r
+  MdeModulePkg/MdeModulePkg.dec\r
+\r
+[LibraryClasses]\r
+  PciLib\r
+  DebugLib\r
+  PeiServicesLib\r
+  MemoryAllocationLib\r
+  PeimEntryPoint\r
+\r
+[Pcd]\r
+  gEfiMdeModulePkgTokenSpaceGuid.PcdSdMmcPciHostControllerMmioBase   ## CONSUMES\r
+\r
+[Ppis]\r
+  gEdkiiPeiSdMmcHostControllerPpiGuid         ## PRODUCES\r
+\r
+[Depex]\r
+  gEfiPeiMasterBootModePpiGuid AND gEfiPeiMemoryDiscoveredPpiGuid\r
+\r
+[UserExtensions.TianoCore."ExtraFiles"]\r
+  SdMmcPciHcPeiExtra.uni
\ No newline at end of file
diff --git a/MdeModulePkg/Bus/Pci/SdMmcPciHcPei/SdMmcPciHcPei.uni b/MdeModulePkg/Bus/Pci/SdMmcPciHcPei/SdMmcPciHcPei.uni
new file mode 100644 (file)
index 0000000..0520cd2
--- /dev/null
@@ -0,0 +1,22 @@
+// /** @file\r
+// The SdMmcPciHcPei driver is used by upper layer to retrieve mmio base address\r
+// of managed pci-based SD/MMC host controller at PEI phase.\r
+//\r
+// Copyright (c) 2015, Intel Corporation. All rights reserved.<BR>\r
+//\r
+// This program and the accompanying materials\r
+// are licensed and made available under the terms and conditions\r
+// of the BSD License which accompanies this distribution.  The\r
+// full text of the license may be found at\r
+// http://opensource.org/licenses/bsd-license.php\r
+//\r
+// THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+// WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+//\r
+// **/\r
+\r
+\r
+#string STR_MODULE_ABSTRACT             #language en-US "Providing interface for upper layer to retrieve mmio base address of managed pci-based SD/MMC host controller at PEI phase."\r
+\r
+#string STR_MODULE_DESCRIPTION          #language en-US "It implements the interface of getting mmio base address of managed pci-based SD/MMC host controller at PEI phase."\r
+\r
diff --git a/MdeModulePkg/Bus/Pci/SdMmcPciHcPei/SdMmcPciHcPeiExtra.uni b/MdeModulePkg/Bus/Pci/SdMmcPciHcPei/SdMmcPciHcPeiExtra.uni
new file mode 100644 (file)
index 0000000..71c4fae
--- /dev/null
@@ -0,0 +1,21 @@
+// /** @file\r
+// SdMmcPciHcPei Localized Strings and Content\r
+//\r
+// Copyright (c) 2015, Intel Corporation. All rights reserved.<BR>\r
+//\r
+// This program and the accompanying materials\r
+// are licensed and made available under the terms and conditions\r
+// of the BSD License which accompanies this distribution.  The\r
+// full text of the license may be found at\r
+// http://opensource.org/licenses/bsd-license.php\r
+//\r
+// THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+// WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+//\r
+// **/\r
+\r
+#string STR_PROPERTIES_MODULE_NAME\r
+#language en-US\r
+"SD/MMC PCI-Based HC Module for Recovery"\r
+\r
+\r
diff --git a/MdeModulePkg/Bus/Sd/EmmcBlockIoPei/EmmcBlockIoPei.c b/MdeModulePkg/Bus/Sd/EmmcBlockIoPei/EmmcBlockIoPei.c
new file mode 100644 (file)
index 0000000..004670c
--- /dev/null
@@ -0,0 +1,807 @@
+/** @file\r
+\r
+  Copyright (c) 2015, Intel Corporation. All rights reserved.<BR>\r
+  This program and the accompanying materials\r
+  are licensed and made available under the terms and conditions of the BSD License\r
+  which accompanies this distribution.  The full text of the license may be found at\r
+  http://opensource.org/licenses/bsd-license.php\r
+\r
+  THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+  WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+\r
+**/\r
+\r
+#include "EmmcBlockIoPei.h"\r
+\r
+//\r
+// Template for EMMC HC Slot Data.\r
+//\r
+EMMC_PEIM_HC_SLOT   gEmmcHcSlotTemplate = {\r
+  EMMC_PEIM_SLOT_SIG,             // Signature\r
+  {                               // Media\r
+    {\r
+      MSG_EMMC_DP,\r
+      FALSE,\r
+      TRUE,\r
+      FALSE,\r
+      0x200,\r
+      0\r
+    },\r
+    {\r
+      MSG_EMMC_DP,\r
+      FALSE,\r
+      TRUE,\r
+      FALSE,\r
+      0x200,\r
+      0\r
+    },\r
+    {\r
+      MSG_EMMC_DP,\r
+      FALSE,\r
+      TRUE,\r
+      FALSE,\r
+      0x200,\r
+      0\r
+    },\r
+    {\r
+      MSG_EMMC_DP,\r
+      FALSE,\r
+      TRUE,\r
+      FALSE,\r
+      0x200,\r
+      0\r
+    },\r
+    {\r
+      MSG_EMMC_DP,\r
+      FALSE,\r
+      TRUE,\r
+      FALSE,\r
+      0x200,\r
+      0\r
+    },\r
+    {\r
+      MSG_EMMC_DP,\r
+      FALSE,\r
+      TRUE,\r
+      FALSE,\r
+      0x200,\r
+      0\r
+    },\r
+    {\r
+      MSG_EMMC_DP,\r
+      FALSE,\r
+      TRUE,\r
+      FALSE,\r
+      0x200,\r
+      0\r
+    },\r
+    {\r
+      MSG_EMMC_DP,\r
+      FALSE,\r
+      TRUE,\r
+      FALSE,\r
+      0x200,\r
+      0\r
+    }\r
+  },\r
+  0,                              // MediaNum\r
+  {                               // PartitionType\r
+    EmmcPartitionUnknown,\r
+    EmmcPartitionUnknown,\r
+    EmmcPartitionUnknown,\r
+    EmmcPartitionUnknown,\r
+    EmmcPartitionUnknown,\r
+    EmmcPartitionUnknown,\r
+    EmmcPartitionUnknown,\r
+    EmmcPartitionUnknown\r
+  },\r
+  0,                              // EmmcHcBase\r
+  {                               // Capability\r
+    0,\r
+  },\r
+  {                               // Csd\r
+    0,\r
+  },\r
+  {                               // ExtCsd\r
+    {0},\r
+  },\r
+  TRUE,                           // SectorAddressing\r
+  NULL                            // Private\r
+};\r
+\r
+//\r
+// Template for EMMC HC Private Data.\r
+//\r
+EMMC_PEIM_HC_PRIVATE_DATA gEmmcHcPrivateTemplate = {\r
+  EMMC_PEIM_SIG,                  // Signature\r
+  NULL,                           // Pool\r
+  {                               // BlkIoPpi\r
+    EmmcBlockIoPeimGetDeviceNo,\r
+    EmmcBlockIoPeimGetMediaInfo,\r
+    EmmcBlockIoPeimReadBlocks\r
+  },\r
+  {                               // BlkIo2Ppi\r
+    EFI_PEI_RECOVERY_BLOCK_IO2_PPI_REVISION,\r
+    EmmcBlockIoPeimGetDeviceNo2,\r
+    EmmcBlockIoPeimGetMediaInfo2,\r
+    EmmcBlockIoPeimReadBlocks2\r
+  },\r
+  {                               // BlkIoPpiList\r
+    EFI_PEI_PPI_DESCRIPTOR_PPI,\r
+    &gEfiPeiVirtualBlockIoPpiGuid,\r
+    NULL\r
+  },\r
+  {                               // BlkIo2PpiList\r
+    EFI_PEI_PPI_DESCRIPTOR_PPI | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST,\r
+    &gEfiPeiVirtualBlockIo2PpiGuid,\r
+    NULL\r
+  },\r
+  {                               // Slot\r
+    {\r
+      0,\r
+    },\r
+    {\r
+      0,\r
+    },\r
+    {\r
+      0,\r
+    },\r
+    {\r
+      0,\r
+    },\r
+    {\r
+      0,\r
+    },\r
+    {\r
+      0,\r
+    }\r
+  },\r
+  0,                              // SlotNum\r
+  0                               // TotalBlkIoDevices\r
+};\r
+/**\r
+  Gets the count of block I/O devices that one specific block driver detects.\r
+\r
+  This function is used for getting the count of block I/O devices that one\r
+  specific block driver detects.  To the PEI ATAPI driver, it returns the number\r
+  of all the detected ATAPI devices it detects during the enumeration process.\r
+  To the PEI legacy floppy driver, it returns the number of all the legacy\r
+  devices it finds during its enumeration process. If no device is detected,\r
+  then the function will return zero.\r
+\r
+  @param[in]  PeiServices          General-purpose services that are available\r
+                                   to every PEIM.\r
+  @param[in]  This                 Indicates the EFI_PEI_RECOVERY_BLOCK_IO_PPI\r
+                                   instance.\r
+  @param[out] NumberBlockDevices   The number of block I/O devices discovered.\r
+\r
+  @retval     EFI_SUCCESS          The operation performed successfully.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+EmmcBlockIoPeimGetDeviceNo (\r
+  IN  EFI_PEI_SERVICES               **PeiServices,\r
+  IN  EFI_PEI_RECOVERY_BLOCK_IO_PPI  *This,\r
+  OUT UINTN                          *NumberBlockDevices\r
+  )\r
+{\r
+  EMMC_PEIM_HC_PRIVATE_DATA   *Private;\r
+\r
+  Private = GET_EMMC_PEIM_HC_PRIVATE_DATA_FROM_THIS (This);\r
+  *NumberBlockDevices = Private->TotalBlkIoDevices;\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+  Gets a block device's media information.\r
+\r
+  This function will provide the caller with the specified block device's media\r
+  information. If the media changes, calling this function will update the media\r
+  information accordingly.\r
+\r
+  @param[in]  PeiServices   General-purpose services that are available to every\r
+                            PEIM\r
+  @param[in]  This          Indicates the EFI_PEI_RECOVERY_BLOCK_IO_PPI instance.\r
+  @param[in]  DeviceIndex   Specifies the block device to which the function wants\r
+                            to talk. Because the driver that implements Block I/O\r
+                            PPIs will manage multiple block devices, the PPIs that\r
+                            want to talk to a single device must specify the\r
+                            device index that was assigned during the enumeration\r
+                            process. This index is a number from one to\r
+                            NumberBlockDevices.\r
+  @param[out] MediaInfo     The media information of the specified block media.\r
+                            The caller is responsible for the ownership of this\r
+                            data structure.\r
+\r
+  @par Note:\r
+      The MediaInfo structure describes an enumeration of possible block device\r
+      types.  This enumeration exists because no device paths are actually passed\r
+      across interfaces that describe the type or class of hardware that is publishing\r
+      the block I/O interface. This enumeration will allow for policy decisions\r
+      in the Recovery PEIM, such as "Try to recover from legacy floppy first,\r
+      LS-120 second, CD-ROM third." If there are multiple partitions abstracted\r
+      by a given device type, they should be reported in ascending order; this\r
+      order also applies to nested partitions, such as legacy MBR, where the\r
+      outermost partitions would have precedence in the reporting order. The\r
+      same logic applies to systems such as IDE that have precedence relationships\r
+      like "Master/Slave" or "Primary/Secondary". The master device should be\r
+      reported first, the slave second.\r
+\r
+  @retval EFI_SUCCESS        Media information about the specified block device\r
+                             was obtained successfully.\r
+  @retval EFI_DEVICE_ERROR   Cannot get the media information due to a hardware\r
+                             error.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+EmmcBlockIoPeimGetMediaInfo (\r
+  IN  EFI_PEI_SERVICES               **PeiServices,\r
+  IN  EFI_PEI_RECOVERY_BLOCK_IO_PPI  *This,\r
+  IN  UINTN                          DeviceIndex,\r
+  OUT EFI_PEI_BLOCK_IO_MEDIA         *MediaInfo\r
+  )\r
+{\r
+  EMMC_PEIM_HC_PRIVATE_DATA          *Private;\r
+  UINT8                              SlotNum;\r
+  UINT8                              MediaNum;\r
+  UINT8                              Location;\r
+  BOOLEAN                            Found;\r
+\r
+  Found   = FALSE;\r
+  Private = GET_EMMC_PEIM_HC_PRIVATE_DATA_FROM_THIS (This);\r
+\r
+  if ((DeviceIndex == 0) || (DeviceIndex > Private->TotalBlkIoDevices)) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  Location = 0;\r
+  MediaNum = 0;\r
+  for (SlotNum = 0; SlotNum < Private->SlotNum; SlotNum++) {\r
+    for (MediaNum = 0; MediaNum < Private->Slot[SlotNum].MediaNum; MediaNum++) {\r
+      Location ++;\r
+      if (Location == DeviceIndex) {\r
+        Found = TRUE;\r
+        break;\r
+      }\r
+    }\r
+    if (Found) {\r
+      break;\r
+    }\r
+  }\r
+\r
+  MediaInfo->DeviceType   = EMMC;\r
+  MediaInfo->MediaPresent = TRUE;\r
+  MediaInfo->LastBlock    = (UINTN)Private->Slot[SlotNum].Media[MediaNum].LastBlock;\r
+  MediaInfo->BlockSize    = Private->Slot[SlotNum].Media[MediaNum].BlockSize;\r
+\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+  Reads the requested number of blocks from the specified block device.\r
+\r
+  The function reads the requested number of blocks from the device. All the\r
+  blocks are read, or an error is returned. If there is no media in the device,\r
+  the function returns EFI_NO_MEDIA.\r
+\r
+  @param[in]  PeiServices   General-purpose services that are available to\r
+                            every PEIM.\r
+  @param[in]  This          Indicates the EFI_PEI_RECOVERY_BLOCK_IO_PPI instance.\r
+  @param[in]  DeviceIndex   Specifies the block device to which the function wants\r
+                            to talk. Because the driver that implements Block I/O\r
+                            PPIs will manage multiple block devices, PPIs that\r
+                            want to talk to a single device must specify the device\r
+                            index that was assigned during the enumeration process.\r
+                            This index is a number from one to NumberBlockDevices.\r
+  @param[in]  StartLBA      The starting logical block address (LBA) to read from\r
+                            on the device\r
+  @param[in]  BufferSize    The size of the Buffer in bytes. This number must be\r
+                            a multiple of the intrinsic block size of the device.\r
+  @param[out] Buffer        A pointer to the destination buffer for the data.\r
+                            The caller is responsible for the ownership of the\r
+                            buffer.\r
+\r
+  @retval EFI_SUCCESS             The data was read correctly from the device.\r
+  @retval EFI_DEVICE_ERROR        The device reported an error while attempting\r
+                                  to perform the read operation.\r
+  @retval EFI_INVALID_PARAMETER   The read request contains LBAs that are not\r
+                                  valid, or the buffer is not properly aligned.\r
+  @retval EFI_NO_MEDIA            There is no media in the device.\r
+  @retval EFI_BAD_BUFFER_SIZE     The BufferSize parameter is not a multiple of\r
+                                  the intrinsic block size of the device.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+EmmcBlockIoPeimReadBlocks (\r
+  IN  EFI_PEI_SERVICES               **PeiServices,\r
+  IN  EFI_PEI_RECOVERY_BLOCK_IO_PPI  *This,\r
+  IN  UINTN                          DeviceIndex,\r
+  IN  EFI_PEI_LBA                    StartLBA,\r
+  IN  UINTN                          BufferSize,\r
+  OUT VOID                           *Buffer\r
+  )\r
+{\r
+  EFI_STATUS                         Status;\r
+  UINT32                             BlockSize;\r
+  UINTN                              NumberOfBlocks;\r
+  EMMC_PEIM_HC_PRIVATE_DATA          *Private;\r
+  UINT8                              SlotNum;\r
+  UINT8                              MediaNum;\r
+  UINT8                              Location;\r
+  UINT8                              PartitionConfig;\r
+  UINTN                              Remaining;\r
+  UINT32                             MaxBlock;\r
+  BOOLEAN                            Found;\r
+\r
+  Status  = EFI_SUCCESS;\r
+  Found   = FALSE;\r
+  Private = GET_EMMC_PEIM_HC_PRIVATE_DATA_FROM_THIS (This);\r
+\r
+  //\r
+  // Check parameters\r
+  //\r
+  if (Buffer == NULL) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  if (BufferSize == 0) {\r
+    return EFI_SUCCESS;\r
+  }\r
+\r
+  if ((DeviceIndex == 0) || (DeviceIndex > Private->TotalBlkIoDevices)) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  Location = 0;\r
+  MediaNum = 0;\r
+  for (SlotNum = 0; SlotNum < Private->SlotNum; SlotNum++) {\r
+    for (MediaNum = 0; MediaNum < Private->Slot[SlotNum].MediaNum; MediaNum++) {\r
+      Location ++;\r
+      if (Location == DeviceIndex) {\r
+        Found = TRUE;\r
+        break;\r
+      }\r
+    }\r
+    if (Found) {\r
+      break;\r
+    }\r
+  }\r
+\r
+  BlockSize = Private->Slot[SlotNum].Media[MediaNum].BlockSize;\r
+  if (BufferSize % BlockSize != 0) {\r
+    return EFI_BAD_BUFFER_SIZE;\r
+  }\r
+\r
+  if (StartLBA > Private->Slot[SlotNum].Media[MediaNum].LastBlock) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  NumberOfBlocks = BufferSize / BlockSize;\r
+\r
+  //\r
+  // Check if needs to switch partition access.\r
+  //\r
+  PartitionConfig = Private->Slot[SlotNum].ExtCsd.PartitionConfig;\r
+  if ((PartitionConfig & 0x7) != Private->Slot[SlotNum].PartitionType[MediaNum]) {\r
+    PartitionConfig &= (UINT8)~0x7;\r
+    PartitionConfig |= Private->Slot[SlotNum].PartitionType[MediaNum];\r
+    Status = EmmcPeimSwitch (\r
+               &Private->Slot[SlotNum],\r
+               0x3,\r
+               OFFSET_OF (EMMC_EXT_CSD, PartitionConfig),\r
+               PartitionConfig,\r
+               0x0\r
+               );\r
+    if (EFI_ERROR (Status)) {\r
+      return Status;\r
+    }\r
+    Private->Slot[SlotNum].ExtCsd.PartitionConfig = PartitionConfig;\r
+  }\r
+  //\r
+  // Start to execute data transfer. The max block number in single cmd is 65535 blocks.\r
+  //\r
+  Remaining = NumberOfBlocks;\r
+  MaxBlock  = 0xFFFF;\r
+\r
+  while (Remaining > 0) {\r
+    if (Remaining <= MaxBlock) {\r
+      NumberOfBlocks = Remaining;\r
+    } else {\r
+      NumberOfBlocks = MaxBlock;\r
+    }\r
+\r
+    Status = EmmcPeimSetBlkCount (&Private->Slot[SlotNum], (UINT16)NumberOfBlocks);\r
+    if (EFI_ERROR (Status)) {\r
+      return Status;\r
+    }\r
+\r
+    BufferSize = NumberOfBlocks * BlockSize;\r
+    Status = EmmcPeimRwMultiBlocks (&Private->Slot[SlotNum], StartLBA, BlockSize, Buffer, BufferSize, TRUE);\r
+    if (EFI_ERROR (Status)) {\r
+      return Status;\r
+    }\r
+\r
+    StartLBA  += NumberOfBlocks;\r
+    Buffer     = (UINT8*)Buffer + BufferSize;\r
+    Remaining -= NumberOfBlocks;\r
+  }\r
+  return Status;\r
+}\r
+\r
+/**\r
+  Gets the count of block I/O devices that one specific block driver detects.\r
+\r
+  This function is used for getting the count of block I/O devices that one\r
+  specific block driver detects.  To the PEI ATAPI driver, it returns the number\r
+  of all the detected ATAPI devices it detects during the enumeration process.\r
+  To the PEI legacy floppy driver, it returns the number of all the legacy\r
+  devices it finds during its enumeration process. If no device is detected,\r
+  then the function will return zero.\r
+\r
+  @param[in]  PeiServices          General-purpose services that are available\r
+                                   to every PEIM.\r
+  @param[in]  This                 Indicates the EFI_PEI_RECOVERY_BLOCK_IO2_PPI\r
+                                   instance.\r
+  @param[out] NumberBlockDevices   The number of block I/O devices discovered.\r
+\r
+  @retval     EFI_SUCCESS          The operation performed successfully.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+EmmcBlockIoPeimGetDeviceNo2 (\r
+  IN  EFI_PEI_SERVICES               **PeiServices,\r
+  IN  EFI_PEI_RECOVERY_BLOCK_IO2_PPI *This,\r
+  OUT UINTN                          *NumberBlockDevices\r
+  )\r
+{\r
+  EMMC_PEIM_HC_PRIVATE_DATA   *Private;\r
+\r
+  Private = GET_EMMC_PEIM_HC_PRIVATE_DATA_FROM_THIS2 (This);\r
+  *NumberBlockDevices = Private->TotalBlkIoDevices;\r
+\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+  Gets a block device's media information.\r
+\r
+  This function will provide the caller with the specified block device's media\r
+  information. If the media changes, calling this function will update the media\r
+  information accordingly.\r
+\r
+  @param[in]  PeiServices   General-purpose services that are available to every\r
+                            PEIM\r
+  @param[in]  This          Indicates the EFI_PEI_RECOVERY_BLOCK_IO2_PPI instance.\r
+  @param[in]  DeviceIndex   Specifies the block device to which the function wants\r
+                            to talk. Because the driver that implements Block I/O\r
+                            PPIs will manage multiple block devices, the PPIs that\r
+                            want to talk to a single device must specify the\r
+                            device index that was assigned during the enumeration\r
+                            process. This index is a number from one to\r
+                            NumberBlockDevices.\r
+  @param[out] MediaInfo     The media information of the specified block media.\r
+                            The caller is responsible for the ownership of this\r
+                            data structure.\r
+\r
+  @par Note:\r
+      The MediaInfo structure describes an enumeration of possible block device\r
+      types.  This enumeration exists because no device paths are actually passed\r
+      across interfaces that describe the type or class of hardware that is publishing\r
+      the block I/O interface. This enumeration will allow for policy decisions\r
+      in the Recovery PEIM, such as "Try to recover from legacy floppy first,\r
+      LS-120 second, CD-ROM third." If there are multiple partitions abstracted\r
+      by a given device type, they should be reported in ascending order; this\r
+      order also applies to nested partitions, such as legacy MBR, where the\r
+      outermost partitions would have precedence in the reporting order. The\r
+      same logic applies to systems such as IDE that have precedence relationships\r
+      like "Master/Slave" or "Primary/Secondary". The master device should be\r
+      reported first, the slave second.\r
+\r
+  @retval EFI_SUCCESS        Media information about the specified block device\r
+                             was obtained successfully.\r
+  @retval EFI_DEVICE_ERROR   Cannot get the media information due to a hardware\r
+                             error.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+EmmcBlockIoPeimGetMediaInfo2 (\r
+  IN  EFI_PEI_SERVICES               **PeiServices,\r
+  IN  EFI_PEI_RECOVERY_BLOCK_IO2_PPI *This,\r
+  IN  UINTN                          DeviceIndex,\r
+  OUT EFI_PEI_BLOCK_IO2_MEDIA        *MediaInfo\r
+  )\r
+{\r
+  EFI_STATUS                         Status;\r
+  EMMC_PEIM_HC_PRIVATE_DATA          *Private;\r
+  EFI_PEI_BLOCK_IO_MEDIA             Media;\r
+  UINT8                              SlotNum;\r
+  UINT8                              MediaNum;\r
+  UINT8                              Location;\r
+  BOOLEAN                            Found;\r
+\r
+  Found   = FALSE;\r
+  Private = GET_EMMC_PEIM_HC_PRIVATE_DATA_FROM_THIS2 (This);\r
+\r
+  Status  = EmmcBlockIoPeimGetMediaInfo (\r
+              PeiServices,\r
+              &Private->BlkIoPpi,\r
+              DeviceIndex,\r
+              &Media\r
+              );\r
+  if (EFI_ERROR (Status)) {\r
+    return Status;\r
+  }\r
+\r
+  Location = 0;\r
+  MediaNum = 0;\r
+  for (SlotNum = 0; SlotNum < Private->SlotNum; SlotNum++) {\r
+    for (MediaNum = 0; MediaNum < Private->Slot[SlotNum].MediaNum; MediaNum++) {\r
+      Location ++;\r
+      if (Location == DeviceIndex) {\r
+        Found = TRUE;\r
+        break;\r
+      }\r
+    }\r
+    if (Found) {\r
+      break;\r
+    }\r
+  }\r
+\r
+  CopyMem (MediaInfo, &(Private->Slot[SlotNum].Media[MediaNum]), sizeof (EFI_PEI_BLOCK_IO2_MEDIA));\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+  Reads the requested number of blocks from the specified block device.\r
+\r
+  The function reads the requested number of blocks from the device. All the\r
+  blocks are read, or an error is returned. If there is no media in the device,\r
+  the function returns EFI_NO_MEDIA.\r
+\r
+  @param[in]  PeiServices   General-purpose services that are available to\r
+                            every PEIM.\r
+  @param[in]  This          Indicates the EFI_PEI_RECOVERY_BLOCK_IO2_PPI instance.\r
+  @param[in]  DeviceIndex   Specifies the block device to which the function wants\r
+                            to talk. Because the driver that implements Block I/O\r
+                            PPIs will manage multiple block devices, PPIs that\r
+                            want to talk to a single device must specify the device\r
+                            index that was assigned during the enumeration process.\r
+                            This index is a number from one to NumberBlockDevices.\r
+  @param[in]  StartLBA      The starting logical block address (LBA) to read from\r
+                            on the device\r
+  @param[in]  BufferSize    The size of the Buffer in bytes. This number must be\r
+                            a multiple of the intrinsic block size of the device.\r
+  @param[out] Buffer        A pointer to the destination buffer for the data.\r
+                            The caller is responsible for the ownership of the\r
+                            buffer.\r
+\r
+  @retval EFI_SUCCESS             The data was read correctly from the device.\r
+  @retval EFI_DEVICE_ERROR        The device reported an error while attempting\r
+                                  to perform the read operation.\r
+  @retval EFI_INVALID_PARAMETER   The read request contains LBAs that are not\r
+                                  valid, or the buffer is not properly aligned.\r
+  @retval EFI_NO_MEDIA            There is no media in the device.\r
+  @retval EFI_BAD_BUFFER_SIZE     The BufferSize parameter is not a multiple of\r
+                                  the intrinsic block size of the device.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+EmmcBlockIoPeimReadBlocks2 (\r
+  IN  EFI_PEI_SERVICES               **PeiServices,\r
+  IN  EFI_PEI_RECOVERY_BLOCK_IO2_PPI *This,\r
+  IN  UINTN                          DeviceIndex,\r
+  IN  EFI_PEI_LBA                    StartLBA,\r
+  IN  UINTN                          BufferSize,\r
+  OUT VOID                           *Buffer\r
+  )\r
+{\r
+  EFI_STATUS                         Status;\r
+  EMMC_PEIM_HC_PRIVATE_DATA          *Private;\r
+\r
+  Status    = EFI_SUCCESS;\r
+  Private   = GET_EMMC_PEIM_HC_PRIVATE_DATA_FROM_THIS2 (This);\r
+\r
+  Status  = EmmcBlockIoPeimReadBlocks (\r
+              PeiServices,\r
+              &Private->BlkIoPpi,\r
+              DeviceIndex,\r
+              StartLBA,\r
+              BufferSize,\r
+              Buffer\r
+              );\r
+  return Status;\r
+}\r
+\r
+/**\r
+  The user code starts with this function.\r
+\r
+  @param  FileHandle             Handle of the file being invoked.\r
+  @param  PeiServices            Describes the list of possible PEI Services.\r
+\r
+  @retval EFI_SUCCESS            The driver is successfully initialized.\r
+  @retval Others                 Can't initialize the driver.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+InitializeEmmcBlockIoPeim (\r
+  IN EFI_PEI_FILE_HANDLE        FileHandle,\r
+  IN CONST EFI_PEI_SERVICES     **PeiServices\r
+  )\r
+{\r
+  EFI_STATUS                       Status;\r
+  EMMC_PEIM_HC_PRIVATE_DATA        *Private;\r
+  EDKII_SD_MMC_HOST_CONTROLLER_PPI *SdMmcHcPpi;\r
+  UINT32                           Index;\r
+  UINT32                           PartitionIndex;\r
+  UINTN                            *MmioBase;\r
+  UINT8                            BarNum;\r
+  UINT8                            SlotNum;\r
+  UINT8                            MediaNum;\r
+  UINT8                            Controller;\r
+  UINT64                           Capacity;\r
+  EMMC_EXT_CSD                     *ExtCsd;\r
+  EMMC_HC_SLOT_CAP                 Capability;\r
+  EMMC_PEIM_HC_SLOT                *Slot;\r
+  UINT32                           SecCount;\r
+  UINT32                           GpSizeMult;\r
+\r
+  //\r
+  // Shadow this PEIM to run from memory\r
+  //\r
+  if (!EFI_ERROR (PeiServicesRegisterForShadow (FileHandle))) {\r
+    return EFI_SUCCESS;\r
+  }\r
+\r
+  //\r
+  // locate Emmc host controller PPI\r
+  //\r
+  Status = PeiServicesLocatePpi (\r
+             &gEdkiiPeiSdMmcHostControllerPpiGuid,\r
+             0,\r
+             NULL,\r
+             (VOID **) &SdMmcHcPpi\r
+             );\r
+  if (EFI_ERROR (Status)) {\r
+    return EFI_DEVICE_ERROR;\r
+  }\r
+\r
+  Controller = 0;\r
+  MmioBase   = NULL;\r
+  while (TRUE) {\r
+    Status = SdMmcHcPpi->GetSdMmcHcMmioBar (SdMmcHcPpi, Controller, &MmioBase, &BarNum);\r
+    //\r
+    // When status is error, meant no controller is found\r
+    //\r
+    if (EFI_ERROR (Status)) {\r
+      break;\r
+    }\r
+\r
+    if (BarNum == 0) {\r
+      Controller++;\r
+      continue;\r
+    }\r
+\r
+    Private = AllocateCopyPool (sizeof (EMMC_PEIM_HC_PRIVATE_DATA), &gEmmcHcPrivateTemplate);\r
+    if (Private == NULL) {\r
+      Status = EFI_OUT_OF_RESOURCES;\r
+      break;\r
+    }\r
+    Private->BlkIoPpiList.Ppi  = (VOID*)&Private->BlkIoPpi;\r
+    Private->BlkIo2PpiList.Ppi = (VOID*)&Private->BlkIo2Ppi;\r
+    //\r
+    // Initialize the memory pool which will be used in all transactions.\r
+    //\r
+    Status = EmmcPeimInitMemPool (Private);\r
+    if (EFI_ERROR (Status)) {\r
+      Status = EFI_OUT_OF_RESOURCES;\r
+      break;\r
+    }\r
+\r
+    for (Index = 0; Index < BarNum; Index++) {\r
+      Status = EmmcPeimHcGetCapability (MmioBase[Index], &Capability);\r
+      if (EFI_ERROR (Status)) {\r
+        continue;\r
+      }\r
+      if (Capability.SlotType != 0x1) {\r
+        DEBUG ((EFI_D_INFO, "The slot at 0x%x is not embedded slot type\n", MmioBase[Index]));\r
+        Status = EFI_UNSUPPORTED;\r
+        continue;\r
+      }\r
+\r
+      Status = EmmcPeimHcReset (MmioBase[Index]);\r
+      if (EFI_ERROR (Status)) {\r
+        continue;\r
+      }\r
+      Status = EmmcPeimHcCardDetect (MmioBase[Index]);\r
+      if (EFI_ERROR (Status)) {\r
+        continue;\r
+      }\r
+      Status = EmmcPeimHcInitHost (MmioBase[Index]);\r
+      if (EFI_ERROR (Status)) {\r
+        continue;\r
+      }\r
+\r
+      SlotNum = Private->SlotNum;\r
+      Slot    = &Private->Slot[SlotNum];\r
+      CopyMem (Slot, &gEmmcHcSlotTemplate, sizeof (EMMC_PEIM_HC_SLOT));\r
+      Slot->Private    = Private;\r
+      Slot->EmmcHcBase = MmioBase[Index];\r
+      CopyMem (&Slot->Capability, &Capability, sizeof (Capability));\r
+\r
+      Status = EmmcPeimIdentification (Slot);\r
+      if (EFI_ERROR (Status)) {\r
+        continue;\r
+      }\r
+\r
+      ExtCsd = &Slot->ExtCsd;\r
+      if (ExtCsd->ExtCsdRev < 5) {\r
+        DEBUG ((EFI_D_ERROR, "The EMMC device version is too low, we don't support!!!\n"));\r
+        Status = EFI_UNSUPPORTED;\r
+        continue;\r
+      }\r
+      if ((ExtCsd->PartitioningSupport & BIT0) != BIT0) {\r
+        DEBUG ((EFI_D_ERROR, "The EMMC device doesn't support Partition Feature!!!\n"));\r
+        Status = EFI_UNSUPPORTED;\r
+        continue;\r
+      }\r
+\r
+      for (PartitionIndex = 0; PartitionIndex < EMMC_PEIM_MAX_PARTITIONS; PartitionIndex++) {\r
+        switch (PartitionIndex) {\r
+          case EmmcPartitionUserData:\r
+            SecCount = *(UINT32*)&ExtCsd->SecCount;\r
+            Capacity = MultU64x32 ((UINT64)SecCount, 0x200);\r
+            break;\r
+          case EmmcPartitionBoot1:\r
+          case EmmcPartitionBoot2:\r
+            Capacity = ExtCsd->BootSizeMult * SIZE_128KB;\r
+            break;\r
+          case EmmcPartitionRPMB:\r
+            Capacity = ExtCsd->RpmbSizeMult * SIZE_128KB;\r
+            break;\r
+          case EmmcPartitionGP1:\r
+            GpSizeMult = (ExtCsd->GpSizeMult[0] | (ExtCsd->GpSizeMult[1] << 8) | (ExtCsd->GpSizeMult[2] << 16));\r
+            Capacity = MultU64x32 (MultU64x32 (MultU64x32 ((UINT64)GpSizeMult, ExtCsd->HcWpGrpSize), ExtCsd->HcEraseGrpSize), SIZE_512KB);\r
+            break;\r
+          case EmmcPartitionGP2:\r
+            GpSizeMult = (ExtCsd->GpSizeMult[3] | (ExtCsd->GpSizeMult[4] << 8) | (ExtCsd->GpSizeMult[5] << 16));\r
+            Capacity = MultU64x32 (MultU64x32 (MultU64x32 ((UINT64)GpSizeMult, ExtCsd->HcWpGrpSize), ExtCsd->HcEraseGrpSize), SIZE_512KB);\r
+            break;\r
+          case EmmcPartitionGP3:\r
+            GpSizeMult = (ExtCsd->GpSizeMult[6] | (ExtCsd->GpSizeMult[7] << 8) | (ExtCsd->GpSizeMult[8] << 16));\r
+            Capacity = MultU64x32 (MultU64x32 (MultU64x32 ((UINT64)GpSizeMult, ExtCsd->HcWpGrpSize), ExtCsd->HcEraseGrpSize), SIZE_512KB);\r
+            break;\r
+          case EmmcPartitionGP4:\r
+            GpSizeMult = (ExtCsd->GpSizeMult[9] | (ExtCsd->GpSizeMult[10] << 8) | (ExtCsd->GpSizeMult[11] << 16));\r
+            Capacity = MultU64x32 (MultU64x32 (MultU64x32 ((UINT64)GpSizeMult, ExtCsd->HcWpGrpSize), ExtCsd->HcEraseGrpSize), SIZE_512KB);\r
+            break;\r
+          default:\r
+            ASSERT (FALSE);\r
+            continue;\r
+        }\r
+\r
+        MediaNum = Slot->MediaNum;\r
+        if (Capacity != 0) {\r
+          Slot->Media[MediaNum].LastBlock = DivU64x32 (Capacity, Slot->Media[MediaNum].BlockSize) - 1;\r
+          Slot->PartitionType[MediaNum] = PartitionIndex;\r
+          Private->TotalBlkIoDevices++;\r
+          Slot->MediaNum++;\r
+        }\r
+      }\r
+      Private->SlotNum++;\r
+    }\r
+    Controller++;\r
+\r
+    if (!EFI_ERROR (Status)) {\r
+      PeiServicesInstallPpi (&Private->BlkIoPpiList);\r
+    }\r
+  }\r
+\r
+  return EFI_SUCCESS;\r
+}\r
diff --git a/MdeModulePkg/Bus/Sd/EmmcBlockIoPei/EmmcBlockIoPei.h b/MdeModulePkg/Bus/Sd/EmmcBlockIoPei/EmmcBlockIoPei.h
new file mode 100644 (file)
index 0000000..5c8b740
--- /dev/null
@@ -0,0 +1,381 @@
+/** @file\r
+\r
+  Copyright (c) 2015, Intel Corporation. All rights reserved.<BR>\r
+  This program and the accompanying materials\r
+  are licensed and made available under the terms and conditions of the BSD License\r
+  which accompanies this distribution.  The full text of the license may be found at\r
+  http://opensource.org/licenses/bsd-license.php\r
+\r
+  THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+  WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+\r
+**/\r
+\r
+#ifndef _EMMC_BLOCK_IO_PEI_H_\r
+#define _EMMC_BLOCK_IO_PEI_H_\r
+\r
+#include <PiPei.h>\r
+\r
+#include <Ppi/SdMmcHostController.h>\r
+#include <Ppi/BlockIo.h>\r
+#include <Ppi/BlockIo2.h>\r
+\r
+#include <Library/DebugLib.h>\r
+#include <Library/BaseLib.h>\r
+#include <Library/BaseMemoryLib.h>\r
+#include <Library/MemoryAllocationLib.h>\r
+#include <Library/IoLib.h>\r
+#include <Library/TimerLib.h>\r
+#include <Library/PeiServicesLib.h>\r
+\r
+#include <IndustryStandard/Emmc.h>\r
+\r
+typedef struct _EMMC_PEIM_HC_PRIVATE_DATA EMMC_PEIM_HC_PRIVATE_DATA;\r
+typedef struct _EMMC_PEIM_HC_SLOT         EMMC_PEIM_HC_SLOT;\r
+typedef struct _EMMC_TRB                  EMMC_TRB;\r
+\r
+#include "EmmcHci.h"\r
+#include "EmmcHcMem.h"\r
+\r
+#define EMMC_PEIM_SIG               SIGNATURE_32 ('E', 'M', 'C', 'P')\r
+#define EMMC_PEIM_SLOT_SIG          SIGNATURE_32 ('E', 'M', 'C', 'S')\r
+\r
+#define EMMC_PEIM_MAX_SLOTS         6\r
+#define EMMC_PEIM_MAX_PARTITIONS    8\r
+\r
+struct _EMMC_PEIM_HC_SLOT {\r
+  UINT32                            Signature;\r
+  EFI_PEI_BLOCK_IO2_MEDIA           Media[EMMC_PEIM_MAX_PARTITIONS];\r
+  UINT8                             MediaNum;\r
+  EMMC_PARTITION_TYPE               PartitionType[EMMC_PEIM_MAX_PARTITIONS];\r
+\r
+  UINTN                             EmmcHcBase;\r
+  EMMC_HC_SLOT_CAP                  Capability;\r
+  EMMC_CSD                          Csd;\r
+  EMMC_EXT_CSD                      ExtCsd;\r
+  BOOLEAN                           SectorAddressing;\r
+  EMMC_PEIM_HC_PRIVATE_DATA         *Private;\r
+};\r
+\r
+struct _EMMC_PEIM_HC_PRIVATE_DATA {\r
+  UINT32                            Signature;\r
+  EMMC_PEIM_MEM_POOL                *Pool;\r
+  EFI_PEI_RECOVERY_BLOCK_IO_PPI     BlkIoPpi;\r
+  EFI_PEI_RECOVERY_BLOCK_IO2_PPI    BlkIo2Ppi;\r
+  EFI_PEI_PPI_DESCRIPTOR            BlkIoPpiList;\r
+  EFI_PEI_PPI_DESCRIPTOR            BlkIo2PpiList;\r
+  EMMC_PEIM_HC_SLOT                 Slot[EMMC_PEIM_MAX_SLOTS];\r
+  UINT8                             SlotNum;\r
+  UINT8                             TotalBlkIoDevices;\r
+};\r
+\r
+#define EMMC_TIMEOUT                MultU64x32((UINT64)(3), 1000000)\r
+#define GET_EMMC_PEIM_HC_PRIVATE_DATA_FROM_THIS(a) CR (a, EMMC_PEIM_HC_PRIVATE_DATA, BlkIoPpi, EMMC_PEIM_SIG)\r
+#define GET_EMMC_PEIM_HC_PRIVATE_DATA_FROM_THIS2(a) CR (a, EMMC_PEIM_HC_PRIVATE_DATA, BlkIo2Ppi, EMMC_PEIM_SIG)\r
+\r
+struct _EMMC_TRB {\r
+  EMMC_PEIM_HC_SLOT                   *Slot;\r
+  UINT16                              BlockSize;\r
+\r
+  EMMC_COMMAND_PACKET                 *Packet;\r
+  VOID                                *Data;\r
+  UINT32                              DataLen;\r
+  BOOLEAN                             Read;\r
+  EMMC_HC_TRANSFER_MODE               Mode;\r
+\r
+  UINT64                              Timeout;\r
+\r
+  EMMC_HC_ADMA_DESC_LINE              *AdmaDesc;\r
+  UINTN                               AdmaDescSize;\r
+};\r
+\r
+/**\r
+  Gets the count of block I/O devices that one specific block driver detects.\r
+\r
+  This function is used for getting the count of block I/O devices that one\r
+  specific block driver detects.  To the PEI ATAPI driver, it returns the number\r
+  of all the detected ATAPI devices it detects during the enumeration process.\r
+  To the PEI legacy floppy driver, it returns the number of all the legacy\r
+  devices it finds during its enumeration process. If no device is detected,\r
+  then the function will return zero.\r
+\r
+  @param[in]  PeiServices          General-purpose services that are available\r
+                                   to every PEIM.\r
+  @param[in]  This                 Indicates the EFI_PEI_RECOVERY_BLOCK_IO_PPI\r
+                                   instance.\r
+  @param[out] NumberBlockDevices   The number of block I/O devices discovered.\r
+\r
+  @retval     EFI_SUCCESS          The operation performed successfully.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+EmmcBlockIoPeimGetDeviceNo (\r
+  IN  EFI_PEI_SERVICES               **PeiServices,\r
+  IN  EFI_PEI_RECOVERY_BLOCK_IO_PPI  *This,\r
+  OUT UINTN                          *NumberBlockDevices\r
+  );\r
+\r
+/**\r
+  Gets a block device's media information.\r
+\r
+  This function will provide the caller with the specified block device's media\r
+  information. If the media changes, calling this function will update the media\r
+  information accordingly.\r
+\r
+  @param[in]  PeiServices   General-purpose services that are available to every\r
+                            PEIM\r
+  @param[in]  This          Indicates the EFI_PEI_RECOVERY_BLOCK_IO_PPI instance.\r
+  @param[in]  DeviceIndex   Specifies the block device to which the function wants\r
+                            to talk. Because the driver that implements Block I/O\r
+                            PPIs will manage multiple block devices, the PPIs that\r
+                            want to talk to a single device must specify the\r
+                            device index that was assigned during the enumeration\r
+                            process. This index is a number from one to\r
+                            NumberBlockDevices.\r
+  @param[out] MediaInfo     The media information of the specified block media.\r
+                            The caller is responsible for the ownership of this\r
+                            data structure.\r
+\r
+  @par Note:\r
+      The MediaInfo structure describes an enumeration of possible block device\r
+      types.  This enumeration exists because no device paths are actually passed\r
+      across interfaces that describe the type or class of hardware that is publishing\r
+      the block I/O interface. This enumeration will allow for policy decisions\r
+      in the Recovery PEIM, such as "Try to recover from legacy floppy first,\r
+      LS-120 second, CD-ROM third." If there are multiple partitions abstracted\r
+      by a given device type, they should be reported in ascending order; this\r
+      order also applies to nested partitions, such as legacy MBR, where the\r
+      outermost partitions would have precedence in the reporting order. The\r
+      same logic applies to systems such as IDE that have precedence relationships\r
+      like "Master/Slave" or "Primary/Secondary". The master device should be\r
+      reported first, the slave second.\r
+\r
+  @retval EFI_SUCCESS        Media information about the specified block device\r
+                             was obtained successfully.\r
+  @retval EFI_DEVICE_ERROR   Cannot get the media information due to a hardware\r
+                             error.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+EmmcBlockIoPeimGetMediaInfo (\r
+  IN  EFI_PEI_SERVICES               **PeiServices,\r
+  IN  EFI_PEI_RECOVERY_BLOCK_IO_PPI  *This,\r
+  IN  UINTN                          DeviceIndex,\r
+  OUT EFI_PEI_BLOCK_IO_MEDIA         *MediaInfo\r
+  );\r
+\r
+/**\r
+  Reads the requested number of blocks from the specified block device.\r
+\r
+  The function reads the requested number of blocks from the device. All the\r
+  blocks are read, or an error is returned. If there is no media in the device,\r
+  the function returns EFI_NO_MEDIA.\r
+\r
+  @param[in]  PeiServices   General-purpose services that are available to\r
+                            every PEIM.\r
+  @param[in]  This          Indicates the EFI_PEI_RECOVERY_BLOCK_IO_PPI instance.\r
+  @param[in]  DeviceIndex   Specifies the block device to which the function wants\r
+                            to talk. Because the driver that implements Block I/O\r
+                            PPIs will manage multiple block devices, PPIs that\r
+                            want to talk to a single device must specify the device\r
+                            index that was assigned during the enumeration process.\r
+                            This index is a number from one to NumberBlockDevices.\r
+  @param[in]  StartLBA      The starting logical block address (LBA) to read from\r
+                            on the device\r
+  @param[in]  BufferSize    The size of the Buffer in bytes. This number must be\r
+                            a multiple of the intrinsic block size of the device.\r
+  @param[out] Buffer        A pointer to the destination buffer for the data.\r
+                            The caller is responsible for the ownership of the\r
+                            buffer.\r
+\r
+  @retval EFI_SUCCESS             The data was read correctly from the device.\r
+  @retval EFI_DEVICE_ERROR        The device reported an error while attempting\r
+                                  to perform the read operation.\r
+  @retval EFI_INVALID_PARAMETER   The read request contains LBAs that are not\r
+                                  valid, or the buffer is not properly aligned.\r
+  @retval EFI_NO_MEDIA            There is no media in the device.\r
+  @retval EFI_BAD_BUFFER_SIZE     The BufferSize parameter is not a multiple of\r
+                                  the intrinsic block size of the device.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+EmmcBlockIoPeimReadBlocks (\r
+  IN  EFI_PEI_SERVICES               **PeiServices,\r
+  IN  EFI_PEI_RECOVERY_BLOCK_IO_PPI  *This,\r
+  IN  UINTN                          DeviceIndex,\r
+  IN  EFI_PEI_LBA                    StartLBA,\r
+  IN  UINTN                          BufferSize,\r
+  OUT VOID                           *Buffer\r
+  );\r
+\r
+/**\r
+  Gets the count of block I/O devices that one specific block driver detects.\r
+\r
+  This function is used for getting the count of block I/O devices that one\r
+  specific block driver detects.  To the PEI ATAPI driver, it returns the number\r
+  of all the detected ATAPI devices it detects during the enumeration process.\r
+  To the PEI legacy floppy driver, it returns the number of all the legacy\r
+  devices it finds during its enumeration process. If no device is detected,\r
+  then the function will return zero.\r
+\r
+  @param[in]  PeiServices          General-purpose services that are available\r
+                                   to every PEIM.\r
+  @param[in]  This                 Indicates the EFI_PEI_RECOVERY_BLOCK_IO2_PPI\r
+                                   instance.\r
+  @param[out] NumberBlockDevices   The number of block I/O devices discovered.\r
+\r
+  @retval     EFI_SUCCESS          The operation performed successfully.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+EmmcBlockIoPeimGetDeviceNo2 (\r
+  IN  EFI_PEI_SERVICES               **PeiServices,\r
+  IN  EFI_PEI_RECOVERY_BLOCK_IO2_PPI *This,\r
+  OUT UINTN                          *NumberBlockDevices\r
+  );\r
+\r
+/**\r
+  Gets a block device's media information.\r
+\r
+  This function will provide the caller with the specified block device's media\r
+  information. If the media changes, calling this function will update the media\r
+  information accordingly.\r
+\r
+  @param[in]  PeiServices   General-purpose services that are available to every\r
+                            PEIM\r
+  @param[in]  This          Indicates the EFI_PEI_RECOVERY_BLOCK_IO2_PPI instance.\r
+  @param[in]  DeviceIndex   Specifies the block device to which the function wants\r
+                            to talk. Because the driver that implements Block I/O\r
+                            PPIs will manage multiple block devices, the PPIs that\r
+                            want to talk to a single device must specify the\r
+                            device index that was assigned during the enumeration\r
+                            process. This index is a number from one to\r
+                            NumberBlockDevices.\r
+  @param[out] MediaInfo     The media information of the specified block media.\r
+                            The caller is responsible for the ownership of this\r
+                            data structure.\r
+\r
+  @par Note:\r
+      The MediaInfo structure describes an enumeration of possible block device\r
+      types.  This enumeration exists because no device paths are actually passed\r
+      across interfaces that describe the type or class of hardware that is publishing\r
+      the block I/O interface. This enumeration will allow for policy decisions\r
+      in the Recovery PEIM, such as "Try to recover from legacy floppy first,\r
+      LS-120 second, CD-ROM third." If there are multiple partitions abstracted\r
+      by a given device type, they should be reported in ascending order; this\r
+      order also applies to nested partitions, such as legacy MBR, where the\r
+      outermost partitions would have precedence in the reporting order. The\r
+      same logic applies to systems such as IDE that have precedence relationships\r
+      like "Master/Slave" or "Primary/Secondary". The master device should be\r
+      reported first, the slave second.\r
+\r
+  @retval EFI_SUCCESS        Media information about the specified block device\r
+                             was obtained successfully.\r
+  @retval EFI_DEVICE_ERROR   Cannot get the media information due to a hardware\r
+                             error.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+EmmcBlockIoPeimGetMediaInfo2 (\r
+  IN  EFI_PEI_SERVICES               **PeiServices,\r
+  IN  EFI_PEI_RECOVERY_BLOCK_IO2_PPI *This,\r
+  IN  UINTN                          DeviceIndex,\r
+  OUT EFI_PEI_BLOCK_IO2_MEDIA        *MediaInfo\r
+  );\r
+\r
+/**\r
+  Reads the requested number of blocks from the specified block device.\r
+\r
+  The function reads the requested number of blocks from the device. All the\r
+  blocks are read, or an error is returned. If there is no media in the device,\r
+  the function returns EFI_NO_MEDIA.\r
+\r
+  @param[in]  PeiServices   General-purpose services that are available to\r
+                            every PEIM.\r
+  @param[in]  This          Indicates the EFI_PEI_RECOVERY_BLOCK_IO2_PPI instance.\r
+  @param[in]  DeviceIndex   Specifies the block device to which the function wants\r
+                            to talk. Because the driver that implements Block I/O\r
+                            PPIs will manage multiple block devices, PPIs that\r
+                            want to talk to a single device must specify the device\r
+                            index that was assigned during the enumeration process.\r
+                            This index is a number from one to NumberBlockDevices.\r
+  @param[in]  StartLBA      The starting logical block address (LBA) to read from\r
+                            on the device\r
+  @param[in]  BufferSize    The size of the Buffer in bytes. This number must be\r
+                            a multiple of the intrinsic block size of the device.\r
+  @param[out] Buffer        A pointer to the destination buffer for the data.\r
+                            The caller is responsible for the ownership of the\r
+                            buffer.\r
+\r
+  @retval EFI_SUCCESS             The data was read correctly from the device.\r
+  @retval EFI_DEVICE_ERROR        The device reported an error while attempting\r
+                                  to perform the read operation.\r
+  @retval EFI_INVALID_PARAMETER   The read request contains LBAs that are not\r
+                                  valid, or the buffer is not properly aligned.\r
+  @retval EFI_NO_MEDIA            There is no media in the device.\r
+  @retval EFI_BAD_BUFFER_SIZE     The BufferSize parameter is not a multiple of\r
+                                  the intrinsic block size of the device.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+EmmcBlockIoPeimReadBlocks2 (\r
+  IN  EFI_PEI_SERVICES               **PeiServices,\r
+  IN  EFI_PEI_RECOVERY_BLOCK_IO2_PPI *This,\r
+  IN  UINTN                          DeviceIndex,\r
+  IN  EFI_PEI_LBA                    StartLBA,\r
+  IN  UINTN                          BufferSize,\r
+  OUT VOID                           *Buffer\r
+  );\r
+\r
+/**\r
+  Initialize the memory management pool for the host controller.\r
+\r
+  @param  Private               The Emmc Peim driver private data.\r
+\r
+  @retval EFI_SUCCESS           The memory pool is initialized.\r
+  @retval Others                Fail to init the memory pool.\r
+\r
+**/\r
+EFI_STATUS\r
+EmmcPeimInitMemPool (\r
+  IN  EMMC_PEIM_HC_PRIVATE_DATA      *Private\r
+  );\r
+\r
+/**\r
+  Allocate some memory from the host controller's memory pool\r
+  which can be used to communicate with host controller.\r
+\r
+  @param  Pool      The host controller's memory pool.\r
+  @param  Size      Size of the memory to allocate.\r
+\r
+  @return The allocated memory or NULL.\r
+\r
+**/\r
+VOID *\r
+EmmcPeimAllocateMem (\r
+  IN  EMMC_PEIM_MEM_POOL        *Pool,\r
+  IN  UINTN                    Size\r
+  );\r
+\r
+/**\r
+  Free the allocated memory back to the memory pool.\r
+\r
+  @param  Pool           The memory pool of the host controller.\r
+  @param  Mem            The memory to free.\r
+  @param  Size           The size of the memory to free.\r
+\r
+**/\r
+VOID\r
+EmmcPeimFreeMem (\r
+  IN EMMC_PEIM_MEM_POOL    *Pool,\r
+  IN VOID                 *Mem,\r
+  IN UINTN                Size\r
+  );\r
+\r
+#endif\r
diff --git a/MdeModulePkg/Bus/Sd/EmmcBlockIoPei/EmmcBlockIoPei.inf b/MdeModulePkg/Bus/Sd/EmmcBlockIoPei/EmmcBlockIoPei.inf
new file mode 100644 (file)
index 0000000..4163b52
--- /dev/null
@@ -0,0 +1,62 @@
+## @file\r
+# Description file for the Embedded MMC (eMMC) Peim driver.\r
+#\r
+# Copyright (c) 2015, Intel Corporation. All rights reserved.<BR>\r
+#\r
+#  This program and the accompanying materials\r
+#  are licensed and made available under the terms and conditions of the BSD License\r
+#  which accompanies this distribution. The full text of the license may be found at\r
+#  http://opensource.org/licenses/bsd-license.php\r
+#  THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+#  WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+#\r
+#\r
+##\r
+\r
+[Defines]\r
+  INF_VERSION                    = 0x00010005\r
+  BASE_NAME                      = EmmcBlockIoPei\r
+  MODULE_UNI_FILE                = EmmcBlockIoPei.uni\r
+  FILE_GUID                      = 7F06A90F-AE0D-4887-82C0-FEC7F4F68B29\r
+  MODULE_TYPE                    = PEIM\r
+  VERSION_STRING                 = 1.0\r
+\r
+  ENTRY_POINT                    = InitializeEmmcBlockIoPeim\r
+\r
+#\r
+# The following information is for reference only and not required by the build tools.\r
+#\r
+#  VALID_ARCHITECTURES           = IA32 X64 IPF EBC\r
+#\r
+\r
+[Sources]\r
+  EmmcBlockIoPei.c\r
+  EmmcBlockIoPei.h\r
+  EmmcHci.c\r
+  EmmcHci.h\r
+  EmmcHcMem.c\r
+  EmmcHcMem.h\r
+\r
+[Packages]\r
+  MdePkg/MdePkg.dec\r
+  MdeModulePkg/MdeModulePkg.dec\r
+\r
+[LibraryClasses]\r
+  IoLib\r
+  TimerLib\r
+  BaseMemoryLib\r
+  PeimEntryPoint\r
+  PeiServicesLib\r
+  DebugLib\r
+\r
+[Ppis]\r
+  gEfiPeiVirtualBlockIoPpiGuid                  ## PRODUCES\r
+  gEfiPeiVirtualBlockIo2PpiGuid                 ## PRODUCES\r
+  gEdkiiPeiSdMmcHostControllerPpiGuid           ## CONSUMES\r
+\r
+[Depex]\r
+  gEfiPeiMemoryDiscoveredPpiGuid AND gEdkiiPeiSdMmcHostControllerPpiGuid\r
+\r
+[UserExtensions.TianoCore."ExtraFiles"]\r
+  EmmcBlockIoPeiExtra.uni\r
+\r
diff --git a/MdeModulePkg/Bus/Sd/EmmcBlockIoPei/EmmcBlockIoPei.uni b/MdeModulePkg/Bus/Sd/EmmcBlockIoPei/EmmcBlockIoPei.uni
new file mode 100644 (file)
index 0000000..f90e831
--- /dev/null
@@ -0,0 +1,21 @@
+// /** @file\r
+// The EmmcBlockIoPei driver is used to support recovery from EMMC device.\r
+//\r
+// Copyright (c) 2015, Intel Corporation. All rights reserved.<BR>\r
+//\r
+// This program and the accompanying materials\r
+// are licensed and made available under the terms and conditions\r
+// of the BSD License which accompanies this distribution.  The\r
+// full text of the license may be found at\r
+// http://opensource.org/licenses/bsd-license.php\r
+//\r
+// THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+// WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+//\r
+// **/\r
+\r
+\r
+#string STR_MODULE_ABSTRACT             #language en-US "Support recovery from EMMC devices"\r
+\r
+#string STR_MODULE_DESCRIPTION          #language en-US "The EmmcBlockIoPei driver is used to support recovery from EMMC device."\r
+\r
diff --git a/MdeModulePkg/Bus/Sd/EmmcBlockIoPei/EmmcBlockIoPeiExtra.uni b/MdeModulePkg/Bus/Sd/EmmcBlockIoPei/EmmcBlockIoPeiExtra.uni
new file mode 100644 (file)
index 0000000..9299c1b
--- /dev/null
@@ -0,0 +1,21 @@
+// /** @file\r
+// EmmcBlockIoPei Localized Strings and Content\r
+//\r
+// Copyright (c) 2015, Intel Corporation. All rights reserved.<BR>\r
+//\r
+// This program and the accompanying materials\r
+// are licensed and made available under the terms and conditions\r
+// of the BSD License which accompanies this distribution.  The\r
+// full text of the license may be found at\r
+// http://opensource.org/licenses/bsd-license.php\r
+//\r
+// THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+// WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+//\r
+// **/\r
+\r
+#string STR_PROPERTIES_MODULE_NAME\r
+#language en-US\r
+"EMMC BlockIo Peim for Recovery"\r
+\r
+\r
diff --git a/MdeModulePkg/Bus/Sd/EmmcBlockIoPei/EmmcHcMem.c b/MdeModulePkg/Bus/Sd/EmmcBlockIoPei/EmmcHcMem.c
new file mode 100644 (file)
index 0000000..073af16
--- /dev/null
@@ -0,0 +1,455 @@
+/** @file\r
+\r
+Copyright (c) 2015, Intel Corporation. All rights reserved.<BR>\r
+\r
+This program and the accompanying materials\r
+are licensed and made available under the terms and conditions\r
+of the BSD License which accompanies this distribution.  The\r
+full text of the license may be found at\r
+http://opensource.org/licenses/bsd-license.php\r
+\r
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+\r
+**/\r
+\r
+#include "EmmcBlockIoPei.h"\r
+\r
+/**\r
+  Allocate a block of memory to be used by the buffer pool.\r
+\r
+  @param  Pages          How many pages to allocate.\r
+\r
+  @return The allocated memory block or NULL if failed.\r
+\r
+**/\r
+EMMC_PEIM_MEM_BLOCK *\r
+EmmcPeimAllocMemBlock (\r
+  IN  UINTN                    Pages\r
+  )\r
+{\r
+  EMMC_PEIM_MEM_BLOCK          *Block;\r
+  EFI_STATUS                   Status;\r
+  VOID                         *TempPtr;\r
+  EFI_PHYSICAL_ADDRESS         Address;\r
+\r
+  TempPtr = NULL;\r
+  Block   = NULL;\r
+\r
+  Status = PeiServicesAllocatePool (sizeof(EMMC_PEIM_MEM_BLOCK), &TempPtr);\r
+  if (EFI_ERROR (Status)) {\r
+    return NULL;\r
+  }\r
+\r
+  ZeroMem ((VOID*)(UINTN)TempPtr, sizeof(EMMC_PEIM_MEM_BLOCK));\r
+\r
+  //\r
+  // each bit in the bit array represents EMMC_PEIM_MEM_UNIT\r
+  // bytes of memory in the memory block.\r
+  //\r
+  ASSERT (EMMC_PEIM_MEM_UNIT * 8 <= EFI_PAGE_SIZE);\r
+\r
+  Block = (EMMC_PEIM_MEM_BLOCK*)(UINTN)TempPtr;\r
+  Block->BufLen   = EFI_PAGES_TO_SIZE (Pages);\r
+  Block->BitsLen  = Block->BufLen / (EMMC_PEIM_MEM_UNIT * 8);\r
+\r
+  Status = PeiServicesAllocatePool (Block->BitsLen, &TempPtr);\r
+  if (EFI_ERROR (Status)) {\r
+    return NULL;\r
+  }\r
+\r
+  ZeroMem ((VOID*)(UINTN)TempPtr, Block->BitsLen);\r
+\r
+  Block->Bits = (UINT8*)(UINTN)TempPtr;\r
+\r
+  Status = PeiServicesAllocatePages (\r
+             EfiBootServicesCode,\r
+             Pages,\r
+             &Address\r
+             );\r
+  if (EFI_ERROR (Status)) {\r
+    return NULL;\r
+  }\r
+\r
+  ZeroMem ((VOID*)(UINTN)Address, EFI_PAGES_TO_SIZE (Pages));\r
+\r
+  Block->Buf  = (UINT8*)((UINTN)Address);\r
+  Block->Next = NULL;\r
+\r
+  return Block;\r
+}\r
+\r
+/**\r
+  Free the memory block from the memory pool.\r
+\r
+  @param  Pool           The memory pool to free the block from.\r
+  @param  Block          The memory block to free.\r
+\r
+**/\r
+VOID\r
+EmmcPeimFreeMemBlock (\r
+  IN EMMC_PEIM_MEM_POOL       *Pool,\r
+  IN EMMC_PEIM_MEM_BLOCK      *Block\r
+  )\r
+{\r
+  ASSERT ((Pool != NULL) && (Block != NULL));\r
+}\r
+\r
+/**\r
+  Alloc some memory from the block.\r
+\r
+  @param  Block          The memory block to allocate memory from.\r
+  @param  Units          Number of memory units to allocate.\r
+\r
+  @return The pointer to the allocated memory. If couldn't allocate the needed memory,\r
+          the return value is NULL.\r
+\r
+**/\r
+VOID *\r
+EmmcPeimAllocMemFromBlock (\r
+  IN  EMMC_PEIM_MEM_BLOCK *Block,\r
+  IN  UINTN               Units\r
+  )\r
+{\r
+  UINTN                   Byte;\r
+  UINT8                   Bit;\r
+  UINTN                   StartByte;\r
+  UINT8                   StartBit;\r
+  UINTN                   Available;\r
+  UINTN                   Count;\r
+\r
+  ASSERT ((Block != 0) && (Units != 0));\r
+\r
+  StartByte  = 0;\r
+  StartBit   = 0;\r
+  Available  = 0;\r
+\r
+  for (Byte = 0, Bit = 0; Byte < Block->BitsLen;) {\r
+    //\r
+    // If current bit is zero, the corresponding memory unit is\r
+    // available, otherwise we need to restart our searching.\r
+    // Available counts the consective number of zero bit.\r
+    //\r
+    if (!EMMC_PEIM_MEM_BIT_IS_SET (Block->Bits[Byte], Bit)) {\r
+      Available++;\r
+\r
+      if (Available >= Units) {\r
+        break;\r
+      }\r
+\r
+      EMMC_PEIM_NEXT_BIT (Byte, Bit);\r
+\r
+    } else {\r
+      EMMC_PEIM_NEXT_BIT (Byte, Bit);\r
+\r
+      Available  = 0;\r
+      StartByte  = Byte;\r
+      StartBit   = Bit;\r
+    }\r
+  }\r
+\r
+  if (Available < Units) {\r
+    return NULL;\r
+  }\r
+\r
+  //\r
+  // Mark the memory as allocated\r
+  //\r
+  Byte  = StartByte;\r
+  Bit   = StartBit;\r
+\r
+  for (Count = 0; Count < Units; Count++) {\r
+    ASSERT (!EMMC_PEIM_MEM_BIT_IS_SET (Block->Bits[Byte], Bit));\r
+\r
+    Block->Bits[Byte] = (UINT8) (Block->Bits[Byte] | (UINT8) EMMC_PEIM_MEM_BIT (Bit));\r
+    EMMC_PEIM_NEXT_BIT (Byte, Bit);\r
+  }\r
+\r
+  return Block->Buf + (StartByte * 8 + StartBit) * EMMC_PEIM_MEM_UNIT;\r
+}\r
+\r
+/**\r
+  Insert the memory block to the pool's list of the blocks.\r
+\r
+  @param  Head           The head of the memory pool's block list.\r
+  @param  Block          The memory block to insert.\r
+\r
+**/\r
+VOID\r
+EmmcPeimInsertMemBlockToPool (\r
+  IN EMMC_PEIM_MEM_BLOCK      *Head,\r
+  IN EMMC_PEIM_MEM_BLOCK      *Block\r
+  )\r
+{\r
+  ASSERT ((Head != NULL) && (Block != NULL));\r
+  Block->Next = Head->Next;\r
+  Head->Next  = Block;\r
+}\r
+\r
+/**\r
+  Is the memory block empty?\r
+\r
+  @param  Block   The memory block to check.\r
+\r
+  @retval TRUE    The memory block is empty.\r
+  @retval FALSE   The memory block isn't empty.\r
+\r
+**/\r
+BOOLEAN\r
+EmmcPeimIsMemBlockEmpty (\r
+  IN EMMC_PEIM_MEM_BLOCK     *Block\r
+  )\r
+{\r
+  UINTN                   Index;\r
+\r
+\r
+  for (Index = 0; Index < Block->BitsLen; Index++) {\r
+    if (Block->Bits[Index] != 0) {\r
+      return FALSE;\r
+    }\r
+  }\r
+\r
+  return TRUE;\r
+}\r
+\r
+/**\r
+  Unlink the memory block from the pool's list.\r
+\r
+  @param  Head           The block list head of the memory's pool.\r
+  @param  BlockToUnlink  The memory block to unlink.\r
+\r
+**/\r
+VOID\r
+EmmcPeimUnlinkMemBlock (\r
+  IN EMMC_PEIM_MEM_BLOCK      *Head,\r
+  IN EMMC_PEIM_MEM_BLOCK      *BlockToUnlink\r
+  )\r
+{\r
+  EMMC_PEIM_MEM_BLOCK         *Block;\r
+\r
+  ASSERT ((Head != NULL) && (BlockToUnlink != NULL));\r
+\r
+  for (Block = Head; Block != NULL; Block = Block->Next) {\r
+    if (Block->Next == BlockToUnlink) {\r
+      Block->Next         = BlockToUnlink->Next;\r
+      BlockToUnlink->Next = NULL;\r
+      break;\r
+    }\r
+  }\r
+}\r
+\r
+/**\r
+  Initialize the memory management pool for the host controller.\r
+\r
+  @param  Private               The Emmc Peim driver private data.\r
+\r
+  @retval EFI_SUCCESS           The memory pool is initialized.\r
+  @retval Others                Fail to init the memory pool.\r
+\r
+**/\r
+EFI_STATUS\r
+EmmcPeimInitMemPool (\r
+  IN  EMMC_PEIM_HC_PRIVATE_DATA  *Private\r
+  )\r
+{\r
+  EMMC_PEIM_MEM_POOL         *Pool;\r
+  EFI_STATUS                 Status;\r
+  VOID                       *TempPtr;\r
+\r
+  TempPtr = NULL;\r
+  Pool    = NULL;\r
+\r
+  Status = PeiServicesAllocatePool (sizeof (EMMC_PEIM_MEM_POOL), &TempPtr);\r
+  if (EFI_ERROR (Status)) {\r
+    return EFI_OUT_OF_RESOURCES;\r
+  }\r
+\r
+  ZeroMem ((VOID*)(UINTN)TempPtr, sizeof (EMMC_PEIM_MEM_POOL));\r
+\r
+  Pool = (EMMC_PEIM_MEM_POOL *)((UINTN)TempPtr);\r
+\r
+  Pool->Head = EmmcPeimAllocMemBlock (EMMC_PEIM_MEM_DEFAULT_PAGES);\r
+\r
+  if (Pool->Head == NULL) {\r
+    return EFI_OUT_OF_RESOURCES;\r
+  }\r
+\r
+  Private->Pool = Pool;\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+  Release the memory management pool.\r
+\r
+  @param  Pool                  The memory pool to free.\r
+\r
+  @retval EFI_DEVICE_ERROR      Fail to free the memory pool.\r
+  @retval EFI_SUCCESS           The memory pool is freed.\r
+\r
+**/\r
+EFI_STATUS\r
+EmmcPeimFreeMemPool (\r
+  IN EMMC_PEIM_MEM_POOL       *Pool\r
+  )\r
+{\r
+  EMMC_PEIM_MEM_BLOCK         *Block;\r
+\r
+  ASSERT (Pool->Head != NULL);\r
+\r
+  //\r
+  // Unlink all the memory blocks from the pool, then free them.\r
+  // EmmcPeimUnlinkMemBlock can't be used to unlink and free the\r
+  // first block.\r
+  //\r
+  for (Block = Pool->Head->Next; Block != NULL; Block = Pool->Head->Next) {\r
+    EmmcPeimFreeMemBlock (Pool, Block);\r
+  }\r
+\r
+  EmmcPeimFreeMemBlock (Pool, Pool->Head);\r
+\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+  Allocate some memory from the host controller's memory pool\r
+  which can be used to communicate with host controller.\r
+\r
+  @param  Pool      The host controller's memory pool.\r
+  @param  Size      Size of the memory to allocate.\r
+\r
+  @return The allocated memory or NULL.\r
+\r
+**/\r
+VOID *\r
+EmmcPeimAllocateMem (\r
+  IN  EMMC_PEIM_MEM_POOL     *Pool,\r
+  IN  UINTN                  Size\r
+  )\r
+{\r
+  EMMC_PEIM_MEM_BLOCK        *Head;\r
+  EMMC_PEIM_MEM_BLOCK        *Block;\r
+  EMMC_PEIM_MEM_BLOCK        *NewBlock;\r
+  VOID                       *Mem;\r
+  UINTN                      AllocSize;\r
+  UINTN                      Pages;\r
+\r
+  Mem       = NULL;\r
+  AllocSize = EMMC_PEIM_MEM_ROUND (Size);\r
+  Head      = Pool->Head;\r
+  ASSERT (Head != NULL);\r
+\r
+  //\r
+  // First check whether current memory blocks can satisfy the allocation.\r
+  //\r
+  for (Block = Head; Block != NULL; Block = Block->Next) {\r
+    Mem = EmmcPeimAllocMemFromBlock (Block, AllocSize / EMMC_PEIM_MEM_UNIT);\r
+\r
+    if (Mem != NULL) {\r
+      ZeroMem (Mem, Size);\r
+      break;\r
+    }\r
+  }\r
+\r
+  if (Mem != NULL) {\r
+    return Mem;\r
+  }\r
+\r
+  //\r
+  // Create a new memory block if there is not enough memory\r
+  // in the pool. If the allocation size is larger than the\r
+  // default page number, just allocate a large enough memory\r
+  // block. Otherwise allocate default pages.\r
+  //\r
+  if (AllocSize > EFI_PAGES_TO_SIZE (EMMC_PEIM_MEM_DEFAULT_PAGES)) {\r
+    Pages = EFI_SIZE_TO_PAGES (AllocSize) + 1;\r
+  } else {\r
+    Pages = EMMC_PEIM_MEM_DEFAULT_PAGES;\r
+  }\r
+\r
+  NewBlock = EmmcPeimAllocMemBlock (Pages);\r
+  if (NewBlock == NULL) {\r
+    return NULL;\r
+  }\r
+\r
+  //\r
+  // Add the new memory block to the pool, then allocate memory from it\r
+  //\r
+  EmmcPeimInsertMemBlockToPool (Head, NewBlock);\r
+  Mem = EmmcPeimAllocMemFromBlock (NewBlock, AllocSize / EMMC_PEIM_MEM_UNIT);\r
+\r
+  if (Mem != NULL) {\r
+    ZeroMem (Mem, Size);\r
+  }\r
+\r
+  return Mem;\r
+}\r
+\r
+/**\r
+  Free the allocated memory back to the memory pool.\r
+\r
+  @param  Pool           The memory pool of the host controller.\r
+  @param  Mem            The memory to free.\r
+  @param  Size           The size of the memory to free.\r
+\r
+**/\r
+VOID\r
+EmmcPeimFreeMem (\r
+  IN EMMC_PEIM_MEM_POOL   *Pool,\r
+  IN VOID                 *Mem,\r
+  IN UINTN                Size\r
+  )\r
+{\r
+  EMMC_PEIM_MEM_BLOCK     *Head;\r
+  EMMC_PEIM_MEM_BLOCK     *Block;\r
+  UINT8                   *ToFree;\r
+  UINTN                   AllocSize;\r
+  UINTN                   Byte;\r
+  UINTN                   Bit;\r
+  UINTN                   Count;\r
+\r
+  Head      = Pool->Head;\r
+  AllocSize = EMMC_PEIM_MEM_ROUND (Size);\r
+  ToFree    = (UINT8 *) Mem;\r
+\r
+  for (Block = Head; Block != NULL; Block = Block->Next) {\r
+    //\r
+    // scan the memory block list for the memory block that\r
+    // completely contains the memory to free.\r
+    //\r
+    if ((Block->Buf <= ToFree) && ((ToFree + AllocSize) <= (Block->Buf + Block->BufLen))) {\r
+      //\r
+      // compute the start byte and bit in the bit array\r
+      //\r
+      Byte  = ((ToFree - Block->Buf) / EMMC_PEIM_MEM_UNIT) / 8;\r
+      Bit   = ((ToFree - Block->Buf) / EMMC_PEIM_MEM_UNIT) % 8;\r
+\r
+      //\r
+      // reset associated bits in bit arry\r
+      //\r
+      for (Count = 0; Count < (AllocSize / EMMC_PEIM_MEM_UNIT); Count++) {\r
+        ASSERT (EMMC_PEIM_MEM_BIT_IS_SET (Block->Bits[Byte], Bit));\r
+\r
+        Block->Bits[Byte] = (UINT8) (Block->Bits[Byte] ^ EMMC_PEIM_MEM_BIT (Bit));\r
+        EMMC_PEIM_NEXT_BIT (Byte, Bit);\r
+      }\r
+\r
+      break;\r
+    }\r
+  }\r
+\r
+  //\r
+  // If Block == NULL, it means that the current memory isn't\r
+  // in the host controller's pool. This is critical because\r
+  // the caller has passed in a wrong memory point\r
+  //\r
+  ASSERT (Block != NULL);\r
+\r
+  //\r
+  // Release the current memory block if it is empty and not the head\r
+  //\r
+  if ((Block != Head) && EmmcPeimIsMemBlockEmpty (Block)) {\r
+    EmmcPeimFreeMemBlock (Pool, Block);\r
+  }\r
+\r
+  return ;\r
+}\r
diff --git a/MdeModulePkg/Bus/Sd/EmmcBlockIoPei/EmmcHcMem.h b/MdeModulePkg/Bus/Sd/EmmcBlockIoPei/EmmcHcMem.h
new file mode 100644 (file)
index 0000000..af0c93c
--- /dev/null
@@ -0,0 +1,61 @@
+/** @file\r
+\r
+Copyright (c) 2015, Intel Corporation. All rights reserved.<BR>\r
+\r
+This program and the accompanying materials\r
+are licensed and made available under the terms and conditions\r
+of the BSD License which accompanies this distribution.  The\r
+full text of the license may be found at\r
+http://opensource.org/licenses/bsd-license.php\r
+\r
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+\r
+**/\r
+\r
+#ifndef _EMMC_PEIM_MEM_H_\r
+#define _EMMC_PEIM_MEM_H_\r
+\r
+#define EMMC_PEIM_MEM_BIT(a)          ((UINTN)(1 << (a)))\r
+\r
+#define EMMC_PEIM_MEM_BIT_IS_SET(Data, Bit)   \\r
+          ((BOOLEAN)(((Data) & EMMC_PEIM_MEM_BIT(Bit)) == EMMC_PEIM_MEM_BIT(Bit)))\r
+\r
+typedef struct _EMMC_PEIM_MEM_BLOCK EMMC_PEIM_MEM_BLOCK;\r
+\r
+struct _EMMC_PEIM_MEM_BLOCK {\r
+  UINT8                   *Bits;    // Bit array to record which unit is allocated\r
+  UINTN                   BitsLen;\r
+  UINT8                   *Buf;\r
+  UINTN                   BufLen;   // Memory size in bytes\r
+  EMMC_PEIM_MEM_BLOCK     *Next;\r
+};\r
+\r
+typedef struct _EMMC_PEIM_MEM_POOL {\r
+  EMMC_PEIM_MEM_BLOCK     *Head;\r
+} EMMC_PEIM_MEM_POOL;\r
+\r
+//\r
+// Memory allocation unit, note that the value must meet EMMC spec alignment requirement.\r
+//\r
+#define EMMC_PEIM_MEM_UNIT           128\r
+\r
+#define EMMC_PEIM_MEM_UNIT_MASK      (EMMC_PEIM_MEM_UNIT - 1)\r
+#define EMMC_PEIM_MEM_DEFAULT_PAGES  16\r
+\r
+#define EMMC_PEIM_MEM_ROUND(Len)     (((Len) + EMMC_PEIM_MEM_UNIT_MASK) & (~EMMC_PEIM_MEM_UNIT_MASK))\r
+\r
+//\r
+// Advance the byte and bit to the next bit, adjust byte accordingly.\r
+//\r
+#define EMMC_PEIM_NEXT_BIT(Byte, Bit)   \\r
+          do {                \\r
+            (Bit)++;          \\r
+            if ((Bit) > 7) {  \\r
+              (Byte)++;       \\r
+              (Bit) = 0;      \\r
+            }                 \\r
+          } while (0)\r
+\r
+#endif\r
+\r
diff --git a/MdeModulePkg/Bus/Sd/EmmcBlockIoPei/EmmcHci.c b/MdeModulePkg/Bus/Sd/EmmcBlockIoPei/EmmcHci.c
new file mode 100644 (file)
index 0000000..050d843
--- /dev/null
@@ -0,0 +1,2833 @@
+/** @file\r
+\r
+  Copyright (c) 2015 - 2016, Intel Corporation. All rights reserved.<BR>\r
+  This program and the accompanying materials\r
+  are licensed and made available under the terms and conditions of the BSD License\r
+  which accompanies this distribution.  The full text of the license may be found at\r
+  http://opensource.org/licenses/bsd-license.php.\r
+\r
+  THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+  WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+\r
+**/\r
+\r
+#include "EmmcBlockIoPei.h"\r
+\r
+/**\r
+  Read/Write specified EMMC host controller mmio register.\r
+\r
+  @param[in]      Address      The address of the mmio register to be read/written.\r
+  @param[in]      Read         A boolean to indicate it's read or write operation.\r
+  @param[in]      Count        The width of the mmio register in bytes.\r
+                               Must be 1, 2 , 4 or 8 bytes.\r
+  @param[in, out] Data         For read operations, the destination buffer to store\r
+                               the results. For write operations, the source buffer\r
+                               to write data from. The caller is responsible for\r
+                               having ownership of the data buffer and ensuring its\r
+                               size not less than Count bytes.\r
+\r
+  @retval EFI_INVALID_PARAMETER The Address or the Data or the Count is not valid.\r
+  @retval EFI_SUCCESS           The read/write operation succeeds.\r
+  @retval Others                The read/write operation fails.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+EmmcPeimHcRwMmio (\r
+  IN     UINTN                 Address,\r
+  IN     BOOLEAN               Read,\r
+  IN     UINT8                 Count,\r
+  IN OUT VOID                  *Data\r
+  )\r
+{\r
+  if ((Address == 0) || (Data == NULL))  {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  if ((Count != 1) && (Count != 2) && (Count != 4) && (Count != 8)) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  switch (Count) {\r
+    case 1:\r
+      if (Read) {\r
+        *(UINT8*)Data = MmioRead8 (Address);\r
+      } else {\r
+        MmioWrite8 (Address, *(UINT8*)Data);\r
+      }\r
+      break;\r
+    case 2:\r
+      if (Read) {\r
+        *(UINT16*)Data = MmioRead16 (Address);\r
+      } else {\r
+        MmioWrite16 (Address, *(UINT16*)Data);\r
+      }\r
+      break;\r
+    case 4:\r
+      if (Read) {\r
+        *(UINT32*)Data = MmioRead32 (Address);\r
+      } else {\r
+        MmioWrite32 (Address, *(UINT32*)Data);\r
+      }\r
+      break;\r
+    case 8:\r
+      if (Read) {\r
+        *(UINT64*)Data = MmioRead64 (Address);\r
+      } else {\r
+        MmioWrite64 (Address, *(UINT64*)Data);\r
+      }\r
+      break;\r
+    default:\r
+      ASSERT (FALSE);\r
+      return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+  Do OR operation with the value of the specified EMMC host controller mmio register.\r
+\r
+  @param[in] Address           The address of the mmio register to be read/written.\r
+  @param[in] Count             The width of the mmio register in bytes.\r
+                               Must be 1, 2 , 4 or 8 bytes.\r
+  @param[in] OrData            The pointer to the data used to do OR operation.\r
+                               The caller is responsible for having ownership of\r
+                               the data buffer and ensuring its size not less than\r
+                               Count bytes.\r
+\r
+  @retval EFI_INVALID_PARAMETER The Address or the OrData or the Count is not valid.\r
+  @retval EFI_SUCCESS           The OR operation succeeds.\r
+  @retval Others                The OR operation fails.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+EmmcPeimHcOrMmio (\r
+  IN  UINTN                    Address,\r
+  IN  UINT8                    Count,\r
+  IN  VOID                     *OrData\r
+  )\r
+{\r
+  EFI_STATUS                   Status;\r
+  UINT64                       Data;\r
+  UINT64                       Or;\r
+\r
+  Status = EmmcPeimHcRwMmio (Address, TRUE, Count, &Data);\r
+  if (EFI_ERROR (Status)) {\r
+    return Status;\r
+  }\r
+\r
+  if (Count == 1) {\r
+    Or = *(UINT8*) OrData;\r
+  } else if (Count == 2) {\r
+    Or = *(UINT16*) OrData;\r
+  } else if (Count == 4) {\r
+    Or = *(UINT32*) OrData;\r
+  } else if (Count == 8) {\r
+    Or = *(UINT64*) OrData;\r
+  } else {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  Data  |= Or;\r
+  Status = EmmcPeimHcRwMmio (Address, FALSE, Count, &Data);\r
+\r
+  return Status;\r
+}\r
+\r
+/**\r
+  Do AND operation with the value of the specified EMMC host controller mmio register.\r
+\r
+  @param[in] Address           The address of the mmio register to be read/written.\r
+  @param[in] Count             The width of the mmio register in bytes.\r
+                               Must be 1, 2 , 4 or 8 bytes.\r
+  @param[in] AndData           The pointer to the data used to do AND operation.\r
+                               The caller is responsible for having ownership of\r
+                               the data buffer and ensuring its size not less than\r
+                               Count bytes.\r
+\r
+  @retval EFI_INVALID_PARAMETER The Address or the AndData or the Count is not valid.\r
+  @retval EFI_SUCCESS           The AND operation succeeds.\r
+  @retval Others                The AND operation fails.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+EmmcPeimHcAndMmio (\r
+  IN  UINTN                    Address,\r
+  IN  UINT8                    Count,\r
+  IN  VOID                     *AndData\r
+  )\r
+{\r
+  EFI_STATUS                   Status;\r
+  UINT64                       Data;\r
+  UINT64                       And;\r
+\r
+  Status = EmmcPeimHcRwMmio (Address, TRUE, Count, &Data);\r
+  if (EFI_ERROR (Status)) {\r
+    return Status;\r
+  }\r
+\r
+  if (Count == 1) {\r
+    And = *(UINT8*) AndData;\r
+  } else if (Count == 2) {\r
+    And = *(UINT16*) AndData;\r
+  } else if (Count == 4) {\r
+    And = *(UINT32*) AndData;\r
+  } else if (Count == 8) {\r
+    And = *(UINT64*) AndData;\r
+  } else {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  Data  &= And;\r
+  Status = EmmcPeimHcRwMmio (Address, FALSE, Count, &Data);\r
+\r
+  return Status;\r
+}\r
+\r
+/**\r
+  Wait for the value of the specified MMIO register set to the test value.\r
+\r
+  @param[in]  Address       The address of the mmio register to be checked.\r
+  @param[in]  Count         The width of the mmio register in bytes.\r
+                            Must be 1, 2, 4 or 8 bytes.\r
+  @param[in]  MaskValue     The mask value of memory.\r
+  @param[in]  TestValue     The test value of memory.\r
+\r
+  @retval EFI_NOT_READY     The MMIO register hasn't set to the expected value.\r
+  @retval EFI_SUCCESS       The MMIO register has expected value.\r
+  @retval Others            The MMIO operation fails.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+EmmcPeimHcCheckMmioSet (\r
+  IN  UINTN                     Address,\r
+  IN  UINT8                     Count,\r
+  IN  UINT64                    MaskValue,\r
+  IN  UINT64                    TestValue\r
+  )\r
+{\r
+  EFI_STATUS            Status;\r
+  UINT64                Value;\r
+\r
+  //\r
+  // Access PCI MMIO space to see if the value is the tested one.\r
+  //\r
+  Value  = 0;\r
+  Status = EmmcPeimHcRwMmio (Address, TRUE, Count, &Value);\r
+  if (EFI_ERROR (Status)) {\r
+    return Status;\r
+  }\r
+\r
+  Value &= MaskValue;\r
+\r
+  if (Value == TestValue) {\r
+    return EFI_SUCCESS;\r
+  }\r
+\r
+  return EFI_NOT_READY;\r
+}\r
+\r
+/**\r
+  Wait for the value of the specified MMIO register set to the test value.\r
+\r
+  @param[in]  Address       The address of the mmio register to wait.\r
+  @param[in]  Count         The width of the mmio register in bytes.\r
+                            Must be 1, 2, 4 or 8 bytes.\r
+  @param[in]  MaskValue     The mask value of memory.\r
+  @param[in]  TestValue     The test value of memory.\r
+  @param[in]  Timeout       The time out value for wait memory set, uses 1\r
+                            microsecond as a unit.\r
+\r
+  @retval EFI_TIMEOUT       The MMIO register hasn't expected value in timeout\r
+                            range.\r
+  @retval EFI_SUCCESS       The MMIO register has expected value.\r
+  @retval Others            The MMIO operation fails.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+EmmcPeimHcWaitMmioSet (\r
+  IN  UINTN                     Address,\r
+  IN  UINT8                     Count,\r
+  IN  UINT64                    MaskValue,\r
+  IN  UINT64                    TestValue,\r
+  IN  UINT64                    Timeout\r
+  )\r
+{\r
+  EFI_STATUS            Status;\r
+  BOOLEAN               InfiniteWait;\r
+\r
+  if (Timeout == 0) {\r
+    InfiniteWait = TRUE;\r
+  } else {\r
+    InfiniteWait = FALSE;\r
+  }\r
+\r
+  while (InfiniteWait || (Timeout > 0)) {\r
+    Status = EmmcPeimHcCheckMmioSet (\r
+               Address,\r
+               Count,\r
+               MaskValue,\r
+               TestValue\r
+               );\r
+    if (Status != EFI_NOT_READY) {\r
+      return Status;\r
+    }\r
+\r
+    //\r
+    // Stall for 1 microsecond.\r
+    //\r
+    MicroSecondDelay (1);\r
+\r
+    Timeout--;\r
+  }\r
+\r
+  return EFI_TIMEOUT;\r
+}\r
+\r
+/**\r
+  Software reset the specified EMMC host controller and enable all interrupts.\r
+\r
+  @param[in] Bar            The mmio base address of the slot to be accessed.\r
+\r
+  @retval EFI_SUCCESS       The software reset executes successfully.\r
+  @retval Others            The software reset fails.\r
+\r
+**/\r
+EFI_STATUS\r
+EmmcPeimHcReset (\r
+  IN UINTN                  Bar\r
+  )\r
+{\r
+  EFI_STATUS                Status;\r
+  UINT8                     SwReset;\r
+\r
+  SwReset = 0xFF;\r
+  Status  = EmmcPeimHcRwMmio (Bar + EMMC_HC_SW_RST, FALSE, sizeof (SwReset), &SwReset);\r
+\r
+  if (EFI_ERROR (Status)) {\r
+    DEBUG ((EFI_D_ERROR, "EmmcPeimHcReset: write full 1 fails: %r\n", Status));\r
+    return Status;\r
+  }\r
+\r
+  Status = EmmcPeimHcWaitMmioSet (\r
+             Bar + EMMC_HC_SW_RST,\r
+             sizeof (SwReset),\r
+             0xFF,\r
+             0x00,\r
+             EMMC_TIMEOUT\r
+             );\r
+  if (EFI_ERROR (Status)) {\r
+    DEBUG ((EFI_D_INFO, "EmmcPeimHcReset: reset done with %r\n", Status));\r
+    return Status;\r
+  }\r
+  //\r
+  // Enable all interrupt after reset all.\r
+  //\r
+  Status = EmmcPeimHcEnableInterrupt (Bar);\r
+\r
+  return Status;\r
+}\r
+\r
+/**\r
+  Set all interrupt status bits in Normal and Error Interrupt Status Enable\r
+  register.\r
+\r
+  @param[in] Bar            The mmio base address of the slot to be accessed.\r
+\r
+  @retval EFI_SUCCESS       The operation executes successfully.\r
+  @retval Others            The operation fails.\r
+\r
+**/\r
+EFI_STATUS\r
+EmmcPeimHcEnableInterrupt (\r
+  IN UINTN                  Bar\r
+  )\r
+{\r
+  EFI_STATUS                Status;\r
+  UINT16                    IntStatus;\r
+\r
+  //\r
+  // Enable all bits in Error Interrupt Status Enable Register\r
+  //\r
+  IntStatus = 0xFFFF;\r
+  Status = EmmcPeimHcRwMmio (Bar + EMMC_HC_ERR_INT_STS_EN, FALSE, sizeof (IntStatus), &IntStatus);\r
+  if (EFI_ERROR (Status)) {\r
+    return Status;\r
+  }\r
+  //\r
+  // Enable all bits in Normal Interrupt Status Enable Register\r
+  //\r
+  IntStatus = 0xFFFF;\r
+  Status = EmmcPeimHcRwMmio (Bar + EMMC_HC_NOR_INT_STS_EN, FALSE, sizeof (IntStatus), &IntStatus);\r
+\r
+  return Status;\r
+}\r
+\r
+/**\r
+  Get the capability data from the specified slot.\r
+\r
+  @param[in]  Bar             The mmio base address of the slot to be accessed.\r
+  @param[out] Capability      The buffer to store the capability data.\r
+\r
+  @retval EFI_SUCCESS         The operation executes successfully.\r
+  @retval Others              The operation fails.\r
+\r
+**/\r
+EFI_STATUS\r
+EmmcPeimHcGetCapability (\r
+  IN     UINTN              Bar,\r
+     OUT EMMC_HC_SLOT_CAP   *Capability\r
+  )\r
+{\r
+  EFI_STATUS                Status;\r
+  UINT64                    Cap;\r
+\r
+  Status = EmmcPeimHcRwMmio (Bar + EMMC_HC_CAP, TRUE, sizeof (Cap), &Cap);\r
+  if (EFI_ERROR (Status)) {\r
+    return Status;\r
+  }\r
+\r
+  CopyMem (Capability, &Cap, sizeof (Cap));\r
+\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+  Detect whether there is a EMMC card attached at the specified EMMC host controller\r
+  slot.\r
+\r
+  Refer to SD Host Controller Simplified spec 3.0 Section 3.1 for details.\r
+\r
+  @param[in]  Bar           The mmio base address of the slot to be accessed.\r
+\r
+  @retval EFI_SUCCESS       There is a EMMC card attached.\r
+  @retval EFI_NO_MEDIA      There is not a EMMC card attached.\r
+  @retval Others            The detection fails.\r
+\r
+**/\r
+EFI_STATUS\r
+EmmcPeimHcCardDetect (\r
+  IN UINTN                  Bar\r
+  )\r
+{\r
+  EFI_STATUS                Status;\r
+  UINT16                    Data;\r
+  UINT32                    PresentState;\r
+\r
+  //\r
+  // Check Normal Interrupt Status Register\r
+  //\r
+  Status = EmmcPeimHcRwMmio (Bar + EMMC_HC_NOR_INT_STS, TRUE, sizeof (Data), &Data);\r
+  if (EFI_ERROR (Status)) {\r
+    return Status;\r
+  }\r
+\r
+  if ((Data & (BIT6 | BIT7)) != 0) {\r
+    //\r
+    // Clear BIT6 and BIT7 by writing 1 to these two bits if set.\r
+    //\r
+    Data  &= BIT6 | BIT7;\r
+    Status = EmmcPeimHcRwMmio (Bar + EMMC_HC_NOR_INT_STS, FALSE, sizeof (Data), &Data);\r
+    if (EFI_ERROR (Status)) {\r
+      return Status;\r
+    }\r
+  }\r
+\r
+  //\r
+  // Check Present State Register to see if there is a card presented.\r
+  //\r
+  Status = EmmcPeimHcRwMmio (Bar + EMMC_HC_PRESENT_STATE, TRUE, sizeof (PresentState), &PresentState);\r
+  if (EFI_ERROR (Status)) {\r
+    return Status;\r
+  }\r
+\r
+  if ((PresentState & BIT16) != 0) {\r
+    return EFI_SUCCESS;\r
+  } else {\r
+    return EFI_NO_MEDIA;\r
+  }\r
+}\r
+\r
+/**\r
+  Stop EMMC card clock.\r
+\r
+  Refer to SD Host Controller Simplified spec 3.0 Section 3.2.2 for details.\r
+\r
+  @param[in]  Bar           The mmio base address of the slot to be accessed.\r
+\r
+  @retval EFI_SUCCESS       Succeed to stop EMMC clock.\r
+  @retval Others            Fail to stop EMMC clock.\r
+\r
+**/\r
+EFI_STATUS\r
+EmmcPeimHcStopClock (\r
+  IN UINTN                  Bar\r
+  )\r
+{\r
+  EFI_STATUS                Status;\r
+  UINT32                    PresentState;\r
+  UINT16                    ClockCtrl;\r
+\r
+  //\r
+  // Ensure no SD transactions are occurring on the SD Bus by\r
+  // waiting for Command Inhibit (DAT) and Command Inhibit (CMD)\r
+  // in the Present State register to be 0.\r
+  //\r
+  Status = EmmcPeimHcWaitMmioSet (\r
+             Bar + EMMC_HC_PRESENT_STATE,\r
+             sizeof (PresentState),\r
+             BIT0 | BIT1,\r
+             0,\r
+             EMMC_TIMEOUT\r
+             );\r
+  if (EFI_ERROR (Status)) {\r
+    return Status;\r
+  }\r
+\r
+  //\r
+  // Set SD Clock Enable in the Clock Control register to 0\r
+  //\r
+  ClockCtrl = (UINT16)~BIT2;\r
+  Status = EmmcPeimHcAndMmio (Bar + EMMC_HC_CLOCK_CTRL, sizeof (ClockCtrl), &ClockCtrl);\r
+\r
+  return Status;\r
+}\r
+\r
+/**\r
+  EMMC card clock supply.\r
+\r
+  Refer to SD Host Controller Simplified spec 3.0 Section 3.2.1 for details.\r
+\r
+  @param[in] Bar            The mmio base address of the slot to be accessed.\r
+  @param[in] ClockFreq      The max clock frequency to be set. The unit is KHz.\r
+\r
+  @retval EFI_SUCCESS       The clock is supplied successfully.\r
+  @retval Others            The clock isn't supplied successfully.\r
+\r
+**/\r
+EFI_STATUS\r
+EmmcPeimHcClockSupply (\r
+  IN UINTN                  Bar,\r
+  IN UINT64                 ClockFreq\r
+  )\r
+{\r
+  EFI_STATUS                Status;\r
+  EMMC_HC_SLOT_CAP          Capability;\r
+  UINT32                    BaseClkFreq;\r
+  UINT32                    SettingFreq;\r
+  UINT32                    Divisor;\r
+  UINT32                    Remainder;\r
+  UINT16                    ControllerVer;\r
+  UINT16                    ClockCtrl;\r
+\r
+  //\r
+  // Calculate a divisor for SD clock frequency\r
+  //\r
+  Status = EmmcPeimHcGetCapability (Bar, &Capability);\r
+  if (EFI_ERROR (Status)) {\r
+    return Status;\r
+  }\r
+  ASSERT (Capability.BaseClkFreq != 0);\r
+\r
+  BaseClkFreq = Capability.BaseClkFreq;\r
+  if ((ClockFreq > (BaseClkFreq * 1000)) || (ClockFreq == 0)) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+  //\r
+  // Calculate the divisor of base frequency.\r
+  //\r
+  Divisor     = 0;\r
+  SettingFreq = BaseClkFreq * 1000;\r
+  while (ClockFreq < SettingFreq) {\r
+    Divisor++;\r
+\r
+    SettingFreq = (BaseClkFreq * 1000) / (2 * Divisor);\r
+    Remainder   = (BaseClkFreq * 1000) % (2 * Divisor);\r
+    if ((ClockFreq == SettingFreq) && (Remainder == 0)) {\r
+      break;\r
+    }\r
+    if ((ClockFreq == SettingFreq) && (Remainder != 0)) {\r
+      SettingFreq ++;\r
+    }\r
+  }\r
+\r
+  DEBUG ((EFI_D_INFO, "BaseClkFreq %dMHz Divisor %d ClockFreq %dKhz\n", BaseClkFreq, Divisor, ClockFreq));\r
+\r
+  Status = EmmcPeimHcRwMmio (Bar + EMMC_HC_CTRL_VER, TRUE, sizeof (ControllerVer), &ControllerVer);\r
+  if (EFI_ERROR (Status)) {\r
+    return Status;\r
+  }\r
+  //\r
+  // Set SDCLK Frequency Select and Internal Clock Enable fields in Clock Control register.\r
+  //\r
+  if ((ControllerVer & 0xFF) == 2) {\r
+    ASSERT (Divisor <= 0x3FF);\r
+    ClockCtrl = ((Divisor & 0xFF) << 8) | ((Divisor & 0x300) >> 2);\r
+  } else if (((ControllerVer & 0xFF) == 0) || ((ControllerVer & 0xFF) == 1)) {\r
+    //\r
+    // Only the most significant bit can be used as divisor.\r
+    //\r
+    if (((Divisor - 1) & Divisor) != 0) {\r
+      Divisor = 1 << (HighBitSet32 (Divisor) + 1);\r
+    }\r
+    ASSERT (Divisor <= 0x80);\r
+    ClockCtrl = (Divisor & 0xFF) << 8;\r
+  } else {\r
+    DEBUG ((EFI_D_ERROR, "Unknown SD Host Controller Spec version [0x%x]!!!\n", ControllerVer));\r
+    return EFI_UNSUPPORTED;\r
+  }\r
+\r
+  //\r
+  // Stop bus clock at first\r
+  //\r
+  Status = EmmcPeimHcStopClock (Bar);\r
+  if (EFI_ERROR (Status)) {\r
+    return Status;\r
+  }\r
+\r
+  //\r
+  // Supply clock frequency with specified divisor\r
+  //\r
+  ClockCtrl |= BIT0;\r
+  Status = EmmcPeimHcRwMmio (Bar + EMMC_HC_CLOCK_CTRL, FALSE, sizeof (ClockCtrl), &ClockCtrl);\r
+  if (EFI_ERROR (Status)) {\r
+    DEBUG ((EFI_D_ERROR, "Set SDCLK Frequency Select and Internal Clock Enable fields fails\n"));\r
+    return Status;\r
+  }\r
+\r
+  //\r
+  // Wait Internal Clock Stable in the Clock Control register to be 1\r
+  //\r
+  Status = EmmcPeimHcWaitMmioSet (\r
+             Bar + EMMC_HC_CLOCK_CTRL,\r
+             sizeof (ClockCtrl),\r
+             BIT1,\r
+             BIT1,\r
+             EMMC_TIMEOUT\r
+             );\r
+  if (EFI_ERROR (Status)) {\r
+    return Status;\r
+  }\r
+\r
+  //\r
+  // Set SD Clock Enable in the Clock Control register to 1\r
+  //\r
+  ClockCtrl = BIT2;\r
+  Status = EmmcPeimHcOrMmio (Bar + EMMC_HC_CLOCK_CTRL, sizeof (ClockCtrl), &ClockCtrl);\r
+\r
+  return Status;\r
+}\r
+\r
+/**\r
+  EMMC bus power control.\r
+\r
+  Refer to SD Host Controller Simplified spec 3.0 Section 3.3 for details.\r
+\r
+  @param[in] Bar            The mmio base address of the slot to be accessed.\r
+  @param[in] PowerCtrl      The value setting to the power control register.\r
+\r
+  @retval TRUE              There is a EMMC card attached.\r
+  @retval FALSE             There is no a EMMC card attached.\r
+\r
+**/\r
+EFI_STATUS\r
+EmmcPeimHcPowerControl (\r
+  IN UINTN                  Bar,\r
+  IN UINT8                  PowerCtrl\r
+  )\r
+{\r
+  EFI_STATUS                Status;\r
+\r
+  //\r
+  // Clr SD Bus Power\r
+  //\r
+  PowerCtrl &= (UINT8)~BIT0;\r
+  Status = EmmcPeimHcRwMmio (Bar + EMMC_HC_POWER_CTRL, FALSE, sizeof (PowerCtrl), &PowerCtrl);\r
+  if (EFI_ERROR (Status)) {\r
+    return Status;\r
+  }\r
+\r
+  //\r
+  // Set SD Bus Voltage Select and SD Bus Power fields in Power Control Register\r
+  //\r
+  PowerCtrl |= BIT0;\r
+  Status = EmmcPeimHcRwMmio (Bar + EMMC_HC_POWER_CTRL, FALSE, sizeof (PowerCtrl), &PowerCtrl);\r
+\r
+  return Status;\r
+}\r
+\r
+/**\r
+  Set the EMMC bus width.\r
+\r
+  Refer to SD Host Controller Simplified spec 3.0 Section 3.4 for details.\r
+\r
+  @param[in] Bar            The mmio base address of the slot to be accessed.\r
+  @param[in] BusWidth       The bus width used by the EMMC device, it must be 1, 4 or 8.\r
+\r
+  @retval EFI_SUCCESS       The bus width is set successfully.\r
+  @retval Others            The bus width isn't set successfully.\r
+\r
+**/\r
+EFI_STATUS\r
+EmmcPeimHcSetBusWidth (\r
+  IN UINTN                  Bar,\r
+  IN UINT16                 BusWidth\r
+  )\r
+{\r
+  EFI_STATUS                Status;\r
+  UINT8                     HostCtrl1;\r
+\r
+  if (BusWidth == 1) {\r
+    HostCtrl1 = (UINT8)~(BIT5 | BIT1);\r
+    Status = EmmcPeimHcAndMmio (Bar + EMMC_HC_HOST_CTRL1, sizeof (HostCtrl1), &HostCtrl1);\r
+  } else if (BusWidth == 4) {\r
+    Status = EmmcPeimHcRwMmio (Bar + EMMC_HC_HOST_CTRL1, TRUE, sizeof (HostCtrl1), &HostCtrl1);\r
+    if (EFI_ERROR (Status)) {\r
+      return Status;\r
+    }\r
+    HostCtrl1 |= BIT1;\r
+    HostCtrl1 &= (UINT8)~BIT5;\r
+    Status = EmmcPeimHcRwMmio (Bar + EMMC_HC_HOST_CTRL1, FALSE, sizeof (HostCtrl1), &HostCtrl1);\r
+  } else if (BusWidth == 8) {\r
+    Status = EmmcPeimHcRwMmio (Bar + EMMC_HC_HOST_CTRL1, TRUE, sizeof (HostCtrl1), &HostCtrl1);\r
+    if (EFI_ERROR (Status)) {\r
+      return Status;\r
+    }\r
+    HostCtrl1 &= (UINT8)~BIT1;\r
+    HostCtrl1 |= BIT5;\r
+    Status = EmmcPeimHcRwMmio (Bar + EMMC_HC_HOST_CTRL1, FALSE, sizeof (HostCtrl1), &HostCtrl1);\r
+  } else {\r
+    ASSERT (FALSE);\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  return Status;\r
+}\r
+\r
+/**\r
+  Supply EMMC card with lowest clock frequency at initialization.\r
+\r
+  @param[in] Bar            The mmio base address of the slot to be accessed.\r
+\r
+  @retval EFI_SUCCESS       The clock is supplied successfully.\r
+  @retval Others            The clock isn't supplied successfully.\r
+\r
+**/\r
+EFI_STATUS\r
+EmmcPeimHcInitClockFreq (\r
+  IN UINTN                  Bar\r
+  )\r
+{\r
+  EFI_STATUS                Status;\r
+  EMMC_HC_SLOT_CAP          Capability;\r
+  UINT32                    InitFreq;\r
+\r
+  //\r
+  // Calculate a divisor for SD clock frequency\r
+  //\r
+  Status = EmmcPeimHcGetCapability (Bar, &Capability);\r
+  if (EFI_ERROR (Status)) {\r
+    return Status;\r
+  }\r
+\r
+  if (Capability.BaseClkFreq == 0) {\r
+    //\r
+    // Don't support get Base Clock Frequency information via another method\r
+    //\r
+    return EFI_UNSUPPORTED;\r
+  }\r
+  //\r
+  // Supply 400KHz clock frequency at initialization phase.\r
+  //\r
+  InitFreq = 400;\r
+  Status = EmmcPeimHcClockSupply (Bar, InitFreq);\r
+  return Status;\r
+}\r
+\r
+/**\r
+  Supply EMMC card with maximum voltage at initialization.\r
+\r
+  Refer to SD Host Controller Simplified spec 3.0 Section 3.3 for details.\r
+\r
+  @param[in] Bar            The mmio base address of the slot to be accessed.\r
+\r
+  @retval EFI_SUCCESS       The voltage is supplied successfully.\r
+  @retval Others            The voltage isn't supplied successfully.\r
+\r
+**/\r
+EFI_STATUS\r
+EmmcPeimHcInitPowerVoltage (\r
+  IN UINTN                  Bar\r
+  )\r
+{\r
+  EFI_STATUS                Status;\r
+  EMMC_HC_SLOT_CAP        Capability;\r
+  UINT8                     MaxVoltage;\r
+  UINT8                     HostCtrl2;\r
+\r
+  //\r
+  // Get the support voltage of the Host Controller\r
+  //\r
+  Status = EmmcPeimHcGetCapability (Bar, &Capability);\r
+  if (EFI_ERROR (Status)) {\r
+    return Status;\r
+  }\r
+  //\r
+  // Calculate supported maximum voltage according to SD Bus Voltage Select\r
+  //\r
+  if (Capability.Voltage33 != 0) {\r
+    //\r
+    // Support 3.3V\r
+    //\r
+    MaxVoltage = 0x0E;\r
+  } else if (Capability.Voltage30 != 0) {\r
+    //\r
+    // Support 3.0V\r
+    //\r
+    MaxVoltage = 0x0C;\r
+  } else if (Capability.Voltage18 != 0) {\r
+    //\r
+    // Support 1.8V\r
+    //\r
+    MaxVoltage = 0x0A;\r
+    HostCtrl2  = BIT3;\r
+    Status = EmmcPeimHcOrMmio (Bar + EMMC_HC_HOST_CTRL2, sizeof (HostCtrl2), &HostCtrl2);\r
+    if (EFI_ERROR (Status)) {\r
+      return Status;\r
+    }\r
+    MicroSecondDelay (5000);\r
+  } else {\r
+    ASSERT (FALSE);\r
+    return EFI_DEVICE_ERROR;\r
+  }\r
+\r
+  //\r
+  // Set SD Bus Voltage Select and SD Bus Power fields in Power Control Register\r
+  //\r
+  Status = EmmcPeimHcPowerControl (Bar, MaxVoltage);\r
+\r
+  return Status;\r
+}\r
+\r
+/**\r
+  Initialize the Timeout Control register with most conservative value at initialization.\r
+\r
+  Refer to SD Host Controller Simplified spec 3.0 Section 2.2.15 for details.\r
+\r
+  @param[in] Bar            The mmio base address of the slot to be accessed.\r
+\r
+  @retval EFI_SUCCESS       The timeout control register is configured successfully.\r
+  @retval Others            The timeout control register isn't configured successfully.\r
+\r
+**/\r
+EFI_STATUS\r
+EmmcPeimHcInitTimeoutCtrl (\r
+  IN UINTN                  Bar\r
+  )\r
+{\r
+  EFI_STATUS                Status;\r
+  UINT8                     Timeout;\r
+\r
+  Timeout = 0x0E;\r
+  Status  = EmmcPeimHcRwMmio (Bar + EMMC_HC_TIMEOUT_CTRL, FALSE, sizeof (Timeout), &Timeout);\r
+\r
+  return Status;\r
+}\r
+\r
+/**\r
+  Initial EMMC host controller with lowest clock frequency, max power and max timeout value\r
+  at initialization.\r
+\r
+  @param[in] Bar            The mmio base address of the slot to be accessed.\r
+\r
+  @retval EFI_SUCCESS       The host controller is initialized successfully.\r
+  @retval Others            The host controller isn't initialized successfully.\r
+\r
+**/\r
+EFI_STATUS\r
+EmmcPeimHcInitHost (\r
+  IN UINTN                  Bar\r
+  )\r
+{\r
+  EFI_STATUS       Status;\r
+\r
+  Status = EmmcPeimHcInitClockFreq (Bar);\r
+  if (EFI_ERROR (Status)) {\r
+    return Status;\r
+  }\r
+\r
+  Status = EmmcPeimHcInitPowerVoltage (Bar);\r
+  if (EFI_ERROR (Status)) {\r
+    return Status;\r
+  }\r
+\r
+  Status = EmmcPeimHcInitTimeoutCtrl (Bar);\r
+  return Status;\r
+}\r
+\r
+/**\r
+  Turn on/off LED.\r
+\r
+  @param[in] Bar            The mmio base address of the slot to be accessed.\r
+  @param[in] On             The boolean to turn on/off LED.\r
+\r
+  @retval EFI_SUCCESS       The LED is turned on/off successfully.\r
+  @retval Others            The LED isn't turned on/off successfully.\r
+\r
+**/\r
+EFI_STATUS\r
+EmmcPeimHcLedOnOff (\r
+  IN UINTN                  Bar,\r
+  IN BOOLEAN                On\r
+  )\r
+{\r
+  EFI_STATUS                Status;\r
+  UINT8                     HostCtrl1;\r
+\r
+  if (On) {\r
+    HostCtrl1 = BIT0;\r
+    Status    = EmmcPeimHcOrMmio (Bar + EMMC_HC_HOST_CTRL1, sizeof (HostCtrl1), &HostCtrl1);\r
+  } else {\r
+    HostCtrl1 = (UINT8)~BIT0;\r
+    Status    = EmmcPeimHcAndMmio (Bar + EMMC_HC_HOST_CTRL1, sizeof (HostCtrl1), &HostCtrl1);\r
+  }\r
+\r
+  return Status;\r
+}\r
+\r
+/**\r
+  Build ADMA descriptor table for transfer.\r
+\r
+  Refer to SD Host Controller Simplified spec 3.0 Section 1.13 for details.\r
+\r
+  @param[in] Trb            The pointer to the EMMC_TRB instance.\r
+\r
+  @retval EFI_SUCCESS       The ADMA descriptor table is created successfully.\r
+  @retval Others            The ADMA descriptor table isn't created successfully.\r
+\r
+**/\r
+EFI_STATUS\r
+BuildAdmaDescTable (\r
+  IN EMMC_TRB               *Trb\r
+  )\r
+{\r
+  EFI_PHYSICAL_ADDRESS      Data;\r
+  UINT64                    DataLen;\r
+  UINT64                    Entries;\r
+  UINT32                    Index;\r
+  UINT64                    Remaining;\r
+  UINT32                    Address;\r
+\r
+  Data    = (EFI_PHYSICAL_ADDRESS)(UINTN)Trb->Data;\r
+  DataLen = Trb->DataLen;\r
+  //\r
+  // Only support 32bit ADMA Descriptor Table\r
+  //\r
+  if ((Data >= 0x100000000ul) || ((Data + DataLen) > 0x100000000ul)) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+  //\r
+  // Address field shall be set on 32-bit boundary (Lower 2-bit is always set to 0)\r
+  // for 32-bit address descriptor table.\r
+  //\r
+  if ((Data & (BIT0 | BIT1)) != 0) {\r
+    DEBUG ((EFI_D_INFO, "The buffer [0x%x] to construct ADMA desc is not aligned to 4 bytes boundary!\n", Data));\r
+  }\r
+\r
+  Entries = DivU64x32 ((DataLen + ADMA_MAX_DATA_PER_LINE - 1), ADMA_MAX_DATA_PER_LINE);\r
+\r
+  Trb->AdmaDescSize = (UINTN)MultU64x32 (Entries, sizeof (EMMC_HC_ADMA_DESC_LINE));\r
+  Trb->AdmaDesc     = EmmcPeimAllocateMem (Trb->Slot->Private->Pool, Trb->AdmaDescSize);\r
+  if (Trb->AdmaDesc == NULL) {\r
+    return EFI_OUT_OF_RESOURCES;\r
+  }\r
+\r
+  Remaining = DataLen;\r
+  Address   = (UINT32)Data;\r
+  for (Index = 0; Index < Entries; Index++) {\r
+    if (Remaining <= ADMA_MAX_DATA_PER_LINE) {\r
+      Trb->AdmaDesc[Index].Valid = 1;\r
+      Trb->AdmaDesc[Index].Act   = 2;\r
+      Trb->AdmaDesc[Index].Length  = (UINT16)Remaining;\r
+      Trb->AdmaDesc[Index].Address = Address;\r
+      break;\r
+    } else {\r
+      Trb->AdmaDesc[Index].Valid = 1;\r
+      Trb->AdmaDesc[Index].Act   = 2;\r
+      Trb->AdmaDesc[Index].Length  = 0;\r
+      Trb->AdmaDesc[Index].Address = Address;\r
+    }\r
+\r
+    Remaining -= ADMA_MAX_DATA_PER_LINE;\r
+    Address   += ADMA_MAX_DATA_PER_LINE;\r
+  }\r
+\r
+  //\r
+  // Set the last descriptor line as end of descriptor table\r
+  //\r
+  Trb->AdmaDesc[Index].End = 1;\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+  Create a new TRB for the EMMC cmd request.\r
+\r
+  @param[in] Slot           The slot number of the EMMC card to send the command to.\r
+  @param[in] Packet         A pointer to the SD command data structure.\r
+\r
+  @return Created Trb or NULL.\r
+\r
+**/\r
+EMMC_TRB *\r
+EmmcPeimCreateTrb (\r
+  IN EMMC_PEIM_HC_SLOT          *Slot,\r
+  IN EMMC_COMMAND_PACKET        *Packet\r
+  )\r
+{\r
+  EMMC_TRB                      *Trb;\r
+  EFI_STATUS                    Status;\r
+  EMMC_HC_SLOT_CAP              Capability;\r
+\r
+  //\r
+  // Calculate a divisor for SD clock frequency\r
+  //\r
+  Status = EmmcPeimHcGetCapability (Slot->EmmcHcBase, &Capability);\r
+  if (EFI_ERROR (Status)) {\r
+    return NULL;\r
+  }\r
+\r
+  Trb = EmmcPeimAllocateMem (Slot->Private->Pool, sizeof (EMMC_TRB));\r
+  if (Trb == NULL) {\r
+    return NULL;\r
+  }\r
+\r
+  Trb->Slot      = Slot;\r
+  Trb->BlockSize = 0x200;\r
+  Trb->Packet    = Packet;\r
+  Trb->Timeout   = Packet->Timeout;\r
+\r
+  if ((Packet->InTransferLength != 0) && (Packet->InDataBuffer != NULL)) {\r
+    Trb->Data    = Packet->InDataBuffer;\r
+    Trb->DataLen = Packet->InTransferLength;\r
+    Trb->Read    = TRUE;\r
+  } else if ((Packet->OutTransferLength != 0) && (Packet->OutDataBuffer != NULL)) {\r
+    Trb->Data    = Packet->OutDataBuffer;\r
+    Trb->DataLen = Packet->OutTransferLength;\r
+    Trb->Read    = FALSE;\r
+  } else if ((Packet->InTransferLength == 0) && (Packet->OutTransferLength == 0)) {\r
+    Trb->Data    = NULL;\r
+    Trb->DataLen = 0;\r
+  } else {\r
+    goto Error;\r
+  }\r
+\r
+  if ((Trb->DataLen % Trb->BlockSize) != 0) {\r
+    if (Trb->DataLen < Trb->BlockSize) {\r
+      Trb->BlockSize = (UINT16)Trb->DataLen;\r
+    }\r
+  }\r
+\r
+  if (Trb->DataLen == 0) {\r
+    Trb->Mode = EmmcNoData;\r
+  } else if (Capability.Adma2 != 0) {\r
+    Trb->Mode = EmmcAdmaMode;\r
+    Status = BuildAdmaDescTable (Trb);\r
+    if (EFI_ERROR (Status)) {\r
+      goto Error;\r
+    }\r
+  } else if (Capability.Sdma != 0) {\r
+    Trb->Mode = EmmcSdmaMode;\r
+  } else {\r
+    Trb->Mode = EmmcPioMode;\r
+  }\r
+\r
+  return Trb;\r
+\r
+Error:\r
+  EmmcPeimFreeTrb (Trb);\r
+  return NULL;\r
+}\r
+\r
+/**\r
+  Free the resource used by the TRB.\r
+\r
+  @param[in] Trb        The pointer to the EMMC_TRB instance.\r
+\r
+**/\r
+VOID\r
+EmmcPeimFreeTrb (\r
+  IN EMMC_TRB           *Trb\r
+  )\r
+{\r
+  if ((Trb != NULL) && (Trb->AdmaDesc != NULL)) {\r
+    EmmcPeimFreeMem (Trb->Slot->Private->Pool, Trb->AdmaDesc, Trb->AdmaDescSize);\r
+  }\r
+\r
+  if (Trb != NULL) {\r
+    EmmcPeimFreeMem (Trb->Slot->Private->Pool, Trb, sizeof (EMMC_TRB));\r
+  }\r
+  return;\r
+}\r
+\r
+/**\r
+  Check if the env is ready for execute specified TRB.\r
+\r
+  @param[in] Bar            The mmio base address of the slot to be accessed.\r
+  @param[in] Trb            The pointer to the EMMC_TRB instance.\r
+\r
+  @retval EFI_SUCCESS       The env is ready for TRB execution.\r
+  @retval EFI_NOT_READY     The env is not ready for TRB execution.\r
+  @retval Others            Some erros happen.\r
+\r
+**/\r
+EFI_STATUS\r
+EmmcPeimCheckTrbEnv (\r
+  IN UINTN                  Bar,\r
+  IN EMMC_TRB               *Trb\r
+  )\r
+{\r
+  EFI_STATUS                          Status;\r
+  EMMC_COMMAND_PACKET                 *Packet;\r
+  UINT32                              PresentState;\r
+\r
+  Packet = Trb->Packet;\r
+\r
+  if ((Packet->EmmcCmdBlk->CommandType == EmmcCommandTypeAdtc) ||\r
+      (Packet->EmmcCmdBlk->ResponseType == EmmcResponceTypeR1b) ||\r
+      (Packet->EmmcCmdBlk->ResponseType == EmmcResponceTypeR5b)) {\r
+    //\r
+    // Wait Command Inhibit (CMD) and Command Inhibit (DAT) in\r
+    // the Present State register to be 0\r
+    //\r
+    PresentState = BIT0 | BIT1;\r
+    if (Packet->EmmcCmdBlk->CommandIndex == EMMC_SEND_TUNING_BLOCK) {\r
+      PresentState = BIT0;\r
+    }\r
+  } else {\r
+    //\r
+    // Wait Command Inhibit (CMD) in the Present State register\r
+    // to be 0\r
+    //\r
+    PresentState = BIT0;\r
+  }\r
+\r
+  Status = EmmcPeimHcCheckMmioSet (\r
+             Bar + EMMC_HC_PRESENT_STATE,\r
+             sizeof (PresentState),\r
+             PresentState,\r
+             0\r
+             );\r
+\r
+  return Status;\r
+}\r
+\r
+/**\r
+  Wait for the env to be ready for execute specified TRB.\r
+\r
+  @param[in] Bar            The mmio base address of the slot to be accessed.\r
+  @param[in] Trb            The pointer to the EMMC_TRB instance.\r
+\r
+  @retval EFI_SUCCESS       The env is ready for TRB execution.\r
+  @retval EFI_TIMEOUT       The env is not ready for TRB execution in time.\r
+  @retval Others            Some erros happen.\r
+\r
+**/\r
+EFI_STATUS\r
+EmmcPeimWaitTrbEnv (\r
+  IN UINTN                  Bar,\r
+  IN EMMC_TRB               *Trb\r
+  )\r
+{\r
+  EFI_STATUS                          Status;\r
+  EMMC_COMMAND_PACKET                 *Packet;\r
+  UINT64                              Timeout;\r
+  BOOLEAN                             InfiniteWait;\r
+\r
+  //\r
+  // Wait Command Complete Interrupt Status bit in Normal Interrupt Status Register\r
+  //\r
+  Packet  = Trb->Packet;\r
+  Timeout = Packet->Timeout;\r
+  if (Timeout == 0) {\r
+    InfiniteWait = TRUE;\r
+  } else {\r
+    InfiniteWait = FALSE;\r
+  }\r
+\r
+  while (InfiniteWait || (Timeout > 0)) {\r
+    //\r
+    // Check Trb execution result by reading Normal Interrupt Status register.\r
+    //\r
+    Status = EmmcPeimCheckTrbEnv (Bar, Trb);\r
+    if (Status != EFI_NOT_READY) {\r
+      return Status;\r
+    }\r
+    //\r
+    // Stall for 1 microsecond.\r
+    //\r
+    MicroSecondDelay (1);\r
+\r
+    Timeout--;\r
+  }\r
+\r
+  return EFI_TIMEOUT;\r
+}\r
+\r
+/**\r
+  Execute the specified TRB.\r
+\r
+  @param[in] Bar            The mmio base address of the slot to be accessed.\r
+  @param[in] Trb            The pointer to the EMMC_TRB instance.\r
+\r
+  @retval EFI_SUCCESS       The TRB is sent to host controller successfully.\r
+  @retval Others            Some erros happen when sending this request to the host controller.\r
+\r
+**/\r
+EFI_STATUS\r
+EmmcPeimExecTrb (\r
+  IN UINTN                  Bar,\r
+  IN EMMC_TRB               *Trb\r
+  )\r
+{\r
+  EFI_STATUS                          Status;\r
+  EMMC_COMMAND_PACKET                 *Packet;\r
+  UINT16                              Cmd;\r
+  UINT16                              IntStatus;\r
+  UINT32                              Argument;\r
+  UINT16                              BlkCount;\r
+  UINT16                              BlkSize;\r
+  UINT16                              TransMode;\r
+  UINT8                               HostCtrl1;\r
+  UINT32                              SdmaAddr;\r
+  UINT64                              AdmaAddr;\r
+\r
+  Packet = Trb->Packet;\r
+  //\r
+  // Clear all bits in Error Interrupt Status Register\r
+  //\r
+  IntStatus = 0xFFFF;\r
+  Status    = EmmcPeimHcRwMmio (Bar + EMMC_HC_ERR_INT_STS, FALSE, sizeof (IntStatus), &IntStatus);\r
+  if (EFI_ERROR (Status)) {\r
+    return Status;\r
+  }\r
+  //\r
+  // Clear all bits in Normal Interrupt Status Register\r
+  //\r
+  IntStatus = 0xFFFF;\r
+  Status    = EmmcPeimHcRwMmio (Bar + EMMC_HC_NOR_INT_STS, FALSE, sizeof (IntStatus), &IntStatus);\r
+  if (EFI_ERROR (Status)) {\r
+    return Status;\r
+  }\r
+  //\r
+  // Set Host Control 1 register DMA Select field\r
+  //\r
+  if (Trb->Mode == EmmcAdmaMode) {\r
+    HostCtrl1 = BIT4;\r
+    Status = EmmcPeimHcOrMmio (Bar + EMMC_HC_HOST_CTRL1, sizeof (HostCtrl1), &HostCtrl1);\r
+    if (EFI_ERROR (Status)) {\r
+      return Status;\r
+    }\r
+  }\r
+\r
+  EmmcPeimHcLedOnOff (Bar, TRUE);\r
+\r
+  if (Trb->Mode == EmmcSdmaMode) {\r
+    if ((UINT64)(UINTN)Trb->Data >= 0x100000000ul) {\r
+      return EFI_INVALID_PARAMETER;\r
+    }\r
+\r
+    SdmaAddr = (UINT32)(UINTN)Trb->Data;\r
+    Status   = EmmcPeimHcRwMmio (Bar + EMMC_HC_SDMA_ADDR, FALSE, sizeof (SdmaAddr), &SdmaAddr);\r
+    if (EFI_ERROR (Status)) {\r
+      return Status;\r
+    }\r
+  } else if (Trb->Mode == EmmcAdmaMode) {\r
+    AdmaAddr = (UINT64)(UINTN)Trb->AdmaDesc;\r
+    Status   = EmmcPeimHcRwMmio (Bar + EMMC_HC_ADMA_SYS_ADDR, FALSE, sizeof (AdmaAddr), &AdmaAddr);\r
+    if (EFI_ERROR (Status)) {\r
+      return Status;\r
+    }\r
+  }\r
+\r
+  BlkSize = Trb->BlockSize;\r
+  if (Trb->Mode == EmmcSdmaMode) {\r
+    //\r
+    // Set SDMA boundary to be 512K bytes.\r
+    //\r
+    BlkSize |= 0x7000;\r
+  }\r
+\r
+  Status = EmmcPeimHcRwMmio (Bar + EMMC_HC_BLK_SIZE, FALSE, sizeof (BlkSize), &BlkSize);\r
+  if (EFI_ERROR (Status)) {\r
+    return Status;\r
+  }\r
+\r
+  BlkCount = (UINT16)(Trb->DataLen / Trb->BlockSize);\r
+  Status   = EmmcPeimHcRwMmio (Bar + EMMC_HC_BLK_COUNT, FALSE, sizeof (BlkCount), &BlkCount);\r
+  if (EFI_ERROR (Status)) {\r
+    return Status;\r
+  }\r
+\r
+  Argument = Packet->EmmcCmdBlk->CommandArgument;\r
+  Status   = EmmcPeimHcRwMmio (Bar + EMMC_HC_ARG1, FALSE, sizeof (Argument), &Argument);\r
+  if (EFI_ERROR (Status)) {\r
+    return Status;\r
+  }\r
+\r
+  TransMode = 0;\r
+  if (Trb->Mode != EmmcNoData) {\r
+    if (Trb->Mode != EmmcPioMode) {\r
+      TransMode |= BIT0;\r
+    }\r
+    if (Trb->Read) {\r
+      TransMode |= BIT4;\r
+    }\r
+    if (BlkCount != 0) {\r
+      TransMode |= BIT5 | BIT1;\r
+    }\r
+  }\r
+\r
+  Status = EmmcPeimHcRwMmio (Bar + EMMC_HC_TRANS_MOD, FALSE, sizeof (TransMode), &TransMode);\r
+  if (EFI_ERROR (Status)) {\r
+    return Status;\r
+  }\r
+\r
+  Cmd = (UINT16)LShiftU64(Packet->EmmcCmdBlk->CommandIndex, 8);\r
+  if (Packet->EmmcCmdBlk->CommandType == EmmcCommandTypeAdtc) {\r
+    Cmd |= BIT5;\r
+  }\r
+  //\r
+  // Convert ResponseType to value\r
+  //\r
+  if (Packet->EmmcCmdBlk->CommandType != EmmcCommandTypeBc) {\r
+    switch (Packet->EmmcCmdBlk->ResponseType) {\r
+      case EmmcResponceTypeR1:\r
+      case EmmcResponceTypeR5:\r
+      case EmmcResponceTypeR6:\r
+      case EmmcResponceTypeR7:\r
+        Cmd |= (BIT1 | BIT3 | BIT4);\r
+        break;\r
+      case EmmcResponceTypeR2:\r
+        Cmd |= (BIT0 | BIT3);\r
+       break;\r
+      case EmmcResponceTypeR3:\r
+      case EmmcResponceTypeR4:\r
+        Cmd |= BIT1;\r
+        break;\r
+      case EmmcResponceTypeR1b:\r
+      case EmmcResponceTypeR5b:\r
+        Cmd |= (BIT0 | BIT1 | BIT3 | BIT4);\r
+        break;\r
+      default:\r
+        ASSERT (FALSE);\r
+        break;\r
+    }\r
+  }\r
+  //\r
+  // Execute cmd\r
+  //\r
+  Status = EmmcPeimHcRwMmio (Bar + EMMC_HC_COMMAND, FALSE, sizeof (Cmd), &Cmd);\r
+  return Status;\r
+}\r
+\r
+/**\r
+  Check the TRB execution result.\r
+\r
+  @param[in] Bar            The mmio base address of the slot to be accessed.\r
+  @param[in] Trb            The pointer to the EMMC_TRB instance.\r
+\r
+  @retval EFI_SUCCESS       The TRB is executed successfully.\r
+  @retval EFI_NOT_READY     The TRB is not completed for execution.\r
+  @retval Others            Some erros happen when executing this request.\r
+\r
+**/\r
+EFI_STATUS\r
+EmmcPeimCheckTrbResult (\r
+  IN UINTN                  Bar,\r
+  IN EMMC_TRB               *Trb\r
+  )\r
+{\r
+  EFI_STATUS                          Status;\r
+  EMMC_COMMAND_PACKET                 *Packet;\r
+  UINT16                              IntStatus;\r
+  UINT32                              Response[4];\r
+  UINT32                              SdmaAddr;\r
+  UINT8                               Index;\r
+  UINT8                               SwReset;\r
+\r
+  SwReset = 0;\r
+  Packet  = Trb->Packet;\r
+  //\r
+  // Check Trb execution result by reading Normal Interrupt Status register.\r
+  //\r
+  Status = EmmcPeimHcRwMmio (\r
+             Bar + EMMC_HC_NOR_INT_STS,\r
+             TRUE,\r
+             sizeof (IntStatus),\r
+             &IntStatus\r
+             );\r
+  if (EFI_ERROR (Status)) {\r
+    goto Done;\r
+  }\r
+  //\r
+  // Check Transfer Complete bit is set or not.\r
+  //\r
+  if ((IntStatus & BIT1) == BIT1) {\r
+    if ((IntStatus & BIT15) == BIT15) {\r
+      //\r
+      // Read Error Interrupt Status register to check if the error is\r
+      // Data Timeout Error.\r
+      // If yes, treat it as success as Transfer Complete has higher\r
+      // priority than Data Timeout Error.\r
+      //\r
+      Status = EmmcPeimHcRwMmio (\r
+                 Bar + EMMC_HC_ERR_INT_STS,\r
+                 TRUE,\r
+                 sizeof (IntStatus),\r
+                 &IntStatus\r
+                 );\r
+      if (!EFI_ERROR (Status)) {\r
+        if ((IntStatus & BIT4) == BIT4) {\r
+          Status = EFI_SUCCESS;\r
+        } else {\r
+          Status = EFI_DEVICE_ERROR;\r
+        }\r
+      }\r
+    }\r
+\r
+    goto Done;\r
+  }\r
+  //\r
+  // Check if there is a error happened during cmd execution.\r
+  // If yes, then do error recovery procedure to follow SD Host Controller\r
+  // Simplified Spec 3.0 section 3.10.1.\r
+  //\r
+  if ((IntStatus & BIT15) == BIT15) {\r
+    Status = EmmcPeimHcRwMmio (\r
+               Bar + EMMC_HC_ERR_INT_STS,\r
+               TRUE,\r
+               sizeof (IntStatus),\r
+               &IntStatus\r
+               );\r
+    if (EFI_ERROR (Status)) {\r
+      goto Done;\r
+    }\r
+\r
+    if ((IntStatus & 0x0F) != 0) {\r
+      SwReset |= BIT1;\r
+    }\r
+    if ((IntStatus & 0xF0) != 0) {\r
+      SwReset |= BIT2;\r
+    }\r
+\r
+    Status = EmmcPeimHcRwMmio (\r
+               Bar + EMMC_HC_SW_RST,\r
+               FALSE,\r
+               sizeof (SwReset),\r
+               &SwReset\r
+               );\r
+    if (EFI_ERROR (Status)) {\r
+      goto Done;\r
+    }\r
+    Status = EmmcPeimHcWaitMmioSet (\r
+               Bar + EMMC_HC_SW_RST,\r
+               sizeof (SwReset),\r
+               0xFF,\r
+               0,\r
+               EMMC_TIMEOUT\r
+               );\r
+    if (EFI_ERROR (Status)) {\r
+      goto Done;\r
+    }\r
+\r
+    Status = EFI_DEVICE_ERROR;\r
+    goto Done;\r
+  }\r
+  //\r
+  // Check if DMA interrupt is signalled for the SDMA transfer.\r
+  //\r
+  if ((Trb->Mode == EmmcSdmaMode) && ((IntStatus & BIT3) == BIT3)) {\r
+    //\r
+    // Clear DMA interrupt bit.\r
+    //\r
+    IntStatus = BIT3;\r
+    Status    = EmmcPeimHcRwMmio (\r
+                  Bar + EMMC_HC_NOR_INT_STS,\r
+                  FALSE,\r
+                  sizeof (IntStatus),\r
+                  &IntStatus\r
+                  );\r
+    if (EFI_ERROR (Status)) {\r
+      goto Done;\r
+    }\r
+    //\r
+    // Update SDMA Address register.\r
+    //\r
+    SdmaAddr = EMMC_SDMA_ROUND_UP ((UINT32)(UINTN)Trb->Data, EMMC_SDMA_BOUNDARY);\r
+    Status   = EmmcPeimHcRwMmio (\r
+                 Bar + EMMC_HC_SDMA_ADDR,\r
+                 FALSE,\r
+                 sizeof (UINT32),\r
+                 &SdmaAddr\r
+                 );\r
+    if (EFI_ERROR (Status)) {\r
+      goto Done;\r
+    }\r
+    Trb->Data = (VOID*)(UINTN)SdmaAddr;\r
+  }\r
+\r
+  if ((Packet->EmmcCmdBlk->CommandType != EmmcCommandTypeAdtc) &&\r
+      (Packet->EmmcCmdBlk->ResponseType != EmmcResponceTypeR1b) &&\r
+      (Packet->EmmcCmdBlk->ResponseType != EmmcResponceTypeR5b)) {\r
+    if ((IntStatus & BIT0) == BIT0) {\r
+      Status = EFI_SUCCESS;\r
+      goto Done;\r
+    }\r
+  }\r
+\r
+  if (Packet->EmmcCmdBlk->CommandIndex == EMMC_SEND_TUNING_BLOCK) {\r
+    Status = EFI_SUCCESS;\r
+    goto Done;\r
+  }\r
+\r
+  Status = EFI_NOT_READY;\r
+Done:\r
+  //\r
+  // Get response data when the cmd is executed successfully.\r
+  //\r
+  if (!EFI_ERROR (Status)) {\r
+    if (Packet->EmmcCmdBlk->CommandType != EmmcCommandTypeBc) {\r
+      for (Index = 0; Index < 4; Index++) {\r
+        Status = EmmcPeimHcRwMmio (\r
+                   Bar + EMMC_HC_RESPONSE + Index * 4,\r
+                   TRUE,\r
+                   sizeof (UINT32),\r
+                   &Response[Index]\r
+                   );\r
+        if (EFI_ERROR (Status)) {\r
+          EmmcPeimHcLedOnOff (Bar, FALSE);\r
+          return Status;\r
+        }\r
+      }\r
+      CopyMem (Packet->EmmcStatusBlk, Response, sizeof (Response));\r
+    }\r
+  }\r
+\r
+  if (Status != EFI_NOT_READY) {\r
+    EmmcPeimHcLedOnOff (Bar, FALSE);\r
+  }\r
+\r
+  return Status;\r
+}\r
+\r
+/**\r
+  Wait for the TRB execution result.\r
+\r
+  @param[in] Bar            The mmio base address of the slot to be accessed.\r
+  @param[in] Trb            The pointer to the EMMC_TRB instance.\r
+\r
+  @retval EFI_SUCCESS       The TRB is executed successfully.\r
+  @retval Others            Some erros happen when executing this request.\r
+\r
+**/\r
+EFI_STATUS\r
+EmmcPeimWaitTrbResult (\r
+  IN UINTN                  Bar,\r
+  IN EMMC_TRB               *Trb\r
+  )\r
+{\r
+  EFI_STATUS                        Status;\r
+  EMMC_COMMAND_PACKET               *Packet;\r
+  UINT64                            Timeout;\r
+  BOOLEAN                           InfiniteWait;\r
+\r
+  Packet = Trb->Packet;\r
+  //\r
+  // Wait Command Complete Interrupt Status bit in Normal Interrupt Status Register\r
+  //\r
+  Timeout = Packet->Timeout;\r
+  if (Timeout == 0) {\r
+    InfiniteWait = TRUE;\r
+  } else {\r
+    InfiniteWait = FALSE;\r
+  }\r
+\r
+  while (InfiniteWait || (Timeout > 0)) {\r
+    //\r
+    // Check Trb execution result by reading Normal Interrupt Status register.\r
+    //\r
+    Status = EmmcPeimCheckTrbResult (Bar, Trb);\r
+    if (Status != EFI_NOT_READY) {\r
+      return Status;\r
+    }\r
+    //\r
+    // Stall for 1 microsecond.\r
+    //\r
+    MicroSecondDelay (1);\r
+\r
+    Timeout--;\r
+  }\r
+\r
+  return EFI_TIMEOUT;\r
+}\r
+\r
+/**\r
+  Sends EMMC command to an EMMC card that is attached to the EMMC controller.\r
+\r
+  If Packet is successfully sent to the EMMC card, then EFI_SUCCESS is returned.\r
+\r
+  If a device error occurs while sending the Packet, then EFI_DEVICE_ERROR is returned.\r
+\r
+  If Slot is not in a valid range for the EMMC controller, then EFI_INVALID_PARAMETER\r
+  is returned.\r
+\r
+  If Packet defines a data command but both InDataBuffer and OutDataBuffer are NULL,\r
+  EFI_INVALID_PARAMETER is returned.\r
+\r
+  @param[in]     Slot           The slot number of the Emmc card to send the command to.\r
+  @param[in,out] Packet         A pointer to the EMMC command data structure.\r
+\r
+  @retval EFI_SUCCESS           The EMMC Command Packet was sent by the host.\r
+  @retval EFI_DEVICE_ERROR      A device error occurred while attempting to send the SD\r
+                                command Packet.\r
+  @retval EFI_INVALID_PARAMETER Packet, Slot, or the contents of the Packet is invalid.\r
+  @retval EFI_INVALID_PARAMETER Packet defines a data command but both InDataBuffer and\r
+                                OutDataBuffer are NULL.\r
+  @retval EFI_NO_MEDIA          SD Device not present in the Slot.\r
+  @retval EFI_UNSUPPORTED       The command described by the EMMC Command Packet is not\r
+                                supported by the host controller.\r
+  @retval EFI_BAD_BUFFER_SIZE   The InTransferLength or OutTransferLength exceeds the\r
+                                limit supported by EMMC card ( i.e. if the number of bytes\r
+                                exceed the Last LBA).\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+EmmcPeimExecCmd (\r
+  IN     EMMC_PEIM_HC_SLOT       *Slot,\r
+  IN OUT EMMC_COMMAND_PACKET     *Packet\r
+  )\r
+{\r
+  EFI_STATUS                      Status;\r
+  EMMC_TRB                        *Trb;\r
+\r
+  if (Packet == NULL) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  if ((Packet->EmmcCmdBlk == NULL) || (Packet->EmmcStatusBlk == NULL)) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  if ((Packet->OutDataBuffer == NULL) && (Packet->OutTransferLength != 0)) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  if ((Packet->InDataBuffer == NULL) && (Packet->InTransferLength != 0)) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  Trb = EmmcPeimCreateTrb (Slot, Packet);\r
+  if (Trb == NULL) {\r
+    return EFI_OUT_OF_RESOURCES;\r
+  }\r
+\r
+  Status = EmmcPeimWaitTrbEnv (Slot->EmmcHcBase, Trb);\r
+  if (EFI_ERROR (Status)) {\r
+    goto Done;\r
+  }\r
+\r
+  Status = EmmcPeimExecTrb (Slot->EmmcHcBase, Trb);\r
+  if (EFI_ERROR (Status)) {\r
+    goto Done;\r
+  }\r
+\r
+  Status = EmmcPeimWaitTrbResult (Slot->EmmcHcBase, Trb);\r
+  if (EFI_ERROR (Status)) {\r
+    goto Done;\r
+  }\r
+\r
+Done:\r
+  EmmcPeimFreeTrb (Trb);\r
+\r
+  return Status;\r
+}\r
+\r
+/**\r
+  Send command GO_IDLE_STATE (CMD0 with argument of 0x00000000) to the device to\r
+  make it go to Idle State.\r
+\r
+  Refer to EMMC Electrical Standard Spec 5.1 Section 6.4 for details.\r
+\r
+  @param[in] Slot           The slot number of the Emmc card to send the command to.\r
+\r
+  @retval EFI_SUCCESS       The EMMC device is reset correctly.\r
+  @retval Others            The device reset fails.\r
+\r
+**/\r
+EFI_STATUS\r
+EmmcPeimReset (\r
+  IN EMMC_PEIM_HC_SLOT      *Slot\r
+  )\r
+{\r
+  EMMC_COMMAND_BLOCK                    EmmcCmdBlk;\r
+  EMMC_STATUS_BLOCK                     EmmcStatusBlk;\r
+  EMMC_COMMAND_PACKET                   Packet;\r
+  EFI_STATUS                            Status;\r
+\r
+  ZeroMem (&EmmcCmdBlk, sizeof (EmmcCmdBlk));\r
+  ZeroMem (&EmmcStatusBlk, sizeof (EmmcStatusBlk));\r
+  ZeroMem (&Packet, sizeof (Packet));\r
+\r
+  Packet.EmmcCmdBlk    = &EmmcCmdBlk;\r
+  Packet.EmmcStatusBlk = &EmmcStatusBlk;\r
+  Packet.Timeout        = EMMC_TIMEOUT;\r
+\r
+  EmmcCmdBlk.CommandIndex = EMMC_GO_IDLE_STATE;\r
+  EmmcCmdBlk.CommandType  = EmmcCommandTypeBc;\r
+  EmmcCmdBlk.ResponseType = 0;\r
+  EmmcCmdBlk.CommandArgument = 0;\r
+\r
+  Status = EmmcPeimExecCmd (Slot, &Packet);\r
+\r
+  return Status;\r
+}\r
+\r
+/**\r
+  Send command SEND_OP_COND to the EMMC device to get the data of the OCR register.\r
+\r
+  Refer to EMMC Electrical Standard Spec 5.1 Section 6.4 for details.\r
+\r
+  @param[in]      Slot      The slot number of the Emmc card to send the command to.\r
+  @param[in, out] Argument  On input, the argument of SEND_OP_COND is to send to the device.\r
+                            On output, the argument is the value of OCR register.\r
+\r
+  @retval EFI_SUCCESS       The operation is done correctly.\r
+  @retval Others            The operation fails.\r
+\r
+**/\r
+EFI_STATUS\r
+EmmcPeimGetOcr (\r
+  IN     EMMC_PEIM_HC_SLOT      *Slot,\r
+  IN OUT UINT32                 *Argument\r
+  )\r
+{\r
+  EMMC_COMMAND_BLOCK                    EmmcCmdBlk;\r
+  EMMC_STATUS_BLOCK                     EmmcStatusBlk;\r
+  EMMC_COMMAND_PACKET                   Packet;\r
+  EFI_STATUS                            Status;\r
+\r
+  ZeroMem (&EmmcCmdBlk, sizeof (EmmcCmdBlk));\r
+  ZeroMem (&EmmcStatusBlk, sizeof (EmmcStatusBlk));\r
+  ZeroMem (&Packet, sizeof (Packet));\r
+\r
+  Packet.EmmcCmdBlk    = &EmmcCmdBlk;\r
+  Packet.EmmcStatusBlk = &EmmcStatusBlk;\r
+  Packet.Timeout        = EMMC_TIMEOUT;\r
+\r
+  EmmcCmdBlk.CommandIndex = EMMC_SEND_OP_COND;\r
+  EmmcCmdBlk.CommandType  = EmmcCommandTypeBcr;\r
+  EmmcCmdBlk.ResponseType = EmmcResponceTypeR3;\r
+  EmmcCmdBlk.CommandArgument = *Argument;\r
+\r
+  Status = EmmcPeimExecCmd (Slot, &Packet);\r
+  if (!EFI_ERROR (Status)) {\r
+    //\r
+    // For details, refer to SD Host Controller Simplified Spec 3.0 Table 2-12.\r
+    //\r
+    *Argument = EmmcStatusBlk.Resp0;\r
+  }\r
+\r
+  return Status;\r
+}\r
+\r
+/**\r
+  Broadcast command ALL_SEND_CID to the bus to ask all the EMMC devices to send the\r
+  data of their CID registers.\r
+\r
+  Refer to EMMC Electrical Standard Spec 5.1 Section 6.4 for details.\r
+\r
+  @param[in] Slot           The slot number of the Emmc card to send the command to.\r
+\r
+  @retval EFI_SUCCESS       The operation is done correctly.\r
+  @retval Others            The operation fails.\r
+\r
+**/\r
+EFI_STATUS\r
+EmmcPeimGetAllCid (\r
+  IN EMMC_PEIM_HC_SLOT      *Slot\r
+  )\r
+{\r
+  EMMC_COMMAND_BLOCK                    EmmcCmdBlk;\r
+  EMMC_STATUS_BLOCK                     EmmcStatusBlk;\r
+  EMMC_COMMAND_PACKET                   Packet;\r
+  EFI_STATUS                            Status;\r
+\r
+  ZeroMem (&EmmcCmdBlk, sizeof (EmmcCmdBlk));\r
+  ZeroMem (&EmmcStatusBlk, sizeof (EmmcStatusBlk));\r
+  ZeroMem (&Packet, sizeof (Packet));\r
+\r
+  Packet.EmmcCmdBlk    = &EmmcCmdBlk;\r
+  Packet.EmmcStatusBlk = &EmmcStatusBlk;\r
+  Packet.Timeout        = EMMC_TIMEOUT;\r
+\r
+  EmmcCmdBlk.CommandIndex = EMMC_ALL_SEND_CID;\r
+  EmmcCmdBlk.CommandType  = EmmcCommandTypeBcr;\r
+  EmmcCmdBlk.ResponseType = EmmcResponceTypeR2;\r
+  EmmcCmdBlk.CommandArgument = 0;\r
+\r
+  Status = EmmcPeimExecCmd (Slot, &Packet);\r
+\r
+  return Status;\r
+}\r
+\r
+/**\r
+  Send command SET_RELATIVE_ADDR to the EMMC device to assign a Relative device\r
+  Address (RCA).\r
+\r
+  Refer to EMMC Electrical Standard Spec 5.1 Section 6.4 for details.\r
+\r
+  @param[in] Slot           The slot number of the Emmc card to send the command to.\r
+  @param[in] Rca            The relative device address to be assigned.\r
+\r
+  @retval EFI_SUCCESS       The operation is done correctly.\r
+  @retval Others            The operation fails.\r
+\r
+**/\r
+EFI_STATUS\r
+EmmcPeimSetRca (\r
+  IN EMMC_PEIM_HC_SLOT      *Slot,\r
+  IN UINT32                 Rca\r
+  )\r
+{\r
+  EMMC_COMMAND_BLOCK                    EmmcCmdBlk;\r
+  EMMC_STATUS_BLOCK                     EmmcStatusBlk;\r
+  EMMC_COMMAND_PACKET                   Packet;\r
+  EFI_STATUS                            Status;\r
+\r
+  ZeroMem (&EmmcCmdBlk, sizeof (EmmcCmdBlk));\r
+  ZeroMem (&EmmcStatusBlk, sizeof (EmmcStatusBlk));\r
+  ZeroMem (&Packet, sizeof (Packet));\r
+\r
+  Packet.EmmcCmdBlk    = &EmmcCmdBlk;\r
+  Packet.EmmcStatusBlk = &EmmcStatusBlk;\r
+  Packet.Timeout        = EMMC_TIMEOUT;\r
+\r
+  EmmcCmdBlk.CommandIndex = EMMC_SET_RELATIVE_ADDR;\r
+  EmmcCmdBlk.CommandType  = EmmcCommandTypeAc;\r
+  EmmcCmdBlk.ResponseType = EmmcResponceTypeR1;\r
+  EmmcCmdBlk.CommandArgument = Rca << 16;\r
+\r
+  Status = EmmcPeimExecCmd (Slot, &Packet);\r
+\r
+  return Status;\r
+}\r
+\r
+/**\r
+  Send command SEND_CSD to the EMMC device to get the data of the CSD register.\r
+\r
+  Refer to EMMC Electrical Standard Spec 5.1 Section 6.10.4 for details.\r
+\r
+  @param[in]  Slot          The slot number of the Emmc card to send the command to.\r
+  @param[in]  Rca           The relative device address of selected device.\r
+  @param[out] Csd           The buffer to store the content of the CSD register.\r
+                            Note the caller should ignore the lowest byte of this\r
+                            buffer as the content of this byte is meaningless even\r
+                            if the operation succeeds.\r
+\r
+  @retval EFI_SUCCESS       The operation is done correctly.\r
+  @retval Others            The operation fails.\r
+\r
+**/\r
+EFI_STATUS\r
+EmmcPeimGetCsd (\r
+  IN     EMMC_PEIM_HC_SLOT              *Slot,\r
+  IN     UINT32                         Rca,\r
+     OUT EMMC_CSD                       *Csd\r
+  )\r
+{\r
+  EMMC_COMMAND_BLOCK                    EmmcCmdBlk;\r
+  EMMC_STATUS_BLOCK                     EmmcStatusBlk;\r
+  EMMC_COMMAND_PACKET                   Packet;\r
+  EFI_STATUS                            Status;\r
+\r
+  ZeroMem (&EmmcCmdBlk, sizeof (EmmcCmdBlk));\r
+  ZeroMem (&EmmcStatusBlk, sizeof (EmmcStatusBlk));\r
+  ZeroMem (&Packet, sizeof (Packet));\r
+\r
+  Packet.EmmcCmdBlk    = &EmmcCmdBlk;\r
+  Packet.EmmcStatusBlk = &EmmcStatusBlk;\r
+  Packet.Timeout        = EMMC_TIMEOUT;\r
+\r
+  EmmcCmdBlk.CommandIndex = EMMC_SEND_CSD;\r
+  EmmcCmdBlk.CommandType  = EmmcCommandTypeAc;\r
+  EmmcCmdBlk.ResponseType = EmmcResponceTypeR2;\r
+  EmmcCmdBlk.CommandArgument = Rca << 16;\r
+\r
+  Status = EmmcPeimExecCmd (Slot, &Packet);\r
+  if (!EFI_ERROR (Status)) {\r
+    //\r
+    // For details, refer to SD Host Controller Simplified Spec 3.0 Table 2-12.\r
+    //\r
+    CopyMem (((UINT8*)Csd) + 1, &EmmcStatusBlk.Resp0, sizeof (EMMC_CSD) - 1);\r
+  }\r
+\r
+  return Status;\r
+}\r
+\r
+/**\r
+  Send command SELECT_DESELECT_CARD to the EMMC device to select/deselect it.\r
+\r
+  Refer to EMMC Electrical Standard Spec 5.1 Section 6.10.4 for details.\r
+\r
+  @param[in] Slot           The slot number of the Emmc card to send the command to.\r
+  @param[in] Rca            The relative device address of selected device.\r
+\r
+  @retval EFI_SUCCESS       The operation is done correctly.\r
+  @retval Others            The operation fails.\r
+\r
+**/\r
+EFI_STATUS\r
+EmmcPeimSelect (\r
+  IN EMMC_PEIM_HC_SLOT      *Slot,\r
+  IN UINT32                 Rca\r
+  )\r
+{\r
+  EMMC_COMMAND_BLOCK                    EmmcCmdBlk;\r
+  EMMC_STATUS_BLOCK                     EmmcStatusBlk;\r
+  EMMC_COMMAND_PACKET                   Packet;\r
+  EFI_STATUS                            Status;\r
+\r
+  ZeroMem (&EmmcCmdBlk, sizeof (EmmcCmdBlk));\r
+  ZeroMem (&EmmcStatusBlk, sizeof (EmmcStatusBlk));\r
+  ZeroMem (&Packet, sizeof (Packet));\r
+\r
+  Packet.EmmcCmdBlk    = &EmmcCmdBlk;\r
+  Packet.EmmcStatusBlk = &EmmcStatusBlk;\r
+  Packet.Timeout        = EMMC_TIMEOUT;\r
+\r
+  EmmcCmdBlk.CommandIndex = EMMC_SELECT_DESELECT_CARD;\r
+  EmmcCmdBlk.CommandType  = EmmcCommandTypeAc;\r
+  EmmcCmdBlk.ResponseType = EmmcResponceTypeR1;\r
+  EmmcCmdBlk.CommandArgument = Rca << 16;\r
+\r
+  Status = EmmcPeimExecCmd (Slot, &Packet);\r
+\r
+  return Status;\r
+}\r
+\r
+/**\r
+  Send command SEND_EXT_CSD to the EMMC device to get the data of the EXT_CSD register.\r
+\r
+  Refer to EMMC Electrical Standard Spec 5.1 Section 6.10.4 for details.\r
+\r
+  @param[in]  Slot          The slot number of the Emmc card to send the command to.\r
+  @param[out] ExtCsd        The buffer to store the content of the EXT_CSD register.\r
+\r
+  @retval EFI_SUCCESS       The operation is done correctly.\r
+  @retval Others            The operation fails.\r
+\r
+**/\r
+EFI_STATUS\r
+EmmcPeimGetExtCsd (\r
+  IN     EMMC_PEIM_HC_SLOT              *Slot,\r
+     OUT EMMC_EXT_CSD                   *ExtCsd\r
+  )\r
+{\r
+  EMMC_COMMAND_BLOCK                    EmmcCmdBlk;\r
+  EMMC_STATUS_BLOCK                     EmmcStatusBlk;\r
+  EMMC_COMMAND_PACKET                   Packet;\r
+  EFI_STATUS                            Status;\r
+\r
+  ZeroMem (&EmmcCmdBlk, sizeof (EmmcCmdBlk));\r
+  ZeroMem (&EmmcStatusBlk, sizeof (EmmcStatusBlk));\r
+  ZeroMem (&Packet, sizeof (Packet));\r
+\r
+  Packet.EmmcCmdBlk    = &EmmcCmdBlk;\r
+  Packet.EmmcStatusBlk = &EmmcStatusBlk;\r
+  Packet.Timeout        = EMMC_TIMEOUT;\r
+\r
+  EmmcCmdBlk.CommandIndex = EMMC_SEND_EXT_CSD;\r
+  EmmcCmdBlk.CommandType  = EmmcCommandTypeAdtc;\r
+  EmmcCmdBlk.ResponseType = EmmcResponceTypeR1;\r
+  EmmcCmdBlk.CommandArgument = 0x00000000;\r
+\r
+  Packet.InDataBuffer     = ExtCsd;\r
+  Packet.InTransferLength = sizeof (EMMC_EXT_CSD);\r
+\r
+  Status = EmmcPeimExecCmd (Slot, &Packet);\r
+  return Status;\r
+}\r
+\r
+/**\r
+  Send command SWITCH to the EMMC device to switch the mode of operation of the\r
+  selected Device or modifies the EXT_CSD registers.\r
+\r
+  Refer to EMMC Electrical Standard Spec 5.1 Section 6.10.4 for details.\r
+\r
+  @param[in] Slot           The slot number of the Emmc card to send the command to.\r
+  @param[in] Access         The access mode of SWTICH command.\r
+  @param[in] Index          The offset of the field to be access.\r
+  @param[in] Value          The value to be set to the specified field of EXT_CSD register.\r
+  @param[in] CmdSet         The value of CmdSet field of EXT_CSD register.\r
+\r
+  @retval EFI_SUCCESS       The operation is done correctly.\r
+  @retval Others            The operation fails.\r
+\r
+**/\r
+EFI_STATUS\r
+EmmcPeimSwitch (\r
+  IN EMMC_PEIM_HC_SLOT                  *Slot,\r
+  IN UINT8                              Access,\r
+  IN UINT8                              Index,\r
+  IN UINT8                              Value,\r
+  IN UINT8                              CmdSet\r
+  )\r
+{\r
+  EMMC_COMMAND_BLOCK                    EmmcCmdBlk;\r
+  EMMC_STATUS_BLOCK                     EmmcStatusBlk;\r
+  EMMC_COMMAND_PACKET                   Packet;\r
+  EFI_STATUS                            Status;\r
+\r
+  ZeroMem (&EmmcCmdBlk, sizeof (EmmcCmdBlk));\r
+  ZeroMem (&EmmcStatusBlk, sizeof (EmmcStatusBlk));\r
+  ZeroMem (&Packet, sizeof (Packet));\r
+\r
+  Packet.EmmcCmdBlk    = &EmmcCmdBlk;\r
+  Packet.EmmcStatusBlk = &EmmcStatusBlk;\r
+  Packet.Timeout        = EMMC_TIMEOUT;\r
+\r
+  EmmcCmdBlk.CommandIndex = EMMC_SWITCH;\r
+  EmmcCmdBlk.CommandType  = EmmcCommandTypeAc;\r
+  EmmcCmdBlk.ResponseType = EmmcResponceTypeR1b;\r
+  EmmcCmdBlk.CommandArgument = (Access << 24) | (Index << 16) | (Value << 8) | CmdSet;\r
+\r
+  Status = EmmcPeimExecCmd (Slot, &Packet);\r
+\r
+  return Status;\r
+}\r
+\r
+/**\r
+  Send command SEND_STATUS to the addressed EMMC device to get its status register.\r
+\r
+  Refer to EMMC Electrical Standard Spec 5.1 Section 6.10.4 for details.\r
+\r
+  @param[in]  Slot          The slot number of the Emmc card to send the command to.\r
+  @param[in]  Rca           The relative device address of addressed device.\r
+  @param[out] DevStatus     The returned device status.\r
+\r
+  @retval EFI_SUCCESS       The operation is done correctly.\r
+  @retval Others            The operation fails.\r
+\r
+**/\r
+EFI_STATUS\r
+EmmcPeimSendStatus (\r
+  IN     EMMC_PEIM_HC_SLOT              *Slot,\r
+  IN     UINT32                         Rca,\r
+     OUT UINT32                         *DevStatus\r
+  )\r
+{\r
+  EMMC_COMMAND_BLOCK                    EmmcCmdBlk;\r
+  EMMC_STATUS_BLOCK                     EmmcStatusBlk;\r
+  EMMC_COMMAND_PACKET                   Packet;\r
+  EFI_STATUS                            Status;\r
+\r
+  ZeroMem (&EmmcCmdBlk, sizeof (EmmcCmdBlk));\r
+  ZeroMem (&EmmcStatusBlk, sizeof (EmmcStatusBlk));\r
+  ZeroMem (&Packet, sizeof (Packet));\r
+\r
+  Packet.EmmcCmdBlk    = &EmmcCmdBlk;\r
+  Packet.EmmcStatusBlk = &EmmcStatusBlk;\r
+  Packet.Timeout        = EMMC_TIMEOUT;\r
+\r
+  EmmcCmdBlk.CommandIndex = EMMC_SEND_STATUS;\r
+  EmmcCmdBlk.CommandType  = EmmcCommandTypeAc;\r
+  EmmcCmdBlk.ResponseType = EmmcResponceTypeR1;\r
+  EmmcCmdBlk.CommandArgument = Rca << 16;\r
+\r
+  Status = EmmcPeimExecCmd (Slot, &Packet);\r
+  if (!EFI_ERROR (Status)) {\r
+    *DevStatus = EmmcStatusBlk.Resp0;\r
+  }\r
+\r
+  return Status;\r
+}\r
+\r
+/**\r
+  Send command SET_BLOCK_COUNT to the addressed EMMC device to set the number of\r
+  blocks for the following block read/write cmd.\r
+\r
+  Refer to EMMC Electrical Standard Spec 5.1 Section 6.10.4 for details.\r
+\r
+  @param[in] Slot           The slot number of the Emmc card to send the command to.\r
+  @param[in] BlockCount     The number of the logical block to access.\r
+\r
+  @retval EFI_SUCCESS       The operation is done correctly.\r
+  @retval Others            The operation fails.\r
+\r
+**/\r
+EFI_STATUS\r
+EmmcPeimSetBlkCount (\r
+  IN EMMC_PEIM_HC_SLOT              *Slot,\r
+  IN UINT16                         BlockCount\r
+  )\r
+{\r
+  EMMC_COMMAND_BLOCK                    EmmcCmdBlk;\r
+  EMMC_STATUS_BLOCK                     EmmcStatusBlk;\r
+  EMMC_COMMAND_PACKET                   Packet;\r
+  EFI_STATUS                            Status;\r
+\r
+  ZeroMem (&EmmcCmdBlk, sizeof (EmmcCmdBlk));\r
+  ZeroMem (&EmmcStatusBlk, sizeof (EmmcStatusBlk));\r
+  ZeroMem (&Packet, sizeof (Packet));\r
+\r
+  Packet.EmmcCmdBlk    = &EmmcCmdBlk;\r
+  Packet.EmmcStatusBlk = &EmmcStatusBlk;\r
+  Packet.Timeout       = EMMC_TIMEOUT;\r
+\r
+  EmmcCmdBlk.CommandIndex = EMMC_SET_BLOCK_COUNT;\r
+  EmmcCmdBlk.CommandType  = EmmcCommandTypeAc;\r
+  EmmcCmdBlk.ResponseType = EmmcResponceTypeR1;\r
+  EmmcCmdBlk.CommandArgument = BlockCount;\r
+\r
+  Status = EmmcPeimExecCmd (Slot, &Packet);\r
+\r
+  return Status;\r
+}\r
+\r
+/**\r
+  Send command READ_MULTIPLE_BLOCK/WRITE_MULTIPLE_BLOCK to the addressed EMMC device\r
+  to read/write the specified number of blocks.\r
+\r
+  Refer to EMMC Electrical Standard Spec 5.1 Section 6.10.4 for details.\r
+\r
+  @param[in] Slot           The slot number of the Emmc card to send the command to.\r
+  @param[in] Lba            The logical block address of starting access.\r
+  @param[in] BlockSize      The block size of specified EMMC device partition.\r
+  @param[in] Buffer         The pointer to the transfer buffer.\r
+  @param[in] BufferSize     The size of transfer buffer.\r
+  @param[in] IsRead         Boolean to show the operation direction.\r
+\r
+  @retval EFI_SUCCESS       The operation is done correctly.\r
+  @retval Others            The operation fails.\r
+\r
+**/\r
+EFI_STATUS\r
+EmmcPeimRwMultiBlocks (\r
+  IN EMMC_PEIM_HC_SLOT              *Slot,\r
+  IN EFI_LBA                        Lba,\r
+  IN UINT32                         BlockSize,\r
+  IN VOID                           *Buffer,\r
+  IN UINTN                          BufferSize,\r
+  IN BOOLEAN                        IsRead\r
+  )\r
+{\r
+  EMMC_COMMAND_BLOCK                    EmmcCmdBlk;\r
+  EMMC_STATUS_BLOCK                     EmmcStatusBlk;\r
+  EMMC_COMMAND_PACKET                   Packet;\r
+  EFI_STATUS                            Status;\r
+\r
+  ZeroMem (&EmmcCmdBlk, sizeof (EmmcCmdBlk));\r
+  ZeroMem (&EmmcStatusBlk, sizeof (EmmcStatusBlk));\r
+  ZeroMem (&Packet, sizeof (Packet));\r
+\r
+  Packet.EmmcCmdBlk    = &EmmcCmdBlk;\r
+  Packet.EmmcStatusBlk = &EmmcStatusBlk;\r
+  //\r
+  // Calculate timeout value through the below formula.\r
+  // Timeout = (transfer size) / (2MB/s).\r
+  // Taking 2MB/s as divisor is because it's nearest to the eMMC lowest\r
+  // transfer speed (2.4MB/s).\r
+  // Refer to eMMC 5.0 spec section 6.9.1 for details.\r
+  //\r
+  Packet.Timeout       = (BufferSize / (2 * 1024 * 1024) + 1) * 1000 * 1000;;\r
+\r
+  if (IsRead) {\r
+    Packet.InDataBuffer     = Buffer;\r
+    Packet.InTransferLength = (UINT32)BufferSize;\r
+\r
+    EmmcCmdBlk.CommandIndex = EMMC_READ_MULTIPLE_BLOCK;\r
+    EmmcCmdBlk.CommandType  = EmmcCommandTypeAdtc;\r
+    EmmcCmdBlk.ResponseType = EmmcResponceTypeR1;\r
+  } else {\r
+    Packet.OutDataBuffer     = Buffer;\r
+    Packet.OutTransferLength = (UINT32)BufferSize;\r
+\r
+    EmmcCmdBlk.CommandIndex = EMMC_WRITE_MULTIPLE_BLOCK;\r
+    EmmcCmdBlk.CommandType  = EmmcCommandTypeAdtc;\r
+    EmmcCmdBlk.ResponseType = EmmcResponceTypeR1;\r
+  }\r
+\r
+  if (Slot->SectorAddressing) {\r
+    EmmcCmdBlk.CommandArgument = (UINT32)Lba;\r
+  } else {\r
+    EmmcCmdBlk.CommandArgument = (UINT32)MultU64x32 (Lba, BlockSize);\r
+  }\r
+\r
+  Status = EmmcPeimExecCmd (Slot, &Packet);\r
+\r
+  return Status;\r
+}\r
+\r
+/**\r
+  Send command SEND_TUNING_BLOCK to the EMMC device for HS200 optimal sampling point\r
+  detection.\r
+\r
+  It may be sent up to 40 times until the host finishes the tuning procedure.\r
+\r
+  Refer to EMMC Electrical Standard Spec 5.1 Section 6.6.8 for details.\r
+\r
+  @param[in] Slot           The slot number of the Emmc card to send the command to.\r
+  @param[in] BusWidth       The bus width to work.\r
+\r
+  @retval EFI_SUCCESS       The operation is done correctly.\r
+  @retval Others            The operation fails.\r
+\r
+**/\r
+EFI_STATUS\r
+EmmcPeimSendTuningBlk (\r
+  IN EMMC_PEIM_HC_SLOT      *Slot,\r
+  IN UINT8                  BusWidth\r
+  )\r
+{\r
+  EMMC_COMMAND_BLOCK                    EmmcCmdBlk;\r
+  EMMC_STATUS_BLOCK                     EmmcStatusBlk;\r
+  EMMC_COMMAND_PACKET                   Packet;\r
+  EFI_STATUS                            Status;\r
+  UINT8                                 TuningBlock[128];\r
+\r
+  ZeroMem (&EmmcCmdBlk, sizeof (EmmcCmdBlk));\r
+  ZeroMem (&EmmcStatusBlk, sizeof (EmmcStatusBlk));\r
+  ZeroMem (&Packet, sizeof (Packet));\r
+\r
+  Packet.EmmcCmdBlk    = &EmmcCmdBlk;\r
+  Packet.EmmcStatusBlk = &EmmcStatusBlk;\r
+  Packet.Timeout        = EMMC_TIMEOUT;\r
+\r
+  EmmcCmdBlk.CommandIndex = EMMC_SEND_TUNING_BLOCK;\r
+  EmmcCmdBlk.CommandType  = EmmcCommandTypeAdtc;\r
+  EmmcCmdBlk.ResponseType = EmmcResponceTypeR1;\r
+  EmmcCmdBlk.CommandArgument = 0;\r
+\r
+  Packet.InDataBuffer = TuningBlock;\r
+  if (BusWidth == 8) {\r
+    Packet.InTransferLength = sizeof (TuningBlock);\r
+  } else {\r
+    Packet.InTransferLength = 64;\r
+  }\r
+\r
+  Status = EmmcPeimExecCmd (Slot, &Packet);\r
+\r
+  return Status;\r
+}\r
+\r
+/**\r
+  Tunning the clock to get HS200 optimal sampling point.\r
+\r
+  Command SEND_TUNING_BLOCK may be sent up to 40 times until the host finishes the\r
+  tuning procedure.\r
+\r
+  Refer to EMMC Electrical Standard Spec 5.1 Section 6.6.8 and SD Host Controller\r
+  Simplified Spec 3.0 section Figure 2-29 for details.\r
+\r
+  @param[in] Slot           The slot number of the Emmc card to send the command to.\r
+  @param[in] BusWidth       The bus width to work.\r
+\r
+  @retval EFI_SUCCESS       The operation is done correctly.\r
+  @retval Others            The operation fails.\r
+\r
+**/\r
+EFI_STATUS\r
+EmmcPeimTuningClkForHs200 (\r
+  IN EMMC_PEIM_HC_SLOT      *Slot,\r
+  IN UINT8                  BusWidth\r
+  )\r
+{\r
+  EFI_STATUS          Status;\r
+  UINT8               HostCtrl2;\r
+  UINT8               Retry;\r
+\r
+  //\r
+  // Notify the host that the sampling clock tuning procedure starts.\r
+  //\r
+  HostCtrl2 = BIT6;\r
+  Status = EmmcPeimHcOrMmio (Slot->EmmcHcBase + EMMC_HC_HOST_CTRL2, sizeof (HostCtrl2), &HostCtrl2);\r
+  if (EFI_ERROR (Status)) {\r
+    return Status;\r
+  }\r
+  //\r
+  // Ask the device to send a sequence of tuning blocks till the tuning procedure is done.\r
+  //\r
+  Retry = 0;\r
+  do {\r
+    Status = EmmcPeimSendTuningBlk (Slot, BusWidth);\r
+    if (EFI_ERROR (Status)) {\r
+      return Status;\r
+    }\r
+\r
+    Status = EmmcPeimHcRwMmio (Slot->EmmcHcBase + EMMC_HC_HOST_CTRL2, TRUE, sizeof (HostCtrl2), &HostCtrl2);\r
+    if (EFI_ERROR (Status)) {\r
+      return Status;\r
+    }\r
+\r
+    if ((HostCtrl2 & (BIT6 | BIT7)) == BIT7) {\r
+      break;\r
+    }\r
+  } while (++Retry < 40);\r
+\r
+  if (Retry == 40) {\r
+    Status = EFI_TIMEOUT;\r
+  }\r
+  return Status;\r
+}\r
+\r
+/**\r
+  Switch the bus width to specified width.\r
+\r
+  Refer to EMMC Electrical Standard Spec 5.1 Section 6.6.9 and SD Host Controller\r
+  Simplified Spec 3.0 section Figure 3-7 for details.\r
+\r
+  @param[in] Slot           The slot number of the Emmc card to send the command to.\r
+  @param[in] Rca            The relative device address to be assigned.\r
+  @param[in] IsDdr          If TRUE, use dual data rate data simpling method. Otherwise\r
+                            use single data rate data simpling method.\r
+  @param[in] BusWidth       The bus width to be set, it could be 4 or 8.\r
+\r
+  @retval EFI_SUCCESS       The operation is done correctly.\r
+  @retval Others            The operation fails.\r
+\r
+**/\r
+EFI_STATUS\r
+EmmcPeimSwitchBusWidth (\r
+  IN EMMC_PEIM_HC_SLOT                  *Slot,\r
+  IN UINT32                             Rca,\r
+  IN BOOLEAN                            IsDdr,\r
+  IN UINT8                              BusWidth\r
+  )\r
+{\r
+  EFI_STATUS          Status;\r
+  UINT8               Access;\r
+  UINT8               Index;\r
+  UINT8               Value;\r
+  UINT8               CmdSet;\r
+  UINT32              DevStatus;\r
+\r
+  //\r
+  // Write Byte, the Value field is written into the byte pointed by Index.\r
+  //\r
+  Access = 0x03;\r
+  Index  = OFFSET_OF (EMMC_EXT_CSD, BusWidth);\r
+  if (BusWidth == 4) {\r
+    Value = 1;\r
+  } else if (BusWidth == 8) {\r
+    Value = 2;\r
+  } else {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  if (IsDdr) {\r
+    Value += 4;\r
+  }\r
+\r
+  CmdSet = 0;\r
+  Status = EmmcPeimSwitch (Slot, Access, Index, Value, CmdSet);\r
+  if (EFI_ERROR (Status)) {\r
+    return Status;\r
+  }\r
+\r
+  Status = EmmcPeimSendStatus (Slot, Rca, &DevStatus);\r
+  if (EFI_ERROR (Status)) {\r
+    return Status;\r
+  }\r
+  //\r
+  // Check the switch operation is really successful or not.\r
+  //\r
+  if ((DevStatus & BIT7) != 0) {\r
+    return EFI_DEVICE_ERROR;\r
+  }\r
+\r
+  Status = EmmcPeimHcSetBusWidth (Slot->EmmcHcBase, BusWidth);\r
+\r
+  return Status;\r
+}\r
+\r
+/**\r
+  Switch the clock frequency to the specified value.\r
+\r
+  Refer to EMMC Electrical Standard Spec 5.1 Section 6.6 and SD Host Controller\r
+  Simplified Spec 3.0 section Figure 3-3 for details.\r
+\r
+  @param[in] Slot           The slot number of the Emmc card to send the command to.\r
+  @param[in] Rca            The relative device address to be assigned.\r
+  @param[in] HsTiming       The value to be written to HS_TIMING field of EXT_CSD register.\r
+  @param[in] ClockFreq      The max clock frequency to be set, the unit is MHz.\r
+\r
+  @retval EFI_SUCCESS       The operation is done correctly.\r
+  @retval Others            The operation fails.\r
+\r
+**/\r
+EFI_STATUS\r
+EmmcPeimSwitchClockFreq (\r
+  IN EMMC_PEIM_HC_SLOT                  *Slot,\r
+  IN UINT32                             Rca,\r
+  IN UINT8                              HsTiming,\r
+  IN UINT32                             ClockFreq\r
+  )\r
+{\r
+  EFI_STATUS          Status;\r
+  UINT8               Access;\r
+  UINT8               Index;\r
+  UINT8               Value;\r
+  UINT8               CmdSet;\r
+  UINT32              DevStatus;\r
+\r
+  //\r
+  // Write Byte, the Value field is written into the byte pointed by Index.\r
+  //\r
+  Access = 0x03;\r
+  Index  = OFFSET_OF (EMMC_EXT_CSD, HsTiming);\r
+  Value  = HsTiming;\r
+  CmdSet = 0;\r
+\r
+  Status = EmmcPeimSwitch (Slot, Access, Index, Value, CmdSet);\r
+  if (EFI_ERROR (Status)) {\r
+    return Status;\r
+  }\r
+\r
+  Status = EmmcPeimSendStatus (Slot, Rca, &DevStatus);\r
+  if (EFI_ERROR (Status)) {\r
+    return Status;\r
+  }\r
+  //\r
+  // Check the switch operation is really successful or not.\r
+  //\r
+  if ((DevStatus & BIT7) != 0) {\r
+    return EFI_DEVICE_ERROR;\r
+  }\r
+  //\r
+  // Convert the clock freq unit from MHz to KHz.\r
+  //\r
+  Status = EmmcPeimHcClockSupply (Slot->EmmcHcBase, ClockFreq * 1000);\r
+\r
+  return Status;\r
+}\r
+\r
+/**\r
+  Switch to the High Speed timing according to request.\r
+\r
+  Refer to EMMC Electrical Standard Spec 5.1 Section 6.6.8 and SD Host Controller\r
+  Simplified Spec 3.0 section Figure 2-29 for details.\r
+\r
+  @param[in] Slot           The slot number of the Emmc card to send the command to.\r
+  @param[in] Rca            The relative device address to be assigned.\r
+  @param[in] ClockFreq      The max clock frequency to be set.\r
+  @param[in] IsDdr          If TRUE, use dual data rate data simpling method. Otherwise\r
+                            use single data rate data simpling method.\r
+  @param[in] BusWidth       The bus width to be set, it could be 4 or 8.\r
+\r
+  @retval EFI_SUCCESS       The operation is done correctly.\r
+  @retval Others            The operation fails.\r
+\r
+**/\r
+EFI_STATUS\r
+EmmcPeimSwitchToHighSpeed (\r
+  IN EMMC_PEIM_HC_SLOT                  *Slot,\r
+  IN UINT32                             Rca,\r
+  IN UINT32                             ClockFreq,\r
+  IN BOOLEAN                            IsDdr,\r
+  IN UINT8                              BusWidth\r
+  )\r
+{\r
+  EFI_STATUS          Status;\r
+  UINT8               HsTiming;\r
+  UINT8               HostCtrl1;\r
+  UINT8               HostCtrl2;\r
+\r
+  Status = EmmcPeimSwitchBusWidth (Slot, Rca, IsDdr, BusWidth);\r
+  if (EFI_ERROR (Status)) {\r
+    return Status;\r
+  }\r
+  //\r
+  // Set to Hight Speed timing\r
+  //\r
+  HostCtrl1 = BIT2;\r
+  Status = EmmcPeimHcOrMmio (Slot->EmmcHcBase + EMMC_HC_HOST_CTRL1, sizeof (HostCtrl1), &HostCtrl1);\r
+  if (EFI_ERROR (Status)) {\r
+    return Status;\r
+  }\r
+\r
+  HostCtrl2 = (UINT8)~0x7;\r
+  Status = EmmcPeimHcAndMmio (Slot->EmmcHcBase + EMMC_HC_HOST_CTRL2, sizeof (HostCtrl2), &HostCtrl2);\r
+  if (EFI_ERROR (Status)) {\r
+    return Status;\r
+  }\r
+  if (IsDdr) {\r
+    HostCtrl2 = BIT2;\r
+  } else if (ClockFreq == 52) {\r
+    HostCtrl2 = BIT0;\r
+  } else {\r
+    HostCtrl2 = 0;\r
+  }\r
+  Status = EmmcPeimHcOrMmio (Slot->EmmcHcBase + EMMC_HC_HOST_CTRL2, sizeof (HostCtrl2), &HostCtrl2);\r
+  if (EFI_ERROR (Status)) {\r
+    return Status;\r
+  }\r
+\r
+  HsTiming = 1;\r
+  Status = EmmcPeimSwitchClockFreq (Slot, Rca, HsTiming, ClockFreq);\r
+  if (EFI_ERROR (Status)) {\r
+    return Status;\r
+  }\r
+\r
+  return Status;\r
+}\r
+\r
+/**\r
+  Switch to the HS200 timing according to request.\r
+\r
+  Refer to EMMC Electrical Standard Spec 5.1 Section 6.6.8 and SD Host Controller\r
+  Simplified Spec 3.0 section Figure 2-29 for details.\r
+\r
+  @param[in] Slot           The slot number of the Emmc card to send the command to.\r
+  @param[in] Rca            The relative device address to be assigned.\r
+  @param[in] ClockFreq      The max clock frequency to be set.\r
+  @param[in] BusWidth       The bus width to be set, it could be 4 or 8.\r
+\r
+  @retval EFI_SUCCESS       The operation is done correctly.\r
+  @retval Others            The operation fails.\r
+\r
+**/\r
+EFI_STATUS\r
+EmmcPeimSwitchToHS200 (\r
+  IN EMMC_PEIM_HC_SLOT                  *Slot,\r
+  IN UINT32                             Rca,\r
+  IN UINT32                             ClockFreq,\r
+  IN UINT8                              BusWidth\r
+  )\r
+{\r
+  EFI_STATUS          Status;\r
+  UINT8               HsTiming;\r
+  UINT8               HostCtrl2;\r
+  UINT16              ClockCtrl;\r
+\r
+  if ((BusWidth != 4) && (BusWidth != 8)) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  Status = EmmcPeimSwitchBusWidth (Slot, Rca, FALSE, BusWidth);\r
+  if (EFI_ERROR (Status)) {\r
+    return Status;\r
+  }\r
+  //\r
+  // Set to HS200/SDR104 timing\r
+  //\r
+  //\r
+  // Stop bus clock at first\r
+  //\r
+  Status = EmmcPeimHcStopClock (Slot->EmmcHcBase);\r
+  if (EFI_ERROR (Status)) {\r
+    return Status;\r
+  }\r
+\r
+  HostCtrl2 = (UINT8)~0x7;\r
+  Status = EmmcPeimHcAndMmio (Slot->EmmcHcBase + EMMC_HC_HOST_CTRL2, sizeof (HostCtrl2), &HostCtrl2);\r
+  if (EFI_ERROR (Status)) {\r
+    return Status;\r
+  }\r
+  HostCtrl2 = BIT0 | BIT1;\r
+  Status = EmmcPeimHcOrMmio (Slot->EmmcHcBase + EMMC_HC_HOST_CTRL2, sizeof (HostCtrl2), &HostCtrl2);\r
+  if (EFI_ERROR (Status)) {\r
+    return Status;\r
+  }\r
+\r
+  //\r
+  // Wait Internal Clock Stable in the Clock Control register to be 1 before set SD Clock Enable bit\r
+  //\r
+  Status = EmmcPeimHcWaitMmioSet (\r
+             Slot->EmmcHcBase + EMMC_HC_CLOCK_CTRL,\r
+             sizeof (ClockCtrl),\r
+             BIT1,\r
+             BIT1,\r
+             EMMC_TIMEOUT\r
+             );\r
+  if (EFI_ERROR (Status)) {\r
+    return Status;\r
+  }\r
+  //\r
+  // Set SD Clock Enable in the Clock Control register to 1\r
+  //\r
+  ClockCtrl = BIT2;\r
+  Status = EmmcPeimHcOrMmio (Slot->EmmcHcBase + EMMC_HC_CLOCK_CTRL, sizeof (ClockCtrl), &ClockCtrl);\r
+\r
+  HsTiming = 2;\r
+  Status = EmmcPeimSwitchClockFreq (Slot, Rca, HsTiming, ClockFreq);\r
+  if (EFI_ERROR (Status)) {\r
+    return Status;\r
+  }\r
+\r
+  Status = EmmcPeimTuningClkForHs200 (Slot, BusWidth);\r
+\r
+  return Status;\r
+}\r
+\r
+/**\r
+  Switch to the HS400 timing according to request.\r
+\r
+  Refer to EMMC Electrical Standard Spec 5.1 Section 6.6.8 and SD Host Controller\r
+  Simplified Spec 3.0 section Figure 2-29 for details.\r
+\r
+  @param[in] Slot           The slot number of the Emmc card to send the command to.\r
+  @param[in] Rca            The relative device address to be assigned.\r
+  @param[in] ClockFreq      The max clock frequency to be set.\r
+\r
+  @retval EFI_SUCCESS       The operation is done correctly.\r
+  @retval Others            The operation fails.\r
+\r
+**/\r
+EFI_STATUS\r
+EmmcPeimSwitchToHS400 (\r
+  IN EMMC_PEIM_HC_SLOT                  *Slot,\r
+  IN UINT32                             Rca,\r
+  IN UINT32                             ClockFreq\r
+  )\r
+{\r
+  EFI_STATUS          Status;\r
+  UINT8               HsTiming;\r
+  UINT8               HostCtrl2;\r
+\r
+  Status = EmmcPeimSwitchToHS200 (Slot, Rca, ClockFreq, 8);\r
+  if (EFI_ERROR (Status)) {\r
+    return Status;\r
+  }\r
+  //\r
+  // Set to Hight Speed timing and set the clock frequency to a value less than 52MHz.\r
+  //\r
+  HsTiming = 1;\r
+  Status = EmmcPeimSwitchClockFreq (Slot, Rca, HsTiming, 52);\r
+  if (EFI_ERROR (Status)) {\r
+    return Status;\r
+  }\r
+  //\r
+  // HS400 mode must use 8 data lines.\r
+  //\r
+  Status = EmmcPeimSwitchBusWidth (Slot, Rca, TRUE, 8);\r
+  if (EFI_ERROR (Status)) {\r
+    return Status;\r
+  }\r
+  //\r
+  // Set to HS400 timing\r
+  //\r
+  HostCtrl2 = (UINT8)~0x7;\r
+  Status = EmmcPeimHcAndMmio (Slot->EmmcHcBase + EMMC_HC_HOST_CTRL2, sizeof (HostCtrl2), &HostCtrl2);\r
+  if (EFI_ERROR (Status)) {\r
+    return Status;\r
+  }\r
+  HostCtrl2 = BIT0 | BIT2;\r
+  Status = EmmcPeimHcOrMmio (Slot->EmmcHcBase + EMMC_HC_HOST_CTRL2, sizeof (HostCtrl2), &HostCtrl2);\r
+  if (EFI_ERROR (Status)) {\r
+    return Status;\r
+  }\r
+\r
+  HsTiming = 3;\r
+  Status = EmmcPeimSwitchClockFreq (Slot, Rca, HsTiming, ClockFreq);\r
+\r
+  return Status;\r
+}\r
+\r
+/**\r
+  Switch the high speed timing according to request.\r
+\r
+  Refer to EMMC Electrical Standard Spec 5.1 Section 6.6.8 and SD Host Controller\r
+  Simplified Spec 3.0 section Figure 2-29 for details.\r
+\r
+  @param[in] Slot           The slot number of the Emmc card to send the command to.\r
+  @param[in] Rca            The relative device address to be assigned.\r
+\r
+  @retval EFI_SUCCESS       The operation is done correctly.\r
+  @retval Others            The operation fails.\r
+\r
+**/\r
+EFI_STATUS\r
+EmmcPeimSetBusMode (\r
+  IN EMMC_PEIM_HC_SLOT                  *Slot,\r
+  IN UINT32                             Rca\r
+  )\r
+{\r
+  EFI_STATUS          Status;\r
+  EMMC_HC_SLOT_CAP    Capability;\r
+  UINT8               HsTiming;\r
+  BOOLEAN             IsDdr;\r
+  UINT32              ClockFreq;\r
+  UINT8               BusWidth;\r
+\r
+  Status = EmmcPeimGetCsd (Slot, Rca, &Slot->Csd);\r
+  if (EFI_ERROR (Status)) {\r
+    DEBUG ((EFI_D_ERROR, "EmmcPeimSetBusMode: EmmcPeimGetCsd fails with %r\n", Status));\r
+    return Status;\r
+  }\r
+\r
+  if ((Slot->Csd.CSizeLow | Slot->Csd.CSizeHigh << 2) == 0xFFF) {\r
+    Slot->SectorAddressing = TRUE;\r
+  } else {\r
+    Slot->SectorAddressing = FALSE;\r
+  }\r
+\r
+  Status = EmmcPeimSelect (Slot, Rca);\r
+  if (EFI_ERROR (Status)) {\r
+    DEBUG ((EFI_D_ERROR, "EmmcPeimSetBusMode: EmmcPeimSelect fails with %r\n", Status));\r
+    return Status;\r
+  }\r
+\r
+  Status = EmmcPeimHcGetCapability (Slot->EmmcHcBase, &Capability);\r
+  if (EFI_ERROR (Status)) {\r
+    DEBUG ((EFI_D_ERROR, "EmmcPeimSetBusMode: EmmcPeimHcGetCapability fails with %r\n", Status));\r
+    return Status;\r
+  }\r
+\r
+  ASSERT (Capability.BaseClkFreq != 0);\r
+  //\r
+  // Check if the Host Controller support 8bits bus width.\r
+  //\r
+  if (Capability.BusWidth8 != 0) {\r
+    BusWidth = 8;\r
+  } else {\r
+    BusWidth = 4;\r
+  }\r
+  //\r
+  // Get Deivce_Type from EXT_CSD register.\r
+  //\r
+  Status = EmmcPeimGetExtCsd (Slot, &Slot->ExtCsd);\r
+  if (EFI_ERROR (Status)) {\r
+    DEBUG ((EFI_D_ERROR, "EmmcPeimSetBusMode: EmmcPeimGetExtCsd fails with %r\n", Status));\r
+    return Status;\r
+  }\r
+  //\r
+  // Calculate supported bus speed/bus width/clock frequency.\r
+  //\r
+  HsTiming  = 0;\r
+  IsDdr     = FALSE;\r
+  ClockFreq = 0;\r
+  if (((Slot->ExtCsd.DeviceType & (BIT4 | BIT5))  != 0) && (Capability.Sdr104 != 0)) {\r
+    HsTiming  = 2;\r
+    IsDdr     = FALSE;\r
+    ClockFreq = 200;\r
+  } else if (((Slot->ExtCsd.DeviceType & (BIT2 | BIT3))  != 0) && (Capability.Ddr50 != 0)) {\r
+    HsTiming  = 1;\r
+    IsDdr     = TRUE;\r
+    ClockFreq = 52;\r
+  } else if (((Slot->ExtCsd.DeviceType & BIT1)  != 0) && (Capability.HighSpeed != 0)) {\r
+    HsTiming  = 1;\r
+    IsDdr     = FALSE;\r
+    ClockFreq = 52;\r
+  } else if (((Slot->ExtCsd.DeviceType & BIT0)  != 0) && (Capability.HighSpeed != 0)) {\r
+    HsTiming  = 1;\r
+    IsDdr     = FALSE;\r
+    ClockFreq = 26;\r
+  }\r
+  //\r
+  // Check if both of the device and the host controller support HS400 DDR mode.\r
+  //\r
+  if (((Slot->ExtCsd.DeviceType & (BIT6 | BIT7))  != 0) && (Capability.Hs400 != 0)) {\r
+    //\r
+    // The host controller supports 8bits bus.\r
+    //\r
+    ASSERT (BusWidth == 8);\r
+    HsTiming  = 3;\r
+    IsDdr     = TRUE;\r
+    ClockFreq = 200;\r
+  }\r
+\r
+  if ((ClockFreq == 0) || (HsTiming == 0)) {\r
+    //\r
+    // Continue using default setting.\r
+    //\r
+    return EFI_SUCCESS;\r
+  }\r
+\r
+  DEBUG ((EFI_D_INFO, "HsTiming %d ClockFreq %d BusWidth %d Ddr %a\n", HsTiming, ClockFreq, BusWidth, IsDdr ? "TRUE":"FALSE"));\r
+\r
+  if (HsTiming == 3) {\r
+    //\r
+    // Execute HS400 timing switch procedure\r
+    //\r
+    Status = EmmcPeimSwitchToHS400 (Slot, Rca, ClockFreq);\r
+  } else if (HsTiming == 2) {\r
+    //\r
+    // Execute HS200 timing switch procedure\r
+    //\r
+    Status = EmmcPeimSwitchToHS200 (Slot, Rca, ClockFreq, BusWidth);\r
+  } else {\r
+    //\r
+    // Execute High Speed timing switch procedure\r
+    //\r
+    Status = EmmcPeimSwitchToHighSpeed (Slot, Rca, ClockFreq, BusWidth, IsDdr);\r
+  }\r
+\r
+  return Status;\r
+}\r
+\r
+/**\r
+  Execute EMMC device identification procedure.\r
+\r
+  Refer to EMMC Electrical Standard Spec 5.1 Section 6.4 for details.\r
+\r
+  @param[in] Slot           The slot number of the Emmc card to send the command to.\r
+\r
+  @retval EFI_SUCCESS       There is a EMMC card.\r
+  @retval Others            There is not a EMMC card.\r
+\r
+**/\r
+EFI_STATUS\r
+EmmcPeimIdentification (\r
+  IN EMMC_PEIM_HC_SLOT           *Slot\r
+  )\r
+{\r
+  EFI_STATUS                     Status;\r
+  UINT32                         Ocr;\r
+  UINT32                         Rca;\r
+\r
+  Status = EmmcPeimReset (Slot);\r
+  if (EFI_ERROR (Status)) {\r
+    DEBUG ((EFI_D_ERROR, "EmmcPeimIdentification: EmmcPeimReset fails with %r\n", Status));\r
+    return Status;\r
+  }\r
+\r
+  Ocr = 0;\r
+  do {\r
+    Status = EmmcPeimGetOcr (Slot, &Ocr);\r
+    if (EFI_ERROR (Status)) {\r
+      DEBUG ((EFI_D_ERROR, "EmmcPeimIdentification: EmmcPeimGetOcr fails with %r\n", Status));\r
+      return Status;\r
+    }\r
+  } while ((Ocr & BIT31) == 0);\r
+\r
+  Status = EmmcPeimGetAllCid (Slot);\r
+  if (EFI_ERROR (Status)) {\r
+    DEBUG ((EFI_D_ERROR, "EmmcPeimIdentification: EmmcPeimGetAllCid fails with %r\n", Status));\r
+    return Status;\r
+  }\r
+  //\r
+  // Don't support multiple devices on the slot, that is\r
+  // shared bus slot feature.\r
+  //\r
+  Rca    = 1;\r
+  Status = EmmcPeimSetRca (Slot, Rca);\r
+  if (EFI_ERROR (Status)) {\r
+    DEBUG ((EFI_D_ERROR, "EmmcPeimIdentification: EmmcPeimSetRca fails with %r\n", Status));\r
+    return Status;\r
+  }\r
+  //\r
+  // Enter Data Tranfer Mode.\r
+  //\r
+  DEBUG ((EFI_D_INFO, "Found a EMMC device at slot [%d], RCA [%d]\n", Slot, Rca));\r
+\r
+  Status = EmmcPeimSetBusMode (Slot, Rca);\r
+\r
+  return Status;\r
+}\r
+\r
diff --git a/MdeModulePkg/Bus/Sd/EmmcBlockIoPei/EmmcHci.h b/MdeModulePkg/Bus/Sd/EmmcBlockIoPei/EmmcHci.h
new file mode 100644 (file)
index 0000000..a74f1c6
--- /dev/null
@@ -0,0 +1,345 @@
+/** @file\r
+\r
+  Copyright (c) 2015, Intel Corporation. All rights reserved.<BR>\r
+  This program and the accompanying materials\r
+  are licensed and made available under the terms and conditions of the BSD License\r
+  which accompanies this distribution.  The full text of the license may be found at\r
+  http://opensource.org/licenses/bsd-license.php.\r
+\r
+  THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+  WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+\r
+**/\r
+\r
+#ifndef _EMMC_HCI_H_\r
+#define _EMMC_HCI_H_\r
+\r
+//\r
+// EMMC Host Controller MMIO Register Offset\r
+//\r
+#define EMMC_HC_SDMA_ADDR           0x00\r
+#define EMMC_HC_ARG2                0x00\r
+#define EMMC_HC_BLK_SIZE            0x04\r
+#define EMMC_HC_BLK_COUNT           0x06\r
+#define EMMC_HC_ARG1                0x08\r
+#define EMMC_HC_TRANS_MOD           0x0C\r
+#define EMMC_HC_COMMAND             0x0E\r
+#define EMMC_HC_RESPONSE            0x10\r
+#define EMMC_HC_BUF_DAT_PORT        0x20\r
+#define EMMC_HC_PRESENT_STATE       0x24\r
+#define EMMC_HC_HOST_CTRL1          0x28\r
+#define EMMC_HC_POWER_CTRL          0x29\r
+#define EMMC_HC_BLK_GAP_CTRL        0x2A\r
+#define EMMC_HC_WAKEUP_CTRL         0x2B\r
+#define EMMC_HC_CLOCK_CTRL          0x2C\r
+#define EMMC_HC_TIMEOUT_CTRL        0x2E\r
+#define EMMC_HC_SW_RST              0x2F\r
+#define EMMC_HC_NOR_INT_STS         0x30\r
+#define EMMC_HC_ERR_INT_STS         0x32\r
+#define EMMC_HC_NOR_INT_STS_EN      0x34\r
+#define EMMC_HC_ERR_INT_STS_EN      0x36\r
+#define EMMC_HC_NOR_INT_SIG_EN      0x38\r
+#define EMMC_HC_ERR_INT_SIG_EN      0x3A\r
+#define EMMC_HC_AUTO_CMD_ERR_STS    0x3C\r
+#define EMMC_HC_HOST_CTRL2          0x3E\r
+#define EMMC_HC_CAP                 0x40\r
+#define EMMC_HC_MAX_CURRENT_CAP     0x48\r
+#define EMMC_HC_FORCE_EVT_AUTO_CMD  0x50\r
+#define EMMC_HC_FORCE_EVT_ERR_INT   0x52\r
+#define EMMC_HC_ADMA_ERR_STS        0x54\r
+#define EMMC_HC_ADMA_SYS_ADDR       0x58\r
+#define EMMC_HC_PRESET_VAL          0x60\r
+#define EMMC_HC_SHARED_BUS_CTRL     0xE0\r
+#define EMMC_HC_SLOT_INT_STS        0xFC\r
+#define EMMC_HC_CTRL_VER            0xFE\r
+\r
+//\r
+// The transfer modes supported by SD Host Controller\r
+// Simplified Spec 3.0 Table 1-2\r
+//\r
+typedef enum {\r
+  EmmcNoData,\r
+  EmmcPioMode,\r
+  EmmcSdmaMode,\r
+  EmmcAdmaMode\r
+} EMMC_HC_TRANSFER_MODE;\r
+\r
+//\r
+// The maximum data length of each descriptor line\r
+//\r
+#define ADMA_MAX_DATA_PER_LINE      0x10000\r
+#define EMMC_SDMA_BOUNDARY          512 * 1024\r
+#define EMMC_SDMA_ROUND_UP(x, n)    (((x) + n) & ~(n - 1))\r
+\r
+typedef enum {\r
+  EmmcCommandTypeBc,  // Broadcast commands, no response\r
+  EmmcCommandTypeBcr, // Broadcast commands with response\r
+  EmmcCommandTypeAc,  // Addressed(point-to-point) commands\r
+  EmmcCommandTypeAdtc // Addressed(point-to-point) data transfer commands\r
+} EMMC_COMMAND_TYPE;\r
+\r
+typedef enum {\r
+  EmmcResponceTypeR1,\r
+  EmmcResponceTypeR1b,\r
+  EmmcResponceTypeR2,\r
+  EmmcResponceTypeR3,\r
+  EmmcResponceTypeR4,\r
+  EmmcResponceTypeR5,\r
+  EmmcResponceTypeR5b,\r
+  EmmcResponceTypeR6,\r
+  EmmcResponceTypeR7\r
+} EMMC_RESPONSE_TYPE;\r
+\r
+typedef struct _EMMC_COMMAND_BLOCK {\r
+  UINT16                            CommandIndex;\r
+  UINT32                            CommandArgument;\r
+  UINT32                            CommandType;      // One of the EMMC_COMMAND_TYPE values\r
+  UINT32                            ResponseType;     // One of the EMMC_RESPONSE_TYPE values\r
+} EMMC_COMMAND_BLOCK;\r
+\r
+typedef struct _EMMC_STATUS_BLOCK {\r
+  UINT32                            Resp0;\r
+  UINT32                            Resp1;\r
+  UINT32                            Resp2;\r
+  UINT32                            Resp3;\r
+} EMMC_STATUS_BLOCK;\r
+\r
+typedef struct _EMMC_COMMAND_PACKET {\r
+  UINT64                            Timeout;\r
+  EMMC_COMMAND_BLOCK                *EmmcCmdBlk;\r
+  EMMC_STATUS_BLOCK                 *EmmcStatusBlk;\r
+  VOID                              *InDataBuffer;\r
+  VOID                              *OutDataBuffer;\r
+  UINT32                            InTransferLength;\r
+  UINT32                            OutTransferLength;\r
+} EMMC_COMMAND_PACKET;\r
+\r
+#pragma pack(1)\r
+\r
+typedef struct {\r
+  UINT32 Valid:1;\r
+  UINT32 End:1;\r
+  UINT32 Int:1;\r
+  UINT32 Reserved:1;\r
+  UINT32 Act:2;\r
+  UINT32 Reserved1:10;\r
+  UINT32 Length:16;\r
+  UINT32 Address;\r
+} EMMC_HC_ADMA_DESC_LINE;\r
+\r
+typedef struct {\r
+  UINT32   TimeoutFreq:6;     // bit 0:5\r
+  UINT32   Reserved:1;        // bit 6\r
+  UINT32   TimeoutUnit:1;     // bit 7\r
+  UINT32   BaseClkFreq:8;     // bit 8:15\r
+  UINT32   MaxBlkLen:2;       // bit 16:17\r
+  UINT32   BusWidth8:1;       // bit 18\r
+  UINT32   Adma2:1;           // bit 19\r
+  UINT32   Reserved2:1;       // bit 20\r
+  UINT32   HighSpeed:1;       // bit 21\r
+  UINT32   Sdma:1;            // bit 22\r
+  UINT32   SuspRes:1;         // bit 23\r
+  UINT32   Voltage33:1;       // bit 24\r
+  UINT32   Voltage30:1;       // bit 25\r
+  UINT32   Voltage18:1;       // bit 26\r
+  UINT32   Reserved3:1;       // bit 27\r
+  UINT32   SysBus64:1;        // bit 28\r
+  UINT32   AsyncInt:1;        // bit 29\r
+  UINT32   SlotType:2;        // bit 30:31\r
+  UINT32   Sdr50:1;           // bit 32\r
+  UINT32   Sdr104:1;          // bit 33\r
+  UINT32   Ddr50:1;           // bit 34\r
+  UINT32   Reserved4:1;       // bit 35\r
+  UINT32   DriverTypeA:1;     // bit 36\r
+  UINT32   DriverTypeC:1;     // bit 37\r
+  UINT32   DriverTypeD:1;     // bit 38\r
+  UINT32   DriverType4:1;     // bit 39\r
+  UINT32   TimerCount:4;      // bit 40:43\r
+  UINT32   Reserved5:1;       // bit 44\r
+  UINT32   TuningSDR50:1;     // bit 45\r
+  UINT32   RetuningMod:2;     // bit 46:47\r
+  UINT32   ClkMultiplier:8;   // bit 48:55\r
+  UINT32   Reserved6:7;       // bit 56:62\r
+  UINT32   Hs400:1;           // bit 63\r
+} EMMC_HC_SLOT_CAP;\r
+\r
+#pragma pack()\r
+\r
+/**\r
+  Software reset the specified EMMC host controller and enable all interrupts.\r
+\r
+  @param[in] Bar            The mmio base address of the slot to be accessed.\r
+\r
+  @retval EFI_SUCCESS       The software reset executes successfully.\r
+  @retval Others            The software reset fails.\r
+\r
+**/\r
+EFI_STATUS\r
+EmmcPeimHcReset (\r
+  IN UINTN                  Bar\r
+  );\r
+\r
+/**\r
+  Set all interrupt status bits in Normal and Error Interrupt Status Enable\r
+  register.\r
+\r
+  @param[in] Bar            The mmio base address of the slot to be accessed.\r
+\r
+  @retval EFI_SUCCESS       The operation executes successfully.\r
+  @retval Others            The operation fails.\r
+\r
+**/\r
+EFI_STATUS\r
+EmmcPeimHcEnableInterrupt (\r
+  IN UINTN                  Bar\r
+  );\r
+\r
+/**\r
+  Get the capability data from the specified slot.\r
+\r
+  @param[in]  Bar             The mmio base address of the slot to be accessed.\r
+  @param[out] Capability      The buffer to store the capability data.\r
+\r
+  @retval EFI_SUCCESS         The operation executes successfully.\r
+  @retval Others              The operation fails.\r
+\r
+**/\r
+EFI_STATUS\r
+EmmcPeimHcGetCapability (\r
+  IN     UINTN              Bar,\r
+     OUT EMMC_HC_SLOT_CAP   *Capability\r
+  );\r
+\r
+/**\r
+  Detect whether there is a EMMC card attached at the specified EMMC host controller\r
+  slot.\r
+\r
+  Refer to SD Host Controller Simplified spec 3.0 Section 3.1 for details.\r
+\r
+  @param[in]  Bar           The mmio base address of the slot to be accessed.\r
+\r
+  @retval EFI_SUCCESS       There is a EMMC card attached.\r
+  @retval EFI_NO_MEDIA      There is not a EMMC card attached.\r
+  @retval Others            The detection fails.\r
+\r
+**/\r
+EFI_STATUS\r
+EmmcPeimHcCardDetect (\r
+  IN UINTN                  Bar\r
+  );\r
+\r
+/**\r
+  Initial EMMC host controller with lowest clock frequency, max power and max timeout value\r
+  at initialization.\r
+\r
+  @param[in] Bar            The mmio base address of the slot to be accessed.\r
+\r
+  @retval EFI_SUCCESS       The host controller is initialized successfully.\r
+  @retval Others            The host controller isn't initialized successfully.\r
+\r
+**/\r
+EFI_STATUS\r
+EmmcPeimHcInitHost (\r
+  IN UINTN                  Bar\r
+  );\r
+\r
+/**\r
+  Send command SWITCH to the EMMC device to switch the mode of operation of the\r
+  selected Device or modifies the EXT_CSD registers.\r
+\r
+  Refer to EMMC Electrical Standard Spec 5.1 Section 6.10.4 for details.\r
+\r
+  @param[in] Slot           The slot number of the Emmc card to send the command to.\r
+  @param[in] Access         The access mode of SWTICH command.\r
+  @param[in] Index          The offset of the field to be access.\r
+  @param[in] Value          The value to be set to the specified field of EXT_CSD register.\r
+  @param[in] CmdSet         The value of CmdSet field of EXT_CSD register.\r
+\r
+  @retval EFI_SUCCESS       The operation is done correctly.\r
+  @retval Others            The operation fails.\r
+\r
+**/\r
+EFI_STATUS\r
+EmmcPeimSwitch (\r
+  IN EMMC_PEIM_HC_SLOT                  *Slot,\r
+  IN UINT8                              Access,\r
+  IN UINT8                              Index,\r
+  IN UINT8                              Value,\r
+  IN UINT8                              CmdSet\r
+  );\r
+\r
+/**\r
+  Send command SET_BLOCK_COUNT to the addressed EMMC device to set the number of\r
+  blocks for the following block read/write cmd.\r
+\r
+  Refer to EMMC Electrical Standard Spec 5.1 Section 6.10.4 for details.\r
+\r
+  @param[in] Slot           The slot number of the Emmc card to send the command to.\r
+  @param[in] BlockCount     The number of the logical block to access.\r
+\r
+  @retval EFI_SUCCESS       The operation is done correctly.\r
+  @retval Others            The operation fails.\r
+\r
+**/\r
+EFI_STATUS\r
+EmmcPeimSetBlkCount (\r
+  IN EMMC_PEIM_HC_SLOT              *Slot,\r
+  IN UINT16                         BlockCount\r
+  );\r
+\r
+/**\r
+  Send command READ_MULTIPLE_BLOCK/WRITE_MULTIPLE_BLOCK to the addressed EMMC device\r
+  to read/write the specified number of blocks.\r
+\r
+  Refer to EMMC Electrical Standard Spec 5.1 Section 6.10.4 for details.\r
+\r
+  @param[in] Slot           The slot number of the Emmc card to send the command to.\r
+  @param[in] Lba            The logical block address of starting access.\r
+  @param[in] BlockSize      The block size of specified EMMC device partition.\r
+  @param[in] Buffer         The pointer to the transfer buffer.\r
+  @param[in] BufferSize     The size of transfer buffer.\r
+  @param[in] IsRead         Boolean to show the operation direction.\r
+\r
+  @retval EFI_SUCCESS       The operation is done correctly.\r
+  @retval Others            The operation fails.\r
+\r
+**/\r
+EFI_STATUS\r
+EmmcPeimRwMultiBlocks (\r
+  IN EMMC_PEIM_HC_SLOT              *Slot,\r
+  IN EFI_LBA                        Lba,\r
+  IN UINT32                         BlockSize,\r
+  IN VOID                           *Buffer,\r
+  IN UINTN                          BufferSize,\r
+  IN BOOLEAN                        IsRead\r
+  );\r
+\r
+/**\r
+  Execute EMMC device identification procedure.\r
+\r
+  Refer to EMMC Electrical Standard Spec 5.1 Section 6.4 for details.\r
+\r
+  @param[in] Slot           The slot number of the Emmc card to send the command to.\r
+\r
+  @retval EFI_SUCCESS       There is a EMMC card.\r
+  @retval Others            There is not a EMMC card.\r
+\r
+**/\r
+EFI_STATUS\r
+EmmcPeimIdentification (\r
+  IN EMMC_PEIM_HC_SLOT           *Slot\r
+  );\r
+\r
+/**\r
+  Free the resource used by the TRB.\r
+\r
+  @param[in] Trb        The pointer to the EMMC_TRB instance.\r
+\r
+**/\r
+VOID\r
+EmmcPeimFreeTrb (\r
+  IN EMMC_TRB           *Trb\r
+  );\r
+\r
+#endif\r
+\r
diff --git a/MdeModulePkg/Bus/Sd/EmmcDxe/ComponentName.c b/MdeModulePkg/Bus/Sd/EmmcDxe/ComponentName.c
new file mode 100644 (file)
index 0000000..c9e9d08
--- /dev/null
@@ -0,0 +1,241 @@
+/** @file\r
+  UEFI Component Name(2) protocol implementation for EmmcDxe driver.\r
+\r
+  Copyright (c) 2015, Intel Corporation. All rights reserved.<BR>\r
+  This program and the accompanying materials\r
+  are licensed and made available under the terms and conditions of the BSD License\r
+  which accompanies this distribution.  The full text of the license may be found at\r
+  http://opensource.org/licenses/bsd-license.php\r
+\r
+  THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+  WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+\r
+**/\r
+\r
+#include "EmmcDxe.h"\r
+\r
+//\r
+// Driver name table\r
+//\r
+GLOBAL_REMOVE_IF_UNREFERENCED EFI_UNICODE_STRING_TABLE mEmmcDxeDriverNameTable[] = {\r
+  { "eng;en", L"Edkii Emmc Device Driver" },\r
+  { NULL , NULL }\r
+};\r
+\r
+//\r
+// Controller name table\r
+//\r
+GLOBAL_REMOVE_IF_UNREFERENCED EFI_UNICODE_STRING_TABLE mEmmcDxeControllerNameTable[] = {\r
+  { "eng;en", L"Edkii Emmc Host Controller" },\r
+  { NULL , NULL }\r
+};\r
+\r
+//\r
+// EFI Component Name Protocol\r
+//\r
+GLOBAL_REMOVE_IF_UNREFERENCED EFI_COMPONENT_NAME_PROTOCOL  gEmmcDxeComponentName = {\r
+  EmmcDxeComponentNameGetDriverName,\r
+  EmmcDxeComponentNameGetControllerName,\r
+  "eng"\r
+};\r
+\r
+//\r
+// EFI Component Name 2 Protocol\r
+//\r
+GLOBAL_REMOVE_IF_UNREFERENCED EFI_COMPONENT_NAME2_PROTOCOL gEmmcDxeComponentName2 = {\r
+  (EFI_COMPONENT_NAME2_GET_DRIVER_NAME) EmmcDxeComponentNameGetDriverName,\r
+  (EFI_COMPONENT_NAME2_GET_CONTROLLER_NAME) EmmcDxeComponentNameGetControllerName,\r
+  "en"\r
+};\r
+\r
+/**\r
+  Retrieves a Unicode string that is the user readable name of the driver.\r
+\r
+  This function retrieves the user readable name of a driver in the form of a\r
+  Unicode string. If the driver specified by This has a user readable name in\r
+  the language specified by Language, then a pointer to the driver name is\r
+  returned in DriverName, and EFI_SUCCESS is returned. If the driver specified\r
+  by This does not support the language specified by Language,\r
+  then EFI_UNSUPPORTED is returned.\r
+\r
+  @param  This[in]              A pointer to the EFI_COMPONENT_NAME2_PROTOCOL or\r
+                                EFI_COMPONENT_NAME_PROTOCOL instance.\r
+\r
+  @param  Language[in]          A pointer to a Null-terminated ASCII string\r
+                                array indicating the language. This is the\r
+                                language of the driver name that the caller is\r
+                                requesting, and it must match one of the\r
+                                languages specified in SupportedLanguages. The\r
+                                number of languages supported by a driver is up\r
+                                to the driver writer. Language is specified\r
+                                in RFC 4646 or ISO 639-2 language code format.\r
+\r
+  @param  DriverName[out]       A pointer to the Unicode string to return.\r
+                                This Unicode string is the name of the\r
+                                driver specified by This in the language\r
+                                specified by Language.\r
+\r
+  @retval EFI_SUCCESS           The Unicode string for the Driver specified by\r
+                                This and the language specified by Language was\r
+                                returned in DriverName.\r
+\r
+  @retval EFI_INVALID_PARAMETER Language is NULL.\r
+\r
+  @retval EFI_INVALID_PARAMETER DriverName is NULL.\r
+\r
+  @retval EFI_UNSUPPORTED       The driver specified by This does not support\r
+                                the language specified by Language.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+EmmcDxeComponentNameGetDriverName (\r
+  IN  EFI_COMPONENT_NAME_PROTOCOL  *This,\r
+  IN  CHAR8                        *Language,\r
+  OUT CHAR16                       **DriverName\r
+  )\r
+{\r
+  return LookupUnicodeString2 (\r
+           Language,\r
+           This->SupportedLanguages,\r
+           mEmmcDxeDriverNameTable,\r
+           DriverName,\r
+           (BOOLEAN)(This == &gEmmcDxeComponentName)\r
+           );\r
+\r
+}\r
+\r
+/**\r
+  Retrieves a Unicode string that is the user readable name of the controller\r
+  that is being managed by a driver.\r
+\r
+  This function retrieves the user readable name of the controller specified by\r
+  ControllerHandle and ChildHandle in the form of a Unicode string. If the\r
+  driver specified by This has a user readable name in the language specified by\r
+  Language, then a pointer to the controller name is returned in ControllerName,\r
+  and EFI_SUCCESS is returned.  If the driver specified by This is not currently\r
+  managing the controller specified by ControllerHandle and ChildHandle,\r
+  then EFI_UNSUPPORTED is returned.  If the driver specified by This does not\r
+  support the language specified by Language, then EFI_UNSUPPORTED is returned.\r
+\r
+  @param  This[in]              A pointer to the EFI_COMPONENT_NAME2_PROTOCOL or\r
+                                EFI_COMPONENT_NAME_PROTOCOL instance.\r
+\r
+  @param  ControllerHandle[in]  The handle of a controller that the driver\r
+                                specified by This is managing.  This handle\r
+                                specifies the controller whose name is to be\r
+                                returned.\r
+\r
+  @param  ChildHandle[in]       The handle of the child controller to retrieve\r
+                                the name of.  This is an optional parameter that\r
+                                may be NULL.  It will be NULL for device\r
+                                drivers.  It will also be NULL for a bus drivers\r
+                                that wish to retrieve the name of the bus\r
+                                controller.  It will not be NULL for a bus\r
+                                driver that wishes to retrieve the name of a\r
+                                child controller.\r
+\r
+  @param  Language[in]          A pointer to a Null-terminated ASCII string\r
+                                array indicating the language.  This is the\r
+                                language of the driver name that the caller is\r
+                                requesting, and it must match one of the\r
+                                languages specified in SupportedLanguages. The\r
+                                number of languages supported by a driver is up\r
+                                to the driver writer. Language is specified in\r
+                                RFC 4646 or ISO 639-2 language code format.\r
+\r
+  @param  ControllerName[out]   A pointer to the Unicode string to return.\r
+                                This Unicode string is the name of the\r
+                                controller specified by ControllerHandle and\r
+                                ChildHandle in the language specified by\r
+                                Language from the point of view of the driver\r
+                                specified by This.\r
+\r
+  @retval EFI_SUCCESS           The Unicode string for the user readable name in\r
+                                the language specified by Language for the\r
+                                driver specified by This was returned in\r
+                                DriverName.\r
+\r
+  @retval EFI_INVALID_PARAMETER ControllerHandle is NULL.\r
+\r
+  @retval EFI_INVALID_PARAMETER ChildHandle is not NULL and it is not a valid\r
+                                EFI_HANDLE.\r
+\r
+  @retval EFI_INVALID_PARAMETER Language is NULL.\r
+\r
+  @retval EFI_INVALID_PARAMETER ControllerName is NULL.\r
+\r
+  @retval EFI_UNSUPPORTED       The driver specified by This is not currently\r
+                                managing the controller specified by\r
+                                ControllerHandle and ChildHandle.\r
+\r
+  @retval EFI_UNSUPPORTED       The driver specified by This does not support\r
+                                the language specified by Language.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+EmmcDxeComponentNameGetControllerName (\r
+  IN  EFI_COMPONENT_NAME_PROTOCOL                     *This,\r
+  IN  EFI_HANDLE                                      ControllerHandle,\r
+  IN  EFI_HANDLE                                      ChildHandle        OPTIONAL,\r
+  IN  CHAR8                                           *Language,\r
+  OUT CHAR16                                          **ControllerName\r
+  )\r
+{\r
+  EFI_STATUS                Status;\r
+  EFI_BLOCK_IO_PROTOCOL     *BlockIo;\r
+  EMMC_DEVICE               *Device;\r
+  EMMC_PARTITION            *Partition;\r
+  EFI_UNICODE_STRING_TABLE  *ControllerNameTable;\r
+\r
+  //\r
+  // Make sure this driver is currently managing ControllHandle\r
+  //\r
+  Status = EfiTestManagedDevice (\r
+             ControllerHandle,\r
+             gEmmcDxeDriverBinding.DriverBindingHandle,\r
+             &gEfiSdMmcPassThruProtocolGuid\r
+             );\r
+  if (EFI_ERROR (Status)) {\r
+    return Status;\r
+  }\r
+\r
+  ControllerNameTable = mEmmcDxeControllerNameTable;\r
+  if (ChildHandle != NULL) {\r
+    Status = EfiTestChildHandle (\r
+               ControllerHandle,\r
+               ChildHandle,\r
+               &gEfiSdMmcPassThruProtocolGuid\r
+               );\r
+    if (EFI_ERROR (Status)) {\r
+      return Status;\r
+    }\r
+    //\r
+    // Get the child context\r
+    //\r
+    Status = gBS->OpenProtocol (\r
+                    ChildHandle,\r
+                    &gEfiBlockIoProtocolGuid,\r
+                    (VOID **) &BlockIo,\r
+                    gEmmcDxeDriverBinding.DriverBindingHandle,\r
+                    ChildHandle,\r
+                    EFI_OPEN_PROTOCOL_GET_PROTOCOL\r
+                    );\r
+    if (EFI_ERROR (Status)) {\r
+      return EFI_UNSUPPORTED;\r
+    }\r
+\r
+    Partition = EMMC_PARTITION_DATA_FROM_BLKIO (BlockIo);\r
+    Device    = Partition->Device;\r
+    ControllerNameTable = Device->ControllerNameTable;\r
+  }\r
+\r
+  return LookupUnicodeString2 (\r
+           Language,\r
+           This->SupportedLanguages,\r
+           ControllerNameTable,\r
+           ControllerName,\r
+           (BOOLEAN)(This == &gEmmcDxeComponentName)\r
+           );}\r
+\r
diff --git a/MdeModulePkg/Bus/Sd/EmmcDxe/EmmcBlockIo.c b/MdeModulePkg/Bus/Sd/EmmcDxe/EmmcBlockIo.c
new file mode 100644 (file)
index 0000000..edb438b
--- /dev/null
@@ -0,0 +1,1591 @@
+/** @file\r
+  The helper functions for BlockIo and BlockIo2 protocol.\r
+\r
+  Copyright (c) 2015, Intel Corporation. All rights reserved.<BR>\r
+  This program and the accompanying materials\r
+  are licensed and made available under the terms and conditions of the BSD License\r
+  which accompanies this distribution.  The full text of the license may be found at\r
+  http://opensource.org/licenses/bsd-license.php\r
+\r
+  THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+  WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+\r
+**/\r
+\r
+#include "EmmcDxe.h"\r
+\r
+/**\r
+  Nonblocking I/O callback funtion when the event is signaled.\r
+\r
+  @param[in]  Event     The Event this notify function registered to.\r
+  @param[in]  Context   Pointer to the context data registered to the\r
+                        Event.\r
+\r
+**/\r
+VOID\r
+EFIAPI\r
+AsyncIoCallback (\r
+  IN EFI_EVENT                Event,\r
+  IN VOID                     *Context\r
+  )\r
+{\r
+  EMMC_REQUEST                *Request;\r
+  EFI_STATUS                  Status;\r
+\r
+  Status = gBS->CloseEvent (Event);\r
+  if (EFI_ERROR (Status)) {\r
+    return;\r
+  }\r
+\r
+  Request = (EMMC_REQUEST *) Context;\r
+\r
+  DEBUG_CODE_BEGIN ();\r
+    DEBUG ((EFI_D_INFO, "Emmc Async Request: CmdIndex[%d] Arg[%08x] %r\n",\r
+            Request->SdMmcCmdBlk.CommandIndex, Request->SdMmcCmdBlk.CommandArgument,\r
+            Request->Packet.TransactionStatus));\r
+  DEBUG_CODE_END ();\r
+\r
+  if (EFI_ERROR (Request->Packet.TransactionStatus)) {\r
+    Request->Token->TransactionStatus = Request->Packet.TransactionStatus;\r
+  }\r
+\r
+  RemoveEntryList (&Request->Link);\r
+\r
+  if (Request->IsEnd) {\r
+    gBS->SignalEvent (Request->Token->Event);\r
+  }\r
+\r
+  FreePool (Request);\r
+}\r
+\r
+/**\r
+  Send command SELECT to the device to select/deselect the device.\r
+\r
+  @param[in]  Device            A pointer to the EMMC_DEVICE instance.\r
+  @param[in]  Rca               The relative device address to use.\r
+\r
+  @retval EFI_SUCCESS           The request is executed successfully.\r
+  @retval EFI_OUT_OF_RESOURCES  The request could not be executed due to a lack of resources.\r
+  @retval Others                The request could not be executed successfully.\r
+\r
+**/\r
+EFI_STATUS\r
+EmmcSelect (\r
+  IN     EMMC_DEVICE                  *Device,\r
+  IN     UINT16                       Rca\r
+  )\r
+{\r
+  EFI_STATUS                          Status;\r
+  EFI_SD_MMC_PASS_THRU_PROTOCOL       *PassThru;\r
+  EFI_SD_MMC_COMMAND_BLOCK            SdMmcCmdBlk;\r
+  EFI_SD_MMC_STATUS_BLOCK             SdMmcStatusBlk;\r
+  EFI_SD_MMC_PASS_THRU_COMMAND_PACKET Packet;\r
+\r
+  PassThru = Device->Private->PassThru;\r
+\r
+  ZeroMem (&SdMmcCmdBlk, sizeof (SdMmcCmdBlk));\r
+  ZeroMem (&SdMmcStatusBlk, sizeof (SdMmcStatusBlk));\r
+  ZeroMem (&Packet, sizeof (Packet));\r
+  Packet.SdMmcCmdBlk    = &SdMmcCmdBlk;\r
+  Packet.SdMmcStatusBlk = &SdMmcStatusBlk;\r
+  Packet.Timeout        = EMMC_GENERIC_TIMEOUT;\r
+\r
+  SdMmcCmdBlk.CommandIndex = EMMC_SELECT_DESELECT_CARD;\r
+  SdMmcCmdBlk.CommandType  = SdMmcCommandTypeAc;\r
+  SdMmcCmdBlk.ResponseType = SdMmcResponseTypeR1;\r
+  SdMmcCmdBlk.CommandArgument = (UINT32)Rca << 16;\r
+\r
+  Status = PassThru->PassThru (PassThru, Device->Slot, &Packet, NULL);\r
+\r
+  return Status;\r
+}\r
+\r
+/**\r
+  Send command SEND_STATUS to the device to get device status.\r
+\r
+  @param[in]  Device            A pointer to the EMMC_DEVICE instance.\r
+  @param[in]  Rca               The relative device address to use.\r
+  @param[out] DevStatus         The buffer to store the device status.\r
+\r
+  @retval EFI_SUCCESS           The request is executed successfully.\r
+  @retval EFI_OUT_OF_RESOURCES  The request could not be executed due to a lack of resources.\r
+  @retval Others                The request could not be executed successfully.\r
+\r
+**/\r
+EFI_STATUS\r
+EmmcSendStatus (\r
+  IN     EMMC_DEVICE                  *Device,\r
+  IN     UINT16                       Rca,\r
+     OUT UINT32                       *DevStatus\r
+  )\r
+{\r
+  EFI_STATUS                          Status;\r
+  EFI_SD_MMC_PASS_THRU_PROTOCOL       *PassThru;\r
+  EFI_SD_MMC_COMMAND_BLOCK            SdMmcCmdBlk;\r
+  EFI_SD_MMC_STATUS_BLOCK             SdMmcStatusBlk;\r
+  EFI_SD_MMC_PASS_THRU_COMMAND_PACKET Packet;\r
+\r
+  PassThru = Device->Private->PassThru;\r
+\r
+  ZeroMem (&SdMmcCmdBlk, sizeof (SdMmcCmdBlk));\r
+  ZeroMem (&SdMmcStatusBlk, sizeof (SdMmcStatusBlk));\r
+  ZeroMem (&Packet, sizeof (Packet));\r
+  Packet.SdMmcCmdBlk    = &SdMmcCmdBlk;\r
+  Packet.SdMmcStatusBlk = &SdMmcStatusBlk;\r
+  Packet.Timeout        = EMMC_GENERIC_TIMEOUT;\r
+\r
+  SdMmcCmdBlk.CommandIndex = EMMC_SEND_STATUS;\r
+  SdMmcCmdBlk.CommandType  = SdMmcCommandTypeAc;\r
+  SdMmcCmdBlk.ResponseType = SdMmcResponseTypeR1;\r
+  SdMmcCmdBlk.CommandArgument = (UINT32)Rca << 16;\r
+\r
+  Status = PassThru->PassThru (PassThru, Device->Slot, &Packet, NULL);\r
+  if (!EFI_ERROR (Status)) {\r
+    CopyMem (DevStatus, &SdMmcStatusBlk.Resp0, sizeof (UINT32));\r
+  }\r
+\r
+  return Status;\r
+}\r
+\r
+/**\r
+  Send command SEND_CSD to the device to get the CSD register data.\r
+\r
+  @param[in]  Device            A pointer to the EMMC_DEVICE instance.\r
+  @param[in]  Rca               The relative device address to use.\r
+  @param[out] Csd               The buffer to store the EMMC_CSD register data.\r
+\r
+  @retval EFI_SUCCESS           The request is executed successfully.\r
+  @retval EFI_OUT_OF_RESOURCES  The request could not be executed due to a lack of resources.\r
+  @retval Others                The request could not be executed successfully.\r
+\r
+**/\r
+EFI_STATUS\r
+EmmcGetCsd (\r
+  IN     EMMC_DEVICE                  *Device,\r
+  IN     UINT16                       Rca,\r
+     OUT EMMC_CSD                     *Csd\r
+  )\r
+{\r
+  EFI_STATUS                          Status;\r
+  EFI_SD_MMC_PASS_THRU_PROTOCOL       *PassThru;\r
+  EFI_SD_MMC_COMMAND_BLOCK            SdMmcCmdBlk;\r
+  EFI_SD_MMC_STATUS_BLOCK             SdMmcStatusBlk;\r
+  EFI_SD_MMC_PASS_THRU_COMMAND_PACKET Packet;\r
+\r
+  PassThru = Device->Private->PassThru;\r
+\r
+  ZeroMem (&SdMmcCmdBlk, sizeof (SdMmcCmdBlk));\r
+  ZeroMem (&SdMmcStatusBlk, sizeof (SdMmcStatusBlk));\r
+  ZeroMem (&Packet, sizeof (Packet));\r
+  ZeroMem (Csd, sizeof (EMMC_CSD));\r
+\r
+  Packet.SdMmcCmdBlk    = &SdMmcCmdBlk;\r
+  Packet.SdMmcStatusBlk = &SdMmcStatusBlk;\r
+  Packet.Timeout        = EMMC_GENERIC_TIMEOUT;\r
+\r
+  SdMmcCmdBlk.CommandIndex = EMMC_SEND_CSD;\r
+  SdMmcCmdBlk.CommandType  = SdMmcCommandTypeAc;\r
+  SdMmcCmdBlk.ResponseType = SdMmcResponseTypeR2;\r
+  SdMmcCmdBlk.CommandArgument = (UINT32)Rca << 16;\r
+\r
+  Status = PassThru->PassThru (PassThru, Device->Slot, &Packet, NULL);\r
+  if (!EFI_ERROR (Status)) {\r
+    //\r
+    // For details, refer to SD Host Controller Simplified Spec 3.0 Table 2-12.\r
+    //\r
+    CopyMem (((UINT8*)Csd) + 1, &SdMmcStatusBlk.Resp0, sizeof (EMMC_CSD) - 1);\r
+  }\r
+\r
+  return Status;\r
+}\r
+\r
+/**\r
+  Send command SEND_CID to the device to get the CID register data.\r
+\r
+  @param[in]  Device            A pointer to the EMMC_DEVICE instance.\r
+  @param[in]  Rca               The relative device address to use.\r
+  @param[out] Cid               The buffer to store the EMMC_CID register data.\r
+\r
+  @retval EFI_SUCCESS           The request is executed successfully.\r
+  @retval EFI_OUT_OF_RESOURCES  The request could not be executed due to a lack of resources.\r
+  @retval Others                The request could not be executed successfully.\r
+\r
+**/\r
+EFI_STATUS\r
+EmmcGetCid (\r
+  IN     EMMC_DEVICE            *Device,\r
+  IN     UINT16                 Rca,\r
+     OUT EMMC_CID               *Cid\r
+  )\r
+{\r
+  EFI_STATUS                          Status;\r
+  EFI_SD_MMC_PASS_THRU_PROTOCOL       *PassThru;\r
+  EFI_SD_MMC_COMMAND_BLOCK            SdMmcCmdBlk;\r
+  EFI_SD_MMC_STATUS_BLOCK             SdMmcStatusBlk;\r
+  EFI_SD_MMC_PASS_THRU_COMMAND_PACKET Packet;\r
+\r
+  PassThru = Device->Private->PassThru;\r
+\r
+  ZeroMem (&SdMmcCmdBlk, sizeof (SdMmcCmdBlk));\r
+  ZeroMem (&SdMmcStatusBlk, sizeof (SdMmcStatusBlk));\r
+  ZeroMem (&Packet, sizeof (Packet));\r
+  ZeroMem (Cid, sizeof (EMMC_CID));\r
+\r
+  Packet.SdMmcCmdBlk    = &SdMmcCmdBlk;\r
+  Packet.SdMmcStatusBlk = &SdMmcStatusBlk;\r
+  Packet.Timeout        = EMMC_GENERIC_TIMEOUT;\r
+\r
+  SdMmcCmdBlk.CommandIndex = EMMC_SEND_CID;\r
+  SdMmcCmdBlk.CommandType  = SdMmcCommandTypeAc;\r
+  SdMmcCmdBlk.ResponseType = SdMmcResponseTypeR2;\r
+  SdMmcCmdBlk.CommandArgument = (UINT32)Rca << 16;\r
+\r
+  Status = PassThru->PassThru (PassThru, Device->Slot, &Packet, NULL);\r
+  if (!EFI_ERROR (Status)) {\r
+    //\r
+    // For details, refer to SD Host Controller Simplified Spec 3.0 Table 2-12.\r
+    //\r
+    CopyMem (((UINT8*)Cid) + 1, &SdMmcStatusBlk.Resp0, sizeof (EMMC_CID) - 1);\r
+  }\r
+\r
+  return Status;\r
+}\r
+\r
+/**\r
+  Send command SEND_EXT_CSD to the device to get the EXT_CSD register data.\r
+\r
+  @param[in]  Device            A pointer to the EMMC_DEVICE instance.\r
+  @param[out] ExtCsd            The buffer to store the EXT_CSD register data.\r
+\r
+  @retval EFI_SUCCESS           The request is executed successfully.\r
+  @retval EFI_OUT_OF_RESOURCES  The request could not be executed due to a lack of resources.\r
+  @retval Others                The request could not be executed successfully.\r
+\r
+**/\r
+EFI_STATUS\r
+EmmcGetExtCsd (\r
+  IN     EMMC_DEVICE                  *Device,\r
+     OUT EMMC_EXT_CSD                 *ExtCsd\r
+  )\r
+{\r
+  EFI_STATUS                          Status;\r
+  EFI_SD_MMC_PASS_THRU_PROTOCOL       *PassThru;\r
+  EFI_SD_MMC_COMMAND_BLOCK            SdMmcCmdBlk;\r
+  EFI_SD_MMC_STATUS_BLOCK             SdMmcStatusBlk;\r
+  EFI_SD_MMC_PASS_THRU_COMMAND_PACKET Packet;\r
+\r
+  PassThru = Device->Private->PassThru;\r
+\r
+  ZeroMem (&SdMmcCmdBlk, sizeof (SdMmcCmdBlk));\r
+  ZeroMem (&SdMmcStatusBlk, sizeof (SdMmcStatusBlk));\r
+  ZeroMem (&Packet, sizeof (Packet));\r
+  ZeroMem (ExtCsd, sizeof (EMMC_EXT_CSD));\r
+  Packet.SdMmcCmdBlk    = &SdMmcCmdBlk;\r
+  Packet.SdMmcStatusBlk = &SdMmcStatusBlk;\r
+  Packet.Timeout        = EMMC_GENERIC_TIMEOUT;\r
+\r
+  SdMmcCmdBlk.CommandIndex = EMMC_SEND_EXT_CSD;\r
+  SdMmcCmdBlk.CommandType  = SdMmcCommandTypeAdtc;\r
+  SdMmcCmdBlk.ResponseType = SdMmcResponseTypeR1;\r
+  SdMmcCmdBlk.CommandArgument = 0x00000000;\r
+  Packet.InDataBuffer     = ExtCsd;\r
+  Packet.InTransferLength = sizeof (EMMC_EXT_CSD);\r
+\r
+  Status = PassThru->PassThru (PassThru, Device->Slot, &Packet, NULL);\r
+\r
+  return Status;\r
+}\r
+\r
+/**\r
+  Set the specified EXT_CSD register field through sync or async I/O request.\r
+\r
+  @param[in]  Partition         A pointer to the EMMC_PARTITION instance.\r
+  @param[in]  Offset            The offset of the specified field in EXT_CSD register.\r
+  @param[in]  Value             The byte value written to the field specified by Offset.\r
+  @param[in]  Token             A pointer to the token associated with the transaction.\r
+  @param[in]  IsEnd             A boolean to show whether it's the last cmd in a series of cmds.\r
+                                This parameter is only meaningful in async I/O request.\r
+\r
+  @retval EFI_SUCCESS           The request is executed successfully.\r
+  @retval EFI_OUT_OF_RESOURCES  The request could not be executed due to a lack of resources.\r
+  @retval Others                The request could not be executed successfully.\r
+\r
+**/\r
+EFI_STATUS\r
+EmmcSetExtCsd (\r
+  IN  EMMC_PARTITION            *Partition,\r
+  IN  UINT8                     Offset,\r
+  IN  UINT8                     Value,\r
+  IN  EFI_BLOCK_IO2_TOKEN       *Token,\r
+  IN  BOOLEAN                   IsEnd\r
+  )\r
+{\r
+  EFI_STATUS                    Status;\r
+  EMMC_DEVICE                   *Device;\r
+  EMMC_REQUEST                  *SetExtCsdReq;\r
+  EFI_SD_MMC_PASS_THRU_PROTOCOL *PassThru;\r
+  UINT32                        CommandArgument;\r
+  EFI_TPL                       OldTpl;\r
+\r
+  SetExtCsdReq = NULL;\r
+\r
+  Device   = Partition->Device;\r
+  PassThru = Device->Private->PassThru;\r
+\r
+  SetExtCsdReq = AllocateZeroPool (sizeof (EMMC_REQUEST));\r
+  if (SetExtCsdReq == NULL) {\r
+    Status = EFI_OUT_OF_RESOURCES;\r
+    goto Error;\r
+  }\r
+\r
+  SetExtCsdReq->Signature = EMMC_REQUEST_SIGNATURE;\r
+  OldTpl = gBS->RaiseTPL (TPL_CALLBACK);\r
+  InsertTailList (&Partition->Queue, &SetExtCsdReq->Link);\r
+  gBS->RestoreTPL (OldTpl);\r
+  SetExtCsdReq->Packet.SdMmcCmdBlk    = &SetExtCsdReq->SdMmcCmdBlk;\r
+  SetExtCsdReq->Packet.SdMmcStatusBlk = &SetExtCsdReq->SdMmcStatusBlk;\r
+  SetExtCsdReq->Packet.Timeout        = EMMC_GENERIC_TIMEOUT;\r
+\r
+  SetExtCsdReq->SdMmcCmdBlk.CommandIndex = EMMC_SWITCH;\r
+  SetExtCsdReq->SdMmcCmdBlk.CommandType  = SdMmcCommandTypeAc;\r
+  SetExtCsdReq->SdMmcCmdBlk.ResponseType = SdMmcResponseTypeR1b;\r
+  //\r
+  // Write the Value to the field specified by Offset.\r
+  //\r
+  CommandArgument = (Value << 8) | (Offset << 16) | BIT24 | BIT25;\r
+  SetExtCsdReq->SdMmcCmdBlk.CommandArgument = CommandArgument;\r
+\r
+  SetExtCsdReq->IsEnd = IsEnd;\r
+  SetExtCsdReq->Token = Token;\r
+\r
+  if ((Token != NULL) && (Token->Event != NULL)) {\r
+    Status = gBS->CreateEvent (\r
+                    EVT_NOTIFY_SIGNAL,\r
+                    TPL_CALLBACK,\r
+                    AsyncIoCallback,\r
+                    SetExtCsdReq,\r
+                    &SetExtCsdReq->Event\r
+                    );\r
+    if (EFI_ERROR (Status)) {\r
+      goto Error;\r
+    }\r
+  } else {\r
+    SetExtCsdReq->Event = NULL;\r
+  }\r
+\r
+  Status = PassThru->PassThru (PassThru, Device->Slot, &SetExtCsdReq->Packet, SetExtCsdReq->Event);\r
+\r
+Error:\r
+  if ((Token != NULL) && (Token->Event != NULL)) {\r
+    //\r
+    // For asynchronous operation, only free request and event in error case.\r
+    // The request and event will be freed in asynchronous callback for success case.\r
+    //\r
+    if (EFI_ERROR (Status) && (SetExtCsdReq != NULL)) {\r
+      OldTpl = gBS->RaiseTPL (TPL_CALLBACK);\r
+      RemoveEntryList (&SetExtCsdReq->Link);\r
+      gBS->RestoreTPL (OldTpl);\r
+      if (SetExtCsdReq->Event != NULL) {\r
+        gBS->CloseEvent (SetExtCsdReq->Event);\r
+      }\r
+      FreePool (SetExtCsdReq);\r
+    }\r
+  } else {\r
+    //\r
+    // For synchronous operation, free request whatever the execution result is.\r
+    //\r
+    if (SetExtCsdReq != NULL) {\r
+      OldTpl = gBS->RaiseTPL (TPL_CALLBACK);\r
+      RemoveEntryList (&SetExtCsdReq->Link);\r
+      gBS->RestoreTPL (OldTpl);\r
+      FreePool (SetExtCsdReq);\r
+    }\r
+  }\r
+\r
+  return Status;\r
+}\r
+\r
+/**\r
+  Set the number of blocks for a block read/write cmd through sync or async I/O request.\r
+\r
+  @param[in]  Partition         A pointer to the EMMC_PARTITION instance.\r
+  @param[in]  BlockNum          The number of blocks for transfer.\r
+  @param[in]  Token             A pointer to the token associated with the transaction.\r
+  @param[in]  IsEnd             A boolean to show whether it's the last cmd in a series of cmds.\r
+                                This parameter is only meaningful in async I/O request.\r
+\r
+  @retval EFI_SUCCESS           The request is executed successfully.\r
+  @retval EFI_OUT_OF_RESOURCES  The request could not be executed due to a lack of resources.\r
+  @retval Others                The request could not be executed successfully.\r
+\r
+**/\r
+EFI_STATUS\r
+EmmcSetBlkCount (\r
+  IN  EMMC_PARTITION            *Partition,\r
+  IN  UINT16                    BlockNum,\r
+  IN  EFI_BLOCK_IO2_TOKEN       *Token,\r
+  IN  BOOLEAN                   IsEnd\r
+  )\r
+{\r
+  EFI_STATUS                    Status;\r
+  EMMC_DEVICE                   *Device;\r
+  EMMC_REQUEST                  *SetBlkCntReq;\r
+  EFI_SD_MMC_PASS_THRU_PROTOCOL *PassThru;\r
+  EFI_TPL                       OldTpl;\r
+\r
+  SetBlkCntReq = NULL;\r
+\r
+  Device   = Partition->Device;\r
+  PassThru = Device->Private->PassThru;\r
+\r
+  SetBlkCntReq = AllocateZeroPool (sizeof (EMMC_REQUEST));\r
+  if (SetBlkCntReq == NULL) {\r
+    Status = EFI_OUT_OF_RESOURCES;\r
+    goto Error;\r
+  }\r
+\r
+  SetBlkCntReq->Signature = EMMC_REQUEST_SIGNATURE;\r
+  OldTpl = gBS->RaiseTPL (TPL_CALLBACK);\r
+  InsertTailList (&Partition->Queue, &SetBlkCntReq->Link);\r
+  gBS->RestoreTPL (OldTpl);\r
+  SetBlkCntReq->Packet.SdMmcCmdBlk    = &SetBlkCntReq->SdMmcCmdBlk;\r
+  SetBlkCntReq->Packet.SdMmcStatusBlk = &SetBlkCntReq->SdMmcStatusBlk;\r
+  SetBlkCntReq->Packet.Timeout        = EMMC_GENERIC_TIMEOUT;\r
+\r
+  SetBlkCntReq->SdMmcCmdBlk.CommandIndex = EMMC_SET_BLOCK_COUNT;\r
+  SetBlkCntReq->SdMmcCmdBlk.CommandType  = SdMmcCommandTypeAc;\r
+  SetBlkCntReq->SdMmcCmdBlk.ResponseType = SdMmcResponseTypeR1;\r
+  SetBlkCntReq->SdMmcCmdBlk.CommandArgument = BlockNum;\r
+\r
+  SetBlkCntReq->IsEnd = IsEnd;\r
+  SetBlkCntReq->Token = Token;\r
+\r
+  if ((Token != NULL) && (Token->Event != NULL)) {\r
+    Status = gBS->CreateEvent (\r
+                    EVT_NOTIFY_SIGNAL,\r
+                    TPL_CALLBACK,\r
+                    AsyncIoCallback,\r
+                    SetBlkCntReq,\r
+                    &SetBlkCntReq->Event\r
+                    );\r
+    if (EFI_ERROR (Status)) {\r
+      goto Error;\r
+    }\r
+  } else {\r
+    SetBlkCntReq->Event = NULL;\r
+  }\r
+\r
+  Status = PassThru->PassThru (PassThru, Device->Slot, &SetBlkCntReq->Packet, SetBlkCntReq->Event);\r
+\r
+Error:\r
+  if ((Token != NULL) && (Token->Event != NULL)) {\r
+    //\r
+    // For asynchronous operation, only free request and event in error case.\r
+    // The request and event will be freed in asynchronous callback for success case.\r
+    //\r
+    if (EFI_ERROR (Status) && (SetBlkCntReq != NULL)) {\r
+      OldTpl = gBS->RaiseTPL (TPL_CALLBACK);\r
+      RemoveEntryList (&SetBlkCntReq->Link);\r
+      gBS->RestoreTPL (OldTpl);\r
+      if (SetBlkCntReq->Event != NULL) {\r
+        gBS->CloseEvent (SetBlkCntReq->Event);\r
+      }\r
+      FreePool (SetBlkCntReq);\r
+    }\r
+  } else {\r
+    //\r
+    // For synchronous operation, free request whatever the execution result is.\r
+    //\r
+    if (SetBlkCntReq != NULL) {\r
+      OldTpl = gBS->RaiseTPL (TPL_CALLBACK);\r
+      RemoveEntryList (&SetBlkCntReq->Link);\r
+      gBS->RestoreTPL (OldTpl);\r
+      FreePool (SetBlkCntReq);\r
+    }\r
+  }\r
+\r
+  return Status;\r
+}\r
+\r
+/**\r
+  Read blocks through security protocol cmds with the way of sync or async I/O request.\r
+\r
+  @param[in]  Partition                    A pointer to the EMMC_PARTITION instance.\r
+  @param[in]  SecurityProtocolId           The value of the "Security Protocol" parameter of\r
+                                           the security protocol command to be sent.\r
+  @param[in]  SecurityProtocolSpecificData The value of the "Security Protocol Specific" parameter\r
+                                           of the security protocol command to be sent.\r
+  @param[in]  PayloadBufferSize            Size in bytes of the payload data buffer.\r
+  @param[out] PayloadBuffer                A pointer to a destination buffer to store the security\r
+                                           protocol command specific payload data for the security\r
+                                           protocol command. The caller is responsible for having\r
+                                           either implicit or explicit ownership of the buffer.\r
+  @param[in]  IsRead                       Indicates it is a read or write operation.\r
+  @param[in]  Timeout                      The timeout value, in 100ns units.\r
+  @param[in]  Token                        A pointer to the token associated with the transaction.\r
+  @param[in]  IsEnd                        A boolean to show whether it's the last cmd in a series of cmds.\r
+                                           This parameter is only meaningful in async I/O request.\r
+\r
+  @retval EFI_SUCCESS                      The request is executed successfully.\r
+  @retval EFI_OUT_OF_RESOURCES             The request could not be executed due to a lack of resources.\r
+  @retval Others                           The request could not be executed successfully.\r
+\r
+**/\r
+EFI_STATUS\r
+EmmcProtocolInOut (\r
+  IN     EMMC_PARTITION            *Partition,\r
+  IN     UINT8                     SecurityProtocol,\r
+  IN     UINT16                    SecurityProtocolSpecificData,\r
+  IN     UINTN                     PayloadBufferSize,\r
+     OUT VOID                      *PayloadBuffer,\r
+  IN     BOOLEAN                   IsRead,\r
+  IN     UINT64                    Timeout,\r
+  IN     EFI_BLOCK_IO2_TOKEN       *Token,\r
+  IN     BOOLEAN                   IsEnd\r
+  )\r
+{\r
+  EFI_STATUS                    Status;\r
+  EMMC_DEVICE                   *Device;\r
+  EMMC_REQUEST                  *ProtocolReq;\r
+  EFI_SD_MMC_PASS_THRU_PROTOCOL *PassThru;\r
+  EFI_TPL                       OldTpl;\r
+\r
+  ProtocolReq = NULL;\r
+\r
+  Device   = Partition->Device;\r
+  PassThru = Device->Private->PassThru;\r
+\r
+  ProtocolReq = AllocateZeroPool (sizeof (EMMC_REQUEST));\r
+  if (ProtocolReq == NULL) {\r
+    Status = EFI_OUT_OF_RESOURCES;\r
+    goto Error;\r
+  }\r
+\r
+  ProtocolReq->Signature = EMMC_REQUEST_SIGNATURE;\r
+  OldTpl = gBS->RaiseTPL (TPL_CALLBACK);\r
+  InsertTailList (&Partition->Queue, &ProtocolReq->Link);\r
+  gBS->RestoreTPL (OldTpl);\r
+  ProtocolReq->Packet.SdMmcCmdBlk    = &ProtocolReq->SdMmcCmdBlk;\r
+  ProtocolReq->Packet.SdMmcStatusBlk = &ProtocolReq->SdMmcStatusBlk;\r
+\r
+  if (IsRead) {\r
+    ProtocolReq->Packet.InDataBuffer     = PayloadBuffer;\r
+    ProtocolReq->Packet.InTransferLength = (UINT32)PayloadBufferSize;\r
+\r
+    ProtocolReq->SdMmcCmdBlk.CommandIndex = EMMC_PROTOCOL_RD;\r
+    ProtocolReq->SdMmcCmdBlk.CommandType  = SdMmcCommandTypeAdtc;\r
+    ProtocolReq->SdMmcCmdBlk.ResponseType = SdMmcResponseTypeR1;\r
+  } else {\r
+    ProtocolReq->Packet.OutDataBuffer     = PayloadBuffer;\r
+    ProtocolReq->Packet.OutTransferLength = (UINT32)PayloadBufferSize;\r
+\r
+    ProtocolReq->SdMmcCmdBlk.CommandIndex = EMMC_PROTOCOL_WR;\r
+    ProtocolReq->SdMmcCmdBlk.CommandType  = SdMmcCommandTypeAdtc;\r
+    ProtocolReq->SdMmcCmdBlk.ResponseType = SdMmcResponseTypeR1;\r
+  }\r
+\r
+  ProtocolReq->SdMmcCmdBlk.CommandArgument = (SecurityProtocol << 8) | (SecurityProtocolSpecificData << 16);\r
+  //\r
+  // Convert to 1 microsecond unit.\r
+  //\r
+  ProtocolReq->Packet.Timeout = DivU64x32 (Timeout, 10) + 1;\r
+\r
+  ProtocolReq->IsEnd = IsEnd;\r
+  ProtocolReq->Token = Token;\r
+\r
+  if ((Token != NULL) && (Token->Event != NULL)) {\r
+    Status = gBS->CreateEvent (\r
+                    EVT_NOTIFY_SIGNAL,\r
+                    TPL_CALLBACK,\r
+                    AsyncIoCallback,\r
+                    ProtocolReq,\r
+                    &ProtocolReq->Event\r
+                    );\r
+    if (EFI_ERROR (Status)) {\r
+      goto Error;\r
+    }\r
+  } else {\r
+    ProtocolReq->Event = NULL;\r
+  }\r
+\r
+  Status = PassThru->PassThru (PassThru, Device->Slot, &ProtocolReq->Packet, ProtocolReq->Event);\r
+\r
+Error:\r
+  if ((Token != NULL) && (Token->Event != NULL)) {\r
+    //\r
+    // For asynchronous operation, only free request and event in error case.\r
+    // The request and event will be freed in asynchronous callback for success case.\r
+    //\r
+    if (EFI_ERROR (Status) && (ProtocolReq != NULL)) {\r
+      OldTpl = gBS->RaiseTPL (TPL_CALLBACK);\r
+      RemoveEntryList (&ProtocolReq->Link);\r
+      gBS->RestoreTPL (OldTpl);\r
+      if (ProtocolReq->Event != NULL) {\r
+        gBS->CloseEvent (ProtocolReq->Event);\r
+      }\r
+      FreePool (ProtocolReq);\r
+    }\r
+  } else {\r
+    //\r
+    // For synchronous operation, free request whatever the execution result is.\r
+    //\r
+    if (ProtocolReq != NULL) {\r
+      OldTpl = gBS->RaiseTPL (TPL_CALLBACK);\r
+      RemoveEntryList (&ProtocolReq->Link);\r
+      gBS->RestoreTPL (OldTpl);\r
+      FreePool (ProtocolReq);\r
+    }\r
+  }\r
+\r
+  return Status;\r
+}\r
+\r
+/**\r
+  Read/write multiple blocks through sync or async I/O request.\r
+\r
+  @param[in]  Partition         A pointer to the EMMC_PARTITION instance.\r
+  @param[in]  Lba               The starting logical block address to be read/written.\r
+                                The caller is responsible for reading/writing to only\r
+                                legitimate locations.\r
+  @param[in]  Buffer            A pointer to the destination/source buffer for the data.\r
+  @param[in]  BufferSize        Size of Buffer, must be a multiple of device block size.\r
+  @param[in]  IsRead            Indicates it is a read or write operation.\r
+  @param[in]  Token             A pointer to the token associated with the transaction.\r
+  @param[in]  IsEnd             A boolean to show whether it's the last cmd in a series of cmds.\r
+                                This parameter is only meaningful in async I/O request.\r
+\r
+  @retval EFI_SUCCESS           The request is executed successfully.\r
+  @retval EFI_OUT_OF_RESOURCES  The request could not be executed due to a lack of resources.\r
+  @retval Others                The request could not be executed successfully.\r
+\r
+**/\r
+EFI_STATUS\r
+EmmcRwMultiBlocks (\r
+  IN  EMMC_PARTITION            *Partition,\r
+  IN  EFI_LBA                   Lba,\r
+  IN  VOID                      *Buffer,\r
+  IN  UINTN                     BufferSize,\r
+  IN  BOOLEAN                   IsRead,\r
+  IN  EFI_BLOCK_IO2_TOKEN       *Token,\r
+  IN  BOOLEAN                   IsEnd\r
+  )\r
+{\r
+  EFI_STATUS                    Status;\r
+  EMMC_DEVICE                   *Device;\r
+  EMMC_REQUEST                  *RwMultiBlkReq;\r
+  EFI_SD_MMC_PASS_THRU_PROTOCOL *PassThru;\r
+  EFI_TPL                       OldTpl;\r
+\r
+  RwMultiBlkReq = NULL;\r
+\r
+  Device   = Partition->Device;\r
+  PassThru = Device->Private->PassThru;\r
+\r
+  RwMultiBlkReq = AllocateZeroPool (sizeof (EMMC_REQUEST));\r
+  if (RwMultiBlkReq == NULL) {\r
+    Status = EFI_OUT_OF_RESOURCES;\r
+    goto Error;\r
+  }\r
+\r
+  RwMultiBlkReq->Signature = EMMC_REQUEST_SIGNATURE;\r
+  OldTpl = gBS->RaiseTPL (TPL_CALLBACK);\r
+  InsertTailList (&Partition->Queue, &RwMultiBlkReq->Link);\r
+  gBS->RestoreTPL (OldTpl);\r
+  RwMultiBlkReq->Packet.SdMmcCmdBlk    = &RwMultiBlkReq->SdMmcCmdBlk;\r
+  RwMultiBlkReq->Packet.SdMmcStatusBlk = &RwMultiBlkReq->SdMmcStatusBlk;\r
+  //\r
+  // Calculate timeout value through the below formula.\r
+  // Timeout = (transfer size) / (2MB/s).\r
+  // Taking 2MB/s as divisor is because it's nearest to the eMMC lowest\r
+  // transfer speed (2.4MB/s).\r
+  // Refer to eMMC 5.0 spec section 6.9.1 for details.\r
+  //\r
+  RwMultiBlkReq->Packet.Timeout = (BufferSize / (2 * 1024 * 1024) + 1) * 1000 * 1000;\r
+\r
+  if (IsRead) {\r
+    RwMultiBlkReq->Packet.InDataBuffer     = Buffer;\r
+    RwMultiBlkReq->Packet.InTransferLength = (UINT32)BufferSize;\r
+\r
+    RwMultiBlkReq->SdMmcCmdBlk.CommandIndex = EMMC_READ_MULTIPLE_BLOCK;\r
+    RwMultiBlkReq->SdMmcCmdBlk.CommandType  = SdMmcCommandTypeAdtc;\r
+    RwMultiBlkReq->SdMmcCmdBlk.ResponseType = SdMmcResponseTypeR1;\r
+  } else {\r
+    RwMultiBlkReq->Packet.OutDataBuffer     = Buffer;\r
+    RwMultiBlkReq->Packet.OutTransferLength = (UINT32)BufferSize;\r
+\r
+    RwMultiBlkReq->SdMmcCmdBlk.CommandIndex = EMMC_WRITE_MULTIPLE_BLOCK;\r
+    RwMultiBlkReq->SdMmcCmdBlk.CommandType  = SdMmcCommandTypeAdtc;\r
+    RwMultiBlkReq->SdMmcCmdBlk.ResponseType = SdMmcResponseTypeR1;\r
+  }\r
+\r
+  if (Partition->Device->SectorAddressing) {\r
+    RwMultiBlkReq->SdMmcCmdBlk.CommandArgument = (UINT32)Lba;\r
+  } else {\r
+    RwMultiBlkReq->SdMmcCmdBlk.CommandArgument = (UINT32)MultU64x32 (Lba, Partition->BlockMedia.BlockSize);\r
+  }\r
+\r
+  RwMultiBlkReq->IsEnd = IsEnd;\r
+  RwMultiBlkReq->Token = Token;\r
+\r
+  if ((Token != NULL) && (Token->Event != NULL)) {\r
+    Status = gBS->CreateEvent (\r
+                    EVT_NOTIFY_SIGNAL,\r
+                    TPL_CALLBACK,\r
+                    AsyncIoCallback,\r
+                    RwMultiBlkReq,\r
+                    &RwMultiBlkReq->Event\r
+                    );\r
+    if (EFI_ERROR (Status)) {\r
+      goto Error;\r
+    }\r
+  } else {\r
+    RwMultiBlkReq->Event = NULL;\r
+  }\r
+\r
+  Status = PassThru->PassThru (PassThru, Device->Slot, &RwMultiBlkReq->Packet, RwMultiBlkReq->Event);\r
+\r
+Error:\r
+  if ((Token != NULL) && (Token->Event != NULL)) {\r
+    //\r
+    // For asynchronous operation, only free request and event in error case.\r
+    // The request and event will be freed in asynchronous callback for success case.\r
+    //\r
+    if (EFI_ERROR (Status) && (RwMultiBlkReq != NULL)) {\r
+      OldTpl = gBS->RaiseTPL (TPL_CALLBACK);\r
+      RemoveEntryList (&RwMultiBlkReq->Link);\r
+      gBS->RestoreTPL (OldTpl);\r
+      if (RwMultiBlkReq->Event != NULL) {\r
+        gBS->CloseEvent (RwMultiBlkReq->Event);\r
+      }\r
+      FreePool (RwMultiBlkReq);\r
+    }\r
+  } else {\r
+    //\r
+    // For synchronous operation, free request whatever the execution result is.\r
+    //\r
+    if (RwMultiBlkReq != NULL) {\r
+      OldTpl = gBS->RaiseTPL (TPL_CALLBACK);\r
+      RemoveEntryList (&RwMultiBlkReq->Link);\r
+      gBS->RestoreTPL (OldTpl);\r
+      FreePool (RwMultiBlkReq);\r
+    }\r
+  }\r
+\r
+  return Status;\r
+}\r
+\r
+/**\r
+  This function transfers data from/to EMMC device.\r
+\r
+  @param[in]       Partition    A pointer to the EMMC_PARTITION instance.\r
+  @param[in]       MediaId      The media ID that the read/write request is for.\r
+  @param[in]       Lba          The starting logical block address to be read/written.\r
+                                The caller is responsible for reading/writing to only\r
+                                legitimate locations.\r
+  @param[in, out]  Buffer       A pointer to the destination/source buffer for the data.\r
+  @param[in]       BufferSize   Size of Buffer, must be a multiple of device block size.\r
+  @param[in]       IsRead       Indicates it is a read or write operation.\r
+  @param[in, out]  Token        A pointer to the token associated with the transaction.\r
+\r
+  @retval EFI_SUCCESS           The data was read/written correctly to the device.\r
+  @retval EFI_WRITE_PROTECTED   The device can not be read/written to.\r
+  @retval EFI_DEVICE_ERROR      The device reported an error while performing the read/write.\r
+  @retval EFI_NO_MEDIA          There is no media in the device.\r
+  @retval EFI_MEDIA_CHNAGED     The MediaId does not matched the current device.\r
+  @retval EFI_BAD_BUFFER_SIZE   The Buffer was not a multiple of the block size of the device.\r
+  @retval EFI_INVALID_PARAMETER The read/write request contains LBAs that are not valid,\r
+                                or the buffer is not on proper alignment.\r
+\r
+**/\r
+EFI_STATUS\r
+EmmcReadWrite (\r
+  IN     EMMC_PARTITION                 *Partition,\r
+  IN     UINT32                         MediaId,\r
+  IN     EFI_LBA                        Lba,\r
+  IN OUT VOID                           *Buffer,\r
+  IN     UINTN                          BufferSize,\r
+  IN     BOOLEAN                        IsRead,\r
+  IN OUT EFI_BLOCK_IO2_TOKEN            *Token\r
+  )\r
+{\r
+  EFI_STATUS                            Status;\r
+  EMMC_DEVICE                           *Device;\r
+  EFI_BLOCK_IO_MEDIA                    *Media;\r
+  UINTN                                 BlockSize;\r
+  UINTN                                 BlockNum;\r
+  UINTN                                 IoAlign;\r
+  UINT8                                 PartitionConfig;\r
+  UINTN                                 Remaining;\r
+  UINT32                                MaxBlock;\r
+  BOOLEAN                               LastRw;\r
+\r
+  Status = EFI_SUCCESS;\r
+  Device = Partition->Device;\r
+  Media  = &Partition->BlockMedia;\r
+  LastRw = FALSE;\r
+\r
+  if (MediaId != Media->MediaId) {\r
+    return EFI_MEDIA_CHANGED;\r
+  }\r
+\r
+  if (!IsRead && Media->ReadOnly) {\r
+    return EFI_WRITE_PROTECTED;\r
+  }\r
+\r
+  //\r
+  // Check parameters.\r
+  //\r
+  if (Buffer == NULL) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  if (BufferSize == 0) {\r
+    if ((Token != NULL) && (Token->Event != NULL)) {\r
+      Token->TransactionStatus = EFI_SUCCESS;\r
+      gBS->SignalEvent (Token->Event);\r
+    }\r
+    return EFI_SUCCESS;\r
+  }\r
+\r
+  BlockSize = Media->BlockSize;\r
+  if ((BufferSize % BlockSize) != 0) {\r
+    return EFI_BAD_BUFFER_SIZE;\r
+  }\r
+\r
+  BlockNum  = BufferSize / BlockSize;\r
+  if ((Lba + BlockNum - 1) > Media->LastBlock) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  IoAlign = Media->IoAlign;\r
+  if (IoAlign > 0 && (((UINTN) Buffer & (IoAlign - 1)) != 0)) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  if ((Token != NULL) && (Token->Event != NULL)) {\r
+    Token->TransactionStatus = EFI_SUCCESS;\r
+  }\r
+  //\r
+  // Check if needs to switch partition access.\r
+  //\r
+  PartitionConfig = Device->ExtCsd.PartitionConfig;\r
+  if ((PartitionConfig & 0x7) != Partition->PartitionType) {\r
+    PartitionConfig &= (UINT8)~0x7;\r
+    PartitionConfig |= Partition->PartitionType;\r
+    Status = EmmcSetExtCsd (Partition, OFFSET_OF (EMMC_EXT_CSD, PartitionConfig), PartitionConfig, Token, FALSE);\r
+    if (EFI_ERROR (Status)) {\r
+      return Status;\r
+    }\r
+    Device->ExtCsd.PartitionConfig = PartitionConfig;\r
+  }\r
+  //\r
+  // Start to execute data transfer. The max block number in single cmd is 65535 blocks.\r
+  //\r
+  Remaining = BlockNum;\r
+  MaxBlock  = 0xFFFF;\r
+\r
+  while (Remaining > 0) {\r
+    if (Remaining <= MaxBlock) {\r
+      BlockNum = Remaining;\r
+      LastRw   = TRUE;\r
+    } else {\r
+      BlockNum = MaxBlock;\r
+    }\r
+    Status = EmmcSetBlkCount (Partition, (UINT16)BlockNum, Token, FALSE);\r
+    if (EFI_ERROR (Status)) {\r
+      return Status;\r
+    }\r
+\r
+    BufferSize = BlockNum * BlockSize;\r
+    Status = EmmcRwMultiBlocks (Partition, Lba, Buffer, BufferSize, IsRead, Token, LastRw);\r
+    if (EFI_ERROR (Status)) {\r
+      return Status;\r
+    }\r
+    DEBUG ((EFI_D_INFO, "Emmc%a(): Lba 0x%x BlkNo 0x%x Event %p with %r\n", IsRead ? "Read" : "Write", Lba, BlockNum, Token->Event, Status));\r
+\r
+    Lba   += BlockNum;\r
+    Buffer = (UINT8*)Buffer + BufferSize;\r
+    Remaining -= BlockNum;\r
+  }\r
+\r
+  return Status;\r
+}\r
+\r
+/**\r
+  Reset the Block Device.\r
+\r
+  @param  This                 Indicates a pointer to the calling context.\r
+  @param  ExtendedVerification Driver may perform diagnostics on reset.\r
+\r
+  @retval EFI_SUCCESS          The device was reset.\r
+  @retval EFI_DEVICE_ERROR     The device is not functioning properly and could\r
+                               not be reset.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+EmmcReset (\r
+  IN  EFI_BLOCK_IO_PROTOCOL     *This,\r
+  IN  BOOLEAN                   ExtendedVerification\r
+  )\r
+{\r
+  EFI_STATUS                    Status;\r
+  EMMC_PARTITION                *Partition;\r
+  EFI_SD_MMC_PASS_THRU_PROTOCOL *PassThru;\r
+\r
+  Partition = EMMC_PARTITION_DATA_FROM_BLKIO (This);\r
+\r
+  PassThru = Partition->Device->Private->PassThru;\r
+  Status   = PassThru->ResetDevice (PassThru, Partition->Device->Slot);\r
+  if (EFI_ERROR (Status)) {\r
+    Status = EFI_DEVICE_ERROR;\r
+  }\r
+\r
+  return Status;\r
+}\r
+\r
+/**\r
+  Read BufferSize bytes from Lba into Buffer.\r
+\r
+  @param  This       Indicates a pointer to the calling context.\r
+  @param  MediaId    Id of the media, changes every time the media is replaced.\r
+  @param  Lba        The starting Logical Block Address to read from\r
+  @param  BufferSize Size of Buffer, must be a multiple of device block size.\r
+  @param  Buffer     A pointer to the destination buffer for the data. The caller is\r
+                     responsible for either having implicit or explicit ownership of the buffer.\r
+\r
+  @retval EFI_SUCCESS           The data was read correctly from the device.\r
+  @retval EFI_DEVICE_ERROR      The device reported an error while performing the read.\r
+  @retval EFI_NO_MEDIA          There is no media in the device.\r
+  @retval EFI_MEDIA_CHANGED     The MediaId does not matched the current device.\r
+  @retval EFI_BAD_BUFFER_SIZE   The Buffer was not a multiple of the block size of the device.\r
+  @retval EFI_INVALID_PARAMETER The read request contains LBAs that are not valid,\r
+                                or the buffer is not on proper alignment.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+EmmcReadBlocks (\r
+  IN     EFI_BLOCK_IO_PROTOCOL  *This,\r
+  IN     UINT32                 MediaId,\r
+  IN     EFI_LBA                Lba,\r
+  IN     UINTN                  BufferSize,\r
+     OUT VOID                   *Buffer\r
+  )\r
+{\r
+  EFI_STATUS             Status;\r
+  EMMC_PARTITION         *Partition;\r
+\r
+  Partition = EMMC_PARTITION_DATA_FROM_BLKIO (This);\r
+\r
+  Status = EmmcReadWrite (Partition, MediaId, Lba, Buffer, BufferSize, TRUE, NULL);\r
+  return Status;\r
+}\r
+\r
+/**\r
+  Write BufferSize bytes from Lba into Buffer.\r
+\r
+  @param  This       Indicates a pointer to the calling context.\r
+  @param  MediaId    The media ID that the write request is for.\r
+  @param  Lba        The starting logical block address to be written. The caller is\r
+                     responsible for writing to only legitimate locations.\r
+  @param  BufferSize Size of Buffer, must be a multiple of device block size.\r
+  @param  Buffer     A pointer to the source buffer for the data.\r
+\r
+  @retval EFI_SUCCESS           The data was written correctly to the device.\r
+  @retval EFI_WRITE_PROTECTED   The device can not be written to.\r
+  @retval EFI_DEVICE_ERROR      The device reported an error while performing the write.\r
+  @retval EFI_NO_MEDIA          There is no media in the device.\r
+  @retval EFI_MEDIA_CHNAGED     The MediaId does not matched the current device.\r
+  @retval EFI_BAD_BUFFER_SIZE   The Buffer was not a multiple of the block size of the device.\r
+  @retval EFI_INVALID_PARAMETER The write request contains LBAs that are not valid,\r
+                                or the buffer is not on proper alignment.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+EmmcWriteBlocks (\r
+  IN  EFI_BLOCK_IO_PROTOCOL   *This,\r
+  IN  UINT32                  MediaId,\r
+  IN  EFI_LBA                 Lba,\r
+  IN  UINTN                   BufferSize,\r
+  IN  VOID                    *Buffer\r
+  )\r
+{\r
+  EFI_STATUS             Status;\r
+  EMMC_PARTITION         *Partition;\r
+\r
+  Partition = EMMC_PARTITION_DATA_FROM_BLKIO (This);\r
+\r
+  Status = EmmcReadWrite (Partition, MediaId, Lba, Buffer, BufferSize, FALSE, NULL);\r
+  return Status;\r
+}\r
+\r
+/**\r
+  Flush the Block Device.\r
+\r
+  @param  This              Indicates a pointer to the calling context.\r
+\r
+  @retval EFI_SUCCESS       All outstanding data was written to the device\r
+  @retval EFI_DEVICE_ERROR  The device reported an error while writing back the data\r
+  @retval EFI_NO_MEDIA      There is no media in the device.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+EmmcFlushBlocks (\r
+  IN  EFI_BLOCK_IO_PROTOCOL   *This\r
+  )\r
+{\r
+  //\r
+  // return directly\r
+  //\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+  Reset the Block Device.\r
+\r
+  @param[in]  This                 Indicates a pointer to the calling context.\r
+  @param[in]  ExtendedVerification Driver may perform diagnostics on reset.\r
+\r
+  @retval EFI_SUCCESS              The device was reset.\r
+  @retval EFI_DEVICE_ERROR         The device is not functioning properly and could\r
+                                   not be reset.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+EmmcResetEx (\r
+  IN  EFI_BLOCK_IO2_PROTOCOL  *This,\r
+  IN  BOOLEAN                 ExtendedVerification\r
+  )\r
+{\r
+  EMMC_PARTITION              *Partition;\r
+  LIST_ENTRY                  *Link;\r
+  LIST_ENTRY                  *NextLink;\r
+  EMMC_REQUEST                *Request;\r
+  EFI_TPL                     OldTpl;\r
+\r
+  Partition = EMMC_PARTITION_DATA_FROM_BLKIO2 (This);\r
+\r
+  OldTpl = gBS->RaiseTPL (TPL_CALLBACK);\r
+  for (Link = GetFirstNode (&Partition->Queue);\r
+       !IsNull (&Partition->Queue, Link);\r
+       Link = NextLink) {\r
+    NextLink = GetNextNode (&Partition->Queue, Link);\r
+    RemoveEntryList (Link);\r
+\r
+    Request = EMMC_REQUEST_FROM_LINK (Link);\r
+\r
+    gBS->CloseEvent (Request->Event);\r
+    Request->Token->TransactionStatus = EFI_ABORTED;\r
+\r
+    if (Request->IsEnd) {\r
+      gBS->SignalEvent (Request->Token->Event);\r
+    }\r
+\r
+    FreePool (Request);\r
+  }\r
+  gBS->RestoreTPL (OldTpl);\r
+\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+  Read BufferSize bytes from Lba into Buffer.\r
+\r
+  @param[in]       This         Indicates a pointer to the calling context.\r
+  @param[in]       MediaId      Id of the media, changes every time the media is replaced.\r
+  @param[in]       Lba          The starting Logical Block Address to read from.\r
+  @param[in, out]  Token        A pointer to the token associated with the transaction.\r
+  @param[in]       BufferSize   Size of Buffer, must be a multiple of device block size.\r
+  @param[out]      Buffer       A pointer to the destination buffer for the data. The caller is\r
+                                responsible for either having implicit or explicit ownership of the buffer.\r
+\r
+  @retval EFI_SUCCESS           The read request was queued if Event is not NULL.\r
+                                The data was read correctly from the device if\r
+                                the Event is NULL.\r
+  @retval EFI_DEVICE_ERROR      The device reported an error while performing\r
+                                the read.\r
+  @retval EFI_NO_MEDIA          There is no media in the device.\r
+  @retval EFI_MEDIA_CHANGED     The MediaId is not for the current media.\r
+  @retval EFI_BAD_BUFFER_SIZE   The BufferSize parameter is not a multiple of the\r
+                                intrinsic block size of the device.\r
+  @retval EFI_INVALID_PARAMETER The read request contains LBAs that are not valid,\r
+                                or the buffer is not on proper alignment.\r
+  @retval EFI_OUT_OF_RESOURCES  The request could not be completed due to a lack\r
+                                of resources.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+EmmcReadBlocksEx (\r
+  IN     EFI_BLOCK_IO2_PROTOCOL *This,\r
+  IN     UINT32                 MediaId,\r
+  IN     EFI_LBA                Lba,\r
+  IN OUT EFI_BLOCK_IO2_TOKEN    *Token,\r
+  IN     UINTN                  BufferSize,\r
+     OUT VOID                   *Buffer\r
+  )\r
+{\r
+  EFI_STATUS             Status;\r
+  EMMC_PARTITION         *Partition;\r
+\r
+  Partition = EMMC_PARTITION_DATA_FROM_BLKIO2 (This);\r
+\r
+  Status = EmmcReadWrite (Partition, MediaId, Lba, Buffer, BufferSize, TRUE, Token);\r
+  return Status;\r
+}\r
+\r
+/**\r
+  Write BufferSize bytes from Lba into Buffer.\r
+\r
+  @param[in]       This         Indicates a pointer to the calling context.\r
+  @param[in]       MediaId      The media ID that the write request is for.\r
+  @param[in]       Lba          The starting logical block address to be written. The\r
+                                caller is responsible for writing to only legitimate\r
+                                locations.\r
+  @param[in, out]  Token        A pointer to the token associated with the transaction.\r
+  @param[in]       BufferSize   Size of Buffer, must be a multiple of device block size.\r
+  @param[in]       Buffer       A pointer to the source buffer for the data.\r
+\r
+  @retval EFI_SUCCESS           The data was written correctly to the device.\r
+  @retval EFI_WRITE_PROTECTED   The device can not be written to.\r
+  @retval EFI_DEVICE_ERROR      The device reported an error while performing the write.\r
+  @retval EFI_NO_MEDIA          There is no media in the device.\r
+  @retval EFI_MEDIA_CHNAGED     The MediaId does not matched the current device.\r
+  @retval EFI_BAD_BUFFER_SIZE   The Buffer was not a multiple of the block size of the device.\r
+  @retval EFI_INVALID_PARAMETER The write request contains LBAs that are not valid,\r
+                                or the buffer is not on proper alignment.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+EmmcWriteBlocksEx (\r
+  IN     EFI_BLOCK_IO2_PROTOCOL *This,\r
+  IN     UINT32                 MediaId,\r
+  IN     EFI_LBA                Lba,\r
+  IN OUT EFI_BLOCK_IO2_TOKEN    *Token,\r
+  IN     UINTN                  BufferSize,\r
+  IN     VOID                   *Buffer\r
+  )\r
+{\r
+  EFI_STATUS             Status;\r
+  EMMC_PARTITION         *Partition;\r
+\r
+  Partition = EMMC_PARTITION_DATA_FROM_BLKIO2 (This);\r
+\r
+  Status = EmmcReadWrite (Partition, MediaId, Lba, Buffer, BufferSize, FALSE, Token);\r
+  return Status;\r
+}\r
+\r
+/**\r
+  Flush the Block Device.\r
+\r
+  @param[in]       This     Indicates a pointer to the calling context.\r
+  @param[in, out]  Token    A pointer to the token associated with the transaction.\r
+\r
+  @retval EFI_SUCCESS       All outstanding data was written to the device\r
+  @retval EFI_DEVICE_ERROR  The device reported an error while writing back the data\r
+  @retval EFI_NO_MEDIA      There is no media in the device.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+EmmcFlushBlocksEx (\r
+  IN     EFI_BLOCK_IO2_PROTOCOL  *This,\r
+  IN OUT EFI_BLOCK_IO2_TOKEN     *Token\r
+  )\r
+{\r
+  //\r
+  // Signal event and return directly.\r
+  //\r
+  if (Token != NULL && Token->Event != NULL) {\r
+    Token->TransactionStatus = EFI_SUCCESS;\r
+    gBS->SignalEvent (Token->Event);\r
+  }\r
+\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+  Send a security protocol command to a device that receives data and/or the result\r
+  of one or more commands sent by SendData.\r
+\r
+  The ReceiveData function sends a security protocol command to the given MediaId.\r
+  The security protocol command sent is defined by SecurityProtocolId and contains\r
+  the security protocol specific data SecurityProtocolSpecificData. The function\r
+  returns the data from the security protocol command in PayloadBuffer.\r
+\r
+  For devices supporting the SCSI command set, the security protocol command is sent\r
+  using the SECURITY PROTOCOL IN command defined in SPC-4.\r
+\r
+  For devices supporting the ATA command set, the security protocol command is sent\r
+  using one of the TRUSTED RECEIVE commands defined in ATA8-ACS if PayloadBufferSize\r
+  is non-zero.\r
+\r
+  If the PayloadBufferSize is zero, the security protocol command is sent using the\r
+  Trusted Non-Data command defined in ATA8-ACS.\r
+\r
+  If PayloadBufferSize is too small to store the available data from the security\r
+  protocol command, the function shall copy PayloadBufferSize bytes into the\r
+  PayloadBuffer and return EFI_WARN_BUFFER_TOO_SMALL.\r
+\r
+  If PayloadBuffer or PayloadTransferSize is NULL and PayloadBufferSize is non-zero,\r
+  the function shall return EFI_INVALID_PARAMETER.\r
+\r
+  If the given MediaId does not support security protocol commands, the function shall\r
+  return EFI_UNSUPPORTED. If there is no media in the device, the function returns\r
+  EFI_NO_MEDIA. If the MediaId is not the ID for the current media in the device,\r
+  the function returns EFI_MEDIA_CHANGED.\r
+\r
+  If the security protocol fails to complete within the Timeout period, the function\r
+  shall return EFI_TIMEOUT.\r
+\r
+  If the security protocol command completes without an error, the function shall\r
+  return EFI_SUCCESS. If the security protocol command completes with an error, the\r
+  function shall return EFI_DEVICE_ERROR.\r
+\r
+  @param[in]  This                         Indicates a pointer to the calling context.\r
+  @param[in]  MediaId                      ID of the medium to receive data from.\r
+  @param[in]  Timeout                      The timeout, in 100ns units, to use for the execution\r
+                                           of the security protocol command. A Timeout value of 0\r
+                                           means that this function will wait indefinitely for the\r
+                                           security protocol command to execute. If Timeout is greater\r
+                                           than zero, then this function will return EFI_TIMEOUT\r
+                                           if the time required to execute the receive data command\r
+                                           is greater than Timeout.\r
+  @param[in]  SecurityProtocolId           The value of the "Security Protocol" parameter of\r
+                                           the security protocol command to be sent.\r
+  @param[in]  SecurityProtocolSpecificData The value of the "Security Protocol Specific" parameter\r
+                                           of the security protocol command to be sent.\r
+  @param[in]  PayloadBufferSize            Size in bytes of the payload data buffer.\r
+  @param[out] PayloadBuffer                A pointer to a destination buffer to store the security\r
+                                           protocol command specific payload data for the security\r
+                                           protocol command. The caller is responsible for having\r
+                                           either implicit or explicit ownership of the buffer.\r
+  @param[out] PayloadTransferSize          A pointer to a buffer to store the size in bytes of the\r
+                                           data written to the payload data buffer.\r
+  @param[in]  IsRead                       Indicates it is a read or write operation.\r
+\r
+  @retval EFI_SUCCESS                  The security protocol command completed successfully.\r
+  @retval EFI_WARN_BUFFER_TOO_SMALL    The PayloadBufferSize was too small to store the available\r
+                                       data from the device. The PayloadBuffer contains the truncated data.\r
+  @retval EFI_UNSUPPORTED              The given MediaId does not support security protocol commands.\r
+  @retval EFI_DEVICE_ERROR             The security protocol command completed with an error.\r
+  @retval EFI_NO_MEDIA                 There is no media in the device.\r
+  @retval EFI_MEDIA_CHANGED            The MediaId is not for the current media.\r
+  @retval EFI_INVALID_PARAMETER        The PayloadBuffer or PayloadTransferSize is NULL and\r
+                                       PayloadBufferSize is non-zero.\r
+  @retval EFI_TIMEOUT                  A timeout occurred while waiting for the security\r
+                                       protocol command to execute.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+EmmcSecurityProtocolInOut (\r
+  IN     EFI_STORAGE_SECURITY_COMMAND_PROTOCOL    *This,\r
+  IN     UINT32                                   MediaId,\r
+  IN     UINT64                                   Timeout,\r
+  IN     UINT8                                    SecurityProtocolId,\r
+  IN     UINT16                                   SecurityProtocolSpecificData,\r
+  IN     UINTN                                    PayloadBufferSize,\r
+     OUT VOID                                     *PayloadBuffer,\r
+     OUT UINTN                                    *PayloadTransferSize,\r
+  IN     BOOLEAN                                  IsRead\r
+  )\r
+{\r
+  EFI_STATUS                       Status;\r
+  EMMC_PARTITION                   *Partition;\r
+  EMMC_DEVICE                      *Device;\r
+  EFI_BLOCK_IO_MEDIA               *Media;\r
+  UINTN                            BlockSize;\r
+  UINTN                            BlockNum;\r
+  UINTN                            IoAlign;\r
+  UINTN                            Remaining;\r
+  UINT32                           MaxBlock;\r
+  UINT8                            PartitionConfig;\r
+\r
+  Status    = EFI_SUCCESS;\r
+  Partition = EMMC_PARTITION_DATA_FROM_SSP (This);\r
+  Device    = Partition->Device;\r
+  Media     = &Partition->BlockMedia;\r
+\r
+  if (PayloadTransferSize != NULL) {\r
+    *PayloadTransferSize = 0;\r
+  }\r
+\r
+  if ((PayloadBuffer == NULL) && (PayloadBufferSize != 0)) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  if (MediaId != Media->MediaId) {\r
+    return EFI_MEDIA_CHANGED;\r
+  }\r
+\r
+  if (PayloadBufferSize == 0) {\r
+    return EFI_SUCCESS;\r
+  }\r
+\r
+  BlockSize = Media->BlockSize;\r
+  if ((PayloadBufferSize % BlockSize) != 0) {\r
+    return EFI_BAD_BUFFER_SIZE;\r
+  }\r
+\r
+  BlockNum  = PayloadBufferSize / BlockSize;\r
+\r
+  IoAlign = Media->IoAlign;\r
+  if (IoAlign > 0 && (((UINTN) PayloadBuffer & (IoAlign - 1)) != 0)) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  //\r
+  // Security protocol interface is synchronous transfer.\r
+  // Waiting for async I/O list to be empty before any operation.\r
+  //\r
+  while (!IsListEmpty (&Partition->Queue));\r
+\r
+  //\r
+  // Check if needs to switch partition access.\r
+  //\r
+  PartitionConfig = Device->ExtCsd.PartitionConfig;\r
+  if ((PartitionConfig & 0x7) != Partition->PartitionType) {\r
+    PartitionConfig &= (UINT8)~0x7;\r
+    PartitionConfig |= Partition->PartitionType;\r
+    Status = EmmcSetExtCsd (Partition, OFFSET_OF (EMMC_EXT_CSD, PartitionConfig), PartitionConfig, NULL, FALSE);\r
+    if (EFI_ERROR (Status)) {\r
+      return Status;\r
+    }\r
+    Device->ExtCsd.PartitionConfig = PartitionConfig;\r
+  }\r
+  //\r
+  // Start to execute data transfer. The max block number in single cmd is 65535 blocks.\r
+  //\r
+  Remaining = BlockNum;\r
+  MaxBlock  = 0xFFFF;\r
+\r
+  while (Remaining > 0) {\r
+    if (Remaining <= MaxBlock) {\r
+      BlockNum = Remaining;\r
+    } else {\r
+      BlockNum = MaxBlock;\r
+    }\r
+\r
+    Status = EmmcSetBlkCount (Partition, (UINT16)BlockNum, NULL, FALSE);\r
+    if (EFI_ERROR (Status)) {\r
+      return Status;\r
+    }\r
+\r
+    PayloadBufferSize = BlockNum * BlockSize;\r
+    Status = EmmcProtocolInOut (Partition, SecurityProtocolId, SecurityProtocolSpecificData, PayloadBufferSize, PayloadBuffer, IsRead, Timeout, NULL, FALSE);\r
+    if (EFI_ERROR (Status)) {\r
+      return Status;\r
+    }\r
+\r
+    PayloadBuffer = (UINT8*)PayloadBuffer + PayloadBufferSize;\r
+    Remaining    -= BlockNum;\r
+    if (PayloadTransferSize != NULL) {\r
+      *PayloadTransferSize += PayloadBufferSize;\r
+    }\r
+  }\r
+\r
+  return Status;\r
+}\r
+\r
+/**\r
+  Send a security protocol command to a device that receives data and/or the result\r
+  of one or more commands sent by SendData.\r
+\r
+  The ReceiveData function sends a security protocol command to the given MediaId.\r
+  The security protocol command sent is defined by SecurityProtocolId and contains\r
+  the security protocol specific data SecurityProtocolSpecificData. The function\r
+  returns the data from the security protocol command in PayloadBuffer.\r
+\r
+  For devices supporting the SCSI command set, the security protocol command is sent\r
+  using the SECURITY PROTOCOL IN command defined in SPC-4.\r
+\r
+  For devices supporting the ATA command set, the security protocol command is sent\r
+  using one of the TRUSTED RECEIVE commands defined in ATA8-ACS if PayloadBufferSize\r
+  is non-zero.\r
+\r
+  If the PayloadBufferSize is zero, the security protocol command is sent using the\r
+  Trusted Non-Data command defined in ATA8-ACS.\r
+\r
+  If PayloadBufferSize is too small to store the available data from the security\r
+  protocol command, the function shall copy PayloadBufferSize bytes into the\r
+  PayloadBuffer and return EFI_WARN_BUFFER_TOO_SMALL.\r
+\r
+  If PayloadBuffer or PayloadTransferSize is NULL and PayloadBufferSize is non-zero,\r
+  the function shall return EFI_INVALID_PARAMETER.\r
+\r
+  If the given MediaId does not support security protocol commands, the function shall\r
+  return EFI_UNSUPPORTED. If there is no media in the device, the function returns\r
+  EFI_NO_MEDIA. If the MediaId is not the ID for the current media in the device,\r
+  the function returns EFI_MEDIA_CHANGED.\r
+\r
+  If the security protocol fails to complete within the Timeout period, the function\r
+  shall return EFI_TIMEOUT.\r
+\r
+  If the security protocol command completes without an error, the function shall\r
+  return EFI_SUCCESS. If the security protocol command completes with an error, the\r
+  function shall return EFI_DEVICE_ERROR.\r
+\r
+  @param  This                         Indicates a pointer to the calling context.\r
+  @param  MediaId                      ID of the medium to receive data from.\r
+  @param  Timeout                      The timeout, in 100ns units, to use for the execution\r
+                                       of the security protocol command. A Timeout value of 0\r
+                                       means that this function will wait indefinitely for the\r
+                                       security protocol command to execute. If Timeout is greater\r
+                                       than zero, then this function will return EFI_TIMEOUT\r
+                                       if the time required to execute the receive data command\r
+                                       is greater than Timeout.\r
+  @param  SecurityProtocolId           The value of the "Security Protocol" parameter of\r
+                                       the security protocol command to be sent.\r
+  @param  SecurityProtocolSpecificData The value of the "Security Protocol Specific" parameter\r
+                                       of the security protocol command to be sent.\r
+  @param  PayloadBufferSize            Size in bytes of the payload data buffer.\r
+  @param  PayloadBuffer                A pointer to a destination buffer to store the security\r
+                                       protocol command specific payload data for the security\r
+                                       protocol command. The caller is responsible for having\r
+                                       either implicit or explicit ownership of the buffer.\r
+  @param  PayloadTransferSize          A pointer to a buffer to store the size in bytes of the\r
+                                       data written to the payload data buffer.\r
+\r
+  @retval EFI_SUCCESS                  The security protocol command completed successfully.\r
+  @retval EFI_WARN_BUFFER_TOO_SMALL    The PayloadBufferSize was too small to store the available\r
+                                       data from the device. The PayloadBuffer contains the truncated data.\r
+  @retval EFI_UNSUPPORTED              The given MediaId does not support security protocol commands.\r
+  @retval EFI_DEVICE_ERROR             The security protocol command completed with an error.\r
+  @retval EFI_NO_MEDIA                 There is no media in the device.\r
+  @retval EFI_MEDIA_CHANGED            The MediaId is not for the current media.\r
+  @retval EFI_INVALID_PARAMETER        The PayloadBuffer or PayloadTransferSize is NULL and\r
+                                       PayloadBufferSize is non-zero.\r
+  @retval EFI_TIMEOUT                  A timeout occurred while waiting for the security\r
+                                       protocol command to execute.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+EmmcSecurityProtocolIn (\r
+  IN EFI_STORAGE_SECURITY_COMMAND_PROTOCOL    *This,\r
+  IN UINT32                                   MediaId,\r
+  IN UINT64                                   Timeout,\r
+  IN UINT8                                    SecurityProtocolId,\r
+  IN UINT16                                   SecurityProtocolSpecificData,\r
+  IN UINTN                                    PayloadBufferSize,\r
+  OUT VOID                                    *PayloadBuffer,\r
+  OUT UINTN                                   *PayloadTransferSize\r
+  )\r
+{\r
+  EFI_STATUS                  Status;\r
+\r
+  if ((PayloadTransferSize == NULL) && PayloadBufferSize != 0) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  Status = EmmcSecurityProtocolInOut (\r
+             This,\r
+             MediaId,\r
+             Timeout,\r
+             SecurityProtocolId,\r
+             SecurityProtocolSpecificData,\r
+             PayloadBufferSize,\r
+             PayloadBuffer,\r
+             PayloadTransferSize,\r
+             TRUE\r
+             );\r
+\r
+  return Status;\r
+}\r
+\r
+/**\r
+  Send a security protocol command to a device.\r
+\r
+  The SendData function sends a security protocol command containing the payload\r
+  PayloadBuffer to the given MediaId. The security protocol command sent is\r
+  defined by SecurityProtocolId and contains the security protocol specific data\r
+  SecurityProtocolSpecificData. If the underlying protocol command requires a\r
+  specific padding for the command payload, the SendData function shall add padding\r
+  bytes to the command payload to satisfy the padding requirements.\r
+\r
+  For devices supporting the SCSI command set, the security protocol command is sent\r
+  using the SECURITY PROTOCOL OUT command defined in SPC-4.\r
+\r
+  For devices supporting the ATA command set, the security protocol command is sent\r
+  using one of the TRUSTED SEND commands defined in ATA8-ACS if PayloadBufferSize\r
+  is non-zero. If the PayloadBufferSize is zero, the security protocol command is\r
+  sent using the Trusted Non-Data command defined in ATA8-ACS.\r
+\r
+  If PayloadBuffer is NULL and PayloadBufferSize is non-zero, the function shall\r
+  return EFI_INVALID_PARAMETER.\r
+\r
+  If the given MediaId does not support security protocol commands, the function\r
+  shall return EFI_UNSUPPORTED. If there is no media in the device, the function\r
+  returns EFI_NO_MEDIA. If the MediaId is not the ID for the current media in the\r
+  device, the function returns EFI_MEDIA_CHANGED.\r
+\r
+  If the security protocol fails to complete within the Timeout period, the function\r
+  shall return EFI_TIMEOUT.\r
+\r
+  If the security protocol command completes without an error, the function shall return\r
+  EFI_SUCCESS. If the security protocol command completes with an error, the function\r
+  shall return EFI_DEVICE_ERROR.\r
+\r
+  @param  This                         Indicates a pointer to the calling context.\r
+  @param  MediaId                      ID of the medium to receive data from.\r
+  @param  Timeout                      The timeout, in 100ns units, to use for the execution\r
+                                       of the security protocol command. A Timeout value of 0\r
+                                       means that this function will wait indefinitely for the\r
+                                       security protocol command to execute. If Timeout is greater\r
+                                       than zero, then this function will return EFI_TIMEOUT\r
+                                       if the time required to execute the receive data command\r
+                                       is greater than Timeout.\r
+  @param  SecurityProtocolId           The value of the "Security Protocol" parameter of\r
+                                       the security protocol command to be sent.\r
+  @param  SecurityProtocolSpecificData The value of the "Security Protocol Specific" parameter\r
+                                       of the security protocol command to be sent.\r
+  @param  PayloadBufferSize            Size in bytes of the payload data buffer.\r
+  @param  PayloadBuffer                A pointer to a destination buffer to store the security\r
+                                       protocol command specific payload data for the security\r
+                                       protocol command.\r
+\r
+  @retval EFI_SUCCESS                  The security protocol command completed successfully.\r
+  @retval EFI_UNSUPPORTED              The given MediaId does not support security protocol commands.\r
+  @retval EFI_DEVICE_ERROR             The security protocol command completed with an error.\r
+  @retval EFI_NO_MEDIA                 There is no media in the device.\r
+  @retval EFI_MEDIA_CHANGED            The MediaId is not for the current media.\r
+  @retval EFI_INVALID_PARAMETER        The PayloadBuffer is NULL and PayloadBufferSize is non-zero.\r
+  @retval EFI_TIMEOUT                  A timeout occurred while waiting for the security\r
+                                       protocol command to execute.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+EmmcSecurityProtocolOut (\r
+  IN EFI_STORAGE_SECURITY_COMMAND_PROTOCOL    *This,\r
+  IN UINT32                                   MediaId,\r
+  IN UINT64                                   Timeout,\r
+  IN UINT8                                    SecurityProtocolId,\r
+  IN UINT16                                   SecurityProtocolSpecificData,\r
+  IN UINTN                                    PayloadBufferSize,\r
+  IN VOID                                     *PayloadBuffer\r
+  )\r
+{\r
+  EFI_STATUS          Status;\r
+\r
+  Status = EmmcSecurityProtocolInOut (\r
+             This,\r
+             MediaId,\r
+             Timeout,\r
+             SecurityProtocolId,\r
+             SecurityProtocolSpecificData,\r
+             PayloadBufferSize,\r
+             PayloadBuffer,\r
+             NULL,\r
+             FALSE\r
+             );\r
+\r
+  return Status;\r
+}\r
+\r
diff --git a/MdeModulePkg/Bus/Sd/EmmcDxe/EmmcBlockIo.h b/MdeModulePkg/Bus/Sd/EmmcDxe/EmmcBlockIo.h
new file mode 100644 (file)
index 0000000..f0e1312
--- /dev/null
@@ -0,0 +1,466 @@
+/** @file\r
+  Header file for EmmcDxe Driver.\r
+\r
+  This file defines common data structures, macro definitions and some module\r
+  internal function header files.\r
+\r
+  Copyright (c) 2015, Intel Corporation. All rights reserved.<BR>\r
+  This program and the accompanying materials\r
+  are licensed and made available under the terms and conditions of the BSD License\r
+  which accompanies this distribution.  The full text of the license may be found at\r
+  http://opensource.org/licenses/bsd-license.php\r
+\r
+  THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+  WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+\r
+**/\r
+\r
+#ifndef _EMMC_BLOCK_IO_H_\r
+#define _EMMC_BLOCK_IO_H_\r
+\r
+/**\r
+  Reset the Block Device.\r
+\r
+  @param  This                 Indicates a pointer to the calling context.\r
+  @param  ExtendedVerification Driver may perform diagnostics on reset.\r
+\r
+  @retval EFI_SUCCESS          The device was reset.\r
+  @retval EFI_DEVICE_ERROR     The device is not functioning properly and could\r
+                               not be reset.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+EmmcReset (\r
+  IN  EFI_BLOCK_IO_PROTOCOL   *This,\r
+  IN  BOOLEAN                 ExtendedVerification\r
+  );\r
+\r
+/**\r
+  Read BufferSize bytes from Lba into Buffer.\r
+\r
+  @param  This       Indicates a pointer to the calling context.\r
+  @param  MediaId    Id of the media, changes every time the media is replaced.\r
+  @param  Lba        The starting Logical Block Address to read from\r
+  @param  BufferSize Size of Buffer, must be a multiple of device block size.\r
+  @param  Buffer     A pointer to the destination buffer for the data. The caller is\r
+                     responsible for either having implicit or explicit ownership of the buffer.\r
+\r
+  @retval EFI_SUCCESS           The data was read correctly from the device.\r
+  @retval EFI_DEVICE_ERROR      The device reported an error while performing the read.\r
+  @retval EFI_NO_MEDIA          There is no media in the device.\r
+  @retval EFI_MEDIA_CHANGED     The MediaId does not matched the current device.\r
+  @retval EFI_BAD_BUFFER_SIZE   The Buffer was not a multiple of the block size of the device.\r
+  @retval EFI_INVALID_PARAMETER The read request contains LBAs that are not valid,\r
+                                or the buffer is not on proper alignment.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+EmmcReadBlocks (\r
+  IN     EFI_BLOCK_IO_PROTOCOL  *This,\r
+  IN     UINT32                 MediaId,\r
+  IN     EFI_LBA                Lba,\r
+  IN     UINTN                  BufferSize,\r
+     OUT VOID                   *Buffer\r
+  );\r
+\r
+/**\r
+  Write BufferSize bytes from Lba into Buffer.\r
+\r
+  @param  This       Indicates a pointer to the calling context.\r
+  @param  MediaId    The media ID that the write request is for.\r
+  @param  Lba        The starting logical block address to be written. The caller is\r
+                     responsible for writing to only legitimate locations.\r
+  @param  BufferSize Size of Buffer, must be a multiple of device block size.\r
+  @param  Buffer     A pointer to the source buffer for the data.\r
+\r
+  @retval EFI_SUCCESS           The data was written correctly to the device.\r
+  @retval EFI_WRITE_PROTECTED   The device can not be written to.\r
+  @retval EFI_DEVICE_ERROR      The device reported an error while performing the write.\r
+  @retval EFI_NO_MEDIA          There is no media in the device.\r
+  @retval EFI_MEDIA_CHNAGED     The MediaId does not matched the current device.\r
+  @retval EFI_BAD_BUFFER_SIZE   The Buffer was not a multiple of the block size of the device.\r
+  @retval EFI_INVALID_PARAMETER The write request contains LBAs that are not valid,\r
+                                or the buffer is not on proper alignment.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+EmmcWriteBlocks (\r
+  IN  EFI_BLOCK_IO_PROTOCOL   *This,\r
+  IN  UINT32                  MediaId,\r
+  IN  EFI_LBA                 Lba,\r
+  IN  UINTN                   BufferSize,\r
+  IN  VOID                    *Buffer\r
+  );\r
+\r
+/**\r
+  Flush the Block Device.\r
+\r
+  @param  This              Indicates a pointer to the calling context.\r
+\r
+  @retval EFI_SUCCESS       All outstanding data was written to the device\r
+  @retval EFI_DEVICE_ERROR  The device reported an error while writing back the data\r
+  @retval EFI_NO_MEDIA      There is no media in the device.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+EmmcFlushBlocks (\r
+  IN  EFI_BLOCK_IO_PROTOCOL   *This\r
+  );\r
+\r
+/**\r
+  Reset the Block Device.\r
+\r
+  @param[in]  This                 Indicates a pointer to the calling context.\r
+  @param[in]  ExtendedVerification Driver may perform diagnostics on reset.\r
+\r
+  @retval EFI_SUCCESS              The device was reset.\r
+  @retval EFI_DEVICE_ERROR         The device is not functioning properly and could\r
+                                   not be reset.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+EmmcResetEx (\r
+  IN  EFI_BLOCK_IO2_PROTOCOL  *This,\r
+  IN  BOOLEAN                 ExtendedVerification\r
+  );\r
+\r
+/**\r
+  Read BufferSize bytes from Lba into Buffer.\r
+\r
+  @param[in]       This         Indicates a pointer to the calling context.\r
+  @param[in]       MediaId      Id of the media, changes every time the media is replaced.\r
+  @param[in]       Lba          The starting Logical Block Address to read from.\r
+  @param[in, out]  Token        A pointer to the token associated with the transaction.\r
+  @param[in]       BufferSize   Size of Buffer, must be a multiple of device block size.\r
+  @param[out]      Buffer       A pointer to the destination buffer for the data. The caller is\r
+                                responsible for either having implicit or explicit ownership of the buffer.\r
+\r
+  @retval EFI_SUCCESS           The read request was queued if Event is not NULL.\r
+                                The data was read correctly from the device if\r
+                                the Event is NULL.\r
+  @retval EFI_DEVICE_ERROR      The device reported an error while performing\r
+                                the read.\r
+  @retval EFI_NO_MEDIA          There is no media in the device.\r
+  @retval EFI_MEDIA_CHANGED     The MediaId is not for the current media.\r
+  @retval EFI_BAD_BUFFER_SIZE   The BufferSize parameter is not a multiple of the\r
+                                intrinsic block size of the device.\r
+  @retval EFI_INVALID_PARAMETER The read request contains LBAs that are not valid,\r
+                                or the buffer is not on proper alignment.\r
+  @retval EFI_OUT_OF_RESOURCES  The request could not be completed due to a lack\r
+                                of resources.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+EmmcReadBlocksEx (\r
+  IN     EFI_BLOCK_IO2_PROTOCOL *This,\r
+  IN     UINT32                 MediaId,\r
+  IN     EFI_LBA                Lba,\r
+  IN OUT EFI_BLOCK_IO2_TOKEN    *Token,\r
+  IN     UINTN                  BufferSize,\r
+     OUT VOID                   *Buffer\r
+  );\r
+\r
+/**\r
+  Write BufferSize bytes from Lba into Buffer.\r
+\r
+  @param[in]       This         Indicates a pointer to the calling context.\r
+  @param[in]       MediaId      The media ID that the write request is for.\r
+  @param[in]       Lba          The starting logical block address to be written. The\r
+                                caller is responsible for writing to only legitimate\r
+                                locations.\r
+  @param[in, out]  Token        A pointer to the token associated with the transaction.\r
+  @param[in]       BufferSize   Size of Buffer, must be a multiple of device block size.\r
+  @param[in]       Buffer       A pointer to the source buffer for the data.\r
+\r
+  @retval EFI_SUCCESS           The data was written correctly to the device.\r
+  @retval EFI_WRITE_PROTECTED   The device can not be written to.\r
+  @retval EFI_DEVICE_ERROR      The device reported an error while performing the write.\r
+  @retval EFI_NO_MEDIA          There is no media in the device.\r
+  @retval EFI_MEDIA_CHNAGED     The MediaId does not matched the current device.\r
+  @retval EFI_BAD_BUFFER_SIZE   The Buffer was not a multiple of the block size of the device.\r
+  @retval EFI_INVALID_PARAMETER The write request contains LBAs that are not valid,\r
+                                or the buffer is not on proper alignment.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+EmmcWriteBlocksEx (\r
+  IN     EFI_BLOCK_IO2_PROTOCOL *This,\r
+  IN     UINT32                 MediaId,\r
+  IN     EFI_LBA                Lba,\r
+  IN OUT EFI_BLOCK_IO2_TOKEN    *Token,\r
+  IN     UINTN                  BufferSize,\r
+  IN     VOID                   *Buffer\r
+  );\r
+\r
+/**\r
+  Flush the Block Device.\r
+\r
+  @param[in]       This     Indicates a pointer to the calling context.\r
+  @param[in, out]  Token    A pointer to the token associated with the transaction.\r
+\r
+  @retval EFI_SUCCESS       All outstanding data was written to the device\r
+  @retval EFI_DEVICE_ERROR  The device reported an error while writing back the data\r
+  @retval EFI_NO_MEDIA      There is no media in the device.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+EmmcFlushBlocksEx (\r
+  IN     EFI_BLOCK_IO2_PROTOCOL  *This,\r
+  IN OUT EFI_BLOCK_IO2_TOKEN     *Token\r
+  );\r
+\r
+/**\r
+  Send a security protocol command to a device that receives data and/or the result\r
+  of one or more commands sent by SendData.\r
+\r
+  The ReceiveData function sends a security protocol command to the given MediaId.\r
+  The security protocol command sent is defined by SecurityProtocolId and contains\r
+  the security protocol specific data SecurityProtocolSpecificData. The function\r
+  returns the data from the security protocol command in PayloadBuffer.\r
+\r
+  For devices supporting the SCSI command set, the security protocol command is sent\r
+  using the SECURITY PROTOCOL IN command defined in SPC-4.\r
+\r
+  For devices supporting the ATA command set, the security protocol command is sent\r
+  using one of the TRUSTED RECEIVE commands defined in ATA8-ACS if PayloadBufferSize\r
+  is non-zero.\r
+\r
+  If the PayloadBufferSize is zero, the security protocol command is sent using the\r
+  Trusted Non-Data command defined in ATA8-ACS.\r
+\r
+  If PayloadBufferSize is too small to store the available data from the security\r
+  protocol command, the function shall copy PayloadBufferSize bytes into the\r
+  PayloadBuffer and return EFI_WARN_BUFFER_TOO_SMALL.\r
+\r
+  If PayloadBuffer or PayloadTransferSize is NULL and PayloadBufferSize is non-zero,\r
+  the function shall return EFI_INVALID_PARAMETER.\r
+\r
+  If the given MediaId does not support security protocol commands, the function shall\r
+  return EFI_UNSUPPORTED. If there is no media in the device, the function returns\r
+  EFI_NO_MEDIA. If the MediaId is not the ID for the current media in the device,\r
+  the function returns EFI_MEDIA_CHANGED.\r
+\r
+  If the security protocol fails to complete within the Timeout period, the function\r
+  shall return EFI_TIMEOUT.\r
+\r
+  If the security protocol command completes without an error, the function shall\r
+  return EFI_SUCCESS. If the security protocol command completes with an error, the\r
+  function shall return EFI_DEVICE_ERROR.\r
+\r
+  @param[in]  This                         Indicates a pointer to the calling context.\r
+  @param[in]  MediaId                      ID of the medium to receive data from.\r
+  @param[in]  Timeout                      The timeout, in 100ns units, to use for the execution\r
+                                           of the security protocol command. A Timeout value of 0\r
+                                           means that this function will wait indefinitely for the\r
+                                           security protocol command to execute. If Timeout is greater\r
+                                           than zero, then this function will return EFI_TIMEOUT\r
+                                           if the time required to execute the receive data command\r
+                                           is greater than Timeout.\r
+  @param[in]  SecurityProtocolId           The value of the "Security Protocol" parameter of\r
+                                           the security protocol command to be sent.\r
+  @param[in]  SecurityProtocolSpecificData The value of the "Security Protocol Specific" parameter\r
+                                           of the security protocol command to be sent.\r
+  @param[in]  PayloadBufferSize            Size in bytes of the payload data buffer.\r
+  @param[out] PayloadBuffer                A pointer to a destination buffer to store the security\r
+                                           protocol command specific payload data for the security\r
+                                           protocol command. The caller is responsible for having\r
+                                           either implicit or explicit ownership of the buffer.\r
+  @param[out] PayloadTransferSize          A pointer to a buffer to store the size in bytes of the\r
+                                           data written to the payload data buffer.\r
+  @param[in]  IsRead                       Indicates it is a read or write operation.\r
+\r
+  @retval EFI_SUCCESS                  The security protocol command completed successfully.\r
+  @retval EFI_WARN_BUFFER_TOO_SMALL    The PayloadBufferSize was too small to store the available\r
+                                       data from the device. The PayloadBuffer contains the truncated data.\r
+  @retval EFI_UNSUPPORTED              The given MediaId does not support security protocol commands.\r
+  @retval EFI_DEVICE_ERROR             The security protocol command completed with an error.\r
+  @retval EFI_NO_MEDIA                 There is no media in the device.\r
+  @retval EFI_MEDIA_CHANGED            The MediaId is not for the current media.\r
+  @retval EFI_INVALID_PARAMETER        The PayloadBuffer or PayloadTransferSize is NULL and\r
+                                       PayloadBufferSize is non-zero.\r
+  @retval EFI_TIMEOUT                  A timeout occurred while waiting for the security\r
+                                       protocol command to execute.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+EmmcSecurityProtocolInOut (\r
+  IN     EFI_STORAGE_SECURITY_COMMAND_PROTOCOL    *This,\r
+  IN     UINT32                                   MediaId,\r
+  IN     UINT64                                   Timeout,\r
+  IN     UINT8                                    SecurityProtocolId,\r
+  IN     UINT16                                   SecurityProtocolSpecificData,\r
+  IN     UINTN                                    PayloadBufferSize,\r
+     OUT VOID                                     *PayloadBuffer,\r
+     OUT UINTN                                    *PayloadTransferSize,\r
+  IN     BOOLEAN                                  IsRead\r
+  );\r
+\r
+/**\r
+  Send a security protocol command to a device that receives data and/or the result\r
+  of one or more commands sent by SendData.\r
+\r
+  The ReceiveData function sends a security protocol command to the given MediaId.\r
+  The security protocol command sent is defined by SecurityProtocolId and contains\r
+  the security protocol specific data SecurityProtocolSpecificData. The function\r
+  returns the data from the security protocol command in PayloadBuffer.\r
+\r
+  For devices supporting the SCSI command set, the security protocol command is sent\r
+  using the SECURITY PROTOCOL IN command defined in SPC-4.\r
+\r
+  For devices supporting the ATA command set, the security protocol command is sent\r
+  using one of the TRUSTED RECEIVE commands defined in ATA8-ACS if PayloadBufferSize\r
+  is non-zero.\r
+\r
+  If the PayloadBufferSize is zero, the security protocol command is sent using the\r
+  Trusted Non-Data command defined in ATA8-ACS.\r
+\r
+  If PayloadBufferSize is too small to store the available data from the security\r
+  protocol command, the function shall copy PayloadBufferSize bytes into the\r
+  PayloadBuffer and return EFI_WARN_BUFFER_TOO_SMALL.\r
+\r
+  If PayloadBuffer or PayloadTransferSize is NULL and PayloadBufferSize is non-zero,\r
+  the function shall return EFI_INVALID_PARAMETER.\r
+\r
+  If the given MediaId does not support security protocol commands, the function shall\r
+  return EFI_UNSUPPORTED. If there is no media in the device, the function returns\r
+  EFI_NO_MEDIA. If the MediaId is not the ID for the current media in the device,\r
+  the function returns EFI_MEDIA_CHANGED.\r
+\r
+  If the security protocol fails to complete within the Timeout period, the function\r
+  shall return EFI_TIMEOUT.\r
+\r
+  If the security protocol command completes without an error, the function shall\r
+  return EFI_SUCCESS. If the security protocol command completes with an error, the\r
+  function shall return EFI_DEVICE_ERROR.\r
+\r
+  @param  This                         Indicates a pointer to the calling context.\r
+  @param  MediaId                      ID of the medium to receive data from.\r
+  @param  Timeout                      The timeout, in 100ns units, to use for the execution\r
+                                       of the security protocol command. A Timeout value of 0\r
+                                       means that this function will wait indefinitely for the\r
+                                       security protocol command to execute. If Timeout is greater\r
+                                       than zero, then this function will return EFI_TIMEOUT\r
+                                       if the time required to execute the receive data command\r
+                                       is greater than Timeout.\r
+  @param  SecurityProtocolId           The value of the "Security Protocol" parameter of\r
+                                       the security protocol command to be sent.\r
+  @param  SecurityProtocolSpecificData The value of the "Security Protocol Specific" parameter\r
+                                       of the security protocol command to be sent.\r
+  @param  PayloadBufferSize            Size in bytes of the payload data buffer.\r
+  @param  PayloadBuffer                A pointer to a destination buffer to store the security\r
+                                       protocol command specific payload data for the security\r
+                                       protocol command. The caller is responsible for having\r
+                                       either implicit or explicit ownership of the buffer.\r
+  @param  PayloadTransferSize          A pointer to a buffer to store the size in bytes of the\r
+                                       data written to the payload data buffer.\r
+\r
+  @retval EFI_SUCCESS                  The security protocol command completed successfully.\r
+  @retval EFI_WARN_BUFFER_TOO_SMALL    The PayloadBufferSize was too small to store the available\r
+                                       data from the device. The PayloadBuffer contains the truncated data.\r
+  @retval EFI_UNSUPPORTED              The given MediaId does not support security protocol commands.\r
+  @retval EFI_DEVICE_ERROR             The security protocol command completed with an error.\r
+  @retval EFI_NO_MEDIA                 There is no media in the device.\r
+  @retval EFI_MEDIA_CHANGED            The MediaId is not for the current media.\r
+  @retval EFI_INVALID_PARAMETER        The PayloadBuffer or PayloadTransferSize is NULL and\r
+                                       PayloadBufferSize is non-zero.\r
+  @retval EFI_TIMEOUT                  A timeout occurred while waiting for the security\r
+                                       protocol command to execute.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+EmmcSecurityProtocolIn (\r
+  IN EFI_STORAGE_SECURITY_COMMAND_PROTOCOL    *This,\r
+  IN UINT32                                   MediaId,\r
+  IN UINT64                                   Timeout,\r
+  IN UINT8                                    SecurityProtocolId,\r
+  IN UINT16                                   SecurityProtocolSpecificData,\r
+  IN UINTN                                    PayloadBufferSize,\r
+  OUT VOID                                    *PayloadBuffer,\r
+  OUT UINTN                                   *PayloadTransferSize\r
+  );\r
+\r
+/**\r
+  Send a security protocol command to a device.\r
+\r
+  The SendData function sends a security protocol command containing the payload\r
+  PayloadBuffer to the given MediaId. The security protocol command sent is\r
+  defined by SecurityProtocolId and contains the security protocol specific data\r
+  SecurityProtocolSpecificData. If the underlying protocol command requires a\r
+  specific padding for the command payload, the SendData function shall add padding\r
+  bytes to the command payload to satisfy the padding requirements.\r
+\r
+  For devices supporting the SCSI command set, the security protocol command is sent\r
+  using the SECURITY PROTOCOL OUT command defined in SPC-4.\r
+\r
+  For devices supporting the ATA command set, the security protocol command is sent\r
+  using one of the TRUSTED SEND commands defined in ATA8-ACS if PayloadBufferSize\r
+  is non-zero. If the PayloadBufferSize is zero, the security protocol command is\r
+  sent using the Trusted Non-Data command defined in ATA8-ACS.\r
+\r
+  If PayloadBuffer is NULL and PayloadBufferSize is non-zero, the function shall\r
+  return EFI_INVALID_PARAMETER.\r
+\r
+  If the given MediaId does not support security protocol commands, the function\r
+  shall return EFI_UNSUPPORTED. If there is no media in the device, the function\r
+  returns EFI_NO_MEDIA. If the MediaId is not the ID for the current media in the\r
+  device, the function returns EFI_MEDIA_CHANGED.\r
+\r
+  If the security protocol fails to complete within the Timeout period, the function\r
+  shall return EFI_TIMEOUT.\r
+\r
+  If the security protocol command completes without an error, the function shall return\r
+  EFI_SUCCESS. If the security protocol command completes with an error, the function\r
+  shall return EFI_DEVICE_ERROR.\r
+\r
+  @param  This                         Indicates a pointer to the calling context.\r
+  @param  MediaId                      ID of the medium to receive data from.\r
+  @param  Timeout                      The timeout, in 100ns units, to use for the execution\r
+                                       of the security protocol command. A Timeout value of 0\r
+                                       means that this function will wait indefinitely for the\r
+                                       security protocol command to execute. If Timeout is greater\r
+                                       than zero, then this function will return EFI_TIMEOUT\r
+                                       if the time required to execute the receive data command\r
+                                       is greater than Timeout.\r
+  @param  SecurityProtocolId           The value of the "Security Protocol" parameter of\r
+                                       the security protocol command to be sent.\r
+  @param  SecurityProtocolSpecificData The value of the "Security Protocol Specific" parameter\r
+                                       of the security protocol command to be sent.\r
+  @param  PayloadBufferSize            Size in bytes of the payload data buffer.\r
+  @param  PayloadBuffer                A pointer to a destination buffer to store the security\r
+                                       protocol command specific payload data for the security\r
+                                       protocol command.\r
+\r
+  @retval EFI_SUCCESS                  The security protocol command completed successfully.\r
+  @retval EFI_UNSUPPORTED              The given MediaId does not support security protocol commands.\r
+  @retval EFI_DEVICE_ERROR             The security protocol command completed with an error.\r
+  @retval EFI_NO_MEDIA                 There is no media in the device.\r
+  @retval EFI_MEDIA_CHANGED            The MediaId is not for the current media.\r
+  @retval EFI_INVALID_PARAMETER        The PayloadBuffer is NULL and PayloadBufferSize is non-zero.\r
+  @retval EFI_TIMEOUT                  A timeout occurred while waiting for the security\r
+                                       protocol command to execute.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+EmmcSecurityProtocolOut (\r
+  IN EFI_STORAGE_SECURITY_COMMAND_PROTOCOL    *This,\r
+  IN UINT32                                   MediaId,\r
+  IN UINT64                                   Timeout,\r
+  IN UINT8                                    SecurityProtocolId,\r
+  IN UINT16                                   SecurityProtocolSpecificData,\r
+  IN UINTN                                    PayloadBufferSize,\r
+  IN VOID                                     *PayloadBuffer\r
+  );\r
+\r
+#endif\r
+\r
diff --git a/MdeModulePkg/Bus/Sd/EmmcDxe/EmmcDxe.c b/MdeModulePkg/Bus/Sd/EmmcDxe/EmmcDxe.c
new file mode 100644 (file)
index 0000000..f07540f
--- /dev/null
@@ -0,0 +1,1175 @@
+/** @file\r
+  The EmmcDxe driver is used to manage the EMMC device.\r
+\r
+  It produces BlockIo, BlockIo2 and StorageSecurity protocols to allow upper layer\r
+  access the EMMC device.\r
+\r
+  Copyright (c) 2015, Intel Corporation. All rights reserved.<BR>\r
+  This program and the accompanying materials\r
+  are licensed and made available under the terms and conditions of the BSD License\r
+  which accompanies this distribution.  The full text of the license may be found at\r
+  http://opensource.org/licenses/bsd-license.php\r
+\r
+  THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+  WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+\r
+**/\r
+\r
+#include "EmmcDxe.h"\r
+\r
+//\r
+// EmmcDxe Driver Binding Protocol Instance\r
+//\r
+EFI_DRIVER_BINDING_PROTOCOL gEmmcDxeDriverBinding = {\r
+  EmmcDxeDriverBindingSupported,\r
+  EmmcDxeDriverBindingStart,\r
+  EmmcDxeDriverBindingStop,\r
+  0x10,\r
+  NULL,\r
+  NULL\r
+};\r
+\r
+//\r
+// Template for Emmc Partitions.\r
+//\r
+EMMC_PARTITION mEmmcPartitionTemplate = {\r
+  EMMC_PARTITION_SIGNATURE,    // Signature\r
+  FALSE,                       // Enable\r
+  EmmcPartitionUnknown,        // PartitionType\r
+  NULL,                        // Handle\r
+  NULL,                        // DevicePath\r
+  {                            // BlockIo\r
+    EFI_BLOCK_IO_PROTOCOL_REVISION,\r
+    NULL,\r
+    EmmcReset,\r
+    EmmcReadBlocks,\r
+    EmmcWriteBlocks,\r
+    EmmcFlushBlocks\r
+  },\r
+  {                            // BlockIo2\r
+    NULL,\r
+    EmmcResetEx,\r
+    EmmcReadBlocksEx,\r
+    EmmcWriteBlocksEx,\r
+    EmmcFlushBlocksEx\r
+  },\r
+  {                            // BlockMedia\r
+    0,                         // MediaId\r
+    FALSE,                     // RemovableMedia\r
+    TRUE,                      // MediaPresent\r
+    FALSE,                     // LogicPartition\r
+    FALSE,                     // ReadOnly\r
+    FALSE,                     // WritingCache\r
+    0x200,                     // BlockSize\r
+    0,                         // IoAlign\r
+    0                          // LastBlock\r
+  },\r
+  {                            // StorageSecurity\r
+    EmmcSecurityProtocolIn,\r
+    EmmcSecurityProtocolOut\r
+  },\r
+  {\r
+    NULL,\r
+    NULL\r
+  },\r
+  NULL                         // Device\r
+};\r
+\r
+/**\r
+  Decode and print EMMC CSD Register content.\r
+\r
+  @param[in] Csd           Pointer to EMMC_CSD data structure.\r
+\r
+  @retval EFI_SUCCESS      The function completed successfully\r
+**/\r
+EFI_STATUS\r
+DumpCsd (\r
+  IN EMMC_CSD  *Csd\r
+  )\r
+{\r
+  DEBUG((DEBUG_INFO, "== Dump Emmc Csd Register==\n"));\r
+  DEBUG((DEBUG_INFO, "  CSD structure                    0x%x\n", Csd->CsdStructure));\r
+  DEBUG((DEBUG_INFO, "  System specification version     0x%x\n", Csd->SpecVers));\r
+  DEBUG((DEBUG_INFO, "  Data read access-time 1          0x%x\n", Csd->Taac));\r
+  DEBUG((DEBUG_INFO, "  Data read access-time 2          0x%x\n", Csd->Nsac));\r
+  DEBUG((DEBUG_INFO, "  Max. bus clock frequency         0x%x\n", Csd->TranSpeed));\r
+  DEBUG((DEBUG_INFO, "  Device command classes           0x%x\n", Csd->Ccc));\r
+  DEBUG((DEBUG_INFO, "  Max. read data block length      0x%x\n", Csd->ReadBlLen));\r
+  DEBUG((DEBUG_INFO, "  Partial blocks for read allowed  0x%x\n", Csd->ReadBlPartial));\r
+  DEBUG((DEBUG_INFO, "  Write block misalignment         0x%x\n", Csd->WriteBlkMisalign));\r
+  DEBUG((DEBUG_INFO, "  Read block misalignment          0x%x\n", Csd->ReadBlkMisalign));\r
+  DEBUG((DEBUG_INFO, "  DSR implemented                  0x%x\n", Csd->DsrImp));\r
+  DEBUG((DEBUG_INFO, "  Device size                      0x%x\n", Csd->CSizeLow | (Csd->CSizeHigh << 2)));\r
+  DEBUG((DEBUG_INFO, "  Max. read current @ VDD min      0x%x\n", Csd->VddRCurrMin));\r
+  DEBUG((DEBUG_INFO, "  Max. read current @ VDD max      0x%x\n", Csd->VddRCurrMax));\r
+  DEBUG((DEBUG_INFO, "  Max. write current @ VDD min     0x%x\n", Csd->VddWCurrMin));\r
+  DEBUG((DEBUG_INFO, "  Max. write current @ VDD max     0x%x\n", Csd->VddWCurrMax));\r
+  DEBUG((DEBUG_INFO, "  Device size multiplier           0x%x\n", Csd->CSizeMult));\r
+  DEBUG((DEBUG_INFO, "  Erase group size                 0x%x\n", Csd->EraseGrpSize));\r
+  DEBUG((DEBUG_INFO, "  Erase group size multiplier      0x%x\n", Csd->EraseGrpMult));\r
+  DEBUG((DEBUG_INFO, "  Write protect group size         0x%x\n", Csd->WpGrpSize));\r
+  DEBUG((DEBUG_INFO, "  Write protect group enable       0x%x\n", Csd->WpGrpEnable));\r
+  DEBUG((DEBUG_INFO, "  Manufacturer default ECC         0x%x\n", Csd->DefaultEcc));\r
+  DEBUG((DEBUG_INFO, "  Write speed factor               0x%x\n", Csd->R2WFactor));\r
+  DEBUG((DEBUG_INFO, "  Max. write data block length     0x%x\n", Csd->WriteBlLen));\r
+  DEBUG((DEBUG_INFO, "  Partial blocks for write allowed 0x%x\n", Csd->WriteBlPartial));\r
+  DEBUG((DEBUG_INFO, "  Content protection application   0x%x\n", Csd->ContentProtApp));\r
+  DEBUG((DEBUG_INFO, "  File format group                0x%x\n", Csd->FileFormatGrp));\r
+  DEBUG((DEBUG_INFO, "  Copy flag (OTP)                  0x%x\n", Csd->Copy));\r
+  DEBUG((DEBUG_INFO, "  Permanent write protection       0x%x\n", Csd->PermWriteProtect));\r
+  DEBUG((DEBUG_INFO, "  Temporary write protection       0x%x\n", Csd->TmpWriteProtect));\r
+  DEBUG((DEBUG_INFO, "  File format                      0x%x\n", Csd->FileFormat));\r
+  DEBUG((DEBUG_INFO, "  ECC code                         0x%x\n", Csd->Ecc));\r
+\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+  Decode and print EMMC EXT_CSD Register content.\r
+\r
+  @param[in] ExtCsd           Pointer to the EMMC_EXT_CSD data structure.\r
+\r
+  @retval EFI_SUCCESS         The function completed successfully\r
+**/\r
+EFI_STATUS\r
+DumpExtCsd (\r
+  IN EMMC_EXT_CSD  *ExtCsd\r
+  )\r
+{\r
+  DEBUG((DEBUG_INFO, "==Dump Emmc ExtCsd Register==\n"));\r
+  DEBUG((DEBUG_INFO, "  Supported Command Sets                 0x%x\n", ExtCsd->CmdSet));\r
+  DEBUG((DEBUG_INFO, "  HPI features                           0x%x\n", ExtCsd->HpiFeatures));\r
+  DEBUG((DEBUG_INFO, "  Background operations support          0x%x\n", ExtCsd->BkOpsSupport));\r
+  DEBUG((DEBUG_INFO, "  Background operations status           0x%x\n", ExtCsd->BkopsStatus));\r
+  DEBUG((DEBUG_INFO, "  Number of correctly programmed sectors 0x%x\n", *((UINT32*)&ExtCsd->CorrectlyPrgSectorsNum[0])));\r
+  DEBUG((DEBUG_INFO, "  Initialization time after partitioning 0x%x\n", ExtCsd->IniTimeoutAp));\r
+  DEBUG((DEBUG_INFO, "  TRIM Multiplier                        0x%x\n", ExtCsd->TrimMult));\r
+  DEBUG((DEBUG_INFO, "  Secure Feature support                 0x%x\n", ExtCsd->SecFeatureSupport));\r
+  DEBUG((DEBUG_INFO, "  Secure Erase Multiplier                0x%x\n", ExtCsd->SecEraseMult));\r
+  DEBUG((DEBUG_INFO, "  Secure TRIM Multiplier                 0x%x\n", ExtCsd->SecTrimMult));\r
+  DEBUG((DEBUG_INFO, "  Boot information                       0x%x\n", ExtCsd->BootInfo));\r
+  DEBUG((DEBUG_INFO, "  Boot partition size                    0x%x\n", ExtCsd->BootSizeMult));\r
+  DEBUG((DEBUG_INFO, "  Access size                            0x%x\n", ExtCsd->AccSize));\r
+  DEBUG((DEBUG_INFO, "  High-capacity erase unit size          0x%x\n", ExtCsd->HcEraseGrpSize));\r
+  DEBUG((DEBUG_INFO, "  High-capacity erase timeout            0x%x\n", ExtCsd->EraseTimeoutMult));\r
+  DEBUG((DEBUG_INFO, "  Reliable write sector count            0x%x\n", ExtCsd->RelWrSecC));\r
+  DEBUG((DEBUG_INFO, "  High-capacity write protect group size 0x%x\n", ExtCsd->HcWpGrpSize));\r
+  DEBUG((DEBUG_INFO, "  Sleep/awake timeout                    0x%x\n", ExtCsd->SATimeout));\r
+  DEBUG((DEBUG_INFO, "  Sector Count                           0x%x\n", *((UINT32*)&ExtCsd->SecCount[0])));\r
+  DEBUG((DEBUG_INFO, "  Partition switching timing             0x%x\n", ExtCsd->PartitionSwitchTime));\r
+  DEBUG((DEBUG_INFO, "  Out-of-interrupt busy timing           0x%x\n", ExtCsd->OutOfInterruptTime));\r
+  DEBUG((DEBUG_INFO, "  I/O Driver Strength                    0x%x\n", ExtCsd->DriverStrength));\r
+  DEBUG((DEBUG_INFO, "  Device type                            0x%x\n", ExtCsd->DeviceType));\r
+  DEBUG((DEBUG_INFO, "  CSD STRUCTURE                          0x%x\n", ExtCsd->CsdStructure));\r
+  DEBUG((DEBUG_INFO, "  Extended CSD revision                  0x%x\n", ExtCsd->ExtCsdRev));\r
+  DEBUG((DEBUG_INFO, "  Command set                            0x%x\n", ExtCsd->CmdSet));\r
+  DEBUG((DEBUG_INFO, "  Command set revision                   0x%x\n", ExtCsd->CmdSetRev));\r
+  DEBUG((DEBUG_INFO, "  Power class                            0x%x\n", ExtCsd->PowerClass));\r
+  DEBUG((DEBUG_INFO, "  High-speed interface timing            0x%x\n", ExtCsd->HsTiming));\r
+  DEBUG((DEBUG_INFO, "  Bus width mode                         0x%x\n", ExtCsd->BusWidth));\r
+  DEBUG((DEBUG_INFO, "  Erased memory content                  0x%x\n", ExtCsd->ErasedMemCont));\r
+  DEBUG((DEBUG_INFO, "  Partition configuration                0x%x\n", ExtCsd->PartitionConfig));\r
+  DEBUG((DEBUG_INFO, "  Boot config protection                 0x%x\n", ExtCsd->BootConfigProt));\r
+  DEBUG((DEBUG_INFO, "  Boot bus Conditions                    0x%x\n", ExtCsd->BootBusConditions));\r
+  DEBUG((DEBUG_INFO, "  High-density erase group definition    0x%x\n", ExtCsd->EraseGroupDef));\r
+  DEBUG((DEBUG_INFO, "  Boot write protection status register  0x%x\n", ExtCsd->BootWpStatus));\r
+  DEBUG((DEBUG_INFO, "  Boot area write protection register    0x%x\n", ExtCsd->BootWp));\r
+  DEBUG((DEBUG_INFO, "  User area write protection register    0x%x\n", ExtCsd->UserWp));\r
+  DEBUG((DEBUG_INFO, "  FW configuration                       0x%x\n", ExtCsd->FwConfig));\r
+  DEBUG((DEBUG_INFO, "  RPMB Size                              0x%x\n", ExtCsd->RpmbSizeMult));\r
+  DEBUG((DEBUG_INFO, "  H/W reset function                     0x%x\n", ExtCsd->RstFunction));\r
+  DEBUG((DEBUG_INFO, "  Partitioning Support                   0x%x\n", ExtCsd->PartitioningSupport));\r
+  DEBUG((DEBUG_INFO, "  Max Enhanced Area Size                 0x%02x%02x%02x\n", \\r
+                        ExtCsd->MaxEnhSizeMult[2], ExtCsd->MaxEnhSizeMult[1], ExtCsd->MaxEnhSizeMult[0]));\r
+  DEBUG((DEBUG_INFO, "  Partitions attribute                   0x%x\n", ExtCsd->PartitionsAttribute));\r
+  DEBUG((DEBUG_INFO, "  Partitioning Setting                   0x%x\n", ExtCsd->PartitionSettingCompleted));\r
+  DEBUG((DEBUG_INFO, "  General Purpose Partition 1 Size       0x%02x%02x%02x\n", \\r
+                        ExtCsd->GpSizeMult[2], ExtCsd->GpSizeMult[1], ExtCsd->GpSizeMult[0]));\r
+  DEBUG((DEBUG_INFO, "  General Purpose Partition 2 Size       0x%02x%02x%02x\n", \\r
+                        ExtCsd->GpSizeMult[5], ExtCsd->GpSizeMult[4], ExtCsd->GpSizeMult[3]));\r
+  DEBUG((DEBUG_INFO, "  General Purpose Partition 3 Size       0x%02x%02x%02x\n", \\r
+                        ExtCsd->GpSizeMult[8], ExtCsd->GpSizeMult[7], ExtCsd->GpSizeMult[6]));\r
+  DEBUG((DEBUG_INFO, "  General Purpose Partition 4 Size       0x%02x%02x%02x\n", \\r
+                        ExtCsd->GpSizeMult[11], ExtCsd->GpSizeMult[10], ExtCsd->GpSizeMult[9]));\r
+  DEBUG((DEBUG_INFO, "  Enhanced User Data Area Size           0x%02x%02x%02x\n", \\r
+                        ExtCsd->EnhSizeMult[2], ExtCsd->EnhSizeMult[1], ExtCsd->EnhSizeMult[0]));\r
+  DEBUG((DEBUG_INFO, "  Enhanced User Data Start Address       0x%x\n", *((UINT32*)&ExtCsd->EnhStartAddr[0])));\r
+  DEBUG((DEBUG_INFO, "  Bad Block Management mode              0x%x\n", ExtCsd->SecBadBlkMgmnt));\r
+  DEBUG((DEBUG_INFO, "  Native sector size                     0x%x\n", ExtCsd->NativeSectorSize));\r
+  DEBUG((DEBUG_INFO, "  Sector size emulation                  0x%x\n", ExtCsd->UseNativeSector));\r
+  DEBUG((DEBUG_INFO, "  Sector size                            0x%x\n", ExtCsd->DataSectorSize));\r
+\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+  Get EMMC device model name.\r
+\r
+  @param[in, out] Device   The pointer to the EMMC_DEVICE data structure.\r
+  @param[in]      Cid      Pointer to EMMC_CID data structure.\r
+\r
+  @retval EFI_SUCCESS      The function completed successfully\r
+\r
+**/\r
+EFI_STATUS\r
+GetEmmcModelName (\r
+  IN OUT EMMC_DEVICE         *Device,\r
+  IN     EMMC_CID            *Cid\r
+  )\r
+{\r
+  CHAR8  String[EMMC_MODEL_NAME_MAX_LEN];\r
+\r
+  ZeroMem (String, sizeof (String));\r
+  CopyMem (String, &Cid->OemId, sizeof (Cid->OemId));\r
+  String[sizeof (Cid->OemId)] = ' ';\r
+  CopyMem (String + sizeof (Cid->OemId) + 1, Cid->ProductName, sizeof (Cid->ProductName));\r
+  String[sizeof (Cid->OemId) + sizeof (Cid->ProductName)] = ' ';\r
+  CopyMem (String + sizeof (Cid->OemId) + sizeof (Cid->ProductName) + 1, Cid->ProductSerialNumber, sizeof (Cid->ProductSerialNumber));\r
+\r
+  AsciiStrToUnicodeStr (String, Device->ModelName);\r
+\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+  Discover all partitions in the EMMC device.\r
+\r
+  @param[in] Device          The pointer to the EMMC_DEVICE data structure.\r
+\r
+  @retval EFI_SUCCESS        All the partitions in the device are successfully enumerated.\r
+  @return Others             Some error occurs when enumerating the partitions.\r
+\r
+**/\r
+EFI_STATUS\r
+DiscoverAllPartitions (\r
+  IN EMMC_DEVICE             *Device\r
+  )\r
+{\r
+  EFI_STATUS                        Status;\r
+  EFI_SD_MMC_PASS_THRU_PROTOCOL     *PassThru;\r
+  EMMC_PARTITION                    *Partition;\r
+  EMMC_CSD                          *Csd;\r
+  EMMC_CID                          *Cid;\r
+  EMMC_EXT_CSD                      *ExtCsd;\r
+  UINT8                             Slot;\r
+  UINT64                            Capacity;\r
+  UINT32                            DevStatus;\r
+  UINT8                             Index;\r
+  UINT32                            SecCount;\r
+  UINT32                            GpSizeMult;\r
+\r
+  PassThru = Device->Private->PassThru;\r
+  Slot     = Device->Slot;\r
+\r
+  Status = EmmcSendStatus (Device, Slot + 1, &DevStatus);\r
+  if (EFI_ERROR (Status)) {\r
+    return Status;\r
+  }\r
+  //\r
+  // Deselect the device to force it enter stby mode before getting CSD\r
+  // register content.\r
+  // Note here we don't judge return status as some EMMC devices return\r
+  // error but the state has been stby.\r
+  //\r
+  EmmcSelect (Device, 0);\r
+\r
+  Status = EmmcSendStatus (Device, Slot + 1, &DevStatus);\r
+  if (EFI_ERROR (Status)) {\r
+    return Status;\r
+  }\r
+\r
+  Csd    = &Device->Csd;\r
+  Status = EmmcGetCsd (Device, Slot + 1, Csd);\r
+  if (EFI_ERROR (Status)) {\r
+    return Status;\r
+  }\r
+  DumpCsd (Csd);\r
+\r
+  if ((Csd->CSizeLow | Csd->CSizeHigh << 2) == 0xFFF) {\r
+    Device->SectorAddressing = TRUE;\r
+  } else {\r
+    Device->SectorAddressing = FALSE;\r
+  }\r
+\r
+  Cid    = &Device->Cid;\r
+  Status = EmmcGetCid (Device, Slot + 1, Cid);\r
+  if (EFI_ERROR (Status)) {\r
+    return Status;\r
+  }\r
+\r
+  Status = EmmcSelect (Device, Slot + 1);\r
+  if (EFI_ERROR (Status)) {\r
+    return Status;\r
+  }\r
+\r
+  ExtCsd = &Device->ExtCsd;\r
+  Status = EmmcGetExtCsd (Device, ExtCsd);\r
+  if (EFI_ERROR (Status)) {\r
+    return Status;\r
+  }\r
+  DumpExtCsd (ExtCsd);\r
+\r
+  if (ExtCsd->ExtCsdRev < 5) {\r
+    DEBUG ((EFI_D_ERROR, "The EMMC device version is too low, we don't support!!!\n"));\r
+    return EFI_UNSUPPORTED;\r
+  }\r
+\r
+  if ((ExtCsd->PartitioningSupport & BIT0) != BIT0) {\r
+    DEBUG ((EFI_D_ERROR, "The EMMC device doesn't support Partition Feature!!!\n"));\r
+    return EFI_UNSUPPORTED;\r
+  }\r
+\r
+  for (Index = 0; Index < EMMC_MAX_PARTITIONS; Index++) {\r
+    Partition = &Device->Partition[Index];\r
+    CopyMem (Partition, &mEmmcPartitionTemplate, sizeof (EMMC_PARTITION));\r
+    Partition->Device             = Device;\r
+    InitializeListHead (&Partition->Queue);\r
+    Partition->BlockIo.Media      = &Partition->BlockMedia;\r
+    Partition->BlockIo2.Media     = &Partition->BlockMedia;\r
+    Partition->PartitionType      = Index;\r
+    Partition->BlockMedia.IoAlign = Device->Private->PassThru->IoAlign;\r
+    Partition->BlockMedia.BlockSize      = 0x200;\r
+    Partition->BlockMedia.LastBlock      = 0x00;\r
+    Partition->BlockMedia.RemovableMedia = FALSE;\r
+    Partition->BlockMedia.MediaPresent     = TRUE;\r
+    Partition->BlockMedia.LogicalPartition = FALSE;\r
+\r
+    switch (Index) {\r
+      case EmmcPartitionUserData:\r
+        SecCount = *(UINT32*)&ExtCsd->SecCount;\r
+        Capacity = MultU64x32 ((UINT64) SecCount, 0x200);\r
+        break;\r
+      case EmmcPartitionBoot1:\r
+      case EmmcPartitionBoot2:\r
+        Capacity = ExtCsd->BootSizeMult * SIZE_128KB;\r
+        break;\r
+      case EmmcPartitionRPMB:\r
+        Capacity = ExtCsd->RpmbSizeMult * SIZE_128KB;\r
+        break;\r
+      case EmmcPartitionGP1:\r
+        GpSizeMult = (UINT32)(ExtCsd->GpSizeMult[0] | (ExtCsd->GpSizeMult[1] << 8) | (ExtCsd->GpSizeMult[2] << 16));\r
+        Capacity = MultU64x32 (MultU64x32 (MultU64x32 ((UINT64)GpSizeMult, ExtCsd->HcWpGrpSize), ExtCsd->HcEraseGrpSize), SIZE_512KB);\r
+        break;\r
+      case EmmcPartitionGP2:\r
+        GpSizeMult = (UINT32)(ExtCsd->GpSizeMult[3] | (ExtCsd->GpSizeMult[4] << 8) | (ExtCsd->GpSizeMult[5] << 16));\r
+        Capacity = MultU64x32 (MultU64x32 (MultU64x32 ((UINT64)GpSizeMult, ExtCsd->HcWpGrpSize), ExtCsd->HcEraseGrpSize), SIZE_512KB);\r
+        break;\r
+      case EmmcPartitionGP3:\r
+        GpSizeMult = (UINT32)(ExtCsd->GpSizeMult[6] | (ExtCsd->GpSizeMult[7] << 8) | (ExtCsd->GpSizeMult[8] << 16));\r
+        Capacity = MultU64x32 (MultU64x32 (MultU64x32 ((UINT64)GpSizeMult, ExtCsd->HcWpGrpSize), ExtCsd->HcEraseGrpSize), SIZE_512KB);\r
+        break;\r
+      case EmmcPartitionGP4:\r
+        GpSizeMult = (UINT32)(ExtCsd->GpSizeMult[9] | (ExtCsd->GpSizeMult[10] << 8) | (ExtCsd->GpSizeMult[11] << 16));\r
+        Capacity = MultU64x32 (MultU64x32 (MultU64x32 ((UINT64)GpSizeMult, ExtCsd->HcWpGrpSize), ExtCsd->HcEraseGrpSize), SIZE_512KB);\r
+        break;\r
+      default:\r
+        ASSERT (FALSE);\r
+        return EFI_INVALID_PARAMETER;\r
+    }\r
+\r
+    if (Capacity != 0) {\r
+      Partition->Enable = TRUE;\r
+      Partition->BlockMedia.LastBlock = DivU64x32 (Capacity, Partition->BlockMedia.BlockSize) - 1;\r
+    }\r
+  }\r
+\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+  Install BlkIo, BlkIo2 and Ssp protocols for the specified partition in the EMMC device.\r
+\r
+  @param[in] Device          The pointer to the EMMC_DEVICE data structure.\r
+  @param[in] Index           The index of the partition.\r
+\r
+  @retval EFI_SUCCESS        The protocols are installed successfully.\r
+  @retval Others             Some error occurs when installing the protocols.\r
+\r
+**/\r
+EFI_STATUS\r
+InstallProtocolOnPartition (\r
+  IN EMMC_DEVICE             *Device,\r
+  IN UINT8                   Index\r
+  )\r
+{\r
+  EFI_STATUS                        Status;\r
+  EMMC_PARTITION                    *Partition;\r
+  CONTROLLER_DEVICE_PATH            ControlNode;\r
+  EFI_DEVICE_PATH_PROTOCOL          *ParentDevicePath;\r
+  EFI_DEVICE_PATH_PROTOCOL          *DevicePath;\r
+  EFI_DEVICE_PATH_PROTOCOL          *RemainingDevicePath;\r
+  EFI_HANDLE                        DeviceHandle;\r
+\r
+  //\r
+  // Build device path\r
+  //\r
+  ParentDevicePath = Device->DevicePath;\r
+\r
+  ControlNode.Header.Type    = HARDWARE_DEVICE_PATH;\r
+  ControlNode.Header.SubType = HW_CONTROLLER_DP;\r
+  SetDevicePathNodeLength (&ControlNode.Header, sizeof (CONTROLLER_DEVICE_PATH));\r
+  ControlNode.ControllerNumber = Index;\r
+\r
+  DevicePath = AppendDevicePathNode (ParentDevicePath, (EFI_DEVICE_PATH_PROTOCOL*)&ControlNode);\r
+  if (DevicePath == NULL) {\r
+    Status = EFI_OUT_OF_RESOURCES;\r
+    goto Error;\r
+  }\r
+\r
+  DeviceHandle = NULL;\r
+  RemainingDevicePath = DevicePath;\r
+  Status = gBS->LocateDevicePath (&gEfiDevicePathProtocolGuid, &RemainingDevicePath, &DeviceHandle);\r
+  if (!EFI_ERROR (Status) && (DeviceHandle != NULL) && IsDevicePathEnd(RemainingDevicePath)) {\r
+    Status = EFI_ALREADY_STARTED;\r
+    goto Error;\r
+  }\r
+\r
+  Partition = &Device->Partition[Index];\r
+  Partition->DevicePath = DevicePath;\r
+  if (Partition->Enable) {\r
+    //\r
+    // Install BlkIo/BlkIo2/Ssp for the specified partition\r
+    //\r
+    Status = gBS->InstallMultipleProtocolInterfaces (\r
+                    &Partition->Handle,\r
+                    &gEfiDevicePathProtocolGuid,\r
+                    Partition->DevicePath,\r
+                    &gEfiBlockIoProtocolGuid,\r
+                    &Partition->BlockIo,\r
+                    &gEfiBlockIo2ProtocolGuid,\r
+                    &Partition->BlockIo2,\r
+                    NULL\r
+                    );\r
+   if (EFI_ERROR (Status)) {\r
+      goto Error;\r
+    }\r
+\r
+    if (((Partition->PartitionType == EmmcPartitionUserData) ||\r
+        (Partition->PartitionType == EmmcPartitionBoot1) ||\r
+        (Partition->PartitionType == EmmcPartitionBoot2)) &&\r
+        ((Device->Csd.Ccc & BIT10) != 0)) {\r
+      Status = gBS->InstallProtocolInterface (\r
+                      &Partition->Handle,\r
+                      &gEfiStorageSecurityCommandProtocolGuid,\r
+                      EFI_NATIVE_INTERFACE,\r
+                      &Partition->StorageSecurity\r
+                      );\r
+      if (EFI_ERROR (Status)) {\r
+        gBS->UninstallMultipleProtocolInterfaces (\r
+               &Partition->Handle,\r
+               &gEfiDevicePathProtocolGuid,\r
+               Partition->DevicePath,\r
+               &gEfiBlockIoProtocolGuid,\r
+               &Partition->BlockIo,\r
+               &gEfiBlockIo2ProtocolGuid,\r
+               &Partition->BlockIo2,\r
+               NULL\r
+               );\r
+        goto Error;\r
+      }\r
+    }\r
+\r
+    gBS->OpenProtocol (\r
+           Device->Private->Controller,\r
+           &gEfiSdMmcPassThruProtocolGuid,\r
+           (VOID **) &(Device->Private->PassThru),\r
+           Device->Private->DriverBindingHandle,\r
+           Partition->Handle,\r
+           EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER\r
+           );\r
+  } else {\r
+    Status = EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+Error:\r
+  if (EFI_ERROR (Status) && (DevicePath != NULL)) {\r
+    FreePool (DevicePath);\r
+  }\r
+\r
+  return Status;\r
+}\r
+\r
+/**\r
+  Scan EMMC Bus to discover the device.\r
+\r
+  @param[in]  Private             The EMMC driver private data structure.\r
+  @param[in]  Slot                The slot number to check device present.\r
+\r
+  @retval EFI_SUCCESS             Successfully to discover the device and attach\r
+                                  SdMmcIoProtocol to it.\r
+  @retval EFI_OUT_OF_RESOURCES    The request could not be completed due to a lack\r
+                                  of resources.\r
+  @retval EFI_ALREADY_STARTED     The device was discovered before.\r
+  @retval Others                  Fail to discover the device.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+DiscoverEmmcDevice (\r
+  IN  EMMC_DRIVER_PRIVATE_DATA    *Private,\r
+  IN  UINT8                       Slot,\r
+  IN  EFI_DEVICE_PATH_PROTOCOL    *RemainingDevicePath\r
+  )\r
+{\r
+  EFI_STATUS                      Status;\r
+  EMMC_DEVICE                     *Device;\r
+  EFI_DEVICE_PATH_PROTOCOL        *DevicePath;\r
+  EFI_DEVICE_PATH_PROTOCOL        *NewDevicePath;\r
+  EFI_DEVICE_PATH_PROTOCOL        *RemainingEmmcDevPath;\r
+  EFI_DEV_PATH                    *Node;\r
+  EFI_HANDLE                      DeviceHandle;\r
+  EFI_SD_MMC_PASS_THRU_PROTOCOL   *PassThru;\r
+  UINT8                           Index;\r
+\r
+  Device              = NULL;\r
+  DevicePath          = NULL;\r
+  NewDevicePath       = NULL;\r
+  RemainingDevicePath = NULL;\r
+  PassThru = Private->PassThru;\r
+  Device   = &Private->Device[Slot];\r
+\r
+  //\r
+  // Build Device Path to check if the EMMC device present at the slot.\r
+  //\r
+  Status = PassThru->BuildDevicePath (\r
+                       PassThru,\r
+                       Slot,\r
+                       &DevicePath\r
+                       );\r
+  if (EFI_ERROR(Status)) {\r
+    return Status;\r
+  }\r
+\r
+  if (DevicePath->SubType != MSG_EMMC_DP) {\r
+    Status = EFI_UNSUPPORTED;\r
+    goto Error;\r
+  }\r
+\r
+  NewDevicePath = AppendDevicePathNode (\r
+                    Private->ParentDevicePath,\r
+                    DevicePath\r
+                    );\r
+  if (NewDevicePath == NULL) {\r
+    Status = EFI_OUT_OF_RESOURCES;\r
+    goto Error;\r
+  }\r
+\r
+  DeviceHandle         = NULL;\r
+  RemainingEmmcDevPath = NewDevicePath;\r
+  Status = gBS->LocateDevicePath (&gEfiDevicePathProtocolGuid, &RemainingEmmcDevPath, &DeviceHandle);\r
+  //\r
+  // The device path to the EMMC device doesn't exist. It means the corresponding device private data hasn't been initialized.\r
+  //\r
+  if (EFI_ERROR (Status) || (DeviceHandle == NULL) || !IsDevicePathEnd (RemainingEmmcDevPath)) {\r
+    Device->DevicePath = NewDevicePath;\r
+    Device->Slot       = Slot;\r
+    Device->Private    = Private;\r
+    //\r
+    // Expose user area in the Sd memory card to upper layer.\r
+    //\r
+    Status = DiscoverAllPartitions (Device);\r
+    if (EFI_ERROR(Status)) {\r
+      FreePool (NewDevicePath);\r
+      goto Error;\r
+    }\r
+\r
+    Status = gBS->InstallProtocolInterface (\r
+                    &Device->Handle,\r
+                    &gEfiDevicePathProtocolGuid,\r
+                    EFI_NATIVE_INTERFACE,\r
+                    Device->DevicePath\r
+                    );\r
+    if (EFI_ERROR(Status)) {\r
+      FreePool (NewDevicePath);\r
+      goto Error;\r
+    }\r
+\r
+    Device->ControllerNameTable = NULL;\r
+    GetEmmcModelName (Device, &Device->Cid);\r
+    AddUnicodeString2 (\r
+      "eng",\r
+      gEmmcDxeComponentName.SupportedLanguages,\r
+      &Device->ControllerNameTable,\r
+      Device->ModelName,\r
+      TRUE\r
+      );\r
+    AddUnicodeString2 (\r
+      "en",\r
+      gEmmcDxeComponentName.SupportedLanguages,\r
+      &Device->ControllerNameTable,\r
+      Device->ModelName,\r
+      FALSE\r
+      );\r
+  }\r
+\r
+  if (RemainingDevicePath == NULL) {\r
+    //\r
+    // Expose all partitions in the Emmc device to upper layer.\r
+    //\r
+    for (Index = 0; Index < EMMC_MAX_PARTITIONS; Index++) {\r
+      InstallProtocolOnPartition (Device, Index);\r
+    }\r
+  } else if (!IsDevicePathEnd (RemainingDevicePath)) {\r
+    //\r
+    // Enumerate the specified partition\r
+    //\r
+    Node = (EFI_DEV_PATH *) RemainingDevicePath;\r
+    if ((DevicePathType (&Node->DevPath) != HARDWARE_DEVICE_PATH) ||\r
+        (DevicePathSubType (&Node->DevPath) != HW_CONTROLLER_DP) ||\r
+        (DevicePathNodeLength (&Node->DevPath) != sizeof (CONTROLLER_DEVICE_PATH))) {\r
+      Status = EFI_INVALID_PARAMETER;\r
+      goto Error;\r
+    }\r
+\r
+    Index = (UINT8)Node->Controller.ControllerNumber;\r
+    if (Index >= EMMC_MAX_PARTITIONS) {\r
+      Status = EFI_INVALID_PARAMETER;\r
+      goto Error;\r
+    }\r
+\r
+    Status = InstallProtocolOnPartition (Device, Index);\r
+  }\r
+\r
+Error:\r
+  FreePool (DevicePath);\r
+\r
+  return Status;\r
+}\r
+\r
+/**\r
+  Tests to see if this driver supports a given controller. If a child device is provided,\r
+  it further tests to see if this driver supports creating a handle for the specified child device.\r
+\r
+  This function checks to see if the driver specified by This supports the device specified by\r
+  ControllerHandle. Drivers will typically use the device path attached to\r
+  ControllerHandle and/or the services from the bus I/O abstraction attached to\r
+  ControllerHandle to determine if the driver supports ControllerHandle. This function\r
+  may be called many times during platform initialization. In order to reduce boot times, the tests\r
+  performed by this function must be very small, and take as little time as possible to execute. This\r
+  function must not change the state of any hardware devices, and this function must be aware that the\r
+  device specified by ControllerHandle may already be managed by the same driver or a\r
+  different driver. This function must match its calls to AllocatePages() with FreePages(),\r
+  AllocatePool() with FreePool(), and OpenProtocol() with CloseProtocol().\r
+  Since ControllerHandle may have been previously started by the same driver, if a protocol is\r
+  already in the opened state, then it must not be closed with CloseProtocol(). This is required\r
+  to guarantee the state of ControllerHandle is not modified by this function.\r
+\r
+  @param[in]  This                 A pointer to the EFI_DRIVER_BINDING_PROTOCOL instance.\r
+  @param[in]  ControllerHandle     The handle of the controller to test. This handle\r
+                                   must support a protocol interface that supplies\r
+                                   an I/O abstraction to the driver.\r
+  @param[in]  RemainingDevicePath  A pointer to the remaining portion of a device path.  This\r
+                                   parameter is ignored by device drivers, and is optional for bus\r
+                                   drivers. For bus drivers, if this parameter is not NULL, then\r
+                                   the bus driver must determine if the bus controller specified\r
+                                   by ControllerHandle and the child controller specified\r
+                                   by RemainingDevicePath are both supported by this\r
+                                   bus driver.\r
+\r
+  @retval EFI_SUCCESS              The device specified by ControllerHandle and\r
+                                   RemainingDevicePath is supported by the driver specified by This.\r
+  @retval EFI_ALREADY_STARTED      The device specified by ControllerHandle and\r
+                                   RemainingDevicePath is already being managed by the driver\r
+                                   specified by This.\r
+  @retval EFI_ACCESS_DENIED        The device specified by ControllerHandle and\r
+                                   RemainingDevicePath is already being managed by a different\r
+                                   driver or an application that requires exclusive access.\r
+                                   Currently not implemented.\r
+  @retval EFI_UNSUPPORTED          The device specified by ControllerHandle and\r
+                                   RemainingDevicePath is not supported by the driver specified by This.\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+EmmcDxeDriverBindingSupported (\r
+  IN EFI_DRIVER_BINDING_PROTOCOL   *This,\r
+  IN EFI_HANDLE                    Controller,\r
+  IN EFI_DEVICE_PATH_PROTOCOL      *RemainingDevicePath\r
+  )\r
+{\r
+  EFI_STATUS                       Status;\r
+  EFI_DEVICE_PATH_PROTOCOL         *ParentDevicePath;\r
+  EFI_SD_MMC_PASS_THRU_PROTOCOL    *PassThru;\r
+  UINT8                            Slot;\r
+\r
+  //\r
+  // Test EFI_SD_MMC_PASS_THRU_PROTOCOL on the controller handle.\r
+  //\r
+  Status = gBS->OpenProtocol (\r
+                  Controller,\r
+                  &gEfiSdMmcPassThruProtocolGuid,\r
+                  (VOID**) &PassThru,\r
+                  This->DriverBindingHandle,\r
+                  Controller,\r
+                  EFI_OPEN_PROTOCOL_BY_DRIVER\r
+                  );\r
+\r
+  if (Status == EFI_ALREADY_STARTED) {\r
+    return EFI_SUCCESS;\r
+  }\r
+\r
+  if (EFI_ERROR (Status)) {\r
+    return Status;\r
+  }\r
+\r
+  //\r
+  // Test RemainingDevicePath is valid or not.\r
+  //\r
+  if ((RemainingDevicePath != NULL) && !IsDevicePathEnd (RemainingDevicePath)) {\r
+    Status = PassThru->GetSlotNumber (PassThru, RemainingDevicePath, &Slot);\r
+    if (EFI_ERROR (Status)) {\r
+      //\r
+      // Close the I/O Abstraction(s) used to perform the supported test\r
+      //\r
+      gBS->CloseProtocol (\r
+             Controller,\r
+             &gEfiSdMmcPassThruProtocolGuid,\r
+             This->DriverBindingHandle,\r
+             Controller\r
+             );\r
+      return Status;\r
+    }\r
+  }\r
+\r
+  //\r
+  // Close the I/O Abstraction(s) used to perform the supported test\r
+  //\r
+  gBS->CloseProtocol (\r
+         Controller,\r
+         &gEfiSdMmcPassThruProtocolGuid,\r
+         This->DriverBindingHandle,\r
+         Controller\r
+         );\r
+\r
+  //\r
+  // Open the EFI Device Path protocol needed to perform the supported test\r
+  //\r
+  Status = gBS->OpenProtocol (\r
+                  Controller,\r
+                  &gEfiDevicePathProtocolGuid,\r
+                  (VOID **) &ParentDevicePath,\r
+                  This->DriverBindingHandle,\r
+                  Controller,\r
+                  EFI_OPEN_PROTOCOL_GET_PROTOCOL\r
+                  );\r
+  return Status;\r
+}\r
+\r
+/**\r
+  Starts a device controller or a bus controller.\r
+\r
+  The Start() function is designed to be invoked from the EFI boot service ConnectController().\r
+  As a result, much of the error checking on the parameters to Start() has been moved into this\r
+  common boot service. It is legal to call Start() from other locations,\r
+  but the following calling restrictions must be followed or the system behavior will not be deterministic.\r
+  1. ControllerHandle must be a valid EFI_HANDLE.\r
+  2. If RemainingDevicePath is not NULL, then it must be a pointer to a naturally aligned\r
+     EFI_DEVICE_PATH_PROTOCOL.\r
+  3. Prior to calling Start(), the Supported() function for the driver specified by This must\r
+     have been called with the same calling parameters, and Supported() must have returned EFI_SUCCESS.\r
+\r
+  @param[in]  This                 A pointer to the EFI_DRIVER_BINDING_PROTOCOL instance.\r
+  @param[in]  ControllerHandle     The handle of the controller to start. This handle\r
+                                   must support a protocol interface that supplies\r
+                                   an I/O abstraction to the driver.\r
+  @param[in]  RemainingDevicePath  A pointer to the remaining portion of a device path.  This\r
+                                   parameter is ignored by device drivers, and is optional for bus\r
+                                   drivers. For a bus driver, if this parameter is NULL, then handles\r
+                                   for all the children of Controller are created by this driver.\r
+                                   If this parameter is not NULL and the first Device Path Node is\r
+                                   not the End of Device Path Node, then only the handle for the\r
+                                   child device specified by the first Device Path Node of\r
+                                   RemainingDevicePath is created by this driver.\r
+                                   If the first Device Path Node of RemainingDevicePath is\r
+                                   the End of Device Path Node, no child handle is created by this\r
+                                   driver.\r
+\r
+  @retval EFI_SUCCESS              The device was started.\r
+  @retval EFI_DEVICE_ERROR         The device could not be started due to a device error.Currently not implemented.\r
+  @retval EFI_OUT_OF_RESOURCES     The request could not be completed due to a lack of resources.\r
+  @retval Others                   The driver failded to start the device.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+EmmcDxeDriverBindingStart (\r
+  IN EFI_DRIVER_BINDING_PROTOCOL   *This,\r
+  IN EFI_HANDLE                    Controller,\r
+  IN EFI_DEVICE_PATH_PROTOCOL      *RemainingDevicePath\r
+  )\r
+{\r
+  EFI_STATUS                       Status;\r
+  EFI_SD_MMC_PASS_THRU_PROTOCOL    *PassThru;\r
+  EFI_DEVICE_PATH_PROTOCOL         *ParentDevicePath;\r
+  EMMC_DRIVER_PRIVATE_DATA         *Private;\r
+  UINT8                            Slot;\r
+\r
+  Private  = NULL;\r
+  PassThru = NULL;\r
+  Status = gBS->OpenProtocol (\r
+                  Controller,\r
+                  &gEfiSdMmcPassThruProtocolGuid,\r
+                  (VOID **) &PassThru,\r
+                  This->DriverBindingHandle,\r
+                  Controller,\r
+                  EFI_OPEN_PROTOCOL_BY_DRIVER\r
+                  );\r
+  if ((EFI_ERROR (Status)) && (Status != EFI_ALREADY_STARTED)) {\r
+    return Status;\r
+  }\r
+\r
+  //\r
+  // Check EFI_ALREADY_STARTED to reuse the original EMMC_DRIVER_PRIVATE_DATA.\r
+  //\r
+  if (Status != EFI_ALREADY_STARTED) {\r
+    Private = AllocateZeroPool (sizeof (EMMC_DRIVER_PRIVATE_DATA));\r
+    if (Private == NULL) {\r
+      Status = EFI_OUT_OF_RESOURCES;\r
+      goto Error;\r
+    }\r
+\r
+    Status = gBS->OpenProtocol (\r
+                    Controller,\r
+                    &gEfiDevicePathProtocolGuid,\r
+                    (VOID **) &ParentDevicePath,\r
+                    This->DriverBindingHandle,\r
+                    Controller,\r
+                    EFI_OPEN_PROTOCOL_GET_PROTOCOL\r
+                    );\r
+    ASSERT_EFI_ERROR (Status);\r
+    Private->PassThru            = PassThru;\r
+    Private->Controller          = Controller;\r
+    Private->ParentDevicePath    = ParentDevicePath;\r
+    Private->DriverBindingHandle = This->DriverBindingHandle;\r
+\r
+    Status = gBS->InstallProtocolInterface (\r
+                    &Controller,\r
+                    &gEfiCallerIdGuid,\r
+                    EFI_NATIVE_INTERFACE,\r
+                    Private\r
+                    );\r
+    if (EFI_ERROR (Status)) {\r
+      goto Error;\r
+    }\r
+  } else {\r
+    Status = gBS->OpenProtocol (\r
+                    Controller,\r
+                    &gEfiCallerIdGuid,\r
+                    (VOID **) &Private,\r
+                    This->DriverBindingHandle,\r
+                    Controller,\r
+                    EFI_OPEN_PROTOCOL_GET_PROTOCOL\r
+                    );\r
+    if (EFI_ERROR (Status)) {\r
+      goto Error;\r
+    }\r
+  }\r
+\r
+  if (RemainingDevicePath == NULL) {\r
+    Slot = 0xFF;\r
+    while (TRUE) {\r
+      Status = PassThru->GetNextSlot (PassThru, &Slot);\r
+      if (EFI_ERROR (Status)) {\r
+        //\r
+        // Cannot find more legal slots.\r
+        //\r
+        Status = EFI_SUCCESS;\r
+        break;\r
+      }\r
+\r
+      Status = DiscoverEmmcDevice (Private, Slot, NULL);\r
+      if (EFI_ERROR (Status) && (Status != EFI_ALREADY_STARTED)) {\r
+        break;\r
+      }\r
+    }\r
+  } else if (!IsDevicePathEnd (RemainingDevicePath)) {\r
+    Status = PassThru->GetSlotNumber (PassThru, RemainingDevicePath, &Slot);\r
+    if (!EFI_ERROR (Status)) {\r
+      Status = DiscoverEmmcDevice (Private, Slot, NextDevicePathNode (RemainingDevicePath));\r
+    }\r
+  }\r
+\r
+Error:\r
+  if (EFI_ERROR (Status) && (Status != EFI_ALREADY_STARTED)) {\r
+    gBS->CloseProtocol (\r
+           Controller,\r
+           &gEfiSdMmcPassThruProtocolGuid,\r
+           This->DriverBindingHandle,\r
+           Controller\r
+           );\r
+\r
+    if (Private != NULL) {\r
+      gBS->UninstallMultipleProtocolInterfaces (\r
+             Controller,\r
+             &gEfiCallerIdGuid,\r
+             Private,\r
+             NULL\r
+             );\r
+      FreePool (Private);\r
+    }\r
+  }\r
+  return Status;\r
+}\r
+\r
+/**\r
+  Stops a device controller or a bus controller.\r
+\r
+  The Stop() function is designed to be invoked from the EFI boot service DisconnectController().\r
+  As a result, much of the error checking on the parameters to Stop() has been moved\r
+  into this common boot service. It is legal to call Stop() from other locations,\r
+  but the following calling restrictions must be followed or the system behavior will not be deterministic.\r
+  1. ControllerHandle must be a valid EFI_HANDLE that was used on a previous call to this\r
+     same driver's Start() function.\r
+  2. The first NumberOfChildren handles of ChildHandleBuffer must all be a valid\r
+     EFI_HANDLE. In addition, all of these handles must have been created in this driver's\r
+     Start() function, and the Start() function must have called OpenProtocol() on\r
+     ControllerHandle with an Attribute of EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER.\r
+\r
+  @param[in]  This              A pointer to the EFI_DRIVER_BINDING_PROTOCOL instance.\r
+  @param[in]  ControllerHandle  A handle to the device being stopped. The handle must\r
+                                support a bus specific I/O protocol for the driver\r
+                                to use to stop the device.\r
+  @param[in]  NumberOfChildren  The number of child device handles in ChildHandleBuffer.\r
+  @param[in]  ChildHandleBuffer An array of child handles to be freed. May be NULL\r
+                                if NumberOfChildren is 0.\r
+\r
+  @retval EFI_SUCCESS           The device was stopped.\r
+  @retval EFI_DEVICE_ERROR      The device could not be stopped due to a device error.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+EmmcDxeDriverBindingStop (\r
+  IN  EFI_DRIVER_BINDING_PROTOCOL     *This,\r
+  IN  EFI_HANDLE                      Controller,\r
+  IN  UINTN                           NumberOfChildren,\r
+  IN  EFI_HANDLE                      *ChildHandleBuffer\r
+  )\r
+{\r
+  EFI_STATUS                             Status;\r
+  BOOLEAN                                AllChildrenStopped;\r
+  UINTN                                  Index;\r
+  EFI_DEVICE_PATH_PROTOCOL               *DevicePath;\r
+  EMMC_DRIVER_PRIVATE_DATA               *Private;\r
+  EMMC_DEVICE                            *Device;\r
+  EMMC_PARTITION                         *Partition;\r
+  EFI_BLOCK_IO_PROTOCOL                  *BlockIo;\r
+  EFI_BLOCK_IO2_PROTOCOL                 *BlockIo2;\r
+  EFI_STORAGE_SECURITY_COMMAND_PROTOCOL  *StorageSecurity;\r
+  LIST_ENTRY                             *Link;\r
+  LIST_ENTRY                             *NextLink;\r
+  EMMC_REQUEST                           *Request;\r
+\r
+  BlockIo  = NULL;\r
+  BlockIo2 = NULL;\r
+  if (NumberOfChildren == 0) {\r
+    Status = gBS->OpenProtocol (\r
+                    Controller,\r
+                    &gEfiCallerIdGuid,\r
+                    (VOID **) &Private,\r
+                    This->DriverBindingHandle,\r
+                    Controller,\r
+                    EFI_OPEN_PROTOCOL_GET_PROTOCOL\r
+                    );\r
+    if (EFI_ERROR (Status)) {\r
+      return EFI_DEVICE_ERROR;\r
+    }\r
+\r
+    for (Index = 0; Index < EMMC_MAX_DEVICES; Index++) {\r
+      Device = &Private->Device[Index];\r
+      Status = gBS->OpenProtocol (\r
+                      Device->Handle,\r
+                      &gEfiDevicePathProtocolGuid,\r
+                      (VOID **) &DevicePath,\r
+                      This->DriverBindingHandle,\r
+                      Controller,\r
+                      EFI_OPEN_PROTOCOL_GET_PROTOCOL\r
+                      );\r
+      if (EFI_ERROR (Status)) {\r
+        continue;\r
+      }\r
+      ASSERT (DevicePath == Device->DevicePath);\r
+      gBS->UninstallProtocolInterface (\r
+             Device->Handle,\r
+             &gEfiDevicePathProtocolGuid,\r
+             DevicePath\r
+             );\r
+      FreePool (Device->DevicePath);\r
+    }\r
+\r
+    gBS->UninstallProtocolInterface (\r
+          Controller,\r
+          &gEfiCallerIdGuid,\r
+          Private\r
+          );\r
+    gBS->CloseProtocol (\r
+          Controller,\r
+          &gEfiSdMmcPassThruProtocolGuid,\r
+          This->DriverBindingHandle,\r
+          Controller\r
+          );\r
+    FreePool (Private);\r
+\r
+    return EFI_SUCCESS;\r
+  }\r
+\r
+  AllChildrenStopped = TRUE;\r
+\r
+  for (Index = 0; Index < NumberOfChildren; Index++) {\r
+    Status = gBS->OpenProtocol (\r
+                    ChildHandleBuffer[Index],\r
+                    &gEfiBlockIoProtocolGuid,\r
+                    (VOID **) &BlockIo,\r
+                    This->DriverBindingHandle,\r
+                    Controller,\r
+                    EFI_OPEN_PROTOCOL_GET_PROTOCOL\r
+                    );\r
+    if (EFI_ERROR (Status)) {\r
+      Status = gBS->OpenProtocol (\r
+                      ChildHandleBuffer[Index],\r
+                      &gEfiBlockIo2ProtocolGuid,\r
+                      (VOID **) &BlockIo2,\r
+                      This->DriverBindingHandle,\r
+                      Controller,\r
+                      EFI_OPEN_PROTOCOL_GET_PROTOCOL\r
+                      );\r
+      if (EFI_ERROR (Status)) {\r
+        AllChildrenStopped = FALSE;\r
+        continue;\r
+      }\r
+    }\r
+\r
+    if (BlockIo != NULL) {\r
+      Partition = EMMC_PARTITION_DATA_FROM_BLKIO (BlockIo);\r
+    } else {\r
+      ASSERT (BlockIo2 != NULL);\r
+      Partition = EMMC_PARTITION_DATA_FROM_BLKIO2 (BlockIo2);\r
+    }\r
+\r
+    for (Link = GetFirstNode (&Partition->Queue);\r
+         !IsNull (&Partition->Queue, Link);\r
+         Link = NextLink) {\r
+      NextLink = GetNextNode (&Partition->Queue, Link);\r
+\r
+      RemoveEntryList (Link);\r
+      Request = EMMC_REQUEST_FROM_LINK (Link);\r
+\r
+      gBS->CloseEvent (Request->Event);\r
+      Request->Token->TransactionStatus = EFI_ABORTED;\r
+\r
+      if (Request->IsEnd) {\r
+        gBS->SignalEvent (Request->Token->Event);\r
+      }\r
+\r
+      FreePool (Request);\r
+    }\r
+\r
+    //\r
+    // Close the child handle\r
+    //\r
+    Status = gBS->CloseProtocol (\r
+                    Controller,\r
+                    &gEfiSdMmcPassThruProtocolGuid,\r
+                    This->DriverBindingHandle,\r
+                    ChildHandleBuffer[Index]\r
+                    );\r
+\r
+    Status = gBS->UninstallMultipleProtocolInterfaces (\r
+                    ChildHandleBuffer[Index],\r
+                    &gEfiDevicePathProtocolGuid,\r
+                    Partition->DevicePath,\r
+                    &gEfiBlockIoProtocolGuid,\r
+                    &Partition->BlockIo,\r
+                    &gEfiBlockIo2ProtocolGuid,\r
+                    &Partition->BlockIo2,\r
+                    NULL\r
+                    );\r
+    if (EFI_ERROR (Status)) {\r
+      AllChildrenStopped = FALSE;\r
+      gBS->OpenProtocol (\r
+             Controller,\r
+             &gEfiSdMmcPassThruProtocolGuid,\r
+             (VOID **)&Partition->Device->Private->PassThru,\r
+             This->DriverBindingHandle,\r
+             ChildHandleBuffer[Index],\r
+             EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER\r
+             );\r
+      continue;\r
+    }\r
+\r
+    //\r
+    // If Storage Security Command Protocol is installed, then uninstall this protocol.\r
+    //\r
+    Status = gBS->OpenProtocol (\r
+                    ChildHandleBuffer[Index],\r
+                    &gEfiStorageSecurityCommandProtocolGuid,\r
+                    (VOID **) &StorageSecurity,\r
+                    This->DriverBindingHandle,\r
+                    Controller,\r
+                    EFI_OPEN_PROTOCOL_GET_PROTOCOL\r
+                    );\r
+\r
+    if (!EFI_ERROR (Status)) {\r
+      Status = gBS->UninstallProtocolInterface (\r
+                      ChildHandleBuffer[Index],\r
+                      &gEfiStorageSecurityCommandProtocolGuid,\r
+                      &Partition->StorageSecurity\r
+                      );\r
+      if (EFI_ERROR (Status)) {\r
+        gBS->OpenProtocol (\r
+          Controller,\r
+          &gEfiSdMmcPassThruProtocolGuid,\r
+          (VOID **) &Partition->Device->Private->PassThru,\r
+          This->DriverBindingHandle,\r
+          ChildHandleBuffer[Index],\r
+          EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER\r
+          );\r
+        AllChildrenStopped = FALSE;\r
+        continue;\r
+      }\r
+    }\r
+\r
+    FreePool (Partition->DevicePath);\r
+  }\r
+\r
+  if (!AllChildrenStopped) {\r
+    return EFI_DEVICE_ERROR;\r
+  }\r
+\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+  The user Entry Point for module EmmcDxe. The user code starts with this function.\r
+\r
+  @param[in] ImageHandle    The firmware allocated handle for the EFI image.\r
+  @param[in] SystemTable    A pointer to the EFI System Table.\r
+\r
+  @retval EFI_SUCCESS       The entry point is executed successfully.\r
+  @retval other             Some errors occur when executing this entry point.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+InitializeEmmcDxe (\r
+  IN EFI_HANDLE           ImageHandle,\r
+  IN EFI_SYSTEM_TABLE     *SystemTable\r
+  )\r
+{\r
+  EFI_STATUS              Status;\r
+\r
+  //\r
+  // Install driver model protocol(s).\r
+  //\r
+  Status = EfiLibInstallDriverBindingComponentName2 (\r
+             ImageHandle,\r
+             SystemTable,\r
+             &gEmmcDxeDriverBinding,\r
+             ImageHandle,\r
+             &gEmmcDxeComponentName,\r
+             &gEmmcDxeComponentName2\r
+             );\r
+  ASSERT_EFI_ERROR (Status);\r
+\r
+  return Status;\r
+}\r
+\r
diff --git a/MdeModulePkg/Bus/Sd/EmmcDxe/EmmcDxe.h b/MdeModulePkg/Bus/Sd/EmmcDxe/EmmcDxe.h
new file mode 100644 (file)
index 0000000..a463e34
--- /dev/null
@@ -0,0 +1,495 @@
+/** @file\r
+  Header file for EmmcDxe Driver.\r
+\r
+  This file defines common data structures, macro definitions and some module\r
+  internal function header files.\r
+\r
+  Copyright (c) 2015, Intel Corporation. All rights reserved.<BR>\r
+  This program and the accompanying materials\r
+  are licensed and made available under the terms and conditions of the BSD License\r
+  which accompanies this distribution.  The full text of the license may be found at\r
+  http://opensource.org/licenses/bsd-license.php\r
+\r
+  THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+  WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+\r
+**/\r
+\r
+#ifndef _EMMC_DXE_H_\r
+#define _EMMC_DXE_H_\r
+\r
+#include <Uefi.h>\r
+#include <IndustryStandard/Emmc.h>\r
+\r
+#include <Protocol/SdMmcPassThru.h>\r
+#include <Protocol/BlockIo.h>\r
+#include <Protocol/BlockIo2.h>\r
+#include <Protocol/StorageSecurityCommand.h>\r
+\r
+#include <Protocol/DevicePath.h>\r
+\r
+#include <Library/DebugLib.h>\r
+#include <Library/UefiDriverEntryPoint.h>\r
+#include <Library/BaseLib.h>\r
+#include <Library/UefiLib.h>\r
+#include <Library/BaseMemoryLib.h>\r
+#include <Library/MemoryAllocationLib.h>\r
+#include <Library/UefiBootServicesTableLib.h>\r
+#include <Library/DevicePathLib.h>\r
+#include <Library/UefiRuntimeServicesTableLib.h>\r
+\r
+#include "EmmcBlockIo.h"\r
+//\r
+// Global Variables\r
+//\r
+extern EFI_DRIVER_BINDING_PROTOCOL      gEmmcDxeDriverBinding;\r
+extern EFI_COMPONENT_NAME_PROTOCOL      gEmmcDxeComponentName;\r
+extern EFI_COMPONENT_NAME2_PROTOCOL     gEmmcDxeComponentName2;\r
+\r
+#define EMMC_PARTITION_SIGNATURE        SIGNATURE_32 ('E', 'm', 'm', 'P')\r
+\r
+#define EMMC_PARTITION_DATA_FROM_BLKIO(a) \\r
+    CR(a, EMMC_PARTITION, BlockIo, EMMC_PARTITION_SIGNATURE)\r
+\r
+#define EMMC_PARTITION_DATA_FROM_BLKIO2(a) \\r
+    CR(a, EMMC_PARTITION, BlockIo2, EMMC_PARTITION_SIGNATURE)\r
+\r
+#define EMMC_PARTITION_DATA_FROM_SSP(a) \\r
+    CR(a, EMMC_PARTITION, StorageSecurity, EMMC_PARTITION_SIGNATURE)\r
+\r
+//\r
+// Take 2.5 seconds as generic time out value, 1 microsecond as unit.\r
+//\r
+#define EMMC_GENERIC_TIMEOUT             2500 * 1000\r
+\r
+#define EMMC_REQUEST_SIGNATURE           SIGNATURE_32 ('E', 'm', 'R', 'e')\r
+\r
+typedef struct _EMMC_DEVICE              EMMC_DEVICE;\r
+typedef struct _EMMC_DRIVER_PRIVATE_DATA EMMC_DRIVER_PRIVATE_DATA;\r
+\r
+//\r
+// Asynchronous I/O request.\r
+//\r
+typedef struct {\r
+  UINT32                                Signature;\r
+  LIST_ENTRY                            Link;\r
+\r
+  EFI_SD_MMC_COMMAND_BLOCK              SdMmcCmdBlk;\r
+  EFI_SD_MMC_STATUS_BLOCK               SdMmcStatusBlk;\r
+  EFI_SD_MMC_PASS_THRU_COMMAND_PACKET   Packet;\r
+\r
+  BOOLEAN                               IsEnd;\r
+\r
+  EFI_BLOCK_IO2_TOKEN                   *Token;\r
+  EFI_EVENT                             Event;\r
+} EMMC_REQUEST;\r
+\r
+#define EMMC_REQUEST_FROM_LINK(a) \\r
+    CR(a, EMMC_REQUEST, Link, EMMC_REQUEST_SIGNATURE)\r
+\r
+typedef struct {\r
+  UINT32                                Signature;\r
+  BOOLEAN                               Enable;\r
+  EMMC_PARTITION_TYPE                   PartitionType;\r
+  EFI_HANDLE                            Handle;\r
+  EFI_DEVICE_PATH_PROTOCOL              *DevicePath;\r
+  EFI_BLOCK_IO_PROTOCOL                 BlockIo;\r
+  EFI_BLOCK_IO2_PROTOCOL                BlockIo2;\r
+  EFI_BLOCK_IO_MEDIA                    BlockMedia;\r
+  EFI_STORAGE_SECURITY_COMMAND_PROTOCOL StorageSecurity;\r
+\r
+  LIST_ENTRY                            Queue;\r
+\r
+  EMMC_DEVICE                           *Device;\r
+} EMMC_PARTITION;\r
+\r
+//\r
+// Up to 6 slots per EMMC PCI host controller\r
+//\r
+#define EMMC_MAX_DEVICES                6\r
+//\r
+// Up to 8 partitions per EMMC device.\r
+//\r
+#define EMMC_MAX_PARTITIONS             8\r
+#define EMMC_MODEL_NAME_MAX_LEN         32\r
+\r
+struct _EMMC_DEVICE {\r
+  EFI_HANDLE                            Handle;\r
+  EFI_DEVICE_PATH_PROTOCOL              *DevicePath;\r
+  UINT8                                 Slot;\r
+  BOOLEAN                               SectorAddressing;\r
+\r
+  EMMC_PARTITION                        Partition[EMMC_MAX_PARTITIONS];\r
+  EMMC_CSD                              Csd;\r
+  EMMC_CID                              Cid;\r
+  EMMC_EXT_CSD                          ExtCsd;\r
+  EFI_UNICODE_STRING_TABLE              *ControllerNameTable;\r
+  //\r
+  // The model name consists of three fields in CID register\r
+  // 1) OEM/Application ID (2 bytes)\r
+  // 2) Product Name       (5 bytes)\r
+  // 3) Product Serial Number (4 bytes)\r
+  // The delimiters of these fields are whitespace.\r
+  //\r
+  CHAR16                                ModelName[EMMC_MODEL_NAME_MAX_LEN];\r
+  EMMC_DRIVER_PRIVATE_DATA              *Private;\r
+} ;\r
+\r
+//\r
+// EMMC DXE driver private data structure\r
+//\r
+struct _EMMC_DRIVER_PRIVATE_DATA {\r
+  EFI_SD_MMC_PASS_THRU_PROTOCOL         *PassThru;\r
+  EFI_HANDLE                            Controller;\r
+  EFI_DEVICE_PATH_PROTOCOL              *ParentDevicePath;\r
+  EFI_HANDLE                            DriverBindingHandle;\r
+\r
+  EMMC_DEVICE                           Device[EMMC_MAX_DEVICES];\r
+} ;\r
+\r
+/**\r
+  Tests to see if this driver supports a given controller. If a child device is provided,\r
+  it further tests to see if this driver supports creating a handle for the specified child device.\r
+\r
+  This function checks to see if the driver specified by This supports the device specified by\r
+  ControllerHandle. Drivers will typically use the device path attached to\r
+  ControllerHandle and/or the services from the bus I/O abstraction attached to\r
+  ControllerHandle to determine if the driver supports ControllerHandle. This function\r
+  may be called many times during platform initialization. In order to reduce boot times, the tests\r
+  performed by this function must be very small, and take as little time as possible to execute. This\r
+  function must not change the state of any hardware devices, and this function must be aware that the\r
+  device specified by ControllerHandle may already be managed by the same driver or a\r
+  different driver. This function must match its calls to AllocatePages() with FreePages(),\r
+  AllocatePool() with FreePool(), and OpenProtocol() with CloseProtocol().\r
+  Since ControllerHandle may have been previously started by the same driver, if a protocol is\r
+  already in the opened state, then it must not be closed with CloseProtocol(). This is required\r
+  to guarantee the state of ControllerHandle is not modified by this function.\r
+\r
+  @param[in]  This                 A pointer to the EFI_DRIVER_BINDING_PROTOCOL instance.\r
+  @param[in]  ControllerHandle     The handle of the controller to test. This handle\r
+                                   must support a protocol interface that supplies\r
+                                   an I/O abstraction to the driver.\r
+  @param[in]  RemainingDevicePath  A pointer to the remaining portion of a device path.  This\r
+                                   parameter is ignored by device drivers, and is optional for bus\r
+                                   drivers. For bus drivers, if this parameter is not NULL, then\r
+                                   the bus driver must determine if the bus controller specified\r
+                                   by ControllerHandle and the child controller specified\r
+                                   by RemainingDevicePath are both supported by this\r
+                                   bus driver.\r
+\r
+  @retval EFI_SUCCESS              The device specified by ControllerHandle and\r
+                                   RemainingDevicePath is supported by the driver specified by This.\r
+  @retval EFI_ALREADY_STARTED      The device specified by ControllerHandle and\r
+                                   RemainingDevicePath is already being managed by the driver\r
+                                   specified by This.\r
+  @retval EFI_ACCESS_DENIED        The device specified by ControllerHandle and\r
+                                   RemainingDevicePath is already being managed by a different\r
+                                   driver or an application that requires exclusive access.\r
+                                   Currently not implemented.\r
+  @retval EFI_UNSUPPORTED          The device specified by ControllerHandle and\r
+                                   RemainingDevicePath is not supported by the driver specified by This.\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+EmmcDxeDriverBindingSupported (\r
+  IN EFI_DRIVER_BINDING_PROTOCOL   *This,\r
+  IN EFI_HANDLE                    Controller,\r
+  IN EFI_DEVICE_PATH_PROTOCOL      *RemainingDevicePath\r
+  );\r
+\r
+/**\r
+  Starts a device controller or a bus controller.\r
+\r
+  The Start() function is designed to be invoked from the EFI boot service ConnectController().\r
+  As a result, much of the error checking on the parameters to Start() has been moved into this\r
+  common boot service. It is legal to call Start() from other locations,\r
+  but the following calling restrictions must be followed or the system behavior will not be deterministic.\r
+  1. ControllerHandle must be a valid EFI_HANDLE.\r
+  2. If RemainingDevicePath is not NULL, then it must be a pointer to a naturally aligned\r
+     EFI_DEVICE_PATH_PROTOCOL.\r
+  3. Prior to calling Start(), the Supported() function for the driver specified by This must\r
+     have been called with the same calling parameters, and Supported() must have returned EFI_SUCCESS.\r
+\r
+  @param[in]  This                 A pointer to the EFI_DRIVER_BINDING_PROTOCOL instance.\r
+  @param[in]  ControllerHandle     The handle of the controller to start. This handle\r
+                                   must support a protocol interface that supplies\r
+                                   an I/O abstraction to the driver.\r
+  @param[in]  RemainingDevicePath  A pointer to the remaining portion of a device path.  This\r
+                                   parameter is ignored by device drivers, and is optional for bus\r
+                                   drivers. For a bus driver, if this parameter is NULL, then handles\r
+                                   for all the children of Controller are created by this driver.\r
+                                   If this parameter is not NULL and the first Device Path Node is\r
+                                   not the End of Device Path Node, then only the handle for the\r
+                                   child device specified by the first Device Path Node of\r
+                                   RemainingDevicePath is created by this driver.\r
+                                   If the first Device Path Node of RemainingDevicePath is\r
+                                   the End of Device Path Node, no child handle is created by this\r
+                                   driver.\r
+\r
+  @retval EFI_SUCCESS              The device was started.\r
+  @retval EFI_DEVICE_ERROR         The device could not be started due to a device error.Currently not implemented.\r
+  @retval EFI_OUT_OF_RESOURCES     The request could not be completed due to a lack of resources.\r
+  @retval Others                   The driver failded to start the device.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+EmmcDxeDriverBindingStart (\r
+  IN EFI_DRIVER_BINDING_PROTOCOL   *This,\r
+  IN EFI_HANDLE                    Controller,\r
+  IN EFI_DEVICE_PATH_PROTOCOL      *RemainingDevicePath\r
+  );\r
+\r
+/**\r
+  Stops a device controller or a bus controller.\r
+\r
+  The Stop() function is designed to be invoked from the EFI boot service DisconnectController().\r
+  As a result, much of the error checking on the parameters to Stop() has been moved\r
+  into this common boot service. It is legal to call Stop() from other locations,\r
+  but the following calling restrictions must be followed or the system behavior will not be deterministic.\r
+  1. ControllerHandle must be a valid EFI_HANDLE that was used on a previous call to this\r
+     same driver's Start() function.\r
+  2. The first NumberOfChildren handles of ChildHandleBuffer must all be a valid\r
+     EFI_HANDLE. In addition, all of these handles must have been created in this driver's\r
+     Start() function, and the Start() function must have called OpenProtocol() on\r
+     ControllerHandle with an Attribute of EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER.\r
+\r
+  @param[in]  This              A pointer to the EFI_DRIVER_BINDING_PROTOCOL instance.\r
+  @param[in]  ControllerHandle  A handle to the device being stopped. The handle must\r
+                                support a bus specific I/O protocol for the driver\r
+                                to use to stop the device.\r
+  @param[in]  NumberOfChildren  The number of child device handles in ChildHandleBuffer.\r
+  @param[in]  ChildHandleBuffer An array of child handles to be freed. May be NULL\r
+                                if NumberOfChildren is 0.\r
+\r
+  @retval EFI_SUCCESS           The device was stopped.\r
+  @retval EFI_DEVICE_ERROR      The device could not be stopped due to a device error.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+EmmcDxeDriverBindingStop (\r
+  IN  EFI_DRIVER_BINDING_PROTOCOL     *This,\r
+  IN  EFI_HANDLE                      Controller,\r
+  IN  UINTN                           NumberOfChildren,\r
+  IN  EFI_HANDLE                      *ChildHandleBuffer\r
+  );\r
+\r
+/**\r
+  Retrieves a Unicode string that is the user readable name of the driver.\r
+\r
+  This function retrieves the user readable name of a driver in the form of a\r
+  Unicode string. If the driver specified by This has a user readable name in\r
+  the language specified by Language, then a pointer to the driver name is\r
+  returned in DriverName, and EFI_SUCCESS is returned. If the driver specified\r
+  by This does not support the language specified by Language,\r
+  then EFI_UNSUPPORTED is returned.\r
+\r
+  @param  This[in]              A pointer to the EFI_COMPONENT_NAME2_PROTOCOL or\r
+                                EFI_COMPONENT_NAME_PROTOCOL instance.\r
+\r
+  @param  Language[in]          A pointer to a Null-terminated ASCII string\r
+                                array indicating the language. This is the\r
+                                language of the driver name that the caller is\r
+                                requesting, and it must match one of the\r
+                                languages specified in SupportedLanguages. The\r
+                                number of languages supported by a driver is up\r
+                                to the driver writer. Language is specified\r
+                                in RFC 4646 or ISO 639-2 language code format.\r
+\r
+  @param  DriverName[out]       A pointer to the Unicode string to return.\r
+                                This Unicode string is the name of the\r
+                                driver specified by This in the language\r
+                                specified by Language.\r
+\r
+  @retval EFI_SUCCESS           The Unicode string for the Driver specified by\r
+                                This and the language specified by Language was\r
+                                returned in DriverName.\r
+\r
+  @retval EFI_INVALID_PARAMETER Language is NULL.\r
+\r
+  @retval EFI_INVALID_PARAMETER DriverName is NULL.\r
+\r
+  @retval EFI_UNSUPPORTED       The driver specified by This does not support\r
+                                the language specified by Language.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+EmmcDxeComponentNameGetDriverName (\r
+  IN  EFI_COMPONENT_NAME_PROTOCOL  *This,\r
+  IN  CHAR8                        *Language,\r
+  OUT CHAR16                       **DriverName\r
+  );\r
+\r
+/**\r
+  Retrieves a Unicode string that is the user readable name of the controller\r
+  that is being managed by a driver.\r
+\r
+  This function retrieves the user readable name of the controller specified by\r
+  ControllerHandle and ChildHandle in the form of a Unicode string. If the\r
+  driver specified by This has a user readable name in the language specified by\r
+  Language, then a pointer to the controller name is returned in ControllerName,\r
+  and EFI_SUCCESS is returned.  If the driver specified by This is not currently\r
+  managing the controller specified by ControllerHandle and ChildHandle,\r
+  then EFI_UNSUPPORTED is returned.  If the driver specified by This does not\r
+  support the language specified by Language, then EFI_UNSUPPORTED is returned.\r
+\r
+  @param  This[in]              A pointer to the EFI_COMPONENT_NAME2_PROTOCOL or\r
+                                EFI_COMPONENT_NAME_PROTOCOL instance.\r
+\r
+  @param  ControllerHandle[in]  The handle of a controller that the driver\r
+                                specified by This is managing.  This handle\r
+                                specifies the controller whose name is to be\r
+                                returned.\r
+\r
+  @param  ChildHandle[in]       The handle of the child controller to retrieve\r
+                                the name of.  This is an optional parameter that\r
+                                may be NULL.  It will be NULL for device\r
+                                drivers.  It will also be NULL for a bus drivers\r
+                                that wish to retrieve the name of the bus\r
+                                controller.  It will not be NULL for a bus\r
+                                driver that wishes to retrieve the name of a\r
+                                child controller.\r
+\r
+  @param  Language[in]          A pointer to a Null-terminated ASCII string\r
+                                array indicating the language.  This is the\r
+                                language of the driver name that the caller is\r
+                                requesting, and it must match one of the\r
+                                languages specified in SupportedLanguages. The\r
+                                number of languages supported by a driver is up\r
+                                to the driver writer. Language is specified in\r
+                                RFC 4646 or ISO 639-2 language code format.\r
+\r
+  @param  ControllerName[out]   A pointer to the Unicode string to return.\r
+                                This Unicode string is the name of the\r
+                                controller specified by ControllerHandle and\r
+                                ChildHandle in the language specified by\r
+                                Language from the point of view of the driver\r
+                                specified by This.\r
+\r
+  @retval EFI_SUCCESS           The Unicode string for the user readable name in\r
+                                the language specified by Language for the\r
+                                driver specified by This was returned in\r
+                                DriverName.\r
+\r
+  @retval EFI_INVALID_PARAMETER ControllerHandle is NULL.\r
+\r
+  @retval EFI_INVALID_PARAMETER ChildHandle is not NULL and it is not a valid\r
+                                EFI_HANDLE.\r
+\r
+  @retval EFI_INVALID_PARAMETER Language is NULL.\r
+\r
+  @retval EFI_INVALID_PARAMETER ControllerName is NULL.\r
+\r
+  @retval EFI_UNSUPPORTED       The driver specified by This is not currently\r
+                                managing the controller specified by\r
+                                ControllerHandle and ChildHandle.\r
+\r
+  @retval EFI_UNSUPPORTED       The driver specified by This does not support\r
+                                the language specified by Language.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+EmmcDxeComponentNameGetControllerName (\r
+  IN  EFI_COMPONENT_NAME_PROTOCOL                     *This,\r
+  IN  EFI_HANDLE                                      ControllerHandle,\r
+  IN  EFI_HANDLE                                      ChildHandle        OPTIONAL,\r
+  IN  CHAR8                                           *Language,\r
+  OUT CHAR16                                          **ControllerName\r
+  );\r
+\r
+/**\r
+  Send command SELECT to the device to select/deselect the device.\r
+\r
+  @param[in]  Device            A pointer to the EMMC_DEVICE instance.\r
+  @param[in]  Rca               The relative device address to use.\r
+\r
+  @retval EFI_SUCCESS           The request is executed successfully.\r
+  @retval EFI_OUT_OF_RESOURCES  The request could not be executed due to a lack of resources.\r
+  @retval Others                The request could not be executed successfully.\r
+\r
+**/\r
+EFI_STATUS\r
+EmmcSelect (\r
+  IN     EMMC_DEVICE            *Device,\r
+  IN     UINT16                 Rca\r
+  );\r
+\r
+/**\r
+  Send command SEND_STATUS to the device to get device status.\r
+\r
+  @param[in]  Device            A pointer to the EMMC_DEVICE instance.\r
+  @param[in]  Rca               The relative device address to use.\r
+  @param[out] DevStatus         The buffer to store the device status.\r
+\r
+  @retval EFI_SUCCESS           The request is executed successfully.\r
+  @retval EFI_OUT_OF_RESOURCES  The request could not be executed due to a lack of resources.\r
+  @retval Others                The request could not be executed successfully.\r
+\r
+**/\r
+EFI_STATUS\r
+EmmcSendStatus (\r
+  IN     EMMC_DEVICE            *Device,\r
+  IN     UINT16                 Rca,\r
+     OUT UINT32                 *DevStatus\r
+  );\r
+\r
+/**\r
+  Send command SEND_CSD to the device to get the CSD register data.\r
+\r
+  @param[in]  Device            A pointer to the EMMC_DEVICE instance.\r
+  @param[in]  Rca               The relative device address to use.\r
+  @param[out] Csd               The buffer to store the EMMC_CSD register data.\r
+\r
+  @retval EFI_SUCCESS           The request is executed successfully.\r
+  @retval EFI_OUT_OF_RESOURCES  The request could not be executed due to a lack of resources.\r
+  @retval Others                The request could not be executed successfully.\r
+\r
+**/\r
+EFI_STATUS\r
+EmmcGetCsd (\r
+  IN     EMMC_DEVICE            *Device,\r
+  IN     UINT16                 Rca,\r
+     OUT EMMC_CSD               *Csd\r
+  );\r
+\r
+/**\r
+  Send command SEND_CID to the device to get the CID register data.\r
+\r
+  @param[in]  Device            A pointer to the EMMC_DEVICE instance.\r
+  @param[in]  Rca               The relative device address to use.\r
+  @param[out] Csd               The buffer to store the EMMC_CSD register data.\r
+\r
+  @retval EFI_SUCCESS           The request is executed successfully.\r
+  @retval EFI_OUT_OF_RESOURCES  The request could not be executed due to a lack of resources.\r
+  @retval Others                The request could not be executed successfully.\r
+\r
+**/\r
+EFI_STATUS\r
+EmmcGetCid (\r
+  IN     EMMC_DEVICE            *Device,\r
+  IN     UINT16                 Rca,\r
+     OUT EMMC_CID               *Cid\r
+  );\r
+\r
+/**\r
+  Send command SEND_EXT_CSD to the device to get the EXT_CSD register data.\r
+\r
+  @param[in]  Device            A pointer to the EMMC_DEVICE instance.\r
+  @param[out] ExtCsd            The buffer to store the EXT_CSD register data.\r
+\r
+  @retval EFI_SUCCESS           The request is executed successfully.\r
+  @retval EFI_OUT_OF_RESOURCES  The request could not be executed due to a lack of resources.\r
+  @retval Others                The request could not be executed successfully.\r
+\r
+**/\r
+EFI_STATUS\r
+EmmcGetExtCsd (\r
+  IN     EMMC_DEVICE            *Device,\r
+     OUT EMMC_EXT_CSD           *ExtCsd\r
+  );\r
+\r
+#endif\r
+\r
diff --git a/MdeModulePkg/Bus/Sd/EmmcDxe/EmmcDxe.inf b/MdeModulePkg/Bus/Sd/EmmcDxe/EmmcDxe.inf
new file mode 100644 (file)
index 0000000..a10bcd2
--- /dev/null
@@ -0,0 +1,66 @@
+## @file\r
+#  EmmcDxe driver is used to manage the EMMC device.\r
+#\r
+#  It produces BlockIo, BlockIo2 and StorageSecurity protocols to allow upper layer\r
+#  access the EMMC device.\r
+#\r
+#  Copyright (c) 2015, Intel Corporation. All rights reserved.<BR>\r
+#\r
+#  This program and the accompanying materials\r
+#  are licensed and made available under the terms and conditions of the BSD License\r
+#  which accompanies this distribution. The full text of the license may be found at\r
+#  http://opensource.org/licenses/bsd-license.php\r
+#  THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+#  WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+#\r
+#\r
+##\r
+\r
+[Defines]\r
+  INF_VERSION                    = 0x00010005\r
+  BASE_NAME                      = EmmcDxe\r
+  MODULE_UNI_FILE                = EmmcDxe.uni\r
+  FILE_GUID                      = 2145F72F-E6F1-4440-A828-59DC9AAB5F89\r
+  MODULE_TYPE                    = UEFI_DRIVER\r
+  VERSION_STRING                 = 1.0\r
+  ENTRY_POINT                    = InitializeEmmcDxe\r
+\r
+#\r
+# The following information is for reference only and not required by the build tools.\r
+#\r
+#  VALID_ARCHITECTURES           = IA32 X64 IPF EBC\r
+#\r
+#  DRIVER_BINDING                =  gEmmcDxeDriverBinding\r
+#  COMPONENT_NAME                =  gEmmcDxeComponentName\r
+#  COMPONENT_NAME2               =  gEmmcDxeComponentName2\r
+#\r
+\r
+[Sources.common]\r
+  ComponentName.c\r
+  EmmcDxe.c\r
+  EmmcDxe.h\r
+  EmmcBlockIo.c\r
+  EmmcBlockIo.h\r
+\r
+[Packages]\r
+  MdePkg/MdePkg.dec\r
+\r
+[LibraryClasses]\r
+  DevicePathLib\r
+  UefiBootServicesTableLib\r
+  MemoryAllocationLib\r
+  BaseMemoryLib\r
+  UefiLib\r
+  BaseLib\r
+  UefiDriverEntryPoint\r
+  DebugLib\r
+\r
+[Protocols]\r
+  gEfiSdMmcPassThruProtocolGuid                ## TO_START\r
+  gEfiBlockIoProtocolGuid                      ## BY_START\r
+  gEfiBlockIo2ProtocolGuid                     ## BY_START\r
+  gEfiStorageSecurityCommandProtocolGuid       ## SOMETIMES_PRODUCES\r
+  ## TO_START\r
+  ## BY_START\r
+  gEfiDevicePathProtocolGuid\r
+\r
diff --git a/MdeModulePkg/Bus/Sd/EmmcDxe/EmmcDxe.uni b/MdeModulePkg/Bus/Sd/EmmcDxe/EmmcDxe.uni
new file mode 100644 (file)
index 0000000..a0c9cf2
--- /dev/null
@@ -0,0 +1,20 @@
+// /** @file\r
+// EMMC device driver to manage the EMMC device and provide interface for upper layer\r
+// access.\r
+//\r
+// Copyright (c) 2015, Intel Corporation. All rights reserved.<BR>\r
+//\r
+// This program and the accompanying materials\r
+// are licensed and made available under the terms and conditions of the BSD License\r
+// which accompanies this distribution. The full text of the license may be found at\r
+// http://opensource.org/licenses/bsd-license.php\r
+// THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+// WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+//\r
+// **/\r
+\r
+\r
+#string STR_MODULE_ABSTRACT             #language en-US "EMMC device driver to manage the EMMC device and provide interface for upper layer access"\r
+\r
+#string STR_MODULE_DESCRIPTION          #language en-US "This driver follows the UEFI driver model and layers on the SdMmcPassThru protocol. It installs BlockIo/BlockIo2/StorageSecurity protocols for the EMMC device partitions."\r
+\r
diff --git a/MdeModulePkg/Bus/Sd/EmmcDxe/EmmcDxeExtra.uni b/MdeModulePkg/Bus/Sd/EmmcDxe/EmmcDxeExtra.uni
new file mode 100644 (file)
index 0000000..083b4f6
--- /dev/null
@@ -0,0 +1,19 @@
+// /** @file\r
+// EmmcDxe Localized Strings and Content\r
+//\r
+// Copyright (c) 2015, Intel Corporation. All rights reserved.<BR>\r
+//\r
+// This program and the accompanying materials\r
+// are licensed and made available under the terms and conditions of the BSD License\r
+// which accompanies this distribution. The full text of the license may be found at\r
+// http://opensource.org/licenses/bsd-license.php\r
+// THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+// WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+//\r
+// **/\r
+\r
+#string STR_PROPERTIES_MODULE_NAME\r
+#language en-US\r
+"EMMC Device Driver"\r
+\r
+\r
diff --git a/MdeModulePkg/Bus/Sd/SdBlockIoPei/SdBlockIoPei.c b/MdeModulePkg/Bus/Sd/SdBlockIoPei/SdBlockIoPei.c
new file mode 100644 (file)
index 0000000..6dc343e
--- /dev/null
@@ -0,0 +1,617 @@
+/** @file\r
+\r
+  Copyright (c) 2015, Intel Corporation. All rights reserved.<BR>\r
+  This program and the accompanying materials\r
+  are licensed and made available under the terms and conditions of the BSD License\r
+  which accompanies this distribution.  The full text of the license may be found at\r
+  http://opensource.org/licenses/bsd-license.php\r
+\r
+  THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+  WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+\r
+**/\r
+\r
+#include "SdBlockIoPei.h"\r
+\r
+//\r
+// Template for SD HC Slot Data.\r
+//\r
+SD_PEIM_HC_SLOT   gSdHcSlotTemplate = {\r
+  SD_PEIM_SLOT_SIG,               // Signature\r
+  {                               // Media\r
+    MSG_SD_DP,\r
+    FALSE,\r
+    TRUE,\r
+    FALSE,\r
+    0x200,\r
+    0\r
+  },\r
+  0,                              // SdHcBase\r
+  {                               // Capability\r
+    0,\r
+  },\r
+  {                               // Csd\r
+    0,\r
+  },\r
+  TRUE,                           // SectorAddressing\r
+  NULL                            // Private\r
+};\r
+\r
+//\r
+// Template for SD HC Private Data.\r
+//\r
+SD_PEIM_HC_PRIVATE_DATA gSdHcPrivateTemplate = {\r
+  SD_PEIM_SIG,                    // Signature\r
+  NULL,                           // Pool\r
+  {                               // BlkIoPpi\r
+    SdBlockIoPeimGetDeviceNo,\r
+    SdBlockIoPeimGetMediaInfo,\r
+    SdBlockIoPeimReadBlocks\r
+  },\r
+  {                               // BlkIo2Ppi\r
+    EFI_PEI_RECOVERY_BLOCK_IO2_PPI_REVISION,\r
+    SdBlockIoPeimGetDeviceNo2,\r
+    SdBlockIoPeimGetMediaInfo2,\r
+    SdBlockIoPeimReadBlocks2\r
+  },\r
+  {                               // BlkIoPpiList\r
+    EFI_PEI_PPI_DESCRIPTOR_PPI,\r
+    &gEfiPeiVirtualBlockIoPpiGuid,\r
+    NULL\r
+  },\r
+  {                               // BlkIo2PpiList\r
+    EFI_PEI_PPI_DESCRIPTOR_PPI | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST,\r
+    &gEfiPeiVirtualBlockIo2PpiGuid,\r
+    NULL\r
+  },\r
+  {                               // Slot\r
+    {\r
+      0,\r
+    },\r
+    {\r
+      0,\r
+    },\r
+    {\r
+      0,\r
+    },\r
+    {\r
+      0,\r
+    },\r
+    {\r
+      0,\r
+    },\r
+    {\r
+      0,\r
+    }\r
+  },\r
+  0,                              // SlotNum\r
+  0                               // TotalBlkIoDevices\r
+};\r
+/**\r
+  Gets the count of block I/O devices that one specific block driver detects.\r
+\r
+  This function is used for getting the count of block I/O devices that one\r
+  specific block driver detects.  To the PEI ATAPI driver, it returns the number\r
+  of all the detected ATAPI devices it detects during the enumeration process.\r
+  To the PEI legacy floppy driver, it returns the number of all the legacy\r
+  devices it finds during its enumeration process. If no device is detected,\r
+  then the function will return zero.\r
+\r
+  @param[in]  PeiServices          General-purpose services that are available\r
+                                   to every PEIM.\r
+  @param[in]  This                 Indicates the EFI_PEI_RECOVERY_BLOCK_IO_PPI\r
+                                   instance.\r
+  @param[out] NumberBlockDevices   The number of block I/O devices discovered.\r
+\r
+  @retval     EFI_SUCCESS          The operation performed successfully.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+SdBlockIoPeimGetDeviceNo (\r
+  IN  EFI_PEI_SERVICES               **PeiServices,\r
+  IN  EFI_PEI_RECOVERY_BLOCK_IO_PPI  *This,\r
+  OUT UINTN                          *NumberBlockDevices\r
+  )\r
+{\r
+  SD_PEIM_HC_PRIVATE_DATA            *Private;\r
+\r
+  Private = GET_SD_PEIM_HC_PRIVATE_DATA_FROM_THIS (This);\r
+  *NumberBlockDevices = Private->TotalBlkIoDevices;\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+  Gets a block device's media information.\r
+\r
+  This function will provide the caller with the specified block device's media\r
+  information. If the media changes, calling this function will update the media\r
+  information accordingly.\r
+\r
+  @param[in]  PeiServices   General-purpose services that are available to every\r
+                            PEIM\r
+  @param[in]  This          Indicates the EFI_PEI_RECOVERY_BLOCK_IO_PPI instance.\r
+  @param[in]  DeviceIndex   Specifies the block device to which the function wants\r
+                            to talk. Because the driver that implements Block I/O\r
+                            PPIs will manage multiple block devices, the PPIs that\r
+                            want to talk to a single device must specify the\r
+                            device index that was assigned during the enumeration\r
+                            process. This index is a number from one to\r
+                            NumberBlockDevices.\r
+  @param[out] MediaInfo     The media information of the specified block media.\r
+                            The caller is responsible for the ownership of this\r
+                            data structure.\r
+\r
+  @par Note:\r
+      The MediaInfo structure describes an enumeration of possible block device\r
+      types.  This enumeration exists because no device paths are actually passed\r
+      across interfaces that describe the type or class of hardware that is publishing\r
+      the block I/O interface. This enumeration will allow for policy decisions\r
+      in the Recovery PEIM, such as "Try to recover from legacy floppy first,\r
+      LS-120 second, CD-ROM third." If there are multiple partitions abstracted\r
+      by a given device type, they should be reported in ascending order; this\r
+      order also applies to nested partitions, such as legacy MBR, where the\r
+      outermost partitions would have precedence in the reporting order. The\r
+      same logic applies to systems such as IDE that have precedence relationships\r
+      like "Master/Slave" or "Primary/Secondary". The master device should be\r
+      reported first, the slave second.\r
+\r
+  @retval EFI_SUCCESS        Media information about the specified block device\r
+                             was obtained successfully.\r
+  @retval EFI_DEVICE_ERROR   Cannot get the media information due to a hardware\r
+                             error.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+SdBlockIoPeimGetMediaInfo (\r
+  IN  EFI_PEI_SERVICES               **PeiServices,\r
+  IN  EFI_PEI_RECOVERY_BLOCK_IO_PPI  *This,\r
+  IN  UINTN                          DeviceIndex,\r
+  OUT EFI_PEI_BLOCK_IO_MEDIA         *MediaInfo\r
+  )\r
+{\r
+  SD_PEIM_HC_PRIVATE_DATA            *Private;\r
+\r
+  Private   = GET_SD_PEIM_HC_PRIVATE_DATA_FROM_THIS (This);\r
+\r
+  if ((DeviceIndex == 0) || (DeviceIndex > Private->TotalBlkIoDevices)) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  MediaInfo->DeviceType   = SD;\r
+  MediaInfo->MediaPresent = TRUE;\r
+  MediaInfo->LastBlock    = (UINTN)Private->Slot[DeviceIndex - 1].Media.LastBlock;\r
+  MediaInfo->BlockSize    = Private->Slot[DeviceIndex - 1].Media.BlockSize;\r
+\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+  Reads the requested number of blocks from the specified block device.\r
+\r
+  The function reads the requested number of blocks from the device. All the\r
+  blocks are read, or an error is returned. If there is no media in the device,\r
+  the function returns EFI_NO_MEDIA.\r
+\r
+  @param[in]  PeiServices   General-purpose services that are available to\r
+                            every PEIM.\r
+  @param[in]  This          Indicates the EFI_PEI_RECOVERY_BLOCK_IO_PPI instance.\r
+  @param[in]  DeviceIndex   Specifies the block device to which the function wants\r
+                            to talk. Because the driver that implements Block I/O\r
+                            PPIs will manage multiple block devices, PPIs that\r
+                            want to talk to a single device must specify the device\r
+                            index that was assigned during the enumeration process.\r
+                            This index is a number from one to NumberBlockDevices.\r
+  @param[in]  StartLBA      The starting logical block address (LBA) to read from\r
+                            on the device\r
+  @param[in]  BufferSize    The size of the Buffer in bytes. This number must be\r
+                            a multiple of the intrinsic block size of the device.\r
+  @param[out] Buffer        A pointer to the destination buffer for the data.\r
+                            The caller is responsible for the ownership of the\r
+                            buffer.\r
+\r
+  @retval EFI_SUCCESS             The data was read correctly from the device.\r
+  @retval EFI_DEVICE_ERROR        The device reported an error while attempting\r
+                                  to perform the read operation.\r
+  @retval EFI_INVALID_PARAMETER   The read request contains LBAs that are not\r
+                                  valid, or the buffer is not properly aligned.\r
+  @retval EFI_NO_MEDIA            There is no media in the device.\r
+  @retval EFI_BAD_BUFFER_SIZE     The BufferSize parameter is not a multiple of\r
+                                  the intrinsic block size of the device.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+SdBlockIoPeimReadBlocks (\r
+  IN  EFI_PEI_SERVICES               **PeiServices,\r
+  IN  EFI_PEI_RECOVERY_BLOCK_IO_PPI  *This,\r
+  IN  UINTN                          DeviceIndex,\r
+  IN  EFI_PEI_LBA                    StartLBA,\r
+  IN  UINTN                          BufferSize,\r
+  OUT VOID                           *Buffer\r
+  )\r
+{\r
+  EFI_STATUS                         Status;\r
+  UINT32                             BlockSize;\r
+  UINTN                              NumberOfBlocks;\r
+  SD_PEIM_HC_PRIVATE_DATA            *Private;\r
+  UINTN                              Remaining;\r
+  UINT32                             MaxBlock;\r
+\r
+  Status  = EFI_SUCCESS;\r
+  Private = GET_SD_PEIM_HC_PRIVATE_DATA_FROM_THIS (This);\r
+\r
+  //\r
+  // Check parameters\r
+  //\r
+  if (Buffer == NULL) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  if (BufferSize == 0) {\r
+    return EFI_SUCCESS;\r
+  }\r
+\r
+  if ((DeviceIndex == 0) || (DeviceIndex > Private->TotalBlkIoDevices)) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  BlockSize = Private->Slot[DeviceIndex - 1].Media.BlockSize;\r
+  if (BufferSize % BlockSize != 0) {\r
+    return EFI_BAD_BUFFER_SIZE;\r
+  }\r
+\r
+  if (StartLBA > Private->Slot[DeviceIndex - 1].Media.LastBlock) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  NumberOfBlocks = BufferSize / BlockSize;\r
+\r
+  //\r
+  // Start to execute data transfer. The max block number in single cmd is 65535 blocks.\r
+  //\r
+  Remaining = NumberOfBlocks;\r
+  MaxBlock  = 0xFFFF;\r
+\r
+  while (Remaining > 0) {\r
+    if (Remaining <= MaxBlock) {\r
+      NumberOfBlocks = Remaining;\r
+    } else {\r
+      NumberOfBlocks = MaxBlock;\r
+    }\r
+\r
+    BufferSize = NumberOfBlocks * BlockSize;\r
+    if (NumberOfBlocks != 1) {\r
+      Status = SdPeimRwMultiBlocks (&Private->Slot[DeviceIndex - 1], StartLBA, BlockSize, Buffer, BufferSize, TRUE);\r
+    } else {\r
+      Status = SdPeimRwSingleBlock (&Private->Slot[DeviceIndex - 1], StartLBA, BlockSize, Buffer, BufferSize, TRUE);\r
+    }\r
+    if (EFI_ERROR (Status)) {\r
+      return Status;\r
+    }\r
+\r
+    StartLBA  += NumberOfBlocks;\r
+    Buffer     = (UINT8*)Buffer + BufferSize;\r
+    Remaining -= NumberOfBlocks;\r
+  }\r
+  return Status;\r
+}\r
+\r
+/**\r
+  Gets the count of block I/O devices that one specific block driver detects.\r
+\r
+  This function is used for getting the count of block I/O devices that one\r
+  specific block driver detects.  To the PEI ATAPI driver, it returns the number\r
+  of all the detected ATAPI devices it detects during the enumeration process.\r
+  To the PEI legacy floppy driver, it returns the number of all the legacy\r
+  devices it finds during its enumeration process. If no device is detected,\r
+  then the function will return zero.\r
+\r
+  @param[in]  PeiServices          General-purpose services that are available\r
+                                   to every PEIM.\r
+  @param[in]  This                 Indicates the EFI_PEI_RECOVERY_BLOCK_IO2_PPI\r
+                                   instance.\r
+  @param[out] NumberBlockDevices   The number of block I/O devices discovered.\r
+\r
+  @retval     EFI_SUCCESS          The operation performed successfully.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+SdBlockIoPeimGetDeviceNo2 (\r
+  IN  EFI_PEI_SERVICES               **PeiServices,\r
+  IN  EFI_PEI_RECOVERY_BLOCK_IO2_PPI *This,\r
+  OUT UINTN                          *NumberBlockDevices\r
+  )\r
+{\r
+  SD_PEIM_HC_PRIVATE_DATA   *Private;\r
+\r
+  Private = GET_SD_PEIM_HC_PRIVATE_DATA_FROM_THIS2 (This);\r
+  *NumberBlockDevices = Private->TotalBlkIoDevices;\r
+\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+  Gets a block device's media information.\r
+\r
+  This function will provide the caller with the specified block device's media\r
+  information. If the media changes, calling this function will update the media\r
+  information accordingly.\r
+\r
+  @param[in]  PeiServices   General-purpose services that are available to every\r
+                            PEIM\r
+  @param[in]  This          Indicates the EFI_PEI_RECOVERY_BLOCK_IO2_PPI instance.\r
+  @param[in]  DeviceIndex   Specifies the block device to which the function wants\r
+                            to talk. Because the driver that implements Block I/O\r
+                            PPIs will manage multiple block devices, the PPIs that\r
+                            want to talk to a single device must specify the\r
+                            device index that was assigned during the enumeration\r
+                            process. This index is a number from one to\r
+                            NumberBlockDevices.\r
+  @param[out] MediaInfo     The media information of the specified block media.\r
+                            The caller is responsible for the ownership of this\r
+                            data structure.\r
+\r
+  @par Note:\r
+      The MediaInfo structure describes an enumeration of possible block device\r
+      types.  This enumeration exists because no device paths are actually passed\r
+      across interfaces that describe the type or class of hardware that is publishing\r
+      the block I/O interface. This enumeration will allow for policy decisions\r
+      in the Recovery PEIM, such as "Try to recover from legacy floppy first,\r
+      LS-120 second, CD-ROM third." If there are multiple partitions abstracted\r
+      by a given device type, they should be reported in ascending order; this\r
+      order also applies to nested partitions, such as legacy MBR, where the\r
+      outermost partitions would have precedence in the reporting order. The\r
+      same logic applies to systems such as IDE that have precedence relationships\r
+      like "Master/Slave" or "Primary/Secondary". The master device should be\r
+      reported first, the slave second.\r
+\r
+  @retval EFI_SUCCESS        Media information about the specified block device\r
+                             was obtained successfully.\r
+  @retval EFI_DEVICE_ERROR   Cannot get the media information due to a hardware\r
+                             error.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+SdBlockIoPeimGetMediaInfo2 (\r
+  IN  EFI_PEI_SERVICES               **PeiServices,\r
+  IN  EFI_PEI_RECOVERY_BLOCK_IO2_PPI *This,\r
+  IN  UINTN                          DeviceIndex,\r
+  OUT EFI_PEI_BLOCK_IO2_MEDIA        *MediaInfo\r
+  )\r
+{\r
+  EFI_STATUS                         Status;\r
+  SD_PEIM_HC_PRIVATE_DATA            *Private;\r
+  EFI_PEI_BLOCK_IO_MEDIA             Media;\r
+\r
+  Private = GET_SD_PEIM_HC_PRIVATE_DATA_FROM_THIS2 (This);\r
+\r
+  Status  = SdBlockIoPeimGetMediaInfo (\r
+              PeiServices,\r
+              &Private->BlkIoPpi,\r
+              DeviceIndex,\r
+              &Media\r
+              );\r
+  if (EFI_ERROR (Status)) {\r
+    return Status;\r
+  }\r
+\r
+  CopyMem (MediaInfo, &(Private->Slot[DeviceIndex - 1].Media), sizeof (EFI_PEI_BLOCK_IO2_MEDIA));\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+  Reads the requested number of blocks from the specified block device.\r
+\r
+  The function reads the requested number of blocks from the device. All the\r
+  blocks are read, or an error is returned. If there is no media in the device,\r
+  the function returns EFI_NO_MEDIA.\r
+\r
+  @param[in]  PeiServices   General-purpose services that are available to\r
+                            every PEIM.\r
+  @param[in]  This          Indicates the EFI_PEI_RECOVERY_BLOCK_IO2_PPI instance.\r
+  @param[in]  DeviceIndex   Specifies the block device to which the function wants\r
+                            to talk. Because the driver that implements Block I/O\r
+                            PPIs will manage multiple block devices, PPIs that\r
+                            want to talk to a single device must specify the device\r
+                            index that was assigned during the enumeration process.\r
+                            This index is a number from one to NumberBlockDevices.\r
+  @param[in]  StartLBA      The starting logical block address (LBA) to read from\r
+                            on the device\r
+  @param[in]  BufferSize    The size of the Buffer in bytes. This number must be\r
+                            a multiple of the intrinsic block size of the device.\r
+  @param[out] Buffer        A pointer to the destination buffer for the data.\r
+                            The caller is responsible for the ownership of the\r
+                            buffer.\r
+\r
+  @retval EFI_SUCCESS             The data was read correctly from the device.\r
+  @retval EFI_DEVICE_ERROR        The device reported an error while attempting\r
+                                  to perform the read operation.\r
+  @retval EFI_INVALID_PARAMETER   The read request contains LBAs that are not\r
+                                  valid, or the buffer is not properly aligned.\r
+  @retval EFI_NO_MEDIA            There is no media in the device.\r
+  @retval EFI_BAD_BUFFER_SIZE     The BufferSize parameter is not a multiple of\r
+                                  the intrinsic block size of the device.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+SdBlockIoPeimReadBlocks2 (\r
+  IN  EFI_PEI_SERVICES               **PeiServices,\r
+  IN  EFI_PEI_RECOVERY_BLOCK_IO2_PPI *This,\r
+  IN  UINTN                          DeviceIndex,\r
+  IN  EFI_PEI_LBA                    StartLBA,\r
+  IN  UINTN                          BufferSize,\r
+  OUT VOID                           *Buffer\r
+  )\r
+{\r
+  EFI_STATUS                         Status;\r
+  SD_PEIM_HC_PRIVATE_DATA            *Private;\r
+\r
+  Status    = EFI_SUCCESS;\r
+  Private   = GET_SD_PEIM_HC_PRIVATE_DATA_FROM_THIS2 (This);\r
+\r
+  Status  = SdBlockIoPeimReadBlocks (\r
+              PeiServices,\r
+              &Private->BlkIoPpi,\r
+              DeviceIndex,\r
+              StartLBA,\r
+              BufferSize,\r
+              Buffer\r
+              );\r
+  return Status;\r
+}\r
+\r
+/**\r
+  The user code starts with this function.\r
+\r
+  @param  FileHandle             Handle of the file being invoked.\r
+  @param  PeiServices            Describes the list of possible PEI Services.\r
+\r
+  @retval EFI_SUCCESS            The driver is successfully initialized.\r
+  @retval Others                 Can't initialize the driver.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+InitializeSdBlockIoPeim (\r
+  IN EFI_PEI_FILE_HANDLE        FileHandle,\r
+  IN CONST EFI_PEI_SERVICES     **PeiServices\r
+  )\r
+{\r
+  EFI_STATUS                       Status;\r
+  SD_PEIM_HC_PRIVATE_DATA          *Private;\r
+  EDKII_SD_MMC_HOST_CONTROLLER_PPI *SdMmcHcPpi;\r
+  UINT32                           Index;\r
+  UINTN                            *MmioBase;\r
+  UINT8                            BarNum;\r
+  UINT8                            SlotNum;\r
+  UINT8                            Controller;\r
+  UINT64                           Capacity;\r
+  SD_HC_SLOT_CAP                   Capability;\r
+  SD_PEIM_HC_SLOT                  *Slot;\r
+  SD_CSD                           *Csd;\r
+  SD_CSD2                          *Csd2;\r
+  UINT32                           CSize;\r
+  UINT32                           CSizeMul;\r
+  UINT32                           ReadBlLen;\r
+\r
+  //\r
+  // Shadow this PEIM to run from memory\r
+  //\r
+  if (!EFI_ERROR (PeiServicesRegisterForShadow (FileHandle))) {\r
+    return EFI_SUCCESS;\r
+  }\r
+\r
+  //\r
+  // locate Sd host controller PPI\r
+  //\r
+  Status = PeiServicesLocatePpi (\r
+             &gEdkiiPeiSdMmcHostControllerPpiGuid,\r
+             0,\r
+             NULL,\r
+             (VOID **) &SdMmcHcPpi\r
+             );\r
+  if (EFI_ERROR (Status)) {\r
+    return EFI_DEVICE_ERROR;\r
+  }\r
+\r
+  Controller = 0;\r
+  MmioBase   = NULL;\r
+  while (TRUE) {\r
+    Status = SdMmcHcPpi->GetSdMmcHcMmioBar (SdMmcHcPpi, Controller, &MmioBase, &BarNum);\r
+    //\r
+    // When status is error, meant no controller is found\r
+    //\r
+    if (EFI_ERROR (Status)) {\r
+      break;\r
+    }\r
+\r
+    if (BarNum == 0) {\r
+      Controller++;\r
+      continue;\r
+    }\r
+\r
+    Private = AllocateCopyPool (sizeof (SD_PEIM_HC_PRIVATE_DATA), &gSdHcPrivateTemplate);\r
+    if (Private == NULL) {\r
+      Status = EFI_OUT_OF_RESOURCES;\r
+      break;\r
+    }\r
+    Private->BlkIoPpiList.Ppi  = (VOID*)&Private->BlkIoPpi;\r
+    Private->BlkIo2PpiList.Ppi = (VOID*)&Private->BlkIo2Ppi;\r
+    //\r
+    // Initialize the memory pool which will be used in all transactions.\r
+    //\r
+    Status = SdPeimInitMemPool (Private);\r
+    if (EFI_ERROR (Status)) {\r
+      Status = EFI_OUT_OF_RESOURCES;\r
+      break;\r
+    }\r
+\r
+    for (Index = 0; Index < BarNum; Index++) {\r
+      Status = SdPeimHcGetCapability (MmioBase[Index], &Capability);\r
+      if (EFI_ERROR (Status)) {\r
+        continue;\r
+      }\r
+      if (Capability.SlotType != 0x1) {\r
+        DEBUG ((EFI_D_INFO, "The slot at 0x%x is not embedded slot type\n", MmioBase[Index]));\r
+        Status = EFI_UNSUPPORTED;\r
+        continue;\r
+      }\r
+\r
+      Status = SdPeimHcReset (MmioBase[Index]);\r
+      if (EFI_ERROR (Status)) {\r
+        continue;\r
+      }\r
+      Status = SdPeimHcCardDetect (MmioBase[Index]);\r
+      if (EFI_ERROR (Status)) {\r
+        continue;\r
+      }\r
+      Status = SdPeimHcInitHost (MmioBase[Index]);\r
+      if (EFI_ERROR (Status)) {\r
+        continue;\r
+      }\r
+\r
+      SlotNum = Private->SlotNum;\r
+      Slot    = &Private->Slot[SlotNum];\r
+      CopyMem (Slot, &gSdHcSlotTemplate, sizeof (SD_PEIM_HC_SLOT));\r
+      Slot->Private  = Private;\r
+      Slot->SdHcBase = MmioBase[Index];\r
+      CopyMem (&Slot->Capability, &Capability, sizeof (Capability));\r
+\r
+      Status = SdPeimIdentification (Slot);\r
+      if (EFI_ERROR (Status)) {\r
+        continue;\r
+      }\r
+\r
+      Csd = &Slot->Csd;\r
+      if (Csd->CsdStructure == 0) {\r
+        Slot->SectorAddressing = FALSE;\r
+        CSize     = (Csd->CSizeHigh << 2 | Csd->CSizeLow) + 1;\r
+        CSizeMul  = (1 << (Csd->CSizeMul + 2));\r
+        ReadBlLen = (1 << (Csd->ReadBlLen));\r
+        Capacity  = MultU64x32 (MultU64x32 ((UINT64)CSize, CSizeMul), ReadBlLen);\r
+      } else {\r
+        Slot->SectorAddressing = TRUE;\r
+        Csd2     = (SD_CSD2*)(VOID*)Csd;\r
+        CSize    = (Csd2->CSizeHigh << 16 | Csd2->CSizeLow) + 1;\r
+        Capacity = MultU64x32 ((UINT64)CSize, SIZE_512KB);\r
+      }\r
+\r
+      Slot->Media.LastBlock = DivU64x32 (Capacity, Slot->Media.BlockSize) - 1;\r
+\r
+      Private->TotalBlkIoDevices++;\r
+      Private->SlotNum++;\r
+    }\r
+\r
+    Controller++;\r
+    if (!EFI_ERROR (Status)) {\r
+      PeiServicesInstallPpi (&Private->BlkIoPpiList);\r
+    }\r
+  }\r
+\r
+  return EFI_SUCCESS;\r
+}\r
diff --git a/MdeModulePkg/Bus/Sd/SdBlockIoPei/SdBlockIoPei.h b/MdeModulePkg/Bus/Sd/SdBlockIoPei/SdBlockIoPei.h
new file mode 100644 (file)
index 0000000..b2491bb
--- /dev/null
@@ -0,0 +1,377 @@
+/** @file\r
+\r
+  Copyright (c) 2015, Intel Corporation. All rights reserved.<BR>\r
+  This program and the accompanying materials\r
+  are licensed and made available under the terms and conditions of the BSD License\r
+  which accompanies this distribution.  The full text of the license may be found at\r
+  http://opensource.org/licenses/bsd-license.php\r
+\r
+  THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+  WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+\r
+**/\r
+\r
+#ifndef _SD_BLOCK_IO_PEI_H_\r
+#define _SD_BLOCK_IO_PEI_H_\r
+\r
+#include <PiPei.h>\r
+\r
+#include <Ppi/SdMmcHostController.h>\r
+#include <Ppi/BlockIo.h>\r
+#include <Ppi/BlockIo2.h>\r
+\r
+#include <Library/DebugLib.h>\r
+#include <Library/BaseLib.h>\r
+#include <Library/BaseMemoryLib.h>\r
+#include <Library/MemoryAllocationLib.h>\r
+#include <Library/IoLib.h>\r
+#include <Library/TimerLib.h>\r
+#include <Library/PeiServicesLib.h>\r
+\r
+#include <IndustryStandard/Sd.h>\r
+\r
+typedef struct _SD_PEIM_HC_PRIVATE_DATA SD_PEIM_HC_PRIVATE_DATA;\r
+typedef struct _SD_PEIM_HC_SLOT         SD_PEIM_HC_SLOT;\r
+typedef struct _SD_TRB                  SD_TRB;\r
+\r
+#include "SdHci.h"\r
+#include "SdHcMem.h"\r
+\r
+#define SD_PEIM_SIG               SIGNATURE_32 ('S', 'D', 'C', 'P')\r
+#define SD_PEIM_SLOT_SIG          SIGNATURE_32 ('S', 'D', 'C', 'S')\r
+\r
+#define SD_PEIM_MAX_SLOTS         6\r
+\r
+struct _SD_PEIM_HC_SLOT {\r
+  UINT32                            Signature;\r
+  EFI_PEI_BLOCK_IO2_MEDIA           Media;\r
+\r
+  UINTN                             SdHcBase;\r
+  SD_HC_SLOT_CAP                    Capability;\r
+  SD_CSD                            Csd;\r
+  BOOLEAN                           SectorAddressing;\r
+  SD_PEIM_HC_PRIVATE_DATA           *Private;\r
+};\r
+\r
+struct _SD_PEIM_HC_PRIVATE_DATA {\r
+  UINT32                            Signature;\r
+  SD_PEIM_MEM_POOL                  *Pool;\r
+  EFI_PEI_RECOVERY_BLOCK_IO_PPI     BlkIoPpi;\r
+  EFI_PEI_RECOVERY_BLOCK_IO2_PPI    BlkIo2Ppi;\r
+  EFI_PEI_PPI_DESCRIPTOR            BlkIoPpiList;\r
+  EFI_PEI_PPI_DESCRIPTOR            BlkIo2PpiList;\r
+  SD_PEIM_HC_SLOT                   Slot[SD_PEIM_MAX_SLOTS];\r
+  UINT8                             SlotNum;\r
+  UINT8                             TotalBlkIoDevices;\r
+};\r
+\r
+#define SD_TIMEOUT                  MultU64x32((UINT64)(3), 1000000)\r
+#define GET_SD_PEIM_HC_PRIVATE_DATA_FROM_THIS(a) CR (a, SD_PEIM_HC_PRIVATE_DATA, BlkIoPpi, SD_PEIM_SIG)\r
+#define GET_SD_PEIM_HC_PRIVATE_DATA_FROM_THIS2(a) CR (a, SD_PEIM_HC_PRIVATE_DATA, BlkIo2Ppi, SD_PEIM_SIG)\r
+\r
+struct _SD_TRB {\r
+  SD_PEIM_HC_SLOT                   *Slot;\r
+  UINT16                            BlockSize;\r
+\r
+  SD_COMMAND_PACKET                 *Packet;\r
+  VOID                              *Data;\r
+  UINT32                            DataLen;\r
+  BOOLEAN                           Read;\r
+  SD_HC_TRANSFER_MODE               Mode;\r
+\r
+  UINT64                            Timeout;\r
+\r
+  SD_HC_ADMA_DESC_LINE              *AdmaDesc;\r
+  UINTN                             AdmaDescSize;\r
+};\r
+\r
+/**\r
+  Gets the count of block I/O devices that one specific block driver detects.\r
+\r
+  This function is used for getting the count of block I/O devices that one\r
+  specific block driver detects.  To the PEI ATAPI driver, it returns the number\r
+  of all the detected ATAPI devices it detects during the enumeration process.\r
+  To the PEI legacy floppy driver, it returns the number of all the legacy\r
+  devices it finds during its enumeration process. If no device is detected,\r
+  then the function will return zero.\r
+\r
+  @param[in]  PeiServices          General-purpose services that are available\r
+                                   to every PEIM.\r
+  @param[in]  This                 Indicates the EFI_PEI_RECOVERY_BLOCK_IO_PPI\r
+                                   instance.\r
+  @param[out] NumberBlockDevices   The number of block I/O devices discovered.\r
+\r
+  @retval     EFI_SUCCESS          The operation performed successfully.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+SdBlockIoPeimGetDeviceNo (\r
+  IN  EFI_PEI_SERVICES               **PeiServices,\r
+  IN  EFI_PEI_RECOVERY_BLOCK_IO_PPI  *This,\r
+  OUT UINTN                          *NumberBlockDevices\r
+  );\r
+\r
+/**\r
+  Gets a block device's media information.\r
+\r
+  This function will provide the caller with the specified block device's media\r
+  information. If the media changes, calling this function will update the media\r
+  information accordingly.\r
+\r
+  @param[in]  PeiServices   General-purpose services that are available to every\r
+                            PEIM\r
+  @param[in]  This          Indicates the EFI_PEI_RECOVERY_BLOCK_IO_PPI instance.\r
+  @param[in]  DeviceIndex   Specifies the block device to which the function wants\r
+                            to talk. Because the driver that implements Block I/O\r
+                            PPIs will manage multiple block devices, the PPIs that\r
+                            want to talk to a single device must specify the\r
+                            device index that was assigned during the enumeration\r
+                            process. This index is a number from one to\r
+                            NumberBlockDevices.\r
+  @param[out] MediaInfo     The media information of the specified block media.\r
+                            The caller is responsible for the ownership of this\r
+                            data structure.\r
+\r
+  @par Note:\r
+      The MediaInfo structure describes an enumeration of possible block device\r
+      types.  This enumeration exists because no device paths are actually passed\r
+      across interfaces that describe the type or class of hardware that is publishing\r
+      the block I/O interface. This enumeration will allow for policy decisions\r
+      in the Recovery PEIM, such as "Try to recover from legacy floppy first,\r
+      LS-120 second, CD-ROM third." If there are multiple partitions abstracted\r
+      by a given device type, they should be reported in ascending order; this\r
+      order also applies to nested partitions, such as legacy MBR, where the\r
+      outermost partitions would have precedence in the reporting order. The\r
+      same logic applies to systems such as IDE that have precedence relationships\r
+      like "Master/Slave" or "Primary/Secondary". The master device should be\r
+      reported first, the slave second.\r
+\r
+  @retval EFI_SUCCESS        Media information about the specified block device\r
+                             was obtained successfully.\r
+  @retval EFI_DEVICE_ERROR   Cannot get the media information due to a hardware\r
+                             error.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+SdBlockIoPeimGetMediaInfo (\r
+  IN  EFI_PEI_SERVICES               **PeiServices,\r
+  IN  EFI_PEI_RECOVERY_BLOCK_IO_PPI  *This,\r
+  IN  UINTN                          DeviceIndex,\r
+  OUT EFI_PEI_BLOCK_IO_MEDIA         *MediaInfo\r
+  );\r
+\r
+/**\r
+  Reads the requested number of blocks from the specified block device.\r
+\r
+  The function reads the requested number of blocks from the device. All the\r
+  blocks are read, or an error is returned. If there is no media in the device,\r
+  the function returns EFI_NO_MEDIA.\r
+\r
+  @param[in]  PeiServices   General-purpose services that are available to\r
+                            every PEIM.\r
+  @param[in]  This          Indicates the EFI_PEI_RECOVERY_BLOCK_IO_PPI instance.\r
+  @param[in]  DeviceIndex   Specifies the block device to which the function wants\r
+                            to talk. Because the driver that implements Block I/O\r
+                            PPIs will manage multiple block devices, PPIs that\r
+                            want to talk to a single device must specify the device\r
+                            index that was assigned during the enumeration process.\r
+                            This index is a number from one to NumberBlockDevices.\r
+  @param[in]  StartLBA      The starting logical block address (LBA) to read from\r
+                            on the device\r
+  @param[in]  BufferSize    The size of the Buffer in bytes. This number must be\r
+                            a multiple of the intrinsic block size of the device.\r
+  @param[out] Buffer        A pointer to the destination buffer for the data.\r
+                            The caller is responsible for the ownership of the\r
+                            buffer.\r
+\r
+  @retval EFI_SUCCESS             The data was read correctly from the device.\r
+  @retval EFI_DEVICE_ERROR        The device reported an error while attempting\r
+                                  to perform the read operation.\r
+  @retval EFI_INVALID_PARAMETER   The read request contains LBAs that are not\r
+                                  valid, or the buffer is not properly aligned.\r
+  @retval EFI_NO_MEDIA            There is no media in the device.\r
+  @retval EFI_BAD_BUFFER_SIZE     The BufferSize parameter is not a multiple of\r
+                                  the intrinsic block size of the device.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+SdBlockIoPeimReadBlocks (\r
+  IN  EFI_PEI_SERVICES               **PeiServices,\r
+  IN  EFI_PEI_RECOVERY_BLOCK_IO_PPI  *This,\r
+  IN  UINTN                          DeviceIndex,\r
+  IN  EFI_PEI_LBA                    StartLBA,\r
+  IN  UINTN                          BufferSize,\r
+  OUT VOID                           *Buffer\r
+  );\r
+\r
+/**\r
+  Gets the count of block I/O devices that one specific block driver detects.\r
+\r
+  This function is used for getting the count of block I/O devices that one\r
+  specific block driver detects.  To the PEI ATAPI driver, it returns the number\r
+  of all the detected ATAPI devices it detects during the enumeration process.\r
+  To the PEI legacy floppy driver, it returns the number of all the legacy\r
+  devices it finds during its enumeration process. If no device is detected,\r
+  then the function will return zero.\r
+\r
+  @param[in]  PeiServices          General-purpose services that are available\r
+                                   to every PEIM.\r
+  @param[in]  This                 Indicates the EFI_PEI_RECOVERY_BLOCK_IO2_PPI\r
+                                   instance.\r
+  @param[out] NumberBlockDevices   The number of block I/O devices discovered.\r
+\r
+  @retval     EFI_SUCCESS          The operation performed successfully.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+SdBlockIoPeimGetDeviceNo2 (\r
+  IN  EFI_PEI_SERVICES               **PeiServices,\r
+  IN  EFI_PEI_RECOVERY_BLOCK_IO2_PPI *This,\r
+  OUT UINTN                          *NumberBlockDevices\r
+  );\r
+\r
+/**\r
+  Gets a block device's media information.\r
+\r
+  This function will provide the caller with the specified block device's media\r
+  information. If the media changes, calling this function will update the media\r
+  information accordingly.\r
+\r
+  @param[in]  PeiServices   General-purpose services that are available to every\r
+                            PEIM\r
+  @param[in]  This          Indicates the EFI_PEI_RECOVERY_BLOCK_IO2_PPI instance.\r
+  @param[in]  DeviceIndex   Specifies the block device to which the function wants\r
+                            to talk. Because the driver that implements Block I/O\r
+                            PPIs will manage multiple block devices, the PPIs that\r
+                            want to talk to a single device must specify the\r
+                            device index that was assigned during the enumeration\r
+                            process. This index is a number from one to\r
+                            NumberBlockDevices.\r
+  @param[out] MediaInfo     The media information of the specified block media.\r
+                            The caller is responsible for the ownership of this\r
+                            data structure.\r
+\r
+  @par Note:\r
+      The MediaInfo structure describes an enumeration of possible block device\r
+      types.  This enumeration exists because no device paths are actually passed\r
+      across interfaces that describe the type or class of hardware that is publishing\r
+      the block I/O interface. This enumeration will allow for policy decisions\r
+      in the Recovery PEIM, such as "Try to recover from legacy floppy first,\r
+      LS-120 second, CD-ROM third." If there are multiple partitions abstracted\r
+      by a given device type, they should be reported in ascending order; this\r
+      order also applies to nested partitions, such as legacy MBR, where the\r
+      outermost partitions would have precedence in the reporting order. The\r
+      same logic applies to systems such as IDE that have precedence relationships\r
+      like "Master/Slave" or "Primary/Secondary". The master device should be\r
+      reported first, the slave second.\r
+\r
+  @retval EFI_SUCCESS        Media information about the specified block device\r
+                             was obtained successfully.\r
+  @retval EFI_DEVICE_ERROR   Cannot get the media information due to a hardware\r
+                             error.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+SdBlockIoPeimGetMediaInfo2 (\r
+  IN  EFI_PEI_SERVICES               **PeiServices,\r
+  IN  EFI_PEI_RECOVERY_BLOCK_IO2_PPI *This,\r
+  IN  UINTN                          DeviceIndex,\r
+  OUT EFI_PEI_BLOCK_IO2_MEDIA        *MediaInfo\r
+  );\r
+\r
+/**\r
+  Reads the requested number of blocks from the specified block device.\r
+\r
+  The function reads the requested number of blocks from the device. All the\r
+  blocks are read, or an error is returned. If there is no media in the device,\r
+  the function returns EFI_NO_MEDIA.\r
+\r
+  @param[in]  PeiServices   General-purpose services that are available to\r
+                            every PEIM.\r
+  @param[in]  This          Indicates the EFI_PEI_RECOVERY_BLOCK_IO2_PPI instance.\r
+  @param[in]  DeviceIndex   Specifies the block device to which the function wants\r
+                            to talk. Because the driver that implements Block I/O\r
+                            PPIs will manage multiple block devices, PPIs that\r
+                            want to talk to a single device must specify the device\r
+                            index that was assigned during the enumeration process.\r
+                            This index is a number from one to NumberBlockDevices.\r
+  @param[in]  StartLBA      The starting logical block address (LBA) to read from\r
+                            on the device\r
+  @param[in]  BufferSize    The size of the Buffer in bytes. This number must be\r
+                            a multiple of the intrinsic block size of the device.\r
+  @param[out] Buffer        A pointer to the destination buffer for the data.\r
+                            The caller is responsible for the ownership of the\r
+                            buffer.\r
+\r
+  @retval EFI_SUCCESS             The data was read correctly from the device.\r
+  @retval EFI_DEVICE_ERROR        The device reported an error while attempting\r
+                                  to perform the read operation.\r
+  @retval EFI_INVALID_PARAMETER   The read request contains LBAs that are not\r
+                                  valid, or the buffer is not properly aligned.\r
+  @retval EFI_NO_MEDIA            There is no media in the device.\r
+  @retval EFI_BAD_BUFFER_SIZE     The BufferSize parameter is not a multiple of\r
+                                  the intrinsic block size of the device.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+SdBlockIoPeimReadBlocks2 (\r
+  IN  EFI_PEI_SERVICES               **PeiServices,\r
+  IN  EFI_PEI_RECOVERY_BLOCK_IO2_PPI *This,\r
+  IN  UINTN                          DeviceIndex,\r
+  IN  EFI_PEI_LBA                    StartLBA,\r
+  IN  UINTN                          BufferSize,\r
+  OUT VOID                           *Buffer\r
+  );\r
+\r
+/**\r
+  Initialize the memory management pool for the host controller.\r
+\r
+  @param  Private               The Sd Peim driver private data.\r
+\r
+  @retval EFI_SUCCESS           The memory pool is initialized.\r
+  @retval Others                Fail to init the memory pool.\r
+\r
+**/\r
+EFI_STATUS\r
+SdPeimInitMemPool (\r
+  IN  SD_PEIM_HC_PRIVATE_DATA      *Private\r
+  );\r
+\r
+/**\r
+  Allocate some memory from the host controller's memory pool\r
+  which can be used to communicate with host controller.\r
+\r
+  @param  Pool      The host controller's memory pool.\r
+  @param  Size      Size of the memory to allocate.\r
+\r
+  @return The allocated memory or NULL.\r
+\r
+**/\r
+VOID *\r
+SdPeimAllocateMem (\r
+  IN  SD_PEIM_MEM_POOL        *Pool,\r
+  IN  UINTN                    Size\r
+  );\r
+\r
+/**\r
+  Free the allocated memory back to the memory pool.\r
+\r
+  @param  Pool           The memory pool of the host controller.\r
+  @param  Mem            The memory to free.\r
+  @param  Size           The size of the memory to free.\r
+\r
+**/\r
+VOID\r
+SdPeimFreeMem (\r
+  IN SD_PEIM_MEM_POOL    *Pool,\r
+  IN VOID                 *Mem,\r
+  IN UINTN                Size\r
+  );\r
+\r
+#endif\r
diff --git a/MdeModulePkg/Bus/Sd/SdBlockIoPei/SdBlockIoPei.inf b/MdeModulePkg/Bus/Sd/SdBlockIoPei/SdBlockIoPei.inf
new file mode 100644 (file)
index 0000000..ca4c39b
--- /dev/null
@@ -0,0 +1,62 @@
+## @file\r
+# Description file for the SD memory card Peim driver.\r
+#\r
+# Copyright (c) 2015, Intel Corporation. All rights reserved.<BR>\r
+#\r
+#  This program and the accompanying materials\r
+#  are licensed and made available under the terms and conditions of the BSD License\r
+#  which accompanies this distribution. The full text of the license may be found at\r
+#  http://opensource.org/licenses/bsd-license.php\r
+#  THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+#  WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+#\r
+#\r
+##\r
+\r
+[Defines]\r
+  INF_VERSION                    = 0x00010005\r
+  BASE_NAME                      = SdBlockIoPei\r
+  MODULE_UNI_FILE                = SdBlockIoPei.uni\r
+  FILE_GUID                      = 17851FBF-45C4-4ff7-A2A0-C3B12D63C27E\r
+  MODULE_TYPE                    = PEIM\r
+  VERSION_STRING                 = 1.0\r
+\r
+  ENTRY_POINT                    = InitializeSdBlockIoPeim\r
+\r
+#\r
+# The following information is for reference only and not required by the build tools.\r
+#\r
+#  VALID_ARCHITECTURES           = IA32 X64 IPF EBC\r
+#\r
+\r
+[Sources]\r
+  SdBlockIoPei.c\r
+  SdBlockIoPei.h\r
+  SdHci.c\r
+  SdHci.h\r
+  SdHcMem.c\r
+  SdHcMem.h\r
+\r
+[Packages]\r
+  MdePkg/MdePkg.dec\r
+  MdeModulePkg/MdeModulePkg.dec\r
+\r
+[LibraryClasses]\r
+  IoLib\r
+  TimerLib\r
+  BaseMemoryLib\r
+  PeimEntryPoint\r
+  PeiServicesLib\r
+  DebugLib\r
+\r
+[Ppis]\r
+  gEfiPeiVirtualBlockIoPpiGuid                  ## PRODUCES\r
+  gEfiPeiVirtualBlockIo2PpiGuid                 ## PRODUCES\r
+  gEdkiiPeiSdMmcHostControllerPpiGuid           ## CONSUMES\r
+\r
+[Depex]\r
+  gEfiPeiMemoryDiscoveredPpiGuid AND gEdkiiPeiSdMmcHostControllerPpiGuid\r
+\r
+[UserExtensions.TianoCore."ExtraFiles"]\r
+  SdBlockIoPeiExtra.uni\r
+\r
diff --git a/MdeModulePkg/Bus/Sd/SdBlockIoPei/SdBlockIoPei.uni b/MdeModulePkg/Bus/Sd/SdBlockIoPei/SdBlockIoPei.uni
new file mode 100644 (file)
index 0000000..30c9f0e
--- /dev/null
@@ -0,0 +1,21 @@
+// /** @file\r
+// The SdBlockIoPei driver is used to support recovery from SD memory card device.\r
+//\r
+// Copyright (c) 2015, Intel Corporation. All rights reserved.<BR>\r
+//\r
+// This program and the accompanying materials\r
+// are licensed and made available under the terms and conditions\r
+// of the BSD License which accompanies this distribution.  The\r
+// full text of the license may be found at\r
+// http://opensource.org/licenses/bsd-license.php\r
+//\r
+// THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+// WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+//\r
+// **/\r
+\r
+\r
+#string STR_MODULE_ABSTRACT             #language en-US "Support recovery from SD memory card devices"\r
+\r
+#string STR_MODULE_DESCRIPTION          #language en-US "The SdBlockIoPei driver is used to support recovery from SD memory card device."\r
+\r
diff --git a/MdeModulePkg/Bus/Sd/SdBlockIoPei/SdBlockIoPeiExtra.uni b/MdeModulePkg/Bus/Sd/SdBlockIoPei/SdBlockIoPeiExtra.uni
new file mode 100644 (file)
index 0000000..141e467
--- /dev/null
@@ -0,0 +1,21 @@
+// /** @file\r
+// SdBlockIoPei Localized Strings and Content\r
+//\r
+// Copyright (c) 2015, Intel Corporation. All rights reserved.<BR>\r
+//\r
+// This program and the accompanying materials\r
+// are licensed and made available under the terms and conditions\r
+// of the BSD License which accompanies this distribution.  The\r
+// full text of the license may be found at\r
+// http://opensource.org/licenses/bsd-license.php\r
+//\r
+// THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+// WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+//\r
+// **/\r
+\r
+#string STR_PROPERTIES_MODULE_NAME\r
+#language en-US\r
+"SD BlockIo Peim for Recovery"\r
+\r
+\r
diff --git a/MdeModulePkg/Bus/Sd/SdBlockIoPei/SdHcMem.c b/MdeModulePkg/Bus/Sd/SdBlockIoPei/SdHcMem.c
new file mode 100644 (file)
index 0000000..8bfe18c
--- /dev/null
@@ -0,0 +1,455 @@
+/** @file\r
+\r
+Copyright (c) 2015, Intel Corporation. All rights reserved.<BR>\r
+\r
+This program and the accompanying materials\r
+are licensed and made available under the terms and conditions\r
+of the BSD License which accompanies this distribution.  The\r
+full text of the license may be found at\r
+http://opensource.org/licenses/bsd-license.php\r
+\r
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+\r
+**/\r
+\r
+#include "SdBlockIoPei.h"\r
+\r
+/**\r
+  Allocate a block of memory to be used by the buffer pool.\r
+\r
+  @param  Pages          How many pages to allocate.\r
+\r
+  @return The allocated memory block or NULL if failed.\r
+\r
+**/\r
+SD_PEIM_MEM_BLOCK *\r
+SdPeimAllocMemBlock (\r
+  IN  UINTN                    Pages\r
+  )\r
+{\r
+  SD_PEIM_MEM_BLOCK            *Block;\r
+  EFI_STATUS                   Status;\r
+  VOID                         *TempPtr;\r
+  EFI_PHYSICAL_ADDRESS         Address;\r
+\r
+  TempPtr = NULL;\r
+  Block   = NULL;\r
+\r
+  Status = PeiServicesAllocatePool (sizeof(SD_PEIM_MEM_BLOCK), &TempPtr);\r
+  if (EFI_ERROR (Status)) {\r
+    return NULL;\r
+  }\r
+\r
+  ZeroMem ((VOID*)(UINTN)TempPtr, sizeof(SD_PEIM_MEM_BLOCK));\r
+\r
+  //\r
+  // each bit in the bit array represents SD_PEIM_MEM_UNIT\r
+  // bytes of memory in the memory block.\r
+  //\r
+  ASSERT (SD_PEIM_MEM_UNIT * 8 <= EFI_PAGE_SIZE);\r
+\r
+  Block = (SD_PEIM_MEM_BLOCK*)(UINTN)TempPtr;\r
+  Block->BufLen   = EFI_PAGES_TO_SIZE (Pages);\r
+  Block->BitsLen  = Block->BufLen / (SD_PEIM_MEM_UNIT * 8);\r
+\r
+  Status = PeiServicesAllocatePool (Block->BitsLen, &TempPtr);\r
+  if (EFI_ERROR (Status)) {\r
+    return NULL;\r
+  }\r
+\r
+  ZeroMem ((VOID*)(UINTN)TempPtr, Block->BitsLen);\r
+\r
+  Block->Bits = (UINT8*)(UINTN)TempPtr;\r
+\r
+  Status = PeiServicesAllocatePages (\r
+             EfiBootServicesCode,\r
+             Pages,\r
+             &Address\r
+             );\r
+  if (EFI_ERROR (Status)) {\r
+    return NULL;\r
+  }\r
+\r
+  ZeroMem ((VOID*)(UINTN)Address, EFI_PAGES_TO_SIZE (Pages));\r
+\r
+  Block->Buf  = (UINT8*)((UINTN)Address);\r
+  Block->Next = NULL;\r
+\r
+  return Block;\r
+}\r
+\r
+/**\r
+  Free the memory block from the memory pool.\r
+\r
+  @param  Pool           The memory pool to free the block from.\r
+  @param  Block          The memory block to free.\r
+\r
+**/\r
+VOID\r
+SdPeimFreeMemBlock (\r
+  IN SD_PEIM_MEM_POOL       *Pool,\r
+  IN SD_PEIM_MEM_BLOCK      *Block\r
+  )\r
+{\r
+  ASSERT ((Pool != NULL) && (Block != NULL));\r
+}\r
+\r
+/**\r
+  Alloc some memory from the block.\r
+\r
+  @param  Block          The memory block to allocate memory from.\r
+  @param  Units          Number of memory units to allocate.\r
+\r
+  @return The pointer to the allocated memory. If couldn't allocate the needed memory,\r
+          the return value is NULL.\r
+\r
+**/\r
+VOID *\r
+SdPeimAllocMemFromBlock (\r
+  IN  SD_PEIM_MEM_BLOCK   *Block,\r
+  IN  UINTN               Units\r
+  )\r
+{\r
+  UINTN                   Byte;\r
+  UINT8                   Bit;\r
+  UINTN                   StartByte;\r
+  UINT8                   StartBit;\r
+  UINTN                   Available;\r
+  UINTN                   Count;\r
+\r
+  ASSERT ((Block != 0) && (Units != 0));\r
+\r
+  StartByte  = 0;\r
+  StartBit   = 0;\r
+  Available  = 0;\r
+\r
+  for (Byte = 0, Bit = 0; Byte < Block->BitsLen;) {\r
+    //\r
+    // If current bit is zero, the corresponding memory unit is\r
+    // available, otherwise we need to restart our searching.\r
+    // Available counts the consective number of zero bit.\r
+    //\r
+    if (!SD_PEIM_MEM_BIT_IS_SET (Block->Bits[Byte], Bit)) {\r
+      Available++;\r
+\r
+      if (Available >= Units) {\r
+        break;\r
+      }\r
+\r
+      SD_PEIM_NEXT_BIT (Byte, Bit);\r
+\r
+    } else {\r
+      SD_PEIM_NEXT_BIT (Byte, Bit);\r
+\r
+      Available  = 0;\r
+      StartByte  = Byte;\r
+      StartBit   = Bit;\r
+    }\r
+  }\r
+\r
+  if (Available < Units) {\r
+    return NULL;\r
+  }\r
+\r
+  //\r
+  // Mark the memory as allocated\r
+  //\r
+  Byte  = StartByte;\r
+  Bit   = StartBit;\r
+\r
+  for (Count = 0; Count < Units; Count++) {\r
+    ASSERT (!SD_PEIM_MEM_BIT_IS_SET (Block->Bits[Byte], Bit));\r
+\r
+    Block->Bits[Byte] = (UINT8) (Block->Bits[Byte] | (UINT8) SD_PEIM_MEM_BIT (Bit));\r
+    SD_PEIM_NEXT_BIT (Byte, Bit);\r
+  }\r
+\r
+  return Block->Buf + (StartByte * 8 + StartBit) * SD_PEIM_MEM_UNIT;\r
+}\r
+\r
+/**\r
+  Insert the memory block to the pool's list of the blocks.\r
+\r
+  @param  Head           The head of the memory pool's block list.\r
+  @param  Block          The memory block to insert.\r
+\r
+**/\r
+VOID\r
+SdPeimInsertMemBlockToPool (\r
+  IN SD_PEIM_MEM_BLOCK      *Head,\r
+  IN SD_PEIM_MEM_BLOCK      *Block\r
+  )\r
+{\r
+  ASSERT ((Head != NULL) && (Block != NULL));\r
+  Block->Next = Head->Next;\r
+  Head->Next  = Block;\r
+}\r
+\r
+/**\r
+  Is the memory block empty?\r
+\r
+  @param  Block   The memory block to check.\r
+\r
+  @retval TRUE    The memory block is empty.\r
+  @retval FALSE   The memory block isn't empty.\r
+\r
+**/\r
+BOOLEAN\r
+SdPeimIsMemBlockEmpty (\r
+  IN SD_PEIM_MEM_BLOCK     *Block\r
+  )\r
+{\r
+  UINTN                    Index;\r
+\r
+\r
+  for (Index = 0; Index < Block->BitsLen; Index++) {\r
+    if (Block->Bits[Index] != 0) {\r
+      return FALSE;\r
+    }\r
+  }\r
+\r
+  return TRUE;\r
+}\r
+\r
+/**\r
+  Unlink the memory block from the pool's list.\r
+\r
+  @param  Head           The block list head of the memory's pool.\r
+  @param  BlockToUnlink  The memory block to unlink.\r
+\r
+**/\r
+VOID\r
+SdPeimUnlinkMemBlock (\r
+  IN SD_PEIM_MEM_BLOCK      *Head,\r
+  IN SD_PEIM_MEM_BLOCK      *BlockToUnlink\r
+  )\r
+{\r
+  SD_PEIM_MEM_BLOCK         *Block;\r
+\r
+  ASSERT ((Head != NULL) && (BlockToUnlink != NULL));\r
+\r
+  for (Block = Head; Block != NULL; Block = Block->Next) {\r
+    if (Block->Next == BlockToUnlink) {\r
+      Block->Next         = BlockToUnlink->Next;\r
+      BlockToUnlink->Next = NULL;\r
+      break;\r
+    }\r
+  }\r
+}\r
+\r
+/**\r
+  Initialize the memory management pool for the host controller.\r
+\r
+  @param  Private               The Sd Peim driver private data.\r
+\r
+  @retval EFI_SUCCESS           The memory pool is initialized.\r
+  @retval Others                Fail to init the memory pool.\r
+\r
+**/\r
+EFI_STATUS\r
+SdPeimInitMemPool (\r
+  IN  SD_PEIM_HC_PRIVATE_DATA  *Private\r
+  )\r
+{\r
+  SD_PEIM_MEM_POOL           *Pool;\r
+  EFI_STATUS                 Status;\r
+  VOID                       *TempPtr;\r
+\r
+  TempPtr = NULL;\r
+  Pool    = NULL;\r
+\r
+  Status = PeiServicesAllocatePool (sizeof (SD_PEIM_MEM_POOL), &TempPtr);\r
+  if (EFI_ERROR (Status)) {\r
+    return EFI_OUT_OF_RESOURCES;\r
+  }\r
+\r
+  ZeroMem ((VOID*)(UINTN)TempPtr, sizeof (SD_PEIM_MEM_POOL));\r
+\r
+  Pool = (SD_PEIM_MEM_POOL *)((UINTN)TempPtr);\r
+\r
+  Pool->Head = SdPeimAllocMemBlock (SD_PEIM_MEM_DEFAULT_PAGES);\r
+\r
+  if (Pool->Head == NULL) {\r
+    return EFI_OUT_OF_RESOURCES;\r
+  }\r
+\r
+  Private->Pool = Pool;\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+  Release the memory management pool.\r
+\r
+  @param  Pool                  The memory pool to free.\r
+\r
+  @retval EFI_DEVICE_ERROR      Fail to free the memory pool.\r
+  @retval EFI_SUCCESS           The memory pool is freed.\r
+\r
+**/\r
+EFI_STATUS\r
+SdPeimFreeMemPool (\r
+  IN SD_PEIM_MEM_POOL       *Pool\r
+  )\r
+{\r
+  SD_PEIM_MEM_BLOCK         *Block;\r
+\r
+  ASSERT (Pool->Head != NULL);\r
+\r
+  //\r
+  // Unlink all the memory blocks from the pool, then free them.\r
+  // SdPeimUnlinkMemBlock can't be used to unlink and free the\r
+  // first block.\r
+  //\r
+  for (Block = Pool->Head->Next; Block != NULL; Block = Pool->Head->Next) {\r
+    SdPeimFreeMemBlock (Pool, Block);\r
+  }\r
+\r
+  SdPeimFreeMemBlock (Pool, Pool->Head);\r
+\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+  Allocate some memory from the host controller's memory pool\r
+  which can be used to communicate with host controller.\r
+\r
+  @param  Pool      The host controller's memory pool.\r
+  @param  Size      Size of the memory to allocate.\r
+\r
+  @return The allocated memory or NULL.\r
+\r
+**/\r
+VOID *\r
+SdPeimAllocateMem (\r
+  IN  SD_PEIM_MEM_POOL       *Pool,\r
+  IN  UINTN                  Size\r
+  )\r
+{\r
+  SD_PEIM_MEM_BLOCK          *Head;\r
+  SD_PEIM_MEM_BLOCK          *Block;\r
+  SD_PEIM_MEM_BLOCK          *NewBlock;\r
+  VOID                       *Mem;\r
+  UINTN                      AllocSize;\r
+  UINTN                      Pages;\r
+\r
+  Mem       = NULL;\r
+  AllocSize = SD_PEIM_MEM_ROUND (Size);\r
+  Head      = Pool->Head;\r
+  ASSERT (Head != NULL);\r
+\r
+  //\r
+  // First check whether current memory blocks can satisfy the allocation.\r
+  //\r
+  for (Block = Head; Block != NULL; Block = Block->Next) {\r
+    Mem = SdPeimAllocMemFromBlock (Block, AllocSize / SD_PEIM_MEM_UNIT);\r
+\r
+    if (Mem != NULL) {\r
+      ZeroMem (Mem, Size);\r
+      break;\r
+    }\r
+  }\r
+\r
+  if (Mem != NULL) {\r
+    return Mem;\r
+  }\r
+\r
+  //\r
+  // Create a new memory block if there is not enough memory\r
+  // in the pool. If the allocation size is larger than the\r
+  // default page number, just allocate a large enough memory\r
+  // block. Otherwise allocate default pages.\r
+  //\r
+  if (AllocSize > EFI_PAGES_TO_SIZE (SD_PEIM_MEM_DEFAULT_PAGES)) {\r
+    Pages = EFI_SIZE_TO_PAGES (AllocSize) + 1;\r
+  } else {\r
+    Pages = SD_PEIM_MEM_DEFAULT_PAGES;\r
+  }\r
+\r
+  NewBlock = SdPeimAllocMemBlock (Pages);\r
+  if (NewBlock == NULL) {\r
+    return NULL;\r
+  }\r
+\r
+  //\r
+  // Add the new memory block to the pool, then allocate memory from it\r
+  //\r
+  SdPeimInsertMemBlockToPool (Head, NewBlock);\r
+  Mem = SdPeimAllocMemFromBlock (NewBlock, AllocSize / SD_PEIM_MEM_UNIT);\r
+\r
+  if (Mem != NULL) {\r
+    ZeroMem (Mem, Size);\r
+  }\r
+\r
+  return Mem;\r
+}\r
+\r
+/**\r
+  Free the allocated memory back to the memory pool.\r
+\r
+  @param  Pool           The memory pool of the host controller.\r
+  @param  Mem            The memory to free.\r
+  @param  Size           The size of the memory to free.\r
+\r
+**/\r
+VOID\r
+SdPeimFreeMem (\r
+  IN SD_PEIM_MEM_POOL     *Pool,\r
+  IN VOID                 *Mem,\r
+  IN UINTN                Size\r
+  )\r
+{\r
+  SD_PEIM_MEM_BLOCK       *Head;\r
+  SD_PEIM_MEM_BLOCK       *Block;\r
+  UINT8                   *ToFree;\r
+  UINTN                   AllocSize;\r
+  UINTN                   Byte;\r
+  UINTN                   Bit;\r
+  UINTN                   Count;\r
+\r
+  Head      = Pool->Head;\r
+  AllocSize = SD_PEIM_MEM_ROUND (Size);\r
+  ToFree    = (UINT8 *) Mem;\r
+\r
+  for (Block = Head; Block != NULL; Block = Block->Next) {\r
+    //\r
+    // scan the memory block list for the memory block that\r
+    // completely contains the memory to free.\r
+    //\r
+    if ((Block->Buf <= ToFree) && ((ToFree + AllocSize) <= (Block->Buf + Block->BufLen))) {\r
+      //\r
+      // compute the start byte and bit in the bit array\r
+      //\r
+      Byte  = ((ToFree - Block->Buf) / SD_PEIM_MEM_UNIT) / 8;\r
+      Bit   = ((ToFree - Block->Buf) / SD_PEIM_MEM_UNIT) % 8;\r
+\r
+      //\r
+      // reset associated bits in bit arry\r
+      //\r
+      for (Count = 0; Count < (AllocSize / SD_PEIM_MEM_UNIT); Count++) {\r
+        ASSERT (SD_PEIM_MEM_BIT_IS_SET (Block->Bits[Byte], Bit));\r
+\r
+        Block->Bits[Byte] = (UINT8) (Block->Bits[Byte] ^ SD_PEIM_MEM_BIT (Bit));\r
+        SD_PEIM_NEXT_BIT (Byte, Bit);\r
+      }\r
+\r
+      break;\r
+    }\r
+  }\r
+\r
+  //\r
+  // If Block == NULL, it means that the current memory isn't\r
+  // in the host controller's pool. This is critical because\r
+  // the caller has passed in a wrong memory point\r
+  //\r
+  ASSERT (Block != NULL);\r
+\r
+  //\r
+  // Release the current memory block if it is empty and not the head\r
+  //\r
+  if ((Block != Head) && SdPeimIsMemBlockEmpty (Block)) {\r
+    SdPeimFreeMemBlock (Pool, Block);\r
+  }\r
+\r
+  return ;\r
+}\r
diff --git a/MdeModulePkg/Bus/Sd/SdBlockIoPei/SdHcMem.h b/MdeModulePkg/Bus/Sd/SdBlockIoPei/SdHcMem.h
new file mode 100644 (file)
index 0000000..096b625
--- /dev/null
@@ -0,0 +1,61 @@
+/** @file\r
+\r
+Copyright (c) 2015, Intel Corporation. All rights reserved.<BR>\r
+\r
+This program and the accompanying materials\r
+are licensed and made available under the terms and conditions\r
+of the BSD License which accompanies this distribution.  The\r
+full text of the license may be found at\r
+http://opensource.org/licenses/bsd-license.php\r
+\r
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+\r
+**/\r
+\r
+#ifndef _SD_PEIM_MEM_H_\r
+#define _SD_PEIM_MEM_H_\r
+\r
+#define SD_PEIM_MEM_BIT(a)          ((UINTN)(1 << (a)))\r
+\r
+#define SD_PEIM_MEM_BIT_IS_SET(Data, Bit)   \\r
+          ((BOOLEAN)(((Data) & SD_PEIM_MEM_BIT(Bit)) == SD_PEIM_MEM_BIT(Bit)))\r
+\r
+typedef struct _SD_PEIM_MEM_BLOCK SD_PEIM_MEM_BLOCK;\r
+\r
+struct _SD_PEIM_MEM_BLOCK {\r
+  UINT8                   *Bits;    // Bit array to record which unit is allocated\r
+  UINTN                   BitsLen;\r
+  UINT8                   *Buf;\r
+  UINTN                   BufLen;   // Memory size in bytes\r
+  SD_PEIM_MEM_BLOCK       *Next;\r
+};\r
+\r
+typedef struct _SD_PEIM_MEM_POOL {\r
+  SD_PEIM_MEM_BLOCK       *Head;\r
+} SD_PEIM_MEM_POOL;\r
+\r
+//\r
+// Memory allocation unit, note that the value must meet SD spec alignment requirement.\r
+//\r
+#define SD_PEIM_MEM_UNIT           128\r
+\r
+#define SD_PEIM_MEM_UNIT_MASK      (SD_PEIM_MEM_UNIT - 1)\r
+#define SD_PEIM_MEM_DEFAULT_PAGES  16\r
+\r
+#define SD_PEIM_MEM_ROUND(Len)     (((Len) + SD_PEIM_MEM_UNIT_MASK) & (~SD_PEIM_MEM_UNIT_MASK))\r
+\r
+//\r
+// Advance the byte and bit to the next bit, adjust byte accordingly.\r
+//\r
+#define SD_PEIM_NEXT_BIT(Byte, Bit)   \\r
+          do {                \\r
+            (Bit)++;          \\r
+            if ((Bit) > 7) {  \\r
+              (Byte)++;       \\r
+              (Bit) = 0;      \\r
+            }                 \\r
+          } while (0)\r
+\r
+#endif\r
+\r
diff --git a/MdeModulePkg/Bus/Sd/SdBlockIoPei/SdHci.c b/MdeModulePkg/Bus/Sd/SdBlockIoPei/SdHci.c
new file mode 100644 (file)
index 0000000..8f7ecf9
--- /dev/null
@@ -0,0 +1,2874 @@
+/** @file\r
+\r
+  Copyright (c) 2015 - 2016, Intel Corporation. All rights reserved.<BR>\r
+  This program and the accompanying materials\r
+  are licensed and made available under the terms and conditions of the BSD License\r
+  which accompanies this distribution.  The full text of the license may be found at\r
+  http://opensource.org/licenses/bsd-license.php.\r
+\r
+  THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+  WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+\r
+**/\r
+\r
+#include "SdBlockIoPei.h"\r
+\r
+/**\r
+  Read/Write specified SD host controller mmio register.\r
+\r
+  @param[in]      Address      The address of the mmio register to be read/written.\r
+  @param[in]      Read         A boolean to indicate it's read or write operation.\r
+  @param[in]      Count        The width of the mmio register in bytes.\r
+                               Must be 1, 2 , 4 or 8 bytes.\r
+  @param[in, out] Data         For read operations, the destination buffer to store\r
+                               the results. For write operations, the source buffer\r
+                               to write data from. The caller is responsible for\r
+                               having ownership of the data buffer and ensuring its\r
+                               size not less than Count bytes.\r
+\r
+  @retval EFI_INVALID_PARAMETER The Address or the Data or the Count is not valid.\r
+  @retval EFI_SUCCESS           The read/write operation succeeds.\r
+  @retval Others                The read/write operation fails.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+SdPeimHcRwMmio (\r
+  IN     UINTN                 Address,\r
+  IN     BOOLEAN               Read,\r
+  IN     UINT8                 Count,\r
+  IN OUT VOID                  *Data\r
+  )\r
+{\r
+  if ((Address == 0) || (Data == NULL))  {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  if ((Count != 1) && (Count != 2) && (Count != 4) && (Count != 8)) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  switch (Count) {\r
+    case 1:\r
+      if (Read) {\r
+        *(UINT8*)Data = MmioRead8 (Address);\r
+      } else {\r
+        MmioWrite8 (Address, *(UINT8*)Data);\r
+      }\r
+      break;\r
+    case 2:\r
+      if (Read) {\r
+        *(UINT16*)Data = MmioRead16 (Address);\r
+      } else {\r
+        MmioWrite16 (Address, *(UINT16*)Data);\r
+      }\r
+      break;\r
+    case 4:\r
+      if (Read) {\r
+        *(UINT32*)Data = MmioRead32 (Address);\r
+      } else {\r
+        MmioWrite32 (Address, *(UINT32*)Data);\r
+      }\r
+      break;\r
+    case 8:\r
+      if (Read) {\r
+        *(UINT64*)Data = MmioRead64 (Address);\r
+      } else {\r
+        MmioWrite64 (Address, *(UINT64*)Data);\r
+      }\r
+      break;\r
+    default:\r
+      ASSERT (FALSE);\r
+      return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+  Do OR operation with the value of the specified SD host controller mmio register.\r
+\r
+  @param[in] Address           The address of the mmio register to be read/written.\r
+  @param[in] Count             The width of the mmio register in bytes.\r
+                               Must be 1, 2 , 4 or 8 bytes.\r
+  @param[in] OrData            The pointer to the data used to do OR operation.\r
+                               The caller is responsible for having ownership of\r
+                               the data buffer and ensuring its size not less than\r
+                               Count bytes.\r
+\r
+  @retval EFI_INVALID_PARAMETER The Address or the OrData or the Count is not valid.\r
+  @retval EFI_SUCCESS           The OR operation succeeds.\r
+  @retval Others                The OR operation fails.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+SdPeimHcOrMmio (\r
+  IN  UINTN                    Address,\r
+  IN  UINT8                    Count,\r
+  IN  VOID                     *OrData\r
+  )\r
+{\r
+  EFI_STATUS                   Status;\r
+  UINT64                       Data;\r
+  UINT64                       Or;\r
+\r
+  Status = SdPeimHcRwMmio (Address, TRUE, Count, &Data);\r
+  if (EFI_ERROR (Status)) {\r
+    return Status;\r
+  }\r
+\r
+  if (Count == 1) {\r
+    Or = *(UINT8*) OrData;\r
+  } else if (Count == 2) {\r
+    Or = *(UINT16*) OrData;\r
+  } else if (Count == 4) {\r
+    Or = *(UINT32*) OrData;\r
+  } else if (Count == 8) {\r
+    Or = *(UINT64*) OrData;\r
+  } else {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  Data  |= Or;\r
+  Status = SdPeimHcRwMmio (Address, FALSE, Count, &Data);\r
+\r
+  return Status;\r
+}\r
+\r
+/**\r
+  Do AND operation with the value of the specified SD host controller mmio register.\r
+\r
+  @param[in] Address           The address of the mmio register to be read/written.\r
+  @param[in] Count             The width of the mmio register in bytes.\r
+                               Must be 1, 2 , 4 or 8 bytes.\r
+  @param[in] AndData           The pointer to the data used to do AND operation.\r
+                               The caller is responsible for having ownership of\r
+                               the data buffer and ensuring its size not less than\r
+                               Count bytes.\r
+\r
+  @retval EFI_INVALID_PARAMETER The Address or the AndData or the Count is not valid.\r
+  @retval EFI_SUCCESS           The AND operation succeeds.\r
+  @retval Others                The AND operation fails.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+SdPeimHcAndMmio (\r
+  IN  UINTN                    Address,\r
+  IN  UINT8                    Count,\r
+  IN  VOID                     *AndData\r
+  )\r
+{\r
+  EFI_STATUS                   Status;\r
+  UINT64                       Data;\r
+  UINT64                       And;\r
+\r
+  Status = SdPeimHcRwMmio (Address, TRUE, Count, &Data);\r
+  if (EFI_ERROR (Status)) {\r
+    return Status;\r
+  }\r
+\r
+  if (Count == 1) {\r
+    And = *(UINT8*) AndData;\r
+  } else if (Count == 2) {\r
+    And = *(UINT16*) AndData;\r
+  } else if (Count == 4) {\r
+    And = *(UINT32*) AndData;\r
+  } else if (Count == 8) {\r
+    And = *(UINT64*) AndData;\r
+  } else {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  Data  &= And;\r
+  Status = SdPeimHcRwMmio (Address, FALSE, Count, &Data);\r
+\r
+  return Status;\r
+}\r
+\r
+/**\r
+  Wait for the value of the specified MMIO register set to the test value.\r
+\r
+  @param[in]  Address       The address of the mmio register to be checked.\r
+  @param[in]  Count         The width of the mmio register in bytes.\r
+                            Must be 1, 2, 4 or 8 bytes.\r
+  @param[in]  MaskValue     The mask value of memory.\r
+  @param[in]  TestValue     The test value of memory.\r
+\r
+  @retval EFI_NOT_READY     The MMIO register hasn't set to the expected value.\r
+  @retval EFI_SUCCESS       The MMIO register has expected value.\r
+  @retval Others            The MMIO operation fails.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+SdPeimHcCheckMmioSet (\r
+  IN  UINTN                     Address,\r
+  IN  UINT8                     Count,\r
+  IN  UINT64                    MaskValue,\r
+  IN  UINT64                    TestValue\r
+  )\r
+{\r
+  EFI_STATUS            Status;\r
+  UINT64                Value;\r
+\r
+  //\r
+  // Access PCI MMIO space to see if the value is the tested one.\r
+  //\r
+  Value  = 0;\r
+  Status = SdPeimHcRwMmio (Address, TRUE, Count, &Value);\r
+  if (EFI_ERROR (Status)) {\r
+    return Status;\r
+  }\r
+\r
+  Value &= MaskValue;\r
+\r
+  if (Value == TestValue) {\r
+    return EFI_SUCCESS;\r
+  }\r
+\r
+  return EFI_NOT_READY;\r
+}\r
+\r
+/**\r
+  Wait for the value of the specified MMIO register set to the test value.\r
+\r
+  @param[in]  Address       The address of the mmio register to wait.\r
+  @param[in]  Count         The width of the mmio register in bytes.\r
+                            Must be 1, 2, 4 or 8 bytes.\r
+  @param[in]  MaskValue     The mask value of memory.\r
+  @param[in]  TestValue     The test value of memory.\r
+  @param[in]  Timeout       The time out value for wait memory set, uses 1\r
+                            microsecond as a unit.\r
+\r
+  @retval EFI_TIMEOUT       The MMIO register hasn't expected value in timeout\r
+                            range.\r
+  @retval EFI_SUCCESS       The MMIO register has expected value.\r
+  @retval Others            The MMIO operation fails.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+SdPeimHcWaitMmioSet (\r
+  IN  UINTN                     Address,\r
+  IN  UINT8                     Count,\r
+  IN  UINT64                    MaskValue,\r
+  IN  UINT64                    TestValue,\r
+  IN  UINT64                    Timeout\r
+  )\r
+{\r
+  EFI_STATUS            Status;\r
+  BOOLEAN               InfiniteWait;\r
+\r
+  if (Timeout == 0) {\r
+    InfiniteWait = TRUE;\r
+  } else {\r
+    InfiniteWait = FALSE;\r
+  }\r
+\r
+  while (InfiniteWait || (Timeout > 0)) {\r
+    Status = SdPeimHcCheckMmioSet (\r
+               Address,\r
+               Count,\r
+               MaskValue,\r
+               TestValue\r
+               );\r
+    if (Status != EFI_NOT_READY) {\r
+      return Status;\r
+    }\r
+\r
+    //\r
+    // Stall for 1 microsecond.\r
+    //\r
+    MicroSecondDelay (1);\r
+\r
+    Timeout--;\r
+  }\r
+\r
+  return EFI_TIMEOUT;\r
+}\r
+\r
+/**\r
+  Software reset the specified SD host controller and enable all interrupts.\r
+\r
+  @param[in] Bar            The mmio base address of the slot to be accessed.\r
+\r
+  @retval EFI_SUCCESS       The software reset executes successfully.\r
+  @retval Others            The software reset fails.\r
+\r
+**/\r
+EFI_STATUS\r
+SdPeimHcReset (\r
+  IN UINTN                  Bar\r
+  )\r
+{\r
+  EFI_STATUS                Status;\r
+  UINT8                     SwReset;\r
+\r
+  SwReset = 0xFF;\r
+  Status  = SdPeimHcRwMmio (Bar + SD_HC_SW_RST, FALSE, sizeof (SwReset), &SwReset);\r
+\r
+  if (EFI_ERROR (Status)) {\r
+    DEBUG ((EFI_D_ERROR, "SdPeimHcReset: write full 1 fails: %r\n", Status));\r
+    return Status;\r
+  }\r
+\r
+  Status = SdPeimHcWaitMmioSet (\r
+             Bar + SD_HC_SW_RST,\r
+             sizeof (SwReset),\r
+             0xFF,\r
+             0x00,\r
+             SD_TIMEOUT\r
+             );\r
+  if (EFI_ERROR (Status)) {\r
+    DEBUG ((EFI_D_INFO, "SdPeimHcReset: reset done with %r\n", Status));\r
+    return Status;\r
+  }\r
+  //\r
+  // Enable all interrupt after reset all.\r
+  //\r
+  Status = SdPeimHcEnableInterrupt (Bar);\r
+\r
+  return Status;\r
+}\r
+\r
+/**\r
+  Set all interrupt status bits in Normal and Error Interrupt Status Enable\r
+  register.\r
+\r
+  @param[in] Bar            The mmio base address of the slot to be accessed.\r
+\r
+  @retval EFI_SUCCESS       The operation executes successfully.\r
+  @retval Others            The operation fails.\r
+\r
+**/\r
+EFI_STATUS\r
+SdPeimHcEnableInterrupt (\r
+  IN UINTN                  Bar\r
+  )\r
+{\r
+  EFI_STATUS                Status;\r
+  UINT16                    IntStatus;\r
+\r
+  //\r
+  // Enable all bits in Error Interrupt Status Enable Register\r
+  //\r
+  IntStatus = 0xFFFF;\r
+  Status = SdPeimHcRwMmio (Bar + SD_HC_ERR_INT_STS_EN, FALSE, sizeof (IntStatus), &IntStatus);\r
+  if (EFI_ERROR (Status)) {\r
+    return Status;\r
+  }\r
+  //\r
+  // Enable all bits in Normal Interrupt Status Enable Register\r
+  //\r
+  IntStatus = 0xFFFF;\r
+  Status = SdPeimHcRwMmio (Bar + SD_HC_NOR_INT_STS_EN, FALSE, sizeof (IntStatus), &IntStatus);\r
+\r
+  return Status;\r
+}\r
+\r
+/**\r
+  Get the capability data from the specified slot.\r
+\r
+  @param[in]  Bar             The mmio base address of the slot to be accessed.\r
+  @param[out] Capability      The buffer to store the capability data.\r
+\r
+  @retval EFI_SUCCESS         The operation executes successfully.\r
+  @retval Others              The operation fails.\r
+\r
+**/\r
+EFI_STATUS\r
+SdPeimHcGetCapability (\r
+  IN     UINTN              Bar,\r
+     OUT SD_HC_SLOT_CAP     *Capability\r
+  )\r
+{\r
+  EFI_STATUS                Status;\r
+  UINT64                    Cap;\r
+\r
+  Status = SdPeimHcRwMmio (Bar + SD_HC_CAP, TRUE, sizeof (Cap), &Cap);\r
+  if (EFI_ERROR (Status)) {\r
+    return Status;\r
+  }\r
+\r
+  CopyMem (Capability, &Cap, sizeof (Cap));\r
+\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+  Detect whether there is a SD card attached at the specified SD host controller\r
+  slot.\r
+\r
+  Refer to SD Host Controller Simplified spec 3.0 Section 3.1 for details.\r
+\r
+  @param[in]  Bar           The mmio base address of the slot to be accessed.\r
+\r
+  @retval EFI_SUCCESS       There is a SD card attached.\r
+  @retval EFI_NO_MEDIA      There is not a SD card attached.\r
+  @retval Others            The detection fails.\r
+\r
+**/\r
+EFI_STATUS\r
+SdPeimHcCardDetect (\r
+  IN UINTN                  Bar\r
+  )\r
+{\r
+  EFI_STATUS                Status;\r
+  UINT16                    Data;\r
+  UINT32                    PresentState;\r
+\r
+  //\r
+  // Check Normal Interrupt Status Register\r
+  //\r
+  Status = SdPeimHcRwMmio (Bar + SD_HC_NOR_INT_STS, TRUE, sizeof (Data), &Data);\r
+  if (EFI_ERROR (Status)) {\r
+    return Status;\r
+  }\r
+\r
+  if ((Data & (BIT6 | BIT7)) != 0) {\r
+    //\r
+    // Clear BIT6 and BIT7 by writing 1 to these two bits if set.\r
+    //\r
+    Data  &= BIT6 | BIT7;\r
+    Status = SdPeimHcRwMmio (Bar + SD_HC_NOR_INT_STS, FALSE, sizeof (Data), &Data);\r
+    if (EFI_ERROR (Status)) {\r
+      return Status;\r
+    }\r
+  }\r
+\r
+  //\r
+  // Check Present State Register to see if there is a card presented.\r
+  //\r
+  Status = SdPeimHcRwMmio (Bar + SD_HC_PRESENT_STATE, TRUE, sizeof (PresentState), &PresentState);\r
+  if (EFI_ERROR (Status)) {\r
+    return Status;\r
+  }\r
+\r
+  if ((PresentState & BIT16) != 0) {\r
+    return EFI_SUCCESS;\r
+  } else {\r
+    return EFI_NO_MEDIA;\r
+  }\r
+}\r
+\r
+/**\r
+  Stop SD card clock.\r
+\r
+  Refer to SD Host Controller Simplified spec 3.0 Section 3.2.2 for details.\r
+\r
+  @param[in]  Bar           The mmio base address of the slot to be accessed.\r
+\r
+  @retval EFI_SUCCESS       Succeed to stop SD clock.\r
+  @retval Others            Fail to stop SD clock.\r
+\r
+**/\r
+EFI_STATUS\r
+SdPeimHcStopClock (\r
+  IN UINTN                  Bar\r
+  )\r
+{\r
+  EFI_STATUS                Status;\r
+  UINT32                    PresentState;\r
+  UINT16                    ClockCtrl;\r
+\r
+  //\r
+  // Ensure no SD transactions are occurring on the SD Bus by\r
+  // waiting for Command Inhibit (DAT) and Command Inhibit (CMD)\r
+  // in the Present State register to be 0.\r
+  //\r
+  Status = SdPeimHcWaitMmioSet (\r
+             Bar + SD_HC_PRESENT_STATE,\r
+             sizeof (PresentState),\r
+             BIT0 | BIT1,\r
+             0,\r
+             SD_TIMEOUT\r
+             );\r
+  if (EFI_ERROR (Status)) {\r
+    return Status;\r
+  }\r
+\r
+  //\r
+  // Set SD Clock Enable in the Clock Control register to 0\r
+  //\r
+  ClockCtrl = (UINT16)~BIT2;\r
+  Status = SdPeimHcAndMmio (Bar + SD_HC_CLOCK_CTRL, sizeof (ClockCtrl), &ClockCtrl);\r
+\r
+  return Status;\r
+}\r
+\r
+/**\r
+  SD card clock supply.\r
+\r
+  Refer to SD Host Controller Simplified spec 3.0 Section 3.2.1 for details.\r
+\r
+  @param[in] Bar            The mmio base address of the slot to be accessed.\r
+  @param[in] ClockFreq      The max clock frequency to be set. The unit is KHz.\r
+\r
+  @retval EFI_SUCCESS       The clock is supplied successfully.\r
+  @retval Others            The clock isn't supplied successfully.\r
+\r
+**/\r
+EFI_STATUS\r
+SdPeimHcClockSupply (\r
+  IN UINTN                  Bar,\r
+  IN UINT64                 ClockFreq\r
+  )\r
+{\r
+  EFI_STATUS                Status;\r
+  SD_HC_SLOT_CAP            Capability;\r
+  UINT32                    BaseClkFreq;\r
+  UINT32                    SettingFreq;\r
+  UINT32                    Divisor;\r
+  UINT32                    Remainder;\r
+  UINT16                    ControllerVer;\r
+  UINT16                    ClockCtrl;\r
+\r
+  //\r
+  // Calculate a divisor for SD clock frequency\r
+  //\r
+  Status = SdPeimHcGetCapability (Bar, &Capability);\r
+  if (EFI_ERROR (Status)) {\r
+    return Status;\r
+  }\r
+  ASSERT (Capability.BaseClkFreq != 0);\r
+\r
+  BaseClkFreq = Capability.BaseClkFreq;\r
+  if ((ClockFreq > (BaseClkFreq * 1000)) || (ClockFreq == 0)) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+  //\r
+  // Calculate the divisor of base frequency.\r
+  //\r
+  Divisor     = 0;\r
+  SettingFreq = BaseClkFreq * 1000;\r
+  while (ClockFreq < SettingFreq) {\r
+    Divisor++;\r
+\r
+    SettingFreq = (BaseClkFreq * 1000) / (2 * Divisor);\r
+    Remainder   = (BaseClkFreq * 1000) % (2 * Divisor);\r
+    if ((ClockFreq == SettingFreq) && (Remainder == 0)) {\r
+      break;\r
+    }\r
+    if ((ClockFreq == SettingFreq) && (Remainder != 0)) {\r
+      SettingFreq ++;\r
+    }\r
+  }\r
+\r
+  DEBUG ((EFI_D_INFO, "BaseClkFreq %dMHz Divisor %d ClockFreq %dKhz\n", BaseClkFreq, Divisor, ClockFreq));\r
+\r
+  Status = SdPeimHcRwMmio (Bar + SD_HC_CTRL_VER, TRUE, sizeof (ControllerVer), &ControllerVer);\r
+  if (EFI_ERROR (Status)) {\r
+    return Status;\r
+  }\r
+  //\r
+  // Set SDCLK Frequency Select and Internal Clock Enable fields in Clock Control register.\r
+  //\r
+  if ((ControllerVer & 0xFF) == 2) {\r
+    ASSERT (Divisor <= 0x3FF);\r
+    ClockCtrl = ((Divisor & 0xFF) << 8) | ((Divisor & 0x300) >> 2);\r
+  } else if (((ControllerVer & 0xFF) == 0) || ((ControllerVer & 0xFF) == 1)) {\r
+    //\r
+    // Only the most significant bit can be used as divisor.\r
+    //\r
+    if (((Divisor - 1) & Divisor) != 0) {\r
+      Divisor = 1 << (HighBitSet32 (Divisor) + 1);\r
+    }\r
+    ASSERT (Divisor <= 0x80);\r
+    ClockCtrl = (Divisor & 0xFF) << 8;\r
+  } else {\r
+    DEBUG ((EFI_D_ERROR, "Unknown SD Host Controller Spec version [0x%x]!!!\n", ControllerVer));\r
+    return EFI_UNSUPPORTED;\r
+  }\r
+\r
+  //\r
+  // Stop bus clock at first\r
+  //\r
+  Status = SdPeimHcStopClock (Bar);\r
+  if (EFI_ERROR (Status)) {\r
+    return Status;\r
+  }\r
+\r
+  //\r
+  // Supply clock frequency with specified divisor\r
+  //\r
+  ClockCtrl |= BIT0;\r
+  Status = SdPeimHcRwMmio (Bar + SD_HC_CLOCK_CTRL, FALSE, sizeof (ClockCtrl), &ClockCtrl);\r
+  if (EFI_ERROR (Status)) {\r
+    DEBUG ((EFI_D_ERROR, "Set SDCLK Frequency Select and Internal Clock Enable fields fails\n"));\r
+    return Status;\r
+  }\r
+\r
+  //\r
+  // Wait Internal Clock Stable in the Clock Control register to be 1\r
+  //\r
+  Status = SdPeimHcWaitMmioSet (\r
+             Bar + SD_HC_CLOCK_CTRL,\r
+             sizeof (ClockCtrl),\r
+             BIT1,\r
+             BIT1,\r
+             SD_TIMEOUT\r
+             );\r
+  if (EFI_ERROR (Status)) {\r
+    return Status;\r
+  }\r
+\r
+  //\r
+  // Set SD Clock Enable in the Clock Control register to 1\r
+  //\r
+  ClockCtrl = BIT2;\r
+  Status = SdPeimHcOrMmio (Bar + SD_HC_CLOCK_CTRL, sizeof (ClockCtrl), &ClockCtrl);\r
+\r
+  return Status;\r
+}\r
+\r
+/**\r
+  SD bus power control.\r
+\r
+  Refer to SD Host Controller Simplified spec 3.0 Section 3.3 for details.\r
+\r
+  @param[in] Bar            The mmio base address of the slot to be accessed.\r
+  @param[in] PowerCtrl      The value setting to the power control register.\r
+\r
+  @retval TRUE              There is a SD card attached.\r
+  @retval FALSE             There is no a SD card attached.\r
+\r
+**/\r
+EFI_STATUS\r
+SdPeimHcPowerControl (\r
+  IN UINTN                  Bar,\r
+  IN UINT8                  PowerCtrl\r
+  )\r
+{\r
+  EFI_STATUS                Status;\r
+\r
+  //\r
+  // Clr SD Bus Power\r
+  //\r
+  PowerCtrl &= (UINT8)~BIT0;\r
+  Status = SdPeimHcRwMmio (Bar + SD_HC_POWER_CTRL, FALSE, sizeof (PowerCtrl), &PowerCtrl);\r
+  if (EFI_ERROR (Status)) {\r
+    return Status;\r
+  }\r
+\r
+  //\r
+  // Set SD Bus Voltage Select and SD Bus Power fields in Power Control Register\r
+  //\r
+  PowerCtrl |= BIT0;\r
+  Status = SdPeimHcRwMmio (Bar + SD_HC_POWER_CTRL, FALSE, sizeof (PowerCtrl), &PowerCtrl);\r
+\r
+  return Status;\r
+}\r
+\r
+/**\r
+  Set the SD bus width.\r
+\r
+  Refer to SD Host Controller Simplified spec 3.0 Section 3.4 for details.\r
+\r
+  @param[in] Bar            The mmio base address of the slot to be accessed.\r
+  @param[in] BusWidth       The bus width used by the SD device, it must be 1, 4 or 8.\r
+\r
+  @retval EFI_SUCCESS       The bus width is set successfully.\r
+  @retval Others            The bus width isn't set successfully.\r
+\r
+**/\r
+EFI_STATUS\r
+SdPeimHcSetBusWidth (\r
+  IN UINTN                  Bar,\r
+  IN UINT16                 BusWidth\r
+  )\r
+{\r
+  EFI_STATUS                Status;\r
+  UINT8                     HostCtrl1;\r
+\r
+  if (BusWidth == 1) {\r
+    HostCtrl1 = (UINT8)~(BIT5 | BIT1);\r
+    Status = SdPeimHcAndMmio (Bar + SD_HC_HOST_CTRL1, sizeof (HostCtrl1), &HostCtrl1);\r
+  } else if (BusWidth == 4) {\r
+    Status = SdPeimHcRwMmio (Bar + SD_HC_HOST_CTRL1, TRUE, sizeof (HostCtrl1), &HostCtrl1);\r
+    if (EFI_ERROR (Status)) {\r
+      return Status;\r
+    }\r
+    HostCtrl1 |= BIT1;\r
+    HostCtrl1 &= (UINT8)~BIT5;\r
+    Status = SdPeimHcRwMmio (Bar + SD_HC_HOST_CTRL1, FALSE, sizeof (HostCtrl1), &HostCtrl1);\r
+  } else if (BusWidth == 8) {\r
+    Status = SdPeimHcRwMmio (Bar + SD_HC_HOST_CTRL1, TRUE, sizeof (HostCtrl1), &HostCtrl1);\r
+    if (EFI_ERROR (Status)) {\r
+      return Status;\r
+    }\r
+    HostCtrl1 &= (UINT8)~BIT1;\r
+    HostCtrl1 |= BIT5;\r
+    Status = SdPeimHcRwMmio (Bar + SD_HC_HOST_CTRL1, FALSE, sizeof (HostCtrl1), &HostCtrl1);\r
+  } else {\r
+    ASSERT (FALSE);\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  return Status;\r
+}\r
+\r
+/**\r
+  Supply SD card with lowest clock frequency at initialization.\r
+\r
+  @param[in] Bar            The mmio base address of the slot to be accessed.\r
+\r
+  @retval EFI_SUCCESS       The clock is supplied successfully.\r
+  @retval Others            The clock isn't supplied successfully.\r
+\r
+**/\r
+EFI_STATUS\r
+SdPeimHcInitClockFreq (\r
+  IN UINTN                  Bar\r
+  )\r
+{\r
+  EFI_STATUS                Status;\r
+  SD_HC_SLOT_CAP            Capability;\r
+  UINT32                    InitFreq;\r
+\r
+  //\r
+  // Calculate a divisor for SD clock frequency\r
+  //\r
+  Status = SdPeimHcGetCapability (Bar, &Capability);\r
+  if (EFI_ERROR (Status)) {\r
+    return Status;\r
+  }\r
+\r
+  if (Capability.BaseClkFreq == 0) {\r
+    //\r
+    // Don't support get Base Clock Frequency information via another method\r
+    //\r
+    return EFI_UNSUPPORTED;\r
+  }\r
+  //\r
+  // Supply 400KHz clock frequency at initialization phase.\r
+  //\r
+  InitFreq = 400;\r
+  Status = SdPeimHcClockSupply (Bar, InitFreq);\r
+  return Status;\r
+}\r
+\r
+/**\r
+  Supply SD card with maximum voltage at initialization.\r
+\r
+  Refer to SD Host Controller Simplified spec 3.0 Section 3.3 for details.\r
+\r
+  @param[in] Bar            The mmio base address of the slot to be accessed.\r
+\r
+  @retval EFI_SUCCESS       The voltage is supplied successfully.\r
+  @retval Others            The voltage isn't supplied successfully.\r
+\r
+**/\r
+EFI_STATUS\r
+SdPeimHcInitPowerVoltage (\r
+  IN UINTN                  Bar\r
+  )\r
+{\r
+  EFI_STATUS                Status;\r
+  SD_HC_SLOT_CAP            Capability;\r
+  UINT8                     MaxVoltage;\r
+  UINT8                     HostCtrl2;\r
+\r
+  //\r
+  // Get the support voltage of the Host Controller\r
+  //\r
+  Status = SdPeimHcGetCapability (Bar, &Capability);\r
+  if (EFI_ERROR (Status)) {\r
+    return Status;\r
+  }\r
+  //\r
+  // Calculate supported maximum voltage according to SD Bus Voltage Select\r
+  //\r
+  if (Capability.Voltage33 != 0) {\r
+    //\r
+    // Support 3.3V\r
+    //\r
+    MaxVoltage = 0x0E;\r
+  } else if (Capability.Voltage30 != 0) {\r
+    //\r
+    // Support 3.0V\r
+    //\r
+    MaxVoltage = 0x0C;\r
+  } else if (Capability.Voltage18 != 0) {\r
+    //\r
+    // Support 1.8V\r
+    //\r
+    MaxVoltage = 0x0A;\r
+    HostCtrl2  = BIT3;\r
+    Status = SdPeimHcOrMmio (Bar + SD_HC_HOST_CTRL2, sizeof (HostCtrl2), &HostCtrl2);\r
+    if (EFI_ERROR (Status)) {\r
+      return Status;\r
+    }\r
+    MicroSecondDelay (5000);\r
+  } else {\r
+    ASSERT (FALSE);\r
+    return EFI_DEVICE_ERROR;\r
+  }\r
+\r
+  //\r
+  // Set SD Bus Voltage Select and SD Bus Power fields in Power Control Register\r
+  //\r
+  Status = SdPeimHcPowerControl (Bar, MaxVoltage);\r
+\r
+  return Status;\r
+}\r
+\r
+/**\r
+  Initialize the Timeout Control register with most conservative value at initialization.\r
+\r
+  Refer to SD Host Controller Simplified spec 3.0 Section 2.2.15 for details.\r
+\r
+  @param[in] Bar            The mmio base address of the slot to be accessed.\r
+\r
+  @retval EFI_SUCCESS       The timeout control register is configured successfully.\r
+  @retval Others            The timeout control register isn't configured successfully.\r
+\r
+**/\r
+EFI_STATUS\r
+SdPeimHcInitTimeoutCtrl (\r
+  IN UINTN                  Bar\r
+  )\r
+{\r
+  EFI_STATUS                Status;\r
+  UINT8                     Timeout;\r
+\r
+  Timeout = 0x0E;\r
+  Status  = SdPeimHcRwMmio (Bar + SD_HC_TIMEOUT_CTRL, FALSE, sizeof (Timeout), &Timeout);\r
+\r
+  return Status;\r
+}\r
+\r
+/**\r
+  Initial SD host controller with lowest clock frequency, max power and max timeout value\r
+  at initialization.\r
+\r
+  @param[in] Bar            The mmio base address of the slot to be accessed.\r
+\r
+  @retval EFI_SUCCESS       The host controller is initialized successfully.\r
+  @retval Others            The host controller isn't initialized successfully.\r
+\r
+**/\r
+EFI_STATUS\r
+SdPeimHcInitHost (\r
+  IN UINTN                  Bar\r
+  )\r
+{\r
+  EFI_STATUS       Status;\r
+\r
+  Status = SdPeimHcInitClockFreq (Bar);\r
+  if (EFI_ERROR (Status)) {\r
+    return Status;\r
+  }\r
+\r
+  Status = SdPeimHcInitPowerVoltage (Bar);\r
+  if (EFI_ERROR (Status)) {\r
+    return Status;\r
+  }\r
+\r
+  Status = SdPeimHcInitTimeoutCtrl (Bar);\r
+  return Status;\r
+}\r
+\r
+/**\r
+  Turn on/off LED.\r
+\r
+  @param[in] Bar            The mmio base address of the slot to be accessed.\r
+  @param[in] On             The boolean to turn on/off LED.\r
+\r
+  @retval EFI_SUCCESS       The LED is turned on/off successfully.\r
+  @retval Others            The LED isn't turned on/off successfully.\r
+\r
+**/\r
+EFI_STATUS\r
+SdPeimHcLedOnOff (\r
+  IN UINTN                  Bar,\r
+  IN BOOLEAN                On\r
+  )\r
+{\r
+  EFI_STATUS                Status;\r
+  UINT8                     HostCtrl1;\r
+\r
+  if (On) {\r
+    HostCtrl1 = BIT0;\r
+    Status    = SdPeimHcOrMmio (Bar + SD_HC_HOST_CTRL1, sizeof (HostCtrl1), &HostCtrl1);\r
+  } else {\r
+    HostCtrl1 = (UINT8)~BIT0;\r
+    Status    = SdPeimHcAndMmio (Bar + SD_HC_HOST_CTRL1, sizeof (HostCtrl1), &HostCtrl1);\r
+  }\r
+\r
+  return Status;\r
+}\r
+\r
+/**\r
+  Build ADMA descriptor table for transfer.\r
+\r
+  Refer to SD Host Controller Simplified spec 3.0 Section 1.13 for details.\r
+\r
+  @param[in] Trb            The pointer to the SD_TRB instance.\r
+\r
+  @retval EFI_SUCCESS       The ADMA descriptor table is created successfully.\r
+  @retval Others            The ADMA descriptor table isn't created successfully.\r
+\r
+**/\r
+EFI_STATUS\r
+BuildAdmaDescTable (\r
+  IN SD_TRB                 *Trb\r
+  )\r
+{\r
+  EFI_PHYSICAL_ADDRESS      Data;\r
+  UINT64                    DataLen;\r
+  UINT64                    Entries;\r
+  UINT32                    Index;\r
+  UINT64                    Remaining;\r
+  UINT32                    Address;\r
+\r
+  Data    = (EFI_PHYSICAL_ADDRESS)(UINTN)Trb->Data;\r
+  DataLen = Trb->DataLen;\r
+  //\r
+  // Only support 32bit ADMA Descriptor Table\r
+  //\r
+  if ((Data >= 0x100000000ul) || ((Data + DataLen) > 0x100000000ul)) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+  //\r
+  // Address field shall be set on 32-bit boundary (Lower 2-bit is always set to 0)\r
+  // for 32-bit address descriptor table.\r
+  //\r
+  if ((Data & (BIT0 | BIT1)) != 0) {\r
+    DEBUG ((EFI_D_INFO, "The buffer [0x%x] to construct ADMA desc is not aligned to 4 bytes boundary!\n", Data));\r
+  }\r
+\r
+  Entries = DivU64x32 ((DataLen + ADMA_MAX_DATA_PER_LINE - 1), ADMA_MAX_DATA_PER_LINE);\r
+\r
+  Trb->AdmaDescSize = (UINTN)MultU64x32 (Entries, sizeof (SD_HC_ADMA_DESC_LINE));\r
+  Trb->AdmaDesc     = SdPeimAllocateMem (Trb->Slot->Private->Pool, Trb->AdmaDescSize);\r
+  if (Trb->AdmaDesc == NULL) {\r
+    return EFI_OUT_OF_RESOURCES;\r
+  }\r
+\r
+  Remaining = DataLen;\r
+  Address   = (UINT32)Data;\r
+  for (Index = 0; Index < Entries; Index++) {\r
+    if (Remaining <= ADMA_MAX_DATA_PER_LINE) {\r
+      Trb->AdmaDesc[Index].Valid = 1;\r
+      Trb->AdmaDesc[Index].Act   = 2;\r
+      Trb->AdmaDesc[Index].Length  = (UINT16)Remaining;\r
+      Trb->AdmaDesc[Index].Address = Address;\r
+      break;\r
+    } else {\r
+      Trb->AdmaDesc[Index].Valid = 1;\r
+      Trb->AdmaDesc[Index].Act   = 2;\r
+      Trb->AdmaDesc[Index].Length  = 0;\r
+      Trb->AdmaDesc[Index].Address = Address;\r
+    }\r
+\r
+    Remaining -= ADMA_MAX_DATA_PER_LINE;\r
+    Address   += ADMA_MAX_DATA_PER_LINE;\r
+  }\r
+\r
+  //\r
+  // Set the last descriptor line as end of descriptor table\r
+  //\r
+  Trb->AdmaDesc[Index].End = 1;\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+  Create a new TRB for the SD cmd request.\r
+\r
+  @param[in] Slot           The slot number of the SD card to send the command to.\r
+  @param[in] Packet         A pointer to the SD command data structure.\r
+\r
+  @return Created Trb or NULL.\r
+\r
+**/\r
+SD_TRB *\r
+SdPeimCreateTrb (\r
+  IN SD_PEIM_HC_SLOT          *Slot,\r
+  IN SD_COMMAND_PACKET        *Packet\r
+  )\r
+{\r
+  SD_TRB                      *Trb;\r
+  EFI_STATUS                  Status;\r
+  SD_HC_SLOT_CAP              Capability;\r
+\r
+  //\r
+  // Calculate a divisor for SD clock frequency\r
+  //\r
+  Status = SdPeimHcGetCapability (Slot->SdHcBase, &Capability);\r
+  if (EFI_ERROR (Status)) {\r
+    return NULL;\r
+  }\r
+\r
+  Trb = SdPeimAllocateMem (Slot->Private->Pool, sizeof (SD_TRB));\r
+  if (Trb == NULL) {\r
+    return NULL;\r
+  }\r
+\r
+  Trb->Slot      = Slot;\r
+  Trb->BlockSize = 0x200;\r
+  Trb->Packet    = Packet;\r
+  Trb->Timeout   = Packet->Timeout;\r
+\r
+  if ((Packet->InTransferLength != 0) && (Packet->InDataBuffer != NULL)) {\r
+    Trb->Data    = Packet->InDataBuffer;\r
+    Trb->DataLen = Packet->InTransferLength;\r
+    Trb->Read    = TRUE;\r
+  } else if ((Packet->OutTransferLength != 0) && (Packet->OutDataBuffer != NULL)) {\r
+    Trb->Data    = Packet->OutDataBuffer;\r
+    Trb->DataLen = Packet->OutTransferLength;\r
+    Trb->Read    = FALSE;\r
+  } else if ((Packet->InTransferLength == 0) && (Packet->OutTransferLength == 0)) {\r
+    Trb->Data    = NULL;\r
+    Trb->DataLen = 0;\r
+  } else {\r
+    goto Error;\r
+  }\r
+\r
+  if ((Trb->DataLen % Trb->BlockSize) != 0) {\r
+    if (Trb->DataLen < Trb->BlockSize) {\r
+      Trb->BlockSize = (UINT16)Trb->DataLen;\r
+    }\r
+  }\r
+\r
+  if (Trb->DataLen == 0) {\r
+    Trb->Mode = SdNoData;\r
+  } else if (Capability.Adma2 != 0) {\r
+    Trb->Mode = SdAdmaMode;\r
+    Status = BuildAdmaDescTable (Trb);\r
+    if (EFI_ERROR (Status)) {\r
+      goto Error;\r
+    }\r
+  } else if (Capability.Sdma != 0) {\r
+    Trb->Mode = SdSdmaMode;\r
+  } else {\r
+    Trb->Mode = SdPioMode;\r
+  }\r
+\r
+  return Trb;\r
+\r
+Error:\r
+  SdPeimFreeTrb (Trb);\r
+  return NULL;\r
+}\r
+\r
+/**\r
+  Free the resource used by the TRB.\r
+\r
+  @param[in] Trb        The pointer to the SD_TRB instance.\r
+\r
+**/\r
+VOID\r
+SdPeimFreeTrb (\r
+  IN SD_TRB           *Trb\r
+  )\r
+{\r
+  if ((Trb != NULL) && (Trb->AdmaDesc != NULL)) {\r
+    SdPeimFreeMem (Trb->Slot->Private->Pool, Trb->AdmaDesc, Trb->AdmaDescSize);\r
+  }\r
+\r
+  if (Trb != NULL) {\r
+    SdPeimFreeMem (Trb->Slot->Private->Pool, Trb, sizeof (SD_TRB));\r
+  }\r
+  return;\r
+}\r
+\r
+/**\r
+  Check if the env is ready for execute specified TRB.\r
+\r
+  @param[in] Bar            The mmio base address of the slot to be accessed.\r
+  @param[in] Trb            The pointer to the SD_TRB instance.\r
+\r
+  @retval EFI_SUCCESS       The env is ready for TRB execution.\r
+  @retval EFI_NOT_READY     The env is not ready for TRB execution.\r
+  @retval Others            Some erros happen.\r
+\r
+**/\r
+EFI_STATUS\r
+SdPeimCheckTrbEnv (\r
+  IN UINTN                  Bar,\r
+  IN SD_TRB                 *Trb\r
+  )\r
+{\r
+  EFI_STATUS                          Status;\r
+  SD_COMMAND_PACKET                   *Packet;\r
+  UINT32                              PresentState;\r
+\r
+  Packet = Trb->Packet;\r
+\r
+  if ((Packet->SdCmdBlk->CommandType == SdCommandTypeAdtc) ||\r
+      (Packet->SdCmdBlk->ResponseType == SdResponseTypeR1b) ||\r
+      (Packet->SdCmdBlk->ResponseType == SdResponseTypeR5b)) {\r
+    //\r
+    // Wait Command Inhibit (CMD) and Command Inhibit (DAT) in\r
+    // the Present State register to be 0\r
+    //\r
+    PresentState = BIT0 | BIT1;\r
+    if (Packet->SdCmdBlk->CommandIndex == SD_SEND_TUNING_BLOCK) {\r
+      PresentState = BIT0;\r
+    }\r
+  } else {\r
+    //\r
+    // Wait Command Inhibit (CMD) in the Present State register\r
+    // to be 0\r
+    //\r
+    PresentState = BIT0;\r
+  }\r
+\r
+  Status = SdPeimHcCheckMmioSet (\r
+             Bar + SD_HC_PRESENT_STATE,\r
+             sizeof (PresentState),\r
+             PresentState,\r
+             0\r
+             );\r
+\r
+  return Status;\r
+}\r
+\r
+/**\r
+  Wait for the env to be ready for execute specified TRB.\r
+\r
+  @param[in] Bar            The mmio base address of the slot to be accessed.\r
+  @param[in] Trb            The pointer to the SD_TRB instance.\r
+\r
+  @retval EFI_SUCCESS       The env is ready for TRB execution.\r
+  @retval EFI_TIMEOUT       The env is not ready for TRB execution in time.\r
+  @retval Others            Some erros happen.\r
+\r
+**/\r
+EFI_STATUS\r
+SdPeimWaitTrbEnv (\r
+  IN UINTN                  Bar,\r
+  IN SD_TRB                 *Trb\r
+  )\r
+{\r
+  EFI_STATUS                          Status;\r
+  SD_COMMAND_PACKET                   *Packet;\r
+  UINT64                              Timeout;\r
+  BOOLEAN                             InfiniteWait;\r
+\r
+  //\r
+  // Wait Command Complete Interrupt Status bit in Normal Interrupt Status Register\r
+  //\r
+  Packet  = Trb->Packet;\r
+  Timeout = Packet->Timeout;\r
+  if (Timeout == 0) {\r
+    InfiniteWait = TRUE;\r
+  } else {\r
+    InfiniteWait = FALSE;\r
+  }\r
+\r
+  while (InfiniteWait || (Timeout > 0)) {\r
+    //\r
+    // Check Trb execution result by reading Normal Interrupt Status register.\r
+    //\r
+    Status = SdPeimCheckTrbEnv (Bar, Trb);\r
+    if (Status != EFI_NOT_READY) {\r
+      return Status;\r
+    }\r
+    //\r
+    // Stall for 1 microsecond.\r
+    //\r
+    MicroSecondDelay (1);\r
+\r
+    Timeout--;\r
+  }\r
+\r
+  return EFI_TIMEOUT;\r
+}\r
+\r
+/**\r
+  Execute the specified TRB.\r
+\r
+  @param[in] Bar            The mmio base address of the slot to be accessed.\r
+  @param[in] Trb            The pointer to the SD_TRB instance.\r
+\r
+  @retval EFI_SUCCESS       The TRB is sent to host controller successfully.\r
+  @retval Others            Some erros happen when sending this request to the host controller.\r
+\r
+**/\r
+EFI_STATUS\r
+SdPeimExecTrb (\r
+  IN UINTN                  Bar,\r
+  IN SD_TRB                 *Trb\r
+  )\r
+{\r
+  EFI_STATUS                          Status;\r
+  SD_COMMAND_PACKET                   *Packet;\r
+  UINT16                              Cmd;\r
+  UINT16                              IntStatus;\r
+  UINT32                              Argument;\r
+  UINT16                              BlkCount;\r
+  UINT16                              BlkSize;\r
+  UINT16                              TransMode;\r
+  UINT8                               HostCtrl1;\r
+  UINT32                              SdmaAddr;\r
+  UINT64                              AdmaAddr;\r
+\r
+  Packet = Trb->Packet;\r
+  //\r
+  // Clear all bits in Error Interrupt Status Register\r
+  //\r
+  IntStatus = 0xFFFF;\r
+  Status    = SdPeimHcRwMmio (Bar + SD_HC_ERR_INT_STS, FALSE, sizeof (IntStatus), &IntStatus);\r
+  if (EFI_ERROR (Status)) {\r
+    return Status;\r
+  }\r
+  //\r
+  // Clear all bits in Normal Interrupt Status Register\r
+  //\r
+  IntStatus = 0xFFFF;\r
+  Status    = SdPeimHcRwMmio (Bar + SD_HC_NOR_INT_STS, FALSE, sizeof (IntStatus), &IntStatus);\r
+  if (EFI_ERROR (Status)) {\r
+    return Status;\r
+  }\r
+  //\r
+  // Set Host Control 1 register DMA Select field\r
+  //\r
+  if (Trb->Mode == SdAdmaMode) {\r
+    HostCtrl1 = BIT4;\r
+    Status = SdPeimHcOrMmio (Bar + SD_HC_HOST_CTRL1, sizeof (HostCtrl1), &HostCtrl1);\r
+    if (EFI_ERROR (Status)) {\r
+      return Status;\r
+    }\r
+  }\r
+\r
+  SdPeimHcLedOnOff (Bar, TRUE);\r
+\r
+  if (Trb->Mode == SdSdmaMode) {\r
+    if ((UINT64)(UINTN)Trb->Data >= 0x100000000ul) {\r
+      return EFI_INVALID_PARAMETER;\r
+    }\r
+\r
+    SdmaAddr = (UINT32)(UINTN)Trb->Data;\r
+    Status   = SdPeimHcRwMmio (Bar + SD_HC_SDMA_ADDR, FALSE, sizeof (SdmaAddr), &SdmaAddr);\r
+    if (EFI_ERROR (Status)) {\r
+      return Status;\r
+    }\r
+  } else if (Trb->Mode == SdAdmaMode) {\r
+    AdmaAddr = (UINT64)(UINTN)Trb->AdmaDesc;\r
+    Status   = SdPeimHcRwMmio (Bar + SD_HC_ADMA_SYS_ADDR, FALSE, sizeof (AdmaAddr), &AdmaAddr);\r
+    if (EFI_ERROR (Status)) {\r
+      return Status;\r
+    }\r
+  }\r
+\r
+  BlkSize = Trb->BlockSize;\r
+  if (Trb->Mode == SdSdmaMode) {\r
+    //\r
+    // Set SDMA boundary to be 512K bytes.\r
+    //\r
+    BlkSize |= 0x7000;\r
+  }\r
+\r
+  Status = SdPeimHcRwMmio (Bar + SD_HC_BLK_SIZE, FALSE, sizeof (BlkSize), &BlkSize);\r
+  if (EFI_ERROR (Status)) {\r
+    return Status;\r
+  }\r
+\r
+  BlkCount = (UINT16)(Trb->DataLen / Trb->BlockSize);\r
+  Status   = SdPeimHcRwMmio (Bar + SD_HC_BLK_COUNT, FALSE, sizeof (BlkCount), &BlkCount);\r
+  if (EFI_ERROR (Status)) {\r
+    return Status;\r
+  }\r
+\r
+  Argument = Packet->SdCmdBlk->CommandArgument;\r
+  Status   = SdPeimHcRwMmio (Bar + SD_HC_ARG1, FALSE, sizeof (Argument), &Argument);\r
+  if (EFI_ERROR (Status)) {\r
+    return Status;\r
+  }\r
+\r
+  TransMode = 0;\r
+  if (Trb->Mode != SdNoData) {\r
+    if (Trb->Mode != SdPioMode) {\r
+      TransMode |= BIT0;\r
+    }\r
+    if (Trb->Read) {\r
+      TransMode |= BIT4;\r
+    }\r
+    if (BlkCount != 0) {\r
+      TransMode |= BIT5 | BIT1;\r
+    }\r
+    if (BlkCount > 1) {\r
+      TransMode |= BIT2;\r
+    }\r
+  }\r
+\r
+  Status = SdPeimHcRwMmio (Bar + SD_HC_TRANS_MOD, FALSE, sizeof (TransMode), &TransMode);\r
+  if (EFI_ERROR (Status)) {\r
+    return Status;\r
+  }\r
+\r
+  Cmd = (UINT16)LShiftU64(Packet->SdCmdBlk->CommandIndex, 8);\r
+  if (Packet->SdCmdBlk->CommandType == SdCommandTypeAdtc) {\r
+    Cmd |= BIT5;\r
+  }\r
+  //\r
+  // Convert ResponseType to value\r
+  //\r
+  if (Packet->SdCmdBlk->CommandType != SdCommandTypeBc) {\r
+    switch (Packet->SdCmdBlk->ResponseType) {\r
+      case SdResponseTypeR1:\r
+      case SdResponseTypeR5:\r
+      case SdResponseTypeR6:\r
+      case SdResponseTypeR7:\r
+        Cmd |= (BIT1 | BIT3 | BIT4);\r
+        break;\r
+      case SdResponseTypeR2:\r
+        Cmd |= (BIT0 | BIT3);\r
+       break;\r
+      case SdResponseTypeR3:\r
+      case SdResponseTypeR4:\r
+        Cmd |= BIT1;\r
+        break;\r
+      case SdResponseTypeR1b:\r
+      case SdResponseTypeR5b:\r
+        Cmd |= (BIT0 | BIT1 | BIT3 | BIT4);\r
+        break;\r
+      default:\r
+        ASSERT (FALSE);\r
+        break;\r
+    }\r
+  }\r
+  //\r
+  // Execute cmd\r
+  //\r
+  Status = SdPeimHcRwMmio (Bar + SD_HC_COMMAND, FALSE, sizeof (Cmd), &Cmd);\r
+  return Status;\r
+}\r
+\r
+/**\r
+  Check the TRB execution result.\r
+\r
+  @param[in] Bar            The mmio base address of the slot to be accessed.\r
+  @param[in] Trb            The pointer to the SD_TRB instance.\r
+\r
+  @retval EFI_SUCCESS       The TRB is executed successfully.\r
+  @retval EFI_NOT_READY     The TRB is not completed for execution.\r
+  @retval Others            Some erros happen when executing this request.\r
+\r
+**/\r
+EFI_STATUS\r
+SdPeimCheckTrbResult (\r
+  IN UINTN                  Bar,\r
+  IN SD_TRB                 *Trb\r
+  )\r
+{\r
+  EFI_STATUS                          Status;\r
+  SD_COMMAND_PACKET                   *Packet;\r
+  UINT16                              IntStatus;\r
+  UINT32                              Response[4];\r
+  UINT32                              SdmaAddr;\r
+  UINT8                               Index;\r
+  UINT8                               SwReset;\r
+\r
+  SwReset = 0;\r
+  Packet  = Trb->Packet;\r
+  //\r
+  // Check Trb execution result by reading Normal Interrupt Status register.\r
+  //\r
+  Status = SdPeimHcRwMmio (\r
+             Bar + SD_HC_NOR_INT_STS,\r
+             TRUE,\r
+             sizeof (IntStatus),\r
+             &IntStatus\r
+             );\r
+  if (EFI_ERROR (Status)) {\r
+    goto Done;\r
+  }\r
+  //\r
+  // Check Transfer Complete bit is set or not.\r
+  //\r
+  if ((IntStatus & BIT1) == BIT1) {\r
+    if ((IntStatus & BIT15) == BIT15) {\r
+      //\r
+      // Read Error Interrupt Status register to check if the error is\r
+      // Data Timeout Error.\r
+      // If yes, treat it as success as Transfer Complete has higher\r
+      // priority than Data Timeout Error.\r
+      //\r
+      Status = SdPeimHcRwMmio (\r
+                 Bar + SD_HC_ERR_INT_STS,\r
+                 TRUE,\r
+                 sizeof (IntStatus),\r
+                 &IntStatus\r
+                 );\r
+      if (!EFI_ERROR (Status)) {\r
+        if ((IntStatus & BIT4) == BIT4) {\r
+          Status = EFI_SUCCESS;\r
+        } else {\r
+          Status = EFI_DEVICE_ERROR;\r
+        }\r
+      }\r
+    }\r
+\r
+    goto Done;\r
+  }\r
+  //\r
+  // Check if there is a error happened during cmd execution.\r
+  // If yes, then do error recovery procedure to follow SD Host Controller\r
+  // Simplified Spec 3.0 section 3.10.1.\r
+  //\r
+  if ((IntStatus & BIT15) == BIT15) {\r
+    Status = SdPeimHcRwMmio (\r
+               Bar + SD_HC_ERR_INT_STS,\r
+               TRUE,\r
+               sizeof (IntStatus),\r
+               &IntStatus\r
+               );\r
+    if (EFI_ERROR (Status)) {\r
+      goto Done;\r
+    }\r
+\r
+    if ((IntStatus & 0x0F) != 0) {\r
+      SwReset |= BIT1;\r
+    }\r
+    if ((IntStatus & 0xF0) != 0) {\r
+      SwReset |= BIT2;\r
+    }\r
+\r
+    Status = SdPeimHcRwMmio (\r
+               Bar + SD_HC_SW_RST,\r
+               FALSE,\r
+               sizeof (SwReset),\r
+               &SwReset\r
+               );\r
+    if (EFI_ERROR (Status)) {\r
+      goto Done;\r
+    }\r
+    Status = SdPeimHcWaitMmioSet (\r
+               Bar + SD_HC_SW_RST,\r
+               sizeof (SwReset),\r
+               0xFF,\r
+               0,\r
+               SD_TIMEOUT\r
+               );\r
+    if (EFI_ERROR (Status)) {\r
+      goto Done;\r
+    }\r
+\r
+    Status = EFI_DEVICE_ERROR;\r
+    goto Done;\r
+  }\r
+  //\r
+  // Check if DMA interrupt is signalled for the SDMA transfer.\r
+  //\r
+  if ((Trb->Mode == SdSdmaMode) && ((IntStatus & BIT3) == BIT3)) {\r
+    //\r
+    // Clear DMA interrupt bit.\r
+    //\r
+    IntStatus = BIT3;\r
+    Status    = SdPeimHcRwMmio (\r
+                  Bar + SD_HC_NOR_INT_STS,\r
+                  FALSE,\r
+                  sizeof (IntStatus),\r
+                  &IntStatus\r
+                  );\r
+    if (EFI_ERROR (Status)) {\r
+      goto Done;\r
+    }\r
+    //\r
+    // Update SDMA Address register.\r
+    //\r
+    SdmaAddr = SD_SDMA_ROUND_UP ((UINT32)(UINTN)Trb->Data, SD_SDMA_BOUNDARY);\r
+    Status   = SdPeimHcRwMmio (\r
+                 Bar + SD_HC_SDMA_ADDR,\r
+                 FALSE,\r
+                 sizeof (UINT32),\r
+                 &SdmaAddr\r
+                 );\r
+    if (EFI_ERROR (Status)) {\r
+      goto Done;\r
+    }\r
+    Trb->Data = (VOID*)(UINTN)SdmaAddr;\r
+  }\r
+\r
+  if ((Packet->SdCmdBlk->CommandType != SdCommandTypeAdtc) &&\r
+      (Packet->SdCmdBlk->ResponseType != SdResponseTypeR1b) &&\r
+      (Packet->SdCmdBlk->ResponseType != SdResponseTypeR5b)) {\r
+    if ((IntStatus & BIT0) == BIT0) {\r
+      Status = EFI_SUCCESS;\r
+      goto Done;\r
+    }\r
+  }\r
+\r
+  if (Packet->SdCmdBlk->CommandIndex == SD_SEND_TUNING_BLOCK) {\r
+    Status = EFI_SUCCESS;\r
+    goto Done;\r
+  }\r
+\r
+  Status = EFI_NOT_READY;\r
+Done:\r
+  //\r
+  // Get response data when the cmd is executed successfully.\r
+  //\r
+  if (!EFI_ERROR (Status)) {\r
+    if (Packet->SdCmdBlk->CommandType != SdCommandTypeBc) {\r
+      for (Index = 0; Index < 4; Index++) {\r
+        Status = SdPeimHcRwMmio (\r
+                   Bar + SD_HC_RESPONSE + Index * 4,\r
+                   TRUE,\r
+                   sizeof (UINT32),\r
+                   &Response[Index]\r
+                   );\r
+        if (EFI_ERROR (Status)) {\r
+          SdPeimHcLedOnOff (Bar, FALSE);\r
+          return Status;\r
+        }\r
+      }\r
+      CopyMem (Packet->SdStatusBlk, Response, sizeof (Response));\r
+    }\r
+  }\r
+\r
+  if (Status != EFI_NOT_READY) {\r
+    SdPeimHcLedOnOff (Bar, FALSE);\r
+  }\r
+\r
+  return Status;\r
+}\r
+\r
+/**\r
+  Wait for the TRB execution result.\r
+\r
+  @param[in] Bar            The mmio base address of the slot to be accessed.\r
+  @param[in] Trb            The pointer to the SD_TRB instance.\r
+\r
+  @retval EFI_SUCCESS       The TRB is executed successfully.\r
+  @retval Others            Some erros happen when executing this request.\r
+\r
+**/\r
+EFI_STATUS\r
+SdPeimWaitTrbResult (\r
+  IN UINTN                  Bar,\r
+  IN SD_TRB                 *Trb\r
+  )\r
+{\r
+  EFI_STATUS                        Status;\r
+  SD_COMMAND_PACKET                 *Packet;\r
+  UINT64                            Timeout;\r
+  BOOLEAN                           InfiniteWait;\r
+\r
+  Packet = Trb->Packet;\r
+  //\r
+  // Wait Command Complete Interrupt Status bit in Normal Interrupt Status Register\r
+  //\r
+  Timeout = Packet->Timeout;\r
+  if (Timeout == 0) {\r
+    InfiniteWait = TRUE;\r
+  } else {\r
+    InfiniteWait = FALSE;\r
+  }\r
+\r
+  while (InfiniteWait || (Timeout > 0)) {\r
+    //\r
+    // Check Trb execution result by reading Normal Interrupt Status register.\r
+    //\r
+    Status = SdPeimCheckTrbResult (Bar, Trb);\r
+    if (Status != EFI_NOT_READY) {\r
+      return Status;\r
+    }\r
+    //\r
+    // Stall for 1 microsecond.\r
+    //\r
+    MicroSecondDelay (1);\r
+\r
+    Timeout--;\r
+  }\r
+\r
+  return EFI_TIMEOUT;\r
+}\r
+\r
+/**\r
+  Sends SD command to an SD card that is attached to the SD controller.\r
+\r
+  If Packet is successfully sent to the SD card, then EFI_SUCCESS is returned.\r
+\r
+  If a device error occurs while sending the Packet, then EFI_DEVICE_ERROR is returned.\r
+\r
+  If Slot is not in a valid range for the SD controller, then EFI_INVALID_PARAMETER\r
+  is returned.\r
+\r
+  If Packet defines a data command but both InDataBuffer and OutDataBuffer are NULL,\r
+  EFI_INVALID_PARAMETER is returned.\r
+\r
+  @param[in]     Slot           The slot number of the Sd card to send the command to.\r
+  @param[in,out] Packet         A pointer to the SD command data structure.\r
+\r
+  @retval EFI_SUCCESS           The SD Command Packet was sent by the host.\r
+  @retval EFI_DEVICE_ERROR      A device error occurred while attempting to send the SD\r
+                                command Packet.\r
+  @retval EFI_INVALID_PARAMETER Packet, Slot, or the contents of the Packet is invalid.\r
+  @retval EFI_INVALID_PARAMETER Packet defines a data command but both InDataBuffer and\r
+                                OutDataBuffer are NULL.\r
+  @retval EFI_NO_MEDIA          SD Device not present in the Slot.\r
+  @retval EFI_UNSUPPORTED       The command described by the SD Command Packet is not\r
+                                supported by the host controller.\r
+  @retval EFI_BAD_BUFFER_SIZE   The InTransferLength or OutTransferLength exceeds the\r
+                                limit supported by SD card ( i.e. if the number of bytes\r
+                                exceed the Last LBA).\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+SdPeimExecCmd (\r
+  IN     SD_PEIM_HC_SLOT       *Slot,\r
+  IN OUT SD_COMMAND_PACKET     *Packet\r
+  )\r
+{\r
+  EFI_STATUS                   Status;\r
+  SD_TRB                       *Trb;\r
+\r
+  if (Packet == NULL) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  if ((Packet->SdCmdBlk == NULL) || (Packet->SdStatusBlk == NULL)) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  if ((Packet->OutDataBuffer == NULL) && (Packet->OutTransferLength != 0)) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  if ((Packet->InDataBuffer == NULL) && (Packet->InTransferLength != 0)) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  Trb = SdPeimCreateTrb (Slot, Packet);\r
+  if (Trb == NULL) {\r
+    return EFI_OUT_OF_RESOURCES;\r
+  }\r
+\r
+  Status = SdPeimWaitTrbEnv (Slot->SdHcBase, Trb);\r
+  if (EFI_ERROR (Status)) {\r
+    goto Done;\r
+  }\r
+\r
+  Status = SdPeimExecTrb (Slot->SdHcBase, Trb);\r
+  if (EFI_ERROR (Status)) {\r
+    goto Done;\r
+  }\r
+\r
+  Status = SdPeimWaitTrbResult (Slot->SdHcBase, Trb);\r
+  if (EFI_ERROR (Status)) {\r
+    goto Done;\r
+  }\r
+\r
+Done:\r
+  SdPeimFreeTrb (Trb);\r
+\r
+  return Status;\r
+}\r
+\r
+/**\r
+  Send command GO_IDLE_STATE to the device to make it go to Idle State.\r
+\r
+  Refer to SD Physical Layer Simplified Spec 4.1 Section 4.7 for details.\r
+\r
+  @param[in] Slot           The slot number of the SD card to send the command to.\r
+\r
+  @retval EFI_SUCCESS       The SD device is reset correctly.\r
+  @retval Others            The device reset fails.\r
+\r
+**/\r
+EFI_STATUS\r
+SdPeimReset (\r
+  IN SD_PEIM_HC_SLOT        *Slot\r
+  )\r
+{\r
+  SD_COMMAND_BLOCK                    SdCmdBlk;\r
+  SD_STATUS_BLOCK                     SdStatusBlk;\r
+  SD_COMMAND_PACKET                   Packet;\r
+  EFI_STATUS                          Status;\r
+\r
+  ZeroMem (&SdCmdBlk, sizeof (SdCmdBlk));\r
+  ZeroMem (&SdStatusBlk, sizeof (SdStatusBlk));\r
+  ZeroMem (&Packet, sizeof (Packet));\r
+\r
+  Packet.SdCmdBlk    = &SdCmdBlk;\r
+  Packet.SdStatusBlk = &SdStatusBlk;\r
+  Packet.Timeout     = SD_TIMEOUT;\r
+\r
+  SdCmdBlk.CommandIndex = SD_GO_IDLE_STATE;\r
+  SdCmdBlk.CommandType  = SdCommandTypeBc;\r
+  SdCmdBlk.ResponseType = 0;\r
+  SdCmdBlk.CommandArgument = 0;\r
+\r
+  Status = SdPeimExecCmd (Slot, &Packet);\r
+\r
+  return Status;\r
+}\r
+\r
+/**\r
+  Send command SEND_IF_COND to the device to inquiry the SD Memory Card interface\r
+  condition.\r
+\r
+  Refer to SD Physical Layer Simplified Spec 4.1 Section 4.7 for details.\r
+\r
+  @param[in] Slot           The slot number of the SD card to send the command to.\r
+  @param[in] SupplyVoltage  The supplied voltage by the host.\r
+  @param[in] CheckPattern   The check pattern to be sent to the device.\r
+\r
+  @retval EFI_SUCCESS       The operation is done correctly.\r
+  @retval Others            The operation fails.\r
+\r
+**/\r
+EFI_STATUS\r
+SdPeimVoltageCheck (\r
+  IN SD_PEIM_HC_SLOT        *Slot,\r
+  IN UINT8                  SupplyVoltage,\r
+  IN UINT8                  CheckPattern\r
+  )\r
+{\r
+  SD_COMMAND_BLOCK                    SdCmdBlk;\r
+  SD_STATUS_BLOCK                     SdStatusBlk;\r
+  SD_COMMAND_PACKET                   Packet;\r
+  EFI_STATUS                          Status;\r
+\r
+  ZeroMem (&SdCmdBlk, sizeof (SdCmdBlk));\r
+  ZeroMem (&SdStatusBlk, sizeof (SdStatusBlk));\r
+  ZeroMem (&Packet, sizeof (Packet));\r
+\r
+  Packet.SdCmdBlk    = &SdCmdBlk;\r
+  Packet.SdStatusBlk = &SdStatusBlk;\r
+  Packet.Timeout     = SD_TIMEOUT;\r
+\r
+  SdCmdBlk.CommandIndex = SD_SEND_IF_COND;\r
+  SdCmdBlk.CommandType  = SdCommandTypeBcr;\r
+  SdCmdBlk.ResponseType = SdResponseTypeR7;\r
+  SdCmdBlk.CommandArgument = (SupplyVoltage << 8) | CheckPattern;\r
+\r
+  Status = SdPeimExecCmd (Slot, &Packet);\r
+  if (!EFI_ERROR (Status)) {\r
+    if (SdStatusBlk.Resp0 != SdCmdBlk.CommandArgument) {\r
+      return EFI_DEVICE_ERROR;\r
+    }\r
+  }\r
+\r
+  return Status;\r
+}\r
+\r
+/**\r
+  Send command SDIO_SEND_OP_COND to the device to see whether it is SDIO device.\r
+\r
+  Refer to SDIO Simplified Spec 3 Section 3.2 for details.\r
+\r
+  @param[in] Slot           The slot number of the SD card to send the command to.\r
+  @param[in] VoltageWindow  The supply voltage window.\r
+  @param[in] S18r           The boolean to show if it should switch to 1.8v.\r
+\r
+  @retval EFI_SUCCESS       The operation is done correctly.\r
+  @retval Others            The operation fails.\r
+\r
+**/\r
+EFI_STATUS\r
+SdioSendOpCond (\r
+  IN SD_PEIM_HC_SLOT        *Slot,\r
+  IN UINT32                 VoltageWindow,\r
+  IN BOOLEAN                S18r\r
+  )\r
+{\r
+  SD_COMMAND_BLOCK                    SdCmdBlk;\r
+  SD_STATUS_BLOCK                     SdStatusBlk;\r
+  SD_COMMAND_PACKET                   Packet;\r
+  EFI_STATUS                          Status;\r
+  UINT32                              Switch;\r
+\r
+  ZeroMem (&SdCmdBlk, sizeof (SdCmdBlk));\r
+  ZeroMem (&SdStatusBlk, sizeof (SdStatusBlk));\r
+  ZeroMem (&Packet, sizeof (Packet));\r
+\r
+  Packet.SdCmdBlk    = &SdCmdBlk;\r
+  Packet.SdStatusBlk = &SdStatusBlk;\r
+  Packet.Timeout     = SD_TIMEOUT;\r
+\r
+  SdCmdBlk.CommandIndex = SDIO_SEND_OP_COND;\r
+  SdCmdBlk.CommandType  = SdCommandTypeBcr;\r
+  SdCmdBlk.ResponseType = SdResponseTypeR4;\r
+\r
+  Switch = S18r ? BIT24 : 0;\r
+\r
+  SdCmdBlk.CommandArgument = (VoltageWindow & 0xFFFFFF) | Switch;\r
+\r
+  Status = SdPeimExecCmd (Slot, &Packet);\r
+\r
+  return Status;\r
+}\r
+\r
+/**\r
+  Send command SD_SEND_OP_COND to the device to see whether it is SDIO device.\r
+\r
+  Refer to SD Physical Layer Simplified Spec 4.1 Section 4.7 for details.\r
+\r
+  @param[in]  Slot           The slot number of the SD card to send the command to.\r
+  @param[in]  Rca            The relative device address of addressed device.\r
+  @param[in]  VoltageWindow  The supply voltage window.\r
+  @param[in]  S18r           The boolean to show if it should switch to 1.8v.\r
+  @param[in]  Xpc            The boolean to show if it should provide 0.36w power control.\r
+  @param[in]  Hcs            The boolean to show if it support host capacity info.\r
+  @param[out] Ocr            The buffer to store returned OCR register value.\r
+\r
+\r
+  @retval EFI_SUCCESS       The operation is done correctly.\r
+  @retval Others            The operation fails.\r
+\r
+**/\r
+EFI_STATUS\r
+SdPeimSendOpCond (\r
+  IN     SD_PEIM_HC_SLOT              *Slot,\r
+  IN     UINT16                       Rca,\r
+  IN     UINT32                       VoltageWindow,\r
+  IN     BOOLEAN                      S18r,\r
+  IN     BOOLEAN                      Xpc,\r
+  IN     BOOLEAN                      Hcs,\r
+     OUT UINT32                       *Ocr\r
+  )\r
+{\r
+  SD_COMMAND_BLOCK                    SdCmdBlk;\r
+  SD_STATUS_BLOCK                     SdStatusBlk;\r
+  SD_COMMAND_PACKET                   Packet;\r
+  EFI_STATUS                          Status;\r
+  UINT32                              Switch;\r
+  UINT32                              MaxPower;\r
+  UINT32                              HostCapacity;\r
+\r
+  ZeroMem (&SdCmdBlk, sizeof (SdCmdBlk));\r
+  ZeroMem (&SdStatusBlk, sizeof (SdStatusBlk));\r
+  ZeroMem (&Packet, sizeof (Packet));\r
+\r
+  Packet.SdCmdBlk    = &SdCmdBlk;\r
+  Packet.SdStatusBlk = &SdStatusBlk;\r
+  Packet.Timeout     = SD_TIMEOUT;\r
+\r
+  SdCmdBlk.CommandIndex = SD_APP_CMD;\r
+  SdCmdBlk.CommandType  = SdCommandTypeAc;\r
+  SdCmdBlk.ResponseType = SdResponseTypeR1;\r
+  SdCmdBlk.CommandArgument = (UINT32)Rca << 16;\r
+\r
+  Status = SdPeimExecCmd (Slot, &Packet);\r
+  if (EFI_ERROR (Status)) {\r
+    return Status;\r
+  }\r
+\r
+  SdCmdBlk.CommandIndex = SD_SEND_OP_COND;\r
+  SdCmdBlk.CommandType  = SdCommandTypeBcr;\r
+  SdCmdBlk.ResponseType = SdResponseTypeR3;\r
+\r
+  Switch       = S18r ? BIT24 : 0;\r
+  MaxPower     = Xpc ? BIT28 : 0;\r
+  HostCapacity = Hcs ? BIT30 : 0;\r
+  SdCmdBlk.CommandArgument = (VoltageWindow & 0xFFFFFF) | Switch | MaxPower | HostCapacity;\r
+\r
+  Status = SdPeimExecCmd (Slot, &Packet);\r
+  if (!EFI_ERROR (Status)) {\r
+    //\r
+    // For details, refer to SD Host Controller Simplified Spec 3.0 Table 2-12.\r
+    //\r
+    *Ocr = SdStatusBlk.Resp0;\r
+  }\r
+\r
+  return Status;\r
+}\r
+\r
+/**\r
+  Broadcast command ALL_SEND_CID to the bus to ask all the SD devices to send the\r
+  data of their CID registers.\r
+\r
+  Refer to SD Physical Layer Simplified Spec 4.1 Section 4.7 for details.\r
+\r
+  @param[in] Slot           The slot number of the SD card to send the command to.\r
+\r
+  @retval EFI_SUCCESS       The operation is done correctly.\r
+  @retval Others            The operation fails.\r
+\r
+**/\r
+EFI_STATUS\r
+SdPeimAllSendCid (\r
+  IN SD_PEIM_HC_SLOT        *Slot\r
+  )\r
+{\r
+  SD_COMMAND_BLOCK                    SdCmdBlk;\r
+  SD_STATUS_BLOCK                     SdStatusBlk;\r
+  SD_COMMAND_PACKET                   Packet;\r
+  EFI_STATUS                          Status;\r
+\r
+  ZeroMem (&SdCmdBlk, sizeof (SdCmdBlk));\r
+  ZeroMem (&SdStatusBlk, sizeof (SdStatusBlk));\r
+  ZeroMem (&Packet, sizeof (Packet));\r
+\r
+  Packet.SdCmdBlk    = &SdCmdBlk;\r
+  Packet.SdStatusBlk = &SdStatusBlk;\r
+  Packet.Timeout        = SD_TIMEOUT;\r
+\r
+  SdCmdBlk.CommandIndex = SD_ALL_SEND_CID;\r
+  SdCmdBlk.CommandType  = SdCommandTypeBcr;\r
+  SdCmdBlk.ResponseType = SdResponseTypeR2;\r
+  SdCmdBlk.CommandArgument = 0;\r
+\r
+  Status = SdPeimExecCmd (Slot, &Packet);\r
+\r
+  return Status;\r
+}\r
+\r
+/**\r
+  Send command SET_RELATIVE_ADDR to the SD device to assign a Relative device\r
+  Address (RCA).\r
+\r
+  Refer to SD Physical Layer Simplified Spec 4.1 Section 4.7 for details.\r
+\r
+  @param[in]  Slot          The slot number of the SD card to send the command to.\r
+  @param[out] Rca           The relative device address to be assigned.\r
+\r
+  @retval EFI_SUCCESS       The operation is done correctly.\r
+  @retval Others            The operation fails.\r
+\r
+**/\r
+EFI_STATUS\r
+SdPeimSetRca (\r
+  IN     SD_PEIM_HC_SLOT              *Slot,\r
+     OUT UINT16                       *Rca\r
+  )\r
+{\r
+  SD_COMMAND_BLOCK                    SdCmdBlk;\r
+  SD_STATUS_BLOCK                     SdStatusBlk;\r
+  SD_COMMAND_PACKET                   Packet;\r
+  EFI_STATUS                          Status;\r
+\r
+  ZeroMem (&SdCmdBlk, sizeof (SdCmdBlk));\r
+  ZeroMem (&SdStatusBlk, sizeof (SdStatusBlk));\r
+  ZeroMem (&Packet, sizeof (Packet));\r
+\r
+  Packet.SdCmdBlk    = &SdCmdBlk;\r
+  Packet.SdStatusBlk = &SdStatusBlk;\r
+  Packet.Timeout        = SD_TIMEOUT;\r
+\r
+  SdCmdBlk.CommandIndex = SD_SET_RELATIVE_ADDR;\r
+  SdCmdBlk.CommandType  = SdCommandTypeBcr;\r
+  SdCmdBlk.ResponseType = SdResponseTypeR6;\r
+\r
+  Status = SdPeimExecCmd (Slot, &Packet);\r
+  if (!EFI_ERROR (Status)) {\r
+    *Rca = (UINT16)(SdStatusBlk.Resp0 >> 16);\r
+  }\r
+\r
+  return Status;\r
+}\r
+\r
+/**\r
+  Send command SEND_CSD to the SD device to get the data of the CSD register.\r
+\r
+  Refer to SD Physical Layer Simplified Spec 4.1 Section 4.7 for details.\r
+\r
+  @param[in]  Slot          The slot number of the SD card to send the command to.\r
+  @param[in]  Rca           The relative device address of selected device.\r
+  @param[out] Csd           The buffer to store the content of the CSD register.\r
+                            Note the caller should ignore the lowest byte of this\r
+                            buffer as the content of this byte is meaningless even\r
+                            if the operation succeeds.\r
+\r
+  @retval EFI_SUCCESS       The operation is done correctly.\r
+  @retval Others            The operation fails.\r
+\r
+**/\r
+EFI_STATUS\r
+SdPeimGetCsd (\r
+  IN     SD_PEIM_HC_SLOT              *Slot,\r
+  IN     UINT16                       Rca,\r
+     OUT SD_CSD                       *Csd\r
+  )\r
+{\r
+  SD_COMMAND_BLOCK                    SdCmdBlk;\r
+  SD_STATUS_BLOCK                     SdStatusBlk;\r
+  SD_COMMAND_PACKET                   Packet;\r
+  EFI_STATUS                          Status;\r
+\r
+  ZeroMem (&SdCmdBlk, sizeof (SdCmdBlk));\r
+  ZeroMem (&SdStatusBlk, sizeof (SdStatusBlk));\r
+  ZeroMem (&Packet, sizeof (Packet));\r
+\r
+  Packet.SdCmdBlk    = &SdCmdBlk;\r
+  Packet.SdStatusBlk = &SdStatusBlk;\r
+  Packet.Timeout        = SD_TIMEOUT;\r
+\r
+  SdCmdBlk.CommandIndex = SD_SEND_CSD;\r
+  SdCmdBlk.CommandType  = SdCommandTypeAc;\r
+  SdCmdBlk.ResponseType = SdResponseTypeR2;\r
+  SdCmdBlk.CommandArgument = (UINT32)Rca << 16;\r
+\r
+  Status = SdPeimExecCmd (Slot, &Packet);\r
+  if (!EFI_ERROR (Status)) {\r
+    //\r
+    // For details, refer to SD Host Controller Simplified Spec 3.0 Table 2-12.\r
+    //\r
+    CopyMem (((UINT8*)Csd) + 1, &SdStatusBlk.Resp0, sizeof (SD_CSD) - 1);\r
+  }\r
+\r
+  return Status;\r
+}\r
+\r
+/**\r
+  Send command SELECT_DESELECT_CARD to the SD device to select/deselect it.\r
+\r
+  Refer to SD Physical Layer Simplified Spec 4.1 Section 4.7 for details.\r
+\r
+  @param[in]  Slot          The slot number of the SD card to send the command to.\r
+  @param[in]  Rca           The relative device address of selected device.\r
+\r
+  @retval EFI_SUCCESS       The operation is done correctly.\r
+  @retval Others            The operation fails.\r
+\r
+**/\r
+EFI_STATUS\r
+SdPeimSelect (\r
+  IN SD_PEIM_HC_SLOT        *Slot,\r
+  IN UINT16                 Rca\r
+  )\r
+{\r
+  SD_COMMAND_BLOCK                    SdCmdBlk;\r
+  SD_STATUS_BLOCK                     SdStatusBlk;\r
+  SD_COMMAND_PACKET                   Packet;\r
+  EFI_STATUS                          Status;\r
+\r
+  ZeroMem (&SdCmdBlk, sizeof (SdCmdBlk));\r
+  ZeroMem (&SdStatusBlk, sizeof (SdStatusBlk));\r
+  ZeroMem (&Packet, sizeof (Packet));\r
+\r
+  Packet.SdCmdBlk    = &SdCmdBlk;\r
+  Packet.SdStatusBlk = &SdStatusBlk;\r
+  Packet.Timeout        = SD_TIMEOUT;\r
+\r
+  SdCmdBlk.CommandIndex = SD_SELECT_DESELECT_CARD;\r
+  SdCmdBlk.CommandType  = SdCommandTypeAc;\r
+  SdCmdBlk.ResponseType = SdResponseTypeR1b;\r
+  SdCmdBlk.CommandArgument = (UINT32)Rca << 16;\r
+\r
+  Status = SdPeimExecCmd (Slot, &Packet);\r
+\r
+  return Status;\r
+}\r
+\r
+/**\r
+  Send command VOLTAGE_SWITCH to the SD device to switch the voltage of the device.\r
+\r
+  Refer to SD Physical Layer Simplified Spec 4.1 Section 4.7 for details.\r
+\r
+  @param[in]  Slot          The slot number of the SD card to send the command to.\r
+\r
+  @retval EFI_SUCCESS       The operation is done correctly.\r
+  @retval Others            The operation fails.\r
+\r
+**/\r
+EFI_STATUS\r
+SdPeimVoltageSwitch (\r
+  IN SD_PEIM_HC_SLOT        *Slot\r
+  )\r
+{\r
+  SD_COMMAND_BLOCK                    SdCmdBlk;\r
+  SD_STATUS_BLOCK                     SdStatusBlk;\r
+  SD_COMMAND_PACKET                   Packet;\r
+  EFI_STATUS                          Status;\r
+\r
+  ZeroMem (&SdCmdBlk, sizeof (SdCmdBlk));\r
+  ZeroMem (&SdStatusBlk, sizeof (SdStatusBlk));\r
+  ZeroMem (&Packet, sizeof (Packet));\r
+\r
+  Packet.SdCmdBlk    = &SdCmdBlk;\r
+  Packet.SdStatusBlk = &SdStatusBlk;\r
+  Packet.Timeout        = SD_TIMEOUT;\r
+\r
+  SdCmdBlk.CommandIndex = SD_VOLTAGE_SWITCH;\r
+  SdCmdBlk.CommandType  = SdCommandTypeAc;\r
+  SdCmdBlk.ResponseType = SdResponseTypeR1;\r
+  SdCmdBlk.CommandArgument = 0;\r
+\r
+  Status = SdPeimExecCmd (Slot, &Packet);\r
+\r
+  return Status;\r
+}\r
+\r
+/**\r
+  Send command SET_BUS_WIDTH to the SD device to set the bus width.\r
+\r
+  Refer to SD Physical Layer Simplified Spec 4.1 Section 4.7 for details.\r
+\r
+  @param[in] Slot           The slot number of the SD card to send the command to.\r
+  @param[in] Rca            The relative device address of addressed device.\r
+  @param[in] BusWidth       The bus width to be set, it could be 1 or 4.\r
+\r
+  @retval EFI_SUCCESS       The operation is done correctly.\r
+  @retval Others            The operation fails.\r
+\r
+**/\r
+EFI_STATUS\r
+SdPeimSetBusWidth (\r
+  IN SD_PEIM_HC_SLOT        *Slot,\r
+  IN UINT16                 Rca,\r
+  IN UINT8                  BusWidth\r
+  )\r
+{\r
+  SD_COMMAND_BLOCK                    SdCmdBlk;\r
+  SD_STATUS_BLOCK                     SdStatusBlk;\r
+  SD_COMMAND_PACKET                   Packet;\r
+  EFI_STATUS                          Status;\r
+  UINT8                               Value;\r
+\r
+  ZeroMem (&SdCmdBlk, sizeof (SdCmdBlk));\r
+  ZeroMem (&SdStatusBlk, sizeof (SdStatusBlk));\r
+  ZeroMem (&Packet, sizeof (Packet));\r
+\r
+  Packet.SdCmdBlk    = &SdCmdBlk;\r
+  Packet.SdStatusBlk = &SdStatusBlk;\r
+  Packet.Timeout     = SD_TIMEOUT;\r
+\r
+  SdCmdBlk.CommandIndex = SD_APP_CMD;\r
+  SdCmdBlk.CommandType  = SdCommandTypeAc;\r
+  SdCmdBlk.ResponseType = SdResponseTypeR1;\r
+  SdCmdBlk.CommandArgument = (UINT32)Rca << 16;\r
+\r
+  Status = SdPeimExecCmd (Slot, &Packet);\r
+  if (EFI_ERROR (Status)) {\r
+    return Status;\r
+  }\r
+\r
+  SdCmdBlk.CommandIndex = SD_SET_BUS_WIDTH;\r
+  SdCmdBlk.CommandType  = SdCommandTypeAc;\r
+  SdCmdBlk.ResponseType = SdResponseTypeR1;\r
+\r
+  if (BusWidth == 1) {\r
+    Value = 0;\r
+  } else if (BusWidth == 4) {\r
+    Value = 2;\r
+  } else {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+  SdCmdBlk.CommandArgument = Value & 0x3;\r
+\r
+  Status = SdPeimExecCmd (Slot, &Packet);\r
+\r
+  return Status;\r
+}\r
+\r
+/**\r
+  Send command SWITCH_FUNC to the SD device to check switchable function or switch card function.\r
+\r
+  Refer to SD Physical Layer Simplified Spec 4.1 Section 4.7 for details.\r
+\r
+  @param[in]  Slot          The slot number of the SD card to send the command to.\r
+  @param[in]  AccessMode    The value for access mode group.\r
+  @param[in]  CommandSystem The value for command set group.\r
+  @param[in]  DriveStrength The value for drive length group.\r
+  @param[in]  PowerLimit    The value for power limit group.\r
+  @param[in]  Mode          Switch or check function.\r
+\r
+  @retval EFI_SUCCESS       The operation is done correctly.\r
+  @retval Others            The operation fails.\r
+\r
+**/\r
+EFI_STATUS\r
+SdPeimSwitch (\r
+  IN SD_PEIM_HC_SLOT        *Slot,\r
+  IN UINT8                  AccessMode,\r
+  IN UINT8                  CommandSystem,\r
+  IN UINT8                  DriveStrength,\r
+  IN UINT8                  PowerLimit,\r
+  IN BOOLEAN                Mode\r
+  )\r
+{\r
+  SD_COMMAND_BLOCK                    SdCmdBlk;\r
+  SD_STATUS_BLOCK                     SdStatusBlk;\r
+  SD_COMMAND_PACKET                   Packet;\r
+  EFI_STATUS                          Status;\r
+  UINT32                              ModeValue;\r
+  UINT8                               Data[64];\r
+\r
+  ZeroMem (&SdCmdBlk, sizeof (SdCmdBlk));\r
+  ZeroMem (&SdStatusBlk, sizeof (SdStatusBlk));\r
+  ZeroMem (&Packet, sizeof (Packet));\r
+\r
+  Packet.SdCmdBlk    = &SdCmdBlk;\r
+  Packet.SdStatusBlk = &SdStatusBlk;\r
+  Packet.Timeout        = SD_TIMEOUT;\r
+\r
+  SdCmdBlk.CommandIndex = SD_SWITCH_FUNC;\r
+  SdCmdBlk.CommandType  = SdCommandTypeAdtc;\r
+  SdCmdBlk.ResponseType = SdResponseTypeR1;\r
+\r
+  ModeValue = Mode ? BIT31 : 0;\r
+  SdCmdBlk.CommandArgument = (AccessMode & 0xF) | ((PowerLimit & 0xF) << 4) | \\r
+                             ((DriveStrength & 0xF) << 8) | ((DriveStrength & 0xF) << 12) | \\r
+                             ModeValue;\r
+  Packet.InDataBuffer     = Data;\r
+  Packet.InTransferLength = sizeof (Data);\r
+\r
+  Status = SdPeimExecCmd (Slot, &Packet);\r
+\r
+  return Status;\r
+}\r
+\r
+/**\r
+  Send command SEND_STATUS to the addressed SD device to get its status register.\r
+\r
+  Refer to SD Physical Layer Simplified Spec 4.1 Section 4.7 for details.\r
+\r
+  @param[in]  Slot          The slot number of the SD card to send the command to.\r
+  @param[in]  Rca           The relative device address of addressed device.\r
+  @param[out] DevStatus     The returned device status.\r
+\r
+  @retval EFI_SUCCESS       The operation is done correctly.\r
+  @retval Others            The operation fails.\r
+\r
+**/\r
+EFI_STATUS\r
+SdPeimSendStatus (\r
+  IN     SD_PEIM_HC_SLOT              *Slot,\r
+  IN     UINT16                       Rca,\r
+     OUT UINT32                       *DevStatus\r
+  )\r
+{\r
+  SD_COMMAND_BLOCK                    SdCmdBlk;\r
+  SD_STATUS_BLOCK                     SdStatusBlk;\r
+  SD_COMMAND_PACKET                   Packet;\r
+  EFI_STATUS                          Status;\r
+\r
+  ZeroMem (&SdCmdBlk, sizeof (SdCmdBlk));\r
+  ZeroMem (&SdStatusBlk, sizeof (SdStatusBlk));\r
+  ZeroMem (&Packet, sizeof (Packet));\r
+\r
+  Packet.SdCmdBlk    = &SdCmdBlk;\r
+  Packet.SdStatusBlk = &SdStatusBlk;\r
+  Packet.Timeout     = SD_TIMEOUT;\r
+\r
+  SdCmdBlk.CommandIndex = SD_SEND_STATUS;\r
+  SdCmdBlk.CommandType  = SdCommandTypeAc;\r
+  SdCmdBlk.ResponseType = SdResponseTypeR1;\r
+  SdCmdBlk.CommandArgument = (UINT32)Rca << 16;\r
+\r
+  Status = SdPeimExecCmd (Slot, &Packet);\r
+  if (!EFI_ERROR (Status)) {\r
+    *DevStatus = SdStatusBlk.Resp0;\r
+  }\r
+\r
+  return Status;\r
+}\r
+\r
+/**\r
+  Send command READ_SINGLE_BLOCK/WRITE_SINGLE_BLOCK to the addressed SD device\r
+  to read/write the specified number of blocks.\r
+\r
+  Refer to SD Physical Layer Simplified Spec 4.1 Section 4.7 for details.\r
+\r
+  @param[in] Slot           The slot number of the SD card to send the command to.\r
+  @param[in] Lba            The logical block address of starting access.\r
+  @param[in] BlockSize      The block size of specified SD device partition.\r
+  @param[in] Buffer         The pointer to the transfer buffer.\r
+  @param[in] BufferSize     The size of transfer buffer.\r
+  @param[in] IsRead         Boolean to show the operation direction.\r
+\r
+  @retval EFI_SUCCESS       The operation is done correctly.\r
+  @retval Others            The operation fails.\r
+\r
+**/\r
+EFI_STATUS\r
+SdPeimRwSingleBlock (\r
+  IN SD_PEIM_HC_SLOT                *Slot,\r
+  IN EFI_LBA                        Lba,\r
+  IN UINT32                         BlockSize,\r
+  IN VOID                           *Buffer,\r
+  IN UINTN                          BufferSize,\r
+  IN BOOLEAN                        IsRead\r
+  )\r
+{\r
+  SD_COMMAND_BLOCK                    SdCmdBlk;\r
+  SD_STATUS_BLOCK                     SdStatusBlk;\r
+  SD_COMMAND_PACKET                   Packet;\r
+  EFI_STATUS                          Status;\r
+\r
+  ZeroMem (&SdCmdBlk, sizeof (SdCmdBlk));\r
+  ZeroMem (&SdStatusBlk, sizeof (SdStatusBlk));\r
+  ZeroMem (&Packet, sizeof (Packet));\r
+\r
+  Packet.SdCmdBlk    = &SdCmdBlk;\r
+  Packet.SdStatusBlk = &SdStatusBlk;\r
+  //\r
+  // Calculate timeout value through the below formula.\r
+  // Timeout = (transfer size) / (2MB/s).\r
+  // Taking 2MB/s as divisor is because it's the lowest\r
+  // transfer speed of class 2.\r
+  //\r
+  Packet.Timeout       = (BufferSize / (2 * 1024 * 1024) + 1) * 1000 * 1000;;\r
+\r
+  if (IsRead) {\r
+    Packet.InDataBuffer     = Buffer;\r
+    Packet.InTransferLength = (UINT32)BufferSize;\r
+\r
+    SdCmdBlk.CommandIndex = SD_READ_SINGLE_BLOCK;\r
+    SdCmdBlk.CommandType  = SdCommandTypeAdtc;\r
+    SdCmdBlk.ResponseType = SdResponseTypeR1;\r
+  } else {\r
+    Packet.OutDataBuffer     = Buffer;\r
+    Packet.OutTransferLength = (UINT32)BufferSize;\r
+\r
+    SdCmdBlk.CommandIndex = SD_WRITE_SINGLE_BLOCK;\r
+    SdCmdBlk.CommandType  = SdCommandTypeAdtc;\r
+    SdCmdBlk.ResponseType = SdResponseTypeR1;\r
+  }\r
+\r
+  if (Slot->SectorAddressing) {\r
+    SdCmdBlk.CommandArgument = (UINT32)Lba;\r
+  } else {\r
+    SdCmdBlk.CommandArgument = (UINT32)MultU64x32 (Lba, BlockSize);\r
+  }\r
+\r
+  Status = SdPeimExecCmd (Slot, &Packet);\r
+\r
+  return Status;\r
+}\r
+\r
+/**\r
+  Send command READ_MULTIPLE_BLOCK/WRITE_MULTIPLE_BLOCK to the addressed SD device\r
+  to read/write the specified number of blocks.\r
+\r
+  Refer to SD Physical Layer Simplified Spec 4.1 Section 4.7 for details.\r
+\r
+  @param[in] Slot           The slot number of the SD card to send the command to.\r
+  @param[in] Lba            The logical block address of starting access.\r
+  @param[in] BlockSize      The block size of specified SD device partition.\r
+  @param[in] Buffer         The pointer to the transfer buffer.\r
+  @param[in] BufferSize     The size of transfer buffer.\r
+  @param[in] IsRead         Boolean to show the operation direction.\r
+\r
+  @retval EFI_SUCCESS       The operation is done correctly.\r
+  @retval Others            The operation fails.\r
+\r
+**/\r
+EFI_STATUS\r
+SdPeimRwMultiBlocks (\r
+  IN SD_PEIM_HC_SLOT                *Slot,\r
+  IN EFI_LBA                        Lba,\r
+  IN UINT32                         BlockSize,\r
+  IN VOID                           *Buffer,\r
+  IN UINTN                          BufferSize,\r
+  IN BOOLEAN                        IsRead\r
+  )\r
+{\r
+  SD_COMMAND_BLOCK                    SdCmdBlk;\r
+  SD_STATUS_BLOCK                     SdStatusBlk;\r
+  SD_COMMAND_PACKET                   Packet;\r
+  EFI_STATUS                          Status;\r
+\r
+  ZeroMem (&SdCmdBlk, sizeof (SdCmdBlk));\r
+  ZeroMem (&SdStatusBlk, sizeof (SdStatusBlk));\r
+  ZeroMem (&Packet, sizeof (Packet));\r
+\r
+  Packet.SdCmdBlk    = &SdCmdBlk;\r
+  Packet.SdStatusBlk = &SdStatusBlk;\r
+  //\r
+  // Calculate timeout value through the below formula.\r
+  // Timeout = (transfer size) / (2MB/s).\r
+  // Taking 2MB/s as divisor is because it's the lowest\r
+  // transfer speed of class 2.\r
+  //\r
+  Packet.Timeout       = (BufferSize / (2 * 1024 * 1024) + 1) * 1000 * 1000;;\r
+\r
+  if (IsRead) {\r
+    Packet.InDataBuffer     = Buffer;\r
+    Packet.InTransferLength = (UINT32)BufferSize;\r
+\r
+    SdCmdBlk.CommandIndex = SD_READ_MULTIPLE_BLOCK;\r
+    SdCmdBlk.CommandType  = SdCommandTypeAdtc;\r
+    SdCmdBlk.ResponseType = SdResponseTypeR1;\r
+  } else {\r
+    Packet.OutDataBuffer     = Buffer;\r
+    Packet.OutTransferLength = (UINT32)BufferSize;\r
+\r
+    SdCmdBlk.CommandIndex = SD_WRITE_MULTIPLE_BLOCK;\r
+    SdCmdBlk.CommandType  = SdCommandTypeAdtc;\r
+    SdCmdBlk.ResponseType = SdResponseTypeR1;\r
+  }\r
+\r
+  if (Slot->SectorAddressing) {\r
+    SdCmdBlk.CommandArgument = (UINT32)Lba;\r
+  } else {\r
+    SdCmdBlk.CommandArgument = (UINT32)MultU64x32 (Lba, BlockSize);\r
+  }\r
+\r
+  Status = SdPeimExecCmd (Slot, &Packet);\r
+\r
+  return Status;\r
+}\r
+\r
+/**\r
+  Send command SEND_TUNING_BLOCK to the SD device for SDR104/SDR50 optimal sampling point\r
+  detection.\r
+\r
+  It may be sent up to 40 times until the host finishes the tuning procedure.\r
+\r
+  Refer to SD Physical Layer Simplified Spec 4.1 Section 4.7 for details.\r
+\r
+  @param[in] Slot           The slot number of the SD card to send the command to.\r
+\r
+  @retval EFI_SUCCESS       The operation is done correctly.\r
+  @retval Others            The operation fails.\r
+\r
+**/\r
+EFI_STATUS\r
+SdPeimSendTuningBlk (\r
+  IN SD_PEIM_HC_SLOT        *Slot\r
+  )\r
+{\r
+  SD_COMMAND_BLOCK                    SdCmdBlk;\r
+  SD_STATUS_BLOCK                     SdStatusBlk;\r
+  SD_COMMAND_PACKET                   Packet;\r
+  EFI_STATUS                          Status;\r
+  UINT8                               TuningBlock[64];\r
+\r
+  ZeroMem (&SdCmdBlk, sizeof (SdCmdBlk));\r
+  ZeroMem (&SdStatusBlk, sizeof (SdStatusBlk));\r
+  ZeroMem (&Packet, sizeof (Packet));\r
+\r
+  Packet.SdCmdBlk    = &SdCmdBlk;\r
+  Packet.SdStatusBlk = &SdStatusBlk;\r
+  Packet.Timeout     = SD_TIMEOUT;\r
+\r
+  SdCmdBlk.CommandIndex = SD_SEND_TUNING_BLOCK;\r
+  SdCmdBlk.CommandType  = SdCommandTypeAdtc;\r
+  SdCmdBlk.ResponseType = SdResponseTypeR1;\r
+  SdCmdBlk.CommandArgument = 0;\r
+\r
+  Packet.InDataBuffer     = TuningBlock;\r
+  Packet.InTransferLength = sizeof (TuningBlock);\r
+\r
+  Status = SdPeimExecCmd (Slot, &Packet);\r
+\r
+  return Status;\r
+}\r
+\r
+/**\r
+  Tunning the sampling point of SDR104 or SDR50 bus speed mode.\r
+\r
+  Command SD_SEND_TUNING_BLOCK may be sent up to 40 times until the host finishes the\r
+  tuning procedure.\r
+\r
+  Refer to SD Physical Layer Simplified Spec 4.1 Section 4.7 and SD Host Controller\r
+  Simplified Spec 3.0 Figure 2-29 for details.\r
+\r
+  @param[in] Slot           The slot number of the SD card to send the command to.\r
+\r
+  @retval EFI_SUCCESS       The operation is done correctly.\r
+  @retval Others            The operation fails.\r
+\r
+**/\r
+EFI_STATUS\r
+SdPeimTuningClock (\r
+  IN SD_PEIM_HC_SLOT        *Slot\r
+  )\r
+{\r
+  EFI_STATUS          Status;\r
+  UINT8               HostCtrl2;\r
+  UINT8               Retry;\r
+\r
+  //\r
+  // Notify the host that the sampling clock tuning procedure starts.\r
+  //\r
+  HostCtrl2 = BIT6;\r
+  Status = SdPeimHcOrMmio (Slot->SdHcBase + SD_HC_HOST_CTRL2, sizeof (HostCtrl2), &HostCtrl2);\r
+  if (EFI_ERROR (Status)) {\r
+    return Status;\r
+  }\r
+  //\r
+  // Ask the device to send a sequence of tuning blocks till the tuning procedure is done.\r
+  //\r
+  Retry = 0;\r
+  do {\r
+    Status = SdPeimSendTuningBlk (Slot);\r
+    if (EFI_ERROR (Status)) {\r
+      return Status;\r
+    }\r
+\r
+    Status = SdPeimHcRwMmio (Slot->SdHcBase + SD_HC_HOST_CTRL2, TRUE, sizeof (HostCtrl2), &HostCtrl2);\r
+    if (EFI_ERROR (Status)) {\r
+      return Status;\r
+    }\r
+\r
+    if ((HostCtrl2 & (BIT6 | BIT7)) == BIT7) {\r
+      break;\r
+    }\r
+  } while (++Retry < 40);\r
+\r
+  if (Retry == 40) {\r
+    Status = EFI_TIMEOUT;\r
+  }\r
+  return Status;\r
+}\r
+\r
+/**\r
+  Switch the bus width to specified width.\r
+\r
+  Refer to SD Physical Layer Simplified Spec 4.1 Section 4.7 and\r
+  SD Host Controller Simplified Spec 3.0 section Figure 3-7 for details.\r
+\r
+  @param[in] Slot           The slot number of the SD card to send the command to.\r
+  @param[in] Rca            The relative device address to be assigned.\r
+  @param[in] BusWidth       The bus width to be set, it could be 4 or 8.\r
+\r
+  @retval EFI_SUCCESS       The operation is done correctly.\r
+  @retval Others            The operation fails.\r
+\r
+**/\r
+EFI_STATUS\r
+SdPeimSwitchBusWidth (\r
+  IN SD_PEIM_HC_SLOT        *Slot,\r
+  IN UINT16                 Rca,\r
+  IN UINT8                  BusWidth\r
+  )\r
+{\r
+  EFI_STATUS          Status;\r
+  UINT32              DevStatus;\r
+\r
+  Status = SdPeimSetBusWidth (Slot, Rca, BusWidth);\r
+  if (EFI_ERROR (Status)) {\r
+    return Status;\r
+  }\r
+\r
+  Status = SdPeimSendStatus (Slot, Rca, &DevStatus);\r
+  if (EFI_ERROR (Status)) {\r
+    return Status;\r
+  }\r
+  //\r
+  // Check the switch operation is really successful or not.\r
+  //\r
+  if ((DevStatus >> 16) != 0) {\r
+    return EFI_DEVICE_ERROR;\r
+  }\r
+\r
+  Status = SdPeimHcSetBusWidth (Slot->SdHcBase, BusWidth);\r
+\r
+  return Status;\r
+}\r
+\r
+/**\r
+  Switch the high speed timing according to request.\r
+\r
+  Refer to SD Physical Layer Simplified Spec 4.1 Section 4.7 and\r
+  SD Host Controller Simplified Spec 3.0 section Figure 2-29 for details.\r
+\r
+  @param[in] Slot           The slot number of the SD card to send the command to.\r
+  @param[in] Rca            The relative device address to be assigned.\r
+  @param[in] S18a           The boolean to show if it's a UHS-I SD card.\r
+\r
+  @retval EFI_SUCCESS       The operation is done correctly.\r
+  @retval Others            The operation fails.\r
+\r
+**/\r
+EFI_STATUS\r
+SdPeimSetBusMode (\r
+  IN SD_PEIM_HC_SLOT        *Slot,\r
+  IN UINT16                 Rca,\r
+  IN BOOLEAN                S18a\r
+  )\r
+{\r
+  EFI_STATUS                   Status;\r
+  SD_HC_SLOT_CAP               Capability;\r
+  UINT32                       ClockFreq;\r
+  UINT8                        BusWidth;\r
+  UINT8                        AccessMode;\r
+  UINT8                        HostCtrl1;\r
+  UINT8                        HostCtrl2;\r
+\r
+  Status = SdPeimGetCsd (Slot, Rca, &Slot->Csd);\r
+  if (EFI_ERROR (Status)) {\r
+    DEBUG ((EFI_D_ERROR, "SdPeimSetBusMode: SdPeimGetCsd fails with %r\n", Status));\r
+    return Status;\r
+  }\r
+\r
+  Status = SdPeimHcGetCapability (Slot->SdHcBase, &Capability);\r
+  if (EFI_ERROR (Status)) {\r
+    return Status;\r
+  }\r
+\r
+  Status = SdPeimSelect (Slot, Rca);\r
+  if (EFI_ERROR (Status)) {\r
+    DEBUG ((EFI_D_ERROR, "SdPeimSetBusMode: SdPeimSelect fails with %r\n", Status));\r
+    return Status;\r
+  }\r
+\r
+  BusWidth = 4;\r
+  Status = SdPeimSwitchBusWidth (Slot, Rca, BusWidth);\r
+  if (EFI_ERROR (Status)) {\r
+    DEBUG ((EFI_D_ERROR, "SdPeimSetBusMode: SdPeimSwitchBusWidth fails with %r\n", Status));\r
+    return Status;\r
+  }\r
+\r
+  //\r
+  // Calculate supported bus speed/bus width/clock frequency.\r
+  //\r
+  ClockFreq = 0;\r
+  if (S18a && (Capability.Sdr104 != 0)) {\r
+    ClockFreq = 208;\r
+    AccessMode = 3;\r
+  } else if (S18a && (Capability.Sdr50 != 0)) {\r
+    ClockFreq = 100;\r
+    AccessMode = 2;\r
+  } else if (S18a && (Capability.Ddr50 != 0)) {\r
+    ClockFreq = 50;\r
+    AccessMode = 4;\r
+  } else {\r
+    ClockFreq = 50;\r
+    AccessMode = 1;\r
+  }\r
+\r
+  DEBUG ((EFI_D_INFO, "AccessMode %d ClockFreq %d BusWidth %d\n", AccessMode, ClockFreq, BusWidth));\r
+\r
+  Status = SdPeimSwitch (Slot, AccessMode, 0, 0, 0, TRUE);\r
+  if (EFI_ERROR (Status)) {\r
+    DEBUG ((EFI_D_ERROR, "SdPeimSetBusMode: SdPeimSwitch fails with %r\n", Status));\r
+    return Status;\r
+  }\r
+\r
+  //\r
+  // Set to Hight Speed timing\r
+  //\r
+  if (AccessMode == 1) {\r
+    HostCtrl1 = BIT2;\r
+    Status = SdPeimHcOrMmio (Slot->SdHcBase + SD_HC_HOST_CTRL1, sizeof (HostCtrl1), &HostCtrl1);\r
+    if (EFI_ERROR (Status)) {\r
+      return Status;\r
+    }\r
+  }\r
+\r
+  HostCtrl2 = (UINT8)~0x7;\r
+  Status = SdPeimHcAndMmio (Slot->SdHcBase + SD_HC_HOST_CTRL2, sizeof (HostCtrl2), &HostCtrl2);\r
+  if (EFI_ERROR (Status)) {\r
+    return Status;\r
+  }\r
+  HostCtrl2 = AccessMode;\r
+  Status = SdPeimHcOrMmio (Slot->SdHcBase + SD_HC_HOST_CTRL2, sizeof (HostCtrl2), &HostCtrl2);\r
+  if (EFI_ERROR (Status)) {\r
+    return Status;\r
+  }\r
+\r
+  Status = SdPeimHcClockSupply (Slot->SdHcBase, ClockFreq * 1000);\r
+  if (EFI_ERROR (Status)) {\r
+    DEBUG ((EFI_D_ERROR, "SdPeimSetBusMode: SdPeimHcClockSupply %r\n", Status));\r
+    return Status;\r
+  }\r
+\r
+  if ((AccessMode == 3) || ((AccessMode == 2) && (Capability.TuningSDR50 != 0))) {\r
+    Status = SdPeimTuningClock (Slot);\r
+    if (EFI_ERROR (Status)) {\r
+      DEBUG ((EFI_D_ERROR, "SdPeimSetBusMode: SdPeimTuningClock fails with %r\n", Status));\r
+      return Status;\r
+    }\r
+  }\r
+\r
+  DEBUG ((EFI_D_INFO, "SdPeimSetBusMode: SdPeimSetBusMode %r\n", Status));\r
+\r
+  return Status;\r
+}\r
+\r
+/**\r
+  Execute SD device identification procedure.\r
+\r
+  Refer to SD Physical Layer Simplified Spec 4.1 Section 3.6 for details.\r
+\r
+  @param[in] Slot           The slot number of the SD card to send the command to.\r
+\r
+  @retval EFI_SUCCESS       There is a SD card.\r
+  @retval Others            There is not a SD card.\r
+\r
+**/\r
+EFI_STATUS\r
+SdPeimIdentification (\r
+  IN SD_PEIM_HC_SLOT        *Slot\r
+  )\r
+{\r
+  EFI_STATUS                     Status;\r
+  UINT32                         Ocr;\r
+  UINT16                         Rca;\r
+  BOOLEAN                        Xpc;\r
+  BOOLEAN                        S18r;\r
+  UINT64                         MaxCurrent;\r
+  UINT64                         Current;\r
+  UINT16                         ControllerVer;\r
+  UINT8                          PowerCtrl;\r
+  UINT32                         PresentState;\r
+  UINT8                          HostCtrl2;\r
+  SD_HC_SLOT_CAP                 Capability;\r
+\r
+  //\r
+  // 1. Send Cmd0 to the device\r
+  //\r
+  Status = SdPeimReset (Slot);\r
+  if (EFI_ERROR (Status)) {\r
+    DEBUG ((EFI_D_ERROR, "SdPeimIdentification: Executing Cmd0 fails with %r\n", Status));\r
+    return Status;\r
+  }\r
+  //\r
+  // 2. Send Cmd8 to the device\r
+  //\r
+  Status = SdPeimVoltageCheck (Slot, 0x1, 0xFF);\r
+  if (EFI_ERROR (Status)) {\r
+    DEBUG ((EFI_D_ERROR, "SdPeimIdentification: Executing Cmd8 fails with %r\n", Status));\r
+    return Status;\r
+  }\r
+  //\r
+  // 3. Send SDIO Cmd5 to the device to the SDIO device OCR register.\r
+  //\r
+  Status = SdioSendOpCond (Slot, 0, FALSE);\r
+  if (!EFI_ERROR (Status)) {\r
+    DEBUG ((EFI_D_ERROR, "SdPeimIdentification: Found SDIO device, ignore it as we don't support\n"));\r
+    return EFI_DEVICE_ERROR;\r
+  }\r
+  //\r
+  // 4. Send Acmd41 with voltage window 0 to the device\r
+  //\r
+  Status = SdPeimSendOpCond (Slot, 0, 0, FALSE, FALSE, FALSE, &Ocr);\r
+  if (EFI_ERROR (Status)) {\r
+    DEBUG ((EFI_D_ERROR, "SdPeimIdentification: Executing SdPeimSendOpCond fails with %r\n", Status));\r
+    return EFI_DEVICE_ERROR;\r
+  }\r
+\r
+  Status = SdPeimHcGetCapability (Slot->SdHcBase, &Capability);\r
+  if (EFI_ERROR (Status)) {\r
+    return Status;\r
+  }\r
+\r
+  Status = SdPeimHcRwMmio (Slot->SdHcBase + SD_HC_MAX_CURRENT_CAP, TRUE, sizeof (Current), &Current);\r
+  if (EFI_ERROR (Status)) {\r
+    return Status;\r
+  }\r
+\r
+  if (Capability.Voltage33 != 0) {\r
+    //\r
+    // Support 3.3V\r
+    //\r
+    MaxCurrent = ((UINT32)Current & 0xFF) * 4;\r
+  } else if (Capability.Voltage30 != 0) {\r
+    //\r
+    // Support 3.0V\r
+    //\r
+    MaxCurrent = (((UINT32)Current >> 8) & 0xFF) * 4;\r
+  } else if (Capability.Voltage18 != 0) {\r
+    //\r
+    // Support 1.8V\r
+    //\r
+    MaxCurrent = (((UINT32)Current >> 16) & 0xFF) * 4;\r
+  } else {\r
+    ASSERT (FALSE);\r
+    return EFI_DEVICE_ERROR;\r
+  }\r
+\r
+  if (MaxCurrent >= 150) {\r
+    Xpc = TRUE;\r
+  } else {\r
+    Xpc = FALSE;\r
+  }\r
+\r
+  Status = SdPeimHcRwMmio (Slot->SdHcBase + SD_HC_CTRL_VER, TRUE, sizeof (ControllerVer), &ControllerVer);\r
+  if (EFI_ERROR (Status)) {\r
+    return Status;\r
+  }\r
+\r
+  if ((ControllerVer & 0xFF) == 2) {\r
+    S18r = TRUE;\r
+  } else if (((ControllerVer & 0xFF) == 0) || ((ControllerVer & 0xFF) == 1)) {\r
+    S18r = FALSE;\r
+  } else {\r
+    ASSERT (FALSE);\r
+    return EFI_UNSUPPORTED;\r
+  }\r
+  //\r
+  // 5. Repeatly send Acmd41 with supply voltage window to the device.\r
+  //    Note here we only support the cards complied with SD physical\r
+  //    layer simplified spec version 2.0 and version 3.0 and above.\r
+  //\r
+  do {\r
+    Status = SdPeimSendOpCond (Slot, 0, Ocr, S18r, Xpc, TRUE, &Ocr);\r
+    if (EFI_ERROR (Status)) {\r
+      DEBUG ((EFI_D_ERROR, "SdPeimIdentification: SdPeimSendOpCond fails with %r Ocr %x, S18r %x, Xpc %x\n", Status, Ocr, S18r, Xpc));\r
+      return EFI_DEVICE_ERROR;\r
+    }\r
+  } while ((Ocr & BIT31) == 0);\r
+\r
+  //\r
+  // 6. If the S18a bit is set and the Host Controller supports 1.8V signaling\r
+  //    (One of support bits is set to 1: SDR50, SDR104 or DDR50 in the\r
+  //    Capabilities register), switch its voltage to 1.8V.\r
+  //\r
+  if ((Capability.Sdr50 != 0 ||\r
+       Capability.Sdr104 != 0 ||\r
+       Capability.Ddr50 != 0) &&\r
+       ((Ocr & BIT24) != 0)) {\r
+    Status = SdPeimVoltageSwitch (Slot);\r
+    if (EFI_ERROR (Status)) {\r
+      DEBUG ((EFI_D_ERROR, "SdPeimIdentification: Executing SdPeimVoltageSwitch fails with %r\n", Status));\r
+      Status = EFI_DEVICE_ERROR;\r
+      goto Error;\r
+    } else {\r
+      Status = SdPeimHcStopClock (Slot->SdHcBase);\r
+      if (EFI_ERROR (Status)) {\r
+        Status = EFI_DEVICE_ERROR;\r
+        goto Error;\r
+      }\r
+\r
+      SdPeimHcRwMmio (Slot->SdHcBase + SD_HC_PRESENT_STATE, TRUE, sizeof (PresentState), &PresentState);\r
+      if (((PresentState >> 20) & 0xF) != 0) {\r
+        DEBUG ((EFI_D_ERROR, "SdPeimIdentification: SwitchVoltage fails with PresentState = 0x%x\n", PresentState));\r
+        Status = EFI_DEVICE_ERROR;\r
+        goto Error;\r
+      }\r
+      HostCtrl2  = BIT3;\r
+      SdPeimHcOrMmio (Slot->SdHcBase + SD_HC_HOST_CTRL2, sizeof (HostCtrl2), &HostCtrl2);\r
+\r
+      MicroSecondDelay (5000);\r
+\r
+      SdPeimHcRwMmio (Slot->SdHcBase + SD_HC_HOST_CTRL2, TRUE, sizeof (HostCtrl2), &HostCtrl2);\r
+      if ((HostCtrl2 & BIT3) == 0) {\r
+        DEBUG ((EFI_D_ERROR, "SdPeimIdentification: SwitchVoltage fails with HostCtrl2 = 0x%x\n", HostCtrl2));\r
+        Status = EFI_DEVICE_ERROR;\r
+        goto Error;\r
+      }\r
+\r
+      SdPeimHcInitClockFreq (Slot->SdHcBase);\r
+\r
+      MicroSecondDelay (1);\r
+\r
+      SdPeimHcRwMmio (Slot->SdHcBase + SD_HC_PRESENT_STATE, TRUE, sizeof (PresentState), &PresentState);\r
+      if (((PresentState >> 20) & 0xF) != 0xF) {\r
+        DEBUG ((EFI_D_ERROR, "SdPeimIdentification: SwitchVoltage fails with PresentState = 0x%x, It should be 0xF\n", PresentState));\r
+        Status = EFI_DEVICE_ERROR;\r
+        goto Error;\r
+      }\r
+    }\r
+    DEBUG ((EFI_D_INFO, "SdPeimIdentification: Switch to 1.8v signal voltage success\n"));\r
+  }\r
+\r
+  Status = SdPeimAllSendCid (Slot);\r
+  if (EFI_ERROR (Status)) {\r
+    DEBUG ((EFI_D_ERROR, "SdPeimIdentification: Executing SdPeimAllSendCid fails with %r\n", Status));\r
+    return Status;\r
+  }\r
+\r
+  Status = SdPeimSetRca (Slot, &Rca);\r
+  if (EFI_ERROR (Status)) {\r
+    DEBUG ((EFI_D_ERROR, "SdPeimIdentification: Executing SdPeimSetRca fails with %r\n", Status));\r
+    return Status;\r
+  }\r
+  //\r
+  // Enter Data Tranfer Mode.\r
+  //\r
+  DEBUG ((EFI_D_INFO, "Found a SD device at slot [%d]\n", Slot));\r
+\r
+  Status = SdPeimSetBusMode (Slot, Rca, ((Ocr & BIT24) != 0));\r
+\r
+  return Status;\r
+\r
+Error:\r
+  //\r
+  // Set SD Bus Power = 0\r
+  //\r
+  PowerCtrl = (UINT8)~BIT0;\r
+  Status = SdPeimHcAndMmio (Slot->SdHcBase + SD_HC_POWER_CTRL, sizeof (PowerCtrl), &PowerCtrl);\r
+  return EFI_DEVICE_ERROR;\r
+}\r
diff --git a/MdeModulePkg/Bus/Sd/SdBlockIoPei/SdHci.h b/MdeModulePkg/Bus/Sd/SdBlockIoPei/SdHci.h
new file mode 100644 (file)
index 0000000..2f44304
--- /dev/null
@@ -0,0 +1,354 @@
+/** @file\r
+\r
+  Copyright (c) 2015, Intel Corporation. All rights reserved.<BR>\r
+  This program and the accompanying materials\r
+  are licensed and made available under the terms and conditions of the BSD License\r
+  which accompanies this distribution.  The full text of the license may be found at\r
+  http://opensource.org/licenses/bsd-license.php.\r
+\r
+  THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+  WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+\r
+**/\r
+\r
+#ifndef _SD_HCI_H_\r
+#define _SD_HCI_H_\r
+\r
+//\r
+// SD Host Controller MMIO Register Offset\r
+//\r
+#define SD_HC_SDMA_ADDR           0x00\r
+#define SD_HC_ARG2                0x00\r
+#define SD_HC_BLK_SIZE            0x04\r
+#define SD_HC_BLK_COUNT           0x06\r
+#define SD_HC_ARG1                0x08\r
+#define SD_HC_TRANS_MOD           0x0C\r
+#define SD_HC_COMMAND             0x0E\r
+#define SD_HC_RESPONSE            0x10\r
+#define SD_HC_BUF_DAT_PORT        0x20\r
+#define SD_HC_PRESENT_STATE       0x24\r
+#define SD_HC_HOST_CTRL1          0x28\r
+#define SD_HC_POWER_CTRL          0x29\r
+#define SD_HC_BLK_GAP_CTRL        0x2A\r
+#define SD_HC_WAKEUP_CTRL         0x2B\r
+#define SD_HC_CLOCK_CTRL          0x2C\r
+#define SD_HC_TIMEOUT_CTRL        0x2E\r
+#define SD_HC_SW_RST              0x2F\r
+#define SD_HC_NOR_INT_STS         0x30\r
+#define SD_HC_ERR_INT_STS         0x32\r
+#define SD_HC_NOR_INT_STS_EN      0x34\r
+#define SD_HC_ERR_INT_STS_EN      0x36\r
+#define SD_HC_NOR_INT_SIG_EN      0x38\r
+#define SD_HC_ERR_INT_SIG_EN      0x3A\r
+#define SD_HC_AUTO_CMD_ERR_STS    0x3C\r
+#define SD_HC_HOST_CTRL2          0x3E\r
+#define SD_HC_CAP                 0x40\r
+#define SD_HC_MAX_CURRENT_CAP     0x48\r
+#define SD_HC_FORCE_EVT_AUTO_CMD  0x50\r
+#define SD_HC_FORCE_EVT_ERR_INT   0x52\r
+#define SD_HC_ADMA_ERR_STS        0x54\r
+#define SD_HC_ADMA_SYS_ADDR       0x58\r
+#define SD_HC_PRESET_VAL          0x60\r
+#define SD_HC_SHARED_BUS_CTRL     0xE0\r
+#define SD_HC_SLOT_INT_STS        0xFC\r
+#define SD_HC_CTRL_VER            0xFE\r
+\r
+//\r
+// The transfer modes supported by SD Host Controller\r
+// Simplified Spec 3.0 Table 1-2\r
+//\r
+typedef enum {\r
+  SdNoData,\r
+  SdPioMode,\r
+  SdSdmaMode,\r
+  SdAdmaMode\r
+} SD_HC_TRANSFER_MODE;\r
+\r
+//\r
+// The maximum data length of each descriptor line\r
+//\r
+#define ADMA_MAX_DATA_PER_LINE      0x10000\r
+#define SD_SDMA_BOUNDARY            512 * 1024\r
+#define SD_SDMA_ROUND_UP(x, n)      (((x) + n) & ~(n - 1))\r
+\r
+typedef enum {\r
+  SdCommandTypeBc,  // Broadcast commands, no response\r
+  SdCommandTypeBcr, // Broadcast commands with response\r
+  SdCommandTypeAc,  // Addressed(point-to-point) commands\r
+  SdCommandTypeAdtc // Addressed(point-to-point) data transfer commands\r
+} SD_COMMAND_TYPE;\r
+\r
+typedef enum {\r
+  SdResponseTypeR1,\r
+  SdResponseTypeR1b,\r
+  SdResponseTypeR2,\r
+  SdResponseTypeR3,\r
+  SdResponseTypeR4,\r
+  SdResponseTypeR5,\r
+  SdResponseTypeR5b,\r
+  SdResponseTypeR6,\r
+  SdResponseTypeR7\r
+} SD_RESPONSE_TYPE;\r
+\r
+typedef struct _SD_COMMAND_BLOCK {\r
+  UINT16                            CommandIndex;\r
+  UINT32                            CommandArgument;\r
+  UINT32                            CommandType;      // One of the SD_COMMAND_TYPE values\r
+  UINT32                            ResponseType;     // One of the SD_RESPONSE_TYPE values\r
+} SD_COMMAND_BLOCK;\r
+\r
+typedef struct _SD_STATUS_BLOCK {\r
+  UINT32                            Resp0;\r
+  UINT32                            Resp1;\r
+  UINT32                            Resp2;\r
+  UINT32                            Resp3;\r
+} SD_STATUS_BLOCK;\r
+\r
+typedef struct _SD_COMMAND_PACKET {\r
+  UINT64                            Timeout;\r
+  SD_COMMAND_BLOCK                  *SdCmdBlk;\r
+  SD_STATUS_BLOCK                   *SdStatusBlk;\r
+  VOID                              *InDataBuffer;\r
+  VOID                              *OutDataBuffer;\r
+  UINT32                            InTransferLength;\r
+  UINT32                            OutTransferLength;\r
+} SD_COMMAND_PACKET;\r
+\r
+#pragma pack(1)\r
+\r
+typedef struct {\r
+  UINT32 Valid:1;\r
+  UINT32 End:1;\r
+  UINT32 Int:1;\r
+  UINT32 Reserved:1;\r
+  UINT32 Act:2;\r
+  UINT32 Reserved1:10;\r
+  UINT32 Length:16;\r
+  UINT32 Address;\r
+} SD_HC_ADMA_DESC_LINE;\r
+\r
+typedef struct {\r
+  UINT32   TimeoutFreq:6;     // bit 0:5\r
+  UINT32   Reserved:1;        // bit 6\r
+  UINT32   TimeoutUnit:1;     // bit 7\r
+  UINT32   BaseClkFreq:8;     // bit 8:15\r
+  UINT32   MaxBlkLen:2;       // bit 16:17\r
+  UINT32   BusWidth8:1;       // bit 18\r
+  UINT32   Adma2:1;           // bit 19\r
+  UINT32   Reserved2:1;       // bit 20\r
+  UINT32   HighSpeed:1;       // bit 21\r
+  UINT32   Sdma:1;            // bit 22\r
+  UINT32   SuspRes:1;         // bit 23\r
+  UINT32   Voltage33:1;       // bit 24\r
+  UINT32   Voltage30:1;       // bit 25\r
+  UINT32   Voltage18:1;       // bit 26\r
+  UINT32   Reserved3:1;       // bit 27\r
+  UINT32   SysBus64:1;        // bit 28\r
+  UINT32   AsyncInt:1;        // bit 29\r
+  UINT32   SlotType:2;        // bit 30:31\r
+  UINT32   Sdr50:1;           // bit 32\r
+  UINT32   Sdr104:1;          // bit 33\r
+  UINT32   Ddr50:1;           // bit 34\r
+  UINT32   Reserved4:1;       // bit 35\r
+  UINT32   DriverTypeA:1;     // bit 36\r
+  UINT32   DriverTypeC:1;     // bit 37\r
+  UINT32   DriverTypeD:1;     // bit 38\r
+  UINT32   DriverType4:1;     // bit 39\r
+  UINT32   TimerCount:4;      // bit 40:43\r
+  UINT32   Reserved5:1;       // bit 44\r
+  UINT32   TuningSDR50:1;     // bit 45\r
+  UINT32   RetuningMod:2;     // bit 46:47\r
+  UINT32   ClkMultiplier:8;   // bit 48:55\r
+  UINT32   Reserved6:7;       // bit 56:62\r
+  UINT32   Hs400:1;           // bit 63\r
+} SD_HC_SLOT_CAP;\r
+\r
+#pragma pack()\r
+\r
+/**\r
+  Software reset the specified SD host controller and enable all interrupts.\r
+\r
+  @param[in] Bar            The mmio base address of the slot to be accessed.\r
+\r
+  @retval EFI_SUCCESS       The software reset executes successfully.\r
+  @retval Others            The software reset fails.\r
+\r
+**/\r
+EFI_STATUS\r
+SdPeimHcReset (\r
+  IN UINTN                  Bar\r
+  );\r
+\r
+/**\r
+  Set all interrupt status bits in Normal and Error Interrupt Status Enable\r
+  register.\r
+\r
+  @param[in] Bar            The mmio base address of the slot to be accessed.\r
+\r
+  @retval EFI_SUCCESS       The operation executes successfully.\r
+  @retval Others            The operation fails.\r
+\r
+**/\r
+EFI_STATUS\r
+SdPeimHcEnableInterrupt (\r
+  IN UINTN                  Bar\r
+  );\r
+\r
+/**\r
+  Get the capability data from the specified slot.\r
+\r
+  @param[in]  Bar             The mmio base address of the slot to be accessed.\r
+  @param[out] Capability      The buffer to store the capability data.\r
+\r
+  @retval EFI_SUCCESS         The operation executes successfully.\r
+  @retval Others              The operation fails.\r
+\r
+**/\r
+EFI_STATUS\r
+SdPeimHcGetCapability (\r
+  IN     UINTN              Bar,\r
+     OUT SD_HC_SLOT_CAP     *Capability\r
+  );\r
+\r
+/**\r
+  Detect whether there is a SD card attached at the specified SD host controller\r
+  slot.\r
+\r
+  Refer to SD Host Controller Simplified spec 3.0 Section 3.1 for details.\r
+\r
+  @param[in]  Bar           The mmio base address of the slot to be accessed.\r
+\r
+  @retval EFI_SUCCESS       There is a SD card attached.\r
+  @retval EFI_NO_MEDIA      There is not a SD card attached.\r
+  @retval Others            The detection fails.\r
+\r
+**/\r
+EFI_STATUS\r
+SdPeimHcCardDetect (\r
+  IN UINTN                  Bar\r
+  );\r
+\r
+/**\r
+  Initial SD host controller with lowest clock frequency, max power and max timeout value\r
+  at initialization.\r
+\r
+  @param[in] Bar            The mmio base address of the slot to be accessed.\r
+\r
+  @retval EFI_SUCCESS       The host controller is initialized successfully.\r
+  @retval Others            The host controller isn't initialized successfully.\r
+\r
+**/\r
+EFI_STATUS\r
+SdPeimHcInitHost (\r
+  IN UINTN                  Bar\r
+  );\r
+\r
+/**\r
+  Send command SWITCH_FUNC to the SD device to check switchable function or switch card function.\r
+\r
+  Refer to SD Physical Layer Simplified Spec 4.1 Section 4.7 for details.\r
+\r
+  @param[in]  Slot          The slot number of the SD card to send the command to.\r
+  @param[in]  AccessMode    The value for access mode group.\r
+  @param[in]  CommandSystem The value for command set group.\r
+  @param[in]  DriveStrength The value for drive length group.\r
+  @param[in]  PowerLimit    The value for power limit group.\r
+  @param[in]  Mode          Switch or check function.\r
+\r
+  @retval EFI_SUCCESS       The operation is done correctly.\r
+  @retval Others            The operation fails.\r
+\r
+**/\r
+EFI_STATUS\r
+SdPeimSwitch (\r
+  IN SD_PEIM_HC_SLOT        *Slot,\r
+  IN UINT8                  AccessMode,\r
+  IN UINT8                  CommandSystem,\r
+  IN UINT8                  DriveStrength,\r
+  IN UINT8                  PowerLimit,\r
+  IN BOOLEAN                Mode\r
+  );\r
+\r
+/**\r
+  Send command READ_SINGLE_BLOCK/WRITE_SINGLE_BLOCK to the addressed SD device\r
+  to read/write the specified number of blocks.\r
+\r
+  Refer to SD Physical Layer Simplified Spec 4.1 Section 4.7 for details.\r
+\r
+  @param[in] Slot           The slot number of the SD card to send the command to.\r
+  @param[in] Lba            The logical block address of starting access.\r
+  @param[in] BlockSize      The block size of specified SD device partition.\r
+  @param[in] Buffer         The pointer to the transfer buffer.\r
+  @param[in] BufferSize     The size of transfer buffer.\r
+  @param[in] IsRead         Boolean to show the operation direction.\r
+\r
+  @retval EFI_SUCCESS       The operation is done correctly.\r
+  @retval Others            The operation fails.\r
+\r
+**/\r
+EFI_STATUS\r
+SdPeimRwSingleBlock (\r
+  IN SD_PEIM_HC_SLOT                *Slot,\r
+  IN EFI_LBA                        Lba,\r
+  IN UINT32                         BlockSize,\r
+  IN VOID                           *Buffer,\r
+  IN UINTN                          BufferSize,\r
+  IN BOOLEAN                        IsRead\r
+  );\r
+\r
+/**\r
+  Send command READ_MULTIPLE_BLOCK/WRITE_MULTIPLE_BLOCK to the addressed SD device\r
+  to read/write the specified number of blocks.\r
+\r
+  Refer to SD Electrical Standard Spec 5.1 Section 6.10.4 for details.\r
+\r
+  @param[in] Slot           The slot number of the Sd card to send the command to.\r
+  @param[in] Lba            The logical block address of starting access.\r
+  @param[in] BlockSize      The block size of specified SD device partition.\r
+  @param[in] Buffer         The pointer to the transfer buffer.\r
+  @param[in] BufferSize     The size of transfer buffer.\r
+  @param[in] IsRead         Boolean to show the operation direction.\r
+\r
+  @retval EFI_SUCCESS       The operation is done correctly.\r
+  @retval Others            The operation fails.\r
+\r
+**/\r
+EFI_STATUS\r
+SdPeimRwMultiBlocks (\r
+  IN SD_PEIM_HC_SLOT                *Slot,\r
+  IN EFI_LBA                        Lba,\r
+  IN UINT32                         BlockSize,\r
+  IN VOID                           *Buffer,\r
+  IN UINTN                          BufferSize,\r
+  IN BOOLEAN                        IsRead\r
+  );\r
+\r
+/**\r
+  Execute SD device identification procedure.\r
+\r
+  Refer to SD Electrical Standard Spec 5.1 Section 6.4 for details.\r
+\r
+  @param[in] Slot           The slot number of the Sd card to send the command to.\r
+\r
+  @retval EFI_SUCCESS       There is a SD card.\r
+  @retval Others            There is not a SD card.\r
+\r
+**/\r
+EFI_STATUS\r
+SdPeimIdentification (\r
+  IN SD_PEIM_HC_SLOT           *Slot\r
+  );\r
+\r
+/**\r
+  Free the resource used by the TRB.\r
+\r
+  @param[in] Trb        The pointer to the SD_TRB instance.\r
+\r
+**/\r
+VOID\r
+SdPeimFreeTrb (\r
+  IN SD_TRB           *Trb\r
+  );\r
+\r
+#endif\r
+\r
diff --git a/MdeModulePkg/Bus/Sd/SdDxe/ComponentName.c b/MdeModulePkg/Bus/Sd/SdDxe/ComponentName.c
new file mode 100644 (file)
index 0000000..2463783
--- /dev/null
@@ -0,0 +1,240 @@
+/** @file\r
+  UEFI Component Name(2) protocol implementation for SdDxe driver.\r
+\r
+  Copyright (c) 2015, Intel Corporation. All rights reserved.<BR>\r
+  This program and the accompanying materials\r
+  are licensed and made available under the terms and conditions of the BSD License\r
+  which accompanies this distribution.  The full text of the license may be found at\r
+  http://opensource.org/licenses/bsd-license.php\r
+\r
+  THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+  WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+\r
+**/\r
+\r
+#include "SdDxe.h"\r
+\r
+//\r
+// Driver name table\r
+//\r
+GLOBAL_REMOVE_IF_UNREFERENCED EFI_UNICODE_STRING_TABLE mSdDxeDriverNameTable[] = {\r
+  { "eng;en", L"Edkii Sd Memory Card Device Driver" },\r
+  { NULL , NULL }\r
+};\r
+\r
+//\r
+// Controller name table\r
+//\r
+GLOBAL_REMOVE_IF_UNREFERENCED EFI_UNICODE_STRING_TABLE mSdDxeControllerNameTable[] = {\r
+  { "eng;en", L"Edkii Sd Host Controller" },\r
+  { NULL , NULL }\r
+};\r
+\r
+//\r
+// EFI Component Name Protocol\r
+//\r
+GLOBAL_REMOVE_IF_UNREFERENCED EFI_COMPONENT_NAME_PROTOCOL  gSdDxeComponentName = {\r
+  SdDxeComponentNameGetDriverName,\r
+  SdDxeComponentNameGetControllerName,\r
+  "eng"\r
+};\r
+\r
+//\r
+// EFI Component Name 2 Protocol\r
+//\r
+GLOBAL_REMOVE_IF_UNREFERENCED EFI_COMPONENT_NAME2_PROTOCOL gSdDxeComponentName2 = {\r
+  (EFI_COMPONENT_NAME2_GET_DRIVER_NAME) SdDxeComponentNameGetDriverName,\r
+  (EFI_COMPONENT_NAME2_GET_CONTROLLER_NAME) SdDxeComponentNameGetControllerName,\r
+  "en"\r
+};\r
+\r
+/**\r
+  Retrieves a Unicode string that is the user readable name of the driver.\r
+\r
+  This function retrieves the user readable name of a driver in the form of a\r
+  Unicode string. If the driver specified by This has a user readable name in\r
+  the language specified by Language, then a pointer to the driver name is\r
+  returned in DriverName, and EFI_SUCCESS is returned. If the driver specified\r
+  by This does not support the language specified by Language,\r
+  then EFI_UNSUPPORTED is returned.\r
+\r
+  @param  This[in]              A pointer to the EFI_COMPONENT_NAME2_PROTOCOL or\r
+                                EFI_COMPONENT_NAME_PROTOCOL instance.\r
+\r
+  @param  Language[in]          A pointer to a Null-terminated ASCII string\r
+                                array indicating the language. This is the\r
+                                language of the driver name that the caller is\r
+                                requesting, and it must match one of the\r
+                                languages specified in SupportedLanguages. The\r
+                                number of languages supported by a driver is up\r
+                                to the driver writer. Language is specified\r
+                                in RFC 4646 or ISO 639-2 language code format.\r
+\r
+  @param  DriverName[out]       A pointer to the Unicode string to return.\r
+                                This Unicode string is the name of the\r
+                                driver specified by This in the language\r
+                                specified by Language.\r
+\r
+  @retval EFI_SUCCESS           The Unicode string for the Driver specified by\r
+                                This and the language specified by Language was\r
+                                returned in DriverName.\r
+\r
+  @retval EFI_INVALID_PARAMETER Language is NULL.\r
+\r
+  @retval EFI_INVALID_PARAMETER DriverName is NULL.\r
+\r
+  @retval EFI_UNSUPPORTED       The driver specified by This does not support\r
+                                the language specified by Language.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+SdDxeComponentNameGetDriverName (\r
+  IN  EFI_COMPONENT_NAME_PROTOCOL  *This,\r
+  IN  CHAR8                        *Language,\r
+  OUT CHAR16                       **DriverName\r
+  )\r
+{\r
+  return LookupUnicodeString2 (\r
+           Language,\r
+           This->SupportedLanguages,\r
+           mSdDxeDriverNameTable,\r
+           DriverName,\r
+           (BOOLEAN)(This == &gSdDxeComponentName)\r
+           );\r
+\r
+}\r
+\r
+/**\r
+  Retrieves a Unicode string that is the user readable name of the controller\r
+  that is being managed by a driver.\r
+\r
+  This function retrieves the user readable name of the controller specified by\r
+  ControllerHandle and ChildHandle in the form of a Unicode string. If the\r
+  driver specified by This has a user readable name in the language specified by\r
+  Language, then a pointer to the controller name is returned in ControllerName,\r
+  and EFI_SUCCESS is returned.  If the driver specified by This is not currently\r
+  managing the controller specified by ControllerHandle and ChildHandle,\r
+  then EFI_UNSUPPORTED is returned.  If the driver specified by This does not\r
+  support the language specified by Language, then EFI_UNSUPPORTED is returned.\r
+\r
+  @param  This[in]              A pointer to the EFI_COMPONENT_NAME2_PROTOCOL or\r
+                                EFI_COMPONENT_NAME_PROTOCOL instance.\r
+\r
+  @param  ControllerHandle[in]  The handle of a controller that the driver\r
+                                specified by This is managing.  This handle\r
+                                specifies the controller whose name is to be\r
+                                returned.\r
+\r
+  @param  ChildHandle[in]       The handle of the child controller to retrieve\r
+                                the name of.  This is an optional parameter that\r
+                                may be NULL.  It will be NULL for device\r
+                                drivers.  It will also be NULL for a bus drivers\r
+                                that wish to retrieve the name of the bus\r
+                                controller.  It will not be NULL for a bus\r
+                                driver that wishes to retrieve the name of a\r
+                                child controller.\r
+\r
+  @param  Language[in]          A pointer to a Null-terminated ASCII string\r
+                                array indicating the language.  This is the\r
+                                language of the driver name that the caller is\r
+                                requesting, and it must match one of the\r
+                                languages specified in SupportedLanguages. The\r
+                                number of languages supported by a driver is up\r
+                                to the driver writer. Language is specified in\r
+                                RFC 4646 or ISO 639-2 language code format.\r
+\r
+  @param  ControllerName[out]   A pointer to the Unicode string to return.\r
+                                This Unicode string is the name of the\r
+                                controller specified by ControllerHandle and\r
+                                ChildHandle in the language specified by\r
+                                Language from the point of view of the driver\r
+                                specified by This.\r
+\r
+  @retval EFI_SUCCESS           The Unicode string for the user readable name in\r
+                                the language specified by Language for the\r
+                                driver specified by This was returned in\r
+                                DriverName.\r
+\r
+  @retval EFI_INVALID_PARAMETER ControllerHandle is NULL.\r
+\r
+  @retval EFI_INVALID_PARAMETER ChildHandle is not NULL and it is not a valid\r
+                                EFI_HANDLE.\r
+\r
+  @retval EFI_INVALID_PARAMETER Language is NULL.\r
+\r
+  @retval EFI_INVALID_PARAMETER ControllerName is NULL.\r
+\r
+  @retval EFI_UNSUPPORTED       The driver specified by This is not currently\r
+                                managing the controller specified by\r
+                                ControllerHandle and ChildHandle.\r
+\r
+  @retval EFI_UNSUPPORTED       The driver specified by This does not support\r
+                                the language specified by Language.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+SdDxeComponentNameGetControllerName (\r
+  IN  EFI_COMPONENT_NAME_PROTOCOL                     *This,\r
+  IN  EFI_HANDLE                                      ControllerHandle,\r
+  IN  EFI_HANDLE                                      ChildHandle        OPTIONAL,\r
+  IN  CHAR8                                           *Language,\r
+  OUT CHAR16                                          **ControllerName\r
+  )\r
+{\r
+  EFI_STATUS                Status;\r
+  EFI_BLOCK_IO_PROTOCOL     *BlockIo;\r
+  SD_DEVICE                 *Device;\r
+  EFI_UNICODE_STRING_TABLE  *ControllerNameTable;\r
+\r
+  //\r
+  // Make sure this driver is currently managing ControllHandle\r
+  //\r
+  Status = EfiTestManagedDevice (\r
+             ControllerHandle,\r
+             gSdDxeDriverBinding.DriverBindingHandle,\r
+             &gEfiSdMmcPassThruProtocolGuid\r
+             );\r
+  if (EFI_ERROR (Status)) {\r
+    return Status;\r
+  }\r
+\r
+  ControllerNameTable = mSdDxeControllerNameTable;\r
+  if (ChildHandle != NULL) {\r
+    Status = EfiTestChildHandle (\r
+               ControllerHandle,\r
+               ChildHandle,\r
+               &gEfiSdMmcPassThruProtocolGuid\r
+               );\r
+    if (EFI_ERROR (Status)) {\r
+      return Status;\r
+    }\r
+    //\r
+    // Get the child context\r
+    //\r
+    Status = gBS->OpenProtocol (\r
+                    ChildHandle,\r
+                    &gEfiBlockIoProtocolGuid,\r
+                    (VOID **) &BlockIo,\r
+                    gSdDxeDriverBinding.DriverBindingHandle,\r
+                    ChildHandle,\r
+                    EFI_OPEN_PROTOCOL_GET_PROTOCOL\r
+                    );\r
+    if (EFI_ERROR (Status)) {\r
+      return EFI_UNSUPPORTED;\r
+    }\r
+\r
+    Device = SD_DEVICE_DATA_FROM_BLKIO (BlockIo);\r
+    ControllerNameTable = Device->ControllerNameTable;\r
+  }\r
+\r
+  return LookupUnicodeString2 (\r
+           Language,\r
+           This->SupportedLanguages,\r
+           ControllerNameTable,\r
+           ControllerName,\r
+           (BOOLEAN)(This == &gSdDxeComponentName)\r
+           );\r
+}\r
+\r
diff --git a/MdeModulePkg/Bus/Sd/SdDxe/SdBlockIo.c b/MdeModulePkg/Bus/Sd/SdDxe/SdBlockIo.c
new file mode 100644 (file)
index 0000000..341d788
--- /dev/null
@@ -0,0 +1,971 @@
+/** @file\r
+  The helper functions for BlockIo and BlockIo2 protocol.\r
+\r
+  Copyright (c) 2015, Intel Corporation. All rights reserved.<BR>\r
+  This program and the accompanying materials\r
+  are licensed and made available under the terms and conditions of the BSD License\r
+  which accompanies this distribution.  The full text of the license may be found at\r
+  http://opensource.org/licenses/bsd-license.php\r
+\r
+  THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+  WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+\r
+**/\r
+\r
+#include "SdDxe.h"\r
+\r
+/**\r
+  Nonblocking I/O callback funtion when the event is signaled.\r
+\r
+  @param[in]  Event     The Event this notify function registered to.\r
+  @param[in]  Context   Pointer to the context data registered to the\r
+                        Event.\r
+\r
+**/\r
+VOID\r
+EFIAPI\r
+AsyncIoCallback (\r
+  IN EFI_EVENT                Event,\r
+  IN VOID                     *Context\r
+  )\r
+{\r
+  SD_REQUEST                  *Request;\r
+\r
+  gBS->CloseEvent (Event);\r
+\r
+  Request = (SD_REQUEST *) Context;\r
+\r
+  DEBUG_CODE_BEGIN ();\r
+    DEBUG ((EFI_D_INFO, "Sd Async Request: CmdIndex[%d] Arg[%08x] %r\n",\r
+            Request->SdMmcCmdBlk.CommandIndex, Request->SdMmcCmdBlk.CommandArgument,\r
+            Request->Packet.TransactionStatus));\r
+  DEBUG_CODE_END ();\r
+\r
+  if (EFI_ERROR (Request->Packet.TransactionStatus)) {\r
+    Request->Token->TransactionStatus = Request->Packet.TransactionStatus;\r
+  }\r
+\r
+  RemoveEntryList (&Request->Link);\r
+\r
+  if (Request->IsEnd) {\r
+    gBS->SignalEvent (Request->Token->Event);\r
+  }\r
+\r
+  FreePool (Request);\r
+}\r
+\r
+/**\r
+  Send command SET_RELATIVE_ADDRESS to the device to set the device address.\r
+\r
+  @param[in]  Device            A pointer to the SD_DEVICE instance.\r
+  @param[out] Rca               The relative device address to assign.\r
+\r
+  @retval EFI_SUCCESS           The request is executed successfully.\r
+  @retval EFI_OUT_OF_RESOURCES  The request could not be executed due to a lack of resources.\r
+  @retval Others                The request could not be executed successfully.\r
+\r
+**/\r
+EFI_STATUS\r
+SdSetRca (\r
+  IN     SD_DEVICE              *Device,\r
+     OUT UINT16                 *Rca\r
+  )\r
+{\r
+  EFI_STATUS                           Status;\r
+  EFI_SD_MMC_PASS_THRU_PROTOCOL        *PassThru;\r
+  EFI_SD_MMC_COMMAND_BLOCK             SdMmcCmdBlk;\r
+  EFI_SD_MMC_STATUS_BLOCK              SdMmcStatusBlk;\r
+  EFI_SD_MMC_PASS_THRU_COMMAND_PACKET  Packet;\r
+\r
+  PassThru = Device->Private->PassThru;\r
+\r
+  ZeroMem (&SdMmcCmdBlk, sizeof (SdMmcCmdBlk));\r
+  ZeroMem (&SdMmcStatusBlk, sizeof (SdMmcStatusBlk));\r
+  ZeroMem (&Packet, sizeof (Packet));\r
+  Packet.SdMmcCmdBlk    = &SdMmcCmdBlk;\r
+  Packet.SdMmcStatusBlk = &SdMmcStatusBlk;\r
+  Packet.Timeout        = SD_GENERIC_TIMEOUT;\r
+\r
+  SdMmcCmdBlk.CommandIndex = SD_SET_RELATIVE_ADDR;\r
+  SdMmcCmdBlk.CommandType  = SdMmcCommandTypeBcr;\r
+  SdMmcCmdBlk.ResponseType = SdMmcResponseTypeR6;\r
+\r
+  Status = PassThru->PassThru (PassThru, Device->Slot, &Packet, NULL);\r
+  if (!EFI_ERROR (Status)) {\r
+    DEBUG ((EFI_D_INFO, "Set RCA succeeds with Resp0 = 0x%x\n", SdMmcStatusBlk.Resp0));\r
+    *Rca = (UINT16)(SdMmcStatusBlk.Resp0 >> 16);\r
+  }\r
+\r
+  return Status;\r
+}\r
+\r
+/**\r
+  Send command SELECT to the device to select/deselect the device.\r
+\r
+  @param[in]  Device            A pointer to the SD_DEVICE instance.\r
+  @param[in]  Rca               The relative device address to use.\r
+\r
+  @retval EFI_SUCCESS           The request is executed successfully.\r
+  @retval EFI_OUT_OF_RESOURCES  The request could not be executed due to a lack of resources.\r
+  @retval Others                The request could not be executed successfully.\r
+\r
+**/\r
+EFI_STATUS\r
+SdSelect (\r
+  IN     SD_DEVICE              *Device,\r
+  IN     UINT16                 Rca\r
+  )\r
+{\r
+  EFI_STATUS                           Status;\r
+  EFI_SD_MMC_PASS_THRU_PROTOCOL        *PassThru;\r
+  EFI_SD_MMC_COMMAND_BLOCK             SdMmcCmdBlk;\r
+  EFI_SD_MMC_STATUS_BLOCK              SdMmcStatusBlk;\r
+  EFI_SD_MMC_PASS_THRU_COMMAND_PACKET  Packet;\r
+\r
+  PassThru = Device->Private->PassThru;\r
+\r
+  ZeroMem (&SdMmcCmdBlk, sizeof (SdMmcCmdBlk));\r
+  ZeroMem (&SdMmcStatusBlk, sizeof (SdMmcStatusBlk));\r
+  ZeroMem (&Packet, sizeof (Packet));\r
+  Packet.SdMmcCmdBlk    = &SdMmcCmdBlk;\r
+  Packet.SdMmcStatusBlk = &SdMmcStatusBlk;\r
+  Packet.Timeout        = SD_GENERIC_TIMEOUT;\r
+\r
+  SdMmcCmdBlk.CommandIndex = SD_SELECT_DESELECT_CARD;\r
+  SdMmcCmdBlk.CommandType  = SdMmcCommandTypeAc;\r
+  SdMmcCmdBlk.ResponseType = SdMmcResponseTypeR1b;\r
+  SdMmcCmdBlk.CommandArgument = (UINT32)Rca << 16;\r
+\r
+  Status = PassThru->PassThru (PassThru, Device->Slot, &Packet, NULL);\r
+\r
+  return Status;\r
+}\r
+\r
+/**\r
+  Send command SEND_STATUS to the device to get device status.\r
+\r
+  @param[in]  Device            A pointer to the SD_DEVICE instance.\r
+  @param[in]  Rca               The relative device address to use.\r
+  @param[out] DevStatus         The buffer to store the device status.\r
+\r
+  @retval EFI_SUCCESS           The request is executed successfully.\r
+  @retval EFI_OUT_OF_RESOURCES  The request could not be executed due to a lack of resources.\r
+  @retval Others                The request could not be executed successfully.\r
+\r
+**/\r
+EFI_STATUS\r
+SdSendStatus (\r
+  IN     SD_DEVICE              *Device,\r
+  IN     UINT16                 Rca,\r
+     OUT UINT32                 *DevStatus\r
+  )\r
+{\r
+  EFI_STATUS                           Status;\r
+  EFI_SD_MMC_PASS_THRU_PROTOCOL        *PassThru;\r
+  EFI_SD_MMC_COMMAND_BLOCK             SdMmcCmdBlk;\r
+  EFI_SD_MMC_STATUS_BLOCK              SdMmcStatusBlk;\r
+  EFI_SD_MMC_PASS_THRU_COMMAND_PACKET  Packet;\r
+\r
+  PassThru = Device->Private->PassThru;\r
+\r
+  ZeroMem (&SdMmcCmdBlk, sizeof (SdMmcCmdBlk));\r
+  ZeroMem (&SdMmcStatusBlk, sizeof (SdMmcStatusBlk));\r
+  ZeroMem (&Packet, sizeof (Packet));\r
+  Packet.SdMmcCmdBlk    = &SdMmcCmdBlk;\r
+  Packet.SdMmcStatusBlk = &SdMmcStatusBlk;\r
+  Packet.Timeout        = SD_GENERIC_TIMEOUT;\r
+\r
+  SdMmcCmdBlk.CommandIndex = SD_SEND_STATUS;\r
+  SdMmcCmdBlk.CommandType  = SdMmcCommandTypeAc;\r
+  SdMmcCmdBlk.ResponseType = SdMmcResponseTypeR1;\r
+  SdMmcCmdBlk.CommandArgument = (UINT32)Rca << 16;\r
+\r
+  Status = PassThru->PassThru (PassThru, Device->Slot, &Packet, NULL);\r
+  if (!EFI_ERROR (Status)) {\r
+    CopyMem (DevStatus, &SdMmcStatusBlk.Resp0, sizeof (UINT32));\r
+  }\r
+  return Status;\r
+}\r
+\r
+/**\r
+  Send command SEND_CSD to the device to get the CSD register data.\r
+\r
+  @param[in]  Device            A pointer to the SD_DEVICE instance.\r
+  @param[in]  Rca               The relative device address to use.\r
+  @param[out] Csd               The buffer to store the SD_CSD register data.\r
+\r
+  @retval EFI_SUCCESS           The request is executed successfully.\r
+  @retval EFI_OUT_OF_RESOURCES  The request could not be executed due to a lack of resources.\r
+  @retval Others                The request could not be executed successfully.\r
+\r
+**/\r
+EFI_STATUS\r
+SdGetCsd (\r
+  IN     SD_DEVICE              *Device,\r
+  IN     UINT16                 Rca,\r
+     OUT SD_CSD                 *Csd\r
+  )\r
+{\r
+  EFI_STATUS                           Status;\r
+  EFI_SD_MMC_PASS_THRU_PROTOCOL        *PassThru;\r
+  EFI_SD_MMC_COMMAND_BLOCK             SdMmcCmdBlk;\r
+  EFI_SD_MMC_STATUS_BLOCK              SdMmcStatusBlk;\r
+  EFI_SD_MMC_PASS_THRU_COMMAND_PACKET  Packet;\r
+\r
+  PassThru = Device->Private->PassThru;\r
+\r
+  ZeroMem (&SdMmcCmdBlk, sizeof (SdMmcCmdBlk));\r
+  ZeroMem (&SdMmcStatusBlk, sizeof (SdMmcStatusBlk));\r
+  ZeroMem (&Packet, sizeof (Packet));\r
+  ZeroMem (Csd, sizeof (SD_CSD));\r
+\r
+  Packet.SdMmcCmdBlk    = &SdMmcCmdBlk;\r
+  Packet.SdMmcStatusBlk = &SdMmcStatusBlk;\r
+  Packet.Timeout        = SD_GENERIC_TIMEOUT;\r
+\r
+  SdMmcCmdBlk.CommandIndex = SD_SEND_CSD;\r
+  SdMmcCmdBlk.CommandType  = SdMmcCommandTypeAc;\r
+  SdMmcCmdBlk.ResponseType = SdMmcResponseTypeR2;\r
+  SdMmcCmdBlk.CommandArgument = (UINT32)Rca << 16;\r
+\r
+  Status = PassThru->PassThru (PassThru, Device->Slot, &Packet, NULL);\r
+\r
+  if (!EFI_ERROR (Status)) {\r
+    //\r
+    // For details, refer to SD Host Controller Simplified Spec 3.0 Table 2-12.\r
+    //\r
+    CopyMem (((UINT8*)Csd) + 1, &SdMmcStatusBlk.Resp0, sizeof (SD_CSD) - 1);\r
+  }\r
+\r
+  return Status;\r
+}\r
+\r
+/**\r
+  Send command SEND_CID to the device to get the CID register data.\r
+\r
+  @param[in]  Device            A pointer to the SD_DEVICE instance.\r
+  @param[in]  Rca               The relative device address to use.\r
+  @param[out] Cid               The buffer to store the SD_CID register data.\r
+\r
+  @retval EFI_SUCCESS           The request is executed successfully.\r
+  @retval EFI_OUT_OF_RESOURCES  The request could not be executed due to a lack of resources.\r
+  @retval Others                The request could not be executed successfully.\r
+\r
+**/\r
+EFI_STATUS\r
+SdGetCid (\r
+  IN     SD_DEVICE              *Device,\r
+  IN     UINT16                 Rca,\r
+     OUT SD_CID                 *Cid\r
+  )\r
+{\r
+  EFI_STATUS                           Status;\r
+  EFI_SD_MMC_PASS_THRU_PROTOCOL        *PassThru;\r
+  EFI_SD_MMC_COMMAND_BLOCK             SdMmcCmdBlk;\r
+  EFI_SD_MMC_STATUS_BLOCK              SdMmcStatusBlk;\r
+  EFI_SD_MMC_PASS_THRU_COMMAND_PACKET  Packet;\r
+\r
+  PassThru = Device->Private->PassThru;\r
+\r
+  ZeroMem (&SdMmcCmdBlk, sizeof (SdMmcCmdBlk));\r
+  ZeroMem (&SdMmcStatusBlk, sizeof (SdMmcStatusBlk));\r
+  ZeroMem (&Packet, sizeof (Packet));\r
+  ZeroMem (Cid, sizeof (SD_CID));\r
+\r
+  Packet.SdMmcCmdBlk    = &SdMmcCmdBlk;\r
+  Packet.SdMmcStatusBlk = &SdMmcStatusBlk;\r
+  Packet.Timeout        = SD_GENERIC_TIMEOUT;\r
+\r
+  SdMmcCmdBlk.CommandIndex = SD_SEND_CID;\r
+  SdMmcCmdBlk.CommandType  = SdMmcCommandTypeAc;\r
+  SdMmcCmdBlk.ResponseType = SdMmcResponseTypeR2;\r
+  SdMmcCmdBlk.CommandArgument = (UINT32)Rca << 16;\r
+\r
+  Status = PassThru->PassThru (PassThru, Device->Slot, &Packet, NULL);\r
+\r
+  if (!EFI_ERROR (Status)) {\r
+    //\r
+    // For details, refer to SD Host Controller Simplified Spec 3.0 Table 2-12.\r
+    //\r
+    CopyMem (((UINT8*)Cid) + 1, &SdMmcStatusBlk.Resp0, sizeof (SD_CID) - 1);\r
+  }\r
+\r
+  return Status;\r
+}\r
+\r
+/**\r
+  Read/write single block through sync or async I/O request.\r
+\r
+  @param[in]  Device            A pointer to the SD_DEVICE instance.\r
+  @param[in]  Lba               The starting logical block address to be read/written.\r
+                                The caller is responsible for reading/writing to only\r
+                                legitimate locations.\r
+  @param[in]  Buffer            A pointer to the destination/source buffer for the data.\r
+  @param[in]  BufferSize        Size of Buffer, must be a multiple of device block size.\r
+  @param[in]  IsRead            Indicates it is a read or write operation.\r
+  @param[in]  Token             A pointer to the token associated with the transaction.\r
+  @param[in]  IsEnd             A boolean to show whether it's the last cmd in a series of cmds.\r
+                                This parameter is only meaningful in async I/O request.\r
+\r
+  @retval EFI_SUCCESS           The request is executed successfully.\r
+  @retval EFI_OUT_OF_RESOURCES  The request could not be executed due to a lack of resources.\r
+  @retval Others                The request could not be executed successfully.\r
+\r
+**/\r
+EFI_STATUS\r
+SdRwSingleBlock (\r
+  IN  SD_DEVICE                 *Device,\r
+  IN  EFI_LBA                   Lba,\r
+  IN  VOID                      *Buffer,\r
+  IN  UINTN                     BufferSize,\r
+  IN  BOOLEAN                   IsRead,\r
+  IN  EFI_BLOCK_IO2_TOKEN       *Token,\r
+  IN  BOOLEAN                   IsEnd\r
+  )\r
+{\r
+  EFI_STATUS                           Status;\r
+  EFI_SD_MMC_PASS_THRU_PROTOCOL        *PassThru;\r
+  SD_REQUEST                           *RwSingleBlkReq;\r
+  EFI_TPL                              OldTpl;\r
+\r
+  RwSingleBlkReq = NULL;\r
+  PassThru       = Device->Private->PassThru;\r
+\r
+  RwSingleBlkReq = AllocateZeroPool (sizeof (SD_REQUEST));\r
+  if (RwSingleBlkReq == NULL) {\r
+    Status = EFI_OUT_OF_RESOURCES;\r
+    goto Error;\r
+  }\r
+\r
+  RwSingleBlkReq->Signature = SD_REQUEST_SIGNATURE;\r
+  OldTpl = gBS->RaiseTPL (TPL_CALLBACK);\r
+  InsertTailList (&Device->Queue, &RwSingleBlkReq->Link);\r
+  gBS->RestoreTPL (OldTpl);\r
+  RwSingleBlkReq->Packet.SdMmcCmdBlk    = &RwSingleBlkReq->SdMmcCmdBlk;\r
+  RwSingleBlkReq->Packet.SdMmcStatusBlk = &RwSingleBlkReq->SdMmcStatusBlk;\r
+  //\r
+  // Calculate timeout value through the below formula.\r
+  // Timeout = (transfer size) / (2MB/s).\r
+  // Taking 2MB/s as divisor as it's the lowest transfer speed\r
+  // above class 2.\r
+  // Refer to SD Physical Layer Simplified spec section 3.4 for details.\r
+  //\r
+  RwSingleBlkReq->Packet.Timeout = (BufferSize / (2 * 1024 * 1024) + 1) * 1000 * 1000;\r
+\r
+  if (IsRead) {\r
+    RwSingleBlkReq->Packet.InDataBuffer     = Buffer;\r
+    RwSingleBlkReq->Packet.InTransferLength = (UINT32)BufferSize;\r
+\r
+    RwSingleBlkReq->SdMmcCmdBlk.CommandIndex = SD_READ_SINGLE_BLOCK;\r
+    RwSingleBlkReq->SdMmcCmdBlk.CommandType  = SdMmcCommandTypeAdtc;\r
+    RwSingleBlkReq->SdMmcCmdBlk.ResponseType = SdMmcResponseTypeR1;\r
+  } else {\r
+    RwSingleBlkReq->Packet.OutDataBuffer     = Buffer;\r
+    RwSingleBlkReq->Packet.OutTransferLength = (UINT32)BufferSize;\r
+\r
+    RwSingleBlkReq->SdMmcCmdBlk.CommandIndex = SD_WRITE_SINGLE_BLOCK;\r
+    RwSingleBlkReq->SdMmcCmdBlk.CommandType  = SdMmcCommandTypeAdtc;\r
+    RwSingleBlkReq->SdMmcCmdBlk.ResponseType = SdMmcResponseTypeR1;\r
+  }\r
+\r
+  if (Device->SectorAddressing) {\r
+    RwSingleBlkReq->SdMmcCmdBlk.CommandArgument = (UINT32)Lba;\r
+  } else {\r
+    RwSingleBlkReq->SdMmcCmdBlk.CommandArgument = (UINT32)MultU64x32 (Lba, Device->BlockMedia.BlockSize);\r
+  }\r
+\r
+  RwSingleBlkReq->IsEnd = IsEnd;\r
+  RwSingleBlkReq->Token = Token;\r
+\r
+  if ((Token != NULL) && (Token->Event != NULL)) {\r
+    Status = gBS->CreateEvent (\r
+                    EVT_NOTIFY_SIGNAL,\r
+                    TPL_CALLBACK,\r
+                    AsyncIoCallback,\r
+                    RwSingleBlkReq,\r
+                    &RwSingleBlkReq->Event\r
+                    );\r
+    if (EFI_ERROR (Status)) {\r
+      goto Error;\r
+    }\r
+  } else {\r
+    RwSingleBlkReq->Event = NULL;\r
+  }\r
+\r
+  Status = PassThru->PassThru (PassThru, Device->Slot, &RwSingleBlkReq->Packet, RwSingleBlkReq->Event);\r
+\r
+Error:\r
+  if ((Token != NULL) && (Token->Event != NULL)) {\r
+    //\r
+    // For asynchronous operation, only free request and event in error case.\r
+    // The request and event will be freed in asynchronous callback for success case.\r
+    //\r
+    if (EFI_ERROR (Status) && (RwSingleBlkReq != NULL)) {\r
+      RemoveEntryList (&RwSingleBlkReq->Link);\r
+      if (RwSingleBlkReq->Event != NULL) {\r
+        gBS->CloseEvent (RwSingleBlkReq->Event);\r
+      }\r
+      FreePool (RwSingleBlkReq);\r
+    }\r
+  } else {\r
+    //\r
+    // For synchronous operation, free request whatever the execution result is.\r
+    //\r
+    if (RwSingleBlkReq != NULL) {\r
+      RemoveEntryList (&RwSingleBlkReq->Link);\r
+      FreePool (RwSingleBlkReq);\r
+    }\r
+  }\r
+\r
+  return Status;\r
+}\r
+\r
+/**\r
+  Read/write multiple blocks through sync or async I/O request.\r
+\r
+  @param[in]  Device            A pointer to the SD_DEVICE instance.\r
+  @param[in]  Lba               The starting logical block address to be read/written.\r
+                                The caller is responsible for reading/writing to only\r
+                                legitimate locations.\r
+  @param[in]  Buffer            A pointer to the destination/source buffer for the data.\r
+  @param[in]  BufferSize        Size of Buffer, must be a multiple of device block size.\r
+  @param[in]  IsRead            Indicates it is a read or write operation.\r
+  @param[in]  Token             A pointer to the token associated with the transaction.\r
+  @param[in]  IsEnd             A boolean to show whether it's the last cmd in a series of cmds.\r
+                                This parameter is only meaningful in async I/O request.\r
+\r
+  @retval EFI_SUCCESS           The request is executed successfully.\r
+  @retval EFI_OUT_OF_RESOURCES  The request could not be executed due to a lack of resources.\r
+  @retval Others                The request could not be executed successfully.\r
+\r
+**/\r
+EFI_STATUS\r
+SdRwMultiBlocks (\r
+  IN  SD_DEVICE                 *Device,\r
+  IN  EFI_LBA                   Lba,\r
+  IN  VOID                      *Buffer,\r
+  IN  UINTN                     BufferSize,\r
+  IN  BOOLEAN                   IsRead,\r
+  IN  EFI_BLOCK_IO2_TOKEN       *Token,\r
+  IN  BOOLEAN                   IsEnd\r
+  )\r
+{\r
+  EFI_STATUS                    Status;\r
+  SD_REQUEST                    *RwMultiBlkReq;\r
+  EFI_SD_MMC_PASS_THRU_PROTOCOL *PassThru;\r
+  EFI_TPL                       OldTpl;\r
+\r
+  RwMultiBlkReq = NULL;\r
+\r
+  PassThru = Device->Private->PassThru;\r
+\r
+  RwMultiBlkReq = AllocateZeroPool (sizeof (SD_REQUEST));\r
+  if (RwMultiBlkReq == NULL) {\r
+    Status = EFI_OUT_OF_RESOURCES;\r
+    goto Error;\r
+  }\r
+\r
+  RwMultiBlkReq->Signature = SD_REQUEST_SIGNATURE;\r
+  OldTpl = gBS->RaiseTPL (TPL_CALLBACK);\r
+  InsertTailList (&Device->Queue, &RwMultiBlkReq->Link);\r
+  gBS->RestoreTPL (OldTpl);\r
+  RwMultiBlkReq->Packet.SdMmcCmdBlk    = &RwMultiBlkReq->SdMmcCmdBlk;\r
+  RwMultiBlkReq->Packet.SdMmcStatusBlk = &RwMultiBlkReq->SdMmcStatusBlk;\r
+  //\r
+  // Calculate timeout value through the below formula.\r
+  // Timeout = (transfer size) / (2MB/s).\r
+  // Taking 2MB/s as divisor as it's the lowest transfer speed\r
+  // above class 2.\r
+  // Refer to SD Physical Layer Simplified spec section 3.4 for details.\r
+  //\r
+  RwMultiBlkReq->Packet.Timeout = (BufferSize / (2 * 1024 * 1024) + 1) * 1000 * 1000;\r
+\r
+  if (IsRead) {\r
+    RwMultiBlkReq->Packet.InDataBuffer     = Buffer;\r
+    RwMultiBlkReq->Packet.InTransferLength = (UINT32)BufferSize;\r
+\r
+    RwMultiBlkReq->SdMmcCmdBlk.CommandIndex = SD_READ_MULTIPLE_BLOCK;\r
+    RwMultiBlkReq->SdMmcCmdBlk.CommandType  = SdMmcCommandTypeAdtc;\r
+    RwMultiBlkReq->SdMmcCmdBlk.ResponseType = SdMmcResponseTypeR1;\r
+  } else {\r
+    RwMultiBlkReq->Packet.OutDataBuffer     = Buffer;\r
+    RwMultiBlkReq->Packet.OutTransferLength = (UINT32)BufferSize;\r
+\r
+    RwMultiBlkReq->SdMmcCmdBlk.CommandIndex = SD_WRITE_MULTIPLE_BLOCK;\r
+    RwMultiBlkReq->SdMmcCmdBlk.CommandType  = SdMmcCommandTypeAdtc;\r
+    RwMultiBlkReq->SdMmcCmdBlk.ResponseType = SdMmcResponseTypeR1;\r
+  }\r
+\r
+  if (Device->SectorAddressing) {\r
+    RwMultiBlkReq->SdMmcCmdBlk.CommandArgument = (UINT32)Lba;\r
+  } else {\r
+    RwMultiBlkReq->SdMmcCmdBlk.CommandArgument = (UINT32)MultU64x32 (Lba, Device->BlockMedia.BlockSize);\r
+  }\r
+\r
+  RwMultiBlkReq->IsEnd = IsEnd;\r
+  RwMultiBlkReq->Token = Token;\r
+\r
+  if ((Token != NULL) && (Token->Event != NULL)) {\r
+    Status = gBS->CreateEvent (\r
+                    EVT_NOTIFY_SIGNAL,\r
+                    TPL_CALLBACK,\r
+                    AsyncIoCallback,\r
+                    RwMultiBlkReq,\r
+                    &RwMultiBlkReq->Event\r
+                    );\r
+    if (EFI_ERROR (Status)) {\r
+      goto Error;\r
+    }\r
+  } else {\r
+    RwMultiBlkReq->Event = NULL;\r
+  }\r
+\r
+  Status = PassThru->PassThru (PassThru, Device->Slot, &RwMultiBlkReq->Packet, RwMultiBlkReq->Event);\r
+\r
+Error:\r
+  if ((Token != NULL) && (Token->Event != NULL)) {\r
+    //\r
+    // For asynchronous operation, only free request and event in error case.\r
+    // The request and event will be freed in asynchronous callback for success case.\r
+    //\r
+    if (EFI_ERROR (Status) && (RwMultiBlkReq != NULL)) {\r
+      RemoveEntryList (&RwMultiBlkReq->Link);\r
+      if (RwMultiBlkReq->Event != NULL) {\r
+        gBS->CloseEvent (RwMultiBlkReq->Event);\r
+      }\r
+      FreePool (RwMultiBlkReq);\r
+    }\r
+  } else {\r
+    //\r
+    // For synchronous operation, free request whatever the execution result is.\r
+    //\r
+    if (RwMultiBlkReq != NULL) {\r
+      RemoveEntryList (&RwMultiBlkReq->Link);\r
+      FreePool (RwMultiBlkReq);\r
+    }\r
+  }\r
+\r
+  return Status;\r
+}\r
+\r
+/**\r
+  This function transfers data from/to the sd memory card device.\r
+\r
+  @param[in]       Device       A pointer to the SD_DEVICE instance.\r
+  @param[in]       MediaId      The media ID that the read/write request is for.\r
+  @param[in]       Lba          The starting logical block address to be read/written.\r
+                                The caller is responsible for reading/writing to only\r
+                                legitimate locations.\r
+  @param[in, out]  Buffer       A pointer to the destination/source buffer for the data.\r
+  @param[in]       BufferSize   Size of Buffer, must be a multiple of device block size.\r
+  @param[in]       IsRead       Indicates it is a read or write operation.\r
+  @param[in, out]  Token        A pointer to the token associated with the transaction.\r
+\r
+  @retval EFI_SUCCESS           The data was read/written correctly to the device.\r
+  @retval EFI_WRITE_PROTECTED   The device can not be read/written to.\r
+  @retval EFI_DEVICE_ERROR      The device reported an error while performing the read/write.\r
+  @retval EFI_NO_MEDIA          There is no media in the device.\r
+  @retval EFI_MEDIA_CHNAGED     The MediaId does not matched the current device.\r
+  @retval EFI_BAD_BUFFER_SIZE   The Buffer was not a multiple of the block size of the device.\r
+  @retval EFI_INVALID_PARAMETER The read/write request contains LBAs that are not valid,\r
+                                or the buffer is not on proper alignment.\r
+\r
+**/\r
+EFI_STATUS\r
+SdReadWrite (\r
+  IN     SD_DEVICE                      *Device,\r
+  IN     UINT32                         MediaId,\r
+  IN     EFI_LBA                        Lba,\r
+  IN OUT VOID                           *Buffer,\r
+  IN     UINTN                          BufferSize,\r
+  IN     BOOLEAN                        IsRead,\r
+  IN OUT EFI_BLOCK_IO2_TOKEN            *Token\r
+  )\r
+{\r
+  EFI_STATUS                            Status;\r
+  EFI_BLOCK_IO_MEDIA                    *Media;\r
+  UINTN                                 BlockSize;\r
+  UINTN                                 BlockNum;\r
+  UINTN                                 IoAlign;\r
+  UINTN                                 Remaining;\r
+  UINT32                                MaxBlock;\r
+  BOOLEAN                               LastRw;\r
+\r
+  Status = EFI_SUCCESS;\r
+  Media  = &Device->BlockMedia;\r
+  LastRw = FALSE;\r
+\r
+  if (MediaId != Media->MediaId) {\r
+    return EFI_MEDIA_CHANGED;\r
+  }\r
+\r
+  if (!IsRead && Media->ReadOnly) {\r
+    return EFI_WRITE_PROTECTED;\r
+  }\r
+\r
+  //\r
+  // Check parameters.\r
+  //\r
+  if (Buffer == NULL) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  if (BufferSize == 0) {\r
+    if ((Token != NULL) && (Token->Event != NULL)) {\r
+      Token->TransactionStatus = EFI_SUCCESS;\r
+      gBS->SignalEvent (Token->Event);\r
+    }\r
+    return EFI_SUCCESS;\r
+  }\r
+\r
+  BlockSize = Media->BlockSize;\r
+  if ((BufferSize % BlockSize) != 0) {\r
+    return EFI_BAD_BUFFER_SIZE;\r
+  }\r
+\r
+  BlockNum  = BufferSize / BlockSize;\r
+  if ((Lba + BlockNum - 1) > Media->LastBlock) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  IoAlign = Media->IoAlign;\r
+  if (IoAlign > 0 && (((UINTN) Buffer & (IoAlign - 1)) != 0)) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  if ((Token != NULL) && (Token->Event != NULL)) {\r
+    Token->TransactionStatus = EFI_SUCCESS;\r
+  }\r
+\r
+  //\r
+  // Start to execute data transfer. The max block number in single cmd is 65535 blocks.\r
+  //\r
+  Remaining = BlockNum;\r
+  MaxBlock  = 0xFFFF;\r
+\r
+  while (Remaining > 0) {\r
+    if (Remaining <= MaxBlock) {\r
+      BlockNum = Remaining;\r
+      LastRw   = TRUE;\r
+    } else {\r
+      BlockNum = MaxBlock;\r
+    }\r
+\r
+    BufferSize = BlockNum * BlockSize;\r
+    if (BlockNum == 1) {\r
+      Status = SdRwSingleBlock (Device, Lba, Buffer, BufferSize, IsRead, Token, LastRw);\r
+    } else {\r
+      Status = SdRwMultiBlocks (Device, Lba, Buffer, BufferSize, IsRead, Token, LastRw);\r
+    }\r
+    if (EFI_ERROR (Status)) {\r
+      return Status;\r
+    }\r
+    DEBUG ((EFI_D_INFO, "Sd%a(): Lba 0x%x BlkNo 0x%x Event %p with %r\n", IsRead ? "Read" : "Write", Lba, BlockNum, Token->Event, Status));\r
+\r
+    Lba   += BlockNum;\r
+    Buffer = (UINT8*)Buffer + BufferSize;\r
+    Remaining -= BlockNum;\r
+  }\r
+\r
+  return Status;\r
+}\r
+\r
+/**\r
+  Reset the Block Device.\r
+\r
+  @param  This                 Indicates a pointer to the calling context.\r
+  @param  ExtendedVerification Driver may perform diagnostics on reset.\r
+\r
+  @retval EFI_SUCCESS          The device was reset.\r
+  @retval EFI_DEVICE_ERROR     The device is not functioning properly and could\r
+                               not be reset.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+SdReset (\r
+  IN  EFI_BLOCK_IO_PROTOCOL     *This,\r
+  IN  BOOLEAN                   ExtendedVerification\r
+  )\r
+{\r
+  EFI_STATUS                    Status;\r
+  SD_DEVICE                     *Device;\r
+  EFI_SD_MMC_PASS_THRU_PROTOCOL *PassThru;\r
+\r
+  Device = SD_DEVICE_DATA_FROM_BLKIO (This);\r
+\r
+  PassThru = Device->Private->PassThru;\r
+  Status   = PassThru->ResetDevice (PassThru, Device->Slot);\r
+  if (EFI_ERROR (Status)) {\r
+    Status = EFI_DEVICE_ERROR;\r
+  }\r
+\r
+  return Status;\r
+}\r
+\r
+/**\r
+  Read BufferSize bytes from Lba into Buffer.\r
+\r
+  @param  This       Indicates a pointer to the calling context.\r
+  @param  MediaId    Id of the media, changes every time the media is replaced.\r
+  @param  Lba        The starting Logical Block Address to read from\r
+  @param  BufferSize Size of Buffer, must be a multiple of device block size.\r
+  @param  Buffer     A pointer to the destination buffer for the data. The caller is\r
+                     responsible for either having implicit or explicit ownership of the buffer.\r
+\r
+  @retval EFI_SUCCESS           The data was read correctly from the device.\r
+  @retval EFI_DEVICE_ERROR      The device reported an error while performing the read.\r
+  @retval EFI_NO_MEDIA          There is no media in the device.\r
+  @retval EFI_MEDIA_CHANGED     The MediaId does not matched the current device.\r
+  @retval EFI_BAD_BUFFER_SIZE   The Buffer was not a multiple of the block size of the device.\r
+  @retval EFI_INVALID_PARAMETER The read request contains LBAs that are not valid,\r
+                                or the buffer is not on proper alignment.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+SdReadBlocks (\r
+  IN     EFI_BLOCK_IO_PROTOCOL  *This,\r
+  IN     UINT32                 MediaId,\r
+  IN     EFI_LBA                Lba,\r
+  IN     UINTN                  BufferSize,\r
+     OUT VOID                   *Buffer\r
+  )\r
+{\r
+  EFI_STATUS             Status;\r
+  SD_DEVICE              *Device;\r
+\r
+  Device = SD_DEVICE_DATA_FROM_BLKIO (This);\r
+\r
+  Status = SdReadWrite (Device, MediaId, Lba, Buffer, BufferSize, TRUE, NULL);\r
+  return Status;\r
+}\r
+\r
+/**\r
+  Write BufferSize bytes from Lba into Buffer.\r
+\r
+  @param  This       Indicates a pointer to the calling context.\r
+  @param  MediaId    The media ID that the write request is for.\r
+  @param  Lba        The starting logical block address to be written. The caller is\r
+                     responsible for writing to only legitimate locations.\r
+  @param  BufferSize Size of Buffer, must be a multiple of device block size.\r
+  @param  Buffer     A pointer to the source buffer for the data.\r
+\r
+  @retval EFI_SUCCESS           The data was written correctly to the device.\r
+  @retval EFI_WRITE_PROTECTED   The device can not be written to.\r
+  @retval EFI_DEVICE_ERROR      The device reported an error while performing the write.\r
+  @retval EFI_NO_MEDIA          There is no media in the device.\r
+  @retval EFI_MEDIA_CHNAGED     The MediaId does not matched the current device.\r
+  @retval EFI_BAD_BUFFER_SIZE   The Buffer was not a multiple of the block size of the device.\r
+  @retval EFI_INVALID_PARAMETER The write request contains LBAs that are not valid,\r
+                                or the buffer is not on proper alignment.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+SdWriteBlocks (\r
+  IN  EFI_BLOCK_IO_PROTOCOL   *This,\r
+  IN  UINT32                  MediaId,\r
+  IN  EFI_LBA                 Lba,\r
+  IN  UINTN                   BufferSize,\r
+  IN  VOID                    *Buffer\r
+  )\r
+{\r
+  EFI_STATUS             Status;\r
+  SD_DEVICE              *Device;\r
+\r
+  Device = SD_DEVICE_DATA_FROM_BLKIO (This);\r
+\r
+  Status = SdReadWrite (Device, MediaId, Lba, Buffer, BufferSize, FALSE, NULL);\r
+  return Status;\r
+}\r
+\r
+/**\r
+  Flush the Block Device.\r
+\r
+  @param  This              Indicates a pointer to the calling context.\r
+\r
+  @retval EFI_SUCCESS       All outstanding data was written to the device\r
+  @retval EFI_DEVICE_ERROR  The device reported an error while writing back the data\r
+  @retval EFI_NO_MEDIA      There is no media in the device.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+SdFlushBlocks (\r
+  IN  EFI_BLOCK_IO_PROTOCOL   *This\r
+  )\r
+{\r
+  //\r
+  // return directly\r
+  //\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+  Reset the Block Device.\r
+\r
+  @param[in]  This                 Indicates a pointer to the calling context.\r
+  @param[in]  ExtendedVerification Driver may perform diagnostics on reset.\r
+\r
+  @retval EFI_SUCCESS              The device was reset.\r
+  @retval EFI_DEVICE_ERROR         The device is not functioning properly and could\r
+                                   not be reset.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+SdResetEx (\r
+  IN  EFI_BLOCK_IO2_PROTOCOL  *This,\r
+  IN  BOOLEAN                 ExtendedVerification\r
+  )\r
+{\r
+  SD_DEVICE                   *Device;\r
+  LIST_ENTRY                  *Link;\r
+  LIST_ENTRY                  *NextLink;\r
+  SD_REQUEST                  *Request;\r
+  EFI_TPL                     OldTpl;\r
+\r
+  Device = SD_DEVICE_DATA_FROM_BLKIO2 (This);\r
+\r
+  OldTpl = gBS->RaiseTPL (TPL_CALLBACK);\r
+  for (Link = GetFirstNode (&Device->Queue);\r
+       !IsNull (&Device->Queue, Link);\r
+       Link = NextLink) {\r
+    NextLink = GetNextNode (&Device->Queue, Link);\r
+    RemoveEntryList (Link);\r
+\r
+    Request = SD_REQUEST_FROM_LINK (Link);\r
+\r
+    gBS->CloseEvent (Request->Event);\r
+    Request->Token->TransactionStatus = EFI_ABORTED;\r
+\r
+    if (Request->IsEnd) {\r
+      gBS->SignalEvent (Request->Token->Event);\r
+    }\r
+\r
+    FreePool (Request);\r
+  }\r
+  gBS->RestoreTPL (OldTpl);\r
+\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+  Read BufferSize bytes from Lba into Buffer.\r
+\r
+  @param[in]       This         Indicates a pointer to the calling context.\r
+  @param[in]       MediaId      Id of the media, changes every time the media is replaced.\r
+  @param[in]       Lba          The starting Logical Block Address to read from.\r
+  @param[in, out]  Token        A pointer to the token associated with the transaction.\r
+  @param[in]       BufferSize   Size of Buffer, must be a multiple of device block size.\r
+  @param[out]      Buffer       A pointer to the destination buffer for the data. The caller is\r
+                                responsible for either having implicit or explicit ownership of the buffer.\r
+\r
+  @retval EFI_SUCCESS           The read request was queued if Event is not NULL.\r
+                                The data was read correctly from the device if\r
+                                the Event is NULL.\r
+  @retval EFI_DEVICE_ERROR      The device reported an error while performing\r
+                                the read.\r
+  @retval EFI_NO_MEDIA          There is no media in the device.\r
+  @retval EFI_MEDIA_CHANGED     The MediaId is not for the current media.\r
+  @retval EFI_BAD_BUFFER_SIZE   The BufferSize parameter is not a multiple of the\r
+                                intrinsic block size of the device.\r
+  @retval EFI_INVALID_PARAMETER The read request contains LBAs that are not valid,\r
+                                or the buffer is not on proper alignment.\r
+  @retval EFI_OUT_OF_RESOURCES  The request could not be completed due to a lack\r
+                                of resources.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+SdReadBlocksEx (\r
+  IN     EFI_BLOCK_IO2_PROTOCOL *This,\r
+  IN     UINT32                 MediaId,\r
+  IN     EFI_LBA                Lba,\r
+  IN OUT EFI_BLOCK_IO2_TOKEN    *Token,\r
+  IN     UINTN                  BufferSize,\r
+     OUT VOID                   *Buffer\r
+  )\r
+{\r
+  EFI_STATUS             Status;\r
+  SD_DEVICE              *Device;\r
+\r
+  Device = SD_DEVICE_DATA_FROM_BLKIO2 (This);\r
+\r
+  Status = SdReadWrite (Device, MediaId, Lba, Buffer, BufferSize, TRUE, Token);\r
+  return Status;\r
+}\r
+\r
+/**\r
+  Write BufferSize bytes from Lba into Buffer.\r
+\r
+  @param[in]       This         Indicates a pointer to the calling context.\r
+  @param[in]       MediaId      The media ID that the write request is for.\r
+  @param[in]       Lba          The starting logical block address to be written. The\r
+                                caller is responsible for writing to only legitimate\r
+                                locations.\r
+  @param[in, out]  Token        A pointer to the token associated with the transaction.\r
+  @param[in]       BufferSize   Size of Buffer, must be a multiple of device block size.\r
+  @param[in]       Buffer       A pointer to the source buffer for the data.\r
+\r
+  @retval EFI_SUCCESS           The data was written correctly to the device.\r
+  @retval EFI_WRITE_PROTECTED   The device can not be written to.\r
+  @retval EFI_DEVICE_ERROR      The device reported an error while performing the write.\r
+  @retval EFI_NO_MEDIA          There is no media in the device.\r
+  @retval EFI_MEDIA_CHNAGED     The MediaId does not matched the current device.\r
+  @retval EFI_BAD_BUFFER_SIZE   The Buffer was not a multiple of the block size of the device.\r
+  @retval EFI_INVALID_PARAMETER The write request contains LBAs that are not valid,\r
+                                or the buffer is not on proper alignment.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+SdWriteBlocksEx (\r
+  IN     EFI_BLOCK_IO2_PROTOCOL *This,\r
+  IN     UINT32                 MediaId,\r
+  IN     EFI_LBA                Lba,\r
+  IN OUT EFI_BLOCK_IO2_TOKEN    *Token,\r
+  IN     UINTN                  BufferSize,\r
+  IN     VOID                   *Buffer\r
+  )\r
+{\r
+  EFI_STATUS             Status;\r
+  SD_DEVICE              *Device;\r
+\r
+  Device = SD_DEVICE_DATA_FROM_BLKIO2 (This);\r
+\r
+  Status = SdReadWrite (Device, MediaId, Lba, Buffer, BufferSize, FALSE, Token);\r
+  return Status;\r
+}\r
+\r
+/**\r
+  Flush the Block Device.\r
+\r
+  @param[in]       This     Indicates a pointer to the calling context.\r
+  @param[in, out]  Token    A pointer to the token associated with the transaction.\r
+\r
+  @retval EFI_SUCCESS       All outstanding data was written to the device\r
+  @retval EFI_DEVICE_ERROR  The device reported an error while writing back the data\r
+  @retval EFI_NO_MEDIA      There is no media in the device.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+SdFlushBlocksEx (\r
+  IN     EFI_BLOCK_IO2_PROTOCOL  *This,\r
+  IN OUT EFI_BLOCK_IO2_TOKEN     *Token\r
+  )\r
+{\r
+  //\r
+  // Signal event and return directly.\r
+  //\r
+  if (Token != NULL && Token->Event != NULL) {\r
+    Token->TransactionStatus = EFI_SUCCESS;\r
+    gBS->SignalEvent (Token->Event);\r
+  }\r
+\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+\r
diff --git a/MdeModulePkg/Bus/Sd/SdDxe/SdBlockIo.h b/MdeModulePkg/Bus/Sd/SdDxe/SdBlockIo.h
new file mode 100644 (file)
index 0000000..36e20de
--- /dev/null
@@ -0,0 +1,221 @@
+/** @file\r
+  Header file for SdDxe Driver.\r
+\r
+  This file defines common data structures, macro definitions and some module\r
+  internal function header files.\r
+\r
+  Copyright (c) 2015, Intel Corporation. All rights reserved.<BR>\r
+  This program and the accompanying materials\r
+  are licensed and made available under the terms and conditions of the BSD License\r
+  which accompanies this distribution.  The full text of the license may be found at\r
+  http://opensource.org/licenses/bsd-license.php\r
+\r
+  THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+  WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+\r
+**/\r
+\r
+#ifndef _SD_BLOCK_IO_H_\r
+#define _SD_BLOCK_IO_H_\r
+\r
+/**\r
+  Reset the Block Device.\r
+\r
+  @param  This                 Indicates a pointer to the calling context.\r
+  @param  ExtendedVerification Driver may perform diagnostics on reset.\r
+\r
+  @retval EFI_SUCCESS          The device was reset.\r
+  @retval EFI_DEVICE_ERROR     The device is not functioning properly and could\r
+                               not be reset.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+SdReset (\r
+  IN  EFI_BLOCK_IO_PROTOCOL   *This,\r
+  IN  BOOLEAN                 ExtendedVerification\r
+  );\r
+\r
+/**\r
+  Read BufferSize bytes from Lba into Buffer.\r
+\r
+  @param  This       Indicates a pointer to the calling context.\r
+  @param  MediaId    Id of the media, changes every time the media is replaced.\r
+  @param  Lba        The starting Logical Block Address to read from\r
+  @param  BufferSize Size of Buffer, must be a multiple of device block size.\r
+  @param  Buffer     A pointer to the destination buffer for the data. The caller is\r
+                     responsible for either having implicit or explicit ownership of the buffer.\r
+\r
+  @retval EFI_SUCCESS           The data was read correctly from the device.\r
+  @retval EFI_DEVICE_ERROR      The device reported an error while performing the read.\r
+  @retval EFI_NO_MEDIA          There is no media in the device.\r
+  @retval EFI_MEDIA_CHANGED     The MediaId does not matched the current device.\r
+  @retval EFI_BAD_BUFFER_SIZE   The Buffer was not a multiple of the block size of the device.\r
+  @retval EFI_INVALID_PARAMETER The read request contains LBAs that are not valid,\r
+                                or the buffer is not on proper alignment.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+SdReadBlocks (\r
+  IN     EFI_BLOCK_IO_PROTOCOL  *This,\r
+  IN     UINT32                 MediaId,\r
+  IN     EFI_LBA                Lba,\r
+  IN     UINTN                  BufferSize,\r
+     OUT VOID                   *Buffer\r
+  );\r
+\r
+/**\r
+  Write BufferSize bytes from Lba into Buffer.\r
+\r
+  @param  This       Indicates a pointer to the calling context.\r
+  @param  MediaId    The media ID that the write request is for.\r
+  @param  Lba        The starting logical block address to be written. The caller is\r
+                     responsible for writing to only legitimate locations.\r
+  @param  BufferSize Size of Buffer, must be a multiple of device block size.\r
+  @param  Buffer     A pointer to the source buffer for the data.\r
+\r
+  @retval EFI_SUCCESS           The data was written correctly to the device.\r
+  @retval EFI_WRITE_PROTECTED   The device can not be written to.\r
+  @retval EFI_DEVICE_ERROR      The device reported an error while performing the write.\r
+  @retval EFI_NO_MEDIA          There is no media in the device.\r
+  @retval EFI_MEDIA_CHNAGED     The MediaId does not matched the current device.\r
+  @retval EFI_BAD_BUFFER_SIZE   The Buffer was not a multiple of the block size of the device.\r
+  @retval EFI_INVALID_PARAMETER The write request contains LBAs that are not valid,\r
+                                or the buffer is not on proper alignment.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+SdWriteBlocks (\r
+  IN  EFI_BLOCK_IO_PROTOCOL   *This,\r
+  IN  UINT32                  MediaId,\r
+  IN  EFI_LBA                 Lba,\r
+  IN  UINTN                   BufferSize,\r
+  IN  VOID                    *Buffer\r
+  );\r
+\r
+/**\r
+  Flush the Block Device.\r
+\r
+  @param  This              Indicates a pointer to the calling context.\r
+\r
+  @retval EFI_SUCCESS       All outstanding data was written to the device\r
+  @retval EFI_DEVICE_ERROR  The device reported an error while writing back the data\r
+  @retval EFI_NO_MEDIA      There is no media in the device.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+SdFlushBlocks (\r
+  IN  EFI_BLOCK_IO_PROTOCOL   *This\r
+  );\r
+\r
+/**\r
+  Reset the Block Device.\r
+\r
+  @param[in]  This                 Indicates a pointer to the calling context.\r
+  @param[in]  ExtendedVerification Driver may perform diagnostics on reset.\r
+\r
+  @retval EFI_SUCCESS              The device was reset.\r
+  @retval EFI_DEVICE_ERROR         The device is not functioning properly and could\r
+                                   not be reset.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+SdResetEx (\r
+  IN  EFI_BLOCK_IO2_PROTOCOL  *This,\r
+  IN  BOOLEAN                 ExtendedVerification\r
+  );\r
+\r
+/**\r
+  Read BufferSize bytes from Lba into Buffer.\r
+\r
+  @param[in]       This         Indicates a pointer to the calling context.\r
+  @param[in]       MediaId      Id of the media, changes every time the media is replaced.\r
+  @param[in]       Lba          The starting Logical Block Address to read from.\r
+  @param[in, out]  Token        A pointer to the token associated with the transaction.\r
+  @param[in]       BufferSize   Size of Buffer, must be a multiple of device block size.\r
+  @param[out]      Buffer       A pointer to the destination buffer for the data. The caller is\r
+                                responsible for either having implicit or explicit ownership of the buffer.\r
+\r
+  @retval EFI_SUCCESS           The read request was queued if Event is not NULL.\r
+                                The data was read correctly from the device if\r
+                                the Event is NULL.\r
+  @retval EFI_DEVICE_ERROR      The device reported an error while performing\r
+                                the read.\r
+  @retval EFI_NO_MEDIA          There is no media in the device.\r
+  @retval EFI_MEDIA_CHANGED     The MediaId is not for the current media.\r
+  @retval EFI_BAD_BUFFER_SIZE   The BufferSize parameter is not a multiple of the\r
+                                intrinsic block size of the device.\r
+  @retval EFI_INVALID_PARAMETER The read request contains LBAs that are not valid,\r
+                                or the buffer is not on proper alignment.\r
+  @retval EFI_OUT_OF_RESOURCES  The request could not be completed due to a lack\r
+                                of resources.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+SdReadBlocksEx (\r
+  IN     EFI_BLOCK_IO2_PROTOCOL *This,\r
+  IN     UINT32                 MediaId,\r
+  IN     EFI_LBA                Lba,\r
+  IN OUT EFI_BLOCK_IO2_TOKEN    *Token,\r
+  IN     UINTN                  BufferSize,\r
+     OUT VOID                   *Buffer\r
+  );\r
+\r
+/**\r
+  Write BufferSize bytes from Lba into Buffer.\r
+\r
+  @param[in]       This         Indicates a pointer to the calling context.\r
+  @param[in]       MediaId      The media ID that the write request is for.\r
+  @param[in]       Lba          The starting logical block address to be written. The\r
+                                caller is responsible for writing to only legitimate\r
+                                locations.\r
+  @param[in, out]  Token        A pointer to the token associated with the transaction.\r
+  @param[in]       BufferSize   Size of Buffer, must be a multiple of device block size.\r
+  @param[in]       Buffer       A pointer to the source buffer for the data.\r
+\r
+  @retval EFI_SUCCESS           The data was written correctly to the device.\r
+  @retval EFI_WRITE_PROTECTED   The device can not be written to.\r
+  @retval EFI_DEVICE_ERROR      The device reported an error while performing the write.\r
+  @retval EFI_NO_MEDIA          There is no media in the device.\r
+  @retval EFI_MEDIA_CHNAGED     The MediaId does not matched the current device.\r
+  @retval EFI_BAD_BUFFER_SIZE   The Buffer was not a multiple of the block size of the device.\r
+  @retval EFI_INVALID_PARAMETER The write request contains LBAs that are not valid,\r
+                                or the buffer is not on proper alignment.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+SdWriteBlocksEx (\r
+  IN     EFI_BLOCK_IO2_PROTOCOL *This,\r
+  IN     UINT32                 MediaId,\r
+  IN     EFI_LBA                Lba,\r
+  IN OUT EFI_BLOCK_IO2_TOKEN    *Token,\r
+  IN     UINTN                  BufferSize,\r
+  IN     VOID                   *Buffer\r
+  );\r
+\r
+/**\r
+  Flush the Block Device.\r
+\r
+  @param[in]       This     Indicates a pointer to the calling context.\r
+  @param[in, out]  Token    A pointer to the token associated with the transaction.\r
+\r
+  @retval EFI_SUCCESS       All outstanding data was written to the device\r
+  @retval EFI_DEVICE_ERROR  The device reported an error while writing back the data\r
+  @retval EFI_NO_MEDIA      There is no media in the device.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+SdFlushBlocksEx (\r
+  IN     EFI_BLOCK_IO2_PROTOCOL  *This,\r
+  IN OUT EFI_BLOCK_IO2_TOKEN     *Token\r
+  );\r
+\r
+#endif\r
+\r
diff --git a/MdeModulePkg/Bus/Sd/SdDxe/SdDxe.c b/MdeModulePkg/Bus/Sd/SdDxe/SdDxe.c
new file mode 100644 (file)
index 0000000..7ed80b6
--- /dev/null
@@ -0,0 +1,888 @@
+/** @file\r
+  The SdDxe driver is used to manage the SD memory card device.\r
+\r
+  It produces BlockIo and BlockIo2 protocols to allow upper layer\r
+  access the SD memory card device.\r
+\r
+  Copyright (c) 2015 - 2016, Intel Corporation. All rights reserved.<BR>\r
+  This program and the accompanying materials\r
+  are licensed and made available under the terms and conditions of the BSD License\r
+  which accompanies this distribution.  The full text of the license may be found at\r
+  http://opensource.org/licenses/bsd-license.php\r
+\r
+  THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+  WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+\r
+**/\r
+\r
+#include "SdDxe.h"\r
+\r
+//\r
+// SdDxe Driver Binding Protocol Instance\r
+//\r
+EFI_DRIVER_BINDING_PROTOCOL gSdDxeDriverBinding = {\r
+  SdDxeDriverBindingSupported,\r
+  SdDxeDriverBindingStart,\r
+  SdDxeDriverBindingStop,\r
+  0x10,\r
+  NULL,\r
+  NULL\r
+};\r
+\r
+//\r
+// Template for SD_DEVICE data structure.\r
+//\r
+SD_DEVICE mSdDeviceTemplate = {\r
+  SD_DEVICE_SIGNATURE,         // Signature\r
+  NULL,                        // Handle\r
+  NULL,                        // DevicePath\r
+  0xFF,                        // Slot\r
+  FALSE,                       // SectorAddressing\r
+  {                            // BlockIo\r
+    EFI_BLOCK_IO_PROTOCOL_REVISION,\r
+    NULL,\r
+    SdReset,\r
+    SdReadBlocks,\r
+    SdWriteBlocks,\r
+    SdFlushBlocks\r
+  },\r
+  {                            // BlockIo2\r
+    NULL,\r
+    SdResetEx,\r
+    SdReadBlocksEx,\r
+    SdWriteBlocksEx,\r
+    SdFlushBlocksEx\r
+  },\r
+  {                            // BlockMedia\r
+    0,                         // MediaId\r
+    FALSE,                     // RemovableMedia\r
+    TRUE,                      // MediaPresent\r
+    FALSE,                     // LogicPartition\r
+    FALSE,                     // ReadOnly\r
+    FALSE,                     // WritingCache\r
+    0x200,                     // BlockSize\r
+    0,                         // IoAlign\r
+    0                          // LastBlock\r
+  },\r
+  {                            // Queue\r
+    NULL,\r
+    NULL\r
+  },\r
+  {                            // Csd\r
+    0,\r
+  },\r
+  {                            // Cid\r
+    0,\r
+  },\r
+  NULL,                        // ControllerNameTable\r
+  {                            // ModelName\r
+    0,\r
+  },\r
+  NULL                         // Private\r
+};\r
+\r
+/**\r
+  Decode and print SD CSD Register content.\r
+\r
+  @param[in] Csd           Pointer to SD_CSD data structure.\r
+\r
+  @retval EFI_SUCCESS      The function completed successfully\r
+**/\r
+EFI_STATUS\r
+DumpCsd (\r
+  IN SD_CSD  *Csd\r
+  )\r
+{\r
+  SD_CSD2 *Csd2;\r
+\r
+  DEBUG((DEBUG_INFO, "== Dump Sd Csd Register==\n"));\r
+  DEBUG((DEBUG_INFO, "  CSD structure                    0x%x\n", Csd->CsdStructure));\r
+  DEBUG((DEBUG_INFO, "  Data read access-time 1          0x%x\n", Csd->Taac));\r
+  DEBUG((DEBUG_INFO, "  Data read access-time 2          0x%x\n", Csd->Nsac));\r
+  DEBUG((DEBUG_INFO, "  Max. bus clock frequency         0x%x\n", Csd->TranSpeed));\r
+  DEBUG((DEBUG_INFO, "  Device command classes           0x%x\n", Csd->Ccc));\r
+  DEBUG((DEBUG_INFO, "  Max. read data block length      0x%x\n", Csd->ReadBlLen));\r
+  DEBUG((DEBUG_INFO, "  Partial blocks for read allowed  0x%x\n", Csd->ReadBlPartial));\r
+  DEBUG((DEBUG_INFO, "  Write block misalignment         0x%x\n", Csd->WriteBlkMisalign));\r
+  DEBUG((DEBUG_INFO, "  Read block misalignment          0x%x\n", Csd->ReadBlkMisalign));\r
+  DEBUG((DEBUG_INFO, "  DSR implemented                  0x%x\n", Csd->DsrImp));\r
+  if (Csd->CsdStructure == 0) {\r
+    DEBUG((DEBUG_INFO, "  Device size                      0x%x\n", Csd->CSizeLow | (Csd->CSizeHigh << 2)));\r
+    DEBUG((DEBUG_INFO, "  Max. read current @ VDD min      0x%x\n", Csd->VddRCurrMin));\r
+    DEBUG((DEBUG_INFO, "  Max. read current @ VDD max      0x%x\n", Csd->VddRCurrMax));\r
+    DEBUG((DEBUG_INFO, "  Max. write current @ VDD min     0x%x\n", Csd->VddWCurrMin));\r
+    DEBUG((DEBUG_INFO, "  Max. write current @ VDD max     0x%x\n", Csd->VddWCurrMax));\r
+  } else {\r
+    Csd2 = (SD_CSD2*)(VOID*)Csd;\r
+    DEBUG((DEBUG_INFO, "  Device size                      0x%x\n", Csd2->CSizeLow | (Csd->CSizeHigh << 16)));\r
+  }\r
+  DEBUG((DEBUG_INFO, "  Erase sector size                0x%x\n", Csd->SectorSize));\r
+  DEBUG((DEBUG_INFO, "  Erase single block enable        0x%x\n", Csd->EraseBlkEn));\r
+  DEBUG((DEBUG_INFO, "  Write protect group size         0x%x\n", Csd->WpGrpSize));\r
+  DEBUG((DEBUG_INFO, "  Write protect group enable       0x%x\n", Csd->WpGrpEnable));\r
+  DEBUG((DEBUG_INFO, "  Write speed factor               0x%x\n", Csd->R2WFactor));\r
+  DEBUG((DEBUG_INFO, "  Max. write data block length     0x%x\n", Csd->WriteBlLen));\r
+  DEBUG((DEBUG_INFO, "  Partial blocks for write allowed 0x%x\n", Csd->WriteBlPartial));\r
+  DEBUG((DEBUG_INFO, "  File format group                0x%x\n", Csd->FileFormatGrp));\r
+  DEBUG((DEBUG_INFO, "  Copy flag (OTP)                  0x%x\n", Csd->Copy));\r
+  DEBUG((DEBUG_INFO, "  Permanent write protection       0x%x\n", Csd->PermWriteProtect));\r
+  DEBUG((DEBUG_INFO, "  Temporary write protection       0x%x\n", Csd->TmpWriteProtect));\r
+  DEBUG((DEBUG_INFO, "  File format                      0x%x\n", Csd->FileFormat));\r
+\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+  Get SD device model name.\r
+\r
+  @param[in, out] Device   The pointer to the SD_DEVICE data structure.\r
+  @param[in]      Cid      Pointer to SD_CID data structure.\r
+\r
+  @retval EFI_SUCCESS      The function completed successfully\r
+\r
+**/\r
+EFI_STATUS\r
+GetSdModelName (\r
+  IN OUT SD_DEVICE         *Device,\r
+  IN     SD_CID            *Cid\r
+  )\r
+{\r
+  CHAR8  String[SD_MODEL_NAME_MAX_LEN];\r
+\r
+  ZeroMem (String, sizeof (String));\r
+  CopyMem (String, Cid->OemId, sizeof (Cid->OemId));\r
+  String[sizeof (Cid->OemId)] = ' ';\r
+  CopyMem (String + sizeof (Cid->OemId) + 1, Cid->ProductName, sizeof (Cid->ProductName));\r
+  String[sizeof (Cid->OemId) + sizeof (Cid->ProductName)] = ' ';\r
+  CopyMem (String + sizeof (Cid->OemId) + sizeof (Cid->ProductName) + 1, Cid->ProductSerialNumber, sizeof (Cid->ProductSerialNumber));\r
+\r
+  AsciiStrToUnicodeStr (String, Device->ModelName);\r
+\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+  Discover user area partition in the SD device.\r
+\r
+  @param[in] Device          The pointer to the SD_DEVICE data structure.\r
+\r
+  @retval EFI_SUCCESS        The user area partition in the SD device is successfully identified.\r
+  @return Others             Some error occurs when identifying the user area.\r
+\r
+**/\r
+EFI_STATUS\r
+DiscoverUserArea (\r
+  IN SD_DEVICE             *Device\r
+  )\r
+{\r
+  EFI_STATUS                        Status;\r
+  SD_CSD                            *Csd;\r
+  SD_CSD2                           *Csd2;\r
+  SD_CID                            *Cid;\r
+  UINT64                            Capacity;\r
+  UINT32                            DevStatus;\r
+  UINT16                            Rca;\r
+  UINT32                            CSize;\r
+  UINT32                            CSizeMul;\r
+  UINT32                            ReadBlLen;\r
+\r
+  //\r
+  // Deselect the device to force it enter stby mode.\r
+  // Note here we don't judge return status as some SD devices return\r
+  // error but the state has been stby.\r
+  //\r
+  SdSelect (Device, 0);\r
+\r
+  Status = SdSetRca (Device, &Rca);\r
+  if (EFI_ERROR (Status)) {\r
+    DEBUG ((EFI_D_ERROR, "DiscoverUserArea(): Assign new Rca = 0x%x fails with %r\n", Rca, Status));\r
+    return Status;\r
+  }\r
+\r
+  Csd    = &Device->Csd;\r
+  Status = SdGetCsd (Device, Rca, Csd);\r
+  if (EFI_ERROR (Status)) {\r
+    return Status;\r
+  }\r
+  DumpCsd (Csd);\r
+\r
+  Cid    = &Device->Cid;\r
+  Status = SdGetCid (Device, Rca, Cid);\r
+  if (EFI_ERROR (Status)) {\r
+    return Status;\r
+  }\r
+  GetSdModelName (Device, Cid);\r
+\r
+  Status = SdSelect (Device, Rca);\r
+  if (EFI_ERROR (Status)) {\r
+    DEBUG ((EFI_D_ERROR, "DiscoverUserArea(): Reselect the device 0x%x fails with %r\n", Rca, Status));\r
+    return Status;\r
+  }\r
+\r
+  Status = SdSendStatus (Device, Rca, &DevStatus);\r
+  if (EFI_ERROR (Status)) {\r
+    return Status;\r
+  }\r
+\r
+  if (Csd->CsdStructure == 0) {\r
+    Device->SectorAddressing = FALSE;\r
+    CSize     = (Csd->CSizeHigh << 2 | Csd->CSizeLow) + 1;\r
+    CSizeMul  = (1 << (Csd->CSizeMul + 2));\r
+    ReadBlLen = (1 << (Csd->ReadBlLen));\r
+    Capacity  = MultU64x32 (MultU64x32 ((UINT64)CSize, CSizeMul), ReadBlLen);\r
+  } else {\r
+    Device->SectorAddressing = TRUE;\r
+    Csd2      = (SD_CSD2*)(VOID*)Csd;\r
+    CSize     = (Csd2->CSizeHigh << 16 | Csd2->CSizeLow) + 1;\r
+    Capacity  = MultU64x32 ((UINT64)CSize, SIZE_512KB);\r
+  }\r
+\r
+  Device->BlockIo.Media               = &Device->BlockMedia;\r
+  Device->BlockIo2.Media              = &Device->BlockMedia;\r
+  Device->BlockMedia.IoAlign          = Device->Private->PassThru->IoAlign;\r
+  Device->BlockMedia.BlockSize        = 0x200;\r
+  Device->BlockMedia.LastBlock        = 0x00;\r
+  Device->BlockMedia.RemovableMedia   = TRUE;\r
+  Device->BlockMedia.MediaPresent     = TRUE;\r
+  Device->BlockMedia.LogicalPartition = FALSE;\r
+  Device->BlockMedia.LastBlock        = DivU64x32 (Capacity, Device->BlockMedia.BlockSize) - 1;\r
+\r
+  return Status;\r
+}\r
+\r
+/**\r
+  Scan SD Bus to discover the device.\r
+\r
+  @param[in]  Private             The SD driver private data structure.\r
+  @param[in]  Slot                The slot number to check device present.\r
+\r
+  @retval EFI_SUCCESS             Successfully to discover the device and attach\r
+                                  SdMmcIoProtocol to it.\r
+  @retval EFI_OUT_OF_RESOURCES    The request could not be completed due to a lack\r
+                                  of resources.\r
+  @retval EFI_ALREADY_STARTED     The device was discovered before.\r
+  @retval Others                  Fail to discover the device.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+DiscoverSdDevice (\r
+  IN  SD_DRIVER_PRIVATE_DATA      *Private,\r
+  IN  UINT8                       Slot\r
+  )\r
+{\r
+  EFI_STATUS                      Status;\r
+  SD_DEVICE                       *Device;\r
+  EFI_DEVICE_PATH_PROTOCOL        *DevicePath;\r
+  EFI_DEVICE_PATH_PROTOCOL        *NewDevicePath;\r
+  EFI_DEVICE_PATH_PROTOCOL        *RemainingDevicePath;\r
+  EFI_HANDLE                      DeviceHandle;\r
+  EFI_SD_MMC_PASS_THRU_PROTOCOL   *PassThru;\r
+\r
+  Device              = NULL;\r
+  DevicePath          = NULL;\r
+  NewDevicePath       = NULL;\r
+  RemainingDevicePath = NULL;\r
+  PassThru = Private->PassThru;\r
+\r
+  //\r
+  // Build Device Path\r
+  //\r
+  Status = PassThru->BuildDevicePath (\r
+                       PassThru,\r
+                       Slot,\r
+                       &DevicePath\r
+                       );\r
+  if (EFI_ERROR(Status)) {\r
+    return Status;\r
+  }\r
+\r
+  if (DevicePath->SubType != MSG_SD_DP) {\r
+    Status = EFI_UNSUPPORTED;\r
+    goto Error;\r
+  }\r
+\r
+  NewDevicePath = AppendDevicePathNode (\r
+                    Private->ParentDevicePath,\r
+                    DevicePath\r
+                    );\r
+\r
+  if (NewDevicePath == NULL) {\r
+    Status = EFI_OUT_OF_RESOURCES;\r
+    goto Error;\r
+  }\r
+\r
+  DeviceHandle = NULL;\r
+  RemainingDevicePath = NewDevicePath;\r
+  Status = gBS->LocateDevicePath (&gEfiDevicePathProtocolGuid, &RemainingDevicePath, &DeviceHandle);\r
+  if (!EFI_ERROR (Status) && (DeviceHandle != NULL) && IsDevicePathEnd(RemainingDevicePath)) {\r
+    //\r
+    // The device has been started, directly return to fast boot.\r
+    //\r
+    Status = EFI_ALREADY_STARTED;\r
+    goto Error;\r
+  }\r
+\r
+  //\r
+  // Allocate buffer to store SD_DEVICE private data.\r
+  //\r
+  Device = AllocateCopyPool (sizeof (SD_DEVICE), &mSdDeviceTemplate);\r
+  if (Device == NULL) {\r
+    Status = EFI_OUT_OF_RESOURCES;\r
+    goto Error;\r
+  }\r
+\r
+  Device->DevicePath = NewDevicePath;\r
+  Device->Slot       = Slot;\r
+  Device->Private    = Private;\r
+  InitializeListHead (&Device->Queue);\r
+\r
+  //\r
+  // Expose user area in the Sd memory card to upper layer.\r
+  //\r
+  Status = DiscoverUserArea (Device);\r
+  if (EFI_ERROR(Status)) {\r
+    goto Error;\r
+  }\r
+\r
+  Device->ControllerNameTable = NULL;\r
+  AddUnicodeString2 (\r
+    "eng",\r
+    gSdDxeComponentName.SupportedLanguages,\r
+    &Device->ControllerNameTable,\r
+    Device->ModelName,\r
+    TRUE\r
+    );\r
+  AddUnicodeString2 (\r
+    "en",\r
+    gSdDxeComponentName.SupportedLanguages,\r
+    &Device->ControllerNameTable,\r
+    Device->ModelName,\r
+    FALSE\r
+    );\r
+\r
+  Status = gBS->InstallMultipleProtocolInterfaces (\r
+                  &Device->Handle,\r
+                  &gEfiDevicePathProtocolGuid,\r
+                  Device->DevicePath,\r
+                  &gEfiBlockIoProtocolGuid,\r
+                  &Device->BlockIo,\r
+                  &gEfiBlockIo2ProtocolGuid,\r
+                  &Device->BlockIo2,\r
+                  NULL\r
+                  );\r
+\r
+  if (!EFI_ERROR (Status)) {\r
+    gBS->OpenProtocol (\r
+           Private->Controller,\r
+           &gEfiSdMmcPassThruProtocolGuid,\r
+           (VOID **) &(Private->PassThru),\r
+           Private->DriverBindingHandle,\r
+           Device->Handle,\r
+           EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER\r
+           );\r
+  }\r
+\r
+Error:\r
+  FreePool (DevicePath);\r
+\r
+  if (EFI_ERROR (Status) && (NewDevicePath != NULL)) {\r
+    FreePool (NewDevicePath);\r
+  }\r
+\r
+  if (EFI_ERROR (Status) && (Device != NULL)) {\r
+    FreePool (Device);\r
+  }\r
+\r
+  return Status;\r
+}\r
+\r
+/**\r
+  Tests to see if this driver supports a given controller. If a child device is provided,\r
+  it further tests to see if this driver supports creating a handle for the specified child device.\r
+\r
+  This function checks to see if the driver specified by This supports the device specified by\r
+  ControllerHandle. Drivers will typically use the device path attached to\r
+  ControllerHandle and/or the services from the bus I/O abstraction attached to\r
+  ControllerHandle to determine if the driver supports ControllerHandle. This function\r
+  may be called many times during platform initialization. In order to reduce boot times, the tests\r
+  performed by this function must be very small, and take as little time as possible to execute. This\r
+  function must not change the state of any hardware devices, and this function must be aware that the\r
+  device specified by ControllerHandle may already be managed by the same driver or a\r
+  different driver. This function must match its calls to AllocatePages() with FreePages(),\r
+  AllocatePool() with FreePool(), and OpenProtocol() with CloseProtocol().\r
+  Since ControllerHandle may have been previously started by the same driver, if a protocol is\r
+  already in the opened state, then it must not be closed with CloseProtocol(). This is required\r
+  to guarantee the state of ControllerHandle is not modified by this function.\r
+\r
+  @param[in]  This                 A pointer to the EFI_DRIVER_BINDING_PROTOCOL instance.\r
+  @param[in]  ControllerHandle     The handle of the controller to test. This handle\r
+                                   must support a protocol interface that supplies\r
+                                   an I/O abstraction to the driver.\r
+  @param[in]  RemainingDevicePath  A pointer to the remaining portion of a device path.  This\r
+                                   parameter is ignored by device drivers, and is optional for bus\r
+                                   drivers. For bus drivers, if this parameter is not NULL, then\r
+                                   the bus driver must determine if the bus controller specified\r
+                                   by ControllerHandle and the child controller specified\r
+                                   by RemainingDevicePath are both supported by this\r
+                                   bus driver.\r
+\r
+  @retval EFI_SUCCESS              The device specified by ControllerHandle and\r
+                                   RemainingDevicePath is supported by the driver specified by This.\r
+  @retval EFI_ALREADY_STARTED      The device specified by ControllerHandle and\r
+                                   RemainingDevicePath is already being managed by the driver\r
+                                   specified by This.\r
+  @retval EFI_ACCESS_DENIED        The device specified by ControllerHandle and\r
+                                   RemainingDevicePath is already being managed by a different\r
+                                   driver or an application that requires exclusive access.\r
+                                   Currently not implemented.\r
+  @retval EFI_UNSUPPORTED          The device specified by ControllerHandle and\r
+                                   RemainingDevicePath is not supported by the driver specified by This.\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+SdDxeDriverBindingSupported (\r
+  IN EFI_DRIVER_BINDING_PROTOCOL   *This,\r
+  IN EFI_HANDLE                    Controller,\r
+  IN EFI_DEVICE_PATH_PROTOCOL      *RemainingDevicePath\r
+  )\r
+{\r
+  EFI_STATUS                       Status;\r
+  EFI_DEVICE_PATH_PROTOCOL         *ParentDevicePath;\r
+  EFI_SD_MMC_PASS_THRU_PROTOCOL    *PassThru;\r
+  UINT8                            Slot;\r
+\r
+  //\r
+  // Test EFI_SD_MMC_PASS_THRU_PROTOCOL on the controller handle.\r
+  //\r
+  Status = gBS->OpenProtocol (\r
+                  Controller,\r
+                  &gEfiSdMmcPassThruProtocolGuid,\r
+                  (VOID**) &PassThru,\r
+                  This->DriverBindingHandle,\r
+                  Controller,\r
+                  EFI_OPEN_PROTOCOL_BY_DRIVER\r
+                  );\r
+\r
+  if (Status == EFI_ALREADY_STARTED) {\r
+    return EFI_SUCCESS;\r
+  }\r
+\r
+  if (EFI_ERROR (Status)) {\r
+    return Status;\r
+  }\r
+\r
+  //\r
+  // Test RemainingDevicePath is valid or not.\r
+  //\r
+  if ((RemainingDevicePath != NULL) && !IsDevicePathEnd (RemainingDevicePath)) {\r
+    Status = PassThru->GetSlotNumber (PassThru, RemainingDevicePath, &Slot);\r
+    if (EFI_ERROR (Status)) {\r
+      //\r
+      // Close the I/O Abstraction(s) used to perform the supported test\r
+      //\r
+      gBS->CloseProtocol (\r
+             Controller,\r
+             &gEfiSdMmcPassThruProtocolGuid,\r
+             This->DriverBindingHandle,\r
+             Controller\r
+             );\r
+      return Status;\r
+    }\r
+  }\r
+\r
+  //\r
+  // Close the I/O Abstraction(s) used to perform the supported test\r
+  //\r
+  gBS->CloseProtocol (\r
+         Controller,\r
+         &gEfiSdMmcPassThruProtocolGuid,\r
+         This->DriverBindingHandle,\r
+         Controller\r
+         );\r
+\r
+  //\r
+  // Open the EFI Device Path protocol needed to perform the supported test\r
+  //\r
+  Status = gBS->OpenProtocol (\r
+                  Controller,\r
+                  &gEfiDevicePathProtocolGuid,\r
+                  (VOID **) &ParentDevicePath,\r
+                  This->DriverBindingHandle,\r
+                  Controller,\r
+                  EFI_OPEN_PROTOCOL_GET_PROTOCOL\r
+                  );\r
+  return Status;\r
+}\r
+\r
+/**\r
+  Starts a device controller or a bus controller.\r
+\r
+  The Start() function is designed to be invoked from the EFI boot service ConnectController().\r
+  As a result, much of the error checking on the parameters to Start() has been moved into this\r
+  common boot service. It is legal to call Start() from other locations,\r
+  but the following calling restrictions must be followed or the system behavior will not be deterministic.\r
+  1. ControllerHandle must be a valid EFI_HANDLE.\r
+  2. If RemainingDevicePath is not NULL, then it must be a pointer to a naturally aligned\r
+     EFI_DEVICE_PATH_PROTOCOL.\r
+  3. Prior to calling Start(), the Supported() function for the driver specified by This must\r
+     have been called with the same calling parameters, and Supported() must have returned EFI_SUCCESS.\r
+\r
+  @param[in]  This                 A pointer to the EFI_DRIVER_BINDING_PROTOCOL instance.\r
+  @param[in]  ControllerHandle     The handle of the controller to start. This handle\r
+                                   must support a protocol interface that supplies\r
+                                   an I/O abstraction to the driver.\r
+  @param[in]  RemainingDevicePath  A pointer to the remaining portion of a device path.  This\r
+                                   parameter is ignored by device drivers, and is optional for bus\r
+                                   drivers. For a bus driver, if this parameter is NULL, then handles\r
+                                   for all the children of Controller are created by this driver.\r
+                                   If this parameter is not NULL and the first Device Path Node is\r
+                                   not the End of Device Path Node, then only the handle for the\r
+                                   child device specified by the first Device Path Node of\r
+                                   RemainingDevicePath is created by this driver.\r
+                                   If the first Device Path Node of RemainingDevicePath is\r
+                                   the End of Device Path Node, no child handle is created by this\r
+                                   driver.\r
+\r
+  @retval EFI_SUCCESS              The device was started.\r
+  @retval EFI_DEVICE_ERROR         The device could not be started due to a device error.Currently not implemented.\r
+  @retval EFI_OUT_OF_RESOURCES     The request could not be completed due to a lack of resources.\r
+  @retval Others                   The driver failded to start the device.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+SdDxeDriverBindingStart (\r
+  IN EFI_DRIVER_BINDING_PROTOCOL   *This,\r
+  IN EFI_HANDLE                    Controller,\r
+  IN EFI_DEVICE_PATH_PROTOCOL      *RemainingDevicePath\r
+  )\r
+{\r
+  EFI_STATUS                       Status;\r
+  EFI_SD_MMC_PASS_THRU_PROTOCOL    *PassThru;\r
+  EFI_DEVICE_PATH_PROTOCOL         *ParentDevicePath;\r
+  SD_DRIVER_PRIVATE_DATA           *Private;\r
+  UINT8                            Slot;\r
+\r
+  Private  = NULL;\r
+  PassThru = NULL;\r
+  Status = gBS->OpenProtocol (\r
+                  Controller,\r
+                  &gEfiSdMmcPassThruProtocolGuid,\r
+                  (VOID **) &PassThru,\r
+                  This->DriverBindingHandle,\r
+                  Controller,\r
+                  EFI_OPEN_PROTOCOL_BY_DRIVER\r
+                  );\r
+  if ((EFI_ERROR (Status)) && (Status != EFI_ALREADY_STARTED)) {\r
+    return Status;\r
+  }\r
+\r
+  //\r
+  // Check EFI_ALREADY_STARTED to reuse the original SD_DRIVER_PRIVATE_DATA.\r
+  //\r
+  if (Status != EFI_ALREADY_STARTED) {\r
+    Private = AllocateZeroPool (sizeof (SD_DRIVER_PRIVATE_DATA));\r
+    if (Private == NULL) {\r
+      Status = EFI_OUT_OF_RESOURCES;\r
+      goto Error;\r
+    }\r
+\r
+    Status = gBS->OpenProtocol (\r
+                    Controller,\r
+                    &gEfiDevicePathProtocolGuid,\r
+                    (VOID **) &ParentDevicePath,\r
+                    This->DriverBindingHandle,\r
+                    Controller,\r
+                    EFI_OPEN_PROTOCOL_GET_PROTOCOL\r
+                    );\r
+    ASSERT_EFI_ERROR (Status);\r
+    Private->PassThru            = PassThru;\r
+    Private->Controller          = Controller;\r
+    Private->ParentDevicePath    = ParentDevicePath;\r
+    Private->DriverBindingHandle = This->DriverBindingHandle;\r
+\r
+    Status = gBS->InstallProtocolInterface (\r
+                    &Controller,\r
+                    &gEfiCallerIdGuid,\r
+                    EFI_NATIVE_INTERFACE,\r
+                    Private\r
+                    );\r
+    if (EFI_ERROR (Status)) {\r
+      goto Error;\r
+    }\r
+  } else {\r
+    Status = gBS->OpenProtocol (\r
+                    Controller,\r
+                    &gEfiCallerIdGuid,\r
+                    (VOID **) &Private,\r
+                    This->DriverBindingHandle,\r
+                    Controller,\r
+                    EFI_OPEN_PROTOCOL_GET_PROTOCOL\r
+                    );\r
+    if (EFI_ERROR (Status)) {\r
+      goto Error;\r
+    }\r
+  }\r
+\r
+  if (RemainingDevicePath == NULL) {\r
+    Slot = 0xFF;\r
+    while (TRUE) {\r
+      Status = PassThru->GetNextSlot (PassThru, &Slot);\r
+      if (EFI_ERROR (Status)) {\r
+        //\r
+        // Cannot find more legal slots.\r
+        //\r
+        Status = EFI_SUCCESS;\r
+        break;\r
+      }\r
+\r
+      Status = DiscoverSdDevice (Private, Slot);\r
+      if (EFI_ERROR (Status) && (Status != EFI_ALREADY_STARTED)) {\r
+        break;\r
+      }\r
+    }\r
+  } else if (!IsDevicePathEnd (RemainingDevicePath)) {\r
+    Status = PassThru->GetSlotNumber (PassThru, RemainingDevicePath, &Slot);\r
+    if (!EFI_ERROR (Status)) {\r
+      Status = DiscoverSdDevice (Private, Slot);\r
+    }\r
+  }\r
+\r
+Error:\r
+  if (EFI_ERROR (Status) && (Status != EFI_ALREADY_STARTED)) {\r
+    gBS->CloseProtocol (\r
+           Controller,\r
+           &gEfiSdMmcPassThruProtocolGuid,\r
+           This->DriverBindingHandle,\r
+           Controller\r
+           );\r
+\r
+    if (Private != NULL) {\r
+      gBS->UninstallMultipleProtocolInterfaces (\r
+           Controller,\r
+           &gEfiCallerIdGuid,\r
+           Private,\r
+           NULL\r
+           );\r
+      FreePool (Private);\r
+    }\r
+  }\r
+  return Status;\r
+}\r
+\r
+/**\r
+  Stops a device controller or a bus controller.\r
+\r
+  The Stop() function is designed to be invoked from the EFI boot service DisconnectController().\r
+  As a result, much of the error checking on the parameters to Stop() has been moved\r
+  into this common boot service. It is legal to call Stop() from other locations,\r
+  but the following calling restrictions must be followed or the system behavior will not be deterministic.\r
+  1. ControllerHandle must be a valid EFI_HANDLE that was used on a previous call to this\r
+     same driver's Start() function.\r
+  2. The first NumberOfChildren handles of ChildHandleBuffer must all be a valid\r
+     EFI_HANDLE. In addition, all of these handles must have been created in this driver's\r
+     Start() function, and the Start() function must have called OpenProtocol() on\r
+     ControllerHandle with an Attribute of EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER.\r
+\r
+  @param[in]  This              A pointer to the EFI_DRIVER_BINDING_PROTOCOL instance.\r
+  @param[in]  ControllerHandle  A handle to the device being stopped. The handle must\r
+                                support a bus specific I/O protocol for the driver\r
+                                to use to stop the device.\r
+  @param[in]  NumberOfChildren  The number of child device handles in ChildHandleBuffer.\r
+  @param[in]  ChildHandleBuffer An array of child handles to be freed. May be NULL\r
+                                if NumberOfChildren is 0.\r
+\r
+  @retval EFI_SUCCESS           The device was stopped.\r
+  @retval EFI_DEVICE_ERROR      The device could not be stopped due to a device error.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+SdDxeDriverBindingStop (\r
+  IN  EFI_DRIVER_BINDING_PROTOCOL     *This,\r
+  IN  EFI_HANDLE                      Controller,\r
+  IN  UINTN                           NumberOfChildren,\r
+  IN  EFI_HANDLE                      *ChildHandleBuffer\r
+  )\r
+{\r
+  EFI_STATUS                          Status;\r
+  BOOLEAN                             AllChildrenStopped;\r
+  UINTN                               Index;\r
+  SD_DRIVER_PRIVATE_DATA              *Private;\r
+  SD_DEVICE                           *Device;\r
+  EFI_SD_MMC_PASS_THRU_PROTOCOL       *PassThru;\r
+  EFI_BLOCK_IO2_PROTOCOL              *BlockIo2;\r
+  EFI_BLOCK_IO_PROTOCOL               *BlockIo;\r
+  LIST_ENTRY                          *Link;\r
+  LIST_ENTRY                          *NextLink;\r
+  SD_REQUEST                          *Request;\r
+  EFI_TPL                             OldTpl;\r
+\r
+  if (NumberOfChildren == 0) {\r
+    Status = gBS->OpenProtocol (\r
+                    Controller,\r
+                    &gEfiCallerIdGuid,\r
+                    (VOID **) &Private,\r
+                    This->DriverBindingHandle,\r
+                    Controller,\r
+                    EFI_OPEN_PROTOCOL_GET_PROTOCOL\r
+                    );\r
+    if (EFI_ERROR (Status)) {\r
+      return EFI_DEVICE_ERROR;\r
+    }\r
+\r
+    gBS->UninstallProtocolInterface (\r
+          Controller,\r
+          &gEfiCallerIdGuid,\r
+          Private\r
+          );\r
+    gBS->CloseProtocol (\r
+          Controller,\r
+          &gEfiSdMmcPassThruProtocolGuid,\r
+          This->DriverBindingHandle,\r
+          Controller\r
+          );\r
+\r
+    FreePool (Private);\r
+\r
+    return EFI_SUCCESS;\r
+  }\r
+\r
+  AllChildrenStopped = TRUE;\r
+\r
+  for (Index = 0; Index < NumberOfChildren; Index++) {\r
+    BlockIo  = NULL;\r
+    BlockIo2 = NULL;\r
+    Status = gBS->OpenProtocol (\r
+                    ChildHandleBuffer[Index],\r
+                    &gEfiBlockIoProtocolGuid,\r
+                    (VOID **) &BlockIo,\r
+                    This->DriverBindingHandle,\r
+                    Controller,\r
+                    EFI_OPEN_PROTOCOL_GET_PROTOCOL\r
+                    );\r
+    if (EFI_ERROR (Status)) {\r
+      Status = gBS->OpenProtocol (\r
+                      ChildHandleBuffer[Index],\r
+                      &gEfiBlockIo2ProtocolGuid,\r
+                      (VOID **) &BlockIo2,\r
+                      This->DriverBindingHandle,\r
+                      Controller,\r
+                      EFI_OPEN_PROTOCOL_GET_PROTOCOL\r
+                      );\r
+      if (EFI_ERROR (Status)) {\r
+        AllChildrenStopped = FALSE;\r
+        continue;\r
+      }\r
+    }\r
+\r
+    if (BlockIo != NULL) {\r
+      Device = SD_DEVICE_DATA_FROM_BLKIO (BlockIo);\r
+    } else {\r
+      ASSERT (BlockIo2 != NULL);\r
+      Device = SD_DEVICE_DATA_FROM_BLKIO2 (BlockIo2);\r
+    }\r
+\r
+    //\r
+    // Free all on-going async tasks.\r
+    //\r
+    OldTpl = gBS->RaiseTPL (TPL_CALLBACK);\r
+    for (Link = GetFirstNode (&Device->Queue);\r
+         !IsNull (&Device->Queue, Link);\r
+         Link = NextLink) {\r
+      NextLink = GetNextNode (&Device->Queue, Link);\r
+      RemoveEntryList (Link);\r
+\r
+      Request = SD_REQUEST_FROM_LINK (Link);\r
+\r
+      gBS->CloseEvent (Request->Event);\r
+      Request->Token->TransactionStatus = EFI_ABORTED;\r
+\r
+      if (Request->IsEnd) {\r
+        gBS->SignalEvent (Request->Token->Event);\r
+      }\r
+\r
+      FreePool (Request);\r
+    }\r
+    gBS->RestoreTPL (OldTpl);\r
+\r
+    //\r
+    // Close the child handle\r
+    //\r
+    Status = gBS->CloseProtocol (\r
+                    Controller,\r
+                    &gEfiSdMmcPassThruProtocolGuid,\r
+                    This->DriverBindingHandle,\r
+                    ChildHandleBuffer[Index]\r
+                    );\r
+\r
+    Status = gBS->UninstallMultipleProtocolInterfaces (\r
+                    ChildHandleBuffer[Index],\r
+                    &gEfiDevicePathProtocolGuid,\r
+                    Device->DevicePath,\r
+                    &gEfiBlockIoProtocolGuid,\r
+                    &Device->BlockIo,\r
+                    &gEfiBlockIo2ProtocolGuid,\r
+                    &Device->BlockIo2,\r
+                    NULL\r
+                    );\r
+    if (EFI_ERROR (Status)) {\r
+      AllChildrenStopped = FALSE;\r
+        gBS->OpenProtocol (\r
+               Controller,\r
+               &gEfiSdMmcPassThruProtocolGuid,\r
+               (VOID **)&PassThru,\r
+               This->DriverBindingHandle,\r
+               ChildHandleBuffer[Index],\r
+               EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER\r
+               );\r
+    } else {\r
+      FreePool (Device->DevicePath);\r
+      FreeUnicodeStringTable (Device->ControllerNameTable);\r
+      FreePool (Device);\r
+    }\r
+  }\r
+\r
+  if (!AllChildrenStopped) {\r
+    return EFI_DEVICE_ERROR;\r
+  }\r
+\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+  The user Entry Point for module SdDxe. The user code starts with this function.\r
+\r
+  @param[in] ImageHandle    The firmware allocated handle for the EFI image.\r
+  @param[in] SystemTable    A pointer to the EFI System Table.\r
+\r
+  @retval EFI_SUCCESS       The entry point is executed successfully.\r
+  @retval other             Some errors occur when executing this entry point.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+InitializeSdDxe (\r
+  IN EFI_HANDLE           ImageHandle,\r
+  IN EFI_SYSTEM_TABLE     *SystemTable\r
+  )\r
+{\r
+  EFI_STATUS              Status;\r
+\r
+  //\r
+  // Install driver model protocol(s).\r
+  //\r
+  Status = EfiLibInstallDriverBindingComponentName2 (\r
+             ImageHandle,\r
+             SystemTable,\r
+             &gSdDxeDriverBinding,\r
+             ImageHandle,\r
+             &gSdDxeComponentName,\r
+             &gSdDxeComponentName2\r
+             );\r
+  ASSERT_EFI_ERROR (Status);\r
+\r
+  return Status;\r
+}\r
+\r
diff --git a/MdeModulePkg/Bus/Sd/SdDxe/SdDxe.h b/MdeModulePkg/Bus/Sd/SdDxe/SdDxe.h
new file mode 100644 (file)
index 0000000..ca1609e
--- /dev/null
@@ -0,0 +1,469 @@
+/** @file\r
+  Header file for SdDxe Driver.\r
+\r
+  This file defines common data structures, macro definitions and some module\r
+  internal function header files.\r
+\r
+  Copyright (c) 2015, Intel Corporation. All rights reserved.<BR>\r
+  This program and the accompanying materials\r
+  are licensed and made available under the terms and conditions of the BSD License\r
+  which accompanies this distribution.  The full text of the license may be found at\r
+  http://opensource.org/licenses/bsd-license.php\r
+\r
+  THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+  WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+\r
+**/\r
+\r
+#ifndef _SD_DXE_H_\r
+#define _SD_DXE_H_\r
+\r
+#include <Uefi.h>\r
+#include <IndustryStandard/Sd.h>\r
+\r
+#include <Protocol/SdMmcPassThru.h>\r
+#include <Protocol/BlockIo.h>\r
+#include <Protocol/BlockIo2.h>\r
+\r
+#include <Protocol/DevicePath.h>\r
+\r
+#include <Library/DebugLib.h>\r
+#include <Library/UefiDriverEntryPoint.h>\r
+#include <Library/BaseLib.h>\r
+#include <Library/UefiLib.h>\r
+#include <Library/BaseMemoryLib.h>\r
+#include <Library/MemoryAllocationLib.h>\r
+#include <Library/UefiBootServicesTableLib.h>\r
+#include <Library/DevicePathLib.h>\r
+#include <Library/UefiRuntimeServicesTableLib.h>\r
+\r
+#include "SdBlockIo.h"\r
+//\r
+// Global Variables\r
+//\r
+extern EFI_DRIVER_BINDING_PROTOCOL      gSdDxeDriverBinding;\r
+extern EFI_COMPONENT_NAME_PROTOCOL      gSdDxeComponentName;\r
+extern EFI_COMPONENT_NAME2_PROTOCOL     gSdDxeComponentName2;\r
+\r
+#define SD_DEVICE_SIGNATURE             SIGNATURE_32 ('S', 'D', 't', 'f')\r
+\r
+#define SD_DEVICE_DATA_FROM_BLKIO(a) \\r
+    CR(a, SD_DEVICE, BlockIo, SD_DEVICE_SIGNATURE)\r
+\r
+#define SD_DEVICE_DATA_FROM_BLKIO2(a) \\r
+    CR(a, SD_DEVICE, BlockIo2, SD_DEVICE_SIGNATURE)\r
+\r
+//\r
+// Take 2.5 seconds as generic time out value, 1 microsecond as unit.\r
+//\r
+#define SD_GENERIC_TIMEOUT              2500 * 1000\r
+\r
+#define SD_REQUEST_SIGNATURE            SIGNATURE_32 ('S', 'D', 'R', 'E')\r
+\r
+#define SD_MODEL_NAME_MAX_LEN           32\r
+\r
+typedef struct _SD_DEVICE               SD_DEVICE;\r
+typedef struct _SD_DRIVER_PRIVATE_DATA  SD_DRIVER_PRIVATE_DATA;\r
+\r
+//\r
+// Asynchronous I/O request.\r
+//\r
+typedef struct {\r
+  UINT32                                Signature;\r
+  LIST_ENTRY                            Link;\r
+\r
+  EFI_SD_MMC_COMMAND_BLOCK              SdMmcCmdBlk;\r
+  EFI_SD_MMC_STATUS_BLOCK               SdMmcStatusBlk;\r
+  EFI_SD_MMC_PASS_THRU_COMMAND_PACKET   Packet;\r
+\r
+  BOOLEAN                               IsEnd;\r
+\r
+  EFI_BLOCK_IO2_TOKEN                   *Token;\r
+\r
+  EFI_EVENT                             Event;\r
+} SD_REQUEST;\r
+\r
+#define SD_REQUEST_FROM_LINK(a) \\r
+    CR(a, SD_REQUEST, Link, SD_REQUEST_SIGNATURE)\r
+\r
+struct _SD_DEVICE {\r
+  UINT32                                Signature;\r
+  EFI_HANDLE                            Handle;\r
+  EFI_DEVICE_PATH_PROTOCOL              *DevicePath;\r
+  UINT8                                 Slot;\r
+  BOOLEAN                               SectorAddressing;\r
+  EFI_BLOCK_IO_PROTOCOL                 BlockIo;\r
+  EFI_BLOCK_IO2_PROTOCOL                BlockIo2;\r
+  EFI_BLOCK_IO_MEDIA                    BlockMedia;\r
+\r
+  LIST_ENTRY                            Queue;\r
+\r
+  SD_CSD                                Csd;\r
+  SD_CID                                Cid;\r
+  EFI_UNICODE_STRING_TABLE              *ControllerNameTable;\r
+  //\r
+  // The model name consists of three fields in CID register\r
+  // 1) OEM/Application ID (2 bytes)\r
+  // 2) Product Name       (5 bytes)\r
+  // 3) Product Serial Number (4 bytes)\r
+  // The delimiters of these fields are whitespace.\r
+  //\r
+  CHAR16                                ModelName[SD_MODEL_NAME_MAX_LEN];\r
+  SD_DRIVER_PRIVATE_DATA                *Private;\r
+} ;\r
+\r
+//\r
+// SD DXE driver private data structure\r
+//\r
+struct _SD_DRIVER_PRIVATE_DATA {\r
+  EFI_SD_MMC_PASS_THRU_PROTOCOL         *PassThru;\r
+  EFI_HANDLE                            Controller;\r
+  EFI_DEVICE_PATH_PROTOCOL              *ParentDevicePath;\r
+  EFI_HANDLE                            DriverBindingHandle;\r
+} ;\r
+\r
+/**\r
+  Tests to see if this driver supports a given controller. If a child device is provided,\r
+  it further tests to see if this driver supports creating a handle for the specified child device.\r
+\r
+  This function checks to see if the driver specified by This supports the device specified by\r
+  ControllerHandle. Drivers will typically use the device path attached to\r
+  ControllerHandle and/or the services from the bus I/O abstraction attached to\r
+  ControllerHandle to determine if the driver supports ControllerHandle. This function\r
+  may be called many times during platform initialization. In order to reduce boot times, the tests\r
+  performed by this function must be very small, and take as little time as possible to execute. This\r
+  function must not change the state of any hardware devices, and this function must be aware that the\r
+  device specified by ControllerHandle may already be managed by the same driver or a\r
+  different driver. This function must match its calls to AllocatePages() with FreePages(),\r
+  AllocatePool() with FreePool(), and OpenProtocol() with CloseProtocol().\r
+  Since ControllerHandle may have been previously started by the same driver, if a protocol is\r
+  already in the opened state, then it must not be closed with CloseProtocol(). This is required\r
+  to guarantee the state of ControllerHandle is not modified by this function.\r
+\r
+  @param[in]  This                 A pointer to the EFI_DRIVER_BINDING_PROTOCOL instance.\r
+  @param[in]  ControllerHandle     The handle of the controller to test. This handle\r
+                                   must support a protocol interface that supplies\r
+                                   an I/O abstraction to the driver.\r
+  @param[in]  RemainingDevicePath  A pointer to the remaining portion of a device path.  This\r
+                                   parameter is ignored by device drivers, and is optional for bus\r
+                                   drivers. For bus drivers, if this parameter is not NULL, then\r
+                                   the bus driver must determine if the bus controller specified\r
+                                   by ControllerHandle and the child controller specified\r
+                                   by RemainingDevicePath are both supported by this\r
+                                   bus driver.\r
+\r
+  @retval EFI_SUCCESS              The device specified by ControllerHandle and\r
+                                   RemainingDevicePath is supported by the driver specified by This.\r
+  @retval EFI_ALREADY_STARTED      The device specified by ControllerHandle and\r
+                                   RemainingDevicePath is already being managed by the driver\r
+                                   specified by This.\r
+  @retval EFI_ACCESS_DENIED        The device specified by ControllerHandle and\r
+                                   RemainingDevicePath is already being managed by a different\r
+                                   driver or an application that requires exclusive access.\r
+                                   Currently not implemented.\r
+  @retval EFI_UNSUPPORTED          The device specified by ControllerHandle and\r
+                                   RemainingDevicePath is not supported by the driver specified by This.\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+SdDxeDriverBindingSupported (\r
+  IN EFI_DRIVER_BINDING_PROTOCOL   *This,\r
+  IN EFI_HANDLE                    Controller,\r
+  IN EFI_DEVICE_PATH_PROTOCOL      *RemainingDevicePath\r
+  );\r
+\r
+/**\r
+  Starts a device controller or a bus controller.\r
+\r
+  The Start() function is designed to be invoked from the EFI boot service ConnectController().\r
+  As a result, much of the error checking on the parameters to Start() has been moved into this\r
+  common boot service. It is legal to call Start() from other locations,\r
+  but the following calling restrictions must be followed or the system behavior will not be deterministic.\r
+  1. ControllerHandle must be a valid EFI_HANDLE.\r
+  2. If RemainingDevicePath is not NULL, then it must be a pointer to a naturally aligned\r
+     EFI_DEVICE_PATH_PROTOCOL.\r
+  3. Prior to calling Start(), the Supported() function for the driver specified by This must\r
+     have been called with the same calling parameters, and Supported() must have returned EFI_SUCCESS.\r
+\r
+  @param[in]  This                 A pointer to the EFI_DRIVER_BINDING_PROTOCOL instance.\r
+  @param[in]  ControllerHandle     The handle of the controller to start. This handle\r
+                                   must support a protocol interface that supplies\r
+                                   an I/O abstraction to the driver.\r
+  @param[in]  RemainingDevicePath  A pointer to the remaining portion of a device path.  This\r
+                                   parameter is ignored by device drivers, and is optional for bus\r
+                                   drivers. For a bus driver, if this parameter is NULL, then handles\r
+                                   for all the children of Controller are created by this driver.\r
+                                   If this parameter is not NULL and the first Device Path Node is\r
+                                   not the End of Device Path Node, then only the handle for the\r
+                                   child device specified by the first Device Path Node of\r
+                                   RemainingDevicePath is created by this driver.\r
+                                   If the first Device Path Node of RemainingDevicePath is\r
+                                   the End of Device Path Node, no child handle is created by this\r
+                                   driver.\r
+\r
+  @retval EFI_SUCCESS              The device was started.\r
+  @retval EFI_DEVICE_ERROR         The device could not be started due to a device error.Currently not implemented.\r
+  @retval EFI_OUT_OF_RESOURCES     The request could not be completed due to a lack of resources.\r
+  @retval Others                   The driver failded to start the device.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+SdDxeDriverBindingStart (\r
+  IN EFI_DRIVER_BINDING_PROTOCOL   *This,\r
+  IN EFI_HANDLE                    Controller,\r
+  IN EFI_DEVICE_PATH_PROTOCOL      *RemainingDevicePath\r
+  );\r
+\r
+/**\r
+  Stops a device controller or a bus controller.\r
+\r
+  The Stop() function is designed to be invoked from the EFI boot service DisconnectController().\r
+  As a result, much of the error checking on the parameters to Stop() has been moved\r
+  into this common boot service. It is legal to call Stop() from other locations,\r
+  but the following calling restrictions must be followed or the system behavior will not be deterministic.\r
+  1. ControllerHandle must be a valid EFI_HANDLE that was used on a previous call to this\r
+     same driver's Start() function.\r
+  2. The first NumberOfChildren handles of ChildHandleBuffer must all be a valid\r
+     EFI_HANDLE. In addition, all of these handles must have been created in this driver's\r
+     Start() function, and the Start() function must have called OpenProtocol() on\r
+     ControllerHandle with an Attribute of EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER.\r
+\r
+  @param[in]  This              A pointer to the EFI_DRIVER_BINDING_PROTOCOL instance.\r
+  @param[in]  ControllerHandle  A handle to the device being stopped. The handle must\r
+                                support a bus specific I/O protocol for the driver\r
+                                to use to stop the device.\r
+  @param[in]  NumberOfChildren  The number of child device handles in ChildHandleBuffer.\r
+  @param[in]  ChildHandleBuffer An array of child handles to be freed. May be NULL\r
+                                if NumberOfChildren is 0.\r
+\r
+  @retval EFI_SUCCESS           The device was stopped.\r
+  @retval EFI_DEVICE_ERROR      The device could not be stopped due to a device error.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+SdDxeDriverBindingStop (\r
+  IN  EFI_DRIVER_BINDING_PROTOCOL     *This,\r
+  IN  EFI_HANDLE                      Controller,\r
+  IN  UINTN                           NumberOfChildren,\r
+  IN  EFI_HANDLE                      *ChildHandleBuffer\r
+  );\r
+\r
+/**\r
+  Retrieves a Unicode string that is the user readable name of the driver.\r
+\r
+  This function retrieves the user readable name of a driver in the form of a\r
+  Unicode string. If the driver specified by This has a user readable name in\r
+  the language specified by Language, then a pointer to the driver name is\r
+  returned in DriverName, and EFI_SUCCESS is returned. If the driver specified\r
+  by This does not support the language specified by Language,\r
+  then EFI_UNSUPPORTED is returned.\r
+\r
+  @param  This[in]              A pointer to the EFI_COMPONENT_NAME2_PROTOCOL or\r
+                                EFI_COMPONENT_NAME_PROTOCOL instance.\r
+\r
+  @param  Language[in]          A pointer to a Null-terminated ASCII string\r
+                                array indicating the language. This is the\r
+                                language of the driver name that the caller is\r
+                                requesting, and it must match one of the\r
+                                languages specified in SupportedLanguages. The\r
+                                number of languages supported by a driver is up\r
+                                to the driver writer. Language is specified\r
+                                in RFC 4646 or ISO 639-2 language code format.\r
+\r
+  @param  DriverName[out]       A pointer to the Unicode string to return.\r
+                                This Unicode string is the name of the\r
+                                driver specified by This in the language\r
+                                specified by Language.\r
+\r
+  @retval EFI_SUCCESS           The Unicode string for the Driver specified by\r
+                                This and the language specified by Language was\r
+                                returned in DriverName.\r
+\r
+  @retval EFI_INVALID_PARAMETER Language is NULL.\r
+\r
+  @retval EFI_INVALID_PARAMETER DriverName is NULL.\r
+\r
+  @retval EFI_UNSUPPORTED       The driver specified by This does not support\r
+                                the language specified by Language.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+SdDxeComponentNameGetDriverName (\r
+  IN  EFI_COMPONENT_NAME_PROTOCOL  *This,\r
+  IN  CHAR8                        *Language,\r
+  OUT CHAR16                       **DriverName\r
+  );\r
+\r
+/**\r
+  Retrieves a Unicode string that is the user readable name of the controller\r
+  that is being managed by a driver.\r
+\r
+  This function retrieves the user readable name of the controller specified by\r
+  ControllerHandle and ChildHandle in the form of a Unicode string. If the\r
+  driver specified by This has a user readable name in the language specified by\r
+  Language, then a pointer to the controller name is returned in ControllerName,\r
+  and EFI_SUCCESS is returned.  If the driver specified by This is not currently\r
+  managing the controller specified by ControllerHandle and ChildHandle,\r
+  then EFI_UNSUPPORTED is returned.  If the driver specified by This does not\r
+  support the language specified by Language, then EFI_UNSUPPORTED is returned.\r
+\r
+  @param  This[in]              A pointer to the EFI_COMPONENT_NAME2_PROTOCOL or\r
+                                EFI_COMPONENT_NAME_PROTOCOL instance.\r
+\r
+  @param  ControllerHandle[in]  The handle of a controller that the driver\r
+                                specified by This is managing.  This handle\r
+                                specifies the controller whose name is to be\r
+                                returned.\r
+\r
+  @param  ChildHandle[in]       The handle of the child controller to retrieve\r
+                                the name of.  This is an optional parameter that\r
+                                may be NULL.  It will be NULL for device\r
+                                drivers.  It will also be NULL for a bus drivers\r
+                                that wish to retrieve the name of the bus\r
+                                controller.  It will not be NULL for a bus\r
+                                driver that wishes to retrieve the name of a\r
+                                child controller.\r
+\r
+  @param  Language[in]          A pointer to a Null-terminated ASCII string\r
+                                array indicating the language.  This is the\r
+                                language of the driver name that the caller is\r
+                                requesting, and it must match one of the\r
+                                languages specified in SupportedLanguages. The\r
+                                number of languages supported by a driver is up\r
+                                to the driver writer. Language is specified in\r
+                                RFC 4646 or ISO 639-2 language code format.\r
+\r
+  @param  ControllerName[out]   A pointer to the Unicode string to return.\r
+                                This Unicode string is the name of the\r
+                                controller specified by ControllerHandle and\r
+                                ChildHandle in the language specified by\r
+                                Language from the point of view of the driver\r
+                                specified by This.\r
+\r
+  @retval EFI_SUCCESS           The Unicode string for the user readable name in\r
+                                the language specified by Language for the\r
+                                driver specified by This was returned in\r
+                                DriverName.\r
+\r
+  @retval EFI_INVALID_PARAMETER ControllerHandle is NULL.\r
+\r
+  @retval EFI_INVALID_PARAMETER ChildHandle is not NULL and it is not a valid\r
+                                EFI_HANDLE.\r
+\r
+  @retval EFI_INVALID_PARAMETER Language is NULL.\r
+\r
+  @retval EFI_INVALID_PARAMETER ControllerName is NULL.\r
+\r
+  @retval EFI_UNSUPPORTED       The driver specified by This is not currently\r
+                                managing the controller specified by\r
+                                ControllerHandle and ChildHandle.\r
+\r
+  @retval EFI_UNSUPPORTED       The driver specified by This does not support\r
+                                the language specified by Language.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+SdDxeComponentNameGetControllerName (\r
+  IN  EFI_COMPONENT_NAME_PROTOCOL                     *This,\r
+  IN  EFI_HANDLE                                      ControllerHandle,\r
+  IN  EFI_HANDLE                                      ChildHandle        OPTIONAL,\r
+  IN  CHAR8                                           *Language,\r
+  OUT CHAR16                                          **ControllerName\r
+  );\r
+\r
+/**\r
+  Send command SET_RELATIVE_ADDRESS to the device to set the device address.\r
+\r
+  @param[in]  Device            A pointer to the SD_DEVICE instance.\r
+  @param[out] Rca               The relative device address to assign.\r
+\r
+  @retval EFI_SUCCESS           The request is executed successfully.\r
+  @retval EFI_OUT_OF_RESOURCES  The request could not be executed due to a lack of resources.\r
+  @retval Others                The request could not be executed successfully.\r
+\r
+**/\r
+EFI_STATUS\r
+SdSetRca (\r
+  IN     SD_DEVICE              *Device,\r
+     OUT UINT16                 *Rca\r
+  );\r
+\r
+/**\r
+  Send command SELECT to the device to select/deselect the device.\r
+\r
+  @param[in]  Device            A pointer to the SD_DEVICE instance.\r
+  @param[in]  Rca               The relative device address to use.\r
+\r
+  @retval EFI_SUCCESS           The request is executed successfully.\r
+  @retval EFI_OUT_OF_RESOURCES  The request could not be executed due to a lack of resources.\r
+  @retval Others                The request could not be executed successfully.\r
+\r
+**/\r
+EFI_STATUS\r
+SdSelect (\r
+  IN     SD_DEVICE              *Device,\r
+  IN     UINT16                 Rca\r
+  );\r
+\r
+/**\r
+  Send command SEND_STATUS to the device to get device status.\r
+\r
+  @param[in]  Device            A pointer to the SD_DEVICE instance.\r
+  @param[in]  Rca               The relative device address to use.\r
+  @param[out] DevStatus         The buffer to store the device status.\r
+  @retval EFI_SUCCESS           The request is executed successfully.\r
+  @retval EFI_OUT_OF_RESOURCES  The request could not be executed due to a lack of resources.\r
+  @retval Others                The request could not be executed successfully.\r
+\r
+**/\r
+EFI_STATUS\r
+SdSendStatus (\r
+  IN     SD_DEVICE              *Device,\r
+  IN     UINT16                 Rca,\r
+     OUT UINT32                 *DevStatus\r
+  );\r
+\r
+/**\r
+  Send command SEND_CSD to the device to get the CSD register data.\r
+\r
+  @param[in]  Device            A pointer to the SD_DEVICE instance.\r
+  @param[in]  Rca               The relative device address to use.\r
+  @param[out] Csd               The buffer to store the SD_CSD register data.\r
+\r
+  @retval EFI_SUCCESS           The request is executed successfully.\r
+  @retval EFI_OUT_OF_RESOURCES  The request could not be executed due to a lack of resources.\r
+  @retval Others                The request could not be executed successfully.\r
+\r
+**/\r
+EFI_STATUS\r
+SdGetCsd (\r
+  IN     SD_DEVICE              *Device,\r
+  IN     UINT16                 Rca,\r
+     OUT SD_CSD                 *Csd\r
+  );\r
+\r
+/**\r
+  Send command SEND_CID to the device to get the CID register data.\r
+\r
+  @param[in]  Device            A pointer to the SD_DEVICE instance.\r
+  @param[in]  Rca               The relative device address to use.\r
+  @param[out] Cid               The buffer to store the SD_CID register data.\r
+\r
+  @retval EFI_SUCCESS           The request is executed successfully.\r
+  @retval EFI_OUT_OF_RESOURCES  The request could not be executed due to a lack of resources.\r
+  @retval Others                The request could not be executed successfully.\r
+\r
+**/\r
+EFI_STATUS\r
+SdGetCid (\r
+  IN     SD_DEVICE              *Device,\r
+  IN     UINT16                 Rca,\r
+     OUT SD_CID                 *Cid\r
+  );\r
+\r
+#endif\r
+\r
diff --git a/MdeModulePkg/Bus/Sd/SdDxe/SdDxe.inf b/MdeModulePkg/Bus/Sd/SdDxe/SdDxe.inf
new file mode 100644 (file)
index 0000000..b24b721
--- /dev/null
@@ -0,0 +1,65 @@
+## @file\r
+#  SdDxe driver is used to manage the SD memory card device.\r
+#\r
+#  It produces BlockIo and BlockIo2 protocols to allow upper layer\r
+#  access the SD memory card device.\r
+#\r
+#  Copyright (c) 2015, Intel Corporation. All rights reserved.<BR>\r
+#\r
+#  This program and the accompanying materials\r
+#  are licensed and made available under the terms and conditions of the BSD License\r
+#  which accompanies this distribution. The full text of the license may be found at\r
+#  http://opensource.org/licenses/bsd-license.php\r
+#  THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+#  WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+#\r
+#\r
+##\r
+\r
+[Defines]\r
+  INF_VERSION                    = 0x00010005\r
+  BASE_NAME                      = SdDxe\r
+  MODULE_UNI_FILE                = SdDxe.uni\r
+  FILE_GUID                      = 430AC2F7-EEC6-4093-94F7-9F825A7C1C40\r
+  MODULE_TYPE                    = UEFI_DRIVER\r
+  VERSION_STRING                 = 1.0\r
+  ENTRY_POINT                    = InitializeSdDxe\r
+\r
+#\r
+# The following information is for reference only and not required by the build tools.\r
+#\r
+#  VALID_ARCHITECTURES           = IA32 X64 IPF EBC\r
+#\r
+#  DRIVER_BINDING                =  gSdDxeDriverBinding\r
+#  COMPONENT_NAME                =  gSdDxeComponentName\r
+#  COMPONENT_NAME2               =  gSdDxeComponentName2\r
+#\r
+\r
+[Sources.common]\r
+  ComponentName.c\r
+  SdDxe.c\r
+  SdDxe.h\r
+  SdBlockIo.c\r
+  SdBlockIo.h\r
+\r
+[Packages]\r
+  MdePkg/MdePkg.dec\r
+\r
+[LibraryClasses]\r
+  DevicePathLib\r
+  UefiBootServicesTableLib\r
+  MemoryAllocationLib\r
+  BaseMemoryLib\r
+  UefiLib\r
+  BaseLib\r
+  UefiDriverEntryPoint\r
+  DebugLib\r
+\r
+[Protocols]\r
+  gEfiSdMmcPassThruProtocolGuid                ## TO_START\r
+  gEfiBlockIoProtocolGuid                      ## BY_START\r
+  gEfiBlockIo2ProtocolGuid                     ## BY_START\r
+  ## TO_START\r
+  ## BY_START\r
+  gEfiDevicePathProtocolGuid\r
+\r
diff --git a/MdeModulePkg/Bus/Sd/SdDxe/SdDxe.uni b/MdeModulePkg/Bus/Sd/SdDxe/SdDxe.uni
new file mode 100644 (file)
index 0000000..dc77ab8
--- /dev/null
@@ -0,0 +1,20 @@
+// /** @file\r
+// SD memory card device driver to manage the SD memory card device and provide interface for upper layer\r
+// access.\r
+//\r
+// Copyright (c) 2015, Intel Corporation. All rights reserved.<BR>\r
+//\r
+// This program and the accompanying materials\r
+// are licensed and made available under the terms and conditions of the BSD License\r
+// which accompanies this distribution. The full text of the license may be found at\r
+// http://opensource.org/licenses/bsd-license.php\r
+// THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+// WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+//\r
+// **/\r
+\r
+\r
+#string STR_MODULE_ABSTRACT             #language en-US "SD device driver to manage the SD memory card device and provide interface for upper layer access"\r
+\r
+#string STR_MODULE_DESCRIPTION          #language en-US "This driver follows the UEFI driver model and layers on the SdMmcPassThru protocol. It installs BlockIo and BlockIo2 protocols on the SD device."\r
+\r
diff --git a/MdeModulePkg/Bus/Sd/SdDxe/SdDxeExtra.uni b/MdeModulePkg/Bus/Sd/SdDxe/SdDxeExtra.uni
new file mode 100644 (file)
index 0000000..dc77ab8
--- /dev/null
@@ -0,0 +1,20 @@
+// /** @file\r
+// SD memory card device driver to manage the SD memory card device and provide interface for upper layer\r
+// access.\r
+//\r
+// Copyright (c) 2015, Intel Corporation. All rights reserved.<BR>\r
+//\r
+// This program and the accompanying materials\r
+// are licensed and made available under the terms and conditions of the BSD License\r
+// which accompanies this distribution. The full text of the license may be found at\r
+// http://opensource.org/licenses/bsd-license.php\r
+// THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+// WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+//\r
+// **/\r
+\r
+\r
+#string STR_MODULE_ABSTRACT             #language en-US "SD device driver to manage the SD memory card device and provide interface for upper layer access"\r
+\r
+#string STR_MODULE_DESCRIPTION          #language en-US "This driver follows the UEFI driver model and layers on the SdMmcPassThru protocol. It installs BlockIo and BlockIo2 protocols on the SD device."\r
+\r
diff --git a/MdeModulePkg/Include/Ppi/SdMmcHostController.h b/MdeModulePkg/Include/Ppi/SdMmcHostController.h
new file mode 100644 (file)
index 0000000..85dee24
--- /dev/null
@@ -0,0 +1,64 @@
+/** @file\r
+\r
+Copyright (c) 2015, Intel Corporation. All rights reserved.<BR>\r
+\r
+This program and the accompanying materials\r
+are licensed and made available under the terms and conditions\r
+of the BSD License which accompanies this distribution.  The\r
+full text of the license may be found at\r
+http://opensource.org/licenses/bsd-license.php\r
+\r
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+\r
+**/\r
+\r
+#ifndef _EDKII_PEI_SD_MMC_HOST_CONTROLLER_PPI_H_\r
+#define _EDKII_PEI_SD_MMC_HOST_CONTROLLER_PPI_H_\r
+\r
+///\r
+/// Global ID for the EDKII_SD_MMC_HOST_CONTROLLER_PPI.\r
+///\r
+#define EDKII_SD_MMC_HOST_CONTROLLER_PPI_GUID \\r
+  { \\r
+    0xb30dfeed, 0x947f, 0x4396, { 0xb1, 0x5a, 0xdf, 0xbd, 0xb9, 0x16, 0xdc, 0x24 } \\r
+  }\r
+\r
+///\r
+/// Forward declaration for the SD_MMC_HOST_CONTROLLER_PPI.\r
+///\r
+typedef struct _EDKII_SD_MMC_HOST_CONTROLLER_PPI  EDKII_SD_MMC_HOST_CONTROLLER_PPI;\r
+\r
+/**\r
+  Get the MMIO base address of SD/MMC host controller.\r
+\r
+  @param[in]     This            The protocol instance pointer.\r
+  @param[in]     ControllerId    The ID of the SD/MMC host controller.\r
+  @param[in,out] MmioBar         The pointer to store the array of available\r
+                                 SD/MMC host controller slot MMIO base addresses.\r
+                                 The entry number of the array is specified by BarNum.\r
+  @param[out]    BarNum          The pointer to store the supported bar number.\r
+\r
+  @retval EFI_SUCCESS            The operation succeeds.\r
+  @retval EFI_INVALID_PARAMETER  The parameters are invalid.\r
+\r
+**/\r
+typedef\r
+EFI_STATUS\r
+(EFIAPI *EDKII_SD_MMC_HC_GET_MMIO_BAR)(\r
+  IN     EDKII_SD_MMC_HOST_CONTROLLER_PPI *This,\r
+  IN     UINT8                            ControllerId,\r
+  IN OUT UINTN                            **MmioBar,\r
+     OUT UINT8                            *BarNum\r
+  );\r
+\r
+///\r
+/// This PPI contains a set of services to interact with the SD_MMC host controller.\r
+///\r
+struct _EDKII_SD_MMC_HOST_CONTROLLER_PPI {\r
+  EDKII_SD_MMC_HC_GET_MMIO_BAR               GetSdMmcHcMmioBar;\r
+};\r
+\r
+extern EFI_GUID gEdkiiPeiSdMmcHostControllerPpiGuid;\r
+\r
+#endif\r
index 1a205617a5399f07d1ade8b42f46771e38ca0663..aa9e8066d8a6b90be2c4b8d9d48515e60dbcd79e 100644 (file)
   ## Include/Ppi/IpmiPpi.h\r
   gPeiIpmiPpiGuid               =  { 0xa9731431, 0xd968, 0x4277, { 0xb7, 0x52, 0xa3, 0xa9, 0xa6, 0xae, 0x18, 0x98 }}\r
 \r
+  ## Include/Ppi/SdMmcHostController.h\r
+  gEdkiiPeiSdMmcHostControllerPpiGuid = { 0xb30dfeed, 0x947f, 0x4396, { 0xb1, 0x5a, 0xdf, 0xbd, 0xb9, 0x16, 0xdc, 0x24 }}\r
+\r
 [Protocols]\r
   ## Load File protocol provides capability to load and unload EFI image into memory and execute it.\r
   #  Include/Protocol/LoadPe32Image.h\r
   # @Prompt Set NX for stack.\r
   gEfiMdeModulePkgTokenSpaceGuid.PcdSetNxForStack|FALSE|BOOLEAN|0x0001006f\r
 \r
+  ## This PCD specifies the PCI-based SD/MMC host controller mmio base address.\r
+  # Define the mmio base address of the pci-based SD/MMC host controller. If there are multiple SD/MMC\r
+  # host controllers, their mmio base addresses are calculated one by one from this base address.\r
+  # @Prompt Mmio base address of pci-based SD/MMC host controller.\r
+  gEfiMdeModulePkgTokenSpaceGuid.PcdSdMmcPciHostControllerMmioBase|0xd0000000|UINT32|0x30001043\r
+\r
 [PcdsPatchableInModule]\r
   ## Specify memory size with page number for PEI code when\r
   #  Loading Module at Fixed Address feature is enabled.\r
index 0b54030f5b0429b417085bff507d8a4bcba81648..b1ece7b2cf452e6866f4c951fdc8e97e03d1c511 100644 (file)
   MdeModulePkg/Bus/Pci/PciBusDxe/PciBusDxe.inf\r
   MdeModulePkg/Bus/Pci/IncompatiblePciDeviceSupportDxe/IncompatiblePciDeviceSupportDxe.inf\r
   MdeModulePkg/Bus/Pci/NvmExpressDxe/NvmExpressDxe.inf\r
+  MdeModulePkg/Bus/Pci/SdMmcPciHcDxe/SdMmcPciHcDxe.inf\r
+  MdeModulePkg/Bus/Pci/SdMmcPciHcPei/SdMmcPciHcPei.inf\r
+  MdeModulePkg/Bus/Sd/EmmcBlockIoPei/EmmcBlockIoPei.inf\r
+  MdeModulePkg/Bus/Sd/SdBlockIoPei/SdBlockIoPei.inf\r
+  MdeModulePkg/Bus/Sd/EmmcDxe/EmmcDxe.inf\r
+  MdeModulePkg/Bus/Sd/SdDxe/SdDxe.inf\r
   MdeModulePkg/Bus/Pci/UfsPciHcDxe/UfsPciHcDxe.inf\r
   MdeModulePkg/Bus/Ufs/UfsPassThruDxe/UfsPassThruDxe.inf\r
   MdeModulePkg/Bus/Pci/UfsPciHcPei/UfsPciHcPei.inf\r