Fedora kernel-2.6.17-1.2142_FC4 patched with stable patch-2.6.17.4-vs2.0.2-rc26.diff
[linux-2.6.git] / drivers / video / tdfxfb.c
index 503ecc3..5e5328d 100644 (file)
@@ -89,7 +89,7 @@
 #define VOODOO3_MAX_PIXCLOCK 300000
 #define VOODOO5_MAX_PIXCLOCK 350000
 
-static struct fb_fix_screeninfo tdfx_fix __initdata = {
+static struct fb_fix_screeninfo tdfx_fix __devinitdata = {
        .id =           "3Dfx",
        .type =         FB_TYPE_PACKED_PIXELS,
        .visual =       FB_VISUAL_PSEUDOCOLOR, 
@@ -98,7 +98,7 @@ static struct fb_fix_screeninfo tdfx_fix __initdata = {
        .accel =        FB_ACCEL_3DFX_BANSHEE
 };
 
-static struct fb_var_screeninfo tdfx_var __initdata = {
+static struct fb_var_screeninfo tdfx_var __devinitdata = {
        /* "640x480, 8 bpp @ 60 Hz */
        .xres =         640,
        .yres =         480,
@@ -154,9 +154,6 @@ MODULE_DEVICE_TABLE(pci, tdfxfb_id_table);
 /*
  *  Frame buffer device API
  */
-int tdfxfb_init(void);
-void tdfxfb_setup(char *options);
-
 static int tdfxfb_check_var(struct fb_var_screeninfo *var, struct fb_info *fb); 
 static int tdfxfb_set_par(struct fb_info *info); 
 static int tdfxfb_setcolreg(u_int regno, u_int red, u_int green, u_int blue, 
@@ -187,7 +184,6 @@ static struct fb_ops tdfxfb_ops = {
        .fb_copyarea    = cfb_copyarea,
        .fb_imageblit   = cfb_imageblit,
 #endif
-       .fb_cursor      = soft_cursor,
 };
 
 /*
@@ -202,8 +198,7 @@ static unsigned long do_lfb_size(struct tdfx_par *par, unsigned short);
  */
 static int  nopan   = 0;
 static int  nowrap  = 1;      // not implemented (yet)
-static int  inverse = 0;
-static char *mode_option __initdata = NULL;
+static char *mode_option __devinitdata = NULL;
 
 /* ------------------------------------------------------------------------- 
  *                      Hardware-specific funcions
@@ -211,41 +206,21 @@ static char *mode_option __initdata = NULL;
 
 #ifdef VGA_REG_IO 
 static inline  u8 vga_inb(struct tdfx_par *par, u32 reg) { return inb(reg); }
-static inline u16 vga_inw(struct tdfx_par *par, u32 reg) { return inw(reg); }
-static inline u16 vga_inl(struct tdfx_par *par, u32 reg) { return inl(reg); }
 
 static inline void vga_outb(struct tdfx_par *par, u32 reg,  u8 val) { outb(val, reg); }
-static inline void vga_outw(struct tdfx_par *par, u32 reg, u16 val) { outw(val, reg); }
-static inline void vga_outl(struct tdfx_par *par, u32 reg, u32 val) { outl(val, reg); }
 #else
 static inline  u8 vga_inb(struct tdfx_par *par, u32 reg) { 
        return inb(par->iobase + reg - 0x300); 
 }
-static inline u16 vga_inw(struct tdfx_par *par, u32 reg) { 
-       return inw(par->iobase + reg - 0x300); 
-}
-static inline u16 vga_inl(struct tdfx_par *par, u32 reg) { 
-       return inl(par->iobase + reg - 0x300); 
-}
 static inline void vga_outb(struct tdfx_par *par, u32 reg,  u8 val) { 
        outb(val, par->iobase + reg - 0x300); 
 }
-static inline void vga_outw(struct tdfx_par *par, u32 reg, u16 val) { 
-       outw(val, par->iobase + reg - 0x300); 
-}
-static inline void vga_outl(struct tdfx_par *par, u32 reg, u32 val) { 
-       outl(val, par->iobase + reg - 0x300); 
-}
 #endif
 
 static inline void gra_outb(struct tdfx_par *par, u32 idx, u8 val) {
        vga_outb(par, GRA_I, idx); vga_outb(par, GRA_D, val);
 }
 
-static inline u8 gra_inb(struct tdfx_par *par, u32 idx) {
-       vga_outb(par, GRA_I, idx); return vga_inb(par, GRA_D);
-}
-
 static inline void seq_outb(struct tdfx_par *par, u32 idx, u8 val) {
        vga_outb(par, SEQ_I, idx); vga_outb(par, SEQ_D, val);
 }
@@ -271,15 +246,6 @@ static inline void att_outb(struct tdfx_par *par, u32 idx, u8 val)
        vga_outb(par, ATT_IW, val);
 }
 
-static inline u8 att_inb(struct tdfx_par *par, u32 idx) 
-{
-       unsigned char tmp;
-
-       tmp = vga_inb(par, IS1_R);
-       vga_outb(par, ATT_IW, idx);
-       return vga_inb(par, ATT_IW);
-}
-
 static inline void vga_disable_video(struct tdfx_par *par)
 {
        unsigned char s;
@@ -300,12 +266,6 @@ static inline void vga_enable_video(struct tdfx_par *par)
        seq_outb(par, 0x00, 0x03);
 }
 
-static inline void vga_disable_palette(struct tdfx_par *par)
-{
-       vga_inb(par, IS1_R);
-       vga_outb(par, ATT_IW, 0x00);
-}
-
 static inline void vga_enable_palette(struct tdfx_par *par)
 {
        vga_inb(par, IS1_R);
@@ -331,7 +291,7 @@ static inline void banshee_make_room(struct tdfx_par *par, int size)
  
 static int banshee_wait_idle(struct fb_info *info)
 {
-       struct tdfx_par *par = (struct tdfx_par *) info->par; 
+       struct tdfx_par *par = info->par;
        int i = 0;
 
        banshee_make_room(par, 1);
@@ -356,36 +316,55 @@ static inline void do_setpalentry(struct tdfx_par *par, unsigned regno, u32 c)
 
 static u32 do_calc_pll(int freq, int* freq_out) 
 {
-       int m, n, k, best_m, best_n, best_k, f_cur, best_error;
+       int m, n, k, best_m, best_n, best_k, best_error;
        int fref = 14318;
   
-       /* this really could be done with more intelligence --
-          255*63*4 = 64260 iterations is silly */
        best_error = freq;
        best_n = best_m = best_k = 0;
-       for (n = 1; n < 256; n++) {
-               for (m = 1; m < 64; m++) {
-                       for (k = 0; k < 4; k++) {
-                               f_cur = fref*(n + 2)/(m + 2)/(1 << k);
-                               if (abs(f_cur - freq) < best_error) {
-                                       best_error = abs(f_cur-freq);
-                                       best_n = n;
-                                       best_m = m;
-                                       best_k = k;
+
+       for (k = 3; k >= 0; k--) {
+               for (m = 63; m >= 0; m--) {
+                       /*
+                        * Estimate value of n that produces target frequency
+                        * with current m and k
+                        */
+                       int n_estimated = (freq * (m + 2) * (1 << k) / fref) - 2;
+
+                       /* Search neighborhood of estimated n */
+                       for (n = max(0, n_estimated - 1);
+                                       n <= min(255, n_estimated + 1); n++) {
+                               /*
+                                * Calculate PLL freqency with current m, k and
+                                * estimated n
+                                */
+                               int f = fref * (n + 2) / (m + 2) / (1 << k);
+                               int error = abs (f - freq);
+
+                               /*
+                                *  If this is the closest we've come to the
+                                * target frequency then remember n, m and k
+                                */
+                               if (error  < best_error) {
+                                       best_error = error;
+                                       best_n     = n;
+                                       best_m     = m;
+                                       best_k     = k;
                                }
                        }
                }
        }
+
        n = best_n;
        m = best_m;
        k = best_k;
        *freq_out = fref*(n + 2)/(m + 2)/(1 << k);
+
        return (n << 8) | (m << 2) | k;
 }
 
 static void do_write_regs(struct fb_info *info, struct banshee_reg* reg) 
 {
-       struct tdfx_par *par = (struct tdfx_par *) info->par; 
+       struct tdfx_par *par = info->par;
        int i;
 
        banshee_wait_idle(info);
@@ -450,36 +429,35 @@ static void do_write_regs(struct fb_info *info, struct banshee_reg* reg)
 
 static unsigned long do_lfb_size(struct tdfx_par *par, unsigned short dev_id) 
 {
-       u32 draminit0 = 0;
-       u32 draminit1 = 0;
-       u32 miscinit1 = 0;
-       u32 lfbsize   = 0;
-       int sgram_p   = 0;
+       u32 draminit0;
+       u32 draminit1;
+       u32 miscinit1;
+
+       int num_chips;
+       int chip_size; /* in MB */
+       u32 lfbsize;
+       int has_sgram;
 
        draminit0 = tdfx_inl(par, DRAMINIT0);  
        draminit1 = tdfx_inl(par, DRAMINIT1);
+
+       num_chips = (draminit0 & DRAMINIT0_SGRAM_NUM) ? 8 : 4;
  
-       if ((dev_id == PCI_DEVICE_ID_3DFX_BANSHEE) ||
-           (dev_id == PCI_DEVICE_ID_3DFX_VOODOO3)) {                    
-               sgram_p = (draminit1 & DRAMINIT1_MEM_SDRAM) ? 0 : 1;
-  
-       lfbsize = sgram_p ?
-               (((draminit0 & DRAMINIT0_SGRAM_NUM)  ? 2 : 1) * 
-               ((draminit0 & DRAMINIT0_SGRAM_TYPE) ? 8 : 4) * 1024 * 1024) :
-               16 * 1024 * 1024;
+       if (dev_id < PCI_DEVICE_ID_3DFX_VOODOO5) {
+               /* Banshee/Voodoo3 */
+               has_sgram = draminit1 & DRAMINIT1_MEM_SDRAM;
+               chip_size = has_sgram ? ((draminit0 & DRAMINIT0_SGRAM_TYPE) ? 2 : 1)
+                                     : 2;
        } else {
                /* Voodoo4/5 */
-               u32 chips, psize, banks;
-
-               chips = ((draminit0 & (1 << 26)) == 0) ? 4 : 8;
-               psize = 1 << ((draminit0 & 0x38000000) >> 28);
-               banks = ((draminit0 & (1 << 30)) == 0) ? 2 : 4;
-               lfbsize = chips * psize * banks;
-               lfbsize <<= 20;
-       }                 
-       /* disable block writes for SDRAM (why?) */
+               has_sgram = 0;
+               chip_size = 1 << ((draminit0 & DRAMINIT0_SGRAM_TYPE_MASK) >> DRAMINIT0_SGRAM_TYPE_SHIFT);
+       }
+       lfbsize = num_chips * chip_size * 1024 * 1024;
+
+       /* disable block writes for SDRAM */
        miscinit1 = tdfx_inl(par, MISCINIT1);
-       miscinit1 |= sgram_p ? 0 : MISCINIT1_2DBLOCK_DIS;
+       miscinit1 |= has_sgram ? 0 : MISCINIT1_2DBLOCK_DIS;
        miscinit1 |= MISCINIT1_CLUT_INV;
 
        banshee_make_room(par, 1); 
@@ -491,7 +469,7 @@ static unsigned long do_lfb_size(struct tdfx_par *par, unsigned short dev_id)
 
 static int tdfxfb_check_var(struct fb_var_screeninfo *var,struct fb_info *info) 
 {
-       struct tdfx_par *par = (struct tdfx_par *) info->par; 
+       struct tdfx_par *par = info->par;
        u32 lpitch;
 
        if (var->bits_per_pixel != 8  && var->bits_per_pixel != 16 &&
@@ -580,7 +558,7 @@ static int tdfxfb_check_var(struct fb_var_screeninfo *var,struct fb_info *info)
 
 static int tdfxfb_set_par(struct fb_info *info)
 {
-       struct tdfx_par *par = (struct tdfx_par *) info->par;   
+       struct tdfx_par *par = info->par;
        u32 hdispend, hsyncsta, hsyncend, htotal;
        u32 hd, hs, he, ht, hbs, hbe;
        u32 vd, vs, ve, vt, vbs, vbe;
@@ -802,59 +780,67 @@ static int tdfxfb_set_par(struct fb_info *info)
 static int tdfxfb_setcolreg(unsigned regno, unsigned red, unsigned green,  
                            unsigned blue,unsigned transp,struct fb_info *info) 
 {
-       struct tdfx_par *par = (struct tdfx_par *) info->par;
+       struct tdfx_par *par = info->par;
        u32 rgbcol;
    
        if (regno >= info->cmap.len || regno > 255) return 1;
    
        switch (info->fix.visual) {
-               case FB_VISUAL_PSEUDOCOLOR:
-                       rgbcol =(((u32)red   & 0xff00) << 8) |
-                               (((u32)green & 0xff00) << 0) |
-                               (((u32)blue  & 0xff00) >> 8);
-                       do_setpalentry(par, regno, rgbcol);
-                       break;
-               /* Truecolor has no hardware color palettes. */
-               case FB_VISUAL_TRUECOLOR:
-                       rgbcol = (CNVT_TOHW( red, info->var.red.length) << info->var.red.offset) |
-                                (CNVT_TOHW( green, info->var.green.length) << info->var.green.offset) |
-                                (CNVT_TOHW( blue, info->var.blue.length) << info->var.blue.offset) |
-                                (CNVT_TOHW( transp, info->var.transp.length) << info->var.transp.offset);
-                               ((u32*)(info->pseudo_palette))[regno] = rgbcol;
-                       break;
-               default:
-                       DPRINTK("bad depth %u\n", info->var.bits_per_pixel);
-                       break;
+       case FB_VISUAL_PSEUDOCOLOR:
+               rgbcol =(((u32)red   & 0xff00) << 8) |
+                       (((u32)green & 0xff00) << 0) |
+                       (((u32)blue  & 0xff00) >> 8);
+               do_setpalentry(par, regno, rgbcol);
+               break;
+       /* Truecolor has no hardware color palettes. */
+       case FB_VISUAL_TRUECOLOR:
+               if (regno < 16) {
+                       rgbcol = (CNVT_TOHW( red, info->var.red.length) <<
+                                 info->var.red.offset) |
+                               (CNVT_TOHW( green, info->var.green.length) <<
+                                info->var.green.offset) |
+                               (CNVT_TOHW( blue, info->var.blue.length) <<
+                                info->var.blue.offset) |
+                               (CNVT_TOHW( transp, info->var.transp.length) <<
+                                info->var.transp.offset);
+                       par->palette[regno] = rgbcol;
+               }
+
+               break;
+       default:
+               DPRINTK("bad depth %u\n", info->var.bits_per_pixel);
+               break;
        }
+
        return 0;
 }
 
 /* 0 unblank, 1 blank, 2 no vsync, 3 no hsync, 4 off */
 static int tdfxfb_blank(int blank, struct fb_info *info)
 { 
-       struct tdfx_par *par = (struct tdfx_par *) info->par;
+       struct tdfx_par *par = info->par;
        u32 dacmode, state = 0, vgablank = 0;
 
        dacmode = tdfx_inl(par, DACMODE);
 
        switch (blank) {
-               case 0: /* Screen: On; HSync: On, VSync: On */    
+               case FB_BLANK_UNBLANK: /* Screen: On; HSync: On, VSync: On */
                        state    = 0;
                        vgablank = 0;
                        break;
-               case 1: /* Screen: Off; HSync: On, VSync: On */
+               case FB_BLANK_NORMAL: /* Screen: Off; HSync: On, VSync: On */
                        state    = 0;
                        vgablank = 1;
                        break;
-               case 2: /* Screen: Off; HSync: On, VSync: Off */
+               case FB_BLANK_VSYNC_SUSPEND: /* Screen: Off; HSync: On, VSync: Off */
                        state    = BIT(3);
                        vgablank = 1;
                        break;
-               case 3: /* Screen: Off; HSync: Off, VSync: On */
+               case FB_BLANK_HSYNC_SUSPEND: /* Screen: Off; HSync: Off, VSync: On */
                        state    = BIT(1);
                        vgablank = 1;
                        break;
-               case 4: /* Screen: Off; HSync: Off, VSync: Off */
+               case FB_BLANK_POWERDOWN: /* Screen: Off; HSync: Off, VSync: Off */
                        state    = BIT(1) | BIT(3);
                        vgablank = 1;
                        break;
@@ -877,7 +863,7 @@ static int tdfxfb_blank(int blank, struct fb_info *info)
 static int tdfxfb_pan_display(struct fb_var_screeninfo *var,
                              struct fb_info *info) 
 {
-       struct tdfx_par *par = (struct tdfx_par *) info->par;
+       struct tdfx_par *par = info->par;
        u32 addr;       
 
        if (nopan || var->xoffset || (var->yoffset > var->yres_virtual))
@@ -900,7 +886,7 @@ static int tdfxfb_pan_display(struct fb_var_screeninfo *var,
  */
 static void tdfxfb_fillrect(struct fb_info *info, const struct fb_fillrect *rect) 
 {
-       struct tdfx_par *par = (struct tdfx_par *) info->par;
+       struct tdfx_par *par = info->par;
        u32 bpp = info->var.bits_per_pixel;
        u32 stride = info->fix.line_length;
        u32 fmt= stride | ((bpp+((bpp==8) ? 0 : 8)) << 13); 
@@ -916,12 +902,11 @@ static void tdfxfb_fillrect(struct fb_info *info, const struct fb_fillrect *rect
        if (info->fix.visual == FB_VISUAL_PSEUDOCOLOR) {
                tdfx_outl(par,  COLORFORE, rect->color);
        } else { /* FB_VISUAL_TRUECOLOR */
-               tdfx_outl(par, COLORFORE, ((u32*)(info->pseudo_palette))[rect->color]);
+               tdfx_outl(par, COLORFORE, par->palette[rect->color]);
        }
        tdfx_outl(par,  COMMAND_2D, COMMAND_2D_FILLRECT | (tdfx_rop << 24));
        tdfx_outl(par,  DSTSIZE,    rect->width | (rect->height << 16));
        tdfx_outl(par,  LAUNCH_2D,  rect->dx | (rect->dy << 16));
-       banshee_wait_idle(info);
 }
 
 /*
@@ -929,7 +914,7 @@ static void tdfxfb_fillrect(struct fb_info *info, const struct fb_fillrect *rect
  */
 static void tdfxfb_copyarea(struct fb_info *info, const struct fb_copyarea *area)  
 {
-       struct tdfx_par *par = (struct tdfx_par *) info->par;
+       struct tdfx_par *par = info->par;
        u32 sx = area->sx, sy = area->sy, dx = area->dx, dy = area->dy;
        u32 bpp = info->var.bits_per_pixel;
        u32 stride = info->fix.line_length;
@@ -957,12 +942,11 @@ static void tdfxfb_copyarea(struct fb_info *info, const struct fb_copyarea *area
        tdfx_outl(par,  DSTSIZE,   area->width | (area->height << 16));
        tdfx_outl(par,  DSTXY,     dx | (dy << 16));
        tdfx_outl(par,  LAUNCH_2D, sx | (sy << 16)); 
-       banshee_wait_idle(info);
 }
 
 static void tdfxfb_imageblit(struct fb_info *info, const struct fb_image *image) 
 {
-       struct tdfx_par *par = (struct tdfx_par *) info->par;
+       struct tdfx_par *par = info->par;
        int size = image->height * ((image->width * image->depth + 7)>>3);
        int fifo_free;
        int i, stride = info->fix.line_length;
@@ -985,8 +969,10 @@ static void tdfxfb_imageblit(struct fb_info *info, const struct fb_image *image)
                                break;
                        case FB_VISUAL_TRUECOLOR:
                        default:
-                               tdfx_outl(par, COLORFORE, ((u32*)(info->pseudo_palette))[image->fg_color]);
-                               tdfx_outl(par, COLORBACK, ((u32*)(info->pseudo_palette))[image->bg_color]);
+                               tdfx_outl(par, COLORFORE,
+                                         par->palette[image->fg_color]);
+                               tdfx_outl(par, COLORBACK,
+                                         par->palette[image->bg_color]);
                }
 #ifdef __BIG_ENDIAN
                srcfmt = 0x400000 | BIT(20);
@@ -1025,14 +1011,13 @@ static void tdfxfb_imageblit(struct fb_info *info, const struct fb_image *image)
                case 2:  tdfx_outl(par, LAUNCH_2D,*(u16*)chardata); break;
                case 3:  tdfx_outl(par, LAUNCH_2D,*(u16*)chardata | ((chardata[3]) << 24)); break;
        }
-       banshee_wait_idle(info);
 }
 #endif /* CONFIG_FB_3DFX_ACCEL */
 
 #ifdef TDFX_HARDWARE_CURSOR
 static int tdfxfb_cursor(struct fb_info *info, struct fb_cursor *cursor)
 {
-       struct tdfx_par *par = (struct tdfx_par *) info->par;
+       struct tdfx_par *par = info->par;
        unsigned long flags;
 
        /*
@@ -1182,18 +1167,17 @@ static int __devinit tdfxfb_probe(struct pci_dev *pdev,
 {
        struct tdfx_par *default_par;
        struct fb_info *info;
-       int size, err, lpitch;
+       int err, lpitch;
 
        if ((err = pci_enable_device(pdev))) {
                printk(KERN_WARNING "tdfxfb: Can't enable pdev: %d\n", err);
                return err;
        }
 
-       size = sizeof(struct tdfx_par)+256*sizeof(u32);
-
-       info = framebuffer_alloc(size, &pdev->dev);
+       info = framebuffer_alloc(sizeof(struct tdfx_par), &pdev->dev);
 
-       if (!info)      return -ENOMEM;
+       if (!info)
+               return -ENOMEM;
                
        default_par = info->par;
  
@@ -1273,7 +1257,7 @@ static int __devinit tdfxfb_probe(struct pci_dev *pdev,
    
        info->fbops             = &tdfxfb_ops;
        info->fix               = tdfx_fix;     
-       info->pseudo_palette    = (void *)(default_par + 1); 
+       info->pseudo_palette    = default_par->palette;
        info->flags             = FBINFO_DEFAULT | FBINFO_HWACCEL_YPAN;
 #ifdef CONFIG_FB_3DFX_ACCEL
        info->flags             |= FBINFO_HWACCEL_FILLRECT |
@@ -1331,6 +1315,28 @@ out_err:
        return -ENXIO;
 }
 
+#ifndef MODULE
+static void tdfxfb_setup(char *options)
+{
+       char* this_opt;
+
+       if (!options || !*options)
+               return;
+
+       while ((this_opt = strsep(&options, ",")) != NULL) {
+               if (!*this_opt)
+                       continue;
+               if(!strcmp(this_opt, "nopan")) {
+                       nopan = 1;
+               } else if(!strcmp(this_opt, "nowrap")) {
+                       nowrap = 1;
+               } else {
+                       mode_option = this_opt;
+               }
+       }
+}
+#endif
+
 /**
  *      tdfxfb_remove - Device removal
  *
@@ -1343,7 +1349,7 @@ out_err:
 static void __devexit tdfxfb_remove(struct pci_dev *pdev)
 {
        struct fb_info *info = pci_get_drvdata(pdev);
-       struct tdfx_par *par = (struct tdfx_par *) info->par;
+       struct tdfx_par *par = info->par;
 
        unregister_framebuffer(info);
        iounmap(par->regbase_virt);
@@ -1360,7 +1366,7 @@ static void __devexit tdfxfb_remove(struct pci_dev *pdev)
        framebuffer_release(info);
 }
 
-int __init tdfxfb_init(void)
+static int __init tdfxfb_init(void)
 {
 #ifndef MODULE
        char *option = NULL;
@@ -1370,7 +1376,7 @@ int __init tdfxfb_init(void)
 
        tdfxfb_setup(option);
 #endif
-        return pci_module_init(&tdfxfb_driver);
+        return pci_register_driver(&tdfxfb_driver);
 }
 
 static void __exit tdfxfb_exit(void)
@@ -1384,30 +1390,3 @@ MODULE_LICENSE("GPL");
  
 module_init(tdfxfb_init);
 module_exit(tdfxfb_exit);
-
-
-#ifndef MODULE
-void tdfxfb_setup(char *options)
-{ 
-       char* this_opt;
-
-       if (!options || !*options)
-               return;
-
-       while ((this_opt = strsep(&options, ",")) != NULL) {    
-               if (!*this_opt)
-                       continue;
-               if (!strcmp(this_opt, "inverse")) {
-                       inverse = 1;
-                       fb_invert_cmaps();
-               } else if(!strcmp(this_opt, "nopan")) {
-                       nopan = 1;
-               } else if(!strcmp(this_opt, "nowrap")) {
-                       nowrap = 1;
-               } else {
-                       mode_option = this_opt;
-               }
-       } 
-}
-#endif
-