Skip to content

Enable validated deep sleep and charger wake - #1

Open
gh123man wants to merge 18 commits into
mainfrom
codex/deep-sleep-support
Open

Enable validated deep sleep and charger wake#1
gh123man wants to merge 18 commits into
mainfrom
codex/deep-sleep-support

Conversation

@gh123man

@gh123man gh123man commented Jul 31, 2026

Copy link
Copy Markdown
Owner

Summary

  • add an explicit per-device ARMADA_MEM_SLEEP_MODE policy
  • select validated deep suspend for Retroid Pocket 6, AYN Odin 2/Mini/Portal, and AYN Thor
  • fail closed when a requested mem-sleep variant is invalid or unavailable
  • configure systemd for SuspendState=mem
  • add host-side suspend-dispatch coverage
  • add an RP6 PMIC GLINK wake policy that:
    • accepts physical power-button wakes
    • accepts a real external-power transition from offline to online
    • returns unrelated charger-firmware/GLINK notifications directly to deep sleep while user.slice remains frozen
    • tracks unplug/replug transitions across hidden resumes
    • retries bounded transient wakeup_count / power/state -EBUSY races
    • fails open for missing or unrecognized wake data
  • document the Qualcomm/Android charger-wake architecture and rejected alternatives
  • make the local package override build recipe compatible with macOS Bash 3.2

Why

Armada's existing real-suspend dispatcher writes mem but does not select or validate the underlying /sys/power/mem_sleep variant. Devices can therefore enter the kernel default rather than deep suspend, while unsupported devices need to retain fake suspend safely.

This PR keeps fake suspend as the global default and opts in only devices covered by the accompanying kernel fixes.

On SM8550, USB-C and battery state are owned by charger firmware on the ADSP and delivered through PMIC GLINK. A real charger attach and unsolicited BATTMGR_NOTIFICATION traffic therefore share the same IPCC/GLINK wake transport. The interrupt handler cannot know the packet semantics before the AP resumes.

Android handles this with a continuously running autosuspend policy. Armada uses a one-shot systemd suspend transaction, so without an equivalent policy every background GLINK notification ends suspend and thaws Gamescope. The new system-sleep hook classifies the wake while user.slice is still frozen and uses the standard atomic wakeup_count protocol to re-enter deep sleep when the wake is transport-only.

Kernel dependency: gh123man/armada-packages#1

The implementation research and kernel/userspace boundary are documented in docs/deep-sleep-charger-wake.md.

Build-only Justfile changes

The Justfile diff is unrelated to suspend behavior and does not change the installed image. It is a behavior-preserving compatibility adjustment made so the local image build can run with macOS's bundled Bash 3.2:

  • replace Bash 4-only mapfile and associative-array package validation with an indexed array populated by while read and a linear membership check
  • append the optional GITHUB_TOKEN secret directly to BUILD_ARGS, avoiding expansion of an empty SECRET_ARGS array under Bash 3.2 with set -u

Armada's normal modern-Linux build environment does not require these changes. They can be split into a separate PR or dropped without affecting the kernel, deep-sleep policy, or runtime behavior.

Validation

  • bash -n passed for the dispatcher, wake policy, and test scripts
  • tests/suspend-dispatch-test.sh passed, including fake suspend, successful deep selection, unavailable deep, invalid variants, and direct state fallback
  • tests/suspend-wake-policy-test.sh passed, including power-key priority, unknown-wake fail-open behavior, charger attach, plugged → unplug → replug tracking, background GLINK resuspend, and transient -EBUSY retry
  • verified per-device environment resolution: selected SM8550 devices resolve to mem + deep; non-opted-in devices remain on fake suspend
  • built a complete arm64 bootc image using the local kernel carrier and passed required bootc container lint checks
  • booted the final policy image wake-policy-power-state-0c1f4b81 on a Retroid Pocket 6 with Linux 7.0.11
  • completed repeated ordinary and in-game deep-suspend/resume cycles, including active rsinput haptics, with no kernel suspend failure
  • verified charging remains around 26 W during deep sleep after negotiation
  • verified charger attach while asleep wakes the device and begins charging
  • verified unplug while asleep remains a hidden background wake, followed by replug producing a full intentional wake
  • reproduced a notification racing resuspend and returning -EBUSY; the bounded retry fix kept the device asleep and subsequent suspend accounting remained clean
  • confirmed battery reporting, speaker audio, ADSP/CDSP, and game audio remained healthy after testing

Known behavior

A background unplug/GLINK wake can briefly expose the last compositor frame (often the sleep-animation frame) before the policy returns to deep sleep. The kernel must resume the AP and display devices before the PMIC GLINK packet can be decoded, while the policy runs later in the systemd-sleep post hook. Gamescope remains frozen and the device does return to real deep sleep; eliminating the flash safely requires earlier display blanking or a kernel/display coordination change and is intentionally left for follow-up.

@gh123man
gh123man marked this pull request as ready for review July 31, 2026 21:44
@gh123man gh123man changed the title Enable validated deep sleep on supported devices Enable validated deep sleep and charger wake Aug 3, 2026
@gh123man
gh123man force-pushed the codex/deep-sleep-support branch from 9b4b3ab to 7260963 Compare August 3, 2026 01:10
@gh123man

gh123man commented Aug 3, 2026

Copy link
Copy Markdown
Owner Author

Post-rebase firmware integration fix

The latest armada-packages rebase included upstream commit 63010cc, which gives the RP6 a device-specific ADSP and speaker-firmware path at qcom/sm8550/retroidpocket/rp6. The Armada image still shipped those known-working blobs only at qcom/sm8550/ayn/odin2, so the first combined snapshot could not start the ADSP. On hardware this appeared as zero ALSA cards and battery power-supply attributes returning EAGAIN/0%.

Commit 8936883 adds a forward-compatible RP6 firmware alias to the existing Odin 2 firmware directory. A native RP6 firmware directory can replace the alias later without another DTB change. The image build now fails if the ADSP, ADSP DTB, speaker-amplifier, battmgr, or ADSP JSON files are unresolved. All eight ARM64 Fedora tests pass, including the new RP6 firmware layout regression test.

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