diff options
Diffstat (limited to 'drivers/gpu/drm/drm_mipi_dbi.c')
-rw-r--r-- | drivers/gpu/drm/drm_mipi_dbi.c | 77 |
1 files changed, 54 insertions, 23 deletions
diff --git a/drivers/gpu/drm/drm_mipi_dbi.c b/drivers/gpu/drm/drm_mipi_dbi.c index daac649aabdb..34bca7567576 100644 --- a/drivers/gpu/drm/drm_mipi_dbi.c +++ b/drivers/gpu/drm/drm_mipi_dbi.c @@ -206,6 +206,7 @@ int mipi_dbi_buf_copy(void *dst, struct iosys_map *src, struct drm_framebuffer * struct drm_rect *clip, bool swap, struct drm_format_conv_state *fmtcnv_state) { + struct mipi_dbi_dev *dbidev = drm_to_mipi_dbi_dev(fb->dev); struct drm_gem_object *gem = drm_gem_fb_get_obj(fb, 0); struct iosys_map dst_map = IOSYS_MAP_INIT_VADDR(dst); int ret; @@ -222,8 +223,18 @@ int mipi_dbi_buf_copy(void *dst, struct iosys_map *src, struct drm_framebuffer * else drm_fb_memcpy(&dst_map, NULL, src, fb, clip); break; + case DRM_FORMAT_RGB888: + drm_fb_memcpy(&dst_map, NULL, src, fb, clip); + break; case DRM_FORMAT_XRGB8888: - drm_fb_xrgb8888_to_rgb565(&dst_map, NULL, src, fb, clip, fmtcnv_state, swap); + switch (dbidev->pixel_format) { + case DRM_FORMAT_RGB565: + drm_fb_xrgb8888_to_rgb565(&dst_map, NULL, src, fb, clip, fmtcnv_state, swap); + break; + case DRM_FORMAT_RGB888: + drm_fb_xrgb8888_to_rgb888(&dst_map, NULL, src, fb, clip, fmtcnv_state); + break; + } break; default: drm_err_once(fb->dev, "Format is not supported: %p4cc\n", @@ -260,9 +271,11 @@ static void mipi_dbi_fb_dirty(struct iosys_map *src, struct drm_framebuffer *fb, struct mipi_dbi_dev *dbidev = drm_to_mipi_dbi_dev(fb->dev); unsigned int height = rect->y2 - rect->y1; unsigned int width = rect->x2 - rect->x1; + const struct drm_format_info *dst_format; struct mipi_dbi *dbi = &dbidev->dbi; bool swap = dbi->swap_bytes; int ret = 0; + size_t len; bool full; void *tr; @@ -283,8 +296,13 @@ static void mipi_dbi_fb_dirty(struct iosys_map *src, struct drm_framebuffer *fb, mipi_dbi_set_window_address(dbidev, rect->x1, rect->x2 - 1, rect->y1, rect->y2 - 1); - ret = mipi_dbi_command_buf(dbi, MIPI_DCS_WRITE_MEMORY_START, tr, - width * height * 2); + if (fb->format->format == DRM_FORMAT_XRGB8888) + dst_format = drm_format_info(dbidev->pixel_format); + else + dst_format = fb->format; + len = drm_format_info_min_pitch(dst_format, 0, width) * height; + + ret = mipi_dbi_command_buf(dbi, MIPI_DCS_WRITE_MEMORY_START, tr, len); err_msg: if (ret) drm_err_once(fb->dev, "Failed to update display %d\n", ret); @@ -572,7 +590,7 @@ static const uint32_t mipi_dbi_formats[] = { * has one fixed &drm_display_mode which is rotated according to @rotation. * This mode is used to set the mode config min/max width/height properties. * - * Use mipi_dbi_dev_init() if you don't need custom formats. + * Use mipi_dbi_dev_init() if you want native RGB565 and emulated XRGB8888 format. * * Note: * Some of the helper functions expects RGB565 to be the default format and the @@ -631,6 +649,9 @@ int mipi_dbi_dev_init_with_formats(struct mipi_dbi_dev *dbidev, drm->mode_config.min_height = dbidev->mode.vdisplay; drm->mode_config.max_height = dbidev->mode.vdisplay; dbidev->rotation = rotation; + dbidev->pixel_format = formats[0]; + if (formats[0] == DRM_FORMAT_RGB888) + dbidev->dbi.write_memory_bpw = 8; DRM_DEBUG_KMS("rotation = %u\n", rotation); @@ -824,15 +845,6 @@ u32 mipi_dbi_spi_cmd_max_speed(struct spi_device *spi, size_t len) } EXPORT_SYMBOL(mipi_dbi_spi_cmd_max_speed); -static bool mipi_dbi_machine_little_endian(void) -{ -#if defined(__LITTLE_ENDIAN) - return true; -#else - return false; -#endif -} - /* * MIPI DBI Type C Option 1 * @@ -855,7 +867,7 @@ static int mipi_dbi_spi1e_transfer(struct mipi_dbi *dbi, int dc, const void *buf, size_t len, unsigned int bpw) { - bool swap_bytes = (bpw == 16 && mipi_dbi_machine_little_endian()); + bool swap_bytes = (bpw == 16); size_t chunk, max_chunk = dbi->tx_buf9_len; struct spi_device *spi = dbi->spi; struct spi_transfer tr = { @@ -1004,7 +1016,7 @@ static int mipi_dbi_spi1_transfer(struct mipi_dbi *dbi, int dc, size_t chunk = min(len, max_chunk); unsigned int i; - if (bpw == 16 && mipi_dbi_machine_little_endian()) { + if (bpw == 16) { for (i = 0; i < (chunk * 2); i += 2) { dst16[i] = *src16 >> 8; dst16[i + 1] = *src16++ & 0xFF; @@ -1088,7 +1100,7 @@ static int mipi_dbi_typec1_command_read(struct mipi_dbi *dbi, u8 *cmd, static int mipi_dbi_typec1_command(struct mipi_dbi *dbi, u8 *cmd, u8 *parameters, size_t num) { - unsigned int bpw = (*cmd == MIPI_DCS_WRITE_MEMORY_START) ? 16 : 8; + unsigned int bpw = 8; int ret; if (mipi_dbi_command_is_read(dbi, *cmd)) @@ -1100,6 +1112,9 @@ static int mipi_dbi_typec1_command(struct mipi_dbi *dbi, u8 *cmd, if (ret || !num) return ret; + if (*cmd == MIPI_DCS_WRITE_MEMORY_START) + bpw = dbi->write_memory_bpw; + return mipi_dbi_spi1_transfer(dbi, 1, parameters, num, bpw); } @@ -1193,8 +1208,8 @@ static int mipi_dbi_typec3_command(struct mipi_dbi *dbi, u8 *cmd, if (ret || !num) return ret; - if (*cmd == MIPI_DCS_WRITE_MEMORY_START && !dbi->swap_bytes) - bpw = 16; + if (*cmd == MIPI_DCS_WRITE_MEMORY_START) + bpw = dbi->write_memory_bpw; spi_bus_lock(spi->controller); gpiod_set_value_cansleep(dbi->dc, 1); @@ -1218,11 +1233,23 @@ static int mipi_dbi_typec3_command(struct mipi_dbi *dbi, u8 *cmd, * If @dc is set, a Type C Option 3 interface is assumed, if not * Type C Option 1. * - * If the SPI master driver doesn't support the necessary bits per word, - * the following transformation is used: + * If the command is %MIPI_DCS_WRITE_MEMORY_START and the pixel format is RGB565, endianness has + * to be taken into account. The MIPI DBI serial interface is big endian and framebuffers are + * assumed stored in memory as little endian (%DRM_FORMAT_BIG_ENDIAN is not supported). * - * - 9-bit: reorder buffer as 9x 8-bit words, padded with no-op command. - * - 16-bit: if big endian send as 8-bit, if little endian swap bytes + * This is how endianness is handled: + * + * Option 1 (D/C as a bit): The buffer is sent on the wire byte by byte so the 16-bit buffer is + * byteswapped before transfer. + * + * Option 3 (D/C as a gpio): If the SPI controller supports 16 bits per word the buffer can be + * sent as-is. If not the caller is responsible for swapping the bytes + * before calling mipi_dbi_command_buf() and the buffer is sent 8 bpw. + * + * This handling is optimised for %DRM_FORMAT_RGB565 framebuffers. + * + * If the interface is Option 1 and the SPI controller doesn't support 9 bits per word, + * the buffer is sent as 9x 8-bit words, padded with MIPI DCS no-op commands if necessary. * * Returns: * Zero on success, negative error code on failure. @@ -1253,12 +1280,15 @@ int mipi_dbi_spi_init(struct spi_device *spi, struct mipi_dbi *dbi, dbi->spi = spi; dbi->read_commands = mipi_dbi_dcs_read_commands; + dbi->write_memory_bpw = 16; if (dc) { dbi->command = mipi_dbi_typec3_command; dbi->dc = dc; - if (mipi_dbi_machine_little_endian() && !spi_is_bpw_supported(spi, 16)) + if (!spi_is_bpw_supported(spi, 16)) { + dbi->write_memory_bpw = 8; dbi->swap_bytes = true; + } } else { dbi->command = mipi_dbi_typec1_command; dbi->tx_buf9_len = SZ_16K; @@ -1475,4 +1505,5 @@ EXPORT_SYMBOL(mipi_dbi_debugfs_init); #endif +MODULE_DESCRIPTION("MIPI Display Bus Interface (DBI) LCD controller support"); MODULE_LICENSE("GPL"); |