Hi Henrik,

On Fri, 8 May 2026 at 00:55, Henrik Grimler <[email protected]> wrote:
>
> Hi Kaustabh,
>
> On Thu, May 07, 2026 at 01:33:28AM +0530, Kaustabh Chakraborty wrote:
> > On 2026-05-05 21:07 +02:00, 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.
> >
> > Do you have any logs or traces which may be able to help pinpoint it?
> > I can try to figure out the issue(s) if you want me to.
>
> I fully synced the mmc dts node with linux variant. This device does
> not have a pinctrl driver so pinctrl settings are not applied though,
> so I also updated the exynos-pinmux mmc function. See attached diff.
>
> I then also enabled just CONFIG_MMC_HS400_SUPPORT, or both
> MMC_HS400_SUPPORT and MMC_HS400_ES_SUPPORT. With MMC_HS400_ES_SUPPORT
> I get:
>
> ODROID-XU3 # mmc info
> Select HS400ES failed -22
> unable to select a mode: -5
>
> And with just MMC_HS400_SUPPORT I get:
>
> ODROID-XU3 # mmc info
> Select HS400 failed -110
> unable to select a mode: -110
>
> I have not run it with additional debugging.
>
> I have plans to switch over to OF_UPSTREAM, and add a pinctrl driver,
> maybe that would fix it. Probably not worth spending too much time
> debugging it at this point.
>
We need to transition Exynos4 and Exynos5 SoCs to OF_UPSTREAM.
I attempted this earlier, but the clock subsystem for these SoCs still
requires work to function correctly in U-Boot.

Thanks
-Anand
> Best regards,
> Henrik Grimler
>
> > >
> > > 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