- mmc spi driver model support
- drop mmc_spi command
- enhanced Strobe mmc HS400 support
- minor mmc bug/fixes and optimization
- omap hsmmc and mvbeu update
- sdhci card detect support
This commit is contained in:
Tom Rini 2019-07-15 09:42:41 -04:00
commit 6674dc77c2
17 changed files with 672 additions and 432 deletions

View File

@ -955,15 +955,6 @@ config CMD_NVME
help
NVM Express device support
config CMD_MMC_SPI
bool "mmc_spi - Set up MMC SPI device"
help
Provides a way to set up an MMC (Multimedia Card) SPI (Serial
Peripheral Interface) device. The device provides a means of
accessing an MMC device via SPI using a single data line, limited
to 20MHz. It is useful since it reduces the amount of protocol code
required.
config CMD_ONENAND
bool "onenand - access to onenand device"
help

View File

@ -93,7 +93,6 @@ obj-$(CONFIG_CMD_MII) += mdio.o
endif
obj-$(CONFIG_CMD_MISC) += misc.o
obj-$(CONFIG_CMD_MMC) += mmc.o
obj-$(CONFIG_CMD_MMC_SPI) += mmc_spi.o
obj-$(CONFIG_MP) += mp.o
obj-$(CONFIG_CMD_MTD) += mtd.o
obj-$(CONFIG_CMD_MTDPARTS) += mtdparts.o

View File

@ -1,88 +0,0 @@
/*
* Command for mmc_spi setup.
*
* Copyright (C) 2010 Thomas Chou <thomas@wytron.com.tw>
* Licensed under the GPL-2 or later.
*/
#include <common.h>
#include <mmc.h>
#include <spi.h>
#ifndef CONFIG_MMC_SPI_BUS
# define CONFIG_MMC_SPI_BUS 0
#endif
#ifndef CONFIG_MMC_SPI_CS
# define CONFIG_MMC_SPI_CS 1
#endif
/* in SPI mode, MMC speed limit is 20MHz, while SD speed limit is 25MHz */
#ifndef CONFIG_MMC_SPI_SPEED
# define CONFIG_MMC_SPI_SPEED 25000000
#endif
/* MMC and SD specs only seem to care that sampling is on the
* rising edge ... meaning SPI modes 0 or 3. So either SPI mode
* should be legit. We'll use mode 0 since the steady state is 0,
* which is appropriate for hotplugging, unless the platform data
* specify mode 3 (if hardware is not compatible to mode 0).
*/
#ifndef CONFIG_MMC_SPI_MODE
# define CONFIG_MMC_SPI_MODE SPI_MODE_0
#endif
static int do_mmc_spi(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
{
uint bus = CONFIG_MMC_SPI_BUS;
uint cs = CONFIG_MMC_SPI_CS;
uint speed = CONFIG_MMC_SPI_SPEED;
uint mode = CONFIG_MMC_SPI_MODE;
char *endp;
struct mmc *mmc;
if (argc < 2)
goto usage;
cs = simple_strtoul(argv[1], &endp, 0);
if (*argv[1] == 0 || (*endp != 0 && *endp != ':'))
goto usage;
if (*endp == ':') {
if (endp[1] == 0)
goto usage;
bus = cs;
cs = simple_strtoul(endp + 1, &endp, 0);
if (*endp != 0)
goto usage;
}
if (argc >= 3) {
speed = simple_strtoul(argv[2], &endp, 0);
if (*argv[2] == 0 || *endp != 0)
goto usage;
}
if (argc >= 4) {
mode = simple_strtoul(argv[3], &endp, 16);
if (*argv[3] == 0 || *endp != 0)
goto usage;
}
if (!spi_cs_is_valid(bus, cs)) {
printf("Invalid SPI bus %u cs %u\n", bus, cs);
return 1;
}
mmc = mmc_spi_init(bus, cs, speed, mode);
if (!mmc) {
printf("Failed to create MMC Device\n");
return 1;
}
printf("%s: %d at %u:%u hz %u mode %u\n", mmc->cfg->name,
mmc->block_dev.devnum, bus, cs, speed, mode);
mmc_init(mmc);
return 0;
usage:
return CMD_RET_USAGE;
}
U_BOOT_CMD(
mmc_spi, 4, 0, do_mmc_spi,
"mmc_spi setup",
"[bus:]cs [hz] [mode] - setup mmc_spi device"
);

View File

@ -46,6 +46,24 @@ config SPL_DM_MMC
if MMC
config MMC_SPI
bool "Support for SPI-based MMC controller"
depends on DM_MMC && DM_SPI
help
This selects SPI-based MMC controllers.
If you have an MMC controller on a SPI bus, say Y here.
If unsure, say N.
config MMC_SPI_CRC_ON
bool "Support CRC for SPI-based MMC controller"
depends on MMC_SPI
default y
help
This enables CRC for SPI-based MMC controllers.
If unsure, say N.
config ARM_PL180_MMCI
bool "ARM AMBA Multimedia Card Interface and compatible support"
depends on DM_MMC && OF_CONTROL
@ -117,6 +135,18 @@ config SPL_MMC_UHS_SUPPORT
cards. The IO voltage must be switchable from 3.3v to 1.8v. The bus
frequency can go up to 208MHz (SDR104)
config MMC_HS400_ES_SUPPORT
bool "enable HS400 Enhanced Strobe support"
help
The HS400 Enhanced Strobe mode is support by some eMMC. The bus
frequency is up to 200MHz. This mode does not tune the IO.
config SPL_MMC_HS400_ES_SUPPORT
bool "enable HS400 Enhanced Strobe support in SPL"
help
The HS400 Enhanced Strobe mode is support by some eMMC. The bus
frequency is up to 200MHz. This mode does not tune the IO.
config MMC_HS400_SUPPORT
bool "enable HS400 support"
select MMC_HS200_SUPPORT

View File

@ -101,7 +101,6 @@ struct fsl_esdhc_plat {
struct esdhc_soc_data {
u32 flags;
u32 caps;
};
/**
@ -146,7 +145,7 @@ struct fsl_esdhc_priv {
u32 tuning_start_tap;
u32 strobe_dll_delay_target;
u32 signal_voltage;
#if IS_ENABLED(CONFIG_DM_REGULATOR)
#if CONFIG_IS_ENABLED(DM_REGULATOR)
struct udevice *vqmmc_dev;
struct udevice *vmmc_dev;
#endif
@ -514,9 +513,9 @@ static int esdhc_send_cmd_common(struct fsl_esdhc_priv *priv, struct mmc *mmc,
/* Workaround for ESDHC errata ENGcm03648 */
if (!data && (cmd->resp_type & MMC_RSP_BUSY)) {
int timeout = 6000;
int timeout = 50000;
/* Poll on DATA0 line for cmd with busy signal for 600 ms */
/* Poll on DATA0 line for cmd with busy signal for 5000 ms */
while (timeout > 0 && !(esdhc_read32(&regs->prsstat) &
PRSSTAT_DAT0)) {
udelay(100);
@ -704,6 +703,7 @@ static int esdhc_change_pinstate(struct udevice *dev)
case UHS_SDR104:
case MMC_HS_200:
case MMC_HS_400:
case MMC_HS_400_ES:
ret = pinctrl_select_state(dev, "state_200mhz");
break;
default:
@ -774,6 +774,7 @@ static int esdhc_set_timing(struct mmc *mmc)
writel(mixctrl, &regs->mixctrl);
break;
case MMC_HS_400:
case MMC_HS_400_ES:
mixctrl |= MIX_CTRL_DDREN | MIX_CTRL_HS400_EN;
writel(mixctrl, &regs->mixctrl);
esdhc_set_strobe_dll(mmc);
@ -1426,10 +1427,8 @@ static int fsl_esdhc_probe(struct udevice *dev)
priv->esdhc_regs = (struct fsl_esdhc *)addr;
priv->dev = dev;
priv->mode = -1;
if (data) {
if (data)
priv->flags = data->flags;
priv->caps = data->caps;
}
val = dev_read_u32_default(dev, "bus-width", -1);
if (val == 8)
@ -1490,9 +1489,6 @@ static int fsl_esdhc_probe(struct udevice *dev)
}
#endif
if (fdt_get_property(fdt, node, "no-1-8-v", NULL))
priv->caps &= ~(UHS_CAPS | MMC_MODE_HS200 | MMC_MODE_HS400);
/*
* TODO:
* Because lack of clk driver, if SDHC clk is not enabled,
@ -1515,7 +1511,7 @@ static int fsl_esdhc_probe(struct udevice *dev)
init_clk_usdhc(dev->seq);
if (IS_ENABLED(CONFIG_CLK)) {
if (CONFIG_IS_ENABLED(CLK)) {
/* Assigned clock already set clock */
ret = clk_get_by_name(dev, "per", &priv->per_clk);
if (ret) {
@ -1543,6 +1539,10 @@ static int fsl_esdhc_probe(struct udevice *dev)
return ret;
}
ret = mmc_of_parse(dev, &plat->cfg);
if (ret)
return ret;
mmc = &plat->mmc;
mmc->cfg = &plat->cfg;
mmc->dev = dev;
@ -1596,6 +1596,21 @@ static int fsl_esdhc_set_ios(struct udevice *dev)
return esdhc_set_ios_common(priv, &plat->mmc);
}
#if CONFIG_IS_ENABLED(MMC_HS400_ES_SUPPORT)
static int fsl_esdhc_set_enhanced_strobe(struct udevice *dev)
{
struct fsl_esdhc_priv *priv = dev_get_priv(dev);
struct fsl_esdhc *regs = priv->esdhc_regs;
u32 m;
m = readl(&regs->mixctrl);
m |= MIX_CTRL_HS400_ES;
writel(m, &regs->mixctrl);
return 0;
}
#endif
static const struct dm_mmc_ops fsl_esdhc_ops = {
.get_cd = fsl_esdhc_get_cd,
.send_cmd = fsl_esdhc_send_cmd,
@ -1603,6 +1618,9 @@ static const struct dm_mmc_ops fsl_esdhc_ops = {
#ifdef MMC_SUPPORTS_TUNING
.execute_tuning = fsl_esdhc_execute_tuning,
#endif
#if CONFIG_IS_ENABLED(MMC_HS400_ES_SUPPORT)
.set_enhanced_strobe = fsl_esdhc_set_enhanced_strobe,
#endif
};
#endif
@ -1610,8 +1628,12 @@ static struct esdhc_soc_data usdhc_imx7d_data = {
.flags = ESDHC_FLAG_USDHC | ESDHC_FLAG_STD_TUNING
| ESDHC_FLAG_HAVE_CAP1 | ESDHC_FLAG_HS200
| ESDHC_FLAG_HS400,
.caps = UHS_CAPS | MMC_MODE_HS200 | MMC_MODE_DDR_52MHz |
MMC_MODE_HS_52MHz | MMC_MODE_HS,
};
static struct esdhc_soc_data usdhc_imx8qm_data = {
.flags = ESDHC_FLAG_USDHC | ESDHC_FLAG_STD_TUNING |
ESDHC_FLAG_HAVE_CAP1 | ESDHC_FLAG_HS200 |
ESDHC_FLAG_HS400 | ESDHC_FLAG_HS400_ES,
};
static const struct udevice_id fsl_esdhc_ids[] = {
@ -1622,6 +1644,7 @@ static const struct udevice_id fsl_esdhc_ids[] = {
{ .compatible = "fsl,imx6q-usdhc", },
{ .compatible = "fsl,imx7d-usdhc", .data = (ulong)&usdhc_imx7d_data,},
{ .compatible = "fsl,imx7ulp-usdhc", },
{ .compatible = "fsl,imx8qm-usdhc", .data = (ulong)&usdhc_imx8qm_data,},
{ .compatible = "fsl,esdhc", },
{ /* sentinel */ }
};

View File

@ -47,20 +47,6 @@ int mmc_set_ios(struct mmc *mmc)
return dm_mmc_set_ios(mmc->dev);
}
void dm_mmc_send_init_stream(struct udevice *dev)
{
struct dm_mmc_ops *ops = mmc_get_ops(dev);
if (ops->send_init_stream)
ops->send_init_stream(dev);
}
void mmc_send_init_stream(struct mmc *mmc)
{
dm_mmc_send_init_stream(mmc->dev);
}
#if CONFIG_IS_ENABLED(MMC_UHS_SUPPORT)
int dm_mmc_wait_dat0(struct udevice *dev, int state, int timeout)
{
struct dm_mmc_ops *ops = mmc_get_ops(dev);
@ -74,7 +60,6 @@ int mmc_wait_dat0(struct mmc *mmc, int state, int timeout)
{
return dm_mmc_wait_dat0(mmc->dev, state, timeout);
}
#endif
int dm_mmc_get_wp(struct udevice *dev)
{
@ -120,6 +105,23 @@ int mmc_execute_tuning(struct mmc *mmc, uint opcode)
}
#endif
#if CONFIG_IS_ENABLED(MMC_HS400_ES_SUPPORT)
int dm_mmc_set_enhanced_strobe(struct udevice *dev)
{
struct dm_mmc_ops *ops = mmc_get_ops(dev);
if (ops->set_enhanced_strobe)
return ops->set_enhanced_strobe(dev);
return -ENOTSUPP;
}
int mmc_set_enhanced_strobe(struct mmc *mmc)
{
return dm_mmc_set_enhanced_strobe(mmc->dev);
}
#endif
int mmc_of_parse(struct udevice *dev, struct mmc_config *cfg)
{
int val;
@ -170,6 +172,22 @@ int mmc_of_parse(struct udevice *dev, struct mmc_config *cfg)
cfg->host_caps |= MMC_CAP(MMC_HS_400);
if (dev_read_bool(dev, "mmc-hs400-1_2v"))
cfg->host_caps |= MMC_CAP(MMC_HS_400);
if (dev_read_bool(dev, "mmc-hs400-enhanced-strobe"))
cfg->host_caps |= MMC_CAP(MMC_HS_400_ES);
if (dev_read_bool(dev, "non-removable")) {
cfg->host_caps |= MMC_CAP_NONREMOVABLE;
} else {
if (dev_read_bool(dev, "cd-inverted"))
cfg->host_caps |= MMC_CAP_CD_ACTIVE_HIGH;
if (dev_read_bool(dev, "broken-cd"))
cfg->host_caps |= MMC_CAP_NEEDS_POLL;
}
if (dev_read_bool(dev, "no-1-8-v")) {
cfg->host_caps &= ~(UHS_CAPS | MMC_MODE_HS200 |
MMC_MODE_HS400 | MMC_MODE_HS400_ES);
}
return 0;
}

View File

@ -21,6 +21,8 @@
#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)
@ -29,12 +31,10 @@ static int mmc_select_mode_and_width(struct mmc *mmc, uint card_caps);
#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)
{
@ -148,6 +148,7 @@ const char *mmc_mode_name(enum bus_mode mode)
[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)
@ -173,6 +174,7 @@ static uint mmc_mode2freq(struct mmc *mmc, enum bus_mode mode)
[UHS_SDR104] = 208000000,
[MMC_HS_200] = 200000000,
[MMC_HS_400] = 200000000,
[MMC_HS_400_ES] = 200000000,
};
if (mode == MMC_LEGACY)
@ -206,7 +208,7 @@ int mmc_send_cmd(struct mmc *mmc, struct mmc_cmd *cmd, struct mmc_data *data)
}
#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;
@ -216,31 +218,50 @@ int mmc_send_status(struct mmc *mmc, int timeout)
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) {
#if !defined(CONFIG_SPL_BUILD) || defined(CONFIG_SPL_LIBCOMMON_SUPPORT)
pr_err("Status Error: 0x%08x\n",
cmd.response[0]);
#endif
return -ECOMM;
}
} else if (--retries < 0)
int mmc_poll_for_busy(struct mmc *mmc, int timeout)
{
unsigned int status;
int err;
err = mmc_wait_dat0(mmc, 1, timeout);
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", status);
#endif
return -ECOMM;
}
if (timeout-- <= 0)
break;
udelay(1000);
}
mmc_trace_state(mmc, &cmd);
if (timeout <= 0) {
#if !defined(CONFIG_SPL_BUILD) || defined(CONFIG_SPL_LIBCOMMON_SUPPORT)
pr_err("Timeout waiting card ready\n");
@ -727,36 +748,67 @@ static int mmc_send_ext_csd(struct mmc *mmc, u8 *ext_csd)
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 = DEFAULT_CMD6_TIMEOUT_MS;
bool is_part_switch = (set == EXT_CSD_CMD_SET_NORMAL) &&
(index == EXT_CSD_PART_CONF);
int retries = 3;
int ret;
if (mmc->gen_cmd6_time)
timeout = mmc->gen_cmd6_time * 10;
if (is_part_switch && mmc->part_switch_time)
timeout = 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);
if (ret) {
retries--;
continue;
if (ret)
return ret;
start = get_timer(0);
/* poll dat0 for rdy/buys status */
ret = mmc_wait_dat0(mmc, 1, timeout);
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);
/* Finally wait until the card is ready or indicates a failure
* to switch. It doesn't hurt to use CMD13 here even if send_status
* is false, because by now (after 'timeout' ms) the bus should be
* 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 (!send_status) {
mdelay(50);
if (!ret && (status & MMC_STATUS_RDY_FOR_DATA))
return 0;
}
/* Waiting for the ready status */
return mmc_send_status(mmc, timeout);
}
return ret;
udelay(100);
} while (get_timer(start) < timeout);
return -ETIMEDOUT;
}
int mmc_switch(struct mmc *mmc, u8 set, u8 index, u8 value)
@ -788,6 +840,11 @@ static int mmc_set_card_speed(struct mmc *mmc, enum bus_mode mode,
case MMC_HS_400:
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;
@ -859,7 +916,8 @@ static int mmc_get_capabilities(struct mmc *mmc)
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;
@ -873,6 +931,13 @@ static int mmc_get_capabilities(struct mmc *mmc)
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
@ -905,49 +970,17 @@ static int mmc_set_capacity(struct mmc *mmc, int part_num)
return 0;
}
#if CONFIG_IS_ENABLED(MMC_HS200_SUPPORT) || CONFIG_IS_ENABLED(MMC_HS400_SUPPORT)
static int mmc_boot_part_access_chk(struct mmc *mmc, unsigned int part_num)
{
int forbidden = 0;
bool change = false;
if (part_num & PART_ACCESS_MASK)
forbidden = MMC_CAP(MMC_HS_200) | MMC_CAP(MMC_HS_400);
if (MMC_CAP(mmc->selected_mode) & forbidden) {
pr_debug("selected mode (%s) is forbidden for part %d\n",
mmc_mode_name(mmc->selected_mode), part_num);
change = true;
} else if (mmc->selected_mode != mmc->best_mode) {
pr_debug("selected mode is not optimal\n");
change = true;
}
if (change)
return mmc_select_mode_and_width(mmc,
mmc->card_caps & ~forbidden);
return 0;
}
#else
static inline int mmc_boot_part_access_chk(struct mmc *mmc,
unsigned int part_num)
{
return 0;
}
#endif
int mmc_switch_part(struct mmc *mmc, unsigned int part_num)
{
int ret;
int retry = 3;
ret = mmc_boot_part_access_chk(mmc, part_num);
if (ret)
return ret;
ret = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL, EXT_CSD_PART_CONF,
(mmc->part_config & ~PART_ACCESS_MASK)
| (part_num & PART_ACCESS_MASK));
do {
ret = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL,
EXT_CSD_PART_CONF,
(mmc->part_config & ~PART_ACCESS_MASK)
| (part_num & PART_ACCESS_MASK));
} while (ret && retry--);
/*
* Set the capacity if the switch succeeded or was intended
@ -1504,10 +1537,6 @@ static int mmc_execute_tuning(struct mmc *mmc, uint opcode)
}
#endif
static void mmc_send_init_stream(struct mmc *mmc)
{
}
static int mmc_set_ios(struct mmc *mmc)
{
int ret = 0;
@ -1672,6 +1701,13 @@ static int sd_select_mode_and_width(struct mmc *mmc, uint card_caps)
mmc_dump_capabilities("host", mmc->host_caps);
#endif
if (mmc_host_is_spi(mmc)) {
mmc_set_bus_width(mmc, 1);
mmc_select_mode(mmc, SD_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;
@ -1778,6 +1814,7 @@ static int mmc_set_lowest_voltage(struct mmc *mmc, enum bus_mode mode,
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 |
@ -1820,6 +1857,12 @@ static inline int mmc_set_lowest_voltage(struct mmc *mmc, enum bus_mode mode,
#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,
@ -1917,6 +1960,47 @@ static int mmc_select_hs400(struct mmc *mmc)
}
#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);\
@ -1934,6 +2018,13 @@ static int mmc_select_mode_and_width(struct mmc *mmc, uint card_caps)
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;
@ -1988,6 +2079,13 @@ static int mmc_select_mode_and_width(struct mmc *mmc, uint card_caps)
printf("Select HS400 failed %d\n", err);
goto error;
}
} else if (mwt->mode == MMC_HS_400_ES) {
err = mmc_select_hs400es(mmc);
if (err) {
printf("Select HS400ES failed %d\n",
err);
goto error;
}
} else {
/* configure the bus speed (card) */
err = mmc_set_card_speed(mmc, mwt->mode, false);
@ -2122,6 +2220,9 @@ static int mmc_startup_v4(struct mmc *mmc)
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,
@ -2131,6 +2232,11 @@ static int mmc_startup_v4(struct mmc *mmc)
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) ||
@ -2664,7 +2770,6 @@ int mmc_get_op_cond(struct mmc *mmc)
retry:
mmc_set_initial_state(mmc);
mmc_send_init_stream(mmc);
/* Reset the Card */
err = mmc_go_idle(mmc);

View File

@ -11,10 +11,11 @@
#include <mmc.h>
extern int mmc_send_cmd(struct mmc *mmc, struct mmc_cmd *cmd,
struct mmc_data *data);
extern int mmc_send_status(struct mmc *mmc, int timeout);
extern int mmc_set_blocklen(struct mmc *mmc, int len);
int mmc_send_cmd(struct mmc *mmc, struct mmc_cmd *cmd, struct mmc_data *data);
int mmc_send_status(struct mmc *mmc, unsigned int *status);
int mmc_poll_for_busy(struct mmc *mmc, int timeout);
int mmc_set_blocklen(struct mmc *mmc, int len);
#ifdef CONFIG_FSL_ESDHC_ADAPTER_IDENT
void mmc_adapter_card_type_ident(void);
#endif

View File

@ -2,6 +2,8 @@
* generic mmc spi driver
*
* Copyright (C) 2010 Thomas Chou <thomas@wytron.com.tw>
* Copyright 2019 Bhargav Shah <bhargavshah1988@gmail.com>
*
* Licensed under the GPL-2 or later.
*/
#include <common.h>
@ -9,21 +11,23 @@
#include <malloc.h>
#include <part.h>
#include <mmc.h>
#include <spi.h>
#include <stdlib.h>
#include <u-boot/crc.h>
#include <linux/crc7.h>
#include <asm/byteorder.h>
#include <dm.h>
#include <spi.h>
/* MMC/SD in SPI mode reports R1 status always */
#define R1_SPI_IDLE (1 << 0)
#define R1_SPI_ERASE_RESET (1 << 1)
#define R1_SPI_ILLEGAL_COMMAND (1 << 2)
#define R1_SPI_COM_CRC (1 << 3)
#define R1_SPI_ERASE_SEQ (1 << 4)
#define R1_SPI_ADDRESS (1 << 5)
#define R1_SPI_PARAMETER (1 << 6)
#define R1_SPI_IDLE BIT(0)
#define R1_SPI_ERASE_RESET BIT(1)
#define R1_SPI_ILLEGAL_COMMAND BIT(2)
#define R1_SPI_COM_CRC BIT(3)
#define R1_SPI_ERASE_SEQ BIT(4)
#define R1_SPI_ADDRESS BIT(5)
#define R1_SPI_PARAMETER BIT(6)
/* R1 bit 7 is always zero, reuse this bit for error */
#define R1_SPI_ERROR (1 << 7)
#define R1_SPI_ERROR BIT(7)
/* Response tokens used to ack each block written: */
#define SPI_MMC_RESPONSE_CODE(x) ((x) & 0x1f)
@ -34,28 +38,45 @@
/* Read and write blocks start with these tokens and end with crc;
* on error, read tokens act like a subset of R2_SPI_* values.
*/
#define SPI_TOKEN_SINGLE 0xfe /* single block r/w, multiblock read */
#define SPI_TOKEN_MULTI_WRITE 0xfc /* multiblock write */
#define SPI_TOKEN_STOP_TRAN 0xfd /* terminate multiblock write */
/* single block write multiblock read */
#define SPI_TOKEN_SINGLE 0xfe
/* multiblock write */
#define SPI_TOKEN_MULTI_WRITE 0xfc
/* terminate multiblock write */
#define SPI_TOKEN_STOP_TRAN 0xfd
/* MMC SPI commands start with a start bit "0" and a transmit bit "1" */
#define MMC_SPI_CMD(x) (0x40 | (x & 0x3f))
#define MMC_SPI_CMD(x) (0x40 | (x))
/* bus capability */
#define MMC_SPI_VOLTAGE (MMC_VDD_32_33 | MMC_VDD_33_34)
#define MMC_SPI_MIN_CLOCK 400000 /* 400KHz to meet MMC spec */
#define MMC_SPI_VOLTAGE (MMC_VDD_32_33 | MMC_VDD_33_34)
#define MMC_SPI_MIN_CLOCK 400000 /* 400KHz to meet MMC spec */
#define MMC_SPI_MAX_CLOCK 25000000 /* SD/MMC legacy speed */
/* timeout value */
#define CTOUT 8
#define RTOUT 3000000 /* 1 sec */
#define WTOUT 3000000 /* 1 sec */
#define CMD_TIMEOUT 8
#define READ_TIMEOUT 3000000 /* 1 sec */
#define WRITE_TIMEOUT 3000000 /* 1 sec */
static uint mmc_spi_sendcmd(struct mmc *mmc, ushort cmdidx, u32 cmdarg)
struct mmc_spi_priv {
struct spi_slave *spi;
struct mmc_config cfg;
struct mmc mmc;
};
static int mmc_spi_sendcmd(struct udevice *dev,
ushort cmdidx, u32 cmdarg, u32 resp_type,
u8 *resp, u32 resp_size,
bool resp_match, u8 resp_match_value)
{
struct spi_slave *spi = mmc->priv;
u8 cmdo[7];
u8 r1;
int i;
int i, rpos = 0, ret = 0;
u8 cmdo[7], r;
debug("%s: cmd%d cmdarg=0x%x resp_type=0x%x "
"resp_size=%d resp_match=%d resp_match_value=0x%x\n",
__func__, cmdidx, cmdarg, resp_type,
resp_size, resp_match, resp_match_value);
cmdo[0] = 0xff;
cmdo[1] = MMC_SPI_CMD(cmdidx);
cmdo[2] = cmdarg >> 24;
@ -63,37 +84,79 @@ static uint mmc_spi_sendcmd(struct mmc *mmc, ushort cmdidx, u32 cmdarg)
cmdo[4] = cmdarg >> 8;
cmdo[5] = cmdarg;
cmdo[6] = (crc7(0, &cmdo[1], 5) << 1) | 0x01;
spi_xfer(spi, sizeof(cmdo) * 8, cmdo, NULL, 0);
for (i = 0; i < CTOUT; i++) {
spi_xfer(spi, 1 * 8, NULL, &r1, 0);
if (i && (r1 & 0x80) == 0) /* r1 response */
break;
}
debug("%s:cmd%d resp%d %x\n", __func__, cmdidx, i, r1);
return r1;
}
ret = dm_spi_xfer(dev, sizeof(cmdo) * 8, cmdo, NULL, 0);
if (ret)
return ret;
static uint mmc_spi_readdata(struct mmc *mmc, void *xbuf,
u32 bcnt, u32 bsize)
{
struct spi_slave *spi = mmc->priv;
u8 *buf = xbuf;
u8 r1;
u16 crc;
int i;
while (bcnt--) {
for (i = 0; i < RTOUT; i++) {
spi_xfer(spi, 1 * 8, NULL, &r1, 0);
if (r1 != 0xff) /* data token */
ret = dm_spi_xfer(dev, 1 * 8, NULL, &r, 0);
if (ret)
return ret;
if (!resp || !resp_size)
return 0;
debug("%s: cmd%d", __func__, cmdidx);
if (resp_match) {
r = ~resp_match_value;
i = CMD_TIMEOUT;
while (i--) {
ret = dm_spi_xfer(dev, 1 * 8, NULL, &r, 0);
if (ret)
return ret;
debug(" resp%d=0x%x", rpos, r);
rpos++;
if (r == resp_match_value)
break;
}
debug("%s:tok%d %x\n", __func__, i, r1);
if (!i && (r != resp_match_value))
return -ETIMEDOUT;
}
for (i = 0; i < resp_size; i++) {
if (i == 0 && resp_match) {
resp[i] = resp_match_value;
continue;
}
ret = dm_spi_xfer(dev, 1 * 8, NULL, &r, 0);
if (ret)
return ret;
debug(" resp%d=0x%x", rpos, r);
rpos++;
resp[i] = r;
}
debug("\n");
return 0;
}
static int mmc_spi_readdata(struct udevice *dev,
void *xbuf, u32 bcnt, u32 bsize)
{
u16 crc;
u8 *buf = xbuf, r1;
int i, ret = 0;
while (bcnt--) {
for (i = 0; i < READ_TIMEOUT; i++) {
ret = dm_spi_xfer(dev, 1 * 8, NULL, &r1, 0);
if (ret)
return ret;
if (r1 == SPI_TOKEN_SINGLE)
break;
}
debug("%s: data tok%d 0x%x\n", __func__, i, r1);
if (r1 == SPI_TOKEN_SINGLE) {
spi_xfer(spi, bsize * 8, NULL, buf, 0);
spi_xfer(spi, 2 * 8, NULL, &crc, 0);
ret = dm_spi_xfer(dev, bsize * 8, NULL, buf, 0);
if (ret)
return ret;
ret = dm_spi_xfer(dev, 2 * 8, NULL, &crc, 0);
if (ret)
return ret;
#ifdef CONFIG_MMC_SPI_CRC_ON
if (be_to_cpu16(crc16_ccitt(0, buf, bsize)) != crc) {
debug("%s: CRC error\n", mmc->cfg->name);
if (be16_to_cpu(crc16_ccitt(0, buf, bsize)) != crc) {
debug("%s: data crc error\n", __func__);
r1 = R1_SPI_COM_CRC;
break;
}
@ -105,48 +168,56 @@ static uint mmc_spi_readdata(struct mmc *mmc, void *xbuf,
}
buf += bsize;
}
return r1;
if (r1 & R1_SPI_COM_CRC)
ret = -ECOMM;
else if (r1) /* other errors */
ret = -ETIMEDOUT;
return ret;
}
static uint mmc_spi_writedata(struct mmc *mmc, const void *xbuf,
u32 bcnt, u32 bsize, int multi)
static int mmc_spi_writedata(struct udevice *dev, const void *xbuf,
u32 bcnt, u32 bsize, int multi)
{
struct spi_slave *spi = mmc->priv;
const u8 *buf = xbuf;
u8 r1;
u8 r1, tok[2];
u16 crc;
u8 tok[2];
int i;
int i, ret = 0;
tok[0] = 0xff;
tok[1] = multi ? SPI_TOKEN_MULTI_WRITE : SPI_TOKEN_SINGLE;
while (bcnt--) {
#ifdef CONFIG_MMC_SPI_CRC_ON
crc = cpu_to_be16(crc16_ccitt(0, (u8 *)buf, bsize));
#endif
spi_xfer(spi, 2 * 8, tok, NULL, 0);
spi_xfer(spi, bsize * 8, buf, NULL, 0);
spi_xfer(spi, 2 * 8, &crc, NULL, 0);
for (i = 0; i < CTOUT; i++) {
spi_xfer(spi, 1 * 8, NULL, &r1, 0);
dm_spi_xfer(dev, 2 * 8, tok, NULL, 0);
dm_spi_xfer(dev, bsize * 8, buf, NULL, 0);
dm_spi_xfer(dev, 2 * 8, &crc, NULL, 0);
for (i = 0; i < CMD_TIMEOUT; i++) {
dm_spi_xfer(dev, 1 * 8, NULL, &r1, 0);
if ((r1 & 0x10) == 0) /* response token */
break;
}
debug("%s:tok%d %x\n", __func__, i, r1);
debug("%s: data tok%d 0x%x\n", __func__, i, r1);
if (SPI_MMC_RESPONSE_CODE(r1) == SPI_RESPONSE_ACCEPTED) {
for (i = 0; i < WTOUT; i++) { /* wait busy */
spi_xfer(spi, 1 * 8, NULL, &r1, 0);
debug("%s: data accepted\n", __func__);
for (i = 0; i < WRITE_TIMEOUT; i++) { /* wait busy */
dm_spi_xfer(dev, 1 * 8, NULL, &r1, 0);
if (i && r1 == 0xff) {
r1 = 0;
break;
}
}
if (i == WTOUT) {
debug("%s:wtout %x\n", __func__, r1);
if (i == WRITE_TIMEOUT) {
debug("%s: data write timeout 0x%x\n",
__func__, r1);
r1 = R1_SPI_ERROR;
break;
}
} else {
debug("%s: err %x\n", __func__, r1);
debug("%s: data error 0x%x\n", __func__, r1);
r1 = R1_SPI_COM_CRC;
break;
}
@ -154,140 +225,204 @@ static uint mmc_spi_writedata(struct mmc *mmc, const void *xbuf,
}
if (multi && bcnt == -1) { /* stop multi write */
tok[1] = SPI_TOKEN_STOP_TRAN;
spi_xfer(spi, 2 * 8, tok, NULL, 0);
for (i = 0; i < WTOUT; i++) { /* wait busy */
spi_xfer(spi, 1 * 8, NULL, &r1, 0);
dm_spi_xfer(dev, 2 * 8, tok, NULL, 0);
for (i = 0; i < WRITE_TIMEOUT; i++) { /* wait busy */
dm_spi_xfer(dev, 1 * 8, NULL, &r1, 0);
if (i && r1 == 0xff) {
r1 = 0;
break;
}
}
if (i == WTOUT) {
debug("%s:wstop %x\n", __func__, r1);
if (i == WRITE_TIMEOUT) {
debug("%s: data write timeout 0x%x\n", __func__, r1);
r1 = R1_SPI_ERROR;
}
}
return r1;
}
static int mmc_spi_request(struct mmc *mmc, struct mmc_cmd *cmd,
struct mmc_data *data)
{
struct spi_slave *spi = mmc->priv;
u8 r1;
int i;
int ret = 0;
debug("%s:cmd%d %x %x\n", __func__,
cmd->cmdidx, cmd->resp_type, cmd->cmdarg);
spi_claim_bus(spi);
spi_cs_activate(spi);
r1 = mmc_spi_sendcmd(mmc, cmd->cmdidx, cmd->cmdarg);
if (r1 == 0xff) { /* no response */
ret = -ENOMEDIUM;
goto done;
} else if (r1 & R1_SPI_COM_CRC) {
if (r1 & R1_SPI_COM_CRC)
ret = -ECOMM;
goto done;
} else if (r1 & ~R1_SPI_IDLE) { /* other errors */
else if (r1) /* other errors */
ret = -ETIMEDOUT;
goto done;
} else if (cmd->resp_type == MMC_RSP_R2) {
r1 = mmc_spi_readdata(mmc, cmd->response, 1, 16);
for (i = 0; i < 4; i++)
cmd->response[i] = be32_to_cpu(cmd->response[i]);
debug("r128 %x %x %x %x\n", cmd->response[0], cmd->response[1],
cmd->response[2], cmd->response[3]);
} else if (!data) {
switch (cmd->cmdidx) {
case SD_CMD_APP_SEND_OP_COND:
case MMC_CMD_SEND_OP_COND:
cmd->response[0] = (r1 & R1_SPI_IDLE) ? 0 : OCR_BUSY;
break;
case SD_CMD_SEND_IF_COND:
case MMC_CMD_SPI_READ_OCR:
spi_xfer(spi, 4 * 8, NULL, cmd->response, 0);
cmd->response[0] = be32_to_cpu(cmd->response[0]);
debug("r32 %x\n", cmd->response[0]);
break;
case MMC_CMD_SEND_STATUS:
spi_xfer(spi, 1 * 8, NULL, cmd->response, 0);
cmd->response[0] = (cmd->response[0] & 0xff) ?
MMC_STATUS_ERROR : MMC_STATUS_RDY_FOR_DATA;
break;
}
} else {
debug("%s:data %x %x %x\n", __func__,
data->flags, data->blocks, data->blocksize);
if (data->flags == MMC_DATA_READ)
r1 = mmc_spi_readdata(mmc, data->dest,
data->blocks, data->blocksize);
else if (data->flags == MMC_DATA_WRITE)
r1 = mmc_spi_writedata(mmc, data->src,
data->blocks, data->blocksize,
(cmd->cmdidx == MMC_CMD_WRITE_MULTIPLE_BLOCK));
if (r1 & R1_SPI_COM_CRC)
ret = -ECOMM;
else if (r1) /* other errors */
ret = -ETIMEDOUT;
}
done:
spi_cs_deactivate(spi);
spi_release_bus(spi);
return ret;
}
static int mmc_spi_set_ios(struct mmc *mmc)
static int dm_mmc_spi_set_ios(struct udevice *dev)
{
struct spi_slave *spi = mmc->priv;
debug("%s: clock %u\n", __func__, mmc->clock);
if (mmc->clock)
spi_set_speed(spi, mmc->clock);
return 0;
}
static int mmc_spi_init_p(struct mmc *mmc)
static int dm_mmc_spi_request(struct udevice *dev, struct mmc_cmd *cmd,
struct mmc_data *data)
{
struct spi_slave *spi = mmc->priv;
spi_set_speed(spi, MMC_SPI_MIN_CLOCK);
spi_claim_bus(spi);
/* cs deactivated for 100+ clock */
spi_xfer(spi, 18 * 8, NULL, NULL, 0);
spi_release_bus(spi);
return 0;
}
int i, multi, ret = 0;
u8 *resp = NULL;
u32 resp_size = 0;
bool resp_match = false;
u8 resp8 = 0, resp40[5] = { 0 }, resp_match_value = 0;
static const struct mmc_ops mmc_spi_ops = {
.send_cmd = mmc_spi_request,
.set_ios = mmc_spi_set_ios,
.init = mmc_spi_init_p,
};
dm_spi_claim_bus(dev);
static struct mmc_config mmc_spi_cfg = {
.name = "MMC_SPI",
.ops = &mmc_spi_ops,
.host_caps = MMC_MODE_SPI,
.voltages = MMC_SPI_VOLTAGE,
.f_min = MMC_SPI_MIN_CLOCK,
.part_type = PART_TYPE_DOS,
.b_max = CONFIG_SYS_MMC_MAX_BLK_COUNT,
};
for (i = 0; i < 4; i++)
cmd->response[i] = 0;
struct mmc *mmc_spi_init(uint bus, uint cs, uint speed, uint mode)
{
struct mmc *mmc;
struct spi_slave *spi;
switch (cmd->cmdidx) {
case SD_CMD_APP_SEND_OP_COND:
case MMC_CMD_SEND_OP_COND:
resp = &resp8;
resp_size = sizeof(resp8);
cmd->cmdarg = 0x40000000;
break;
case SD_CMD_SEND_IF_COND:
resp = (u8 *)&resp40[0];
resp_size = sizeof(resp40);
resp_match = true;
resp_match_value = R1_SPI_IDLE;
break;
case MMC_CMD_SPI_READ_OCR:
resp = (u8 *)&resp40[0];
resp_size = sizeof(resp40);
break;
case MMC_CMD_SEND_STATUS:
case MMC_CMD_SET_BLOCKLEN:
case MMC_CMD_SPI_CRC_ON_OFF:
case MMC_CMD_STOP_TRANSMISSION:
resp = &resp8;
resp_size = sizeof(resp8);
resp_match = true;
resp_match_value = 0x0;
break;
case MMC_CMD_SEND_CSD:
case MMC_CMD_SEND_CID:
case MMC_CMD_READ_SINGLE_BLOCK:
case MMC_CMD_READ_MULTIPLE_BLOCK:
case MMC_CMD_WRITE_SINGLE_BLOCK:
case MMC_CMD_WRITE_MULTIPLE_BLOCK:
break;
default:
resp = &resp8;
resp_size = sizeof(resp8);
resp_match = true;
resp_match_value = R1_SPI_IDLE;
break;
};
spi = spi_setup_slave(bus, cs, speed, mode);
if (spi == NULL)
return NULL;
ret = mmc_spi_sendcmd(dev, cmd->cmdidx, cmd->cmdarg, cmd->resp_type,
resp, resp_size, resp_match, resp_match_value);
if (ret)
goto done;
mmc_spi_cfg.f_max = speed;
mmc = mmc_create(&mmc_spi_cfg, spi);
if (mmc == NULL) {
spi_free_slave(spi);
return NULL;
switch (cmd->cmdidx) {
case SD_CMD_APP_SEND_OP_COND:
case MMC_CMD_SEND_OP_COND:
cmd->response[0] = (resp8 & R1_SPI_IDLE) ? 0 : OCR_BUSY;
break;
case SD_CMD_SEND_IF_COND:
case MMC_CMD_SPI_READ_OCR:
cmd->response[0] = resp40[4];
cmd->response[0] |= (uint)resp40[3] << 8;
cmd->response[0] |= (uint)resp40[2] << 16;
cmd->response[0] |= (uint)resp40[1] << 24;
break;
case MMC_CMD_SEND_STATUS:
cmd->response[0] = (resp8 & 0xff) ?
MMC_STATUS_ERROR : MMC_STATUS_RDY_FOR_DATA;
break;
case MMC_CMD_SEND_CID:
case MMC_CMD_SEND_CSD:
ret = mmc_spi_readdata(dev, cmd->response, 1, 16);
if (ret)
return ret;
for (i = 0; i < 4; i++)
cmd->response[i] =
cpu_to_be32(cmd->response[i]);
break;
default:
cmd->response[0] = resp8;
break;
}
return mmc;
debug("%s: cmd%d resp0=0x%x resp1=0x%x resp2=0x%x resp3=0x%x\n",
__func__, cmd->cmdidx, cmd->response[0], cmd->response[1],
cmd->response[2], cmd->response[3]);
if (data) {
debug("%s: data flags=0x%x blocks=%d block_size=%d\n",
__func__, data->flags, data->blocks, data->blocksize);
multi = (cmd->cmdidx == MMC_CMD_WRITE_MULTIPLE_BLOCK);
if (data->flags == MMC_DATA_READ)
ret = mmc_spi_readdata(dev, data->dest,
data->blocks, data->blocksize);
else if (data->flags == MMC_DATA_WRITE)
ret = mmc_spi_writedata(dev, data->src,
data->blocks, data->blocksize,
multi);
}
done:
dm_spi_release_bus(dev);
return ret;
}
static int mmc_spi_probe(struct udevice *dev)
{
struct mmc_spi_priv *priv = dev_get_priv(dev);
struct mmc_uclass_priv *upriv = dev_get_uclass_priv(dev);
char *name;
priv->spi = dev_get_parent_priv(dev);
if (!priv->spi->max_hz)
priv->spi->max_hz = MMC_SPI_MAX_CLOCK;
priv->spi->speed = 0;
priv->spi->mode = SPI_MODE_0;
priv->spi->wordlen = 8;
name = malloc(strlen(dev->parent->name) + strlen(dev->name) + 4);
if (!name)
return -ENOMEM;
sprintf(name, "%s:%s", dev->parent->name, dev->name);
priv->cfg.name = name;
priv->cfg.host_caps = MMC_MODE_SPI;
priv->cfg.voltages = MMC_SPI_VOLTAGE;
priv->cfg.f_min = MMC_SPI_MIN_CLOCK;
priv->cfg.f_max = priv->spi->max_hz;
priv->cfg.part_type = PART_TYPE_DOS;
priv->cfg.b_max = CONFIG_SYS_MMC_MAX_BLK_COUNT;
priv->mmc.cfg = &priv->cfg;
priv->mmc.priv = priv;
priv->mmc.dev = dev;
upriv->mmc = &priv->mmc;
return 0;
}
static int mmc_spi_bind(struct udevice *dev)
{
struct mmc_spi_priv *priv = dev_get_priv(dev);
return mmc_bind(dev, &priv->mmc, &priv->cfg);
}
static const struct dm_mmc_ops mmc_spi_ops = {
.send_cmd = dm_mmc_spi_request,
.set_ios = dm_mmc_spi_set_ios,
};
static const struct udevice_id dm_mmc_spi_match[] = {
{ .compatible = "mmc-spi-slot" },
{ /* sentinel */ }
};
U_BOOT_DRIVER(mmc_spi) = {
.name = "mmc_spi",
.id = UCLASS_MMC,
.of_match = dm_mmc_spi_match,
.ops = &mmc_spi_ops,
.probe = mmc_spi_probe,
.bind = mmc_spi_bind,
.priv_auto_alloc_size = sizeof(struct mmc_spi_priv),
};

View File

@ -119,7 +119,7 @@ ulong mmc_berase(struct blk_desc *block_dev, lbaint_t start, lbaint_t blkcnt)
blk += blk_r;
/* Waiting for the ready status */
if (mmc_send_status(mmc, timeout))
if (mmc_poll_for_busy(mmc, timeout))
return 0;
}
@ -177,7 +177,7 @@ static ulong mmc_write_blocks(struct mmc *mmc, lbaint_t start,
}
/* Waiting for the ready status */
if (mmc_send_status(mmc, timeout))
if (mmc_poll_for_busy(mmc, timeout))
return 0;
return blkcnt;

View File

@ -430,7 +430,6 @@ static void omap_hsmmc_conf_bus_power(struct mmc *mmc, uint signal_voltage)
writel(ac12, &mmc_base->ac12);
}
#if CONFIG_IS_ENABLED(MMC_UHS_SUPPORT)
static int omap_hsmmc_wait_dat0(struct udevice *dev, int state, int timeout)
{
int ret = -ETIMEDOUT;
@ -456,7 +455,6 @@ static int omap_hsmmc_wait_dat0(struct udevice *dev, int state, int timeout)
return ret;
}
#endif
#if CONFIG_IS_ENABLED(MMC_IO_VOLTAGE)
#if CONFIG_IS_ENABLED(DM_REGULATOR)
@ -775,14 +773,6 @@ tuning_error:
return ret;
}
#endif
static void omap_hsmmc_send_init_stream(struct udevice *dev)
{
struct omap_hsmmc_data *priv = dev_get_priv(dev);
struct hsmmc *mmc_base = priv->base_addr;
mmc_init_stream(mmc_base);
}
#endif
static void mmc_enable_irq(struct mmc *mmc, struct mmc_cmd *cmd)
@ -1065,18 +1055,17 @@ static int omap_hsmmc_send_cmd(struct udevice *dev, struct mmc_cmd *cmd,
if (get_timer(0) - start > MAX_RETRY_MS) {
printf("%s: timedout waiting on cmd inhibit to clear\n",
__func__);
mmc_reset_controller_fsm(mmc_base, SYSCTL_SRD);
mmc_reset_controller_fsm(mmc_base, SYSCTL_SRC);
return -ETIMEDOUT;
}
}
writel(0xFFFFFFFF, &mmc_base->stat);
start = get_timer(0);
while (readl(&mmc_base->stat)) {
if (get_timer(0) - start > MAX_RETRY_MS) {
printf("%s: timedout waiting for STAT (%x) to clear\n",
__func__, readl(&mmc_base->stat));
return -ETIMEDOUT;
}
if (readl(&mmc_base->stat)) {
mmc_reset_controller_fsm(mmc_base, SYSCTL_SRD);
mmc_reset_controller_fsm(mmc_base, SYSCTL_SRC);
}
/*
* CMDREG
* CMDIDX[13:8] : Command index
@ -1522,10 +1511,7 @@ static const struct dm_mmc_ops omap_hsmmc_ops = {
#ifdef MMC_SUPPORTS_TUNING
.execute_tuning = omap_hsmmc_execute_tuning,
#endif
.send_init_stream = omap_hsmmc_send_init_stream,
#if CONFIG_IS_ENABLED(MMC_UHS_SUPPORT)
.wait_dat0 = omap_hsmmc_wait_dat0,
#endif
};
#else
static const struct mmc_ops omap_hsmmc_ops = {

View File

@ -103,7 +103,7 @@ static int mmc_rpmb_request(struct mmc *mmc, const struct s_rpmb *s,
cmd.cmdidx = MMC_CMD_WRITE_MULTIPLE_BLOCK;
cmd.cmdarg = 0;
cmd.resp_type = MMC_RSP_R1b;
cmd.resp_type = MMC_RSP_R1;
data.src = (const char *)s;
data.blocks = 1;
@ -327,7 +327,7 @@ static int send_write_mult_block(struct mmc *mmc, const struct s_rpmb *frm,
{
struct mmc_cmd cmd = {
.cmdidx = MMC_CMD_WRITE_MULTIPLE_BLOCK,
.resp_type = MMC_RSP_R1b,
.resp_type = MMC_RSP_R1,
};
struct mmc_data data = {
.src = (const void *)frm,

View File

@ -12,6 +12,7 @@
#include <malloc.h>
#include <mmc.h>
#include <sdhci.h>
#include <dm.h>
#if defined(CONFIG_FIXED_SDHCI_ALIGNED_BUFFER)
void *aligned_buffer = (void *)CONFIG_FIXED_SDHCI_ALIGNED_BUFFER;
@ -590,6 +591,12 @@ static int sdhci_set_ios(struct mmc *mmc)
static int sdhci_init(struct mmc *mmc)
{
struct sdhci_host *host = mmc->priv;
#if CONFIG_IS_ENABLED(DM_MMC) && CONFIG_IS_ENABLED(DM_GPIO)
struct udevice *dev = mmc->dev;
gpio_request_by_name(dev, "cd-gpio", 0,
&host->cd_gpio, GPIOD_IS_IN);
#endif
sdhci_reset(host, SDHCI_RESET_ALL);
@ -624,9 +631,40 @@ int sdhci_probe(struct udevice *dev)
return sdhci_init(mmc);
}
int sdhci_get_cd(struct udevice *dev)
{
struct mmc *mmc = mmc_get_mmc_dev(dev);
struct sdhci_host *host = mmc->priv;
int value;
/* If nonremovable, assume that the card is always present. */
if (mmc->cfg->host_caps & MMC_CAP_NONREMOVABLE)
return 1;
/* If polling, assume that the card is always present. */
if (mmc->cfg->host_caps & MMC_CAP_NEEDS_POLL)
return 1;
#if CONFIG_IS_ENABLED(DM_GPIO)
value = dm_gpio_get_value(&host->cd_gpio);
if (value >= 0) {
if (mmc->cfg->host_caps & MMC_CAP_CD_ACTIVE_HIGH)
return !value;
else
return value;
}
#endif
value = !!(sdhci_readl(host, SDHCI_PRESENT_STATE) &
SDHCI_CARD_PRESENT);
if (mmc->cfg->host_caps & MMC_CAP_CD_ACTIVE_HIGH)
return !value;
else
return value;
}
const struct dm_mmc_ops sdhci_ops = {
.send_cmd = sdhci_send_command,
.set_ios = sdhci_set_ios,
.get_cd = sdhci_get_cd,
#ifdef MMC_SUPPORTS_TUNING
.execute_tuning = sdhci_execute_tuning,
#endif

View File

@ -438,7 +438,6 @@
#ifdef CONFIG_MMC
#define CONFIG_SYS_FSL_ESDHC_ADDR CONFIG_SYS_MPC85xx_ESDHC_ADDR
#define CONFIG_MMC_SPI
#endif
/* Misc Extra Settings */

View File

@ -65,6 +65,11 @@
#define MMC_MODE_DDR_52MHz MMC_CAP(MMC_DDR_52)
#define MMC_MODE_HS200 MMC_CAP(MMC_HS_200)
#define MMC_MODE_HS400 MMC_CAP(MMC_HS_400)
#define MMC_MODE_HS400_ES MMC_CAP(MMC_HS_400_ES)
#define MMC_CAP_NONREMOVABLE BIT(14)
#define MMC_CAP_NEEDS_POLL BIT(15)
#define MMC_CAP_CD_ACTIVE_HIGH BIT(16)
#define MMC_MODE_8BIT BIT(30)
#define MMC_MODE_4BIT BIT(29)
@ -219,13 +224,16 @@ static inline bool mmc_is_tuning_cmd(uint cmdidx)
#define EXT_CSD_BOOT_BUS_WIDTH 177
#define EXT_CSD_PART_CONF 179 /* R/W */
#define EXT_CSD_BUS_WIDTH 183 /* R/W */
#define EXT_CSD_STROBE_SUPPORT 184 /* R/W */
#define EXT_CSD_HS_TIMING 185 /* R/W */
#define EXT_CSD_REV 192 /* RO */
#define EXT_CSD_CARD_TYPE 196 /* RO */
#define EXT_CSD_PART_SWITCH_TIME 199 /* RO */
#define EXT_CSD_SEC_CNT 212 /* RO, 4 bytes */
#define EXT_CSD_HC_WP_GRP_SIZE 221 /* RO */
#define EXT_CSD_HC_ERASE_GRP_SIZE 224 /* RO */
#define EXT_CSD_BOOT_MULT 226 /* RO */
#define EXT_CSD_GENERIC_CMD6_TIME 248 /* RO */
#define EXT_CSD_BKOPS_SUPPORT 502 /* RO */
/*
@ -260,11 +268,13 @@ static inline bool mmc_is_tuning_cmd(uint cmdidx)
#define EXT_CSD_DDR_BUS_WIDTH_4 5 /* Card is in 4 bit DDR mode */
#define EXT_CSD_DDR_BUS_WIDTH_8 6 /* Card is in 8 bit DDR mode */
#define EXT_CSD_DDR_FLAG BIT(2) /* Flag for DDR mode */
#define EXT_CSD_BUS_WIDTH_STROBE BIT(7) /* Enhanced strobe mode */
#define EXT_CSD_TIMING_LEGACY 0 /* no high speed */
#define EXT_CSD_TIMING_HS 1 /* HS */
#define EXT_CSD_TIMING_HS200 2 /* HS200 */
#define EXT_CSD_TIMING_HS400 3 /* HS400 */
#define EXT_CSD_DRV_STR_SHIFT 4 /* Driver Strength shift */
#define EXT_CSD_BOOT_ACK_ENABLE (1 << 6)
#define EXT_CSD_BOOT_PARTITION_ENABLE (1 << 3)
@ -414,14 +424,6 @@ struct dm_mmc_ops {
*/
int (*set_ios)(struct udevice *dev);
/**
* send_init_stream() - send the initialization stream: 74 clock cycles
* This is used after power up before sending the first command
*
* @dev: Device to update
*/
void (*send_init_stream)(struct udevice *dev);
/**
* get_cd() - See whether a card is present
*
@ -449,7 +451,6 @@ struct dm_mmc_ops {
int (*execute_tuning)(struct udevice *dev, uint opcode);
#endif
#if CONFIG_IS_ENABLED(MMC_UHS_SUPPORT)
/**
* wait_dat0() - wait until dat0 is in the target state
* (CLK must be running during the wait)
@ -460,6 +461,10 @@ struct dm_mmc_ops {
* @return 0 if dat0 is in the target state, -ve on error
*/
int (*wait_dat0)(struct udevice *dev, int state, int timeout);
#if CONFIG_IS_ENABLED(MMC_HS400_ES_SUPPORT)
/* set_enhanced_strobe() - set HS400 enhanced strobe */
int (*set_enhanced_strobe)(struct udevice *dev);
#endif
};
@ -468,7 +473,6 @@ struct dm_mmc_ops {
int dm_mmc_send_cmd(struct udevice *dev, struct mmc_cmd *cmd,
struct mmc_data *data);
int dm_mmc_set_ios(struct udevice *dev);
void dm_mmc_send_init_stream(struct udevice *dev);
int dm_mmc_get_cd(struct udevice *dev);
int dm_mmc_get_wp(struct udevice *dev);
int dm_mmc_execute_tuning(struct udevice *dev, uint opcode);
@ -476,11 +480,11 @@ int dm_mmc_wait_dat0(struct udevice *dev, int state, int timeout);
/* Transition functions for compatibility */
int mmc_set_ios(struct mmc *mmc);
void mmc_send_init_stream(struct mmc *mmc);
int mmc_getcd(struct mmc *mmc);
int mmc_getwp(struct mmc *mmc);
int mmc_execute_tuning(struct mmc *mmc, uint opcode);
int mmc_wait_dat0(struct mmc *mmc, int state, int timeout);
int mmc_set_enhanced_strobe(struct mmc *mmc);
#else
struct mmc_ops {
@ -526,6 +530,7 @@ enum bus_mode {
UHS_SDR104,
MMC_HS_200,
MMC_HS_400,
MMC_HS_400_ES,
MMC_MODES_END
};
@ -543,6 +548,10 @@ static inline bool mmc_is_mode_ddr(enum bus_mode mode)
#if CONFIG_IS_ENABLED(MMC_HS400_SUPPORT)
else if (mode == MMC_HS_400)
return true;
#endif
#if CONFIG_IS_ENABLED(MMC_HS400_ES_SUPPORT)
else if (mode == MMC_HS_400_ES)
return true;
#endif
else
return false;
@ -593,6 +602,8 @@ struct mmc {
u8 part_attr;
u8 wr_rel_set;
u8 part_config;
u8 gen_cmd6_time;
u8 part_switch_time;
uint tran_speed;
uint legacy_speed; /* speed for the legacy mode provided by the card */
uint read_bl_len;
@ -828,7 +839,6 @@ void mmc_set_preinit(struct mmc *mmc, int preinit);
#else
#define mmc_host_is_spi(mmc) 0
#endif
struct mmc *mmc_spi_init(uint bus, uint cs, uint speed, uint mode);
void board_mmc_power_init(void);
int board_mmc_init(bd_t *bis);
@ -839,6 +849,9 @@ extern uint mmc_get_env_part(struct mmc *mmc);
# endif
int mmc_get_env_dev(void);
/* Minimum partition switch timeout in units of 10-milliseconds */
#define MMC_MIN_PART_SWITCH_TIME 30 /* 300 ms */
/* Set block count limit because of 16 bit register limit on some hardware*/
#ifndef CONFIG_SYS_MMC_MAX_BLK_COUNT
#define CONFIG_SYS_MMC_MAX_BLK_COUNT 65535

View File

@ -222,13 +222,9 @@
#define MMC_CAP_SDIO_IRQ (1 << 3)
/* Talks only SPI protocols */
#define MMC_CAP_SPI (1 << 4)
/* Needs polling for card-detection */
#define MMC_CAP_NEEDS_POLL (1 << 5)
/* Can the host do 8 bit transfers */
#define MMC_CAP_8_BIT_DATA (1 << 6)
/* Nonremovable e.g. eMMC */
#define MMC_CAP_NONREMOVABLE (1 << 8)
/* Waits while card is busy */
#define MMC_CAP_WAIT_WHILE_BUSY (1 << 9)
/* Allow erase/trim commands */

View File

@ -1165,12 +1165,6 @@ CONFIG_MMCBOOTCOMMAND
CONFIG_MMCROOT
CONFIG_MMC_DEFAULT_DEV
CONFIG_MMC_RPMB_TRACE
CONFIG_MMC_SPI
CONFIG_MMC_SPI_BUS
CONFIG_MMC_SPI_CRC_ON
CONFIG_MMC_SPI_CS
CONFIG_MMC_SPI_MODE
CONFIG_MMC_SPI_SPEED
CONFIG_MMC_SUNXI_SLOT
CONFIG_MMU
CONFIG_MONITOR_IS_IN_RAM