MdeModulePkg/SdMmcPciHcDxe: Send SEND_STATUS at lower frequency
authorAlbecki, Mateusz <mateusz.albecki@intel.com>
Tue, 25 Feb 2020 15:05:53 +0000 (23:05 +0800)
committermergify[bot] <37929162+mergify[bot]@users.noreply.github.com>
Thu, 5 Mar 2020 01:51:59 +0000 (01:51 +0000)
REF: https://bugzilla.tianocore.org/show_bug.cgi?id=1140

To avoid stability issues on some designs the driver
will now send SEND_STATUS at previous, lower, frequency
when upgrading the bus timing.

Cc: Hao A Wu <hao.a.wu@intel.com>
Cc: Marcin Wojtas <mw@semihalf.com>
Cc: Zhichao Gao <zhichao.gao@intel.com>
Cc: Liming Gao <liming.gao@intel.com>
Signed-off-by: Mateusz Albecki <mateusz.albecki@intel.com>
Reviewed-by: Hao A Wu <hao.a.wu@intel.com>
MdeModulePkg/Bus/Pci/SdMmcPciHcDxe/EmmcDevice.c
MdeModulePkg/Bus/Pci/SdMmcPciHcDxe/SdMmcPciHcDxe.c
MdeModulePkg/Bus/Pci/SdMmcPciHcDxe/SdMmcPciHcDxe.h
MdeModulePkg/Bus/Pci/SdMmcPciHcDxe/SdMmcPciHci.c

index 776c0e7..8b5f8e8 100644 (file)
@@ -558,6 +558,43 @@ EmmcTuningClkForHs200 (
   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
@@ -591,7 +628,6 @@ EmmcSwitchBusWidth (
   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
@@ -617,18 +653,10 @@ EmmcSwitchBusWidth (
     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
@@ -669,9 +697,9 @@ EmmcSwitchBusTiming (
   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
@@ -695,7 +723,7 @@ EmmcSwitchBusTiming (
       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
@@ -724,6 +752,26 @@ EmmcSwitchBusTiming (
     return Status;\r
   }\r
 \r
+  //\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
+  // 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
@@ -732,17 +780,11 @@ EmmcSwitchBusTiming (
     return Status;\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
-  //\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
+  if (DelaySendStatus) {\r
+    Status = EmmcCheckSwitchStatus (PassThru, Slot, Rca);\r
+    if (EFI_ERROR (Status)) {\r
+      return Status;\r
+    }\r
   }\r
 \r
   return Status;\r
index b18ff3e..57f4cf3 100644 (file)
@@ -28,7 +28,7 @@ EFI_DRIVER_BINDING_PROTOCOL gSdMmcPciHcDriverBinding = {
   NULL\r
 };\r
 \r
-#define SLOT_INIT_TEMPLATE {0, UnknownSlot, 0, 0, 0, \\r
+#define SLOT_INIT_TEMPLATE {0, UnknownSlot, 0, 0, 0, 0, \\r
                                {EDKII_SD_MMC_BUS_WIDTH_IGNORE,\\r
                                EDKII_SD_MMC_CLOCK_FREQ_IGNORE,\\r
                                {EDKII_SD_MMC_DRIVER_STRENGTH_IGNORE}}}\r
index 5bc3577..bb3d384 100644 (file)
@@ -83,6 +83,7 @@ typedef struct {
   BOOLEAN                            MediaPresent;\r
   BOOLEAN                            Initialized;\r
   SD_MMC_CARD_TYPE                   CardType;\r
+  UINT64                             CurrentFreq;\r
   EDKII_SD_MMC_OPERATING_PARAMETERS  OperatingParameters;\r
 } SD_MMC_HC_SLOT;\r
 \r
index 43626ff..7971196 100644 (file)
@@ -931,6 +931,8 @@ SdMmcHcClockSupply (
     }\r
   }\r
 \r
+  Private->Slot[Slot].CurrentFreq = ClockFreq;\r
+\r
   return Status;\r
 }\r
 \r