// SPDX-License-Identifier: GPL-2.0+
/*
* Copyright 2008, Freescale Semiconductor, Inc
+ * Copyright 2020 NXP
* Andy Fleming
*
* Based vaguely on the Linux code
#include <config.h>
#include <common.h>
+#include <blk.h>
#include <command.h>
#include <dm.h>
+#include <log.h>
#include <dm/device-internal.h>
#include <errno.h>
#include <mmc.h>
#include <part.h>
+#include <linux/bitops.h>
+#include <linux/delay.h>
#include <power/regulator.h>
#include <malloc.h>
#include <memalign.h>
#include <div64.h>
#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)
-static int mmc_select_mode_and_width(struct mmc *mmc, uint card_caps);
-#endif
#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)
+static int mmc_wait_dat0(struct mmc *mmc, int state, int timeout_us)
{
return -ENOSYS;
}
-#endif
__weak int board_mmc_getwp(struct mmc *mmc)
{
{
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)",
[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)
{
static const int freqs[] = {
[MMC_LEGACY] = 25000000,
- [SD_LEGACY] = 25000000,
[MMC_HS] = 26000000,
[SD_HS] = 50000000,
[MMC_HS_52] = 52000000,
[UHS_SDR104] = 208000000,
[MMC_HS_200] = 200000000,
[MMC_HS_400] = 200000000,
+ [MMC_HS_400_ES] = 200000000,
};
if (mode == MMC_LEGACY)
}
#endif
-int mmc_send_status(struct mmc *mmc, int timeout)
+/**
+ * mmc_send_cmd_retry() - send a command to the mmc device, retrying on error
+ *
+ * @dev: device to receive the command
+ * @cmd: command to send
+ * @data: additional data to send/receive
+ * @retries: how many times to retry; mmc_send_cmd is always called at least
+ * once
+ * @return 0 if ok, -ve on error
+ */
+static int mmc_send_cmd_retry(struct mmc *mmc, struct mmc_cmd *cmd,
+ struct mmc_data *data, uint retries)
+{
+ int ret;
+
+ do {
+ ret = mmc_send_cmd(mmc, cmd, data);
+ } while (ret && retries--);
+
+ return ret;
+}
+
+/**
+ * mmc_send_cmd_quirks() - send a command to the mmc device, retrying if a
+ * specific quirk is enabled
+ *
+ * @dev: device to receive the command
+ * @cmd: command to send
+ * @data: additional data to send/receive
+ * @quirk: retry only if this quirk is enabled
+ * @retries: how many times to retry; mmc_send_cmd is always called at least
+ * once
+ * @return 0 if ok, -ve on error
+ */
+static int mmc_send_cmd_quirks(struct mmc *mmc, struct mmc_cmd *cmd,
+ struct mmc_data *data, u32 quirk, uint retries)
+{
+ if (CONFIG_IS_ENABLED(MMC_QUIRKS) && mmc->quirks & quirk)
+ return mmc_send_cmd_retry(mmc, cmd, data, retries);
+ else
+ return mmc_send_cmd(mmc, cmd, data);
+}
+
+int mmc_send_status(struct mmc *mmc, unsigned int *status)
{
struct mmc_cmd cmd;
- int err, retries = 5;
+ int ret;
cmd.cmdidx = MMC_CMD_SEND_STATUS;
cmd.resp_type = MMC_RSP_R1;
if (!mmc_host_is_spi(mmc))
cmd.cmdarg = mmc->rca << 16;
+ ret = mmc_send_cmd_retry(mmc, &cmd, NULL, 4);
+ mmc_trace_state(mmc, &cmd);
+ if (!ret)
+ *status = cmd.response[0];
+
+ return ret;
+}
+
+int mmc_poll_for_busy(struct mmc *mmc, int timeout_ms)
+{
+ unsigned int status;
+ int err;
+
+ err = mmc_wait_dat0(mmc, 1, timeout_ms * 1000);
+ if (err != -ENOSYS)
+ return err;
+
while (1) {
- 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;
+ 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 (cmd.response[0] & MMC_STATUS_MASK) {
+ if (status & MMC_STATUS_MASK) {
#if !defined(CONFIG_SPL_BUILD) || defined(CONFIG_SPL_LIBCOMMON_SUPPORT)
- pr_err("Status Error: 0x%08x\n",
- cmd.response[0]);
+ pr_err("Status Error: 0x%08x\n", status);
#endif
- return -ECOMM;
- }
- } else if (--retries < 0)
- return err;
+ return -ECOMM;
+ }
- if (timeout-- <= 0)
+ if (timeout_ms-- <= 0)
break;
udelay(1000);
}
- mmc_trace_state(mmc, &cmd);
- 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
int mmc_set_blocklen(struct mmc *mmc, int len)
{
struct mmc_cmd cmd;
- int err;
if (mmc->ddr_mode)
return 0;
cmd.resp_type = MMC_RSP_R1;
cmd.cmdarg = len;
- err = mmc_send_cmd(mmc, &cmd, NULL);
-
-#ifdef CONFIG_MMC_QUIRKS
- if (err && (mmc->quirks & MMC_QUIRK_RETRY_SET_BLOCKLEN)) {
- int retries = 4;
- /*
- * It has been seen that SET_BLOCKLEN may fail on the first
- * attempt, let's try a few more time
- */
- do {
- err = mmc_send_cmd(mmc, &cmd, NULL);
- if (!err)
- break;
- } while (retries--);
- }
-#endif
-
- return err;
+ return mmc_send_cmd_quirks(mmc, &cmd, NULL,
+ MMC_QUIRK_RETRY_SET_BLOCKLEN, 4);
}
#ifdef MMC_SUPPORTS_TUNING
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
int dev_num = block_dev->devnum;
int err;
lbaint_t cur, blocks_todo = blkcnt;
+ uint b_max;
if (blkcnt == 0)
return 0;
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;
static int mmc_send_op_cond(struct mmc *mmc)
{
int err, i;
+ int timeout = 1000;
+ uint start;
/* Some cards seem to need this */
mmc_go_idle(mmc);
+ start = get_timer(0);
/* Asking to the card its capabilities */
- for (i = 0; i < 2; i++) {
+ for (i = 0; ; i++) {
err = mmc_send_op_cond_iter(mmc, i != 0);
if (err)
return err;
/* exit if not busy (flag seems to be inverted) */
if (mmc->ocr & OCR_BUSY)
break;
+
+ if (get_timer(start) > timeout)
+ return -ETIMEDOUT;
+ udelay(100);
}
mmc->op_cond_pending = 1;
return 0;
}
-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;
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 = 1000;
- int retries = 3;
+ int timeout_ms = DEFAULT_CMD6_TIMEOUT_MS;
+ bool is_part_switch = (set == EXT_CSD_CMD_SET_NORMAL) &&
+ (index == EXT_CSD_PART_CONF);
int ret;
+ if (mmc->gen_cmd6_time)
+ timeout_ms = mmc->gen_cmd6_time * 10;
+
+ if (is_part_switch && mmc->part_switch_time)
+ timeout_ms = mmc->part_switch_time * 10;
+
cmd.cmdidx = MMC_CMD_SWITCH;
cmd.resp_type = MMC_RSP_R1b;
cmd.cmdarg = (MMC_SWITCH_MODE_WRITE_BYTE << 24) |
(index << 16) |
(value << 8);
- while (retries > 0) {
- ret = mmc_send_cmd(mmc, &cmd, NULL);
+ ret = mmc_send_cmd_retry(mmc, &cmd, NULL, 3);
+ if (ret)
+ return ret;
- if (ret) {
- retries--;
- continue;
- }
+ start = get_timer(0);
- if (!send_status) {
- mdelay(50);
- return 0;
- }
+ /* poll dat0 for rdy/buys status */
+ ret = mmc_wait_dat0(mmc, 1, timeout_ms * 1000);
+ if (ret && ret != -ENOSYS)
+ return ret;
- /* Waiting for the ready status */
- return mmc_send_status(mmc, timeout);
+ /*
+ * 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_ms);
+ return 0;
}
- return ret;
+ /* 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' 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 (!ret && (status & MMC_STATUS_RDY_FOR_DATA))
+ return 0;
+ udelay(100);
+ } while (get_timer(start) < timeout_ms);
+
+ return -ETIMEDOUT;
}
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)
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;
break;
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;
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
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;
+ int retry = 3;
- 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));
+ 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
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
}
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;
cmd.resp_type = MMC_RSP_R1;
cmd.cmdarg = 0;
- timeout = 3;
-
-retry_scr:
data.dest = (char *)scr;
data.blocksize = 8;
data.blocks = 1;
data.flags = MMC_DATA_READ;
- err = mmc_send_cmd(mmc, &cmd, &data);
-
- if (err) {
- if (timeout--)
- goto retry_scr;
+ err = mmc_send_cmd_retry(mmc, &cmd, &data, 3);
+ if (err)
return err;
- }
mmc->scr[0] = __be32_to_cpu(scr[0]);
mmc->scr[1] = __be32_to_cpu(scr[1]);
return 0;
switch (mode) {
- case SD_LEGACY:
+ case MMC_LEGACY:
speed = UHS_SDR12_BUS_SPEED;
break;
case SD_HS:
struct mmc_cmd cmd;
ALLOC_CACHE_ALIGN_BUFFER(uint, ssr, 16);
struct mmc_data data;
- int timeout = 3;
unsigned int au, eo, et, es;
cmd.cmdidx = MMC_CMD_APP_CMD;
cmd.resp_type = MMC_RSP_R1;
cmd.cmdarg = mmc->rca << 16;
- err = mmc_send_cmd(mmc, &cmd, NULL);
+ err = mmc_send_cmd_quirks(mmc, &cmd, NULL, MMC_QUIRK_RETRY_APP_CMD, 4);
if (err)
return err;
cmd.resp_type = MMC_RSP_R1;
cmd.cmdarg = 0;
-retry_ssr:
data.dest = (char *)ssr;
data.blocksize = 64;
data.blocks = 1;
data.flags = MMC_DATA_READ;
- err = mmc_send_cmd(mmc, &cmd, &data);
- if (err) {
- if (timeout--)
- goto retry_ssr;
-
+ err = mmc_send_cmd_retry(mmc, &cmd, &data, 3);
+ if (err)
return err;
- }
for (i = 0; i < 16; i++)
ssr[i] = be32_to_cpu(ssr[i]);
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)
},
#endif
{
- .mode = SD_LEGACY,
+ .mode = MMC_LEGACY,
.widths = MMC_MODE_4BIT | MMC_MODE_1BIT,
}
};
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);
+#if CONFIG_IS_ENABLED(MMC_WRITE)
+ err = sd_read_ssr(mmc);
+ if (err)
+ pr_warn("unable to read ssr\n");
+#endif
+ return 0;
+ }
+
/* Restrict card's capabilities by what the host can do */
caps = card_caps & mmc->host_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);
}
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 |
#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,
mmc_set_clock(mmc, mmc->tran_speed, false);
/* execute tuning if needed */
+ mmc->hs400_tuning = 1;
err = mmc_execute_tuning(mmc, MMC_CMD_SEND_TUNING_BLOCK_HS200);
+ mmc->hs400_tuning = 0;
if (err) {
debug("tuning failed\n");
return err;
/* Set back to HS */
mmc_set_card_speed(mmc, MMC_HS, true);
+ err = mmc_hs400_prepare_ddr(mmc);
+ 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);
if (err)
}
#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);\
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;
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);
err = mmc_execute_tuning(mmc,
mwt->tuning);
if (err) {
- pr_debug("tuning failed\n");
+ pr_debug("tuning failed : %d\n", err);
goto error;
}
}
return 0;
error:
mmc_set_signal_voltage(mmc, old_voltage);
- /* if an error occured, revert to a safer bus mode */
+ /* if an error occurred, revert to a safer bus mode */
mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL,
EXT_CSD_BUS_WIDTH, EXT_CSD_BUS_WIDTH_1);
mmc_select_mode(mmc, MMC_LEGACY);
}
}
- pr_err("unable to select a mode\n");
+ pr_err("unable to select a mode : %d\n", err);
return -ENOTSUPP;
}
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,
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) ||
cmd.resp_type = MMC_RSP_R2;
cmd.cmdarg = 0;
- err = mmc_send_cmd(mmc, &cmd, NULL);
-
-#ifdef CONFIG_MMC_QUIRKS
- if (err && (mmc->quirks & MMC_QUIRK_RETRY_SEND_CID)) {
- int retries = 4;
- /*
- * It has been seen that SEND_CID may fail on the first
- * attempt, let's try a few more time
- */
- do {
- err = mmc_send_cmd(mmc, &cmd, NULL);
- if (!err)
- break;
- } while (retries--);
- }
-#endif
-
+ err = mmc_send_cmd_quirks(mmc, &cmd, NULL, MMC_QUIRK_RETRY_SEND_CID, 4);
if (err)
return err;
#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)) {
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)
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);
if (mmc->vmmc_supply) {
int ret = regulator_set_enable(mmc->vmmc_supply, true);
- if (ret) {
- puts("Error enabling VMMC supply\n");
+ if (ret && ret != -EACCES) {
+ printf("Error enabling VMMC supply : %d\n", ret);
return ret;
}
}
if (mmc->vmmc_supply) {
int ret = regulator_set_enable(mmc->vmmc_supply, false);
- if (ret) {
- pr_debug("Error disabling VMMC supply\n");
+ if (ret && ret != -EACCES) {
+ pr_debug("Error disabling VMMC supply : %d\n", ret);
return ret;
}
}
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.
if (mmc->has_init)
return 0;
-#ifdef CONFIG_FSL_ESDHC_ADAPTER_IDENT
- mmc_adapter_card_type_ident();
-#endif
err = mmc_power_init(mmc);
if (err)
return err;
#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);
return err;
#if CONFIG_IS_ENABLED(DM_MMC)
- /* The device has already been probed ready for use */
+ /*
+ * Re-initialization is needed to clear old configuration for
+ * mmc rescan.
+ */
+ err = mmc_reinit(mmc);
#else
/* made sure it's not NULL earlier */
err = mmc->cfg->ops->init(mmc);
+#endif
if (err)
return err;
-#endif
mmc->ddr_mode = 0;
retry:
if (err)
return err;
- /* The internal partition reset to user partition(0) at every CMD0*/
+ /* The internal partition reset to user partition(0) at every CMD0 */
mmc_get_blk_desc(mmc)->hwpart = 0;
/* Test for SD version 2 */
if (err) {
#if !defined(CONFIG_SPL_BUILD) || defined(CONFIG_SPL_LIBCOMMON_SUPPORT)
- pr_err("Card did not respond to voltage select!\n");
+ pr_err("Card did not respond to voltage select! : %d\n", err);
#endif
return -EOPNOTSUPP;
}
* 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) {
}
/* CPU-specific MMC initializations */
-__weak int cpu_mmc_init(bd_t *bis)
+__weak int cpu_mmc_init(struct bd_info *bis)
{
return -1;
}
/* board-specific MMC initializations. */
-__weak int board_mmc_init(bd_t *bis)
+__weak int board_mmc_init(struct bd_info *bis)
{
return -1;
}
}
#if CONFIG_IS_ENABLED(DM_MMC)
-static int mmc_probe(bd_t *bis)
+static int mmc_probe(struct bd_info *bis)
{
int ret, i;
struct uclass *uc;
return 0;
}
#else
-static int mmc_probe(bd_t *bis)
+static int mmc_probe(struct bd_info *bis)
{
if (board_mmc_init(bis) < 0)
cpu_mmc_init(bis);
}
#endif
-int mmc_initialize(bd_t *bis)
+int mmc_initialize(struct bd_info *bis)
{
static int initialized = 0;
int ret;
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;
+ if (m->preinit)
+ mmc_start_init(m);
+
+ return 0;
+}
+#endif
+
#ifdef CONFIG_CMD_BKOPS_ENABLE
int mmc_set_bkops_enable(struct mmc *mmc)
{
return 0;
}
#endif
+
+__weak int mmc_get_env_dev(void)
+{
+#ifdef CONFIG_SYS_MMC_ENV_DEV
+ return CONFIG_SYS_MMC_ENV_DEV;
+#else
+ return 0;
+#endif
+}