summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorOlivier Deprez <o-deprez@ti.com>2012-06-25 11:06:31 +0200
committerLeif Lindholm <leif.lindholm@linaro.org>2014-05-09 15:11:00 +0100
commit2fd76708362c11b237c62a76c1b6ad2691dddf91 (patch)
treea7227cda33ecf87f0aa0f2c8e4b6051025202a0a
parent66c7cdb34796556fa89afb4889911853ef502544 (diff)
MmcDxe: fixes sd card identification on panda
It is observed with few SD cards that the protocol is hanging after issuing cmd5 and before cmd8. Adding a small delay inbetween recovers and driver bring up is continuing without problem. Signed-off-by: Steven Kinney <steven.kinney@linaro.org>
-rw-r--r--EmbeddedPkg/Universal/MmcDxe/MmcBlockIo.c259
1 files changed, 259 insertions, 0 deletions
diff --git a/EmbeddedPkg/Universal/MmcDxe/MmcBlockIo.c b/EmbeddedPkg/Universal/MmcDxe/MmcBlockIo.c
index 04c82613d..81ba7372f 100644
--- a/EmbeddedPkg/Universal/MmcDxe/MmcBlockIo.c
+++ b/EmbeddedPkg/Universal/MmcDxe/MmcBlockIo.c
@@ -64,6 +64,265 @@ MmcGetCardStatus (
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 1 // Added for Panda Board
+ /* It seems few SD cards need some time to recover from this command? */
+ MicroSecondDelay(1000);
+#endif
+
+ 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 (
IN EFI_BLOCK_IO_PROTOCOL *This,
IN BOOLEAN ExtendedVerification