[PATCH 1/3] mmc: stm32_sdmmc2: add dual data rate support

To support dual data rate with STM32 sdmmc2 driver, the dedicated bit (DDR - BIT(18)) needs to be set in the CLKRC register. Clock bypass (no divider) is not allowed in this case. This is required for the eMMC DDR modes.
Signed-off-by: Yann Gautier yann.gautier@foss.st.com ---
drivers/mmc/stm32_sdmmc2.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-)
diff --git a/drivers/mmc/stm32_sdmmc2.c b/drivers/mmc/stm32_sdmmc2.c index bfce8a2e4a..3cfa5a66f1 100644 --- a/drivers/mmc/stm32_sdmmc2.c +++ b/drivers/mmc/stm32_sdmmc2.c @@ -598,13 +598,16 @@ static int stm32_sdmmc2_set_ios(struct udevice *dev) * clk_div > 0 and NEGEDGE = 1 => command and data generated on * SDMMCCLK falling edge */ - if (desired && ((sys_clock > desired) || + if (desired && (sys_clock > desired || mmc->ddr_mode || IS_RISING_EDGE(plat->clk_reg_msk))) { clk = DIV_ROUND_UP(sys_clock, 2 * desired); if (clk > SDMMC_CLKCR_CLKDIV_MAX) clk = SDMMC_CLKCR_CLKDIV_MAX; }
+ if (mmc->ddr_mode) + clk |= SDMMC_CLKCR_DDR; + if (mmc->bus_width == 4) clk |= SDMMC_CLKCR_WIDBUS_4; if (mmc->bus_width == 8)

The UHS modes for SD, HS200 and HS400 modes for eMMC are not supported by the stm32_sdmmc2 driver. Make it clear by removing the corresponding caps after parsing the DT.
Signed-off-by: Yann Gautier yann.gautier@foss.st.com ---
drivers/mmc/stm32_sdmmc2.c | 2 ++ 1 file changed, 2 insertions(+)
diff --git a/drivers/mmc/stm32_sdmmc2.c b/drivers/mmc/stm32_sdmmc2.c index 3cfa5a66f1..e1240b0cf3 100644 --- a/drivers/mmc/stm32_sdmmc2.c +++ b/drivers/mmc/stm32_sdmmc2.c @@ -675,6 +675,8 @@ static int stm32_sdmmc2_of_to_plat(struct udevice *dev) if (ret) return ret;
+ cfg->host_caps &= ~(UHS_CAPS | MMC_MODE_HS200 | MMC_MODE_HS400 | MMC_MODE_HS400_ES); + ret = clk_get_by_index(dev, 0, &plat->clk); if (ret) return ret;

On 9/13/22 20:23, Yann Gautier wrote:
The UHS modes for SD, HS200 and HS400 modes for eMMC are not supported by the stm32_sdmmc2 driver. Make it clear by removing the corresponding caps after parsing the DT.
Signed-off-by: Yann Gautier yann.gautier@foss.st.com
Reviewed-by: Jaehoon Chung jh80.chung@samsung.com
Best Regards, Jaehoon Chung
drivers/mmc/stm32_sdmmc2.c | 2 ++ 1 file changed, 2 insertions(+)
diff --git a/drivers/mmc/stm32_sdmmc2.c b/drivers/mmc/stm32_sdmmc2.c index 3cfa5a66f1..e1240b0cf3 100644 --- a/drivers/mmc/stm32_sdmmc2.c +++ b/drivers/mmc/stm32_sdmmc2.c @@ -675,6 +675,8 @@ static int stm32_sdmmc2_of_to_plat(struct udevice *dev) if (ret) return ret;
- cfg->host_caps &= ~(UHS_CAPS | MMC_MODE_HS200 | MMC_MODE_HS400 | MMC_MODE_HS400_ES);
- ret = clk_get_by_index(dev, 0, &plat->clk); if (ret) return ret;

The SDMMC IOs can be in an IO domain, that has to be enabled. This is done by enabling vqmmc in the driver. This has no impact on configurations not using an IO domain, the check can then be executed on all platforms managing regulator, and the vqmmc regulator enabled on all platforms having it in their DT.
Signed-off-by: Yann Gautier yann.gautier@foss.st.com
--- There are 2 checkpatch warnings: drivers/mmc/stm32_sdmmc2.c:40: warning: Use 'if (IS_ENABLED(CONFIG...))' instead of '#if or #ifdef' where possible drivers/mmc/stm32_sdmmc2.c:580: warning: Use 'if (IS_ENABLED(CONFIG...))' instead of '#if or #ifdef' where possible But this cannot be changed as the vqmmc_supply field in struct mmc is under flag: #if CONFIG_IS_ENABLED(DM_REGULATOR). For platforms not enabling this flag there would be a compilation error.
drivers/mmc/stm32_sdmmc2.c | 13 +++++++++++++ 1 file changed, 13 insertions(+)
diff --git a/drivers/mmc/stm32_sdmmc2.c b/drivers/mmc/stm32_sdmmc2.c index e1240b0cf3..1195134844 100644 --- a/drivers/mmc/stm32_sdmmc2.c +++ b/drivers/mmc/stm32_sdmmc2.c @@ -25,6 +25,7 @@ #include <asm/io.h> #include <asm/gpio.h> #include <linux/iopoll.h> +#include <power/regulator.h> #include <watchdog.h>
struct stm32_sdmmc2_plat { @@ -36,6 +37,9 @@ struct stm32_sdmmc2_plat { struct gpio_desc cd_gpio; u32 clk_reg_msk; u32 pwr_reg_msk; +#if CONFIG_IS_ENABLED(DM_REGULATOR) + bool vqmmc_enabled; +#endif };
struct stm32_sdmmc2_ctx { @@ -572,6 +576,15 @@ static void stm32_sdmmc2_pwron(struct stm32_sdmmc2_plat *plat) plat->base + SDMMC_POWER);
/* during the first 74 SDMMC_CK cycles the SDMMC is still disabled. */ + +#if CONFIG_IS_ENABLED(DM_REGULATOR) + if (plat->mmc.vqmmc_supply && !plat->vqmmc_enabled) { + if (regulator_set_enable_if_allowed(plat->mmc.vqmmc_supply, true)) + dev_dbg(plat->mmc.dev, "failed to enable vqmmc-supply\n"); + else + plat->vqmmc_enabled = true; + } +#endif }
#define IS_RISING_EDGE(reg) (reg & SDMMC_CLKCR_NEGEDGE ? 0 : 1)

On 9/13/22 20:23, Yann Gautier wrote:
The SDMMC IOs can be in an IO domain, that has to be enabled. This is done by enabling vqmmc in the driver. This has no impact on configurations not using an IO domain, the check can then be executed on all platforms managing regulator, and the vqmmc regulator enabled on all platforms having it in their DT.
Signed-off-by: Yann Gautier yann.gautier@foss.st.com
Reviewed-by: Jaehoon Chung jh80.chung@samsung.com
Best Regards, Jaehoon Chung
There are 2 checkpatch warnings: drivers/mmc/stm32_sdmmc2.c:40: warning: Use 'if (IS_ENABLED(CONFIG...))' instead of '#if or #ifdef' where possible drivers/mmc/stm32_sdmmc2.c:580: warning: Use 'if (IS_ENABLED(CONFIG...))' instead of '#if or #ifdef' where possible But this cannot be changed as the vqmmc_supply field in struct mmc is under flag: #if CONFIG_IS_ENABLED(DM_REGULATOR). For platforms not enabling this flag there would be a compilation error.
drivers/mmc/stm32_sdmmc2.c | 13 +++++++++++++ 1 file changed, 13 insertions(+)
diff --git a/drivers/mmc/stm32_sdmmc2.c b/drivers/mmc/stm32_sdmmc2.c index e1240b0cf3..1195134844 100644 --- a/drivers/mmc/stm32_sdmmc2.c +++ b/drivers/mmc/stm32_sdmmc2.c @@ -25,6 +25,7 @@ #include <asm/io.h> #include <asm/gpio.h> #include <linux/iopoll.h> +#include <power/regulator.h> #include <watchdog.h>
struct stm32_sdmmc2_plat { @@ -36,6 +37,9 @@ struct stm32_sdmmc2_plat { struct gpio_desc cd_gpio; u32 clk_reg_msk; u32 pwr_reg_msk; +#if CONFIG_IS_ENABLED(DM_REGULATOR)
- bool vqmmc_enabled;
+#endif };
struct stm32_sdmmc2_ctx { @@ -572,6 +576,15 @@ static void stm32_sdmmc2_pwron(struct stm32_sdmmc2_plat *plat) plat->base + SDMMC_POWER);
/* during the first 74 SDMMC_CK cycles the SDMMC is still disabled. */
+#if CONFIG_IS_ENABLED(DM_REGULATOR)
- if (plat->mmc.vqmmc_supply && !plat->vqmmc_enabled) {
if (regulator_set_enable_if_allowed(plat->mmc.vqmmc_supply, true))
dev_dbg(plat->mmc.dev, "failed to enable vqmmc-supply\n");
else
plat->vqmmc_enabled = true;
- }
+#endif }
#define IS_RISING_EDGE(reg) (reg & SDMMC_CLKCR_NEGEDGE ? 0 : 1)

On 9/13/22 20:23, Yann Gautier wrote:
To support dual data rate with STM32 sdmmc2 driver, the dedicated bit (DDR - BIT(18)) needs to be set in the CLKRC register. Clock bypass (no divider) is not allowed in this case. This is required for the eMMC DDR modes.
Signed-off-by: Yann Gautier yann.gautier@foss.st.com
Reviewed-by: Jaehoon Chung jh80.chung@samsung.com
Best Regards, Jaehoon Chung
drivers/mmc/stm32_sdmmc2.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-)
diff --git a/drivers/mmc/stm32_sdmmc2.c b/drivers/mmc/stm32_sdmmc2.c index bfce8a2e4a..3cfa5a66f1 100644 --- a/drivers/mmc/stm32_sdmmc2.c +++ b/drivers/mmc/stm32_sdmmc2.c @@ -598,13 +598,16 @@ static int stm32_sdmmc2_set_ios(struct udevice *dev) * clk_div > 0 and NEGEDGE = 1 => command and data generated on * SDMMCCLK falling edge */
- if (desired && ((sys_clock > desired) ||
if (desired && (sys_clock > desired || mmc->ddr_mode || IS_RISING_EDGE(plat->clk_reg_msk))) { clk = DIV_ROUND_UP(sys_clock, 2 * desired); if (clk > SDMMC_CLKCR_CLKDIV_MAX) clk = SDMMC_CLKCR_CLKDIV_MAX; }
if (mmc->ddr_mode)
clk |= SDMMC_CLKCR_DDR;
if (mmc->bus_width == 4) clk |= SDMMC_CLKCR_WIDBUS_4; if (mmc->bus_width == 8)

On 9/13/22 20:23, Yann Gautier wrote:
To support dual data rate with STM32 sdmmc2 driver, the dedicated bit (DDR - BIT(18)) needs to be set in the CLKRC register. Clock bypass (no divider) is not allowed in this case. This is required for the eMMC DDR modes.
Signed-off-by: Yann Gautier yann.gautier@foss.st.com Reviewed-by: Jaehoon Chung jh80.chung@samsung.com
Applied to u-boot-mmc. Thanks! (with [PATCH 2/3] and [PATCH 3/3])
Best Regards, Jaehoon Chung
drivers/mmc/stm32_sdmmc2.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-)
diff --git a/drivers/mmc/stm32_sdmmc2.c b/drivers/mmc/stm32_sdmmc2.c index bfce8a2e4a..3cfa5a66f1 100644 --- a/drivers/mmc/stm32_sdmmc2.c +++ b/drivers/mmc/stm32_sdmmc2.c @@ -598,13 +598,16 @@ static int stm32_sdmmc2_set_ios(struct udevice *dev) * clk_div > 0 and NEGEDGE = 1 => command and data generated on * SDMMCCLK falling edge */
- if (desired && ((sys_clock > desired) ||
if (desired && (sys_clock > desired || mmc->ddr_mode || IS_RISING_EDGE(plat->clk_reg_msk))) { clk = DIV_ROUND_UP(sys_clock, 2 * desired); if (clk > SDMMC_CLKCR_CLKDIV_MAX) clk = SDMMC_CLKCR_CLKDIV_MAX; }
if (mmc->ddr_mode)
clk |= SDMMC_CLKCR_DDR;
if (mmc->bus_width == 4) clk |= SDMMC_CLKCR_WIDBUS_4; if (mmc->bus_width == 8)
participants (3)
-
Jaehoon Chung
-
Jaehoon Chung
-
Yann Gautier