[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 --- V2: Protect vqmmc_dev access in uniphier_sd_set_pins() with an ifdef just like everywhere else --- drivers/mmc/uniphier-sd.c | 35 ++++++++++++++++++++++++++--------- 1 file changed, 26 insertions(+), 9 deletions(-)
diff --git a/drivers/mmc/uniphier-sd.c b/drivers/mmc/uniphier-sd.c index 552e37d852..e6c610a22a 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,26 @@ 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); + +#ifdef CONFIG_DM_REGULATOR + 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); + } +#endif + + 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 +714,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 +782,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 +792,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);

2018-01-17 2:16 GMT+09:00 Marek Vasut marek.vasut@gmail.com:
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
V2: Protect vqmmc_dev access in uniphier_sd_set_pins() with an ifdef just like everywhere else
drivers/mmc/uniphier-sd.c | 35 ++++++++++++++++++++++++++--------- 1 file changed, 26 insertions(+), 9 deletions(-)
diff --git a/drivers/mmc/uniphier-sd.c b/drivers/mmc/uniphier-sd.c index 552e37d852..e6c610a22a 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,26 @@ 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);
This gives me a new warning for my board, where CONFIG_DM_REGULATOR is disabled.
drivers/mmc/uniphier-sd.c:685:27: warning: unused variable ‘priv’ [-Wunused-variable] struct uniphier_sd_priv *priv = dev_get_priv(dev); ^~~~
Is it reasonable to surround the whole this function by #if CONFIG_IS_ENABLED(MMC_IO_VOLTAGE) ?
+#ifdef CONFIG_DM_REGULATOR
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);
}
+#endif
if (mmc->signal_voltage == MMC_SIGNAL_VOLTAGE_180)
pinctrl_select_state(dev, "state_uhs");
else
pinctrl_select_state(dev, "default");
+}
I am not sure about this code. If MMC_SIGNAL_VOLTAGE_180 is set, is it always UHS? eMMC also can do 1.8V signaling.
static int uniphier_sd_set_ios(struct udevice *dev) { struct uniphier_sd_priv *priv = dev_get_priv(dev); @@ -690,6 +714,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 +782,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 +792,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);
The return value from device_get_supply_regulator() is overwritten by the following clk_get_by_index().
Shouldn't it be checked?

On 01/25/2018 11:23 AM, Masahiro Yamada wrote:
2018-01-17 2:16 GMT+09:00 Marek Vasut marek.vasut@gmail.com:
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
V2: Protect vqmmc_dev access in uniphier_sd_set_pins() with an ifdef just like everywhere else
drivers/mmc/uniphier-sd.c | 35 ++++++++++++++++++++++++++--------- 1 file changed, 26 insertions(+), 9 deletions(-)
diff --git a/drivers/mmc/uniphier-sd.c b/drivers/mmc/uniphier-sd.c index 552e37d852..e6c610a22a 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,26 @@ 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);
This gives me a new warning for my board, where CONFIG_DM_REGULATOR is disabled.
drivers/mmc/uniphier-sd.c:685:27: warning: unused variable ‘priv’ [-Wunused-variable] struct uniphier_sd_priv *priv = dev_get_priv(dev); ^~~~
Is it reasonable to surround the whole this function by #if CONFIG_IS_ENABLED(MMC_IO_VOLTAGE) ?
No, rather the pinconf bit should be protected by ifdef CONFIG_PINCONF and there should be a __maybe_unused prepended to the mmc variable.
+#ifdef CONFIG_DM_REGULATOR
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);
}
+#endif
if (mmc->signal_voltage == MMC_SIGNAL_VOLTAGE_180)
pinctrl_select_state(dev, "state_uhs");
else
pinctrl_select_state(dev, "default");
+}
I am not sure about this code. If MMC_SIGNAL_VOLTAGE_180 is set, is it always UHS? eMMC also can do 1.8V signaling.
Probably not all of them, so I can add a switch and set the pinconf to UHS only for UHS modes.
static int uniphier_sd_set_ios(struct udevice *dev) { struct uniphier_sd_priv *priv = dev_get_priv(dev); @@ -690,6 +714,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 +782,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 +792,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);
The return value from device_get_supply_regulator() is overwritten by the following clk_get_by_index().
Shouldn't it be checked?
The regulator is optional, so no, it should be discarded. I'll drop the ret =.

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 e6c610a22a..2f7ec680a3 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 @@ -854,11 +856,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 */ } };

2018-01-17 2:16 GMT+09:00 Marek Vasut marek.vasut@gmail.com:
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 e6c610a22a..2f7ec680a3 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 @@ -854,11 +856,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 */ }
};
Acked-by: Masahiro Yamada yamada.masahiro@socionext.com

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 2f7ec680a3..d828535b11 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)

2018-01-17 2:17 GMT+09:00 Marek Vasut marek.vasut@gmail.com:
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 2f7ec680a3..d828535b11 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)
-- 2.15.1
Acked-by: Masahiro Yamada yamada.masahiro@socionext.com

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 d828535b11..2af8244515 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; @@ -695,6 +700,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); } #endif
@@ -720,6 +726,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; }
@@ -734,10 +745,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) @@ -855,6 +1140,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; }

2018-01-17 2:17 GMT+09:00 Marek Vasut marek.vasut@gmail.com:
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 d828535b11..2af8244515 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;
@@ -695,6 +700,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); }
#endif
@@ -720,6 +726,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;
}
@@ -734,10 +745,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) @@ -855,6 +1140,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;
}
--
Honestly, I am terrified by this huge Renesas-specific code. The HS200 support is Renesas's own extension.
Split the code into your file?

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 2af8244515..3b7f04e59a 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;

2018-01-17 2:17 GMT+09:00 Marek Vasut marek.vasut@gmail.com:
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
Acked-by: Masahiro Yamada yamada.masahiro@socionext.com

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 3b7f04e59a..087be5650e 100644 --- a/drivers/mmc/uniphier-sd.c +++ b/drivers/mmc/uniphier-sd.c @@ -1122,16 +1122,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",

2018-01-17 2:17 GMT+09:00 Marek Vasut marek.vasut@gmail.com:
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
Acked-by: Masahiro Yamada yamada.masahiro@socionext.com

Hi,
On 01/17/2018 02:16 AM, 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
If Masahiro is ok, i will pick this patch and others to u-boot-mmc.
Best Regards, Jaehoon Chung
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 {

2018-01-25 10:01 GMT+09:00 Jaehoon Chung jh80.chung@samsung.com:
Hi,
On 01/17/2018 02:16 AM, 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
If Masahiro is ok, i will pick this patch and others to u-boot-mmc.
Best Regards, Jaehoon Chung
Acked-by: Masahiro Yamada yamada.masahiro@socionext.com
participants (3)
-
Jaehoon Chung
-
Marek Vasut
-
Masahiro Yamada