drm/tiny: Add RAiO RA8875 display controller driver support
Subsystems (4)
v3 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 7c4bda20eb0f150315d19f1b51058820e75d3f3d)
Link to v1: https://lore.kernel.org/all/[email protected]/
Link to v2: https://lore.kernel.org/all/[email protected]/
---
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/
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 | 713 ++++++++++++++++++ 6 files changed, 812 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
PATCH v3 1/2 dt-bindings: display: panel: Add RAiO RA8875 display controller
The binding is for SPI-connected RA8875 TFT display controller by RAiO Technology Inc. It supports display resolutions of up to 800x480.
--- .../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
@@ -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. This binding describes the SPI-connected device. + +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>; + + panel: 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
@@ -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
Re: [PATCH v3 1/2] dt-bindings: display: panel: Add RAiO RA8875 display controller
Quoted 22 lines · Adam Azuddin
The binding is for SPI-connected RA8875 TFT display controller by RAiO Technology Inc. It supports display resolutions of up to 800x480.
Assisted-by LLMSigned-off-by Adam Azuddin <[email protected]>--- .../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.yamlDocumentation/devicetree/bindings/display/panel/raio,ra8875.yaml new file +5
-0@@ -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#
Documentation/devicetree/bindings/display/panel/raio,ra8875.yaml line 15
Quoted 10 lines
Documentation/devicetree/bindings/display/panel/raio,ra8875.yaml new file +10
-0+ +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. This binding describes the SPI-connected device.
This binding describes all three, or at least it should describe both i2c and spi in the current state. I have no idea what the parallel interfaces look like in dt, but if what you've got covers spi it should also cover i2c. Probably remove this last sentence.
pw-bot: changes-requested
Quoted 30 lines
Documentation/devicetree/bindings/display/panel/raio,ra8875.yaml new file +30
-0+ +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
Documentation/devicetree/bindings/display/panel/raio,ra8875.yaml line 55
Quoted 10 lines
Documentation/devicetree/bindings/display/panel/raio,ra8875.yaml new file +10
-0+ +examples: + - | + #include <dt-bindings/gpio/gpio.h> + + spi { + #address-cells = <1>; + #size-cells = <0>; + + panel: display@0 {
Drop the unused panel label if there's a respin.
Quoted 38 lines
Documentation/devicetree/bindings/display/panel/raio,ra8875.yaml new file +22
-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@@ -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
Re: [PATCH v3 1/2] dt-bindings: display: panel: Add RAiO RA8875 display controller
Quoted 11 lines · Conor Dooley
Documentation/devicetree/bindings/display/panel/raio,ra8875.yaml line 15
Quoted 4 lines · Adam Azuddin
Documentation/devicetree/bindings/display/panel/raio,ra8875.yaml new file +4
-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. This binding describes the SPI-connected device.This binding describes all three, or at least it should describe both i2c and spi in the current state. I have no idea what the parallel interfaces look like in dt, but if what you've got covers spi it should also cover i2c. Probably remove this last sentence.
pw-bot: changes-requested
Understood, I'll drop that last sentence.
Quoted 3 lines
Quoted 1 line
+ panel: display@0 {
Drop the unused panel label if there's a respin.
Will do.
Thanks for the review,
Adam
PATCH v3 2/2 drm/tiny: Add RAiO RA8875 display controller driver
In reply to Adam AzuddinAdd 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.
--- MAINTAINERS | 6 + drivers/gpu/drm/tiny/Kconfig | 13 + drivers/gpu/drm/tiny/Makefile | 1 + drivers/gpu/drm/tiny/ra8875.c | 713 ++++++++++++++++++++++++++++++++++ 4 files changed, 733 insertions(+) create mode 100644 drivers/gpu/drm/tiny/ra8875.c
MAINTAINERS +6 -0
@@ -8449,6 +8449,12 @@ S: Maintained F: Documentation/devicetree/bindings/display/panel/raydium,rm67191.yaml F: drivers/gpu/drm/panel/panel-raydium-rm67191.c +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 SAMSUNG DB7430 PANELS M: Linus Walleij <[email protected]> S: Maintained
drivers/gpu/drm/tiny/Kconfig +13 -0
@@ -195,6 +195,19 @@ config TINYDRM_REPAPER If M is selected the module will be called repaper. +config DRM_RA8875 + tristate "DRM support for RA8875 display panels" + depends on DRM && SPI + 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-TFTM070-5V4) + + If M is selected the module will be called ra8875. + config TINYDRM_SHARP_MEMORY tristate "DRM support for Sharp Memory LCD panels" depends on DRM && SPI
drivers/gpu/drm/tiny/Makefile +1 -0
@@ -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 +713 -0
713 lines not on this page · raw message
Signature · 1 line
2.55.0
[email protected]
AI reviewRe: [PATCH v3 2/2] drm/tiny: Add RAiO RA8875 display controller driver
Thank you for your contribution! Sashiko AI review found 6 potential issue(s) to consider: - [High] drm/tiny: ra8875: sleeping functions called in atomic context - [High] drm/tiny: ra8875…
Thank you for your contribution! Sashiko AI review found 6 potential issue(s) to consider:
- [High] drm/tiny: ra8875: sleeping functions called in atomic context
- [High] drm/tiny: ra8875: out-of-bounds DMA read due to double len increment
- [High] drm/tiny: ra8875: heap buffer overflow in ra8875_clear_screen
- [Medium] drm/tiny: ra8875: unsafe DMA from unaligned struct members
- [Low] drm/tiny: ra8875: spurious "Shadow map is null" error on plane disable
- [Low] drm/tiny: ra8875: missing error check on ra8875_write_pixels
--
commit a60dff365b1d365d54b1d95db3b3bdf06cf4d8be
Author: Adam Azuddin <[email protected]>
drm/tiny: Add RAiO RA8875 display controller driver
This commit adds a DRM tiny driver for the RAiO RA8875 SPI-connected TFT display controller. It supports display resolutions up to 800x480 and uses the GEM shmem helper for buffer management.
Quoted 6 lines
drivers/gpu/drm/tiny/ra8875.c new file +0
-0@@ -0,0 +1,713 @@
[ ... ]
drivers/gpu/drm/tiny/ra8875.c line 117
Quoted 11 lines
drivers/gpu/drm/tiny/ra8875.c new file +11
-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 ];
[Severity: Medium]
Is it safe to use these inline arrays for DMA?
According to kernel DMA rules, buffers mapped for DMA must not share a cacheline with other variables. Concurrent CPU accesses to adjacent members in the structure (such as userspace reading mode properties) during an ongoing SPI DMA transfer might cause cacheline bouncing and silent data corruption. Should these arrays have cacheline alignment attributes or be allocated separately?
Quoted 2 lines
drivers/gpu/drm/tiny/ra8875.c new file +2
-0+u8 *txbuf; +};
[ ... ]
drivers/gpu/drm/tiny/ra8875.c line 179
Quoted 11 lines
drivers/gpu/drm/tiny/ra8875.c new file +11
-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,1 + len);
[Severity: High]
Does this length calculation cause an out-of-bounds DMA read?
The callers (ra8875_clear_screen() and ra8875_fb_dirty()) already account for the 1-byte command header when calculating the len argument. For example, they pass '1 + rows * width * 2'. This double-addition appears to cause the requested SPI transfer size to be 1 byte larger than intended, which can exceed the fixed heap allocation of txbuf.
Quoted 5 lines
drivers/gpu/drm/tiny/ra8875.c new file +5
-0+} + +static int ra8875_hw_init (struct ra8875_device *ra8875, +struct drm_display_mode *mode) +{
drivers/gpu/drm/tiny/ra8875.c line 194
Quoted 10 lines
drivers/gpu/drm/tiny/ra8875.c new file +10
-0+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]
Can these sleeping functions be called safely here?
This hardware initialization routine is invoked by ra8875_crtc_atomic_enable(), which runs in atomic context. Calling msleep(), usleep_range(), or gpiod_set_value_cansleep() in an atomic context causes kernel warnings and potential deadlocks. Note that synchronous spi_write() is also used throughout these atomic callbacks, which similarly sleeps.
[ ... ]
Quoted 8 lines
drivers/gpu/drm/tiny/ra8875.c new file +8
-0+static int ra8875_clear_screen (struct ra8875_device *ra8875, +struct drm_display_mode *mode) +{ +int width = mode->hdisplay; +int height = mode->vdisplay; +int y, rows, ret; +u8 *txbuf = ra8875->txbuf; +int rows_per_chunk =RA8875_TXBUF_ROWS ;
[ ... ]
drivers/gpu/drm/tiny/ra8875.c line 364
Quoted 5 lines
drivers/gpu/drm/tiny/ra8875.c new file +5
-0+ ret =ra8875_write_reg (ra8875,RA8875_CURV1 ,0 ); +if (ret) +return ret; + +memset (txbuf,0 ,1 + rows_per_chunk * width *2 );
[Severity: High]
Does this risk a heap buffer overflow?
The width parameter is derived from mode->hdisplay. Since ra8875_mode_valid() does not restrict the maximum width, a maliciously large hdisplay (e.g., 1600) could cause this memset to exceed the fixed txbuf allocation bounds and corrupt kernel memory.
Quoted 9 lines
drivers/gpu/drm/tiny/ra8875.c new file +9
-0+ txbuf[0 ] =RA8875_DATAWRITE ; + +for (y =0 ; y < height; y += rows) { + rows =min (rows_per_chunk, height - y); +ra8875_write_pixels (ra8875,1 + rows * width *2 ); + } + +return 0 ; +}
[ ... ]
Quoted 3 lines
drivers/gpu/drm/tiny/ra8875.c new file +3
-0+static void ra8875_fb_dirty (struct ra8875_device *ra8875,struct iosys_map *src, +struct drm_framebuffer *fb,struct drm_rect *rect) +{
[ ... ]
drivers/gpu/drm/tiny/ra8875.c line 451
Quoted 10 lines
drivers/gpu/drm/tiny/ra8875.c new file +10
-0+for (int y = rect->y1; y < rect->y2; y += rows) { +struct drm_rect chunk; + + rows =min (RA8875_TXBUF_ROWS , rect->y2 - y); + chunk =DRM_RECT_INIT (rect->x1, y, width, rows); + +iosys_map_set_vaddr (&dst, ra8875->txbuf +1 ); +drm_fb_swab (&dst,NULL , src, fb, &chunk, false, &fmtcnv_state); + +ra8875_write_pixels (ra8875,1 + rows * width *2 );
[Severity: Low]
Is it intentional that the integer return value of ra8875_write_pixels() is ignored here?
If an SPI bus error occurs, the driver will blindly continue to iterate and attempt to write subsequent chunks, hiding the failure from the kernel log.
Quoted 4 lines
drivers/gpu/drm/tiny/ra8875.c new file +4
-0+ } + +drm_format_conv_state_release (&fmtcnv_state); +return ;
[ ... ]
Quoted 6 lines
drivers/gpu/drm/tiny/ra8875.c new file +6
-0+static void ra8875_plane_atomic_update (struct drm_plane *plane,struct drm_atomic_commit *state) +{ + struct ra8875_device *ra8875 = container_of(plane->dev, struct ra8875_device, drm); +struct drm_plane_state *old_plane_state =drm_atomic_get_old_plane_state (state, plane); +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);
drivers/gpu/drm/tiny/ra8875.c line 476
Quoted 10 lines
drivers/gpu/drm/tiny/ra8875.c new file +10
-0+struct drm_framebuffer *fb = plane_state->fb; +struct drm_rect rect; +struct iosys_map *map = &shadow_plane_state->data[0 ]; +int idx; + +if (!drm_dev_enter (&ra8875->drm, &idx)) +return ; + +if (iosys_map_is_null (map)) { +drm_err (&ra8875->drm,"Shadow map is null\n" );
[Severity: Low]
Will this unconditionally log a spurious error for standard plane disable operations?
Since the driver does not implement the atomic_disable hook, the core falls back to calling atomic_update() with a NULL framebuffer when disabling the plane.
Quoted 7 lines
drivers/gpu/drm/tiny/ra8875.c new file +7
-0+ goto exit; + } +if (drm_atomic_helper_damage_merged (old_plane_state, plane_state, &rect)) +ra8875_fb_dirty (ra8875, map, fb, &rect); +exit: +drm_dev_exit (idx); +}
Signature · 1 line
Sashiko AI review · https://sashiko.dev/#/patchset/[email protected]?part=2