Blame view

drivers/video/cirrusfb.c 76.7 KB
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
  /*
   * drivers/video/cirrusfb.c - driver for Cirrus Logic chipsets
   *
   * Copyright 1999-2001 Jeff Garzik <jgarzik@pobox.com>
   *
   * Contributors (thanks, all!)
   *
   *	David Eger:
   *	Overhaul for Linux 2.6
   *
   *      Jeff Rugen:
   *      Major contributions;  Motorola PowerStack (PPC and PCI) support,
   *      GD54xx, 1280x1024 mode support, change MCLK based on VCLK.
   *
   *	Geert Uytterhoeven:
   *	Excellent code review.
   *
   *	Lars Hecking:
   *	Amiga updates and testing.
   *
   * Original cirrusfb author:  Frank Neumann
   *
   * Based on retz3fb.c and cirrusfb.c:
   *      Copyright (C) 1997 Jes Sorensen
   *      Copyright (C) 1996 Frank Neumann
   *
   ***************************************************************
   *
   * Format this code with GNU indent '-kr -i8 -pcs' options.
   *
   * 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.
   *
   */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
36
37
38
39
40
  #include <linux/module.h>
  #include <linux/kernel.h>
  #include <linux/errno.h>
  #include <linux/string.h>
  #include <linux/mm.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
41
42
43
  #include <linux/delay.h>
  #include <linux/fb.h>
  #include <linux/init.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
44
45
46
47
48
49
50
51
52
53
54
55
  #include <asm/pgtable.h>
  
  #ifdef CONFIG_ZORRO
  #include <linux/zorro.h>
  #endif
  #ifdef CONFIG_PCI
  #include <linux/pci.h>
  #endif
  #ifdef CONFIG_AMIGA
  #include <asm/amigahw.h>
  #endif
  #ifdef CONFIG_PPC_PREP
e8222502e   Benjamin Herrenschmidt   [PATCH] powerpc: ...
56
  #include <asm/machdep.h>
8503df659   Krzysztof Helt   cirrusfb: checkpa...
57
  #define isPReP machine_is(prep)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
58
59
60
  #else
  #define isPReP 0
  #endif
0ff1edeef   Krzysztof Helt   cirrusfb: code im...
61
62
  #include <video/vga.h>
  #include <video/cirrus.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
63

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
64
65
66
67
68
  /*****************************************************************
   *
   * debugging and utility macros
   *
   */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
69
70
  /* disable runtime assertions? */
  /* #define CIRRUSFB_NDEBUG */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
71
72
73
  /* debugging assertions */
  #ifndef CIRRUSFB_NDEBUG
  #define assert(expr) \
8503df659   Krzysztof Helt   cirrusfb: checkpa...
74
75
76
  	if (!(expr)) { \
  		printk("Assertion failed! %s,%s,%s,line=%d
  ", \
5ae121705   Harvey Harrison   video: replace re...
77
  		#expr, __FILE__, __func__, __LINE__); \
8503df659   Krzysztof Helt   cirrusfb: checkpa...
78
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
79
80
81
  #else
  #define assert(expr)
  #endif
8503df659   Krzysztof Helt   cirrusfb: checkpa...
82
  #define MB_ (1024 * 1024)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
83

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
84
85
86
87
88
89
90
  /*****************************************************************
   *
   * chipset information
   *
   */
  
  /* board types */
7345de32d   Krzysztof Helt   cirrusfb: remove ...
91
  enum cirrus_board {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
92
  	BT_NONE = 0,
7cade31ca   Krzysztof Helt   cirrusfb: use 24b...
93
94
95
96
  	BT_SD64,	/* GD5434 */
  	BT_PICCOLO,	/* GD5426 */
  	BT_PICASSO,	/* GD5426 or GD5428 */
  	BT_SPECTRUM,	/* GD5426 or GD5428 */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
97
98
99
  	BT_PICASSO4,	/* GD5446 */
  	BT_ALPINE,	/* GD543x/4x */
  	BT_GD5480,
78d780e07   Krzysztof Helt   cirrusfb: various...
100
101
  	BT_LAGUNA,	/* GD5462/64 */
  	BT_LAGUNAB,	/* GD5465 */
7345de32d   Krzysztof Helt   cirrusfb: remove ...
102
  };
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
103

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
104
105
106
  /*
   * per-board-type information, used for enumerating and abstracting
   * chip-specific information
7345de32d   Krzysztof Helt   cirrusfb: remove ...
107
   * NOTE: MUST be in the same order as enum cirrus_board in order to
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
108
109
110
111
112
113
114
115
116
   * use direct indexing on this array
   * NOTE: '__initdata' cannot be used as some of this info
   * is required at runtime.  Maybe separate into an init-only and
   * a run-time table?
   */
  static const struct cirrusfb_board_info_rec {
  	char *name;		/* ASCII name of chipset */
  	long maxclock[5];		/* maximum video clock */
  	/* for  1/4bpp, 8bpp 15/16bpp, 24bpp, 32bpp - numbers from xorg code */
c930faaed   Richard Knutsson   cirrusfb: convert...
117
118
  	bool init_sr07 : 1; /* init SR07 during init_vgachip() */
  	bool init_sr1f : 1; /* write SR1F during init_vgachip() */
8503df659   Krzysztof Helt   cirrusfb: checkpa...
119
120
  	/* construct bit 19 of screen start address */
  	bool scrn_start_bit19 : 1;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
  
  	/* initial SR07 value, then for each mode */
  	unsigned char sr07;
  	unsigned char sr07_1bpp;
  	unsigned char sr07_1bpp_mux;
  	unsigned char sr07_8bpp;
  	unsigned char sr07_8bpp_mux;
  
  	unsigned char sr1f;	/* SR1F VGA initial register value */
  } cirrusfb_board_info[] = {
  	[BT_SD64] = {
  		.name			= "CL SD64",
  		.maxclock		= {
  			/* guess */
  			/* the SD64/P4 have a higher max. videoclock */
75ed3a17a   Krzysztof Helt   cirrusfb: convert...
136
  			135100, 135100, 85500, 85500, 0
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
137
  		},
c930faaed   Richard Knutsson   cirrusfb: convert...
138
139
140
  		.init_sr07		= true,
  		.init_sr1f		= true,
  		.scrn_start_bit19	= true,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
141
142
  		.sr07			= 0xF0,
  		.sr07_1bpp		= 0xF0,
df3aafd57   Krzysztof Helt   cirrusfb: GD5434 ...
143
  		.sr07_1bpp_mux		= 0xF6,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
144
  		.sr07_8bpp		= 0xF1,
df3aafd57   Krzysztof Helt   cirrusfb: GD5434 ...
145
  		.sr07_8bpp_mux		= 0xF7,
8f19e15b8   Krzysztof Helt   cirrusfb: set MCL...
146
  		.sr1f			= 0x1E
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
147
148
149
150
151
152
153
  	},
  	[BT_PICCOLO] = {
  		.name			= "CL Piccolo",
  		.maxclock		= {
  			/* guess */
  			90000, 90000, 90000, 90000, 90000
  		},
c930faaed   Richard Knutsson   cirrusfb: convert...
154
155
156
  		.init_sr07		= true,
  		.init_sr1f		= true,
  		.scrn_start_bit19	= false,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
157
158
159
160
161
162
163
164
165
166
167
  		.sr07			= 0x80,
  		.sr07_1bpp		= 0x80,
  		.sr07_8bpp		= 0x81,
  		.sr1f			= 0x22
  	},
  	[BT_PICASSO] = {
  		.name			= "CL Picasso",
  		.maxclock		= {
  			/* guess */
  			90000, 90000, 90000, 90000, 90000
  		},
c930faaed   Richard Knutsson   cirrusfb: convert...
168
169
170
  		.init_sr07		= true,
  		.init_sr1f		= true,
  		.scrn_start_bit19	= false,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
171
172
173
174
175
176
177
178
179
180
181
  		.sr07			= 0x20,
  		.sr07_1bpp		= 0x20,
  		.sr07_8bpp		= 0x21,
  		.sr1f			= 0x22
  	},
  	[BT_SPECTRUM] = {
  		.name			= "CL Spectrum",
  		.maxclock		= {
  			/* guess */
  			90000, 90000, 90000, 90000, 90000
  		},
c930faaed   Richard Knutsson   cirrusfb: convert...
182
183
184
  		.init_sr07		= true,
  		.init_sr1f		= true,
  		.scrn_start_bit19	= false,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
185
186
187
188
189
190
191
192
193
194
  		.sr07			= 0x80,
  		.sr07_1bpp		= 0x80,
  		.sr07_8bpp		= 0x81,
  		.sr1f			= 0x22
  	},
  	[BT_PICASSO4] = {
  		.name			= "CL Picasso4",
  		.maxclock		= {
  			135100, 135100, 85500, 85500, 0
  		},
c930faaed   Richard Knutsson   cirrusfb: convert...
195
196
197
  		.init_sr07		= true,
  		.init_sr1f		= false,
  		.scrn_start_bit19	= true,
527410ff7   Krzysztof Helt   cirrusfb: GD5446 ...
198
199
200
201
202
  		.sr07			= 0xA0,
  		.sr07_1bpp		= 0xA0,
  		.sr07_1bpp_mux		= 0xA6,
  		.sr07_8bpp		= 0xA1,
  		.sr07_8bpp_mux		= 0xA7,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
203
204
205
206
207
208
209
210
  		.sr1f			= 0
  	},
  	[BT_ALPINE] = {
  		.name			= "CL Alpine",
  		.maxclock		= {
  			/* for the GD5430.  GD5446 can do more... */
  			85500, 85500, 50000, 28500, 0
  		},
c930faaed   Richard Knutsson   cirrusfb: convert...
211
212
213
  		.init_sr07		= true,
  		.init_sr1f		= true,
  		.scrn_start_bit19	= true,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
214
  		.sr07			= 0xA0,
527410ff7   Krzysztof Helt   cirrusfb: GD5446 ...
215
216
  		.sr07_1bpp		= 0xA0,
  		.sr07_1bpp_mux		= 0xA6,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
217
218
219
220
221
222
223
224
225
  		.sr07_8bpp		= 0xA1,
  		.sr07_8bpp_mux		= 0xA7,
  		.sr1f			= 0x1C
  	},
  	[BT_GD5480] = {
  		.name			= "CL GD5480",
  		.maxclock		= {
  			135100, 200000, 200000, 135100, 135100
  		},
c930faaed   Richard Knutsson   cirrusfb: convert...
226
227
228
  		.init_sr07		= true,
  		.init_sr1f		= true,
  		.scrn_start_bit19	= true,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
229
230
231
232
233
234
235
236
  		.sr07			= 0x10,
  		.sr07_1bpp		= 0x11,
  		.sr07_8bpp		= 0x11,
  		.sr1f			= 0x1C
  	},
  	[BT_LAGUNA] = {
  		.name			= "CL Laguna",
  		.maxclock		= {
78d780e07   Krzysztof Helt   cirrusfb: various...
237
238
239
240
241
242
243
244
245
246
247
248
  			/* taken from X11 code */
  			170000, 170000, 170000, 170000, 135100,
  		},
  		.init_sr07		= false,
  		.init_sr1f		= false,
  		.scrn_start_bit19	= true,
  	},
  	[BT_LAGUNAB] = {
  		.name			= "CL Laguna AGP",
  		.maxclock		= {
  			/* taken from X11 code */
  			170000, 250000, 170000, 170000, 135100,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
249
  		},
c930faaed   Richard Knutsson   cirrusfb: convert...
250
251
252
  		.init_sr07		= false,
  		.init_sr1f		= false,
  		.scrn_start_bit19	= true,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
253
254
  	}
  };
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
255
256
  #ifdef CONFIG_PCI
  #define CHIP(id, btype) \
4153812fc   Grant Coady   [PATCH] pci_ids: ...
257
  	{ PCI_VENDOR_ID_CIRRUS, id, PCI_ANY_ID, PCI_ANY_ID, 0, 0, (btype) }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
258
259
  
  static struct pci_device_id cirrusfb_pci_table[] = {
8503df659   Krzysztof Helt   cirrusfb: checkpa...
260
  	CHIP(PCI_DEVICE_ID_CIRRUS_5436, BT_ALPINE),
df3aafd57   Krzysztof Helt   cirrusfb: GD5434 ...
261
262
  	CHIP(PCI_DEVICE_ID_CIRRUS_5434_8, BT_SD64),
  	CHIP(PCI_DEVICE_ID_CIRRUS_5434_4, BT_SD64),
8503df659   Krzysztof Helt   cirrusfb: checkpa...
263
264
265
266
267
268
269
  	CHIP(PCI_DEVICE_ID_CIRRUS_5430, BT_ALPINE), /* GD-5440 is same id */
  	CHIP(PCI_DEVICE_ID_CIRRUS_7543, BT_ALPINE),
  	CHIP(PCI_DEVICE_ID_CIRRUS_7548, BT_ALPINE),
  	CHIP(PCI_DEVICE_ID_CIRRUS_5480, BT_GD5480), /* MacPicasso likely */
  	CHIP(PCI_DEVICE_ID_CIRRUS_5446, BT_PICASSO4), /* Picasso 4 is 5446 */
  	CHIP(PCI_DEVICE_ID_CIRRUS_5462, BT_LAGUNA), /* CL Laguna */
  	CHIP(PCI_DEVICE_ID_CIRRUS_5464, BT_LAGUNA), /* CL Laguna 3D */
78d780e07   Krzysztof Helt   cirrusfb: various...
270
  	CHIP(PCI_DEVICE_ID_CIRRUS_5465, BT_LAGUNAB), /* CL Laguna 3DA*/
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
271
272
273
274
275
  	{ 0, }
  };
  MODULE_DEVICE_TABLE(pci, cirrusfb_pci_table);
  #undef CHIP
  #endif /* CONFIG_PCI */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
276
  #ifdef CONFIG_ZORRO
0e0d13364   Geert Uytterhoeven   fbdev/cirrusfb: R...
277
278
279
280
281
282
283
  struct zorrocl {
  	enum cirrus_board type;	/* Board type */
  	u32 regoffset;		/* Offset of registers in first Zorro device */
  	u32 ramsize;		/* Size of video RAM in first Zorro device */
  				/* If zero, use autoprobe on RAM device */
  	u32 ramoffset;		/* Offset of video RAM in first Zorro device */
  	zorro_id ramid;		/* Zorro ID of RAM device */
17bdf4895   Geert Uytterhoeven   fbdev/cirrusfb: A...
284
  	zorro_id ramid2;	/* Zorro ID of optional second RAM device */
0e0d13364   Geert Uytterhoeven   fbdev/cirrusfb: R...
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
  };
  
  static const struct zorrocl zcl_sd64 __devinitconst = {
  	.type		= BT_SD64,
  	.ramid		= ZORRO_PROD_HELFRICH_SD64_RAM,
  };
  
  static const struct zorrocl zcl_piccolo __devinitconst = {
  	.type		= BT_PICCOLO,
  	.ramid		= ZORRO_PROD_HELFRICH_PICCOLO_RAM,
  };
  
  static const struct zorrocl zcl_picasso __devinitconst = {
  	.type		= BT_PICASSO,
  	.ramid		= ZORRO_PROD_VILLAGE_TRONIC_PICASSO_II_II_PLUS_RAM,
  };
  
  static const struct zorrocl zcl_spectrum __devinitconst = {
  	.type		= BT_SPECTRUM,
  	.ramid		= ZORRO_PROD_GVP_EGS_28_24_SPECTRUM_RAM,
  };
  
  static const struct zorrocl zcl_picasso4_z3 __devinitconst = {
  	.type		= BT_PICASSO4,
  	.regoffset	= 0x00600000,
  	.ramsize	= 4 * MB_,
e78bb882b   Geert Uytterhoeven   fbdev/cirrusfb: A...
311
  	.ramoffset	= 0x01000000,	/* 0x02000000 for 64 MiB boards */
0e0d13364   Geert Uytterhoeven   fbdev/cirrusfb: R...
312
  };
17bdf4895   Geert Uytterhoeven   fbdev/cirrusfb: A...
313
314
315
316
317
318
  static const struct zorrocl zcl_picasso4_z2 __devinitconst = {
  	.type		= BT_PICASSO4,
  	.regoffset	= 0x10000,
  	.ramid		= ZORRO_PROD_VILLAGE_TRONIC_PICASSO_IV_Z2_RAM1,
  	.ramid2		= ZORRO_PROD_VILLAGE_TRONIC_PICASSO_IV_Z2_RAM2,
  };
0e0d13364   Geert Uytterhoeven   fbdev/cirrusfb: R...
319
320
  
  static const struct zorro_device_id cirrusfb_zorro_table[] __devinitconst = {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
321
  	{
0e0d13364   Geert Uytterhoeven   fbdev/cirrusfb: R...
322
323
  		.id		= ZORRO_PROD_HELFRICH_SD64_REG,
  		.driver_data	= (unsigned long)&zcl_sd64,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
324
  	}, {
0e0d13364   Geert Uytterhoeven   fbdev/cirrusfb: R...
325
326
  		.id		= ZORRO_PROD_HELFRICH_PICCOLO_REG,
  		.driver_data	= (unsigned long)&zcl_piccolo,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
327
  	}, {
0e0d13364   Geert Uytterhoeven   fbdev/cirrusfb: R...
328
329
  		.id	= ZORRO_PROD_VILLAGE_TRONIC_PICASSO_II_II_PLUS_REG,
  		.driver_data	= (unsigned long)&zcl_picasso,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
330
  	}, {
0e0d13364   Geert Uytterhoeven   fbdev/cirrusfb: R...
331
332
  		.id		= ZORRO_PROD_GVP_EGS_28_24_SPECTRUM_REG,
  		.driver_data	= (unsigned long)&zcl_spectrum,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
333
334
  	}, {
  		.id		= ZORRO_PROD_VILLAGE_TRONIC_PICASSO_IV_Z3,
0e0d13364   Geert Uytterhoeven   fbdev/cirrusfb: R...
335
  		.driver_data	= (unsigned long)&zcl_picasso4_z3,
17bdf4895   Geert Uytterhoeven   fbdev/cirrusfb: A...
336
337
338
  	}, {
  		.id		= ZORRO_PROD_VILLAGE_TRONIC_PICASSO_IV_Z2_REG,
  		.driver_data	= (unsigned long)&zcl_picasso4_z2,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
339
340
341
  	},
  	{ 0 }
  };
bf54a2b3c   Geert Uytterhoeven   m68k: amiga - Zor...
342
  MODULE_DEVICE_TABLE(zorro, cirrusfb_zorro_table);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
343
  #endif /* CONFIG_ZORRO */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
344
  #ifdef CIRRUSFB_DEBUG
7345de32d   Krzysztof Helt   cirrusfb: remove ...
345
  enum cirrusfb_dbg_reg_class {
8503df659   Krzysztof Helt   cirrusfb: checkpa...
346
347
  	CRT,
  	SEQ
7345de32d   Krzysztof Helt   cirrusfb: remove ...
348
  };
8503df659   Krzysztof Helt   cirrusfb: checkpa...
349
  #endif		/* CIRRUSFB_DEBUG */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
350
351
352
  
  /* info about board */
  struct cirrusfb_info {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
353
  	u8 __iomem *regbase;
6e30fc086   Krzysztof Helt   cirrusfb: add mmi...
354
  	u8 __iomem *laguna_mmio;
7345de32d   Krzysztof Helt   cirrusfb: remove ...
355
  	enum cirrus_board btype;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
356
  	unsigned char SFR;	/* Shadow of special function register */
48c329e90   Krzysztof Helt   cirrusfb: various...
357
  	int multiplexing;
df3aafd57   Krzysztof Helt   cirrusfb: GD5434 ...
358
  	int doubleVCLK;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
359
  	int blank_mode;
64beab14f   Krzysztof Helt   cirrusfb: drop de...
360
  	u32 pseudo_palette[16];
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
361

9199ec5c5   Krzysztof Helt   cirrusfb: remove ...
362
  	void (*unmap)(struct fb_info *info);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
363
  };
90ab5ee94   Rusty Russell   module_param: mak...
364
  static bool noaccel __devinitdata;
a1d35a7a5   Krzysztof Helt   cirrusfb: use mod...
365
  static char *mode_option __devinitdata = "640x480@60";
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
366
367
368
  
  /****************************************************************************/
  /**** BEGIN PROTOTYPES ******************************************************/
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
369
  /*--- Interface used by the world ------------------------------------------*/
8503df659   Krzysztof Helt   cirrusfb: checkpa...
370
371
  static int cirrusfb_pan_display(struct fb_var_screeninfo *var,
  				struct fb_info *info);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
372

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
373
  /*--- Internal routines ----------------------------------------------------*/
9199ec5c5   Krzysztof Helt   cirrusfb: remove ...
374
  static void init_vgachip(struct fb_info *info);
8503df659   Krzysztof Helt   cirrusfb: checkpa...
375
376
377
378
379
380
381
382
383
384
  static void switch_monitor(struct cirrusfb_info *cinfo, int on);
  static void WGen(const struct cirrusfb_info *cinfo,
  		 int regnum, unsigned char val);
  static unsigned char RGen(const struct cirrusfb_info *cinfo, int regnum);
  static void AttrOn(const struct cirrusfb_info *cinfo);
  static void WHDR(const struct cirrusfb_info *cinfo, unsigned char val);
  static void WSFR(struct cirrusfb_info *cinfo, unsigned char val);
  static void WSFR2(struct cirrusfb_info *cinfo, unsigned char val);
  static void WClut(struct cirrusfb_info *cinfo, unsigned char regnum,
  		  unsigned char red, unsigned char green, unsigned char blue);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
385
  #if 0
8503df659   Krzysztof Helt   cirrusfb: checkpa...
386
387
388
  static void RClut(struct cirrusfb_info *cinfo, unsigned char regnum,
  		  unsigned char *red, unsigned char *green,
  		  unsigned char *blue);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
389
  #endif
8503df659   Krzysztof Helt   cirrusfb: checkpa...
390
391
392
393
394
395
396
397
398
  static void cirrusfb_WaitBLT(u8 __iomem *regbase);
  static void cirrusfb_BitBLT(u8 __iomem *regbase, int bits_per_pixel,
  			    u_short curx, u_short cury,
  			    u_short destx, u_short desty,
  			    u_short width, u_short height,
  			    u_short line_length);
  static void cirrusfb_RectFill(u8 __iomem *regbase, int bits_per_pixel,
  			      u_short x, u_short y,
  			      u_short width, u_short height,
9e8480625   Krzysztof Helt   cirrusfb: add ima...
399
400
  			      u32 fg_color, u32 bg_color,
  			      u_short line_length, u_char blitmode);
8503df659   Krzysztof Helt   cirrusfb: checkpa...
401

dafa32c5a   Krzysztof Helt   cirrusfb: drop cl...
402
  static void bestclock(long freq, int *nom, int *den, int *div);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
403
404
  
  #ifdef CIRRUSFB_DEBUG
75ed3a17a   Krzysztof Helt   cirrusfb: convert...
405
406
407
  static void cirrusfb_dbg_reg_dump(struct fb_info *info, caddr_t regbase);
  static void cirrusfb_dbg_print_regs(struct fb_info *info,
  				    caddr_t regbase,
7345de32d   Krzysztof Helt   cirrusfb: remove ...
408
  				    enum cirrusfb_dbg_reg_class reg_class, ...);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
409
410
411
412
413
  #endif /* CIRRUSFB_DEBUG */
  
  /*** END   PROTOTYPES ********************************************************/
  /*****************************************************************************/
  /*** BEGIN Interface Used by the World ***************************************/
78d780e07   Krzysztof Helt   cirrusfb: various...
414
415
416
417
  static inline int is_laguna(const struct cirrusfb_info *cinfo)
  {
  	return cinfo->btype == BT_LAGUNA || cinfo->btype == BT_LAGUNAB;
  }
8503df659   Krzysztof Helt   cirrusfb: checkpa...
418
  static int opencount;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
419
420
  
  /*--- Open /dev/fbx ---------------------------------------------------------*/
8503df659   Krzysztof Helt   cirrusfb: checkpa...
421
  static int cirrusfb_open(struct fb_info *info, int user)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
422
423
  {
  	if (opencount++ == 0)
8503df659   Krzysztof Helt   cirrusfb: checkpa...
424
  		switch_monitor(info->par, 1);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
425
426
427
428
  	return 0;
  }
  
  /*--- Close /dev/fbx --------------------------------------------------------*/
8503df659   Krzysztof Helt   cirrusfb: checkpa...
429
  static int cirrusfb_release(struct fb_info *info, int user)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
430
431
  {
  	if (--opencount == 0)
8503df659   Krzysztof Helt   cirrusfb: checkpa...
432
  		switch_monitor(info->par, 0);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
433
434
435
436
437
438
  	return 0;
  }
  
  /**** END   Interface used by the World *************************************/
  /****************************************************************************/
  /**** BEGIN Hardware specific Routines **************************************/
486ff387c   Krzysztof Helt   cirrusfb: do not ...
439
  /* Check if the MCLK is not a better clock source */
75ed3a17a   Krzysztof Helt   cirrusfb: convert...
440
  static int cirrusfb_check_mclk(struct fb_info *info, long freq)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
441
  {
75ed3a17a   Krzysztof Helt   cirrusfb: convert...
442
  	struct cirrusfb_info *cinfo = info->par;
486ff387c   Krzysztof Helt   cirrusfb: do not ...
443
  	long mclk = vga_rseq(cinfo->regbase, CL_SEQR1F) & 0x3f;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
444

486ff387c   Krzysztof Helt   cirrusfb: do not ...
445
446
  	/* Read MCLK value */
  	mclk = (14318 * mclk) >> 3;
75ed3a17a   Krzysztof Helt   cirrusfb: convert...
447
448
  	dev_dbg(info->device, "Read MCLK of %ld kHz
  ", mclk);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
449
450
  
  	/* Determine if we should use MCLK instead of VCLK, and if so, what we
486ff387c   Krzysztof Helt   cirrusfb: do not ...
451
452
453
454
  	 * should divide it by to get VCLK
  	 */
  
  	if (abs(freq - mclk) < 250) {
75ed3a17a   Krzysztof Helt   cirrusfb: convert...
455
456
  		dev_dbg(info->device, "Using VCLK = MCLK
  ");
486ff387c   Krzysztof Helt   cirrusfb: do not ...
457
458
  		return 1;
  	} else if (abs(freq - (mclk / 2)) < 250) {
75ed3a17a   Krzysztof Helt   cirrusfb: convert...
459
460
  		dev_dbg(info->device, "Using VCLK = MCLK/2
  ");
486ff387c   Krzysztof Helt   cirrusfb: do not ...
461
  		return 2;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
462
  	}
486ff387c   Krzysztof Helt   cirrusfb: do not ...
463
  	return 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
464
  }
99a458475   Krzysztof Helt   cirrusfb: check_v...
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
  static int cirrusfb_check_pixclock(const struct fb_var_screeninfo *var,
  				   struct fb_info *info)
  {
  	long freq;
  	long maxclock;
  	struct cirrusfb_info *cinfo = info->par;
  	unsigned maxclockidx = var->bits_per_pixel >> 3;
  
  	/* convert from ps to kHz */
  	freq = PICOS2KHZ(var->pixclock);
  
  	dev_dbg(info->device, "desired pixclock: %ld kHz
  ", freq);
  
  	maxclock = cirrusfb_board_info[cinfo->btype].maxclock[maxclockidx];
  	cinfo->multiplexing = 0;
  
  	/* If the frequency is greater than we can support, we might be able
  	 * to use multiplexing for the video mode */
  	if (freq > maxclock) {
dd14f71cc   Krzysztof Helt   cirrusfb: fix clo...
485
486
487
488
489
490
491
492
493
494
495
  		dev_err(info->device,
  			"Frequency greater than maxclock (%ld kHz)
  ",
  			maxclock);
  		return -EINVAL;
  	}
  	/*
  	 * Additional constraint: 8bpp uses DAC clock doubling to allow maximum
  	 * pixel clock
  	 */
  	if (var->bits_per_pixel == 8) {
99a458475   Krzysztof Helt   cirrusfb: check_v...
496
497
  		switch (cinfo->btype) {
  		case BT_ALPINE:
8f19e15b8   Krzysztof Helt   cirrusfb: set MCL...
498
  		case BT_SD64:
dd14f71cc   Krzysztof Helt   cirrusfb: fix clo...
499
500
501
502
  		case BT_PICASSO4:
  			if (freq > 85500)
  				cinfo->multiplexing = 1;
  			break;
99a458475   Krzysztof Helt   cirrusfb: check_v...
503
  		case BT_GD5480:
dd14f71cc   Krzysztof Helt   cirrusfb: fix clo...
504
505
  			if (freq > 135100)
  				cinfo->multiplexing = 1;
99a458475   Krzysztof Helt   cirrusfb: check_v...
506
507
508
  			break;
  
  		default:
8f19e15b8   Krzysztof Helt   cirrusfb: set MCL...
509
  			break;
99a458475   Krzysztof Helt   cirrusfb: check_v...
510
511
  		}
  	}
df3aafd57   Krzysztof Helt   cirrusfb: GD5434 ...
512
513
  
  	/* If we have a 1MB 5434, we need to put ourselves in a mode where
99a458475   Krzysztof Helt   cirrusfb: check_v...
514
  	 * the VCLK is double the pixel clock. */
df3aafd57   Krzysztof Helt   cirrusfb: GD5434 ...
515
516
517
518
  	cinfo->doubleVCLK = 0;
  	if (cinfo->btype == BT_SD64 && info->fix.smem_len <= MB_ &&
  	    var->bits_per_pixel == 16) {
  		cinfo->doubleVCLK = 1;
99a458475   Krzysztof Helt   cirrusfb: check_v...
519
  	}
df3aafd57   Krzysztof Helt   cirrusfb: GD5434 ...
520

99a458475   Krzysztof Helt   cirrusfb: check_v...
521
522
  	return 0;
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
523
524
525
  static int cirrusfb_check_var(struct fb_var_screeninfo *var,
  			      struct fb_info *info)
  {
09a2910e5   Krzysztof Helt   cirrusfb: check_p...
526
527
528
  	int yres;
  	/* memory size in pixels */
  	unsigned pixels = info->screen_size * 8 / var->bits_per_pixel;
614c0dc93   Krzysztof Helt   cirrusfb: add acc...
529
  	struct cirrusfb_info *cinfo = info->par;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
530
531
  
  	switch (var->bits_per_pixel) {
060b6002b   Krzysztof Helt   cirrusfb: code im...
532
  	case 1:
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
533
534
  		var->red.offset = 0;
  		var->red.length = 1;
060b6002b   Krzysztof Helt   cirrusfb: code im...
535
536
  		var->green = var->red;
  		var->blue = var->red;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
537
538
539
540
  		break;
  
  	case 8:
  		var->red.offset = 0;
99a458475   Krzysztof Helt   cirrusfb: check_v...
541
  		var->red.length = 8;
060b6002b   Krzysztof Helt   cirrusfb: code im...
542
543
  		var->green = var->red;
  		var->blue = var->red;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
544
545
546
  		break;
  
  	case 16:
8503df659   Krzysztof Helt   cirrusfb: checkpa...
547
  		if (isPReP) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
548
549
550
551
  			var->red.offset = 2;
  			var->green.offset = -3;
  			var->blue.offset = 8;
  		} else {
c4dec3962   Krzysztof Helt   cirrusfb: use 5-6...
552
  			var->red.offset = 11;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
553
554
555
556
  			var->green.offset = 5;
  			var->blue.offset = 0;
  		}
  		var->red.length = 5;
c4dec3962   Krzysztof Helt   cirrusfb: use 5-6...
557
  		var->green.length = 6;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
558
559
  		var->blue.length = 5;
  		break;
7cade31ca   Krzysztof Helt   cirrusfb: use 24b...
560
  	case 24:
8503df659   Krzysztof Helt   cirrusfb: checkpa...
561
  		if (isPReP) {
7cade31ca   Krzysztof Helt   cirrusfb: use 24b...
562
563
564
  			var->red.offset = 0;
  			var->green.offset = 8;
  			var->blue.offset = 16;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
565
566
567
568
569
570
571
572
573
574
575
  		} else {
  			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:
75ed3a17a   Krzysztof Helt   cirrusfb: convert...
576
577
578
  		dev_dbg(info->device,
  			"Unsupported bpp size: %d
  ", var->bits_per_pixel);
0efb2a03a   Krzysztof Helt   cirrusfb: do not ...
579
  		return -EINVAL;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
580
  	}
75ed3a17a   Krzysztof Helt   cirrusfb: convert...
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
  	if (var->xres_virtual < var->xres)
  		var->xres_virtual = var->xres;
  	/* use highest possible virtual resolution */
  	if (var->yres_virtual == -1) {
  		var->yres_virtual = pixels / var->xres_virtual;
  
  		dev_info(info->device,
  			 "virtual resolution set to maximum of %dx%d
  ",
  			 var->xres_virtual, var->yres_virtual);
  	}
  	if (var->yres_virtual < var->yres)
  		var->yres_virtual = var->yres;
  
  	if (var->xres_virtual * var->yres_virtual > pixels) {
  		dev_err(info->device, "mode %dx%dx%d rejected... "
  		      "virtual resolution too high to fit into video memory!
  ",
  			var->xres_virtual, var->yres_virtual,
  			var->bits_per_pixel);
  		return -EINVAL;
  	}
75ed3a17a   Krzysztof Helt   cirrusfb: convert...
603
604
605
606
607
608
609
610
611
612
  	if (var->xoffset < 0)
  		var->xoffset = 0;
  	if (var->yoffset < 0)
  		var->yoffset = 0;
  
  	/* truncate xoffset and yoffset to maximum if too high */
  	if (var->xoffset > var->xres_virtual - var->xres)
  		var->xoffset = var->xres_virtual - var->xres - 1;
  	if (var->yoffset > var->yres_virtual - var->yres)
  		var->yoffset = var->yres_virtual - var->yres - 1;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
613
614
615
616
617
618
619
620
621
622
623
624
625
626
  	var->red.msb_right =
  	    var->green.msb_right =
  	    var->blue.msb_right =
  	    var->transp.offset =
  	    var->transp.length =
  	    var->transp.msb_right = 0;
  
  	yres = var->yres;
  	if (var->vmode & FB_VMODE_DOUBLE)
  		yres *= 2;
  	else if (var->vmode & FB_VMODE_INTERLACED)
  		yres = (yres + 1) / 2;
  
  	if (yres >= 1280) {
75ed3a17a   Krzysztof Helt   cirrusfb: convert...
627
  		dev_err(info->device, "ERROR: VerticalTotal >= 1280; "
8503df659   Krzysztof Helt   cirrusfb: checkpa...
628
629
  			"special treatment required! (TODO)
  ");
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
630
631
  		return -EINVAL;
  	}
99a458475   Krzysztof Helt   cirrusfb: check_v...
632
633
  	if (cirrusfb_check_pixclock(var, info))
  		return -EINVAL;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
634

614c0dc93   Krzysztof Helt   cirrusfb: add acc...
635
636
  	if (!is_laguna(cinfo))
  		var->accel_flags = FB_ACCELF_TEXT;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
637
638
  	return 0;
  }
75ed3a17a   Krzysztof Helt   cirrusfb: convert...
639
  static void cirrusfb_set_mclk_as_source(const struct fb_info *info, int div)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
640
  {
75ed3a17a   Krzysztof Helt   cirrusfb: convert...
641
  	struct cirrusfb_info *cinfo = info->par;
486ff387c   Krzysztof Helt   cirrusfb: do not ...
642
  	unsigned char old1f, old1e;
75ed3a17a   Krzysztof Helt   cirrusfb: convert...
643

8503df659   Krzysztof Helt   cirrusfb: checkpa...
644
  	assert(cinfo != NULL);
486ff387c   Krzysztof Helt   cirrusfb: do not ...
645
646
647
  	old1f = vga_rseq(cinfo->regbase, CL_SEQR1F) & ~0x40;
  
  	if (div) {
75ed3a17a   Krzysztof Helt   cirrusfb: convert...
648
649
650
  		dev_dbg(info->device, "Set %s as pixclock source.
  ",
  			(div == 2) ? "MCLK/2" : "MCLK");
486ff387c   Krzysztof Helt   cirrusfb: do not ...
651
652
653
654
  		old1f |= 0x40;
  		old1e = vga_rseq(cinfo->regbase, CL_SEQR1E) & ~0x1;
  		if (div == 2)
  			old1e |= 1;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
655

486ff387c   Krzysztof Helt   cirrusfb: do not ...
656
  		vga_wseq(cinfo->regbase, CL_SEQR1E, old1e);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
657
  	}
486ff387c   Krzysztof Helt   cirrusfb: do not ...
658
  	vga_wseq(cinfo->regbase, CL_SEQR1F, old1f);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
659
660
661
662
663
664
665
  }
  
  /*************************************************************************
  	cirrusfb_set_par_foo()
  
  	actually writes the values for a new video mode into the hardware,
  **************************************************************************/
8503df659   Krzysztof Helt   cirrusfb: checkpa...
666
  static int cirrusfb_set_par_foo(struct fb_info *info)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
667
668
669
  {
  	struct cirrusfb_info *cinfo = info->par;
  	struct fb_var_screeninfo *var = &info->var;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
670
671
  	u8 __iomem *regbase = cinfo->regbase;
  	unsigned char tmp;
6683e01e2   Krzysztof Helt   cirrusfb: do not ...
672
  	int pitch;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
673
  	const struct cirrusfb_board_info_rec *bi;
9a85cf51f   Krzysztof Helt   cirrusfb: elimina...
674
675
  	int hdispend, hsyncstart, hsyncend, htotal;
  	int yres, vdispend, vsyncstart, vsyncend, vtotal;
dafa32c5a   Krzysztof Helt   cirrusfb: drop cl...
676
677
  	long freq;
  	int nom, den, div;
1b48cb563   Krzysztof Helt   cirrusfb: Laguna ...
678
  	unsigned int control = 0, format = 0, threshold = 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
679

75ed3a17a   Krzysztof Helt   cirrusfb: convert...
680
681
  	dev_dbg(info->device, "Requested mode: %dx%dx%d
  ",
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
682
  	       var->xres, var->yres, var->bits_per_pixel);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
683

99a458475   Krzysztof Helt   cirrusfb: check_v...
684
685
686
687
688
  	switch (var->bits_per_pixel) {
  	case 1:
  		info->fix.line_length = var->xres_virtual / 8;
  		info->fix.visual = FB_VISUAL_MONO10;
  		break;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
689

99a458475   Krzysztof Helt   cirrusfb: check_v...
690
691
692
693
694
695
  	case 8:
  		info->fix.line_length = var->xres_virtual;
  		info->fix.visual = FB_VISUAL_PSEUDOCOLOR;
  		break;
  
  	case 16:
7cade31ca   Krzysztof Helt   cirrusfb: use 24b...
696
  	case 24:
99a458475   Krzysztof Helt   cirrusfb: check_v...
697
698
699
700
  		info->fix.line_length = var->xres_virtual *
  					var->bits_per_pixel >> 3;
  		info->fix.visual = FB_VISUAL_TRUECOLOR;
  		break;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
701
  	}
99a458475   Krzysztof Helt   cirrusfb: check_v...
702
703
704
  	info->fix.type = FB_TYPE_PACKED_PIXELS;
  
  	init_vgachip(info);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
705
706
  
  	bi = &cirrusfb_board_info[cinfo->btype];
9a85cf51f   Krzysztof Helt   cirrusfb: elimina...
707
708
  	hsyncstart = var->xres + var->right_margin;
  	hsyncend = hsyncstart + var->hsync_len;
8636a9240   Krzysztof Helt   cirrusfb: fix int...
709
710
711
712
  	htotal = (hsyncend + var->left_margin) / 8;
  	hdispend = var->xres / 8;
  	hsyncstart = hsyncstart / 8;
  	hsyncend = hsyncend / 8;
9a85cf51f   Krzysztof Helt   cirrusfb: elimina...
713

8636a9240   Krzysztof Helt   cirrusfb: fix int...
714
715
  	vdispend = var->yres;
  	vsyncstart = vdispend + var->lower_margin;
9a85cf51f   Krzysztof Helt   cirrusfb: elimina...
716
717
  	vsyncend = vsyncstart + var->vsync_len;
  	vtotal = vsyncend + var->upper_margin;
9a85cf51f   Krzysztof Helt   cirrusfb: elimina...
718
719
  
  	if (var->vmode & FB_VMODE_DOUBLE) {
8636a9240   Krzysztof Helt   cirrusfb: fix int...
720
  		vdispend *= 2;
9a85cf51f   Krzysztof Helt   cirrusfb: elimina...
721
722
723
724
  		vsyncstart *= 2;
  		vsyncend *= 2;
  		vtotal *= 2;
  	} else if (var->vmode & FB_VMODE_INTERLACED) {
8636a9240   Krzysztof Helt   cirrusfb: fix int...
725
  		vdispend = (vdispend + 1) / 2;
9a85cf51f   Krzysztof Helt   cirrusfb: elimina...
726
727
728
729
  		vsyncstart = (vsyncstart + 1) / 2;
  		vsyncend = (vsyncend + 1) / 2;
  		vtotal = (vtotal + 1) / 2;
  	}
8636a9240   Krzysztof Helt   cirrusfb: fix int...
730
  	yres = vdispend;
9a85cf51f   Krzysztof Helt   cirrusfb: elimina...
731
732
733
734
735
736
  	if (yres >= 1024) {
  		vtotal /= 2;
  		vsyncstart /= 2;
  		vsyncend /= 2;
  		vdispend /= 2;
  	}
8636a9240   Krzysztof Helt   cirrusfb: fix int...
737
738
739
740
741
  
  	vdispend -= 1;
  	vsyncstart -= 1;
  	vsyncend -= 1;
  	vtotal -= 2;
48c329e90   Krzysztof Helt   cirrusfb: various...
742
  	if (cinfo->multiplexing) {
9a85cf51f   Krzysztof Helt   cirrusfb: elimina...
743
744
745
746
747
  		htotal /= 2;
  		hsyncstart /= 2;
  		hsyncend /= 2;
  		hdispend /= 2;
  	}
8636a9240   Krzysztof Helt   cirrusfb: fix int...
748
749
750
751
752
  
  	htotal -= 5;
  	hdispend -= 1;
  	hsyncstart += 1;
  	hsyncend += 1;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
753
  	/* unlock register VGA_CRTC_H_TOTAL..CRT7 */
8503df659   Krzysztof Helt   cirrusfb: checkpa...
754
  	vga_wcrt(regbase, VGA_CRTC_V_SYNC_END, 0x20);	/* previously: 0x00) */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
755
756
  
  	/* if debugging is enabled, all parameters get output before writing */
75ed3a17a   Krzysztof Helt   cirrusfb: convert...
757
758
  	dev_dbg(info->device, "CRT0: %d
  ", htotal);
9a85cf51f   Krzysztof Helt   cirrusfb: elimina...
759
  	vga_wcrt(regbase, VGA_CRTC_H_TOTAL, htotal);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
760

75ed3a17a   Krzysztof Helt   cirrusfb: convert...
761
762
  	dev_dbg(info->device, "CRT1: %d
  ", hdispend);
9a85cf51f   Krzysztof Helt   cirrusfb: elimina...
763
  	vga_wcrt(regbase, VGA_CRTC_H_DISP, hdispend);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
764

75ed3a17a   Krzysztof Helt   cirrusfb: convert...
765
766
  	dev_dbg(info->device, "CRT2: %d
  ", var->xres / 8);
9a85cf51f   Krzysztof Helt   cirrusfb: elimina...
767
  	vga_wcrt(regbase, VGA_CRTC_H_BLANK_START, var->xres / 8);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
768

8503df659   Krzysztof Helt   cirrusfb: checkpa...
769
  	/*  + 128: Compatible read */
75ed3a17a   Krzysztof Helt   cirrusfb: convert...
770
771
  	dev_dbg(info->device, "CRT3: 128+%d
  ", (htotal + 5) % 32);
8503df659   Krzysztof Helt   cirrusfb: checkpa...
772
  	vga_wcrt(regbase, VGA_CRTC_H_BLANK_END,
9a85cf51f   Krzysztof Helt   cirrusfb: elimina...
773
  		 128 + ((htotal + 5) % 32));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
774

75ed3a17a   Krzysztof Helt   cirrusfb: convert...
775
776
  	dev_dbg(info->device, "CRT4: %d
  ", hsyncstart);
9a85cf51f   Krzysztof Helt   cirrusfb: elimina...
777
  	vga_wcrt(regbase, VGA_CRTC_H_SYNC_START, hsyncstart);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
778

9a85cf51f   Krzysztof Helt   cirrusfb: elimina...
779
780
  	tmp = hsyncend % 32;
  	if ((htotal + 5) & 32)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
781
  		tmp += 128;
75ed3a17a   Krzysztof Helt   cirrusfb: convert...
782
783
  	dev_dbg(info->device, "CRT5: %d
  ", tmp);
8503df659   Krzysztof Helt   cirrusfb: checkpa...
784
  	vga_wcrt(regbase, VGA_CRTC_H_SYNC_END, tmp);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
785

75ed3a17a   Krzysztof Helt   cirrusfb: convert...
786
787
  	dev_dbg(info->device, "CRT6: %d
  ", vtotal & 0xff);
9a85cf51f   Krzysztof Helt   cirrusfb: elimina...
788
  	vga_wcrt(regbase, VGA_CRTC_V_TOTAL, vtotal & 0xff);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
789
790
  
  	tmp = 16;		/* LineCompare bit #9 */
9a85cf51f   Krzysztof Helt   cirrusfb: elimina...
791
  	if (vtotal & 256)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
792
  		tmp |= 1;
9a85cf51f   Krzysztof Helt   cirrusfb: elimina...
793
  	if (vdispend & 256)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
794
  		tmp |= 2;
9a85cf51f   Krzysztof Helt   cirrusfb: elimina...
795
  	if (vsyncstart & 256)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
796
  		tmp |= 4;
9a85cf51f   Krzysztof Helt   cirrusfb: elimina...
797
  	if ((vdispend + 1) & 256)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
798
  		tmp |= 8;
9a85cf51f   Krzysztof Helt   cirrusfb: elimina...
799
  	if (vtotal & 512)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
800
  		tmp |= 32;
9a85cf51f   Krzysztof Helt   cirrusfb: elimina...
801
  	if (vdispend & 512)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
802
  		tmp |= 64;
9a85cf51f   Krzysztof Helt   cirrusfb: elimina...
803
  	if (vsyncstart & 512)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
804
  		tmp |= 128;
75ed3a17a   Krzysztof Helt   cirrusfb: convert...
805
806
  	dev_dbg(info->device, "CRT7: %d
  ", tmp);
8503df659   Krzysztof Helt   cirrusfb: checkpa...
807
  	vga_wcrt(regbase, VGA_CRTC_OVERFLOW, tmp);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
808
809
  
  	tmp = 0x40;		/* LineCompare bit #8 */
9a85cf51f   Krzysztof Helt   cirrusfb: elimina...
810
  	if ((vdispend + 1) & 512)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
811
812
813
  		tmp |= 0x20;
  	if (var->vmode & FB_VMODE_DOUBLE)
  		tmp |= 0x80;
75ed3a17a   Krzysztof Helt   cirrusfb: convert...
814
815
  	dev_dbg(info->device, "CRT9: %d
  ", tmp);
8503df659   Krzysztof Helt   cirrusfb: checkpa...
816
  	vga_wcrt(regbase, VGA_CRTC_MAX_SCAN, tmp);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
817

75ed3a17a   Krzysztof Helt   cirrusfb: convert...
818
819
  	dev_dbg(info->device, "CRT10: %d
  ", vsyncstart & 0xff);
9a85cf51f   Krzysztof Helt   cirrusfb: elimina...
820
  	vga_wcrt(regbase, VGA_CRTC_V_SYNC_START, vsyncstart & 0xff);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
821

75ed3a17a   Krzysztof Helt   cirrusfb: convert...
822
823
  	dev_dbg(info->device, "CRT11: 64+32+%d
  ", vsyncend % 16);
9a85cf51f   Krzysztof Helt   cirrusfb: elimina...
824
  	vga_wcrt(regbase, VGA_CRTC_V_SYNC_END, vsyncend % 16 + 64 + 32);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
825

75ed3a17a   Krzysztof Helt   cirrusfb: convert...
826
827
  	dev_dbg(info->device, "CRT12: %d
  ", vdispend & 0xff);
9a85cf51f   Krzysztof Helt   cirrusfb: elimina...
828
  	vga_wcrt(regbase, VGA_CRTC_V_DISP_END, vdispend & 0xff);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
829

75ed3a17a   Krzysztof Helt   cirrusfb: convert...
830
831
  	dev_dbg(info->device, "CRT15: %d
  ", (vdispend + 1) & 0xff);
9a85cf51f   Krzysztof Helt   cirrusfb: elimina...
832
  	vga_wcrt(regbase, VGA_CRTC_V_BLANK_START, (vdispend + 1) & 0xff);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
833

75ed3a17a   Krzysztof Helt   cirrusfb: convert...
834
835
  	dev_dbg(info->device, "CRT16: %d
  ", vtotal & 0xff);
9a85cf51f   Krzysztof Helt   cirrusfb: elimina...
836
  	vga_wcrt(regbase, VGA_CRTC_V_BLANK_END, vtotal & 0xff);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
837

75ed3a17a   Krzysztof Helt   cirrusfb: convert...
838
839
  	dev_dbg(info->device, "CRT18: 0xff
  ");
8503df659   Krzysztof Helt   cirrusfb: checkpa...
840
  	vga_wcrt(regbase, VGA_CRTC_LINE_COMPARE, 0xff);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
841
842
843
844
  
  	tmp = 0;
  	if (var->vmode & FB_VMODE_INTERLACED)
  		tmp |= 1;
9a85cf51f   Krzysztof Helt   cirrusfb: elimina...
845
  	if ((htotal + 5) & 64)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
846
  		tmp |= 16;
9a85cf51f   Krzysztof Helt   cirrusfb: elimina...
847
  	if ((htotal + 5) & 128)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
848
  		tmp |= 32;
9a85cf51f   Krzysztof Helt   cirrusfb: elimina...
849
  	if (vtotal & 256)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
850
  		tmp |= 64;
9a85cf51f   Krzysztof Helt   cirrusfb: elimina...
851
  	if (vtotal & 512)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
852
  		tmp |= 128;
75ed3a17a   Krzysztof Helt   cirrusfb: convert...
853
854
  	dev_dbg(info->device, "CRT1a: %d
  ", tmp);
8503df659   Krzysztof Helt   cirrusfb: checkpa...
855
  	vga_wcrt(regbase, CL_CRT1A, tmp);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
856

dafa32c5a   Krzysztof Helt   cirrusfb: drop cl...
857
  	freq = PICOS2KHZ(var->pixclock);
df3aafd57   Krzysztof Helt   cirrusfb: GD5434 ...
858
859
860
  	if (var->bits_per_pixel == 24)
  		if (cinfo->btype == BT_ALPINE || cinfo->btype == BT_SD64)
  			freq *= 3;
dd14f71cc   Krzysztof Helt   cirrusfb: fix clo...
861
862
  	if (cinfo->multiplexing)
  		freq /= 2;
df3aafd57   Krzysztof Helt   cirrusfb: GD5434 ...
863
864
  	if (cinfo->doubleVCLK)
  		freq *= 2;
7cade31ca   Krzysztof Helt   cirrusfb: use 24b...
865

dafa32c5a   Krzysztof Helt   cirrusfb: drop cl...
866
  	bestclock(freq, &nom, &den, &div);
75ed3a17a   Krzysztof Helt   cirrusfb: convert...
867
868
869
  	dev_dbg(info->device, "VCLK freq: %ld kHz  nom: %d  den: %d  div: %d
  ",
  		freq, nom, den, div);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
870
871
872
873
  	/* set VCLK0 */
  	/* hardware RefClock: 14.31818 MHz */
  	/* formula: VClk = (OSC * N) / (D * (1+P)) */
  	/* Example: VClk = (14.31818 * 91) / (23 * (1+1)) = 28.325 MHz */
8f19e15b8   Krzysztof Helt   cirrusfb: set MCL...
874
875
  	if (cinfo->btype == BT_ALPINE || cinfo->btype == BT_PICASSO4 ||
  	    cinfo->btype == BT_SD64) {
486ff387c   Krzysztof Helt   cirrusfb: do not ...
876
877
878
  		/* if freq is close to mclk or mclk/2 select mclk
  		 * as clock source
  		 */
75ed3a17a   Krzysztof Helt   cirrusfb: convert...
879
  		int divMCLK = cirrusfb_check_mclk(info, freq);
df3aafd57   Krzysztof Helt   cirrusfb: GD5434 ...
880
  		if (divMCLK)
486ff387c   Krzysztof Helt   cirrusfb: do not ...
881
  			nom = 0;
df3aafd57   Krzysztof Helt   cirrusfb: GD5434 ...
882
  		cirrusfb_set_mclk_as_source(info, divMCLK);
486ff387c   Krzysztof Helt   cirrusfb: do not ...
883
  	}
78d780e07   Krzysztof Helt   cirrusfb: various...
884
  	if (is_laguna(cinfo)) {
6e30fc086   Krzysztof Helt   cirrusfb: add mmi...
885
886
887
  		long pcifc = fb_readl(cinfo->laguna_mmio + 0x3fc);
  		unsigned char tile = fb_readb(cinfo->laguna_mmio + 0x407);
  		unsigned short tile_control;
78d780e07   Krzysztof Helt   cirrusfb: various...
888
889
890
891
892
  		if (cinfo->btype == BT_LAGUNAB) {
  			tile_control = fb_readw(cinfo->laguna_mmio + 0x2c4);
  			tile_control &= ~0x80;
  			fb_writew(tile_control, cinfo->laguna_mmio + 0x2c4);
  		}
6e30fc086   Krzysztof Helt   cirrusfb: add mmi...
893
894
895
896
897
898
899
  
  		fb_writel(pcifc | 0x10000000l, cinfo->laguna_mmio + 0x3fc);
  		fb_writeb(tile & 0x3f, cinfo->laguna_mmio + 0x407);
  		control = fb_readw(cinfo->laguna_mmio + 0x402);
  		threshold = fb_readw(cinfo->laguna_mmio + 0xea);
  		control &= ~0x6800;
  		format = 0;
4242a23c9   Krzysztof Helt   cirrusfb: fix thr...
900
  		threshold &= 0xffc0 & 0x3fbf;
6e30fc086   Krzysztof Helt   cirrusfb: add mmi...
901
  	}
486ff387c   Krzysztof Helt   cirrusfb: do not ...
902
  	if (nom) {
486ff387c   Krzysztof Helt   cirrusfb: do not ...
903
904
905
  		tmp = den << 1;
  		if (div != 0)
  			tmp |= 1;
486ff387c   Krzysztof Helt   cirrusfb: do not ...
906
907
908
909
910
  		/* 6 bit denom; ONLY 5434!!! (bugged me 10 days) */
  		if ((cinfo->btype == BT_SD64) ||
  		    (cinfo->btype == BT_ALPINE) ||
  		    (cinfo->btype == BT_GD5480))
  			tmp |= 0x80;
55a4ea6ab   Krzysztof Helt   cirrusfb: fix Lag...
911
  		/* Laguna chipset has reversed clock registers */
78d780e07   Krzysztof Helt   cirrusfb: various...
912
  		if (is_laguna(cinfo)) {
55a4ea6ab   Krzysztof Helt   cirrusfb: fix Lag...
913
914
915
  			vga_wseq(regbase, CL_SEQRE, tmp);
  			vga_wseq(regbase, CL_SEQR1E, nom);
  		} else {
df3aafd57   Krzysztof Helt   cirrusfb: GD5434 ...
916
917
  			vga_wseq(regbase, CL_SEQRE, nom);
  			vga_wseq(regbase, CL_SEQR1E, tmp);
55a4ea6ab   Krzysztof Helt   cirrusfb: fix Lag...
918
  		}
486ff387c   Krzysztof Helt   cirrusfb: do not ...
919
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
920

9a85cf51f   Krzysztof Helt   cirrusfb: elimina...
921
  	if (yres >= 1024)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
922
  		/* 1280x1024 */
8503df659   Krzysztof Helt   cirrusfb: checkpa...
923
  		vga_wcrt(regbase, VGA_CRTC_MODE, 0xc7);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
924
925
926
  	else
  		/* mode control: VGA_CRTC_START_HI enable, ROTATE(?), 16bit
  		 * address wrap, no compat. */
8503df659   Krzysztof Helt   cirrusfb: checkpa...
927
  		vga_wcrt(regbase, VGA_CRTC_MODE, 0xc3);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
928

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
929
930
931
  	/* don't know if it would hurt to also program this if no interlaced */
  	/* mode is used, but I feel better this way.. :-) */
  	if (var->vmode & FB_VMODE_INTERLACED)
9a85cf51f   Krzysztof Helt   cirrusfb: elimina...
932
  		vga_wcrt(regbase, VGA_CRTC_REGS, htotal / 2);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
933
  	else
8503df659   Krzysztof Helt   cirrusfb: checkpa...
934
  		vga_wcrt(regbase, VGA_CRTC_REGS, 0x00);	/* interlace control */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
935

df3aafd57   Krzysztof Helt   cirrusfb: GD5434 ...
936
  	/* adjust horizontal/vertical sync type (low/high), use VCLK3 */
8503df659   Krzysztof Helt   cirrusfb: checkpa...
937
  	/* enable display memory & CRTC I/O address for color mode */
df3aafd57   Krzysztof Helt   cirrusfb: GD5434 ...
938
  	tmp = 0x03 | 0xc;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
939
940
941
942
  	if (var->sync & FB_SYNC_HOR_HIGH_ACT)
  		tmp |= 0x40;
  	if (var->sync & FB_SYNC_VERT_HIGH_ACT)
  		tmp |= 0x80;
8503df659   Krzysztof Helt   cirrusfb: checkpa...
943
  	WGen(cinfo, VGA_MIS_W, tmp);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
944

8503df659   Krzysztof Helt   cirrusfb: checkpa...
945
946
947
948
  	/* text cursor on and start line */
  	vga_wcrt(regbase, VGA_CRTC_CURSOR_START, 0);
  	/* text cursor end line */
  	vga_wcrt(regbase, VGA_CRTC_CURSOR_END, 31);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
949
950
951
952
953
954
955
956
957
  
  	/******************************************************
  	 *
  	 * 1 bpp
  	 *
  	 */
  
  	/* programming for different color depths */
  	if (var->bits_per_pixel == 1) {
75ed3a17a   Krzysztof Helt   cirrusfb: convert...
958
959
  		dev_dbg(info->device, "preparing for 1 bit deep display
  ");
8503df659   Krzysztof Helt   cirrusfb: checkpa...
960
  		vga_wgfx(regbase, VGA_GFX_MODE, 0);	/* mode register */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
961
962
963
964
965
966
967
968
969
970
  
  		/* SR07 */
  		switch (cinfo->btype) {
  		case BT_SD64:
  		case BT_PICCOLO:
  		case BT_PICASSO:
  		case BT_SPECTRUM:
  		case BT_PICASSO4:
  		case BT_ALPINE:
  		case BT_GD5480:
8503df659   Krzysztof Helt   cirrusfb: checkpa...
971
  			vga_wseq(regbase, CL_SEQR7,
48c329e90   Krzysztof Helt   cirrusfb: various...
972
  				 cinfo->multiplexing ?
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
973
974
975
976
  					bi->sr07_1bpp_mux : bi->sr07_1bpp);
  			break;
  
  		case BT_LAGUNA:
78d780e07   Krzysztof Helt   cirrusfb: various...
977
  		case BT_LAGUNAB:
8503df659   Krzysztof Helt   cirrusfb: checkpa...
978
979
  			vga_wseq(regbase, CL_SEQR7,
  				vga_rseq(regbase, CL_SEQR7) & ~0x01);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
980
981
982
  			break;
  
  		default:
75ed3a17a   Krzysztof Helt   cirrusfb: convert...
983
984
  			dev_warn(info->device, "unknown Board
  ");
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
985
986
987
988
989
  			break;
  		}
  
  		/* Extended Sequencer Mode */
  		switch (cinfo->btype) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
990
991
  
  		case BT_PICCOLO:
060b6002b   Krzysztof Helt   cirrusfb: code im...
992
  		case BT_SPECTRUM:
8503df659   Krzysztof Helt   cirrusfb: checkpa...
993
994
  			/* evtl d0 bei 1 bit? avoid FIFO underruns..? */
  			vga_wseq(regbase, CL_SEQRF, 0xb0);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
995
996
997
  			break;
  
  		case BT_PICASSO:
8503df659   Krzysztof Helt   cirrusfb: checkpa...
998
999
  			/* ## vorher d0 avoid FIFO underruns..? */
  			vga_wseq(regbase, CL_SEQRF, 0xd0);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1000
  			break;
8f19e15b8   Krzysztof Helt   cirrusfb: set MCL...
1001
  		case BT_SD64:
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1002
1003
1004
1005
  		case BT_PICASSO4:
  		case BT_ALPINE:
  		case BT_GD5480:
  		case BT_LAGUNA:
78d780e07   Krzysztof Helt   cirrusfb: various...
1006
  		case BT_LAGUNAB:
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1007
1008
1009
1010
  			/* do nothing */
  			break;
  
  		default:
75ed3a17a   Krzysztof Helt   cirrusfb: convert...
1011
1012
  			dev_warn(info->device, "unknown Board
  ");
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1013
1014
  			break;
  		}
8503df659   Krzysztof Helt   cirrusfb: checkpa...
1015
1016
  		/* pixel mask: pass-through for first plane */
  		WGen(cinfo, VGA_PEL_MSK, 0x01);
48c329e90   Krzysztof Helt   cirrusfb: various...
1017
  		if (cinfo->multiplexing)
8503df659   Krzysztof Helt   cirrusfb: checkpa...
1018
1019
  			/* hidden dac reg: 1280x1024 */
  			WHDR(cinfo, 0x4a);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1020
  		else
8503df659   Krzysztof Helt   cirrusfb: checkpa...
1021
1022
1023
1024
1025
1026
  			/* hidden dac: nothing */
  			WHDR(cinfo, 0);
  		/* memory mode: odd/even, ext. memory */
  		vga_wseq(regbase, VGA_SEQ_MEMORY_MODE, 0x06);
  		/* plane mask: only write to first plane */
  		vga_wseq(regbase, VGA_SEQ_PLANE_WRITE, 0x01);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1027
1028
1029
1030
1031
1032
1033
1034
1035
  	}
  
  	/******************************************************
  	 *
  	 * 8 bpp
  	 *
  	 */
  
  	else if (var->bits_per_pixel == 8) {
75ed3a17a   Krzysztof Helt   cirrusfb: convert...
1036
1037
  		dev_dbg(info->device, "preparing for 8 bit deep display
  ");
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1038
1039
1040
1041
1042
1043
1044
1045
  		switch (cinfo->btype) {
  		case BT_SD64:
  		case BT_PICCOLO:
  		case BT_PICASSO:
  		case BT_SPECTRUM:
  		case BT_PICASSO4:
  		case BT_ALPINE:
  		case BT_GD5480:
8503df659   Krzysztof Helt   cirrusfb: checkpa...
1046
  			vga_wseq(regbase, CL_SEQR7,
48c329e90   Krzysztof Helt   cirrusfb: various...
1047
  				  cinfo->multiplexing ?
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1048
1049
1050
1051
  					bi->sr07_8bpp_mux : bi->sr07_8bpp);
  			break;
  
  		case BT_LAGUNA:
78d780e07   Krzysztof Helt   cirrusfb: various...
1052
  		case BT_LAGUNAB:
8503df659   Krzysztof Helt   cirrusfb: checkpa...
1053
1054
  			vga_wseq(regbase, CL_SEQR7,
  				vga_rseq(regbase, CL_SEQR7) | 0x01);
6e30fc086   Krzysztof Helt   cirrusfb: add mmi...
1055
  			threshold |= 0x10;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1056
1057
1058
  			break;
  
  		default:
75ed3a17a   Krzysztof Helt   cirrusfb: convert...
1059
1060
  			dev_warn(info->device, "unknown Board
  ");
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1061
1062
1063
1064
  			break;
  		}
  
  		switch (cinfo->btype) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1065
  		case BT_PICCOLO:
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1066
  		case BT_PICASSO:
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1067
  		case BT_SPECTRUM:
8503df659   Krzysztof Helt   cirrusfb: checkpa...
1068
1069
  			/* Fast Page-Mode writes */
  			vga_wseq(regbase, CL_SEQRF, 0xb0);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1070
1071
1072
1073
  			break;
  
  		case BT_PICASSO4:
  #ifdef CONFIG_ZORRO
8503df659   Krzysztof Helt   cirrusfb: checkpa...
1074
1075
  			/* ### INCOMPLETE!! */
  			vga_wseq(regbase, CL_SEQRF, 0xb8);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1076
  #endif
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1077
  		case BT_ALPINE:
8f19e15b8   Krzysztof Helt   cirrusfb: set MCL...
1078
  		case BT_SD64:
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1079
1080
  		case BT_GD5480:
  		case BT_LAGUNA:
78d780e07   Krzysztof Helt   cirrusfb: various...
1081
  		case BT_LAGUNAB:
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1082
1083
1084
1085
  			/* do nothing */
  			break;
  
  		default:
75ed3a17a   Krzysztof Helt   cirrusfb: convert...
1086
1087
  			dev_warn(info->device, "unknown board
  ");
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1088
1089
  			break;
  		}
8503df659   Krzysztof Helt   cirrusfb: checkpa...
1090
1091
  		/* mode register: 256 color mode */
  		vga_wgfx(regbase, VGA_GFX_MODE, 64);
48c329e90   Krzysztof Helt   cirrusfb: various...
1092
  		if (cinfo->multiplexing)
8503df659   Krzysztof Helt   cirrusfb: checkpa...
1093
1094
  			/* hidden dac reg: 1280x1024 */
  			WHDR(cinfo, 0x4a);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1095
  		else
8503df659   Krzysztof Helt   cirrusfb: checkpa...
1096
1097
  			/* hidden dac: nothing */
  			WHDR(cinfo, 0);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1098
1099
1100
1101
1102
1103
1104
1105
1106
  	}
  
  	/******************************************************
  	 *
  	 * 16 bpp
  	 *
  	 */
  
  	else if (var->bits_per_pixel == 16) {
75ed3a17a   Krzysztof Helt   cirrusfb: convert...
1107
1108
  		dev_dbg(info->device, "preparing for 16 bit deep display
  ");
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1109
  		switch (cinfo->btype) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1110
  		case BT_PICCOLO:
060b6002b   Krzysztof Helt   cirrusfb: code im...
1111
  		case BT_SPECTRUM:
8503df659   Krzysztof Helt   cirrusfb: checkpa...
1112
1113
1114
  			vga_wseq(regbase, CL_SEQR7, 0x87);
  			/* Fast Page-Mode writes */
  			vga_wseq(regbase, CL_SEQRF, 0xb0);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1115
1116
1117
  			break;
  
  		case BT_PICASSO:
8503df659   Krzysztof Helt   cirrusfb: checkpa...
1118
1119
1120
  			vga_wseq(regbase, CL_SEQR7, 0x27);
  			/* Fast Page-Mode writes */
  			vga_wseq(regbase, CL_SEQRF, 0xb0);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1121
  			break;
8f19e15b8   Krzysztof Helt   cirrusfb: set MCL...
1122
  		case BT_SD64:
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1123
  		case BT_PICASSO4:
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1124
  		case BT_ALPINE:
8f19e15b8   Krzysztof Helt   cirrusfb: set MCL...
1125
  			/* Extended Sequencer Mode: 256c col. mode */
df3aafd57   Krzysztof Helt   cirrusfb: GD5434 ...
1126
1127
  			vga_wseq(regbase, CL_SEQR7,
  					cinfo->doubleVCLK ? 0xa3 : 0xa7);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1128
1129
1130
  			break;
  
  		case BT_GD5480:
8503df659   Krzysztof Helt   cirrusfb: checkpa...
1131
  			vga_wseq(regbase, CL_SEQR7, 0x17);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1132
1133
1134
1135
  			/* We already set SRF and SR1F */
  			break;
  
  		case BT_LAGUNA:
78d780e07   Krzysztof Helt   cirrusfb: various...
1136
  		case BT_LAGUNAB:
8503df659   Krzysztof Helt   cirrusfb: checkpa...
1137
1138
  			vga_wseq(regbase, CL_SEQR7,
  				vga_rseq(regbase, CL_SEQR7) & ~0x01);
6e30fc086   Krzysztof Helt   cirrusfb: add mmi...
1139
1140
1141
  			control |= 0x2000;
  			format |= 0x1400;
  			threshold |= 0x10;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1142
1143
1144
  			break;
  
  		default:
75ed3a17a   Krzysztof Helt   cirrusfb: convert...
1145
1146
  			dev_warn(info->device, "unknown Board
  ");
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1147
1148
  			break;
  		}
8503df659   Krzysztof Helt   cirrusfb: checkpa...
1149
1150
  		/* mode register: 256 color mode */
  		vga_wgfx(regbase, VGA_GFX_MODE, 64);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1151
  #ifdef CONFIG_PCI
df3aafd57   Krzysztof Helt   cirrusfb: GD5434 ...
1152
  		WHDR(cinfo, cinfo->doubleVCLK ? 0xe1 : 0xc1);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1153
1154
  #elif defined(CONFIG_ZORRO)
  		/* FIXME: CONFIG_PCI and CONFIG_ZORRO may be defined both */
8503df659   Krzysztof Helt   cirrusfb: checkpa...
1155
  		WHDR(cinfo, 0xa0);	/* hidden dac reg: nothing special */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1156
  #endif
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1157
1158
1159
1160
  	}
  
  	/******************************************************
  	 *
7cade31ca   Krzysztof Helt   cirrusfb: use 24b...
1161
  	 * 24 bpp
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1162
1163
  	 *
  	 */
7cade31ca   Krzysztof Helt   cirrusfb: use 24b...
1164
1165
1166
  	else if (var->bits_per_pixel == 24) {
  		dev_dbg(info->device, "preparing for 24 bit deep display
  ");
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1167
  		switch (cinfo->btype) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1168
  		case BT_PICCOLO:
060b6002b   Krzysztof Helt   cirrusfb: code im...
1169
  		case BT_SPECTRUM:
8503df659   Krzysztof Helt   cirrusfb: checkpa...
1170
1171
1172
  			vga_wseq(regbase, CL_SEQR7, 0x85);
  			/* Fast Page-Mode writes */
  			vga_wseq(regbase, CL_SEQRF, 0xb0);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1173
1174
1175
  			break;
  
  		case BT_PICASSO:
8503df659   Krzysztof Helt   cirrusfb: checkpa...
1176
1177
1178
  			vga_wseq(regbase, CL_SEQR7, 0x25);
  			/* Fast Page-Mode writes */
  			vga_wseq(regbase, CL_SEQRF, 0xb0);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1179
  			break;
8f19e15b8   Krzysztof Helt   cirrusfb: set MCL...
1180
  		case BT_SD64:
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1181
  		case BT_PICASSO4:
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1182
  		case BT_ALPINE:
8f19e15b8   Krzysztof Helt   cirrusfb: set MCL...
1183
  			/* Extended Sequencer Mode: 256c col. mode */
7cade31ca   Krzysztof Helt   cirrusfb: use 24b...
1184
  			vga_wseq(regbase, CL_SEQR7, 0xa5);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1185
1186
1187
  			break;
  
  		case BT_GD5480:
7cade31ca   Krzysztof Helt   cirrusfb: use 24b...
1188
  			vga_wseq(regbase, CL_SEQR7, 0x15);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1189
1190
1191
1192
  			/* We already set SRF and SR1F */
  			break;
  
  		case BT_LAGUNA:
78d780e07   Krzysztof Helt   cirrusfb: various...
1193
  		case BT_LAGUNAB:
8503df659   Krzysztof Helt   cirrusfb: checkpa...
1194
1195
  			vga_wseq(regbase, CL_SEQR7,
  				vga_rseq(regbase, CL_SEQR7) & ~0x01);
7cade31ca   Krzysztof Helt   cirrusfb: use 24b...
1196
1197
  			control |= 0x4000;
  			format |= 0x2400;
6e30fc086   Krzysztof Helt   cirrusfb: add mmi...
1198
  			threshold |= 0x20;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1199
1200
1201
  			break;
  
  		default:
75ed3a17a   Krzysztof Helt   cirrusfb: convert...
1202
1203
  			dev_warn(info->device, "unknown Board
  ");
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1204
1205
  			break;
  		}
8503df659   Krzysztof Helt   cirrusfb: checkpa...
1206
1207
  		/* mode register: 256 color mode */
  		vga_wgfx(regbase, VGA_GFX_MODE, 64);
8503df659   Krzysztof Helt   cirrusfb: checkpa...
1208
1209
  		/* hidden dac reg: 8-8-8 mode (24 or 32) */
  		WHDR(cinfo, 0xc5);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1210
1211
1212
1213
1214
1215
1216
  	}
  
  	/******************************************************
  	 *
  	 * unknown/unsupported bpp
  	 *
  	 */
8503df659   Krzysztof Helt   cirrusfb: checkpa...
1217
  	else
75ed3a17a   Krzysztof Helt   cirrusfb: convert...
1218
1219
1220
  		dev_err(info->device,
  			"What's this? requested color depth == %d.
  ",
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1221
  			var->bits_per_pixel);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1222

6683e01e2   Krzysztof Helt   cirrusfb: do not ...
1223
1224
  	pitch = info->fix.line_length >> 3;
  	vga_wcrt(regbase, VGA_CRTC_OFFSET, pitch & 0xff);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1225
  	tmp = 0x22;
6683e01e2   Krzysztof Helt   cirrusfb: do not ...
1226
  	if (pitch & 0x100)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1227
  		tmp |= 0x10;	/* offset overflow bit */
8503df659   Krzysztof Helt   cirrusfb: checkpa...
1228
1229
  	/* screen start addr #16-18, fastpagemode cycles */
  	vga_wcrt(regbase, CL_CRT1B, tmp);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1230

213d4bdd8   Krzysztof Helt   cirrusfb: add Lag...
1231
1232
  	/* screen start address bit 19 */
  	if (cirrusfb_board_info[cinfo->btype].scrn_start_bit19)
6683e01e2   Krzysztof Helt   cirrusfb: do not ...
1233
  		vga_wcrt(regbase, CL_CRT1D, (pitch >> 9) & 1);
8503df659   Krzysztof Helt   cirrusfb: checkpa...
1234

78d780e07   Krzysztof Helt   cirrusfb: various...
1235
  	if (is_laguna(cinfo)) {
213d4bdd8   Krzysztof Helt   cirrusfb: add Lag...
1236
1237
1238
1239
1240
1241
1242
1243
1244
1245
1246
1247
1248
1249
1250
1251
1252
1253
  		tmp = 0;
  		if ((htotal + 5) & 256)
  			tmp |= 128;
  		if (hdispend & 256)
  			tmp |= 64;
  		if (hsyncstart & 256)
  			tmp |= 48;
  		if (vtotal & 1024)
  			tmp |= 8;
  		if (vdispend & 1024)
  			tmp |= 4;
  		if (vsyncstart & 1024)
  			tmp |= 3;
  
  		vga_wcrt(regbase, CL_CRT1E, tmp);
  		dev_dbg(info->device, "CRT1e: %d
  ", tmp);
  	}
8503df659   Krzysztof Helt   cirrusfb: checkpa...
1254
1255
  	/* pixel panning */
  	vga_wattr(regbase, CL_AR33, 0);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1256
1257
1258
  
  	/* [ EGS: SetOffset(); ] */
  	/* From SetOffset(): Turn on VideoEnable bit in Attribute controller */
8503df659   Krzysztof Helt   cirrusfb: checkpa...
1259
  	AttrOn(cinfo);
78d780e07   Krzysztof Helt   cirrusfb: various...
1260
  	if (is_laguna(cinfo)) {
6e30fc086   Krzysztof Helt   cirrusfb: add mmi...
1261
1262
1263
1264
1265
  		/* no tiles */
  		fb_writew(control | 0x1000, cinfo->laguna_mmio + 0x402);
  		fb_writew(format, cinfo->laguna_mmio + 0xc0);
  		fb_writew(threshold, cinfo->laguna_mmio + 0xea);
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1266
1267
1268
1269
1270
1271
1272
1273
  	/* finally, turn on everything - turn off "FullBandwidth" bit */
  	/* also, set "DotClock%2" bit where requested */
  	tmp = 0x01;
  
  /*** FB_VMODE_CLOCK_HALVE in linux/fb.h not defined anymore ?
      if (var->vmode & FB_VMODE_CLOCK_HALVE)
  	tmp |= 0x08;
  */
8503df659   Krzysztof Helt   cirrusfb: checkpa...
1274
  	vga_wseq(regbase, VGA_SEQ_CLOCK_MODE, tmp);
75ed3a17a   Krzysztof Helt   cirrusfb: convert...
1275
1276
  	dev_dbg(info->device, "CL_SEQR1: %d
  ", tmp);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1277

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1278
  #ifdef CIRRUSFB_DEBUG
75ed3a17a   Krzysztof Helt   cirrusfb: convert...
1279
  	cirrusfb_dbg_reg_dump(info, NULL);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1280
  #endif
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1281
1282
1283
1284
1285
  	return 0;
  }
  
  /* for some reason incomprehensible to me, cirrusfb requires that you write
   * the registers twice for the settings to take..grr. -dte */
8503df659   Krzysztof Helt   cirrusfb: checkpa...
1286
  static int cirrusfb_set_par(struct fb_info *info)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1287
  {
8503df659   Krzysztof Helt   cirrusfb: checkpa...
1288
1289
  	cirrusfb_set_par_foo(info);
  	return cirrusfb_set_par_foo(info);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1290
  }
8503df659   Krzysztof Helt   cirrusfb: checkpa...
1291
1292
1293
  static int cirrusfb_setcolreg(unsigned regno, unsigned red, unsigned green,
  			      unsigned blue, unsigned transp,
  			      struct fb_info *info)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1294
1295
1296
1297
1298
1299
1300
1301
1302
1303
1304
  {
  	struct cirrusfb_info *cinfo = info->par;
  
  	if (regno > 255)
  		return -EINVAL;
  
  	if (info->fix.visual == FB_VISUAL_TRUECOLOR) {
  		u32 v;
  		red >>= (16 - info->var.red.length);
  		green >>= (16 - info->var.green.length);
  		blue >>= (16 - info->var.blue.length);
8503df659   Krzysztof Helt   cirrusfb: checkpa...
1305
  		if (regno >= 16)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1306
1307
1308
1309
  			return 1;
  		v = (red << info->var.red.offset) |
  		    (green << info->var.green.offset) |
  		    (blue << info->var.blue.offset);
060b6002b   Krzysztof Helt   cirrusfb: code im...
1310
  		cinfo->pseudo_palette[regno] = v;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1311
1312
  		return 0;
  	}
8503df659   Krzysztof Helt   cirrusfb: checkpa...
1313
1314
  	if (info->var.bits_per_pixel == 8)
  		WClut(cinfo, regno, red >> 10, green >> 10, blue >> 10);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1315
1316
1317
1318
1319
1320
1321
1322
1323
1324
  
  	return 0;
  
  }
  
  /*************************************************************************
  	cirrusfb_pan_display()
  
  	performs display panning - provided hardware permits this
  **************************************************************************/
8503df659   Krzysztof Helt   cirrusfb: checkpa...
1325
1326
  static int cirrusfb_pan_display(struct fb_var_screeninfo *var,
  				struct fb_info *info)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1327
  {
99a458475   Krzysztof Helt   cirrusfb: check_v...
1328
  	int xoffset;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1329
  	unsigned long base;
213d4bdd8   Krzysztof Helt   cirrusfb: add Lag...
1330
  	unsigned char tmp, xpix;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1331
  	struct cirrusfb_info *cinfo = info->par;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1332
1333
1334
1335
  	/* no range checks for xoffset and yoffset,   */
  	/* as fb_pan_display has already done this */
  	if (var->vmode & FB_VMODE_YWRAP)
  		return -EINVAL;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1336
  	xoffset = var->xoffset * info->var.bits_per_pixel / 8;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1337

99a458475   Krzysztof Helt   cirrusfb: check_v...
1338
  	base = var->yoffset * info->fix.line_length + xoffset;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1339
1340
1341
1342
1343
1344
1345
1346
  
  	if (info->var.bits_per_pixel == 1) {
  		/* base is already correct */
  		xpix = (unsigned char) (var->xoffset % 8);
  	} else {
  		base /= 4;
  		xpix = (unsigned char) ((xoffset % 4) * 2);
  	}
78d780e07   Krzysztof Helt   cirrusfb: various...
1347
  	if (!is_laguna(cinfo))
1b48cb563   Krzysztof Helt   cirrusfb: Laguna ...
1348
  		cirrusfb_WaitBLT(cinfo->regbase);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1349
1350
  
  	/* lower 8 + 8 bits of screen start address */
99a458475   Krzysztof Helt   cirrusfb: check_v...
1351
1352
  	vga_wcrt(cinfo->regbase, VGA_CRTC_START_LO, base & 0xff);
  	vga_wcrt(cinfo->regbase, VGA_CRTC_START_HI, (base >> 8) & 0xff);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1353

213d4bdd8   Krzysztof Helt   cirrusfb: add Lag...
1354
1355
  	/* 0xf2 is %11110010, exclude tmp bits */
  	tmp = vga_rcrt(cinfo->regbase, CL_CRT1B) & 0xf2;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1356
1357
1358
1359
1360
1361
1362
  	/* construct bits 16, 17 and 18 of screen start address */
  	if (base & 0x10000)
  		tmp |= 0x01;
  	if (base & 0x20000)
  		tmp |= 0x04;
  	if (base & 0x40000)
  		tmp |= 0x08;
213d4bdd8   Krzysztof Helt   cirrusfb: add Lag...
1363
  	vga_wcrt(cinfo->regbase, CL_CRT1B, tmp);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1364
1365
  
  	/* construct bit 19 of screen start address */
48c329e90   Krzysztof Helt   cirrusfb: various...
1366
  	if (cirrusfb_board_info[cinfo->btype].scrn_start_bit19) {
78d780e07   Krzysztof Helt   cirrusfb: various...
1367
1368
1369
1370
1371
  		tmp = vga_rcrt(cinfo->regbase, CL_CRT1D);
  		if (is_laguna(cinfo))
  			tmp = (tmp & ~0x18) | ((base >> 16) & 0x18);
  		else
  			tmp = (tmp & ~0x80) | ((base >> 12) & 0x80);
48c329e90   Krzysztof Helt   cirrusfb: various...
1372
1373
  		vga_wcrt(cinfo->regbase, CL_CRT1D, tmp);
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1374

8503df659   Krzysztof Helt   cirrusfb: checkpa...
1375
1376
1377
1378
  	/* write pixel panning value to AR33; this does not quite work in 8bpp
  	 *
  	 * ### Piccolo..? Will this work?
  	 */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1379
  	if (info->var.bits_per_pixel == 1)
8503df659   Krzysztof Helt   cirrusfb: checkpa...
1380
  		vga_wattr(cinfo->regbase, CL_AR33, xpix);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1381

8503df659   Krzysztof Helt   cirrusfb: checkpa...
1382
  	return 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1383
  }
8503df659   Krzysztof Helt   cirrusfb: checkpa...
1384
  static int cirrusfb_blank(int blank_mode, struct fb_info *info)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1385
1386
  {
  	/*
8503df659   Krzysztof Helt   cirrusfb: checkpa...
1387
1388
1389
1390
1391
1392
1393
1394
1395
  	 * Blank the screen if blank_mode != 0, else unblank. If blank == NULL
  	 * then the caller blanks by setting the CLUT (Color Look Up Table)
  	 * to all black. Return 0 if blanking succeeded, != 0 if un-/blanking
  	 * failed due to e.g. a video mode which doesn't support it.
  	 * Implements VESA suspend and powerdown modes on hardware that
  	 * supports disabling hsync/vsync:
  	 *   blank_mode == 2: suspend vsync
  	 *   blank_mode == 3: suspend hsync
  	 *   blank_mode == 4: powerdown
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1396
1397
1398
1399
  	 */
  	unsigned char val;
  	struct cirrusfb_info *cinfo = info->par;
  	int current_mode = cinfo->blank_mode;
75ed3a17a   Krzysztof Helt   cirrusfb: convert...
1400
1401
  	dev_dbg(info->device, "ENTER, blank mode = %d
  ", blank_mode);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1402
1403
1404
  
  	if (info->state != FBINFO_STATE_RUNNING ||
  	    current_mode == blank_mode) {
75ed3a17a   Krzysztof Helt   cirrusfb: convert...
1405
1406
  		dev_dbg(info->device, "EXIT, returning 0
  ");
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1407
1408
1409
1410
1411
  		return 0;
  	}
  
  	/* Undo current */
  	if (current_mode == FB_BLANK_NORMAL ||
213d4bdd8   Krzysztof Helt   cirrusfb: add Lag...
1412
  	    current_mode == FB_BLANK_UNBLANK)
8503df659   Krzysztof Helt   cirrusfb: checkpa...
1413
  		/* clear "FullBandwidth" bit */
213d4bdd8   Krzysztof Helt   cirrusfb: add Lag...
1414
1415
  		val = 0;
  	else
8503df659   Krzysztof Helt   cirrusfb: checkpa...
1416
  		/* set "FullBandwidth" bit */
213d4bdd8   Krzysztof Helt   cirrusfb: add Lag...
1417
1418
1419
1420
  		val = 0x20;
  
  	val |= vga_rseq(cinfo->regbase, VGA_SEQ_CLOCK_MODE) & 0xdf;
  	vga_wseq(cinfo->regbase, VGA_SEQ_CLOCK_MODE, val);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1421
1422
1423
1424
  
  	switch (blank_mode) {
  	case FB_BLANK_UNBLANK:
  	case FB_BLANK_NORMAL:
213d4bdd8   Krzysztof Helt   cirrusfb: add Lag...
1425
  		val = 0x00;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1426
1427
  		break;
  	case FB_BLANK_VSYNC_SUSPEND:
213d4bdd8   Krzysztof Helt   cirrusfb: add Lag...
1428
  		val = 0x04;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1429
1430
  		break;
  	case FB_BLANK_HSYNC_SUSPEND:
213d4bdd8   Krzysztof Helt   cirrusfb: add Lag...
1431
  		val = 0x02;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1432
1433
  		break;
  	case FB_BLANK_POWERDOWN:
213d4bdd8   Krzysztof Helt   cirrusfb: add Lag...
1434
  		val = 0x06;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1435
1436
  		break;
  	default:
75ed3a17a   Krzysztof Helt   cirrusfb: convert...
1437
1438
  		dev_dbg(info->device, "EXIT, returning 1
  ");
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1439
1440
  		return 1;
  	}
213d4bdd8   Krzysztof Helt   cirrusfb: add Lag...
1441
  	vga_wgfx(cinfo->regbase, CL_GRE, val);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1442
  	cinfo->blank_mode = blank_mode;
75ed3a17a   Krzysztof Helt   cirrusfb: convert...
1443
1444
  	dev_dbg(info->device, "EXIT, returning 0
  ");
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1445
1446
1447
1448
  
  	/* Let fbcon do a soft blank for us */
  	return (blank_mode == FB_BLANK_NORMAL) ? 1 : 0;
  }
213d4bdd8   Krzysztof Helt   cirrusfb: add Lag...
1449

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1450
1451
1452
  /**** END   Hardware specific Routines **************************************/
  /****************************************************************************/
  /**** BEGIN Internal Routines ***********************************************/
9199ec5c5   Krzysztof Helt   cirrusfb: remove ...
1453
  static void init_vgachip(struct fb_info *info)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1454
  {
9199ec5c5   Krzysztof Helt   cirrusfb: remove ...
1455
  	struct cirrusfb_info *cinfo = info->par;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1456
  	const struct cirrusfb_board_info_rec *bi;
8503df659   Krzysztof Helt   cirrusfb: checkpa...
1457
  	assert(cinfo != NULL);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1458
1459
1460
1461
1462
1463
  
  	bi = &cirrusfb_board_info[cinfo->btype];
  
  	/* reset board globally */
  	switch (cinfo->btype) {
  	case BT_PICCOLO:
8503df659   Krzysztof Helt   cirrusfb: checkpa...
1464
1465
1466
1467
  		WSFR(cinfo, 0x01);
  		udelay(500);
  		WSFR(cinfo, 0x51);
  		udelay(500);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1468
1469
  		break;
  	case BT_PICASSO:
8503df659   Krzysztof Helt   cirrusfb: checkpa...
1470
1471
  		WSFR2(cinfo, 0xff);
  		udelay(500);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1472
1473
1474
  		break;
  	case BT_SD64:
  	case BT_SPECTRUM:
8503df659   Krzysztof Helt   cirrusfb: checkpa...
1475
1476
1477
1478
  		WSFR(cinfo, 0x1f);
  		udelay(500);
  		WSFR(cinfo, 0x4f);
  		udelay(500);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1479
1480
  		break;
  	case BT_PICASSO4:
8503df659   Krzysztof Helt   cirrusfb: checkpa...
1481
1482
1483
  		/* disable flickerfixer */
  		vga_wcrt(cinfo->regbase, CL_CRT51, 0x00);
  		mdelay(100);
8503df659   Krzysztof Helt   cirrusfb: checkpa...
1484
1485
  		/* mode */
  		vga_wgfx(cinfo->regbase, CL_GR31, 0x00);
7cade31ca   Krzysztof Helt   cirrusfb: use 24b...
1486
  	case BT_GD5480:  /* fall through */
8503df659   Krzysztof Helt   cirrusfb: checkpa...
1487
1488
  		/* from Klaus' NetBSD driver: */
  		vga_wgfx(cinfo->regbase, CL_GR2F, 0x00);
7cade31ca   Krzysztof Helt   cirrusfb: use 24b...
1489
1490
1491
  	case BT_ALPINE:  /* fall through */
  		/* put blitter into 542x compat */
  		vga_wgfx(cinfo->regbase, CL_GR33, 0x00);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1492
  		break;
1b48cb563   Krzysztof Helt   cirrusfb: Laguna ...
1493
  	case BT_LAGUNA:
78d780e07   Krzysztof Helt   cirrusfb: various...
1494
  	case BT_LAGUNAB:
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1495
1496
1497
1498
  		/* Nothing to do to reset the board. */
  		break;
  
  	default:
75ed3a17a   Krzysztof Helt   cirrusfb: convert...
1499
1500
  		dev_err(info->device, "Warning: Unknown board type
  ");
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1501
1502
  		break;
  	}
9199ec5c5   Krzysztof Helt   cirrusfb: remove ...
1503
1504
  	/* make sure RAM size set by this point */
  	assert(info->screen_size > 0);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1505
1506
1507
  
  	/* the P4 is not fully initialized here; I rely on it having been */
  	/* inited under AmigaOS already, which seems to work just fine    */
8503df659   Krzysztof Helt   cirrusfb: checkpa...
1508
  	/* (Klaus advised to do it this way)			      */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1509
1510
  
  	if (cinfo->btype != BT_PICASSO4) {
8503df659   Krzysztof Helt   cirrusfb: checkpa...
1511
1512
1513
  		WGen(cinfo, CL_VSSM, 0x10);	/* EGS: 0x16 */
  		WGen(cinfo, CL_POS102, 0x01);
  		WGen(cinfo, CL_VSSM, 0x08);	/* EGS: 0x0e */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1514
1515
  
  		if (cinfo->btype != BT_SD64)
8503df659   Krzysztof Helt   cirrusfb: checkpa...
1516
  			WGen(cinfo, CL_VSSM2, 0x01);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1517

8503df659   Krzysztof Helt   cirrusfb: checkpa...
1518
  		/* reset sequencer logic */
1b48cb563   Krzysztof Helt   cirrusfb: Laguna ...
1519
  		vga_wseq(cinfo->regbase, VGA_SEQ_RESET, 0x03);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1520

8503df659   Krzysztof Helt   cirrusfb: checkpa...
1521
1522
  		/* FullBandwidth (video off) and 8/9 dot clock */
  		vga_wseq(cinfo->regbase, VGA_SEQ_CLOCK_MODE, 0x21);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1523

8503df659   Krzysztof Helt   cirrusfb: checkpa...
1524
1525
1526
1527
  		/* "magic cookie" - doesn't make any sense to me.. */
  /*      vga_wgfx(cinfo->regbase, CL_GRA, 0xce);   */
  		/* unlock all extension registers */
  		vga_wseq(cinfo->regbase, CL_SEQR6, 0x12);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1528

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1529
1530
  		switch (cinfo->btype) {
  		case BT_GD5480:
8503df659   Krzysztof Helt   cirrusfb: checkpa...
1531
  			vga_wseq(cinfo->regbase, CL_SEQRF, 0x98);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1532
1533
  			break;
  		case BT_ALPINE:
1b48cb563   Krzysztof Helt   cirrusfb: Laguna ...
1534
  		case BT_LAGUNA:
78d780e07   Krzysztof Helt   cirrusfb: various...
1535
  		case BT_LAGUNAB:
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1536
1537
  			break;
  		case BT_SD64:
df3aafd57   Krzysztof Helt   cirrusfb: GD5434 ...
1538
  #ifdef CONFIG_ZORRO
8503df659   Krzysztof Helt   cirrusfb: checkpa...
1539
  			vga_wseq(cinfo->regbase, CL_SEQRF, 0xb8);
df3aafd57   Krzysztof Helt   cirrusfb: GD5434 ...
1540
  #endif
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1541
1542
  			break;
  		default:
8503df659   Krzysztof Helt   cirrusfb: checkpa...
1543
1544
  			vga_wseq(cinfo->regbase, CL_SEQR16, 0x0f);
  			vga_wseq(cinfo->regbase, CL_SEQRF, 0xb0);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1545
1546
1547
  			break;
  		}
  	}
8503df659   Krzysztof Helt   cirrusfb: checkpa...
1548
1549
1550
1551
  	/* plane mask: nothing */
  	vga_wseq(cinfo->regbase, VGA_SEQ_PLANE_WRITE, 0xff);
  	/* character map select: doesn't even matter in gx mode */
  	vga_wseq(cinfo->regbase, VGA_SEQ_CHARACTER_MAP, 0x00);
48c329e90   Krzysztof Helt   cirrusfb: various...
1552
1553
  	/* memory mode: chain4, ext. memory */
  	vga_wseq(cinfo->regbase, VGA_SEQ_MEMORY_MODE, 0x0a);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1554
1555
1556
  
  	/* controller-internal base address of video memory */
  	if (bi->init_sr07)
8503df659   Krzysztof Helt   cirrusfb: checkpa...
1557
  		vga_wseq(cinfo->regbase, CL_SEQR7, bi->sr07);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1558

8503df659   Krzysztof Helt   cirrusfb: checkpa...
1559
1560
  	/*  vga_wseq(cinfo->regbase, CL_SEQR8, 0x00); */
  	/* EEPROM control: shouldn't be necessary to write to this at all.. */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1561

8503df659   Krzysztof Helt   cirrusfb: checkpa...
1562
1563
1564
1565
1566
1567
1568
1569
  	/* graphics cursor X position (incomplete; position gives rem. 3 bits */
  	vga_wseq(cinfo->regbase, CL_SEQR10, 0x00);
  	/* graphics cursor Y position (..."... ) */
  	vga_wseq(cinfo->regbase, CL_SEQR11, 0x00);
  	/* graphics cursor attributes */
  	vga_wseq(cinfo->regbase, CL_SEQR12, 0x00);
  	/* graphics cursor pattern address */
  	vga_wseq(cinfo->regbase, CL_SEQR13, 0x00);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1570
1571
1572
  
  	/* writing these on a P4 might give problems..  */
  	if (cinfo->btype != BT_PICASSO4) {
8503df659   Krzysztof Helt   cirrusfb: checkpa...
1573
1574
1575
1576
  		/* configuration readback and ext. color */
  		vga_wseq(cinfo->regbase, CL_SEQR17, 0x00);
  		/* signature generator */
  		vga_wseq(cinfo->regbase, CL_SEQR18, 0x02);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1577
  	}
8503df659   Krzysztof Helt   cirrusfb: checkpa...
1578
1579
1580
1581
1582
1583
  	/* Screen A preset row scan: none */
  	vga_wcrt(cinfo->regbase, VGA_CRTC_PRESET_ROW, 0x00);
  	/* Text cursor start: disable text cursor */
  	vga_wcrt(cinfo->regbase, VGA_CRTC_CURSOR_START, 0x20);
  	/* Text cursor end: - */
  	vga_wcrt(cinfo->regbase, VGA_CRTC_CURSOR_END, 0x00);
8503df659   Krzysztof Helt   cirrusfb: checkpa...
1584
1585
1586
1587
1588
1589
1590
  	/* text cursor location high: 0 */
  	vga_wcrt(cinfo->regbase, VGA_CRTC_CURSOR_HI, 0x00);
  	/* text cursor location low: 0 */
  	vga_wcrt(cinfo->regbase, VGA_CRTC_CURSOR_LO, 0x00);
  
  	/* Underline Row scanline: - */
  	vga_wcrt(cinfo->regbase, VGA_CRTC_UNDERLINE, 0x00);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1591
  	/* ### add 0x40 for text modes with > 30 MHz pixclock */
8503df659   Krzysztof Helt   cirrusfb: checkpa...
1592
1593
1594
1595
1596
1597
1598
1599
1600
1601
1602
1603
1604
1605
1606
1607
1608
1609
1610
1611
1612
  	/* ext. display controls: ext.adr. wrap */
  	vga_wcrt(cinfo->regbase, CL_CRT1B, 0x02);
  
  	/* Set/Reset registes: - */
  	vga_wgfx(cinfo->regbase, VGA_GFX_SR_VALUE, 0x00);
  	/* Set/Reset enable: - */
  	vga_wgfx(cinfo->regbase, VGA_GFX_SR_ENABLE, 0x00);
  	/* Color Compare: - */
  	vga_wgfx(cinfo->regbase, VGA_GFX_COMPARE_VALUE, 0x00);
  	/* Data Rotate: - */
  	vga_wgfx(cinfo->regbase, VGA_GFX_DATA_ROTATE, 0x00);
  	/* Read Map Select: - */
  	vga_wgfx(cinfo->regbase, VGA_GFX_PLANE_READ, 0x00);
  	/* Mode: conf. for 16/4/2 color mode, no odd/even, read/write mode 0 */
  	vga_wgfx(cinfo->regbase, VGA_GFX_MODE, 0x00);
  	/* Miscellaneous: memory map base address, graphics mode */
  	vga_wgfx(cinfo->regbase, VGA_GFX_MISC, 0x01);
  	/* Color Don't care: involve all planes */
  	vga_wgfx(cinfo->regbase, VGA_GFX_COMPARE_MASK, 0x0f);
  	/* Bit Mask: no mask at all */
  	vga_wgfx(cinfo->regbase, VGA_GFX_BIT_MASK, 0xff);
1b48cb563   Krzysztof Helt   cirrusfb: Laguna ...
1613

df3aafd57   Krzysztof Helt   cirrusfb: GD5434 ...
1614
1615
  	if (cinfo->btype == BT_ALPINE || cinfo->btype == BT_SD64 ||
  	    is_laguna(cinfo))
8503df659   Krzysztof Helt   cirrusfb: checkpa...
1616
1617
  		/* (5434 can't have bit 3 set for bitblt) */
  		vga_wgfx(cinfo->regbase, CL_GRB, 0x20);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1618
  	else
8503df659   Krzysztof Helt   cirrusfb: checkpa...
1619
1620
1621
1622
1623
1624
1625
1626
1627
1628
1629
1630
1631
1632
1633
1634
1635
1636
1637
1638
1639
1640
1641
1642
1643
1644
1645
1646
1647
1648
1649
1650
1651
1652
1653
1654
  	/* Graphics controller mode extensions: finer granularity,
  	 * 8byte data latches
  	 */
  		vga_wgfx(cinfo->regbase, CL_GRB, 0x28);
  
  	vga_wgfx(cinfo->regbase, CL_GRC, 0xff);	/* Color Key compare: - */
  	vga_wgfx(cinfo->regbase, CL_GRD, 0x00);	/* Color Key compare mask: - */
  	vga_wgfx(cinfo->regbase, CL_GRE, 0x00);	/* Miscellaneous control: - */
  	/* Background color byte 1: - */
  	/*  vga_wgfx (cinfo->regbase, CL_GR10, 0x00); */
  	/*  vga_wgfx (cinfo->regbase, CL_GR11, 0x00); */
  
  	/* Attribute Controller palette registers: "identity mapping" */
  	vga_wattr(cinfo->regbase, VGA_ATC_PALETTE0, 0x00);
  	vga_wattr(cinfo->regbase, VGA_ATC_PALETTE1, 0x01);
  	vga_wattr(cinfo->regbase, VGA_ATC_PALETTE2, 0x02);
  	vga_wattr(cinfo->regbase, VGA_ATC_PALETTE3, 0x03);
  	vga_wattr(cinfo->regbase, VGA_ATC_PALETTE4, 0x04);
  	vga_wattr(cinfo->regbase, VGA_ATC_PALETTE5, 0x05);
  	vga_wattr(cinfo->regbase, VGA_ATC_PALETTE6, 0x06);
  	vga_wattr(cinfo->regbase, VGA_ATC_PALETTE7, 0x07);
  	vga_wattr(cinfo->regbase, VGA_ATC_PALETTE8, 0x08);
  	vga_wattr(cinfo->regbase, VGA_ATC_PALETTE9, 0x09);
  	vga_wattr(cinfo->regbase, VGA_ATC_PALETTEA, 0x0a);
  	vga_wattr(cinfo->regbase, VGA_ATC_PALETTEB, 0x0b);
  	vga_wattr(cinfo->regbase, VGA_ATC_PALETTEC, 0x0c);
  	vga_wattr(cinfo->regbase, VGA_ATC_PALETTED, 0x0d);
  	vga_wattr(cinfo->regbase, VGA_ATC_PALETTEE, 0x0e);
  	vga_wattr(cinfo->regbase, VGA_ATC_PALETTEF, 0x0f);
  
  	/* Attribute Controller mode: graphics mode */
  	vga_wattr(cinfo->regbase, VGA_ATC_MODE, 0x01);
  	/* Overscan color reg.: reg. 0 */
  	vga_wattr(cinfo->regbase, VGA_ATC_OVERSCAN, 0x00);
  	/* Color Plane enable: Enable all 4 planes */
  	vga_wattr(cinfo->regbase, VGA_ATC_PLANE_ENABLE, 0x0f);
8503df659   Krzysztof Helt   cirrusfb: checkpa...
1655
1656
1657
1658
  	/* Color Select: - */
  	vga_wattr(cinfo->regbase, VGA_ATC_COLOR_PAGE, 0x00);
  
  	WGen(cinfo, VGA_PEL_MSK, 0xff);	/* Pixel mask: no mask */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1659

8503df659   Krzysztof Helt   cirrusfb: checkpa...
1660
1661
1662
1663
  	/* BLT Start/status: Blitter reset */
  	vga_wgfx(cinfo->regbase, CL_GR31, 0x04);
  	/* - " -	   : "end-of-reset" */
  	vga_wgfx(cinfo->regbase, CL_GR31, 0x00);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1664
1665
  
  	/* misc... */
8503df659   Krzysztof Helt   cirrusfb: checkpa...
1666
  	WHDR(cinfo, 0);	/* Hidden DAC register: - */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1667
1668
  	return;
  }
8503df659   Krzysztof Helt   cirrusfb: checkpa...
1669
  static void switch_monitor(struct cirrusfb_info *cinfo, int on)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1670
1671
1672
  {
  #ifdef CONFIG_ZORRO /* only works on Zorro boards */
  	static int IsOn = 0;	/* XXX not ok for multiple boards */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1673
1674
1675
1676
1677
1678
1679
1680
  	if (cinfo->btype == BT_PICASSO4)
  		return;		/* nothing to switch */
  	if (cinfo->btype == BT_ALPINE)
  		return;		/* nothing to switch */
  	if (cinfo->btype == BT_GD5480)
  		return;		/* nothing to switch */
  	if (cinfo->btype == BT_PICASSO) {
  		if ((on && !IsOn) || (!on && IsOn))
8503df659   Krzysztof Helt   cirrusfb: checkpa...
1681
  			WSFR(cinfo, 0xff);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1682
1683
1684
1685
1686
  		return;
  	}
  	if (on) {
  		switch (cinfo->btype) {
  		case BT_SD64:
8503df659   Krzysztof Helt   cirrusfb: checkpa...
1687
  			WSFR(cinfo, cinfo->SFR | 0x21);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1688
1689
  			break;
  		case BT_PICCOLO:
8503df659   Krzysztof Helt   cirrusfb: checkpa...
1690
  			WSFR(cinfo, cinfo->SFR | 0x28);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1691
1692
  			break;
  		case BT_SPECTRUM:
8503df659   Krzysztof Helt   cirrusfb: checkpa...
1693
  			WSFR(cinfo, 0x6f);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1694
1695
1696
1697
1698
1699
  			break;
  		default: /* do nothing */ break;
  		}
  	} else {
  		switch (cinfo->btype) {
  		case BT_SD64:
8503df659   Krzysztof Helt   cirrusfb: checkpa...
1700
  			WSFR(cinfo, cinfo->SFR & 0xde);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1701
1702
  			break;
  		case BT_PICCOLO:
8503df659   Krzysztof Helt   cirrusfb: checkpa...
1703
  			WSFR(cinfo, cinfo->SFR & 0xd7);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1704
1705
  			break;
  		case BT_SPECTRUM:
8503df659   Krzysztof Helt   cirrusfb: checkpa...
1706
  			WSFR(cinfo, 0x4f);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1707
  			break;
75ed3a17a   Krzysztof Helt   cirrusfb: convert...
1708
1709
  		default: /* do nothing */
  			break;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1710
1711
  		}
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1712
1713
  #endif /* CONFIG_ZORRO */
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1714
1715
1716
  /******************************************/
  /* Linux 2.6-style  accelerated functions */
  /******************************************/
8343c89c4   Krzysztof Helt   cirrusfb: acceler...
1717
1718
1719
1720
1721
1722
1723
1724
1725
1726
  static int cirrusfb_sync(struct fb_info *info)
  {
  	struct cirrusfb_info *cinfo = info->par;
  
  	if (!is_laguna(cinfo)) {
  		while (vga_rgfx(cinfo->regbase, CL_GR31) & 0x03)
  			cpu_relax();
  	}
  	return 0;
  }
8503df659   Krzysztof Helt   cirrusfb: checkpa...
1727
1728
  static void cirrusfb_fillrect(struct fb_info *info,
  			      const struct fb_fillrect *region)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1729
  {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1730
1731
  	struct fb_fillrect modded;
  	int vxres, vyres;
060b6002b   Krzysztof Helt   cirrusfb: code im...
1732
1733
1734
1735
  	struct cirrusfb_info *cinfo = info->par;
  	int m = info->var.bits_per_pixel;
  	u32 color = (info->fix.visual == FB_VISUAL_TRUECOLOR) ?
  		cinfo->pseudo_palette[region->color] : region->color;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1736
1737
1738
1739
1740
1741
1742
1743
1744
1745
1746
1747
  
  	if (info->state != FBINFO_STATE_RUNNING)
  		return;
  	if (info->flags & FBINFO_HWACCEL_DISABLED) {
  		cfb_fillrect(info, region);
  		return;
  	}
  
  	vxres = info->var.xres_virtual;
  	vyres = info->var.yres_virtual;
  
  	memcpy(&modded, region, sizeof(struct fb_fillrect));
8503df659   Krzysztof Helt   cirrusfb: checkpa...
1748
  	if (!modded.width || !modded.height ||
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1749
1750
  	   modded.dx >= vxres || modded.dy >= vyres)
  		return;
8503df659   Krzysztof Helt   cirrusfb: checkpa...
1751
1752
1753
1754
  	if (modded.dx + modded.width  > vxres)
  		modded.width  = vxres - modded.dx;
  	if (modded.dy + modded.height > vyres)
  		modded.height = vyres - modded.dy;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1755

060b6002b   Krzysztof Helt   cirrusfb: code im...
1756
1757
1758
1759
  	cirrusfb_RectFill(cinfo->regbase,
  			  info->var.bits_per_pixel,
  			  (region->dx * m) / 8, region->dy,
  			  (region->width * m) / 8, region->height,
9e8480625   Krzysztof Helt   cirrusfb: add ima...
1760
1761
  			  color, color,
  			  info->fix.line_length, 0x40);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1762
  }
8503df659   Krzysztof Helt   cirrusfb: checkpa...
1763
1764
  static void cirrusfb_copyarea(struct fb_info *info,
  			      const struct fb_copyarea *area)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1765
  {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1766
1767
  	struct fb_copyarea modded;
  	u32 vxres, vyres;
060b6002b   Krzysztof Helt   cirrusfb: code im...
1768
1769
  	struct cirrusfb_info *cinfo = info->par;
  	int m = info->var.bits_per_pixel;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1770
1771
1772
1773
1774
1775
1776
1777
1778
1779
  
  	if (info->state != FBINFO_STATE_RUNNING)
  		return;
  	if (info->flags & FBINFO_HWACCEL_DISABLED) {
  		cfb_copyarea(info, area);
  		return;
  	}
  
  	vxres = info->var.xres_virtual;
  	vyres = info->var.yres_virtual;
060b6002b   Krzysztof Helt   cirrusfb: code im...
1780
  	memcpy(&modded, area, sizeof(struct fb_copyarea));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1781

8503df659   Krzysztof Helt   cirrusfb: checkpa...
1782
  	if (!modded.width || !modded.height ||
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1783
1784
1785
  	   modded.sx >= vxres || modded.sy >= vyres ||
  	   modded.dx >= vxres || modded.dy >= vyres)
  		return;
8503df659   Krzysztof Helt   cirrusfb: checkpa...
1786
1787
1788
1789
1790
1791
1792
1793
  	if (modded.sx + modded.width > vxres)
  		modded.width = vxres - modded.sx;
  	if (modded.dx + modded.width > vxres)
  		modded.width = vxres - modded.dx;
  	if (modded.sy + modded.height > vyres)
  		modded.height = vyres - modded.sy;
  	if (modded.dy + modded.height > vyres)
  		modded.height = vyres - modded.dy;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1794

060b6002b   Krzysztof Helt   cirrusfb: code im...
1795
1796
1797
1798
  	cirrusfb_BitBLT(cinfo->regbase, info->var.bits_per_pixel,
  			(area->sx * m) / 8, area->sy,
  			(area->dx * m) / 8, area->dy,
  			(area->width * m) / 8, area->height,
0ff1edeef   Krzysztof Helt   cirrusfb: code im...
1799
  			info->fix.line_length);
060b6002b   Krzysztof Helt   cirrusfb: code im...
1800

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1801
  }
8503df659   Krzysztof Helt   cirrusfb: checkpa...
1802
1803
  static void cirrusfb_imageblit(struct fb_info *info,
  			       const struct fb_image *image)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1804
1805
  {
  	struct cirrusfb_info *cinfo = info->par;
7cade31ca   Krzysztof Helt   cirrusfb: use 24b...
1806
  	unsigned char op = (info->var.bits_per_pixel == 24) ? 0xc : 0x4;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1807

9e8480625   Krzysztof Helt   cirrusfb: add ima...
1808
1809
  	if (info->state != FBINFO_STATE_RUNNING)
  		return;
df3aafd57   Krzysztof Helt   cirrusfb: GD5434 ...
1810
1811
1812
1813
1814
  	/* Alpine/SD64 does not work at 24bpp ??? */
  	if (info->flags & FBINFO_HWACCEL_DISABLED || image->depth != 1)
  		cfb_imageblit(info, image);
  	else if ((cinfo->btype == BT_ALPINE || cinfo->btype == BT_SD64) &&
  		  op == 0xc)
9e8480625   Krzysztof Helt   cirrusfb: add ima...
1815
1816
1817
1818
1819
1820
1821
1822
1823
1824
1825
1826
1827
  		cfb_imageblit(info, image);
  	else {
  		unsigned size = ((image->width + 7) >> 3) * image->height;
  		int m = info->var.bits_per_pixel;
  		u32 fg, bg;
  
  		if (info->var.bits_per_pixel == 8) {
  			fg = image->fg_color;
  			bg = image->bg_color;
  		} else {
  			fg = ((u32 *)(info->pseudo_palette))[image->fg_color];
  			bg = ((u32 *)(info->pseudo_palette))[image->bg_color];
  		}
7cade31ca   Krzysztof Helt   cirrusfb: use 24b...
1828
1829
1830
1831
1832
1833
1834
1835
1836
1837
  		if (info->var.bits_per_pixel == 24) {
  			/* clear background first */
  			cirrusfb_RectFill(cinfo->regbase,
  					  info->var.bits_per_pixel,
  					  (image->dx * m) / 8, image->dy,
  					  (image->width * m) / 8,
  					  image->height,
  					  bg, bg,
  					  info->fix.line_length, 0x40);
  		}
9e8480625   Krzysztof Helt   cirrusfb: add ima...
1838
1839
1840
1841
1842
  		cirrusfb_RectFill(cinfo->regbase,
  				  info->var.bits_per_pixel,
  				  (image->dx * m) / 8, image->dy,
  				  (image->width * m) / 8, image->height,
  				  fg, bg,
7cade31ca   Krzysztof Helt   cirrusfb: use 24b...
1843
  				  info->fix.line_length, op);
9e8480625   Krzysztof Helt   cirrusfb: add ima...
1844
1845
  		memcpy(info->screen_base, image->data, size);
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1846
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1847
1848
1849
  #ifdef CONFIG_PPC_PREP
  #define PREP_VIDEO_BASE ((volatile unsigned long) 0xC0000000)
  #define PREP_IO_BASE    ((volatile unsigned char *) 0x80000000)
8503df659   Krzysztof Helt   cirrusfb: checkpa...
1850
  static void get_prep_addrs(unsigned long *display, unsigned long *registers)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1851
  {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1852
1853
  	*display = PREP_VIDEO_BASE;
  	*registers = (unsigned long) PREP_IO_BASE;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1854
1855
1856
  }
  
  #endif				/* CONFIG_PPC_PREP */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1857
  #ifdef CONFIG_PCI
8503df659   Krzysztof Helt   cirrusfb: checkpa...
1858
  static int release_io_ports;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1859
1860
1861
1862
1863
  
  /* Pulled the logic from XFree86 Cirrus driver to get the memory size,
   * based on the DRAM bandwidth bit and DRAM bank switching bit.  This
   * works with 1MB, 2MB and 4MB configurations (which the Motorola boards
   * seem to have. */
75ed3a17a   Krzysztof Helt   cirrusfb: convert...
1864
1865
  static unsigned int __devinit cirrusfb_get_memsize(struct fb_info *info,
  						   u8 __iomem *regbase)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1866
1867
  {
  	unsigned long mem;
55a4ea6ab   Krzysztof Helt   cirrusfb: fix Lag...
1868
  	struct cirrusfb_info *cinfo = info->par;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1869

78d780e07   Krzysztof Helt   cirrusfb: various...
1870
  	if (is_laguna(cinfo)) {
55a4ea6ab   Krzysztof Helt   cirrusfb: fix Lag...
1871
1872
1873
1874
1875
1876
1877
1878
1879
1880
1881
1882
1883
1884
1885
1886
1887
1888
1889
1890
1891
1892
1893
1894
1895
1896
  		unsigned char SR14 = vga_rseq(regbase, CL_SEQR14);
  
  		mem = ((SR14 & 7) + 1) << 20;
  	} else {
  		unsigned char SRF = vga_rseq(regbase, CL_SEQRF);
  		switch ((SRF & 0x18)) {
  		case 0x08:
  			mem = 512 * 1024;
  			break;
  		case 0x10:
  			mem = 1024 * 1024;
  			break;
  		/* 64-bit DRAM data bus width; assume 2MB.
  		 * Also indicates 2MB memory on the 5430.
  		 */
  		case 0x18:
  			mem = 2048 * 1024;
  			break;
  		default:
  			dev_warn(info->device, "Unknown memory size!
  ");
  			mem = 1024 * 1024;
  		}
  		/* If DRAM bank switching is enabled, there must be
  		 * twice as much memory installed. (4MB on the 5434)
  		 */
df3aafd57   Krzysztof Helt   cirrusfb: GD5434 ...
1897
  		if (cinfo->btype != BT_ALPINE && (SRF & 0x80) != 0)
55a4ea6ab   Krzysztof Helt   cirrusfb: fix Lag...
1898
  			mem *= 2;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1899
  	}
8503df659   Krzysztof Helt   cirrusfb: checkpa...
1900

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1901
  	/* TODO: Handling of GD5446/5480 (see XF86 sources ...) */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1902
1903
  	return mem;
  }
8503df659   Krzysztof Helt   cirrusfb: checkpa...
1904
1905
  static void get_pci_addrs(const struct pci_dev *pdev,
  			  unsigned long *display, unsigned long *registers)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1906
  {
8503df659   Krzysztof Helt   cirrusfb: checkpa...
1907
1908
1909
  	assert(pdev != NULL);
  	assert(display != NULL);
  	assert(registers != NULL);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1910

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1911
1912
1913
1914
1915
1916
1917
1918
1919
1920
1921
1922
  	*display = 0;
  	*registers = 0;
  
  	/* This is a best-guess for now */
  
  	if (pci_resource_flags(pdev, 0) & IORESOURCE_IO) {
  		*display = pci_resource_start(pdev, 1);
  		*registers = pci_resource_start(pdev, 0);
  	} else {
  		*display = pci_resource_start(pdev, 0);
  		*registers = pci_resource_start(pdev, 1);
  	}
8503df659   Krzysztof Helt   cirrusfb: checkpa...
1923
  	assert(*display != 0);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1924
  }
9199ec5c5   Krzysztof Helt   cirrusfb: remove ...
1925
  static void cirrusfb_pci_unmap(struct fb_info *info)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1926
  {
64beab14f   Krzysztof Helt   cirrusfb: drop de...
1927
  	struct pci_dev *pdev = to_pci_dev(info->device);
6e30fc086   Krzysztof Helt   cirrusfb: add mmi...
1928
  	struct cirrusfb_info *cinfo = info->par;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1929

6e30fc086   Krzysztof Helt   cirrusfb: add mmi...
1930
1931
  	if (cinfo->laguna_mmio == NULL)
  		iounmap(cinfo->laguna_mmio);
9199ec5c5   Krzysztof Helt   cirrusfb: remove ...
1932
  	iounmap(info->screen_base);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1933
1934
1935
1936
1937
1938
  #if 0 /* if system didn't claim this region, we would... */
  	release_mem_region(0xA0000, 65535);
  #endif
  	if (release_io_ports)
  		release_region(0x3C0, 32);
  	pci_release_regions(pdev);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1939
1940
  }
  #endif /* CONFIG_PCI */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1941
  #ifdef CONFIG_ZORRO
f5ee051e7   Al Viro   section fixes for...
1942
  static void cirrusfb_zorro_unmap(struct fb_info *info)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1943
  {
d91f5bb69   Al Viro   fix cirrusfb brea...
1944
  	struct cirrusfb_info *cinfo = info->par;
64beab14f   Krzysztof Helt   cirrusfb: drop de...
1945
  	struct zorro_dev *zdev = to_zorro_dev(info->device);
0e0d13364   Geert Uytterhoeven   fbdev/cirrusfb: R...
1946
  	if (info->fix.smem_start > 16 * MB_)
9199ec5c5   Krzysztof Helt   cirrusfb: remove ...
1947
  		iounmap(info->screen_base);
0e0d13364   Geert Uytterhoeven   fbdev/cirrusfb: R...
1948
1949
1950
1951
  	if (info->fix.mmio_start > 16 * MB_)
  		iounmap(cinfo->regbase);
  
  	zorro_release_device(zdev);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1952
1953
  }
  #endif /* CONFIG_ZORRO */
48c329e90   Krzysztof Helt   cirrusfb: various...
1954
1955
1956
1957
1958
1959
1960
1961
1962
1963
1964
1965
  /* function table of the above functions */
  static struct fb_ops cirrusfb_ops = {
  	.owner		= THIS_MODULE,
  	.fb_open	= cirrusfb_open,
  	.fb_release	= cirrusfb_release,
  	.fb_setcolreg	= cirrusfb_setcolreg,
  	.fb_check_var	= cirrusfb_check_var,
  	.fb_set_par	= cirrusfb_set_par,
  	.fb_pan_display = cirrusfb_pan_display,
  	.fb_blank	= cirrusfb_blank,
  	.fb_fillrect	= cirrusfb_fillrect,
  	.fb_copyarea	= cirrusfb_copyarea,
8343c89c4   Krzysztof Helt   cirrusfb: acceler...
1966
  	.fb_sync	= cirrusfb_sync,
48c329e90   Krzysztof Helt   cirrusfb: various...
1967
1968
  	.fb_imageblit	= cirrusfb_imageblit,
  };
c395d3e8c   Krzysztof Helt   cirrusfb: add __d...
1969
  static int __devinit cirrusfb_set_fbinfo(struct fb_info *info)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1970
  {
9199ec5c5   Krzysztof Helt   cirrusfb: remove ...
1971
  	struct cirrusfb_info *cinfo = info->par;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1972
  	struct fb_var_screeninfo *var = &info->var;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1973
1974
1975
1976
1977
  	info->pseudo_palette = cinfo->pseudo_palette;
  	info->flags = FBINFO_DEFAULT
  		    | FBINFO_HWACCEL_XPAN
  		    | FBINFO_HWACCEL_YPAN
  		    | FBINFO_HWACCEL_FILLRECT
9e8480625   Krzysztof Helt   cirrusfb: add ima...
1978
  		    | FBINFO_HWACCEL_IMAGEBLIT
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1979
  		    | FBINFO_HWACCEL_COPYAREA;
614c0dc93   Krzysztof Helt   cirrusfb: add acc...
1980
  	if (noaccel || is_laguna(cinfo)) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1981
  		info->flags |= FBINFO_HWACCEL_DISABLED;
614c0dc93   Krzysztof Helt   cirrusfb: add acc...
1982
1983
1984
  		info->fix.accel = FB_ACCEL_NONE;
  	} else
  		info->fix.accel = FB_ACCEL_CIRRUS_ALPINE;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1985
  	info->fbops = &cirrusfb_ops;
9e8480625   Krzysztof Helt   cirrusfb: add ima...
1986

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1987
1988
1989
  	if (cinfo->btype == BT_GD5480) {
  		if (var->bits_per_pixel == 16)
  			info->screen_base += 1 * MB_;
1cea9a9a6   Krzysztof Helt   cirrusfb: remove ...
1990
  		if (var->bits_per_pixel == 32)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1991
1992
1993
1994
1995
1996
1997
1998
1999
  			info->screen_base += 2 * MB_;
  	}
  
  	/* Fill fix common fields */
  	strlcpy(info->fix.id, cirrusfb_board_info[cinfo->btype].name,
  		sizeof(info->fix.id));
  
  	/* monochrome: only 1 memory plane */
  	/* 8 bit and above: Use whole memory area */
9199ec5c5   Krzysztof Helt   cirrusfb: remove ...
2000
2001
2002
  	info->fix.smem_len   = info->screen_size;
  	if (var->bits_per_pixel == 1)
  		info->fix.smem_len /= 4;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2003
  	info->fix.type_aux   = 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2004
2005
2006
  	info->fix.xpanstep   = 1;
  	info->fix.ypanstep   = 1;
  	info->fix.ywrapstep  = 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2007
2008
  
  	/* FIXME: map region at 0xB8000 if available, fill in here */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2009
  	info->fix.mmio_len   = 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2010
2011
2012
2013
2014
  
  	fb_alloc_cmap(&info->cmap, 256, 0);
  
  	return 0;
  }
c395d3e8c   Krzysztof Helt   cirrusfb: add __d...
2015
  static int __devinit cirrusfb_register(struct fb_info *info)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2016
  {
9199ec5c5   Krzysztof Helt   cirrusfb: remove ...
2017
  	struct cirrusfb_info *cinfo = info->par;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2018
  	int err;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2019
2020
  
  	/* sanity checks */
48c329e90   Krzysztof Helt   cirrusfb: various...
2021
  	assert(cinfo->btype != BT_NONE);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2022

a1d35a7a5   Krzysztof Helt   cirrusfb: use mod...
2023
2024
  	/* set all the vital stuff */
  	cirrusfb_set_fbinfo(info);
75ed3a17a   Krzysztof Helt   cirrusfb: convert...
2025
2026
  	dev_dbg(info->device, "(RAM start set to: 0x%p)
  ", info->screen_base);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2027

a1d35a7a5   Krzysztof Helt   cirrusfb: use mod...
2028
2029
  	err = fb_find_mode(&info->var, info, mode_option, NULL, 0, NULL, 8);
  	if (!err) {
75ed3a17a   Krzysztof Helt   cirrusfb: convert...
2030
2031
  		dev_dbg(info->device, "wrong initial video mode
  ");
a1d35a7a5   Krzysztof Helt   cirrusfb: use mod...
2032
2033
2034
  		err = -EINVAL;
  		goto err_dealloc_cmap;
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2035
  	info->var.activate = FB_ACTIVATE_NOW;
99a458475   Krzysztof Helt   cirrusfb: check_v...
2036
  	err = cirrusfb_check_var(&info->var, info);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2037
2038
  	if (err < 0) {
  		/* should never happen */
75ed3a17a   Krzysztof Helt   cirrusfb: convert...
2039
2040
2041
  		dev_dbg(info->device,
  			"choking on default var... umm, no good.
  ");
a1d35a7a5   Krzysztof Helt   cirrusfb: use mod...
2042
  		goto err_dealloc_cmap;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2043
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2044
2045
  	err = register_framebuffer(info);
  	if (err < 0) {
75ed3a17a   Krzysztof Helt   cirrusfb: convert...
2046
2047
2048
  		dev_err(info->device,
  			"could not register fb device; err = %d!
  ", err);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2049
2050
  		goto err_dealloc_cmap;
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2051
2052
2053
2054
  	return 0;
  
  err_dealloc_cmap:
  	fb_dealloc_cmap(&info->cmap);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2055
2056
  	return err;
  }
8503df659   Krzysztof Helt   cirrusfb: checkpa...
2057
  static void __devexit cirrusfb_cleanup(struct fb_info *info)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2058
2059
  {
  	struct cirrusfb_info *cinfo = info->par;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2060

8503df659   Krzysztof Helt   cirrusfb: checkpa...
2061
  	switch_monitor(cinfo, 0);
8503df659   Krzysztof Helt   cirrusfb: checkpa...
2062
2063
  	unregister_framebuffer(info);
  	fb_dealloc_cmap(&info->cmap);
75ed3a17a   Krzysztof Helt   cirrusfb: convert...
2064
2065
  	dev_dbg(info->device, "Framebuffer unregistered
  ");
9199ec5c5   Krzysztof Helt   cirrusfb: remove ...
2066
  	cinfo->unmap(info);
060b6002b   Krzysztof Helt   cirrusfb: code im...
2067
  	framebuffer_release(info);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2068
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2069
  #ifdef CONFIG_PCI
c395d3e8c   Krzysztof Helt   cirrusfb: add __d...
2070
2071
  static int __devinit cirrusfb_pci_register(struct pci_dev *pdev,
  					   const struct pci_device_id *ent)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2072
2073
2074
  {
  	struct cirrusfb_info *cinfo;
  	struct fb_info *info;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2075
2076
2077
2078
2079
2080
2081
2082
2083
2084
2085
2086
2087
2088
2089
  	unsigned long board_addr, board_size;
  	int ret;
  
  	ret = pci_enable_device(pdev);
  	if (ret < 0) {
  		printk(KERN_ERR "cirrusfb: Cannot enable PCI device
  ");
  		goto err_out;
  	}
  
  	info = framebuffer_alloc(sizeof(struct cirrusfb_info), &pdev->dev);
  	if (!info) {
  		printk(KERN_ERR "cirrusfb: could not allocate memory
  ");
  		ret = -ENOMEM;
78d780e07   Krzysztof Helt   cirrusfb: various...
2090
  		goto err_out;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2091
2092
2093
  	}
  
  	cinfo = info->par;
48c329e90   Krzysztof Helt   cirrusfb: various...
2094
  	cinfo->btype = (enum cirrus_board) ent->driver_data;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2095

75ed3a17a   Krzysztof Helt   cirrusfb: convert...
2096
2097
2098
  	dev_dbg(info->device,
  		" Found PCI device, base address 0 is 0x%Lx, btype set to %d
  ",
48c329e90   Krzysztof Helt   cirrusfb: various...
2099
  		(unsigned long long)pdev->resource[0].start,  cinfo->btype);
75ed3a17a   Krzysztof Helt   cirrusfb: convert...
2100
2101
2102
  	dev_dbg(info->device, " base address 1 is 0x%Lx
  ",
  		(unsigned long long)pdev->resource[1].start);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2103

8503df659   Krzysztof Helt   cirrusfb: checkpa...
2104
2105
  	if (isPReP) {
  		pci_write_config_dword(pdev, PCI_BASE_ADDRESS_0, 0x00000000);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2106
  #ifdef CONFIG_PPC_PREP
9199ec5c5   Krzysztof Helt   cirrusfb: remove ...
2107
  		get_prep_addrs(&board_addr, &info->fix.mmio_start);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2108
  #endif
8503df659   Krzysztof Helt   cirrusfb: checkpa...
2109
  	/* PReP dies if we ioremap the IO registers, but it works w/out... */
9199ec5c5   Krzysztof Helt   cirrusfb: remove ...
2110
  		cinfo->regbase = (char __iomem *) info->fix.mmio_start;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2111
  	} else {
75ed3a17a   Krzysztof Helt   cirrusfb: convert...
2112
2113
2114
  		dev_dbg(info->device,
  			"Attempt to get PCI info for Cirrus Graphics Card
  ");
9199ec5c5   Krzysztof Helt   cirrusfb: remove ...
2115
  		get_pci_addrs(pdev, &board_addr, &info->fix.mmio_start);
8503df659   Krzysztof Helt   cirrusfb: checkpa...
2116
2117
  		/* FIXME: this forces VGA.  alternatives? */
  		cinfo->regbase = NULL;
6e30fc086   Krzysztof Helt   cirrusfb: add mmi...
2118
  		cinfo->laguna_mmio = ioremap(info->fix.mmio_start, 0x1000);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2119
  	}
75ed3a17a   Krzysztof Helt   cirrusfb: convert...
2120
2121
  	dev_dbg(info->device, "Board address: 0x%lx, register address: 0x%lx
  ",
9199ec5c5   Krzysztof Helt   cirrusfb: remove ...
2122
  		board_addr, info->fix.mmio_start);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2123

48c329e90   Krzysztof Helt   cirrusfb: various...
2124
  	board_size = (cinfo->btype == BT_GD5480) ?
75ed3a17a   Krzysztof Helt   cirrusfb: convert...
2125
  		32 * MB_ : cirrusfb_get_memsize(info, cinfo->regbase);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2126
2127
  
  	ret = pci_request_regions(pdev, "cirrusfb");
8503df659   Krzysztof Helt   cirrusfb: checkpa...
2128
  	if (ret < 0) {
75ed3a17a   Krzysztof Helt   cirrusfb: convert...
2129
2130
2131
  		dev_err(info->device, "cannot reserve region 0x%lx, abort
  ",
  			board_addr);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2132
2133
2134
2135
  		goto err_release_fb;
  	}
  #if 0 /* if the system didn't claim this region, we would... */
  	if (!request_mem_region(0xA0000, 65535, "cirrusfb")) {
75ed3a17a   Krzysztof Helt   cirrusfb: convert...
2136
2137
2138
  		dev_err(info->device, "cannot reserve region 0x%lx, abort
  ",
  			0xA0000L);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2139
2140
2141
2142
2143
2144
  		ret = -EBUSY;
  		goto err_release_regions;
  	}
  #endif
  	if (request_region(0x3C0, 32, "cirrusfb"))
  		release_io_ports = 1;
9199ec5c5   Krzysztof Helt   cirrusfb: remove ...
2145
2146
  	info->screen_base = ioremap(board_addr, board_size);
  	if (!info->screen_base) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2147
2148
2149
  		ret = -EIO;
  		goto err_release_legacy;
  	}
9199ec5c5   Krzysztof Helt   cirrusfb: remove ...
2150
2151
  	info->fix.smem_start = board_addr;
  	info->screen_size = board_size;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2152
  	cinfo->unmap = cirrusfb_pci_unmap;
75ed3a17a   Krzysztof Helt   cirrusfb: convert...
2153
2154
2155
2156
  	dev_info(info->device,
  		 "Cirrus Logic chipset on PCI bus, RAM (%lu kB) at 0x%lx
  ",
  		 info->screen_size >> 10, board_addr);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2157
  	pci_set_drvdata(pdev, info);
9199ec5c5   Krzysztof Helt   cirrusfb: remove ...
2158
  	ret = cirrusfb_register(info);
78d780e07   Krzysztof Helt   cirrusfb: various...
2159
2160
  	if (!ret)
  		return 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2161

78d780e07   Krzysztof Helt   cirrusfb: various...
2162
2163
  	pci_set_drvdata(pdev, NULL);
  	iounmap(info->screen_base);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2164
2165
2166
2167
2168
2169
2170
2171
2172
  err_release_legacy:
  	if (release_io_ports)
  		release_region(0x3C0, 32);
  #if 0
  	release_mem_region(0xA0000, 65535);
  err_release_regions:
  #endif
  	pci_release_regions(pdev);
  err_release_fb:
78d780e07   Krzysztof Helt   cirrusfb: various...
2173
  	if (cinfo->laguna_mmio != NULL)
6e30fc086   Krzysztof Helt   cirrusfb: add mmi...
2174
  		iounmap(cinfo->laguna_mmio);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2175
  	framebuffer_release(info);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2176
2177
2178
  err_out:
  	return ret;
  }
8503df659   Krzysztof Helt   cirrusfb: checkpa...
2179
  static void __devexit cirrusfb_pci_unregister(struct pci_dev *pdev)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2180
2181
  {
  	struct fb_info *info = pci_get_drvdata(pdev);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2182

8503df659   Krzysztof Helt   cirrusfb: checkpa...
2183
  	cirrusfb_cleanup(info);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2184
2185
2186
2187
2188
2189
2190
2191
2192
2193
2194
2195
2196
2197
2198
  }
  
  static struct pci_driver cirrusfb_pci_driver = {
  	.name		= "cirrusfb",
  	.id_table	= cirrusfb_pci_table,
  	.probe		= cirrusfb_pci_register,
  	.remove		= __devexit_p(cirrusfb_pci_unregister),
  #ifdef CONFIG_PM
  #if 0
  	.suspend	= cirrusfb_pci_suspend,
  	.resume		= cirrusfb_pci_resume,
  #endif
  #endif
  };
  #endif /* CONFIG_PCI */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2199
  #ifdef CONFIG_ZORRO
c395d3e8c   Krzysztof Helt   cirrusfb: add __d...
2200
2201
  static int __devinit cirrusfb_zorro_register(struct zorro_dev *z,
  					     const struct zorro_device_id *ent)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2202
  {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2203
  	struct fb_info *info;
0e0d13364   Geert Uytterhoeven   fbdev/cirrusfb: R...
2204
2205
  	int error;
  	const struct zorrocl *zcl;
7345de32d   Krzysztof Helt   cirrusfb: remove ...
2206
  	enum cirrus_board btype;
0e0d13364   Geert Uytterhoeven   fbdev/cirrusfb: R...
2207
2208
  	unsigned long regbase, ramsize, rambase;
  	struct cirrusfb_info *cinfo;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2209
2210
2211
  
  	info = framebuffer_alloc(sizeof(struct cirrusfb_info), &z->dev);
  	if (!info) {
8503df659   Krzysztof Helt   cirrusfb: checkpa...
2212
2213
  		printk(KERN_ERR "cirrusfb: could not allocate memory
  ");
0e0d13364   Geert Uytterhoeven   fbdev/cirrusfb: R...
2214
  		return -ENOMEM;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2215
  	}
0e0d13364   Geert Uytterhoeven   fbdev/cirrusfb: R...
2216
2217
2218
2219
2220
2221
  	zcl = (const struct zorrocl *)ent->driver_data;
  	btype = zcl->type;
  	regbase = zorro_resource_start(z) + zcl->regoffset;
  	ramsize = zcl->ramsize;
  	if (ramsize) {
  		rambase = zorro_resource_start(z) + zcl->ramoffset;
e78bb882b   Geert Uytterhoeven   fbdev/cirrusfb: A...
2222
2223
2224
2225
  		if (zorro_resource_len(z) == 64 * MB_) {
  			/* Quirk for 64 MiB Picasso IV */
  			rambase += zcl->ramoffset;
  		}
0e0d13364   Geert Uytterhoeven   fbdev/cirrusfb: R...
2226
2227
2228
2229
2230
2231
2232
2233
2234
2235
  	} else {
  		struct zorro_dev *ram = zorro_find_device(zcl->ramid, NULL);
  		if (!ram || !zorro_resource_len(ram)) {
  			dev_err(info->device, "No video RAM found
  ");
  			error = -ENODEV;
  			goto err_release_fb;
  		}
  		rambase = zorro_resource_start(ram);
  		ramsize = zorro_resource_len(ram);
17bdf4895   Geert Uytterhoeven   fbdev/cirrusfb: A...
2236
2237
2238
2239
2240
2241
2242
2243
2244
2245
2246
  		if (zcl->ramid2 &&
  		    (ram = zorro_find_device(zcl->ramid2, NULL))) {
  			if (zorro_resource_start(ram) != rambase + ramsize) {
  				dev_warn(info->device,
  					 "Skipping non-contiguous RAM at %pR
  ",
  					 &ram->resource);
  			} else {
  				ramsize += zorro_resource_len(ram);
  			}
  		}
0e0d13364   Geert Uytterhoeven   fbdev/cirrusfb: R...
2247
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2248

0e0d13364   Geert Uytterhoeven   fbdev/cirrusfb: R...
2249
2250
2251
2252
2253
  	dev_info(info->device,
  		 "%s board detected, REG at 0x%lx, %lu MiB RAM at 0x%lx
  ",
  		 cirrusfb_board_info[btype].name, regbase, ramsize / MB_,
  		 rambase);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2254
2255
  
  	if (!zorro_request_device(z, "cirrusfb")) {
0e0d13364   Geert Uytterhoeven   fbdev/cirrusfb: R...
2256
2257
2258
  		dev_err(info->device, "Cannot reserve %pR
  ", &z->resource);
  		error = -EBUSY;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2259
2260
  		goto err_release_fb;
  	}
0e0d13364   Geert Uytterhoeven   fbdev/cirrusfb: R...
2261
2262
  	cinfo = info->par;
  	cinfo->btype = btype;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2263

0e0d13364   Geert Uytterhoeven   fbdev/cirrusfb: R...
2264
2265
2266
2267
2268
2269
2270
2271
2272
  	info->fix.mmio_start = regbase;
  	cinfo->regbase = regbase > 16 * MB_ ? ioremap(regbase, 64 * 1024)
  					    : (caddr_t)ZTWO_VADDR(regbase);
  	if (!cinfo->regbase) {
  		dev_err(info->device, "Cannot map registers
  ");
  		error = -EIO;
  		goto err_release_dev;
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2273

0e0d13364   Geert Uytterhoeven   fbdev/cirrusfb: R...
2274
2275
2276
2277
2278
2279
2280
2281
2282
  	info->fix.smem_start = rambase;
  	info->screen_size = ramsize;
  	info->screen_base = rambase > 16 * MB_ ? ioremap(rambase, ramsize)
  					       : (caddr_t)ZTWO_VADDR(rambase);
  	if (!info->screen_base) {
  		dev_err(info->device, "Cannot map video RAM
  ");
  		error = -EIO;
  		goto err_unmap_reg;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2283
  	}
0e0d13364   Geert Uytterhoeven   fbdev/cirrusfb: R...
2284

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2285
  	cinfo->unmap = cirrusfb_zorro_unmap;
75ed3a17a   Krzysztof Helt   cirrusfb: convert...
2286
  	dev_info(info->device,
0e0d13364   Geert Uytterhoeven   fbdev/cirrusfb: R...
2287
2288
2289
  		 "Cirrus Logic chipset on Zorro bus, RAM (%lu MiB) at 0x%lx
  ",
  		 ramsize / MB_, rambase);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2290

8f19e15b8   Krzysztof Helt   cirrusfb: set MCL...
2291
2292
2293
2294
  	/* MCLK select etc. */
  	if (cirrusfb_board_info[btype].init_sr1f)
  		vga_wseq(cinfo->regbase, CL_SEQR1F,
  			 cirrusfb_board_info[btype].sr1f);
0e0d13364   Geert Uytterhoeven   fbdev/cirrusfb: R...
2295
2296
2297
2298
2299
2300
2301
  	error = cirrusfb_register(info);
  	if (error) {
  		dev_err(info->device, "Failed to register device, error %d
  ",
  			error);
  		goto err_unmap_ram;
  	}
bc5d8ac02   Krzysztof Helt   cirrusfb: fix err...
2302

0e0d13364   Geert Uytterhoeven   fbdev/cirrusfb: R...
2303
2304
  	zorro_set_drvdata(z, info);
  	return 0;
bc5d8ac02   Krzysztof Helt   cirrusfb: fix err...
2305

0e0d13364   Geert Uytterhoeven   fbdev/cirrusfb: R...
2306
2307
  err_unmap_ram:
  	if (rambase > 16 * MB_)
bc5d8ac02   Krzysztof Helt   cirrusfb: fix err...
2308
  		iounmap(info->screen_base);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2309

0e0d13364   Geert Uytterhoeven   fbdev/cirrusfb: R...
2310
2311
2312
2313
2314
  err_unmap_reg:
  	if (regbase > 16 * MB_)
  		iounmap(cinfo->regbase);
  err_release_dev:
  	zorro_release_device(z);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2315
2316
  err_release_fb:
  	framebuffer_release(info);
0e0d13364   Geert Uytterhoeven   fbdev/cirrusfb: R...
2317
  	return error;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2318
2319
2320
2321
2322
  }
  
  void __devexit cirrusfb_zorro_unregister(struct zorro_dev *z)
  {
  	struct fb_info *info = zorro_get_drvdata(z);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2323

8503df659   Krzysztof Helt   cirrusfb: checkpa...
2324
  	cirrusfb_cleanup(info);
0e0d13364   Geert Uytterhoeven   fbdev/cirrusfb: R...
2325
  	zorro_set_drvdata(z, NULL);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2326
2327
2328
2329
2330
2331
2332
2333
2334
  }
  
  static struct zorro_driver cirrusfb_zorro_driver = {
  	.name		= "cirrusfb",
  	.id_table	= cirrusfb_zorro_table,
  	.probe		= cirrusfb_zorro_register,
  	.remove		= __devexit_p(cirrusfb_zorro_unregister),
  };
  #endif /* CONFIG_ZORRO */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2335
  #ifndef MODULE
75ed3a17a   Krzysztof Helt   cirrusfb: convert...
2336
2337
  static int __init cirrusfb_setup(char *options)
  {
ee11940f8   Vlada Peric   cirrusfb: remove ...
2338
  	char *this_opt;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2339

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2340
2341
  	if (!options || !*options)
  		return 0;
8503df659   Krzysztof Helt   cirrusfb: checkpa...
2342
  	while ((this_opt = strsep(&options, ",")) != NULL) {
a1d35a7a5   Krzysztof Helt   cirrusfb: use mod...
2343
2344
  		if (!*this_opt)
  			continue;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2345

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2346
2347
  		if (!strcmp(this_opt, "noaccel"))
  			noaccel = 1;
a1d35a7a5   Krzysztof Helt   cirrusfb: use mod...
2348
2349
2350
2351
  		else if (!strncmp(this_opt, "mode:", 5))
  			mode_option = this_opt + 5;
  		else
  			mode_option = this_opt;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2352
2353
2354
2355
  	}
  	return 0;
  }
  #endif
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2356
2357
2358
2359
2360
2361
2362
      /*
       *  Modularization
       */
  
  MODULE_AUTHOR("Copyright 1999,2000 Jeff Garzik <jgarzik@pobox.com>");
  MODULE_DESCRIPTION("Accelerated FBDev driver for Cirrus Logic chips");
  MODULE_LICENSE("GPL");
48c329e90   Krzysztof Helt   cirrusfb: various...
2363
2364
2365
2366
2367
2368
2369
2370
2371
2372
2373
2374
2375
2376
2377
2378
2379
2380
2381
2382
  static int __init cirrusfb_init(void)
  {
  	int error = 0;
  
  #ifndef MODULE
  	char *option = NULL;
  
  	if (fb_get_options("cirrusfb", &option))
  		return -ENODEV;
  	cirrusfb_setup(option);
  #endif
  
  #ifdef CONFIG_ZORRO
  	error |= zorro_register_driver(&cirrusfb_zorro_driver);
  #endif
  #ifdef CONFIG_PCI
  	error |= pci_register_driver(&cirrusfb_pci_driver);
  #endif
  	return error;
  }
8503df659   Krzysztof Helt   cirrusfb: checkpa...
2383
  static void __exit cirrusfb_exit(void)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2384
2385
2386
2387
2388
2389
2390
2391
2392
2393
  {
  #ifdef CONFIG_PCI
  	pci_unregister_driver(&cirrusfb_pci_driver);
  #endif
  #ifdef CONFIG_ZORRO
  	zorro_unregister_driver(&cirrusfb_zorro_driver);
  #endif
  }
  
  module_init(cirrusfb_init);
a1d35a7a5   Krzysztof Helt   cirrusfb: use mod...
2394
2395
  module_param(mode_option, charp, 0);
  MODULE_PARM_DESC(mode_option, "Initial video mode e.g. '648x480-8@60'");
55a0dd83e   Krzysztof Helt   cirrusfb: add noa...
2396
2397
  module_param(noaccel, bool, 0);
  MODULE_PARM_DESC(noaccel, "Disable acceleration");
a1d35a7a5   Krzysztof Helt   cirrusfb: use mod...
2398

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2399
2400
2401
  #ifdef MODULE
  module_exit(cirrusfb_exit);
  #endif
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2402
2403
2404
2405
  /**********************************************************************/
  /* about the following functions - I have used the same names for the */
  /* functions as Markus Wild did in his Retina driver for NetBSD as    */
  /* they just made sense for this purpose. Apart from that, I wrote    */
8503df659   Krzysztof Helt   cirrusfb: checkpa...
2406
  /* these functions myself.					    */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2407
2408
2409
  /**********************************************************************/
  
  /*** WGen() - write into one of the external/general registers ***/
8503df659   Krzysztof Helt   cirrusfb: checkpa...
2410
  static void WGen(const struct cirrusfb_info *cinfo,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2411
2412
2413
2414
2415
2416
  		  int regnum, unsigned char val)
  {
  	unsigned long regofs = 0;
  
  	if (cinfo->btype == BT_PICASSO) {
  		/* Picasso II specific hack */
8503df659   Krzysztof Helt   cirrusfb: checkpa...
2417
2418
  /*	      if (regnum == VGA_PEL_IR || regnum == VGA_PEL_D ||
  		  regnum == CL_VSSM2) */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2419
2420
2421
  		if (regnum == VGA_PEL_IR || regnum == VGA_PEL_D)
  			regofs = 0xfff;
  	}
8503df659   Krzysztof Helt   cirrusfb: checkpa...
2422
  	vga_w(cinfo->regbase, regofs + regnum, val);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2423
2424
2425
  }
  
  /*** RGen() - read out one of the external/general registers ***/
8503df659   Krzysztof Helt   cirrusfb: checkpa...
2426
  static unsigned char RGen(const struct cirrusfb_info *cinfo, int regnum)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2427
2428
2429
2430
2431
  {
  	unsigned long regofs = 0;
  
  	if (cinfo->btype == BT_PICASSO) {
  		/* Picasso II specific hack */
8503df659   Krzysztof Helt   cirrusfb: checkpa...
2432
2433
  /*	      if (regnum == VGA_PEL_IR || regnum == VGA_PEL_D ||
  		  regnum == CL_VSSM2) */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2434
2435
2436
  		if (regnum == VGA_PEL_IR || regnum == VGA_PEL_D)
  			regofs = 0xfff;
  	}
8503df659   Krzysztof Helt   cirrusfb: checkpa...
2437
  	return vga_r(cinfo->regbase, regofs + regnum);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2438
2439
2440
  }
  
  /*** AttrOn() - turn on VideoEnable for Attribute controller ***/
8503df659   Krzysztof Helt   cirrusfb: checkpa...
2441
  static void AttrOn(const struct cirrusfb_info *cinfo)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2442
  {
8503df659   Krzysztof Helt   cirrusfb: checkpa...
2443
  	assert(cinfo != NULL);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2444

8503df659   Krzysztof Helt   cirrusfb: checkpa...
2445
  	if (vga_rcrt(cinfo->regbase, CL_CRT24) & 0x80) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2446
2447
  		/* if we're just in "write value" mode, write back the */
  		/* same value as before to not modify anything */
8503df659   Krzysztof Helt   cirrusfb: checkpa...
2448
2449
  		vga_w(cinfo->regbase, VGA_ATT_IW,
  		      vga_r(cinfo->regbase, VGA_ATT_R));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2450
2451
  	}
  	/* turn on video bit */
8503df659   Krzysztof Helt   cirrusfb: checkpa...
2452
2453
  /*      vga_w(cinfo->regbase, VGA_ATT_IW, 0x20); */
  	vga_w(cinfo->regbase, VGA_ATT_IW, 0x33);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2454
2455
  
  	/* dummy write on Reg0 to be on "write index" mode next time */
8503df659   Krzysztof Helt   cirrusfb: checkpa...
2456
  	vga_w(cinfo->regbase, VGA_ATT_IW, 0x00);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2457
2458
2459
2460
2461
2462
2463
2464
  }
  
  /*** WHDR() - write into the Hidden DAC register ***/
  /* as the HDR is the only extension register that requires special treatment
   * (the other extension registers are accessible just like the "ordinary"
   * registers of their functional group) here is a specialized routine for
   * accessing the HDR
   */
8503df659   Krzysztof Helt   cirrusfb: checkpa...
2465
  static void WHDR(const struct cirrusfb_info *cinfo, unsigned char val)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2466
2467
  {
  	unsigned char dummy;
78d780e07   Krzysztof Helt   cirrusfb: various...
2468
  	if (is_laguna(cinfo))
1b48cb563   Krzysztof Helt   cirrusfb: Laguna ...
2469
  		return;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2470
2471
2472
  	if (cinfo->btype == BT_PICASSO) {
  		/* Klaus' hint for correct access to HDR on some boards */
  		/* first write 0 to pixel mask (3c6) */
8503df659   Krzysztof Helt   cirrusfb: checkpa...
2473
2474
  		WGen(cinfo, VGA_PEL_MSK, 0x00);
  		udelay(200);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2475
  		/* next read dummy from pixel address (3c8) */
8503df659   Krzysztof Helt   cirrusfb: checkpa...
2476
2477
  		dummy = RGen(cinfo, VGA_PEL_IW);
  		udelay(200);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2478
2479
  	}
  	/* now do the usual stuff to access the HDR */
8503df659   Krzysztof Helt   cirrusfb: checkpa...
2480
2481
2482
2483
2484
2485
2486
2487
  	dummy = RGen(cinfo, VGA_PEL_MSK);
  	udelay(200);
  	dummy = RGen(cinfo, VGA_PEL_MSK);
  	udelay(200);
  	dummy = RGen(cinfo, VGA_PEL_MSK);
  	udelay(200);
  	dummy = RGen(cinfo, VGA_PEL_MSK);
  	udelay(200);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2488

8503df659   Krzysztof Helt   cirrusfb: checkpa...
2489
2490
  	WGen(cinfo, VGA_PEL_MSK, val);
  	udelay(200);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2491
2492
2493
  
  	if (cinfo->btype == BT_PICASSO) {
  		/* now first reset HDR access counter */
8503df659   Krzysztof Helt   cirrusfb: checkpa...
2494
2495
  		dummy = RGen(cinfo, VGA_PEL_IW);
  		udelay(200);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2496
2497
2498
  
  		/* and at the end, restore the mask value */
  		/* ## is this mask always 0xff? */
8503df659   Krzysztof Helt   cirrusfb: checkpa...
2499
2500
  		WGen(cinfo, VGA_PEL_MSK, 0xff);
  		udelay(200);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2501
2502
  	}
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2503
  /*** WSFR() - write to the "special function register" (SFR) ***/
8503df659   Krzysztof Helt   cirrusfb: checkpa...
2504
  static void WSFR(struct cirrusfb_info *cinfo, unsigned char val)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2505
2506
  {
  #ifdef CONFIG_ZORRO
8503df659   Krzysztof Helt   cirrusfb: checkpa...
2507
  	assert(cinfo->regbase != NULL);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2508
  	cinfo->SFR = val;
8503df659   Krzysztof Helt   cirrusfb: checkpa...
2509
  	z_writeb(val, cinfo->regbase + 0x8000);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2510
2511
2512
2513
  #endif
  }
  
  /* The Picasso has a second register for switching the monitor bit */
8503df659   Krzysztof Helt   cirrusfb: checkpa...
2514
  static void WSFR2(struct cirrusfb_info *cinfo, unsigned char val)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2515
2516
2517
2518
  {
  #ifdef CONFIG_ZORRO
  	/* writing an arbitrary value to this one causes the monitor switcher */
  	/* to flip to Amiga display */
8503df659   Krzysztof Helt   cirrusfb: checkpa...
2519
  	assert(cinfo->regbase != NULL);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2520
  	cinfo->SFR = val;
8503df659   Krzysztof Helt   cirrusfb: checkpa...
2521
  	z_writeb(val, cinfo->regbase + 0x9000);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2522
2523
  #endif
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2524
  /*** WClut - set CLUT entry (range: 0..63) ***/
8503df659   Krzysztof Helt   cirrusfb: checkpa...
2525
  static void WClut(struct cirrusfb_info *cinfo, unsigned char regnum, unsigned char red,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2526
2527
2528
2529
2530
  	    unsigned char green, unsigned char blue)
  {
  	unsigned int data = VGA_PEL_D;
  
  	/* address write mode register is not translated.. */
8503df659   Krzysztof Helt   cirrusfb: checkpa...
2531
  	vga_w(cinfo->regbase, VGA_PEL_IW, regnum);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2532
2533
  
  	if (cinfo->btype == BT_PICASSO || cinfo->btype == BT_PICASSO4 ||
1b48cb563   Krzysztof Helt   cirrusfb: Laguna ...
2534
  	    cinfo->btype == BT_ALPINE || cinfo->btype == BT_GD5480 ||
df3aafd57   Krzysztof Helt   cirrusfb: GD5434 ...
2535
  	    cinfo->btype == BT_SD64 || is_laguna(cinfo)) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2536
2537
2538
  		/* but DAC data register IS, at least for Picasso II */
  		if (cinfo->btype == BT_PICASSO)
  			data += 0xfff;
8503df659   Krzysztof Helt   cirrusfb: checkpa...
2539
2540
2541
  		vga_w(cinfo->regbase, data, red);
  		vga_w(cinfo->regbase, data, green);
  		vga_w(cinfo->regbase, data, blue);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2542
  	} else {
8503df659   Krzysztof Helt   cirrusfb: checkpa...
2543
2544
2545
  		vga_w(cinfo->regbase, data, blue);
  		vga_w(cinfo->regbase, data, green);
  		vga_w(cinfo->regbase, data, red);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2546
2547
  	}
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2548
2549
  #if 0
  /*** RClut - read CLUT entry (range 0..63) ***/
8503df659   Krzysztof Helt   cirrusfb: checkpa...
2550
  static void RClut(struct cirrusfb_info *cinfo, unsigned char regnum, unsigned char *red,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2551
2552
2553
  	    unsigned char *green, unsigned char *blue)
  {
  	unsigned int data = VGA_PEL_D;
8503df659   Krzysztof Helt   cirrusfb: checkpa...
2554
  	vga_w(cinfo->regbase, VGA_PEL_IR, regnum);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2555
2556
2557
2558
2559
  
  	if (cinfo->btype == BT_PICASSO || cinfo->btype == BT_PICASSO4 ||
  	    cinfo->btype == BT_ALPINE || cinfo->btype == BT_GD5480) {
  		if (cinfo->btype == BT_PICASSO)
  			data += 0xfff;
8503df659   Krzysztof Helt   cirrusfb: checkpa...
2560
2561
2562
  		*red = vga_r(cinfo->regbase, data);
  		*green = vga_r(cinfo->regbase, data);
  		*blue = vga_r(cinfo->regbase, data);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2563
  	} else {
8503df659   Krzysztof Helt   cirrusfb: checkpa...
2564
2565
2566
  		*blue = vga_r(cinfo->regbase, data);
  		*green = vga_r(cinfo->regbase, data);
  		*red = vga_r(cinfo->regbase, data);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2567
2568
2569
  	}
  }
  #endif
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2570
2571
2572
2573
2574
2575
2576
  /*******************************************************************
  	cirrusfb_WaitBLT()
  
  	Wait for the BitBLT engine to complete a possible earlier job
  *********************************************************************/
  
  /* FIXME: use interrupts instead */
8503df659   Krzysztof Helt   cirrusfb: checkpa...
2577
  static void cirrusfb_WaitBLT(u8 __iomem *regbase)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2578
  {
8503df659   Krzysztof Helt   cirrusfb: checkpa...
2579
  	while (vga_rgfx(regbase, CL_GR31) & 0x08)
48c329e90   Krzysztof Helt   cirrusfb: various...
2580
  		cpu_relax();
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2581
2582
2583
2584
2585
2586
2587
  }
  
  /*******************************************************************
  	cirrusfb_BitBLT()
  
  	perform accelerated "scrolling"
  ********************************************************************/
8343c89c4   Krzysztof Helt   cirrusfb: acceler...
2588
2589
2590
2591
  static void cirrusfb_set_blitter(u8 __iomem *regbase,
  			    u_short nwidth, u_short nheight,
  			    u_long nsrc, u_long ndest,
  			    u_short bltmode, u_short line_length)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2592

8343c89c4   Krzysztof Helt   cirrusfb: acceler...
2593
  {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2594
  	/* pitch: set to line_length */
8503df659   Krzysztof Helt   cirrusfb: checkpa...
2595
2596
2597
2598
2599
2600
2601
2602
  	/* dest pitch low */
  	vga_wgfx(regbase, CL_GR24, line_length & 0xff);
  	/* dest pitch hi */
  	vga_wgfx(regbase, CL_GR25, line_length >> 8);
  	/* source pitch low */
  	vga_wgfx(regbase, CL_GR26, line_length & 0xff);
  	/* source pitch hi */
  	vga_wgfx(regbase, CL_GR27, line_length >> 8);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2603
2604
  
  	/* BLT width: actual number of pixels - 1 */
8503df659   Krzysztof Helt   cirrusfb: checkpa...
2605
2606
2607
2608
  	/* BLT width low */
  	vga_wgfx(regbase, CL_GR20, nwidth & 0xff);
  	/* BLT width hi */
  	vga_wgfx(regbase, CL_GR21, nwidth >> 8);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2609
2610
  
  	/* BLT height: actual number of lines -1 */
8503df659   Krzysztof Helt   cirrusfb: checkpa...
2611
2612
2613
2614
  	/* BLT height low */
  	vga_wgfx(regbase, CL_GR22, nheight & 0xff);
  	/* BLT width hi */
  	vga_wgfx(regbase, CL_GR23, nheight >> 8);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2615
2616
  
  	/* BLT destination */
8503df659   Krzysztof Helt   cirrusfb: checkpa...
2617
2618
2619
2620
2621
2622
  	/* BLT dest low */
  	vga_wgfx(regbase, CL_GR28, (u_char) (ndest & 0xff));
  	/* BLT dest mid */
  	vga_wgfx(regbase, CL_GR29, (u_char) (ndest >> 8));
  	/* BLT dest hi */
  	vga_wgfx(regbase, CL_GR2A, (u_char) (ndest >> 16));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2623
2624
  
  	/* BLT source */
8503df659   Krzysztof Helt   cirrusfb: checkpa...
2625
2626
2627
2628
2629
2630
  	/* BLT src low */
  	vga_wgfx(regbase, CL_GR2C, (u_char) (nsrc & 0xff));
  	/* BLT src mid */
  	vga_wgfx(regbase, CL_GR2D, (u_char) (nsrc >> 8));
  	/* BLT src hi */
  	vga_wgfx(regbase, CL_GR2E, (u_char) (nsrc >> 16));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2631
2632
  
  	/* BLT mode */
8503df659   Krzysztof Helt   cirrusfb: checkpa...
2633
  	vga_wgfx(regbase, CL_GR30, bltmode);	/* BLT mode */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2634
2635
  
  	/* BLT ROP: SrcCopy */
8503df659   Krzysztof Helt   cirrusfb: checkpa...
2636
  	vga_wgfx(regbase, CL_GR32, 0x0d);	/* BLT ROP */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2637
2638
  
  	/* and finally: GO! */
527410ff7   Krzysztof Helt   cirrusfb: GD5446 ...
2639
  	vga_wgfx(regbase, CL_GR31, 0x02);	/* BLT Start/status */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2640
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2641
  /*******************************************************************
8343c89c4   Krzysztof Helt   cirrusfb: acceler...
2642
  	cirrusfb_BitBLT()
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2643

8343c89c4   Krzysztof Helt   cirrusfb: acceler...
2644
  	perform accelerated "scrolling"
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2645
  ********************************************************************/
8343c89c4   Krzysztof Helt   cirrusfb: acceler...
2646
2647
2648
2649
2650
  static void cirrusfb_BitBLT(u8 __iomem *regbase, int bits_per_pixel,
  			    u_short curx, u_short cury,
  			    u_short destx, u_short desty,
  			    u_short width, u_short height,
  			    u_short line_length)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2651
  {
8343c89c4   Krzysztof Helt   cirrusfb: acceler...
2652
2653
2654
2655
  	u_short nwidth = width - 1;
  	u_short nheight = height - 1;
  	u_long nsrc, ndest;
  	u_char bltmode;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2656

8343c89c4   Krzysztof Helt   cirrusfb: acceler...
2657
2658
2659
2660
2661
2662
2663
2664
2665
2666
2667
2668
2669
2670
2671
2672
2673
2674
2675
2676
  	bltmode = 0x00;
  	/* if source adr < dest addr, do the Blt backwards */
  	if (cury <= desty) {
  		if (cury == desty) {
  			/* if src and dest are on the same line, check x */
  			if (curx < destx)
  				bltmode |= 0x01;
  		} else
  			bltmode |= 0x01;
  	}
  	/* standard case: forward blitting */
  	nsrc = (cury * line_length) + curx;
  	ndest = (desty * line_length) + destx;
  	if (bltmode) {
  		/* this means start addresses are at the end,
  		 * counting backwards
  		 */
  		nsrc += nheight * line_length + nwidth;
  		ndest += nheight * line_length + nwidth;
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2677

8503df659   Krzysztof Helt   cirrusfb: checkpa...
2678
  	cirrusfb_WaitBLT(regbase);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2679

8343c89c4   Krzysztof Helt   cirrusfb: acceler...
2680
2681
2682
  	cirrusfb_set_blitter(regbase, nwidth, nheight,
  			    nsrc, ndest, bltmode, line_length);
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2683

8343c89c4   Krzysztof Helt   cirrusfb: acceler...
2684
2685
  /*******************************************************************
  	cirrusfb_RectFill()
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2686

8343c89c4   Krzysztof Helt   cirrusfb: acceler...
2687
2688
  	perform accelerated rectangle fill
  ********************************************************************/
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2689

8343c89c4   Krzysztof Helt   cirrusfb: acceler...
2690
2691
  static void cirrusfb_RectFill(u8 __iomem *regbase, int bits_per_pixel,
  		     u_short x, u_short y, u_short width, u_short height,
9e8480625   Krzysztof Helt   cirrusfb: add ima...
2692
2693
  		     u32 fg_color, u32 bg_color, u_short line_length,
  		     u_char blitmode)
8343c89c4   Krzysztof Helt   cirrusfb: acceler...
2694
2695
2696
  {
  	u_long ndest = (y * line_length) + x;
  	u_char op;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2697

8343c89c4   Krzysztof Helt   cirrusfb: acceler...
2698
  	cirrusfb_WaitBLT(regbase);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2699
2700
2701
  
  	/* This is a ColorExpand Blt, using the */
  	/* same color for foreground and background */
9e8480625   Krzysztof Helt   cirrusfb: add ima...
2702
2703
  	vga_wgfx(regbase, VGA_GFX_SR_VALUE, bg_color);
  	vga_wgfx(regbase, VGA_GFX_SR_ENABLE, fg_color);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2704

9e8480625   Krzysztof Helt   cirrusfb: add ima...
2705
  	op = 0x80;
8343c89c4   Krzysztof Helt   cirrusfb: acceler...
2706
  	if (bits_per_pixel >= 16) {
9e8480625   Krzysztof Helt   cirrusfb: add ima...
2707
2708
2709
  		vga_wgfx(regbase, CL_GR10, bg_color >> 8);
  		vga_wgfx(regbase, CL_GR11, fg_color >> 8);
  		op = 0x90;
8343c89c4   Krzysztof Helt   cirrusfb: acceler...
2710
  	}
7cade31ca   Krzysztof Helt   cirrusfb: use 24b...
2711
  	if (bits_per_pixel >= 24) {
9e8480625   Krzysztof Helt   cirrusfb: add ima...
2712
2713
  		vga_wgfx(regbase, CL_GR12, bg_color >> 16);
  		vga_wgfx(regbase, CL_GR13, fg_color >> 16);
7cade31ca   Krzysztof Helt   cirrusfb: use 24b...
2714
2715
2716
  		op = 0xa0;
  	}
  	if (bits_per_pixel == 32) {
9e8480625   Krzysztof Helt   cirrusfb: add ima...
2717
2718
2719
  		vga_wgfx(regbase, CL_GR14, bg_color >> 24);
  		vga_wgfx(regbase, CL_GR15, fg_color >> 24);
  		op = 0xb0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2720
  	}
8343c89c4   Krzysztof Helt   cirrusfb: acceler...
2721
  	cirrusfb_set_blitter(regbase, width - 1, height - 1,
9e8480625   Krzysztof Helt   cirrusfb: add ima...
2722
  			    0, ndest, op | blitmode, line_length);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2723
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2724
2725
2726
2727
  /**************************************************************************
   * bestclock() - determine closest possible clock lower(?) than the
   * desired pixel clock
   **************************************************************************/
dafa32c5a   Krzysztof Helt   cirrusfb: drop cl...
2728
  static void bestclock(long freq, int *nom, int *den, int *div)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2729
  {
dafa32c5a   Krzysztof Helt   cirrusfb: drop cl...
2730
2731
  	int n, d;
  	long h, diff;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2732

8503df659   Krzysztof Helt   cirrusfb: checkpa...
2733
2734
2735
  	assert(nom != NULL);
  	assert(den != NULL);
  	assert(div != NULL);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2736
2737
2738
2739
  
  	*nom = 0;
  	*den = 0;
  	*div = 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2740
2741
  	if (freq < 8000)
  		freq = 8000;
dafa32c5a   Krzysztof Helt   cirrusfb: drop cl...
2742
  	diff = freq;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2743
2744
  
  	for (n = 32; n < 128; n++) {
7528f5438   Krzysztof Helt   cirrusfb: simplif...
2745
  		int s = 0;
dafa32c5a   Krzysztof Helt   cirrusfb: drop cl...
2746
  		d = (14318 * n) / freq;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2747
  		if ((d >= 7) && (d <= 63)) {
7528f5438   Krzysztof Helt   cirrusfb: simplif...
2748
2749
2750
2751
2752
2753
2754
  			int temp = d;
  
  			if (temp > 31) {
  				s = 1;
  				temp >>= 1;
  			}
  			h = ((14318 * n) / temp) >> s;
dafa32c5a   Krzysztof Helt   cirrusfb: drop cl...
2755
2756
2757
  			h = h > freq ? h - freq : freq - h;
  			if (h < diff) {
  				diff = h;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2758
  				*nom = n;
7528f5438   Krzysztof Helt   cirrusfb: simplif...
2759
2760
  				*den = temp;
  				*div = s;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2761
2762
  			}
  		}
7528f5438   Krzysztof Helt   cirrusfb: simplif...
2763
  		d++;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2764
  		if ((d >= 7) && (d <= 63)) {
7528f5438   Krzysztof Helt   cirrusfb: simplif...
2765
2766
2767
2768
2769
  			if (d > 31) {
  				s = 1;
  				d >>= 1;
  			}
  			h = ((14318 * n) / d) >> s;
dafa32c5a   Krzysztof Helt   cirrusfb: drop cl...
2770
2771
2772
  			h = h > freq ? h - freq : freq - h;
  			if (h < diff) {
  				diff = h;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2773
  				*nom = n;
7528f5438   Krzysztof Helt   cirrusfb: simplif...
2774
2775
  				*den = d;
  				*div = s;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2776
2777
2778
  			}
  		}
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2779
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2780
2781
2782
2783
2784
2785
2786
2787
2788
2789
  /* -------------------------------------------------------------------------
   *
   * debugging functions
   *
   * -------------------------------------------------------------------------
   */
  
  #ifdef CIRRUSFB_DEBUG
  
  /**
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2790
2791
2792
2793
2794
2795
2796
2797
2798
   * cirrusfb_dbg_print_regs
   * @base: If using newmmio, the newmmio base address, otherwise %NULL
   * @reg_class: type of registers to read: %CRT, or %SEQ
   *
   * DESCRIPTION:
   * Dumps the given list of VGA CRTC registers.  If @base is %NULL,
   * old-style I/O ports are queried for information, otherwise MMIO is
   * used at the given @base address to query the information.
   */
75ed3a17a   Krzysztof Helt   cirrusfb: convert...
2799
2800
2801
  static void cirrusfb_dbg_print_regs(struct fb_info *info,
  				    caddr_t regbase,
  				    enum cirrusfb_dbg_reg_class reg_class, ...)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2802
2803
2804
2805
2806
  {
  	va_list list;
  	unsigned char val = 0;
  	unsigned reg;
  	char *name;
8503df659   Krzysztof Helt   cirrusfb: checkpa...
2807
  	va_start(list, reg_class);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2808

8503df659   Krzysztof Helt   cirrusfb: checkpa...
2809
  	name = va_arg(list, char *);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2810
  	while (name != NULL) {
8503df659   Krzysztof Helt   cirrusfb: checkpa...
2811
  		reg = va_arg(list, int);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2812
2813
2814
  
  		switch (reg_class) {
  		case CRT:
8503df659   Krzysztof Helt   cirrusfb: checkpa...
2815
  			val = vga_rcrt(regbase, (unsigned char) reg);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2816
2817
  			break;
  		case SEQ:
8503df659   Krzysztof Helt   cirrusfb: checkpa...
2818
  			val = vga_rseq(regbase, (unsigned char) reg);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2819
2820
2821
  			break;
  		default:
  			/* should never occur */
c930faaed   Richard Knutsson   cirrusfb: convert...
2822
  			assert(false);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2823
2824
  			break;
  		}
75ed3a17a   Krzysztof Helt   cirrusfb: convert...
2825
2826
  		dev_dbg(info->device, "%8s = 0x%02X
  ", name, val);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2827

8503df659   Krzysztof Helt   cirrusfb: checkpa...
2828
  		name = va_arg(list, char *);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2829
  	}
8503df659   Krzysztof Helt   cirrusfb: checkpa...
2830
  	va_end(list);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2831
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2832
  /**
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2833
2834
2835
2836
2837
2838
2839
2840
   * cirrusfb_dbg_reg_dump
   * @base: If using newmmio, the newmmio base address, otherwise %NULL
   *
   * DESCRIPTION:
   * Dumps a list of interesting VGA and CIRRUSFB registers.  If @base is %NULL,
   * old-style I/O ports are queried for information, otherwise MMIO is
   * used at the given @base address to query the information.
   */
75ed3a17a   Krzysztof Helt   cirrusfb: convert...
2841
  static void cirrusfb_dbg_reg_dump(struct fb_info *info, caddr_t regbase)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2842
  {
75ed3a17a   Krzysztof Helt   cirrusfb: convert...
2843
2844
  	dev_dbg(info->device, "VGA CRTC register dump:
  ");
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2845

75ed3a17a   Krzysztof Helt   cirrusfb: convert...
2846
  	cirrusfb_dbg_print_regs(info, regbase, CRT,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2847
2848
2849
2850
2851
2852
2853
2854
2855
2856
2857
2858
2859
2860
2861
2862
2863
2864
2865
2866
2867
2868
2869
2870
2871
2872
2873
2874
2875
2876
2877
2878
2879
2880
2881
2882
2883
2884
2885
2886
2887
2888
2889
2890
2891
2892
2893
2894
  			   "CR00", 0x00,
  			   "CR01", 0x01,
  			   "CR02", 0x02,
  			   "CR03", 0x03,
  			   "CR04", 0x04,
  			   "CR05", 0x05,
  			   "CR06", 0x06,
  			   "CR07", 0x07,
  			   "CR08", 0x08,
  			   "CR09", 0x09,
  			   "CR0A", 0x0A,
  			   "CR0B", 0x0B,
  			   "CR0C", 0x0C,
  			   "CR0D", 0x0D,
  			   "CR0E", 0x0E,
  			   "CR0F", 0x0F,
  			   "CR10", 0x10,
  			   "CR11", 0x11,
  			   "CR12", 0x12,
  			   "CR13", 0x13,
  			   "CR14", 0x14,
  			   "CR15", 0x15,
  			   "CR16", 0x16,
  			   "CR17", 0x17,
  			   "CR18", 0x18,
  			   "CR22", 0x22,
  			   "CR24", 0x24,
  			   "CR26", 0x26,
  			   "CR2D", 0x2D,
  			   "CR2E", 0x2E,
  			   "CR2F", 0x2F,
  			   "CR30", 0x30,
  			   "CR31", 0x31,
  			   "CR32", 0x32,
  			   "CR33", 0x33,
  			   "CR34", 0x34,
  			   "CR35", 0x35,
  			   "CR36", 0x36,
  			   "CR37", 0x37,
  			   "CR38", 0x38,
  			   "CR39", 0x39,
  			   "CR3A", 0x3A,
  			   "CR3B", 0x3B,
  			   "CR3C", 0x3C,
  			   "CR3D", 0x3D,
  			   "CR3E", 0x3E,
  			   "CR3F", 0x3F,
  			   NULL);
75ed3a17a   Krzysztof Helt   cirrusfb: convert...
2895
2896
  	dev_dbg(info->device, "
  ");
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2897

75ed3a17a   Krzysztof Helt   cirrusfb: convert...
2898
2899
  	dev_dbg(info->device, "VGA SEQ register dump:
  ");
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2900

75ed3a17a   Krzysztof Helt   cirrusfb: convert...
2901
  	cirrusfb_dbg_print_regs(info, regbase, SEQ,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2902
2903
2904
2905
2906
2907
2908
2909
2910
2911
2912
2913
2914
2915
2916
2917
2918
2919
2920
2921
2922
2923
2924
2925
2926
2927
2928
  			   "SR00", 0x00,
  			   "SR01", 0x01,
  			   "SR02", 0x02,
  			   "SR03", 0x03,
  			   "SR04", 0x04,
  			   "SR08", 0x08,
  			   "SR09", 0x09,
  			   "SR0A", 0x0A,
  			   "SR0B", 0x0B,
  			   "SR0D", 0x0D,
  			   "SR10", 0x10,
  			   "SR11", 0x11,
  			   "SR12", 0x12,
  			   "SR13", 0x13,
  			   "SR14", 0x14,
  			   "SR15", 0x15,
  			   "SR16", 0x16,
  			   "SR17", 0x17,
  			   "SR18", 0x18,
  			   "SR19", 0x19,
  			   "SR1A", 0x1A,
  			   "SR1B", 0x1B,
  			   "SR1C", 0x1C,
  			   "SR1D", 0x1D,
  			   "SR1E", 0x1E,
  			   "SR1F", 0x1F,
  			   NULL);
75ed3a17a   Krzysztof Helt   cirrusfb: convert...
2929
2930
  	dev_dbg(info->device, "
  ");
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2931
2932
2933
  }
  
  #endif				/* CIRRUSFB_DEBUG */