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
}\r
\r
//\r
- // Convert the clock freq unit from MHz to KHz.\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
- Status = SdMmcHcClockSupply (PciIo, Slot, ClockFreq * 1000, Private->BaseClkFreq[Slot], Private->ControllerVersion[Slot]);\r
- if (EFI_ERROR (Status)) {\r
- return Status;\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
- Status = EmmcSendStatus (PassThru, Slot, Rca, &DevStatus);\r
- if (EFI_ERROR (Status)) {\r
- DEBUG ((DEBUG_ERROR, "EmmcSwitchBusTiming: Send status fails with %r\n", Status));\r
- return Status;\r
- }\r
//\r
- // Check the switch operation is really successful or not.\r
+ // Convert the clock freq unit from MHz to KHz.\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
+ 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