Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

drm/mipi-dbi: Add support for DRM_FORMAT_RGB888

DRM_FORMAT_RGB888 is 24 bits per pixel and it would be natural to send it
on the SPI bus using a 24 bits per word transfer. The problem with this
is that not all SPI controllers support 24 bpw.

Since DRM_FORMAT_RGB888 is stored in memory as little endian and the SPI
bus is big endian we use 8 bpw to always get the same pixel format on the
bus: b8g8r8.

The MIPI DCS specification lists the standard commands that can be sent
over the MIPI DBI interface. The set_address_mode (36h) command has one
bit in the parameter that controls RGB/BGR order. This means that the
controller can be configured to receive the pixel as BGR.

RGB888 is rarely supported on these controllers but RGB666 is very common.
All datasheets I have seen do at least support the pixel format option
where each color is sent as one byte and the 6 MSB's are used.

All this put together means that we can send each pixel as b8g8r8 and an
RGB666 capable controller sees this as b6x2g6x2r6x2.

v4:
- s/emulation_format/pixel_format/ (Dmitry)

Reviewed-by: Dmitry Baryshkov <dmitry.baryshkov@linaro.org>
Link: https://patchwork.freedesktop.org/patch/msgid/20240604-panel-mipi-dbi-rgb666-v4-4-d7c2bcb9b78d@tronnes.org
Signed-off-by: Noralf Trønnes <noralf@tronnes.org>

+30 -4
+25 -4
drivers/gpu/drm/drm_mipi_dbi.c
··· 206 206 struct drm_rect *clip, bool swap, 207 207 struct drm_format_conv_state *fmtcnv_state) 208 208 { 209 + struct mipi_dbi_dev *dbidev = drm_to_mipi_dbi_dev(fb->dev); 209 210 struct drm_gem_object *gem = drm_gem_fb_get_obj(fb, 0); 210 211 struct iosys_map dst_map = IOSYS_MAP_INIT_VADDR(dst); 211 212 int ret; ··· 223 222 else 224 223 drm_fb_memcpy(&dst_map, NULL, src, fb, clip); 225 224 break; 225 + case DRM_FORMAT_RGB888: 226 + drm_fb_memcpy(&dst_map, NULL, src, fb, clip); 227 + break; 226 228 case DRM_FORMAT_XRGB8888: 227 - drm_fb_xrgb8888_to_rgb565(&dst_map, NULL, src, fb, clip, fmtcnv_state, swap); 229 + switch (dbidev->pixel_format) { 230 + case DRM_FORMAT_RGB565: 231 + drm_fb_xrgb8888_to_rgb565(&dst_map, NULL, src, fb, clip, fmtcnv_state, swap); 232 + break; 233 + case DRM_FORMAT_RGB888: 234 + drm_fb_xrgb8888_to_rgb888(&dst_map, NULL, src, fb, clip, fmtcnv_state); 235 + break; 236 + } 228 237 break; 229 238 default: 230 239 drm_err_once(fb->dev, "Format is not supported: %p4cc\n", ··· 271 260 struct mipi_dbi_dev *dbidev = drm_to_mipi_dbi_dev(fb->dev); 272 261 unsigned int height = rect->y2 - rect->y1; 273 262 unsigned int width = rect->x2 - rect->x1; 263 + const struct drm_format_info *dst_format; 274 264 struct mipi_dbi *dbi = &dbidev->dbi; 275 265 bool swap = dbi->swap_bytes; 276 266 int ret = 0; 267 + size_t len; 277 268 bool full; 278 269 void *tr; 279 270 ··· 296 283 mipi_dbi_set_window_address(dbidev, rect->x1, rect->x2 - 1, rect->y1, 297 284 rect->y2 - 1); 298 285 299 - ret = mipi_dbi_command_buf(dbi, MIPI_DCS_WRITE_MEMORY_START, tr, 300 - width * height * 2); 286 + if (fb->format->format == DRM_FORMAT_XRGB8888) 287 + dst_format = drm_format_info(dbidev->pixel_format); 288 + else 289 + dst_format = fb->format; 290 + len = drm_format_info_min_pitch(dst_format, 0, width) * height; 291 + 292 + ret = mipi_dbi_command_buf(dbi, MIPI_DCS_WRITE_MEMORY_START, tr, len); 301 293 err_msg: 302 294 if (ret) 303 295 drm_err_once(fb->dev, "Failed to update display %d\n", ret); ··· 590 572 * has one fixed &drm_display_mode which is rotated according to @rotation. 591 573 * This mode is used to set the mode config min/max width/height properties. 592 574 * 593 - * Use mipi_dbi_dev_init() if you don't need custom formats. 575 + * Use mipi_dbi_dev_init() if you want native RGB565 and emulated XRGB8888 format. 594 576 * 595 577 * Note: 596 578 * Some of the helper functions expects RGB565 to be the default format and the ··· 649 631 drm->mode_config.min_height = dbidev->mode.vdisplay; 650 632 drm->mode_config.max_height = dbidev->mode.vdisplay; 651 633 dbidev->rotation = rotation; 634 + dbidev->pixel_format = formats[0]; 635 + if (formats[0] == DRM_FORMAT_RGB888) 636 + dbidev->dbi.write_memory_bpw = 8; 652 637 653 638 DRM_DEBUG_KMS("rotation = %u\n", rotation); 654 639
+5
include/drm/drm_mipi_dbi.h
··· 102 102 struct drm_display_mode mode; 103 103 104 104 /** 105 + * @pixel_format: Native pixel format (DRM_FORMAT\_\*) 106 + */ 107 + u32 pixel_format; 108 + 109 + /** 105 110 * @tx_buf: Buffer used for transfer (copy clip rect area) 106 111 */ 107 112 u16 *tx_buf;