From: Tanmay Kathpalia Date: Wed, 3 Dec 2025 12:21:34 +0000 (-0800) Subject: mmc: sdhci-cadence: Set controller and PHY speed modes for SD and eMMC cards X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=fa7e82127fad8b5926b383ec20e06af75a15bd3a;p=thirdparty%2Fu-boot.git 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 --- 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)