/** This function can detect these card types: 1. MMC card 2. SD 1.1 card 3. SD 2.0 standard card 3. SD 2.0 high capacity card @param CardData Pointer to CARD_DATA. @return EFI_SUCCESS @return others **/ EFI_STATUS GetCardType ( IN CARD_DATA *CardData ) { EFI_STATUS Status; EFI_SD_HOST_IO_PROTOCOL *SDHostIo; UINT32 Argument; UINT32 ResponseData; UINT32 Count; BOOLEAN SDCommand8Support; SDHostIo = CardData->SDHostIo; // // Reset the card // Status = SendCommand ( CardData, GO_IDLE_STATE, 0, NoData, NULL, 0, ResponseNo, TIMEOUT_COMMAND, NULL ); if (EFI_ERROR (Status)) { DEBUG((EFI_D_ERROR, "GO_IDLE_STATE Fail Status = 0x%x\n", Status)); goto Exit; } // //No spec requirment, can be adjusted // gBS->Stall (10 * 1000); // // Only 2.7V - 3.6V is supported for SD2.0, only SD 2.0 card can pass // MMC and SD1.1 card will fail this command // Argument = (VOLTAGE_27_36 << 8) | CHECK_PATTERN; ResponseData = 0; SDCommand8Support = FALSE; Status = SendCommand ( CardData, SEND_IF_COND, Argument, NoData, NULL, 0, ResponseR7, TIMEOUT_COMMAND, &ResponseData ); if (EFI_ERROR (Status)) { if (Status != EFI_TIMEOUT) { DEBUG((EFI_D_ERROR, "SEND_IF_COND Fail, none time out error\n")); goto Exit; } } else { if (ResponseData != Argument) { DEBUG((EFI_D_ERROR, "SEND_IF_COND Fail, respond data does not match send data\n")); Status = EFI_DEVICE_ERROR; goto Exit; } SDCommand8Support = TRUE; } Argument = 0; if (SDHostIo->HostCapability.V30Support == TRUE) { Argument |= BIT17 | BIT18; } else if (SDHostIo->HostCapability.V33Support == TRUE) { Argument |= BIT20 | BIT21; } if (SDCommand8Support) { // //If command SD_SEND_OP_COND sucessed, it should be set. // SD 1.1 card will ignore it // SD 2.0 standard card will repsond with CCS 0, SD high capacity card will respond with CCS 1 // CCS is BIT30 of OCR Argument |= BIT30; } Count = 20; // //Only SD card will respond to this command, and spec says the card only checks condition at first ACMD41 command // do { Status = SendAppCommand ( CardData, SD_SEND_OP_COND, Argument, NoData, NULL, 0, ResponseR3, TIMEOUT_COMMAND, (UINT32*)&(CardData->OCRRegister) ); if (EFI_ERROR (Status)) { if ((Status == EFI_TIMEOUT) && (!SDCommand8Support)) { CardData->CardType = MMCCard; Status = EFI_SUCCESS; DEBUG((EFI_D_INFO, "SD_SEND_OP_COND, MMC card was identified\n")); } else { // // Not as expected, MMC card should has no response, which means timeout. // SD card should pass this command // DEBUG((EFI_D_ERROR, "SD_SEND_OP_COND Fail, check whether it is neither a MMC card nor a SD card\n")); } goto Exit; } // //Avoid waiting if sucess. Busy bit 0 means not ready // if (CardData->OCRRegister.Busy == 1) { break; } gBS->Stall (50 * 1000); Count--; if (Count == 0) { DEBUG((EFI_D_ERROR, "Card is always in busy state\n")); Status = EFI_TIMEOUT; goto Exit; } } while (1); // //Check supported voltage // Argument = 0; if (SDHostIo->HostCapability.V30Support == TRUE) { if ((CardData->OCRRegister.V270_V360 & BIT2) == BIT2) { Argument |= BIT17; } else if ((CardData->OCRRegister.V270_V360 & BIT3) == BIT3) { Argument |= BIT18; } } else if (SDHostIo->HostCapability.V33Support == TRUE) { if ((CardData->OCRRegister.V270_V360 & BIT5) == BIT5) { Argument |= BIT20; } else if ((CardData->OCRRegister.V270_V360 & BIT6) == BIT6) { Argument |= BIT21; } } if (Argument == 0) { // //No matched support voltage // PutCardInactive (CardData); DEBUG((EFI_D_ERROR, "No matched voltage for this card\n")); Status = EFI_UNSUPPORTED; goto Exit; } CardData->CardType = SDMemoryCard; if (SDCommand8Support == TRUE) { CardData->CardType = SDMemoryCard2; DEBUG((EFI_D_INFO, "SD_SEND_OP_COND, SD 2.0 or above standard card was identified\n")); } if ((CardData->OCRRegister.AccessMode & BIT1) == BIT1) { CardData->CardType = SDMemoryCard2High; DEBUG((EFI_D_INFO, "SD_SEND_OP_COND, SD 2.0 or above high capacity card was identified\n")); } Exit: return Status; }
/** MMC card high/low voltage selection function @param CardData Pointer to CARD_DATA. @retval EFI_SUCCESS @retval EFI_INVALID_PARAMETER @retval EFI_UNSUPPORTED @retval EFI_BAD_BUFFER_SIZE **/ EFI_STATUS MMCCardVoltageSelection ( IN CARD_DATA *CardData ) { EFI_STATUS Status; EFI_SD_HOST_IO_PROTOCOL *SDHostIo; UINT8 Index; UINT8 Retry; UINT32 TimeOut; SDHostIo = CardData->SDHostIo; Status = EFI_SUCCESS; // //First try the high voltage, then if supported choose the low voltage // for (Index = 0; Index < 2; Index++) { for (Retry = 0; Retry < 3; Retry++) { // // To bring back the normal MMC card to work // after sending the SD command. Otherwise some // card could not work Status = SendCommand ( SDHostIo, GO_IDLE_STATE, 0, NoData, NULL, 0, ResponseNo, TIMEOUT_COMMAND, NULL ); if (EFI_ERROR (Status)) { DEBUG((EFI_D_ERROR, "GO_IDLE_STATE Fail Status = 0x%x\n", Status)); continue; } // //CE-ATA device needs long delay // gBS->Stall ((Retry + 1) * 50 * 1000); // //Get OCR register to check voltage support, first time the OCR is 0 // Status = SendCommand ( SDHostIo, SEND_OP_COND, 0, NoData, NULL, 0, ResponseR3, TIMEOUT_COMMAND, (UINT32*)&(CardData->OCRRegister) ); if (!EFI_ERROR (Status)) { break; } } if (Retry == 3) { DEBUG((EFI_D_ERROR, "SEND_OP_COND Fail Status = 0x%x\n", Status)); Status = EFI_DEVICE_ERROR; goto Exit; } if (CardData->OCRRegister.V170_V195 == 1) { CardData->DualVoltage = TRUE; } if (CardData->OCRRegister.V270_V360 != 0x1F && CardData->OCRRegister.V200_V260 != 0) { DEBUG((EFI_D_ERROR, "Incompatiable voltage device\n")); PutCardInactive (CardData); Status = EFI_INCOMPATIBLE_VERSION; goto Exit; } if (Index == 0) { // //Choose the high voltage first // CardData->OCRRegister.V170_V195 = 0; } else { // //Choose the low voltage // CardData->OCRRegister.V170_V195 = 1; CardData->OCRRegister.V270_V360 = 0; } // //TimeOut Value, 5000 * 100 * 1000 = 5 s // TimeOut = 5000; do { Status = SendCommand ( SDHostIo, SEND_OP_COND, *(UINT32*)&(CardData->OCRRegister), NoData, NULL, 0, ResponseR3, TIMEOUT_COMMAND, (UINT32*)&(CardData->OCRRegister) ); if (EFI_ERROR (Status)) { DEBUG((EFI_D_ERROR, "SEND_OP_COND Fail Status = 0x%x\n", Status)); goto Exit; } gBS->Stall (1 * 1000); TimeOut--; DEBUG((EFI_D_ERROR, "Card is always in busy state, timeout:%d(in 5000)\n", TimeOut)); if (TimeOut == 0) { Status = EFI_TIMEOUT; goto Exit; } } while (CardData->OCRRegister.Busy != 1); if (CardData->DualVoltage == TRUE && SDHostIo->HostCapability.V18Support == TRUE) { // //Power Off the card and then power on into low voltage // SDHostIo->SetHostVoltage (SDHostIo, 0); gBS->Stall (1 * 1000); SDHostIo->SetHostVoltage (SDHostIo, 18); } else { // //Not support the low voltage, exit // break; } } Exit: return Status; }