]> git.proxmox.com Git - mirror_edk2.git/commitdiff
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 d04be6595c31799b1cc49099fad3569b7bf02ae8..08f2ad93498eb0d19ef6c365b6e5989b72fc1ff2 100644 (file)
@@ -1,7 +1,7 @@
 /** @file\r
   Definition of the MMC Host Protocol\r
 \r
 /** @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
   \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
 #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
 typedef enum _MMC_STATE {\r
     MmcInvalidState = 0,\r
     MmcHwInitializationState,\r
index 9104f60ae01afe5d3c6ff999356694eaa68e0173..e84c3c1cdf1b803df5cc70732ba06c20a4b71e5e 100644 (file)
@@ -1,7 +1,7 @@
 /** @file\r
   Main Header file for the MMC DXE driver\r
 \r
 /** @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
   \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
   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
   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
   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
   );\r
 \r
 VOID\r
index 4b9b64e46f0bd7cac74e3a184d53516bd97181e8..04c82613d5b7b80f6641bdeaef6755cc1fcc2e55 100644 (file)
@@ -1,6 +1,6 @@
 /** @file\r
 *\r
 /** @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
 *\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
 \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
 EFI_STATUS\r
 MmcNotifyState (\r
   IN MMC_HOST_INSTANCE *MmcHostInstance,\r
@@ -65,259 +62,6 @@ MmcGetCardStatus (
   return Status;\r
 }\r
 \r
   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
 EFI_STATUS\r
 EFIAPI\r
 MmcReset (\r
index 80e15bb8505bfe073c9f78faf30084507286fc3b..069b8c766c9f7d6dda4d0aa84f9ee1c0aa596e5a 100644 (file)
@@ -1,7 +1,7 @@
 #/** @file\r
 #  Build file for the MMC DXE driver\r
 #\r
 #/** @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
 #  \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
   ComponentName.c\r
   Mmc.c\r
   MmcBlockIo.c\r
+  MmcIdentification.c\r
   MmcDebug.c\r
   Diagnostics.c\r
 \r
   MmcDebug.c\r
   Diagnostics.c\r
 \r
@@ -48,4 +49,4 @@
   gEfiDriverDiagnostics2ProtocolGuid\r
   \r
 [Depex]\r
   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