Merge tag 'mmc-2020-11-29' of https://gitlab.denx.de/u-boot/custodians/u-boot-mmc
- mmc minor update for better debug and error check - fsl_esdhc sysctl set and make sure delay check for HS400
This commit is contained in:
commit
a7ab4b71d5
@ -70,7 +70,9 @@ struct fsl_esdhc {
|
|||||||
uint sdtimingctl; /* SD timing control register */
|
uint sdtimingctl; /* SD timing control register */
|
||||||
char reserved8[20]; /* reserved */
|
char reserved8[20]; /* reserved */
|
||||||
uint dllcfg0; /* DLL config 0 register */
|
uint dllcfg0; /* DLL config 0 register */
|
||||||
char reserved9[680]; /* reserved */
|
char reserved9[12]; /* reserved */
|
||||||
|
uint dllstat0; /* DLL status 0 register */
|
||||||
|
char reserved10[664];/* reserved */
|
||||||
uint esdhcctl; /* eSDHC control register */
|
uint esdhcctl; /* eSDHC control register */
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -617,9 +619,11 @@ static void esdhc_exit_hs400(struct fsl_esdhc_priv *priv)
|
|||||||
esdhc_tuning_block_enable(priv, false);
|
esdhc_tuning_block_enable(priv, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void esdhc_set_timing(struct fsl_esdhc_priv *priv, enum bus_mode mode)
|
static int esdhc_set_timing(struct fsl_esdhc_priv *priv, enum bus_mode mode)
|
||||||
{
|
{
|
||||||
struct fsl_esdhc *regs = priv->esdhc_regs;
|
struct fsl_esdhc *regs = priv->esdhc_regs;
|
||||||
|
ulong start;
|
||||||
|
u32 val;
|
||||||
|
|
||||||
/* Exit HS400 mode before setting any other mode */
|
/* Exit HS400 mode before setting any other mode */
|
||||||
if (esdhc_read32(®s->tbctl) & HS400_MODE &&
|
if (esdhc_read32(®s->tbctl) & HS400_MODE &&
|
||||||
@ -640,17 +644,33 @@ static void esdhc_set_timing(struct fsl_esdhc_priv *priv, enum bus_mode mode)
|
|||||||
esdhc_setbits32(®s->dllcfg0, DLL_FREQ_SEL);
|
esdhc_setbits32(®s->dllcfg0, DLL_FREQ_SEL);
|
||||||
|
|
||||||
esdhc_setbits32(®s->dllcfg0, DLL_ENABLE);
|
esdhc_setbits32(®s->dllcfg0, DLL_ENABLE);
|
||||||
|
|
||||||
|
esdhc_setbits32(®s->dllcfg0, DLL_RESET);
|
||||||
|
udelay(1);
|
||||||
|
esdhc_clrbits32(®s->dllcfg0, DLL_RESET);
|
||||||
|
|
||||||
|
start = get_timer(0);
|
||||||
|
val = DLL_STS_SLV_LOCK;
|
||||||
|
while (!(esdhc_read32(®s->dllstat0) & val)) {
|
||||||
|
if (get_timer(start) > 1000) {
|
||||||
|
printf("fsl_esdhc: delay chain lock timeout\n");
|
||||||
|
return -ETIMEDOUT;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
esdhc_setbits32(®s->tbctl, HS400_WNDW_ADJUST);
|
esdhc_setbits32(®s->tbctl, HS400_WNDW_ADJUST);
|
||||||
|
|
||||||
esdhc_clock_control(priv, false);
|
esdhc_clock_control(priv, false);
|
||||||
esdhc_flush_async_fifo(priv);
|
esdhc_flush_async_fifo(priv);
|
||||||
}
|
}
|
||||||
esdhc_clock_control(priv, true);
|
esdhc_clock_control(priv, true);
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int esdhc_set_ios_common(struct fsl_esdhc_priv *priv, struct mmc *mmc)
|
static int esdhc_set_ios_common(struct fsl_esdhc_priv *priv, struct mmc *mmc)
|
||||||
{
|
{
|
||||||
struct fsl_esdhc *regs = priv->esdhc_regs;
|
struct fsl_esdhc *regs = priv->esdhc_regs;
|
||||||
|
int ret;
|
||||||
|
|
||||||
if (priv->is_sdhc_per_clk) {
|
if (priv->is_sdhc_per_clk) {
|
||||||
/* Select to use peripheral clock */
|
/* Select to use peripheral clock */
|
||||||
@ -667,7 +687,9 @@ static int esdhc_set_ios_common(struct fsl_esdhc_priv *priv, struct mmc *mmc)
|
|||||||
set_sysctl(priv, mmc, mmc->clock);
|
set_sysctl(priv, mmc, mmc->clock);
|
||||||
|
|
||||||
/* Set timing */
|
/* Set timing */
|
||||||
esdhc_set_timing(priv, mmc->selected_mode);
|
ret = esdhc_set_timing(priv, mmc->selected_mode);
|
||||||
|
if (ret)
|
||||||
|
return ret;
|
||||||
|
|
||||||
/* Set the bus width */
|
/* Set the bus width */
|
||||||
esdhc_clrbits32(®s->proctl, PROCTL_DTW_4 | PROCTL_DTW_8);
|
esdhc_clrbits32(®s->proctl, PROCTL_DTW_4 | PROCTL_DTW_8);
|
||||||
@ -715,7 +737,7 @@ static int esdhc_init_common(struct fsl_esdhc_priv *priv, struct mmc *mmc)
|
|||||||
esdhc_setbits32(®s->sysctl, SYSCTL_HCKEN | SYSCTL_IPGEN);
|
esdhc_setbits32(®s->sysctl, SYSCTL_HCKEN | SYSCTL_IPGEN);
|
||||||
|
|
||||||
/* Set the initial clock speed */
|
/* Set the initial clock speed */
|
||||||
mmc_set_clock(mmc, 400000, MMC_CLK_ENABLE);
|
set_sysctl(priv, mmc, 400000);
|
||||||
|
|
||||||
/* Disable the BRR and BWR bits in IRQSTAT */
|
/* Disable the BRR and BWR bits in IRQSTAT */
|
||||||
esdhc_clrbits32(®s->irqstaten, IRQSTATEN_BRR | IRQSTATEN_BWR);
|
esdhc_clrbits32(®s->irqstaten, IRQSTATEN_BRR | IRQSTATEN_BWR);
|
||||||
|
@ -207,26 +207,65 @@ int mmc_send_cmd(struct mmc *mmc, struct mmc_cmd *cmd, struct mmc_data *data)
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
/**
|
||||||
|
* mmc_send_cmd_retry() - send a command to the mmc device, retrying on error
|
||||||
|
*
|
||||||
|
* @dev: device to receive the command
|
||||||
|
* @cmd: command to send
|
||||||
|
* @data: additional data to send/receive
|
||||||
|
* @retries: how many times to retry; mmc_send_cmd is always called at least
|
||||||
|
* once
|
||||||
|
* @return 0 if ok, -ve on error
|
||||||
|
*/
|
||||||
|
static int mmc_send_cmd_retry(struct mmc *mmc, struct mmc_cmd *cmd,
|
||||||
|
struct mmc_data *data, uint retries)
|
||||||
|
{
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
do {
|
||||||
|
ret = mmc_send_cmd(mmc, cmd, data);
|
||||||
|
} while (ret && retries--);
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* mmc_send_cmd_quirks() - send a command to the mmc device, retrying if a
|
||||||
|
* specific quirk is enabled
|
||||||
|
*
|
||||||
|
* @dev: device to receive the command
|
||||||
|
* @cmd: command to send
|
||||||
|
* @data: additional data to send/receive
|
||||||
|
* @quirk: retry only if this quirk is enabled
|
||||||
|
* @retries: how many times to retry; mmc_send_cmd is always called at least
|
||||||
|
* once
|
||||||
|
* @return 0 if ok, -ve on error
|
||||||
|
*/
|
||||||
|
static int mmc_send_cmd_quirks(struct mmc *mmc, struct mmc_cmd *cmd,
|
||||||
|
struct mmc_data *data, u32 quirk, uint retries)
|
||||||
|
{
|
||||||
|
if (CONFIG_IS_ENABLED(MMC_QUIRKS) && mmc->quirks & quirk)
|
||||||
|
return mmc_send_cmd_retry(mmc, cmd, data, retries);
|
||||||
|
else
|
||||||
|
return mmc_send_cmd(mmc, cmd, data);
|
||||||
|
}
|
||||||
|
|
||||||
int mmc_send_status(struct mmc *mmc, unsigned int *status)
|
int mmc_send_status(struct mmc *mmc, unsigned int *status)
|
||||||
{
|
{
|
||||||
struct mmc_cmd cmd;
|
struct mmc_cmd cmd;
|
||||||
int err, retries = 5;
|
int ret;
|
||||||
|
|
||||||
cmd.cmdidx = MMC_CMD_SEND_STATUS;
|
cmd.cmdidx = MMC_CMD_SEND_STATUS;
|
||||||
cmd.resp_type = MMC_RSP_R1;
|
cmd.resp_type = MMC_RSP_R1;
|
||||||
if (!mmc_host_is_spi(mmc))
|
if (!mmc_host_is_spi(mmc))
|
||||||
cmd.cmdarg = mmc->rca << 16;
|
cmd.cmdarg = mmc->rca << 16;
|
||||||
|
|
||||||
while (retries--) {
|
ret = mmc_send_cmd_retry(mmc, &cmd, NULL, 4);
|
||||||
err = mmc_send_cmd(mmc, &cmd, NULL);
|
|
||||||
if (!err) {
|
|
||||||
mmc_trace_state(mmc, &cmd);
|
|
||||||
*status = cmd.response[0];
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
mmc_trace_state(mmc, &cmd);
|
mmc_trace_state(mmc, &cmd);
|
||||||
return -ECOMM;
|
if (!ret)
|
||||||
|
*status = cmd.response[0];
|
||||||
|
|
||||||
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
int mmc_poll_for_busy(struct mmc *mmc, int timeout_ms)
|
int mmc_poll_for_busy(struct mmc *mmc, int timeout_ms)
|
||||||
@ -274,7 +313,6 @@ int mmc_poll_for_busy(struct mmc *mmc, int timeout_ms)
|
|||||||
int mmc_set_blocklen(struct mmc *mmc, int len)
|
int mmc_set_blocklen(struct mmc *mmc, int len)
|
||||||
{
|
{
|
||||||
struct mmc_cmd cmd;
|
struct mmc_cmd cmd;
|
||||||
int err;
|
|
||||||
|
|
||||||
if (mmc->ddr_mode)
|
if (mmc->ddr_mode)
|
||||||
return 0;
|
return 0;
|
||||||
@ -283,24 +321,8 @@ int mmc_set_blocklen(struct mmc *mmc, int len)
|
|||||||
cmd.resp_type = MMC_RSP_R1;
|
cmd.resp_type = MMC_RSP_R1;
|
||||||
cmd.cmdarg = len;
|
cmd.cmdarg = len;
|
||||||
|
|
||||||
err = mmc_send_cmd(mmc, &cmd, NULL);
|
return mmc_send_cmd_quirks(mmc, &cmd, NULL,
|
||||||
|
MMC_QUIRK_RETRY_SET_BLOCKLEN, 4);
|
||||||
#ifdef CONFIG_MMC_QUIRKS
|
|
||||||
if (err && (mmc->quirks & MMC_QUIRK_RETRY_SET_BLOCKLEN)) {
|
|
||||||
int retries = 4;
|
|
||||||
/*
|
|
||||||
* It has been seen that SET_BLOCKLEN may fail on the first
|
|
||||||
* attempt, let's try a few more time
|
|
||||||
*/
|
|
||||||
do {
|
|
||||||
err = mmc_send_cmd(mmc, &cmd, NULL);
|
|
||||||
if (!err)
|
|
||||||
break;
|
|
||||||
} while (retries--);
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
return err;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef MMC_SUPPORTS_TUNING
|
#ifdef MMC_SUPPORTS_TUNING
|
||||||
@ -771,7 +793,6 @@ static int __mmc_switch(struct mmc *mmc, u8 set, u8 index, u8 value,
|
|||||||
int timeout_ms = DEFAULT_CMD6_TIMEOUT_MS;
|
int timeout_ms = DEFAULT_CMD6_TIMEOUT_MS;
|
||||||
bool is_part_switch = (set == EXT_CSD_CMD_SET_NORMAL) &&
|
bool is_part_switch = (set == EXT_CSD_CMD_SET_NORMAL) &&
|
||||||
(index == EXT_CSD_PART_CONF);
|
(index == EXT_CSD_PART_CONF);
|
||||||
int retries = 3;
|
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
if (mmc->gen_cmd6_time)
|
if (mmc->gen_cmd6_time)
|
||||||
@ -786,10 +807,7 @@ static int __mmc_switch(struct mmc *mmc, u8 set, u8 index, u8 value,
|
|||||||
(index << 16) |
|
(index << 16) |
|
||||||
(value << 8);
|
(value << 8);
|
||||||
|
|
||||||
do {
|
ret = mmc_send_cmd_retry(mmc, &cmd, NULL, 3);
|
||||||
ret = mmc_send_cmd(mmc, &cmd, NULL);
|
|
||||||
} while (ret && retries-- > 0);
|
|
||||||
|
|
||||||
if (ret)
|
if (ret)
|
||||||
return ret;
|
return ret;
|
||||||
|
|
||||||
@ -1287,22 +1305,15 @@ static int sd_get_capabilities(struct mmc *mmc)
|
|||||||
cmd.resp_type = MMC_RSP_R1;
|
cmd.resp_type = MMC_RSP_R1;
|
||||||
cmd.cmdarg = 0;
|
cmd.cmdarg = 0;
|
||||||
|
|
||||||
timeout = 3;
|
|
||||||
|
|
||||||
retry_scr:
|
|
||||||
data.dest = (char *)scr;
|
data.dest = (char *)scr;
|
||||||
data.blocksize = 8;
|
data.blocksize = 8;
|
||||||
data.blocks = 1;
|
data.blocks = 1;
|
||||||
data.flags = MMC_DATA_READ;
|
data.flags = MMC_DATA_READ;
|
||||||
|
|
||||||
err = mmc_send_cmd(mmc, &cmd, &data);
|
err = mmc_send_cmd_retry(mmc, &cmd, &data, 3);
|
||||||
|
|
||||||
if (err) {
|
|
||||||
if (timeout--)
|
|
||||||
goto retry_scr;
|
|
||||||
|
|
||||||
|
if (err)
|
||||||
return err;
|
return err;
|
||||||
}
|
|
||||||
|
|
||||||
mmc->scr[0] = __be32_to_cpu(scr[0]);
|
mmc->scr[0] = __be32_to_cpu(scr[0]);
|
||||||
mmc->scr[1] = __be32_to_cpu(scr[1]);
|
mmc->scr[1] = __be32_to_cpu(scr[1]);
|
||||||
@ -1463,28 +1474,13 @@ static int sd_read_ssr(struct mmc *mmc)
|
|||||||
struct mmc_cmd cmd;
|
struct mmc_cmd cmd;
|
||||||
ALLOC_CACHE_ALIGN_BUFFER(uint, ssr, 16);
|
ALLOC_CACHE_ALIGN_BUFFER(uint, ssr, 16);
|
||||||
struct mmc_data data;
|
struct mmc_data data;
|
||||||
int timeout = 3;
|
|
||||||
unsigned int au, eo, et, es;
|
unsigned int au, eo, et, es;
|
||||||
|
|
||||||
cmd.cmdidx = MMC_CMD_APP_CMD;
|
cmd.cmdidx = MMC_CMD_APP_CMD;
|
||||||
cmd.resp_type = MMC_RSP_R1;
|
cmd.resp_type = MMC_RSP_R1;
|
||||||
cmd.cmdarg = mmc->rca << 16;
|
cmd.cmdarg = mmc->rca << 16;
|
||||||
|
|
||||||
err = mmc_send_cmd(mmc, &cmd, NULL);
|
err = mmc_send_cmd_quirks(mmc, &cmd, NULL, MMC_QUIRK_RETRY_APP_CMD, 4);
|
||||||
#ifdef CONFIG_MMC_QUIRKS
|
|
||||||
if (err && (mmc->quirks & MMC_QUIRK_RETRY_APP_CMD)) {
|
|
||||||
int retries = 4;
|
|
||||||
/*
|
|
||||||
* It has been seen that APP_CMD may fail on the first
|
|
||||||
* attempt, let's try a few more times
|
|
||||||
*/
|
|
||||||
do {
|
|
||||||
err = mmc_send_cmd(mmc, &cmd, NULL);
|
|
||||||
if (!err)
|
|
||||||
break;
|
|
||||||
} while (retries--);
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
if (err)
|
if (err)
|
||||||
return err;
|
return err;
|
||||||
|
|
||||||
@ -1492,19 +1488,14 @@ static int sd_read_ssr(struct mmc *mmc)
|
|||||||
cmd.resp_type = MMC_RSP_R1;
|
cmd.resp_type = MMC_RSP_R1;
|
||||||
cmd.cmdarg = 0;
|
cmd.cmdarg = 0;
|
||||||
|
|
||||||
retry_ssr:
|
|
||||||
data.dest = (char *)ssr;
|
data.dest = (char *)ssr;
|
||||||
data.blocksize = 64;
|
data.blocksize = 64;
|
||||||
data.blocks = 1;
|
data.blocks = 1;
|
||||||
data.flags = MMC_DATA_READ;
|
data.flags = MMC_DATA_READ;
|
||||||
|
|
||||||
err = mmc_send_cmd(mmc, &cmd, &data);
|
err = mmc_send_cmd_retry(mmc, &cmd, &data, 3);
|
||||||
if (err) {
|
if (err)
|
||||||
if (timeout--)
|
|
||||||
goto retry_ssr;
|
|
||||||
|
|
||||||
return err;
|
return err;
|
||||||
}
|
|
||||||
|
|
||||||
for (i = 0; i < 16; i++)
|
for (i = 0; i < 16; i++)
|
||||||
ssr[i] = be32_to_cpu(ssr[i]);
|
ssr[i] = be32_to_cpu(ssr[i]);
|
||||||
@ -2179,7 +2170,7 @@ static int mmc_select_mode_and_width(struct mmc *mmc, uint card_caps)
|
|||||||
err = mmc_execute_tuning(mmc,
|
err = mmc_execute_tuning(mmc,
|
||||||
mwt->tuning);
|
mwt->tuning);
|
||||||
if (err) {
|
if (err) {
|
||||||
pr_debug("tuning failed\n");
|
pr_debug("tuning failed : %d\n", err);
|
||||||
goto error;
|
goto error;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -2200,7 +2191,7 @@ error:
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pr_err("unable to select a mode\n");
|
pr_err("unable to select a mode : %d\n", err);
|
||||||
|
|
||||||
return -ENOTSUPP;
|
return -ENOTSUPP;
|
||||||
}
|
}
|
||||||
@ -2441,23 +2432,7 @@ static int mmc_startup(struct mmc *mmc)
|
|||||||
cmd.resp_type = MMC_RSP_R2;
|
cmd.resp_type = MMC_RSP_R2;
|
||||||
cmd.cmdarg = 0;
|
cmd.cmdarg = 0;
|
||||||
|
|
||||||
err = mmc_send_cmd(mmc, &cmd, NULL);
|
err = mmc_send_cmd_quirks(mmc, &cmd, NULL, MMC_QUIRK_RETRY_SEND_CID, 4);
|
||||||
|
|
||||||
#ifdef CONFIG_MMC_QUIRKS
|
|
||||||
if (err && (mmc->quirks & MMC_QUIRK_RETRY_SEND_CID)) {
|
|
||||||
int retries = 4;
|
|
||||||
/*
|
|
||||||
* It has been seen that SEND_CID may fail on the first
|
|
||||||
* attempt, let's try a few more time
|
|
||||||
*/
|
|
||||||
do {
|
|
||||||
err = mmc_send_cmd(mmc, &cmd, NULL);
|
|
||||||
if (!err)
|
|
||||||
break;
|
|
||||||
} while (retries--);
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
if (err)
|
if (err)
|
||||||
return err;
|
return err;
|
||||||
|
|
||||||
@ -2745,8 +2720,8 @@ static int mmc_power_on(struct mmc *mmc)
|
|||||||
if (mmc->vmmc_supply) {
|
if (mmc->vmmc_supply) {
|
||||||
int ret = regulator_set_enable(mmc->vmmc_supply, true);
|
int ret = regulator_set_enable(mmc->vmmc_supply, true);
|
||||||
|
|
||||||
if (ret) {
|
if (ret && ret != -EACCES) {
|
||||||
puts("Error enabling VMMC supply\n");
|
printf("Error enabling VMMC supply : %d\n", ret);
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -2761,8 +2736,8 @@ static int mmc_power_off(struct mmc *mmc)
|
|||||||
if (mmc->vmmc_supply) {
|
if (mmc->vmmc_supply) {
|
||||||
int ret = regulator_set_enable(mmc->vmmc_supply, false);
|
int ret = regulator_set_enable(mmc->vmmc_supply, false);
|
||||||
|
|
||||||
if (ret) {
|
if (ret && ret != -EACCES) {
|
||||||
pr_debug("Error disabling VMMC supply\n");
|
pr_debug("Error disabling VMMC supply : %d\n", ret);
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -2866,7 +2841,7 @@ retry:
|
|||||||
|
|
||||||
if (err) {
|
if (err) {
|
||||||
#if !defined(CONFIG_SPL_BUILD) || defined(CONFIG_SPL_LIBCOMMON_SUPPORT)
|
#if !defined(CONFIG_SPL_BUILD) || defined(CONFIG_SPL_LIBCOMMON_SUPPORT)
|
||||||
pr_err("Card did not respond to voltage select!\n");
|
pr_err("Card did not respond to voltage select! : %d\n", err);
|
||||||
#endif
|
#endif
|
||||||
return -EOPNOTSUPP;
|
return -EOPNOTSUPP;
|
||||||
}
|
}
|
||||||
|
@ -187,8 +187,12 @@
|
|||||||
|
|
||||||
/* DLL config 0 register */
|
/* DLL config 0 register */
|
||||||
#define DLL_ENABLE 0x80000000
|
#define DLL_ENABLE 0x80000000
|
||||||
|
#define DLL_RESET 0x40000000
|
||||||
#define DLL_FREQ_SEL 0x08000000
|
#define DLL_FREQ_SEL 0x08000000
|
||||||
|
|
||||||
|
/* DLL status 0 register */
|
||||||
|
#define DLL_STS_SLV_LOCK 0x08000000
|
||||||
|
|
||||||
#define MAX_TUNING_LOOP 40
|
#define MAX_TUNING_LOOP 40
|
||||||
|
|
||||||
#define HOSTVER_VENDOR(x) (((x) >> 8) & 0xff)
|
#define HOSTVER_VENDOR(x) (((x) >> 8) & 0xff)
|
||||||
|
Loading…
Reference in New Issue
Block a user