Kaynağa Gözat

MmcDxe: Adding eMMC support

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
Olivier Martin 10 yıl önce
ebeveyn
işleme
b4fdedc254

+ 5 - 1
EmbeddedPkg/Include/Protocol/MmcHost.h

@@ -1,7 +1,7 @@
 /** @file
   Definition of the MMC Host Protocol
 
-  Copyright (c) 2011, ARM Limited. All rights reserved.
+  Copyright (c) 2011-2014, ARM Limited. All rights reserved.
   
   This program and the accompanying materials                          
   are licensed and made available under the terms and conditions of the BSD License         
@@ -64,6 +64,10 @@ typedef UINT32 MMC_CMD;
 #define MMC_CMD55             (MMC_INDX(55) | MMC_CMD_WAIT_RESPONSE)
 #define MMC_ACMD41            (MMC_INDX(41) | MMC_CMD_WAIT_RESPONSE | MMC_CMD_NO_CRC_RESPONSE)
 
+// Valid responses for CMD1 in eMMC
+#define EMMC_CMD1_CAPACITY_LESS_THAN_2GB 0x00FF8080 // Capacity <= 2GB, byte addressing used
+#define EMMC_CMD1_CAPACITY_GREATER_THAN_2GB 0x40FF8080 // Capacity > 2GB, 512-byte sector addressing used
+
 typedef enum _MMC_STATE {
     MmcInvalidState = 0,
     MmcHwInitializationState,

+ 11 - 3
EmbeddedPkg/Universal/MmcDxe/Mmc.h

@@ -1,7 +1,7 @@
 /** @file
   Main Header file for the MMC DXE driver
 
-  Copyright (c) 2011-2013, ARM Limited. All rights reserved.
+  Copyright (c) 2011-2014, ARM Limited. All rights reserved.
   
   This program and the accompanying materials                          
   are licensed and made available under the terms and conditions of the BSD License         
@@ -58,6 +58,7 @@ typedef enum {
   UNKNOWN_CARD,
   MMC_CARD,              //MMC card
   MMC_CARD_HIGH,         //MMC Card with High capacity
+  EMMC_CARD,             //eMMC 4.41 card
   SD_CARD,               //SD 1.1 card
   SD_CARD_2,             //SD 2.0 or above standard card
   SD_CARD_2_HIGH         //SD 2.0 or above high capacity card
@@ -289,8 +290,15 @@ MmcFlushBlocks (
   IN EFI_BLOCK_IO_PROTOCOL  *This
   );
 
-EFI_STATUS InitializeMmcDevice (
-  IN  MMC_HOST_INSTANCE   *MmcHost
+EFI_STATUS
+MmcNotifyState (
+  IN MMC_HOST_INSTANCE      *MmcHostInstance,
+  IN MMC_STATE               State
+  );
+
+EFI_STATUS
+InitializeMmcDevice (
+  IN  MMC_HOST_INSTANCE     *MmcHost
   );
 
 VOID

+ 1 - 257
EmbeddedPkg/Universal/MmcDxe/MmcBlockIo.c

@@ -1,6 +1,6 @@
 /** @file
 *
-*  Copyright (c) 2011-2013, ARM Limited. All rights reserved.
+*  Copyright (c) 2011-2014, ARM Limited. All rights reserved.
 *
 *  This program and the accompanying materials
 *  are licensed and made available under the terms and conditions of the BSD License
@@ -17,9 +17,6 @@
 
 #include "Mmc.h"
 
-#define MAX_RETRY_COUNT  1000
-#define CMD_RETRY_COUNT  20
-
 EFI_STATUS
 MmcNotifyState (
   IN MMC_HOST_INSTANCE *MmcHostInstance,
@@ -65,259 +62,6 @@ MmcGetCardStatus (
   return Status;
 }
 
-EFI_STATUS
-EFIAPI
-MmcIdentificationMode (
-  IN MMC_HOST_INSTANCE     *MmcHostInstance
-  )
-{
-  EFI_STATUS              Status;
-  UINT32                  Response[4];
-  UINTN                   Timeout;
-  UINTN                   CmdArg;
-  BOOLEAN                 IsHCS;
-  EFI_MMC_HOST_PROTOCOL   *MmcHost;
-
-  MmcHost = MmcHostInstance->MmcHost;
-  CmdArg = 0;
-  IsHCS = FALSE;
-
-  if (MmcHost == NULL) {
-    return EFI_INVALID_PARAMETER;
-  }
-
-  // We can get into this function if we restart the identification mode
-  if (MmcHostInstance->State == MmcHwInitializationState) {
-    // Initialize the MMC Host HW
-    Status = MmcNotifyState (MmcHostInstance, MmcHwInitializationState);
-    if (EFI_ERROR (Status)) {
-      DEBUG ((EFI_D_ERROR, "MmcIdentificationMode() : Error MmcHwInitializationState\n"));
-      return Status;
-    }
-  }
-
-  Status = MmcHost->SendCommand (MmcHost, MMC_CMD0, 0);
-  if (EFI_ERROR (Status)) {
-    DEBUG ((EFI_D_ERROR, "MmcIdentificationMode(MMC_CMD0): Error\n"));
-    return Status;
-  }
-
-  Status = MmcNotifyState (MmcHostInstance, MmcIdleState);
-  if (EFI_ERROR (Status)) {
-    DEBUG ((EFI_D_ERROR, "MmcIdentificationMode() : Error MmcIdleState\n"));
-    return Status;
-  }
-
-  // Are we using SDIO ?
-  Status = MmcHost->SendCommand (MmcHost, MMC_CMD5, 0);
-  if (Status == EFI_SUCCESS) {
-    DEBUG ((EFI_D_ERROR, "MmcIdentificationMode(MMC_CMD5): Error - SDIO not supported.\n"));
-    return EFI_UNSUPPORTED;
-  }
-
-  // Check which kind of card we are using. Ver2.00 or later SD Memory Card (PL180 is SD v1.1)
-  CmdArg = (0x0UL << 12 | BIT8 | 0xCEUL << 0);
-  Status = MmcHost->SendCommand (MmcHost, MMC_CMD8, CmdArg);
-  if (Status == EFI_SUCCESS) {
-    DEBUG ((EFI_D_ERROR, "Card is SD2.0 => Supports high capacity\n"));
-    IsHCS = TRUE;
-    MmcHost->ReceiveResponse (MmcHost, MMC_RESPONSE_TYPE_R7, Response);
-    PrintResponseR1 (Response[0]);
-    //check if it is valid response
-    if (Response[0] != CmdArg) {
-      DEBUG ((EFI_D_ERROR, "The Card is not usable\n"));
-      return EFI_UNSUPPORTED;
-    }
-  } else {
-    DEBUG ((EFI_D_ERROR, "Not a SD2.0 Card\n"));
-  }
-
-  // We need to wait for the MMC or SD card is ready => (gCardInfo.OCRData.PowerUp == 1)
-  Timeout = MAX_RETRY_COUNT;
-  while (Timeout > 0) {
-    // SD Card or MMC Card ? CMD55 indicates to the card that the next command is an application specific command
-    Status = MmcHost->SendCommand (MmcHost, MMC_CMD55, 0);
-    if (Status == EFI_SUCCESS) {
-      DEBUG ((EFI_D_INFO, "Card should be SD\n"));
-      if (IsHCS) {
-        MmcHostInstance->CardInfo.CardType = SD_CARD_2;
-      } else {
-        MmcHostInstance->CardInfo.CardType = SD_CARD;
-      }
-
-      // Note: The first time CmdArg will be zero
-      CmdArg = ((UINTN *) &(MmcHostInstance->CardInfo.OCRData))[0];
-      if (IsHCS) {
-        CmdArg |= BIT30;
-      }
-      Status = MmcHost->SendCommand (MmcHost, MMC_ACMD41, CmdArg);
-      if (!EFI_ERROR (Status)) {
-        MmcHost->ReceiveResponse (MmcHost, MMC_RESPONSE_TYPE_OCR, Response);
-        ((UINT32 *) &(MmcHostInstance->CardInfo.OCRData))[0] = Response[0];
-      }
-    } else {
-      DEBUG ((EFI_D_INFO, "Card should be MMC\n"));
-      MmcHostInstance->CardInfo.CardType = MMC_CARD;
-
-      Status = MmcHost->SendCommand (MmcHost, MMC_CMD1, 0x800000);
-      if (!EFI_ERROR (Status)) {
-        MmcHost->ReceiveResponse (MmcHost, MMC_RESPONSE_TYPE_OCR, Response);
-        ((UINT32 *) &(MmcHostInstance->CardInfo.OCRData))[0] = Response[0];
-      }
-    }
-
-    if (!EFI_ERROR (Status)) {
-      if (!MmcHostInstance->CardInfo.OCRData.PowerUp) {
-        MicroSecondDelay (1);
-        Timeout--;
-      } else {
-        if ((MmcHostInstance->CardInfo.CardType == SD_CARD_2) && (MmcHostInstance->CardInfo.OCRData.AccessMode & BIT1)) {
-          MmcHostInstance->CardInfo.CardType = SD_CARD_2_HIGH;
-          DEBUG ((EFI_D_ERROR, "High capacity card.\n"));
-        }
-        break;  // The MMC/SD card is ready. Continue the Identification Mode
-      }
-    } else {
-      MicroSecondDelay (1);
-      Timeout--;
-    }
-  }
-
-  if (Timeout == 0) {
-    DEBUG ((EFI_D_ERROR, "MmcIdentificationMode(): No Card\n"));
-    return EFI_NO_MEDIA;
-  } else {
-    PrintOCR (Response[0]);
-  }
-
-  Status = MmcNotifyState (MmcHostInstance, MmcReadyState);
-  if (EFI_ERROR (Status)) {
-    DEBUG ((EFI_D_ERROR, "MmcIdentificationMode() : Error MmcReadyState\n"));
-    return Status;
-  }
-
-  Status = MmcHost->SendCommand (MmcHost, MMC_CMD2, 0);
-  if (EFI_ERROR (Status)) {
-    DEBUG ((EFI_D_ERROR, "MmcIdentificationMode(MMC_CMD2): Error\n"));
-    return Status;
-  }
-  MmcHost->ReceiveResponse (MmcHost, MMC_RESPONSE_TYPE_CID, Response);
-  PrintCID (Response);
-
-  Status = MmcNotifyState (MmcHostInstance, MmcIdentificationState);
-  if (EFI_ERROR (Status)) {
-    DEBUG ((EFI_D_ERROR, "MmcIdentificationMode() : Error MmcIdentificationState\n"));
-    return Status;
-  }
-
-  //
-  // Note, SD specifications say that "if the command execution causes a state change, it
-  // will be visible to the host in the response to the next command"
-  // The status returned for this CMD3 will be 2 - identification
-  //
-  CmdArg = 1;
-  Status = MmcHost->SendCommand (MmcHost, MMC_CMD3, CmdArg);
-  if (EFI_ERROR (Status)) {
-    DEBUG ((EFI_D_ERROR, "MmcIdentificationMode(MMC_CMD3): Error\n"));
-    return Status;
-  }
-
-  MmcHost->ReceiveResponse (MmcHost, MMC_RESPONSE_TYPE_RCA, Response);
-  PrintRCA (Response[0]);
-
-  // For MMC card, RCA is assigned by CMD3 while CMD3 dumps the RCA for SD card
-  if (MmcHostInstance->CardInfo.CardType != MMC_CARD) {
-    MmcHostInstance->CardInfo.RCA = Response[0] >> 16;
-  } else {
-    MmcHostInstance->CardInfo.RCA = CmdArg;
-  }
-
-  Status = MmcNotifyState (MmcHostInstance, MmcStandByState);
-  if (EFI_ERROR (Status)) {
-    DEBUG ((EFI_D_ERROR, "MmcIdentificationMode() : Error MmcStandByState\n"));
-    return Status;
-  }
-
-  return EFI_SUCCESS;
-}
-
-EFI_STATUS InitializeMmcDevice (
-  IN  MMC_HOST_INSTANCE   *MmcHostInstance
-  )
-{
-  UINT32                  Response[4];
-  EFI_STATUS              Status;
-  UINTN                   CardSize, NumBlocks, BlockSize, CmdArg;
-  EFI_MMC_HOST_PROTOCOL   *MmcHost;
-  UINTN                   BlockCount;
-
-  BlockCount = 1;
-  MmcHost = MmcHostInstance->MmcHost;
-
-  MmcIdentificationMode (MmcHostInstance);
-
-  //Send a command to get Card specific data
-  CmdArg = MmcHostInstance->CardInfo.RCA << 16;
-  Status = MmcHost->SendCommand (MmcHost, MMC_CMD9, CmdArg);
-  if (EFI_ERROR (Status)) {
-    DEBUG((EFI_D_ERROR, "InitializeMmcDevice(MMC_CMD9): Error, Status=%r\n", Status));
-    return Status;
-  }
-  //Read Response
-  MmcHost->ReceiveResponse (MmcHost, MMC_RESPONSE_TYPE_CSD, Response);
-  PrintCSD (Response);
-
-  if (MmcHostInstance->CardInfo.CardType == SD_CARD_2_HIGH) {
-    CardSize = HC_MMC_CSD_GET_DEVICESIZE (Response);
-    NumBlocks = ((CardSize + 1) * 1024);
-    BlockSize = 1 << MMC_CSD_GET_READBLLEN (Response);
-  } else {
-    CardSize = MMC_CSD_GET_DEVICESIZE (Response);
-    NumBlocks = (CardSize + 1) * (1 << (MMC_CSD_GET_DEVICESIZEMULT (Response) + 2));
-    BlockSize = 1 << MMC_CSD_GET_READBLLEN (Response);
-  }
-
-  //For >=2G card, BlockSize may be 1K, but the transfer size is 512 bytes.
-  if (BlockSize > 512) {
-    NumBlocks = MultU64x32 (NumBlocks, BlockSize/512);
-    BlockSize = 512;
-  }
-
-  MmcHostInstance->BlockIo.Media->LastBlock    = (NumBlocks - 1);
-  MmcHostInstance->BlockIo.Media->BlockSize    = BlockSize;
-  MmcHostInstance->BlockIo.Media->ReadOnly     = MmcHost->IsReadOnly (MmcHost);
-  MmcHostInstance->BlockIo.Media->MediaPresent = TRUE;
-  MmcHostInstance->BlockIo.Media->MediaId++;
-
-  CmdArg = MmcHostInstance->CardInfo.RCA << 16;
-  Status = MmcHost->SendCommand (MmcHost, MMC_CMD7, CmdArg);
-  if (EFI_ERROR (Status)) {
-    DEBUG((EFI_D_ERROR, "InitializeMmcDevice(MMC_CMD7): Error and Status = %r\n", Status));
-    return Status;
-  }
-
-  Status = MmcNotifyState (MmcHostInstance, MmcTransferState);
-  if (EFI_ERROR (Status)) {
-    DEBUG((EFI_D_ERROR, "InitializeMmcDevice(): Error MmcTransferState\n"));
-    return Status;
-  }
-
-  // Set Block Length
-  Status = MmcHost->SendCommand (MmcHost, MMC_CMD16, MmcHostInstance->BlockIo.Media->BlockSize);
-  if (EFI_ERROR (Status)) {
-    DEBUG((EFI_D_ERROR, "InitializeMmcDevice(MMC_CMD16): Error MmcHostInstance->BlockIo.Media->BlockSize: %d and Error = %r\n",
-                        MmcHostInstance->BlockIo.Media->BlockSize, Status));
-    return Status;
-  }
-
-  // Block Count (not used). Could return an error for SD card
-  if (MmcHostInstance->CardInfo.CardType == MMC_CARD) {
-    MmcHost->SendCommand (MmcHost, MMC_CMD23, BlockCount);
-  }
-
-  return EFI_SUCCESS;
-}
-
 EFI_STATUS
 EFIAPI
 MmcReset (

+ 3 - 2
EmbeddedPkg/Universal/MmcDxe/MmcDxe.inf

@@ -1,7 +1,7 @@
 #/** @file
 #  Build file for the MMC DXE driver
 #
-#  Copyright (c) 2011-2013, ARM Limited. All rights reserved.
+#  Copyright (c) 2011-2014, ARM Limited. All rights reserved.
 #  
 #  This program and the accompanying materials                          
 #  are licensed and made available under the terms and conditions of the BSD License         
@@ -26,6 +26,7 @@
   ComponentName.c
   Mmc.c
   MmcBlockIo.c
+  MmcIdentification.c
   MmcDebug.c
   Diagnostics.c
 
@@ -48,4 +49,4 @@
   gEfiDriverDiagnostics2ProtocolGuid
   
 [Depex]
-  TRUE
+  TRUE


+ 456 - 0
EmbeddedPkg/Universal/MmcDxe/MmcIdentification.c

@@ -0,0 +1,456 @@
+/** @file
+*
+*  Copyright (c) 2011-2014, ARM Limited. All rights reserved.
+*
+*  This program and the accompanying materials
+*  are licensed and made available under the terms and conditions of the BSD License
+*  which accompanies this distribution.  The full text of the license may be found at
+*  http://opensource.org/licenses/bsd-license.php
+*
+*  THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+*  WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+*
+**/
+
+#include <Library/TimerLib.h>
+
+#include "Mmc.h"
+
+typedef union {
+  UINT32 Raw;
+  OCR    Ocr;
+} OCR_RESPONSE;
+
+#define MAX_RETRY_COUNT         1000
+#define CMD_RETRY_COUNT         20
+#define RCA_SHIFT_OFFSET        16
+#define EMMC_CARD_SIZE          512
+#define EMMC_ECSD_SIZE_OFFSET   53
+
+UINT32 mEmmcRcaCount = 0;
+
+STATIC
+EFI_STATUS
+EFIAPI
+EmmcIdentificationMode (
+  IN MMC_HOST_INSTANCE     *MmcHostInstance,
+  IN OCR_RESPONSE           Response
+  )
+{
+  EFI_MMC_HOST_PROTOCOL *Host;
+  EFI_BLOCK_IO_MEDIA    *Media;
+  EFI_STATUS Status;
+  UINT32     RCA;
+  UINT32     ECSD[128];
+
+  Host  = MmcHostInstance->MmcHost;
+  Media = MmcHostInstance->BlockIo.Media;
+
+  // Fetch card identity register
+  Status = Host->SendCommand (Host, MMC_CMD2, 0);
+  if (EFI_ERROR (Status)) {
+    DEBUG ((EFI_D_ERROR, "EmmcIdentificationMode(): Failed to send CMD2, Status=%r.\n", Status));
+    return Status;
+  }
+
+  Status = Host->ReceiveResponse (Host, MMC_RESPONSE_TYPE_R2, (UINT32 *)&(MmcHostInstance->CardInfo.CIDData));
+  if (EFI_ERROR (Status)) {
+    DEBUG ((EFI_D_ERROR, "EmmcIdentificationMode(): CID retrieval error, Status=%r.\n", Status));
+    return Status;
+  }
+
+  // Assign a relative address value to the card
+  MmcHostInstance->CardInfo.RCA = ++mEmmcRcaCount; // TODO: might need a more sophisticated way of doing this
+  RCA = MmcHostInstance->CardInfo.RCA << RCA_SHIFT_OFFSET;
+  Status = Host->SendCommand (Host, MMC_CMD3, RCA);
+  if (EFI_ERROR (Status)) {
+    DEBUG ((EFI_D_ERROR, "EmmcIdentificationMode(): RCA set error, Status=%r.\n", Status));
+    return Status;
+  }
+
+  // Fetch card specific data
+  Status = Host->SendCommand (Host, MMC_CMD9, RCA);
+  if (EFI_ERROR (Status)) {
+    DEBUG ((EFI_D_ERROR, "EmmcIdentificationMode(): Failed to send CMD9, Status=%r.\n", Status));
+    return Status;
+  }
+
+  Status = Host->ReceiveResponse (Host, MMC_RESPONSE_TYPE_R2, (UINT32 *)&(MmcHostInstance->CardInfo.CSDData));
+  if (EFI_ERROR (Status)) {
+    DEBUG ((EFI_D_ERROR, "EmmcIdentificationMode(): CSD retrieval error, Status=%r.\n", Status));
+    return Status;
+  }
+
+  // Select the card
+  Status = Host->SendCommand (Host, MMC_CMD7, RCA);
+  if (EFI_ERROR (Status)) {
+    DEBUG ((EFI_D_ERROR, "EmmcIdentificationMode(): Card selection error, Status=%r.\n", Status));
+  }
+
+  // Fetch ECSD
+  Status = Host->SendCommand (Host, MMC_CMD8, RCA);
+  if (EFI_ERROR (Status)) {
+    DEBUG ((EFI_D_ERROR, "EmmcIdentificationMode(): ECSD fetch error, Status=%r.\n", Status));
+  }
+
+  Status = Host->ReadBlockData (Host, 0, 512, ECSD);
+  if (EFI_ERROR (Status)) {
+    DEBUG ((EFI_D_ERROR, "EmmcIdentificationMode(): ECSD read error, Status=%r.\n", Status));
+    return Status;
+  }
+
+  // Set up media
+  Media->BlockSize = EMMC_CARD_SIZE; // 512-byte support is mandatory for eMMC cards
+  Media->MediaId = MmcHostInstance->CardInfo.CIDData.PSN;
+  Media->ReadOnly = MmcHostInstance->CardInfo.CSDData.PERM_WRITE_PROTECT;
+  Media->LogicalBlocksPerPhysicalBlock = 1;
+  Media->IoAlign = 4;
+  // Compute last block using bits [215:212] of the ECSD
+  Media->LastBlock = ECSD[EMMC_ECSD_SIZE_OFFSET] - 1; // eMMC isn't supposed to report this for
+  // Cards <2GB in size, but the model does.
+
+  // Setup card type
+  MmcHostInstance->CardInfo.CardType = EMMC_CARD;
+  return EFI_SUCCESS;
+}
+
+STATIC
+EFI_STATUS
+InitializeSdMmcDevice (
+  IN  MMC_HOST_INSTANCE   *MmcHostInstance
+  )
+{
+  UINT32        CmdArg;
+  UINT32        Response[4];
+  UINTN         BlockSize;
+  UINTN         CardSize;
+  UINTN         NumBlocks;
+  EFI_STATUS    Status;
+  EFI_MMC_HOST_PROTOCOL     *MmcHost;
+
+  MmcHost = MmcHostInstance->MmcHost;
+
+  // Send a command to get Card specific data
+  CmdArg = MmcHostInstance->CardInfo.RCA << 16;
+  Status = MmcHost->SendCommand (MmcHost, MMC_CMD9, CmdArg);
+  if (EFI_ERROR (Status)) {
+    DEBUG((EFI_D_ERROR, "InitializeSdMmcDevice(MMC_CMD9): Error, Status=%r\n", Status));
+    return Status;
+  }
+
+  // Read Response
+  Status = MmcHost->ReceiveResponse (MmcHost, MMC_RESPONSE_TYPE_CSD, Response);
+  if (EFI_ERROR (Status)) {
+    DEBUG((EFI_D_ERROR, "InitializeSdMmcDevice(): Failed to receive CSD, Status=%r\n", Status));
+    return Status;
+  }
+  PrintCSD (Response);
+
+  if (MmcHostInstance->CardInfo.CardType == SD_CARD_2_HIGH) {
+    CardSize = HC_MMC_CSD_GET_DEVICESIZE (Response);
+    NumBlocks = ((CardSize + 1) * 1024);
+    BlockSize = 1 << MMC_CSD_GET_READBLLEN (Response);
+  } else {
+    CardSize = MMC_CSD_GET_DEVICESIZE (Response);
+    NumBlocks = (CardSize + 1) * (1 << (MMC_CSD_GET_DEVICESIZEMULT (Response) + 2));
+    BlockSize = 1 << MMC_CSD_GET_READBLLEN (Response);
+  }
+
+  // For >=2G card, BlockSize may be 1K, but the transfer size is 512 bytes.
+  if (BlockSize > 512) {
+    NumBlocks = MultU64x32 (NumBlocks, BlockSize / 512);
+    BlockSize = 512;
+  }
+
+  MmcHostInstance->BlockIo.Media->LastBlock    = (NumBlocks - 1);
+  MmcHostInstance->BlockIo.Media->BlockSize    = BlockSize;
+  MmcHostInstance->BlockIo.Media->ReadOnly     = MmcHost->IsReadOnly (MmcHost);
+  MmcHostInstance->BlockIo.Media->MediaPresent = TRUE;
+  MmcHostInstance->BlockIo.Media->MediaId++;
+
+  CmdArg = MmcHostInstance->CardInfo.RCA << 16;
+  Status = MmcHost->SendCommand (MmcHost, MMC_CMD7, CmdArg);
+  if (EFI_ERROR (Status)) {
+    DEBUG((EFI_D_ERROR, "InitializeSdMmcDevice(MMC_CMD7): Error and Status = %r\n", Status));
+    return Status;
+  }
+
+  return EFI_SUCCESS;
+}
+
+STATIC
+EFI_STATUS
+EFIAPI
+MmcIdentificationMode (
+  IN MMC_HOST_INSTANCE     *MmcHostInstance
+  )
+{
+  EFI_STATUS              Status;
+  UINT32                  Response[4];
+  UINTN                   Timeout;
+  UINTN                   CmdArg;
+  BOOLEAN                 IsHCS;
+  EFI_MMC_HOST_PROTOCOL   *MmcHost;
+  OCR_RESPONSE            OcrResponse;
+
+  MmcHost = MmcHostInstance->MmcHost;
+  CmdArg = 0;
+  IsHCS = FALSE;
+
+  if (MmcHost == NULL) {
+    return EFI_INVALID_PARAMETER;
+  }
+
+  // We can get into this function if we restart the identification mode
+  if (MmcHostInstance->State == MmcHwInitializationState) {
+    // Initialize the MMC Host HW
+    Status = MmcNotifyState (MmcHostInstance, MmcHwInitializationState);
+    if (EFI_ERROR (Status)) {
+      DEBUG ((EFI_D_ERROR, "MmcIdentificationMode() : Error MmcHwInitializationState, Status=%r.\n", Status));
+      return Status;
+    }
+  }
+
+  Status = MmcHost->SendCommand (MmcHost, MMC_CMD0, 0);
+  if (EFI_ERROR (Status)) {
+    DEBUG ((EFI_D_ERROR, "MmcIdentificationMode(MMC_CMD0): Error, Status=%r.\n", Status));
+    return Status;
+  }
+  Status = MmcNotifyState (MmcHostInstance, MmcIdleState);
+  if (EFI_ERROR (Status)) {
+    DEBUG ((EFI_D_ERROR, "MmcIdentificationMode() : Error MmcIdleState, Status=%r.\n", Status));
+    return Status;
+  }
+
+  // Send CMD1 to get OCR (SD / MMC)
+  Status = MmcHost->SendCommand (MmcHost, MMC_CMD1, EMMC_CMD1_CAPACITY_GREATER_THAN_2GB);
+  if (Status == EFI_SUCCESS) {
+    Status = MmcHost->ReceiveResponse (MmcHost, MMC_RESPONSE_TYPE_OCR, (UINT32 *)&OcrResponse);
+    if (EFI_ERROR (Status)) {
+      DEBUG ((EFI_D_ERROR, "MmcIdentificationMode() : Failed to receive OCR, Status=%r.\n", Status));
+      return Status;
+    }
+
+    if (!OcrResponse.Ocr.PowerUp) {
+      DEBUG ((EFI_D_ERROR, "MmcIdentificationMode(MMC_CMD1): Card initialisation failure, Status=%r.\n", Status));
+      return EFI_DEVICE_ERROR;
+    }
+    OcrResponse.Ocr.PowerUp = 0;
+    if (OcrResponse.Raw == EMMC_CMD1_CAPACITY_GREATER_THAN_2GB) {
+      MmcHostInstance->CardInfo.OCRData.AccessMode = BIT1;
+    }
+    else {
+      MmcHostInstance->CardInfo.OCRData.AccessMode = 0x0;
+    }
+    if (OcrResponse.Raw == EMMC_CMD1_CAPACITY_GREATER_THAN_2GB ||
+        OcrResponse.Raw == EMMC_CMD1_CAPACITY_LESS_THAN_2GB) {
+      return EmmcIdentificationMode (MmcHostInstance, OcrResponse);
+    }
+  } else {
+    DEBUG ((EFI_D_ERROR, "MmcIdentificationMode(MMC_CMD1) : Failed to send command, Status=%r.\n", Status));
+    return Status;
+  }
+
+  // Are we using SDIO ?
+  Status = MmcHost->SendCommand (MmcHost, MMC_CMD5, 0);
+  if (Status == EFI_SUCCESS) {
+    DEBUG ((EFI_D_ERROR, "MmcIdentificationMode(MMC_CMD5): Error - SDIO not supported, Status=%r.\n", Status));
+    return EFI_UNSUPPORTED;
+  }
+
+  // Check which kind of card we are using. Ver2.00 or later SD Memory Card (PL180 is SD v1.1)
+  CmdArg = (0x0UL << 12 | BIT8 | 0xCEUL << 0);
+  Status = MmcHost->SendCommand (MmcHost, MMC_CMD8, CmdArg);
+  if (Status == EFI_SUCCESS) {
+    DEBUG ((EFI_D_ERROR, "Card is SD2.0 => Supports high capacity\n"));
+    IsHCS = TRUE;
+    Status = MmcHost->ReceiveResponse (MmcHost, MMC_RESPONSE_TYPE_R7, Response);
+    if (EFI_ERROR (Status)) {
+      DEBUG ((EFI_D_ERROR, "MmcIdentificationMode() : Failed to receive response to CMD8, Status=%r.\n", Status));
+      return Status;
+    }
+    PrintResponseR1 (Response[0]);
+    // Check if it is valid response
+    if (Response[0] != CmdArg) {
+      DEBUG ((EFI_D_ERROR, "The Card is not usable\n"));
+      return EFI_UNSUPPORTED;
+    }
+  } else {
+    DEBUG ((EFI_D_ERROR, "Not a SD2.0 Card\n"));
+  }
+
+  // We need to wait for the MMC or SD card is ready => (gCardInfo.OCRData.PowerUp == 1)
+  Timeout = MAX_RETRY_COUNT;
+  while (Timeout > 0) {
+    // SD Card or MMC Card ? CMD55 indicates to the card that the next command is an application specific command
+    Status = MmcHost->SendCommand (MmcHost, MMC_CMD55, 0);
+    if (Status == EFI_SUCCESS) {
+      DEBUG ((EFI_D_INFO, "Card should be SD\n"));
+      if (IsHCS) {
+        MmcHostInstance->CardInfo.CardType = SD_CARD_2;
+      } else {
+        MmcHostInstance->CardInfo.CardType = SD_CARD;
+      }
+
+      // Note: The first time CmdArg will be zero
+      CmdArg = ((UINTN *) &(MmcHostInstance->CardInfo.OCRData))[0];
+      if (IsHCS) {
+        CmdArg |= BIT30;
+      }
+      Status = MmcHost->SendCommand (MmcHost, MMC_ACMD41, CmdArg);
+      if (!EFI_ERROR (Status)) {
+        Status = MmcHost->ReceiveResponse (MmcHost, MMC_RESPONSE_TYPE_OCR, Response);
+        if (EFI_ERROR (Status)) {
+          DEBUG ((EFI_D_ERROR, "MmcIdentificationMode() : Failed to receive OCR, Status=%r.\n", Status));
+          return Status;
+        }
+        ((UINT32 *) &(MmcHostInstance->CardInfo.OCRData))[0] = Response[0];
+      }
+    } else {
+      DEBUG ((EFI_D_INFO, "Card should be MMC\n"));
+      MmcHostInstance->CardInfo.CardType = MMC_CARD;
+
+      Status = MmcHost->SendCommand (MmcHost, MMC_CMD1, 0x800000);
+      if (!EFI_ERROR (Status)) {
+        Status = MmcHost->ReceiveResponse (MmcHost, MMC_RESPONSE_TYPE_OCR, Response);
+        if (EFI_ERROR (Status)) {
+          DEBUG ((EFI_D_ERROR, "MmcIdentificationMode() : Failed to receive OCR, Status=%r.\n", Status));
+          return Status;
+        }
+        ((UINT32 *) &(MmcHostInstance->CardInfo.OCRData))[0] = Response[0];
+      }
+    }
+
+    if (!EFI_ERROR (Status)) {
+      if (!MmcHostInstance->CardInfo.OCRData.PowerUp) {
+        MicroSecondDelay (1);
+        Timeout--;
+      } else {
+        if ((MmcHostInstance->CardInfo.CardType == SD_CARD_2) && (MmcHostInstance->CardInfo.OCRData.AccessMode & BIT1)) {
+          MmcHostInstance->CardInfo.CardType = SD_CARD_2_HIGH;
+          DEBUG ((EFI_D_ERROR, "High capacity card.\n"));
+        }
+        break;  // The MMC/SD card is ready. Continue the Identification Mode
+      }
+    } else {
+      MicroSecondDelay (1);
+      Timeout--;
+    }
+  }
+
+  if (Timeout == 0) {
+    DEBUG ((EFI_D_ERROR, "MmcIdentificationMode(): No Card\n"));
+    return EFI_NO_MEDIA;
+  } else {
+    PrintOCR (Response[0]);
+  }
+
+  Status = MmcNotifyState (MmcHostInstance, MmcReadyState);
+  if (EFI_ERROR (Status)) {
+    DEBUG ((EFI_D_ERROR, "MmcIdentificationMode() : Error MmcReadyState\n"));
+    return Status;
+  }
+
+  Status = MmcHost->SendCommand (MmcHost, MMC_CMD2, 0);
+  if (EFI_ERROR (Status)) {
+    DEBUG ((EFI_D_ERROR, "MmcIdentificationMode(MMC_CMD2): Error\n"));
+    return Status;
+  }
+  Status = MmcHost->ReceiveResponse (MmcHost, MMC_RESPONSE_TYPE_CID, Response);
+  if (EFI_ERROR (Status)) {
+    DEBUG ((EFI_D_ERROR, "MmcIdentificationMode() : Failed to receive CID, Status=%r.\n", Status));
+    return Status;
+  }
+
+  PrintCID (Response);
+
+  Status = MmcHost->NotifyState (MmcHost, MmcIdentificationState);
+  if (EFI_ERROR (Status)) {
+    DEBUG ((EFI_D_ERROR, "MmcIdentificationMode() : Error MmcIdentificationState\n"));
+    return Status;
+  }
+
+  //
+  // Note, SD specifications say that "if the command execution causes a state change, it
+  // will be visible to the host in the response to the next command"
+  // The status returned for this CMD3 will be 2 - identification
+  //
+  CmdArg = 1;
+  Status = MmcHost->SendCommand (MmcHost, MMC_CMD3, CmdArg);
+  if (EFI_ERROR (Status)) {
+    DEBUG ((EFI_D_ERROR, "MmcIdentificationMode(MMC_CMD3): Error\n"));
+    return Status;
+  }
+
+  Status = MmcHost->ReceiveResponse (MmcHost, MMC_RESPONSE_TYPE_RCA, Response);
+  if (EFI_ERROR (Status)) {
+    DEBUG ((EFI_D_ERROR, "MmcIdentificationMode() : Failed to receive RCA, Status=%r.\n", Status));
+    return Status;
+  }
+  PrintRCA (Response[0]);
+
+  // For MMC card, RCA is assigned by CMD3 while CMD3 dumps the RCA for SD card
+  if (MmcHostInstance->CardInfo.CardType != MMC_CARD) {
+    MmcHostInstance->CardInfo.RCA = Response[0] >> 16;
+  } else {
+    MmcHostInstance->CardInfo.RCA = CmdArg;
+  }
+  Status = MmcNotifyState (MmcHostInstance, MmcStandByState);
+  if (EFI_ERROR (Status)) {
+    DEBUG ((EFI_D_ERROR, "MmcIdentificationMode() : Error MmcStandByState\n"));
+    return Status;
+  }
+
+  return EFI_SUCCESS;
+}
+
+EFI_STATUS
+InitializeMmcDevice (
+  IN  MMC_HOST_INSTANCE   *MmcHostInstance
+  )
+{
+  EFI_STATUS              Status;
+  EFI_MMC_HOST_PROTOCOL   *MmcHost;
+  UINTN                   BlockCount;
+
+  BlockCount = 1;
+  MmcHost = MmcHostInstance->MmcHost;
+
+  Status = MmcIdentificationMode (MmcHostInstance);
+  if (EFI_ERROR (Status)) {
+    DEBUG((EFI_D_ERROR, "InitializeMmcDevice(): Error in Identification Mode, Status=%r\n", Status));
+    return Status;
+  }
+
+  Status = MmcNotifyState (MmcHostInstance, MmcTransferState);
+  if (EFI_ERROR (Status)) {
+    DEBUG((EFI_D_ERROR, "InitializeMmcDevice(): Error MmcTransferState, Status=%r\n", Status));
+    return Status;
+  }
+
+  if (MmcHostInstance->CardInfo.CardType != EMMC_CARD) {
+    Status = InitializeSdMmcDevice (MmcHostInstance);
+    if (EFI_ERROR (Status)) {
+      return Status;
+    }
+  }
+
+  // Set Block Length
+  Status = MmcHost->SendCommand (MmcHost, MMC_CMD16, MmcHostInstance->BlockIo.Media->BlockSize);
+  if (EFI_ERROR (Status)) {
+    DEBUG((EFI_D_ERROR, "InitializeMmcDevice(MMC_CMD16): Error MmcHostInstance->BlockIo.Media->BlockSize: %d and Error = %r\n",
+                        MmcHostInstance->BlockIo.Media->BlockSize, Status));
+    return Status;
+  }
+
+  // Block Count (not used). Could return an error for SD card
+  if (MmcHostInstance->CardInfo.CardType == MMC_CARD) {
+    Status = MmcHost->SendCommand (MmcHost, MMC_CMD23, BlockCount);
+    if (EFI_ERROR (Status)) {
+      DEBUG((EFI_D_ERROR, "InitializeMmcDevice(MMC_CMD23): Error, Status=%r\n", Status));
+      return Status;
+    }
+  }
+
+  return EFI_SUCCESS;
+}