Skip to content

Apple SoC sleep: one driver for all Apple SoCs, matched only on tested ones - #1334

Closed
DjDeveloperr wants to merge 14 commits into
fix/t8140-sleep-followupsfrom
feat/apple-soc-sleep-generic
Closed

DjDeveloperr wants to merge 14 commits into
fix/t8140-sleep-followupsfrom
feat/apple-soc-sleep-generic

Conversation

@DjDeveloperr

@DjDeveloperr DjDeveloperr commented Nov 9, 2026 •

Copy link
Copy Markdown
Contributor

Makes the T8140 suspend-to-RAM driver an Apple SoC sleep driver. It binds only on SoCs whose sleep has been measured and tested, which today means T8140 (MacBook Neo). Every other SoC keeps s2idle and doesn't change. Stacked on #1313 (fix/t8140-sleep-review, cc859e5).

What's generic now

  • The driver. drivers/soc/apple/t8140-sleep.c is now drivers/soc/apple/sleep.c, built as apple-sleep under CONFIG_APPLE_SOC_SLEEP. That covers the whole path: CPU power ops, refusals, the coprocessors' last stops, the display off, the debug-link cut, ANS's PCIe block, the macOS match, the commit, the return and the rewake.
  • The old symbol. CONFIG_APPLE_T8140_SLEEP stays as a Kconfig transitional symbol, so an old .config still turns the driver on.
  • What moved into match data. Each SoC has a struct apple_sleep_soc, one per compatible. It holds:
    • the power words the sleep drives by name: the DCP and DCPEXT CPU, front end and system domains, SIO_CPU, SEP, the USB complex, AP_TMM, GPIO, ANS and ANS's PCIe block;
    • the ps-aon debug switch and the pwrgate words;
    • every list macOS was measured with: all words, on and off at the commit, no-auto, the wake order, polled-off, stray and gate-off;
    • the coprocessor gate list, by DT path;
    • the wake-source names and the mask of the wake block's last word;
    • the PCIe host the radio's PERST# is found on.
  • Per-device books. The books the driver keeps for each word used to be sized by T8140's tables. They are now allocated for the SoC's lists at probe.
  • What stays in shared code. Block-relative layouts and protocols, each found through its own reg-names entry: the PS word bits, ASC, SPMI/HPM, WDT, DCS, MCC, AMCC, DVFM, CLLT, cluster, PTD, clk-mux, the pin controller and the APCIe block. A SoC whose block differs gets a field for it when it's added.
  • AIC. The apple,t8140-aic3 check is now an aic_info.fw_suspend flag in the AIC's own match data.
  • DCP. The apple,t8140-dcp / apple,t8140-dcpext checks for the sleep and DPMS power cycle and the oslog echo are now apple_dcp_hw_data.s2r / .s2r_ext.
  • Binding. The file, the compatible and the properties are unchanged. The compatible is now an enum, and the title and description are generic.

How a chip is added

  1. Measure its sleep under aura, as T8140's was.
  2. Add <soc>_sleep_soc and { .compatible = "apple,<soc>-sleep", .data = &<soc>_sleep_soc } to apple_sleep_of_match. Add the compatible to the binding's enum and the node to the SoC's dtsi.
  3. Set fw_suspend in its AIC match data. Set s2r / s2r_ext in its DCP data if the DCP's sequence holds there.
  4. Once it has passed on hardware, add the compatible to apple_sleep_test_tested[] in sleep-test.c. The KUnit suite apple-sleep-soc-data checks that every list names only words of the SoC's full lists, with no duplicates, and that the lists fit the books. A mistake there would otherwise be skipped at the wake without a word.

Why untested chips are unchanged

  • No probe. The match table holds only apple,t8140-sleep, and only t8140.dtsi has that compatible. Without a match the driver never probes, so there's no suspend_set_ops() and no spin-table power ops, and mem_sleep stays s2idle exactly as before.
  • Flags only on T8140. The AIC and DCP flags are set only in T8140's match entries, where the compatible checks matched before. No other DT names those compatibles, even as a fallback.
  • Helpers unchanged. The exported apple_sleep_* helpers are unchanged and still answer as before when no sleep driver has probed.

No functional change on T8140

  • (a) rename. .text is identical to T8140 sleep: fixes from review #1313's t8140-sleep.o. The only data change is the module name string. Git shows the file as a 100% rename.
  • (b1) identifier rename. .text, .rodata, .data and relocations are identical. Only the driver name string changes (apple-sleep, same length).
  • (b2) match data. The new object's t8140_sleep_soc was decoded from its DWARF layout and checked against the old object and source: every table, named word, pwrgate word, count, mask and string, and the of_match data pointer. 50 of 50 checks match.
  • (c) AIC and DCP. Each flag is set exactly where its compatible check matched before.

Not generalized, on purpose

  • rtkit.c oslog echo. It's an of_machine_is_compatible("apple,t8140") check, but it's general RTKit behaviour, not sleep.
  • pmp-export.c apple_pmp_keep_bound(). This is a driver-wide suppress_bind_attrs, read before any device or match data exists. A helper that depends on the sleep config would change T8140 kernels built without it.
  • dwc3-apple GCTL hibernation setup. It's controller reset programming, run at every reset, and the driver has no match data.
  • ATC PHY has_t8140_dp. It's a PHY variant flag. Its sleep-in-place also needs apple_sleep_domain_check(), which fails without the sleep driver.
  • macsmc's MBSW wake-reason bits. They use T8140's numbering, but they're reached only after a firmware suspend, so only on matched SoCs. A new SoC must check them.
  • Already generic. Everything else the series touches is already keyed on DT properties (apple,sleep-ssps, apple,sleep-ddr, apple,sleep-driver-owned), on pm_suspend_via_firmware(), on the sleep driver's registration, or on its own match data (NVMe sleep_traced, GPU sleep_restart, SIO firmware_only, EDAC t8140_ni).

Visible renames

  • The platform driver is now apple-sleep, at /sys/bus/platform/drivers/apple-sleep/, and its log prefix is apple-sleep.
  • The dyndbg module name is now apple_sleep.
  • The distro configs' symbol moves to CONFIG_APPLE_SOC_SLEEP: alarm-aurora#199 and nixos-aurora#203 get a follow-up commit, which also takes T8140 sleep follow-ups: RTC wake on rtc0, SEP restart after a refusal, commit audit, USB recovery #1333's CONFIG_RTC_DRV_APPLE_PMU=y. fedora-aurora#242 needs nothing, because it validates against the pinned asahi.config.

Tests

  • CI on this PR passes: source, rust-build and kunit.
  • Build. Asahi profile with Rust on: drivers/soc/apple/ drivers/irqchip/ drivers/gpu/drm/apple/ drivers/gpu/drm/asahi/ drivers/dma/ drivers/mfd/ drivers/nvme/host/ drivers/pci/controller/ drivers/phy/apple/ drivers/pmdomain/apple/ drivers/usb/dwc3/ drivers/usb/typec/tipd/ plus the t8140-j700, t6000-j314s, t8112-j413, t6041-j614c and t6040-j616s DTBs. Exit 0. The only warnings are the known apple.c thread-safety ones and rustc deprecation notes, none from this series. sleep.o is also clean with W=1, and checkpatch is clean.
  • KUnit (QEMU arm64, the stack's config with CONFIG_APPLE_SOC_SLEEP=y and the new suite):
    • Run 1: 532 tests, 531 passed, 1 skipped (apple_g17_rx_util_min_test, which needs UCLAMP). That's T8140 sleep: fixes from review #1313's 528 plus the 4 cases of apple-sleep-soc-data.
    • Runs 2 and 3 ran under load average 19-22 from other lanes' kernel builds. Both oopsed in the upstream DRM scheduler mock tests (drm_sched_parallel_submit_test cleanup: mock_sched_cancel_job() -> hrtimer_cancel(), a NULL dereference). That broke the KUnit device bus for every later suite. This series doesn't touch drivers/gpu/drm/scheduler.
    • Run 5 ran every other suite of the same build by name glob: 490 tests, 489 passed, 1 skipped.
  • Negative control. With a word added to T8140's wake order that its full list lacks, apple-sleep-soc-data fails on exactly that word.
  • Host tests (tools/asahi/run-host-tests.py): apple-dcp 87/87 (through the clang wrapper with -Wno-unused-but-set-global, as on T8140 sleep: fixes from review #1313), display26 1/1, t6030-wiring 3/3, tunnel-route 1/1, tiled-split 2/2 (with mutations), t6030-clock 1/1, rtkit-oslog 6/6, atc-usb3 2/2 (with mutations), neo-stability 10/10, apple-dart-fw 1/1, apple-dart-range 1/1, t8140-external-bw 1/1. apple-dcp's resource-profile copies the DCP's hw data struct, so its mock gets the two new fields in the DCP commit.
  • DT. dt_binding_check on the binding passes. dt-validate of t8140-j700.dtb gives the same lines with the old and the new binding, and none for the sleep node.

Merging with #1333 (sleep follow-ups)

#1333 (fix/t8140-sleep-followups, a078d77) is also stacked on #1313. The rename commit here is a pure 100% move, so git carries #1333's changes to t8140-sleep.c over to sleep.c. A trial merge (git merge-tree):

🤖 Generated with Claude Code

The suspend-to-RAM driver for a kernel at EL2 isn't T8140's alone: other
Apple SoCs are to share it, each added by match data once tested. Move
t8140-sleep.c to sleep.c, built as apple-sleep, and rename its symbol to
CONFIG_APPLE_SOC_SLEEP. CONFIG_APPLE_T8140_SLEEP stays as a transitional
symbol, so an old config still enables it.

The file moves unchanged. No functional change.

Signed-off-by: Diljit Singh <hey@djdev.me>
Rename the driver's own identifiers from t8140_* to apple_sleep_* and
sleep_*, and its platform driver from t8140-sleep to apple-sleep. The
tables that hold T8140's measured power words, coprocessors and wake
sources keep their t8140_ prefix, as the next change makes them T8140's
match data.

Every renamed identifier keeps its length. The object's text, data and
relocations are unchanged; only the driver name string differs.

Signed-off-by: Diljit Singh <hey@djdev.me>
The sleep controls' registers and properties aren't T8140's alone: the
next SoC to get the suspend-to-RAM driver uses the same binding with its
own compatible, as its power domains differ. Make the compatible an enum,
so one is added there, and title and describe the binding for Apple SoCs.

apple,t8140-sleep stays as it is, with the same properties.

Signed-off-by: Diljit Singh <hey@djdev.me>
Everything the sleep driver knew about T8140 was in its code: the offsets
of the power words it drives itself, the lists of words macOS was
measured with at the commit and the wake, the stray words, the
coprocessors that must be bound or stopped, the wake sources' names, the
power-gate words and the PCIe host the radio is on. Put them in a
struct apple_sleep_soc, one per compatible, and have the shared code
take them from there. The books kept per word, until now sized by
T8140's tables, are allocated for the SoC's lists at probe.

The match table holds only SoCs whose sleep has been measured and tested,
so only T8140 for now. Every other SoC doesn't match: the driver doesn't
bind there, and s2idle stays the only sleep, as before. Another SoC is
added by its own data and compatible, after the same test.

The Kconfig help names Apple SoCs and the tested list. No functional
change on T8140: each table and value in the new data is the one the
code used before.

Signed-off-by: Diljit Singh <hey@djdev.me>
A word that one of a SoC's lists names but its full list lacks is skipped
at the wake without a word, and a duplicate splits the books kept for it.
Check every matched SoC's data for both, that its lists fit the driver's
books, that its wake sources are in range and unique, and that the match
table holds only the SoCs whose sleep was tested.

Signed-off-by: Diljit Singh <hey@djdev.me>
…h data

The controller's state is saved across a firmware-driven suspend only on
"apple,t8140-aic3", by a compatible check. Make that a flag in the AIC's
own match data, so the SoC that gets the sleep driver next turns it on
there.

No functional change: only T8140's data sets it.

Signed-off-by: Diljit Singh <hey@djdev.me>
Whether a firmware-driven sleep stops the DCP's firmware and powers it
down, restarting it warm after, is decided by "apple,t8140-dcp" and
"apple,t8140-dcpext" compatible checks. So is the log counter echo that
the warm restart needs, and the internal panel's power cycle at DPMS
off. Make both flags of the DCP's own match data, s2r and s2r_ext, set
for T8140's two processors.

No functional change: the flags are set exactly where the compatibles
matched. The apple-dcp host test's copy of the struct gets the two
fields, as it compiles T8140's two initializers.

Signed-off-by: Diljit Singh <hey@djdev.me>
DjDeveloperr added a commit to aurora-silicon/alarm-aurora that referenced this pull request Nov 9, 2026
… RTC

aurora-silicon/linux#1334 renames the deep-sleep driver for all Apple
SoCs: CONFIG_APPLE_T8140_SLEEP becomes CONFIG_APPLE_SOC_SLEEP, and
asahi.config sets the new one. #1333 makes the PMU RTC the J700's rtc0,
built in, so asahi.config sets CONFIG_RTC_DRV_APPLE_PMU=y. Record both in
the resolved config, which NixOS builds from without merging the
fragment and then checks against it.

TODO: both need the kernel pin to carry #1334 and #1333, which the
PKGBUILD's TODO says too. Under d4d2678 neither symbol changes anything:
it has no sleep driver, and olddefconfig drops the unknown one.

Signed-off-by: Diljit Singh <hey@djdev.me>
DjDeveloperr added a commit to aurora-silicon/nixos-aurora that referenced this pull request Nov 9, 2026
Refresh kernel/config from alarm-aurora 5c410f8 (alarm-aurora#199). It
renames CONFIG_APPLE_T8140_SLEEP to CONFIG_APPLE_SOC_SLEEP, as
aurora-silicon/linux#1334 does for the sleep driver, and builds the PMU
RTC in (CONFIG_RTC_DRV_APPLE_PMU=y), as #1333 does to make it the J700's
rtc0. Both pins put those lines in asahi.config, and this build validates
against that fragment after merging only nixos.config.

TODO: this needs a kernel pin with #1334 and #1333, as the comment in
overlay.nix says. Under d4d2678 the fragment still asks for the PMU RTC
as a module, so the config's =y doesn't validate there.

Signed-off-by: Diljit Singh <hey@djdev.me>
…neric

Bring the T8140 sleep follow-ups under the renamed driver. The one
conflict is the comment above the enclave's tell, which takes the
follow-ups' wording and the new apple_sleep_enclave_tell() name.

Signed-off-by: Diljit Singh <hey@djdev.me>
The follow-ups were written against t8140-sleep.c. Move their last uses
of the old names to the renamed driver:

- apple_sleep_commit_stops_coprocs() reads apple_sleep, not
  t8140_sleep, which no longer exists.
- The enclave's commit checks CONFIG_APPLE_SOC_SLEEP. The old
  APPLE_T8140_SLEEP is now a transitional symbol, which never reaches
  autoconf.h, so the old check was always false and every sleep commit
  would have been refused.
- The SEP host test's mock and its no-capability-check mutation follow
  the new symbol.

No functional change against the follow-ups on the old driver.

Signed-off-by: Diljit Singh <hey@djdev.me>
@DjDeveloperr
DjDeveloperr changed the base branch from fix/t8140-sleep-review to fix/t8140-sleep-followups November 9, 2026 14:57
…neric

Brings in the page select resend and integration/aurora 15f88e1. Git
carries the resend's hunk into sleep.c without a conflict; the next
commit moves it to the new names.

Signed-off-by: Diljit Singh <hey@djdev.me>
The debug port's page select resend was written against t8140-sleep.c.
Its two calls go to sleep_hpm_cmd(), the renamed t8140_hpm_cmd(), which
no longer exists.

No functional change against the resend on the old driver.

Signed-off-by: Diljit Singh <hey@djdev.me>
…neric

Brings in #1208's aop-bootargs host test fix. No conflicts.

Signed-off-by: Diljit Singh <hey@djdev.me>
Signed-off-by: Diljit Singh <hey@djdev.me>
…neric

Brings in integration/aurora ac11649 (#1311, PCIe multi power domain
support) through #1208. No conflicts.

Signed-off-by: Diljit Singh <hey@djdev.me>
@DjDeveloperr

Copy link
Copy Markdown
Contributor Author

Superseded by #1445 (merged as 2b05915); its changes are in integration/aurora. The generic driver is drivers/soc/apple/sleep.c.

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.

1 participant