]> git.proxmox.com Git - mirror_edk2.git/blobdiff - MdeModulePkg/Bus/Sd/SdBlockIoPei/SdHci.c
MdeModulePkg/SdMmc: Add break to avoid dead loop when polling OCR Reg
[mirror_edk2.git] / MdeModulePkg / Bus / Sd / SdBlockIoPei / SdHci.c
index 8f7ecf9395f7a5c09643fee0e5dcc8491337e23d..eebadd79bc9879efcab9cd88e1c3fdcbf56ae3b2 100644 (file)
@@ -1,6 +1,6 @@
 /** @file\r
 \r
-  Copyright (c) 2015 - 2016, Intel Corporation. All rights reserved.<BR>\r
+  Copyright (c) 2015 - 2017, 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
@@ -535,9 +535,15 @@ SdPeimHcClockSupply (
   ASSERT (Capability.BaseClkFreq != 0);\r
 \r
   BaseClkFreq = Capability.BaseClkFreq;\r
-  if ((ClockFreq > (BaseClkFreq * 1000)) || (ClockFreq == 0)) {\r
+\r
+  if (ClockFreq == 0) {\r
     return EFI_INVALID_PARAMETER;\r
   }\r
+\r
+  if (ClockFreq > (BaseClkFreq * 1000)) {\r
+    ClockFreq = BaseClkFreq * 1000;\r
+  }\r
+\r
   //\r
   // Calculate the divisor of base frequency.\r
   //\r
@@ -1026,26 +1032,27 @@ SdPeimCreateTrb (
     goto Error;\r
   }\r
 \r
-  if ((Trb->DataLen % Trb->BlockSize) != 0) {\r
-    if (Trb->DataLen < Trb->BlockSize) {\r
-      Trb->BlockSize = (UINT16)Trb->DataLen;\r
-    }\r
+  if ((Trb->DataLen != 0) && (Trb->DataLen < Trb->BlockSize)) {\r
+    Trb->BlockSize = (UINT16)Trb->DataLen;\r
   }\r
 \r
-  if (Trb->DataLen == 0) {\r
-    Trb->Mode = SdNoData;\r
-  } else if (Capability.Adma2 != 0) {\r
-    Trb->Mode = SdAdmaMode;\r
-    Status = BuildAdmaDescTable (Trb);\r
-    if (EFI_ERROR (Status)) {\r
-      goto Error;\r
-    }\r
-  } else if (Capability.Sdma != 0) {\r
-    Trb->Mode = SdSdmaMode;\r
-  } else {\r
+  if (Packet->SdCmdBlk->CommandIndex == SD_SEND_TUNING_BLOCK) {\r
     Trb->Mode = SdPioMode;\r
+  } else {\r
+    if (Trb->DataLen == 0) {\r
+      Trb->Mode = SdNoData;\r
+    } else if (Capability.Adma2 != 0) {\r
+      Trb->Mode = SdAdmaMode;\r
+      Status = BuildAdmaDescTable (Trb);\r
+      if (EFI_ERROR (Status)) {\r
+        goto Error;\r
+      }\r
+    } else if (Capability.Sdma != 0) {\r
+      Trb->Mode = SdSdmaMode;\r
+    } else {\r
+      Trb->Mode = SdPioMode;\r
+    }\r
   }\r
-\r
   return Trb;\r
 \r
 Error:\r
@@ -1105,9 +1112,6 @@ SdPeimCheckTrbEnv (
     // the Present State register to be 0\r
     //\r
     PresentState = BIT0 | BIT1;\r
-    if (Packet->SdCmdBlk->CommandIndex == SD_SEND_TUNING_BLOCK) {\r
-      PresentState = BIT0;\r
-    }\r
   } else {\r
     //\r
     // Wait Command Inhibit (CMD) in the Present State register\r
@@ -1267,7 +1271,13 @@ SdPeimExecTrb (
     return Status;\r
   }\r
 \r
-  BlkCount = (UINT16)(Trb->DataLen / Trb->BlockSize);\r
+  BlkCount = 0;\r
+  if (Trb->Mode != SdNoData) {\r
+    //\r
+    // Calcuate Block Count.\r
+    //\r
+    BlkCount = (UINT16)(Trb->DataLen / Trb->BlockSize);\r
+  }\r
   Status   = SdPeimHcRwMmio (Bar + SD_HC_BLK_COUNT, FALSE, sizeof (BlkCount), &BlkCount);\r
   if (EFI_ERROR (Status)) {\r
     return Status;\r
@@ -1287,9 +1297,12 @@ SdPeimExecTrb (
     if (Trb->Read) {\r
       TransMode |= BIT4;\r
     }\r
-    if (BlkCount != 0) {\r
+    if (BlkCount > 1) {\r
       TransMode |= BIT5 | BIT1;\r
     }\r
+    //\r
+    // SD memory card needs to use AUTO CMD12 feature.\r
+    //\r
     if (BlkCount > 1) {\r
       TransMode |= BIT2;\r
     }\r
@@ -1362,6 +1375,7 @@ SdPeimCheckTrbResult (
   UINT32                              SdmaAddr;\r
   UINT8                               Index;\r
   UINT8                               SwReset;\r
+  UINT32                              PioLength;\r
 \r
   SwReset = 0;\r
   Packet  = Trb->Packet;\r
@@ -1494,8 +1508,26 @@ SdPeimCheckTrbResult (
   }\r
 \r
   if (Packet->SdCmdBlk->CommandIndex == SD_SEND_TUNING_BLOCK) {\r
-    Status = EFI_SUCCESS;\r
-    goto Done;\r
+    //\r
+    // When performing tuning procedure (Execute Tuning is set to 1) through PIO mode,\r
+    // wait Buffer Read Ready bit of Normal Interrupt Status Register to be 1.\r
+    // Refer to SD Host Controller Simplified Specification 3.0 figure 2-29 for details.\r
+    //\r
+    if ((IntStatus & BIT5) == BIT5) {\r
+      //\r
+      // Clear Buffer Read Ready interrupt at first.\r
+      //\r
+      IntStatus = BIT5;\r
+      SdPeimHcRwMmio (Bar + SD_HC_NOR_INT_STS, FALSE, sizeof (IntStatus), &IntStatus);\r
+      //\r
+      // Read data out from Buffer Port register\r
+      //\r
+      for (PioLength = 0; PioLength < Trb->DataLen; PioLength += 4) {\r
+        SdPeimHcRwMmio (Bar + SD_HC_BUF_DAT_PORT, TRUE, 4, (UINT8*)Trb->Data + PioLength);\r
+      }\r
+      Status = EFI_SUCCESS;\r
+      goto Done;\r
+    }\r
   }\r
 \r
   Status = EFI_NOT_READY;\r
@@ -2160,6 +2192,7 @@ SdPeimSetBusWidth (
   @param[in]  DriveStrength The value for drive length group.\r
   @param[in]  PowerLimit    The value for power limit group.\r
   @param[in]  Mode          Switch or check function.\r
+  @param[out] SwitchResp    The return switch function status.\r
 \r
   @retval EFI_SUCCESS       The operation is done correctly.\r
   @retval Others            The operation fails.\r
@@ -2167,12 +2200,13 @@ SdPeimSetBusWidth (
 **/\r
 EFI_STATUS\r
 SdPeimSwitch (\r
-  IN SD_PEIM_HC_SLOT        *Slot,\r
-  IN UINT8                  AccessMode,\r
-  IN UINT8                  CommandSystem,\r
-  IN UINT8                  DriveStrength,\r
-  IN UINT8                  PowerLimit,\r
-  IN BOOLEAN                Mode\r
+  IN     SD_PEIM_HC_SLOT              *Slot,\r
+  IN     UINT8                        AccessMode,\r
+  IN     UINT8                        CommandSystem,\r
+  IN     UINT8                        DriveStrength,\r
+  IN     UINT8                        PowerLimit,\r
+  IN     BOOLEAN                      Mode,\r
+     OUT UINT8                        *SwitchResp\r
   )\r
 {\r
   SD_COMMAND_BLOCK                    SdCmdBlk;\r
@@ -2180,7 +2214,6 @@ SdPeimSwitch (
   SD_COMMAND_PACKET                   Packet;\r
   EFI_STATUS                          Status;\r
   UINT32                              ModeValue;\r
-  UINT8                               Data[64];\r
 \r
   ZeroMem (&SdCmdBlk, sizeof (SdCmdBlk));\r
   ZeroMem (&SdStatusBlk, sizeof (SdStatusBlk));\r
@@ -2198,8 +2231,8 @@ SdPeimSwitch (
   SdCmdBlk.CommandArgument = (AccessMode & 0xF) | ((PowerLimit & 0xF) << 4) | \\r
                              ((DriveStrength & 0xF) << 8) | ((DriveStrength & 0xF) << 12) | \\r
                              ModeValue;\r
-  Packet.InDataBuffer     = Data;\r
-  Packet.InTransferLength = sizeof (Data);\r
+  Packet.InDataBuffer     = SwitchResp;\r
+  Packet.InTransferLength = 64;\r
 \r
   Status = SdPeimExecCmd (Slot, &Packet);\r
 \r
@@ -2491,15 +2524,25 @@ SdPeimTuningClock (
       return Status;\r
     }\r
 \r
-    if ((HostCtrl2 & (BIT6 | BIT7)) == BIT7) {\r
+    if ((HostCtrl2 & (BIT6 | BIT7)) == 0) {\r
       break;\r
     }\r
+\r
+    if ((HostCtrl2 & (BIT6 | BIT7)) == BIT7) {\r
+      return EFI_SUCCESS;\r
+    }\r
   } while (++Retry < 40);\r
 \r
-  if (Retry == 40) {\r
-    Status = EFI_TIMEOUT;\r
+  DEBUG ((EFI_D_ERROR, "SdPeimTuningClock: Send tuning block fails at %d times with HostCtrl2 %02x\n", Retry, HostCtrl2));\r
+  //\r
+  // Abort the tuning procedure and reset the tuning circuit.\r
+  //\r
+  HostCtrl2 = (UINT8)~(BIT6 | BIT7);\r
+  Status = SdPeimHcAndMmio (Slot->SdHcBase + SD_HC_HOST_CTRL2, sizeof (HostCtrl2), &HostCtrl2);\r
+  if (EFI_ERROR (Status)) {\r
+    return Status;\r
   }\r
-  return Status;\r
+  return EFI_DEVICE_ERROR;\r
 }\r
 \r
 /**\r
@@ -2575,6 +2618,7 @@ SdPeimSetBusMode (
   UINT8                        AccessMode;\r
   UINT8                        HostCtrl1;\r
   UINT8                        HostCtrl2;\r
+  UINT8                        SwitchResp[64];\r
 \r
   Status = SdPeimGetCsd (Slot, Rca, &Slot->Csd);\r
   if (EFI_ERROR (Status)) {\r
@@ -2601,31 +2645,46 @@ SdPeimSetBusMode (
   }\r
 \r
   //\r
-  // Calculate supported bus speed/bus width/clock frequency.\r
+  // Get the supported bus speed from SWITCH cmd return data group #1.\r
+  //\r
+  ZeroMem (SwitchResp, sizeof (SwitchResp));\r
+  Status = SdPeimSwitch (Slot, 0xF, 0xF, 0xF, 0xF, FALSE, SwitchResp);\r
+  if (EFI_ERROR (Status)) {\r
+    return Status;\r
+  }\r
+  //\r
+  // Calculate supported bus speed/bus width/clock frequency by host and device capability.\r
   //\r
   ClockFreq = 0;\r
-  if (S18a && (Capability.Sdr104 != 0)) {\r
+  if (S18a && (Capability.Sdr104 != 0) && ((SwitchResp[13] & BIT3) != 0)) {\r
     ClockFreq = 208;\r
     AccessMode = 3;\r
-  } else if (S18a && (Capability.Sdr50 != 0)) {\r
+  } else if (S18a && (Capability.Sdr50 != 0) && ((SwitchResp[13] & BIT2) != 0)) {\r
     ClockFreq = 100;\r
     AccessMode = 2;\r
-  } else if (S18a && (Capability.Ddr50 != 0)) {\r
+  } else if (S18a && (Capability.Ddr50 != 0) && ((SwitchResp[13] & BIT4) != 0)) {\r
     ClockFreq = 50;\r
     AccessMode = 4;\r
-  } else {\r
+  } else if ((SwitchResp[13] & BIT1) != 0) {\r
     ClockFreq = 50;\r
     AccessMode = 1;\r
+  } else {\r
+    ClockFreq = 25;\r
+    AccessMode = 0;\r
   }\r
 \r
-  DEBUG ((EFI_D_INFO, "AccessMode %d ClockFreq %d BusWidth %d\n", AccessMode, ClockFreq, BusWidth));\r
+  DEBUG ((EFI_D_INFO, "SdPeimSetBusMode: AccessMode %d ClockFreq %d BusWidth %d\n", AccessMode, ClockFreq, BusWidth));\r
 \r
-  Status = SdPeimSwitch (Slot, AccessMode, 0, 0, 0, TRUE);\r
+  Status = SdPeimSwitch (Slot, AccessMode, 0xF, 0xF, 0xF, TRUE, SwitchResp);\r
   if (EFI_ERROR (Status)) {\r
     DEBUG ((EFI_D_ERROR, "SdPeimSetBusMode: SdPeimSwitch fails with %r\n", Status));\r
     return Status;\r
   }\r
 \r
+  if ((SwitchResp[16] & 0xF) != AccessMode) {\r
+    DEBUG ((EFI_D_ERROR, "SdPeimSetBusMode: SdPeimSwitch to AccessMode %d ClockFreq %d BusWidth %d fails! The Switch response is 0x%1x\n", AccessMode, ClockFreq, BusWidth, SwitchResp[16] & 0xF));\r
+    return EFI_DEVICE_ERROR;\r
+  }\r
   //\r
   // Set to Hight Speed timing\r
   //\r
@@ -2695,7 +2754,7 @@ SdPeimIdentification (
   UINT32                         PresentState;\r
   UINT8                          HostCtrl2;\r
   SD_HC_SLOT_CAP                 Capability;\r
-\r
+  UINTN                          Retry;\r
   //\r
   // 1. Send Cmd0 to the device\r
   //\r
@@ -2783,12 +2842,20 @@ SdPeimIdentification (
   //    Note here we only support the cards complied with SD physical\r
   //    layer simplified spec version 2.0 and version 3.0 and above.\r
   //\r
+  Ocr   = 0;\r
+  Retry = 0;\r
   do {\r
     Status = SdPeimSendOpCond (Slot, 0, Ocr, S18r, Xpc, TRUE, &Ocr);\r
     if (EFI_ERROR (Status)) {\r
       DEBUG ((EFI_D_ERROR, "SdPeimIdentification: SdPeimSendOpCond fails with %r Ocr %x, S18r %x, Xpc %x\n", Status, Ocr, S18r, Xpc));\r
       return EFI_DEVICE_ERROR;\r
     }\r
+\r
+    if (Retry++ == 100) {\r
+      DEBUG ((EFI_D_ERROR, "SdPeimIdentification: SdPeimSendOpCond fails too many times\n"));\r
+      return EFI_DEVICE_ERROR;\r
+    }\r
+    MicroSecondDelay (10 * 1000);\r
   } while ((Ocr & BIT31) == 0);\r
 \r
   //\r
@@ -2832,7 +2899,7 @@ SdPeimIdentification (
 \r
       SdPeimHcInitClockFreq (Slot->SdHcBase);\r
 \r
-      MicroSecondDelay (1);\r
+      MicroSecondDelay (1000);\r
 \r
       SdPeimHcRwMmio (Slot->SdHcBase + SD_HC_PRESENT_STATE, TRUE, sizeof (PresentState), &PresentState);\r
       if (((PresentState >> 20) & 0xF) != 0xF) {\r