*\r
**/\r
\r
+#include <Library/BaseMemoryLib.h>\r
+#include <Library/TimerLib.h>\r
+\r
#include "Mmc.h"\r
\r
typedef union {\r
#define EMMC_CARD_SIZE 512\r
#define EMMC_ECSD_SIZE_OFFSET 53\r
\r
+#define EXTCSD_BUS_WIDTH 183\r
+#define EXTCSD_HS_TIMING 185\r
+\r
+#define EMMC_TIMING_BACKWARD 0\r
+#define EMMC_TIMING_HS 1\r
+#define EMMC_TIMING_HS200 2\r
+#define EMMC_TIMING_HS400 3\r
+\r
+#define EMMC_BUS_WIDTH_1BIT 0\r
+#define EMMC_BUS_WIDTH_4BIT 1\r
+#define EMMC_BUS_WIDTH_8BIT 2\r
+#define EMMC_BUS_WIDTH_DDR_4BIT 5\r
+#define EMMC_BUS_WIDTH_DDR_8BIT 6\r
+\r
+#define EMMC_SWITCH_ERROR (1 << 7)\r
+\r
+#define SD_BUS_WIDTH_1BIT (1 << 0)\r
+#define SD_BUS_WIDTH_4BIT (1 << 2)\r
+\r
+#define SD_CCC_SWITCH (1 << 10)\r
+\r
+#define DEVICE_STATE(x) (((x) >> 9) & 0xf)\r
+typedef enum _EMMC_DEVICE_STATE {\r
+ EMMC_IDLE_STATE = 0,\r
+ EMMC_READY_STATE,\r
+ EMMC_IDENT_STATE,\r
+ EMMC_STBY_STATE,\r
+ EMMC_TRAN_STATE,\r
+ EMMC_DATA_STATE,\r
+ EMMC_RCV_STATE,\r
+ EMMC_PRG_STATE,\r
+ EMMC_DIS_STATE,\r
+ EMMC_BTST_STATE,\r
+ EMMC_SLP_STATE\r
+} EMMC_DEVICE_STATE;\r
+\r
UINT32 mEmmcRcaCount = 0;\r
\r
+STATIC\r
+EFI_STATUS\r
+EFIAPI\r
+EmmcGetDeviceState (\r
+ IN MMC_HOST_INSTANCE *MmcHostInstance,\r
+ OUT EMMC_DEVICE_STATE *State\r
+ )\r
+{\r
+ EFI_MMC_HOST_PROTOCOL *Host;\r
+ EFI_STATUS Status;\r
+ UINT32 Data, RCA;\r
+\r
+ if (State == NULL) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ Host = MmcHostInstance->MmcHost;\r
+ RCA = MmcHostInstance->CardInfo.RCA << RCA_SHIFT_OFFSET;\r
+ Status = Host->SendCommand (Host, MMC_CMD13, RCA);\r
+ if (EFI_ERROR (Status)) {\r
+ DEBUG ((EFI_D_ERROR, "EmmcGetDeviceState(): Failed to get card status, Status=%r.\n", Status));\r
+ return Status;\r
+ }\r
+ Status = Host->ReceiveResponse (Host, MMC_RESPONSE_TYPE_R1, &Data);\r
+ if (EFI_ERROR (Status)) {\r
+ DEBUG ((EFI_D_ERROR, "EmmcGetDeviceState(): Failed to get response of CMD13, Status=%r.\n", Status));\r
+ return Status;\r
+ }\r
+ if (Data & EMMC_SWITCH_ERROR) {\r
+ DEBUG ((EFI_D_ERROR, "EmmcGetDeviceState(): Failed to switch expected mode, Status=%r.\n", Status));\r
+ return EFI_DEVICE_ERROR;\r
+ }\r
+ *State = DEVICE_STATE(Data);\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+STATIC\r
+EFI_STATUS\r
+EFIAPI\r
+EmmcSetEXTCSD (\r
+ IN MMC_HOST_INSTANCE *MmcHostInstance,\r
+ UINT32 ExtCmdIndex,\r
+ UINT32 Value\r
+ )\r
+{\r
+ EFI_MMC_HOST_PROTOCOL *Host;\r
+ EMMC_DEVICE_STATE State;\r
+ EFI_STATUS Status;\r
+ UINT32 Argument;\r
+\r
+ Host = MmcHostInstance->MmcHost;\r
+ Argument = EMMC_CMD6_ARG_ACCESS(3) | EMMC_CMD6_ARG_INDEX(ExtCmdIndex) |\r
+ EMMC_CMD6_ARG_VALUE(Value) | EMMC_CMD6_ARG_CMD_SET(1);\r
+ Status = Host->SendCommand (Host, MMC_CMD6, Argument);\r
+ if (EFI_ERROR (Status)) {\r
+ DEBUG ((EFI_D_ERROR, "EmmcSetEXTCSD(): Failed to send CMD6, Status=%r.\n", Status));\r
+ return Status;\r
+ }\r
+ // Make sure device exiting prog mode\r
+ do {\r
+ Status = EmmcGetDeviceState (MmcHostInstance, &State);\r
+ if (EFI_ERROR (Status)) {\r
+ DEBUG ((EFI_D_ERROR, "EmmcSetEXTCSD(): Failed to get device state, Status=%r.\n", Status));\r
+ return Status;\r
+ }\r
+ } while (State == EMMC_PRG_STATE);\r
+ return EFI_SUCCESS;\r
+}\r
+\r
STATIC\r
EFI_STATUS\r
EFIAPI\r
EFI_MMC_HOST_PROTOCOL *Host;\r
EFI_BLOCK_IO_MEDIA *Media;\r
EFI_STATUS Status;\r
+ EMMC_DEVICE_STATE State;\r
UINT32 RCA;\r
\r
Host = MmcHostInstance->MmcHost;\r
DEBUG ((EFI_D_ERROR, "EmmcIdentificationMode(): Card selection error, Status=%r.\n", Status));\r
}\r
\r
+ if (MMC_HOST_HAS_SETIOS(Host)) {\r
+ // Set 1-bit bus width\r
+ Status = Host->SetIos (Host, 0, 1, EMMCBACKWARD);\r
+ if (EFI_ERROR (Status)) {\r
+ DEBUG ((EFI_D_ERROR, "EmmcIdentificationMode(): Set 1-bit bus width error, Status=%r.\n", Status));\r
+ return Status;\r
+ }\r
+\r
+ // Set 1-bit bus width for EXTCSD\r
+ Status = EmmcSetEXTCSD (MmcHostInstance, EXTCSD_BUS_WIDTH, EMMC_BUS_WIDTH_1BIT);\r
+ if (EFI_ERROR (Status)) {\r
+ DEBUG ((EFI_D_ERROR, "EmmcIdentificationMode(): Set extcsd bus width error, Status=%r.\n", Status));\r
+ return Status;\r
+ }\r
+ }\r
+\r
// Fetch ECSD\r
- Status = Host->SendCommand (Host, MMC_CMD8, RCA);\r
+ Status = Host->SendCommand (Host, MMC_CMD8, 0);\r
if (EFI_ERROR (Status)) {\r
DEBUG ((EFI_D_ERROR, "EmmcIdentificationMode(): ECSD fetch error, Status=%r.\n", Status));\r
}\r
return Status;\r
}\r
\r
+ // Make sure device exiting data mode\r
+ do {\r
+ Status = EmmcGetDeviceState (MmcHostInstance, &State);\r
+ if (EFI_ERROR (Status)) {\r
+ DEBUG ((EFI_D_ERROR, "EmmcIdentificationMode(): Failed to get device state, Status=%r.\n", Status));\r
+ return Status;\r
+ }\r
+ } while (State == EMMC_DATA_STATE);\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
return EFI_SUCCESS;\r
}\r
\r
+STATIC\r
+EFI_STATUS\r
+InitializeEmmcDevice (\r
+ IN MMC_HOST_INSTANCE *MmcHostInstance\r
+ )\r
+{\r
+ EFI_MMC_HOST_PROTOCOL *Host;\r
+ EFI_STATUS Status = EFI_SUCCESS;\r
+ ECSD *ECSDData;\r
+ UINT32 BusClockFreq, Idx, BusMode;\r
+ UINT32 TimingMode[4] = {EMMCHS52DDR1V2, EMMCHS52DDR1V8, EMMCHS52, EMMCHS26};\r
+\r
+ Host = MmcHostInstance->MmcHost;\r
+ ECSDData = &MmcHostInstance->CardInfo.ECSDData;\r
+ if (ECSDData->DEVICE_TYPE == EMMCBACKWARD)\r
+ return EFI_SUCCESS;\r
+\r
+ if (!MMC_HOST_HAS_SETIOS(Host)) {\r
+ return EFI_SUCCESS;\r
+ }\r
+ Status = EmmcSetEXTCSD (MmcHostInstance, EXTCSD_HS_TIMING, EMMC_TIMING_HS);\r
+ if (EFI_ERROR (Status)) {\r
+ DEBUG ((DEBUG_ERROR, "InitializeEmmcDevice(): Failed to switch high speed mode, Status:%r.\n", Status));\r
+ return Status;\r
+ }\r
+\r
+ for (Idx = 0; Idx < 4; Idx++) {\r
+ switch (TimingMode[Idx]) {\r
+ case EMMCHS52DDR1V2:\r
+ case EMMCHS52DDR1V8:\r
+ case EMMCHS52:\r
+ BusClockFreq = 52000000;\r
+ break;\r
+ case EMMCHS26:\r
+ BusClockFreq = 26000000;\r
+ break;\r
+ default:\r
+ return EFI_UNSUPPORTED;\r
+ }\r
+ Status = Host->SetIos (Host, BusClockFreq, 8, TimingMode[Idx]);\r
+ if (!EFI_ERROR (Status)) {\r
+ switch (TimingMode[Idx]) {\r
+ case EMMCHS52DDR1V2:\r
+ case EMMCHS52DDR1V8:\r
+ BusMode = EMMC_BUS_WIDTH_DDR_8BIT;\r
+ break;\r
+ case EMMCHS52:\r
+ case EMMCHS26:\r
+ BusMode = EMMC_BUS_WIDTH_8BIT;\r
+ break;\r
+ default:\r
+ return EFI_UNSUPPORTED;\r
+ }\r
+ Status = EmmcSetEXTCSD (MmcHostInstance, EXTCSD_BUS_WIDTH, BusMode);\r
+ if (EFI_ERROR (Status)) {\r
+ DEBUG ((DEBUG_ERROR, "InitializeEmmcDevice(): Failed to set EXTCSD bus width, Status:%r\n", Status));\r
+ }\r
+ return Status;\r
+ }\r
+ }\r
+ return Status;\r
+}\r
+\r
STATIC\r
EFI_STATUS\r
InitializeSdMmcDevice (\r
{\r
UINT32 CmdArg;\r
UINT32 Response[4];\r
+ UINT32 Buffer[128];\r
UINTN BlockSize;\r
UINTN CardSize;\r
UINTN NumBlocks;\r
+ BOOLEAN CccSwitch;\r
+ SCR Scr;\r
EFI_STATUS Status;\r
EFI_MMC_HOST_PROTOCOL *MmcHost;\r
\r
return Status;\r
}\r
PrintCSD (Response);\r
+ if (MMC_CSD_GET_CCC(Response) & SD_CCC_SWITCH) {\r
+ CccSwitch = TRUE;\r
+ } else {\r
+ CccSwitch = FALSE;\r
+ }\r
\r
if (MmcHostInstance->CardInfo.CardType == SD_CARD_2_HIGH) {\r
CardSize = HC_MMC_CSD_GET_DEVICESIZE (Response);\r
return Status;\r
}\r
\r
+ Status = MmcHost->SendCommand (MmcHost, MMC_CMD55, CmdArg);\r
+ if (EFI_ERROR (Status)) {\r
+ DEBUG ((EFI_D_ERROR, "%a(MMC_CMD55): Error and Status = %r\n", Status));\r
+ return Status;\r
+ }\r
+ Status = MmcHost->ReceiveResponse (MmcHost, MMC_RESPONSE_TYPE_R1, Response);\r
+ if (EFI_ERROR (Status)) {\r
+ DEBUG ((EFI_D_ERROR, "%a(MMC_CMD55): Error and Status = %r\n", Status));\r
+ return Status;\r
+ }\r
+ if ((Response[0] & MMC_STATUS_APP_CMD) == 0) {\r
+ return EFI_SUCCESS;\r
+ }\r
+\r
+ /* SCR */\r
+ Status = MmcHost->SendCommand (MmcHost, MMC_ACMD51, 0);\r
+ if (EFI_ERROR (Status)) {\r
+ DEBUG ((EFI_D_ERROR, "%a(MMC_ACMD51): Error and Status = %r\n", __func__, Status));\r
+ return Status;\r
+ } else {\r
+ Status = MmcHost->ReadBlockData (MmcHost, 0, 8, Buffer);\r
+ if (EFI_ERROR (Status)) {\r
+ DEBUG ((EFI_D_ERROR, "%a(MMC_ACMD51): ReadBlockData Error and Status = %r\n", __func__, Status));\r
+ return Status;\r
+ }\r
+ CopyMem (&Scr, Buffer, 8);\r
+ if (Scr.SD_SPEC == 2) {\r
+ if (Scr.SD_SPEC3 == 1) {\r
+ if (Scr.SD_SPEC4 == 1) {\r
+ DEBUG ((EFI_D_INFO, "Found SD Card for Spec Version 4.xx\n"));\r
+ } else {\r
+ DEBUG ((EFI_D_INFO, "Found SD Card for Spec Version 3.0x\n"));\r
+ }\r
+ } else {\r
+ if (Scr.SD_SPEC4 == 0) {\r
+ DEBUG ((EFI_D_INFO, "Found SD Card for Spec Version 2.0\n"));\r
+ } else {\r
+ DEBUG ((EFI_D_ERROR, "Found invalid SD Card\n"));\r
+ }\r
+ }\r
+ } else {\r
+ if ((Scr.SD_SPEC3 == 0) && (Scr.SD_SPEC4 == 0)) {\r
+ if (Scr.SD_SPEC == 1) {\r
+ DEBUG ((EFI_D_INFO, "Found SD Card for Spec Version 1.10\n"));\r
+ } else {\r
+ DEBUG ((EFI_D_INFO, "Found SD Card for Spec Version 1.0\n"));\r
+ }\r
+ } else {\r
+ DEBUG ((EFI_D_ERROR, "Found invalid SD Card\n"));\r
+ }\r
+ }\r
+ }\r
+ if (CccSwitch) {\r
+ /* SD Switch, Mode:1, Group:0, Value:1 */\r
+ CmdArg = 1 << 31 | 0x00FFFFFF;\r
+ CmdArg &= ~(0xF << (0 * 4));\r
+ CmdArg |= 1 << (0 * 4);\r
+ Status = MmcHost->SendCommand (MmcHost, MMC_CMD6, CmdArg);\r
+ if (EFI_ERROR (Status)) {\r
+ DEBUG ((EFI_D_ERROR, "%a(MMC_CMD6): Error and Status = %r\n", Status));\r
+ return Status;\r
+ } else {\r
+ Status = MmcHost->ReadBlockData (MmcHost, 0, 64, Buffer);\r
+ if (EFI_ERROR (Status)) {\r
+ DEBUG ((EFI_D_ERROR, "%a(MMC_CMD6): ReadBlockData Error and Status = %r\n", Status));\r
+ return Status;\r
+ }\r
+ }\r
+ }\r
+ if (Scr.SD_BUS_WIDTHS & SD_BUS_WIDTH_4BIT) {\r
+ CmdArg = MmcHostInstance->CardInfo.RCA << 16;\r
+ Status = MmcHost->SendCommand (MmcHost, MMC_CMD55, CmdArg);\r
+ if (EFI_ERROR (Status)) {\r
+ DEBUG ((EFI_D_ERROR, "%a(MMC_CMD55): Error and Status = %r\n", Status));\r
+ return Status;\r
+ }\r
+ /* Width: 4 */\r
+ Status = MmcHost->SendCommand (MmcHost, MMC_CMD6, 2);\r
+ if (EFI_ERROR (Status)) {\r
+ DEBUG ((EFI_D_ERROR, "%a(MMC_CMD6): Error and Status = %r\n", Status));\r
+ return Status;\r
+ }\r
+ }\r
+ if (MMC_HOST_HAS_SETIOS(MmcHost)) {\r
+ Status = MmcHost->SetIos (MmcHost, 26 * 1000 * 1000, 4, EMMCBACKWARD);\r
+ if (EFI_ERROR (Status)) {\r
+ DEBUG ((EFI_D_ERROR, "%a(SetIos): Error and Status = %r\n", Status));\r
+ return Status;\r
+ }\r
+ }\r
return EFI_SUCCESS;\r
}\r
\r
\r
if (MmcHostInstance->CardInfo.CardType != EMMC_CARD) {\r
Status = InitializeSdMmcDevice (MmcHostInstance);\r
- if (EFI_ERROR (Status)) {\r
- return Status;\r
- }\r
+ } else {\r
+ Status = InitializeEmmcDevice (MmcHostInstance);\r
+ }\r
+ if (EFI_ERROR (Status)) {\r
+ return Status;\r
}\r
\r
// Set Block Length\r