summaryrefslogtreecommitdiff
path: root/MdeModulePkg/Bus
diff options
context:
space:
mode:
Diffstat (limited to 'MdeModulePkg/Bus')
-rw-r--r--MdeModulePkg/Bus/Pci/SdMmcPciHcDxe/EmmcDevice.c88
-rw-r--r--MdeModulePkg/Bus/Pci/SdMmcPciHcDxe/SdMmcPciHcDxe.c2
-rw-r--r--MdeModulePkg/Bus/Pci/SdMmcPciHcDxe/SdMmcPciHcDxe.h1
-rw-r--r--MdeModulePkg/Bus/Pci/SdMmcPciHcDxe/SdMmcPciHci.c2
4 files changed, 69 insertions, 24 deletions
diff --git a/MdeModulePkg/Bus/Pci/SdMmcPciHcDxe/EmmcDevice.c b/MdeModulePkg/Bus/Pci/SdMmcPciHcDxe/EmmcDevice.c
index 776c0e7..8b5f8e8 100644
--- a/MdeModulePkg/Bus/Pci/SdMmcPciHcDxe/EmmcDevice.c
+++ b/MdeModulePkg/Bus/Pci/SdMmcPciHcDxe/EmmcDevice.c
@@ -559,6 +559,43 @@ EmmcTuningClkForHs200 (
}
/**
+ Check the SWITCH operation status.
+
+ @param[in] PassThru A pointer to the EFI_SD_MMC_PASS_THRU_PROTOCOL instance.
+ @param[in] Slot The slot number on which command should be sent.
+ @param[in] Rca The relative device address.
+
+ @retval EFI_SUCCESS The SWITCH finished siccessfully.
+ @retval others The SWITCH failed.
+**/
+EFI_STATUS
+EmmcCheckSwitchStatus (
+ IN EFI_SD_MMC_PASS_THRU_PROTOCOL *PassThru,
+ IN UINT8 Slot,
+ IN UINT16 Rca
+ )
+{
+ EFI_STATUS Status;
+ UINT32 DevStatus;
+
+ Status = EmmcSendStatus (PassThru, Slot, Rca, &DevStatus);
+ if (EFI_ERROR (Status)) {
+ DEBUG ((DEBUG_ERROR, "EmmcCheckSwitchStatus: Send status fails with %r\n", Status));
+ return Status;
+ }
+
+ //
+ // Check the switch operation is really successful or not.
+ //
+ if ((DevStatus & BIT7) != 0) {
+ DEBUG ((DEBUG_ERROR, "EmmcCheckSwitchStatus: The switch operation fails as DevStatus is 0x%08x\n", DevStatus));
+ return EFI_DEVICE_ERROR;
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
Switch the bus width to specified width.
Refer to EMMC Electrical Standard Spec 5.1 Section 6.6.9 and SD Host Controller
@@ -591,7 +628,6 @@ EmmcSwitchBusWidth (
UINT8 Index;
UINT8 Value;
UINT8 CmdSet;
- UINT32 DevStatus;
//
// Write Byte, the Value field is written into the byte pointed by Index.
@@ -617,18 +653,10 @@ EmmcSwitchBusWidth (
return Status;
}
- Status = EmmcSendStatus (PassThru, Slot, Rca, &DevStatus);
+ Status = EmmcCheckSwitchStatus (PassThru, Slot, Rca);
if (EFI_ERROR (Status)) {
- DEBUG ((DEBUG_ERROR, "EmmcSwitchBusWidth: Send status fails with %r\n", Status));
return Status;
}
- //
- // Check the switch operation is really successful or not.
- //
- if ((DevStatus & BIT7) != 0) {
- DEBUG ((DEBUG_ERROR, "EmmcSwitchBusWidth: The switch operation fails as DevStatus is 0x%08x\n", DevStatus));
- return EFI_DEVICE_ERROR;
- }
Status = SdMmcHcSetBusWidth (PciIo, Slot, BusWidth);
@@ -669,9 +697,9 @@ EmmcSwitchBusTiming (
UINT8 Index;
UINT8 Value;
UINT8 CmdSet;
- UINT32 DevStatus;
SD_MMC_HC_PRIVATE_DATA *Private;
UINT8 HostCtrl1;
+ BOOLEAN DelaySendStatus;
Private = SD_MMC_HC_PRIVATE_FROM_THIS (PassThru);
//
@@ -695,7 +723,7 @@ EmmcSwitchBusTiming (
Value = 0;
break;
default:
- DEBUG ((DEBUG_ERROR, "EmmcSwitchBusTiming: Unsupported BusTiming(%d\n)", BusTiming));
+ DEBUG ((DEBUG_ERROR, "EmmcSwitchBusTiming: Unsupported BusTiming(%d)\n", BusTiming));
return EFI_INVALID_PARAMETER;
}
@@ -725,6 +753,26 @@ EmmcSwitchBusTiming (
}
//
+ // For cases when we switch bus timing to higher mode from current we want to
+ // send SEND_STATUS at current, lower, frequency then the target frequency to avoid
+ // stability issues. It has been observed that some designs are unable to process the
+ // SEND_STATUS at higher frequency during switch to HS200 @200MHz irrespective of the number of retries
+ // and only running the clock tuning is able to make them work at target frequency.
+ //
+ // For cases when we are downgrading the frequency and current high frequency is invalid
+ // we have to first change the frequency to target frequency and then send the SEND_STATUS.
+ //
+ if (Private->Slot[Slot].CurrentFreq < (ClockFreq * 1000)) {
+ Status = EmmcCheckSwitchStatus (PassThru, Slot, Rca);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ DelaySendStatus = FALSE;
+ } else {
+ DelaySendStatus = TRUE;
+ }
+
+ //
// Convert the clock freq unit from MHz to KHz.
//
Status = SdMmcHcClockSupply (Private, Slot, BusTiming, FALSE, ClockFreq * 1000);
@@ -732,17 +780,11 @@ EmmcSwitchBusTiming (
return Status;
}
- Status = EmmcSendStatus (PassThru, Slot, Rca, &DevStatus);
- if (EFI_ERROR (Status)) {
- DEBUG ((DEBUG_ERROR, "EmmcSwitchBusTiming: Send status fails with %r\n", Status));
- return Status;
- }
- //
- // Check the switch operation is really successful or not.
- //
- if ((DevStatus & BIT7) != 0) {
- DEBUG ((DEBUG_ERROR, "EmmcSwitchBusTiming: The switch operation fails as DevStatus is 0x%08x\n", DevStatus));
- return EFI_DEVICE_ERROR;
+ if (DelaySendStatus) {
+ Status = EmmcCheckSwitchStatus (PassThru, Slot, Rca);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
}
return Status;
diff --git a/MdeModulePkg/Bus/Pci/SdMmcPciHcDxe/SdMmcPciHcDxe.c b/MdeModulePkg/Bus/Pci/SdMmcPciHcDxe/SdMmcPciHcDxe.c
index b18ff3e..57f4cf3 100644
--- a/MdeModulePkg/Bus/Pci/SdMmcPciHcDxe/SdMmcPciHcDxe.c
+++ b/MdeModulePkg/Bus/Pci/SdMmcPciHcDxe/SdMmcPciHcDxe.c
@@ -28,7 +28,7 @@ EFI_DRIVER_BINDING_PROTOCOL gSdMmcPciHcDriverBinding = {
NULL
};
-#define SLOT_INIT_TEMPLATE {0, UnknownSlot, 0, 0, 0, \
+#define SLOT_INIT_TEMPLATE {0, UnknownSlot, 0, 0, 0, 0, \
{EDKII_SD_MMC_BUS_WIDTH_IGNORE,\
EDKII_SD_MMC_CLOCK_FREQ_IGNORE,\
{EDKII_SD_MMC_DRIVER_STRENGTH_IGNORE}}}
diff --git a/MdeModulePkg/Bus/Pci/SdMmcPciHcDxe/SdMmcPciHcDxe.h b/MdeModulePkg/Bus/Pci/SdMmcPciHcDxe/SdMmcPciHcDxe.h
index 5bc3577..bb3d384 100644
--- a/MdeModulePkg/Bus/Pci/SdMmcPciHcDxe/SdMmcPciHcDxe.h
+++ b/MdeModulePkg/Bus/Pci/SdMmcPciHcDxe/SdMmcPciHcDxe.h
@@ -83,6 +83,7 @@ typedef struct {
BOOLEAN MediaPresent;
BOOLEAN Initialized;
SD_MMC_CARD_TYPE CardType;
+ UINT64 CurrentFreq;
EDKII_SD_MMC_OPERATING_PARAMETERS OperatingParameters;
} SD_MMC_HC_SLOT;
diff --git a/MdeModulePkg/Bus/Pci/SdMmcPciHcDxe/SdMmcPciHci.c b/MdeModulePkg/Bus/Pci/SdMmcPciHcDxe/SdMmcPciHci.c
index 43626ff..7971196 100644
--- a/MdeModulePkg/Bus/Pci/SdMmcPciHcDxe/SdMmcPciHci.c
+++ b/MdeModulePkg/Bus/Pci/SdMmcPciHcDxe/SdMmcPciHci.c
@@ -931,6 +931,8 @@ SdMmcHcClockSupply (
}
}
+ Private->Slot[Slot].CurrentFreq = ClockFreq;
+
return Status;
}