dispcc reconfigures display PLLs at probe, corrupting a bootloader splash (upstreamable) #20

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

disp_cc_sm8250_probe() unconditionally rewrites both display PLLs, with no check for whether anything is currently running off them. On any device whose bootloader hands over a live scanout, this corrupts the display.

Not a gts6l quirk — the code path is generic and affects every SoC the driver covers (sm8150, sc8180x, sm8250, sm8350).

The code

drivers/clk/qcom/dispcc-sm8250.c (sm8150 uses this driver — it matches qcom,sm8150-dispcc):

if (of_device_is_compatible(pdev->dev.of_node, "qcom,sm8350-dispcc")) {
        clk_lucid_5lpe_pll_configure(&disp_cc_pll0, regmap, &disp_cc_pll0_config);
        clk_lucid_5lpe_pll_configure(&disp_cc_pll1, regmap, &disp_cc_pll1_config);
} else {
        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);

clk_*_pll_configure() writes the full PLL configuration — L value, alpha, config_ctl, user_ctl, test registers. There is no "is this PLL already enabled/locked?" guard.

Symptom on gts6l

ABL hands over a live dual-DSI 2560x1600 scanout of cont_splash_mem at 0x9c400000, clocked from disp_cc_pll0/pll1. dispcc's probe pulls that configuration out from under the running display, and the panel garbles into the "two panes, shrunken" state recorded in MAINLINE-NOTES, then freezes.

Confirmed by bisect (#17): with dispcc/videocc/gpucc bound and &mdss still disabled — so no DRM involvement whatsoever — the panel freezes. The system stays up: 6/6 clean boots. So this is display corruption, not instability; the boot hang is a separate problem (#19).

That also explains why the historical workaround needed both &mdss disabled and initcall_blacklist=disp_cc_sm8250_driver_init: disabling the DRM driver alone still leaves dispcc free to wreck the PLLs.

Why it matters to us specifically

The gtsfb framebuffer earlycon paints into that same live scanout and is our only pre-USB diagnostic channel — it is how the ldo17 regression that killed the whole pm8150 regulator provider was caught. dispcc probing destroys it. So today we must choose between a usable panel console and a bound dispcc, which is an unnecessary tradeoff.

Proposed fix

Skip the reconfigure when the PLL is already running. Roughly: read PLL_MODE / the enable and lock bits via the regmap before calling clk_*_pll_configure(), and leave a locked, enabled PLL alone — the same reasoning qcom_branch_set_clk_en() style helpers already use elsewhere, and what downstream does implicitly by taking votes on live clocks rather than programming them.

Needs care about what the rest of probe assumes: qcom_cc_really_probe() registers the PLLs as clocks afterwards, so the in-kernel state must still reflect the hardware's actual rate rather than the config that was skipped. That is the part worth getting right before proposing it upstream.

Upstream angle

This is the more submittable of the two display issues — small, generic, and reproducible in principle on any Qualcomm board with a bootloader splash. #19 (the missing continuous-splash handoff in DRM/MSM) is the larger structural gap and is likely a much longer conversation upstream.

Related: #17 (bisect that isolated this), #19 (the &mdss boot hang).

`disp_cc_sm8250_probe()` unconditionally rewrites both display PLLs, with no check for whether anything is currently running off them. On any device whose bootloader hands over a live scanout, this corrupts the display. Not a gts6l quirk — the code path is generic and affects every SoC the driver covers (sm8150, sc8180x, sm8250, sm8350). ## The code `drivers/clk/qcom/dispcc-sm8250.c` (sm8150 uses this driver — it matches `qcom,sm8150-dispcc`): ```c if (of_device_is_compatible(pdev->dev.of_node, "qcom,sm8350-dispcc")) { clk_lucid_5lpe_pll_configure(&disp_cc_pll0, regmap, &disp_cc_pll0_config); clk_lucid_5lpe_pll_configure(&disp_cc_pll1, regmap, &disp_cc_pll1_config); } else { 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); ``` `clk_*_pll_configure()` writes the full PLL configuration — L value, alpha, `config_ctl`, `user_ctl`, test registers. There is no "is this PLL already enabled/locked?" guard. ## Symptom on gts6l ABL hands over a live **dual-DSI** 2560x1600 scanout of `cont_splash_mem` at `0x9c400000`, clocked from `disp_cc_pll0`/`pll1`. dispcc's probe pulls that configuration out from under the running display, and the panel garbles into the "two panes, shrunken" state recorded in MAINLINE-NOTES, then freezes. Confirmed by bisect (#17): with dispcc/videocc/gpucc **bound** and `&mdss` still disabled — so no DRM involvement whatsoever — the panel freezes. **The system stays up: 6/6 clean boots.** So this is display corruption, not instability; the boot hang is a separate problem (#19). That also explains why the historical workaround needed *both* `&mdss` disabled **and** `initcall_blacklist=disp_cc_sm8250_driver_init`: disabling the DRM driver alone still leaves dispcc free to wreck the PLLs. ## Why it matters to us specifically The `gtsfb` framebuffer earlycon paints into that same live scanout and is our **only** pre-USB diagnostic channel — it is how the ldo17 regression that killed the whole pm8150 regulator provider was caught. dispcc probing destroys it. So today we must choose between a usable panel console and a bound dispcc, which is an unnecessary tradeoff. ## Proposed fix Skip the reconfigure when the PLL is already running. Roughly: read `PLL_MODE` / the enable and lock bits via the regmap before calling `clk_*_pll_configure()`, and leave a locked, enabled PLL alone — the same reasoning `qcom_branch_set_clk_en()` style helpers already use elsewhere, and what downstream does implicitly by taking votes on live clocks rather than programming them. Needs care about what the rest of probe assumes: `qcom_cc_really_probe()` registers the PLLs as clocks afterwards, so the in-kernel state must still reflect the *hardware's* actual rate rather than the config that was skipped. That is the part worth getting right before proposing it upstream. ## Upstream angle This is the more submittable of the two display issues — small, generic, and reproducible in principle on any Qualcomm board with a bootloader splash. #19 (the missing continuous-splash handoff in DRM/MSM) is the larger structural gap and is likely a much longer conversation upstream. Related: #17 (bisect that isolated this), #19 (the `&mdss` boot hang).
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#20
No description provided.