[PATCH 2/3] drm/tiny: ssd16xx: support panels whose RAM X order is reversed

LiangCheng Wang <[email protected]>
Newsgroups org.freedesktop.lists.dri-devel,org.kernel.vger.linux-kernel
Message-ID <[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]>
---
 drivers/gpu/drm/tiny/ssd16xx.c | 22 ++++++++++++++++------
 1 file changed, 16 insertions(+), 6 deletions(-)

diff --git a/drivers/gpu/drm/tiny/ssd16xx.c b/drivers/gpu/drm/tiny/ssd16xx.c
index 02a28c0e07085e35d5210b6e20c214b163ede88f..d311720bbfbe0dd288dbd588be02c79b5eab3eab 100644
--- a/drivers/gpu/drm/tiny/ssd16xx.c
+++ b/drivers/gpu/drm/tiny/ssd16xx.c
@@ -380,6 +380,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;
 };
@@ -584,6 +587,7 @@ static const struct ssd16xx_device_config ssd16xx_device_configs[] = {
 		.default_refresh_mode_init = SSD16XX_REFRESH_FULL,
 		.red_supported     = false,
 		.default_color_mode = SSD16XX_COLOR_MODE_BW,
+		.x_mirror          = true,
 		.booster_soft_start_data = pixpaper426m_booster_soft_start,
 		.booster_soft_start_len  = ARRAY_SIZE(pixpaper426m_booster_soft_start),
 		.mode = &pixpaper426m_mode,
@@ -1199,10 +1203,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;
@@ -1224,7 +1229,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;
 
@@ -1246,7 +1252,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) {
@@ -1272,7 +1279,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) {
@@ -1345,7 +1353,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.34.1
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.