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. //