From: Santhosh Kumar K <s-k6@ti.com>
To: <broonie@kernel.org>, <robh@kernel.org>, <krzk+dt@kernel.org>,
<conor+dt@kernel.org>, <miquel.raynal@bootlin.com>,
<richard@nod.at>, <vigneshr@ti.com>, <pratyush@kernel.org>,
<mwalle@kernel.org>, <takahiro.kuwano@infineon.com>
Cc: <linux-spi@vger.kernel.org>, <devicetree@vger.kernel.org>,
<linux-kernel@vger.kernel.org>, <linux-mtd@lists.infradead.org>,
<praneeth@ti.com>, <u-kumar1@ti.com>, <a-dutta@ti.com>,
<s-k6@ti.com>
Subject: [PATCH v7 00/18] spi: cadence-quadspi: add PHY tuning support
Date: Wed, 12 Aug 2026 00:02:55 +0530 [thread overview]
Message-ID: <20260811183313.1550425-1-s-k6@ti.com> (raw)
This series implements PHY tuning support for the Cadence QSPI controller
to enable reliable high-speed operations. Without PHY tuning, controllers
use conservative timing that limits performance. PHY tuning calibrates
RX/TX delay lines to find optimal data capture timing windows, enabling
operation up to the controller's maximum frequency.
Background:
High-speed SPI memory controllers require precise timing calibration for
reliable operation. At higher frequencies, board-to-board variations make
fixed timing parameters inadequate. The Cadence QSPI controller includes
a PHY interface with programmable delay lines (0-127 taps) for RX and TX
paths, but these require runtime calibration to find the valid timing
window.
Approach:
Add SDR/DDR PHY tuning algorithms for the Cadence controller:
SDR Mode Tuning (1D search):
- Searches for two consecutive valid RX delay windows
- Selects the larger window and uses its midpoint for maximum margin
- TX delay fixed at maximum (127) as it's less critical in SDR
DDR Mode Tuning (2D search):
- Finds RX boundaries (rxlow/rxhigh) using TX window sweeps
- Finds TX boundaries (txlow/txhigh) at fixed RX positions
- Defines valid region corners and detects gaps via binary search
- Applies temperature compensation for optimal point selection
- Handles single or dual passing regions with different strategies
Patch description:
Infrastructure (1-5):
- Patch 1: Add spi-max-post-config-frequency-hz to describe maximum
frequency achievable post controller configuration
- Patch 2: Add spi-phy-pattern-partition phandle for
NOR flash PHY tuning pattern location
- Patch 3: Parse spi-max-post-config-frequency-hz in spi.c; adds
spi_device.post_config_max_speed_hz (0 when not set
keeping all existing DT fully compatible)
- Patch 4: Extend spi_mem_adjust_op_freq() with a bypass: if
op->max_freq equals post_config_max_speed_hz, return
immediately leaving op->max_freq unchanged. All other
ops are capped to max_speed_hz. Also require per_op_freq
controller capability for post-config ops in
spi_mem_default_supports_op()
- Patch 5: Add execute_tuning callback to spi_controller_mem_ops and
spi_mem_execute_tuning() wrapper in SPI-MEM core;
serialises access via spi_mem_access_start/end and
rejects GPIO chip selects
Cadence QSPI Implementation (6-14):
- Patch 6: Move cqspi_readdata_capture() earlier (preparatory)
- Patch 7: Add DQS bit to cqspi_readdata_capture() (preparatory)
- Patch 8: Add complete PHY tuning support: DLL management, pattern
verification (NOR via spi-phy-pattern-partition phandle,
NAND via write-to-cache), SDR 1D and DDR 2D search
algorithms with temperature compensation, AM654-specific
execute_tuning entry point
- Patch 9: Reject 2-byte-address DDR operations via a new
CQSPI_NO_PHY_TUNING_WITH_ODDR_2B_ADDR quirk flag to work
around AM654 OSPI erratum i2383
- Patch 10: Refactor direct read path for PHY support (preparatory)
- Patch 11: Enable PHY for direct reads at the calibrated frequency
when both transfer boundaries are 16-byte aligned,
falling back to non-PHY DMA otherwise; also reprograms
DLL on chip-select switch when two devices have
different calibrated settings
- Patch 12: Enable PHY for indirect writes of at least
CQSPI_PHY_MIN_INDIRECT_WRITE_LEN bytes
- Patch 13: Reprogram per-device CS timing on any chip-select switch
- Patch 14: Reprogram the PHY DLL (master config and RX/TX taps) on
runtime resume, since the DLL loses its lock when the
OSPI controller is power-gated
MTD core (15-18):
- Patch 15: Extract spinand_select_op_variant() into a shared helper
spinand_op_find_best_variant() with a skip_mask
- Patch 16: Negotiate optimal controller operating point before dirmap
creation; iterate all read variants in performance order
across ODTR and SSDR interfaces
- Patch 17: Extract spi_nor_spimem_get_read_op() helper (preparatory)
- Patch 18: Execute controller optimization in spi_nor_probe() before
creating dirmaps
Testing:
This series was tested on TI's
AM62Ax SK with OSPI NAND flash and
AM62Px SK with OSPI NOR flash:
Read throughput:
|----------------------------------------|
| | non-PHY | PHY |
|----------------------------------------|
| OSPI NOR (8D) | 37.5 MB/s | 218 MB/s |
|----------------------------------------|
| OSPI NAND (8S) | 9.2 MB/s | 35.6 MB/s |
|----------------------------------------|
Write throughput:
|----------------------------------------|
| | non-PHY | PHY |
|----------------------------------------|
| OSPI NAND (8S) | 6 MB/s | 9.2 MB/s |
|----------------------------------------|
Test log: https://gist.github.com/santhosh21/79c89e104e6d35c4071845293901e3ad
Repo: https://github.com/santhosh21/linux/commits/phy_tuning_v7/
Changes in v7:
- Serialise spi_mem_execute_tuning() with spi_mem_access_start/end and
reject GPIO chip-select configurations
- Fix cqspi_phy_apply_setting() to also write the calibrated
read_delay to CQSPI_REG_READCAPTURE, previously software-only
- Use local op copies for pattern write/verify instead of mutating
the caller's op templates in place
- Fix the READCAPTURE bypass bit in cqspi_tune_phy() to match the
value validated during calibration instead of being hardcoded
- Enable PHY before starting the indirect-write state machine instead
of after; the old order was a guaranteed deadlock
- Add a new patch to reprogram the PHY DLL on runtime resume
- Fix continuous-read and ODTR/SSDR template handling on ranked
fallback in spinand_try_ranked_variant(), preventing data
corruption after a fallback
- Fix other, smaller correctness issues raised by sashiko-bot
- Rebase on v7.2-rc7
- Link to v6: https://lore.kernel.org/linux-spi/20260723110219.3180747-1-s-k6@ti.com/
Changes in v6:
- Add maxItems to spi-max-post-config-frequency-hz property
- Rebase on v7.2-rc4
- Collect tag from Krzysztof
- Link to v5: https://lore.kernel.org/linux-spi/20260717185116.2065505-1-s-k6@ti.com/
Changes in v5:
- Rename spi-max-post-config-frequency to spi-max-post-config-frequency-hz
per DT schema unit suffix convention
- Rename CQSPI_NO_2BYTE_ADDR_PHY_DDR quirk to
CQSPI_NO_PHY_TUNING_WITH_ODDR_2B_ADDR for clarity
- Rename SPI NAND identifiers to remove PHY-specific terminology:
spinand_configure_phy() -> spinand_optimize_controller()
spinand_try_phy_ranked() -> spinand_try_ranked_variant()
spinand_reset_max_ops() -> spinand_reset_max_freq_ops()
spinand_op_find_best() -> spinand_op_find_best_variant()
phy_read_variants (field) -> all_read_variants
- Replace bool odtr parameter with enum spinand_bus_interface iface in
spinand_op_find_best_variant() to preserve the existing enumeration
- Replace cqspi_get_phy_pattern_offset() with per-flash probe-time
phandle lookup in cqspi_of_get_flash_pdata(); fixes incorrect pattern
offset selection when multiple flash devices share a controller
- In cqspi_tune_phy(), reprogramme and resync the DLL when the active
device's calibrated settings differ from hardware
- Edit cqspi_phy_apply_setting() to update phy_setting.rx and
phy_setting.tx alongside phy_setting.read_delay
- Reprogram per-device CS timing (CQSPI_REG_DELAY and read-capture register)
on any chip-select switch, not only on clock changes
- Move post_config_max_speed_hz early-return to the top of
spinand_optimize_controller(), before any state is modified
- Remove dead NULL guards on SSDR op templates in Pass 2
- Downgrade tuning-failure log messages from dev_warn to dev_dbg
- Rebase on v7.2-rc3
- Collect tags
- Link to v4: https://lore.kernel.org/linux-spi/20260618073725.84733-1-s-k6@ti.com/
Changes in v4:
- Add spi-max-post-config-frequency instead of extending spi-max-frequency
to accept an optional second value
- Replace spi_mem_apply_base_freq_cap() with spi_mem_adjust_op_freq() extension
- For SPI NOR/NAND, execute PHY tuning before the dirmap creation
- For SPI NAND, execute PHY tuning across all operation variants available,
perform duration comparison, and select the best resulting variant
by taking controller-specific restrictions into account
- Move i2383 check from cqspi_supports_mem_op() to cqspi_am654_ospi_execute_tuning()
- Rename cdns,phy-pattern-partition to spi-phy-pattern-partition,
cqspi_phy_enable to cqspi_tune_phy and f_pdata->use_phy to use_tuned_phy
- Remove redundant spi-max-frequency parsing in driver cqspi_of_get_flash_pdata()
- Extract DMA refactoring into a preparatory patch
- Rebase on v7.1
- Collect tags from Miquel
- Link to v3: https://lore.kernel.org/linux-spi/20260527175527.2247679-1-s-k6@ti.com/
Changes in v3:
- Drop spi-has-dqs DT property; DQS is now enabled automatically when
the selected read operation uses DDR signalling (dtr flags in the op)
- Extend spi-max-frequency to accept an optional second value forming a
[base-freq, max-freq] pair; the presence of two values signals PHY
tuning intent and encodes both the conservative base speed and the
calibration target in one property
- Add base_speed_hz to struct spi_device (spi.c/spi.h) and parse the
two-element array there; single-value DT is fully backward-compatible
- Move frequency enforcement from the cadence driver to core: new
spi_mem_apply_base_freq_cap() called from spi_mem_exec_op() replaces
the per-driver cqspi_op_matches_tuned() and non_phy_clk_rate field
- Propagate the tuned max_freq to dirmap op templates after
execute_tuning() succeeds; store persistent op templates in
spi_nor.max_read_op and spinand.{max_read,max_write}_op so the
frequency writeback survives across the probe call
- Replace NOR pattern partition lookup by name with a
cdns,phy-pattern-partition DT phandle pointing directly to the
partition node
- Add CQSPI_NO_2BYTE_ADDR_PHY_DDR quirk and reject 2-byte-address DDR
ops in cqspi_supports_mem_op() to work around AM654 erratum i2383
- Remove RFC tag
- Rebase on v7.1-rc5
- Collect tags from Miquel
- Link to v2: https://lore.kernel.org/linux-spi/20260113141617.1905039-1-s-k6@ti.com/
Changes in v2:
- Restructure the .execute_tuning() call from spi-mem clients instead
of mtdcore with best read_op and write_op (optional) passed
- Add compatible-specific .execute_tuning() call which can be called by
spi_mem_execute_tuning() if exists
- Handle tuning requirement check by controller instead of spi-mem
clients
- Add support to write the phy_pattern to cache if relevant write_op
is passed or get the partition offset which contains the phy_pattern
- Add tuning algorithm for DDR mode
- Add support for DQS
- Restrict PHY frequency to tuned operations
- Link to v1: https://lore.kernel.org/linux-spi/20250811193219.731851-1-s-k6@ti.com/
Signed-off-by: Santhosh Kumar K <s-k6@ti.com>
Pratyush Yadav (1):
mtd: spi-nor: extract read op template construction into helper
Santhosh Kumar K (17):
spi: dt-bindings: add spi-max-post-config-frequency-hz property
spi: dt-bindings: add spi-phy-pattern-partition property
spi: parse spi-max-post-config-frequency-hz into
post_config_max_speed_hz
spi: spi-mem: teach spi_mem_adjust_op_freq() about post-config ops
spi: spi-mem: add execute_tuning callback and spi_mem_execute_tuning()
spi: cadence-quadspi: move cqspi_readdata_capture earlier
spi: cadence-quadspi: add DQS support to read data capture
spi: cadence-quadspi: add PHY tuning support
spi: cadence-quadspi: skip DDR PHY tuning for 2-byte-address ops
(i2383)
spi: cadence-quadspi: refactor direct read path for PHY support
spi: cadence-quadspi: enable PHY for direct reads
spi: cadence-quadspi: enable PHY for indirect writes
spi: cadence-quadspi: reprogram CS timing on every chip-select switch
spi: cadence-quadspi: reprogram PHY DLL on runtime resume
mtd: spinand: extract variant ranking logic into
spinand_op_find_best_variant()
mtd: spinand: negotiate optimal controller operating point before
dirmap creation
mtd: spi-nor: run controller optimization before dirmap creation
.../bindings/spi/cdns,qspi-nor.yaml | 17 +
.../bindings/spi/spi-peripheral-props.yaml | 13 +
drivers/mtd/nand/spi/core.c | 253 +-
drivers/mtd/spi-nor/core.c | 80 +-
drivers/spi/spi-cadence-quadspi.c | 2280 +++++++++++++++--
drivers/spi/spi-mem.c | 55 +-
drivers/spi/spi.c | 2 +
include/linux/mtd/spi-nor.h | 3 +
include/linux/mtd/spinand.h | 11 +
include/linux/spi/spi-mem.h | 14 +
include/linux/spi/spi.h | 3 +
11 files changed, 2541 insertions(+), 190 deletions(-)
--
2.34.1
next reply other threads:[~2026-08-11 18:34 UTC|newest]
Thread overview: 19+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-08-11 18:32 Santhosh Kumar K [this message]
2026-08-11 18:32 ` [PATCH v7 01/18] spi: dt-bindings: add spi-max-post-config-frequency-hz property Santhosh Kumar K
2026-08-11 18:32 ` [PATCH v7 02/18] spi: dt-bindings: add spi-phy-pattern-partition property Santhosh Kumar K
2026-08-11 18:32 ` [PATCH v7 03/18] spi: parse spi-max-post-config-frequency-hz into post_config_max_speed_hz Santhosh Kumar K
2026-08-11 18:32 ` [PATCH v7 04/18] spi: spi-mem: teach spi_mem_adjust_op_freq() about post-config ops Santhosh Kumar K
2026-08-11 18:33 ` [PATCH v7 05/18] spi: spi-mem: add execute_tuning callback and spi_mem_execute_tuning() Santhosh Kumar K
2026-08-11 18:33 ` [PATCH v7 06/18] spi: cadence-quadspi: move cqspi_readdata_capture earlier Santhosh Kumar K
2026-08-11 18:33 ` [PATCH v7 07/18] spi: cadence-quadspi: add DQS support to read data capture Santhosh Kumar K
2026-08-11 18:33 ` [PATCH v7 08/18] spi: cadence-quadspi: add PHY tuning support Santhosh Kumar K
2026-08-11 18:33 ` [PATCH v7 09/18] spi: cadence-quadspi: skip DDR PHY tuning for 2-byte-address ops (i2383) Santhosh Kumar K
2026-08-11 18:33 ` [PATCH v7 10/18] spi: cadence-quadspi: refactor direct read path for PHY support Santhosh Kumar K
2026-08-11 18:33 ` [PATCH v7 11/18] spi: cadence-quadspi: enable PHY for direct reads Santhosh Kumar K
2026-08-11 18:33 ` [PATCH v7 12/18] spi: cadence-quadspi: enable PHY for indirect writes Santhosh Kumar K
2026-08-11 18:33 ` [PATCH v7 13/18] spi: cadence-quadspi: reprogram CS timing on every chip-select switch Santhosh Kumar K
2026-08-11 18:33 ` [PATCH v7 14/18] spi: cadence-quadspi: reprogram PHY DLL on runtime resume Santhosh Kumar K
2026-08-11 18:33 ` [PATCH v7 15/18] mtd: spinand: extract variant ranking logic into spinand_op_find_best_variant() Santhosh Kumar K
2026-08-11 18:33 ` [PATCH v7 16/18] mtd: spinand: negotiate optimal controller operating point before dirmap creation Santhosh Kumar K
2026-08-11 18:33 ` [PATCH v7 17/18] mtd: spi-nor: extract read op template construction into helper Santhosh Kumar K
2026-08-11 18:33 ` [PATCH v7 18/18] mtd: spi-nor: run controller optimization before dirmap creation Santhosh Kumar K
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20260811183313.1550425-1-s-k6@ti.com \
--to=s-k6@ti.com \
--cc=a-dutta@ti.com \
--cc=broonie@kernel.org \
--cc=conor+dt@kernel.org \
--cc=devicetree@vger.kernel.org \
--cc=krzk+dt@kernel.org \
--cc=linux-kernel@vger.kernel.org \
--cc=linux-mtd@lists.infradead.org \
--cc=linux-spi@vger.kernel.org \
--cc=miquel.raynal@bootlin.com \
--cc=mwalle@kernel.org \
--cc=praneeth@ti.com \
--cc=pratyush@kernel.org \
--cc=richard@nod.at \
--cc=robh@kernel.org \
--cc=takahiro.kuwano@infineon.com \
--cc=u-kumar1@ti.com \
--cc=vigneshr@ti.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox