One typo within SdCardSwitch():

  if (Mode) {
    if ((((AccessMode & 0xF) != 0xF) && ((SwitchResp[16] & 0xF) != AccessMode) 
||
        ...
        (((PowerLimit & 0xF) != 0xF) && (((SwitchResp[15] >> 4) & 0xF) != 
PowerLimit)))) {
      return EFI_DEVICE_ERROR;
    }
  }

should be:

  if (Mode) {
    if ((((AccessMode & 0xF) != 0xF) && ((SwitchResp[16] & 0xF) != AccessMode)) 
||
        ...
        (((PowerLimit & 0xF) != 0xF) && (((SwitchResp[15] >> 4) & 0xF) != 
PowerLimit))) {
      return EFI_DEVICE_ERROR;
    }
  }

Other than this, this patch looks good to me,
Reviewed-by: Hao A Wu <hao.a...@intel.com>

I will handle this when I push it.

Best Regards,
Hao Wu


> -----Original Message-----
> From: Albecki, Mateusz
> Sent: Wednesday, June 26, 2019 9:10 PM
> To: devel@edk2.groups.io
> Cc: Albecki, Mateusz; Wu, Hao A
> Subject: [PATCH v4 2/2] MdeModulePkg/SdMmcHcDxe: Implement revision
> 3 of SdMmcOverrideProtocol
> 
> From: "Albecki, Mateusz" <mateusz.albe...@intel.com>
> 
> https://bugzilla.tianocore.org/show_bug.cgi?id=1882
> 
> Implement support for GetOperatingParamters notify phase
> in SdMmcHcDxe driver. GetOperatingParameters notify phase
> is signaled before we start card detection and initialization.
> Code has been updated for both eMMC and SD card controllers to
> take into consideration those new parameters. Initialization process
> has been divided into 2 steps. In the first step we bring the link
> up to the point where we can get card identification data(Extended
> CSD in eMMC case and SWITCH command response in SD card case). This
> data is later used along with controller capabilities and operating
> parameters passed in GetOperatingParameters phase to choose prefered
> bus settings in GetTargetBusSettings function. Those settings are later
> on to start bus training to high speeds. If user passes incompatible
> setting with selected bus timing driver will assume it's standard behavior
> with respect to that setting. For instance if HS400 has been selected as a
> target bus timing due to card and controller support bus width setting of
> 4 and 1 bit won't be respected and 8 bit setting will be choosen instead.
> 
> Cc: Hao A Wu <hao.a...@intel.com>
> Signed-off-by: Mateusz Albecki <mateusz.albe...@intel.com>
> ---
>  MdeModulePkg/Bus/Pci/SdMmcPciHcDxe/EmmcDevice.c    | 512
> +++++++++++++++------
>  MdeModulePkg/Bus/Pci/SdMmcPciHcDxe/SdDevice.c      | 410
> ++++++++++++++---
>  MdeModulePkg/Bus/Pci/SdMmcPciHcDxe/SdMmcPciHcDxe.c |  52 ++-
>  MdeModulePkg/Bus/Pci/SdMmcPciHcDxe/SdMmcPciHcDxe.h |  18 +-
>  MdeModulePkg/Bus/Pci/SdMmcPciHcDxe/SdMmcPciHci.c   |  34 ++
>  MdeModulePkg/Bus/Pci/SdMmcPciHcDxe/SdMmcPciHci.h   |  19 +
>  6 files changed, 814 insertions(+), 231 deletions(-)
> 
> diff --git a/MdeModulePkg/Bus/Pci/SdMmcPciHcDxe/EmmcDevice.c
> b/MdeModulePkg/Bus/Pci/SdMmcPciHcDxe/EmmcDevice.c
> index deaf4468c9..3f4a8e5413 100644
> --- a/MdeModulePkg/Bus/Pci/SdMmcPciHcDxe/EmmcDevice.c
> +++ b/MdeModulePkg/Bus/Pci/SdMmcPciHcDxe/EmmcDevice.c
> @@ -641,13 +641,13 @@ EmmcSwitchBusWidth (
>    Refer to EMMC Electrical Standard Spec 5.1 Section 6.6 and SD Host
> Controller
>    Simplified Spec 3.0 Figure 3-3 for details.
> 
> -  @param[in] PciIo          A pointer to the EFI_PCI_IO_PROTOCOL instance.
> -  @param[in] PassThru       A pointer to the
> EFI_SD_MMC_PASS_THRU_PROTOCOL instance.
> -  @param[in] Slot           The slot number of the SD card to send the 
> command
> to.
> -  @param[in] Rca            The relative device address to be assigned.
> -  @param[in] HsTiming       The value to be written to HS_TIMING field of
> EXT_CSD register.
> -  @param[in] Timing         The bus mode timing indicator.
> -  @param[in] ClockFreq      The max clock frequency to be set, the unit is
> MHz.
> +  @param[in] PciIo           A pointer to the EFI_PCI_IO_PROTOCOL instance.
> +  @param[in] PassThru        A pointer to the
> EFI_SD_MMC_PASS_THRU_PROTOCOL instance.
> +  @param[in] Slot            The slot number of the SD card to send the
> command to.
> +  @param[in] Rca             The relative device address to be assigned.
> +  @param[in] DriverStrength  Driver strength to set for speed modes that
> support it.
> +  @param[in] BusTiming       The bus mode timing indicator.
> +  @param[in] ClockFreq       The max clock frequency to be set, the unit is
> MHz.
> 
>    @retval EFI_SUCCESS       The operation is done correctly.
>    @retval Others            The operation fails.
> @@ -659,8 +659,8 @@ EmmcSwitchBusTiming (
>    IN EFI_SD_MMC_PASS_THRU_PROTOCOL      *PassThru,
>    IN UINT8                              Slot,
>    IN UINT16                             Rca,
> -  IN UINT8                              HsTiming,
> -  IN SD_MMC_BUS_MODE                    Timing,
> +  IN EDKII_SD_MMC_DRIVER_STRENGTH       DriverStrength,
> +  IN SD_MMC_BUS_MODE                    BusTiming,
>    IN UINT32                             ClockFreq
>    )
>  {
> @@ -678,12 +678,29 @@ EmmcSwitchBusTiming (
>    //
>    Access = 0x03;
>    Index  = OFFSET_OF (EMMC_EXT_CSD, HsTiming);
> -  Value  = HsTiming;
>    CmdSet = 0;
> +  switch (BusTiming) {
> +    case SdMmcMmcHs400:
> +      Value = (UINT8)((DriverStrength.Emmc << 4) | 3);
> +      break;
> +    case SdMmcMmcHs200:
> +      Value = (UINT8)((DriverStrength.Emmc << 4) | 2);
> +      break;
> +    case SdMmcMmcHsSdr:
> +    case SdMmcMmcHsDdr:
> +      Value = 1;
> +      break;
> +    case SdMmcMmcLegacy:
> +      Value = 0;
> +      break;
> +    default:
> +      DEBUG ((DEBUG_ERROR, "EmmcSwitchBusTiming: Unsupported
> BusTiming(%d\n)", BusTiming));
> +      return EFI_INVALID_PARAMETER;
> +  }
> 
>    Status = EmmcSwitch (PassThru, Slot, Access, Index, Value, CmdSet);
>    if (EFI_ERROR (Status)) {
> -    DEBUG ((DEBUG_ERROR, "EmmcSwitchBusTiming: Switch to hstiming %d
> fails with %r\n", HsTiming, Status));
> +    DEBUG ((DEBUG_ERROR, "EmmcSwitchBusTiming: Switch to bus
> timing %d fails with %r\n", BusTiming, Status));
>      return Status;
>    }
> 
> @@ -713,7 +730,7 @@ EmmcSwitchBusTiming (
>                            Private->ControllerHandle,
>                            Slot,
>                            EdkiiSdMmcSwitchClockFreqPost,
> -                          &Timing
> +                          &BusTiming
>                            );
>      if (EFI_ERROR (Status)) {
>        DEBUG ((
> @@ -739,10 +756,7 @@ EmmcSwitchBusTiming (
>    @param[in] PassThru       A pointer to the
> EFI_SD_MMC_PASS_THRU_PROTOCOL instance.
>    @param[in] Slot           The slot number of the SD card to send the 
> command
> to.
>    @param[in] Rca            The relative device address to be assigned.
> -  @param[in] ClockFreq      The max clock frequency to be set.
> -  @param[in] IsDdr          If TRUE, use dual data rate data simpling method.
> Otherwise
> -                            use single data rate data simpling method.
> -  @param[in] BusWidth       The bus width to be set, it could be 4 or 8.
> +  @param[in] BusMode        Pointer to SD_MMC_BUS_SETTINGS structure
> containing bus settings.
> 
>    @retval EFI_SUCCESS       The operation is done correctly.
>    @retval Others            The operation fails.
> @@ -754,25 +768,34 @@ EmmcSwitchToHighSpeed (
>    IN EFI_SD_MMC_PASS_THRU_PROTOCOL      *PassThru,
>    IN UINT8                              Slot,
>    IN UINT16                             Rca,
> -  IN UINT32                             ClockFreq,
> -  IN BOOLEAN                            IsDdr,
> -  IN UINT8                              BusWidth
> +  IN SD_MMC_BUS_SETTINGS                *BusMode
>    )
>  {
>    EFI_STATUS              Status;
> -  UINT8                   HsTiming;
>    UINT8                   HostCtrl1;
> -  SD_MMC_BUS_MODE         Timing;
>    SD_MMC_HC_PRIVATE_DATA  *Private;
> +  BOOLEAN                 IsDdr;
> 
>    Private = SD_MMC_HC_PRIVATE_FROM_THIS (PassThru);
> 
> -  Status = EmmcSwitchBusWidth (PciIo, PassThru, Slot, Rca, IsDdr, BusWidth);
> +  if ((BusMode->BusTiming != SdMmcMmcHsSdr && BusMode-
> >BusTiming != SdMmcMmcHsDdr) ||
> +      BusMode->ClockFreq > 52) {
> +    return EFI_INVALID_PARAMETER;
> +  }
> +
> +  if (BusMode->BusTiming == SdMmcMmcHsDdr) {
> +    IsDdr = TRUE;
> +  } else {
> +    IsDdr = FALSE;
> +  }
> +
> +  Status = EmmcSwitchBusWidth (PciIo, PassThru, Slot, Rca, IsDdr, BusMode-
> >BusWidth);
>    if (EFI_ERROR (Status)) {
>      return Status;
>    }
> +
>    //
> -  // Set to Hight Speed timing
> +  // Set to High Speed timing
>    //
>    HostCtrl1 = BIT2;
>    Status = SdMmcHcOrMmio (PciIo, Slot, SD_MMC_HC_HOST_CTRL1, sizeof
> (HostCtrl1), &HostCtrl1);
> @@ -780,37 +803,25 @@ EmmcSwitchToHighSpeed (
>      return Status;
>    }
> 
> -  if (IsDdr) {
> -    Timing = SdMmcMmcHsDdr;
> -  } else if (ClockFreq == 52) {
> -    Timing = SdMmcMmcHsSdr;
> -  } else {
> -    Timing = SdMmcMmcLegacy;
> -  }
> -
> -  Status = SdMmcHcUhsSignaling (Private->ControllerHandle, PciIo, Slot,
> Timing);
> +  Status = SdMmcHcUhsSignaling (Private->ControllerHandle, PciIo, Slot,
> BusMode->BusTiming);
>    if (EFI_ERROR (Status)) {
>      return Status;
>    }
> 
> -  HsTiming = 1;
> -  Status = EmmcSwitchBusTiming (PciIo, PassThru, Slot, Rca, HsTiming, Timing,
> ClockFreq);
> -
> -  return Status;
> +  return EmmcSwitchBusTiming (PciIo, PassThru, Slot, Rca, BusMode-
> >DriverStrength, BusMode->BusTiming, BusMode->ClockFreq);
>  }
> 
>  /**
> -  Switch to the HS200 timing according to request.
> +  Switch to the HS200 timing. This function assumes that eMMC bus is still in
> legacy mode.
> 
>    Refer to EMMC Electrical Standard Spec 5.1 Section 6.6.8 and SD Host
> Controller
>    Simplified Spec 3.0 Figure 2-29 for details.
> 
> -  @param[in] PciIo          A pointer to the EFI_PCI_IO_PROTOCOL instance.
> -  @param[in] PassThru       A pointer to the
> EFI_SD_MMC_PASS_THRU_PROTOCOL instance.
> -  @param[in] Slot           The slot number of the SD card to send the 
> command
> to.
> -  @param[in] Rca            The relative device address to be assigned.
> -  @param[in] ClockFreq      The max clock frequency to be set.
> -  @param[in] BusWidth       The bus width to be set, it could be 4 or 8.
> +  @param[in] PciIo           A pointer to the EFI_PCI_IO_PROTOCOL instance.
> +  @param[in] PassThru        A pointer to the
> EFI_SD_MMC_PASS_THRU_PROTOCOL instance.
> +  @param[in] Slot            The slot number of the SD card to send the
> command to.
> +  @param[in] Rca             The relative device address to be assigned.
> +  @param[in] BusMode         Pointer to SD_MMC_BUS_SETTINGS structure
> containing bus settings.
> 
>    @retval EFI_SUCCESS       The operation is done correctly.
>    @retval Others            The operation fails.
> @@ -822,30 +833,25 @@ EmmcSwitchToHS200 (
>    IN EFI_SD_MMC_PASS_THRU_PROTOCOL      *PassThru,
>    IN UINT8                              Slot,
>    IN UINT16                             Rca,
> -  IN UINT32                             ClockFreq,
> -  IN UINT8                              BusWidth
> +  IN SD_MMC_BUS_SETTINGS                *BusMode
>    )
>  {
>    EFI_STATUS               Status;
> -  UINT8                    HsTiming;
>    UINT16                   ClockCtrl;
> -  SD_MMC_BUS_MODE          Timing;
>    SD_MMC_HC_PRIVATE_DATA  *Private;
> 
>    Private = SD_MMC_HC_PRIVATE_FROM_THIS (PassThru);
> 
> -  if ((BusWidth != 4) && (BusWidth != 8)) {
> +  if (BusMode->BusTiming != SdMmcMmcHs200 ||
> +      (BusMode->BusWidth != 4 && BusMode->BusWidth != 8)) {
>      return EFI_INVALID_PARAMETER;
>    }
> 
> -  Status = EmmcSwitchBusWidth (PciIo, PassThru, Slot, Rca, FALSE, BusWidth);
> +  Status = EmmcSwitchBusWidth (PciIo, PassThru, Slot, Rca, FALSE,
> BusMode->BusWidth);
>    if (EFI_ERROR (Status)) {
>      return Status;
>    }
>    //
> -  // Set to HS200/SDR104 timing
> -  //
> -  //
>    // Stop bus clock at first
>    //
>    Status = SdMmcHcStopClock (PciIo, Slot);
> @@ -853,9 +859,7 @@ EmmcSwitchToHS200 (
>      return Status;
>    }
> 
> -  Timing = SdMmcMmcHs200;
> -
> -  Status = SdMmcHcUhsSignaling (Private->ControllerHandle, PciIo, Slot,
> Timing);
> +  Status = SdMmcHcUhsSignaling (Private->ControllerHandle, PciIo, Slot,
> BusMode->BusTiming);
>    if (EFI_ERROR (Status)) {
>      return Status;
>    }
> @@ -881,28 +885,27 @@ EmmcSwitchToHS200 (
>    ClockCtrl = BIT2;
>    Status = SdMmcHcOrMmio (PciIo, Slot, SD_MMC_HC_CLOCK_CTRL, sizeof
> (ClockCtrl), &ClockCtrl);
> 
> -  HsTiming = 2;
> -  Status = EmmcSwitchBusTiming (PciIo, PassThru, Slot, Rca, HsTiming, Timing,
> ClockFreq);
> +  Status = EmmcSwitchBusTiming (PciIo, PassThru, Slot, Rca, BusMode-
> >DriverStrength, BusMode->BusTiming, BusMode->ClockFreq);
>    if (EFI_ERROR (Status)) {
>      return Status;
>    }
> 
> -  Status = EmmcTuningClkForHs200 (PciIo, PassThru, Slot, BusWidth);
> +  Status = EmmcTuningClkForHs200 (PciIo, PassThru, Slot, BusMode-
> >BusWidth);
> 
>    return Status;
>  }
> 
>  /**
> -  Switch to the HS400 timing according to request.
> +  Switch to the HS400 timing. This function assumes that eMMC bus is still in
> legacy mode.
> 
>    Refer to EMMC Electrical Standard Spec 5.1 Section 6.6.8 and SD Host
> Controller
>    Simplified Spec 3.0 Figure 2-29 for details.
> 
> -  @param[in] PciIo          A pointer to the EFI_PCI_IO_PROTOCOL instance.
> -  @param[in] PassThru       A pointer to the
> EFI_SD_MMC_PASS_THRU_PROTOCOL instance.
> -  @param[in] Slot           The slot number of the SD card to send the 
> command
> to.
> -  @param[in] Rca            The relative device address to be assigned.
> -  @param[in] ClockFreq      The max clock frequency to be set.
> +  @param[in] PciIo           A pointer to the EFI_PCI_IO_PROTOCOL instance.
> +  @param[in] PassThru        A pointer to the
> EFI_SD_MMC_PASS_THRU_PROTOCOL instance.
> +  @param[in] Slot            The slot number of the SD card to send the
> command to.
> +  @param[in] Rca             The relative device address to be assigned.
> +  @param[in] BusMode         Pointer to SD_MMC_BUS_SETTINGS structure
> containing bus settings.
> 
>    @retval EFI_SUCCESS       The operation is done correctly.
>    @retval Others            The operation fails.
> @@ -914,47 +917,314 @@ EmmcSwitchToHS400 (
>    IN EFI_SD_MMC_PASS_THRU_PROTOCOL      *PassThru,
>    IN UINT8                              Slot,
>    IN UINT16                             Rca,
> -  IN UINT32                             ClockFreq
> +  IN SD_MMC_BUS_SETTINGS                *BusMode
>    )
>  {
>    EFI_STATUS                 Status;
> -  UINT8                      HsTiming;
> -  SD_MMC_BUS_MODE            Timing;
>    SD_MMC_HC_PRIVATE_DATA     *Private;
> +  SD_MMC_BUS_SETTINGS        Hs200BusMode;
> +  UINT32                     HsFreq;
> +
> +  if (BusMode->BusTiming != SdMmcMmcHs400 ||
> +      BusMode->BusWidth != 8) {
> +    return EFI_INVALID_PARAMETER;
> +  }
> 
>    Private = SD_MMC_HC_PRIVATE_FROM_THIS (PassThru);
> +  Hs200BusMode.BusTiming = SdMmcMmcHs200;
> +  Hs200BusMode.BusWidth = BusMode->BusWidth;
> +  Hs200BusMode.ClockFreq = BusMode->ClockFreq;
> +  Hs200BusMode.DriverStrength = BusMode->DriverStrength;
> 
> -  Status = EmmcSwitchToHS200 (PciIo, PassThru, Slot, Rca, ClockFreq, 8);
> +  Status = EmmcSwitchToHS200 (PciIo, PassThru, Slot, Rca, &Hs200BusMode);
>    if (EFI_ERROR (Status)) {
>      return Status;
>    }
> +
>    //
> -  // Set to Hight Speed timing and set the clock frequency to a value less 
> than
> 52MHz.
> +  // Set to High Speed timing and set the clock frequency to a value less 
> than
> or equal to 52MHz.
> +  // This step is necessary to be able to switch Bus into 8 bit DDR mode 
> which
> is unsupported in HS200.
>    //
> -  HsTiming = 1;
> -  Status = EmmcSwitchBusTiming (PciIo, PassThru, Slot, Rca, HsTiming,
> SdMmcMmcHsSdr, 52);
> +  Status = SdMmcHcUhsSignaling (Private->ControllerHandle, PciIo, Slot,
> SdMmcMmcHsSdr);
>    if (EFI_ERROR (Status)) {
>      return Status;
>    }
> -  //
> -  // HS400 mode must use 8 data lines.
> -  //
> -  Status = EmmcSwitchBusWidth (PciIo, PassThru, Slot, Rca, TRUE, 8);
> +
> +  HsFreq = BusMode->ClockFreq < 52 ? BusMode->ClockFreq : 52;
> +  Status = EmmcSwitchBusTiming (PciIo, PassThru, Slot, Rca, BusMode-
> >DriverStrength, SdMmcMmcHsSdr, HsFreq);
>    if (EFI_ERROR (Status)) {
>      return Status;
>    }
> 
> -  Timing = SdMmcMmcHs400;
> +  Status = EmmcSwitchBusWidth (PciIo, PassThru, Slot, Rca, TRUE, BusMode-
> >BusWidth);
> +  if (EFI_ERROR (Status)) {
> +    return Status;
> +  }
> 
> -  Status = SdMmcHcUhsSignaling (Private->ControllerHandle, PciIo, Slot,
> Timing);
> +  Status = SdMmcHcUhsSignaling (Private->ControllerHandle, PciIo, Slot,
> BusMode->BusTiming);
>    if (EFI_ERROR (Status)) {
>      return Status;
>    }
> 
> -  HsTiming = 3;
> -  Status = EmmcSwitchBusTiming (PciIo, PassThru, Slot, Rca, HsTiming, Timing,
> ClockFreq);
> +  return EmmcSwitchBusTiming (PciIo, PassThru, Slot, Rca, BusMode-
> >DriverStrength, BusMode->BusTiming, BusMode->ClockFreq);
> +}
> 
> -  return Status;
> +/**
> +  Check if passed BusTiming is supported in both controller and card.
> +
> +  @param[in] Private    Pointer to controller private data
> +  @param[in] SlotIndex  Index of the slot in the controller
> +  @param[in] ExtCsd     Pointer to the card's extended CSD
> +  @param[in] BusTiming  Bus timing to check
> +
> +  @retval TRUE  Both card and controller support given BusTiming
> +  @retval FALSE Card or controller doesn't support given BusTiming
> +**/
> +BOOLEAN
> +EmmcIsBusTimingSupported (
> +  IN SD_MMC_HC_PRIVATE_DATA  *Private,
> +  IN UINT8                   SlotIndex,
> +  IN EMMC_EXT_CSD            *ExtCsd,
> +  IN SD_MMC_BUS_MODE         BusTiming
> +  )
> +{
> +  BOOLEAN             Supported;
> +  SD_MMC_HC_SLOT_CAP  *Capabilities;
> +
> +  Capabilities = &Private->Capability[SlotIndex];
> +
> +  Supported = FALSE;
> +  switch (BusTiming) {
> +    case SdMmcMmcHs400:
> +      if ((((ExtCsd->DeviceType & (BIT6 | BIT7))  != 0) && (Capabilities-
> >Hs400 != 0)) && Capabilities->BusWidth8 != 0) {
> +        Supported = TRUE;
> +      }
> +      break;
> +    case SdMmcMmcHs200:
> +      if ((((ExtCsd->DeviceType & (BIT4 | BIT5))  != 0) && (Capabilities-
> >Sdr104 != 0))) {
> +        Supported = TRUE;
> +      }
> +      break;
> +    case SdMmcMmcHsDdr:
> +      if ((((ExtCsd->DeviceType & (BIT2 | BIT3))  != 0) && (Capabilities-
> >Ddr50 != 0))) {
> +        Supported = TRUE;
> +      }
> +      break;
> +    case SdMmcMmcHsSdr:
> +      if ((((ExtCsd->DeviceType & BIT1)  != 0) && (Capabilities->HighSpeed !=
> 0))) {
> +        Supported = TRUE;
> +      }
> +      break;
> +    case SdMmcMmcLegacy:
> +      if ((ExtCsd->DeviceType & BIT0) != 0) {
> +        Supported = TRUE;
> +      }
> +      break;
> +    default:
> +      ASSERT (FALSE);
> +  }
> +
> +  return Supported;
> +}
> +
> +/**
> +  Get the target bus timing to set on the link. This function
> +  will try to select highest bus timing supported by card, controller
> +  and the driver.
> +
> +  @param[in] Private    Pointer to controller private data
> +  @param[in] SlotIndex  Index of the slot in the controller
> +  @param[in] ExtCsd     Pointer to the card's extended CSD
> +
> +  @return  Bus timing value that should be set on link
> +**/
> +SD_MMC_BUS_MODE
> +EmmcGetTargetBusTiming (
> +  IN SD_MMC_HC_PRIVATE_DATA  *Private,
> +  IN UINT8                    SlotIndex,
> +  IN EMMC_EXT_CSD             *ExtCsd
> +  )
> +{
> +  SD_MMC_BUS_MODE  BusTiming;
> +
> +  //
> +  // We start with highest bus timing that this driver currently supports and
> +  // return as soon as we find supported timing.
> +  //
> +  BusTiming = SdMmcMmcHs400;
> +  while (BusTiming > SdMmcMmcLegacy) {
> +    if (EmmcIsBusTimingSupported (Private, SlotIndex, ExtCsd, BusTiming)) {
> +      break;
> +    }
> +    BusTiming--;
> +  }
> +
> +  return BusTiming;
> +}
> +
> +/**
> +  Check if the passed bus width is supported by controller and card.
> +
> +  @param[in] Private    Pointer to controller private data
> +  @param[in] SlotIndex  Index of the slot in the controller
> +  @param[in] BusTiming  Bus timing set on the link
> +  @param[in] BusWidth   Bus width to check
> +
> +  @retval TRUE   Passed bus width is supported in current bus configuration
> +  @retval FALSE  Passed bus width is not supported in current bus
> configuration
> +**/
> +BOOLEAN
> +EmmcIsBusWidthSupported (
> +  IN SD_MMC_HC_PRIVATE_DATA   *Private,
> +  IN UINT8                    SlotIndex,
> +  IN SD_MMC_BUS_MODE          BusTiming,
> +  IN UINT16                   BusWidth
> +  )
> +{
> +  if (BusWidth == 8 && Private->Capability[SlotIndex].BusWidth8 != 0) {
> +    return TRUE;
> +  } else if (BusWidth == 4 && BusTiming != SdMmcMmcHs400) {
> +    return TRUE;
> +  } else if (BusWidth == 1 && (BusTiming == SdMmcMmcHsSdr || BusTiming
> == SdMmcMmcLegacy)) {
> +    return TRUE;
> +  }
> +
> +  return FALSE;
> +}
> +
> +/**
> +  Get the target bus width to be set on the bus.
> +
> +  @param[in] Private    Pointer to controller private data
> +  @param[in] SlotIndex  Index of the slot in the controller
> +  @param[in] ExtCsd     Pointer to card's extended CSD
> +  @param[in] BusTiming  Bus timing set on the bus
> +
> +  @return Bus width to be set on the bus
> +**/
> +UINT8
> +EmmcGetTargetBusWidth (
> +  IN SD_MMC_HC_PRIVATE_DATA   *Private,
> +  IN UINT8                    SlotIndex,
> +  IN EMMC_EXT_CSD             *ExtCsd,
> +  IN SD_MMC_BUS_MODE          BusTiming
> +  )
> +{
> +  UINT8  BusWidth;
> +  UINT8  PreferredBusWidth;
> +
> +  PreferredBusWidth = Private-
> >Slot[SlotIndex].OperatingParameters.BusWidth;
> +
> +  if (PreferredBusWidth != EDKII_SD_MMC_BUS_WIDTH_IGNORE &&
> +      EmmcIsBusWidthSupported (Private, SlotIndex, BusTiming,
> PreferredBusWidth)) {
> +    BusWidth = PreferredBusWidth;
> +  } else if (EmmcIsBusWidthSupported (Private, SlotIndex, BusTiming, 8)) {
> +    BusWidth = 8;
> +  } else if (EmmcIsBusWidthSupported (Private, SlotIndex, BusTiming, 4)) {
> +    BusWidth = 4;
> +  } else {
> +    BusWidth = 1;
> +  }
> +
> +  return BusWidth;
> +}
> +
> +/**
> +  Get the target clock frequency to be set on the bus.
> +
> +  @param[in] Private    Pointer to controller private data
> +  @param[in] SlotIndex  Index of the slot in the controller
> +  @param[in] ExtCsd     Pointer to card's extended CSD
> +  @param[in] BusTiming  Bus timing to be set on the bus
> +
> +  @return Value of the clock frequency to be set on bus in MHz
> +**/
> +UINT32
> +EmmcGetTargetClockFreq (
> +  IN SD_MMC_HC_PRIVATE_DATA   *Private,
> +  IN UINT8                    SlotIndex,
> +  IN EMMC_EXT_CSD             *ExtCsd,
> +  IN SD_MMC_BUS_MODE          BusTiming
> +  )
> +{
> +  UINT32 PreferredClockFreq;
> +  UINT32 MaxClockFreq;
> +
> +  PreferredClockFreq = Private-
> >Slot[SlotIndex].OperatingParameters.ClockFreq;
> +
> +  switch (BusTiming) {
> +    case SdMmcMmcHs400:
> +    case SdMmcMmcHs200:
> +      MaxClockFreq = 200;
> +      break;
> +    case SdMmcMmcHsSdr:
> +    case SdMmcMmcHsDdr:
> +      MaxClockFreq = 52;
> +      break;
> +    default:
> +      MaxClockFreq = 26;
> +      break;
> +  }
> +
> +  if (PreferredClockFreq != EDKII_SD_MMC_CLOCK_FREQ_IGNORE &&
> PreferredClockFreq < MaxClockFreq) {
> +    return PreferredClockFreq;
> +  } else {
> +    return MaxClockFreq;
> +  }
> +}
> +
> +/**
> +  Get the driver strength to be set on bus.
> +
> +  @param[in] Private    Pointer to controller private data
> +  @param[in] SlotIndex  Index of the slot in the controller
> +  @param[in] ExtCsd     Pointer to card's extended CSD
> +  @param[in] BusTiming  Bus timing set on the bus
> +
> +  @return Value of the driver strength to be set on the bus
> +**/
> +EDKII_SD_MMC_DRIVER_STRENGTH
> +EmmcGetTargetDriverStrength (
> +  IN SD_MMC_HC_PRIVATE_DATA   *Private,
> +  IN UINT8                    SlotIndex,
> +  IN EMMC_EXT_CSD             *ExtCsd,
> +  IN SD_MMC_BUS_MODE          BusTiming
> +  )
> +{
> +  EDKII_SD_MMC_DRIVER_STRENGTH  PreferredDriverStrength;
> +  EDKII_SD_MMC_DRIVER_STRENGTH  DriverStrength;
> +
> +  PreferredDriverStrength = Private-
> >Slot[SlotIndex].OperatingParameters.DriverStrength;
> +  DriverStrength.Emmc = EmmcDriverStrengthType0;
> +
> +  if (PreferredDriverStrength.Emmc !=
> EDKII_SD_MMC_DRIVER_STRENGTH_IGNORE &&
> +      (ExtCsd->DriverStrength & (BIT0 << PreferredDriverStrength.Emmc))) {
> +    DriverStrength.Emmc = PreferredDriverStrength.Emmc;
> +  }
> +
> +  return DriverStrength;
> +}
> +
> +/**
> +  Get the target settings for the bus mode.
> +
> +  @param[in]  Private    Pointer to controller private data
> +  @param[in]  SlotIndex  Index of the slot in the controller
> +  @param[in]  ExtCsd     Pointer to card's extended CSD
> +  @param[out] BusMode    Target configuration of the bus
> +**/
> +VOID
> +EmmcGetTargetBusMode (
> +  IN SD_MMC_HC_PRIVATE_DATA  *Private,
> +  IN UINT8                   SlotIndex,
> +  IN EMMC_EXT_CSD            *ExtCsd,
> +  OUT SD_MMC_BUS_SETTINGS    *BusMode
> +  )
> +{
> +  BusMode->BusTiming = EmmcGetTargetBusTiming (Private, SlotIndex,
> ExtCsd);
> +  BusMode->BusWidth = EmmcGetTargetBusWidth (Private, SlotIndex,
> ExtCsd, BusMode->BusTiming);
> +  BusMode->ClockFreq = EmmcGetTargetClockFreq (Private, SlotIndex,
> ExtCsd, BusMode->BusTiming);
> +  BusMode->DriverStrength = EmmcGetTargetDriverStrength (Private,
> SlotIndex, ExtCsd, BusMode->BusTiming);
>  }
> 
>  /**
> @@ -983,10 +1253,7 @@ EmmcSetBusMode (
>    EFI_STATUS                    Status;
>    EMMC_CSD                      Csd;
>    EMMC_EXT_CSD                  ExtCsd;
> -  UINT8                         HsTiming;
> -  BOOLEAN                       IsDdr;
> -  UINT32                        ClockFreq;
> -  UINT8                         BusWidth;
> +  SD_MMC_BUS_SETTINGS           BusMode;
>    SD_MMC_HC_PRIVATE_DATA        *Private;
> 
>    Private = SD_MMC_HC_PRIVATE_FROM_THIS (PassThru);
> @@ -1004,85 +1271,30 @@ EmmcSetBusMode (
>    }
> 
>    ASSERT (Private->BaseClkFreq[Slot] != 0);
> +
>    //
> -  // Check if the Host Controller support 8bits bus width.
> -  //
> -  if (Private->Capability[Slot].BusWidth8 != 0) {
> -    BusWidth = 8;
> -  } else {
> -    BusWidth = 4;
> -  }
> -  //
> -  // Get Deivce_Type from EXT_CSD register.
> +  // Get Device_Type from EXT_CSD register.
>    //
>    Status = EmmcGetExtCsd (PassThru, Slot, &ExtCsd);
>    if (EFI_ERROR (Status)) {
>      DEBUG ((DEBUG_ERROR, "EmmcSetBusMode: GetExtCsd fails with %r\n",
> Status));
>      return Status;
>    }
> -  //
> -  // Calculate supported bus speed/bus width/clock frequency.
> -  //
> -  HsTiming  = 0;
> -  IsDdr     = FALSE;
> -  ClockFreq = 0;
> -  if (((ExtCsd.DeviceType & (BIT4 | BIT5))  != 0) && (Private-
> >Capability[Slot].Sdr104 != 0)) {
> -    HsTiming  = 2;
> -    IsDdr     = FALSE;
> -    ClockFreq = 200;
> -  } else if (((ExtCsd.DeviceType & (BIT2 | BIT3))  != 0) && (Private-
> >Capability[Slot].Ddr50 != 0)) {
> -    HsTiming  = 1;
> -    IsDdr     = TRUE;
> -    ClockFreq = 52;
> -  } else if (((ExtCsd.DeviceType & BIT1)  != 0) && (Private-
> >Capability[Slot].HighSpeed != 0)) {
> -    HsTiming  = 1;
> -    IsDdr     = FALSE;
> -    ClockFreq = 52;
> -  } else if (((ExtCsd.DeviceType & BIT0)  != 0) && (Private-
> >Capability[Slot].HighSpeed != 0)) {
> -    HsTiming  = 1;
> -    IsDdr     = FALSE;
> -    ClockFreq = 26;
> -  }
> -  //
> -  // Check if both of the device and the host controller support HS400 DDR
> mode.
> -  //
> -  if (((ExtCsd.DeviceType & (BIT6 | BIT7))  != 0) && (Private-
> >Capability[Slot].Hs400 != 0)) {
> -    //
> -    // The host controller supports 8bits bus.
> -    //
> -    ASSERT (BusWidth == 8);
> -    HsTiming  = 3;
> -    IsDdr     = TRUE;
> -    ClockFreq = 200;
> -  }
> 
> -  if ((ClockFreq == 0) || (HsTiming == 0)) {
> -    //
> -    // Continue using default setting.
> -    //
> -    return EFI_SUCCESS;
> -  }
> +  EmmcGetTargetBusMode (Private, Slot, &ExtCsd, &BusMode);
> 
> -  DEBUG ((DEBUG_INFO, "EmmcSetBusMode: HsTiming %d ClockFreq %d
> BusWidth %d Ddr %a\n", HsTiming, ClockFreq, BusWidth, IsDdr ?
> "TRUE":"FALSE"));
> +  DEBUG ((DEBUG_INFO, "EmmcSetBusMode: Target bus mode: timing
> = %d, width = %d, clock freq = %d, driver strength = %d\n",
> +                          BusMode.BusTiming, BusMode.BusWidth, 
> BusMode.ClockFreq,
> BusMode.DriverStrength.Emmc));
> 
> -  if (HsTiming == 3) {
> -    //
> -    // Execute HS400 timing switch procedure
> -    //
> -    Status = EmmcSwitchToHS400 (PciIo, PassThru, Slot, Rca, ClockFreq);
> -  } else if (HsTiming == 2) {
> -    //
> -    // Execute HS200 timing switch procedure
> -    //
> -    Status = EmmcSwitchToHS200 (PciIo, PassThru, Slot, Rca, ClockFreq,
> BusWidth);
> +  if (BusMode.BusTiming == SdMmcMmcHs400) {
> +    Status = EmmcSwitchToHS400 (PciIo, PassThru, Slot, Rca, &BusMode);
> +  } else if (BusMode.BusTiming == SdMmcMmcHs200) {
> +    Status = EmmcSwitchToHS200 (PciIo, PassThru, Slot, Rca, &BusMode);
>    } else {
> -    //
> -    // Execute High Speed timing switch procedure
> -    //
> -    Status = EmmcSwitchToHighSpeed (PciIo, PassThru, Slot, Rca, ClockFreq,
> IsDdr, BusWidth);
> +    Status = EmmcSwitchToHighSpeed (PciIo, PassThru, Slot, Rca, &BusMode);
>    }
> 
> -  DEBUG ((DEBUG_INFO, "EmmcSetBusMode: Switch to %a %r\n", (HsTiming
> == 3) ? "HS400" : ((HsTiming == 2) ? "HS200" : "HighSpeed"), Status));
> +  DEBUG ((DEBUG_INFO, "EmmcSetBusMode: Switch to %a %r\n",
> (BusMode.BusTiming == SdMmcMmcHs400) ? "HS400" :
> ((BusMode.BusTiming == SdMmcMmcHs200) ? "HS200" : "HighSpeed"),
> Status));
> 
>    return Status;
>  }
> diff --git a/MdeModulePkg/Bus/Pci/SdMmcPciHcDxe/SdDevice.c
> b/MdeModulePkg/Bus/Pci/SdMmcPciHcDxe/SdDevice.c
> index 17936a5492..88ece5256c 100644
> --- a/MdeModulePkg/Bus/Pci/SdMmcPciHcDxe/SdDevice.c
> +++ b/MdeModulePkg/Bus/Pci/SdMmcPciHcDxe/SdDevice.c
> @@ -313,10 +313,6 @@ SdCardSetRca (
>    return Status;
>  }
> 
> -
> -
> -
> -
>  /**
>    Send command SELECT_DESELECT_CARD to the SD device to
> select/deselect it.
> 
> @@ -472,14 +468,14 @@ SdCardSetBusWidth (
> 
>    Refer to SD Physical Layer Simplified Spec 4.1 Section 4.7 for details.
> 
> -  @param[in]  PassThru      A pointer to the
> EFI_SD_MMC_PASS_THRU_PROTOCOL instance.
> -  @param[in]  Slot          The slot number of the SD card to send the 
> command
> to.
> -  @param[in]  AccessMode    The value for access mode group.
> -  @param[in]  CommandSystem The value for command set group.
> -  @param[in]  DriveStrength The value for drive length group.
> -  @param[in]  PowerLimit    The value for power limit group.
> -  @param[in]  Mode          Switch or check function.
> -  @param[out] SwitchResp    The return switch function status.
> +  @param[in]  PassThru       A pointer to the
> EFI_SD_MMC_PASS_THRU_PROTOCOL instance.
> +  @param[in]  Slot           The slot number of the SD card to send the
> command to.
> +  @param[in]  BusTiming      Target bus timing based on which access group
> value will be set.
> +  @param[in]  CommandSystem  The value for command set group.
> +  @param[in]  DriverStrength The value for driver strength group.
> +  @param[in]  PowerLimit     The value for power limit group.
> +  @param[in]  Mode           Switch or check function.
> +  @param[out] SwitchResp     The return switch function status.
> 
>    @retval EFI_SUCCESS       The operation is done correctly.
>    @retval Others            The operation fails.
> @@ -489,9 +485,9 @@ EFI_STATUS
>  SdCardSwitch (
>    IN     EFI_SD_MMC_PASS_THRU_PROTOCOL  *PassThru,
>    IN     UINT8                          Slot,
> -  IN     UINT8                          AccessMode,
> +  IN     SD_MMC_BUS_MODE                BusTiming,
>    IN     UINT8                          CommandSystem,
> -  IN     UINT8                          DriveStrength,
> +  IN     SD_DRIVER_STRENGTH_TYPE        DriverStrength,
>    IN     UINT8                          PowerLimit,
>    IN     BOOLEAN                        Mode,
>       OUT UINT8                          *SwitchResp
> @@ -502,6 +498,7 @@ SdCardSwitch (
>    EFI_SD_MMC_PASS_THRU_COMMAND_PACKET   Packet;
>    EFI_STATUS                            Status;
>    UINT32                                ModeValue;
> +  UINT8                                 AccessMode;
> 
>    ZeroMem (&SdMmcCmdBlk, sizeof (SdMmcCmdBlk));
>    ZeroMem (&SdMmcStatusBlk, sizeof (SdMmcStatusBlk));
> @@ -516,14 +513,49 @@ SdCardSwitch (
>    SdMmcCmdBlk.ResponseType = SdMmcResponseTypeR1;
> 
>    ModeValue = Mode ? BIT31 : 0;
> -  SdMmcCmdBlk.CommandArgument = (AccessMode & 0xF) | ((PowerLimit
> & 0xF) << 4) | \
> -                                ((DriveStrength & 0xF) << 8) | 
> ((DriveStrength & 0xF) << 12)
> | \
> +
> +  switch (BusTiming) {
> +    case SdMmcUhsDdr50:
> +      AccessMode = 0x4;
> +      break;
> +    case SdMmcUhsSdr104:
> +      AccessMode = 0x3;
> +      break;
> +    case SdMmcUhsSdr50:
> +      AccessMode = 0x2;
> +      break;
> +    case SdMmcUhsSdr25:
> +    case SdMmcSdHs:
> +      AccessMode = 0x1;
> +      break;
> +    case SdMmcUhsSdr12:
> +    case SdMmcSdDs:
> +      AccessMode = 0;
> +      break;
> +    default:
> +      AccessMode = 0xF;
> +  }
> +
> +  SdMmcCmdBlk.CommandArgument = (AccessMode & 0xF) |
> ((CommandSystem & 0xF) << 4) | \
> +                                ((DriverStrength & 0xF) << 8) | ((PowerLimit 
> & 0xF) << 12) |
> \
>                                  ModeValue;
> 
>    Packet.InDataBuffer     = SwitchResp;
>    Packet.InTransferLength = 64;
> 
>    Status = SdMmcPassThruPassThru (PassThru, Slot, &Packet, NULL);
> +  if (EFI_ERROR (Status)) {
> +    return Status;
> +  }
> +
> +  if (Mode) {
> +    if ((((AccessMode & 0xF) != 0xF) && ((SwitchResp[16] & 0xF) !=
> AccessMode) ||
> +        (((CommandSystem & 0xF) != 0xF) && (((SwitchResp[16] >> 4) & 0xF) !=
> CommandSystem)) ||
> +        (((DriverStrength & 0xF) != 0xF) && ((SwitchResp[15] & 0xF) !=
> DriverStrength)) ||
> +        (((PowerLimit & 0xF) != 0xF) && (((SwitchResp[15] >> 4) & 0xF) !=
> PowerLimit)))) {
> +      return EFI_DEVICE_ERROR;
> +    }
> +  }
> 
>    return Status;
>  }
> @@ -748,6 +780,273 @@ SdCardSwitchBusWidth (
>    return Status;
>  }
> 
> +/**
> +  Check if passed BusTiming is supported in both controller and card.
> +
> +  @param[in] Private                  Pointer to controller private data
> +  @param[in] SlotIndex                Index of the slot in the controller
> +  @param[in] CardSupportedBusTimings  Bitmask indicating which bus
> timings are supported by card
> +  @param[in] IsInUhsI                 Flag indicating if link is in UHS-I
> +
> +  @retval TRUE  Both card and controller support given BusTiming
> +  @retval FALSE Card or controller doesn't support given BusTiming
> +**/
> +BOOLEAN
> +SdIsBusTimingSupported (
> +  IN SD_MMC_HC_PRIVATE_DATA   *Private,
> +  IN UINT8                    SlotIndex,
> +  IN UINT8                    CardSupportedBusTimings,
> +  IN BOOLEAN                  IsInUhsI,
> +  IN SD_MMC_BUS_MODE          BusTiming
> +  )
> +{
> +  SD_MMC_HC_SLOT_CAP           *Capability;
> +
> +  Capability = &Private->Capability[SlotIndex];
> +
> +  if (IsInUhsI) {
> +    switch (BusTiming) {
> +      case SdMmcUhsSdr104:
> +        if ((Capability->Sdr104 != 0) && ((CardSupportedBusTimings & BIT3) !=
> 0)) {
> +          return TRUE;
> +        }
> +        break;
> +      case SdMmcUhsDdr50:
> +        if ((Capability->Ddr50 != 0) && ((CardSupportedBusTimings & BIT4) != 
> 0))
> {
> +          return TRUE;
> +        }
> +        break;
> +      case SdMmcUhsSdr50:
> +        if ((Capability->Sdr50 != 0) && ((CardSupportedBusTimings & BIT2) != 
> 0))
> {
> +          return TRUE;
> +        }
> +        break;
> +      case SdMmcUhsSdr25:
> +        if ((CardSupportedBusTimings & BIT1) != 0) {
> +          return TRUE;
> +        }
> +        break;
> +      case SdMmcUhsSdr12:
> +        if ((CardSupportedBusTimings & BIT0) != 0) {
> +          return TRUE;
> +        }
> +        break;
> +      default:
> +        break;
> +    }
> +  } else {
> +    switch (BusTiming) {
> +      case SdMmcSdHs:
> +        if ((Capability->HighSpeed != 0) && (CardSupportedBusTimings &
> BIT1) != 0) {
> +          return TRUE;
> +        }
> +        break;
> +      case SdMmcSdDs:
> +        if ((CardSupportedBusTimings & BIT0) != 0) {
> +          return TRUE;
> +        }
> +        break;
> +      default:
> +        break;
> +    }
> +  }
> +
> +  return FALSE;
> +}
> +
> +/**
> +  Get the target bus timing to set on the link. This function
> +  will try to select highest bus timing supported by card, controller
> +  and the driver.
> +
> +  @param[in] Private                  Pointer to controller private data
> +  @param[in] SlotIndex                Index of the slot in the controller
> +  @param[in] CardSupportedBusTimings  Bitmask indicating which bus
> timings are supported by card
> +  @param[in] IsInUhsI                 Flag indicating if link is in UHS-I
> +
> +  @return  Bus timing value that should be set on link
> +**/
> +SD_MMC_BUS_MODE
> +SdGetTargetBusTiming (
> +  IN SD_MMC_HC_PRIVATE_DATA  *Private,
> +  IN UINT8                   SlotIndex,
> +  IN UINT8                   CardSupportedBusTimings,
> +  IN BOOLEAN                 IsInUhsI
> +  )
> +{
> +  SD_MMC_BUS_MODE  BusTiming;
> +
> +  if (IsInUhsI) {
> +    BusTiming = SdMmcUhsSdr104;
> +  } else {
> +    BusTiming = SdMmcSdHs;
> +  }
> +
> +  while (BusTiming > SdMmcSdDs) {
> +    if (SdIsBusTimingSupported (Private, SlotIndex,
> CardSupportedBusTimings, IsInUhsI, BusTiming)) {
> +      break;
> +    }
> +    BusTiming--;
> +  }
> +
> +  return BusTiming;
> +}
> +
> +/**
> +  Get the target bus width to be set on the bus.
> +
> +  @param[in] Private    Pointer to controller private data
> +  @param[in] SlotIndex  Index of the slot in the controller
> +  @param[in] BusTiming  Bus timing set on the bus
> +
> +  @return Bus width to be set on the bus
> +**/
> +UINT8
> +SdGetTargetBusWidth (
> +  IN SD_MMC_HC_PRIVATE_DATA   *Private,
> +  IN UINT8                    SlotIndex,
> +  IN SD_MMC_BUS_MODE          BusTiming
> +  )
> +{
> +  UINT8  BusWidth;
> +  UINT8  PreferredBusWidth;
> +
> +  PreferredBusWidth = Private-
> >Slot[SlotIndex].OperatingParameters.BusWidth;
> +
> +  if (BusTiming == SdMmcSdDs || BusTiming == SdMmcSdHs) {
> +    if (PreferredBusWidth != EDKII_SD_MMC_BUS_WIDTH_IGNORE &&
> +        (PreferredBusWidth == 1 || PreferredBusWidth == 4)) {
> +      BusWidth = PreferredBusWidth;
> +    } else {
> +      BusWidth = 4;
> +    }
> +  } else {
> +    //
> +    // UHS-I modes support only 4-bit width.
> +    // Switch to 4-bit has been done before calling this function anyway so
> +    // this is purely informational.
> +    //
> +    BusWidth = 4;
> +  }
> +
> +  return BusWidth;
> +}
> +
> +/**
> +  Get the target clock frequency to be set on the bus.
> +
> +  @param[in] Private    Pointer to controller private data
> +  @param[in] SlotIndex  Index of the slot in the controller
> +  @param[in] BusTiming  Bus timing to be set on the bus
> +
> +  @return Value of the clock frequency to be set on bus in MHz
> +**/
> +UINT32
> +SdGetTargetBusClockFreq (
> +  IN SD_MMC_HC_PRIVATE_DATA   *Private,
> +  IN UINT8                    SlotIndex,
> +  IN SD_MMC_BUS_MODE          BusTiming
> +  )
> +{
> +  UINT32 PreferredClockFreq;
> +  UINT32 MaxClockFreq;
> +
> +  PreferredClockFreq = Private-
> >Slot[SlotIndex].OperatingParameters.ClockFreq;
> +
> +  switch (BusTiming) {
> +    case SdMmcUhsSdr104:
> +      MaxClockFreq = 208;
> +      break;
> +    case SdMmcUhsSdr50:
> +      MaxClockFreq = 100;
> +      break;
> +    case SdMmcUhsDdr50:
> +    case SdMmcUhsSdr25:
> +    case SdMmcSdHs:
> +      MaxClockFreq = 50;
> +      break;
> +    case SdMmcUhsSdr12:
> +    case SdMmcSdDs:
> +    default:
> +      MaxClockFreq = 25;
> +  }
> +
> +  if (PreferredClockFreq != EDKII_SD_MMC_CLOCK_FREQ_IGNORE &&
> PreferredClockFreq < MaxClockFreq) {
> +    return PreferredClockFreq;
> +  } else {
> +    return MaxClockFreq;
> +  }
> +}
> +
> +/**
> +  Get the driver strength to be set on bus.
> +
> +  @param[in] Private                       Pointer to controller private data
> +  @param[in] SlotIndex                     Index of the slot in the 
> controller
> +  @param[in] CardSupportedDriverStrengths  Bitmask indicating which
> driver strengths are supported on the card
> +  @param[in] BusTiming                     Bus timing set on the bus
> +
> +  @return Value of the driver strength to be set on the bus
> +**/
> +EDKII_SD_MMC_DRIVER_STRENGTH
> +SdGetTargetDriverStrength (
> +  IN SD_MMC_HC_PRIVATE_DATA   *Private,
> +  IN UINT8                    SlotIndex,
> +  IN UINT8                    CardSupportedDriverStrengths,
> +  IN SD_MMC_BUS_MODE          BusTiming
> +  )
> +{
> +  EDKII_SD_MMC_DRIVER_STRENGTH  PreferredDriverStrength;
> +  EDKII_SD_MMC_DRIVER_STRENGTH  DriverStrength;
> +
> +  if (BusTiming == SdMmcSdDs || BusTiming == SdMmcSdHs) {
> +    DriverStrength.Sd = SdDriverStrengthIgnore;
> +    return DriverStrength;
> +  }
> +
> +  PreferredDriverStrength = Private-
> >Slot[SlotIndex].OperatingParameters.DriverStrength;
> +  DriverStrength.Sd = SdDriverStrengthTypeB;
> +
> +  if (PreferredDriverStrength.Sd !=
> EDKII_SD_MMC_DRIVER_STRENGTH_IGNORE &&
> +      (CardSupportedDriverStrengths & (BIT0 << PreferredDriverStrength.Sd)))
> {
> +
> +    if ((PreferredDriverStrength.Sd == SdDriverStrengthTypeA &&
> +        (Private->Capability[SlotIndex].DriverTypeA != 0)) ||
> +        (PreferredDriverStrength.Sd == SdDriverStrengthTypeC &&
> +        (Private->Capability[SlotIndex].DriverTypeC != 0)) ||
> +        (PreferredDriverStrength.Sd == SdDriverStrengthTypeD &&
> +        (Private->Capability[SlotIndex].DriverTypeD != 0))) {
> +      DriverStrength.Sd = PreferredDriverStrength.Sd;
> +    }
> +  }
> +
> +  return DriverStrength;
> +}
> +
> +/**
> +  Get the target settings for the bus mode.
> +
> +  @param[in]  Private          Pointer to controller private data
> +  @param[in]  SlotIndex        Index of the slot in the controller
> +  @param[in]  SwitchQueryResp  Pointer to switch query response
> +  @param[in]  IsInUhsI         Flag indicating if link is in UHS-I mode
> +  @param[out] BusMode          Target configuration of the bus
> +**/
> +VOID
> +SdGetTargetBusMode (
> +  IN SD_MMC_HC_PRIVATE_DATA  *Private,
> +  IN UINT8                   SlotIndex,
> +  IN UINT8                   *SwitchQueryResp,
> +  IN BOOLEAN                 IsInUhsI,
> +  OUT SD_MMC_BUS_SETTINGS    *BusMode
> +  )
> +{
> +  BusMode->BusTiming = SdGetTargetBusTiming (Private, SlotIndex,
> SwitchQueryResp[13], IsInUhsI);
> +  BusMode->BusWidth = SdGetTargetBusWidth (Private, SlotIndex,
> BusMode->BusTiming);
> +  BusMode->ClockFreq = SdGetTargetBusClockFreq (Private, SlotIndex,
> BusMode->BusTiming);
> +  BusMode->DriverStrength = SdGetTargetDriverStrength (Private,
> SlotIndex, SwitchQueryResp[9], BusMode->BusTiming);
> +}
> +
>  /**
>    Switch the high speed timing according to request.
> 
> @@ -775,13 +1074,10 @@ SdCardSetBusMode (
>  {
>    EFI_STATUS                   Status;
>    SD_MMC_HC_SLOT_CAP           *Capability;
> -  UINT32                       ClockFreq;
> -  UINT8                        BusWidth;
> -  UINT8                        AccessMode;
>    UINT8                        HostCtrl1;
>    UINT8                        SwitchResp[64];
> -  SD_MMC_BUS_MODE              Timing;
>    SD_MMC_HC_PRIVATE_DATA       *Private;
> +  SD_MMC_BUS_SETTINGS          BusMode;
> 
>    Private = SD_MMC_HC_PRIVATE_FROM_THIS (PassThru);
> 
> @@ -792,61 +1088,51 @@ SdCardSetBusMode (
>      return Status;
>    }
> 
> -  BusWidth = 4;
> -
> -  Status = SdCardSwitchBusWidth (PciIo, PassThru, Slot, Rca, BusWidth);
> -  if (EFI_ERROR (Status)) {
> -    return Status;
> +  if (S18A) {
> +    //
> +    // For UHS-I speed modes 4-bit data bus is requiered so we
> +    // switch here irrespective of platform preference.
> +    //
> +    Status = SdCardSwitchBusWidth (PciIo, PassThru, Slot, Rca, 4);
> +    if (EFI_ERROR (Status)) {
> +      return Status;
> +    }
>    }
> +
>    //
>    // Get the supported bus speed from SWITCH cmd return data group #1.
>    //
> -  Status = SdCardSwitch (PassThru, Slot, 0xF, 0xF, 0xF, 0xF, FALSE,
> SwitchResp);
> +  Status = SdCardSwitch (PassThru, Slot, 0xFF, 0xF, SdDriverStrengthIgnore,
> 0xF, FALSE, SwitchResp);
>    if (EFI_ERROR (Status)) {
>      return Status;
>    }
> -  //
> -  // Calculate supported bus speed/bus width/clock frequency by host and
> device capability.
> -  //
> -  ClockFreq = 0;
> -  if (S18A && (Capability->Sdr104 != 0) && ((SwitchResp[13] & BIT3) != 0)) {
> -    ClockFreq = 208;
> -    AccessMode = 3;
> -    Timing = SdMmcUhsSdr104;
> -  } else if (S18A && (Capability->Sdr50 != 0) && ((SwitchResp[13] & BIT2) != 
> 0))
> {
> -    ClockFreq = 100;
> -    AccessMode = 2;
> -    Timing = SdMmcUhsSdr50;
> -  } else if (S18A && (Capability->Ddr50 != 0) && ((SwitchResp[13] & BIT4) !=
> 0)) {
> -    ClockFreq = 50;
> -    AccessMode = 4;
> -    Timing = SdMmcUhsDdr50;
> -  } else if ((SwitchResp[13] & BIT1) != 0) {
> -    ClockFreq = 50;
> -    AccessMode = 1;
> -    Timing = SdMmcUhsSdr25;
> -  } else {
> -    ClockFreq = 25;
> -    AccessMode = 0;
> -    Timing = SdMmcUhsSdr12;
> +
> +  SdGetTargetBusMode (Private, Slot, SwitchResp, S18A, &BusMode);
> +
> +  DEBUG ((DEBUG_INFO, "SdCardSetBusMode: Target bus mode: bus timing
> = %d, bus width = %d, clock freq[MHz] = %d, driver strength = %d\n",
> +                         BusMode.BusTiming, BusMode.BusWidth, 
> BusMode.ClockFreq,
> BusMode.DriverStrength.Sd));
> +
> +  if (!S18A) {
> +    Status = SdCardSwitchBusWidth (PciIo, PassThru, Slot, Rca,
> BusMode.BusWidth);
> +    if (EFI_ERROR (Status)) {
> +      return Status;
> +    }
>    }
> 
> -  Status = SdCardSwitch (PassThru, Slot, AccessMode, 0xF, 0xF, 0xF, TRUE,
> SwitchResp);
> +  Status = SdCardSwitch (PassThru, Slot, BusMode.BusTiming, 0xF,
> BusMode.DriverStrength.Sd, 0xF, TRUE, SwitchResp);
>    if (EFI_ERROR (Status)) {
>      return Status;
>    }
> 
> -  if ((SwitchResp[16] & 0xF) != AccessMode) {
> -    DEBUG ((DEBUG_ERROR, "SdCardSetBusMode: Switch to AccessMode %d
> ClockFreq %d BusWidth %d fails! The Switch response is 0x%1x\n",
> AccessMode, ClockFreq, BusWidth, SwitchResp[16] & 0xF));
> -    return EFI_DEVICE_ERROR;
> +  Status = SdMmcSetDriverStrength (Private->PciIo, Slot,
> BusMode.DriverStrength.Sd);
> +  if (EFI_ERROR (Status)) {
> +    return Status;
>    }
> 
> -  DEBUG ((DEBUG_INFO, "SdCardSetBusMode: Switch to AccessMode %d
> ClockFreq %d BusWidth %d\n", AccessMode, ClockFreq, BusWidth));
> -
>    //
> -  // Set to Hight Speed timing
> +  // Set to High Speed timing
>    //
> -  if (AccessMode == 1) {
> +  if (BusMode.BusTiming == SdMmcSdHs) {
>      HostCtrl1 = BIT2;
>      Status = SdMmcHcOrMmio (PciIo, Slot, SD_MMC_HC_HOST_CTRL1, sizeof
> (HostCtrl1), &HostCtrl1);
>      if (EFI_ERROR (Status)) {
> @@ -854,12 +1140,12 @@ SdCardSetBusMode (
>      }
>    }
> 
> -  Status = SdMmcHcUhsSignaling (Private->ControllerHandle, PciIo, Slot,
> Timing);
> +  Status = SdMmcHcUhsSignaling (Private->ControllerHandle, PciIo, Slot,
> BusMode.BusTiming);
>    if (EFI_ERROR (Status)) {
>      return Status;
>    }
> 
> -  Status = SdMmcHcClockSupply (PciIo, Slot, ClockFreq * 1000, Private-
> >BaseClkFreq[Slot], Private->ControllerVersion[Slot]);
> +  Status = SdMmcHcClockSupply (PciIo, Slot, BusMode.ClockFreq * 1000,
> Private->BaseClkFreq[Slot], Private->ControllerVersion[Slot]);
>    if (EFI_ERROR (Status)) {
>      return Status;
>    }
> @@ -869,7 +1155,7 @@ SdCardSetBusMode (
>                            Private->ControllerHandle,
>                            Slot,
>                            EdkiiSdMmcSwitchClockFreqPost,
> -                          &Timing
> +                          &BusMode.BusTiming
>                            );
>      if (EFI_ERROR (Status)) {
>        DEBUG ((
> @@ -882,7 +1168,7 @@ SdCardSetBusMode (
>      }
>    }
> 
> -  if ((AccessMode == 3) || ((AccessMode == 2) && (Capability-
> >TuningSDR50 != 0))) {
> +  if ((BusMode.BusTiming == SdMmcUhsSdr104) || ((BusMode.BusTiming
> == SdMmcUhsSdr50) && (Capability->TuningSDR50 != 0))) {
>      Status = SdCardTuningClock (PciIo, PassThru, Slot);
>      if (EFI_ERROR (Status)) {
>        return Status;
> diff --git a/MdeModulePkg/Bus/Pci/SdMmcPciHcDxe/SdMmcPciHcDxe.c
> b/MdeModulePkg/Bus/Pci/SdMmcPciHcDxe/SdMmcPciHcDxe.c
> index 4881ee44cc..373f1bed45 100644
> --- a/MdeModulePkg/Bus/Pci/SdMmcPciHcDxe/SdMmcPciHcDxe.c
> +++ b/MdeModulePkg/Bus/Pci/SdMmcPciHcDxe/SdMmcPciHcDxe.c
> @@ -28,6 +28,11 @@ EFI_DRIVER_BINDING_PROTOCOL
> gSdMmcPciHcDriverBinding = {
>    NULL
>  };
> 
> +#define SLOT_INIT_TEMPLATE {0, UnknownSlot, 0, 0, 0, \
> +                               {EDKII_SD_MMC_BUS_WIDTH_IGNORE,\
> +                               EDKII_SD_MMC_CLOCK_FREQ_IGNORE,\
> +                               {EDKII_SD_MMC_DRIVER_STRENGTH_IGNORE}}}
> +
>  //
>  // Template for SD/MMC host controller private data.
>  //
> @@ -50,8 +55,12 @@ SD_MMC_HC_PRIVATE_DATA gSdMmcPciHcTemplate
> = {
>                                      // Queue
>    INITIALIZE_LIST_HEAD_VARIABLE (gSdMmcPciHcTemplate.Queue),
>    {                                 // Slot
> -    {0, UnknownSlot, 0, 0, 0}, {0, UnknownSlot, 0, 0, 0}, {0, UnknownSlot, 
> 0, 0,
> 0},
> -    {0, UnknownSlot, 0, 0, 0}, {0, UnknownSlot, 0, 0, 0}, {0, UnknownSlot, 
> 0, 0,
> 0}
> +    SLOT_INIT_TEMPLATE,
> +    SLOT_INIT_TEMPLATE,
> +    SLOT_INIT_TEMPLATE,
> +    SLOT_INIT_TEMPLATE,
> +    SLOT_INIT_TEMPLATE,
> +    SLOT_INIT_TEMPLATE
>    },
>    {                                 // Capability
>      {0},
> @@ -328,6 +337,7 @@ SdMmcPciHcEnumerateDevice (
> 
>    return;
>  }
> +
>  /**
>    Tests to see if this driver supports a given controller. If a child device 
> is
> provided,
>    it further tests to see if this driver supports creating a handle for the
> specified child device.
> @@ -619,7 +629,6 @@ SdMmcPciHcDriverBindingStart (
>    Support64BitDma = TRUE;
>    for (Slot = FirstBar; Slot < (FirstBar + SlotNum); Slot++) {
>      Private->Slot[Slot].Enable = TRUE;
> -
>      //
>      // Get SD/MMC Pci Host Controller Version
>      //
> @@ -635,19 +644,34 @@ SdMmcPciHcDriverBindingStart (
> 
>      Private->BaseClkFreq[Slot] = Private->Capability[Slot].BaseClkFreq;
> 
> -    if (mOverride != NULL && mOverride->Capability != NULL) {
> -      Status = mOverride->Capability (
> -                            Controller,
> -                            Slot,
> -                            &Private->Capability[Slot],
> -                            &Private->BaseClkFreq[Slot]
> -                            );
> -      if (EFI_ERROR (Status)) {
> -        DEBUG ((DEBUG_WARN, "%a: Failed to override capability - %r\n",
> -          __FUNCTION__, Status));
> -        continue;
> +    if (mOverride != NULL) {
> +      if (mOverride->Capability != NULL) {
> +        Status = mOverride->Capability (
> +                              Controller,
> +                              Slot,
> +                              &Private->Capability[Slot],
> +                              &Private->BaseClkFreq[Slot]
> +                              );
> +        if (EFI_ERROR (Status)) {
> +          DEBUG ((DEBUG_WARN, "%a: Failed to override capability - %r\n",
> +            __FUNCTION__, Status));
> +          continue;
> +        }
> +      }
> +
> +      if (mOverride->NotifyPhase != NULL) {
> +        Status = mOverride->NotifyPhase (
> +                              Controller,
> +                              Slot,
> +                              EdkiiSdMmcGetOperatingParam,
> +                              (VOID*)&Private->Slot[Slot].OperatingParameters
> +                              );
> +        if (EFI_ERROR (Status)) {
> +          DEBUG ((DEBUG_WARN, "%a: Failed to get operating parameters,
> using defaults\n", __FUNCTION__));
> +        }
>        }
>      }
> +
>      DumpCapabilityReg (Slot, &Private->Capability[Slot]);
>      DEBUG ((
>        DEBUG_INFO,
> diff --git a/MdeModulePkg/Bus/Pci/SdMmcPciHcDxe/SdMmcPciHcDxe.h
> b/MdeModulePkg/Bus/Pci/SdMmcPciHcDxe/SdMmcPciHcDxe.h
> index 77bbf83b76..c29e48767e 100644
> --- a/MdeModulePkg/Bus/Pci/SdMmcPciHcDxe/SdMmcPciHcDxe.h
> +++ b/MdeModulePkg/Bus/Pci/SdMmcPciHcDxe/SdMmcPciHcDxe.h
> @@ -78,11 +78,12 @@ typedef enum {
>  } EFI_SD_MMC_SLOT_TYPE;
> 
>  typedef struct {
> -  BOOLEAN                           Enable;
> -  EFI_SD_MMC_SLOT_TYPE              SlotType;
> -  BOOLEAN                           MediaPresent;
> -  BOOLEAN                           Initialized;
> -  SD_MMC_CARD_TYPE                  CardType;
> +  BOOLEAN                            Enable;
> +  EFI_SD_MMC_SLOT_TYPE               SlotType;
> +  BOOLEAN                            MediaPresent;
> +  BOOLEAN                            Initialized;
> +  SD_MMC_CARD_TYPE                   CardType;
> +  EDKII_SD_MMC_OPERATING_PARAMETERS  OperatingParameters;
>  } SD_MMC_HC_SLOT;
> 
>  typedef struct {
> @@ -120,6 +121,13 @@ typedef struct {
>    UINT32                              BaseClkFreq[SD_MMC_HC_MAX_SLOT];
>  } SD_MMC_HC_PRIVATE_DATA;
> 
> +typedef struct {
> +  SD_MMC_BUS_MODE               BusTiming;
> +  UINT8                         BusWidth;
> +  UINT32                        ClockFreq;
> +  EDKII_SD_MMC_DRIVER_STRENGTH  DriverStrength;
> +} SD_MMC_BUS_SETTINGS;
> +
>  #define SD_MMC_HC_TRB_SIG             SIGNATURE_32 ('T', 'R', 'B', 'T')
> 
>  //
> diff --git a/MdeModulePkg/Bus/Pci/SdMmcPciHcDxe/SdMmcPciHci.c
> b/MdeModulePkg/Bus/Pci/SdMmcPciHcDxe/SdMmcPciHci.c
> index 5d1f977e55..b9d04e0f17 100644
> --- a/MdeModulePkg/Bus/Pci/SdMmcPciHcDxe/SdMmcPciHci.c
> +++ b/MdeModulePkg/Bus/Pci/SdMmcPciHcDxe/SdMmcPciHci.c
> @@ -1339,6 +1339,40 @@ SdMmcHcUhsSignaling (
>    return EFI_SUCCESS;
>  }
> 
> +/**
> +  Set driver strength in host controller.
> +
> +  @param[in] PciIo           The PCI IO protocol instance.
> +  @param[in] SlotIndex       The slot index of the card.
> +  @param[in] DriverStrength  DriverStrength to set in the controller.
> +
> +  @retval EFI_SUCCESS  Driver strength programmed successfully.
> +  @retval Others       Failed to set driver strength.
> +**/
> +EFI_STATUS
> +SdMmcSetDriverStrength (
> +  IN EFI_PCI_IO_PROTOCOL      *PciIo,
> +  IN UINT8                    SlotIndex,
> +  IN SD_DRIVER_STRENGTH_TYPE  DriverStrength
> +  )
> +{
> +  EFI_STATUS  Status;
> +  UINT16      HostCtrl2;
> +
> +  if (DriverStrength == SdDriverStrengthIgnore) {
> +    return EFI_SUCCESS;
> +  }
> +
> +  HostCtrl2 = (UINT16)~SD_MMC_HC_CTRL_DRIVER_STRENGTH_MASK;
> +  Status = SdMmcHcAndMmio (PciIo, SlotIndex, SD_MMC_HC_HOST_CTRL2,
> sizeof (HostCtrl2), &HostCtrl2);
> +  if (EFI_ERROR (Status)) {
> +    return Status;
> +  }
> +
> +  HostCtrl2 = (DriverStrength << 4) &
> SD_MMC_HC_CTRL_DRIVER_STRENGTH_MASK;
> +  return SdMmcHcOrMmio (PciIo, SlotIndex, SD_MMC_HC_HOST_CTRL2,
> sizeof (HostCtrl2), &HostCtrl2);
> +}
> +
>  /**
>    Turn on/off LED.
> 
> diff --git a/MdeModulePkg/Bus/Pci/SdMmcPciHcDxe/SdMmcPciHci.h
> b/MdeModulePkg/Bus/Pci/SdMmcPciHcDxe/SdMmcPciHci.h
> index 0b0d415256..088c70451c 100644
> --- a/MdeModulePkg/Bus/Pci/SdMmcPciHcDxe/SdMmcPciHci.h
> +++ b/MdeModulePkg/Bus/Pci/SdMmcPciHcDxe/SdMmcPciHci.h
> @@ -72,6 +72,8 @@ SPDX-License-Identifier: BSD-2-Clause-Patent
>  #define SD_MMC_HC_CTRL_MMC_HS200      0x0003
>  #define SD_MMC_HC_CTRL_MMC_HS400      0x0005
> 
> +#define SD_MMC_HC_CTRL_DRIVER_STRENGTH_MASK  0x0030
> +
>  //
>  // The transfer modes supported by SD Host Controller
>  //
> @@ -617,4 +619,21 @@ SdMmcHcUhsSignaling (
>    IN SD_MMC_BUS_MODE        Timing
>    );
> 
> +/**
> +  Set driver strength in host controller.
> +
> +  @param[in] PciIo           The PCI IO protocol instance.
> +  @param[in] SlotIndex       The slot index of the card.
> +  @param[in] DriverStrength  DriverStrength to set in the controller.
> +
> +  @retval EFI_SUCCESS  Driver strength programmed successfully.
> +  @retval Others       Failed to set driver strength.
> +**/
> +EFI_STATUS
> +SdMmcSetDriverStrength (
> +  IN EFI_PCI_IO_PROTOCOL      *PciIo,
> +  IN UINT8                    SlotIndex,
> +  IN SD_DRIVER_STRENGTH_TYPE  DriverStrength
> +  );
> +
>  #endif
> --
> 2.14.1.windows.1


-=-=-=-=-=-=-=-=-=-=-=-
Groups.io Links: You receive all messages sent to this group.

View/Reply Online (#42912): https://edk2.groups.io/g/devel/message/42912
Mute This Topic: https://groups.io/mt/32214576/21656
Group Owner: devel+ow...@edk2.groups.io
Unsubscribe: https://edk2.groups.io/g/devel/unsub  [arch...@mail-archive.com]
-=-=-=-=-=-=-=-=-=-=-=-

Reply via email to