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

Reply via email to