From: Igor Velkov <[email protected]>

`sf probe <bus>:<cs> <speed>` ignores the speed for a flash that has a
device tree node. _spi_get_bus_and_cs() probes the device, and with it
the flash reads its JEDEC ID, at spi-max-frequency from the device tree.
The requested speed is set only after the probe, and the slave keeps
max_hz from the device tree, so the next claim of the bus goes back to
that frequency.

A device bound without a device tree node already gets the requested
speed and mode before the probe. Do the same for a device from the
device tree, for the duration of the probe.

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

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 from the running one.
---
 drivers/spi/spi-uclass.c |  9 +++++++++
 test/dm/spi.c            | 20 ++++++++++++++++++++
 2 files changed, 29 insertions(+)

diff --git a/drivers/spi/spi-uclass.c b/drivers/spi/spi-uclass.c
index 120565df149..097c1ae665e 100644
--- a/drivers/spi/spi-uclass.c
+++ b/drivers/spi/spi-uclass.c
@@ -517,8 +517,17 @@ int _spi_get_bus_and_cs(int busnum, int cs, int speed, int 
mode,
 
        if (!device_active(dev)) {
                struct spi_slave *slave;
+               uint dt_max_hz = plat->max_hz;
+               uint dt_mode = plat->mode;
 
+               /* Probe at the caller's speed and mode: a flash reads its ID 
here */
+               if (speed && !created) {
+                       plat->max_hz = speed;
+                       plat->mode = mode;
+               }
                ret = device_probe(dev);
+               plat->max_hz = dt_max_hz;
+               plat->mode = dt_mode;
                if (ret)
                        goto err;
                slave = dev_get_parent_priv(dev);
diff --git a/test/dm/spi.c b/test/dm/spi.c
index a89ba06274f..4ea4bcd1196 100644
--- a/test/dm/spi.c
+++ b/test/dm/spi.c
@@ -91,6 +91,26 @@ static int dm_test_spi_find(struct unit_test_state *uts)
 }
 DM_TEST(dm_test_spi_find, UTF_SCAN_PDATA | UTF_SCAN_FDT);
 
+/* Test that the first probe of a device from the DT uses the caller's speed */
+static int dm_test_spi_probe_speed(struct unit_test_state *uts)
+{
+       const int busnum = 0, cs = 0, mode = 0, speed = 1000000;
+       struct spi_slave *slave;
+       struct udevice *bus;
+
+       /* spi.bin@0 has spi-max-frequency = <40000000> */
+       ut_assertok(_spi_get_bus_and_cs(busnum, cs, speed, mode, NULL, NULL,
+                                       &bus, &slave));
+       ut_asserteq(speed, slave->max_hz);
+
+       ut_assertok(spi_claim_bus(slave));
+       ut_asserteq(speed, sandbox_spi_get_speed(bus));
+       spi_release_bus(slave);
+
+       return 0;
+}
+DM_TEST(dm_test_spi_probe_speed, UTF_SCAN_PDATA | UTF_SCAN_FDT);
+
 /* dm_test_spi_switch_slaves - Helper function to check whether spi_claim_bus
  *                             operates correctly with two spi slaves.
  *

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

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


Reply via email to