提交 83dc4227 编写于 作者: K Kishon Vijay Abraham I 提交者: Jaehoon Chung

mmc: Retry some MMC cmds on failure

With certain SD cards like Kingston 8GB/16GB UHS card, it is seen that
MMC_CMD_ALL_SEND_CID cmd fails on first attempt, but succeeds
subsequently. Therefore, retry MMC_CMD_ALL_SEND_CID cmd a few time
as done in Linux kernel.
Similarly, it is seen that MMC_CMD_SET_BLOCKLEN may fail on first
attempt, therefore retry this cmd a few times as done in kernel.

To make it clear that those are optionnal workarounds, a new Kconfig
option 'MMC_QUIRKS' is added (enabled by default).
Signed-off-by: NVignesh R <vigneshr@ti.com>
Signed-off-by: NKishon Vijay Abraham I <kishon@ti.com>
Signed-off-by: NJean-Jacques Hiblot <jjhiblot@ti.com>
上级 01298da3
...@@ -42,6 +42,15 @@ config ARM_PL180_MMCI ...@@ -42,6 +42,15 @@ config ARM_PL180_MMCI
If you have an ARM(R) platform with a Multimedia Card slot, If you have an ARM(R) platform with a Multimedia Card slot,
say Y or M here. say Y or M here.
config MMC_QUIRKS
bool "Enable quirks"
default y
help
Some cards and hosts may sometimes behave unexpectedly (quirks).
This option enable workarounds to handle those quirks. Some of them
are enabled by default, other may require additionnal flags or are
enabled by the host driver.
config MMC_VERBOSE config MMC_VERBOSE
bool "Output more information about the MMC" bool "Output more information about the MMC"
default y default y
......
...@@ -279,6 +279,7 @@ int mmc_send_status(struct mmc *mmc, int timeout) ...@@ -279,6 +279,7 @@ int mmc_send_status(struct mmc *mmc, int timeout)
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;
...@@ -287,7 +288,24 @@ int mmc_set_blocklen(struct mmc *mmc, int len) ...@@ -287,7 +288,24 @@ 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;
return mmc_send_cmd(mmc, &cmd, NULL); err = mmc_send_cmd(mmc, &cmd, NULL);
#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;
} }
static int mmc_read_blocks(struct mmc *mmc, void *dst, lbaint_t start, static int mmc_read_blocks(struct mmc *mmc, void *dst, lbaint_t start,
...@@ -1881,7 +1899,6 @@ static int mmc_startup(struct mmc *mmc) ...@@ -1881,7 +1899,6 @@ static int mmc_startup(struct mmc *mmc)
cmd.resp_type = MMC_RSP_R1; cmd.resp_type = MMC_RSP_R1;
cmd.cmdarg = 1; cmd.cmdarg = 1;
err = mmc_send_cmd(mmc, &cmd, NULL); err = mmc_send_cmd(mmc, &cmd, NULL);
if (err) if (err)
return err; return err;
} }
...@@ -1895,6 +1912,21 @@ static int mmc_startup(struct mmc *mmc) ...@@ -1895,6 +1912,21 @@ static int mmc_startup(struct mmc *mmc)
err = mmc_send_cmd(mmc, &cmd, NULL); err = mmc_send_cmd(mmc, &cmd, NULL);
#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;
...@@ -2239,6 +2271,11 @@ int mmc_start_init(struct mmc *mmc) ...@@ -2239,6 +2271,11 @@ int mmc_start_init(struct mmc *mmc)
if (err) if (err)
return err; return err;
#ifdef CONFIG_MMC_QUIRKS
mmc->quirks = MMC_QUIRK_RETRY_SET_BLOCKLEN |
MMC_QUIRK_RETRY_SEND_CID;
#endif
err = mmc_power_cycle(mmc); err = mmc_power_cycle(mmc);
if (err) { if (err) {
/* /*
......
...@@ -306,6 +306,9 @@ static inline bool mmc_is_tuning_cmd(uint cmdidx) ...@@ -306,6 +306,9 @@ static inline bool mmc_is_tuning_cmd(uint cmdidx)
#define ENHNCD_SUPPORT (0x2) #define ENHNCD_SUPPORT (0x2)
#define PART_ENH_ATTRIB (0x1f) #define PART_ENH_ATTRIB (0x1f)
#define MMC_QUIRK_RETRY_SEND_CID BIT(0)
#define MMC_QUIRK_RETRY_SET_BLOCKLEN BIT(1)
enum mmc_voltage { enum mmc_voltage {
MMC_SIGNAL_VOLTAGE_000 = 0, MMC_SIGNAL_VOLTAGE_000 = 0,
MMC_SIGNAL_VOLTAGE_120, MMC_SIGNAL_VOLTAGE_120,
...@@ -591,6 +594,7 @@ struct mmc { ...@@ -591,6 +594,7 @@ struct mmc {
* operating mode due to limitations when * operating mode due to limitations when
* accessing the boot partitions * accessing the boot partitions
*/ */
u32 quirks;
}; };
struct mmc_hwpart_conf { struct mmc_hwpart_conf {
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册