Skip to contentSkip to conversation

drm/tiny: Add RAiO RA8875 display controller driver support

PATCH Superseded Adam Azuddin 3 participants 7 messages Oct 12 – Oct 13

Subsystems (4)

v4 of 6 Superseded Latest is v6 →

lore
Share & tools
lore
#0 lore raw

v4 cover drm/tiny: Add RAiO RA8875 display controller driver support

This series adds a new drm/tiny driver and matching dt-binding for the RAiO RA8875 SPI display controller. An fbtft driver for this chip currently exists at drivers/staging/fbtft/fb_ra8875.c, but fbtft is a legacy fbdev-based staging driver, and nothing in mainline DRM currently supports this controller.

This driver does not use drm_mipi_dbi. The RA8875 SPI protocol is structurally incompatible with both Type C options drm_mipi_dbi supports. Type C1 encodes command/data as a 9th bit within a 9-bit SPI word. The RA8875 uses a full prefix byte (0x80 = command write, 0x00 = data write, 0x40 = data read, 0xC0 = status read) sent as a separate 8-bit transaction. These are not the same thing and cannot be mapped to each other. Type C3 models two transfer types via a D/CX GPIO. The RA8875 has four transfer cycle types and no D/CX pin.

My ER-TFTM050-3 board has RST tied NC, and VDD is a fixed supply set via an on-board solder jumper rather than software-controllable, so I couldn't test reset-gpios/vdd-supply myself, but added them as optional/required properties respectively per review feedback for boards that do need them.

Tested on a Raspberry Pi 3B connected over SPI to an East Rising ER-TFTM050-3, a 5" 800x480 panel driven by the RA8875 in Linux 7.3.0-rc4. Based on drm-misc-next (commit 73df79cceb8c)

Link to v1: https://lore.kernel.org/all/[email protected]/
Link to v2: https://lore.kernel.org/all/[email protected]/
Link to v3: https://lore.kernel.org/all/[email protected]/
---
Changes in v4:

Documentation/devicetree/bindings/display/panel/raio,ra8875.yaml:
- Drop the sentence in the description saying the binding covers only the SPI-connected device (Conor).
- Drop unused panel label

drivers/gpu/drm/tiny/ra8875.c:
- Catch error value from ra8875_write_pixels
- Use consistent include header format.
- Return if fb is null in atomic_update
- Drop unnecessary extra byte in pixel data spi write.

drivers/gpu/drm/tiny/Kconfig:
- Add depends on OF, which is caught by intel 0-day[3]

Changes in v3:

Documentation/devicetree/bindings/display/panel/raio,ra8875.yaml:
- Add gpio.h include in example to pass dt_binding_check
- Remove spi-max-frequency as there is no reference in datasheet

drivers/gpu/drm/tiny/ra8875.c:
- Remove debug-only ra8875_read_reg function
- Chunk large SPI transfers to 16 rows per chunk
- Remove unnecessary includes and spi cs setups in probe
- Create ra8875_write_pixels function for clear_screen and fb_dirty
- Use 2 spi writes instead of 1 write with 2 transfers and cs_change in write_reg

Changes in v2:

Documentation/devicetree/bindings/display/panel/raio,ra8875.yaml (review by Krzysztof Kozlowski):
- Add hardware description to the binding
- Drop the display-timings property, and instead require it in the required block
- Add a required vdd-supply and an optional reset gpio property
- Rename the example node to a more generic "panel: display@0"

drivers/gpu/drm/tiny/Makefile and Kconfig:
- Remove TINYDRM prefix from the config name (Thomas Zimmermann [1])

drivers/gpu/drm/tiny/ra8875.c:
- Reformat device_id table to match current convention (Krzysztof Kozlowski)
- Drop unneeded linux/mod_devicetable.h include (Uwe Kleine-König)
- Use drm_dev_unplug() instead of drm_dev_unregister() in remove callback
- Move stack-allocated cmd/data buffers into ra8875_device struct
- Add mode_valid() callback to validate height/width against panel maximum
- Add optional reset gpio
- Use dev_err_probe() in probe function
- Remove connector detect callback
- Remove unnecessary |= on register write return value in hw_init
- Migrate from simple display pipe to manually-handled plane/crtc/encoder, following the simple-KMS-helper removal effort [2]
- Use defined constants instead of magic values where possible
- Use drm_atomic_helper_damage_merged() and drm_fb_swab() in plane update

[1] https://lore.kernel.org/all/[email protected]/
[2] https://lore.kernel.org/all/20260705-drm-simple-kms-removal-v1-0-b4e1ca053623@oss.qualcomm.com/
[3] https://lore.kernel.org/all/[email protected]/

Adam Azuddin (2):
dt-bindings: display: panel: Add RAiO RA8875 display controller drm/tiny: Add RAiO RA8875 display controller driver

 .../bindings/display/panel/raio,ra8875.yaml   |  77 ++
 .../devicetree/bindings/vendor-prefixes.yaml  |   2 +
 MAINTAINERS                                   |   6 +
 drivers/gpu/drm/tiny/Kconfig                  |  13 +
 drivers/gpu/drm/tiny/Makefile                 |   1 +
 drivers/gpu/drm/tiny/ra8875.c                 | 719 ++++++++++++++++++
 6 files changed, 818 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/display/panel/raio,ra8875.yaml
 create mode 100644 drivers/gpu/drm/tiny/ra8875.c
Signature · 1 line
2.55.0
#1 lore raw

PATCH v4 1/2 dt-bindings: display: panel: Add RAiO RA8875 display controller

The RA8875 is an SPI-connected TFT display controller by RAiO Technology Inc. It supports display resolutions of up to 800x480.

Add YAML binding schema for the RA8875 controller, along with the raio vendor prefix for RAiO Technology Inc.

Assisted-by LLM
---
 .../bindings/display/panel/raio,ra8875.yaml   | 77 +++++++++++++++++++
 .../devicetree/bindings/vendor-prefixes.yaml  |  2 +
 2 files changed, 79 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/display/panel/raio,ra8875.yaml
Documentation/devicetree/bindings/display/panel/raio,ra8875.yaml new file +77 -0
new file mode 100644
index 000000000000..86777e2cec57
@@ -0,0 +1,77 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/display/panel/raio,ra8875.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: RAiO RA8875 Display Controller
+
+maintainers:
+  - Adam Azuddin <[email protected]>
+
+description:
+  The RA8875 is a TFT LCD controller for panels up to 800x480 pixels.
+  It can be connected to the controller via 8080/6800 parallel interface,
+  SPI or I2C.
+
+allOf:
+  - $ref: panel-common.yaml#
+  - $ref: /schemas/spi/spi-peripheral-props.yaml#
+
+properties:
+  compatible:
+    const: raio,ra8875
+
+  reg:
+    maxItems: 1
+
+  vdd-supply:
+    description:
+      3.3 V supply for the IO pins, the oscillator IO pins, the ADC pins
+      and the internal LDO. The 1.8 V core rail is generated internally.
+
+  reset-gpios:
+    description:
+      GPIO connected to the active-low RST# pin. Optional, since the board
+      may instead use an RC reset circuit.
+    maxItems: 1
+
+required:
+  - compatible
+  - reg
+  - display-timings
+  - vdd-supply
+
+unevaluatedProperties: false
+
+examples:
+  - |
+    #include <dt-bindings/gpio/gpio.h>
+
+    spi {
+        #address-cells = <1>;
+        #size-cells = <0>;
+
+        display@0 {
+            compatible = "raio,ra8875";
+            reg = <0>;
+            spi-max-frequency = <16000000>;
+            vdd-supply = <&vcc_3v3>;
+            reset-gpios = <&gpio 25 GPIO_ACTIVE_LOW>;
+
+            display-timings {
+                native-mode = <&timing0>;
+                timing0: timing0 {
+                    clock-frequency = <25000000>;
+                    hactive = <800>;
+                    vactive = <480>;
+                    hfront-porch = <40>;
+                    hsync-len = <40>;
+                    hback-porch = <40>;
+                    vfront-porch = <10>;
+                    vsync-len = <10>;
+                    vback-porch = <20>;
+                };
+            };
+        };
+    };
Documentation/devicetree/bindings/vendor-prefixes.yaml +2 -0
index ba2002969373..99d5113fb035 100644
@@ -1395,6 +1395,8 @@ patternProperties:
     description: Radxa
   "^raidsonic,.*":
     description: RaidSonic Technology GmbH
+  "^raio,.*":
+    description: RAiO Technology Inc.
   "^ralink,.*":
     description: Mediatek/Ralink Technology Corp.
   "^ramtron,.*":
Signature · 1 line
2.55.0
#2 lore raw

Re: [PATCH v4 1/2] dt-bindings: display: panel: Add RAiO RA8875 display controller

Thank you for your contribution! Sashiko AI review found 3 potential issue(s) to consider: - [Medium] dt-bindings: spi-peripheral-props.yaml restricts reg to 256, breaking parallel/I2C buses…

Thank you for your contribution! Sashiko AI review found 3 potential issue(s) to consider:
- [Medium] dt-bindings: spi-peripheral-props.yaml restricts reg to 256, breaking parallel/I2C buses
- [Medium] dt-bindings: missing dc-gpios breaks schema validation for legacy DTs
- [Medium] dt-bindings: display: panel: raio,ra8875: missing interrupts property for INT# pin --

commit 770e5c23771cd9005f8ced2e1ea873a2b2042967
Author: Adam Azuddin <[email protected]>

dt-bindings: display: panel: Add RAiO RA8875 display controller

The RA8875 is an SPI-connected TFT display controller by RAiO Technology Inc. It supports display resolutions of up to 800x480.

Add YAML binding schema for the RA8875 controller, along with the raio vendor prefix for RAiO Technology Inc.

Quoted 6 lines
Documentation/devicetree/bindings/display/panel/raio,ra8875.yaml new file +0 -0
new file mode 100644
index 0000000000000..86777e2cec57a
@@ -0,0 +1,77 @@

[ ... ]

Documentation/devicetree/bindings/display/panel/raio,ra8875.yaml line 19

Quoted 8 lines
Documentation/devicetree/bindings/display/panel/raio,ra8875.yaml new file +8 -0
+description:
+  The RA8875 is a TFT LCD controller for panels up to 800x480 pixels.
+  It can be connected to the controller via 8080/6800 parallel interface,
+  SPI or I2C.
+
+allOf:
+  - $ref: panel-common.yaml#
+  - $ref: /schemas/spi/spi-peripheral-props.yaml#

[Severity: Medium]
Since the description mentions the device can be connected via 8080/6800 parallel interface or I2C, does unconditionally including the SPI peripheral properties here break non-SPI bindings?

The spi-peripheral-props.yaml schema restricts the elements of the reg property to a maximum value of 256. For parallel memory-mapped interfaces, the reg property typically holds a full physical address which violates this constraint, causing device tree validation to fail.

Could this inclusion be made conditional based on the bus type instead?

[ ... ]

Documentation/devicetree/bindings/display/panel/raio,ra8875.yaml line 45

Quoted 7 lines
Documentation/devicetree/bindings/display/panel/raio,ra8875.yaml new file +7 -0
+required:
+  - compatible
+  - reg
+  - display-timings
+  - vdd-supply
+
+unevaluatedProperties: false

[Severity: Medium]
Will this break validation for existing device trees that include the dc-gpios property?

The legacy fbtft driver strictly required this property for the raio,ra8875 device and would abort probe without it:

drivers/staging/fbtft/fbtft-core.c:fbtft_verify_gpios() {
    ...
    if (pdata->display.buswidth != 9 &&  par->startbyte == 0 &&
        !par->gpio.dc) {
        dev_err(par->info->device,
            "Missing info about 'dc' gpio. Aborting.\n");
        return -EINVAL;
    }
    ...
}

Because existing device trees in the wild must contain this property to work with the legacy driver, omitting it here while setting unevaluatedProperties to false will cause them to fail validation.

[Severity: Medium]
Does this schema omission prevent describing the hardware accurately when the INT# pin is connected?

The RA8875 hardware features a dedicated INT# pin to signal events from its built-in touchscreen and keypad controllers. Omitting the interrupts property while setting unevaluatedProperties to false means valid device trees specifying this interrupt routing will be rejected.

Should the interrupts property be added to allow full hardware description, even if the current DRM driver does not consume it?

Signature · 1 line
Sashiko AI review · https://sashiko.dev/#/patchset/[email protected]?part=1
#3 lore raw

Re: [PATCH v4 1/2] dt-bindings: display: panel: Add RAiO RA8875 display controller

In reply to Adam Azuddin
Quoted 4 lines · Adam Azuddin

The RA8875 is an SPI-connected TFT display controller by RAiO Technology Inc. It supports display resolutions of up to 800x480.

Add YAML binding schema for the RA8875 controller, along with

So you ignored my feedback.

Not reviewing the rest.

Best regards,
Krzysztof

#4 lore raw

Re: [PATCH v4 1/2] dt-bindings: display: panel: Add RAiO RA8875 display controller

Hi Krzysztof,

Quoted 7 lines · Krzysztof Kozlowski
Quoted 4 lines · Adam Azuddin

The RA8875 is an SPI-connected TFT display controller by RAiO Technology Inc. It supports display resolutions of up to 800x480.

Add YAML binding schema for the RA8875 controller, along with

So you ignored my feedback.

My mistake, I misunderstood your feedback regarding the redundant binding text in the commit description.

I will fix the commit message and send v5.

Best regards,
Adam

#5 lore raw

PATCH v4 2/2 drm/tiny: Add RAiO RA8875 display controller driver

In reply to Adam Azuddin

Add a DRM tiny driver for the RAiO RA8875 SPI-connected TFT display controller. The driver supports display resolutions up to 800x480 and uses the GEM shmem helper for buffer management.

Assisted-by LLM
---
 MAINTAINERS                   |   6 +
 drivers/gpu/drm/tiny/Kconfig  |  13 +
 drivers/gpu/drm/tiny/Makefile |   1 +
 drivers/gpu/drm/tiny/ra8875.c | 719 ++++++++++++++++++++++++++++++++++
 4 files changed, 739 insertions(+)
 create mode 100644 drivers/gpu/drm/tiny/ra8875.c
MAINTAINERS +6 -0
index a08087fb6e67..ccc36f168e19 100644
@@ -8450,6 +8450,12 @@ T:	git https://gitlab.freedesktop.org/drm/misc/kernel.git
 F:	drivers/gpu/drm/qxl/
 F:	include/uapi/drm/qxl_drm.h
 
+DRM DRIVER FOR RAIO RA8875 PANELS
+M:	Adam Azuddin <[email protected]>
+S:	Maintained
+F:	Documentation/devicetree/bindings/display/panel/raio,ra8875.yaml
+F:	drivers/gpu/drm/tiny/ra8875.c
+
 DRM DRIVER FOR RAYDIUM RM67191 PANELS
 M:	Robert Chiras <[email protected]>
 S:	Maintained
drivers/gpu/drm/tiny/Kconfig +13 -0
index f0e72d4b6a47..2f1c49e31dd6 100644
@@ -98,6 +98,19 @@ config DRM_PIXPAPER
 
 	  If M is selected, the module will be built as pixpaper.ko.
 
+config DRM_RA8875
+	tristate "DRM support for RA8875 display panels"
+	depends on DRM && SPI && OF
+	select DRM_CLIENT_SELECTION
+	select DRM_KMS_HELPER
+	select DRM_GEM_SHMEM_HELPER
+	select VIDEOMODE_HELPERS
+	help
+	  DRM driver for the following RAiO RA8875 based LCD panels:
+	  * East Rising 5.00" TFT LCD (ER-TFTM050-3)
+
+	  If M is selected the module will be called ra8875.
+
 config TINYDRM_HX8357D
 	tristate "DRM support for HX8357D display panels"
 	depends on DRM && SPI
drivers/gpu/drm/tiny/Makefile +1 -0
index 48d30bf6152f..ed4602097fbb 100644
@@ -14,4 +14,5 @@ obj-$(CONFIG_TINYDRM_ILI9341)		+= ili9341.o
 obj-$(CONFIG_TINYDRM_ILI9486)		+= ili9486.o
 obj-$(CONFIG_TINYDRM_MI0283QT)		+= mi0283qt.o
 obj-$(CONFIG_TINYDRM_REPAPER)		+= repaper.o
+obj-$(CONFIG_DRM_RA8875)		+= ra8875.o
 obj-$(CONFIG_TINYDRM_SHARP_MEMORY)	+= sharp-memory.o
drivers/gpu/drm/tiny/ra8875.c new file +719 -0

719 lines not on this page · raw message

Signature · 1 line
2.55.0
#6 lore raw

Re: [PATCH v4 2/2] drm/tiny: Add RAiO RA8875 display controller driver

Thank you for your contribution! Sashiko AI review found 3 potential issue(s) to consider: - [High] drm: sleeping functions called from atomic commit callbacks - [High] spi: DMA-mapped buffers…

Thank you for your contribution! Sashiko AI review found 3 potential issue(s) to consider:
- [High] drm: sleeping functions called from atomic commit callbacks
- [High] spi: DMA-mapped buffers embedded in struct ra8875_device lack cacheline alignment
- [High] drm/tiny: ra8875: heap overflow in ra8875_clear_screen() via oversized mode --

commit 7912d063f00aebeba1b3f55021d00d84d5599465
Author: Adam Azuddin <[email protected]>

drm/tiny: Add RAiO RA8875 display controller driver

Add a DRM tiny driver for the RAiO RA8875 SPI-connected TFT display controller. The driver supports display resolutions up to 800x480 and uses the GEM shmem helper for buffer management.

Quoted 5 lines
drivers/gpu/drm/tiny/ra8875.c new file +0 -0
new file mode 100644
@@ -0,0 +1,719 @@

[ ... ]

drivers/gpu/drm/tiny/ra8875.c line 119

Quoted 13 lines
drivers/gpu/drm/tiny/ra8875.c new file +13 -0
+struct ra8875_device {
+	struct drm_device drm;
+	struct spi_device *spi;
+	struct gpio_desc *rst_gpio;
+	struct drm_crtc crtc;
+	struct drm_plane plane;
+	struct drm_encoder encoder;
+	struct drm_connector connector;
+	struct drm_display_mode mode;
+	u8 cmd_buf[RA8875_CMD_DATA_BUF_SIZE];
+	u8 data_buf[RA8875_CMD_DATA_BUF_SIZE];
+	u8 *txbuf;
+};

[Severity: High]
Since these embedded arrays are passed to spi_write() and may be mapped for DMA transfers, could they cause memory corruption?

During DMA mapping, the CPU performs cache invalidation and flushing operations that operate on full cache lines. Because these small buffers share cache lines with adjacent members of struct ra8875_device, this risks silent memory corruption of adjacent fields (such as the txbuf pointer) via false sharing.

Should these be declared with ____cacheline_aligned, or allocated separately?

[ ... ]

drivers/gpu/drm/tiny/ra8875.c line 180

Quoted 12 lines
drivers/gpu/drm/tiny/ra8875.c new file +12 -0
+static int ra8875_write_pixels(struct ra8875_device *ra8875, size_t len)
+{
+	int ret;
+
+	ra8875->cmd_buf[0] = RA8875_CMDWRITE;
+	ra8875->cmd_buf[1] = RA8875_MRWC;
+	ret = spi_write(ra8875->spi, ra8875->cmd_buf, 2);
+	if (ret)
+		return ret;
+
+	return spi_write(ra8875->spi, ra8875->txbuf, len);
+}

[Severity: High]
Can this blocking SPI write cause scheduling while atomic warnings?

The DRM subsystem guidelines state that plane atomic callbacks (like ra8875_plane_atomic_update()) execute in an atomic context where sleeping is strictly forbidden.

Because ra8875_plane_atomic_update() calls ra8875_fb_dirty() which in turn calls ra8875_write_pixels(), this synchronously invokes spi_write(). The spi_write() API is blocking, takes a mutex, and sleeps during the transfer.

Could this be moved to a non-atomic worker or handled differently?

drivers/gpu/drm/tiny/ra8875.c line 194

Quoted 13 lines
drivers/gpu/drm/tiny/ra8875.c new file +13 -0
+static int ra8875_hw_init(struct ra8875_device *ra8875,
+			  struct drm_display_mode *mode)
+{
+	u8 hdwr, hndr, hstr, hpwr, vpwr;
+	u16 vdhr, vndr, vstr;
+	int ret;
+
+	if (ra8875->rst_gpio) {
+		gpiod_set_value_cansleep(ra8875->rst_gpio, 1);
+		usleep_range(1000, 1200);
+		gpiod_set_value_cansleep(ra8875->rst_gpio, 0);
+		msleep(RA8875_RESET_WAIT_MS);
+	}

[Severity: High]
Does this code call sleeping functions from an atomic commit callback?

ra8875_crtc_atomic_enable() calls ra8875_hw_init(), which invokes gpiod_set_value_cansleep(), usleep_range(), and msleep().

The DRM guidelines require that CRTC atomic enable callbacks do not sleep. Executing these functions within the atomic commit pipeline can cause priority inversion, deadlocks, and system instability.

[ ... ]

drivers/gpu/drm/tiny/ra8875.c line 502

Quoted 12 lines
drivers/gpu/drm/tiny/ra8875.c new file +12 -0
+static enum drm_mode_status ra8875_mode_valid(struct drm_crtc *crtc,
+					      const struct drm_display_mode *mode)
+{
+	if (mode->hdisplay % 8 != 0 || mode->hsync_start % 8 != 0 ||
+	    mode->hsync_end % 8 != 0 || mode->htotal % 8 != 0) {
+		drm_dbg_kms(crtc->dev,
+		   "mode timings must be 8-pixel aligned (hdisplay=%d hsync_start=%d hsync_end=%d htotal=%d)\n",
+			    mode->hdisplay, mode->hsync_start, mode->hsync_end, mode->htotal);
+		return MODE_H_ILLEGAL;
+	}
+	return MODE_OK;
+}

[Severity: High]
Could this validation allow custom modes to trigger a heap buffer overflow?

In ra8875_probe(), txbuf is allocated with a fixed size based on RA8875_MAX_WIDTH:

    buf_size = 1 + RA8875_TXBUF_ROWS * RA8875_MAX_WIDTH * 2;
    ra8875->txbuf = devm_kzalloc(&spi->dev, buf_size, GFP_KERNEL);

When userspace submits a custom display mode, the DRM core does not restrict mode dimensions against mode_config.max_width (which only limits framebuffer sizes). Since there is no explicit check here that mode->hdisplay is less than or equal to RA8875_MAX_WIDTH, a malicious or oversized mode can reach ra8875_clear_screen().

This results in a heap overwrite when deriving the memset length:

    int width = mode->hdisplay;
    ...
    memset(txbuf, 0, 1 + rows_per_chunk * width * 2);

Should this function verify that mode->hdisplay <= RA8875_MAX_WIDTH and mode->vdisplay <= RA8875_MAX_HEIGHT?

Signature · 1 line
Sashiko AI review · https://sashiko.dev/#/patchset/[email protected]?part=2