[U-Boot] [PATCH V3 01/13] mmc: tmio: Simplify pinmux handling

The SD UHS SDR12, SDR25, SDR50, SDR104, DDR50 and MMC HS200, HS400 modes all use 1.8V signaling, while all the legacy modes use 3.3V signaling. While there are extra modes which use 1.2V signaling, the existing hardware does not support those.
Simplify the pinmux such that 3.3V signaling implies legacy mode pinmux and the rest implies UHS mode pinmux. This prevents the massive case statement from growing further. Moreover, it fixes an edge case where during SD 1.8V switch, the bus mode is still set to default while the signaling is already set to 1.8V, which results in an attempt to communicate with a 1.8V card using pins in 3.3V mode and thus communication failure.
Signed-off-by: Marek Vasut marek.vasut+renesas@gmail.com Cc: Masahiro Yamada yamada.masahiro@socionext.com --- V2: No change V3: No change --- drivers/mmc/tmio-common.c | 22 +++------------------- 1 file changed, 3 insertions(+), 19 deletions(-)
diff --git a/drivers/mmc/tmio-common.c b/drivers/mmc/tmio-common.c index 138de59470..5f927c6150 100644 --- a/drivers/mmc/tmio-common.c +++ b/drivers/mmc/tmio-common.c @@ -622,26 +622,10 @@ static void tmio_sd_set_pins(struct udevice *dev) #endif
#ifdef CONFIG_PINCTRL - switch (mmc->selected_mode) { - case MMC_LEGACY: - case SD_LEGACY: - case MMC_HS: - case SD_HS: - case MMC_HS_52: - case MMC_DDR_52: - pinctrl_select_state(dev, "default"); - break; - case UHS_SDR12: - case UHS_SDR25: - case UHS_SDR50: - case UHS_DDR50: - case UHS_SDR104: - case MMC_HS_200: + if (mmc->signal_voltage == MMC_SIGNAL_VOLTAGE_180) pinctrl_select_state(dev, "state_uhs"); - break; - default: - break; - } + else + pinctrl_select_state(dev, "default"); #endif }

Properly handle return values and abort operations when they are non-zero. This is a minor improvement, which fixes two remaining unchecked return values.
Signed-off-by: Marek Vasut marek.vasut+renesas@gmail.com Cc: Masahiro Yamada yamada.masahiro@socionext.com --- V2: No change V3: No change --- drivers/mmc/tmio-common.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-)
diff --git a/drivers/mmc/tmio-common.c b/drivers/mmc/tmio-common.c index 5f927c6150..f1ce019db5 100644 --- a/drivers/mmc/tmio-common.c +++ b/drivers/mmc/tmio-common.c @@ -498,6 +498,8 @@ int tmio_sd_send_cmd(struct udevice *dev, struct mmc_cmd *cmd, ret = tmio_sd_dma_xfer(dev, data); else ret = tmio_sd_pio_xfer(dev, data); + if (ret) + return ret;
ret = tmio_sd_wait_for_irq(dev, TMIO_SD_INFO1, TMIO_SD_INFO1_CMP); @@ -505,9 +507,8 @@ int tmio_sd_send_cmd(struct udevice *dev, struct mmc_cmd *cmd, return ret; }
- tmio_sd_wait_for_irq(dev, TMIO_SD_INFO2, TMIO_SD_INFO2_SCLKDIVEN); - - return ret; + return tmio_sd_wait_for_irq(dev, TMIO_SD_INFO2, + TMIO_SD_INFO2_SCLKDIVEN); }
static int tmio_sd_set_bus_width(struct tmio_sd_priv *priv,

In case the controller performs card tuning, that is, sends MMC command 19 or 21, silence possible CRC error warning prints. The warnings are bound to happen, since the tuning will fail for some settings while searching for the optimal configuration of the bus and that is perfectly OK.
This patch passes around the MMC command structure and adds check into tmio_sd_check_error() to avoid printing CRC error warning when the tuning happens.
Signed-off-by: Marek Vasut marek.vasut+renesas@gmail.com Cc: Masahiro Yamada yamada.masahiro@socionext.com --- V2: No change V3: No change --- drivers/mmc/tmio-common.c | 45 +++++++++++++++++++++------------------ 1 file changed, 24 insertions(+), 21 deletions(-)
diff --git a/drivers/mmc/tmio-common.c b/drivers/mmc/tmio-common.c index f1ce019db5..785b654671 100644 --- a/drivers/mmc/tmio-common.c +++ b/drivers/mmc/tmio-common.c @@ -95,7 +95,7 @@ static void __dma_unmap_single(dma_addr_t addr, size_t size, invalidate_dcache_range(addr, addr + size); }
-static int tmio_sd_check_error(struct udevice *dev) +static int tmio_sd_check_error(struct udevice *dev, struct mmc_cmd *cmd) { struct tmio_sd_priv *priv = dev_get_priv(dev); u32 info2 = tmio_sd_readl(priv, TMIO_SD_INFO2); @@ -116,7 +116,9 @@ static int tmio_sd_check_error(struct udevice *dev)
if (info2 & (TMIO_SD_INFO2_ERR_END | TMIO_SD_INFO2_ERR_CRC | TMIO_SD_INFO2_ERR_IDX)) { - dev_err(dev, "communication out of sync\n"); + if ((cmd->cmdidx != MMC_CMD_SEND_TUNING_BLOCK) && + (cmd->cmdidx != MMC_CMD_SEND_TUNING_BLOCK_HS200)) + dev_err(dev, "communication out of sync\n"); return -EILSEQ; }
@@ -129,8 +131,8 @@ static int tmio_sd_check_error(struct udevice *dev) return 0; }
-static int tmio_sd_wait_for_irq(struct udevice *dev, unsigned int reg, - u32 flag) +static int tmio_sd_wait_for_irq(struct udevice *dev, struct mmc_cmd *cmd, + unsigned int reg, u32 flag) { struct tmio_sd_priv *priv = dev_get_priv(dev); long wait = 1000000; @@ -142,7 +144,7 @@ static int tmio_sd_wait_for_irq(struct udevice *dev, unsigned int reg, return -ETIMEDOUT; }
- ret = tmio_sd_check_error(dev); + ret = tmio_sd_check_error(dev, cmd); if (ret) return ret;
@@ -178,15 +180,15 @@ tmio_pio_read_fifo(64, q) tmio_pio_read_fifo(32, l) tmio_pio_read_fifo(16, w)
-static int tmio_sd_pio_read_one_block(struct udevice *dev, char *pbuf, - uint blocksize) +static int tmio_sd_pio_read_one_block(struct udevice *dev, struct mmc_cmd *cmd, + char *pbuf, uint blocksize) { struct tmio_sd_priv *priv = dev_get_priv(dev); int ret;
/* wait until the buffer is filled with data */ - ret = tmio_sd_wait_for_irq(dev, TMIO_SD_INFO2, - TMIO_SD_INFO2_BRE); + ret = tmio_sd_wait_for_irq(dev, cmd, TMIO_SD_INFO2, + TMIO_SD_INFO2_BRE); if (ret) return ret;
@@ -231,15 +233,15 @@ tmio_pio_write_fifo(64, q) tmio_pio_write_fifo(32, l) tmio_pio_write_fifo(16, w)
-static int tmio_sd_pio_write_one_block(struct udevice *dev, +static int tmio_sd_pio_write_one_block(struct udevice *dev, struct mmc_cmd *cmd, const char *pbuf, uint blocksize) { struct tmio_sd_priv *priv = dev_get_priv(dev); int ret;
/* wait until the buffer becomes empty */ - ret = tmio_sd_wait_for_irq(dev, TMIO_SD_INFO2, - TMIO_SD_INFO2_BWE); + ret = tmio_sd_wait_for_irq(dev, cmd, TMIO_SD_INFO2, + TMIO_SD_INFO2_BWE); if (ret) return ret;
@@ -255,7 +257,8 @@ static int tmio_sd_pio_write_one_block(struct udevice *dev, return 0; }
-static int tmio_sd_pio_xfer(struct udevice *dev, struct mmc_data *data) +static int tmio_sd_pio_xfer(struct udevice *dev, struct mmc_cmd *cmd, + struct mmc_data *data) { const char *src = data->src; char *dest = data->dest; @@ -263,10 +266,10 @@ static int tmio_sd_pio_xfer(struct udevice *dev, struct mmc_data *data)
for (i = 0; i < data->blocks; i++) { if (data->flags & MMC_DATA_READ) - ret = tmio_sd_pio_read_one_block(dev, dest, + ret = tmio_sd_pio_read_one_block(dev, cmd, dest, data->blocksize); else - ret = tmio_sd_pio_write_one_block(dev, src, + ret = tmio_sd_pio_write_one_block(dev, cmd, src, data->blocksize); if (ret) return ret; @@ -468,8 +471,8 @@ int tmio_sd_send_cmd(struct udevice *dev, struct mmc_cmd *cmd, cmd->cmdidx, tmp, cmd->cmdarg); tmio_sd_writel(priv, tmp, TMIO_SD_CMD);
- ret = tmio_sd_wait_for_irq(dev, TMIO_SD_INFO1, - TMIO_SD_INFO1_RSP); + ret = tmio_sd_wait_for_irq(dev, cmd, TMIO_SD_INFO1, + TMIO_SD_INFO1_RSP); if (ret) return ret;
@@ -497,17 +500,17 @@ int tmio_sd_send_cmd(struct udevice *dev, struct mmc_cmd *cmd, tmio_sd_addr_is_dmaable(data->src)) ret = tmio_sd_dma_xfer(dev, data); else - ret = tmio_sd_pio_xfer(dev, data); + ret = tmio_sd_pio_xfer(dev, cmd, data); if (ret) return ret;
- ret = tmio_sd_wait_for_irq(dev, TMIO_SD_INFO1, - TMIO_SD_INFO1_CMP); + ret = tmio_sd_wait_for_irq(dev, cmd, TMIO_SD_INFO1, + TMIO_SD_INFO1_CMP); if (ret) return ret; }
- return tmio_sd_wait_for_irq(dev, TMIO_SD_INFO2, + return tmio_sd_wait_for_irq(dev, cmd, TMIO_SD_INFO2, TMIO_SD_INFO2_SCLKDIVEN); }

Configure the clock settings before reconfiguring any other IO settings. This is required when the clock must be stopped before changing eg. the pin configuration or any of the other properties of the bus. Running the clock configuration first allows the MMC core to do just that.
Signed-off-by: Marek Vasut marek.vasut+renesas@gmail.com Cc: Masahiro Yamada yamada.masahiro@socionext.com --- V2: No change V3: No change --- drivers/mmc/tmio-common.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/drivers/mmc/tmio-common.c b/drivers/mmc/tmio-common.c index 785b654671..2a73829d99 100644 --- a/drivers/mmc/tmio-common.c +++ b/drivers/mmc/tmio-common.c @@ -642,11 +642,11 @@ int tmio_sd_set_ios(struct udevice *dev) dev_dbg(dev, "clock %uHz, DDRmode %d, width %u\n", mmc->clock, mmc->ddr_mode, mmc->bus_width);
+ tmio_sd_set_clk_rate(priv, mmc); ret = tmio_sd_set_bus_width(priv, mmc); if (ret) return ret; tmio_sd_set_ddr_mode(priv, mmc); - tmio_sd_set_clk_rate(priv, mmc); tmio_sd_set_pins(dev);
return 0;

Preinitialize the SD card signals regulator to 3.3V, which is the default post-reset setting, to be sure the regulator is set to a valid value.
Signed-off-by: Marek Vasut marek.vasut+renesas@gmail.com Cc: Masahiro Yamada yamada.masahiro@socionext.com --- V2: No change V3: No change --- drivers/mmc/tmio-common.c | 2 ++ 1 file changed, 2 insertions(+)
diff --git a/drivers/mmc/tmio-common.c b/drivers/mmc/tmio-common.c index 2a73829d99..0eca83a0f4 100644 --- a/drivers/mmc/tmio-common.c +++ b/drivers/mmc/tmio-common.c @@ -720,6 +720,8 @@ int tmio_sd_probe(struct udevice *dev, u32 quirks)
#ifdef CONFIG_DM_REGULATOR device_get_supply_regulator(dev, "vqmmc-supply", &priv->vqmmc_dev); + if (priv->vqmmc_dev) + regulator_set_value(priv->vqmmc_dev, 3300000); #endif
ret = mmc_of_parse(dev, &plat->cfg);

Switch the driver to using clk_get_rate()/clk_set_rate() instead of caching the mclk frequency in it's private data. This is required on the SDHI variant of the controller, where the upstream mclk need to be adjusted when using UHS modes.
Platforms which do not support clock framework or do not support it in eg. SPL default to 100 MHz clock.
Signed-off-by: Marek Vasut marek.vasut+renesas@gmail.com Cc: Masahiro Yamada yamada.masahiro@socionext.com --- V2: - Fix build on certain platforms using SPL without clock framework V3: - Turn clk_get_rate into a callback and fill it as needed on both renesas and socionext platforms --- drivers/mmc/renesas-sdhi.c | 21 +++++++++++++-------- drivers/mmc/tmio-common.c | 17 ++++++++++++++--- drivers/mmc/tmio-common.h | 5 ++++- drivers/mmc/uniphier-sd.c | 30 ++++++++++++++++++++---------- 4 files changed, 51 insertions(+), 22 deletions(-)
diff --git a/drivers/mmc/renesas-sdhi.c b/drivers/mmc/renesas-sdhi.c index f8dc5f57ce..edb8e22d3c 100644 --- a/drivers/mmc/renesas-sdhi.c +++ b/drivers/mmc/renesas-sdhi.c @@ -328,15 +328,21 @@ static const struct udevice_id renesas_sdhi_match[] = { { /* sentinel */ } };
+static ulong renesas_sdhi_clk_get_rate(struct tmio_sd_priv *priv) +{ + return clk_get_rate(&priv->clk); +} + static int renesas_sdhi_probe(struct udevice *dev) { struct tmio_sd_priv *priv = dev_get_priv(dev); u32 quirks = dev_get_driver_data(dev); struct fdt_resource reg_res; - struct clk clk; DECLARE_GLOBAL_DATA_PTR; int ret;
+ priv->clk_get_rate = renesas_sdhi_clk_get_rate; + if (quirks == RENESAS_GEN2_QUIRKS) { ret = fdt_get_resource(gd->fdt_blob, dev_of_offset(dev), "reg", 0, ®_res); @@ -350,22 +356,21 @@ static int renesas_sdhi_probe(struct udevice *dev) quirks |= TMIO_SD_CAP_16BIT; }
- ret = clk_get_by_index(dev, 0, &clk); + ret = clk_get_by_index(dev, 0, &priv->clk); if (ret < 0) { dev_err(dev, "failed to get host clock\n"); return ret; }
/* set to max rate */ - priv->mclk = clk_set_rate(&clk, ULONG_MAX); - if (IS_ERR_VALUE(priv->mclk)) { + ret = clk_set_rate(&priv->clk, 200000000); + if (ret < 0) { dev_err(dev, "failed to set rate for host clock\n"); - clk_free(&clk); - return priv->mclk; + clk_free(&priv->clk); + return ret; }
- ret = clk_enable(&clk); - clk_free(&clk); + ret = clk_enable(&priv->clk); if (ret) { dev_err(dev, "failed to enable host clock\n"); return ret; diff --git a/drivers/mmc/tmio-common.c b/drivers/mmc/tmio-common.c index 0eca83a0f4..3ba2f07460 100644 --- a/drivers/mmc/tmio-common.c +++ b/drivers/mmc/tmio-common.c @@ -555,16 +555,24 @@ static void tmio_sd_set_ddr_mode(struct tmio_sd_priv *priv, tmio_sd_writel(priv, tmp, TMIO_SD_IF_MODE); }
+static ulong tmio_sd_clk_get_rate(struct tmio_sd_priv *priv) +{ + return priv->clk_get_rate(priv); +} + static void tmio_sd_set_clk_rate(struct tmio_sd_priv *priv, struct mmc *mmc) { unsigned int divisor; u32 val, tmp; + ulong mclk;
if (!mmc->clock) return;
- divisor = DIV_ROUND_UP(priv->mclk, mmc->clock); + mclk = tmio_sd_clk_get_rate(priv); + + divisor = DIV_ROUND_UP(mclk, mmc->clock);
if (divisor <= 1) val = (priv->caps & TMIO_SD_CAP_RCAR) ? @@ -708,6 +716,7 @@ int tmio_sd_probe(struct udevice *dev, u32 quirks) struct tmio_sd_priv *priv = dev_get_priv(dev); struct mmc_uclass_priv *upriv = dev_get_uclass_priv(dev); fdt_addr_t base; + ulong mclk; int ret;
base = devfdt_get_addr(dev); @@ -750,10 +759,12 @@ int tmio_sd_probe(struct udevice *dev, u32 quirks)
tmio_sd_host_init(priv);
+ mclk = tmio_sd_clk_get_rate(priv); + plat->cfg.voltages = MMC_VDD_165_195 | MMC_VDD_32_33 | MMC_VDD_33_34; - plat->cfg.f_min = priv->mclk / + plat->cfg.f_min = mclk / (priv->caps & TMIO_SD_CAP_DIV1024 ? 1024 : 512); - plat->cfg.f_max = priv->mclk; + plat->cfg.f_max = mclk; plat->cfg.b_max = U32_MAX; /* max value of TMIO_SD_SECCNT */
upriv->mmc = &plat->mmc; diff --git a/drivers/mmc/tmio-common.h b/drivers/mmc/tmio-common.h index 792b1ba5ae..6591c61c3c 100644 --- a/drivers/mmc/tmio-common.h +++ b/drivers/mmc/tmio-common.h @@ -117,7 +117,6 @@ struct tmio_sd_plat {
struct tmio_sd_priv { void __iomem *regbase; - unsigned long mclk; unsigned int version; u32 caps; #define TMIO_SD_CAP_NONREMOVABLE BIT(0) /* Nonremovable e.g. eMMC */ @@ -133,6 +132,10 @@ struct tmio_sd_priv { #ifdef CONFIG_DM_REGULATOR struct udevice *vqmmc_dev; #endif +#if CONFIG_IS_ENABLED(CLK) + struct clk clk; +#endif + ulong (*clk_get_rate)(struct tmio_sd_priv *); };
int tmio_sd_send_cmd(struct udevice *dev, struct mmc_cmd *cmd, diff --git a/drivers/mmc/uniphier-sd.c b/drivers/mmc/uniphier-sd.c index 813c28494c..6539880ab5 100644 --- a/drivers/mmc/uniphier-sd.c +++ b/drivers/mmc/uniphier-sd.c @@ -31,35 +31,45 @@ static const struct udevice_id uniphier_sd_match[] = { { /* sentinel */ } };
+static ulong uniphier_sd_clk_get_rate(struct tmio_sd_priv *priv) +{ +#if CONFIG_IS_ENABLED(CLK) + return clk_get_rate(&priv->clk); +#elif CONFIG_SPL_BUILD + return 100000000; +#else + return 0; +#endif +} + static int uniphier_sd_probe(struct udevice *dev) { struct tmio_sd_priv *priv = dev_get_priv(dev); + + priv->clk_get_rate = uniphier_sd_clk_get_rate; + #ifndef CONFIG_SPL_BUILD - struct clk clk; int ret;
- ret = clk_get_by_index(dev, 0, &clk); + ret = clk_get_by_index(dev, 0, &priv->clk); if (ret < 0) { dev_err(dev, "failed to get host clock\n"); return ret; }
/* set to max rate */ - priv->mclk = clk_set_rate(&clk, ULONG_MAX); - if (IS_ERR_VALUE(priv->mclk)) { + ret = clk_set_rate(&priv->clk, ULONG_MAX); + if (ret < 0) { dev_err(dev, "failed to set rate for host clock\n"); - clk_free(&clk); - return priv->mclk; + clk_free(&priv->clk); + return ret; }
- ret = clk_enable(&clk); - clk_free(&clk); + ret = clk_enable(&priv->clk); if (ret) { dev_err(dev, "failed to enable host clock\n"); return ret; } -#else - priv->mclk = 100000000; #endif
return tmio_sd_probe(dev, 0);

The TMIO core has a quirk where divider == 1 must not be set in DDR modes. Handle this by setting divider to 2, as suggested in the documentation.
Signed-off-by: Marek Vasut marek.vasut+renesas@gmail.com Cc: Masahiro Yamada yamada.masahiro@socionext.com --- V2: No change V3: No change --- drivers/mmc/tmio-common.c | 4 ++++ 1 file changed, 4 insertions(+)
diff --git a/drivers/mmc/tmio-common.c b/drivers/mmc/tmio-common.c index 3ba2f07460..424b60ce52 100644 --- a/drivers/mmc/tmio-common.c +++ b/drivers/mmc/tmio-common.c @@ -574,6 +574,10 @@ static void tmio_sd_set_clk_rate(struct tmio_sd_priv *priv,
divisor = DIV_ROUND_UP(mclk, mmc->clock);
+ /* Do not set divider to 0xff in DDR mode */ + if (mmc->ddr_mode && (divisor == 1)) + divisor = 2; + if (divisor <= 1) val = (priv->caps & TMIO_SD_CAP_RCAR) ? TMIO_SD_CLKCTL_RCAR_DIV1 : TMIO_SD_CLKCTL_DIV1;

The TMIO core has a feature where it can automatically disable clock output when the bus is not in use. While this is useful, it also interferes with switching the bus to 1.8V and other background tasks of the SD/MMC cards, which require clock to be enabled.
This patch respects the mmc->clk_disable and only disables the clock when the MMC core requests it. Otherwise the clock are continuously generated on the bus.
Signed-off-by: Marek Vasut marek.vasut+renesas@gmail.com Cc: Masahiro Yamada yamada.masahiro@socionext.com --- V2: No change V3: No change --- drivers/mmc/tmio-common.c | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-)
diff --git a/drivers/mmc/tmio-common.c b/drivers/mmc/tmio-common.c index 424b60ce52..fad2816ca5 100644 --- a/drivers/mmc/tmio-common.c +++ b/drivers/mmc/tmio-common.c @@ -612,10 +612,16 @@ static void tmio_sd_set_clk_rate(struct tmio_sd_priv *priv, tmio_sd_writel(priv, tmp, TMIO_SD_CLKCTL);
tmp &= ~TMIO_SD_CLKCTL_DIV_MASK; - tmp |= val | TMIO_SD_CLKCTL_OFFEN; + tmp |= val; tmio_sd_writel(priv, tmp, TMIO_SD_CLKCTL);
- tmp |= TMIO_SD_CLKCTL_SCLKEN; + if (!mmc->clk_disable) { + tmp &= ~TMIO_SD_CLKCTL_OFFEN; + tmp |= TMIO_SD_CLKCTL_SCLKEN; + } else { + tmp |= TMIO_SD_CLKCTL_OFFEN; + tmp &= ~TMIO_SD_CLKCTL_SCLKEN; + } tmio_sd_writel(priv, tmp, TMIO_SD_CLKCTL);
udelay(1000);

Add check to avoid touching the SCC tuning registers in case the IP doesn't support them or if the support isn't in place yet.
Signed-off-by: Marek Vasut marek.vasut+renesas@gmail.com Cc: Masahiro Yamada yamada.masahiro@socionext.com --- V2: No change V3: No change --- drivers/mmc/renesas-sdhi.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-)
diff --git a/drivers/mmc/renesas-sdhi.c b/drivers/mmc/renesas-sdhi.c index edb8e22d3c..465663ba97 100644 --- a/drivers/mmc/renesas-sdhi.c +++ b/drivers/mmc/renesas-sdhi.c @@ -294,7 +294,8 @@ static int renesas_sdhi_set_ios(struct udevice *dev) #if CONFIG_IS_ENABLED(MMC_HS200_SUPPORT) struct tmio_sd_priv *priv = dev_get_priv(dev);
- renesas_sdhi_reset_tuning(priv); + if (priv->caps & TMIO_SD_CAP_RCAR_UHS) + renesas_sdhi_reset_tuning(priv); #endif
return ret; @@ -378,7 +379,7 @@ static int renesas_sdhi_probe(struct udevice *dev)
ret = tmio_sd_probe(dev, quirks); #if CONFIG_IS_ENABLED(MMC_HS200_SUPPORT) - if (!ret) + if (!ret && (priv->caps & TMIO_SD_CAP_RCAR_UHS)) renesas_sdhi_reset_tuning(priv); #endif return ret;

Make sure to clear HS400 configuration when resetting the SCC block.
Signed-off-by: Marek Vasut marek.vasut+renesas@gmail.com Cc: Masahiro Yamada yamada.masahiro@socionext.com --- V2: No change V3: No change --- drivers/mmc/renesas-sdhi.c | 7 +++++++ 1 file changed, 7 insertions(+)
diff --git a/drivers/mmc/renesas-sdhi.c b/drivers/mmc/renesas-sdhi.c index 465663ba97..884b4a5cc8 100644 --- a/drivers/mmc/renesas-sdhi.c +++ b/drivers/mmc/renesas-sdhi.c @@ -34,6 +34,8 @@ #define RENESAS_SDHI_SCC_RVSREQ_RVSERR BIT(2) #define RENESAS_SDHI_SCC_SMPCMP 0x818 #define RENESAS_SDHI_SCC_TMPPORT2 0x81c +#define RENESAS_SDHI_SCC_TMPPORT2_HS400EN BIT(31) +#define RENESAS_SDHI_SCC_TMPPORT2_HS400OSEL BIT(4)
#define RENESAS_SDHI_MAX_TAP 3
@@ -90,6 +92,11 @@ static void renesas_sdhi_reset_tuning(struct tmio_sd_priv *priv) reg &= ~RENESAS_SDHI_SCC_CKSEL_DTSEL; tmio_sd_writel(priv, reg, RENESAS_SDHI_SCC_CKSEL);
+ reg = tmio_sd_readl(priv, RENESAS_SDHI_SCC_TMPPORT2); + reg &= ~(RENESAS_SDHI_SCC_TMPPORT2_HS400EN | + RENESAS_SDHI_SCC_TMPPORT2_HS400OSEL); + tmio_sd_writel(priv, reg, RENESAS_SDHI_SCC_TMPPORT2); + reg = tmio_sd_readl(priv, TMIO_SD_CLKCTL); reg |= TMIO_SD_CLKCTL_SCLKEN; tmio_sd_writel(priv, reg, TMIO_SD_CLKCTL);

When the bus switches to 1.8V mode of operation, it is necessary to verify that the card correctly initiated and completed the voltage switch. This is done by reading out the state of DATA0 line.
This patch implement support for reading out the state of the DATA0 line, so the MMC core code can correctly switch to 1.8V mode.
Signed-off-by: Marek Vasut marek.vasut+renesas@gmail.com Cc: Masahiro Yamada yamada.masahiro@socionext.com --- V2: No change V3: No change --- drivers/mmc/renesas-sdhi.c | 27 ++++++++++++++++++++++++++- 1 file changed, 26 insertions(+), 1 deletion(-)
diff --git a/drivers/mmc/renesas-sdhi.c b/drivers/mmc/renesas-sdhi.c index 884b4a5cc8..73f6bf1562 100644 --- a/drivers/mmc/renesas-sdhi.c +++ b/drivers/mmc/renesas-sdhi.c @@ -308,13 +308,38 @@ static int renesas_sdhi_set_ios(struct udevice *dev) return ret; }
+#if CONFIG_IS_ENABLED(MMC_UHS_SUPPORT) +static int renesas_sdhi_wait_dat0(struct udevice *dev, int state, int timeout) +{ + int ret = -ETIMEDOUT; + bool dat0_high; + bool target_dat0_high = !!state; + struct tmio_sd_priv *priv = dev_get_priv(dev); + + timeout = DIV_ROUND_UP(timeout, 10); /* check every 10 us. */ + while (timeout--) { + dat0_high = !!(tmio_sd_readl(priv, TMIO_SD_INFO2) & TMIO_SD_INFO2_DAT0); + if (dat0_high == target_dat0_high) { + ret = 0; + break; + } + udelay(10); + } + + return ret; +} +#endif + static const struct dm_mmc_ops renesas_sdhi_ops = { .send_cmd = tmio_sd_send_cmd, .set_ios = renesas_sdhi_set_ios, .get_cd = tmio_sd_get_cd, -#if CONFIG_IS_ENABLED(MMC_HS200_SUPPORT) +#if CONFIG_IS_ENABLED(MMC_UHS_SUPPORT) || CONFIG_IS_ENABLED(MMC_HS200_SUPPORT) .execute_tuning = renesas_sdhi_execute_tuning, #endif +#if CONFIG_IS_ENABLED(MMC_UHS_SUPPORT) + .wait_dat0 = renesas_sdhi_wait_dat0, +#endif };
#define RENESAS_GEN2_QUIRKS TMIO_SD_CAP_RCAR_GEN2

Switch CPG settings when transitioning between HS200/HS400/SDR104 and regular modes. This is required for the SCC block to operate correctly.
Signed-off-by: Marek Vasut marek.vasut+renesas@gmail.com Cc: Masahiro Yamada yamada.masahiro@socionext.com --- V2: No change V3: No change --- drivers/mmc/renesas-sdhi.c | 28 +++++++++++++++++++++++++++- 1 file changed, 27 insertions(+), 1 deletion(-)
diff --git a/drivers/mmc/renesas-sdhi.c b/drivers/mmc/renesas-sdhi.c index 73f6bf1562..9a454ef949 100644 --- a/drivers/mmc/renesas-sdhi.c +++ b/drivers/mmc/renesas-sdhi.c @@ -292,9 +292,35 @@ out: } #endif
+static void renesas_sdhi_set_clk(struct udevice *dev) +{ + struct tmio_sd_priv *priv = dev_get_priv(dev); + struct mmc *mmc = mmc_get_mmc_dev(dev); + u32 tmp; + + if (!mmc->clock) + return; + + /* Stop the clock before changing its rate to avoid a glitch signal */ + tmp = tmio_sd_readl(priv, TMIO_SD_CLKCTL); + tmp &= ~TMIO_SD_CLKCTL_SCLKEN; + tmio_sd_writel(priv, tmp, TMIO_SD_CLKCTL); + + if ((mmc->selected_mode == UHS_SDR104) || + (mmc->selected_mode == MMC_HS_200)) { + clk_set_rate(&priv->clk, 400000000); + } else { + clk_set_rate(&priv->clk, 200000000); + } +} + static int renesas_sdhi_set_ios(struct udevice *dev) { - int ret = tmio_sd_set_ios(dev); + int ret; + + renesas_sdhi_set_clk(dev); + + ret = tmio_sd_set_ios(dev);
mdelay(10);

It is perfectly fine to write th DTCNTL TAP count and enable the SCC sampling clock operation in the same write.
Signed-off-by: Marek Vasut marek.vasut+renesas@gmail.com Cc: Masahiro Yamada yamada.masahiro@socionext.com --- V2: No change V3: No change --- drivers/mmc/renesas-sdhi.c | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-)
diff --git a/drivers/mmc/renesas-sdhi.c b/drivers/mmc/renesas-sdhi.c index 9a454ef949..fd2a361a6d 100644 --- a/drivers/mmc/renesas-sdhi.c +++ b/drivers/mmc/renesas-sdhi.c @@ -51,12 +51,9 @@ static unsigned int renesas_sdhi_init_tuning(struct tmio_sd_priv *priv) tmio_sd_writel(priv, reg, TMIO_SD_CLKCTL);
/* Set sampling clock selection range */ - tmio_sd_writel(priv, 0x8 << RENESAS_SDHI_SCC_DTCNTL_TAPNUM_SHIFT, - RENESAS_SDHI_SCC_DTCNTL); - - reg = tmio_sd_readl(priv, RENESAS_SDHI_SCC_DTCNTL); - reg |= RENESAS_SDHI_SCC_DTCNTL_TAPEN; - tmio_sd_writel(priv, reg, RENESAS_SDHI_SCC_DTCNTL); + tmio_sd_writel(priv, (0x8 << RENESAS_SDHI_SCC_DTCNTL_TAPNUM_SHIFT) | + RENESAS_SDHI_SCC_DTCNTL_TAPEN, + RENESAS_SDHI_SCC_DTCNTL);
reg = tmio_sd_readl(priv, RENESAS_SDHI_SCC_CKSEL); reg |= RENESAS_SDHI_SCC_CKSEL_DTSEL;
participants (1)
-
Marek Vasut