Blame view

drivers/video/tdfxfb.c 42.8 KB
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1
2
3
4
5
6
  /*
   *
   * tdfxfb.c
   *
   * Author: Hannu Mallat <hmallat@cc.hut.fi>
   *
3cbe9cff9   Krzysztof Helt   tdfxfb: checkpatc...
7
   * Copyright © 1999 Hannu Mallat
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
8
9
10
11
12
   * All rights reserved
   *
   * Created      : Thu Sep 23 18:17:43 1999, hmallat
   * Last modified: Tue Nov  2 21:19:47 1999, hmallat
   *
feff3880d   Krzysztof Helt   tdfxfb: move I2C ...
13
14
15
16
17
18
   * I2C part copied from the i2c-voodoo3.c driver by:
   * Frodo Looijaard <frodol@dds.nl>,
   * Philip Edelbrock <phil@netroedge.com>,
   * Ralph Metzler <rjkm@thp.uni-koeln.de>, and
   * Mark D. Studebaker <mdsxyz123@yahoo.com>
   *
8af1d50f7   Krzysztof Helt   tdfxfb: coding st...
19
   * Lots of the information here comes from the Daryll Strauss' Banshee
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
20
21
22
23
24
25
26
27
28
29
30
31
   * patches to the XF86 server, and the rest comes from the 3dfx
   * Banshee specification. I'm very much indebted to Daryll for his
   * work on the X server.
   *
   * Voodoo3 support was contributed Harold Oga. Lots of additions
   * (proper acceleration, 24 bpp, hardware cursor) and bug fixes by Attila
   * Kesmarki. Thanks guys!
   *
   * Voodoo1 and Voodoo2 support aren't relevant to this driver as they
   * behave very differently from the Voodoo3/4/5. For anyone wanting to
   * use frame buffer on the Voodoo1/2, see the sstfb driver (which is
   * located at http://www.sourceforge.net/projects/sstfb).
8af1d50f7   Krzysztof Helt   tdfxfb: coding st...
32
   *
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
33
34
35
36
37
38
39
40
41
   * While I _am_ grateful to 3Dfx for releasing the specs for Banshee,
   * I do wish the next version is a bit more complete. Without the XF86
   * patches I couldn't have gotten even this far... for instance, the
   * extensions to the VGA register set go completely unmentioned in the
   * spec! Also, lots of references are made to the 'SST core', but no
   * spec is publicly available, AFAIK.
   *
   * The structure of this driver comes pretty much from the Permedia
   * driver by Ilario Nardinocchi, which in turn is based on skeletonfb.
8af1d50f7   Krzysztof Helt   tdfxfb: coding st...
42
   *
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
43
   * TODO:
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
44
45
46
47
48
49
50
   * - multihead support (basically need to support an array of fb_infos)
   * - support other architectures (PPC, Alpha); does the fact that the VGA
   *   core can be accessed only thru I/O (not memory mapped) complicate
   *   things?
   *
   * Version history:
   *
3cbe9cff9   Krzysztof Helt   tdfxfb: checkpatc...
51
   * 0.1.4 (released 2002-05-28)	ported over to new fbdev api by James Simmons
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
52
   *
3cbe9cff9   Krzysztof Helt   tdfxfb: checkpatc...
53
54
   * 0.1.3 (released 1999-11-02)	added Attila's panning support, code
   *				reorg, hwcursor address page size alignment
af901ca18   André Goddard Rosa   tree-wide: fix as...
55
   *				(for mmapping both frame buffer and regs),
3cbe9cff9   Krzysztof Helt   tdfxfb: checkpatc...
56
57
58
59
60
61
62
   *				and my changes to get rid of hardcoded
   *				VGA i/o register locations (uses PCI
   *				configuration info now)
   * 0.1.2 (released 1999-10-19)	added Attila Kesmarki's bug fixes and
   *				improvements
   * 0.1.1 (released 1999-10-07)	added Voodoo3 support by Harold Oga.
   * 0.1.0 (released 1999-10-06)	initial version
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
63
64
   *
   */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
65
66
67
68
69
  #include <linux/module.h>
  #include <linux/kernel.h>
  #include <linux/errno.h>
  #include <linux/string.h>
  #include <linux/mm.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
70
  #include <linux/slab.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
71
72
73
  #include <linux/fb.h>
  #include <linux/init.h>
  #include <linux/pci.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
74
  #include <asm/io.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
75
76
  
  #include <video/tdfx.h>
5ae121705   Harvey Harrison   video: replace re...
77
  #define DPRINTK(a, b...) pr_debug("fb: %s: " a, __func__ , ## b)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
78

0960bd3db   Krzysztof Helt   tdfxfb: mtrr support
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
  #ifdef CONFIG_MTRR
  #include <asm/mtrr.h>
  #else
  /* duplicate asm/mtrr.h defines to work on archs without mtrr */
  #define MTRR_TYPE_WRCOMB     1
  
  static inline int mtrr_add(unsigned long base, unsigned long size,
  				unsigned int type, char increment)
  {
      return -ENODEV;
  }
  static inline int mtrr_del(int reg, unsigned long base,
  				unsigned long size)
  {
      return -ENODEV;
  }
  #endif
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
96
97
98
99
100
  #define BANSHEE_MAX_PIXCLOCK 270000
  #define VOODOO3_MAX_PIXCLOCK 300000
  #define VOODOO5_MAX_PIXCLOCK 350000
  
  static struct fb_fix_screeninfo tdfx_fix __devinitdata = {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
101
  	.type =		FB_TYPE_PACKED_PIXELS,
8af1d50f7   Krzysztof Helt   tdfxfb: coding st...
102
  	.visual =	FB_VISUAL_PSEUDOCOLOR,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
103
  	.ypanstep =	1,
8af1d50f7   Krzysztof Helt   tdfxfb: coding st...
104
  	.ywrapstep =	1,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
105
106
107
108
109
110
111
112
113
  	.accel =	FB_ACCEL_3DFX_BANSHEE
  };
  
  static struct fb_var_screeninfo tdfx_var __devinitdata = {
  	/* "640x480, 8 bpp @ 60 Hz */
  	.xres =		640,
  	.yres =		480,
  	.xres_virtual =	640,
  	.yres_virtual =	1024,
8af1d50f7   Krzysztof Helt   tdfxfb: coding st...
114
  	.bits_per_pixel = 8,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
  	.red =		{0, 8, 0},
  	.blue =		{0, 8, 0},
  	.green =	{0, 8, 0},
  	.activate =	FB_ACTIVATE_NOW,
  	.height =	-1,
  	.width =	-1,
  	.accel_flags =	FB_ACCELF_TEXT,
  	.pixclock =	39722,
  	.left_margin =	40,
  	.right_margin =	24,
  	.upper_margin =	32,
  	.lower_margin =	11,
  	.hsync_len =	96,
  	.vsync_len =	2,
  	.vmode =	FB_VMODE_NONINTERLACED
  };
  
  /*
   * PCI driver prototypes
   */
  static int __devinit tdfxfb_probe(struct pci_dev *pdev,
  				  const struct pci_device_id *id);
  static void __devexit tdfxfb_remove(struct pci_dev *pdev);
  
  static struct pci_device_id tdfxfb_id_table[] = {
  	{ PCI_VENDOR_ID_3DFX, PCI_DEVICE_ID_3DFX_BANSHEE,
  	  PCI_ANY_ID, PCI_ANY_ID, PCI_BASE_CLASS_DISPLAY << 16,
  	  0xff0000, 0 },
  	{ PCI_VENDOR_ID_3DFX, PCI_DEVICE_ID_3DFX_VOODOO3,
  	  PCI_ANY_ID, PCI_ANY_ID, PCI_BASE_CLASS_DISPLAY << 16,
  	  0xff0000, 0 },
  	{ PCI_VENDOR_ID_3DFX, PCI_DEVICE_ID_3DFX_VOODOO5,
  	  PCI_ANY_ID, PCI_ANY_ID, PCI_BASE_CLASS_DISPLAY << 16,
  	  0xff0000, 0 },
  	{ 0, }
  };
  
  static struct pci_driver tdfxfb_driver = {
  	.name		= "tdfxfb",
8af1d50f7   Krzysztof Helt   tdfxfb: coding st...
154
155
156
  	.id_table	= tdfxfb_id_table,
  	.probe		= tdfxfb_probe,
  	.remove		= __devexit_p(tdfxfb_remove),
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
157
158
159
160
161
  };
  
  MODULE_DEVICE_TABLE(pci, tdfxfb_id_table);
  
  /*
8af1d50f7   Krzysztof Helt   tdfxfb: coding st...
162
   * Driver data
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
163
   */
90b0f0853   Krzysztof Helt   tdfxfb: hardware ...
164
165
166
  static int nopan;
  static int nowrap = 1;      /* not implemented (yet) */
  static int hwcursor = 1;
0960bd3db   Krzysztof Helt   tdfxfb: mtrr support
167
168
  static char *mode_option __devinitdata;
  /* mtrr option */
90ab5ee94   Rusty Russell   module_param: mak...
169
  static bool nomtrr __devinitdata;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
170

8af1d50f7   Krzysztof Helt   tdfxfb: coding st...
171
  /* -------------------------------------------------------------------------
3cbe9cff9   Krzysztof Helt   tdfxfb: checkpatc...
172
   *			Hardware-specific funcions
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
173
   * ------------------------------------------------------------------------- */
8af1d50f7   Krzysztof Helt   tdfxfb: coding st...
174
175
176
  static inline u8 vga_inb(struct tdfx_par *par, u32 reg)
  {
  	return inb(par->iobase + reg - 0x300);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
177
  }
4f05b53b2   Krzysztof Helt   tdfxfb: code impr...
178

8af1d50f7   Krzysztof Helt   tdfxfb: coding st...
179
180
181
  static inline void vga_outb(struct tdfx_par *par, u32 reg, u8 val)
  {
  	outb(val, par->iobase + reg - 0x300);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
182
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
183

8af1d50f7   Krzysztof Helt   tdfxfb: coding st...
184
185
186
  static inline void gra_outb(struct tdfx_par *par, u32 idx, u8 val)
  {
  	vga_outb(par, GRA_I, idx);
254c94710   Krzysztof Helt   tdfxfb: palette f...
187
  	wmb();
8af1d50f7   Krzysztof Helt   tdfxfb: coding st...
188
  	vga_outb(par, GRA_D, val);
254c94710   Krzysztof Helt   tdfxfb: palette f...
189
  	wmb();
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
190
  }
8af1d50f7   Krzysztof Helt   tdfxfb: coding st...
191
192
193
  static inline void seq_outb(struct tdfx_par *par, u32 idx, u8 val)
  {
  	vga_outb(par, SEQ_I, idx);
254c94710   Krzysztof Helt   tdfxfb: palette f...
194
  	wmb();
8af1d50f7   Krzysztof Helt   tdfxfb: coding st...
195
  	vga_outb(par, SEQ_D, val);
254c94710   Krzysztof Helt   tdfxfb: palette f...
196
  	wmb();
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
197
  }
8af1d50f7   Krzysztof Helt   tdfxfb: coding st...
198
199
200
  static inline u8 seq_inb(struct tdfx_par *par, u32 idx)
  {
  	vga_outb(par, SEQ_I, idx);
254c94710   Krzysztof Helt   tdfxfb: palette f...
201
  	mb();
8af1d50f7   Krzysztof Helt   tdfxfb: coding st...
202
  	return vga_inb(par, SEQ_D);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
203
  }
8af1d50f7   Krzysztof Helt   tdfxfb: coding st...
204
205
206
  static inline void crt_outb(struct tdfx_par *par, u32 idx, u8 val)
  {
  	vga_outb(par, CRT_I, idx);
254c94710   Krzysztof Helt   tdfxfb: palette f...
207
  	wmb();
8af1d50f7   Krzysztof Helt   tdfxfb: coding st...
208
  	vga_outb(par, CRT_D, val);
254c94710   Krzysztof Helt   tdfxfb: palette f...
209
  	wmb();
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
210
  }
8af1d50f7   Krzysztof Helt   tdfxfb: coding st...
211
212
213
  static inline u8 crt_inb(struct tdfx_par *par, u32 idx)
  {
  	vga_outb(par, CRT_I, idx);
254c94710   Krzysztof Helt   tdfxfb: palette f...
214
  	mb();
8af1d50f7   Krzysztof Helt   tdfxfb: coding st...
215
  	return vga_inb(par, CRT_D);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
216
  }
8af1d50f7   Krzysztof Helt   tdfxfb: coding st...
217
  static inline void att_outb(struct tdfx_par *par, u32 idx, u8 val)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
218
219
  {
  	unsigned char tmp;
8af1d50f7   Krzysztof Helt   tdfxfb: coding st...
220

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
  	tmp = vga_inb(par, IS1_R);
  	vga_outb(par, ATT_IW, idx);
  	vga_outb(par, ATT_IW, val);
  }
  
  static inline void vga_disable_video(struct tdfx_par *par)
  {
  	unsigned char s;
  
  	s = seq_inb(par, 0x01) | 0x20;
  	seq_outb(par, 0x00, 0x01);
  	seq_outb(par, 0x01, s);
  	seq_outb(par, 0x00, 0x03);
  }
  
  static inline void vga_enable_video(struct tdfx_par *par)
  {
  	unsigned char s;
  
  	s = seq_inb(par, 0x01) & 0xdf;
  	seq_outb(par, 0x00, 0x01);
  	seq_outb(par, 0x01, s);
  	seq_outb(par, 0x00, 0x03);
  }
  
  static inline void vga_enable_palette(struct tdfx_par *par)
  {
  	vga_inb(par, IS1_R);
254c94710   Krzysztof Helt   tdfxfb: palette f...
249
  	mb();
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
250
251
  	vga_outb(par, ATT_IW, 0x20);
  }
8af1d50f7   Krzysztof Helt   tdfxfb: coding st...
252
  static inline u32 tdfx_inl(struct tdfx_par *par, unsigned int reg)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
253
254
255
256
257
258
259
260
261
262
263
264
265
  {
  	return readl(par->regbase_virt + reg);
  }
  
  static inline void tdfx_outl(struct tdfx_par *par, unsigned int reg, u32 val)
  {
  	writel(val, par->regbase_virt + reg);
  }
  
  static inline void banshee_make_room(struct tdfx_par *par, int size)
  {
  	/* Note: The Voodoo3's onboard FIFO has 32 slots. This loop
  	 * won't quit if you ask for more. */
f67fd7c10   Krzysztof Helt   tdfxfb: replace b...
266
267
  	while ((tdfx_inl(par, STATUS) & 0x1f) < size - 1)
  		cpu_relax();
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
268
  }
3cbe9cff9   Krzysztof Helt   tdfxfb: checkpatc...
269

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
270
271
  static int banshee_wait_idle(struct fb_info *info)
  {
a807f618b   Antonino A. Daplas   [PATCH] fbdev: td...
272
  	struct tdfx_par *par = info->par;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
273
274
275
276
  	int i = 0;
  
  	banshee_make_room(par, 1);
  	tdfx_outl(par, COMMAND_3D, COMMAND_3D_NOP);
4f05b53b2   Krzysztof Helt   tdfxfb: code impr...
277
  	do {
3cbe9cff9   Krzysztof Helt   tdfxfb: checkpatc...
278
279
  		if ((tdfx_inl(par, STATUS) & STATUS_BUSY) == 0)
  			i++;
4f05b53b2   Krzysztof Helt   tdfxfb: code impr...
280
  	} while (i < 3);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
281
282
283
284
  	return 0;
  }
  
  /*
8af1d50f7   Krzysztof Helt   tdfxfb: coding st...
285
   * Set the color of a palette entry in 8bpp mode
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
286
287
   */
  static inline void do_setpalentry(struct tdfx_par *par, unsigned regno, u32 c)
3cbe9cff9   Krzysztof Helt   tdfxfb: checkpatc...
288
  {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
289
290
  	banshee_make_room(par, 2);
  	tdfx_outl(par, DACADDR, regno);
254c94710   Krzysztof Helt   tdfxfb: palette f...
291
292
  	/* read after write makes it working */
  	tdfx_inl(par, DACADDR);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
293
294
  	tdfx_outl(par, DACDATA, c);
  }
8af1d50f7   Krzysztof Helt   tdfxfb: coding st...
295
  static u32 do_calc_pll(int freq, int *freq_out)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
296
  {
0fbe9caff   Richard Drummond   [PATCH] Better PL...
297
  	int m, n, k, best_m, best_n, best_k, best_error;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
298
  	int fref = 14318;
8af1d50f7   Krzysztof Helt   tdfxfb: coding st...
299

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
300
301
  	best_error = freq;
  	best_n = best_m = best_k = 0;
0fbe9caff   Richard Drummond   [PATCH] Better PL...
302
303
304
305
306
307
308
  
  	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
  			 */
4f05b53b2   Krzysztof Helt   tdfxfb: code impr...
309
  			int n_estimated = ((freq * (m + 2) << k) / fref) - 2;
0fbe9caff   Richard Drummond   [PATCH] Better PL...
310
311
  
  			/* Search neighborhood of estimated n */
4f05b53b2   Krzysztof Helt   tdfxfb: code impr...
312
313
314
  			for (n = max(0, n_estimated);
  				n <= min(255, n_estimated + 1);
  				n++) {
0fbe9caff   Richard Drummond   [PATCH] Better PL...
315
316
317
318
  				/*
  				 * Calculate PLL freqency with current m, k and
  				 * estimated n
  				 */
4f05b53b2   Krzysztof Helt   tdfxfb: code impr...
319
  				int f = (fref * (n + 2) / (m + 2)) >> k;
8af1d50f7   Krzysztof Helt   tdfxfb: coding st...
320
  				int error = abs(f - freq);
0fbe9caff   Richard Drummond   [PATCH] Better PL...
321
322
  
  				/*
8af1d50f7   Krzysztof Helt   tdfxfb: coding st...
323
  				 * If this is the closest we've come to the
0fbe9caff   Richard Drummond   [PATCH] Better PL...
324
325
  				 * target frequency then remember n, m and k
  				 */
8af1d50f7   Krzysztof Helt   tdfxfb: coding st...
326
  				if (error < best_error) {
0fbe9caff   Richard Drummond   [PATCH] Better PL...
327
  					best_error = error;
8af1d50f7   Krzysztof Helt   tdfxfb: coding st...
328
329
330
  					best_n = n;
  					best_m = m;
  					best_k = k;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
331
332
333
334
  				}
  			}
  		}
  	}
0fbe9caff   Richard Drummond   [PATCH] Better PL...
335

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
336
337
338
  	n = best_n;
  	m = best_m;
  	k = best_k;
4f05b53b2   Krzysztof Helt   tdfxfb: code impr...
339
  	*freq_out = (fref * (n + 2) / (m + 2)) >> k;
0fbe9caff   Richard Drummond   [PATCH] Better PL...
340

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
341
342
  	return (n << 8) | (m << 2) | k;
  }
8af1d50f7   Krzysztof Helt   tdfxfb: coding st...
343
  static void do_write_regs(struct fb_info *info, struct banshee_reg *reg)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
344
  {
a807f618b   Antonino A. Daplas   [PATCH] fbdev: td...
345
  	struct tdfx_par *par = info->par;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
346
347
348
349
350
351
352
353
354
  	int i;
  
  	banshee_wait_idle(info);
  
  	tdfx_outl(par, MISCINIT1, tdfx_inl(par, MISCINIT1) | 0x01);
  
  	crt_outb(par, 0x11, crt_inb(par, 0x11) & 0x7f); /* CRT unprotect */
  
  	banshee_make_room(par, 3);
8af1d50f7   Krzysztof Helt   tdfxfb: coding st...
355
356
  	tdfx_outl(par, VGAINIT1, reg->vgainit1 & 0x001FFFFF);
  	tdfx_outl(par, VIDPROCCFG, reg->vidcfg & ~0x00000001);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
357
358
359
360
  #if 0
  	tdfx_outl(par, PLLCTRL1, reg->mempll);
  	tdfx_outl(par, PLLCTRL2, reg->gfxpll);
  #endif
8af1d50f7   Krzysztof Helt   tdfxfb: coding st...
361
  	tdfx_outl(par, PLLCTRL0, reg->vidpll);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
  
  	vga_outb(par, MISC_W, reg->misc[0x00] | 0x01);
  
  	for (i = 0; i < 5; i++)
  		seq_outb(par, i, reg->seq[i]);
  
  	for (i = 0; i < 25; i++)
  		crt_outb(par, i, reg->crt[i]);
  
  	for (i = 0; i < 9; i++)
  		gra_outb(par, i, reg->gra[i]);
  
  	for (i = 0; i < 21; i++)
  		att_outb(par, i, reg->att[i]);
  
  	crt_outb(par, 0x1a, reg->ext[0]);
  	crt_outb(par, 0x1b, reg->ext[1]);
  
  	vga_enable_palette(par);
  	vga_enable_video(par);
4f05b53b2   Krzysztof Helt   tdfxfb: code impr...
382
  	banshee_make_room(par, 9);
8af1d50f7   Krzysztof Helt   tdfxfb: coding st...
383
384
385
  	tdfx_outl(par, VGAINIT0, reg->vgainit0);
  	tdfx_outl(par, DACMODE, reg->dacmode);
  	tdfx_outl(par, VIDDESKSTRIDE, reg->stride);
90b0f0853   Krzysztof Helt   tdfxfb: hardware ...
386
  	tdfx_outl(par, HWCURPATADDR, reg->curspataddr);
8af1d50f7   Krzysztof Helt   tdfxfb: coding st...
387
388
389
390
391
392
393
394
  
  	tdfx_outl(par, VIDSCREENSIZE, reg->screensize);
  	tdfx_outl(par, VIDDESKSTART, reg->startaddr);
  	tdfx_outl(par, VIDPROCCFG, reg->vidcfg);
  	tdfx_outl(par, VGAINIT1, reg->vgainit1);
  	tdfx_outl(par, MISCINIT0, reg->miscinit0);
  
  	banshee_make_room(par, 8);
4f05b53b2   Krzysztof Helt   tdfxfb: code impr...
395
396
  	tdfx_outl(par, SRCBASE, reg->startaddr);
  	tdfx_outl(par, DSTBASE, reg->startaddr);
8af1d50f7   Krzysztof Helt   tdfxfb: coding st...
397
398
399
400
401
402
  	tdfx_outl(par, COMMANDEXTRA_2D, 0);
  	tdfx_outl(par, CLIP0MIN, 0);
  	tdfx_outl(par, CLIP0MAX, 0x0fff0fff);
  	tdfx_outl(par, CLIP1MIN, 0);
  	tdfx_outl(par, CLIP1MAX, 0x0fff0fff);
  	tdfx_outl(par, SRCXY, 0);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
403
404
405
  
  	banshee_wait_idle(info);
  }
8af1d50f7   Krzysztof Helt   tdfxfb: coding st...
406
  static unsigned long do_lfb_size(struct tdfx_par *par, unsigned short dev_id)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
407
  {
4f05b53b2   Krzysztof Helt   tdfxfb: code impr...
408
409
  	u32 draminit0 = tdfx_inl(par, DRAMINIT0);
  	u32 draminit1 = tdfx_inl(par, DRAMINIT1);
333f98172   Richard Drummond   [PATCH] Clean-up ...
410
  	u32 miscinit1;
4f05b53b2   Krzysztof Helt   tdfxfb: code impr...
411
  	int num_chips = (draminit0 & DRAMINIT0_SGRAM_NUM) ? 8 : 4;
333f98172   Richard Drummond   [PATCH] Clean-up ...
412
  	int chip_size; /* in MB */
4f05b53b2   Krzysztof Helt   tdfxfb: code impr...
413
  	int has_sgram = draminit1 & DRAMINIT1_MEM_SDRAM;
8af1d50f7   Krzysztof Helt   tdfxfb: coding st...
414

333f98172   Richard Drummond   [PATCH] Clean-up ...
415
416
  	if (dev_id < PCI_DEVICE_ID_3DFX_VOODOO5) {
  		/* Banshee/Voodoo3 */
8af1d50f7   Krzysztof Helt   tdfxfb: coding st...
417
  		chip_size = 2;
bf6910c0a   Krzysztof Helt   tdfxfb: fix SDRAM...
418
  		if (has_sgram && !(draminit0 & DRAMINIT0_SGRAM_TYPE))
4f05b53b2   Krzysztof Helt   tdfxfb: code impr...
419
  			chip_size = 1;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
420
421
  	} else {
  		/* Voodoo4/5 */
333f98172   Richard Drummond   [PATCH] Clean-up ...
422
  		has_sgram = 0;
4f05b53b2   Krzysztof Helt   tdfxfb: code impr...
423
424
  		chip_size = draminit0 & DRAMINIT0_SGRAM_TYPE_MASK;
  		chip_size = 1 << (chip_size >> DRAMINIT0_SGRAM_TYPE_SHIFT);
333f98172   Richard Drummond   [PATCH] Clean-up ...
425
  	}
333f98172   Richard Drummond   [PATCH] Clean-up ...
426
427
  
  	/* disable block writes for SDRAM */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
428
  	miscinit1 = tdfx_inl(par, MISCINIT1);
333f98172   Richard Drummond   [PATCH] Clean-up ...
429
  	miscinit1 |= has_sgram ? 0 : MISCINIT1_2DBLOCK_DIS;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
430
  	miscinit1 |= MISCINIT1_CLUT_INV;
8af1d50f7   Krzysztof Helt   tdfxfb: coding st...
431
  	banshee_make_room(par, 1);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
432
  	tdfx_outl(par, MISCINIT1, miscinit1);
4f05b53b2   Krzysztof Helt   tdfxfb: code impr...
433
  	return num_chips * chip_size * 1024l * 1024;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
434
435
436
  }
  
  /* ------------------------------------------------------------------------- */
8af1d50f7   Krzysztof Helt   tdfxfb: coding st...
437
  static int tdfxfb_check_var(struct fb_var_screeninfo *var, struct fb_info *info)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
438
  {
a807f618b   Antonino A. Daplas   [PATCH] fbdev: td...
439
  	struct tdfx_par *par = info->par;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
  	u32 lpitch;
  
  	if (var->bits_per_pixel != 8  && var->bits_per_pixel != 16 &&
  	    var->bits_per_pixel != 24 && var->bits_per_pixel != 32) {
  		DPRINTK("depth not supported: %u
  ", var->bits_per_pixel);
  		return -EINVAL;
  	}
  
  	if (var->xres != var->xres_virtual)
  		var->xres_virtual = var->xres;
  
  	if (var->yres > var->yres_virtual)
  		var->yres_virtual = var->yres;
  
  	if (var->xoffset) {
  		DPRINTK("xoffset not supported
  ");
  		return -EINVAL;
  	}
90b0f0853   Krzysztof Helt   tdfxfb: hardware ...
460
  	var->yoffset = 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
461

3cbe9cff9   Krzysztof Helt   tdfxfb: checkpatc...
462
463
464
465
466
467
  	/*
  	 * Banshee doesn't support interlace, but Voodoo4/5 and probably
  	 * Voodoo3 do.
  	 * no direct information about device id now?
  	 *  use max_pixclock for this...
  	 */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
468
  	if (((var->vmode & FB_VMODE_MASK) == FB_VMODE_INTERLACED) &&
8af1d50f7   Krzysztof Helt   tdfxfb: coding st...
469
  	    (par->max_pixclock < VOODOO3_MAX_PIXCLOCK)) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
470
471
472
473
  		DPRINTK("interlace not supported
  ");
  		return -EINVAL;
  	}
215059d24   Krzysztof Helt   tdfxfb: make use ...
474
475
476
477
478
479
  	if (info->monspecs.hfmax && info->monspecs.vfmax &&
  	    info->monspecs.dclkmax && fb_validate_mode(var, info) < 0) {
  		DPRINTK("mode outside monitor's specs
  ");
  		return -EINVAL;
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
480
  	var->xres = (var->xres + 15) & ~15; /* could sometimes be 8 */
8af1d50f7   Krzysztof Helt   tdfxfb: coding st...
481
  	lpitch = var->xres * ((var->bits_per_pixel + 7) >> 3);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
482
483
484
485
486
  	if (var->xres < 320 || var->xres > 2048) {
  		DPRINTK("width not supported: %u
  ", var->xres);
  		return -EINVAL;
  	}
8af1d50f7   Krzysztof Helt   tdfxfb: coding st...
487

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
488
489
490
491
492
  	if (var->yres < 200 || var->yres > 2048) {
  		DPRINTK("height not supported: %u
  ", var->yres);
  		return -EINVAL;
  	}
8af1d50f7   Krzysztof Helt   tdfxfb: coding st...
493

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
494
  	if (lpitch * var->yres_virtual > info->fix.smem_len) {
8af1d50f7   Krzysztof Helt   tdfxfb: coding st...
495
  		var->yres_virtual = info->fix.smem_len / lpitch;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
496
497
498
  		if (var->yres_virtual < var->yres) {
  			DPRINTK("no memory for screen (%ux%ux%u)
  ",
8af1d50f7   Krzysztof Helt   tdfxfb: coding st...
499
500
  				var->xres, var->yres_virtual,
  				var->bits_per_pixel);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
501
502
503
  			return -EINVAL;
  		}
  	}
8af1d50f7   Krzysztof Helt   tdfxfb: coding st...
504

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
505
  	if (PICOS2KHZ(var->pixclock) > par->max_pixclock) {
8af1d50f7   Krzysztof Helt   tdfxfb: coding st...
506
507
508
  		DPRINTK("pixclock too high (%ldKHz)
  ",
  			PICOS2KHZ(var->pixclock));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
509
510
  		return -EINVAL;
  	}
92744dd51   Krzysztof Helt   tdfxfb: 3 fixes
511
512
  	var->transp.offset = 0;
  	var->transp.length = 0;
8af1d50f7   Krzysztof Helt   tdfxfb: coding st...
513
514
  	switch (var->bits_per_pixel) {
  	case 8:
3cbe9cff9   Krzysztof Helt   tdfxfb: checkpatc...
515
516
517
518
  		var->red.length = 8;
  		var->red.offset = 0;
  		var->green = var->red;
  		var->blue = var->red;
8af1d50f7   Krzysztof Helt   tdfxfb: coding st...
519
520
521
522
523
524
525
526
527
528
  		break;
  	case 16:
  		var->red.offset   = 11;
  		var->red.length   = 5;
  		var->green.offset = 5;
  		var->green.length = 6;
  		var->blue.offset  = 0;
  		var->blue.length  = 5;
  		break;
  	case 32:
92744dd51   Krzysztof Helt   tdfxfb: 3 fixes
529
530
  		var->transp.offset = 24;
  		var->transp.length = 8;
8af1d50f7   Krzysztof Helt   tdfxfb: coding st...
531
  	case 24:
92744dd51   Krzysztof Helt   tdfxfb: 3 fixes
532
533
534
  		var->red.offset = 16;
  		var->green.offset = 8;
  		var->blue.offset = 0;
8af1d50f7   Krzysztof Helt   tdfxfb: coding st...
535
536
  		var->red.length = var->green.length = var->blue.length = 8;
  		break;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
537
  	}
3cbe9cff9   Krzysztof Helt   tdfxfb: checkpatc...
538
539
  	var->width = -1;
  	var->height = -1;
8af1d50f7   Krzysztof Helt   tdfxfb: coding st...
540

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
541
  	var->accel_flags = FB_ACCELF_TEXT;
8af1d50f7   Krzysztof Helt   tdfxfb: coding st...
542
543
544
545
  
  	DPRINTK("Checking graphics mode at %dx%d depth %d
  ",
  		var->xres, var->yres, var->bits_per_pixel);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
546
547
548
549
550
  	return 0;
  }
  
  static int tdfxfb_set_par(struct fb_info *info)
  {
a807f618b   Antonino A. Daplas   [PATCH] fbdev: td...
551
  	struct tdfx_par *par = info->par;
4f05b53b2   Krzysztof Helt   tdfxfb: code impr...
552
553
554
555
  	u32 hdispend = info->var.xres;
  	u32 hsyncsta = hdispend + info->var.right_margin;
  	u32 hsyncend = hsyncsta + info->var.hsync_len;
  	u32 htotal   = hsyncend + info->var.left_margin;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
556
557
558
559
  	u32 hd, hs, he, ht, hbs, hbe;
  	u32 vd, vs, ve, vt, vbs, vbe;
  	struct banshee_reg reg;
  	int fout, freq;
4f05b53b2   Krzysztof Helt   tdfxfb: code impr...
560
561
  	u32 wd;
  	u32 cpp = (info->var.bits_per_pixel + 7) >> 3;
8af1d50f7   Krzysztof Helt   tdfxfb: coding st...
562

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
563
  	memset(&reg, 0, sizeof(reg));
8af1d50f7   Krzysztof Helt   tdfxfb: coding st...
564
565
566
567
568
  
  	reg.vidcfg = VIDCFG_VIDPROC_ENABLE | VIDCFG_DESK_ENABLE |
  		     VIDCFG_CURS_X11 |
  		     ((cpp - 1) << VIDCFG_PIXFMT_SHIFT) |
  		     (cpp != 1 ? VIDCFG_CLUT_BYPASS : 0);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
569
570
571
  
  	/* PLL settings */
  	freq = PICOS2KHZ(info->var.pixclock);
8af1d50f7   Krzysztof Helt   tdfxfb: coding st...
572
  	reg.vidcfg &= ~VIDCFG_2X;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
573

8af1d50f7   Krzysztof Helt   tdfxfb: coding st...
574
  	if (freq > par->max_pixclock / 2) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
575
576
577
578
579
580
581
582
  		freq = freq > par->max_pixclock ? par->max_pixclock : freq;
  		reg.dacmode |= DACMODE_2X;
  		reg.vidcfg  |= VIDCFG_2X;
  		hdispend >>= 1;
  		hsyncsta >>= 1;
  		hsyncend >>= 1;
  		htotal   >>= 1;
  	}
8af1d50f7   Krzysztof Helt   tdfxfb: coding st...
583

3cbe9cff9   Krzysztof Helt   tdfxfb: checkpatc...
584
585
  	wd = (hdispend >> 3) - 1;
  	hd  = wd;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
586
587
588
589
590
591
592
  	hs  = (hsyncsta >> 3) - 1;
  	he  = (hsyncend >> 3) - 1;
  	ht  = (htotal >> 3) - 1;
  	hbs = hd;
  	hbe = ht;
  
  	if ((info->var.vmode & FB_VMODE_MASK) == FB_VMODE_DOUBLE) {
3cbe9cff9   Krzysztof Helt   tdfxfb: checkpatc...
593
  		vd = (info->var.yres << 1) - 1;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
594
595
  		vs  = vd + (info->var.lower_margin << 1);
  		ve  = vs + (info->var.vsync_len << 1);
3cbe9cff9   Krzysztof Helt   tdfxfb: checkpatc...
596
  		vt = ve + (info->var.upper_margin << 1) - 1;
4f05b53b2   Krzysztof Helt   tdfxfb: code impr...
597
598
599
  		reg.screensize = info->var.xres | (info->var.yres << 13);
  		reg.vidcfg |= VIDCFG_HALF_MODE;
  		reg.crt[0x09] = 0x80;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
600
  	} else {
3cbe9cff9   Krzysztof Helt   tdfxfb: checkpatc...
601
  		vd = info->var.yres - 1;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
602
603
  		vs  = vd + info->var.lower_margin;
  		ve  = vs + info->var.vsync_len;
3cbe9cff9   Krzysztof Helt   tdfxfb: checkpatc...
604
  		vt = ve + info->var.upper_margin - 1;
4f05b53b2   Krzysztof Helt   tdfxfb: code impr...
605
606
  		reg.screensize = info->var.xres | (info->var.yres << 12);
  		reg.vidcfg &= ~VIDCFG_HALF_MODE;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
607
  	}
3cbe9cff9   Krzysztof Helt   tdfxfb: checkpatc...
608
609
  	vbs = vd;
  	vbe = vt;
8af1d50f7   Krzysztof Helt   tdfxfb: coding st...
610

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
611
  	/* this is all pretty standard VGA register stuffing */
8af1d50f7   Krzysztof Helt   tdfxfb: coding st...
612
  	reg.misc[0x00] = 0x0f |
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
613
614
615
  			(info->var.xres < 400 ? 0xa0 :
  			 info->var.xres < 480 ? 0x60 :
  			 info->var.xres < 768 ? 0xe0 : 0x20);
8af1d50f7   Krzysztof Helt   tdfxfb: coding st...
616

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
  	reg.gra[0x05] = 0x40;
  	reg.gra[0x06] = 0x05;
  	reg.gra[0x07] = 0x0f;
  	reg.gra[0x08] = 0xff;
  
  	reg.att[0x00] = 0x00;
  	reg.att[0x01] = 0x01;
  	reg.att[0x02] = 0x02;
  	reg.att[0x03] = 0x03;
  	reg.att[0x04] = 0x04;
  	reg.att[0x05] = 0x05;
  	reg.att[0x06] = 0x06;
  	reg.att[0x07] = 0x07;
  	reg.att[0x08] = 0x08;
  	reg.att[0x09] = 0x09;
  	reg.att[0x0a] = 0x0a;
  	reg.att[0x0b] = 0x0b;
  	reg.att[0x0c] = 0x0c;
  	reg.att[0x0d] = 0x0d;
  	reg.att[0x0e] = 0x0e;
  	reg.att[0x0f] = 0x0f;
  	reg.att[0x10] = 0x41;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
639
  	reg.att[0x12] = 0x0f;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
640
641
642
643
644
645
646
647
648
649
650
651
  
  	reg.seq[0x00] = 0x03;
  	reg.seq[0x01] = 0x01; /* fixme: clkdiv2? */
  	reg.seq[0x02] = 0x0f;
  	reg.seq[0x03] = 0x00;
  	reg.seq[0x04] = 0x0e;
  
  	reg.crt[0x00] = ht - 4;
  	reg.crt[0x01] = hd;
  	reg.crt[0x02] = hbs;
  	reg.crt[0x03] = 0x80 | (hbe & 0x1f);
  	reg.crt[0x04] = hs;
8af1d50f7   Krzysztof Helt   tdfxfb: coding st...
652
  	reg.crt[0x05] = ((hbe & 0x20) << 2) | (he & 0x1f);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
653
654
655
656
657
  	reg.crt[0x06] = vt;
  	reg.crt[0x07] = ((vs & 0x200) >> 2) |
  			((vd & 0x200) >> 3) |
  			((vt & 0x200) >> 4) | 0x10 |
  			((vbs & 0x100) >> 5) |
8af1d50f7   Krzysztof Helt   tdfxfb: coding st...
658
659
660
  			((vs & 0x100) >> 6) |
  			((vd & 0x100) >> 7) |
  			((vt & 0x100) >> 8);
4f05b53b2   Krzysztof Helt   tdfxfb: code impr...
661
  	reg.crt[0x09] |= 0x40 | ((vbs & 0x200) >> 4);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
662
  	reg.crt[0x10] = vs;
8af1d50f7   Krzysztof Helt   tdfxfb: coding st...
663
  	reg.crt[0x11] = (ve & 0x0f) | 0x20;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
664
665
  	reg.crt[0x12] = vd;
  	reg.crt[0x13] = wd;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
666
  	reg.crt[0x15] = vbs;
8af1d50f7   Krzysztof Helt   tdfxfb: coding st...
667
  	reg.crt[0x16] = vbe + 1;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
668
669
  	reg.crt[0x17] = 0xc3;
  	reg.crt[0x18] = 0xff;
8af1d50f7   Krzysztof Helt   tdfxfb: coding st...
670

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
671
  	/* Banshee's nonvga stuff */
8af1d50f7   Krzysztof Helt   tdfxfb: coding st...
672
673
  	reg.ext[0x00] = (((ht & 0x100) >> 8) |
  			((hd & 0x100) >> 6) |
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
674
  			((hbs & 0x100) >> 4) |
8af1d50f7   Krzysztof Helt   tdfxfb: coding st...
675
676
677
678
679
680
681
682
683
  			((hbe & 0x40) >> 1) |
  			((hs & 0x100) >> 2) |
  			((he & 0x20) << 2));
  	reg.ext[0x01] = (((vt & 0x400) >> 10) |
  			((vd & 0x400) >> 8) |
  			((vbs & 0x400) >> 6) |
  			((vbe & 0x400) >> 4));
  
  	reg.vgainit0 =	VGAINIT0_8BIT_DAC     |
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
684
685
686
687
688
  			VGAINIT0_EXT_ENABLE   |
  			VGAINIT0_WAKEUP_3C3   |
  			VGAINIT0_ALT_READBACK |
  			VGAINIT0_EXTSHIFTOUT;
  	reg.vgainit1 = tdfx_inl(par, VGAINIT1) & 0x1fffff;
90b0f0853   Krzysztof Helt   tdfxfb: hardware ...
689
690
  	if (hwcursor)
  		reg.curspataddr = info->fix.smem_len;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
691
  	reg.cursloc   = 0;
8af1d50f7   Krzysztof Helt   tdfxfb: coding st...
692
693
  
  	reg.cursc0    = 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
694
  	reg.cursc1    = 0xffffff;
8af1d50f7   Krzysztof Helt   tdfxfb: coding st...
695

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
696
  	reg.stride    = info->var.xres * cpp;
4f05b53b2   Krzysztof Helt   tdfxfb: code impr...
697
698
  	reg.startaddr = info->var.yoffset * reg.stride
  			+ info->var.xoffset * cpp;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
699

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
700
701
702
703
704
  	reg.vidpll = do_calc_pll(freq, &fout);
  #if 0
  	reg.mempll = do_calc_pll(..., &fout);
  	reg.gfxpll = do_calc_pll(..., &fout);
  #endif
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
705
706
707
708
709
710
  	if ((info->var.vmode & FB_VMODE_MASK) == FB_VMODE_INTERLACED)
  		reg.vidcfg |= VIDCFG_INTERLACE;
  	reg.miscinit0 = tdfx_inl(par, MISCINIT0);
  
  #if defined(__BIG_ENDIAN)
  	switch (info->var.bits_per_pixel) {
8af1d50f7   Krzysztof Helt   tdfxfb: coding st...
711
712
713
714
715
716
717
718
719
720
721
722
723
  	case 8:
  	case 24:
  		reg.miscinit0 &= ~(1 << 30);
  		reg.miscinit0 &= ~(1 << 31);
  		break;
  	case 16:
  		reg.miscinit0 |= (1 << 30);
  		reg.miscinit0 |= (1 << 31);
  		break;
  	case 32:
  		reg.miscinit0 |= (1 << 30);
  		reg.miscinit0 &= ~(1 << 31);
  		break;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
724
  	}
8af1d50f7   Krzysztof Helt   tdfxfb: coding st...
725
  #endif
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
726
727
728
  	do_write_regs(info, &reg);
  
  	/* Now change fb_fix_screeninfo according to changes in par */
4f05b53b2   Krzysztof Helt   tdfxfb: code impr...
729
  	info->fix.line_length = reg.stride;
8af1d50f7   Krzysztof Helt   tdfxfb: coding st...
730
  	info->fix.visual = (info->var.bits_per_pixel == 8)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
731
732
  				? FB_VISUAL_PSEUDOCOLOR
  				: FB_VISUAL_TRUECOLOR;
8af1d50f7   Krzysztof Helt   tdfxfb: coding st...
733
734
735
736
  	DPRINTK("Graphics mode is now set at %dx%d depth %d
  ",
  		info->var.xres, info->var.yres, info->var.bits_per_pixel);
  	return 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
737
738
739
  }
  
  /* A handy macro shamelessly pinched from matroxfb */
3cbe9cff9   Krzysztof Helt   tdfxfb: checkpatc...
740
  #define CNVT_TOHW(val, width) ((((val) << (width)) + 0x7FFF - (val)) >> 16)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
741

8af1d50f7   Krzysztof Helt   tdfxfb: coding st...
742
743
744
  static int tdfxfb_setcolreg(unsigned regno, unsigned red, unsigned green,
  			    unsigned blue, unsigned transp,
  			    struct fb_info *info)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
745
  {
a807f618b   Antonino A. Daplas   [PATCH] fbdev: td...
746
  	struct tdfx_par *par = info->par;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
747
  	u32 rgbcol;
8af1d50f7   Krzysztof Helt   tdfxfb: coding st...
748
749
750
  
  	if (regno >= info->cmap.len || regno > 255)
  		return 1;
254c94710   Krzysztof Helt   tdfxfb: palette f...
751
752
753
  	/* grayscale works only partially under directcolor */
  	if (info->var.grayscale) {
  		/* grayscale = 0.30*R + 0.59*G + 0.11*B */
3cbe9cff9   Krzysztof Helt   tdfxfb: checkpatc...
754
755
756
  		blue = (red * 77 + green * 151 + blue * 28) >> 8;
  		green = blue;
  		red = blue;
254c94710   Krzysztof Helt   tdfxfb: palette f...
757
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
758
  	switch (info->fix.visual) {
54243cefd   Antonino A. Daplas   [PATCH] tdfxfb: F...
759
  	case FB_VISUAL_PSEUDOCOLOR:
3cbe9cff9   Krzysztof Helt   tdfxfb: checkpatc...
760
761
762
  		rgbcol = (((u32)red   & 0xff00) << 8) |
  			 (((u32)green & 0xff00) << 0) |
  			 (((u32)blue  & 0xff00) >> 8);
54243cefd   Antonino A. Daplas   [PATCH] tdfxfb: F...
763
764
765
766
767
  		do_setpalentry(par, regno, rgbcol);
  		break;
  	/* Truecolor has no hardware color palettes. */
  	case FB_VISUAL_TRUECOLOR:
  		if (regno < 16) {
8af1d50f7   Krzysztof Helt   tdfxfb: coding st...
768
  			rgbcol = (CNVT_TOHW(red, info->var.red.length) <<
a807f618b   Antonino A. Daplas   [PATCH] fbdev: td...
769
  				  info->var.red.offset) |
8af1d50f7   Krzysztof Helt   tdfxfb: coding st...
770
  				(CNVT_TOHW(green, info->var.green.length) <<
54243cefd   Antonino A. Daplas   [PATCH] tdfxfb: F...
771
  				 info->var.green.offset) |
8af1d50f7   Krzysztof Helt   tdfxfb: coding st...
772
  				(CNVT_TOHW(blue, info->var.blue.length) <<
54243cefd   Antonino A. Daplas   [PATCH] tdfxfb: F...
773
  				 info->var.blue.offset) |
8af1d50f7   Krzysztof Helt   tdfxfb: coding st...
774
  				(CNVT_TOHW(transp, info->var.transp.length) <<
54243cefd   Antonino A. Daplas   [PATCH] tdfxfb: F...
775
776
777
778
779
780
781
782
783
  				 info->var.transp.offset);
  			par->palette[regno] = rgbcol;
  		}
  
  		break;
  	default:
  		DPRINTK("bad depth %u
  ", info->var.bits_per_pixel);
  		break;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
784
  	}
54243cefd   Antonino A. Daplas   [PATCH] tdfxfb: F...
785

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
786
787
788
789
790
  	return 0;
  }
  
  /* 0 unblank, 1 blank, 2 no vsync, 3 no hsync, 4 off */
  static int tdfxfb_blank(int blank, struct fb_info *info)
8af1d50f7   Krzysztof Helt   tdfxfb: coding st...
791
  {
a807f618b   Antonino A. Daplas   [PATCH] fbdev: td...
792
  	struct tdfx_par *par = info->par;
4f05b53b2   Krzysztof Helt   tdfxfb: code impr...
793
794
  	int vgablank = 1;
  	u32 dacmode = tdfx_inl(par, DACMODE);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
795

4f05b53b2   Krzysztof Helt   tdfxfb: code impr...
796
  	dacmode &= ~(BIT(1) | BIT(3));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
797
798
  
  	switch (blank) {
8af1d50f7   Krzysztof Helt   tdfxfb: coding st...
799
  	case FB_BLANK_UNBLANK: /* Screen: On; HSync: On, VSync: On */
8af1d50f7   Krzysztof Helt   tdfxfb: coding st...
800
801
802
  		vgablank = 0;
  		break;
  	case FB_BLANK_NORMAL: /* Screen: Off; HSync: On, VSync: On */
8af1d50f7   Krzysztof Helt   tdfxfb: coding st...
803
804
  		break;
  	case FB_BLANK_VSYNC_SUSPEND: /* Screen: Off; HSync: On, VSync: Off */
4f05b53b2   Krzysztof Helt   tdfxfb: code impr...
805
  		dacmode |= BIT(3);
8af1d50f7   Krzysztof Helt   tdfxfb: coding st...
806
807
  		break;
  	case FB_BLANK_HSYNC_SUSPEND: /* Screen: Off; HSync: Off, VSync: On */
4f05b53b2   Krzysztof Helt   tdfxfb: code impr...
808
  		dacmode |= BIT(1);
8af1d50f7   Krzysztof Helt   tdfxfb: coding st...
809
810
  		break;
  	case FB_BLANK_POWERDOWN: /* Screen: Off; HSync: Off, VSync: Off */
4f05b53b2   Krzysztof Helt   tdfxfb: code impr...
811
  		dacmode |= BIT(1) | BIT(3);
8af1d50f7   Krzysztof Helt   tdfxfb: coding st...
812
  		break;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
813
  	}
8af1d50f7   Krzysztof Helt   tdfxfb: coding st...
814
  	banshee_make_room(par, 1);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
815
  	tdfx_outl(par, DACMODE, dacmode);
8af1d50f7   Krzysztof Helt   tdfxfb: coding st...
816
  	if (vgablank)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
817
818
819
820
821
  		vga_disable_video(par);
  	else
  		vga_enable_video(par);
  	return 0;
  }
8af1d50f7   Krzysztof Helt   tdfxfb: coding st...
822
  /*
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
823
   * Set the starting position of the visible screen to var->yoffset
8af1d50f7   Krzysztof Helt   tdfxfb: coding st...
824
   */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
825
  static int tdfxfb_pan_display(struct fb_var_screeninfo *var,
8af1d50f7   Krzysztof Helt   tdfxfb: coding st...
826
  			      struct fb_info *info)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
827
  {
a807f618b   Antonino A. Daplas   [PATCH] fbdev: td...
828
  	struct tdfx_par *par = info->par;
4f05b53b2   Krzysztof Helt   tdfxfb: code impr...
829
  	u32 addr = var->yoffset * info->fix.line_length;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
830

c2c12155c   Krzysztof Helt   tdfxfb: remove yp...
831
  	if (nopan || var->xoffset)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
832
  		return -EINVAL;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
833
834
  	banshee_make_room(par, 1);
  	tdfx_outl(par, VIDDESKSTART, addr);
8af1d50f7   Krzysztof Helt   tdfxfb: coding st...
835

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
836
837
838
839
840
  	return 0;
  }
  
  #ifdef CONFIG_FB_3DFX_ACCEL
  /*
8af1d50f7   Krzysztof Helt   tdfxfb: coding st...
841
   * FillRect 2D command (solidfill or invert (via ROP_XOR))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
842
   */
8af1d50f7   Krzysztof Helt   tdfxfb: coding st...
843
844
  static void tdfxfb_fillrect(struct fb_info *info,
  			    const struct fb_fillrect *rect)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
845
  {
a807f618b   Antonino A. Daplas   [PATCH] fbdev: td...
846
  	struct tdfx_par *par = info->par;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
847
848
  	u32 bpp = info->var.bits_per_pixel;
  	u32 stride = info->fix.line_length;
3cbe9cff9   Krzysztof Helt   tdfxfb: checkpatc...
849
  	u32 fmt = stride | ((bpp + ((bpp == 8) ? 0 : 8)) << 13);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
850
  	int tdfx_rop;
92744dd51   Krzysztof Helt   tdfxfb: 3 fixes
851
852
853
  	u32 dx = rect->dx;
  	u32 dy = rect->dy;
  	u32 dstbase = 0;
8af1d50f7   Krzysztof Helt   tdfxfb: coding st...
854
855
  
  	if (rect->rop == ROP_COPY)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
856
  		tdfx_rop = TDFX_ROP_COPY;
8af1d50f7   Krzysztof Helt   tdfxfb: coding st...
857
  	else
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
858
  		tdfx_rop = TDFX_ROP_XOR;
25985edce   Lucas De Marchi   Fix common misspe...
859
  	/* assume always rect->height < 4096 */
92744dd51   Krzysztof Helt   tdfxfb: 3 fixes
860
861
862
863
  	if (dy + rect->height > 4095) {
  		dstbase = stride * dy;
  		dy = 0;
  	}
25985edce   Lucas De Marchi   Fix common misspe...
864
  	/* assume always rect->width < 4096 */
92744dd51   Krzysztof Helt   tdfxfb: 3 fixes
865
866
867
868
869
  	if (dx + rect->width > 4095) {
  		dstbase += dx * bpp >> 3;
  		dx = 0;
  	}
  	banshee_make_room(par, 6);
8af1d50f7   Krzysztof Helt   tdfxfb: coding st...
870
  	tdfx_outl(par, DSTFORMAT, fmt);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
871
  	if (info->fix.visual == FB_VISUAL_PSEUDOCOLOR) {
8af1d50f7   Krzysztof Helt   tdfxfb: coding st...
872
  		tdfx_outl(par, COLORFORE, rect->color);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
873
  	} else { /* FB_VISUAL_TRUECOLOR */
a807f618b   Antonino A. Daplas   [PATCH] fbdev: td...
874
  		tdfx_outl(par, COLORFORE, par->palette[rect->color]);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
875
  	}
8af1d50f7   Krzysztof Helt   tdfxfb: coding st...
876
  	tdfx_outl(par, COMMAND_2D, COMMAND_2D_FILLRECT | (tdfx_rop << 24));
92744dd51   Krzysztof Helt   tdfxfb: 3 fixes
877
  	tdfx_outl(par, DSTBASE, dstbase);
8af1d50f7   Krzysztof Helt   tdfxfb: coding st...
878
  	tdfx_outl(par, DSTSIZE, rect->width | (rect->height << 16));
92744dd51   Krzysztof Helt   tdfxfb: 3 fixes
879
  	tdfx_outl(par, LAUNCH_2D, dx | (dy << 16));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
880
881
882
  }
  
  /*
8af1d50f7   Krzysztof Helt   tdfxfb: coding st...
883
   * Screen-to-Screen BitBlt 2D command (for the bmove fb op.)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
884
   */
8af1d50f7   Krzysztof Helt   tdfxfb: coding st...
885
886
  static void tdfxfb_copyarea(struct fb_info *info,
  			    const struct fb_copyarea *area)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
887
  {
a807f618b   Antonino A. Daplas   [PATCH] fbdev: td...
888
  	struct tdfx_par *par = info->par;
8af1d50f7   Krzysztof Helt   tdfxfb: coding st...
889
  	u32 sx = area->sx, sy = area->sy, dx = area->dx, dy = area->dy;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
890
891
892
  	u32 bpp = info->var.bits_per_pixel;
  	u32 stride = info->fix.line_length;
  	u32 blitcmd = COMMAND_2D_S2S_BITBLT | (TDFX_ROP_COPY << 24);
8af1d50f7   Krzysztof Helt   tdfxfb: coding st...
893
  	u32 fmt = stride | ((bpp + ((bpp == 8) ? 0 : 8)) << 13);
92744dd51   Krzysztof Helt   tdfxfb: 3 fixes
894
895
  	u32 dstbase = 0;
  	u32 srcbase = 0;
25985edce   Lucas De Marchi   Fix common misspe...
896
  	/* assume always area->height < 4096 */
92744dd51   Krzysztof Helt   tdfxfb: 3 fixes
897
898
899
900
  	if (sy + area->height > 4095) {
  		srcbase = stride * sy;
  		sy = 0;
  	}
25985edce   Lucas De Marchi   Fix common misspe...
901
  	/* assume always area->width < 4096 */
92744dd51   Krzysztof Helt   tdfxfb: 3 fixes
902
903
904
905
  	if (sx + area->width > 4095) {
  		srcbase += sx * bpp >> 3;
  		sx = 0;
  	}
25985edce   Lucas De Marchi   Fix common misspe...
906
  	/* assume always area->height < 4096 */
92744dd51   Krzysztof Helt   tdfxfb: 3 fixes
907
908
909
910
  	if (dy + area->height > 4095) {
  		dstbase = stride * dy;
  		dy = 0;
  	}
25985edce   Lucas De Marchi   Fix common misspe...
911
  	/* assume always area->width < 4096 */
92744dd51   Krzysztof Helt   tdfxfb: 3 fixes
912
913
914
915
  	if (dx + area->width > 4095) {
  		dstbase += dx * bpp >> 3;
  		dx = 0;
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
916
  	if (area->sx <= area->dx) {
3cbe9cff9   Krzysztof Helt   tdfxfb: checkpatc...
917
  		/* -X */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
918
919
920
921
922
  		blitcmd |= BIT(14);
  		sx += area->width - 1;
  		dx += area->width - 1;
  	}
  	if (area->sy <= area->dy) {
3cbe9cff9   Krzysztof Helt   tdfxfb: checkpatc...
923
  		/* -Y */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
924
925
926
927
  		blitcmd |= BIT(15);
  		sy += area->height - 1;
  		dy += area->height - 1;
  	}
8af1d50f7   Krzysztof Helt   tdfxfb: coding st...
928

92744dd51   Krzysztof Helt   tdfxfb: 3 fixes
929
  	banshee_make_room(par, 8);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
930

8af1d50f7   Krzysztof Helt   tdfxfb: coding st...
931
932
933
934
935
  	tdfx_outl(par, SRCFORMAT, fmt);
  	tdfx_outl(par, DSTFORMAT, fmt);
  	tdfx_outl(par, COMMAND_2D, blitcmd);
  	tdfx_outl(par, DSTSIZE, area->width | (area->height << 16));
  	tdfx_outl(par, DSTXY, dx | (dy << 16));
92744dd51   Krzysztof Helt   tdfxfb: 3 fixes
936
937
  	tdfx_outl(par, SRCBASE, srcbase);
  	tdfx_outl(par, DSTBASE, dstbase);
8af1d50f7   Krzysztof Helt   tdfxfb: coding st...
938
  	tdfx_outl(par, LAUNCH_2D, sx | (sy << 16));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
939
  }
8af1d50f7   Krzysztof Helt   tdfxfb: coding st...
940
  static void tdfxfb_imageblit(struct fb_info *info, const struct fb_image *image)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
941
  {
a807f618b   Antonino A. Daplas   [PATCH] fbdev: td...
942
  	struct tdfx_par *par = info->par;
8af1d50f7   Krzysztof Helt   tdfxfb: coding st...
943
  	int size = image->height * ((image->width * image->depth + 7) >> 3);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
944
945
946
  	int fifo_free;
  	int i, stride = info->fix.line_length;
  	u32 bpp = info->var.bits_per_pixel;
8af1d50f7   Krzysztof Helt   tdfxfb: coding st...
947
  	u32 dstfmt = stride | ((bpp + ((bpp == 8) ? 0 : 8)) << 13);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
948
949
  	u8 *chardata = (u8 *) image->data;
  	u32 srcfmt;
92744dd51   Krzysztof Helt   tdfxfb: 3 fixes
950
951
952
  	u32 dx = image->dx;
  	u32 dy = image->dy;
  	u32 dstbase = 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
953
954
  
  	if (image->depth != 1) {
3cbe9cff9   Krzysztof Helt   tdfxfb: checkpatc...
955
956
957
958
959
  #ifdef BROKEN_CODE
  		banshee_make_room(par, 6 + ((size + 3) >> 2));
  		srcfmt = stride | ((bpp + ((bpp == 8) ? 0 : 8)) << 13) |
  			0x400000;
  #else
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
960
  		cfb_imageblit(info, image);
3cbe9cff9   Krzysztof Helt   tdfxfb: checkpatc...
961
  #endif
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
962
  		return;
92744dd51   Krzysztof Helt   tdfxfb: 3 fixes
963
964
965
966
967
968
969
970
971
972
973
974
975
976
  	}
  	banshee_make_room(par, 9);
  	switch (info->fix.visual) {
  	case FB_VISUAL_PSEUDOCOLOR:
  		tdfx_outl(par, COLORFORE, image->fg_color);
  		tdfx_outl(par, COLORBACK, image->bg_color);
  		break;
  	case FB_VISUAL_TRUECOLOR:
  	default:
  		tdfx_outl(par, COLORFORE,
  			  par->palette[image->fg_color]);
  		tdfx_outl(par, COLORBACK,
  			  par->palette[image->bg_color]);
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
977
  #ifdef __BIG_ENDIAN
92744dd51   Krzysztof Helt   tdfxfb: 3 fixes
978
  	srcfmt = 0x400000 | BIT(20);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
979
  #else
92744dd51   Krzysztof Helt   tdfxfb: 3 fixes
980
  	srcfmt = 0x400000;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
981
  #endif
25985edce   Lucas De Marchi   Fix common misspe...
982
  	/* assume always image->height < 4096 */
92744dd51   Krzysztof Helt   tdfxfb: 3 fixes
983
984
985
986
  	if (dy + image->height > 4095) {
  		dstbase = stride * dy;
  		dy = 0;
  	}
25985edce   Lucas De Marchi   Fix common misspe...
987
  	/* assume always image->width < 4096 */
92744dd51   Krzysztof Helt   tdfxfb: 3 fixes
988
989
990
  	if (dx + image->width > 4095) {
  		dstbase += dx * bpp >> 3;
  		dx = 0;
8af1d50f7   Krzysztof Helt   tdfxfb: coding st...
991
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
992

92744dd51   Krzysztof Helt   tdfxfb: 3 fixes
993
  	tdfx_outl(par, DSTBASE, dstbase);
8af1d50f7   Krzysztof Helt   tdfxfb: coding st...
994
  	tdfx_outl(par, SRCXY, 0);
92744dd51   Krzysztof Helt   tdfxfb: 3 fixes
995
  	tdfx_outl(par, DSTXY, dx | (dy << 16));
3cbe9cff9   Krzysztof Helt   tdfxfb: checkpatc...
996
997
  	tdfx_outl(par, COMMAND_2D,
  		  COMMAND_2D_H2S_BITBLT | (TDFX_ROP_COPY << 24));
8af1d50f7   Krzysztof Helt   tdfxfb: coding st...
998
999
1000
  	tdfx_outl(par, SRCFORMAT, srcfmt);
  	tdfx_outl(par, DSTFORMAT, dstfmt);
  	tdfx_outl(par, DSTSIZE, image->width | (image->height << 16));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1001
1002
1003
1004
  
  	/* A count of how many free FIFO entries we've requested.
  	 * When this goes negative, we need to request more. */
  	fifo_free = 0;
8af1d50f7   Krzysztof Helt   tdfxfb: coding st...
1005
1006
1007
1008
1009
  	/* Send four bytes at a time of data */
  	for (i = (size >> 2); i > 0; i--) {
  		if (--fifo_free < 0) {
  			fifo_free = 31;
  			banshee_make_room(par, fifo_free);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1010
  		}
3cbe9cff9   Krzysztof Helt   tdfxfb: checkpatc...
1011
  		tdfx_outl(par, LAUNCH_2D, *(u32 *)chardata);
8af1d50f7   Krzysztof Helt   tdfxfb: coding st...
1012
1013
  		chardata += 4;
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1014

8af1d50f7   Krzysztof Helt   tdfxfb: coding st...
1015
1016
  	/* Send the leftovers now */
  	banshee_make_room(par, 3);
4f05b53b2   Krzysztof Helt   tdfxfb: code impr...
1017
  	switch (size % 4) {
8af1d50f7   Krzysztof Helt   tdfxfb: coding st...
1018
1019
1020
1021
1022
1023
  	case 0:
  		break;
  	case 1:
  		tdfx_outl(par, LAUNCH_2D, *chardata);
  		break;
  	case 2:
3cbe9cff9   Krzysztof Helt   tdfxfb: checkpatc...
1024
  		tdfx_outl(par, LAUNCH_2D, *(u16 *)chardata);
8af1d50f7   Krzysztof Helt   tdfxfb: coding st...
1025
1026
1027
  		break;
  	case 3:
  		tdfx_outl(par, LAUNCH_2D,
3cbe9cff9   Krzysztof Helt   tdfxfb: checkpatc...
1028
  			*(u16 *)chardata | (chardata[3] << 24));
8af1d50f7   Krzysztof Helt   tdfxfb: coding st...
1029
  		break;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1030
1031
1032
  	}
  }
  #endif /* CONFIG_FB_3DFX_ACCEL */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1033
1034
  static int tdfxfb_cursor(struct fb_info *info, struct fb_cursor *cursor)
  {
a807f618b   Antonino A. Daplas   [PATCH] fbdev: td...
1035
  	struct tdfx_par *par = info->par;
90b0f0853   Krzysztof Helt   tdfxfb: hardware ...
1036
1037
1038
1039
1040
1041
1042
1043
1044
1045
1046
1047
1048
1049
1050
1051
  	u32 vidcfg;
  
  	if (!hwcursor)
  		return -EINVAL;	/* just to force soft_cursor() call */
  
  	/* Too large of a cursor or wrong bpp :-( */
  	if (cursor->image.width > 64 ||
  	    cursor->image.height > 64 ||
  	    cursor->image.depth > 1)
  		return -EINVAL;
  
  	vidcfg = tdfx_inl(par, VIDPROCCFG);
  	if (cursor->enable)
  		tdfx_outl(par, VIDPROCCFG, vidcfg | VIDCFG_HWCURSOR_ENABLE);
  	else
  		tdfx_outl(par, VIDPROCCFG, vidcfg & ~VIDCFG_HWCURSOR_ENABLE);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1052
1053
  
  	/*
8af1d50f7   Krzysztof Helt   tdfxfb: coding st...
1054
  	 * If the cursor is not be changed this means either we want the
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1055
  	 * current cursor state (if enable is set) or we want to query what
8af1d50f7   Krzysztof Helt   tdfxfb: coding st...
1056
1057
1058
1059
  	 * we can do with the cursor (if enable is not set)
  	 */
  	if (!cursor->set)
  		return 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1060

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1061
  	/* fix cursor color - XFree86 forgets to restore it properly */
90b0f0853   Krzysztof Helt   tdfxfb: hardware ...
1062
1063
1064
1065
  	if (cursor->set & FB_CUR_SETCMAP) {
  		struct fb_cmap cmap = info->cmap;
  		u32 bg_idx = cursor->image.bg_color;
  		u32 fg_idx = cursor->image.fg_color;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1066
  		unsigned long bg_color, fg_color;
90b0f0853   Krzysztof Helt   tdfxfb: hardware ...
1067
1068
1069
1070
1071
1072
  		fg_color = (((u32)cmap.red[fg_idx]   & 0xff00) << 8) |
  			   (((u32)cmap.green[fg_idx] & 0xff00) << 0) |
  			   (((u32)cmap.blue[fg_idx]  & 0xff00) >> 8);
  		bg_color = (((u32)cmap.red[bg_idx]   & 0xff00) << 8) |
  			   (((u32)cmap.green[bg_idx] & 0xff00) << 0) |
  			   (((u32)cmap.blue[bg_idx]  & 0xff00) >> 8);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1073
1074
1075
  		banshee_make_room(par, 2);
  		tdfx_outl(par, HWCURC0, bg_color);
  		tdfx_outl(par, HWCURC1, fg_color);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1076
  	}
90b0f0853   Krzysztof Helt   tdfxfb: hardware ...
1077
1078
1079
  	if (cursor->set & FB_CUR_SETPOS) {
  		int x = cursor->image.dx;
  		int y = cursor->image.dy - info->var.yoffset;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1080

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1081
1082
  		x += 63;
  		y += 63;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1083
1084
  		banshee_make_room(par, 1);
  		tdfx_outl(par, HWCURLOC, (y << 16) + x);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1085
  	}
90b0f0853   Krzysztof Helt   tdfxfb: hardware ...
1086
  	if (cursor->set & (FB_CUR_SETIMAGE | FB_CUR_SETSHAPE)) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1087
  		/*
8af1d50f7   Krzysztof Helt   tdfxfb: coding st...
1088
  		 * Voodoo 3 and above cards use 2 monochrome cursor patterns.
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1089
1090
1091
1092
1093
  		 *    The reason is so the card can fetch 8 words at a time
  		 * and are stored on chip for use for the next 8 scanlines.
  		 * This reduces the number of times for access to draw the
  		 * cursor for each screen refresh.
  		 *    Each pattern is a bitmap of 64 bit wide and 64 bit high
90b0f0853   Krzysztof Helt   tdfxfb: hardware ...
1094
  		 * (total of 8192 bits or 1024 bytes). The two patterns are
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1095
1096
1097
1098
  		 * stored in such a way that pattern 0 always resides in the
  		 * lower half (least significant 64 bits) of a 128 bit word
  		 * and pattern 1 the upper half. If you examine the data of
  		 * the cursor image the graphics card uses then from the
25985edce   Lucas De Marchi   Fix common misspe...
1099
  		 * beginning you see line one of pattern 0, line one of
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1100
1101
1102
1103
1104
  		 * pattern 1, line two of pattern 0, line two of pattern 1,
  		 * etc etc. The linear stride for the cursor is always 16 bytes
  		 * (128 bits) which is the maximum cursor width times two for
  		 * the two monochrome patterns.
  		 */
90b0f0853   Krzysztof Helt   tdfxfb: hardware ...
1105
1106
1107
1108
1109
1110
1111
1112
1113
1114
1115
1116
1117
1118
1119
1120
1121
1122
1123
1124
1125
1126
  		u8 __iomem *cursorbase = info->screen_base + info->fix.smem_len;
  		u8 *bitmap = (u8 *)cursor->image.data;
  		u8 *mask = (u8 *)cursor->mask;
  		int i;
  
  		fb_memset(cursorbase, 0, 1024);
  
  		for (i = 0; i < cursor->image.height; i++) {
  			int h = 0;
  			int j = (cursor->image.width + 7) >> 3;
  
  			for (; j > 0; j--) {
  				u8 data = *mask ^ *bitmap;
  				if (cursor->rop == ROP_COPY)
  					data = *mask & *bitmap;
  				/* Pattern 0. Copy the cursor mask to it */
  				fb_writeb(*mask, cursorbase + h);
  				mask++;
  				/* Pattern 1. Copy the cursor bitmap to it */
  				fb_writeb(data, cursorbase + h + 8);
  				bitmap++;
  				h++;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1127
  			}
90b0f0853   Krzysztof Helt   tdfxfb: hardware ...
1128
  			cursorbase += 16;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1129
1130
  		}
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1131
1132
  	return 0;
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1133

8af1d50f7   Krzysztof Helt   tdfxfb: coding st...
1134
1135
1136
1137
1138
1139
1140
1141
  static struct fb_ops tdfxfb_ops = {
  	.owner		= THIS_MODULE,
  	.fb_check_var	= tdfxfb_check_var,
  	.fb_set_par	= tdfxfb_set_par,
  	.fb_setcolreg	= tdfxfb_setcolreg,
  	.fb_blank	= tdfxfb_blank,
  	.fb_pan_display	= tdfxfb_pan_display,
  	.fb_sync	= banshee_wait_idle,
90b0f0853   Krzysztof Helt   tdfxfb: hardware ...
1142
  	.fb_cursor	= tdfxfb_cursor,
8af1d50f7   Krzysztof Helt   tdfxfb: coding st...
1143
1144
1145
1146
1147
1148
1149
1150
1151
1152
  #ifdef CONFIG_FB_3DFX_ACCEL
  	.fb_fillrect	= tdfxfb_fillrect,
  	.fb_copyarea	= tdfxfb_copyarea,
  	.fb_imageblit	= tdfxfb_imageblit,
  #else
  	.fb_fillrect	= cfb_fillrect,
  	.fb_copyarea	= cfb_copyarea,
  	.fb_imageblit	= cfb_imageblit,
  #endif
  };
feff3880d   Krzysztof Helt   tdfxfb: move I2C ...
1153
1154
1155
1156
1157
1158
1159
1160
1161
1162
1163
1164
1165
1166
1167
1168
1169
1170
1171
1172
1173
1174
1175
1176
1177
1178
1179
1180
1181
1182
1183
1184
1185
1186
1187
1188
1189
1190
1191
1192
1193
1194
1195
1196
1197
1198
1199
1200
1201
1202
1203
1204
1205
1206
1207
1208
1209
1210
1211
1212
1213
1214
1215
1216
1217
1218
1219
1220
1221
1222
1223
1224
1225
1226
1227
1228
1229
1230
1231
1232
1233
1234
1235
1236
1237
1238
1239
1240
1241
1242
1243
1244
1245
1246
1247
1248
1249
1250
1251
1252
1253
1254
1255
1256
1257
1258
1259
1260
1261
1262
1263
1264
1265
1266
1267
1268
1269
1270
1271
1272
1273
1274
1275
1276
1277
1278
1279
1280
1281
1282
1283
1284
1285
1286
1287
1288
1289
  #ifdef CONFIG_FB_3DFX_I2C
  /* The voo GPIO registers don't have individual masks for each bit
     so we always have to read before writing. */
  
  static void tdfxfb_i2c_setscl(void *data, int val)
  {
  	struct tdfxfb_i2c_chan 	*chan = data;
  	struct tdfx_par 	*par = chan->par;
  	unsigned int r;
  
  	r = tdfx_inl(par, VIDSERPARPORT);
  	if (val)
  		r |= I2C_SCL_OUT;
  	else
  		r &= ~I2C_SCL_OUT;
  	tdfx_outl(par, VIDSERPARPORT, r);
  	tdfx_inl(par, VIDSERPARPORT);	/* flush posted write */
  }
  
  static void tdfxfb_i2c_setsda(void *data, int val)
  {
  	struct tdfxfb_i2c_chan 	*chan = data;
  	struct tdfx_par 	*par = chan->par;
  	unsigned int r;
  
  	r = tdfx_inl(par, VIDSERPARPORT);
  	if (val)
  		r |= I2C_SDA_OUT;
  	else
  		r &= ~I2C_SDA_OUT;
  	tdfx_outl(par, VIDSERPARPORT, r);
  	tdfx_inl(par, VIDSERPARPORT);	/* flush posted write */
  }
  
  /* The GPIO pins are open drain, so the pins always remain outputs.
     We rely on the i2c-algo-bit routines to set the pins high before
     reading the input from other chips. */
  
  static int tdfxfb_i2c_getscl(void *data)
  {
  	struct tdfxfb_i2c_chan 	*chan = data;
  	struct tdfx_par 	*par = chan->par;
  
  	return (0 != (tdfx_inl(par, VIDSERPARPORT) & I2C_SCL_IN));
  }
  
  static int tdfxfb_i2c_getsda(void *data)
  {
  	struct tdfxfb_i2c_chan 	*chan = data;
  	struct tdfx_par 	*par = chan->par;
  
  	return (0 != (tdfx_inl(par, VIDSERPARPORT) & I2C_SDA_IN));
  }
  
  static void tdfxfb_ddc_setscl(void *data, int val)
  {
  	struct tdfxfb_i2c_chan 	*chan = data;
  	struct tdfx_par 	*par = chan->par;
  	unsigned int r;
  
  	r = tdfx_inl(par, VIDSERPARPORT);
  	if (val)
  		r |= DDC_SCL_OUT;
  	else
  		r &= ~DDC_SCL_OUT;
  	tdfx_outl(par, VIDSERPARPORT, r);
  	tdfx_inl(par, VIDSERPARPORT);	/* flush posted write */
  }
  
  static void tdfxfb_ddc_setsda(void *data, int val)
  {
  	struct tdfxfb_i2c_chan 	*chan = data;
  	struct tdfx_par 	*par = chan->par;
  	unsigned int r;
  
  	r = tdfx_inl(par, VIDSERPARPORT);
  	if (val)
  		r |= DDC_SDA_OUT;
  	else
  		r &= ~DDC_SDA_OUT;
  	tdfx_outl(par, VIDSERPARPORT, r);
  	tdfx_inl(par, VIDSERPARPORT);	/* flush posted write */
  }
  
  static int tdfxfb_ddc_getscl(void *data)
  {
  	struct tdfxfb_i2c_chan 	*chan = data;
  	struct tdfx_par 	*par = chan->par;
  
  	return (0 != (tdfx_inl(par, VIDSERPARPORT) & DDC_SCL_IN));
  }
  
  static int tdfxfb_ddc_getsda(void *data)
  {
  	struct tdfxfb_i2c_chan 	*chan = data;
  	struct tdfx_par 	*par = chan->par;
  
  	return (0 != (tdfx_inl(par, VIDSERPARPORT) & DDC_SDA_IN));
  }
  
  static int __devinit tdfxfb_setup_ddc_bus(struct tdfxfb_i2c_chan *chan,
  					  const char *name, struct device *dev)
  {
  	int rc;
  
  	strlcpy(chan->adapter.name, name, sizeof(chan->adapter.name));
  	chan->adapter.owner		= THIS_MODULE;
  	chan->adapter.class		= I2C_CLASS_DDC;
  	chan->adapter.algo_data		= &chan->algo;
  	chan->adapter.dev.parent	= dev;
  	chan->algo.setsda		= tdfxfb_ddc_setsda;
  	chan->algo.setscl		= tdfxfb_ddc_setscl;
  	chan->algo.getsda		= tdfxfb_ddc_getsda;
  	chan->algo.getscl		= tdfxfb_ddc_getscl;
  	chan->algo.udelay		= 10;
  	chan->algo.timeout		= msecs_to_jiffies(500);
  	chan->algo.data 		= chan;
  
  	i2c_set_adapdata(&chan->adapter, chan);
  
  	rc = i2c_bit_add_bus(&chan->adapter);
  	if (rc == 0)
  		DPRINTK("I2C bus %s registered.
  ", name);
  	else
  		chan->par = NULL;
  
  	return rc;
  }
  
  static int __devinit tdfxfb_setup_i2c_bus(struct tdfxfb_i2c_chan *chan,
  					  const char *name, struct device *dev)
  {
  	int rc;
  
  	strlcpy(chan->adapter.name, name, sizeof(chan->adapter.name));
  	chan->adapter.owner		= THIS_MODULE;
feff3880d   Krzysztof Helt   tdfxfb: move I2C ...
1290
1291
1292
1293
1294
1295
1296
1297
1298
1299
1300
1301
1302
1303
1304
1305
1306
1307
1308
1309
1310
1311
1312
1313
1314
1315
1316
1317
1318
1319
1320
1321
1322
1323
1324
1325
1326
1327
1328
1329
1330
1331
1332
1333
1334
1335
  	chan->adapter.algo_data		= &chan->algo;
  	chan->adapter.dev.parent	= dev;
  	chan->algo.setsda		= tdfxfb_i2c_setsda;
  	chan->algo.setscl		= tdfxfb_i2c_setscl;
  	chan->algo.getsda		= tdfxfb_i2c_getsda;
  	chan->algo.getscl		= tdfxfb_i2c_getscl;
  	chan->algo.udelay		= 10;
  	chan->algo.timeout		= msecs_to_jiffies(500);
  	chan->algo.data 		= chan;
  
  	i2c_set_adapdata(&chan->adapter, chan);
  
  	rc = i2c_bit_add_bus(&chan->adapter);
  	if (rc == 0)
  		DPRINTK("I2C bus %s registered.
  ", name);
  	else
  		chan->par = NULL;
  
  	return rc;
  }
  
  static void __devinit tdfxfb_create_i2c_busses(struct fb_info *info)
  {
  	struct tdfx_par *par = info->par;
  
  	tdfx_outl(par, VIDINFORMAT, 0x8160);
  	tdfx_outl(par, VIDSERPARPORT, 0xcffc0020);
  
  	par->chan[0].par = par;
  	par->chan[1].par = par;
  
  	tdfxfb_setup_ddc_bus(&par->chan[0], "Voodoo3-DDC", info->dev);
  	tdfxfb_setup_i2c_bus(&par->chan[1], "Voodoo3-I2C", info->dev);
  }
  
  static void tdfxfb_delete_i2c_busses(struct tdfx_par *par)
  {
  	if (par->chan[0].par)
  		i2c_del_adapter(&par->chan[0].adapter);
  	par->chan[0].par = NULL;
  
  	if (par->chan[1].par)
  		i2c_del_adapter(&par->chan[1].adapter);
  	par->chan[1].par = NULL;
  }
215059d24   Krzysztof Helt   tdfxfb: make use ...
1336
1337
1338
1339
1340
1341
1342
1343
1344
1345
1346
1347
1348
1349
1350
1351
1352
1353
  
  static int tdfxfb_probe_i2c_connector(struct tdfx_par *par,
  				      struct fb_monspecs *specs)
  {
  	u8 *edid = NULL;
  
  	DPRINTK("Probe DDC Bus
  ");
  	if (par->chan[0].par)
  		edid = fb_ddc_read(&par->chan[0].adapter);
  
  	if (edid) {
  		fb_edid_to_monspecs(edid, specs);
  		kfree(edid);
  		return 0;
  	}
  	return 1;
  }
feff3880d   Krzysztof Helt   tdfxfb: move I2C ...
1354
  #endif /* CONFIG_FB_3DFX_I2C */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1355
1356
1357
1358
1359
1360
1361
1362
1363
1364
  /**
   *      tdfxfb_probe - Device Initializiation
   *
   *      @pdev:  PCI Device to initialize
   *      @id:    PCI Device ID
   *
   *      Initializes and allocates resources for PCI device @pdev.
   *
   */
  static int __devinit tdfxfb_probe(struct pci_dev *pdev,
8af1d50f7   Krzysztof Helt   tdfxfb: coding st...
1365
  				  const struct pci_device_id *id)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1366
1367
1368
  {
  	struct tdfx_par *default_par;
  	struct fb_info *info;
a807f618b   Antonino A. Daplas   [PATCH] fbdev: td...
1369
  	int err, lpitch;
215059d24   Krzysztof Helt   tdfxfb: make use ...
1370
1371
  	struct fb_monspecs *specs;
  	bool found;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1372

3cbe9cff9   Krzysztof Helt   tdfxfb: checkpatc...
1373
1374
1375
1376
  	err = pci_enable_device(pdev);
  	if (err) {
  		printk(KERN_ERR "tdfxfb: Can't enable pdev: %d
  ", err);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1377
1378
  		return err;
  	}
a807f618b   Antonino A. Daplas   [PATCH] fbdev: td...
1379
  	info = framebuffer_alloc(sizeof(struct tdfx_par), &pdev->dev);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1380

a807f618b   Antonino A. Daplas   [PATCH] fbdev: td...
1381
1382
  	if (!info)
  		return -ENOMEM;
8af1d50f7   Krzysztof Helt   tdfxfb: coding st...
1383

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1384
  	default_par = info->par;
3b25613c2   Krzysztof Helt   tdfxfb: do not ma...
1385
  	info->fix = tdfx_fix;
8af1d50f7   Krzysztof Helt   tdfxfb: coding st...
1386

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1387
1388
  	/* Configure the default fb_fix_screeninfo first */
  	switch (pdev->device) {
8af1d50f7   Krzysztof Helt   tdfxfb: coding st...
1389
  	case PCI_DEVICE_ID_3DFX_BANSHEE:
3b25613c2   Krzysztof Helt   tdfxfb: do not ma...
1390
  		strcpy(info->fix.id, "3Dfx Banshee");
8af1d50f7   Krzysztof Helt   tdfxfb: coding st...
1391
1392
1393
  		default_par->max_pixclock = BANSHEE_MAX_PIXCLOCK;
  		break;
  	case PCI_DEVICE_ID_3DFX_VOODOO3:
3b25613c2   Krzysztof Helt   tdfxfb: do not ma...
1394
  		strcpy(info->fix.id, "3Dfx Voodoo3");
8af1d50f7   Krzysztof Helt   tdfxfb: coding st...
1395
1396
1397
  		default_par->max_pixclock = VOODOO3_MAX_PIXCLOCK;
  		break;
  	case PCI_DEVICE_ID_3DFX_VOODOO5:
3b25613c2   Krzysztof Helt   tdfxfb: do not ma...
1398
  		strcpy(info->fix.id, "3Dfx Voodoo5");
8af1d50f7   Krzysztof Helt   tdfxfb: coding st...
1399
1400
  		default_par->max_pixclock = VOODOO5_MAX_PIXCLOCK;
  		break;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1401
  	}
3b25613c2   Krzysztof Helt   tdfxfb: do not ma...
1402
1403
1404
  	info->fix.mmio_start = pci_resource_start(pdev, 0);
  	info->fix.mmio_len = pci_resource_len(pdev, 0);
  	if (!request_mem_region(info->fix.mmio_start, info->fix.mmio_len,
92744dd51   Krzysztof Helt   tdfxfb: 3 fixes
1405
  				"tdfx regbase")) {
3cbe9cff9   Krzysztof Helt   tdfxfb: checkpatc...
1406
1407
  		printk(KERN_ERR "tdfxfb: Can't reserve regbase
  ");
92744dd51   Krzysztof Helt   tdfxfb: 3 fixes
1408
1409
  		goto out_err;
  	}
8af1d50f7   Krzysztof Helt   tdfxfb: coding st...
1410
  	default_par->regbase_virt =
3b25613c2   Krzysztof Helt   tdfxfb: do not ma...
1411
  		ioremap_nocache(info->fix.mmio_start, info->fix.mmio_len);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1412
  	if (!default_par->regbase_virt) {
3cbe9cff9   Krzysztof Helt   tdfxfb: checkpatc...
1413
1414
  		printk(KERN_ERR "fb: Can't remap %s register area.
  ",
3b25613c2   Krzysztof Helt   tdfxfb: do not ma...
1415
  				info->fix.id);
92744dd51   Krzysztof Helt   tdfxfb: 3 fixes
1416
  		goto out_err_regbase;
8af1d50f7   Krzysztof Helt   tdfxfb: coding st...
1417
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1418

3b25613c2   Krzysztof Helt   tdfxfb: do not ma...
1419
1420
1421
1422
1423
  	info->fix.smem_start = pci_resource_start(pdev, 1);
  	info->fix.smem_len = do_lfb_size(default_par, pdev->device);
  	if (!info->fix.smem_len) {
  		printk(KERN_ERR "fb: Can't count %s memory.
  ", info->fix.id);
92744dd51   Krzysztof Helt   tdfxfb: 3 fixes
1424
  		goto out_err_regbase;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1425
  	}
3b25613c2   Krzysztof Helt   tdfxfb: do not ma...
1426
  	if (!request_mem_region(info->fix.smem_start,
8af1d50f7   Krzysztof Helt   tdfxfb: coding st...
1427
  				pci_resource_len(pdev, 1), "tdfx smem")) {
3cbe9cff9   Krzysztof Helt   tdfxfb: checkpatc...
1428
1429
  		printk(KERN_ERR "tdfxfb: Can't reserve smem
  ");
92744dd51   Krzysztof Helt   tdfxfb: 3 fixes
1430
  		goto out_err_regbase;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1431
  	}
3b25613c2   Krzysztof Helt   tdfxfb: do not ma...
1432
1433
  	info->screen_base = ioremap_nocache(info->fix.smem_start,
  					    info->fix.smem_len);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1434
  	if (!info->screen_base) {
3cbe9cff9   Krzysztof Helt   tdfxfb: checkpatc...
1435
1436
  		printk(KERN_ERR "fb: Can't remap %s framebuffer.
  ",
3b25613c2   Krzysztof Helt   tdfxfb: do not ma...
1437
  				info->fix.id);
92744dd51   Krzysztof Helt   tdfxfb: 3 fixes
1438
  		goto out_err_screenbase;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1439
1440
1441
  	}
  
  	default_par->iobase = pci_resource_start(pdev, 2);
8af1d50f7   Krzysztof Helt   tdfxfb: coding st...
1442

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1443
  	if (!request_region(pci_resource_start(pdev, 2),
8af1d50f7   Krzysztof Helt   tdfxfb: coding st...
1444
  			    pci_resource_len(pdev, 2), "tdfx iobase")) {
3cbe9cff9   Krzysztof Helt   tdfxfb: checkpatc...
1445
1446
  		printk(KERN_ERR "tdfxfb: Can't reserve iobase
  ");
92744dd51   Krzysztof Helt   tdfxfb: 3 fixes
1447
  		goto out_err_screenbase;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1448
  	}
3b25613c2   Krzysztof Helt   tdfxfb: do not ma...
1449
1450
1451
  	printk(KERN_INFO "fb: %s memory = %dK
  ", info->fix.id,
  			info->fix.smem_len >> 10);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1452

0960bd3db   Krzysztof Helt   tdfxfb: mtrr support
1453
1454
1455
  	default_par->mtrr_handle = -1;
  	if (!nomtrr)
  		default_par->mtrr_handle =
3b25613c2   Krzysztof Helt   tdfxfb: do not ma...
1456
  			mtrr_add(info->fix.smem_start, info->fix.smem_len,
0960bd3db   Krzysztof Helt   tdfxfb: mtrr support
1457
  				 MTRR_TYPE_WRCOMB, 1);
3b25613c2   Krzysztof Helt   tdfxfb: do not ma...
1458
1459
  	info->fix.ypanstep	= nopan ? 0 : 1;
  	info->fix.ywrapstep	= nowrap ? 0 : 1;
8af1d50f7   Krzysztof Helt   tdfxfb: coding st...
1460

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1461
  	info->fbops		= &tdfxfb_ops;
a807f618b   Antonino A. Daplas   [PATCH] fbdev: td...
1462
  	info->pseudo_palette	= default_par->palette;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1463
1464
  	info->flags		= FBINFO_DEFAULT | FBINFO_HWACCEL_YPAN;
  #ifdef CONFIG_FB_3DFX_ACCEL
3cbe9cff9   Krzysztof Helt   tdfxfb: checkpatc...
1465
  	info->flags		|= FBINFO_HWACCEL_FILLRECT |
92744dd51   Krzysztof Helt   tdfxfb: 3 fixes
1466
1467
1468
  				   FBINFO_HWACCEL_COPYAREA |
  				   FBINFO_HWACCEL_IMAGEBLIT |
  				   FBINFO_READS_FAST;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1469
  #endif
90b0f0853   Krzysztof Helt   tdfxfb: hardware ...
1470
1471
1472
1473
1474
  	/* reserve 8192 bits for cursor */
  	/* the 2.4 driver says PAGE_MASK boundary is not enough for Voodoo4 */
  	if (hwcursor)
  		info->fix.smem_len = (info->fix.smem_len - 1024) &
  					(PAGE_MASK << 1);
215059d24   Krzysztof Helt   tdfxfb: make use ...
1475
1476
1477
  	specs = &info->monspecs;
  	found = false;
  	info->var.bits_per_pixel = 8;
feff3880d   Krzysztof Helt   tdfxfb: move I2C ...
1478
1479
  #ifdef CONFIG_FB_3DFX_I2C
  	tdfxfb_create_i2c_busses(info);
215059d24   Krzysztof Helt   tdfxfb: make use ...
1480
1481
1482
1483
1484
1485
1486
1487
1488
1489
1490
1491
1492
1493
1494
1495
1496
1497
1498
1499
1500
1501
1502
  	err = tdfxfb_probe_i2c_connector(default_par, specs);
  
  	if (!err) {
  		if (specs->modedb == NULL)
  			DPRINTK("Unable to get Mode Database
  ");
  		else {
  			const struct fb_videomode *m;
  
  			fb_videomode_to_modelist(specs->modedb,
  						 specs->modedb_len,
  						 &info->modelist);
  			m = fb_find_best_display(specs, &info->modelist);
  			if (m) {
  				fb_videomode_to_var(&info->var, m);
  				/* fill all other info->var's fields */
  				if (tdfxfb_check_var(&info->var, info) < 0)
  					info->var = tdfx_var;
  				else
  					found = true;
  			}
  		}
  	}
feff3880d   Krzysztof Helt   tdfxfb: move I2C ...
1503
  #endif
215059d24   Krzysztof Helt   tdfxfb: make use ...
1504
  	if (!mode_option && !found)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1505
  		mode_option = "640x480@60";
8af1d50f7   Krzysztof Helt   tdfxfb: coding st...
1506

215059d24   Krzysztof Helt   tdfxfb: make use ...
1507
1508
1509
1510
1511
1512
1513
1514
1515
1516
1517
1518
  	if (mode_option) {
  		err = fb_find_mode(&info->var, info, mode_option,
  				   specs->modedb, specs->modedb_len,
  				   NULL, info->var.bits_per_pixel);
  		if (!err || err == 4)
  			info->var = tdfx_var;
  	}
  
  	if (found) {
  		fb_destroy_modedb(specs->modedb);
  		specs->modedb = NULL;
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1519
1520
1521
  
  	/* maximize virtual vertical length */
  	lpitch = info->var.xres_virtual * ((info->var.bits_per_pixel + 7) >> 3);
8af1d50f7   Krzysztof Helt   tdfxfb: coding st...
1522
  	info->var.yres_virtual = info->fix.smem_len / lpitch;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1523
  	if (info->var.yres_virtual < info->var.yres)
92744dd51   Krzysztof Helt   tdfxfb: 3 fixes
1524
  		goto out_err_iobase;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1525
1526
  
  	if (fb_alloc_cmap(&info->cmap, 256, 0) < 0) {
3cbe9cff9   Krzysztof Helt   tdfxfb: checkpatc...
1527
1528
  		printk(KERN_ERR "tdfxfb: Can't allocate color map
  ");
92744dd51   Krzysztof Helt   tdfxfb: 3 fixes
1529
  		goto out_err_iobase;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1530
1531
1532
  	}
  
  	if (register_framebuffer(info) < 0) {
3cbe9cff9   Krzysztof Helt   tdfxfb: checkpatc...
1533
1534
  		printk(KERN_ERR "tdfxfb: can't register framebuffer
  ");
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1535
  		fb_dealloc_cmap(&info->cmap);
92744dd51   Krzysztof Helt   tdfxfb: 3 fixes
1536
  		goto out_err_iobase;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1537
1538
1539
1540
1541
  	}
  	/*
  	 * Our driver data
  	 */
  	pci_set_drvdata(pdev, info);
8af1d50f7   Krzysztof Helt   tdfxfb: coding st...
1542
  	return 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1543

92744dd51   Krzysztof Helt   tdfxfb: 3 fixes
1544
  out_err_iobase:
feff3880d   Krzysztof Helt   tdfxfb: move I2C ...
1545
1546
1547
  #ifdef CONFIG_FB_3DFX_I2C
  	tdfxfb_delete_i2c_busses(default_par);
  #endif
0960bd3db   Krzysztof Helt   tdfxfb: mtrr support
1548
1549
1550
  	if (default_par->mtrr_handle >= 0)
  		mtrr_del(default_par->mtrr_handle, info->fix.smem_start,
  			 info->fix.smem_len);
26692f53e   Julia Lawall   VIDEO: Correct us...
1551
1552
  	release_region(pci_resource_start(pdev, 2),
  		       pci_resource_len(pdev, 2));
92744dd51   Krzysztof Helt   tdfxfb: 3 fixes
1553
1554
1555
  out_err_screenbase:
  	if (info->screen_base)
  		iounmap(info->screen_base);
3b25613c2   Krzysztof Helt   tdfxfb: do not ma...
1556
  	release_mem_region(info->fix.smem_start, pci_resource_len(pdev, 1));
92744dd51   Krzysztof Helt   tdfxfb: 3 fixes
1557
  out_err_regbase:
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1558
1559
1560
1561
1562
  	/*
  	 * Cleanup after anything that was remapped/allocated.
  	 */
  	if (default_par->regbase_virt)
  		iounmap(default_par->regbase_virt);
3b25613c2   Krzysztof Helt   tdfxfb: do not ma...
1563
  	release_mem_region(info->fix.mmio_start, info->fix.mmio_len);
92744dd51   Krzysztof Helt   tdfxfb: 3 fixes
1564
  out_err:
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1565
1566
1567
1568
1569
  	framebuffer_release(info);
  	return -ENXIO;
  }
  
  #ifndef MODULE
0ce85eb88   Randy Dunlap   tdfxfb: fix secti...
1570
  static void __init tdfxfb_setup(char *options)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1571
  {
8af1d50f7   Krzysztof Helt   tdfxfb: coding st...
1572
  	char *this_opt;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1573
1574
1575
1576
1577
1578
1579
  
  	if (!options || !*options)
  		return;
  
  	while ((this_opt = strsep(&options, ",")) != NULL) {
  		if (!*this_opt)
  			continue;
8af1d50f7   Krzysztof Helt   tdfxfb: coding st...
1580
  		if (!strcmp(this_opt, "nopan")) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1581
  			nopan = 1;
8af1d50f7   Krzysztof Helt   tdfxfb: coding st...
1582
  		} else if (!strcmp(this_opt, "nowrap")) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1583
  			nowrap = 1;
0960bd3db   Krzysztof Helt   tdfxfb: mtrr support
1584
1585
1586
1587
1588
1589
  		} else if (!strncmp(this_opt, "hwcursor=", 9)) {
  			hwcursor = simple_strtoul(this_opt + 9, NULL, 0);
  #ifdef CONFIG_MTRR
  		} else if (!strncmp(this_opt, "nomtrr", 6)) {
  			nomtrr = 1;
  #endif
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1590
1591
1592
1593
1594
1595
1596
1597
1598
1599
1600
1601
1602
1603
1604
1605
1606
1607
1608
  		} else {
  			mode_option = this_opt;
  		}
  	}
  }
  #endif
  
  /**
   *      tdfxfb_remove - Device removal
   *
   *      @pdev:  PCI Device to cleanup
   *
   *      Releases all resources allocated during the course of the driver's
   *      lifetime for the PCI device @pdev.
   *
   */
  static void __devexit tdfxfb_remove(struct pci_dev *pdev)
  {
  	struct fb_info *info = pci_get_drvdata(pdev);
a807f618b   Antonino A. Daplas   [PATCH] fbdev: td...
1609
  	struct tdfx_par *par = info->par;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1610
1611
  
  	unregister_framebuffer(info);
feff3880d   Krzysztof Helt   tdfxfb: move I2C ...
1612
1613
1614
  #ifdef CONFIG_FB_3DFX_I2C
  	tdfxfb_delete_i2c_busses(par);
  #endif
0960bd3db   Krzysztof Helt   tdfxfb: mtrr support
1615
1616
1617
  	if (par->mtrr_handle >= 0)
  		mtrr_del(par->mtrr_handle, info->fix.smem_start,
  			 info->fix.smem_len);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1618
1619
1620
1621
1622
1623
1624
1625
1626
1627
1628
  	iounmap(par->regbase_virt);
  	iounmap(info->screen_base);
  
  	/* Clean up after reserved regions */
  	release_region(pci_resource_start(pdev, 2),
  		       pci_resource_len(pdev, 2));
  	release_mem_region(pci_resource_start(pdev, 1),
  			   pci_resource_len(pdev, 1));
  	release_mem_region(pci_resource_start(pdev, 0),
  			   pci_resource_len(pdev, 0));
  	pci_set_drvdata(pdev, NULL);
895d72279   Andres Salomon   tdfxfb: fix memor...
1629
  	fb_dealloc_cmap(&info->cmap);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1630
1631
1632
1633
1634
1635
1636
1637
1638
1639
1640
1641
1642
  	framebuffer_release(info);
  }
  
  static int __init tdfxfb_init(void)
  {
  #ifndef MODULE
  	char *option = NULL;
  
  	if (fb_get_options("tdfxfb", &option))
  		return -ENODEV;
  
  	tdfxfb_setup(option);
  #endif
8af1d50f7   Krzysztof Helt   tdfxfb: coding st...
1643
  	return pci_register_driver(&tdfxfb_driver);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1644
1645
1646
1647
  }
  
  static void __exit tdfxfb_exit(void)
  {
8af1d50f7   Krzysztof Helt   tdfxfb: coding st...
1648
  	pci_unregister_driver(&tdfxfb_driver);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1649
1650
1651
1652
1653
  }
  
  MODULE_AUTHOR("Hannu Mallat <hmallat@cc.hut.fi>");
  MODULE_DESCRIPTION("3Dfx framebuffer device driver");
  MODULE_LICENSE("GPL");
8af1d50f7   Krzysztof Helt   tdfxfb: coding st...
1654

90b0f0853   Krzysztof Helt   tdfxfb: hardware ...
1655
1656
1657
  module_param(hwcursor, int, 0644);
  MODULE_PARM_DESC(hwcursor, "Enable hardware cursor "
  			"(1=enable, 0=disable, default=1)");
ea9014bca   Krzysztof Helt   tdfxfb: add mode_...
1658
1659
  module_param(mode_option, charp, 0);
  MODULE_PARM_DESC(mode_option, "Initial video mode e.g. '648x480-8@60'");
0960bd3db   Krzysztof Helt   tdfxfb: mtrr support
1660
1661
1662
1663
  #ifdef CONFIG_MTRR
  module_param(nomtrr, bool, 0);
  MODULE_PARM_DESC(nomtrr, "Disable MTRR support (default: enabled)");
  #endif
90b0f0853   Krzysztof Helt   tdfxfb: hardware ...
1664

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1665
1666
  module_init(tdfxfb_init);
  module_exit(tdfxfb_exit);