MmcDxe: Adding eMMC support
authorOlivier Martin <olivier.martin@arm.com>
Thu, 9 Jan 2014 19:06:25 +0000 (19:06 +0000)
committeroliviermartin <oliviermartin@6f19259b-4bc3-4df7-8a09-765794883524>
Thu, 9 Jan 2014 19:06:25 +0000 (19:06 +0000)
Contributed-under: TianoCore Contribution Agreement 1.0
Signed-off-by: Olivier Martin <olivier.martin@arm.com>
git-svn-id: https://svn.code.sf.net/p/edk2/code/trunk/edk2@15074 6f19259b-4bc3-4df7-8a09-765794883524

EmbeddedPkg/Include/Protocol/MmcHost.h
EmbeddedPkg/Universal/MmcDxe/Mmc.h
EmbeddedPkg/Universal/MmcDxe/MmcBlockIo.c
EmbeddedPkg/Universal/MmcDxe/MmcDxe.inf
EmbeddedPkg/Universal/MmcDxe/MmcIdentification.c [new file with mode: 0644]

index d04be65..08f2ad9 100644 (file)
@@ -1,7 +1,7 @@
 /** @file\r
   Definition of the MMC Host Protocol\r
 \r
-  Copyright (c) 2011, ARM Limited. All rights reserved.\r
+  Copyright (c) 2011-2014, ARM Limited. All rights reserved.\r
   \r
   This program and the accompanying materials                          \r
   are licensed and made available under the terms and conditions of the BSD License         \r
@@ -64,6 +64,10 @@ typedef UINT32 MMC_CMD;
 #define MMC_CMD55             (MMC_INDX(55) | MMC_CMD_WAIT_RESPONSE)\r
 #define MMC_ACMD41            (MMC_INDX(41) | MMC_CMD_WAIT_RESPONSE | MMC_CMD_NO_CRC_RESPONSE)\r
 \r
+// Valid responses for CMD1 in eMMC\r
+#define EMMC_CMD1_CAPACITY_LESS_THAN_2GB 0x00FF8080 // Capacity <= 2GB, byte addressing used\r
+#define EMMC_CMD1_CAPACITY_GREATER_THAN_2GB 0x40FF8080 // Capacity > 2GB, 512-byte sector addressing used\r
+\r
 typedef enum _MMC_STATE {\r
     MmcInvalidState = 0,\r
     MmcHwInitializationState,\r
index 9104f60..e84c3c1 100644 (file)
@@ -1,7 +1,7 @@
 /** @file\r
   Main Header file for the MMC DXE driver\r
 \r
-  Copyright (c) 2011-2013, ARM Limited. All rights reserved.\r
+  Copyright (c) 2011-2014, ARM Limited. All rights reserved.\r
   \r
   This program and the accompanying materials                          \r
   are licensed and made available under the terms and conditions of the BSD License         \r
@@ -58,6 +58,7 @@ typedef enum {
   UNKNOWN_CARD,\r
   MMC_CARD,              //MMC card\r
   MMC_CARD_HIGH,         //MMC Card with High capacity\r
+  EMMC_CARD,             //eMMC 4.41 card\r
   SD_CARD,               //SD 1.1 card\r
   SD_CARD_2,             //SD 2.0 or above standard card\r
   SD_CARD_2_HIGH         //SD 2.0 or above high capacity card\r
@@ -289,8 +290,15 @@ MmcFlushBlocks (
   IN EFI_BLOCK_IO_PROTOCOL  *This\r
   );\r
 \r
-EFI_STATUS InitializeMmcDevice (\r
-  IN  MMC_HOST_INSTANCE   *MmcHost\r
+EFI_STATUS\r
+MmcNotifyState (\r
+  IN MMC_HOST_INSTANCE      *MmcHostInstance,\r
+  IN MMC_STATE               State\r
+  );\r
+\r
+EFI_STATUS\r
+InitializeMmcDevice (\r
+  IN  MMC_HOST_INSTANCE     *MmcHost\r
   );\r
 \r
 VOID\r
index 4b9b64e..04c8261 100644 (file)
@@ -1,6 +1,6 @@
 /** @file\r
 *\r
-*  Copyright (c) 2011-2013, ARM Limited. All rights reserved.\r
+*  Copyright (c) 2011-2014, ARM Limited. All rights reserved.\r
 *\r
 *  This program and the accompanying materials\r
 *  are licensed and made available under the terms and conditions of the BSD License\r
@@ -17,9 +17,6 @@
 \r
 #include "Mmc.h"\r
 \r
-#define MAX_RETRY_COUNT  1000\r
-#define CMD_RETRY_COUNT  20\r
-\r
 EFI_STATUS\r
 MmcNotifyState (\r
   IN MMC_HOST_INSTANCE *MmcHostInstance,\r
@@ -65,259 +62,6 @@ MmcGetCardStatus (
   return Status;\r
 }\r
 \r
-EFI_STATUS\r
-EFIAPI\r
-MmcIdentificationMode (\r
-  IN MMC_HOST_INSTANCE     *MmcHostInstance\r
-  )\r
-{\r
-  EFI_STATUS              Status;\r
-  UINT32                  Response[4];\r
-  UINTN                   Timeout;\r
-  UINTN                   CmdArg;\r
-  BOOLEAN                 IsHCS;\r
-  EFI_MMC_HOST_PROTOCOL   *MmcHost;\r
-\r
-  MmcHost = MmcHostInstance->MmcHost;\r
-  CmdArg = 0;\r
-  IsHCS = FALSE;\r
-\r
-  if (MmcHost == NULL) {\r
-    return EFI_INVALID_PARAMETER;\r
-  }\r
-\r
-  // We can get into this function if we restart the identification mode\r
-  if (MmcHostInstance->State == MmcHwInitializationState) {\r
-    // Initialize the MMC Host HW\r
-    Status = MmcNotifyState (MmcHostInstance, MmcHwInitializationState);\r
-    if (EFI_ERROR (Status)) {\r
-      DEBUG ((EFI_D_ERROR, "MmcIdentificationMode() : Error MmcHwInitializationState\n"));\r
-      return Status;\r
-    }\r
-  }\r
-\r
-  Status = MmcHost->SendCommand (MmcHost, MMC_CMD0, 0);\r
-  if (EFI_ERROR (Status)) {\r
-    DEBUG ((EFI_D_ERROR, "MmcIdentificationMode(MMC_CMD0): Error\n"));\r
-    return Status;\r
-  }\r
-\r
-  Status = MmcNotifyState (MmcHostInstance, MmcIdleState);\r
-  if (EFI_ERROR (Status)) {\r
-    DEBUG ((EFI_D_ERROR, "MmcIdentificationMode() : Error MmcIdleState\n"));\r
-    return Status;\r
-  }\r
-\r
-  // Are we using SDIO ?\r
-  Status = MmcHost->SendCommand (MmcHost, MMC_CMD5, 0);\r
-  if (Status == EFI_SUCCESS) {\r
-    DEBUG ((EFI_D_ERROR, "MmcIdentificationMode(MMC_CMD5): Error - SDIO not supported.\n"));\r
-    return EFI_UNSUPPORTED;\r
-  }\r
-\r
-  // Check which kind of card we are using. Ver2.00 or later SD Memory Card (PL180 is SD v1.1)\r
-  CmdArg = (0x0UL << 12 | BIT8 | 0xCEUL << 0);\r
-  Status = MmcHost->SendCommand (MmcHost, MMC_CMD8, CmdArg);\r
-  if (Status == EFI_SUCCESS) {\r
-    DEBUG ((EFI_D_ERROR, "Card is SD2.0 => Supports high capacity\n"));\r
-    IsHCS = TRUE;\r
-    MmcHost->ReceiveResponse (MmcHost, MMC_RESPONSE_TYPE_R7, Response);\r
-    PrintResponseR1 (Response[0]);\r
-    //check if it is valid response\r
-    if (Response[0] != CmdArg) {\r
-      DEBUG ((EFI_D_ERROR, "The Card is not usable\n"));\r
-      return EFI_UNSUPPORTED;\r
-    }\r
-  } else {\r
-    DEBUG ((EFI_D_ERROR, "Not a SD2.0 Card\n"));\r
-  }\r
-\r
-  // We need to wait for the MMC or SD card is ready => (gCardInfo.OCRData.PowerUp == 1)\r
-  Timeout = MAX_RETRY_COUNT;\r
-  while (Timeout > 0) {\r
-    // SD Card or MMC Card ? CMD55 indicates to the card that the next command is an application specific command\r
-    Status = MmcHost->SendCommand (MmcHost, MMC_CMD55, 0);\r
-    if (Status == EFI_SUCCESS) {\r
-      DEBUG ((EFI_D_INFO, "Card should be SD\n"));\r
-      if (IsHCS) {\r
-        MmcHostInstance->CardInfo.CardType = SD_CARD_2;\r
-      } else {\r
-        MmcHostInstance->CardInfo.CardType = SD_CARD;\r
-      }\r
-\r
-      // Note: The first time CmdArg will be zero\r
-      CmdArg = ((UINTN *) &(MmcHostInstance->CardInfo.OCRData))[0];\r
-      if (IsHCS) {\r
-        CmdArg |= BIT30;\r
-      }\r
-      Status = MmcHost->SendCommand (MmcHost, MMC_ACMD41, CmdArg);\r
-      if (!EFI_ERROR (Status)) {\r
-        MmcHost->ReceiveResponse (MmcHost, MMC_RESPONSE_TYPE_OCR, Response);\r
-        ((UINT32 *) &(MmcHostInstance->CardInfo.OCRData))[0] = Response[0];\r
-      }\r
-    } else {\r
-      DEBUG ((EFI_D_INFO, "Card should be MMC\n"));\r
-      MmcHostInstance->CardInfo.CardType = MMC_CARD;\r
-\r
-      Status = MmcHost->SendCommand (MmcHost, MMC_CMD1, 0x800000);\r
-      if (!EFI_ERROR (Status)) {\r
-        MmcHost->ReceiveResponse (MmcHost, MMC_RESPONSE_TYPE_OCR, Response);\r
-        ((UINT32 *) &(MmcHostInstance->CardInfo.OCRData))[0] = Response[0];\r
-      }\r
-    }\r
-\r
-    if (!EFI_ERROR (Status)) {\r
-      if (!MmcHostInstance->CardInfo.OCRData.PowerUp) {\r
-        MicroSecondDelay (1);\r
-        Timeout--;\r
-      } else {\r
-        if ((MmcHostInstance->CardInfo.CardType == SD_CARD_2) && (MmcHostInstance->CardInfo.OCRData.AccessMode & BIT1)) {\r
-          MmcHostInstance->CardInfo.CardType = SD_CARD_2_HIGH;\r
-          DEBUG ((EFI_D_ERROR, "High capacity card.\n"));\r
-        }\r
-        break;  // The MMC/SD card is ready. Continue the Identification Mode\r
-      }\r
-    } else {\r
-      MicroSecondDelay (1);\r
-      Timeout--;\r
-    }\r
-  }\r
-\r
-  if (Timeout == 0) {\r
-    DEBUG ((EFI_D_ERROR, "MmcIdentificationMode(): No Card\n"));\r
-    return EFI_NO_MEDIA;\r
-  } else {\r
-    PrintOCR (Response[0]);\r
-  }\r
-\r
-  Status = MmcNotifyState (MmcHostInstance, MmcReadyState);\r
-  if (EFI_ERROR (Status)) {\r
-    DEBUG ((EFI_D_ERROR, "MmcIdentificationMode() : Error MmcReadyState\n"));\r
-    return Status;\r
-  }\r
-\r
-  Status = MmcHost->SendCommand (MmcHost, MMC_CMD2, 0);\r
-  if (EFI_ERROR (Status)) {\r
-    DEBUG ((EFI_D_ERROR, "MmcIdentificationMode(MMC_CMD2): Error\n"));\r
-    return Status;\r
-  }\r
-  MmcHost->ReceiveResponse (MmcHost, MMC_RESPONSE_TYPE_CID, Response);\r
-  PrintCID (Response);\r
-\r
-  Status = MmcNotifyState (MmcHostInstance, MmcIdentificationState);\r
-  if (EFI_ERROR (Status)) {\r
-    DEBUG ((EFI_D_ERROR, "MmcIdentificationMode() : Error MmcIdentificationState\n"));\r
-    return Status;\r
-  }\r
-\r
-  //\r
-  // Note, SD specifications say that "if the command execution causes a state change, it\r
-  // will be visible to the host in the response to the next command"\r
-  // The status returned for this CMD3 will be 2 - identification\r
-  //\r
-  CmdArg = 1;\r
-  Status = MmcHost->SendCommand (MmcHost, MMC_CMD3, CmdArg);\r
-  if (EFI_ERROR (Status)) {\r
-    DEBUG ((EFI_D_ERROR, "MmcIdentificationMode(MMC_CMD3): Error\n"));\r
-    return Status;\r
-  }\r
-\r
-  MmcHost->ReceiveResponse (MmcHost, MMC_RESPONSE_TYPE_RCA, Response);\r
-  PrintRCA (Response[0]);\r
-\r
-  // For MMC card, RCA is assigned by CMD3 while CMD3 dumps the RCA for SD card\r
-  if (MmcHostInstance->CardInfo.CardType != MMC_CARD) {\r
-    MmcHostInstance->CardInfo.RCA = Response[0] >> 16;\r
-  } else {\r
-    MmcHostInstance->CardInfo.RCA = CmdArg;\r
-  }\r
-\r
-  Status = MmcNotifyState (MmcHostInstance, MmcStandByState);\r
-  if (EFI_ERROR (Status)) {\r
-    DEBUG ((EFI_D_ERROR, "MmcIdentificationMode() : Error MmcStandByState\n"));\r
-    return Status;\r
-  }\r
-\r
-  return EFI_SUCCESS;\r
-}\r
-\r
-EFI_STATUS InitializeMmcDevice (\r
-  IN  MMC_HOST_INSTANCE   *MmcHostInstance\r
-  )\r
-{\r
-  UINT32                  Response[4];\r
-  EFI_STATUS              Status;\r
-  UINTN                   CardSize, NumBlocks, BlockSize, CmdArg;\r
-  EFI_MMC_HOST_PROTOCOL   *MmcHost;\r
-  UINTN                   BlockCount;\r
-\r
-  BlockCount = 1;\r
-  MmcHost = MmcHostInstance->MmcHost;\r
-\r
-  MmcIdentificationMode (MmcHostInstance);\r
-\r
-  //Send a command to get Card specific data\r
-  CmdArg = MmcHostInstance->CardInfo.RCA << 16;\r
-  Status = MmcHost->SendCommand (MmcHost, MMC_CMD9, CmdArg);\r
-  if (EFI_ERROR (Status)) {\r
-    DEBUG((EFI_D_ERROR, "InitializeMmcDevice(MMC_CMD9): Error, Status=%r\n", Status));\r
-    return Status;\r
-  }\r
-  //Read Response\r
-  MmcHost->ReceiveResponse (MmcHost, MMC_RESPONSE_TYPE_CSD, Response);\r
-  PrintCSD (Response);\r
-\r
-  if (MmcHostInstance->CardInfo.CardType == SD_CARD_2_HIGH) {\r
-    CardSize = HC_MMC_CSD_GET_DEVICESIZE (Response);\r
-    NumBlocks = ((CardSize + 1) * 1024);\r
-    BlockSize = 1 << MMC_CSD_GET_READBLLEN (Response);\r
-  } else {\r
-    CardSize = MMC_CSD_GET_DEVICESIZE (Response);\r
-    NumBlocks = (CardSize + 1) * (1 << (MMC_CSD_GET_DEVICESIZEMULT (Response) + 2));\r
-    BlockSize = 1 << MMC_CSD_GET_READBLLEN (Response);\r
-  }\r
-\r
-  //For >=2G card, BlockSize may be 1K, but the transfer size is 512 bytes.\r
-  if (BlockSize > 512) {\r
-    NumBlocks = MultU64x32 (NumBlocks, BlockSize/512);\r
-    BlockSize = 512;\r
-  }\r
-\r
-  MmcHostInstance->BlockIo.Media->LastBlock    = (NumBlocks - 1);\r
-  MmcHostInstance->BlockIo.Media->BlockSize    = BlockSize;\r
-  MmcHostInstance->BlockIo.Media->ReadOnly     = MmcHost->IsReadOnly (MmcHost);\r
-  MmcHostInstance->BlockIo.Media->MediaPresent = TRUE;\r
-  MmcHostInstance->BlockIo.Media->MediaId++;\r
-\r
-  CmdArg = MmcHostInstance->CardInfo.RCA << 16;\r
-  Status = MmcHost->SendCommand (MmcHost, MMC_CMD7, CmdArg);\r
-  if (EFI_ERROR (Status)) {\r
-    DEBUG((EFI_D_ERROR, "InitializeMmcDevice(MMC_CMD7): Error and Status = %r\n", Status));\r
-    return Status;\r
-  }\r
-\r
-  Status = MmcNotifyState (MmcHostInstance, MmcTransferState);\r
-  if (EFI_ERROR (Status)) {\r
-    DEBUG((EFI_D_ERROR, "InitializeMmcDevice(): Error MmcTransferState\n"));\r
-    return Status;\r
-  }\r
-\r
-  // Set Block Length\r
-  Status = MmcHost->SendCommand (MmcHost, MMC_CMD16, MmcHostInstance->BlockIo.Media->BlockSize);\r
-  if (EFI_ERROR (Status)) {\r
-    DEBUG((EFI_D_ERROR, "InitializeMmcDevice(MMC_CMD16): Error MmcHostInstance->BlockIo.Media->BlockSize: %d and Error = %r\n",\r
-                        MmcHostInstance->BlockIo.Media->BlockSize, Status));\r
-    return Status;\r
-  }\r
-\r
-  // Block Count (not used). Could return an error for SD card\r
-  if (MmcHostInstance->CardInfo.CardType == MMC_CARD) {\r
-    MmcHost->SendCommand (MmcHost, MMC_CMD23, BlockCount);\r
-  }\r
-\r
-  return EFI_SUCCESS;\r
-}\r
-\r
 EFI_STATUS\r
 EFIAPI\r
 MmcReset (\r
index 80e15bb..069b8c7 100644 (file)
@@ -1,7 +1,7 @@
 #/** @file\r
 #  Build file for the MMC DXE driver\r
 #\r
-#  Copyright (c) 2011-2013, ARM Limited. All rights reserved.\r
+#  Copyright (c) 2011-2014, ARM Limited. All rights reserved.\r
 #  \r
 #  This program and the accompanying materials                          \r
 #  are licensed and made available under the terms and conditions of the BSD License         \r
@@ -26,6 +26,7 @@
   ComponentName.c\r
   Mmc.c\r
   MmcBlockIo.c\r
+  MmcIdentification.c\r
   MmcDebug.c\r
   Diagnostics.c\r
 \r
@@ -48,4 +49,4 @@
   gEfiDriverDiagnostics2ProtocolGuid\r
   \r
 [Depex]\r
-  TRUE\r
\ No newline at end of file
+  TRUE\r\r
diff --git a/EmbeddedPkg/Universal/MmcDxe/MmcIdentification.c b/EmbeddedPkg/Universal/MmcDxe/MmcIdentification.c
new file mode 100644 (file)
index 0000000..32efe19
--- /dev/null
@@ -0,0 +1,456 @@
+/** @file\r
+*\r
+*  Copyright (c) 2011-2014, ARM Limited. All rights reserved.\r
+*\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
+*\r
+**/\r
+\r
+#include <Library/TimerLib.h>\r
+\r
+#include "Mmc.h"\r
+\r
+typedef union {\r
+  UINT32 Raw;\r
+  OCR    Ocr;\r
+} OCR_RESPONSE;\r
+\r
+#define MAX_RETRY_COUNT         1000\r
+#define CMD_RETRY_COUNT         20\r
+#define RCA_SHIFT_OFFSET        16\r
+#define EMMC_CARD_SIZE          512\r
+#define EMMC_ECSD_SIZE_OFFSET   53\r
+\r
+UINT32 mEmmcRcaCount = 0;\r
+\r
+STATIC\r
+EFI_STATUS\r
+EFIAPI\r
+EmmcIdentificationMode (\r
+  IN MMC_HOST_INSTANCE     *MmcHostInstance,\r
+  IN OCR_RESPONSE           Response\r
+  )\r
+{\r
+  EFI_MMC_HOST_PROTOCOL *Host;\r
+  EFI_BLOCK_IO_MEDIA    *Media;\r
+  EFI_STATUS Status;\r
+  UINT32     RCA;\r
+  UINT32     ECSD[128];\r
+\r
+  Host  = MmcHostInstance->MmcHost;\r
+  Media = MmcHostInstance->BlockIo.Media;\r
+\r
+  // Fetch card identity register\r
+  Status = Host->SendCommand (Host, MMC_CMD2, 0);\r
+  if (EFI_ERROR (Status)) {\r
+    DEBUG ((EFI_D_ERROR, "EmmcIdentificationMode(): Failed to send CMD2, Status=%r.\n", Status));\r
+    return Status;\r
+  }\r
+\r
+  Status = Host->ReceiveResponse (Host, MMC_RESPONSE_TYPE_R2, (UINT32 *)&(MmcHostInstance->CardInfo.CIDData));\r
+  if (EFI_ERROR (Status)) {\r
+    DEBUG ((EFI_D_ERROR, "EmmcIdentificationMode(): CID retrieval error, Status=%r.\n", Status));\r
+    return Status;\r
+  }\r
+\r
+  // Assign a relative address value to the card\r
+  MmcHostInstance->CardInfo.RCA = ++mEmmcRcaCount; // TODO: might need a more sophisticated way of doing this\r
+  RCA = MmcHostInstance->CardInfo.RCA << RCA_SHIFT_OFFSET;\r
+  Status = Host->SendCommand (Host, MMC_CMD3, RCA);\r
+  if (EFI_ERROR (Status)) {\r
+    DEBUG ((EFI_D_ERROR, "EmmcIdentificationMode(): RCA set error, Status=%r.\n", Status));\r
+    return Status;\r
+  }\r
+\r
+  // Fetch card specific data\r
+  Status = Host->SendCommand (Host, MMC_CMD9, RCA);\r
+  if (EFI_ERROR (Status)) {\r
+    DEBUG ((EFI_D_ERROR, "EmmcIdentificationMode(): Failed to send CMD9, Status=%r.\n", Status));\r
+    return Status;\r
+  }\r
+\r
+  Status = Host->ReceiveResponse (Host, MMC_RESPONSE_TYPE_R2, (UINT32 *)&(MmcHostInstance->CardInfo.CSDData));\r
+  if (EFI_ERROR (Status)) {\r
+    DEBUG ((EFI_D_ERROR, "EmmcIdentificationMode(): CSD retrieval error, Status=%r.\n", Status));\r
+    return Status;\r
+  }\r
+\r
+  // Select the card\r
+  Status = Host->SendCommand (Host, MMC_CMD7, RCA);\r
+  if (EFI_ERROR (Status)) {\r
+    DEBUG ((EFI_D_ERROR, "EmmcIdentificationMode(): Card selection error, Status=%r.\n", Status));\r
+  }\r
+\r
+  // Fetch ECSD\r
+  Status = Host->SendCommand (Host, MMC_CMD8, RCA);\r
+  if (EFI_ERROR (Status)) {\r
+    DEBUG ((EFI_D_ERROR, "EmmcIdentificationMode(): ECSD fetch error, Status=%r.\n", Status));\r
+  }\r
+\r
+  Status = Host->ReadBlockData (Host, 0, 512, ECSD);\r
+  if (EFI_ERROR (Status)) {\r
+    DEBUG ((EFI_D_ERROR, "EmmcIdentificationMode(): ECSD read error, Status=%r.\n", Status));\r
+    return Status;\r
+  }\r
+\r
+  // Set up media\r
+  Media->BlockSize = EMMC_CARD_SIZE; // 512-byte support is mandatory for eMMC cards\r
+  Media->MediaId = MmcHostInstance->CardInfo.CIDData.PSN;\r
+  Media->ReadOnly = MmcHostInstance->CardInfo.CSDData.PERM_WRITE_PROTECT;\r
+  Media->LogicalBlocksPerPhysicalBlock = 1;\r
+  Media->IoAlign = 4;\r
+  // Compute last block using bits [215:212] of the ECSD\r
+  Media->LastBlock = ECSD[EMMC_ECSD_SIZE_OFFSET] - 1; // eMMC isn't supposed to report this for\r
+  // Cards <2GB in size, but the model does.\r
+\r
+  // Setup card type\r
+  MmcHostInstance->CardInfo.CardType = EMMC_CARD;\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+STATIC\r
+EFI_STATUS\r
+InitializeSdMmcDevice (\r
+  IN  MMC_HOST_INSTANCE   *MmcHostInstance\r
+  )\r
+{\r
+  UINT32        CmdArg;\r
+  UINT32        Response[4];\r
+  UINTN         BlockSize;\r
+  UINTN         CardSize;\r
+  UINTN         NumBlocks;\r
+  EFI_STATUS    Status;\r
+  EFI_MMC_HOST_PROTOCOL     *MmcHost;\r
+\r
+  MmcHost = MmcHostInstance->MmcHost;\r
+\r
+  // Send a command to get Card specific data\r
+  CmdArg = MmcHostInstance->CardInfo.RCA << 16;\r
+  Status = MmcHost->SendCommand (MmcHost, MMC_CMD9, CmdArg);\r
+  if (EFI_ERROR (Status)) {\r
+    DEBUG((EFI_D_ERROR, "InitializeSdMmcDevice(MMC_CMD9): Error, Status=%r\n", Status));\r
+    return Status;\r
+  }\r
+\r
+  // Read Response\r
+  Status = MmcHost->ReceiveResponse (MmcHost, MMC_RESPONSE_TYPE_CSD, Response);\r
+  if (EFI_ERROR (Status)) {\r
+    DEBUG((EFI_D_ERROR, "InitializeSdMmcDevice(): Failed to receive CSD, Status=%r\n", Status));\r
+    return Status;\r
+  }\r
+  PrintCSD (Response);\r
+\r
+  if (MmcHostInstance->CardInfo.CardType == SD_CARD_2_HIGH) {\r
+    CardSize = HC_MMC_CSD_GET_DEVICESIZE (Response);\r
+    NumBlocks = ((CardSize + 1) * 1024);\r
+    BlockSize = 1 << MMC_CSD_GET_READBLLEN (Response);\r
+  } else {\r
+    CardSize = MMC_CSD_GET_DEVICESIZE (Response);\r
+    NumBlocks = (CardSize + 1) * (1 << (MMC_CSD_GET_DEVICESIZEMULT (Response) + 2));\r
+    BlockSize = 1 << MMC_CSD_GET_READBLLEN (Response);\r
+  }\r
+\r
+  // For >=2G card, BlockSize may be 1K, but the transfer size is 512 bytes.\r
+  if (BlockSize > 512) {\r
+    NumBlocks = MultU64x32 (NumBlocks, BlockSize / 512);\r
+    BlockSize = 512;\r
+  }\r
+\r
+  MmcHostInstance->BlockIo.Media->LastBlock    = (NumBlocks - 1);\r
+  MmcHostInstance->BlockIo.Media->BlockSize    = BlockSize;\r
+  MmcHostInstance->BlockIo.Media->ReadOnly     = MmcHost->IsReadOnly (MmcHost);\r
+  MmcHostInstance->BlockIo.Media->MediaPresent = TRUE;\r
+  MmcHostInstance->BlockIo.Media->MediaId++;\r
+\r
+  CmdArg = MmcHostInstance->CardInfo.RCA << 16;\r
+  Status = MmcHost->SendCommand (MmcHost, MMC_CMD7, CmdArg);\r
+  if (EFI_ERROR (Status)) {\r
+    DEBUG((EFI_D_ERROR, "InitializeSdMmcDevice(MMC_CMD7): Error and Status = %r\n", Status));\r
+    return Status;\r
+  }\r
+\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+STATIC\r
+EFI_STATUS\r
+EFIAPI\r
+MmcIdentificationMode (\r
+  IN MMC_HOST_INSTANCE     *MmcHostInstance\r
+  )\r
+{\r
+  EFI_STATUS              Status;\r
+  UINT32                  Response[4];\r
+  UINTN                   Timeout;\r
+  UINTN                   CmdArg;\r
+  BOOLEAN                 IsHCS;\r
+  EFI_MMC_HOST_PROTOCOL   *MmcHost;\r
+  OCR_RESPONSE            OcrResponse;\r
+\r
+  MmcHost = MmcHostInstance->MmcHost;\r
+  CmdArg = 0;\r
+  IsHCS = FALSE;\r
+\r
+  if (MmcHost == NULL) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  // We can get into this function if we restart the identification mode\r
+  if (MmcHostInstance->State == MmcHwInitializationState) {\r
+    // Initialize the MMC Host HW\r
+    Status = MmcNotifyState (MmcHostInstance, MmcHwInitializationState);\r
+    if (EFI_ERROR (Status)) {\r
+      DEBUG ((EFI_D_ERROR, "MmcIdentificationMode() : Error MmcHwInitializationState, Status=%r.\n", Status));\r
+      return Status;\r
+    }\r
+  }\r
+\r
+  Status = MmcHost->SendCommand (MmcHost, MMC_CMD0, 0);\r
+  if (EFI_ERROR (Status)) {\r
+    DEBUG ((EFI_D_ERROR, "MmcIdentificationMode(MMC_CMD0): Error, Status=%r.\n", Status));\r
+    return Status;\r
+  }\r
+  Status = MmcNotifyState (MmcHostInstance, MmcIdleState);\r
+  if (EFI_ERROR (Status)) {\r
+    DEBUG ((EFI_D_ERROR, "MmcIdentificationMode() : Error MmcIdleState, Status=%r.\n", Status));\r
+    return Status;\r
+  }\r
+\r
+  // Send CMD1 to get OCR (SD / MMC)\r
+  Status = MmcHost->SendCommand (MmcHost, MMC_CMD1, EMMC_CMD1_CAPACITY_GREATER_THAN_2GB);\r
+  if (Status == EFI_SUCCESS) {\r
+    Status = MmcHost->ReceiveResponse (MmcHost, MMC_RESPONSE_TYPE_OCR, (UINT32 *)&OcrResponse);\r
+    if (EFI_ERROR (Status)) {\r
+      DEBUG ((EFI_D_ERROR, "MmcIdentificationMode() : Failed to receive OCR, Status=%r.\n", Status));\r
+      return Status;\r
+    }\r
+\r
+    if (!OcrResponse.Ocr.PowerUp) {\r
+      DEBUG ((EFI_D_ERROR, "MmcIdentificationMode(MMC_CMD1): Card initialisation failure, Status=%r.\n", Status));\r
+      return EFI_DEVICE_ERROR;\r
+    }\r
+    OcrResponse.Ocr.PowerUp = 0;\r
+    if (OcrResponse.Raw == EMMC_CMD1_CAPACITY_GREATER_THAN_2GB) {\r
+      MmcHostInstance->CardInfo.OCRData.AccessMode = BIT1;\r
+    }\r
+    else {\r
+      MmcHostInstance->CardInfo.OCRData.AccessMode = 0x0;\r
+    }\r
+    if (OcrResponse.Raw == EMMC_CMD1_CAPACITY_GREATER_THAN_2GB ||\r
+        OcrResponse.Raw == EMMC_CMD1_CAPACITY_LESS_THAN_2GB) {\r
+      return EmmcIdentificationMode (MmcHostInstance, OcrResponse);\r
+    }\r
+  } else {\r
+    DEBUG ((EFI_D_ERROR, "MmcIdentificationMode(MMC_CMD1) : Failed to send command, Status=%r.\n", Status));\r
+    return Status;\r
+  }\r
+\r
+  // Are we using SDIO ?\r
+  Status = MmcHost->SendCommand (MmcHost, MMC_CMD5, 0);\r
+  if (Status == EFI_SUCCESS) {\r
+    DEBUG ((EFI_D_ERROR, "MmcIdentificationMode(MMC_CMD5): Error - SDIO not supported, Status=%r.\n", Status));\r
+    return EFI_UNSUPPORTED;\r
+  }\r
+\r
+  // Check which kind of card we are using. Ver2.00 or later SD Memory Card (PL180 is SD v1.1)\r
+  CmdArg = (0x0UL << 12 | BIT8 | 0xCEUL << 0);\r
+  Status = MmcHost->SendCommand (MmcHost, MMC_CMD8, CmdArg);\r
+  if (Status == EFI_SUCCESS) {\r
+    DEBUG ((EFI_D_ERROR, "Card is SD2.0 => Supports high capacity\n"));\r
+    IsHCS = TRUE;\r
+    Status = MmcHost->ReceiveResponse (MmcHost, MMC_RESPONSE_TYPE_R7, Response);\r
+    if (EFI_ERROR (Status)) {\r
+      DEBUG ((EFI_D_ERROR, "MmcIdentificationMode() : Failed to receive response to CMD8, Status=%r.\n", Status));\r
+      return Status;\r
+    }\r
+    PrintResponseR1 (Response[0]);\r
+    // Check if it is valid response\r
+    if (Response[0] != CmdArg) {\r
+      DEBUG ((EFI_D_ERROR, "The Card is not usable\n"));\r
+      return EFI_UNSUPPORTED;\r
+    }\r
+  } else {\r
+    DEBUG ((EFI_D_ERROR, "Not a SD2.0 Card\n"));\r
+  }\r
+\r
+  // We need to wait for the MMC or SD card is ready => (gCardInfo.OCRData.PowerUp == 1)\r
+  Timeout = MAX_RETRY_COUNT;\r
+  while (Timeout > 0) {\r
+    // SD Card or MMC Card ? CMD55 indicates to the card that the next command is an application specific command\r
+    Status = MmcHost->SendCommand (MmcHost, MMC_CMD55, 0);\r
+    if (Status == EFI_SUCCESS) {\r
+      DEBUG ((EFI_D_INFO, "Card should be SD\n"));\r
+      if (IsHCS) {\r
+        MmcHostInstance->CardInfo.CardType = SD_CARD_2;\r
+      } else {\r
+        MmcHostInstance->CardInfo.CardType = SD_CARD;\r
+      }\r
+\r
+      // Note: The first time CmdArg will be zero\r
+      CmdArg = ((UINTN *) &(MmcHostInstance->CardInfo.OCRData))[0];\r
+      if (IsHCS) {\r
+        CmdArg |= BIT30;\r
+      }\r
+      Status = MmcHost->SendCommand (MmcHost, MMC_ACMD41, CmdArg);\r
+      if (!EFI_ERROR (Status)) {\r
+        Status = MmcHost->ReceiveResponse (MmcHost, MMC_RESPONSE_TYPE_OCR, Response);\r
+        if (EFI_ERROR (Status)) {\r
+          DEBUG ((EFI_D_ERROR, "MmcIdentificationMode() : Failed to receive OCR, Status=%r.\n", Status));\r
+          return Status;\r
+        }\r
+        ((UINT32 *) &(MmcHostInstance->CardInfo.OCRData))[0] = Response[0];\r
+      }\r
+    } else {\r
+      DEBUG ((EFI_D_INFO, "Card should be MMC\n"));\r
+      MmcHostInstance->CardInfo.CardType = MMC_CARD;\r
+\r
+      Status = MmcHost->SendCommand (MmcHost, MMC_CMD1, 0x800000);\r
+      if (!EFI_ERROR (Status)) {\r
+        Status = MmcHost->ReceiveResponse (MmcHost, MMC_RESPONSE_TYPE_OCR, Response);\r
+        if (EFI_ERROR (Status)) {\r
+          DEBUG ((EFI_D_ERROR, "MmcIdentificationMode() : Failed to receive OCR, Status=%r.\n", Status));\r
+          return Status;\r
+        }\r
+        ((UINT32 *) &(MmcHostInstance->CardInfo.OCRData))[0] = Response[0];\r
+      }\r
+    }\r
+\r
+    if (!EFI_ERROR (Status)) {\r
+      if (!MmcHostInstance->CardInfo.OCRData.PowerUp) {\r
+        MicroSecondDelay (1);\r
+        Timeout--;\r
+      } else {\r
+        if ((MmcHostInstance->CardInfo.CardType == SD_CARD_2) && (MmcHostInstance->CardInfo.OCRData.AccessMode & BIT1)) {\r
+          MmcHostInstance->CardInfo.CardType = SD_CARD_2_HIGH;\r
+          DEBUG ((EFI_D_ERROR, "High capacity card.\n"));\r
+        }\r
+        break;  // The MMC/SD card is ready. Continue the Identification Mode\r
+      }\r
+    } else {\r
+      MicroSecondDelay (1);\r
+      Timeout--;\r
+    }\r
+  }\r
+\r
+  if (Timeout == 0) {\r
+    DEBUG ((EFI_D_ERROR, "MmcIdentificationMode(): No Card\n"));\r
+    return EFI_NO_MEDIA;\r
+  } else {\r
+    PrintOCR (Response[0]);\r
+  }\r
+\r
+  Status = MmcNotifyState (MmcHostInstance, MmcReadyState);\r
+  if (EFI_ERROR (Status)) {\r
+    DEBUG ((EFI_D_ERROR, "MmcIdentificationMode() : Error MmcReadyState\n"));\r
+    return Status;\r
+  }\r
+\r
+  Status = MmcHost->SendCommand (MmcHost, MMC_CMD2, 0);\r
+  if (EFI_ERROR (Status)) {\r
+    DEBUG ((EFI_D_ERROR, "MmcIdentificationMode(MMC_CMD2): Error\n"));\r
+    return Status;\r
+  }\r
+  Status = MmcHost->ReceiveResponse (MmcHost, MMC_RESPONSE_TYPE_CID, Response);\r
+  if (EFI_ERROR (Status)) {\r
+    DEBUG ((EFI_D_ERROR, "MmcIdentificationMode() : Failed to receive CID, Status=%r.\n", Status));\r
+    return Status;\r
+  }\r
+\r
+  PrintCID (Response);\r
+\r
+  Status = MmcHost->NotifyState (MmcHost, MmcIdentificationState);\r
+  if (EFI_ERROR (Status)) {\r
+    DEBUG ((EFI_D_ERROR, "MmcIdentificationMode() : Error MmcIdentificationState\n"));\r
+    return Status;\r
+  }\r
+\r
+  //\r
+  // Note, SD specifications say that "if the command execution causes a state change, it\r
+  // will be visible to the host in the response to the next command"\r
+  // The status returned for this CMD3 will be 2 - identification\r
+  //\r
+  CmdArg = 1;\r
+  Status = MmcHost->SendCommand (MmcHost, MMC_CMD3, CmdArg);\r
+  if (EFI_ERROR (Status)) {\r
+    DEBUG ((EFI_D_ERROR, "MmcIdentificationMode(MMC_CMD3): Error\n"));\r
+    return Status;\r
+  }\r
+\r
+  Status = MmcHost->ReceiveResponse (MmcHost, MMC_RESPONSE_TYPE_RCA, Response);\r
+  if (EFI_ERROR (Status)) {\r
+    DEBUG ((EFI_D_ERROR, "MmcIdentificationMode() : Failed to receive RCA, Status=%r.\n", Status));\r
+    return Status;\r
+  }\r
+  PrintRCA (Response[0]);\r
+\r
+  // For MMC card, RCA is assigned by CMD3 while CMD3 dumps the RCA for SD card\r
+  if (MmcHostInstance->CardInfo.CardType != MMC_CARD) {\r
+    MmcHostInstance->CardInfo.RCA = Response[0] >> 16;\r
+  } else {\r
+    MmcHostInstance->CardInfo.RCA = CmdArg;\r
+  }\r
+  Status = MmcNotifyState (MmcHostInstance, MmcStandByState);\r
+  if (EFI_ERROR (Status)) {\r
+    DEBUG ((EFI_D_ERROR, "MmcIdentificationMode() : Error MmcStandByState\n"));\r
+    return Status;\r
+  }\r
+\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+EFI_STATUS\r
+InitializeMmcDevice (\r
+  IN  MMC_HOST_INSTANCE   *MmcHostInstance\r
+  )\r
+{\r
+  EFI_STATUS              Status;\r
+  EFI_MMC_HOST_PROTOCOL   *MmcHost;\r
+  UINTN                   BlockCount;\r
+\r
+  BlockCount = 1;\r
+  MmcHost = MmcHostInstance->MmcHost;\r
+\r
+  Status = MmcIdentificationMode (MmcHostInstance);\r
+  if (EFI_ERROR (Status)) {\r
+    DEBUG((EFI_D_ERROR, "InitializeMmcDevice(): Error in Identification Mode, Status=%r\n", Status));\r
+    return Status;\r
+  }\r
+\r
+  Status = MmcNotifyState (MmcHostInstance, MmcTransferState);\r
+  if (EFI_ERROR (Status)) {\r
+    DEBUG((EFI_D_ERROR, "InitializeMmcDevice(): Error MmcTransferState, Status=%r\n", Status));\r
+    return Status;\r
+  }\r
+\r
+  if (MmcHostInstance->CardInfo.CardType != EMMC_CARD) {\r
+    Status = InitializeSdMmcDevice (MmcHostInstance);\r
+    if (EFI_ERROR (Status)) {\r
+      return Status;\r
+    }\r
+  }\r
+\r
+  // Set Block Length\r
+  Status = MmcHost->SendCommand (MmcHost, MMC_CMD16, MmcHostInstance->BlockIo.Media->BlockSize);\r
+  if (EFI_ERROR (Status)) {\r
+    DEBUG((EFI_D_ERROR, "InitializeMmcDevice(MMC_CMD16): Error MmcHostInstance->BlockIo.Media->BlockSize: %d and Error = %r\n",\r
+                        MmcHostInstance->BlockIo.Media->BlockSize, Status));\r
+    return Status;\r
+  }\r
+\r
+  // Block Count (not used). Could return an error for SD card\r
+  if (MmcHostInstance->CardInfo.CardType == MMC_CARD) {\r
+    Status = MmcHost->SendCommand (MmcHost, MMC_CMD23, BlockCount);\r
+    if (EFI_ERROR (Status)) {\r
+      DEBUG((EFI_D_ERROR, "InitializeMmcDevice(MMC_CMD23): Error, Status=%r\n", Status));\r
+      return Status;\r
+    }\r
+  }\r
+\r
+  return EFI_SUCCESS;\r
+}\r