public inbox for devel@edk2.groups.io
 help / color / mirror / Atom feed
From: Ard Biesheuvel <ard.biesheuvel@linaro.org>
To: Haojian Zhuang <haojian.zhuang@linaro.org>
Cc: Ryan Harkin <ryan.harkin@linaro.org>,
	edk2-devel-01 <edk2-devel@lists.01.org>,
	 Leif Lindholm <leif.lindholm@linaro.org>
Subject: Re: [PATCH v7 1/4] MmcDxe: add interface to change io width and speed
Date: Wed, 23 Nov 2016 08:56:48 +0000	[thread overview]
Message-ID: <CAKv+Gu__abF41Jm5zoVDsR713F8_kMpAzFhQqn+H8FM1XQLvXw@mail.gmail.com> (raw)
In-Reply-To: <1479884921-25398-2-git-send-email-haojian.zhuang@linaro.org>

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
>


  reply	other threads:[~2016-11-23  8:56 UTC|newest]

Thread overview: 10+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2016-11-23  7:08 [PATCH v7 0/4] enhance MMC Haojian Zhuang
2016-11-23  7:08 ` [PATCH v7 1/4] MmcDxe: add interface to change io width and speed Haojian Zhuang
2016-11-23  8:56   ` Ard Biesheuvel [this message]
2016-11-23  7:08 ` [PATCH v7 2/4] MmcDxe: set iospeed and bus width in SD stack Haojian Zhuang
2016-11-23  8:58   ` Ard Biesheuvel
2016-11-23  7:08 ` [PATCH v7 3/4] PL180: update for indentifying SD Haojian Zhuang
2016-11-23  8:59   ` Ard Biesheuvel
2016-11-23  7:08 ` [PATCH v7 4/4] MmcDxe: expand to support multiple blocks Haojian Zhuang
2016-11-23  9:01   ` Ard Biesheuvel
2016-11-23  8:54 ` [PATCH v7 0/4] enhance MMC Ard Biesheuvel

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-list from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=CAKv+Gu__abF41Jm5zoVDsR713F8_kMpAzFhQqn+H8FM1XQLvXw@mail.gmail.com \
    --to=devel@edk2.groups.io \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox