summaryrefslogtreecommitdiff
path: root/drivers
diff options
context:
space:
mode:
authorMarek Vasut <marek.vasut@gmail.com>2019-11-23 13:36:24 +0100
committerPeng Fan <peng.fan@nxp.com>2019-11-27 16:56:46 +0800
commit1bdcb83d293614dc770a7b76229da61ee19855bf (patch)
tree31ce411410ad465f06124ffb8e187a95e1b63749 /drivers
parent6900066cf67cb95503a922088eed4b31cccba8c2 (diff)
mmc: tmio: sdhi: Skip bad taps
Some of the tuning taps produce suboptimal results. Add code which skips those "bad" taps. Signed-off-by: Marek Vasut <marek.vasut+renesas@gmail.com> Cc: Masahiro Yamada <yamada.masahiro@socionext.com>
Diffstat (limited to 'drivers')
-rw-r--r--drivers/mmc/renesas-sdhi.c49
-rw-r--r--drivers/mmc/tmio-common.h1
2 files changed, 49 insertions, 1 deletions
diff --git a/drivers/mmc/renesas-sdhi.c b/drivers/mmc/renesas-sdhi.c
index dcc77dd86c..087d8b47a8 100644
--- a/drivers/mmc/renesas-sdhi.c
+++ b/drivers/mmc/renesas-sdhi.c
@@ -97,6 +97,7 @@ static bool renesas_sdhi_check_scc_error(struct udevice *dev)
struct tmio_sd_priv *priv = dev_get_priv(dev);
struct mmc *mmc = mmc_get_mmc_dev(dev);
unsigned long new_tap = priv->tap_set;
+ unsigned long error_tap = priv->tap_set;
u32 reg, smpcmp;
if ((priv->caps & TMIO_SD_CAP_RCAR_UHS) &&
@@ -140,15 +141,32 @@ static bool renesas_sdhi_check_scc_error(struct udevice *dev)
case RENESAS_SDHI_SCC_SMPCMP_CMD_REQUP:
new_tap = (priv->tap_set +
priv->tap_num + 1) % priv->tap_num;
+ error_tap = (priv->tap_set +
+ priv->tap_num - 1) % priv->tap_num;
break;
case RENESAS_SDHI_SCC_SMPCMP_CMD_REQDOWN:
new_tap = (priv->tap_set +
priv->tap_num - 1) % priv->tap_num;
+ error_tap = (priv->tap_set +
+ priv->tap_num + 1) % priv->tap_num;
break;
default:
return true; /* Need re-tune */
}
+ if (priv->hs400_bad_tap & BIT(new_tap)) {
+ /*
+ * New tap is bad tap (cannot change).
+ * Compare with HS200 tuning result.
+ * In HS200 tuning, when smpcmp[error_tap]
+ * is OK, retune is executed.
+ */
+ if (priv->smpcmp & BIT(error_tap))
+ return true; /* Need retune */
+
+ return false; /* cannot change */
+ }
+
priv->tap_set = new_tap;
} else {
if (reg & RENESAS_SDHI_SCC_RVSREQ_RVSERR)
@@ -303,6 +321,7 @@ static int renesas_sdhi_hs400(struct udevice *dev)
struct mmc *mmc = mmc_get_mmc_dev(dev);
bool hs400 = (mmc->selected_mode == MMC_HS_400);
int ret, taps = hs400 ? priv->nrtaps : 8;
+ unsigned long new_tap;
u32 reg;
if (taps == 4) /* HS400 on 4tap SoC needs different clock */
@@ -335,6 +354,24 @@ static int renesas_sdhi_hs400(struct udevice *dev)
RENESAS_SDHI_SCC_DTCNTL_TAPEN,
RENESAS_SDHI_SCC_DTCNTL);
+ /* Avoid bad TAP */
+ if (priv->hs400_bad_tap & BIT(priv->tap_set)) {
+ new_tap = (priv->tap_set +
+ priv->tap_num + 1) % priv->tap_num;
+
+ if (priv->hs400_bad_tap & BIT(new_tap))
+ new_tap = (priv->tap_set +
+ priv->tap_num - 1) % priv->tap_num;
+
+ if (priv->hs400_bad_tap & BIT(new_tap)) {
+ new_tap = priv->tap_set;
+ debug("Three consecutive bad tap is prohibited\n");
+ }
+
+ priv->tap_set = new_tap;
+ tmio_sd_writel(priv, priv->tap_set, RENESAS_SDHI_SCC_TAPSET);
+ }
+
if (taps == 4) {
tmio_sd_writel(priv, priv->tap_set >> 1,
RENESAS_SDHI_SCC_TAPSET);
@@ -682,13 +719,23 @@ static void renesas_sdhi_filter_caps(struct udevice *dev)
(rmobile_get_cpu_rev_fraction() <= 2)))
plat->cfg.host_caps &= ~MMC_MODE_HS400;
- /* M3W ES1.x for x>2 can use HS400 with manual adjustment */
+ /* H3 ES2.0, ES3.0 and M3W ES1.2 and M3N bad taps */
+ if (((rmobile_get_cpu_type() == RMOBILE_CPU_TYPE_R8A7795) &&
+ (rmobile_get_cpu_rev_integer() >= 2)) ||
+ ((rmobile_get_cpu_type() == RMOBILE_CPU_TYPE_R8A7796) &&
+ (rmobile_get_cpu_rev_integer() == 1) &&
+ (rmobile_get_cpu_rev_fraction() == 2)) ||
+ (rmobile_get_cpu_type() == RMOBILE_CPU_TYPE_R8A77965))
+ priv->hs400_bad_tap = BIT(2) | BIT(3) | BIT(6) | BIT(7);
+
+ /* M3W ES1.x for x>2 can use HS400 with manual adjustment and taps */
if ((rmobile_get_cpu_type() == RMOBILE_CPU_TYPE_R8A7796) &&
(rmobile_get_cpu_rev_integer() == 1) &&
(rmobile_get_cpu_rev_fraction() > 2)) {
priv->adjust_hs400_enable = true;
priv->adjust_hs400_offset = 3;
priv->adjust_hs400_calibrate = 0x9;
+ priv->hs400_bad_tap = BIT(1) | BIT(3) | BIT(5) | BIT(7);
}
/* M3N can use HS400 with manual adjustment */
diff --git a/drivers/mmc/tmio-common.h b/drivers/mmc/tmio-common.h
index 79f51d21af..f39118e337 100644
--- a/drivers/mmc/tmio-common.h
+++ b/drivers/mmc/tmio-common.h
@@ -145,6 +145,7 @@ struct tmio_sd_priv {
bool adjust_hs400_enable;
u8 adjust_hs400_offset;
u8 adjust_hs400_calibrate;
+ u8 hs400_bad_tap;
#endif
ulong (*clk_get_rate)(struct tmio_sd_priv *);
};