MdeModulePkg/SdMmcPciHcDxe: Check SD's supported bus mode before switch

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

Cc: Wu, Hao A <hao.a.wu@intel.com>
Contributed-under: TianoCore Contribution Agreement 1.0
Signed-off-by: Feng Tian <feng.tian@intel.com>
This commit is contained in:
Feng Tian 2016-05-03 09:57:55 +08:00
parent 8c983d3e06
commit 6263ae931d
3 changed files with 86 additions and 52 deletions

View File

@ -591,6 +591,7 @@ SdCardSetBusWidth (
@param[in] DriveStrength The value for drive length group. @param[in] DriveStrength The value for drive length group.
@param[in] PowerLimit The value for power limit group. @param[in] PowerLimit The value for power limit group.
@param[in] Mode Switch or check function. @param[in] Mode Switch or check function.
@param[out] SwitchResp The return switch function status.
@retval EFI_SUCCESS The operation is done correctly. @retval EFI_SUCCESS The operation is done correctly.
@retval Others The operation fails. @retval Others The operation fails.
@ -598,13 +599,14 @@ SdCardSetBusWidth (
**/ **/
EFI_STATUS EFI_STATUS
SdCardSwitch ( SdCardSwitch (
IN EFI_SD_MMC_PASS_THRU_PROTOCOL *PassThru, IN EFI_SD_MMC_PASS_THRU_PROTOCOL *PassThru,
IN UINT8 Slot, IN UINT8 Slot,
IN UINT8 AccessMode, IN UINT8 AccessMode,
IN UINT8 CommandSystem, IN UINT8 CommandSystem,
IN UINT8 DriveStrength, IN UINT8 DriveStrength,
IN UINT8 PowerLimit, IN UINT8 PowerLimit,
IN BOOLEAN Mode IN BOOLEAN Mode,
OUT UINT8 *SwitchResp
) )
{ {
EFI_SD_MMC_COMMAND_BLOCK SdMmcCmdBlk; EFI_SD_MMC_COMMAND_BLOCK SdMmcCmdBlk;
@ -612,7 +614,6 @@ SdCardSwitch (
EFI_SD_MMC_PASS_THRU_COMMAND_PACKET Packet; EFI_SD_MMC_PASS_THRU_COMMAND_PACKET Packet;
EFI_STATUS Status; EFI_STATUS Status;
UINT32 ModeValue; UINT32 ModeValue;
UINT8 Data[64];
ZeroMem (&SdMmcCmdBlk, sizeof (SdMmcCmdBlk)); ZeroMem (&SdMmcCmdBlk, sizeof (SdMmcCmdBlk));
ZeroMem (&SdMmcStatusBlk, sizeof (SdMmcStatusBlk)); ZeroMem (&SdMmcStatusBlk, sizeof (SdMmcStatusBlk));
@ -631,8 +632,8 @@ SdCardSwitch (
((DriveStrength & 0xF) << 8) | ((DriveStrength & 0xF) << 12) | \ ((DriveStrength & 0xF) << 8) | ((DriveStrength & 0xF) << 12) | \
ModeValue; ModeValue;
Packet.InDataBuffer = Data; Packet.InDataBuffer = SwitchResp;
Packet.InTransferLength = sizeof (Data); Packet.InTransferLength = 64;
Status = SdMmcPassThruPassThru (PassThru, Slot, &Packet, NULL); Status = SdMmcPassThruPassThru (PassThru, Slot, &Packet, NULL);
@ -891,6 +892,7 @@ SdCardSetBusMode (
UINT8 AccessMode; UINT8 AccessMode;
UINT8 HostCtrl1; UINT8 HostCtrl1;
UINT8 HostCtrl2; UINT8 HostCtrl2;
UINT8 SwitchResp[64];
SD_MMC_HC_PRIVATE_DATA *Private; SD_MMC_HC_PRIVATE_DATA *Private;
Private = SD_MMC_HC_PRIVATE_FROM_THIS (PassThru); Private = SD_MMC_HC_PRIVATE_FROM_THIS (PassThru);
@ -908,31 +910,45 @@ SdCardSetBusMode (
if (EFI_ERROR (Status)) { if (EFI_ERROR (Status)) {
return Status; return Status;
} }
// //
// Calculate supported bus speed/bus width/clock frequency. // Get the supported bus speed from SWITCH cmd return data group #1.
// //
ClockFreq = 0; Status = SdCardSwitch (PassThru, Slot, 0xF, 0xF, 0xF, 0xF, FALSE, SwitchResp);
if (S18A && (Capability->Sdr104 != 0)) {
ClockFreq = 208;
AccessMode = 3;
} else if (S18A && (Capability->Sdr50 != 0)) {
ClockFreq = 100;
AccessMode = 2;
} else if (S18A && (Capability->Ddr50 != 0)) {
ClockFreq = 50;
AccessMode = 4;
} else {
ClockFreq = 50;
AccessMode = 1;
}
DEBUG ((EFI_D_INFO, "SdCardSetBusMode: AccessMode %d ClockFreq %d BusWidth %d\n", AccessMode, ClockFreq, BusWidth));
Status = SdCardSwitch (PassThru, Slot, AccessMode, 0, 0, 0, TRUE);
if (EFI_ERROR (Status)) { if (EFI_ERROR (Status)) {
return Status; return Status;
} }
//
// Calculate supported bus speed/bus width/clock frequency by host and device capability.
//
ClockFreq = 0;
if (S18A && (Capability->Sdr104 != 0) && ((SwitchResp[13] & BIT3) != 0)) {
ClockFreq = 208;
AccessMode = 3;
} else if (S18A && (Capability->Sdr50 != 0) && ((SwitchResp[13] & BIT2) != 0)) {
ClockFreq = 100;
AccessMode = 2;
} else if (S18A && (Capability->Ddr50 != 0) && ((SwitchResp[13] & BIT4) != 0)) {
ClockFreq = 50;
AccessMode = 4;
} else if ((SwitchResp[13] & BIT1) != 0) {
ClockFreq = 50;
AccessMode = 1;
} else {
ClockFreq = 25;
AccessMode = 0;
}
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 // Set to Hight Speed timing

View File

@ -2192,6 +2192,7 @@ SdPeimSetBusWidth (
@param[in] DriveStrength The value for drive length group. @param[in] DriveStrength The value for drive length group.
@param[in] PowerLimit The value for power limit group. @param[in] PowerLimit The value for power limit group.
@param[in] Mode Switch or check function. @param[in] Mode Switch or check function.
@param[out] SwitchResp The return switch function status.
@retval EFI_SUCCESS The operation is done correctly. @retval EFI_SUCCESS The operation is done correctly.
@retval Others The operation fails. @retval Others The operation fails.
@ -2199,12 +2200,13 @@ SdPeimSetBusWidth (
**/ **/
EFI_STATUS EFI_STATUS
SdPeimSwitch ( SdPeimSwitch (
IN SD_PEIM_HC_SLOT *Slot, IN SD_PEIM_HC_SLOT *Slot,
IN UINT8 AccessMode, IN UINT8 AccessMode,
IN UINT8 CommandSystem, IN UINT8 CommandSystem,
IN UINT8 DriveStrength, IN UINT8 DriveStrength,
IN UINT8 PowerLimit, IN UINT8 PowerLimit,
IN BOOLEAN Mode IN BOOLEAN Mode,
OUT UINT8 *SwitchResp
) )
{ {
SD_COMMAND_BLOCK SdCmdBlk; SD_COMMAND_BLOCK SdCmdBlk;
@ -2212,7 +2214,6 @@ SdPeimSwitch (
SD_COMMAND_PACKET Packet; SD_COMMAND_PACKET Packet;
EFI_STATUS Status; EFI_STATUS Status;
UINT32 ModeValue; UINT32 ModeValue;
UINT8 Data[64];
ZeroMem (&SdCmdBlk, sizeof (SdCmdBlk)); ZeroMem (&SdCmdBlk, sizeof (SdCmdBlk));
ZeroMem (&SdStatusBlk, sizeof (SdStatusBlk)); ZeroMem (&SdStatusBlk, sizeof (SdStatusBlk));
@ -2230,8 +2231,8 @@ SdPeimSwitch (
SdCmdBlk.CommandArgument = (AccessMode & 0xF) | ((PowerLimit & 0xF) << 4) | \ SdCmdBlk.CommandArgument = (AccessMode & 0xF) | ((PowerLimit & 0xF) << 4) | \
((DriveStrength & 0xF) << 8) | ((DriveStrength & 0xF) << 12) | \ ((DriveStrength & 0xF) << 8) | ((DriveStrength & 0xF) << 12) | \
ModeValue; ModeValue;
Packet.InDataBuffer = Data; Packet.InDataBuffer = SwitchResp;
Packet.InTransferLength = sizeof (Data); Packet.InTransferLength = 64;
Status = SdPeimExecCmd (Slot, &Packet); Status = SdPeimExecCmd (Slot, &Packet);
@ -2617,6 +2618,7 @@ SdPeimSetBusMode (
UINT8 AccessMode; UINT8 AccessMode;
UINT8 HostCtrl1; UINT8 HostCtrl1;
UINT8 HostCtrl2; UINT8 HostCtrl2;
UINT8 SwitchResp[64];
Status = SdPeimGetCsd (Slot, Rca, &Slot->Csd); Status = SdPeimGetCsd (Slot, Rca, &Slot->Csd);
if (EFI_ERROR (Status)) { 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; ClockFreq = 0;
if (S18a && (Capability.Sdr104 != 0)) { if (S18a && (Capability.Sdr104 != 0) && ((SwitchResp[13] & BIT3) != 0)) {
ClockFreq = 208; ClockFreq = 208;
AccessMode = 3; AccessMode = 3;
} else if (S18a && (Capability.Sdr50 != 0)) { } else if (S18a && (Capability.Sdr50 != 0) && ((SwitchResp[13] & BIT2) != 0)) {
ClockFreq = 100; ClockFreq = 100;
AccessMode = 2; AccessMode = 2;
} else if (S18a && (Capability.Ddr50 != 0)) { } else if (S18a && (Capability.Ddr50 != 0) && ((SwitchResp[13] & BIT4) != 0)) {
ClockFreq = 50; ClockFreq = 50;
AccessMode = 4; AccessMode = 4;
} else { } else if ((SwitchResp[13] & BIT1) != 0) {
ClockFreq = 50; ClockFreq = 50;
AccessMode = 1; 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)) { if (EFI_ERROR (Status)) {
DEBUG ((EFI_D_ERROR, "SdPeimSetBusMode: SdPeimSwitch fails with %r\n", Status)); DEBUG ((EFI_D_ERROR, "SdPeimSetBusMode: SdPeimSwitch fails with %r\n", Status));
return 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 // Set to Hight Speed timing
// //

View File

@ -254,6 +254,7 @@ SdPeimHcInitHost (
@param[in] DriveStrength The value for drive length group. @param[in] DriveStrength The value for drive length group.
@param[in] PowerLimit The value for power limit group. @param[in] PowerLimit The value for power limit group.
@param[in] Mode Switch or check function. @param[in] Mode Switch or check function.
@param[out] SwitchResp The return switch function status.
@retval EFI_SUCCESS The operation is done correctly. @retval EFI_SUCCESS The operation is done correctly.
@retval Others The operation fails. @retval Others The operation fails.
@ -261,12 +262,13 @@ SdPeimHcInitHost (
**/ **/
EFI_STATUS EFI_STATUS
SdPeimSwitch ( SdPeimSwitch (
IN SD_PEIM_HC_SLOT *Slot, IN SD_PEIM_HC_SLOT *Slot,
IN UINT8 AccessMode, IN UINT8 AccessMode,
IN UINT8 CommandSystem, IN UINT8 CommandSystem,
IN UINT8 DriveStrength, IN UINT8 DriveStrength,
IN UINT8 PowerLimit, IN UINT8 PowerLimit,
IN BOOLEAN Mode IN BOOLEAN Mode,
OUT UINT8 *SwitchResp
); );
/** /**