#define SH_MOBILE_SDHI_SCC_CKSEL 0x006
#define SH_MOBILE_SDHI_SCC_RVSCNTL 0x008
#define SH_MOBILE_SDHI_SCC_RVSREQ 0x00A
+#define SH_MOBILE_SDHI_SCC_SMPCMP 0x00C
#define SH_MOBILE_SDHI_SCC_TMPPORT2 0x00E
/* Definitions for values the SH_MOBILE_SDHI_SCC_DTCNTL register */
#define SH_MOBILE_SDHI_SCC_RVSREQ_RVSERR BIT(2)
#define SH_MOBILE_SDHI_SCC_RVSREQ_REQTAPUP BIT(1)
#define SH_MOBILE_SDHI_SCC_RVSREQ_REQTAPDOWN BIT(0)
+/* Definitions for values the SH_MOBILE_SDHI_SCC_SMPCMP register */
+#define SH_MOBILE_SDHI_SCC_SMPCMP_CMD_ERR (BIT(24) | BIT(8))
+#define SH_MOBILE_SDHI_SCC_SMPCMP_CMD_REQUP BIT(24)
+#define SH_MOBILE_SDHI_SCC_SMPCMP_CMD_REQDOWN BIT(8)
/* Definitions for values the SH_MOBILE_SDHI_SCC_TMPPORT2 register */
#define SH_MOBILE_SDHI_SCC_TMPPORT2_HS400OSEL BIT(4)
#define SH_MOBILE_SDHI_SCC_TMPPORT2_HS400EN BIT(31)
static bool renesas_sdhi_manual_correction(struct tmio_mmc_host *host, bool use_4tap)
{
struct renesas_sdhi *priv = host_to_priv(host);
+ unsigned long new_tap = host->tap_set;
u32 val;
val = sd_scc_read32(host, priv, SH_MOBILE_SDHI_SCC_RVSREQ);
sd_scc_write32(host, priv, SH_MOBILE_SDHI_SCC_RVSREQ, 0);
/* Change TAP position according to correction status */
- if (val & SH_MOBILE_SDHI_SCC_RVSREQ_RVSERR)
- return true; /* Need re-tune */
- else if (val & SH_MOBILE_SDHI_SCC_RVSREQ_REQTAPUP)
- host->tap_set = (host->tap_set + 1) % host->tap_num;
- else if (val & SH_MOBILE_SDHI_SCC_RVSREQ_REQTAPDOWN)
- host->tap_set = (host->tap_set - 1) % host->tap_num;
- else
- return false;
+ if (sd_ctrl_read16(host, CTL_VERSION) == SDHI_VER_GEN3_SDMMC &&
+ host->mmc->ios.timing == MMC_TIMING_MMC_HS400) {
+ /*
+ * With HS400, the DAT signal is based on DS, not CLK.
+ * Therefore, use only CMD status.
+ */
+ u32 smpcmp = sd_scc_read32(host, priv, SH_MOBILE_SDHI_SCC_SMPCMP) &
+ SH_MOBILE_SDHI_SCC_SMPCMP_CMD_ERR;
+ if (!smpcmp)
+ return false; /* no error in CMD signal */
+ else if (smpcmp == SH_MOBILE_SDHI_SCC_SMPCMP_CMD_REQUP)
+ new_tap++;
+ else if (smpcmp == SH_MOBILE_SDHI_SCC_SMPCMP_CMD_REQDOWN)
+ new_tap--;
+ else
+ return true; /* need retune */
+ } else {
+ if (val & SH_MOBILE_SDHI_SCC_RVSREQ_RVSERR)
+ return true; /* need retune */
+ else if (val & SH_MOBILE_SDHI_SCC_RVSREQ_REQTAPUP)
+ new_tap++;
+ else if (val & SH_MOBILE_SDHI_SCC_RVSREQ_REQTAPDOWN)
+ new_tap--;
+ else
+ return false;
+ }
+ host->tap_set = (new_tap % host->tap_num);
sd_scc_write32(host, priv, SH_MOBILE_SDHI_SCC_TAPSET,
host->tap_set / (use_4tap ? 2 : 1));