+/**\r
+ Check if passed BusTiming is supported in both controller and card.\r
+\r
+ @param[in] Private Pointer to controller private data\r
+ @param[in] SlotIndex Index of the slot in the controller\r
+ @param[in] CardSupportedBusTimings Bitmask indicating which bus timings are supported by card\r
+ @param[in] IsInUhsI Flag indicating if link is in UHS-I\r
+\r
+ @retval TRUE Both card and controller support given BusTiming\r
+ @retval FALSE Card or controller doesn't support given BusTiming\r
+**/\r
+BOOLEAN\r
+SdIsBusTimingSupported (\r
+ IN SD_MMC_HC_PRIVATE_DATA *Private,\r
+ IN UINT8 SlotIndex,\r
+ IN UINT8 CardSupportedBusTimings,\r
+ IN BOOLEAN IsInUhsI,\r
+ IN SD_MMC_BUS_MODE BusTiming\r
+ )\r
+{\r
+ SD_MMC_HC_SLOT_CAP *Capability;\r
+\r
+ Capability = &Private->Capability[SlotIndex];\r
+\r
+ if (IsInUhsI) {\r
+ switch (BusTiming) {\r
+ case SdMmcUhsSdr104:\r
+ if ((Capability->Sdr104 != 0) && ((CardSupportedBusTimings & BIT3) != 0)) {\r
+ return TRUE;\r
+ }\r
+ break;\r
+ case SdMmcUhsDdr50:\r
+ if ((Capability->Ddr50 != 0) && ((CardSupportedBusTimings & BIT4) != 0)) {\r
+ return TRUE;\r
+ }\r
+ break;\r
+ case SdMmcUhsSdr50:\r
+ if ((Capability->Sdr50 != 0) && ((CardSupportedBusTimings & BIT2) != 0)) {\r
+ return TRUE;\r
+ }\r
+ break;\r
+ case SdMmcUhsSdr25:\r
+ if ((CardSupportedBusTimings & BIT1) != 0) {\r
+ return TRUE;\r
+ }\r
+ break;\r
+ case SdMmcUhsSdr12:\r
+ if ((CardSupportedBusTimings & BIT0) != 0) {\r
+ return TRUE;\r
+ }\r
+ break;\r
+ default:\r
+ break;\r
+ }\r
+ } else {\r
+ switch (BusTiming) {\r
+ case SdMmcSdHs:\r
+ if ((Capability->HighSpeed != 0) && (CardSupportedBusTimings & BIT1) != 0) {\r
+ return TRUE;\r
+ }\r
+ break;\r
+ case SdMmcSdDs:\r
+ if ((CardSupportedBusTimings & BIT0) != 0) {\r
+ return TRUE;\r
+ }\r
+ break;\r
+ default:\r
+ break;\r
+ }\r
+ }\r
+\r
+ return FALSE;\r
+}\r
+\r
+/**\r
+ Get the target bus timing to set on the link. This function\r
+ will try to select highest bus timing supported by card, controller\r
+ and the driver.\r
+\r
+ @param[in] Private Pointer to controller private data\r
+ @param[in] SlotIndex Index of the slot in the controller\r
+ @param[in] CardSupportedBusTimings Bitmask indicating which bus timings are supported by card\r
+ @param[in] IsInUhsI Flag indicating if link is in UHS-I\r
+\r
+ @return Bus timing value that should be set on link\r
+**/\r
+SD_MMC_BUS_MODE\r
+SdGetTargetBusTiming (\r
+ IN SD_MMC_HC_PRIVATE_DATA *Private,\r
+ IN UINT8 SlotIndex,\r
+ IN UINT8 CardSupportedBusTimings,\r
+ IN BOOLEAN IsInUhsI\r
+ )\r
+{\r
+ SD_MMC_BUS_MODE BusTiming;\r
+\r
+ if (IsInUhsI) {\r
+ BusTiming = SdMmcUhsSdr104;\r
+ } else {\r
+ BusTiming = SdMmcSdHs;\r
+ }\r
+\r
+ while (BusTiming > SdMmcSdDs) {\r
+ if (SdIsBusTimingSupported (Private, SlotIndex, CardSupportedBusTimings, IsInUhsI, BusTiming)) {\r
+ break;\r
+ }\r
+ BusTiming--;\r
+ }\r
+\r
+ return BusTiming;\r
+}\r
+\r
+/**\r
+ Get the target bus width to be set on the bus.\r
+\r
+ @param[in] Private Pointer to controller private data\r
+ @param[in] SlotIndex Index of the slot in the controller\r
+ @param[in] BusTiming Bus timing set on the bus\r
+\r
+ @return Bus width to be set on the bus\r
+**/\r
+UINT8\r
+SdGetTargetBusWidth (\r
+ IN SD_MMC_HC_PRIVATE_DATA *Private,\r
+ IN UINT8 SlotIndex,\r
+ IN SD_MMC_BUS_MODE BusTiming\r
+ )\r
+{\r
+ UINT8 BusWidth;\r
+ UINT8 PreferredBusWidth;\r
+\r
+ PreferredBusWidth = Private->Slot[SlotIndex].OperatingParameters.BusWidth;\r
+\r
+ if (BusTiming == SdMmcSdDs || BusTiming == SdMmcSdHs) {\r
+ if (PreferredBusWidth != EDKII_SD_MMC_BUS_WIDTH_IGNORE &&\r
+ (PreferredBusWidth == 1 || PreferredBusWidth == 4)) {\r
+ BusWidth = PreferredBusWidth;\r
+ } else {\r
+ BusWidth = 4;\r
+ }\r
+ } else {\r
+ //\r
+ // UHS-I modes support only 4-bit width.\r
+ // Switch to 4-bit has been done before calling this function anyway so\r
+ // this is purely informational.\r
+ //\r
+ BusWidth = 4;\r
+ }\r
+\r
+ return BusWidth;\r
+}\r
+\r
+/**\r
+ Get the target clock frequency to be set on the bus.\r
+\r
+ @param[in] Private Pointer to controller private data\r
+ @param[in] SlotIndex Index of the slot in the controller\r
+ @param[in] BusTiming Bus timing to be set on the bus\r
+\r
+ @return Value of the clock frequency to be set on bus in MHz\r
+**/\r
+UINT32\r
+SdGetTargetBusClockFreq (\r
+ IN SD_MMC_HC_PRIVATE_DATA *Private,\r
+ IN UINT8 SlotIndex,\r
+ IN SD_MMC_BUS_MODE BusTiming\r
+ )\r
+{\r
+ UINT32 PreferredClockFreq;\r
+ UINT32 MaxClockFreq;\r
+\r
+ PreferredClockFreq = Private->Slot[SlotIndex].OperatingParameters.ClockFreq;\r
+\r
+ switch (BusTiming) {\r
+ case SdMmcUhsSdr104:\r
+ MaxClockFreq = 208;\r
+ break;\r
+ case SdMmcUhsSdr50:\r
+ MaxClockFreq = 100;\r
+ break;\r
+ case SdMmcUhsDdr50:\r
+ case SdMmcUhsSdr25:\r
+ case SdMmcSdHs:\r
+ MaxClockFreq = 50;\r
+ break;\r
+ case SdMmcUhsSdr12:\r
+ case SdMmcSdDs:\r
+ default:\r
+ MaxClockFreq = 25;\r
+ }\r
+\r
+ if (PreferredClockFreq != EDKII_SD_MMC_CLOCK_FREQ_IGNORE && PreferredClockFreq < MaxClockFreq) {\r
+ return PreferredClockFreq;\r
+ } else {\r
+ return MaxClockFreq;\r
+ }\r
+}\r
+\r
+/**\r
+ Get the driver strength to be set on bus.\r
+\r
+ @param[in] Private Pointer to controller private data\r
+ @param[in] SlotIndex Index of the slot in the controller\r
+ @param[in] CardSupportedDriverStrengths Bitmask indicating which driver strengths are supported on the card\r
+ @param[in] BusTiming Bus timing set on the bus\r
+\r
+ @return Value of the driver strength to be set on the bus\r
+**/\r
+EDKII_SD_MMC_DRIVER_STRENGTH\r
+SdGetTargetDriverStrength (\r
+ IN SD_MMC_HC_PRIVATE_DATA *Private,\r
+ IN UINT8 SlotIndex,\r
+ IN UINT8 CardSupportedDriverStrengths,\r
+ IN SD_MMC_BUS_MODE BusTiming\r
+ )\r
+{\r
+ EDKII_SD_MMC_DRIVER_STRENGTH PreferredDriverStrength;\r
+ EDKII_SD_MMC_DRIVER_STRENGTH DriverStrength;\r
+\r
+ if (BusTiming == SdMmcSdDs || BusTiming == SdMmcSdHs) {\r
+ DriverStrength.Sd = SdDriverStrengthIgnore;\r
+ return DriverStrength;\r
+ }\r
+\r
+ PreferredDriverStrength = Private->Slot[SlotIndex].OperatingParameters.DriverStrength;\r
+ DriverStrength.Sd = SdDriverStrengthTypeB;\r
+\r
+ if (PreferredDriverStrength.Sd != EDKII_SD_MMC_DRIVER_STRENGTH_IGNORE &&\r
+ (CardSupportedDriverStrengths & (BIT0 << PreferredDriverStrength.Sd))) {\r
+\r
+ if ((PreferredDriverStrength.Sd == SdDriverStrengthTypeA &&\r
+ (Private->Capability[SlotIndex].DriverTypeA != 0)) ||\r
+ (PreferredDriverStrength.Sd == SdDriverStrengthTypeC &&\r
+ (Private->Capability[SlotIndex].DriverTypeC != 0)) ||\r
+ (PreferredDriverStrength.Sd == SdDriverStrengthTypeD &&\r
+ (Private->Capability[SlotIndex].DriverTypeD != 0))) {\r
+ DriverStrength.Sd = PreferredDriverStrength.Sd;\r
+ }\r
+ }\r
+\r
+ return DriverStrength;\r
+}\r
+\r
+/**\r
+ Get the target settings for the bus mode.\r
+\r
+ @param[in] Private Pointer to controller private data\r
+ @param[in] SlotIndex Index of the slot in the controller\r
+ @param[in] SwitchQueryResp Pointer to switch query response\r
+ @param[in] IsInUhsI Flag indicating if link is in UHS-I mode\r
+ @param[out] BusMode Target configuration of the bus\r
+**/\r
+VOID\r
+SdGetTargetBusMode (\r
+ IN SD_MMC_HC_PRIVATE_DATA *Private,\r
+ IN UINT8 SlotIndex,\r
+ IN UINT8 *SwitchQueryResp,\r
+ IN BOOLEAN IsInUhsI,\r
+ OUT SD_MMC_BUS_SETTINGS *BusMode\r
+ )\r
+{\r
+ BusMode->BusTiming = SdGetTargetBusTiming (Private, SlotIndex, SwitchQueryResp[13], IsInUhsI);\r
+ BusMode->BusWidth = SdGetTargetBusWidth (Private, SlotIndex, BusMode->BusTiming);\r
+ BusMode->ClockFreq = SdGetTargetBusClockFreq (Private, SlotIndex, BusMode->BusTiming);\r
+ BusMode->DriverStrength = SdGetTargetDriverStrength (Private, SlotIndex, SwitchQueryResp[9], BusMode->BusTiming);\r
+}\r
+\r