\r
It would expose EFI_SD_MMC_PASS_THRU_PROTOCOL for upper layer use.\r
\r
- Copyright (c) 2018, NVIDIA CORPORATION. All rights reserved.\r
- Copyright (c) 2015 - 2019, 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) 2018-2019, NVIDIA CORPORATION. All rights reserved.\r
+ Copyright (c) 2015 - 2020, Intel Corporation. All rights reserved.<BR>\r
+ SPDX-License-Identifier: BSD-2-Clause-Patent\r
\r
**/\r
\r
)\r
{\r
EFI_STATUS Status;\r
+ EFI_PCI_IO_PROTOCOL_WIDTH Width;\r
\r
if ((PciIo == NULL) || (Data == NULL)) {\r
return EFI_INVALID_PARAMETER;\r
}\r
\r
- if ((Count != 1) && (Count != 2) && (Count != 4) && (Count != 8)) {\r
- return EFI_INVALID_PARAMETER;\r
+ switch (Count) {\r
+ case 1:\r
+ Width = EfiPciIoWidthUint8;\r
+ break;\r
+ case 2:\r
+ Width = EfiPciIoWidthUint16;\r
+ Count = 1;\r
+ break;\r
+ case 4:\r
+ Width = EfiPciIoWidthUint32;\r
+ Count = 1;\r
+ break;\r
+ case 8:\r
+ Width = EfiPciIoWidthUint32;\r
+ Count = 2;\r
+ break;\r
+ default:\r
+ return EFI_INVALID_PARAMETER;\r
}\r
\r
if (Read) {\r
Status = PciIo->Mem.Read (\r
PciIo,\r
- EfiPciIoWidthUint8,\r
+ Width,\r
BarIndex,\r
(UINT64) Offset,\r
Count,\r
} else {\r
Status = PciIo->Mem.Write (\r
PciIo,\r
- EfiPciIoWidthUint8,\r
+ Width,\r
BarIndex,\r
(UINT64) Offset,\r
Count,\r
return Status;\r
}\r
\r
+/**\r
+ Start the SD clock.\r
+\r
+ @param[in] PciIo The PCI IO protocol instance.\r
+ @param[in] Slot The slot number.\r
+\r
+ @retval EFI_SUCCESS Succeeded to start the SD clock.\r
+ @retval Others Failed to start the SD clock.\r
+**/\r
+EFI_STATUS\r
+SdMmcHcStartSdClock (\r
+ IN EFI_PCI_IO_PROTOCOL *PciIo,\r
+ IN UINT8 Slot\r
+ )\r
+{\r
+ UINT16 ClockCtrl;\r
+\r
+ //\r
+ // Set SD Clock Enable in the Clock Control register to 1\r
+ //\r
+ ClockCtrl = BIT2;\r
+ return SdMmcHcOrMmio (PciIo, Slot, SD_MMC_HC_CLOCK_CTRL, sizeof (ClockCtrl), &ClockCtrl);\r
+}\r
+\r
/**\r
SD/MMC card clock supply.\r
\r
Refer to SD Host Controller Simplified spec 3.0 Section 3.2.1 for details.\r
\r
- @param[in] PciIo The PCI IO protocol instance.\r
- @param[in] Slot The slot number of the SD card to send the command to.\r
- @param[in] ClockFreq The max clock frequency to be set. The unit is KHz.\r
- @param[in] BaseClkFreq The base clock frequency of host controller in MHz.\r
- @param[in] ControllerVer The version of host controller.\r
+ @param[in] Private A pointer to the SD_MMC_HC_PRIVATE_DATA instance.\r
+ @param[in] Slot The slot number of the SD card to send the command to.\r
+ @param[in] BusTiming BusTiming at which the frequency change is done.\r
+ @param[in] FirstTimeSetup Flag to indicate whether the clock is being setup for the first time.\r
+ @param[in] ClockFreq The max clock frequency to be set. The unit is KHz.\r
\r
@retval EFI_SUCCESS The clock is supplied successfully.\r
@retval Others The clock isn't supplied successfully.\r
**/\r
EFI_STATUS\r
SdMmcHcClockSupply (\r
- IN EFI_PCI_IO_PROTOCOL *PciIo,\r
- IN UINT8 Slot,\r
- IN UINT64 ClockFreq,\r
- IN UINT32 BaseClkFreq,\r
- IN UINT16 ControllerVer\r
+ IN SD_MMC_HC_PRIVATE_DATA *Private,\r
+ IN UINT8 Slot,\r
+ IN SD_MMC_BUS_MODE BusTiming,\r
+ IN BOOLEAN FirstTimeSetup,\r
+ IN UINT64 ClockFreq\r
)\r
{\r
EFI_STATUS Status;\r
UINT32 Divisor;\r
UINT32 Remainder;\r
UINT16 ClockCtrl;\r
+ UINT32 BaseClkFreq;\r
+ UINT16 ControllerVer;\r
+ EFI_PCI_IO_PROTOCOL *PciIo;\r
\r
- //\r
- // Calculate a divisor for SD clock frequency\r
- //\r
- ASSERT (BaseClkFreq != 0);\r
+ PciIo = Private->PciIo;\r
+ BaseClkFreq = Private->BaseClkFreq[Slot];\r
+ ControllerVer = Private->ControllerVersion[Slot];\r
\r
- if (ClockFreq == 0) {\r
+ if (BaseClkFreq == 0 || ClockFreq == 0) {\r
return EFI_INVALID_PARAMETER;\r
}\r
\r
return Status;\r
}\r
\r
+ Status = SdMmcHcStartSdClock (PciIo, Slot);\r
+ if (EFI_ERROR (Status)) {\r
+ return Status;\r
+ }\r
+\r
//\r
- // Set SD Clock Enable in the Clock Control register to 1\r
+ // We don't notify the platform on first time setup to avoid changing\r
+ // legacy behavior. During first time setup we also don't know what type\r
+ // of the card slot it is and which enum value of BusTiming applies.\r
//\r
- ClockCtrl = BIT2;\r
- Status = SdMmcHcOrMmio (PciIo, Slot, SD_MMC_HC_CLOCK_CTRL, sizeof (ClockCtrl), &ClockCtrl);\r
+ if (!FirstTimeSetup && mOverride != NULL && mOverride->NotifyPhase != NULL) {\r
+ Status = mOverride->NotifyPhase (\r
+ Private->ControllerHandle,\r
+ Slot,\r
+ EdkiiSdMmcSwitchClockFreqPost,\r
+ &BusTiming\r
+ );\r
+ if (EFI_ERROR (Status)) {\r
+ DEBUG ((\r
+ DEBUG_ERROR,\r
+ "%a: SD/MMC switch clock freq post notifier callback failed - %r\n",\r
+ __FUNCTION__,\r
+ Status\r
+ ));\r
+ return Status;\r
+ }\r
+ }\r
+\r
+ Private->Slot[Slot].CurrentFreq = ClockFreq;\r
\r
return Status;\r
}\r
if (ControllerVer >= SD_MMC_HC_CTRL_VER_400) {\r
HostCtrl2 = SD_MMC_HC_V4_EN;\r
//\r
- // Check if V4 64bit support is available\r
+ // Check if controller version V4.0\r
//\r
- if (Capability.SysBus64V4 != 0) {\r
- HostCtrl2 |= SD_MMC_HC_64_ADDR_EN;\r
- DEBUG ((DEBUG_INFO, "Enabled V4 64 bit system bus support\n"));\r
+ if (ControllerVer == SD_MMC_HC_CTRL_VER_400) {\r
+ //\r
+ // Check if 64bit support is available\r
+ //\r
+ if (Capability.SysBus64V3 != 0) {\r
+ HostCtrl2 |= SD_MMC_HC_64_ADDR_EN;\r
+ DEBUG ((DEBUG_INFO, "Enabled V4 64 bit system bus support\n"));\r
+ }\r
}\r
//\r
// Check if controller version V4.10 or higher\r
//\r
- if (ControllerVer >= SD_MMC_HC_CTRL_VER_410) {\r
+ else if (ControllerVer >= SD_MMC_HC_CTRL_VER_410) {\r
+ //\r
+ // Check if 64bit support is available\r
+ //\r
+ if (Capability.SysBus64V4 != 0) {\r
+ HostCtrl2 |= SD_MMC_HC_64_ADDR_EN;\r
+ DEBUG ((DEBUG_INFO, "Enabled V4 64 bit system bus support\n"));\r
+ }\r
HostCtrl2 |= SD_MMC_HC_26_DATA_LEN_ADMA_EN;\r
DEBUG ((DEBUG_INFO, "Enabled V4 26 bit data length ADMA support\n"));\r
}\r
return EFI_SUCCESS;\r
}\r
\r
-/**\r
- Supply SD/MMC card with lowest clock frequency at initialization.\r
-\r
- @param[in] PciIo The PCI IO protocol instance.\r
- @param[in] Slot The slot number of the SD card to send the command to.\r
- @param[in] BaseClkFreq The base clock frequency of host controller in MHz.\r
- @param[in] ControllerVer The version of host controller.\r
-\r
- @retval EFI_SUCCESS The clock is supplied successfully.\r
- @retval Others The clock isn't supplied successfully.\r
-\r
-**/\r
-EFI_STATUS\r
-SdMmcHcInitClockFreq (\r
- IN EFI_PCI_IO_PROTOCOL *PciIo,\r
- IN UINT8 Slot,\r
- IN UINT32 BaseClkFreq,\r
- IN UINT16 ControllerVer\r
- )\r
-{\r
- EFI_STATUS Status;\r
- UINT32 InitFreq;\r
-\r
- //\r
- // According to SDHCI specification ver. 4.2, BaseClkFreq field value of\r
- // the Capability Register 1 can be zero, which means a need for obtaining\r
- // the clock frequency via another method. Fail in case it is not updated\r
- // by SW at this point.\r
- //\r
- if (BaseClkFreq == 0) {\r
- //\r
- // Don't support get Base Clock Frequency information via another method\r
- //\r
- return EFI_UNSUPPORTED;\r
- }\r
- //\r
- // Supply 400KHz clock frequency at initialization phase.\r
- //\r
- InitFreq = 400;\r
- Status = SdMmcHcClockSupply (PciIo, Slot, InitFreq, BaseClkFreq, ControllerVer);\r
- return Status;\r
-}\r
-\r
/**\r
Supply SD/MMC card with maximum voltage at initialization.\r
\r
return Status;\r
}\r
\r
- Status = SdMmcHcInitClockFreq (PciIo, Slot, Private->BaseClkFreq[Slot], Private->ControllerVersion[Slot]);\r
+ //\r
+ // Perform first time clock setup with 400 KHz frequency.\r
+ // We send the 0 as the BusTiming value because at this time\r
+ // we still do not know the slot type and which enum value will apply.\r
+ // Since it is a first time setup SdMmcHcClockSupply won't notify\r
+ // the platofrm driver anyway so it doesn't matter.\r
+ //\r
+ Status = SdMmcHcClockSupply (Private, Slot, 0, TRUE, 400);\r
if (EFI_ERROR (Status)) {\r
return Status;\r
}\r
return EFI_SUCCESS;\r
}\r
\r
+/**\r
+ Set driver strength in host controller.\r
+\r
+ @param[in] PciIo The PCI IO protocol instance.\r
+ @param[in] SlotIndex The slot index of the card.\r
+ @param[in] DriverStrength DriverStrength to set in the controller.\r
+\r
+ @retval EFI_SUCCESS Driver strength programmed successfully.\r
+ @retval Others Failed to set driver strength.\r
+**/\r
+EFI_STATUS\r
+SdMmcSetDriverStrength (\r
+ IN EFI_PCI_IO_PROTOCOL *PciIo,\r
+ IN UINT8 SlotIndex,\r
+ IN SD_DRIVER_STRENGTH_TYPE DriverStrength\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ UINT16 HostCtrl2;\r
+\r
+ if (DriverStrength == SdDriverStrengthIgnore) {\r
+ return EFI_SUCCESS;\r
+ }\r
+\r
+ HostCtrl2 = (UINT16)~SD_MMC_HC_CTRL_DRIVER_STRENGTH_MASK;\r
+ Status = SdMmcHcAndMmio (PciIo, SlotIndex, SD_MMC_HC_HOST_CTRL2, sizeof (HostCtrl2), &HostCtrl2);\r
+ if (EFI_ERROR (Status)) {\r
+ return Status;\r
+ }\r
+\r
+ HostCtrl2 = (DriverStrength << 4) & SD_MMC_HC_CTRL_DRIVER_STRENGTH_MASK;\r
+ return SdMmcHcOrMmio (PciIo, SlotIndex, SD_MMC_HC_HOST_CTRL2, sizeof (HostCtrl2), &HostCtrl2);\r
+}\r
+\r
/**\r
Turn on/off LED.\r
\r
EFI_PCI_IO_PROTOCOL *PciIo;\r
EFI_STATUS Status;\r
UINTN Bytes;\r
- BOOLEAN AddressingMode64;\r
- BOOLEAN DataLength26;\r
UINT32 AdmaMaxDataPerLine;\r
UINT32 DescSize;\r
VOID *AdmaDesc;\r
\r
- AddressingMode64 = FALSE;\r
- DataLength26 = FALSE;\r
AdmaMaxDataPerLine = ADMA_MAX_DATA_PER_LINE_16B;\r
DescSize = sizeof (SD_MMC_HC_ADMA_32_DESC_LINE);\r
AdmaDesc = NULL;\r
DataLen = Trb->DataLen;\r
PciIo = Trb->Private->PciIo;\r
\r
- //\r
- // Detect whether 64bit addressing is supported.\r
- //\r
- if (ControllerVer >= SD_MMC_HC_CTRL_VER_400) {\r
- Status = SdMmcHcCheckMmioSet(PciIo, Trb->Slot, SD_MMC_HC_HOST_CTRL2, sizeof(UINT16),\r
- SD_MMC_HC_V4_EN|SD_MMC_HC_64_ADDR_EN, SD_MMC_HC_V4_EN|SD_MMC_HC_64_ADDR_EN);\r
- if (!EFI_ERROR (Status)) {\r
- AddressingMode64 = TRUE;\r
- DescSize = sizeof (SD_MMC_HC_ADMA_64_DESC_LINE);\r
- }\r
- }\r
//\r
// Check for valid ranges in 32bit ADMA Descriptor Table\r
//\r
- if (!AddressingMode64 &&\r
+ if ((Trb->Mode == SdMmcAdma32bMode) &&\r
((Data >= 0x100000000ul) || ((Data + DataLen) > 0x100000000ul))) {\r
return EFI_INVALID_PARAMETER;\r
}\r
//\r
// Check address field alignment\r
//\r
- if (AddressingMode64) {\r
+ if (Trb->Mode != SdMmcAdma32bMode) {\r
//\r
// Address field shall be set on 64-bit boundary (Lower 3-bit is always set to 0)\r
//\r
DEBUG ((DEBUG_INFO, "The buffer [0x%x] to construct ADMA desc is not aligned to 4 bytes boundary!\n", Data));\r
}\r
}\r
+\r
//\r
- // Detect whether 26bit data length is supported.\r
+ // Configure 64b ADMA.\r
//\r
- Status = SdMmcHcCheckMmioSet(PciIo, Trb->Slot, SD_MMC_HC_HOST_CTRL2, sizeof(UINT16),\r
- SD_MMC_HC_26_DATA_LEN_ADMA_EN, SD_MMC_HC_26_DATA_LEN_ADMA_EN);\r
- if (!EFI_ERROR (Status)) {\r
- DataLength26 = TRUE;\r
+ if (Trb->Mode == SdMmcAdma64bV3Mode) {\r
+ DescSize = sizeof (SD_MMC_HC_ADMA_64_V3_DESC_LINE);\r
+ }else if (Trb->Mode == SdMmcAdma64bV4Mode) {\r
+ DescSize = sizeof (SD_MMC_HC_ADMA_64_V4_DESC_LINE);\r
+ }\r
+ //\r
+ // Configure 26b data length.\r
+ //\r
+ if (Trb->AdmaLengthMode == SdMmcAdmaLen26b) {\r
AdmaMaxDataPerLine = ADMA_MAX_DATA_PER_LINE_26B;\r
}\r
\r
return EFI_OUT_OF_RESOURCES;\r
}\r
\r
- if ((!AddressingMode64) &&\r
+ if ((Trb->Mode == SdMmcAdma32bMode) &&\r
(UINT64)(UINTN)Trb->AdmaDescPhy > 0x100000000ul) {\r
//\r
// The ADMA doesn't support 64bit addressing.\r
PciIo,\r
Trb->AdmaMap\r
);\r
+ Trb->AdmaMap = NULL;\r
+\r
PciIo->FreeBuffer (\r
PciIo,\r
EFI_SIZE_TO_PAGES (TableSize),\r
\r
Remaining = DataLen;\r
Address = Data;\r
- if (!AddressingMode64) {\r
+ if (Trb->Mode == SdMmcAdma32bMode) {\r
Trb->Adma32Desc = AdmaDesc;\r
- Trb->Adma64Desc = NULL;\r
+ } else if (Trb->Mode == SdMmcAdma64bV3Mode) {\r
+ Trb->Adma64V3Desc = AdmaDesc;\r
} else {\r
- Trb->Adma64Desc = AdmaDesc;\r
- Trb->Adma32Desc = NULL;\r
+ Trb->Adma64V4Desc = AdmaDesc;\r
}\r
+\r
for (Index = 0; Index < Entries; Index++) {\r
- if (!AddressingMode64) {\r
+ if (Trb->Mode == SdMmcAdma32bMode) {\r
if (Remaining <= AdmaMaxDataPerLine) {\r
Trb->Adma32Desc[Index].Valid = 1;\r
Trb->Adma32Desc[Index].Act = 2;\r
- if (DataLength26) {\r
+ if (Trb->AdmaLengthMode == SdMmcAdmaLen26b) {\r
Trb->Adma32Desc[Index].UpperLength = (UINT16)RShiftU64 (Remaining, 16);\r
}\r
Trb->Adma32Desc[Index].LowerLength = (UINT16)(Remaining & MAX_UINT16);\r
} else {\r
Trb->Adma32Desc[Index].Valid = 1;\r
Trb->Adma32Desc[Index].Act = 2;\r
- if (DataLength26) {\r
+ if (Trb->AdmaLengthMode == SdMmcAdmaLen26b) {\r
Trb->Adma32Desc[Index].UpperLength = 0;\r
}\r
Trb->Adma32Desc[Index].LowerLength = 0;\r
Trb->Adma32Desc[Index].Address = (UINT32)Address;\r
}\r
+ } else if (Trb->Mode == SdMmcAdma64bV3Mode) {\r
+ if (Remaining <= AdmaMaxDataPerLine) {\r
+ Trb->Adma64V3Desc[Index].Valid = 1;\r
+ Trb->Adma64V3Desc[Index].Act = 2;\r
+ if (Trb->AdmaLengthMode == SdMmcAdmaLen26b) {\r
+ Trb->Adma64V3Desc[Index].UpperLength = (UINT16)RShiftU64 (Remaining, 16);\r
+ }\r
+ Trb->Adma64V3Desc[Index].LowerLength = (UINT16)(Remaining & MAX_UINT16);\r
+ Trb->Adma64V3Desc[Index].LowerAddress = (UINT32)Address;\r
+ Trb->Adma64V3Desc[Index].UpperAddress = (UINT32)RShiftU64 (Address, 32);\r
+ break;\r
+ } else {\r
+ Trb->Adma64V3Desc[Index].Valid = 1;\r
+ Trb->Adma64V3Desc[Index].Act = 2;\r
+ if (Trb->AdmaLengthMode == SdMmcAdmaLen26b) {\r
+ Trb->Adma64V3Desc[Index].UpperLength = 0;\r
+ }\r
+ Trb->Adma64V3Desc[Index].LowerLength = 0;\r
+ Trb->Adma64V3Desc[Index].LowerAddress = (UINT32)Address;\r
+ Trb->Adma64V3Desc[Index].UpperAddress = (UINT32)RShiftU64 (Address, 32);\r
+ }\r
} else {\r
if (Remaining <= AdmaMaxDataPerLine) {\r
- Trb->Adma64Desc[Index].Valid = 1;\r
- Trb->Adma64Desc[Index].Act = 2;\r
- if (DataLength26) {\r
- Trb->Adma64Desc[Index].UpperLength = (UINT16)RShiftU64 (Remaining, 16);\r
+ Trb->Adma64V4Desc[Index].Valid = 1;\r
+ Trb->Adma64V4Desc[Index].Act = 2;\r
+ if (Trb->AdmaLengthMode == SdMmcAdmaLen26b) {\r
+ Trb->Adma64V4Desc[Index].UpperLength = (UINT16)RShiftU64 (Remaining, 16);\r
}\r
- Trb->Adma64Desc[Index].LowerLength = (UINT16)(Remaining & MAX_UINT16);\r
- Trb->Adma64Desc[Index].LowerAddress = (UINT32)Address;\r
- Trb->Adma64Desc[Index].UpperAddress = (UINT32)RShiftU64 (Address, 32);\r
+ Trb->Adma64V4Desc[Index].LowerLength = (UINT16)(Remaining & MAX_UINT16);\r
+ Trb->Adma64V4Desc[Index].LowerAddress = (UINT32)Address;\r
+ Trb->Adma64V4Desc[Index].UpperAddress = (UINT32)RShiftU64 (Address, 32);\r
break;\r
} else {\r
- Trb->Adma64Desc[Index].Valid = 1;\r
- Trb->Adma64Desc[Index].Act = 2;\r
- if (DataLength26) {\r
- Trb->Adma64Desc[Index].UpperLength = 0;\r
+ Trb->Adma64V4Desc[Index].Valid = 1;\r
+ Trb->Adma64V4Desc[Index].Act = 2;\r
+ if (Trb->AdmaLengthMode == SdMmcAdmaLen26b) {\r
+ Trb->Adma64V4Desc[Index].UpperLength = 0;\r
}\r
- Trb->Adma64Desc[Index].LowerLength = 0;\r
- Trb->Adma64Desc[Index].LowerAddress = (UINT32)Address;\r
- Trb->Adma64Desc[Index].UpperAddress = (UINT32)RShiftU64 (Address, 32);\r
+ Trb->Adma64V4Desc[Index].LowerLength = 0;\r
+ Trb->Adma64V4Desc[Index].LowerAddress = (UINT32)Address;\r
+ Trb->Adma64V4Desc[Index].UpperAddress = (UINT32)RShiftU64 (Address, 32);\r
}\r
}\r
\r
//\r
// Set the last descriptor line as end of descriptor table\r
//\r
- AddressingMode64 ? (Trb->Adma64Desc[Index].End = 1) : (Trb->Adma32Desc[Index].End = 1);\r
+ if (Trb->Mode == SdMmcAdma32bMode) {\r
+ Trb->Adma32Desc[Index].End = 1;\r
+ } else if (Trb->Mode == SdMmcAdma64bV3Mode) {\r
+ Trb->Adma64V3Desc[Index].End = 1;\r
+ } else {\r
+ Trb->Adma64V4Desc[Index].End = 1;\r
+ }\r
return EFI_SUCCESS;\r
}\r
\r
Trb->Event = Event;\r
Trb->Started = FALSE;\r
Trb->Timeout = Packet->Timeout;\r
+ Trb->Retries = SD_MMC_TRB_RETRIES;\r
Trb->Private = Private;\r
\r
if ((Packet->InTransferLength != 0) && (Packet->InDataBuffer != NULL)) {\r
if (Trb->DataLen == 0) {\r
Trb->Mode = SdMmcNoData;\r
} else if (Private->Capability[Slot].Adma2 != 0) {\r
- Trb->Mode = SdMmcAdmaMode;\r
+ Trb->Mode = SdMmcAdma32bMode;\r
+ Trb->AdmaLengthMode = SdMmcAdmaLen16b;\r
+ if ((Private->ControllerVersion[Slot] == SD_MMC_HC_CTRL_VER_300) &&\r
+ (Private->Capability[Slot].SysBus64V3 == 1)) {\r
+ Trb->Mode = SdMmcAdma64bV3Mode;\r
+ } else if (((Private->ControllerVersion[Slot] == SD_MMC_HC_CTRL_VER_400) &&\r
+ (Private->Capability[Slot].SysBus64V3 == 1)) ||\r
+ ((Private->ControllerVersion[Slot] >= SD_MMC_HC_CTRL_VER_410) &&\r
+ (Private->Capability[Slot].SysBus64V4 == 1))) {\r
+ Trb->Mode = SdMmcAdma64bV4Mode;\r
+ }\r
+ if (Private->ControllerVersion[Slot] >= SD_MMC_HC_CTRL_VER_410) {\r
+ Trb->AdmaLengthMode = SdMmcAdmaLen26b;\r
+ }\r
Status = BuildAdmaDescTable (Trb, Private->ControllerVersion[Slot]);\r
if (EFI_ERROR (Status)) {\r
- PciIo->Unmap (PciIo, Trb->DataMap);\r
goto Error;\r
}\r
} else if (Private->Capability[Slot].Sdma != 0) {\r
Trb->Adma32Desc\r
);\r
}\r
- if (Trb->Adma64Desc != NULL) {\r
+ if (Trb->Adma64V3Desc != NULL) {\r
PciIo->FreeBuffer (\r
PciIo,\r
Trb->AdmaPages,\r
- Trb->Adma64Desc\r
+ Trb->Adma64V3Desc\r
+ );\r
+ }\r
+ if (Trb->Adma64V4Desc != NULL) {\r
+ PciIo->FreeBuffer (\r
+ PciIo,\r
+ Trb->AdmaPages,\r
+ Trb->Adma64V4Desc\r
);\r
}\r
if (Trb->DataMap != NULL) {\r
if (EFI_ERROR (Status)) {\r
return Status;\r
}\r
+\r
+ if (Private->ControllerVersion[Trb->Slot] >= SD_MMC_HC_CTRL_VER_400) {\r
+ Status = SdMmcHcCheckMmioSet(PciIo, Trb->Slot, SD_MMC_HC_HOST_CTRL2, sizeof(UINT16),\r
+ SD_MMC_HC_64_ADDR_EN, SD_MMC_HC_64_ADDR_EN);\r
+ if (!EFI_ERROR (Status)) {\r
+ AddressingMode64 = TRUE;\r
+ }\r
+ }\r
+\r
//\r
// Set Host Control 1 register DMA Select field\r
//\r
- if (Trb->Mode == SdMmcAdmaMode) {\r
+ if ((Trb->Mode == SdMmcAdma32bMode) ||\r
+ (Trb->Mode == SdMmcAdma64bV4Mode)) {\r
HostCtrl1 = BIT4;\r
Status = SdMmcHcOrMmio (PciIo, Trb->Slot, SD_MMC_HC_HOST_CTRL1, sizeof (HostCtrl1), &HostCtrl1);\r
if (EFI_ERROR (Status)) {\r
return Status;\r
}\r
+ } else if (Trb->Mode == SdMmcAdma64bV3Mode) {\r
+ HostCtrl1 = BIT4|BIT3;\r
+ Status = SdMmcHcOrMmio (PciIo, Trb->Slot, SD_MMC_HC_HOST_CTRL1, sizeof (HostCtrl1), &HostCtrl1);\r
+ if (EFI_ERROR (Status)) {\r
+ return Status;\r
+ }\r
}\r
\r
SdMmcHcLedOnOff (PciIo, Trb->Slot, TRUE);\r
\r
- if (Private->ControllerVersion[Trb->Slot] >= SD_MMC_HC_CTRL_VER_400) {\r
- Status = SdMmcHcCheckMmioSet(PciIo, Trb->Slot, SD_MMC_HC_HOST_CTRL2, sizeof(UINT16),\r
- SD_MMC_HC_V4_EN|SD_MMC_HC_64_ADDR_EN, SD_MMC_HC_V4_EN|SD_MMC_HC_64_ADDR_EN);\r
- if (!EFI_ERROR (Status)) {\r
- AddressingMode64 = TRUE;\r
- }\r
- }\r
-\r
if (Trb->Mode == SdMmcSdmaMode) {\r
if ((!AddressingMode64) &&\r
((UINT64)(UINTN)Trb->DataPhy >= 0x100000000ul)) {\r
if (EFI_ERROR (Status)) {\r
return Status;\r
}\r
- } else if (Trb->Mode == SdMmcAdmaMode) {\r
+ } else if ((Trb->Mode == SdMmcAdma32bMode) ||\r
+ (Trb->Mode == SdMmcAdma64bV3Mode) ||\r
+ (Trb->Mode == SdMmcAdma64bV4Mode)) {\r
AdmaAddr = (UINT64)(UINTN)Trb->AdmaDescPhy;\r
Status = SdMmcHcRwMmio (PciIo, Trb->Slot, SD_MMC_HC_ADMA_SYS_ADDR, FALSE, sizeof (AdmaAddr), &AdmaAddr);\r
if (EFI_ERROR (Status)) {\r
return Status;\r
}\r
\r
+/**\r
+ Performs SW reset based on passed error status mask.\r
+\r
+ @param[in] Private Pointer to driver private data.\r
+ @param[in] Slot Index of the slot to reset.\r
+ @param[in] ErrIntStatus Error interrupt status mask.\r
+\r
+ @retval EFI_SUCCESS Software reset performed successfully.\r
+ @retval Other Software reset failed.\r
+**/\r
+EFI_STATUS\r
+SdMmcSoftwareReset (\r
+ IN SD_MMC_HC_PRIVATE_DATA *Private,\r
+ IN UINT8 Slot,\r
+ IN UINT16 ErrIntStatus\r
+ )\r
+{\r
+ UINT8 SwReset;\r
+ EFI_STATUS Status;\r
+\r
+ SwReset = 0;\r
+ if ((ErrIntStatus & 0x0F) != 0) {\r
+ SwReset |= BIT1;\r
+ }\r
+ if ((ErrIntStatus & 0x70) != 0) {\r
+ SwReset |= BIT2;\r
+ }\r
+\r
+ Status = SdMmcHcRwMmio (\r
+ Private->PciIo,\r
+ Slot,\r
+ SD_MMC_HC_SW_RST,\r
+ FALSE,\r
+ sizeof (SwReset),\r
+ &SwReset\r
+ );\r
+ if (EFI_ERROR (Status)) {\r
+ return Status;\r
+ }\r
+\r
+ Status = SdMmcHcWaitMmioSet (\r
+ Private->PciIo,\r
+ Slot,\r
+ SD_MMC_HC_SW_RST,\r
+ sizeof (SwReset),\r
+ 0xFF,\r
+ 0,\r
+ SD_MMC_HC_GENERIC_TIMEOUT\r
+ );\r
+ if (EFI_ERROR (Status)) {\r
+ return Status;\r
+ }\r
+\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+ Checks the error status in error status register\r
+ and issues appropriate software reset as described in\r
+ SD specification section 3.10.\r
+\r
+ @param[in] Private Pointer to driver private data.\r
+ @param[in] Slot Index of the slot for device.\r
+ @param[in] IntStatus Normal interrupt status mask.\r
+\r
+ @retval EFI_CRC_ERROR CRC error happened during CMD execution.\r
+ @retval EFI_SUCCESS No error reported.\r
+ @retval Others Some other error happened.\r
+\r
+**/\r
+EFI_STATUS\r
+SdMmcCheckAndRecoverErrors (\r
+ IN SD_MMC_HC_PRIVATE_DATA *Private,\r
+ IN UINT8 Slot,\r
+ IN UINT16 IntStatus\r
+ )\r
+{\r
+ UINT16 ErrIntStatus;\r
+ EFI_STATUS Status;\r
+ EFI_STATUS ErrorStatus;\r
+\r
+ if ((IntStatus & BIT15) == 0) {\r
+ return EFI_SUCCESS;\r
+ }\r
+\r
+ Status = SdMmcHcRwMmio (\r
+ Private->PciIo,\r
+ Slot,\r
+ SD_MMC_HC_ERR_INT_STS,\r
+ TRUE,\r
+ sizeof (ErrIntStatus),\r
+ &ErrIntStatus\r
+ );\r
+ if (EFI_ERROR (Status)) {\r
+ return Status;\r
+ }\r
+\r
+ //\r
+ // If the data timeout error is reported\r
+ // but data transfer is signaled as completed we\r
+ // have to ignore data timeout. We also assume that no\r
+ // other error is present on the link since data transfer\r
+ // completed successfully. Error interrupt status\r
+ // register is going to be reset when the next command\r
+ // is started.\r
+ //\r
+ if (((ErrIntStatus & BIT4) != 0) && ((IntStatus & BIT1) != 0)) {\r
+ return EFI_SUCCESS;\r
+ }\r
+\r
+ //\r
+ // We treat both CMD and DAT CRC errors and\r
+ // end bits errors as EFI_CRC_ERROR. This will\r
+ // let higher layer know that the error possibly\r
+ // happened due to random bus condition and the\r
+ // command can be retried.\r
+ //\r
+ if ((ErrIntStatus & (BIT1 | BIT2 | BIT5 | BIT6)) != 0) {\r
+ ErrorStatus = EFI_CRC_ERROR;\r
+ } else {\r
+ ErrorStatus = EFI_DEVICE_ERROR;\r
+ }\r
+\r
+ Status = SdMmcSoftwareReset (Private, Slot, ErrIntStatus);\r
+ if (EFI_ERROR (Status)) {\r
+ return Status;\r
+ }\r
+\r
+ return ErrorStatus;\r
+}\r
+\r
/**\r
Check the TRB execution result.\r
\r
UINT32 Response[4];\r
UINT64 SdmaAddr;\r
UINT8 Index;\r
- UINT8 SwReset;\r
UINT32 PioLength;\r
\r
- SwReset = 0;\r
Packet = Trb->Packet;\r
//\r
// Check Trb execution result by reading Normal Interrupt Status register.\r
if (EFI_ERROR (Status)) {\r
goto Done;\r
}\r
+\r
//\r
- // Check Transfer Complete bit is set or not.\r
+ // Check if there are any errors reported by host controller\r
+ // and if neccessary recover the controller before next command is executed.\r
//\r
- if ((IntStatus & BIT1) == BIT1) {\r
- if ((IntStatus & BIT15) == BIT15) {\r
- //\r
- // Read Error Interrupt Status register to check if the error is\r
- // Data Timeout Error.\r
- // If yes, treat it as success as Transfer Complete has higher\r
- // priority than Data Timeout Error.\r
- //\r
- Status = SdMmcHcRwMmio (\r
- Private->PciIo,\r
- Trb->Slot,\r
- SD_MMC_HC_ERR_INT_STS,\r
- TRUE,\r
- sizeof (IntStatus),\r
- &IntStatus\r
- );\r
- if (!EFI_ERROR (Status)) {\r
- if ((IntStatus & BIT4) == BIT4) {\r
- Status = EFI_SUCCESS;\r
- } else {\r
- Status = EFI_DEVICE_ERROR;\r
- }\r
- }\r
- }\r
-\r
+ Status = SdMmcCheckAndRecoverErrors (Private, Trb->Slot, IntStatus);\r
+ if (EFI_ERROR (Status)) {\r
goto Done;\r
}\r
+\r
//\r
- // Check if there is a error happened during cmd execution.\r
- // If yes, then do error recovery procedure to follow SD Host Controller\r
- // Simplified Spec 3.0 section 3.10.1.\r
+ // Check Transfer Complete bit is set or not.\r
//\r
- if ((IntStatus & BIT15) == BIT15) {\r
- Status = SdMmcHcRwMmio (\r
- Private->PciIo,\r
- Trb->Slot,\r
- SD_MMC_HC_ERR_INT_STS,\r
- TRUE,\r
- sizeof (IntStatus),\r
- &IntStatus\r
- );\r
- if (EFI_ERROR (Status)) {\r
- goto Done;\r
- }\r
- if ((IntStatus & 0x0F) != 0) {\r
- SwReset |= BIT1;\r
- }\r
- if ((IntStatus & 0xF0) != 0) {\r
- SwReset |= BIT2;\r
- }\r
-\r
- Status = SdMmcHcRwMmio (\r
- Private->PciIo,\r
- Trb->Slot,\r
- SD_MMC_HC_SW_RST,\r
- FALSE,\r
- sizeof (SwReset),\r
- &SwReset\r
- );\r
- if (EFI_ERROR (Status)) {\r
- goto Done;\r
- }\r
- Status = SdMmcHcWaitMmioSet (\r
- Private->PciIo,\r
- Trb->Slot,\r
- SD_MMC_HC_SW_RST,\r
- sizeof (SwReset),\r
- 0xFF,\r
- 0,\r
- SD_MMC_HC_GENERIC_TIMEOUT\r
- );\r
- if (EFI_ERROR (Status)) {\r
- goto Done;\r
- }\r
-\r
- Status = EFI_DEVICE_ERROR;\r
+ if ((IntStatus & BIT1) == BIT1) {\r
goto Done;\r
}\r
+\r
//\r
// Check if DMA interrupt is signalled for the SDMA transfer.\r
//\r