#include <errno.h>
#include <mmc.h>
#include <part.h>
+#include <power/regulator.h>
#include <malloc.h>
#include <memalign.h>
#include <linux/list.h>
#include <div64.h>
#include "mmc_private.h"
-static struct list_head mmc_devices;
-static int cur_dev_num = -1;
+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,
+};
+
+#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)
__weak int board_mmc_getwp(struct mmc *mmc)
{
return -1;
{
return -1;
}
+#endif
-int mmc_send_cmd(struct mmc *mmc, struct mmc_cmd *cmd, struct mmc_data *data)
+#ifdef CONFIG_MMC_TRACE
+void mmmc_trace_before_send(struct mmc *mmc, struct mmc_cmd *cmd)
{
- int ret;
+ printf("CMD_SEND:%d\n", cmd->cmdidx);
+ printf("\t\tARG\t\t\t 0x%08X\n", cmd->cmdarg);
+}
-#ifdef CONFIG_MMC_TRACE
+void mmmc_trace_after_send(struct mmc *mmc, struct mmc_cmd *cmd, int ret)
+{
int i;
u8 *ptr;
- printf("CMD_SEND:%d\n", cmd->cmdidx);
- printf("\t\tARG\t\t\t 0x%08X\n", cmd->cmdarg);
- ret = mmc->cfg->ops->send_cmd(mmc, cmd, data);
- switch (cmd->resp_type) {
+ if (ret) {
+ printf("\t\tRET\t\t\t %d\n", ret);
+ } else {
+ switch (cmd->resp_type) {
case MMC_RSP_NONE:
printf("\t\tMMC_RSP_NONE\n");
break;
default:
printf("\t\tERROR MMC rsp not supported\n");
break;
+ }
}
-#else
- ret = mmc->cfg->ops->send_cmd(mmc, cmd, data);
+}
+
+void mmc_trace_state(struct mmc *mmc, struct mmc_cmd *cmd)
+{
+ int status;
+
+ status = (cmd->response[0] & MMC_STATUS_CURR_STATE) >> 9;
+ printf("CURR STATE:%d\n", status);
+}
#endif
+
+#if !CONFIG_IS_ENABLED(DM_MMC)
+int mmc_send_cmd(struct mmc *mmc, struct mmc_cmd *cmd, struct mmc_data *data)
+{
+ int ret;
+
+ mmmc_trace_before_send(mmc, cmd);
+ ret = mmc->cfg->ops->send_cmd(mmc, cmd, data);
+ mmmc_trace_after_send(mmc, cmd, ret);
+
return ret;
}
+#endif
int mmc_send_status(struct mmc *mmc, int timeout)
{
struct mmc_cmd cmd;
int err, retries = 5;
-#ifdef CONFIG_MMC_TRACE
- int status;
-#endif
cmd.cmdidx = MMC_CMD_SEND_STATUS;
cmd.resp_type = MMC_RSP_R1;
printf("Status Error: 0x%08X\n",
cmd.response[0]);
#endif
- return COMM_ERR;
+ return -ECOMM;
}
} else if (--retries < 0)
return err;
udelay(1000);
}
-#ifdef CONFIG_MMC_TRACE
- status = (cmd.response[0] & MMC_STATUS_CURR_STATE) >> 9;
- printf("CURR STATE:%d\n", status);
-#endif
+ mmc_trace_state(mmc, &cmd);
if (timeout <= 0) {
#if !defined(CONFIG_SPL_BUILD) || defined(CONFIG_SPL_LIBCOMMON_SUPPORT)
printf("Timeout waiting card ready\n");
#endif
- return TIMEOUT;
+ return -ETIMEDOUT;
}
- if (cmd.response[0] & MMC_STATUS_SWITCH_ERROR)
- return SWITCH_ERR;
return 0;
}
return mmc_send_cmd(mmc, &cmd, NULL);
}
-struct mmc *find_mmc_device(int dev_num)
-{
- struct mmc *m;
- struct list_head *entry;
-
- list_for_each(entry, &mmc_devices) {
- m = list_entry(entry, struct mmc, link);
-
- if (m->block_dev.devnum == dev_num)
- return m;
- }
-
-#if !defined(CONFIG_SPL_BUILD) || defined(CONFIG_SPL_LIBCOMMON_SUPPORT)
- printf("MMC Device %d not found\n", dev_num);
-#endif
-
- return NULL;
-}
-
static int mmc_read_blocks(struct mmc *mmc, void *dst, lbaint_t start,
lbaint_t blkcnt)
{
return blkcnt;
}
-static ulong mmc_bread(struct blk_desc *block_dev, lbaint_t start,
- lbaint_t blkcnt, void *dst)
+#if CONFIG_IS_ENABLED(BLK)
+ulong mmc_bread(struct udevice *dev, lbaint_t start, lbaint_t blkcnt, void *dst)
+#else
+ulong mmc_bread(struct blk_desc *block_dev, lbaint_t start, lbaint_t blkcnt,
+ void *dst)
+#endif
{
+#if CONFIG_IS_ENABLED(BLK)
+ struct blk_desc *block_dev = dev_get_uclass_platdata(dev);
+#endif
int dev_num = block_dev->devnum;
int err;
lbaint_t cur, blocks_todo = blkcnt;
if (!mmc)
return 0;
- err = mmc_select_hwpart(dev_num, block_dev->hwpart);
+ if (CONFIG_IS_ENABLED(MMC_TINY))
+ err = mmc_switch_part(mmc, block_dev->hwpart);
+ else
+ err = blk_dselect_hwpart(block_dev, block_dev->hwpart);
+
if (err < 0)
return 0;
- if ((start + blkcnt) > mmc->block_dev.lba) {
+ 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, mmc->block_dev.lba);
+ start + blkcnt, block_dev->lba);
#endif
return 0;
}
break;
if (timeout-- <= 0)
- return UNUSABLE_ERR;
+ return -EOPNOTSUPP;
udelay(1000);
}
mmc->op_cond_pending = 0;
if (!(mmc->ocr & OCR_BUSY)) {
+ /* Some cards seem to need this */
+ mmc_go_idle(mmc);
+
start = get_timer(0);
while (1) {
err = mmc_send_op_cond_iter(mmc, 1);
if (mmc->ocr & OCR_BUSY)
break;
if (get_timer(start) > timeout)
- return UNUSABLE_ERR;
+ return -EOPNOTSUPP;
udelay(100);
}
}
return err;
}
-
-static int mmc_switch(struct mmc *mmc, u8 set, u8 index, u8 value)
+int mmc_switch(struct mmc *mmc, u8 set, u8 index, u8 value)
{
struct mmc_cmd cmd;
int timeout = 1000;
+ int retries = 3;
int ret;
cmd.cmdidx = MMC_CMD_SWITCH;
(index << 16) |
(value << 8);
- ret = mmc_send_cmd(mmc, &cmd, NULL);
+ 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;
+ }
- /* Waiting for the ready status */
- if (!ret)
- ret = mmc_send_status(mmc, timeout);
+ retries--;
+ }
return ret;
err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL, EXT_CSD_HS_TIMING, 1);
if (err)
- return err == SWITCH_ERR ? 0 : err;
+ return err;
/* Now check to see that it worked */
err = mmc_send_ext_csd(mmc, ext_csd);
return -1;
}
- mmc->block_dev.lba = lldiv(mmc->capacity, mmc->read_bl_len);
-
- return 0;
-}
-
-int mmc_select_hwpart(int dev_num, int hwpart)
-{
- struct mmc *mmc = find_mmc_device(dev_num);
- int ret;
-
- if (!mmc)
- return -ENODEV;
-
- if (mmc->block_dev.hwpart == hwpart)
- return 0;
-
- if (mmc->part_config == MMCPART_NOAVAILABLE) {
- printf("Card doesn't support part_switch\n");
- return -EMEDIUMTYPE;
- }
-
- ret = mmc_switch_part(dev_num, hwpart);
- if (ret)
- return ret;
+ mmc_get_blk_desc(mmc)->lba = lldiv(mmc->capacity, mmc->read_bl_len);
return 0;
}
-
-int mmc_switch_part(int dev_num, unsigned int part_num)
+int mmc_switch_part(struct mmc *mmc, unsigned int part_num)
{
- struct mmc *mmc = find_mmc_device(dev_num);
int ret;
- if (!mmc)
- return -1;
-
ret = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL, EXT_CSD_PART_CONF,
(mmc->part_config & ~PART_ACCESS_MASK)
| (part_num & PART_ACCESS_MASK));
*/
if ((ret == 0) || ((ret == -ENODEV) && (part_num == 0))) {
ret = mmc_set_capacity(mmc, part_num);
- mmc->block_dev.hwpart = part_num;
+ mmc_get_blk_desc(mmc)->hwpart = part_num;
}
return ret;
return 0;
}
+#if !CONFIG_IS_ENABLED(DM_MMC)
int mmc_getcd(struct mmc *mmc)
{
int cd;
return cd;
}
+#endif
static int sd_switch(struct mmc *mmc, int mode, int group, u8 value, u8 *resp)
{
{
int err;
struct mmc_cmd cmd;
- ALLOC_CACHE_ALIGN_BUFFER(uint, scr, 2);
- ALLOC_CACHE_ALIGN_BUFFER(uint, switch_status, 16);
+ ALLOC_CACHE_ALIGN_BUFFER(__be32, scr, 2);
+ ALLOC_CACHE_ALIGN_BUFFER(__be32, switch_status, 16);
struct mmc_data data;
int timeout;
mmc->scr[1] = __be32_to_cpu(scr[1]);
switch ((mmc->scr[0] >> 24) & 0xf) {
- case 0:
- mmc->version = SD_VERSION_1_0;
- break;
- case 1:
- mmc->version = SD_VERSION_1_10;
- break;
- case 2:
- mmc->version = SD_VERSION_2;
- if ((mmc->scr[0] >> 15) & 0x1)
- mmc->version = SD_VERSION_3;
- break;
- default:
- mmc->version = SD_VERSION_1_0;
- break;
+ case 0:
+ mmc->version = SD_VERSION_1_0;
+ break;
+ case 1:
+ mmc->version = SD_VERSION_1_10;
+ break;
+ case 2:
+ mmc->version = SD_VERSION_2;
+ if ((mmc->scr[0] >> 15) & 0x1)
+ mmc->version = SD_VERSION_3;
+ break;
+ default:
+ mmc->version = SD_VERSION_1_0;
+ break;
}
if (mmc->scr[0] & SD_DATA_4BIT)
return 0;
}
+static int sd_read_ssr(struct mmc *mmc)
+{
+ int err, i;
+ 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);
+ if (err)
+ return err;
+
+ cmd.cmdidx = SD_CMD_APP_SD_STATUS;
+ 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;
+
+ return err;
+ }
+
+ for (i = 0; i < 16; i++)
+ ssr[i] = be32_to_cpu(ssr[i]);
+
+ au = (ssr[2] >> 12) & 0xF;
+ if ((au <= 9) || (mmc->version == SD_VERSION_3)) {
+ mmc->ssr.au = sd_au_size[au];
+ es = (ssr[3] >> 24) & 0xFF;
+ es |= (ssr[2] & 0xFF) << 8;
+ et = (ssr[3] >> 18) & 0x3F;
+ if (es && et) {
+ eo = (ssr[3] >> 16) & 0x3;
+ mmc->ssr.erase_timeout = (et * 1000) / es;
+ mmc->ssr.erase_offset = eo * 1000;
+ }
+ } else {
+ debug("Invalid Allocation Unit Size.\n");
+ }
+
+ return 0;
+}
+
/* frequency bases */
/* divided by 10 to be nice to platforms without floating point */
static const int fbase[] = {
/* Multiplier values for TRAN_SPEED. Multiplied by 10 to be nice
* to platforms without floating point.
*/
-static const int multipliers[] = {
+static const u8 multipliers[] = {
0, /* reserved */
10,
12,
80,
};
+#if !CONFIG_IS_ENABLED(DM_MMC)
static void mmc_set_ios(struct mmc *mmc)
{
if (mmc->cfg->ops->set_ios)
mmc->cfg->ops->set_ios(mmc);
}
+#endif
void mmc_set_clock(struct mmc *mmc, uint clock)
{
mmc_set_ios(mmc);
}
-static int mmc_startup(struct mmc *mmc)
+static int sd_select_bus_freq_width(struct mmc *mmc)
{
- int err, i;
- uint mult, freq;
- u64 cmult, csize, capacity;
+ int err;
struct mmc_cmd cmd;
- ALLOC_CACHE_ALIGN_BUFFER(u8, ext_csd, MMC_MAX_BLOCK_LEN);
- ALLOC_CACHE_ALIGN_BUFFER(u8, test_csd, MMC_MAX_BLOCK_LEN);
- int timeout = 1000;
- bool has_parts = false;
- bool part_completed;
-
-#ifdef CONFIG_MMC_SPI_CRC_ON
- if (mmc_host_is_spi(mmc)) { /* enable CRC check for spi */
- cmd.cmdidx = MMC_CMD_SPI_CRC_ON_OFF;
- cmd.resp_type = MMC_RSP_R1;
- cmd.cmdarg = 1;
- err = mmc_send_cmd(mmc, &cmd, NULL);
-
- if (err)
- return err;
- }
-#endif
-
- /* Put the Card in Identify Mode */
- cmd.cmdidx = mmc_host_is_spi(mmc) ? MMC_CMD_SEND_CID :
- MMC_CMD_ALL_SEND_CID; /* cmd not supported in spi */
- cmd.resp_type = MMC_RSP_R2;
- cmd.cmdarg = 0;
-
- err = mmc_send_cmd(mmc, &cmd, NULL);
+ err = sd_change_freq(mmc);
if (err)
return err;
- memcpy(mmc->cid, cmd.response, 16);
+ /* Restrict card's capabilities by what the host can do */
+ mmc->card_caps &= mmc->cfg->host_caps;
- /*
- * For MMC cards, set the Relative Address.
- * For SD cards, get the Relatvie Address.
- * This also puts the cards into Standby State
- */
- if (!mmc_host_is_spi(mmc)) { /* cmd not supported in spi */
- cmd.cmdidx = SD_CMD_SEND_RELATIVE_ADDR;
+ if (mmc->card_caps & MMC_MODE_4BIT) {
+ cmd.cmdidx = MMC_CMD_APP_CMD;
+ cmd.resp_type = MMC_RSP_R1;
cmd.cmdarg = mmc->rca << 16;
- cmd.resp_type = MMC_RSP_R6;
err = mmc_send_cmd(mmc, &cmd, NULL);
+ if (err)
+ return err;
+ cmd.cmdidx = SD_CMD_APP_SET_BUS_WIDTH;
+ cmd.resp_type = MMC_RSP_R1;
+ cmd.cmdarg = 2;
+ err = mmc_send_cmd(mmc, &cmd, NULL);
if (err)
return err;
- if (IS_SD(mmc))
- mmc->rca = (cmd.response[0] >> 16) & 0xffff;
+ mmc_set_bus_width(mmc, 4);
}
- /* Get the Card-Specific Data */
- cmd.cmdidx = MMC_CMD_SEND_CSD;
- cmd.resp_type = MMC_RSP_R2;
- cmd.cmdarg = mmc->rca << 16;
+ err = sd_read_ssr(mmc);
+ if (err)
+ return err;
- err = mmc_send_cmd(mmc, &cmd, NULL);
+ if (mmc->card_caps & MMC_MODE_HS)
+ mmc->tran_speed = 50000000;
+ else
+ mmc->tran_speed = 25000000;
+
+ return 0;
+}
- /* Waiting for the ready status */
- mmc_send_status(mmc, timeout);
+static int mmc_select_bus_freq_width(struct mmc *mmc, const u8 *ext_csd)
+{
+ ALLOC_CACHE_ALIGN_BUFFER(u8, test_csd, MMC_MAX_BLOCK_LEN);
+ /* An array of possible bus widths in order of preference */
+ static const unsigned int ext_csd_bits[] = {
+ EXT_CSD_DDR_BUS_WIDTH_8,
+ EXT_CSD_DDR_BUS_WIDTH_4,
+ EXT_CSD_BUS_WIDTH_8,
+ EXT_CSD_BUS_WIDTH_4,
+ EXT_CSD_BUS_WIDTH_1,
+ };
+ /* An array to map CSD bus widths to host cap bits */
+ static const unsigned int ext_to_hostcaps[] = {
+ [EXT_CSD_DDR_BUS_WIDTH_4] =
+ MMC_MODE_DDR_52MHz | MMC_MODE_4BIT,
+ [EXT_CSD_DDR_BUS_WIDTH_8] =
+ MMC_MODE_DDR_52MHz | MMC_MODE_8BIT,
+ [EXT_CSD_BUS_WIDTH_4] = MMC_MODE_4BIT,
+ [EXT_CSD_BUS_WIDTH_8] = MMC_MODE_8BIT,
+ };
+ /* An array to map chosen bus width to an integer */
+ static const unsigned int widths[] = {
+ 8, 4, 8, 4, 1,
+ };
+ int err;
+ int idx;
+ err = mmc_change_freq(mmc);
if (err)
return err;
- mmc->csd[0] = cmd.response[0];
- mmc->csd[1] = cmd.response[1];
- mmc->csd[2] = cmd.response[2];
- mmc->csd[3] = cmd.response[3];
+ /* Restrict card's capabilities by what the host can do */
+ mmc->card_caps &= mmc->cfg->host_caps;
- if (mmc->version == MMC_VERSION_UNKNOWN) {
- int version = (cmd.response[0] >> 26) & 0xf;
+ /* Only version 4 of MMC supports wider bus widths */
+ if (mmc->version < MMC_VERSION_4)
+ return 0;
- switch (version) {
- case 0:
- mmc->version = MMC_VERSION_1_2;
- break;
- case 1:
- mmc->version = MMC_VERSION_1_4;
- break;
- case 2:
- mmc->version = MMC_VERSION_2_2;
- break;
- case 3:
- mmc->version = MMC_VERSION_3;
- break;
- case 4:
- mmc->version = MMC_VERSION_4;
- break;
- default:
- mmc->version = MMC_VERSION_1_2;
- break;
+ for (idx = 0; idx < ARRAY_SIZE(ext_csd_bits); idx++) {
+ unsigned int extw = ext_csd_bits[idx];
+ unsigned int caps = ext_to_hostcaps[extw];
+ /*
+ * If the bus width is still not changed,
+ * don't try to set the default again.
+ * Otherwise, recover from switch attempts
+ * by switching to 1-bit bus width.
+ */
+ if (extw == EXT_CSD_BUS_WIDTH_1 &&
+ mmc->bus_width == 1) {
+ err = 0;
+ break;
}
- }
- /* divide frequency by 10, since the mults are 10x bigger */
- freq = fbase[(cmd.response[0] & 0x7)];
- mult = multipliers[((cmd.response[0] >> 3) & 0xf)];
+ /*
+ * Check to make sure the card and controller support
+ * these capabilities
+ */
+ if ((mmc->card_caps & caps) != caps)
+ continue;
- mmc->tran_speed = freq * mult;
+ err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL,
+ EXT_CSD_BUS_WIDTH, extw);
- mmc->dsr_imp = ((cmd.response[1] >> 12) & 0x1);
- mmc->read_bl_len = 1 << ((cmd.response[1] >> 16) & 0xf);
+ if (err)
+ continue;
- if (IS_SD(mmc))
- mmc->write_bl_len = mmc->read_bl_len;
- else
- mmc->write_bl_len = 1 << ((cmd.response[3] >> 22) & 0xf);
+ mmc->ddr_mode = (caps & MMC_MODE_DDR_52MHz) ? 1 : 0;
+ mmc_set_bus_width(mmc, widths[idx]);
- if (mmc->high_capacity) {
- csize = (mmc->csd[1] & 0x3f) << 16
- | (mmc->csd[2] & 0xffff0000) >> 16;
- cmult = 8;
- } else {
- csize = (mmc->csd[1] & 0x3ff) << 2
- | (mmc->csd[2] & 0xc0000000) >> 30;
- cmult = (mmc->csd[2] & 0x00038000) >> 15;
+ err = mmc_send_ext_csd(mmc, test_csd);
+
+ if (err)
+ continue;
+
+ /* Only compare read only fields */
+ if (ext_csd[EXT_CSD_PARTITIONING_SUPPORT]
+ == test_csd[EXT_CSD_PARTITIONING_SUPPORT] &&
+ ext_csd[EXT_CSD_HC_WP_GRP_SIZE]
+ == test_csd[EXT_CSD_HC_WP_GRP_SIZE] &&
+ ext_csd[EXT_CSD_REV]
+ == test_csd[EXT_CSD_REV] &&
+ ext_csd[EXT_CSD_HC_ERASE_GRP_SIZE]
+ == test_csd[EXT_CSD_HC_ERASE_GRP_SIZE] &&
+ memcmp(&ext_csd[EXT_CSD_SEC_CNT],
+ &test_csd[EXT_CSD_SEC_CNT], 4) == 0)
+ break;
+
+ err = -EBADMSG;
+ }
+
+ if (err)
+ return err;
+
+ if (mmc->card_caps & MMC_MODE_HS) {
+ if (mmc->card_caps & MMC_MODE_HS_52MHz)
+ mmc->tran_speed = 52000000;
+ else
+ mmc->tran_speed = 26000000;
+ }
+
+ return err;
+}
+
+static int mmc_startup_v4(struct mmc *mmc, u8 *ext_csd)
+{
+ int err, i;
+ u64 capacity;
+ bool has_parts = false;
+ bool part_completed;
+
+ 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) {
+ /*
+ * According to the JEDEC Standard, the value of
+ * ext_csd's capacity is valid if the value is more
+ * than 2GB
+ */
+ capacity = ext_csd[EXT_CSD_SEC_CNT] << 0
+ | ext_csd[EXT_CSD_SEC_CNT + 1] << 8
+ | ext_csd[EXT_CSD_SEC_CNT + 2] << 16
+ | ext_csd[EXT_CSD_SEC_CNT + 3] << 24;
+ capacity *= MMC_MAX_BLOCK_LEN;
+ if ((capacity >> 20) > 2 * 1024)
+ 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,
+ * except for enabling the high-capacity group size
+ * definition (see below).
+ */
+ part_completed = !!(ext_csd[EXT_CSD_PARTITION_SETTING] &
+ EXT_CSD_PARTITION_SETTING_COMPLETED);
+
+ /* store the partition info of emmc */
+ mmc->part_support = ext_csd[EXT_CSD_PARTITIONING_SUPPORT];
+ if ((ext_csd[EXT_CSD_PARTITIONING_SUPPORT] & PART_SUPPORT) ||
+ ext_csd[EXT_CSD_BOOT_MULT])
+ mmc->part_config = ext_csd[EXT_CSD_PART_CONF];
+ if (part_completed &&
+ (ext_csd[EXT_CSD_PARTITIONING_SUPPORT] & ENHNCD_SUPPORT))
+ mmc->part_attr = ext_csd[EXT_CSD_PARTITIONS_ATTRIBUTE];
+
+ mmc->capacity_boot = ext_csd[EXT_CSD_BOOT_MULT] << 17;
+
+ mmc->capacity_rpmb = ext_csd[EXT_CSD_RPMB_MULT] << 17;
+
+ for (i = 0; i < 4; i++) {
+ int idx = EXT_CSD_GP_SIZE_MULT + i * 3;
+ uint mult = (ext_csd[idx + 2] << 16) +
+ (ext_csd[idx + 1] << 8) + ext_csd[idx];
+ if (mult)
+ has_parts = true;
+ if (!part_completed)
+ continue;
+ mmc->capacity_gp[i] = mult;
+ mmc->capacity_gp[i] *=
+ ext_csd[EXT_CSD_HC_ERASE_GRP_SIZE];
+ mmc->capacity_gp[i] *= ext_csd[EXT_CSD_HC_WP_GRP_SIZE];
+ mmc->capacity_gp[i] <<= 19;
+ }
+
+ if (part_completed) {
+ mmc->enh_user_size =
+ (ext_csd[EXT_CSD_ENH_SIZE_MULT + 2] << 16) +
+ (ext_csd[EXT_CSD_ENH_SIZE_MULT + 1] << 8) +
+ ext_csd[EXT_CSD_ENH_SIZE_MULT];
+ mmc->enh_user_size *= ext_csd[EXT_CSD_HC_ERASE_GRP_SIZE];
+ mmc->enh_user_size *= ext_csd[EXT_CSD_HC_WP_GRP_SIZE];
+ mmc->enh_user_size <<= 19;
+ mmc->enh_user_start =
+ (ext_csd[EXT_CSD_ENH_START_ADDR + 3] << 24) +
+ (ext_csd[EXT_CSD_ENH_START_ADDR + 2] << 16) +
+ (ext_csd[EXT_CSD_ENH_START_ADDR + 1] << 8) +
+ ext_csd[EXT_CSD_ENH_START_ADDR];
+ if (mmc->high_capacity)
+ mmc->enh_user_start <<= 9;
+ }
+
+ /*
+ * Host needs to enable ERASE_GRP_DEF bit if device is
+ * partitioned. This bit will be lost every time after a reset
+ * or power off. This will affect erase size.
+ */
+ if (part_completed)
+ has_parts = true;
+ if ((ext_csd[EXT_CSD_PARTITIONING_SUPPORT] & PART_SUPPORT) &&
+ (ext_csd[EXT_CSD_PARTITIONS_ATTRIBUTE] & PART_ENH_ATTRIB))
+ has_parts = true;
+ if (has_parts) {
+ err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL,
+ EXT_CSD_ERASE_GROUP_DEF, 1);
+
+ if (err)
+ return err;
+
+ ext_csd[EXT_CSD_ERASE_GROUP_DEF] = 1;
+ }
+
+ if (ext_csd[EXT_CSD_ERASE_GROUP_DEF] & 0x01) {
+ /* Read out group size from ext_csd */
+ mmc->erase_grp_size =
+ ext_csd[EXT_CSD_HC_ERASE_GRP_SIZE] * 1024;
+ /*
+ * if high capacity and partition setting completed
+ * SEC_COUNT is valid even if it is smaller than 2 GiB
+ * JEDEC Standard JESD84-B45, 6.2.4
+ */
+ if (mmc->high_capacity && part_completed) {
+ capacity = (ext_csd[EXT_CSD_SEC_CNT]) |
+ (ext_csd[EXT_CSD_SEC_CNT + 1] << 8) |
+ (ext_csd[EXT_CSD_SEC_CNT + 2] << 16) |
+ (ext_csd[EXT_CSD_SEC_CNT + 3] << 24);
+ capacity *= MMC_MAX_BLOCK_LEN;
+ mmc->capacity_user = capacity;
+ }
+ } else {
+ /* Calculate the group size from the csd value. */
+ int erase_gsz, erase_gmul;
+
+ erase_gsz = (mmc->csd[2] & 0x00007c00) >> 10;
+ erase_gmul = (mmc->csd[2] & 0x000003e0) >> 5;
+ mmc->erase_grp_size = (erase_gsz + 1)
+ * (erase_gmul + 1);
+ }
+
+ mmc->hc_wp_grp_size = 1024
+ * ext_csd[EXT_CSD_HC_ERASE_GRP_SIZE]
+ * ext_csd[EXT_CSD_HC_WP_GRP_SIZE];
+
+ mmc->wr_rel_set = ext_csd[EXT_CSD_WR_REL_SET];
+
+ return 0;
+}
+
+static int mmc_startup(struct mmc *mmc)
+{
+ int err, i;
+ uint mult, freq;
+ u64 cmult, csize;
+ struct mmc_cmd cmd;
+ ALLOC_CACHE_ALIGN_BUFFER(u8, ext_csd, MMC_MAX_BLOCK_LEN);
+ struct blk_desc *bdesc;
+
+#ifdef CONFIG_MMC_SPI_CRC_ON
+ if (mmc_host_is_spi(mmc)) { /* enable CRC check for spi */
+ cmd.cmdidx = MMC_CMD_SPI_CRC_ON_OFF;
+ cmd.resp_type = MMC_RSP_R1;
+ cmd.cmdarg = 1;
+ err = mmc_send_cmd(mmc, &cmd, NULL);
+
+ if (err)
+ return err;
+ }
+#endif
+
+ /* Put the Card in Identify Mode */
+ cmd.cmdidx = mmc_host_is_spi(mmc) ? MMC_CMD_SEND_CID :
+ MMC_CMD_ALL_SEND_CID; /* cmd not supported in spi */
+ cmd.resp_type = MMC_RSP_R2;
+ cmd.cmdarg = 0;
+
+ err = mmc_send_cmd(mmc, &cmd, NULL);
+
+ if (err)
+ return err;
+
+ memcpy(mmc->cid, cmd.response, 16);
+
+ /*
+ * For MMC cards, set the Relative Address.
+ * For SD cards, get the Relatvie Address.
+ * This also puts the cards into Standby State
+ */
+ if (!mmc_host_is_spi(mmc)) { /* cmd not supported in spi */
+ cmd.cmdidx = SD_CMD_SEND_RELATIVE_ADDR;
+ cmd.cmdarg = mmc->rca << 16;
+ cmd.resp_type = MMC_RSP_R6;
+
+ err = mmc_send_cmd(mmc, &cmd, NULL);
+
+ if (err)
+ return err;
+
+ if (IS_SD(mmc))
+ mmc->rca = (cmd.response[0] >> 16) & 0xffff;
+ }
+
+ /* Get the Card-Specific Data */
+ cmd.cmdidx = MMC_CMD_SEND_CSD;
+ cmd.resp_type = MMC_RSP_R2;
+ cmd.cmdarg = mmc->rca << 16;
+
+ err = mmc_send_cmd(mmc, &cmd, NULL);
+
+ if (err)
+ return err;
+
+ mmc->csd[0] = cmd.response[0];
+ mmc->csd[1] = cmd.response[1];
+ mmc->csd[2] = cmd.response[2];
+ mmc->csd[3] = cmd.response[3];
+
+ if (mmc->version == MMC_VERSION_UNKNOWN) {
+ int version = (cmd.response[0] >> 26) & 0xf;
+
+ switch (version) {
+ case 0:
+ mmc->version = MMC_VERSION_1_2;
+ break;
+ case 1:
+ mmc->version = MMC_VERSION_1_4;
+ break;
+ case 2:
+ mmc->version = MMC_VERSION_2_2;
+ break;
+ case 3:
+ mmc->version = MMC_VERSION_3;
+ break;
+ case 4:
+ mmc->version = MMC_VERSION_4;
+ break;
+ default:
+ mmc->version = MMC_VERSION_1_2;
+ break;
+ }
+ }
+
+ /* divide frequency by 10, since the mults are 10x bigger */
+ freq = fbase[(cmd.response[0] & 0x7)];
+ mult = multipliers[((cmd.response[0] >> 3) & 0xf)];
+
+ mmc->tran_speed = freq * mult;
+
+ mmc->dsr_imp = ((cmd.response[1] >> 12) & 0x1);
+ mmc->read_bl_len = 1 << ((cmd.response[1] >> 16) & 0xf);
+
+ if (IS_SD(mmc))
+ mmc->write_bl_len = mmc->read_bl_len;
+ else
+ mmc->write_bl_len = 1 << ((cmd.response[3] >> 22) & 0xf);
+
+ if (mmc->high_capacity) {
+ csize = (mmc->csd[1] & 0x3f) << 16
+ | (mmc->csd[2] & 0xffff0000) >> 16;
+ cmult = 8;
+ } else {
+ csize = (mmc->csd[1] & 0x3ff) << 2
+ | (mmc->csd[2] & 0xc0000000) >> 30;
+ cmult = (mmc->csd[2] & 0x00038000) >> 15;
}
mmc->capacity_user = (csize + 1) << (cmult + 2);
*/
mmc->erase_grp_size = 1;
mmc->part_config = MMCPART_NOAVAILABLE;
- if (!IS_SD(mmc) && (mmc->version >= MMC_VERSION_4)) {
- /* 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) {
- /*
- * According to the JEDEC Standard, the value of
- * ext_csd's capacity is valid if the value is more
- * than 2GB
- */
- capacity = ext_csd[EXT_CSD_SEC_CNT] << 0
- | ext_csd[EXT_CSD_SEC_CNT + 1] << 8
- | ext_csd[EXT_CSD_SEC_CNT + 2] << 16
- | ext_csd[EXT_CSD_SEC_CNT + 3] << 24;
- capacity *= MMC_MAX_BLOCK_LEN;
- if ((capacity >> 20) > 2 * 1024)
- 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;
- }
-
- /* 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,
- * except for enabling the high-capacity group size
- * definition (see below). */
- part_completed = !!(ext_csd[EXT_CSD_PARTITION_SETTING] &
- EXT_CSD_PARTITION_SETTING_COMPLETED);
-
- /* store the partition info of emmc */
- mmc->part_support = ext_csd[EXT_CSD_PARTITIONING_SUPPORT];
- if ((ext_csd[EXT_CSD_PARTITIONING_SUPPORT] & PART_SUPPORT) ||
- ext_csd[EXT_CSD_BOOT_MULT])
- mmc->part_config = ext_csd[EXT_CSD_PART_CONF];
- if (part_completed &&
- (ext_csd[EXT_CSD_PARTITIONING_SUPPORT] & ENHNCD_SUPPORT))
- mmc->part_attr = ext_csd[EXT_CSD_PARTITIONS_ATTRIBUTE];
-
- mmc->capacity_boot = ext_csd[EXT_CSD_BOOT_MULT] << 17;
-
- mmc->capacity_rpmb = ext_csd[EXT_CSD_RPMB_MULT] << 17;
-
- for (i = 0; i < 4; i++) {
- int idx = EXT_CSD_GP_SIZE_MULT + i * 3;
- uint mult = (ext_csd[idx + 2] << 16) +
- (ext_csd[idx + 1] << 8) + ext_csd[idx];
- if (mult)
- has_parts = true;
- if (!part_completed)
- continue;
- mmc->capacity_gp[i] = mult;
- mmc->capacity_gp[i] *=
- ext_csd[EXT_CSD_HC_ERASE_GRP_SIZE];
- mmc->capacity_gp[i] *= ext_csd[EXT_CSD_HC_WP_GRP_SIZE];
- mmc->capacity_gp[i] <<= 19;
- }
-
- if (part_completed) {
- mmc->enh_user_size =
- (ext_csd[EXT_CSD_ENH_SIZE_MULT+2] << 16) +
- (ext_csd[EXT_CSD_ENH_SIZE_MULT+1] << 8) +
- ext_csd[EXT_CSD_ENH_SIZE_MULT];
- mmc->enh_user_size *= ext_csd[EXT_CSD_HC_ERASE_GRP_SIZE];
- mmc->enh_user_size *= ext_csd[EXT_CSD_HC_WP_GRP_SIZE];
- mmc->enh_user_size <<= 19;
- mmc->enh_user_start =
- (ext_csd[EXT_CSD_ENH_START_ADDR+3] << 24) +
- (ext_csd[EXT_CSD_ENH_START_ADDR+2] << 16) +
- (ext_csd[EXT_CSD_ENH_START_ADDR+1] << 8) +
- ext_csd[EXT_CSD_ENH_START_ADDR];
- if (mmc->high_capacity)
- mmc->enh_user_start <<= 9;
- }
-
- /*
- * Host needs to enable ERASE_GRP_DEF bit if device is
- * partitioned. This bit will be lost every time after a reset
- * or power off. This will affect erase size.
- */
- if (part_completed)
- has_parts = true;
- if ((ext_csd[EXT_CSD_PARTITIONING_SUPPORT] & PART_SUPPORT) &&
- (ext_csd[EXT_CSD_PARTITIONS_ATTRIBUTE] & PART_ENH_ATTRIB))
- has_parts = true;
- if (has_parts) {
- err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL,
- EXT_CSD_ERASE_GROUP_DEF, 1);
-
- if (err)
- return err;
- else
- ext_csd[EXT_CSD_ERASE_GROUP_DEF] = 1;
- }
-
- if (ext_csd[EXT_CSD_ERASE_GROUP_DEF] & 0x01) {
- /* Read out group size from ext_csd */
- mmc->erase_grp_size =
- ext_csd[EXT_CSD_HC_ERASE_GRP_SIZE] * 1024;
- /*
- * if high capacity and partition setting completed
- * SEC_COUNT is valid even if it is smaller than 2 GiB
- * JEDEC Standard JESD84-B45, 6.2.4
- */
- if (mmc->high_capacity && part_completed) {
- capacity = (ext_csd[EXT_CSD_SEC_CNT]) |
- (ext_csd[EXT_CSD_SEC_CNT + 1] << 8) |
- (ext_csd[EXT_CSD_SEC_CNT + 2] << 16) |
- (ext_csd[EXT_CSD_SEC_CNT + 3] << 24);
- capacity *= MMC_MAX_BLOCK_LEN;
- mmc->capacity_user = capacity;
- }
- } else {
- /* Calculate the group size from the csd value. */
- int erase_gsz, erase_gmul;
- erase_gsz = (mmc->csd[2] & 0x00007c00) >> 10;
- erase_gmul = (mmc->csd[2] & 0x000003e0) >> 5;
- mmc->erase_grp_size = (erase_gsz + 1)
- * (erase_gmul + 1);
- }
-
- mmc->hc_wp_grp_size = 1024
- * ext_csd[EXT_CSD_HC_ERASE_GRP_SIZE]
- * ext_csd[EXT_CSD_HC_WP_GRP_SIZE];
-
- mmc->wr_rel_set = ext_csd[EXT_CSD_WR_REL_SET];
- }
+ err = mmc_startup_v4(mmc, ext_csd);
+ if (err)
+ return err;
- err = mmc_set_capacity(mmc, mmc->block_dev.hwpart);
+ err = mmc_set_capacity(mmc, mmc_get_blk_desc(mmc)->hwpart);
if (err)
return err;
if (IS_SD(mmc))
- err = sd_change_freq(mmc);
+ err = sd_select_bus_freq_width(mmc);
else
- err = mmc_change_freq(mmc);
+ err = mmc_select_bus_freq_width(mmc, ext_csd);
if (err)
return err;
- /* Restrict card's capabilities by what the host can do */
- mmc->card_caps &= mmc->cfg->host_caps;
-
- if (IS_SD(mmc)) {
- if (mmc->card_caps & MMC_MODE_4BIT) {
- cmd.cmdidx = MMC_CMD_APP_CMD;
- cmd.resp_type = MMC_RSP_R1;
- cmd.cmdarg = mmc->rca << 16;
-
- err = mmc_send_cmd(mmc, &cmd, NULL);
- if (err)
- return err;
-
- cmd.cmdidx = SD_CMD_APP_SET_BUS_WIDTH;
- cmd.resp_type = MMC_RSP_R1;
- cmd.cmdarg = 2;
- err = mmc_send_cmd(mmc, &cmd, NULL);
- if (err)
- return err;
-
- mmc_set_bus_width(mmc, 4);
- }
-
- if (mmc->card_caps & MMC_MODE_HS)
- mmc->tran_speed = 50000000;
- else
- mmc->tran_speed = 25000000;
- } else if (mmc->version >= MMC_VERSION_4) {
- /* Only version 4 of MMC supports wider bus widths */
- int idx;
-
- /* An array of possible bus widths in order of preference */
- static unsigned ext_csd_bits[] = {
- EXT_CSD_DDR_BUS_WIDTH_8,
- EXT_CSD_DDR_BUS_WIDTH_4,
- EXT_CSD_BUS_WIDTH_8,
- EXT_CSD_BUS_WIDTH_4,
- EXT_CSD_BUS_WIDTH_1,
- };
-
- /* An array to map CSD bus widths to host cap bits */
- static unsigned ext_to_hostcaps[] = {
- [EXT_CSD_DDR_BUS_WIDTH_4] =
- MMC_MODE_DDR_52MHz | MMC_MODE_4BIT,
- [EXT_CSD_DDR_BUS_WIDTH_8] =
- MMC_MODE_DDR_52MHz | MMC_MODE_8BIT,
- [EXT_CSD_BUS_WIDTH_4] = MMC_MODE_4BIT,
- [EXT_CSD_BUS_WIDTH_8] = MMC_MODE_8BIT,
- };
-
- /* An array to map chosen bus width to an integer */
- static unsigned widths[] = {
- 8, 4, 8, 4, 1,
- };
-
- for (idx=0; idx < ARRAY_SIZE(ext_csd_bits); idx++) {
- unsigned int extw = ext_csd_bits[idx];
- unsigned int caps = ext_to_hostcaps[extw];
-
- /*
- * If the bus width is still not changed,
- * don't try to set the default again.
- * Otherwise, recover from switch attempts
- * by switching to 1-bit bus width.
- */
- if (extw == EXT_CSD_BUS_WIDTH_1 &&
- mmc->bus_width == 1) {
- err = 0;
- break;
- }
-
- /*
- * Check to make sure the card and controller support
- * these capabilities
- */
- if ((mmc->card_caps & caps) != caps)
- continue;
-
- err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL,
- EXT_CSD_BUS_WIDTH, extw);
-
- if (err)
- continue;
-
- mmc->ddr_mode = (caps & MMC_MODE_DDR_52MHz) ? 1 : 0;
- mmc_set_bus_width(mmc, widths[idx]);
-
- err = mmc_send_ext_csd(mmc, test_csd);
-
- if (err)
- continue;
-
- /* Only compare read only fields */
- if (ext_csd[EXT_CSD_PARTITIONING_SUPPORT]
- == test_csd[EXT_CSD_PARTITIONING_SUPPORT] &&
- ext_csd[EXT_CSD_HC_WP_GRP_SIZE]
- == test_csd[EXT_CSD_HC_WP_GRP_SIZE] &&
- ext_csd[EXT_CSD_REV]
- == test_csd[EXT_CSD_REV] &&
- ext_csd[EXT_CSD_HC_ERASE_GRP_SIZE]
- == test_csd[EXT_CSD_HC_ERASE_GRP_SIZE] &&
- memcmp(&ext_csd[EXT_CSD_SEC_CNT],
- &test_csd[EXT_CSD_SEC_CNT], 4) == 0)
- break;
- else
- err = SWITCH_ERR;
- }
-
- if (err)
- return err;
-
- if (mmc->card_caps & MMC_MODE_HS) {
- if (mmc->card_caps & MMC_MODE_HS_52MHz)
- mmc->tran_speed = 52000000;
- else
- mmc->tran_speed = 26000000;
- }
- }
-
mmc_set_clock(mmc, mmc->tran_speed);
/* Fix the block length for DDR mode */
}
/* fill in device description */
- mmc->block_dev.lun = 0;
- mmc->block_dev.hwpart = 0;
- mmc->block_dev.type = 0;
- mmc->block_dev.blksz = mmc->read_bl_len;
- mmc->block_dev.log2blksz = LOG2(mmc->block_dev.blksz);
- mmc->block_dev.lba = lldiv(mmc->capacity, mmc->read_bl_len);
+ bdesc = mmc_get_blk_desc(mmc);
+ bdesc->lun = 0;
+ bdesc->hwpart = 0;
+ bdesc->type = 0;
+ bdesc->blksz = mmc->read_bl_len;
+ bdesc->log2blksz = LOG2(bdesc->blksz);
+ bdesc->lba = lldiv(mmc->capacity, mmc->read_bl_len);
#if !defined(CONFIG_SPL_BUILD) || \
(defined(CONFIG_SPL_LIBCOMMON_SUPPORT) && \
!defined(CONFIG_USE_TINY_PRINTF))
- sprintf(mmc->block_dev.vendor, "Man %06x Snr %04x%04x",
+ sprintf(bdesc->vendor, "Man %06x Snr %04x%04x",
mmc->cid[0] >> 24, (mmc->cid[2] & 0xffff),
(mmc->cid[3] >> 16) & 0xffff);
- sprintf(mmc->block_dev.product, "%c%c%c%c%c%c", mmc->cid[0] & 0xff,
+ sprintf(bdesc->product, "%c%c%c%c%c%c", mmc->cid[0] & 0xff,
(mmc->cid[1] >> 24), (mmc->cid[1] >> 16) & 0xff,
(mmc->cid[1] >> 8) & 0xff, mmc->cid[1] & 0xff,
(mmc->cid[2] >> 24) & 0xff);
- sprintf(mmc->block_dev.revision, "%d.%d", (mmc->cid[2] >> 20) & 0xf,
+ sprintf(bdesc->revision, "%d.%d", (mmc->cid[2] >> 20) & 0xf,
(mmc->cid[2] >> 16) & 0xf);
#else
- mmc->block_dev.vendor[0] = 0;
- mmc->block_dev.product[0] = 0;
- mmc->block_dev.revision[0] = 0;
+ bdesc->vendor[0] = 0;
+ bdesc->product[0] = 0;
+ bdesc->revision[0] = 0;
#endif
#if !defined(CONFIG_SPL_BUILD) || defined(CONFIG_SPL_LIBDISK_SUPPORT)
- part_init(&mmc->block_dev);
+ part_init(bdesc);
#endif
return 0;
return err;
if ((cmd.response[0] & 0xff) != 0xaa)
- return UNUSABLE_ERR;
+ return -EOPNOTSUPP;
else
mmc->version = SD_VERSION_2;
return 0;
}
-/* not used any more */
-int __deprecated mmc_register(struct mmc *mmc)
+#if !CONFIG_IS_ENABLED(DM_MMC)
+/* board-specific MMC power initializations. */
+__weak void board_mmc_power_init(void)
{
-#if !defined(CONFIG_SPL_BUILD) || defined(CONFIG_SPL_LIBCOMMON_SUPPORT)
- printf("%s is deprecated! use mmc_create() instead.\n", __func__);
-#endif
- return -1;
}
+#endif
-struct mmc *mmc_create(const struct mmc_config *cfg, void *priv)
+static int mmc_power_init(struct mmc *mmc)
{
- struct mmc *mmc;
-
- /* quick validation */
- if (cfg == NULL || cfg->ops == NULL || cfg->ops->send_cmd == NULL ||
- cfg->f_min == 0 || cfg->f_max == 0 || cfg->b_max == 0)
- return NULL;
-
- mmc = calloc(1, sizeof(*mmc));
- if (mmc == NULL)
- return NULL;
-
- mmc->cfg = cfg;
- mmc->priv = priv;
-
- /* the following chunk was mmc_register() */
-
- /* Setup dsr related values */
- mmc->dsr_imp = 0;
- mmc->dsr = 0xffffffff;
- /* Setup the universal parts of the block interface just once */
- mmc->block_dev.if_type = IF_TYPE_MMC;
- mmc->block_dev.devnum = cur_dev_num++;
- mmc->block_dev.removable = 1;
- mmc->block_dev.block_read = mmc_bread;
- mmc->block_dev.block_write = mmc_bwrite;
- mmc->block_dev.block_erase = mmc_berase;
-
- /* setup initial part type */
- mmc->block_dev.part_type = mmc->cfg->part_type;
-
- INIT_LIST_HEAD(&mmc->link);
-
- list_add_tail(&mmc->link, &mmc_devices);
-
- return mmc;
-}
+#if CONFIG_IS_ENABLED(DM_MMC)
+#if CONFIG_IS_ENABLED(DM_REGULATOR)
+ int ret;
-void mmc_destroy(struct mmc *mmc)
-{
- /* only freeing memory for now */
- free(mmc);
-}
+ ret = device_get_supply_regulator(mmc->dev, "vmmc-supply",
+ &mmc->vmmc_supply);
+ if (ret)
+ debug("%s: No vmmc supply\n", mmc->dev->name);
-#ifdef CONFIG_PARTITIONS
-struct blk_desc *mmc_get_dev(int dev)
-{
- struct mmc *mmc = find_mmc_device(dev);
- if (!mmc || mmc_init(mmc))
- return NULL;
+ ret = device_get_supply_regulator(mmc->dev, "vqmmc-supply",
+ &mmc->vqmmc_supply);
+ if (ret)
+ debug("%s: No vqmmc supply\n", mmc->dev->name);
- return &mmc->block_dev;
-}
+ if (mmc->vmmc_supply) {
+ ret = regulator_set_enable(mmc->vmmc_supply, true);
+ if (ret) {
+ puts("Error enabling VMMC supply\n");
+ return ret;
+ }
+ }
#endif
-
-/* board-specific MMC power initializations. */
-__weak void board_mmc_power_init(void)
-{
+#else /* !CONFIG_DM_MMC */
+ /*
+ * Driver model should use a regulator, as above, rather than calling
+ * out to board code.
+ */
+ board_mmc_power_init();
+#endif
+ return 0;
}
int mmc_start_init(struct mmc *mmc)
{
+ bool no_card;
int err;
/* we pretend there's no card when init is NULL */
- if (mmc_getcd(mmc) == 0 || mmc->cfg->ops->init == 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 NO_CARD_ERR;
+ return -ENOMEDIUM;
}
if (mmc->has_init)
#ifdef CONFIG_FSL_ESDHC_ADAPTER_IDENT
mmc_adapter_card_type_ident();
#endif
- board_mmc_power_init();
+ err = mmc_power_init(mmc);
+ if (err)
+ return err;
+#if CONFIG_IS_ENABLED(DM_MMC)
+ /* The device has already been probed ready for use */
+#else
/* made sure it's not NULL earlier */
err = mmc->cfg->ops->init(mmc);
-
if (err)
return err;
-
+#endif
mmc->ddr_mode = 0;
mmc_set_bus_width(mmc, 1);
mmc_set_clock(mmc, 1);
return err;
/* The internal partition reset to user partition(0) at every CMD0*/
- mmc->block_dev.hwpart = 0;
+ mmc_get_blk_desc(mmc)->hwpart = 0;
/* Test for SD version 2 */
err = mmc_send_if_cond(mmc);
err = sd_send_op_cond(mmc);
/* If the command timed out, we check for an MMC card */
- if (err == TIMEOUT) {
+ if (err == -ETIMEDOUT) {
err = mmc_send_op_cond(mmc);
if (err) {
#if !defined(CONFIG_SPL_BUILD) || defined(CONFIG_SPL_LIBCOMMON_SUPPORT)
printf("Card did not respond to voltage select!\n");
#endif
- return UNUSABLE_ERR;
+ return -EOPNOTSUPP;
}
}
int mmc_init(struct mmc *mmc)
{
int err = 0;
- unsigned start;
+ __maybe_unused unsigned start;
+#if CONFIG_IS_ENABLED(DM_MMC)
+ struct mmc_uclass_priv *upriv = dev_get_uclass_priv(mmc->dev);
+ upriv->mmc = mmc;
+#endif
if (mmc->has_init)
return 0;
if (!err)
err = mmc_complete_init(mmc);
- debug("%s: %d, time %lu\n", __func__, err, get_timer(start));
+ if (err)
+ printf("%s: %d, time %lu\n", __func__, err, get_timer(start));
+
return err;
}
return -1;
}
-#if !defined(CONFIG_SPL_BUILD) || defined(CONFIG_SPL_LIBCOMMON_SUPPORT)
-
-void print_mmc_devices(char separator)
-{
- struct mmc *m;
- struct list_head *entry;
- char *mmc_type;
-
- list_for_each(entry, &mmc_devices) {
- m = list_entry(entry, struct mmc, link);
-
- if (m->has_init)
- mmc_type = IS_SD(m) ? "SD" : "eMMC";
- else
- mmc_type = NULL;
-
- printf("%s: %d", m->cfg->name, m->block_dev.devnum);
- if (mmc_type)
- printf(" (%s)", mmc_type);
-
- if (entry->next != &mmc_devices) {
- printf("%c", separator);
- if (separator != '\n')
- puts (" ");
- }
- }
-
- printf("\n");
-}
-
-#else
-void print_mmc_devices(char separator) { }
-#endif
-
-int get_mmc_num(void)
-{
- return cur_dev_num;
-}
-
void mmc_set_preinit(struct mmc *mmc, int preinit)
{
mmc->preinit = preinit;
}
-static void do_preinit(void)
-{
- struct mmc *m;
- struct list_head *entry;
-
- list_for_each(entry, &mmc_devices) {
- m = list_entry(entry, struct mmc, link);
-
-#ifdef CONFIG_FSL_ESDHC_ADAPTER_IDENT
- mmc_set_preinit(m, 1);
-#endif
- if (m->preinit)
- mmc_start_init(m);
- }
-}
-
-#if defined(CONFIG_DM_MMC) && defined(CONFIG_SPL_BUILD)
+#if CONFIG_IS_ENABLED(DM_MMC) && defined(CONFIG_SPL_BUILD)
static int mmc_probe(bd_t *bis)
{
return 0;
}
-#elif defined(CONFIG_DM_MMC)
+#elif CONFIG_IS_ENABLED(DM_MMC)
static int mmc_probe(bd_t *bis)
{
int ret, i;
return 0;
initialized = 1;
- INIT_LIST_HEAD (&mmc_devices);
- cur_dev_num = 0;
-
+#if !CONFIG_IS_ENABLED(BLK)
+#if !CONFIG_IS_ENABLED(MMC_TINY)
+ mmc_list_init();
+#endif
+#endif
ret = mmc_probe(bis);
if (ret)
return ret;
print_mmc_devices(',');
#endif
- do_preinit();
+ mmc_do_preinit();
return 0;
}
-#ifdef CONFIG_SUPPORT_EMMC_BOOT
-/*
- * This function changes the size of boot partition and the size of rpmb
- * partition present on EMMC devices.
- *
- * Input Parameters:
- * struct *mmc: pointer for the mmc device strcuture
- * bootsize: size of boot partition
- * rpmbsize: size of rpmb partition
- *
- * Returns 0 on success.
- */
-
-int mmc_boot_partition_size_change(struct mmc *mmc, unsigned long bootsize,
- unsigned long rpmbsize)
+#ifdef CONFIG_CMD_BKOPS_ENABLE
+int mmc_set_bkops_enable(struct mmc *mmc)
{
int err;
- struct mmc_cmd cmd;
-
- /* Only use this command for raw EMMC moviNAND. Enter backdoor mode */
- cmd.cmdidx = MMC_CMD_RES_MAN;
- cmd.resp_type = MMC_RSP_R1b;
- cmd.cmdarg = MMC_CMD62_ARG1;
+ ALLOC_CACHE_ALIGN_BUFFER(u8, ext_csd, MMC_MAX_BLOCK_LEN);
- err = mmc_send_cmd(mmc, &cmd, NULL);
+ err = mmc_send_ext_csd(mmc, ext_csd);
if (err) {
- debug("mmc_boot_partition_size_change: Error1 = %d\n", err);
+ puts("Could not get ext_csd register values\n");
return err;
}
- /* Boot partition changing mode */
- cmd.cmdidx = MMC_CMD_RES_MAN;
- cmd.resp_type = MMC_RSP_R1b;
- cmd.cmdarg = MMC_CMD62_ARG2;
-
- err = mmc_send_cmd(mmc, &cmd, NULL);
- if (err) {
- debug("mmc_boot_partition_size_change: Error2 = %d\n", err);
- return err;
+ if (!(ext_csd[EXT_CSD_BKOPS_SUPPORT] & 0x1)) {
+ puts("Background operations not supported on device\n");
+ return -EMEDIUMTYPE;
}
- /* boot partition size is multiple of 128KB */
- bootsize = (bootsize * 1024) / 128;
- /* Arg: boot partition size */
- cmd.cmdidx = MMC_CMD_RES_MAN;
- cmd.resp_type = MMC_RSP_R1b;
- cmd.cmdarg = bootsize;
-
- err = mmc_send_cmd(mmc, &cmd, NULL);
- if (err) {
- debug("mmc_boot_partition_size_change: Error3 = %d\n", err);
- return err;
+ if (ext_csd[EXT_CSD_BKOPS_EN] & 0x1) {
+ puts("Background operations already enabled\n");
+ return 0;
}
- /* RPMB partition size is multiple of 128KB */
- rpmbsize = (rpmbsize * 1024) / 128;
- /* Arg: RPMB partition size */
- cmd.cmdidx = MMC_CMD_RES_MAN;
- cmd.resp_type = MMC_RSP_R1b;
- cmd.cmdarg = rpmbsize;
- err = mmc_send_cmd(mmc, &cmd, NULL);
+ err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL, EXT_CSD_BKOPS_EN, 1);
if (err) {
- debug("mmc_boot_partition_size_change: Error4 = %d\n", err);
+ puts("Failed to enable manual background operations\n");
return err;
}
- return 0;
-}
-
-/*
- * Modify EXT_CSD[177] which is BOOT_BUS_WIDTH
- * based on the passed in values for BOOT_BUS_WIDTH, RESET_BOOT_BUS_WIDTH
- * and BOOT_MODE.
- *
- * Returns 0 on success.
- */
-int mmc_set_boot_bus_width(struct mmc *mmc, u8 width, u8 reset, u8 mode)
-{
- int err;
-
- err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL, EXT_CSD_BOOT_BUS_WIDTH,
- EXT_CSD_BOOT_BUS_WIDTH_MODE(mode) |
- EXT_CSD_BOOT_BUS_WIDTH_RESET(reset) |
- EXT_CSD_BOOT_BUS_WIDTH_WIDTH(width));
-
- if (err)
- return err;
- return 0;
-}
-
-/*
- * Modify EXT_CSD[179] which is PARTITION_CONFIG (formerly BOOT_CONFIG)
- * based on the passed in values for BOOT_ACK, BOOT_PARTITION_ENABLE and
- * PARTITION_ACCESS.
- *
- * Returns 0 on success.
- */
-int mmc_set_part_conf(struct mmc *mmc, u8 ack, u8 part_num, u8 access)
-{
- int err;
- err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL, EXT_CSD_PART_CONF,
- EXT_CSD_BOOT_ACK(ack) |
- EXT_CSD_BOOT_PART_NUM(part_num) |
- EXT_CSD_PARTITION_ACCESS(access));
+ puts("Enabled manual background operations\n");
- if (err)
- return err;
return 0;
}
-
-/*
- * Modify EXT_CSD[162] which is RST_n_FUNCTION based on the given value
- * for enable. Note that this is a write-once field for non-zero values.
- *
- * Returns 0 on success.
- */
-int mmc_set_rst_n_function(struct mmc *mmc, u8 enable)
-{
- return mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL, EXT_CSD_RST_N_FUNCTION,
- enable);
-}
#endif