X-Git-Url: https://git.librecmc.org/?a=blobdiff_plain;f=drivers%2Fmmc%2Fmmc.c;h=02494db75a7d796a7779769b3a1ed14998f8c044;hb=c05ed00afb95fa5237f16962fccf5810437317bf;hp=c9aa13b409ac9d4a6ff7b63af4ac86646aa7e44c;hpb=6674dc77c2f735ec9bc02434626125698d2755ff;p=oweals%2Fu-boot.git diff --git a/drivers/mmc/mmc.c b/drivers/mmc/mmc.c index c9aa13b409..02494db75a 100644 --- a/drivers/mmc/mmc.c +++ b/drivers/mmc/mmc.c @@ -8,12 +8,15 @@ #include #include +#include #include #include +#include #include #include #include #include +#include #include #include #include @@ -24,14 +27,10 @@ #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) -static int mmc_select_mode_and_width(struct mmc *mmc, uint card_caps); -#endif #if !CONFIG_IS_ENABLED(DM_MMC) -static int mmc_wait_dat0(struct mmc *mmc, int state, int timeout) +static int mmc_wait_dat0(struct mmc *mmc, int state, int timeout_us) { return -ENOSYS; } @@ -136,7 +135,6 @@ const char *mmc_mode_name(enum bus_mode mode) { static const char *const names[] = { [MMC_LEGACY] = "MMC legacy", - [SD_LEGACY] = "SD Legacy", [MMC_HS] = "MMC High Speed (26MHz)", [SD_HS] = "SD High Speed (50MHz)", [UHS_SDR12] = "UHS SDR12 (25MHz)", @@ -162,7 +160,6 @@ static uint mmc_mode2freq(struct mmc *mmc, enum bus_mode mode) { static const int freqs[] = { [MMC_LEGACY] = 25000000, - [SD_LEGACY] = 25000000, [MMC_HS] = 26000000, [SD_HS] = 50000000, [MMC_HS_52] = 52000000, @@ -230,12 +227,12 @@ int mmc_send_status(struct mmc *mmc, unsigned int *status) return -ECOMM; } -int mmc_poll_for_busy(struct mmc *mmc, int timeout) +int mmc_poll_for_busy(struct mmc *mmc, int timeout_ms) { unsigned int status; int err; - err = mmc_wait_dat0(mmc, 1, timeout); + err = mmc_wait_dat0(mmc, 1, timeout_ms * 1000); if (err != -ENOSYS) return err; @@ -256,13 +253,13 @@ int mmc_poll_for_busy(struct mmc *mmc, int timeout) return -ECOMM; } - if (timeout-- <= 0) + if (timeout_ms-- <= 0) break; udelay(1000); } - if (timeout <= 0) { + if (timeout_ms <= 0) { #if !defined(CONFIG_SPL_BUILD) || defined(CONFIG_SPL_LIBCOMMON_SUPPORT) pr_err("Timeout waiting card ready\n"); #endif @@ -415,6 +412,16 @@ static int mmc_read_blocks(struct mmc *mmc, void *dst, lbaint_t start, return blkcnt; } +#if !CONFIG_IS_ENABLED(DM_MMC) +static int mmc_get_b_max(struct mmc *mmc, void *dst, lbaint_t blkcnt) +{ + if (mmc->cfg->ops->get_b_max) + return mmc->cfg->ops->get_b_max(mmc, dst, blkcnt); + else + return mmc->cfg->b_max; +} +#endif + #if CONFIG_IS_ENABLED(BLK) ulong mmc_bread(struct udevice *dev, lbaint_t start, lbaint_t blkcnt, void *dst) #else @@ -428,6 +435,7 @@ ulong mmc_bread(struct blk_desc *block_dev, lbaint_t start, lbaint_t blkcnt, int dev_num = block_dev->devnum; int err; lbaint_t cur, blocks_todo = blkcnt; + uint b_max; if (blkcnt == 0) return 0; @@ -457,9 +465,10 @@ ulong mmc_bread(struct blk_desc *block_dev, lbaint_t start, lbaint_t blkcnt, return 0; } + b_max = mmc_get_b_max(mmc, dst, blkcnt); + do { - cur = (blocks_todo > mmc->cfg->b_max) ? - mmc->cfg->b_max : blocks_todo; + cur = (blocks_todo > b_max) ? b_max : blocks_todo; if (mmc_read_blocks(mmc, dst, start, cur) != cur) { pr_debug("%s: Failed to read blocks\n", __func__); return 0; @@ -724,7 +733,7 @@ static int mmc_complete_op_cond(struct mmc *mmc) } -static int mmc_send_ext_csd(struct mmc *mmc, u8 *ext_csd) +int mmc_send_ext_csd(struct mmc *mmc, u8 *ext_csd) { struct mmc_cmd cmd; struct mmc_data data; @@ -750,17 +759,17 @@ static int __mmc_switch(struct mmc *mmc, u8 set, u8 index, u8 value, { unsigned int status, start; struct mmc_cmd cmd; - int timeout = DEFAULT_CMD6_TIMEOUT_MS; + int timeout_ms = 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; + timeout_ms = mmc->gen_cmd6_time * 10; if (is_part_switch && mmc->part_switch_time) - timeout = mmc->part_switch_time * 10; + timeout_ms = mmc->part_switch_time * 10; cmd.cmdidx = MMC_CMD_SWITCH; cmd.resp_type = MMC_RSP_R1b; @@ -778,7 +787,7 @@ static int __mmc_switch(struct mmc *mmc, u8 set, u8 index, u8 value, start = get_timer(0); /* poll dat0 for rdy/buys status */ - ret = mmc_wait_dat0(mmc, 1, timeout); + ret = mmc_wait_dat0(mmc, 1, timeout_ms * 1000); if (ret && ret != -ENOSYS) return ret; @@ -788,11 +797,11 @@ static int __mmc_switch(struct mmc *mmc, u8 set, u8 index, u8 value, * stated timeout to be sufficient. */ if (ret == -ENOSYS && !send_status) - mdelay(timeout); + mdelay(timeout_ms); /* 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 + * is false, because by now (after 'timeout_ms' ms) the bus should be * reliable. */ do { @@ -806,7 +815,7 @@ static int __mmc_switch(struct mmc *mmc, u8 set, u8 index, u8 value, if (!ret && (status & MMC_STATUS_RDY_FOR_DATA)) return 0; udelay(100); - } while (get_timer(start) < timeout); + } while (get_timer(start) < timeout_ms); return -ETIMEDOUT; } @@ -816,6 +825,11 @@ int mmc_switch(struct mmc *mmc, u8 set, u8 index, u8 value) return __mmc_switch(mmc, set, index, value, true); } +int mmc_boot_wp(struct mmc *mmc) +{ + return mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL, EXT_CSD_BOOT_WP, 1); +} + #if !CONFIG_IS_ENABLED(MMC_TINY) static int mmc_set_card_speed(struct mmc *mmc, enum bus_mode mode, bool hsdowngrade) @@ -1126,9 +1140,11 @@ int mmc_hwpart_config(struct mmc *mmc, ext_csd[EXT_CSD_ERASE_GROUP_DEF] = 1; +#if CONFIG_IS_ENABLED(MMC_WRITE) /* update erase group size to be high-capacity */ mmc->erase_grp_size = ext_csd[EXT_CSD_HC_ERASE_GRP_SIZE] * 1024; +#endif } @@ -1241,7 +1257,7 @@ static int sd_get_capabilities(struct mmc *mmc) u32 sd3_bus_mode; #endif - mmc->card_caps = MMC_MODE_1BIT | MMC_CAP(SD_LEGACY); + mmc->card_caps = MMC_MODE_1BIT | MMC_CAP(MMC_LEGACY); if (mmc_host_is_spi(mmc)) return 0; @@ -1354,7 +1370,7 @@ static int sd_set_card_speed(struct mmc *mmc, enum bus_mode mode) return 0; switch (mode) { - case SD_LEGACY: + case MMC_LEGACY: speed = UHS_SDR12_BUS_SPEED; break; case SD_HS: @@ -1444,6 +1460,20 @@ static int sd_read_ssr(struct mmc *mmc) cmd.cmdarg = mmc->rca << 16; err = mmc_send_cmd(mmc, &cmd, NULL); +#ifdef CONFIG_MMC_QUIRKS + if (err && (mmc->quirks & MMC_QUIRK_RETRY_APP_CMD)) { + int retries = 4; + /* + * It has been seen that APP_CMD may fail on the first + * attempt, let's try a few more times + */ + do { + err = mmc_send_cmd(mmc, &cmd, NULL); + if (!err) + break; + } while (retries--); + } +#endif if (err) return err; @@ -1546,6 +1576,16 @@ static int mmc_set_ios(struct mmc *mmc) return ret; } + +static int mmc_host_power_cycle(struct mmc *mmc) +{ + int ret = 0; + + if (mmc->cfg->ops->host_power_cycle) + ret = mmc->cfg->ops->host_power_cycle(mmc); + + return ret; +} #endif int mmc_set_clock(struct mmc *mmc, uint clock, bool disable) @@ -1673,7 +1713,7 @@ static const struct mode_width_tuning sd_modes_by_pref[] = { }, #endif { - .mode = SD_LEGACY, + .mode = MMC_LEGACY, .widths = MMC_MODE_4BIT | MMC_MODE_1BIT, } }; @@ -1703,7 +1743,7 @@ static int sd_select_mode_and_width(struct mmc *mmc, uint card_caps) if (mmc_host_is_spi(mmc)) { mmc_set_bus_width(mmc, 1); - mmc_select_mode(mmc, SD_LEGACY); + mmc_select_mode(mmc, MMC_LEGACY); mmc_set_clock(mmc, mmc->tran_speed, MMC_CLK_ENABLE); return 0; } @@ -1762,7 +1802,7 @@ static int sd_select_mode_and_width(struct mmc *mmc, uint card_caps) error: /* revert to a safer bus speed */ - mmc_select_mode(mmc, SD_LEGACY); + mmc_select_mode(mmc, MMC_LEGACY); mmc_set_clock(mmc, mmc->tran_speed, MMC_CLK_ENABLE); } @@ -2539,7 +2579,7 @@ static int mmc_startup(struct mmc *mmc) #if CONFIG_IS_ENABLED(MMC_TINY) mmc_set_clock(mmc, mmc->legacy_speed, false); - mmc_select_mode(mmc, IS_SD(mmc) ? SD_LEGACY : MMC_LEGACY); + mmc_select_mode(mmc, MMC_LEGACY); mmc_set_bus_width(mmc, 1); #else if (IS_SD(mmc)) { @@ -2551,7 +2591,7 @@ static int mmc_startup(struct mmc *mmc) err = mmc_get_capabilities(mmc); if (err) return err; - mmc_select_mode_and_width(mmc, mmc->card_caps); + err = mmc_select_mode_and_width(mmc, mmc->card_caps); } #endif if (err) @@ -2577,7 +2617,7 @@ static int mmc_startup(struct mmc *mmc) bdesc->lba = lldiv(mmc->capacity, mmc->read_bl_len); #if !defined(CONFIG_SPL_BUILD) || \ (defined(CONFIG_SPL_LIBCOMMON_SUPPORT) && \ - !defined(CONFIG_USE_TINY_PRINTF)) + !CONFIG_IS_ENABLED(USE_TINY_PRINTF)) sprintf(bdesc->vendor, "Man %06x Snr %04x%04x", mmc->cid[0] >> 24, (mmc->cid[2] & 0xffff), (mmc->cid[3] >> 16) & 0xffff); @@ -2715,6 +2755,11 @@ static int mmc_power_cycle(struct mmc *mmc) ret = mmc_power_off(mmc); if (ret) return ret; + + ret = mmc_host_power_cycle(mmc); + if (ret) + return ret; + /* * SD spec recommends at least 1ms of delay. Let's wait for 2ms * to be on the safer side. @@ -2740,7 +2785,8 @@ int mmc_get_op_cond(struct mmc *mmc) #ifdef CONFIG_MMC_QUIRKS mmc->quirks = MMC_QUIRK_RETRY_SET_BLOCKLEN | - MMC_QUIRK_RETRY_SEND_CID; + MMC_QUIRK_RETRY_SEND_CID | + MMC_QUIRK_RETRY_APP_CMD; #endif err = mmc_power_cycle(mmc); @@ -2815,16 +2861,18 @@ int mmc_start_init(struct mmc *mmc) * all hosts are capable of 1 bit bus-width and able to use the legacy * timings. */ - mmc->host_caps = mmc->cfg->host_caps | MMC_CAP(SD_LEGACY) | + mmc->host_caps = mmc->cfg->host_caps | MMC_CAP(MMC_LEGACY) | MMC_CAP(MMC_LEGACY) | MMC_MODE_1BIT; - +#if CONFIG_IS_ENABLED(DM_MMC) + mmc_deferred_probe(mmc); +#endif #if !defined(CONFIG_MMC_BROKEN_CD) - /* we pretend there's no card when init is NULL */ no_card = mmc_getcd(mmc) == 0; #else no_card = 0; #endif #if !CONFIG_IS_ENABLED(DM_MMC) + /* we pretend there's no card when init is NULL */ no_card = no_card || (mmc->cfg->ops->init == NULL); #endif if (no_card) { @@ -2998,6 +3046,30 @@ int mmc_initialize(bd_t *bis) return 0; } +#if CONFIG_IS_ENABLED(DM_MMC) +int mmc_init_device(int num) +{ + struct udevice *dev; + struct mmc *m; + int ret; + + ret = uclass_get_device(UCLASS_MMC, num, &dev); + if (ret) + return ret; + + m = mmc_get_mmc_dev(dev); + if (!m) + return 0; +#ifdef CONFIG_FSL_ESDHC_ADAPTER_IDENT + mmc_set_preinit(m, 1); +#endif + if (m->preinit) + mmc_start_init(m); + + return 0; +} +#endif + #ifdef CONFIG_CMD_BKOPS_ENABLE int mmc_set_bkops_enable(struct mmc *mmc) {