X-Git-Url: http://pilppa.org/gitweb/gitweb.cgi?a=blobdiff_plain;f=drivers%2Fvideo%2Fs3fb.c;h=7d53bc23b9c75fac01392afcb4d26421d5f36c03;hb=41d867c9ac852ce17069f8ae680f25877be97942;hp=3091b20124b45eb94d609da9a9702a92e9e1c9c1;hpb=14d21785885c018611efd8aa75a5c11eaea29087;p=linux-2.6-omap-h63xx.git diff --git a/drivers/video/s3fb.c b/drivers/video/s3fb.c index 3091b20124b..7d53bc23b9c 100644 --- a/drivers/video/s3fb.c +++ b/drivers/video/s3fb.c @@ -65,7 +65,7 @@ static const struct svga_fb_format s3fb_formats[] = { static const struct svga_pll s3_pll = {3, 129, 3, 33, 0, 3, - 60000, 240000, 14318}; + 35000, 240000, 14318}; static const int s3_memsizes[] = {4096, 0, 3072, 8192, 2048, 6144, 1024, 512}; @@ -164,7 +164,7 @@ MODULE_PARM_DESC(fasttext, "Enable S3 fast text mode (1=enable, 0=disable, defau static void s3fb_settile_fast(struct fb_info *info, struct fb_tilemap *map) { const u8 *font = map->data; - u8* fb = (u8 *) info->screen_base; + u8 __iomem *fb = (u8 __iomem *) info->screen_base; int i, c; if ((map->width != 8) || (map->height != 16) || @@ -177,20 +177,19 @@ static void s3fb_settile_fast(struct fb_info *info, struct fb_tilemap *map) fb += 2; for (i = 0; i < map->height; i++) { for (c = 0; c < map->length; c++) { - fb[c * 4] = font[c * map->height + i]; + fb_writeb(font[c * map->height + i], fb + c * 4); } fb += 1024; } } - - static struct fb_tile_ops s3fb_tile_ops = { .fb_settile = svga_settile, .fb_tilecopy = svga_tilecopy, .fb_tilefill = svga_tilefill, .fb_tileblit = svga_tileblit, .fb_tilecursor = svga_tilecursor, + .fb_get_tilemax = svga_get_tilemax, }; static struct fb_tile_ops s3fb_fast_tile_ops = { @@ -199,6 +198,7 @@ static struct fb_tile_ops s3fb_fast_tile_ops = { .fb_tilefill = svga_tilefill, .fb_tileblit = svga_tileblit, .fb_tilecursor = svga_tilecursor, + .fb_get_tilemax = svga_get_tilemax, }; @@ -326,8 +326,13 @@ static void s3_set_pixclock(struct fb_info *info, u32 pixclock) { u16 m, n, r; u8 regval; + int rv; - svga_compute_pll(&s3_pll, 1000000000 / pixclock, &m, &n, &r, info->node); + rv = svga_compute_pll(&s3_pll, 1000000000 / pixclock, &m, &n, &r, info->node); + if (rv < 0) { + printk(KERN_ERR "fb%d: cannot set requested pixclock, keeping old value\n", info->node); + return; + } /* Set VGA misc register */ regval = vga_r(NULL, VGA_MIS_R); @@ -395,11 +400,17 @@ static int s3fb_check_var(struct fb_var_screeninfo *var, struct fb_info *info) { struct s3fb_info *par = info->par; int rv, mem, step; + u16 m, n, r; /* Find appropriate format */ rv = svga_match_format (s3fb_formats, var, NULL); - if ((rv < 0) || ((par->chip == CHIP_988_VIRGE_VX) ? (rv == 7) : (rv == 6))) - { /* 24bpp on VIRGE VX, 32bpp on others */ + + /* 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)) + rv = -EINVAL; + + if (rv < 0) { printk(KERN_ERR "fb%d: unsupported mode requested\n", info->node); return rv; } @@ -417,20 +428,26 @@ static int s3fb_check_var(struct fb_var_screeninfo *var, struct fb_info *info) /* Check whether have enough memory */ mem = ((var->bits_per_pixel * var->xres_virtual) >> 3) * var->yres_virtual; - if (mem > info->screen_size) - { + if (mem > info->screen_size) { printk(KERN_ERR "fb%d: not enough framebuffer memory (%d kB requested , %d kB available)\n", info->node, mem >> 10, (unsigned int) (info->screen_size >> 10)); return -EINVAL; } rv = svga_check_timings (&s3_timing_regs, var, info->node); - if (rv < 0) - { + if (rv < 0) { printk(KERN_ERR "fb%d: invalid timings requested\n", info->node); return rv; } + rv = svga_compute_pll(&s3_pll, PICOS2KHZ(var->pixclock), &m, &n, &r, + info->node); + if (rv < 0) { + printk(KERN_ERR "fb%d: invalid pixclock value requested\n", + info->node); + return rv; + } + return 0; } @@ -449,6 +466,10 @@ static int s3fb_set_par(struct fb_info *info) info->flags &= ~FBINFO_MISC_TILEBLITTING; info->tileops = NULL; + /* in 4bpp supports 8p wide tiles only, any tiles otherwise */ + info->pixmap.blit_x = (bpp == 4) ? (1 << (8 - 1)) : (~(u32)0); + info->pixmap.blit_y = ~(u32)0; + offset_value = (info->var.xres_virtual * bpp) / 64; screen_size = info->var.yres_virtual * info->fix.line_length; } else { @@ -458,6 +479,10 @@ static int s3fb_set_par(struct fb_info *info) info->flags |= FBINFO_MISC_TILEBLITTING; info->tileops = fasttext ? &s3fb_fast_tile_ops : &s3fb_tile_ops; + /* supports 8x16 tiles only */ + info->pixmap.blit_x = 1 << (8 - 1); + info->pixmap.blit_y = 1 << (16 - 1); + offset_value = info->var.xres_virtual / 16; screen_size = (info->var.xres_virtual * info->var.yres_virtual) / 64; } @@ -656,7 +681,7 @@ static int s3fb_set_par(struct fb_info *info) value = ((value * hmul) / 8) - 5; vga_wcrt(NULL, 0x3C, (value + 1) / 2); - memset((u8*)info->screen_base, 0x00, screen_size); + memset_io(info->screen_base, 0x00, screen_size); /* Device and screen back on */ svga_wcrt_mask(0x17, 0x80, 0x80); svga_wseq_mask(0x01, 0x00, 0x20); @@ -699,7 +724,7 @@ static int s3fb_setcolreg(u_int regno, u_int red, u_int green, u_int blue, break; case 16: if (regno >= 16) - return -EINVAL; + return 0; if (fb->var.green.length == 5) ((u32*)fb->pseudo_palette)[regno] = ((red & 0xF800) >> 1) | @@ -712,9 +737,9 @@ static int s3fb_setcolreg(u_int regno, u_int red, u_int green, u_int blue, case 24: case 32: if (regno >= 16) - return -EINVAL; + return 0; - ((u32*)fb->pseudo_palette)[regno] = ((transp & 0xFF00) << 16) | ((red & 0xFF00) << 8) | + ((u32*)fb->pseudo_palette)[regno] = ((red & 0xFF00) << 8) | (green & 0xFF00) | ((blue & 0xFF00) >> 8); break; default: @@ -767,12 +792,6 @@ static int s3fb_pan_display(struct fb_var_screeninfo *var, struct fb_info *info) unsigned int offset; - /* Validate the offsets */ - if ((var->xoffset + var->xres) > var->xres_virtual) - return -EINVAL; - if ((var->yoffset + var->yres) > var->yres_virtual) - return -EINVAL; - /* Calculate the offset */ if (var->bits_per_pixel == 0) { offset = (var->yoffset / 16) * (var->xres_virtual / 2) + (var->xoffset / 2); @@ -805,6 +824,7 @@ static struct fb_ops s3fb_ops = { .fb_fillrect = s3fb_fillrect, .fb_copyarea = cfb_copyarea, .fb_imageblit = s3fb_imageblit, + .fb_get_caps = svga_get_caps, }; /* ------------------------------------------------------------------------- */ @@ -1061,6 +1081,7 @@ static int s3_pci_resume(struct pci_dev* dev) { struct fb_info *info = pci_get_drvdata(dev); struct s3fb_info *par = info->par; + int err; dev_info(&(dev->dev), "resume\n"); @@ -1075,7 +1096,13 @@ static int s3_pci_resume(struct pci_dev* dev) pci_set_power_state(dev, PCI_D0); pci_restore_state(dev); - pci_enable_device(dev); + err = pci_enable_device(dev); + if (err) { + mutex_unlock(&(par->open_lock)); + release_console_sem(); + dev_err(&(dev->dev), "error %d enabling device for resume\n", err); + return err; + } pci_set_master(dev); s3fb_set_par(info);