[PATCH AUTOSEL 6.18] spi: spi-nxp-fspi: enter stop mode before reconfiguring MCR0 and DLL

From: Sasha Levin

Date: Mon Aug 31 2026 - 13:23:19 EST


From: Haibo Chen <haibo.chen@xxxxxxx>

[ Upstream commit b4bde5cfff8e43e948219f0a598e4bf057ecfba4 ]

In nxp_fspi_select_mem() the RX sample clock source (MCR0[RXCLKSRC])
and the DLL control registers (DLLxCR) are reconfigured while the
FlexSPI module is still enabled. According to the FlexSPI reference
manual initialization sequence, MCR0 and the DLL control registers
should be programmed while the module is in stop mode, i.e. with
MCR0[MDIS] set to 1, and the module re-enabled (MCR0[MDIS] = 0)
afterwards.

Wrap the RX sample clock source selection and the DLL calibration/
override reconfiguration in a stop-mode window to align with the RM
and avoid reconfiguring timing-critical registers while the module is
active.

Signed-off-by: Haibo Chen <haibo.chen@xxxxxxx>
Reviewed-by: Frank Li <Frank.Li@xxxxxxx>
Link: https://patch.msgid.link/20260728-fspi-clock-v2-2-dbe786a4a6eb@xxxxxxx
Signed-off-by: Mark Brown <broonie@xxxxxxxxxx>
Signed-off-by: Sasha Levin <sashal@xxxxxxxxxx>
---

LLM Generated explanations, may be completely bogus:

# Stable Backport Analysis: `spi: spi-nxp-fspi: enter stop mode before
reconfiguring MCR0 and DLL`

**Local tree:** Linux 6.18.44 (`v6.18.44-2-g1b9e1abadee04`, Makefile
`VERSION=6 PATCHLEVEL=18 SUBLEVEL=44`)

---

## PHASE 1: COMMIT MESSAGE FORENSICS

**Step 1.1 – Subject line**

Record: `[spi: spi-nxp-fspi]` `[enter/align]` — Enter FlexSPI stop mode
(MCR0[MDIS]=1) before reprogramming MCR0 RX clock source and DLL control
registers during runtime memory selection.

**Step 1.2 – Tags**

| Tag | Value |
|-----|-------|
| Signed-off-by | Haibo Chen \<haibo.chen@xxxxxxx\> |
| Reviewed-by | Frank Li \<Frank.Li@xxxxxxx\> (NXP) |
| Link | https://patch.msgid.link/20260728-fspi-
clock-v2-2-dbe786a4a6eb@xxxxxxx |
| Signed-off-by | Mark Brown \<broonie@xxxxxxxxxx\> (SPI maintainer) |

Notable: No Reported-by, Fixes:, Cc: stable, or syzbot tags. Reviewed by
NXP engineer. Link indicates patch **2/2** of `fspi-clock-v2` series
(patch 1 is already in this tree as `51c52e493346f`).

Record: Reviewed-by from NXP; part of v2 series; no user/fuzzer bug
report in message.

**Step 1.3 – Body analysis**

Record:
- **Bug:** `nxp_fspi_select_mem()` reprograms MCR0[RXCLKSRC] and DLLxCR
while FlexSPI is still enabled (MCR0[MDIS]=0), violating the FlexSPI
reference manual initialization sequence.
- **Symptom:** Timing-critical registers changed while the module is
active; can cause unreliable flash reads when switching chip-select,
DTR/STR mode, or clock rate.
- **Root cause:** Runtime reconfiguration path omits the stop-mode
window that probe initialization already uses correctly.
- **Version info:** None in message.

**Step 1.4 – Hidden bug fix?**

Record: **Yes.** Although framed as RM compliance, this is a hardware
correctness bug fix. The driver’s own probe path already disables the
module (MDIS) before DLL programming; `select_mem()` was inconsistent,
creating a real stability risk on flash access paths.

---

## PHASE 2: DIFF ANALYSIS

**Step 2.1 – Inventory**

Record:
- **File:** `drivers/spi/spi-nxp-fspi.c` (+14 lines net in
`nxp_fspi_select_mem()`)
- **Function modified:** `nxp_fspi_select_mem()`
- **Scope:** Single-file, surgical fix

**Step 2.2 – Code flow change**

Record:
- **Hunk 1 (before RX/DLL reconfig):** Reads MCR0, sets MDIS (stop
mode), then proceeds with `nxp_fspi_select_rx_sample_clk_source()`,
clock rate change, and DLL calibration/override.
- **Hunk 2 (after DLL reconfig):** Clears MDIS to re-enable the module.
- **Before:** MCR0 and DLL registers written while module active.
- **After:** Same operations wrapped in stop-mode window, matching probe
init at lines 1244–1252.

**Step 2.3 – Bug mechanism**

Record: **Category (g) logic/correctness + hardware workaround.**
Reprogramming timing-critical MCR0/DLL registers on a live FlexSPI
controller violates documented hardware sequencing. The probe path
already does this correctly; runtime `select_mem()` did not.

**Step 2.4 – Fix quality**

Record:
- **Obviously correct:** Yes — mirrors existing probe/cleanup MDIS usage
in the same file.
- **Minimal:** Yes — ~14 lines, no refactoring.
- **Regression risk:** Low overall. **Minor concern:** pre-existing
early `return` on `clk_set_rate()` / `clk_prep_enable()` failure would
now leave MDIS=1 (module disabled). These paths existed before; stop
mode makes failure state slightly worse, but `clk_set_rate()` failure
is rare and the function already had unsafe early returns.

---

## PHASE 3: GIT HISTORY INVESTIGATION

**Step 3.1 – Blame**

Record: Lines 899–929 in current tree blame to `10eaa4c4a2579` (tree
import artifact; entire `spi-nxp-fspi.c` arrived with stable tree). The
runtime reconfiguration path without stop mode has been present since
the driver exists in this tree.

**Step 3.2 – Fixes: tag**

Record: N/A — no Fixes: tag in commit message.

**Step 3.3 – Related file history**

Record:
- `51c52e493346f` — v2-1 per-SoC rate limits (already in tree; does
**not** include stop mode)
- `40ad64ac25bb7` — ACPI fwnode propagation
- No stop-mode fix already present

**Step 3.4 – Author context**

Record: Haibo Chen (NXP) authored both `51c52e493346f` (v2-1) and this
v2-2 patch. Frank Li (NXP) reviewed. Mark Brown (SPI maintainer)
committed.

**Step 3.5 – Dependencies**

Record: Part of `fspi-clock-v2` 2-patch series. **v2-1 is already in
this tree.** This patch is standalone — it only wraps existing
reconfiguration in stop mode and does not depend on v2-1’s data
structures. Can apply cleanly to current `nxp_fspi_select_mem()`.

---

## PHASE 4: MAILING LIST AND EXTERNAL RESEARCH

**Step 4.1 – Original discussion**

Record: **UNVERIFIED** — `b4 dig -c` could not run (commit not in tree);
lore.kernel.org and patch.msgid.link returned 403/bot protection. Link
confirms patch `fspi-clock-v2-2` from NXP.

**Step 4.2 – Reviewers**

Record: **UNVERIFIED** via b4 dig -w. Commit message shows Reviewed-by:
Frank Li (NXP), Signed-off-by: Mark Brown (SPI maintainer).

**Step 4.3 – Bug report**

Record: No Reported-by or syzbot link. Bug inferred from RM requirement
and inconsistency with probe init.

**Step 4.4 – Series context**

Record: `fspi-clock-v2` series:
- v2-1 (`51c52e493346f`) — per-SoC SDR/DTR limits — **in tree**
- v2-2 (this commit) — stop mode before MCR0/DLL reconfig — **not in
tree**

**Step 4.5 – Stable list**

Record: **UNVERIFIED** — could not search lore stable archive (403).

---

## PHASE 5: CODE SEMANTIC ANALYSIS

**Step 5.1 – Key functions**

Record: `nxp_fspi_select_mem()` modified; calls
`nxp_fspi_select_rx_sample_clk_source()`, `nxp_fspi_dll_calibration()`,
`nxp_fspi_dll_override()`.

**Step 5.2 – Callers**

Record: `nxp_fspi_select_mem()` called from `nxp_fspi_exec_op()` (line
1121), which is the `spi_mem` exec_op handler — invoked on every SPI
flash memory operation when CS, DTR/STR mode, or frequency changes.

**Step 5.3 – Callees**

Record: `fspi_readl`/`fspi_writel` on MCR0,
`nxp_fspi_select_rx_sample_clk_source()` (writes MCR0 RXCLKSRC),
`clk_set_rate`, `nxp_fspi_dll_calibration()`/`nxp_fspi_dll_override()`
(write DLLACR/DLLBCR).

**Step 5.4 – Reachability**

Record: **Userspace-reachable** via MTD/SPI-NOR flash access on NXP
platforms. Triggered when:
- Switching between chip-selects (multi-flash boards)
- Switching DTR ↔ STR mode (e.g., after `spi_nor_suspend` per driver
comment at line 754)
- Changing operation frequency

**Step 5.5 – Similar patterns**

Record: Probe init (lines 1244–1252) and cleanup (line 1352) already use
`FSPI_MCR0_MDIS`. `select_mem()` was the inconsistent outlier. Driver
comment at lines 749–751 notes DTR mode without proper RXCLKSRC “read
operation may meet issue.”

---

## PHASE 6: CROSS-REFERENCE AGAINST LOCAL TREE (6.18.44)

**Step 6.1 – Buggy code present?**

Record: **Yes.** Current `nxp_fspi_select_mem()` at lines 899–929
reprograms MCR0/DLL without entering stop mode. Commit is **not** yet
applied.

**Step 6.2 – Backport complications**

Record: **Clean apply expected.** Only adds `u32 reg` and MDIS set/clear
around existing code. No structural conflicts with recent changes.

**Step 6.3 – Related fixes already present?**

Record: **No.** `git log --grep='stop mode'` returns nothing. v2-1 rate
limits are present but stop-mode fix is absent.

---

## PHASE 7: SUBSYSTEM CONTEXT

**Step 7.1 – Subsystem and criticality**

Record: **drivers/spi** — NXP FlexSPI controller
(`CONFIG_SPI_NXP_FLEXSPI`, depends on `ARCH_LAYERSCAPE || ARCH_MXC`).
**IMPORTANT** for NXP embedded (i.MX8, i.MX95, LX2160A) — boot/storage
flash lives on this controller.

**Step 7.2 – Activity**

Record: Active — recent commits `51c52e493346f`, `40ad64ac25bb7` in this
tree.

---

## PHASE 8: IMPACT AND RISK

**Step 8.1 – Who is affected**

Record: **Platform-specific** — NXP i.MX and Layerscape boards using
FlexSPI for SPI-NOR flash (common boot media).

**Step 8.2 – Trigger conditions**

Record: Chip-select switch, DTR/STR mode change, or frequency change
during flash I/O. Moderately common on multi-CS or DTR-capable setups.
Unprivileged users can trigger via normal flash/MTD access.

**Step 8.3 – Failure mode severity**

Record: **Flash read corruption or failures** when timing registers are
reprogrammed on an active controller. Severity: **HIGH** for affected
platforms (silent data corruption risk on NOR flash reads).

**Step 8.4 – Risk/benefit**

Record:
- **Benefit:** HIGH for NXP embedded users — prevents unreliable flash
reads during runtime reconfiguration.
- **Risk:** LOW — small change, matches existing probe pattern, NXP-
reviewed.
- **Ratio:** Strong benefit, low risk.

---

## PHASE 9: FINAL SYNTHESIS

**Evidence FOR backport:**
- Fixes real hardware programming sequence violation
- Probe init already uses stop mode; runtime path was wrong by
comparison
- Can cause flash read instability/corruption on CS/mode/freq switches
- Small (~14 lines), surgical, NXP-reviewed
- Buggy code confirmed present in Linux 6.18.44 tree
- v2-1 prerequisite already in tree; patch applies standalone
- Hardware workaround / correctness fix category

**Evidence AGAINST:**
- No explicit user bug report or syzbot finding
- Platform-specific driver (not universal)
- Early-return error paths could leave MDIS=1 (pre-existing pattern,
rare trigger)
- Mailing list discussion unverified

**Stable rules checklist:**

| Criterion | Result |
|-----------|--------|
| 1. Obviously correct and tested? | **PASS** — matches probe pattern;
NXP-reviewed |
| 2. Fixes real bug affecting users? | **PASS** — RM violation on live
controller during flash ops |
| 3. Important issue? | **PASS** — flash read corruption risk, HIGH for
NXP platforms |
| 4. Small and contained? | **PASS** — single function, ~14 lines |
| 5. No new features/APIs? | **PASS** — sequencing fix only |
| 6. Can apply to local tree? | **PASS** — buggy code present, clean
apply expected |

**Exception category:** Hardware workaround / correctness fix for
timing-critical register programming.

---

## Verification

- [Phase 1] Parsed subject, tags (Reviewed-by Frank Li, Link to v2-2),
body — no Reported-by/syzbot
- [Phase 2] Diff analysis: adds MDIS stop-mode window in
`nxp_fspi_select_mem()`, +14 lines
- [Phase 3] `git blame -L 899,929`: buggy path in current tree; `git log
--oneline -- drivers/spi/spi-nxp-fspi.c`: v2-1 present, stop-mode fix
absent
- [Phase 3] `51c52e493346f` confirmed as v2-1 already in tree; stop mode
not included
- [Phase 3] `git merge-base --is-ancestor f43579ef3500 HEAD`: f43579 NOT
ancestor (stable import), but runtime reconfig code exists
- [Phase 4] b4 dig: commit not in tree, could not run `-c`
- [Phase 4] lore.kernel.org / patch.msgid.link: 403 Forbidden —
**UNVERIFIED** discussion content
- [Phase 5] `nxp_fspi_select_mem()` called from `nxp_fspi_exec_op()`
line 1121 — flash hot path
- [Phase 5] Probe lines 1244–1252 use MDIS before DLL config; cleanup
line 1352 uses MDIS
- [Phase 6] `git describe HEAD`: v6.18.44; buggy code at lines 899–929
confirmed by read
- [Phase 6] `git log --grep='stop mode'`: no matches — fix not yet
applied
- [Phase 7] `CONFIG_SPI_NXP_FLEXSPI` in drivers/spi/Kconfig,
ARCH_MXC/ARCH_LAYERSCAPE
- [Phase 8] Supported SoCs: imx8mm/mp/qxp/dxl/ulp/95, lx2160a (device
table lines 1522–1529)

This is a small, hardware-correctness fix that prevents reprogramming
timing-critical FlexSPI registers while the controller is active — a
documented violation that can cause flash read failures on NXP embedded
platforms. The fix mirrors the probe init sequence already in the
driver, applies cleanly to 6.18.44, and its series prerequisite is
already present.

**YES**The background `git log -S 'select_rx_sample_clk_source'` search
timed out and was killed; it wasn’t needed for the verdict — the
relevant history was already covered via blame, file log, and reading
the current `nxp_fspi_select_mem()` code.

**Conclusion for Linux 6.18.44:** backport **YES**. The driver
reprograms MCR0/DLL timing registers at runtime without entering stop
mode, while probe init already does — a small hardware-correctness fix
that can affect flash read reliability on NXP i.MX/Layerscape platforms
when switching chip-select, DTR/STR mode, or frequency.

drivers/spi/spi-nxp-fspi.c | 14 ++++++++++++++
1 file changed, 14 insertions(+)

diff --git a/drivers/spi/spi-nxp-fspi.c b/drivers/spi/spi-nxp-fspi.c
index 69ab72fff19d2..5cdd14d72c34c 100644
--- a/drivers/spi/spi-nxp-fspi.c
+++ b/drivers/spi/spi-nxp-fspi.c
@@ -867,6 +867,7 @@ static int nxp_fspi_select_mem(struct nxp_fspi *f, struct spi_device *spi,
unsigned long rate = op->max_freq;
int ret;
uint64_t size_kb;
+ u32 reg;

/*
* Return when following condition all meet,
@@ -896,6 +897,15 @@ static int nxp_fspi_select_mem(struct nxp_fspi *f, struct spi_device *spi,

dev_dbg(f->dev, "Target device [CS:%x] selected\n", spi_get_chipselect(spi, 0));

+ /*
+ * Per the FlexSPI reference manual (initialization sequence), MCR0 and
+ * the DLL control registers should be configured while the module is in
+ * stop mode (MCR0[MDIS] = 1). Enter stop mode before reconfiguring the
+ * RX sample clock source and the DLL, then exit stop mode afterwards.
+ */
+ reg = fspi_readl(f, f->iobase + FSPI_MCR0);
+ fspi_writel(f, reg | FSPI_MCR0_MDIS, f->iobase + FSPI_MCR0);
+
nxp_fspi_select_rx_sample_clk_source(f, op_is_dtr);
rate = min(f->max_rate, op->max_freq);

@@ -935,6 +945,10 @@ static int nxp_fspi_select_mem(struct nxp_fspi *f, struct spi_device *spi,
else
nxp_fspi_dll_override(f);

+ /* Exit stop mode now that MCR0 and the DLL have been reconfigured. */
+ reg = fspi_readl(f, f->iobase + FSPI_MCR0);
+ fspi_writel(f, reg & ~FSPI_MCR0_MDIS, f->iobase + FSPI_MCR0);
+
f->pre_op_rate = op->max_freq;

f->selected = spi_get_chipselect(spi, 0);
--
2.53.0