diff --git a/arch/arm/dts/r8a77990-ebisu.dts b/arch/arm/dts/r8a77990-ebisu.dts index 5e3c195d4c..0f269d0469 100644 --- a/arch/arm/dts/r8a77990-ebisu.dts +++ b/arch/arm/dts/r8a77990-ebisu.dts @@ -46,6 +46,54 @@ regulator-boot-on; regulator-always-on; }; + + vcc_sdhi0: regulator-vcc-sdhi0 { + compatible = "regulator-fixed"; + + regulator-name = "SDHI0 Vcc"; + regulator-min-microvolt = <3300000>; + regulator-max-microvolt = <3300000>; + + gpio = <&gpio5 17 GPIO_ACTIVE_HIGH>; + enable-active-high; + }; + + vccq_sdhi0: regulator-vccq-sdhi0 { + compatible = "regulator-gpio"; + + regulator-name = "SDHI0 VccQ"; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <3300000>; + + gpios = <&gpio5 18 GPIO_ACTIVE_HIGH>; + gpios-states = <1>; + states = <3300000 1 + 1800000 0>; + }; + + vcc_sdhi1: regulator-vcc-sdhi1 { + compatible = "regulator-fixed"; + + regulator-name = "SDHI1 Vcc"; + regulator-min-microvolt = <3300000>; + regulator-max-microvolt = <3300000>; + + gpio = <&gpio0 4 GPIO_ACTIVE_HIGH>; + enable-active-high; + }; + + vccq_sdhi1: regulator-vccq-sdhi1 { + compatible = "regulator-gpio"; + + regulator-name = "SDHI1 VccQ"; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <3300000>; + + gpios = <&gpio3 15 GPIO_ACTIVE_HIGH>; + gpios-states = <1>; + states = <3300000 1 + 1800000 0>; + }; }; &avb { @@ -94,14 +142,38 @@ function = "scif_clk"; }; + sdhi0_pins: sd0 { + groups = "sdhi0_data4", "sdhi0_ctrl"; + function = "sdhi0"; + power-source = <3300>; + }; + + sdhi0_pins_uhs: sd0_uhs { + groups = "sdhi0_data4", "sdhi0_ctrl"; + function = "sdhi0"; + power-source = <1800>; + }; + + sdhi1_pins: sd1 { + groups = "sdhi1_data4", "sdhi1_ctrl"; + function = "sdhi1"; + power-source = <3300>; + }; + + sdhi1_pins_uhs: sd1_uhs { + groups = "sdhi1_data4", "sdhi1_ctrl"; + function = "sdhi1"; + power-source = <1800>; + }; + sdhi3_pins: sd2 { - groups = "sdhi3_data8", "sdhi3_ctrl"; + groups = "sdhi3_data8", "sdhi3_ctrl", "sdhi3_ds"; function = "sdhi3"; power-source = <1800>; }; sdhi3_pins_uhs: sd2_uhs { - groups = "sdhi3_data8", "sdhi3_ctrl"; + groups = "sdhi3_data8", "sdhi3_ctrl", "sdhi3_ds"; function = "sdhi3"; power-source = <1800>; }; @@ -120,11 +192,40 @@ }; &sdhi0 { + /* full size SD */ + pinctrl-0 = <&sdhi0_pins>; + pinctrl-1 = <&sdhi0_pins_uhs>; + pinctrl-names = "default", "state_uhs"; + + vmmc-supply = <&vcc_sdhi0>; + vqmmc-supply = <&vccq_sdhi0>; + cd-gpios = <&gpio3 12 GPIO_ACTIVE_LOW>; + wp-gpios = <&gpio3 13 GPIO_ACTIVE_HIGH>; + bus-width = <4>; + sd-uhs-sdr12; + sd-uhs-sdr25; + sd-uhs-sdr50; + sd-uhs-sdr104; status = "okay"; + max-frequency = <208000000>; }; &sdhi1 { + /* microSD */ + pinctrl-0 = <&sdhi1_pins>; + pinctrl-1 = <&sdhi1_pins_uhs>; + pinctrl-names = "default", "state_uhs"; + + vmmc-supply = <&vcc_sdhi1>; + vqmmc-supply = <&vccq_sdhi1>; + cd-gpios = <&gpio3 14 GPIO_ACTIVE_LOW>; + bus-width = <4>; + sd-uhs-sdr12; + sd-uhs-sdr25; + sd-uhs-sdr50; + sd-uhs-sdr104; status = "okay"; + max-frequency = <208000000>; }; &sdhi3 { @@ -137,6 +238,7 @@ vqmmc-supply = <®_1p8v>; bus-width = <8>; mmc-hs200-1_8v; + mmc-hs400-1_8v; non-removable; status = "okay"; }; diff --git a/arch/arm/dts/salvator-common.dtsi b/arch/arm/dts/salvator-common.dtsi index a36e0ebca0..b036a713ea 100644 --- a/arch/arm/dts/salvator-common.dtsi +++ b/arch/arm/dts/salvator-common.dtsi @@ -480,13 +480,13 @@ }; sdhi2_pins: sd2 { - groups = "sdhi2_data8", "sdhi2_ctrl"; + groups = "sdhi2_data8", "sdhi2_ctrl", "sdhi2_ds"; function = "sdhi2"; power-source = <1800>; }; sdhi2_pins_uhs: sd2_uhs { - groups = "sdhi2_data8", "sdhi2_ctrl"; + groups = "sdhi2_data8", "sdhi2_ctrl", "sdhi2_ds"; function = "sdhi2"; power-source = <1800>; }; @@ -618,8 +618,13 @@ cd-gpios = <&gpio3 12 GPIO_ACTIVE_LOW>; wp-gpios = <&gpio3 13 GPIO_ACTIVE_HIGH>; bus-width = <4>; + sd-uhs-sdr12; + sd-uhs-sdr25; sd-uhs-sdr50; + sd-uhs-sdr104; status = "okay"; + + max-frequency = <208000000>; }; &sdhi2 { @@ -632,9 +637,11 @@ vqmmc-supply = <®_1p8v>; bus-width = <8>; mmc-hs200-1_8v; + mmc-hs400-1_8v; non-removable; fixed-emmc-driver-type = <1>; status = "okay"; + max-frequency = <200000000>; }; &sdhi3 { @@ -647,8 +654,12 @@ cd-gpios = <&gpio4 15 GPIO_ACTIVE_LOW>; wp-gpios = <&gpio4 16 GPIO_ACTIVE_HIGH>; bus-width = <4>; + sd-uhs-sdr12; + sd-uhs-sdr25; sd-uhs-sdr50; + sd-uhs-sdr104; status = "okay"; + max-frequency = <208000000>; }; &ssi1 { diff --git a/arch/arm/dts/ulcb.dtsi b/arch/arm/dts/ulcb.dtsi index ab886650cd..e16c7f245e 100644 --- a/arch/arm/dts/ulcb.dtsi +++ b/arch/arm/dts/ulcb.dtsi @@ -308,13 +308,13 @@ }; sdhi2_pins: sd2 { - groups = "sdhi2_data8", "sdhi2_ctrl"; + groups = "sdhi2_data8", "sdhi2_ctrl", "sdhi2_ds"; function = "sdhi2"; power-source = <1800>; }; sdhi2_pins_uhs: sd2_uhs { - groups = "sdhi2_data8", "sdhi2_ctrl"; + groups = "sdhi2_data8", "sdhi2_ctrl", "sdhi2_ds"; function = "sdhi2"; power-source = <1800>; }; @@ -396,8 +396,12 @@ vqmmc-supply = <&vccq_sdhi0>; cd-gpios = <&gpio3 12 GPIO_ACTIVE_LOW>; bus-width = <4>; + sd-uhs-sdr12; + sd-uhs-sdr25; sd-uhs-sdr50; + sd-uhs-sdr104; status = "okay"; + max-frequency = <208000000>; }; &sdhi2 { @@ -410,8 +414,10 @@ vqmmc-supply = <®_1p8v>; bus-width = <8>; mmc-hs200-1_8v; + mmc-hs400-1_8v; non-removable; status = "okay"; + max-frequency = <200000000>; }; &ssi1 { diff --git a/configs/r8a7795_salvator-x_defconfig b/configs/r8a7795_salvator-x_defconfig index 40712a44c3..149d6274aa 100644 --- a/configs/r8a7795_salvator-x_defconfig +++ b/configs/r8a7795_salvator-x_defconfig @@ -41,6 +41,7 @@ CONFIG_DM_MMC=y CONFIG_MMC_IO_VOLTAGE=y CONFIG_MMC_UHS_SUPPORT=y CONFIG_MMC_HS200_SUPPORT=y +CONFIG_MMC_HS400_SUPPORT=y CONFIG_RENESAS_SDHI=y CONFIG_PHY_MICREL=y CONFIG_PHY_MICREL_KSZ90X1=y diff --git a/configs/r8a7795_ulcb_defconfig b/configs/r8a7795_ulcb_defconfig index f1d150b5a0..8d765e2804 100644 --- a/configs/r8a7795_ulcb_defconfig +++ b/configs/r8a7795_ulcb_defconfig @@ -41,6 +41,7 @@ CONFIG_DM_MMC=y CONFIG_MMC_IO_VOLTAGE=y CONFIG_MMC_UHS_SUPPORT=y CONFIG_MMC_HS200_SUPPORT=y +CONFIG_MMC_HS400_SUPPORT=y CONFIG_RENESAS_SDHI=y CONFIG_PHY_MICREL=y CONFIG_PHY_MICREL_KSZ90X1=y diff --git a/configs/r8a77965_salvator-x_defconfig b/configs/r8a77965_salvator-x_defconfig index 72549e2836..2d6b86f0bb 100644 --- a/configs/r8a77965_salvator-x_defconfig +++ b/configs/r8a77965_salvator-x_defconfig @@ -42,6 +42,7 @@ CONFIG_DM_MMC=y CONFIG_MMC_IO_VOLTAGE=y CONFIG_MMC_UHS_SUPPORT=y CONFIG_MMC_HS200_SUPPORT=y +CONFIG_MMC_HS400_SUPPORT=y CONFIG_RENESAS_SDHI=y CONFIG_PHY_MICREL=y CONFIG_PHY_MICREL_KSZ90X1=y diff --git a/configs/r8a7796_salvator-x_defconfig b/configs/r8a7796_salvator-x_defconfig index 7c39268a43..352504532d 100644 --- a/configs/r8a7796_salvator-x_defconfig +++ b/configs/r8a7796_salvator-x_defconfig @@ -42,6 +42,7 @@ CONFIG_DM_MMC=y CONFIG_MMC_IO_VOLTAGE=y CONFIG_MMC_UHS_SUPPORT=y CONFIG_MMC_HS200_SUPPORT=y +CONFIG_MMC_HS400_SUPPORT=y CONFIG_RENESAS_SDHI=y CONFIG_PHY_MICREL=y CONFIG_PHY_MICREL_KSZ90X1=y diff --git a/configs/r8a7796_ulcb_defconfig b/configs/r8a7796_ulcb_defconfig index ef5c9443f9..b68bb7c647 100644 --- a/configs/r8a7796_ulcb_defconfig +++ b/configs/r8a7796_ulcb_defconfig @@ -42,6 +42,7 @@ CONFIG_DM_MMC=y CONFIG_MMC_IO_VOLTAGE=y CONFIG_MMC_UHS_SUPPORT=y CONFIG_MMC_HS200_SUPPORT=y +CONFIG_MMC_HS400_SUPPORT=y CONFIG_RENESAS_SDHI=y CONFIG_PHY_MICREL=y CONFIG_PHY_MICREL_KSZ90X1=y diff --git a/configs/r8a77990_ebisu_defconfig b/configs/r8a77990_ebisu_defconfig index 7363310d52..5a8fc04e17 100644 --- a/configs/r8a77990_ebisu_defconfig +++ b/configs/r8a77990_ebisu_defconfig @@ -42,6 +42,7 @@ CONFIG_DM_MMC=y CONFIG_MMC_IO_VOLTAGE=y CONFIG_MMC_UHS_SUPPORT=y CONFIG_MMC_HS200_SUPPORT=y +CONFIG_MMC_HS400_SUPPORT=y CONFIG_RENESAS_SDHI=y CONFIG_PHY_MICREL=y CONFIG_PHY_MICREL_KSZ90X1=y diff --git a/drivers/clk/renesas/clk-rcar-gen3.c b/drivers/clk/renesas/clk-rcar-gen3.c index 99698b1f46..0529fc8763 100644 --- a/drivers/clk/renesas/clk-rcar-gen3.c +++ b/drivers/clk/renesas/clk-rcar-gen3.c @@ -107,7 +107,7 @@ static int gen3_clk_get_parent(struct gen3_clk_priv *priv, struct clk *clk, return renesas_clk_get_parent(clk, info, parent); } -static int gen3_clk_setup_sdif_div(struct clk *clk) +static int gen3_clk_setup_sdif_div(struct clk *clk, ulong rate) { struct gen3_clk_priv *priv = dev_get_priv(clk->dev); struct cpg_mssr_info *info = priv->info; @@ -133,7 +133,7 @@ static int gen3_clk_setup_sdif_div(struct clk *clk) debug("%s[%i] SDIF offset=%x\n", __func__, __LINE__, core->offset); - writel(1, priv->base + core->offset); + writel((rate == 400000000) ? 0x4 : 0x1, priv->base + core->offset); return 0; } @@ -141,10 +141,6 @@ static int gen3_clk_setup_sdif_div(struct clk *clk) static int gen3_clk_enable(struct clk *clk) { struct gen3_clk_priv *priv = dev_get_priv(clk->dev); - int ret = gen3_clk_setup_sdif_div(clk); - - if (ret) - return ret; return renesas_clk_endisable(clk, priv->base, true); } @@ -328,7 +324,7 @@ static ulong gen3_clk_get_rate(struct clk *clk) static ulong gen3_clk_set_rate(struct clk *clk, ulong rate) { /* Force correct SD-IF divider configuration if applicable */ - gen3_clk_setup_sdif_div(clk); + gen3_clk_setup_sdif_div(clk, rate); return gen3_clk_get_rate64(clk); } diff --git a/drivers/mmc/mmc-uclass.c b/drivers/mmc/mmc-uclass.c index f73f07254b..76225b7939 100644 --- a/drivers/mmc/mmc-uclass.c +++ b/drivers/mmc/mmc-uclass.c @@ -166,6 +166,10 @@ int mmc_of_parse(struct udevice *dev, struct mmc_config *cfg) cfg->host_caps |= MMC_CAP(MMC_HS_200); if (dev_read_bool(dev, "mmc-hs200-1_2v")) cfg->host_caps |= MMC_CAP(MMC_HS_200); + if (dev_read_bool(dev, "mmc-hs400-1_8v")) + cfg->host_caps |= MMC_CAP(MMC_HS_400); + if (dev_read_bool(dev, "mmc-hs400-1_2v")) + cfg->host_caps |= MMC_CAP(MMC_HS_400); return 0; } diff --git a/drivers/mmc/renesas-sdhi.c b/drivers/mmc/renesas-sdhi.c index e7f96f8bf2..733b6d62f5 100644 --- a/drivers/mmc/renesas-sdhi.c +++ b/drivers/mmc/renesas-sdhi.c @@ -17,7 +17,9 @@ #include "tmio-common.h" -#if CONFIG_IS_ENABLED(MMC_HS200_SUPPORT) +#if CONFIG_IS_ENABLED(MMC_UHS_SUPPORT) || \ + CONFIG_IS_ENABLED(MMC_HS200_SUPPORT) || \ + CONFIG_IS_ENABLED(MMC_HS400_SUPPORT) /* SCC registers */ #define RENESAS_SDHI_SCC_DTCNTL 0x800 @@ -107,6 +109,56 @@ static void renesas_sdhi_reset_tuning(struct tmio_sd_priv *priv) tmio_sd_writel(priv, reg, RENESAS_SDHI_SCC_RVSCNTL); } +static int renesas_sdhi_hs400(struct udevice *dev) +{ + struct tmio_sd_priv *priv = dev_get_priv(dev); + struct mmc *mmc = mmc_get_mmc_dev(dev); + bool hs400 = (mmc->selected_mode == MMC_HS_400); + int ret, taps = hs400 ? priv->nrtaps : 8; + u32 reg; + + if (taps == 4) /* HS400 on 4tap SoC needs different clock */ + ret = clk_set_rate(&priv->clk, 400000000); + else + ret = clk_set_rate(&priv->clk, 200000000); + if (ret < 0) + return ret; + + tmio_sd_writel(priv, 0, RENESAS_SDHI_SCC_RVSREQ); + + reg = tmio_sd_readl(priv, RENESAS_SDHI_SCC_TMPPORT2); + if (hs400) { + reg |= RENESAS_SDHI_SCC_TMPPORT2_HS400EN | + RENESAS_SDHI_SCC_TMPPORT2_HS400OSEL; + } else { + reg &= ~(RENESAS_SDHI_SCC_TMPPORT2_HS400EN | + RENESAS_SDHI_SCC_TMPPORT2_HS400OSEL); + } + + tmio_sd_writel(priv, reg, RENESAS_SDHI_SCC_TMPPORT2); + + tmio_sd_writel(priv, (taps << RENESAS_SDHI_SCC_DTCNTL_TAPNUM_SHIFT) | + RENESAS_SDHI_SCC_DTCNTL_TAPEN, + RENESAS_SDHI_SCC_DTCNTL); + + if (taps == 4) { + tmio_sd_writel(priv, priv->tap_set >> 1, + RENESAS_SDHI_SCC_TAPSET); + } else { + tmio_sd_writel(priv, priv->tap_set, RENESAS_SDHI_SCC_TAPSET); + } + + reg = tmio_sd_readl(priv, RENESAS_SDHI_SCC_CKSEL); + reg |= RENESAS_SDHI_SCC_CKSEL_DTSEL; + tmio_sd_writel(priv, reg, RENESAS_SDHI_SCC_CKSEL); + + reg = tmio_sd_readl(priv, RENESAS_SDHI_SCC_RVSCNTL); + reg |= RENESAS_SDHI_SCC_RVSCNTL_RVSEN; + tmio_sd_writel(priv, reg, RENESAS_SDHI_SCC_RVSCNTL); + + return 0; +} + static void renesas_sdhi_prepare_tuning(struct tmio_sd_priv *priv, unsigned long tap) { @@ -125,7 +177,6 @@ static int renesas_sdhi_select_tuning(struct tmio_sd_priv *priv, unsigned int smpcmp) { unsigned long tap_cnt; /* counter of tuning success */ - unsigned long tap_set; /* tap position */ unsigned long tap_start;/* start position of tuning success */ unsigned long tap_end; /* end position of tuning success */ unsigned long ntap; /* temporary counter of tuning success */ @@ -209,12 +260,12 @@ static int renesas_sdhi_select_tuning(struct tmio_sd_priv *priv, select = true; if (select) - tap_set = ((tap_start + tap_end) / 2) % tap_num; + priv->tap_set = ((tap_start + tap_end) / 2) % tap_num; else return -EIO; /* Set SCC */ - tmio_sd_writel(priv, tap_set, RENESAS_SDHI_SCC_TAPSET); + tmio_sd_writel(priv, priv->tap_set, RENESAS_SDHI_SCC_TAPSET); /* Enable auto re-tuning */ reg = tmio_sd_readl(priv, RENESAS_SDHI_SCC_RVSCNTL); @@ -240,6 +291,7 @@ int renesas_sdhi_execute_tuning(struct udevice *dev, uint opcode) /* clock tuning is not needed for upto 52MHz */ if (!((mmc->selected_mode == MMC_HS_200) || + (mmc->selected_mode == MMC_HS_400) || (mmc->selected_mode == UHS_SDR104) || (mmc->selected_mode == UHS_SDR50))) return 0; @@ -287,19 +339,42 @@ out: return ret; } +#else +static int renesas_sdhi_hs400(struct udevice *dev) +{ + return 0; +} #endif static int renesas_sdhi_set_ios(struct udevice *dev) { - int ret = tmio_sd_set_ios(dev); + struct tmio_sd_priv *priv = dev_get_priv(dev); + u32 tmp; + int ret; + + /* Stop the clock before changing its rate to avoid a glitch signal */ + tmp = tmio_sd_readl(priv, TMIO_SD_CLKCTL); + tmp &= ~TMIO_SD_CLKCTL_SCLKEN; + tmio_sd_writel(priv, tmp, TMIO_SD_CLKCTL); + + ret = renesas_sdhi_hs400(dev); + if (ret) + return ret; + + ret = tmio_sd_set_ios(dev); mdelay(10); -#if CONFIG_IS_ENABLED(MMC_HS200_SUPPORT) - struct tmio_sd_priv *priv = dev_get_priv(dev); - - if (priv->caps & TMIO_SD_CAP_RCAR_UHS) +#if CONFIG_IS_ENABLED(MMC_UHS_SUPPORT) || \ + CONFIG_IS_ENABLED(MMC_HS200_SUPPORT) || \ + CONFIG_IS_ENABLED(MMC_HS400_SUPPORT) + struct mmc *mmc = mmc_get_mmc_dev(dev); + if ((priv->caps & TMIO_SD_CAP_RCAR_UHS) && + (mmc->selected_mode != UHS_SDR104) && + (mmc->selected_mode != MMC_HS_200) && + (mmc->selected_mode != MMC_HS_400)) { renesas_sdhi_reset_tuning(priv); + } #endif return ret; @@ -331,7 +406,9 @@ static const struct dm_mmc_ops renesas_sdhi_ops = { .send_cmd = tmio_sd_send_cmd, .set_ios = renesas_sdhi_set_ios, .get_cd = tmio_sd_get_cd, -#if CONFIG_IS_ENABLED(MMC_UHS_SUPPORT) || CONFIG_IS_ENABLED(MMC_HS200_SUPPORT) +#if CONFIG_IS_ENABLED(MMC_UHS_SUPPORT) || \ + CONFIG_IS_ENABLED(MMC_HS200_SUPPORT) || \ + CONFIG_IS_ENABLED(MMC_HS400_SUPPORT) .execute_tuning = renesas_sdhi_execute_tuning, #endif #if CONFIG_IS_ENABLED(MMC_UHS_SUPPORT) @@ -358,15 +435,45 @@ static const struct udevice_id renesas_sdhi_match[] = { { /* sentinel */ } }; +static ulong renesas_sdhi_clk_get_rate(struct tmio_sd_priv *priv) +{ + return clk_get_rate(&priv->clk); +} + +static void renesas_sdhi_filter_caps(struct udevice *dev) +{ + struct tmio_sd_plat *plat = dev_get_platdata(dev); + struct tmio_sd_priv *priv = dev_get_priv(dev); + + if (!(priv->caps & TMIO_SD_CAP_RCAR_GEN3)) + return; + + /* HS400 is not supported on H3 ES1.x and M3W ES1.0,ES1.1 */ + if (((rmobile_get_cpu_type() == RMOBILE_CPU_TYPE_R8A7795) && + (rmobile_get_cpu_rev_integer() <= 1)) || + ((rmobile_get_cpu_type() == RMOBILE_CPU_TYPE_R8A7796) && + (rmobile_get_cpu_rev_integer() == 1) && + (rmobile_get_cpu_rev_fraction() <= 1))) + plat->cfg.host_caps &= ~MMC_MODE_HS400; + + /* H3 ES2.0 uses 4 tuning taps */ + if ((rmobile_get_cpu_type() == RMOBILE_CPU_TYPE_R8A7795) && + (rmobile_get_cpu_rev_integer() == 2)) + priv->nrtaps = 4; + else + priv->nrtaps = 8; +} + static int renesas_sdhi_probe(struct udevice *dev) { struct tmio_sd_priv *priv = dev_get_priv(dev); u32 quirks = dev_get_driver_data(dev); struct fdt_resource reg_res; - struct clk clk; DECLARE_GLOBAL_DATA_PTR; int ret; + priv->clk_get_rate = renesas_sdhi_clk_get_rate; + if (quirks == RENESAS_GEN2_QUIRKS) { ret = fdt_get_resource(gd->fdt_blob, dev_of_offset(dev), "reg", 0, ®_res); @@ -380,29 +487,33 @@ static int renesas_sdhi_probe(struct udevice *dev) quirks |= TMIO_SD_CAP_16BIT; } - ret = clk_get_by_index(dev, 0, &clk); + ret = clk_get_by_index(dev, 0, &priv->clk); if (ret < 0) { dev_err(dev, "failed to get host clock\n"); return ret; } /* set to max rate */ - priv->mclk = clk_set_rate(&clk, ULONG_MAX); - if (IS_ERR_VALUE(priv->mclk)) { + ret = clk_set_rate(&priv->clk, 200000000); + if (ret < 0) { dev_err(dev, "failed to set rate for host clock\n"); - clk_free(&clk); - return priv->mclk; + clk_free(&priv->clk); + return ret; } - ret = clk_enable(&clk); - clk_free(&clk); + ret = clk_enable(&priv->clk); if (ret) { dev_err(dev, "failed to enable host clock\n"); return ret; } ret = tmio_sd_probe(dev, quirks); -#if CONFIG_IS_ENABLED(MMC_HS200_SUPPORT) + + renesas_sdhi_filter_caps(dev); + +#if CONFIG_IS_ENABLED(MMC_UHS_SUPPORT) || \ + CONFIG_IS_ENABLED(MMC_HS200_SUPPORT) || \ + CONFIG_IS_ENABLED(MMC_HS400_SUPPORT) if (!ret && (priv->caps & TMIO_SD_CAP_RCAR_UHS)) renesas_sdhi_reset_tuning(priv); #endif diff --git a/drivers/mmc/tmio-common.c b/drivers/mmc/tmio-common.c index 0eca83a0f4..201492001f 100644 --- a/drivers/mmc/tmio-common.c +++ b/drivers/mmc/tmio-common.c @@ -555,55 +555,76 @@ static void tmio_sd_set_ddr_mode(struct tmio_sd_priv *priv, tmio_sd_writel(priv, tmp, TMIO_SD_IF_MODE); } -static void tmio_sd_set_clk_rate(struct tmio_sd_priv *priv, - struct mmc *mmc) +static ulong tmio_sd_clk_get_rate(struct tmio_sd_priv *priv) +{ + return priv->clk_get_rate(priv); +} + +static void tmio_sd_set_clk_rate(struct tmio_sd_priv *priv, struct mmc *mmc) { unsigned int divisor; - u32 val, tmp; + u32 tmp, val = 0; + ulong mclk; - if (!mmc->clock) - return; + if (mmc->clock) { + mclk = tmio_sd_clk_get_rate(priv); - divisor = DIV_ROUND_UP(priv->mclk, mmc->clock); + divisor = DIV_ROUND_UP(mclk, mmc->clock); - if (divisor <= 1) - val = (priv->caps & TMIO_SD_CAP_RCAR) ? - TMIO_SD_CLKCTL_RCAR_DIV1 : TMIO_SD_CLKCTL_DIV1; - else if (divisor <= 2) - val = TMIO_SD_CLKCTL_DIV2; - else if (divisor <= 4) - val = TMIO_SD_CLKCTL_DIV4; - else if (divisor <= 8) - val = TMIO_SD_CLKCTL_DIV8; - else if (divisor <= 16) - val = TMIO_SD_CLKCTL_DIV16; - else if (divisor <= 32) - val = TMIO_SD_CLKCTL_DIV32; - else if (divisor <= 64) - val = TMIO_SD_CLKCTL_DIV64; - else if (divisor <= 128) - val = TMIO_SD_CLKCTL_DIV128; - else if (divisor <= 256) - val = TMIO_SD_CLKCTL_DIV256; - else if (divisor <= 512 || !(priv->caps & TMIO_SD_CAP_DIV1024)) - val = TMIO_SD_CLKCTL_DIV512; - else - val = TMIO_SD_CLKCTL_DIV1024; + /* Do not set divider to 0xff in DDR mode */ + if (mmc->ddr_mode && (divisor == 1)) + divisor = 2; + + if (divisor <= 1) + val = (priv->caps & TMIO_SD_CAP_RCAR) ? + TMIO_SD_CLKCTL_RCAR_DIV1 : TMIO_SD_CLKCTL_DIV1; + else if (divisor <= 2) + val = TMIO_SD_CLKCTL_DIV2; + else if (divisor <= 4) + val = TMIO_SD_CLKCTL_DIV4; + else if (divisor <= 8) + val = TMIO_SD_CLKCTL_DIV8; + else if (divisor <= 16) + val = TMIO_SD_CLKCTL_DIV16; + else if (divisor <= 32) + val = TMIO_SD_CLKCTL_DIV32; + else if (divisor <= 64) + val = TMIO_SD_CLKCTL_DIV64; + else if (divisor <= 128) + val = TMIO_SD_CLKCTL_DIV128; + else if (divisor <= 256) + val = TMIO_SD_CLKCTL_DIV256; + else if (divisor <= 512 || !(priv->caps & TMIO_SD_CAP_DIV1024)) + val = TMIO_SD_CLKCTL_DIV512; + else + val = TMIO_SD_CLKCTL_DIV1024; + } tmp = tmio_sd_readl(priv, TMIO_SD_CLKCTL); - if (tmp & TMIO_SD_CLKCTL_SCLKEN && - (tmp & TMIO_SD_CLKCTL_DIV_MASK) == val) - return; + if (mmc->clock && + !((tmp & TMIO_SD_CLKCTL_SCLKEN) && + ((tmp & TMIO_SD_CLKCTL_DIV_MASK) == val))) { + /* + * Stop the clock before changing its rate + * to avoid a glitch signal + */ + tmp &= ~TMIO_SD_CLKCTL_SCLKEN; + tmio_sd_writel(priv, tmp, TMIO_SD_CLKCTL); - /* stop the clock before changing its rate to avoid a glitch signal */ - tmp &= ~TMIO_SD_CLKCTL_SCLKEN; - tmio_sd_writel(priv, tmp, TMIO_SD_CLKCTL); + /* Change the clock rate. */ + tmp &= ~TMIO_SD_CLKCTL_DIV_MASK; + tmp |= val; + } - tmp &= ~TMIO_SD_CLKCTL_DIV_MASK; - tmp |= val | TMIO_SD_CLKCTL_OFFEN; - tmio_sd_writel(priv, tmp, TMIO_SD_CLKCTL); + /* Enable or Disable the clock */ + if (mmc->clk_disable) { + tmp |= TMIO_SD_CLKCTL_OFFEN; + tmp &= ~TMIO_SD_CLKCTL_SCLKEN; + } else { + tmp &= ~TMIO_SD_CLKCTL_OFFEN; + tmp |= TMIO_SD_CLKCTL_SCLKEN; + } - tmp |= TMIO_SD_CLKCTL_SCLKEN; tmio_sd_writel(priv, tmp, TMIO_SD_CLKCTL); udelay(1000); @@ -708,6 +729,7 @@ int tmio_sd_probe(struct udevice *dev, u32 quirks) struct tmio_sd_priv *priv = dev_get_priv(dev); struct mmc_uclass_priv *upriv = dev_get_uclass_priv(dev); fdt_addr_t base; + ulong mclk; int ret; base = devfdt_get_addr(dev); @@ -750,10 +772,12 @@ int tmio_sd_probe(struct udevice *dev, u32 quirks) tmio_sd_host_init(priv); + mclk = tmio_sd_clk_get_rate(priv); + plat->cfg.voltages = MMC_VDD_165_195 | MMC_VDD_32_33 | MMC_VDD_33_34; - plat->cfg.f_min = priv->mclk / + plat->cfg.f_min = mclk / (priv->caps & TMIO_SD_CAP_DIV1024 ? 1024 : 512); - plat->cfg.f_max = priv->mclk; + plat->cfg.f_max = mclk; plat->cfg.b_max = U32_MAX; /* max value of TMIO_SD_SECCNT */ upriv->mmc = &plat->mmc; diff --git a/drivers/mmc/tmio-common.h b/drivers/mmc/tmio-common.h index 792b1ba5ae..192026ce3e 100644 --- a/drivers/mmc/tmio-common.h +++ b/drivers/mmc/tmio-common.h @@ -117,7 +117,6 @@ struct tmio_sd_plat { struct tmio_sd_priv { void __iomem *regbase; - unsigned long mclk; unsigned int version; u32 caps; #define TMIO_SD_CAP_NONREMOVABLE BIT(0) /* Nonremovable e.g. eMMC */ @@ -133,6 +132,14 @@ struct tmio_sd_priv { #ifdef CONFIG_DM_REGULATOR struct udevice *vqmmc_dev; #endif +#if CONFIG_IS_ENABLED(CLK) + struct clk clk; +#endif +#if CONFIG_IS_ENABLED(RENESAS_SDHI) + u8 tap_set; + u8 nrtaps; +#endif + ulong (*clk_get_rate)(struct tmio_sd_priv *); }; int tmio_sd_send_cmd(struct udevice *dev, struct mmc_cmd *cmd, diff --git a/drivers/mmc/uniphier-sd.c b/drivers/mmc/uniphier-sd.c index 813c28494c..6539880ab5 100644 --- a/drivers/mmc/uniphier-sd.c +++ b/drivers/mmc/uniphier-sd.c @@ -31,35 +31,45 @@ static const struct udevice_id uniphier_sd_match[] = { { /* sentinel */ } }; +static ulong uniphier_sd_clk_get_rate(struct tmio_sd_priv *priv) +{ +#if CONFIG_IS_ENABLED(CLK) + return clk_get_rate(&priv->clk); +#elif CONFIG_SPL_BUILD + return 100000000; +#else + return 0; +#endif +} + static int uniphier_sd_probe(struct udevice *dev) { struct tmio_sd_priv *priv = dev_get_priv(dev); + + priv->clk_get_rate = uniphier_sd_clk_get_rate; + #ifndef CONFIG_SPL_BUILD - struct clk clk; int ret; - ret = clk_get_by_index(dev, 0, &clk); + ret = clk_get_by_index(dev, 0, &priv->clk); if (ret < 0) { dev_err(dev, "failed to get host clock\n"); return ret; } /* set to max rate */ - priv->mclk = clk_set_rate(&clk, ULONG_MAX); - if (IS_ERR_VALUE(priv->mclk)) { + ret = clk_set_rate(&priv->clk, ULONG_MAX); + if (ret < 0) { dev_err(dev, "failed to set rate for host clock\n"); - clk_free(&clk); - return priv->mclk; + clk_free(&priv->clk); + return ret; } - ret = clk_enable(&clk); - clk_free(&clk); + ret = clk_enable(&priv->clk); if (ret) { dev_err(dev, "failed to enable host clock\n"); return ret; } -#else - priv->mclk = 100000000; #endif return tmio_sd_probe(dev, 0);