diff options
author | Eric Miao <ycmiao@ycmiao-hp520.(none)> | 2008-12-18 09:36:26 -0500 |
---|---|---|
committer | Eric Miao <eric.miao@marvell.com> | 2008-12-29 04:59:17 -0500 |
commit | 878f5783199a95cfa91db45a6e34d2f72756fa18 (patch) | |
tree | c979a4d4fdadf270baff1471f44ac91fe5c5e6af /drivers/video/pxafb.c | |
parent | a0427509a76c61984fbba4e206b617c689f419ef (diff) |
[ARM] pxafb: cleanup of the color format manipulation code
1. introduce var_to_depth() to calculate the color depth including the
transparency bit
2. the conversion from 'fb_var_screeninfo' to LCCR3 BPP bits can be re-
used by overlays (in OVLxC1), thus an individual pxafb_var_to_bpp()
has been separated out.
3. pxafb_setmode() should really set the color bitfields correctly at
begining, introduce a pxafb_set_pixfmt() for this
4. allow user apps to specify color formats within fb_var_screeninfo,
and checking of this in pxafb_check_var() has been simplified as
below:
a) pxafb_var_to_bpp() should pass - which means a basically correct
bits_per_pixel and color depth setting
b) the RGBT bitfields are then forced into supported values by
pxafb_set_pixfmt()
Signed-off-by: Eric Miao <eric.miao@marvell.com>
Signed-off-by: Eric Miao <ycmiao@ycmiao-hp520.(none)>
Diffstat (limited to 'drivers/video/pxafb.c')
-rw-r--r-- | drivers/video/pxafb.c | 183 |
1 files changed, 106 insertions, 77 deletions
diff --git a/drivers/video/pxafb.c b/drivers/video/pxafb.c index c57f909cb7a8..1faf52642f5f 100644 --- a/drivers/video/pxafb.c +++ b/drivers/video/pxafb.c | |||
@@ -66,7 +66,7 @@ | |||
66 | LCCR0_SFM | LCCR0_LDM | LCCR0_ENB) | 66 | LCCR0_SFM | LCCR0_LDM | LCCR0_ENB) |
67 | 67 | ||
68 | #define LCCR3_INVALID_CONFIG_MASK (LCCR3_HSP | LCCR3_VSP |\ | 68 | #define LCCR3_INVALID_CONFIG_MASK (LCCR3_HSP | LCCR3_VSP |\ |
69 | LCCR3_PCD | LCCR3_BPP) | 69 | LCCR3_PCD | LCCR3_BPP(0xf)) |
70 | 70 | ||
71 | static int pxafb_activate_var(struct fb_var_screeninfo *var, | 71 | static int pxafb_activate_var(struct fb_var_screeninfo *var, |
72 | struct pxafb_info *); | 72 | struct pxafb_info *); |
@@ -221,37 +221,110 @@ pxafb_setcolreg(u_int regno, u_int red, u_int green, u_int blue, | |||
221 | return ret; | 221 | return ret; |
222 | } | 222 | } |
223 | 223 | ||
224 | /* | 224 | /* calculate pixel depth, transparency bit included, >=16bpp formats _only_ */ |
225 | * pxafb_bpp_to_lccr3(): | 225 | static inline int var_to_depth(struct fb_var_screeninfo *var) |
226 | * Convert a bits per pixel value to the correct bit pattern for LCCR3 | ||
227 | */ | ||
228 | static int pxafb_bpp_to_lccr3(struct fb_var_screeninfo *var) | ||
229 | { | 226 | { |
230 | int ret = 0; | 227 | return var->red.length + var->green.length + |
228 | var->blue.length + var->transp.length; | ||
229 | } | ||
230 | |||
231 | /* calculate 4-bit BPP value for LCCR3 and OVLxC1 */ | ||
232 | static int pxafb_var_to_bpp(struct fb_var_screeninfo *var) | ||
233 | { | ||
234 | int bpp = -EINVAL; | ||
235 | |||
231 | switch (var->bits_per_pixel) { | 236 | switch (var->bits_per_pixel) { |
232 | case 1: ret = LCCR3_1BPP; break; | 237 | case 1: bpp = 0; break; |
233 | case 2: ret = LCCR3_2BPP; break; | 238 | case 2: bpp = 1; break; |
234 | case 4: ret = LCCR3_4BPP; break; | 239 | case 4: bpp = 2; break; |
235 | case 8: ret = LCCR3_8BPP; break; | 240 | case 8: bpp = 3; break; |
236 | case 16: ret = LCCR3_16BPP; break; | 241 | case 16: bpp = 4; break; |
237 | case 24: | 242 | case 24: |
238 | switch (var->red.length + var->green.length + | 243 | switch (var_to_depth(var)) { |
239 | var->blue.length + var->transp.length) { | 244 | case 18: bpp = 6; break; /* 18-bits/pixel packed */ |
240 | case 18: ret = LCCR3_18BPP_P | LCCR3_PDFOR_3; break; | 245 | case 19: bpp = 8; break; /* 19-bits/pixel packed */ |
241 | case 19: ret = LCCR3_19BPP_P; break; | 246 | case 24: bpp = 9; break; |
242 | } | 247 | } |
243 | break; | 248 | break; |
244 | case 32: | 249 | case 32: |
245 | switch (var->red.length + var->green.length + | 250 | switch (var_to_depth(var)) { |
246 | var->blue.length + var->transp.length) { | 251 | case 18: bpp = 5; break; /* 18-bits/pixel unpacked */ |
247 | case 18: ret = LCCR3_18BPP | LCCR3_PDFOR_3; break; | 252 | case 19: bpp = 7; break; /* 19-bits/pixel unpacked */ |
248 | case 19: ret = LCCR3_19BPP; break; | 253 | case 25: bpp = 10; break; |
249 | case 24: ret = LCCR3_24BPP | LCCR3_PDFOR_3; break; | ||
250 | case 25: ret = LCCR3_25BPP; break; | ||
251 | } | 254 | } |
252 | break; | 255 | break; |
253 | } | 256 | } |
254 | return ret; | 257 | return bpp; |
258 | } | ||
259 | |||
260 | /* | ||
261 | * pxafb_var_to_lccr3(): | ||
262 | * Convert a bits per pixel value to the correct bit pattern for LCCR3 | ||
263 | * | ||
264 | * NOTE: for PXA27x with overlays support, the LCCR3_PDFOR_x bits have an | ||
265 | * implication of the acutal use of transparency bit, which we handle it | ||
266 | * here separatedly. See PXA27x Developer's Manual, Section <<7.4.6 Pixel | ||
267 | * Formats>> for the valid combination of PDFOR, PAL_FOR for various BPP. | ||
268 | * | ||
269 | * Transparency for palette pixel formats is not supported at the moment. | ||
270 | */ | ||
271 | static uint32_t pxafb_var_to_lccr3(struct fb_var_screeninfo *var) | ||
272 | { | ||
273 | int bpp = pxafb_var_to_bpp(var); | ||
274 | uint32_t lccr3; | ||
275 | |||
276 | if (bpp < 0) | ||
277 | return 0; | ||
278 | |||
279 | lccr3 = LCCR3_BPP(bpp); | ||
280 | |||
281 | switch (var_to_depth(var)) { | ||
282 | case 16: lccr3 |= var->transp.length ? LCCR3_PDFOR_3 : 0; break; | ||
283 | case 18: lccr3 |= LCCR3_PDFOR_3; break; | ||
284 | case 24: lccr3 |= var->transp.length ? LCCR3_PDFOR_2 : LCCR3_PDFOR_3; | ||
285 | break; | ||
286 | case 19: | ||
287 | case 25: lccr3 |= LCCR3_PDFOR_0; break; | ||
288 | } | ||
289 | return lccr3; | ||
290 | } | ||
291 | |||
292 | #define SET_PIXFMT(v, r, g, b, t) \ | ||
293 | ({ \ | ||
294 | (v)->transp.offset = (t) ? (r) + (g) + (b) : 0; \ | ||
295 | (v)->transp.length = (t) ? (t) : 0; \ | ||
296 | (v)->blue.length = (b); (v)->blue.offset = 0; \ | ||
297 | (v)->green.length = (g); (v)->green.offset = (b); \ | ||
298 | (v)->red.length = (r); (v)->red.offset = (b) + (g); \ | ||
299 | }) | ||
300 | |||
301 | /* set the RGBT bitfields of fb_var_screeninf according to | ||
302 | * var->bits_per_pixel and given depth | ||
303 | */ | ||
304 | static void pxafb_set_pixfmt(struct fb_var_screeninfo *var, int depth) | ||
305 | { | ||
306 | if (depth == 0) | ||
307 | depth = var->bits_per_pixel; | ||
308 | |||
309 | if (var->bits_per_pixel < 16) { | ||
310 | /* indexed pixel formats */ | ||
311 | var->red.offset = 0; var->red.length = 8; | ||
312 | var->green.offset = 0; var->green.length = 8; | ||
313 | var->blue.offset = 0; var->blue.length = 8; | ||
314 | var->transp.offset = 0; var->transp.length = 8; | ||
315 | } | ||
316 | |||
317 | switch (depth) { | ||
318 | case 16: var->transp.length ? | ||
319 | SET_PIXFMT(var, 5, 5, 5, 1) : /* RGBT555 */ | ||
320 | SET_PIXFMT(var, 5, 6, 5, 0); break; /* RGB565 */ | ||
321 | case 18: SET_PIXFMT(var, 6, 6, 6, 0); break; /* RGB666 */ | ||
322 | case 19: SET_PIXFMT(var, 6, 6, 6, 1); break; /* RGBT666 */ | ||
323 | case 24: var->transp.length ? | ||
324 | SET_PIXFMT(var, 8, 8, 7, 1) : /* RGBT887 */ | ||
325 | SET_PIXFMT(var, 8, 8, 8, 0); break; /* RGB888 */ | ||
326 | case 25: SET_PIXFMT(var, 8, 8, 8, 1); break; /* RGBT888 */ | ||
327 | } | ||
255 | } | 328 | } |
256 | 329 | ||
257 | #ifdef CONFIG_CPU_FREQ | 330 | #ifdef CONFIG_CPU_FREQ |
@@ -313,6 +386,9 @@ static void pxafb_setmode(struct fb_var_screeninfo *var, | |||
313 | var->lower_margin = mode->lower_margin; | 386 | var->lower_margin = mode->lower_margin; |
314 | var->sync = mode->sync; | 387 | var->sync = mode->sync; |
315 | var->grayscale = mode->cmap_greyscale; | 388 | var->grayscale = mode->cmap_greyscale; |
389 | |||
390 | /* set the initial RGBA bitfields */ | ||
391 | pxafb_set_pixfmt(var, mode->depth); | ||
316 | } | 392 | } |
317 | 393 | ||
318 | /* | 394 | /* |
@@ -328,6 +404,7 @@ static int pxafb_check_var(struct fb_var_screeninfo *var, struct fb_info *info) | |||
328 | { | 404 | { |
329 | struct pxafb_info *fbi = (struct pxafb_info *)info; | 405 | struct pxafb_info *fbi = (struct pxafb_info *)info; |
330 | struct pxafb_mach_info *inf = fbi->dev->platform_data; | 406 | struct pxafb_mach_info *inf = fbi->dev->platform_data; |
407 | int err; | ||
331 | 408 | ||
332 | if (var->xres < MIN_XRES) | 409 | if (var->xres < MIN_XRES) |
333 | var->xres = MIN_XRES; | 410 | var->xres = MIN_XRES; |
@@ -359,60 +436,12 @@ static int pxafb_check_var(struct fb_var_screeninfo *var, struct fb_info *info) | |||
359 | else | 436 | else |
360 | var->yres_virtual = max(var->yres_virtual, var->yres); | 437 | var->yres_virtual = max(var->yres_virtual, var->yres); |
361 | 438 | ||
362 | /* | 439 | /* do a test conversion to BPP fields to check the color formats */ |
363 | * Setup the RGB parameters for this display. | 440 | err = pxafb_var_to_bpp(var); |
364 | * | 441 | if (err < 0) |
365 | * The pixel packing format is described on page 7-11 of the | 442 | return err; |
366 | * PXA2XX Developer's Manual. | ||
367 | */ | ||
368 | if (var->bits_per_pixel == 16) { | ||
369 | var->red.offset = 11; var->red.length = 5; | ||
370 | var->green.offset = 5; var->green.length = 6; | ||
371 | var->blue.offset = 0; var->blue.length = 5; | ||
372 | var->transp.offset = var->transp.length = 0; | ||
373 | } else if (var->bits_per_pixel > 16) { | ||
374 | struct pxafb_mode_info *mode; | ||
375 | 443 | ||
376 | mode = pxafb_getmode(inf, var); | 444 | pxafb_set_pixfmt(var, var_to_depth(var)); |
377 | if (!mode) | ||
378 | return -EINVAL; | ||
379 | |||
380 | switch (mode->depth) { | ||
381 | case 18: /* RGB666 */ | ||
382 | var->transp.offset = var->transp.length = 0; | ||
383 | var->red.offset = 12; var->red.length = 6; | ||
384 | var->green.offset = 6; var->green.length = 6; | ||
385 | var->blue.offset = 0; var->blue.length = 6; | ||
386 | break; | ||
387 | case 19: /* RGBT666 */ | ||
388 | var->transp.offset = 18; var->transp.length = 1; | ||
389 | var->red.offset = 12; var->red.length = 6; | ||
390 | var->green.offset = 6; var->green.length = 6; | ||
391 | var->blue.offset = 0; var->blue.length = 6; | ||
392 | break; | ||
393 | case 24: /* RGB888 */ | ||
394 | var->transp.offset = var->transp.length = 0; | ||
395 | var->red.offset = 16; var->red.length = 8; | ||
396 | var->green.offset = 8; var->green.length = 8; | ||
397 | var->blue.offset = 0; var->blue.length = 8; | ||
398 | break; | ||
399 | case 25: /* RGBT888 */ | ||
400 | var->transp.offset = 24; var->transp.length = 1; | ||
401 | var->red.offset = 16; var->red.length = 8; | ||
402 | var->green.offset = 8; var->green.length = 8; | ||
403 | var->blue.offset = 0; var->blue.length = 8; | ||
404 | break; | ||
405 | default: | ||
406 | return -EINVAL; | ||
407 | } | ||
408 | } else { | ||
409 | var->red.offset = var->green.offset = 0; | ||
410 | var->blue.offset = var->transp.offset = 0; | ||
411 | var->red.length = 8; | ||
412 | var->green.length = 8; | ||
413 | var->blue.length = 8; | ||
414 | var->transp.length = 0; | ||
415 | } | ||
416 | 445 | ||
417 | #ifdef CONFIG_CPU_FREQ | 446 | #ifdef CONFIG_CPU_FREQ |
418 | pr_debug("pxafb: dma period = %d ps\n", | 447 | pr_debug("pxafb: dma period = %d ps\n", |
@@ -978,7 +1007,7 @@ static int pxafb_activate_var(struct fb_var_screeninfo *var, | |||
978 | (LCCR0_LDM | LCCR0_SFM | LCCR0_IUM | LCCR0_EFM | | 1007 | (LCCR0_LDM | LCCR0_SFM | LCCR0_IUM | LCCR0_EFM | |
979 | LCCR0_QDM | LCCR0_BM | LCCR0_OUM); | 1008 | LCCR0_QDM | LCCR0_BM | LCCR0_OUM); |
980 | 1009 | ||
981 | fbi->reg_lccr3 |= pxafb_bpp_to_lccr3(var); | 1010 | fbi->reg_lccr3 |= pxafb_var_to_lccr3(var); |
982 | 1011 | ||
983 | fbi->reg_lccr4 = lcd_readl(fbi, LCCR4) & ~LCCR4_PAL_FOR_MASK; | 1012 | fbi->reg_lccr4 = lcd_readl(fbi, LCCR4) & ~LCCR4_PAL_FOR_MASK; |
984 | fbi->reg_lccr4 |= (fbi->lccr4 & LCCR4_PAL_FOR_MASK); | 1013 | fbi->reg_lccr4 |= (fbi->lccr4 & LCCR4_PAL_FOR_MASK); |