+// SPDX-License-Identifier: GPL-2.0+
/*
* Copyright 2008, Freescale Semiconductor, Inc
* Andy Fleming
*
* Based vaguely on the Linux code
- *
- * SPDX-License-Identifier: GPL-2.0+
*/
#include <config.h>
#include <div64.h>
#include "mmc_private.h"
-static const unsigned int sd_au_size[] = {
- 0, SZ_16K / 512, SZ_32K / 512,
- SZ_64K / 512, SZ_128K / 512, SZ_256K / 512,
- SZ_512K / 512, SZ_1M / 512, SZ_2M / 512,
- SZ_4M / 512, SZ_8M / 512, (SZ_8M + SZ_4M) / 512,
- SZ_16M / 512, (SZ_16M + SZ_8M) / 512, SZ_32M / 512, SZ_64M / 512,
-};
-
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);
-
-#if CONFIG_IS_ENABLED(MMC_TINY)
-static struct mmc mmc_static;
-struct mmc *find_mmc_device(int dev_num)
-{
- return &mmc_static;
-}
-
-void mmc_do_preinit(void)
-{
- struct mmc *m = &mmc_static;
-#ifdef CONFIG_FSL_ESDHC_ADAPTER_IDENT
- mmc_set_preinit(m, 1);
-#endif
- if (m->preinit)
- mmc_start_init(m);
-}
-
-struct blk_desc *mmc_get_blk_desc(struct mmc *mmc)
-{
- return &mmc->block_dev;
-}
#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)
{
return -ENOSYS;
}
+#endif
__weak int board_mmc_getwp(struct mmc *mmc)
{
[MMC_HS_52] = "MMC High Speed (52MHz)",
[MMC_DDR_52] = "MMC DDR52 (52MHz)",
[MMC_HS_200] = "HS200 (200MHz)",
+ [MMC_HS_400] = "HS400 (200MHz)",
};
if (mode >= MMC_MODES_END)
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,
+ [MMC_DDR_52] = 52000000,
[UHS_SDR12] = 25000000,
[UHS_SDR25] = 50000000,
[UHS_SDR50] = 100000000,
- [UHS_SDR104] = 208000000,
[UHS_DDR50] = 50000000,
- [MMC_HS_52] = 52000000,
- [MMC_DDR_52] = 52000000,
+ [UHS_SDR104] = 208000000,
[MMC_HS_200] = 200000000,
+ [MMC_HS_400] = 200000000,
};
if (mode == MMC_LEGACY)
mmc->selected_mode = mode;
mmc->tran_speed = mmc_mode2freq(mmc, mode);
mmc->ddr_mode = mmc_is_mode_ddr(mode);
- debug("selecting mode %s (freq : %d MHz)\n", mmc_mode_name(mode),
- mmc->tran_speed / 1000000);
+ pr_debug("selecting mode %s (freq : %d MHz)\n", mmc_mode_name(mode),
+ mmc->tran_speed / 1000000);
return 0;
}
if (cmd.response[0] & MMC_STATUS_MASK) {
#if !defined(CONFIG_SPL_BUILD) || defined(CONFIG_SPL_LIBCOMMON_SUPPORT)
- printf("Status Error: 0x%08X\n",
- cmd.response[0]);
+ pr_err("Status Error: 0x%08X\n",
+ cmd.response[0]);
#endif
return -ECOMM;
}
mmc_trace_state(mmc, &cmd);
if (timeout <= 0) {
#if !defined(CONFIG_SPL_BUILD) || defined(CONFIG_SPL_LIBCOMMON_SUPPORT)
- printf("Timeout waiting card ready\n");
+ pr_err("Timeout waiting card ready\n");
#endif
return -ETIMEDOUT;
}
return err;
}
+#ifdef MMC_SUPPORTS_TUNING
+static const u8 tuning_blk_pattern_4bit[] = {
+ 0xff, 0x0f, 0xff, 0x00, 0xff, 0xcc, 0xc3, 0xcc,
+ 0xc3, 0x3c, 0xcc, 0xff, 0xfe, 0xff, 0xfe, 0xef,
+ 0xff, 0xdf, 0xff, 0xdd, 0xff, 0xfb, 0xff, 0xfb,
+ 0xbf, 0xff, 0x7f, 0xff, 0x77, 0xf7, 0xbd, 0xef,
+ 0xff, 0xf0, 0xff, 0xf0, 0x0f, 0xfc, 0xcc, 0x3c,
+ 0xcc, 0x33, 0xcc, 0xcf, 0xff, 0xef, 0xff, 0xee,
+ 0xff, 0xfd, 0xff, 0xfd, 0xdf, 0xff, 0xbf, 0xff,
+ 0xbb, 0xff, 0xf7, 0xff, 0xf7, 0x7f, 0x7b, 0xde,
+};
+
+static const u8 tuning_blk_pattern_8bit[] = {
+ 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0x00,
+ 0xff, 0xff, 0xcc, 0xcc, 0xcc, 0x33, 0xcc, 0xcc,
+ 0xcc, 0x33, 0x33, 0xcc, 0xcc, 0xcc, 0xff, 0xff,
+ 0xff, 0xee, 0xff, 0xff, 0xff, 0xee, 0xee, 0xff,
+ 0xff, 0xff, 0xdd, 0xff, 0xff, 0xff, 0xdd, 0xdd,
+ 0xff, 0xff, 0xff, 0xbb, 0xff, 0xff, 0xff, 0xbb,
+ 0xbb, 0xff, 0xff, 0xff, 0x77, 0xff, 0xff, 0xff,
+ 0x77, 0x77, 0xff, 0x77, 0xbb, 0xdd, 0xee, 0xff,
+ 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00,
+ 0x00, 0xff, 0xff, 0xcc, 0xcc, 0xcc, 0x33, 0xcc,
+ 0xcc, 0xcc, 0x33, 0x33, 0xcc, 0xcc, 0xcc, 0xff,
+ 0xff, 0xff, 0xee, 0xff, 0xff, 0xff, 0xee, 0xee,
+ 0xff, 0xff, 0xff, 0xdd, 0xff, 0xff, 0xff, 0xdd,
+ 0xdd, 0xff, 0xff, 0xff, 0xbb, 0xff, 0xff, 0xff,
+ 0xbb, 0xbb, 0xff, 0xff, 0xff, 0x77, 0xff, 0xff,
+ 0xff, 0x77, 0x77, 0xff, 0x77, 0xbb, 0xdd, 0xee,
+};
+
+int mmc_send_tuning(struct mmc *mmc, u32 opcode, int *cmd_error)
+{
+ struct mmc_cmd cmd;
+ struct mmc_data data;
+ const u8 *tuning_block_pattern;
+ int size, err;
+
+ if (mmc->bus_width == 8) {
+ tuning_block_pattern = tuning_blk_pattern_8bit;
+ size = sizeof(tuning_blk_pattern_8bit);
+ } else if (mmc->bus_width == 4) {
+ tuning_block_pattern = tuning_blk_pattern_4bit;
+ size = sizeof(tuning_blk_pattern_4bit);
+ } else {
+ return -EINVAL;
+ }
+
+ ALLOC_CACHE_ALIGN_BUFFER(u8, data_buf, size);
+
+ cmd.cmdidx = opcode;
+ cmd.cmdarg = 0;
+ cmd.resp_type = MMC_RSP_R1;
+
+ data.dest = (void *)data_buf;
+ data.blocks = 1;
+ data.blocksize = size;
+ data.flags = MMC_DATA_READ;
+
+ err = mmc_send_cmd(mmc, &cmd, &data);
+ if (err)
+ return err;
+
+ if (memcmp(data_buf, tuning_block_pattern, size))
+ return -EIO;
+
+ return 0;
+}
+#endif
+
static int mmc_read_blocks(struct mmc *mmc, void *dst, lbaint_t start,
lbaint_t blkcnt)
{
cmd.resp_type = MMC_RSP_R1b;
if (mmc_send_cmd(mmc, &cmd, NULL)) {
#if !defined(CONFIG_SPL_BUILD) || defined(CONFIG_SPL_LIBCOMMON_SUPPORT)
- printf("mmc fail to send stop cmd\n");
+ pr_err("mmc fail to send stop cmd\n");
#endif
return 0;
}
if ((start + blkcnt) > block_dev->lba) {
#if !defined(CONFIG_SPL_BUILD) || defined(CONFIG_SPL_LIBCOMMON_SUPPORT)
- printf("MMC: block number 0x" LBAF " exceeds max(0x" LBAF ")\n",
- start + blkcnt, block_dev->lba);
+ pr_err("MMC: block number 0x" LBAF " exceeds max(0x" LBAF ")\n",
+ start + blkcnt, block_dev->lba);
#endif
return 0;
}
if (mmc_set_blocklen(mmc, mmc->read_bl_len)) {
- debug("%s: Failed to set blocklen\n", __func__);
+ pr_debug("%s: Failed to set blocklen\n", __func__);
return 0;
}
cur = (blocks_todo > mmc->cfg->b_max) ?
mmc->cfg->b_max : blocks_todo;
if (mmc_read_blocks(mmc, dst, start, cur) != cur) {
- debug("%s: Failed to read blocks\n", __func__);
+ pr_debug("%s: Failed to read blocks\n", __func__);
return 0;
}
blocks_todo -= cur;
return 0;
}
+#if CONFIG_IS_ENABLED(MMC_UHS_SUPPORT)
static int mmc_switch_voltage(struct mmc *mmc, int signal_voltage)
{
struct mmc_cmd cmd;
* During a signal voltage level switch, the clock must be gated
* for 5 ms according to the SD spec
*/
- mmc_set_clock(mmc, mmc->clock, true);
+ mmc_set_clock(mmc, mmc->clock, MMC_CLK_DISABLE);
err = mmc_set_signal_voltage(mmc, signal_voltage);
if (err)
/* Keep clock gated for at least 10 ms, though spec only says 5 ms */
mdelay(10);
- mmc_set_clock(mmc, mmc->clock, false);
+ mmc_set_clock(mmc, mmc->clock, MMC_CLK_ENABLE);
/*
* Failure to switch is indicated by the card holding
return 0;
}
+#endif
static int sd_send_op_cond(struct mmc *mmc, bool uhs_en)
{
mmc->ocr = cmd.response[0];
+#if CONFIG_IS_ENABLED(MMC_UHS_SUPPORT)
if (uhs_en && !(mmc_host_is_spi(mmc)) && (cmd.response[0] & 0x41000000)
== 0x41000000) {
err = mmc_switch_voltage(mmc, MMC_SIGNAL_VOLTAGE_180);
if (err)
return err;
}
+#endif
mmc->high_capacity = ((mmc->ocr & OCR_HCS) == OCR_HCS);
mmc->rca = 0;
{
struct mmc_cmd cmd;
int timeout = 1000;
- uint start;
+ ulong start;
int err;
mmc->op_cond_pending = 0;
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)
{
struct mmc_cmd cmd;
int timeout = 1000;
while (retries > 0) {
ret = mmc_send_cmd(mmc, &cmd, NULL);
- /* Waiting for the ready status */
- if (!ret) {
- ret = mmc_send_status(mmc, timeout);
- return ret;
+ if (ret) {
+ retries--;
+ continue;
}
- retries--;
+ if (!send_status) {
+ mdelay(50);
+ return 0;
+ }
+
+ /* Waiting for the ready status */
+ return mmc_send_status(mmc, timeout);
}
return ret;
}
-static int mmc_set_card_speed(struct mmc *mmc, enum bus_mode mode)
+int mmc_switch(struct mmc *mmc, u8 set, u8 index, u8 value)
+{
+ return __mmc_switch(mmc, set, index, value, true);
+}
+
+#if !CONFIG_IS_ENABLED(MMC_TINY)
+static int mmc_set_card_speed(struct mmc *mmc, enum bus_mode mode,
+ bool hsdowngrade)
{
int err;
int speed_bits;
case MMC_DDR_52:
speed_bits = EXT_CSD_TIMING_HS;
break;
+#if CONFIG_IS_ENABLED(MMC_HS200_SUPPORT)
case MMC_HS_200:
speed_bits = EXT_CSD_TIMING_HS200;
break;
+#endif
+#if CONFIG_IS_ENABLED(MMC_HS400_SUPPORT)
+ case MMC_HS_400:
+ 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);
u8 *ext_csd = mmc->ext_csd;
char cardtype;
- mmc->card_caps = MMC_MODE_1BIT;
+ mmc->card_caps = MMC_MODE_1BIT | MMC_CAP(MMC_LEGACY);
if (mmc_host_is_spi(mmc))
return 0;
return 0;
if (!ext_csd) {
- printf("No ext_csd found!\n"); /* this should enver happen */
+ pr_err("No ext_csd found!\n"); /* this should enver happen */
return -ENOTSUPP;
}
mmc->card_caps |= MMC_MODE_4BIT | MMC_MODE_8BIT;
- cardtype = ext_csd[EXT_CSD_CARD_TYPE] & 0x3f;
+ cardtype = ext_csd[EXT_CSD_CARD_TYPE];
mmc->cardtype = cardtype;
+#if CONFIG_IS_ENABLED(MMC_HS200_SUPPORT)
if (cardtype & (EXT_CSD_CARD_TYPE_HS200_1_2V |
EXT_CSD_CARD_TYPE_HS200_1_8V)) {
mmc->card_caps |= MMC_MODE_HS200;
}
+#endif
+#if CONFIG_IS_ENABLED(MMC_HS400_SUPPORT)
+ if (cardtype & (EXT_CSD_CARD_TYPE_HS400_1_2V |
+ EXT_CSD_CARD_TYPE_HS400_1_8V)) {
+ mmc->card_caps |= MMC_MODE_HS400;
+ }
+#endif
if (cardtype & EXT_CSD_CARD_TYPE_52) {
if (cardtype & EXT_CSD_CARD_TYPE_DDR_52)
mmc->card_caps |= MMC_MODE_DDR_52MHz;
return 0;
}
+#endif
static int mmc_set_capacity(struct mmc *mmc, int part_num)
{
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;
forbidden = MMC_CAP(MMC_HS_200);
if (MMC_CAP(mmc->selected_mode) & forbidden) {
- debug("selected mode (%s) is forbidden for part %d\n",
- mmc_mode_name(mmc->selected_mode), part_num);
+ 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) {
- debug("selected mode is not optimal\n");
+ pr_debug("selected mode is not optimal\n");
change = true;
}
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)
{
return ret;
}
+#if CONFIG_IS_ENABLED(MMC_HW_PARTITIONING)
int mmc_hwpart_config(struct mmc *mmc,
const struct mmc_hwpart_conf *conf,
enum mmc_hwpart_conf_mode mode)
return -EINVAL;
if (IS_SD(mmc) || (mmc->version < MMC_VERSION_4_41)) {
- printf("eMMC >= 4.4 required for enhanced user data area\n");
+ pr_err("eMMC >= 4.4 required for enhanced user data area\n");
return -EMEDIUMTYPE;
}
if (!(mmc->part_support & PART_SUPPORT)) {
- printf("Card does not support partitioning\n");
+ pr_err("Card does not support partitioning\n");
return -EMEDIUMTYPE;
}
if (!mmc->hc_wp_grp_size) {
- printf("Card does not define HC WP group size\n");
+ pr_err("Card does not define HC WP group size\n");
return -EMEDIUMTYPE;
}
if (conf->user.enh_size) {
if (conf->user.enh_size % mmc->hc_wp_grp_size ||
conf->user.enh_start % mmc->hc_wp_grp_size) {
- printf("User data enhanced area not HC WP group "
+ pr_err("User data enhanced area not HC WP group "
"size aligned\n");
return -EINVAL;
}
for (pidx = 0; pidx < 4; pidx++) {
if (conf->gp_part[pidx].size % mmc->hc_wp_grp_size) {
- printf("GP%i partition not HC WP group size "
+ pr_err("GP%i partition not HC WP group size "
"aligned\n", pidx+1);
return -EINVAL;
}
}
if (part_attrs && ! (mmc->part_support & ENHNCD_SUPPORT)) {
- printf("Card does not support enhanced attribute\n");
+ pr_err("Card does not support enhanced attribute\n");
return -EMEDIUMTYPE;
}
(ext_csd[EXT_CSD_MAX_ENH_SIZE_MULT+1] << 8) +
ext_csd[EXT_CSD_MAX_ENH_SIZE_MULT];
if (tot_enh_size_mult > max_enh_size_mult) {
- printf("Total enhanced size exceeds maximum (%u > %u)\n",
+ pr_err("Total enhanced size exceeds maximum (%u > %u)\n",
tot_enh_size_mult, max_enh_size_mult);
return -EMEDIUMTYPE;
}
if (ext_csd[EXT_CSD_PARTITION_SETTING] &
EXT_CSD_PARTITION_SETTING_COMPLETED) {
- printf("Card already partitioned\n");
+ pr_err("Card already partitioned\n");
return -EPERM;
}
return 0;
}
+#endif
#if !CONFIG_IS_ENABLED(DM_MMC)
int mmc_getcd(struct mmc *mmc)
}
#endif
+#if !CONFIG_IS_ENABLED(MMC_TINY)
static int sd_switch(struct mmc *mmc, int mode, int group, u8 value, u8 *resp)
{
struct mmc_cmd cmd;
return mmc_send_cmd(mmc, &cmd, &data);
}
-
static int sd_get_capabilities(struct mmc *mmc)
{
int err;
ALLOC_CACHE_ALIGN_BUFFER(__be32, switch_status, 16);
struct mmc_data data;
int timeout;
+#if CONFIG_IS_ENABLED(MMC_UHS_SUPPORT)
u32 sd3_bus_mode;
+#endif
- mmc->card_caps = MMC_MODE_1BIT;
+ mmc->card_caps = MMC_MODE_1BIT | MMC_CAP(SD_LEGACY);
if (mmc_host_is_spi(mmc))
return 0;
if (__be32_to_cpu(switch_status[3]) & SD_HIGHSPEED_SUPPORTED)
mmc->card_caps |= MMC_CAP(SD_HS);
+#if CONFIG_IS_ENABLED(MMC_UHS_SUPPORT)
/* Version before 3.0 don't support UHS modes */
if (mmc->version < SD_VERSION_3)
return 0;
mmc->card_caps |= MMC_CAP(UHS_SDR12);
if (sd3_bus_mode & SD_MODE_UHS_DDR50)
mmc->card_caps |= MMC_CAP(UHS_DDR50);
+#endif
return 0;
}
ALLOC_CACHE_ALIGN_BUFFER(uint, switch_status, 16);
int speed;
+ /* SD version 1.00 and 1.01 does not support CMD 6 */
+ if (mmc->version == SD_VERSION_1_0)
+ return 0;
+
switch (mode) {
case SD_LEGACY:
- case UHS_SDR12:
speed = UHS_SDR12_BUS_SPEED;
break;
case SD_HS:
+ speed = HIGH_SPEED_BUS_SPEED;
+ break;
+#if CONFIG_IS_ENABLED(MMC_UHS_SUPPORT)
+ case UHS_SDR12:
+ speed = UHS_SDR12_BUS_SPEED;
+ break;
case UHS_SDR25:
speed = UHS_SDR25_BUS_SPEED;
break;
case UHS_SDR104:
speed = UHS_SDR104_BUS_SPEED;
break;
+#endif
default:
return -EINVAL;
}
if (err)
return err;
- if ((__be32_to_cpu(switch_status[4]) >> 24) != speed)
+ if (((__be32_to_cpu(switch_status[4]) >> 24) & 0xF) != speed)
return -ENOTSUPP;
return 0;
}
-int sd_select_bus_width(struct mmc *mmc, int w)
+static int sd_select_bus_width(struct mmc *mmc, int w)
{
int err;
struct mmc_cmd cmd;
return 0;
}
+#endif
+#if CONFIG_IS_ENABLED(MMC_WRITE)
static int sd_read_ssr(struct mmc *mmc)
{
+ static const unsigned int sd_au_size[] = {
+ 0, SZ_16K / 512, SZ_32K / 512,
+ SZ_64K / 512, SZ_128K / 512, SZ_256K / 512,
+ SZ_512K / 512, SZ_1M / 512, SZ_2M / 512,
+ SZ_4M / 512, SZ_8M / 512, (SZ_8M + SZ_4M) / 512,
+ SZ_16M / 512, (SZ_16M + SZ_8M) / 512, SZ_32M / 512,
+ SZ_64M / 512,
+ };
int err, i;
struct mmc_cmd cmd;
ALLOC_CACHE_ALIGN_BUFFER(uint, ssr, 16);
mmc->ssr.erase_offset = eo * 1000;
}
} else {
- debug("Invalid Allocation Unit Size.\n");
+ pr_debug("Invalid Allocation Unit Size.\n");
}
return 0;
}
-
+#endif
/* frequency bases */
/* divided by 10 to be nice to platforms without floating point */
static const int fbase[] = {
return 4;
if (cap == MMC_MODE_1BIT)
return 1;
- printf("invalid bus witdh capability 0x%x\n", cap);
+ pr_warn("invalid bus witdh capability 0x%x\n", cap);
return 0;
}
#if !CONFIG_IS_ENABLED(DM_MMC)
+#ifdef MMC_SUPPORTS_TUNING
static int mmc_execute_tuning(struct mmc *mmc, uint opcode)
{
return -ENOTSUPP;
}
+#endif
static void mmc_send_init_stream(struct mmc *mmc)
{
int mmc_set_clock(struct mmc *mmc, uint clock, bool disable)
{
- if (clock > mmc->cfg->f_max)
- clock = mmc->cfg->f_max;
+ if (!disable) {
+ if (clock > mmc->cfg->f_max)
+ clock = mmc->cfg->f_max;
- if (clock < mmc->cfg->f_min)
- clock = mmc->cfg->f_min;
+ if (clock < mmc->cfg->f_min)
+ clock = mmc->cfg->f_min;
+ }
mmc->clock = clock;
mmc->clk_disable = disable;
+ debug("clock is %s (%dHz)\n", disable ? "disabled" : "enabled", clock);
+
return mmc_set_ios(mmc);
}
{
enum bus_mode mode;
- printf("%s: widths [", text);
+ pr_debug("%s: widths [", text);
if (caps & MMC_MODE_8BIT)
- printf("8, ");
+ pr_debug("8, ");
if (caps & MMC_MODE_4BIT)
- printf("4, ");
+ pr_debug("4, ");
if (caps & MMC_MODE_1BIT)
- printf("1, ");
- printf("\b\b] modes [");
+ pr_debug("1, ");
+ pr_debug("\b\b] modes [");
for (mode = MMC_LEGACY; mode < MMC_MODES_END; mode++)
if (MMC_CAP(mode) & caps)
- printf("%s, ", mmc_mode_name(mode));
- printf("\b\b]\n");
+ pr_debug("%s, ", mmc_mode_name(mode));
+ pr_debug("\b\b]\n");
}
#endif
struct mode_width_tuning {
enum bus_mode mode;
uint widths;
+#ifdef MMC_SUPPORTS_TUNING
uint tuning;
+#endif
};
+#if CONFIG_IS_ENABLED(MMC_IO_VOLTAGE)
int mmc_voltage_to_mv(enum mmc_voltage voltage)
{
switch (voltage) {
mmc->signal_voltage = signal_voltage;
err = mmc_set_ios(mmc);
if (err)
- debug("unable to set voltage (err %d)\n", err);
+ pr_debug("unable to set voltage (err %d)\n", err);
return err;
}
+#else
+static inline int mmc_set_signal_voltage(struct mmc *mmc, uint signal_voltage)
+{
+ return 0;
+}
+#endif
+#if !CONFIG_IS_ENABLED(MMC_TINY)
static const struct mode_width_tuning sd_modes_by_pref[] = {
+#if CONFIG_IS_ENABLED(MMC_UHS_SUPPORT)
+#ifdef MMC_SUPPORTS_TUNING
{
.mode = UHS_SDR104,
.widths = MMC_MODE_4BIT | MMC_MODE_1BIT,
.tuning = MMC_CMD_SEND_TUNING_BLOCK
},
+#endif
{
.mode = UHS_SDR50,
.widths = MMC_MODE_4BIT | MMC_MODE_1BIT,
.mode = UHS_SDR25,
.widths = MMC_MODE_4BIT | MMC_MODE_1BIT,
},
+#endif
{
.mode = SD_HS,
.widths = MMC_MODE_4BIT | MMC_MODE_1BIT,
},
+#if CONFIG_IS_ENABLED(MMC_UHS_SUPPORT)
{
.mode = UHS_SDR12,
.widths = MMC_MODE_4BIT | MMC_MODE_1BIT,
},
+#endif
{
.mode = SD_LEGACY,
.widths = MMC_MODE_4BIT | MMC_MODE_1BIT,
int err;
uint widths[] = {MMC_MODE_4BIT, MMC_MODE_1BIT};
const struct mode_width_tuning *mwt;
+#if CONFIG_IS_ENABLED(MMC_UHS_SUPPORT)
bool uhs_en = (mmc->ocr & OCR_S18R) ? true : false;
+#else
+ bool uhs_en = false;
+#endif
uint caps;
+#ifdef DEBUG
+ mmc_dump_capabilities("sd card", card_caps);
+ mmc_dump_capabilities("host", mmc->host_caps);
+#endif
/* Restrict card's capabilities by what the host can do */
- caps = card_caps & (mmc->host_caps | MMC_MODE_1BIT);
+ caps = card_caps & mmc->host_caps;
if (!uhs_en)
caps &= ~UHS_CAPS;
for (w = widths; w < widths + ARRAY_SIZE(widths); w++) {
if (*w & caps & mwt->widths) {
- debug("trying mode %s width %d (at %d MHz)\n",
- mmc_mode_name(mwt->mode),
- bus_width(*w),
- mmc_mode2freq(mmc, mwt->mode) / 1000000);
+ pr_debug("trying mode %s width %d (at %d MHz)\n",
+ mmc_mode_name(mwt->mode),
+ bus_width(*w),
+ mmc_mode2freq(mmc, mwt->mode) / 1000000);
/* configure the bus width (card + host) */
err = sd_select_bus_width(mmc, bus_width(*w));
/* configure the bus mode (host) */
mmc_select_mode(mmc, mwt->mode);
- mmc_set_clock(mmc, mmc->tran_speed, false);
+ mmc_set_clock(mmc, mmc->tran_speed,
+ MMC_CLK_ENABLE);
+#ifdef MMC_SUPPORTS_TUNING
/* execute tuning if needed */
if (mwt->tuning && !mmc_host_is_spi(mmc)) {
err = mmc_execute_tuning(mmc,
mwt->tuning);
if (err) {
- debug("tuning failed\n");
+ pr_debug("tuning failed\n");
goto error;
}
}
+#endif
+#if CONFIG_IS_ENABLED(MMC_WRITE)
err = sd_read_ssr(mmc);
+ if (err)
+ pr_warn("unable to read ssr\n");
+#endif
if (!err)
return 0;
- printf("bad ssr\n");
-
error:
/* revert to a safer bus speed */
mmc_select_mode(mmc, SD_LEGACY);
- mmc_set_clock(mmc, mmc->tran_speed, false);
+ mmc_set_clock(mmc, mmc->tran_speed,
+ MMC_CLK_ENABLE);
}
}
}
- printf("unable to select a mode\n");
+ pr_err("unable to select a mode\n");
return -ENOTSUPP;
}
const u8 *ext_csd = mmc->ext_csd;
ALLOC_CACHE_ALIGN_BUFFER(u8, test_csd, MMC_MAX_BLOCK_LEN);
+ if (mmc->version < MMC_VERSION_4)
+ return 0;
+
err = mmc_send_ext_csd(mmc, test_csd);
if (err)
return err;
return -EBADMSG;
}
+#if CONFIG_IS_ENABLED(MMC_IO_VOLTAGE)
static int mmc_set_lowest_voltage(struct mmc *mmc, enum bus_mode mode,
uint32_t allowed_mask)
{
u32 card_mask = 0;
switch (mode) {
+ case MMC_HS_400:
case MMC_HS_200:
- if (mmc->cardtype & EXT_CSD_CARD_TYPE_HS200_1_8V)
+ if (mmc->cardtype & (EXT_CSD_CARD_TYPE_HS200_1_8V |
+ EXT_CSD_CARD_TYPE_HS400_1_8V))
card_mask |= MMC_SIGNAL_VOLTAGE_180;
- if (mmc->cardtype & EXT_CSD_CARD_TYPE_HS200_1_2V)
+ if (mmc->cardtype & (EXT_CSD_CARD_TYPE_HS200_1_2V |
+ EXT_CSD_CARD_TYPE_HS400_1_2V))
card_mask |= MMC_SIGNAL_VOLTAGE_120;
break;
case MMC_DDR_52:
return -ENOTSUPP;
}
+#else
+static inline int mmc_set_lowest_voltage(struct mmc *mmc, enum bus_mode mode,
+ uint32_t allowed_mask)
+{
+ return 0;
+}
+#endif
static const struct mode_width_tuning mmc_modes_by_pref[] = {
+#if CONFIG_IS_ENABLED(MMC_HS400_SUPPORT)
+ {
+ .mode = MMC_HS_400,
+ .widths = MMC_MODE_8BIT,
+ .tuning = MMC_CMD_SEND_TUNING_BLOCK_HS200
+ },
+#endif
+#if CONFIG_IS_ENABLED(MMC_HS200_SUPPORT)
{
.mode = MMC_HS_200,
.widths = MMC_MODE_8BIT | MMC_MODE_4BIT,
.tuning = MMC_CMD_SEND_TUNING_BLOCK_HS200
},
+#endif
{
.mode = MMC_DDR_52,
.widths = MMC_MODE_8BIT | MMC_MODE_4BIT,
{MMC_MODE_1BIT, false, EXT_CSD_BUS_WIDTH_1},
};
+#if CONFIG_IS_ENABLED(MMC_HS400_SUPPORT)
+static int mmc_select_hs400(struct mmc *mmc)
+{
+ int err;
+
+ /* Set timing to HS200 for tuning */
+ err = mmc_set_card_speed(mmc, MMC_HS_200, false);
+ if (err)
+ return err;
+
+ /* configure the bus mode (host) */
+ mmc_select_mode(mmc, MMC_HS_200);
+ mmc_set_clock(mmc, mmc->tran_speed, false);
+
+ /* execute tuning if needed */
+ err = mmc_execute_tuning(mmc, MMC_CMD_SEND_TUNING_BLOCK_HS200);
+ if (err) {
+ debug("tuning failed\n");
+ return err;
+ }
+
+ /* Set back to HS */
+ mmc_set_card_speed(mmc, MMC_HS, false);
+ mmc_set_clock(mmc, mmc_mode2freq(mmc, MMC_HS), false);
+
+ 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, false);
+ if (err)
+ return err;
+
+ mmc_select_mode(mmc, MMC_HS_400);
+ err = mmc_set_clock(mmc, mmc->tran_speed, false);
+ if (err)
+ return err;
+
+ return 0;
+}
+#else
+static int mmc_select_hs400(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);\
const struct mode_width_tuning *mwt;
const struct ext_csd_bus_width *ecbw;
+#ifdef DEBUG
+ mmc_dump_capabilities("mmc", card_caps);
+ mmc_dump_capabilities("host", mmc->host_caps);
+#endif
+
/* Restrict card's capabilities by what the host can do */
- card_caps &= (mmc->host_caps | MMC_MODE_1BIT);
+ card_caps &= mmc->host_caps;
/* Only version 4 of MMC supports wider bus widths */
if (mmc->version < MMC_VERSION_4)
return 0;
if (!mmc->ext_csd) {
- debug("No ext_csd found!\n"); /* this should enver happen */
+ pr_debug("No ext_csd found!\n"); /* this should enver happen */
return -ENOTSUPP;
}
- mmc_set_clock(mmc, mmc->legacy_speed, false);
+#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,
mmc_is_mode_ddr(mwt->mode), ecbw) {
enum mmc_voltage old_voltage;
- debug("trying mode %s width %d (at %d MHz)\n",
- mmc_mode_name(mwt->mode),
- bus_width(ecbw->cap),
- mmc_mode2freq(mmc, mwt->mode) / 1000000);
+ pr_debug("trying mode %s width %d (at %d MHz)\n",
+ mmc_mode_name(mwt->mode),
+ bus_width(ecbw->cap),
+ mmc_mode2freq(mmc, mwt->mode) / 1000000);
old_voltage = mmc->signal_voltage;
err = mmc_set_lowest_voltage(mmc, mwt->mode,
MMC_ALL_SIGNAL_VOLTAGE);
goto error;
mmc_set_bus_width(mmc, bus_width(ecbw->cap));
- /* configure the bus speed (card) */
- err = mmc_set_card_speed(mmc, mwt->mode);
- if (err)
- goto error;
-
- /*
- * configure the bus width AND the ddr mode (card)
- * The host side will be taken care of in the next step
- */
- if (ecbw->ext_csd_bits & EXT_CSD_DDR_FLAG) {
- err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL,
- EXT_CSD_BUS_WIDTH,
- ecbw->ext_csd_bits);
+ if (mwt->mode == MMC_HS_400) {
+ err = mmc_select_hs400(mmc);
+ if (err) {
+ printf("Select HS400 failed %d\n", err);
+ goto error;
+ }
+ } else {
+ /* configure the bus speed (card) */
+ err = mmc_set_card_speed(mmc, mwt->mode, false);
if (err)
goto error;
- }
- /* configure the bus mode (host) */
- mmc_select_mode(mmc, mwt->mode);
- mmc_set_clock(mmc, mmc->tran_speed, false);
+ /*
+ * configure the bus width AND the ddr mode
+ * (card). The host side will be taken care
+ * of in the next step
+ */
+ if (ecbw->ext_csd_bits & EXT_CSD_DDR_FLAG) {
+ err = mmc_switch(mmc,
+ EXT_CSD_CMD_SET_NORMAL,
+ EXT_CSD_BUS_WIDTH,
+ ecbw->ext_csd_bits);
+ if (err)
+ goto error;
+ }
- /* execute tuning if needed */
- if (mwt->tuning) {
- err = mmc_execute_tuning(mmc, mwt->tuning);
- if (err) {
- debug("tuning failed\n");
- goto error;
+ /* configure the bus mode (host) */
+ mmc_select_mode(mmc, mwt->mode);
+ mmc_set_clock(mmc, mmc->tran_speed,
+ MMC_CLK_ENABLE);
+#ifdef MMC_SUPPORTS_TUNING
+
+ /* execute tuning if needed */
+ if (mwt->tuning) {
+ err = mmc_execute_tuning(mmc,
+ mwt->tuning);
+ if (err) {
+ pr_debug("tuning failed\n");
+ goto error;
+ }
}
+#endif
}
/* do a transfer to check the configuration */
}
}
- printf("unable to select a mode\n");
+ pr_err("unable to select a mode\n");
return -ENOTSUPP;
}
+#endif
+
+#if CONFIG_IS_ENABLED(MMC_TINY)
+DEFINE_CACHE_ALIGN_BUFFER(u8, ext_csd_bkup, MMC_MAX_BLOCK_LEN);
+#endif
static int mmc_startup_v4(struct mmc *mmc)
{
u64 capacity;
bool has_parts = false;
bool part_completed;
- u8 *ext_csd;
+ static const u32 mmc_versions[] = {
+ MMC_VERSION_4,
+ MMC_VERSION_4_1,
+ MMC_VERSION_4_2,
+ MMC_VERSION_4_3,
+ MMC_VERSION_4_4,
+ MMC_VERSION_4_41,
+ MMC_VERSION_4_5,
+ MMC_VERSION_5_0,
+ MMC_VERSION_5_1
+ };
- if (IS_SD(mmc) || (mmc->version < MMC_VERSION_4))
+#if CONFIG_IS_ENABLED(MMC_TINY)
+ u8 *ext_csd = ext_csd_bkup;
+
+ if (IS_SD(mmc) || mmc->version < MMC_VERSION_4)
return 0;
- ext_csd = malloc_cache_aligned(MMC_MAX_BLOCK_LEN);
- if (!ext_csd)
- return -ENOMEM;
+ if (!mmc->ext_csd)
+ memset(ext_csd_bkup, 0, sizeof(ext_csd_bkup));
+
+ err = mmc_send_ext_csd(mmc, ext_csd);
+ if (err)
+ goto error;
+
+ /* store the ext csd for future reference */
+ if (!mmc->ext_csd)
+ mmc->ext_csd = ext_csd;
+#else
+ ALLOC_CACHE_ALIGN_BUFFER(u8, ext_csd, MMC_MAX_BLOCK_LEN);
- mmc->ext_csd = ext_csd;
+ if (IS_SD(mmc) || (mmc->version < MMC_VERSION_4))
+ return 0;
/* check ext_csd version and capacity */
err = mmc_send_ext_csd(mmc, ext_csd);
if (err)
- return err;
- if (ext_csd[EXT_CSD_REV] >= 2) {
+ goto error;
+
+ /* store the ext csd for future reference */
+ if (!mmc->ext_csd)
+ mmc->ext_csd = malloc(MMC_MAX_BLOCK_LEN);
+ if (!mmc->ext_csd)
+ return -ENOMEM;
+ memcpy(mmc->ext_csd, ext_csd, MMC_MAX_BLOCK_LEN);
+#endif
+ if (ext_csd[EXT_CSD_REV] >= ARRAY_SIZE(mmc_versions))
+ return -EINVAL;
+
+ mmc->version = mmc_versions[ext_csd[EXT_CSD_REV]];
+
+ if (mmc->version >= MMC_VERSION_4_2) {
/*
* According to the JEDEC Standard, the value of
* ext_csd's capacity is valid if the value is more
mmc->capacity_user = capacity;
}
- switch (ext_csd[EXT_CSD_REV]) {
- case 1:
- mmc->version = MMC_VERSION_4_1;
- break;
- case 2:
- mmc->version = MMC_VERSION_4_2;
- break;
- case 3:
- mmc->version = MMC_VERSION_4_3;
- break;
- case 5:
- mmc->version = MMC_VERSION_4_41;
- break;
- case 6:
- mmc->version = MMC_VERSION_4_5;
- break;
- case 7:
- mmc->version = MMC_VERSION_5_0;
- break;
- case 8:
- mmc->version = MMC_VERSION_5_1;
- break;
- }
-
/* 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,
mmc->capacity_gp[i] <<= 19;
}
+#ifndef CONFIG_SPL_BUILD
if (part_completed) {
mmc->enh_user_size =
(ext_csd[EXT_CSD_ENH_SIZE_MULT + 2] << 16) +
if (mmc->high_capacity)
mmc->enh_user_start <<= 9;
}
+#endif
/*
* Host needs to enable ERASE_GRP_DEF bit if device is
EXT_CSD_ERASE_GROUP_DEF, 1);
if (err)
- return err;
+ goto error;
ext_csd[EXT_CSD_ERASE_GROUP_DEF] = 1;
}
if (ext_csd[EXT_CSD_ERASE_GROUP_DEF] & 0x01) {
+#if CONFIG_IS_ENABLED(MMC_WRITE)
/* Read out group size from ext_csd */
mmc->erase_grp_size =
ext_csd[EXT_CSD_HC_ERASE_GRP_SIZE] * 1024;
+#endif
/*
* if high capacity and partition setting completed
* SEC_COUNT is valid even if it is smaller than 2 GiB
capacity *= MMC_MAX_BLOCK_LEN;
mmc->capacity_user = capacity;
}
- } else {
+ }
+#if CONFIG_IS_ENABLED(MMC_WRITE)
+ else {
/* Calculate the group size from the csd value. */
int erase_gsz, erase_gmul;
mmc->erase_grp_size = (erase_gsz + 1)
* (erase_gmul + 1);
}
-
+#endif
+#if CONFIG_IS_ENABLED(MMC_HW_PARTITIONING)
mmc->hc_wp_grp_size = 1024
* ext_csd[EXT_CSD_HC_ERASE_GRP_SIZE]
* ext_csd[EXT_CSD_HC_WP_GRP_SIZE];
+#endif
mmc->wr_rel_set = ext_csd[EXT_CSD_WR_REL_SET];
return 0;
+error:
+ if (mmc->ext_csd) {
+#if !CONFIG_IS_ENABLED(MMC_TINY)
+ free(mmc->ext_csd);
+#endif
+ mmc->ext_csd = NULL;
+ }
+ return err;
}
static int mmc_startup(struct mmc *mmc)
mmc->dsr_imp = ((cmd.response[1] >> 12) & 0x1);
mmc->read_bl_len = 1 << ((cmd.response[1] >> 16) & 0xf);
+#if CONFIG_IS_ENABLED(MMC_WRITE)
if (IS_SD(mmc))
mmc->write_bl_len = mmc->read_bl_len;
else
mmc->write_bl_len = 1 << ((cmd.response[3] >> 22) & 0xf);
+#endif
if (mmc->high_capacity) {
csize = (mmc->csd[1] & 0x3f) << 16
if (mmc->read_bl_len > MMC_MAX_BLOCK_LEN)
mmc->read_bl_len = MMC_MAX_BLOCK_LEN;
+#if CONFIG_IS_ENABLED(MMC_WRITE)
if (mmc->write_bl_len > MMC_MAX_BLOCK_LEN)
mmc->write_bl_len = MMC_MAX_BLOCK_LEN;
+#endif
if ((mmc->dsr_imp) && (0xffffffff != mmc->dsr)) {
cmd.cmdidx = MMC_CMD_SET_DSR;
cmd.cmdarg = (mmc->dsr & 0xffff) << 16;
cmd.resp_type = MMC_RSP_NONE;
if (mmc_send_cmd(mmc, &cmd, NULL))
- printf("MMC: SET_DSR failed\n");
+ pr_warn("MMC: SET_DSR failed\n");
}
/* Select the card, and put it into Transfer Mode */
/*
* For SD, its erase group is always one sector
*/
+#if CONFIG_IS_ENABLED(MMC_WRITE)
mmc->erase_grp_size = 1;
+#endif
mmc->part_config = MMCPART_NOAVAILABLE;
err = mmc_startup_v4(mmc);
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_set_bus_width(mmc, 1);
+#else
if (IS_SD(mmc)) {
err = sd_get_capabilities(mmc);
if (err)
return err;
mmc_select_mode_and_width(mmc, mmc->card_caps);
}
-
+#endif
if (err)
return err;
/* Fix the block length for DDR mode */
if (mmc->ddr_mode) {
mmc->read_bl_len = MMC_MAX_BLOCK_LEN;
+#if CONFIG_IS_ENABLED(MMC_WRITE)
mmc->write_bl_len = MMC_MAX_BLOCK_LEN;
+#endif
}
/* fill in device description */
bdesc->product[0] = 0;
bdesc->revision[0] = 0;
#endif
-#if !defined(CONFIG_SPL_BUILD) || defined(CONFIG_SPL_LIBDISK_SUPPORT)
+
+#if !defined(CONFIG_DM_MMC) && (!defined(CONFIG_SPL_BUILD) || defined(CONFIG_SPL_LIBDISK_SUPPORT))
part_init(bdesc);
#endif
ret = device_get_supply_regulator(mmc->dev, "vmmc-supply",
&mmc->vmmc_supply);
if (ret)
- debug("%s: No vmmc supply\n", mmc->dev->name);
+ pr_debug("%s: No vmmc supply\n", mmc->dev->name);
ret = device_get_supply_regulator(mmc->dev, "vqmmc-supply",
&mmc->vqmmc_supply);
if (ret)
- debug("%s: No vqmmc supply\n", mmc->dev->name);
+ pr_debug("%s: No vqmmc supply\n", mmc->dev->name);
#endif
#else /* !CONFIG_DM_MMC */
/*
if (err != 0)
err = mmc_set_signal_voltage(mmc, MMC_SIGNAL_VOLTAGE_180);
if (err != 0)
- printf("mmc: failed to set signal voltage\n");
+ pr_warn("mmc: failed to set signal voltage\n");
mmc_select_mode(mmc, MMC_LEGACY);
mmc_set_bus_width(mmc, 1);
- mmc_set_clock(mmc, 0, false);
+ mmc_set_clock(mmc, 0, MMC_CLK_ENABLE);
}
static int mmc_power_on(struct mmc *mmc)
static int mmc_power_off(struct mmc *mmc)
{
- mmc_set_clock(mmc, 1, true);
+ mmc_set_clock(mmc, 0, MMC_CLK_DISABLE);
#if CONFIG_IS_ENABLED(DM_MMC) && CONFIG_IS_ENABLED(DM_REGULATOR)
if (mmc->vmmc_supply) {
int ret = regulator_set_enable(mmc->vmmc_supply, false);
if (ret) {
- debug("Error disabling VMMC supply\n");
+ pr_debug("Error disabling VMMC supply\n");
return ret;
}
}
return mmc_power_on(mmc);
}
-int mmc_start_init(struct mmc *mmc)
+int mmc_get_op_cond(struct mmc *mmc)
{
- bool no_card;
bool uhs_en = supports_uhs(mmc->cfg->host_caps);
int err;
- mmc->host_caps = mmc->cfg->host_caps;
-
- /* we pretend there's no card when init is NULL */
- no_card = mmc_getcd(mmc) == 0;
-#if !CONFIG_IS_ENABLED(DM_MMC)
- no_card = no_card || (mmc->cfg->ops->init == NULL);
-#endif
- if (no_card) {
- mmc->has_init = 0;
-#if !defined(CONFIG_SPL_BUILD) || defined(CONFIG_SPL_LIBCOMMON_SUPPORT)
- printf("MMC: no card present\n");
-#endif
- return -ENOMEDIUM;
- }
-
if (mmc->has_init)
return 0;
* to use the UHS modes, because we wouldn't be able to
* recover from an error during the UHS initialization.
*/
- debug("Unable to do a full power cycle. Disabling the UHS modes for safety\n");
+ pr_debug("Unable to do a full power cycle. Disabling the UHS modes for safety\n");
uhs_en = false;
mmc->host_caps &= ~UHS_CAPS;
err = mmc_power_on(mmc);
if (err) {
#if !defined(CONFIG_SPL_BUILD) || defined(CONFIG_SPL_LIBCOMMON_SUPPORT)
- printf("Card did not respond to voltage select!\n");
+ pr_err("Card did not respond to voltage select!\n");
#endif
return -EOPNOTSUPP;
}
}
+ return err;
+}
+
+int mmc_start_init(struct mmc *mmc)
+{
+ bool no_card;
+ int err = 0;
+
+ /*
+ * 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_CAP(MMC_LEGACY) | MMC_MODE_1BIT;
+
+#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)
+ no_card = no_card || (mmc->cfg->ops->init == NULL);
+#endif
+ if (no_card) {
+ mmc->has_init = 0;
+#if !defined(CONFIG_SPL_BUILD) || defined(CONFIG_SPL_LIBCOMMON_SUPPORT)
+ pr_err("MMC: no card present\n");
+#endif
+ return -ENOMEDIUM;
+ }
+
+ err = mmc_get_op_cond(mmc);
+
if (!err)
mmc->init_in_progress = 1;
int mmc_init(struct mmc *mmc)
{
int err = 0;
- __maybe_unused unsigned start;
+ __maybe_unused ulong start;
#if CONFIG_IS_ENABLED(DM_MMC)
struct mmc_uclass_priv *upriv = dev_get_uclass_priv(mmc->dev);
if (!err)
err = mmc_complete_init(mmc);
if (err)
- printf("%s: %d, time %lu\n", __func__, err, get_timer(start));
+ pr_info("%s: %d, time %lu\n", __func__, err, get_timer(start));
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;
mmc->preinit = preinit;
}
-#if CONFIG_IS_ENABLED(DM_MMC) && defined(CONFIG_SPL_BUILD)
-static int mmc_probe(bd_t *bis)
-{
- return 0;
-}
-#elif CONFIG_IS_ENABLED(DM_MMC)
+#if CONFIG_IS_ENABLED(DM_MMC)
static int mmc_probe(bd_t *bis)
{
int ret, i;
uclass_foreach_dev(dev, uc) {
ret = device_probe(dev);
if (ret)
- printf("%s - probe failed: %d\n", dev->name, ret);
+ pr_err("%s - probe failed: %d\n", dev->name, ret);
}
return 0;