Skip to content

fix(splash): stop the Pi 2 boot splash falling back to the text theme - #3199

Merged
vpetersson merged 2 commits into
masterfrom
fix/plymouth-device-timeout-slow-pi
Jul 16, 2026
Merged

fix(splash): stop the Pi 2 boot splash falling back to the text theme#3199
vpetersson merged 2 commits into
masterfrom
fix/plymouth-device-timeout-slow-pi

Conversation

@vpetersson

Copy link
Copy Markdown
Contributor

Issues Fixed

The Plymouth boot splash never paints on the Pi 2 — the screen shows the text plugin's status output on black instead of the Anthias splash. Not reproducible on a Pi 3 A+ despite byte-identical config.txt, cmdline.txt, theme files and Plymouth version, which is what made it look board-specific and mysterious.

Description

plymouthd waits DeviceTimeout seconds for a graphics device before concluding there is none. Our plymouthd.conf never set the key, so it inherited the distro default of 8s. A plymouth.debug trace on the Pi 2 shows vc4's /dev/dri/card0 only appearing at ~14.3s, while the timeout expires at ~12.65s:

04.646  Device timeout is set to nan        <- our plymouthd.conf
04.648  Device timeout is set to 8.000000   <- distro defaults
12.652  Timeout elapsed, looking for devices from udev
12.661  Creating non-graphical devices, since there's no suitable graphics hardware
12.662  adding text display for terminal /dev/tty1
14.325  got add event for device /dev/dri/card0
14.325  ignoring since we're already using text splash for local console

plymouthd commits to the text splash, then explicitly ignores card0 when it finally arrives. A Pi 3 A+ (Cortex-A53 @1.4GHz) probes vc4 inside the 8s window; the Pi 2 (Cortex-A7 @900MHz) does not. Same config, different clock — so this is a timing race, and any board slow enough to probe vc4 past 8s is affected.

Two changes:

  1. DeviceTimeout=30 in plymouthd.default, giving slower boards room. This costs nothing on a genuinely headless board: the wait runs alongside boot and plymouth-quit still tears the splash down at boot completion.

  2. Rebuild the initramfs from a handler. This is part of the fix, not incidental — plymouthd starts from the initramfs and reads its theme and DeviceTimeout from the copy baked in there, so a config-only change would be inert. The role wrote plymouthd.conf after plymouth-set-default-theme -R, so the initramfs only ever embedded the pre-copy config. It happened to work because cleanup() in install.sh runs apt-get install plymouth --reinstall, which triggers update-initramfs afterwards — load-bearing by accident. Dropping -R and rebuilding once from a handler makes the ordering explicit and correct.

Validation

Real Pi 2 (armhf/Raspbian trixie, display attached):

  1. Reverted the board to the exact pre-fix state (conf without DeviceTimeout, distro plymouthd.defaults, initramfs rebuilt).
  2. Ran the splashscreen role against it — handler fired.
  3. Confirmed DeviceTimeout=30 is embedded inside initramfs7, not just on disk.
  4. Rebooted. Trace now shows:
Device timeout is set to 30.000000
drm driver: vc4
Creating 1920x1080 renderer head
Loading boot splash theme '.../anthias/anthias.plymouth'
show_splash_screen : starting boot animation
executing script file

no pixel displays: 0. Text fallback: 0. Only theme loaded: anthias.

Checklist

  • I have performed a self-review of my own code.
  • New and existing unit tests pass locally and on CI with my changes. (ansible-lint ansible/ passes, production profile, 0 failures.)
  • I have done an end-to-end test for Raspberry Pi devices. (Role run + reboot on a real Pi 2 with a display; see Validation.)
  • I have tested my changes for x86 devices. Not tested on x86 — the role runs there too, but x86 boots via GRUB/efifb and was not part of this repro. The change is a timeout increase plus an initramfs rebuild, both benign there, but worth a sanity check before merge.
  • I added a documentation for the changes I have made (when necessary). Not needed — rationale is captured in-file.

🤖 Generated with Claude Code

plymouthd waits DeviceTimeout seconds for a graphics device before
deciding there is none. Our plymouthd.conf never set the key, so it
inherited the distro default of 8s.

On slower boards that is not enough. A plymouth.debug trace on a Pi 2
shows vc4's /dev/dri/card0 only appearing ~14.3s in, while the timeout
expires at ~12.65s:

    04.646  Device timeout is set to nan        <- our plymouthd.conf
    04.648  Device timeout is set to 8.000000   <- distro defaults
    12.652  Timeout elapsed, looking for devices from udev
    12.661  Creating non-graphical devices, since there's no suitable
            graphics hardware
    12.662  adding text display for terminal /dev/tty1
    14.309  got add event for device /dev/fb0
    14.310  ignoring since we're already using text splash for local
            console
    14.325  got add event for device /dev/dri/card0
    14.325  ignoring since we're already using text splash

plymouthd commits to the text splash and then explicitly ignores card0
when it finally arrives, so the Anthias splash never paints — the screen
shows the text plugin's status output instead. A Pi 3 A+ probes vc4
inside the 8s window, which is why identical config renders there.

Set DeviceTimeout=30 to give the slower boards room. This costs nothing
when there genuinely is no display: the wait runs alongside boot and
plymouth-quit still tears the splash down at boot completion.

Rebuilding the initramfs is part of the fix, not incidental. plymouthd
starts from the initramfs and reads its theme and DeviceTimeout from the
copy baked in there, so a config-only change is inert. The role wrote
plymouthd.conf *after* `plymouth-set-default-theme -R`, meaning the
initramfs only ever embedded the pre-copy config; it happened to work
because install.sh's `apt-get install plymouth --reinstall` in cleanup()
triggers update-initramfs afterwards. Drop the -R and rebuild once from
a handler, after every file the role installs is in place.

Validated on a Pi 2 (192.168.200.210, armhf/Raspbian trixie): reverted
to the pre-fix state, ran the role, confirmed DeviceTimeout=30 is
embedded in initramfs7, rebooted with a display attached. Trace now
shows the drm renderer opening a 1920x1080 head and loading the anthias
theme, with zero "no pixel displays" and zero text fallbacks.

Co-Authored-By: Claude Opus 4.8 (1M context) <[email protected]>
@vpetersson
vpetersson requested a review from a team as a code owner July 16, 2026 11:24
@vpetersson vpetersson self-assigned this Jul 16, 2026
@vpetersson
vpetersson requested a review from Copilot July 16, 2026 11:24

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Adjusts the splashscreen Ansible role so Plymouth on slower Raspberry Pi boards (notably Pi 2) reliably waits long enough for /dev/dri/card0 to appear, preventing fallback to the text splash and ensuring the Anthias theme actually renders during early boot (initramfs stage).

Changes:

  • Adds DeviceTimeout=30 to the Plymouth daemon defaults shipped by the role.
  • Stops rebuilding initramfs mid-role via plymouth-set-default-theme -R; instead triggers a single end-of-play initramfs rebuild via a handler.
  • Notifies the initramfs regeneration handler when theme files and Plymouth config files are updated.

Reviewed changes

Copilot reviewed 3 out of 3 changed files in this pull request and generated 1 comment.

File Description
ansible/roles/splashscreen/tasks/main.yml Adds handler notifications and removes -R to ensure initramfs rebuild happens after all relevant files are in place.
ansible/roles/splashscreen/handlers/main.yml Introduces a handler to regenerate initramfs once per play when notified.
ansible/roles/splashscreen/files/plymouthd.default Sets DeviceTimeout=30 with rationale to avoid graphics timeout on slower boards.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread ansible/roles/splashscreen/files/plymouthd.default
The header claimed the file was distribution defaults overwritten during
upgrades. It is Ansible-managed and installed to two paths, and the old
wording was misleading in at least one of them.

Spell out the split instead: plymouthd reads /etc/plymouth/plymouthd.conf
first and falls back to /usr/share/plymouth/plymouthd.defaults for absent
keys, and the defaults copy is reverted to the distro's own by the
plymouth --reinstall in install.sh's cleanup(). That is why every key we
depend on has to be set here rather than left to fall through — the
reason DeviceTimeout is pinned in this file at all.

Co-Authored-By: Claude Opus 4.8 (1M context) <[email protected]>
@sonarqubecloud

Copy link
Copy Markdown

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 3 out of 3 changed files in this pull request and generated no new comments.

@vpetersson
vpetersson merged commit 791d0a8 into master Jul 16, 2026
10 checks passed
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