mmc: msm_sdcc: optimize sampling clock tuning procedure
SDCC-Card tuning sequence comprises of 16 phases. When the
card is detected for the first time the entire tuning
sequence should be implemented to determine the optimum phase
and lock the DLL. However, if the card is transitioning out
of low power mode or when the clock frequency is changed
dynamically, there is no need to carry out tuning sequence
for all 16 phases. It is sufficient to try with the last
successful tuning phase first. This reduces the overhead
involved in executing the entire tuning operation.
In case if the last successful tuning phase has failed,
tuning for all phases needs to be carried out to figure
out optimum phase.
CRs-Fixed: 433495
Change-Id: I78ea074a9bdeb5686c96debfcde3490d50beaf09
Signed-off-by: Sujit Reddy Thumma <sthumma@codeaurora.org>
diff --git a/drivers/mmc/host/msm_sdcc.c b/drivers/mmc/host/msm_sdcc.c
index 0938305..827d3d0 100644
--- a/drivers/mmc/host/msm_sdcc.c
+++ b/drivers/mmc/host/msm_sdcc.c
@@ -75,6 +75,7 @@
#define SPS_MIN_XFER_SIZE MCI_FIFOSIZE
#define MSM_MMC_BUS_VOTING_DELAY 200 /* msecs */
+#define INVALID_TUNING_PHASE -1
#if defined(CONFIG_DEBUG_FS)
static void msmsdcc_dbg_createhost(struct msmsdcc_host *);
@@ -1367,6 +1368,9 @@
|| data->mrq->cmd->opcode == MMC_BUS_TEST_R
|| data->mrq->cmd->opcode ==
MMC_SEND_TUNING_BLOCK_HS200)) {
+ /* Execute full tuning in case of CRC/timeout errors */
+ host->saved_tuning_phase = INVALID_TUNING_PHASE;
+
pr_err("%s: Data CRC error\n",
mmc_hostname(host->mmc));
pr_err("%s: opcode 0x%.8x\n", __func__,
@@ -1383,6 +1387,9 @@
*/
if (!(data->mrq->cmd->opcode == MMC_BUS_TEST_W
|| data->mrq->cmd->opcode == MMC_BUS_TEST_R)) {
+ /* Execute full tuning in case of CRC/timeout errors */
+ host->saved_tuning_phase = INVALID_TUNING_PHASE;
+
pr_err("%s: CMD%d: Data timeout\n",
mmc_hostname(host->mmc),
data->mrq->cmd->opcode);
@@ -1739,6 +1746,8 @@
pr_err("%s: CMD%d: Command CRC error\n",
mmc_hostname(host->mmc), cmd->opcode);
msmsdcc_dump_sdcc_state(host);
+ /* Execute full tuning in case of CRC errors */
+ host->saved_tuning_phase = INVALID_TUNING_PHASE;
cmd->error = -EILSEQ;
}
@@ -4040,6 +4049,7 @@
u8 phase, *data_buf, tuned_phases[16], tuned_phase_cnt = 0;
const u32 *tuning_block_pattern = tuning_block_64;
int size = sizeof(tuning_block_64); /* Tuning pattern size in bytes */
+ bool is_tuning_all_phases;
pr_debug("%s: Enter %s\n", mmc_hostname(mmc), __func__);
@@ -4073,7 +4083,13 @@
goto out;
}
- phase = 0;
+ is_tuning_all_phases = !(host->mmc->card &&
+ (host->saved_tuning_phase != INVALID_TUNING_PHASE));
+retry:
+ if (is_tuning_all_phases)
+ phase = 0; /* start from phase 0 during init */
+ else
+ phase = (u8)host->saved_tuning_phase;
do {
struct mmc_command cmd = {0};
struct mmc_data data = {0};
@@ -4105,9 +4121,16 @@
if (!cmd.error && !data.error &&
!memcmp(data_buf, tuning_block_pattern, size)) {
/* tuning is successful at this tuning point */
+ if (!is_tuning_all_phases)
+ goto kfree;
tuned_phases[tuned_phase_cnt++] = phase;
pr_debug("%s: %s: found good phase = %d\n",
mmc_hostname(mmc), __func__, phase);
+ } else if (!is_tuning_all_phases) {
+ pr_debug("%s: tuning failed at saved phase (%d), retrying\n",
+ mmc_hostname(mmc), (u32)phase);
+ is_tuning_all_phases = true;
+ goto retry;
}
} while (++phase < 16);
@@ -4126,6 +4149,8 @@
rc = msmsdcc_config_cm_sdc4_dll_phase(host, phase);
if (rc)
goto kfree;
+ else
+ host->saved_tuning_phase = phase;
pr_debug("%s: %s: finally setting the tuning phase to %d\n",
mmc_hostname(mmc), __func__, phase);
} else {
@@ -5740,6 +5765,7 @@
dev_err(&pdev->dev, "Failed to read MCLK\n");
set_default_hw_caps(host);
+ host->saved_tuning_phase = INVALID_TUNING_PHASE;
/*
* Set the register write delay according to min. clock frequency
diff --git a/drivers/mmc/host/msm_sdcc.h b/drivers/mmc/host/msm_sdcc.h
index d46cc32..f3e8b90 100644
--- a/drivers/mmc/host/msm_sdcc.h
+++ b/drivers/mmc/host/msm_sdcc.h
@@ -415,6 +415,7 @@
struct device_attribute max_bus_bw;
struct device_attribute polling;
struct device_attribute idle_timeout;
+ int saved_tuning_phase;
};
#define MSMSDCC_VERSION_STEP_MASK 0x0000FFFF