summaryrefslogtreecommitdiff
path: root/drivers/video/fbdev/s3fb.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/video/fbdev/s3fb.c')
-rw-r--r--drivers/video/fbdev/s3fb.c177
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);