X-Git-Url: https://git.proxmox.com/?a=blobdiff_plain;f=MdeModulePkg%2FBus%2FPci%2FSdMmcPciHcDxe%2FSdMmcPciHci.c;h=7971196a253a84339798ec9480166edd8dcd884f;hb=643623147a1feaddd734ddd84604e1d8e9dcebee;hp=d2bd112c14273aafa5966bb72f6c5b132d85bd0c;hpb=48555339beb65f90bd42995a15bd38cd45e378f5;p=mirror_edk2.git
diff --git a/MdeModulePkg/Bus/Pci/SdMmcPciHcDxe/SdMmcPciHci.c b/MdeModulePkg/Bus/Pci/SdMmcPciHcDxe/SdMmcPciHci.c
index d2bd112c14..7971196a25 100644
--- a/MdeModulePkg/Bus/Pci/SdMmcPciHcDxe/SdMmcPciHci.c
+++ b/MdeModulePkg/Bus/Pci/SdMmcPciHcDxe/SdMmcPciHci.c
@@ -1,17 +1,14 @@
/** @file
This driver is used to manage SD/MMC PCI host controllers which are compliance
- with SD Host Controller Simplified Specification version 3.00.
+ with SD Host Controller Simplified Specification version 3.00 plus the 64-bit
+ System Addressing support in SD Host Controller Simplified Specification version
+ 4.20.
It would expose EFI_SD_MMC_PASS_THRU_PROTOCOL for upper layer use.
- Copyright (c) 2015 - 2016, Intel Corporation. All rights reserved.
- This program and the accompanying materials
- are licensed and made available under the terms and conditions of the BSD License
- which accompanies this distribution. The full text of the license may be found at
- http://opensource.org/licenses/bsd-license.php
-
- THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
- WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+ Copyright (c) 2018-2019, NVIDIA CORPORATION. All rights reserved.
+ Copyright (c) 2015 - 2020, Intel Corporation. All rights reserved.
+ SPDX-License-Identifier: BSD-2-Clause-Patent
**/
@@ -33,46 +30,47 @@ DumpCapabilityReg (
//
// Dump Capability Data
//
- DEBUG ((EFI_D_INFO, " == Slot [%d] Capability is 0x%x ==\n", Slot, Capability));
- DEBUG ((EFI_D_INFO, " Timeout Clk Freq %d%a\n", Capability->TimeoutFreq, (Capability->TimeoutUnit) ? "MHz" : "KHz"));
- DEBUG ((EFI_D_INFO, " Base Clk Freq %dMHz\n", Capability->BaseClkFreq));
- DEBUG ((EFI_D_INFO, " Max Blk Len %dbytes\n", 512 * (1 << Capability->MaxBlkLen)));
- DEBUG ((EFI_D_INFO, " 8-bit Support %a\n", Capability->BusWidth8 ? "TRUE" : "FALSE"));
- DEBUG ((EFI_D_INFO, " ADMA2 Support %a\n", Capability->Adma2 ? "TRUE" : "FALSE"));
- DEBUG ((EFI_D_INFO, " HighSpeed Support %a\n", Capability->HighSpeed ? "TRUE" : "FALSE"));
- DEBUG ((EFI_D_INFO, " SDMA Support %a\n", Capability->Sdma ? "TRUE" : "FALSE"));
- DEBUG ((EFI_D_INFO, " Suspend/Resume %a\n", Capability->SuspRes ? "TRUE" : "FALSE"));
- DEBUG ((EFI_D_INFO, " Voltage 3.3 %a\n", Capability->Voltage33 ? "TRUE" : "FALSE"));
- DEBUG ((EFI_D_INFO, " Voltage 3.0 %a\n", Capability->Voltage30 ? "TRUE" : "FALSE"));
- DEBUG ((EFI_D_INFO, " Voltage 1.8 %a\n", Capability->Voltage18 ? "TRUE" : "FALSE"));
- DEBUG ((EFI_D_INFO, " 64-bit Sys Bus %a\n", Capability->SysBus64 ? "TRUE" : "FALSE"));
- DEBUG ((EFI_D_INFO, " Async Interrupt %a\n", Capability->AsyncInt ? "TRUE" : "FALSE"));
- DEBUG ((EFI_D_INFO, " SlotType "));
+ DEBUG ((DEBUG_INFO, " == Slot [%d] Capability is 0x%x ==\n", Slot, Capability));
+ DEBUG ((DEBUG_INFO, " Timeout Clk Freq %d%a\n", Capability->TimeoutFreq, (Capability->TimeoutUnit) ? "MHz" : "KHz"));
+ DEBUG ((DEBUG_INFO, " Base Clk Freq %dMHz\n", Capability->BaseClkFreq));
+ DEBUG ((DEBUG_INFO, " Max Blk Len %dbytes\n", 512 * (1 << Capability->MaxBlkLen)));
+ DEBUG ((DEBUG_INFO, " 8-bit Support %a\n", Capability->BusWidth8 ? "TRUE" : "FALSE"));
+ DEBUG ((DEBUG_INFO, " ADMA2 Support %a\n", Capability->Adma2 ? "TRUE" : "FALSE"));
+ DEBUG ((DEBUG_INFO, " HighSpeed Support %a\n", Capability->HighSpeed ? "TRUE" : "FALSE"));
+ DEBUG ((DEBUG_INFO, " SDMA Support %a\n", Capability->Sdma ? "TRUE" : "FALSE"));
+ DEBUG ((DEBUG_INFO, " Suspend/Resume %a\n", Capability->SuspRes ? "TRUE" : "FALSE"));
+ DEBUG ((DEBUG_INFO, " Voltage 3.3 %a\n", Capability->Voltage33 ? "TRUE" : "FALSE"));
+ DEBUG ((DEBUG_INFO, " Voltage 3.0 %a\n", Capability->Voltage30 ? "TRUE" : "FALSE"));
+ DEBUG ((DEBUG_INFO, " Voltage 1.8 %a\n", Capability->Voltage18 ? "TRUE" : "FALSE"));
+ DEBUG ((DEBUG_INFO, " V4 64-bit Sys Bus %a\n", Capability->SysBus64V4 ? "TRUE" : "FALSE"));
+ DEBUG ((DEBUG_INFO, " V3 64-bit Sys Bus %a\n", Capability->SysBus64V3 ? "TRUE" : "FALSE"));
+ DEBUG ((DEBUG_INFO, " Async Interrupt %a\n", Capability->AsyncInt ? "TRUE" : "FALSE"));
+ DEBUG ((DEBUG_INFO, " SlotType "));
if (Capability->SlotType == 0x00) {
- DEBUG ((EFI_D_INFO, "%a\n", "Removable Slot"));
+ DEBUG ((DEBUG_INFO, "%a\n", "Removable Slot"));
} else if (Capability->SlotType == 0x01) {
- DEBUG ((EFI_D_INFO, "%a\n", "Embedded Slot"));
+ DEBUG ((DEBUG_INFO, "%a\n", "Embedded Slot"));
} else if (Capability->SlotType == 0x02) {
- DEBUG ((EFI_D_INFO, "%a\n", "Shared Bus Slot"));
+ DEBUG ((DEBUG_INFO, "%a\n", "Shared Bus Slot"));
} else {
- DEBUG ((EFI_D_INFO, "%a\n", "Reserved"));
- }
- DEBUG ((EFI_D_INFO, " SDR50 Support %a\n", Capability->Sdr50 ? "TRUE" : "FALSE"));
- DEBUG ((EFI_D_INFO, " SDR104 Support %a\n", Capability->Sdr104 ? "TRUE" : "FALSE"));
- DEBUG ((EFI_D_INFO, " DDR50 Support %a\n", Capability->Ddr50 ? "TRUE" : "FALSE"));
- DEBUG ((EFI_D_INFO, " Driver Type A %a\n", Capability->DriverTypeA ? "TRUE" : "FALSE"));
- DEBUG ((EFI_D_INFO, " Driver Type C %a\n", Capability->DriverTypeC ? "TRUE" : "FALSE"));
- DEBUG ((EFI_D_INFO, " Driver Type D %a\n", Capability->DriverTypeD ? "TRUE" : "FALSE"));
- DEBUG ((EFI_D_INFO, " Driver Type 4 %a\n", Capability->DriverType4 ? "TRUE" : "FALSE"));
+ DEBUG ((DEBUG_INFO, "%a\n", "Reserved"));
+ }
+ DEBUG ((DEBUG_INFO, " SDR50 Support %a\n", Capability->Sdr50 ? "TRUE" : "FALSE"));
+ DEBUG ((DEBUG_INFO, " SDR104 Support %a\n", Capability->Sdr104 ? "TRUE" : "FALSE"));
+ DEBUG ((DEBUG_INFO, " DDR50 Support %a\n", Capability->Ddr50 ? "TRUE" : "FALSE"));
+ DEBUG ((DEBUG_INFO, " Driver Type A %a\n", Capability->DriverTypeA ? "TRUE" : "FALSE"));
+ DEBUG ((DEBUG_INFO, " Driver Type C %a\n", Capability->DriverTypeC ? "TRUE" : "FALSE"));
+ DEBUG ((DEBUG_INFO, " Driver Type D %a\n", Capability->DriverTypeD ? "TRUE" : "FALSE"));
+ DEBUG ((DEBUG_INFO, " Driver Type 4 %a\n", Capability->DriverType4 ? "TRUE" : "FALSE"));
if (Capability->TimerCount == 0) {
- DEBUG ((EFI_D_INFO, " Retuning TimerCnt Disabled\n", 2 * (Capability->TimerCount - 1)));
+ DEBUG ((DEBUG_INFO, " Retuning TimerCnt Disabled\n", 2 * (Capability->TimerCount - 1)));
} else {
- DEBUG ((EFI_D_INFO, " Retuning TimerCnt %dseconds\n", 2 * (Capability->TimerCount - 1)));
+ DEBUG ((DEBUG_INFO, " Retuning TimerCnt %dseconds\n", 2 * (Capability->TimerCount - 1)));
}
- DEBUG ((EFI_D_INFO, " SDR50 Tuning %a\n", Capability->TuningSDR50 ? "TRUE" : "FALSE"));
- DEBUG ((EFI_D_INFO, " Retuning Mode Mode %d\n", Capability->RetuningMod + 1));
- DEBUG ((EFI_D_INFO, " Clock Multiplier M = %d\n", Capability->ClkMultiplier + 1));
- DEBUG ((EFI_D_INFO, " HS 400 %a\n", Capability->Hs400 ? "TRUE" : "FALSE"));
+ DEBUG ((DEBUG_INFO, " SDR50 Tuning %a\n", Capability->TuningSDR50 ? "TRUE" : "FALSE"));
+ DEBUG ((DEBUG_INFO, " Retuning Mode Mode %d\n", Capability->RetuningMod + 1));
+ DEBUG ((DEBUG_INFO, " Clock Multiplier M = %d\n", Capability->ClkMultiplier + 1));
+ DEBUG ((DEBUG_INFO, " HS 400 %a\n", Capability->Hs400 ? "TRUE" : "FALSE"));
return;
}
@@ -150,19 +148,36 @@ SdMmcHcRwMmio (
)
{
EFI_STATUS Status;
+ EFI_PCI_IO_PROTOCOL_WIDTH Width;
if ((PciIo == NULL) || (Data == NULL)) {
return EFI_INVALID_PARAMETER;
}
- if ((Count != 1) && (Count != 2) && (Count != 4) && (Count != 8)) {
- return EFI_INVALID_PARAMETER;
+ switch (Count) {
+ case 1:
+ Width = EfiPciIoWidthUint8;
+ break;
+ case 2:
+ Width = EfiPciIoWidthUint16;
+ Count = 1;
+ break;
+ case 4:
+ Width = EfiPciIoWidthUint32;
+ Count = 1;
+ break;
+ case 8:
+ Width = EfiPciIoWidthUint32;
+ Count = 2;
+ break;
+ default:
+ return EFI_INVALID_PARAMETER;
}
if (Read) {
Status = PciIo->Mem.Read (
PciIo,
- EfiPciIoWidthUint8,
+ Width,
BarIndex,
(UINT64) Offset,
Count,
@@ -171,7 +186,7 @@ SdMmcHcRwMmio (
} else {
Status = PciIo->Mem.Write (
PciIo,
- EfiPciIoWidthUint8,
+ Width,
BarIndex,
(UINT64) Offset,
Count,
@@ -416,10 +431,40 @@ SdMmcHcWaitMmioSet (
return EFI_TIMEOUT;
}
+/**
+ Get the controller version information from the specified slot.
+
+ @param[in] PciIo The PCI IO protocol instance.
+ @param[in] Slot The slot number of the SD card to send the command to.
+ @param[out] Version The buffer to store the version information.
+
+ @retval EFI_SUCCESS The operation executes successfully.
+ @retval Others The operation fails.
+
+**/
+EFI_STATUS
+SdMmcHcGetControllerVersion (
+ IN EFI_PCI_IO_PROTOCOL *PciIo,
+ IN UINT8 Slot,
+ OUT UINT16 *Version
+ )
+{
+ EFI_STATUS Status;
+
+ Status = SdMmcHcRwMmio (PciIo, Slot, SD_MMC_HC_CTRL_VER, TRUE, sizeof (UINT16), Version);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ *Version &= 0xFF;
+
+ return EFI_SUCCESS;
+}
+
/**
Software reset the specified SD/MMC host controller and enable all interrupts.
- @param[in] PciIo The PCI IO protocol instance.
+ @param[in] Private A pointer to the SD_MMC_HC_PRIVATE_DATA instance.
@param[in] Slot The slot number of the SD card to send the command to.
@retval EFI_SUCCESS The software reset executes successfully.
@@ -428,18 +473,38 @@ SdMmcHcWaitMmioSet (
**/
EFI_STATUS
SdMmcHcReset (
- IN EFI_PCI_IO_PROTOCOL *PciIo,
+ IN SD_MMC_HC_PRIVATE_DATA *Private,
IN UINT8 Slot
)
{
EFI_STATUS Status;
UINT8 SwReset;
+ EFI_PCI_IO_PROTOCOL *PciIo;
+
+ //
+ // Notify the SD/MMC override protocol that we are about to reset
+ // the SD/MMC host controller.
+ //
+ if (mOverride != NULL && mOverride->NotifyPhase != NULL) {
+ Status = mOverride->NotifyPhase (
+ Private->ControllerHandle,
+ Slot,
+ EdkiiSdMmcResetPre,
+ NULL);
+ if (EFI_ERROR (Status)) {
+ DEBUG ((DEBUG_WARN,
+ "%a: SD/MMC pre reset notifier callback failed - %r\n",
+ __FUNCTION__, Status));
+ return Status;
+ }
+ }
- SwReset = 0xFF;
- Status = SdMmcHcRwMmio (PciIo, Slot, SD_MMC_HC_SW_RST, FALSE, sizeof (SwReset), &SwReset);
+ PciIo = Private->PciIo;
+ SwReset = BIT0;
+ Status = SdMmcHcOrMmio (PciIo, Slot, SD_MMC_HC_SW_RST, sizeof (SwReset), &SwReset);
if (EFI_ERROR (Status)) {
- DEBUG ((EFI_D_ERROR, "SdMmcHcReset: write full 1 fails: %r\n", Status));
+ DEBUG ((DEBUG_ERROR, "SdMmcHcReset: write SW Reset for All fails: %r\n", Status));
return Status;
}
@@ -448,18 +513,41 @@ SdMmcHcReset (
Slot,
SD_MMC_HC_SW_RST,
sizeof (SwReset),
- 0xFF,
+ BIT0,
0x00,
SD_MMC_HC_GENERIC_TIMEOUT
);
if (EFI_ERROR (Status)) {
- DEBUG ((EFI_D_INFO, "SdMmcHcReset: reset done with %r\n", Status));
+ DEBUG ((DEBUG_INFO, "SdMmcHcReset: reset done with %r\n", Status));
return Status;
}
+
//
// Enable all interrupt after reset all.
//
Status = SdMmcHcEnableInterrupt (PciIo, Slot);
+ if (EFI_ERROR (Status)) {
+ DEBUG ((DEBUG_INFO, "SdMmcHcReset: SdMmcHcEnableInterrupt done with %r\n",
+ Status));
+ return Status;
+ }
+
+ //
+ // Notify the SD/MMC override protocol that we have just reset
+ // the SD/MMC host controller.
+ //
+ if (mOverride != NULL && mOverride->NotifyPhase != NULL) {
+ Status = mOverride->NotifyPhase (
+ Private->ControllerHandle,
+ Slot,
+ EdkiiSdMmcResetPost,
+ NULL);
+ if (EFI_ERROR (Status)) {
+ DEBUG ((DEBUG_WARN,
+ "%a: SD/MMC post reset notifier callback failed - %r\n",
+ __FUNCTION__, Status));
+ }
+ }
return Status;
}
@@ -583,6 +671,20 @@ SdMmcHcCardDetect (
UINT16 Data;
UINT32 PresentState;
+ //
+ // Check Present State Register to see if there is a card presented.
+ //
+ Status = SdMmcHcRwMmio (PciIo, Slot, SD_MMC_HC_PRESENT_STATE, TRUE, sizeof (PresentState), &PresentState);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ if ((PresentState & BIT16) != 0) {
+ *MediaPresent = TRUE;
+ } else {
+ *MediaPresent = FALSE;
+ }
+
//
// Check Normal Interrupt Status Register
//
@@ -601,19 +703,6 @@ SdMmcHcCardDetect (
return Status;
}
- //
- // Check Present State Register to see if there is a card presented.
- //
- Status = SdMmcHcRwMmio (PciIo, Slot, SD_MMC_HC_PRESENT_STATE, TRUE, sizeof (PresentState), &PresentState);
- if (EFI_ERROR (Status)) {
- return Status;
- }
-
- if ((PresentState & BIT16) != 0) {
- *MediaPresent = TRUE;
- } else {
- *MediaPresent = FALSE;
- }
return EFI_MEDIA_CHANGED;
}
@@ -669,15 +758,40 @@ SdMmcHcStopClock (
return Status;
}
+/**
+ Start the SD clock.
+
+ @param[in] PciIo The PCI IO protocol instance.
+ @param[in] Slot The slot number.
+
+ @retval EFI_SUCCESS Succeeded to start the SD clock.
+ @retval Others Failed to start the SD clock.
+**/
+EFI_STATUS
+SdMmcHcStartSdClock (
+ IN EFI_PCI_IO_PROTOCOL *PciIo,
+ IN UINT8 Slot
+ )
+{
+ UINT16 ClockCtrl;
+
+ //
+ // Set SD Clock Enable in the Clock Control register to 1
+ //
+ ClockCtrl = BIT2;
+ return SdMmcHcOrMmio (PciIo, Slot, SD_MMC_HC_CLOCK_CTRL, sizeof (ClockCtrl), &ClockCtrl);
+}
+
/**
SD/MMC card clock supply.
Refer to SD Host Controller Simplified spec 3.0 Section 3.2.1 for details.
- @param[in] PciIo The PCI IO protocol instance.
- @param[in] Slot The slot number of the SD card to send the command to.
- @param[in] ClockFreq The max clock frequency to be set. The unit is KHz.
- @param[in] Capability The capability of the slot.
+ @param[in] Private A pointer to the SD_MMC_HC_PRIVATE_DATA instance.
+ @param[in] Slot The slot number of the SD card to send the command to.
+ @param[in] BusTiming BusTiming at which the frequency change is done.
+ @param[in] FirstTimeSetup Flag to indicate whether the clock is being setup for the first time.
+ @param[in] ClockFreq The max clock frequency to be set. The unit is KHz.
@retval EFI_SUCCESS The clock is supplied successfully.
@retval Others The clock isn't supplied successfully.
@@ -685,29 +799,34 @@ SdMmcHcStopClock (
**/
EFI_STATUS
SdMmcHcClockSupply (
- IN EFI_PCI_IO_PROTOCOL *PciIo,
- IN UINT8 Slot,
- IN UINT64 ClockFreq,
- IN SD_MMC_HC_SLOT_CAP Capability
+ IN SD_MMC_HC_PRIVATE_DATA *Private,
+ IN UINT8 Slot,
+ IN SD_MMC_BUS_MODE BusTiming,
+ IN BOOLEAN FirstTimeSetup,
+ IN UINT64 ClockFreq
)
{
EFI_STATUS Status;
- UINT32 BaseClkFreq;
UINT32 SettingFreq;
UINT32 Divisor;
UINT32 Remainder;
- UINT16 ControllerVer;
UINT16 ClockCtrl;
+ UINT32 BaseClkFreq;
+ UINT16 ControllerVer;
+ EFI_PCI_IO_PROTOCOL *PciIo;
- //
- // Calculate a divisor for SD clock frequency
- //
- ASSERT (Capability.BaseClkFreq != 0);
+ PciIo = Private->PciIo;
+ BaseClkFreq = Private->BaseClkFreq[Slot];
+ ControllerVer = Private->ControllerVersion[Slot];
- BaseClkFreq = Capability.BaseClkFreq;
- if ((ClockFreq > (BaseClkFreq * 1000)) || (ClockFreq == 0)) {
+ if (BaseClkFreq == 0 || ClockFreq == 0) {
return EFI_INVALID_PARAMETER;
}
+
+ if (ClockFreq > (BaseClkFreq * 1000)) {
+ ClockFreq = BaseClkFreq * 1000;
+ }
+
//
// Calculate the divisor of base frequency.
//
@@ -726,19 +845,17 @@ SdMmcHcClockSupply (
}
}
- DEBUG ((EFI_D_INFO, "BaseClkFreq %dMHz Divisor %d ClockFreq %dKhz\n", BaseClkFreq, Divisor, ClockFreq));
+ DEBUG ((DEBUG_INFO, "BaseClkFreq %dMHz Divisor %d ClockFreq %dKhz\n", BaseClkFreq, Divisor, ClockFreq));
- Status = SdMmcHcRwMmio (PciIo, Slot, SD_MMC_HC_CTRL_VER, TRUE, sizeof (ControllerVer), &ControllerVer);
- if (EFI_ERROR (Status)) {
- return Status;
- }
//
// Set SDCLK Frequency Select and Internal Clock Enable fields in Clock Control register.
//
- if ((ControllerVer & 0xFF) == 2) {
+ if ((ControllerVer >= SD_MMC_HC_CTRL_VER_300) &&
+ (ControllerVer <= SD_MMC_HC_CTRL_VER_420)) {
ASSERT (Divisor <= 0x3FF);
ClockCtrl = ((Divisor & 0xFF) << 8) | ((Divisor & 0x300) >> 2);
- } else if (((ControllerVer & 0xFF) == 0) || ((ControllerVer & 0xFF) == 1)) {
+ } else if ((ControllerVer == SD_MMC_HC_CTRL_VER_100) ||
+ (ControllerVer == SD_MMC_HC_CTRL_VER_200)) {
//
// Only the most significant bit can be used as divisor.
//
@@ -748,7 +865,7 @@ SdMmcHcClockSupply (
ASSERT (Divisor <= 0x80);
ClockCtrl = (Divisor & 0xFF) << 8;
} else {
- DEBUG ((EFI_D_ERROR, "Unknown SD Host Controller Spec version [0x%x]!!!\n", ControllerVer));
+ DEBUG ((DEBUG_ERROR, "Unknown SD Host Controller Spec version [0x%x]!!!\n", ControllerVer));
return EFI_UNSUPPORTED;
}
@@ -766,7 +883,7 @@ SdMmcHcClockSupply (
ClockCtrl |= BIT0;
Status = SdMmcHcRwMmio (PciIo, Slot, SD_MMC_HC_CLOCK_CTRL, FALSE, sizeof (ClockCtrl), &ClockCtrl);
if (EFI_ERROR (Status)) {
- DEBUG ((EFI_D_ERROR, "Set SDCLK Frequency Select and Internal Clock Enable fields fails\n"));
+ DEBUG ((DEBUG_ERROR, "Set SDCLK Frequency Select and Internal Clock Enable fields fails\n"));
return Status;
}
@@ -786,11 +903,35 @@ SdMmcHcClockSupply (
return Status;
}
+ Status = SdMmcHcStartSdClock (PciIo, Slot);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
//
- // Set SD Clock Enable in the Clock Control register to 1
+ // We don't notify the platform on first time setup to avoid changing
+ // legacy behavior. During first time setup we also don't know what type
+ // of the card slot it is and which enum value of BusTiming applies.
//
- ClockCtrl = BIT2;
- Status = SdMmcHcOrMmio (PciIo, Slot, SD_MMC_HC_CLOCK_CTRL, sizeof (ClockCtrl), &ClockCtrl);
+ if (!FirstTimeSetup && mOverride != NULL && mOverride->NotifyPhase != NULL) {
+ Status = mOverride->NotifyPhase (
+ Private->ControllerHandle,
+ Slot,
+ EdkiiSdMmcSwitchClockFreqPost,
+ &BusTiming
+ );
+ if (EFI_ERROR (Status)) {
+ DEBUG ((
+ DEBUG_ERROR,
+ "%a: SD/MMC switch clock freq post notifier callback failed - %r\n",
+ __FUNCTION__,
+ Status
+ ));
+ return Status;
+ }
+ }
+
+ Private->Slot[Slot].CurrentFreq = ClockFreq;
return Status;
}
@@ -886,41 +1027,65 @@ SdMmcHcSetBusWidth (
}
/**
- Supply SD/MMC card with lowest clock frequency at initialization.
+ Configure V4 controller enhancements at initialization.
@param[in] PciIo The PCI IO protocol instance.
@param[in] Slot The slot number of the SD card to send the command to.
@param[in] Capability The capability of the slot.
+ @param[in] ControllerVer The version of host controller.
@retval EFI_SUCCESS The clock is supplied successfully.
- @retval Others The clock isn't supplied successfully.
**/
EFI_STATUS
-SdMmcHcInitClockFreq (
+SdMmcHcInitV4Enhancements (
IN EFI_PCI_IO_PROTOCOL *PciIo,
IN UINT8 Slot,
- IN SD_MMC_HC_SLOT_CAP Capability
+ IN SD_MMC_HC_SLOT_CAP Capability,
+ IN UINT16 ControllerVer
)
{
EFI_STATUS Status;
- UINT32 InitFreq;
+ UINT16 HostCtrl2;
//
- // Calculate a divisor for SD clock frequency
+ // Check if controller version V4 or higher
//
- if (Capability.BaseClkFreq == 0) {
+ if (ControllerVer >= SD_MMC_HC_CTRL_VER_400) {
+ HostCtrl2 = SD_MMC_HC_V4_EN;
//
- // Don't support get Base Clock Frequency information via another method
+ // Check if controller version V4.0
//
- return EFI_UNSUPPORTED;
+ if (ControllerVer == SD_MMC_HC_CTRL_VER_400) {
+ //
+ // Check if 64bit support is available
+ //
+ if (Capability.SysBus64V3 != 0) {
+ HostCtrl2 |= SD_MMC_HC_64_ADDR_EN;
+ DEBUG ((DEBUG_INFO, "Enabled V4 64 bit system bus support\n"));
+ }
+ }
+ //
+ // Check if controller version V4.10 or higher
+ //
+ else if (ControllerVer >= SD_MMC_HC_CTRL_VER_410) {
+ //
+ // Check if 64bit support is available
+ //
+ if (Capability.SysBus64V4 != 0) {
+ HostCtrl2 |= SD_MMC_HC_64_ADDR_EN;
+ DEBUG ((DEBUG_INFO, "Enabled V4 64 bit system bus support\n"));
+ }
+ HostCtrl2 |= SD_MMC_HC_26_DATA_LEN_ADMA_EN;
+ DEBUG ((DEBUG_INFO, "Enabled V4 26 bit data length ADMA support\n"));
+ }
+ Status = SdMmcHcOrMmio (PciIo, Slot, SD_MMC_HC_HOST_CTRL2, sizeof (HostCtrl2), &HostCtrl2);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
}
- //
- // Supply 400KHz clock frequency at initialization phase.
- //
- InitFreq = 400;
- Status = SdMmcHcClockSupply (PciIo, Slot, InitFreq, Capability);
- return Status;
+
+ return EFI_SUCCESS;
}
/**
@@ -1015,9 +1180,8 @@ SdMmcHcInitTimeoutCtrl (
Initial SD/MMC host controller with lowest clock frequency, max power and max timeout value
at initialization.
- @param[in] PciIo The PCI IO protocol instance.
+ @param[in] Private A pointer to the SD_MMC_HC_PRIVATE_DATA instance.
@param[in] Slot The slot number of the SD card to send the command to.
- @param[in] Capability The capability of the slot.
@retval EFI_SUCCESS The host controller is initialized successfully.
@retval Others The host controller isn't initialized successfully.
@@ -1025,14 +1189,48 @@ SdMmcHcInitTimeoutCtrl (
**/
EFI_STATUS
SdMmcHcInitHost (
- IN EFI_PCI_IO_PROTOCOL *PciIo,
- IN UINT8 Slot,
- IN SD_MMC_HC_SLOT_CAP Capability
+ IN SD_MMC_HC_PRIVATE_DATA *Private,
+ IN UINT8 Slot
)
{
- EFI_STATUS Status;
+ EFI_STATUS Status;
+ EFI_PCI_IO_PROTOCOL *PciIo;
+ SD_MMC_HC_SLOT_CAP Capability;
- Status = SdMmcHcInitClockFreq (PciIo, Slot, Capability);
+ //
+ // Notify the SD/MMC override protocol that we are about to initialize
+ // the SD/MMC host controller.
+ //
+ if (mOverride != NULL && mOverride->NotifyPhase != NULL) {
+ Status = mOverride->NotifyPhase (
+ Private->ControllerHandle,
+ Slot,
+ EdkiiSdMmcInitHostPre,
+ NULL);
+ if (EFI_ERROR (Status)) {
+ DEBUG ((DEBUG_WARN,
+ "%a: SD/MMC pre init notifier callback failed - %r\n",
+ __FUNCTION__, Status));
+ return Status;
+ }
+ }
+
+ PciIo = Private->PciIo;
+ Capability = Private->Capability[Slot];
+
+ Status = SdMmcHcInitV4Enhancements (PciIo, Slot, Capability, Private->ControllerVersion[Slot]);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ //
+ // Perform first time clock setup with 400 KHz frequency.
+ // We send the 0 as the BusTiming value because at this time
+ // we still do not know the slot type and which enum value will apply.
+ // Since it is a first time setup SdMmcHcClockSupply won't notify
+ // the platofrm driver anyway so it doesn't matter.
+ //
+ Status = SdMmcHcClockSupply (Private, Slot, 0, TRUE, 400);
if (EFI_ERROR (Status)) {
return Status;
}
@@ -1043,9 +1241,152 @@ SdMmcHcInitHost (
}
Status = SdMmcHcInitTimeoutCtrl (PciIo, Slot);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ //
+ // Notify the SD/MMC override protocol that we are have just initialized
+ // the SD/MMC host controller.
+ //
+ if (mOverride != NULL && mOverride->NotifyPhase != NULL) {
+ Status = mOverride->NotifyPhase (
+ Private->ControllerHandle,
+ Slot,
+ EdkiiSdMmcInitHostPost,
+ NULL);
+ if (EFI_ERROR (Status)) {
+ DEBUG ((DEBUG_WARN,
+ "%a: SD/MMC post init notifier callback failed - %r\n",
+ __FUNCTION__, Status));
+ }
+ }
return Status;
}
+/**
+ Set SD Host Controler control 2 registry according to selected speed.
+
+ @param[in] ControllerHandle The handle of the controller.
+ @param[in] PciIo The PCI IO protocol instance.
+ @param[in] Slot The slot number of the SD card to send the command to.
+ @param[in] Timing The timing to select.
+
+ @retval EFI_SUCCESS The timing is set successfully.
+ @retval Others The timing isn't set successfully.
+**/
+EFI_STATUS
+SdMmcHcUhsSignaling (
+ IN EFI_HANDLE ControllerHandle,
+ IN EFI_PCI_IO_PROTOCOL *PciIo,
+ IN UINT8 Slot,
+ IN SD_MMC_BUS_MODE Timing
+ )
+{
+ EFI_STATUS Status;
+ UINT8 HostCtrl2;
+
+ HostCtrl2 = (UINT8)~SD_MMC_HC_CTRL_UHS_MASK;
+ Status = SdMmcHcAndMmio (PciIo, Slot, SD_MMC_HC_HOST_CTRL2, sizeof (HostCtrl2), &HostCtrl2);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ switch (Timing) {
+ case SdMmcUhsSdr12:
+ HostCtrl2 = SD_MMC_HC_CTRL_UHS_SDR12;
+ break;
+ case SdMmcUhsSdr25:
+ HostCtrl2 = SD_MMC_HC_CTRL_UHS_SDR25;
+ break;
+ case SdMmcUhsSdr50:
+ HostCtrl2 = SD_MMC_HC_CTRL_UHS_SDR50;
+ break;
+ case SdMmcUhsSdr104:
+ HostCtrl2 = SD_MMC_HC_CTRL_UHS_SDR104;
+ break;
+ case SdMmcUhsDdr50:
+ HostCtrl2 = SD_MMC_HC_CTRL_UHS_DDR50;
+ break;
+ case SdMmcMmcLegacy:
+ HostCtrl2 = SD_MMC_HC_CTRL_MMC_LEGACY;
+ break;
+ case SdMmcMmcHsSdr:
+ HostCtrl2 = SD_MMC_HC_CTRL_MMC_HS_SDR;
+ break;
+ case SdMmcMmcHsDdr:
+ HostCtrl2 = SD_MMC_HC_CTRL_MMC_HS_DDR;
+ break;
+ case SdMmcMmcHs200:
+ HostCtrl2 = SD_MMC_HC_CTRL_MMC_HS200;
+ break;
+ case SdMmcMmcHs400:
+ HostCtrl2 = SD_MMC_HC_CTRL_MMC_HS400;
+ break;
+ default:
+ HostCtrl2 = 0;
+ break;
+ }
+ Status = SdMmcHcOrMmio (PciIo, Slot, SD_MMC_HC_HOST_CTRL2, sizeof (HostCtrl2), &HostCtrl2);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ if (mOverride != NULL && mOverride->NotifyPhase != NULL) {
+ Status = mOverride->NotifyPhase (
+ ControllerHandle,
+ Slot,
+ EdkiiSdMmcUhsSignaling,
+ &Timing
+ );
+ if (EFI_ERROR (Status)) {
+ DEBUG ((
+ DEBUG_ERROR,
+ "%a: SD/MMC uhs signaling notifier callback failed - %r\n",
+ __FUNCTION__,
+ Status
+ ));
+ return Status;
+ }
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Set driver strength in host controller.
+
+ @param[in] PciIo The PCI IO protocol instance.
+ @param[in] SlotIndex The slot index of the card.
+ @param[in] DriverStrength DriverStrength to set in the controller.
+
+ @retval EFI_SUCCESS Driver strength programmed successfully.
+ @retval Others Failed to set driver strength.
+**/
+EFI_STATUS
+SdMmcSetDriverStrength (
+ IN EFI_PCI_IO_PROTOCOL *PciIo,
+ IN UINT8 SlotIndex,
+ IN SD_DRIVER_STRENGTH_TYPE DriverStrength
+ )
+{
+ EFI_STATUS Status;
+ UINT16 HostCtrl2;
+
+ if (DriverStrength == SdDriverStrengthIgnore) {
+ return EFI_SUCCESS;
+ }
+
+ HostCtrl2 = (UINT16)~SD_MMC_HC_CTRL_DRIVER_STRENGTH_MASK;
+ Status = SdMmcHcAndMmio (PciIo, SlotIndex, SD_MMC_HC_HOST_CTRL2, sizeof (HostCtrl2), &HostCtrl2);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ HostCtrl2 = (DriverStrength << 4) & SD_MMC_HC_CTRL_DRIVER_STRENGTH_MASK;
+ return SdMmcHcOrMmio (PciIo, SlotIndex, SD_MMC_HC_HOST_CTRL2, sizeof (HostCtrl2), &HostCtrl2);
+}
+
/**
Turn on/off LED.
@@ -1081,9 +1422,10 @@ SdMmcHcLedOnOff (
/**
Build ADMA descriptor table for transfer.
- Refer to SD Host Controller Simplified spec 3.0 Section 1.13 for details.
+ Refer to SD Host Controller Simplified spec 4.2 Section 1.13 for details.
@param[in] Trb The pointer to the SD_MMC_HC_TRB instance.
+ @param[in] ControllerVer The version of host controller.
@retval EFI_SUCCESS The ADMA descriptor table is created successfully.
@retval Others The ADMA descriptor table isn't created successfully.
@@ -1091,7 +1433,8 @@ SdMmcHcLedOnOff (
**/
EFI_STATUS
BuildAdmaDescTable (
- IN SD_MMC_HC_TRB *Trb
+ IN SD_MMC_HC_TRB *Trb,
+ IN UINT16 ControllerVer
)
{
EFI_PHYSICAL_ADDRESS Data;
@@ -1099,49 +1442,84 @@ BuildAdmaDescTable (
UINT64 Entries;
UINT32 Index;
UINT64 Remaining;
- UINT32 Address;
+ UINT64 Address;
UINTN TableSize;
EFI_PCI_IO_PROTOCOL *PciIo;
EFI_STATUS Status;
UINTN Bytes;
+ UINT32 AdmaMaxDataPerLine;
+ UINT32 DescSize;
+ VOID *AdmaDesc;
+
+ AdmaMaxDataPerLine = ADMA_MAX_DATA_PER_LINE_16B;
+ DescSize = sizeof (SD_MMC_HC_ADMA_32_DESC_LINE);
+ AdmaDesc = NULL;
Data = Trb->DataPhy;
DataLen = Trb->DataLen;
PciIo = Trb->Private->PciIo;
+
//
- // Only support 32bit ADMA Descriptor Table
+ // Check for valid ranges in 32bit ADMA Descriptor Table
//
- if ((Data >= 0x100000000ul) || ((Data + DataLen) > 0x100000000ul)) {
+ if ((Trb->Mode == SdMmcAdma32bMode) &&
+ ((Data >= 0x100000000ul) || ((Data + DataLen) > 0x100000000ul))) {
return EFI_INVALID_PARAMETER;
}
//
- // Address field shall be set on 32-bit boundary (Lower 2-bit is always set to 0)
- // for 32-bit address descriptor table.
+ // Check address field alignment
+ //
+ if (Trb->Mode != SdMmcAdma32bMode) {
+ //
+ // Address field shall be set on 64-bit boundary (Lower 3-bit is always set to 0)
+ //
+ if ((Data & (BIT0 | BIT1 | BIT2)) != 0) {
+ DEBUG ((DEBUG_INFO, "The buffer [0x%x] to construct ADMA desc is not aligned to 8 bytes boundary!\n", Data));
+ }
+ } else {
+ //
+ // Address field shall be set on 32-bit boundary (Lower 2-bit is always set to 0)
+ //
+ if ((Data & (BIT0 | BIT1)) != 0) {
+ DEBUG ((DEBUG_INFO, "The buffer [0x%x] to construct ADMA desc is not aligned to 4 bytes boundary!\n", Data));
+ }
+ }
+
+ //
+ // Configure 64b ADMA.
+ //
+ if (Trb->Mode == SdMmcAdma64bV3Mode) {
+ DescSize = sizeof (SD_MMC_HC_ADMA_64_V3_DESC_LINE);
+ }else if (Trb->Mode == SdMmcAdma64bV4Mode) {
+ DescSize = sizeof (SD_MMC_HC_ADMA_64_V4_DESC_LINE);
+ }
+ //
+ // Configure 26b data length.
//
- if ((Data & (BIT0 | BIT1)) != 0) {
- DEBUG ((EFI_D_INFO, "The buffer [0x%x] to construct ADMA desc is not aligned to 4 bytes boundary!\n", Data));
+ if (Trb->AdmaLengthMode == SdMmcAdmaLen26b) {
+ AdmaMaxDataPerLine = ADMA_MAX_DATA_PER_LINE_26B;
}
- Entries = DivU64x32 ((DataLen + ADMA_MAX_DATA_PER_LINE - 1), ADMA_MAX_DATA_PER_LINE);
- TableSize = (UINTN)MultU64x32 (Entries, sizeof (SD_MMC_HC_ADMA_DESC_LINE));
+ Entries = DivU64x32 ((DataLen + AdmaMaxDataPerLine - 1), AdmaMaxDataPerLine);
+ TableSize = (UINTN)MultU64x32 (Entries, DescSize);
Trb->AdmaPages = (UINT32)EFI_SIZE_TO_PAGES (TableSize);
Status = PciIo->AllocateBuffer (
PciIo,
AllocateAnyPages,
EfiBootServicesData,
EFI_SIZE_TO_PAGES (TableSize),
- (VOID **)&Trb->AdmaDesc,
+ (VOID **)&AdmaDesc,
0
);
if (EFI_ERROR (Status)) {
return EFI_OUT_OF_RESOURCES;
}
- ZeroMem (Trb->AdmaDesc, TableSize);
+ ZeroMem (AdmaDesc, TableSize);
Bytes = TableSize;
Status = PciIo->Map (
PciIo,
EfiPciIoOperationBusMasterCommonBuffer,
- Trb->AdmaDesc,
+ AdmaDesc,
&Bytes,
&Trb->AdmaDescPhy,
&Trb->AdmaMap
@@ -1154,12 +1532,13 @@ BuildAdmaDescTable (
PciIo->FreeBuffer (
PciIo,
EFI_SIZE_TO_PAGES (TableSize),
- Trb->AdmaDesc
+ AdmaDesc
);
return EFI_OUT_OF_RESOURCES;
}
- if ((UINT64)(UINTN)Trb->AdmaDescPhy > 0x100000000ul) {
+ if ((Trb->Mode == SdMmcAdma32bMode) &&
+ (UINT64)(UINTN)Trb->AdmaDescPhy > 0x100000000ul) {
//
// The ADMA doesn't support 64bit addressing.
//
@@ -1167,38 +1546,104 @@ BuildAdmaDescTable (
PciIo,
Trb->AdmaMap
);
+ Trb->AdmaMap = NULL;
+
PciIo->FreeBuffer (
PciIo,
EFI_SIZE_TO_PAGES (TableSize),
- Trb->AdmaDesc
+ AdmaDesc
);
return EFI_DEVICE_ERROR;
}
Remaining = DataLen;
- Address = (UINT32)Data;
+ Address = Data;
+ if (Trb->Mode == SdMmcAdma32bMode) {
+ Trb->Adma32Desc = AdmaDesc;
+ } else if (Trb->Mode == SdMmcAdma64bV3Mode) {
+ Trb->Adma64V3Desc = AdmaDesc;
+ } else {
+ Trb->Adma64V4Desc = AdmaDesc;
+ }
+
for (Index = 0; Index < Entries; Index++) {
- if (Remaining <= ADMA_MAX_DATA_PER_LINE) {
- Trb->AdmaDesc[Index].Valid = 1;
- Trb->AdmaDesc[Index].Act = 2;
- Trb->AdmaDesc[Index].Length = (UINT16)Remaining;
- Trb->AdmaDesc[Index].Address = Address;
- break;
+ if (Trb->Mode == SdMmcAdma32bMode) {
+ if (Remaining <= AdmaMaxDataPerLine) {
+ Trb->Adma32Desc[Index].Valid = 1;
+ Trb->Adma32Desc[Index].Act = 2;
+ if (Trb->AdmaLengthMode == SdMmcAdmaLen26b) {
+ Trb->Adma32Desc[Index].UpperLength = (UINT16)RShiftU64 (Remaining, 16);
+ }
+ Trb->Adma32Desc[Index].LowerLength = (UINT16)(Remaining & MAX_UINT16);
+ Trb->Adma32Desc[Index].Address = (UINT32)Address;
+ break;
+ } else {
+ Trb->Adma32Desc[Index].Valid = 1;
+ Trb->Adma32Desc[Index].Act = 2;
+ if (Trb->AdmaLengthMode == SdMmcAdmaLen26b) {
+ Trb->Adma32Desc[Index].UpperLength = 0;
+ }
+ Trb->Adma32Desc[Index].LowerLength = 0;
+ Trb->Adma32Desc[Index].Address = (UINT32)Address;
+ }
+ } else if (Trb->Mode == SdMmcAdma64bV3Mode) {
+ if (Remaining <= AdmaMaxDataPerLine) {
+ Trb->Adma64V3Desc[Index].Valid = 1;
+ Trb->Adma64V3Desc[Index].Act = 2;
+ if (Trb->AdmaLengthMode == SdMmcAdmaLen26b) {
+ Trb->Adma64V3Desc[Index].UpperLength = (UINT16)RShiftU64 (Remaining, 16);
+ }
+ Trb->Adma64V3Desc[Index].LowerLength = (UINT16)(Remaining & MAX_UINT16);
+ Trb->Adma64V3Desc[Index].LowerAddress = (UINT32)Address;
+ Trb->Adma64V3Desc[Index].UpperAddress = (UINT32)RShiftU64 (Address, 32);
+ break;
+ } else {
+ Trb->Adma64V3Desc[Index].Valid = 1;
+ Trb->Adma64V3Desc[Index].Act = 2;
+ if (Trb->AdmaLengthMode == SdMmcAdmaLen26b) {
+ Trb->Adma64V3Desc[Index].UpperLength = 0;
+ }
+ Trb->Adma64V3Desc[Index].LowerLength = 0;
+ Trb->Adma64V3Desc[Index].LowerAddress = (UINT32)Address;
+ Trb->Adma64V3Desc[Index].UpperAddress = (UINT32)RShiftU64 (Address, 32);
+ }
} else {
- Trb->AdmaDesc[Index].Valid = 1;
- Trb->AdmaDesc[Index].Act = 2;
- Trb->AdmaDesc[Index].Length = 0;
- Trb->AdmaDesc[Index].Address = Address;
+ if (Remaining <= AdmaMaxDataPerLine) {
+ Trb->Adma64V4Desc[Index].Valid = 1;
+ Trb->Adma64V4Desc[Index].Act = 2;
+ if (Trb->AdmaLengthMode == SdMmcAdmaLen26b) {
+ Trb->Adma64V4Desc[Index].UpperLength = (UINT16)RShiftU64 (Remaining, 16);
+ }
+ Trb->Adma64V4Desc[Index].LowerLength = (UINT16)(Remaining & MAX_UINT16);
+ Trb->Adma64V4Desc[Index].LowerAddress = (UINT32)Address;
+ Trb->Adma64V4Desc[Index].UpperAddress = (UINT32)RShiftU64 (Address, 32);
+ break;
+ } else {
+ Trb->Adma64V4Desc[Index].Valid = 1;
+ Trb->Adma64V4Desc[Index].Act = 2;
+ if (Trb->AdmaLengthMode == SdMmcAdmaLen26b) {
+ Trb->Adma64V4Desc[Index].UpperLength = 0;
+ }
+ Trb->Adma64V4Desc[Index].LowerLength = 0;
+ Trb->Adma64V4Desc[Index].LowerAddress = (UINT32)Address;
+ Trb->Adma64V4Desc[Index].UpperAddress = (UINT32)RShiftU64 (Address, 32);
+ }
}
- Remaining -= ADMA_MAX_DATA_PER_LINE;
- Address += ADMA_MAX_DATA_PER_LINE;
+ Remaining -= AdmaMaxDataPerLine;
+ Address += AdmaMaxDataPerLine;
}
//
// Set the last descriptor line as end of descriptor table
//
- Trb->AdmaDesc[Index].End = 1;
+ if (Trb->Mode == SdMmcAdma32bMode) {
+ Trb->Adma32Desc[Index].End = 1;
+ } else if (Trb->Mode == SdMmcAdma64bV3Mode) {
+ Trb->Adma64V3Desc[Index].End = 1;
+ } else {
+ Trb->Adma64V4Desc[Index].End = 1;
+ }
return EFI_SUCCESS;
}
@@ -1242,6 +1687,7 @@ SdMmcCreateTrb (
Trb->Event = Event;
Trb->Started = FALSE;
Trb->Timeout = Packet->Timeout;
+ Trb->Retries = SD_MMC_TRB_RETRIES;
Trb->Private = Private;
if ((Packet->InTransferLength != 0) && (Packet->InDataBuffer != NULL)) {
@@ -1259,52 +1705,69 @@ SdMmcCreateTrb (
goto Error;
}
- if (Trb->Read) {
- Flag = EfiPciIoOperationBusMasterWrite;
- } else {
- Flag = EfiPciIoOperationBusMasterRead;
+ if ((Trb->DataLen != 0) && (Trb->DataLen < Trb->BlockSize)) {
+ Trb->BlockSize = (UINT16)Trb->DataLen;
}
- PciIo = Private->PciIo;
- if (Trb->DataLen != 0) {
- MapLength = Trb->DataLen;
- Status = PciIo->Map (
- PciIo,
- Flag,
- Trb->Data,
- &MapLength,
- &Trb->DataPhy,
- &Trb->DataMap
- );
- if (EFI_ERROR (Status) || (Trb->DataLen != MapLength)) {
- Status = EFI_BAD_BUFFER_SIZE;
- goto Error;
+ if (((Private->Slot[Trb->Slot].CardType == EmmcCardType) &&
+ (Packet->SdMmcCmdBlk->CommandIndex == EMMC_SEND_TUNING_BLOCK)) ||
+ ((Private->Slot[Trb->Slot].CardType == SdCardType) &&
+ (Packet->SdMmcCmdBlk->CommandIndex == SD_SEND_TUNING_BLOCK))) {
+ Trb->Mode = SdMmcPioMode;
+ } else {
+ if (Trb->Read) {
+ Flag = EfiPciIoOperationBusMasterWrite;
+ } else {
+ Flag = EfiPciIoOperationBusMasterRead;
}
- }
- if ((Trb->DataLen % Trb->BlockSize) != 0) {
- if (Trb->DataLen < Trb->BlockSize) {
- Trb->BlockSize = (UINT16)Trb->DataLen;
+ PciIo = Private->PciIo;
+ if (Trb->DataLen != 0) {
+ MapLength = Trb->DataLen;
+ Status = PciIo->Map (
+ PciIo,
+ Flag,
+ Trb->Data,
+ &MapLength,
+ &Trb->DataPhy,
+ &Trb->DataMap
+ );
+ if (EFI_ERROR (Status) || (Trb->DataLen != MapLength)) {
+ Status = EFI_BAD_BUFFER_SIZE;
+ goto Error;
+ }
}
- }
- if (Trb->DataLen == 0) {
- Trb->Mode = SdMmcNoData;
- } else if (Private->Capability[Slot].Adma2 != 0) {
- Trb->Mode = SdMmcAdmaMode;
- Status = BuildAdmaDescTable (Trb);
- if (EFI_ERROR (Status)) {
- PciIo->Unmap (PciIo, Trb->DataMap);
- goto Error;
+ if (Trb->DataLen == 0) {
+ Trb->Mode = SdMmcNoData;
+ } else if (Private->Capability[Slot].Adma2 != 0) {
+ Trb->Mode = SdMmcAdma32bMode;
+ Trb->AdmaLengthMode = SdMmcAdmaLen16b;
+ if ((Private->ControllerVersion[Slot] == SD_MMC_HC_CTRL_VER_300) &&
+ (Private->Capability[Slot].SysBus64V3 == 1)) {
+ Trb->Mode = SdMmcAdma64bV3Mode;
+ } else if (((Private->ControllerVersion[Slot] == SD_MMC_HC_CTRL_VER_400) &&
+ (Private->Capability[Slot].SysBus64V3 == 1)) ||
+ ((Private->ControllerVersion[Slot] >= SD_MMC_HC_CTRL_VER_410) &&
+ (Private->Capability[Slot].SysBus64V4 == 1))) {
+ Trb->Mode = SdMmcAdma64bV4Mode;
+ }
+ if (Private->ControllerVersion[Slot] >= SD_MMC_HC_CTRL_VER_410) {
+ Trb->AdmaLengthMode = SdMmcAdmaLen26b;
+ }
+ Status = BuildAdmaDescTable (Trb, Private->ControllerVersion[Slot]);
+ if (EFI_ERROR (Status)) {
+ goto Error;
+ }
+ } else if (Private->Capability[Slot].Sdma != 0) {
+ Trb->Mode = SdMmcSdmaMode;
+ } else {
+ Trb->Mode = SdMmcPioMode;
}
- } else if (Private->Capability[Slot].Sdma != 0) {
- Trb->Mode = SdMmcSdmaMode;
- } else {
- Trb->Mode = SdMmcPioMode;
}
if (Event != NULL) {
- OldTpl = gBS->RaiseTPL (TPL_CALLBACK);
+ OldTpl = gBS->RaiseTPL (TPL_NOTIFY);
InsertTailList (&Private->Queue, &Trb->TrbList);
gBS->RestoreTPL (OldTpl);
}
@@ -1337,11 +1800,25 @@ SdMmcFreeTrb (
Trb->AdmaMap
);
}
- if (Trb->AdmaDesc != NULL) {
+ if (Trb->Adma32Desc != NULL) {
+ PciIo->FreeBuffer (
+ PciIo,
+ Trb->AdmaPages,
+ Trb->Adma32Desc
+ );
+ }
+ if (Trb->Adma64V3Desc != NULL) {
PciIo->FreeBuffer (
PciIo,
Trb->AdmaPages,
- Trb->AdmaDesc
+ Trb->Adma64V3Desc
+ );
+ }
+ if (Trb->Adma64V4Desc != NULL) {
+ PciIo->FreeBuffer (
+ PciIo,
+ Trb->AdmaPages,
+ Trb->Adma64V4Desc
);
}
if (Trb->DataMap != NULL) {
@@ -1386,15 +1863,6 @@ SdMmcCheckTrbEnv (
// the Present State register to be 0
//
PresentState = BIT0 | BIT1;
- //
- // For Send Tuning Block cmd, just wait for Command Inhibit (CMD) to be 0
- //
- if (((Private->Slot[Trb->Slot].CardType == EmmcCardType) &&
- (Packet->SdMmcCmdBlk->CommandIndex == EMMC_SEND_TUNING_BLOCK)) ||
- ((Private->Slot[Trb->Slot].CardType == SdCardType) &&
- (Packet->SdMmcCmdBlk->CommandIndex == SD_SEND_TUNING_BLOCK))) {
- PresentState = BIT0;
- }
} else {
//
// Wait Command Inhibit (CMD) in the Present State register
@@ -1490,12 +1958,15 @@ SdMmcExecTrb (
UINT16 Cmd;
UINT16 IntStatus;
UINT32 Argument;
- UINT16 BlkCount;
+ UINT32 BlkCount;
UINT16 BlkSize;
UINT16 TransMode;
UINT8 HostCtrl1;
- UINT32 SdmaAddr;
+ UINT64 SdmaAddr;
UINT64 AdmaAddr;
+ BOOLEAN AddressingMode64;
+
+ AddressingMode64 = FALSE;
Packet = Trb->Packet;
PciIo = Trb->Private->PciIo;
@@ -1515,30 +1986,55 @@ SdMmcExecTrb (
if (EFI_ERROR (Status)) {
return Status;
}
+
+ if (Private->ControllerVersion[Trb->Slot] >= SD_MMC_HC_CTRL_VER_400) {
+ Status = SdMmcHcCheckMmioSet(PciIo, Trb->Slot, SD_MMC_HC_HOST_CTRL2, sizeof(UINT16),
+ SD_MMC_HC_64_ADDR_EN, SD_MMC_HC_64_ADDR_EN);
+ if (!EFI_ERROR (Status)) {
+ AddressingMode64 = TRUE;
+ }
+ }
+
//
// Set Host Control 1 register DMA Select field
//
- if (Trb->Mode == SdMmcAdmaMode) {
+ if ((Trb->Mode == SdMmcAdma32bMode) ||
+ (Trb->Mode == SdMmcAdma64bV4Mode)) {
HostCtrl1 = BIT4;
Status = SdMmcHcOrMmio (PciIo, Trb->Slot, SD_MMC_HC_HOST_CTRL1, sizeof (HostCtrl1), &HostCtrl1);
if (EFI_ERROR (Status)) {
return Status;
}
+ } else if (Trb->Mode == SdMmcAdma64bV3Mode) {
+ HostCtrl1 = BIT4|BIT3;
+ Status = SdMmcHcOrMmio (PciIo, Trb->Slot, SD_MMC_HC_HOST_CTRL1, sizeof (HostCtrl1), &HostCtrl1);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
}
SdMmcHcLedOnOff (PciIo, Trb->Slot, TRUE);
if (Trb->Mode == SdMmcSdmaMode) {
- if ((UINT64)(UINTN)Trb->DataPhy >= 0x100000000ul) {
+ if ((!AddressingMode64) &&
+ ((UINT64)(UINTN)Trb->DataPhy >= 0x100000000ul)) {
return EFI_INVALID_PARAMETER;
}
- SdmaAddr = (UINT32)(UINTN)Trb->DataPhy;
- Status = SdMmcHcRwMmio (PciIo, Trb->Slot, SD_MMC_HC_SDMA_ADDR, FALSE, sizeof (SdmaAddr), &SdmaAddr);
+ SdmaAddr = (UINT64)(UINTN)Trb->DataPhy;
+
+ if (Private->ControllerVersion[Trb->Slot] >= SD_MMC_HC_CTRL_VER_400) {
+ Status = SdMmcHcRwMmio (PciIo, Trb->Slot, SD_MMC_HC_ADMA_SYS_ADDR, FALSE, sizeof (UINT64), &SdmaAddr);
+ } else {
+ Status = SdMmcHcRwMmio (PciIo, Trb->Slot, SD_MMC_HC_SDMA_ADDR, FALSE, sizeof (UINT32), &SdmaAddr);
+ }
+
if (EFI_ERROR (Status)) {
return Status;
}
- } else if (Trb->Mode == SdMmcAdmaMode) {
+ } else if ((Trb->Mode == SdMmcAdma32bMode) ||
+ (Trb->Mode == SdMmcAdma64bV3Mode) ||
+ (Trb->Mode == SdMmcAdma64bV4Mode)) {
AdmaAddr = (UINT64)(UINTN)Trb->AdmaDescPhy;
Status = SdMmcHcRwMmio (PciIo, Trb->Slot, SD_MMC_HC_ADMA_SYS_ADDR, FALSE, sizeof (AdmaAddr), &AdmaAddr);
if (EFI_ERROR (Status)) {
@@ -1559,8 +2055,18 @@ SdMmcExecTrb (
return Status;
}
- BlkCount = (UINT16)(Trb->DataLen / Trb->BlockSize);
- Status = SdMmcHcRwMmio (PciIo, Trb->Slot, SD_MMC_HC_BLK_COUNT, FALSE, sizeof (BlkCount), &BlkCount);
+ BlkCount = 0;
+ if (Trb->Mode != SdMmcNoData) {
+ //
+ // Calcuate Block Count.
+ //
+ BlkCount = (Trb->DataLen / Trb->BlockSize);
+ }
+ if (Private->ControllerVersion[Trb->Slot] >= SD_MMC_HC_CTRL_VER_410) {
+ Status = SdMmcHcRwMmio (PciIo, Trb->Slot, SD_MMC_HC_SDMA_ADDR, FALSE, sizeof (UINT32), &BlkCount);
+ } else {
+ Status = SdMmcHcRwMmio (PciIo, Trb->Slot, SD_MMC_HC_BLK_COUNT, FALSE, sizeof (UINT16), &BlkCount);
+ }
if (EFI_ERROR (Status)) {
return Status;
}
@@ -1579,7 +2085,7 @@ SdMmcExecTrb (
if (Trb->Read) {
TransMode |= BIT4;
}
- if (BlkCount != 0) {
+ if (BlkCount > 1) {
TransMode |= BIT5 | BIT1;
}
//
@@ -1635,6 +2141,137 @@ SdMmcExecTrb (
return Status;
}
+/**
+ Performs SW reset based on passed error status mask.
+
+ @param[in] Private Pointer to driver private data.
+ @param[in] Slot Index of the slot to reset.
+ @param[in] ErrIntStatus Error interrupt status mask.
+
+ @retval EFI_SUCCESS Software reset performed successfully.
+ @retval Other Software reset failed.
+**/
+EFI_STATUS
+SdMmcSoftwareReset (
+ IN SD_MMC_HC_PRIVATE_DATA *Private,
+ IN UINT8 Slot,
+ IN UINT16 ErrIntStatus
+ )
+{
+ UINT8 SwReset;
+ EFI_STATUS Status;
+
+ SwReset = 0;
+ if ((ErrIntStatus & 0x0F) != 0) {
+ SwReset |= BIT1;
+ }
+ if ((ErrIntStatus & 0x70) != 0) {
+ SwReset |= BIT2;
+ }
+
+ Status = SdMmcHcRwMmio (
+ Private->PciIo,
+ Slot,
+ SD_MMC_HC_SW_RST,
+ FALSE,
+ sizeof (SwReset),
+ &SwReset
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ Status = SdMmcHcWaitMmioSet (
+ Private->PciIo,
+ Slot,
+ SD_MMC_HC_SW_RST,
+ sizeof (SwReset),
+ 0xFF,
+ 0,
+ SD_MMC_HC_GENERIC_TIMEOUT
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Checks the error status in error status register
+ and issues appropriate software reset as described in
+ SD specification section 3.10.
+
+ @param[in] Private Pointer to driver private data.
+ @param[in] Slot Index of the slot for device.
+ @param[in] IntStatus Normal interrupt status mask.
+
+ @retval EFI_CRC_ERROR CRC error happened during CMD execution.
+ @retval EFI_SUCCESS No error reported.
+ @retval Others Some other error happened.
+
+**/
+EFI_STATUS
+SdMmcCheckAndRecoverErrors (
+ IN SD_MMC_HC_PRIVATE_DATA *Private,
+ IN UINT8 Slot,
+ IN UINT16 IntStatus
+ )
+{
+ UINT16 ErrIntStatus;
+ EFI_STATUS Status;
+ EFI_STATUS ErrorStatus;
+
+ if ((IntStatus & BIT15) == 0) {
+ return EFI_SUCCESS;
+ }
+
+ Status = SdMmcHcRwMmio (
+ Private->PciIo,
+ Slot,
+ SD_MMC_HC_ERR_INT_STS,
+ TRUE,
+ sizeof (ErrIntStatus),
+ &ErrIntStatus
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ //
+ // If the data timeout error is reported
+ // but data transfer is signaled as completed we
+ // have to ignore data timeout. We also assume that no
+ // other error is present on the link since data transfer
+ // completed successfully. Error interrupt status
+ // register is going to be reset when the next command
+ // is started.
+ //
+ if (((ErrIntStatus & BIT4) != 0) && ((IntStatus & BIT1) != 0)) {
+ return EFI_SUCCESS;
+ }
+
+ //
+ // We treat both CMD and DAT CRC errors and
+ // end bits errors as EFI_CRC_ERROR. This will
+ // let higher layer know that the error possibly
+ // happened due to random bus condition and the
+ // command can be retried.
+ //
+ if ((ErrIntStatus & (BIT1 | BIT2 | BIT5 | BIT6)) != 0) {
+ ErrorStatus = EFI_CRC_ERROR;
+ } else {
+ ErrorStatus = EFI_DEVICE_ERROR;
+ }
+
+ Status = SdMmcSoftwareReset (Private, Slot, ErrIntStatus);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ return ErrorStatus;
+}
+
/**
Check the TRB execution result.
@@ -1656,11 +2293,10 @@ SdMmcCheckTrbResult (
EFI_SD_MMC_PASS_THRU_COMMAND_PACKET *Packet;
UINT16 IntStatus;
UINT32 Response[4];
- UINT32 SdmaAddr;
+ UINT64 SdmaAddr;
UINT8 Index;
- UINT8 SwReset;
+ UINT32 PioLength;
- SwReset = 0;
Packet = Trb->Packet;
//
// Check Trb execution result by reading Normal Interrupt Status register.
@@ -1676,87 +2312,23 @@ SdMmcCheckTrbResult (
if (EFI_ERROR (Status)) {
goto Done;
}
+
//
- // Check Transfer Complete bit is set or not.
+ // Check if there are any errors reported by host controller
+ // and if neccessary recover the controller before next command is executed.
//
- if ((IntStatus & BIT1) == BIT1) {
- if ((IntStatus & BIT15) == BIT15) {
- //
- // Read Error Interrupt Status register to check if the error is
- // Data Timeout Error.
- // If yes, treat it as success as Transfer Complete has higher
- // priority than Data Timeout Error.
- //
- Status = SdMmcHcRwMmio (
- Private->PciIo,
- Trb->Slot,
- SD_MMC_HC_ERR_INT_STS,
- TRUE,
- sizeof (IntStatus),
- &IntStatus
- );
- if (!EFI_ERROR (Status)) {
- if ((IntStatus & BIT4) == BIT4) {
- Status = EFI_SUCCESS;
- } else {
- Status = EFI_DEVICE_ERROR;
- }
- }
- }
-
+ Status = SdMmcCheckAndRecoverErrors (Private, Trb->Slot, IntStatus);
+ if (EFI_ERROR (Status)) {
goto Done;
}
+
//
- // Check if there is a error happened during cmd execution.
- // If yes, then do error recovery procedure to follow SD Host Controller
- // Simplified Spec 3.0 section 3.10.1.
+ // Check Transfer Complete bit is set or not.
//
- if ((IntStatus & BIT15) == BIT15) {
- Status = SdMmcHcRwMmio (
- Private->PciIo,
- Trb->Slot,
- SD_MMC_HC_ERR_INT_STS,
- TRUE,
- sizeof (IntStatus),
- &IntStatus
- );
- if (EFI_ERROR (Status)) {
- goto Done;
- }
- if ((IntStatus & 0x0F) != 0) {
- SwReset |= BIT1;
- }
- if ((IntStatus & 0xF0) != 0) {
- SwReset |= BIT2;
- }
-
- Status = SdMmcHcRwMmio (
- Private->PciIo,
- Trb->Slot,
- SD_MMC_HC_SW_RST,
- FALSE,
- sizeof (SwReset),
- &SwReset
- );
- if (EFI_ERROR (Status)) {
- goto Done;
- }
- Status = SdMmcHcWaitMmioSet (
- Private->PciIo,
- Trb->Slot,
- SD_MMC_HC_SW_RST,
- sizeof (SwReset),
- 0xFF,
- 0,
- SD_MMC_HC_GENERIC_TIMEOUT
- );
- if (EFI_ERROR (Status)) {
- goto Done;
- }
-
- Status = EFI_DEVICE_ERROR;
+ if ((IntStatus & BIT1) == BIT1) {
goto Done;
}
+
//
// Check if DMA interrupt is signalled for the SDMA transfer.
//
@@ -1779,8 +2351,19 @@ SdMmcCheckTrbResult (
//
// Update SDMA Address register.
//
- SdmaAddr = SD_MMC_SDMA_ROUND_UP ((UINT32)(UINTN)Trb->DataPhy, SD_MMC_SDMA_BOUNDARY);
- Status = SdMmcHcRwMmio (
+ SdmaAddr = SD_MMC_SDMA_ROUND_UP ((UINTN)Trb->DataPhy, SD_MMC_SDMA_BOUNDARY);
+
+ if (Private->ControllerVersion[Trb->Slot] >= SD_MMC_HC_CTRL_VER_400) {
+ Status = SdMmcHcRwMmio (
+ Private->PciIo,
+ Trb->Slot,
+ SD_MMC_HC_ADMA_SYS_ADDR,
+ FALSE,
+ sizeof (UINT64),
+ &SdmaAddr
+ );
+ } else {
+ Status = SdMmcHcRwMmio (
Private->PciIo,
Trb->Slot,
SD_MMC_HC_SDMA_ADDR,
@@ -1788,10 +2371,12 @@ SdMmcCheckTrbResult (
sizeof (UINT32),
&SdmaAddr
);
+ }
+
if (EFI_ERROR (Status)) {
goto Done;
}
- Trb->DataPhy = (UINT32)(UINTN)SdmaAddr;
+ Trb->DataPhy = (UINT64)(UINTN)SdmaAddr;
}
if ((Packet->SdMmcCmdBlk->CommandType != SdMmcCommandTypeAdtc) &&
@@ -1808,12 +2393,25 @@ SdMmcCheckTrbResult (
((Private->Slot[Trb->Slot].CardType == SdCardType) &&
(Packet->SdMmcCmdBlk->CommandIndex == SD_SEND_TUNING_BLOCK))) {
//
- // While performing tuning procedure (Execute Tuning is set to 1),
- // Transfer Completeis not set to 1
- // Refer to SD Host Controller Simplified Specification 3.0 table 2-23 for details.
+ // When performing tuning procedure (Execute Tuning is set to 1) through PIO mode,
+ // wait Buffer Read Ready bit of Normal Interrupt Status Register to be 1.
+ // Refer to SD Host Controller Simplified Specification 3.0 figure 2-29 for details.
//
- Status = EFI_SUCCESS;
- goto Done;
+ if ((IntStatus & BIT5) == BIT5) {
+ //
+ // Clear Buffer Read Ready interrupt at first.
+ //
+ IntStatus = BIT5;
+ SdMmcHcRwMmio (Private->PciIo, Trb->Slot, SD_MMC_HC_NOR_INT_STS, FALSE, sizeof (IntStatus), &IntStatus);
+ //
+ // Read data out from Buffer Port register
+ //
+ for (PioLength = 0; PioLength < Trb->DataLen; PioLength += 4) {
+ SdMmcHcRwMmio (Private->PciIo, Trb->Slot, SD_MMC_HC_BUF_DAT_PORT, TRUE, 4, (UINT8*)Trb->Data + PioLength);
+ }
+ Status = EFI_SUCCESS;
+ goto Done;
+ }
}
Status = EFI_NOT_READY;