mmc: mmc: extend the mmc_send_tuning()
The mmc_execute_tuning() has already prepared the opcode, there is no need to prepare it again at mmc_send_tuning(), and, there is a BUG of mmc_send_tuning() to determine the opcode by bus width, assume eMMC was running at HS200, 4bit mode, then the mmc_send_tuning() will overwrite the opcode from CMD21 to CMD19, then got error. in addition, extend an argument of "cmd_error" to allow getting if there was cmd error when tune response. Signed-off-by: Chaotian Jing <chaotian.jing@mediatek.com> [Ulf: Rebased patch] Signed-off-by: Ulf Hansson <ulf.hansson@linaro.org>
This commit is contained in:
parent
c9b5061e77
commit
9979dbe515
|
@ -588,7 +588,7 @@ int mmc_switch(struct mmc_card *card, u8 set, u8 index, u8 value,
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL_GPL(mmc_switch);
|
EXPORT_SYMBOL_GPL(mmc_switch);
|
||||||
|
|
||||||
int mmc_send_tuning(struct mmc_host *host)
|
int mmc_send_tuning(struct mmc_host *host, u32 opcode, int *cmd_error)
|
||||||
{
|
{
|
||||||
struct mmc_request mrq = {NULL};
|
struct mmc_request mrq = {NULL};
|
||||||
struct mmc_command cmd = {0};
|
struct mmc_command cmd = {0};
|
||||||
|
@ -598,16 +598,13 @@ int mmc_send_tuning(struct mmc_host *host)
|
||||||
const u8 *tuning_block_pattern;
|
const u8 *tuning_block_pattern;
|
||||||
int size, err = 0;
|
int size, err = 0;
|
||||||
u8 *data_buf;
|
u8 *data_buf;
|
||||||
u32 opcode;
|
|
||||||
|
|
||||||
if (ios->bus_width == MMC_BUS_WIDTH_8) {
|
if (ios->bus_width == MMC_BUS_WIDTH_8) {
|
||||||
tuning_block_pattern = tuning_blk_pattern_8bit;
|
tuning_block_pattern = tuning_blk_pattern_8bit;
|
||||||
size = sizeof(tuning_blk_pattern_8bit);
|
size = sizeof(tuning_blk_pattern_8bit);
|
||||||
opcode = MMC_SEND_TUNING_BLOCK_HS200;
|
|
||||||
} else if (ios->bus_width == MMC_BUS_WIDTH_4) {
|
} else if (ios->bus_width == MMC_BUS_WIDTH_4) {
|
||||||
tuning_block_pattern = tuning_blk_pattern_4bit;
|
tuning_block_pattern = tuning_blk_pattern_4bit;
|
||||||
size = sizeof(tuning_blk_pattern_4bit);
|
size = sizeof(tuning_blk_pattern_4bit);
|
||||||
opcode = MMC_SEND_TUNING_BLOCK;
|
|
||||||
} else
|
} else
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
|
|
||||||
|
@ -638,6 +635,9 @@ int mmc_send_tuning(struct mmc_host *host)
|
||||||
|
|
||||||
mmc_wait_for_req(host, &mrq);
|
mmc_wait_for_req(host, &mrq);
|
||||||
|
|
||||||
|
if (cmd_error)
|
||||||
|
*cmd_error = cmd.error;
|
||||||
|
|
||||||
if (cmd.error) {
|
if (cmd.error) {
|
||||||
err = cmd.error;
|
err = cmd.error;
|
||||||
goto out;
|
goto out;
|
||||||
|
|
|
@ -446,7 +446,7 @@ out:
|
||||||
return loc;
|
return loc;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int dw_mci_exynos_execute_tuning(struct dw_mci_slot *slot)
|
static int dw_mci_exynos_execute_tuning(struct dw_mci_slot *slot, u32 opcode)
|
||||||
{
|
{
|
||||||
struct dw_mci *host = slot->host;
|
struct dw_mci *host = slot->host;
|
||||||
struct dw_mci_exynos_priv_data *priv = host->priv;
|
struct dw_mci_exynos_priv_data *priv = host->priv;
|
||||||
|
@ -461,7 +461,7 @@ static int dw_mci_exynos_execute_tuning(struct dw_mci_slot *slot)
|
||||||
mci_writel(host, TMOUT, ~0);
|
mci_writel(host, TMOUT, ~0);
|
||||||
smpl = dw_mci_exynos_move_next_clksmpl(host);
|
smpl = dw_mci_exynos_move_next_clksmpl(host);
|
||||||
|
|
||||||
if (!mmc_send_tuning(mmc))
|
if (!mmc_send_tuning(mmc, opcode, NULL))
|
||||||
candiates |= (1 << smpl);
|
candiates |= (1 << smpl);
|
||||||
|
|
||||||
} while (start_smpl != smpl);
|
} while (start_smpl != smpl);
|
||||||
|
|
|
@ -83,7 +83,7 @@ static void dw_mci_rk3288_set_ios(struct dw_mci *host, struct mmc_ios *ios)
|
||||||
#define NUM_PHASES 360
|
#define NUM_PHASES 360
|
||||||
#define TUNING_ITERATION_TO_PHASE(i) (DIV_ROUND_UP((i) * 360, NUM_PHASES))
|
#define TUNING_ITERATION_TO_PHASE(i) (DIV_ROUND_UP((i) * 360, NUM_PHASES))
|
||||||
|
|
||||||
static int dw_mci_rk3288_execute_tuning(struct dw_mci_slot *slot)
|
static int dw_mci_rk3288_execute_tuning(struct dw_mci_slot *slot, u32 opcode)
|
||||||
{
|
{
|
||||||
struct dw_mci *host = slot->host;
|
struct dw_mci *host = slot->host;
|
||||||
struct dw_mci_rockchip_priv_data *priv = host->priv;
|
struct dw_mci_rockchip_priv_data *priv = host->priv;
|
||||||
|
@ -114,7 +114,7 @@ static int dw_mci_rk3288_execute_tuning(struct dw_mci_slot *slot)
|
||||||
for (i = 0; i < NUM_PHASES; ) {
|
for (i = 0; i < NUM_PHASES; ) {
|
||||||
clk_set_phase(priv->sample_clk, TUNING_ITERATION_TO_PHASE(i));
|
clk_set_phase(priv->sample_clk, TUNING_ITERATION_TO_PHASE(i));
|
||||||
|
|
||||||
v = !mmc_send_tuning(mmc);
|
v = !mmc_send_tuning(mmc, opcode, NULL);
|
||||||
|
|
||||||
if (i == 0)
|
if (i == 0)
|
||||||
first_v = v;
|
first_v = v;
|
||||||
|
|
|
@ -1540,7 +1540,7 @@ static int dw_mci_execute_tuning(struct mmc_host *mmc, u32 opcode)
|
||||||
int err = -EINVAL;
|
int err = -EINVAL;
|
||||||
|
|
||||||
if (drv_data && drv_data->execute_tuning)
|
if (drv_data && drv_data->execute_tuning)
|
||||||
err = drv_data->execute_tuning(slot);
|
err = drv_data->execute_tuning(slot, opcode);
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -290,7 +290,7 @@ struct dw_mci_drv_data {
|
||||||
void (*prepare_command)(struct dw_mci *host, u32 *cmdr);
|
void (*prepare_command)(struct dw_mci *host, u32 *cmdr);
|
||||||
void (*set_ios)(struct dw_mci *host, struct mmc_ios *ios);
|
void (*set_ios)(struct dw_mci *host, struct mmc_ios *ios);
|
||||||
int (*parse_dt)(struct dw_mci *host);
|
int (*parse_dt)(struct dw_mci *host);
|
||||||
int (*execute_tuning)(struct dw_mci_slot *slot);
|
int (*execute_tuning)(struct dw_mci_slot *slot, u32 opcode);
|
||||||
int (*prepare_hs400_tuning)(struct dw_mci *host,
|
int (*prepare_hs400_tuning)(struct dw_mci *host,
|
||||||
struct mmc_ios *ios);
|
struct mmc_ios *ios);
|
||||||
int (*switch_voltage)(struct mmc_host *mmc,
|
int (*switch_voltage)(struct mmc_host *mmc,
|
||||||
|
|
|
@ -759,7 +759,7 @@ static int esdhc_executing_tuning(struct sdhci_host *host, u32 opcode)
|
||||||
min = ESDHC_TUNE_CTRL_MIN;
|
min = ESDHC_TUNE_CTRL_MIN;
|
||||||
while (min < ESDHC_TUNE_CTRL_MAX) {
|
while (min < ESDHC_TUNE_CTRL_MAX) {
|
||||||
esdhc_prepare_tuning(host, min);
|
esdhc_prepare_tuning(host, min);
|
||||||
if (!mmc_send_tuning(host->mmc))
|
if (!mmc_send_tuning(host->mmc, opcode, NULL))
|
||||||
break;
|
break;
|
||||||
min += ESDHC_TUNE_CTRL_STEP;
|
min += ESDHC_TUNE_CTRL_STEP;
|
||||||
}
|
}
|
||||||
|
@ -768,7 +768,7 @@ static int esdhc_executing_tuning(struct sdhci_host *host, u32 opcode)
|
||||||
max = min + ESDHC_TUNE_CTRL_STEP;
|
max = min + ESDHC_TUNE_CTRL_STEP;
|
||||||
while (max < ESDHC_TUNE_CTRL_MAX) {
|
while (max < ESDHC_TUNE_CTRL_MAX) {
|
||||||
esdhc_prepare_tuning(host, max);
|
esdhc_prepare_tuning(host, max);
|
||||||
if (mmc_send_tuning(host->mmc)) {
|
if (mmc_send_tuning(host->mmc, opcode, NULL)) {
|
||||||
max -= ESDHC_TUNE_CTRL_STEP;
|
max -= ESDHC_TUNE_CTRL_STEP;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -778,7 +778,7 @@ static int esdhc_executing_tuning(struct sdhci_host *host, u32 opcode)
|
||||||
/* use average delay to get the best timing */
|
/* use average delay to get the best timing */
|
||||||
avg = (min + max) / 2;
|
avg = (min + max) / 2;
|
||||||
esdhc_prepare_tuning(host, avg);
|
esdhc_prepare_tuning(host, avg);
|
||||||
ret = mmc_send_tuning(host->mmc);
|
ret = mmc_send_tuning(host->mmc, opcode, NULL);
|
||||||
esdhc_post_tuning(host);
|
esdhc_post_tuning(host);
|
||||||
|
|
||||||
dev_dbg(mmc_dev(host->mmc), "tunning %s at 0x%x ret %d\n",
|
dev_dbg(mmc_dev(host->mmc), "tunning %s at 0x%x ret %d\n",
|
||||||
|
|
|
@ -373,7 +373,7 @@ retry:
|
||||||
if (rc)
|
if (rc)
|
||||||
return rc;
|
return rc;
|
||||||
|
|
||||||
rc = mmc_send_tuning(mmc);
|
rc = mmc_send_tuning(mmc, opcode, NULL);
|
||||||
if (!rc) {
|
if (!rc) {
|
||||||
/* Tuning is successful at this tuning point */
|
/* Tuning is successful at this tuning point */
|
||||||
tuned_phases[tuned_phase_cnt++] = phase;
|
tuned_phases[tuned_phase_cnt++] = phase;
|
||||||
|
|
|
@ -98,7 +98,7 @@ retry:
|
||||||
clock_setting | phase,
|
clock_setting | phase,
|
||||||
SDHCI_CLK_DELAY_SETTING);
|
SDHCI_CLK_DELAY_SETTING);
|
||||||
|
|
||||||
if (!mmc_send_tuning(mmc)) {
|
if (!mmc_send_tuning(mmc, opcode, NULL)) {
|
||||||
/* Tuning is successful at this tuning point */
|
/* Tuning is successful at this tuning point */
|
||||||
tuned_phase_cnt++;
|
tuned_phase_cnt++;
|
||||||
dev_dbg(mmc_dev(mmc), "%s: Found good phase = %d\n",
|
dev_dbg(mmc_dev(mmc), "%s: Found good phase = %d\n",
|
||||||
|
|
|
@ -153,7 +153,7 @@ extern int mmc_wait_for_app_cmd(struct mmc_host *, struct mmc_card *,
|
||||||
struct mmc_command *, int);
|
struct mmc_command *, int);
|
||||||
extern void mmc_start_bkops(struct mmc_card *card, bool from_exception);
|
extern void mmc_start_bkops(struct mmc_card *card, bool from_exception);
|
||||||
extern int mmc_switch(struct mmc_card *, u8, u8, u8, unsigned int);
|
extern int mmc_switch(struct mmc_card *, u8, u8, u8, unsigned int);
|
||||||
extern int mmc_send_tuning(struct mmc_host *host);
|
extern int mmc_send_tuning(struct mmc_host *host, u32 opcode, int *cmd_error);
|
||||||
extern int mmc_get_ext_csd(struct mmc_card *card, u8 **new_ext_csd);
|
extern int mmc_get_ext_csd(struct mmc_card *card, u8 **new_ext_csd);
|
||||||
|
|
||||||
#define MMC_ERASE_ARG 0x00000000
|
#define MMC_ERASE_ARG 0x00000000
|
||||||
|
|
Loading…
Reference in a new issue