[U-Boot] [PATCH 01/15] mmc: uniphier: Factor out FIFO accessors

Add macros to generate the FIFO accessors, since the code is almost the same with only minor differences. This is done in preparation for adding 16bit variant of the IP.
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/matsushita-common.c | 122 ++++++++++++++++++++-------------------- 1 file changed, 60 insertions(+), 62 deletions(-)
diff --git a/drivers/mmc/matsushita-common.c b/drivers/mmc/matsushita-common.c index ed67710714..4553b168f5 100644 --- a/drivers/mmc/matsushita-common.c +++ b/drivers/mmc/matsushita-common.c @@ -132,11 +132,36 @@ static int matsu_sd_wait_for_irq(struct udevice *dev, unsigned int reg, return 0; }
+#define matsu_pio_read_fifo(__width, __suffix) \ +static void matsu_pio_read_fifo_##__width(struct matsu_sd_priv *priv, \ + char *pbuf, uint blksz) \ +{ \ + u##__width *buf = (u##__width *)pbuf; \ + int i; \ + \ + if (likely(IS_ALIGNED((uintptr_t)buf, ((__width) / 8)))) { \ + for (i = 0; i < blksz / ((__width) / 8); i++) { \ + *buf++ = matsu_sd_read##__suffix(priv, \ + MATSU_SD_BUF); \ + } \ + } else { \ + for (i = 0; i < blksz / ((__width) / 8); i++) { \ + u##__width data; \ + data = matsu_sd_read##__suffix(priv, \ + MATSU_SD_BUF); \ + put_unaligned(data, buf++); \ + } \ + } \ +} + +matsu_pio_read_fifo(64, q) +matsu_pio_read_fifo(32, l) + static int matsu_sd_pio_read_one_block(struct udevice *dev, char *pbuf, uint blocksize) { struct matsu_sd_priv *priv = dev_get_priv(dev); - int i, ret; + int ret;
/* wait until the buffer is filled with data */ ret = matsu_sd_wait_for_irq(dev, MATSU_SD_INFO2, @@ -150,83 +175,56 @@ static int matsu_sd_pio_read_one_block(struct udevice *dev, char *pbuf, */ matsu_sd_writel(priv, 0, MATSU_SD_INFO2);
- if (priv->caps & MATSU_SD_CAP_64BIT) { - u64 *buf = (u64 *)pbuf; - if (likely(IS_ALIGNED((uintptr_t)buf, 8))) { - for (i = 0; i < blocksize / 8; i++) { - *buf++ = matsu_sd_readq(priv, - MATSU_SD_BUF); - } - } else { - for (i = 0; i < blocksize / 8; i++) { - u64 data; - data = matsu_sd_readq(priv, - MATSU_SD_BUF); - put_unaligned(data, buf++); - } - } - } else { - u32 *buf = (u32 *)pbuf; - if (likely(IS_ALIGNED((uintptr_t)buf, 4))) { - for (i = 0; i < blocksize / 4; i++) { - *buf++ = matsu_sd_readl(priv, - MATSU_SD_BUF); - } - } else { - for (i = 0; i < blocksize / 4; i++) { - u32 data; - data = matsu_sd_readl(priv, MATSU_SD_BUF); - put_unaligned(data, buf++); - } - } - } + if (priv->caps & MATSU_SD_CAP_64BIT) + matsu_pio_read_fifo_64(priv, pbuf, blocksize); + else + matsu_pio_read_fifo_32(priv, pbuf, blocksize);
return 0; }
+#define matsu_pio_write_fifo(__width, __suffix) \ +static void matsu_pio_write_fifo_##__width(struct matsu_sd_priv *priv, \ + const char *pbuf, uint blksz)\ +{ \ + const u##__width *buf = (const u##__width *)pbuf; \ + int i; \ + \ + if (likely(IS_ALIGNED((uintptr_t)buf, ((__width) / 8)))) { \ + for (i = 0; i < blksz / ((__width) / 8); i++) { \ + matsu_sd_write##__suffix(priv, *buf++, \ + MATSU_SD_BUF); \ + } \ + } else { \ + for (i = 0; i < blksz / ((__width) / 8); i++) { \ + u##__width data = get_unaligned(buf++); \ + matsu_sd_write##__suffix(priv, data, \ + MATSU_SD_BUF); \ + } \ + } \ +} + +matsu_pio_write_fifo(64, q) +matsu_pio_write_fifo(32, l) + static int matsu_sd_pio_write_one_block(struct udevice *dev, const char *pbuf, uint blocksize) { struct matsu_sd_priv *priv = dev_get_priv(dev); - int i, ret; + int ret;
/* wait until the buffer becomes empty */ ret = matsu_sd_wait_for_irq(dev, MATSU_SD_INFO2, - MATSU_SD_INFO2_BWE); + MATSU_SD_INFO2_BWE); if (ret) return ret;
matsu_sd_writel(priv, 0, MATSU_SD_INFO2);
- if (priv->caps & MATSU_SD_CAP_64BIT) { - const u64 *buf = (const u64 *)pbuf; - if (likely(IS_ALIGNED((uintptr_t)buf, 8))) { - for (i = 0; i < blocksize / 8; i++) { - matsu_sd_writeq(priv, *buf++, - MATSU_SD_BUF); - } - } else { - for (i = 0; i < blocksize / 8; i++) { - u64 data = get_unaligned(buf++); - matsu_sd_writeq(priv, data, - MATSU_SD_BUF); - } - } - } else { - const u32 *buf = (const u32 *)pbuf; - if (likely(IS_ALIGNED((uintptr_t)buf, 4))) { - for (i = 0; i < blocksize / 4; i++) { - matsu_sd_writel(priv, *buf++, - MATSU_SD_BUF); - } - } else { - for (i = 0; i < blocksize / 4; i++) { - u32 data = get_unaligned(buf++); - matsu_sd_writel(priv, data, - MATSU_SD_BUF); - } - } - } + if (priv->caps & MATSU_SD_CAP_64BIT) + matsu_pio_write_fifo_64(priv, pbuf, blocksize); + else + matsu_pio_write_fifo_32(priv, pbuf, blocksize);
return 0; }

Drop useless check in matsu_sd_{read,write}q(), this is only ever called to read the data from FIFO and only when 64bit variant of the block is used anyway.
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/matsushita-common.c | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-)
diff --git a/drivers/mmc/matsushita-common.c b/drivers/mmc/matsushita-common.c index 4553b168f5..ec5469850b 100644 --- a/drivers/mmc/matsushita-common.c +++ b/drivers/mmc/matsushita-common.c @@ -23,19 +23,13 @@ DECLARE_GLOBAL_DATA_PTR;
static u64 matsu_sd_readq(struct matsu_sd_priv *priv, unsigned int reg) { - if (priv->caps & MATSU_SD_CAP_64BIT) - return readq(priv->regbase + (reg << 1)); - else - return readq(priv->regbase + reg); + return readq(priv->regbase + (reg << 1)); }
static void matsu_sd_writeq(struct matsu_sd_priv *priv, u64 val, unsigned int reg) { - if (priv->caps & MATSU_SD_CAP_64BIT) - writeq(val, priv->regbase + (reg << 1)); - else - writeq(val, priv->regbase + reg); + writeq(val, priv->regbase + (reg << 1)); }
static u32 matsu_sd_readl(struct matsu_sd_priv *priv, unsigned int reg)

Add support for 16bit mutation of the Matsushita SD IP. Since some registers are internally 32bit, the matsu_sd_{read,write}l() has to special-case this 16bit variant a bit.
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/matsushita-common.c | 42 +++++++++++++++++++++++++++++++++++++---- drivers/mmc/matsushita-common.h | 1 + 2 files changed, 39 insertions(+), 4 deletions(-)
diff --git a/drivers/mmc/matsushita-common.c b/drivers/mmc/matsushita-common.c index ec5469850b..9f7f47c86b 100644 --- a/drivers/mmc/matsushita-common.c +++ b/drivers/mmc/matsushita-common.c @@ -32,11 +32,31 @@ static void matsu_sd_writeq(struct matsu_sd_priv *priv, writeq(val, priv->regbase + (reg << 1)); }
+static u16 matsu_sd_readw(struct matsu_sd_priv *priv, unsigned int reg) +{ + return readw(priv->regbase + (reg >> 1)); +} + +static void matsu_sd_writew(struct matsu_sd_priv *priv, + u16 val, unsigned int reg) +{ + writew(val, priv->regbase + (reg >> 1)); +} + static u32 matsu_sd_readl(struct matsu_sd_priv *priv, unsigned int reg) { + u32 val; + if (priv->caps & MATSU_SD_CAP_64BIT) return readl(priv->regbase + (reg << 1)); - else + else if (priv->caps & MATSU_SD_CAP_16BIT) { + val = readw(priv->regbase + (reg >> 1)) & 0xffff; + if ((reg == MATSU_SD_RSP10) || (reg == MATSU_SD_RSP32) || + (reg == MATSU_SD_RSP54) || (reg == MATSU_SD_RSP76)) { + val |= readw(priv->regbase + (reg >> 1) + 2) << 16; + } + return val; + } else return readl(priv->regbase + reg); }
@@ -45,7 +65,11 @@ static void matsu_sd_writel(struct matsu_sd_priv *priv, { if (priv->caps & MATSU_SD_CAP_64BIT) writel(val, priv->regbase + (reg << 1)); - else + if (priv->caps & MATSU_SD_CAP_16BIT) { + writew(val & 0xffff, priv->regbase + (reg >> 1)); + if (val >> 16) + writew(val >> 16, priv->regbase + (reg >> 1) + 2); + } else writel(val, priv->regbase + reg); }
@@ -150,6 +174,7 @@ static void matsu_pio_read_fifo_##__width(struct matsu_sd_priv *priv, \
matsu_pio_read_fifo(64, q) matsu_pio_read_fifo(32, l) +matsu_pio_read_fifo(16, w)
static int matsu_sd_pio_read_one_block(struct udevice *dev, char *pbuf, uint blocksize) @@ -171,6 +196,8 @@ static int matsu_sd_pio_read_one_block(struct udevice *dev, char *pbuf,
if (priv->caps & MATSU_SD_CAP_64BIT) matsu_pio_read_fifo_64(priv, pbuf, blocksize); + else if (priv->caps & MATSU_SD_CAP_16BIT) + matsu_pio_read_fifo_16(priv, pbuf, blocksize); else matsu_pio_read_fifo_32(priv, pbuf, blocksize);
@@ -200,6 +227,7 @@ static void matsu_pio_write_fifo_##__width(struct matsu_sd_priv *priv, \
matsu_pio_write_fifo(64, q) matsu_pio_write_fifo(32, l) +matsu_pio_write_fifo(16, w)
static int matsu_sd_pio_write_one_block(struct udevice *dev, const char *pbuf, uint blocksize) @@ -217,6 +245,8 @@ static int matsu_sd_pio_write_one_block(struct udevice *dev,
if (priv->caps & MATSU_SD_CAP_64BIT) matsu_pio_write_fifo_64(priv, pbuf, blocksize); + else if (priv->caps & MATSU_SD_CAP_16BIT) + matsu_pio_write_fifo_16(priv, pbuf, blocksize); else matsu_pio_write_fifo_32(priv, pbuf, blocksize);
@@ -602,8 +632,12 @@ static void matsu_sd_host_init(struct matsu_sd_priv *priv) * This register dropped backward compatibility at version 0x10. * Write an appropriate value depending on the IP version. */ - matsu_sd_writel(priv, priv->version >= 0x10 ? 0x00000101 : 0x00000000, - MATSU_SD_HOST_MODE); + if (priv->version >= 0x10) + matsu_sd_writel(priv, 0x101, MATSU_SD_HOST_MODE); + else if (priv->caps & MATSU_SD_CAP_16BIT) + matsu_sd_writel(priv, 0x1, MATSU_SD_HOST_MODE); + else + matsu_sd_writel(priv, 0x0, MATSU_SD_HOST_MODE);
if (priv->caps & MATSU_SD_CAP_DMA_INTERNAL) { tmp = matsu_sd_readl(priv, MATSU_SD_DMA_MODE); diff --git a/drivers/mmc/matsushita-common.h b/drivers/mmc/matsushita-common.h index e517a2d56b..c1b28a0128 100644 --- a/drivers/mmc/matsushita-common.h +++ b/drivers/mmc/matsushita-common.h @@ -123,6 +123,7 @@ struct matsu_sd_priv { #define MATSU_SD_CAP_DMA_INTERNAL BIT(1) /* have internal DMA engine */ #define MATSU_SD_CAP_DIV1024 BIT(2) /* divisor 1024 is available */ #define MATSU_SD_CAP_64BIT BIT(3) /* Controller is 64bit */ +#define MATSU_SD_CAP_16BIT BIT(4) /* Controller is 16bit */ };
int matsu_sd_send_cmd(struct udevice *dev, struct mmc_cmd *cmd,

Certain instances of the SD IP require more elaborate digging in the DT to figure out which variant of the SD IP is in use. Allow explicit passing of the quirks into the probe 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/matsushita-common.c | 3 +-- drivers/mmc/matsushita-common.h | 2 +- drivers/mmc/renesas-sdhi.c | 9 ++++++++- drivers/mmc/uniphier-sd.c | 7 ++++++- 4 files changed, 16 insertions(+), 5 deletions(-)
diff --git a/drivers/mmc/matsushita-common.c b/drivers/mmc/matsushita-common.c index 9f7f47c86b..0b0cbaf9e1 100644 --- a/drivers/mmc/matsushita-common.c +++ b/drivers/mmc/matsushita-common.c @@ -653,12 +653,11 @@ int matsu_sd_bind(struct udevice *dev) return mmc_bind(dev, &plat->mmc, &plat->cfg); }
-int matsu_sd_probe(struct udevice *dev) +int matsu_sd_probe(struct udevice *dev, u32 quirks) { struct matsu_sd_plat *plat = dev_get_platdata(dev); struct matsu_sd_priv *priv = dev_get_priv(dev); struct mmc_uclass_priv *upriv = dev_get_uclass_priv(dev); - const u32 quirks = dev_get_driver_data(dev); fdt_addr_t base; struct clk clk; int ret; diff --git a/drivers/mmc/matsushita-common.h b/drivers/mmc/matsushita-common.h index c1b28a0128..a03d8f97e5 100644 --- a/drivers/mmc/matsushita-common.h +++ b/drivers/mmc/matsushita-common.h @@ -132,6 +132,6 @@ int matsu_sd_set_ios(struct udevice *dev); int matsu_sd_get_cd(struct udevice *dev);
int matsu_sd_bind(struct udevice *dev); -int matsu_sd_probe(struct udevice *dev); +int matsu_sd_probe(struct udevice *dev, u32 quirks);
#endif /* __MATSUSHITA_COMMON_H__ */ diff --git a/drivers/mmc/renesas-sdhi.c b/drivers/mmc/renesas-sdhi.c index 9b388b3ab0..d6b3bfbadc 100644 --- a/drivers/mmc/renesas-sdhi.c +++ b/drivers/mmc/renesas-sdhi.c @@ -38,12 +38,19 @@ static const struct udevice_id renesas_sdhi_match[] = { { /* sentinel */ } };
+static int renesas_sdhi_probe(struct udevice *dev) +{ + u32 quirks = dev_get_driver_data(dev); + + return matsu_sd_probe(dev, quirks); +} + U_BOOT_DRIVER(renesas_sdhi) = { .name = "renesas-sdhi", .id = UCLASS_MMC, .of_match = renesas_sdhi_match, .bind = matsu_sd_bind, - .probe = matsu_sd_probe, + .probe = renesas_sdhi_probe, .priv_auto_alloc_size = sizeof(struct matsu_sd_priv), .platdata_auto_alloc_size = sizeof(struct matsu_sd_plat), .ops = &renesas_sdhi_ops, diff --git a/drivers/mmc/uniphier-sd.c b/drivers/mmc/uniphier-sd.c index 72f0d46758..42eb9c2c84 100644 --- a/drivers/mmc/uniphier-sd.c +++ b/drivers/mmc/uniphier-sd.c @@ -30,12 +30,17 @@ static const struct udevice_id uniphier_sd_match[] = { { /* sentinel */ } };
+static int uniphier_sd_probe(struct udevice *dev) +{ + return matsu_sd_probe(dev, 0); +} + U_BOOT_DRIVER(uniphier_mmc) = { .name = "uniphier-mmc", .id = UCLASS_MMC, .of_match = uniphier_sd_match, .bind = matsu_sd_bind, - .probe = matsu_sd_probe, + .probe = uniphier_sd_probe, .priv_auto_alloc_size = sizeof(struct matsu_sd_priv), .platdata_auto_alloc_size = sizeof(struct matsu_sd_plat), .ops = &uniphier_sd_ops,

The Renesas RCar Gen2 chips have a mix of 32bit and 16bit variants of the IP. There is no DT property which allows discerning those, so what Linux does is it checks the size of the register area and if it is 0x100, the IP is 16bit, otherwise the IP is 32bit. Handle the distinction the same way.
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/renesas-sdhi.c | 13 +++++++++++++ 1 file changed, 13 insertions(+)
diff --git a/drivers/mmc/renesas-sdhi.c b/drivers/mmc/renesas-sdhi.c index d6b3bfbadc..521574387b 100644 --- a/drivers/mmc/renesas-sdhi.c +++ b/drivers/mmc/renesas-sdhi.c @@ -41,6 +41,19 @@ static const struct udevice_id renesas_sdhi_match[] = { static int renesas_sdhi_probe(struct udevice *dev) { u32 quirks = dev_get_driver_data(dev); + struct fdt_resource reg_res; + DECLARE_GLOBAL_DATA_PTR; + int ret; + + ret = fdt_get_resource(gd->fdt_blob, dev_of_offset(dev), "reg", + 0, ®_res); + if (ret < 0) { + dev_err(dev, ""reg" resource not found, ret=%i\n", ret); + return ret; + } + + if (quirks == 0 && fdt_resource_size(®_res) == 0x100) + quirks = MATSU_SD_CAP_16BIT;
return matsu_sd_probe(dev, quirks); }

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/matsushita-common.c | 23 +++++++---------------- 1 file changed, 7 insertions(+), 16 deletions(-)
diff --git a/drivers/mmc/matsushita-common.c b/drivers/mmc/matsushita-common.c index 0b0cbaf9e1..449f533d1b 100644 --- a/drivers/mmc/matsushita-common.c +++ b/drivers/mmc/matsushita-common.c @@ -703,24 +703,15 @@ int matsu_sd_probe(struct udevice *dev, u32 quirks) 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 {

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/matsushita-common.h | 5 +++++ drivers/mmc/renesas-sdhi.c | 43 ++++++++++++++++++++++++----------------- 2 files changed, 30 insertions(+), 18 deletions(-)
diff --git a/drivers/mmc/matsushita-common.h b/drivers/mmc/matsushita-common.h index a03d8f97e5..c23dc1a79a 100644 --- a/drivers/mmc/matsushita-common.h +++ b/drivers/mmc/matsushita-common.h @@ -124,6 +124,11 @@ struct matsu_sd_priv { #define MATSU_SD_CAP_DIV1024 BIT(2) /* divisor 1024 is available */ #define MATSU_SD_CAP_64BIT BIT(3) /* Controller is 64bit */ #define MATSU_SD_CAP_16BIT BIT(4) /* Controller is 16bit */ +#define MATSU_SD_CAP_RCAR_GEN2 BIT(5) /* Renesas RCar version of IP */ +#define MATSU_SD_CAP_RCAR_GEN3 BIT(6) /* Renesas RCar version of IP */ +#define MATSU_SD_CAP_RCAR_UHS BIT(7) /* Renesas RCar UHS/SDR modes */ +#define MATSU_SD_CAP_RCAR \ + (MATSU_SD_CAP_RCAR_GEN2 | MATSU_SD_CAP_RCAR_GEN3) };
int matsu_sd_send_cmd(struct udevice *dev, struct mmc_cmd *cmd, diff --git a/drivers/mmc/renesas-sdhi.c b/drivers/mmc/renesas-sdhi.c index 521574387b..73f68c8c3a 100644 --- a/drivers/mmc/renesas-sdhi.c +++ b/drivers/mmc/renesas-sdhi.c @@ -24,17 +24,21 @@ static const struct dm_mmc_ops renesas_sdhi_ops = { .get_cd = matsu_sd_get_cd, };
+#define RENESAS_GEN2_QUIRKS MATSU_SD_CAP_RCAR_GEN2 +#define RENESAS_GEN3_QUIRKS \ + MATSU_SD_CAP_64BIT | MATSU_SD_CAP_RCAR_GEN3 | MATSU_SD_CAP_RCAR_UHS + static const struct udevice_id renesas_sdhi_match[] = { - { .compatible = "renesas,sdhi-r8a7790", .data = 0 }, - { .compatible = "renesas,sdhi-r8a7791", .data = 0 }, - { .compatible = "renesas,sdhi-r8a7792", .data = 0 }, - { .compatible = "renesas,sdhi-r8a7793", .data = 0 }, - { .compatible = "renesas,sdhi-r8a7794", .data = 0 }, - { .compatible = "renesas,sdhi-r8a7795", .data = MATSU_SD_CAP_64BIT }, - { .compatible = "renesas,sdhi-r8a7796", .data = MATSU_SD_CAP_64BIT }, - { .compatible = "renesas,sdhi-r8a77965", .data = MATSU_SD_CAP_64BIT }, - { .compatible = "renesas,sdhi-r8a77970", .data = MATSU_SD_CAP_64BIT }, - { .compatible = "renesas,sdhi-r8a77995", .data = MATSU_SD_CAP_64BIT }, + { .compatible = "renesas,sdhi-r8a7790", .data = RENESAS_GEN2_QUIRKS }, + { .compatible = "renesas,sdhi-r8a7791", .data = RENESAS_GEN2_QUIRKS }, + { .compatible = "renesas,sdhi-r8a7792", .data = RENESAS_GEN2_QUIRKS }, + { .compatible = "renesas,sdhi-r8a7793", .data = RENESAS_GEN2_QUIRKS }, + { .compatible = "renesas,sdhi-r8a7794", .data = RENESAS_GEN2_QUIRKS }, + { .compatible = "renesas,sdhi-r8a7795", .data = RENESAS_GEN3_QUIRKS }, + { .compatible = "renesas,sdhi-r8a7796", .data = RENESAS_GEN3_QUIRKS }, + { .compatible = "renesas,sdhi-r8a77965", .data = RENESAS_GEN3_QUIRKS }, + { .compatible = "renesas,sdhi-r8a77970", .data = RENESAS_GEN3_QUIRKS }, + { .compatible = "renesas,sdhi-r8a77995", .data = RENESAS_GEN3_QUIRKS }, { /* sentinel */ } };
@@ -45,15 +49,18 @@ static int renesas_sdhi_probe(struct udevice *dev) DECLARE_GLOBAL_DATA_PTR; int ret;
- ret = fdt_get_resource(gd->fdt_blob, dev_of_offset(dev), "reg", - 0, ®_res); - if (ret < 0) { - dev_err(dev, ""reg" resource not found, ret=%i\n", ret); - return ret; - } + if (quirks == RENESAS_GEN2_QUIRKS) { + ret = fdt_get_resource(gd->fdt_blob, dev_of_offset(dev), + "reg", 0, ®_res); + if (ret < 0) { + dev_err(dev, ""reg" resource not found, ret=%i\n", + ret); + return ret; + }
- if (quirks == 0 && fdt_resource_size(®_res) == 0x100) - quirks = MATSU_SD_CAP_16BIT; + if (fdt_resource_size(®_res) == 0x100) + quirks |= MATSU_SD_CAP_16BIT; + }
return matsu_sd_probe(dev, quirks); }

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/matsushita-common.c | 3 ++- drivers/mmc/matsushita-common.h | 1 + 2 files changed, 3 insertions(+), 1 deletion(-)
diff --git a/drivers/mmc/matsushita-common.c b/drivers/mmc/matsushita-common.c index 449f533d1b..7e05b1f3d1 100644 --- a/drivers/mmc/matsushita-common.c +++ b/drivers/mmc/matsushita-common.c @@ -542,7 +542,8 @@ static void matsu_sd_set_clk_rate(struct matsu_sd_priv *priv, divisor = DIV_ROUND_UP(priv->mclk, mmc->clock);
if (divisor <= 1) - val = MATSU_SD_CLKCTL_DIV1; + val = (priv->caps & MATSU_SD_CAP_RCAR) ? + MATSU_SD_CLKCTL_RCAR_DIV1 : MATSU_SD_CLKCTL_DIV1; else if (divisor <= 2) val = MATSU_SD_CLKCTL_DIV2; else if (divisor <= 4) diff --git a/drivers/mmc/matsushita-common.h b/drivers/mmc/matsushita-common.h index c23dc1a79a..a10ad202c8 100644 --- a/drivers/mmc/matsushita-common.h +++ b/drivers/mmc/matsushita-common.h @@ -63,6 +63,7 @@ #define MATSU_SD_CLKCTL_DIV4 BIT(0) /* SDCLK = CLK / 4 */ #define MATSU_SD_CLKCTL_DIV2 0 /* SDCLK = CLK / 2 */ #define MATSU_SD_CLKCTL_DIV1 BIT(10) /* SDCLK = CLK */ +#define MATSU_SD_CLKCTL_RCAR_DIV1 0xff /* SDCLK = CLK (RCar ver.) */ #define MATSU_SD_CLKCTL_OFFEN BIT(9) /* stop SDCLK when unused */ #define MATSU_SD_CLKCTL_SCLKEN BIT(8) /* SDCLK output enable */ #define MATSU_SD_SIZE 0x04c /* block size */

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/matsushita-common.c | 10 +++++++++- drivers/mmc/matsushita-common.h | 4 ++-- 2 files changed, 11 insertions(+), 3 deletions(-)
diff --git a/drivers/mmc/matsushita-common.c b/drivers/mmc/matsushita-common.c index 7e05b1f3d1..11e4553d87 100644 --- a/drivers/mmc/matsushita-common.c +++ b/drivers/mmc/matsushita-common.c @@ -339,7 +339,15 @@ static int matsu_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 = MATSU_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 & MATSU_SD_CAP_RCAR) ? + MATSU_SD_DMA_INFO1_END_RD : + MATSU_SD_DMA_INFO1_END_RD2; tmp |= MATSU_SD_DMA_MODE_DIR_RD; } else { buf = (void *)data->src; diff --git a/drivers/mmc/matsushita-common.h b/drivers/mmc/matsushita-common.h index a10ad202c8..8c81bbcc4b 100644 --- a/drivers/mmc/matsushita-common.h +++ b/drivers/mmc/matsushita-common.h @@ -96,8 +96,8 @@ #define MATSU_SD_DMA_RST_RD BIT(9) #define MATSU_SD_DMA_RST_WR BIT(8) #define MATSU_SD_DMA_INFO1 0x420 -#define MATSU_SD_DMA_INFO1_END_RD2 BIT(20) /* DMA from device is complete*/ -#define MATSU_SD_DMA_INFO1_END_RD BIT(17) /* Don't use! Hardware bug */ +#define MATSU_SD_DMA_INFO1_END_RD2 BIT(20) /* DMA from device is complete (uniphier) */ +#define MATSU_SD_DMA_INFO1_END_RD BIT(17) /* DMA from device is complete (renesas) */ #define MATSU_SD_DMA_INFO1_END_WR BIT(16) /* DMA to device is complete */ #define MATSU_SD_DMA_INFO1_MASK 0x424 #define MATSU_SD_DMA_INFO2 0x428

Handle bus width 0 as 1-bit bus to assure valid content of MATSU_SD_OPTION register WIDTH field.
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/matsushita-common.c | 1 + 1 file changed, 1 insertion(+)
diff --git a/drivers/mmc/matsushita-common.c b/drivers/mmc/matsushita-common.c index 11e4553d87..377f349b41 100644 --- a/drivers/mmc/matsushita-common.c +++ b/drivers/mmc/matsushita-common.c @@ -504,6 +504,7 @@ static int matsu_sd_set_bus_width(struct matsu_sd_priv *priv, u32 val, tmp;
switch (mmc->bus_width) { + case 0: case 1: val = MATSU_SD_OPTION_WIDTH_1; break;

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/matsushita-common.c | 17 ++++++++--------- 1 file changed, 8 insertions(+), 9 deletions(-)
diff --git a/drivers/mmc/matsushita-common.c b/drivers/mmc/matsushita-common.c index 377f349b41..d5facd972f 100644 --- a/drivers/mmc/matsushita-common.c +++ b/drivers/mmc/matsushita-common.c @@ -722,16 +722,15 @@ int matsu_sd_probe(struct udevice *dev, u32 quirks) 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 = matsu_sd_readl(priv, MATSU_SD_VERSION) & - MATSU_SD_VERSION_IP; - dev_dbg(dev, "version %x\n", priv->version); - if (priv->version >= 0x10) { - priv->caps |= MATSU_SD_CAP_DMA_INTERNAL; - priv->caps |= MATSU_SD_CAP_DIV1024; - } + + priv->version = matsu_sd_readl(priv, MATSU_SD_VERSION) & + MATSU_SD_VERSION_IP; + dev_dbg(dev, "version %x\n", priv->version); + if (priv->version >= 0x10) { + priv->caps |= MATSU_SD_CAP_DMA_INTERNAL; + priv->caps |= MATSU_SD_CAP_DIV1024; }
if (fdt_get_property(gd->fdt_blob, dev_of_offset(dev), "non-removable",

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/matsushita-common.c | 52 ++++++++++++++++++++++++++++++++++------- drivers/mmc/matsushita-common.h | 3 +++ 2 files changed, 46 insertions(+), 9 deletions(-)
diff --git a/drivers/mmc/matsushita-common.c b/drivers/mmc/matsushita-common.c index d5facd972f..b143f5c229 100644 --- a/drivers/mmc/matsushita-common.c +++ b/drivers/mmc/matsushita-common.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> @@ -593,6 +594,46 @@ static void matsu_sd_set_clk_rate(struct matsu_sd_priv *priv, udelay(1000); }
+static void matsu_sd_set_pins(struct udevice *dev) +{ + __maybe_unused struct mmc *mmc = mmc_get_mmc_dev(dev); + +#ifdef CONFIG_DM_REGULATOR + struct matsu_sd_priv *priv = dev_get_priv(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); + regulator_set_enable(priv->vqmmc_dev, true); + } +#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: + pinctrl_select_state(dev, "state_uhs"); + break; + default: + break; + } +#endif +} + int matsu_sd_set_ios(struct udevice *dev) { struct matsu_sd_priv *priv = dev_get_priv(dev); @@ -607,6 +648,7 @@ int matsu_sd_set_ios(struct udevice *dev) return ret; matsu_sd_set_ddr_mode(priv, mmc); matsu_sd_set_clk_rate(priv, mmc); + matsu_sd_set_pins(dev);
return 0; } @@ -671,9 +713,6 @@ int matsu_sd_probe(struct udevice *dev, u32 quirks) 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) @@ -684,12 +723,7 @@ int matsu_sd_probe(struct udevice *dev, u32 quirks) 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); - } + device_get_supply_regulator(dev, "vqmmc-supply", &priv->vqmmc_dev); #endif
ret = clk_get_by_index(dev, 0, &clk); diff --git a/drivers/mmc/matsushita-common.h b/drivers/mmc/matsushita-common.h index 8c81bbcc4b..b019b72b3e 100644 --- a/drivers/mmc/matsushita-common.h +++ b/drivers/mmc/matsushita-common.h @@ -130,6 +130,9 @@ struct matsu_sd_priv { #define MATSU_SD_CAP_RCAR_UHS BIT(7) /* Renesas RCar UHS/SDR modes */ #define MATSU_SD_CAP_RCAR \ (MATSU_SD_CAP_RCAR_GEN2 | MATSU_SD_CAP_RCAR_GEN3) +#ifdef CONFIG_DM_REGULATOR + struct udevice *vqmmc_dev; +#endif };
int matsu_sd_send_cmd(struct udevice *dev, struct mmc_cmd *cmd,

Export the matsu_sd_{read,write}l() common register access functions, so that they can be used by other drivers sharing the common code.
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/matsushita-common.c | 4 ++-- drivers/mmc/matsushita-common.h | 4 ++++ 2 files changed, 6 insertions(+), 2 deletions(-)
diff --git a/drivers/mmc/matsushita-common.c b/drivers/mmc/matsushita-common.c index b143f5c229..3f538c354e 100644 --- a/drivers/mmc/matsushita-common.c +++ b/drivers/mmc/matsushita-common.c @@ -44,7 +44,7 @@ static void matsu_sd_writew(struct matsu_sd_priv *priv, writew(val, priv->regbase + (reg >> 1)); }
-static u32 matsu_sd_readl(struct matsu_sd_priv *priv, unsigned int reg) +u32 matsu_sd_readl(struct matsu_sd_priv *priv, unsigned int reg) { u32 val;
@@ -61,7 +61,7 @@ static u32 matsu_sd_readl(struct matsu_sd_priv *priv, unsigned int reg) return readl(priv->regbase + reg); }
-static void matsu_sd_writel(struct matsu_sd_priv *priv, +void matsu_sd_writel(struct matsu_sd_priv *priv, u32 val, unsigned int reg) { if (priv->caps & MATSU_SD_CAP_64BIT) diff --git a/drivers/mmc/matsushita-common.h b/drivers/mmc/matsushita-common.h index b019b72b3e..3be91c310e 100644 --- a/drivers/mmc/matsushita-common.h +++ b/drivers/mmc/matsushita-common.h @@ -143,4 +143,8 @@ int matsu_sd_get_cd(struct udevice *dev); int matsu_sd_bind(struct udevice *dev); int matsu_sd_probe(struct udevice *dev, u32 quirks);
+u32 matsu_sd_readl(struct matsu_sd_priv *priv, unsigned int reg); +void matsu_sd_writel(struct matsu_sd_priv *priv, + u32 val, unsigned int reg); + #endif /* __MATSUSHITA_COMMON_H__ */

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/renesas-sdhi.c | 292 ++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 290 insertions(+), 2 deletions(-)
diff --git a/drivers/mmc/renesas-sdhi.c b/drivers/mmc/renesas-sdhi.c index 73f68c8c3a..e9edcf5f17 100644 --- a/drivers/mmc/renesas-sdhi.c +++ b/drivers/mmc/renesas-sdhi.c @@ -18,10 +18,293 @@
#include "matsushita-common.h"
+#if CONFIG_IS_ENABLED(MMC_HS200_SUPPORT) + +/* SCC registers */ +#define RENESAS_SDHI_SCC_DTCNTL 0x800 +#define RENESAS_SDHI_SCC_DTCNTL_TAPEN BIT(0) +#define RENESAS_SDHI_SCC_DTCNTL_TAPNUM_SHIFT 16 +#define RENESAS_SDHI_SCC_DTCNTL_TAPNUM_MASK 0xff +#define RENESAS_SDHI_SCC_TAPSET 0x804 +#define RENESAS_SDHI_SCC_DT2FF 0x808 +#define RENESAS_SDHI_SCC_CKSEL 0x80c +#define RENESAS_SDHI_SCC_CKSEL_DTSEL BIT(0) +#define RENESAS_SDHI_SCC_RVSCNTL 0x810 +#define RENESAS_SDHI_SCC_RVSCNTL_RVSEN BIT(0) +#define RENESAS_SDHI_SCC_RVSREQ 0x814 +#define RENESAS_SDHI_SCC_RVSREQ_RVSERR BIT(2) +#define RENESAS_SDHI_SCC_SMPCMP 0x818 +#define RENESAS_SDHI_SCC_TMPPORT2 0x81c + +#define RENESAS_SDHI_MAX_TAP 3 + +static unsigned int renesas_sdhi_init_tuning(struct matsu_sd_priv *priv) +{ + u32 reg; + + /* Initialize SCC */ + matsu_sd_writel(priv, 0, MATSU_SD_INFO1); + + reg = matsu_sd_readl(priv, MATSU_SD_CLKCTL); + reg &= ~MATSU_SD_CLKCTL_SCLKEN; + matsu_sd_writel(priv, reg, MATSU_SD_CLKCTL); + + /* Set sampling clock selection range */ + matsu_sd_writel(priv, 0x8 << RENESAS_SDHI_SCC_DTCNTL_TAPNUM_SHIFT, + RENESAS_SDHI_SCC_DTCNTL); + + reg = matsu_sd_readl(priv, RENESAS_SDHI_SCC_DTCNTL); + reg |= RENESAS_SDHI_SCC_DTCNTL_TAPEN; + matsu_sd_writel(priv, reg, RENESAS_SDHI_SCC_DTCNTL); + + reg = matsu_sd_readl(priv, RENESAS_SDHI_SCC_CKSEL); + reg |= RENESAS_SDHI_SCC_CKSEL_DTSEL; + matsu_sd_writel(priv, reg, RENESAS_SDHI_SCC_CKSEL); + + reg = matsu_sd_readl(priv, RENESAS_SDHI_SCC_RVSCNTL); + reg &= ~RENESAS_SDHI_SCC_RVSCNTL_RVSEN; + matsu_sd_writel(priv, reg, RENESAS_SDHI_SCC_RVSCNTL); + + matsu_sd_writel(priv, 0x300 /* scc_tappos */, + RENESAS_SDHI_SCC_DT2FF); + + reg = matsu_sd_readl(priv, MATSU_SD_CLKCTL); + reg |= MATSU_SD_CLKCTL_SCLKEN; + matsu_sd_writel(priv, reg, MATSU_SD_CLKCTL); + + /* Read TAPNUM */ + return (matsu_sd_readl(priv, RENESAS_SDHI_SCC_DTCNTL) >> + RENESAS_SDHI_SCC_DTCNTL_TAPNUM_SHIFT) & + RENESAS_SDHI_SCC_DTCNTL_TAPNUM_MASK; +} + +static void renesas_sdhi_reset_tuning(struct matsu_sd_priv *priv) +{ + u32 reg; + + /* Reset SCC */ + reg = matsu_sd_readl(priv, MATSU_SD_CLKCTL); + reg &= ~MATSU_SD_CLKCTL_SCLKEN; + matsu_sd_writel(priv, reg, MATSU_SD_CLKCTL); + + reg = matsu_sd_readl(priv, RENESAS_SDHI_SCC_CKSEL); + reg &= ~RENESAS_SDHI_SCC_CKSEL_DTSEL; + matsu_sd_writel(priv, reg, RENESAS_SDHI_SCC_CKSEL); + + reg = matsu_sd_readl(priv, MATSU_SD_CLKCTL); + reg |= MATSU_SD_CLKCTL_SCLKEN; + matsu_sd_writel(priv, reg, MATSU_SD_CLKCTL); + + reg = matsu_sd_readl(priv, RENESAS_SDHI_SCC_RVSCNTL); + reg &= ~RENESAS_SDHI_SCC_RVSCNTL_RVSEN; + matsu_sd_writel(priv, reg, RENESAS_SDHI_SCC_RVSCNTL); + + reg = matsu_sd_readl(priv, RENESAS_SDHI_SCC_RVSCNTL); + reg &= ~RENESAS_SDHI_SCC_RVSCNTL_RVSEN; + matsu_sd_writel(priv, reg, RENESAS_SDHI_SCC_RVSCNTL); +} + +static void renesas_sdhi_prepare_tuning(struct matsu_sd_priv *priv, + unsigned long tap) +{ + /* Set sampling clock position */ + matsu_sd_writel(priv, tap, RENESAS_SDHI_SCC_TAPSET); +} + +static unsigned int renesas_sdhi_compare_scc_data(struct matsu_sd_priv *priv) +{ + /* Get comparison of sampling data */ + return matsu_sd_readl(priv, RENESAS_SDHI_SCC_SMPCMP); +} + +static int renesas_sdhi_select_tuning(struct matsu_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 */ + matsu_sd_writel(priv, 0, RENESAS_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 RENESAS_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 >= RENESAS_SDHI_MAX_TAP) + select = true; + + if (select) + tap_set = ((tap_start + tap_end) / 2) % tap_num; + else + return -EIO; + + /* Set SCC */ + matsu_sd_writel(priv, tap_set, RENESAS_SDHI_SCC_TAPSET); + + /* Enable auto re-tuning */ + reg = matsu_sd_readl(priv, RENESAS_SDHI_SCC_RVSCNTL); + reg |= RENESAS_SDHI_SCC_RVSCNTL_RVSEN; + matsu_sd_writel(priv, reg, RENESAS_SDHI_SCC_RVSCNTL); + + return 0; +} + +int renesas_sdhi_execute_tuning(struct udevice *dev, uint opcode) +{ + struct matsu_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 & MATSU_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 = renesas_sdhi_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++) { + renesas_sdhi_prepare_tuning(priv, i % tap_num); + + /* Force PIO for the tuning */ + caps = priv->caps; + priv->caps &= ~MATSU_SD_CAP_DMA_INTERNAL; + + ret = mmc_send_tuning(mmc, opcode, NULL); + + priv->caps = caps; + + if (ret == 0) + taps |= BIT(i); + + ret = renesas_sdhi_compare_scc_data(priv); + if (ret == 0) + smpcmp |= BIT(i); + + mdelay(1); + } + + ret = renesas_sdhi_select_tuning(priv, tap_num, taps, smpcmp); + +out: + if (ret < 0) { + dev_warn(dev, "Tuning procedure failed\n"); + renesas_sdhi_reset_tuning(priv); + } + + return ret; +} +#endif + +static int renesas_sdhi_set_ios(struct udevice *dev) +{ + int ret = matsu_sd_set_ios(dev); +#if CONFIG_IS_ENABLED(MMC_HS200_SUPPORT) + struct matsu_sd_priv *priv = dev_get_priv(dev); + + renesas_sdhi_reset_tuning(priv); +#endif + + return ret; +} + static const struct dm_mmc_ops renesas_sdhi_ops = { .send_cmd = matsu_sd_send_cmd, - .set_ios = matsu_sd_set_ios, + .set_ios = renesas_sdhi_set_ios, .get_cd = matsu_sd_get_cd, +#if CONFIG_IS_ENABLED(MMC_HS200_SUPPORT) + .execute_tuning = renesas_sdhi_execute_tuning, +#endif };
#define RENESAS_GEN2_QUIRKS MATSU_SD_CAP_RCAR_GEN2 @@ -62,7 +345,12 @@ static int renesas_sdhi_probe(struct udevice *dev) quirks |= MATSU_SD_CAP_16BIT; }
- return matsu_sd_probe(dev, quirks); + ret = matsu_sd_probe(dev, quirks); +#if CONFIG_IS_ENABLED(MMC_HS200_SUPPORT) + if (!ret) + renesas_sdhi_reset_tuning(dev_get_priv(dev)); +#endif + return ret; }
U_BOOT_DRIVER(renesas_sdhi) = {

Enable the HS200 on RCar Gen3 platforms, since the SDHI core supports it.
Signed-off-by: Marek Vasut marek.vasut+renesas@gmail.com Cc: Nobuhiro Iwamatsu iwamatsu@nigauri.org --- configs/r8a7795_salvator-x_defconfig | 4 ++++ configs/r8a7795_ulcb_defconfig | 4 ++++ configs/r8a7796_salvator-x_defconfig | 4 ++++ configs/r8a7796_ulcb_defconfig | 4 ++++ configs/r8a77970_eagle_defconfig | 4 ++++ configs/r8a77995_draak_defconfig | 4 ++++ 6 files changed, 24 insertions(+)
diff --git a/configs/r8a7795_salvator-x_defconfig b/configs/r8a7795_salvator-x_defconfig index 0614894333..b48513ca2a 100644 --- a/configs/r8a7795_salvator-x_defconfig +++ b/configs/r8a7795_salvator-x_defconfig @@ -37,7 +37,11 @@ CONFIG_RCAR_GPIO=y CONFIG_DM_I2C=y CONFIG_SYS_I2C_RCAR_IIC=y CONFIG_DM_MMC=y +CONFIG_MMC_IO_VOLTAGE=y +CONFIG_MMC_UHS_SUPPORT=y +CONFIG_MMC_HS200_SUPPORT=y CONFIG_RENESAS_SDHI=y +CONFIG_MMC_RENESAS_TUNING=y CONFIG_PHY_MICREL=y CONFIG_PHY_MICREL_KSZ90X1=y CONFIG_DM_ETH=y diff --git a/configs/r8a7795_ulcb_defconfig b/configs/r8a7795_ulcb_defconfig index cffa7197a1..a45aec3c43 100644 --- a/configs/r8a7795_ulcb_defconfig +++ b/configs/r8a7795_ulcb_defconfig @@ -37,7 +37,11 @@ CONFIG_RCAR_GPIO=y CONFIG_DM_I2C=y CONFIG_SYS_I2C_RCAR_IIC=y CONFIG_DM_MMC=y +CONFIG_MMC_IO_VOLTAGE=y +CONFIG_MMC_UHS_SUPPORT=y +CONFIG_MMC_HS200_SUPPORT=y CONFIG_RENESAS_SDHI=y +CONFIG_MMC_RENESAS_TUNING=y CONFIG_PHY_MICREL=y CONFIG_PHY_MICREL_KSZ90X1=y CONFIG_DM_ETH=y diff --git a/configs/r8a7796_salvator-x_defconfig b/configs/r8a7796_salvator-x_defconfig index 535163fc31..680c7d9226 100644 --- a/configs/r8a7796_salvator-x_defconfig +++ b/configs/r8a7796_salvator-x_defconfig @@ -38,7 +38,11 @@ CONFIG_RCAR_GPIO=y CONFIG_DM_I2C=y CONFIG_SYS_I2C_RCAR_IIC=y CONFIG_DM_MMC=y +CONFIG_MMC_IO_VOLTAGE=y +CONFIG_MMC_UHS_SUPPORT=y +CONFIG_MMC_HS200_SUPPORT=y CONFIG_RENESAS_SDHI=y +CONFIG_MMC_RENESAS_TUNING=y CONFIG_PHY_MICREL=y CONFIG_PHY_MICREL_KSZ90X1=y CONFIG_DM_ETH=y diff --git a/configs/r8a7796_ulcb_defconfig b/configs/r8a7796_ulcb_defconfig index 45c0ca219f..2b552cc531 100644 --- a/configs/r8a7796_ulcb_defconfig +++ b/configs/r8a7796_ulcb_defconfig @@ -38,7 +38,11 @@ CONFIG_RCAR_GPIO=y CONFIG_DM_I2C=y CONFIG_SYS_I2C_RCAR_IIC=y CONFIG_DM_MMC=y +CONFIG_MMC_IO_VOLTAGE=y +CONFIG_MMC_UHS_SUPPORT=y +CONFIG_MMC_HS200_SUPPORT=y CONFIG_RENESAS_SDHI=y +CONFIG_MMC_RENESAS_TUNING=y CONFIG_PHY_MICREL=y CONFIG_PHY_MICREL_KSZ90X1=y CONFIG_DM_ETH=y diff --git a/configs/r8a77970_eagle_defconfig b/configs/r8a77970_eagle_defconfig index 2e7f7ac645..56c949f135 100644 --- a/configs/r8a77970_eagle_defconfig +++ b/configs/r8a77970_eagle_defconfig @@ -37,7 +37,11 @@ CONFIG_RCAR_GPIO=y CONFIG_DM_I2C=y CONFIG_SYS_I2C_RCAR_IIC=y CONFIG_DM_MMC=y +CONFIG_MMC_IO_VOLTAGE=y +CONFIG_MMC_UHS_SUPPORT=y +CONFIG_MMC_HS200_SUPPORT=y CONFIG_RENESAS_SDHI=y +CONFIG_MMC_RENESAS_TUNING=y CONFIG_PHY_MICREL=y CONFIG_PHY_MICREL_KSZ90X1=y CONFIG_DM_ETH=y diff --git a/configs/r8a77995_draak_defconfig b/configs/r8a77995_draak_defconfig index 7a2e33e001..9792f5efe7 100644 --- a/configs/r8a77995_draak_defconfig +++ b/configs/r8a77995_draak_defconfig @@ -38,7 +38,11 @@ CONFIG_RCAR_GPIO=y CONFIG_DM_I2C=y CONFIG_SYS_I2C_RCAR_IIC=y CONFIG_DM_MMC=y +CONFIG_MMC_IO_VOLTAGE=y +CONFIG_MMC_UHS_SUPPORT=y +CONFIG_MMC_HS200_SUPPORT=y CONFIG_RENESAS_SDHI=y +CONFIG_MMC_RENESAS_TUNING=y CONFIG_MTD=y CONFIG_MTD_NOR_FLASH=y CONFIG_CFI_FLASH=y
participants (1)
-
Marek Vasut