Index: linux-2.6.21gum/drivers/video/pxafb.c =================================================================== --- linux-2.6.21gum.orig/drivers/video/pxafb.c +++ linux-2.6.21gum/drivers/video/pxafb.c @@ -191,6 +191,10 @@ static int pxafb_bpp_to_lccr3(struct fb_ case 4: ret = LCCR3_4BPP; break; case 8: ret = LCCR3_8BPP; break; case 16: ret = LCCR3_16BPP; break; + case 18: ret = (var->nonstd == 24 ? LCCR3_18BPP_PACKED : LCCR3_18BPP); break; + case 19: ret = (var->nonstd == 24 ? LCCR3_19BPP_PACKED : LCCR3_19BPP); break; + case 24: ret = LCCR3_24BPP; break; + case 25: ret = LCCR3_25BPP; break; } return ret; } @@ -204,11 +208,12 @@ static int pxafb_bpp_to_lccr3(struct fb_ */ static unsigned int pxafb_display_dma_period(struct fb_var_screeninfo *var) { - /* - * Period = pixclock * bits_per_byte * bytes_per_transfer - * / memory_bits_per_pixel; - */ - return var->pixclock * 8 * 16 / var->bits_per_pixel; + /* + * Period = pixclock * bits_per_byte * bytes_per_transfer + * / memory_bits_per_pixel; + */ + struct pxafb_mach_info *inf = fbi->dev->platform_data; + return var->pixclock * 8 * 16 / (var->nonstd ? var->nonstd : var->bits_per_pixel); } extern unsigned int get_clk_frequency_khz(int info); @@ -307,6 +312,26 @@ static int pxafb_check_var(struct fb_var var->green.offset = 5; var->green.length = 6; var->blue.offset = 0; var->blue.length = 5; var->transp.offset = var->transp.length = 0; + } else if (var->bits_per_pixel == 18) { + var->transp.offset = var->transp.length = 0; + var->red.offset = 12; var->red.length=6; + var->green.offset = 6; var->green.length=6; + var->blue.offset = 0; var->blue.length=6; + } else if (var->bits_per_pixel == 19) { + var->transp.offset = 18; var->transp.length = 1; + var->red.offset = 12; var->red.length=6; + var->green.offset = 6; var->green.length=6; + var->blue.offset = 0; var->blue.length=6; + } else if (var->bits_per_pixel == 24) { + var->transp.offset = var->transp.length = 0; + var->red.offset = 16; var->red.length=8; + var->green.offset = 8; var->green.length=8; + var->blue.offset = 0; var->blue.length=8; + } else if (var->bits_per_pixel == 25) { + var->transp.offset = 18; var->transp.length = 1; + var->red.offset = 16; var->red.length=8; + var->green.offset = 8; var->green.length=8; + var->blue.offset = 0; var->blue.length=8; } else { var->red.offset = var->green.offset = var->blue.offset = var->transp.offset = 0; var->red.length = 8; @@ -342,7 +367,7 @@ static int pxafb_set_par(struct fb_info pr_debug("pxafb: set_par\n"); - if (var->bits_per_pixel == 16) + if (var->bits_per_pixel >= 16) fbi->fb.fix.visual = FB_VISUAL_TRUECOLOR; else if (!fbi->cmap_static) fbi->fb.fix.visual = FB_VISUAL_PSEUDOCOLOR; @@ -355,9 +380,10 @@ static int pxafb_set_par(struct fb_info fbi->fb.fix.visual = FB_VISUAL_STATIC_PSEUDOCOLOR; } - fbi->fb.fix.line_length = var->xres_virtual * - var->bits_per_pixel / 8; - if (var->bits_per_pixel == 16) + fbi->fb.fix.line_length = var->xres_virtual * + (var->nonstd ? var->nonstd : var->bits_per_pixel) / 8; + + if (var->bits_per_pixel >= 16) fbi->palette_size = 0; else fbi->palette_size = var->bits_per_pixel == 1 ? 4 : 1 << var->bits_per_pixel; @@ -374,7 +400,7 @@ static int pxafb_set_par(struct fb_info */ pxafb_set_truecolor(fbi->fb.fix.visual == FB_VISUAL_TRUECOLOR); - if (fbi->fb.var.bits_per_pixel == 16) + if (fbi->fb.var.bits_per_pixel >= 16) fb_dealloc_cmap(&fbi->fb.cmap); else fb_alloc_cmap(&fbi->fb.cmap, 1<fb.var.bits_per_pixel, 0); @@ -584,6 +610,14 @@ static int pxafb_activate_var(struct fb_ case 8: case 16: break; + case 18: + case 19: + case 24: + case 25: + if(var->nonstd) break; + printk(KERN_ERR "%s: must specify nonstd when bit depth==%d\n", + fbi->fb.fix.id, var->bits_per_pixel); + break; default: printk(KERN_ERR "%s: invalid bit depth %d\n", fbi->fb.fix.id, var->bits_per_pixel); @@ -679,7 +713,7 @@ static int pxafb_activate_var(struct fb_ fbi->dmadesc_palette_cpu->fidr = 0; fbi->dmadesc_palette_cpu->ldcmd = (fbi->palette_size * 2) | LDCMD_PAL; - if (var->bits_per_pixel == 16) { + if (var->bits_per_pixel >= 16) { /* palette shouldn't be loaded in true-color mode */ fbi->dmadesc_fbhigh_cpu->fdadr = fbi->dmadesc_fbhigh_dma; fbi->fdadr0 = fbi->dmadesc_fbhigh_dma; /* no pal just fbhigh */ @@ -1135,7 +1169,7 @@ static struct pxafb_info * __init pxafb_ fbi->fb.fix.ywrapstep = 0; fbi->fb.fix.accel = FB_ACCEL_NONE; - fbi->fb.var.nonstd = 0; + fbi->fb.var.nonstd = mode->nonstd; fbi->fb.var.activate = FB_ACTIVATE_NOW; fbi->fb.var.height = -1; fbi->fb.var.width = -1; @@ -1161,7 +1195,7 @@ static struct pxafb_info * __init pxafb_ fbi->task_state = (u_char)-1; for (i = 0; i < inf->num_modes; i++) { - smemlen = mode[i].xres * mode[i].yres * mode[i].bpp / 8; + smemlen = mode[i].xres * mode[i].yres * (mode[i].nonstd ? mode[i].nonstd : mode[i].bpp) / 8; if (smemlen > fbi->fb.fix.smem_len) fbi->fb.fix.smem_len = smemlen; } @@ -1189,12 +1223,19 @@ static int __init pxafb_parse_options(st if (!strncmp(this_opt, "mode:", 5)) { const char *name = this_opt+5; unsigned int namelen = strlen(name); - int res_specified = 0, bpp_specified = 0; - unsigned int xres = 0, yres = 0, bpp = 0; + int res_specified = 0, bpp_specified = 0, nonstd_specified = 0; + unsigned int xres = 0, yres = 0, bpp = 0, nonstd = 0; int yres_specified = 0; int i; for (i = namelen-1; i >= 0; i--) { switch (name[i]) { + case '/': + if (!nonstd_specified) { + nonstd = simple_strtoul(&name[i+1], NULL, 0); + nonstd_specified = 1; + } else + goto done; + break; case '-': namelen = i; if (!bpp_specified && !yres_specified) { @@ -1227,12 +1268,29 @@ static int __init pxafb_parse_options(st } if (bpp_specified) switch (bpp) { + case 18: + case 19: + case 24: + case 25: + if(nonstd_specified && (((bpp == 18 || bpp == 19) && nonstd == 24) || nonstd == 32)) + { + inf->modes[0].nonstd = nonstd; + dev_info(dev, "overriding nonstd pixel packing: %d\n",nonstd); + } else { + dev_err(dev, "Depth %d requires nonstd to be specified\n",bpp); + break; + } case 1: case 2: case 4: case 8: case 16: inf->modes[0].bpp = bpp; + if(nonstd_specified) { + dev_err(dev, "Depth %d requires nonstd to *not* be specified\n",bpp); + } else { + inf->modes[0].nonstd = 0; + } dev_info(dev, "overriding bit depth: %d\n", bpp); break; default: Index: linux-2.6.21gum/include/asm-arm/arch-pxa/pxa-regs.h =================================================================== --- linux-2.6.21gum.orig/include/asm-arm/arch-pxa/pxa-regs.h +++ linux-2.6.21gum/include/asm-arm/arch-pxa/pxa-regs.h @@ -1878,6 +1878,12 @@ #define LCCR3_4BPP (2 << 24) #define LCCR3_8BPP (3 << 24) #define LCCR3_16BPP (4 << 24) +#define LCCR3_18BPP (5 << 24) +#define LCCR3_18BPP_PACKED (6 << 24) +#define LCCR3_19BPP (7 << 24) +#define LCCR3_19BPP_PACKED (1 << 29) +#define LCCR3_24BPP ((1 << 29) | (1 << 24)) +#define LCCR3_25BPP ((1 << 29) | (2 << 24)) #define FDADR0 __REG(0x44000200) /* DMA Channel 0 Frame Descriptor Address Register */ #define FSADR0 __REG(0x44000204) /* DMA Channel 0 Frame Source Address Register */ Index: linux-2.6.21gum/include/asm-arm/arch-pxa/pxafb.h =================================================================== --- linux-2.6.21gum.orig/include/asm-arm/arch-pxa/pxafb.h +++ linux-2.6.21gum/include/asm-arm/arch-pxa/pxafb.h @@ -25,6 +25,7 @@ struct pxafb_mode_info { u_short xres; u_short yres; + /* bpp is the path-to-screen bits per pixel, not the in-memory storage required */ u_char bpp; u_char hsync_len; u_char left_margin; @@ -36,7 +37,9 @@ struct pxafb_mode_info { u_char sync; u_int cmap_greyscale:1, - unused:31; + nonstd:8, /* nonstd represents the in-memory bits per pixel + ie 24 or 32 for 18/19bpp mode, or 32 for 24/25bpp mode */ + unused:23; }; struct pxafb_mach_info { Index: linux-2.6.21gum/arch/arm/mach-pxa/gumstix.c =================================================================== --- linux-2.6.21gum.orig/arch/arm/mach-pxa/gumstix.c +++ linux-2.6.21gum/arch/arm/mach-pxa/gumstix.c @@ -116,7 +116,8 @@ static struct pxafb_mode_info gumstix_fb .pixclock = 110000, .xres = 480, .yres = 272, - .bpp = 16, + .bpp = 18, + .nonstd = 24, .hsync_len = 41, .left_margin = 2, .right_margin = 2, @@ -144,7 +145,8 @@ static struct pxafb_mode_info gumstix_fb .vsync_len = 10, // VLW from datasheet: 10 typ .upper_margin = 2, // VBP - VLW from datasheet: 12 - 10 = 2 .lower_margin = 4, // VFP from datasheet: 4 typ - .bpp = 16, + .bpp = 18, + .nonstd = 24, .sync = 0, // Hsync and Vsync both active low }; Index: linux-2.6.21gum/drivers/video/cfbfillrect.c =================================================================== --- linux-2.6.21gum.orig/drivers/video/cfbfillrect.c +++ linux-2.6.21gum/drivers/video/cfbfillrect.c @@ -62,7 +62,10 @@ pixel_to_pat( u32 bpp, u32 pixel) return 0x0001001001001001ul*pixel; case 16: return 0x0001000100010001ul*pixel; + case 18: + case 19: case 24: + case 25: return 0x0000000001000001ul*pixel; case 32: return 0x0000000100000001ul*pixel; @@ -87,7 +90,10 @@ pixel_to_pat( u32 bpp, u32 pixel) return 0x00001001ul*pixel; case 16: return 0x00010001ul*pixel; + case 18: + case 19: case 24: + case 25: return 0x00000001ul*pixel; case 32: return 0x00000001ul*pixel; @@ -346,7 +352,7 @@ void cfb_fillrect(struct fb_info *p, con unsigned long pat, fg; unsigned long width = rect->width, height = rect->height; int bits = BITS_PER_LONG, bytes = bits >> 3; - u32 bpp = p->var.bits_per_pixel; + u32 bpp = (p->var.nonstd ? p->var.nonstd : p->var.bits_per_pixel); unsigned long __iomem *dst; int dst_idx, left; Index: linux-2.6.21gum/drivers/video/cfbimgblt.c =================================================================== --- linux-2.6.21gum.orig/drivers/video/cfbimgblt.c +++ linux-2.6.21gum/drivers/video/cfbimgblt.c @@ -83,7 +83,7 @@ static inline void color_imageblit(const /* Draw the penguin */ u32 __iomem *dst, *dst2; u32 color = 0, val, shift; - int i, n, bpp = p->var.bits_per_pixel; + int i, n, bpp = (p->var.nonstd ? p->var.nonstd : p->var.bits_per_pixel); u32 null_bits = 32 - bpp; u32 *palette = (u32 *) p->pseudo_palette; const u8 *src = image->data; @@ -140,7 +140,7 @@ static inline void slow_imageblit(const u32 start_index, u32 pitch_index) { - u32 shift, color = 0, bpp = p->var.bits_per_pixel; + u32 shift, color = 0, bpp = (p->var.nonstd ? p->var.nonstd : p->var.bits_per_pixel); u32 __iomem *dst, *dst2; u32 val, pitch = p->fix.line_length; u32 null_bits = 32 - bpp; @@ -213,7 +213,7 @@ static inline void fast_imageblit(const u8 __iomem *dst1, u32 fgcolor, u32 bgcolor) { - u32 fgx = fgcolor, bgx = bgcolor, bpp = p->var.bits_per_pixel; + u32 fgx = fgcolor, bgx = bgcolor, bpp = (p->var.nonstd ? p->var.nonstd : p->var.bits_per_pixel); u32 ppw = 32/bpp, spitch = (image->width + 7)/8; u32 bit_mask, end_mask, eorx, shift; const char *s = image->data, *src; @@ -262,7 +262,7 @@ static inline void fast_imageblit(const void cfb_imageblit(struct fb_info *p, const struct fb_image *image) { u32 fgcolor, bgcolor, start_index, bitstart, pitch_index = 0; - u32 bpl = sizeof(u32), bpp = p->var.bits_per_pixel; + u32 bpl = sizeof(u32), bpp = (p->var.nonstd ? p->var.nonstd : p->var.bits_per_pixel); u32 width = image->width; u32 dx = image->dx, dy = image->dy; u8 __iomem *dst1; Index: linux-2.6.21gum/drivers/video/cfbcopyarea.c =================================================================== --- linux-2.6.21gum.orig/drivers/video/cfbcopyarea.c +++ linux-2.6.21gum/drivers/video/cfbcopyarea.c @@ -365,8 +365,8 @@ void cfb_copyarea(struct fb_info *p, con dst = src = (unsigned long __iomem *)((unsigned long)p->screen_base & ~(bytes-1)); dst_idx = src_idx = 8*((unsigned long)p->screen_base & (bytes-1)); // add offset of source and target area - dst_idx += dy*bits_per_line + dx*p->var.bits_per_pixel; - src_idx += sy*bits_per_line + sx*p->var.bits_per_pixel; + dst_idx += dy*bits_per_line + dx*(p->var.nonstd ? p->var.nonstd : p->var.bits_per_pixel); + src_idx += sy*bits_per_line + sx*(p->var.nonstd ? p->var.nonstd : p->var.bits_per_pixel); if (p->fbops->fb_sync) p->fbops->fb_sync(p); @@ -380,7 +380,7 @@ void cfb_copyarea(struct fb_info *p, con src += src_idx >> (ffs(bits) - 1); src_idx &= (bytes - 1); bitcpy_rev(dst, dst_idx, src, src_idx, bits, - width*p->var.bits_per_pixel); + width*(p->var.nonstd ? p->var.nonstd : p->var.bits_per_pixel)); } } else { while (height--) { @@ -389,7 +389,7 @@ void cfb_copyarea(struct fb_info *p, con src += src_idx >> (ffs(bits) - 1); src_idx &= (bytes - 1); bitcpy(dst, dst_idx, src, src_idx, bits, - width*p->var.bits_per_pixel); + width*(p->var.nonstd ? p->var.nonstd : p->var.bits_per_pixel)); dst_idx += bits_per_line; src_idx += bits_per_line; } Index: linux-2.6.21gum/drivers/video/console/fbcon.c =================================================================== --- linux-2.6.21gum.orig/drivers/video/console/fbcon.c +++ linux-2.6.21gum/drivers/video/console/fbcon.c @@ -983,9 +983,10 @@ static const char *fbcon_startup(void) DPRINTK("mode: %s\n", info->fix.id); DPRINTK("visual: %d\n", info->fix.visual); - DPRINTK("res: %dx%d-%d\n", info->var.xres, + DPRINTK("res: %dx%d-%d(%d)\n", info->var.xres, info->var.yres, - info->var.bits_per_pixel); + info->var.bits_per_pixel, + info->var.nonstd ? info->var.nonstd : info->var.bits_per_pixel); #ifdef CONFIG_ATARI if (MACH_IS_ATARI) { Index: linux-2.6.21gum/Documentation/fb/pxafb.txt =================================================================== --- linux-2.6.21gum.orig/Documentation/fb/pxafb.txt +++ linux-2.6.21gum/Documentation/fb/pxafb.txt @@ -9,11 +9,13 @@ For example: or on the kernel command line video=pxafb:mode:640x480-8,passive -mode:XRESxYRES[-BPP] +mode:XRESxYRES[-BPP[/PACKING]] XRES == LCCR1_PPL + 1 YRES == LLCR2_LPP + 1 The resolution of the display in pixels BPP == The bit depth. Valid values are 1, 2, 4, 8 and 16. + PACKING == The in-memory bits per pixel. Valid values are 24, 32 when + BPP == 18,19,24,25 pixclock:PIXCLOCK Pixel clock in picoseconds