Watch
1
0
Fork
You've already forked SouveraineOS
0
SouveraineOS/saf/device/display.md
Fimeg bde961c6f2 saf: one spine — device, state, and work under the index
PAF becomes saf/device (history kept), STATE.md dissolves
into saf/state.md with the dated era archived, the substrate
SAF moves up from souveraine, and every agreement points at
saf/INDEX.md and nowhere else. one map, nothing to remember
2026-08-18 09:47:30 -04:00

5.9 KiB

PAF · Display — SW43408 panel, DSI, bias rails (SOLVED 2026-07-10)

Current regression — verified on glass 2026-07-11

On current kernel 7.1.1-sdm845-g56b0a053bef8, a true unplugged cold boot still produces a green flash during boot. Green flashes also remain on wake. During AP-side DT2W testing the first double tap sometimes does a visible green-flash/black half-wake and the second wakes the panel. The kernel trace shows the first gesture reaches panel prepare and is immediately followed by unprepare; there are no DSI/DPU errors. In one successful wake the visible frame remained stale despite a synchronized system clock and live Hyprland + Quickshell processes. This is an observation, not proof of a panel-only root cause; preserve it for the display/DPMS investigation.

Recovery and clock distinction, 2026-07-11: after an instrumented libssc-triggered lockup, blueline-screen-toggle on re-prepared the panel but it unprepared again seconds later even with hypridle stopped. Do not churn panel/FTS resets in that state. A normal reboot of the known-good current slot restored the panel and compositor. The first post-boot ii screenshot still showed the Jul-06 20:00 clock floor even though NTP had corrected system time; restarting only Quickshell (qs -c ii kill, then qs -c ii) refreshed it to the real time. Therefore an old ii clock is not alone evidence of a frozen scanout. The remaining task is to prevent ii from retaining the pre-NTP clock, not to reset the panel again.

Cold boot → Hyprland AND power-button sleep/wake visually verified on kernel g766205b60588. Read this whole file before touching panel-lg-sw43408.c, the labibb regulator, or the display DT.

The doctrine: WARM-CYCLE. Do not dismantle again.

The working design in drivers/gpu/drm/panel/panel-lg-sw43408.c:

  • .prepare = regulators + reset pulse only. No DCS.
  • .enable = the ENTIRE DCS init (gamma, TE, sleep-out, vendor regs, PPS, compression, display-on) — runs over a fully-up DSI link, onto a still-powered DDIC, on every DPMS-on.
  • .disable = display_off + enter_sleep (HS mode). That is ALL DPMS-off does.
  • No .unprepare power-off. The panel keeps vddi/vpnl forever after first boot; reset is never re-asserted at runtime.

Why: upstream's prepare-time cold-cycle design cannot cold-start this panel. Full power-off + reset + re-init produces a green flash (display-on latching onto random GRAM) then permanent black, on every transition. That is the original "screen won't wake without the sdm845-mainline hack" bug (David's report). The warm-cycle shape IS the fix — the panel is re-initialized warm, never cold.

History: the working design was dismantled on 2026-07-09 by ee6611adb ("adopt upstream prepare-time init") and a day of ordering experiments failed to make cold-start work (display-on before PPS, after PPS, downstream power sequencing — all green-flash-black). 766205b60 restored the warm-cycle architecture. Any future "align with upstream" refactor must first prove cold-start on real glass.

Bias rails: LAB/IBB under SWIRE (hardware) control

Matching downstream: the DDIC drives the OLED bias rails over the SWIRE wire, not software.

  • DT: qcom,swire-control on the pmi8998 labibb node (1b02532a4).
  • Driver: SWIRE ops are software no-ops (enable/disable/set_voltage return 0); probe writes IBB ENABLE_CTL=0x40 (SWIRE_RDY, module-enable cleared). LAB ENABLE_CTL=0x00 is CORRECT in SWIRE mode (slaved to IBB in hardware).
  • Behavior: panel sleep-in → rails physically drop; sleep-out → rails rise. Register-verified live across DPMS cycles: STATUS1 (IBB 0xdc08 / LAB 0xde08 on regmap 0-03) reads 00/00 off → 80/a0 on.
  • The panel driver's supplies are vddi + vpnl ONLY. It never touches LAB/IBB. c789daaa8 fixed the tail end of the old design (unprepare disabling never-enabled rails → unbalanced-disable → panel->prepared stuck true → EBUSY zombie); moot under warm-cycle but the lesson stands: an error return from unprepare wedges the prepared flag forever.
  • Voltage: software set_voltage is a no-op; hardware stays at the bootloader's 5.5V programming.

Userspace wake path

  • Hyprland (Lua build) power-button / tap-to-wake toggle: blueline-screen-toggle on the phone. Wake needs BOTH hl.dsp.dpms("on") AND hl.dsp.force_renderer_reload() — dpms-on alone can issue a commit with no real CRTC transition (crtc=NULL skips drm_panel_prepare; long-standing compositor-side hole). Gotcha fixed 2026-07-10: the script called forceRendererReload(), which the Lua Hyprland renamed to force_renderer_reload() — every power-button wake silently no-op'd. Dispatcher names must be verified against the running Hyprland, errors surface only in the hyprctl reply.
  • greetd → start-hyprland as initial session; the boot chain fbcon → greetd → Hyprland does one panel takeover, warm.

Diagnostic quick kit

  • Rails now: sudo grep -E "^(dc08|de08):" /sys/kernel/debug/regmap/0-03/registers (80/a0 = up, 00/00 = SWIRE-dropped).
  • Compositor truth: grim screenshot — separates "compositor renders" from "glass shows" (they diverged for two days; the screenshot was pixel-perfect while the glass was black).
  • DPMS from SSH: HYPRLAND_INSTANCE_SIGNATURE=$(ls /run/user/1000/hypr/) XDG_RUNTIME_DIR=/run/user/1000 hyprctl dispatch 'hl.dsp.dpms("off"|"on")'.
  • drm.debug=0x1ff wraps the dmesg ring in ~130ms of transition traffic — use journalctl -k or a lower mask for transition captures.
  • Boot-time DSI PLL lock failed + already disabled/unprepared clk warnings at ~0.4s: probe-time deferred-probe noise, once per boot, benign-but-ugly (error path double-disables a clk). Not a transition bug.

Known-good fallback

../staging/deploy-139aa/boot-139aa7748181-pmoschain.img — pre-SWIRE-era kernel (stmfts touch, warm-cycle display of that era). Module tree already on the phone. Prefer fixing forward on the blueline tip.