/** This function set the bus and device width for MMC card @param CardData Pointer to CARD_DATA. @param Width 1, 4, 8 bits. @retval EFI_SUCCESS @retval EFI_UNSUPPORTED @retval EFI_INVALID_PARAMETER **/ EFI_STATUS MMCCardSetBusWidth ( IN CARD_DATA *CardData, IN UINT8 BusWidth, IN BOOLEAN EnableDDRMode ) { EFI_STATUS Status; EFI_SD_HOST_IO_PROTOCOL *SDHostIo; SWITCH_ARGUMENT SwitchArgument; UINT8 Value; SDHostIo = CardData->SDHostIo; Value = 0; switch (BusWidth) { case 8: if (EnableDDRMode) Value = 6; else Value = 2; break; case 4: if (EnableDDRMode) Value = 5; else Value = 1; break; case 1: if (EnableDDRMode) // Bus width 1 is not supported in ddr mode return EFI_UNSUPPORTED; Value = 0; break; default: ASSERT(0); } ZeroMem(&SwitchArgument, sizeof (SWITCH_ARGUMENT)); SwitchArgument.CmdSet = 0; SwitchArgument.Value = Value; SwitchArgument.Index = (UINT32)((UINTN) (&(CardData->ExtCSDRegister.BUS_WIDTH)) - (UINTN)(&(CardData->ExtCSDRegister))); SwitchArgument.Access = WriteByte_Mode; Status = SendCommand ( CardData, SWITCH, *(UINT32*)&SwitchArgument, NoData, NULL, 0, ResponseR1b, TIMEOUT_COMMAND, (UINT32*)&(CardData->CardStatus) ); if (!EFI_ERROR (Status)) { Status = SendCommand ( CardData, SEND_STATUS, (CardData->Address << 16), NoData, NULL, 0, ResponseR1, TIMEOUT_COMMAND, (UINT32*)&(CardData->CardStatus) ); if (EFI_ERROR (Status)) { DEBUG((EFI_D_ERROR, "SWITCH %d bits Fail\n", BusWidth)); goto Exit; } else { DEBUG((EFI_D_ERROR, "MMCCardSetBusWidth:SWITCH Card Status:0x%x\n", *(UINT32*)&(CardData->CardStatus))); Status = SDHostIo->SetBusWidth (SDHostIo, BusWidth); if (EFI_ERROR (Status)) { DEBUG((EFI_D_ERROR, "SWITCH set %d bits Fail\n", BusWidth)); goto Exit; } gBS->Stall (5 * 1000); } } if (!EnableDDRMode) { // CMD19 and CMD14 are illegal commands in ddr mode //if (EFI_ERROR (Status)) { // DEBUG((EFI_D_ERROR, "MMCCardBusWidthTest: Fail to enable high speed mode\n")); // goto Exit; //} Status = MMCCardBusWidthTest (CardData, BusWidth); if (EFI_ERROR (Status)) { DEBUG((EFI_D_ERROR, "MMCCardBusWidthTest %d bit Fail\n", BusWidth)); goto Exit; } } CardData->CurrentBusWidth = BusWidth; Exit: return Status; }
/** MMC/SD card init function @param CardData Pointer to CARD_DATA. @return EFI_SUCCESS @return others **/ EFI_STATUS MMCSDCardInit ( IN CARD_DATA *CardData ) { EFI_STATUS Status; EFI_SD_HOST_IO_PROTOCOL *SDHostIo; SWITCH_ARGUMENT SwitchArgument; UINT32 Data; UINT32 Argument; UINT8 PowerValue; ASSERT(CardData != NULL); SDHostIo = CardData->SDHostIo; Status = GetCardType (CardData); if (EFI_ERROR (Status)) { goto Exit; } ASSERT (CardData->CardType != UnknownCard); // //MMC, SD card need host auto stop command support // SDHostIo->EnableAutoStopCmd (SDHostIo, TRUE); if (CardData->CardType == MMCCard) { Status = MMCCardVoltageSelection (CardData); if (EFI_ERROR(Status)) { goto Exit; } } // // Get CID Register, but the info is not used currently // Status = SendCommand ( SDHostIo, ALL_SEND_CID, 0, NoData, NULL, 0, ResponseR2, TIMEOUT_COMMAND, (UINT32*)&(CardData->CIDRegister) ); if (EFI_ERROR (Status)) { DEBUG((EFI_D_ERROR, "ALL_SEND_CID Fail Status = 0x%x\n", Status)); goto Exit; } // //SET_RELATIVE_ADDR // if (CardData->CardType == MMCCard) { // //Hard code the RCA address // CardData->Address = 1; // // Set RCA Register // Status = SendCommand ( SDHostIo, SET_RELATIVE_ADDR, (CardData->Address << 16), NoData, NULL, 0, ResponseR1, TIMEOUT_COMMAND, (UINT32*)&(CardData->CardStatus) ); if (EFI_ERROR (Status)) { DEBUG((EFI_D_ERROR, "SET_RELATIVE_ADDR Fail Status = 0x%x\n", Status)); goto Exit; } } else { Data = 0; Status = SendCommand ( SDHostIo, SET_RELATIVE_ADDR, 0, NoData, NULL, 0, ResponseR6, TIMEOUT_COMMAND, &Data ); if (EFI_ERROR (Status)) { DEBUG((EFI_D_ERROR, "SET_RELATIVE_ADDR Fail Status = 0x%x\n", Status)); goto Exit; } CardData->Address = (UINT16)(Data >> 16); *(UINT32*)&CardData->CardStatus = Data & 0x1FFF; CardData->CardStatus.ERROR = (Data >> 13) & 0x1; CardData->CardStatus.ILLEGAL_COMMAND = (Data >> 14) & 0x1; CardData->CardStatus.COM_CRC_ERROR = (Data >> 15) & 0x1; Status = CheckCardStatus (*(UINT32*)&CardData->CardStatus); if (EFI_ERROR (Status)) { DEBUG((EFI_D_ERROR, "SET_RELATIVE_ADDR Fail Status = 0x%x\n", Status)); goto Exit; } } // // Get CSD Register // Status = SendCommand ( SDHostIo, SEND_CSD, (CardData->Address << 16), NoData, NULL, 0, ResponseR2, TIMEOUT_COMMAND, (UINT32*)&(CardData->CSDRegister) ); if (EFI_ERROR (Status)) { DEBUG((EFI_D_ERROR, "SEND_CSD Fail Status = 0x%x\n", Status)); goto Exit; } DEBUG((EFI_D_INFO, "CardData->CSDRegister.SPEC_VERS = 0x%x\n", CardData->CSDRegister.SPEC_VERS)); DEBUG((EFI_D_INFO, "CardData->CSDRegister.CSD_STRUCTURE = 0x%x\n", CardData->CSDRegister.CSD_STRUCTURE)); Status = CaculateCardParameter (CardData); if (EFI_ERROR (Status)) { goto Exit; } // // It is platform and hardware specific, need hadrware engineer input // if (CardData->CSDRegister.DSR_IMP == 1) { // // Default is 0x404 // Status = SendCommand ( SDHostIo, SET_DSR, (DEFAULT_DSR_VALUE << 16), NoData, NULL, 0, ResponseNo, TIMEOUT_COMMAND, NULL ); if (EFI_ERROR (Status)) { DEBUG((EFI_D_ERROR, "SET_DSR Fail Status = 0x%x\n", Status)); // // Assume can operate even fail // } } // //Change clock frequency from 400KHz to max supported when not in high speed mode //Workaround to downgrade the frequency of MMC Card ver4.0 or above //In other words, don't enable high speed mode for the MMC card ver4.0 or above if ((CardData->CSDRegister.SPEC_VERS >= 4) && (CardData->CardType == MMCCard) ) { CardData->CSDRegister.SPEC_VERS = 3; } Status = SDHostIo->SetClockFrequency (SDHostIo, CardData->MaxFrequency); if (EFI_ERROR (Status)) { DEBUG((EFI_D_ERROR, "MMCSDCardInit:Fail to SetClockFrequency \n")); goto Exit; } // //Put the card into tran state // Status = SendCommand ( SDHostIo, SELECT_DESELECT_CARD, (CardData->Address << 16), NoData, NULL, 0, ResponseR1, TIMEOUT_COMMAND, (UINT32*)&(CardData->CardStatus) ); if (EFI_ERROR (Status)) { DEBUG((EFI_D_ERROR, "SELECT_DESELECT_CARD Fail Status = 0x%x\n", Status)); goto Exit; } // // No spec requirment, can be adjusted // gBS->Stall (5 * 1000); // // No need to do so // // Status = SendCommand ( SDHostIo, SEND_STATUS, (CardData->Address << 16), NoData, NULL, 0, ResponseR1, TIMEOUT_COMMAND, (UINT32*)&(CardData->CardStatus) ); if (EFI_ERROR (Status)) { DEBUG((EFI_D_ERROR, "SELECT_DESELECT_CARD SEND_STATUS Fail Status = 0x%x\n", Status)); goto Exit; } // //if the SPEC_VERS indicates a version 4.0 or higher //The card is a high speed card and support Switch //and Send_ext_csd command //otherwise it is an old card // if (CardData->CardType == MMCCard) { // //Only V4.0 and above supports more than 1 bits and high speed // if (CardData->CSDRegister.SPEC_VERS >= 4) { // //Get ExtCSDRegister // Status = SendCommand ( SDHostIo, SEND_EXT_CSD, 0x0, InData, CardData->AlignedBuffer, sizeof (EXT_CSD), ResponseR1, TIMEOUT_DATA, (UINT32*)&(CardData->CardStatus) ); if (EFI_ERROR (Status)) { DEBUG((EFI_D_ERROR, "SEND_EXT_CSD Fail Status = 0x%x\n", Status)); goto Exit; } CopyMem (&(CardData->ExtCSDRegister), CardData->AlignedBuffer, sizeof (EXT_CSD)); // // Recaculate the block number for >2G MMC card // Data = (CardData->ExtCSDRegister.SEC_COUNT[0]) | (CardData->ExtCSDRegister.SEC_COUNT[1] << 8) | (CardData->ExtCSDRegister.SEC_COUNT[2] << 16) | (CardData->ExtCSDRegister.SEC_COUNT[3] << 24); if (Data != 0) { CardData->BlockNumber = Data; } // // Check current chipset capability and the plugged-in card // whether supports HighSpeed // if (SDHostIo->HostCapability.HighSpeedSupport) { // //Change card timing to high speed interface timing // ZeroMem(&SwitchArgument, sizeof (SWITCH_ARGUMENT)); SwitchArgument.CmdSet = 0; SwitchArgument.Value = 1; SwitchArgument.Index = (UINT32)((UINTN) (&(CardData->ExtCSDRegister.HS_TIMING)) - (UINTN)(&(CardData->ExtCSDRegister))); SwitchArgument.Access = WriteByte_Mode; Status = SendCommand ( CardData->SDHostIo, SWITCH, *(UINT32*)&SwitchArgument, NoData, NULL, 0, ResponseR1b, TIMEOUT_COMMAND, (UINT32*)&(CardData->CardStatus) ); if (EFI_ERROR (Status)) { DEBUG((EFI_D_ERROR, "MMCSDCardInit:SWITCH frequency Fail Status = 0x%x\n", Status)); } gBS->Stall (5 * 1000); if (!EFI_ERROR (Status)) { Status = SendCommand ( SDHostIo, SEND_STATUS, (CardData->Address << 16), NoData, NULL, 0, ResponseR1, TIMEOUT_COMMAND, (UINT32*)&(CardData->CardStatus) ); if (!EFI_ERROR (Status)) { // // Change host clock to support high speed and enable chispet to // support speed // if ((CardData->ExtCSDRegister.CARD_TYPE & BIT1) != 0) { Status = SDHostIo->SetClockFrequency (SDHostIo, FREQUENCY_MMC_PP_HIGH); } else if ((CardData->ExtCSDRegister.CARD_TYPE & BIT0) != 0) { Status = SDHostIo->SetClockFrequency (SDHostIo, FREQUENCY_MMC_PP); } else { Status = EFI_UNSUPPORTED; } if (EFI_ERROR (Status)) { DEBUG((EFI_D_ERROR, "MMCSDCardInit:Fail to SetClockFrequency \n")); goto Exit; } // // It seems no need to stall after changing bus freqeuncy. // It is said that the freqeuncy can be changed at any time. Just appends 8 clocks after command. // But SetClock alreay has delay. // } } } Status = MMCCardBusWidthTest (CardData, 1); if (EFI_ERROR (Status)) { DEBUG((EFI_D_ERROR, "MMCCardBusWidthTest 1 bit Fail Status = 0x%x\n", Status)); } // // Prefer wide bus width for performance // // // Set to BusWidth bits mode, only version 4.0 or above support more than 1 bits // if (SDHostIo->HostCapability.BusWidth8 == TRUE) { Status = MMCCardSetBusWidth (CardData, 8); if (EFI_ERROR (Status)) { // // CE-ATA may support 8 bits and 4 bits, but has no software method for detection // Status = MMCCardSetBusWidth (CardData, 4); if (EFI_ERROR (Status)) { goto Exit; } } } else if (SDHostIo->HostCapability.BusWidth4 == TRUE) { Status = MMCCardSetBusWidth (CardData, 4); if (EFI_ERROR (Status)) { goto Exit; } } PowerValue = 0; if (CardData->CurrentBusWidth == 8) { if ((CardData->ExtCSDRegister.CARD_TYPE & BIT1) != 0) { PowerValue = CardData->ExtCSDRegister.PWR_CL_52_360; PowerValue = PowerValue >> 4; } else if ((CardData->ExtCSDRegister.CARD_TYPE & BIT0) != 0) { PowerValue = CardData->ExtCSDRegister.PWR_CL_26_360; PowerValue = PowerValue >> 4; }