* [PATCH 1/3] mmc: msm_sdhci: Fix incorrect divider calculation for SDCLK
@ 2025-12-10 15:54 Loic Poulain
2025-12-10 15:54 ` [PATCH 2/3] clk/qcom: qcm2290: Add SDCC1 apps clock frequency table Loic Poulain
` (3 more replies)
0 siblings, 4 replies; 6+ messages in thread
From: Loic Poulain @ 2025-12-10 15:54 UTC (permalink / raw)
To: lukma, casey.connolly, neil.armstrong
Cc: sumit.garg, trini, peng.fan, jh80.chung, u-boot-qcom, u-boot,
Loic Poulain
When 'max-clk' is not specified, the SDHCI core retrieves the base clock
from the SDHCI_CAPABILITIES register (bits [15:8]). However, this field
is unreliable on MSM SDHCI controllers, as noted by the Linux driver
using the SDHCI_QUIRK_CAP_CLOCK_BASE_BROKEN flag. In addition, the field
is only 8 bits wide and cannot represent base clocks above 255 MHz.
On platforms like Agatti/QCM2290, the firmware sets the SDHCI clock to
384 MHz, but the capabilities register reports 200 MHz. As a result,
the core calculates a divider of 4, producing a 96 MHz SDCLK instead of
the intended ~52 MHz. This overclocking can cause sporadic CRC errors
with certain eMMC.
To fix this, use the actual clock rate reported by the SDHCI core clock
instead of relying on the capabilities register for divider calculation.
Signed-off-by: Loic Poulain <loic.poulain@oss.qualcomm.com>
---
drivers/mmc/msm_sdhci.c | 3 +++
1 file changed, 3 insertions(+)
diff --git a/drivers/mmc/msm_sdhci.c b/drivers/mmc/msm_sdhci.c
index ac77fb06bf7..ec003991928 100644
--- a/drivers/mmc/msm_sdhci.c
+++ b/drivers/mmc/msm_sdhci.c
@@ -114,6 +114,9 @@ static int msm_sdc_clk_init(struct udevice *dev)
return -EINVAL;
}
+ /* This is the base clock sdhci core will use to configure the SDCLK */
+ prv->host.max_clk = clk_rate;
+
writel_relaxed(CORE_VENDOR_SPEC_POR_VAL,
prv->host.ioaddr + var_info->core_vendor_spec);
--
2.34.1
^ permalink raw reply related [flat|nested] 6+ messages in thread* [PATCH 2/3] clk/qcom: qcm2290: Add SDCC1 apps clock frequency table 2025-12-10 15:54 [PATCH 1/3] mmc: msm_sdhci: Fix incorrect divider calculation for SDCLK Loic Poulain @ 2025-12-10 15:54 ` Loic Poulain 2025-12-12 1:00 ` Sumit Garg 2025-12-10 15:54 ` [PATCH 3/3] mmc: msm_sdhci: Add DLL control hook to disable DLL below 100 MHz Loic Poulain ` (2 subsequent siblings) 3 siblings, 1 reply; 6+ messages in thread From: Loic Poulain @ 2025-12-10 15:54 UTC (permalink / raw) To: lukma, casey.connolly, neil.armstrong Cc: sumit.garg, trini, peng.fan, jh80.chung, u-boot-qcom, u-boot, Loic Poulain, Sumit Garg Add support for configuring the SDCC1 apps clock on QCM2290 by introducing a frequency table and enabling dynamic rate setting. Previously, the clock was assumed to be fixed at 384 MHz by firmware, which limited flexibility and correctness when selecting optimal rates for SD/MMC operations. Suggested-by: Sumit Garg <sumit.garg@oss.qualcomm.com> Signed-off-by: Loic Poulain <loic.poulain@oss.qualcomm.com> --- drivers/clk/qcom/clock-qcm2290.c | 29 +++++++++++++++++++++++++++-- 1 file changed, 27 insertions(+), 2 deletions(-) diff --git a/drivers/clk/qcom/clock-qcm2290.c b/drivers/clk/qcom/clock-qcm2290.c index fad104fb91a..5a599085b50 100644 --- a/drivers/clk/qcom/clock-qcm2290.c +++ b/drivers/clk/qcom/clock-qcm2290.c @@ -17,6 +17,8 @@ #define QUPV3_WRAP0_S4_CMD_RCGR 0x1f608 #define SDCC2_APPS_CLK_CMD_RCGR 0x1e00c +#define SDCC1_APPS_CLK_CMD_RCGR 0x38028 + static const struct freq_tbl ftbl_gcc_qupv3_wrap0_s0_clk_src[] = { F(7372800, CFG_CLK_SRC_GPLL0_AUX2, 1, 384, 15625), @@ -55,6 +57,25 @@ static const struct pll_vote_clk gpll7_clk = { .vote_bit = BIT(7), }; +static const struct freq_tbl ftbl_gcc_sdcc1_apps_clk_src[] = { + F(144000, CFG_CLK_SRC_CXO, 16, 3, 25), + F(400000, CFG_CLK_SRC_CXO, 12, 1, 4), + F(20000000, CFG_CLK_SRC_GPLL0_AUX2, 5, 1, 3), + F(25000000, CFG_CLK_SRC_GPLL0_AUX2, 6, 1, 2), + F(50000000, CFG_CLK_SRC_GPLL0_AUX2, 6, 0, 0), + F(100000000, CFG_CLK_SRC_GPLL0_AUX2, 3, 0, 0), + F(192000000, CFG_CLK_SRC_GPLL6, 2, 0, 0), + F(384000000, CFG_CLK_SRC_GPLL6, 1, 0, 0), + {} +}; + +static const struct pll_vote_clk gpll6_clk = { + .status = 0x6000, + .status_bit = BIT(31), + .ena_vote = 0x79000, + .vote_bit = BIT(7), +}; + static const struct gate_clk qcm2290_clks[] = { GATE_CLK(GCC_AHB2PHY_USB_CLK, 0x1d008, 0x00000001), GATE_CLK(GCC_CFG_NOC_USB3_PRIM_AXI_CLK, 0x1a084, 0x00000001), @@ -109,8 +130,12 @@ static ulong qcm2290_set_rate(struct clk *clk, ulong rate) 8); return freq->freq; case GCC_SDCC1_APPS_CLK: - /* The firmware turns this on for us and always sets it to this rate */ - return 384000000; + clk_enable_gpll0(priv->base, &gpll6_clk); + freq = qcom_find_freq(ftbl_gcc_sdcc1_apps_clk_src, rate); + clk_rcg_set_rate_mnd(priv->base, SDCC1_APPS_CLK_CMD_RCGR, + freq->pre_div, freq->m, freq->n, freq->src, + 8); + return freq->freq; default: return 0; } -- 2.34.1 ^ permalink raw reply related [flat|nested] 6+ messages in thread
* Re: [PATCH 2/3] clk/qcom: qcm2290: Add SDCC1 apps clock frequency table 2025-12-10 15:54 ` [PATCH 2/3] clk/qcom: qcm2290: Add SDCC1 apps clock frequency table Loic Poulain @ 2025-12-12 1:00 ` Sumit Garg 0 siblings, 0 replies; 6+ messages in thread From: Sumit Garg @ 2025-12-12 1:00 UTC (permalink / raw) To: Loic Poulain Cc: lukma, casey.connolly, neil.armstrong, trini, peng.fan, jh80.chung, u-boot-qcom, u-boot, Sumit Garg On Wed, Dec 10, 2025 at 04:54:53PM +0100, Loic Poulain wrote: > Add support for configuring the SDCC1 apps clock on QCM2290 by introducing > a frequency table and enabling dynamic rate setting. Previously, the clock > was assumed to be fixed at 384 MHz by firmware, which limited flexibility > and correctness when selecting optimal rates for SD/MMC operations. > > Suggested-by: Sumit Garg <sumit.garg@oss.qualcomm.com> > Signed-off-by: Loic Poulain <loic.poulain@oss.qualcomm.com> > --- > drivers/clk/qcom/clock-qcm2290.c | 29 +++++++++++++++++++++++++++-- > 1 file changed, 27 insertions(+), 2 deletions(-) Reviewed-by: Sumit Garg <sumit.garg@oss.qualcomm.com> -Sumit > > diff --git a/drivers/clk/qcom/clock-qcm2290.c b/drivers/clk/qcom/clock-qcm2290.c > index fad104fb91a..5a599085b50 100644 > --- a/drivers/clk/qcom/clock-qcm2290.c > +++ b/drivers/clk/qcom/clock-qcm2290.c > @@ -17,6 +17,8 @@ > > #define QUPV3_WRAP0_S4_CMD_RCGR 0x1f608 > #define SDCC2_APPS_CLK_CMD_RCGR 0x1e00c > +#define SDCC1_APPS_CLK_CMD_RCGR 0x38028 > + > > static const struct freq_tbl ftbl_gcc_qupv3_wrap0_s0_clk_src[] = { > F(7372800, CFG_CLK_SRC_GPLL0_AUX2, 1, 384, 15625), > @@ -55,6 +57,25 @@ static const struct pll_vote_clk gpll7_clk = { > .vote_bit = BIT(7), > }; > > +static const struct freq_tbl ftbl_gcc_sdcc1_apps_clk_src[] = { > + F(144000, CFG_CLK_SRC_CXO, 16, 3, 25), > + F(400000, CFG_CLK_SRC_CXO, 12, 1, 4), > + F(20000000, CFG_CLK_SRC_GPLL0_AUX2, 5, 1, 3), > + F(25000000, CFG_CLK_SRC_GPLL0_AUX2, 6, 1, 2), > + F(50000000, CFG_CLK_SRC_GPLL0_AUX2, 6, 0, 0), > + F(100000000, CFG_CLK_SRC_GPLL0_AUX2, 3, 0, 0), > + F(192000000, CFG_CLK_SRC_GPLL6, 2, 0, 0), > + F(384000000, CFG_CLK_SRC_GPLL6, 1, 0, 0), > + {} > +}; > + > +static const struct pll_vote_clk gpll6_clk = { > + .status = 0x6000, > + .status_bit = BIT(31), > + .ena_vote = 0x79000, > + .vote_bit = BIT(7), > +}; > + > static const struct gate_clk qcm2290_clks[] = { > GATE_CLK(GCC_AHB2PHY_USB_CLK, 0x1d008, 0x00000001), > GATE_CLK(GCC_CFG_NOC_USB3_PRIM_AXI_CLK, 0x1a084, 0x00000001), > @@ -109,8 +130,12 @@ static ulong qcm2290_set_rate(struct clk *clk, ulong rate) > 8); > return freq->freq; > case GCC_SDCC1_APPS_CLK: > - /* The firmware turns this on for us and always sets it to this rate */ > - return 384000000; > + clk_enable_gpll0(priv->base, &gpll6_clk); > + freq = qcom_find_freq(ftbl_gcc_sdcc1_apps_clk_src, rate); > + clk_rcg_set_rate_mnd(priv->base, SDCC1_APPS_CLK_CMD_RCGR, > + freq->pre_div, freq->m, freq->n, freq->src, > + 8); > + return freq->freq; > default: > return 0; > } > -- > 2.34.1 > ^ permalink raw reply [flat|nested] 6+ messages in thread
* [PATCH 3/3] mmc: msm_sdhci: Add DLL control hook to disable DLL below 100 MHz 2025-12-10 15:54 [PATCH 1/3] mmc: msm_sdhci: Fix incorrect divider calculation for SDCLK Loic Poulain 2025-12-10 15:54 ` [PATCH 2/3] clk/qcom: qcm2290: Add SDCC1 apps clock frequency table Loic Poulain @ 2025-12-10 15:54 ` Loic Poulain 2025-12-12 0:59 ` [PATCH 1/3] mmc: msm_sdhci: Fix incorrect divider calculation for SDCLK Sumit Garg 2026-01-16 18:03 ` Casey Connolly 3 siblings, 0 replies; 6+ messages in thread From: Loic Poulain @ 2025-12-10 15:54 UTC (permalink / raw) To: lukma, casey.connolly, neil.armstrong Cc: sumit.garg, trini, peng.fan, jh80.chung, u-boot-qcom, u-boot, Sumit Garg, Loic Poulain From: Sumit Garg <sumit.garg@oss.qualcomm.com> Introduce an SDHCI ops hook (config_dll) for MSM SDHCI and implement a minimal DLL control routine that ensures the core DLL is disabled when the bus clock is at or below 100 MHz. This approach mirrors the Linux MSM SDHCI driver. Signed-off-by: Sumit Garg <sumit.garg@oss.qualcomm.com> Signed-off-by: Loic Poulain <loic.poulain@oss.qualcomm.com> --- drivers/mmc/msm_sdhci.c | 37 +++++++++++++++++++++++++++++++++++++ 1 file changed, 37 insertions(+) diff --git a/drivers/mmc/msm_sdhci.c b/drivers/mmc/msm_sdhci.c index ec003991928..38dc36a2194 100644 --- a/drivers/mmc/msm_sdhci.c +++ b/drivers/mmc/msm_sdhci.c @@ -36,6 +36,11 @@ #define CORE_VENDOR_SPEC_POR_VAL 0xa9c +#define CORE_DLL_PDN BIT(29) +#define CORE_DLL_RST BIT(30) + +#define MHZ(X) ((X) * 1000000UL) + struct msm_sdhc_plat { struct mmc_config cfg; struct mmc mmc; @@ -51,6 +56,7 @@ struct msm_sdhc { struct msm_sdhc_variant_info { bool mci_removed; + u32 core_dll_config; u32 core_vendor_spec; u32 core_vendor_spec_capabilities0; }; @@ -149,6 +155,34 @@ static int msm_sdc_mci_init(struct msm_sdhc *prv) return 0; } +static int msm_sdhci_config_dll(struct sdhci_host *host, u32 clock, bool enable) +{ + struct udevice *dev = mmc_to_dev(host->mmc); + const struct msm_sdhc_variant_info *var_info = (void *)dev_get_driver_data(dev); + u32 config; + + if (enable && clock < MHZ(100)) { + /* + * DLL is not required for clock <= 100MHz + * Thus, make sure DLL is disabled when not required + */ + config = readl(host->ioaddr + var_info->core_dll_config); + config |= CORE_DLL_RST; + writel(config, host->ioaddr + var_info->core_dll_config); + + config = readl(host->ioaddr + var_info->core_dll_config); + config |= CORE_DLL_PDN; + writel(config, host->ioaddr + var_info->core_dll_config); + } + + return 0; +} + +struct sdhci_ops msm_sdhci_ops = { + .config_dll = &msm_sdhci_config_dll, + .set_control_reg = &sdhci_set_control_reg, +}; + static int msm_sdc_probe(struct udevice *dev) { struct mmc_uclass_priv *upriv = dev_get_uclass_priv(dev); @@ -223,6 +257,7 @@ static int msm_sdc_probe(struct udevice *dev) host->mmc = &plat->mmc; host->mmc->dev = dev; + host->ops = &msm_sdhci_ops; ret = sdhci_setup_cfg(&plat->cfg, host, 0, 0); if (ret) return ret; @@ -288,6 +323,7 @@ static int msm_sdc_bind(struct udevice *dev) static const struct msm_sdhc_variant_info msm_sdhc_mci_var = { .mci_removed = false, + .core_dll_config = 0x100, .core_vendor_spec = 0x10c, .core_vendor_spec_capabilities0 = 0x11c, }; @@ -295,6 +331,7 @@ static const struct msm_sdhc_variant_info msm_sdhc_mci_var = { static const struct msm_sdhc_variant_info msm_sdhc_v5_var = { .mci_removed = true, + .core_dll_config = 0x200, .core_vendor_spec = 0x20c, .core_vendor_spec_capabilities0 = 0x21c, }; -- 2.34.1 ^ permalink raw reply related [flat|nested] 6+ messages in thread
* Re: [PATCH 1/3] mmc: msm_sdhci: Fix incorrect divider calculation for SDCLK 2025-12-10 15:54 [PATCH 1/3] mmc: msm_sdhci: Fix incorrect divider calculation for SDCLK Loic Poulain 2025-12-10 15:54 ` [PATCH 2/3] clk/qcom: qcm2290: Add SDCC1 apps clock frequency table Loic Poulain 2025-12-10 15:54 ` [PATCH 3/3] mmc: msm_sdhci: Add DLL control hook to disable DLL below 100 MHz Loic Poulain @ 2025-12-12 0:59 ` Sumit Garg 2026-01-16 18:03 ` Casey Connolly 3 siblings, 0 replies; 6+ messages in thread From: Sumit Garg @ 2025-12-12 0:59 UTC (permalink / raw) To: Loic Poulain Cc: lukma, casey.connolly, neil.armstrong, trini, peng.fan, jh80.chung, u-boot-qcom, u-boot On Wed, Dec 10, 2025 at 04:54:52PM +0100, Loic Poulain wrote: > When 'max-clk' is not specified, the SDHCI core retrieves the base clock > from the SDHCI_CAPABILITIES register (bits [15:8]). However, this field > is unreliable on MSM SDHCI controllers, as noted by the Linux driver > using the SDHCI_QUIRK_CAP_CLOCK_BASE_BROKEN flag. In addition, the field > is only 8 bits wide and cannot represent base clocks above 255 MHz. > > On platforms like Agatti/QCM2290, the firmware sets the SDHCI clock to > 384 MHz, but the capabilities register reports 200 MHz. As a result, > the core calculates a divider of 4, producing a 96 MHz SDCLK instead of > the intended ~52 MHz. This overclocking can cause sporadic CRC errors > with certain eMMC. > > To fix this, use the actual clock rate reported by the SDHCI core clock > instead of relying on the capabilities register for divider calculation. > > Signed-off-by: Loic Poulain <loic.poulain@oss.qualcomm.com> > --- > drivers/mmc/msm_sdhci.c | 3 +++ > 1 file changed, 3 insertions(+) Reviewed-by: Sumit Garg <sumit.garg@oss.qualcomm.com> -Sumit > > diff --git a/drivers/mmc/msm_sdhci.c b/drivers/mmc/msm_sdhci.c > index ac77fb06bf7..ec003991928 100644 > --- a/drivers/mmc/msm_sdhci.c > +++ b/drivers/mmc/msm_sdhci.c > @@ -114,6 +114,9 @@ static int msm_sdc_clk_init(struct udevice *dev) > return -EINVAL; > } > > + /* This is the base clock sdhci core will use to configure the SDCLK */ > + prv->host.max_clk = clk_rate; > + > writel_relaxed(CORE_VENDOR_SPEC_POR_VAL, > prv->host.ioaddr + var_info->core_vendor_spec); > > -- > 2.34.1 > ^ permalink raw reply [flat|nested] 6+ messages in thread
* Re: [PATCH 1/3] mmc: msm_sdhci: Fix incorrect divider calculation for SDCLK 2025-12-10 15:54 [PATCH 1/3] mmc: msm_sdhci: Fix incorrect divider calculation for SDCLK Loic Poulain ` (2 preceding siblings ...) 2025-12-12 0:59 ` [PATCH 1/3] mmc: msm_sdhci: Fix incorrect divider calculation for SDCLK Sumit Garg @ 2026-01-16 18:03 ` Casey Connolly 3 siblings, 0 replies; 6+ messages in thread From: Casey Connolly @ 2026-01-16 18:03 UTC (permalink / raw) To: lukma, neil.armstrong, Loic Poulain Cc: sumit.garg, trini, peng.fan, jh80.chung, u-boot-qcom, u-boot On Wed, 10 Dec 2025 16:54:52 +0100, Loic Poulain wrote: > When 'max-clk' is not specified, the SDHCI core retrieves the base clock > from the SDHCI_CAPABILITIES register (bits [15:8]). However, this field > is unreliable on MSM SDHCI controllers, as noted by the Linux driver > using the SDHCI_QUIRK_CAP_CLOCK_BASE_BROKEN flag. In addition, the field > is only 8 bits wide and cannot represent base clocks above 255 MHz. > > On platforms like Agatti/QCM2290, the firmware sets the SDHCI clock to > 384 MHz, but the capabilities register reports 200 MHz. As a result, > the core calculates a divider of 4, producing a 96 MHz SDCLK instead of > the intended ~52 MHz. This overclocking can cause sporadic CRC errors > with certain eMMC. > > [...] Applied, thanks! [1/3] mmc: msm_sdhci: Fix incorrect divider calculation for SDCLK https://source.denx.de/u-boot/custodians/u-boot-snapdragon/-/commit/edd1fb0c3695 [2/3] clk/qcom: qcm2290: Add SDCC1 apps clock frequency table https://source.denx.de/u-boot/custodians/u-boot-snapdragon/-/commit/3ddc67573fab [3/3] mmc: msm_sdhci: Add DLL control hook to disable DLL below 100 MHz https://source.denx.de/u-boot/custodians/u-boot-snapdragon/-/commit/338c4b820804 Best regards, -- // Casey (she/they) ^ permalink raw reply [flat|nested] 6+ messages in thread
end of thread, other threads:[~2026-01-16 18:05 UTC | newest] Thread overview: 6+ messages (download: mbox.gz follow: Atom feed -- links below jump to the message on this page -- 2025-12-10 15:54 [PATCH 1/3] mmc: msm_sdhci: Fix incorrect divider calculation for SDCLK Loic Poulain 2025-12-10 15:54 ` [PATCH 2/3] clk/qcom: qcm2290: Add SDCC1 apps clock frequency table Loic Poulain 2025-12-12 1:00 ` Sumit Garg 2025-12-10 15:54 ` [PATCH 3/3] mmc: msm_sdhci: Add DLL control hook to disable DLL below 100 MHz Loic Poulain 2025-12-12 0:59 ` [PATCH 1/3] mmc: msm_sdhci: Fix incorrect divider calculation for SDCLK Sumit Garg 2026-01-16 18:03 ` Casey Connolly
This is an external index of several public inboxes, see mirroring instructions on how to clone and mirror all data and code used by this external index.