--- /dev/null
+/** @file\r
+\r
+MMC/SD transfer specific functions\r
+\r
+Copyright (c) 2013-2015 Intel Corporation.\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 "SDMediaDevice.h"\r
+\r
+/**\r
+ Check card status, print the debug info and check the error\r
+\r
+ @param Status Status got from card status register.\r
+\r
+ @retval EFI_SUCCESS\r
+ @retval EFI_DEVICE_ERROR\r
+\r
+**/\r
+EFI_STATUS\r
+CheckCardStatus (\r
+ IN UINT32 Status\r
+ )\r
+{\r
+ CARD_STATUS *CardStatus;\r
+ CardStatus = (CARD_STATUS*)(&Status);\r
+\r
+ if (CardStatus->ADDRESS_OUT_OF_RANGE) {\r
+ DEBUG ((EFI_D_ERROR, "CardStatus: ADDRESS_OUT_OF_RANGE\n"));\r
+ }\r
+\r
+ if (CardStatus->ADDRESS_MISALIGN) {\r
+ DEBUG ((EFI_D_ERROR, "CardStatus: ADDRESS_MISALIGN\n"));\r
+ }\r
+\r
+ if (CardStatus->BLOCK_LEN_ERROR) {\r
+ DEBUG ((EFI_D_ERROR, "CardStatus: BLOCK_LEN_ERROR\n"));\r
+ }\r
+\r
+ if (CardStatus->ERASE_SEQ_ERROR) {\r
+ DEBUG ((EFI_D_ERROR, "CardStatus: ERASE_SEQ_ERROR\n"));\r
+ }\r
+\r
+ if (CardStatus->ERASE_PARAM) {\r
+ DEBUG ((EFI_D_ERROR, "CardStatus: ERASE_PARAM\n"));\r
+ }\r
+\r
+ if (CardStatus->WP_VIOLATION) {\r
+ DEBUG ((EFI_D_ERROR, "CardStatus: WP_VIOLATION\n"));\r
+ }\r
+\r
+ if (CardStatus->CARD_IS_LOCKED) {\r
+ DEBUG ((EFI_D_ERROR, "CardStatus: CARD_IS_LOCKED\n"));\r
+ }\r
+\r
+ if (CardStatus->LOCK_UNLOCK_FAILED) {\r
+ DEBUG ((EFI_D_ERROR, "CardStatus: LOCK_UNLOCK_FAILED\n"));\r
+ }\r
+\r
+ if (CardStatus->COM_CRC_ERROR) {\r
+ DEBUG ((EFI_D_ERROR, "CardStatus: COM_CRC_ERROR\n"));\r
+ }\r
+\r
+ if (CardStatus->ILLEGAL_COMMAND) {\r
+ DEBUG ((EFI_D_ERROR, "CardStatus: ILLEGAL_COMMAND\n"));\r
+ }\r
+\r
+ if (CardStatus->CARD_ECC_FAILED) {\r
+ DEBUG ((EFI_D_ERROR, "CardStatus: CARD_ECC_FAILED\n"));\r
+ }\r
+\r
+ if (CardStatus->CC_ERROR) {\r
+ DEBUG ((EFI_D_ERROR, "CardStatus: CC_ERROR\n"));\r
+ }\r
+\r
+ if (CardStatus->ERROR) {\r
+ DEBUG ((EFI_D_ERROR, "CardStatus: ERROR\n"));\r
+ }\r
+\r
+ if (CardStatus->UNDERRUN) {\r
+ DEBUG ((EFI_D_ERROR, "CardStatus: UNDERRUN\n"));\r
+ }\r
+\r
+ if (CardStatus->OVERRUN) {\r
+ DEBUG ((EFI_D_ERROR, "CardStatus: OVERRUN\n"));\r
+ }\r
+\r
+ if (CardStatus->CID_CSD_OVERWRITE) {\r
+ DEBUG ((EFI_D_ERROR, "CardStatus: CID_CSD_OVERWRITE\n"));\r
+ }\r
+\r
+ if (CardStatus->WP_ERASE_SKIP) {\r
+ DEBUG ((EFI_D_ERROR, "CardStatus: WP_ERASE_SKIP\n"));\r
+ }\r
+\r
+ if (CardStatus->ERASE_RESET) {\r
+ DEBUG ((EFI_D_ERROR, "CardStatus: ERASE_RESET\n"));\r
+ }\r
+\r
+ if (CardStatus->SWITCH_ERROR) {\r
+ DEBUG ((EFI_D_ERROR, "CardStatus: SWITCH_ERROR\n"));\r
+ }\r
+\r
+ if ((Status & 0xFCFFA080) != 0) {\r
+ return EFI_DEVICE_ERROR;\r
+ }\r
+\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+ Send command by using Host IO protocol\r
+\r
+ @param This A pointer to the EFI_SD_HOST_IO_PROTOCOL instance.\r
+ @param CommandIndex The command index to set the command index field of command register.\r
+ @param Argument Command argument to set the argument field of command register.\r
+ @param DataType TRANSFER_TYPE, indicates no data, data in or data out.\r
+ @param Buffer Contains the data read from / write to the device.\r
+ @param BufferSize The size of the buffer.\r
+ @param ResponseType RESPONSE_TYPE.\r
+ @param TimeOut Time out value in 1 ms unit.\r
+ @param ResponseData Depending on the ResponseType, such as CSD or card status.\r
+\r
+ @retval EFI_SUCCESS\r
+ @retval EFI_INVALID_PARAMETER\r
+ @retval EFI_UNSUPPORTED\r
+ @retval EFI_DEVICE_ERROR\r
+\r
+**/\r
+EFI_STATUS\r
+SendCommand (\r
+ IN CARD_DATA *CardData,\r
+ IN UINT16 CommandIndex,\r
+ IN UINT32 Argument,\r
+ IN TRANSFER_TYPE DataType,\r
+ IN UINT8 *Buffer, OPTIONAL\r
+ IN UINT32 BufferSize,\r
+ IN RESPONSE_TYPE ResponseType,\r
+ IN UINT32 TimeOut,\r
+ OUT UINT32 *ResponseData\r
+ )\r
+{\r
+\r
+ EFI_STATUS Status;\r
+ EFI_SD_HOST_IO_PROTOCOL *SDHostIo;\r
+ SDHostIo = CardData->SDHostIo;\r
+ if (CardData->CardType != MMCCard && CardData->CardType != MMCCardHighCap) {\r
+ CommandIndex |= AUTO_CMD12_ENABLE;\r
+ }\r
+\r
+ Status = SDHostIo->SendCommand (\r
+ SDHostIo,\r
+ CommandIndex,\r
+ Argument,\r
+ DataType,\r
+ Buffer,\r
+ BufferSize,\r
+ ResponseType,\r
+ TimeOut,\r
+ ResponseData\r
+ );\r
+ if (!EFI_ERROR (Status)) {\r
+ if (ResponseType == ResponseR1 || ResponseType == ResponseR1b) {\r
+ ASSERT(ResponseData != NULL);\r
+ Status = CheckCardStatus (*ResponseData);\r
+ }\r
+ } else {\r
+ SDHostIo->ResetSDHost (SDHostIo, Reset_DAT_CMD);\r
+ }\r
+\r
+ return Status;\r
+}\r
+\r
+/**\r
+ Send the card APP_CMD command with the following command indicated by CommandIndex\r
+\r
+ @param CardData Pointer to CARD_DATA.\r
+ @param CommandIndex The command index to set the command index field of command register.\r
+ @param Argument Command argument to set the argument field of command register.\r
+ @param DataType TRANSFER_TYPE, indicates no data, data in or data out.\r
+ @param Buffer Contains the data read from / write to the device.\r
+ @param BufferSize The size of the buffer.\r
+ @param ResponseType RESPONSE_TYPE.\r
+ @param TimeOut Time out value in 1 ms unit.\r
+ @param ResponseData Depending on the ResponseType, such as CSD or card status.\r
+\r
+ @retval EFI_SUCCESS\r
+ @retval EFI_INVALID_PARAMETER\r
+ @retval EFI_UNSUPPORTED\r
+ @retval EFI_DEVICE_ERROR\r
+\r
+**/\r
+EFI_STATUS\r
+SendAppCommand (\r
+ IN CARD_DATA *CardData,\r
+ IN UINT16 CommandIndex,\r
+ IN UINT32 Argument,\r
+ IN TRANSFER_TYPE DataType,\r
+ IN UINT8 *Buffer, OPTIONAL\r
+ IN UINT32 BufferSize,\r
+ IN RESPONSE_TYPE ResponseType,\r
+ IN UINT32 TimeOut,\r
+ OUT UINT32 *ResponseData\r
+ )\r
+{\r
+\r
+ EFI_STATUS Status;\r
+ EFI_SD_HOST_IO_PROTOCOL *SDHostIo;\r
+ UINT8 Index;\r
+\r
+ SDHostIo = CardData->SDHostIo;\r
+ Status = EFI_SUCCESS;\r
+\r
+ for (Index = 0; Index < 2; Index++) {\r
+ Status = SDHostIo->SendCommand (\r
+ SDHostIo,\r
+ APP_CMD,\r
+ (CardData->Address << 16),\r
+ NoData,\r
+ NULL,\r
+ 0,\r
+ ResponseR1,\r
+ TIMEOUT_COMMAND,\r
+ (UINT32*)&(CardData->CardStatus)\r
+ );\r
+ if (!EFI_ERROR (Status)) {\r
+ Status = CheckCardStatus (*(UINT32*)&(CardData->CardStatus));\r
+ if (CardData->CardStatus.SAPP_CMD != 1) {\r
+ Status = EFI_DEVICE_ERROR;\r
+ }\r
+ if (!EFI_ERROR (Status)) {\r
+ break;\r
+ }\r
+ } else {\r
+ SDHostIo->ResetSDHost (SDHostIo, Reset_Auto);\r
+ }\r
+ }\r
+\r
+ if (EFI_ERROR (Status)) {\r
+ return Status;\r
+ }\r
+ if (CardData->CardType != MMCCard && CardData->CardType != MMCCardHighCap) {\r
+ CommandIndex |= AUTO_CMD12_ENABLE;\r
+ }\r
+\r
+ Status = SDHostIo->SendCommand (\r
+ SDHostIo,\r
+ CommandIndex,\r
+ Argument,\r
+ DataType,\r
+ Buffer,\r
+ BufferSize,\r
+ ResponseType,\r
+ TimeOut,\r
+ ResponseData\r
+ );\r
+ if (!EFI_ERROR (Status)) {\r
+ if (ResponseType == ResponseR1 || ResponseType == ResponseR1b) {\r
+ ASSERT(ResponseData != NULL);\r
+ Status = CheckCardStatus (*ResponseData);\r
+ }\r
+ } else {\r
+ SDHostIo->ResetSDHost (SDHostIo, Reset_Auto);\r
+ }\r
+\r
+ return Status;\r
+}\r
+\r
+\r
+/**\r
+ Send the card FAST_IO command\r
+\r
+ @param CardData Pointer to CARD_DATA.\r
+ @param RegisterAddress Register Address.\r
+ @param RegisterData Pointer to register Data.\r
+ @param Write TRUE for write, FALSE for read.\r
+\r
+ @retval EFI_SUCCESS\r
+ @retval EFI_UNSUPPORTED\r
+ @retval EFI_INVALID_PARAMETER\r
+ @retval EFI_DEVICE_ERROR\r
+\r
+**/\r
+EFI_STATUS\r
+FastIO (\r
+ IN CARD_DATA *CardData,\r
+ IN UINT8 RegisterAddress,\r
+ IN OUT UINT8 *RegisterData,\r
+ IN BOOLEAN Write\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ UINT32 Argument;\r
+ UINT32 Data;\r
+\r
+ Status = EFI_SUCCESS;\r
+\r
+ if (RegisterData == NULL) {\r
+ Status = EFI_INVALID_PARAMETER;\r
+ goto Exit;\r
+ }\r
+\r
+ Argument = (CardData->Address << 16) | (RegisterAddress << 8);\r
+ if (Write) {\r
+ Argument |= BIT15 | (*RegisterData);\r
+ }\r
+\r
+ Status = SendCommand (\r
+ CardData,\r
+ FAST_IO,\r
+ Argument,\r
+ NoData,\r
+ NULL,\r
+ 0,\r
+ ResponseR4,\r
+ TIMEOUT_COMMAND,\r
+ &Data\r
+ );\r
+ if (EFI_ERROR (Status)) {\r
+ goto Exit;\r
+ }\r
+\r
+ if ((Data & BIT15) == 0) {\r
+ Status = EFI_DEVICE_ERROR;\r
+ goto Exit;\r
+ }\r
+\r
+ if (!Write) {\r
+ *RegisterData = (UINT8)Data;\r
+ }\r
+\r
+Exit:\r
+ return Status;\r
+}\r
+\r
+/**\r
+ Send the card GO_INACTIVE_STATE command.\r
+\r
+ @param CardData Pointer to CARD_DATA.\r
+\r
+ @return EFI_SUCCESS\r
+ @return others\r
+\r
+**/\r
+EFI_STATUS\r
+PutCardInactive (\r
+ IN CARD_DATA *CardData\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+\r
+\r
+ Status = SendCommand (\r
+ CardData,\r
+ GO_INACTIVE_STATE,\r
+ (CardData->Address << 16),\r
+ NoData,\r
+ NULL,\r
+ 0,\r
+ ResponseNo,\r
+ TIMEOUT_COMMAND,\r
+ NULL\r
+ );\r
+\r
+ return Status;\r
+\r
+}\r
+\r
+/**\r
+ Get card interested information for CSD rergister\r
+\r
+ @param CardData Pointer to CARD_DATA.\r
+\r
+ @retval EFI_SUCCESS\r
+ @retval EFI_UNSUPPORTED\r
+ @retval EFI_INVALID_PARAMETER\r
+\r
+**/\r
+EFI_STATUS\r
+CaculateCardParameter (\r
+ IN CARD_DATA *CardData\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ UINT32 Frequency;\r
+ UINT32 Multiple;\r
+ UINT32 CSize;\r
+ CSD_SDV2 *CsdSDV2;\r
+\r
+ Status = EFI_SUCCESS;\r
+\r
+ switch (CardData->CSDRegister.TRAN_SPEED & 0x7) {\r
+ case 0:\r
+ Frequency = 100 * 1000;\r
+ break;\r
+\r
+ case 1:\r
+ Frequency = 1 * 1000 * 1000;\r
+ break;\r
+\r
+ case 2:\r
+ Frequency = 10 * 1000 * 1000;\r
+ break;\r
+\r
+ case 3:\r
+ Frequency = 100 * 1000 * 1000;\r
+ break;\r
+\r
+ default:\r
+ Status = EFI_INVALID_PARAMETER;\r
+ goto Exit;\r
+ }\r
+\r
+ switch ((CardData->CSDRegister.TRAN_SPEED >> 3) & 0xF) {\r
+ case 1:\r
+ Multiple = 10;\r
+ break;\r
+\r
+ case 2:\r
+ Multiple = 12;\r
+ break;\r
+\r
+ case 3:\r
+ Multiple = 13;\r
+ break;\r
+\r
+ case 4:\r
+ Multiple = 15;\r
+ break;\r
+\r
+ case 5:\r
+ Multiple = 20;\r
+ break;\r
+\r
+ case 6:\r
+ if (CardData->CardType == MMCCard || CardData->CardType == MMCCardHighCap) {\r
+ Multiple = 26;\r
+ } else {\r
+ Multiple = 25;\r
+ }\r
+ break;\r
+\r
+ case 7:\r
+ Multiple = 30;\r
+ break;\r
+\r
+ case 8:\r
+ Multiple = 35;\r
+ break;\r
+\r
+ case 9:\r
+ Multiple = 40;\r
+ break;\r
+\r
+ case 10:\r
+ Multiple = 45;\r
+ break;\r
+\r
+ case 11:\r
+ if (CardData->CardType == MMCCard || CardData->CardType == MMCCardHighCap) {\r
+ Multiple = 52;\r
+ } else {\r
+ Multiple = 50;\r
+ }\r
+ break;\r
+\r
+ case 12:\r
+ Multiple = 55;\r
+ break;\r
+\r
+ case 13:\r
+ Multiple = 60;\r
+ break;\r
+\r
+ case 14:\r
+ Multiple = 70;\r
+ break;\r
+\r
+ case 15:\r
+ Multiple = 80;\r
+ break;\r
+\r
+ default:\r
+ Status = EFI_INVALID_PARAMETER;\r
+ goto Exit;\r
+ }\r
+\r
+ Frequency = Frequency * Multiple / 10;\r
+ CardData->MaxFrequency = Frequency;\r
+\r
+ CardData->BlockLen = 1 << CardData->CSDRegister.READ_BL_LEN;\r
+\r
+ if (CardData->CardType == SDMemoryCard2High) {\r
+ ASSERT(CardData->CSDRegister.CSD_STRUCTURE == 1);\r
+ CsdSDV2 = (CSD_SDV2*)&CardData->CSDRegister;\r
+ //\r
+ // The SD Spec 2.0 says (CSize + 1) * 512K is the total size, so block numbber is (CSize + 1) * 1K\r
+ // the K here means 1024 not 1000\r
+ //\r
+ CardData->BlockNumber = DivU64x32 (MultU64x32 (CsdSDV2->C_SIZE + 1, 512 * 1024) , CardData->BlockLen);\r
+ } else {\r
+ //\r
+ // For MMC card > 2G, the block number will be recaculate later\r
+ //\r
+ CSize = CardData->CSDRegister.C_SIZELow2 | (CardData->CSDRegister.C_SIZEHigh10 << 2);\r
+ CardData->BlockNumber = MultU64x32 (LShiftU64 (1, CardData->CSDRegister.C_SIZE_MULT + 2), CSize + 1);\r
+ }\r
+\r
+ //\r
+ //For >= 2G card, BlockLen may be 1024, but the transfer size is still 512 bytes\r
+ //\r
+ if (CardData->BlockLen > 512) {\r
+ CardData->BlockNumber = DivU64x32 (MultU64x32 (CardData->BlockNumber, CardData->BlockLen), 512);\r
+ CardData->BlockLen = 512;\r
+ }\r
+\r
+ DEBUG((\r
+ EFI_D_INFO,\r
+ "CalculateCardParameter: Card Size: 0x%lx\n", MultU64x32 (CardData->BlockNumber, CardData->BlockLen)\r
+ ));\r
+\r
+Exit:\r
+ return Status;\r
+}\r
+\r
+/**\r
+ Test the bus width setting for MMC card.It is used only for verification purpose.\r
+\r
+ @param CardData Pointer to CARD_DATA.\r
+ @param Width 1, 4, 8 bits.\r
+\r
+ @retval EFI_SUCCESS\r
+ @retval EFI_UNSUPPORTED\r
+ @retval EFI_INVALID_PARAMETER\r
+\r
+**/\r
+EFI_STATUS\r
+MMCCardBusWidthTest (\r
+ IN CARD_DATA *CardData,\r
+ IN UINT32 Width\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ UINT64 Data;\r
+ UINT64 Value;\r
+\r
+ ASSERT(CardData != NULL);\r
+\r
+\r
+ Value = 0;\r
+\r
+ switch (Width) {\r
+ case 1:\r
+ Data = 0x80;\r
+ break;\r
+\r
+ case 4:\r
+ Data = 0x5A;\r
+ break;\r
+\r
+ case 8:\r
+ Data = 0xAA55;\r
+ break;\r
+\r
+ default:\r
+ Status = EFI_INVALID_PARAMETER;\r
+ goto Exit;\r
+ }\r
+\r
+ CopyMem (CardData->AlignedBuffer, &Data, Width);\r
+ Status = SendCommand (\r
+ CardData,\r
+ BUSTEST_W,\r
+ 0,\r
+ OutData,\r
+ CardData->AlignedBuffer,\r
+ Width,\r
+ ResponseR1,\r
+ TIMEOUT_COMMAND,\r
+ (UINT32*)&(CardData->CardStatus)\r
+ );\r
+ if (EFI_ERROR (Status)) {\r
+ DEBUG((EFI_D_ERROR, "MMCCardBusWidthTest:SendCommand BUSTEST_W 0x%x\n", *(UINT32*)&(CardData->CardStatus)));\r
+ goto Exit;\r
+ }\r
+\r
+ gBS->Stall (10 * 1000);\r
+\r
+ Data = 0;\r
+\r
+ Status = SendCommand (\r
+ CardData,\r
+ BUSTEST_R,\r
+ 0,\r
+ InData,\r
+ CardData->AlignedBuffer,\r
+ Width,\r
+ ResponseR1,\r
+ TIMEOUT_COMMAND,\r
+ (UINT32*)&(CardData->CardStatus)\r
+ );\r
+ if (EFI_ERROR (Status)) {\r
+ DEBUG((EFI_D_ERROR, "MMCCardBusWidthTest:SendCommand BUSTEST_R 0x%x\n", *(UINT32*)&(CardData->CardStatus)));\r
+ goto Exit;\r
+ }\r
+ CopyMem (&Data, CardData->AlignedBuffer, Width);\r
+\r
+ switch (Width) {\r
+ case 1:\r
+ Value = (~(Data ^ 0x80)) & 0xC0;\r
+ break;\r
+ case 4:\r
+ Value = (~(Data ^ 0x5A)) & 0xFF;\r
+ break;\r
+ case 8:\r
+ Value = (~(Data ^ 0xAA55)) & 0xFFFF;\r
+ break;\r
+ }\r
+\r
+ if (Value == 0) {\r
+ Status = EFI_SUCCESS;\r
+ } else {\r
+ Status = EFI_UNSUPPORTED;\r
+ }\r
+\r
+\r
+Exit:\r
+ return Status;\r
+}\r
+\r
+/**\r
+ This function can detect these card types:\r
+ 1. MMC card\r
+ 2. SD 1.1 card\r
+ 3. SD 2.0 standard card\r
+ 3. SD 2.0 high capacity card\r
+\r
+ @param CardData Pointer to CARD_DATA.\r
+\r
+ @return EFI_SUCCESS\r
+ @return others\r
+\r
+**/\r
+EFI_STATUS\r
+GetCardType (\r
+ IN CARD_DATA *CardData\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ EFI_SD_HOST_IO_PROTOCOL *SDHostIo;\r
+ UINT32 Argument;\r
+ UINT32 ResponseData;\r
+ UINT32 Count;\r
+ BOOLEAN SDCommand8Support;\r
+\r
+\r
+ SDHostIo = CardData->SDHostIo;\r
+\r
+ //\r
+ // Reset the card\r
+ //\r
+ Status = SendCommand (\r
+ CardData,\r
+ GO_IDLE_STATE,\r
+ 0,\r
+ NoData,\r
+ NULL,\r
+ 0,\r
+ ResponseNo,\r
+ TIMEOUT_COMMAND,\r
+ NULL\r
+ );\r
+ if (EFI_ERROR (Status)) {\r
+ DEBUG((EFI_D_ERROR, "GO_IDLE_STATE Fail Status = 0x%x\n", Status));\r
+ goto Exit;\r
+ }\r
+\r
+ //\r
+ //No spec requirment, can be adjusted\r
+ //\r
+ gBS->Stall (10 * 1000);\r
+\r
+\r
+ //\r
+ // Only 2.7V - 3.6V is supported for SD2.0, only SD 2.0 card can pass\r
+ // MMC and SD1.1 card will fail this command\r
+ //\r
+ Argument = (VOLTAGE_27_36 << 8) | CHECK_PATTERN;\r
+ ResponseData = 0;\r
+ SDCommand8Support = FALSE;\r
+\r
+ Status = SendCommand (\r
+ CardData,\r
+ SEND_IF_COND,\r
+ Argument,\r
+ NoData,\r
+ NULL,\r
+ 0,\r
+ ResponseR7,\r
+ TIMEOUT_COMMAND,\r
+ &ResponseData\r
+ );\r
+\r
+ if (EFI_ERROR (Status)) {\r
+ if (Status != EFI_TIMEOUT) {\r
+ DEBUG((EFI_D_ERROR, "SEND_IF_COND Fail, none time out error\n"));\r
+ goto Exit;\r
+ }\r
+ } else {\r
+ if (ResponseData != Argument) {\r
+ DEBUG((EFI_D_ERROR, "SEND_IF_COND Fail, respond data does not match send data\n"));\r
+ Status = EFI_DEVICE_ERROR;\r
+ goto Exit;\r
+ }\r
+ SDCommand8Support = TRUE;\r
+ }\r
+\r
+\r
+ Argument = 0;\r
+ if (SDHostIo->HostCapability.V30Support == TRUE) {\r
+ Argument |= BIT17 | BIT18;\r
+ } else if (SDHostIo->HostCapability.V33Support == TRUE) {\r
+ Argument |= BIT20 | BIT21;\r
+ }\r
+\r
+ if (SDCommand8Support) {\r
+ //\r
+ //If command SD_SEND_OP_COND sucessed, it should be set.\r
+ // SD 1.1 card will ignore it\r
+ // SD 2.0 standard card will repsond with CCS 0, SD high capacity card will respond with CCS 1\r
+ // CCS is BIT30 of OCR\r
+ Argument |= BIT30;\r
+ }\r
+\r
+\r
+ Count = 20;\r
+ //\r
+ //Only SD card will respond to this command, and spec says the card only checks condition at first ACMD41 command\r
+ //\r
+ do {\r
+ Status = SendAppCommand (\r
+ CardData,\r
+ SD_SEND_OP_COND,\r
+ Argument,\r
+ NoData,\r
+ NULL,\r
+ 0,\r
+ ResponseR3,\r
+ TIMEOUT_COMMAND,\r
+ (UINT32*)&(CardData->OCRRegister)\r
+ );\r
+ if (EFI_ERROR (Status)) {\r
+ if ((Status == EFI_TIMEOUT) && (!SDCommand8Support)) {\r
+ CardData->CardType = MMCCard;\r
+ Status = EFI_SUCCESS;\r
+ DEBUG((EFI_D_INFO, "SD_SEND_OP_COND, MMC card was identified\n"));\r
+ } else {\r
+ //\r
+ // Not as expected, MMC card should has no response, which means timeout.\r
+ // SD card should pass this command\r
+ //\r
+ DEBUG((EFI_D_ERROR, "SD_SEND_OP_COND Fail, check whether it is neither a MMC card nor a SD card\n"));\r
+ }\r
+ goto Exit;\r
+ }\r
+ //\r
+ //Avoid waiting if sucess. Busy bit 0 means not ready\r
+ //\r
+ if (CardData->OCRRegister.Busy == 1) {\r
+ break;\r
+ }\r
+\r
+ gBS->Stall (50 * 1000);\r
+ Count--;\r
+ if (Count == 0) {\r
+ DEBUG((EFI_D_ERROR, "Card is always in busy state\n"));\r
+ Status = EFI_TIMEOUT;\r
+ goto Exit;\r
+ }\r
+ } while (1);\r
+\r
+ //\r
+ //Check supported voltage\r
+ //\r
+ Argument = 0;\r
+ if (SDHostIo->HostCapability.V30Support == TRUE) {\r
+ if ((CardData->OCRRegister.V270_V360 & BIT2) == BIT2) {\r
+ Argument |= BIT17;\r
+ } else if ((CardData->OCRRegister.V270_V360 & BIT3) == BIT3) {\r
+ Argument |= BIT18;\r
+ }\r
+ } else if (SDHostIo->HostCapability.V33Support == TRUE) {\r
+ if ((CardData->OCRRegister.V270_V360 & BIT5) == BIT5) {\r
+ Argument |= BIT20;\r
+ } else if ((CardData->OCRRegister.V270_V360 & BIT6) == BIT6) {\r
+ Argument |= BIT21;\r
+ }\r
+ }\r
+\r
+ if (Argument == 0) {\r
+ //\r
+ //No matched support voltage\r
+ //\r
+ PutCardInactive (CardData);\r
+ DEBUG((EFI_D_ERROR, "No matched voltage for this card\n"));\r
+ Status = EFI_UNSUPPORTED;\r
+ goto Exit;\r
+ }\r
+\r
+ CardData->CardType = SDMemoryCard;\r
+ if (SDCommand8Support == TRUE) {\r
+ CardData->CardType = SDMemoryCard2;\r
+ DEBUG((EFI_D_INFO, "SD_SEND_OP_COND, SD 2.0 or above standard card was identified\n"));\r
+ }\r
+\r
+ if ((CardData->OCRRegister.AccessMode & BIT1) == BIT1) {\r
+ CardData->CardType = SDMemoryCard2High;\r
+ DEBUG((EFI_D_INFO, "SD_SEND_OP_COND, SD 2.0 or above high capacity card was identified\n"));\r
+ }\r
+\r
+\r
+\r
+Exit:\r
+ return Status;\r
+}\r
+\r
+/**\r
+ MMC card high/low voltage selection function\r
+\r
+ @param CardData Pointer to CARD_DATA.\r
+\r
+ @retval EFI_SUCCESS\r
+ @retval EFI_INVALID_PARAMETER\r
+ @retval EFI_UNSUPPORTED\r
+ @retval EFI_BAD_BUFFER_SIZE\r
+\r
+**/\r
+EFI_STATUS\r
+MMCCardVoltageSelection (\r
+ IN CARD_DATA *CardData\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ EFI_SD_HOST_IO_PROTOCOL *SDHostIo;\r
+ UINT8 Retry;\r
+ UINT32 TimeOut;\r
+\r
+ Status = EFI_SUCCESS;\r
+ SDHostIo = CardData->SDHostIo;\r
+ //\r
+ //First try the high voltage, then if supported choose the low voltage\r
+ //\r
+\r
+ for (Retry = 0; Retry < 3; Retry++) {\r
+ //\r
+ // To bring back the normal MMC card to work\r
+ // after sending the SD command. Otherwise some\r
+ // card could not work\r
+\r
+ Status = SendCommand (\r
+ CardData,\r
+ GO_IDLE_STATE,\r
+ 0,\r
+ NoData,\r
+ NULL,\r
+ 0,\r
+ ResponseNo,\r
+ TIMEOUT_COMMAND,\r
+ NULL\r
+ );\r
+ if (EFI_ERROR (Status)) {\r
+ DEBUG((EFI_D_ERROR, "GO_IDLE_STATE Fail Status = 0x%x\n", Status));\r
+ continue;\r
+ }\r
+ //\r
+ //CE-ATA device needs long delay\r
+ //\r
+ gBS->Stall ((Retry + 1) * 50 * 1000);\r
+\r
+ //\r
+ //Get OCR register to check voltage support, first time the OCR is 0\r
+ //\r
+ Status = SendCommand (\r
+ CardData,\r
+ SEND_OP_COND,\r
+ 0,\r
+ NoData,\r
+ NULL,\r
+ 0,\r
+ ResponseR3,\r
+ TIMEOUT_COMMAND,\r
+ (UINT32*)&(CardData->OCRRegister)\r
+ );\r
+ if (!EFI_ERROR (Status)) {\r
+ break;\r
+ }\r
+ }\r
+\r
+ if (Retry == 3) {\r
+ DEBUG((EFI_D_ERROR, "SEND_OP_COND Fail Status = 0x%x\n", Status));\r
+ Status = EFI_DEVICE_ERROR;\r
+ goto Exit;\r
+ }\r
+\r
+ //\r
+ //TimeOut Value, 5000 * 100 * 1000 = 5 s\r
+ //\r
+ TimeOut = 5000;\r
+\r
+ do {\r
+ Status = SendCommand (\r
+ CardData,\r
+ SEND_OP_COND,\r
+ 0x40300000,\r
+ NoData,\r
+ NULL,\r
+ 0,\r
+ ResponseR3,\r
+ TIMEOUT_COMMAND,\r
+ (UINT32*)&(CardData->OCRRegister)\r
+ );\r
+ if (EFI_ERROR (Status)) {\r
+ DEBUG((EFI_D_ERROR, "SEND_OP_COND Fail Status = 0x%x\n", Status));\r
+ goto Exit;\r
+ }\r
+\r
+ gBS->Stall (1 * 1000);\r
+ TimeOut--;\r
+ if (TimeOut == 0) {\r
+ Status = EFI_TIMEOUT;\r
+ DEBUG((EFI_D_ERROR, "Card is always in busy state\n"));\r
+ goto Exit;\r
+ }\r
+ } while (CardData->OCRRegister.Busy != 1);\r
+\r
+ if (CardData->OCRRegister.AccessMode == 2) // eMMC Card uses Sector Addressing - High Capacity\r
+ {\r
+ DEBUG((EFI_D_INFO, "eMMC Card is High Capacity\n"));\r
+ CardData->CardType = MMCCardHighCap;\r
+ }\r
+\r
+Exit:\r
+ return Status;\r
+\r
+}\r
+\r
+/**\r
+ This function set the bus and device width for MMC card\r
+\r
+ @param CardData Pointer to CARD_DATA.\r
+ @param Width 1, 4, 8 bits.\r
+\r
+ @retval EFI_SUCCESS\r
+ @retval EFI_UNSUPPORTED\r
+ @retval EFI_INVALID_PARAMETER\r
+\r
+**/\r
+EFI_STATUS\r
+MMCCardSetBusWidth (\r
+ IN CARD_DATA *CardData,\r
+ IN UINT8 BusWidth,\r
+ IN BOOLEAN EnableDDRMode\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ EFI_SD_HOST_IO_PROTOCOL *SDHostIo;\r
+ SWITCH_ARGUMENT SwitchArgument;\r
+ UINT8 Value;\r
+\r
+ SDHostIo = CardData->SDHostIo;\r
+ Value = 0;\r
+ switch (BusWidth) {\r
+ case 8:\r
+ if (EnableDDRMode)\r
+ Value = 6;\r
+ else\r
+ Value = 2;\r
+ break;\r
+\r
+ case 4:\r
+ if (EnableDDRMode)\r
+ Value = 5;\r
+ else\r
+ Value = 1;\r
+ break;\r
+\r
+ case 1:\r
+ if (EnableDDRMode) // Bus width 1 is not supported in ddr mode\r
+ return EFI_UNSUPPORTED;\r
+ Value = 0;\r
+ break;\r
+\r
+ default:\r
+ ASSERT(0);\r
+ }\r
+\r
+\r
+ ZeroMem(&SwitchArgument, sizeof (SWITCH_ARGUMENT));\r
+ SwitchArgument.CmdSet = 0;\r
+ SwitchArgument.Value = Value;\r
+ SwitchArgument.Index = (UINT32)((UINTN)\r
+ (&(CardData->ExtCSDRegister.BUS_WIDTH)) - (UINTN)(&(CardData->ExtCSDRegister)));\r
+ SwitchArgument.Access = WriteByte_Mode;\r
+ Status = SendCommand (\r
+ CardData,\r
+ SWITCH,\r
+ *(UINT32*)&SwitchArgument,\r
+ NoData,\r
+ NULL,\r
+ 0,\r
+ ResponseR1b,\r
+ TIMEOUT_COMMAND,\r
+ (UINT32*)&(CardData->CardStatus)\r
+ );\r
+ if (!EFI_ERROR (Status)) {\r
+ Status = SendCommand (\r
+ CardData,\r
+ SEND_STATUS,\r
+ (CardData->Address << 16),\r
+ NoData,\r
+ NULL,\r
+ 0,\r
+ ResponseR1,\r
+ TIMEOUT_COMMAND,\r
+ (UINT32*)&(CardData->CardStatus)\r
+ );\r
+ if (EFI_ERROR (Status)) {\r
+ DEBUG((EFI_D_ERROR, "SWITCH %d bits Fail\n", BusWidth));\r
+ goto Exit;\r
+ } else {\r
+ DEBUG((EFI_D_ERROR, "MMCCardSetBusWidth:SWITCH Card Status:0x%x\n", *(UINT32*)&(CardData->CardStatus)));\r
+ Status = SDHostIo->SetBusWidth (SDHostIo, BusWidth);\r
+ if (EFI_ERROR (Status)) {\r
+ DEBUG((EFI_D_ERROR, "SWITCH set %d bits Fail\n", BusWidth));\r
+ goto Exit;\r
+ }\r
+ gBS->Stall (5 * 1000);\r
+ }\r
+ }\r
+\r
+ if (!EnableDDRMode) { // CMD19 and CMD14 are illegal commands in ddr mode\r
+ //if (EFI_ERROR (Status)) {\r
+ // DEBUG((EFI_D_ERROR, "MMCCardBusWidthTest: Fail to enable high speed mode\n"));\r
+ // goto Exit;\r
+ //}\r
+\r
+ Status = MMCCardBusWidthTest (CardData, BusWidth);\r
+ if (EFI_ERROR (Status)) {\r
+ DEBUG((EFI_D_ERROR, "MMCCardBusWidthTest %d bit Fail\n", BusWidth));\r
+ goto Exit;\r
+ }\r
+ }\r
+\r
+ CardData->CurrentBusWidth = BusWidth;\r
+\r
+Exit:\r
+ return Status;\r
+}\r
+\r
+\r
+/**\r
+ MMC/SD card init function\r
+\r
+ @param CardData Pointer to CARD_DATA.\r
+\r
+ @return EFI_SUCCESS\r
+ @return others\r
+\r
+**/\r
+EFI_STATUS\r
+MMCSDCardInit (\r
+ IN CARD_DATA *CardData\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ EFI_SD_HOST_IO_PROTOCOL *SDHostIo;\r
+ SWITCH_ARGUMENT SwitchArgument;\r
+ UINT32 Data;\r
+ UINT32 Argument;\r
+ UINT32 nIndex;\r
+ UINT8 PowerValue;\r
+ BOOLEAN EnableDDRMode;\r
+\r
+ ASSERT(CardData != NULL);\r
+ SDHostIo = CardData->SDHostIo;\r
+ EnableDDRMode = FALSE;\r
+\r
+ CardData->CardType = UnknownCard;\r
+ Status = GetCardType (CardData);\r
+ if (EFI_ERROR (Status)) {\r
+ goto Exit;\r
+ }\r
+ DEBUG((DEBUG_INFO, "CardData->CardType 0x%x\n", CardData->CardType));\r
+\r
+ ASSERT (CardData->CardType != UnknownCard);\r
+ //\r
+ //MMC, SD card need host auto stop command support\r
+ //\r
+ SDHostIo->EnableAutoStopCmd (SDHostIo, TRUE);\r
+\r
+ if (CardData->CardType == MMCCard) {\r
+ Status = MMCCardVoltageSelection (CardData);\r
+ if (EFI_ERROR(Status)) {\r
+ goto Exit;\r
+ }\r
+ }\r
+\r
+ //\r
+ // Get CID Register\r
+ //\r
+ Status = SendCommand (\r
+ CardData,\r
+ ALL_SEND_CID,\r
+ 0,\r
+ NoData,\r
+ NULL,\r
+ 0,\r
+ ResponseR2,\r
+ TIMEOUT_COMMAND,\r
+ (UINT32*)&(CardData->CIDRegister)\r
+ );\r
+ if (EFI_ERROR (Status)) {\r
+ DEBUG((EFI_D_ERROR, "ALL_SEND_CID Fail Status = 0x%x\n", Status));\r
+ goto Exit;\r
+ } else {\r
+ // Dump out the Card ID data\r
+ DEBUG((EFI_D_INFO, "Product Name: "));\r
+ for ( nIndex=0; nIndex<6; nIndex++ ) {\r
+ DEBUG((EFI_D_INFO, "%c", CardData->CIDRegister.PNM[nIndex]));\r
+ }\r
+ DEBUG((EFI_D_INFO, "\nApplication ID : %d\n", CardData->CIDRegister.OID));\r
+ DEBUG((EFI_D_INFO, "Manufacturer ID: %d\n", CardData->CIDRegister.MID));\r
+ DEBUG((EFI_D_INFO, "Revision ID : %d\n", CardData->CIDRegister.PRV));\r
+ DEBUG((EFI_D_INFO, "Serial Number : %d\n", CardData->CIDRegister.PSN));\r
+ }\r
+\r
+ //\r
+ //SET_RELATIVE_ADDR\r
+ //\r
+ if (CardData->CardType == MMCCard || CardData->CardType == MMCCardHighCap) {\r
+ //\r
+ //Hard code the RCA address\r
+ //\r
+ CardData->Address = 1;\r
+\r
+ //\r
+ // Set RCA Register\r
+ //\r
+ Status = SendCommand (\r
+ CardData,\r
+ SET_RELATIVE_ADDR,\r
+ (CardData->Address << 16),\r
+ NoData,\r
+ NULL,\r
+ 0,\r
+ ResponseR1,\r
+ TIMEOUT_COMMAND,\r
+ (UINT32*)&(CardData->CardStatus)\r
+ );\r
+ if (EFI_ERROR (Status)) {\r
+ DEBUG((EFI_D_ERROR, "SET_RELATIVE_ADDR Fail Status = 0x%x\n", Status));\r
+ goto Exit;\r
+ }\r
+ } else {\r
+ Data = 0;\r
+ Status = SendCommand (\r
+ CardData,\r
+ SET_RELATIVE_ADDR,\r
+ 0,\r
+ NoData,\r
+ NULL,\r
+ 0,\r
+ ResponseR6,\r
+ TIMEOUT_COMMAND,\r
+ &Data\r
+ );\r
+ if (EFI_ERROR (Status)) {\r
+ DEBUG((EFI_D_ERROR, "SET_RELATIVE_ADDR Fail Status = 0x%x\n", Status));\r
+ goto Exit;\r
+ }\r
+\r
+ CardData->Address = (UINT16)(Data >> 16);\r
+ *(UINT32*)&CardData->CardStatus = Data & 0x1FFF;\r
+ CardData->CardStatus.ERROR = (Data >> 13) & 0x1;\r
+ CardData->CardStatus.ILLEGAL_COMMAND = (Data >> 14) & 0x1;\r
+ CardData->CardStatus.COM_CRC_ERROR = (Data >> 15) & 0x1;\r
+ Status = CheckCardStatus (*(UINT32*)&CardData->CardStatus);\r
+ if (EFI_ERROR (Status)) {\r
+ DEBUG((EFI_D_ERROR, "SET_RELATIVE_ADDR Fail Status = 0x%x\n", Status));\r
+ goto Exit;\r
+ }\r
+ }\r
+\r
+ //\r
+ // Get CSD Register\r
+ //\r
+ Status = SendCommand (\r
+ CardData,\r
+ SEND_CSD,\r
+ (CardData->Address << 16),\r
+ NoData,\r
+ NULL,\r
+ 0,\r
+ ResponseR2,\r
+ TIMEOUT_COMMAND,\r
+ (UINT32*)&(CardData->CSDRegister)\r
+ );\r
+ if (EFI_ERROR (Status)) {\r
+ DEBUG((EFI_D_ERROR, "SEND_CSD Fail Status = 0x%x\n", Status));\r
+ goto Exit;\r
+ }\r
+\r
+ DEBUG((EFI_D_INFO, "CardData->CSDRegister.SPEC_VERS = 0x%x\n", CardData->CSDRegister.SPEC_VERS));\r
+ DEBUG((EFI_D_INFO, "CardData->CSDRegister.CSD_STRUCTURE = 0x%x\n", CardData->CSDRegister.CSD_STRUCTURE));\r
+\r
+ Status = CaculateCardParameter (CardData);\r
+ if (EFI_ERROR (Status)) {\r
+ goto Exit;\r
+ }\r
+\r
+\r
+ //\r
+ // It is platform and hardware specific, need hadrware engineer input\r
+ //\r
+ if (CardData->CSDRegister.DSR_IMP == 1) {\r
+ //\r
+ // Default is 0x404\r
+ //\r
+ Status = SendCommand (\r
+ CardData,\r
+ SET_DSR,\r
+ (DEFAULT_DSR_VALUE << 16),\r
+ NoData,\r
+ NULL,\r
+ 0,\r
+ ResponseNo,\r
+ TIMEOUT_COMMAND,\r
+ NULL\r
+ );\r
+ if (EFI_ERROR (Status)) {\r
+ DEBUG((EFI_D_ERROR, "SET_DSR Fail Status = 0x%x\n", Status));\r
+ //\r
+ // Assume can operate even fail\r
+ //\r
+ }\r
+ }\r
+ //\r
+ //Change clock frequency from 400KHz to max supported when not in high speed mode\r
+ //\r
+ Status = SDHostIo->SetClockFrequency (SDHostIo, CardData->MaxFrequency);\r
+ if (EFI_ERROR (Status)) {\r
+ DEBUG((EFI_D_ERROR, "MMCSDCardInit:Fail to SetClockFrequency \n"));\r
+ goto Exit;\r
+ }\r
+\r
+ //\r
+ //Put the card into tran state\r
+ //\r
+ Status = SendCommand (\r
+ CardData,\r
+ SELECT_DESELECT_CARD,\r
+ (CardData->Address << 16),\r
+ NoData,\r
+ NULL,\r
+ 0,\r
+ ResponseR1,\r
+ TIMEOUT_COMMAND,\r
+ (UINT32*)&(CardData->CardStatus)\r
+ );\r
+ if (EFI_ERROR (Status)) {\r
+ DEBUG((EFI_D_ERROR, "SELECT_DESELECT_CARD Fail Status = 0x%x\n", Status));\r
+ goto Exit;\r
+ }\r
+\r
+ //\r
+ // No spec requirment, can be adjusted\r
+ //\r
+ gBS->Stall (5 * 1000);\r
+ //\r
+ // No need to do so\r
+ //\r
+ //\r
+ Status = SendCommand (\r
+ CardData,\r
+ SEND_STATUS,\r
+ (CardData->Address << 16),\r
+ NoData,\r
+ NULL,\r
+ 0,\r
+ ResponseR1,\r
+ TIMEOUT_COMMAND,\r
+ (UINT32*)&(CardData->CardStatus)\r
+ );\r
+ if (EFI_ERROR (Status)) {\r
+ DEBUG((EFI_D_ERROR, "SELECT_DESELECT_CARD SEND_STATUS Fail Status = 0x%x\n", Status));\r
+ goto Exit;\r
+ }\r
+ //\r
+ //if the SPEC_VERS indicates a version 4.0 or higher\r
+ //The card is a high speed card and support Switch\r
+ //and Send_ext_csd command\r
+ //otherwise it is an old card\r
+ //\r
+\r
+ if (CardData->CardType == MMCCard || CardData->CardType == MMCCardHighCap) {\r
+ //\r
+ //Only V4.0 and above supports more than 1 bits and high speed\r
+ //\r
+ if (CardData->CSDRegister.SPEC_VERS >= 4) {\r
+ //\r
+ //Get ExtCSDRegister\r
+ //\r
+ Status = SendCommand (\r
+ CardData,\r
+ SEND_EXT_CSD,\r
+ 0x0,\r
+ InData,\r
+ CardData->AlignedBuffer,\r
+ sizeof (EXT_CSD),\r
+ ResponseR1,\r
+ TIMEOUT_DATA,\r
+ (UINT32*)&(CardData->CardStatus)\r
+ );\r
+ if (EFI_ERROR (Status)) {\r
+ DEBUG((EFI_D_ERROR, "SEND_EXT_CSD Fail Status = 0x%x\n", Status));\r
+ goto Exit;\r
+ }\r
+\r
+ CopyMem (&(CardData->ExtCSDRegister), CardData->AlignedBuffer, sizeof (EXT_CSD));\r
+\r
+ //\r
+ // Recaculate the block number for >2G MMC card\r
+ //\r
+ Data = (CardData->ExtCSDRegister.SEC_COUNT[0]) |\r
+ (CardData->ExtCSDRegister.SEC_COUNT[1] << 8) |\r
+ (CardData->ExtCSDRegister.SEC_COUNT[2] << 16) |\r
+ (CardData->ExtCSDRegister.SEC_COUNT[3] << 24);\r
+\r
+ if (Data != 0) {\r
+ CardData->BlockNumber = Data;\r
+ }\r
+ DEBUG((DEBUG_INFO, "CardData->BlockNumber %d\n", Data));\r
+ DEBUG((EFI_D_ERROR, "CardData->ExtCSDRegister.CARD_TYPE -> %d\n", (UINTN)CardData->ExtCSDRegister.CARD_TYPE));\r
+ if ((CardData->ExtCSDRegister.CARD_TYPE & BIT2)||\r
+ (CardData->ExtCSDRegister.CARD_TYPE & BIT3)) {\r
+ //DEBUG((DEBUG_INFO, "To enable DDR mode\n"));\r
+ //EnableDDRMode = TRUE;\r
+ }\r
+ //\r
+ // Check current chipset capability and the plugged-in card\r
+ // whether supports HighSpeed\r
+ //\r
+ if (SDHostIo->HostCapability.HighSpeedSupport) {\r
+\r
+ //\r
+ //Change card timing to high speed interface timing\r
+ //\r
+ ZeroMem(&SwitchArgument, sizeof (SWITCH_ARGUMENT));\r
+ SwitchArgument.CmdSet = 0;\r
+ SwitchArgument.Value = 1;\r
+ SwitchArgument.Index = (UINT32)((UINTN)\r
+ (&(CardData->ExtCSDRegister.HS_TIMING)) - (UINTN)(&(CardData->ExtCSDRegister)));\r
+ SwitchArgument.Access = WriteByte_Mode;\r
+ Status = SendCommand (\r
+ CardData,\r
+ SWITCH,\r
+ *(UINT32*)&SwitchArgument,\r
+ NoData,\r
+ NULL,\r
+ 0,\r
+ ResponseR1b,\r
+ TIMEOUT_COMMAND,\r
+ (UINT32*)&(CardData->CardStatus)\r
+ );\r
+ if (EFI_ERROR (Status)) {\r
+ DEBUG((EFI_D_ERROR, "MMCSDCardInit:SWITCH frequency Fail Status = 0x%x\n", Status));\r
+ }\r
+\r
+ gBS->Stall (5 * 1000);\r
+\r
+\r
+ if (!EFI_ERROR (Status)) {\r
+ Status = SendCommand (\r
+ CardData,\r
+ SEND_STATUS,\r
+ (CardData->Address << 16),\r
+ NoData,\r
+ NULL,\r
+ 0,\r
+ ResponseR1,\r
+ TIMEOUT_COMMAND,\r
+ (UINT32*)&(CardData->CardStatus)\r
+ );\r
+ if (!EFI_ERROR (Status)) {\r
+ if (EnableDDRMode) {\r
+ DEBUG((EFI_D_ERROR, "Enable ddr mode on host controller\n"));\r
+ SDHostIo->SetDDRMode (SDHostIo, TRUE);\r
+ } else {\r
+ DEBUG((EFI_D_ERROR, "Enable high speed mode on host controller\n"));\r
+ SDHostIo->SetHighSpeedMode (SDHostIo, TRUE);\r
+ }\r
+ //\r
+ // Change host clock to support high speed and enable chispet to\r
+ // support speed\r
+ //\r
+ if ((CardData->ExtCSDRegister.CARD_TYPE & BIT1) != 0) {\r
+ Status = SDHostIo->SetClockFrequency (SDHostIo, FREQUENCY_MMC_PP_HIGH);\r
+ } else if ((CardData->ExtCSDRegister.CARD_TYPE & BIT0) != 0) {\r
+ Status = SDHostIo->SetClockFrequency (SDHostIo, FREQUENCY_MMC_PP);\r
+ } else {\r
+ Status = EFI_UNSUPPORTED;\r
+ }\r
+ if (EFI_ERROR (Status)) {\r
+ DEBUG((EFI_D_ERROR, "MMCSDCardInit:Fail to SetClockFrequency \n"));\r
+ goto Exit;\r
+ }\r
+ //\r
+ // It seems no need to stall after changing bus freqeuncy.\r
+ // It is said that the freqeuncy can be changed at any time. Just appends 8 clocks after command.\r
+ // But SetClock alreay has delay.\r
+ //\r
+ }\r
+ }\r
+\r
+ }\r
+\r
+\r
+\r
+ //\r
+ // Prefer wide bus width for performance\r
+ //\r
+ //\r
+ // Set to BusWidth bits mode, only version 4.0 or above support more than 1 bits\r
+ //\r
+ if (SDHostIo->HostCapability.BusWidth8 == TRUE) {\r
+ Status = MMCCardSetBusWidth (CardData, 8, EnableDDRMode);\r
+ if (EFI_ERROR (Status)) {\r
+ //\r
+ // CE-ATA may support 8 bits and 4 bits, but has no software method for detection\r
+ //\r
+ Status = MMCCardSetBusWidth (CardData, 4, EnableDDRMode);\r
+ if (EFI_ERROR (Status)) {\r
+ goto Exit;\r
+ }\r
+ }\r
+ } else if (SDHostIo->HostCapability.BusWidth4 == TRUE) {\r
+ Status = MMCCardSetBusWidth (CardData, 4, EnableDDRMode);\r
+ if (EFI_ERROR (Status)) {\r
+ goto Exit;\r
+ }\r
+ }\r
+\r
+ PowerValue = 0;\r
+\r
+ if (CardData->CurrentBusWidth == 8) {\r
+ if ((CardData->ExtCSDRegister.CARD_TYPE & BIT1) != 0) {\r
+ PowerValue = CardData->ExtCSDRegister.PWR_CL_52_360;\r
+ PowerValue = PowerValue >> 4;\r
+ } else if ((CardData->ExtCSDRegister.CARD_TYPE & BIT0) != 0) {\r
+ PowerValue = CardData->ExtCSDRegister.PWR_CL_26_360;\r
+ PowerValue = PowerValue >> 4;\r
+ }\r
+ } else if (CardData->CurrentBusWidth == 4) {\r
+ if ((CardData->ExtCSDRegister.CARD_TYPE & BIT1) != 0) {\r
+ PowerValue = CardData->ExtCSDRegister.PWR_CL_52_360;\r
+ PowerValue = PowerValue & 0xF;\r
+ } else if ((CardData->ExtCSDRegister.CARD_TYPE & BIT0) != 0) {\r
+ PowerValue = CardData->ExtCSDRegister.PWR_CL_26_360;\r
+ PowerValue = PowerValue & 0xF;\r
+ }\r
+ }\r
+\r
+ if (PowerValue != 0) {\r
+ //\r
+ //Update Power Class\r
+ //\r
+ ZeroMem(&SwitchArgument, sizeof (SWITCH_ARGUMENT));\r
+ SwitchArgument.CmdSet = 0;\r
+ SwitchArgument.Value = PowerValue;\r
+ SwitchArgument.Index = (UINT32)((UINTN)\r
+ (&(CardData->ExtCSDRegister.POWER_CLASS)) - (UINTN)(&(CardData->ExtCSDRegister)));\r
+ SwitchArgument.Access = WriteByte_Mode;\r
+ Status = SendCommand (\r
+ CardData,\r
+ SWITCH,\r
+ *(UINT32*)&SwitchArgument,\r
+ NoData,\r
+ NULL,\r
+ 0,\r
+ ResponseR1b,\r
+ TIMEOUT_COMMAND,\r
+ (UINT32*)&(CardData->CardStatus)\r
+ );\r
+ if (!EFI_ERROR (Status)) {\r
+ Status = SendCommand (\r
+ CardData,\r
+ SEND_STATUS,\r
+ (CardData->Address << 16),\r
+ NoData,\r
+ NULL,\r
+ 0,\r
+ ResponseR1,\r
+ TIMEOUT_COMMAND,\r
+ (UINT32*)&(CardData->CardStatus)\r
+ );\r
+ if (EFI_ERROR (Status)) {\r
+ DEBUG((EFI_D_ERROR, "SWITCH Power Class Fail Status = 0x%x\n", Status));\r
+ }\r
+ //gBS->Stall (10 * 1000);\r
+ }\r
+ }\r
+\r
+\r
+\r
+ } else {\r
+\r
+\r
+ DEBUG((EFI_D_ERROR, "MMC Card version %d only supportes 1 bits at lower transfer speed\n",CardData->CSDRegister.SPEC_VERS));\r
+ }\r
+ } else {\r
+ //\r
+ // Pin 1, at power up this line has a 50KOhm pull up enabled in the card.\r
+ // This pull-up should be disconnected by the user, during regular data transfer,\r
+ // with SET_CLR_CARD_DETECT (ACMD42) command\r
+ //\r
+ Status = SendAppCommand (\r
+ CardData,\r
+ SET_CLR_CARD_DETECT,\r
+ 0,\r
+ NoData,\r
+ NULL,\r
+ 0,\r
+ ResponseR1,\r
+ TIMEOUT_COMMAND,\r
+ (UINT32*)&(CardData->CardStatus)\r
+ );\r
+ if (EFI_ERROR (Status)) {\r
+ DEBUG((EFI_D_ERROR, "SET_CLR_CARD_DETECT Fail Status = 0x%x\n", Status));\r
+ goto Exit;\r
+ }\r
+\r
+ /*\r
+ //\r
+ // Don't rely on SCR and SD status, some cards have unexpected SCR.\r
+ // It only sets private section, the other bits are 0\r
+ // such as Sandisk Ultra II 4.0G, KinSton mini SD 128M, Toshiba 2.0GB\r
+ // Some card even fail this command, KinSton SD 4GB\r
+ //\r
+ Status = SendAppCommand (\r
+ CardData,\r
+ SEND_SCR,\r
+ 0,\r
+ InData,\r
+ (UINT8*)&(CardData->SCRRegister),\r
+ sizeof(SCR),\r
+ ResponseR1,\r
+ TIMEOUT_COMMAND,\r
+ (UINT32*)&(CardData->CardStatus)\r
+ );\r
+ if (EFI_ERROR (Status)) {\r
+ goto Exit;\r
+ }\r
+\r
+ //\r
+ // SD memory card at least supports 1 and 4 bits.\r
+ //\r
+ // ASSERT ((CardData->SCRRegister.SD_BUS_WIDTH & (BIT0 | BIT2)) == (BIT0 | BIT2));\r
+ */\r
+\r
+ //\r
+ // Set Bus Width to 4\r
+ //\r
+ Status = SendAppCommand (\r
+ CardData,\r
+ SET_BUS_WIDTH,\r
+ SD_BUS_WIDTH_4,\r
+ NoData,\r
+ NULL,\r
+ 0,\r
+ ResponseR1,\r
+ TIMEOUT_COMMAND,\r
+ (UINT32*)&(CardData->CardStatus)\r
+ );\r
+ if (EFI_ERROR (Status)) {\r
+ DEBUG((EFI_D_ERROR, "SET_BUS_WIDTH 4 bits Fail Status = 0x%x\n", Status));\r
+ goto Exit;\r
+ }\r
+\r
+ Status = SDHostIo->SetBusWidth (SDHostIo, 4);\r
+ if (EFI_ERROR (Status)) {\r
+ goto Exit;\r
+ }\r
+ CardData->CurrentBusWidth = 4;\r
+\r
+\r
+ if ((SDHostIo->HostCapability.HighSpeedSupport == FALSE) ||\r
+ ((CardData->CSDRegister.CCC & BIT10) != BIT10)) {\r
+ //\r
+ // Host must support high speed\r
+ // Card must support Switch function\r
+ //\r
+ goto Exit;\r
+ }\r
+\r
+ //\r
+ //Mode = 0, group 1, function 1, check operation\r
+ //\r
+ Argument = 0xFFFF01;\r
+ ZeroMem (&CardData->SwitchStatus, sizeof (SWITCH_STATUS));\r
+\r
+ Status = SendCommand (\r
+ CardData,\r
+ SWITCH_FUNC,\r
+ Argument,\r
+ InData,\r
+ CardData->AlignedBuffer,\r
+ sizeof (SWITCH_STATUS),\r
+ ResponseR1,\r
+ TIMEOUT_COMMAND,\r
+ (UINT32*)&(CardData->CardStatus)\r
+ );\r
+ if (EFI_ERROR (Status)) {\r
+ goto Exit;\r
+ }\r
+ CopyMem (&(CardData->SwitchStatus), CardData->AlignedBuffer, sizeof (SWITCH_STATUS));\r
+\r
+ if ((CardData->SwitchStatus.DataStructureVersion == 0x0) ||\r
+ ((CardData->SwitchStatus.Group1BusyStatus & BIT1) != BIT1)) {\r
+ //\r
+ // 1. SD 1.1 card does not suppport busy bit\r
+ // 2. Ready state\r
+ //\r
+ //\r
+\r
+ //\r
+ //Mode = 1, group 1, function 1, BIT31 set means set mode\r
+ //\r
+ Argument = 0xFFFF01 | BIT31;\r
+ ZeroMem (&CardData->SwitchStatus, sizeof (SWITCH_STATUS));\r
+\r
+ Status = SendCommand (\r
+ CardData,\r
+ SWITCH_FUNC,\r
+ Argument,\r
+ InData,\r
+ CardData->AlignedBuffer,\r
+ sizeof (SWITCH_STATUS),\r
+ ResponseR1,\r
+ TIMEOUT_COMMAND,\r
+ (UINT32*)&(CardData->CardStatus)\r
+ );\r
+ if (EFI_ERROR (Status)) {\r
+ goto Exit;\r
+ }\r
+ CopyMem (&(CardData->SwitchStatus), CardData->AlignedBuffer, sizeof (SWITCH_STATUS));\r
+\r
+ if ((CardData->SwitchStatus.DataStructureVersion == 0x0) ||\r
+ ((CardData->SwitchStatus.Group1BusyStatus & BIT1) != BIT1)) {\r
+ //\r
+ // 1. SD 1.1 card does not suppport busy bit\r
+ // 2. Ready state\r
+ //\r
+\r
+ //\r
+ // 8 clocks, (1/ 25M) * 8 ==> 320 us, so 1ms > 0.32 ms\r
+ //\r
+ gBS->Stall (1000);\r
+\r
+ //\r
+ //Change host clock\r
+ //\r
+ Status = SDHostIo->SetClockFrequency (SDHostIo, FREQUENCY_SD_PP_HIGH);\r
+ if (EFI_ERROR (Status)) {\r
+ goto Exit;\r
+ }\r
+\r
+ }\r
+ }\r
+ }\r
+ if (!((CardData->ExtCSDRegister.CARD_TYPE & BIT2) ||\r
+ (CardData->ExtCSDRegister.CARD_TYPE & BIT3))) {\r
+\r
+ //\r
+ // Set Block Length, to improve compatibility in case of some cards\r
+ //\r
+ Status = SendCommand (\r
+ CardData,\r
+ SET_BLOCKLEN,\r
+ 512,\r
+ NoData,\r
+ NULL,\r
+ 0,\r
+ ResponseR1,\r
+ TIMEOUT_COMMAND,\r
+ (UINT32*)&(CardData->CardStatus)\r
+ );\r
+ if (EFI_ERROR (Status)) {\r
+ DEBUG((EFI_D_ERROR, "SET_BLOCKLEN Fail Status = 0x%x\n", Status));\r
+ goto Exit;\r
+ }\r
+ }\r
+ SDHostIo->SetBlockLength (SDHostIo, 512);\r
+\r
+\r
+Exit:\r
+ return Status;\r
+}\r
+\r