EmbeddedPkg/MmcDxe: set I/O speed and bus width in SD stack
authorHaojian Zhuang <haojian.zhuang@linaro.org>
Wed, 23 Nov 2016 13:36:22 +0000 (21:36 +0800)
committerArd Biesheuvel <ard.biesheuvel@linaro.org>
Thu, 24 Nov 2016 16:29:03 +0000 (16:29 +0000)
Add more SD commands to support 4-bit bus width & iospeed.

Contributed-under: TianoCore Contribution Agreement 1.0
Signed-off-by: Haojian Zhuang <haojian.zhuang@linaro.org>
Tested-by: Ryan Harkin <ryan.harkin@linaro.org>
Reviewed-by: Ard Biesheuvel <ard.biesheuvel@linaro.org>
EmbeddedPkg/Universal/MmcDxe/Mmc.h
EmbeddedPkg/Universal/MmcDxe/MmcIdentification.c

index fb3f6c9..c96ff2e 100644 (file)
@@ -80,6 +80,22 @@ typedef struct {
   UINT32  PowerUp:     1; // This bit is set to LOW if the card has not finished the power up routine\r
 } OCR;\r
 \r
+typedef struct {\r
+  UINT8   SD_SPEC:               4; // SD Memory Card - Spec. Version [59:56]\r
+  UINT8   SCR_STRUCTURE:         4; // SCR Structure [63:60]\r
+  UINT8   SD_BUS_WIDTHS:         4; // DAT Bus widths supported [51:48]\r
+  UINT8   DATA_STAT_AFTER_ERASE: 1; // Data Status after erases [55]\r
+  UINT8   SD_SECURITY:           3; // CPRM Security Support [54:52]\r
+  UINT8   EX_SECURITY_1:         1; // Extended Security Support [43]\r
+  UINT8   SD_SPEC4:              1; // Spec. Version 4.00 or higher [42]\r
+  UINT8   RESERVED_1:            2; // Reserved [41:40]\r
+  UINT8   SD_SPEC3:              1; // Spec. Version 3.00 or higher [47]\r
+  UINT8   EX_SECURITY_2:         3; // Extended Security Support [46:44]\r
+  UINT8   CMD_SUPPORT:           4; // Command Support bits [35:32]\r
+  UINT8   RESERVED_2:            4; // Reserved [39:36]\r
+  UINT32  RESERVED_3;               // Manufacturer Usage [31:0]\r
+} SCR;\r
+\r
 typedef struct {\r
   UINT32  NOT_USED;   // 1 [0:0]\r
   UINT32  CRC;        // CRC7 checksum [7:1]\r
index decfd54..574a77e 100644 (file)
@@ -12,6 +12,9 @@
 *\r
 **/\r
 \r
+#include <Library/BaseMemoryLib.h>\r
+#include <Library/TimerLib.h>\r
+\r
 #include "Mmc.h"\r
 \r
 typedef union {\r
@@ -41,6 +44,11 @@ typedef union {
 \r
 #define EMMC_SWITCH_ERROR       (1 << 7)\r
 \r
+#define SD_BUS_WIDTH_1BIT       (1 << 0)\r
+#define SD_BUS_WIDTH_4BIT       (1 << 2)\r
+\r
+#define SD_CCC_SWITCH           (1 << 10)\r
+\r
 #define DEVICE_STATE(x)         (((x) >> 9) & 0xf)\r
 typedef enum _EMMC_DEVICE_STATE {\r
   EMMC_IDLE_STATE = 0,\r
@@ -296,9 +304,12 @@ InitializeSdMmcDevice (
 {\r
   UINT32        CmdArg;\r
   UINT32        Response[4];\r
+  UINT32        Buffer[128];\r
   UINTN         BlockSize;\r
   UINTN         CardSize;\r
   UINTN         NumBlocks;\r
+  BOOLEAN       CccSwitch;\r
+  SCR           Scr;\r
   EFI_STATUS    Status;\r
   EFI_MMC_HOST_PROTOCOL     *MmcHost;\r
 \r
@@ -319,6 +330,11 @@ InitializeSdMmcDevice (
     return Status;\r
   }\r
   PrintCSD (Response);\r
+  if (MMC_CSD_GET_CCC(Response) & SD_CCC_SWITCH) {\r
+    CccSwitch = TRUE;\r
+  } else {\r
+    CccSwitch = FALSE;\r
+  }\r
 \r
   if (MmcHostInstance->CardInfo.CardType == SD_CARD_2_HIGH) {\r
     CardSize = HC_MMC_CSD_GET_DEVICESIZE (Response);\r
@@ -349,6 +365,96 @@ InitializeSdMmcDevice (
     return Status;\r
   }\r
 \r
+  Status = MmcHost->SendCommand (MmcHost, MMC_CMD55, CmdArg);\r
+  if (EFI_ERROR (Status)) {\r
+    DEBUG ((EFI_D_ERROR, "%a(MMC_CMD55): Error and Status = %r\n", Status));\r
+    return Status;\r
+  }\r
+  Status = MmcHost->ReceiveResponse (MmcHost, MMC_RESPONSE_TYPE_R1, Response);\r
+  if (EFI_ERROR (Status)) {\r
+    DEBUG ((EFI_D_ERROR, "%a(MMC_CMD55): Error and Status = %r\n", Status));\r
+    return Status;\r
+  }\r
+  if ((Response[0] & MMC_STATUS_APP_CMD) == 0) {\r
+    return EFI_SUCCESS;\r
+  }\r
+\r
+  /* SCR */\r
+  Status = MmcHost->SendCommand (MmcHost, MMC_ACMD51, 0);\r
+  if (EFI_ERROR (Status)) {\r
+    DEBUG ((EFI_D_ERROR, "%a(MMC_ACMD51): Error and Status = %r\n", __func__, Status));\r
+    return Status;\r
+  } else {\r
+    Status = MmcHost->ReadBlockData (MmcHost, 0, 8, Buffer);\r
+    if (EFI_ERROR (Status)) {\r
+      DEBUG ((EFI_D_ERROR, "%a(MMC_ACMD51): ReadBlockData Error and Status = %r\n", __func__, Status));\r
+      return Status;\r
+    }\r
+    CopyMem (&Scr, Buffer, 8);\r
+    if (Scr.SD_SPEC == 2) {\r
+      if (Scr.SD_SPEC3 == 1) {\r
+       if (Scr.SD_SPEC4 == 1) {\r
+          DEBUG ((EFI_D_INFO, "Found SD Card for Spec Version 4.xx\n"));\r
+       } else {\r
+          DEBUG ((EFI_D_INFO, "Found SD Card for Spec Version 3.0x\n"));\r
+       }\r
+      } else {\r
+       if (Scr.SD_SPEC4 == 0) {\r
+          DEBUG ((EFI_D_INFO, "Found SD Card for Spec Version 2.0\n"));\r
+       } else {\r
+         DEBUG ((EFI_D_ERROR, "Found invalid SD Card\n"));\r
+       }\r
+      }\r
+    } else {\r
+      if ((Scr.SD_SPEC3 == 0) && (Scr.SD_SPEC4 == 0)) {\r
+        if (Scr.SD_SPEC == 1) {\r
+         DEBUG ((EFI_D_INFO, "Found SD Card for Spec Version 1.10\n"));\r
+       } else {\r
+         DEBUG ((EFI_D_INFO, "Found SD Card for Spec Version 1.0\n"));\r
+       }\r
+      } else {\r
+        DEBUG ((EFI_D_ERROR, "Found invalid SD Card\n"));\r
+      }\r
+    }\r
+  }\r
+  if (CccSwitch) {\r
+    /* SD Switch, Mode:1, Group:0, Value:1 */\r
+    CmdArg = 1 << 31 | 0x00FFFFFF;\r
+    CmdArg &= ~(0xF << (0 * 4));\r
+    CmdArg |= 1 << (0 * 4);\r
+    Status = MmcHost->SendCommand (MmcHost, MMC_CMD6, CmdArg);\r
+    if (EFI_ERROR (Status)) {\r
+      DEBUG ((EFI_D_ERROR, "%a(MMC_CMD6): Error and Status = %r\n", Status));\r
+       return Status;\r
+    } else {\r
+      Status = MmcHost->ReadBlockData (MmcHost, 0, 64, Buffer);\r
+      if (EFI_ERROR (Status)) {\r
+        DEBUG ((EFI_D_ERROR, "%a(MMC_CMD6): ReadBlockData Error and Status = %r\n", Status));\r
+        return Status;\r
+      }\r
+    }\r
+  }\r
+  if (Scr.SD_BUS_WIDTHS & SD_BUS_WIDTH_4BIT) {\r
+    CmdArg = MmcHostInstance->CardInfo.RCA << 16;\r
+    Status = MmcHost->SendCommand (MmcHost, MMC_CMD55, CmdArg);\r
+    if (EFI_ERROR (Status)) {\r
+      DEBUG ((EFI_D_ERROR, "%a(MMC_CMD55): Error and Status = %r\n", Status));\r
+      return Status;\r
+    }\r
+    /* Width: 4 */\r
+    Status = MmcHost->SendCommand (MmcHost, MMC_CMD6, 2);\r
+    if (EFI_ERROR (Status)) {\r
+      DEBUG ((EFI_D_ERROR, "%a(MMC_CMD6): Error and Status = %r\n", Status));\r
+      return Status;\r
+    }\r
+  }\r
+  if (MMC_HOST_HAS_SETIOS(MmcHost)) {\r
+    Status = MmcHost->SetIos (MmcHost, 26 * 1000 * 1000, 4, EMMCBACKWARD);\r
+    if (EFI_ERROR (Status)) {\r
+      DEBUG ((EFI_D_ERROR, "%a(SetIos): Error and Status = %r\n", Status));\r
+      return Status;\r
+    }\r
+  }\r
   return EFI_SUCCESS;\r
 }\r
 \r