Repository navigation
Conversation
IOMFB 26.x takes setPowerState (A473) on the out-of-band channel, the older contexts' +4, which the T8132 words carry as stream 1 (bit 10): the AP packet goes at shared-memory offset 0x8000, the firmware answers on the same stream, and the callbacks it makes meanwhile arrive at 0x68000 with bit 10 set. The J713 backend so far admitted stream 0 only. Let a top-level AP call name stream 1, and while it is outstanding, decode incoming words with bit 10 as stream-1 packets. Calls nested in one of its callbacks stay on stream 1, at the next aligned offset after the outstanding packet, as on stream 0. Stream-0 traffic is unchanged. The first user is system sleep. Signed-off-by: Erik Bourget <erik@ebourget.net>
Powering the J713 display down and up with setPowerState (A473), the 26.6.2 firmware calls back into the AP: acknowledgeSetPowerState (D106), will_power_off_signal (D002), get_calendar_time_ms (D209), powerUpDART (D572), swap_complete_intent (D592), set_kernel_power_assert (D700), aot_supported_peek (D203), set_power_trace_enable (D008), set_idle_caching_state_ap (D117) and enable_backlight_message_ap_gated (D594). The exact-shape table refused them, which quarantines the session. Add their shapes and answer them for this machine: the notifications and setters with an ACK, the status-returning calls with success, AOT support with false, and the calendar time in milliseconds. The DART and the power assertion are the AP's to hold: the J713 keeps the display domains on across suspend-to-idle. Signed-off-by: Erik Bourget <erik@ebourget.net>
The J713 DCP refused system sleep: the retained T8132 session had no
qualified handshake. setPowerState (A473) out of band is that handshake
on IOMFB 26.x: with the panel blanked, setPowerState(0) powers the
display pipeline down (the firmware logs "power on -> off" and disables
its M3 helpers) and setPowerState(1) brings it back, after which the
next present scans out again.
apple-drm is a consumer of the DCP, so its suspend handler has blanked
the panel when the DCP suspends, and its resume handler restores the
CRTC after the DCP resumed. Power the display down in between, with the
coprocessor running and its power domains kept on through the wakeup
path, as on the older DCPs; refuse sleep should the panel still scan
out. Presents while the display is down are refused.
The request is the 16-byte {u64 state; u8 flags[4]; u8 result_null;
u8 pad[3]}, the reply {u32 value; u32 status}; a nonzero status fails
the transition and the session.
Signed-off-by: Erik Bourget <erik@ebourget.net>
The J713's retained DMA owners refuse system sleep: the radio's DART with managed streams, and the display DARTs, which borrow the running DCP's live page-table root. Neither has a suspend boundary of its own, and their state cannot be restored from a copy. Suspend-to-idle does not need one. These DARTs have no power domain of their own in the tree, and the DCP keeps the display domains on across s2idle, so their state stays where it is. Let them through for suspend-to-idle only, saving their registers solely for resume to check that nothing moved. Every other sleep state is still refused. A DART whose retained state changed cannot be trusted with its live DMA, and a resume error does not stop the PM core from resuming consumers. Quarantine the managed streams and the borrowed display consumers through the same paths as a translation fault before failing resume, so that their later maps are refused. A host test exercises the extracted check, quarantine and map functions. Signed-off-by: Erik Bourget <erik@ebourget.net>
The J713's radio port, whose streams the OS adopts from the boot loader's handoff, refuses system sleep in its noirq phase. It has no suspend boundary of its own, but suspend-to-idle does not need one: the port has no power domain in the tree, so it stays up as any other internal port does, whose resume does nothing. Let it through for suspend-to-idle only; every other sleep state is still refused. Signed-off-by: Erik Bourget <erik@ebourget.net>
A coprocessor can keep running in its power domain across system sleep without system-sleep callbacks of its own, as the J713's GPU firmware does. Describe such a domain, which the OS keeps on during system sleep; runtime power management is unaffected. Signed-off-by: Erik Bourget <erik@ebourget.net>
…tem sleep The J713's G16 GPU has no system-sleep callbacks, so in the noirq phase genpd powers its GFX domain off, and the TVM gate above it, under the running GPU firmware; the power-on at resume then times out. Let a domain marked apple,sleep-retained decline its power-off while the system sleeps: genpd then keeps it and its parents on. Runtime power management is unchanged. Signed-off-by: Erik Bourget <erik@ebourget.net>
Some coprocessors message the AP periodically while idle: the J713's GPU firmware asks for ring service about twice a second, and its AOP sends a report every second. Describe a mailbox whose messages need not wake the system, so the OS can leave them in the FIFO while it sleeps and handle them at resume. Signed-off-by: Erik Bourget <erik@ebourget.net>
…uest The receive IRQ of the ASC mailboxes is IRQF_NO_SUSPEND, so every coprocessor message wakes a CPU out of suspend-to-idle. On the J713 the GPU firmware's idle ring-service kicks and an AOP report every second wake it about three times a second: in 938 s of s2idle, 1472 wakeups and only 512 s in deep idle. For a mailbox marked apple,hold-rx-in-sleep, mask the receive IRQ from noirq suspend to noirq resume, so its messages wait in the FIFO and the consumer handles them on resume. The mailbox is a supplier of its consumer, so this runs after the consumer suspended and before it resumes. The firmware throttles once its outbox fills: after 148 s of s2idle, 11 GPU and 3 AOP messages were waiting, with 3 wakeups and 146.9 s in deep idle. Signed-off-by: Erik Bourget <erik@ebourget.net>
The G16 firmware keeps running across suspend-to-idle: keep its GFX domain on through system sleep, and hold its idle ring-service kicks in the mailbox instead of waking the system about twice a second. Signed-off-by: Erik Bourget <erik@ebourget.net>
With DPMS off, the J713 display was only blanked: the swap to no surface stops presenting, but the display pipeline stays powered. A blanked panel is the state in which system sleep powers the display down with setPowerState(0), and the same works here. After a successful blank, power the display down, and power it back up with setPowerState(1) before the next present, so the first frame after DPMS on brings the panel back. System sleep with the display already down leaves it down and skips its own setPowerState(0); after resume the next present powers it up. A refused transition fails the session, as in system sleep. debugfs reports whether the display is down, how often it went down, and how long the last and longest power-down and power-up took. On the J713, idle on battery with the backlight off, DPMS off saved 346 mW before this change (3.04 -> 2.69 W) and saves 1.20 W with it (2.93 -> 1.73 W), each measured within one run. Over 200 blank/wake cycles, power-down took 128-132 ms and power-up 55-56 ms. Signed-off-by: Erik Bourget <erik@ebourget.net>
This was referenced Oct 27, 2026
Contributor
Author
|
Superseded by #830, where this is commit 4, on top of #449's DCP sleep handshake (commits 1–3 there). On the current base, the host test |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Depends on #449. This branch is #449's head (
4fe8d2f1acfa) plus one commit,drm/apple: m4: Power the display down while it is blanked. Only that last commit is for review here.The problem
On the J713, DPMS off (screen lock, idle blank,
hyprctl dispatch dpms) only blanks the display:iomfb_m4_blank()swaps to no surface, but the display pipeline stays powered until the next frame. #449 already powers it down for system sleep withsetPowerState(0)once the panel is blanked, and brings it back withsetPowerState(1).The change
setPowerState(0), the same call J713 (M4 MacBook Air): suspend-to-idle #449 makes for system sleep.setPowerState(1)before its swap, so the compositor's first frame brings the panel and backlight back. This is the path resume already uses.setPowerState(0), and the display stays down after resume until the next present.iomfb_m4gainsdisplay_off,off_cycles, andoff_us/on_us(last/longest).How it was tested
The tested kernel is the J713 test tree with this commit. Its
iomfb_m4.cis byte-identical to this branch's, its config matches the J713 daily kernel's, and its callers (dcp_poweroff()→iomfb_m4_blank(),dcp_flush()→iomfb_m4_present(), platform suspend and resume) are the same as here. This branch alone does not boot a J713 (it lacks the other J713 series), as with #449.Power. Idle on battery, 2 s samples over 120 s per phase, medians. Each column is one run on one boot, so compare within a column:
The draw returns to its starting level after DPMS on in both runs.
Stress. 200 blank/wake cycles through Omarchy's DPMS commands, checking debugfs after every step. All 200 passed, with no errors. Each blank powered the display down, and each wake powered it up with new frames flowing.
setPowerState(0)setPowerState(1)The power-down runs inside the commit that disables the CRTC, so that commit takes about 130 ms longer. Hyprland's DPMS dispatch still returned in 10–12 ms.
Other cases.
/sys/power/state. Suspend skipped its own power-down (off_cyclesunchanged), resumed with the display still down, and one key press brought it back.IOAVVideoInterface open failed, which J713 (M4 MacBook Air): suspend-to-idle #449's sleep path also logs, with no effect.Known limits
Checks on this branch
checkpatch.pl --strict: clean.fetch_updatedeprecation notices, in code this commit doesn't touch.tools/testing/m4-dcp-errors/run.py: passes, as on J713 (M4 MacBook Air): suspend-to-idle #449's head.tools/testing/apple/check-backlight.py,check-backlight-retry.pyandcheck-lifetime.py: do not compile on J713 (M4 MacBook Air): suspend-to-idle #449's head either. Their harnesses predate the current headers (linux/math64.hnot found, andapple_dcp_afkepmembers moved). The errors are identical on both heads, and this commit doesn't touch those files.