From: LiangCheng Wang <[email protected]> Some panels have their first column wired to the controller's last source output, so the controller scans RAM X in the opposite direction and the image comes out horizontally mirrored. SSD1677 offers no source-direction control that I could find - command 0x01 only affects the gate side - so it has to be handled while packing the framebuffer.
Add an x_mirror flag to struct ssd16xx_device_config and honour it in both branches of ssd16xx_convert_fb_to_1bpp(): the scanline order in the landscape path, and the inner loop in the portrait one, which is what maps to RAM X there. The DRM_FORMAT_R1 memcpy fast path cannot mirror while copying, so it is skipped when the flag is set. Enable it for the pixpaper-426m entry. Tested on a Mayqueen PIXPAPER 4.26m (SSD1677, 800x480): a pattern with four differently sized corner blocks renders correctly at rotation 0, and a DT rotation of 90 gives a clean clockwise portrait. Doing only the landscape path leaves the portrait output transposed. Signed-off-by: LiangCheng Wang <[email protected]> Signed-off-by: Devarsh Thakkar <[email protected]> --- Changes from v1: - New patch introduced to prepare base for pixpaper drivers/gpu/drm/solomon/ssd16xx.c | 22 ++++++++++++++++------ 1 file changed, 16 insertions(+), 6 deletions(-) diff --git a/drivers/gpu/drm/solomon/ssd16xx.c b/drivers/gpu/drm/solomon/ssd16xx.c index 6331f367d864..8fe09dca589e 100644 --- a/drivers/gpu/drm/solomon/ssd16xx.c +++ b/drivers/gpu/drm/solomon/ssd16xx.c @@ -358,6 +358,9 @@ struct ssd16xx_device_config { const u8 *booster_soft_start_data; u8 booster_soft_start_len; + /* Controller scans this panel's RAM X in the reverse direction. */ + bool x_mirror; + /* Panel-specific display mode (resolution and physical dimensions) */ const struct drm_display_mode *mode; }; @@ -513,6 +516,7 @@ static const struct ssd16xx_device_config ssd16xx_device_configs[] = { .default_clear_on_disable = -1, .default_refresh_mode_init = SSD16XX_REFRESH_FULL, .red_supported = false, /* 2-colour black/white panel */ + .x_mirror = false, .default_color_mode = SSD16XX_COLOR_MODE_BW, .mode = &gdey042t81_mode, }, @@ -1121,10 +1125,11 @@ static void ssd16xx_convert_fb_to_3color(u8 *bw_dst, u8 *red_dst, static void ssd16xx_convert_fb_to_1bpp(u8 *dst, struct iosys_map *src, struct drm_framebuffer *fb, struct drm_rect *rect, - unsigned int orientation) + unsigned int orientation, + bool x_mirror) { u32 format = fb->format->format; - int x, y; + int x, y, i; u8 byte = 0; unsigned int bit_pos = 0; unsigned int dst_idx = 0; @@ -1146,7 +1151,8 @@ static void ssd16xx_convert_fb_to_1bpp(u8 *dst, struct iosys_map *src, * if not, the generic pixel-by-pixel loop below handles non-aligned * rects safely. */ - if (format == DRM_FORMAT_R1 && orientation == 0 && rect->x1 % 8 == 0) { + if (format == DRM_FORMAT_R1 && orientation == 0 && rect->x1 % 8 == 0 && + !x_mirror) { unsigned int src_pitch = fb->pitches[0]; unsigned int width_bytes = drm_rect_width(rect) / 8; @@ -1168,7 +1174,8 @@ static void ssd16xx_convert_fb_to_1bpp(u8 *dst, struct iosys_map *src, * The data entry mode and cursor position control scan direction. */ for (x = rect->x2 - 1; x >= (int)rect->x1; x--) { - for (y = rect->y1; y < rect->y2; y++) { + for (i = 0; i < drm_rect_height(rect); i++) { + y = x_mirror ? rect->y2 - 1 - i : rect->y1 + i; if (ssd16xx_pixel_is_white(src, fb, x, y)) byte |= (1 << (7 - bit_pos)); if (++bit_pos == 8) { @@ -1194,7 +1201,8 @@ static void ssd16xx_convert_fb_to_1bpp(u8 *dst, struct iosys_map *src, * The data entry mode and cursor position control scan direction. */ for (y = rect->y1; y < rect->y2; y++) { - for (x = rect->x1; x < rect->x2; x++) { + for (i = 0; i < drm_rect_width(rect); i++) { + x = x_mirror ? rect->x2 - 1 - i : rect->x1 + i; if (ssd16xx_pixel_is_white(src, fb, x, y)) byte |= (1 << (7 - bit_pos)); if (++bit_pos == 8) { @@ -1267,7 +1275,9 @@ static int ssd16xx_fb_dirty(struct drm_framebuffer *fb, struct drm_rect *rect, if (red_buffer) ssd16xx_convert_fb_to_3color(mono_buffer, red_buffer, &map, fb, rect); else - ssd16xx_convert_fb_to_1bpp(mono_buffer, &map, fb, rect, device->orientation); + ssd16xx_convert_fb_to_1bpp(mono_buffer, &map, fb, rect, + device->orientation, + device->device_cfg->x_mirror); drm_dbg(&device->drm, "fb_dirty: mono[0..3]=0x%02x 0x%02x 0x%02x 0x%02x (data_size=%u)\n", -- 2.39.1
