MdeModulePkg/SdMmcPciHcDxe: Fix bus timing switch sequence

REF: https://bugzilla.tianocore.org/show_bug.cgi?id=2218

SD specification recommends switching card bus timing before
switching bus timing in controller. Emmc driver used to do
this switch other way around. This commit adds controller
timing switch in EmmcSwitchBusTiming function to enforce this
order and removes all controller timing programming from
EmmcSwitchToXXX functions.

Signed-off-by: Mateusz Albecki <mateusz.albecki@intel.com>
Reviewed-by: Hao A Wu <hao.a.wu@intel.com>
Tested-by: Hao A Wu <hao.a.wu@intel.com>
Tested-by: Marcin Wojtas <mw@semihalf.com>
This commit is contained in:
Albecki, Mateusz 2019-09-26 22:27:43 +08:00 committed by Hao A Wu
parent 206783aa7f
commit a8c1fc70db
1 changed files with 26 additions and 44 deletions

View File

@ -671,6 +671,7 @@ EmmcSwitchBusTiming (
UINT8 CmdSet;
UINT32 DevStatus;
SD_MMC_HC_PRIVATE_DATA *Private;
UINT8 HostCtrl1;
Private = SD_MMC_HC_PRIVATE_FROM_THIS (PassThru);
//
@ -704,6 +705,25 @@ EmmcSwitchBusTiming (
return Status;
}
if (BusTiming == SdMmcMmcHsSdr || BusTiming == SdMmcMmcHsDdr) {
HostCtrl1 = BIT2;
Status = SdMmcHcOrMmio (PciIo, Slot, SD_MMC_HC_HOST_CTRL1, sizeof (HostCtrl1), &HostCtrl1);
if (EFI_ERROR (Status)) {
return Status;
}
} else {
HostCtrl1 = (UINT8)~BIT2;
Status = SdMmcHcAndMmio (PciIo, Slot, SD_MMC_HC_HOST_CTRL1, sizeof (HostCtrl1), &HostCtrl1);
if (EFI_ERROR (Status)) {
return Status;
}
}
Status = SdMmcHcUhsSignaling (Private->ControllerHandle, PciIo, Slot, BusTiming);
if (EFI_ERROR (Status)) {
return Status;
}
//
// Convert the clock freq unit from MHz to KHz.
//
@ -772,12 +792,8 @@ EmmcSwitchToHighSpeed (
)
{
EFI_STATUS Status;
UINT8 HostCtrl1;
SD_MMC_HC_PRIVATE_DATA *Private;
BOOLEAN IsDdr;
Private = SD_MMC_HC_PRIVATE_FROM_THIS (PassThru);
if ((BusMode->BusTiming != SdMmcMmcHsSdr && BusMode->BusTiming != SdMmcMmcHsDdr) ||
BusMode->ClockFreq > 52) {
return EFI_INVALID_PARAMETER;
@ -794,20 +810,6 @@ EmmcSwitchToHighSpeed (
return Status;
}
//
// Set to High Speed timing
//
HostCtrl1 = BIT2;
Status = SdMmcHcOrMmio (PciIo, Slot, SD_MMC_HC_HOST_CTRL1, sizeof (HostCtrl1), &HostCtrl1);
if (EFI_ERROR (Status)) {
return Status;
}
Status = SdMmcHcUhsSignaling (Private->ControllerHandle, PciIo, Slot, BusMode->BusTiming);
if (EFI_ERROR (Status)) {
return Status;
}
return EmmcSwitchBusTiming (PciIo, PassThru, Slot, Rca, BusMode->DriverStrength, BusMode->BusTiming, BusMode->ClockFreq);
}
@ -837,9 +839,6 @@ EmmcSwitchToHS200 (
)
{
EFI_STATUS Status;
SD_MMC_HC_PRIVATE_DATA *Private;
Private = SD_MMC_HC_PRIVATE_FROM_THIS (PassThru);
if (BusMode->BusTiming != SdMmcMmcHs200 ||
(BusMode->BusWidth != 4 && BusMode->BusWidth != 8)) {
@ -851,11 +850,6 @@ EmmcSwitchToHS200 (
return Status;
}
Status = SdMmcHcUhsSignaling (Private->ControllerHandle, PciIo, Slot, BusMode->BusTiming);
if (EFI_ERROR (Status)) {
return Status;
}
Status = EmmcSwitchBusTiming (PciIo, PassThru, Slot, Rca, BusMode->DriverStrength, BusMode->BusTiming, BusMode->ClockFreq);
if (EFI_ERROR (Status)) {
return Status;
@ -892,7 +886,6 @@ EmmcSwitchToHS400 (
)
{
EFI_STATUS Status;
SD_MMC_HC_PRIVATE_DATA *Private;
SD_MMC_BUS_SETTINGS Hs200BusMode;
UINT32 HsFreq;
@ -901,7 +894,6 @@ EmmcSwitchToHS400 (
return EFI_INVALID_PARAMETER;
}
Private = SD_MMC_HC_PRIVATE_FROM_THIS (PassThru);
Hs200BusMode.BusTiming = SdMmcMmcHs200;
Hs200BusMode.BusWidth = BusMode->BusWidth;
Hs200BusMode.ClockFreq = BusMode->ClockFreq;
@ -916,11 +908,6 @@ EmmcSwitchToHS400 (
// 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.
//
Status = SdMmcHcUhsSignaling (Private->ControllerHandle, PciIo, Slot, SdMmcMmcHsSdr);
if (EFI_ERROR (Status)) {
return Status;
}
HsFreq = BusMode->ClockFreq < 52 ? BusMode->ClockFreq : 52;
Status = EmmcSwitchBusTiming (PciIo, PassThru, Slot, Rca, BusMode->DriverStrength, SdMmcMmcHsSdr, HsFreq);
if (EFI_ERROR (Status)) {
@ -932,11 +919,6 @@ EmmcSwitchToHS400 (
return Status;
}
Status = SdMmcHcUhsSignaling (Private->ControllerHandle, PciIo, Slot, BusMode->BusTiming);
if (EFI_ERROR (Status)) {
return Status;
}
return EmmcSwitchBusTiming (PciIo, PassThru, Slot, Rca, BusMode->DriverStrength, BusMode->BusTiming, BusMode->ClockFreq);
}