Blame view

drivers/video/pm2fb.c 49.3 KB
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1
2
3
4
5
6
7
8
9
10
11
12
13
  /*
   * Permedia2 framebuffer driver.
   *
   * 2.5/2.6 driver:
   * Copyright (c) 2003 Jim Hague (jim.hague@acm.org)
   *
   * based on 2.4 driver:
   * Copyright (c) 1998-2000 Ilario Nardinocchi (nardinoc@CS.UniBO.IT)
   * Copyright (c) 1999 Jakub Jelinek (jakub@redhat.com)
   *
   * and additional input from James Simmon's port of Hannu Mallat's tdfx
   * driver.
   *
45f169ec8   Krzysztof Helt   pm2fb: source cod...
14
   * I have a Creative Graphics Blaster Exxtreme card - pm2fb on x86. I
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
15
16
17
18
19
20
21
22
23
24
25
26
   * have no access to other pm2fb implementations. Sparc (and thus
   * hopefully other big-endian) devices now work, thanks to a lot of
   * testing work by Ron Murray. I have no access to CVision hardware,
   * and therefore for now I am omitting the CVision code.
   *
   * Multiple boards support has been on the TODO list for ages.
   * Don't expect this to change.
   *
   * 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.
   *
2f7bb99fc   Krzysztof Helt   pm2fb: white spac...
27
   *
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
28
   */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
29
30
31
32
33
34
  #include <linux/module.h>
  #include <linux/moduleparam.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
35
36
37
38
39
  #include <linux/slab.h>
  #include <linux/delay.h>
  #include <linux/fb.h>
  #include <linux/init.h>
  #include <linux/pci.h>
d5383fcc4   Krzysztof Helt   pm3fb: mtrr suppo...
40
41
42
  #ifdef CONFIG_MTRR
  #include <asm/mtrr.h>
  #endif
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
43
44
45
46
47
48
49
50
51
52
53
54
55
56
  
  #include <video/permedia2.h>
  #include <video/cvisionppc.h>
  
  #if !defined(__LITTLE_ENDIAN) && !defined(__BIG_ENDIAN)
  #error	"The endianness of the target host has not been defined."
  #endif
  
  #if !defined(CONFIG_PCI)
  #error "Only generic PCI cards supported."
  #endif
  
  #undef PM2FB_MASTER_DEBUG
  #ifdef PM2FB_MASTER_DEBUG
3843faa2c   Krzysztof Helt   pm2fb: checkpatch...
57
  #define DPRINTK(a, b...)	\
5ae121705   Harvey Harrison   video: replace re...
58
  	printk(KERN_DEBUG "pm2fb: %s: " a, __func__ , ## b)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
59
  #else
3843faa2c   Krzysztof Helt   pm2fb: checkpatch...
60
  #define DPRINTK(a, b...)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
61
  #endif
91b3a6f4c   Krzysztof Helt   pm2fb: accelerate...
62
  #define PM2_PIXMAP_SIZE	(1600 * 4)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
63
  /*
2f7bb99fc   Krzysztof Helt   pm2fb: white spac...
64
   * Driver data
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
65
   */
1ddc28d7e   Krzysztof Helt   pm2fb: panning an...
66
  static int hwcursor = 1;
5eb81e808   Krzysztof Helt   pm2fb: change opt...
67
  static char *mode_option __devinitdata;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
68
69
70
71
72
73
74
75
76
77
  
  /*
   * The XFree GLINT driver will (I think to implement hardware cursor
   * support on TVP4010 and similar where there is no RAMDAC - see
   * comment in set_video) always request +ve sync regardless of what
   * the mode requires. This screws me because I have a Sun
   * fixed-frequency monitor which absolutely has to have -ve sync. So
   * these flags allow the user to specify that requests for +ve sync
   * should be silently turned in -ve sync.
   */
90ab5ee94   Rusty Russell   module_param: mak...
78
79
80
  static bool lowhsync;
  static bool lowvsync;
  static bool noaccel __devinitdata;
d5383fcc4   Krzysztof Helt   pm3fb: mtrr suppo...
81
82
  /* mtrr option */
  #ifdef CONFIG_MTRR
90ab5ee94   Rusty Russell   module_param: mak...
83
  static bool nomtrr __devinitdata;
d5383fcc4   Krzysztof Helt   pm3fb: mtrr suppo...
84
  #endif
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
85
86
87
88
89
90
91
92
  
  /*
   * The hardware state of the graphics card that isn't part of the
   * screeninfo.
   */
  struct pm2fb_par
  {
  	pm2type_t	type;		/* Board type */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
93
  	unsigned char	__iomem *v_regs;/* virtual address of p_regs */
2f7bb99fc   Krzysztof Helt   pm2fb: white spac...
94
  	u32		memclock;	/* memclock */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
95
96
97
98
  	u32		video;		/* video flags before blanking */
  	u32		mem_config;	/* MemConfig reg at probe */
  	u32		mem_control;	/* MemControl reg at probe */
  	u32		boot_address;	/* BootAddress reg at probe */
2f7bb99fc   Krzysztof Helt   pm2fb: white spac...
99
  	u32		palette[16];
d5383fcc4   Krzysztof Helt   pm3fb: mtrr suppo...
100
  	int		mtrr_handle;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
101
102
103
104
105
106
107
  };
  
  /*
   * Here we define the default structs fb_fix_screeninfo and fb_var_screeninfo
   * if we don't use modedb.
   */
  static struct fb_fix_screeninfo pm2fb_fix __devinitdata = {
2f7bb99fc   Krzysztof Helt   pm2fb: white spac...
108
  	.id =		"",
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
109
110
111
112
  	.type =		FB_TYPE_PACKED_PIXELS,
  	.visual =	FB_VISUAL_PSEUDOCOLOR,
  	.xpanstep =	1,
  	.ypanstep =	1,
2f7bb99fc   Krzysztof Helt   pm2fb: white spac...
113
  	.ywrapstep =	0,
87a7cc685   Krzysztof Helt   pm2fb: accelerate...
114
  	.accel =	FB_ACCEL_3DLABS_PERMEDIA2,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
115
116
117
118
119
120
121
  };
  
  /*
   * Default video mode. In case the modedb doesn't work.
   */
  static struct fb_var_screeninfo pm2fb_var __devinitdata = {
  	/* "640x480, 8 bpp @ 60 Hz */
2f7bb99fc   Krzysztof Helt   pm2fb: white spac...
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
  	.xres =			640,
  	.yres =			480,
  	.xres_virtual =		640,
  	.yres_virtual =		480,
  	.bits_per_pixel =	8,
  	.red =			{0, 8, 0},
  	.blue =			{0, 8, 0},
  	.green =		{0, 8, 0},
  	.activate =		FB_ACTIVATE_NOW,
  	.height =		-1,
  	.width =		-1,
  	.accel_flags =		0,
  	.pixclock =		39721,
  	.left_margin =		40,
  	.right_margin =		24,
  	.upper_margin =		32,
  	.lower_margin =		11,
  	.hsync_len =		96,
  	.vsync_len =		2,
  	.vmode =		FB_VMODE_NONINTERLACED
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
142
143
144
145
146
  };
  
  /*
   * Utility functions
   */
3843faa2c   Krzysztof Helt   pm2fb: checkpatch...
147
  static inline u32 pm2_RD(struct pm2fb_par *p, s32 off)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
148
  {
45f169ec8   Krzysztof Helt   pm2fb: source cod...
149
  	return fb_readl(p->v_regs + off);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
150
  }
3843faa2c   Krzysztof Helt   pm2fb: checkpatch...
151
  static inline void pm2_WR(struct pm2fb_par *p, s32 off, u32 v)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
152
  {
45f169ec8   Krzysztof Helt   pm2fb: source cod...
153
  	fb_writel(v, p->v_regs + off);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
154
  }
3843faa2c   Krzysztof Helt   pm2fb: checkpatch...
155
  static inline u32 pm2_RDAC_RD(struct pm2fb_par *p, s32 idx)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
156
  {
45f169ec8   Krzysztof Helt   pm2fb: source cod...
157
  	pm2_WR(p, PM2R_RD_PALETTE_WRITE_ADDRESS, idx);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
158
  	mb();
45f169ec8   Krzysztof Helt   pm2fb: source cod...
159
160
  	return pm2_RD(p, PM2R_RD_INDEXED_DATA);
  }
3843faa2c   Krzysztof Helt   pm2fb: checkpatch...
161
  static inline u32 pm2v_RDAC_RD(struct pm2fb_par *p, s32 idx)
45f169ec8   Krzysztof Helt   pm2fb: source cod...
162
163
164
165
  {
  	pm2_WR(p, PM2VR_RD_INDEX_LOW, idx & 0xff);
  	mb();
  	return pm2_RD(p,  PM2VR_RD_INDEXED_DATA);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
166
  }
3843faa2c   Krzysztof Helt   pm2fb: checkpatch...
167
  static inline void pm2_RDAC_WR(struct pm2fb_par *p, s32 idx, u32 v)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
168
  {
45f169ec8   Krzysztof Helt   pm2fb: source cod...
169
  	pm2_WR(p, PM2R_RD_PALETTE_WRITE_ADDRESS, idx);
11d1a62c5   Krzysztof Helt   pm2fb: RDAC_WR ba...
170
  	wmb();
45f169ec8   Krzysztof Helt   pm2fb: source cod...
171
  	pm2_WR(p, PM2R_RD_INDEXED_DATA, v);
11d1a62c5   Krzysztof Helt   pm2fb: RDAC_WR ba...
172
  	wmb();
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
173
  }
3843faa2c   Krzysztof Helt   pm2fb: checkpatch...
174
  static inline void pm2v_RDAC_WR(struct pm2fb_par *p, s32 idx, u32 v)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
175
176
  {
  	pm2_WR(p, PM2VR_RD_INDEX_LOW, idx & 0xff);
11d1a62c5   Krzysztof Helt   pm2fb: RDAC_WR ba...
177
  	wmb();
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
178
  	pm2_WR(p, PM2VR_RD_INDEXED_DATA, v);
11d1a62c5   Krzysztof Helt   pm2fb: RDAC_WR ba...
179
  	wmb();
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
180
181
182
  }
  
  #ifdef CONFIG_FB_PM2_FIFO_DISCONNECT
2f7bb99fc   Krzysztof Helt   pm2fb: white spac...
183
  #define WAIT_FIFO(p, a)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
184
  #else
3843faa2c   Krzysztof Helt   pm2fb: checkpatch...
185
  static inline void WAIT_FIFO(struct pm2fb_par *p, u32 a)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
186
  {
6416ad736   Krzysztof Helt   pm2fb: replace bu...
187
188
  	while (pm2_RD(p, PM2R_IN_FIFO_SPACE) < a)
  		cpu_relax();
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
189
190
191
192
193
194
  }
  #endif
  
  /*
   * partial products for the supported horizontal resolutions.
   */
2f7bb99fc   Krzysztof Helt   pm2fb: white spac...
195
  #define PACKPP(p0, p1, p2)	(((p2) << 6) | ((p1) << 3) | (p0))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
  static const struct {
  	u16 width;
  	u16 pp;
  } pp_table[] = {
  	{ 32,	PACKPP(1, 0, 0) }, { 64,	PACKPP(1, 1, 0) },
  	{ 96,	PACKPP(1, 1, 1) }, { 128,	PACKPP(2, 1, 1) },
  	{ 160,	PACKPP(2, 2, 1) }, { 192,	PACKPP(2, 2, 2) },
  	{ 224,	PACKPP(3, 2, 1) }, { 256,	PACKPP(3, 2, 2) },
  	{ 288,	PACKPP(3, 3, 1) }, { 320,	PACKPP(3, 3, 2) },
  	{ 384,	PACKPP(3, 3, 3) }, { 416,	PACKPP(4, 3, 1) },
  	{ 448,	PACKPP(4, 3, 2) }, { 512,	PACKPP(4, 3, 3) },
  	{ 544,	PACKPP(4, 4, 1) }, { 576,	PACKPP(4, 4, 2) },
  	{ 640,	PACKPP(4, 4, 3) }, { 768,	PACKPP(4, 4, 4) },
  	{ 800,	PACKPP(5, 4, 1) }, { 832,	PACKPP(5, 4, 2) },
  	{ 896,	PACKPP(5, 4, 3) }, { 1024,	PACKPP(5, 4, 4) },
  	{ 1056,	PACKPP(5, 5, 1) }, { 1088,	PACKPP(5, 5, 2) },
  	{ 1152,	PACKPP(5, 5, 3) }, { 1280,	PACKPP(5, 5, 4) },
  	{ 1536,	PACKPP(5, 5, 5) }, { 1568,	PACKPP(6, 5, 1) },
  	{ 1600,	PACKPP(6, 5, 2) }, { 1664,	PACKPP(6, 5, 3) },
  	{ 1792,	PACKPP(6, 5, 4) }, { 2048,	PACKPP(6, 5, 5) },
  	{ 0,	0 } };
  
  static u32 partprod(u32 xres)
  {
  	int i;
  
  	for (i = 0; pp_table[i].width && pp_table[i].width != xres; i++)
  		;
45f169ec8   Krzysztof Helt   pm2fb: source cod...
224
  	if (pp_table[i].width == 0)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
225
226
227
228
229
230
231
232
  		DPRINTK("invalid width %u
  ", xres);
  	return pp_table[i].pp;
  }
  
  static u32 to3264(u32 timing, int bpp, int is64)
  {
  	switch (bpp) {
45f169ec8   Krzysztof Helt   pm2fb: source cod...
233
234
  	case 24:
  		timing *= 3;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
235
  	case 8:
45f169ec8   Krzysztof Helt   pm2fb: source cod...
236
  		timing >>= 1;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
237
  	case 16:
45f169ec8   Krzysztof Helt   pm2fb: source cod...
238
  		timing >>= 1;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
239
  	case 32:
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
240
241
  		break;
  	}
45f169ec8   Krzysztof Helt   pm2fb: source cod...
242
243
  	if (is64)
  		timing >>= 1;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
244
245
  	return timing;
  }
3843faa2c   Krzysztof Helt   pm2fb: checkpatch...
246
247
  static void pm2_mnp(u32 clk, unsigned char *mm, unsigned char *nn,
  		    unsigned char *pp)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
248
249
250
251
252
253
254
255
256
257
258
259
260
  {
  	unsigned char m;
  	unsigned char n;
  	unsigned char p;
  	u32 f;
  	s32 curr;
  	s32 delta = 100000;
  
  	*mm = *nn = *pp = 0;
  	for (n = 2; n < 15; n++) {
  		for (m = 2; m; m++) {
  			f = PM2_REFERENCE_CLOCK * m / n;
  			if (f >= 150000 && f <= 300000) {
45f169ec8   Krzysztof Helt   pm2fb: source cod...
261
262
263
264
265
266
267
  				for (p = 0; p < 5; p++, f >>= 1) {
  					curr = (clk > f) ? clk - f : f - clk;
  					if (curr < delta) {
  						delta = curr;
  						*mm = m;
  						*nn = n;
  						*pp = p;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
268
269
270
271
272
273
  					}
  				}
  			}
  		}
  	}
  }
3843faa2c   Krzysztof Helt   pm2fb: checkpatch...
274
275
  static void pm2v_mnp(u32 clk, unsigned char *mm, unsigned char *nn,
  		     unsigned char *pp)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
276
277
278
279
280
281
282
283
  {
  	unsigned char m;
  	unsigned char n;
  	unsigned char p;
  	u32 f;
  	s32 delta = 1000;
  
  	*mm = *nn = *pp = 0;
45f169ec8   Krzysztof Helt   pm2fb: source cod...
284
  	for (m = 1; m < 128; m++) {
d4a96b531   Krzysztof Helt   pm2fb: pixclock s...
285
  		for (n = 2 * m + 1; n; n++) {
45f169ec8   Krzysztof Helt   pm2fb: source cod...
286
287
288
289
290
291
292
  			for (p = 0; p < 2; p++) {
  				f = (PM2_REFERENCE_CLOCK >> (p + 1)) * n / m;
  				if (clk > f - delta && clk < f + delta) {
  					delta = (clk > f) ? clk - f : f - clk;
  					*mm = m;
  					*nn = n;
  					*pp = p;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
293
294
295
296
297
  				}
  			}
  		}
  	}
  }
3843faa2c   Krzysztof Helt   pm2fb: checkpatch...
298
299
  static void clear_palette(struct pm2fb_par *p)
  {
45f169ec8   Krzysztof Helt   pm2fb: source cod...
300
  	int i = 256;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
301
302
303
304
305
306
307
308
309
310
311
  
  	WAIT_FIFO(p, 1);
  	pm2_WR(p, PM2R_RD_PALETTE_WRITE_ADDRESS, 0);
  	wmb();
  	while (i--) {
  		WAIT_FIFO(p, 3);
  		pm2_WR(p, PM2R_RD_PALETTE_DATA, 0);
  		pm2_WR(p, PM2R_RD_PALETTE_DATA, 0);
  		pm2_WR(p, PM2R_RD_PALETTE_DATA, 0);
  	}
  }
3843faa2c   Krzysztof Helt   pm2fb: checkpatch...
312
  static void reset_card(struct pm2fb_par *p)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
313
314
315
316
317
318
  {
  	if (p->type == PM2_TYPE_PERMEDIA2V)
  		pm2_WR(p, PM2VR_RD_INDEX_HIGH, 0);
  	pm2_WR(p, PM2R_RESET_STATUS, 0);
  	mb();
  	while (pm2_RD(p, PM2R_RESET_STATUS) & PM2F_BEING_RESET)
6416ad736   Krzysztof Helt   pm2fb: replace bu...
319
  		cpu_relax();
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
  	mb();
  #ifdef CONFIG_FB_PM2_FIFO_DISCONNECT
  	DPRINTK("FIFO disconnect enabled
  ");
  	pm2_WR(p, PM2R_FIFO_DISCON, 1);
  	mb();
  #endif
  
  	/* Restore stashed memory config information from probe */
  	WAIT_FIFO(p, 3);
  	pm2_WR(p, PM2R_MEM_CONTROL, p->mem_control);
  	pm2_WR(p, PM2R_BOOT_ADDRESS, p->boot_address);
  	wmb();
  	pm2_WR(p, PM2R_MEM_CONFIG, p->mem_config);
  }
3843faa2c   Krzysztof Helt   pm2fb: checkpatch...
335
  static void reset_config(struct pm2fb_par *p)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
336
  {
138a451cc   Krzysztof Helt   pm2fb: Permedia 2...
337
  	WAIT_FIFO(p, 53);
2f7bb99fc   Krzysztof Helt   pm2fb: white spac...
338
  	pm2_WR(p, PM2R_CHIP_CONFIG, pm2_RD(p, PM2R_CHIP_CONFIG) &
45f169ec8   Krzysztof Helt   pm2fb: source cod...
339
  			~(PM2F_VGA_ENABLE | PM2F_VGA_FIXED));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
340
341
342
343
344
345
346
347
  	pm2_WR(p, PM2R_BYPASS_WRITE_MASK, ~(0L));
  	pm2_WR(p, PM2R_FRAMEBUFFER_WRITE_MASK, ~(0L));
  	pm2_WR(p, PM2R_FIFO_CONTROL, 0);
  	pm2_WR(p, PM2R_APERTURE_ONE, 0);
  	pm2_WR(p, PM2R_APERTURE_TWO, 0);
  	pm2_WR(p, PM2R_RASTERIZER_MODE, 0);
  	pm2_WR(p, PM2R_DELTA_MODE, PM2F_DELTA_ORDER_RGB);
  	pm2_WR(p, PM2R_LB_READ_FORMAT, 0);
2f7bb99fc   Krzysztof Helt   pm2fb: white spac...
348
  	pm2_WR(p, PM2R_LB_WRITE_FORMAT, 0);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
  	pm2_WR(p, PM2R_LB_READ_MODE, 0);
  	pm2_WR(p, PM2R_LB_SOURCE_OFFSET, 0);
  	pm2_WR(p, PM2R_FB_SOURCE_OFFSET, 0);
  	pm2_WR(p, PM2R_FB_PIXEL_OFFSET, 0);
  	pm2_WR(p, PM2R_FB_WINDOW_BASE, 0);
  	pm2_WR(p, PM2R_LB_WINDOW_BASE, 0);
  	pm2_WR(p, PM2R_FB_SOFT_WRITE_MASK, ~(0L));
  	pm2_WR(p, PM2R_FB_HARD_WRITE_MASK, ~(0L));
  	pm2_WR(p, PM2R_FB_READ_PIXEL, 0);
  	pm2_WR(p, PM2R_DITHER_MODE, 0);
  	pm2_WR(p, PM2R_AREA_STIPPLE_MODE, 0);
  	pm2_WR(p, PM2R_DEPTH_MODE, 0);
  	pm2_WR(p, PM2R_STENCIL_MODE, 0);
  	pm2_WR(p, PM2R_TEXTURE_ADDRESS_MODE, 0);
  	pm2_WR(p, PM2R_TEXTURE_READ_MODE, 0);
  	pm2_WR(p, PM2R_TEXEL_LUT_MODE, 0);
  	pm2_WR(p, PM2R_YUV_MODE, 0);
  	pm2_WR(p, PM2R_COLOR_DDA_MODE, 0);
  	pm2_WR(p, PM2R_TEXTURE_COLOR_MODE, 0);
  	pm2_WR(p, PM2R_FOG_MODE, 0);
  	pm2_WR(p, PM2R_ALPHA_BLEND_MODE, 0);
  	pm2_WR(p, PM2R_LOGICAL_OP_MODE, 0);
  	pm2_WR(p, PM2R_STATISTICS_MODE, 0);
  	pm2_WR(p, PM2R_SCISSOR_MODE, 0);
  	pm2_WR(p, PM2R_FILTER_MODE, PM2F_SYNCHRONIZATION);
138a451cc   Krzysztof Helt   pm2fb: Permedia 2...
374
  	pm2_WR(p, PM2R_RD_PIXEL_MASK, 0xff);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
375
376
377
378
379
  	switch (p->type) {
  	case PM2_TYPE_PERMEDIA2:
  		pm2_RDAC_WR(p, PM2I_RD_MODE_CONTROL, 0); /* no overlay */
  		pm2_RDAC_WR(p, PM2I_RD_CURSOR_CONTROL, 0);
  		pm2_RDAC_WR(p, PM2I_RD_MISC_CONTROL, PM2F_RD_PALETTE_WIDTH_8);
45f169ec8   Krzysztof Helt   pm2fb: source cod...
380
381
382
383
384
  		pm2_RDAC_WR(p, PM2I_RD_COLOR_KEY_CONTROL, 0);
  		pm2_RDAC_WR(p, PM2I_RD_OVERLAY_KEY, 0);
  		pm2_RDAC_WR(p, PM2I_RD_RED_KEY, 0);
  		pm2_RDAC_WR(p, PM2I_RD_GREEN_KEY, 0);
  		pm2_RDAC_WR(p, PM2I_RD_BLUE_KEY, 0);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
385
386
387
388
389
  		break;
  	case PM2_TYPE_PERMEDIA2V:
  		pm2v_RDAC_WR(p, PM2VI_RD_MISC_CONTROL, 1); /* 8bit */
  		break;
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
390
  }
3843faa2c   Krzysztof Helt   pm2fb: checkpatch...
391
  static void set_aperture(struct pm2fb_par *p, u32 depth)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
392
393
394
395
396
397
  {
  	/*
  	 * The hardware is little-endian. When used in big-endian
  	 * hosts, the on-chip aperture settings are used where
  	 * possible to translate from host to card byte order.
  	 */
45f169ec8   Krzysztof Helt   pm2fb: source cod...
398
  	WAIT_FIFO(p, 2);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
  #ifdef __LITTLE_ENDIAN
  	pm2_WR(p, PM2R_APERTURE_ONE, PM2F_APERTURE_STANDARD);
  #else
  	switch (depth) {
  	case 24:	/* RGB->BGR */
  		/*
  		 * We can't use the aperture to translate host to
  		 * card byte order here, so we switch to BGR mode
  		 * in pm2fb_set_par().
  		 */
  	case 8:		/* B->B */
  		pm2_WR(p, PM2R_APERTURE_ONE, PM2F_APERTURE_STANDARD);
  		break;
  	case 16:	/* HL->LH */
  		pm2_WR(p, PM2R_APERTURE_ONE, PM2F_APERTURE_HALFWORDSWAP);
  		break;
  	case 32:	/* RGBA->ABGR */
  		pm2_WR(p, PM2R_APERTURE_ONE, PM2F_APERTURE_BYTESWAP);
  		break;
  	}
  #endif
3843faa2c   Krzysztof Helt   pm2fb: checkpatch...
420
  	/* We don't use aperture two, so this may be superflous */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
421
422
  	pm2_WR(p, PM2R_APERTURE_TWO, PM2F_APERTURE_STANDARD);
  }
3843faa2c   Krzysztof Helt   pm2fb: checkpatch...
423
  static void set_color(struct pm2fb_par *p, unsigned char regno,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
424
425
426
427
428
429
430
431
432
433
434
  		      unsigned char r, unsigned char g, unsigned char b)
  {
  	WAIT_FIFO(p, 4);
  	pm2_WR(p, PM2R_RD_PALETTE_WRITE_ADDRESS, regno);
  	wmb();
  	pm2_WR(p, PM2R_RD_PALETTE_DATA, r);
  	wmb();
  	pm2_WR(p, PM2R_RD_PALETTE_DATA, g);
  	wmb();
  	pm2_WR(p, PM2R_RD_PALETTE_DATA, b);
  }
3843faa2c   Krzysztof Helt   pm2fb: checkpatch...
435
  static void set_memclock(struct pm2fb_par *par, u32 clk)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
436
437
438
  {
  	int i;
  	unsigned char m, n, p;
e5d809d77   Krzysztof Helt   pm2fb: Permedia 2...
439
440
441
  	switch (par->type) {
  	case PM2_TYPE_PERMEDIA2V:
  		pm2v_mnp(clk/2, &m, &n, &p);
45f169ec8   Krzysztof Helt   pm2fb: source cod...
442
  		WAIT_FIFO(par, 12);
e5d809d77   Krzysztof Helt   pm2fb: Permedia 2...
443
444
  		pm2_WR(par, PM2VR_RD_INDEX_HIGH, PM2VI_RD_MCLK_CONTROL >> 8);
  		pm2v_RDAC_WR(par, PM2VI_RD_MCLK_CONTROL, 0);
e5d809d77   Krzysztof Helt   pm2fb: Permedia 2...
445
446
447
  		pm2v_RDAC_WR(par, PM2VI_RD_MCLK_PRESCALE, m);
  		pm2v_RDAC_WR(par, PM2VI_RD_MCLK_FEEDBACK, n);
  		pm2v_RDAC_WR(par, PM2VI_RD_MCLK_POSTSCALE, p);
e5d809d77   Krzysztof Helt   pm2fb: Permedia 2...
448
449
  		pm2v_RDAC_WR(par, PM2VI_RD_MCLK_CONTROL, 1);
  		rmb();
45f169ec8   Krzysztof Helt   pm2fb: source cod...
450
451
452
  		for (i = 256; i; i--)
  			if (pm2v_RDAC_RD(par, PM2VI_RD_MCLK_CONTROL) & 2)
  				break;
e5d809d77   Krzysztof Helt   pm2fb: Permedia 2...
453
454
455
456
457
458
  		pm2_WR(par, PM2VR_RD_INDEX_HIGH, 0);
  		break;
  	case PM2_TYPE_PERMEDIA2:
  		pm2_mnp(clk, &m, &n, &p);
  		WAIT_FIFO(par, 10);
  		pm2_RDAC_WR(par, PM2I_RD_MEMORY_CLOCK_3, 6);
e5d809d77   Krzysztof Helt   pm2fb: Permedia 2...
459
460
  		pm2_RDAC_WR(par, PM2I_RD_MEMORY_CLOCK_1, m);
  		pm2_RDAC_WR(par, PM2I_RD_MEMORY_CLOCK_2, n);
e5d809d77   Krzysztof Helt   pm2fb: Permedia 2...
461
  		pm2_RDAC_WR(par, PM2I_RD_MEMORY_CLOCK_3, 8|p);
e5d809d77   Krzysztof Helt   pm2fb: Permedia 2...
462
463
  		pm2_RDAC_RD(par, PM2I_RD_MEMORY_CLOCK_STATUS);
  		rmb();
45f169ec8   Krzysztof Helt   pm2fb: source cod...
464
465
466
  		for (i = 256; i; i--)
  			if (pm2_RD(par, PM2R_RD_INDEXED_DATA) & PM2F_PLL_LOCKED)
  				break;
e5d809d77   Krzysztof Helt   pm2fb: Permedia 2...
467
468
  		break;
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
469
  }
3843faa2c   Krzysztof Helt   pm2fb: checkpatch...
470
  static void set_pixclock(struct pm2fb_par *par, u32 clk)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
471
472
473
474
475
476
477
  {
  	int i;
  	unsigned char m, n, p;
  
  	switch (par->type) {
  	case PM2_TYPE_PERMEDIA2:
  		pm2_mnp(clk, &m, &n, &p);
45f169ec8   Krzysztof Helt   pm2fb: source cod...
478
  		WAIT_FIFO(par, 10);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
479
  		pm2_RDAC_WR(par, PM2I_RD_PIXEL_CLOCK_A3, 0);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
480
481
  		pm2_RDAC_WR(par, PM2I_RD_PIXEL_CLOCK_A1, m);
  		pm2_RDAC_WR(par, PM2I_RD_PIXEL_CLOCK_A2, n);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
482
  		pm2_RDAC_WR(par, PM2I_RD_PIXEL_CLOCK_A3, 8|p);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
483
484
  		pm2_RDAC_RD(par, PM2I_RD_PIXEL_CLOCK_STATUS);
  		rmb();
45f169ec8   Krzysztof Helt   pm2fb: source cod...
485
486
487
  		for (i = 256; i; i--)
  			if (pm2_RD(par, PM2R_RD_INDEXED_DATA) & PM2F_PLL_LOCKED)
  				break;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
488
489
490
491
492
493
494
495
496
497
498
499
  		break;
  	case PM2_TYPE_PERMEDIA2V:
  		pm2v_mnp(clk/2, &m, &n, &p);
  		WAIT_FIFO(par, 8);
  		pm2_WR(par, PM2VR_RD_INDEX_HIGH, PM2VI_RD_CLK0_PRESCALE >> 8);
  		pm2v_RDAC_WR(par, PM2VI_RD_CLK0_PRESCALE, m);
  		pm2v_RDAC_WR(par, PM2VI_RD_CLK0_FEEDBACK, n);
  		pm2v_RDAC_WR(par, PM2VI_RD_CLK0_POSTSCALE, p);
  		pm2_WR(par, PM2VR_RD_INDEX_HIGH, 0);
  		break;
  	}
  }
3843faa2c   Krzysztof Helt   pm2fb: checkpatch...
500
501
  static void set_video(struct pm2fb_par *p, u32 video)
  {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
502
  	u32 tmp;
45f169ec8   Krzysztof Helt   pm2fb: source cod...
503
  	u32 vsync = video;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
504
505
506
  
  	DPRINTK("video = 0x%x
  ", video);
2f7bb99fc   Krzysztof Helt   pm2fb: white spac...
507

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
508
509
510
511
512
513
  	/*
  	 * The hardware cursor needs +vsync to recognise vert retrace.
  	 * We may not be using the hardware cursor, but the X Glint
  	 * driver may well. So always set +hsync/+vsync and then set
  	 * the RAMDAC to invert the sync if necessary.
  	 */
45f169ec8   Krzysztof Helt   pm2fb: source cod...
514
515
  	vsync &= ~(PM2F_HSYNC_MASK | PM2F_VSYNC_MASK);
  	vsync |= PM2F_HSYNC_ACT_HIGH | PM2F_VSYNC_ACT_HIGH;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
516

138a451cc   Krzysztof Helt   pm2fb: Permedia 2...
517
  	WAIT_FIFO(p, 3);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
  	pm2_WR(p, PM2R_VIDEO_CONTROL, vsync);
  
  	switch (p->type) {
  	case PM2_TYPE_PERMEDIA2:
  		tmp = PM2F_RD_PALETTE_WIDTH_8;
  		if ((video & PM2F_HSYNC_MASK) == PM2F_HSYNC_ACT_LOW)
  			tmp |= 4; /* invert hsync */
  		if ((video & PM2F_VSYNC_MASK) == PM2F_VSYNC_ACT_LOW)
  			tmp |= 8; /* invert vsync */
  		pm2_RDAC_WR(p, PM2I_RD_MISC_CONTROL, tmp);
  		break;
  	case PM2_TYPE_PERMEDIA2V:
  		tmp = 0;
  		if ((video & PM2F_HSYNC_MASK) == PM2F_HSYNC_ACT_LOW)
  			tmp |= 1; /* invert hsync */
  		if ((video & PM2F_VSYNC_MASK) == PM2F_VSYNC_ACT_LOW)
  			tmp |= 4; /* invert vsync */
  		pm2v_RDAC_WR(p, PM2VI_RD_SYNC_CONTROL, tmp);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
536
537
538
539
540
  		break;
  	}
  }
  
  /*
2f7bb99fc   Krzysztof Helt   pm2fb: white spac...
541
542
543
   *	pm2fb_check_var - Optional function. Validates a var passed in.
   *	@var: frame buffer variable screen structure
   *	@info: frame buffer structure that represents a single frame buffer
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
   *
   *	Checks to see if the hardware supports the state requested by
   *	var passed in.
   *
   *	Returns negative errno on error, or zero on success.
   */
  static int pm2fb_check_var(struct fb_var_screeninfo *var, struct fb_info *info)
  {
  	u32 lpitch;
  
  	if (var->bits_per_pixel != 8  && var->bits_per_pixel != 16 &&
  	    var->bits_per_pixel != 24 && var->bits_per_pixel != 32) {
  		DPRINTK("depth not supported: %u
  ", var->bits_per_pixel);
  		return -EINVAL;
  	}
  
  	if (var->xres != var->xres_virtual) {
3843faa2c   Krzysztof Helt   pm2fb: checkpatch...
562
563
564
  		DPRINTK("virtual x resolution != "
  			"physical x resolution not supported
  ");
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
565
566
567
568
  		return -EINVAL;
  	}
  
  	if (var->yres > var->yres_virtual) {
3843faa2c   Krzysztof Helt   pm2fb: checkpatch...
569
570
571
  		DPRINTK("virtual y resolution < "
  			"physical y resolution not possible
  ");
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
572
573
  		return -EINVAL;
  	}
1ddc28d7e   Krzysztof Helt   pm2fb: panning an...
574
575
576
577
  	/* permedia cannot blit over 2048 */
  	if (var->yres_virtual > 2047) {
  		var->yres_virtual = 2047;
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
578
579
580
581
582
583
584
585
586
587
588
589
590
  	if (var->xoffset) {
  		DPRINTK("xoffset not supported
  ");
  		return -EINVAL;
  	}
  
  	if ((var->vmode & FB_VMODE_MASK) == FB_VMODE_INTERLACED) {
  		DPRINTK("interlace not supported
  ");
  		return -EINVAL;
  	}
  
  	var->xres = (var->xres + 15) & ~15; /* could sometimes be 8 */
45f169ec8   Krzysztof Helt   pm2fb: source cod...
591
  	lpitch = var->xres * ((var->bits_per_pixel + 7) >> 3);
2f7bb99fc   Krzysztof Helt   pm2fb: white spac...
592

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
593
594
595
596
597
  	if (var->xres < 320 || var->xres > 1600) {
  		DPRINTK("width not supported: %u
  ", var->xres);
  		return -EINVAL;
  	}
2f7bb99fc   Krzysztof Helt   pm2fb: white spac...
598

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
599
600
601
602
603
  	if (var->yres < 200 || var->yres > 1200) {
  		DPRINTK("height not supported: %u
  ", var->yres);
  		return -EINVAL;
  	}
2f7bb99fc   Krzysztof Helt   pm2fb: white spac...
604

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
605
606
607
608
609
610
  	if (lpitch * var->yres_virtual > info->fix.smem_len) {
  		DPRINTK("no memory for screen (%ux%ux%u)
  ",
  			var->xres, var->yres_virtual, var->bits_per_pixel);
  		return -EINVAL;
  	}
2f7bb99fc   Krzysztof Helt   pm2fb: white spac...
611

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
612
  	if (PICOS2KHZ(var->pixclock) > PM2_MAX_PIXCLOCK) {
3843faa2c   Krzysztof Helt   pm2fb: checkpatch...
613
614
615
  		DPRINTK("pixclock too high (%ldKHz)
  ",
  			PICOS2KHZ(var->pixclock));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
616
617
  		return -EINVAL;
  	}
76c7d3ffe   krzysztof.h1@wp.pl   pm2fb: reset tran...
618
619
  	var->transp.offset = 0;
  	var->transp.length = 0;
3843faa2c   Krzysztof Helt   pm2fb: checkpatch...
620
  	switch (var->bits_per_pixel) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
621
  	case 8:
3843faa2c   Krzysztof Helt   pm2fb: checkpatch...
622
623
624
  		var->red.length = 8;
  		var->green.length = 8;
  		var->blue.length = 8;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
  		break;
  	case 16:
  		var->red.offset   = 11;
  		var->red.length   = 5;
  		var->green.offset = 5;
  		var->green.length = 6;
  		var->blue.offset  = 0;
  		var->blue.length  = 5;
  		break;
  	case 32:
  		var->transp.offset = 24;
  		var->transp.length = 8;
  		var->red.offset	  = 16;
  		var->green.offset = 8;
  		var->blue.offset  = 0;
3843faa2c   Krzysztof Helt   pm2fb: checkpatch...
640
641
642
  		var->red.length = 8;
  		var->green.length = 8;
  		var->blue.length = 8;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
643
644
645
646
647
648
649
650
651
652
  		break;
  	case 24:
  #ifdef __BIG_ENDIAN
  		var->red.offset   = 0;
  		var->blue.offset  = 16;
  #else
  		var->red.offset   = 16;
  		var->blue.offset  = 0;
  #endif
  		var->green.offset = 8;
3843faa2c   Krzysztof Helt   pm2fb: checkpatch...
653
654
655
  		var->red.length = 8;
  		var->green.length = 8;
  		var->blue.length = 8;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
656
657
  		break;
  	}
3843faa2c   Krzysztof Helt   pm2fb: checkpatch...
658
659
  	var->height = -1;
  	var->width = -1;
2f7bb99fc   Krzysztof Helt   pm2fb: white spac...
660

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
661
  	var->accel_flags = 0;	/* Can't mmap if this is on */
2f7bb99fc   Krzysztof Helt   pm2fb: white spac...
662

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
663
664
665
666
667
668
669
  	DPRINTK("Checking graphics mode at %dx%d depth %d
  ",
  		var->xres, var->yres, var->bits_per_pixel);
  	return 0;
  }
  
  /**
2f7bb99fc   Krzysztof Helt   pm2fb: white spac...
670
671
   *	pm2fb_set_par - Alters the hardware state.
   *	@info: frame buffer structure that represents a single frame buffer
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
672
673
674
675
676
677
   *
   *	Using the fb_var_screeninfo in fb_info we set the resolution of the
   *	this particular framebuffer.
   */
  static int pm2fb_set_par(struct fb_info *info)
  {
6772a2ee9   Antonino A. Daplas   [PATCH] fbdev: pm...
678
  	struct pm2fb_par *par = info->par;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
679
  	u32 pixclock;
45f169ec8   Krzysztof Helt   pm2fb: source cod...
680
681
682
  	u32 width = (info->var.xres_virtual + 7) & ~7;
  	u32 height = info->var.yres_virtual;
  	u32 depth = (info->var.bits_per_pixel + 7) & ~7;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
683
684
685
686
687
688
689
690
691
  	u32 hsstart, hsend, hbend, htotal;
  	u32 vsstart, vsend, vbend, vtotal;
  	u32 stride;
  	u32 base;
  	u32 video = 0;
  	u32 clrmode = PM2F_RD_COLOR_MODE_RGB | PM2F_RD_GUI_ACTIVE;
  	u32 txtmap = 0;
  	u32 pixsize = 0;
  	u32 clrformat = 0;
138a451cc   Krzysztof Helt   pm2fb: Permedia 2...
692
  	u32 misc = 1; /* 8-bit DAC */
45f169ec8   Krzysztof Helt   pm2fb: source cod...
693
  	u32 xres = (info->var.xres + 31) & ~31;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
694
695
696
697
698
  	int data64;
  
  	reset_card(par);
  	reset_config(par);
  	clear_palette(par);
45f169ec8   Krzysztof Helt   pm2fb: source cod...
699
  	if (par->memclock)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
700
  		set_memclock(par, par->memclock);
2f7bb99fc   Krzysztof Helt   pm2fb: white spac...
701

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
702
703
  	depth = (depth > 32) ? 32 : depth;
  	data64 = depth > 8 || par->type == PM2_TYPE_PERMEDIA2V;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
704
705
706
707
708
709
  	pixclock = PICOS2KHZ(info->var.pixclock);
  	if (pixclock > PM2_MAX_PIXCLOCK) {
  		DPRINTK("pixclock too high (%uKHz)
  ", pixclock);
  		return -EINVAL;
  	}
2f7bb99fc   Krzysztof Helt   pm2fb: white spac...
710

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
711
712
713
714
715
716
717
718
  	hsstart = to3264(info->var.right_margin, depth, data64);
  	hsend = hsstart + to3264(info->var.hsync_len, depth, data64);
  	hbend = hsend + to3264(info->var.left_margin, depth, data64);
  	htotal = to3264(xres, depth, data64) + hbend - 1;
  	vsstart = (info->var.lower_margin)
  		? info->var.lower_margin - 1
  		: 0;	/* FIXME! */
  	vsend = info->var.lower_margin + info->var.vsync_len - 1;
3843faa2c   Krzysztof Helt   pm2fb: checkpatch...
719
720
  	vbend = info->var.lower_margin + info->var.vsync_len +
  		info->var.upper_margin;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
721
722
723
724
725
  	vtotal = info->var.yres + vbend - 1;
  	stride = to3264(width, depth, 1);
  	base = to3264(info->var.yoffset * xres + info->var.xoffset, depth, 1);
  	if (data64)
  		video |= PM2F_DATA_64_ENABLE;
2f7bb99fc   Krzysztof Helt   pm2fb: white spac...
726

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
727
728
729
730
731
732
733
  	if (info->var.sync & FB_SYNC_HOR_HIGH_ACT) {
  		if (lowhsync) {
  			DPRINTK("ignoring +hsync, using -hsync.
  ");
  			video |= PM2F_HSYNC_ACT_LOW;
  		} else
  			video |= PM2F_HSYNC_ACT_HIGH;
3843faa2c   Krzysztof Helt   pm2fb: checkpatch...
734
  	} else
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
735
  		video |= PM2F_HSYNC_ACT_LOW;
3843faa2c   Krzysztof Helt   pm2fb: checkpatch...
736

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
737
738
739
740
741
742
743
  	if (info->var.sync & FB_SYNC_VERT_HIGH_ACT) {
  		if (lowvsync) {
  			DPRINTK("ignoring +vsync, using -vsync.
  ");
  			video |= PM2F_VSYNC_ACT_LOW;
  		} else
  			video |= PM2F_VSYNC_ACT_HIGH;
3843faa2c   Krzysztof Helt   pm2fb: checkpatch...
744
  	} else
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
745
  		video |= PM2F_VSYNC_ACT_LOW;
3843faa2c   Krzysztof Helt   pm2fb: checkpatch...
746

45f169ec8   Krzysztof Helt   pm2fb: source cod...
747
  	if ((info->var.vmode & FB_VMODE_MASK) == FB_VMODE_INTERLACED) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
748
749
750
751
  		DPRINTK("interlaced not supported
  ");
  		return -EINVAL;
  	}
45f169ec8   Krzysztof Helt   pm2fb: source cod...
752
  	if ((info->var.vmode & FB_VMODE_MASK) == FB_VMODE_DOUBLE)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
753
  		video |= PM2F_LINE_DOUBLE;
45f169ec8   Krzysztof Helt   pm2fb: source cod...
754
  	if ((info->var.activate & FB_ACTIVATE_MASK) == FB_ACTIVATE_NOW)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
  		video |= PM2F_VIDEO_ENABLE;
  	par->video = video;
  
  	info->fix.visual =
  		(depth == 8) ? FB_VISUAL_PSEUDOCOLOR : FB_VISUAL_TRUECOLOR;
  	info->fix.line_length = info->var.xres * depth / 8;
  	info->cmap.len = 256;
  
  	/*
  	 * Settings calculated. Now write them out.
  	 */
  	if (par->type == PM2_TYPE_PERMEDIA2V) {
  		WAIT_FIFO(par, 1);
  		pm2_WR(par, PM2VR_RD_INDEX_HIGH, 0);
  	}
2f7bb99fc   Krzysztof Helt   pm2fb: white spac...
770

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
771
  	set_aperture(par, depth);
2f7bb99fc   Krzysztof Helt   pm2fb: white spac...
772

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
773
774
  	mb();
  	WAIT_FIFO(par, 19);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
775
776
777
  	switch (depth) {
  	case 8:
  		pm2_WR(par, PM2R_FB_READ_PIXEL, 0);
138a451cc   Krzysztof Helt   pm2fb: Permedia 2...
778
  		clrformat = 0x2e;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
779
780
781
782
783
784
785
  		break;
  	case 16:
  		pm2_WR(par, PM2R_FB_READ_PIXEL, 1);
  		clrmode |= PM2F_RD_TRUECOLOR | PM2F_RD_PIXELFORMAT_RGB565;
  		txtmap = PM2F_TEXTEL_SIZE_16;
  		pixsize = 1;
  		clrformat = 0x70;
138a451cc   Krzysztof Helt   pm2fb: Permedia 2...
786
  		misc |= 8;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
787
788
789
790
791
792
793
  		break;
  	case 32:
  		pm2_WR(par, PM2R_FB_READ_PIXEL, 2);
  		clrmode |= PM2F_RD_TRUECOLOR | PM2F_RD_PIXELFORMAT_RGBA8888;
  		txtmap = PM2F_TEXTEL_SIZE_32;
  		pixsize = 2;
  		clrformat = 0x20;
138a451cc   Krzysztof Helt   pm2fb: Permedia 2...
794
  		misc |= 8;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
795
796
797
798
799
800
801
  		break;
  	case 24:
  		pm2_WR(par, PM2R_FB_READ_PIXEL, 4);
  		clrmode |= PM2F_RD_TRUECOLOR | PM2F_RD_PIXELFORMAT_RGB888;
  		txtmap = PM2F_TEXTEL_SIZE_24;
  		pixsize = 4;
  		clrformat = 0x20;
138a451cc   Krzysztof Helt   pm2fb: Permedia 2...
802
  		misc |= 8;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
  		break;
  	}
  	pm2_WR(par, PM2R_FB_WRITE_MODE, PM2F_FB_WRITE_ENABLE);
  	pm2_WR(par, PM2R_FB_READ_MODE, partprod(xres));
  	pm2_WR(par, PM2R_LB_READ_MODE, partprod(xres));
  	pm2_WR(par, PM2R_TEXTURE_MAP_FORMAT, txtmap | partprod(xres));
  	pm2_WR(par, PM2R_H_TOTAL, htotal);
  	pm2_WR(par, PM2R_HS_START, hsstart);
  	pm2_WR(par, PM2R_HS_END, hsend);
  	pm2_WR(par, PM2R_HG_END, hbend);
  	pm2_WR(par, PM2R_HB_END, hbend);
  	pm2_WR(par, PM2R_V_TOTAL, vtotal);
  	pm2_WR(par, PM2R_VS_START, vsstart);
  	pm2_WR(par, PM2R_VS_END, vsend);
  	pm2_WR(par, PM2R_VB_END, vbend);
  	pm2_WR(par, PM2R_SCREEN_STRIDE, stride);
  	wmb();
  	pm2_WR(par, PM2R_WINDOW_ORIGIN, 0);
  	pm2_WR(par, PM2R_SCREEN_SIZE, (height << 16) | width);
  	pm2_WR(par, PM2R_SCISSOR_MODE, PM2F_SCREEN_SCISSOR_ENABLE);
  	wmb();
  	pm2_WR(par, PM2R_SCREEN_BASE, base);
  	wmb();
  	set_video(par, video);
138a451cc   Krzysztof Helt   pm2fb: Permedia 2...
827
  	WAIT_FIFO(par, 10);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
828
829
830
  	switch (par->type) {
  	case PM2_TYPE_PERMEDIA2:
  		pm2_RDAC_WR(par, PM2I_RD_COLOR_MODE, clrmode);
45f169ec8   Krzysztof Helt   pm2fb: source cod...
831
  		pm2_RDAC_WR(par, PM2I_RD_COLOR_KEY_CONTROL,
3843faa2c   Krzysztof Helt   pm2fb: checkpatch...
832
  				(depth == 8) ? 0 : PM2F_COLOR_KEY_TEST_OFF);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
833
834
  		break;
  	case PM2_TYPE_PERMEDIA2V:
138a451cc   Krzysztof Helt   pm2fb: Permedia 2...
835
  		pm2v_RDAC_WR(par, PM2VI_RD_DAC_CONTROL, 0);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
836
837
  		pm2v_RDAC_WR(par, PM2VI_RD_PIXEL_SIZE, pixsize);
  		pm2v_RDAC_WR(par, PM2VI_RD_COLOR_FORMAT, clrformat);
138a451cc   Krzysztof Helt   pm2fb: Permedia 2...
838
839
  		pm2v_RDAC_WR(par, PM2VI_RD_MISC_CONTROL, misc);
  		pm2v_RDAC_WR(par, PM2VI_RD_OVERLAY_KEY, 0);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
840
841
842
843
844
845
  		break;
  	}
  	set_pixclock(par, pixclock);
  	DPRINTK("Setting graphics mode at %dx%d depth %d
  ",
  		info->var.xres, info->var.yres, info->var.bits_per_pixel);
2f7bb99fc   Krzysztof Helt   pm2fb: white spac...
846
  	return 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
847
848
849
  }
  
  /**
2f7bb99fc   Krzysztof Helt   pm2fb: white spac...
850
851
852
853
   *	pm2fb_setcolreg - Sets a color register.
   *	@regno: boolean, 0 copy local, 1 get_user() function
   *	@red: frame buffer colormap structure
   *	@green: The green value which can be up to 16 bits wide
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
854
   *	@blue:  The blue value which can be up to 16 bits wide.
2f7bb99fc   Krzysztof Helt   pm2fb: white spac...
855
856
857
858
859
   *	@transp: If supported the alpha value which can be up to 16 bits wide.
   *	@info: frame buffer info structure
   *
   *	Set a single color register. The values supplied have a 16 bit
   *	magnitude which needs to be scaled in this function for the hardware.
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
860
   *	Pretty much a direct lift from tdfxfb.c.
2f7bb99fc   Krzysztof Helt   pm2fb: white spac...
861
   *
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
862
863
864
865
866
867
   *	Returns negative errno on error, or zero on success.
   */
  static int pm2fb_setcolreg(unsigned regno, unsigned red, unsigned green,
  			   unsigned blue, unsigned transp,
  			   struct fb_info *info)
  {
6772a2ee9   Antonino A. Daplas   [PATCH] fbdev: pm...
868
  	struct pm2fb_par *par = info->par;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
869
870
  
  	if (regno >= info->cmap.len)  /* no. of hw registers */
138a451cc   Krzysztof Helt   pm2fb: Permedia 2...
871
  		return -EINVAL;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
872
873
874
875
876
  	/*
  	 * Program hardware... do anything you want with transp
  	 */
  
  	/* grayscale works only partially under directcolor */
3843faa2c   Krzysztof Helt   pm2fb: checkpatch...
877
878
  	/* grayscale = 0.30*R + 0.59*G + 0.11*B */
  	if (info->var.grayscale)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
879
  		red = green = blue = (red * 77 + green * 151 + blue * 28) >> 8;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
880
881
882
883
884
885
886
887
888
889
890
891
  
  	/* Directcolor:
  	 *   var->{color}.offset contains start of bitfield
  	 *   var->{color}.length contains length of bitfield
  	 *   {hardwarespecific} contains width of DAC
  	 *   cmap[X] is programmed to
  	 *   (X << red.offset) | (X << green.offset) | (X << blue.offset)
  	 *   RAMDAC[X] is programmed to (red, green, blue)
  	 *
  	 * Pseudocolor:
  	 *    uses offset = 0 && length = DAC register width.
  	 *    var->{color}.offset is 0
551e378ca   Daniel Mack   tree-wide: s/widh...
892
  	 *    var->{color}.length contains width of DAC
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
893
894
895
896
897
898
899
900
901
902
903
  	 *    cmap is not used
  	 *    DAC[X] is programmed to (red, green, blue)
  	 * Truecolor:
  	 *    does not use RAMDAC (usually has 3 of them).
  	 *    var->{color}.offset contains start of bitfield
  	 *    var->{color}.length contains length of bitfield
  	 *    cmap is programmed to
  	 *    (red << red.offset) | (green << green.offset) |
  	 *    (blue << blue.offset) | (transp << transp.offset)
  	 *    RAMDAC does not exist
  	 */
2f7bb99fc   Krzysztof Helt   pm2fb: white spac...
904
  #define CNVT_TOHW(val, width) ((((val) << (width)) + 0x7FFF -(val)) >> 16)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
905
906
907
908
909
910
911
912
913
  	switch (info->fix.visual) {
  	case FB_VISUAL_TRUECOLOR:
  	case FB_VISUAL_PSEUDOCOLOR:
  		red = CNVT_TOHW(red, info->var.red.length);
  		green = CNVT_TOHW(green, info->var.green.length);
  		blue = CNVT_TOHW(blue, info->var.blue.length);
  		transp = CNVT_TOHW(transp, info->var.transp.length);
  		break;
  	case FB_VISUAL_DIRECTCOLOR:
2f7bb99fc   Krzysztof Helt   pm2fb: white spac...
914
915
916
  		/* example here assumes 8 bit DAC. Might be different
  		 * for your hardware */
  		red = CNVT_TOHW(red, 8);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
917
918
919
920
921
922
923
924
925
926
927
928
  		green = CNVT_TOHW(green, 8);
  		blue = CNVT_TOHW(blue, 8);
  		/* hey, there is bug in transp handling... */
  		transp = CNVT_TOHW(transp, 8);
  		break;
  	}
  #undef CNVT_TOHW
  	/* Truecolor has hardware independent palette */
  	if (info->fix.visual == FB_VISUAL_TRUECOLOR) {
  		u32 v;
  
  		if (regno >= 16)
138a451cc   Krzysztof Helt   pm2fb: Permedia 2...
929
  			return -EINVAL;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
930
931
932
933
934
935
936
937
  
  		v = (red << info->var.red.offset) |
  			(green << info->var.green.offset) |
  			(blue << info->var.blue.offset) |
  			(transp << info->var.transp.offset);
  
  		switch (info->var.bits_per_pixel) {
  		case 8:
2f7bb99fc   Krzysztof Helt   pm2fb: white spac...
938
939
  			break;
  		case 16:
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
940
  		case 24:
2f7bb99fc   Krzysztof Helt   pm2fb: white spac...
941
942
  		case 32:
  			par->palette[regno] = v;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
943
944
945
  			break;
  		}
  		return 0;
3843faa2c   Krzysztof Helt   pm2fb: checkpatch...
946
  	} else if (info->fix.visual == FB_VISUAL_PSEUDOCOLOR)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
947
948
949
950
951
952
  		set_color(par, regno, red, green, blue);
  
  	return 0;
  }
  
  /**
2f7bb99fc   Krzysztof Helt   pm2fb: white spac...
953
954
955
   *	pm2fb_pan_display - Pans the display.
   *	@var: frame buffer variable screen structure
   *	@info: frame buffer structure that represents a single frame buffer
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
956
957
   *
   *	Pan (or wrap, depending on the `vmode' field) the display using the
2f7bb99fc   Krzysztof Helt   pm2fb: white spac...
958
959
   *	`xoffset' and `yoffset' fields of the `var' structure.
   *	If the values don't fit, return -EINVAL.
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
960
   *
2f7bb99fc   Krzysztof Helt   pm2fb: white spac...
961
   *	Returns negative errno on error, or zero on success.
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
962
963
964
965
966
   *
   */
  static int pm2fb_pan_display(struct fb_var_screeninfo *var,
  			     struct fb_info *info)
  {
6772a2ee9   Antonino A. Daplas   [PATCH] fbdev: pm...
967
  	struct pm2fb_par *p = info->par;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
968
  	u32 base;
df9306de4   Laurent Pinchart   pm2fb: use displa...
969
970
  	u32 depth = (info->var.bits_per_pixel + 7) & ~7;
  	u32 xres = (info->var.xres + 31) & ~31;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
971

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
972
973
974
  	depth = (depth > 32) ? 32 : depth;
  	base = to3264(var->yoffset * xres + var->xoffset, depth, 1);
  	WAIT_FIFO(p, 1);
2f7bb99fc   Krzysztof Helt   pm2fb: white spac...
975
  	pm2_WR(p, PM2R_SCREEN_BASE, base);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
976
977
978
979
  	return 0;
  }
  
  /**
2f7bb99fc   Krzysztof Helt   pm2fb: white spac...
980
981
982
   *	pm2fb_blank - Blanks the display.
   *	@blank_mode: the blank mode we want.
   *	@info: frame buffer structure that represents a single frame buffer
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
983
   *
2f7bb99fc   Krzysztof Helt   pm2fb: white spac...
984
985
986
987
988
989
990
   *	Blank the screen if blank_mode != 0, else unblank. 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
991
   *
2f7bb99fc   Krzysztof Helt   pm2fb: white spac...
992
   *	Returns negative errno on error, or zero on success.
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
993
994
995
996
   *
   */
  static int pm2fb_blank(int blank_mode, struct fb_info *info)
  {
6772a2ee9   Antonino A. Daplas   [PATCH] fbdev: pm...
997
  	struct pm2fb_par *par = info->par;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
998
999
1000
1001
1002
1003
1004
1005
1006
1007
1008
1009
1010
1011
1012
1013
  	u32 video = par->video;
  
  	DPRINTK("blank_mode %d
  ", blank_mode);
  
  	switch (blank_mode) {
  	case FB_BLANK_UNBLANK:
  		/* Screen: On */
  		video |= PM2F_VIDEO_ENABLE;
  		break;
  	case FB_BLANK_NORMAL:
  		/* Screen: Off */
  		video &= ~PM2F_VIDEO_ENABLE;
  		break;
  	case FB_BLANK_VSYNC_SUSPEND:
  		/* VSync: Off */
45f169ec8   Krzysztof Helt   pm2fb: source cod...
1014
  		video &= ~(PM2F_VSYNC_MASK | PM2F_BLANK_LOW);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1015
1016
1017
  		break;
  	case FB_BLANK_HSYNC_SUSPEND:
  		/* HSync: Off */
45f169ec8   Krzysztof Helt   pm2fb: source cod...
1018
  		video &= ~(PM2F_HSYNC_MASK | PM2F_BLANK_LOW);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1019
1020
1021
  		break;
  	case FB_BLANK_POWERDOWN:
  		/* HSync: Off, VSync: Off */
3843faa2c   Krzysztof Helt   pm2fb: checkpatch...
1022
  		video &= ~(PM2F_VSYNC_MASK | PM2F_HSYNC_MASK | PM2F_BLANK_LOW);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1023
1024
1025
1026
1027
  		break;
  	}
  	set_video(par, video);
  	return 0;
  }
03b9ae4b8   Antonino A. Daplas   pm2fb: fb_sync added
1028
1029
1030
1031
1032
1033
1034
1035
1036
  static int pm2fb_sync(struct fb_info *info)
  {
  	struct pm2fb_par *par = info->par;
  
  	WAIT_FIFO(par, 1);
  	pm2_WR(par, PM2R_SYNC, 0);
  	mb();
  	do {
  		while (pm2_RD(par, PM2R_OUT_FIFO_WORDS) == 0)
6416ad736   Krzysztof Helt   pm2fb: replace bu...
1037
  			cpu_relax();
03b9ae4b8   Antonino A. Daplas   pm2fb: fb_sync added
1038
1039
1040
1041
  	} while (pm2_RD(par, PM2R_OUT_FIFO) != PM2TAG(PM2R_SYNC));
  
  	return 0;
  }
3843faa2c   Krzysztof Helt   pm2fb: checkpatch...
1042
  static void pm2fb_fillrect(struct fb_info *info,
87a7cc685   Krzysztof Helt   pm2fb: accelerate...
1043
1044
  				const struct fb_fillrect *region)
  {
3843faa2c   Krzysztof Helt   pm2fb: checkpatch...
1045
  	struct pm2fb_par *par = info->par;
87a7cc685   Krzysztof Helt   pm2fb: accelerate...
1046
1047
1048
  	struct fb_fillrect modded;
  	int vxres, vyres;
  	u32 color = (info->fix.visual == FB_VISUAL_TRUECOLOR) ?
3843faa2c   Krzysztof Helt   pm2fb: checkpatch...
1049
  		((u32 *)info->pseudo_palette)[region->color] : region->color;
87a7cc685   Krzysztof Helt   pm2fb: accelerate...
1050
1051
1052
1053
1054
1055
1056
1057
1058
1059
1060
1061
1062
  
  	if (info->state != FBINFO_STATE_RUNNING)
  		return;
  	if ((info->flags & FBINFO_HWACCEL_DISABLED) ||
  		region->rop != ROP_COPY ) {
  		cfb_fillrect(info, region);
  		return;
  	}
  
  	vxres = info->var.xres_virtual;
  	vyres = info->var.yres_virtual;
  
  	memcpy(&modded, region, sizeof(struct fb_fillrect));
45f169ec8   Krzysztof Helt   pm2fb: source cod...
1063
1064
  	if (!modded.width || !modded.height ||
  	    modded.dx >= vxres || modded.dy >= vyres)
87a7cc685   Krzysztof Helt   pm2fb: accelerate...
1065
  		return;
45f169ec8   Krzysztof Helt   pm2fb: source cod...
1066
  	if (modded.dx + modded.width  > vxres)
87a7cc685   Krzysztof Helt   pm2fb: accelerate...
1067
  		modded.width  = vxres - modded.dx;
45f169ec8   Krzysztof Helt   pm2fb: source cod...
1068
  	if (modded.dy + modded.height > vyres)
87a7cc685   Krzysztof Helt   pm2fb: accelerate...
1069
  		modded.height = vyres - modded.dy;
45f169ec8   Krzysztof Helt   pm2fb: source cod...
1070
  	if (info->var.bits_per_pixel == 8)
87a7cc685   Krzysztof Helt   pm2fb: accelerate...
1071
  		color |= color << 8;
45f169ec8   Krzysztof Helt   pm2fb: source cod...
1072
  	if (info->var.bits_per_pixel <= 16)
87a7cc685   Krzysztof Helt   pm2fb: accelerate...
1073
  		color |= color << 16;
45f169ec8   Krzysztof Helt   pm2fb: source cod...
1074
1075
1076
1077
1078
1079
1080
1081
1082
1083
1084
  	WAIT_FIFO(par, 3);
  	pm2_WR(par, PM2R_CONFIG, PM2F_CONFIG_FB_WRITE_ENABLE);
  	pm2_WR(par, PM2R_RECTANGLE_ORIGIN, (modded.dy << 16) | modded.dx);
  	pm2_WR(par, PM2R_RECTANGLE_SIZE, (modded.height << 16) | modded.width);
  	if (info->var.bits_per_pixel != 24) {
  		WAIT_FIFO(par, 2);
  		pm2_WR(par, PM2R_FB_BLOCK_COLOR, color);
  		wmb();
  		pm2_WR(par, PM2R_RENDER,
  				PM2F_RENDER_RECTANGLE | PM2F_RENDER_FASTFILL);
  	} else {
30dcc9093   Krzysztof Helt   pm2fb: accelerate...
1085
1086
1087
1088
1089
  		WAIT_FIFO(par, 4);
  		pm2_WR(par, PM2R_COLOR_DDA_MODE, 1);
  		pm2_WR(par, PM2R_CONSTANT_COLOR, color);
  		wmb();
  		pm2_WR(par, PM2R_RENDER,
3843faa2c   Krzysztof Helt   pm2fb: checkpatch...
1090
1091
  				PM2F_RENDER_RECTANGLE |
  				PM2F_INCREASE_X | PM2F_INCREASE_Y );
30dcc9093   Krzysztof Helt   pm2fb: accelerate...
1092
  		pm2_WR(par, PM2R_COLOR_DDA_MODE, 0);
45f169ec8   Krzysztof Helt   pm2fb: source cod...
1093
  	}
87a7cc685   Krzysztof Helt   pm2fb: accelerate...
1094
1095
1096
1097
1098
  }
  
  static void pm2fb_copyarea(struct fb_info *info,
  				const struct fb_copyarea *area)
  {
45f169ec8   Krzysztof Helt   pm2fb: source cod...
1099
  	struct pm2fb_par *par = info->par;
87a7cc685   Krzysztof Helt   pm2fb: accelerate...
1100
1101
1102
1103
1104
1105
1106
1107
1108
1109
1110
1111
1112
1113
  	struct fb_copyarea modded;
  	u32 vxres, vyres;
  
  	if (info->state != FBINFO_STATE_RUNNING)
  		return;
  	if (info->flags & FBINFO_HWACCEL_DISABLED) {
  		cfb_copyarea(info, area);
  		return;
  	}
  
  	memcpy(&modded, area, sizeof(struct fb_copyarea));
  
  	vxres = info->var.xres_virtual;
  	vyres = info->var.yres_virtual;
45f169ec8   Krzysztof Helt   pm2fb: source cod...
1114
1115
1116
  	if (!modded.width || !modded.height ||
  	    modded.sx >= vxres || modded.sy >= vyres ||
  	    modded.dx >= vxres || modded.dy >= vyres)
87a7cc685   Krzysztof Helt   pm2fb: accelerate...
1117
  		return;
45f169ec8   Krzysztof Helt   pm2fb: source cod...
1118
  	if (modded.sx + modded.width > vxres)
87a7cc685   Krzysztof Helt   pm2fb: accelerate...
1119
  		modded.width = vxres - modded.sx;
45f169ec8   Krzysztof Helt   pm2fb: source cod...
1120
  	if (modded.dx + modded.width > vxres)
87a7cc685   Krzysztof Helt   pm2fb: accelerate...
1121
  		modded.width = vxres - modded.dx;
45f169ec8   Krzysztof Helt   pm2fb: source cod...
1122
  	if (modded.sy + modded.height > vyres)
87a7cc685   Krzysztof Helt   pm2fb: accelerate...
1123
  		modded.height = vyres - modded.sy;
45f169ec8   Krzysztof Helt   pm2fb: source cod...
1124
  	if (modded.dy + modded.height > vyres)
87a7cc685   Krzysztof Helt   pm2fb: accelerate...
1125
  		modded.height = vyres - modded.dy;
45f169ec8   Krzysztof Helt   pm2fb: source cod...
1126
1127
1128
1129
  	WAIT_FIFO(par, 5);
  	pm2_WR(par, PM2R_CONFIG, PM2F_CONFIG_FB_WRITE_ENABLE |
  		PM2F_CONFIG_FB_READ_SOURCE_ENABLE);
  	pm2_WR(par, PM2R_FB_SOURCE_DELTA,
3843faa2c   Krzysztof Helt   pm2fb: checkpatch...
1130
1131
  			((modded.sy - modded.dy) & 0xfff) << 16 |
  			((modded.sx - modded.dx) & 0xfff));
45f169ec8   Krzysztof Helt   pm2fb: source cod...
1132
1133
1134
1135
  	pm2_WR(par, PM2R_RECTANGLE_ORIGIN, (modded.dy << 16) | modded.dx);
  	pm2_WR(par, PM2R_RECTANGLE_SIZE, (modded.height << 16) | modded.width);
  	wmb();
  	pm2_WR(par, PM2R_RENDER, PM2F_RENDER_RECTANGLE |
3843faa2c   Krzysztof Helt   pm2fb: checkpatch...
1136
1137
  				(modded.dx < modded.sx ? PM2F_INCREASE_X : 0) |
  				(modded.dy < modded.sy ? PM2F_INCREASE_Y : 0));
87a7cc685   Krzysztof Helt   pm2fb: accelerate...
1138
  }
91b3a6f4c   Krzysztof Helt   pm2fb: accelerate...
1139
1140
1141
1142
1143
  static void pm2fb_imageblit(struct fb_info *info, const struct fb_image *image)
  {
  	struct pm2fb_par *par = info->par;
  	u32 height = image->height;
  	u32 fgx, bgx;
3843faa2c   Krzysztof Helt   pm2fb: checkpatch...
1144
  	const u32 *src = (const u32 *)image->data;
91b3a6f4c   Krzysztof Helt   pm2fb: accelerate...
1145
  	u32 xres = (info->var.xres + 31) & ~31;
bc9c6a175   Krzysztof Helt   pm2fb: big endian...
1146
1147
1148
1149
1150
  	int raster_mode = 1; /* invert bits */
  
  #ifdef __LITTLE_ENDIAN
  	raster_mode |= 3 << 7; /* reverse byte order */
  #endif
91b3a6f4c   Krzysztof Helt   pm2fb: accelerate...
1151
1152
1153
1154
1155
1156
1157
1158
  
  	if (info->state != FBINFO_STATE_RUNNING)
  		return;
  	if (info->flags & FBINFO_HWACCEL_DISABLED || image->depth != 1) {
  		cfb_imageblit(info, image);
  		return;
  	}
  	switch (info->fix.visual) {
45f169ec8   Krzysztof Helt   pm2fb: source cod...
1159
1160
1161
1162
1163
1164
1165
1166
1167
  	case FB_VISUAL_PSEUDOCOLOR:
  		fgx = image->fg_color;
  		bgx = image->bg_color;
  		break;
  	case FB_VISUAL_TRUECOLOR:
  	default:
  		fgx = par->palette[image->fg_color];
  		bgx = par->palette[image->bg_color];
  		break;
91b3a6f4c   Krzysztof Helt   pm2fb: accelerate...
1168
1169
1170
1171
1172
1173
1174
1175
1176
1177
1178
1179
1180
1181
1182
1183
1184
1185
1186
  	}
  	if (info->var.bits_per_pixel == 8) {
  		fgx |= fgx << 8;
  		bgx |= bgx << 8;
  	}
  	if (info->var.bits_per_pixel <= 16) {
  		fgx |= fgx << 16;
  		bgx |= bgx << 16;
  	}
  
  	WAIT_FIFO(par, 13);
  	pm2_WR(par, PM2R_FB_READ_MODE, partprod(xres));
  	pm2_WR(par, PM2R_SCISSOR_MIN_XY,
  			((image->dy & 0xfff) << 16) | (image->dx & 0x0fff));
  	pm2_WR(par, PM2R_SCISSOR_MAX_XY,
  			(((image->dy + image->height) & 0x0fff) << 16) |
  			((image->dx + image->width) & 0x0fff));
  	pm2_WR(par, PM2R_SCISSOR_MODE, 1);
  	/* GXcopy & UNIT_ENABLE */
45f169ec8   Krzysztof Helt   pm2fb: source cod...
1187
  	pm2_WR(par, PM2R_LOGICAL_OP_MODE, (0x3 << 1) | 1);
91b3a6f4c   Krzysztof Helt   pm2fb: accelerate...
1188
1189
1190
1191
1192
1193
1194
1195
1196
1197
1198
  	pm2_WR(par, PM2R_RECTANGLE_ORIGIN,
  			((image->dy & 0xfff) << 16) | (image->dx & 0x0fff));
  	pm2_WR(par, PM2R_RECTANGLE_SIZE,
  			((image->height & 0x0fff) << 16) |
  			((image->width) & 0x0fff));
  	if (info->var.bits_per_pixel == 24) {
  		pm2_WR(par, PM2R_COLOR_DDA_MODE, 1);
  		/* clear area */
  		pm2_WR(par, PM2R_CONSTANT_COLOR, bgx);
  		pm2_WR(par, PM2R_RENDER,
  			PM2F_RENDER_RECTANGLE |
45f169ec8   Krzysztof Helt   pm2fb: source cod...
1199
  			PM2F_INCREASE_X | PM2F_INCREASE_Y);
bc9c6a175   Krzysztof Helt   pm2fb: big endian...
1200
1201
  		/* BitMapPackEachScanline */
  		pm2_WR(par, PM2R_RASTERIZER_MODE, raster_mode | (1 << 9));
91b3a6f4c   Krzysztof Helt   pm2fb: accelerate...
1202
1203
1204
1205
1206
1207
1208
1209
1210
1211
1212
1213
  		pm2_WR(par, PM2R_CONSTANT_COLOR, fgx);
  		pm2_WR(par, PM2R_RENDER,
  			PM2F_RENDER_RECTANGLE |
  			PM2F_INCREASE_X | PM2F_INCREASE_Y |
  			PM2F_RENDER_SYNC_ON_BIT_MASK);
  	} else {
  		pm2_WR(par, PM2R_COLOR_DDA_MODE, 0);
  		/* clear area */
  		pm2_WR(par, PM2R_FB_BLOCK_COLOR, bgx);
  		pm2_WR(par, PM2R_RENDER,
  			PM2F_RENDER_RECTANGLE |
  			PM2F_RENDER_FASTFILL |
45f169ec8   Krzysztof Helt   pm2fb: source cod...
1214
  			PM2F_INCREASE_X | PM2F_INCREASE_Y);
bc9c6a175   Krzysztof Helt   pm2fb: big endian...
1215
  		pm2_WR(par, PM2R_RASTERIZER_MODE, raster_mode);
91b3a6f4c   Krzysztof Helt   pm2fb: accelerate...
1216
1217
1218
1219
1220
1221
1222
1223
1224
1225
1226
1227
1228
1229
1230
1231
1232
1233
1234
1235
1236
1237
1238
  		pm2_WR(par, PM2R_FB_BLOCK_COLOR, fgx);
  		pm2_WR(par, PM2R_RENDER,
  			PM2F_RENDER_RECTANGLE |
  			PM2F_INCREASE_X | PM2F_INCREASE_Y |
  			PM2F_RENDER_FASTFILL |
  			PM2F_RENDER_SYNC_ON_BIT_MASK);
  	}
  
  	while (height--) {
  		int width = ((image->width + 7) >> 3)
  				+ info->pixmap.scan_align - 1;
  		width >>= 2;
  		WAIT_FIFO(par, width);
  		while (width--) {
  			pm2_WR(par, PM2R_BIT_MASK_PATTERN, *src);
  			src++;
  		}
  	}
  	WAIT_FIFO(par, 3);
  	pm2_WR(par, PM2R_RASTERIZER_MODE, 0);
  	pm2_WR(par, PM2R_COLOR_DDA_MODE, 0);
  	pm2_WR(par, PM2R_SCISSOR_MODE, 0);
  }
8f5d050af   Krzysztof Helt   pm2fb: Permedia 2...
1239
1240
1241
1242
1243
1244
1245
1246
1247
1248
1249
  /*
   *	Hardware cursor support.
   */
  static const u8 cursor_bits_lookup[16] = {
  	0x00, 0x40, 0x10, 0x50, 0x04, 0x44, 0x14, 0x54,
  	0x01, 0x41, 0x11, 0x51, 0x05, 0x45, 0x15, 0x55
  };
  
  static int pm2vfb_cursor(struct fb_info *info, struct fb_cursor *cursor)
  {
  	struct pm2fb_par *par = info->par;
2a36f9c49   Krzysztof Helt   pm2fb: hardware c...
1250
  	u8 mode = PM2F_CURSORMODE_TYPE_X;
1ddc28d7e   Krzysztof Helt   pm2fb: panning an...
1251
1252
  	int x = cursor->image.dx - info->var.xoffset;
  	int y = cursor->image.dy - info->var.yoffset;
8f5d050af   Krzysztof Helt   pm2fb: Permedia 2...
1253

8f5d050af   Krzysztof Helt   pm2fb: Permedia 2...
1254
1255
1256
1257
  	if (cursor->enable)
  		mode |= PM2F_CURSORMODE_CURSOR_ENABLE;
  
  	pm2v_RDAC_WR(par, PM2VI_RD_CURSOR_MODE, mode);
1ddc28d7e   Krzysztof Helt   pm2fb: panning an...
1258
1259
1260
1261
1262
1263
  	if (!cursor->enable)
  		x = 2047;	/* push it outside display */
  	pm2v_RDAC_WR(par, PM2VI_RD_CURSOR_X_LOW, x & 0xff);
  	pm2v_RDAC_WR(par, PM2VI_RD_CURSOR_X_HIGH, (x >> 8) & 0xf);
  	pm2v_RDAC_WR(par, PM2VI_RD_CURSOR_Y_LOW, y & 0xff);
  	pm2v_RDAC_WR(par, PM2VI_RD_CURSOR_Y_HIGH, (y >> 8) & 0xf);
8f5d050af   Krzysztof Helt   pm2fb: Permedia 2...
1264
1265
1266
1267
1268
1269
1270
  	/*
  	 * If the cursor is not be changed this means either we want the
  	 * current cursor state (if enable is set) or we want to query what
  	 * we can do with the cursor (if enable is not set)
  	 */
  	if (!cursor->set)
  		return 0;
8f5d050af   Krzysztof Helt   pm2fb: Permedia 2...
1271
1272
1273
1274
1275
1276
1277
1278
1279
1280
1281
1282
1283
1284
1285
1286
1287
1288
1289
1290
1291
1292
1293
1294
1295
1296
1297
1298
1299
1300
1301
1302
1303
1304
1305
1306
1307
1308
1309
1310
1311
1312
1313
1314
1315
1316
1317
1318
1319
1320
1321
1322
1323
1324
1325
1326
1327
1328
1329
1330
1331
1332
1333
1334
1335
1336
1337
1338
1339
1340
1341
1342
1343
1344
1345
1346
1347
  	if (cursor->set & FB_CUR_SETHOT) {
  		pm2v_RDAC_WR(par, PM2VI_RD_CURSOR_X_HOT,
  			     cursor->hot.x & 0x3f);
  		pm2v_RDAC_WR(par, PM2VI_RD_CURSOR_Y_HOT,
  			     cursor->hot.y & 0x3f);
  	}
  
  	if (cursor->set & FB_CUR_SETCMAP) {
  		u32 fg_idx = cursor->image.fg_color;
  		u32 bg_idx = cursor->image.bg_color;
  		struct fb_cmap cmap = info->cmap;
  
  		/* the X11 driver says one should use these color registers */
  		pm2_WR(par, PM2VR_RD_INDEX_HIGH, PM2VI_RD_CURSOR_PALETTE >> 8);
  		pm2v_RDAC_WR(par, PM2VI_RD_CURSOR_PALETTE + 0,
  			     cmap.red[bg_idx] >> 8 );
  		pm2v_RDAC_WR(par, PM2VI_RD_CURSOR_PALETTE + 1,
  			     cmap.green[bg_idx] >> 8 );
  		pm2v_RDAC_WR(par, PM2VI_RD_CURSOR_PALETTE + 2,
  			     cmap.blue[bg_idx] >> 8 );
  
  		pm2v_RDAC_WR(par, PM2VI_RD_CURSOR_PALETTE + 3,
  			     cmap.red[fg_idx] >> 8 );
  		pm2v_RDAC_WR(par, PM2VI_RD_CURSOR_PALETTE + 4,
  			     cmap.green[fg_idx] >> 8 );
  		pm2v_RDAC_WR(par, PM2VI_RD_CURSOR_PALETTE + 5,
  			     cmap.blue[fg_idx] >> 8 );
  		pm2_WR(par, PM2VR_RD_INDEX_HIGH, 0);
  	}
  
  	if (cursor->set & (FB_CUR_SETSHAPE | FB_CUR_SETIMAGE)) {
  		u8 *bitmap = (u8 *)cursor->image.data;
  		u8 *mask = (u8 *)cursor->mask;
  		int i;
  		int pos = PM2VI_RD_CURSOR_PATTERN;
  
  		for (i = 0; i < cursor->image.height; i++) {
  			int j = (cursor->image.width + 7) >> 3;
  			int k = 8 - j;
  
  			pm2_WR(par, PM2VR_RD_INDEX_HIGH, pos >> 8);
  
  			for (; j > 0; j--) {
  				u8 data = *bitmap ^ *mask;
  
  				if (cursor->rop == ROP_COPY)
  					data = *mask & *bitmap;
  				/* Upper 4 bits of bitmap data */
  				pm2v_RDAC_WR(par, pos++,
  					cursor_bits_lookup[data >> 4] |
  					(cursor_bits_lookup[*mask >> 4] << 1));
  				/* Lower 4 bits of bitmap */
  				pm2v_RDAC_WR(par, pos++,
  					cursor_bits_lookup[data & 0xf] |
  					(cursor_bits_lookup[*mask & 0xf] << 1));
  				bitmap++;
  				mask++;
  			}
  			for (; k > 0; k--) {
  				pm2v_RDAC_WR(par, pos++, 0);
  				pm2v_RDAC_WR(par, pos++, 0);
  			}
  		}
  
  		while (pos < (1024 + PM2VI_RD_CURSOR_PATTERN)) {
  			pm2_WR(par, PM2VR_RD_INDEX_HIGH, pos >> 8);
  			pm2v_RDAC_WR(par, pos++, 0);
  		}
  
  		pm2_WR(par, PM2VR_RD_INDEX_HIGH, 0);
  	}
  	return 0;
  }
  
  static int pm2fb_cursor(struct fb_info *info, struct fb_cursor *cursor)
  {
  	struct pm2fb_par *par = info->par;
2a36f9c49   Krzysztof Helt   pm2fb: hardware c...
1348
1349
1350
1351
1352
1353
1354
1355
1356
1357
  	u8 mode;
  
  	if (!hwcursor)
  		return -EINVAL;	/* just to force soft_cursor() call */
  
  	/* Too large of a cursor or wrong bpp :-( */
  	if (cursor->image.width > 64 ||
  	    cursor->image.height > 64 ||
  	    cursor->image.depth > 1)
  		return -EINVAL;
8f5d050af   Krzysztof Helt   pm2fb: Permedia 2...
1358
1359
1360
  
  	if (par->type == PM2_TYPE_PERMEDIA2V)
  		return pm2vfb_cursor(info, cursor);
1ddc28d7e   Krzysztof Helt   pm2fb: panning an...
1361
  	mode = 0x40;
2a36f9c49   Krzysztof Helt   pm2fb: hardware c...
1362
1363
1364
1365
1366
1367
1368
1369
1370
1371
1372
1373
1374
1375
  	if (cursor->enable)
  		 mode = 0x43;
  
  	pm2_RDAC_WR(par, PM2I_RD_CURSOR_CONTROL, mode);
  
  	/*
  	 * If the cursor is not be changed this means either we want the
  	 * current cursor state (if enable is set) or we want to query what
  	 * we can do with the cursor (if enable is not set)
  	 */
  	if (!cursor->set)
  		return 0;
  
  	if (cursor->set & FB_CUR_SETPOS) {
1ddc28d7e   Krzysztof Helt   pm2fb: panning an...
1376
1377
  		int x = cursor->image.dx - info->var.xoffset + 63;
  		int y = cursor->image.dy - info->var.yoffset + 63;
2a36f9c49   Krzysztof Helt   pm2fb: hardware c...
1378

2a36f9c49   Krzysztof Helt   pm2fb: hardware c...
1379
1380
1381
1382
1383
1384
1385
1386
1387
1388
1389
1390
1391
1392
1393
1394
1395
1396
1397
1398
1399
1400
1401
1402
1403
1404
1405
1406
1407
1408
1409
1410
1411
1412
1413
1414
1415
1416
1417
1418
1419
1420
1421
1422
1423
1424
1425
1426
1427
1428
1429
1430
1431
1432
1433
1434
1435
1436
1437
1438
1439
1440
1441
1442
1443
1444
1445
1446
1447
1448
1449
1450
1451
1452
1453
1454
1455
1456
1457
1458
1459
1460
1461
  		WAIT_FIFO(par, 4);
  		pm2_WR(par, PM2R_RD_CURSOR_X_LSB, x & 0xff);
  		pm2_WR(par, PM2R_RD_CURSOR_X_MSB, (x >> 8) & 0x7);
  		pm2_WR(par, PM2R_RD_CURSOR_Y_LSB, y & 0xff);
  		pm2_WR(par, PM2R_RD_CURSOR_Y_MSB, (y >> 8) & 0x7);
  	}
  
  	if (cursor->set & FB_CUR_SETCMAP) {
  		u32 fg_idx = cursor->image.fg_color;
  		u32 bg_idx = cursor->image.bg_color;
  
  		WAIT_FIFO(par, 7);
  		pm2_WR(par, PM2R_RD_CURSOR_COLOR_ADDRESS, 1);
  		pm2_WR(par, PM2R_RD_CURSOR_COLOR_DATA,
  			info->cmap.red[bg_idx] >> 8);
  		pm2_WR(par, PM2R_RD_CURSOR_COLOR_DATA,
  			info->cmap.green[bg_idx] >> 8);
  		pm2_WR(par, PM2R_RD_CURSOR_COLOR_DATA,
  			info->cmap.blue[bg_idx] >> 8);
  
  		pm2_WR(par, PM2R_RD_CURSOR_COLOR_DATA,
  			info->cmap.red[fg_idx] >> 8);
  		pm2_WR(par, PM2R_RD_CURSOR_COLOR_DATA,
  			info->cmap.green[fg_idx] >> 8);
  		pm2_WR(par, PM2R_RD_CURSOR_COLOR_DATA,
  			info->cmap.blue[fg_idx] >> 8);
  	}
  
  	if (cursor->set & (FB_CUR_SETSHAPE | FB_CUR_SETIMAGE)) {
  		u8 *bitmap = (u8 *)cursor->image.data;
  		u8 *mask = (u8 *)cursor->mask;
  		int i;
  
  		WAIT_FIFO(par, 1);
  		pm2_WR(par, PM2R_RD_PALETTE_WRITE_ADDRESS, 0);
  
  		for (i = 0; i < cursor->image.height; i++) {
  			int j = (cursor->image.width + 7) >> 3;
  			int k = 8 - j;
  
  			WAIT_FIFO(par, 8);
  			for (; j > 0; j--) {
  				u8 data = *bitmap ^ *mask;
  
  				if (cursor->rop == ROP_COPY)
  					data = *mask & *bitmap;
  				/* bitmap data */
  				pm2_WR(par, PM2R_RD_CURSOR_DATA, data);
  				bitmap++;
  				mask++;
  			}
  			for (; k > 0; k--)
  				pm2_WR(par, PM2R_RD_CURSOR_DATA, 0);
  		}
  		for (; i < 64; i++) {
  			int j = 8;
  			WAIT_FIFO(par, 8);
  			while (j-- > 0)
  				pm2_WR(par, PM2R_RD_CURSOR_DATA, 0);
  		}
  
  		mask = (u8 *)cursor->mask;
  		for (i = 0; i < cursor->image.height; i++) {
  			int j = (cursor->image.width + 7) >> 3;
  			int k = 8 - j;
  
  			WAIT_FIFO(par, 8);
  			for (; j > 0; j--) {
  				/* mask */
  				pm2_WR(par, PM2R_RD_CURSOR_DATA, *mask);
  				mask++;
  			}
  			for (; k > 0; k--)
  				pm2_WR(par, PM2R_RD_CURSOR_DATA, 0);
  		}
  		for (; i < 64; i++) {
  			int j = 8;
  			WAIT_FIFO(par, 8);
  			while (j-- > 0)
  				pm2_WR(par, PM2R_RD_CURSOR_DATA, 0);
  		}
  	}
  	return 0;
8f5d050af   Krzysztof Helt   pm2fb: Permedia 2...
1462
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1463
1464
1465
1466
1467
1468
1469
1470
1471
1472
1473
1474
1475
  /* ------------ Hardware Independent Functions ------------ */
  
  /*
   *  Frame buffer operations
   */
  
  static struct fb_ops pm2fb_ops = {
  	.owner		= THIS_MODULE,
  	.fb_check_var	= pm2fb_check_var,
  	.fb_set_par	= pm2fb_set_par,
  	.fb_setcolreg	= pm2fb_setcolreg,
  	.fb_blank	= pm2fb_blank,
  	.fb_pan_display	= pm2fb_pan_display,
87a7cc685   Krzysztof Helt   pm2fb: accelerate...
1476
1477
  	.fb_fillrect	= pm2fb_fillrect,
  	.fb_copyarea	= pm2fb_copyarea,
91b3a6f4c   Krzysztof Helt   pm2fb: accelerate...
1478
  	.fb_imageblit	= pm2fb_imageblit,
03b9ae4b8   Antonino A. Daplas   pm2fb: fb_sync added
1479
  	.fb_sync	= pm2fb_sync,
8f5d050af   Krzysztof Helt   pm2fb: Permedia 2...
1480
  	.fb_cursor	= pm2fb_cursor,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1481
1482
1483
1484
1485
1486
1487
1488
1489
1490
1491
1492
1493
1494
1495
1496
1497
1498
1499
1500
  };
  
  /*
   * PCI stuff
   */
  
  
  /**
   * Device initialisation
   *
   * Initialise and allocate resource for PCI device.
   *
   * @param	pdev	PCI device.
   * @param	id	PCI device ID.
   */
  static int __devinit pm2fb_probe(struct pci_dev *pdev,
  				 const struct pci_device_id *id)
  {
  	struct pm2fb_par *default_par;
  	struct fb_info *info;
3843faa2c   Krzysztof Helt   pm2fb: checkpatch...
1501
1502
  	int err;
  	int retval = -ENXIO;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1503
1504
  
  	err = pci_enable_device(pdev);
45f169ec8   Krzysztof Helt   pm2fb: source cod...
1505
  	if (err) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1506
1507
1508
1509
  		printk(KERN_WARNING "pm2fb: Can't enable pdev: %d
  ", err);
  		return err;
  	}
6772a2ee9   Antonino A. Daplas   [PATCH] fbdev: pm...
1510
  	info = framebuffer_alloc(sizeof(struct pm2fb_par), &pdev->dev);
45f169ec8   Krzysztof Helt   pm2fb: source cod...
1511
  	if (!info)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1512
  		return -ENOMEM;
6772a2ee9   Antonino A. Daplas   [PATCH] fbdev: pm...
1513
  	default_par = info->par;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1514
1515
1516
1517
1518
1519
1520
1521
1522
1523
1524
1525
1526
1527
1528
1529
1530
1531
1532
1533
1534
1535
1536
1537
1538
1539
1540
1541
1542
1543
  
  	switch (pdev->device) {
  	case  PCI_DEVICE_ID_TI_TVP4020:
  		strcpy(pm2fb_fix.id, "TVP4020");
  		default_par->type = PM2_TYPE_PERMEDIA2;
  		break;
  	case  PCI_DEVICE_ID_3DLABS_PERMEDIA2:
  		strcpy(pm2fb_fix.id, "Permedia2");
  		default_par->type = PM2_TYPE_PERMEDIA2;
  		break;
  	case  PCI_DEVICE_ID_3DLABS_PERMEDIA2V:
  		strcpy(pm2fb_fix.id, "Permedia2v");
  		default_par->type = PM2_TYPE_PERMEDIA2V;
  		break;
  	}
  
  	pm2fb_fix.mmio_start = pci_resource_start(pdev, 0);
  	pm2fb_fix.mmio_len = PM2_REGS_SIZE;
  
  #if defined(__BIG_ENDIAN)
  	/*
  	 * PM2 has a 64k register file, mapped twice in 128k. Lower
  	 * map is little-endian, upper map is big-endian.
  	 */
  	pm2fb_fix.mmio_start += PM2_REGS_SIZE;
  	DPRINTK("Adjusting register base for big-endian.
  ");
  #endif
  	DPRINTK("Register base at 0x%lx
  ", pm2fb_fix.mmio_start);
2f7bb99fc   Krzysztof Helt   pm2fb: white spac...
1544

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1545
  	/* Registers - request region and map it. */
45f169ec8   Krzysztof Helt   pm2fb: source cod...
1546
1547
  	if (!request_mem_region(pm2fb_fix.mmio_start, pm2fb_fix.mmio_len,
  				"pm2fb regbase")) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1548
1549
1550
1551
1552
1553
  		printk(KERN_WARNING "pm2fb: Can't reserve regbase.
  ");
  		goto err_exit_neither;
  	}
  	default_par->v_regs =
  		ioremap_nocache(pm2fb_fix.mmio_start, pm2fb_fix.mmio_len);
45f169ec8   Krzysztof Helt   pm2fb: source cod...
1554
  	if (!default_par->v_regs) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1555
1556
1557
1558
1559
1560
1561
1562
1563
1564
1565
1566
1567
1568
1569
  		printk(KERN_WARNING "pm2fb: Can't remap %s register area.
  ",
  		       pm2fb_fix.id);
  		release_mem_region(pm2fb_fix.mmio_start, pm2fb_fix.mmio_len);
  		goto err_exit_neither;
  	}
  
  	/* Stash away memory register info for use when we reset the board */
  	default_par->mem_control = pm2_RD(default_par, PM2R_MEM_CONTROL);
  	default_par->boot_address = pm2_RD(default_par, PM2R_BOOT_ADDRESS);
  	default_par->mem_config = pm2_RD(default_par, PM2R_MEM_CONFIG);
  	DPRINTK("MemControl 0x%x BootAddress 0x%x MemConfig 0x%x
  ",
  		default_par->mem_control, default_par->boot_address,
  		default_par->mem_config);
45f169ec8   Krzysztof Helt   pm2fb: source cod...
1570
  	if (default_par->mem_control == 0 &&
9127fa285   Peter 'p2' De Schrijver   [PATCH] pm2fb: Ma...
1571
  		default_par->boot_address == 0x31 &&
f1c15f938   Krzysztof Helt   pm2fb: 3dlabs Per...
1572
  		default_par->mem_config == 0x259fffff) {
9a31f0f76   Krzysztof Helt   pm2fb: memclock s...
1573
  		default_par->memclock = CVPPC_MEMCLOCK;
45f169ec8   Krzysztof Helt   pm2fb: source cod...
1574
1575
1576
  		default_par->mem_control = 0;
  		default_par->boot_address = 0x20;
  		default_par->mem_config = 0xe6002021;
f1c15f938   Krzysztof Helt   pm2fb: 3dlabs Per...
1577
1578
  		if (pdev->subsystem_vendor == 0x1048 &&
  			pdev->subsystem_device == 0x0a31) {
3843faa2c   Krzysztof Helt   pm2fb: checkpatch...
1579
1580
1581
  			DPRINTK("subsystem_vendor: %04x, "
  				"subsystem_device: %04x
  ",
f1c15f938   Krzysztof Helt   pm2fb: 3dlabs Per...
1582
  				pdev->subsystem_vendor, pdev->subsystem_device);
3843faa2c   Krzysztof Helt   pm2fb: checkpatch...
1583
1584
1585
  			DPRINTK("We have not been initialized by VGA BIOS and "
  				"are running on an Elsa Winner 2000 Office
  ");
f1c15f938   Krzysztof Helt   pm2fb: 3dlabs Per...
1586
1587
  			DPRINTK("Initializing card timings manually...
  ");
138a451cc   Krzysztof Helt   pm2fb: Permedia 2...
1588
  			default_par->memclock = 100000;
f1c15f938   Krzysztof Helt   pm2fb: 3dlabs Per...
1589
1590
1591
  		}
  		if (pdev->subsystem_vendor == 0x3d3d &&
  			pdev->subsystem_device == 0x0100) {
3843faa2c   Krzysztof Helt   pm2fb: checkpatch...
1592
1593
1594
  			DPRINTK("subsystem_vendor: %04x, "
  				"subsystem_device: %04x
  ",
f1c15f938   Krzysztof Helt   pm2fb: 3dlabs Per...
1595
  				pdev->subsystem_vendor, pdev->subsystem_device);
3843faa2c   Krzysztof Helt   pm2fb: checkpatch...
1596
1597
1598
  			DPRINTK("We have not been initialized by VGA BIOS and "
  				"are running on an 3dlabs reference board
  ");
f1c15f938   Krzysztof Helt   pm2fb: 3dlabs Per...
1599
1600
  			DPRINTK("Initializing card timings manually...
  ");
45f169ec8   Krzysztof Helt   pm2fb: source cod...
1601
  			default_par->memclock = 74894;
f1c15f938   Krzysztof Helt   pm2fb: 3dlabs Per...
1602
  		}
9127fa285   Peter 'p2' De Schrijver   [PATCH] pm2fb: Ma...
1603
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1604
  	/* Now work out how big lfb is going to be. */
3843faa2c   Krzysztof Helt   pm2fb: checkpatch...
1605
  	switch (default_par->mem_config & PM2F_MEM_CONFIG_RAM_MASK) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1606
  	case PM2F_MEM_BANKS_1:
45f169ec8   Krzysztof Helt   pm2fb: source cod...
1607
  		pm2fb_fix.smem_len = 0x200000;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1608
1609
  		break;
  	case PM2F_MEM_BANKS_2:
45f169ec8   Krzysztof Helt   pm2fb: source cod...
1610
  		pm2fb_fix.smem_len = 0x400000;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1611
1612
  		break;
  	case PM2F_MEM_BANKS_3:
45f169ec8   Krzysztof Helt   pm2fb: source cod...
1613
  		pm2fb_fix.smem_len = 0x600000;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1614
1615
  		break;
  	case PM2F_MEM_BANKS_4:
45f169ec8   Krzysztof Helt   pm2fb: source cod...
1616
  		pm2fb_fix.smem_len = 0x800000;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1617
1618
  		break;
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1619
  	pm2fb_fix.smem_start = pci_resource_start(pdev, 1);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1620
1621
  
  	/* Linear frame buffer - request region and map it. */
45f169ec8   Krzysztof Helt   pm2fb: source cod...
1622
1623
  	if (!request_mem_region(pm2fb_fix.smem_start, pm2fb_fix.smem_len,
  				"pm2fb smem")) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1624
1625
1626
1627
  		printk(KERN_WARNING "pm2fb: Can't reserve smem.
  ");
  		goto err_exit_mmio;
  	}
4560daaf0   Krzysztof Helt   pm2fb: removal of...
1628
  	info->screen_base =
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1629
  		ioremap_nocache(pm2fb_fix.smem_start, pm2fb_fix.smem_len);
45f169ec8   Krzysztof Helt   pm2fb: source cod...
1630
  	if (!info->screen_base) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1631
1632
1633
1634
1635
  		printk(KERN_WARNING "pm2fb: Can't ioremap smem area.
  ");
  		release_mem_region(pm2fb_fix.smem_start, pm2fb_fix.smem_len);
  		goto err_exit_mmio;
  	}
d5383fcc4   Krzysztof Helt   pm3fb: mtrr suppo...
1636
1637
1638
1639
1640
1641
1642
1643
  #ifdef CONFIG_MTRR
  	default_par->mtrr_handle = -1;
  	if (!nomtrr)
  		default_par->mtrr_handle =
  			mtrr_add(pm2fb_fix.smem_start,
  				 pm2fb_fix.smem_len,
  				 MTRR_TYPE_WRCOMB, 1);
  #endif
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1644
  	info->fbops		= &pm2fb_ops;
2f7bb99fc   Krzysztof Helt   pm2fb: white spac...
1645
  	info->fix		= pm2fb_fix;
6772a2ee9   Antonino A. Daplas   [PATCH] fbdev: pm...
1646
  	info->pseudo_palette	= default_par->palette;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1647
  	info->flags		= FBINFO_DEFAULT |
2f7bb99fc   Krzysztof Helt   pm2fb: white spac...
1648
1649
  				  FBINFO_HWACCEL_YPAN |
  				  FBINFO_HWACCEL_COPYAREA |
91b3a6f4c   Krzysztof Helt   pm2fb: accelerate...
1650
  				  FBINFO_HWACCEL_IMAGEBLIT |
2f7bb99fc   Krzysztof Helt   pm2fb: white spac...
1651
  				  FBINFO_HWACCEL_FILLRECT;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1652

91b3a6f4c   Krzysztof Helt   pm2fb: accelerate...
1653
1654
  	info->pixmap.addr = kmalloc(PM2_PIXMAP_SIZE, GFP_KERNEL);
  	if (!info->pixmap.addr) {
3843faa2c   Krzysztof Helt   pm2fb: checkpatch...
1655
  		retval = -ENOMEM;
91b3a6f4c   Krzysztof Helt   pm2fb: accelerate...
1656
1657
1658
1659
1660
1661
1662
  		goto err_exit_pixmap;
  	}
  	info->pixmap.size = PM2_PIXMAP_SIZE;
  	info->pixmap.buf_align = 4;
  	info->pixmap.scan_align = 4;
  	info->pixmap.access_align = 32;
  	info->pixmap.flags = FB_PIXMAP_SYSTEM;
d5383fcc4   Krzysztof Helt   pm3fb: mtrr suppo...
1663
  	if (noaccel) {
91b3a6f4c   Krzysztof Helt   pm2fb: accelerate...
1664
1665
1666
1667
  		printk(KERN_DEBUG "disabling acceleration
  ");
  		info->flags |= FBINFO_HWACCEL_DISABLED;
  		info->pixmap.scan_align = 1;
d5383fcc4   Krzysztof Helt   pm3fb: mtrr suppo...
1668
  	}
5eb81e808   Krzysztof Helt   pm2fb: change opt...
1669
1670
  	if (!mode_option)
  		mode_option = "640x480@60";
2f7bb99fc   Krzysztof Helt   pm2fb: white spac...
1671

5eb81e808   Krzysztof Helt   pm2fb: change opt...
1672
  	err = fb_find_mode(&info->var, info, mode_option, NULL, 0, NULL, 8);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1673
1674
  	if (!err || err == 4)
  		info->var = pm2fb_var;
2ae09f0da   Krzysztof Helt   pm2fb: correct er...
1675
1676
  	retval = fb_alloc_cmap(&info->cmap, 256, 0);
  	if (retval < 0)
435d56fcd   Krzysztof Helt   pm2fb: fix of jum...
1677
  		goto err_exit_both;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1678

2ae09f0da   Krzysztof Helt   pm2fb: correct er...
1679
1680
  	retval = register_framebuffer(info);
  	if (retval < 0)
435d56fcd   Krzysztof Helt   pm2fb: fix of jum...
1681
  		goto err_exit_all;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1682
1683
1684
  
  	printk(KERN_INFO "fb%d: %s frame buffer device, memory = %dK.
  ",
4560daaf0   Krzysztof Helt   pm2fb: removal of...
1685
  	       info->node, info->fix.id, pm2fb_fix.smem_len / 1024);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1686
1687
1688
1689
1690
1691
1692
1693
1694
  
  	/*
  	 * Our driver data
  	 */
  	pci_set_drvdata(pdev, info);
  
  	return 0;
  
   err_exit_all:
2f7bb99fc   Krzysztof Helt   pm2fb: white spac...
1695
1696
  	fb_dealloc_cmap(&info->cmap);
   err_exit_both:
91b3a6f4c   Krzysztof Helt   pm2fb: accelerate...
1697
1698
  	kfree(info->pixmap.addr);
   err_exit_pixmap:
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1699
1700
1701
1702
1703
1704
1705
  	iounmap(info->screen_base);
  	release_mem_region(pm2fb_fix.smem_start, pm2fb_fix.smem_len);
   err_exit_mmio:
  	iounmap(default_par->v_regs);
  	release_mem_region(pm2fb_fix.mmio_start, pm2fb_fix.mmio_len);
   err_exit_neither:
  	framebuffer_release(info);
3843faa2c   Krzysztof Helt   pm2fb: checkpatch...
1706
  	return retval;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1707
1708
1709
1710
1711
1712
1713
1714
1715
1716
1717
  }
  
  /**
   * Device removal.
   *
   * Release all device resources.
   *
   * @param	pdev	PCI device to clean up.
   */
  static void __devexit pm2fb_remove(struct pci_dev *pdev)
  {
3843faa2c   Krzysztof Helt   pm2fb: checkpatch...
1718
1719
  	struct fb_info *info = pci_get_drvdata(pdev);
  	struct fb_fix_screeninfo *fix = &info->fix;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1720
1721
1722
  	struct pm2fb_par *par = info->par;
  
  	unregister_framebuffer(info);
2f7bb99fc   Krzysztof Helt   pm2fb: white spac...
1723

d5383fcc4   Krzysztof Helt   pm3fb: mtrr suppo...
1724
1725
1726
1727
1728
  #ifdef CONFIG_MTRR
  	if (par->mtrr_handle >= 0)
  		mtrr_del(par->mtrr_handle, info->fix.smem_start,
  			 info->fix.smem_len);
  #endif /* CONFIG_MTRR */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1729
1730
1731
1732
1733
1734
  	iounmap(info->screen_base);
  	release_mem_region(fix->smem_start, fix->smem_len);
  	iounmap(par->v_regs);
  	release_mem_region(fix->mmio_start, fix->mmio_len);
  
  	pci_set_drvdata(pdev, NULL);
27aa069a8   Krzysztof Helt   pm2fb: free cmap ...
1735
  	fb_dealloc_cmap(&info->cmap);
3843faa2c   Krzysztof Helt   pm2fb: checkpatch...
1736
  	kfree(info->pixmap.addr);
491bcc9bf   Krzysztof Helt   fbdev: use frameb...
1737
  	framebuffer_release(info);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1738
1739
1740
1741
  }
  
  static struct pci_device_id pm2fb_id_table[] = {
  	{ PCI_VENDOR_ID_TI, PCI_DEVICE_ID_TI_TVP4020,
138a451cc   Krzysztof Helt   pm2fb: Permedia 2...
1742
  	  PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 },
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1743
  	{ PCI_VENDOR_ID_3DLABS, PCI_DEVICE_ID_3DLABS_PERMEDIA2,
138a451cc   Krzysztof Helt   pm2fb: Permedia 2...
1744
  	  PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 },
f1c15f938   Krzysztof Helt   pm2fb: 3dlabs Per...
1745
  	{ PCI_VENDOR_ID_3DLABS, PCI_DEVICE_ID_3DLABS_PERMEDIA2V,
138a451cc   Krzysztof Helt   pm2fb: Permedia 2...
1746
  	  PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 },
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1747
1748
1749
1750
1751
  	{ 0, }
  };
  
  static struct pci_driver pm2fb_driver = {
  	.name		= "pm2fb",
2f7bb99fc   Krzysztof Helt   pm2fb: white spac...
1752
1753
1754
  	.id_table	= pm2fb_id_table,
  	.probe		= pm2fb_probe,
  	.remove		= __devexit_p(pm2fb_remove),
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1755
1756
1757
1758
1759
1760
1761
  };
  
  MODULE_DEVICE_TABLE(pci, pm2fb_id_table);
  
  
  #ifndef MODULE
  /**
75e1b6a84   Joe Perches   video: Fix spefic...
1762
   * Parse user specified options.
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1763
1764
1765
1766
1767
   *
   * This is, comma-separated options following `video=pm2fb:'.
   */
  static int __init pm2fb_setup(char *options)
  {
3843faa2c   Krzysztof Helt   pm2fb: checkpatch...
1768
  	char *this_opt;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1769
1770
1771
  
  	if (!options || !*options)
  		return 0;
2f7bb99fc   Krzysztof Helt   pm2fb: white spac...
1772
  	while ((this_opt = strsep(&options, ",")) != NULL) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1773
1774
  		if (!*this_opt)
  			continue;
3843faa2c   Krzysztof Helt   pm2fb: checkpatch...
1775
  		if (!strcmp(this_opt, "lowhsync"))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1776
  			lowhsync = 1;
3843faa2c   Krzysztof Helt   pm2fb: checkpatch...
1777
  		else if (!strcmp(this_opt, "lowvsync"))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1778
  			lowvsync = 1;
8f5d050af   Krzysztof Helt   pm2fb: Permedia 2...
1779
1780
  		else if (!strncmp(this_opt, "hwcursor=", 9))
  			hwcursor = simple_strtoul(this_opt + 9, NULL, 0);
d5383fcc4   Krzysztof Helt   pm3fb: mtrr suppo...
1781
  #ifdef CONFIG_MTRR
3843faa2c   Krzysztof Helt   pm2fb: checkpatch...
1782
  		else if (!strncmp(this_opt, "nomtrr", 6))
d5383fcc4   Krzysztof Helt   pm3fb: mtrr suppo...
1783
1784
  			nomtrr = 1;
  #endif
3843faa2c   Krzysztof Helt   pm2fb: checkpatch...
1785
  		else if (!strncmp(this_opt, "noaccel", 7))
d5383fcc4   Krzysztof Helt   pm3fb: mtrr suppo...
1786
  			noaccel = 1;
3843faa2c   Krzysztof Helt   pm2fb: checkpatch...
1787
  		else
5eb81e808   Krzysztof Helt   pm2fb: change opt...
1788
  			mode_option = this_opt;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1789
1790
1791
1792
1793
1794
1795
1796
1797
1798
1799
1800
1801
1802
1803
1804
1805
1806
1807
1808
1809
1810
1811
1812
1813
1814
1815
1816
1817
1818
1819
1820
1821
1822
  	}
  	return 0;
  }
  #endif
  
  
  static int __init pm2fb_init(void)
  {
  #ifndef MODULE
  	char *option = NULL;
  
  	if (fb_get_options("pm2fb", &option))
  		return -ENODEV;
  	pm2fb_setup(option);
  #endif
  
  	return pci_register_driver(&pm2fb_driver);
  }
  
  module_init(pm2fb_init);
  
  #ifdef MODULE
  /*
   *  Cleanup
   */
  
  static void __exit pm2fb_exit(void)
  {
  	pci_unregister_driver(&pm2fb_driver);
  }
  #endif
  
  #ifdef MODULE
  module_exit(pm2fb_exit);
5eb81e808   Krzysztof Helt   pm2fb: change opt...
1823
1824
  module_param(mode_option, charp, 0);
  MODULE_PARM_DESC(mode_option, "Initial video mode e.g. '648x480-8@60'");
9e3f0ca81   Krzysztof Helt   fbdev: add remove...
1825
1826
  module_param_named(mode, mode_option, charp, 0);
  MODULE_PARM_DESC(mode, "Initial video mode e.g. '648x480-8@60' (deprecated)");
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1827
1828
1829
1830
  module_param(lowhsync, bool, 0);
  MODULE_PARM_DESC(lowhsync, "Force horizontal sync low regardless of mode");
  module_param(lowvsync, bool, 0);
  MODULE_PARM_DESC(lowvsync, "Force vertical sync low regardless of mode");
d5383fcc4   Krzysztof Helt   pm3fb: mtrr suppo...
1831
1832
  module_param(noaccel, bool, 0);
  MODULE_PARM_DESC(noaccel, "Disable acceleration");
8f5d050af   Krzysztof Helt   pm2fb: Permedia 2...
1833
1834
  module_param(hwcursor, int, 0644);
  MODULE_PARM_DESC(hwcursor, "Enable hardware cursor "
1ddc28d7e   Krzysztof Helt   pm2fb: panning an...
1835
  			"(1=enable, 0=disable, default=1)");
d5383fcc4   Krzysztof Helt   pm3fb: mtrr suppo...
1836
1837
1838
1839
  #ifdef CONFIG_MTRR
  module_param(nomtrr, bool, 0);
  MODULE_PARM_DESC(nomtrr, "Disable MTRR support (0 or 1=disabled) (default=0)");
  #endif
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1840
1841
1842
1843
1844
  
  MODULE_AUTHOR("Jim Hague <jim.hague@acm.org>");
  MODULE_DESCRIPTION("Permedia2 framebuffer device driver");
  MODULE_LICENSE("GPL");
  #endif