]> git.proxmox.com Git - mirror_edk2.git/blobdiff - MdeModulePkg/Bus/Pci/SdMmcPciHcDxe/SdDevice.c
MdeModulePkg/SdMmcPciHcDxe: Enhance driver traces
[mirror_edk2.git] / MdeModulePkg / Bus / Pci / SdMmcPciHcDxe / SdDevice.c
index 07bd07ad410ab9c0994978dd5d7c8013cc114f05..b630daab76312832bc3aa4e20c2b267a030b9ffb 100644 (file)
@@ -1,14 +1,9 @@
 /** @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
+  Copyright (c) 2018, NVIDIA CORPORATION. All rights reserved.\r
+  Copyright (c) 2015 - 2016, Intel Corporation. All rights reserved.<BR>\r
+  SPDX-License-Identifier: BSD-2-Clause-Patent\r
 \r
 **/\r
 \r
@@ -318,117 +313,6 @@ SdCardSetRca (
   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
@@ -464,7 +348,9 @@ SdCardSelect (
 \r
   SdMmcCmdBlk.CommandIndex = SD_SELECT_DESELECT_CARD;\r
   SdMmcCmdBlk.CommandType  = SdMmcCommandTypeAc;\r
-  SdMmcCmdBlk.ResponseType = SdMmcResponseTypeR1b;\r
+  if (Rca != 0) {\r
+    SdMmcCmdBlk.ResponseType = SdMmcResponseTypeR1b;\r
+  }\r
   SdMmcCmdBlk.CommandArgument = (UINT32)Rca << 16;\r
 \r
   Status = SdMmcPassThruPassThru (PassThru, Slot, &Packet, NULL);\r
@@ -582,13 +468,14 @@ SdCardSetBusWidth (
 \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
+  @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]  BusTiming      Target bus timing based on which access group value will be set.\r
+  @param[in]  CommandSystem  The value for command set group.\r
+  @param[in]  DriverStrength The value for driver strength group.\r
+  @param[in]  PowerLimit     The value for power limit group.\r
+  @param[in]  Mode           Switch or check function.\r
+  @param[out] SwitchResp     The return switch function status.\r
 \r
   @retval EFI_SUCCESS       The operation is done correctly.\r
   @retval Others            The operation fails.\r
@@ -596,13 +483,14 @@ SdCardSetBusWidth (
 **/\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
+  IN     EFI_SD_MMC_PASS_THRU_PROTOCOL  *PassThru,\r
+  IN     UINT8                          Slot,\r
+  IN     SD_MMC_BUS_MODE                BusTiming,\r
+  IN     UINT8                          CommandSystem,\r
+  IN     SD_DRIVER_STRENGTH_TYPE        DriverStrength,\r
+  IN     UINT8                          PowerLimit,\r
+  IN     BOOLEAN                        Mode,\r
+     OUT UINT8                          *SwitchResp\r
   )\r
 {\r
   EFI_SD_MMC_COMMAND_BLOCK              SdMmcCmdBlk;\r
@@ -610,7 +498,7 @@ SdCardSwitch (
   EFI_SD_MMC_PASS_THRU_COMMAND_PACKET   Packet;\r
   EFI_STATUS                            Status;\r
   UINT32                                ModeValue;\r
-  UINT8                                 Data[64];\r
+  UINT8                                 AccessMode;\r
 \r
   ZeroMem (&SdMmcCmdBlk, sizeof (SdMmcCmdBlk));\r
   ZeroMem (&SdMmcStatusBlk, sizeof (SdMmcStatusBlk));\r
@@ -625,14 +513,49 @@ SdCardSwitch (
   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
+\r
+  switch (BusTiming) {\r
+    case SdMmcUhsDdr50:\r
+      AccessMode = 0x4;\r
+      break;\r
+    case SdMmcUhsSdr104:\r
+      AccessMode = 0x3;\r
+      break;\r
+    case SdMmcUhsSdr50:\r
+      AccessMode = 0x2;\r
+      break;\r
+    case SdMmcUhsSdr25:\r
+    case SdMmcSdHs:\r
+      AccessMode = 0x1;\r
+      break;\r
+    case SdMmcUhsSdr12:\r
+    case SdMmcSdDs:\r
+      AccessMode = 0;\r
+      break;\r
+    default:\r
+      AccessMode = 0xF;\r
+  }\r
+\r
+  SdMmcCmdBlk.CommandArgument = (AccessMode & 0xF) | ((CommandSystem & 0xF) << 4) | \\r
+                                ((DriverStrength & 0xF) << 8) | ((PowerLimit & 0xF) << 12) | \\r
                                 ModeValue;\r
 \r
-  Packet.InDataBuffer     = Data;\r
-  Packet.InTransferLength = sizeof (Data);\r
+  Packet.InDataBuffer     = SwitchResp;\r
+  Packet.InTransferLength = 64;\r
 \r
   Status = SdMmcPassThruPassThru (PassThru, Slot, &Packet, NULL);\r
+  if (EFI_ERROR (Status)) {\r
+    return Status;\r
+  }\r
+\r
+  if (Mode) {\r
+    if ((((AccessMode & 0xF) != 0xF) && ((SwitchResp[16] & 0xF) != AccessMode)) ||\r
+        (((CommandSystem & 0xF) != 0xF) && (((SwitchResp[16] >> 4) & 0xF) != CommandSystem)) ||\r
+        (((DriverStrength & 0xF) != 0xF) && ((SwitchResp[15] & 0xF) != DriverStrength)) ||\r
+        (((PowerLimit & 0xF) != 0xF) && (((SwitchResp[15] >> 4) & 0xF) != PowerLimit))) {\r
+      return EFI_DEVICE_ERROR;\r
+    }\r
+  }\r
 \r
   return Status;\r
 }\r
@@ -776,7 +699,7 @@ SdCardTuningClock (
   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
+      DEBUG ((DEBUG_ERROR, "SdCardSendTuningBlk: Send tuning block fails with %r\n", Status));\r
       return Status;\r
     }\r
 \r
@@ -785,17 +708,24 @@ SdCardTuningClock (
       return Status;\r
     }\r
 \r
-    if ((HostCtrl2 & (BIT6 | BIT7)) == BIT7) {\r
+    if ((HostCtrl2 & (BIT6 | BIT7)) == 0) {\r
       break;\r
     }\r
+    if ((HostCtrl2 & (BIT6 | BIT7)) == BIT7) {\r
+      return EFI_SUCCESS;\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
+  DEBUG ((DEBUG_ERROR, "SdCardTuningClock: Send tuning block fails at %d times with HostCtrl2 %02x\n", Retry, HostCtrl2));\r
+  //\r
+  // Abort the tuning procedure and reset the tuning circuit.\r
+  //\r
+  HostCtrl2 = (UINT8)~(BIT6 | BIT7);\r
+  Status = SdMmcHcAndMmio (PciIo, Slot, SD_MMC_HC_HOST_CTRL2, sizeof (HostCtrl2), &HostCtrl2);\r
+  if (EFI_ERROR (Status)) {\r
+    return Status;\r
   }\r
-\r
-  return Status;\r
+  return EFI_DEVICE_ERROR;\r
 }\r
 \r
 /**\r
@@ -828,20 +758,20 @@ SdCardSwitchBusWidth (
 \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
+    DEBUG ((DEBUG_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
+    DEBUG ((DEBUG_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
+    DEBUG ((DEBUG_ERROR, "SdCardSwitchBusWidth: The switch operation fails as DevStatus is 0x%08x\n", DevStatus));\r
     return EFI_DEVICE_ERROR;\r
   }\r
 \r
@@ -850,6 +780,273 @@ SdCardSwitchBusWidth (
   return Status;\r
 }\r
 \r
+/**\r
+  Check if passed BusTiming is supported in both controller and card.\r
+\r
+  @param[in] Private                  Pointer to controller private data\r
+  @param[in] SlotIndex                Index of the slot in the controller\r
+  @param[in] CardSupportedBusTimings  Bitmask indicating which bus timings are supported by card\r
+  @param[in] IsInUhsI                 Flag indicating if link is in UHS-I\r
+\r
+  @retval TRUE  Both card and controller support given BusTiming\r
+  @retval FALSE Card or controller doesn't support given BusTiming\r
+**/\r
+BOOLEAN\r
+SdIsBusTimingSupported (\r
+  IN SD_MMC_HC_PRIVATE_DATA   *Private,\r
+  IN UINT8                    SlotIndex,\r
+  IN UINT8                    CardSupportedBusTimings,\r
+  IN BOOLEAN                  IsInUhsI,\r
+  IN SD_MMC_BUS_MODE          BusTiming\r
+  )\r
+{\r
+  SD_MMC_HC_SLOT_CAP           *Capability;\r
+\r
+  Capability = &Private->Capability[SlotIndex];\r
+\r
+  if (IsInUhsI) {\r
+    switch (BusTiming) {\r
+      case SdMmcUhsSdr104:\r
+        if ((Capability->Sdr104 != 0) && ((CardSupportedBusTimings & BIT3) != 0)) {\r
+          return TRUE;\r
+        }\r
+        break;\r
+      case SdMmcUhsDdr50:\r
+        if ((Capability->Ddr50 != 0) && ((CardSupportedBusTimings & BIT4) != 0)) {\r
+          return TRUE;\r
+        }\r
+        break;\r
+      case SdMmcUhsSdr50:\r
+        if ((Capability->Sdr50 != 0) && ((CardSupportedBusTimings & BIT2) != 0)) {\r
+          return TRUE;\r
+        }\r
+        break;\r
+      case SdMmcUhsSdr25:\r
+        if ((CardSupportedBusTimings & BIT1) != 0) {\r
+          return TRUE;\r
+        }\r
+        break;\r
+      case SdMmcUhsSdr12:\r
+        if ((CardSupportedBusTimings & BIT0) != 0) {\r
+          return TRUE;\r
+        }\r
+        break;\r
+      default:\r
+        break;\r
+    }\r
+  } else {\r
+    switch (BusTiming) {\r
+      case SdMmcSdHs:\r
+        if ((Capability->HighSpeed != 0) && (CardSupportedBusTimings & BIT1) != 0) {\r
+          return TRUE;\r
+        }\r
+        break;\r
+      case SdMmcSdDs:\r
+        if ((CardSupportedBusTimings & BIT0) != 0) {\r
+          return TRUE;\r
+        }\r
+        break;\r
+      default:\r
+        break;\r
+    }\r
+  }\r
+\r
+  return FALSE;\r
+}\r
+\r
+/**\r
+  Get the target bus timing to set on the link. This function\r
+  will try to select highest bus timing supported by card, controller\r
+  and the driver.\r
+\r
+  @param[in] Private                  Pointer to controller private data\r
+  @param[in] SlotIndex                Index of the slot in the controller\r
+  @param[in] CardSupportedBusTimings  Bitmask indicating which bus timings are supported by card\r
+  @param[in] IsInUhsI                 Flag indicating if link is in UHS-I\r
+\r
+  @return  Bus timing value that should be set on link\r
+**/\r
+SD_MMC_BUS_MODE\r
+SdGetTargetBusTiming (\r
+  IN SD_MMC_HC_PRIVATE_DATA  *Private,\r
+  IN UINT8                   SlotIndex,\r
+  IN UINT8                   CardSupportedBusTimings,\r
+  IN BOOLEAN                 IsInUhsI\r
+  )\r
+{\r
+  SD_MMC_BUS_MODE  BusTiming;\r
+\r
+  if (IsInUhsI) {\r
+    BusTiming = SdMmcUhsSdr104;\r
+  } else {\r
+    BusTiming = SdMmcSdHs;\r
+  }\r
+\r
+  while (BusTiming > SdMmcSdDs) {\r
+    if (SdIsBusTimingSupported (Private, SlotIndex, CardSupportedBusTimings, IsInUhsI, BusTiming)) {\r
+      break;\r
+    }\r
+    BusTiming--;\r
+  }\r
+\r
+  return BusTiming;\r
+}\r
+\r
+/**\r
+  Get the target bus width to be set on the bus.\r
+\r
+  @param[in] Private    Pointer to controller private data\r
+  @param[in] SlotIndex  Index of the slot in the controller\r
+  @param[in] BusTiming  Bus timing set on the bus\r
+\r
+  @return Bus width to be set on the bus\r
+**/\r
+UINT8\r
+SdGetTargetBusWidth (\r
+  IN SD_MMC_HC_PRIVATE_DATA   *Private,\r
+  IN UINT8                    SlotIndex,\r
+  IN SD_MMC_BUS_MODE          BusTiming\r
+  )\r
+{\r
+  UINT8  BusWidth;\r
+  UINT8  PreferredBusWidth;\r
+\r
+  PreferredBusWidth = Private->Slot[SlotIndex].OperatingParameters.BusWidth;\r
+\r
+  if (BusTiming == SdMmcSdDs || BusTiming == SdMmcSdHs) {\r
+    if (PreferredBusWidth != EDKII_SD_MMC_BUS_WIDTH_IGNORE &&\r
+        (PreferredBusWidth == 1 || PreferredBusWidth == 4)) {\r
+      BusWidth = PreferredBusWidth;\r
+    } else {\r
+      BusWidth = 4;\r
+    }\r
+  } else {\r
+    //\r
+    // UHS-I modes support only 4-bit width.\r
+    // Switch to 4-bit has been done before calling this function anyway so\r
+    // this is purely informational.\r
+    //\r
+    BusWidth = 4;\r
+  }\r
+\r
+  return BusWidth;\r
+}\r
+\r
+/**\r
+  Get the target clock frequency to be set on the bus.\r
+\r
+  @param[in] Private    Pointer to controller private data\r
+  @param[in] SlotIndex  Index of the slot in the controller\r
+  @param[in] BusTiming  Bus timing to be set on the bus\r
+\r
+  @return Value of the clock frequency to be set on bus in MHz\r
+**/\r
+UINT32\r
+SdGetTargetBusClockFreq (\r
+  IN SD_MMC_HC_PRIVATE_DATA   *Private,\r
+  IN UINT8                    SlotIndex,\r
+  IN SD_MMC_BUS_MODE          BusTiming\r
+  )\r
+{\r
+  UINT32 PreferredClockFreq;\r
+  UINT32 MaxClockFreq;\r
+\r
+  PreferredClockFreq = Private->Slot[SlotIndex].OperatingParameters.ClockFreq;\r
+\r
+  switch (BusTiming) {\r
+    case SdMmcUhsSdr104:\r
+      MaxClockFreq = 208;\r
+      break;\r
+    case SdMmcUhsSdr50:\r
+      MaxClockFreq = 100;\r
+      break;\r
+    case SdMmcUhsDdr50:\r
+    case SdMmcUhsSdr25:\r
+    case SdMmcSdHs:\r
+      MaxClockFreq = 50;\r
+      break;\r
+    case SdMmcUhsSdr12:\r
+    case SdMmcSdDs:\r
+    default:\r
+      MaxClockFreq = 25;\r
+  }\r
+\r
+  if (PreferredClockFreq != EDKII_SD_MMC_CLOCK_FREQ_IGNORE && PreferredClockFreq < MaxClockFreq) {\r
+    return PreferredClockFreq;\r
+  } else {\r
+    return MaxClockFreq;\r
+  }\r
+}\r
+\r
+/**\r
+  Get the driver strength to be set on bus.\r
+\r
+  @param[in] Private                       Pointer to controller private data\r
+  @param[in] SlotIndex                     Index of the slot in the controller\r
+  @param[in] CardSupportedDriverStrengths  Bitmask indicating which driver strengths are supported on the card\r
+  @param[in] BusTiming                     Bus timing set on the bus\r
+\r
+  @return Value of the driver strength to be set on the bus\r
+**/\r
+EDKII_SD_MMC_DRIVER_STRENGTH\r
+SdGetTargetDriverStrength (\r
+  IN SD_MMC_HC_PRIVATE_DATA   *Private,\r
+  IN UINT8                    SlotIndex,\r
+  IN UINT8                    CardSupportedDriverStrengths,\r
+  IN SD_MMC_BUS_MODE          BusTiming\r
+  )\r
+{\r
+  EDKII_SD_MMC_DRIVER_STRENGTH  PreferredDriverStrength;\r
+  EDKII_SD_MMC_DRIVER_STRENGTH  DriverStrength;\r
+\r
+  if (BusTiming == SdMmcSdDs || BusTiming == SdMmcSdHs) {\r
+    DriverStrength.Sd = SdDriverStrengthIgnore;\r
+    return DriverStrength;\r
+  }\r
+\r
+  PreferredDriverStrength = Private->Slot[SlotIndex].OperatingParameters.DriverStrength;\r
+  DriverStrength.Sd = SdDriverStrengthTypeB;\r
+\r
+  if (PreferredDriverStrength.Sd != EDKII_SD_MMC_DRIVER_STRENGTH_IGNORE &&\r
+      (CardSupportedDriverStrengths & (BIT0 << PreferredDriverStrength.Sd))) {\r
+\r
+    if ((PreferredDriverStrength.Sd == SdDriverStrengthTypeA &&\r
+        (Private->Capability[SlotIndex].DriverTypeA != 0)) ||\r
+        (PreferredDriverStrength.Sd == SdDriverStrengthTypeC &&\r
+        (Private->Capability[SlotIndex].DriverTypeC != 0)) ||\r
+        (PreferredDriverStrength.Sd == SdDriverStrengthTypeD &&\r
+        (Private->Capability[SlotIndex].DriverTypeD != 0))) {\r
+      DriverStrength.Sd = PreferredDriverStrength.Sd;\r
+    }\r
+  }\r
+\r
+  return DriverStrength;\r
+}\r
+\r
+/**\r
+  Get the target settings for the bus mode.\r
+\r
+  @param[in]  Private          Pointer to controller private data\r
+  @param[in]  SlotIndex        Index of the slot in the controller\r
+  @param[in]  SwitchQueryResp  Pointer to switch query response\r
+  @param[in]  IsInUhsI         Flag indicating if link is in UHS-I mode\r
+  @param[out] BusMode          Target configuration of the bus\r
+**/\r
+VOID\r
+SdGetTargetBusMode (\r
+  IN SD_MMC_HC_PRIVATE_DATA  *Private,\r
+  IN UINT8                   SlotIndex,\r
+  IN UINT8                   *SwitchQueryResp,\r
+  IN BOOLEAN                 IsInUhsI,\r
+  OUT SD_MMC_BUS_SETTINGS    *BusMode\r
+  )\r
+{\r
+  BusMode->BusTiming = SdGetTargetBusTiming (Private, SlotIndex, SwitchQueryResp[13], IsInUhsI);\r
+  BusMode->BusWidth = SdGetTargetBusWidth (Private, SlotIndex, BusMode->BusTiming);\r
+  BusMode->ClockFreq = SdGetTargetBusClockFreq (Private, SlotIndex, BusMode->BusTiming);\r
+  BusMode->DriverStrength = SdGetTargetDriverStrength (Private, SlotIndex, SwitchQueryResp[9], BusMode->BusTiming);\r
+}\r
+\r
 /**\r
   Switch the high speed timing according to request.\r
 \r
@@ -877,12 +1074,10 @@ SdCardSetBusMode (
 {\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
+  UINT8                        SwitchResp[64];\r
   SD_MMC_HC_PRIVATE_DATA       *Private;\r
+  SD_MMC_BUS_SETTINGS          BusMode;\r
 \r
   Private = SD_MMC_HC_PRIVATE_FROM_THIS (PassThru);\r
 \r
@@ -893,42 +1088,51 @@ SdCardSetBusMode (
     return Status;\r
   }\r
 \r
-  BusWidth = 4;\r
+  if (S18A) {\r
+    //\r
+    // For UHS-I speed modes 4-bit data bus is requiered so we\r
+    // switch here irrespective of platform preference.\r
+    //\r
+    Status = SdCardSwitchBusWidth (PciIo, PassThru, Slot, Rca, 4);\r
+    if (EFI_ERROR (Status)) {\r
+      return Status;\r
+    }\r
+  }\r
 \r
-  Status = SdCardSwitchBusWidth (PciIo, PassThru, Slot, Rca, BusWidth);\r
+  //\r
+  // Get the supported bus speed from SWITCH cmd return data group #1.\r
+  //\r
+  Status = SdCardSwitch (PassThru, Slot, 0xFF, 0xF, SdDriverStrengthIgnore, 0xF, FALSE, SwitchResp);\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
+  SdGetTargetBusMode (Private, Slot, SwitchResp, S18A, &BusMode);\r
+\r
+  DEBUG ((DEBUG_INFO, "SdCardSetBusMode: Target bus mode: bus timing = %d, bus width = %d, clock freq[MHz] = %d, driver strength = %d\n",\r
+                         BusMode.BusTiming, BusMode.BusWidth, BusMode.ClockFreq, BusMode.DriverStrength.Sd));\r
+\r
+  if (!S18A) {\r
+    Status = SdCardSwitchBusWidth (PciIo, PassThru, Slot, Rca, BusMode.BusWidth);\r
+    if (EFI_ERROR (Status)) {\r
+      return Status;\r
+    }\r
   }\r
 \r
-  DEBUG ((EFI_D_INFO, "SdCardSetBusMode: AccessMode %d ClockFreq %d BusWidth %d\n", AccessMode, ClockFreq, BusWidth));\r
+  Status = SdCardSwitch (PassThru, Slot, BusMode.BusTiming, 0xF, BusMode.DriverStrength.Sd, 0xF, TRUE, SwitchResp);\r
+  if (EFI_ERROR (Status)) {\r
+    return Status;\r
+  }\r
 \r
-  Status = SdCardSwitch (PassThru, Slot, AccessMode, 0, 0, 0, TRUE);\r
+  Status = SdMmcSetDriverStrength (Private->PciIo, Slot, BusMode.DriverStrength.Sd);\r
   if (EFI_ERROR (Status)) {\r
     return Status;\r
   }\r
 \r
   //\r
-  // Set to Hight Speed timing\r
+  // Set to High Speed timing\r
   //\r
-  if (AccessMode == 1) {\r
+  if (BusMode.BusTiming == SdMmcSdHs) {\r
     HostCtrl1 = BIT2;\r
     Status = SdMmcHcOrMmio (PciIo, Slot, SD_MMC_HC_HOST_CTRL1, sizeof (HostCtrl1), &HostCtrl1);\r
     if (EFI_ERROR (Status)) {\r
@@ -936,23 +1140,17 @@ SdCardSetBusMode (
     }\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
+  Status = SdMmcHcUhsSignaling (Private->ControllerHandle, PciIo, Slot, BusMode.BusTiming);\r
   if (EFI_ERROR (Status)) {\r
     return Status;\r
   }\r
 \r
-  Status = SdMmcHcClockSupply (PciIo, Slot, ClockFreq * 1000, *Capability);\r
+  Status = SdMmcHcClockSupply (Private, Slot, BusMode.BusTiming, FALSE, BusMode.ClockFreq * 1000);\r
   if (EFI_ERROR (Status)) {\r
     return Status;\r
   }\r
 \r
-  if ((AccessMode == 3) || ((AccessMode == 2) && (Capability->TuningSDR50 != 0))) {\r
+  if ((BusMode.BusTiming == SdMmcUhsSdr104) || ((BusMode.BusTiming == SdMmcUhsSdr50) && (Capability->TuningSDR50 != 0))) {\r
     Status = SdCardTuningClock (PciIo, PassThru, Slot);\r
     if (EFI_ERROR (Status)) {\r
       return Status;\r
@@ -992,6 +1190,7 @@ SdCardIdentification (
   UINT8                          PowerCtrl;\r
   UINT32                         PresentState;\r
   UINT8                          HostCtrl2;\r
+  UINTN                          Retry;\r
 \r
   PciIo    = Private->PciIo;\r
   PassThru = &Private->PassThru;\r
@@ -1000,7 +1199,7 @@ SdCardIdentification (
   //\r
   Status = SdCardReset (PassThru, Slot);\r
   if (EFI_ERROR (Status)) {\r
-    DEBUG ((EFI_D_INFO, "SdCardIdentification: Executing Cmd0 fails with %r\n", Status));\r
+    DEBUG ((DEBUG_INFO, "SdCardIdentification: Executing Cmd0 fails with %r\n", Status));\r
     return Status;\r
   }\r
   //\r
@@ -1008,7 +1207,7 @@ SdCardIdentification (
   //\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
+    DEBUG ((DEBUG_INFO, "SdCardIdentification: Executing Cmd8 fails with %r\n", Status));\r
     return Status;\r
   }\r
   //\r
@@ -1016,7 +1215,7 @@ SdCardIdentification (
   //\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
+    DEBUG ((DEBUG_INFO, "SdCardIdentification: Found SDIO device, ignore it as we don't support\n"));\r
     return EFI_DEVICE_ERROR;\r
   }\r
   //\r
@@ -1024,7 +1223,7 @@ SdCardIdentification (
   //\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
+    DEBUG ((DEBUG_INFO, "SdCardIdentification: Executing SdCardSendOpCond fails with %r\n", Status));\r
     return EFI_DEVICE_ERROR;\r
   }\r
 \r
@@ -1059,9 +1258,10 @@ SdCardIdentification (
     return Status;\r
   }\r
 \r
-  if ((ControllerVer & 0xFF) == 2) {\r
+  if (((ControllerVer & 0xFF) >= SD_MMC_HC_CTRL_VER_300) &&\r
+      ((ControllerVer & 0xFF) <= SD_MMC_HC_CTRL_VER_420)) {\r
     S18r = TRUE;\r
-  } else if (((ControllerVer & 0xFF) == 0) || ((ControllerVer & 0xFF) == 1)) {\r
+  } else if (((ControllerVer & 0xFF) == SD_MMC_HC_CTRL_VER_100) || ((ControllerVer & 0xFF) == SD_MMC_HC_CTRL_VER_200)) {\r
     S18r = FALSE;\r
   } else {\r
     ASSERT (FALSE);\r
@@ -1072,12 +1272,20 @@ SdCardIdentification (
   //    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
+  Ocr   = 0;\r
+  Retry = 0;\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
+      DEBUG ((DEBUG_ERROR, "SdCardIdentification: SdCardSendOpCond fails with %r Ocr %x, S18r %x, Xpc %x\n", Status, Ocr, S18r, Xpc));\r
+      return EFI_DEVICE_ERROR;\r
+    }\r
+\r
+    if (Retry++ == 100) {\r
+      DEBUG ((DEBUG_ERROR, "SdCardIdentification: SdCardSendOpCond fails too many times\n"));\r
       return EFI_DEVICE_ERROR;\r
     }\r
+    gBS->Stall(10 * 1000);\r
   } while ((Ocr & BIT31) == 0);\r
 \r
   //\r
@@ -1091,7 +1299,7 @@ SdCardIdentification (
        ((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
+      DEBUG ((DEBUG_ERROR, "SdCardIdentification: Executing SdCardVoltageSwitch fails with %r\n", Status));\r
       Status = EFI_DEVICE_ERROR;\r
       goto Error;\r
     } else {\r
@@ -1103,7 +1311,7 @@ SdCardIdentification (
 \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
+        DEBUG ((DEBUG_ERROR, "SdCardIdentification: SwitchVoltage fails with PresentState = 0x%x\n", PresentState));\r
         Status = EFI_DEVICE_ERROR;\r
         goto Error;\r
       }\r
@@ -1114,40 +1322,43 @@ SdCardIdentification (
 \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
+        DEBUG ((DEBUG_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
+      Status = SdMmcHcStartSdClock (PciIo, Slot);\r
+      if (EFI_ERROR (Status)) {\r
+        goto Error;\r
+      }\r
 \r
-      gBS->Stall (1);\r
+      gBS->Stall (1000);\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
+        DEBUG ((DEBUG_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
+    DEBUG ((DEBUG_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
+    DEBUG ((DEBUG_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
+    DEBUG ((DEBUG_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
+  DEBUG ((DEBUG_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