From: Marcus Folkesson marcus.folkesson@gmail.com
[ Upstream commit e61c35157d32b4b422f0a4cbc3c40d04d883a9c9 ]
Depending on which display that is connected to the controller, an "1" means either a black or a white pixel.
The supported formats (R1/R2/XRGB8888) expects the pixels to map against (4bit): 00 => Black 01 => Dark Gray 10 => Light Gray 11 => White
If this is not what the display map against, make it possible to invert the pixels.
Reviewed-by: Javier Martinez Canillas javierm@redhat.com Signed-off-by: Marcus Folkesson marcus.folkesson@gmail.com Link: https://lore.kernel.org/r/20250721-st7571-format-v2-4-159f4134098c@gmail.com Signed-off-by: Javier Martinez Canillas javierm@redhat.com Signed-off-by: Sasha Levin sashal@kernel.org ---
LLM Generated explanations, may be completely bogus:
YES
- Fixes a real user-visible bug: Many ST7571/ST7567-based panels wire pixel polarity differently, so a “1” stored in display RAM can mean black or white depending on the glass. Without a way to invert, affected panels show inverted colors/gray levels. This change makes that correctable in a board-specific, opt-in way via DT.
- Small, contained change with default behavior unchanged: The driver still programs “normal” mode unless explicitly told to invert. The only behavior change is when the new DT boolean is present.
- Specific code changes - Adds per-device state to track inversion: - `drivers/gpu/drm/sitronix/st7571-i2c.c:154` adds `bool inverted;` to `struct st7571_device`. - Parses an opt-in DT property for both variants: - `drivers/gpu/drm/sitronix/st7571-i2c.c:796` reads `sitronix,inverted` in `st7567_parse_dt()`. - `drivers/gpu/drm/sitronix/st7571-i2c.c:824` reads `sitronix,inverted` in `st7571_parse_dt()`. - Applies inversion during controller initialization: - Previously hardcoded to normal mode, i.e. `ST7571_SET_REVERSE(0)`. - Now conditional: - `drivers/gpu/drm/sitronix/st7571-i2c.c:879` uses `ST7571_SET_REVERSE(st7567->inverted ? 1 : 0)` in the ST7567 init sequence. - `drivers/gpu/drm/sitronix/st7571-i2c.c:923` uses `ST7571_SET_REVERSE(st7571->inverted ? 1 : 0)` in the ST7571 init sequence. - The command used is appropriate: `ST7571_SET_REVERSE(r)` (`drivers/gpu/drm/sitronix/st7571-i2c.c:61`) toggles the controller’s normal/inverse display mapping, which affects both monochrome and 4-level grayscale mapping uniformly.
- No architectural changes and minimal risk of regressions: - Change is confined to a single driver and two init paths; no core DRM impacts. - Default remains normal (non-inverted), so existing systems are unaffected unless they opt in via DT. - No userspace ABI changes; the interface is device-tree only. - The property is boolean and optional; absence preserves legacy behavior.
- Stable backport criteria fit: - Addresses a correctness issue for real hardware (wrong polarity makes displays appear inverted). - Patch is small and straightforward, with clear, localized side effects. - No new features visible to userspace; it’s an optional DT quirk to match panel wiring.
Given the above, this is a low-risk, targeted fix enabling correct operation for affected panels and is suitable for stable backporting.
drivers/gpu/drm/sitronix/st7571-i2c.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-)
diff --git a/drivers/gpu/drm/sitronix/st7571-i2c.c b/drivers/gpu/drm/sitronix/st7571-i2c.c index 453eb7e045e5f..125e810df1391 100644 --- a/drivers/gpu/drm/sitronix/st7571-i2c.c +++ b/drivers/gpu/drm/sitronix/st7571-i2c.c @@ -151,6 +151,7 @@ struct st7571_device { bool ignore_nak;
bool grayscale; + bool inverted; u32 height_mm; u32 width_mm; u32 startline; @@ -792,6 +793,7 @@ static int st7567_parse_dt(struct st7571_device *st7567)
of_property_read_u32(np, "width-mm", &st7567->width_mm); of_property_read_u32(np, "height-mm", &st7567->height_mm); + st7567->inverted = of_property_read_bool(np, "sitronix,inverted");
st7567->pformat = &st7571_monochrome; st7567->bpp = 1; @@ -819,6 +821,7 @@ static int st7571_parse_dt(struct st7571_device *st7571) of_property_read_u32(np, "width-mm", &st7571->width_mm); of_property_read_u32(np, "height-mm", &st7571->height_mm); st7571->grayscale = of_property_read_bool(np, "sitronix,grayscale"); + st7571->inverted = of_property_read_bool(np, "sitronix,inverted");
if (st7571->grayscale) { st7571->pformat = &st7571_grayscale; @@ -873,7 +876,7 @@ static int st7567_lcd_init(struct st7571_device *st7567) ST7571_SET_POWER(0x6), /* Power Control, VC: ON, VR: ON, VF: OFF */ ST7571_SET_POWER(0x7), /* Power Control, VC: ON, VR: ON, VF: ON */
- ST7571_SET_REVERSE(0), + ST7571_SET_REVERSE(st7567->inverted ? 1 : 0), ST7571_SET_ENTIRE_DISPLAY_ON(0), };
@@ -917,7 +920,7 @@ static int st7571_lcd_init(struct st7571_device *st7571) ST7571_SET_COLOR_MODE(st7571->pformat->mode), ST7571_COMMAND_SET_NORMAL,
- ST7571_SET_REVERSE(0), + ST7571_SET_REVERSE(st7571->inverted ? 1 : 0), ST7571_SET_ENTIRE_DISPLAY_ON(0), };