Blame view

drivers/video/tridentfb.c 40.2 KB
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1
  /*
49b1f4b44   Krzysztof Helt   tridentfb: accele...
2
   * Frame buffer driver for Trident TGUI, Blade and Image series
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3
   *
245a2c2c6   Krzysztof Helt   tridentfb: coding...
4
   * Copyright 2001, 2002 - Jani Monoses   <jani@iv.ro>
ddb53d48d   Krzysztof Helt   fbdev: remove cyb...
5
   * Copyright 2009 Krzysztof Helt <krzysztof.h1@wp.pl>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
6
7
   *
   * CREDITS:(in order of appearance)
245a2c2c6   Krzysztof Helt   tridentfb: coding...
8
9
10
11
12
13
   *	skeletonfb.c by Geert Uytterhoeven and other fb code in drivers/video
   *	Special thanks ;) to Mattia Crivellini <tia@mclink.it>
   *	much inspired by the XFree86 4.x Trident driver sources
   *	by Alan Hourihane the FreeVGA project
   *	Francesco Salvestrini <salvestrini@users.sf.net> XP support,
   *	code, suggestions
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
14
   * TODO:
245a2c2c6   Krzysztof Helt   tridentfb: coding...
15
   *	timing value tweaking so it looks good on every monitor in every mode
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
16
   */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
17
18
19
20
  #include <linux/module.h>
  #include <linux/fb.h>
  #include <linux/init.h>
  #include <linux/pci.h>
5a0e3ad6a   Tejun Heo   include cleanup: ...
21
  #include <linux/slab.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
22
23
  
  #include <linux/delay.h>
10172ed6d   Krzysztof Helt   tridentfb: make u...
24
  #include <video/vga.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
25
  #include <video/trident.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
26
  struct tridentfb_par {
245a2c2c6   Krzysztof Helt   tridentfb: coding...
27
  	void __iomem *io_virt;	/* iospace virtual memory address */
ea8ee55c1   Krzysztof Helt   tridentfb: move g...
28
  	u32 pseudo_pal[16];
122e8ad3c   Krzysztof Helt   tridentfb: move g...
29
  	int chip_id;
6eed8e1ec   Krzysztof Helt   tridentfb: move g...
30
  	int flatpanel;
d9cad04bc   Krzysztof Helt   tridentfb: move g...
31
32
33
34
35
36
  	void (*init_accel) (struct tridentfb_par *, int, int);
  	void (*wait_engine) (struct tridentfb_par *);
  	void (*fill_rect)
  		(struct tridentfb_par *par, u32, u32, u32, u32, u32, u32);
  	void (*copy_rect)
  		(struct tridentfb_par *par, u32, u32, u32, u32, u32, u32);
0292be4a3   Krzysztof Helt   tridentfb: add im...
37
38
39
  	void (*image_blit)
  		(struct tridentfb_par *par, const char*,
  		 u32, u32, u32, u32, u32, u32);
5cf138457   Krzysztof Helt   tridentfb: source...
40
  	unsigned char eng_oper;	/* engine operation... */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
41
  };
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
42
  static struct fb_fix_screeninfo tridentfb_fix = {
245a2c2c6   Krzysztof Helt   tridentfb: coding...
43
  	.id = "Trident",
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
44
45
46
47
48
  	.type = FB_TYPE_PACKED_PIXELS,
  	.ypanstep = 1,
  	.visual = FB_VISUAL_PSEUDOCOLOR,
  	.accel = FB_ACCEL_NONE,
  };
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
49
50
51
  /* defaults which are normally overriden by user values */
  
  /* video mode */
5cf138457   Krzysztof Helt   tridentfb: source...
52
  static char *mode_option __devinitdata = "640x480-8@60";
6eed8e1ec   Krzysztof Helt   tridentfb: move g...
53
  static int bpp __devinitdata = 8;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
54

6eed8e1ec   Krzysztof Helt   tridentfb: move g...
55
  static int noaccel __devinitdata;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
56
57
58
  
  static int center;
  static int stretch;
6eed8e1ec   Krzysztof Helt   tridentfb: move g...
59
60
  static int fp __devinitdata;
  static int crt __devinitdata;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
61

6eed8e1ec   Krzysztof Helt   tridentfb: move g...
62
63
  static int memsize __devinitdata;
  static int memdiff __devinitdata;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
64
  static int nativex;
07f41e45f   Krzysztof Helt   tridentfb: change...
65
66
  module_param(mode_option, charp, 0);
  MODULE_PARM_DESC(mode_option, "Initial video mode e.g. '648x480-8@60'");
9e3f0ca81   Krzysztof Helt   fbdev: add remove...
67
68
  module_param_named(mode, mode_option, charp, 0);
  MODULE_PARM_DESC(mode, "Initial video mode e.g. '648x480-8@60' (deprecated)");
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
69
70
71
72
73
74
75
76
  module_param(bpp, int, 0);
  module_param(center, int, 0);
  module_param(stretch, int, 0);
  module_param(noaccel, int, 0);
  module_param(memsize, int, 0);
  module_param(memdiff, int, 0);
  module_param(nativex, int, 0);
  module_param(fp, int, 0);
6eed8e1ec   Krzysztof Helt   tridentfb: move g...
77
  MODULE_PARM_DESC(fp, "Define if flatpanel is connected");
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
78
  module_param(crt, int, 0);
6eed8e1ec   Krzysztof Helt   tridentfb: move g...
79
  MODULE_PARM_DESC(crt, "Define if CRT is connected");
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
80

5cf138457   Krzysztof Helt   tridentfb: source...
81
  static inline int is_oldclock(int id)
6bdf10356   Krzysztof Helt   tridentfb: fix cl...
82
  {
a0d922562   Krzysztof Helt   tridentfb: add TG...
83
84
  	return	(id == TGUI9440) ||
  		(id == TGUI9660) ||
0e73a47f0   Krzysztof Helt   tridentfb: improv...
85
86
  		(id == CYBER9320);
  }
5cf138457   Krzysztof Helt   tridentfb: source...
87
  static inline int is_oldprotect(int id)
0e73a47f0   Krzysztof Helt   tridentfb: improv...
88
  {
5cf138457   Krzysztof Helt   tridentfb: source...
89
  	return	is_oldclock(id) ||
0e73a47f0   Krzysztof Helt   tridentfb: improv...
90
  		(id == PROVIDIA9685) ||
0e73a47f0   Krzysztof Helt   tridentfb: improv...
91
92
  		(id == CYBER9382) ||
  		(id == CYBER9385);
6bdf10356   Krzysztof Helt   tridentfb: fix cl...
93
  }
5cf138457   Krzysztof Helt   tridentfb: source...
94
  static inline int is_blade(int id)
e0759a5fb   Krzysztof Helt   tridentfb: conver...
95
96
97
98
99
100
101
102
103
104
  {
  	return	(id == BLADE3D) ||
  		(id == CYBERBLADEE4) ||
  		(id == CYBERBLADEi7) ||
  		(id == CYBERBLADEi7D) ||
  		(id == CYBERBLADEi1) ||
  		(id == CYBERBLADEi1D) ||
  		(id == CYBERBLADEAi1) ||
  		(id == CYBERBLADEAi1D);
  }
5cf138457   Krzysztof Helt   tridentfb: source...
105
  static inline int is_xp(int id)
e0759a5fb   Krzysztof Helt   tridentfb: conver...
106
107
108
109
110
  {
  	return	(id == CYBERBLADEXPAi1) ||
  		(id == CYBERBLADEXPm8) ||
  		(id == CYBERBLADEXPm16);
  }
5cf138457   Krzysztof Helt   tridentfb: source...
111
  static inline int is3Dchip(int id)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
112
  {
5cf138457   Krzysztof Helt   tridentfb: source...
113
  	return	is_blade(id) || is_xp(id) ||
245a2c2c6   Krzysztof Helt   tridentfb: coding...
114
115
  		(id == CYBER9397) || (id == CYBER9397DVD) ||
  		(id == CYBER9520) || (id == CYBER9525DVD) ||
5cf138457   Krzysztof Helt   tridentfb: source...
116
  		(id == IMAGE975) || (id == IMAGE985);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
117
  }
5cf138457   Krzysztof Helt   tridentfb: source...
118
  static inline int iscyber(int id)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
119
120
  {
  	switch (id) {
245a2c2c6   Krzysztof Helt   tridentfb: coding...
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
  	case CYBER9388:
  	case CYBER9382:
  	case CYBER9385:
  	case CYBER9397:
  	case CYBER9397DVD:
  	case CYBER9520:
  	case CYBER9525DVD:
  	case CYBERBLADEE4:
  	case CYBERBLADEi7D:
  	case CYBERBLADEi1:
  	case CYBERBLADEi1D:
  	case CYBERBLADEAi1:
  	case CYBERBLADEAi1D:
  	case CYBERBLADEXPAi1:
  		return 1;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
136

245a2c2c6   Krzysztof Helt   tridentfb: coding...
137
  	case CYBER9320:
245a2c2c6   Krzysztof Helt   tridentfb: coding...
138
  	case CYBERBLADEi7:	/* VIA MPV4 integrated version */
245a2c2c6   Krzysztof Helt   tridentfb: coding...
139
140
141
142
  	default:
  		/* case CYBERBLDAEXPm8:  Strange */
  		/* case CYBERBLDAEXPm16: Strange */
  		return 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
143
144
  	}
  }
306fa6f60   Krzysztof Helt   tridentfb: replac...
145
146
147
148
  static inline void t_outb(struct tridentfb_par *p, u8 val, u16 reg)
  {
  	fb_writeb(val, p->io_virt + reg);
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
149

306fa6f60   Krzysztof Helt   tridentfb: replac...
150
151
152
153
  static inline u8 t_inb(struct tridentfb_par *p, u16 reg)
  {
  	return fb_readb(p->io_virt + reg);
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
154

306fa6f60   Krzysztof Helt   tridentfb: replac...
155
156
157
158
159
160
161
162
163
  static inline void writemmr(struct tridentfb_par *par, u16 r, u32 v)
  {
  	fb_writel(v, par->io_virt + r);
  }
  
  static inline u32 readmmr(struct tridentfb_par *par, u16 r)
  {
  	return fb_readl(par->io_virt + r);
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
164

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
165
166
167
  /*
   * Blade specific acceleration.
   */
245a2c2c6   Krzysztof Helt   tridentfb: coding...
168
  #define point(x, y) ((y) << 16 | (x))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
169

306fa6f60   Krzysztof Helt   tridentfb: replac...
170
  static void blade_init_accel(struct tridentfb_par *par, int pitch, int bpp)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
171
  {
245a2c2c6   Krzysztof Helt   tridentfb: coding...
172
  	int v1 = (pitch >> 3) << 20;
49b1f4b44   Krzysztof Helt   tridentfb: accele...
173
174
  	int tmp = bpp == 24 ? 2 : (bpp >> 4);
  	int v2 = v1 | (tmp << 29);
306fa6f60   Krzysztof Helt   tridentfb: replac...
175
176
177
178
179
180
181
182
183
  	writemmr(par, 0x21C0, v2);
  	writemmr(par, 0x21C4, v2);
  	writemmr(par, 0x21B8, v2);
  	writemmr(par, 0x21BC, v2);
  	writemmr(par, 0x21D0, v1);
  	writemmr(par, 0x21D4, v1);
  	writemmr(par, 0x21C8, v1);
  	writemmr(par, 0x21CC, v1);
  	writemmr(par, 0x216C, 0);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
184
  }
306fa6f60   Krzysztof Helt   tridentfb: replac...
185
  static void blade_wait_engine(struct tridentfb_par *par)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
186
  {
49b1f4b44   Krzysztof Helt   tridentfb: accele...
187
188
  	while (readmmr(par, STATUS) & 0xFA800000)
  		cpu_relax();
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
189
  }
306fa6f60   Krzysztof Helt   tridentfb: replac...
190
191
  static void blade_fill_rect(struct tridentfb_par *par,
  			    u32 x, u32 y, u32 w, u32 h, u32 c, u32 rop)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
192
  {
49b1f4b44   Krzysztof Helt   tridentfb: accele...
193
194
  	writemmr(par, COLOR, c);
  	writemmr(par, ROP, rop ? ROP_X : ROP_S);
306fa6f60   Krzysztof Helt   tridentfb: replac...
195
  	writemmr(par, CMD, 0x20000000 | 1 << 19 | 1 << 4 | 2 << 2);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
196

49b1f4b44   Krzysztof Helt   tridentfb: accele...
197
198
  	writemmr(par, DST1, point(x, y));
  	writemmr(par, DST2, point(x + w - 1, y + h - 1));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
199
  }
0292be4a3   Krzysztof Helt   tridentfb: add im...
200
201
202
203
204
205
206
207
208
209
210
211
212
213
  static void blade_image_blit(struct tridentfb_par *par, const char *data,
  			     u32 x, u32 y, u32 w, u32 h, u32 c, u32 b)
  {
  	unsigned size = ((w + 31) >> 5) * h;
  
  	writemmr(par, COLOR, c);
  	writemmr(par, BGCOLOR, b);
  	writemmr(par, CMD, 0xa0000000 | 3 << 19);
  
  	writemmr(par, DST1, point(x, y));
  	writemmr(par, DST2, point(x + w - 1, y + h - 1));
  
  	memcpy(par->io_virt + 0x10000, data, 4 * size);
  }
306fa6f60   Krzysztof Helt   tridentfb: replac...
214
215
  static void blade_copy_rect(struct tridentfb_par *par,
  			    u32 x1, u32 y1, u32 x2, u32 y2, u32 w, u32 h)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
216
  {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
217
  	int direction = 2;
49b1f4b44   Krzysztof Helt   tridentfb: accele...
218
219
220
221
  	u32 s1 = point(x1, y1);
  	u32 s2 = point(x1 + w - 1, y1 + h - 1);
  	u32 d1 = point(x2, y2);
  	u32 d2 = point(x2 + w - 1, y2 + h - 1);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
222
223
  
  	if ((y1 > y2) || ((y1 == y2) && (x1 > x2)))
245a2c2c6   Krzysztof Helt   tridentfb: coding...
224
  		direction = 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
225

306fa6f60   Krzysztof Helt   tridentfb: replac...
226
227
  	writemmr(par, ROP, ROP_S);
  	writemmr(par, CMD, 0xE0000000 | 1 << 19 | 1 << 4 | 1 << 2 | direction);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
228

49b1f4b44   Krzysztof Helt   tridentfb: accele...
229
230
231
232
  	writemmr(par, SRC1, direction ? s2 : s1);
  	writemmr(par, SRC2, direction ? s1 : s2);
  	writemmr(par, DST1, direction ? d2 : d1);
  	writemmr(par, DST2, direction ? d1 : d2);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
233
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
234
235
236
  /*
   * BladeXP specific acceleration functions
   */
306fa6f60   Krzysztof Helt   tridentfb: replac...
237
  static void xp_init_accel(struct tridentfb_par *par, int pitch, int bpp)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
238
  {
49b1f4b44   Krzysztof Helt   tridentfb: accele...
239
240
  	unsigned char x = bpp == 24 ? 3 : (bpp >> 4);
  	int v1 = pitch << (bpp == 24 ? 20 : (18 + x));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
241
242
  
  	switch (pitch << (bpp >> 3)) {
245a2c2c6   Krzysztof Helt   tridentfb: coding...
243
244
245
246
247
248
249
250
251
252
253
254
255
  	case 8192:
  	case 512:
  		x |= 0x00;
  		break;
  	case 1024:
  		x |= 0x04;
  		break;
  	case 2048:
  		x |= 0x08;
  		break;
  	case 4096:
  		x |= 0x0C;
  		break;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
256
  	}
306fa6f60   Krzysztof Helt   tridentfb: replac...
257
  	t_outb(par, x, 0x2125);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
258

5cf138457   Krzysztof Helt   tridentfb: source...
259
  	par->eng_oper = x | 0x40;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
260

306fa6f60   Krzysztof Helt   tridentfb: replac...
261
262
263
  	writemmr(par, 0x2154, v1);
  	writemmr(par, 0x2150, v1);
  	t_outb(par, 3, 0x2126);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
264
  }
306fa6f60   Krzysztof Helt   tridentfb: replac...
265
  static void xp_wait_engine(struct tridentfb_par *par)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
266
  {
5cf138457   Krzysztof Helt   tridentfb: source...
267
268
  	int count = 0;
  	int timeout = 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
269

49b1f4b44   Krzysztof Helt   tridentfb: accele...
270
  	while (t_inb(par, STATUS) & 0x80) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
271
272
273
274
275
276
277
  		count++;
  		if (count == 10000000) {
  			/* Timeout */
  			count = 9990000;
  			timeout++;
  			if (timeout == 8) {
  				/* Reset engine */
49b1f4b44   Krzysztof Helt   tridentfb: accele...
278
  				t_outb(par, 0x00, STATUS);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
279
280
281
  				return;
  			}
  		}
49b1f4b44   Krzysztof Helt   tridentfb: accele...
282
  		cpu_relax();
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
283
284
  	}
  }
306fa6f60   Krzysztof Helt   tridentfb: replac...
285
286
  static void xp_fill_rect(struct tridentfb_par *par,
  			 u32 x, u32 y, u32 w, u32 h, u32 c, u32 rop)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
287
  {
306fa6f60   Krzysztof Helt   tridentfb: replac...
288
289
  	writemmr(par, 0x2127, ROP_P);
  	writemmr(par, 0x2158, c);
49b1f4b44   Krzysztof Helt   tridentfb: accele...
290
291
292
293
  	writemmr(par, DRAWFL, 0x4000);
  	writemmr(par, OLDDIM, point(h, w));
  	writemmr(par, OLDDST, point(y, x));
  	t_outb(par, 0x01, OLDCMD);
5cf138457   Krzysztof Helt   tridentfb: source...
294
  	t_outb(par, par->eng_oper, 0x2125);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
295
  }
306fa6f60   Krzysztof Helt   tridentfb: replac...
296
297
  static void xp_copy_rect(struct tridentfb_par *par,
  			 u32 x1, u32 y1, u32 x2, u32 y2, u32 w, u32 h)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
298
  {
245a2c2c6   Krzysztof Helt   tridentfb: coding...
299
  	u32 x1_tmp, x2_tmp, y1_tmp, y2_tmp;
5cf138457   Krzysztof Helt   tridentfb: source...
300
  	int direction = 0x0004;
245a2c2c6   Krzysztof Helt   tridentfb: coding...
301

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
302
303
304
305
306
307
308
309
  	if ((x1 < x2) && (y1 == y2)) {
  		direction |= 0x0200;
  		x1_tmp = x1 + w - 1;
  		x2_tmp = x2 + w - 1;
  	} else {
  		x1_tmp = x1;
  		x2_tmp = x2;
  	}
245a2c2c6   Krzysztof Helt   tridentfb: coding...
310

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
311
312
313
314
  	if (y1 < y2) {
  		direction |= 0x0100;
  		y1_tmp = y1 + h - 1;
  		y2_tmp = y2 + h - 1;
245a2c2c6   Krzysztof Helt   tridentfb: coding...
315
  	} else {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
316
317
318
  		y1_tmp = y1;
  		y2_tmp = y2;
  	}
49b1f4b44   Krzysztof Helt   tridentfb: accele...
319
  	writemmr(par, DRAWFL, direction);
306fa6f60   Krzysztof Helt   tridentfb: replac...
320
  	t_outb(par, ROP_S, 0x2127);
49b1f4b44   Krzysztof Helt   tridentfb: accele...
321
322
323
324
  	writemmr(par, OLDSRC, point(y1_tmp, x1_tmp));
  	writemmr(par, OLDDST, point(y2_tmp, x2_tmp));
  	writemmr(par, OLDDIM, point(h, w));
  	t_outb(par, 0x01, OLDCMD);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
325
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
326
327
328
  /*
   * Image specific acceleration functions
   */
306fa6f60   Krzysztof Helt   tridentfb: replac...
329
  static void image_init_accel(struct tridentfb_par *par, int pitch, int bpp)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
330
  {
49b1f4b44   Krzysztof Helt   tridentfb: accele...
331
  	int tmp = bpp == 24 ? 2: (bpp >> 4);
306fa6f60   Krzysztof Helt   tridentfb: replac...
332
333
334
335
336
337
338
339
340
341
342
343
344
  	writemmr(par, 0x2120, 0xF0000000);
  	writemmr(par, 0x2120, 0x40000000 | tmp);
  	writemmr(par, 0x2120, 0x80000000);
  	writemmr(par, 0x2144, 0x00000000);
  	writemmr(par, 0x2148, 0x00000000);
  	writemmr(par, 0x2150, 0x00000000);
  	writemmr(par, 0x2154, 0x00000000);
  	writemmr(par, 0x2120, 0x60000000 | (pitch << 16) | pitch);
  	writemmr(par, 0x216C, 0x00000000);
  	writemmr(par, 0x2170, 0x00000000);
  	writemmr(par, 0x217C, 0x00000000);
  	writemmr(par, 0x2120, 0x10000000);
  	writemmr(par, 0x2130, (2047 << 16) | 2047);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
345
  }
306fa6f60   Krzysztof Helt   tridentfb: replac...
346
  static void image_wait_engine(struct tridentfb_par *par)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
347
  {
49b1f4b44   Krzysztof Helt   tridentfb: accele...
348
349
  	while (readmmr(par, 0x2164) & 0xF0000000)
  		cpu_relax();
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
350
  }
306fa6f60   Krzysztof Helt   tridentfb: replac...
351
352
  static void image_fill_rect(struct tridentfb_par *par,
  			    u32 x, u32 y, u32 w, u32 h, u32 c, u32 rop)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
353
  {
306fa6f60   Krzysztof Helt   tridentfb: replac...
354
355
  	writemmr(par, 0x2120, 0x80000000);
  	writemmr(par, 0x2120, 0x90000000 | ROP_S);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
356

306fa6f60   Krzysztof Helt   tridentfb: replac...
357
  	writemmr(par, 0x2144, c);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
358

49b1f4b44   Krzysztof Helt   tridentfb: accele...
359
360
  	writemmr(par, DST1, point(x, y));
  	writemmr(par, DST2, point(x + w - 1, y + h - 1));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
361

306fa6f60   Krzysztof Helt   tridentfb: replac...
362
  	writemmr(par, 0x2124, 0x80000000 | 3 << 22 | 1 << 10 | 1 << 9);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
363
  }
306fa6f60   Krzysztof Helt   tridentfb: replac...
364
365
  static void image_copy_rect(struct tridentfb_par *par,
  			    u32 x1, u32 y1, u32 x2, u32 y2, u32 w, u32 h)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
366
  {
2c86a0c26   Krzysztof Helt   tridentfb: accele...
367
  	int direction = 0x4;
49b1f4b44   Krzysztof Helt   tridentfb: accele...
368
369
370
371
  	u32 s1 = point(x1, y1);
  	u32 s2 = point(x1 + w - 1, y1 + h - 1);
  	u32 d1 = point(x2, y2);
  	u32 d2 = point(x2 + w - 1, y2 + h - 1);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
372

245a2c2c6   Krzysztof Helt   tridentfb: coding...
373
374
  	if ((y1 > y2) || ((y1 == y2) && (x1 > x2)))
  		direction = 0;
306fa6f60   Krzysztof Helt   tridentfb: replac...
375
376
  	writemmr(par, 0x2120, 0x80000000);
  	writemmr(par, 0x2120, 0x90000000 | ROP_S);
245a2c2c6   Krzysztof Helt   tridentfb: coding...
377

49b1f4b44   Krzysztof Helt   tridentfb: accele...
378
379
380
381
  	writemmr(par, SRC1, direction ? s2 : s1);
  	writemmr(par, SRC2, direction ? s1 : s2);
  	writemmr(par, DST1, direction ? d2 : d1);
  	writemmr(par, DST2, direction ? d1 : d2);
306fa6f60   Krzysztof Helt   tridentfb: replac...
382
383
  	writemmr(par, 0x2124,
  		 0x80000000 | 1 << 22 | 1 << 10 | 1 << 7 | direction);
245a2c2c6   Krzysztof Helt   tridentfb: coding...
384
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
385

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
386
  /*
bcac2d5fe   Krzysztof Helt   tridentfb: add ac...
387
388
389
390
391
   * TGUI 9440/96XX acceleration
   */
  
  static void tgui_init_accel(struct tridentfb_par *par, int pitch, int bpp)
  {
49b1f4b44   Krzysztof Helt   tridentfb: accele...
392
  	unsigned char x = bpp == 24 ? 3 : (bpp >> 4);
bcac2d5fe   Krzysztof Helt   tridentfb: add ac...
393
394
395
396
  
  	/* disable clipping */
  	writemmr(par, 0x2148, 0);
  	writemmr(par, 0x214C, point(4095, 2047));
bcac2d5fe   Krzysztof Helt   tridentfb: add ac...
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
  	switch ((pitch * bpp) / 8) {
  	case 8192:
  	case 512:
  		x |= 0x00;
  		break;
  	case 1024:
  		x |= 0x04;
  		break;
  	case 2048:
  		x |= 0x08;
  		break;
  	case 4096:
  		x |= 0x0C;
  		break;
  	}
  
  	fb_writew(x, par->io_virt + 0x2122);
  }
  
  static void tgui_fill_rect(struct tridentfb_par *par,
  			   u32 x, u32 y, u32 w, u32 h, u32 c, u32 rop)
  {
  	t_outb(par, ROP_P, 0x2127);
49b1f4b44   Krzysztof Helt   tridentfb: accele...
420
421
422
423
424
  	writemmr(par, OLDCLR, c);
  	writemmr(par, DRAWFL, 0x4020);
  	writemmr(par, OLDDIM, point(w - 1, h - 1));
  	writemmr(par, OLDDST, point(x, y));
  	t_outb(par, 1, OLDCMD);
bcac2d5fe   Krzysztof Helt   tridentfb: add ac...
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
  }
  
  static void tgui_copy_rect(struct tridentfb_par *par,
  			   u32 x1, u32 y1, u32 x2, u32 y2, u32 w, u32 h)
  {
  	int flags = 0;
  	u16 x1_tmp, x2_tmp, y1_tmp, y2_tmp;
  
  	if ((x1 < x2) && (y1 == y2)) {
  		flags |= 0x0200;
  		x1_tmp = x1 + w - 1;
  		x2_tmp = x2 + w - 1;
  	} else {
  		x1_tmp = x1;
  		x2_tmp = x2;
  	}
  
  	if (y1 < y2) {
  		flags |= 0x0100;
  		y1_tmp = y1 + h - 1;
  		y2_tmp = y2 + h - 1;
  	} else {
  		y1_tmp = y1;
  		y2_tmp = y2;
  	}
49b1f4b44   Krzysztof Helt   tridentfb: accele...
450
  	writemmr(par, DRAWFL, 0x4 | flags);
bcac2d5fe   Krzysztof Helt   tridentfb: add ac...
451
  	t_outb(par, ROP_S, 0x2127);
49b1f4b44   Krzysztof Helt   tridentfb: accele...
452
453
454
455
  	writemmr(par, OLDSRC, point(x1_tmp, y1_tmp));
  	writemmr(par, OLDDST, point(x2_tmp, y2_tmp));
  	writemmr(par, OLDDIM, point(w - 1, h - 1));
  	t_outb(par, 1, OLDCMD);
bcac2d5fe   Krzysztof Helt   tridentfb: add ac...
456
457
458
  }
  
  /*
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
459
460
   * Accel functions called by the upper layers
   */
245a2c2c6   Krzysztof Helt   tridentfb: coding...
461
462
  static void tridentfb_fillrect(struct fb_info *info,
  			       const struct fb_fillrect *fr)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
463
  {
306fa6f60   Krzysztof Helt   tridentfb: replac...
464
  	struct tridentfb_par *par = info->par;
49b1f4b44   Krzysztof Helt   tridentfb: accele...
465
  	int col;
245a2c2c6   Krzysztof Helt   tridentfb: coding...
466

01a2d9ed8   Krzysztof Helt   tridentfb: accele...
467
468
469
470
  	if (info->flags & FBINFO_HWACCEL_DISABLED) {
  		cfb_fillrect(info, fr);
  		return;
  	}
49b1f4b44   Krzysztof Helt   tridentfb: accele...
471
472
  	if (info->var.bits_per_pixel == 8) {
  		col = fr->color;
245a2c2c6   Krzysztof Helt   tridentfb: coding...
473
474
  		col |= col << 8;
  		col |= col << 16;
49b1f4b44   Krzysztof Helt   tridentfb: accele...
475
  	} else
245a2c2c6   Krzysztof Helt   tridentfb: coding...
476
  		col = ((u32 *)(info->pseudo_palette))[fr->color];
245a2c2c6   Krzysztof Helt   tridentfb: coding...
477

49b1f4b44   Krzysztof Helt   tridentfb: accele...
478
  	par->wait_engine(par);
d9cad04bc   Krzysztof Helt   tridentfb: move g...
479
  	par->fill_rect(par, fr->dx, fr->dy, fr->width,
306fa6f60   Krzysztof Helt   tridentfb: replac...
480
  		       fr->height, col, fr->rop);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
481
  }
49b1f4b44   Krzysztof Helt   tridentfb: accele...
482

0292be4a3   Krzysztof Helt   tridentfb: add im...
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
  static void tridentfb_imageblit(struct fb_info *info,
  				const struct fb_image *img)
  {
  	struct tridentfb_par *par = info->par;
  	int col, bgcol;
  
  	if ((info->flags & FBINFO_HWACCEL_DISABLED) || img->depth != 1) {
  		cfb_imageblit(info, img);
  		return;
  	}
  	if (info->var.bits_per_pixel == 8) {
  		col = img->fg_color;
  		col |= col << 8;
  		col |= col << 16;
  		bgcol = img->bg_color;
  		bgcol |= bgcol << 8;
  		bgcol |= bgcol << 16;
  	} else {
  		col = ((u32 *)(info->pseudo_palette))[img->fg_color];
  		bgcol = ((u32 *)(info->pseudo_palette))[img->bg_color];
  	}
  
  	par->wait_engine(par);
  	if (par->image_blit)
  		par->image_blit(par, img->data, img->dx, img->dy,
  				img->width, img->height, col, bgcol);
  	else
  		cfb_imageblit(info, img);
  }
245a2c2c6   Krzysztof Helt   tridentfb: coding...
512
513
  static void tridentfb_copyarea(struct fb_info *info,
  			       const struct fb_copyarea *ca)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
514
  {
306fa6f60   Krzysztof Helt   tridentfb: replac...
515
  	struct tridentfb_par *par = info->par;
01a2d9ed8   Krzysztof Helt   tridentfb: accele...
516
517
518
519
  	if (info->flags & FBINFO_HWACCEL_DISABLED) {
  		cfb_copyarea(info, ca);
  		return;
  	}
49b1f4b44   Krzysztof Helt   tridentfb: accele...
520
  	par->wait_engine(par);
d9cad04bc   Krzysztof Helt   tridentfb: move g...
521
  	par->copy_rect(par, ca->sx, ca->sy, ca->dx, ca->dy,
306fa6f60   Krzysztof Helt   tridentfb: replac...
522
  		       ca->width, ca->height);
49b1f4b44   Krzysztof Helt   tridentfb: accele...
523
524
525
526
527
  }
  
  static int tridentfb_sync(struct fb_info *info)
  {
  	struct tridentfb_par *par = info->par;
01a2d9ed8   Krzysztof Helt   tridentfb: accele...
528
529
  	if (!(info->flags & FBINFO_HWACCEL_DISABLED))
  		par->wait_engine(par);
49b1f4b44   Krzysztof Helt   tridentfb: accele...
530
  	return 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
531
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
532

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
533
534
535
  /*
   * Hardware access functions
   */
306fa6f60   Krzysztof Helt   tridentfb: replac...
536
  static inline unsigned char read3X4(struct tridentfb_par *par, int reg)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
537
  {
10172ed6d   Krzysztof Helt   tridentfb: make u...
538
  	return vga_mm_rcrt(par->io_virt, reg);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
539
  }
306fa6f60   Krzysztof Helt   tridentfb: replac...
540
541
  static inline void write3X4(struct tridentfb_par *par, int reg,
  			    unsigned char val)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
542
  {
10172ed6d   Krzysztof Helt   tridentfb: make u...
543
  	vga_mm_wcrt(par->io_virt, reg, val);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
544
  }
10172ed6d   Krzysztof Helt   tridentfb: make u...
545
546
  static inline unsigned char read3CE(struct tridentfb_par *par,
  				    unsigned char reg)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
547
  {
10172ed6d   Krzysztof Helt   tridentfb: make u...
548
  	return vga_mm_rgfx(par->io_virt, reg);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
549
  }
306fa6f60   Krzysztof Helt   tridentfb: replac...
550
551
  static inline void writeAttr(struct tridentfb_par *par, int reg,
  			     unsigned char val)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
552
  {
10172ed6d   Krzysztof Helt   tridentfb: make u...
553
554
  	fb_readb(par->io_virt + VGA_IS1_RC);	/* flip-flop to index */
  	vga_mm_wattr(par->io_virt, reg, val);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
555
  }
306fa6f60   Krzysztof Helt   tridentfb: replac...
556
557
  static inline void write3CE(struct tridentfb_par *par, int reg,
  			    unsigned char val)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
558
  {
10172ed6d   Krzysztof Helt   tridentfb: make u...
559
  	vga_mm_wgfx(par->io_virt, reg, val);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
560
  }
13b0de49f   Krzysztof Helt   tridentfb: fix co...
561
  static void enable_mmio(struct tridentfb_par *par)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
562
563
  {
  	/* Goto New Mode */
10172ed6d   Krzysztof Helt   tridentfb: make u...
564
  	vga_io_rseq(0x0B);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
565
566
  
  	/* Unprotect registers */
10172ed6d   Krzysztof Helt   tridentfb: make u...
567
  	vga_io_wseq(NewMode1, 0x80);
13b0de49f   Krzysztof Helt   tridentfb: fix co...
568
569
  	if (!is_oldprotect(par->chip_id))
  		vga_io_wseq(Protection, 0x92);
245a2c2c6   Krzysztof Helt   tridentfb: coding...
570

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
571
  	/* Enable MMIO */
245a2c2c6   Krzysztof Helt   tridentfb: coding...
572
  	outb(PCIReg, 0x3D4);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
573
  	outb(inb(0x3D5) | 0x01, 0x3D5);
e8ed857c6   Krzysztof Helt   tridentfb: resour...
574
  }
306fa6f60   Krzysztof Helt   tridentfb: replac...
575
  static void disable_mmio(struct tridentfb_par *par)
e8ed857c6   Krzysztof Helt   tridentfb: resour...
576
  {
e8ed857c6   Krzysztof Helt   tridentfb: resour...
577
  	/* Goto New Mode */
10172ed6d   Krzysztof Helt   tridentfb: make u...
578
  	vga_mm_rseq(par->io_virt, 0x0B);
e8ed857c6   Krzysztof Helt   tridentfb: resour...
579
580
  
  	/* Unprotect registers */
10172ed6d   Krzysztof Helt   tridentfb: make u...
581
  	vga_mm_wseq(par->io_virt, NewMode1, 0x80);
13b0de49f   Krzysztof Helt   tridentfb: fix co...
582
583
  	if (!is_oldprotect(par->chip_id))
  		vga_mm_wseq(par->io_virt, Protection, 0x92);
e8ed857c6   Krzysztof Helt   tridentfb: resour...
584
585
  
  	/* Disable MMIO */
306fa6f60   Krzysztof Helt   tridentfb: replac...
586
587
  	t_outb(par, PCIReg, 0x3D4);
  	t_outb(par, t_inb(par, 0x3D5) & ~0x01, 0x3D5);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
588
  }
5cf138457   Krzysztof Helt   tridentfb: source...
589
  static inline void crtc_unlock(struct tridentfb_par *par)
306fa6f60   Krzysztof Helt   tridentfb: replac...
590
  {
10172ed6d   Krzysztof Helt   tridentfb: make u...
591
592
  	write3X4(par, VGA_CRTC_V_SYNC_END,
  		 read3X4(par, VGA_CRTC_V_SYNC_END) & 0x7F);
306fa6f60   Krzysztof Helt   tridentfb: replac...
593
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
594
595
  
  /*  Return flat panel's maximum x resolution */
306fa6f60   Krzysztof Helt   tridentfb: replac...
596
  static int __devinit get_nativex(struct tridentfb_par *par)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
597
  {
245a2c2c6   Krzysztof Helt   tridentfb: coding...
598
  	int x, y, tmp;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
599
600
601
  
  	if (nativex)
  		return nativex;
306fa6f60   Krzysztof Helt   tridentfb: replac...
602
  	tmp = (read3CE(par, VertStretch) >> 4) & 3;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
603
604
  
  	switch (tmp) {
245a2c2c6   Krzysztof Helt   tridentfb: coding...
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
  	case 0:
  		x = 1280; y = 1024;
  		break;
  	case 2:
  		x = 1024; y = 768;
  		break;
  	case 3:
  		x = 800; y = 600;
  		break;
  	case 4:
  		x = 1400; y = 1050;
  		break;
  	case 1:
  	default:
  		x = 640;  y = 480;
  		break;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
621
622
623
624
625
626
627
628
  	}
  
  	output("%dx%d flat panel found
  ", x, y);
  	return x;
  }
  
  /* Set pitch */
5cf138457   Krzysztof Helt   tridentfb: source...
629
  static inline void set_lwidth(struct tridentfb_par *par, int width)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
630
  {
10172ed6d   Krzysztof Helt   tridentfb: make u...
631
  	write3X4(par, VGA_CRTC_OFFSET, width & 0xFF);
306fa6f60   Krzysztof Helt   tridentfb: replac...
632
633
  	write3X4(par, AddColReg,
  		 (read3X4(par, AddColReg) & 0xCF) | ((width & 0x300) >> 4));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
634
635
636
  }
  
  /* For resolutions smaller than FP resolution stretch */
306fa6f60   Krzysztof Helt   tridentfb: replac...
637
  static void screen_stretch(struct tridentfb_par *par)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
638
  {
122e8ad3c   Krzysztof Helt   tridentfb: move g...
639
  	if (par->chip_id != CYBERBLADEXPAi1)
306fa6f60   Krzysztof Helt   tridentfb: replac...
640
  		write3CE(par, BiosReg, 0);
245a2c2c6   Krzysztof Helt   tridentfb: coding...
641
  	else
306fa6f60   Krzysztof Helt   tridentfb: replac...
642
643
644
  		write3CE(par, BiosReg, 8);
  	write3CE(par, VertStretch, (read3CE(par, VertStretch) & 0x7C) | 1);
  	write3CE(par, HorStretch, (read3CE(par, HorStretch) & 0x7C) | 1);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
645
646
647
  }
  
  /* For resolutions smaller than FP resolution center */
5cf138457   Krzysztof Helt   tridentfb: source...
648
  static inline void screen_center(struct tridentfb_par *par)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
649
  {
306fa6f60   Krzysztof Helt   tridentfb: replac...
650
651
  	write3CE(par, VertStretch, (read3CE(par, VertStretch) & 0x7C) | 0x80);
  	write3CE(par, HorStretch, (read3CE(par, HorStretch) & 0x7C) | 0x80);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
652
653
654
  }
  
  /* Address of first shown pixel in display memory */
306fa6f60   Krzysztof Helt   tridentfb: replac...
655
  static void set_screen_start(struct tridentfb_par *par, int base)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
656
  {
306fa6f60   Krzysztof Helt   tridentfb: replac...
657
  	u8 tmp;
10172ed6d   Krzysztof Helt   tridentfb: make u...
658
659
  	write3X4(par, VGA_CRTC_START_LO, base & 0xFF);
  	write3X4(par, VGA_CRTC_START_HI, (base & 0xFF00) >> 8);
306fa6f60   Krzysztof Helt   tridentfb: replac...
660
661
662
663
  	tmp = read3X4(par, CRTCModuleTest) & 0xDF;
  	write3X4(par, CRTCModuleTest, tmp | ((base & 0x10000) >> 11));
  	tmp = read3X4(par, CRTHiOrd) & 0xF8;
  	write3X4(par, CRTHiOrd, tmp | ((base & 0xE0000) >> 17));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
664
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
665
  /* Set dotclock frequency */
306fa6f60   Krzysztof Helt   tridentfb: replac...
666
  static void set_vclk(struct tridentfb_par *par, unsigned long freq)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
667
  {
245a2c2c6   Krzysztof Helt   tridentfb: coding...
668
  	int m, n, k;
6bdf10356   Krzysztof Helt   tridentfb: fix cl...
669
670
671
  	unsigned long fi, d, di;
  	unsigned char best_m = 0, best_n = 0, best_k = 0;
  	unsigned char hi, lo;
6280fd4f9   Krzysztof Helt   tridentfb: Blade3...
672
  	unsigned char shift = !is_oldclock(par->chip_id) ? 2 : 1;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
673

3f275ea30   Krzysztof Helt   tridentfb: improv...
674
  	d = 20000;
6280fd4f9   Krzysztof Helt   tridentfb: Blade3...
675
676
677
  	for (k = shift; k >= 0; k--)
  		for (m = 1; m < 32; m++) {
  			n = ((m + 2) << shift) - 8;
34dec2431   Krzysztof Helt   tridentfb: variou...
678
  			for (n = (n < 0 ? 0 : n); n < 122; n++) {
3f275ea30   Krzysztof Helt   tridentfb: improv...
679
  				fi = ((14318l * (n + 8)) / (m + 2)) >> k;
34dec2431   Krzysztof Helt   tridentfb: variou...
680
  				di = abs(fi - freq);
6280fd4f9   Krzysztof Helt   tridentfb: Blade3...
681
  				if (di < d || (di == d && k == best_k)) {
245a2c2c6   Krzysztof Helt   tridentfb: coding...
682
  					d = di;
6bdf10356   Krzysztof Helt   tridentfb: fix cl...
683
684
685
  					best_n = n;
  					best_m = m;
  					best_k = k;
245a2c2c6   Krzysztof Helt   tridentfb: coding...
686
  				}
3f275ea30   Krzysztof Helt   tridentfb: improv...
687
688
  				if (fi > freq)
  					break;
245a2c2c6   Krzysztof Helt   tridentfb: coding...
689
  			}
34dec2431   Krzysztof Helt   tridentfb: variou...
690
  		}
6bdf10356   Krzysztof Helt   tridentfb: fix cl...
691
692
693
694
695
696
697
698
  
  	if (is_oldclock(par->chip_id)) {
  		lo = best_n | (best_m << 7);
  		hi = (best_m >> 1) | (best_k << 4);
  	} else {
  		lo = best_n;
  		hi = best_m | (best_k << 6);
  	}
122e8ad3c   Krzysztof Helt   tridentfb: move g...
699
  	if (is3Dchip(par->chip_id)) {
10172ed6d   Krzysztof Helt   tridentfb: make u...
700
701
  		vga_mm_wseq(par->io_virt, ClockHigh, hi);
  		vga_mm_wseq(par->io_virt, ClockLow, lo);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
702
  	} else {
c1724feca   Krzysztof Helt   tridentfb: use mm...
703
704
  		t_outb(par, lo, 0x43C8);
  		t_outb(par, hi, 0x43C9);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
705
  	}
245a2c2c6   Krzysztof Helt   tridentfb: coding...
706
707
  	debug("VCLK = %X %X
  ", hi, lo);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
708
709
710
  }
  
  /* Set number of lines for flat panels*/
306fa6f60   Krzysztof Helt   tridentfb: replac...
711
  static void set_number_of_lines(struct tridentfb_par *par, int lines)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
712
  {
306fa6f60   Krzysztof Helt   tridentfb: replac...
713
  	int tmp = read3CE(par, CyberEnhance) & 0x8F;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
714
715
716
717
718
719
720
721
  	if (lines > 1024)
  		tmp |= 0x50;
  	else if (lines > 768)
  		tmp |= 0x30;
  	else if (lines > 600)
  		tmp |= 0x20;
  	else if (lines > 480)
  		tmp |= 0x10;
306fa6f60   Krzysztof Helt   tridentfb: replac...
722
  	write3CE(par, CyberEnhance, tmp);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
723
724
725
726
  }
  
  /*
   * If we see that FP is active we assume we have one.
6eed8e1ec   Krzysztof Helt   tridentfb: move g...
727
   * Otherwise we have a CRT display. User can override.
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
728
   */
6eed8e1ec   Krzysztof Helt   tridentfb: move g...
729
  static int __devinit is_flatpanel(struct tridentfb_par *par)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
730
731
  {
  	if (fp)
6eed8e1ec   Krzysztof Helt   tridentfb: move g...
732
  		return 1;
122e8ad3c   Krzysztof Helt   tridentfb: move g...
733
  	if (crt || !iscyber(par->chip_id))
6eed8e1ec   Krzysztof Helt   tridentfb: move g...
734
735
  		return 0;
  	return (read3CE(par, FPConfig) & 0x10) ? 1 : 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
736
737
738
  }
  
  /* Try detecting the video memory size */
306fa6f60   Krzysztof Helt   tridentfb: replac...
739
  static unsigned int __devinit get_memsize(struct tridentfb_par *par)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
740
741
742
743
744
745
746
747
  {
  	unsigned char tmp, tmp2;
  	unsigned int k;
  
  	/* If memory size provided by user */
  	if (memsize)
  		k = memsize * Kb;
  	else
122e8ad3c   Krzysztof Helt   tridentfb: move g...
748
  		switch (par->chip_id) {
245a2c2c6   Krzysztof Helt   tridentfb: coding...
749
750
751
  		case CYBER9525DVD:
  			k = 2560 * Kb;
  			break;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
752
  		default:
306fa6f60   Krzysztof Helt   tridentfb: replac...
753
  			tmp = read3X4(par, SPR) & 0x0F;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
754
  			switch (tmp) {
245a2c2c6   Krzysztof Helt   tridentfb: coding...
755
  			case 0x01:
b614ce8b3   Krzysztof Helt   tridentfb: fix me...
756
  				k = 512 * Kb;
245a2c2c6   Krzysztof Helt   tridentfb: coding...
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
  				break;
  			case 0x02:
  				k = 6 * Mb;	/* XP */
  				break;
  			case 0x03:
  				k = 1 * Mb;
  				break;
  			case 0x04:
  				k = 8 * Mb;
  				break;
  			case 0x06:
  				k = 10 * Mb;	/* XP */
  				break;
  			case 0x07:
  				k = 2 * Mb;
  				break;
  			case 0x08:
  				k = 12 * Mb;	/* XP */
  				break;
  			case 0x0A:
  				k = 14 * Mb;	/* XP */
  				break;
  			case 0x0C:
  				k = 16 * Mb;	/* XP */
  				break;
  			case 0x0E:		/* XP */
10172ed6d   Krzysztof Helt   tridentfb: make u...
783
  				tmp2 = vga_mm_rseq(par->io_virt, 0xC1);
245a2c2c6   Krzysztof Helt   tridentfb: coding...
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
  				switch (tmp2) {
  				case 0x00:
  					k = 20 * Mb;
  					break;
  				case 0x01:
  					k = 24 * Mb;
  					break;
  				case 0x10:
  					k = 28 * Mb;
  					break;
  				case 0x11:
  					k = 32 * Mb;
  					break;
  				default:
  					k = 1 * Mb;
  					break;
  				}
  				break;
  
  			case 0x0F:
  				k = 4 * Mb;
  				break;
  			default:
  				k = 1 * Mb;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
808
  				break;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
809
  			}
245a2c2c6   Krzysztof Helt   tridentfb: coding...
810
  		}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
811
812
  
  	k -= memdiff * Kb;
245a2c2c6   Krzysztof Helt   tridentfb: coding...
813
814
  	output("framebuffer size = %d Kb
  ", k / Kb);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
815
816
817
818
  	return k;
  }
  
  /* See if we can handle the video mode described in var */
245a2c2c6   Krzysztof Helt   tridentfb: coding...
819
820
  static int tridentfb_check_var(struct fb_var_screeninfo *var,
  			       struct fb_info *info)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
821
  {
6eed8e1ec   Krzysztof Helt   tridentfb: move g...
822
  	struct tridentfb_par *par = info->par;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
823
  	int bpp = var->bits_per_pixel;
bcac2d5fe   Krzysztof Helt   tridentfb: add ac...
824
  	int line_length;
74a933fea   Krzysztof Helt   tridentfb: improv...
825
  	int ramdac = 230000; /* 230MHz for most 3D chips */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
826
827
828
829
  	debug("enter
  ");
  
  	/* check color depth */
245a2c2c6   Krzysztof Helt   tridentfb: coding...
830
  	if (bpp == 24)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
831
  		bpp = var->bits_per_pixel = 32;
49b1f4b44   Krzysztof Helt   tridentfb: accele...
832
833
  	if (bpp != 8 && bpp != 16 && bpp != 32)
  		return -EINVAL;
54f019e54   Krzysztof Helt   tridentfb: fix hi...
834
835
  	if (par->chip_id == TGUI9440 && bpp == 32)
  		return -EINVAL;
245a2c2c6   Krzysztof Helt   tridentfb: coding...
836
  	/* check whether resolution fits on panel and in memory */
6eed8e1ec   Krzysztof Helt   tridentfb: move g...
837
  	if (par->flatpanel && nativex && var->xres > nativex)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
838
  		return -EINVAL;
74a933fea   Krzysztof Helt   tridentfb: improv...
839
840
  	/* various resolution checks */
  	var->xres = (var->xres + 7) & ~0x7;
49b1f4b44   Krzysztof Helt   tridentfb: accele...
841
  	if (var->xres > var->xres_virtual)
74a933fea   Krzysztof Helt   tridentfb: improv...
842
  		var->xres_virtual = var->xres;
49b1f4b44   Krzysztof Helt   tridentfb: accele...
843
844
845
846
847
848
849
  	if (var->yres > var->yres_virtual)
  		var->yres_virtual = var->yres;
  	if (var->xres_virtual > 4095 || var->yres > 2048)
  		return -EINVAL;
  	/* prevent from position overflow for acceleration */
  	if (var->yres_virtual > 0xffff)
  		return -EINVAL;
bcac2d5fe   Krzysztof Helt   tridentfb: add ac...
850
  	line_length = var->xres_virtual * bpp / 8;
01a2d9ed8   Krzysztof Helt   tridentfb: accele...
851
852
853
  
  	if (!is3Dchip(par->chip_id) &&
  	    !(info->flags & FBINFO_HWACCEL_DISABLED)) {
bcac2d5fe   Krzysztof Helt   tridentfb: add ac...
854
855
856
857
858
859
860
861
862
863
864
  		/* acceleration requires line length to be power of 2 */
  		if (line_length <= 512)
  			var->xres_virtual = 512 * 8 / bpp;
  		else if (line_length <= 1024)
  			var->xres_virtual = 1024 * 8 / bpp;
  		else if (line_length <= 2048)
  			var->xres_virtual = 2048 * 8 / bpp;
  		else if (line_length <= 4096)
  			var->xres_virtual = 4096 * 8 / bpp;
  		else if (line_length <= 8192)
  			var->xres_virtual = 8192 * 8 / bpp;
49b1f4b44   Krzysztof Helt   tridentfb: accele...
865
866
  		else
  			return -EINVAL;
bcac2d5fe   Krzysztof Helt   tridentfb: add ac...
867
868
869
  
  		line_length = var->xres_virtual * bpp / 8;
  	}
01a2d9ed8   Krzysztof Helt   tridentfb: accele...
870

f330c4b19   Krzysztof Helt   tridentfb: y-pann...
871
872
873
  	/* datasheet specifies how to set panning only up to 4 MB */
  	if (line_length * (var->yres_virtual - var->yres) > (4 << 20))
  		var->yres_virtual = ((4 << 20) / line_length) + var->yres;
bcac2d5fe   Krzysztof Helt   tridentfb: add ac...
874
  	if (line_length * var->yres_virtual > info->fix.smem_len)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
875
876
877
  		return -EINVAL;
  
  	switch (bpp) {
245a2c2c6   Krzysztof Helt   tridentfb: coding...
878
879
  	case 8:
  		var->red.offset = 0;
a4af1798d   Krzysztof Helt   tridentfb: fix 22...
880
881
882
  		var->red.length = 8;
  		var->green = var->red;
  		var->blue = var->red;
245a2c2c6   Krzysztof Helt   tridentfb: coding...
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
  		break;
  	case 16:
  		var->red.offset = 11;
  		var->green.offset = 5;
  		var->blue.offset = 0;
  		var->red.length = 5;
  		var->green.length = 6;
  		var->blue.length = 5;
  		break;
  	case 32:
  		var->red.offset = 16;
  		var->green.offset = 8;
  		var->blue.offset = 0;
  		var->red.length = 8;
  		var->green.length = 8;
  		var->blue.length = 8;
  		break;
  	default:
  		return -EINVAL;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
902
  	}
74a933fea   Krzysztof Helt   tridentfb: improv...
903
904
905
906
907
908
  
  	if (is_xp(par->chip_id))
  		ramdac = 350000;
  
  	switch (par->chip_id) {
  	case TGUI9440:
54f019e54   Krzysztof Helt   tridentfb: fix hi...
909
  		ramdac = (bpp >= 16) ? 45000 : 90000;
74a933fea   Krzysztof Helt   tridentfb: improv...
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
  		break;
  	case CYBER9320:
  	case TGUI9660:
  		ramdac = 135000;
  		break;
  	case PROVIDIA9685:
  	case CYBER9388:
  	case CYBER9382:
  	case CYBER9385:
  		ramdac = 170000;
  		break;
  	}
  
  	/* The clock is doubled for 32 bpp */
  	if (bpp == 32)
  		ramdac /= 2;
  
  	if (PICOS2KHZ(var->pixclock) > ramdac)
  		return -EINVAL;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
929
930
931
932
933
934
  	debug("exit
  ");
  
  	return 0;
  
  }
245a2c2c6   Krzysztof Helt   tridentfb: coding...
935

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
936
937
  /* Pan the display */
  static int tridentfb_pan_display(struct fb_var_screeninfo *var,
245a2c2c6   Krzysztof Helt   tridentfb: coding...
938
  				 struct fb_info *info)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
939
  {
306fa6f60   Krzysztof Helt   tridentfb: replac...
940
  	struct tridentfb_par *par = info->par;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
941
942
943
944
  	unsigned int offset;
  
  	debug("enter
  ");
4541dbe15   Laurent Pinchart   tridentfb: use di...
945
946
  	offset = (var->xoffset + (var->yoffset * info->var.xres_virtual))
  		* info->var.bits_per_pixel / 32;
306fa6f60   Krzysztof Helt   tridentfb: replac...
947
  	set_screen_start(par, offset);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
948
949
950
951
  	debug("exit
  ");
  	return 0;
  }
5cf138457   Krzysztof Helt   tridentfb: source...
952
  static inline void shadowmode_on(struct tridentfb_par *par)
306fa6f60   Krzysztof Helt   tridentfb: replac...
953
954
955
  {
  	write3CE(par, CyberControl, read3CE(par, CyberControl) | 0x81);
  }
5cf138457   Krzysztof Helt   tridentfb: source...
956
  static inline void shadowmode_off(struct tridentfb_par *par)
306fa6f60   Krzysztof Helt   tridentfb: replac...
957
958
959
  {
  	write3CE(par, CyberControl, read3CE(par, CyberControl) & 0x7E);
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
960
961
962
963
  
  /* Set the hardware to the requested video mode */
  static int tridentfb_set_par(struct fb_info *info)
  {
5cf138457   Krzysztof Helt   tridentfb: source...
964
  	struct tridentfb_par *par = info->par;
245a2c2c6   Krzysztof Helt   tridentfb: coding...
965
966
967
  	u32 htotal, hdispend, hsyncstart, hsyncend, hblankstart, hblankend;
  	u32 vtotal, vdispend, vsyncstart, vsyncend, vblankstart, vblankend;
  	struct fb_var_screeninfo *var = &info->var;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
968
969
  	int bpp = var->bits_per_pixel;
  	unsigned char tmp;
3f275ea30   Krzysztof Helt   tridentfb: improv...
970
  	unsigned long vclk;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
971
972
  	debug("enter
  ");
245a2c2c6   Krzysztof Helt   tridentfb: coding...
973
  	hdispend = var->xres / 8 - 1;
34dec2431   Krzysztof Helt   tridentfb: variou...
974
975
  	hsyncstart = (var->xres + var->right_margin) / 8;
  	hsyncend = (var->xres + var->right_margin + var->hsync_len) / 8;
7f762d23e   Krzysztof Helt   tridentfb: fix ti...
976
977
  	htotal = (var->xres + var->left_margin + var->right_margin +
  		  var->hsync_len) / 8 - 5;
0e73a47f0   Krzysztof Helt   tridentfb: improv...
978
  	hblankstart = hdispend + 1;
7f762d23e   Krzysztof Helt   tridentfb: fix ti...
979
  	hblankend = htotal + 3;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
980

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
981
982
  	vdispend = var->yres - 1;
  	vsyncstart = var->yres + var->lower_margin;
7f762d23e   Krzysztof Helt   tridentfb: fix ti...
983
984
  	vsyncend = vsyncstart + var->vsync_len;
  	vtotal = var->upper_margin + vsyncend - 2;
0e73a47f0   Krzysztof Helt   tridentfb: improv...
985
  	vblankstart = vdispend + 1;
7f762d23e   Krzysztof Helt   tridentfb: fix ti...
986
  	vblankend = vtotal;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
987

34dec2431   Krzysztof Helt   tridentfb: variou...
988
989
990
991
992
993
994
995
  	if (info->var.vmode & FB_VMODE_INTERLACED) {
  		vtotal /= 2;
  		vdispend /= 2;
  		vsyncstart /= 2;
  		vsyncend /= 2;
  		vblankstart /= 2;
  		vblankend /= 2;
  	}
13b0de49f   Krzysztof Helt   tridentfb: fix co...
996
  	enable_mmio(par);
306fa6f60   Krzysztof Helt   tridentfb: replac...
997
998
  	crtc_unlock(par);
  	write3CE(par, CyberControl, 8);
34dec2431   Krzysztof Helt   tridentfb: variou...
999
1000
1001
1002
1003
  	tmp = 0xEB;
  	if (var->sync & FB_SYNC_HOR_HIGH_ACT)
  		tmp &= ~0x40;
  	if (var->sync & FB_SYNC_VERT_HIGH_ACT)
  		tmp &= ~0x80;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1004

6eed8e1ec   Krzysztof Helt   tridentfb: move g...
1005
  	if (par->flatpanel && var->xres < nativex) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1006
1007
1008
1009
1010
  		/*
  		 * on flat panels with native size larger
  		 * than requested resolution decide whether
  		 * we stretch or center
  		 */
34dec2431   Krzysztof Helt   tridentfb: variou...
1011
  		t_outb(par, tmp | 0xC0, VGA_MIS_W);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1012

306fa6f60   Krzysztof Helt   tridentfb: replac...
1013
  		shadowmode_on(par);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1014

245a2c2c6   Krzysztof Helt   tridentfb: coding...
1015
  		if (center)
306fa6f60   Krzysztof Helt   tridentfb: replac...
1016
  			screen_center(par);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1017
  		else if (stretch)
306fa6f60   Krzysztof Helt   tridentfb: replac...
1018
  			screen_stretch(par);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1019
1020
  
  	} else {
34dec2431   Krzysztof Helt   tridentfb: variou...
1021
  		t_outb(par, tmp, VGA_MIS_W);
306fa6f60   Krzysztof Helt   tridentfb: replac...
1022
  		write3CE(par, CyberControl, 8);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1023
1024
1025
  	}
  
  	/* vertical timing values */
10172ed6d   Krzysztof Helt   tridentfb: make u...
1026
1027
1028
1029
1030
  	write3X4(par, VGA_CRTC_V_TOTAL, vtotal & 0xFF);
  	write3X4(par, VGA_CRTC_V_DISP_END, vdispend & 0xFF);
  	write3X4(par, VGA_CRTC_V_SYNC_START, vsyncstart & 0xFF);
  	write3X4(par, VGA_CRTC_V_SYNC_END, (vsyncend & 0x0F));
  	write3X4(par, VGA_CRTC_V_BLANK_START, vblankstart & 0xFF);
7f762d23e   Krzysztof Helt   tridentfb: fix ti...
1031
  	write3X4(par, VGA_CRTC_V_BLANK_END, vblankend & 0xFF);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1032
1033
  
  	/* horizontal timing values */
10172ed6d   Krzysztof Helt   tridentfb: make u...
1034
1035
1036
1037
  	write3X4(par, VGA_CRTC_H_TOTAL, htotal & 0xFF);
  	write3X4(par, VGA_CRTC_H_DISP, hdispend & 0xFF);
  	write3X4(par, VGA_CRTC_H_SYNC_START, hsyncstart & 0xFF);
  	write3X4(par, VGA_CRTC_H_SYNC_END,
306fa6f60   Krzysztof Helt   tridentfb: replac...
1038
  		 (hsyncend & 0x1F) | ((hblankend & 0x20) << 2));
10172ed6d   Krzysztof Helt   tridentfb: make u...
1039
  	write3X4(par, VGA_CRTC_H_BLANK_START, hblankstart & 0xFF);
7f762d23e   Krzysztof Helt   tridentfb: fix ti...
1040
  	write3X4(par, VGA_CRTC_H_BLANK_END, hblankend & 0x1F);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1041
1042
1043
1044
1045
1046
1047
1048
1049
1050
1051
  
  	/* higher bits of vertical timing values */
  	tmp = 0x10;
  	if (vtotal & 0x100) tmp |= 0x01;
  	if (vdispend & 0x100) tmp |= 0x02;
  	if (vsyncstart & 0x100) tmp |= 0x04;
  	if (vblankstart & 0x100) tmp |= 0x08;
  
  	if (vtotal & 0x200) tmp |= 0x20;
  	if (vdispend & 0x200) tmp |= 0x40;
  	if (vsyncstart & 0x200) tmp |= 0x80;
10172ed6d   Krzysztof Helt   tridentfb: make u...
1052
  	write3X4(par, VGA_CRTC_OVERFLOW, tmp);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1053

7f762d23e   Krzysztof Helt   tridentfb: fix ti...
1054
1055
  	tmp = read3X4(par, CRTHiOrd) & 0x07;
  	tmp |= 0x08;	/* line compare bit 10 */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1056
1057
1058
1059
  	if (vtotal & 0x400) tmp |= 0x80;
  	if (vblankstart & 0x400) tmp |= 0x40;
  	if (vsyncstart & 0x400) tmp |= 0x20;
  	if (vdispend & 0x400) tmp |= 0x10;
306fa6f60   Krzysztof Helt   tridentfb: replac...
1060
  	write3X4(par, CRTHiOrd, tmp);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1061

7f762d23e   Krzysztof Helt   tridentfb: fix ti...
1062
1063
1064
1065
  	tmp = (htotal >> 8) & 0x01;
  	tmp |= (hdispend >> 7) & 0x02;
  	tmp |= (hsyncstart >> 5) & 0x08;
  	tmp |= (hblankstart >> 4) & 0x10;
306fa6f60   Krzysztof Helt   tridentfb: replac...
1066
  	write3X4(par, HorizOverflow, tmp);
245a2c2c6   Krzysztof Helt   tridentfb: coding...
1067

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1068
1069
  	tmp = 0x40;
  	if (vblankstart & 0x200) tmp |= 0x20;
245a2c2c6   Krzysztof Helt   tridentfb: coding...
1070
  //FIXME	if (info->var.vmode & FB_VMODE_DOUBLE) tmp |= 0x80;  /* double scan for 200 line modes */
10172ed6d   Krzysztof Helt   tridentfb: make u...
1071
  	write3X4(par, VGA_CRTC_MAX_SCAN, tmp);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1072

10172ed6d   Krzysztof Helt   tridentfb: make u...
1073
1074
1075
  	write3X4(par, VGA_CRTC_LINE_COMPARE, 0xFF);
  	write3X4(par, VGA_CRTC_PRESET_ROW, 0);
  	write3X4(par, VGA_CRTC_MODE, 0xC3);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1076

306fa6f60   Krzysztof Helt   tridentfb: replac...
1077
  	write3X4(par, LinearAddReg, 0x20);	/* enable linear addressing */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1078

245a2c2c6   Krzysztof Helt   tridentfb: coding...
1079
  	tmp = (info->var.vmode & FB_VMODE_INTERLACED) ? 0x84 : 0x80;
306fa6f60   Krzysztof Helt   tridentfb: replac...
1080
1081
  	/* enable access extended memory */
  	write3X4(par, CRTCModuleTest, tmp);
34dec2431   Krzysztof Helt   tridentfb: variou...
1082
1083
1084
1085
  	tmp = read3CE(par, MiscIntContReg) & ~0x4;
  	if (info->var.vmode & FB_VMODE_INTERLACED)
  		tmp |= 0x4;
  	write3CE(par, MiscIntContReg, tmp);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1086

306fa6f60   Krzysztof Helt   tridentfb: replac...
1087
1088
  	/* enable GE for text acceleration */
  	write3X4(par, GraphEngReg, 0x80);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1089

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1090
  	switch (bpp) {
245a2c2c6   Krzysztof Helt   tridentfb: coding...
1091
1092
1093
1094
1095
1096
1097
1098
1099
1100
1101
1102
  	case 8:
  		tmp = 0x00;
  		break;
  	case 16:
  		tmp = 0x05;
  		break;
  	case 24:
  		tmp = 0x29;
  		break;
  	case 32:
  		tmp = 0x09;
  		break;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1103
  	}
306fa6f60   Krzysztof Helt   tridentfb: replac...
1104
  	write3X4(par, PixelBusReg, tmp);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1105

0e73a47f0   Krzysztof Helt   tridentfb: improv...
1106
1107
1108
  	tmp = read3X4(par, DRAMControl);
  	if (!is_oldprotect(par->chip_id))
  		tmp |= 0x10;
122e8ad3c   Krzysztof Helt   tridentfb: move g...
1109
  	if (iscyber(par->chip_id))
245a2c2c6   Krzysztof Helt   tridentfb: coding...
1110
  		tmp |= 0x20;
306fa6f60   Krzysztof Helt   tridentfb: replac...
1111
  	write3X4(par, DRAMControl, tmp);	/* both IO, linear enable */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1112

306fa6f60   Krzysztof Helt   tridentfb: replac...
1113
  	write3X4(par, InterfaceSel, read3X4(par, InterfaceSel) | 0x40);
0e73a47f0   Krzysztof Helt   tridentfb: improv...
1114
1115
  	if (!is_xp(par->chip_id))
  		write3X4(par, Performance, read3X4(par, Performance) | 0x10);
306fa6f60   Krzysztof Helt   tridentfb: replac...
1116
  	/* MMIO & PCI read and write burst enable */
13b0de49f   Krzysztof Helt   tridentfb: fix co...
1117
  	if (par->chip_id != TGUI9440 && par->chip_id != IMAGE975)
a0d922562   Krzysztof Helt   tridentfb: add TG...
1118
  		write3X4(par, PCIReg, read3X4(par, PCIReg) | 0x06);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1119

10172ed6d   Krzysztof Helt   tridentfb: make u...
1120
1121
  	vga_mm_wseq(par->io_virt, 0, 3);
  	vga_mm_wseq(par->io_virt, 1, 1); /* set char clock 8 dots wide */
306fa6f60   Krzysztof Helt   tridentfb: replac...
1122
  	/* enable 4 maps because needed in chain4 mode */
10172ed6d   Krzysztof Helt   tridentfb: make u...
1123
1124
1125
  	vga_mm_wseq(par->io_virt, 2, 0x0F);
  	vga_mm_wseq(par->io_virt, 3, 0);
  	vga_mm_wseq(par->io_virt, 4, 0x0E); /* memory mode enable bitmaps ?? */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1126

54f019e54   Krzysztof Helt   tridentfb: fix hi...
1127
1128
  	/* convert from picoseconds to kHz */
  	vclk = PICOS2KHZ(info->var.pixclock);
306fa6f60   Krzysztof Helt   tridentfb: replac...
1129
  	/* divide clock by 2 if 32bpp chain4 mode display and CPU path */
65e93e038   Krzysztof Helt   tridentfb: preser...
1130
  	tmp = read3CE(par, MiscExtFunc) & 0xF0;
54f019e54   Krzysztof Helt   tridentfb: fix hi...
1131
  	if (bpp == 32 || (par->chip_id == TGUI9440 && bpp == 16)) {
65e93e038   Krzysztof Helt   tridentfb: preser...
1132
  		tmp |= 8;
54f019e54   Krzysztof Helt   tridentfb: fix hi...
1133
1134
1135
  		vclk *= 2;
  	}
  	set_vclk(par, vclk);
65e93e038   Krzysztof Helt   tridentfb: preser...
1136
  	write3CE(par, MiscExtFunc, tmp | 0x12);
306fa6f60   Krzysztof Helt   tridentfb: replac...
1137
1138
1139
  	write3CE(par, 0x5, 0x40);	/* no CGA compat, allow 256 col */
  	write3CE(par, 0x6, 0x05);	/* graphics mode */
  	write3CE(par, 0x7, 0x0F);	/* planes? */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1140

306fa6f60   Krzysztof Helt   tridentfb: replac...
1141
1142
1143
1144
  	/* graphics mode and support 256 color modes */
  	writeAttr(par, 0x10, 0x41);
  	writeAttr(par, 0x12, 0x0F);	/* planes */
  	writeAttr(par, 0x13, 0);	/* horizontal pel panning */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1145

245a2c2c6   Krzysztof Helt   tridentfb: coding...
1146
1147
  	/* colors */
  	for (tmp = 0; tmp < 0x10; tmp++)
306fa6f60   Krzysztof Helt   tridentfb: replac...
1148
  		writeAttr(par, tmp, tmp);
10172ed6d   Krzysztof Helt   tridentfb: make u...
1149
1150
  	fb_readb(par->io_virt + VGA_IS1_RC);	/* flip-flop to index */
  	t_outb(par, 0x20, VGA_ATT_W);		/* enable attr */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1151
1152
  
  	switch (bpp) {
245a2c2c6   Krzysztof Helt   tridentfb: coding...
1153
1154
1155
  	case 8:
  		tmp = 0;
  		break;
245a2c2c6   Krzysztof Helt   tridentfb: coding...
1156
1157
1158
1159
1160
1161
1162
  	case 16:
  		tmp = 0x30;
  		break;
  	case 24:
  	case 32:
  		tmp = 0xD0;
  		break;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1163
  	}
10172ed6d   Krzysztof Helt   tridentfb: make u...
1164
1165
1166
1167
1168
1169
1170
  	t_inb(par, VGA_PEL_IW);
  	t_inb(par, VGA_PEL_MSK);
  	t_inb(par, VGA_PEL_MSK);
  	t_inb(par, VGA_PEL_MSK);
  	t_inb(par, VGA_PEL_MSK);
  	t_outb(par, tmp, VGA_PEL_MSK);
  	t_inb(par, VGA_PEL_IW);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1171

6eed8e1ec   Krzysztof Helt   tridentfb: move g...
1172
  	if (par->flatpanel)
306fa6f60   Krzysztof Helt   tridentfb: replac...
1173
  		set_number_of_lines(par, info->var.yres);
bcac2d5fe   Krzysztof Helt   tridentfb: add ac...
1174
1175
  	info->fix.line_length = info->var.xres_virtual * bpp / 8;
  	set_lwidth(par, info->fix.line_length / 8);
01a2d9ed8   Krzysztof Helt   tridentfb: accele...
1176
1177
1178
  
  	if (!(info->flags & FBINFO_HWACCEL_DISABLED))
  		par->init_accel(par, info->var.xres_virtual, bpp);
2c86a0c26   Krzysztof Helt   tridentfb: accele...
1179

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1180
  	info->fix.visual = (bpp == 8) ? FB_VISUAL_PSEUDOCOLOR : FB_VISUAL_TRUECOLOR;
245a2c2c6   Krzysztof Helt   tridentfb: coding...
1181
  	info->cmap.len = (bpp == 8) ? 256 : 16;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1182
1183
1184
1185
1186
1187
1188
  	debug("exit
  ");
  	return 0;
  }
  
  /* Set one color register */
  static int tridentfb_setcolreg(unsigned regno, unsigned red, unsigned green,
245a2c2c6   Krzysztof Helt   tridentfb: coding...
1189
1190
  			       unsigned blue, unsigned transp,
  			       struct fb_info *info)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1191
1192
  {
  	int bpp = info->var.bits_per_pixel;
306fa6f60   Krzysztof Helt   tridentfb: replac...
1193
  	struct tridentfb_par *par = info->par;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1194
1195
1196
  
  	if (regno >= info->cmap.len)
  		return 1;
973d9ab23   Antonino A. Daplas   tridentfb: fix ps...
1197
  	if (bpp == 8) {
10172ed6d   Krzysztof Helt   tridentfb: make u...
1198
1199
  		t_outb(par, 0xFF, VGA_PEL_MSK);
  		t_outb(par, regno, VGA_PEL_IW);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1200

10172ed6d   Krzysztof Helt   tridentfb: make u...
1201
1202
1203
  		t_outb(par, red >> 10, VGA_PEL_D);
  		t_outb(par, green >> 10, VGA_PEL_D);
  		t_outb(par, blue >> 10, VGA_PEL_D);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1204

973d9ab23   Antonino A. Daplas   tridentfb: fix ps...
1205
1206
1207
1208
1209
1210
1211
1212
1213
  	} else if (regno < 16) {
  		if (bpp == 16) {	/* RGB 565 */
  			u32 col;
  
  			col = (red & 0xF800) | ((green & 0xFC00) >> 5) |
  				((blue & 0xF800) >> 11);
  			col |= col << 16;
  			((u32 *)(info->pseudo_palette))[regno] = col;
  		} else if (bpp == 32)		/* ARGB 8888 */
5cf138457   Krzysztof Helt   tridentfb: source...
1214
  			((u32 *)info->pseudo_palette)[regno] =
245a2c2c6   Krzysztof Helt   tridentfb: coding...
1215
1216
  				((transp & 0xFF00) << 16)	|
  				((red & 0xFF00) << 8)		|
973d9ab23   Antonino A. Daplas   tridentfb: fix ps...
1217
  				((green & 0xFF00))		|
245a2c2c6   Krzysztof Helt   tridentfb: coding...
1218
  				((blue & 0xFF00) >> 8);
973d9ab23   Antonino A. Daplas   tridentfb: fix ps...
1219
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1220

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1221
1222
  	return 0;
  }
5cf138457   Krzysztof Helt   tridentfb: source...
1223
  /* Try blanking the screen. For flat panels it does nothing */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1224
1225
  static int tridentfb_blank(int blank_mode, struct fb_info *info)
  {
245a2c2c6   Krzysztof Helt   tridentfb: coding...
1226
  	unsigned char PMCont, DPMSCont;
306fa6f60   Krzysztof Helt   tridentfb: replac...
1227
  	struct tridentfb_par *par = info->par;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1228
1229
1230
  
  	debug("enter
  ");
6eed8e1ec   Krzysztof Helt   tridentfb: move g...
1231
  	if (par->flatpanel)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1232
  		return 0;
306fa6f60   Krzysztof Helt   tridentfb: replac...
1233
1234
1235
  	t_outb(par, 0x04, 0x83C8); /* Read DPMS Control */
  	PMCont = t_inb(par, 0x83C6) & 0xFC;
  	DPMSCont = read3CE(par, PowerStatus) & 0xFC;
245a2c2c6   Krzysztof Helt   tridentfb: coding...
1236
  	switch (blank_mode) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1237
1238
1239
1240
1241
1242
1243
1244
1245
1246
1247
1248
1249
1250
1251
1252
1253
1254
1255
1256
1257
1258
  	case FB_BLANK_UNBLANK:
  		/* Screen: On, HSync: On, VSync: On */
  	case FB_BLANK_NORMAL:
  		/* Screen: Off, HSync: On, VSync: On */
  		PMCont |= 0x03;
  		DPMSCont |= 0x00;
  		break;
  	case FB_BLANK_HSYNC_SUSPEND:
  		/* Screen: Off, HSync: Off, VSync: On */
  		PMCont |= 0x02;
  		DPMSCont |= 0x01;
  		break;
  	case FB_BLANK_VSYNC_SUSPEND:
  		/* Screen: Off, HSync: On, VSync: Off */
  		PMCont |= 0x02;
  		DPMSCont |= 0x02;
  		break;
  	case FB_BLANK_POWERDOWN:
  		/* Screen: Off, HSync: Off, VSync: Off */
  		PMCont |= 0x00;
  		DPMSCont |= 0x03;
  		break;
245a2c2c6   Krzysztof Helt   tridentfb: coding...
1259
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1260

306fa6f60   Krzysztof Helt   tridentfb: replac...
1261
1262
1263
  	write3CE(par, PowerStatus, DPMSCont);
  	t_outb(par, 4, 0x83C8);
  	t_outb(par, PMCont, 0x83C6);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1264
1265
1266
1267
1268
1269
1270
  
  	debug("exit
  ");
  
  	/* let fbcon do a softblank for us */
  	return (blank_mode == FB_BLANK_NORMAL) ? 1 : 0;
  }
245a2c2c6   Krzysztof Helt   tridentfb: coding...
1271
1272
1273
1274
1275
1276
1277
1278
1279
  static struct fb_ops tridentfb_ops = {
  	.owner = THIS_MODULE,
  	.fb_setcolreg = tridentfb_setcolreg,
  	.fb_pan_display = tridentfb_pan_display,
  	.fb_blank = tridentfb_blank,
  	.fb_check_var = tridentfb_check_var,
  	.fb_set_par = tridentfb_set_par,
  	.fb_fillrect = tridentfb_fillrect,
  	.fb_copyarea = tridentfb_copyarea,
0292be4a3   Krzysztof Helt   tridentfb: add im...
1280
  	.fb_imageblit = tridentfb_imageblit,
49b1f4b44   Krzysztof Helt   tridentfb: accele...
1281
  	.fb_sync = tridentfb_sync,
245a2c2c6   Krzysztof Helt   tridentfb: coding...
1282
  };
e09ed099d   Krzysztof Helt   tridentfb: conver...
1283
1284
  static int __devinit trident_pci_probe(struct pci_dev *dev,
  				       const struct pci_device_id *id)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1285
1286
1287
  {
  	int err;
  	unsigned char revision;
e09ed099d   Krzysztof Helt   tridentfb: conver...
1288
1289
  	struct fb_info *info;
  	struct tridentfb_par *default_par;
122e8ad3c   Krzysztof Helt   tridentfb: move g...
1290
1291
  	int chip3D;
  	int chip_id;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1292
1293
1294
1295
  
  	err = pci_enable_device(dev);
  	if (err)
  		return err;
e09ed099d   Krzysztof Helt   tridentfb: conver...
1296
1297
1298
1299
  	info = framebuffer_alloc(sizeof(struct tridentfb_par), &dev->dev);
  	if (!info)
  		return -ENOMEM;
  	default_par = info->par;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1300
1301
1302
  	chip_id = id->device;
  
  	/* If PCI id is 0x9660 then further detect chip type */
245a2c2c6   Krzysztof Helt   tridentfb: coding...
1303

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1304
  	if (chip_id == TGUI9660) {
10172ed6d   Krzysztof Helt   tridentfb: make u...
1305
  		revision = vga_io_rseq(RevisionID);
245a2c2c6   Krzysztof Helt   tridentfb: coding...
1306

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1307
  		switch (revision) {
0e73a47f0   Krzysztof Helt   tridentfb: improv...
1308
1309
1310
  		case 0x21:
  			chip_id = PROVIDIA9685;
  			break;
245a2c2c6   Krzysztof Helt   tridentfb: coding...
1311
1312
1313
1314
1315
1316
1317
1318
1319
1320
1321
1322
1323
1324
1325
1326
1327
1328
1329
1330
1331
1332
1333
1334
  		case 0x22:
  		case 0x23:
  			chip_id = CYBER9397;
  			break;
  		case 0x2A:
  			chip_id = CYBER9397DVD;
  			break;
  		case 0x30:
  		case 0x33:
  		case 0x34:
  		case 0x35:
  		case 0x38:
  		case 0x3A:
  		case 0xB3:
  			chip_id = CYBER9385;
  			break;
  		case 0x40 ... 0x43:
  			chip_id = CYBER9382;
  			break;
  		case 0x4A:
  			chip_id = CYBER9388;
  			break;
  		default:
  			break;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1335
1336
1337
1338
  		}
  	}
  
  	chip3D = is3Dchip(chip_id);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1339
1340
  
  	if (is_xp(chip_id)) {
d9cad04bc   Krzysztof Helt   tridentfb: move g...
1341
1342
1343
1344
  		default_par->init_accel = xp_init_accel;
  		default_par->wait_engine = xp_wait_engine;
  		default_par->fill_rect = xp_fill_rect;
  		default_par->copy_rect = xp_copy_rect;
01a2d9ed8   Krzysztof Helt   tridentfb: accele...
1345
  		tridentfb_fix.accel = FB_ACCEL_TRIDENT_BLADEXP;
245a2c2c6   Krzysztof Helt   tridentfb: coding...
1346
  	} else if (is_blade(chip_id)) {
d9cad04bc   Krzysztof Helt   tridentfb: move g...
1347
1348
1349
1350
  		default_par->init_accel = blade_init_accel;
  		default_par->wait_engine = blade_wait_engine;
  		default_par->fill_rect = blade_fill_rect;
  		default_par->copy_rect = blade_copy_rect;
0292be4a3   Krzysztof Helt   tridentfb: add im...
1351
  		default_par->image_blit = blade_image_blit;
01a2d9ed8   Krzysztof Helt   tridentfb: accele...
1352
  		tridentfb_fix.accel = FB_ACCEL_TRIDENT_BLADE3D;
bcac2d5fe   Krzysztof Helt   tridentfb: add ac...
1353
  	} else if (chip3D) {			/* 3DImage family left */
d9cad04bc   Krzysztof Helt   tridentfb: move g...
1354
1355
1356
1357
  		default_par->init_accel = image_init_accel;
  		default_par->wait_engine = image_wait_engine;
  		default_par->fill_rect = image_fill_rect;
  		default_par->copy_rect = image_copy_rect;
01a2d9ed8   Krzysztof Helt   tridentfb: accele...
1358
  		tridentfb_fix.accel = FB_ACCEL_TRIDENT_3DIMAGE;
bcac2d5fe   Krzysztof Helt   tridentfb: add ac...
1359
1360
1361
1362
1363
  	} else { 				/* TGUI 9440/96XX family */
  		default_par->init_accel = tgui_init_accel;
  		default_par->wait_engine = xp_wait_engine;
  		default_par->fill_rect = tgui_fill_rect;
  		default_par->copy_rect = tgui_copy_rect;
01a2d9ed8   Krzysztof Helt   tridentfb: accele...
1364
  		tridentfb_fix.accel = FB_ACCEL_TRIDENT_TGUI;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1365
  	}
122e8ad3c   Krzysztof Helt   tridentfb: move g...
1366
  	default_par->chip_id = chip_id;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1367
  	/* setup MMIO region */
245a2c2c6   Krzysztof Helt   tridentfb: coding...
1368
  	tridentfb_fix.mmio_start = pci_resource_start(dev, 1);
5cf138457   Krzysztof Helt   tridentfb: source...
1369
  	tridentfb_fix.mmio_len = pci_resource_len(dev, 1);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1370

5cf138457   Krzysztof Helt   tridentfb: source...
1371
1372
  	if (!request_mem_region(tridentfb_fix.mmio_start,
  				tridentfb_fix.mmio_len, "tridentfb")) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1373
1374
  		debug("request_region failed!
  ");
3876ae8be   Krzysztof Helt   tridentfb: improv...
1375
  		framebuffer_release(info);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1376
1377
  		return -1;
  	}
e09ed099d   Krzysztof Helt   tridentfb: conver...
1378
1379
  	default_par->io_virt = ioremap_nocache(tridentfb_fix.mmio_start,
  					       tridentfb_fix.mmio_len);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1380

e09ed099d   Krzysztof Helt   tridentfb: conver...
1381
  	if (!default_par->io_virt) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1382
1383
  		debug("ioremap failed
  ");
e8ed857c6   Krzysztof Helt   tridentfb: resour...
1384
1385
  		err = -1;
  		goto out_unmap1;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1386
  	}
13b0de49f   Krzysztof Helt   tridentfb: fix co...
1387
  	enable_mmio(default_par);
bcac2d5fe   Krzysztof Helt   tridentfb: add ac...
1388

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1389
  	/* setup framebuffer memory */
245a2c2c6   Krzysztof Helt   tridentfb: coding...
1390
  	tridentfb_fix.smem_start = pci_resource_start(dev, 0);
e09ed099d   Krzysztof Helt   tridentfb: conver...
1391
  	tridentfb_fix.smem_len = get_memsize(default_par);
245a2c2c6   Krzysztof Helt   tridentfb: coding...
1392

5cf138457   Krzysztof Helt   tridentfb: source...
1393
1394
  	if (!request_mem_region(tridentfb_fix.smem_start,
  				tridentfb_fix.smem_len, "tridentfb")) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1395
1396
  		debug("request_mem_region failed!
  ");
e09ed099d   Krzysztof Helt   tridentfb: conver...
1397
  		disable_mmio(info->par);
a02f6402d   Amol Lad   [PATCH] ioremap b...
1398
  		err = -1;
e8ed857c6   Krzysztof Helt   tridentfb: resour...
1399
  		goto out_unmap1;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1400
  	}
e09ed099d   Krzysztof Helt   tridentfb: conver...
1401
1402
  	info->screen_base = ioremap_nocache(tridentfb_fix.smem_start,
  					    tridentfb_fix.smem_len);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1403

e09ed099d   Krzysztof Helt   tridentfb: conver...
1404
  	if (!info->screen_base) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1405
1406
  		debug("ioremap failed
  ");
a02f6402d   Amol Lad   [PATCH] ioremap b...
1407
  		err = -1;
e8ed857c6   Krzysztof Helt   tridentfb: resour...
1408
  		goto out_unmap2;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1409
  	}
6eed8e1ec   Krzysztof Helt   tridentfb: move g...
1410
  	default_par->flatpanel = is_flatpanel(default_par);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1411

6eed8e1ec   Krzysztof Helt   tridentfb: move g...
1412
  	if (default_par->flatpanel)
e09ed099d   Krzysztof Helt   tridentfb: conver...
1413
  		nativex = get_nativex(default_par);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1414

e09ed099d   Krzysztof Helt   tridentfb: conver...
1415
1416
  	info->fix = tridentfb_fix;
  	info->fbops = &tridentfb_ops;
aa0aa8ab2   Krzysztof Helt   tridentfb: fix un...
1417
  	info->pseudo_palette = default_par->pseudo_pal;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1418

e09ed099d   Krzysztof Helt   tridentfb: conver...
1419
  	info->flags = FBINFO_DEFAULT | FBINFO_HWACCEL_YPAN;
01a2d9ed8   Krzysztof Helt   tridentfb: accele...
1420
1421
1422
1423
1424
1425
  	if (!noaccel && default_par->init_accel) {
  		info->flags &= ~FBINFO_HWACCEL_DISABLED;
  		info->flags |= FBINFO_HWACCEL_COPYAREA;
  		info->flags |= FBINFO_HWACCEL_FILLRECT;
  	} else
  		info->flags |= FBINFO_HWACCEL_DISABLED;
ddb53d48d   Krzysztof Helt   fbdev: remove cyb...
1426
1427
  	if (is_blade(chip_id) && chip_id != BLADE3D)
  		info->flags |= FBINFO_READS_FAST;
0292be4a3   Krzysztof Helt   tridentfb: add im...
1428
1429
1430
1431
1432
1433
1434
1435
1436
1437
1438
1439
1440
1441
1442
1443
1444
1445
1446
1447
1448
1449
1450
  	info->pixmap.addr = kmalloc(4096, GFP_KERNEL);
  	if (!info->pixmap.addr) {
  		err = -ENOMEM;
  		goto out_unmap2;
  	}
  
  	info->pixmap.size = 4096;
  	info->pixmap.buf_align = 4;
  	info->pixmap.scan_align = 1;
  	info->pixmap.access_align = 32;
  	info->pixmap.flags = FB_PIXMAP_SYSTEM;
  
  	if (default_par->image_blit) {
  		info->flags |= FBINFO_HWACCEL_IMAGEBLIT;
  		info->pixmap.scan_align = 4;
  	}
  
  	if (noaccel) {
  		printk(KERN_DEBUG "disabling acceleration
  ");
  		info->flags |= FBINFO_HWACCEL_DISABLED;
  		info->pixmap.scan_align = 1;
  	}
ea8ee55c1   Krzysztof Helt   tridentfb: move g...
1451
  	if (!fb_find_mode(&info->var, info,
07f41e45f   Krzysztof Helt   tridentfb: change...
1452
  			  mode_option, NULL, 0, NULL, bpp)) {
a02f6402d   Amol Lad   [PATCH] ioremap b...
1453
  		err = -EINVAL;
e8ed857c6   Krzysztof Helt   tridentfb: resour...
1454
  		goto out_unmap2;
a02f6402d   Amol Lad   [PATCH] ioremap b...
1455
  	}
e09ed099d   Krzysztof Helt   tridentfb: conver...
1456
  	err = fb_alloc_cmap(&info->cmap, 256, 0);
e8ed857c6   Krzysztof Helt   tridentfb: resour...
1457
1458
  	if (err < 0)
  		goto out_unmap2;
ea8ee55c1   Krzysztof Helt   tridentfb: move g...
1459
  	info->var.activate |= FB_ACTIVATE_NOW;
e09ed099d   Krzysztof Helt   tridentfb: conver...
1460
1461
  	info->device = &dev->dev;
  	if (register_framebuffer(info) < 0) {
5cf138457   Krzysztof Helt   tridentfb: source...
1462
1463
  		printk(KERN_ERR "tridentfb: could not register framebuffer
  ");
e09ed099d   Krzysztof Helt   tridentfb: conver...
1464
  		fb_dealloc_cmap(&info->cmap);
a02f6402d   Amol Lad   [PATCH] ioremap b...
1465
  		err = -EINVAL;
e8ed857c6   Krzysztof Helt   tridentfb: resour...
1466
  		goto out_unmap2;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1467
1468
1469
  	}
  	output("fb%d: %s frame buffer device %dx%d-%dbpp
  ",
ea8ee55c1   Krzysztof Helt   tridentfb: move g...
1470
1471
  	   info->node, info->fix.id, info->var.xres,
  	   info->var.yres, info->var.bits_per_pixel);
e09ed099d   Krzysztof Helt   tridentfb: conver...
1472
1473
  
  	pci_set_drvdata(dev, info);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1474
  	return 0;
a02f6402d   Amol Lad   [PATCH] ioremap b...
1475

e8ed857c6   Krzysztof Helt   tridentfb: resour...
1476
  out_unmap2:
0292be4a3   Krzysztof Helt   tridentfb: add im...
1477
  	kfree(info->pixmap.addr);
e09ed099d   Krzysztof Helt   tridentfb: conver...
1478
1479
  	if (info->screen_base)
  		iounmap(info->screen_base);
e8ed857c6   Krzysztof Helt   tridentfb: resour...
1480
  	release_mem_region(tridentfb_fix.smem_start, tridentfb_fix.smem_len);
e09ed099d   Krzysztof Helt   tridentfb: conver...
1481
  	disable_mmio(info->par);
e8ed857c6   Krzysztof Helt   tridentfb: resour...
1482
  out_unmap1:
e09ed099d   Krzysztof Helt   tridentfb: conver...
1483
1484
  	if (default_par->io_virt)
  		iounmap(default_par->io_virt);
e8ed857c6   Krzysztof Helt   tridentfb: resour...
1485
  	release_mem_region(tridentfb_fix.mmio_start, tridentfb_fix.mmio_len);
e09ed099d   Krzysztof Helt   tridentfb: conver...
1486
  	framebuffer_release(info);
a02f6402d   Amol Lad   [PATCH] ioremap b...
1487
  	return err;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1488
  }
245a2c2c6   Krzysztof Helt   tridentfb: coding...
1489
  static void __devexit trident_pci_remove(struct pci_dev *dev)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1490
  {
e09ed099d   Krzysztof Helt   tridentfb: conver...
1491
1492
1493
1494
  	struct fb_info *info = pci_get_drvdata(dev);
  	struct tridentfb_par *par = info->par;
  
  	unregister_framebuffer(info);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1495
  	iounmap(par->io_virt);
e09ed099d   Krzysztof Helt   tridentfb: conver...
1496
  	iounmap(info->screen_base);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1497
  	release_mem_region(tridentfb_fix.smem_start, tridentfb_fix.smem_len);
e8ed857c6   Krzysztof Helt   tridentfb: resour...
1498
  	release_mem_region(tridentfb_fix.mmio_start, tridentfb_fix.mmio_len);
e09ed099d   Krzysztof Helt   tridentfb: conver...
1499
  	pci_set_drvdata(dev, NULL);
0292be4a3   Krzysztof Helt   tridentfb: add im...
1500
  	kfree(info->pixmap.addr);
07b39b49b   Andres Salomon   tridentfb: fix me...
1501
  	fb_dealloc_cmap(&info->cmap);
e09ed099d   Krzysztof Helt   tridentfb: conver...
1502
  	framebuffer_release(info);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1503
1504
1505
1506
  }
  
  /* List of boards that we are trying to support */
  static struct pci_device_id trident_devices[] = {
245a2c2c6   Krzysztof Helt   tridentfb: coding...
1507
1508
1509
1510
1511
1512
1513
1514
  	{PCI_VENDOR_ID_TRIDENT,	BLADE3D, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
  	{PCI_VENDOR_ID_TRIDENT,	CYBERBLADEi7, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
  	{PCI_VENDOR_ID_TRIDENT,	CYBERBLADEi7D, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
  	{PCI_VENDOR_ID_TRIDENT,	CYBERBLADEi1, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
  	{PCI_VENDOR_ID_TRIDENT,	CYBERBLADEi1D, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
  	{PCI_VENDOR_ID_TRIDENT,	CYBERBLADEAi1, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
  	{PCI_VENDOR_ID_TRIDENT,	CYBERBLADEAi1D, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
  	{PCI_VENDOR_ID_TRIDENT,	CYBERBLADEE4, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
a0d922562   Krzysztof Helt   tridentfb: add TG...
1515
  	{PCI_VENDOR_ID_TRIDENT,	TGUI9440, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
245a2c2c6   Krzysztof Helt   tridentfb: coding...
1516
1517
1518
1519
1520
1521
1522
1523
1524
1525
1526
1527
  	{PCI_VENDOR_ID_TRIDENT,	TGUI9660, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
  	{PCI_VENDOR_ID_TRIDENT,	IMAGE975, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
  	{PCI_VENDOR_ID_TRIDENT,	IMAGE985, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
  	{PCI_VENDOR_ID_TRIDENT,	CYBER9320, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
  	{PCI_VENDOR_ID_TRIDENT,	CYBER9388, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
  	{PCI_VENDOR_ID_TRIDENT,	CYBER9520, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
  	{PCI_VENDOR_ID_TRIDENT,	CYBER9525DVD, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
  	{PCI_VENDOR_ID_TRIDENT,	CYBER9397, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
  	{PCI_VENDOR_ID_TRIDENT,	CYBER9397DVD, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
  	{PCI_VENDOR_ID_TRIDENT,	CYBERBLADEXPAi1, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
  	{PCI_VENDOR_ID_TRIDENT,	CYBERBLADEXPm8, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
  	{PCI_VENDOR_ID_TRIDENT,	CYBERBLADEXPm16, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1528
  	{0,}
245a2c2c6   Krzysztof Helt   tridentfb: coding...
1529
1530
1531
  };
  
  MODULE_DEVICE_TABLE(pci, trident_devices);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1532
1533
  
  static struct pci_driver tridentfb_pci_driver = {
245a2c2c6   Krzysztof Helt   tridentfb: coding...
1534
1535
1536
1537
  	.name = "tridentfb",
  	.id_table = trident_devices,
  	.probe = trident_pci_probe,
  	.remove = __devexit_p(trident_pci_remove)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1538
1539
1540
1541
1542
  };
  
  /*
   * Parse user specified options (`video=trident:')
   * example:
245a2c2c6   Krzysztof Helt   tridentfb: coding...
1543
   *	video=trident:800x600,bpp=16,noaccel
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1544
1545
   */
  #ifndef MODULE
07f41e45f   Krzysztof Helt   tridentfb: change...
1546
  static int __init tridentfb_setup(char *options)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1547
  {
245a2c2c6   Krzysztof Helt   tridentfb: coding...
1548
  	char *opt;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1549
1550
  	if (!options || !*options)
  		return 0;
245a2c2c6   Krzysztof Helt   tridentfb: coding...
1551
1552
1553
1554
  	while ((opt = strsep(&options, ",")) != NULL) {
  		if (!*opt)
  			continue;
  		if (!strncmp(opt, "noaccel", 7))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1555
  			noaccel = 1;
245a2c2c6   Krzysztof Helt   tridentfb: coding...
1556
  		else if (!strncmp(opt, "fp", 2))
6eed8e1ec   Krzysztof Helt   tridentfb: move g...
1557
  			fp = 1;
245a2c2c6   Krzysztof Helt   tridentfb: coding...
1558
  		else if (!strncmp(opt, "crt", 3))
6eed8e1ec   Krzysztof Helt   tridentfb: move g...
1559
  			fp = 0;
245a2c2c6   Krzysztof Helt   tridentfb: coding...
1560
1561
1562
  		else if (!strncmp(opt, "bpp=", 4))
  			bpp = simple_strtoul(opt + 4, NULL, 0);
  		else if (!strncmp(opt, "center", 6))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1563
  			center = 1;
245a2c2c6   Krzysztof Helt   tridentfb: coding...
1564
  		else if (!strncmp(opt, "stretch", 7))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1565
  			stretch = 1;
245a2c2c6   Krzysztof Helt   tridentfb: coding...
1566
1567
1568
1569
1570
1571
  		else if (!strncmp(opt, "memsize=", 8))
  			memsize = simple_strtoul(opt + 8, NULL, 0);
  		else if (!strncmp(opt, "memdiff=", 8))
  			memdiff = simple_strtoul(opt + 8, NULL, 0);
  		else if (!strncmp(opt, "nativex=", 8))
  			nativex = simple_strtoul(opt + 8, NULL, 0);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1572
  		else
07f41e45f   Krzysztof Helt   tridentfb: change...
1573
  			mode_option = opt;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1574
1575
1576
1577
1578
1579
1580
1581
1582
1583
1584
1585
1586
1587
  	}
  	return 0;
  }
  #endif
  
  static int __init tridentfb_init(void)
  {
  #ifndef MODULE
  	char *option = NULL;
  
  	if (fb_get_options("tridentfb", &option))
  		return -ENODEV;
  	tridentfb_setup(option);
  #endif
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1588
1589
1590
1591
1592
1593
1594
  	return pci_register_driver(&tridentfb_pci_driver);
  }
  
  static void __exit tridentfb_exit(void)
  {
  	pci_unregister_driver(&tridentfb_pci_driver);
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1595
1596
1597
1598
1599
1600
  module_init(tridentfb_init);
  module_exit(tridentfb_exit);
  
  MODULE_AUTHOR("Jani Monoses <jani@iv.ro>");
  MODULE_DESCRIPTION("Framebuffer driver for Trident cards");
  MODULE_LICENSE("GPL");
ddb53d48d   Krzysztof Helt   fbdev: remove cyb...
1601
  MODULE_ALIAS("cyblafb");
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1602