From e3a14b6684bc591d0648e2bb8de383074ee81f43 Mon Sep 17 00:00:00 2001 From: T Karthik Reddy Date: Tue, 25 Jun 2019 13:39:01 +0200 Subject: [PATCH 01/27] mmc: mvebu: Remove unused MMC_CAP.. macros Removed MMC_CAP_NONREMOVABLE, MMC_CAP_NEEDS_POLL macros from mvebu_mmc.h to avoid redefining of these macros when compiled with mvebu based configs. Signed-off-by: T Karthik Reddy Signed-off-by: Michal Simek --- include/mvebu_mmc.h | 4 ---- 1 file changed, 4 deletions(-) diff --git a/include/mvebu_mmc.h b/include/mvebu_mmc.h index d51b1fe4670..7397165f67f 100644 --- a/include/mvebu_mmc.h +++ b/include/mvebu_mmc.h @@ -222,13 +222,9 @@ #define MMC_CAP_SDIO_IRQ (1 << 3) /* Talks only SPI protocols */ #define MMC_CAP_SPI (1 << 4) -/* Needs polling for card-detection */ -#define MMC_CAP_NEEDS_POLL (1 << 5) /* Can the host do 8 bit transfers */ #define MMC_CAP_8_BIT_DATA (1 << 6) -/* Nonremovable e.g. eMMC */ -#define MMC_CAP_NONREMOVABLE (1 << 8) /* Waits while card is busy */ #define MMC_CAP_WAIT_WHILE_BUSY (1 << 9) /* Allow erase/trim commands */ From 86a94e7b2b8cdf37138e2c5cef10193f6093a9bd Mon Sep 17 00:00:00 2001 From: T Karthik Reddy Date: Tue, 25 Jun 2019 13:39:02 +0200 Subject: [PATCH 02/27] mmc: Read sd card detect properties from DT This patch reads card detect properties from device tree & added mmc capability macros in mmc.h. Signed-off-by: T Karthik Reddy Signed-off-by: Michal Simek --- drivers/mmc/mmc-uclass.c | 9 +++++++++ include/mmc.h | 4 ++++ 2 files changed, 13 insertions(+) diff --git a/drivers/mmc/mmc-uclass.c b/drivers/mmc/mmc-uclass.c index a9c8f335c14..fa4d1af55d6 100644 --- a/drivers/mmc/mmc-uclass.c +++ b/drivers/mmc/mmc-uclass.c @@ -171,6 +171,15 @@ int mmc_of_parse(struct udevice *dev, struct mmc_config *cfg) if (dev_read_bool(dev, "mmc-hs400-1_2v")) cfg->host_caps |= MMC_CAP(MMC_HS_400); + if (dev_read_bool(dev, "non-removable")) { + cfg->host_caps |= MMC_CAP_NONREMOVABLE; + } else { + if (dev_read_bool(dev, "cd-inverted")) + cfg->host_caps |= MMC_CAP_CD_ACTIVE_HIGH; + if (dev_read_bool(dev, "broken-cd")) + cfg->host_caps |= MMC_CAP_NEEDS_POLL; + } + return 0; } diff --git a/include/mmc.h b/include/mmc.h index 1f30f71d25f..2be3e91fcb5 100644 --- a/include/mmc.h +++ b/include/mmc.h @@ -66,6 +66,10 @@ #define MMC_MODE_HS200 MMC_CAP(MMC_HS_200) #define MMC_MODE_HS400 MMC_CAP(MMC_HS_400) +#define MMC_CAP_NONREMOVABLE BIT(14) +#define MMC_CAP_NEEDS_POLL BIT(15) +#define MMC_CAP_CD_ACTIVE_HIGH BIT(16) + #define MMC_MODE_8BIT BIT(30) #define MMC_MODE_4BIT BIT(29) #define MMC_MODE_1BIT BIT(28) From 451931ea7002c74aafeafde8893d6eb6d7b460f0 Mon Sep 17 00:00:00 2001 From: T Karthik Reddy Date: Tue, 25 Jun 2019 13:39:03 +0200 Subject: [PATCH 03/27] mmc: sdhci: Read cd-gpio from devicetree This patch reads cd-gpio property from devicetree Signed-off-by: T Karthik Reddy Signed-off-by: Michal Simek Reviewed-by: Peng Fan --- drivers/mmc/sdhci.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/drivers/mmc/sdhci.c b/drivers/mmc/sdhci.c index e2bb90abbdf..4ffe74e35e0 100644 --- a/drivers/mmc/sdhci.c +++ b/drivers/mmc/sdhci.c @@ -590,6 +590,12 @@ static int sdhci_set_ios(struct mmc *mmc) static int sdhci_init(struct mmc *mmc) { struct sdhci_host *host = mmc->priv; +#if CONFIG_IS_ENABLED(DM_MMC) && CONFIG_IS_ENABLED(DM_GPIO) + struct udevice *dev = mmc->dev; + + gpio_request_by_name(dev, "cd-gpio", 0, + &host->cd_gpio, GPIOD_IS_IN); +#endif sdhci_reset(host, SDHCI_RESET_ALL); From da18c62b6e6a46e7c9cc932e26b192d10ab1d26d Mon Sep 17 00:00:00 2001 From: T Karthik Reddy Date: Tue, 25 Jun 2019 13:39:04 +0200 Subject: [PATCH 04/27] mmc: sdhci: Implement SDHCI card detect Card detect function implemented for SDHCI framework. Signed-off-by: T Karthik Reddy Signed-off-by: Michal Simek --- drivers/mmc/sdhci.c | 32 ++++++++++++++++++++++++++++++++ 1 file changed, 32 insertions(+) diff --git a/drivers/mmc/sdhci.c b/drivers/mmc/sdhci.c index 4ffe74e35e0..c4e88790bc6 100644 --- a/drivers/mmc/sdhci.c +++ b/drivers/mmc/sdhci.c @@ -12,6 +12,7 @@ #include #include #include +#include #if defined(CONFIG_FIXED_SDHCI_ALIGNED_BUFFER) void *aligned_buffer = (void *)CONFIG_FIXED_SDHCI_ALIGNED_BUFFER; @@ -630,9 +631,40 @@ int sdhci_probe(struct udevice *dev) return sdhci_init(mmc); } +int sdhci_get_cd(struct udevice *dev) +{ + struct mmc *mmc = mmc_get_mmc_dev(dev); + struct sdhci_host *host = mmc->priv; + int value; + + /* If nonremovable, assume that the card is always present. */ + if (mmc->cfg->host_caps & MMC_CAP_NONREMOVABLE) + return 1; + /* If polling, assume that the card is always present. */ + if (mmc->cfg->host_caps & MMC_CAP_NEEDS_POLL) + return 1; + +#if CONFIG_IS_ENABLED(DM_GPIO) + value = dm_gpio_get_value(&host->cd_gpio); + if (value >= 0) { + if (mmc->cfg->host_caps & MMC_CAP_CD_ACTIVE_HIGH) + return !value; + else + return value; + } +#endif + value = !!(sdhci_readl(host, SDHCI_PRESENT_STATE) & + SDHCI_CARD_PRESENT); + if (mmc->cfg->host_caps & MMC_CAP_CD_ACTIVE_HIGH) + return !value; + else + return value; +} + const struct dm_mmc_ops sdhci_ops = { .send_cmd = sdhci_send_command, .set_ios = sdhci_set_ios, + .get_cd = sdhci_get_cd, #ifdef MMC_SUPPORTS_TUNING .execute_tuning = sdhci_execute_tuning, #endif From 24b1e0c7e2e3ac55fa431251b90d1521a42e3bf2 Mon Sep 17 00:00:00 2001 From: Akio Hirayama Date: Fri, 28 Jun 2019 21:16:25 +0900 Subject: [PATCH 05/27] mmc: rpmb: fix response type of CMD25 The response type of CMD25 is R1 instead of R1b. Signed-off-by: Akio Hirayama [masahiro: add log ] Signed-off-by: Masahiro Yamada --- drivers/mmc/rpmb.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/mmc/rpmb.c b/drivers/mmc/rpmb.c index 908f1920895..33371fe562e 100644 --- a/drivers/mmc/rpmb.c +++ b/drivers/mmc/rpmb.c @@ -103,7 +103,7 @@ static int mmc_rpmb_request(struct mmc *mmc, const struct s_rpmb *s, cmd.cmdidx = MMC_CMD_WRITE_MULTIPLE_BLOCK; cmd.cmdarg = 0; - cmd.resp_type = MMC_RSP_R1b; + cmd.resp_type = MMC_RSP_R1; data.src = (const char *)s; data.blocks = 1; @@ -327,7 +327,7 @@ static int send_write_mult_block(struct mmc *mmc, const struct s_rpmb *frm, { struct mmc_cmd cmd = { .cmdidx = MMC_CMD_WRITE_MULTIPLE_BLOCK, - .resp_type = MMC_RSP_R1b, + .resp_type = MMC_RSP_R1, }; struct mmc_data data = { .src = (const void *)frm, From b2ffa3320ac4b3f040c80768e2b8456bc23aebcc Mon Sep 17 00:00:00 2001 From: Jean-Jacques Hiblot Date: Tue, 2 Jul 2019 10:53:48 +0200 Subject: [PATCH 06/27] mmc: omap_hsmmc: reset FSM for DAT and CMD lines if needed before a new command It sometimes happen that the PSTATE register does not indicate that the bus is ready when it really is. This usually happens after a mode switch. In that case it makes sense to reset the FSM handling the CMD and DATA Also reset the FSMs if the STATE register cannot be cleared. This also sometimes happens after a mode switch. Signed-off-by: Jean-Jacques Hiblot --- drivers/mmc/omap_hsmmc.c | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/drivers/mmc/omap_hsmmc.c b/drivers/mmc/omap_hsmmc.c index 133cdc13527..5446ca8b8d7 100644 --- a/drivers/mmc/omap_hsmmc.c +++ b/drivers/mmc/omap_hsmmc.c @@ -1065,18 +1065,17 @@ static int omap_hsmmc_send_cmd(struct udevice *dev, struct mmc_cmd *cmd, if (get_timer(0) - start > MAX_RETRY_MS) { printf("%s: timedout waiting on cmd inhibit to clear\n", __func__); + mmc_reset_controller_fsm(mmc_base, SYSCTL_SRD); + mmc_reset_controller_fsm(mmc_base, SYSCTL_SRC); return -ETIMEDOUT; } } writel(0xFFFFFFFF, &mmc_base->stat); - start = get_timer(0); - while (readl(&mmc_base->stat)) { - if (get_timer(0) - start > MAX_RETRY_MS) { - printf("%s: timedout waiting for STAT (%x) to clear\n", - __func__, readl(&mmc_base->stat)); - return -ETIMEDOUT; - } + if (readl(&mmc_base->stat)) { + mmc_reset_controller_fsm(mmc_base, SYSCTL_SRD); + mmc_reset_controller_fsm(mmc_base, SYSCTL_SRC); } + /* * CMDREG * CMDIDX[13:8] : Command index From db52e19ced0ad7e4d4fb3160dcc201eaf820aa8c Mon Sep 17 00:00:00 2001 From: Jean-Jacques Hiblot Date: Tue, 2 Jul 2019 10:53:49 +0200 Subject: [PATCH 07/27] mmc: omap_hsmmc: don't fill the send_init_stream callback This is not required. The MMC core sends CMD0 right after the initialization and it serves the same purpose. Signed-off-by: Jean-Jacques Hiblot --- drivers/mmc/omap_hsmmc.c | 9 --------- 1 file changed, 9 deletions(-) diff --git a/drivers/mmc/omap_hsmmc.c b/drivers/mmc/omap_hsmmc.c index 5446ca8b8d7..d8f36cd1db5 100644 --- a/drivers/mmc/omap_hsmmc.c +++ b/drivers/mmc/omap_hsmmc.c @@ -775,14 +775,6 @@ tuning_error: return ret; } #endif - -static void omap_hsmmc_send_init_stream(struct udevice *dev) -{ - struct omap_hsmmc_data *priv = dev_get_priv(dev); - struct hsmmc *mmc_base = priv->base_addr; - - mmc_init_stream(mmc_base); -} #endif static void mmc_enable_irq(struct mmc *mmc, struct mmc_cmd *cmd) @@ -1521,7 +1513,6 @@ static const struct dm_mmc_ops omap_hsmmc_ops = { #ifdef MMC_SUPPORTS_TUNING .execute_tuning = omap_hsmmc_execute_tuning, #endif - .send_init_stream = omap_hsmmc_send_init_stream, #if CONFIG_IS_ENABLED(MMC_UHS_SUPPORT) .wait_dat0 = omap_hsmmc_wait_dat0, #endif From c5bda37589683ea5d26424ec75c2474226f4dd62 Mon Sep 17 00:00:00 2001 From: Jean-Jacques Hiblot Date: Tue, 2 Jul 2019 10:53:50 +0200 Subject: [PATCH 08/27] Revert "mmc: Add a new callback function to perform the 74 clocks cycle sequence" This reverts commit 318a7a576bc49aa8b4207e694d3fbd48c663d6ac. The last and only user of this callback had been the omap_hsmmc driver. It is not used anymore. Removing the callback. Signed-off-by: Jean-Jacques Hiblot --- drivers/mmc/mmc-uclass.c | 13 ------------- drivers/mmc/mmc.c | 5 ----- include/mmc.h | 10 ---------- 3 files changed, 28 deletions(-) diff --git a/drivers/mmc/mmc-uclass.c b/drivers/mmc/mmc-uclass.c index fa4d1af55d6..923a3b150f8 100644 --- a/drivers/mmc/mmc-uclass.c +++ b/drivers/mmc/mmc-uclass.c @@ -47,19 +47,6 @@ int mmc_set_ios(struct mmc *mmc) return dm_mmc_set_ios(mmc->dev); } -void dm_mmc_send_init_stream(struct udevice *dev) -{ - struct dm_mmc_ops *ops = mmc_get_ops(dev); - - if (ops->send_init_stream) - ops->send_init_stream(dev); -} - -void mmc_send_init_stream(struct mmc *mmc) -{ - dm_mmc_send_init_stream(mmc->dev); -} - #if CONFIG_IS_ENABLED(MMC_UHS_SUPPORT) int dm_mmc_wait_dat0(struct udevice *dev, int state, int timeout) { diff --git a/drivers/mmc/mmc.c b/drivers/mmc/mmc.c index 71b52c6cf2c..112f9689f7e 100644 --- a/drivers/mmc/mmc.c +++ b/drivers/mmc/mmc.c @@ -1504,10 +1504,6 @@ static int mmc_execute_tuning(struct mmc *mmc, uint opcode) } #endif -static void mmc_send_init_stream(struct mmc *mmc) -{ -} - static int mmc_set_ios(struct mmc *mmc) { int ret = 0; @@ -2664,7 +2660,6 @@ int mmc_get_op_cond(struct mmc *mmc) retry: mmc_set_initial_state(mmc); - mmc_send_init_stream(mmc); /* Reset the Card */ err = mmc_go_idle(mmc); diff --git a/include/mmc.h b/include/mmc.h index 2be3e91fcb5..7f95c3585a2 100644 --- a/include/mmc.h +++ b/include/mmc.h @@ -418,14 +418,6 @@ struct dm_mmc_ops { */ int (*set_ios)(struct udevice *dev); - /** - * send_init_stream() - send the initialization stream: 74 clock cycles - * This is used after power up before sending the first command - * - * @dev: Device to update - */ - void (*send_init_stream)(struct udevice *dev); - /** * get_cd() - See whether a card is present * @@ -472,7 +464,6 @@ struct dm_mmc_ops { int dm_mmc_send_cmd(struct udevice *dev, struct mmc_cmd *cmd, struct mmc_data *data); int dm_mmc_set_ios(struct udevice *dev); -void dm_mmc_send_init_stream(struct udevice *dev); int dm_mmc_get_cd(struct udevice *dev); int dm_mmc_get_wp(struct udevice *dev); int dm_mmc_execute_tuning(struct udevice *dev, uint opcode); @@ -480,7 +471,6 @@ int dm_mmc_wait_dat0(struct udevice *dev, int state, int timeout); /* Transition functions for compatibility */ int mmc_set_ios(struct mmc *mmc); -void mmc_send_init_stream(struct mmc *mmc); int mmc_getcd(struct mmc *mmc); int mmc_getwp(struct mmc *mmc); int mmc_execute_tuning(struct mmc *mmc, uint opcode); From c2c22b9df3f7e01a60a01a4b4a5d3dda95bac0bc Mon Sep 17 00:00:00 2001 From: Jean-Jacques Hiblot Date: Tue, 2 Jul 2019 10:53:51 +0200 Subject: [PATCH 09/27] mmc: omap_hsmmc: provide wait_dat0 even if UHS modes are not supported This function can also be used for eMMC devices. Signed-off-by: Jean-Jacques Hiblot --- drivers/mmc/omap_hsmmc.c | 4 ---- 1 file changed, 4 deletions(-) diff --git a/drivers/mmc/omap_hsmmc.c b/drivers/mmc/omap_hsmmc.c index d8f36cd1db5..3ea7f4e173d 100644 --- a/drivers/mmc/omap_hsmmc.c +++ b/drivers/mmc/omap_hsmmc.c @@ -430,7 +430,6 @@ static void omap_hsmmc_conf_bus_power(struct mmc *mmc, uint signal_voltage) writel(ac12, &mmc_base->ac12); } -#if CONFIG_IS_ENABLED(MMC_UHS_SUPPORT) static int omap_hsmmc_wait_dat0(struct udevice *dev, int state, int timeout) { int ret = -ETIMEDOUT; @@ -456,7 +455,6 @@ static int omap_hsmmc_wait_dat0(struct udevice *dev, int state, int timeout) return ret; } -#endif #if CONFIG_IS_ENABLED(MMC_IO_VOLTAGE) #if CONFIG_IS_ENABLED(DM_REGULATOR) @@ -1513,9 +1511,7 @@ static const struct dm_mmc_ops omap_hsmmc_ops = { #ifdef MMC_SUPPORTS_TUNING .execute_tuning = omap_hsmmc_execute_tuning, #endif -#if CONFIG_IS_ENABLED(MMC_UHS_SUPPORT) .wait_dat0 = omap_hsmmc_wait_dat0, -#endif }; #else static const struct mmc_ops omap_hsmmc_ops = { From 863d10044aae5ee40a9cf9a76aed62822cf45c30 Mon Sep 17 00:00:00 2001 From: Jean-Jacques Hiblot Date: Tue, 2 Jul 2019 10:53:52 +0200 Subject: [PATCH 10/27] mmc: add mmc_poll_for_busy() and change the purpose of mmc_send_status() mmc_send_status() is currently used to poll the card until it is ready, not actually returning the status of the card. Make it return the status and add another function to poll the card. Also remove the 'extern' declaration in the mmc-private.h header to comply with the coding standard. Signed-off-by: Jean-Jacques Hiblot --- drivers/mmc/mmc.c | 47 ++++++++++++++++++++++++++------------- drivers/mmc/mmc_private.h | 9 ++++---- drivers/mmc/mmc_write.c | 4 ++-- 3 files changed, 38 insertions(+), 22 deletions(-) diff --git a/drivers/mmc/mmc.c b/drivers/mmc/mmc.c index 112f9689f7e..36cce79eafe 100644 --- a/drivers/mmc/mmc.c +++ b/drivers/mmc/mmc.c @@ -206,7 +206,7 @@ int mmc_send_cmd(struct mmc *mmc, struct mmc_cmd *cmd, struct mmc_data *data) } #endif -int mmc_send_status(struct mmc *mmc, int timeout) +int mmc_send_status(struct mmc *mmc, unsigned int *status) { struct mmc_cmd cmd; int err, retries = 5; @@ -216,31 +216,46 @@ int mmc_send_status(struct mmc *mmc, int timeout) if (!mmc_host_is_spi(mmc)) cmd.cmdarg = mmc->rca << 16; - while (1) { + while (retries--) { err = mmc_send_cmd(mmc, &cmd, NULL); if (!err) { - if ((cmd.response[0] & MMC_STATUS_RDY_FOR_DATA) && - (cmd.response[0] & MMC_STATUS_CURR_STATE) != - MMC_STATE_PRG) - break; + mmc_trace_state(mmc, &cmd); + *status = cmd.response[0]; + return 0; + } + } + mmc_trace_state(mmc, &cmd); + return -ECOMM; +} - if (cmd.response[0] & MMC_STATUS_MASK) { -#if !defined(CONFIG_SPL_BUILD) || defined(CONFIG_SPL_LIBCOMMON_SUPPORT) - pr_err("Status Error: 0x%08x\n", - cmd.response[0]); -#endif - return -ECOMM; - } - } else if (--retries < 0) +int mmc_poll_for_busy(struct mmc *mmc, int timeout) +{ + unsigned int status; + int err; + + while (1) { + err = mmc_send_status(mmc, &status); + if (err) return err; + if ((status & MMC_STATUS_RDY_FOR_DATA) && + (status & MMC_STATUS_CURR_STATE) != + MMC_STATE_PRG) + break; + + if (status & MMC_STATUS_MASK) { +#if !defined(CONFIG_SPL_BUILD) || defined(CONFIG_SPL_LIBCOMMON_SUPPORT) + pr_err("Status Error: 0x%08x\n", status); +#endif + return -ECOMM; + } + if (timeout-- <= 0) break; udelay(1000); } - mmc_trace_state(mmc, &cmd); if (timeout <= 0) { #if !defined(CONFIG_SPL_BUILD) || defined(CONFIG_SPL_LIBCOMMON_SUPPORT) pr_err("Timeout waiting card ready\n"); @@ -752,7 +767,7 @@ static int __mmc_switch(struct mmc *mmc, u8 set, u8 index, u8 value, } /* Waiting for the ready status */ - return mmc_send_status(mmc, timeout); + return mmc_poll_for_busy(mmc, timeout); } return ret; diff --git a/drivers/mmc/mmc_private.h b/drivers/mmc/mmc_private.h index f49b6eb573c..35170d03abb 100644 --- a/drivers/mmc/mmc_private.h +++ b/drivers/mmc/mmc_private.h @@ -11,10 +11,11 @@ #include -extern int mmc_send_cmd(struct mmc *mmc, struct mmc_cmd *cmd, - struct mmc_data *data); -extern int mmc_send_status(struct mmc *mmc, int timeout); -extern int mmc_set_blocklen(struct mmc *mmc, int len); +int mmc_send_cmd(struct mmc *mmc, struct mmc_cmd *cmd, struct mmc_data *data); +int mmc_send_status(struct mmc *mmc, unsigned int *status); +int mmc_poll_for_busy(struct mmc *mmc, int timeout); + +int mmc_set_blocklen(struct mmc *mmc, int len); #ifdef CONFIG_FSL_ESDHC_ADAPTER_IDENT void mmc_adapter_card_type_ident(void); #endif diff --git a/drivers/mmc/mmc_write.c b/drivers/mmc/mmc_write.c index c8c83c9188e..02648b0f503 100644 --- a/drivers/mmc/mmc_write.c +++ b/drivers/mmc/mmc_write.c @@ -119,7 +119,7 @@ ulong mmc_berase(struct blk_desc *block_dev, lbaint_t start, lbaint_t blkcnt) blk += blk_r; /* Waiting for the ready status */ - if (mmc_send_status(mmc, timeout)) + if (mmc_poll_for_busy(mmc, timeout)) return 0; } @@ -177,7 +177,7 @@ static ulong mmc_write_blocks(struct mmc *mmc, lbaint_t start, } /* Waiting for the ready status */ - if (mmc_send_status(mmc, timeout)) + if (mmc_poll_for_busy(mmc, timeout)) return 0; return blkcnt; From cd0b80ec9c97bdd9fb6642671efad8ef3cb33858 Mon Sep 17 00:00:00 2001 From: Jean-Jacques Hiblot Date: Tue, 2 Jul 2019 10:53:53 +0200 Subject: [PATCH 11/27] mmc: if possible, poll the busy state using DAT0 Using the DAT0 line as a rdy/busy line is an alternative to reading the status register of the card. It especially useful in situation where the bus is not in a good shape, like when modes are switched. This is also how the linux driver behaves. Note of warning: As per the specification, while polling on DAT0 the CLK must not turned off: "[...] Without a clock edge the Device (unless previously disconnected by a deselect command (CMD7)) will force the DAT0 line down, forever. [...]" Signed-off-by: Jean-Jacques Hiblot --- drivers/mmc/mmc-uclass.c | 2 -- drivers/mmc/mmc.c | 6 ++++-- include/mmc.h | 2 -- 3 files changed, 4 insertions(+), 6 deletions(-) diff --git a/drivers/mmc/mmc-uclass.c b/drivers/mmc/mmc-uclass.c index 923a3b150f8..9327c8302de 100644 --- a/drivers/mmc/mmc-uclass.c +++ b/drivers/mmc/mmc-uclass.c @@ -47,7 +47,6 @@ int mmc_set_ios(struct mmc *mmc) return dm_mmc_set_ios(mmc->dev); } -#if CONFIG_IS_ENABLED(MMC_UHS_SUPPORT) int dm_mmc_wait_dat0(struct udevice *dev, int state, int timeout) { struct dm_mmc_ops *ops = mmc_get_ops(dev); @@ -61,7 +60,6 @@ int mmc_wait_dat0(struct mmc *mmc, int state, int timeout) { return dm_mmc_wait_dat0(mmc->dev, state, timeout); } -#endif int dm_mmc_get_wp(struct udevice *dev) { diff --git a/drivers/mmc/mmc.c b/drivers/mmc/mmc.c index 36cce79eafe..a61e311ccaa 100644 --- a/drivers/mmc/mmc.c +++ b/drivers/mmc/mmc.c @@ -29,12 +29,10 @@ static int mmc_select_mode_and_width(struct mmc *mmc, uint card_caps); #if !CONFIG_IS_ENABLED(DM_MMC) -#if CONFIG_IS_ENABLED(MMC_UHS_SUPPORT) static int mmc_wait_dat0(struct mmc *mmc, int state, int timeout) { return -ENOSYS; } -#endif __weak int board_mmc_getwp(struct mmc *mmc) { @@ -233,6 +231,10 @@ int mmc_poll_for_busy(struct mmc *mmc, int timeout) unsigned int status; int err; + err = mmc_wait_dat0(mmc, 1, timeout); + if (err != -ENOSYS) + return err; + while (1) { err = mmc_send_status(mmc, &status); if (err) diff --git a/include/mmc.h b/include/mmc.h index 7f95c3585a2..cf83b74dcbc 100644 --- a/include/mmc.h +++ b/include/mmc.h @@ -445,7 +445,6 @@ struct dm_mmc_ops { int (*execute_tuning)(struct udevice *dev, uint opcode); #endif -#if CONFIG_IS_ENABLED(MMC_UHS_SUPPORT) /** * wait_dat0() - wait until dat0 is in the target state * (CLK must be running during the wait) @@ -456,7 +455,6 @@ struct dm_mmc_ops { * @return 0 if dat0 is in the target state, -ve on error */ int (*wait_dat0)(struct udevice *dev, int state, int timeout); -#endif }; #define mmc_get_ops(dev) ((struct dm_mmc_ops *)(dev)->driver->ops) From 39320c537def08bafa07ef3dd0f519465e56d57d Mon Sep 17 00:00:00 2001 From: Jean-Jacques Hiblot Date: Tue, 2 Jul 2019 10:53:54 +0200 Subject: [PATCH 12/27] mmc: use the generic timeout for cmd6 (SWITCH) provided in the ext_csd Starting with rev 4.5, the eMMC can define a generic timeout for the SWITCH command. Following Linux Kernel code, the timeout also changed from 1000 -> 500 Signed-off-by: Jean-Jacques Hiblot --- drivers/mmc/mmc.c | 10 +++++++++- include/mmc.h | 2 ++ 2 files changed, 11 insertions(+), 1 deletion(-) diff --git a/drivers/mmc/mmc.c b/drivers/mmc/mmc.c index a61e311ccaa..ff56c3dd67d 100644 --- a/drivers/mmc/mmc.c +++ b/drivers/mmc/mmc.c @@ -21,6 +21,8 @@ #include #include "mmc_private.h" +#define DEFAULT_CMD6_TIMEOUT_MS 500 + static int mmc_set_signal_voltage(struct mmc *mmc, uint signal_voltage); static int mmc_power_cycle(struct mmc *mmc); #if !CONFIG_IS_ENABLED(MMC_TINY) @@ -745,10 +747,13 @@ static int __mmc_switch(struct mmc *mmc, u8 set, u8 index, u8 value, bool send_status) { struct mmc_cmd cmd; - int timeout = 1000; + int timeout = DEFAULT_CMD6_TIMEOUT_MS; int retries = 3; int ret; + if (mmc->gen_cmd6_time) + timeout = mmc->gen_cmd6_time * 10; + cmd.cmdidx = MMC_CMD_SWITCH; cmd.resp_type = MMC_RSP_R1b; cmd.cmdarg = (MMC_SWITCH_MODE_WRITE_BYTE << 24) | @@ -2135,6 +2140,9 @@ static int mmc_startup_v4(struct mmc *mmc) mmc->capacity_user = capacity; } + if (mmc->version >= MMC_VERSION_4_5) + mmc->gen_cmd6_time = ext_csd[EXT_CSD_GENERIC_CMD6_TIME]; + /* The partition data may be non-zero but it is only * effective if PARTITION_SETTING_COMPLETED is set in * EXT_CSD, so ignore any data if this bit is not set, diff --git a/include/mmc.h b/include/mmc.h index cf83b74dcbc..711cb5d116d 100644 --- a/include/mmc.h +++ b/include/mmc.h @@ -230,6 +230,7 @@ static inline bool mmc_is_tuning_cmd(uint cmdidx) #define EXT_CSD_HC_WP_GRP_SIZE 221 /* RO */ #define EXT_CSD_HC_ERASE_GRP_SIZE 224 /* RO */ #define EXT_CSD_BOOT_MULT 226 /* RO */ +#define EXT_CSD_GENERIC_CMD6_TIME 248 /* RO */ #define EXT_CSD_BKOPS_SUPPORT 502 /* RO */ /* @@ -585,6 +586,7 @@ struct mmc { u8 part_attr; u8 wr_rel_set; u8 part_config; + u8 gen_cmd6_time; uint tran_speed; uint legacy_speed; /* speed for the legacy mode provided by the card */ uint read_bl_len; From 513e00b64e63c277ad6dd667b823282ef4d177c1 Mon Sep 17 00:00:00 2001 From: Jean-Jacques Hiblot Date: Tue, 2 Jul 2019 10:53:55 +0200 Subject: [PATCH 13/27] mmc: When switching partition, use the timeout specified in the ext_csd The e-MMC spec allows the e-MMC to specify a timeout for the partition switch command. It can take up to 2550 ms. There is no lower limit to this value in the spec, but do as the the linux driver does and force it to be at least 300ms. Signed-off-by: Jean-Jacques Hiblot --- drivers/mmc/mmc.c | 10 ++++++++++ include/mmc.h | 5 +++++ 2 files changed, 15 insertions(+) diff --git a/drivers/mmc/mmc.c b/drivers/mmc/mmc.c index ff56c3dd67d..e5cee7dbc88 100644 --- a/drivers/mmc/mmc.c +++ b/drivers/mmc/mmc.c @@ -748,12 +748,17 @@ static int __mmc_switch(struct mmc *mmc, u8 set, u8 index, u8 value, { struct mmc_cmd cmd; int timeout = DEFAULT_CMD6_TIMEOUT_MS; + bool is_part_switch = (set == EXT_CSD_CMD_SET_NORMAL) && + (index == EXT_CSD_PART_CONF); int retries = 3; int ret; if (mmc->gen_cmd6_time) timeout = mmc->gen_cmd6_time * 10; + if (is_part_switch && mmc->part_switch_time) + timeout = mmc->part_switch_time * 10; + cmd.cmdidx = MMC_CMD_SWITCH; cmd.resp_type = MMC_RSP_R1b; cmd.cmdarg = (MMC_SWITCH_MODE_WRITE_BYTE << 24) | @@ -2152,6 +2157,11 @@ static int mmc_startup_v4(struct mmc *mmc) part_completed = !!(ext_csd[EXT_CSD_PARTITION_SETTING] & EXT_CSD_PARTITION_SETTING_COMPLETED); + mmc->part_switch_time = ext_csd[EXT_CSD_PART_SWITCH_TIME]; + /* Some eMMC set the value too low so set a minimum */ + if (mmc->part_switch_time < MMC_MIN_PART_SWITCH_TIME && mmc->part_switch_time) + mmc->part_switch_time = MMC_MIN_PART_SWITCH_TIME; + /* store the partition info of emmc */ mmc->part_support = ext_csd[EXT_CSD_PARTITIONING_SUPPORT]; if ((ext_csd[EXT_CSD_PARTITIONING_SUPPORT] & PART_SUPPORT) || diff --git a/include/mmc.h b/include/mmc.h index 711cb5d116d..032873c2ff9 100644 --- a/include/mmc.h +++ b/include/mmc.h @@ -226,6 +226,7 @@ static inline bool mmc_is_tuning_cmd(uint cmdidx) #define EXT_CSD_HS_TIMING 185 /* R/W */ #define EXT_CSD_REV 192 /* RO */ #define EXT_CSD_CARD_TYPE 196 /* RO */ +#define EXT_CSD_PART_SWITCH_TIME 199 /* RO */ #define EXT_CSD_SEC_CNT 212 /* RO, 4 bytes */ #define EXT_CSD_HC_WP_GRP_SIZE 221 /* RO */ #define EXT_CSD_HC_ERASE_GRP_SIZE 224 /* RO */ @@ -587,6 +588,7 @@ struct mmc { u8 wr_rel_set; u8 part_config; u8 gen_cmd6_time; + u8 part_switch_time; uint tran_speed; uint legacy_speed; /* speed for the legacy mode provided by the card */ uint read_bl_len; @@ -833,6 +835,9 @@ extern uint mmc_get_env_part(struct mmc *mmc); # endif int mmc_get_env_dev(void); +/* Minimum partition switch timeout in units of 10-milliseconds */ +#define MMC_MIN_PART_SWITCH_TIME 30 /* 300 ms */ + /* Set block count limit because of 16 bit register limit on some hardware*/ #ifndef CONFIG_SYS_MMC_MAX_BLK_COUNT #define CONFIG_SYS_MMC_MAX_BLK_COUNT 65535 From bb98b8c5c06a5a9befb74aef843f7cd698c52d5d Mon Sep 17 00:00:00 2001 From: Jean-Jacques Hiblot Date: Tue, 2 Jul 2019 10:53:56 +0200 Subject: [PATCH 14/27] mmc: During a switch, poll on dat0 if available and check the final status The switch operation can sometimes make the bus unreliable, in that case the send_status parameter should be false to indicate not to poll using CMD13. If polling on dat0 is possible, we should use it to detect the end of the operation. At the end of the operation it is safe to use CMD13 to get the status of the card. It is important to do so because the operation may have failed. Signed-off-by: Jean-Jacques Hiblot --- drivers/mmc/mmc.c | 51 ++++++++++++++++++++++++++++++++++------------- 1 file changed, 37 insertions(+), 14 deletions(-) diff --git a/drivers/mmc/mmc.c b/drivers/mmc/mmc.c index e5cee7dbc88..1ad35fff7d1 100644 --- a/drivers/mmc/mmc.c +++ b/drivers/mmc/mmc.c @@ -746,6 +746,7 @@ static int mmc_send_ext_csd(struct mmc *mmc, u8 *ext_csd) static int __mmc_switch(struct mmc *mmc, u8 set, u8 index, u8 value, bool send_status) { + unsigned int status, start; struct mmc_cmd cmd; int timeout = DEFAULT_CMD6_TIMEOUT_MS; bool is_part_switch = (set == EXT_CSD_CMD_SET_NORMAL) && @@ -765,25 +766,47 @@ static int __mmc_switch(struct mmc *mmc, u8 set, u8 index, u8 value, (index << 16) | (value << 8); - while (retries > 0) { + do { ret = mmc_send_cmd(mmc, &cmd, NULL); + } while (ret && retries-- > 0); - if (ret) { - retries--; - continue; + if (ret) + return ret; + + start = get_timer(0); + + /* poll dat0 for rdy/buys status */ + ret = mmc_wait_dat0(mmc, 1, timeout); + if (ret && ret != -ENOSYS) + return ret; + + /* + * In cases when not allowed to poll by using CMD13 or because we aren't + * capable of polling by using mmc_wait_dat0, then rely on waiting the + * stated timeout to be sufficient. + */ + if (ret == -ENOSYS && !send_status) + mdelay(timeout); + + /* Finally wait until the card is ready or indicates a failure + * to switch. It doesn't hurt to use CMD13 here even if send_status + * is false, because by now (after 'timeout' ms) the bus should be + * reliable. + */ + do { + ret = mmc_send_status(mmc, &status); + + if (!ret && (status & MMC_STATUS_SWITCH_ERROR)) { + pr_debug("switch failed %d/%d/0x%x !\n", set, index, + value); + return -EIO; } - - if (!send_status) { - mdelay(50); + if (!ret && (status & MMC_STATUS_RDY_FOR_DATA)) return 0; - } - - /* Waiting for the ready status */ - return mmc_poll_for_busy(mmc, timeout); - } - - return ret; + udelay(100); + } while (get_timer(start) < timeout); + return -ETIMEDOUT; } int mmc_switch(struct mmc *mmc, u8 set, u8 index, u8 value) From 9bc5666c8a32aa335b236fb3e140aa55766c7b03 Mon Sep 17 00:00:00 2001 From: Jean-Jacques Hiblot Date: Tue, 2 Jul 2019 10:53:57 +0200 Subject: [PATCH 15/27] mmc: do not change mode when accessing a boot partition Accessing the boot partition had been error prone with HS200 and HS400 and was disabled. The driver first switched to a lesser mode and then switched the partition access. It was mostly due to a bad handling of the switch and has been fixed, so let's remove this 'feature' Signed-off-by: Jean-Jacques Hiblot --- drivers/mmc/mmc.c | 36 ------------------------------------ 1 file changed, 36 deletions(-) diff --git a/drivers/mmc/mmc.c b/drivers/mmc/mmc.c index 1ad35fff7d1..709733747ab 100644 --- a/drivers/mmc/mmc.c +++ b/drivers/mmc/mmc.c @@ -955,46 +955,10 @@ static int mmc_set_capacity(struct mmc *mmc, int part_num) return 0; } -#if CONFIG_IS_ENABLED(MMC_HS200_SUPPORT) || CONFIG_IS_ENABLED(MMC_HS400_SUPPORT) -static int mmc_boot_part_access_chk(struct mmc *mmc, unsigned int part_num) -{ - int forbidden = 0; - bool change = false; - - if (part_num & PART_ACCESS_MASK) - forbidden = MMC_CAP(MMC_HS_200) | MMC_CAP(MMC_HS_400); - - if (MMC_CAP(mmc->selected_mode) & forbidden) { - pr_debug("selected mode (%s) is forbidden for part %d\n", - mmc_mode_name(mmc->selected_mode), part_num); - change = true; - } else if (mmc->selected_mode != mmc->best_mode) { - pr_debug("selected mode is not optimal\n"); - change = true; - } - - if (change) - return mmc_select_mode_and_width(mmc, - mmc->card_caps & ~forbidden); - - return 0; -} -#else -static inline int mmc_boot_part_access_chk(struct mmc *mmc, - unsigned int part_num) -{ - return 0; -} -#endif - int mmc_switch_part(struct mmc *mmc, unsigned int part_num) { int ret; - ret = mmc_boot_part_access_chk(mmc, part_num); - if (ret) - return ret; - ret = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL, EXT_CSD_PART_CONF, (mmc->part_config & ~PART_ACCESS_MASK) | (part_num & PART_ACCESS_MASK)); From 0538477c53237230c36b78cfe5fa26aed81c9d87 Mon Sep 17 00:00:00 2001 From: Jean-Jacques Hiblot Date: Tue, 2 Jul 2019 10:53:58 +0200 Subject: [PATCH 16/27] mmc: retry a few times if a partition switch failed This operation may fail. Retry it a few times before giving up and report a failure. Signed-off-by: Jean-Jacques Hiblot --- drivers/mmc/mmc.c | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/drivers/mmc/mmc.c b/drivers/mmc/mmc.c index 709733747ab..cec39a9acf4 100644 --- a/drivers/mmc/mmc.c +++ b/drivers/mmc/mmc.c @@ -958,10 +958,14 @@ static int mmc_set_capacity(struct mmc *mmc, int part_num) int mmc_switch_part(struct mmc *mmc, unsigned int part_num) { int ret; + int retry = 3; - ret = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL, EXT_CSD_PART_CONF, - (mmc->part_config & ~PART_ACCESS_MASK) - | (part_num & PART_ACCESS_MASK)); + do { + ret = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL, + EXT_CSD_PART_CONF, + (mmc->part_config & ~PART_ACCESS_MASK) + | (part_num & PART_ACCESS_MASK)); + } while (ret && retry--); /* * Set the capacity if the switch succeeded or was intended From f49ff79935730279cca0e6a288bcc9ad4f4f63dd Mon Sep 17 00:00:00 2001 From: Anup Patel Date: Mon, 8 Jul 2019 04:10:43 +0000 Subject: [PATCH 17/27] mmc: skip select_mode_and_width for MMC SPI host The MMC mode and width are fixed for MMC SPI host hence we skip sd_select_mode_and_width() and mmc_select_mode_and_width() for MMC SPI host. Signed-off-by: Anup Patel Reviewed-by: Bin Meng Tested-by: Bin Meng --- drivers/mmc/mmc.c | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/drivers/mmc/mmc.c b/drivers/mmc/mmc.c index cec39a9acf4..2a1ba6e51dc 100644 --- a/drivers/mmc/mmc.c +++ b/drivers/mmc/mmc.c @@ -1686,6 +1686,13 @@ static int sd_select_mode_and_width(struct mmc *mmc, uint card_caps) mmc_dump_capabilities("host", mmc->host_caps); #endif + if (mmc_host_is_spi(mmc)) { + mmc_set_bus_width(mmc, 1); + mmc_select_mode(mmc, SD_LEGACY); + mmc_set_clock(mmc, mmc->tran_speed, MMC_CLK_ENABLE); + return 0; + } + /* Restrict card's capabilities by what the host can do */ caps = card_caps & mmc->host_caps; @@ -1948,6 +1955,13 @@ static int mmc_select_mode_and_width(struct mmc *mmc, uint card_caps) mmc_dump_capabilities("host", mmc->host_caps); #endif + if (mmc_host_is_spi(mmc)) { + mmc_set_bus_width(mmc, 1); + mmc_select_mode(mmc, MMC_LEGACY); + mmc_set_clock(mmc, mmc->tran_speed, MMC_CLK_ENABLE); + return 0; + } + /* Restrict card's capabilities by what the host can do */ card_caps &= mmc->host_caps; From 05e35d429745253752b68f73146c22268ec9a5a8 Mon Sep 17 00:00:00 2001 From: Bhargav Shah Date: Mon, 8 Jul 2019 04:10:48 +0000 Subject: [PATCH 18/27] mmc: mmc_spi: Re-write driver using DM framework This patch rewrites MMC SPI driver using U-Boot DM framework and get it's working on SiFive Unleashed board. Signed-off-by: Bhargav Shah Signed-off-by: Anup Patel Reviewed-by: Bin Meng Tested-by: Bin Meng --- drivers/mmc/Kconfig | 18 ++ drivers/mmc/mmc_spi.c | 491 ++++++++++++++++++++++------------- scripts/config_whitelist.txt | 6 - 3 files changed, 331 insertions(+), 184 deletions(-) diff --git a/drivers/mmc/Kconfig b/drivers/mmc/Kconfig index b5180ea4a06..a4a6a6c085d 100644 --- a/drivers/mmc/Kconfig +++ b/drivers/mmc/Kconfig @@ -46,6 +46,24 @@ config SPL_DM_MMC if MMC +config MMC_SPI + bool "Support for SPI-based MMC controller" + depends on DM_MMC && DM_SPI + help + This selects SPI-based MMC controllers. + If you have an MMC controller on a SPI bus, say Y here. + + If unsure, say N. + +config MMC_SPI_CRC_ON + bool "Support CRC for SPI-based MMC controller" + depends on MMC_SPI + default y + help + This enables CRC for SPI-based MMC controllers. + + If unsure, say N. + config ARM_PL180_MMCI bool "ARM AMBA Multimedia Card Interface and compatible support" depends on DM_MMC && OF_CONTROL diff --git a/drivers/mmc/mmc_spi.c b/drivers/mmc/mmc_spi.c index 4f57990d9c4..f3d687ae806 100644 --- a/drivers/mmc/mmc_spi.c +++ b/drivers/mmc/mmc_spi.c @@ -2,6 +2,8 @@ * generic mmc spi driver * * Copyright (C) 2010 Thomas Chou + * Copyright 2019 Bhargav Shah + * * Licensed under the GPL-2 or later. */ #include @@ -9,21 +11,23 @@ #include #include #include -#include +#include #include #include #include +#include +#include /* MMC/SD in SPI mode reports R1 status always */ -#define R1_SPI_IDLE (1 << 0) -#define R1_SPI_ERASE_RESET (1 << 1) -#define R1_SPI_ILLEGAL_COMMAND (1 << 2) -#define R1_SPI_COM_CRC (1 << 3) -#define R1_SPI_ERASE_SEQ (1 << 4) -#define R1_SPI_ADDRESS (1 << 5) -#define R1_SPI_PARAMETER (1 << 6) +#define R1_SPI_IDLE BIT(0) +#define R1_SPI_ERASE_RESET BIT(1) +#define R1_SPI_ILLEGAL_COMMAND BIT(2) +#define R1_SPI_COM_CRC BIT(3) +#define R1_SPI_ERASE_SEQ BIT(4) +#define R1_SPI_ADDRESS BIT(5) +#define R1_SPI_PARAMETER BIT(6) /* R1 bit 7 is always zero, reuse this bit for error */ -#define R1_SPI_ERROR (1 << 7) +#define R1_SPI_ERROR BIT(7) /* Response tokens used to ack each block written: */ #define SPI_MMC_RESPONSE_CODE(x) ((x) & 0x1f) @@ -34,28 +38,45 @@ /* Read and write blocks start with these tokens and end with crc; * on error, read tokens act like a subset of R2_SPI_* values. */ -#define SPI_TOKEN_SINGLE 0xfe /* single block r/w, multiblock read */ -#define SPI_TOKEN_MULTI_WRITE 0xfc /* multiblock write */ -#define SPI_TOKEN_STOP_TRAN 0xfd /* terminate multiblock write */ +/* single block write multiblock read */ +#define SPI_TOKEN_SINGLE 0xfe +/* multiblock write */ +#define SPI_TOKEN_MULTI_WRITE 0xfc +/* terminate multiblock write */ +#define SPI_TOKEN_STOP_TRAN 0xfd /* MMC SPI commands start with a start bit "0" and a transmit bit "1" */ -#define MMC_SPI_CMD(x) (0x40 | (x & 0x3f)) +#define MMC_SPI_CMD(x) (0x40 | (x)) /* bus capability */ -#define MMC_SPI_VOLTAGE (MMC_VDD_32_33 | MMC_VDD_33_34) -#define MMC_SPI_MIN_CLOCK 400000 /* 400KHz to meet MMC spec */ +#define MMC_SPI_VOLTAGE (MMC_VDD_32_33 | MMC_VDD_33_34) +#define MMC_SPI_MIN_CLOCK 400000 /* 400KHz to meet MMC spec */ +#define MMC_SPI_MAX_CLOCK 25000000 /* SD/MMC legacy speed */ /* timeout value */ -#define CTOUT 8 -#define RTOUT 3000000 /* 1 sec */ -#define WTOUT 3000000 /* 1 sec */ +#define CMD_TIMEOUT 8 +#define READ_TIMEOUT 3000000 /* 1 sec */ +#define WRITE_TIMEOUT 3000000 /* 1 sec */ -static uint mmc_spi_sendcmd(struct mmc *mmc, ushort cmdidx, u32 cmdarg) +struct mmc_spi_priv { + struct spi_slave *spi; + struct mmc_config cfg; + struct mmc mmc; +}; + +static int mmc_spi_sendcmd(struct udevice *dev, + ushort cmdidx, u32 cmdarg, u32 resp_type, + u8 *resp, u32 resp_size, + bool resp_match, u8 resp_match_value) { - struct spi_slave *spi = mmc->priv; - u8 cmdo[7]; - u8 r1; - int i; + int i, rpos = 0, ret = 0; + u8 cmdo[7], r; + + debug("%s: cmd%d cmdarg=0x%x resp_type=0x%x " + "resp_size=%d resp_match=%d resp_match_value=0x%x\n", + __func__, cmdidx, cmdarg, resp_type, + resp_size, resp_match, resp_match_value); + cmdo[0] = 0xff; cmdo[1] = MMC_SPI_CMD(cmdidx); cmdo[2] = cmdarg >> 24; @@ -63,37 +84,79 @@ static uint mmc_spi_sendcmd(struct mmc *mmc, ushort cmdidx, u32 cmdarg) cmdo[4] = cmdarg >> 8; cmdo[5] = cmdarg; cmdo[6] = (crc7(0, &cmdo[1], 5) << 1) | 0x01; - spi_xfer(spi, sizeof(cmdo) * 8, cmdo, NULL, 0); - for (i = 0; i < CTOUT; i++) { - spi_xfer(spi, 1 * 8, NULL, &r1, 0); - if (i && (r1 & 0x80) == 0) /* r1 response */ - break; - } - debug("%s:cmd%d resp%d %x\n", __func__, cmdidx, i, r1); - return r1; -} + ret = dm_spi_xfer(dev, sizeof(cmdo) * 8, cmdo, NULL, 0); + if (ret) + return ret; -static uint mmc_spi_readdata(struct mmc *mmc, void *xbuf, - u32 bcnt, u32 bsize) -{ - struct spi_slave *spi = mmc->priv; - u8 *buf = xbuf; - u8 r1; - u16 crc; - int i; - while (bcnt--) { - for (i = 0; i < RTOUT; i++) { - spi_xfer(spi, 1 * 8, NULL, &r1, 0); - if (r1 != 0xff) /* data token */ + ret = dm_spi_xfer(dev, 1 * 8, NULL, &r, 0); + if (ret) + return ret; + + if (!resp || !resp_size) + return 0; + + debug("%s: cmd%d", __func__, cmdidx); + + if (resp_match) { + r = ~resp_match_value; + i = CMD_TIMEOUT; + while (i--) { + ret = dm_spi_xfer(dev, 1 * 8, NULL, &r, 0); + if (ret) + return ret; + debug(" resp%d=0x%x", rpos, r); + rpos++; + if (r == resp_match_value) break; } - debug("%s:tok%d %x\n", __func__, i, r1); + if (!i && (r != resp_match_value)) + return -ETIMEDOUT; + } + + for (i = 0; i < resp_size; i++) { + if (i == 0 && resp_match) { + resp[i] = resp_match_value; + continue; + } + ret = dm_spi_xfer(dev, 1 * 8, NULL, &r, 0); + if (ret) + return ret; + debug(" resp%d=0x%x", rpos, r); + rpos++; + resp[i] = r; + } + + debug("\n"); + + return 0; +} + +static int mmc_spi_readdata(struct udevice *dev, + void *xbuf, u32 bcnt, u32 bsize) +{ + u16 crc; + u8 *buf = xbuf, r1; + int i, ret = 0; + + while (bcnt--) { + for (i = 0; i < READ_TIMEOUT; i++) { + ret = dm_spi_xfer(dev, 1 * 8, NULL, &r1, 0); + if (ret) + return ret; + if (r1 == SPI_TOKEN_SINGLE) + break; + } + debug("%s: data tok%d 0x%x\n", __func__, i, r1); if (r1 == SPI_TOKEN_SINGLE) { - spi_xfer(spi, bsize * 8, NULL, buf, 0); - spi_xfer(spi, 2 * 8, NULL, &crc, 0); + ret = dm_spi_xfer(dev, bsize * 8, NULL, buf, 0); + if (ret) + return ret; + ret = dm_spi_xfer(dev, 2 * 8, NULL, &crc, 0); + if (ret) + return ret; #ifdef CONFIG_MMC_SPI_CRC_ON - if (be_to_cpu16(crc16_ccitt(0, buf, bsize)) != crc) { - debug("%s: CRC error\n", mmc->cfg->name); + if (be16_to_cpu(crc16_ccitt(0, buf, bsize)) != crc) { + debug("%s: data crc error\n", __func__); r1 = R1_SPI_COM_CRC; break; } @@ -105,48 +168,56 @@ static uint mmc_spi_readdata(struct mmc *mmc, void *xbuf, } buf += bsize; } - return r1; + + if (r1 & R1_SPI_COM_CRC) + ret = -ECOMM; + else if (r1) /* other errors */ + ret = -ETIMEDOUT; + + return ret; } -static uint mmc_spi_writedata(struct mmc *mmc, const void *xbuf, - u32 bcnt, u32 bsize, int multi) +static int mmc_spi_writedata(struct udevice *dev, const void *xbuf, + u32 bcnt, u32 bsize, int multi) { - struct spi_slave *spi = mmc->priv; const u8 *buf = xbuf; - u8 r1; + u8 r1, tok[2]; u16 crc; - u8 tok[2]; - int i; + int i, ret = 0; + tok[0] = 0xff; tok[1] = multi ? SPI_TOKEN_MULTI_WRITE : SPI_TOKEN_SINGLE; + while (bcnt--) { #ifdef CONFIG_MMC_SPI_CRC_ON crc = cpu_to_be16(crc16_ccitt(0, (u8 *)buf, bsize)); #endif - spi_xfer(spi, 2 * 8, tok, NULL, 0); - spi_xfer(spi, bsize * 8, buf, NULL, 0); - spi_xfer(spi, 2 * 8, &crc, NULL, 0); - for (i = 0; i < CTOUT; i++) { - spi_xfer(spi, 1 * 8, NULL, &r1, 0); + dm_spi_xfer(dev, 2 * 8, tok, NULL, 0); + dm_spi_xfer(dev, bsize * 8, buf, NULL, 0); + dm_spi_xfer(dev, 2 * 8, &crc, NULL, 0); + for (i = 0; i < CMD_TIMEOUT; i++) { + dm_spi_xfer(dev, 1 * 8, NULL, &r1, 0); if ((r1 & 0x10) == 0) /* response token */ break; } - debug("%s:tok%d %x\n", __func__, i, r1); + debug("%s: data tok%d 0x%x\n", __func__, i, r1); if (SPI_MMC_RESPONSE_CODE(r1) == SPI_RESPONSE_ACCEPTED) { - for (i = 0; i < WTOUT; i++) { /* wait busy */ - spi_xfer(spi, 1 * 8, NULL, &r1, 0); + debug("%s: data accepted\n", __func__); + for (i = 0; i < WRITE_TIMEOUT; i++) { /* wait busy */ + dm_spi_xfer(dev, 1 * 8, NULL, &r1, 0); if (i && r1 == 0xff) { r1 = 0; break; } } - if (i == WTOUT) { - debug("%s:wtout %x\n", __func__, r1); + if (i == WRITE_TIMEOUT) { + debug("%s: data write timeout 0x%x\n", + __func__, r1); r1 = R1_SPI_ERROR; break; } } else { - debug("%s: err %x\n", __func__, r1); + debug("%s: data error 0x%x\n", __func__, r1); r1 = R1_SPI_COM_CRC; break; } @@ -154,140 +225,204 @@ static uint mmc_spi_writedata(struct mmc *mmc, const void *xbuf, } if (multi && bcnt == -1) { /* stop multi write */ tok[1] = SPI_TOKEN_STOP_TRAN; - spi_xfer(spi, 2 * 8, tok, NULL, 0); - for (i = 0; i < WTOUT; i++) { /* wait busy */ - spi_xfer(spi, 1 * 8, NULL, &r1, 0); + dm_spi_xfer(dev, 2 * 8, tok, NULL, 0); + for (i = 0; i < WRITE_TIMEOUT; i++) { /* wait busy */ + dm_spi_xfer(dev, 1 * 8, NULL, &r1, 0); if (i && r1 == 0xff) { r1 = 0; break; } } - if (i == WTOUT) { - debug("%s:wstop %x\n", __func__, r1); + if (i == WRITE_TIMEOUT) { + debug("%s: data write timeout 0x%x\n", __func__, r1); r1 = R1_SPI_ERROR; } } - return r1; -} -static int mmc_spi_request(struct mmc *mmc, struct mmc_cmd *cmd, - struct mmc_data *data) -{ - struct spi_slave *spi = mmc->priv; - u8 r1; - int i; - int ret = 0; - debug("%s:cmd%d %x %x\n", __func__, - cmd->cmdidx, cmd->resp_type, cmd->cmdarg); - spi_claim_bus(spi); - spi_cs_activate(spi); - r1 = mmc_spi_sendcmd(mmc, cmd->cmdidx, cmd->cmdarg); - if (r1 == 0xff) { /* no response */ - ret = -ENOMEDIUM; - goto done; - } else if (r1 & R1_SPI_COM_CRC) { + if (r1 & R1_SPI_COM_CRC) ret = -ECOMM; - goto done; - } else if (r1 & ~R1_SPI_IDLE) { /* other errors */ + else if (r1) /* other errors */ ret = -ETIMEDOUT; - goto done; - } else if (cmd->resp_type == MMC_RSP_R2) { - r1 = mmc_spi_readdata(mmc, cmd->response, 1, 16); - for (i = 0; i < 4; i++) - cmd->response[i] = be32_to_cpu(cmd->response[i]); - debug("r128 %x %x %x %x\n", cmd->response[0], cmd->response[1], - cmd->response[2], cmd->response[3]); - } else if (!data) { - switch (cmd->cmdidx) { - case SD_CMD_APP_SEND_OP_COND: - case MMC_CMD_SEND_OP_COND: - cmd->response[0] = (r1 & R1_SPI_IDLE) ? 0 : OCR_BUSY; - break; - case SD_CMD_SEND_IF_COND: - case MMC_CMD_SPI_READ_OCR: - spi_xfer(spi, 4 * 8, NULL, cmd->response, 0); - cmd->response[0] = be32_to_cpu(cmd->response[0]); - debug("r32 %x\n", cmd->response[0]); - break; - case MMC_CMD_SEND_STATUS: - spi_xfer(spi, 1 * 8, NULL, cmd->response, 0); - cmd->response[0] = (cmd->response[0] & 0xff) ? - MMC_STATUS_ERROR : MMC_STATUS_RDY_FOR_DATA; - break; - } - } else { - debug("%s:data %x %x %x\n", __func__, - data->flags, data->blocks, data->blocksize); - if (data->flags == MMC_DATA_READ) - r1 = mmc_spi_readdata(mmc, data->dest, - data->blocks, data->blocksize); - else if (data->flags == MMC_DATA_WRITE) - r1 = mmc_spi_writedata(mmc, data->src, - data->blocks, data->blocksize, - (cmd->cmdidx == MMC_CMD_WRITE_MULTIPLE_BLOCK)); - if (r1 & R1_SPI_COM_CRC) - ret = -ECOMM; - else if (r1) /* other errors */ - ret = -ETIMEDOUT; - } -done: - spi_cs_deactivate(spi); - spi_release_bus(spi); + return ret; } -static int mmc_spi_set_ios(struct mmc *mmc) +static int dm_mmc_spi_set_ios(struct udevice *dev) { - struct spi_slave *spi = mmc->priv; - - debug("%s: clock %u\n", __func__, mmc->clock); - if (mmc->clock) - spi_set_speed(spi, mmc->clock); return 0; } -static int mmc_spi_init_p(struct mmc *mmc) +static int dm_mmc_spi_request(struct udevice *dev, struct mmc_cmd *cmd, + struct mmc_data *data) { - struct spi_slave *spi = mmc->priv; - spi_set_speed(spi, MMC_SPI_MIN_CLOCK); - spi_claim_bus(spi); - /* cs deactivated for 100+ clock */ - spi_xfer(spi, 18 * 8, NULL, NULL, 0); - spi_release_bus(spi); - return 0; -} + int i, multi, ret = 0; + u8 *resp = NULL; + u32 resp_size = 0; + bool resp_match = false; + u8 resp8 = 0, resp40[5] = { 0 }, resp_match_value = 0; -static const struct mmc_ops mmc_spi_ops = { - .send_cmd = mmc_spi_request, - .set_ios = mmc_spi_set_ios, - .init = mmc_spi_init_p, -}; + dm_spi_claim_bus(dev); -static struct mmc_config mmc_spi_cfg = { - .name = "MMC_SPI", - .ops = &mmc_spi_ops, - .host_caps = MMC_MODE_SPI, - .voltages = MMC_SPI_VOLTAGE, - .f_min = MMC_SPI_MIN_CLOCK, - .part_type = PART_TYPE_DOS, - .b_max = CONFIG_SYS_MMC_MAX_BLK_COUNT, -}; + for (i = 0; i < 4; i++) + cmd->response[i] = 0; -struct mmc *mmc_spi_init(uint bus, uint cs, uint speed, uint mode) -{ - struct mmc *mmc; - struct spi_slave *spi; + switch (cmd->cmdidx) { + case SD_CMD_APP_SEND_OP_COND: + case MMC_CMD_SEND_OP_COND: + resp = &resp8; + resp_size = sizeof(resp8); + cmd->cmdarg = 0x40000000; + break; + case SD_CMD_SEND_IF_COND: + resp = (u8 *)&resp40[0]; + resp_size = sizeof(resp40); + resp_match = true; + resp_match_value = R1_SPI_IDLE; + break; + case MMC_CMD_SPI_READ_OCR: + resp = (u8 *)&resp40[0]; + resp_size = sizeof(resp40); + break; + case MMC_CMD_SEND_STATUS: + case MMC_CMD_SET_BLOCKLEN: + case MMC_CMD_SPI_CRC_ON_OFF: + case MMC_CMD_STOP_TRANSMISSION: + resp = &resp8; + resp_size = sizeof(resp8); + resp_match = true; + resp_match_value = 0x0; + break; + case MMC_CMD_SEND_CSD: + case MMC_CMD_SEND_CID: + case MMC_CMD_READ_SINGLE_BLOCK: + case MMC_CMD_READ_MULTIPLE_BLOCK: + case MMC_CMD_WRITE_SINGLE_BLOCK: + case MMC_CMD_WRITE_MULTIPLE_BLOCK: + break; + default: + resp = &resp8; + resp_size = sizeof(resp8); + resp_match = true; + resp_match_value = R1_SPI_IDLE; + break; + }; - spi = spi_setup_slave(bus, cs, speed, mode); - if (spi == NULL) - return NULL; + ret = mmc_spi_sendcmd(dev, cmd->cmdidx, cmd->cmdarg, cmd->resp_type, + resp, resp_size, resp_match, resp_match_value); + if (ret) + goto done; - mmc_spi_cfg.f_max = speed; - - mmc = mmc_create(&mmc_spi_cfg, spi); - if (mmc == NULL) { - spi_free_slave(spi); - return NULL; + switch (cmd->cmdidx) { + case SD_CMD_APP_SEND_OP_COND: + case MMC_CMD_SEND_OP_COND: + cmd->response[0] = (resp8 & R1_SPI_IDLE) ? 0 : OCR_BUSY; + break; + case SD_CMD_SEND_IF_COND: + case MMC_CMD_SPI_READ_OCR: + cmd->response[0] = resp40[4]; + cmd->response[0] |= (uint)resp40[3] << 8; + cmd->response[0] |= (uint)resp40[2] << 16; + cmd->response[0] |= (uint)resp40[1] << 24; + break; + case MMC_CMD_SEND_STATUS: + cmd->response[0] = (resp8 & 0xff) ? + MMC_STATUS_ERROR : MMC_STATUS_RDY_FOR_DATA; + break; + case MMC_CMD_SEND_CID: + case MMC_CMD_SEND_CSD: + ret = mmc_spi_readdata(dev, cmd->response, 1, 16); + if (ret) + return ret; + for (i = 0; i < 4; i++) + cmd->response[i] = + cpu_to_be32(cmd->response[i]); + break; + default: + cmd->response[0] = resp8; + break; } - return mmc; + + debug("%s: cmd%d resp0=0x%x resp1=0x%x resp2=0x%x resp3=0x%x\n", + __func__, cmd->cmdidx, cmd->response[0], cmd->response[1], + cmd->response[2], cmd->response[3]); + + if (data) { + debug("%s: data flags=0x%x blocks=%d block_size=%d\n", + __func__, data->flags, data->blocks, data->blocksize); + multi = (cmd->cmdidx == MMC_CMD_WRITE_MULTIPLE_BLOCK); + if (data->flags == MMC_DATA_READ) + ret = mmc_spi_readdata(dev, data->dest, + data->blocks, data->blocksize); + else if (data->flags == MMC_DATA_WRITE) + ret = mmc_spi_writedata(dev, data->src, + data->blocks, data->blocksize, + multi); + } + +done: + dm_spi_release_bus(dev); + + return ret; } + +static int mmc_spi_probe(struct udevice *dev) +{ + struct mmc_spi_priv *priv = dev_get_priv(dev); + struct mmc_uclass_priv *upriv = dev_get_uclass_priv(dev); + char *name; + + priv->spi = dev_get_parent_priv(dev); + if (!priv->spi->max_hz) + priv->spi->max_hz = MMC_SPI_MAX_CLOCK; + priv->spi->speed = 0; + priv->spi->mode = SPI_MODE_0; + priv->spi->wordlen = 8; + + name = malloc(strlen(dev->parent->name) + strlen(dev->name) + 4); + if (!name) + return -ENOMEM; + sprintf(name, "%s:%s", dev->parent->name, dev->name); + + priv->cfg.name = name; + priv->cfg.host_caps = MMC_MODE_SPI; + priv->cfg.voltages = MMC_SPI_VOLTAGE; + priv->cfg.f_min = MMC_SPI_MIN_CLOCK; + priv->cfg.f_max = priv->spi->max_hz; + priv->cfg.part_type = PART_TYPE_DOS; + priv->cfg.b_max = CONFIG_SYS_MMC_MAX_BLK_COUNT; + + priv->mmc.cfg = &priv->cfg; + priv->mmc.priv = priv; + priv->mmc.dev = dev; + + upriv->mmc = &priv->mmc; + + return 0; +} + +static int mmc_spi_bind(struct udevice *dev) +{ + struct mmc_spi_priv *priv = dev_get_priv(dev); + + return mmc_bind(dev, &priv->mmc, &priv->cfg); +} + +static const struct dm_mmc_ops mmc_spi_ops = { + .send_cmd = dm_mmc_spi_request, + .set_ios = dm_mmc_spi_set_ios, +}; + +static const struct udevice_id dm_mmc_spi_match[] = { + { .compatible = "mmc-spi-slot" }, + { /* sentinel */ } +}; + +U_BOOT_DRIVER(mmc_spi) = { + .name = "mmc_spi", + .id = UCLASS_MMC, + .of_match = dm_mmc_spi_match, + .ops = &mmc_spi_ops, + .probe = mmc_spi_probe, + .bind = mmc_spi_bind, + .priv_auto_alloc_size = sizeof(struct mmc_spi_priv), +}; diff --git a/scripts/config_whitelist.txt b/scripts/config_whitelist.txt index 2c9cfb450d0..44c03968307 100644 --- a/scripts/config_whitelist.txt +++ b/scripts/config_whitelist.txt @@ -1165,12 +1165,6 @@ CONFIG_MMCBOOTCOMMAND CONFIG_MMCROOT CONFIG_MMC_DEFAULT_DEV CONFIG_MMC_RPMB_TRACE -CONFIG_MMC_SPI -CONFIG_MMC_SPI_BUS -CONFIG_MMC_SPI_CRC_ON -CONFIG_MMC_SPI_CS -CONFIG_MMC_SPI_MODE -CONFIG_MMC_SPI_SPEED CONFIG_MMC_SUNXI_SLOT CONFIG_MMU CONFIG_MONITOR_IS_IN_RAM From a897269c932999a5c028654489ad68baa6806fdb Mon Sep 17 00:00:00 2001 From: Anup Patel Date: Mon, 8 Jul 2019 04:10:55 +0000 Subject: [PATCH 19/27] cmd: Remove mmc_spi command The mmc_spi command was added to manually setup MMC over SPI bus using command. This was required by the legacy non-DM MMC_SPI driver. With DM based MMC_SPI driver in-place, we can now use all general storge commands and mmc command for MMC over SPI bus hence we remove the mmc_spi command all it's references. Suggested-by: Bin Meng Signed-off-by: Anup Patel Reviewed-by: Bin Meng --- cmd/Kconfig | 9 ---- cmd/Makefile | 1 - cmd/mmc_spi.c | 88 --------------------------------------- include/configs/UCP1020.h | 1 - include/mmc.h | 1 - 5 files changed, 100 deletions(-) delete mode 100644 cmd/mmc_spi.c diff --git a/cmd/Kconfig b/cmd/Kconfig index 7f6bca81a92..67284d8a5f6 100644 --- a/cmd/Kconfig +++ b/cmd/Kconfig @@ -955,15 +955,6 @@ config CMD_NVME help NVM Express device support -config CMD_MMC_SPI - bool "mmc_spi - Set up MMC SPI device" - help - Provides a way to set up an MMC (Multimedia Card) SPI (Serial - Peripheral Interface) device. The device provides a means of - accessing an MMC device via SPI using a single data line, limited - to 20MHz. It is useful since it reduces the amount of protocol code - required. - config CMD_ONENAND bool "onenand - access to onenand device" help diff --git a/cmd/Makefile b/cmd/Makefile index 49e64cde1d0..0aa37414533 100644 --- a/cmd/Makefile +++ b/cmd/Makefile @@ -93,7 +93,6 @@ obj-$(CONFIG_CMD_MII) += mdio.o endif obj-$(CONFIG_CMD_MISC) += misc.o obj-$(CONFIG_CMD_MMC) += mmc.o -obj-$(CONFIG_CMD_MMC_SPI) += mmc_spi.o obj-$(CONFIG_MP) += mp.o obj-$(CONFIG_CMD_MTD) += mtd.o obj-$(CONFIG_CMD_MTDPARTS) += mtdparts.o diff --git a/cmd/mmc_spi.c b/cmd/mmc_spi.c deleted file mode 100644 index 0c44d068178..00000000000 --- a/cmd/mmc_spi.c +++ /dev/null @@ -1,88 +0,0 @@ -/* - * Command for mmc_spi setup. - * - * Copyright (C) 2010 Thomas Chou - * Licensed under the GPL-2 or later. - */ - -#include -#include -#include - -#ifndef CONFIG_MMC_SPI_BUS -# define CONFIG_MMC_SPI_BUS 0 -#endif -#ifndef CONFIG_MMC_SPI_CS -# define CONFIG_MMC_SPI_CS 1 -#endif -/* in SPI mode, MMC speed limit is 20MHz, while SD speed limit is 25MHz */ -#ifndef CONFIG_MMC_SPI_SPEED -# define CONFIG_MMC_SPI_SPEED 25000000 -#endif -/* MMC and SD specs only seem to care that sampling is on the - * rising edge ... meaning SPI modes 0 or 3. So either SPI mode - * should be legit. We'll use mode 0 since the steady state is 0, - * which is appropriate for hotplugging, unless the platform data - * specify mode 3 (if hardware is not compatible to mode 0). - */ -#ifndef CONFIG_MMC_SPI_MODE -# define CONFIG_MMC_SPI_MODE SPI_MODE_0 -#endif - -static int do_mmc_spi(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) -{ - uint bus = CONFIG_MMC_SPI_BUS; - uint cs = CONFIG_MMC_SPI_CS; - uint speed = CONFIG_MMC_SPI_SPEED; - uint mode = CONFIG_MMC_SPI_MODE; - char *endp; - struct mmc *mmc; - - if (argc < 2) - goto usage; - - cs = simple_strtoul(argv[1], &endp, 0); - if (*argv[1] == 0 || (*endp != 0 && *endp != ':')) - goto usage; - if (*endp == ':') { - if (endp[1] == 0) - goto usage; - bus = cs; - cs = simple_strtoul(endp + 1, &endp, 0); - if (*endp != 0) - goto usage; - } - if (argc >= 3) { - speed = simple_strtoul(argv[2], &endp, 0); - if (*argv[2] == 0 || *endp != 0) - goto usage; - } - if (argc >= 4) { - mode = simple_strtoul(argv[3], &endp, 16); - if (*argv[3] == 0 || *endp != 0) - goto usage; - } - if (!spi_cs_is_valid(bus, cs)) { - printf("Invalid SPI bus %u cs %u\n", bus, cs); - return 1; - } - - mmc = mmc_spi_init(bus, cs, speed, mode); - if (!mmc) { - printf("Failed to create MMC Device\n"); - return 1; - } - printf("%s: %d at %u:%u hz %u mode %u\n", mmc->cfg->name, - mmc->block_dev.devnum, bus, cs, speed, mode); - mmc_init(mmc); - return 0; - -usage: - return CMD_RET_USAGE; -} - -U_BOOT_CMD( - mmc_spi, 4, 0, do_mmc_spi, - "mmc_spi setup", - "[bus:]cs [hz] [mode] - setup mmc_spi device" -); diff --git a/include/configs/UCP1020.h b/include/configs/UCP1020.h index 268a41c82c6..6a01a904254 100644 --- a/include/configs/UCP1020.h +++ b/include/configs/UCP1020.h @@ -438,7 +438,6 @@ #ifdef CONFIG_MMC #define CONFIG_SYS_FSL_ESDHC_ADDR CONFIG_SYS_MPC85xx_ESDHC_ADDR -#define CONFIG_MMC_SPI #endif /* Misc Extra Settings */ diff --git a/include/mmc.h b/include/mmc.h index 032873c2ff9..0ef891f5c26 100644 --- a/include/mmc.h +++ b/include/mmc.h @@ -824,7 +824,6 @@ void mmc_set_preinit(struct mmc *mmc, int preinit); #else #define mmc_host_is_spi(mmc) 0 #endif -struct mmc *mmc_spi_init(uint bus, uint cs, uint speed, uint mode); void board_mmc_power_init(void); int board_mmc_init(bd_t *bis); From 8277171663084e20c0eca7c0b9681019f1a2a353 Mon Sep 17 00:00:00 2001 From: Ye Li Date: Thu, 11 Jul 2019 03:29:02 +0000 Subject: [PATCH 20/27] mmc: fsl_esdhc_imx: fix config check issue when building in SPL Should use CONFIG_IS_ENABLED not IS_ENABLED for clock and regulator drivers, CONFIG_IS_ENABLED will check the CONFIG_SPL_CLK and CONFIG_SPL_DM_REGULATOR when building SPL. Signed-off-by: Ye Li Reviewed-by: Bin Meng --- drivers/mmc/fsl_esdhc_imx.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/mmc/fsl_esdhc_imx.c b/drivers/mmc/fsl_esdhc_imx.c index c0d47ba3784..49382026f1e 100644 --- a/drivers/mmc/fsl_esdhc_imx.c +++ b/drivers/mmc/fsl_esdhc_imx.c @@ -146,7 +146,7 @@ struct fsl_esdhc_priv { u32 tuning_start_tap; u32 strobe_dll_delay_target; u32 signal_voltage; -#if IS_ENABLED(CONFIG_DM_REGULATOR) +#if CONFIG_IS_ENABLED(DM_REGULATOR) struct udevice *vqmmc_dev; struct udevice *vmmc_dev; #endif @@ -1515,7 +1515,7 @@ static int fsl_esdhc_probe(struct udevice *dev) init_clk_usdhc(dev->seq); - if (IS_ENABLED(CONFIG_CLK)) { + if (CONFIG_IS_ENABLED(CLK)) { /* Assigned clock already set clock */ ret = clk_get_by_name(dev, "per", &priv->per_clk); if (ret) { From 44acd492480f8c8047326f3cb02d3e4d3760ecd0 Mon Sep 17 00:00:00 2001 From: Peng Fan Date: Wed, 10 Jul 2019 14:43:07 +0800 Subject: [PATCH 21/27] mmc: support hs400 enhanced strobe mode eMMC 5.1+ supports HS400 Enhances Strobe mode without the need for tuning procedure. The flow is as following: - set HS_TIMIMG (Highspeed) - Host change freq to <= 52Mhz - set the bus width to Enhanced strobe and DDR8Bit(CMD6), EXT_CSD[183] = 0x86 instead of 0x80 - set HS_TIMING to 0x3 (HS400) - Host change freq to <= 200Mhz - Host select HS400 enhanced strobe complete Signed-off-by: Peng Fan --- drivers/mmc/Kconfig | 12 +++++++ drivers/mmc/mmc-uclass.c | 17 ++++++++++ drivers/mmc/mmc.c | 72 +++++++++++++++++++++++++++++++++++++++- include/mmc.h | 15 +++++++++ 4 files changed, 115 insertions(+), 1 deletion(-) diff --git a/drivers/mmc/Kconfig b/drivers/mmc/Kconfig index a4a6a6c085d..890ef358a00 100644 --- a/drivers/mmc/Kconfig +++ b/drivers/mmc/Kconfig @@ -135,6 +135,18 @@ config SPL_MMC_UHS_SUPPORT cards. The IO voltage must be switchable from 3.3v to 1.8v. The bus frequency can go up to 208MHz (SDR104) +config MMC_HS400_ES_SUPPORT + bool "enable HS400 Enhanced Strobe support" + help + The HS400 Enhanced Strobe mode is support by some eMMC. The bus + frequency is up to 200MHz. This mode does not tune the IO. + +config SPL_MMC_HS400_ES_SUPPORT + bool "enable HS400 Enhanced Strobe support in SPL" + help + The HS400 Enhanced Strobe mode is support by some eMMC. The bus + frequency is up to 200MHz. This mode does not tune the IO. + config MMC_HS400_SUPPORT bool "enable HS400 support" select MMC_HS200_SUPPORT diff --git a/drivers/mmc/mmc-uclass.c b/drivers/mmc/mmc-uclass.c index 9327c8302de..8bf63bbd9ca 100644 --- a/drivers/mmc/mmc-uclass.c +++ b/drivers/mmc/mmc-uclass.c @@ -105,6 +105,23 @@ int mmc_execute_tuning(struct mmc *mmc, uint opcode) } #endif +#if CONFIG_IS_ENABLED(MMC_HS400_ES_SUPPORT) +int dm_mmc_set_enhanced_strobe(struct udevice *dev) +{ + struct dm_mmc_ops *ops = mmc_get_ops(dev); + + if (ops->set_enhanced_strobe) + return ops->set_enhanced_strobe(dev); + + return -ENOTSUPP; +} + +int mmc_set_enhanced_strobe(struct mmc *mmc) +{ + return dm_mmc_set_enhanced_strobe(mmc->dev); +} +#endif + int mmc_of_parse(struct udevice *dev, struct mmc_config *cfg) { int val; diff --git a/drivers/mmc/mmc.c b/drivers/mmc/mmc.c index 2a1ba6e51dc..c9aa13b409a 100644 --- a/drivers/mmc/mmc.c +++ b/drivers/mmc/mmc.c @@ -148,6 +148,7 @@ const char *mmc_mode_name(enum bus_mode mode) [MMC_DDR_52] = "MMC DDR52 (52MHz)", [MMC_HS_200] = "HS200 (200MHz)", [MMC_HS_400] = "HS400 (200MHz)", + [MMC_HS_400_ES] = "HS400ES (200MHz)", }; if (mode >= MMC_MODES_END) @@ -173,6 +174,7 @@ static uint mmc_mode2freq(struct mmc *mmc, enum bus_mode mode) [UHS_SDR104] = 208000000, [MMC_HS_200] = 200000000, [MMC_HS_400] = 200000000, + [MMC_HS_400_ES] = 200000000, }; if (mode == MMC_LEGACY) @@ -838,6 +840,11 @@ static int mmc_set_card_speed(struct mmc *mmc, enum bus_mode mode, case MMC_HS_400: speed_bits = EXT_CSD_TIMING_HS400; break; +#endif +#if CONFIG_IS_ENABLED(MMC_HS400_ES_SUPPORT) + case MMC_HS_400_ES: + speed_bits = EXT_CSD_TIMING_HS400; + break; #endif case MMC_LEGACY: speed_bits = EXT_CSD_TIMING_LEGACY; @@ -909,7 +916,8 @@ static int mmc_get_capabilities(struct mmc *mmc) mmc->card_caps |= MMC_MODE_HS200; } #endif -#if CONFIG_IS_ENABLED(MMC_HS400_SUPPORT) +#if CONFIG_IS_ENABLED(MMC_HS400_SUPPORT) || \ + CONFIG_IS_ENABLED(MMC_HS400_ES_SUPPORT) if (cardtype & (EXT_CSD_CARD_TYPE_HS400_1_2V | EXT_CSD_CARD_TYPE_HS400_1_8V)) { mmc->card_caps |= MMC_MODE_HS400; @@ -923,6 +931,13 @@ static int mmc_get_capabilities(struct mmc *mmc) if (cardtype & EXT_CSD_CARD_TYPE_26) mmc->card_caps |= MMC_MODE_HS; +#if CONFIG_IS_ENABLED(MMC_HS400_ES_SUPPORT) + if (ext_csd[EXT_CSD_STROBE_SUPPORT] && + (mmc->card_caps & MMC_MODE_HS400)) { + mmc->card_caps |= MMC_MODE_HS400_ES; + } +#endif + return 0; } #endif @@ -1799,6 +1814,7 @@ static int mmc_set_lowest_voltage(struct mmc *mmc, enum bus_mode mode, u32 card_mask = 0; switch (mode) { + case MMC_HS_400_ES: case MMC_HS_400: case MMC_HS_200: if (mmc->cardtype & (EXT_CSD_CARD_TYPE_HS200_1_8V | @@ -1841,6 +1857,12 @@ static inline int mmc_set_lowest_voltage(struct mmc *mmc, enum bus_mode mode, #endif static const struct mode_width_tuning mmc_modes_by_pref[] = { +#if CONFIG_IS_ENABLED(MMC_HS400_ES_SUPPORT) + { + .mode = MMC_HS_400_ES, + .widths = MMC_MODE_8BIT, + }, +#endif #if CONFIG_IS_ENABLED(MMC_HS400_SUPPORT) { .mode = MMC_HS_400, @@ -1938,6 +1960,47 @@ static int mmc_select_hs400(struct mmc *mmc) } #endif +#if CONFIG_IS_ENABLED(MMC_HS400_ES_SUPPORT) +#if !CONFIG_IS_ENABLED(DM_MMC) +static int mmc_set_enhanced_strobe(struct mmc *mmc) +{ + return -ENOTSUPP; +} +#endif +static int mmc_select_hs400es(struct mmc *mmc) +{ + int err; + + err = mmc_set_card_speed(mmc, MMC_HS, true); + if (err) + return err; + + err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL, EXT_CSD_BUS_WIDTH, + EXT_CSD_BUS_WIDTH_8 | EXT_CSD_DDR_FLAG | + EXT_CSD_BUS_WIDTH_STROBE); + if (err) { + printf("switch to bus width for hs400 failed\n"); + return err; + } + /* TODO: driver strength */ + err = mmc_set_card_speed(mmc, MMC_HS_400_ES, false); + if (err) + return err; + + mmc_select_mode(mmc, MMC_HS_400_ES); + err = mmc_set_clock(mmc, mmc->tran_speed, false); + if (err) + return err; + + return mmc_set_enhanced_strobe(mmc); +} +#else +static int mmc_select_hs400es(struct mmc *mmc) +{ + return -ENOTSUPP; +} +#endif + #define for_each_supported_width(caps, ddr, ecbv) \ for (ecbv = ext_csd_bus_width;\ ecbv < ext_csd_bus_width + ARRAY_SIZE(ext_csd_bus_width);\ @@ -2016,6 +2079,13 @@ static int mmc_select_mode_and_width(struct mmc *mmc, uint card_caps) printf("Select HS400 failed %d\n", err); goto error; } + } else if (mwt->mode == MMC_HS_400_ES) { + err = mmc_select_hs400es(mmc); + if (err) { + printf("Select HS400ES failed %d\n", + err); + goto error; + } } else { /* configure the bus speed (card) */ err = mmc_set_card_speed(mmc, mwt->mode, false); diff --git a/include/mmc.h b/include/mmc.h index 0ef891f5c26..46422f41a48 100644 --- a/include/mmc.h +++ b/include/mmc.h @@ -65,6 +65,7 @@ #define MMC_MODE_DDR_52MHz MMC_CAP(MMC_DDR_52) #define MMC_MODE_HS200 MMC_CAP(MMC_HS_200) #define MMC_MODE_HS400 MMC_CAP(MMC_HS_400) +#define MMC_MODE_HS400_ES MMC_CAP(MMC_HS_400_ES) #define MMC_CAP_NONREMOVABLE BIT(14) #define MMC_CAP_NEEDS_POLL BIT(15) @@ -223,6 +224,7 @@ static inline bool mmc_is_tuning_cmd(uint cmdidx) #define EXT_CSD_BOOT_BUS_WIDTH 177 #define EXT_CSD_PART_CONF 179 /* R/W */ #define EXT_CSD_BUS_WIDTH 183 /* R/W */ +#define EXT_CSD_STROBE_SUPPORT 184 /* R/W */ #define EXT_CSD_HS_TIMING 185 /* R/W */ #define EXT_CSD_REV 192 /* RO */ #define EXT_CSD_CARD_TYPE 196 /* RO */ @@ -266,11 +268,13 @@ static inline bool mmc_is_tuning_cmd(uint cmdidx) #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 EXT_CSD_BUS_WIDTH_STROBE BIT(7) /* Enhanced strobe mode */ #define EXT_CSD_TIMING_LEGACY 0 /* no high speed */ #define EXT_CSD_TIMING_HS 1 /* HS */ #define EXT_CSD_TIMING_HS200 2 /* HS200 */ #define EXT_CSD_TIMING_HS400 3 /* HS400 */ +#define EXT_CSD_DRV_STR_SHIFT 4 /* Driver Strength shift */ #define EXT_CSD_BOOT_ACK_ENABLE (1 << 6) #define EXT_CSD_BOOT_PARTITION_ENABLE (1 << 3) @@ -457,6 +461,11 @@ struct dm_mmc_ops { * @return 0 if dat0 is in the target state, -ve on error */ int (*wait_dat0)(struct udevice *dev, int state, int timeout); + +#if CONFIG_IS_ENABLED(MMC_HS400_ES_SUPPORT) + /* set_enhanced_strobe() - set HS400 enhanced strobe */ + int (*set_enhanced_strobe)(struct udevice *dev); +#endif }; #define mmc_get_ops(dev) ((struct dm_mmc_ops *)(dev)->driver->ops) @@ -475,6 +484,7 @@ int mmc_getcd(struct mmc *mmc); int mmc_getwp(struct mmc *mmc); int mmc_execute_tuning(struct mmc *mmc, uint opcode); int mmc_wait_dat0(struct mmc *mmc, int state, int timeout); +int mmc_set_enhanced_strobe(struct mmc *mmc); #else struct mmc_ops { @@ -520,6 +530,7 @@ enum bus_mode { UHS_SDR104, MMC_HS_200, MMC_HS_400, + MMC_HS_400_ES, MMC_MODES_END }; @@ -537,6 +548,10 @@ static inline bool mmc_is_mode_ddr(enum bus_mode mode) #if CONFIG_IS_ENABLED(MMC_HS400_SUPPORT) else if (mode == MMC_HS_400) return true; +#endif +#if CONFIG_IS_ENABLED(MMC_HS400_ES_SUPPORT) + else if (mode == MMC_HS_400_ES) + return true; #endif else return false; From b0fc3127bd22fc8d1185163e42f6a8457e5ca32c Mon Sep 17 00:00:00 2001 From: Peng Fan Date: Wed, 10 Jul 2019 09:35:18 +0000 Subject: [PATCH 22/27] mmc: Parse HS400 Enhanced strobe DT properties Add HS400 Enhanced strobe properties parsing support to mmc_of_parse(). Signed-off-by: Peng Fan Reviewed-by: Jean-Jacques Hiblot Cc: Marek Vasut --- drivers/mmc/mmc-uclass.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/mmc/mmc-uclass.c b/drivers/mmc/mmc-uclass.c index 8bf63bbd9ca..d4db4c85791 100644 --- a/drivers/mmc/mmc-uclass.c +++ b/drivers/mmc/mmc-uclass.c @@ -172,6 +172,8 @@ int mmc_of_parse(struct udevice *dev, struct mmc_config *cfg) cfg->host_caps |= MMC_CAP(MMC_HS_400); if (dev_read_bool(dev, "mmc-hs400-1_2v")) cfg->host_caps |= MMC_CAP(MMC_HS_400); + if (dev_read_bool(dev, "mmc-hs400-enhanced-strobe")) + cfg->host_caps |= MMC_CAP(MMC_HS_400_ES); if (dev_read_bool(dev, "non-removable")) { cfg->host_caps |= MMC_CAP_NONREMOVABLE; From 479a8dd6dc2ca9223514289ed2aa11c659197594 Mon Sep 17 00:00:00 2001 From: Peng Fan Date: Wed, 10 Jul 2019 09:35:20 +0000 Subject: [PATCH 23/27] mmc: Parse no-1-8-v DT property Parse no-1-8-v DT Signed-off-by: Peng Fan Reviewed-by: Jean-Jacques Hiblot Cc: Marek Vasut --- drivers/mmc/mmc-uclass.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/drivers/mmc/mmc-uclass.c b/drivers/mmc/mmc-uclass.c index d4db4c85791..551007905c3 100644 --- a/drivers/mmc/mmc-uclass.c +++ b/drivers/mmc/mmc-uclass.c @@ -184,6 +184,11 @@ int mmc_of_parse(struct udevice *dev, struct mmc_config *cfg) cfg->host_caps |= MMC_CAP_NEEDS_POLL; } + if (dev_read_bool(dev, "no-1-8-v")) { + cfg->host_caps &= ~(UHS_CAPS | MMC_MODE_HS200 | + MMC_MODE_HS400 | MMC_MODE_HS400_ES); + } + return 0; } From b0155ac63ce97a73183a6deae1559fb3baa3f61f Mon Sep 17 00:00:00 2001 From: Peng Fan Date: Wed, 10 Jul 2019 09:35:24 +0000 Subject: [PATCH 24/27] mmc: fsl_esdhc_imx: use mmc_of_parse to set host_caps Use mmc_of_parse to set host_caps. Signed-off-by: Peng Fan --- drivers/mmc/fsl_esdhc_imx.c | 14 +++++--------- 1 file changed, 5 insertions(+), 9 deletions(-) diff --git a/drivers/mmc/fsl_esdhc_imx.c b/drivers/mmc/fsl_esdhc_imx.c index 49382026f1e..0d2587982cd 100644 --- a/drivers/mmc/fsl_esdhc_imx.c +++ b/drivers/mmc/fsl_esdhc_imx.c @@ -101,7 +101,6 @@ struct fsl_esdhc_plat { struct esdhc_soc_data { u32 flags; - u32 caps; }; /** @@ -1426,10 +1425,8 @@ static int fsl_esdhc_probe(struct udevice *dev) priv->esdhc_regs = (struct fsl_esdhc *)addr; priv->dev = dev; priv->mode = -1; - if (data) { + if (data) priv->flags = data->flags; - priv->caps = data->caps; - } val = dev_read_u32_default(dev, "bus-width", -1); if (val == 8) @@ -1490,9 +1487,6 @@ static int fsl_esdhc_probe(struct udevice *dev) } #endif - if (fdt_get_property(fdt, node, "no-1-8-v", NULL)) - priv->caps &= ~(UHS_CAPS | MMC_MODE_HS200 | MMC_MODE_HS400); - /* * TODO: * Because lack of clk driver, if SDHC clk is not enabled, @@ -1543,6 +1537,10 @@ static int fsl_esdhc_probe(struct udevice *dev) return ret; } + ret = mmc_of_parse(dev, &plat->cfg); + if (ret) + return ret; + mmc = &plat->mmc; mmc->cfg = &plat->cfg; mmc->dev = dev; @@ -1610,8 +1608,6 @@ static struct esdhc_soc_data usdhc_imx7d_data = { .flags = ESDHC_FLAG_USDHC | ESDHC_FLAG_STD_TUNING | ESDHC_FLAG_HAVE_CAP1 | ESDHC_FLAG_HS200 | ESDHC_FLAG_HS400, - .caps = UHS_CAPS | MMC_MODE_HS200 | MMC_MODE_DDR_52MHz | - MMC_MODE_HS_52MHz | MMC_MODE_HS, }; static const struct udevice_id fsl_esdhc_ids[] = { From e9c22552675ec90258da1b60819baf5bea36f1c1 Mon Sep 17 00:00:00 2001 From: Peng Fan Date: Wed, 10 Jul 2019 09:35:26 +0000 Subject: [PATCH 25/27] mmc: fsl_esdhc_imx: add HS400 Enhanced strobe support Implement set_enhanced_strobe hook for fsl_esdhc_imx, ,in esdhc_set_timing and esdhc_change_pinstate, also handle HS400_ES. Signed-off-by: Peng Fan --- drivers/mmc/fsl_esdhc_imx.c | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/drivers/mmc/fsl_esdhc_imx.c b/drivers/mmc/fsl_esdhc_imx.c index 0d2587982cd..51d22256522 100644 --- a/drivers/mmc/fsl_esdhc_imx.c +++ b/drivers/mmc/fsl_esdhc_imx.c @@ -703,6 +703,7 @@ static int esdhc_change_pinstate(struct udevice *dev) case UHS_SDR104: case MMC_HS_200: case MMC_HS_400: + case MMC_HS_400_ES: ret = pinctrl_select_state(dev, "state_200mhz"); break; default: @@ -773,6 +774,7 @@ static int esdhc_set_timing(struct mmc *mmc) writel(mixctrl, ®s->mixctrl); break; case MMC_HS_400: + case MMC_HS_400_ES: mixctrl |= MIX_CTRL_DDREN | MIX_CTRL_HS400_EN; writel(mixctrl, ®s->mixctrl); esdhc_set_strobe_dll(mmc); @@ -1594,6 +1596,21 @@ static int fsl_esdhc_set_ios(struct udevice *dev) return esdhc_set_ios_common(priv, &plat->mmc); } +#if CONFIG_IS_ENABLED(MMC_HS400_ES_SUPPORT) +static int fsl_esdhc_set_enhanced_strobe(struct udevice *dev) +{ + struct fsl_esdhc_priv *priv = dev_get_priv(dev); + struct fsl_esdhc *regs = priv->esdhc_regs; + u32 m; + + m = readl(®s->mixctrl); + m |= MIX_CTRL_HS400_ES; + writel(m, ®s->mixctrl); + + return 0; +} +#endif + static const struct dm_mmc_ops fsl_esdhc_ops = { .get_cd = fsl_esdhc_get_cd, .send_cmd = fsl_esdhc_send_cmd, @@ -1601,6 +1618,9 @@ static const struct dm_mmc_ops fsl_esdhc_ops = { #ifdef MMC_SUPPORTS_TUNING .execute_tuning = fsl_esdhc_execute_tuning, #endif +#if CONFIG_IS_ENABLED(MMC_HS400_ES_SUPPORT) + .set_enhanced_strobe = fsl_esdhc_set_enhanced_strobe, +#endif }; #endif From 609ba125c50545424ea946cd034069bec96b5da9 Mon Sep 17 00:00:00 2001 From: Peng Fan Date: Wed, 10 Jul 2019 09:35:28 +0000 Subject: [PATCH 26/27] mmc: fsl_esdhc_imx: add i.MX8QM compatible Add i.MX8QM compatible and soc data, the soc data is following Linux i.MX SDHC driver. Signed-off-by: Peng Fan --- drivers/mmc/fsl_esdhc_imx.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/drivers/mmc/fsl_esdhc_imx.c b/drivers/mmc/fsl_esdhc_imx.c index 51d22256522..2152d8aa3ae 100644 --- a/drivers/mmc/fsl_esdhc_imx.c +++ b/drivers/mmc/fsl_esdhc_imx.c @@ -1630,6 +1630,12 @@ static struct esdhc_soc_data usdhc_imx7d_data = { | ESDHC_FLAG_HS400, }; +static struct esdhc_soc_data usdhc_imx8qm_data = { + .flags = ESDHC_FLAG_USDHC | ESDHC_FLAG_STD_TUNING | + ESDHC_FLAG_HAVE_CAP1 | ESDHC_FLAG_HS200 | + ESDHC_FLAG_HS400 | ESDHC_FLAG_HS400_ES, +}; + static const struct udevice_id fsl_esdhc_ids[] = { { .compatible = "fsl,imx53-esdhc", }, { .compatible = "fsl,imx6ul-usdhc", }, @@ -1638,6 +1644,7 @@ static const struct udevice_id fsl_esdhc_ids[] = { { .compatible = "fsl,imx6q-usdhc", }, { .compatible = "fsl,imx7d-usdhc", .data = (ulong)&usdhc_imx7d_data,}, { .compatible = "fsl,imx7ulp-usdhc", }, + { .compatible = "fsl,imx8qm-usdhc", .data = (ulong)&usdhc_imx8qm_data,}, { .compatible = "fsl,esdhc", }, { /* sentinel */ } }; From 356f782c6ef9ec971d18662b82ddab25b0dc4fed Mon Sep 17 00:00:00 2001 From: Peng Fan Date: Wed, 10 Jul 2019 09:35:30 +0000 Subject: [PATCH 27/27] mmc: fsl_esdhc_imx: enlarge mmc timeout Flash system partition with fastboot will earse the partition firstly The 600ms timeout will fail on some SD Card. Enlarge it to 5s to make it works for most of sdcard Cc: guoyin.chen Signed-off-by: Peng Fan --- drivers/mmc/fsl_esdhc_imx.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/mmc/fsl_esdhc_imx.c b/drivers/mmc/fsl_esdhc_imx.c index 2152d8aa3ae..43106dec756 100644 --- a/drivers/mmc/fsl_esdhc_imx.c +++ b/drivers/mmc/fsl_esdhc_imx.c @@ -513,9 +513,9 @@ static int esdhc_send_cmd_common(struct fsl_esdhc_priv *priv, struct mmc *mmc, /* Workaround for ESDHC errata ENGcm03648 */ if (!data && (cmd->resp_type & MMC_RSP_BUSY)) { - int timeout = 6000; + int timeout = 50000; - /* Poll on DATA0 line for cmd with busy signal for 600 ms */ + /* Poll on DATA0 line for cmd with busy signal for 5000 ms */ while (timeout > 0 && !(esdhc_read32(®s->prsstat) & PRSSTAT_DAT0)) { udelay(100);