Message ID | 1479884921-25398-2-git-send-email-haojian.zhuang@linaro.org |
---|---|
State | New |
Headers | show |
On 23 November 2016 at 07:08, Haojian Zhuang <haojian.zhuang@linaro.org> wrote: > By default, MMC is initialized with 1-bit mode and less than 400KHz bus > clock. It causes MMC working inefficiently. > > Add the interface to change the bus width and speed. > > Set io bus width on both MMC controller and EXTCSD. Otherwise, it may > cause unmatched failure case. And support more timing mode, high speed, > HS200 & HS400 mode. > > Contributed-under: TianoCore Contribution Agreement 1.0 > Signed-off-by: Haojian Zhuang <haojian.zhuang@linaro.org> > Tested-by: Ryan Harkin <ryan.harkin@linaro.org> > --- > EmbeddedPkg/Include/Protocol/MmcHost.h | 25 ++- > EmbeddedPkg/Universal/MmcDxe/Mmc.h | 5 + > EmbeddedPkg/Universal/MmcDxe/MmcIdentification.c | 185 ++++++++++++++++++++++- > 3 files changed, 211 insertions(+), 4 deletions(-) > > diff --git a/EmbeddedPkg/Include/Protocol/MmcHost.h b/EmbeddedPkg/Include/Protocol/MmcHost.h > index 89f2e80..9d7a604 100644 > --- a/EmbeddedPkg/Include/Protocol/MmcHost.h > +++ b/EmbeddedPkg/Include/Protocol/MmcHost.h > @@ -49,6 +49,7 @@ typedef UINT32 MMC_CMD; > #define MMC_CMD2 (MMC_INDX(2) | MMC_CMD_WAIT_RESPONSE | MMC_CMD_LONG_RESPONSE) > #define MMC_CMD3 (MMC_INDX(3) | MMC_CMD_WAIT_RESPONSE) > #define MMC_CMD5 (MMC_INDX(5) | MMC_CMD_WAIT_RESPONSE | MMC_CMD_NO_CRC_RESPONSE) > +#define MMC_CMD6 (MMC_INDX(6) | MMC_CMD_WAIT_RESPONSE) > #define MMC_CMD7 (MMC_INDX(7) | MMC_CMD_WAIT_RESPONSE) > #define MMC_CMD8 (MMC_INDX(8) | MMC_CMD_WAIT_RESPONSE) > #define MMC_CMD9 (MMC_INDX(9) | MMC_CMD_WAIT_RESPONSE | MMC_CMD_LONG_RESPONSE) > @@ -82,6 +83,16 @@ typedef enum _MMC_STATE { > MmcDisconnectState, > } MMC_STATE; > > +#define EMMCBACKWARD (0) > +#define EMMCHS26 (1 << 0) // High-Speed @26MHz at rated device voltages > +#define EMMCHS52 (1 << 1) // High-Speed @52MHz at rated device voltages > +#define EMMCHS52DDR1V8 (1 << 2) // High-Speed Dual Data Rate @52MHz 1.8V or 3V I/O > +#define EMMCHS52DDR1V2 (1 << 3) // High-Speed Dual Data Rate @52MHz 1.2V I/O > +#define EMMCHS200SDR1V8 (1 << 4) // HS200 Single Data Rate @200MHz 1.8V I/O > +#define EMMCHS200SDR1V2 (1 << 5) // HS200 Single Data Rate @200MHz 1.2V I/O > +#define EMMCHS400DDR1V8 (1 << 6) // HS400 Dual Data Rate @400MHz 1.8V I/O > +#define EMMCHS400DDR1V2 (1 << 7) // HS400 Dual Data Rate @400MHz 1.2V I/O > + > /// > /// Forward declaration for EFI_MMC_HOST_PROTOCOL > /// > @@ -131,6 +142,13 @@ typedef EFI_STATUS (EFIAPI *MMC_WRITEBLOCKDATA) ( > IN UINT32 *Buffer > ); > > +typedef EFI_STATUS (EFIAPI *MMC_SETIOS) ( > + IN EFI_MMC_HOST_PROTOCOL *This, > + IN UINT32 BusClockFreq, > + IN UINT32 BusWidth, > + IN UINT32 TimingMode > + ); > + > > struct _EFI_MMC_HOST_PROTOCOL { > > @@ -147,9 +165,14 @@ struct _EFI_MMC_HOST_PROTOCOL { > MMC_READBLOCKDATA ReadBlockData; > MMC_WRITEBLOCKDATA WriteBlockData; > > + MMC_SETIOS SetIos; > + > }; > > -#define MMC_HOST_PROTOCOL_REVISION 0x00010001 // 1.1 > +#define MMC_HOST_PROTOCOL_REVISION 0x00010002 // 1.2 > + > +#define MMC_HOST_HAS_SETIOS(Host) (Host->Revision >= MMC_HOST_PROTOCOL_REVISION && \ > + Host->SetIos != NULL) > This looks fine now. But in patch 4/4 you increase the revision again, which does not make a lot of sense. I think the best solution is to split off the changes to the protocol header, and add both new protocol methods in a single patch. > extern EFI_GUID gEfiMmcHostProtocolGuid; > > diff --git a/EmbeddedPkg/Universal/MmcDxe/Mmc.h b/EmbeddedPkg/Universal/MmcDxe/Mmc.h > index 112bc47..fb3f6c9 100644 > --- a/EmbeddedPkg/Universal/MmcDxe/Mmc.h > +++ b/EmbeddedPkg/Universal/MmcDxe/Mmc.h > @@ -55,6 +55,11 @@ > #define MMC_R0_STATE_TRAN 4 > #define MMC_R0_STATE_DATA 5 > > +#define EMMC_CMD6_ARG_ACCESS(x) (((x) & 0x3) << 24) > +#define EMMC_CMD6_ARG_INDEX(x) (((x) & 0xFF) << 16) > +#define EMMC_CMD6_ARG_VALUE(x) (((x) & 0xFF) << 8) > +#define EMMC_CMD6_ARG_CMD_SET(x) (((x) & 0x7) << 0) > + > typedef enum { > UNKNOWN_CARD, > MMC_CARD, //MMC card > diff --git a/EmbeddedPkg/Universal/MmcDxe/MmcIdentification.c b/EmbeddedPkg/Universal/MmcDxe/MmcIdentification.c > index 9aefb26..7441459 100644 > --- a/EmbeddedPkg/Universal/MmcDxe/MmcIdentification.c > +++ b/EmbeddedPkg/Universal/MmcDxe/MmcIdentification.c > @@ -25,11 +25,111 @@ typedef union { > #define EMMC_CARD_SIZE 512 > #define EMMC_ECSD_SIZE_OFFSET 53 > > +#define EXTCSD_BUS_WIDTH 183 > +#define EXTCSD_HS_TIMING 185 > + > +#define EMMC_TIMING_BACKWARD 0 > +#define EMMC_TIMING_HS 1 > +#define EMMC_TIMING_HS200 2 > +#define EMMC_TIMING_HS400 3 > + > +#define EMMC_BUS_WIDTH_1BIT 0 > +#define EMMC_BUS_WIDTH_4BIT 1 > +#define EMMC_BUS_WIDTH_8BIT 2 > +#define EMMC_BUS_WIDTH_DDR_4BIT 5 > +#define EMMC_BUS_WIDTH_DDR_8BIT 6 > + > +#define EMMC_SWITCH_ERROR (1 << 7) > + > +#define DEVICE_STATE(x) (((x) >> 9) & 0xf) > +typedef enum _EMMC_DEVICE_STATE { > + EMMC_IDLE_STATE = 0, > + EMMC_READY_STATE, > + EMMC_IDENT_STATE, > + EMMC_STBY_STATE, > + EMMC_TRAN_STATE, > + EMMC_DATA_STATE, > + EMMC_RCV_STATE, > + EMMC_PRG_STATE, > + EMMC_DIS_STATE, > + EMMC_BTST_STATE, > + EMMC_SLP_STATE > +} EMMC_DEVICE_STATE; > + > UINT32 mEmmcRcaCount = 0; > > STATIC > EFI_STATUS > EFIAPI > +EmmcGetDeviceState ( > + IN MMC_HOST_INSTANCE *MmcHostInstance, > + OUT EMMC_DEVICE_STATE *State > + ) > +{ > + EFI_MMC_HOST_PROTOCOL *Host; > + EFI_STATUS Status; > + UINT32 Data, RCA; > + > + if (State == NULL) { > + return EFI_INVALID_PARAMETER; > + } > + > + Host = MmcHostInstance->MmcHost; > + RCA = MmcHostInstance->CardInfo.RCA << RCA_SHIFT_OFFSET; > + Status = Host->SendCommand (Host, MMC_CMD13, RCA); > + if (EFI_ERROR (Status)) { > + DEBUG ((EFI_D_ERROR, "EmmcGetDeviceState(): Failed to get card status, Status=%r.\n", Status)); > + return Status; > + } > + Status = Host->ReceiveResponse (Host, MMC_RESPONSE_TYPE_R1, &Data); > + if (EFI_ERROR (Status)) { > + DEBUG ((EFI_D_ERROR, "EmmcGetDeviceState(): Failed to get response of CMD13, Status=%r.\n", Status)); > + return Status; > + } > + if (Data & EMMC_SWITCH_ERROR) { > + DEBUG ((EFI_D_ERROR, "EmmcGetDeviceState(): Failed to switch expected mode, Status=%r.\n", Status)); > + return EFI_DEVICE_ERROR; > + } > + *State = DEVICE_STATE(Data); > + return EFI_SUCCESS; > +} > + > +STATIC > +EFI_STATUS > +EFIAPI > +EmmcSetEXTCSD ( > + IN MMC_HOST_INSTANCE *MmcHostInstance, > + UINT32 ExtCmdIndex, > + UINT32 Value > + ) > +{ > + EFI_MMC_HOST_PROTOCOL *Host; > + EMMC_DEVICE_STATE State; > + EFI_STATUS Status; > + UINT32 Argument; > + > + Host = MmcHostInstance->MmcHost; > + Argument = EMMC_CMD6_ARG_ACCESS(3) | EMMC_CMD6_ARG_INDEX(ExtCmdIndex) | > + EMMC_CMD6_ARG_VALUE(Value) | EMMC_CMD6_ARG_CMD_SET(1); > + Status = Host->SendCommand (Host, MMC_CMD6, Argument); > + if (EFI_ERROR (Status)) { > + DEBUG ((EFI_D_ERROR, "EmmcSetEXTCSD(): Failed to send CMD6, Status=%r.\n", Status)); > + return Status; > + } > + // Make sure device exiting prog mode > + do { > + Status = EmmcGetDeviceState (MmcHostInstance, &State); > + if (EFI_ERROR (Status)) { > + DEBUG ((EFI_D_ERROR, "EmmcSetEXTCSD(): Failed to get device state, Status=%r.\n", Status)); > + return Status; > + } > + } while (State == EMMC_PRG_STATE); > + return EFI_SUCCESS; > +} > + > +STATIC > +EFI_STATUS > +EFIAPI > EmmcIdentificationMode ( > IN MMC_HOST_INSTANCE *MmcHostInstance, > IN OCR_RESPONSE Response > @@ -38,6 +138,7 @@ EmmcIdentificationMode ( > EFI_MMC_HOST_PROTOCOL *Host; > EFI_BLOCK_IO_MEDIA *Media; > EFI_STATUS Status; > + EMMC_DEVICE_STATE State; > UINT32 RCA; > > Host = MmcHostInstance->MmcHost; > @@ -84,6 +185,22 @@ EmmcIdentificationMode ( > DEBUG ((EFI_D_ERROR, "EmmcIdentificationMode(): Card selection error, Status=%r.\n", Status)); > } > > + if (MMC_HOST_HAS_SETIOS(Host)) { > + // Set 1-bit bus width > + Status = Host->SetIos (Host, 0, 1, EMMCBACKWARD); > + if (EFI_ERROR (Status)) { > + DEBUG ((EFI_D_ERROR, "EmmcIdentificationMode(): Set 1-bit bus width error, Status=%r.\n", Status)); > + return Status; > + } > + > + // Set 1-bit bus width for EXTCSD > + Status = EmmcSetEXTCSD (MmcHostInstance, EXTCSD_BUS_WIDTH, EMMC_BUS_WIDTH_1BIT); > + if (EFI_ERROR (Status)) { > + DEBUG ((EFI_D_ERROR, "EmmcIdentificationMode(): Set extcsd bus width error, Status=%r.\n", Status)); > + return Status; > + } > + } > + > // Fetch ECSD > Status = Host->SendCommand (Host, MMC_CMD8, RCA); > if (EFI_ERROR (Status)) { > @@ -96,6 +213,15 @@ EmmcIdentificationMode ( > return Status; > } > > + // Make sure device exiting data mode > + do { > + Status = EmmcGetDeviceState (MmcHostInstance, &State); > + if (EFI_ERROR (Status)) { > + DEBUG ((EFI_D_ERROR, "EmmcIdentificationMode(): Failed to get device state, Status=%r.\n", Status)); > + return Status; > + } > + } while (State == EMMC_DATA_STATE); > + > // Set up media > Media->BlockSize = EMMC_CARD_SIZE; // 512-byte support is mandatory for eMMC cards > Media->MediaId = MmcHostInstance->CardInfo.CIDData.PSN; > @@ -113,6 +239,57 @@ EmmcIdentificationMode ( > > STATIC > EFI_STATUS > +InitializeEmmcDevice ( > + IN MMC_HOST_INSTANCE *MmcHostInstance > + ) > +{ > + EFI_MMC_HOST_PROTOCOL *Host; > + EFI_STATUS Status = EFI_SUCCESS; > + ECSD *ECSDData; > + UINT32 BusClockFreq, Idx; > + UINT32 TimingMode[4] = {EMMCHS52DDR1V2, EMMCHS52DDR1V8, EMMCHS52, EMMCHS26}; > + > + Host = MmcHostInstance->MmcHost; > + ECSDData = &MmcHostInstance->CardInfo.ECSDData; > + if (ECSDData->DEVICE_TYPE == EMMCBACKWARD) > + return EFI_SUCCESS; > + > + if (!MMC_HOST_HAS_SETIOS(Host)) { > + return EFI_SUCCESS; > + } > + Status = EmmcSetEXTCSD (MmcHostInstance, EXTCSD_HS_TIMING, EMMC_TIMING_HS); > + if (EFI_ERROR (Status)) { > + DEBUG ((DEBUG_ERROR, "InitializeEmmcDevice(): Failed to switch high speed mode, Status:%r.\n", Status)); > + return Status; > + } > + > + for (Idx = 0; Idx < 4; Idx++) { > + switch (TimingMode[Idx]) { > + case EMMCHS52DDR1V2: > + case EMMCHS52DDR1V8: > + case EMMCHS52: > + BusClockFreq = 52000000; > + break; > + case EMMCHS26: > + BusClockFreq = 26000000; > + break; > + default: > + return EFI_UNSUPPORTED; > + } > + Status = Host->SetIos (Host, BusClockFreq, 8, TimingMode[Idx]); > + if (!EFI_ERROR (Status)) { > + Status = EmmcSetEXTCSD (MmcHostInstance, EXTCSD_BUS_WIDTH, EMMC_BUS_WIDTH_DDR_8BIT); > + if (EFI_ERROR (Status)) { > + DEBUG ((DEBUG_ERROR, "InitializeEmmcDevice(): Failed to set EXTCSD bus width, Status:%r\n", Status)); > + } > + return Status; > + } > + } > + return Status; > +} > + > +STATIC > +EFI_STATUS > InitializeSdMmcDevice ( > IN MMC_HOST_INSTANCE *MmcHostInstance > ) > @@ -431,9 +608,11 @@ InitializeMmcDevice ( > > if (MmcHostInstance->CardInfo.CardType != EMMC_CARD) { > Status = InitializeSdMmcDevice (MmcHostInstance); > - if (EFI_ERROR (Status)) { > - return Status; > - } > + } else { > + Status = InitializeEmmcDevice (MmcHostInstance); > + } > + if (EFI_ERROR (Status)) { > + return Status; > } > > // Set Block Length > -- > 2.7.4 > _______________________________________________ edk2-devel mailing list edk2-devel@lists.01.org https://lists.01.org/mailman/listinfo/edk2-devel
diff --git a/EmbeddedPkg/Include/Protocol/MmcHost.h b/EmbeddedPkg/Include/Protocol/MmcHost.h index 89f2e80..9d7a604 100644 --- a/EmbeddedPkg/Include/Protocol/MmcHost.h +++ b/EmbeddedPkg/Include/Protocol/MmcHost.h @@ -49,6 +49,7 @@ typedef UINT32 MMC_CMD; #define MMC_CMD2 (MMC_INDX(2) | MMC_CMD_WAIT_RESPONSE | MMC_CMD_LONG_RESPONSE) #define MMC_CMD3 (MMC_INDX(3) | MMC_CMD_WAIT_RESPONSE) #define MMC_CMD5 (MMC_INDX(5) | MMC_CMD_WAIT_RESPONSE | MMC_CMD_NO_CRC_RESPONSE) +#define MMC_CMD6 (MMC_INDX(6) | MMC_CMD_WAIT_RESPONSE) #define MMC_CMD7 (MMC_INDX(7) | MMC_CMD_WAIT_RESPONSE) #define MMC_CMD8 (MMC_INDX(8) | MMC_CMD_WAIT_RESPONSE) #define MMC_CMD9 (MMC_INDX(9) | MMC_CMD_WAIT_RESPONSE | MMC_CMD_LONG_RESPONSE) @@ -82,6 +83,16 @@ typedef enum _MMC_STATE { MmcDisconnectState, } MMC_STATE; +#define EMMCBACKWARD (0) +#define EMMCHS26 (1 << 0) // High-Speed @26MHz at rated device voltages +#define EMMCHS52 (1 << 1) // High-Speed @52MHz at rated device voltages +#define EMMCHS52DDR1V8 (1 << 2) // High-Speed Dual Data Rate @52MHz 1.8V or 3V I/O +#define EMMCHS52DDR1V2 (1 << 3) // High-Speed Dual Data Rate @52MHz 1.2V I/O +#define EMMCHS200SDR1V8 (1 << 4) // HS200 Single Data Rate @200MHz 1.8V I/O +#define EMMCHS200SDR1V2 (1 << 5) // HS200 Single Data Rate @200MHz 1.2V I/O +#define EMMCHS400DDR1V8 (1 << 6) // HS400 Dual Data Rate @400MHz 1.8V I/O +#define EMMCHS400DDR1V2 (1 << 7) // HS400 Dual Data Rate @400MHz 1.2V I/O + /// /// Forward declaration for EFI_MMC_HOST_PROTOCOL /// @@ -131,6 +142,13 @@ typedef EFI_STATUS (EFIAPI *MMC_WRITEBLOCKDATA) ( IN UINT32 *Buffer ); +typedef EFI_STATUS (EFIAPI *MMC_SETIOS) ( + IN EFI_MMC_HOST_PROTOCOL *This, + IN UINT32 BusClockFreq, + IN UINT32 BusWidth, + IN UINT32 TimingMode + ); + struct _EFI_MMC_HOST_PROTOCOL { @@ -147,9 +165,14 @@ struct _EFI_MMC_HOST_PROTOCOL { MMC_READBLOCKDATA ReadBlockData; MMC_WRITEBLOCKDATA WriteBlockData; + MMC_SETIOS SetIos; + }; -#define MMC_HOST_PROTOCOL_REVISION 0x00010001 // 1.1 +#define MMC_HOST_PROTOCOL_REVISION 0x00010002 // 1.2 + +#define MMC_HOST_HAS_SETIOS(Host) (Host->Revision >= MMC_HOST_PROTOCOL_REVISION && \ + Host->SetIos != NULL) extern EFI_GUID gEfiMmcHostProtocolGuid; diff --git a/EmbeddedPkg/Universal/MmcDxe/Mmc.h b/EmbeddedPkg/Universal/MmcDxe/Mmc.h index 112bc47..fb3f6c9 100644 --- a/EmbeddedPkg/Universal/MmcDxe/Mmc.h +++ b/EmbeddedPkg/Universal/MmcDxe/Mmc.h @@ -55,6 +55,11 @@ #define MMC_R0_STATE_TRAN 4 #define MMC_R0_STATE_DATA 5 +#define EMMC_CMD6_ARG_ACCESS(x) (((x) & 0x3) << 24) +#define EMMC_CMD6_ARG_INDEX(x) (((x) & 0xFF) << 16) +#define EMMC_CMD6_ARG_VALUE(x) (((x) & 0xFF) << 8) +#define EMMC_CMD6_ARG_CMD_SET(x) (((x) & 0x7) << 0) + typedef enum { UNKNOWN_CARD, MMC_CARD, //MMC card diff --git a/EmbeddedPkg/Universal/MmcDxe/MmcIdentification.c b/EmbeddedPkg/Universal/MmcDxe/MmcIdentification.c index 9aefb26..7441459 100644 --- a/EmbeddedPkg/Universal/MmcDxe/MmcIdentification.c +++ b/EmbeddedPkg/Universal/MmcDxe/MmcIdentification.c @@ -25,11 +25,111 @@ typedef union { #define EMMC_CARD_SIZE 512 #define EMMC_ECSD_SIZE_OFFSET 53 +#define EXTCSD_BUS_WIDTH 183 +#define EXTCSD_HS_TIMING 185 + +#define EMMC_TIMING_BACKWARD 0 +#define EMMC_TIMING_HS 1 +#define EMMC_TIMING_HS200 2 +#define EMMC_TIMING_HS400 3 + +#define EMMC_BUS_WIDTH_1BIT 0 +#define EMMC_BUS_WIDTH_4BIT 1 +#define EMMC_BUS_WIDTH_8BIT 2 +#define EMMC_BUS_WIDTH_DDR_4BIT 5 +#define EMMC_BUS_WIDTH_DDR_8BIT 6 + +#define EMMC_SWITCH_ERROR (1 << 7) + +#define DEVICE_STATE(x) (((x) >> 9) & 0xf) +typedef enum _EMMC_DEVICE_STATE { + EMMC_IDLE_STATE = 0, + EMMC_READY_STATE, + EMMC_IDENT_STATE, + EMMC_STBY_STATE, + EMMC_TRAN_STATE, + EMMC_DATA_STATE, + EMMC_RCV_STATE, + EMMC_PRG_STATE, + EMMC_DIS_STATE, + EMMC_BTST_STATE, + EMMC_SLP_STATE +} EMMC_DEVICE_STATE; + UINT32 mEmmcRcaCount = 0; STATIC EFI_STATUS EFIAPI +EmmcGetDeviceState ( + IN MMC_HOST_INSTANCE *MmcHostInstance, + OUT EMMC_DEVICE_STATE *State + ) +{ + EFI_MMC_HOST_PROTOCOL *Host; + EFI_STATUS Status; + UINT32 Data, RCA; + + if (State == NULL) { + return EFI_INVALID_PARAMETER; + } + + Host = MmcHostInstance->MmcHost; + RCA = MmcHostInstance->CardInfo.RCA << RCA_SHIFT_OFFSET; + Status = Host->SendCommand (Host, MMC_CMD13, RCA); + if (EFI_ERROR (Status)) { + DEBUG ((EFI_D_ERROR, "EmmcGetDeviceState(): Failed to get card status, Status=%r.\n", Status)); + return Status; + } + Status = Host->ReceiveResponse (Host, MMC_RESPONSE_TYPE_R1, &Data); + if (EFI_ERROR (Status)) { + DEBUG ((EFI_D_ERROR, "EmmcGetDeviceState(): Failed to get response of CMD13, Status=%r.\n", Status)); + return Status; + } + if (Data & EMMC_SWITCH_ERROR) { + DEBUG ((EFI_D_ERROR, "EmmcGetDeviceState(): Failed to switch expected mode, Status=%r.\n", Status)); + return EFI_DEVICE_ERROR; + } + *State = DEVICE_STATE(Data); + return EFI_SUCCESS; +} + +STATIC +EFI_STATUS +EFIAPI +EmmcSetEXTCSD ( + IN MMC_HOST_INSTANCE *MmcHostInstance, + UINT32 ExtCmdIndex, + UINT32 Value + ) +{ + EFI_MMC_HOST_PROTOCOL *Host; + EMMC_DEVICE_STATE State; + EFI_STATUS Status; + UINT32 Argument; + + Host = MmcHostInstance->MmcHost; + Argument = EMMC_CMD6_ARG_ACCESS(3) | EMMC_CMD6_ARG_INDEX(ExtCmdIndex) | + EMMC_CMD6_ARG_VALUE(Value) | EMMC_CMD6_ARG_CMD_SET(1); + Status = Host->SendCommand (Host, MMC_CMD6, Argument); + if (EFI_ERROR (Status)) { + DEBUG ((EFI_D_ERROR, "EmmcSetEXTCSD(): Failed to send CMD6, Status=%r.\n", Status)); + return Status; + } + // Make sure device exiting prog mode + do { + Status = EmmcGetDeviceState (MmcHostInstance, &State); + if (EFI_ERROR (Status)) { + DEBUG ((EFI_D_ERROR, "EmmcSetEXTCSD(): Failed to get device state, Status=%r.\n", Status)); + return Status; + } + } while (State == EMMC_PRG_STATE); + return EFI_SUCCESS; +} + +STATIC +EFI_STATUS +EFIAPI EmmcIdentificationMode ( IN MMC_HOST_INSTANCE *MmcHostInstance, IN OCR_RESPONSE Response @@ -38,6 +138,7 @@ EmmcIdentificationMode ( EFI_MMC_HOST_PROTOCOL *Host; EFI_BLOCK_IO_MEDIA *Media; EFI_STATUS Status; + EMMC_DEVICE_STATE State; UINT32 RCA; Host = MmcHostInstance->MmcHost; @@ -84,6 +185,22 @@ EmmcIdentificationMode ( DEBUG ((EFI_D_ERROR, "EmmcIdentificationMode(): Card selection error, Status=%r.\n", Status)); } + if (MMC_HOST_HAS_SETIOS(Host)) { + // Set 1-bit bus width + Status = Host->SetIos (Host, 0, 1, EMMCBACKWARD); + if (EFI_ERROR (Status)) { + DEBUG ((EFI_D_ERROR, "EmmcIdentificationMode(): Set 1-bit bus width error, Status=%r.\n", Status)); + return Status; + } + + // Set 1-bit bus width for EXTCSD + Status = EmmcSetEXTCSD (MmcHostInstance, EXTCSD_BUS_WIDTH, EMMC_BUS_WIDTH_1BIT); + if (EFI_ERROR (Status)) { + DEBUG ((EFI_D_ERROR, "EmmcIdentificationMode(): Set extcsd bus width error, Status=%r.\n", Status)); + return Status; + } + } + // Fetch ECSD Status = Host->SendCommand (Host, MMC_CMD8, RCA); if (EFI_ERROR (Status)) { @@ -96,6 +213,15 @@ EmmcIdentificationMode ( return Status; } + // Make sure device exiting data mode + do { + Status = EmmcGetDeviceState (MmcHostInstance, &State); + if (EFI_ERROR (Status)) { + DEBUG ((EFI_D_ERROR, "EmmcIdentificationMode(): Failed to get device state, Status=%r.\n", Status)); + return Status; + } + } while (State == EMMC_DATA_STATE); + // Set up media Media->BlockSize = EMMC_CARD_SIZE; // 512-byte support is mandatory for eMMC cards Media->MediaId = MmcHostInstance->CardInfo.CIDData.PSN; @@ -113,6 +239,57 @@ EmmcIdentificationMode ( STATIC EFI_STATUS +InitializeEmmcDevice ( + IN MMC_HOST_INSTANCE *MmcHostInstance + ) +{ + EFI_MMC_HOST_PROTOCOL *Host; + EFI_STATUS Status = EFI_SUCCESS; + ECSD *ECSDData; + UINT32 BusClockFreq, Idx; + UINT32 TimingMode[4] = {EMMCHS52DDR1V2, EMMCHS52DDR1V8, EMMCHS52, EMMCHS26}; + + Host = MmcHostInstance->MmcHost; + ECSDData = &MmcHostInstance->CardInfo.ECSDData; + if (ECSDData->DEVICE_TYPE == EMMCBACKWARD) + return EFI_SUCCESS; + + if (!MMC_HOST_HAS_SETIOS(Host)) { + return EFI_SUCCESS; + } + Status = EmmcSetEXTCSD (MmcHostInstance, EXTCSD_HS_TIMING, EMMC_TIMING_HS); + if (EFI_ERROR (Status)) { + DEBUG ((DEBUG_ERROR, "InitializeEmmcDevice(): Failed to switch high speed mode, Status:%r.\n", Status)); + return Status; + } + + for (Idx = 0; Idx < 4; Idx++) { + switch (TimingMode[Idx]) { + case EMMCHS52DDR1V2: + case EMMCHS52DDR1V8: + case EMMCHS52: + BusClockFreq = 52000000; + break; + case EMMCHS26: + BusClockFreq = 26000000; + break; + default: + return EFI_UNSUPPORTED; + } + Status = Host->SetIos (Host, BusClockFreq, 8, TimingMode[Idx]); + if (!EFI_ERROR (Status)) { + Status = EmmcSetEXTCSD (MmcHostInstance, EXTCSD_BUS_WIDTH, EMMC_BUS_WIDTH_DDR_8BIT); + if (EFI_ERROR (Status)) { + DEBUG ((DEBUG_ERROR, "InitializeEmmcDevice(): Failed to set EXTCSD bus width, Status:%r\n", Status)); + } + return Status; + } + } + return Status; +} + +STATIC +EFI_STATUS InitializeSdMmcDevice ( IN MMC_HOST_INSTANCE *MmcHostInstance ) @@ -431,9 +608,11 @@ InitializeMmcDevice ( if (MmcHostInstance->CardInfo.CardType != EMMC_CARD) { Status = InitializeSdMmcDevice (MmcHostInstance); - if (EFI_ERROR (Status)) { - return Status; - } + } else { + Status = InitializeEmmcDevice (MmcHostInstance); + } + if (EFI_ERROR (Status)) { + return Status; } // Set Block Length