On 23 November 2016 at 07:08, Haojian Zhuang <haojian.zhu...@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.zhu...@linaro.org> > Tested-by: Ryan Harkin <ryan.har...@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