Blame view

drivers/video/s3fb.c 45.1 KB
a268422de   Ondrej Zajicek   [PATCH] fbdev dri...
1
2
3
4
5
6
7
8
9
10
11
12
  /*
   * linux/drivers/video/s3fb.c -- Frame buffer device driver for S3 Trio/Virge
   *
   * Copyright (c) 2006-2007 Ondrej Zajicek <santiago@crfreenet.org>
   *
   * This file is subject to the terms and conditions of the GNU General Public
   * License.  See the file COPYING in the main directory of this archive for
   * more details.
   *
   * Code is based on David Boucher's viafb (http://davesdomain.org.uk/viafb/)
   * which is based on the code of neofb.
   */
a268422de   Ondrej Zajicek   [PATCH] fbdev dri...
13
14
15
16
17
18
  #include <linux/module.h>
  #include <linux/kernel.h>
  #include <linux/errno.h>
  #include <linux/string.h>
  #include <linux/mm.h>
  #include <linux/tty.h>
a268422de   Ondrej Zajicek   [PATCH] fbdev dri...
19
20
21
22
23
  #include <linux/delay.h>
  #include <linux/fb.h>
  #include <linux/svga.h>
  #include <linux/init.h>
  #include <linux/pci.h>
ac751efa6   Torben Hohn   console: rename a...
24
  #include <linux/console.h> /* Why should fb driver call console functions? because console_lock() */
a268422de   Ondrej Zajicek   [PATCH] fbdev dri...
25
  #include <video/vga.h>
86c0f043a   Ondrej Zary   s3fb: add DDC sup...
26
27
  #include <linux/i2c.h>
  #include <linux/i2c-algo-bit.h>
a268422de   Ondrej Zajicek   [PATCH] fbdev dri...
28
29
30
31
32
33
34
35
36
37
38
  #ifdef CONFIG_MTRR
  #include <asm/mtrr.h>
  #endif
  
  struct s3fb_info {
  	int chip, rev, mclk_freq;
  	int mtrr_reg;
  	struct vgastate state;
  	struct mutex open_lock;
  	unsigned int ref_count;
  	u32 pseudo_palette[16];
86c0f043a   Ondrej Zary   s3fb: add DDC sup...
39
40
41
42
43
44
  #ifdef CONFIG_FB_S3_DDC
  	u8 __iomem *mmio;
  	bool ddc_registered;
  	struct i2c_adapter ddc_adapter;
  	struct i2c_algo_bit_data ddc_algo;
  #endif
a268422de   Ondrej Zajicek   [PATCH] fbdev dri...
45
46
47
48
49
50
51
52
  };
  
  
  /* ------------------------------------------------------------------------- */
  
  static const struct svga_fb_format s3fb_formats[] = {
  	{ 0,  {0, 6, 0},  {0, 6, 0},  {0, 6, 0}, {0, 0, 0}, 0,
  		FB_TYPE_TEXT, FB_AUX_TEXT_SVGA_STEP4,	FB_VISUAL_PSEUDOCOLOR, 8, 16},
c26d7b29d   Michal Januszewski   s3fb: fix color c...
53
  	{ 4,  {0, 4, 0},  {0, 4, 0},  {0, 4, 0}, {0, 0, 0}, 0,
a268422de   Ondrej Zajicek   [PATCH] fbdev dri...
54
  		FB_TYPE_PACKED_PIXELS, 0,		FB_VISUAL_PSEUDOCOLOR, 8, 16},
c26d7b29d   Michal Januszewski   s3fb: fix color c...
55
  	{ 4,  {0, 4, 0},  {0, 4, 0},  {0, 4, 0}, {0, 0, 0}, 1,
a268422de   Ondrej Zajicek   [PATCH] fbdev dri...
56
  		FB_TYPE_INTERLEAVED_PLANES, 1,		FB_VISUAL_PSEUDOCOLOR, 8, 16},
c26d7b29d   Michal Januszewski   s3fb: fix color c...
57
  	{ 8,  {0, 8, 0},  {0, 8, 0},  {0, 8, 0}, {0, 0, 0}, 0,
a268422de   Ondrej Zajicek   [PATCH] fbdev dri...
58
59
60
61
62
63
64
65
66
67
68
69
70
71
  		FB_TYPE_PACKED_PIXELS, 0,		FB_VISUAL_PSEUDOCOLOR, 4, 8},
  	{16,  {10, 5, 0}, {5, 5, 0},  {0, 5, 0}, {0, 0, 0}, 0,
  		FB_TYPE_PACKED_PIXELS, 0,		FB_VISUAL_TRUECOLOR, 2, 4},
  	{16,  {11, 5, 0}, {5, 6, 0},  {0, 5, 0}, {0, 0, 0}, 0,
  		FB_TYPE_PACKED_PIXELS, 0,		FB_VISUAL_TRUECOLOR, 2, 4},
  	{24,  {16, 8, 0}, {8, 8, 0},  {0, 8, 0}, {0, 0, 0}, 0,
  		FB_TYPE_PACKED_PIXELS, 0,		FB_VISUAL_TRUECOLOR, 1, 2},
  	{32,  {16, 8, 0}, {8, 8, 0},  {0, 8, 0}, {0, 0, 0}, 0,
  		FB_TYPE_PACKED_PIXELS, 0,		FB_VISUAL_TRUECOLOR, 1, 2},
  	SVGA_FORMAT_END
  };
  
  
  static const struct svga_pll s3_pll = {3, 129, 3, 33, 0, 3,
249bdbbf0   Ondrej Zajicek   s3fb: driver fixes
72
  	35000, 240000, 14318};
5694f9ce5   Ondrej Zary   s3fb: add support...
73
74
  static const struct svga_pll s3_trio3d_pll = {3, 129, 3, 31, 0, 4,
  	230000, 460000, 14318};
a268422de   Ondrej Zajicek   [PATCH] fbdev dri...
75
76
77
78
79
  
  static const int s3_memsizes[] = {4096, 0, 3072, 8192, 2048, 6144, 1024, 512};
  
  static const char * const s3_names[] = {"S3 Unknown", "S3 Trio32", "S3 Trio64", "S3 Trio64V+",
  			"S3 Trio64UV+", "S3 Trio64V2/DX", "S3 Trio64V2/GX",
94e948e6e   Ondrej Zary   s3fb: fix Virge/GX2
80
  			"S3 Plato/PX", "S3 Aurora64V+", "S3 Virge",
a268422de   Ondrej Zajicek   [PATCH] fbdev dri...
81
  			"S3 Virge/VX", "S3 Virge/DX", "S3 Virge/GX",
94e948e6e   Ondrej Zary   s3fb: fix Virge/GX2
82
  			"S3 Virge/GX2", "S3 Virge/GX2+", "",
5694f9ce5   Ondrej Zary   s3fb: add support...
83
84
  			"S3 Trio3D/1X", "S3 Trio3D/2X", "S3 Trio3D/2X",
  			"S3 Trio3D"};
a268422de   Ondrej Zajicek   [PATCH] fbdev dri...
85
86
87
88
89
90
91
92
93
94
95
96
97
98
  
  #define CHIP_UNKNOWN		0x00
  #define CHIP_732_TRIO32		0x01
  #define CHIP_764_TRIO64		0x02
  #define CHIP_765_TRIO64VP	0x03
  #define CHIP_767_TRIO64UVP	0x04
  #define CHIP_775_TRIO64V2_DX	0x05
  #define CHIP_785_TRIO64V2_GX	0x06
  #define CHIP_551_PLATO_PX	0x07
  #define CHIP_M65_AURORA64VP	0x08
  #define CHIP_325_VIRGE		0x09
  #define CHIP_988_VIRGE_VX	0x0A
  #define CHIP_375_VIRGE_DX	0x0B
  #define CHIP_385_VIRGE_GX	0x0C
94e948e6e   Ondrej Zary   s3fb: fix Virge/GX2
99
100
  #define CHIP_357_VIRGE_GX2	0x0D
  #define CHIP_359_VIRGE_GX2P	0x0E
9966c4fea   Ondrej Zary   add support for S...
101
102
103
  #define CHIP_360_TRIO3D_1X	0x10
  #define CHIP_362_TRIO3D_2X	0x11
  #define CHIP_368_TRIO3D_2X	0x12
5694f9ce5   Ondrej Zary   s3fb: add support...
104
  #define CHIP_365_TRIO3D		0x13
a268422de   Ondrej Zajicek   [PATCH] fbdev dri...
105
106
107
108
  
  #define CHIP_XXX_TRIO		0x80
  #define CHIP_XXX_TRIO64V2_DXGX	0x81
  #define CHIP_XXX_VIRGE_DXGX	0x82
9966c4fea   Ondrej Zary   add support for S...
109
  #define CHIP_36X_TRIO3D_1X_2X	0x83
a268422de   Ondrej Zajicek   [PATCH] fbdev dri...
110
111
112
  
  #define CHIP_UNDECIDED_FLAG	0x80
  #define CHIP_MASK		0xFF
86c0f043a   Ondrej Zary   s3fb: add DDC sup...
113
114
  #define MMIO_OFFSET		0x1000000
  #define MMIO_SIZE		0x10000
a268422de   Ondrej Zajicek   [PATCH] fbdev dri...
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
  /* CRT timing register sets */
  
  static const struct vga_regset s3_h_total_regs[]        = {{0x00, 0, 7}, {0x5D, 0, 0}, VGA_REGSET_END};
  static const struct vga_regset s3_h_display_regs[]      = {{0x01, 0, 7}, {0x5D, 1, 1}, VGA_REGSET_END};
  static const struct vga_regset s3_h_blank_start_regs[]  = {{0x02, 0, 7}, {0x5D, 2, 2}, VGA_REGSET_END};
  static const struct vga_regset s3_h_blank_end_regs[]    = {{0x03, 0, 4}, {0x05, 7, 7}, VGA_REGSET_END};
  static const struct vga_regset s3_h_sync_start_regs[]   = {{0x04, 0, 7}, {0x5D, 4, 4}, VGA_REGSET_END};
  static const struct vga_regset s3_h_sync_end_regs[]     = {{0x05, 0, 4}, VGA_REGSET_END};
  
  static const struct vga_regset s3_v_total_regs[]        = {{0x06, 0, 7}, {0x07, 0, 0}, {0x07, 5, 5}, {0x5E, 0, 0}, VGA_REGSET_END};
  static const struct vga_regset s3_v_display_regs[]      = {{0x12, 0, 7}, {0x07, 1, 1}, {0x07, 6, 6}, {0x5E, 1, 1}, VGA_REGSET_END};
  static const struct vga_regset s3_v_blank_start_regs[]  = {{0x15, 0, 7}, {0x07, 3, 3}, {0x09, 5, 5}, {0x5E, 2, 2}, VGA_REGSET_END};
  static const struct vga_regset s3_v_blank_end_regs[]    = {{0x16, 0, 7}, VGA_REGSET_END};
  static const struct vga_regset s3_v_sync_start_regs[]   = {{0x10, 0, 7}, {0x07, 2, 2}, {0x07, 7, 7}, {0x5E, 4, 4}, VGA_REGSET_END};
  static const struct vga_regset s3_v_sync_end_regs[]     = {{0x11, 0, 3}, VGA_REGSET_END};
  
  static const struct vga_regset s3_line_compare_regs[]   = {{0x18, 0, 7}, {0x07, 4, 4}, {0x09, 6, 6}, {0x5E, 6, 6}, VGA_REGSET_END};
7fe029df4   Ondrej Zary   s3fb: use new sta...
132
  static const struct vga_regset s3_start_address_regs[]  = {{0x0d, 0, 7}, {0x0c, 0, 7}, {0x69, 0, 4}, VGA_REGSET_END};
a268422de   Ondrej Zajicek   [PATCH] fbdev dri...
133
  static const struct vga_regset s3_offset_regs[]         = {{0x13, 0, 7}, {0x51, 4, 5}, VGA_REGSET_END}; /* set 0x43 bit 2 to 0 */
cb11c0489   Ondrej Zary   s3fb: enable DTPC
134
  static const struct vga_regset s3_dtpc_regs[]		= {{0x3B, 0, 7}, {0x5D, 6, 6}, VGA_REGSET_END};
a268422de   Ondrej Zajicek   [PATCH] fbdev dri...
135
136
137
138
139
140
141
142
143
144
145
  static const struct svga_timing_regs s3_timing_regs     = {
  	s3_h_total_regs, s3_h_display_regs, s3_h_blank_start_regs,
  	s3_h_blank_end_regs, s3_h_sync_start_regs, s3_h_sync_end_regs,
  	s3_v_total_regs, s3_v_display_regs, s3_v_blank_start_regs,
  	s3_v_blank_end_regs, s3_v_sync_start_regs, s3_v_sync_end_regs,
  };
  
  
  /* ------------------------------------------------------------------------- */
  
  /* Module parameters */
86c0f043a   Ondrej Zary   s3fb: add DDC sup...
146
  static char *mode_option __devinitdata;
a268422de   Ondrej Zajicek   [PATCH] fbdev dri...
147
148
  
  #ifdef CONFIG_MTRR
a81405439   Krzysztof Helt   s3fb: add option ...
149
  static int mtrr __devinitdata = 1;
a268422de   Ondrej Zajicek   [PATCH] fbdev dri...
150
151
152
153
154
155
156
157
  #endif
  
  static int fasttext = 1;
  
  
  MODULE_AUTHOR("(c) 2006-2007 Ondrej Zajicek <santiago@crfreenet.org>");
  MODULE_LICENSE("GPL");
  MODULE_DESCRIPTION("fbdev driver for S3 Trio/Virge");
a81405439   Krzysztof Helt   s3fb: add option ...
158
159
160
161
  module_param(mode_option, charp, 0444);
  MODULE_PARM_DESC(mode_option, "Default video mode ('640x480-8@60', etc)");
  module_param_named(mode, mode_option, charp, 0444);
  MODULE_PARM_DESC(mode, "Default video mode ('640x480-8@60', etc) (deprecated)");
a268422de   Ondrej Zajicek   [PATCH] fbdev dri...
162
163
164
165
166
167
168
169
170
171
172
  
  #ifdef CONFIG_MTRR
  module_param(mtrr, int, 0444);
  MODULE_PARM_DESC(mtrr, "Enable write-combining with MTRR (1=enable, 0=disable, default=1)");
  #endif
  
  module_param(fasttext, int, 0644);
  MODULE_PARM_DESC(fasttext, "Enable S3 fast text mode (1=enable, 0=disable, default=1)");
  
  
  /* ------------------------------------------------------------------------- */
86c0f043a   Ondrej Zary   s3fb: add DDC sup...
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
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
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
  #ifdef CONFIG_FB_S3_DDC
  
  #define DDC_REG		0xaa		/* Trio 3D/1X/2X */
  #define DDC_MMIO_REG	0xff20		/* all other chips */
  #define DDC_SCL_OUT	(1 << 0)
  #define DDC_SDA_OUT	(1 << 1)
  #define DDC_SCL_IN	(1 << 2)
  #define DDC_SDA_IN	(1 << 3)
  #define DDC_DRIVE_EN	(1 << 4)
  
  static bool s3fb_ddc_needs_mmio(int chip)
  {
  	return !(chip == CHIP_360_TRIO3D_1X  ||
  		 chip == CHIP_362_TRIO3D_2X  ||
  		 chip == CHIP_368_TRIO3D_2X);
  }
  
  static u8 s3fb_ddc_read(struct s3fb_info *par)
  {
  	if (s3fb_ddc_needs_mmio(par->chip))
  		return readb(par->mmio + DDC_MMIO_REG);
  	else
  		return vga_rcrt(par->state.vgabase, DDC_REG);
  }
  
  static void s3fb_ddc_write(struct s3fb_info *par, u8 val)
  {
  	if (s3fb_ddc_needs_mmio(par->chip))
  		writeb(val, par->mmio + DDC_MMIO_REG);
  	else
  		vga_wcrt(par->state.vgabase, DDC_REG, val);
  }
  
  static void s3fb_ddc_setscl(void *data, int val)
  {
  	struct s3fb_info *par = data;
  	unsigned char reg;
  
  	reg = s3fb_ddc_read(par) | DDC_DRIVE_EN;
  	if (val)
  		reg |= DDC_SCL_OUT;
  	else
  		reg &= ~DDC_SCL_OUT;
  	s3fb_ddc_write(par, reg);
  }
  
  static void s3fb_ddc_setsda(void *data, int val)
  {
  	struct s3fb_info *par = data;
  	unsigned char reg;
  
  	reg = s3fb_ddc_read(par) | DDC_DRIVE_EN;
  	if (val)
  		reg |= DDC_SDA_OUT;
  	else
  		reg &= ~DDC_SDA_OUT;
  	s3fb_ddc_write(par, reg);
  }
  
  static int s3fb_ddc_getscl(void *data)
  {
  	struct s3fb_info *par = data;
  
  	return !!(s3fb_ddc_read(par) & DDC_SCL_IN);
  }
  
  static int s3fb_ddc_getsda(void *data)
  {
  	struct s3fb_info *par = data;
  
  	return !!(s3fb_ddc_read(par) & DDC_SDA_IN);
  }
  
  static int __devinit s3fb_setup_ddc_bus(struct fb_info *info)
  {
  	struct s3fb_info *par = info->par;
  
  	strlcpy(par->ddc_adapter.name, info->fix.id,
  		sizeof(par->ddc_adapter.name));
  	par->ddc_adapter.owner		= THIS_MODULE;
  	par->ddc_adapter.class		= I2C_CLASS_DDC;
  	par->ddc_adapter.algo_data	= &par->ddc_algo;
  	par->ddc_adapter.dev.parent	= info->device;
  	par->ddc_algo.setsda		= s3fb_ddc_setsda;
  	par->ddc_algo.setscl		= s3fb_ddc_setscl;
  	par->ddc_algo.getsda		= s3fb_ddc_getsda;
  	par->ddc_algo.getscl		= s3fb_ddc_getscl;
  	par->ddc_algo.udelay		= 10;
  	par->ddc_algo.timeout		= 20;
  	par->ddc_algo.data		= par;
  
  	i2c_set_adapdata(&par->ddc_adapter, par);
  
  	/*
  	 * some Virge cards have external MUX to switch chip I2C bus between
  	 * DDC and extension pins - switch it do DDC
  	 */
  /*	vga_wseq(par->state.vgabase, 0x08, 0x06); - not needed, already unlocked */
  	if (par->chip == CHIP_357_VIRGE_GX2 ||
  	    par->chip == CHIP_359_VIRGE_GX2P)
  		svga_wseq_mask(par->state.vgabase, 0x0d, 0x01, 0x03);
  	else
  		svga_wseq_mask(par->state.vgabase, 0x0d, 0x00, 0x03);
  	/* some Virge need this or the DDC is ignored */
  	svga_wcrt_mask(par->state.vgabase, 0x5c, 0x03, 0x03);
  
  	return i2c_bit_add_bus(&par->ddc_adapter);
  }
  #endif /* CONFIG_FB_S3_DDC */
  
  
  /* ------------------------------------------------------------------------- */
a268422de   Ondrej Zajicek   [PATCH] fbdev dri...
285
286
287
288
289
  /* Set font in S3 fast text mode */
  
  static void s3fb_settile_fast(struct fb_info *info, struct fb_tilemap *map)
  {
  	const u8 *font = map->data;
75814d87a   Antonino A. Daplas   s3fb: add sparse ...
290
  	u8 __iomem *fb = (u8 __iomem *) info->screen_base;
a268422de   Ondrej Zajicek   [PATCH] fbdev dri...
291
292
293
294
295
296
297
298
299
300
301
302
303
  	int i, c;
  
  	if ((map->width != 8) || (map->height != 16) ||
  	    (map->depth != 1) || (map->length != 256)) {
  	    	printk(KERN_ERR "fb%d: unsupported font parameters: width %d, height %d, depth %d, length %d
  ",
  			info->node, map->width, map->height, map->depth, map->length);
  		return;
  	}
  
  	fb += 2;
  	for (i = 0; i < map->height; i++) {
  		for (c = 0; c < map->length; c++) {
75814d87a   Antonino A. Daplas   s3fb: add sparse ...
304
  			fb_writeb(font[c * map->height + i], fb + c * 4);
a268422de   Ondrej Zajicek   [PATCH] fbdev dri...
305
306
307
308
  		}
  		fb += 1024;
  	}
  }
55db09238   David Miller   svga: Make svga_t...
309
310
311
312
313
314
  static void s3fb_tilecursor(struct fb_info *info, struct fb_tilecursor *cursor)
  {
  	struct s3fb_info *par = info->par;
  
  	svga_tilecursor(par->state.vgabase, info, cursor);
  }
a268422de   Ondrej Zajicek   [PATCH] fbdev dri...
315
316
317
318
319
  static struct fb_tile_ops s3fb_tile_ops = {
  	.fb_settile	= svga_settile,
  	.fb_tilecopy	= svga_tilecopy,
  	.fb_tilefill    = svga_tilefill,
  	.fb_tileblit    = svga_tileblit,
55db09238   David Miller   svga: Make svga_t...
320
  	.fb_tilecursor  = s3fb_tilecursor,
34ed25f50   Ondrej Zajicek   s3fb: updates
321
  	.fb_get_tilemax = svga_get_tilemax,
a268422de   Ondrej Zajicek   [PATCH] fbdev dri...
322
323
324
325
326
327
328
  };
  
  static struct fb_tile_ops s3fb_fast_tile_ops = {
  	.fb_settile	= s3fb_settile_fast,
  	.fb_tilecopy	= svga_tilecopy,
  	.fb_tilefill    = svga_tilefill,
  	.fb_tileblit    = svga_tileblit,
55db09238   David Miller   svga: Make svga_t...
329
  	.fb_tilecursor  = s3fb_tilecursor,
34ed25f50   Ondrej Zajicek   s3fb: updates
330
  	.fb_get_tilemax = svga_get_tilemax,
a268422de   Ondrej Zajicek   [PATCH] fbdev dri...
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
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
450
451
452
453
454
455
  };
  
  
  /* ------------------------------------------------------------------------- */
  
  /* image data is MSB-first, fb structure is MSB-first too */
  static inline u32 expand_color(u32 c)
  {
  	return ((c & 1) | ((c & 2) << 7) | ((c & 4) << 14) | ((c & 8) << 21)) * 0xFF;
  }
  
  /* s3fb_iplan_imageblit silently assumes that almost everything is 8-pixel aligned */
  static void s3fb_iplan_imageblit(struct fb_info *info, const struct fb_image *image)
  {
  	u32 fg = expand_color(image->fg_color);
  	u32 bg = expand_color(image->bg_color);
  	const u8 *src1, *src;
  	u8 __iomem *dst1;
  	u32 __iomem *dst;
  	u32 val;
  	int x, y;
  
  	src1 = image->data;
  	dst1 = info->screen_base + (image->dy * info->fix.line_length)
  		 + ((image->dx / 8) * 4);
  
  	for (y = 0; y < image->height; y++) {
  		src = src1;
  		dst = (u32 __iomem *) dst1;
  		for (x = 0; x < image->width; x += 8) {
  			val = *(src++) * 0x01010101;
  			val = (val & fg) | (~val & bg);
  			fb_writel(val, dst++);
  		}
  		src1 += image->width / 8;
  		dst1 += info->fix.line_length;
  	}
  
  }
  
  /* s3fb_iplan_fillrect silently assumes that almost everything is 8-pixel aligned */
  static void s3fb_iplan_fillrect(struct fb_info *info, const struct fb_fillrect *rect)
  {
  	u32 fg = expand_color(rect->color);
  	u8 __iomem *dst1;
  	u32 __iomem *dst;
  	int x, y;
  
  	dst1 = info->screen_base + (rect->dy * info->fix.line_length)
  		 + ((rect->dx / 8) * 4);
  
  	for (y = 0; y < rect->height; y++) {
  		dst = (u32 __iomem *) dst1;
  		for (x = 0; x < rect->width; x += 8) {
  			fb_writel(fg, dst++);
  		}
  		dst1 += info->fix.line_length;
  	}
  }
  
  
  /* image data is MSB-first, fb structure is high-nibble-in-low-byte-first */
  static inline u32 expand_pixel(u32 c)
  {
  	return (((c &  1) << 24) | ((c &  2) << 27) | ((c &  4) << 14) | ((c &   8) << 17) |
  		((c & 16) <<  4) | ((c & 32) <<  7) | ((c & 64) >>  6) | ((c & 128) >>  3)) * 0xF;
  }
  
  /* s3fb_cfb4_imageblit silently assumes that almost everything is 8-pixel aligned */
  static void s3fb_cfb4_imageblit(struct fb_info *info, const struct fb_image *image)
  {
  	u32 fg = image->fg_color * 0x11111111;
  	u32 bg = image->bg_color * 0x11111111;
  	const u8 *src1, *src;
  	u8 __iomem *dst1;
  	u32 __iomem *dst;
  	u32 val;
  	int x, y;
  
  	src1 = image->data;
  	dst1 = info->screen_base + (image->dy * info->fix.line_length)
  		 + ((image->dx / 8) * 4);
  
  	for (y = 0; y < image->height; y++) {
  		src = src1;
  		dst = (u32 __iomem *) dst1;
  		for (x = 0; x < image->width; x += 8) {
  			val = expand_pixel(*(src++));
  			val = (val & fg) | (~val & bg);
  			fb_writel(val, dst++);
  		}
  		src1 += image->width / 8;
  		dst1 += info->fix.line_length;
  	}
  }
  
  static void s3fb_imageblit(struct fb_info *info, const struct fb_image *image)
  {
  	if ((info->var.bits_per_pixel == 4) && (image->depth == 1)
  	    && ((image->width % 8) == 0) && ((image->dx % 8) == 0)) {
  		if (info->fix.type == FB_TYPE_INTERLEAVED_PLANES)
  			s3fb_iplan_imageblit(info, image);
  		else
  			s3fb_cfb4_imageblit(info, image);
  	} else
  		cfb_imageblit(info, image);
  }
  
  static void s3fb_fillrect(struct fb_info *info, const struct fb_fillrect *rect)
  {
  	if ((info->var.bits_per_pixel == 4)
  	    && ((rect->width % 8) == 0) && ((rect->dx % 8) == 0)
  	    && (info->fix.type == FB_TYPE_INTERLEAVED_PLANES))
  		s3fb_iplan_fillrect(info, rect);
  	 else
  		cfb_fillrect(info, rect);
  }
  
  
  
  /* ------------------------------------------------------------------------- */
  
  
  static void s3_set_pixclock(struct fb_info *info, u32 pixclock)
  {
9966c4fea   Ondrej Zary   add support for S...
456
  	struct s3fb_info *par = info->par;
a268422de   Ondrej Zajicek   [PATCH] fbdev dri...
457
458
  	u16 m, n, r;
  	u8 regval;
249bdbbf0   Ondrej Zajicek   s3fb: driver fixes
459
  	int rv;
a268422de   Ondrej Zajicek   [PATCH] fbdev dri...
460

5694f9ce5   Ondrej Zary   s3fb: add support...
461
462
  	rv = svga_compute_pll((par->chip == CHIP_365_TRIO3D) ? &s3_trio3d_pll : &s3_pll,
  			      1000000000 / pixclock, &m, &n, &r, info->node);
249bdbbf0   Ondrej Zajicek   s3fb: driver fixes
463
464
465
466
467
  	if (rv < 0) {
  		printk(KERN_ERR "fb%d: cannot set requested pixclock, keeping old value
  ", info->node);
  		return;
  	}
a268422de   Ondrej Zajicek   [PATCH] fbdev dri...
468
469
  
  	/* Set VGA misc register  */
f86459335   David Miller   s3fb: Pass par->s...
470
471
  	regval = vga_r(par->state.vgabase, VGA_MIS_R);
  	vga_w(par->state.vgabase, VGA_MIS_W, regval | VGA_MIS_ENB_PLL_LOAD);
a268422de   Ondrej Zajicek   [PATCH] fbdev dri...
472
473
  
  	/* Set S3 clock registers */
94e948e6e   Ondrej Zary   s3fb: fix Virge/GX2
474
475
476
  	if (par->chip == CHIP_357_VIRGE_GX2 ||
  	    par->chip == CHIP_359_VIRGE_GX2P ||
  	    par->chip == CHIP_360_TRIO3D_1X ||
9966c4fea   Ondrej Zary   add support for S...
477
478
  	    par->chip == CHIP_362_TRIO3D_2X ||
  	    par->chip == CHIP_368_TRIO3D_2X) {
f86459335   David Miller   s3fb: Pass par->s...
479
480
  		vga_wseq(par->state.vgabase, 0x12, (n - 2) | ((r & 3) << 6));	/* n and two bits of r */
  		vga_wseq(par->state.vgabase, 0x29, r >> 2); /* remaining highest bit of r */
9966c4fea   Ondrej Zary   add support for S...
481
  	} else
f86459335   David Miller   s3fb: Pass par->s...
482
483
  		vga_wseq(par->state.vgabase, 0x12, (n - 2) | (r << 5));
  	vga_wseq(par->state.vgabase, 0x13, m - 2);
a268422de   Ondrej Zajicek   [PATCH] fbdev dri...
484
485
486
487
  
  	udelay(1000);
  
  	/* Activate clock - write 0, 1, 0 to seq/15 bit 5 */
f86459335   David Miller   s3fb: Pass par->s...
488
489
490
491
  	regval = vga_rseq (par->state.vgabase, 0x15); /* | 0x80; */
  	vga_wseq(par->state.vgabase, 0x15, regval & ~(1<<5));
  	vga_wseq(par->state.vgabase, 0x15, regval |  (1<<5));
  	vga_wseq(par->state.vgabase, 0x15, regval & ~(1<<5));
a268422de   Ondrej Zajicek   [PATCH] fbdev dri...
492
493
494
495
496
497
498
499
500
501
502
  }
  
  
  /* Open framebuffer */
  
  static int s3fb_open(struct fb_info *info, int user)
  {
  	struct s3fb_info *par = info->par;
  
  	mutex_lock(&(par->open_lock));
  	if (par->ref_count == 0) {
3ff259f2e   David Miller   s3fb: Don't clobb...
503
  		void __iomem *vgabase = par->state.vgabase;
a268422de   Ondrej Zajicek   [PATCH] fbdev dri...
504
  		memset(&(par->state), 0, sizeof(struct vgastate));
3ff259f2e   David Miller   s3fb: Don't clobb...
505
  		par->state.vgabase = vgabase;
a268422de   Ondrej Zajicek   [PATCH] fbdev dri...
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
  		par->state.flags = VGA_SAVE_MODE | VGA_SAVE_FONTS | VGA_SAVE_CMAP;
  		par->state.num_crtc = 0x70;
  		par->state.num_seq = 0x20;
  		save_vga(&(par->state));
  	}
  
  	par->ref_count++;
  	mutex_unlock(&(par->open_lock));
  
  	return 0;
  }
  
  /* Close framebuffer */
  
  static int s3fb_release(struct fb_info *info, int user)
  {
  	struct s3fb_info *par = info->par;
  
  	mutex_lock(&(par->open_lock));
  	if (par->ref_count == 0) {
  		mutex_unlock(&(par->open_lock));
  		return -EINVAL;
  	}
  
  	if (par->ref_count == 1)
  		restore_vga(&(par->state));
  
  	par->ref_count--;
  	mutex_unlock(&(par->open_lock));
  
  	return 0;
  }
  
  /* Validate passed in var */
  
  static int s3fb_check_var(struct fb_var_screeninfo *var, struct fb_info *info)
  {
  	struct s3fb_info *par = info->par;
  	int rv, mem, step;
c3ca34f90   Krzysztof Helt   s3fb: do not allo...
545
  	u16 m, n, r;
a268422de   Ondrej Zajicek   [PATCH] fbdev dri...
546
547
548
  
  	/* Find appropriate format */
  	rv = svga_match_format (s3fb_formats, var, NULL);
d4b766a0b   Ondrej Zajicek   svgalib: mode sel...
549
550
551
552
553
554
555
  
  	/* 32bpp mode is not supported on VIRGE VX,
  	   24bpp is not supported on others */
  	if ((par->chip == CHIP_988_VIRGE_VX) ? (rv == 7) : (rv == 6))
  		rv = -EINVAL;
  
  	if (rv < 0) {
a268422de   Ondrej Zajicek   [PATCH] fbdev dri...
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
  		printk(KERN_ERR "fb%d: unsupported mode requested
  ", info->node);
  		return rv;
  	}
  
  	/* Do not allow to have real resoulution larger than virtual */
  	if (var->xres > var->xres_virtual)
  		var->xres_virtual = var->xres;
  
  	if (var->yres > var->yres_virtual)
  		var->yres_virtual = var->yres;
  
  	/* Round up xres_virtual to have proper alignment of lines */
  	step = s3fb_formats[rv].xresstep - 1;
  	var->xres_virtual = (var->xres_virtual+step) & ~step;
  
  	/* Check whether have enough memory */
  	mem = ((var->bits_per_pixel * var->xres_virtual) >> 3) * var->yres_virtual;
c3ca34f90   Krzysztof Helt   s3fb: do not allo...
574
  	if (mem > info->screen_size) {
a268422de   Ondrej Zajicek   [PATCH] fbdev dri...
575
576
577
578
579
580
581
  		printk(KERN_ERR "fb%d: not enough framebuffer memory (%d kB requested , %d kB available)
  ",
  			info->node, mem >> 10, (unsigned int) (info->screen_size >> 10));
  		return -EINVAL;
  	}
  
  	rv = svga_check_timings (&s3_timing_regs, var, info->node);
c3ca34f90   Krzysztof Helt   s3fb: do not allo...
582
  	if (rv < 0) {
a268422de   Ondrej Zajicek   [PATCH] fbdev dri...
583
584
585
586
  		printk(KERN_ERR "fb%d: invalid timings requested
  ", info->node);
  		return rv;
  	}
c3ca34f90   Krzysztof Helt   s3fb: do not allo...
587
588
589
590
591
592
593
594
  	rv = svga_compute_pll(&s3_pll, PICOS2KHZ(var->pixclock), &m, &n, &r,
  				info->node);
  	if (rv < 0) {
  		printk(KERN_ERR "fb%d: invalid pixclock value requested
  ",
  			info->node);
  		return rv;
  	}
a268422de   Ondrej Zajicek   [PATCH] fbdev dri...
595
596
597
598
599
600
601
602
  	return 0;
  }
  
  /* Set video mode from par */
  
  static int s3fb_set_par(struct fb_info *info)
  {
  	struct s3fb_info *par = info->par;
9966c4fea   Ondrej Zary   add support for S...
603
  	u32 value, mode, hmul, offset_value, screen_size, multiplex, dbytes;
a268422de   Ondrej Zajicek   [PATCH] fbdev dri...
604
  	u32 bpp = info->var.bits_per_pixel;
cb11c0489   Ondrej Zary   s3fb: enable DTPC
605
  	u32 htotal, hsstart;
a268422de   Ondrej Zajicek   [PATCH] fbdev dri...
606
607
608
609
610
611
612
  
  	if (bpp != 0) {
  		info->fix.ypanstep = 1;
  		info->fix.line_length = (info->var.xres_virtual * bpp) / 8;
  
  		info->flags &= ~FBINFO_MISC_TILEBLITTING;
  		info->tileops = NULL;
34ed25f50   Ondrej Zajicek   s3fb: updates
613
614
  		/* in 4bpp supports 8p wide tiles only, any tiles otherwise */
  		info->pixmap.blit_x = (bpp == 4) ? (1 << (8 - 1)) : (~(u32)0);
8db51668f   Antonino A. Daplas   s3fb: limit 8x16 ...
615
  		info->pixmap.blit_y = ~(u32)0;
34ed25f50   Ondrej Zajicek   s3fb: updates
616

a268422de   Ondrej Zajicek   [PATCH] fbdev dri...
617
618
619
620
621
622
623
624
  		offset_value = (info->var.xres_virtual * bpp) / 64;
  		screen_size = info->var.yres_virtual * info->fix.line_length;
  	} else {
  		info->fix.ypanstep = 16;
  		info->fix.line_length = 0;
  
  		info->flags |= FBINFO_MISC_TILEBLITTING;
  		info->tileops = fasttext ? &s3fb_fast_tile_ops : &s3fb_tile_ops;
34ed25f50   Ondrej Zajicek   s3fb: updates
625

8db51668f   Antonino A. Daplas   s3fb: limit 8x16 ...
626
627
628
  		/* supports 8x16 tiles only */
  		info->pixmap.blit_x = 1 << (8 - 1);
  		info->pixmap.blit_y = 1 << (16 - 1);
a268422de   Ondrej Zajicek   [PATCH] fbdev dri...
629
630
631
632
633
634
635
636
637
638
  
  		offset_value = info->var.xres_virtual / 16;
  		screen_size = (info->var.xres_virtual * info->var.yres_virtual) / 64;
  	}
  
  	info->var.xoffset = 0;
  	info->var.yoffset = 0;
  	info->var.activate = FB_ACTIVATE_NOW;
  
  	/* Unlock registers */
f86459335   David Miller   s3fb: Pass par->s...
639
640
641
  	vga_wcrt(par->state.vgabase, 0x38, 0x48);
  	vga_wcrt(par->state.vgabase, 0x39, 0xA5);
  	vga_wseq(par->state.vgabase, 0x08, 0x06);
ea770789d   David Miller   svga: Make svga_w...
642
  	svga_wcrt_mask(par->state.vgabase, 0x11, 0x00, 0x80);
a268422de   Ondrej Zajicek   [PATCH] fbdev dri...
643
644
  
  	/* Blank screen and turn off sync */
d907ec04c   David Miller   svga: Make svga_w...
645
  	svga_wseq_mask(par->state.vgabase, 0x01, 0x20, 0x20);
ea770789d   David Miller   svga: Make svga_w...
646
  	svga_wcrt_mask(par->state.vgabase, 0x17, 0x00, 0x80);
a268422de   Ondrej Zajicek   [PATCH] fbdev dri...
647
648
  
  	/* Set default values */
e2fade2c1   David Miller   svga: Make svga_s...
649
  	svga_set_default_gfx_regs(par->state.vgabase);
f51a14dde   David Miller   svga: Make svga_s...
650
  	svga_set_default_atc_regs(par->state.vgabase);
a4ade8394   David Miller   svga: Make svga_s...
651
  	svga_set_default_seq_regs(par->state.vgabase);
1d28fcadb   David Miller   svga: Make svga_s...
652
  	svga_set_default_crt_regs(par->state.vgabase);
21da386d0   David Miller   svga: Make svga_w...
653
654
  	svga_wcrt_multi(par->state.vgabase, s3_line_compare_regs, 0xFFFFFFFF);
  	svga_wcrt_multi(par->state.vgabase, s3_start_address_regs, 0);
a268422de   Ondrej Zajicek   [PATCH] fbdev dri...
655
656
  
  	/* S3 specific initialization */
ea770789d   David Miller   svga: Make svga_w...
657
658
  	svga_wcrt_mask(par->state.vgabase, 0x58, 0x10, 0x10); /* enable linear framebuffer */
  	svga_wcrt_mask(par->state.vgabase, 0x31, 0x08, 0x08); /* enable sequencer access to framebuffer above 256 kB */
a268422de   Ondrej Zajicek   [PATCH] fbdev dri...
659

ea770789d   David Miller   svga: Make svga_w...
660
661
662
663
  /*	svga_wcrt_mask(par->state.vgabase, 0x33, 0x08, 0x08); */ /* DDR ?	*/
  /*	svga_wcrt_mask(par->state.vgabase, 0x43, 0x01, 0x01); */ /* DDR ?	*/
  	svga_wcrt_mask(par->state.vgabase, 0x33, 0x00, 0x08); /* no DDR ?	*/
  	svga_wcrt_mask(par->state.vgabase, 0x43, 0x00, 0x01); /* no DDR ?	*/
a268422de   Ondrej Zajicek   [PATCH] fbdev dri...
664

ea770789d   David Miller   svga: Make svga_w...
665
  	svga_wcrt_mask(par->state.vgabase, 0x5D, 0x00, 0x28); /* Clear strange HSlen bits */
a268422de   Ondrej Zajicek   [PATCH] fbdev dri...
666

ea770789d   David Miller   svga: Make svga_w...
667
  /*	svga_wcrt_mask(par->state.vgabase, 0x58, 0x03, 0x03); */
a268422de   Ondrej Zajicek   [PATCH] fbdev dri...
668

ea770789d   David Miller   svga: Make svga_w...
669
670
  /*	svga_wcrt_mask(par->state.vgabase, 0x53, 0x12, 0x13); */ /* enable MMIO */
  /*	svga_wcrt_mask(par->state.vgabase, 0x40, 0x08, 0x08); */ /* enable write buffer */
a268422de   Ondrej Zajicek   [PATCH] fbdev dri...
671
672
673
674
675
  
  
  	/* Set the offset register */
  	pr_debug("fb%d: offset register       : %d
  ", info->node, offset_value);
21da386d0   David Miller   svga: Make svga_w...
676
  	svga_wcrt_multi(par->state.vgabase, s3_offset_regs, offset_value);
a268422de   Ondrej Zajicek   [PATCH] fbdev dri...
677

94e948e6e   Ondrej Zary   s3fb: fix Virge/GX2
678
679
680
  	if (par->chip != CHIP_357_VIRGE_GX2 &&
  	    par->chip != CHIP_359_VIRGE_GX2P &&
  	    par->chip != CHIP_360_TRIO3D_1X &&
9966c4fea   Ondrej Zary   add support for S...
681
682
  	    par->chip != CHIP_362_TRIO3D_2X &&
  	    par->chip != CHIP_368_TRIO3D_2X) {
f86459335   David Miller   s3fb: Pass par->s...
683
684
685
686
  		vga_wcrt(par->state.vgabase, 0x54, 0x18); /* M parameter */
  		vga_wcrt(par->state.vgabase, 0x60, 0xff); /* N parameter */
  		vga_wcrt(par->state.vgabase, 0x61, 0xff); /* L parameter */
  		vga_wcrt(par->state.vgabase, 0x62, 0xff); /* L parameter */
9966c4fea   Ondrej Zary   add support for S...
687
  	}
a268422de   Ondrej Zajicek   [PATCH] fbdev dri...
688

f86459335   David Miller   s3fb: Pass par->s...
689
  	vga_wcrt(par->state.vgabase, 0x3A, 0x35);
f6b0cc477   David Miller   svga: Make svga_w...
690
  	svga_wattr(par->state.vgabase, 0x33, 0x00);
a268422de   Ondrej Zajicek   [PATCH] fbdev dri...
691
692
  
  	if (info->var.vmode & FB_VMODE_DOUBLE)
ea770789d   David Miller   svga: Make svga_w...
693
  		svga_wcrt_mask(par->state.vgabase, 0x09, 0x80, 0x80);
a268422de   Ondrej Zajicek   [PATCH] fbdev dri...
694
  	else
ea770789d   David Miller   svga: Make svga_w...
695
  		svga_wcrt_mask(par->state.vgabase, 0x09, 0x00, 0x80);
a268422de   Ondrej Zajicek   [PATCH] fbdev dri...
696
697
  
  	if (info->var.vmode & FB_VMODE_INTERLACED)
ea770789d   David Miller   svga: Make svga_w...
698
  		svga_wcrt_mask(par->state.vgabase, 0x42, 0x20, 0x20);
a268422de   Ondrej Zajicek   [PATCH] fbdev dri...
699
  	else
ea770789d   David Miller   svga: Make svga_w...
700
  		svga_wcrt_mask(par->state.vgabase, 0x42, 0x00, 0x20);
a268422de   Ondrej Zajicek   [PATCH] fbdev dri...
701
702
  
  	/* Disable hardware graphics cursor */
ea770789d   David Miller   svga: Make svga_w...
703
  	svga_wcrt_mask(par->state.vgabase, 0x45, 0x00, 0x01);
a268422de   Ondrej Zajicek   [PATCH] fbdev dri...
704
  	/* Disable Streams engine */
ea770789d   David Miller   svga: Make svga_w...
705
  	svga_wcrt_mask(par->state.vgabase, 0x67, 0x00, 0x0C);
a268422de   Ondrej Zajicek   [PATCH] fbdev dri...
706
707
708
709
710
  
  	mode = svga_match_format(s3fb_formats, &(info->var), &(info->fix));
  
  	/* S3 virge DX hack */
  	if (par->chip == CHIP_375_VIRGE_DX) {
f86459335   David Miller   s3fb: Pass par->s...
711
712
  		vga_wcrt(par->state.vgabase, 0x86, 0x80);
  		vga_wcrt(par->state.vgabase, 0x90, 0x00);
a268422de   Ondrej Zajicek   [PATCH] fbdev dri...
713
714
715
716
  	}
  
  	/* S3 virge VX hack */
  	if (par->chip == CHIP_988_VIRGE_VX) {
f86459335   David Miller   s3fb: Pass par->s...
717
718
  		vga_wcrt(par->state.vgabase, 0x50, 0x00);
  		vga_wcrt(par->state.vgabase, 0x67, 0x50);
66cde97da   Ondrej Zary   s3fb: fix Virge/VX
719
  		msleep(10); /* screen remains blank sometimes without this */
f86459335   David Miller   s3fb: Pass par->s...
720
721
  		vga_wcrt(par->state.vgabase, 0x63, (mode <= 2) ? 0x90 : 0x09);
  		vga_wcrt(par->state.vgabase, 0x66, 0x90);
a268422de   Ondrej Zajicek   [PATCH] fbdev dri...
722
  	}
94e948e6e   Ondrej Zary   s3fb: fix Virge/GX2
723
724
725
  	if (par->chip == CHIP_357_VIRGE_GX2 ||
  	    par->chip == CHIP_359_VIRGE_GX2P ||
  	    par->chip == CHIP_360_TRIO3D_1X ||
9966c4fea   Ondrej Zary   add support for S...
726
  	    par->chip == CHIP_362_TRIO3D_2X ||
5694f9ce5   Ondrej Zary   s3fb: add support...
727
  	    par->chip == CHIP_368_TRIO3D_2X ||
cb11c0489   Ondrej Zary   s3fb: enable DTPC
728
729
730
  	    par->chip == CHIP_365_TRIO3D    ||
  	    par->chip == CHIP_375_VIRGE_DX  ||
  	    par->chip == CHIP_385_VIRGE_GX) {
9966c4fea   Ondrej Zary   add support for S...
731
  		dbytes = info->var.xres * ((bpp+7)/8);
f86459335   David Miller   s3fb: Pass par->s...
732
733
  		vga_wcrt(par->state.vgabase, 0x91, (dbytes + 7) / 8);
  		vga_wcrt(par->state.vgabase, 0x90, (((dbytes + 7) / 8) >> 8) | 0x80);
9966c4fea   Ondrej Zary   add support for S...
734

f86459335   David Miller   s3fb: Pass par->s...
735
  		vga_wcrt(par->state.vgabase, 0x66, 0x81);
9966c4fea   Ondrej Zary   add support for S...
736
  	}
94e948e6e   Ondrej Zary   s3fb: fix Virge/GX2
737
  	if (par->chip == CHIP_357_VIRGE_GX2  ||
cb11c0489   Ondrej Zary   s3fb: enable DTPC
738
739
740
741
742
743
744
  	    par->chip == CHIP_359_VIRGE_GX2P ||
  	    par->chip == CHIP_360_TRIO3D_1X ||
  	    par->chip == CHIP_362_TRIO3D_2X ||
  	    par->chip == CHIP_368_TRIO3D_2X)
  		vga_wcrt(par->state.vgabase, 0x34, 0x00);
  	else	/* enable Data Transfer Position Control (DTPC) */
  		vga_wcrt(par->state.vgabase, 0x34, 0x10);
ea770789d   David Miller   svga: Make svga_w...
745
  	svga_wcrt_mask(par->state.vgabase, 0x31, 0x00, 0x40);
a268422de   Ondrej Zajicek   [PATCH] fbdev dri...
746
747
748
749
750
751
752
753
  	multiplex = 0;
  	hmul = 1;
  
  	/* Set mode-specific register values */
  	switch (mode) {
  	case 0:
  		pr_debug("fb%d: text mode
  ", info->node);
9c96394bb   David Miller   svga: Make svga_s...
754
  		svga_set_textmode_vga_regs(par->state.vgabase);
a268422de   Ondrej Zajicek   [PATCH] fbdev dri...
755
756
  
  		/* Set additional registers like in 8-bit mode */
ea770789d   David Miller   svga: Make svga_w...
757
758
  		svga_wcrt_mask(par->state.vgabase, 0x50, 0x00, 0x30);
  		svga_wcrt_mask(par->state.vgabase, 0x67, 0x00, 0xF0);
a268422de   Ondrej Zajicek   [PATCH] fbdev dri...
759
760
  
  		/* Disable enhanced mode */
ea770789d   David Miller   svga: Make svga_w...
761
  		svga_wcrt_mask(par->state.vgabase, 0x3A, 0x00, 0x30);
a268422de   Ondrej Zajicek   [PATCH] fbdev dri...
762
763
764
765
  
  		if (fasttext) {
  			pr_debug("fb%d: high speed text mode set
  ", info->node);
ea770789d   David Miller   svga: Make svga_w...
766
  			svga_wcrt_mask(par->state.vgabase, 0x31, 0x40, 0x40);
a268422de   Ondrej Zajicek   [PATCH] fbdev dri...
767
768
769
770
771
  		}
  		break;
  	case 1:
  		pr_debug("fb%d: 4 bit pseudocolor
  ", info->node);
f86459335   David Miller   s3fb: Pass par->s...
772
  		vga_wgfx(par->state.vgabase, VGA_GFX_MODE, 0x40);
a268422de   Ondrej Zajicek   [PATCH] fbdev dri...
773
774
  
  		/* Set additional registers like in 8-bit mode */
ea770789d   David Miller   svga: Make svga_w...
775
776
  		svga_wcrt_mask(par->state.vgabase, 0x50, 0x00, 0x30);
  		svga_wcrt_mask(par->state.vgabase, 0x67, 0x00, 0xF0);
a268422de   Ondrej Zajicek   [PATCH] fbdev dri...
777
778
  
  		/* disable enhanced mode */
ea770789d   David Miller   svga: Make svga_w...
779
  		svga_wcrt_mask(par->state.vgabase, 0x3A, 0x00, 0x30);
a268422de   Ondrej Zajicek   [PATCH] fbdev dri...
780
781
782
783
784
785
  		break;
  	case 2:
  		pr_debug("fb%d: 4 bit pseudocolor, planar
  ", info->node);
  
  		/* Set additional registers like in 8-bit mode */
ea770789d   David Miller   svga: Make svga_w...
786
787
  		svga_wcrt_mask(par->state.vgabase, 0x50, 0x00, 0x30);
  		svga_wcrt_mask(par->state.vgabase, 0x67, 0x00, 0xF0);
a268422de   Ondrej Zajicek   [PATCH] fbdev dri...
788
789
  
  		/* disable enhanced mode */
ea770789d   David Miller   svga: Make svga_w...
790
  		svga_wcrt_mask(par->state.vgabase, 0x3A, 0x00, 0x30);
a268422de   Ondrej Zajicek   [PATCH] fbdev dri...
791
792
793
794
  		break;
  	case 3:
  		pr_debug("fb%d: 8 bit pseudocolor
  ", info->node);
ea770789d   David Miller   svga: Make svga_w...
795
  		svga_wcrt_mask(par->state.vgabase, 0x50, 0x00, 0x30);
9966c4fea   Ondrej Zary   add support for S...
796
  		if (info->var.pixclock > 20000 ||
94e948e6e   Ondrej Zary   s3fb: fix Virge/GX2
797
798
  		    par->chip == CHIP_357_VIRGE_GX2 ||
  		    par->chip == CHIP_359_VIRGE_GX2P ||
9966c4fea   Ondrej Zary   add support for S...
799
800
801
  		    par->chip == CHIP_360_TRIO3D_1X ||
  		    par->chip == CHIP_362_TRIO3D_2X ||
  		    par->chip == CHIP_368_TRIO3D_2X)
ea770789d   David Miller   svga: Make svga_w...
802
  			svga_wcrt_mask(par->state.vgabase, 0x67, 0x00, 0xF0);
9966c4fea   Ondrej Zary   add support for S...
803
  		else {
ea770789d   David Miller   svga: Make svga_w...
804
  			svga_wcrt_mask(par->state.vgabase, 0x67, 0x10, 0xF0);
a268422de   Ondrej Zajicek   [PATCH] fbdev dri...
805
806
807
808
809
810
811
812
  			multiplex = 1;
  		}
  		break;
  	case 4:
  		pr_debug("fb%d: 5/5/5 truecolor
  ", info->node);
  		if (par->chip == CHIP_988_VIRGE_VX) {
  			if (info->var.pixclock > 20000)
ea770789d   David Miller   svga: Make svga_w...
813
  				svga_wcrt_mask(par->state.vgabase, 0x67, 0x20, 0xF0);
a268422de   Ondrej Zajicek   [PATCH] fbdev dri...
814
  			else
ea770789d   David Miller   svga: Make svga_w...
815
  				svga_wcrt_mask(par->state.vgabase, 0x67, 0x30, 0xF0);
3827d10ed   Ondrej Zary   s3fb: fix 15/16bp...
816
817
818
819
820
821
822
823
824
  		} else if (par->chip == CHIP_365_TRIO3D) {
  			svga_wcrt_mask(par->state.vgabase, 0x50, 0x10, 0x30);
  			if (info->var.pixclock > 8695) {
  				svga_wcrt_mask(par->state.vgabase, 0x67, 0x30, 0xF0);
  				hmul = 2;
  			} else {
  				svga_wcrt_mask(par->state.vgabase, 0x67, 0x20, 0xF0);
  				multiplex = 1;
  			}
a268422de   Ondrej Zajicek   [PATCH] fbdev dri...
825
  		} else {
ea770789d   David Miller   svga: Make svga_w...
826
827
  			svga_wcrt_mask(par->state.vgabase, 0x50, 0x10, 0x30);
  			svga_wcrt_mask(par->state.vgabase, 0x67, 0x30, 0xF0);
94e948e6e   Ondrej Zary   s3fb: fix Virge/GX2
828
829
830
  			if (par->chip != CHIP_357_VIRGE_GX2 &&
  			    par->chip != CHIP_359_VIRGE_GX2P &&
  			    par->chip != CHIP_360_TRIO3D_1X &&
9966c4fea   Ondrej Zary   add support for S...
831
832
833
  			    par->chip != CHIP_362_TRIO3D_2X &&
  			    par->chip != CHIP_368_TRIO3D_2X)
  				hmul = 2;
a268422de   Ondrej Zajicek   [PATCH] fbdev dri...
834
835
836
837
838
839
840
  		}
  		break;
  	case 5:
  		pr_debug("fb%d: 5/6/5 truecolor
  ", info->node);
  		if (par->chip == CHIP_988_VIRGE_VX) {
  			if (info->var.pixclock > 20000)
ea770789d   David Miller   svga: Make svga_w...
841
  				svga_wcrt_mask(par->state.vgabase, 0x67, 0x40, 0xF0);
a268422de   Ondrej Zajicek   [PATCH] fbdev dri...
842
  			else
ea770789d   David Miller   svga: Make svga_w...
843
  				svga_wcrt_mask(par->state.vgabase, 0x67, 0x50, 0xF0);
3827d10ed   Ondrej Zary   s3fb: fix 15/16bp...
844
845
846
847
848
849
850
851
852
  		} else if (par->chip == CHIP_365_TRIO3D) {
  			svga_wcrt_mask(par->state.vgabase, 0x50, 0x10, 0x30);
  			if (info->var.pixclock > 8695) {
  				svga_wcrt_mask(par->state.vgabase, 0x67, 0x50, 0xF0);
  				hmul = 2;
  			} else {
  				svga_wcrt_mask(par->state.vgabase, 0x67, 0x40, 0xF0);
  				multiplex = 1;
  			}
a268422de   Ondrej Zajicek   [PATCH] fbdev dri...
853
  		} else {
ea770789d   David Miller   svga: Make svga_w...
854
855
  			svga_wcrt_mask(par->state.vgabase, 0x50, 0x10, 0x30);
  			svga_wcrt_mask(par->state.vgabase, 0x67, 0x50, 0xF0);
94e948e6e   Ondrej Zary   s3fb: fix Virge/GX2
856
857
858
  			if (par->chip != CHIP_357_VIRGE_GX2 &&
  			    par->chip != CHIP_359_VIRGE_GX2P &&
  			    par->chip != CHIP_360_TRIO3D_1X &&
9966c4fea   Ondrej Zary   add support for S...
859
860
861
  			    par->chip != CHIP_362_TRIO3D_2X &&
  			    par->chip != CHIP_368_TRIO3D_2X)
  				hmul = 2;
a268422de   Ondrej Zajicek   [PATCH] fbdev dri...
862
863
864
865
866
867
  		}
  		break;
  	case 6:
  		/* VIRGE VX case */
  		pr_debug("fb%d: 8/8/8 truecolor
  ", info->node);
ea770789d   David Miller   svga: Make svga_w...
868
  		svga_wcrt_mask(par->state.vgabase, 0x67, 0xD0, 0xF0);
a268422de   Ondrej Zajicek   [PATCH] fbdev dri...
869
870
871
872
  		break;
  	case 7:
  		pr_debug("fb%d: 8/8/8/8 truecolor
  ", info->node);
ea770789d   David Miller   svga: Make svga_w...
873
874
  		svga_wcrt_mask(par->state.vgabase, 0x50, 0x30, 0x30);
  		svga_wcrt_mask(par->state.vgabase, 0x67, 0xD0, 0xF0);
a268422de   Ondrej Zajicek   [PATCH] fbdev dri...
875
876
877
878
879
880
881
882
  		break;
  	default:
  		printk(KERN_ERR "fb%d: unsupported mode - bug
  ", info->node);
  		return -EINVAL;
  	}
  
  	if (par->chip != CHIP_988_VIRGE_VX) {
d907ec04c   David Miller   svga: Make svga_w...
883
884
  		svga_wseq_mask(par->state.vgabase, 0x15, multiplex ? 0x10 : 0x00, 0x10);
  		svga_wseq_mask(par->state.vgabase, 0x18, multiplex ? 0x80 : 0x00, 0x80);
a268422de   Ondrej Zajicek   [PATCH] fbdev dri...
885
886
887
  	}
  
  	s3_set_pixclock(info, info->var.pixclock);
38d2620ea   David Miller   svga: Make svga_s...
888
  	svga_set_timings(par->state.vgabase, &s3_timing_regs, &(info->var), hmul, 1,
a268422de   Ondrej Zajicek   [PATCH] fbdev dri...
889
890
891
892
893
  			 (info->var.vmode & FB_VMODE_DOUBLE)     ? 2 : 1,
  			 (info->var.vmode & FB_VMODE_INTERLACED) ? 2 : 1,
  			 hmul, info->node);
  
  	/* Set interlaced mode start/end register */
cb11c0489   Ondrej Zary   s3fb: enable DTPC
894
895
896
897
898
899
  	htotal = info->var.xres + info->var.left_margin + info->var.right_margin + info->var.hsync_len;
  	htotal = ((htotal * hmul) / 8) - 5;
  	vga_wcrt(par->state.vgabase, 0x3C, (htotal + 1) / 2);
  
  	/* Set Data Transfer Position */
  	hsstart = ((info->var.xres + info->var.right_margin) * hmul) / 8;
66cde97da   Ondrej Zary   s3fb: fix Virge/VX
900
901
  	/* + 2 is needed for Virge/VX, does no harm on other cards */
  	value = clamp((htotal + hsstart + 1) / 2 + 2, hsstart + 4, htotal + 1);
cb11c0489   Ondrej Zary   s3fb: enable DTPC
902
  	svga_wcrt_multi(par->state.vgabase, s3_dtpc_regs, value);
a268422de   Ondrej Zajicek   [PATCH] fbdev dri...
903

75814d87a   Antonino A. Daplas   s3fb: add sparse ...
904
  	memset_io(info->screen_base, 0x00, screen_size);
a268422de   Ondrej Zajicek   [PATCH] fbdev dri...
905
  	/* Device and screen back on */
ea770789d   David Miller   svga: Make svga_w...
906
  	svga_wcrt_mask(par->state.vgabase, 0x17, 0x80, 0x80);
d907ec04c   David Miller   svga: Make svga_w...
907
  	svga_wseq_mask(par->state.vgabase, 0x01, 0x00, 0x20);
a268422de   Ondrej Zajicek   [PATCH] fbdev dri...
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
  
  	return 0;
  }
  
  /* Set a colour register */
  
  static int s3fb_setcolreg(u_int regno, u_int red, u_int green, u_int blue,
  				u_int transp, struct fb_info *fb)
  {
  	switch (fb->var.bits_per_pixel) {
  	case 0:
  	case 4:
  		if (regno >= 16)
  			return -EINVAL;
  
  		if ((fb->var.bits_per_pixel == 4) &&
  		    (fb->var.nonstd == 0)) {
  			outb(0xF0, VGA_PEL_MSK);
  			outb(regno*16, VGA_PEL_IW);
  		} else {
  			outb(0x0F, VGA_PEL_MSK);
  			outb(regno, VGA_PEL_IW);
  		}
  		outb(red >> 10, VGA_PEL_D);
  		outb(green >> 10, VGA_PEL_D);
  		outb(blue >> 10, VGA_PEL_D);
  		break;
  	case 8:
  		if (regno >= 256)
  			return -EINVAL;
  
  		outb(0xFF, VGA_PEL_MSK);
  		outb(regno, VGA_PEL_IW);
  		outb(red >> 10, VGA_PEL_D);
  		outb(green >> 10, VGA_PEL_D);
  		outb(blue >> 10, VGA_PEL_D);
  		break;
  	case 16:
  		if (regno >= 16)
249bdbbf0   Ondrej Zajicek   s3fb: driver fixes
947
  			return 0;
a268422de   Ondrej Zajicek   [PATCH] fbdev dri...
948
949
950
951
952
953
954
955
956
957
958
959
  
  		if (fb->var.green.length == 5)
  			((u32*)fb->pseudo_palette)[regno] = ((red & 0xF800) >> 1) |
  				((green & 0xF800) >> 6) | ((blue & 0xF800) >> 11);
  		else if (fb->var.green.length == 6)
  			((u32*)fb->pseudo_palette)[regno] = (red & 0xF800) |
  				((green & 0xFC00) >> 5) | ((blue & 0xF800) >> 11);
  		else return -EINVAL;
  		break;
  	case 24:
  	case 32:
  		if (regno >= 16)
249bdbbf0   Ondrej Zajicek   s3fb: driver fixes
960
  			return 0;
a268422de   Ondrej Zajicek   [PATCH] fbdev dri...
961

249bdbbf0   Ondrej Zajicek   s3fb: driver fixes
962
  		((u32*)fb->pseudo_palette)[regno] = ((red & 0xFF00) << 8) |
a268422de   Ondrej Zajicek   [PATCH] fbdev dri...
963
964
965
966
967
968
969
970
971
972
973
974
975
976
  			(green & 0xFF00) | ((blue & 0xFF00) >> 8);
  		break;
  	default:
  		return -EINVAL;
  	}
  
  	return 0;
  }
  
  
  /* Set the display blanking state */
  
  static int s3fb_blank(int blank_mode, struct fb_info *info)
  {
d907ec04c   David Miller   svga: Make svga_w...
977
  	struct s3fb_info *par = info->par;
a268422de   Ondrej Zajicek   [PATCH] fbdev dri...
978
979
980
981
  	switch (blank_mode) {
  	case FB_BLANK_UNBLANK:
  		pr_debug("fb%d: unblank
  ", info->node);
ea770789d   David Miller   svga: Make svga_w...
982
  		svga_wcrt_mask(par->state.vgabase, 0x56, 0x00, 0x06);
d907ec04c   David Miller   svga: Make svga_w...
983
  		svga_wseq_mask(par->state.vgabase, 0x01, 0x00, 0x20);
a268422de   Ondrej Zajicek   [PATCH] fbdev dri...
984
985
986
987
  		break;
  	case FB_BLANK_NORMAL:
  		pr_debug("fb%d: blank
  ", info->node);
ea770789d   David Miller   svga: Make svga_w...
988
  		svga_wcrt_mask(par->state.vgabase, 0x56, 0x00, 0x06);
d907ec04c   David Miller   svga: Make svga_w...
989
  		svga_wseq_mask(par->state.vgabase, 0x01, 0x20, 0x20);
a268422de   Ondrej Zajicek   [PATCH] fbdev dri...
990
991
992
993
  		break;
  	case FB_BLANK_HSYNC_SUSPEND:
  		pr_debug("fb%d: hsync
  ", info->node);
ea770789d   David Miller   svga: Make svga_w...
994
  		svga_wcrt_mask(par->state.vgabase, 0x56, 0x02, 0x06);
d907ec04c   David Miller   svga: Make svga_w...
995
  		svga_wseq_mask(par->state.vgabase, 0x01, 0x20, 0x20);
a268422de   Ondrej Zajicek   [PATCH] fbdev dri...
996
997
998
999
  		break;
  	case FB_BLANK_VSYNC_SUSPEND:
  		pr_debug("fb%d: vsync
  ", info->node);
ea770789d   David Miller   svga: Make svga_w...
1000
  		svga_wcrt_mask(par->state.vgabase, 0x56, 0x04, 0x06);
d907ec04c   David Miller   svga: Make svga_w...
1001
  		svga_wseq_mask(par->state.vgabase, 0x01, 0x20, 0x20);
a268422de   Ondrej Zajicek   [PATCH] fbdev dri...
1002
1003
1004
1005
  		break;
  	case FB_BLANK_POWERDOWN:
  		pr_debug("fb%d: sync down
  ", info->node);
ea770789d   David Miller   svga: Make svga_w...
1006
  		svga_wcrt_mask(par->state.vgabase, 0x56, 0x06, 0x06);
d907ec04c   David Miller   svga: Make svga_w...
1007
  		svga_wseq_mask(par->state.vgabase, 0x01, 0x20, 0x20);
a268422de   Ondrej Zajicek   [PATCH] fbdev dri...
1008
1009
1010
1011
1012
1013
1014
1015
  		break;
  	}
  
  	return 0;
  }
  
  
  /* Pan the display */
21da386d0   David Miller   svga: Make svga_w...
1016
1017
1018
  static int s3fb_pan_display(struct fb_var_screeninfo *var, struct fb_info *info)
  {
  	struct s3fb_info *par = info->par;
a268422de   Ondrej Zajicek   [PATCH] fbdev dri...
1019
  	unsigned int offset;
a268422de   Ondrej Zajicek   [PATCH] fbdev dri...
1020
  	/* Calculate the offset */
a4aadc931   Laurent Pinchart   s3fb: use display...
1021
1022
1023
  	if (info->var.bits_per_pixel == 0) {
  		offset = (var->yoffset / 16) * (info->var.xres_virtual / 2)
  		       + (var->xoffset / 2);
a268422de   Ondrej Zajicek   [PATCH] fbdev dri...
1024
1025
1026
  		offset = offset >> 2;
  	} else {
  		offset = (var->yoffset * info->fix.line_length) +
a4aadc931   Laurent Pinchart   s3fb: use display...
1027
  			 (var->xoffset * info->var.bits_per_pixel / 8);
a268422de   Ondrej Zajicek   [PATCH] fbdev dri...
1028
1029
1030
1031
  		offset = offset >> 2;
  	}
  
  	/* Set the offset */
21da386d0   David Miller   svga: Make svga_w...
1032
  	svga_wcrt_multi(par->state.vgabase, s3_start_address_regs, offset);
a268422de   Ondrej Zajicek   [PATCH] fbdev dri...
1033
1034
1035
1036
1037
1038
1039
1040
1041
1042
1043
1044
1045
1046
1047
1048
1049
1050
1051
1052
  
  	return 0;
  }
  
  /* ------------------------------------------------------------------------- */
  
  /* Frame buffer operations */
  
  static struct fb_ops s3fb_ops = {
  	.owner		= THIS_MODULE,
  	.fb_open	= s3fb_open,
  	.fb_release	= s3fb_release,
  	.fb_check_var	= s3fb_check_var,
  	.fb_set_par	= s3fb_set_par,
  	.fb_setcolreg	= s3fb_setcolreg,
  	.fb_blank	= s3fb_blank,
  	.fb_pan_display	= s3fb_pan_display,
  	.fb_fillrect	= s3fb_fillrect,
  	.fb_copyarea	= cfb_copyarea,
  	.fb_imageblit	= s3fb_imageblit,
5a87ede94   Antonino A. Daplas   svgalib: move fb_...
1053
  	.fb_get_caps    = svga_get_caps,
a268422de   Ondrej Zajicek   [PATCH] fbdev dri...
1054
1055
1056
  };
  
  /* ------------------------------------------------------------------------- */
f86459335   David Miller   s3fb: Pass par->s...
1057
  static int __devinit s3_identification(struct s3fb_info *par)
a268422de   Ondrej Zajicek   [PATCH] fbdev dri...
1058
  {
f86459335   David Miller   s3fb: Pass par->s...
1059
  	int chip = par->chip;
a268422de   Ondrej Zajicek   [PATCH] fbdev dri...
1060
  	if (chip == CHIP_XXX_TRIO) {
f86459335   David Miller   s3fb: Pass par->s...
1061
1062
1063
  		u8 cr30 = vga_rcrt(par->state.vgabase, 0x30);
  		u8 cr2e = vga_rcrt(par->state.vgabase, 0x2e);
  		u8 cr2f = vga_rcrt(par->state.vgabase, 0x2f);
a268422de   Ondrej Zajicek   [PATCH] fbdev dri...
1064
1065
1066
1067
1068
1069
1070
1071
1072
1073
1074
1075
1076
1077
  
  		if ((cr30 == 0xE0) || (cr30 == 0xE1)) {
  			if (cr2e == 0x10)
  				return CHIP_732_TRIO32;
  			if (cr2e == 0x11) {
  				if (! (cr2f & 0x40))
  					return CHIP_764_TRIO64;
  				else
  					return CHIP_765_TRIO64VP;
  			}
  		}
  	}
  
  	if (chip == CHIP_XXX_TRIO64V2_DXGX) {
f86459335   David Miller   s3fb: Pass par->s...
1078
  		u8 cr6f = vga_rcrt(par->state.vgabase, 0x6f);
a268422de   Ondrej Zajicek   [PATCH] fbdev dri...
1079
1080
1081
1082
1083
1084
1085
1086
  
  		if (! (cr6f & 0x01))
  			return CHIP_775_TRIO64V2_DX;
  		else
  			return CHIP_785_TRIO64V2_GX;
  	}
  
  	if (chip == CHIP_XXX_VIRGE_DXGX) {
f86459335   David Miller   s3fb: Pass par->s...
1087
  		u8 cr6f = vga_rcrt(par->state.vgabase, 0x6f);
a268422de   Ondrej Zajicek   [PATCH] fbdev dri...
1088
1089
1090
1091
1092
1093
  
  		if (! (cr6f & 0x01))
  			return CHIP_375_VIRGE_DX;
  		else
  			return CHIP_385_VIRGE_GX;
  	}
9966c4fea   Ondrej Zary   add support for S...
1094
  	if (chip == CHIP_36X_TRIO3D_1X_2X) {
f86459335   David Miller   s3fb: Pass par->s...
1095
  		switch (vga_rcrt(par->state.vgabase, 0x2f)) {
9966c4fea   Ondrej Zary   add support for S...
1096
1097
1098
1099
1100
1101
1102
1103
  		case 0x00:
  			return CHIP_360_TRIO3D_1X;
  		case 0x01:
  			return CHIP_362_TRIO3D_2X;
  		case 0x02:
  			return CHIP_368_TRIO3D_2X;
  		}
  	}
a268422de   Ondrej Zajicek   [PATCH] fbdev dri...
1104
1105
1106
1107
1108
1109
1110
1111
  	return CHIP_UNKNOWN;
  }
  
  
  /* PCI probe */
  
  static int __devinit s3_pci_probe(struct pci_dev *dev, const struct pci_device_id *id)
  {
94c322c30   David Miller   s3fb: Compute VGA...
1112
1113
  	struct pci_bus_region bus_reg;
  	struct resource vga_res;
a268422de   Ondrej Zajicek   [PATCH] fbdev dri...
1114
1115
1116
1117
  	struct fb_info *info;
  	struct s3fb_info *par;
  	int rc;
  	u8 regval, cr38, cr39;
86c0f043a   Ondrej Zary   s3fb: add DDC sup...
1118
  	bool found = false;
a268422de   Ondrej Zajicek   [PATCH] fbdev dri...
1119
1120
1121
1122
1123
1124
1125
1126
1127
  
  	/* Ignore secondary VGA device because there is no VGA arbitration */
  	if (! svga_primary_device(dev)) {
  		dev_info(&(dev->dev), "ignoring secondary device
  ");
  		return -ENODEV;
  	}
  
  	/* Allocate and fill driver data structure */
20e061fb7   Ondrej Zajicek   fbdev: framebuffe...
1128
  	info = framebuffer_alloc(sizeof(struct s3fb_info), &(dev->dev));
a268422de   Ondrej Zajicek   [PATCH] fbdev dri...
1129
1130
1131
1132
1133
1134
1135
1136
1137
1138
1139
1140
1141
1142
1143
  	if (!info) {
  		dev_err(&(dev->dev), "cannot allocate memory
  ");
  		return -ENOMEM;
  	}
  
  	par = info->par;
  	mutex_init(&par->open_lock);
  
  	info->flags = FBINFO_PARTIAL_PAN_OK | FBINFO_HWACCEL_YPAN;
  	info->fbops = &s3fb_ops;
  
  	/* Prepare PCI device */
  	rc = pci_enable_device(dev);
  	if (rc < 0) {
594a88197   Ondrej Zajicek   vt8623fb: fix ker...
1144
1145
  		dev_err(info->device, "cannot enable PCI device
  ");
a268422de   Ondrej Zajicek   [PATCH] fbdev dri...
1146
1147
1148
1149
1150
  		goto err_enable_device;
  	}
  
  	rc = pci_request_regions(dev, "s3fb");
  	if (rc < 0) {
594a88197   Ondrej Zajicek   vt8623fb: fix ker...
1151
1152
  		dev_err(info->device, "cannot reserve framebuffer region
  ");
a268422de   Ondrej Zajicek   [PATCH] fbdev dri...
1153
1154
1155
1156
1157
1158
1159
1160
1161
1162
1163
  		goto err_request_regions;
  	}
  
  
  	info->fix.smem_start = pci_resource_start(dev, 0);
  	info->fix.smem_len = pci_resource_len(dev, 0);
  
  	/* Map physical IO memory address into kernel space */
  	info->screen_base = pci_iomap(dev, 0, 0);
  	if (! info->screen_base) {
  		rc = -ENOMEM;
594a88197   Ondrej Zajicek   vt8623fb: fix ker...
1164
1165
  		dev_err(info->device, "iomap for framebuffer failed
  ");
a268422de   Ondrej Zajicek   [PATCH] fbdev dri...
1166
1167
  		goto err_iomap;
  	}
94c322c30   David Miller   s3fb: Compute VGA...
1168
1169
1170
1171
1172
1173
1174
1175
  	bus_reg.start = 0;
  	bus_reg.end = 64 * 1024;
  
  	vga_res.flags = IORESOURCE_IO;
  
  	pcibios_bus_to_resource(dev, &vga_res, &bus_reg);
  
  	par->state.vgabase = (void __iomem *) vga_res.start;
a268422de   Ondrej Zajicek   [PATCH] fbdev dri...
1176
  	/* Unlock regs */
f86459335   David Miller   s3fb: Pass par->s...
1177
1178
1179
1180
1181
  	cr38 = vga_rcrt(par->state.vgabase, 0x38);
  	cr39 = vga_rcrt(par->state.vgabase, 0x39);
  	vga_wseq(par->state.vgabase, 0x08, 0x06);
  	vga_wcrt(par->state.vgabase, 0x38, 0x48);
  	vga_wcrt(par->state.vgabase, 0x39, 0xA5);
a268422de   Ondrej Zajicek   [PATCH] fbdev dri...
1182

9966c4fea   Ondrej Zary   add support for S...
1183
  	/* Identify chip type */
a268422de   Ondrej Zajicek   [PATCH] fbdev dri...
1184
  	par->chip = id->driver_data & CHIP_MASK;
f86459335   David Miller   s3fb: Pass par->s...
1185
  	par->rev = vga_rcrt(par->state.vgabase, 0x2f);
a268422de   Ondrej Zajicek   [PATCH] fbdev dri...
1186
  	if (par->chip & CHIP_UNDECIDED_FLAG)
f86459335   David Miller   s3fb: Pass par->s...
1187
  		par->chip = s3_identification(par);
a268422de   Ondrej Zajicek   [PATCH] fbdev dri...
1188

9966c4fea   Ondrej Zary   add support for S...
1189
1190
  	/* Find how many physical memory there is on card */
  	/* 0x36 register is accessible even if other registers are locked */
f86459335   David Miller   s3fb: Pass par->s...
1191
  	regval = vga_rcrt(par->state.vgabase, 0x36);
9966c4fea   Ondrej Zary   add support for S...
1192
1193
  	if (par->chip == CHIP_360_TRIO3D_1X ||
  	    par->chip == CHIP_362_TRIO3D_2X ||
5694f9ce5   Ondrej Zary   s3fb: add support...
1194
1195
  	    par->chip == CHIP_368_TRIO3D_2X ||
  	    par->chip == CHIP_365_TRIO3D) {
9966c4fea   Ondrej Zary   add support for S...
1196
1197
1198
1199
1200
1201
  		switch ((regval & 0xE0) >> 5) {
  		case 0: /* 8MB -- only 4MB usable for display */
  		case 1: /* 4MB with 32-bit bus */
  		case 2:	/* 4MB */
  			info->screen_size = 4 << 20;
  			break;
5694f9ce5   Ondrej Zary   s3fb: add support...
1202
  		case 4: /* 2MB on 365 Trio3D */
9966c4fea   Ondrej Zary   add support for S...
1203
1204
1205
1206
  		case 6: /* 2MB */
  			info->screen_size = 2 << 20;
  			break;
  		}
94e948e6e   Ondrej Zary   s3fb: fix Virge/GX2
1207
1208
1209
1210
1211
1212
1213
1214
1215
1216
  	} else if (par->chip == CHIP_357_VIRGE_GX2 ||
  		   par->chip == CHIP_359_VIRGE_GX2P) {
  		switch ((regval & 0xC0) >> 6) {
  		case 1: /* 4MB */
  			info->screen_size = 4 << 20;
  			break;
  		case 3: /* 2MB */
  			info->screen_size = 2 << 20;
  			break;
  		}
66cde97da   Ondrej Zary   s3fb: fix Virge/VX
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
  	} else if (par->chip == CHIP_988_VIRGE_VX) {
  		switch ((regval & 0x60) >> 5) {
  		case 0: /* 2MB */
  			info->screen_size = 2 << 20;
  			break;
  		case 1: /* 4MB */
  			info->screen_size = 4 << 20;
  			break;
  		case 2: /* 6MB */
  			info->screen_size = 6 << 20;
  			break;
  		case 3: /* 8MB */
  			info->screen_size = 8 << 20;
  			break;
  		}
  		/* off-screen memory */
  		regval = vga_rcrt(par->state.vgabase, 0x37);
  		switch ((regval & 0x60) >> 5) {
  		case 1: /* 4MB */
  			info->screen_size -= 4 << 20;
  			break;
  		case 2: /* 2MB */
  			info->screen_size -= 2 << 20;
  			break;
  		}
9966c4fea   Ondrej Zary   add support for S...
1242
1243
1244
  	} else
  		info->screen_size = s3_memsizes[regval >> 5] << 10;
  	info->fix.smem_len = info->screen_size;
a268422de   Ondrej Zajicek   [PATCH] fbdev dri...
1245
  	/* Find MCLK frequency */
f86459335   David Miller   s3fb: Pass par->s...
1246
1247
  	regval = vga_rseq(par->state.vgabase, 0x10);
  	par->mclk_freq = ((vga_rseq(par->state.vgabase, 0x11) + 2) * 14318) / ((regval & 0x1F)  + 2);
a268422de   Ondrej Zajicek   [PATCH] fbdev dri...
1248
1249
1250
  	par->mclk_freq = par->mclk_freq >> (regval >> 5);
  
  	/* Restore locks */
f86459335   David Miller   s3fb: Pass par->s...
1251
1252
  	vga_wcrt(par->state.vgabase, 0x38, cr38);
  	vga_wcrt(par->state.vgabase, 0x39, cr39);
a268422de   Ondrej Zajicek   [PATCH] fbdev dri...
1253
1254
1255
1256
1257
1258
1259
1260
1261
  
  	strcpy(info->fix.id, s3_names [par->chip]);
  	info->fix.mmio_start = 0;
  	info->fix.mmio_len = 0;
  	info->fix.type = FB_TYPE_PACKED_PIXELS;
  	info->fix.visual = FB_VISUAL_PSEUDOCOLOR;
  	info->fix.ypanstep = 0;
  	info->fix.accel = FB_ACCEL_NONE;
  	info->pseudo_palette = (void*) (par->pseudo_palette);
86c0f043a   Ondrej Zary   s3fb: add DDC sup...
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
1290
1291
1292
1293
1294
1295
1296
1297
1298
1299
1300
1301
1302
  	info->var.bits_per_pixel = 8;
  
  #ifdef CONFIG_FB_S3_DDC
  	/* Enable MMIO if needed */
  	if (s3fb_ddc_needs_mmio(par->chip)) {
  		par->mmio = ioremap(info->fix.smem_start + MMIO_OFFSET, MMIO_SIZE);
  		if (par->mmio)
  			svga_wcrt_mask(par->state.vgabase, 0x53, 0x08, 0x08);	/* enable MMIO */
  		else
  			dev_err(info->device, "unable to map MMIO at 0x%lx, disabling DDC",
  				info->fix.smem_start + MMIO_OFFSET);
  	}
  	if (!s3fb_ddc_needs_mmio(par->chip) || par->mmio)
  		if (s3fb_setup_ddc_bus(info) == 0) {
  			u8 *edid = fb_ddc_read(&par->ddc_adapter);
  			par->ddc_registered = true;
  			if (edid) {
  				fb_edid_to_monspecs(edid, &info->monspecs);
  				kfree(edid);
  				if (!info->monspecs.modedb)
  					dev_err(info->device, "error getting mode database
  ");
  				else {
  					const struct fb_videomode *m;
  
  					fb_videomode_to_modelist(info->monspecs.modedb,
  								 info->monspecs.modedb_len,
  								 &info->modelist);
  					m = fb_find_best_display(&info->monspecs, &info->modelist);
  					if (m) {
  						fb_videomode_to_var(&info->var, m);
  						/* fill all other info->var's fields */
  						if (s3fb_check_var(&info->var, info) == 0)
  							found = true;
  					}
  				}
  			}
  		}
  #endif
  	if (!mode_option && !found)
  		mode_option = "640x480-8@60";
a268422de   Ondrej Zajicek   [PATCH] fbdev dri...
1303
1304
  
  	/* Prepare startup mode */
86c0f043a   Ondrej Zary   s3fb: add DDC sup...
1305
1306
1307
1308
1309
1310
1311
1312
1313
1314
1315
1316
1317
1318
1319
1320
1321
1322
1323
1324
1325
1326
1327
  	if (mode_option) {
  		rc = fb_find_mode(&info->var, info, mode_option,
  				   info->monspecs.modedb, info->monspecs.modedb_len,
  				   NULL, info->var.bits_per_pixel);
  		if (!rc || rc == 4) {
  			rc = -EINVAL;
  			dev_err(info->device, "mode %s not found
  ", mode_option);
  			fb_destroy_modedb(info->monspecs.modedb);
  			info->monspecs.modedb = NULL;
  			goto err_find_mode;
  		}
  	}
  
  	fb_destroy_modedb(info->monspecs.modedb);
  	info->monspecs.modedb = NULL;
  
  	/* maximize virtual vertical size for fast scrolling */
  	info->var.yres_virtual = info->fix.smem_len * 8 /
  			(info->var.bits_per_pixel * info->var.xres_virtual);
  	if (info->var.yres_virtual < info->var.yres) {
  		dev_err(info->device, "virtual vertical size smaller than real
  ");
a268422de   Ondrej Zajicek   [PATCH] fbdev dri...
1328
1329
  		goto err_find_mode;
  	}
99d054d82   Ondrej Zary   s3fb: maximize vi...
1330
1331
1332
1333
1334
1335
1336
1337
  	/* maximize virtual vertical size for fast scrolling */
  	info->var.yres_virtual = info->fix.smem_len * 8 /
  			(info->var.bits_per_pixel * info->var.xres_virtual);
  	if (info->var.yres_virtual < info->var.yres) {
  		dev_err(info->device, "virtual vertical size smaller than real
  ");
  		goto err_find_mode;
  	}
a268422de   Ondrej Zajicek   [PATCH] fbdev dri...
1338
1339
  	rc = fb_alloc_cmap(&info->cmap, 256, 0);
  	if (rc < 0) {
594a88197   Ondrej Zajicek   vt8623fb: fix ker...
1340
1341
  		dev_err(info->device, "cannot allocate colormap
  ");
a268422de   Ondrej Zajicek   [PATCH] fbdev dri...
1342
1343
1344
1345
1346
  		goto err_alloc_cmap;
  	}
  
  	rc = register_framebuffer(info);
  	if (rc < 0) {
594a88197   Ondrej Zajicek   vt8623fb: fix ker...
1347
1348
  		dev_err(info->device, "cannot register framebuffer
  ");
a268422de   Ondrej Zajicek   [PATCH] fbdev dri...
1349
1350
1351
1352
1353
1354
1355
1356
1357
1358
  		goto err_reg_fb;
  	}
  
  	printk(KERN_INFO "fb%d: %s on %s, %d MB RAM, %d MHz MCLK
  ", info->node, info->fix.id,
  		 pci_name(dev), info->fix.smem_len >> 20, (par->mclk_freq + 500) / 1000);
  
  	if (par->chip == CHIP_UNKNOWN)
  		printk(KERN_INFO "fb%d: unknown chip, CR2D=%x, CR2E=%x, CRT2F=%x, CRT30=%x
  ",
f86459335   David Miller   s3fb: Pass par->s...
1359
1360
  			info->node, vga_rcrt(par->state.vgabase, 0x2d), vga_rcrt(par->state.vgabase, 0x2e),
  			vga_rcrt(par->state.vgabase, 0x2f), vga_rcrt(par->state.vgabase, 0x30));
a268422de   Ondrej Zajicek   [PATCH] fbdev dri...
1361
1362
1363
1364
1365
1366
1367
1368
1369
1370
1371
1372
1373
1374
1375
1376
1377
1378
  
  	/* Record a reference to the driver data */
  	pci_set_drvdata(dev, info);
  
  #ifdef CONFIG_MTRR
  	if (mtrr) {
  		par->mtrr_reg = -1;
  		par->mtrr_reg = mtrr_add(info->fix.smem_start, info->fix.smem_len, MTRR_TYPE_WRCOMB, 1);
  	}
  #endif
  
  	return 0;
  
  	/* Error handling */
  err_reg_fb:
  	fb_dealloc_cmap(&info->cmap);
  err_alloc_cmap:
  err_find_mode:
86c0f043a   Ondrej Zary   s3fb: add DDC sup...
1379
1380
1381
1382
1383
1384
  #ifdef CONFIG_FB_S3_DDC
  	if (par->ddc_registered)
  		i2c_del_adapter(&par->ddc_adapter);
  	if (par->mmio)
  		iounmap(par->mmio);
  #endif
a268422de   Ondrej Zajicek   [PATCH] fbdev dri...
1385
1386
1387
1388
1389
1390
1391
1392
1393
1394
1395
1396
1397
1398
1399
1400
  	pci_iounmap(dev, info->screen_base);
  err_iomap:
  	pci_release_regions(dev);
  err_request_regions:
  /*	pci_disable_device(dev); */
  err_enable_device:
  	framebuffer_release(info);
  	return rc;
  }
  
  
  /* PCI remove */
  
  static void __devexit s3_pci_remove(struct pci_dev *dev)
  {
  	struct fb_info *info = pci_get_drvdata(dev);
4f2970b9f   Paul Mundt   s3fb: fix up DDC ...
1401
  	struct s3fb_info __maybe_unused *par = info->par;
a268422de   Ondrej Zajicek   [PATCH] fbdev dri...
1402
1403
1404
1405
1406
1407
1408
1409
1410
1411
1412
1413
  
  	if (info) {
  
  #ifdef CONFIG_MTRR
  		if (par->mtrr_reg >= 0) {
  			mtrr_del(par->mtrr_reg, 0, 0);
  			par->mtrr_reg = -1;
  		}
  #endif
  
  		unregister_framebuffer(info);
  		fb_dealloc_cmap(&info->cmap);
86c0f043a   Ondrej Zary   s3fb: add DDC sup...
1414
1415
1416
1417
1418
1419
  #ifdef CONFIG_FB_S3_DDC
  		if (par->ddc_registered)
  			i2c_del_adapter(&par->ddc_adapter);
  		if (par->mmio)
  			iounmap(par->mmio);
  #endif
a268422de   Ondrej Zajicek   [PATCH] fbdev dri...
1420
1421
1422
1423
1424
1425
1426
1427
1428
1429
1430
1431
1432
1433
1434
  		pci_iounmap(dev, info->screen_base);
  		pci_release_regions(dev);
  /*		pci_disable_device(dev); */
  
  		pci_set_drvdata(dev, NULL);
  		framebuffer_release(info);
  	}
  }
  
  /* PCI suspend */
  
  static int s3_pci_suspend(struct pci_dev* dev, pm_message_t state)
  {
  	struct fb_info *info = pci_get_drvdata(dev);
  	struct s3fb_info *par = info->par;
594a88197   Ondrej Zajicek   vt8623fb: fix ker...
1435
1436
  	dev_info(info->device, "suspend
  ");
a268422de   Ondrej Zajicek   [PATCH] fbdev dri...
1437

ac751efa6   Torben Hohn   console: rename a...
1438
  	console_lock();
a268422de   Ondrej Zajicek   [PATCH] fbdev dri...
1439
1440
1441
1442
  	mutex_lock(&(par->open_lock));
  
  	if ((state.event == PM_EVENT_FREEZE) || (par->ref_count == 0)) {
  		mutex_unlock(&(par->open_lock));
ac751efa6   Torben Hohn   console: rename a...
1443
  		console_unlock();
a268422de   Ondrej Zajicek   [PATCH] fbdev dri...
1444
1445
1446
1447
1448
1449
1450
1451
1452
1453
  		return 0;
  	}
  
  	fb_set_suspend(info, 1);
  
  	pci_save_state(dev);
  	pci_disable_device(dev);
  	pci_set_power_state(dev, pci_choose_state(dev, state));
  
  	mutex_unlock(&(par->open_lock));
ac751efa6   Torben Hohn   console: rename a...
1454
  	console_unlock();
a268422de   Ondrej Zajicek   [PATCH] fbdev dri...
1455
1456
1457
1458
1459
1460
1461
1462
1463
1464
1465
  
  	return 0;
  }
  
  
  /* PCI resume */
  
  static int s3_pci_resume(struct pci_dev* dev)
  {
  	struct fb_info *info = pci_get_drvdata(dev);
  	struct s3fb_info *par = info->par;
6314db411   Randy Dunlap   s3fb: fix PCI mus...
1466
  	int err;
a268422de   Ondrej Zajicek   [PATCH] fbdev dri...
1467

594a88197   Ondrej Zajicek   vt8623fb: fix ker...
1468
1469
  	dev_info(info->device, "resume
  ");
a268422de   Ondrej Zajicek   [PATCH] fbdev dri...
1470

ac751efa6   Torben Hohn   console: rename a...
1471
  	console_lock();
a268422de   Ondrej Zajicek   [PATCH] fbdev dri...
1472
1473
1474
1475
  	mutex_lock(&(par->open_lock));
  
  	if (par->ref_count == 0) {
  		mutex_unlock(&(par->open_lock));
ac751efa6   Torben Hohn   console: rename a...
1476
  		console_unlock();
a268422de   Ondrej Zajicek   [PATCH] fbdev dri...
1477
1478
1479
1480
1481
  		return 0;
  	}
  
  	pci_set_power_state(dev, PCI_D0);
  	pci_restore_state(dev);
6314db411   Randy Dunlap   s3fb: fix PCI mus...
1482
1483
1484
  	err = pci_enable_device(dev);
  	if (err) {
  		mutex_unlock(&(par->open_lock));
ac751efa6   Torben Hohn   console: rename a...
1485
  		console_unlock();
594a88197   Ondrej Zajicek   vt8623fb: fix ker...
1486
1487
  		dev_err(info->device, "error %d enabling device for resume
  ", err);
6314db411   Randy Dunlap   s3fb: fix PCI mus...
1488
1489
  		return err;
  	}
a268422de   Ondrej Zajicek   [PATCH] fbdev dri...
1490
1491
1492
1493
1494
1495
  	pci_set_master(dev);
  
  	s3fb_set_par(info);
  	fb_set_suspend(info, 0);
  
  	mutex_unlock(&(par->open_lock));
ac751efa6   Torben Hohn   console: rename a...
1496
  	console_unlock();
a268422de   Ondrej Zajicek   [PATCH] fbdev dri...
1497
1498
1499
1500
1501
1502
1503
1504
1505
1506
1507
1508
1509
1510
1511
1512
1513
1514
  
  	return 0;
  }
  
  
  /* List of boards that we are trying to support */
  
  static struct pci_device_id s3_devices[] __devinitdata = {
  	{PCI_DEVICE(PCI_VENDOR_ID_S3, 0x8810), .driver_data = CHIP_XXX_TRIO},
  	{PCI_DEVICE(PCI_VENDOR_ID_S3, 0x8811), .driver_data = CHIP_XXX_TRIO},
  	{PCI_DEVICE(PCI_VENDOR_ID_S3, 0x8812), .driver_data = CHIP_M65_AURORA64VP},
  	{PCI_DEVICE(PCI_VENDOR_ID_S3, 0x8814), .driver_data = CHIP_767_TRIO64UVP},
  	{PCI_DEVICE(PCI_VENDOR_ID_S3, 0x8901), .driver_data = CHIP_XXX_TRIO64V2_DXGX},
  	{PCI_DEVICE(PCI_VENDOR_ID_S3, 0x8902), .driver_data = CHIP_551_PLATO_PX},
  
  	{PCI_DEVICE(PCI_VENDOR_ID_S3, 0x5631), .driver_data = CHIP_325_VIRGE},
  	{PCI_DEVICE(PCI_VENDOR_ID_S3, 0x883D), .driver_data = CHIP_988_VIRGE_VX},
  	{PCI_DEVICE(PCI_VENDOR_ID_S3, 0x8A01), .driver_data = CHIP_XXX_VIRGE_DXGX},
94e948e6e   Ondrej Zary   s3fb: fix Virge/GX2
1515
1516
  	{PCI_DEVICE(PCI_VENDOR_ID_S3, 0x8A10), .driver_data = CHIP_357_VIRGE_GX2},
  	{PCI_DEVICE(PCI_VENDOR_ID_S3, 0x8A11), .driver_data = CHIP_359_VIRGE_GX2P},
a268422de   Ondrej Zajicek   [PATCH] fbdev dri...
1517
  	{PCI_DEVICE(PCI_VENDOR_ID_S3, 0x8A12), .driver_data = CHIP_359_VIRGE_GX2P},
9966c4fea   Ondrej Zary   add support for S...
1518
  	{PCI_DEVICE(PCI_VENDOR_ID_S3, 0x8A13), .driver_data = CHIP_36X_TRIO3D_1X_2X},
5694f9ce5   Ondrej Zary   s3fb: add support...
1519
  	{PCI_DEVICE(PCI_VENDOR_ID_S3, 0x8904), .driver_data = CHIP_365_TRIO3D},
a268422de   Ondrej Zajicek   [PATCH] fbdev dri...
1520
1521
1522
1523
1524
1525
1526
1527
1528
1529
1530
1531
1532
1533
1534
  
  	{0, 0, 0, 0, 0, 0, 0}
  };
  
  
  MODULE_DEVICE_TABLE(pci, s3_devices);
  
  static struct pci_driver s3fb_pci_driver = {
  	.name		= "s3fb",
  	.id_table	= s3_devices,
  	.probe		= s3_pci_probe,
  	.remove		= __devexit_p(s3_pci_remove),
  	.suspend	= s3_pci_suspend,
  	.resume		= s3_pci_resume,
  };
75e1b6a84   Joe Perches   video: Fix spefic...
1535
  /* Parse user specified options */
a268422de   Ondrej Zajicek   [PATCH] fbdev dri...
1536
1537
1538
1539
1540
1541
1542
1543
1544
1545
1546
1547
1548
1549
  
  #ifndef MODULE
  static int  __init s3fb_setup(char *options)
  {
  	char *opt;
  
  	if (!options || !*options)
  		return 0;
  
  	while ((opt = strsep(&options, ",")) != NULL) {
  
  		if (!*opt)
  			continue;
  #ifdef CONFIG_MTRR
62fa4dc7f   Ondrej Zajicek   [PATCH] Fix build...
1550
  		else if (!strncmp(opt, "mtrr:", 5))
a268422de   Ondrej Zajicek   [PATCH] fbdev dri...
1551
1552
  			mtrr = simple_strtoul(opt + 5, NULL, 0);
  #endif
62fa4dc7f   Ondrej Zajicek   [PATCH] Fix build...
1553
1554
  		else if (!strncmp(opt, "fasttext:", 9))
  			fasttext = simple_strtoul(opt + 9, NULL, 0);
a268422de   Ondrej Zajicek   [PATCH] fbdev dri...
1555
  		else
a81405439   Krzysztof Helt   s3fb: add option ...
1556
  			mode_option = opt;
a268422de   Ondrej Zajicek   [PATCH] fbdev dri...
1557
1558
1559
1560
1561
1562
1563
1564
1565
1566
1567
1568
1569
1570
1571
1572
1573
1574
1575
1576
1577
1578
1579
1580
1581
1582
1583
1584
1585
1586
1587
1588
1589
1590
1591
1592
1593
1594
1595
  	}
  
  	return 0;
  }
  #endif
  
  /* Cleanup */
  
  static void __exit s3fb_cleanup(void)
  {
  	pr_debug("s3fb: cleaning up
  ");
  	pci_unregister_driver(&s3fb_pci_driver);
  }
  
  /* Driver Initialisation */
  
  static int __init s3fb_init(void)
  {
  
  #ifndef MODULE
  	char *option = NULL;
  
  	if (fb_get_options("s3fb", &option))
  		return -ENODEV;
  	s3fb_setup(option);
  #endif
  
  	pr_debug("s3fb: initializing
  ");
  	return pci_register_driver(&s3fb_pci_driver);
  }
  
  /* ------------------------------------------------------------------------- */
  
  /* Modularization */
  
  module_init(s3fb_init);
  module_exit(s3fb_cleanup);