Skip to contentSkip to conversation

drm/tiny: add support for PIXPAPER 4.26 monochrome e-ink panel

PATCH Superseded LiangCheng Wang 3 participants 5 messages May 26

Subsystems (4)

v2 of 3 Superseded Latest is v3 →

lore
Share & tools
lore

LiangCheng Wang

author maintainer
#0 lore raw

v2 cover drm/tiny: add support for PIXPAPER 4.26 monochrome e-ink panel

This patch series adds support for the Mayqueen Pixpaper 4.26 monochrome e-ink display panel, controlled via SPI.

The series includes:
- Device tree binding updates for the Pixpaper 4.26 panel
- A DRM tiny driver implementation for the Pixpaper 4.26 panel
- A MAINTAINERS update for the Pixpaper DRM drivers and binding

The panel supports 800x480 resolution with XRGB8888 framebuffer input and uses SPI, along with GPIO lines for reset, busy, and data/command control.

Tested on:
- Raspberry Pi 5 with Linux kernel 7.1.0-rc1

Feedback is welcome.

---
Changes in v2:
- Explain why pixpaper-426m requires a distinct compatible string despite sharing the same SPI and GPIO properties with the existing Pixpaper panel.
- Drop the duplicated pixpaper-426m DT binding example.
- Update the binding description for multiple Pixpaper panels.
- Select DRM_GEM_SHMEM_HELPER instead of DRM_GEM_DMA_HELPER for the pixpaper-426m driver.
- Link to v1: https://lore.kernel.org/r/[email protected]

---
LiangCheng Wang (2):
dt-bindings: display: mayqueen,pixpaper: add pixpaper-426m drm/tiny: add support for PIXPAPER 4.26 monochrome e-ink panel

 .../bindings/display/mayqueen,pixpaper.yaml        |  13 +-
 MAINTAINERS                                        |   3 +-
 drivers/gpu/drm/tiny/Kconfig                       |  16 +
 drivers/gpu/drm/tiny/Makefile                      |   1 +
 drivers/gpu/drm/tiny/pixpaper-426m.c               | 828 +++++++++++++++++++++
 5 files changed, 855 insertions(+), 6 deletions(-)

---
base-commit: a293ec25d59dd96309058c70df5a4dd0f889a1e4
change-id: 20260505-bar-523f2c3f6939

Best regards,

Signature · 1 line
LiangCheng Wang <[email protected]>
author maintainer
#1 lore raw

PATCH v2 1/2 dt-bindings: display: mayqueen,pixpaper: add pixpaper-426m

Add the compatible string for the PIXPAPER 4.26 monochrome e-ink panel to the Mayqueen Pixpaper binding.

The new panel uses the same SPI and GPIO properties as the existing Pixpaper panel, but it is not software-compatible with it. The 4.26-inch panel requires different panel-specific initialization and update command sequences, so use a distinct compatible string.

Document the new compatible string and update the binding description accordingly.

---
 .../devicetree/bindings/display/mayqueen,pixpaper.yaml      | 13 ++++++++-----
 1 file changed, 8 insertions(+), 5 deletions(-)
Documentation/devicetree/bindings/display/mayqueen,pixpaper.yaml +8 -5
index cd27f8ba5ae1d94660818525b5fa71db98c8acb7..68a6157114604a8308259191e55d1e2d15d76c11 100644
@@ -4,22 +4,25 @@
 $id: http://devicetree.org/schemas/display/mayqueen,pixpaper.yaml#
 $schema: http://devicetree.org/meta-schemas/core.yaml#
 
-title: Mayqueen Pixpaper e-ink display panel
+title: Mayqueen Pixpaper e-ink display panels
 
 maintainers:
   - LiangCheng Wang <[email protected]>
 
 description:
-  The Pixpaper is an e-ink display panel controlled via an SPI interface.
-  The panel has a resolution of 122x250 pixels and requires GPIO pins for
-  reset, busy, and data/command control.
+  Mayqueen Pixpaper e-ink display panels are controlled via an SPI interface
+  and require GPIO pins for reset, busy, and data/command control. Different
+  panel models use model-specific command sequences selected via their
+  compatible strings.
 
 allOf:
   - $ref: /schemas/spi/spi-peripheral-props.yaml#
 
 properties:
   compatible:
-    const: mayqueen,pixpaper
+    enum:
+      - mayqueen,pixpaper
+      - mayqueen,pixpaper-426m
 
   reg:
     maxItems: 1
Signature · 1 line
2.34.1
author maintainer
#3 lore raw

PATCH v2 2/2 drm/tiny: add support for PIXPAPER 4.26 monochrome e-ink panel

In reply to LiangCheng Wang

Introduce a DRM driver for the Mayqueen Pixpaper 4.26 monochrome e-ink display panel, which is controlled via SPI. The driver supports an 800x480 display with XRGB8888 framebuffer input.

Also, add Kconfig and Makefile entries for the driver and update MAINTAINERS for the Pixpaper DRM drivers and binding.

---
 MAINTAINERS                          |   3 +-
 drivers/gpu/drm/tiny/Kconfig         |  16 +
 drivers/gpu/drm/tiny/Makefile        |   1 +
 drivers/gpu/drm/tiny/pixpaper-426m.c | 828 +++++++++++++++++++++++++++++++++++
 4 files changed, 847 insertions(+), 1 deletion(-)
MAINTAINERS +2 -1
index 882214b0e7db53bb8cc8e75b5d2269ee0591ea20..eebd73ee1f531d3785ec963da03fbab265c2d188 100644
@@ -8234,11 +8234,12 @@ T:	git https://gitlab.freedesktop.org/drm/misc/kernel.git
 F:	Documentation/devicetree/bindings/display/repaper.txt
 F:	drivers/gpu/drm/tiny/repaper.c
 
-DRM DRIVER FOR PIXPAPER E-INK PANEL
+DRM DRIVER FOR PIXPAPER E-INK PANELS
 M:	LiangCheng Wang <[email protected]>
 L:	[email protected]
 S:	Maintained
 F:	Documentation/devicetree/bindings/display/mayqueen,pixpaper.yaml
+F:	drivers/gpu/drm/tiny/pixpaper-426m.c
 F:	drivers/gpu/drm/tiny/pixpaper.c
 
 DRM DRIVER FOR QEMU'S CIRRUS DEVICE
drivers/gpu/drm/tiny/Kconfig +16 -0
index f0e72d4b6a4709564e63c758e857bdb4a320dbe7..028c4314106ac31dfa717f6433c28e58b34c21e8 100644
@@ -98,6 +98,22 @@ config DRM_PIXPAPER
 
 	  If M is selected, the module will be built as pixpaper.ko.
 
+config DRM_PIXPAPER_426M
+	tristate "DRM support for PIXPAPER 4.26 monochrome display panel"
+	depends on DRM && SPI
+	depends on MMU
+	select DRM_CLIENT_SELECTION
+	select DRM_GEM_SHMEM_HELPER
+	select DRM_KMS_HELPER
+	help
+	  DRM driver for the Mayqueen Pixpaper 4.26 monochrome e-ink
+	  display panel.
+
+	  This driver supports SPI-connected 800x480 monochrome panels
+	  with an XRGB8888 framebuffer input format.
+
+	  If M is selected, the module will be built as pixpaper-426m.ko.
+
 config TINYDRM_HX8357D
 	tristate "DRM support for HX8357D display panels"
 	depends on DRM && SPI
drivers/gpu/drm/tiny/Makefile +1 -0
index 48d30bf6152f979404ac1004174587823a30109e..037b751a1a851cc2f86f701ff71008bcb9c59f29 100644
@@ -7,6 +7,7 @@ obj-$(CONFIG_DRM_CIRRUS_QEMU)		+= cirrus-qemu.o
 obj-$(CONFIG_DRM_GM12U320)		+= gm12u320.o
 obj-$(CONFIG_DRM_PANEL_MIPI_DBI)	+= panel-mipi-dbi.o
 obj-$(CONFIG_DRM_PIXPAPER)              += pixpaper.o
+obj-$(CONFIG_DRM_PIXPAPER_426M)         += pixpaper-426m.o
 obj-$(CONFIG_TINYDRM_HX8357D)		+= hx8357d.o
 obj-$(CONFIG_TINYDRM_ILI9163)		+= ili9163.o
 obj-$(CONFIG_TINYDRM_ILI9225)		+= ili9225.o
drivers/gpu/drm/tiny/pixpaper-426m.c new file +828 -0

828 lines not on this page · raw message

Signature · 1 line
2.34.1
#4 lore raw
Thank you for your contribution! Sashiko AI review found 5 potential issue(s) to consider: - [High] The plane's atomic_update callback calls multiple sleeping functions and allocates memory with…

Thank you for your contribution! Sashiko AI review found 5 potential issue(s) to consider:
- [High] The plane's atomic_update callback calls multiple sleeping functions and allocates memory with GFP_KERNEL, violating DRM subsystem constraints.
- [High] The driver passes stack-allocated variables and read-only data (.rodata) directly to spi_write(), which violates Linux DMA API requirements.
- [High] Incorrect pixel format extraction on big-endian architectures due to native 32-bit reads of a little-endian byte array.
- [Medium] Hardware timeouts in pixpaper_wait_busy() are logged but not propagated to the caller, causing the driver to issue subsequent commands to an unready panel.
- [Medium] The format conversion function pixpaper_xrgb8888_to_bw() unintentionally flips the image horizontally.
--

commit 9e268f738b87e01832dbe79fc73ab5d8adefe3cb
Author: LiangCheng Wang <[email protected]>

drm/tiny: add support for PIXPAPER 4.26 monochrome e-ink panel

Introduce a DRM driver for the Mayqueen Pixpaper 4.26 monochrome e-ink display panel, which is controlled via SPI. The driver supports an 800x480 display with XRGB8888 framebuffer input.

Quoted 5 lines
drivers/gpu/drm/tiny/pixpaper-426m.c new file +0 -0
new file mode 100644
index 0000000000000..159dcc246092f

[ ... ]

drivers/gpu/drm/tiny/pixpaper-426m.c line 250

Quoted 12 lines
drivers/gpu/drm/tiny/pixpaper-426m.c new file +12 -0
+static void pixpaper_wait_busy(struct pixpaper_panel *panel)
+{
+	unsigned int timeout_ms = PIXPAPER_BUSY_TIMEOUT_MS;
+	unsigned long timeout_jiffies = jiffies + msecs_to_jiffies(timeout_ms);
+
+	usleep_range(PIXPAPER_BUSY_POLL_INITIAL_US_MIN,
+		     PIXPAPER_BUSY_POLL_INITIAL_US_MAX);
+	while (gpiod_get_value_cansleep(panel->busy) != 0) {
+		if (time_after(jiffies, timeout_jiffies)) {
+			drm_warn(&panel->drm, "Busy wait timed out\n");
+			return;
+		}

[Severity: Medium]
Should this function update the error context when it times out?

Currently, on timeout it logs a warning but returns without setting err->errno_code to -ETIMEDOUT or another error code. Because the error context is not updated, callers like pixpaper_trigger_update() remain unaware of the failure and continue sending SPI commands to an unready panel, which may cause hardware state corruption.

Quoted 4 lines
drivers/gpu/drm/tiny/pixpaper-426m.c new file +4 -0
+		usleep_range(PIXPAPER_BUSY_POLL_US_MIN,
+			     PIXPAPER_BUSY_POLL_US_MAX);
+	}
+}

[ ... ]

drivers/gpu/drm/tiny/pixpaper-426m.c line 283

Quoted 11 lines
drivers/gpu/drm/tiny/pixpaper-426m.c new file +11 -0
+static void pixpaper_send_cmd(struct pixpaper_panel *panel, u8 cmd,
+			      struct pixpaper_error_ctx *err)
+{
+	pixpaper_spi_write(panel, 0, &cmd, sizeof(cmd), err);
+}
+
+static void pixpaper_send_data(struct pixpaper_panel *panel, u8 data,
+			       struct pixpaper_error_ctx *err)
+{
+	pixpaper_spi_write(panel, 1, &data, sizeof(data), err);
+}

[Severity: High]
Does this code violate the DMA API by mapping stack memory?

The spi_write() function maps the provided buffer using the DMA API. In pixpaper_send_cmd() and pixpaper_send_data(), pointers to local stack variables (cmd and data) are passed.

The Linux DMA API forbids mapping stack memory because cacheline operations by the DMA controller can silently corrupt adjacent stack frames or cause kernel panics.

[ ... ]

drivers/gpu/drm/tiny/pixpaper-426m.c line 322

Quoted 10 lines
drivers/gpu/drm/tiny/pixpaper-426m.c new file +10 -0
+static void pixpaper_send_init_seq(struct pixpaper_panel *panel,
+				   const struct pixpaper_init_seq *seq,
+				   struct pixpaper_error_ctx *err)
+{
+	if (err->errno_code || !seq->data || !seq->len)
+		return;
+
+	pixpaper_send_cmd(panel, seq->cmd, err);
+	pixpaper_spi_write(panel, 1, seq->data, seq->len, err);
+}

[Severity: High]
Can passing read-only data to spi_write() cause DMA issues here?

The caller passes pointers to global const arrays residing in .rodata (e.g., pixpaper_init_temp_sensor). The DMA API also explicitly forbids mapping read-only data.

[ ... ]

drivers/gpu/drm/tiny/pixpaper-426m.c line 347

Quoted 12 lines
drivers/gpu/drm/tiny/pixpaper-426m.c new file +12 -0
+static void *pixpaper_prepare_buffer(const void *vaddr,
+				     const struct drm_framebuffer *fb,
+				     u32 *dst_pitch,
+				     struct pixpaper_error_ctx *err)
+{
+	void *dst;
+
+	if (err->errno_code)
+		return NULL;
+
+	*dst_pitch = DIV_ROUND_UP(fb->width, 8);
+	dst = kzalloc(*dst_pitch * fb->height, GFP_KERNEL);

[Severity: High]
Is it safe to allocate memory with GFP_KERNEL here?

This function is called from pixpaper_plane_atomic_update(), which executes in an atomic context where sleeping is forbidden. This allocation can cause kernel warnings (e.g., scheduling while atomic) and potential deadlocks.

Quoted 4 lines
drivers/gpu/drm/tiny/pixpaper-426m.c new file +4 -0
+	if (!dst) {
+		err->errno_code = -ENOMEM;
+		return NULL;
+	}

[ ... ]

Quoted 6 lines
drivers/gpu/drm/tiny/pixpaper-426m.c new file +6 -0
+static void pixpaper_xrgb8888_to_bw(const void *src, void *dst, u32 height,
+				    u32 width, u32 src_pitch, u32 dst_pitch)
+{
+	const uint8_t *src_base = src;
+	uint8_t *dst_pixels = dst;
+

drivers/gpu/drm/tiny/pixpaper-426m.c line 410

Quoted 10 lines
drivers/gpu/drm/tiny/pixpaper-426m.c new file +10 -0
+	if (dst == NULL || src == NULL)
+		return;
+
+	for (u32 y = 0; y < height; y++) {
+		uint8_t *dst_row = dst_pixels + y * dst_pitch;
+		const uint8_t *src_row = src_base + y * src_pitch;
+		const uint32_t *src_pixels = (const uint32_t *)src_row;
+
+		for (u32 x = 0; x < width; x++) {
+			u32 src_x = width - 1 - x;

[Severity: Medium]
Does this coordinate mapping intentionally flip the image horizontally?

The source pixel index is calculated as width - 1 - x, while the destination bit is derived directly from x. This maps the rightmost pixel of the source to the leftmost pixel of the output.

drivers/gpu/drm/tiny/pixpaper-426m.c line 421

Quoted 11 lines
drivers/gpu/drm/tiny/pixpaper-426m.c new file +11 -0
+			uint8_t r, g, b;
+			u8 bit;
+			u32 bit_pos = x % 8;
+			u32 byte_pos = x / 8;
+			uint32_t gray_val;
+			uint32_t pixel;
+
+			pixel = src_pixels[src_x];
+			r = (pixel >> 16) & 0xFF;
+			g = (pixel >> 8) & 0xFF;
+			b = pixel & 0xFF;

[Severity: High]
Can this pixel format extraction fail on big-endian architectures?

The DRM_FORMAT_XRGB8888 pixel format specifies bytes in little-endian order in memory (B, G, R, X). The native 32-bit read casts the source buffer and performs a 32-bit load. On big-endian architectures, this will interpret the byte sequence incorrectly, placing the color bytes in the wrong positions and extracting the wrong channels.

[ ... ]

drivers/gpu/drm/tiny/pixpaper-426m.c line 499

Quoted 3 lines
drivers/gpu/drm/tiny/pixpaper-426m.c new file +3 -0
+static void pixpaper_plane_atomic_update(struct drm_plane *plane,
+					 struct drm_atomic_state *state)
+{

[Severity: High]
Are you aware that plane atomic_update callbacks execute in an atomic context where sleeping is forbidden?

This function calls pixpaper_prepare_buffer(), which allocates memory with GFP_KERNEL, and it invokes blocking SPI operations via pixpaper_write_image() and pixpaper_trigger_update() which sleep. Calling sleeping functions from atomic context violates DRM subsystem constraints.

Quoted 4 lines
drivers/gpu/drm/tiny/pixpaper-426m.c new file +4 -0
+	struct drm_plane_state *plane_state =
+		drm_atomic_get_new_plane_state(state, plane);
+	struct drm_shadow_plane_state *shadow_plane_state =
+		to_drm_shadow_plane_state(plane_state);
Signature · 1 line
Sashiko AI review · https://sashiko.dev/#/patchset/[email protected]?part=2