summaryrefslogtreecommitdiff
path: root/drivers/mmc/renesas-sdhi.c
diff options
context:
space:
mode:
authorMarek Vasut <marek.vasut@gmail.com>2019-11-23 15:36:23 +0300
committerPeng Fan <peng.fan@nxp.com>2019-11-27 11:56:46 +0300
commit6900066cf67cb95503a922088eed4b31cccba8c2 (patch)
treec737ff060cc5789d3c46bac323d6564b1dda5050 /drivers/mmc/renesas-sdhi.c
parent8f39b03022b1edaf16738b920fea879ebc5c9c17 (diff)
downloadu-boot-6900066cf67cb95503a922088eed4b31cccba8c2.tar.xz
mmc: tmio: sdhi: Add SCC error checking
Check SCC for errors after check command if applicable and optionally adjust the bus skew settings accordingly. Signed-off-by: Marek Vasut <marek.vasut+renesas@gmail.com> Cc: Masahiro Yamada <yamada.masahiro@socionext.com>
Diffstat (limited to 'drivers/mmc/renesas-sdhi.c')
-rw-r--r--drivers/mmc/renesas-sdhi.c85
1 files changed, 85 insertions, 0 deletions
diff --git a/drivers/mmc/renesas-sdhi.c b/drivers/mmc/renesas-sdhi.c
index 8c690a27b2..dcc77dd86c 100644
--- a/drivers/mmc/renesas-sdhi.c
+++ b/drivers/mmc/renesas-sdhi.c
@@ -34,7 +34,12 @@
#define RENESAS_SDHI_SCC_RVSCNTL_RVSEN BIT(0)
#define RENESAS_SDHI_SCC_RVSREQ 0x814
#define RENESAS_SDHI_SCC_RVSREQ_RVSERR BIT(2)
+#define RENESAS_SDHI_SCC_RVSREQ_REQTAPUP BIT(1)
+#define RENESAS_SDHI_SCC_RVSREQ_REQTAPDOWN BIT(0)
#define RENESAS_SDHI_SCC_SMPCMP 0x818
+#define RENESAS_SDHI_SCC_SMPCMP_CMD_ERR (BIT(24) | BIT(8))
+#define RENESAS_SDHI_SCC_SMPCMP_CMD_REQUP BIT(24)
+#define RENESAS_SDHI_SCC_SMPCMP_CMD_REQDOWN BIT(8)
#define RENESAS_SDHI_SCC_TMPPORT2 0x81c
#define RENESAS_SDHI_SCC_TMPPORT2_HS400EN BIT(31)
#define RENESAS_SDHI_SCC_TMPPORT2_HS400OSEL BIT(4)
@@ -87,6 +92,84 @@ static void sd_scc_tmpport_write32(struct tmio_sd_priv *priv, u32 addr, u32 val)
tmio_sd_writel(priv, 0, RENESAS_SDHI_SCC_TMPPORT4);
}
+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;
+ u32 reg, smpcmp;
+
+ if ((priv->caps & TMIO_SD_CAP_RCAR_UHS) &&
+ (mmc->selected_mode != UHS_SDR104) &&
+ (mmc->selected_mode != MMC_HS_200) &&
+ (mmc->selected_mode != MMC_HS_400) &&
+ (priv->nrtaps != 4))
+ return false;
+
+ reg = tmio_sd_readl(priv, RENESAS_SDHI_SCC_RVSCNTL);
+ /* Handle automatic tuning correction */
+ if (reg & RENESAS_SDHI_SCC_RVSCNTL_RVSEN) {
+ reg = tmio_sd_readl(priv, RENESAS_SDHI_SCC_RVSREQ);
+ if (reg & RENESAS_SDHI_SCC_RVSREQ_RVSERR) {
+ tmio_sd_writel(priv, 0, RENESAS_SDHI_SCC_RVSREQ);
+ return true;
+ }
+
+ return false;
+ }
+
+ /* Handle manual tuning correction */
+ reg = tmio_sd_readl(priv, RENESAS_SDHI_SCC_RVSREQ);
+ if (!reg) /* No error */
+ return false;
+
+ tmio_sd_writel(priv, 0, RENESAS_SDHI_SCC_RVSREQ);
+
+ if (mmc->selected_mode == MMC_HS_400) {
+ /*
+ * Correction Error Status contains CMD and DAT signal status.
+ * In HS400, DAT signal based on DS signal, not CLK.
+ * Therefore, use only CMD status.
+ */
+ smpcmp = tmio_sd_readl(priv, RENESAS_SDHI_SCC_SMPCMP) &
+ RENESAS_SDHI_SCC_SMPCMP_CMD_ERR;
+
+ switch (smpcmp) {
+ case 0:
+ return false; /* No error in CMD signal */
+ case RENESAS_SDHI_SCC_SMPCMP_CMD_REQUP:
+ new_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;
+ break;
+ default:
+ return true; /* Need re-tune */
+ }
+
+ priv->tap_set = new_tap;
+ } else {
+ if (reg & RENESAS_SDHI_SCC_RVSREQ_RVSERR)
+ return true; /* Need re-tune */
+ else if (reg & RENESAS_SDHI_SCC_RVSREQ_REQTAPUP)
+ priv->tap_set = (priv->tap_set +
+ priv->tap_num + 1) % priv->tap_num;
+ else if (reg & RENESAS_SDHI_SCC_RVSREQ_REQTAPDOWN)
+ priv->tap_set = (priv->tap_set +
+ priv->tap_num - 1) % priv->tap_num;
+ else
+ return false;
+ }
+
+ /* Set TAP position */
+ tmio_sd_writel(priv, priv->tap_set >> ((priv->nrtaps == 4) ? 1 : 0),
+ RENESAS_SDHI_SCC_TAPSET);
+
+ return false;
+}
+
static void renesas_sdhi_adjust_hs400_mode_enable(struct tmio_sd_priv *priv)
{
u32 calib_code;
@@ -536,6 +619,8 @@ static int renesas_sdhi_send_cmd(struct udevice *dev, struct mmc_cmd *cmd,
CONFIG_IS_ENABLED(MMC_HS400_SUPPORT)
struct tmio_sd_priv *priv = dev_get_priv(dev);
+ renesas_sdhi_check_scc_error(dev);
+
if (cmd->cmdidx == MMC_CMD_SEND_STATUS)
renesas_sdhi_adjust_hs400_mode_enable(priv);
#endif