When using a >8bpp framebuffer, offb advertises truecolor, not directcolor,
and doesn't touch the color map even if it has a corresponding access method
for the real hardware.

Thus it needs to set the pseudo-palette with all 3 components of the color,
like other truecolor framebuffers, not with copies of the color index like
a directcolor framebuffer would do.

This went unnoticed for a long time because it's pretty hard to get offb
to kick in with anything but 8bpp (old BootX under MacOS will do that and
qemu does it).

Signed-off-by: Benjamin Herrenschmidt <b...@kernel.crashing.org>
---

diff --git a/drivers/video/offb.c b/drivers/video/offb.c
index cb163a5..24e1fc6 100644
--- a/drivers/video/offb.c
+++ b/drivers/video/offb.c
@@ -100,36 +100,32 @@ static int offb_setcolreg(u_int regno, u_int red, u_int 
green, u_int blue,
                          u_int transp, struct fb_info *info)
 {
        struct offb_par *par = (struct offb_par *) info->par;
-       int i, depth;
-       u32 *pal = info->pseudo_palette;
-
-       depth = info->var.bits_per_pixel;
-       if (depth == 16)
-               depth = (info->var.green.length == 5) ? 15 : 16;
-
-       if (regno > 255 ||
-           (depth == 16 && regno > 63) ||
-           (depth == 15 && regno > 31))
-               return 1;
-
-       if (regno < 16) {
-               switch (depth) {
-               case 15:
-                       pal[regno] = (regno << 10) | (regno << 5) | regno;
-                       break;
-               case 16:
-                       pal[regno] = (regno << 11) | (regno << 5) | regno;
-                       break;
-               case 24:
-                       pal[regno] = (regno << 16) | (regno << 8) | regno;
-                       break;
-               case 32:
-                       i = (regno << 8) | regno;
-                       pal[regno] = (i << 16) | i;
-                       break;
+
+       if (info->fix.visual == FB_VISUAL_TRUECOLOR) {
+               u32 *pal = info->pseudo_palette;
+               u32 cr = red >> (16 - info->var.red.length);
+               u32 cg = green >> (16 - info->var.green.length);
+               u32 cb = blue >> (16 - info->var.blue.length);
+               u32 value;
+
+               if (regno >= 16)
+                       return -EINVAL;
+
+               value = (cr << info->var.red.offset) |
+                       (cg << info->var.green.offset) |
+                       (cb << info->var.blue.offset);
+               if (info->var.transp.length > 0) {
+                       u32 mask = (1 << info->var.transp.length) - 1;
+                       mask <<= info->var.transp.offset;
+                       value |= mask;
                }
+               pal[regno] = value;
+               return 0;
        }
 
+       if (regno > 255)
+               return -EINVAL;
+
        red >>= 8;
        green >>= 8;
        blue >>= 8;


_______________________________________________
Linuxppc-dev mailing list
Linuxppc-dev@lists.ozlabs.org
https://lists.ozlabs.org/listinfo/linuxppc-dev

Reply via email to