It would expose EFI_SD_MMC_PASS_THRU_PROTOCOL for upper layer use.\r
\r
Copyright (c) 2018-2019, NVIDIA CORPORATION. All rights reserved.\r
- Copyright (c) 2015 - 2019, Intel Corporation. All rights reserved.<BR>\r
+ Copyright (c) 2015 - 2020, Intel Corporation. All rights reserved.<BR>\r
SPDX-License-Identifier: BSD-2-Clause-Patent\r
\r
**/\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
return Status;\r
}\r
\r
- //\r
- // Set SD Clock Enable in the Clock Control register to 1\r
- //\r
- ClockCtrl = BIT2;\r
- Status = SdMmcHcOrMmio (PciIo, Slot, SD_MMC_HC_CLOCK_CTRL, sizeof (ClockCtrl), &ClockCtrl);\r
+ Status = SdMmcHcStartSdClock (PciIo, Slot);\r
+ if (EFI_ERROR (Status)) {\r
+ return Status;\r
+ }\r
\r
//\r
// We don't notify the platform on first time setup to avoid changing\r
}\r
}\r
\r
+ Private->Slot[Slot].CurrentFreq = ClockFreq;\r
+\r
return Status;\r
}\r
\r
PciIo,\r
Trb->AdmaMap\r
);\r
+ Trb->AdmaMap = NULL;\r
+\r
PciIo->FreeBuffer (\r
PciIo,\r
EFI_SIZE_TO_PAGES (TableSize),\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
}\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
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