/** @file\r
This driver is used to manage SD/MMC PCI host controllers which are compliance\r
- with SD Host Controller Simplified Specification version 3.00.\r
+ with SD Host Controller Simplified Specification version 3.00 plus the 64-bit\r
+ System Addressing support in SD Host Controller Simplified Specification version\r
+ 4.20.\r
\r
It would expose EFI_SD_MMC_PASS_THRU_PROTOCOL for upper layer use.\r
\r
- Copyright (c) 2015 - 2016, Intel Corporation. All rights reserved.<BR>\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
DEBUG ((DEBUG_INFO, " Voltage 3.3 %a\n", Capability->Voltage33 ? "TRUE" : "FALSE"));\r
DEBUG ((DEBUG_INFO, " Voltage 3.0 %a\n", Capability->Voltage30 ? "TRUE" : "FALSE"));\r
DEBUG ((DEBUG_INFO, " Voltage 1.8 %a\n", Capability->Voltage18 ? "TRUE" : "FALSE"));\r
- DEBUG ((DEBUG_INFO, " 64-bit Sys Bus %a\n", Capability->SysBus64 ? "TRUE" : "FALSE"));\r
+ DEBUG ((DEBUG_INFO, " V4 64-bit Sys Bus %a\n", Capability->SysBus64V4 ? "TRUE" : "FALSE"));\r
+ DEBUG ((DEBUG_INFO, " V3 64-bit Sys Bus %a\n", Capability->SysBus64V3 ? "TRUE" : "FALSE"));\r
DEBUG ((DEBUG_INFO, " Async Interrupt %a\n", Capability->AsyncInt ? "TRUE" : "FALSE"));\r
DEBUG ((DEBUG_INFO, " SlotType "));\r
if (Capability->SlotType == 0x00) {\r
return EFI_TIMEOUT;\r
}\r
\r
+/**\r
+ Get the controller version information from the specified slot.\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[out] Version The buffer to store the version information.\r
+\r
+ @retval EFI_SUCCESS The operation executes successfully.\r
+ @retval Others The operation fails.\r
+\r
+**/\r
+EFI_STATUS\r
+SdMmcHcGetControllerVersion (\r
+ IN EFI_PCI_IO_PROTOCOL *PciIo,\r
+ IN UINT8 Slot,\r
+ OUT UINT16 *Version\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+\r
+ Status = SdMmcHcRwMmio (PciIo, Slot, SD_MMC_HC_CTRL_VER, TRUE, sizeof (UINT16), Version);\r
+ if (EFI_ERROR (Status)) {\r
+ return Status;\r
+ }\r
+\r
+ *Version &= 0xFF;\r
+\r
+ return EFI_SUCCESS;\r
+}\r
+\r
/**\r
Software reset the specified SD/MMC host controller and enable all interrupts.\r
\r
- @param[in] PciIo The PCI IO protocol instance.\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
\r
@retval EFI_SUCCESS The software reset executes successfully.\r
**/\r
EFI_STATUS\r
SdMmcHcReset (\r
- IN EFI_PCI_IO_PROTOCOL *PciIo,\r
+ IN SD_MMC_HC_PRIVATE_DATA *Private,\r
IN UINT8 Slot\r
)\r
{\r
EFI_STATUS Status;\r
UINT8 SwReset;\r
+ EFI_PCI_IO_PROTOCOL *PciIo;\r
\r
- SwReset = 0xFF;\r
- Status = SdMmcHcRwMmio (PciIo, Slot, SD_MMC_HC_SW_RST, FALSE, sizeof (SwReset), &SwReset);\r
+ //\r
+ // Notify the SD/MMC override protocol that we are about to reset\r
+ // the SD/MMC host controller.\r
+ //\r
+ if (mOverride != NULL && mOverride->NotifyPhase != NULL) {\r
+ Status = mOverride->NotifyPhase (\r
+ Private->ControllerHandle,\r
+ Slot,\r
+ EdkiiSdMmcResetPre,\r
+ NULL);\r
+ if (EFI_ERROR (Status)) {\r
+ DEBUG ((DEBUG_WARN,\r
+ "%a: SD/MMC pre reset notifier callback failed - %r\n",\r
+ __FUNCTION__, Status));\r
+ return Status;\r
+ }\r
+ }\r
+\r
+ PciIo = Private->PciIo;\r
+ SwReset = BIT0;\r
+ Status = SdMmcHcOrMmio (PciIo, Slot, SD_MMC_HC_SW_RST, sizeof (SwReset), &SwReset);\r
\r
if (EFI_ERROR (Status)) {\r
- DEBUG ((DEBUG_ERROR, "SdMmcHcReset: write full 1 fails: %r\n", Status));\r
+ DEBUG ((DEBUG_ERROR, "SdMmcHcReset: write SW Reset for All fails: %r\n", Status));\r
return Status;\r
}\r
\r
Slot,\r
SD_MMC_HC_SW_RST,\r
sizeof (SwReset),\r
- 0xFF,\r
+ BIT0,\r
0x00,\r
SD_MMC_HC_GENERIC_TIMEOUT\r
);\r
DEBUG ((DEBUG_INFO, "SdMmcHcReset: reset done with %r\n", Status));\r
return Status;\r
}\r
+\r
//\r
// Enable all interrupt after reset all.\r
//\r
Status = SdMmcHcEnableInterrupt (PciIo, Slot);\r
+ if (EFI_ERROR (Status)) {\r
+ DEBUG ((DEBUG_INFO, "SdMmcHcReset: SdMmcHcEnableInterrupt done with %r\n",\r
+ Status));\r
+ return Status;\r
+ }\r
+\r
+ //\r
+ // Notify the SD/MMC override protocol that we have just reset\r
+ // the SD/MMC host controller.\r
+ //\r
+ if (mOverride != NULL && mOverride->NotifyPhase != NULL) {\r
+ Status = mOverride->NotifyPhase (\r
+ Private->ControllerHandle,\r
+ Slot,\r
+ EdkiiSdMmcResetPost,\r
+ NULL);\r
+ if (EFI_ERROR (Status)) {\r
+ DEBUG ((DEBUG_WARN,\r
+ "%a: SD/MMC post reset notifier callback failed - %r\n",\r
+ __FUNCTION__, Status));\r
+ }\r
+ }\r
\r
return Status;\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] Capability The capability of the slot.\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
IN EFI_PCI_IO_PROTOCOL *PciIo,\r
IN UINT8 Slot,\r
IN UINT64 ClockFreq,\r
- IN SD_MMC_HC_SLOT_CAP Capability\r
+ IN UINT32 BaseClkFreq,\r
+ IN UINT16 ControllerVer\r
)\r
{\r
EFI_STATUS Status;\r
- UINT32 BaseClkFreq;\r
UINT32 SettingFreq;\r
UINT32 Divisor;\r
UINT32 Remainder;\r
- UINT16 ControllerVer;\r
UINT16 ClockCtrl;\r
\r
//\r
// Calculate a divisor for SD clock frequency\r
//\r
- ASSERT (Capability.BaseClkFreq != 0);\r
+ ASSERT (BaseClkFreq != 0);\r
\r
- BaseClkFreq = Capability.BaseClkFreq;\r
if (ClockFreq == 0) {\r
return EFI_INVALID_PARAMETER;\r
}\r
\r
DEBUG ((DEBUG_INFO, "BaseClkFreq %dMHz Divisor %d ClockFreq %dKhz\n", BaseClkFreq, Divisor, ClockFreq));\r
\r
- Status = SdMmcHcRwMmio (PciIo, Slot, SD_MMC_HC_CTRL_VER, TRUE, sizeof (ControllerVer), &ControllerVer);\r
- if (EFI_ERROR (Status)) {\r
- return Status;\r
- }\r
//\r
// Set SDCLK Frequency Select and Internal Clock Enable fields in Clock Control register.\r
//\r
- if ((ControllerVer & 0xFF) == 2) {\r
+ if ((ControllerVer >= SD_MMC_HC_CTRL_VER_300) &&\r
+ (ControllerVer <= SD_MMC_HC_CTRL_VER_420)) {\r
ASSERT (Divisor <= 0x3FF);\r
ClockCtrl = ((Divisor & 0xFF) << 8) | ((Divisor & 0x300) >> 2);\r
- } else if (((ControllerVer & 0xFF) == 0) || ((ControllerVer & 0xFF) == 1)) {\r
+ } else if ((ControllerVer == SD_MMC_HC_CTRL_VER_100) ||\r
+ (ControllerVer == SD_MMC_HC_CTRL_VER_200)) {\r
//\r
// Only the most significant bit can be used as divisor.\r
//\r
}\r
\r
/**\r
- Supply SD/MMC card with lowest clock frequency at initialization.\r
+ Configure V4 controller enhancements 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] Capability The capability of the slot.\r
+ @param[in] ControllerVer The version of host controller.\r
+\r
+ @retval EFI_SUCCESS The clock is supplied successfully.\r
+\r
+**/\r
+EFI_STATUS\r
+SdMmcHcInitV4Enhancements (\r
+ IN EFI_PCI_IO_PROTOCOL *PciIo,\r
+ IN UINT8 Slot,\r
+ IN SD_MMC_HC_SLOT_CAP Capability,\r
+ IN UINT16 ControllerVer\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ UINT16 HostCtrl2;\r
+\r
+ //\r
+ // Check if controller version V4 or higher\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
+ //\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
+ //\r
+ // Check if controller version V4.10 or higher\r
+ //\r
+ if (ControllerVer >= SD_MMC_HC_CTRL_VER_410) {\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
+ Status = SdMmcHcOrMmio (PciIo, Slot, SD_MMC_HC_HOST_CTRL2, sizeof (HostCtrl2), &HostCtrl2);\r
+ if (EFI_ERROR (Status)) {\r
+ return Status;\r
+ }\r
+ }\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
SdMmcHcInitClockFreq (\r
IN EFI_PCI_IO_PROTOCOL *PciIo,\r
IN UINT8 Slot,\r
- IN SD_MMC_HC_SLOT_CAP Capability\r
+ IN UINT32 BaseClkFreq,\r
+ IN UINT16 ControllerVer\r
)\r
{\r
EFI_STATUS Status;\r
UINT32 InitFreq;\r
\r
//\r
- // Calculate a divisor for SD clock frequency\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 (Capability.BaseClkFreq == 0) {\r
+ if (BaseClkFreq == 0) {\r
//\r
// Don't support get Base Clock Frequency information via another method\r
//\r
// Supply 400KHz clock frequency at initialization phase.\r
//\r
InitFreq = 400;\r
- Status = SdMmcHcClockSupply (PciIo, Slot, InitFreq, Capability);\r
+ Status = SdMmcHcClockSupply (PciIo, Slot, InitFreq, BaseClkFreq, ControllerVer);\r
return Status;\r
}\r
\r
Initial SD/MMC host controller with lowest clock frequency, max power and max timeout value\r
at initialization.\r
\r
- @param[in] PciIo The PCI IO protocol instance.\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] Capability The capability of the slot.\r
\r
@retval EFI_SUCCESS The host controller is initialized successfully.\r
@retval Others The host controller isn't initialized successfully.\r
**/\r
EFI_STATUS\r
SdMmcHcInitHost (\r
- IN EFI_PCI_IO_PROTOCOL *PciIo,\r
- IN UINT8 Slot,\r
- IN SD_MMC_HC_SLOT_CAP Capability\r
+ IN SD_MMC_HC_PRIVATE_DATA *Private,\r
+ IN UINT8 Slot\r
)\r
{\r
- EFI_STATUS Status;\r
+ EFI_STATUS Status;\r
+ EFI_PCI_IO_PROTOCOL *PciIo;\r
+ SD_MMC_HC_SLOT_CAP Capability;\r
\r
- Status = SdMmcHcInitClockFreq (PciIo, Slot, Capability);\r
+ //\r
+ // Notify the SD/MMC override protocol that we are about to initialize\r
+ // the SD/MMC host controller.\r
+ //\r
+ if (mOverride != NULL && mOverride->NotifyPhase != NULL) {\r
+ Status = mOverride->NotifyPhase (\r
+ Private->ControllerHandle,\r
+ Slot,\r
+ EdkiiSdMmcInitHostPre,\r
+ NULL);\r
+ if (EFI_ERROR (Status)) {\r
+ DEBUG ((DEBUG_WARN,\r
+ "%a: SD/MMC pre init notifier callback failed - %r\n",\r
+ __FUNCTION__, Status));\r
+ return Status;\r
+ }\r
+ }\r
+\r
+ PciIo = Private->PciIo;\r
+ Capability = Private->Capability[Slot];\r
+\r
+ Status = SdMmcHcInitV4Enhancements (PciIo, Slot, Capability, Private->ControllerVersion[Slot]);\r
+ if (EFI_ERROR (Status)) {\r
+ return Status;\r
+ }\r
+\r
+ Status = SdMmcHcInitClockFreq (PciIo, Slot, Private->BaseClkFreq[Slot], Private->ControllerVersion[Slot]);\r
if (EFI_ERROR (Status)) {\r
return Status;\r
}\r
}\r
\r
Status = SdMmcHcInitTimeoutCtrl (PciIo, Slot);\r
+ if (EFI_ERROR (Status)) {\r
+ return Status;\r
+ }\r
+\r
+ //\r
+ // Notify the SD/MMC override protocol that we are have just initialized\r
+ // the SD/MMC host controller.\r
+ //\r
+ if (mOverride != NULL && mOverride->NotifyPhase != NULL) {\r
+ Status = mOverride->NotifyPhase (\r
+ Private->ControllerHandle,\r
+ Slot,\r
+ EdkiiSdMmcInitHostPost,\r
+ NULL);\r
+ if (EFI_ERROR (Status)) {\r
+ DEBUG ((DEBUG_WARN,\r
+ "%a: SD/MMC post init notifier callback failed - %r\n",\r
+ __FUNCTION__, Status));\r
+ }\r
+ }\r
return Status;\r
}\r
\r
+/**\r
+ Set SD Host Controler control 2 registry according to selected speed.\r
+\r
+ @param[in] ControllerHandle The handle of the controller.\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] Timing The timing to select.\r
+\r
+ @retval EFI_SUCCESS The timing is set successfully.\r
+ @retval Others The timing isn't set successfully.\r
+**/\r
+EFI_STATUS\r
+SdMmcHcUhsSignaling (\r
+ IN EFI_HANDLE ControllerHandle,\r
+ IN EFI_PCI_IO_PROTOCOL *PciIo,\r
+ IN UINT8 Slot,\r
+ IN SD_MMC_BUS_MODE Timing\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ UINT8 HostCtrl2;\r
+\r
+ HostCtrl2 = (UINT8)~SD_MMC_HC_CTRL_UHS_MASK;\r
+ Status = SdMmcHcAndMmio (PciIo, Slot, SD_MMC_HC_HOST_CTRL2, sizeof (HostCtrl2), &HostCtrl2);\r
+ if (EFI_ERROR (Status)) {\r
+ return Status;\r
+ }\r
+\r
+ switch (Timing) {\r
+ case SdMmcUhsSdr12:\r
+ HostCtrl2 = SD_MMC_HC_CTRL_UHS_SDR12;\r
+ break;\r
+ case SdMmcUhsSdr25:\r
+ HostCtrl2 = SD_MMC_HC_CTRL_UHS_SDR25;\r
+ break;\r
+ case SdMmcUhsSdr50:\r
+ HostCtrl2 = SD_MMC_HC_CTRL_UHS_SDR50;\r
+ break;\r
+ case SdMmcUhsSdr104:\r
+ HostCtrl2 = SD_MMC_HC_CTRL_UHS_SDR104;\r
+ break;\r
+ case SdMmcUhsDdr50:\r
+ HostCtrl2 = SD_MMC_HC_CTRL_UHS_DDR50;\r
+ break;\r
+ case SdMmcMmcLegacy:\r
+ HostCtrl2 = SD_MMC_HC_CTRL_MMC_LEGACY;\r
+ break;\r
+ case SdMmcMmcHsSdr:\r
+ HostCtrl2 = SD_MMC_HC_CTRL_MMC_HS_SDR;\r
+ break;\r
+ case SdMmcMmcHsDdr:\r
+ HostCtrl2 = SD_MMC_HC_CTRL_MMC_HS_DDR;\r
+ break;\r
+ case SdMmcMmcHs200:\r
+ HostCtrl2 = SD_MMC_HC_CTRL_MMC_HS200;\r
+ break;\r
+ case SdMmcMmcHs400:\r
+ HostCtrl2 = SD_MMC_HC_CTRL_MMC_HS400;\r
+ break;\r
+ default:\r
+ HostCtrl2 = 0;\r
+ break;\r
+ }\r
+ Status = SdMmcHcOrMmio (PciIo, Slot, SD_MMC_HC_HOST_CTRL2, sizeof (HostCtrl2), &HostCtrl2);\r
+ if (EFI_ERROR (Status)) {\r
+ return Status;\r
+ }\r
+\r
+ if (mOverride != NULL && mOverride->NotifyPhase != NULL) {\r
+ Status = mOverride->NotifyPhase (\r
+ ControllerHandle,\r
+ Slot,\r
+ EdkiiSdMmcUhsSignaling,\r
+ &Timing\r
+ );\r
+ if (EFI_ERROR (Status)) {\r
+ DEBUG ((\r
+ DEBUG_ERROR,\r
+ "%a: SD/MMC uhs signaling notifier callback failed - %r\n",\r
+ __FUNCTION__,\r
+ Status\r
+ ));\r
+ return Status;\r
+ }\r
+ }\r
+\r
+ return EFI_SUCCESS;\r
+}\r
+\r
/**\r
Turn on/off LED.\r
\r
/**\r
Build ADMA descriptor table for transfer.\r
\r
- Refer to SD Host Controller Simplified spec 3.0 Section 1.13 for details.\r
+ Refer to SD Host Controller Simplified spec 4.2 Section 1.13 for details.\r
\r
@param[in] Trb The pointer to the SD_MMC_HC_TRB instance.\r
+ @param[in] ControllerVer The version of host controller.\r
\r
@retval EFI_SUCCESS The ADMA descriptor table is created successfully.\r
@retval Others The ADMA descriptor table isn't created successfully.\r
**/\r
EFI_STATUS\r
BuildAdmaDescTable (\r
- IN SD_MMC_HC_TRB *Trb\r
+ IN SD_MMC_HC_TRB *Trb,\r
+ IN UINT16 ControllerVer\r
)\r
{\r
EFI_PHYSICAL_ADDRESS Data;\r
UINT64 Entries;\r
UINT32 Index;\r
UINT64 Remaining;\r
- UINT32 Address;\r
+ UINT64 Address;\r
UINTN TableSize;\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
\r
Data = Trb->DataPhy;\r
DataLen = Trb->DataLen;\r
PciIo = Trb->Private->PciIo;\r
+\r
//\r
- // Only support 32bit ADMA Descriptor Table\r
+ // Detect whether 64bit addressing is supported.\r
//\r
- if ((Data >= 0x100000000ul) || ((Data + DataLen) > 0x100000000ul)) {\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
+ ((Data >= 0x100000000ul) || ((Data + DataLen) > 0x100000000ul))) {\r
return EFI_INVALID_PARAMETER;\r
}\r
//\r
- // Address field shall be set on 32-bit boundary (Lower 2-bit is always set to 0)\r
- // for 32-bit address descriptor table.\r
+ // Check address field alignment\r
+ //\r
+ if (AddressingMode64) {\r
+ //\r
+ // Address field shall be set on 64-bit boundary (Lower 3-bit is always set to 0)\r
+ //\r
+ if ((Data & (BIT0 | BIT1 | BIT2)) != 0) {\r
+ DEBUG ((DEBUG_INFO, "The buffer [0x%x] to construct ADMA desc is not aligned to 8 bytes boundary!\n", Data));\r
+ }\r
+ } else {\r
+ //\r
+ // Address field shall be set on 32-bit boundary (Lower 2-bit is always set to 0)\r
+ //\r
+ if ((Data & (BIT0 | BIT1)) != 0) {\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
+ // Detect whether 26bit data length is supported.\r
//\r
- if ((Data & (BIT0 | BIT1)) != 0) {\r
- DEBUG ((DEBUG_INFO, "The buffer [0x%x] to construct ADMA desc is not aligned to 4 bytes boundary!\n", Data));\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
+ AdmaMaxDataPerLine = ADMA_MAX_DATA_PER_LINE_26B;\r
}\r
\r
- Entries = DivU64x32 ((DataLen + ADMA_MAX_DATA_PER_LINE - 1), ADMA_MAX_DATA_PER_LINE);\r
- TableSize = (UINTN)MultU64x32 (Entries, sizeof (SD_MMC_HC_ADMA_DESC_LINE));\r
+ Entries = DivU64x32 ((DataLen + AdmaMaxDataPerLine - 1), AdmaMaxDataPerLine);\r
+ TableSize = (UINTN)MultU64x32 (Entries, DescSize);\r
Trb->AdmaPages = (UINT32)EFI_SIZE_TO_PAGES (TableSize);\r
Status = PciIo->AllocateBuffer (\r
PciIo,\r
AllocateAnyPages,\r
EfiBootServicesData,\r
EFI_SIZE_TO_PAGES (TableSize),\r
- (VOID **)&Trb->AdmaDesc,\r
+ (VOID **)&AdmaDesc,\r
0\r
);\r
if (EFI_ERROR (Status)) {\r
return EFI_OUT_OF_RESOURCES;\r
}\r
- ZeroMem (Trb->AdmaDesc, TableSize);\r
+ ZeroMem (AdmaDesc, TableSize);\r
Bytes = TableSize;\r
Status = PciIo->Map (\r
PciIo,\r
EfiPciIoOperationBusMasterCommonBuffer,\r
- Trb->AdmaDesc,\r
+ AdmaDesc,\r
&Bytes,\r
&Trb->AdmaDescPhy,\r
&Trb->AdmaMap\r
PciIo->FreeBuffer (\r
PciIo,\r
EFI_SIZE_TO_PAGES (TableSize),\r
- Trb->AdmaDesc\r
+ AdmaDesc\r
);\r
return EFI_OUT_OF_RESOURCES;\r
}\r
\r
- if ((UINT64)(UINTN)Trb->AdmaDescPhy > 0x100000000ul) {\r
+ if ((!AddressingMode64) &&\r
+ (UINT64)(UINTN)Trb->AdmaDescPhy > 0x100000000ul) {\r
//\r
// The ADMA doesn't support 64bit addressing.\r
//\r
PciIo->FreeBuffer (\r
PciIo,\r
EFI_SIZE_TO_PAGES (TableSize),\r
- Trb->AdmaDesc\r
+ AdmaDesc\r
);\r
return EFI_DEVICE_ERROR;\r
}\r
\r
Remaining = DataLen;\r
- Address = (UINT32)Data;\r
+ Address = Data;\r
+ if (!AddressingMode64) {\r
+ Trb->Adma32Desc = AdmaDesc;\r
+ Trb->Adma64Desc = NULL;\r
+ } else {\r
+ Trb->Adma64Desc = AdmaDesc;\r
+ Trb->Adma32Desc = NULL;\r
+ }\r
for (Index = 0; Index < Entries; Index++) {\r
- if (Remaining <= ADMA_MAX_DATA_PER_LINE) {\r
- Trb->AdmaDesc[Index].Valid = 1;\r
- Trb->AdmaDesc[Index].Act = 2;\r
- Trb->AdmaDesc[Index].Length = (UINT16)Remaining;\r
- Trb->AdmaDesc[Index].Address = Address;\r
- break;\r
+ if (!AddressingMode64) {\r
+ if (Remaining <= AdmaMaxDataPerLine) {\r
+ Trb->Adma32Desc[Index].Valid = 1;\r
+ Trb->Adma32Desc[Index].Act = 2;\r
+ if (DataLength26) {\r
+ Trb->Adma32Desc[Index].UpperLength = (UINT16)RShiftU64 (Remaining, 16);\r
+ }\r
+ Trb->Adma32Desc[Index].LowerLength = (UINT16)(Remaining & MAX_UINT16);\r
+ Trb->Adma32Desc[Index].Address = (UINT32)Address;\r
+ break;\r
+ } else {\r
+ Trb->Adma32Desc[Index].Valid = 1;\r
+ Trb->Adma32Desc[Index].Act = 2;\r
+ if (DataLength26) {\r
+ Trb->Adma32Desc[Index].UpperLength = 0;\r
+ }\r
+ Trb->Adma32Desc[Index].LowerLength = 0;\r
+ Trb->Adma32Desc[Index].Address = (UINT32)Address;\r
+ }\r
} else {\r
- Trb->AdmaDesc[Index].Valid = 1;\r
- Trb->AdmaDesc[Index].Act = 2;\r
- Trb->AdmaDesc[Index].Length = 0;\r
- Trb->AdmaDesc[Index].Address = Address;\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
+ }\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
+ 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
+ }\r
+ Trb->Adma64Desc[Index].LowerLength = 0;\r
+ Trb->Adma64Desc[Index].LowerAddress = (UINT32)Address;\r
+ Trb->Adma64Desc[Index].UpperAddress = (UINT32)RShiftU64 (Address, 32);\r
+ }\r
}\r
\r
- Remaining -= ADMA_MAX_DATA_PER_LINE;\r
- Address += ADMA_MAX_DATA_PER_LINE;\r
+ Remaining -= AdmaMaxDataPerLine;\r
+ Address += AdmaMaxDataPerLine;\r
}\r
\r
//\r
// Set the last descriptor line as end of descriptor table\r
//\r
- Trb->AdmaDesc[Index].End = 1;\r
+ AddressingMode64 ? (Trb->Adma64Desc[Index].End = 1) : (Trb->Adma32Desc[Index].End = 1);\r
return EFI_SUCCESS;\r
}\r
\r
goto Error;\r
}\r
\r
- if (Trb->DataLen < Trb->BlockSize) {\r
+ if ((Trb->DataLen != 0) && (Trb->DataLen < Trb->BlockSize)) {\r
Trb->BlockSize = (UINT16)Trb->DataLen;\r
}\r
\r
Trb->Mode = SdMmcNoData;\r
} else if (Private->Capability[Slot].Adma2 != 0) {\r
Trb->Mode = SdMmcAdmaMode;\r
- Status = BuildAdmaDescTable (Trb);\r
+ Status = BuildAdmaDescTable (Trb, Private->ControllerVersion[Slot]);\r
if (EFI_ERROR (Status)) {\r
PciIo->Unmap (PciIo, Trb->DataMap);\r
goto Error;\r
Trb->AdmaMap\r
);\r
}\r
- if (Trb->AdmaDesc != NULL) {\r
+ if (Trb->Adma32Desc != NULL) {\r
PciIo->FreeBuffer (\r
PciIo,\r
Trb->AdmaPages,\r
- Trb->AdmaDesc\r
+ Trb->Adma32Desc\r
+ );\r
+ }\r
+ if (Trb->Adma64Desc != NULL) {\r
+ PciIo->FreeBuffer (\r
+ PciIo,\r
+ Trb->AdmaPages,\r
+ Trb->Adma64Desc\r
);\r
}\r
if (Trb->DataMap != NULL) {\r
UINT16 Cmd;\r
UINT16 IntStatus;\r
UINT32 Argument;\r
- UINT16 BlkCount;\r
+ UINT32 BlkCount;\r
UINT16 BlkSize;\r
UINT16 TransMode;\r
UINT8 HostCtrl1;\r
- UINT32 SdmaAddr;\r
+ UINT64 SdmaAddr;\r
UINT64 AdmaAddr;\r
+ BOOLEAN AddressingMode64;\r
+\r
+ AddressingMode64 = FALSE;\r
\r
Packet = Trb->Packet;\r
PciIo = Trb->Private->PciIo;\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 ((UINT64)(UINTN)Trb->DataPhy >= 0x100000000ul) {\r
+ if ((!AddressingMode64) &&\r
+ ((UINT64)(UINTN)Trb->DataPhy >= 0x100000000ul)) {\r
return EFI_INVALID_PARAMETER;\r
}\r
\r
- SdmaAddr = (UINT32)(UINTN)Trb->DataPhy;\r
- Status = SdMmcHcRwMmio (PciIo, Trb->Slot, SD_MMC_HC_SDMA_ADDR, FALSE, sizeof (SdmaAddr), &SdmaAddr);\r
+ SdmaAddr = (UINT64)(UINTN)Trb->DataPhy;\r
+\r
+ if (Private->ControllerVersion[Trb->Slot] >= SD_MMC_HC_CTRL_VER_400) {\r
+ Status = SdMmcHcRwMmio (PciIo, Trb->Slot, SD_MMC_HC_ADMA_SYS_ADDR, FALSE, sizeof (UINT64), &SdmaAddr);\r
+ } else {\r
+ Status = SdMmcHcRwMmio (PciIo, Trb->Slot, SD_MMC_HC_SDMA_ADDR, FALSE, sizeof (UINT32), &SdmaAddr);\r
+ }\r
+\r
if (EFI_ERROR (Status)) {\r
return Status;\r
}\r
//\r
// Calcuate Block Count.\r
//\r
- BlkCount = (UINT16)(Trb->DataLen / Trb->BlockSize);\r
+ BlkCount = (Trb->DataLen / Trb->BlockSize);\r
+ }\r
+ if (Private->ControllerVersion[Trb->Slot] >= SD_MMC_HC_CTRL_VER_410) {\r
+ Status = SdMmcHcRwMmio (PciIo, Trb->Slot, SD_MMC_HC_SDMA_ADDR, FALSE, sizeof (UINT32), &BlkCount);\r
+ } else {\r
+ Status = SdMmcHcRwMmio (PciIo, Trb->Slot, SD_MMC_HC_BLK_COUNT, FALSE, sizeof (UINT16), &BlkCount);\r
}\r
- Status = SdMmcHcRwMmio (PciIo, Trb->Slot, SD_MMC_HC_BLK_COUNT, FALSE, sizeof (BlkCount), &BlkCount);\r
if (EFI_ERROR (Status)) {\r
return Status;\r
}\r
EFI_SD_MMC_PASS_THRU_COMMAND_PACKET *Packet;\r
UINT16 IntStatus;\r
UINT32 Response[4];\r
- UINT32 SdmaAddr;\r
+ UINT64 SdmaAddr;\r
UINT8 Index;\r
UINT8 SwReset;\r
UINT32 PioLength;\r
//\r
// Update SDMA Address register.\r
//\r
- SdmaAddr = SD_MMC_SDMA_ROUND_UP ((UINT32)(UINTN)Trb->DataPhy, SD_MMC_SDMA_BOUNDARY);\r
- Status = SdMmcHcRwMmio (\r
+ SdmaAddr = SD_MMC_SDMA_ROUND_UP ((UINTN)Trb->DataPhy, SD_MMC_SDMA_BOUNDARY);\r
+\r
+ if (Private->ControllerVersion[Trb->Slot] >= SD_MMC_HC_CTRL_VER_400) {\r
+ Status = SdMmcHcRwMmio (\r
+ Private->PciIo,\r
+ Trb->Slot,\r
+ SD_MMC_HC_ADMA_SYS_ADDR,\r
+ FALSE,\r
+ sizeof (UINT64),\r
+ &SdmaAddr\r
+ );\r
+ } else {\r
+ Status = SdMmcHcRwMmio (\r
Private->PciIo,\r
Trb->Slot,\r
SD_MMC_HC_SDMA_ADDR,\r
sizeof (UINT32),\r
&SdmaAddr\r
);\r
+ }\r
+\r
if (EFI_ERROR (Status)) {\r
goto Done;\r
}\r
- Trb->DataPhy = (UINT32)(UINTN)SdmaAddr;\r
+ Trb->DataPhy = (UINT64)(UINTN)SdmaAddr;\r
}\r
\r
if ((Packet->SdMmcCmdBlk->CommandType != SdMmcCommandTypeAdtc) &&\r