/** @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
#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
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
--- /dev/null
+/** @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