[PATCH 2/4] mmc: sdhci-cadence6: program PHONY_DQS_TIMING for extended-read DDR

From: tze . yee . ng

Date: Tue Sep 22 2026 - 07:13:57 EST


From: Tze Yee Ng <tze.yee.ng@xxxxxxxxxx>

The SD6HC PHY left PHONY_DQS_TIMING (phy_ctrl_reg[9:4]) at 0 in all
modes. Per the Cadence DLL PHY documentation it must be the rebar (RE#)
pulse width in clk_phy cycles minus 1 in extended read mode, and 0
otherwise. Leaving it 0 in extended-read DDR duplicates one DDR edge
(the silent odd/even edge-capture defect).

This controller's rebar pulse is a fixed 2 clk_phy cycles, so extended-
read DDR needs 1; confirmed on DDR50 hardware (1 captures both beats, 2
corrupts reads). Derive it from the extended-read-mode state and apply
it only in DDR modes, since SDR extended-read samples a single edge and
is unaffected. This is generic to any SD6HC-PHY SoC, so it is kept
separate from the per-SoC read-path tuning.

Signed-off-by: Tze Yee Ng <tze.yee.ng@xxxxxxxxxx>
---
drivers/mmc/host/sdhci-cadence-phy-v6.c | 15 +++++++++++++++
1 file changed, 15 insertions(+)

diff --git a/drivers/mmc/host/sdhci-cadence-phy-v6.c b/drivers/mmc/host/sdhci-cadence-phy-v6.c
index 35f35ef9c710..84592ae42762 100644
--- a/drivers/mmc/host/sdhci-cadence-phy-v6.c
+++ b/drivers/mmc/host/sdhci-cadence-phy-v6.c
@@ -90,6 +90,9 @@
#define SDHCI_CDNS6_PHY_CTRL_REG 0x2080
#define SDHCI_CDNS6_PHY_CTRL_PHONY_DQS_TIMING GENMASK(9, 4)

+/* Width of this controller's rebar (RE#) pulse in clk_phy cycles. */
+#define SDHCI_CDNS6_PHY_REBAR_PULSE_CYCLES 2
+
/* Default PHY settings */
#define SDHCI_CDNS6_PHY_DEFAULT_IOCELL_DELAY 2500
#define SDHCI_CDNS6_PHY_DEFAULT_DELAY_ELEMENT 24
@@ -143,6 +146,9 @@ struct sdhci_cdns6_phy {
bool cp_use_phony_dqs; /* bit [20] */
bool cp_use_phony_dqs_cmd; /* bit [19] */

+ /* PHY_CTRL register fields */
+ u32 cp_phony_dqs_timing;
+
/* HRS07 register - IO delay Information */
u8 sdhc_rw_compensate; /* bits [20:16] */
u8 sdhc_idelay_val; /* bits [4:0] */
@@ -517,6 +523,13 @@ static void sdhci_cdns6_phy_calc_dat_in(struct sdhci_cdns6_phy *phy)
if (phy->mode == MMC_TIMING_MMC_HS200)
phy->cp_read_dqs_delay = phy->hs200_tune_val;

+ if (phy->sdhc_extended_rd_mode &&
+ (phy->mode == MMC_TIMING_UHS_DDR50 ||
+ phy->mode == MMC_TIMING_MMC_DDR52))
+ phy->cp_phony_dqs_timing = SDHCI_CDNS6_PHY_REBAR_PULSE_CYCLES - 1;
+ else
+ phy->cp_phony_dqs_timing = 0;
+
if (strobe_dat) {
/* dqs loopback input via IO cell */
hcsdclkadj += phy->iocell_input_delay;
@@ -715,6 +728,8 @@ int sdhci_cdns6_phy_init(struct sdhci_cdns_priv *priv)

reg = sdhci_cdns6_read_phy_reg(priv, SDHCI_CDNS6_PHY_CTRL_REG);
reg &= ~SDHCI_CDNS6_PHY_CTRL_PHONY_DQS_TIMING;
+ reg |= FIELD_PREP(SDHCI_CDNS6_PHY_CTRL_PHONY_DQS_TIMING,
+ phy->cp_phony_dqs_timing);
sdhci_cdns6_write_phy_reg(priv, SDHCI_CDNS6_PHY_CTRL_REG, reg);

/*
--
2.43.7