return EFI_DEVICE_ERROR;\r
}\r
\r
+/**\r
+ Check the SWITCH operation status.\r
+\r
+ @param[in] PassThru A pointer to the EFI_SD_MMC_PASS_THRU_PROTOCOL instance.\r
+ @param[in] Slot The slot number on which command should be sent.\r
+ @param[in] Rca The relative device address.\r
+\r
+ @retval EFI_SUCCESS The SWITCH finished siccessfully.\r
+ @retval others The SWITCH failed.\r
+**/\r
+EFI_STATUS\r
+EmmcCheckSwitchStatus (\r
+ IN EFI_SD_MMC_PASS_THRU_PROTOCOL *PassThru,\r
+ IN UINT8 Slot,\r
+ IN UINT16 Rca\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ UINT32 DevStatus;\r
+\r
+ Status = EmmcSendStatus (PassThru, Slot, Rca, &DevStatus);\r
+ if (EFI_ERROR (Status)) {\r
+ DEBUG ((DEBUG_ERROR, "EmmcCheckSwitchStatus: Send status fails with %r\n", Status));\r
+ return Status;\r
+ }\r
+\r
+ //\r
+ // Check the switch operation is really successful or not.\r
+ //\r
+ if ((DevStatus & BIT7) != 0) {\r
+ DEBUG ((DEBUG_ERROR, "EmmcCheckSwitchStatus: The switch operation fails as DevStatus is 0x%08x\n", DevStatus));\r
+ return EFI_DEVICE_ERROR;\r
+ }\r
+\r
+ return EFI_SUCCESS;\r
+}\r
+\r
/**\r
Switch the bus width to specified width.\r
\r
UINT8 Index;\r
UINT8 Value;\r
UINT8 CmdSet;\r
- UINT32 DevStatus;\r
\r
//\r
// Write Byte, the Value field is written into the byte pointed by Index.\r
return Status;\r
}\r
\r
- Status = EmmcSendStatus (PassThru, Slot, Rca, &DevStatus);\r
+ Status = EmmcCheckSwitchStatus (PassThru, Slot, Rca);\r
if (EFI_ERROR (Status)) {\r
- DEBUG ((DEBUG_ERROR, "EmmcSwitchBusWidth: Send status fails with %r\n", Status));\r
return Status;\r
}\r
- //\r
- // Check the switch operation is really successful or not.\r
- //\r
- if ((DevStatus & BIT7) != 0) {\r
- DEBUG ((DEBUG_ERROR, "EmmcSwitchBusWidth: The switch operation fails as DevStatus is 0x%08x\n", DevStatus));\r
- return EFI_DEVICE_ERROR;\r
- }\r
\r
Status = SdMmcHcSetBusWidth (PciIo, Slot, BusWidth);\r
\r
UINT8 Index;\r
UINT8 Value;\r
UINT8 CmdSet;\r
- UINT32 DevStatus;\r
SD_MMC_HC_PRIVATE_DATA *Private;\r
+ UINT8 HostCtrl1;\r
+ BOOLEAN DelaySendStatus;\r
\r
Private = SD_MMC_HC_PRIVATE_FROM_THIS (PassThru);\r
//\r
Value = 0;\r
break;\r
default:\r
- DEBUG ((DEBUG_ERROR, "EmmcSwitchBusTiming: Unsupported BusTiming(%d\n)", BusTiming));\r
+ DEBUG ((DEBUG_ERROR, "EmmcSwitchBusTiming: Unsupported BusTiming(%d)\n", BusTiming));\r
return EFI_INVALID_PARAMETER;\r
}\r
\r
return Status;\r
}\r
\r
- //\r
- // Convert the clock freq unit from MHz to KHz.\r
- //\r
- Status = SdMmcHcClockSupply (PciIo, Slot, ClockFreq * 1000, Private->BaseClkFreq[Slot], Private->ControllerVersion[Slot]);\r
- if (EFI_ERROR (Status)) {\r
- return Status;\r
+ if (BusTiming == SdMmcMmcHsSdr || BusTiming == SdMmcMmcHsDdr) {\r
+ HostCtrl1 = BIT2;\r
+ Status = SdMmcHcOrMmio (PciIo, Slot, SD_MMC_HC_HOST_CTRL1, sizeof (HostCtrl1), &HostCtrl1);\r
+ if (EFI_ERROR (Status)) {\r
+ return Status;\r
+ }\r
+ } else {\r
+ HostCtrl1 = (UINT8)~BIT2;\r
+ Status = SdMmcHcAndMmio (PciIo, Slot, SD_MMC_HC_HOST_CTRL1, sizeof (HostCtrl1), &HostCtrl1);\r
+ if (EFI_ERROR (Status)) {\r
+ return Status;\r
+ }\r
}\r
\r
- Status = EmmcSendStatus (PassThru, Slot, Rca, &DevStatus);\r
+ Status = SdMmcHcUhsSignaling (Private->ControllerHandle, PciIo, Slot, BusTiming);\r
if (EFI_ERROR (Status)) {\r
- DEBUG ((DEBUG_ERROR, "EmmcSwitchBusTiming: Send status fails with %r\n", Status));\r
return Status;\r
}\r
+\r
//\r
- // Check the switch operation is really successful or not.\r
+ // For cases when we switch bus timing to higher mode from current we want to\r
+ // send SEND_STATUS at current, lower, frequency then the target frequency to avoid\r
+ // stability issues. It has been observed that some designs are unable to process the\r
+ // SEND_STATUS at higher frequency during switch to HS200 @200MHz irrespective of the number of retries\r
+ // and only running the clock tuning is able to make them work at target frequency.\r
//\r
- if ((DevStatus & BIT7) != 0) {\r
- DEBUG ((DEBUG_ERROR, "EmmcSwitchBusTiming: The switch operation fails as DevStatus is 0x%08x\n", DevStatus));\r
- return EFI_DEVICE_ERROR;\r
+ // For cases when we are downgrading the frequency and current high frequency is invalid\r
+ // we have to first change the frequency to target frequency and then send the SEND_STATUS.\r
+ //\r
+ if (Private->Slot[Slot].CurrentFreq < (ClockFreq * 1000)) {\r
+ Status = EmmcCheckSwitchStatus (PassThru, Slot, Rca);\r
+ if (EFI_ERROR (Status)) {\r
+ return Status;\r
+ }\r
+ DelaySendStatus = FALSE;\r
+ } else {\r
+ DelaySendStatus = TRUE;\r
+ }\r
+\r
+ //\r
+ // Convert the clock freq unit from MHz to KHz.\r
+ //\r
+ Status = SdMmcHcClockSupply (Private, Slot, BusTiming, FALSE, ClockFreq * 1000);\r
+ if (EFI_ERROR (Status)) {\r
+ return Status;\r
}\r
\r
- if (mOverride != NULL && mOverride->NotifyPhase != NULL) {\r
- Status = mOverride->NotifyPhase (\r
- Private->ControllerHandle,\r
- Slot,\r
- EdkiiSdMmcSwitchClockFreqPost,\r
- &BusTiming\r
- );\r
+ if (DelaySendStatus) {\r
+ Status = EmmcCheckSwitchStatus (PassThru, Slot, Rca);\r
if (EFI_ERROR (Status)) {\r
- DEBUG ((\r
- DEBUG_ERROR,\r
- "%a: SD/MMC switch clock freq post notifier callback failed - %r\n",\r
- __FUNCTION__,\r
- Status\r
- ));\r
return Status;\r
}\r
}\r
IN SD_MMC_BUS_SETTINGS *BusMode\r
)\r
{\r
- EFI_STATUS Status;\r
- UINT8 HostCtrl1;\r
- SD_MMC_HC_PRIVATE_DATA *Private;\r
- BOOLEAN IsDdr;\r
+ EFI_STATUS Status;\r
+ BOOLEAN IsDdr;\r
\r
- Private = SD_MMC_HC_PRIVATE_FROM_THIS (PassThru);\r
-\r
- if ((BusMode->BusTiming != SdMmcMmcHsSdr && BusMode->BusTiming != SdMmcMmcHsDdr) ||\r
+ if ((BusMode->BusTiming != SdMmcMmcHsSdr && BusMode->BusTiming != SdMmcMmcHsDdr && BusMode->BusTiming != SdMmcMmcLegacy) ||\r
BusMode->ClockFreq > 52) {\r
return EFI_INVALID_PARAMETER;\r
}\r
return Status;\r
}\r
\r
- //\r
- // Set to High Speed timing\r
- //\r
- HostCtrl1 = BIT2;\r
- Status = SdMmcHcOrMmio (PciIo, Slot, SD_MMC_HC_HOST_CTRL1, sizeof (HostCtrl1), &HostCtrl1);\r
- if (EFI_ERROR (Status)) {\r
- return Status;\r
- }\r
-\r
- Status = SdMmcHcUhsSignaling (Private->ControllerHandle, PciIo, Slot, BusMode->BusTiming);\r
- if (EFI_ERROR (Status)) {\r
- return Status;\r
- }\r
-\r
return EmmcSwitchBusTiming (PciIo, PassThru, Slot, Rca, BusMode->DriverStrength, BusMode->BusTiming, BusMode->ClockFreq);\r
}\r
\r
IN SD_MMC_BUS_SETTINGS *BusMode\r
)\r
{\r
- EFI_STATUS Status;\r
- SD_MMC_HC_PRIVATE_DATA *Private;\r
-\r
- Private = SD_MMC_HC_PRIVATE_FROM_THIS (PassThru);\r
+ EFI_STATUS Status;\r
\r
if (BusMode->BusTiming != SdMmcMmcHs200 ||\r
(BusMode->BusWidth != 4 && BusMode->BusWidth != 8)) {\r
return Status;\r
}\r
\r
- Status = SdMmcHcUhsSignaling (Private->ControllerHandle, PciIo, Slot, BusMode->BusTiming);\r
- if (EFI_ERROR (Status)) {\r
- return Status;\r
- }\r
-\r
Status = EmmcSwitchBusTiming (PciIo, PassThru, Slot, Rca, BusMode->DriverStrength, BusMode->BusTiming, BusMode->ClockFreq);\r
if (EFI_ERROR (Status)) {\r
return Status;\r
IN SD_MMC_BUS_SETTINGS *BusMode\r
)\r
{\r
- EFI_STATUS Status;\r
- SD_MMC_HC_PRIVATE_DATA *Private;\r
- SD_MMC_BUS_SETTINGS Hs200BusMode;\r
- UINT32 HsFreq;\r
+ EFI_STATUS Status;\r
+ SD_MMC_BUS_SETTINGS Hs200BusMode;\r
+ UINT32 HsFreq;\r
\r
if (BusMode->BusTiming != SdMmcMmcHs400 ||\r
BusMode->BusWidth != 8) {\r
return EFI_INVALID_PARAMETER;\r
}\r
\r
- Private = SD_MMC_HC_PRIVATE_FROM_THIS (PassThru);\r
Hs200BusMode.BusTiming = SdMmcMmcHs200;\r
Hs200BusMode.BusWidth = BusMode->BusWidth;\r
Hs200BusMode.ClockFreq = BusMode->ClockFreq;\r
// Set to High Speed timing and set the clock frequency to a value less than or equal to 52MHz.\r
// This step is necessary to be able to switch Bus into 8 bit DDR mode which is unsupported in HS200.\r
//\r
- Status = SdMmcHcUhsSignaling (Private->ControllerHandle, PciIo, Slot, SdMmcMmcHsSdr);\r
- if (EFI_ERROR (Status)) {\r
- return Status;\r
- }\r
-\r
HsFreq = BusMode->ClockFreq < 52 ? BusMode->ClockFreq : 52;\r
Status = EmmcSwitchBusTiming (PciIo, PassThru, Slot, Rca, BusMode->DriverStrength, SdMmcMmcHsSdr, HsFreq);\r
if (EFI_ERROR (Status)) {\r
return Status;\r
}\r
\r
- Status = SdMmcHcUhsSignaling (Private->ControllerHandle, PciIo, Slot, BusMode->BusTiming);\r
- if (EFI_ERROR (Status)) {\r
- return Status;\r
- }\r
-\r
return EmmcSwitchBusTiming (PciIo, PassThru, Slot, Rca, BusMode->DriverStrength, BusMode->BusTiming, BusMode->ClockFreq);\r
}\r
\r
} else if (BusMode.BusTiming == SdMmcMmcHs200) {\r
Status = EmmcSwitchToHS200 (PciIo, PassThru, Slot, Rca, &BusMode);\r
} else {\r
+ //\r
+ // Note that EmmcSwitchToHighSpeed is also called for SdMmcMmcLegacy\r
+ // bus timing. This is because even though we might not want to\r
+ // change the timing itself we still want to allow customization of\r
+ // bus parameters such as clock frequency and bus width.\r
+ //\r
Status = EmmcSwitchToHighSpeed (PciIo, PassThru, Slot, Rca, &BusMode);\r
}\r
\r