diff options
author | Florian Tobias Schandinat <FlorianSchandinat@gmx.de> | 2010-03-10 18:21:40 -0500 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2010-03-12 18:52:34 -0500 |
commit | 415559fbf2353f4271a4cd6e11259b8bbc97cc33 (patch) | |
tree | 4bcece3887bfc489d096f60ae28a688a31abe6fd /drivers/video | |
parent | dbb7884be758ca9ac5ec84cbe7eb21f21bce9d8f (diff) |
viafb: rework color setting
This is a rewritten version of viafb_setcolreg. The hardware register
writes were split up and moved to hw.c where they belong as this is really
low level stuff. It was made dual fb aware.
Furthermore viafb_setcmap was removed as the problem with 8bpp originated
from a bug in writing multiple color registers at once. The removal of
viafb_setcmap might introduce a small performance regression but its
certainly better to receive the correct result a bit slower than a garbled
picture fast. It should give us a working 8bpp mode and is more
extensible than the old hardcoded code. No other regressions are expected
but as the hardware might be a bit picky it might cause some regressions
in 8bpp mode on some hardware although I doubt that.
Signed-off-by: Florian Tobias Schandinat <FlorianSchandinat@gmx.de>
Cc: Joseph Chan <JosephChan@via.com.tw>
Cc: Scott Fang <ScottFang@viatech.com.cn>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Diffstat (limited to 'drivers/video')
-rw-r--r-- | drivers/video/via/hw.c | 28 | ||||
-rw-r--r-- | drivers/video/via/hw.h | 2 | ||||
-rw-r--r-- | drivers/video/via/viafbdev.c | 237 |
3 files changed, 51 insertions, 216 deletions
diff --git a/drivers/video/via/hw.c b/drivers/video/via/hw.c index 47d9024d7c30..1823253a6f40 100644 --- a/drivers/video/via/hw.c +++ b/drivers/video/via/hw.c | |||
@@ -691,7 +691,7 @@ void viafb_set_primary_color_depth(u8 depth) | |||
691 | 691 | ||
692 | DEBUG_MSG(KERN_DEBUG "viafb_set_primary_color_depth(%d)\n", depth); | 692 | DEBUG_MSG(KERN_DEBUG "viafb_set_primary_color_depth(%d)\n", depth); |
693 | switch (depth) { | 693 | switch (depth) { |
694 | case 6: | 694 | case 8: |
695 | value = 0x00; | 695 | value = 0x00; |
696 | break; | 696 | break; |
697 | case 16: | 697 | case 16: |
@@ -715,7 +715,7 @@ void viafb_set_secondary_color_depth(u8 depth) | |||
715 | 715 | ||
716 | DEBUG_MSG(KERN_DEBUG "viafb_set_secondary_color_depth(%d)\n", depth); | 716 | DEBUG_MSG(KERN_DEBUG "viafb_set_secondary_color_depth(%d)\n", depth); |
717 | switch (depth) { | 717 | switch (depth) { |
718 | case 6: | 718 | case 8: |
719 | value = 0x00; | 719 | value = 0x00; |
720 | break; | 720 | break; |
721 | case 16: | 721 | case 16: |
@@ -733,6 +733,27 @@ void viafb_set_secondary_color_depth(u8 depth) | |||
733 | viafb_write_reg_mask(0x67, VIACR, value, 0xC0); | 733 | viafb_write_reg_mask(0x67, VIACR, value, 0xC0); |
734 | } | 734 | } |
735 | 735 | ||
736 | static void set_color_register(u8 index, u8 red, u8 green, u8 blue) | ||
737 | { | ||
738 | outb(0xFF, 0x3C6); /* bit mask of palette */ | ||
739 | outb(index, 0x3C8); | ||
740 | outb(red, 0x3C9); | ||
741 | outb(green, 0x3C9); | ||
742 | outb(blue, 0x3C9); | ||
743 | } | ||
744 | |||
745 | void viafb_set_primary_color_register(u8 index, u8 red, u8 green, u8 blue) | ||
746 | { | ||
747 | viafb_write_reg_mask(0x1A, VIASR, 0x00, 0x01); | ||
748 | set_color_register(index, red, green, blue); | ||
749 | } | ||
750 | |||
751 | void viafb_set_secondary_color_register(u8 index, u8 red, u8 green, u8 blue) | ||
752 | { | ||
753 | viafb_write_reg_mask(0x1A, VIASR, 0x01, 0x01); | ||
754 | set_color_register(index, red, green, blue); | ||
755 | } | ||
756 | |||
736 | void viafb_set_output_path(int device, int set_iga, int output_interface) | 757 | void viafb_set_output_path(int device, int set_iga, int output_interface) |
737 | { | 758 | { |
738 | switch (device) { | 759 | switch (device) { |
@@ -2210,8 +2231,7 @@ int viafb_setmode(struct VideoModeTable *vmode_tbl, int video_bpp, | |||
2210 | outb(VPIT.SR[i - 1], VIASR + 1); | 2231 | outb(VPIT.SR[i - 1], VIASR + 1); |
2211 | } | 2232 | } |
2212 | 2233 | ||
2213 | viafb_write_reg_mask(0x15, VIASR, viafbinfo->fix.visual | 2234 | viafb_write_reg_mask(0x15, VIASR, 0xA2, 0xA2); |
2214 | == FB_VISUAL_PSEUDOCOLOR ? 0x22 : 0xA2, 0xA2); | ||
2215 | viafb_set_iga_path(); | 2235 | viafb_set_iga_path(); |
2216 | 2236 | ||
2217 | /* Write CRTC */ | 2237 | /* Write CRTC */ |
diff --git a/drivers/video/via/hw.h b/drivers/video/via/hw.h index 691fbd2d8067..12ef32d334cb 100644 --- a/drivers/video/via/hw.h +++ b/drivers/video/via/hw.h | |||
@@ -914,6 +914,8 @@ void viafb_set_primary_address(u32 addr); | |||
914 | void viafb_set_secondary_address(u32 addr); | 914 | void viafb_set_secondary_address(u32 addr); |
915 | void viafb_set_primary_pitch(u32 pitch); | 915 | void viafb_set_primary_pitch(u32 pitch); |
916 | void viafb_set_secondary_pitch(u32 pitch); | 916 | void viafb_set_secondary_pitch(u32 pitch); |
917 | void viafb_set_primary_color_register(u8 index, u8 red, u8 green, u8 blue); | ||
918 | void viafb_set_secondary_color_register(u8 index, u8 red, u8 green, u8 blue); | ||
917 | void viafb_get_fb_info(unsigned int *fb_base, unsigned int *fb_len); | 919 | void viafb_get_fb_info(unsigned int *fb_base, unsigned int *fb_len); |
918 | 920 | ||
919 | #endif /* __HW_H__ */ | 921 | #endif /* __HW_H__ */ |
diff --git a/drivers/video/via/viafbdev.c b/drivers/video/via/viafbdev.c index 0fe748d66a6c..410de33f5778 100644 --- a/drivers/video/via/viafbdev.c +++ b/drivers/video/via/viafbdev.c | |||
@@ -76,9 +76,9 @@ static void viafb_fill_var_color_info(struct fb_var_screeninfo *var, u8 depth) | |||
76 | var->red.offset = 0; | 76 | var->red.offset = 0; |
77 | var->green.offset = 0; | 77 | var->green.offset = 0; |
78 | var->blue.offset = 0; | 78 | var->blue.offset = 0; |
79 | var->red.length = 6; | 79 | var->red.length = 8; |
80 | var->green.length = 6; | 80 | var->green.length = 8; |
81 | var->blue.length = 6; | 81 | var->blue.length = 8; |
82 | break; | 82 | break; |
83 | case 16: | 83 | case 16: |
84 | var->bits_per_pixel = 16; | 84 | var->bits_per_pixel = 16; |
@@ -255,219 +255,33 @@ static int viafb_set_par(struct fb_info *info) | |||
255 | static int viafb_setcolreg(unsigned regno, unsigned red, unsigned green, | 255 | static int viafb_setcolreg(unsigned regno, unsigned red, unsigned green, |
256 | unsigned blue, unsigned transp, struct fb_info *info) | 256 | unsigned blue, unsigned transp, struct fb_info *info) |
257 | { | 257 | { |
258 | u8 sr1a, sr1b, cr67, cr6a, rev = 0, shift = 10; | 258 | struct viafb_par *viapar = info->par; |
259 | unsigned cmap_entries = (info->var.bits_per_pixel == 8) ? 256 : 16; | 259 | u32 r, g, b; |
260 | DEBUG_MSG(KERN_INFO "viafb_setcolreg!\n"); | ||
261 | if (regno >= cmap_entries) | ||
262 | return 1; | ||
263 | if (UNICHROME_CLE266 == viaparinfo->chip_info->gfx_chip_name) { | ||
264 | /* | ||
265 | * Read PCI bus 0,dev 0,function 0,index 0xF6 to get chip rev. | ||
266 | */ | ||
267 | outl(0x80000000 | (0xf6 & ~3), (unsigned long)0xCF8); | ||
268 | rev = (inl((unsigned long)0xCFC) >> ((0xf6 & 3) * 8)) & 0xff; | ||
269 | } | ||
270 | switch (info->var.bits_per_pixel) { | ||
271 | case 8: | ||
272 | outb(0x1A, 0x3C4); | ||
273 | sr1a = inb(0x3C5); | ||
274 | outb(0x1B, 0x3C4); | ||
275 | sr1b = inb(0x3C5); | ||
276 | outb(0x67, 0x3D4); | ||
277 | cr67 = inb(0x3D5); | ||
278 | outb(0x6A, 0x3D4); | ||
279 | cr6a = inb(0x3D5); | ||
280 | |||
281 | /* Map the 3C6/7/8/9 to the IGA2 */ | ||
282 | outb(0x1A, 0x3C4); | ||
283 | outb(sr1a | 0x01, 0x3C5); | ||
284 | /* Second Display Engine colck always on */ | ||
285 | outb(0x1B, 0x3C4); | ||
286 | outb(sr1b | 0x80, 0x3C5); | ||
287 | /* Second Display Color Depth 8 */ | ||
288 | outb(0x67, 0x3D4); | ||
289 | outb(cr67 & 0x3F, 0x3D5); | ||
290 | outb(0x6A, 0x3D4); | ||
291 | /* Second Display Channel Reset CR6A[6]) */ | ||
292 | outb(cr6a & 0xBF, 0x3D5); | ||
293 | /* Second Display Channel Enable CR6A[7] */ | ||
294 | outb(cr6a | 0x80, 0x3D5); | ||
295 | /* Second Display Channel stop reset) */ | ||
296 | outb(cr6a | 0x40, 0x3D5); | ||
297 | |||
298 | /* Bit mask of palette */ | ||
299 | outb(0xFF, 0x3c6); | ||
300 | /* Write one register of IGA2 */ | ||
301 | outb(regno, 0x3C8); | ||
302 | if (UNICHROME_CLE266 == viaparinfo->chip_info->gfx_chip_name && | ||
303 | rev >= 15) { | ||
304 | shift = 8; | ||
305 | viafb_write_reg_mask(CR6A, VIACR, BIT5, BIT5); | ||
306 | viafb_write_reg_mask(SR15, VIASR, BIT7, BIT7); | ||
307 | } else { | ||
308 | shift = 10; | ||
309 | viafb_write_reg_mask(CR6A, VIACR, 0, BIT5); | ||
310 | viafb_write_reg_mask(SR15, VIASR, 0, BIT7); | ||
311 | } | ||
312 | outb(red >> shift, 0x3C9); | ||
313 | outb(green >> shift, 0x3C9); | ||
314 | outb(blue >> shift, 0x3C9); | ||
315 | |||
316 | /* Map the 3C6/7/8/9 to the IGA1 */ | ||
317 | outb(0x1A, 0x3C4); | ||
318 | outb(sr1a & 0xFE, 0x3C5); | ||
319 | /* Bit mask of palette */ | ||
320 | outb(0xFF, 0x3c6); | ||
321 | /* Write one register of IGA1 */ | ||
322 | outb(regno, 0x3C8); | ||
323 | outb(red >> shift, 0x3C9); | ||
324 | outb(green >> shift, 0x3C9); | ||
325 | outb(blue >> shift, 0x3C9); | ||
326 | |||
327 | outb(0x1A, 0x3C4); | ||
328 | outb(sr1a, 0x3C5); | ||
329 | outb(0x1B, 0x3C4); | ||
330 | outb(sr1b, 0x3C5); | ||
331 | outb(0x67, 0x3D4); | ||
332 | outb(cr67, 0x3D5); | ||
333 | outb(0x6A, 0x3D4); | ||
334 | outb(cr6a, 0x3D5); | ||
335 | break; | ||
336 | case 16: | ||
337 | ((u32 *) info->pseudo_palette)[regno] = (red & 0xF800) | | ||
338 | ((green & 0xFC00) >> 5) | ((blue & 0xF800) >> 11); | ||
339 | break; | ||
340 | case 32: | ||
341 | ((u32 *) info->pseudo_palette)[regno] = | ||
342 | ((transp & 0xFF00) << 16) | | ||
343 | ((red & 0xFF00) << 8) | | ||
344 | ((green & 0xFF00)) | ((blue & 0xFF00) >> 8); | ||
345 | break; | ||
346 | } | ||
347 | |||
348 | return 0; | ||
349 | 260 | ||
350 | } | 261 | if (info->fix.visual == FB_VISUAL_PSEUDOCOLOR) { |
262 | if (regno > 255) | ||
263 | return -EINVAL; | ||
351 | 264 | ||
352 | /*CALLED BY: fb_set_cmap */ | 265 | if (!viafb_dual_fb || viapar->iga_path == IGA1) |
353 | /* fb_set_var, pass 256 colors */ | 266 | viafb_set_primary_color_register(regno, red >> 8, |
354 | /*CALLED BY: fb_set_cmap */ | 267 | green >> 8, blue >> 8); |
355 | /* fbcon_set_palette, pass 16 colors */ | ||
356 | static int viafb_setcmap(struct fb_cmap *cmap, struct fb_info *info) | ||
357 | { | ||
358 | u32 len = cmap->len; | ||
359 | u32 i; | ||
360 | u16 *pred = cmap->red; | ||
361 | u16 *pgreen = cmap->green; | ||
362 | u16 *pblue = cmap->blue; | ||
363 | u16 *ptransp = cmap->transp; | ||
364 | u8 sr1a, sr1b, cr67, cr6a, rev = 0, shift = 10; | ||
365 | if (len > 256) | ||
366 | return 1; | ||
367 | if (UNICHROME_CLE266 == viaparinfo->chip_info->gfx_chip_name) { | ||
368 | /* | ||
369 | * Read PCI bus 0, dev 0, function 0, index 0xF6 to get chip | ||
370 | * rev. | ||
371 | */ | ||
372 | outl(0x80000000 | (0xf6 & ~3), (unsigned long)0xCF8); | ||
373 | rev = (inl((unsigned long)0xCFC) >> ((0xf6 & 3) * 8)) & 0xff; | ||
374 | } | ||
375 | switch (info->var.bits_per_pixel) { | ||
376 | case 8: | ||
377 | outb(0x1A, 0x3C4); | ||
378 | sr1a = inb(0x3C5); | ||
379 | outb(0x1B, 0x3C4); | ||
380 | sr1b = inb(0x3C5); | ||
381 | outb(0x67, 0x3D4); | ||
382 | cr67 = inb(0x3D5); | ||
383 | outb(0x6A, 0x3D4); | ||
384 | cr6a = inb(0x3D5); | ||
385 | /* Map the 3C6/7/8/9 to the IGA2 */ | ||
386 | outb(0x1A, 0x3C4); | ||
387 | outb(sr1a | 0x01, 0x3C5); | ||
388 | outb(0x1B, 0x3C4); | ||
389 | /* Second Display Engine colck always on */ | ||
390 | outb(sr1b | 0x80, 0x3C5); | ||
391 | outb(0x67, 0x3D4); | ||
392 | /* Second Display Color Depth 8 */ | ||
393 | outb(cr67 & 0x3F, 0x3D5); | ||
394 | outb(0x6A, 0x3D4); | ||
395 | /* Second Display Channel Reset CR6A[6]) */ | ||
396 | outb(cr6a & 0xBF, 0x3D5); | ||
397 | /* Second Display Channel Enable CR6A[7] */ | ||
398 | outb(cr6a | 0x80, 0x3D5); | ||
399 | /* Second Display Channel stop reset) */ | ||
400 | outb(cr6a | 0xC0, 0x3D5); | ||
401 | |||
402 | /* Bit mask of palette */ | ||
403 | outb(0xFF, 0x3c6); | ||
404 | outb(0x00, 0x3C8); | ||
405 | if (UNICHROME_CLE266 == viaparinfo->chip_info->gfx_chip_name && | ||
406 | rev >= 15) { | ||
407 | shift = 8; | ||
408 | viafb_write_reg_mask(CR6A, VIACR, BIT5, BIT5); | ||
409 | viafb_write_reg_mask(SR15, VIASR, BIT7, BIT7); | ||
410 | } else { | ||
411 | shift = 10; | ||
412 | viafb_write_reg_mask(CR6A, VIACR, 0, BIT5); | ||
413 | viafb_write_reg_mask(SR15, VIASR, 0, BIT7); | ||
414 | } | ||
415 | for (i = 0; i < len; i++) { | ||
416 | outb((*(pred + i)) >> shift, 0x3C9); | ||
417 | outb((*(pgreen + i)) >> shift, 0x3C9); | ||
418 | outb((*(pblue + i)) >> shift, 0x3C9); | ||
419 | } | ||
420 | 268 | ||
421 | outb(0x1A, 0x3C4); | 269 | if (!viafb_dual_fb || viapar->iga_path == IGA2) |
422 | /* Map the 3C6/7/8/9 to the IGA1 */ | 270 | viafb_set_secondary_color_register(regno, red >> 8, |
423 | outb(sr1a & 0xFE, 0x3C5); | 271 | green >> 8, blue >> 8); |
424 | /* Bit mask of palette */ | 272 | } else { |
425 | outb(0xFF, 0x3c6); | 273 | if (regno > 15) |
426 | outb(0x00, 0x3C8); | 274 | return -EINVAL; |
427 | for (i = 0; i < len; i++) { | ||
428 | outb((*(pred + i)) >> shift, 0x3C9); | ||
429 | outb((*(pgreen + i)) >> shift, 0x3C9); | ||
430 | outb((*(pblue + i)) >> shift, 0x3C9); | ||
431 | } | ||
432 | 275 | ||
433 | outb(0x1A, 0x3C4); | 276 | r = (red >> (16 - info->var.red.length)) |
434 | outb(sr1a, 0x3C5); | 277 | << info->var.red.offset; |
435 | outb(0x1B, 0x3C4); | 278 | b = (blue >> (16 - info->var.blue.length)) |
436 | outb(sr1b, 0x3C5); | 279 | << info->var.blue.offset; |
437 | outb(0x67, 0x3D4); | 280 | g = (green >> (16 - info->var.green.length)) |
438 | outb(cr67, 0x3D5); | 281 | << info->var.green.offset; |
439 | outb(0x6A, 0x3D4); | 282 | ((u32 *) info->pseudo_palette)[regno] = r | g | b; |
440 | outb(cr6a, 0x3D5); | ||
441 | break; | ||
442 | case 16: | ||
443 | if (len > 17) | ||
444 | return 0; /* Because static u32 pseudo_pal[17]; */ | ||
445 | for (i = 0; i < len; i++) | ||
446 | ((u32 *) info->pseudo_palette)[i] = | ||
447 | (*(pred + i) & 0xF800) | | ||
448 | ((*(pgreen + i) & 0xFC00) >> 5) | | ||
449 | ((*(pblue + i) & 0xF800) >> 11); | ||
450 | break; | ||
451 | case 32: | ||
452 | if (len > 17) | ||
453 | return 0; | ||
454 | if (ptransp) { | ||
455 | for (i = 0; i < len; i++) | ||
456 | ((u32 *) info->pseudo_palette)[i] = | ||
457 | ((*(ptransp + i) & 0xFF00) << 16) | | ||
458 | ((*(pred + i) & 0xFF00) << 8) | | ||
459 | ((*(pgreen + i) & 0xFF00)) | | ||
460 | ((*(pblue + i) & 0xFF00) >> 8); | ||
461 | } else { | ||
462 | for (i = 0; i < len; i++) | ||
463 | ((u32 *) info->pseudo_palette)[i] = | ||
464 | 0x00000000 | | ||
465 | ((*(pred + i) & 0xFF00) << 8) | | ||
466 | ((*(pgreen + i) & 0xFF00)) | | ||
467 | ((*(pblue + i) & 0xFF00) >> 8); | ||
468 | } | ||
469 | break; | ||
470 | } | 283 | } |
284 | |||
471 | return 0; | 285 | return 0; |
472 | } | 286 | } |
473 | 287 | ||
@@ -2286,7 +2100,6 @@ static struct fb_ops viafb_ops = { | |||
2286 | .fb_cursor = viafb_cursor, | 2100 | .fb_cursor = viafb_cursor, |
2287 | .fb_ioctl = viafb_ioctl, | 2101 | .fb_ioctl = viafb_ioctl, |
2288 | .fb_sync = viafb_sync, | 2102 | .fb_sync = viafb_sync, |
2289 | .fb_setcmap = viafb_setcmap, | ||
2290 | }; | 2103 | }; |
2291 | 2104 | ||
2292 | module_init(viafb_init); | 2105 | module_init(viafb_init); |