Skip to content

wbec: full-power-cycle request + warm reset / two-stage watchdog (WB7.4 + WB8.5)#91

Open
evgeny-boger wants to merge 7 commits into
mainfrom
feature/ec-full-cycle-request
Open

wbec: full-power-cycle request + warm reset / two-stage watchdog (WB7.4 + WB8.5)#91
evgeny-boger wants to merge 7 commits into
mainfrom
feature/ec-full-cycle-request

Conversation

@evgeny-boger

@evgeny-boger evgeny-boger commented Jul 5, 2026

Copy link
Copy Markdown
Member

Three related embedded-controller changes.

Explicit full-power-cycle request — all EC models

A new POWER_CTRL bit (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:

  • 1st timeout → warm reset, power-on reason 8 (Watchdog (warm reset))
  • not fed by the next timeout → hard power cycle, reason 5 (Watchdog)
  • feeding the watchdog re-arms the warm stage

Consumers that detect watchdog resets must now treat both 5 and 8 as "watchdog".

The pulse is on the shared PMIC_RESET_PWROK line, and it works on both boards for different reasons:

  • WB8.5 (AXP15060): the line drives the T507 RESET; the PMIC ignores the pulse at the factory default REG32[4]=0, so its rails stay up.
  • WB7.4 (AXP221, AXP20x/22x family): PWROK is an output there (power-good / SoC reset; its delay is set by REG 0x36 bit 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-pstore harvests a console-ramoops written 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_CTRL bit 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_cycle bit, the watchdog state machine, and the power-sequencer guard. Both model images build with the warm stage compiled in.

evgeny-boger and others added 6 commits July 4, 2026 14:35
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>
@evgeny-boger evgeny-boger changed the base branch from feature/warm-watchdog-reset to main July 8, 2026 13:59
@evgeny-boger evgeny-boger changed the title Add explicit full-power-cycle request to POWER_CTRL (bit3) wb85: warm SoC reset, two-stage watchdog escalation, and full-power-cycle request Jul 8, 2026
@evgeny-boger evgeny-boger changed the title wb85: warm SoC reset, two-stage watchdog escalation, and full-power-cycle request wbec: full-power-cycle request (all models) + warm reset / two-stage watchdog (WB8.5) Jul 8, 2026
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>
@evgeny-boger evgeny-boger changed the title wbec: full-power-cycle request (all models) + warm reset / two-stage watchdog (WB8.5) wbec: full-power-cycle request + warm reset / two-stage watchdog (WB7.4 + WB8.5) Jul 9, 2026
@evgeny-boger evgeny-boger requested a review from pgasheev July 9, 2026 17:52
@evgeny-boger evgeny-boger marked this pull request as ready for review July 9, 2026 17:53
Comment thread debian/changelog
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

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Робот? И дата не сходится, 4 июля - суббота была

Comment thread unittests/regmap_test

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Бинарник попал в коммит

Comment thread src/wbec.c
break;
}

#if defined(WBEC_HAS_WARM_RESET)

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Т.к. WBEC_HAS_WARM_RESET есть у обеих таргетов, может не заворачивать в ифдеф? А то собираемость и работа без этого дефайна всё равно не проверяется

Comment thread src/wbec.c
// прервать её (например, оставить линию PMIC RESET (PWROK)
// взведённой навсегда - SoC заклинит в сбросе).
// Взведённые флаги watchdog не теряются: они будут обработаны
// после завершения начатой последовательности

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

По факту вроде как флаги сбрасываются. wdt_handle_timed_out(); в состоянии WBEC_STATE_POWER_ON_SEQUENCE_WAIT

Comment thread src/wbec.c
// Сбрасывается, когда Linux сбрасывает watchdog (система жива).
// Если после тёплого сброса Linux так и не начал сбрасывать watchdog,
// следующий таймаут приведёт к жёсткому сбросу по питанию
bool wd_warm_reset_attempted;

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Нейронка подсказывает:

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В пропадает;

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Надо обновить коммент для WB74

@pgasheev pgasheev left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

missclick

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants