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 v5 00/17] spi: cadence-quadspi: add PHY tuning support
Date: Sat, 18 Jul 2026 00:20:59 +0530 [thread overview]
Message-ID: <20260717185116.2065505-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
- Patch 5: Add execute_tuning callback to spi_controller_mem_ops and
spi_mem_execute_tuning() wrapper in SPI-MEM core
Cadence QSPI Implementation (6-13):
- 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; split the transfer into an
unaligned head, a 16-byte-aligned middle section with PHY
active, and an unaligned tail; 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
MTD core (14-17):
- Patch 14: Extract spinand_select_op_variant() into a shared helper
spinand_op_find_best_variant() with a skip_mask
- Patch 15: Negotiate optimal controller operating point before dirmap
creation; iterate all read variants in performance order
across ODTR and SSDR interfaces
- Patch 16: Extract spi_nor_spimem_get_read_op() helper (preparatory)
- Patch 17: 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/0b9b5f94411c655f3edaff91f1c319d8
Repo: https://github.com/santhosh21/linux/commits/phy_tuning_v5
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 (16):
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
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 | 12 +
drivers/mtd/nand/spi/core.c | 238 +-
drivers/mtd/spi-nor/core.c | 80 +-
drivers/spi/spi-cadence-quadspi.c | 2232 +++++++++++++++--
drivers/spi/spi-mem.c | 40 +
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, 2467 insertions(+), 185 deletions(-)
--
2.34.1
next reply other threads:[~2026-07-17 18:52 UTC|newest]
Thread overview: 18+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-07-17 18:50 Santhosh Kumar K [this message]
2026-07-17 18:51 ` [PATCH v5 01/17] spi: dt-bindings: add spi-max-post-config-frequency-hz property Santhosh Kumar K
2026-07-17 18:51 ` [PATCH v5 02/17] spi: dt-bindings: add spi-phy-pattern-partition property Santhosh Kumar K
2026-07-17 18:51 ` [PATCH v5 03/17] spi: parse spi-max-post-config-frequency-hz into post_config_max_speed_hz Santhosh Kumar K
2026-07-17 18:51 ` [PATCH v5 04/17] spi: spi-mem: teach spi_mem_adjust_op_freq() about post-config ops Santhosh Kumar K
2026-07-17 18:51 ` [PATCH v5 05/17] spi: spi-mem: add execute_tuning callback and spi_mem_execute_tuning() Santhosh Kumar K
2026-07-17 18:51 ` [PATCH v5 06/17] spi: cadence-quadspi: move cqspi_readdata_capture earlier Santhosh Kumar K
2026-07-17 18:51 ` [PATCH v5 07/17] spi: cadence-quadspi: add DQS support to read data capture Santhosh Kumar K
2026-07-17 18:51 ` [PATCH v5 08/17] spi: cadence-quadspi: add PHY tuning support Santhosh Kumar K
2026-07-17 18:51 ` [PATCH v5 09/17] spi: cadence-quadspi: skip DDR PHY tuning for 2-byte-address ops (i2383) Santhosh Kumar K
2026-07-17 18:51 ` [PATCH v5 10/17] spi: cadence-quadspi: refactor direct read path for PHY support Santhosh Kumar K
2026-07-17 18:51 ` [PATCH v5 11/17] spi: cadence-quadspi: enable PHY for direct reads Santhosh Kumar K
2026-07-17 18:51 ` [PATCH v5 12/17] spi: cadence-quadspi: enable PHY for indirect writes Santhosh Kumar K
2026-07-17 18:51 ` [PATCH v5 13/17] spi: cadence-quadspi: reprogram CS timing on every chip-select switch Santhosh Kumar K
2026-07-17 18:51 ` [PATCH v5 14/17] mtd: spinand: extract variant ranking logic into spinand_op_find_best_variant() Santhosh Kumar K
2026-07-17 18:51 ` [PATCH v5 15/17] mtd: spinand: negotiate optimal controller operating point before dirmap creation Santhosh Kumar K
2026-07-17 18:51 ` [PATCH v5 16/17] mtd: spi-nor: extract read op template construction into helper Santhosh Kumar K
2026-07-17 18:51 ` [PATCH v5 17/17] 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=20260717185116.2065505-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