From: Igor Velkov <[email protected]>

'sf probe <bus>:<cs> <speed>' ignores the speed for a flash that has a
device tree node: the probe, and with it the JEDEC ID read, runs at
spi-max-frequency, and the requested speed reaches the controller only
after it.

On ROCK Pi 4A the device tree sets spi-max-frequency = <108000000> and
the flash does not answer at the resulting clock, at any requested
speed:

  => sf probe 1:0 1000000
  jedec_spi_nor flash@0: unrecognized JEDEC id bytes: ff, ff, ff

Before the probe, set the requested speed in the platform data of the
device, as _spi_get_bus_and_cs() already does for a device it binds
without a device tree node, and restore the saved value right after it,
so the platform data ends up unchanged. slave->mode keeps the device
tree value. A speed above spi-max-frequency is honoured, as it already
is after the probe. Only sf probe with an explicit speed changes: sf
probe without one and the other spi_flash_probe() callers still probe a
device tree flash at spi-max-frequency.

With this change:

  => sf probe 1:0 1000000
  SF: Detected xt25f32 with page size 256 Bytes, erase size 4 KiB, total 4 MiB

Add a sandbox test for it.

Signed-off-by: Igor Velkov <[email protected]>
---
Tested in sandbox (the new test fails without the change) and on ROCK
Pi 4A with U-Boot proper chainloaded: without the change sf probe 1:0
at 1 and 10 MHz reads ff ff ff, with it the flash is detected.
---
Changes in v2:
- Move the override from _spi_get_bus_and_cs() to sf probe, so only an
  explicit speed from the shell changes; other callers keep probing at
  the DT speed (Simon)
- Override only max_hz and keep the DT mode (Simon)
- Test through sf probe on spi.bin@1 (spi-cpol, spi-cpha) that
  plat->max_hz and the DT mode bits survive (Simon)
- Drop the wrong v1 claim that the next bus claim returns to the DT speed
- Leave the post-probe spi_set_speed_mode() from e2e95e5e2542 as is:
  SF_DEFAULT_SPEED takes effect there, and 117 of 153 SPL_SPI_LOAD
  defconfigs set it
- Link to v1: 
https://lore.kernel.org/r/[email protected]
---
 cmd/sf.c     | 11 +++++++++++
 test/dm/sf.c | 29 +++++++++++++++++++++++++++++
 2 files changed, 40 insertions(+)

diff --git a/cmd/sf.c b/cmd/sf.c
index ec9ebde2aaf..7dabb4d1684 100644
--- a/cmd/sf.c
+++ b/cmd/sf.c
@@ -146,7 +146,18 @@ static int do_spi_flash_probe(int argc, char *const argv[])
                        }
                }
        } else {
+               struct dm_spi_slave_plat *plat = NULL;
+               uint saved_max_hz = 0;
+
+               /* Probe at the requested speed: the flash reads its ID there */
+               if (!ret && speed) {
+                       plat = dev_get_parent_plat(new);
+                       saved_max_hz = plat->max_hz;
+                       plat->max_hz = speed;
+               }
                flash = spi_flash_probe(bus, cs, speed, mode);
+               if (plat)
+                       plat->max_hz = saved_max_hz;
        }
 
        if (!flash) {
diff --git a/test/dm/sf.c b/test/dm/sf.c
index 0ec02ac694b..ea93f0b65b0 100644
--- a/test/dm/sf.c
+++ b/test/dm/sf.c
@@ -106,3 +106,32 @@ static int dm_test_spi_flash_func(struct unit_test_state 
*uts)
        return 0;
 }
 DM_TEST(dm_test_spi_flash_func, UTF_SCAN_PDATA | UTF_SCAN_FDT);
+
+/* Test that 'sf probe' with a speed probes a DT flash at that speed */
+static int dm_test_spi_flash_probe_speed(struct unit_test_state *uts)
+{
+       struct dm_spi_slave_plat *plat;
+       struct spi_slave *slave;
+       struct udevice *bus, *dev;
+
+       /* spi.bin@1 has spi-max-frequency = <50000000>, spi-cpol and spi-cpha 
*/
+       ut_assertok(run_command("host save hostfs - 0 spi.bin 200000", 0));
+       ut_assertok(run_command("sf probe 0:1 1000000", 0));
+       ut_assertok(spi_find_bus_and_cs(0, 1, &bus, &dev));
+       slave = dev_get_parent_priv(dev);
+       plat = dev_get_parent_plat(dev);
+       ut_asserteq(1000000, slave->max_hz);
+       ut_asserteq(50000000, plat->max_hz);
+       ut_asserteq(SPI_CPOL | SPI_CPHA, slave->mode & (SPI_CPOL | SPI_CPHA));
+
+       /* Without a speed, the DT value applies again */
+       ut_assertok(run_command("sf probe 0:1", 0));
+       ut_assertok(spi_find_bus_and_cs(0, 1, &bus, &dev));
+       slave = dev_get_parent_priv(dev);
+       ut_asserteq(50000000, slave->max_hz);
+
+       sandbox_sf_unbind_emul(state_get_current(), 0, 1);
+
+       return 0;
+}
+DM_TEST(dm_test_spi_flash_probe_speed, UTF_SCAN_PDATA | UTF_SCAN_FDT);

---
base-commit: dfcfc4c9f78d1743f490a497082a4ec8e058aae8
change-id: 20260930-spi-probe-speed-1628c684e624

Best regards,
-- 
Igor Velkov <[email protected]>


Reply via email to