diff options
Diffstat (limited to 'drivers/video/fbdev/s3fb.c')
-rw-r--r-- | drivers/video/fbdev/s3fb.c | 177 |
1 files changed, 123 insertions, 54 deletions
diff --git a/drivers/video/fbdev/s3fb.c b/drivers/video/fbdev/s3fb.c index ff84106ecf1c..ba30e5568cab 100644 --- a/drivers/video/fbdev/s3fb.c +++ b/drivers/video/fbdev/s3fb.c @@ -50,10 +50,14 @@ struct s3fb_info { static const struct svga_fb_format s3fb_formats[] = { { 0, {0, 6, 0}, {0, 6, 0}, {0, 6, 0}, {0, 0, 0}, 0, FB_TYPE_TEXT, FB_AUX_TEXT_SVGA_STEP4, FB_VISUAL_PSEUDOCOLOR, 8, 16}, - { 4, {0, 4, 0}, {0, 4, 0}, {0, 4, 0}, {0, 0, 0}, 0, - FB_TYPE_PACKED_PIXELS, 0, FB_VISUAL_PSEUDOCOLOR, 8, 16}, + { 1, {0, 1, 0}, {0, 1, 0}, {0, 1, 0}, {0, 0, 0}, 2, + FB_TYPE_PACKED_PIXELS, 0, FB_VISUAL_PSEUDOCOLOR, 32, 64}, + { 2, {0, 2, 0}, {0, 2, 0}, {0, 2, 0}, {0, 0, 0}, 2, + FB_TYPE_PACKED_PIXELS, 0, FB_VISUAL_PSEUDOCOLOR, 16, 32}, { 4, {0, 4, 0}, {0, 4, 0}, {0, 4, 0}, {0, 0, 0}, 1, FB_TYPE_INTERLEAVED_PLANES, 1, FB_VISUAL_PSEUDOCOLOR, 8, 16}, + { 4, {0, 4, 0}, {0, 4, 0}, {0, 4, 0}, {0, 0, 0}, 2, + FB_TYPE_PACKED_PIXELS, 0, FB_VISUAL_PSEUDOCOLOR, 8, 16}, { 8, {0, 8, 0}, {0, 8, 0}, {0, 8, 0}, {0, 0, 0}, 0, FB_TYPE_PACKED_PIXELS, 0, FB_VISUAL_PSEUDOCOLOR, 4, 8}, {16, {10, 5, 0}, {5, 5, 0}, {0, 5, 0}, {0, 0, 0}, 0, @@ -557,7 +561,7 @@ static int s3fb_check_var(struct fb_var_screeninfo *var, struct fb_info *info) /* 32bpp mode is not supported on VIRGE VX, 24bpp is not supported on others */ - if ((par->chip == CHIP_988_VIRGE_VX) ? (rv == 7) : (rv == 6)) + if ((par->chip == CHIP_988_VIRGE_VX) ? (rv == 9) : (rv == 8)) rv = -EINVAL; if (rv < 0) { @@ -607,7 +611,7 @@ static int s3fb_set_par(struct fb_info *info) struct s3fb_info *par = info->par; u32 value, mode, hmul, offset_value, screen_size, multiplex, dbytes; u32 bpp = info->var.bits_per_pixel; - u32 htotal, hsstart; + u32 htotal, hsstart, pel_msk; if (bpp != 0) { info->fix.ypanstep = 1; @@ -617,9 +621,11 @@ static int s3fb_set_par(struct fb_info *info) info->tileops = NULL; /* in 4bpp supports 8p wide tiles only, any tiles otherwise */ - if (bpp == 4) { + if (bpp == 4 && (info->var.nonstd & 1) != 0) { + int i; bitmap_zero(info->pixmap.blit_x, FB_MAX_BLIT_WIDTH); - set_bit(8 - 1, info->pixmap.blit_x); + for (i = 8; i <= FB_MAX_BLIT_WIDTH; i += 8) + set_bit(i - 1, info->pixmap.blit_x); } else { bitmap_fill(info->pixmap.blit_x, FB_MAX_BLIT_WIDTH); } @@ -730,7 +736,7 @@ static int s3fb_set_par(struct fb_info *info) vga_wcrt(par->state.vgabase, 0x50, 0x00); vga_wcrt(par->state.vgabase, 0x67, 0x50); msleep(10); /* screen remains blank sometimes without this */ - vga_wcrt(par->state.vgabase, 0x63, (mode <= 2) ? 0x90 : 0x09); + vga_wcrt(par->state.vgabase, 0x63, (mode <= 4) ? 0x90 : 0x09); vga_wcrt(par->state.vgabase, 0x66, 0x90); } @@ -763,12 +769,17 @@ static int s3fb_set_par(struct fb_info *info) svga_wcrt_mask(par->state.vgabase, 0x31, 0x00, 0x40); multiplex = 0; hmul = 1; + pel_msk = 0xff; + + svga_wcrt_mask(par->state.vgabase, 0x08, 0x00, 0x60); + svga_wcrt_mask(par->state.vgabase, 0x05, 0x00, 0x60); /* Set mode-specific register values */ switch (mode) { case 0: fb_dbg(info, "text mode\n"); svga_set_textmode_vga_regs(par->state.vgabase); + pel_msk = 0x0f; /* Set additional registers like in 8-bit mode */ svga_wcrt_mask(par->state.vgabase, 0x50, 0x00, 0x30); @@ -783,8 +794,11 @@ static int s3fb_set_par(struct fb_info *info) } break; case 1: - fb_dbg(info, "4 bit pseudocolor\n"); - vga_wgfx(par->state.vgabase, VGA_GFX_MODE, 0x40); + fb_dbg(info, "1 bit pseudocolor\n"); + svga_wseq_mask(par->state.vgabase, 0x01, 0x10, 0x14); + svga_wcrt_mask(par->state.vgabase, 0x08, 0x60, 0x60); + svga_wcrt_mask(par->state.vgabase, 0x05, 0x40, 0x60); + pel_msk = 0x01; /* Set additional registers like in 8-bit mode */ svga_wcrt_mask(par->state.vgabase, 0x50, 0x00, 0x30); @@ -794,7 +808,13 @@ static int s3fb_set_par(struct fb_info *info) svga_wcrt_mask(par->state.vgabase, 0x3A, 0x00, 0x30); break; case 2: - fb_dbg(info, "4 bit pseudocolor, planar\n"); + fb_dbg(info, "2 bit pseudocolor\n"); + svga_wseq_mask(par->state.vgabase, 0x01, 0x04, 0x14); + svga_wseq_mask(par->state.vgabase, 0x04, 0x08, 0x08); + vga_wgfx(par->state.vgabase, VGA_GFX_MODE, 0x20); + svga_wcrt_mask(par->state.vgabase, 0x08, 0x20, 0x60); + svga_wcrt_mask(par->state.vgabase, 0x05, 0x40, 0x60); + pel_msk = 0x03; /* Set additional registers like in 8-bit mode */ svga_wcrt_mask(par->state.vgabase, 0x50, 0x00, 0x30); @@ -804,8 +824,35 @@ static int s3fb_set_par(struct fb_info *info) svga_wcrt_mask(par->state.vgabase, 0x3A, 0x00, 0x30); break; case 3: + fb_dbg(info, "4 bit pseudocolor, planar\n"); + pel_msk = 0x0f; + + /* Set additional registers like in 8-bit mode */ + svga_wcrt_mask(par->state.vgabase, 0x50, 0x00, 0x30); + svga_wcrt_mask(par->state.vgabase, 0x67, 0x00, 0xF0); + svga_wcrt_mask(par->state.vgabase, 0x05, 0x40, 0x60); + + /* disable enhanced mode */ + svga_wcrt_mask(par->state.vgabase, 0x3A, 0x00, 0x30); + break; + case 4: + fb_dbg(info, "4 bit pseudocolor\n"); + vga_wgfx(par->state.vgabase, VGA_GFX_MODE, 0x40); + svga_wattr(par->state.vgabase, 0x33, 0x01); + svga_wcrt_mask(par->state.vgabase, 0x05, 0x40, 0x60); + pel_msk = 0xf0; + + /* Set additional registers like in 8-bit mode */ + svga_wcrt_mask(par->state.vgabase, 0x50, 0x00, 0x30); + svga_wcrt_mask(par->state.vgabase, 0x67, 0x00, 0xF0); + + /* disable enhanced mode */ + svga_wcrt_mask(par->state.vgabase, 0x3A, 0x00, 0x30); + break; + case 5: fb_dbg(info, "8 bit pseudocolor\n"); svga_wcrt_mask(par->state.vgabase, 0x50, 0x00, 0x30); + svga_wcrt_mask(par->state.vgabase, 0x05, 0x20, 0x60); if (info->var.pixclock > 20000 || par->chip == CHIP_357_VIRGE_GX2 || par->chip == CHIP_359_VIRGE_GX2P || @@ -819,7 +866,7 @@ static int s3fb_set_par(struct fb_info *info) multiplex = 1; } break; - case 4: + case 6: fb_dbg(info, "5/5/5 truecolor\n"); if (par->chip == CHIP_988_VIRGE_VX) { if (info->var.pixclock > 20000) @@ -847,7 +894,7 @@ static int s3fb_set_par(struct fb_info *info) hmul = 2; } break; - case 5: + case 7: fb_dbg(info, "5/6/5 truecolor\n"); if (par->chip == CHIP_988_VIRGE_VX) { if (info->var.pixclock > 20000) @@ -875,12 +922,12 @@ static int s3fb_set_par(struct fb_info *info) hmul = 2; } break; - case 6: + case 8: /* VIRGE VX case */ fb_dbg(info, "8/8/8 truecolor\n"); svga_wcrt_mask(par->state.vgabase, 0x67, 0xD0, 0xF0); break; - case 7: + case 9: fb_dbg(info, "8/8/8/8 truecolor\n"); svga_wcrt_mask(par->state.vgabase, 0x50, 0x30, 0x30); svga_wcrt_mask(par->state.vgabase, 0x67, 0xD0, 0xF0); @@ -889,6 +936,7 @@ static int s3fb_set_par(struct fb_info *info) fb_err(info, "unsupported mode - bug\n"); return -EINVAL; } + vga_w(par->state.vgabase, VGA_PEL_MSK, pel_msk); if (par->chip != CHIP_988_VIRGE_VX) { svga_wseq_mask(par->state.vgabase, 0x15, multiplex ? 0x10 : 0x00, 0x10); @@ -927,33 +975,26 @@ static int s3fb_set_par(struct fb_info *info) static int s3fb_setcolreg(u_int regno, u_int red, u_int green, u_int blue, u_int transp, struct fb_info *fb) { + struct s3fb_info *par = fb->par; + int cols; + switch (fb->var.bits_per_pixel) { case 0: + case 1: + case 2: case 4: - if (regno >= 16) - return -EINVAL; - - if ((fb->var.bits_per_pixel == 4) && - (fb->var.nonstd == 0)) { - outb(0xF0, VGA_PEL_MSK); - outb(regno*16, VGA_PEL_IW); - } else { - outb(0x0F, VGA_PEL_MSK); - outb(regno, VGA_PEL_IW); - } - outb(red >> 10, VGA_PEL_D); - outb(green >> 10, VGA_PEL_D); - outb(blue >> 10, VGA_PEL_D); - break; case 8: - if (regno >= 256) + cols = 1 << (fb->var.bits_per_pixel ? fb->var.bits_per_pixel : 4); + if (regno >= cols) return -EINVAL; - outb(0xFF, VGA_PEL_MSK); - outb(regno, VGA_PEL_IW); - outb(red >> 10, VGA_PEL_D); - outb(green >> 10, VGA_PEL_D); - outb(blue >> 10, VGA_PEL_D); + if ((fb->var.bits_per_pixel == 4) && ((fb->var.nonstd & 1) == 0)) + regno <<= 4; + + vga_w(par->state.vgabase, VGA_PEL_IW, regno); + vga_w(par->state.vgabase, VGA_PEL_D, red >> 10); + vga_w(par->state.vgabase, VGA_PEL_D, green >> 10); + vga_w(par->state.vgabase, VGA_PEL_D, blue >> 10); break; case 16: if (regno >= 16) @@ -988,34 +1029,30 @@ static int s3fb_setcolreg(u_int regno, u_int red, u_int green, u_int blue, static int s3fb_blank(int blank_mode, struct fb_info *info) { struct s3fb_info *par = info->par; + u8 data; + + data = (blank_mode == FB_BLANK_UNBLANK) ? 0x00 : 0x20; + svga_wseq_mask(par->state.vgabase, 0x01, data, 0x20); + svga_wseq_mask(par->state.vgabase, 0x18, data, 0x20); switch (blank_mode) { - case FB_BLANK_UNBLANK: - fb_dbg(info, "unblank\n"); - svga_wcrt_mask(par->state.vgabase, 0x56, 0x00, 0x06); - svga_wseq_mask(par->state.vgabase, 0x01, 0x00, 0x20); - break; - case FB_BLANK_NORMAL: - fb_dbg(info, "blank\n"); - svga_wcrt_mask(par->state.vgabase, 0x56, 0x00, 0x06); - svga_wseq_mask(par->state.vgabase, 0x01, 0x20, 0x20); + default: + data = 0x00; break; case FB_BLANK_HSYNC_SUSPEND: - fb_dbg(info, "hsync\n"); - svga_wcrt_mask(par->state.vgabase, 0x56, 0x02, 0x06); - svga_wseq_mask(par->state.vgabase, 0x01, 0x20, 0x20); + data = 0x02; break; case FB_BLANK_VSYNC_SUSPEND: - fb_dbg(info, "vsync\n"); - svga_wcrt_mask(par->state.vgabase, 0x56, 0x04, 0x06); - svga_wseq_mask(par->state.vgabase, 0x01, 0x20, 0x20); + data = 0x04; break; case FB_BLANK_POWERDOWN: - fb_dbg(info, "sync down\n"); - svga_wcrt_mask(par->state.vgabase, 0x56, 0x06, 0x06); - svga_wseq_mask(par->state.vgabase, 0x01, 0x20, 0x20); + data = 0x06; break; } + svga_wcrt_mask(par->state.vgabase, 0x56, data, 0x06); + + data = (blank_mode == FB_BLANK_POWERDOWN) ? 0x01 : 0x00; + svga_wseq_mask(par->state.vgabase, 0x14, data, 0x01); return 0; } @@ -1045,6 +1082,33 @@ static int s3fb_pan_display(struct fb_var_screeninfo *var, struct fb_info *info) return 0; } +/* Get capabilities of accelerator based on the mode */ + +static void s3fb_get_caps(struct fb_info *info, struct fb_blit_caps *caps, + struct fb_var_screeninfo *var) +{ + int i; + + if (var->bits_per_pixel == 0) { + /* can only support 256 8x16 bitmap */ + bitmap_zero(caps->x, FB_MAX_BLIT_WIDTH); + set_bit(8 - 1, caps->x); + bitmap_zero(caps->y, FB_MAX_BLIT_HEIGHT); + set_bit(16 - 1, caps->y); + caps->len = 256; + } else { + if (var->bits_per_pixel == 4 && (var->nonstd & 1) != 0) { + bitmap_zero(caps->x, FB_MAX_BLIT_WIDTH); + for (i = 8; i <= FB_MAX_BLIT_WIDTH; i += 8) + set_bit(i - 1, caps->x); + } else { + bitmap_fill(caps->x, FB_MAX_BLIT_WIDTH); + } + bitmap_fill(caps->y, FB_MAX_BLIT_HEIGHT); + caps->len = ~(u32)0; + } +} + /* ------------------------------------------------------------------------- */ /* Frame buffer operations */ @@ -1063,7 +1127,7 @@ static const struct fb_ops s3fb_ops = { .fb_copyarea = cfb_copyarea, .fb_imageblit = s3fb_imageblit, __FB_DEFAULT_IOMEM_OPS_MMAP, - .fb_get_caps = svga_get_caps, + .fb_get_caps = s3fb_get_caps, }; /* ------------------------------------------------------------------------- */ @@ -1445,6 +1509,8 @@ static int __maybe_unused s3_pci_suspend(struct device *dev) } fb_set_suspend(info, 1); + svga_wseq_mask(par->state.vgabase, 0x18, 0x20, 0x20); + svga_wseq_mask(par->state.vgabase, 0x14, 0x01, 0x01); mutex_unlock(&(par->open_lock)); console_unlock(); @@ -1471,6 +1537,9 @@ static int __maybe_unused s3_pci_resume(struct device *dev) return 0; } + vga_wseq(par->state.vgabase, 0x08, 0x06); + svga_wseq_mask(par->state.vgabase, 0x18, 0x00, 0x20); + svga_wseq_mask(par->state.vgabase, 0x14, 0x00, 0x01); s3fb_set_par(info); fb_set_suspend(info, 0); |