Flaky boot is display bring-up: dispcc reprograms ABL's live scanout #17

Open
opened 2026-08-25 10:49:04 +00:00 by kit · 2 comments
Owner

The intermittent "device doesn't come back from reboot" failure that has taxed this project for weeks is display bring-up. It is not U-Boot, not the SD card, not the battery, and not random.

Evidence — single-variable test (2026-08-25)

image display boots hangs
A &mdss disabled + initcall_blacklist=disp_cc_sm8250_driver_init,video_cc_sm8150_driver_init,gpu_cc_sm8150_driver_init 5+ consecutive 0
B identical, display re-enabled 4 2 (1st and 4th)

Images A and B were byte-identical apart from the display change. Both carried: ldo17 at 3304000, pm8150b removed, ramoops relaid to match stock, ss_plog + sec_debug reservations, CONFIG_GTS6L_SECLOG, clk_ignore_unused pd_ignore_unused regulator_ignore_unused, loglevel=7, log_buf_len=4M.

~50% hang rate with display on, 0/5+ with it off.

Mechanism

ABL hands over a live 2560x1600 x8r8g8b8 stride-10240 scanout of cont_splash_mem at 0x9c400000. Mainline DRM/MSM has no continuous-splash handoff for sm8150, so dispcc reprograms the display clocks underneath a display that is mid-scanout.

This is the same mechanism MAINLINE-NOTES already documented from the console side — "dispcc probes and reprograms the display clocks, the scanout changes shape (two panes, shrunken)". That was recorded as a cosmetic problem (we go blind) once the console moved to USB. It is not cosmetic; roughly half the time it takes the boot with it.

Corroborating: pre-fix boots log dsi 0 TIMEOUT_STATUS=00000001 and dsi 1 TIMEOUT_STATUS=00000001, six times, at 14.5 s.

It is a hang, not a crash

After a hung boot, TWRP reports reset_reason = NPON and reset_klog / reset_summary / auto_comment / reset_tzlog are all 0 bytes. Samsung's debug layer records resets; a hang that gets power-cycled out of leaves no record. So there is no post-mortem for this — the panel console is the only window, which is why it stayed invisible for so long.

Not yet isolated

Four things were disabled together. Still to bisect:

  • &mdss itself
  • disp_cc_sm8250_driver_init (sm8150 uses the sm8250 dispcc driver — dispcc-sm8250.c matches qcom,sm8150-dispcc)
  • video_cc_sm8150_driver_init
  • gpu_cc_sm8150_driver_init

dispcc is the prime suspect — it is what reprograms the display clocks under the live scanout. videocc/gpucc were likely blacklisted alongside it historically and are probably innocent.

Consequences

Keep display off for bring-up work. A device that boots every time is worth far more than a panel, and the framebuffer console still works in that configuration — that is how the ldo17 regression was caught.

Every experiment run before 2026-08-25 was collected on a platform that failed to boot about a third of the time. Results whose arms were single boots should be treated as suspect (see #16 for the class of error this causes).

Real fix (open question)

Either implement continuous-splash handoff, or have the bootloader stop the display before handing over. The latter is simpler but costs the U-Boot/earlycon framebuffer console, which is currently our only pre-USB diagnostic channel — so it is not free.

Related: #10 and #12 touch the same panel driver; #6 depends on how the splash handover is resolved.

Full write-up: baselines/flaky-boot-display.md.

The intermittent "device doesn't come back from reboot" failure that has taxed this project for weeks is **display bring-up**. It is not U-Boot, not the SD card, not the battery, and not random. ## Evidence — single-variable test (2026-08-25) | image | display | boots | hangs | |---|---|---|---| | A | `&mdss` disabled + `initcall_blacklist=disp_cc_sm8250_driver_init,video_cc_sm8150_driver_init,gpu_cc_sm8150_driver_init` | 5+ consecutive | **0** | | B | identical, display re-enabled | 4 | **2** (1st and 4th) | Images A and B were byte-identical apart from the display change. Both carried: ldo17 at 3304000, pm8150b removed, ramoops relaid to match stock, `ss_plog` + `sec_debug` reservations, `CONFIG_GTS6L_SECLOG`, `clk_ignore_unused pd_ignore_unused regulator_ignore_unused`, `loglevel=7`, `log_buf_len=4M`. ~50% hang rate with display on, 0/5+ with it off. ## Mechanism ABL hands over a **live** 2560x1600 x8r8g8b8 stride-10240 scanout of `cont_splash_mem` at `0x9c400000`. Mainline DRM/MSM has no continuous-splash handoff for sm8150, so `dispcc` reprograms the display clocks underneath a display that is mid-scanout. This is the same mechanism MAINLINE-NOTES already documented from the console side — "dispcc probes and reprograms the display clocks, the scanout changes shape (two panes, shrunken)". That was recorded as a *cosmetic* problem (we go blind) once the console moved to USB. It is not cosmetic; roughly half the time it takes the boot with it. Corroborating: pre-fix boots log `dsi 0 TIMEOUT_STATUS=00000001` and `dsi 1 TIMEOUT_STATUS=00000001`, six times, at 14.5 s. ## It is a hang, not a crash After a hung boot, TWRP reports `reset_reason` = `NPON` and `reset_klog` / `reset_summary` / `auto_comment` / `reset_tzlog` are all **0 bytes**. Samsung's debug layer records *resets*; a hang that gets power-cycled out of leaves no record. So there is no post-mortem for this — the panel console is the only window, which is why it stayed invisible for so long. ## Not yet isolated Four things were disabled together. Still to bisect: - `&mdss` itself - `disp_cc_sm8250_driver_init` (sm8150 uses the sm8250 dispcc driver — `dispcc-sm8250.c` matches `qcom,sm8150-dispcc`) - `video_cc_sm8150_driver_init` - `gpu_cc_sm8150_driver_init` **dispcc is the prime suspect** — it is what reprograms the display clocks under the live scanout. videocc/gpucc were likely blacklisted alongside it historically and are probably innocent. ## Consequences Keep display **off** for bring-up work. A device that boots every time is worth far more than a panel, and the framebuffer console still works in that configuration — that is how the ldo17 regression was caught. Every experiment run before 2026-08-25 was collected on a platform that failed to boot about a third of the time. Results whose arms were single boots should be treated as suspect (see #16 for the class of error this causes). ## Real fix (open question) Either implement continuous-splash handoff, or have the bootloader stop the display before handing over. The latter is simpler but costs the U-Boot/earlycon framebuffer console, which is currently our only pre-USB diagnostic channel — so it is not free. Related: #10 and #12 touch the same panel driver; #6 depends on how the splash handover is resolved. Full write-up: `baselines/flaky-boot-display.md`.
Author
Owner

Bisected: two separate failures, one root cause

The four things that were disabled together are not equivalent. Measured on the now-reliable platform:

configuration panel boot
all disabled (&mdss off + 3 initcalls blacklisted) readable 5+ clean
dispcc + videocc + gpucc bound, &mdss still off freezes 6/6 OK
everything enabled freezes 2 hangs in 4

dispcc corrupts the display but does not hang the system. &mdss is what hangs it.

Why dispcc corrupts the panel

disp_cc_sm8250_probe() (sm8150 uses the sm8250 driver) unconditionally rewrites both display PLLs:

clk_lucid_pll_configure(&disp_cc_pll0, regmap, &disp_cc_pll0_config);
clk_lucid_pll_configure(&disp_cc_pll1, regmap, &disp_cc_pll1_config);

/* Enable clock gating for MDP clocks */
regmap_update_bits(regmap, 0x8000, 0x10, 0x10);

No check for whether anything is running off them. ABL hands over a live dual-DSI scanout clocked from exactly those PLLs, so this yanks the configuration out from under an active display — which is the "two panes, shrunken" garbling, and it happens with no DRM involvement at all. That is why disabling &mdss alone was never sufficient and the initcall blacklist was also needed.

This looks like a genuine upstream bug, not a gts6l quirk: a clock controller should not reconfigure a PLL that is already locked and running, on any Qualcomm device that boots with a bootloader splash. Plausible fix is small — read the PLL state at probe and skip clk_lucid_pll_configure() if it is already enabled/locked.

Why downstream does not have either problem

Confirmed from Samsung's source, not inferred. dsi_display_splash_res_init() in drivers/gpu/drm/msm/dsi-staging/dsi_display.c:

  • detects a live scanout by reading a controller register — dsi_display_get_cont_splash_status()hw->ops.get_cont_splash_status(hw)
  • takes votes on the GDSC, core clk and link clk that are already on, rather than programming them
  • votes the regulators on rather than toggling
  • dsi_config_host_engine_state_for_cont_splash() syncs driver state to hardware state, never the reverse
  • dsi_panel_bl_handoff() inherits brightness without re-init

And on the panel side it is explicit (samsung_lego/ss_dsi_panel_common.c:2689):

if (!vdd->samsung_splash_enabled)
        ss_send_cmd(vdd, TX_ON_PRE_SEQ);
else
        LCD_INFO("splash booting.. do not send ON_PRE_SEQ..\n");

Mainline 6.17 has no equivalent whatsoevercont_splash appears in zero files under drivers/gpu/drm/msm/. There is no detection, no adoption, no skip.

Note our panel-samsung-ana38401.c is not at fault here: its prepare() does a correct cold init (reset asserted 70 ms, released, wait for tcon_rdy). The problem is that a correct cold init is being performed on live hardware, in the wrong order, by a stack that does not know the hardware is live.

Consequences

  • The two goals conflict: dispcc must stay blacklisted to keep the panel console (which is how the ldo17 regression was caught), but it is not needed for boot stability.
  • The &mdss hang is the one that matters for a usable device, and it is the harder of the two — it is the cont_splash gap proper.
  • videocc/gpucc were almost certainly innocent bystanders blacklisted alongside dispcc historically; nothing here implicates them.

Method note

The first attempt at this bisect produced six clean boots that meant nothing: a stale bootargs left in U-Boot's saved env from an unrelated experiment was being merged with the boot image's cmdline, so the kernel saw two initcall_blacklist= entries and dispcc stayed blacklisted despite the image saying otherwise. Caught only because dispcc=unbound contradicted what the test claimed to be testing. Any arm of this bisect should verify the thing it claims to have changed actually changed — /sys/bus/platform/devices/af00000.clock-controller/driver for dispcc.

## Bisected: two separate failures, one root cause The four things that were disabled together are not equivalent. Measured on the now-reliable platform: | configuration | panel | boot | |---|---|---| | all disabled (`&mdss` off + 3 initcalls blacklisted) | readable | 5+ clean | | dispcc + videocc + gpucc **bound**, `&mdss` still off | **freezes** | **6/6 OK** | | everything enabled | freezes | **2 hangs in 4** | **dispcc corrupts the display but does not hang the system. `&mdss` is what hangs it.** ### Why dispcc corrupts the panel `disp_cc_sm8250_probe()` (sm8150 uses the sm8250 driver) unconditionally rewrites both display PLLs: ```c clk_lucid_pll_configure(&disp_cc_pll0, regmap, &disp_cc_pll0_config); clk_lucid_pll_configure(&disp_cc_pll1, regmap, &disp_cc_pll1_config); /* Enable clock gating for MDP clocks */ regmap_update_bits(regmap, 0x8000, 0x10, 0x10); ``` No check for whether anything is running off them. ABL hands over a live **dual-DSI** scanout clocked from exactly those PLLs, so this yanks the configuration out from under an active display — which is the "two panes, shrunken" garbling, and it happens with **no DRM involvement at all**. That is why disabling `&mdss` alone was never sufficient and the initcall blacklist was also needed. This looks like a genuine upstream bug, not a gts6l quirk: a clock controller should not reconfigure a PLL that is already locked and running, on any Qualcomm device that boots with a bootloader splash. Plausible fix is small — read the PLL state at probe and skip `clk_lucid_pll_configure()` if it is already enabled/locked. ### Why downstream does not have either problem Confirmed from Samsung's source, not inferred. `dsi_display_splash_res_init()` in `drivers/gpu/drm/msm/dsi-staging/dsi_display.c`: - detects a live scanout by reading a controller register — `dsi_display_get_cont_splash_status()` → `hw->ops.get_cont_splash_status(hw)` - takes **votes** on the GDSC, core clk and link clk that are already on, rather than programming them - votes the regulators on rather than toggling - `dsi_config_host_engine_state_for_cont_splash()` syncs **driver state to hardware state**, never the reverse - `dsi_panel_bl_handoff()` inherits brightness without re-init And on the panel side it is explicit (`samsung_lego/ss_dsi_panel_common.c:2689`): ```c if (!vdd->samsung_splash_enabled) ss_send_cmd(vdd, TX_ON_PRE_SEQ); else LCD_INFO("splash booting.. do not send ON_PRE_SEQ..\n"); ``` **Mainline 6.17 has no equivalent whatsoever** — `cont_splash` appears in zero files under `drivers/gpu/drm/msm/`. There is no detection, no adoption, no skip. Note our `panel-samsung-ana38401.c` is *not* at fault here: its `prepare()` does a correct cold init (reset asserted 70 ms, released, wait for `tcon_rdy`). The problem is that a correct cold init is being performed on live hardware, in the wrong order, by a stack that does not know the hardware is live. ### Consequences - The two goals conflict: **dispcc must stay blacklisted to keep the panel console** (which is how the ldo17 regression was caught), but it is not needed for boot stability. - The `&mdss` hang is the one that matters for a usable device, and it is the harder of the two — it is the cont_splash gap proper. - videocc/gpucc were almost certainly innocent bystanders blacklisted alongside dispcc historically; nothing here implicates them. ### Method note The first attempt at this bisect produced six clean boots that meant **nothing**: a stale `bootargs` left in U-Boot's saved env from an unrelated experiment was being merged with the boot image's cmdline, so the kernel saw *two* `initcall_blacklist=` entries and dispcc stayed blacklisted despite the image saying otherwise. Caught only because `dispcc=unbound` contradicted what the test claimed to be testing. Any arm of this bisect should verify the thing it claims to have changed actually changed — `/sys/bus/platform/devices/af00000.clock-controller/driver` for dispcc.
Author
Owner

Split out into two issues

The bisect above found two independent failures sharing one root cause (ABL handing over a live scanout). They have different fixes, different scope and different upstream stories, so they now have their own issues:

  • #19 — mainline msm has no continuous-splash handoff, so &mdss hangs the boot. The substantive half: the ~50% boot hang. Mainline has no detection/adoption/skip at all, where downstream has all four. Larger, structural, gates Display and GPU.
  • #20 — dispcc reconfigures the display PLLs at probe, corrupting a bootloader splash. The panel-freeze half, without any DRM involvement. Small, generic to every SoC dispcc-sm8250.c covers, and the more plausible upstream submission of the two.

This issue stays as the record of how the flaky boot was tracked down and bisected — the single-variable test, the dsi TIMEOUT_STATUS corroboration, the hang-not-crash finding from Samsung's reset diagnostics, and the invalid first bisect run and how it was caught.

Practical takeaway for anyone picking this up: keep the display off for bring-up work. &mdss disabled plus initcall_blacklist=disp_cc_sm8250_driver_init,video_cc_sm8150_driver_init,gpu_cc_sm8150_driver_init,simplefb_driver_init gives a device that boots every time and keeps the gtsfb panel console legible end-to-end. Note the two are not the same requirement: dispcc only needs blacklisting for the console (#20), not for stability — &mdss is what costs you the boot (#19).

## Split out into two issues The bisect above found two independent failures sharing one root cause (ABL handing over a live scanout). They have different fixes, different scope and different upstream stories, so they now have their own issues: - **#19 — mainline msm has no continuous-splash handoff, so `&mdss` hangs the boot.** The substantive half: the ~50% boot hang. Mainline has no detection/adoption/skip at all, where downstream has all four. Larger, structural, gates Display and GPU. - **#20 — dispcc reconfigures the display PLLs at probe, corrupting a bootloader splash.** The panel-freeze half, *without* any DRM involvement. Small, generic to every SoC `dispcc-sm8250.c` covers, and the more plausible upstream submission of the two. This issue stays as the record of how the flaky boot was tracked down and bisected — the single-variable test, the `dsi TIMEOUT_STATUS` corroboration, the hang-not-crash finding from Samsung's reset diagnostics, and the invalid first bisect run and how it was caught. **Practical takeaway for anyone picking this up:** keep the display off for bring-up work. `&mdss` disabled plus `initcall_blacklist=disp_cc_sm8250_driver_init,video_cc_sm8150_driver_init,gpu_cc_sm8150_driver_init,simplefb_driver_init` gives a device that boots every time *and* keeps the `gtsfb` panel console legible end-to-end. Note the two are not the same requirement: dispcc only needs blacklisting for the console (#20), not for stability — `&mdss` is what costs you the boot (#19).
Sign in to join this conversation.
No labels
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
kit/linux-gts6l#17
No description provided.