[U-Boot] [PATCH 1/7] mmc: uniphier-sd: Use mmc_of_parse()

Drop the ad-hoc DT caps parsing in favor of common framework function.
Signed-off-by: Marek Vasut marek.vasut+renesas@gmail.com Cc: Jaehoon Chung jh80.chung@samsung.com Cc: Masahiro Yamada yamada.masahiro@socionext.com --- drivers/mmc/uniphier-sd.c | 23 +++++++---------------- 1 file changed, 7 insertions(+), 16 deletions(-)
diff --git a/drivers/mmc/uniphier-sd.c b/drivers/mmc/uniphier-sd.c index 741f9dfd9c..552e37d852 100644 --- a/drivers/mmc/uniphier-sd.c +++ b/drivers/mmc/uniphier-sd.c @@ -799,24 +799,15 @@ static int uniphier_sd_probe(struct udevice *dev) return ret; }
- plat->cfg.name = dev->name; - plat->cfg.host_caps = MMC_MODE_HS_52MHz | MMC_MODE_HS; - - switch (fdtdec_get_int(gd->fdt_blob, dev_of_offset(dev), "bus-width", - 1)) { - case 8: - plat->cfg.host_caps |= MMC_MODE_8BIT; - break; - case 4: - plat->cfg.host_caps |= MMC_MODE_4BIT; - break; - case 1: - break; - default: - dev_err(dev, "Invalid "bus-width" value\n"); - return -EINVAL; + ret = mmc_of_parse(dev, &plat->cfg); + if (ret < 0) { + dev_err(dev, "failed to parse host caps\n"); + return ret; }
+ plat->cfg.name = dev->name; + plat->cfg.host_caps |= MMC_MODE_HS_52MHz | MMC_MODE_HS; + if (quirks) { priv->caps = quirks; } else {

Factor out the regulator handling into set_ios and add support for selecting pin configuration based on the voltage to support UHS modes.
Signed-off-by: Marek Vasut marek.vasut+renesas@gmail.com Cc: Jaehoon Chung jh80.chung@samsung.com Cc: Masahiro Yamada yamada.masahiro@socionext.com --- drivers/mmc/uniphier-sd.c | 33 ++++++++++++++++++++++++--------- 1 file changed, 24 insertions(+), 9 deletions(-)
diff --git a/drivers/mmc/uniphier-sd.c b/drivers/mmc/uniphier-sd.c index 552e37d852..ebcc12a8ae 100644 --- a/drivers/mmc/uniphier-sd.c +++ b/drivers/mmc/uniphier-sd.c @@ -10,6 +10,7 @@ #include <fdtdec.h> #include <mmc.h> #include <dm.h> +#include <dm/pinctrl.h> #include <linux/compat.h> #include <linux/dma-direction.h> #include <linux/io.h> @@ -134,6 +135,9 @@ struct uniphier_sd_priv { #define UNIPHIER_SD_CAP_DMA_INTERNAL BIT(1) /* have internal DMA engine */ #define UNIPHIER_SD_CAP_DIV1024 BIT(2) /* divisor 1024 is available */ #define UNIPHIER_SD_CAP_64BIT BIT(3) /* Controller is 64bit */ +#ifdef CONFIG_DM_REGULATOR + struct udevice *vqmmc_dev; +#endif };
static u64 uniphier_sd_readq(struct uniphier_sd_priv *priv, unsigned int reg) @@ -676,6 +680,24 @@ static void uniphier_sd_set_clk_rate(struct uniphier_sd_priv *priv, udelay(1000); }
+static void uniphier_sd_set_pins(struct udevice *dev) +{ + struct uniphier_sd_priv *priv = dev_get_priv(dev); + struct mmc *mmc = mmc_get_mmc_dev(dev); + + if (priv->vqmmc_dev) { + if (mmc->signal_voltage == MMC_SIGNAL_VOLTAGE_180) + regulator_set_value(priv->vqmmc_dev, 1800000); + else + regulator_set_value(priv->vqmmc_dev, 3300000); + } + + if (mmc->signal_voltage == MMC_SIGNAL_VOLTAGE_180) + pinctrl_select_state(dev, "state_uhs"); + else + pinctrl_select_state(dev, "default"); +} + static int uniphier_sd_set_ios(struct udevice *dev) { struct uniphier_sd_priv *priv = dev_get_priv(dev); @@ -690,6 +712,7 @@ static int uniphier_sd_set_ios(struct udevice *dev) return ret; uniphier_sd_set_ddr_mode(priv, mmc); uniphier_sd_set_clk_rate(priv, mmc); + uniphier_sd_set_pins(dev);
return 0; } @@ -757,9 +780,6 @@ static int uniphier_sd_probe(struct udevice *dev) fdt_addr_t base; struct clk clk; int ret; -#ifdef CONFIG_DM_REGULATOR - struct udevice *vqmmc_dev; -#endif
base = devfdt_get_addr(dev); if (base == FDT_ADDR_T_NONE) @@ -770,12 +790,7 @@ static int uniphier_sd_probe(struct udevice *dev) return -ENOMEM;
#ifdef CONFIG_DM_REGULATOR - ret = device_get_supply_regulator(dev, "vqmmc-supply", &vqmmc_dev); - if (!ret) { - /* Set the regulator to 3.3V until we support 1.8V modes */ - regulator_set_value(vqmmc_dev, 3300000); - regulator_set_enable(vqmmc_dev, true); - } + ret = device_get_supply_regulator(dev, "vqmmc-supply", &priv->vqmmc_dev); #endif
ret = clk_get_by_index(dev, 0, &clk);

On 01/07/2018 04:29 AM, Marek Vasut wrote:
Factor out the regulator handling into set_ios and add support for selecting pin configuration based on the voltage to support UHS modes.
Signed-off-by: Marek Vasut marek.vasut+renesas@gmail.com Cc: Jaehoon Chung jh80.chung@samsung.com Cc: Masahiro Yamada yamada.masahiro@socionext.com
drivers/mmc/uniphier-sd.c | 33 ++++++++++++++++++++++++--------- 1 file changed, 24 insertions(+), 9 deletions(-)
diff --git a/drivers/mmc/uniphier-sd.c b/drivers/mmc/uniphier-sd.c index 552e37d852..ebcc12a8ae 100644 --- a/drivers/mmc/uniphier-sd.c +++ b/drivers/mmc/uniphier-sd.c @@ -10,6 +10,7 @@ #include <fdtdec.h> #include <mmc.h> #include <dm.h> +#include <dm/pinctrl.h> #include <linux/compat.h> #include <linux/dma-direction.h> #include <linux/io.h> @@ -134,6 +135,9 @@ struct uniphier_sd_priv { #define UNIPHIER_SD_CAP_DMA_INTERNAL BIT(1) /* have internal DMA engine */ #define UNIPHIER_SD_CAP_DIV1024 BIT(2) /* divisor 1024 is available */ #define UNIPHIER_SD_CAP_64BIT BIT(3) /* Controller is 64bit */ +#ifdef CONFIG_DM_REGULATOR
- struct udevice *vqmmc_dev;
+#endif };
static u64 uniphier_sd_readq(struct uniphier_sd_priv *priv, unsigned int reg) @@ -676,6 +680,24 @@ static void uniphier_sd_set_clk_rate(struct uniphier_sd_priv *priv, udelay(1000); }
+static void uniphier_sd_set_pins(struct udevice *dev) +{
- struct uniphier_sd_priv *priv = dev_get_priv(dev);
- struct mmc *mmc = mmc_get_mmc_dev(dev);
- if (priv->vqmmc_dev) {
You added #ifdef CONFIG_DM_REGULATOR in struct uniphier_sd_priv. If CONFIG_DM_REGULATOR is disabled, it can't refer the vqmmc_dev.?
if (mmc->signal_voltage == MMC_SIGNAL_VOLTAGE_180)
regulator_set_value(priv->vqmmc_dev, 1800000);
else
regulator_set_value(priv->vqmmc_dev, 3300000);
- }
- if (mmc->signal_voltage == MMC_SIGNAL_VOLTAGE_180)
pinctrl_select_state(dev, "state_uhs");
- else
pinctrl_select_state(dev, "default");
+}
static int uniphier_sd_set_ios(struct udevice *dev) { struct uniphier_sd_priv *priv = dev_get_priv(dev); @@ -690,6 +712,7 @@ static int uniphier_sd_set_ios(struct udevice *dev) return ret; uniphier_sd_set_ddr_mode(priv, mmc); uniphier_sd_set_clk_rate(priv, mmc);
uniphier_sd_set_pins(dev);
return 0;
} @@ -757,9 +780,6 @@ static int uniphier_sd_probe(struct udevice *dev) fdt_addr_t base; struct clk clk; int ret; -#ifdef CONFIG_DM_REGULATOR
- struct udevice *vqmmc_dev;
-#endif
base = devfdt_get_addr(dev); if (base == FDT_ADDR_T_NONE) @@ -770,12 +790,7 @@ static int uniphier_sd_probe(struct udevice *dev) return -ENOMEM;
#ifdef CONFIG_DM_REGULATOR
- ret = device_get_supply_regulator(dev, "vqmmc-supply", &vqmmc_dev);
- if (!ret) {
/* Set the regulator to 3.3V until we support 1.8V modes */
regulator_set_value(vqmmc_dev, 3300000);
regulator_set_enable(vqmmc_dev, true);
- }
- ret = device_get_supply_regulator(dev, "vqmmc-supply", &priv->vqmmc_dev);
#endif
ret = clk_get_by_index(dev, 0, &clk);

On 01/12/2018 10:15 AM, Jaehoon Chung wrote:
On 01/07/2018 04:29 AM, Marek Vasut wrote:
Factor out the regulator handling into set_ios and add support for selecting pin configuration based on the voltage to support UHS modes.
Signed-off-by: Marek Vasut marek.vasut+renesas@gmail.com Cc: Jaehoon Chung jh80.chung@samsung.com Cc: Masahiro Yamada yamada.masahiro@socionext.com
drivers/mmc/uniphier-sd.c | 33 ++++++++++++++++++++++++--------- 1 file changed, 24 insertions(+), 9 deletions(-)
diff --git a/drivers/mmc/uniphier-sd.c b/drivers/mmc/uniphier-sd.c index 552e37d852..ebcc12a8ae 100644 --- a/drivers/mmc/uniphier-sd.c +++ b/drivers/mmc/uniphier-sd.c @@ -10,6 +10,7 @@ #include <fdtdec.h> #include <mmc.h> #include <dm.h> +#include <dm/pinctrl.h> #include <linux/compat.h> #include <linux/dma-direction.h> #include <linux/io.h> @@ -134,6 +135,9 @@ struct uniphier_sd_priv { #define UNIPHIER_SD_CAP_DMA_INTERNAL BIT(1) /* have internal DMA engine */ #define UNIPHIER_SD_CAP_DIV1024 BIT(2) /* divisor 1024 is available */ #define UNIPHIER_SD_CAP_64BIT BIT(3) /* Controller is 64bit */ +#ifdef CONFIG_DM_REGULATOR
- struct udevice *vqmmc_dev;
+#endif };
static u64 uniphier_sd_readq(struct uniphier_sd_priv *priv, unsigned int reg) @@ -676,6 +680,24 @@ static void uniphier_sd_set_clk_rate(struct uniphier_sd_priv *priv, udelay(1000); }
+static void uniphier_sd_set_pins(struct udevice *dev) +{
- struct uniphier_sd_priv *priv = dev_get_priv(dev);
- struct mmc *mmc = mmc_get_mmc_dev(dev);
- if (priv->vqmmc_dev) {
You added #ifdef CONFIG_DM_REGULATOR in struct uniphier_sd_priv. If CONFIG_DM_REGULATOR is disabled, it can't refer the vqmmc_dev.?
Oh, thanks. V2 is coming.

Add a quirk to identify that the controller is Renesas RCar variant of the Matsushita SD IP and another quirk indicating it can support Renesas RCar HS200/HS400/SDR104 modes.
Signed-off-by: Marek Vasut marek.vasut+renesas@gmail.com Cc: Jaehoon Chung jh80.chung@samsung.com Cc: Masahiro Yamada yamada.masahiro@socionext.com --- drivers/mmc/uniphier-sd.c | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-)
diff --git a/drivers/mmc/uniphier-sd.c b/drivers/mmc/uniphier-sd.c index ebcc12a8ae..bcc2dec459 100644 --- a/drivers/mmc/uniphier-sd.c +++ b/drivers/mmc/uniphier-sd.c @@ -135,6 +135,8 @@ struct uniphier_sd_priv { #define UNIPHIER_SD_CAP_DMA_INTERNAL BIT(1) /* have internal DMA engine */ #define UNIPHIER_SD_CAP_DIV1024 BIT(2) /* divisor 1024 is available */ #define UNIPHIER_SD_CAP_64BIT BIT(3) /* Controller is 64bit */ +#define UNIPHIER_SD_CAP_RCAR BIT(4) /* Renesas RCar version of IP */ +#define UNIPHIER_SD_CAP_RCAR_UHS BIT(5) /* Renesas RCar UHS/SDR modes */ #ifdef CONFIG_DM_REGULATOR struct udevice *vqmmc_dev; #endif @@ -852,11 +854,14 @@ static int uniphier_sd_probe(struct udevice *dev) return 0; }
+#define RENESAS_SD_QUIRKS \ + UNIPHIER_SD_CAP_64BIT | UNIPHIER_SD_CAP_RCAR | UNIPHIER_SD_CAP_RCAR_UHS + static const struct udevice_id uniphier_sd_match[] = { - { .compatible = "renesas,sdhi-r8a7795", .data = UNIPHIER_SD_CAP_64BIT }, - { .compatible = "renesas,sdhi-r8a7796", .data = UNIPHIER_SD_CAP_64BIT }, - { .compatible = "renesas,sdhi-r8a77970", .data = UNIPHIER_SD_CAP_64BIT }, - { .compatible = "renesas,sdhi-r8a77995", .data = UNIPHIER_SD_CAP_64BIT }, + { .compatible = "renesas,sdhi-r8a7795", .data = RENESAS_SD_QUIRKS }, + { .compatible = "renesas,sdhi-r8a7796", .data = RENESAS_SD_QUIRKS }, + { .compatible = "renesas,sdhi-r8a77970", .data = RENESAS_SD_QUIRKS }, + { .compatible = "renesas,sdhi-r8a77995", .data = RENESAS_SD_QUIRKS }, { .compatible = "socionext,uniphier-sdhc", .data = 0 }, { /* sentinel */ } };

On the Renesas version of the IP, the /1 divider is realized by setting the clock register [7:0] to 0xff instead of setting bit 10 of the register. Check the quirk and handle accordingly.
Signed-off-by: Marek Vasut marek.vasut+renesas@gmail.com Cc: Jaehoon Chung jh80.chung@samsung.com Cc: Masahiro Yamada yamada.masahiro@socionext.com --- drivers/mmc/uniphier-sd.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-)
diff --git a/drivers/mmc/uniphier-sd.c b/drivers/mmc/uniphier-sd.c index bcc2dec459..f0cf14c264 100644 --- a/drivers/mmc/uniphier-sd.c +++ b/drivers/mmc/uniphier-sd.c @@ -75,6 +75,7 @@ DECLARE_GLOBAL_DATA_PTR; #define UNIPHIER_SD_CLKCTL_DIV4 BIT(0) /* SDCLK = CLK / 4 */ #define UNIPHIER_SD_CLKCTL_DIV2 0 /* SDCLK = CLK / 2 */ #define UNIPHIER_SD_CLKCTL_DIV1 BIT(10) /* SDCLK = CLK */ +#define UNIPHIER_SD_CLKCTL_RCAR_DIV1 0xff /* SDCLK = CLK (RCar ver.) */ #define UNIPHIER_SD_CLKCTL_OFFEN BIT(9) /* stop SDCLK when unused */ #define UNIPHIER_SD_CLKCTL_SCLKEN BIT(8) /* SDCLK output enable */ #define UNIPHIER_SD_SIZE 0x04c /* block size */ @@ -641,7 +642,8 @@ static void uniphier_sd_set_clk_rate(struct uniphier_sd_priv *priv, divisor = DIV_ROUND_UP(priv->mclk, mmc->clock);
if (divisor <= 1) - val = UNIPHIER_SD_CLKCTL_DIV1; + val = (priv->caps & UNIPHIER_SD_CAP_RCAR) ? + UNIPHIER_SD_CLKCTL_RCAR_DIV1 : UNIPHIER_SD_CLKCTL_DIV1; else if (divisor <= 2) val = UNIPHIER_SD_CLKCTL_DIV2; else if (divisor <= 4)

Add code for PHY tuning required for SDR104/HS200 support on Renesas RCar.
Signed-off-by: Marek Vasut marek.vasut+renesas@gmail.com Cc: Jaehoon Chung jh80.chung@samsung.com Cc: Masahiro Yamada yamada.masahiro@socionext.com --- drivers/mmc/uniphier-sd.c | 290 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 290 insertions(+)
diff --git a/drivers/mmc/uniphier-sd.c b/drivers/mmc/uniphier-sd.c index f0cf14c264..3e0d61268e 100644 --- a/drivers/mmc/uniphier-sd.c +++ b/drivers/mmc/uniphier-sd.c @@ -143,6 +143,10 @@ struct uniphier_sd_priv { #endif };
+#if CONFIG_IS_ENABLED(MMC_HS200_SUPPORT) +static void uniphier_sd_reset_tuning(struct uniphier_sd_priv *priv); +#endif + static u64 uniphier_sd_readq(struct uniphier_sd_priv *priv, unsigned int reg) { if (priv->caps & UNIPHIER_SD_CAP_64BIT) @@ -596,6 +600,7 @@ static int uniphier_sd_set_bus_width(struct uniphier_sd_priv *priv, u32 val, tmp;
switch (mmc->bus_width) { + case 0: case 1: val = UNIPHIER_SD_OPTION_WIDTH_1; break; @@ -694,6 +699,7 @@ static void uniphier_sd_set_pins(struct udevice *dev) regulator_set_value(priv->vqmmc_dev, 1800000); else regulator_set_value(priv->vqmmc_dev, 3300000); + regulator_set_enable(priv->vqmmc_dev, true); }
if (mmc->signal_voltage == MMC_SIGNAL_VOLTAGE_180) @@ -718,6 +724,11 @@ static int uniphier_sd_set_ios(struct udevice *dev) uniphier_sd_set_clk_rate(priv, mmc); uniphier_sd_set_pins(dev);
+#if CONFIG_IS_ENABLED(MMC_HS200_SUPPORT) + if (priv->caps & UNIPHIER_SD_CAP_RCAR_UHS) + uniphier_sd_reset_tuning(priv); +#endif + return 0; }
@@ -732,10 +743,284 @@ static int uniphier_sd_get_cd(struct udevice *dev) UNIPHIER_SD_INFO1_CD); }
+/* + * Renesas RCar SDR104 / HS200 + */ +#if CONFIG_IS_ENABLED(MMC_HS200_SUPPORT) + +/* SCC registers */ +#define SH_MOBILE_SDHI_SCC_DTCNTL 0x800 +#define SH_MOBILE_SDHI_SCC_DTCNTL_TAPEN BIT(0) +#define SH_MOBILE_SDHI_SCC_DTCNTL_TAPNUM_SHIFT 16 +#define SH_MOBILE_SDHI_SCC_DTCNTL_TAPNUM_MASK 0xff +#define SH_MOBILE_SDHI_SCC_TAPSET 0x804 +#define SH_MOBILE_SDHI_SCC_DT2FF 0x808 +#define SH_MOBILE_SDHI_SCC_CKSEL 0x80c +#define SH_MOBILE_SDHI_SCC_CKSEL_DTSEL BIT(0) +#define SH_MOBILE_SDHI_SCC_RVSCNTL 0x810 +#define SH_MOBILE_SDHI_SCC_RVSCNTL_RVSEN BIT(0) +#define SH_MOBILE_SDHI_SCC_RVSREQ 0x814 +#define SH_MOBILE_SDHI_SCC_RVSREQ_RVSERR BIT(2) +#define SH_MOBILE_SDHI_SCC_SMPCMP 0x818 +#define SH_MOBILE_SDHI_SCC_TMPPORT2 0x81c + +#define SH_MOBILE_SDHI_MAX_TAP 3 + +static unsigned int uniphier_sd_init_tuning(struct uniphier_sd_priv *priv) +{ + u32 reg; + + /* Initialize SCC */ + uniphier_sd_writel(priv, 0, UNIPHIER_SD_INFO1); + + reg = uniphier_sd_readl(priv, UNIPHIER_SD_CLKCTL); + reg &= ~UNIPHIER_SD_CLKCTL_SCLKEN; + uniphier_sd_writel(priv, reg, UNIPHIER_SD_CLKCTL); + + /* Set sampling clock selection range */ + uniphier_sd_writel(priv, 0x8 << SH_MOBILE_SDHI_SCC_DTCNTL_TAPNUM_SHIFT, + SH_MOBILE_SDHI_SCC_DTCNTL); + + reg = uniphier_sd_readl(priv, SH_MOBILE_SDHI_SCC_DTCNTL); + reg |= SH_MOBILE_SDHI_SCC_DTCNTL_TAPEN; + uniphier_sd_writel(priv, reg, SH_MOBILE_SDHI_SCC_DTCNTL); + + reg = uniphier_sd_readl(priv, SH_MOBILE_SDHI_SCC_CKSEL); + reg |= SH_MOBILE_SDHI_SCC_CKSEL_DTSEL; + uniphier_sd_writel(priv, reg, SH_MOBILE_SDHI_SCC_CKSEL); + + reg = uniphier_sd_readl(priv, SH_MOBILE_SDHI_SCC_RVSCNTL); + reg &= ~SH_MOBILE_SDHI_SCC_RVSCNTL_RVSEN; + uniphier_sd_writel(priv, reg, SH_MOBILE_SDHI_SCC_RVSCNTL); + + uniphier_sd_writel(priv, 0x300 /* scc_tappos */, + SH_MOBILE_SDHI_SCC_DT2FF); + + reg = uniphier_sd_readl(priv, UNIPHIER_SD_CLKCTL); + reg |= UNIPHIER_SD_CLKCTL_SCLKEN; + uniphier_sd_writel(priv, reg, UNIPHIER_SD_CLKCTL); + + /* Read TAPNUM */ + return (uniphier_sd_readl(priv, SH_MOBILE_SDHI_SCC_DTCNTL) >> + SH_MOBILE_SDHI_SCC_DTCNTL_TAPNUM_SHIFT) & + SH_MOBILE_SDHI_SCC_DTCNTL_TAPNUM_MASK; +} + +static void uniphier_sd_reset_tuning(struct uniphier_sd_priv *priv) +{ + u32 reg; + + /* Reset SCC */ + reg = uniphier_sd_readl(priv, UNIPHIER_SD_CLKCTL); + reg &= ~UNIPHIER_SD_CLKCTL_SCLKEN; + uniphier_sd_writel(priv, reg, UNIPHIER_SD_CLKCTL); + + reg = uniphier_sd_readl(priv, SH_MOBILE_SDHI_SCC_CKSEL); + reg &= ~SH_MOBILE_SDHI_SCC_CKSEL_DTSEL; + uniphier_sd_writel(priv, reg, SH_MOBILE_SDHI_SCC_CKSEL); + + reg = uniphier_sd_readl(priv, UNIPHIER_SD_CLKCTL); + reg |= UNIPHIER_SD_CLKCTL_SCLKEN; + uniphier_sd_writel(priv, reg, UNIPHIER_SD_CLKCTL); + + reg = uniphier_sd_readl(priv, SH_MOBILE_SDHI_SCC_RVSCNTL); + reg &= ~SH_MOBILE_SDHI_SCC_RVSCNTL_RVSEN; + uniphier_sd_writel(priv, reg, SH_MOBILE_SDHI_SCC_RVSCNTL); + + reg = uniphier_sd_readl(priv, SH_MOBILE_SDHI_SCC_RVSCNTL); + reg &= ~SH_MOBILE_SDHI_SCC_RVSCNTL_RVSEN; + uniphier_sd_writel(priv, reg, SH_MOBILE_SDHI_SCC_RVSCNTL); +} + +static void uniphier_sd_prepare_tuning(struct uniphier_sd_priv *priv, + unsigned long tap) +{ + /* Set sampling clock position */ + uniphier_sd_writel(priv, tap, SH_MOBILE_SDHI_SCC_TAPSET); +} + +static unsigned int sh_mobile_sdhi_compare_scc_data(struct uniphier_sd_priv *priv) +{ + /* Get comparison of sampling data */ + return uniphier_sd_readl(priv, SH_MOBILE_SDHI_SCC_SMPCMP); +} + +static int uniphier_sd_select_tuning(struct uniphier_sd_priv *priv, + unsigned int tap_num, unsigned int taps, + 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 */ + unsigned long match_cnt;/* counter of matching data */ + unsigned long i; + bool select = false; + u32 reg; + + /* Clear SCC_RVSREQ */ + uniphier_sd_writel(priv, 0, SH_MOBILE_SDHI_SCC_RVSREQ); + + /* Merge the results */ + for (i = 0; i < tap_num * 2; i++) { + if (!(taps & BIT(i))) { + taps &= ~BIT(i % tap_num); + taps &= ~BIT((i % tap_num) + tap_num); + } + if (!(smpcmp & BIT(i))) { + smpcmp &= ~BIT(i % tap_num); + smpcmp &= ~BIT((i % tap_num) + tap_num); + } + } + + /* + * Find the longest consecutive run of successful probes. If that + * is more than SH_MOBILE_SDHI_MAX_TAP probes long then use the + * center index as the tap. + */ + tap_cnt = 0; + ntap = 0; + tap_start = 0; + tap_end = 0; + for (i = 0; i < tap_num * 2; i++) { + if (taps & BIT(i)) + ntap++; + else { + if (ntap > tap_cnt) { + tap_start = i - ntap; + tap_end = i - 1; + tap_cnt = ntap; + } + ntap = 0; + } + } + + if (ntap > tap_cnt) { + tap_start = i - ntap; + tap_end = i - 1; + tap_cnt = ntap; + } + + /* + * If all of the TAP is OK, the sampling clock position is selected by + * identifying the change point of data. + */ + if (tap_cnt == tap_num * 2) { + match_cnt = 0; + ntap = 0; + tap_start = 0; + tap_end = 0; + for (i = 0; i < tap_num * 2; i++) { + if (smpcmp & BIT(i)) + ntap++; + else { + if (ntap > match_cnt) { + tap_start = i - ntap; + tap_end = i - 1; + match_cnt = ntap; + } + ntap = 0; + } + } + if (ntap > match_cnt) { + tap_start = i - ntap; + tap_end = i - 1; + match_cnt = ntap; + } + if (match_cnt) + select = true; + } else if (tap_cnt >= SH_MOBILE_SDHI_MAX_TAP) + select = true; + + if (select) + tap_set = ((tap_start + tap_end) / 2) % tap_num; + else + return -EIO; + + /* Set SCC */ + uniphier_sd_writel(priv, tap_set, SH_MOBILE_SDHI_SCC_TAPSET); + + /* Enable auto re-tuning */ + reg = uniphier_sd_readl(priv, SH_MOBILE_SDHI_SCC_RVSCNTL); + reg |= SH_MOBILE_SDHI_SCC_RVSCNTL_RVSEN; + uniphier_sd_writel(priv, reg, SH_MOBILE_SDHI_SCC_RVSCNTL); + + return 0; +} + +static int uniphier_sd_execute_tuning(struct udevice *dev, uint opcode) +{ + struct uniphier_sd_priv *priv = dev_get_priv(dev); + struct mmc_uclass_priv *upriv = dev_get_uclass_priv(dev); + struct mmc *mmc = upriv->mmc; + unsigned int tap_num; + unsigned int taps = 0, smpcmp = 0; + int i, ret = 0; + u32 caps; + + /* Only supported on Renesas RCar */ + if (!(priv->caps & UNIPHIER_SD_CAP_RCAR_UHS)) + return -EINVAL; + + /* clock tuning is not needed for upto 52MHz */ + if (!((mmc->selected_mode == MMC_HS_200) || + (mmc->selected_mode == UHS_SDR104) || + (mmc->selected_mode == UHS_SDR50))) + return 0; + + tap_num = uniphier_sd_init_tuning(priv); + if (!tap_num) + /* Tuning is not supported */ + goto out; + + if (tap_num * 2 >= sizeof(taps) * 8) { + dev_err(dev, + "Too many taps, skipping tuning. Please consider updating size of taps field of tmio_mmc_host\n"); + goto out; + } + + /* Issue CMD19 twice for each tap */ + for (i = 0; i < 2 * tap_num; i++) { + uniphier_sd_prepare_tuning(priv, i % tap_num); + + /* Force PIO for the tuning */ + caps = priv->caps; + priv->caps &= ~UNIPHIER_SD_CAP_DMA_INTERNAL; + + ret = mmc_send_tuning(mmc, opcode, NULL); + + priv->caps = caps; + + if (ret == 0) + taps |= BIT(i); + + ret = sh_mobile_sdhi_compare_scc_data(priv); + if (ret == 0) + smpcmp |= BIT(i); + + mdelay(1); + } + + ret = uniphier_sd_select_tuning(priv, tap_num, taps, smpcmp); + +out: + if (ret < 0) { + dev_warn(dev, "Tuning procedure failed\n"); + uniphier_sd_reset_tuning(priv); + } + + return ret; +} +#endif + static const struct dm_mmc_ops uniphier_sd_ops = { .send_cmd = uniphier_sd_send_cmd, .set_ios = uniphier_sd_set_ios, .get_cd = uniphier_sd_get_cd, +#if CONFIG_IS_ENABLED(MMC_HS200_SUPPORT) + .execute_tuning = uniphier_sd_execute_tuning, +#endif };
static void uniphier_sd_host_init(struct uniphier_sd_priv *priv) @@ -853,6 +1138,11 @@ static int uniphier_sd_probe(struct udevice *dev)
upriv->mmc = &plat->mmc;
+#if CONFIG_IS_ENABLED(MMC_HS200_SUPPORT) + if (priv->caps & UNIPHIER_SD_CAP_RCAR_UHS) + uniphier_sd_reset_tuning(priv); +#endif + return 0; }

The DMA READ completion flag position differs on Socionext and Renesas SoCs. It is bit 20 on Socionext SoCs and using bit 17 is a hardware bug and forbidden. It is bit 17 on Renesas SoCs and bit 20 does not work on them.
Signed-off-by: Marek Vasut marek.vasut+renesas@gmail.com Cc: Jaehoon Chung jh80.chung@samsung.com Cc: Masahiro Yamada yamada.masahiro@socionext.com --- drivers/mmc/uniphier-sd.c | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-)
diff --git a/drivers/mmc/uniphier-sd.c b/drivers/mmc/uniphier-sd.c index 3e0d61268e..62f2031a04 100644 --- a/drivers/mmc/uniphier-sd.c +++ b/drivers/mmc/uniphier-sd.c @@ -108,8 +108,8 @@ DECLARE_GLOBAL_DATA_PTR; #define UNIPHIER_SD_DMA_RST_RD BIT(9) #define UNIPHIER_SD_DMA_RST_WR BIT(8) #define UNIPHIER_SD_DMA_INFO1 0x420 -#define UNIPHIER_SD_DMA_INFO1_END_RD2 BIT(20) /* DMA from device is complete*/ -#define UNIPHIER_SD_DMA_INFO1_END_RD BIT(17) /* Don't use! Hardware bug */ +#define UNIPHIER_SD_DMA_INFO1_END_RD2 BIT(20) /* DMA from device is complete (uniphier) */ +#define UNIPHIER_SD_DMA_INFO1_END_RD BIT(17) /* DMA from device is complete (renesas) */ #define UNIPHIER_SD_DMA_INFO1_END_WR BIT(16) /* DMA to device is complete */ #define UNIPHIER_SD_DMA_INFO1_MASK 0x424 #define UNIPHIER_SD_DMA_INFO2 0x428 @@ -443,7 +443,15 @@ static int uniphier_sd_dma_xfer(struct udevice *dev, struct mmc_data *data) if (data->flags & MMC_DATA_READ) { buf = data->dest; dir = DMA_FROM_DEVICE; - poll_flag = UNIPHIER_SD_DMA_INFO1_END_RD2; + /* + * The DMA READ completion flag position differs on Socionext + * and Renesas SoCs. It is bit 20 on Socionext SoCs and using + * bit 17 is a hardware bug and forbidden. It is bit 17 on + * Renesas SoCs and bit 20 does not work on them. + */ + poll_flag = (priv->caps & UNIPHIER_SD_CAP_RCAR) ? + UNIPHIER_SD_DMA_INFO1_END_RD : + UNIPHIER_SD_DMA_INFO1_END_RD2; tmp |= UNIPHIER_SD_DMA_MODE_DIR_RD; } else { buf = (void *)data->src;

Handle the controller version even if quirks are set. The controller in Renesas Gen3 SoCs does provide the version register, which indicates a controller v10 and the controller does support internal DMA and /1024 divider.
Signed-off-by: Marek Vasut marek.vasut+renesas@gmail.com Cc: Jaehoon Chung jh80.chung@samsung.com Cc: Masahiro Yamada yamada.masahiro@socionext.com --- drivers/mmc/uniphier-sd.c | 17 ++++++++--------- 1 file changed, 8 insertions(+), 9 deletions(-)
diff --git a/drivers/mmc/uniphier-sd.c b/drivers/mmc/uniphier-sd.c index 62f2031a04..157002e10e 100644 --- a/drivers/mmc/uniphier-sd.c +++ b/drivers/mmc/uniphier-sd.c @@ -1120,16 +1120,15 @@ static int uniphier_sd_probe(struct udevice *dev) plat->cfg.name = dev->name; plat->cfg.host_caps |= MMC_MODE_HS_52MHz | MMC_MODE_HS;
- if (quirks) { + if (quirks) priv->caps = quirks; - } else { - priv->version = uniphier_sd_readl(priv, UNIPHIER_SD_VERSION) & - UNIPHIER_SD_VERSION_IP; - dev_dbg(dev, "version %x\n", priv->version); - if (priv->version >= 0x10) { - priv->caps |= UNIPHIER_SD_CAP_DMA_INTERNAL; - priv->caps |= UNIPHIER_SD_CAP_DIV1024; - } + + priv->version = uniphier_sd_readl(priv, UNIPHIER_SD_VERSION) & + UNIPHIER_SD_VERSION_IP; + dev_dbg(dev, "version %x\n", priv->version); + if (priv->version >= 0x10) { + priv->caps |= UNIPHIER_SD_CAP_DMA_INTERNAL; + priv->caps |= UNIPHIER_SD_CAP_DIV1024; }
if (fdt_get_property(gd->fdt_blob, dev_of_offset(dev), "non-removable",

On 01/06/2018 08:29 PM, Marek Vasut wrote:
Drop the ad-hoc DT caps parsing in favor of common framework function.
Signed-off-by: Marek Vasut marek.vasut+renesas@gmail.com Cc: Jaehoon Chung jh80.chung@samsung.com Cc: Masahiro Yamada yamada.masahiro@socionext.com
Just for completeness, this all applies to u-boot/next , since the HS200 patches which are in next are needed. I'd really appreciate it if these were applied right after that u-boot/next hits u-boot/master after 2018.01 is out .
participants (2)
-
Jaehoon Chung
-
Marek Vasut