blob: d8c84c46435674e7fc11c9691ef8dafc18c8d682 [file] [log] [blame]
Author: Matt Delco <delco@chromium.org>
This enables eMMC booting when starting edk2 from depthcharge.
Previously the driver would bail out with an error while setting
the eMMC frequency. The underlying problem has to do with shifting
down to a slower mode and speed, which generally only happens in 1 place
in the code.
diff --git a/MdeModulePkg/Bus/Pci/SdMmcPciHcDxe/EmmcDevice.c b/MdeModulePkg/Bus/Pci/SdMmcPciHcDxe/EmmcDevice.c
index c5fd214307..fd0e8b4f17 100755
--- a/MdeModulePkg/Bus/Pci/SdMmcPciHcDxe/EmmcDevice.c
+++ b/MdeModulePkg/Bus/Pci/SdMmcPciHcDxe/EmmcDevice.c
@@ -676,6 +676,20 @@ EmmcSwitchClockFreq (
SD_MMC_HC_PRIVATE_DATA *Private;
Private = SD_MMC_HC_PRIVATE_FROM_THIS (PassThru);
+
+ //
+ // We should switch to the slower speed of the old and new modes before issuing the switch.
+ // The state of the old mode isn't saved, but 26 MHz is the slowest speed that's currently
+ // used so if we see that speed then we know it's the minimum and we can specify it.
+ //
+ if (ClockFreq <= 26) {
+ Status = SdMmcHcClockSupply (PciIo, Slot, ClockFreq * 1000, Private->Capability[Slot]);
+ if (EFI_ERROR (Status)) {
+ DEBUG ((DEBUG_ERROR, "EmmcSwitchClockFreq: Change to HC clock fails with %r\n", Status));
+ return Status;
+ }
+ }
+
//
// Write Byte, the Value field is written into the byte pointed by Index.
//
@@ -690,6 +704,36 @@ EmmcSwitchClockFreq (
return Status;
}
+ //
+ // If we've switched to the slowest speed then clear the UHS mode from the host controller.
+ // Conversely, if we're switching to HS400 (HsTiming==3) then enable UHS and increase to the
+ // new speed. If this action isn't performed here then the subsequent status query can
+ // encounter CRC errors.
+ //
+ if (ClockFreq <= 26) {
+ UINT8 HostCtrl2;
+ HostCtrl2 = (UINT8)~0x7;
+ Status = SdMmcHcAndMmio (PciIo, Slot, SD_MMC_HC_HOST_CTRL2, sizeof (HostCtrl2), &HostCtrl2);
+ if (EFI_ERROR (Status)) {
+ DEBUG ((DEBUG_ERROR, "EmmcSwitchClockFreq: Change to clear UHS Mode fails with %r\n", Status));
+ return Status;
+ }
+ }
+ if (HsTiming == 3) {
+ UINT8 HostCtrl2;
+ HostCtrl2 = BIT0 | BIT2;
+ Status = SdMmcHcOrMmio (PciIo, Slot, SD_MMC_HC_HOST_CTRL2, sizeof (HostCtrl2), &HostCtrl2);
+ if (EFI_ERROR (Status)) {
+ DEBUG ((DEBUG_ERROR, "EmmcSwitchClockFreq: Change to set UHS Mode fails with %r\n", Status));
+ return Status;
+ }
+ Status = SdMmcHcClockSupply (PciIo, Slot, ClockFreq * 1000, Private->Capability[Slot]);
+ if (EFI_ERROR (Status)) {
+ DEBUG ((DEBUG_ERROR, "EmmcSwitchClockFreq: Change to set UHS Mode fails with %r\n", Status));
+ return Status;
+ }
+ }
+
Status = EmmcSendStatus (PassThru, Slot, Rca, &DevStatus);
if (EFI_ERROR (Status)) {
DEBUG ((DEBUG_ERROR, "EmmcSwitchClockFreq: Send status fails with %r\n", Status));
@@ -705,7 +749,9 @@ EmmcSwitchClockFreq (
//
// Convert the clock freq unit from MHz to KHz.
//
- Status = SdMmcHcClockSupply (PciIo, Slot, ClockFreq * 1000, Private->Capability[Slot]);
+ if (ClockFreq > 26 && HsTiming != 3) {
+ Status = SdMmcHcClockSupply (PciIo, Slot, ClockFreq * 1000, Private->Capability[Slot]);
+ }
return Status;
}
@@ -912,7 +958,9 @@ EmmcSwitchToHS400 (
{
EFI_STATUS Status;
UINT8 HsTiming;
+#if 0
UINT8 HostCtrl2;
+#endif
Status = EmmcSwitchToHS200 (PciIo, PassThru, Slot, Rca, ClockFreq, 8);
if (EFI_ERROR (Status)) {
@@ -920,9 +968,11 @@ EmmcSwitchToHS400 (
}
//
// Set to Hight Speed timing and set the clock frequency to a value less than 52MHz.
+ // 26 Mhz is specified to trigger a workaround in EmmcSwitchClockFreq that slows
+ // down the clock before issuing the switch command.
//
HsTiming = 1;
- Status = EmmcSwitchClockFreq (PciIo, PassThru, Slot, Rca, HsTiming, 52);
+ Status = EmmcSwitchClockFreq (PciIo, PassThru, Slot, Rca, HsTiming, 26);
if (EFI_ERROR (Status)) {
return Status;
}
@@ -933,6 +983,7 @@ EmmcSwitchToHS400 (
if (EFI_ERROR (Status)) {
return Status;
}
+#if 0
//
// Clean UHS Mode Select field of Host Control 2 reigster before update
//
@@ -949,6 +1000,7 @@ EmmcSwitchToHS400 (
if (EFI_ERROR (Status)) {
return Status;
}
+#endif
HsTiming = 3;
Status = EmmcSwitchClockFreq (PciIo, PassThru, Slot, Rca, HsTiming, ClockFreq);
@@ -1164,4 +1216,3 @@ EmmcIdentification (
return Status;
}
-
diff --git a/MdeModulePkg/Bus/Pci/SdMmcPciHcDxe/SdMmcPciHci.c b/MdeModulePkg/Bus/Pci/SdMmcPciHcDxe/SdMmcPciHci.c
index aa75aa8d24..dd852a9068 100644
--- a/MdeModulePkg/Bus/Pci/SdMmcPciHcDxe/SdMmcPciHci.c
+++ b/MdeModulePkg/Bus/Pci/SdMmcPciHcDxe/SdMmcPciHci.c
@@ -1637,6 +1637,15 @@ SdMmcExecTrb (
}
}
//
+ // Disable CRC on Switch command for EMMC -- we only care about the busy signal.
+ // SD's SD_SWITCH_FUNC uses SdMmcCommandTypeAdtc and SdMmcResponseTypeR1
+ //
+ if (Packet->SdMmcCmdBlk->CommandIndex == EMMC_SWITCH &&
+ Packet->SdMmcCmdBlk->CommandType == SdMmcCommandTypeAc &&
+ Packet->SdMmcCmdBlk->ResponseType == SdMmcResponseTypeR1b) {
+ Cmd &= ~(BIT3);
+ }
+ //
// Execute cmd
//
Status = SdMmcHcRwMmio (PciIo, Trb->Slot, SD_MMC_HC_COMMAND, FALSE, sizeof (Cmd), &Cmd);