packages/chip/docs/pd/power-management-firmware.md
Status: planning_skeleton_release_blocked
+-------------------------------------+
user-space | Android HAL / Power HIDL |
+-------------------------------------+
|
v
+-------------------------------------+
S-mode Linux | cpufreq / regulator / clk / thermal |
+-------------------------------------+
|
| SBI MPxy mailbox (SBI v3.0)
v
+-------------------------------------+
M-mode OpenSBI | sbi_mpxy / rpmi_proxy |
+-------------------------------------+
|
| RPMI v1.0 frame
v
+-------------------------------------+
AON Ibex PMC | fw/pmc/src/main.c |
| rpmi_server.c |
| dvfs_arbiter.c |
| pmic_sequencer.c |
| thermal_policy.c |
| droop_telemetry.c |
+-------------------------------------+
|
| SPMI v2.0 (or I2C-FM+ fallback)
v
+-------------------------------------+
External PMIC set | 6-8 catalog buck/LDO ICs |
+-------------------------------------+
cpufreq-sbi-mpxy.c — Linux 6.x merged. Sends SCMI-equivalent DVFS
commands over the MPxy mailbox.regulator-sbi-mpxy.c — voltage / rail enable. Merged for 6.x.thermal-sbi-mpxy.c — DTS readout and throttle policy hooks.Pin the OpenSBI release at silicon bring-up. Current target: OpenSBI 1.5
or newer with merged SBI MPxy + RPMI proxy support. The pin is recorded in
docs/evidence/power/pmic-procurement.yaml once selected.
Targets RV32IMC Ibex management core. Lives in fw/pmc/:
| File | Role |
|---|---|
src/main.c | Boot, init, scheduler loop. |
src/rpmi_server.c | RPMI v1.0 frame parser/serializer; per-service handler dispatch. |
src/dvfs_arbiter.c | DVFS table lookup, AVFS request merge, target-code resolution per rail. |
src/pmic_sequencer.c | PMIC power-on / power-off sequence per rail dependencies. |
src/spmi.c | SPMI v2.0 master bit-bang / accelerator driver. |
src/i2c.c | I2C-FM-plus fallback master. |
src/thermal_policy.c | DTS readout, throttle ladder enforcement. |
src/droop_telemetry.c | Droop / AVFS counter aggregation, leak to Linux. |
src/secure_boot.c | Secure-boot key handling stub (HMAC/ECDSA verification). |
The DVFS arbiter consumes per-corner DVFS tables from docs/pd/dvfs-tables/
which the build system flashes into PMC SRAM at boot. Each table entry binds
a frequency target to a voltage code and a stability margin.
fw/pmc/src/secure_boot.c (boot ROM lives in fw/boot-rom/).VDD_PMC, VDD_AON rails via SPMI POR sequence.VDD_SOC_FABRIC, VDD_SRAM, VDD_CPU_BIG,
VDD_LPDDR_* in fixed sequence.PMC enters its scheduler idle hook when no RPMI request is in flight. On Linux S0i2 / S3 / S4 entry:
PD_CPU_BIG, PD_NPU, PD_GPU. SRAM at retention voltage.Wake events: AON wake controller IRQ -> PMC -> reverse sequence.
The Ibex PMC runs a single sequencer (fw/pmc/src/pmic_sequencer.c) that
serialises rail enable/disable across S-state transitions. The transitions
are atomic at the PMC scheduler level — Linux S-state RPC blocks on the
sequencer return.
+----------------+
| S0_ACTIVE |
+-------+--------+
| RPMI:SYSTEM:SUSPEND
v
+--------+ +--------------+ +--------+ +--------+
| QUIESCE|--->| GATE_GPU |--->| GATE_ |--->| GATE_ |
| CPU AP | | NPU FABRIC | | SRAM | | CPU_* |
+--------+ +--------------+ +--------+ +--------+
block I/O |
completion v
+-------------------+
| LPDDR SELF-REFRESH|
+---------+---------+
| SPMI LPDDR cmd
v
+-------------------+
| DISABLE BUCKS: |
| CPU_BIG, LITTLE, |
| NPU, GPU, FABRIC, |
| SRAM |
+---------+---------+
| SPMI per-rail off
v
+-------------------+
| S3_DEEP_IDLE |
+-------------------+
AON + PMC + LPDDR
array supplies only
wake IRQ (AON wake controller)
|
v
+-----------------+
| PMIC POR | bring up SOC_FABRIC and SRAM bucks first;
| (reverse order) | RPMI POR table -> SPMI commands
+--------+--------+
|
v
+-----------------+
| LPDDR EXIT | command exit from self-refresh
| SELF-REFRESH |
+--------+--------+
|
v
+-----------------+
| RAISE CPU_BIG / | per-rail SPMI enables; PLLs relock; AVFS arms
| LITTLE BUCKS |
+--------+--------+
|
v
+-----------------+
| RAISE NPU + GPU | background; SoC can resume Linux before NPU
| BUCKS | is fully online
+--------+--------+
|
v
+-----------------+
| DEASSERT CPU | cpu hart 0 resumes from OpenSBI fw_dynamic
| RESET |
+--------+--------+
|
v
+-----------------+
| S0_ACTIVE | RPMI:SYSTEM:RESUME returns to Linux
+-----------------+
S0_ACTIVE --(idle hint)--> GATE_NPU --> GATE_GPU --> SRAM_RETENTION
|
v
S0I2_LIGHT
CPU_BIG retains
SOC_FABRIC at low
LPDDR active
Reverse on wake: SRAM exit retention -> raise GPU -> raise NPU. No PMIC power-off transitions; only DVFS code lowering on the SRAM rail.
Linux persists state to nvm; PMC then runs the full S3 sequence AND additionally disables LPDDR array supply after the controller flushes. PMC remains alive but in deep sleep, polled by RTC. Wake path is BOOT_ROM reset because DRAM contents are lost.
If any SPMI transaction returns NACK during a sequence, the PMC aborts the
transition, marks PMC_STATUS_FAULT via rtl/power/pmc_top.sv, and
returns RPMI_FAIL_HW_FAULT to S-mode. Linux must replay the suspend; the
PMC restores the rails it had already commanded before the failure.
docs/evidence/power/pmic-procurement.yaml.