* [RFC PATCH] clk: qcom: dispcc-sm8750: reset the MDSS blocks at probe when the bootloader left them running @ 2026-10-22 14:08 Qianhui Xu 2026-10-22 14:26 ` sashiko-bot 2026-10-22 17:22 ` Taniya Das 0 siblings, 2 replies; 5+ messages in thread From: Qianhui Xu @ 2026-10-22 14:08 UTC (permalink / raw) To: linux-arm-msm Cc: linux-clk, dri-devel, Bjorn Andersson, Konrad Dybcio, Dmitry Baryshkov, Michael Turquette, Stephen Boyd On Lenovo Legion Y700 Gen4 (SM8750, "lenovo,elden") the bootloader hands over with the display block fully active: the dispcc PLLs are locked and MDSS core / core_int2 / RSCC are out of reset. The kernel's mdss_reset() and clk_*_pll_configure() then run on top of that live state and the command-mode panel fails to initialise: msm_dsi ae94000.dsi: command DMA timeout: status=0x2200200 msm_dsi ae94000.dsi: bonded command DMA failed: master=-110 peer=-110 panel-novatek-nt36536: Failed to initialize panel: -5 The result is a cold boot with backlight only and no /dev/dri/card0. Asseting the three dispcc block resets and releasing them before the PLLs are programmed makes the block start from a known-zero state, after which the same panel initialises reliably. Measured on the same device, downstream 7.2 payload, alternating real power-on cold boots (fastboot boot of two images that differ only in this hunk and the DSI PHY change mentioned below): without the reset: 5 of 9 cold boots failed (command DMA timeout) with the reset: 15 of 15 cold boots OK (two variants, see below) As an RFC I have gated it to lenovo,elden because I cannot tell whether other boards that hand over with a live display would benefit or would be broken by resetting the block. Two questions: 1. Is a per-board workaround in dispcc probe the right place, or should this be expressed as a DT property (e.g. qcom,reset-mdss-at-probe) or be handled unconditionally in the dispcc driver / in mdss? 2. LinuxLoader solves the same problem on the bootloader side under the name "DisableDisplayHW". Would you rather see the reset done by mdss_reset()/DPU before the PLLs are configured, so that it also helps other bootloaders that leave the block running? Separately, and relevant to Dmitry's "drm/msm/dsi/phy: power up the digital top before starting the 7nm PLL" series: on the same board the missing DIGTOP_PWRDN_B handling produces exactly the reported DSI PLL(0) lock failed, status=0x00000000 four times per boot (the PHY PLL is enabled by the clock framework from of_clk_set_defaults() before the PHY is touched). With DIGTOP_PWRDN_B set and cleared together with PLL_SHUTDOWNB that message disappears from every boot I measured (10 out of 10), but it does not change the command DMA behaviour above: an image with only that change still failed 3 of 4 cold boots with the PLL reported locked. So the two are independent, and the DIGTOP change looks correct on its own. Signed-off-by: Qianhui Xu <xiaqinghuan@mail.ustc.edu.cn> --- drivers/clk/qcom/dispcc-sm8750.c | 35 ++++++++++++++++++++++++++ 1 file changed, 35 insertions(+) diff --git a/drivers/clk/qcom/dispcc-sm8750.c b/drivers/clk/qcom/dispcc-sm8750.c index e1d9534..c2a1705 100644 --- a/drivers/clk/qcom/dispcc-sm8750.c +++ b/drivers/clk/qcom/dispcc-sm8750.c @@ -5,9 +5,11 @@ */ #include <linux/clk-provider.h> +#include <linux/delay.h> #include <linux/err.h> #include <linux/kernel.h> #include <linux/module.h> +#include <linux/of.h> #include <linux/platform_device.h> #include <linux/regmap.h> #include <linux/pm_runtime.h> @@ -1919,6 +1921,39 @@ static int disp_cc_sm8750_probe(struct platform_device *pdev) goto err_put_rpm; } + /* + * Some bootloaders hand over with the display block still fully + * active: dispcc PLLs locked and MDSS core / core_int2 / RSCC out of + * reset. Probing on top of that live state makes the command-mode + * panel fail to initialise (command DMA timeout, panel init -EIO). + * + * Assert the three block resets and release them before the PLLs are + * configured, so the block starts from a known-zero state. + * + * Limited to Lenovo Elden for now: it is the only board where this + * handover behaviour was observed and the fix verified. + */ + if (of_machine_is_compatible("lenovo,elden")) { + static const u16 elden_bcrs[] = { + DISP_CC_MDSS_CORE_BCR, + DISP_CC_MDSS_CORE_INT2_BCR, + DISP_CC_MDSS_RSCC_BCR, + }; + unsigned int reg; + int i; + + for (i = 0; i < ARRAY_SIZE(elden_bcrs); i++) { + reg = disp_cc_sm8750_resets[elden_bcrs[i]].reg; + regmap_write(regmap, reg, 0x1); + } + /* Hold for one full ~30 Hz frame before releasing. */ + msleep(50); + for (i = ARRAY_SIZE(elden_bcrs) - 1; i >= 0; i--) { + reg = disp_cc_sm8750_resets[elden_bcrs[i]].reg; + regmap_write(regmap, reg, 0x0); + } + } + clk_taycan_elu_pll_configure(&disp_cc_pll0, regmap, &disp_cc_pll0_config); clk_taycan_elu_pll_configure(&disp_cc_pll1, regmap, &disp_cc_pll1_config); clk_pongo_elu_pll_configure(&disp_cc_pll2, regmap, &disp_cc_pll2_config); ^ permalink raw reply related [flat|nested] 5+ messages in thread
* Re: [RFC PATCH] clk: qcom: dispcc-sm8750: reset the MDSS blocks at probe when the bootloader left them running 2026-10-22 14:08 [RFC PATCH] clk: qcom: dispcc-sm8750: reset the MDSS blocks at probe when the bootloader left them running Qianhui Xu @ 2026-10-22 14:26 ` sashiko-bot 2026-10-22 17:22 ` Taniya Das 1 sibling, 0 replies; 5+ messages in thread From: sashiko-bot @ 2026-10-22 14:26 UTC (permalink / raw) To: Qianhui Xu; +Cc: linux-clk, dri-devel Thank you for your contribution! Sashiko AI review found 4 potential issue(s) to consider: - [High] clk: qcom: dispcc-sm8750: unconditional MDSS reset in disp_cc_sm8750_probe() - [Medium] clk: qcom: BCR resets in disp_cc_sm8750_probe() do not reset locked PLLs - [Medium] clk: qcom: dispcc-sm8750: undocumented compatible in disp_cc_sm8750_probe() - [Medium] clk: qcom: dispcc-sm8750: raw BCR regmap_write() without mask or readback -- commit 996de5a901e9074e1f51bf1b7638e333551726e6 Author: Qianhui Xu <xiaqinghuan@mail.ustc.edu.cn> clk: qcom: dispcc-sm8750: reset the MDSS blocks at probe when the bootloader left them running This commit adds a board-specific reset sequence in disp_cc_sm8750_probe() for "lenovo,elden" that asserts and deasserts three display block resets with a 50 ms delay before configuring the display PLLs. > diff --git a/drivers/clk/qcom/dispcc-sm8750.c b/drivers/clk/qcom/dispcc-sm8750.c > index 3205ce5c1ad9e..f38ba86b4fd54 100644 > --- a/drivers/clk/qcom/dispcc-sm8750.c > +++ b/drivers/clk/qcom/dispcc-sm8750.c [ ... ] > @@ -1932,6 +1934,39 @@ static int disp_cc_sm8750_probe(struct platform_device *pdev) > goto err_put_rpm; > } > > + /* > + * Some bootloaders hand over with the display block still fully > + * active: dispcc PLLs locked and MDSS core / core_int2 / RSCC out of > + * reset. Probing on top of that live state makes the command-mode > + * panel fail to initialise (command DMA timeout, panel init -EIO). > + * > + * Assert the three block resets and release them before the PLLs are > + * configured, so the block starts from a known-zero state. > + * > + * Limited to Lenovo Elden for now: it is the only board where this > + * handover behaviour was observed and the fix verified. > + */ > + if (of_machine_is_compatible("lenovo,elden")) { [Severity: Medium] Is it valid to match against "lenovo,elden" in disp_cc_sm8750_probe() in drivers/clk/qcom/dispcc-sm8750.c when that compatible string is not documented in the device tree bindings? In Documentation/devicetree/bindings/arm/qcom.yaml, the documented board compatibles for qcom,sm8750 are: - items: - enum: - qcom,sm8750-mtp - qcom,sm8750-qrd - const: qcom,sm8750 Since active bootloader display handover can occur on other qcom,sm8750 boards as well, should this handover state be handled in the display driver or described via documented bindings rather than hardcoding an undocumented board compatible in the SoC clock driver? > + static const u16 elden_bcrs[] = { > + DISP_CC_MDSS_CORE_BCR, > + DISP_CC_MDSS_CORE_INT2_BCR, > + DISP_CC_MDSS_RSCC_BCR, > + }; > + unsigned int reg; > + int i; > + > + for (i = 0; i < ARRAY_SIZE(elden_bcrs); i++) { > + reg = disp_cc_sm8750_resets[elden_bcrs[i]].reg; > + regmap_write(regmap, reg, 0x1); > + } > + /* Hold for one full ~30 Hz frame before releasing. */ > + msleep(50); > + for (i = ARRAY_SIZE(elden_bcrs) - 1; i >= 0; i--) { > + reg = disp_cc_sm8750_resets[elden_bcrs[i]].reg; > + regmap_write(regmap, reg, 0x0); > + } [Severity: Medium] Should disp_cc_sm8750_probe() in drivers/clk/qcom/dispcc-sm8750.c use raw regmap_write() calls on the full 32-bit reset registers without a bitmask or readback? In drivers/clk/qcom/reset.c, qcom_reset_set_assert() updates only the target reset bit and reads back the register to flush posted writes across the interconnect: rst = to_qcom_reset_controller(rcdev); map = &rst->reset_map[id]; mask = map->bitmask ? map->bitmask : BIT(map->bit); regmap_update_bits(rst->regmap, map->reg, mask, assert ? mask : 0); /* Read back the register to ensure write completion, ignore the value */ regmap_read(rst->regmap, map->reg, &mask); Could overwriting the entire register with 0x1 and 0x0 via regmap_write() clobber other bits in those registers, and allow posted writes to remain buffered when the msleep(50) delay begins? > + } [Severity: High] Can unconditionally resetting DISP_CC_MDSS_CORE_BCR, DISP_CC_MDSS_CORE_INT2_BCR, and DISP_CC_MDSS_RSCC_BCR in disp_cc_sm8750_probe() in drivers/clk/qcom/dispcc-sm8750.c cause regressions during boot and driver probe? disp_cc_sm8750_probe() is the clock, reset, and power domain provider, whereas the consumer driver in drivers/gpu/drm/msm/msm_mdss.c already handles resetting the display block during msm_mdss_init() via msm_mdss_reset(): static int msm_mdss_reset(struct device *dev) { struct reset_control *reset; reset = reset_control_get_optional_exclusive(dev, NULL); ... reset_control_assert(reset); msleep(20); reset_control_deassert(reset); reset_control_put(reset); return 0; } Running this reset inside disp_cc_sm8750_probe() happens before the drm/msm driver probes and calls aperture_remove_all_conflicting_devices() in drivers/gpu/drm/msm/msm_kms.c. If a bootloader framebuffer (such as simpledrm or efifb) is active, or if drm/msm is disabled, modular, or deferred, asserting these resets in disp_cc_sm8750_probe() will tear down active display scanout and ongoing dma traffic. In addition, this reset loop executes before qcom_cc_really_probe() initializes mdss_gdsc and mdss_int2_gdsc via gdsc_init() in drivers/clk/qcom/gdsc.c and before qcom_cc_clk_regs_configure() enables disp_cc_sm8750_critical_cbcrs (DISP_CC_SLEEP_CLK, DISP_CC_XO_CLK, DISP_CC_MDSS_RSCC_AHB_CLK, and DISP_CC_MDSS_RSCC_VSYNC_CLK), without verifying that mdss_gdsc and mdss_int2_gdsc are powered on. Would it be safer to handle the reset requirements in msm_mdss_reset() in drivers/gpu/drm/msm/msm_mdss.c and the device tree reset properties rather than in disp_cc_sm8750_probe()? > + > clk_taycan_elu_pll_configure(&disp_cc_pll0, regmap, &disp_cc_pll0_config); > clk_taycan_elu_pll_configure(&disp_cc_pll1, regmap, &disp_cc_pll1_config); > clk_pongo_elu_pll_configure(&disp_cc_pll2, regmap, &disp_cc_pll2_config); [Severity: Medium] Does asserting elden_bcrs[] in disp_cc_sm8750_probe() in drivers/clk/qcom/dispcc-sm8750.c actually allow clk_taycan_elu_pll_configure() and clk_pongo_elu_pll_configure() to reprogram locked PLLs as described in the comment and commit message? The comment states: Assert the three block resets and release them before the PLLs are configured, so the block starts from a known-zero state. However, DISP_CC_MDSS_CORE_BCR, DISP_CC_MDSS_CORE_INT2_BCR, and DISP_CC_MDSS_RSCC_BCR only reset the downstream display sub-blocks and do not reset or unlock disp_cc_pll0, disp_cc_pll1, or disp_cc_pll2. When the bootloader leaves those PLLs locked, clk_taycan_elu_pll_configure() (which maps to clk_lucid_evo_pll_configure() in drivers/clk/qcom/clk-alpha-pll.c) still returns early without programming the PLL: if (trion_pll_is_enabled(pll, regmap)) { pr_debug("Lucid Evo PLL is already enabled, skipping configuration\n"); return; } And clk_pongo_elu_pll_configure() in drivers/clk/qcom/clk-alpha-pll.c does the same: if (trion_pll_is_enabled(pll, regmap)) return; Also, disp_cc_sm8750_probe() does not check whether the display blocks or PLLs were left running by the bootloader before asserting the resets and sleeping for 50 ms. Should the code and comment be updated to reflect that the block resets do not reset the PLLs and check whether the hardware is actually active? -- Sashiko AI review · https://sashiko.dev/#/patchset/20261022140811.469417-1-xiaqinghuan@mail.ustc.edu.cn?part=1 ^ permalink raw reply [flat|nested] 5+ messages in thread
* Re: [RFC PATCH] clk: qcom: dispcc-sm8750: reset the MDSS blocks at probe when the bootloader left them running 2026-10-22 14:08 [RFC PATCH] clk: qcom: dispcc-sm8750: reset the MDSS blocks at probe when the bootloader left them running Qianhui Xu 2026-10-22 14:26 ` sashiko-bot @ 2026-10-22 17:22 ` Taniya Das 2026-10-23 7:52 ` Qianhui Xu 2026-10-28 11:57 ` Qianhui Xu 1 sibling, 2 replies; 5+ messages in thread From: Taniya Das @ 2026-10-22 17:22 UTC (permalink / raw) To: Qianhui Xu, linux-arm-msm Cc: linux-clk, dri-devel, Bjorn Andersson, Konrad Dybcio, Dmitry Baryshkov, Michael Turquette, Stephen Boyd On 10/22/2026 7:38 PM, Qianhui Xu wrote: > > + /* > + * Some bootloaders hand over with the display block still fully > + * active: dispcc PLLs locked and MDSS core / core_int2 / RSCC out of > + * reset. Probing on top of that live state makes the command-mode > + * panel fail to initialise (command DMA timeout, panel init -EIO). > + * > + * Assert the three block resets and release them before the PLLs are > + * configured, so the block starts from a known-zero state. > + * > + * Limited to Lenovo Elden for now: it is the only board where this > + * handover behaviour was observed and the fix verified. > + */ > + if (of_machine_is_compatible("lenovo,elden")) { > + static const u16 elden_bcrs[] = { > + DISP_CC_MDSS_CORE_BCR, > + DISP_CC_MDSS_CORE_INT2_BCR, > + DISP_CC_MDSS_RSCC_BCR, > + }; > + unsigned int reg; > + int i; > + > + for (i = 0; i < ARRAY_SIZE(elden_bcrs); i++) { > + reg = disp_cc_sm8750_resets[elden_bcrs[i]].reg; > + regmap_write(regmap, reg, 0x1); > + } > + /* Hold for one full ~30 Hz frame before releasing. */ > + msleep(50); > + for (i = ARRAY_SIZE(elden_bcrs) - 1; i >= 0; i--) { > + reg = disp_cc_sm8750_resets[elden_bcrs[i]].reg; > + regmap_write(regmap, reg, 0x0); > + } > + } > + These resets if required should be taken care or triggered from the Display SW driver. It is not on to the clock driver to drive these resets. If these are done the complete dispcc would be reset and when the PLLs gets reconfigured there should be a flicker observed on the display. -- Thanks, Taniya Das ^ permalink raw reply [flat|nested] 5+ messages in thread
* Re: [RFC PATCH] clk: qcom: dispcc-sm8750: reset the MDSS blocks at probe when the bootloader left them running 2026-10-22 17:22 ` Taniya Das @ 2026-10-23 7:52 ` Qianhui Xu 2026-10-28 11:57 ` Qianhui Xu 1 sibling, 0 replies; 5+ messages in thread From: Qianhui Xu @ 2026-10-23 7:52 UTC (permalink / raw) To: Taniya Das, linux-arm-msm Cc: linux-clk, dri-devel, Bjorn Andersson, Konrad Dybcio, Dmitry Baryshkov, Stephen Boyd Hi Taniya, Thanks for the direct answer. You are right on both points and I accept them: the dispcc probe is not the correct place to drive these resets, and resetting the whole block and then reconfiguring the PLLs will flicker if anything is already scanning out. Why it ended up there Looking at why I did not put it where you suggest: msm_mdss_reset() in drivers/gpu/drm/msm/msm_mdss.c only handles one reset, the unnamed one from the mdss node, which on sm8750.dtsi is DISP_CC_MDSS_CORE_BCR. It also runs from msm_mdss_init(), i.e. after the dispcc provider has probed, and the PLLs are configured during that dispcc probe (clk_taycan_elu_pll_configure()/clk_pongo_elu_pll_configure() sit a few lines below the hunk I added). So CORE_INT2 and RSCC have no writer at all in the current tree, and by the time the display side could touch them the PLLs have already been programmed. Asserting the three BCRs in dispcc probe was the earliest point I had access to. That is a description of the constraint, not a defence of the location. What I think the right shape is Move all three BCRs to the display side, into msm_mdss_reset(), and use reset_control_bulk() instead of raw register writes. Three questions before I write v2: 1. Is extending msm_mdss_reset() to CORE / CORE_INT2 / RSCC acceptable, or would you rather have them taken from somewhere else in the display stack? 2. Can we guarantee that the reset happens before the PLLs are configured at all? Right now the ordering I can observe is dispcc provider probe (PLL configure) -> mdss probe (msm_mdss_reset). If that ordering is inherent, then a reset in msm_mdss_reset() is still "after the PLLs were configured once", which is exactly the state you are worried about. 3. If (2) cannot be guaranteed, would an explicit reset in the mdss path before the first clk_set_rate() on the dispcc PLLs be acceptable, so the block is reset while it is still quiescent and the PLLs are then programmed only once? Measured data On the same unit, 23 real power-on cold boots (POR, fastboot boot of images that differ only in these hunks), alternating: without the reset: 5 of 9 boots failed with command DMA timeout with the reset: 15 of 15 boots OK (two variants pooled) Fisher exact, two-sided: p = 0.003 Split by hunk: only-0154 5/5 OK; only-0155 3/4 still failed. So the display-block reset, not the DSI PHY change, is what moves the failure rate. I am not claiming this identifies the root cause, only that it is reproducible and pinned to that one hunk. A caveat I want to state myself The A/B tree deliberately does not describe chosen/simple-framebuffer, so the "simpledrm is being torn down" case was not exercised by these measurements at all. If simpledrm or efifb is running on a board, the reset I added would indeed pull the framebuffer out from under it and produce exactly the flicker you describe. Your objection and the review comment below point at the same thing, and the display-side placement plus a liveness check is the only version of this I would defend. The review comments Also folding in the three Medium points from the automated review, so the thread stays in one place: - The lenovo,elden board compatible is not in mainline arm/qcom.yaml yet. It is added by the board DTS series and goes in with it; I will not send a separate binding patch for it. - The raw regmap_write() of 0x1/0x0 over the whole BCR register is a real defect: it does not mask and does not read back, unlike qcom_reset_set_assert() which uses regmap_update_bits() plus a readback to flush the posted write. v2 will use reset_control_* for this reason as well. - The comment claiming the block starts from a "known-zero state" reads as if the reset also resets the PLLs; it does not, and clk_*_pll_configure() returns early when trion_pll_is_enabled() is true. I will drop that wording from both the comment and the commit message. Next step I will send v2 with the hunk moved to the display side, reset_control_* instead of raw writes, and a control run where simple-framebuffer is present in DT, so the flicker case is measured instead of argued about. If the answer to question 2 is "cannot be guaranteed", say so and I will drop the series rather than work around the ordering. Thanks, Qianhui Xu ^ permalink raw reply [flat|nested] 5+ messages in thread
* Re: [RFC PATCH] clk: qcom: dispcc-sm8750: reset the MDSS blocks at probe when the bootloader left them running 2026-10-22 17:22 ` Taniya Das 2026-10-23 7:52 ` Qianhui Xu @ 2026-10-28 11:57 ` Qianhui Xu 1 sibling, 0 replies; 5+ messages in thread From: Qianhui Xu @ 2026-10-28 11:57 UTC (permalink / raw) To: Taniya Das, linux-arm-msm Cc: linux-clk, dri-devel, Bjorn Andersson, Konrad Dybcio, Dmitry Baryshkov, Michael Turquette, Stephen Boyd Hi Taniya, Thanks, that is a clear answer and I will drop the clock-side shape. Taking your two points at face value: - the resets belong to the display side, not to dispcc probe; - resetting the whole block after the PLLs are configured will flicker. So the RFC as posted is withdrawn. I will not resend it in that form. Where I think the replacement lands, and where I would like your opinion before spending time on it: The reset already exists on the display side. msm_mdss_reset() in drivers/gpu/drm/msm/msm_mdss.c asserts the mdss reset, sleeps 20 ms and deasserts it, and sm8750.dtsi already points that reset at DISP_CC_MDSS_CORE_BCR. The "hold it for one frame" timing is not new either, that function carries the same comment upstream today. So the mechanism is there; my patch only moved it earlier, into dispcc probe. The reason I moved it is ordering. On this SoC mdss consumes dispcc clocks and MDSS_GDSC, so dispcc probes first and the dispcc PLLs are programmed inside disp_cc_sm8750_probe(). msm_mdss_reset() then runs after that, so resetting there would take down PLLs that were just configured - which is the flicker you describe, and quite possibly the same failure I was trying to avoid in the first place. So my open question is narrower than the original RFC: given that ordering, where should a board that is handed over with a live display block put the reset? Three shapes I can see: 1. keep only the single CORE_BCR reset that DT already describes, and let the clock framework reprogram the PLLs after it; 2. drop the block reset entirely and do a per-encoder reset in the DPU/DSI enable path, so the PLL section is never touched; 3. leave it to the bootloader - the vendor loader has a DisableDisplayHW knob for exactly this - and carry nothing in the kernel. I am not asking you to design it. I would just like to know which of those three you would not reject outright, so I do not spend a cycle on the wrong one. If the answer is "none of them, this is a bootloader problem", that is a useful answer too and I will write it up that way. No date attached - this is a background item for me, and I would rather come back with measurements than with a schedule. Thanks, Qianhui Xu ^ permalink raw reply [flat|nested] 5+ messages in thread
end of thread, other threads:[~2026-10-28 11:57 UTC | newest] Thread overview: 5+ messages (download: mbox.gz follow: Atom feed -- links below jump to the message on this page -- 2026-10-22 14:08 [RFC PATCH] clk: qcom: dispcc-sm8750: reset the MDSS blocks at probe when the bootloader left them running Qianhui Xu 2026-10-22 14:26 ` sashiko-bot 2026-10-22 17:22 ` Taniya Das 2026-10-23 7:52 ` Qianhui Xu 2026-10-28 11:57 ` Qianhui Xu
This is a public inbox, see mirroring instructions for how to clone and mirror all data and code used for this inbox