#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,
.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,
/*
* 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,
*/
static int nopan = 0;
static int nowrap = 1; // not implemented (yet)
-static char *mode_option __initdata = NULL;
+static char *mode_option __devinitdata = NULL;
/* -------------------------------------------------------------------------
* Hardware-specific funcions
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 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);
return -ENXIO;
}
+#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, "nopan")) {
+ nopan = 1;
+ } else if(!strcmp(this_opt, "nowrap")) {
+ nowrap = 1;
+ } else {
+ mode_option = this_opt;
+ }
+ }
+}
+#endif
+
/**
* tdfxfb_remove - Device removal
*
framebuffer_release(info);
}
-int __init tdfxfb_init(void)
+static int __init tdfxfb_init(void)
{
#ifndef MODULE
char *option = NULL;
tdfxfb_setup(option);
#endif
- return pci_module_init(&tdfxfb_driver);
+ return pci_register_driver(&tdfxfb_driver);
}
static void __exit tdfxfb_exit(void)
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, "nopan")) {
- nopan = 1;
- } else if(!strcmp(this_opt, "nowrap")) {
- nowrap = 1;
- } else {
- mode_option = this_opt;
- }
- }
-}
-#endif
-