The sequencer can open and close a switch, but only the reset controller can hold a whole domain in reset and release it in order, and only it remembers why the chip last restarted. On NanoSoC both live in the same always-on block, nano_rstpwr, which hides the handshake until the day the two disagree: resets released into a domain whose isolation is still on, or a wake nobody recorded. This lesson draws the handshake that keeps them consistent.
Going down, software writes PWR_CTRL.SW_OFF_REQ, the sequencer takes it from there, and the reset controller asserts rst_sys_n and rst_cpu_n as sequencer outputs during ASSERT_RST, 2 peripheral clocks before the switch opens. Coming up, the power-good signal crosses from the supply monitor into the peripheral domain through a two-flop synchroniser, the 8-clock margin runs, the PLL relocks, and only then do the resets release in the fabric order: rst_sys_n first after 18 system clocks, rst_cpu_n last after 8 system clocks plus 2 CPU clocks. The CPU is last for a reason the reset lessons teach: its two-flop release is faster than the fabric's eighteen clocks, so an early CPU would fetch into a fabric still in reset; this is NanoSoC bug 2, reset release order.
Two registers make the handshake visible to software. PWR_STATUS.SW_ON reads the sequencer's position, 1 in RUN, 0 from SWITCH_OFF until RST_RELEASE, so a driver can tell refusal from progress. RST_CAUSE records the reason, POR, pad, software reset or WAKE on bit 3, write-1-to-clear and reset by POR only, so the boot ROM reads it before touching SRAM0 and chooses the retained-image path on a wake. See Release Order Across Domains for the reset-ordering mechanism and Power-On and Warm Reset for the warm-reset side.
Signal | From | To | Crossing | Meaning |
|---|---|---|---|---|
SW_OFF_REQ (PWR_CTRL bit 0) | Software | Sequencer | Register in PD_AON | Start the power-down sequence |
DMA BUSY / SBR BUSY (status reads) | Driver (CPU) | Sequencer (via request) | APB register reads in RUN | Quiesce contract: the sequencer samples no live PD_SW levels |
pgood | Supply monitor | Sequencer | 2-flop synchroniser into clk_per | Rail usable; starts the 8-clock margin |
pll_lock | PLL | Sequencer and reset control | 2-flop synchroniser | Relock complete; clocks may open |
rst_sys_n, rst_cpu_n | Reset controller | PD_SW domains | Async assert, 2-flop sync release per domain | Ordered release: fabric first, CPU last |
RST_CAUSE bit 3 | Reset controller | Boot software | W1C register, POR-only reset | This boot is a wake; use the retained image |
The reset-assert order on entry and the release order on exit match the cold-boot order bit for bit: slaves and fabric first, CPU last.
Power-good and lock cross through synchronisers, never as raw combinational enables into the sequencer.
RST_CAUSE is read before any retained state is used, on every boot path including the software-reset path.
Force each handshake input in turn and watch the machine stall where it should: pgood held low must hold SWITCH_ON, lock held low must hold RELOCK. Test the quiesce contract in software: a sleep requested mid-job must be caught by the driver's idle check before the request is ever written. If the wake completes but software takes the cold path, RST_CAUSE was cleared or never set; check that only POR resets it and that the boot ROM reads it before any code that could clear it. If resets release but the first fetch hangs, suspect the CPU-last rule, the classic reset-order failure of the reset lessons.
Because good means the threshold was crossed, not that the rail has settled under load or that the synchronised copy has arrived. The margin covers settling plus synchroniser delay; releasing isolation on the raw edge is the hurry the timeout lesson forbids.