wbec: full-power-cycle request + warm reset / two-stage watchdog (WB7.4 + WB8.5)#91
wbec: full-power-cycle request + warm reset / two-stage watchdog (WB7.4 + WB8.5)#91evgeny-boger wants to merge 7 commits into
Conversation
Warm reset pulses the PMIC RESET (PWROK) line for 100 ms instead of cycling the 5V rail. On WB 8.5 the line is wired to both the AXP15060 PWROK pin and the T507 RESET pin; with PMIC restart-on-PWROK-low disabled (AXP REG32[4]=0, the power-on default) the pulse resets only the SoC while all PMIC rails, including DRAM power, stay up. DRAM contents survive, so ramoops panic logs can be read back after reboot. Validated on WB 8.5.1: 16 MB test pattern survived EC-driven PWROK reset bit-perfect. The feature is gated by WBEC_HAS_WARM_RESET, defined only in config_wb85.h: the pulse behavior is hardware-validated on WB 8.5 only, so WB74 keeps its exact previous behavior (immediate hard power cycle on watchdog timeout, 2 s PMIC RESET hold on the reset_pmic request). On WB85 the watchdog escalates in two stages: the first timeout triggers a warm reset (new appended poweron reason 8, REASON_WATCHDOG_WARM); if Linux does not feed the watchdog via regmap before the next timeout, the EC falls back to the original hard power cycle (REASON_WATCHDOG). Feeding the watchdog re-arms the warm stage; a timeout-only regmap write restarts the timer but deliberately does not re-arm it. On WB85 the reset_pmic request from Linux (POWER_CTRL bit 2) now performs the short-pulse warm reset instead of the 2 s hold. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01RiQPqJiM3ftEk3SDda31Kf
…light A watchdog timeout racing a 3.3V loss (or a reset_pmic request) in the same main loop pass started a second power sequence on top of the warm reset pulse already in flight. The pulse never completed, the PMIC RESET (PWROK) line stayed latched and the SoC was held in reset forever: 5V rail on, no SPL/U-Boot output ever, and no further watchdog recovery (the escalation was latched to hard resets, which did not release the line). Matches the failure observed on a WB 8.5.1 bench unit after a rapid kernel-hang reboot loop. The same race latched the line on WB74 via the reset_pmic request path. - wbec: allow only one power action per pass in WORKING; once a power sequence is started, defer the watchdog and 3.3V checks to the next passes (pending watchdog flags are not lost) - wbec: restart the escalation after a stage-2 hard reset so unfed timeouts alternate warm/hard; the first hang of every fresh boot gets a DRAM-preserving warm reset and ramoops stays readable - linux-power-control: hard_reset/hard_off/power-on always release the PMIC RESET (PWROK) line so no aborted sequence can leave it latched; a completed warm pulse turns 5V on before the power-on sequence - add wbec + linux-power-control + wdt integration test suite with a board model (PMIC/SoC/5V rail): reproduces the wedge, sweeps PMIC failure timing across all reset phases, asserts bounded recovery Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01EVPkc2g2yir6SGyrED6uNT
A host (specifically the WB8 U-Boot pstore shuttle, which saves the ramoops region to eMMC before asking for a power cycle) needs a way to request a guaranteed full 5V cycle that is distinguishable from a normal reboot in poweron_reason. - POWER_CTRL gains bit3 full_cycle; the region stays one 16-bit word, old hosts are unaffected (they never set the bit). - New poweron reason REASON_FULL_CYCLE appended at the end of the ABI list, so diagnostics can tell a shuttle cycle from a user reboot. - full_cycle is decoded with higher priority than reboot: bootloaders set both bits in one write so the same frame works on older firmware (where reboot already performs the full cycle and bit3 is ignored). - Reuses linux_cpu_pwr_seq_hard_reset(); the handler sits inside the one-power-action-per-pass guard introduced by the wedge fix. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01EVPkc2g2yir6SGyrED6uNT
- consume the companion reboot bit together with full_cycle so it cannot stay latched in the regmap for a future read-modify-write client - re-arm the warm watchdog stage after a shuttle-requested cycle, same as the watchdog's own hard-reset branch (an immediate re-hang gets a warm, log-preserving reset again) - document the reboot==full-cycle compatibility contract on POWER_CTRL in the ABI header - unit tests: full_cycle request, and the bootloader contract that full_cycle wins over a simultaneous reboot bit with both bits consumed - changelog entry for the new ABI surface Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01EVPkc2g2yir6SGyrED6uNT
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…tages green on the same commit)
WB 7.4 uses an AXP221 (AXP20x/22x family), not the AXP15060 of WB 8.5. In that family PWROK is an output (power-good / SoC reset; its delay is configured by REG 0x36 bit 2) and there is no "restart the PMU when PWROK is pulled low" function -- that appeared only in AXP15060/AXP2101, which is exactly why WB 8.5 has to suppress it via REG32[4]=0. On WB 7.4 there is nothing to suppress: the pulse resets only the SoC while the PMIC keeps every rail up. The warm reset asserts the same GPIO that the already-shipping linux_cpu_pwr_seq_reset_pmic() drives, for 100 ms instead of up to 2 s, so it introduces no new stimulus to the hardware. Verified on a WB 7.4: a watchdog warm reset (poweron_reason 8) leaves the RTC GP registers intact and systemd-pstore harvests a console-ramoops written before the reset, i.e. the ramoops region in DRAM survives. A board that is never fed still escalates to a hard power cycle (reason 5), which does zero those RTC registers. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
| sweeps PMIC failure timing across all reset sequence phases and | ||
| asserts the watchdog always recovers the SoC in bounded time | ||
|
|
||
| -- Wiren Board Robot <info@wirenboard.com> Fri, 04 Jul 2026 14:00:00 +0300 |
There was a problem hiding this comment.
Робот? И дата не сходится, 4 июля - суббота была
| break; | ||
| } | ||
|
|
||
| #if defined(WBEC_HAS_WARM_RESET) |
There was a problem hiding this comment.
Т.к. WBEC_HAS_WARM_RESET есть у обеих таргетов, может не заворачивать в ифдеф? А то собираемость и работа без этого дефайна всё равно не проверяется
| // прервать её (например, оставить линию PMIC RESET (PWROK) | ||
| // взведённой навсегда - SoC заклинит в сбросе). | ||
| // Взведённые флаги watchdog не теряются: они будут обработаны | ||
| // после завершения начатой последовательности |
There was a problem hiding this comment.
По факту вроде как флаги сбрасываются. wdt_handle_timed_out(); в состоянии WBEC_STATE_POWER_ON_SEQUENCE_WAIT
| // Сбрасывается, когда Linux сбрасывает watchdog (система жива). | ||
| // Если после тёплого сброса Linux так и не начал сбрасывать watchdog, | ||
| // следующий таймаут приведёт к жёсткому сбросу по питанию | ||
| bool wd_warm_reset_attempted; |
There was a problem hiding this comment.
Нейронка подсказывает:
wd_warm_reset_attempted = false ставится в ветке full_cycle и после жёсткого сброса по watchdog, но не ставится в других ветках, которые тоже делают полный цикл 5В: LINUX_POWERCTRL_REBOOT (src/wbec.c:559), REASON_REBOOT_NO_ALARM (:554), оба hard_reset при потере 3.3В (:685, :704). Окно узкое (обычно перед reboot Linux успевает покормить watchdog, и флаг снимается через wdt_handle_fed), но, например, после восстановления от аварии PMIC первое зависание свежей загрузки получит жёсткий сброс вместо тёплого — ramoops потеряется, вопреки заявленному в changelog инварианту «эскалация начинается заново после каждого полного цикла».
| * пока PMIC не перезапустят снятием 5В или удержанием PWRON; | ||
| * - линия PMIC RESET (PWROK): на WB85 (WBEC_HAS_WARM_RESET) удерживает | ||
| * в сбросе только SoC (PMIC игнорирует), на WB74 сбрасывает PMIC | ||
| * и 3.3В пропадает; |
There was a problem hiding this comment.
Надо обновить коммент для WB74
Three related embedded-controller changes.
Explicit full-power-cycle request — all EC models
A new
POWER_CTRLbit (full_cycle, bit 3): when set together with the reboot bit, the EC performs a genuine 5 V power cycle rather than a warm reset, and reports it as a distinct power-on reason (REASON_FULL_CYCLE, 9). The handler is compiled unconditionally, so every model understands it. Old firmware ignores the bit, and there the reboot bit already performs a full cycle, so a caller sets both bits and needs no version probe.This lets a bootloader request a guaranteed power cut — for example, the U-Boot pstore shuttle parks a crash log to storage and then forces the board off and back on to recover it.
Warm SoC reset + two-stage watchdog escalation — WB7.4 and WB8.5
On a watchdog timeout the EC first pulses the SoC RESET line — a warm reset that preserves DRAM — and only escalates to a full power cycle if the board fails to recover:
Watchdog (warm reset))Watchdog)Consumers that detect watchdog resets must now treat both 5 and 8 as "watchdog".
The pulse is on the shared
PMIC_RESET_PWROKline, and it works on both boards for different reasons:REG32[4]=0, so its rails stay up.PWROKis an output there (power-good / SoC reset; its delay is set byREG 0x36bit 2), and the family has no "restart the PMU on PWROK low" function at all — that only appeared in AXP15060/AXP2101, which is precisely what WB8.5 must suppress. So on WB7.4 there is nothing to suppress.The warm reset asserts the same GPIO that the already-shipping
linux_cpu_pwr_seq_reset_pmic()drives, for 100 ms instead of up to 2 s — no new stimulus to the hardware.Verified on WB7.4 hardware: after a watchdog warm reset (reason 8) the RTC GP registers survive and
systemd-pstoreharvests aconsole-ramoopswritten before the reset — i.e. the ramoops region in DRAM is preserved. A board that is never fed still escalates to a hard power cycle (reason 5), which does zero those RTC registers.Also:
reset_pmic(POWER_CTRLbit 2) now performs the short warm pulse instead of the 2 s PMIC RESET hold, on both models.Power-sequencer hardening
Never start a second power sequence while one is already in flight — previously this could wedge the controller.
Tests
Unit and integration tests for the
full_cyclebit, the watchdog state machine, and the power-sequencer guard. Both model images build with the warm stage compiled in.