/** @file\r
\r
- Copyright (c) 2015 - 2016, Intel Corporation. All rights reserved.<BR>\r
+ Copyright (c) 2015 - 2017, Intel Corporation. All rights reserved.<BR>\r
This program and the accompanying materials\r
are licensed and made available under the terms and conditions of the BSD License\r
which accompanies this distribution. The full text of the license may be found at\r
ASSERT (Capability.BaseClkFreq != 0);\r
\r
BaseClkFreq = Capability.BaseClkFreq;\r
- if ((ClockFreq > (BaseClkFreq * 1000)) || (ClockFreq == 0)) {\r
+\r
+ if (ClockFreq == 0) {\r
return EFI_INVALID_PARAMETER;\r
}\r
+\r
+ if (ClockFreq > (BaseClkFreq * 1000)) {\r
+ ClockFreq = BaseClkFreq * 1000;\r
+ }\r
+\r
//\r
// Calculate the divisor of base frequency.\r
//\r
goto Error;\r
}\r
\r
- if ((Trb->DataLen % Trb->BlockSize) != 0) {\r
- if (Trb->DataLen < Trb->BlockSize) {\r
- Trb->BlockSize = (UINT16)Trb->DataLen;\r
- }\r
+ if ((Trb->DataLen != 0) && (Trb->DataLen < Trb->BlockSize)) {\r
+ Trb->BlockSize = (UINT16)Trb->DataLen;\r
}\r
\r
- if (Trb->DataLen == 0) {\r
- Trb->Mode = SdNoData;\r
- } else if (Capability.Adma2 != 0) {\r
- Trb->Mode = SdAdmaMode;\r
- Status = BuildAdmaDescTable (Trb);\r
- if (EFI_ERROR (Status)) {\r
- goto Error;\r
- }\r
- } else if (Capability.Sdma != 0) {\r
- Trb->Mode = SdSdmaMode;\r
- } else {\r
+ if (Packet->SdCmdBlk->CommandIndex == SD_SEND_TUNING_BLOCK) {\r
Trb->Mode = SdPioMode;\r
+ } else {\r
+ if (Trb->DataLen == 0) {\r
+ Trb->Mode = SdNoData;\r
+ } else if (Capability.Adma2 != 0) {\r
+ Trb->Mode = SdAdmaMode;\r
+ Status = BuildAdmaDescTable (Trb);\r
+ if (EFI_ERROR (Status)) {\r
+ goto Error;\r
+ }\r
+ } else if (Capability.Sdma != 0) {\r
+ Trb->Mode = SdSdmaMode;\r
+ } else {\r
+ Trb->Mode = SdPioMode;\r
+ }\r
}\r
-\r
return Trb;\r
\r
Error:\r
// the Present State register to be 0\r
//\r
PresentState = BIT0 | BIT1;\r
- if (Packet->SdCmdBlk->CommandIndex == SD_SEND_TUNING_BLOCK) {\r
- PresentState = BIT0;\r
- }\r
} else {\r
//\r
// Wait Command Inhibit (CMD) in the Present State register\r
return Status;\r
}\r
\r
- BlkCount = (UINT16)(Trb->DataLen / Trb->BlockSize);\r
+ BlkCount = 0;\r
+ if (Trb->Mode != SdNoData) {\r
+ //\r
+ // Calcuate Block Count.\r
+ //\r
+ BlkCount = (UINT16)(Trb->DataLen / Trb->BlockSize);\r
+ }\r
Status = SdPeimHcRwMmio (Bar + SD_HC_BLK_COUNT, FALSE, sizeof (BlkCount), &BlkCount);\r
if (EFI_ERROR (Status)) {\r
return Status;\r
if (Trb->Read) {\r
TransMode |= BIT4;\r
}\r
- if (BlkCount != 0) {\r
+ if (BlkCount > 1) {\r
TransMode |= BIT5 | BIT1;\r
}\r
+ //\r
+ // SD memory card needs to use AUTO CMD12 feature.\r
+ //\r
if (BlkCount > 1) {\r
TransMode |= BIT2;\r
}\r
UINT32 SdmaAddr;\r
UINT8 Index;\r
UINT8 SwReset;\r
+ UINT32 PioLength;\r
\r
SwReset = 0;\r
Packet = Trb->Packet;\r
}\r
\r
if (Packet->SdCmdBlk->CommandIndex == SD_SEND_TUNING_BLOCK) {\r
- Status = EFI_SUCCESS;\r
- goto Done;\r
+ //\r
+ // When performing tuning procedure (Execute Tuning is set to 1) through PIO mode,\r
+ // wait Buffer Read Ready bit of Normal Interrupt Status Register to be 1.\r
+ // Refer to SD Host Controller Simplified Specification 3.0 figure 2-29 for details.\r
+ //\r
+ if ((IntStatus & BIT5) == BIT5) {\r
+ //\r
+ // Clear Buffer Read Ready interrupt at first.\r
+ //\r
+ IntStatus = BIT5;\r
+ SdPeimHcRwMmio (Bar + SD_HC_NOR_INT_STS, FALSE, sizeof (IntStatus), &IntStatus);\r
+ //\r
+ // Read data out from Buffer Port register\r
+ //\r
+ for (PioLength = 0; PioLength < Trb->DataLen; PioLength += 4) {\r
+ SdPeimHcRwMmio (Bar + SD_HC_BUF_DAT_PORT, TRUE, 4, (UINT8*)Trb->Data + PioLength);\r
+ }\r
+ Status = EFI_SUCCESS;\r
+ goto Done;\r
+ }\r
}\r
\r
Status = EFI_NOT_READY;\r
@param[in] DriveStrength The value for drive length group.\r
@param[in] PowerLimit The value for power limit group.\r
@param[in] Mode Switch or check function.\r
+ @param[out] SwitchResp The return switch function status.\r
\r
@retval EFI_SUCCESS The operation is done correctly.\r
@retval Others The operation fails.\r
**/\r
EFI_STATUS\r
SdPeimSwitch (\r
- IN SD_PEIM_HC_SLOT *Slot,\r
- IN UINT8 AccessMode,\r
- IN UINT8 CommandSystem,\r
- IN UINT8 DriveStrength,\r
- IN UINT8 PowerLimit,\r
- IN BOOLEAN Mode\r
+ IN SD_PEIM_HC_SLOT *Slot,\r
+ IN UINT8 AccessMode,\r
+ IN UINT8 CommandSystem,\r
+ IN UINT8 DriveStrength,\r
+ IN UINT8 PowerLimit,\r
+ IN BOOLEAN Mode,\r
+ OUT UINT8 *SwitchResp\r
)\r
{\r
SD_COMMAND_BLOCK SdCmdBlk;\r
SD_COMMAND_PACKET Packet;\r
EFI_STATUS Status;\r
UINT32 ModeValue;\r
- UINT8 Data[64];\r
\r
ZeroMem (&SdCmdBlk, sizeof (SdCmdBlk));\r
ZeroMem (&SdStatusBlk, sizeof (SdStatusBlk));\r
SdCmdBlk.CommandArgument = (AccessMode & 0xF) | ((PowerLimit & 0xF) << 4) | \\r
((DriveStrength & 0xF) << 8) | ((DriveStrength & 0xF) << 12) | \\r
ModeValue;\r
- Packet.InDataBuffer = Data;\r
- Packet.InTransferLength = sizeof (Data);\r
+ Packet.InDataBuffer = SwitchResp;\r
+ Packet.InTransferLength = 64;\r
\r
Status = SdPeimExecCmd (Slot, &Packet);\r
\r
return Status;\r
}\r
\r
- if ((HostCtrl2 & (BIT6 | BIT7)) == BIT7) {\r
+ if ((HostCtrl2 & (BIT6 | BIT7)) == 0) {\r
break;\r
}\r
+\r
+ if ((HostCtrl2 & (BIT6 | BIT7)) == BIT7) {\r
+ return EFI_SUCCESS;\r
+ }\r
} while (++Retry < 40);\r
\r
- if (Retry == 40) {\r
- Status = EFI_TIMEOUT;\r
+ DEBUG ((EFI_D_ERROR, "SdPeimTuningClock: Send tuning block fails at %d times with HostCtrl2 %02x\n", Retry, HostCtrl2));\r
+ //\r
+ // Abort the tuning procedure and reset the tuning circuit.\r
+ //\r
+ HostCtrl2 = (UINT8)~(BIT6 | BIT7);\r
+ Status = SdPeimHcAndMmio (Slot->SdHcBase + SD_HC_HOST_CTRL2, sizeof (HostCtrl2), &HostCtrl2);\r
+ if (EFI_ERROR (Status)) {\r
+ return Status;\r
}\r
- return Status;\r
+ return EFI_DEVICE_ERROR;\r
}\r
\r
/**\r
UINT8 AccessMode;\r
UINT8 HostCtrl1;\r
UINT8 HostCtrl2;\r
+ UINT8 SwitchResp[64];\r
\r
Status = SdPeimGetCsd (Slot, Rca, &Slot->Csd);\r
if (EFI_ERROR (Status)) {\r
}\r
\r
//\r
- // Calculate supported bus speed/bus width/clock frequency.\r
+ // Get the supported bus speed from SWITCH cmd return data group #1.\r
+ //\r
+ ZeroMem (SwitchResp, sizeof (SwitchResp));\r
+ Status = SdPeimSwitch (Slot, 0xF, 0xF, 0xF, 0xF, FALSE, SwitchResp);\r
+ if (EFI_ERROR (Status)) {\r
+ return Status;\r
+ }\r
+ //\r
+ // Calculate supported bus speed/bus width/clock frequency by host and device capability.\r
//\r
ClockFreq = 0;\r
- if (S18a && (Capability.Sdr104 != 0)) {\r
+ if (S18a && (Capability.Sdr104 != 0) && ((SwitchResp[13] & BIT3) != 0)) {\r
ClockFreq = 208;\r
AccessMode = 3;\r
- } else if (S18a && (Capability.Sdr50 != 0)) {\r
+ } else if (S18a && (Capability.Sdr50 != 0) && ((SwitchResp[13] & BIT2) != 0)) {\r
ClockFreq = 100;\r
AccessMode = 2;\r
- } else if (S18a && (Capability.Ddr50 != 0)) {\r
+ } else if (S18a && (Capability.Ddr50 != 0) && ((SwitchResp[13] & BIT4) != 0)) {\r
ClockFreq = 50;\r
AccessMode = 4;\r
- } else {\r
+ } else if ((SwitchResp[13] & BIT1) != 0) {\r
ClockFreq = 50;\r
AccessMode = 1;\r
+ } else {\r
+ ClockFreq = 25;\r
+ AccessMode = 0;\r
}\r
\r
- DEBUG ((EFI_D_INFO, "AccessMode %d ClockFreq %d BusWidth %d\n", AccessMode, ClockFreq, BusWidth));\r
+ DEBUG ((EFI_D_INFO, "SdPeimSetBusMode: AccessMode %d ClockFreq %d BusWidth %d\n", AccessMode, ClockFreq, BusWidth));\r
\r
- Status = SdPeimSwitch (Slot, AccessMode, 0, 0, 0, TRUE);\r
+ Status = SdPeimSwitch (Slot, AccessMode, 0xF, 0xF, 0xF, TRUE, SwitchResp);\r
if (EFI_ERROR (Status)) {\r
DEBUG ((EFI_D_ERROR, "SdPeimSetBusMode: SdPeimSwitch fails with %r\n", Status));\r
return Status;\r
}\r
\r
+ if ((SwitchResp[16] & 0xF) != AccessMode) {\r
+ 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));\r
+ return EFI_DEVICE_ERROR;\r
+ }\r
//\r
// Set to Hight Speed timing\r
//\r
UINT32 PresentState;\r
UINT8 HostCtrl2;\r
SD_HC_SLOT_CAP Capability;\r
-\r
+ UINTN Retry;\r
//\r
// 1. Send Cmd0 to the device\r
//\r
// Note here we only support the cards complied with SD physical\r
// layer simplified spec version 2.0 and version 3.0 and above.\r
//\r
+ Ocr = 0;\r
+ Retry = 0;\r
do {\r
Status = SdPeimSendOpCond (Slot, 0, Ocr, S18r, Xpc, TRUE, &Ocr);\r
if (EFI_ERROR (Status)) {\r
DEBUG ((EFI_D_ERROR, "SdPeimIdentification: SdPeimSendOpCond fails with %r Ocr %x, S18r %x, Xpc %x\n", Status, Ocr, S18r, Xpc));\r
return EFI_DEVICE_ERROR;\r
}\r
+\r
+ if (Retry++ == 100) {\r
+ DEBUG ((EFI_D_ERROR, "SdPeimIdentification: SdPeimSendOpCond fails too many times\n"));\r
+ return EFI_DEVICE_ERROR;\r
+ }\r
+ MicroSecondDelay (10 * 1000);\r
} while ((Ocr & BIT31) == 0);\r
\r
//\r
\r
SdPeimHcInitClockFreq (Slot->SdHcBase);\r
\r
- MicroSecondDelay (1);\r
+ MicroSecondDelay (1000);\r
\r
SdPeimHcRwMmio (Slot->SdHcBase + SD_HC_PRESENT_STATE, TRUE, sizeof (PresentState), &PresentState);\r
if (((PresentState >> 20) & 0xF) != 0xF) {\r