From b033255a5795cc2d88f761c856d6e8e354267582 Mon Sep 17 00:00:00 2001 From: Tanmay Kathpalia Date: Wed, 3 Dec 2025 04:21:31 -0800 Subject: [PATCH 1/9] mmc: sdhci-cadence: Add reset control support Add reset control functionality to the SDHCI Cadence driver to properly handle hardware reset sequences during probe. This ensures the controller is in a known state before initialization. Signed-off-by: Tanmay Kathpalia Reviewed-by: Balsundar Ponnusamy Reviewed-by: Peng Fan Signed-off-by: Peng Fan --- drivers/mmc/sdhci-cadence.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/drivers/mmc/sdhci-cadence.c b/drivers/mmc/sdhci-cadence.c index 7d169efa476..6c9d24fe5f7 100644 --- a/drivers/mmc/sdhci-cadence.c +++ b/drivers/mmc/sdhci-cadence.c @@ -15,6 +15,7 @@ #include #include #include +#include #include #include "sdhci-cadence.h" @@ -214,6 +215,7 @@ static int sdhci_cdns_probe(struct udevice *dev) struct mmc_uclass_priv *upriv = dev_get_uclass_priv(dev); struct sdhci_cdns_plat *plat = dev_get_plat(dev); struct sdhci_host *host = dev_get_priv(dev); + struct reset_ctl_bulk reset_bulk; fdt_addr_t base; int ret; @@ -225,6 +227,10 @@ static int sdhci_cdns_probe(struct udevice *dev) if (!plat->hrs_addr) return -ENOMEM; + ret = reset_get_bulk(dev, &reset_bulk); + if (!ret) + reset_deassert_bulk(&reset_bulk); + host->name = dev->name; host->ioaddr = plat->hrs_addr + SDHCI_CDNS_SRS_BASE; host->ops = &sdhci_cdns_ops; From aebb523a23818a8ee4199c9532b51e3d4020696f Mon Sep 17 00:00:00 2001 From: Tanmay Kathpalia Date: Wed, 3 Dec 2025 04:21:32 -0800 Subject: [PATCH 2/9] mmc: mmc-uclass: Use max-frequency from device tree with default handling When the max-frequency property is not specified in the device tree, the function now explicitly defaults to 0 instead of leaving cfg->f_max uninitialized. This allows sdhci_setup_cfg() to properly detect the absence of a device tree specified frequency and fall back to using the host controller's maximum base clock frequency from the capabilities register. Signed-off-by: Tanmay Kathpalia Reviewed-by: Peng Fan Signed-off-by: Peng Fan --- drivers/mmc/mmc-uclass.c | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/drivers/mmc/mmc-uclass.c b/drivers/mmc/mmc-uclass.c index 2f4dc5bd887..bf0bea93853 100644 --- a/drivers/mmc/mmc-uclass.c +++ b/drivers/mmc/mmc-uclass.c @@ -243,8 +243,13 @@ int mmc_of_parse(struct udevice *dev, struct mmc_config *cfg) return -EINVAL; } - /* f_max is obtained from the optional "max-frequency" property */ - dev_read_u32(dev, "max-frequency", &cfg->f_max); + /* + * Maximum frequency is obtained from the optional "max-frequency" property. + * If not specified in device tree, defaults to 0 and sdhci_setup_cfg() + * will set the MMC configuration maximum frequency to the host controller's + * maximum base clock frequency from capabilities register. + */ + cfg->f_max = dev_read_u32_default(dev, "max-frequency", 0); if (dev_read_bool(dev, "cap-sd-highspeed")) cfg->host_caps |= MMC_CAP(SD_HS); From 1e40e419aeb25f8d9a3f6872b5dcd05a2ed2b06e Mon Sep 17 00:00:00 2001 From: Tanmay Kathpalia Date: Wed, 3 Dec 2025 04:21:33 -0800 Subject: [PATCH 3/9] mmc: sdhci-cadence: Use max-frequency property from device tree When f_max parameter is 0 in sdhci_setup_cfg(), the function defaults to using the maximum frequency from host controller capabilities register instead of the max-frequency property parsed from device tree. The max-frequency property from device tree is parsed by mmc_of_parse() and stored in plat->cfg.f_max, but sdhci_setup_cfg() was being called with f_max=0, causing it to ignore the device tree value and use the host capabilities register value instead. Fix this by passing plat->cfg.f_max to sdhci_setup_cfg() to ensure the device tree specified maximum frequency is respected over the hardware default. Signed-off-by: Tanmay Kathpalia Reviewed-by: Balsundar Ponnusamy Reviewed-by: Peng Fan Signed-off-by: Peng Fan --- drivers/mmc/sdhci-cadence.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/mmc/sdhci-cadence.c b/drivers/mmc/sdhci-cadence.c index 6c9d24fe5f7..b92b3df3ed9 100644 --- a/drivers/mmc/sdhci-cadence.c +++ b/drivers/mmc/sdhci-cadence.c @@ -253,7 +253,7 @@ static int sdhci_cdns_probe(struct udevice *dev) host->mmc = &plat->mmc; host->mmc->dev = dev; - ret = sdhci_setup_cfg(&plat->cfg, host, 0, 0); + ret = sdhci_setup_cfg(&plat->cfg, host, plat->cfg.f_max, 0); if (ret) return ret; From fa7e82127fad8b5926b383ec20e06af75a15bd3a Mon Sep 17 00:00:00 2001 From: Tanmay Kathpalia Date: Wed, 3 Dec 2025 04:21:34 -0800 Subject: [PATCH 4/9] mmc: sdhci-cadence: Set controller and PHY speed modes for SD and eMMC cards Replace the legacy clock frequency-based timing mode selection with proper MMC timing mode constants. Changes to sdhci-cadence.c: - Add sdhci_cdns_get_hrs06_mode() helper function for mode selection - Replace clock frequency logic with mmc->selected_mode switch statement - Use proper MMC timing constants (MMC_HS, UHS_SDR104, etc.) - Add SD card specific handling with standard SDHCI control register setup Changes to sdhci-cadence6.c: - Add SD high speed PHY and control configuration arrays - Update sdhci_cdns6_phy_adj() to use timing modes instead of HRS06 modes - Support both SD and eMMC timing modes with appropriate PHY settings Signed-off-by: Tanmay Kathpalia Reviewed-by: Balsundar Ponnusamy Reviewed-by: Peng Fan Signed-off-by: Peng Fan --- drivers/mmc/sdhci-cadence.c | 72 +++++++++++++++++++++++++++--------- drivers/mmc/sdhci-cadence6.c | 39 ++++++++++++++++--- 2 files changed, 87 insertions(+), 24 deletions(-) diff --git a/drivers/mmc/sdhci-cadence.c b/drivers/mmc/sdhci-cadence.c index b92b3df3ed9..5e2a4037605 100644 --- a/drivers/mmc/sdhci-cadence.c +++ b/drivers/mmc/sdhci-cadence.c @@ -2,6 +2,7 @@ /* * Copyright (C) 2016 Socionext Inc. * Author: Masahiro Yamada + * Copyright (C) 2025 Altera Corporation */ #include @@ -84,39 +85,74 @@ static int sdhci_cdns_phy_init(struct sdhci_cdns_plat *plat, return 0; } +static unsigned int sdhci_cdns_get_hrs06_mode(struct mmc *mmc) +{ + unsigned int mode; + + if (IS_SD(mmc)) { + mode = SDHCI_CDNS_HRS06_MODE_SD; + } else { + switch (mmc->selected_mode) { + case MMC_LEGACY: + mode = SDHCI_CDNS_HRS06_MODE_SD; /* use this for Legacy */ + break; + + case MMC_HS: + case MMC_HS_52: + mode = SDHCI_CDNS_HRS06_MODE_MMC_SDR; + break; + + case UHS_DDR50: + case MMC_DDR_52: + mode = SDHCI_CDNS_HRS06_MODE_MMC_DDR; + break; + + case UHS_SDR104: + case MMC_HS_200: + mode = SDHCI_CDNS_HRS06_MODE_MMC_HS200; + break; + + case MMC_HS_400: + case MMC_HS_400_ES: + mode = SDHCI_CDNS_HRS06_MODE_MMC_HS400; + break; + + default: + mode = SDHCI_CDNS_HRS06_MODE_SD; + break; + } + } + return mode; +} + static void sdhci_cdns_set_control_reg(struct sdhci_host *host) { struct mmc *mmc = host->mmc; struct sdhci_cdns_plat *plat = dev_get_plat(mmc->dev); - unsigned int clock = mmc->clock; u32 mode, tmp; /* - * REVISIT: - * The mode should be decided by MMC_TIMING_* like Linux, but - * U-Boot does not support timing. Use the clock frequency instead. + * Select HRS06 mode based on card type and selected timing mode. + * For SD cards, always use SD mode (000b) as per Cadence user guide, + * section 12.7 (HRS06), Part Number: IP6061. + * For eMMC, use selected_mode to pick the appropriate mode. */ - if (clock <= 26000000) { - mode = SDHCI_CDNS_HRS06_MODE_SD; /* use this for Legacy */ - } else if (clock <= 52000000) { - if (mmc->ddr_mode) - mode = SDHCI_CDNS_HRS06_MODE_MMC_DDR; - else - mode = SDHCI_CDNS_HRS06_MODE_MMC_SDR; - } else { - if (mmc->ddr_mode) - mode = SDHCI_CDNS_HRS06_MODE_MMC_HS400; - else - mode = SDHCI_CDNS_HRS06_MODE_MMC_HS200; - } + mode = sdhci_cdns_get_hrs06_mode(mmc); tmp = readl(plat->hrs_addr + SDHCI_CDNS_HRS06); tmp &= ~SDHCI_CDNS_HRS06_MODE; tmp |= FIELD_PREP(SDHCI_CDNS_HRS06_MODE, mode); writel(tmp, plat->hrs_addr + SDHCI_CDNS_HRS06); + /* + * For SD cards, program standard SDHCI Host Control2 UHS/voltage + * registers for UHS-I support. + */ + if (IS_SD(mmc)) + sdhci_set_control_reg(host); + if (device_is_compatible(mmc->dev, "cdns,sd6hc")) - sdhci_cdns6_phy_adj(mmc->dev, plat, mode); + sdhci_cdns6_phy_adj(mmc->dev, plat, mmc->selected_mode); } static const struct sdhci_ops sdhci_cdns_ops = { diff --git a/drivers/mmc/sdhci-cadence6.c b/drivers/mmc/sdhci-cadence6.c index ead96dc0c91..d4e2cb1c83e 100644 --- a/drivers/mmc/sdhci-cadence6.c +++ b/drivers/mmc/sdhci-cadence6.c @@ -2,6 +2,7 @@ /* * Copyright (C) 2023 Starfive. * Author: Kuan Lim Lee + * Copyright (C) 2025 Altera Corporation */ #include @@ -77,6 +78,13 @@ static struct sdhci_cdns6_phy_cfg sd_ds_phy_cfgs[] = { { "cdns,phy-dq-timing-delay-sd-ds", 0x00000001, }, }; +static struct sdhci_cdns6_phy_cfg sd_hs_phy_cfgs[] = { + { "cdns,phy-dqs-timing-delay-sd-hs", 0x00380004, }, + { "cdns,phy-gate-lpbk_ctrl-delay-sd-hs", 0x01A00040, }, + { "cdns,phy-dll-slave-ctrl-sd-hs", 0x00000000, }, + { "cdns,phy-dq-timing-delay-sd-hs", 0x00000001, }, +}; + static struct sdhci_cdns6_phy_cfg emmc_sdr_phy_cfgs[] = { { "cdns,phy-dqs-timing-delay-semmc-sdr", 0x00380004, }, { "cdns,phy-gate-lpbk_ctrl-delay-emmc-sdr", 0x01A00040, }, @@ -112,6 +120,13 @@ static struct sdhci_cdns6_ctrl_cfg sd_ds_ctrl_cfgs[] = { { "cdns,ctrl-hrs07-timing-delay-sd-ds", 0x00080000, }, }; +static struct sdhci_cdns6_ctrl_cfg sd_hs_ctrl_cfgs[] = { + { "cdns,ctrl-hrs09-timing-delay-sd-hs", 0x0001800C, }, + { "cdns,ctrl-hrs10-lpbk_ctrl-delay-sd-hs", 0x00030000, }, + { "cdns,ctrl-hrs16-slave-ctrl-sd-hs", 0x00000000, }, + { "cdns,ctrl-hrs07-timing-delay-sd-hs", 0x00080000, }, +}; + static struct sdhci_cdns6_ctrl_cfg emmc_sdr_ctrl_cfgs[] = { { "cdns,ctrl-hrs09-timing-delay-emmc-sdr", 0x0001800C, }, { "cdns,ctrl-hrs10-lpbk_ctrl-delay-emmc-sdr", 0x00030000, }, @@ -186,27 +201,39 @@ int sdhci_cdns6_phy_adj(struct udevice *dev, struct sdhci_cdns_plat *plat, u32 m int i, ret; switch (mode) { - case SDHCI_CDNS_HRS06_MODE_SD: + case UHS_SDR12: + case MMC_LEGACY: sdhci_cdns6_phy_cfgs = sd_ds_phy_cfgs; sdhci_cdns6_ctrl_cfgs = sd_ds_ctrl_cfgs; break; - case SDHCI_CDNS_HRS06_MODE_MMC_SDR: + case SD_HS: + case UHS_SDR25: + case MMC_HS: + sdhci_cdns6_phy_cfgs = sd_hs_phy_cfgs; + sdhci_cdns6_ctrl_cfgs = sd_hs_ctrl_cfgs; + break; + + case UHS_SDR50: + case MMC_HS_52: sdhci_cdns6_phy_cfgs = emmc_sdr_phy_cfgs; sdhci_cdns6_ctrl_cfgs = emmc_sdr_ctrl_cfgs; break; - case SDHCI_CDNS_HRS06_MODE_MMC_DDR: + case UHS_DDR50: + case MMC_DDR_52: sdhci_cdns6_phy_cfgs = emmc_ddr_phy_cfgs; sdhci_cdns6_ctrl_cfgs = emmc_ddr_ctrl_cfgs; break; - case SDHCI_CDNS_HRS06_MODE_MMC_HS200: + case UHS_SDR104: + case MMC_HS_200: sdhci_cdns6_phy_cfgs = emmc_hs200_phy_cfgs; sdhci_cdns6_ctrl_cfgs = emmc_hs200_ctrl_cfgs; break; - case SDHCI_CDNS_HRS06_MODE_MMC_HS400: + case MMC_HS_400: + case MMC_HS_400_ES: sdhci_cdns6_phy_cfgs = emmc_hs400_phy_cfgs; sdhci_cdns6_ctrl_cfgs = emmc_hs400_ctrl_cfgs; break; @@ -263,7 +290,7 @@ int sdhci_cdns6_phy_adj(struct udevice *dev, struct sdhci_cdns_plat *plat, u32 m int sdhci_cdns6_phy_init(struct udevice *dev, struct sdhci_cdns_plat *plat) { - return sdhci_cdns6_phy_adj(dev, plat, SDHCI_CDNS_HRS06_MODE_SD); + return sdhci_cdns6_phy_adj(dev, plat, MMC_LEGACY); } int sdhci_cdns6_set_tune_val(struct sdhci_cdns_plat *plat, unsigned int val) From 90f43c7edc61634400c808110081f97e42b63bc6 Mon Sep 17 00:00:00 2001 From: Tanmay Kathpalia Date: Wed, 3 Dec 2025 04:21:35 -0800 Subject: [PATCH 5/9] mmc: sdhci: Add SDHCI_SPEC_400, _410, and _420 version defines Add SDHCI_SPEC_400, SDHCI_SPEC_410, and SDHCI_SPEC_420 macros to sdhci.h to support newer SDHCI specification versions. These defines are required for compatibility with controllers implementing SDHCI 4.0 and above. Reference: https://lore.kernel.org/all/1535617305-16952-2-git-send-email-zhang.chunyan@linaro.org/ Signed-off-by: Tanmay Kathpalia Reviewed-by: Balsundar Ponnusamy Reviewed-by: Peng Fan Signed-off-by: Peng Fan --- include/sdhci.h | 3 +++ 1 file changed, 3 insertions(+) diff --git a/include/sdhci.h b/include/sdhci.h index d9c0597a0c1..fb847821d58 100644 --- a/include/sdhci.h +++ b/include/sdhci.h @@ -223,6 +223,9 @@ #define SDHCI_SPEC_100 0 #define SDHCI_SPEC_200 1 #define SDHCI_SPEC_300 2 +#define SDHCI_SPEC_400 3 +#define SDHCI_SPEC_410 4 +#define SDHCI_SPEC_420 5 #define SDHCI_GET_VERSION(x) (x->version & SDHCI_SPEC_VER_MASK) From 7d52b66b9b8e00815ef968c4ad0f2f704228fb69 Mon Sep 17 00:00:00 2001 From: Tanmay Kathpalia Date: Wed, 3 Dec 2025 04:21:36 -0800 Subject: [PATCH 6/9] mmc: sdhci-cadence: Use hardware version field for Cadence SDHCI controller Replace device tree compatible string checks with hardware version field detection to determine SDHCI controller capabilities. This approach is more robust and aligns with standard SDHCI specification practices. Controllers with SDHCI version 4.2 and above will automatically use the enhanced PHY adjustment, and tuning v6-specific procedures. Signed-off-by: Tanmay Kathpalia Reviewed-by: Balsundar Ponnusamy Acked-by: Peng Fan Signed-off-by: Peng Fan --- drivers/mmc/sdhci-cadence.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/drivers/mmc/sdhci-cadence.c b/drivers/mmc/sdhci-cadence.c index 5e2a4037605..a0b9434e4f0 100644 --- a/drivers/mmc/sdhci-cadence.c +++ b/drivers/mmc/sdhci-cadence.c @@ -151,7 +151,7 @@ static void sdhci_cdns_set_control_reg(struct sdhci_host *host) if (IS_SD(mmc)) sdhci_set_control_reg(host); - if (device_is_compatible(mmc->dev, "cdns,sd6hc")) + if (SDHCI_GET_VERSION(host) >= SDHCI_SPEC_420) sdhci_cdns6_phy_adj(mmc->dev, plat, mmc->selected_mode); } @@ -162,11 +162,13 @@ static const struct sdhci_ops sdhci_cdns_ops = { static int sdhci_cdns_set_tune_val(struct sdhci_cdns_plat *plat, unsigned int val) { + struct mmc *mmc = &plat->mmc; + struct sdhci_host *host = dev_get_priv(mmc->dev); void __iomem *reg = plat->hrs_addr + SDHCI_CDNS_HRS06; u32 tmp; int i, ret; - if (device_is_compatible(plat->mmc.dev, "cdns,sd6hc")) + if (SDHCI_GET_VERSION(host) >= SDHCI_SPEC_420) return sdhci_cdns6_set_tune_val(plat, val); if (WARN_ON(!FIELD_FIT(SDHCI_CDNS_HRS06_TUNE, val))) From 3dafdeface93a68c78f0921ea3d9237c7c622fdc Mon Sep 17 00:00:00 2001 From: Tanmay Kathpalia Date: Wed, 3 Dec 2025 04:21:37 -0800 Subject: [PATCH 7/9] mmc: sdhci-cadence: Enable software tuning for both SD and eMMC interfaces Remove interface type restrictions in sdhci_cdns_execute_tuning() to enable software tuning for both SD and eMMC devices. The previous assumption that SD timing should be handled by SDHCI core is incorrect based on the actual function assignment logic. The execute_tuning function is assigned based on MMC_SUPPORTS_TUNING config, which is enabled by both MMC_UHS_SUPPORT and MMC_HS200_SUPPORT. Changes: Remove IS_MMC() check that restricted tuning to eMMC only Remove opcode validation limited to MMC_CMD_SEND_TUNING_BLOCK_HS200 Signed-off-by: Tanmay Kathpalia Reviewed-by: Balsundar Ponnusamy Reviewed-by: Peng Fan Signed-off-by: Peng Fan --- drivers/mmc/sdhci-cadence.c | 12 +++--------- 1 file changed, 3 insertions(+), 9 deletions(-) diff --git a/drivers/mmc/sdhci-cadence.c b/drivers/mmc/sdhci-cadence.c index a0b9434e4f0..c7f88977ef9 100644 --- a/drivers/mmc/sdhci-cadence.c +++ b/drivers/mmc/sdhci-cadence.c @@ -207,16 +207,10 @@ static int __maybe_unused sdhci_cdns_execute_tuning(struct udevice *dev, int i; /* - * This handler only implements the eMMC tuning that is specific to - * this controller. The tuning for SD timing should be handled by the - * SDHCI core. + * This function performs the tuning process for both SD and eMMC + * interfaces. It sweeps through all available tuning points, + * sending tuning commands at each step. */ - if (!IS_MMC(mmc)) - return -ENOTSUPP; - - if (WARN_ON(opcode != MMC_CMD_SEND_TUNING_BLOCK_HS200)) - return -EINVAL; - for (i = 0; i < SDHCI_CDNS_MAX_TUNING_LOOP; i++) { if (sdhci_cdns_set_tune_val(plat, i) || mmc_send_tuning(mmc, opcode)) { /* bad */ From 7c2ba8a2024101463ec03b8003e6c0146f2db893 Mon Sep 17 00:00:00 2001 From: Tanmay Kathpalia Date: Wed, 3 Dec 2025 04:21:38 -0800 Subject: [PATCH 8/9] mmc: sdhci-cadence6: socfpga: Fix DT property naming convention MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 1. Replace underscores with hyphens in device tree property names to follow the standard DT naming convention. This affects all "lpbk_ctrl" properties which are now correctly named "lpbk-ctrl". Changes: - cdns,phy-gate-lpbk_ctrl-delay-* → cdns,phy-gate-lpbk-ctrl-delay-* - cdns,ctrl-hrs10-lpbk_ctrl-delay-* → cdns,ctrl-hrs10-lpbk-ctrl-delay-* 2. Fix typo: semmc → emmc in eMMC SDR PHY property name Signed-off-by: Tanmay Kathpalia Reviewed-by: Balsundar Ponnusamy Acked-by: Peng Fan Signed-off-by: Peng Fan --- drivers/mmc/sdhci-cadence6.c | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/drivers/mmc/sdhci-cadence6.c b/drivers/mmc/sdhci-cadence6.c index d4e2cb1c83e..d9467293807 100644 --- a/drivers/mmc/sdhci-cadence6.c +++ b/drivers/mmc/sdhci-cadence6.c @@ -73,84 +73,84 @@ struct sdhci_cdns6_ctrl_cfg { static struct sdhci_cdns6_phy_cfg sd_ds_phy_cfgs[] = { { "cdns,phy-dqs-timing-delay-sd-ds", 0x00380004, }, - { "cdns,phy-gate-lpbk_ctrl-delay-sd-ds", 0x01A00040, }, + { "cdns,phy-gate-lpbk-ctrl-delay-sd-ds", 0x01A00040, }, { "cdns,phy-dll-slave-ctrl-sd-ds", 0x00000000, }, { "cdns,phy-dq-timing-delay-sd-ds", 0x00000001, }, }; static struct sdhci_cdns6_phy_cfg sd_hs_phy_cfgs[] = { { "cdns,phy-dqs-timing-delay-sd-hs", 0x00380004, }, - { "cdns,phy-gate-lpbk_ctrl-delay-sd-hs", 0x01A00040, }, + { "cdns,phy-gate-lpbk-ctrl-delay-sd-hs", 0x01A00040, }, { "cdns,phy-dll-slave-ctrl-sd-hs", 0x00000000, }, { "cdns,phy-dq-timing-delay-sd-hs", 0x00000001, }, }; static struct sdhci_cdns6_phy_cfg emmc_sdr_phy_cfgs[] = { - { "cdns,phy-dqs-timing-delay-semmc-sdr", 0x00380004, }, - { "cdns,phy-gate-lpbk_ctrl-delay-emmc-sdr", 0x01A00040, }, + { "cdns,phy-dqs-timing-delay-emmc-sdr", 0x00380004, }, + { "cdns,phy-gate-lpbk-ctrl-delay-emmc-sdr", 0x01A00040, }, { "cdns,phy-dll-slave-ctrl-emmc-sdr", 0x00000000, }, { "cdns,phy-dq-timing-delay-emmc-sdr", 0x00000001, }, }; static struct sdhci_cdns6_phy_cfg emmc_ddr_phy_cfgs[] = { { "cdns,phy-dqs-timing-delay-emmc-ddr", 0x00380004, }, - { "cdns,phy-gate-lpbk_ctrl-delay-emmc-ddr", 0x01A00040, }, + { "cdns,phy-gate-lpbk-ctrl-delay-emmc-ddr", 0x01A00040, }, { "cdns,phy-dll-slave-ctrl-emmc-ddr", 0x00000000, }, { "cdns,phy-dq-timing-delay-emmc-ddr", 0x10000001, }, }; static struct sdhci_cdns6_phy_cfg emmc_hs200_phy_cfgs[] = { { "cdns,phy-dqs-timing-delay-emmc-hs200", 0x00380004, }, - { "cdns,phy-gate-lpbk_ctrl-delay-emmc-hs200", 0x01A00040, }, + { "cdns,phy-gate-lpbk-ctrl-delay-emmc-hs200", 0x01A00040, }, { "cdns,phy-dll-slave-ctrl-emmc-hs200", 0x00DADA00, }, { "cdns,phy-dq-timing-delay-emmc-hs200", 0x00000001, }, }; static struct sdhci_cdns6_phy_cfg emmc_hs400_phy_cfgs[] = { { "cdns,phy-dqs-timing-delay-emmc-hs400", 0x00280004, }, - { "cdns,phy-gate-lpbk_ctrl-delay-emmc-hs400", 0x01A00040, }, + { "cdns,phy-gate-lpbk-ctrl-delay-emmc-hs400", 0x01A00040, }, { "cdns,phy-dll-slave-ctrl-emmc-hs400", 0x00DAD800, }, { "cdns,phy-dq-timing-delay-emmc-hs400", 0x00000001, }, }; static struct sdhci_cdns6_ctrl_cfg sd_ds_ctrl_cfgs[] = { { "cdns,ctrl-hrs09-timing-delay-sd-ds", 0x0001800C, }, - { "cdns,ctrl-hrs10-lpbk_ctrl-delay-sd-ds", 0x00020000, }, + { "cdns,ctrl-hrs10-lpbk-ctrl-delay-sd-ds", 0x00020000, }, { "cdns,ctrl-hrs16-slave-ctrl-sd-ds", 0x00000000, }, { "cdns,ctrl-hrs07-timing-delay-sd-ds", 0x00080000, }, }; static struct sdhci_cdns6_ctrl_cfg sd_hs_ctrl_cfgs[] = { { "cdns,ctrl-hrs09-timing-delay-sd-hs", 0x0001800C, }, - { "cdns,ctrl-hrs10-lpbk_ctrl-delay-sd-hs", 0x00030000, }, + { "cdns,ctrl-hrs10-lpbk-ctrl-delay-sd-hs", 0x00030000, }, { "cdns,ctrl-hrs16-slave-ctrl-sd-hs", 0x00000000, }, { "cdns,ctrl-hrs07-timing-delay-sd-hs", 0x00080000, }, }; static struct sdhci_cdns6_ctrl_cfg emmc_sdr_ctrl_cfgs[] = { { "cdns,ctrl-hrs09-timing-delay-emmc-sdr", 0x0001800C, }, - { "cdns,ctrl-hrs10-lpbk_ctrl-delay-emmc-sdr", 0x00030000, }, + { "cdns,ctrl-hrs10-lpbk-ctrl-delay-emmc-sdr", 0x00030000, }, { "cdns,ctrl-hrs16-slave-ctrl-emmc-sdr", 0x00000000, }, { "cdns,ctrl-hrs07-timing-delay-emmc-sdr", 0x00080000, }, }; static struct sdhci_cdns6_ctrl_cfg emmc_ddr_ctrl_cfgs[] = { { "cdns,ctrl-hrs09-timing-delay-emmc-ddr", 0x0001800C, }, - { "cdns,ctrl-hrs10-lpbk_ctrl-delay-emmc-ddr", 0x00020000, }, + { "cdns,ctrl-hrs10-lpbk-ctrl-delay-emmc-ddr", 0x00020000, }, { "cdns,ctrl-hrs16-slave-ctrl-emmc-ddr", 0x11000001, }, { "cdns,ctrl-hrs07-timing-delay-emmc-ddr", 0x00090001, }, }; static struct sdhci_cdns6_ctrl_cfg emmc_hs200_ctrl_cfgs[] = { { "cdns,ctrl-hrs09-timing-delay-emmc-hs200", 0x00018000, }, - { "cdns,ctrl-hrs10-lpbk_ctrl-delay-emmc-hs200", 0x00080000, }, + { "cdns,ctrl-hrs10-lpbk-ctrl-delay-emmc-hs200", 0x00080000, }, { "cdns,ctrl-hrs16-slave-ctrl-emmc-hs200", 0x00000000, }, { "cdns,ctrl-hrs07-timing-delay-emmc-hs200", 0x00090000, }, }; static struct sdhci_cdns6_ctrl_cfg emmc_hs400_ctrl_cfgs[] = { { "cdns,ctrl-hrs09-timing-delay-emmc-hs400", 0x00018000, }, - { "cdns,ctrl-hrs10-lpbk_ctrl-delay-emmc-hs400", 0x00080000, }, + { "cdns,ctrl-hrs10-lpbk-ctrl-delay-emmc-hs400", 0x00080000, }, { "cdns,ctrl-hrs16-slave-ctrl-emmc-hs400", 0x11000000, }, { "cdns,ctrl-hrs07-timing-delay-emmc-hs400", 0x00080000, }, }; From ed0e33cec099e3f9e459cef7f66ff91068e2d71c Mon Sep 17 00:00:00 2001 From: Tanmay Kathpalia Date: Wed, 3 Dec 2025 04:21:39 -0800 Subject: [PATCH 9/9] mmc: sdhci-cadence6: Add DLL master control and improve tuning reliability - Add support for configuring the PHY DLL master control register for all SD/eMMC timing modes (DS, HS, SDR, DDR, HS200, HS400) by extending the PHY configuration arrays and writing the value during PHY adjustment. - Fix tuning reliability by toggling the DLL reset before and after updating the PHY_DLL_SLAVE_CTRL_REG_ADDR register. Signed-off-by: Tanmay Kathpalia Reviewed-by: Balsundar Ponnusamy Acked-by: Peng Fan Signed-off-by: Peng Fan --- drivers/mmc/sdhci-cadence6.c | 21 ++++++++++++++++++++- 1 file changed, 20 insertions(+), 1 deletion(-) diff --git a/drivers/mmc/sdhci-cadence6.c b/drivers/mmc/sdhci-cadence6.c index d9467293807..91a245aa490 100644 --- a/drivers/mmc/sdhci-cadence6.c +++ b/drivers/mmc/sdhci-cadence6.c @@ -58,7 +58,7 @@ #define PHY_DLL_SLAVE_CTRL_REG_READ_DQS_CMD_DELAY GENMASK(31, 24) #define PHY_DLL_SLAVE_CTRL_REG_READ_DQS_DELAY GENMASK(7, 0) -#define SDHCI_CDNS6_PHY_CFG_NUM 4 +#define SDHCI_CDNS6_PHY_CFG_NUM 5 #define SDHCI_CDNS6_CTRL_CFG_NUM 4 struct sdhci_cdns6_phy_cfg { @@ -76,6 +76,7 @@ static struct sdhci_cdns6_phy_cfg sd_ds_phy_cfgs[] = { { "cdns,phy-gate-lpbk-ctrl-delay-sd-ds", 0x01A00040, }, { "cdns,phy-dll-slave-ctrl-sd-ds", 0x00000000, }, { "cdns,phy-dq-timing-delay-sd-ds", 0x00000001, }, + { "cdns,phy-dll-master-ctrl-sd-ds", 0x00800004, }, }; static struct sdhci_cdns6_phy_cfg sd_hs_phy_cfgs[] = { @@ -83,6 +84,7 @@ static struct sdhci_cdns6_phy_cfg sd_hs_phy_cfgs[] = { { "cdns,phy-gate-lpbk-ctrl-delay-sd-hs", 0x01A00040, }, { "cdns,phy-dll-slave-ctrl-sd-hs", 0x00000000, }, { "cdns,phy-dq-timing-delay-sd-hs", 0x00000001, }, + { "cdns,phy-dll-master-ctrl-sd-hs", 0x00800004, }, }; static struct sdhci_cdns6_phy_cfg emmc_sdr_phy_cfgs[] = { @@ -90,6 +92,7 @@ static struct sdhci_cdns6_phy_cfg emmc_sdr_phy_cfgs[] = { { "cdns,phy-gate-lpbk-ctrl-delay-emmc-sdr", 0x01A00040, }, { "cdns,phy-dll-slave-ctrl-emmc-sdr", 0x00000000, }, { "cdns,phy-dq-timing-delay-emmc-sdr", 0x00000001, }, + { "cdns,phy-dll-master-ctrl-emmc-sdr", 0x00800004, }, }; static struct sdhci_cdns6_phy_cfg emmc_ddr_phy_cfgs[] = { @@ -97,6 +100,7 @@ static struct sdhci_cdns6_phy_cfg emmc_ddr_phy_cfgs[] = { { "cdns,phy-gate-lpbk-ctrl-delay-emmc-ddr", 0x01A00040, }, { "cdns,phy-dll-slave-ctrl-emmc-ddr", 0x00000000, }, { "cdns,phy-dq-timing-delay-emmc-ddr", 0x10000001, }, + { "cdns,phy-dll-master-ctrl-emmc-ddr", 0x00800004, }, }; static struct sdhci_cdns6_phy_cfg emmc_hs200_phy_cfgs[] = { @@ -104,6 +108,7 @@ static struct sdhci_cdns6_phy_cfg emmc_hs200_phy_cfgs[] = { { "cdns,phy-gate-lpbk-ctrl-delay-emmc-hs200", 0x01A00040, }, { "cdns,phy-dll-slave-ctrl-emmc-hs200", 0x00DADA00, }, { "cdns,phy-dq-timing-delay-emmc-hs200", 0x00000001, }, + { "cdns,phy-dll-master-ctrl-emmc-hs200", 0x00000004, }, }; static struct sdhci_cdns6_phy_cfg emmc_hs400_phy_cfgs[] = { @@ -111,6 +116,7 @@ static struct sdhci_cdns6_phy_cfg emmc_hs400_phy_cfgs[] = { { "cdns,phy-gate-lpbk-ctrl-delay-emmc-hs400", 0x01A00040, }, { "cdns,phy-dll-slave-ctrl-emmc-hs400", 0x00DAD800, }, { "cdns,phy-dq-timing-delay-emmc-hs400", 0x00000001, }, + { "cdns,phy-dll-master-ctrl-emmc-hs400", 0x00000004, }, }; static struct sdhci_cdns6_ctrl_cfg sd_ds_ctrl_cfgs[] = { @@ -252,6 +258,7 @@ int sdhci_cdns6_phy_adj(struct udevice *dev, struct sdhci_cdns_plat *plat, u32 m sdhci_cdns6_write_phy_reg(plat, PHY_DQS_TIMING_REG_ADDR, sdhci_cdns6_phy_cfgs[0].val); sdhci_cdns6_write_phy_reg(plat, PHY_GATE_LPBK_CTRL_REG_ADDR, sdhci_cdns6_phy_cfgs[1].val); + sdhci_cdns6_write_phy_reg(plat, PHY_DLL_MASTER_CTRL_REG_ADDR, sdhci_cdns6_phy_cfgs[4].val); sdhci_cdns6_write_phy_reg(plat, PHY_DLL_SLAVE_CTRL_REG_ADDR, sdhci_cdns6_phy_cfgs[2].val); /* Switch Off the DLL Reset */ @@ -296,6 +303,7 @@ int sdhci_cdns6_phy_init(struct udevice *dev, struct sdhci_cdns_plat *plat) int sdhci_cdns6_set_tune_val(struct sdhci_cdns_plat *plat, unsigned int val) { u32 tmp, tuneval; + int ret; tuneval = (val * 256) / SDHCI_CDNS_MAX_TUNING_LOOP; @@ -304,7 +312,18 @@ int sdhci_cdns6_set_tune_val(struct sdhci_cdns_plat *plat, unsigned int val) PHY_DLL_SLAVE_CTRL_REG_READ_DQS_DELAY); tmp |= FIELD_PREP(PHY_DLL_SLAVE_CTRL_REG_READ_DQS_CMD_DELAY, tuneval) | FIELD_PREP(PHY_DLL_SLAVE_CTRL_REG_READ_DQS_DELAY, tuneval); + + /* Switch On the DLL Reset */ + sdhci_cdns6_reset_phy_dll(plat, true); + sdhci_cdns6_write_phy_reg(plat, PHY_DLL_SLAVE_CTRL_REG_ADDR, tmp); + /* Switch Off the DLL Reset */ + ret = sdhci_cdns6_reset_phy_dll(plat, false); + if (ret) { + printf("sdhci_cdns6_reset_phy is not completed\n"); + return ret; + } + return 0; }