[PATCH 1/2] mci: add eMMC DDR52 support
Marco Felsch
m.felsch at pengutronix.de
Tue Apr 18 00:27:12 PDT 2023
Hi Ahmad,
On 23-04-17, Ahmad Fatoum wrote:
> The maximum card frequency that can be configured by barebox currently
> is 50MHz for SD and 52MHz for eMMC. Higher speed modes require runtime
> voltage switching or tuning sequences, which are not yet implemented.
>
> Only exception is eMMC's DDR52: This mode was first introduced with
> MMC 4.4 and can be used even at 3.3V.
Nice :)
> This commit adds DDR52 support to the core. This introduces no functional
> change, because host controllers must opt-in by setting the appropriate
> host capabilities.
>
> Signed-off-by: Ahmad Fatoum <a.fatoum at pengutronix.de>
> ---
> drivers/mci/mci-core.c | 54 +++++++++++++++++++++++++++++++++++-------
> include/mci.h | 19 +++++++++++++++
> 2 files changed, 64 insertions(+), 9 deletions(-)
>
> diff --git a/drivers/mci/mci-core.c b/drivers/mci/mci-core.c
> index f647cae8203b..86f468edfea6 100644
> --- a/drivers/mci/mci-core.c
> +++ b/drivers/mci/mci-core.c
> @@ -135,6 +135,9 @@ static int mci_set_blocklen(struct mci *mci, unsigned len)
> {
> struct mci_cmd cmd;
>
> + if (mci->host->timing == MMC_TIMING_MMC_DDR52)
> + return 0;
> +
> mci_setup_cmd(&cmd, MMC_CMD_SET_BLOCKLEN, len, MMC_RSP_R1);
> return mci_send_cmd(mci, &cmd, NULL);
> }
> @@ -649,11 +652,15 @@ static int mmc_change_freq(struct mci *mci)
> return 0;
> }
>
> - /* High Speed is set, there are two types: 52MHz and 26MHz */
> - if (cardtype & EXT_CSD_CARD_TYPE_52)
> - mci->card_caps |= MMC_CAP_MMC_HIGHSPEED_52MHZ | MMC_CAP_MMC_HIGHSPEED;
> - else
> - mci->card_caps |= MMC_CAP_MMC_HIGHSPEED;
> + mci->card_caps |= MMC_CAP_MMC_HIGHSPEED;
> +
> + /* High Speed is set, there are three types: 26MHz, 52MHz, 52MHz DDR */
> + if (cardtype & EXT_CSD_CARD_TYPE_52) {
> + mci->card_caps |= MMC_CAP_MMC_HIGHSPEED_52MHZ;
> +
> + if (cardtype & EXT_CSD_CARD_TYPE_DDR_1_8V)
> + mci->card_caps |= MMC_CAP_MMC_3_3V_DDR | MMC_CAP_MMC_1_8V_DDR;
> + }
>
> if (IS_ENABLED(CONFIG_MCI_MMC_BOOT_PARTITIONS) &&
> mci->ext_csd[EXT_CSD_REV] >= 3 && mci->ext_csd[EXT_CSD_BOOT_SIZE_MULT]) {
> @@ -1170,15 +1177,20 @@ static int mci_startup_sd(struct mci *mci)
> static int mci_startup_mmc(struct mci *mci)
> {
> struct mci_host *host = mci->host;
> + enum mci_timing timing_orig;
> int err;
> int idx = 0;
> static unsigned ext_csd_bits[] = {
> EXT_CSD_BUS_WIDTH_4,
> EXT_CSD_BUS_WIDTH_8,
> + EXT_CSD_DDR_BUS_WIDTH_4,
> + EXT_CSD_DDR_BUS_WIDTH_8,
> };
> static unsigned bus_widths[] = {
> MMC_BUS_WIDTH_4,
> MMC_BUS_WIDTH_8,
> + MMC_BUS_WIDTH_4,
> + MMC_BUS_WIDTH_8,
This is duplicated or should it be MMC_DDR_BUS_WIDTH_4/8?
> };
>
> /* if possible, speed up the transfer */
> @@ -1191,6 +1203,8 @@ static int mci_startup_mmc(struct mci *mci)
> host->timing = MMC_TIMING_MMC_HS;
> }
>
> + timing_orig = host->timing;
> +
> mci_set_clock(mci, mci->tran_speed);
>
> if (!(host->host_caps & (MMC_CAP_4_BIT_DATA | MMC_CAP_8_BIT_DATA)))
> @@ -1205,6 +1219,9 @@ static int mci_startup_mmc(struct mci *mci)
> if (host->host_caps & MMC_CAP_8_BIT_DATA)
> idx = 1;
>
> + if (mci_caps(mci) & MMC_CAP_MMC_1_8V_DDR)
> + idx += 2;
> +
> for (; idx >= 0; idx--) {
>
> /*
> @@ -1221,11 +1238,25 @@ static int mci_startup_mmc(struct mci *mci)
> continue;
> }
>
> + if (ext_csd_bits[idx] & EXT_CSD_DDR_FLAG)
> + host->timing = MMC_TIMING_MMC_DDR52;
> + else
> + host->timing = timing_orig;
> +
> + dev_dbg(&mci->dev, "attempting buswidth %u%s\n", bus_widths[idx],
> + mci_timing_is_ddr(host->timing) ? " (DDR)" : "");
> +
> mci_set_bus_width(mci, bus_widths[idx]);
>
> err = mmc_compare_ext_csds(mci, bus_widths[idx]);
> - if (!err)
> - break;
> + if (!err) {
> + if (host->timing == MMC_TIMING_MMC_DDR52) {
> + mci->read_bl_len = SECTOR_SIZE;
> + mci->write_bl_len = SECTOR_SIZE;
> + }
> +
> + return 0;
> + }
> }
>
> return err;
> @@ -1654,6 +1685,8 @@ static const char *mci_timing_tostr(unsigned timing)
> return "MMC HS";
> case MMC_TIMING_SD_HS:
> return "SD HS";
> + case MMC_TIMING_MMC_DDR52:
> + return "MMC DDR52";
> default:
> return "unknown"; /* shouldn't happen */
> }
> @@ -1661,12 +1694,15 @@ static const char *mci_timing_tostr(unsigned timing)
>
> static void mci_print_caps(unsigned caps)
> {
> - printf(" capabilities: %s%s%s%s%s\n",
> + printf(" capabilities: %s%s%s%s%s%s%s%s\n",
> caps & MMC_CAP_4_BIT_DATA ? "4bit " : "",
> caps & MMC_CAP_8_BIT_DATA ? "8bit " : "",
> caps & MMC_CAP_SD_HIGHSPEED ? "sd-hs " : "",
> caps & MMC_CAP_MMC_HIGHSPEED ? "mmc-hs " : "",
> - caps & MMC_CAP_MMC_HIGHSPEED_52MHZ ? "mmc-52MHz " : "");
> + caps & MMC_CAP_MMC_HIGHSPEED_52MHZ ? "mmc-52MHz " : "",
> + caps & MMC_CAP_MMC_3_3V_DDR ? "ddr-3.3v " : "",
> + caps & MMC_CAP_MMC_1_8V_DDR ? "ddr-1.8v " : "",
> + caps & MMC_CAP_MMC_1_2V_DDR ? "ddr-1.2v " : "");
At the moment we only report what barebox does support, ddr-1.8v and
ddr-1.2v isn't supported. Do we really want to report this?
Regards,
Marco
> }
>
> /**
> diff --git a/include/mci.h b/include/mci.h
> index d356f071f7f2..88712c35492e 100644
> --- a/include/mci.h
> +++ b/include/mci.h
> @@ -51,6 +51,11 @@
> #define MMC_CAP_SD_HIGHSPEED (1 << 3)
> #define MMC_CAP_MMC_HIGHSPEED (1 << 4)
> #define MMC_CAP_MMC_HIGHSPEED_52MHZ (1 << 5)
> +#define MMC_CAP_MMC_3_3V_DDR (1 << 7) /* Host supports eMMC DDR 3.3V */
> +#define MMC_CAP_MMC_1_8V_DDR (1 << 8) /* Host supports eMMC DDR 1.8V */
> +#define MMC_CAP_MMC_1_2V_DDR (1 << 9) /* Host supports eMMC DDR 1.2V */
> +#define MMC_CAP_DDR (MMC_CAP_3_3V_DDR | MMC_CAP_1_8V_DDR | \
> + MMC_CAP_1_2V_DDR)
> /* Mask of all caps for bus width */
> #define MMC_CAP_BIT_DATA_MASK (MMC_CAP_4_BIT_DATA | MMC_CAP_8_BIT_DATA)
>
> @@ -308,6 +313,7 @@
> #define EXT_CSD_BUS_WIDTH_8 2 /* Card is in 8 bit mode */
> #define EXT_CSD_DDR_BUS_WIDTH_4 5 /* Card is in 4 bit DDR mode */
> #define EXT_CSD_DDR_BUS_WIDTH_8 6 /* Card is in 8 bit DDR mode */
> +#define EXT_CSD_DDR_FLAG BIT(2) /* Flag for DDR mode */
>
> #define R1_ILLEGAL_COMMAND (1 << 22)
> #define R1_STATUS(x) (x & 0xFFF9A000)
> @@ -410,6 +416,19 @@ enum mci_timing {
> MMC_TIMING_MMC_HS400 = 8,
> };
>
> +static inline bool mci_timing_is_ddr(enum mci_timing timing)
> +{
> + switch (timing) {
> + case MMC_TIMING_UHS_DDR50:
> + case MMC_TIMING_MMC_HS200:
> + case MMC_TIMING_MMC_DDR52:
> + case MMC_TIMING_MMC_HS400:
> + return true;
> + default:
> + return false;
> + }
> +}
> +
> struct mci_ios {
> unsigned int clock; /* clock rate */
>
> --
> 2.39.2
>
>
>
More information about the barebox
mailing list