Before switch to a bus mode, we need check if the SD device supports
this bus mode.

Cc: Wu, Hao A <[email protected]>
Contributed-under: TianoCore Contribution Agreement 1.0
Signed-off-by: Feng Tian <[email protected]>
---
 MdeModulePkg/Bus/Pci/SdMmcPciHcDxe/SdDevice.c | 54 +++++++++++++++++----------
 MdeModulePkg/Bus/Sd/SdBlockIoPei/SdHci.c      | 48 ++++++++++++++++--------
 MdeModulePkg/Bus/Sd/SdBlockIoPei/SdHci.h      | 14 ++++---
 3 files changed, 75 insertions(+), 41 deletions(-)

diff --git a/MdeModulePkg/Bus/Pci/SdMmcPciHcDxe/SdDevice.c 
b/MdeModulePkg/Bus/Pci/SdMmcPciHcDxe/SdDevice.c
index b4e2c58..8193f4e 100644
--- a/MdeModulePkg/Bus/Pci/SdMmcPciHcDxe/SdDevice.c
+++ b/MdeModulePkg/Bus/Pci/SdMmcPciHcDxe/SdDevice.c
@@ -591,6 +591,7 @@ SdCardSetBusWidth (
   @param[in]  DriveStrength The value for drive length group.
   @param[in]  PowerLimit    The value for power limit group.
   @param[in]  Mode          Switch or check function.
+  @param[out] SwitchResp    The return switch function status.
 
   @retval EFI_SUCCESS       The operation is done correctly.
   @retval Others            The operation fails.
@@ -598,13 +599,14 @@ SdCardSetBusWidth (
 **/
 EFI_STATUS
 SdCardSwitch (
-  IN EFI_SD_MMC_PASS_THRU_PROTOCOL      *PassThru,
-  IN UINT8                              Slot,
-  IN UINT8                              AccessMode,
-  IN UINT8                              CommandSystem,
-  IN UINT8                              DriveStrength,
-  IN UINT8                              PowerLimit,
-  IN BOOLEAN                            Mode
+  IN     EFI_SD_MMC_PASS_THRU_PROTOCOL  *PassThru,
+  IN     UINT8                          Slot,
+  IN     UINT8                          AccessMode,
+  IN     UINT8                          CommandSystem,
+  IN     UINT8                          DriveStrength,
+  IN     UINT8                          PowerLimit,
+  IN     BOOLEAN                        Mode,
+     OUT UINT8                          *SwitchResp
   )
 {
   EFI_SD_MMC_COMMAND_BLOCK              SdMmcCmdBlk;
@@ -612,7 +614,6 @@ SdCardSwitch (
   EFI_SD_MMC_PASS_THRU_COMMAND_PACKET   Packet;
   EFI_STATUS                            Status;
   UINT32                                ModeValue;
-  UINT8                                 Data[64];
 
   ZeroMem (&SdMmcCmdBlk, sizeof (SdMmcCmdBlk));
   ZeroMem (&SdMmcStatusBlk, sizeof (SdMmcStatusBlk));
@@ -631,8 +632,8 @@ SdCardSwitch (
                                 ((DriveStrength & 0xF) << 8) | ((DriveStrength 
& 0xF) << 12) | \
                                 ModeValue;
 
-  Packet.InDataBuffer     = Data;
-  Packet.InTransferLength = sizeof (Data);
+  Packet.InDataBuffer     = SwitchResp;
+  Packet.InTransferLength = 64;
 
   Status = SdMmcPassThruPassThru (PassThru, Slot, &Packet, NULL);
 
@@ -891,6 +892,7 @@ SdCardSetBusMode (
   UINT8                        AccessMode;
   UINT8                        HostCtrl1;
   UINT8                        HostCtrl2;
+  UINT8                        SwitchResp[64];
   SD_MMC_HC_PRIVATE_DATA       *Private;
 
   Private = SD_MMC_HC_PRIVATE_FROM_THIS (PassThru);
@@ -908,32 +910,46 @@ SdCardSetBusMode (
   if (EFI_ERROR (Status)) {
     return Status;
   }
-
   //
-  // Calculate supported bus speed/bus width/clock frequency.
+  // Get the supported bus speed from SWITCH cmd return data group #1.
+  //
+  Status = SdCardSwitch (PassThru, Slot, 0xF, 0xF, 0xF, 0xF, FALSE, 
SwitchResp);
+  if (EFI_ERROR (Status)) {
+    return Status;
+  }
+  //
+  // Calculate supported bus speed/bus width/clock frequency by host and 
device capability.
   //
   ClockFreq = 0;
-  if (S18A && (Capability->Sdr104 != 0)) {
+  if (S18A && (Capability->Sdr104 != 0) && ((SwitchResp[13] & BIT3) != 0)) {
     ClockFreq = 208;
     AccessMode = 3;
-  } else if (S18A && (Capability->Sdr50 != 0)) {
+  } else if (S18A && (Capability->Sdr50 != 0) && ((SwitchResp[13] & BIT2) != 
0)) {
     ClockFreq = 100;
     AccessMode = 2;
-  } else if (S18A && (Capability->Ddr50 != 0)) {
+  } else if (S18A && (Capability->Ddr50 != 0) && ((SwitchResp[13] & BIT4) != 
0)) {
     ClockFreq = 50;
     AccessMode = 4;
-  } else {
+  } else if ((SwitchResp[13] & BIT1) != 0) {
     ClockFreq = 50;
     AccessMode = 1;
+  } else {
+    ClockFreq = 25;
+    AccessMode = 0;
   }
 
-  DEBUG ((EFI_D_INFO, "SdCardSetBusMode: AccessMode %d ClockFreq %d BusWidth 
%d\n", AccessMode, ClockFreq, BusWidth));
-
-  Status = SdCardSwitch (PassThru, Slot, AccessMode, 0, 0, 0, TRUE);
+  Status = SdCardSwitch (PassThru, Slot, AccessMode, 0xF, 0xF, 0xF, TRUE, 
SwitchResp);
   if (EFI_ERROR (Status)) {
     return Status;
   }
 
+  if ((SwitchResp[16] & 0xF) != AccessMode) {
+    DEBUG ((EFI_D_ERROR, "SdCardSetBusMode: Switch to AccessMode %d ClockFreq 
%d BusWidth %d fails! The Switch response is 0x%1x\n", AccessMode, ClockFreq, 
BusWidth, SwitchResp[16] & 0xF));
+    return EFI_DEVICE_ERROR;
+  }
+
+  DEBUG ((EFI_D_INFO, "SdCardSetBusMode: Switch to AccessMode %d ClockFreq %d 
BusWidth %d\n", AccessMode, ClockFreq, BusWidth));
+
   //
   // Set to Hight Speed timing
   //
diff --git a/MdeModulePkg/Bus/Sd/SdBlockIoPei/SdHci.c 
b/MdeModulePkg/Bus/Sd/SdBlockIoPei/SdHci.c
index bb6df8f..c251fbe 100644
--- a/MdeModulePkg/Bus/Sd/SdBlockIoPei/SdHci.c
+++ b/MdeModulePkg/Bus/Sd/SdBlockIoPei/SdHci.c
@@ -2192,6 +2192,7 @@ SdPeimSetBusWidth (
   @param[in]  DriveStrength The value for drive length group.
   @param[in]  PowerLimit    The value for power limit group.
   @param[in]  Mode          Switch or check function.
+  @param[out] SwitchResp    The return switch function status.
 
   @retval EFI_SUCCESS       The operation is done correctly.
   @retval Others            The operation fails.
@@ -2199,12 +2200,13 @@ SdPeimSetBusWidth (
 **/
 EFI_STATUS
 SdPeimSwitch (
-  IN SD_PEIM_HC_SLOT        *Slot,
-  IN UINT8                  AccessMode,
-  IN UINT8                  CommandSystem,
-  IN UINT8                  DriveStrength,
-  IN UINT8                  PowerLimit,
-  IN BOOLEAN                Mode
+  IN     SD_PEIM_HC_SLOT              *Slot,
+  IN     UINT8                        AccessMode,
+  IN     UINT8                        CommandSystem,
+  IN     UINT8                        DriveStrength,
+  IN     UINT8                        PowerLimit,
+  IN     BOOLEAN                      Mode,
+     OUT UINT8                        *SwitchResp
   )
 {
   SD_COMMAND_BLOCK                    SdCmdBlk;
@@ -2212,7 +2214,6 @@ SdPeimSwitch (
   SD_COMMAND_PACKET                   Packet;
   EFI_STATUS                          Status;
   UINT32                              ModeValue;
-  UINT8                               Data[64];
 
   ZeroMem (&SdCmdBlk, sizeof (SdCmdBlk));
   ZeroMem (&SdStatusBlk, sizeof (SdStatusBlk));
@@ -2230,8 +2231,8 @@ SdPeimSwitch (
   SdCmdBlk.CommandArgument = (AccessMode & 0xF) | ((PowerLimit & 0xF) << 4) | \
                              ((DriveStrength & 0xF) << 8) | ((DriveStrength & 
0xF) << 12) | \
                              ModeValue;
-  Packet.InDataBuffer     = Data;
-  Packet.InTransferLength = sizeof (Data);
+  Packet.InDataBuffer     = SwitchResp;
+  Packet.InTransferLength = 64;
 
   Status = SdPeimExecCmd (Slot, &Packet);
 
@@ -2617,6 +2618,7 @@ SdPeimSetBusMode (
   UINT8                        AccessMode;
   UINT8                        HostCtrl1;
   UINT8                        HostCtrl2;
+  UINT8                        SwitchResp[64];
 
   Status = SdPeimGetCsd (Slot, Rca, &Slot->Csd);
   if (EFI_ERROR (Status)) {
@@ -2643,31 +2645,45 @@ SdPeimSetBusMode (
   }
 
   //
-  // Calculate supported bus speed/bus width/clock frequency.
+  // Get the supported bus speed from SWITCH cmd return data group #1.
+  //
+  Status = SdPeimSwitch (Slot, 0xF, 0xF, 0xF, 0xF, FALSE, SwitchResp);
+  if (EFI_ERROR (Status)) {
+    return Status;
+  }
+  //
+  // Calculate supported bus speed/bus width/clock frequency by host and 
device capability.
   //
   ClockFreq = 0;
-  if (S18a && (Capability.Sdr104 != 0)) {
+  if (S18a && (Capability.Sdr104 != 0) && ((SwitchResp[13] & BIT3) != 0)) {
     ClockFreq = 208;
     AccessMode = 3;
-  } else if (S18a && (Capability.Sdr50 != 0)) {
+  } else if (S18a && (Capability.Sdr50 != 0) && ((SwitchResp[13] & BIT2) != 
0)) {
     ClockFreq = 100;
     AccessMode = 2;
-  } else if (S18a && (Capability.Ddr50 != 0)) {
+  } else if (S18a && (Capability.Ddr50 != 0) && ((SwitchResp[13] & BIT4) != 
0)) {
     ClockFreq = 50;
     AccessMode = 4;
-  } else {
+  } else if ((SwitchResp[13] & BIT1) != 0) {
     ClockFreq = 50;
     AccessMode = 1;
+  } else {
+    ClockFreq = 25;
+    AccessMode = 0;
   }
 
-  DEBUG ((EFI_D_INFO, "AccessMode %d ClockFreq %d BusWidth %d\n", AccessMode, 
ClockFreq, BusWidth));
+  DEBUG ((EFI_D_INFO, "SdPeimSetBusMode: AccessMode %d ClockFreq %d BusWidth 
%d\n", AccessMode, ClockFreq, BusWidth));
 
-  Status = SdPeimSwitch (Slot, AccessMode, 0, 0, 0, TRUE);
+  Status = SdPeimSwitch (Slot, AccessMode, 0xF, 0xF, 0xF, TRUE, SwitchResp);
   if (EFI_ERROR (Status)) {
     DEBUG ((EFI_D_ERROR, "SdPeimSetBusMode: SdPeimSwitch fails with %r\n", 
Status));
     return Status;
   }
 
+  if ((SwitchResp[16] & 0xF) != AccessMode) {
+    DEBUG ((EFI_D_ERROR, "SdPeimSetBusMode: SdPeimSwitch to AccessMode %d 
ClockFreq %d BusWidth %d fails! The Switch response is 0x%1x\n", AccessMode, 
ClockFreq, BusWidth, SwitchResp[16] & 0xF));
+    return EFI_DEVICE_ERROR;
+  }
   //
   // Set to Hight Speed timing
   //
diff --git a/MdeModulePkg/Bus/Sd/SdBlockIoPei/SdHci.h 
b/MdeModulePkg/Bus/Sd/SdBlockIoPei/SdHci.h
index 2f44304..b7c0dbc 100644
--- a/MdeModulePkg/Bus/Sd/SdBlockIoPei/SdHci.h
+++ b/MdeModulePkg/Bus/Sd/SdBlockIoPei/SdHci.h
@@ -254,6 +254,7 @@ SdPeimHcInitHost (
   @param[in]  DriveStrength The value for drive length group.
   @param[in]  PowerLimit    The value for power limit group.
   @param[in]  Mode          Switch or check function.
+  @param[out] SwitchResp    The return switch function status.
 
   @retval EFI_SUCCESS       The operation is done correctly.
   @retval Others            The operation fails.
@@ -261,12 +262,13 @@ SdPeimHcInitHost (
 **/
 EFI_STATUS
 SdPeimSwitch (
-  IN SD_PEIM_HC_SLOT        *Slot,
-  IN UINT8                  AccessMode,
-  IN UINT8                  CommandSystem,
-  IN UINT8                  DriveStrength,
-  IN UINT8                  PowerLimit,
-  IN BOOLEAN                Mode
+  IN     SD_PEIM_HC_SLOT              *Slot,
+  IN     UINT8                        AccessMode,
+  IN     UINT8                        CommandSystem,
+  IN     UINT8                        DriveStrength,
+  IN     UINT8                        PowerLimit,
+  IN     BOOLEAN                      Mode,
+     OUT UINT8                        *SwitchResp
   );
 
 /**
-- 
2.7.1.windows.2

_______________________________________________
edk2-devel mailing list
[email protected]
https://lists.01.org/mailman/listinfo/edk2-devel

Reply via email to