platform: msm_shared: Recover from all tuning phases pass issue
Tuning procedure fails to find a bad phase due to CDR circuit being in
bad state. Emmc data transfers in hs200/hs400 fail because of this bad phase.
To enable the CDR circuit to select a good phase, send a tuning command after the
default phase is selected and CDR is enabled.
Change-Id: Ic9cac55961bde285c353a3632161ef73975e57dd
diff --git a/platform/msm_shared/sdhci_msm.c b/platform/msm_shared/sdhci_msm.c
index f6d66da..45c87c1 100644
--- a/platform/msm_shared/sdhci_msm.c
+++ b/platform/msm_shared/sdhci_msm.c
@@ -42,6 +42,7 @@
#define MX_DRV_SUPPORTED_HS200 3
+static bool attempt_cdr_unlock;
/* Known data stored in the card & read during tuning
* process. 64 bytes for 4bit bus width & 128 bytes
@@ -720,15 +721,6 @@
/* In Tuning mode */
host->tuning_in_progress = true;
- /* Calibration for CDCLP533 needed for HS400 mode */
- if (msm_host->tuning_done && !msm_host->calibration_done && host->timing == MMC_HS400_TIMING)
- {
- ret = sdhci_msm_hs400_calibration(host);
- if (!ret)
- msm_host->calibration_done = true;
- goto out;
- }
-
if (bus_width == DATA_BUS_WIDTH_8BIT)
{
tuning_block = (uint32_t *)tuning_block_128;
@@ -744,26 +736,34 @@
ASSERT(tuning_data);
+ /* Calibration for CDCLP533 needed for HS400 mode */
+ if (msm_host->tuning_done && !msm_host->calibration_done && host->timing == MMC_HS400_TIMING)
+ {
+ ret = sdhci_msm_hs400_calibration(host);
+ if (!ret)
+ msm_host->calibration_done = true;
+ goto out;
+ }
+
/* Reset & Initialize the DLL block */
if (sdhci_msm_init_dll(host))
{
ret = 1;
- goto free;
+ goto out;
}
retry_tuning:
tuned_phase_cnt = 0;
phase = 0;
+ struct mmc_command cmd = {0};
while (phase < MAX_PHASES)
{
- struct mmc_command cmd = {0};
-
/* configure dll to set phase delay */
if (sdhci_msm_config_dll(host, phase))
{
ret = 1;
- goto free;
+ goto out;
}
cmd.cmd_index = CMD21_SEND_TUNING_BLOCK;
@@ -803,7 +803,10 @@
mmc_set_drv_type(host, card, 0);
if (tuned_phase_cnt == MAX_PHASES)
+ {
+ attempt_cdr_unlock = true;
dprintf(CRITICAL, "WARNING: All phase passed.The selected phase may not be optimal\n");
+ }
/* Find the appropriate tuned phase */
if (tuned_phase_cnt)
@@ -820,7 +823,7 @@
{
dprintf(CRITICAL, "Failed in selecting the tuning phase\n");
ret = 1;
- goto free;
+ goto out;
}
phase = (uint32_t) ret;
@@ -829,7 +832,7 @@
DBG("\n: %s: Tuned Phase: 0x%08x\n", __func__, phase);
if (sdhci_msm_config_dll(host, phase))
- goto free;
+ goto out;
/* Save the tuned phase */
host->msm_host->saved_phase = phase;
@@ -840,9 +843,30 @@
ret = 1;
}
-free:
- free(tuning_data);
out:
+ /* If all the tuning phases passed, send CMD21 after enabling
+ * CDR to make sure right tuning phase is selected by CDR
+ */
+ if (attempt_cdr_unlock)
+ {
+ cmd.cmd_index = CMD21_SEND_TUNING_BLOCK;
+ cmd.argument = 0x0;
+ cmd.cmd_type = SDHCI_CMD_TYPE_NORMAL;
+ cmd.resp_type = SDHCI_CMD_RESP_R1;
+ cmd.trans_mode = SDHCI_MMC_READ;
+ cmd.data_present = 0x1;
+ cmd.data.data_ptr = tuning_data;
+ cmd.data.blk_sz = size;
+ cmd.data.num_blocks = 0x1;
+
+ /* send command */
+ if (!sdhci_send_command(host, &cmd))
+ {
+ DBG("\n: %s: Sending CMD21 after CDR enable with default phases fail\n", __func__);
+ }
+ }
+
+ free(tuning_data);
/* Tuning done */
host->tuning_in_progress = false;
host->msm_host->tuning_done = true;