]> git.proxmox.com Git - mirror_edk2.git/blobdiff - MdeModulePkg/Bus/Pci/SdMmcPciHcDxe/SdMmcPciHcDxe.c
MdeModulePkg/SdMmcPciHcDxe: Send SEND_STATUS at lower frequency
[mirror_edk2.git] / MdeModulePkg / Bus / Pci / SdMmcPciHcDxe / SdMmcPciHcDxe.c
index 5de1dd6fd9e694fdbeb5ec86133b5a85ba468407..57f4cf329a1adcc42eaa706f61a7448426a71a71 100644 (file)
@@ -1,22 +1,21 @@
 /** @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
@@ -29,6 +28,11 @@ EFI_DRIVER_BINDING_PROTOCOL gSdMmcPciHcDriverBinding = {
   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
@@ -51,8 +55,12 @@ SD_MMC_HC_PRIVATE_DATA gSdMmcPciHcTemplate = {
                                     // 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
@@ -60,7 +68,9 @@ SD_MMC_HC_PRIVATE_DATA gSdMmcPciHcTemplate = {
   {                                 // MaxCurrent\r
     0,\r
   },\r
-  0                                 // ControllerVersion\r
+  {\r
+    0                               // ControllerVersion\r
+  }\r
 };\r
 \r
 SD_DEVICE_PATH    mSdDpTemplate = {\r
@@ -197,17 +207,19 @@ Done:
       Trb->Packet->TransactionStatus = EFI_TIMEOUT;\r
       TrbEvent = Trb->Event;\r
       SdMmcFreeTrb (Trb);\r
-      DEBUG ((EFI_D_VERBOSE, "ProcessAsyncTaskList(): Signal Event %p EFI_TIMEOUT\n", TrbEvent));\r
+      DEBUG ((DEBUG_VERBOSE, "ProcessAsyncTaskList(): Signal Event %p EFI_TIMEOUT\n", TrbEvent));\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
     SdMmcFreeTrb (Trb);\r
-    DEBUG ((EFI_D_VERBOSE, "ProcessAsyncTaskList(): Signal Event %p with %r\n", TrbEvent, Status));\r
+    DEBUG ((DEBUG_VERBOSE, "ProcessAsyncTaskList(): Signal Event %p with %r\n", TrbEvent, Status));\r
     gBS->SignalEvent (TrbEvent);\r
   }\r
   return;\r
@@ -246,7 +258,7 @@ SdMmcPciHcEnumerateDevice (
     if ((Private->Slot[Slot].Enable) && (Private->Slot[Slot].SlotType == RemovableSlot)) {\r
       Status = SdMmcHcCardDetect (Private->PciIo, Slot, &MediaPresent);\r
       if ((Status == EFI_MEDIA_CHANGED) && !MediaPresent) {\r
-        DEBUG ((EFI_D_INFO, "SdMmcPciHcEnumerateDevice: device disconnected at slot %d of pci %p\n", Slot, Private->PciIo));\r
+        DEBUG ((DEBUG_INFO, "SdMmcPciHcEnumerateDevice: device disconnected at slot %d of pci %p\n", Slot, Private->PciIo));\r
         Private->Slot[Slot].MediaPresent = FALSE;\r
         Private->Slot[Slot].Initialized  = FALSE;\r
         //\r
@@ -277,18 +289,18 @@ SdMmcPciHcEnumerateDevice (
               );\r
       }\r
       if ((Status == EFI_MEDIA_CHANGED) && MediaPresent) {\r
-        DEBUG ((EFI_D_INFO, "SdMmcPciHcEnumerateDevice: device connected at slot %d of pci %p\n", Slot, Private->PciIo));\r
+        DEBUG ((DEBUG_INFO, "SdMmcPciHcEnumerateDevice: device connected at slot %d of pci %p\n", Slot, Private->PciIo));\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
@@ -327,6 +339,7 @@ SdMmcPciHcEnumerateDevice (
 \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
@@ -529,7 +542,7 @@ SdMmcPciHcDriverBindingStart (
   BOOLEAN                         MediaPresent;\r
   BOOLEAN                         Support64BitDma;\r
 \r
-  DEBUG ((EFI_D_INFO, "SdMmcPciHcDriverBindingStart: Start\n"));\r
+  DEBUG ((DEBUG_INFO, "SdMmcPciHcDriverBindingStart: Start\n"));\r
 \r
   //\r
   // Open PCI I/O Protocol and save pointer to open protocol\r
@@ -601,17 +614,86 @@ SdMmcPciHcDriverBindingStart (
     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
@@ -620,29 +702,35 @@ SdMmcPciHcDriverBindingStart (
 \r
     Private->Slot[Slot].SlotType = Private->Capability[Slot].SlotType;\r
     if ((Private->Slot[Slot].SlotType != RemovableSlot) && (Private->Slot[Slot].SlotType != EmbeddedSlot)) {\r
-      DEBUG ((EFI_D_INFO, "SdMmcPciHcDxe doesn't support the slot type [%d]!!!\n", Private->Slot[Slot].SlotType));\r
+      DEBUG ((DEBUG_INFO, "SdMmcPciHcDxe doesn't support the slot type [%d]!!!\n", Private->Slot[Slot].SlotType));\r
       continue;\r
     }\r
 \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 ((EFI_D_ERROR, "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
@@ -679,7 +767,7 @@ SdMmcPciHcDriverBindingStart (
                       NULL\r
                       );\r
     if (EFI_ERROR (Status)) {\r
-      DEBUG ((EFI_D_WARN, "SdMmcPciHcDriverBindingStart: failed to enable 64-bit DMA (%r)\n", Status));\r
+      DEBUG ((DEBUG_WARN, "SdMmcPciHcDriverBindingStart: failed to enable 64-bit DMA (%r)\n", Status));\r
     }\r
   }\r
 \r
@@ -728,7 +816,7 @@ SdMmcPciHcDriverBindingStart (
                   NULL\r
                   );\r
 \r
-  DEBUG ((EFI_D_INFO, "SdMmcPciHcDriverBindingStart: %r End on %x\n", Status, Controller));\r
+  DEBUG ((DEBUG_INFO, "SdMmcPciHcDriverBindingStart: %r End on %x\n", Status, Controller));\r
 \r
 Done:\r
   if (EFI_ERROR (Status)) {\r
@@ -809,7 +897,7 @@ SdMmcPciHcDriverBindingStop (
   LIST_ENTRY                          *NextLink;\r
   SD_MMC_HC_TRB                       *Trb;\r
 \r
-  DEBUG ((EFI_D_INFO, "SdMmcPciHcDriverBindingStop: Start\n"));\r
+  DEBUG ((DEBUG_INFO, "SdMmcPciHcDriverBindingStop: Start\n"));\r
 \r
   Status = gBS->OpenProtocol (\r
                   Controller,\r
@@ -883,7 +971,59 @@ SdMmcPciHcDriverBindingStop (
 \r
   FreePool (Private);\r
 \r
-  DEBUG ((EFI_D_INFO, "SdMmcPciHcDriverBindingStop: End with %r\n", Status));\r
+  DEBUG ((DEBUG_INFO, "SdMmcPciHcDriverBindingStop: End with %r\n", Status));\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
@@ -937,7 +1077,6 @@ SdMmcPassThruPassThru (
   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
@@ -980,41 +1119,9 @@ SdMmcPassThruPassThru (
     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