On Tue, May 05, 2026 at 09:07:29PM +0200, Henrik Grimler wrote:
>Hi Kaustabh,
>
>On Sun, May 03, 2026 at 05:51:26PM +0530, Kaustabh Chakraborty wrote:
>> HS400 support was added, but configuration necessary for HS400 support
>> was left out. Add necessary changes, which includes:
>> - Device tree properties, such as "samsung,dw-mshc-hs400-timing" and
>>   "samsung,read-strobe-delay", which function as per dt-bindings.
>> - Registers related to HS400, which are necessary to enable HS400+ support.
>> - Appropriate timing tunings for the HS400 mode.
>> 
>> Note that these changes are loosely based off of its Linux kernel
>> counterpart.
>> 
>> Fixes: bbe3b9fa0922 ("mmc: exynos_dw_mmc: add support for MMC HS200 and 
>> HS400 modes")
>> Signed-off-by: Kaustabh Chakraborty <[email protected]>
>
>Reviewed-by: Henrik Grimler <[email protected]>
>
>This works fine on exynos5422-odroid-xu4 without hs400. I was not able
>to get hs400 working on the device, seems more changes than just dts
>update are needed.

Is this patchset good for you all or is there any plan for a new version for
2026.07?

Thanks
Peng

>
>Best regards,
>Henrik Grimler
>
>> ---
>>  arch/arm/mach-exynos/include/mach/dwmmc.h |  5 ++
>>  drivers/mmc/exynos_dw_mmc.c               | 81 
>> +++++++++++++++++++++++++++++++
>>  2 files changed, 86 insertions(+)
>> 
>> diff --git a/arch/arm/mach-exynos/include/mach/dwmmc.h 
>> b/arch/arm/mach-exynos/include/mach/dwmmc.h
>> index 4432deedef7..50081326c25 100644
>> --- a/arch/arm/mach-exynos/include/mach/dwmmc.h
>> +++ b/arch/arm/mach-exynos/include/mach/dwmmc.h
>> @@ -15,6 +15,11 @@
>>  #define DWMCI_SET_DRV_CLK(x)                ((x) << 16)
>>  #define DWMCI_SET_DIV_RATIO(x)              ((x) << 24)
>>  
>> +/* HS400 Related Registers */
>> +#define DWMCI_HS400_DQS_EN          0x180
>> +#define DWMCI_HS400_ASYNC_FIFO_CTRL 0x184
>> +#define DWMCI_HS400_DLINE_CTRL              0x188
>> +
>>  /* Protector Register */
>>  #define DWMCI_EMMCP_BASE            0x1000
>>  #define EMMCP_MPSECURITY            (DWMCI_EMMCP_BASE + 0x0010)
>> diff --git a/drivers/mmc/exynos_dw_mmc.c b/drivers/mmc/exynos_dw_mmc.c
>> index 7ccd113bd79..6558cdc803d 100644
>> --- a/drivers/mmc/exynos_dw_mmc.c
>> +++ b/drivers/mmc/exynos_dw_mmc.c
>> @@ -8,6 +8,7 @@
>>  #include <dwmmc.h>
>>  #include <asm/global_data.h>
>>  #include <malloc.h>
>> +#include <mmc.h>
>>  #include <errno.h>
>>  #include <asm/arch/dwmmc.h>
>>  #include <asm/arch/clk.h>
>> @@ -30,6 +31,14 @@
>>  #define CLKSEL_UP_SAMPLE(x, y)              (((x) & ~CLKSEL_CCLK_SAMPLE(7)) 
>> | \
>>                                       CLKSEL_CCLK_SAMPLE(y))
>>  
>> +/* RCLK_EN register defines */
>> +#define DATA_STROBE_EN                      BIT(0)
>> +#define AXI_NON_BLOCKING_WR BIT(7)
>> +
>> +/* DLINE_CTRL register defines */
>> +#define DQS_CTRL_RD_DELAY(x, y)             (((x) & ~0x3FF) | ((y) & 0x3FF))
>> +#define DQS_CTRL_GET_RD_DELAY(x)    ((x) & 0x3FF)
>> +
>>  /**
>>   * DOC: Quirk flags for different Exynos DW MMC blocks
>>   *
>> @@ -71,6 +80,11 @@ struct dwmci_exynos_priv_data {
>>      struct clk clk;
>>      u32 sdr_timing;
>>      u32 ddr_timing;
>> +    u32 hs400_timing;
>> +    u32 tuned_sample;
>> +    u32 dqs_delay;
>> +    u32 saved_dqs_en;
>> +    u32 saved_strobe_ctrl;
>>      const struct exynos_dwmmc_variant *chip;
>>  };
>>  
>> @@ -162,6 +176,27 @@ static u8 exynos_dwmmc_get_ciu_div(struct dwmci_host 
>> *host)
>>                              & DWMCI_DIVRATIO_MASK) + 1;
>>  }
>>  
>> +static void exynos_config_hs400(struct dwmci_host *host, enum bus_mode mode)
>> +{
>> +    struct dwmci_exynos_priv_data *priv = exynos_dwmmc_get_priv(host);
>> +    u32 dqs, strobe;
>> +
>> +    dqs = priv->saved_dqs_en;
>> +    strobe = priv->saved_strobe_ctrl;
>> +
>> +    switch (mode) {
>> +    case MMC_HS_400:
>> +            dqs |= DATA_STROBE_EN;
>> +            strobe = DQS_CTRL_RD_DELAY(strobe, priv->dqs_delay);
>> +            break;
>> +    default:
>> +            dqs &= ~DATA_STROBE_EN;
>> +    }
>> +
>> +    dwmci_writel(host, DWMCI_HS400_DQS_EN, dqs);
>> +    dwmci_writel(host, DWMCI_HS400_DLINE_CTRL, strobe);
>> +}
>> +
>>  /* Configure CLKSEL register with chosen timing values */
>>  static int exynos_dwmci_clksel(struct dwmci_host *host)
>>  {
>> @@ -170,6 +205,9 @@ static int exynos_dwmci_clksel(struct dwmci_host *host)
>>      u32 timing;
>>  
>>      switch (host->mmc->selected_mode) {
>> +    case MMC_HS_400:
>> +            timing = CLKSEL_UP_SAMPLE(priv->hs400_timing, 
>> priv->tuned_sample);
>> +            break;
>>      case MMC_DDR_52:
>>              timing = priv->ddr_timing;
>>              break;
>> @@ -186,6 +224,9 @@ static int exynos_dwmci_clksel(struct dwmci_host *host)
>>  
>>      dwmci_writel(host, priv->chip->clksel, timing);
>>  
>> +    if (CONFIG_IS_ENABLED(MMC_HS400_SUPPORT))
>> +            exynos_config_hs400(host, host->mmc->selected_mode);
>> +
>>      return 0;
>>  }
>>  
>> @@ -223,6 +264,16 @@ static void exynos_dwmci_board_init(struct dwmci_host 
>> *host)
>>  {
>>      struct dwmci_exynos_priv_data *priv = exynos_dwmmc_get_priv(host);
>>  
>> +    if (CONFIG_IS_ENABLED(MMC_HS400_SUPPORT)) {
>> +            priv->saved_strobe_ctrl = dwmci_readl(host, 
>> DWMCI_HS400_DLINE_CTRL);
>> +            priv->saved_dqs_en = dwmci_readl(host, DWMCI_HS400_DQS_EN);
>> +            priv->saved_dqs_en |= AXI_NON_BLOCKING_WR;
>> +            dwmci_writel(host, DWMCI_HS400_DQS_EN, priv->saved_dqs_en);
>> +            if (!priv->dqs_delay)
>> +                    priv->dqs_delay =
>> +                            DQS_CTRL_GET_RD_DELAY(priv->saved_strobe_ctrl);
>> +    }
>> +
>>      if (priv->chip->quirks & DWMCI_QUIRK_DISABLE_SMU) {
>>              dwmci_writel(host, EMMCP_MPSBEGIN0, 0);
>>              dwmci_writel(host, EMMCP_SEND0, 0);
>> @@ -319,6 +370,22 @@ static int exynos_dwmmc_of_to_plat(struct udevice *dev)
>>                                 DWMCI_SET_DIV_RATIO(div);
>>      }
>>  
>> +    err = dev_read_u32_array(dev, "samsung,dw-mshc-hs400-timing", timing, 
>> 2);
>> +    if (err) {
>> +            debug("DWMMC%d: Can't get hs400-timings, using ddr-timings\n",
>> +                  host->dev_index);
>> +            priv->hs400_timing = priv->ddr_timing;
>> +    } else {
>> +            priv->hs400_timing = DWMCI_SET_SAMPLE_CLK(timing[0]) |
>> +                                 DWMCI_SET_DRV_CLK(timing[1]) |
>> +                                 DWMCI_SET_DIV_RATIO(1);
>> +            if (dev_read_u32(dev, "samsung,read-strobe-delay", 
>> &priv->dqs_delay)) {
>> +                    priv->dqs_delay = 0;
>> +                    debug("DWMMC%d: read-strobe-delay is not found, 
>> assuming usage of default value\n",
>> +                          host->dev_index);
>> +            }
>> +    }
>> +
>>      host->buswidth = dev_read_u32_default(dev, "bus-width", 4);
>>      host->fifo_depth = dev_read_u32_default(dev, "fifo-depth", 0);
>>      host->bus_hz = dev_read_u32_default(dev, "clock-frequency", 0);
>> @@ -356,6 +423,16 @@ static int exynos_dwmmc_get_best_clksmpl(u8 candidates)
>>      return -EIO;
>>  }
>>  
>> +static int dw_mci_exynos_prepare_hs400_tuning(struct dwmci_host *host)
>> +{
>> +    struct dwmci_exynos_priv_data *priv = exynos_dwmmc_get_priv(host);
>> +
>> +    dwmci_writel(host, priv->chip->clksel, priv->hs400_timing);
>> +    host->bus_hz = exynos_dwmci_get_clk(host, host->clock);
>> +
>> +    return 0;
>> +}
>> +
>>  static int exynos_dwmmc_execute_tuning(struct udevice *dev, u32 opcode)
>>  {
>>      struct dwmci_exynos_priv_data *priv = dev_get_priv(dev);
>> @@ -365,6 +442,9 @@ static int exynos_dwmmc_execute_tuning(struct udevice 
>> *dev, u32 opcode)
>>      u32 clksel;
>>      int ret;
>>  
>> +    if (mmc->hs400_tuning)
>> +            dw_mci_exynos_prepare_hs400_tuning(host);
>> +
>>      clksel = dwmci_readl(host, priv->chip->clksel);
>>      start_smpl = CLKSEL_CCLK_SAMPLE(clksel);
>>  
>> @@ -387,6 +467,7 @@ static int exynos_dwmmc_execute_tuning(struct udevice 
>> *dev, u32 opcode)
>>              return ret;
>>      }
>>  
>> +    priv->tuned_sample = ret;
>>      dwmci_writel(host, priv->chip->clksel, CLKSEL_UP_SAMPLE(clksel, ret));
>>  
>>      return 0;
>> 
>> -- 
>> 2.53.0
>> 

Reply via email to