add 24bpp support

Now that cirrusdrmfb is enabled in QEMU /dev/fb0 exists
and ply-image runs and fails. Cirrus VGA has 24bpp pixels and
ply-image so far only supported 16bpp and 32bpp. This commit
adds support for 24bpp framebuffers. It also adds cirrus
device to KMS list.

BUG=chromium:289439
TEST=run smoke test

Change-Id: I0115021a17ce39c29316d453ab52a705084268e8
Signed-off-by: Dominik Behr <dbehr@chromium.org>
Reviewed-on: https://chromium-review.googlesource.com/169016
Reviewed-by: Stéphane Marchesin <marcheu@chromium.org>
diff --git a/src/ply-frame-buffer.c b/src/ply-frame-buffer.c
index 5be9fff..6fbb163 100644
--- a/src/ply-frame-buffer.c
+++ b/src/ply-frame-buffer.c
@@ -524,42 +524,64 @@
    * 3) In all other cases we copy line by line.
    */
   if (buffer->bytes_per_pixel != sizeof(*data)) {
-    uint16_t *src_16 = 0, *src_16_end;
     int line;
 
-    /* Handle the 16 bpp case (specifically RGB 565 case) */
-    if (buffer->bytes_per_pixel != 2)
-      return false;
+    if (buffer->bytes_per_pixel == 2) {
+      uint16_t *src_16 = 0, *src_16_end;
 
-    /* Allocate temporary row pixel data storage for 16 bpp displays */
-    src_16 = (uint16_t *) malloc(width * sizeof(*src_16));
+      /* Allocate temporary row pixel data storage for 16 bpp displays */
+      src_16 = (uint16_t *) malloc(width * sizeof(*src_16));
 
-    if (!src_16)
-      return false;
+      if (!src_16)
+        return false;
 
-    src_16_end = src_16 + width;
+      src_16_end = src_16 + width;
 
-    for (line = 0; line < lines; line++) {
-      const uint32_t *src_32_temp;
-      uint16_t *src_16_temp;
+      for (line = 0; line < lines; line++) {
+        const uint32_t *src_32_temp;
+        uint16_t *src_16_temp;
 
-      for (src_32_temp = src, src_16_temp = src_16;
-           src_16_temp != src_16_end;
-           src_16_temp++) {
-        uint32_t src_32_value = *src_32_temp++;
-        *src_16_temp = (uint16_t)(
-            ((src_32_value & 0x00F80000) >> 8) |
-            ((src_32_value & 0x0000FC00) >> 5) |
-            ((src_32_value & 0x000000F8) >> 3)
-          );
+        for (src_32_temp = src, src_16_temp = src_16;
+             src_16_temp != src_16_end;
+             src_16_temp++) {
+          uint32_t src_32_value = *src_32_temp++;
+          *src_16_temp = (uint16_t)(
+              ((src_32_value & 0x00F80000) >> 8) |
+              ((src_32_value & 0x0000FC00) >> 5) |
+              ((src_32_value & 0x000000F8) >> 3)
+            );
+        }
+        memcpy(dst, src_16, width * buffer->bytes_per_pixel);
+
+        dst += buffer->row_stride * buffer->bytes_per_pixel;
+        src += area->width;
       }
-      memcpy(dst, src_16, width * buffer->bytes_per_pixel);
 
-      dst += buffer->row_stride * buffer->bytes_per_pixel;
-      src += area->width;
+      free(src_16);
+    } else if (buffer->bytes_per_pixel == 3) {
+      uint8_t *src_8 = (uint8_t *) malloc(width * sizeof(uint8_t) * 3);
+
+      if (!src_8)
+        return false;
+
+      for (line = 0; line < lines; line++) {
+        int col;
+        uint8_t *s = src_8;
+        for (col = 0; col < width; col++) {
+          *s++ = (uint8_t)(src[col] & 0xFF); // blue
+          *s++ = (uint8_t)((src[col] >> 8) & 0xFF); // green
+          *s++ = (uint8_t)((src[col] >> 16) & 0xFF); // red
+        }
+
+        memcpy(dst, src_8, width * buffer->bytes_per_pixel);
+
+        dst += buffer->row_stride * buffer->bytes_per_pixel;
+        src += area->width;
+      }
+      free(src_8);
+    } else {
+      return false;
     }
-
-    free(src_16);
   } else if (width == area->width && width == buffer->row_stride) {
     memcpy(dst, src, width * lines * sizeof(*data));
   } else {
@@ -606,6 +628,22 @@
       }
       break;
     }
+    case 3: {
+      uint8_t* ptr = (uint8_t*) buffer->map_address;
+      uint8_t* curr_ptr;
+      uint8_t b0 = (uint8_t)(fb_clear_color & 0xFF);
+      uint8_t b1 = (uint8_t)((fb_clear_color >> 8) & 0xFF);
+      uint8_t b2 = (uint8_t)((fb_clear_color >> 16) & 0xFF);
+      for (j = 0; j < fb_height; j++) {
+        curr_ptr = ptr + j * fb_stride * 3;
+        for (i = 0; i < fb_width; i++) {
+          *curr_ptr++ = b0;
+          *curr_ptr++ = b1;
+          *curr_ptr++ = b2;
+        }
+      }
+      break;
+    }
     case 2: {
       uint16_t* ptr = (uint16_t*) buffer->map_address;
       uint16_t* curr_ptr;
diff --git a/src/ply-kms.c b/src/ply-kms.c
index 809514d..855dfbd 100644
--- a/src/ply-kms.c
+++ b/src/ply-kms.c
@@ -26,7 +26,7 @@
 #include "ply-utils.h"
 
 int ply_kms_open() {
-  const char *kModuleList[] = { "i915", "exynos" };
+  const char *kModuleList[] = { "i915", "exynos", "cirrus" };
   int fd = -1;
   int i;