| 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);
|