diff options
-rw-r--r-- | drivers/video/cirrusfb.c | 195 |
1 files changed, 74 insertions, 121 deletions
diff --git a/drivers/video/cirrusfb.c b/drivers/video/cirrusfb.c index 12f45520e5d3..bab713b63a0c 100644 --- a/drivers/video/cirrusfb.c +++ b/drivers/video/cirrusfb.c | |||
@@ -432,6 +432,53 @@ static int cirrusfb_check_mclk(struct fb_info *info, long freq) | |||
432 | return 0; | 432 | return 0; |
433 | } | 433 | } |
434 | 434 | ||
435 | static int cirrusfb_check_pixclock(const struct fb_var_screeninfo *var, | ||
436 | struct fb_info *info) | ||
437 | { | ||
438 | long freq; | ||
439 | long maxclock; | ||
440 | struct cirrusfb_info *cinfo = info->par; | ||
441 | unsigned maxclockidx = var->bits_per_pixel >> 3; | ||
442 | |||
443 | /* convert from ps to kHz */ | ||
444 | freq = PICOS2KHZ(var->pixclock); | ||
445 | |||
446 | dev_dbg(info->device, "desired pixclock: %ld kHz\n", freq); | ||
447 | |||
448 | maxclock = cirrusfb_board_info[cinfo->btype].maxclock[maxclockidx]; | ||
449 | cinfo->multiplexing = 0; | ||
450 | |||
451 | /* If the frequency is greater than we can support, we might be able | ||
452 | * to use multiplexing for the video mode */ | ||
453 | if (freq > maxclock) { | ||
454 | switch (cinfo->btype) { | ||
455 | case BT_ALPINE: | ||
456 | case BT_GD5480: | ||
457 | cinfo->multiplexing = 1; | ||
458 | break; | ||
459 | |||
460 | default: | ||
461 | dev_err(info->device, | ||
462 | "Frequency greater than maxclock (%ld kHz)\n", | ||
463 | maxclock); | ||
464 | return -EINVAL; | ||
465 | } | ||
466 | } | ||
467 | #if 0 | ||
468 | /* TODO: If we have a 1MB 5434, we need to put ourselves in a mode where | ||
469 | * the VCLK is double the pixel clock. */ | ||
470 | switch (var->bits_per_pixel) { | ||
471 | case 16: | ||
472 | case 32: | ||
473 | if (var->xres <= 800) | ||
474 | /* Xbh has this type of clock for 32-bit */ | ||
475 | freq /= 2; | ||
476 | break; | ||
477 | } | ||
478 | #endif | ||
479 | return 0; | ||
480 | } | ||
481 | |||
435 | static int cirrusfb_check_var(struct fb_var_screeninfo *var, | 482 | static int cirrusfb_check_var(struct fb_var_screeninfo *var, |
436 | struct fb_info *info) | 483 | struct fb_info *info) |
437 | { | 484 | { |
@@ -449,7 +496,7 @@ static int cirrusfb_check_var(struct fb_var_screeninfo *var, | |||
449 | 496 | ||
450 | case 8: | 497 | case 8: |
451 | var->red.offset = 0; | 498 | var->red.offset = 0; |
452 | var->red.length = 6; | 499 | var->red.length = 8; |
453 | var->green = var->red; | 500 | var->green = var->red; |
454 | var->blue = var->red; | 501 | var->blue = var->red; |
455 | break; | 502 | break; |
@@ -513,7 +560,6 @@ static int cirrusfb_check_var(struct fb_var_screeninfo *var, | |||
513 | return -EINVAL; | 560 | return -EINVAL; |
514 | } | 561 | } |
515 | 562 | ||
516 | |||
517 | if (var->xoffset < 0) | 563 | if (var->xoffset < 0) |
518 | var->xoffset = 0; | 564 | var->xoffset = 0; |
519 | if (var->yoffset < 0) | 565 | if (var->yoffset < 0) |
@@ -544,80 +590,9 @@ static int cirrusfb_check_var(struct fb_var_screeninfo *var, | |||
544 | return -EINVAL; | 590 | return -EINVAL; |
545 | } | 591 | } |
546 | 592 | ||
547 | return 0; | 593 | if (cirrusfb_check_pixclock(var, info)) |
548 | } | 594 | return -EINVAL; |
549 | |||
550 | static int cirrusfb_decode_var(const struct fb_var_screeninfo *var, | ||
551 | struct fb_info *info) | ||
552 | { | ||
553 | long freq; | ||
554 | long maxclock; | ||
555 | int maxclockidx = var->bits_per_pixel >> 3; | ||
556 | struct cirrusfb_info *cinfo = info->par; | ||
557 | |||
558 | switch (var->bits_per_pixel) { | ||
559 | case 1: | ||
560 | info->fix.line_length = var->xres_virtual / 8; | ||
561 | info->fix.visual = FB_VISUAL_MONO10; | ||
562 | break; | ||
563 | |||
564 | case 8: | ||
565 | info->fix.line_length = var->xres_virtual; | ||
566 | info->fix.visual = FB_VISUAL_PSEUDOCOLOR; | ||
567 | break; | ||
568 | |||
569 | case 16: | ||
570 | case 32: | ||
571 | info->fix.line_length = var->xres_virtual * maxclockidx; | ||
572 | info->fix.visual = FB_VISUAL_TRUECOLOR; | ||
573 | break; | ||
574 | |||
575 | default: | ||
576 | dev_dbg(info->device, | ||
577 | "Unsupported bpp size: %d\n", var->bits_per_pixel); | ||
578 | assert(false); | ||
579 | /* should never occur */ | ||
580 | break; | ||
581 | } | ||
582 | |||
583 | info->fix.type = FB_TYPE_PACKED_PIXELS; | ||
584 | |||
585 | /* convert from ps to kHz */ | ||
586 | freq = PICOS2KHZ(var->pixclock); | ||
587 | |||
588 | dev_dbg(info->device, "desired pixclock: %ld kHz\n", freq); | ||
589 | |||
590 | maxclock = cirrusfb_board_info[cinfo->btype].maxclock[maxclockidx]; | ||
591 | cinfo->multiplexing = 0; | ||
592 | |||
593 | /* If the frequency is greater than we can support, we might be able | ||
594 | * to use multiplexing for the video mode */ | ||
595 | if (freq > maxclock) { | ||
596 | switch (cinfo->btype) { | ||
597 | case BT_ALPINE: | ||
598 | case BT_GD5480: | ||
599 | cinfo->multiplexing = 1; | ||
600 | break; | ||
601 | 595 | ||
602 | default: | ||
603 | dev_err(info->device, | ||
604 | "Frequency greater than maxclock (%ld kHz)\n", | ||
605 | maxclock); | ||
606 | return -EINVAL; | ||
607 | } | ||
608 | } | ||
609 | #if 0 | ||
610 | /* TODO: If we have a 1MB 5434, we need to put ourselves in a mode where | ||
611 | * the VCLK is double the pixel clock. */ | ||
612 | switch (var->bits_per_pixel) { | ||
613 | case 16: | ||
614 | case 32: | ||
615 | if (var->xres <= 800) | ||
616 | /* Xbh has this type of clock for 32-bit */ | ||
617 | freq /= 2; | ||
618 | break; | ||
619 | } | ||
620 | #endif | ||
621 | return 0; | 596 | return 0; |
622 | } | 597 | } |
623 | 598 | ||
@@ -653,7 +628,6 @@ static int cirrusfb_set_par_foo(struct fb_info *info) | |||
653 | struct fb_var_screeninfo *var = &info->var; | 628 | struct fb_var_screeninfo *var = &info->var; |
654 | u8 __iomem *regbase = cinfo->regbase; | 629 | u8 __iomem *regbase = cinfo->regbase; |
655 | unsigned char tmp; | 630 | unsigned char tmp; |
656 | int err; | ||
657 | int pitch; | 631 | int pitch; |
658 | const struct cirrusfb_board_info_rec *bi; | 632 | const struct cirrusfb_board_info_rec *bi; |
659 | int hdispend, hsyncstart, hsyncend, htotal; | 633 | int hdispend, hsyncstart, hsyncend, htotal; |
@@ -664,16 +638,28 @@ static int cirrusfb_set_par_foo(struct fb_info *info) | |||
664 | 638 | ||
665 | dev_dbg(info->device, "Requested mode: %dx%dx%d\n", | 639 | dev_dbg(info->device, "Requested mode: %dx%dx%d\n", |
666 | var->xres, var->yres, var->bits_per_pixel); | 640 | var->xres, var->yres, var->bits_per_pixel); |
667 | dev_dbg(info->device, "pixclock: %d\n", var->pixclock); | ||
668 | 641 | ||
669 | init_vgachip(info); | 642 | switch (var->bits_per_pixel) { |
643 | case 1: | ||
644 | info->fix.line_length = var->xres_virtual / 8; | ||
645 | info->fix.visual = FB_VISUAL_MONO10; | ||
646 | break; | ||
670 | 647 | ||
671 | err = cirrusfb_decode_var(var, info); | 648 | case 8: |
672 | if (err) { | 649 | info->fix.line_length = var->xres_virtual; |
673 | /* should never happen */ | 650 | info->fix.visual = FB_VISUAL_PSEUDOCOLOR; |
674 | dev_dbg(info->device, "mode change aborted. invalid var.\n"); | 651 | break; |
675 | return -EINVAL; | 652 | |
653 | case 16: | ||
654 | case 32: | ||
655 | info->fix.line_length = var->xres_virtual * | ||
656 | var->bits_per_pixel >> 3; | ||
657 | info->fix.visual = FB_VISUAL_TRUECOLOR; | ||
658 | break; | ||
676 | } | 659 | } |
660 | info->fix.type = FB_TYPE_PACKED_PIXELS; | ||
661 | |||
662 | init_vgachip(info); | ||
677 | 663 | ||
678 | bi = &cirrusfb_board_info[cinfo->btype]; | 664 | bi = &cirrusfb_board_info[cinfo->btype]; |
679 | 665 | ||
@@ -873,9 +859,6 @@ static int cirrusfb_set_par_foo(struct fb_info *info) | |||
873 | * address wrap, no compat. */ | 859 | * address wrap, no compat. */ |
874 | vga_wcrt(regbase, VGA_CRTC_MODE, 0xc3); | 860 | vga_wcrt(regbase, VGA_CRTC_MODE, 0xc3); |
875 | 861 | ||
876 | /* HAEH? vga_wcrt(regbase, VGA_CRTC_V_SYNC_END, 0x20); | ||
877 | * previously: 0x00 unlock VGA_CRTC_H_TOTAL..CRT7 */ | ||
878 | |||
879 | /* don't know if it would hurt to also program this if no interlaced */ | 862 | /* don't know if it would hurt to also program this if no interlaced */ |
880 | /* mode is used, but I feel better this way.. :-) */ | 863 | /* mode is used, but I feel better this way.. :-) */ |
881 | if (var->vmode & FB_VMODE_INTERLACED) | 864 | if (var->vmode & FB_VMODE_INTERLACED) |
@@ -883,8 +866,6 @@ static int cirrusfb_set_par_foo(struct fb_info *info) | |||
883 | else | 866 | else |
884 | vga_wcrt(regbase, VGA_CRTC_REGS, 0x00); /* interlace control */ | 867 | vga_wcrt(regbase, VGA_CRTC_REGS, 0x00); /* interlace control */ |
885 | 868 | ||
886 | vga_wseq(regbase, VGA_SEQ_CHARACTER_MAP, 0); | ||
887 | |||
888 | /* adjust horizontal/vertical sync type (low/high) */ | 869 | /* adjust horizontal/vertical sync type (low/high) */ |
889 | /* enable display memory & CRTC I/O address for color mode */ | 870 | /* enable display memory & CRTC I/O address for color mode */ |
890 | tmp = 0x03; | 871 | tmp = 0x03; |
@@ -896,8 +877,6 @@ static int cirrusfb_set_par_foo(struct fb_info *info) | |||
896 | tmp |= 0xc; | 877 | tmp |= 0xc; |
897 | WGen(cinfo, VGA_MIS_W, tmp); | 878 | WGen(cinfo, VGA_MIS_W, tmp); |
898 | 879 | ||
899 | /* Screen A Preset Row-Scan register */ | ||
900 | vga_wcrt(regbase, VGA_CRTC_PRESET_ROW, 0); | ||
901 | /* text cursor on and start line */ | 880 | /* text cursor on and start line */ |
902 | vga_wcrt(regbase, VGA_CRTC_CURSOR_START, 0); | 881 | vga_wcrt(regbase, VGA_CRTC_CURSOR_START, 0); |
903 | /* text cursor end line */ | 882 | /* text cursor end line */ |
@@ -1248,7 +1227,6 @@ static int cirrusfb_set_par_foo(struct fb_info *info) | |||
1248 | dev_dbg(info->device, "CRT1e: %d\n", tmp); | 1227 | dev_dbg(info->device, "CRT1e: %d\n", tmp); |
1249 | } | 1228 | } |
1250 | 1229 | ||
1251 | |||
1252 | /* pixel panning */ | 1230 | /* pixel panning */ |
1253 | vga_wattr(regbase, CL_AR33, 0); | 1231 | vga_wattr(regbase, CL_AR33, 0); |
1254 | 1232 | ||
@@ -1274,9 +1252,6 @@ static int cirrusfb_set_par_foo(struct fb_info *info) | |||
1274 | vga_wseq(regbase, VGA_SEQ_CLOCK_MODE, tmp); | 1252 | vga_wseq(regbase, VGA_SEQ_CLOCK_MODE, tmp); |
1275 | dev_dbg(info->device, "CL_SEQR1: %d\n", tmp); | 1253 | dev_dbg(info->device, "CL_SEQR1: %d\n", tmp); |
1276 | 1254 | ||
1277 | /* pan to requested offset */ | ||
1278 | cirrusfb_pan_display(var, info); | ||
1279 | |||
1280 | #ifdef CIRRUSFB_DEBUG | 1255 | #ifdef CIRRUSFB_DEBUG |
1281 | cirrusfb_dbg_reg_dump(info, NULL); | 1256 | cirrusfb_dbg_reg_dump(info, NULL); |
1282 | #endif | 1257 | #endif |
@@ -1332,8 +1307,7 @@ static int cirrusfb_setcolreg(unsigned regno, unsigned red, unsigned green, | |||
1332 | static int cirrusfb_pan_display(struct fb_var_screeninfo *var, | 1307 | static int cirrusfb_pan_display(struct fb_var_screeninfo *var, |
1333 | struct fb_info *info) | 1308 | struct fb_info *info) |
1334 | { | 1309 | { |
1335 | int xoffset = 0; | 1310 | int xoffset; |
1336 | int yoffset = 0; | ||
1337 | unsigned long base; | 1311 | unsigned long base; |
1338 | unsigned char tmp, xpix; | 1312 | unsigned char tmp, xpix; |
1339 | struct cirrusfb_info *cinfo = info->par; | 1313 | struct cirrusfb_info *cinfo = info->par; |
@@ -1347,9 +1321,8 @@ static int cirrusfb_pan_display(struct fb_var_screeninfo *var, | |||
1347 | return -EINVAL; | 1321 | return -EINVAL; |
1348 | 1322 | ||
1349 | xoffset = var->xoffset * info->var.bits_per_pixel / 8; | 1323 | xoffset = var->xoffset * info->var.bits_per_pixel / 8; |
1350 | yoffset = var->yoffset; | ||
1351 | 1324 | ||
1352 | base = yoffset * info->fix.line_length + xoffset; | 1325 | base = var->yoffset * info->fix.line_length + xoffset; |
1353 | 1326 | ||
1354 | if (info->var.bits_per_pixel == 1) { | 1327 | if (info->var.bits_per_pixel == 1) { |
1355 | /* base is already correct */ | 1328 | /* base is already correct */ |
@@ -1363,10 +1336,8 @@ static int cirrusfb_pan_display(struct fb_var_screeninfo *var, | |||
1363 | cirrusfb_WaitBLT(cinfo->regbase); | 1336 | cirrusfb_WaitBLT(cinfo->regbase); |
1364 | 1337 | ||
1365 | /* lower 8 + 8 bits of screen start address */ | 1338 | /* lower 8 + 8 bits of screen start address */ |
1366 | vga_wcrt(cinfo->regbase, VGA_CRTC_START_LO, | 1339 | vga_wcrt(cinfo->regbase, VGA_CRTC_START_LO, base & 0xff); |
1367 | (unsigned char) (base & 0xff)); | 1340 | vga_wcrt(cinfo->regbase, VGA_CRTC_START_HI, (base >> 8) & 0xff); |
1368 | vga_wcrt(cinfo->regbase, VGA_CRTC_START_HI, | ||
1369 | (unsigned char) (base >> 8)); | ||
1370 | 1341 | ||
1371 | /* 0xf2 is %11110010, exclude tmp bits */ | 1342 | /* 0xf2 is %11110010, exclude tmp bits */ |
1372 | tmp = vga_rcrt(cinfo->regbase, CL_CRT1B) & 0xf2; | 1343 | tmp = vga_rcrt(cinfo->regbase, CL_CRT1B) & 0xf2; |
@@ -1544,10 +1515,6 @@ static void init_vgachip(struct fb_info *info) | |||
1544 | 1515 | ||
1545 | /* FullBandwidth (video off) and 8/9 dot clock */ | 1516 | /* FullBandwidth (video off) and 8/9 dot clock */ |
1546 | vga_wseq(cinfo->regbase, VGA_SEQ_CLOCK_MODE, 0x21); | 1517 | vga_wseq(cinfo->regbase, VGA_SEQ_CLOCK_MODE, 0x21); |
1547 | /* polarity (-/-), disable access to display memory, | ||
1548 | * VGA_CRTC_START_HI base address: color | ||
1549 | */ | ||
1550 | WGen(cinfo, VGA_MIS_W, 0xc1); | ||
1551 | 1518 | ||
1552 | /* "magic cookie" - doesn't make any sense to me.. */ | 1519 | /* "magic cookie" - doesn't make any sense to me.. */ |
1553 | /* vga_wgfx(cinfo->regbase, CL_GRA, 0xce); */ | 1520 | /* vga_wgfx(cinfo->regbase, CL_GRA, 0xce); */ |
@@ -1614,10 +1581,6 @@ static void init_vgachip(struct fb_info *info) | |||
1614 | vga_wcrt(cinfo->regbase, VGA_CRTC_CURSOR_START, 0x20); | 1581 | vga_wcrt(cinfo->regbase, VGA_CRTC_CURSOR_START, 0x20); |
1615 | /* Text cursor end: - */ | 1582 | /* Text cursor end: - */ |
1616 | vga_wcrt(cinfo->regbase, VGA_CRTC_CURSOR_END, 0x00); | 1583 | vga_wcrt(cinfo->regbase, VGA_CRTC_CURSOR_END, 0x00); |
1617 | /* Screen start address high: 0 */ | ||
1618 | vga_wcrt(cinfo->regbase, VGA_CRTC_START_HI, 0x00); | ||
1619 | /* Screen start address low: 0 */ | ||
1620 | vga_wcrt(cinfo->regbase, VGA_CRTC_START_LO, 0x00); | ||
1621 | /* text cursor location high: 0 */ | 1584 | /* text cursor location high: 0 */ |
1622 | vga_wcrt(cinfo->regbase, VGA_CRTC_CURSOR_HI, 0x00); | 1585 | vga_wcrt(cinfo->regbase, VGA_CRTC_CURSOR_HI, 0x00); |
1623 | /* text cursor location low: 0 */ | 1586 | /* text cursor location low: 0 */ |
@@ -1625,10 +1588,6 @@ static void init_vgachip(struct fb_info *info) | |||
1625 | 1588 | ||
1626 | /* Underline Row scanline: - */ | 1589 | /* Underline Row scanline: - */ |
1627 | vga_wcrt(cinfo->regbase, VGA_CRTC_UNDERLINE, 0x00); | 1590 | vga_wcrt(cinfo->regbase, VGA_CRTC_UNDERLINE, 0x00); |
1628 | /* mode control: timing enable, byte mode, no compat modes */ | ||
1629 | vga_wcrt(cinfo->regbase, VGA_CRTC_MODE, 0xc3); | ||
1630 | /* Line Compare: not needed */ | ||
1631 | vga_wcrt(cinfo->regbase, VGA_CRTC_LINE_COMPARE, 0x00); | ||
1632 | /* ### add 0x40 for text modes with > 30 MHz pixclock */ | 1591 | /* ### add 0x40 for text modes with > 30 MHz pixclock */ |
1633 | /* ext. display controls: ext.adr. wrap */ | 1592 | /* ext. display controls: ext.adr. wrap */ |
1634 | vga_wcrt(cinfo->regbase, CL_CRT1B, 0x02); | 1593 | vga_wcrt(cinfo->regbase, CL_CRT1B, 0x02); |
@@ -1697,12 +1656,6 @@ static void init_vgachip(struct fb_info *info) | |||
1697 | 1656 | ||
1698 | WGen(cinfo, VGA_PEL_MSK, 0xff); /* Pixel mask: no mask */ | 1657 | WGen(cinfo, VGA_PEL_MSK, 0xff); /* Pixel mask: no mask */ |
1699 | 1658 | ||
1700 | if (cinfo->btype != BT_ALPINE && cinfo->btype != BT_GD5480) | ||
1701 | /* polarity (-/-), enable display mem, | ||
1702 | * VGA_CRTC_START_HI i/o base = color | ||
1703 | */ | ||
1704 | WGen(cinfo, VGA_MIS_W, 0xc3); | ||
1705 | |||
1706 | /* BLT Start/status: Blitter reset */ | 1659 | /* BLT Start/status: Blitter reset */ |
1707 | vga_wgfx(cinfo->regbase, CL_GR31, 0x04); | 1660 | vga_wgfx(cinfo->regbase, CL_GR31, 0x04); |
1708 | /* - " - : "end-of-reset" */ | 1661 | /* - " - : "end-of-reset" */ |
@@ -2052,7 +2005,7 @@ static int __devinit cirrusfb_register(struct fb_info *info) | |||
2052 | 2005 | ||
2053 | info->var.activate = FB_ACTIVATE_NOW; | 2006 | info->var.activate = FB_ACTIVATE_NOW; |
2054 | 2007 | ||
2055 | err = cirrusfb_decode_var(&info->var, info); | 2008 | err = cirrusfb_check_var(&info->var, info); |
2056 | if (err < 0) { | 2009 | if (err < 0) { |
2057 | /* should never happen */ | 2010 | /* should never happen */ |
2058 | dev_dbg(info->device, | 2011 | dev_dbg(info->device, |