#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)
{
void mmmc_trace_before_send(struct mmc *mmc, struct mmc_cmd *cmd)
{
printf("CMD_SEND:%d\n", cmd->cmdidx);
- printf("\t\tARG\t\t\t 0x%08X\n", cmd->cmdarg);
+ printf("\t\tARG\t\t\t 0x%08x\n", cmd->cmdarg);
}
void mmmc_trace_after_send(struct mmc *mmc, struct mmc_cmd *cmd, int ret)
printf("\t\tMMC_RSP_NONE\n");
break;
case MMC_RSP_R1:
- printf("\t\tMMC_RSP_R1,5,6,7 \t 0x%08X \n",
+ printf("\t\tMMC_RSP_R1,5,6,7 \t 0x%08x \n",
cmd->response[0]);
break;
case MMC_RSP_R1b:
- printf("\t\tMMC_RSP_R1b\t\t 0x%08X \n",
+ printf("\t\tMMC_RSP_R1b\t\t 0x%08x \n",
cmd->response[0]);
break;
case MMC_RSP_R2:
- printf("\t\tMMC_RSP_R2\t\t 0x%08X \n",
+ printf("\t\tMMC_RSP_R2\t\t 0x%08x \n",
cmd->response[0]);
- printf("\t\t \t\t 0x%08X \n",
+ printf("\t\t \t\t 0x%08x \n",
cmd->response[1]);
- printf("\t\t \t\t 0x%08X \n",
+ printf("\t\t \t\t 0x%08x \n",
cmd->response[2]);
- printf("\t\t \t\t 0x%08X \n",
+ printf("\t\t \t\t 0x%08x \n",
cmd->response[3]);
printf("\n");
printf("\t\t\t\t\tDUMPING DATA\n");
ptr = (u8 *)&cmd->response[i];
ptr += 3;
for (j = 0; j < 4; j++)
- printf("%02X ", *ptr--);
+ printf("%02x ", *ptr--);
printf("\n");
}
break;
case MMC_RSP_R3:
- printf("\t\tMMC_RSP_R3,4\t\t 0x%08X \n",
+ printf("\t\tMMC_RSP_R3,4\t\t 0x%08x \n",
cmd->response[0]);
break;
default:
{
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)
+int mmc_send_status(struct mmc *mmc, unsigned int *status)
{
struct mmc_cmd cmd;
int err, retries = 5;
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) {
+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_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",
- 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
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;
return err;
}
-int mmc_switch(struct mmc *mmc, u8 set, u8 index, u8 value)
+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 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_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) {
+ do {
ret = mmc_send_cmd(mmc, &cmd, NULL);
+ } while (ret && retries-- > 0);
- /* Waiting for the ready status */
- if (!ret) {
- ret = mmc_send_status(mmc, timeout);
- return ret;
+ if (ret)
+ return ret;
+
+ start = get_timer(0);
+
+ /* poll dat0 for rdy/buys status */
+ ret = mmc_wait_dat0(mmc, 1, timeout_ms * 1000);
+ 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_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' 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);
- retries--;
- }
+ return -ETIMEDOUT;
+}
- return ret;
+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)
+static int mmc_set_card_speed(struct mmc *mmc, enum bus_mode mode,
+ bool hsdowngrade)
{
int err;
int speed_bits;
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;
default:
return -EINVAL;
}
- err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL, EXT_CSD_HS_TIMING,
- speed_bits);
+
+ err = __mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL, EXT_CSD_HS_TIMING,
+ speed_bits, !hsdowngrade);
if (err)
return err;
+#if CONFIG_IS_ENABLED(MMC_HS200_SUPPORT) || \
+ CONFIG_IS_ENABLED(MMC_HS400_SUPPORT)
+ /*
+ * In case the eMMC is in HS200/HS400 mode and we are downgrading
+ * to HS mode, the card clock are still running much faster than
+ * the supported HS mode clock, so we can not reliably read out
+ * Extended CSD. Reconfigure the controller to run at HS mode.
+ */
+ if (hsdowngrade) {
+ mmc_select_mode(mmc, MMC_HS);
+ mmc_set_clock(mmc, mmc_mode2freq(mmc, MMC_HS), false);
+ }
+#endif
+
if ((mode == MMC_HS) || (mode == MMC_HS_52)) {
/* Now check to see that it worked */
err = mmc_send_ext_csd(mmc, test_csd);
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)
-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);
-
- 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;
return 0;
switch (mode) {
- case SD_LEGACY:
+ case MMC_LEGACY:
speed = UHS_SDR12_BUS_SPEED;
break;
case SD_HS:
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;
}
#endif
-static void mmc_send_init_stream(struct mmc *mmc)
-{
-}
-
static int mmc_set_ios(struct mmc *mmc)
{
int ret = 0;
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);
+ 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,
int err;
/* Set timing to HS200 for tuning */
- err = mmc_set_card_speed(mmc, MMC_HS_200);
+ err = mmc_set_card_speed(mmc, MMC_HS_200, false);
if (err)
return err;
}
/* Set back to HS */
- mmc_set_card_speed(mmc, MMC_HS);
- mmc_set_clock(mmc, mmc_mode2freq(mmc, MMC_HS), false);
+ mmc_set_card_speed(mmc, MMC_HS, true);
err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL, EXT_CSD_BUS_WIDTH,
EXT_CSD_BUS_WIDTH_8 | EXT_CSD_DDR_FLAG);
if (err)
return err;
- err = mmc_set_card_speed(mmc, MMC_HS_400);
+ err = mmc_set_card_speed(mmc, MMC_HS_400, false);
if (err)
return 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;
return -ENOTSUPP;
}
- mmc_set_clock(mmc, mmc->legacy_speed, MMC_CLK_ENABLE);
+#if CONFIG_IS_ENABLED(MMC_HS200_SUPPORT) || \
+ CONFIG_IS_ENABLED(MMC_HS400_SUPPORT)
+ /*
+ * In case the eMMC is in HS200/HS400 mode, downgrade to HS mode
+ * before doing anything else, since a transition from either of
+ * the HS200/HS400 mode directly to legacy mode is not supported.
+ */
+ if (mmc->selected_mode == MMC_HS_200 ||
+ mmc->selected_mode == MMC_HS_400)
+ mmc_set_card_speed(mmc, MMC_HS, true);
+ else
+#endif
+ mmc_set_clock(mmc, mmc->legacy_speed, MMC_CLK_ENABLE);
for_each_mmc_mode_by_pref(card_caps, mwt) {
for_each_supported_width(card_caps & mwt->widths,
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);
+ err = mmc_set_card_speed(mmc, mwt->mode, false);
if (err)
goto error;
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) ||
#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);
bdesc->revision[0] = 0;
#endif
+#if !defined(CONFIG_DM_MMC) && (!defined(CONFIG_SPL_BUILD) || defined(CONFIG_SPL_LIBDISK_SUPPORT))
+ part_init(bdesc);
+#endif
+
return 0;
}
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.
#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);
retry:
mmc_set_initial_state(mmc);
- mmc_send_init_stream(mmc);
/* Reset the Card */
err = mmc_go_idle(mmc);
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 */
* 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) {
return err;
}
+#if CONFIG_IS_ENABLED(MMC_UHS_SUPPORT) || \
+ CONFIG_IS_ENABLED(MMC_HS200_SUPPORT) || \
+ CONFIG_IS_ENABLED(MMC_HS400_SUPPORT)
+int mmc_deinit(struct mmc *mmc)
+{
+ u32 caps_filtered;
+
+ if (!mmc->has_init)
+ return 0;
+
+ if (IS_SD(mmc)) {
+ caps_filtered = mmc->card_caps &
+ ~(MMC_CAP(UHS_SDR12) | MMC_CAP(UHS_SDR25) |
+ MMC_CAP(UHS_SDR50) | MMC_CAP(UHS_DDR50) |
+ MMC_CAP(UHS_SDR104));
+
+ return sd_select_mode_and_width(mmc, caps_filtered);
+ } else {
+ caps_filtered = mmc->card_caps &
+ ~(MMC_CAP(MMC_HS_200) | MMC_CAP(MMC_HS_400));
+
+ return mmc_select_mode_and_width(mmc, caps_filtered);
+ }
+}
+#endif
+
int mmc_set_dsr(struct mmc *mmc, u16 val)
{
mmc->dsr = val;
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)
{