/** @file\r
\r
- Copyright (c) 2015 - 2016, 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
- http://opensource.org/licenses/bsd-license.php.\r
-\r
- THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
- WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+ Copyright (c) 2015 - 2017, Intel Corporation. All rights reserved.<BR>\r
+ SPDX-License-Identifier: BSD-2-Clause-Patent\r
\r
**/\r
\r
UINT64 Remaining;\r
UINT32 Address;\r
\r
- Data = (EFI_PHYSICAL_ADDRESS)(UINTN)Trb->Data;\r
+ Data = Trb->DataPhy;\r
DataLen = Trb->DataLen;\r
//\r
// Only support 32bit ADMA Descriptor Table\r
SD_TRB *Trb;\r
EFI_STATUS Status;\r
SD_HC_SLOT_CAP Capability;\r
+ EDKII_IOMMU_OPERATION MapOp;\r
+ UINTN MapLength;\r
\r
//\r
// Calculate a divisor for SD clock frequency\r
return NULL;\r
}\r
\r
- Trb = SdPeimAllocateMem (Slot->Private->Pool, sizeof (SD_TRB));\r
+ Trb = AllocateZeroPool (sizeof (SD_TRB));\r
if (Trb == NULL) {\r
return NULL;\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
- }\r
+ } else {\r
+ if (Trb->Read) {\r
+ MapOp = EdkiiIoMmuOperationBusMasterWrite;\r
+ } else {\r
+ MapOp = EdkiiIoMmuOperationBusMasterRead;\r
+ }\r
\r
+ if (Trb->DataLen != 0) {\r
+ MapLength = Trb->DataLen;\r
+ Status = IoMmuMap (MapOp, Trb->Data, &MapLength, &Trb->DataPhy, &Trb->DataMap);\r
+\r
+ if (EFI_ERROR (Status) || (MapLength != Trb->DataLen)) {\r
+ DEBUG ((DEBUG_ERROR, "SdPeimCreateTrb: Fail to map data buffer.\n"));\r
+ goto Error;\r
+ }\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
+ Trb->Mode = SdPioMode;\r
+ }\r
+ }\r
return Trb;\r
\r
Error:\r
IN SD_TRB *Trb\r
)\r
{\r
+ if ((Trb != NULL) && (Trb->DataMap != NULL)) {\r
+ IoMmuUnmap (Trb->DataMap);\r
+ }\r
+\r
if ((Trb != NULL) && (Trb->AdmaDesc != NULL)) {\r
SdPeimFreeMem (Trb->Slot->Private->Pool, Trb->AdmaDesc, Trb->AdmaDescSize);\r
}\r
\r
if (Trb != NULL) {\r
- SdPeimFreeMem (Trb->Slot->Private->Pool, Trb, sizeof (SD_TRB));\r
+ FreePool (Trb);\r
}\r
return;\r
}\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
SdPeimHcLedOnOff (Bar, TRUE);\r
\r
if (Trb->Mode == SdSdmaMode) {\r
- if ((UINT64)(UINTN)Trb->Data >= 0x100000000ul) {\r
+ if ((UINT64)(UINTN)Trb->DataPhy >= 0x100000000ul) {\r
return EFI_INVALID_PARAMETER;\r
}\r
\r
- SdmaAddr = (UINT32)(UINTN)Trb->Data;\r
+ SdmaAddr = (UINT32)(UINTN)Trb->DataPhy;\r
Status = SdPeimHcRwMmio (Bar + SD_HC_SDMA_ADDR, FALSE, sizeof (SdmaAddr), &SdmaAddr);\r
if (EFI_ERROR (Status)) {\r
return Status;\r
return Status;\r
}\r
\r
- BlkCount = (UINT16)(Trb->DataLen / Trb->BlockSize);\r
+ BlkCount = 0;\r
+ if (Trb->Mode != SdNoData) {\r
+ //\r
+ // Calculate 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
// Update SDMA Address register.\r
//\r
- SdmaAddr = SD_SDMA_ROUND_UP ((UINT32)(UINTN)Trb->Data, SD_SDMA_BOUNDARY);\r
+ SdmaAddr = SD_SDMA_ROUND_UP ((UINT32)(UINTN)Trb->DataPhy, SD_SDMA_BOUNDARY);\r
Status = SdPeimHcRwMmio (\r
Bar + SD_HC_SDMA_ADDR,\r
FALSE,\r
if (EFI_ERROR (Status)) {\r
goto Done;\r
}\r
- Trb->Data = (VOID*)(UINTN)SdmaAddr;\r
+ Trb->DataPhy = (UINT32)(UINTN)SdmaAddr;\r
}\r
\r
if ((Packet->SdCmdBlk->CommandType != SdCommandTypeAdtc) &&\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
}\r
\r
/**\r
- Tunning the sampling point of SDR104 or SDR50 bus speed mode.\r
+ Tuning the sampling point of SDR104 or SDR50 bus speed mode.\r
\r
Command SD_SEND_TUNING_BLOCK may be sent up to 40 times until the host finishes the\r
tuning procedure.\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
+ // Set to High Speed timing\r
//\r
if (AccessMode == 1) {\r
HostCtrl1 = BIT2;\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