]> git.proxmox.com Git - mirror_edk2.git/blobdiff - MdeModulePkg/Bus/Pci/SdMmcPciHcDxe/SdMmcPciHci.c
MdeModulePkg/SdMmcPciHcDxe: Update comment for spec compliance status
[mirror_edk2.git] / MdeModulePkg / Bus / Pci / SdMmcPciHcDxe / SdMmcPciHci.c
index 9672b5b9bf18184055f6fc7f53bf3a8c68619d6d..4c64da3b207a9ff5c4fad447115fb3f2f21eb0ad 100644 (file)
@@ -1,10 +1,13 @@
 /** @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
+  Copyright (c) 2018, NVIDIA CORPORATION. All rights reserved.\r
+  Copyright (c) 2015 - 2019, 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
@@ -45,7 +48,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
@@ -416,6 +420,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 +478,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
@@ -454,11 +489,11 @@ SdMmcHcReset (
   }\r
 \r
   PciIo   = Private->PciIo;\r
-  SwReset = 0xFF;\r
-  Status  = SdMmcHcRwMmio (PciIo, Slot, SD_MMC_HC_SW_RST, FALSE, sizeof (SwReset), &SwReset);\r
+  SwReset = BIT0;\r
+  Status  = SdMmcHcOrMmio (PciIo, Slot, SD_MMC_HC_SW_RST, sizeof (SwReset), &SwReset);\r
 \r
   if (EFI_ERROR (Status)) {\r
-    DEBUG ((DEBUG_ERROR, "SdMmcHcReset: write full 1 fails: %r\n", Status));\r
+    DEBUG ((DEBUG_ERROR, "SdMmcHcReset: write SW Reset for All fails: %r\n", Status));\r
     return Status;\r
   }\r
 \r
@@ -467,7 +502,7 @@ SdMmcHcReset (
              Slot,\r
              SD_MMC_HC_SW_RST,\r
              sizeof (SwReset),\r
-             0xFF,\r
+             BIT0,\r
              0x00,\r
              SD_MMC_HC_GENERIC_TIMEOUT\r
              );\r
@@ -494,7 +529,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 +755,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 +767,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 +810,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) == 2) {\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 +966,62 @@ 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 V4 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
+    //\r
+    // Check if controller version V4.10 or higher\r
+    //\r
+    if (ControllerVer >= SD_MMC_HC_CTRL_VER_410) {\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 +1031,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 +1054,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 +1175,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 +1188,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 +1216,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 +1227,95 @@ 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
   Turn on/off LED.\r
 \r
@@ -1167,9 +1351,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 +1362,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 +1371,93 @@ 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
+  BOOLEAN                   AddressingMode64;\r
+  BOOLEAN                   DataLength26;\r
+  UINT32                    AdmaMaxDataPerLine;\r
+  UINT32                    DescSize;\r
+  VOID                      *AdmaDesc;\r
+\r
+  AddressingMode64   = FALSE;\r
+  DataLength26       = FALSE;\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
+  // Detect whether 64bit addressing is supported.\r
+  //\r
+  if (ControllerVer >= SD_MMC_HC_CTRL_VER_400) {\r
+    Status = SdMmcHcCheckMmioSet(PciIo, Trb->Slot, SD_MMC_HC_HOST_CTRL2, sizeof(UINT16),\r
+                                 SD_MMC_HC_V4_EN|SD_MMC_HC_64_ADDR_EN, SD_MMC_HC_V4_EN|SD_MMC_HC_64_ADDR_EN);\r
+    if (!EFI_ERROR (Status)) {\r
+      AddressingMode64 = TRUE;\r
+      DescSize = sizeof (SD_MMC_HC_ADMA_64_DESC_LINE);\r
+    }\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 (!AddressingMode64 &&\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 ((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 (AddressingMode64) {\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
+  // Detect whether 26bit data length is supported.\r
+  //\r
+  Status = SdMmcHcCheckMmioSet(PciIo, Trb->Slot, SD_MMC_HC_HOST_CTRL2, sizeof(UINT16),\r
+                               SD_MMC_HC_26_DATA_LEN_ADMA_EN, SD_MMC_HC_26_DATA_LEN_ADMA_EN);\r
+  if (!EFI_ERROR (Status)) {\r
+    DataLength26 = TRUE;\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 +1470,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 ((!AddressingMode64) &&\r
+      (UINT64)(UINTN)Trb->AdmaDescPhy > 0x100000000ul) {\r
     //\r
     // The ADMA doesn't support 64bit addressing.\r
     //\r
@@ -1256,35 +1487,71 @@ 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 (!AddressingMode64) {\r
+    Trb->Adma32Desc = AdmaDesc;\r
+    Trb->Adma64Desc = NULL;\r
+  } else {\r
+    Trb->Adma64Desc = AdmaDesc;\r
+    Trb->Adma32Desc = NULL;\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 (!AddressingMode64) {\r
+      if (Remaining <= AdmaMaxDataPerLine) {\r
+        Trb->Adma32Desc[Index].Valid = 1;\r
+        Trb->Adma32Desc[Index].Act   = 2;\r
+        if (DataLength26) {\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 (DataLength26) {\r
+          Trb->Adma32Desc[Index].UpperLength  = 0;\r
+        }\r
+        Trb->Adma32Desc[Index].LowerLength  = 0;\r
+        Trb->Adma32Desc[Index].Address = (UINT32)Address;\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->Adma64Desc[Index].Valid = 1;\r
+        Trb->Adma64Desc[Index].Act   = 2;\r
+        if (DataLength26) {\r
+          Trb->Adma64Desc[Index].UpperLength  = (UINT16)RShiftU64 (Remaining, 16);\r
+        }\r
+        Trb->Adma64Desc[Index].LowerLength  = (UINT16)(Remaining & MAX_UINT16);\r
+        Trb->Adma64Desc[Index].LowerAddress = (UINT32)Address;\r
+        Trb->Adma64Desc[Index].UpperAddress = (UINT32)RShiftU64 (Address, 32);\r
+        break;\r
+      } else {\r
+        Trb->Adma64Desc[Index].Valid = 1;\r
+        Trb->Adma64Desc[Index].Act   = 2;\r
+        if (DataLength26) {\r
+          Trb->Adma64Desc[Index].UpperLength  = 0;\r
+        }\r
+        Trb->Adma64Desc[Index].LowerLength  = 0;\r
+        Trb->Adma64Desc[Index].LowerAddress = (UINT32)Address;\r
+        Trb->Adma64Desc[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
+  AddressingMode64 ? (Trb->Adma64Desc[Index].End = 1) : (Trb->Adma32Desc[Index].End = 1);\r
   return EFI_SUCCESS;\r
 }\r
 \r
@@ -1382,7 +1649,7 @@ SdMmcCreateTrb (
       Trb->Mode = SdMmcNoData;\r
     } else if (Private->Capability[Slot].Adma2 != 0) {\r
       Trb->Mode = SdMmcAdmaMode;\r
-      Status = BuildAdmaDescTable (Trb);\r
+      Status = BuildAdmaDescTable (Trb, Private->ControllerVersion[Slot]);\r
       if (EFI_ERROR (Status)) {\r
         PciIo->Unmap (PciIo, Trb->DataMap);\r
         goto Error;\r
@@ -1428,11 +1695,18 @@ 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->Adma64Desc != NULL) {\r
     PciIo->FreeBuffer (\r
       PciIo,\r
       Trb->AdmaPages,\r
-      Trb->AdmaDesc\r
+      Trb->Adma64Desc\r
     );\r
   }\r
   if (Trb->DataMap != NULL) {\r
@@ -1572,12 +1846,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
@@ -1610,13 +1887,28 @@ SdMmcExecTrb (
 \r
   SdMmcHcLedOnOff (PciIo, Trb->Slot, TRUE);\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_V4_EN|SD_MMC_HC_64_ADDR_EN, SD_MMC_HC_V4_EN|SD_MMC_HC_64_ADDR_EN);\r
+    if (!EFI_ERROR (Status)) {\r
+      AddressingMode64 = TRUE;\r
+    }\r
+  }\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
@@ -1646,9 +1938,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 +2040,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 +2164,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 +2184,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