]> git.proxmox.com Git - mirror_edk2.git/blobdiff - MdeModulePkg/Bus/Pci/SdMmcPciHcDxe/SdMmcPciHci.c
MdeModulePkg/SdMmcHcDxe: Implement revision 3 of SdMmcOverrideProtocol
[mirror_edk2.git] / MdeModulePkg / Bus / Pci / SdMmcPciHcDxe / SdMmcPciHci.c
index 3b9a184bc4efcdd504a70ed1bd579fc8f14e368d..b9d04e0f17a20d6212860f654b6d78f4eeaefcdb 100644 (file)
@@ -1,17 +1,14 @@
 /** @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
+  with SD Host Controller Simplified Specification version 3.00 plus the 64-bit\r
+  System Addressing support in SD Host Controller Simplified Specification version\r
+  4.20.\r
 \r
   It would expose EFI_SD_MMC_PASS_THRU_PROTOCOL for upper layer use.\r
 \r
-  Copyright (c) 2015 - 2017, 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
+  Copyright (c) 2018-2019, NVIDIA CORPORATION. All rights reserved.\r
+  Copyright (c) 2015 - 2019, Intel Corporation. All rights reserved.<BR>\r
+  SPDX-License-Identifier: BSD-2-Clause-Patent\r
 \r
 **/\r
 \r
@@ -45,7 +42,8 @@ DumpCapabilityReg (
   DEBUG ((DEBUG_INFO, "   Voltage 3.3       %a\n", Capability->Voltage33 ? "TRUE" : "FALSE"));\r
   DEBUG ((DEBUG_INFO, "   Voltage 3.0       %a\n", Capability->Voltage30 ? "TRUE" : "FALSE"));\r
   DEBUG ((DEBUG_INFO, "   Voltage 1.8       %a\n", Capability->Voltage18 ? "TRUE" : "FALSE"));\r
-  DEBUG ((DEBUG_INFO, "   64-bit Sys Bus    %a\n", Capability->SysBus64 ? "TRUE" : "FALSE"));\r
+  DEBUG ((DEBUG_INFO, "   V4 64-bit Sys Bus %a\n", Capability->SysBus64V4 ? "TRUE" : "FALSE"));\r
+  DEBUG ((DEBUG_INFO, "   V3 64-bit Sys Bus %a\n", Capability->SysBus64V3 ? "TRUE" : "FALSE"));\r
   DEBUG ((DEBUG_INFO, "   Async Interrupt   %a\n", Capability->AsyncInt ? "TRUE" : "FALSE"));\r
   DEBUG ((DEBUG_INFO, "   SlotType          "));\r
   if (Capability->SlotType == 0x00) {\r
@@ -150,19 +148,36 @@ SdMmcHcRwMmio (
   )\r
 {\r
   EFI_STATUS                   Status;\r
+  EFI_PCI_IO_PROTOCOL_WIDTH    Width;\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
+  switch (Count) {\r
+    case 1:\r
+      Width = EfiPciIoWidthUint8;\r
+      break;\r
+    case 2:\r
+      Width = EfiPciIoWidthUint16;\r
+      Count = 1;\r
+      break;\r
+    case 4:\r
+      Width = EfiPciIoWidthUint32;\r
+      Count = 1;\r
+      break;\r
+    case 8:\r
+      Width = EfiPciIoWidthUint32;\r
+      Count = 2;\r
+      break;\r
+    default:\r
+      return EFI_INVALID_PARAMETER;\r
   }\r
 \r
   if (Read) {\r
     Status = PciIo->Mem.Read (\r
                           PciIo,\r
-                          EfiPciIoWidthUint8,\r
+                          Width,\r
                           BarIndex,\r
                           (UINT64) Offset,\r
                           Count,\r
@@ -171,7 +186,7 @@ SdMmcHcRwMmio (
   } else {\r
     Status = PciIo->Mem.Write (\r
                           PciIo,\r
-                          EfiPciIoWidthUint8,\r
+                          Width,\r
                           BarIndex,\r
                           (UINT64) Offset,\r
                           Count,\r
@@ -416,6 +431,36 @@ SdMmcHcWaitMmioSet (
   return EFI_TIMEOUT;\r
 }\r
 \r
+/**\r
+  Get the controller version information 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] Version         The buffer to store the version information.\r
+\r
+  @retval EFI_SUCCESS         The operation executes successfully.\r
+  @retval Others              The operation fails.\r
+\r
+**/\r
+EFI_STATUS\r
+SdMmcHcGetControllerVersion (\r
+  IN     EFI_PCI_IO_PROTOCOL  *PciIo,\r
+  IN     UINT8                Slot,\r
+  OUT    UINT16               *Version\r
+  )\r
+{\r
+  EFI_STATUS                Status;\r
+\r
+  Status = SdMmcHcRwMmio (PciIo, Slot, SD_MMC_HC_CTRL_VER, TRUE, sizeof (UINT16), Version);\r
+  if (EFI_ERROR (Status)) {\r
+    return Status;\r
+  }\r
+\r
+  *Version &= 0xFF;\r
+\r
+  return EFI_SUCCESS;\r
+}\r
+\r
 /**\r
   Software reset the specified SD/MMC host controller and enable all interrupts.\r
 \r
@@ -444,7 +489,8 @@ SdMmcHcReset (
     Status = mOverride->NotifyPhase (\r
                           Private->ControllerHandle,\r
                           Slot,\r
-                          EdkiiSdMmcResetPre);\r
+                          EdkiiSdMmcResetPre,\r
+                          NULL);\r
     if (EFI_ERROR (Status)) {\r
       DEBUG ((DEBUG_WARN,\r
         "%a: SD/MMC pre reset notifier callback failed - %r\n",\r
@@ -494,7 +540,8 @@ SdMmcHcReset (
     Status = mOverride->NotifyPhase (\r
                           Private->ControllerHandle,\r
                           Slot,\r
-                          EdkiiSdMmcResetPost);\r
+                          EdkiiSdMmcResetPost,\r
+                          NULL);\r
     if (EFI_ERROR (Status)) {\r
       DEBUG ((DEBUG_WARN,\r
         "%a: SD/MMC post reset notifier callback failed - %r\n",\r
@@ -719,7 +766,8 @@ SdMmcHcStopClock (
   @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
+  @param[in] BaseClkFreq    The base clock frequency of host controller in MHz.\r
+  @param[in] ControllerVer  The version of host controller.\r
 \r
   @retval EFI_SUCCESS       The clock is supplied successfully.\r
   @retval Others            The clock isn't supplied successfully.\r
@@ -730,23 +778,21 @@ SdMmcHcClockSupply (
   IN EFI_PCI_IO_PROTOCOL    *PciIo,\r
   IN UINT8                  Slot,\r
   IN UINT64                 ClockFreq,\r
-  IN SD_MMC_HC_SLOT_CAP     Capability\r
+  IN UINT32                 BaseClkFreq,\r
+  IN UINT16                 ControllerVer\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
+  ASSERT (BaseClkFreq != 0);\r
 \r
-  BaseClkFreq = Capability.BaseClkFreq;\r
   if (ClockFreq == 0) {\r
     return EFI_INVALID_PARAMETER;\r
   }\r
@@ -775,17 +821,15 @@ SdMmcHcClockSupply (
 \r
   DEBUG ((DEBUG_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) == SD_MMC_HC_CTRL_VER_300) {\r
+  if ((ControllerVer >= SD_MMC_HC_CTRL_VER_300) &&\r
+      (ControllerVer <= SD_MMC_HC_CTRL_VER_420)) {\r
     ASSERT (Divisor <= 0x3FF);\r
     ClockCtrl = ((Divisor & 0xFF) << 8) | ((Divisor & 0x300) >> 2);\r
-  } else if (((ControllerVer & 0xFF) == 0) || ((ControllerVer & 0xFF) == 1)) {\r
+  } else if ((ControllerVer == SD_MMC_HC_CTRL_VER_100) ||\r
+             (ControllerVer == SD_MMC_HC_CTRL_VER_200)) {\r
     //\r
     // Only the most significant bit can be used as divisor.\r
     //\r
@@ -933,11 +977,74 @@ SdMmcHcSetBusWidth (
 }\r
 \r
 /**\r
-  Supply SD/MMC card with lowest clock frequency at initialization.\r
+  Configure V4 controller enhancements 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
+  @param[in] ControllerVer  The version of host controller.\r
+\r
+  @retval EFI_SUCCESS       The clock is supplied successfully.\r
+\r
+**/\r
+EFI_STATUS\r
+SdMmcHcInitV4Enhancements (\r
+  IN EFI_PCI_IO_PROTOCOL    *PciIo,\r
+  IN UINT8                  Slot,\r
+  IN SD_MMC_HC_SLOT_CAP     Capability,\r
+  IN UINT16                 ControllerVer\r
+  )\r
+{\r
+  EFI_STATUS                Status;\r
+  UINT16                    HostCtrl2;\r
+\r
+  //\r
+  // Check if controller version V4 or higher\r
+  //\r
+  if (ControllerVer >= SD_MMC_HC_CTRL_VER_400) {\r
+    HostCtrl2 = SD_MMC_HC_V4_EN;\r
+    //\r
+    // Check if controller version V4.0\r
+    //\r
+    if (ControllerVer == SD_MMC_HC_CTRL_VER_400) {\r
+      //\r
+      // Check if 64bit support is available\r
+      //\r
+      if (Capability.SysBus64V3 != 0) {\r
+        HostCtrl2 |= SD_MMC_HC_64_ADDR_EN;\r
+        DEBUG ((DEBUG_INFO, "Enabled V4 64 bit system bus support\n"));\r
+      }\r
+    }\r
+    //\r
+    // Check if controller version V4.10 or higher\r
+    //\r
+    else if (ControllerVer >= SD_MMC_HC_CTRL_VER_410) {\r
+      //\r
+      // Check if 64bit support is available\r
+      //\r
+      if (Capability.SysBus64V4 != 0) {\r
+        HostCtrl2 |= SD_MMC_HC_64_ADDR_EN;\r
+        DEBUG ((DEBUG_INFO, "Enabled V4 64 bit system bus support\n"));\r
+      }\r
+      HostCtrl2 |= SD_MMC_HC_26_DATA_LEN_ADMA_EN;\r
+      DEBUG ((DEBUG_INFO, "Enabled V4 26 bit data length ADMA support\n"));\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
+\r
+  return EFI_SUCCESS;\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] BaseClkFreq    The base clock frequency of host controller in MHz.\r
+  @param[in] ControllerVer  The version of host controller.\r
 \r
   @retval EFI_SUCCESS       The clock is supplied successfully.\r
   @retval Others            The clock isn't supplied successfully.\r
@@ -947,16 +1054,20 @@ EFI_STATUS
 SdMmcHcInitClockFreq (\r
   IN EFI_PCI_IO_PROTOCOL    *PciIo,\r
   IN UINT8                  Slot,\r
-  IN SD_MMC_HC_SLOT_CAP     Capability\r
+  IN UINT32                 BaseClkFreq,\r
+  IN UINT16                 ControllerVer\r
   )\r
 {\r
   EFI_STATUS                Status;\r
   UINT32                    InitFreq;\r
 \r
   //\r
-  // Calculate a divisor for SD clock frequency\r
+  // According to SDHCI specification ver. 4.2, BaseClkFreq field value of\r
+  // the Capability Register 1 can be zero, which means a need for obtaining\r
+  // the clock frequency via another method. Fail in case it is not updated\r
+  // by SW at this point.\r
   //\r
-  if (Capability.BaseClkFreq == 0) {\r
+  if (BaseClkFreq == 0) {\r
     //\r
     // Don't support get Base Clock Frequency information via another method\r
     //\r
@@ -966,7 +1077,7 @@ SdMmcHcInitClockFreq (
   // Supply 400KHz clock frequency at initialization phase.\r
   //\r
   InitFreq = 400;\r
-  Status = SdMmcHcClockSupply (PciIo, Slot, InitFreq, Capability);\r
+  Status = SdMmcHcClockSupply (PciIo, Slot, InitFreq, BaseClkFreq, ControllerVer);\r
   return Status;\r
 }\r
 \r
@@ -1087,7 +1198,8 @@ SdMmcHcInitHost (
     Status = mOverride->NotifyPhase (\r
                           Private->ControllerHandle,\r
                           Slot,\r
-                          EdkiiSdMmcInitHostPre);\r
+                          EdkiiSdMmcInitHostPre,\r
+                          NULL);\r
     if (EFI_ERROR (Status)) {\r
       DEBUG ((DEBUG_WARN,\r
         "%a: SD/MMC pre init notifier callback failed - %r\n",\r
@@ -1099,7 +1211,12 @@ SdMmcHcInitHost (
   PciIo = Private->PciIo;\r
   Capability = Private->Capability[Slot];\r
 \r
-  Status = SdMmcHcInitClockFreq (PciIo, Slot, Capability);\r
+  Status = SdMmcHcInitV4Enhancements (PciIo, Slot, Capability, Private->ControllerVersion[Slot]);\r
+  if (EFI_ERROR (Status)) {\r
+    return Status;\r
+  }\r
+\r
+  Status = SdMmcHcInitClockFreq (PciIo, Slot, Private->BaseClkFreq[Slot], Private->ControllerVersion[Slot]);\r
   if (EFI_ERROR (Status)) {\r
     return Status;\r
   }\r
@@ -1122,7 +1239,8 @@ SdMmcHcInitHost (
     Status = mOverride->NotifyPhase (\r
                           Private->ControllerHandle,\r
                           Slot,\r
-                          EdkiiSdMmcInitHostPost);\r
+                          EdkiiSdMmcInitHostPost,\r
+                          NULL);\r
     if (EFI_ERROR (Status)) {\r
       DEBUG ((DEBUG_WARN,\r
         "%a: SD/MMC post init notifier callback failed - %r\n",\r
@@ -1132,6 +1250,129 @@ SdMmcHcInitHost (
   return Status;\r
 }\r
 \r
+/**\r
+  Set SD Host Controler control 2 registry according to selected speed.\r
+\r
+  @param[in] ControllerHandle The handle of the controller.\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] Timing           The timing to select.\r
+\r
+  @retval EFI_SUCCESS         The timing is set successfully.\r
+  @retval Others              The timing isn't set successfully.\r
+**/\r
+EFI_STATUS\r
+SdMmcHcUhsSignaling (\r
+  IN EFI_HANDLE             ControllerHandle,\r
+  IN EFI_PCI_IO_PROTOCOL    *PciIo,\r
+  IN UINT8                  Slot,\r
+  IN SD_MMC_BUS_MODE        Timing\r
+  )\r
+{\r
+  EFI_STATUS                 Status;\r
+  UINT8                      HostCtrl2;\r
+\r
+  HostCtrl2 = (UINT8)~SD_MMC_HC_CTRL_UHS_MASK;\r
+  Status = SdMmcHcAndMmio (PciIo, Slot, SD_MMC_HC_HOST_CTRL2, sizeof (HostCtrl2), &HostCtrl2);\r
+  if (EFI_ERROR (Status)) {\r
+    return Status;\r
+  }\r
+\r
+  switch (Timing) {\r
+    case SdMmcUhsSdr12:\r
+      HostCtrl2 = SD_MMC_HC_CTRL_UHS_SDR12;\r
+      break;\r
+    case SdMmcUhsSdr25:\r
+      HostCtrl2 = SD_MMC_HC_CTRL_UHS_SDR25;\r
+      break;\r
+    case SdMmcUhsSdr50:\r
+      HostCtrl2 = SD_MMC_HC_CTRL_UHS_SDR50;\r
+      break;\r
+    case SdMmcUhsSdr104:\r
+      HostCtrl2 = SD_MMC_HC_CTRL_UHS_SDR104;\r
+      break;\r
+    case SdMmcUhsDdr50:\r
+      HostCtrl2 = SD_MMC_HC_CTRL_UHS_DDR50;\r
+      break;\r
+    case SdMmcMmcLegacy:\r
+      HostCtrl2 = SD_MMC_HC_CTRL_MMC_LEGACY;\r
+      break;\r
+    case SdMmcMmcHsSdr:\r
+      HostCtrl2 = SD_MMC_HC_CTRL_MMC_HS_SDR;\r
+      break;\r
+    case SdMmcMmcHsDdr:\r
+      HostCtrl2 = SD_MMC_HC_CTRL_MMC_HS_DDR;\r
+      break;\r
+    case SdMmcMmcHs200:\r
+      HostCtrl2 = SD_MMC_HC_CTRL_MMC_HS200;\r
+      break;\r
+    case SdMmcMmcHs400:\r
+      HostCtrl2 = SD_MMC_HC_CTRL_MMC_HS400;\r
+      break;\r
+    default:\r
+     HostCtrl2 = 0;\r
+     break;\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
+  if (mOverride != NULL && mOverride->NotifyPhase != NULL) {\r
+    Status = mOverride->NotifyPhase (\r
+                          ControllerHandle,\r
+                          Slot,\r
+                          EdkiiSdMmcUhsSignaling,\r
+                          &Timing\r
+                          );\r
+    if (EFI_ERROR (Status)) {\r
+      DEBUG ((\r
+        DEBUG_ERROR,\r
+        "%a: SD/MMC uhs signaling notifier callback failed - %r\n",\r
+        __FUNCTION__,\r
+        Status\r
+        ));\r
+      return Status;\r
+    }\r
+  }\r
+\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+  Set driver strength in host controller.\r
+\r
+  @param[in] PciIo           The PCI IO protocol instance.\r
+  @param[in] SlotIndex       The slot index of the card.\r
+  @param[in] DriverStrength  DriverStrength to set in the controller.\r
+\r
+  @retval EFI_SUCCESS  Driver strength programmed successfully.\r
+  @retval Others       Failed to set driver strength.\r
+**/\r
+EFI_STATUS\r
+SdMmcSetDriverStrength (\r
+  IN EFI_PCI_IO_PROTOCOL      *PciIo,\r
+  IN UINT8                    SlotIndex,\r
+  IN SD_DRIVER_STRENGTH_TYPE  DriverStrength\r
+  )\r
+{\r
+  EFI_STATUS  Status;\r
+  UINT16      HostCtrl2;\r
+\r
+  if (DriverStrength == SdDriverStrengthIgnore) {\r
+    return EFI_SUCCESS;\r
+  }\r
+\r
+  HostCtrl2 = (UINT16)~SD_MMC_HC_CTRL_DRIVER_STRENGTH_MASK;\r
+  Status = SdMmcHcAndMmio (PciIo, SlotIndex, SD_MMC_HC_HOST_CTRL2, sizeof (HostCtrl2), &HostCtrl2);\r
+  if (EFI_ERROR (Status)) {\r
+    return Status;\r
+  }\r
+\r
+  HostCtrl2 = (DriverStrength << 4) & SD_MMC_HC_CTRL_DRIVER_STRENGTH_MASK;\r
+  return SdMmcHcOrMmio (PciIo, SlotIndex, SD_MMC_HC_HOST_CTRL2, sizeof (HostCtrl2), &HostCtrl2);\r
+}\r
+\r
 /**\r
   Turn on/off LED.\r
 \r
@@ -1167,9 +1408,10 @@ SdMmcHcLedOnOff (
 /**\r
   Build ADMA descriptor table for transfer.\r
 \r
-  Refer to SD Host Controller Simplified spec 3.0 Section 1.13 for details.\r
+  Refer to SD Host Controller Simplified spec 4.2 Section 1.13 for details.\r
 \r
   @param[in] Trb            The pointer to the SD_MMC_HC_TRB instance.\r
+  @param[in] ControllerVer  The version of host controller.\r
 \r
   @retval EFI_SUCCESS       The ADMA descriptor table is created successfully.\r
   @retval Others            The ADMA descriptor table isn't created successfully.\r
@@ -1177,7 +1419,8 @@ SdMmcHcLedOnOff (
 **/\r
 EFI_STATUS\r
 BuildAdmaDescTable (\r
-  IN SD_MMC_HC_TRB          *Trb\r
+  IN SD_MMC_HC_TRB          *Trb,\r
+  IN UINT16                 ControllerVer\r
   )\r
 {\r
   EFI_PHYSICAL_ADDRESS      Data;\r
@@ -1185,49 +1428,84 @@ BuildAdmaDescTable (
   UINT64                    Entries;\r
   UINT32                    Index;\r
   UINT64                    Remaining;\r
-  UINT32                    Address;\r
+  UINT64                    Address;\r
   UINTN                     TableSize;\r
   EFI_PCI_IO_PROTOCOL       *PciIo;\r
   EFI_STATUS                Status;\r
   UINTN                     Bytes;\r
+  UINT32                    AdmaMaxDataPerLine;\r
+  UINT32                    DescSize;\r
+  VOID                      *AdmaDesc;\r
+\r
+  AdmaMaxDataPerLine = ADMA_MAX_DATA_PER_LINE_16B;\r
+  DescSize           = sizeof (SD_MMC_HC_ADMA_32_DESC_LINE);\r
+  AdmaDesc           = NULL;\r
 \r
   Data    = Trb->DataPhy;\r
   DataLen = Trb->DataLen;\r
   PciIo   = Trb->Private->PciIo;\r
+\r
   //\r
-  // Only support 32bit ADMA Descriptor Table\r
+  // Check for valid ranges in 32bit ADMA Descriptor Table\r
   //\r
-  if ((Data >= 0x100000000ul) || ((Data + DataLen) > 0x100000000ul)) {\r
+  if ((Trb->Mode == SdMmcAdma32bMode) &&\r
+      ((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
+  // Check address field alignment\r
+  //\r
+  if (Trb->Mode != SdMmcAdma32bMode) {\r
+    //\r
+    // Address field shall be set on 64-bit boundary (Lower 3-bit is always set to 0)\r
+    //\r
+    if ((Data & (BIT0 | BIT1 | BIT2)) != 0) {\r
+      DEBUG ((DEBUG_INFO, "The buffer [0x%x] to construct ADMA desc is not aligned to 8 bytes boundary!\n", Data));\r
+    }\r
+  } else {\r
+    //\r
+    // Address field shall be set on 32-bit boundary (Lower 2-bit is always set to 0)\r
+    //\r
+    if ((Data & (BIT0 | BIT1)) != 0) {\r
+      DEBUG ((DEBUG_INFO, "The buffer [0x%x] to construct ADMA desc is not aligned to 4 bytes boundary!\n", Data));\r
+    }\r
+  }\r
+\r
+  //\r
+  // Configure 64b ADMA.\r
   //\r
-  if ((Data & (BIT0 | BIT1)) != 0) {\r
-    DEBUG ((DEBUG_INFO, "The buffer [0x%x] to construct ADMA desc is not aligned to 4 bytes boundary!\n", Data));\r
+  if (Trb->Mode == SdMmcAdma64bV3Mode) {\r
+    DescSize = sizeof (SD_MMC_HC_ADMA_64_V3_DESC_LINE);\r
+  }else if (Trb->Mode == SdMmcAdma64bV4Mode) {\r
+    DescSize = sizeof (SD_MMC_HC_ADMA_64_V4_DESC_LINE);\r
+  }\r
+  //\r
+  // Configure 26b data length.\r
+  //\r
+  if (Trb->AdmaLengthMode == SdMmcAdmaLen26b) {\r
+    AdmaMaxDataPerLine = ADMA_MAX_DATA_PER_LINE_26B;\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
+  Entries   = DivU64x32 ((DataLen + AdmaMaxDataPerLine - 1), AdmaMaxDataPerLine);\r
+  TableSize = (UINTN)MultU64x32 (Entries, DescSize);\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
+                    (VOID **)&AdmaDesc,\r
                     0\r
                     );\r
   if (EFI_ERROR (Status)) {\r
     return EFI_OUT_OF_RESOURCES;\r
   }\r
-  ZeroMem (Trb->AdmaDesc, TableSize);\r
+  ZeroMem (AdmaDesc, TableSize);\r
   Bytes  = TableSize;\r
   Status = PciIo->Map (\r
                     PciIo,\r
                     EfiPciIoOperationBusMasterCommonBuffer,\r
-                    Trb->AdmaDesc,\r
+                    AdmaDesc,\r
                     &Bytes,\r
                     &Trb->AdmaDescPhy,\r
                     &Trb->AdmaMap\r
@@ -1240,12 +1518,13 @@ BuildAdmaDescTable (
     PciIo->FreeBuffer (\r
              PciIo,\r
              EFI_SIZE_TO_PAGES (TableSize),\r
-             Trb->AdmaDesc\r
+             AdmaDesc\r
              );\r
     return EFI_OUT_OF_RESOURCES;\r
   }\r
 \r
-  if ((UINT64)(UINTN)Trb->AdmaDescPhy > 0x100000000ul) {\r
+  if ((Trb->Mode == SdMmcAdma32bMode) &&\r
+      (UINT64)(UINTN)Trb->AdmaDescPhy > 0x100000000ul) {\r
     //\r
     // The ADMA doesn't support 64bit addressing.\r
     //\r
@@ -1256,35 +1535,99 @@ BuildAdmaDescTable (
     PciIo->FreeBuffer (\r
       PciIo,\r
       EFI_SIZE_TO_PAGES (TableSize),\r
-      Trb->AdmaDesc\r
+      AdmaDesc\r
     );\r
     return EFI_DEVICE_ERROR;\r
   }\r
 \r
   Remaining = DataLen;\r
-  Address   = (UINT32)Data;\r
+  Address   = Data;\r
+  if (Trb->Mode == SdMmcAdma32bMode) {\r
+    Trb->Adma32Desc = AdmaDesc;\r
+  } else if (Trb->Mode == SdMmcAdma64bV3Mode) {\r
+    Trb->Adma64V3Desc = AdmaDesc;\r
+  } else {\r
+    Trb->Adma64V4Desc = AdmaDesc;\r
+  }\r
+\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
+    if (Trb->Mode == SdMmcAdma32bMode) {\r
+      if (Remaining <= AdmaMaxDataPerLine) {\r
+        Trb->Adma32Desc[Index].Valid = 1;\r
+        Trb->Adma32Desc[Index].Act   = 2;\r
+        if (Trb->AdmaLengthMode == SdMmcAdmaLen26b) {\r
+          Trb->Adma32Desc[Index].UpperLength = (UINT16)RShiftU64 (Remaining, 16);\r
+        }\r
+        Trb->Adma32Desc[Index].LowerLength = (UINT16)(Remaining & MAX_UINT16);\r
+        Trb->Adma32Desc[Index].Address = (UINT32)Address;\r
+        break;\r
+      } else {\r
+        Trb->Adma32Desc[Index].Valid = 1;\r
+        Trb->Adma32Desc[Index].Act   = 2;\r
+        if (Trb->AdmaLengthMode == SdMmcAdmaLen26b) {\r
+          Trb->Adma32Desc[Index].UpperLength  = 0;\r
+        }\r
+        Trb->Adma32Desc[Index].LowerLength  = 0;\r
+        Trb->Adma32Desc[Index].Address = (UINT32)Address;\r
+      }\r
+    } else if (Trb->Mode == SdMmcAdma64bV3Mode) {\r
+      if (Remaining <= AdmaMaxDataPerLine) {\r
+        Trb->Adma64V3Desc[Index].Valid = 1;\r
+        Trb->Adma64V3Desc[Index].Act   = 2;\r
+        if (Trb->AdmaLengthMode == SdMmcAdmaLen26b) {\r
+          Trb->Adma64V3Desc[Index].UpperLength  = (UINT16)RShiftU64 (Remaining, 16);\r
+        }\r
+        Trb->Adma64V3Desc[Index].LowerLength  = (UINT16)(Remaining & MAX_UINT16);\r
+        Trb->Adma64V3Desc[Index].LowerAddress = (UINT32)Address;\r
+        Trb->Adma64V3Desc[Index].UpperAddress = (UINT32)RShiftU64 (Address, 32);\r
+        break;\r
+      } else {\r
+        Trb->Adma64V3Desc[Index].Valid = 1;\r
+        Trb->Adma64V3Desc[Index].Act   = 2;\r
+        if (Trb->AdmaLengthMode == SdMmcAdmaLen26b) {\r
+          Trb->Adma64V3Desc[Index].UpperLength  = 0;\r
+        }\r
+        Trb->Adma64V3Desc[Index].LowerLength  = 0;\r
+        Trb->Adma64V3Desc[Index].LowerAddress = (UINT32)Address;\r
+        Trb->Adma64V3Desc[Index].UpperAddress = (UINT32)RShiftU64 (Address, 32);\r
+      }\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
+      if (Remaining <= AdmaMaxDataPerLine) {\r
+        Trb->Adma64V4Desc[Index].Valid = 1;\r
+        Trb->Adma64V4Desc[Index].Act   = 2;\r
+        if (Trb->AdmaLengthMode == SdMmcAdmaLen26b) {\r
+          Trb->Adma64V4Desc[Index].UpperLength  = (UINT16)RShiftU64 (Remaining, 16);\r
+        }\r
+        Trb->Adma64V4Desc[Index].LowerLength  = (UINT16)(Remaining & MAX_UINT16);\r
+        Trb->Adma64V4Desc[Index].LowerAddress = (UINT32)Address;\r
+        Trb->Adma64V4Desc[Index].UpperAddress = (UINT32)RShiftU64 (Address, 32);\r
+        break;\r
+      } else {\r
+        Trb->Adma64V4Desc[Index].Valid = 1;\r
+        Trb->Adma64V4Desc[Index].Act   = 2;\r
+        if (Trb->AdmaLengthMode == SdMmcAdmaLen26b) {\r
+          Trb->Adma64V4Desc[Index].UpperLength  = 0;\r
+        }\r
+        Trb->Adma64V4Desc[Index].LowerLength  = 0;\r
+        Trb->Adma64V4Desc[Index].LowerAddress = (UINT32)Address;\r
+        Trb->Adma64V4Desc[Index].UpperAddress = (UINT32)RShiftU64 (Address, 32);\r
+      }\r
     }\r
 \r
-    Remaining -= ADMA_MAX_DATA_PER_LINE;\r
-    Address   += ADMA_MAX_DATA_PER_LINE;\r
+    Remaining -= AdmaMaxDataPerLine;\r
+    Address   += AdmaMaxDataPerLine;\r
   }\r
 \r
   //\r
   // Set the last descriptor line as end of descriptor table\r
   //\r
-  Trb->AdmaDesc[Index].End = 1;\r
+  if (Trb->Mode == SdMmcAdma32bMode) {\r
+    Trb->Adma32Desc[Index].End = 1;\r
+  } else if (Trb->Mode == SdMmcAdma64bV3Mode) {\r
+    Trb->Adma64V3Desc[Index].End = 1;\r
+  } else {\r
+    Trb->Adma64V4Desc[Index].End = 1;\r
+  }\r
   return EFI_SUCCESS;\r
 }\r
 \r
@@ -1381,8 +1724,21 @@ SdMmcCreateTrb (
     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
+      Trb->Mode = SdMmcAdma32bMode;\r
+      Trb->AdmaLengthMode = SdMmcAdmaLen16b;\r
+      if ((Private->ControllerVersion[Slot] == SD_MMC_HC_CTRL_VER_300) &&\r
+          (Private->Capability[Slot].SysBus64V3 == 1)) {\r
+        Trb->Mode = SdMmcAdma64bV3Mode;\r
+      } else if (((Private->ControllerVersion[Slot] == SD_MMC_HC_CTRL_VER_400) &&\r
+                  (Private->Capability[Slot].SysBus64V3 == 1)) ||\r
+                 ((Private->ControllerVersion[Slot] >= SD_MMC_HC_CTRL_VER_410) &&\r
+                  (Private->Capability[Slot].SysBus64V4 == 1))) {\r
+        Trb->Mode = SdMmcAdma64bV4Mode;\r
+      }\r
+      if (Private->ControllerVersion[Slot] >= SD_MMC_HC_CTRL_VER_410) {\r
+        Trb->AdmaLengthMode = SdMmcAdmaLen26b;\r
+      }\r
+      Status = BuildAdmaDescTable (Trb, Private->ControllerVersion[Slot]);\r
       if (EFI_ERROR (Status)) {\r
         PciIo->Unmap (PciIo, Trb->DataMap);\r
         goto Error;\r
@@ -1428,11 +1784,25 @@ SdMmcFreeTrb (
       Trb->AdmaMap\r
     );\r
   }\r
-  if (Trb->AdmaDesc != NULL) {\r
+  if (Trb->Adma32Desc != NULL) {\r
+    PciIo->FreeBuffer (\r
+      PciIo,\r
+      Trb->AdmaPages,\r
+      Trb->Adma32Desc\r
+    );\r
+  }\r
+  if (Trb->Adma64V3Desc != NULL) {\r
+    PciIo->FreeBuffer (\r
+      PciIo,\r
+      Trb->AdmaPages,\r
+      Trb->Adma64V3Desc\r
+    );\r
+  }\r
+  if (Trb->Adma64V4Desc != NULL) {\r
     PciIo->FreeBuffer (\r
       PciIo,\r
       Trb->AdmaPages,\r
-      Trb->AdmaDesc\r
+      Trb->Adma64V4Desc\r
     );\r
   }\r
   if (Trb->DataMap != NULL) {\r
@@ -1572,12 +1942,15 @@ SdMmcExecTrb (
   UINT16                              Cmd;\r
   UINT16                              IntStatus;\r
   UINT32                              Argument;\r
-  UINT16                              BlkCount;\r
+  UINT32                              BlkCount;\r
   UINT16                              BlkSize;\r
   UINT16                              TransMode;\r
   UINT8                               HostCtrl1;\r
-  UINT32                              SdmaAddr;\r
+  UINT64                              SdmaAddr;\r
   UINT64                              AdmaAddr;\r
+  BOOLEAN                             AddressingMode64;\r
+\r
+  AddressingMode64 = FALSE;\r
 \r
   Packet = Trb->Packet;\r
   PciIo  = Trb->Private->PciIo;\r
@@ -1597,30 +1970,55 @@ SdMmcExecTrb (
   if (EFI_ERROR (Status)) {\r
     return Status;\r
   }\r
+\r
+  if (Private->ControllerVersion[Trb->Slot] >= SD_MMC_HC_CTRL_VER_400) {\r
+    Status = SdMmcHcCheckMmioSet(PciIo, Trb->Slot, SD_MMC_HC_HOST_CTRL2, sizeof(UINT16),\r
+                                 SD_MMC_HC_64_ADDR_EN, SD_MMC_HC_64_ADDR_EN);\r
+    if (!EFI_ERROR (Status)) {\r
+      AddressingMode64 = TRUE;\r
+    }\r
+  }\r
+\r
   //\r
   // Set Host Control 1 register DMA Select field\r
   //\r
-  if (Trb->Mode == SdMmcAdmaMode) {\r
+  if ((Trb->Mode == SdMmcAdma32bMode) ||\r
+      (Trb->Mode == SdMmcAdma64bV4Mode)) {\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
+  } else if (Trb->Mode == SdMmcAdma64bV3Mode) {\r
+    HostCtrl1 = BIT4|BIT3;\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
+    if ((!AddressingMode64) &&\r
+        ((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
+    SdmaAddr = (UINT64)(UINTN)Trb->DataPhy;\r
+\r
+    if (Private->ControllerVersion[Trb->Slot] >= SD_MMC_HC_CTRL_VER_400) {\r
+      Status = SdMmcHcRwMmio (PciIo, Trb->Slot, SD_MMC_HC_ADMA_SYS_ADDR, FALSE, sizeof (UINT64), &SdmaAddr);\r
+    } else {\r
+      Status = SdMmcHcRwMmio (PciIo, Trb->Slot, SD_MMC_HC_SDMA_ADDR, FALSE, sizeof (UINT32), &SdmaAddr);\r
+    }\r
+\r
     if (EFI_ERROR (Status)) {\r
       return Status;\r
     }\r
-  } else if (Trb->Mode == SdMmcAdmaMode) {\r
+  } else if ((Trb->Mode == SdMmcAdma32bMode) ||\r
+             (Trb->Mode == SdMmcAdma64bV3Mode) ||\r
+             (Trb->Mode == SdMmcAdma64bV4Mode)) {\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
@@ -1646,9 +2044,13 @@ SdMmcExecTrb (
     //\r
     // Calcuate Block Count.\r
     //\r
-    BlkCount = (UINT16)(Trb->DataLen / Trb->BlockSize);\r
+    BlkCount = (Trb->DataLen / Trb->BlockSize);\r
+  }\r
+  if (Private->ControllerVersion[Trb->Slot] >= SD_MMC_HC_CTRL_VER_410) {\r
+    Status = SdMmcHcRwMmio (PciIo, Trb->Slot, SD_MMC_HC_SDMA_ADDR, FALSE, sizeof (UINT32), &BlkCount);\r
+  } else {\r
+    Status = SdMmcHcRwMmio (PciIo, Trb->Slot, SD_MMC_HC_BLK_COUNT, FALSE, sizeof (UINT16), &BlkCount);\r
   }\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
@@ -1744,7 +2146,7 @@ SdMmcCheckTrbResult (
   EFI_SD_MMC_PASS_THRU_COMMAND_PACKET *Packet;\r
   UINT16                              IntStatus;\r
   UINT32                              Response[4];\r
-  UINT32                              SdmaAddr;\r
+  UINT64                              SdmaAddr;\r
   UINT8                               Index;\r
   UINT8                               SwReset;\r
   UINT32                              PioLength;\r
@@ -1868,8 +2270,19 @@ SdMmcCheckTrbResult (
     //\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
+    SdmaAddr = SD_MMC_SDMA_ROUND_UP ((UINTN)Trb->DataPhy, SD_MMC_SDMA_BOUNDARY);\r
+\r
+    if (Private->ControllerVersion[Trb->Slot] >= SD_MMC_HC_CTRL_VER_400) {\r
+      Status = SdMmcHcRwMmio (\r
+                 Private->PciIo,\r
+                 Trb->Slot,\r
+                 SD_MMC_HC_ADMA_SYS_ADDR,\r
+                 FALSE,\r
+                 sizeof (UINT64),\r
+                 &SdmaAddr\r
+                 );\r
+    } else {\r
+      Status = SdMmcHcRwMmio (\r
                  Private->PciIo,\r
                  Trb->Slot,\r
                  SD_MMC_HC_SDMA_ADDR,\r
@@ -1877,10 +2290,12 @@ SdMmcCheckTrbResult (
                  sizeof (UINT32),\r
                  &SdmaAddr\r
                  );\r
+    }\r
+\r
     if (EFI_ERROR (Status)) {\r
       goto Done;\r
     }\r
-    Trb->DataPhy = (UINT32)(UINTN)SdmaAddr;\r
+    Trb->DataPhy = (UINT64)(UINTN)SdmaAddr;\r
   }\r
 \r
   if ((Packet->SdMmcCmdBlk->CommandType != SdMmcCommandTypeAdtc) &&\r