aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/video/via
diff options
context:
space:
mode:
authorFlorian Tobias Schandinat <FlorianSchandinat@gmx.de>2010-03-10 18:21:40 -0500
committerLinus Torvalds <torvalds@linux-foundation.org>2010-03-12 18:52:34 -0500
commit415559fbf2353f4271a4cd6e11259b8bbc97cc33 (patch)
tree4bcece3887bfc489d096f60ae28a688a31abe6fd /drivers/video/via
parentdbb7884be758ca9ac5ec84cbe7eb21f21bce9d8f (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/via')
-rw-r--r--drivers/video/via/hw.c28
-rw-r--r--drivers/video/via/hw.h2
-rw-r--r--drivers/video/via/viafbdev.c237
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
736static 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
745void 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
751void 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
736void viafb_set_output_path(int device, int set_iga, int output_interface) 757void 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);
914void viafb_set_secondary_address(u32 addr); 914void viafb_set_secondary_address(u32 addr);
915void viafb_set_primary_pitch(u32 pitch); 915void viafb_set_primary_pitch(u32 pitch);
916void viafb_set_secondary_pitch(u32 pitch); 916void viafb_set_secondary_pitch(u32 pitch);
917void viafb_set_primary_color_register(u8 index, u8 red, u8 green, u8 blue);
918void viafb_set_secondary_color_register(u8 index, u8 red, u8 green, u8 blue);
917void viafb_get_fb_info(unsigned int *fb_base, unsigned int *fb_len); 919void 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)
255static int viafb_setcolreg(unsigned regno, unsigned red, unsigned green, 255static int viafb_setcolreg(unsigned regno, unsigned red, unsigned green,
256unsigned blue, unsigned transp, struct fb_info *info) 256unsigned 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 */
356static 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
2292module_init(viafb_init); 2105module_init(viafb_init);