X-Git-Url: https://git.proxmox.com/?a=blobdiff_plain;f=MdeModulePkg%2FBus%2FPci%2FSdMmcPciHcDxe%2FSdMmcPciHci.c;h=7971196a253a84339798ec9480166edd8dcd884f;hb=643623147a1feaddd734ddd84604e1d8e9dcebee;hp=f667264c5e7177d762c3e7eb06b38a46ccb105c1;hpb=49accdedf956f175041040e677163b7cbb746283;p=mirror_edk2.git
diff --git a/MdeModulePkg/Bus/Pci/SdMmcPciHcDxe/SdMmcPciHci.c b/MdeModulePkg/Bus/Pci/SdMmcPciHcDxe/SdMmcPciHci.c
index f667264c5e..7971196a25 100644
--- a/MdeModulePkg/Bus/Pci/SdMmcPciHcDxe/SdMmcPciHci.c
+++ b/MdeModulePkg/Bus/Pci/SdMmcPciHcDxe/SdMmcPciHci.c
@@ -7,7 +7,7 @@
It would expose EFI_SD_MMC_PASS_THRU_PROTOCOL for upper layer use.
Copyright (c) 2018-2019, NVIDIA CORPORATION. All rights reserved.
- Copyright (c) 2015 - 2019, Intel Corporation. All rights reserved.
+ Copyright (c) 2015 - 2020, Intel Corporation. All rights reserved.
SPDX-License-Identifier: BSD-2-Clause-Patent
**/
@@ -758,6 +758,30 @@ 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.
@@ -879,11 +903,10 @@ SdMmcHcClockSupply (
return Status;
}
- //
- // Set SD Clock Enable in the Clock Control register to 1
- //
- ClockCtrl = BIT2;
- Status = SdMmcHcOrMmio (PciIo, Slot, SD_MMC_HC_CLOCK_CTRL, sizeof (ClockCtrl), &ClockCtrl);
+ Status = SdMmcHcStartSdClock (PciIo, Slot);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
//
// We don't notify the platform on first time setup to avoid changing
@@ -908,6 +931,8 @@ SdMmcHcClockSupply (
}
}
+ Private->Slot[Slot].CurrentFreq = ClockFreq;
+
return Status;
}
@@ -1521,6 +1546,8 @@ BuildAdmaDescTable (
PciIo,
Trb->AdmaMap
);
+ Trb->AdmaMap = NULL;
+
PciIo->FreeBuffer (
PciIo,
EFI_SIZE_TO_PAGES (TableSize),
@@ -1660,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)) {
@@ -1729,7 +1757,6 @@ SdMmcCreateTrb (
}
Status = BuildAdmaDescTable (Trb, Private->ControllerVersion[Slot]);
if (EFI_ERROR (Status)) {
- PciIo->Unmap (PciIo, Trb->DataMap);
goto Error;
}
} else if (Private->Capability[Slot].Sdma != 0) {
@@ -2114,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.
@@ -2137,10 +2295,8 @@ SdMmcCheckTrbResult (
UINT32 Response[4];
UINT64 SdmaAddr;
UINT8 Index;
- UINT8 SwReset;
UINT32 PioLength;
- SwReset = 0;
Packet = Trb->Packet;
//
// Check Trb execution result by reading Normal Interrupt Status register.
@@ -2156,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.
//