mirror of https://github.com/acidanthera/audk.git
EmbeddedPkg/MmcDxe: invoke SetIos() protocol method to set speed and width
Add the interface to change the bus width and speed. By default, MMC is initialized with 1-bit mode and less than 400KHz bus clock. It causes MMC working inefficiently. Set I/O 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> Reviewed-by: Ard Biesheuvel <ard.biesheuvel@linaro.org>
This commit is contained in:
parent
1df2fe1433
commit
752ae80514
|
@ -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
|
||||
|
|
|
@ -25,8 +25,108 @@ 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
|
||||
|
@ -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;
|
||||
|
@ -111,6 +237,57 @@ EmmcIdentificationMode (
|
|||
return EFI_SUCCESS;
|
||||
}
|
||||
|
||||
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 (
|
||||
|
@ -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
|
||||
|
|
Loading…
Reference in New Issue