* [PATCH v2 0/2] Pixel 3 display fixes
@ 2026-08-10 9:55 ` David Heidelberg
0 siblings, 0 replies; 8+ messages in thread
From: David Heidelberg via B4 Relay @ 2026-08-10 9:55 UTC (permalink / raw)
To: Sumit Semwal, Casey Connolly, Neil Armstrong, Jessica Zhang,
Maarten Lankhorst, Maxime Ripard, Thomas Zimmermann, David Airlie,
Simona Vetter, Dmitry Baryshkov, Marijn Suijten, Vinod Koul
Cc: dri-devel, linux-kernel, phone-devel, David Heidelberg
Fix panel not recovering after unprepare and backlight intensity.
I extensively reproduced the vendor bootloader sequence, but after the
boot isn't possible to do the full initialization of the display (at
least on Pixel 3, and panel can't be found anywhere else).
The downstream, due to having attached touchscreen reusing same
supplies, never turns the panel off. Let's do the same.
Signed-off-by: David Heidelberg <david@ixit.cz>
---
Changes in v2:
- Unintended change 255 -> 256 for default brigtness. Drop it.
- Added R-bs.
- Link to v1: https://patch.msgid.link/20260809-fix-blueline-panel-v1-0-e7f3a6beb1fa@ixit.cz
---
David Heidelberg (2):
drm/panel: lg-sw43408: do not assert reset across unprepare
drm/panel: lg-sw43408: use the full DCS brightness range
drivers/gpu/drm/panel/panel-lg-sw43408.c | 12 +++++++++---
1 file changed, 9 insertions(+), 3 deletions(-)
---
base-commit: 95d6a9ccef99117115e41e9adb271243bd5e985b
change-id: 20260809-fix-blueline-panel-af2b7c967f2d
Best regards,
--
David Heidelberg <david@ixit.cz>
^ permalink raw reply [flat|nested] 8+ messages in thread
* [PATCH v2 0/2] Pixel 3 display fixes
@ 2026-08-10 9:55 ` David Heidelberg
0 siblings, 0 replies; 8+ messages in thread
From: David Heidelberg @ 2026-08-10 9:55 UTC (permalink / raw)
To: Sumit Semwal, Casey Connolly, Neil Armstrong, Jessica Zhang,
Maarten Lankhorst, Maxime Ripard, Thomas Zimmermann, David Airlie,
Simona Vetter, Dmitry Baryshkov, Marijn Suijten, Vinod Koul
Cc: dri-devel, linux-kernel, phone-devel, David Heidelberg
Fix panel not recovering after unprepare and backlight intensity.
I extensively reproduced the vendor bootloader sequence, but after the
boot isn't possible to do the full initialization of the display (at
least on Pixel 3, and panel can't be found anywhere else).
The downstream, due to having attached touchscreen reusing same
supplies, never turns the panel off. Let's do the same.
Signed-off-by: David Heidelberg <david@ixit.cz>
---
Changes in v2:
- Unintended change 255 -> 256 for default brigtness. Drop it.
- Added R-bs.
- Link to v1: https://patch.msgid.link/20260809-fix-blueline-panel-v1-0-e7f3a6beb1fa@ixit.cz
---
David Heidelberg (2):
drm/panel: lg-sw43408: do not assert reset across unprepare
drm/panel: lg-sw43408: use the full DCS brightness range
drivers/gpu/drm/panel/panel-lg-sw43408.c | 12 +++++++++---
1 file changed, 9 insertions(+), 3 deletions(-)
---
base-commit: 95d6a9ccef99117115e41e9adb271243bd5e985b
change-id: 20260809-fix-blueline-panel-af2b7c967f2d
Best regards,
--
David Heidelberg <david@ixit.cz>
^ permalink raw reply [flat|nested] 8+ messages in thread
* [PATCH v2 1/2] drm/panel: lg-sw43408: do not assert reset across unprepare
2026-08-10 9:55 ` David Heidelberg
@ 2026-08-10 9:55 ` David Heidelberg
-1 siblings, 0 replies; 8+ messages in thread
From: David Heidelberg via B4 Relay @ 2026-08-10 9:55 UTC (permalink / raw)
To: Sumit Semwal, Casey Connolly, Neil Armstrong, Jessica Zhang,
Maarten Lankhorst, Maxime Ripard, Thomas Zimmermann, David Airlie,
Simona Vetter, Dmitry Baryshkov, Marijn Suijten, Vinod Koul
Cc: dri-devel, linux-kernel, phone-devel, David Heidelberg
From: David Heidelberg <david@ixit.cz>
Asserting the reset GPIO in unprepare() and leaving it asserted puts
the DDIC into a state it never recovers from: after the following
prepare() the panel answers all DCS commands, reports display-on with
clean self-diagnostics, and its configuration registers read back
identical to a working panel, but it never lights up again.
On the Pixel 3, vddi is shared with the touchscreen controller and
remains powered while the panel is off, so with this driver the DDIC
sits in reset with its logic rail up for the whole blank period - a
state the vendor stack never creates: the vendor firmware only toggles
reset as part of a full power-on sequence, and the vendor OS never
power-cycles the panel at all (LP mode is used instead).
Leave reset alone in unprepare(); prepare() performs the regular reset
sequence anyway.
Without this, the Pixel 3 display never comes back after the first
blank/unblank cycle.
Since there isn't any other panel or device using this DDIC, this
approach seems resoanble to address the issue.
Fixes: 069a6c0e94f9 ("drm: panel: Add LG sw43408 panel driver")
Reviewed-by: Neil Armstrong <neil.armstrong@linaro.org>
Signed-off-by: David Heidelberg <david@ixit.cz>
---
drivers/gpu/drm/panel/panel-lg-sw43408.c | 10 ++++++++--
1 file changed, 8 insertions(+), 2 deletions(-)
diff --git a/drivers/gpu/drm/panel/panel-lg-sw43408.c b/drivers/gpu/drm/panel/panel-lg-sw43408.c
index 293826c5006b9..0bf8e08f10b9c 100644
--- a/drivers/gpu/drm/panel/panel-lg-sw43408.c
+++ b/drivers/gpu/drm/panel/panel-lg-sw43408.c
@@ -50,18 +50,24 @@ static int sw43408_unprepare(struct drm_panel *panel)
int ret;
mipi_dsi_dcs_set_display_off_multi(&ctx);
mipi_dsi_dcs_enter_sleep_mode_multi(&ctx);
mipi_dsi_msleep(&ctx, 100);
- gpiod_set_value(sw43408->reset_gpio, 1);
-
+ /*
+ * Keep reset deasserted: vddi may stay powered (it is shared with
+ * the touchscreen on Pixel 3) and holding the DDIC in reset while
+ * its logic rail is up puts it into a state that no init sequence
+ * recovers from - the panel keeps answering DCS commands and
+ * reports display-on, but never lights up again. The vendor stack
+ * only ever toggles reset as part of a powered-up init sequence.
+ */
ret = regulator_bulk_disable(ARRAY_SIZE(sw43408_supplies), sw43408->supplies);
return ret ? : ctx.accum_err;
}
static int sw43408_program(struct drm_panel *panel)
{
struct sw43408_panel *sw43408 = to_panel_info(panel);
--
2.55.0
^ permalink raw reply related [flat|nested] 8+ messages in thread
* [PATCH v2 1/2] drm/panel: lg-sw43408: do not assert reset across unprepare
@ 2026-08-10 9:55 ` David Heidelberg
0 siblings, 0 replies; 8+ messages in thread
From: David Heidelberg @ 2026-08-10 9:55 UTC (permalink / raw)
To: Sumit Semwal, Casey Connolly, Neil Armstrong, Jessica Zhang,
Maarten Lankhorst, Maxime Ripard, Thomas Zimmermann, David Airlie,
Simona Vetter, Dmitry Baryshkov, Marijn Suijten, Vinod Koul
Cc: dri-devel, linux-kernel, phone-devel, David Heidelberg
Asserting the reset GPIO in unprepare() and leaving it asserted puts
the DDIC into a state it never recovers from: after the following
prepare() the panel answers all DCS commands, reports display-on with
clean self-diagnostics, and its configuration registers read back
identical to a working panel, but it never lights up again.
On the Pixel 3, vddi is shared with the touchscreen controller and
remains powered while the panel is off, so with this driver the DDIC
sits in reset with its logic rail up for the whole blank period - a
state the vendor stack never creates: the vendor firmware only toggles
reset as part of a full power-on sequence, and the vendor OS never
power-cycles the panel at all (LP mode is used instead).
Leave reset alone in unprepare(); prepare() performs the regular reset
sequence anyway.
Without this, the Pixel 3 display never comes back after the first
blank/unblank cycle.
Since there isn't any other panel or device using this DDIC, this
approach seems resoanble to address the issue.
Fixes: 069a6c0e94f9 ("drm: panel: Add LG sw43408 panel driver")
Reviewed-by: Neil Armstrong <neil.armstrong@linaro.org>
Signed-off-by: David Heidelberg <david@ixit.cz>
---
drivers/gpu/drm/panel/panel-lg-sw43408.c | 10 ++++++++--
1 file changed, 8 insertions(+), 2 deletions(-)
diff --git a/drivers/gpu/drm/panel/panel-lg-sw43408.c b/drivers/gpu/drm/panel/panel-lg-sw43408.c
index 293826c5006b9..0bf8e08f10b9c 100644
--- a/drivers/gpu/drm/panel/panel-lg-sw43408.c
+++ b/drivers/gpu/drm/panel/panel-lg-sw43408.c
@@ -50,18 +50,24 @@ static int sw43408_unprepare(struct drm_panel *panel)
int ret;
mipi_dsi_dcs_set_display_off_multi(&ctx);
mipi_dsi_dcs_enter_sleep_mode_multi(&ctx);
mipi_dsi_msleep(&ctx, 100);
- gpiod_set_value(sw43408->reset_gpio, 1);
-
+ /*
+ * Keep reset deasserted: vddi may stay powered (it is shared with
+ * the touchscreen on Pixel 3) and holding the DDIC in reset while
+ * its logic rail is up puts it into a state that no init sequence
+ * recovers from - the panel keeps answering DCS commands and
+ * reports display-on, but never lights up again. The vendor stack
+ * only ever toggles reset as part of a powered-up init sequence.
+ */
ret = regulator_bulk_disable(ARRAY_SIZE(sw43408_supplies), sw43408->supplies);
return ret ? : ctx.accum_err;
}
static int sw43408_program(struct drm_panel *panel)
{
struct sw43408_panel *sw43408 = to_panel_info(panel);
--
2.55.0
^ permalink raw reply related [flat|nested] 8+ messages in thread
* [PATCH v2 2/2] drm/panel: lg-sw43408: use the full DCS brightness range
2026-08-10 9:55 ` David Heidelberg
@ 2026-08-10 9:55 ` David Heidelberg
-1 siblings, 0 replies; 8+ messages in thread
From: David Heidelberg via B4 Relay @ 2026-08-10 9:55 UTC (permalink / raw)
To: Sumit Semwal, Casey Connolly, Neil Armstrong, Jessica Zhang,
Maarten Lankhorst, Maxime Ripard, Thomas Zimmermann, David Airlie,
Simona Vetter, Dmitry Baryshkov, Marijn Suijten, Vinod Koul
Cc: dri-devel, linux-kernel, phone-devel, David Heidelberg
From: David Heidelberg <david@ixit.cz>
The vendor firmware panel configuration (XBL DisplayDxe panel XML)
declares DCSMaxBrightness 0x332 with a two-byte brightness command,
and the driver already sends two bytes via
mipi_dsi_dcs_set_display_brightness_large().
Capping max_brightness at 255 therefore limits the panel to ~31% of
its real brightness range. Use the firmware maximum.
Fixes: 069a6c0e94f9 ("drm: panel: Add LG sw43408 panel driver")
Signed-off-by: David Heidelberg <david@ixit.cz>
---
drivers/gpu/drm/panel/panel-lg-sw43408.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/drivers/gpu/drm/panel/panel-lg-sw43408.c b/drivers/gpu/drm/panel/panel-lg-sw43408.c
index 0bf8e08f10b9c..be132b65b0c13 100644
--- a/drivers/gpu/drm/panel/panel-lg-sw43408.c
+++ b/drivers/gpu/drm/panel/panel-lg-sw43408.c
@@ -203,17 +203,17 @@ static const struct backlight_ops sw43408_backlight_ops = {
};
static int sw43408_backlight_init(struct sw43408_panel *ctx)
{
struct device *dev = &ctx->link->dev;
const struct backlight_properties props = {
.type = BACKLIGHT_PLATFORM,
.brightness = 255,
- .max_brightness = 255,
+ .max_brightness = 818,
};
ctx->base.backlight = devm_backlight_device_register(dev, dev_name(dev), dev,
ctx->link,
&sw43408_backlight_ops,
&props);
if (IS_ERR(ctx->base.backlight))
--
2.55.0
^ permalink raw reply related [flat|nested] 8+ messages in thread
* [PATCH v2 2/2] drm/panel: lg-sw43408: use the full DCS brightness range
@ 2026-08-10 9:55 ` David Heidelberg
0 siblings, 0 replies; 8+ messages in thread
From: David Heidelberg @ 2026-08-10 9:55 UTC (permalink / raw)
To: Sumit Semwal, Casey Connolly, Neil Armstrong, Jessica Zhang,
Maarten Lankhorst, Maxime Ripard, Thomas Zimmermann, David Airlie,
Simona Vetter, Dmitry Baryshkov, Marijn Suijten, Vinod Koul
Cc: dri-devel, linux-kernel, phone-devel, David Heidelberg
The vendor firmware panel configuration (XBL DisplayDxe panel XML)
declares DCSMaxBrightness 0x332 with a two-byte brightness command,
and the driver already sends two bytes via
mipi_dsi_dcs_set_display_brightness_large().
Capping max_brightness at 255 therefore limits the panel to ~31% of
its real brightness range. Use the firmware maximum.
Fixes: 069a6c0e94f9 ("drm: panel: Add LG sw43408 panel driver")
Signed-off-by: David Heidelberg <david@ixit.cz>
---
drivers/gpu/drm/panel/panel-lg-sw43408.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/drivers/gpu/drm/panel/panel-lg-sw43408.c b/drivers/gpu/drm/panel/panel-lg-sw43408.c
index 0bf8e08f10b9c..be132b65b0c13 100644
--- a/drivers/gpu/drm/panel/panel-lg-sw43408.c
+++ b/drivers/gpu/drm/panel/panel-lg-sw43408.c
@@ -203,17 +203,17 @@ static const struct backlight_ops sw43408_backlight_ops = {
};
static int sw43408_backlight_init(struct sw43408_panel *ctx)
{
struct device *dev = &ctx->link->dev;
const struct backlight_properties props = {
.type = BACKLIGHT_PLATFORM,
.brightness = 255,
- .max_brightness = 255,
+ .max_brightness = 818,
};
ctx->base.backlight = devm_backlight_device_register(dev, dev_name(dev), dev,
ctx->link,
&sw43408_backlight_ops,
&props);
if (IS_ERR(ctx->base.backlight))
--
2.55.0
^ permalink raw reply related [flat|nested] 8+ messages in thread
* Re: [PATCH v2 2/2] drm/panel: lg-sw43408: use the full DCS brightness range
2026-08-10 9:55 ` David Heidelberg
(?)
@ 2026-08-10 9:59 ` Neil Armstrong
-1 siblings, 0 replies; 8+ messages in thread
From: Neil Armstrong @ 2026-08-10 9:59 UTC (permalink / raw)
To: david, Sumit Semwal, Casey Connolly, Jessica Zhang,
Maarten Lankhorst, Maxime Ripard, Thomas Zimmermann, David Airlie,
Simona Vetter, Dmitry Baryshkov, Marijn Suijten, Vinod Koul
Cc: dri-devel, linux-kernel, phone-devel
On 8/10/26 11:55, David Heidelberg via B4 Relay wrote:
> From: David Heidelberg <david@ixit.cz>
>
> The vendor firmware panel configuration (XBL DisplayDxe panel XML)
> declares DCSMaxBrightness 0x332 with a two-byte brightness command,
> and the driver already sends two bytes via
> mipi_dsi_dcs_set_display_brightness_large().
>
> Capping max_brightness at 255 therefore limits the panel to ~31% of
> its real brightness range. Use the firmware maximum.
>
> Fixes: 069a6c0e94f9 ("drm: panel: Add LG sw43408 panel driver")
> Signed-off-by: David Heidelberg <david@ixit.cz>
> ---
> drivers/gpu/drm/panel/panel-lg-sw43408.c | 2 +-
> 1 file changed, 1 insertion(+), 1 deletion(-)
>
> diff --git a/drivers/gpu/drm/panel/panel-lg-sw43408.c b/drivers/gpu/drm/panel/panel-lg-sw43408.c
> index 0bf8e08f10b9c..be132b65b0c13 100644
> --- a/drivers/gpu/drm/panel/panel-lg-sw43408.c
> +++ b/drivers/gpu/drm/panel/panel-lg-sw43408.c
> @@ -203,17 +203,17 @@ static const struct backlight_ops sw43408_backlight_ops = {
> };
>
> static int sw43408_backlight_init(struct sw43408_panel *ctx)
> {
> struct device *dev = &ctx->link->dev;
> const struct backlight_properties props = {
> .type = BACKLIGHT_PLATFORM,
> .brightness = 255,
> - .max_brightness = 255,
> + .max_brightness = 818,
> };
>
> ctx->base.backlight = devm_backlight_device_register(dev, dev_name(dev), dev,
> ctx->link,
> &sw43408_backlight_ops,
> &props);
>
> if (IS_ERR(ctx->base.backlight))
>
Reviewed-by: Neil Armstrong <neil.armstrong@linaro.org>
Thanks,
Neil
^ permalink raw reply [flat|nested] 8+ messages in thread
* Re: [PATCH v2 1/2] drm/panel: lg-sw43408: do not assert reset across unprepare
2026-08-10 9:55 ` David Heidelberg
(?)
@ 2026-08-10 10:02 ` sashiko-bot
-1 siblings, 0 replies; 8+ messages in thread
From: sashiko-bot @ 2026-08-10 10:02 UTC (permalink / raw)
To: David Heidelberg; +Cc: dri-devel
Thank you for your contribution! Sashiko AI review found 2 potential issue(s) to consider:
Pre-existing issues:
- [High] Incomplete fix for the unrecoverable hardware state. The patch removes the reset assertion from `sw43408_unprepare()` to fix a hardware lockup, but the exact same reset assertion remains in the error path of `sw43408_prepare()`.
- [High] Missing `drm_panel_remove()` in the probe error path leaves a dangling panel in the global registry, leading to a Use-After-Free.
--
--- Patch [1]: [PATCH v2 1/2] drm/panel: lg-sw43408: do not assert reset across unprepare ---
commit c7e02c477c8a5888497460cbf8b8bcfc7759b23d
Author: David Heidelberg <david@ixit.cz>
drm/panel: lg-sw43408: do not assert reset across unprepare
This patch removes the reset assertion from the unprepare() function.
Asserting the reset GPIO while the logic rail remains powered puts the DDIC
into a state it cannot recover from.
> diff --git a/drivers/gpu/drm/panel/panel-lg-sw43408.c b/drivers/gpu/drm/panel/panel-lg-sw43408.c
> index 293826c5006b9..0bf8e08f10b9c 100644
> --- a/drivers/gpu/drm/panel/panel-lg-sw43408.c
> +++ b/drivers/gpu/drm/panel/panel-lg-sw43408.c
> @@ -55,8 +55,14 @@ static int sw43408_unprepare(struct drm_panel *panel)
>
> mipi_dsi_msleep(&ctx, 100);
>
> - gpiod_set_value(sw43408->reset_gpio, 1);
> -
> + /*
> + * Keep reset deasserted: vddi may stay powered (it is shared with
> + * the touchscreen on Pixel 3) and holding the DDIC in reset while
> + * its logic rail is up puts it into a state that no init sequence
> + * recovers from - the panel keeps answering DCS commands and
> + * reports display-on, but never lights up again. The vendor stack
> + * only ever toggles reset as part of a powered-up init sequence.
> + */
> ret = regulator_bulk_disable(ARRAY_SIZE(sw43408_supplies), sw43408->supplies);
>
> return ret ? : ctx.accum_err;
[Severity: High]
This isn't a bug introduced by this patch, but the same reset assertion that
causes the unrecoverable hardware state still exists in the error path of
sw43408_prepare().
If sw43408_program() fails, the driver branches to poweroff and asserts
the reset GPIO while vddi might still be powered:
drivers/gpu/drm/panel/panel-lg-sw43408.c:sw43408_prepare() {
...
ret = sw43408_program(panel);
if (ret)
goto poweroff;
return 0;
poweroff:
gpiod_set_value(ctx->reset_gpio, 1);
regulator_bulk_disable(ARRAY_SIZE(sw43408_supplies), ctx->supplies);
return ret;
}
Could this leave the DDIC in the same unrecoverable state if a DCS command
fails during initialization?
[Severity: High]
This is a pre-existing issue, but there appears to be a potential
use-after-free in the probe function.
If mipi_dsi_attach() fails in sw43408_probe(), the driver returns an error
without calling drm_panel_remove():
drivers/gpu/drm/panel/panel-lg-sw43408.c:sw43408_probe() {
...
ret = sw43408_add(ctx);
if (ret < 0)
return ret;
...
return mipi_dsi_attach(dsi);
}
Since sw43408_add() calls drm_panel_add() rather than devm_drm_panel_add(),
doesn't this leave the panel globally registered?
If devres then frees the panel's regulators and GPIOs upon probe failure,
could a display controller attempting to use the registered panel encounter
a use-after-free?
--
Sashiko AI review · https://sashiko.dev/#/patchset/20260810-fix-blueline-panel-v2-0-9344dfdbc3f9@ixit.cz?part=1
^ permalink raw reply [flat|nested] 8+ messages in thread
end of thread, other threads:[~2026-08-10 10:03 UTC | newest]
Thread overview: 8+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-08-10 9:55 [PATCH v2 0/2] Pixel 3 display fixes David Heidelberg via B4 Relay
2026-08-10 9:55 ` David Heidelberg
2026-08-10 9:55 ` [PATCH v2 1/2] drm/panel: lg-sw43408: do not assert reset across unprepare David Heidelberg via B4 Relay
2026-08-10 9:55 ` David Heidelberg
2026-08-10 10:02 ` sashiko-bot
2026-08-10 9:55 ` [PATCH v2 2/2] drm/panel: lg-sw43408: use the full DCS brightness range David Heidelberg via B4 Relay
2026-08-10 9:55 ` David Heidelberg
2026-08-10 9:59 ` Neil Armstrong
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.