From daeff6d5e63f0435fad0bcfcf7bdf55c73d6e0fc Mon Sep 17 00:00:00 2001 From: liquidraver <504870+liquidraver@users.noreply.github.com> Date: Tue, 11 Aug 2026 13:57:49 +0200 Subject: [PATCH] defer qspi bringup to when we really need it --- .../adapters/datastore/ZephyrDataStore.cpp | 19 +++++++++++++++++++ .../meshtracker_x1_nrf52840.dts | 16 +++++++++++++++- zephcore/helpers/qspi_probe.c | 18 ++++++++++++++++++ 3 files changed, 52 insertions(+), 1 deletion(-) diff --git a/zephcore/adapters/datastore/ZephyrDataStore.cpp b/zephcore/adapters/datastore/ZephyrDataStore.cpp index 157402e..618ddf1 100644 --- a/zephcore/adapters/datastore/ZephyrDataStore.cpp +++ b/zephcore/adapters/datastore/ZephyrDataStore.cpp @@ -110,6 +110,25 @@ bool ZephyrDataStore::mount() * on /ext. Without this the store silently falls back to internal /lfs, * and the next boot that does mount /ext runs a needless contact * migration — the "Migrating contacts to external storage" churn. */ +#if DT_NODE_HAS_PROP(DT_COMPAT_GET_ANY_STATUS_OKAY(nordic_qspi_nor), zephyr_deferred_init) + /* The flash is deferred-init: probing it at boot raced its own + * power rail and the JEDEC read came back 00 00 00, so the + * driver failed and /ext could never mount. Initialising it here + * instead means the part has had until first use to wake up — + * over a second — rather than us guessing a settling delay. */ + { + const struct device *qspi_dev = + DEVICE_DT_GET(DT_COMPAT_GET_ANY_STATUS_OKAY(nordic_qspi_nor)); + + if (!device_is_ready(qspi_dev)) { + int drc = device_init(qspi_dev); + + LOG_INF("QSPI flash deferred init: rc=%d ready=%d", + drc, (int)device_is_ready(qspi_dev)); + } + } +#endif + FS_FSTAB_DECLARE_ENTRY(DT_NODELABEL(qspi_lfs)); int rc = fs_mount(&FS_FSTAB_ENTRY(DT_NODELABEL(qspi_lfs))); if (is_mounted(extMountPoint())) { diff --git a/zephcore/boards/nrf52840/meshtracker_x1/meshtracker_x1_nrf52840.dts b/zephcore/boards/nrf52840/meshtracker_x1/meshtracker_x1_nrf52840.dts index b1840f3..e7f320f 100644 --- a/zephcore/boards/nrf52840/meshtracker_x1/meshtracker_x1_nrf52840.dts +++ b/zephcore/boards/nrf52840/meshtracker_x1/meshtracker_x1_nrf52840.dts @@ -113,7 +113,13 @@ regulator-name = "flash-power"; enable-gpios = <&gpio0 15 GPIO_ACTIVE_HIGH>; regulator-boot-on; - startup-delay-us = <10000>; + /* Documents the part's requirement, but do not rely on it: + * regulator_fixed_init() drives the enable GPIO active and then + * passes is_enabled=true into regulator_common_init(), which + * takes the refcount-only branch — regulator_delay() sits on the + * other one and never runs. The flash gets its settling time + * from deferred init instead (see the qspi_flash node). */ + startup-delay-us = <100000>; }; /* P1.06 — gates the battery ADC divider, enabled on demand */ @@ -328,6 +334,14 @@ qspi_flash: qspi_flash@0 { compatible = "nordic,qspi-nor"; reg = <0>; + /* Do not probe this at boot. The rail is switched on by + * flash-power a few init priorities earlier, and the part is not + * driving the bus yet when the driver's JEDEC read goes out — + * it answers 00 00 00 at 0.4 s and a correct c8 40 17 by 5.9 s + * on the very same boot. A fixed settling delay would only be a + * guess at where in between it wakes; instead the driver is + * initialised on demand, when the store first mounts /ext. */ + zephyr,deferred-init; writeoc = "pp4io"; readoc = "read4io"; sck-frequency = <16000000>; diff --git a/zephcore/helpers/qspi_probe.c b/zephcore/helpers/qspi_probe.c index 1f25168..e343b2e 100644 --- a/zephcore/helpers/qspi_probe.c +++ b/zephcore/helpers/qspi_probe.c @@ -24,6 +24,7 @@ #include #include #include +#include #include #if IS_ENABLED(CONFIG_ZEPHCORE_QSPI_RDID_PROBE) && \ @@ -81,6 +82,23 @@ static int qspi_rdid_probe(void) flash->name, (int)flash->state->init_res, P_SCK, P_CSN, P_IO0, P_IO1); +#if DT_NODE_EXISTS(DT_NODELABEL(flash_power)) + /* The driver reading 00 00 00 says the part was not driving the bus, + * which is either "the rail never came up" or "it came up too late". + * Those need opposite fixes, and the supply state here separates them: + * enabled now but the JEDEC read failed means the rail is fine and the + * startup delay is short. */ + { + const struct device *supply = + DEVICE_DT_GET(DT_NODELABEL(flash_power)); + + LOG_INF("flash supply '%s': ready=%d enabled=%d", + supply->name, (int)device_is_ready(supply), + device_is_ready(supply) + ? (int)regulator_is_enabled(supply) : -1); + } +#endif + gpio_pin_configure(p0, P_CSN, GPIO_OUTPUT_HIGH); gpio_pin_configure(p0, P_SCK, GPIO_OUTPUT_LOW); gpio_pin_configure(p0, P_IO0, GPIO_OUTPUT_LOW);