Display: mainline msm has no continuous-splash handoff, so &mdss hangs the boot #19

Open
opened 2026-08-25 12:56:57 +00:00 by kit · 0 comments
Owner

ABL hands the kernel a live display: a 2560x1600 x8r8g8b8 stride-10240 dual-DSI scanout of cont_splash_mem at 0x9c400000, still running. Mainline's DRM/MSM stack has no concept of this and programs the hardware as if it were off. Enabling &mdss therefore hangs roughly half of all boots.

This is the substantive half of #17 (the other half, dispcc rewriting the display PLLs, corrupts the panel but does not hang the system).

Evidence

From #17's bisect, on an otherwise-identical image:

configuration panel boot
&mdss off, dispcc/videocc/gpucc blacklisted readable 5+ clean
dispcc/videocc/gpucc bound, &mdss off freezes 6/6 OK
&mdss on freezes 2 hangs in 4

It is a hang, not a crash: afterwards TWRP reports reset_reason=NPON with reset_klog, reset_summary, auto_comment and reset_tzlog all empty. Samsung's layer records resets; a hang that gets power-cycled out of leaves nothing behind. The panel console is the only window into it.

What mainline is missing

cont_splash appears in zero files under drivers/gpu/drm/msm/ in 6.17. No detection, no adoption, no skip.

Downstream (drivers/gpu/drm/msm/dsi-staging/dsi_display.c, dsi_display_splash_res_init()) does all four:

  1. Detects a live scanout by reading a controller register —
    dsi_display_get_cont_splash_status()hw->ops.get_cont_splash_status(hw), per-ctrl.
  2. Votes on resources that are already on — GDSC, then dsi_display_clk_ctrl(..., DSI_ALL_CLKS, DSI_CLK_ON) and dsi_pwr_enable_regulator(). It takes references; it does not program.
  3. Syncs driver state to hardware statedsi_config_host_engine_state_for_cont_splash(), never the reverse.
  4. Inherits brightnessdsi_panel_bl_handoff().

And the panel ON sequence is explicitly skipped (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 instead reprograms the DSI host and PHY and then resets the panel underneath the running scanout.

Worth being clear that our panel driver is not at fault: ana38401_prepare() does a correct cold init (reset asserted 70 ms, released, wait for tcon_rdy). A correct cold init is simply the wrong operation to perform on hardware that is already running, and nothing in mainline tells it otherwise.

Routes

A. Quiesce before probe (smaller). Shut the DSI/DPU down cleanly before mainline touches them, so the existing cold-init path runs from a known-off state — which is the case mainline actually supports. Costs the bootloader splash and the gtsfb earlycon from that point on, but #6 already established that a brief black frame is unavoidable here, so little is lost. Open question: where the shutdown lives, since U-Boot has no DSI driver (it only writes into the framebuffer ABL set up), so it likely has to be early Linux.

B. Implement adoption (larger, upstreamable). Port the cont_splash concept — detect, vote, sync state, skip panel init. This is what downstream does and what a proper fix looks like. Considerably more work, touches dpu/dsi/panel, and arguably belongs upstream rather than in our tree.

Route A is the pragmatic unblock for a usable device; route B is the real fix.

Why it matters

Display and GPU are both gated on this, and it is the reason the device currently runs with the display disabled. It is also why the flaky boot taxed the project for weeks before being identified (#17).

Related: #17 (bisect and dispcc), #6 (splash continuity — already concluded that true downstream-style continuous splash is impossible without this), #10 and #12 (same panel driver).

ABL hands the kernel a **live** display: a 2560x1600 x8r8g8b8 stride-10240 dual-DSI scanout of `cont_splash_mem` at `0x9c400000`, still running. Mainline's DRM/MSM stack has no concept of this and programs the hardware as if it were off. Enabling `&mdss` therefore hangs roughly half of all boots. This is the substantive half of #17 (the other half, dispcc rewriting the display PLLs, corrupts the panel but does not hang the system). ## Evidence From #17's bisect, on an otherwise-identical image: | configuration | panel | boot | |---|---|---| | `&mdss` off, dispcc/videocc/gpucc blacklisted | readable | 5+ clean | | dispcc/videocc/gpucc **bound**, `&mdss` off | freezes | 6/6 OK | | **`&mdss` on** | freezes | **2 hangs in 4** | It is a hang, not a crash: afterwards TWRP reports `reset_reason=NPON` with `reset_klog`, `reset_summary`, `auto_comment` and `reset_tzlog` all empty. Samsung's layer records resets; a hang that gets power-cycled out of leaves nothing behind. The panel console is the only window into it. ## What mainline is missing `cont_splash` appears in **zero files** under `drivers/gpu/drm/msm/` in 6.17. No detection, no adoption, no skip. Downstream (`drivers/gpu/drm/msm/dsi-staging/dsi_display.c`, `dsi_display_splash_res_init()`) does all four: 1. **Detects** a live scanout by reading a controller register — `dsi_display_get_cont_splash_status()` → `hw->ops.get_cont_splash_status(hw)`, per-ctrl. 2. **Votes** on resources that are already on — GDSC, then `dsi_display_clk_ctrl(..., DSI_ALL_CLKS, DSI_CLK_ON)` and `dsi_pwr_enable_regulator()`. It takes references; it does not program. 3. **Syncs driver state to hardware state** — `dsi_config_host_engine_state_for_cont_splash()`, never the reverse. 4. **Inherits brightness** — `dsi_panel_bl_handoff()`. And the panel ON sequence is explicitly skipped (`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 instead reprograms the DSI host and PHY and then resets the panel underneath the running scanout. Worth being clear that **our panel driver is not at fault**: `ana38401_prepare()` does a correct cold init (reset asserted 70 ms, released, wait for `tcon_rdy`). A correct cold init is simply the wrong operation to perform on hardware that is already running, and nothing in mainline tells it otherwise. ## Routes **A. Quiesce before probe (smaller).** Shut the DSI/DPU down cleanly before mainline touches them, so the existing cold-init path runs from a known-off state — which is the case mainline actually supports. Costs the bootloader splash and the `gtsfb` earlycon from that point on, but #6 already established that a brief black frame is unavoidable here, so little is lost. Open question: where the shutdown lives, since U-Boot has no DSI driver (it only writes into the framebuffer ABL set up), so it likely has to be early Linux. **B. Implement adoption (larger, upstreamable).** Port the cont_splash concept — detect, vote, sync state, skip panel init. This is what downstream does and what a proper fix looks like. Considerably more work, touches dpu/dsi/panel, and arguably belongs upstream rather than in our tree. Route A is the pragmatic unblock for a usable device; route B is the real fix. ## Why it matters Display and GPU are both gated on this, and it is the reason the device currently runs with the display disabled. It is also why the flaky boot taxed the project for weeks before being identified (#17). Related: #17 (bisect and dispcc), #6 (splash continuity — already concluded that true downstream-style continuous splash is impossible without this), #10 and #12 (same panel driver).
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#19
No description provided.