[U-Boot] [PATCH V3 1/6] mmc: tmio: Switch to clock framework

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 e7f96f8bf2..f4283d055f 100644 --- a/drivers/mmc/renesas-sdhi.c +++ b/drivers/mmc/renesas-sdhi.c @@ -358,15 +358,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); @@ -380,22 +386,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 --- 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 --- 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);

On Wed, Nov 14, 2018 at 8:44 AM Marek Vasut marek.vasut@gmail.com wrote:
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
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);
What is the point of setting TMIO_SD_CLKCTL_OFFEN when TMIO_SD_CLKCTL_SCLKEN is unset?
Why isn't the code like this?
if (!mmc->clk_disable) tmp |= TMIO_SD_CLKCTL_SCLKEN; else tmp &= ~TMIO_SD_CLKCTL_SCLKEN;
/* Never use OFFEN because it interferes with 1.8 switching */ tmp &= ~TMIO_SD_CLKCTL_OFFEN;
tmio_sd_writel(priv, tmp, TMIO_SD_CLKCTL);
One more thing, you wrote
if (!mmc->clk_disable) ... else ...
in this patch.
Then, soon you will rewrite it to
if (mmc->clk_disable) ... else ...
in another patch:
http://patchwork.ozlabs.org/patch/998542/
Noise changes.

On 11/27/2018 04:43 AM, Masahiro Yamada wrote:
On Wed, Nov 14, 2018 at 8:44 AM Marek Vasut marek.vasut@gmail.com wrote:
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
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);
What is the point of setting TMIO_SD_CLKCTL_OFFEN when TMIO_SD_CLKCTL_SCLKEN is unset?
Why isn't the code like this?
if (!mmc->clk_disable) tmp |= TMIO_SD_CLKCTL_SCLKEN; else tmp &= ~TMIO_SD_CLKCTL_SCLKEN; /* Never use OFFEN because it interferes with 1.8 switching */ tmp &= ~TMIO_SD_CLKCTL_OFFEN; tmio_sd_writel(priv, tmp, TMIO_SD_CLKCTL);
I think this could be done, but I'd have to re-run the entire bulk of tests on all boards to see if nothing broke. I'd prefer to get this in (if it doesn't break your system) and then add a patch on top.
One more thing, you wrote
if (!mmc->clk_disable) ... else ...
in this patch.
Then, soon you will rewrite it to
if (mmc->clk_disable) ... else ...
in another patch:
I know, I added the other one afterward, since I discovered another card which had clock problems.

Filter out HS400 support on SoCs where HS400 is not supported yet.
Signed-off-by: Marek Vasut marek.vasut+renesas@gmail.com Cc: Masahiro Yamada yamada.masahiro@socionext.com --- V3: New patch --- drivers/mmc/renesas-sdhi.c | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+)
diff --git a/drivers/mmc/renesas-sdhi.c b/drivers/mmc/renesas-sdhi.c index f4283d055f..0cc6f27279 100644 --- a/drivers/mmc/renesas-sdhi.c +++ b/drivers/mmc/renesas-sdhi.c @@ -363,6 +363,23 @@ static ulong renesas_sdhi_clk_get_rate(struct tmio_sd_priv *priv) return clk_get_rate(&priv->clk); }
+static void renesas_sdhi_filter_caps(struct udevice *dev) +{ + struct tmio_sd_plat *plat = dev_get_platdata(dev); + struct tmio_sd_priv *priv = dev_get_priv(dev); + + if (!(priv->caps & TMIO_SD_CAP_RCAR_GEN3)) + return; + + /* HS400 is not supported on H3 ES1.x and M3W ES1.0,ES1.1 */ + if (((rmobile_get_cpu_type() == RMOBILE_CPU_TYPE_R8A7795) && + (rmobile_get_cpu_rev_integer() <= 1)) || + ((rmobile_get_cpu_type() == RMOBILE_CPU_TYPE_R8A7796) && + (rmobile_get_cpu_rev_integer() == 1) && + (rmobile_get_cpu_rev_fraction() <= 1))) + plat->cfg.host_caps &= ~MMC_MODE_HS400; +} + static int renesas_sdhi_probe(struct udevice *dev) { struct tmio_sd_priv *priv = dev_get_priv(dev); @@ -407,6 +424,9 @@ static int renesas_sdhi_probe(struct udevice *dev) }
ret = tmio_sd_probe(dev, quirks); + + renesas_sdhi_filter_caps(dev); + #if CONFIG_IS_ENABLED(MMC_HS200_SUPPORT) if (!ret && (priv->caps & TMIO_SD_CAP_RCAR_UHS)) renesas_sdhi_reset_tuning(priv);

Move the tap_pos variable, which is the HS200/HS400/SDR104 calibration offset, into private data, so it can be passed around. This is done in preparation for the HS400 mode, which needs to adjust this value.
Signed-off-by: Marek Vasut marek.vasut+renesas@gmail.com Cc: Masahiro Yamada yamada.masahiro@socionext.com --- V3: New patch --- drivers/mmc/renesas-sdhi.c | 5 ++--- drivers/mmc/tmio-common.h | 3 +++ 2 files changed, 5 insertions(+), 3 deletions(-)
diff --git a/drivers/mmc/renesas-sdhi.c b/drivers/mmc/renesas-sdhi.c index 0cc6f27279..1ed50d6292 100644 --- a/drivers/mmc/renesas-sdhi.c +++ b/drivers/mmc/renesas-sdhi.c @@ -125,7 +125,6 @@ static int renesas_sdhi_select_tuning(struct tmio_sd_priv *priv, unsigned int smpcmp) { unsigned long tap_cnt; /* counter of tuning success */ - unsigned long tap_set; /* tap position */ unsigned long tap_start;/* start position of tuning success */ unsigned long tap_end; /* end position of tuning success */ unsigned long ntap; /* temporary counter of tuning success */ @@ -209,12 +208,12 @@ static int renesas_sdhi_select_tuning(struct tmio_sd_priv *priv, select = true;
if (select) - tap_set = ((tap_start + tap_end) / 2) % tap_num; + priv->tap_set = ((tap_start + tap_end) / 2) % tap_num; else return -EIO;
/* Set SCC */ - tmio_sd_writel(priv, tap_set, RENESAS_SDHI_SCC_TAPSET); + tmio_sd_writel(priv, priv->tap_set, RENESAS_SDHI_SCC_TAPSET);
/* Enable auto re-tuning */ reg = tmio_sd_readl(priv, RENESAS_SDHI_SCC_RVSCNTL); diff --git a/drivers/mmc/tmio-common.h b/drivers/mmc/tmio-common.h index 6591c61c3c..9a427b5311 100644 --- a/drivers/mmc/tmio-common.h +++ b/drivers/mmc/tmio-common.h @@ -134,6 +134,9 @@ struct tmio_sd_priv { #endif #if CONFIG_IS_ENABLED(CLK) struct clk clk; +#endif +#if CONFIG_IS_ENABLED(RENESAS_SDHI) + u8 tap_set; #endif ulong (*clk_get_rate)(struct tmio_sd_priv *); };

Add support for the HS400 mode to SDHI driver. This uses the up-tune mechanism from already supported HS200 tuning.
Signed-off-by: Marek Vasut marek.vasut+renesas@gmail.com Cc: Masahiro Yamada yamada.masahiro@socionext.com --- V3: New patch --- drivers/mmc/renesas-sdhi.c | 103 ++++++++++++++++++++++++++++++++++--- drivers/mmc/tmio-common.h | 1 + 2 files changed, 96 insertions(+), 8 deletions(-)
diff --git a/drivers/mmc/renesas-sdhi.c b/drivers/mmc/renesas-sdhi.c index 1ed50d6292..259b4f71ed 100644 --- a/drivers/mmc/renesas-sdhi.c +++ b/drivers/mmc/renesas-sdhi.c @@ -17,7 +17,9 @@
#include "tmio-common.h"
-#if CONFIG_IS_ENABLED(MMC_HS200_SUPPORT) +#if CONFIG_IS_ENABLED(MMC_UHS_SUPPORT) || \ + CONFIG_IS_ENABLED(MMC_HS200_SUPPORT) || \ + CONFIG_IS_ENABLED(MMC_HS400_SUPPORT)
/* SCC registers */ #define RENESAS_SDHI_SCC_DTCNTL 0x800 @@ -107,6 +109,56 @@ static void renesas_sdhi_reset_tuning(struct tmio_sd_priv *priv) tmio_sd_writel(priv, reg, RENESAS_SDHI_SCC_RVSCNTL); }
+static int renesas_sdhi_hs400(struct udevice *dev) +{ + struct tmio_sd_priv *priv = dev_get_priv(dev); + struct mmc *mmc = mmc_get_mmc_dev(dev); + bool hs400 = (mmc->selected_mode == MMC_HS_400); + int ret, taps = hs400 ? priv->nrtaps : 8; + u32 reg; + + if (taps == 4) /* HS400 on 4tap SoC needs different clock */ + ret = clk_set_rate(&priv->clk, 400000000); + else + ret = clk_set_rate(&priv->clk, 200000000); + if (ret < 0) + return ret; + + tmio_sd_writel(priv, 0, RENESAS_SDHI_SCC_RVSREQ); + + reg = tmio_sd_readl(priv, RENESAS_SDHI_SCC_TMPPORT2); + if (hs400) { + reg |= RENESAS_SDHI_SCC_TMPPORT2_HS400EN | + RENESAS_SDHI_SCC_TMPPORT2_HS400OSEL; + } else { + reg &= ~(RENESAS_SDHI_SCC_TMPPORT2_HS400EN | + RENESAS_SDHI_SCC_TMPPORT2_HS400OSEL); + } + + tmio_sd_writel(priv, reg, RENESAS_SDHI_SCC_TMPPORT2); + + tmio_sd_writel(priv, (taps << RENESAS_SDHI_SCC_DTCNTL_TAPNUM_SHIFT) | + RENESAS_SDHI_SCC_DTCNTL_TAPEN, + RENESAS_SDHI_SCC_DTCNTL); + + if (taps == 4) { + tmio_sd_writel(priv, priv->tap_set >> 1, + RENESAS_SDHI_SCC_TAPSET); + } else { + tmio_sd_writel(priv, priv->tap_set, RENESAS_SDHI_SCC_TAPSET); + } + + reg = tmio_sd_readl(priv, RENESAS_SDHI_SCC_CKSEL); + reg |= RENESAS_SDHI_SCC_CKSEL_DTSEL; + tmio_sd_writel(priv, reg, RENESAS_SDHI_SCC_CKSEL); + + reg = tmio_sd_readl(priv, RENESAS_SDHI_SCC_RVSCNTL); + reg |= RENESAS_SDHI_SCC_RVSCNTL_RVSEN; + tmio_sd_writel(priv, reg, RENESAS_SDHI_SCC_RVSCNTL); + + return 0; +} + static void renesas_sdhi_prepare_tuning(struct tmio_sd_priv *priv, unsigned long tap) { @@ -239,6 +291,7 @@ int renesas_sdhi_execute_tuning(struct udevice *dev, uint opcode)
/* clock tuning is not needed for upto 52MHz */ if (!((mmc->selected_mode == MMC_HS_200) || + (mmc->selected_mode == MMC_HS_400) || (mmc->selected_mode == UHS_SDR104) || (mmc->selected_mode == UHS_SDR50))) return 0; @@ -286,19 +339,42 @@ out:
return ret; } +#else +static int renesas_sdhi_hs400(struct udevice *dev) +{ + return 0; +} #endif
static int renesas_sdhi_set_ios(struct udevice *dev) { - int ret = tmio_sd_set_ios(dev); + struct tmio_sd_priv *priv = dev_get_priv(dev); + struct mmc *mmc = mmc_get_mmc_dev(dev); + u32 tmp; + int ret;
- mdelay(10); + /* 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 CONFIG_IS_ENABLED(MMC_HS200_SUPPORT) - struct tmio_sd_priv *priv = dev_get_priv(dev); + ret = renesas_sdhi_hs400(dev); + if (ret) + return ret; + + ret = tmio_sd_set_ios(dev);
- if (priv->caps & TMIO_SD_CAP_RCAR_UHS) + mdelay(10); + +#if CONFIG_IS_ENABLED(MMC_UHS_SUPPORT) || \ + CONFIG_IS_ENABLED(MMC_HS200_SUPPORT) || \ + CONFIG_IS_ENABLED(MMC_HS400_SUPPORT) + 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)) { renesas_sdhi_reset_tuning(priv); + } #endif
return ret; @@ -330,7 +406,9 @@ 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_UHS_SUPPORT) || CONFIG_IS_ENABLED(MMC_HS200_SUPPORT) +#if CONFIG_IS_ENABLED(MMC_UHS_SUPPORT) || \ + CONFIG_IS_ENABLED(MMC_HS200_SUPPORT) || \ + CONFIG_IS_ENABLED(MMC_HS400_SUPPORT) .execute_tuning = renesas_sdhi_execute_tuning, #endif #if CONFIG_IS_ENABLED(MMC_UHS_SUPPORT) @@ -377,6 +455,13 @@ static void renesas_sdhi_filter_caps(struct udevice *dev) (rmobile_get_cpu_rev_integer() == 1) && (rmobile_get_cpu_rev_fraction() <= 1))) plat->cfg.host_caps &= ~MMC_MODE_HS400; + + /* H3 ES2.0 uses 4 tuning taps */ + if ((rmobile_get_cpu_type() == RMOBILE_CPU_TYPE_R8A7795) && + (rmobile_get_cpu_rev_integer() == 2)) + priv->nrtaps = 4; + else + priv->nrtaps = 8; }
static int renesas_sdhi_probe(struct udevice *dev) @@ -426,7 +511,9 @@ static int renesas_sdhi_probe(struct udevice *dev)
renesas_sdhi_filter_caps(dev);
-#if CONFIG_IS_ENABLED(MMC_HS200_SUPPORT) +#if CONFIG_IS_ENABLED(MMC_UHS_SUPPORT) || \ + CONFIG_IS_ENABLED(MMC_HS200_SUPPORT) || \ + CONFIG_IS_ENABLED(MMC_HS400_SUPPORT) if (!ret && (priv->caps & TMIO_SD_CAP_RCAR_UHS)) renesas_sdhi_reset_tuning(priv); #endif diff --git a/drivers/mmc/tmio-common.h b/drivers/mmc/tmio-common.h index 9a427b5311..192026ce3e 100644 --- a/drivers/mmc/tmio-common.h +++ b/drivers/mmc/tmio-common.h @@ -137,6 +137,7 @@ struct tmio_sd_priv { #endif #if CONFIG_IS_ENABLED(RENESAS_SDHI) u8 tap_set; + u8 nrtaps; #endif ulong (*clk_get_rate)(struct tmio_sd_priv *); };

On 11/14/2018 12:40 AM, Marek Vasut wrote:
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
Yamada-san, can you please check 1/6..3/6 ?
Thanks !

On Tue, Nov 27, 2018 at 6:35 AM Marek Vasut marek.vasut@gmail.com wrote:
On 11/14/2018 12:40 AM, Marek Vasut wrote:
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
Yamada-san, can you please check 1/6..3/6 ?
Not tested, but 1/6, 2/6 look good. I left comments in 3/6.
-- Best Regards Masahiro Yamada

On 11/27/2018 04:45 AM, Masahiro Yamada wrote:
On Tue, Nov 27, 2018 at 6:35 AM Marek Vasut marek.vasut@gmail.com wrote:
On 11/14/2018 12:40 AM, Marek Vasut wrote:
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
Yamada-san, can you please check 1/6..3/6 ?
Not tested, but 1/6, 2/6 look good. I left comments in 3/6.
You can grab the whole bulk at [1] and test it if you want. There are some extra renesas-specific bits, but those shouldn't affect you.
btw is there any chance to buy a uniphier board with TMIO SD controller?
[1] https://github.com/marex/u-boot-sh/commits/mmc-next-v4
participants (2)
-
Marek Vasut
-
Masahiro Yamada