All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH v3 0/4] mmc: sdhci-cadence: SD6HC DDR50/DDR52 read-path tuning and fixes
@ 2026-11-06  6:16 tze.yee.ng
  2026-11-06  6:16 ` [PATCH v3 1/4] mmc: sdhci-cadence: abort failed tuning command on SD6HC tze.yee.ng
                   ` (3 more replies)
  0 siblings, 4 replies; 7+ messages in thread
From: tze.yee.ng @ 2026-11-06  6:16 UTC (permalink / raw)
  To: Tanmay Kathpalia, Adrian Hunter, linux-mmc, linux-kernel,
	Rob Herring, Krzysztof Kozlowski, Conor Dooley, devicetree,
	Ulf Hansson

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

This series enables the extended-read DDR modes - SD DDR50 and eMMC
DDR52 - on the Cadence SD6HC (SD/eMMC v6) PHY. Neither mode runs a host
tuning sequence (CMD19/CMD21), so the read path must be centred by
static, board/SoC-characterised PHY settings. Bringing it up on Agilex5
also exposed PHY issues affecting the existing tuned modes.

  - Patch 1: abort a failed tuning command on SD6HC. The software tuning
    loop never aborted a command that errored, so after a CMD21 command
    error the eMMC could stay in the Data state and time out the CMD6
    that HS400 selection issues next; mmc_send_abort_tuning() clears it
    (a no-op for SD).
  - Patch 2: program PHONY_DQS_TIMING (left 0 in all modes); in the
    extended-read DDR modes it must be the rebar pulse width in clk_phy
    cycles minus 1, else one DDR beat is duplicated.
  - Patch 3: document three optional SD6HC read-path properties for the
    extended-read DDR modes (SD DDR50, eMMC DDR52).
  - Patch 4: read those properties at probe and apply them in DDR50 and
    DDR52, and make the DQS_TIMING update clear USE_LPBK_DQS before
    reprogramming it so the loopback/phony selection takes effect.

The new cdns,ddr-* properties are unused in this series; they will be
consumed by the socfpga_agilex5_socdk and socfpga_agilex5_socdk_emmc
device trees, submitted as a separate series.

Tested on Agilex5 SoCDK: SD DDR50, eMMC DDR52 and eMMC HS400.

Signed-off-by: Tze Yee Ng <tze.yee.ng@altera.com>
---
Changes in v3:
- Patch 1: replaced the post-tuning PHY settle (v2 1/4) with aborting
  the failed tuning command. Added Suggested-by. (Tanmay Kathpalia)
- Patch 2: unchanged; retains Adrian's Acked-by.
- Patch 3: re-expressed cdns,ddr-read-dqs-delay-ps as
  cdns,ddr-read-dqs-delay - a count of DLL delay elements (0-255, each
  cdns,delay-element-ps wide) that maps 1:1 to the 8-bit PHY field -
  instead of a picosecond value; added $ref uint32 and maximum: 255,
  dropped the redundant minimum: 0, and used plain description: text.
  (Krzysztof Kozlowski)
- Patch 4: read cdns,ddr-read-dqs-delay directly as the delay-element
  count and write it to the 8-bit field, dropping the v2 ps->element
  conversion (divide by cdns,delay-element-ps) and the FIELD_MAX()
  clamp. Hoisted the repeated DDR-mode test to a local, removed the
  probe-time firmware-value warning, and unwrapped lines to 100 cols.
  (Adrian Hunter, Krzysztof Kozlowski)

- Link to v2: https://lore.kernel.org/all/cover.1791459448.git.tze.yee.ng@altera.com/
- Link to v1: https://lore.kernel.org/all/cover.1790074790.git.tze.yee.ng@altera.com/
---
To: Adrian Hunter <adrian.hunter@intel.com>
To: Tanmay Kathpalia <tanmay.kathpalia@altera.com>
To: Ulf Hansson <ulfh@kernel.org>
To: Rob Herring <robh@kernel.org>
To: Krzysztof Kozlowski <krzk+dt@kernel.org>
To: Conor Dooley <conor+dt@kernel.org>
Cc: linux-mmc@vger.kernel.org
Cc: linux-kernel@vger.kernel.org
Cc: devicetree@vger.kernel.org

---
Tze Yee Ng (4):
      mmc: sdhci-cadence: abort failed tuning command on SD6HC
      mmc: sdhci-cadence6: program PHONY_DQS_TIMING for extended-read DDR
      dt-bindings: mmc: cdns,sd6hc: add SD6HC DDR50 read-path tuning
      mmc: sdhci-cadence6: read SD6HC DDR50 tuning from device tree

 .../devicetree/bindings/mmc/cdns,sd6hc.yaml        | 30 ++++++++++++
 drivers/mmc/host/sdhci-cadence-core.c              | 11 ++++-
 drivers/mmc/host/sdhci-cadence-phy-v6.c            | 57 +++++++++++++++++++++-
 3 files changed, 96 insertions(+), 2 deletions(-)
---
base-commit: 2febfc8acbf712439b6d30c99b108641d881fd75
change-id: 20261106-sd_cadence_ddr50_v3-35f970f31364

Best regards,
--  
Tze Yee Ng <tze.yee.ng@altera.com>


^ permalink raw reply	[flat|nested] 7+ messages in thread

* [PATCH v3 1/4] mmc: sdhci-cadence: abort failed tuning command on SD6HC
  2026-11-06  6:16 [PATCH v3 0/4] mmc: sdhci-cadence: SD6HC DDR50/DDR52 read-path tuning and fixes tze.yee.ng
@ 2026-11-06  6:16 ` tze.yee.ng
  2026-11-06  6:16 ` [PATCH v3 2/4] mmc: sdhci-cadence6: program PHONY_DQS_TIMING for extended-read DDR tze.yee.ng
                   ` (2 subsequent siblings)
  3 siblings, 0 replies; 7+ messages in thread
From: tze.yee.ng @ 2026-11-06  6:16 UTC (permalink / raw)
  To: Tanmay Kathpalia, Adrian Hunter, linux-mmc, linux-kernel,
	Rob Herring, Krzysztof Kozlowski, Conor Dooley, devicetree,
	Ulf Hansson

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

SD6HC uses a software tuning loop that calls mmc_send_tuning() for every
tap but never aborts a command that fails. When a CMD21 fails with a
command error the eMMC can remain in the Data state and reject the next
command, so the CMD6 that mmc_select_hs400() issues right after tuning
times out. SD is not affected because CMD12 cannot abort CMD19.

Request the command error from mmc_send_tuning() and, on a command
error, abort the tuning command with mmc_send_abort_tuning(), which is a
no-op for SD. This matches the generic sdhci tuning path.

Suggested-by: Tanmay Kathpalia <tanmay.kathpalia@altera.com>
Signed-off-by: Tze Yee Ng <tze.yee.ng@altera.com>
---
Changes in v3:
- New patch replacing the v2 1/4 PHY settle: abort the failed tuning
  command (mmc_send_abort_tuning(), a no-op for SD) instead of masking
  the post-tuning command timeout with a settle delay. (Tanmay Kathpalia)
---
 drivers/mmc/host/sdhci-cadence-core.c | 11 ++++++++++-
 1 file changed, 10 insertions(+), 1 deletion(-)

diff --git a/drivers/mmc/host/sdhci-cadence-core.c b/drivers/mmc/host/sdhci-cadence-core.c
index 745455743b01..a94296cebf47 100644
--- a/drivers/mmc/host/sdhci-cadence-core.c
+++ b/drivers/mmc/host/sdhci-cadence-core.c
@@ -330,9 +330,18 @@ static int sdhci_cdns_execute_tuning(struct sdhci_host *host, u32 opcode)
 	}
 
 	for (i = 0; i < SDHCI_CDNS_MAX_TUNING_LOOP; i++) {
+		int cmd_error = 0;
+
 		if (sdhci_cdns_set_tune_val(host, i) ||
-		    mmc_send_tuning(host->mmc, opcode, NULL)) { /* bad */
+		    mmc_send_tuning(host->mmc, opcode, &cmd_error)) { /* bad */
 			cur_streak = 0;
+			/*
+			 * Abort a failed tuning command so an eMMC does not
+			 * stay in the Data state and reject the next command;
+			 * a no-op for SD.
+			 */
+			if (cmd_error)
+				mmc_send_abort_tuning(host->mmc, opcode);
 		} else { /* good */
 			cur_streak++;
 			if (cur_streak > max_streak) {

-- 
2.43.7


^ permalink raw reply related	[flat|nested] 7+ messages in thread

* [PATCH v3 2/4] mmc: sdhci-cadence6: program PHONY_DQS_TIMING for extended-read DDR
  2026-11-06  6:16 [PATCH v3 0/4] mmc: sdhci-cadence: SD6HC DDR50/DDR52 read-path tuning and fixes tze.yee.ng
  2026-11-06  6:16 ` [PATCH v3 1/4] mmc: sdhci-cadence: abort failed tuning command on SD6HC tze.yee.ng
@ 2026-11-06  6:16 ` tze.yee.ng
  2026-11-06  6:22   ` sashiko-bot
  2026-11-06  6:16 ` [PATCH v3 3/4] dt-bindings: mmc: cdns,sd6hc: add SD6HC DDR50 read-path tuning tze.yee.ng
  2026-11-06  6:16 ` [PATCH v3 4/4] mmc: sdhci-cadence6: read SD6HC DDR50 tuning from device tree tze.yee.ng
  3 siblings, 1 reply; 7+ messages in thread
From: tze.yee.ng @ 2026-11-06  6:16 UTC (permalink / raw)
  To: Tanmay Kathpalia, Adrian Hunter, linux-mmc, linux-kernel,
	Rob Herring, Krzysztof Kozlowski, Conor Dooley, devicetree,
	Ulf Hansson

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

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).

On this integration the rebar pulse is 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.

Acked-by: Adrian Hunter <adrian.hunter@intel.com>
Signed-off-by: Tze Yee Ng <tze.yee.ng@altera.com>
---
Changes in v3:
- No change; retains Adrian's Acked-by.

Changes in v2:
- Added Adrian's Acked-by.
- Reworded the commit message to drop the "generic to any SD6HC-PHY SoC"
  framing. (Adrian Hunter)
---
 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 22d56bb46d75..8d6a9c26c139 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


^ permalink raw reply related	[flat|nested] 7+ messages in thread

* [PATCH v3 3/4] dt-bindings: mmc: cdns,sd6hc: add SD6HC DDR50 read-path tuning
  2026-11-06  6:16 [PATCH v3 0/4] mmc: sdhci-cadence: SD6HC DDR50/DDR52 read-path tuning and fixes tze.yee.ng
  2026-11-06  6:16 ` [PATCH v3 1/4] mmc: sdhci-cadence: abort failed tuning command on SD6HC tze.yee.ng
  2026-11-06  6:16 ` [PATCH v3 2/4] mmc: sdhci-cadence6: program PHONY_DQS_TIMING for extended-read DDR tze.yee.ng
@ 2026-11-06  6:16 ` tze.yee.ng
  2026-11-06 12:40   ` Krzysztof Kozlowski
  2026-11-06  6:16 ` [PATCH v3 4/4] mmc: sdhci-cadence6: read SD6HC DDR50 tuning from device tree tze.yee.ng
  3 siblings, 1 reply; 7+ messages in thread
From: tze.yee.ng @ 2026-11-06  6:16 UTC (permalink / raw)
  To: Tanmay Kathpalia, Adrian Hunter, linux-mmc, linux-kernel,
	Rob Herring, Krzysztof Kozlowski, Conor Dooley, devicetree,
	Ulf Hansson

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

DDR50 has no CMD19 tuning, so the SD6HC read path must be centred by
static, board/SoC-characterised PHY settings. Add three optional SD6HC
properties for the extended-read DDR modes (SD DDR50 and eMMC DDR52):

  - cdns,ddr-read-dqs-delay:    read-DQS delay as a count of DLL delay
    elements (0-255), each cdns,delay-element-ps wide, that centres the
    read eye (default 0).
  - cdns,ddr-no-lpbk-dqs:       disable the loopback DQS read strobe and
    use the fabricated phony DQS instead. Loopback DQS is the recommended
    default; set this only on boards that need the phony DQS read path.
  - cdns,ddr-phony-dqs-timing:  PHY_CTRL[9:4] phony DQS assertion timing.
    The driver derives this from the RE# pulse width; this property
    overrides the computed value for boards whose flight time shifts the
    DDR data return.

Signed-off-by: Tze Yee Ng <tze.yee.ng@altera.com>
---
Changes in v3:
- Re-expressed cdns,ddr-read-dqs-delay-ps as cdns,ddr-read-dqs-delay: a
  count of DLL delay elements (0-255, each cdns,delay-element-ps wide)
  that maps 1:1 to the 8-bit PHY field, instead of a picosecond value.
  (Krzysztof Kozlowski)
- Added $ref uint32 and maximum: 255; dropped the redundant minimum: 0.
- Used plain description: text for the three new properties.

Changes in v2:
- Retitled to "dt-bindings: mmc: cdns,sd6hc:". (Tanmay Kathpalia)
- Renamed cdns,ddr50-* -> cdns,ddr-*. (Tanmay Kathpalia)
- cdns,ddr-read-dqs-delay-ps is now in picoseconds. (Krzysztof Kozlowski)
- Replaced the read-DQS source selector with a cdns,ddr-no-lpbk-dqs
  boolean. (Krzysztof Kozlowski)
- Reworded the phony-dqs-timing text. (Krzysztof Kozlowski,
  Tanmay Kathpalia)
- Dropped the SD4HC note. (Tanmay Kathpalia)
- Scope the new properties to the extended-read DDR modes (DDR50 and
  DDR52). (Tanmay Kathpalia)
---
 .../devicetree/bindings/mmc/cdns,sd6hc.yaml        | 30 ++++++++++++++++++++++
 1 file changed, 30 insertions(+)

diff --git a/Documentation/devicetree/bindings/mmc/cdns,sd6hc.yaml b/Documentation/devicetree/bindings/mmc/cdns,sd6hc.yaml
index d5ea2717904b..ee6a28ef2e34 100644
--- a/Documentation/devicetree/bindings/mmc/cdns,sd6hc.yaml
+++ b/Documentation/devicetree/bindings/mmc/cdns,sd6hc.yaml
@@ -74,6 +74,36 @@ properties:
     maximum: 1000
     default: 24
 
+  cdns,ddr-read-dqs-delay:
+    description:
+      Read-DQS delay (DLL_SLAVE[7:0]) that centres the read eye in the
+      extended-read DDR modes (SD DDR50, eMMC DDR52), which have no CMD19
+      tuning. Expressed as a count of DLL delay elements, each element
+      cdns,delay-element-ps wide, written directly to the 8-bit hardware
+      field.
+    $ref: /schemas/types.yaml#/definitions/uint32
+    maximum: 255
+    default: 0
+
+  cdns,ddr-no-lpbk-dqs:
+    description:
+      Disable the loopback DQS read strobe and use the fabricated (phony)
+      DQS instead in the extended-read DDR modes (SD DDR50, eMMC DDR52).
+      Loopback DQS is the recommended default; set this only on boards that
+      require the phony DQS read path.
+    type: boolean
+
+  cdns,ddr-phony-dqs-timing:
+    description:
+      Phony DQS assertion timing (PHY_CTRL[9:4]) for the extended-read DDR
+      modes (SD DDR50, eMMC DDR52). The driver computes this from the RE#
+      pulse width per the Cadence PHY guide; set it only to override that
+      value on boards whose DDR data returns shifted (e.g. longer flight
+      time on modular/SoM layouts). If absent, the computed value is used.
+    $ref: /schemas/types.yaml#/definitions/uint32
+    minimum: 0
+    maximum: 0x3f
+
 required:
   - compatible
   - reg

-- 
2.43.7


^ permalink raw reply related	[flat|nested] 7+ messages in thread

* [PATCH v3 4/4] mmc: sdhci-cadence6: read SD6HC DDR50 tuning from device tree
  2026-11-06  6:16 [PATCH v3 0/4] mmc: sdhci-cadence: SD6HC DDR50/DDR52 read-path tuning and fixes tze.yee.ng
                   ` (2 preceding siblings ...)
  2026-11-06  6:16 ` [PATCH v3 3/4] dt-bindings: mmc: cdns,sd6hc: add SD6HC DDR50 read-path tuning tze.yee.ng
@ 2026-11-06  6:16 ` tze.yee.ng
  3 siblings, 0 replies; 7+ messages in thread
From: tze.yee.ng @ 2026-11-06  6:16 UTC (permalink / raw)
  To: Tanmay Kathpalia, Adrian Hunter, linux-mmc, linux-kernel,
	Rob Herring, Krzysztof Kozlowski, Conor Dooley, devicetree,
	Ulf Hansson

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

DDR50 has no CMD19 tuning, so the SD6HC read path relies on static PHY
settings that need board/SoC characterisation. Read the read-DQS delay,
read-DQS source and phony DQS assertion timing from the new
cdns,ddr-read-dqs-delay, cdns,ddr-no-lpbk-dqs and
cdns,ddr-phony-dqs-timing DT properties at PHY probe and apply them in
the extended-read DDR modes (DDR50 and DDR52). The read-DQS delay is a
count of DLL delay elements (each cdns,delay-element-ps wide) written
directly to the 8-bit PHY field (0-255).

Loopback DQS is the recommended read-capture path and stays the default;
cdns,ddr-no-lpbk-dqs lets a board fall back to the fabricated phony DQS.
When a property is absent the driver-computed value is kept - for the
phony DQS timing, the value derived from the RE# pulse width
(REBAR_PULSE_CYCLES-1).

Signed-off-by: Tze Yee Ng <tze.yee.ng@altera.com>
---
Changes in v3:
- Read cdns,ddr-read-dqs-delay directly as the delay-element count and
  write it to the 8-bit PHY field; dropped the ps->element conversion
  (divide by cdns,delay-element-ps) and the FIELD_MAX() clamp.
  (Krzysztof Kozlowski)
- Hoisted the repeated DDR-mode test to a local bool. (Adrian Hunter)
- Removed the probe-time dev_warn() that validated the firmware value.
  (Adrian Hunter)
- Unwrapped the of_property_read_u32() call to 100 columns.
  (Adrian Hunter)

Changes in v2:
- Updated patch title to "mmc: sdhci-cadence6:" since it touches only the
  v6 PHY.
- Renamed the properties to cdns,ddr-*.
- Read cdns,ddr-read-dqs-delay-ps in ps and convert it to delay elements
  (dividing by cdns,delay-element-ps), clamping that quotient to the 8-bit
  PHY field. (Krzysztof Kozlowski)
- Read cdns,ddr-no-lpbk-dqs via of_property_read_bool().
  (Krzysztof Kozlowski)
- Dropped the v1 per-property range checks and redundant FIELD_MAX() write
  masks. (Adrian Hunter)
- Apply the overrides in both DDR50 and DDR52.
---
 drivers/mmc/host/sdhci-cadence-phy-v6.c | 48 ++++++++++++++++++++++++++++++---
 1 file changed, 44 insertions(+), 4 deletions(-)

diff --git a/drivers/mmc/host/sdhci-cadence-phy-v6.c b/drivers/mmc/host/sdhci-cadence-phy-v6.c
index 8d6a9c26c139..d905e39d4b6f 100644
--- a/drivers/mmc/host/sdhci-cadence-phy-v6.c
+++ b/drivers/mmc/host/sdhci-cadence-phy-v6.c
@@ -129,6 +129,11 @@ struct sdhci_cdns6_phy {
 	/* Active delay element (ps); doubled when one SDMCLK requires > 256 steps */
 	u32 delay_element;
 
+	/* DDR read-path overrides (SoC-specific) */
+	u32 ddr_read_dqs_delay;
+	bool ddr_no_lpbk_dqs;
+	s32 ddr_phony_dqs_timing;
+
 	/* PHY_DLL_SLAVE_CTRL register fields */
 	u8 cp_read_dqs_cmd_delay;	/* bits [31:24] */
 	u8 cp_clk_wrdqs_delay;		/* bits [23:16] */
@@ -145,6 +150,7 @@ struct sdhci_cdns6_phy {
 	/* PHY_DQS_TIMING register fields */
 	bool cp_use_phony_dqs;		/* bit [20] */
 	bool cp_use_phony_dqs_cmd;	/* bit [19] */
+	bool cp_use_lpbk_dqs;		/* bit [21] */
 
 	/* PHY_CTRL register fields */
 	u32 cp_phony_dqs_timing;
@@ -511,6 +517,7 @@ static void sdhci_cdns6_phy_calc_dat_in(struct sdhci_cdns6_phy *phy)
 {
 	u32 hcsdclkadj = 0;
 	bool strobe_dat = (phy->mode == MMC_TIMING_MMC_HS400);
+	bool ddr = (phy->mode == MMC_TIMING_UHS_DDR50 || phy->mode == MMC_TIMING_MMC_DDR52);
 
 	if (strobe_dat) {
 		phy->cp_use_phony_dqs = false;
@@ -523,13 +530,31 @@ 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))
+	if (ddr && phy->ddr_read_dqs_delay)
+		phy->cp_read_dqs_delay = phy->ddr_read_dqs_delay;
+
+	phy->cp_use_lpbk_dqs = 1;
+
+	if (phy->sdhc_extended_rd_mode && ddr)
 		phy->cp_phony_dqs_timing = SDHCI_CDNS6_PHY_REBAR_PULSE_CYCLES - 1;
 	else
 		phy->cp_phony_dqs_timing = 0;
 
+	/*
+	 * Loopback DQS is the recommended read-capture path; allow boards that
+	 * need the fabricated phony DQS instead to opt out in the DDR modes.
+	 */
+	if (ddr && phy->ddr_no_lpbk_dqs)
+		phy->cp_use_lpbk_dqs = 0;
+
+	/*
+	 * The computed phony DQS timing above is derived from the RE# pulse
+	 * width. Allow a DT override for boards whose flight time shifts the
+	 * returning DDR data relative to the fabricated strobe.
+	 */
+	if (ddr && phy->ddr_phony_dqs_timing >= 0)
+		phy->cp_phony_dqs_timing = phy->ddr_phony_dqs_timing;
+
 	if (strobe_dat) {
 		/* dqs loopback input via IO cell */
 		hcsdclkadj += phy->iocell_input_delay;
@@ -693,10 +718,11 @@ int sdhci_cdns6_phy_init(struct sdhci_cdns_priv *priv)
 	sdhci_cdns6_dll_reset(priv, true);
 
 	reg = sdhci_cdns6_read_phy_reg(priv, SDHCI_CDNS6_PHY_DQS_TIMING_REG);
+	reg &= ~SDHCI_CDNS6_PHY_DQS_TIMING_USE_LPBK_DQS;
 	reg &= ~SDHCI_CDNS6_PHY_DQS_TIMING_USE_PHONY_DQS;
 	reg &= ~SDHCI_CDNS6_PHY_DQS_TIMING_USE_PHONY_DQS_CMD;
 	reg |= SDHCI_CDNS6_PHY_DQS_TIMING_USE_EXT_LPBK_DQS;
-	reg |= SDHCI_CDNS6_PHY_DQS_TIMING_USE_LPBK_DQS;
+	reg |= FIELD_PREP(SDHCI_CDNS6_PHY_DQS_TIMING_USE_LPBK_DQS, phy->cp_use_lpbk_dqs);
 	reg |= FIELD_PREP(SDHCI_CDNS6_PHY_DQS_TIMING_USE_PHONY_DQS, phy->cp_use_phony_dqs);
 	reg |= FIELD_PREP(SDHCI_CDNS6_PHY_DQS_TIMING_USE_PHONY_DQS_CMD, phy->cp_use_phony_dqs_cmd);
 	sdhci_cdns6_write_phy_reg(priv, SDHCI_CDNS6_PHY_DQS_TIMING_REG, reg);
@@ -878,6 +904,7 @@ int sdhci_cdns6_phy_probe(struct platform_device *pdev, struct sdhci_cdns_priv *
 	struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
 	struct sdhci_cdns6_phy *phy;
 	unsigned long val;
+	u32 prop;
 	int ret;
 
 	phy = devm_kzalloc(dev, sizeof(*phy), GFP_KERNEL);
@@ -916,6 +943,19 @@ int sdhci_cdns6_phy_probe(struct platform_device *pdev, struct sdhci_cdns_priv *
 
 	phy->delay_element_org = phy->delay_element;
 
+	/*
+	 * Optional read-path tuning for the extended-read DDR modes (SD DDR50,
+	 * eMMC DDR52).
+	 */
+	phy->ddr_read_dqs_delay = 0;
+	of_property_read_u32(dev->of_node, "cdns,ddr-read-dqs-delay", &phy->ddr_read_dqs_delay);
+
+	phy->ddr_no_lpbk_dqs = of_property_read_bool(dev->of_node, "cdns,ddr-no-lpbk-dqs");
+
+	phy->ddr_phony_dqs_timing = -1;
+	if (!of_property_read_u32(dev->of_node, "cdns,ddr-phony-dqs-timing", &prop))
+		phy->ddr_phony_dqs_timing = prop;
+
 	priv->phy = phy;
 
 	return 0;

-- 
2.43.7


^ permalink raw reply related	[flat|nested] 7+ messages in thread

* Re: [PATCH v3 2/4] mmc: sdhci-cadence6: program PHONY_DQS_TIMING for extended-read DDR
  2026-11-06  6:16 ` [PATCH v3 2/4] mmc: sdhci-cadence6: program PHONY_DQS_TIMING for extended-read DDR tze.yee.ng
@ 2026-11-06  6:22   ` sashiko-bot
  0 siblings, 0 replies; 7+ messages in thread
From: sashiko-bot @ 2026-11-06  6:22 UTC (permalink / raw)
  To: tze.yee.ng, devicetree; +Cc: robh, conor+dt

Thank you for your contribution! Sashiko AI review found 1 potential
issue to consider:
- [Low] mmc: sdhci-cadence6: missing Fixes trailer for commit
  882fb340a956
--

commit a251f955cff38a0f481d2f8c32d309cec95d2889
Author: Tze Yee Ng <tze.yee.ng@altera.com>

> mmc: sdhci-cadence6: program PHONY_DQS_TIMING for extended-read DDR
>
> 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).
>
> On this integration the rebar pulse is 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.
>
> Acked-by: Adrian Hunter <adrian.hunter@intel.com>
> Signed-off-by: Tze Yee Ng <tze.yee.ng@altera.com>

[Severity: Low]
Since this fixes a hardware programming defect in extended-read DDR modes
introduced when SD6HC support was added, should this include:

  Fixes: 882fb340a956 ("mmc: sdhci-cadence: add Cadence SD6HC support")

-- 
Sashiko AI review · https://sashiko.dev/#/patchset/20261106-sd_cadence_ddr50_v3-v3-0-cb50afece614@altera.com?part=2

^ permalink raw reply	[flat|nested] 7+ messages in thread

* Re: [PATCH v3 3/4] dt-bindings: mmc: cdns,sd6hc: add SD6HC DDR50 read-path tuning
  2026-11-06  6:16 ` [PATCH v3 3/4] dt-bindings: mmc: cdns,sd6hc: add SD6HC DDR50 read-path tuning tze.yee.ng
@ 2026-11-06 12:40   ` Krzysztof Kozlowski
  0 siblings, 0 replies; 7+ messages in thread
From: Krzysztof Kozlowski @ 2026-11-06 12:40 UTC (permalink / raw)
  To: tze.yee.ng
  Cc: Tanmay Kathpalia, Adrian Hunter, linux-mmc, linux-kernel,
	Rob Herring, Krzysztof Kozlowski, Conor Dooley, devicetree,
	Ulf Hansson

On Fri, Nov 06, 2026 at 02:16:54PM +0800, tze.yee.ng@altera.com wrote:
> From: Tze Yee Ng <tze.yee.ng@altera.com>
> 
> DDR50 has no CMD19 tuning, so the SD6HC read path must be centred by
> static, board/SoC-characterised PHY settings. Add three optional SD6HC
> properties for the extended-read DDR modes (SD DDR50 and eMMC DDR52):
> 
>   - cdns,ddr-read-dqs-delay:    read-DQS delay as a count of DLL delay
>     elements (0-255), each cdns,delay-element-ps wide, that centres the
>     read eye (default 0).
>   - cdns,ddr-no-lpbk-dqs:       disable the loopback DQS read strobe and
>     use the fabricated phony DQS instead. Loopback DQS is the recommended
>     default; set this only on boards that need the phony DQS read path.
>   - cdns,ddr-phony-dqs-timing:  PHY_CTRL[9:4] phony DQS assertion timing.
>     The driver derives this from the RE# pulse width; this property
>     overrides the computed value for boards whose flight time shifts the
>     DDR data return.
> 
> Signed-off-by: Tze Yee Ng <tze.yee.ng@altera.com>
> ---
> Changes in v3:

Reviewed-by: Krzysztof Kozlowski <krzysztof.kozlowski@oss.qualcomm.com>

Best regards,
Krzysztof


^ permalink raw reply	[flat|nested] 7+ messages in thread

end of thread, other threads:[~2026-11-06 12:40 UTC | newest]

Thread overview: 7+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-11-06  6:16 [PATCH v3 0/4] mmc: sdhci-cadence: SD6HC DDR50/DDR52 read-path tuning and fixes tze.yee.ng
2026-11-06  6:16 ` [PATCH v3 1/4] mmc: sdhci-cadence: abort failed tuning command on SD6HC tze.yee.ng
2026-11-06  6:16 ` [PATCH v3 2/4] mmc: sdhci-cadence6: program PHONY_DQS_TIMING for extended-read DDR tze.yee.ng
2026-11-06  6:22   ` sashiko-bot
2026-11-06  6:16 ` [PATCH v3 3/4] dt-bindings: mmc: cdns,sd6hc: add SD6HC DDR50 read-path tuning tze.yee.ng
2026-11-06 12:40   ` Krzysztof Kozlowski
2026-11-06  6:16 ` [PATCH v3 4/4] mmc: sdhci-cadence6: read SD6HC DDR50 tuning from device tree tze.yee.ng

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.