mirror of
https://github.com/Fishwaldo/u-boot.git
synced 2025-03-21 22:51:37 +00:00
mmc: refactor SD startup to make it easier to support new modes
The SDcard startup process currently handles only 2 modes. To make it easier to add support for more modes, let's make the process more generic and use a list of the modes to try. The major functional change is that when a mode fails we try the next one. Not all modes are tried, only those supported by the card and the host. Signed-off-by: Jean-Jacques Hiblot <jjhiblot@ti.com> Reviewed-by: Simon Glass <sjg@chromium.org>
This commit is contained in:
parent
7a96ec7459
commit
d0c221fe73
2 changed files with 127 additions and 51 deletions
|
@ -237,7 +237,8 @@ int mmc_send_status(struct mmc *mmc, int timeout)
|
||||||
(cmd.response[0] & MMC_STATUS_CURR_STATE) !=
|
(cmd.response[0] & MMC_STATUS_CURR_STATE) !=
|
||||||
MMC_STATE_PRG)
|
MMC_STATE_PRG)
|
||||||
break;
|
break;
|
||||||
else if (cmd.response[0] & MMC_STATUS_MASK) {
|
|
||||||
|
if (cmd.response[0] & MMC_STATUS_MASK) {
|
||||||
#if !defined(CONFIG_SPL_BUILD) || defined(CONFIG_SPL_LIBCOMMON_SUPPORT)
|
#if !defined(CONFIG_SPL_BUILD) || defined(CONFIG_SPL_LIBCOMMON_SUPPORT)
|
||||||
printf("Status Error: 0x%08X\n",
|
printf("Status Error: 0x%08X\n",
|
||||||
cmd.response[0]);
|
cmd.response[0]);
|
||||||
|
@ -610,7 +611,7 @@ static int mmc_change_freq(struct mmc *mmc)
|
||||||
char cardtype;
|
char cardtype;
|
||||||
int err;
|
int err;
|
||||||
|
|
||||||
mmc->card_caps = 0;
|
mmc->card_caps = MMC_MODE_1BIT;
|
||||||
|
|
||||||
if (mmc_host_is_spi(mmc))
|
if (mmc_host_is_spi(mmc))
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -936,7 +937,7 @@ static int sd_switch(struct mmc *mmc, int mode, int group, u8 value, u8 *resp)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static int sd_change_freq(struct mmc *mmc)
|
static int sd_get_capabilities(struct mmc *mmc)
|
||||||
{
|
{
|
||||||
int err;
|
int err;
|
||||||
struct mmc_cmd cmd;
|
struct mmc_cmd cmd;
|
||||||
|
@ -945,7 +946,7 @@ static int sd_change_freq(struct mmc *mmc)
|
||||||
struct mmc_data data;
|
struct mmc_data data;
|
||||||
int timeout;
|
int timeout;
|
||||||
|
|
||||||
mmc->card_caps = 0;
|
mmc->card_caps = MMC_MODE_1BIT;
|
||||||
|
|
||||||
if (mmc_host_is_spi(mmc))
|
if (mmc_host_is_spi(mmc))
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -1022,26 +1023,53 @@ retry_scr:
|
||||||
}
|
}
|
||||||
|
|
||||||
/* If high-speed isn't supported, we return */
|
/* If high-speed isn't supported, we return */
|
||||||
if (!(__be32_to_cpu(switch_status[3]) & SD_HIGHSPEED_SUPPORTED))
|
if (__be32_to_cpu(switch_status[3]) & SD_HIGHSPEED_SUPPORTED)
|
||||||
return 0;
|
mmc->card_caps |= MMC_CAP(SD_HS);
|
||||||
|
|
||||||
/*
|
return 0;
|
||||||
* If the host doesn't support SD_HIGHSPEED, do not switch card to
|
}
|
||||||
* HIGHSPEED mode even if the card support SD_HIGHSPPED.
|
|
||||||
* This can avoid furthur problem when the card runs in different
|
static int sd_set_card_speed(struct mmc *mmc, enum bus_mode mode)
|
||||||
* mode between the host.
|
{
|
||||||
*/
|
int err;
|
||||||
if (!((mmc->cfg->host_caps & MMC_MODE_HS_52MHz) &&
|
|
||||||
(mmc->cfg->host_caps & MMC_MODE_HS)))
|
ALLOC_CACHE_ALIGN_BUFFER(uint, switch_status, 16);
|
||||||
return 0;
|
|
||||||
|
|
||||||
err = sd_switch(mmc, SD_SWITCH_SWITCH, 0, 1, (u8 *)switch_status);
|
err = sd_switch(mmc, SD_SWITCH_SWITCH, 0, 1, (u8 *)switch_status);
|
||||||
|
|
||||||
if (err)
|
if (err)
|
||||||
return err;
|
return err;
|
||||||
|
|
||||||
if ((__be32_to_cpu(switch_status[4]) & 0x0f000000) == 0x01000000)
|
if ((__be32_to_cpu(switch_status[4]) & 0x0f000000) != 0x01000000)
|
||||||
mmc->card_caps |= MMC_MODE_HS;
|
return -ENOTSUPP;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int sd_select_bus_width(struct mmc *mmc, int w)
|
||||||
|
{
|
||||||
|
int err;
|
||||||
|
struct mmc_cmd cmd;
|
||||||
|
|
||||||
|
if ((w != 4) && (w != 1))
|
||||||
|
return -EINVAL;
|
||||||
|
|
||||||
|
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;
|
||||||
|
if (w == 4)
|
||||||
|
cmd.cmdarg = 2;
|
||||||
|
else if (w == 1)
|
||||||
|
cmd.cmdarg = 0;
|
||||||
|
err = mmc_send_cmd(mmc, &cmd, NULL);
|
||||||
|
if (err)
|
||||||
|
return err;
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -1133,6 +1161,18 @@ static const u8 multipliers[] = {
|
||||||
80,
|
80,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static inline int bus_width(uint cap)
|
||||||
|
{
|
||||||
|
if (cap == MMC_MODE_8BIT)
|
||||||
|
return 8;
|
||||||
|
if (cap == MMC_MODE_4BIT)
|
||||||
|
return 4;
|
||||||
|
if (cap == MMC_MODE_1BIT)
|
||||||
|
return 1;
|
||||||
|
printf("invalid bus witdh capability 0x%x\n", cap);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
#if !CONFIG_IS_ENABLED(DM_MMC)
|
#if !CONFIG_IS_ENABLED(DM_MMC)
|
||||||
static void mmc_set_ios(struct mmc *mmc)
|
static void mmc_set_ios(struct mmc *mmc)
|
||||||
{
|
{
|
||||||
|
@ -1176,8 +1216,9 @@ void mmc_dump_capabilities(const char *text, uint caps)
|
||||||
printf("8, ");
|
printf("8, ");
|
||||||
if (caps & MMC_MODE_4BIT)
|
if (caps & MMC_MODE_4BIT)
|
||||||
printf("4, ");
|
printf("4, ");
|
||||||
printf("1] modes [");
|
if (caps & MMC_MODE_1BIT)
|
||||||
|
printf("1, ");
|
||||||
|
printf("\b\b] modes [");
|
||||||
for (mode = MMC_LEGACY; mode < MMC_MODES_END; mode++)
|
for (mode = MMC_LEGACY; mode < MMC_MODES_END; mode++)
|
||||||
if (MMC_CAP(mode) & caps)
|
if (MMC_CAP(mode) & caps)
|
||||||
printf("%s, ", mmc_mode_name(mode));
|
printf("%s, ", mmc_mode_name(mode));
|
||||||
|
@ -1185,47 +1226,81 @@ void mmc_dump_capabilities(const char *text, uint caps)
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
static int sd_select_bus_freq_width(struct mmc *mmc)
|
struct mode_width_tuning {
|
||||||
|
enum bus_mode mode;
|
||||||
|
uint widths;
|
||||||
|
};
|
||||||
|
|
||||||
|
static const struct mode_width_tuning sd_modes_by_pref[] = {
|
||||||
|
{
|
||||||
|
.mode = SD_HS,
|
||||||
|
.widths = MMC_MODE_4BIT | MMC_MODE_1BIT,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
.mode = SD_LEGACY,
|
||||||
|
.widths = MMC_MODE_4BIT | MMC_MODE_1BIT,
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
#define for_each_sd_mode_by_pref(caps, mwt) \
|
||||||
|
for (mwt = sd_modes_by_pref;\
|
||||||
|
mwt < sd_modes_by_pref + ARRAY_SIZE(sd_modes_by_pref);\
|
||||||
|
mwt++) \
|
||||||
|
if (caps & MMC_CAP(mwt->mode))
|
||||||
|
|
||||||
|
static int sd_select_mode_and_width(struct mmc *mmc)
|
||||||
{
|
{
|
||||||
int err;
|
int err;
|
||||||
struct mmc_cmd cmd;
|
uint widths[] = {MMC_MODE_4BIT, MMC_MODE_1BIT};
|
||||||
|
const struct mode_width_tuning *mwt;
|
||||||
|
|
||||||
err = sd_change_freq(mmc);
|
err = sd_get_capabilities(mmc);
|
||||||
if (err)
|
if (err)
|
||||||
return err;
|
return err;
|
||||||
|
|
||||||
/* Restrict card's capabilities by what the host can do */
|
/* Restrict card's capabilities by what the host can do */
|
||||||
mmc->card_caps &= mmc->cfg->host_caps;
|
mmc->card_caps &= (mmc->cfg->host_caps | MMC_MODE_1BIT);
|
||||||
|
|
||||||
if (mmc->card_caps & MMC_MODE_4BIT) {
|
for_each_sd_mode_by_pref(mmc->card_caps, mwt) {
|
||||||
cmd.cmdidx = MMC_CMD_APP_CMD;
|
uint *w;
|
||||||
cmd.resp_type = MMC_RSP_R1;
|
|
||||||
cmd.cmdarg = mmc->rca << 16;
|
|
||||||
|
|
||||||
err = mmc_send_cmd(mmc, &cmd, NULL);
|
for (w = widths; w < widths + ARRAY_SIZE(widths); w++) {
|
||||||
if (err)
|
if (*w & mmc->card_caps & mwt->widths) {
|
||||||
return err;
|
debug("trying mode %s width %d (at %d MHz)\n",
|
||||||
|
mmc_mode_name(mwt->mode),
|
||||||
|
bus_width(*w),
|
||||||
|
mmc_mode2freq(mmc, mwt->mode) / 1000000);
|
||||||
|
|
||||||
cmd.cmdidx = SD_CMD_APP_SET_BUS_WIDTH;
|
/* configure the bus width (card + host) */
|
||||||
cmd.resp_type = MMC_RSP_R1;
|
err = sd_select_bus_width(mmc, bus_width(*w));
|
||||||
cmd.cmdarg = 2;
|
if (err)
|
||||||
err = mmc_send_cmd(mmc, &cmd, NULL);
|
goto error;
|
||||||
if (err)
|
mmc_set_bus_width(mmc, bus_width(*w));
|
||||||
return err;
|
|
||||||
|
|
||||||
mmc_set_bus_width(mmc, 4);
|
/* configure the bus mode (card) */
|
||||||
|
err = sd_set_card_speed(mmc, mwt->mode);
|
||||||
|
if (err)
|
||||||
|
goto error;
|
||||||
|
|
||||||
|
/* configure the bus mode (host) */
|
||||||
|
mmc_select_mode(mmc, mwt->mode);
|
||||||
|
mmc_set_clock(mmc, mmc->tran_speed);
|
||||||
|
|
||||||
|
err = sd_read_ssr(mmc);
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
err = sd_read_ssr(mmc);
|
printf("unable to select a mode\n");
|
||||||
if (err)
|
return -ENOTSUPP;
|
||||||
return err;
|
|
||||||
|
|
||||||
if (mmc->card_caps & MMC_MODE_HS)
|
|
||||||
mmc_select_mode(mmc, SD_HS);
|
|
||||||
else
|
|
||||||
mmc_select_mode(mmc, SD_LEGACY);
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -1290,7 +1365,7 @@ static int mmc_select_bus_freq_width(struct mmc *mmc)
|
||||||
return err;
|
return err;
|
||||||
|
|
||||||
/* Restrict card's capabilities by what the host can do */
|
/* Restrict card's capabilities by what the host can do */
|
||||||
mmc->card_caps &= mmc->cfg->host_caps;
|
mmc->card_caps &= (mmc->cfg->host_caps | MMC_MODE_1BIT);
|
||||||
|
|
||||||
/* Only version 4 of MMC supports wider bus widths */
|
/* Only version 4 of MMC supports wider bus widths */
|
||||||
if (mmc->version < MMC_VERSION_4)
|
if (mmc->version < MMC_VERSION_4)
|
||||||
|
@ -1685,7 +1760,7 @@ static int mmc_startup(struct mmc *mmc)
|
||||||
return err;
|
return err;
|
||||||
|
|
||||||
if (IS_SD(mmc))
|
if (IS_SD(mmc))
|
||||||
err = sd_select_bus_freq_width(mmc);
|
err = sd_select_mode_and_width(mmc);
|
||||||
else
|
else
|
||||||
err = mmc_select_bus_freq_width(mmc);
|
err = mmc_select_bus_freq_width(mmc);
|
||||||
|
|
||||||
|
|
|
@ -59,6 +59,7 @@
|
||||||
|
|
||||||
#define MMC_MODE_8BIT BIT(30)
|
#define MMC_MODE_8BIT BIT(30)
|
||||||
#define MMC_MODE_4BIT BIT(29)
|
#define MMC_MODE_4BIT BIT(29)
|
||||||
|
#define MMC_MODE_1BIT BIT(28)
|
||||||
#define MMC_MODE_SPI BIT(27)
|
#define MMC_MODE_SPI BIT(27)
|
||||||
|
|
||||||
|
|
||||||
|
|
Loading…
Add table
Reference in a new issue