/** @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
- 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
- http://opensource.org/licenses/bsd-license.php\r
-\r
- THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
- WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+ Copyright (c) 2018-2019, NVIDIA CORPORATION. All rights reserved.\r
+ Copyright (c) 2015 - 2020, Intel Corporation. All rights reserved.<BR>\r
+ SPDX-License-Identifier: BSD-2-Clause-Patent\r
\r
**/\r
\r
#include "SdMmcPciHcDxe.h"\r
\r
+EDKII_SD_MMC_OVERRIDE *mOverride;\r
+\r
//\r
// Driver Global Variables\r
//\r
NULL\r
};\r
\r
+#define SLOT_INIT_TEMPLATE {0, UnknownSlot, 0, 0, 0, 0, \\r
+ {EDKII_SD_MMC_BUS_WIDTH_IGNORE,\\r
+ EDKII_SD_MMC_CLOCK_FREQ_IGNORE,\\r
+ {EDKII_SD_MMC_DRIVER_STRENGTH_IGNORE}}}\r
+\r
//\r
// Template for SD/MMC host controller private data.\r
//\r
// Queue\r
INITIALIZE_LIST_HEAD_VARIABLE (gSdMmcPciHcTemplate.Queue),\r
{ // Slot\r
- {0, UnknownSlot, 0, 0, 0}, {0, UnknownSlot, 0, 0, 0}, {0, UnknownSlot, 0, 0, 0},\r
- {0, UnknownSlot, 0, 0, 0}, {0, UnknownSlot, 0, 0, 0}, {0, UnknownSlot, 0, 0, 0}\r
+ SLOT_INIT_TEMPLATE,\r
+ SLOT_INIT_TEMPLATE,\r
+ SLOT_INIT_TEMPLATE,\r
+ SLOT_INIT_TEMPLATE,\r
+ SLOT_INIT_TEMPLATE,\r
+ SLOT_INIT_TEMPLATE\r
},\r
{ // Capability\r
{0},\r
{ // MaxCurrent\r
0,\r
},\r
- 0 // ControllerVersion\r
+ {\r
+ 0 // ControllerVersion\r
+ }\r
};\r
\r
SD_DEVICE_PATH mSdDpTemplate = {\r
gBS->SignalEvent (TrbEvent);\r
return;\r
}\r
- }\r
- if ((Trb != NULL) && (Status != EFI_NOT_READY)) {\r
+ } else if ((Trb != NULL) && (Status == EFI_CRC_ERROR) && (Trb->Retries > 0)) {\r
+ Trb->Retries--;\r
+ Trb->Started = FALSE;\r
+ } else if ((Trb != NULL)) {\r
RemoveEntryList (Link);\r
Trb->Packet->TransactionStatus = Status;\r
TrbEvent = Trb->Event;\r
//\r
// Reset the specified slot of the SD/MMC Pci Host Controller\r
//\r
- Status = SdMmcHcReset (Private->PciIo, Slot);\r
+ Status = SdMmcHcReset (Private, Slot);\r
if (EFI_ERROR (Status)) {\r
continue;\r
}\r
//\r
// Reinitialize slot and restart identification process for the new attached device\r
//\r
- Status = SdMmcHcInitHost (Private->PciIo, Slot, Private->Capability[Slot]);\r
+ Status = SdMmcHcInitHost (Private, Slot);\r
if (EFI_ERROR (Status)) {\r
continue;\r
}\r
\r
return;\r
}\r
+\r
/**\r
Tests to see if this driver supports a given controller. If a child device is provided,\r
it further tests to see if this driver supports creating a handle for the specified child device.\r
goto Done;\r
}\r
\r
+ //\r
+ // Attempt to locate the singleton instance of the SD/MMC override protocol,\r
+ // which implements platform specific workarounds for non-standard SDHCI\r
+ // implementations.\r
+ //\r
+ if (mOverride == NULL) {\r
+ Status = gBS->LocateProtocol (&gEdkiiSdMmcOverrideProtocolGuid, NULL,\r
+ (VOID **)&mOverride);\r
+ if (!EFI_ERROR (Status)) {\r
+ DEBUG ((DEBUG_INFO, "%a: found SD/MMC override protocol\n",\r
+ __FUNCTION__));\r
+ }\r
+ }\r
+\r
Support64BitDma = TRUE;\r
for (Slot = FirstBar; Slot < (FirstBar + SlotNum); Slot++) {\r
Private->Slot[Slot].Enable = TRUE;\r
+ //\r
+ // Get SD/MMC Pci Host Controller Version\r
+ //\r
+ Status = SdMmcHcGetControllerVersion (PciIo, Slot, &Private->ControllerVersion[Slot]);\r
+ if (EFI_ERROR (Status)) {\r
+ continue;\r
+ }\r
\r
Status = SdMmcHcGetCapability (PciIo, Slot, &Private->Capability[Slot]);\r
if (EFI_ERROR (Status)) {\r
continue;\r
}\r
+\r
+ Private->BaseClkFreq[Slot] = Private->Capability[Slot].BaseClkFreq;\r
+\r
+ if (mOverride != NULL) {\r
+ if (mOverride->Capability != NULL) {\r
+ Status = mOverride->Capability (\r
+ Controller,\r
+ Slot,\r
+ &Private->Capability[Slot],\r
+ &Private->BaseClkFreq[Slot]\r
+ );\r
+ if (EFI_ERROR (Status)) {\r
+ DEBUG ((DEBUG_WARN, "%a: Failed to override capability - %r\n",\r
+ __FUNCTION__, Status));\r
+ continue;\r
+ }\r
+ }\r
+\r
+ if (mOverride->NotifyPhase != NULL) {\r
+ Status = mOverride->NotifyPhase (\r
+ Controller,\r
+ Slot,\r
+ EdkiiSdMmcGetOperatingParam,\r
+ (VOID*)&Private->Slot[Slot].OperatingParameters\r
+ );\r
+ if (EFI_ERROR (Status)) {\r
+ DEBUG ((DEBUG_WARN, "%a: Failed to get operating parameters, using defaults\n", __FUNCTION__));\r
+ }\r
+ }\r
+ }\r
+\r
DumpCapabilityReg (Slot, &Private->Capability[Slot]);\r
+ DEBUG ((\r
+ DEBUG_INFO,\r
+ "Slot[%d] Base Clock Frequency: %dMHz\n",\r
+ Slot,\r
+ Private->BaseClkFreq[Slot]\r
+ ));\r
\r
- Support64BitDma &= Private->Capability[Slot].SysBus64;\r
+ //\r
+ // If any of the slots does not support 64b system bus\r
+ // do not enable 64b DMA in the PCI layer.\r
+ //\r
+ if ((Private->ControllerVersion[Slot] == SD_MMC_HC_CTRL_VER_300 &&\r
+ Private->Capability[Slot].SysBus64V3 == 0) ||\r
+ (Private->ControllerVersion[Slot] == SD_MMC_HC_CTRL_VER_400 &&\r
+ Private->Capability[Slot].SysBus64V3 == 0) ||\r
+ (Private->ControllerVersion[Slot] >= SD_MMC_HC_CTRL_VER_410 &&\r
+ Private->Capability[Slot].SysBus64V4 == 0)) {\r
+ Support64BitDma = FALSE;\r
+ }\r
\r
Status = SdMmcHcGetMaxCurrent (PciIo, Slot, &Private->MaxCurrent[Slot]);\r
if (EFI_ERROR (Status)) {\r
//\r
// Reset the specified slot of the SD/MMC Pci Host Controller\r
//\r
- Status = SdMmcHcReset (PciIo, Slot);\r
+ Status = SdMmcHcReset (Private, Slot);\r
if (EFI_ERROR (Status)) {\r
continue;\r
}\r
//\r
// Check whether there is a SD/MMC card attached\r
//\r
- Status = SdMmcHcCardDetect (PciIo, Slot, &MediaPresent);\r
- if (EFI_ERROR (Status) && (Status != EFI_MEDIA_CHANGED)) {\r
- continue;\r
- } else if (!MediaPresent) {\r
- DEBUG ((DEBUG_INFO, "SdMmcHcCardDetect: No device attached in Slot[%d]!!!\n", Slot));\r
- continue;\r
+ if (Private->Slot[Slot].SlotType == RemovableSlot) {\r
+ Status = SdMmcHcCardDetect (PciIo, Slot, &MediaPresent);\r
+ if (EFI_ERROR (Status) && (Status != EFI_MEDIA_CHANGED)) {\r
+ continue;\r
+ } else if (!MediaPresent) {\r
+ DEBUG ((\r
+ DEBUG_INFO,\r
+ "SdMmcHcCardDetect: No device attached in Slot[%d]!!!\n",\r
+ Slot\r
+ ));\r
+ continue;\r
+ }\r
}\r
\r
- Status = SdMmcHcInitHost (PciIo, Slot, Private->Capability[Slot]);\r
+ Status = SdMmcHcInitHost (Private, Slot);\r
if (EFI_ERROR (Status)) {\r
continue;\r
}\r
return Status;\r
}\r
\r
+/**\r
+ Execute TRB synchronously.\r
+\r
+ @param[in] Private Pointer to driver private data.\r
+ @param[in] Trb Pointer to TRB to execute.\r
+\r
+ @retval EFI_SUCCESS TRB executed successfully.\r
+ @retval Other TRB failed.\r
+**/\r
+EFI_STATUS\r
+SdMmcPassThruExecSyncTrb (\r
+ IN SD_MMC_HC_PRIVATE_DATA *Private,\r
+ IN SD_MMC_HC_TRB *Trb\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ EFI_TPL OldTpl;\r
+\r
+ //\r
+ // Wait async I/O list is empty before execute sync I/O operation.\r
+ //\r
+ while (TRUE) {\r
+ OldTpl = gBS->RaiseTPL (TPL_NOTIFY);\r
+ if (IsListEmpty (&Private->Queue)) {\r
+ gBS->RestoreTPL (OldTpl);\r
+ break;\r
+ }\r
+ gBS->RestoreTPL (OldTpl);\r
+ }\r
+\r
+ while (Trb->Retries) {\r
+ Status = SdMmcWaitTrbEnv (Private, Trb);\r
+ if (EFI_ERROR (Status)) {\r
+ return Status;\r
+ }\r
+\r
+ Status = SdMmcExecTrb (Private, Trb);\r
+ if (EFI_ERROR (Status)) {\r
+ return Status;\r
+ }\r
+\r
+ Status = SdMmcWaitTrbResult (Private, Trb);\r
+ if (Status == EFI_CRC_ERROR) {\r
+ Trb->Retries--;\r
+ } else {\r
+ return Status;\r
+ }\r
+ }\r
+\r
+ return Status;\r
+}\r
+\r
/**\r
Sends SD command to an SD card that is attached to the SD controller.\r
\r
EFI_STATUS Status;\r
SD_MMC_HC_PRIVATE_DATA *Private;\r
SD_MMC_HC_TRB *Trb;\r
- EFI_TPL OldTpl;\r
\r
if ((This == NULL) || (Packet == NULL)) {\r
return EFI_INVALID_PARAMETER;\r
return EFI_SUCCESS;\r
}\r
\r
- //\r
- // Wait async I/O list is empty before execute sync I/O operation.\r
- //\r
- while (TRUE) {\r
- OldTpl = gBS->RaiseTPL (TPL_NOTIFY);\r
- if (IsListEmpty (&Private->Queue)) {\r
- gBS->RestoreTPL (OldTpl);\r
- break;\r
- }\r
- gBS->RestoreTPL (OldTpl);\r
- }\r
-\r
- Status = SdMmcWaitTrbEnv (Private, Trb);\r
- if (EFI_ERROR (Status)) {\r
- goto Done;\r
- }\r
-\r
- Status = SdMmcExecTrb (Private, Trb);\r
- if (EFI_ERROR (Status)) {\r
- goto Done;\r
- }\r
-\r
- Status = SdMmcWaitTrbResult (Private, Trb);\r
- if (EFI_ERROR (Status)) {\r
- goto Done;\r
- }\r
-\r
-Done:\r
- if ((Trb != NULL) && (Trb->AdmaDesc != NULL)) {\r
- FreePages (Trb->AdmaDesc, Trb->AdmaPages);\r
- }\r
+ Status = SdMmcPassThruExecSyncTrb (Private, Trb);\r
\r
- if (Trb != NULL) {\r
- FreePool (Trb);\r
- }\r
+ SdMmcFreeTrb (Trb);\r
\r
return Status;\r
}\r