mmc: renesas_sdhi: Add manual correction
This patch adds a manual correction mechanism for SDHI. Currently, SDHI uses automatic TAP position correction. However, TAP position can also be corrected manually via correction error status flags. Signed-off-by: Takeshi Saito <takeshi.saito.xv@renesas.com> Reviewed-by: Yoshihiro Shimoda <yoshihiro.shimoda.uh@renesas.com> Signed-off-by: Wolfram Sang <wsa+renesas@sang-engineering.com> Link: https://lore.kernel.org/r/20191217114034.13290-3-wsa+renesas@sang-engineering.com Signed-off-by: Ulf Hansson <ulf.hansson@linaro.org>
This commit is contained in:
parent
44f54e7012
commit
11a219606a
|
@ -57,6 +57,7 @@ struct renesas_sdhi {
|
|||
void __iomem *scc_ctl;
|
||||
u32 scc_tappos;
|
||||
u32 scc_tappos_hs400;
|
||||
bool doing_tune;
|
||||
};
|
||||
|
||||
#define host_to_priv(host) \
|
||||
|
|
|
@ -263,6 +263,8 @@ static int renesas_sdhi_start_signal_voltage_switch(struct mmc_host *mmc,
|
|||
#define SH_MOBILE_SDHI_SCC_RVSCNTL_RVSEN BIT(0)
|
||||
/* Definitions for values the SH_MOBILE_SDHI_SCC_RVSREQ 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_TMPPORT2 register */
|
||||
#define SH_MOBILE_SDHI_SCC_TMPPORT2_HS400OSEL BIT(4)
|
||||
#define SH_MOBILE_SDHI_SCC_TMPPORT2_HS400EN BIT(31)
|
||||
|
@ -321,6 +323,8 @@ static void renesas_sdhi_prepare_tuning(struct tmio_mmc_host *host,
|
|||
{
|
||||
struct renesas_sdhi *priv = host_to_priv(host);
|
||||
|
||||
priv->doing_tune = true;
|
||||
|
||||
/* Set sampling clock position */
|
||||
sd_scc_write32(host, priv, SH_MOBILE_SDHI_SCC_TAPSET, tap);
|
||||
}
|
||||
|
@ -426,6 +430,8 @@ static int renesas_sdhi_select_tuning(struct tmio_mmc_host *host)
|
|||
unsigned long ntap; /* temporary counter of tuning success */
|
||||
unsigned long i;
|
||||
|
||||
priv->doing_tune = false;
|
||||
|
||||
/* Clear SCC_RVSREQ */
|
||||
sd_scc_write32(host, priv, SH_MOBILE_SDHI_SCC_RVSREQ, 0);
|
||||
|
||||
|
@ -485,6 +491,47 @@ static int renesas_sdhi_select_tuning(struct tmio_mmc_host *host)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static bool renesas_sdhi_manual_correction(struct tmio_mmc_host *host, bool use_4tap)
|
||||
{
|
||||
struct renesas_sdhi *priv = host_to_priv(host);
|
||||
u32 val;
|
||||
|
||||
val = sd_scc_read32(host, priv, SH_MOBILE_SDHI_SCC_RVSREQ);
|
||||
if (!val)
|
||||
return false;
|
||||
|
||||
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;
|
||||
|
||||
sd_scc_write32(host, priv, SH_MOBILE_SDHI_SCC_TAPSET,
|
||||
host->tap_set / (use_4tap ? 2 : 1));
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
static bool renesas_sdhi_auto_correction(struct tmio_mmc_host *host)
|
||||
{
|
||||
struct renesas_sdhi *priv = host_to_priv(host);
|
||||
|
||||
/* Check SCC error */
|
||||
if (sd_scc_read32(host, priv, SH_MOBILE_SDHI_SCC_RVSREQ) &
|
||||
SH_MOBILE_SDHI_SCC_RVSREQ_RVSERR) {
|
||||
sd_scc_write32(host, priv, SH_MOBILE_SDHI_SCC_RVSREQ, 0);
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
static bool renesas_sdhi_check_scc_error(struct tmio_mmc_host *host)
|
||||
{
|
||||
struct renesas_sdhi *priv = host_to_priv(host);
|
||||
|
@ -499,20 +546,14 @@ static bool renesas_sdhi_check_scc_error(struct tmio_mmc_host *host)
|
|||
!(host->mmc->ios.timing == MMC_TIMING_MMC_HS400 && !use_4tap))
|
||||
return false;
|
||||
|
||||
if (mmc_doing_retune(host->mmc))
|
||||
if (mmc_doing_retune(host->mmc) || priv->doing_tune)
|
||||
return false;
|
||||
|
||||
/* Check SCC error */
|
||||
if (sd_scc_read32(host, priv, SH_MOBILE_SDHI_SCC_RVSCNTL) &
|
||||
SH_MOBILE_SDHI_SCC_RVSCNTL_RVSEN &&
|
||||
sd_scc_read32(host, priv, SH_MOBILE_SDHI_SCC_RVSREQ) &
|
||||
SH_MOBILE_SDHI_SCC_RVSREQ_RVSERR) {
|
||||
/* Clear SCC error */
|
||||
sd_scc_write32(host, priv, SH_MOBILE_SDHI_SCC_RVSREQ, 0);
|
||||
return true;
|
||||
}
|
||||
SH_MOBILE_SDHI_SCC_RVSCNTL_RVSEN)
|
||||
return renesas_sdhi_auto_correction(host);
|
||||
|
||||
return false;
|
||||
return renesas_sdhi_manual_correction(host, use_4tap);
|
||||
}
|
||||
|
||||
static void renesas_sdhi_hw_reset(struct tmio_mmc_host *host)
|
||||
|
|
Loading…
Reference in New Issue