Blame view

drivers/video/pm3fb.c 42.5 KB
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1
2
  /*
   *  linux/drivers/video/pm3fb.c -- 3DLabs Permedia3 frame buffer device
f23a06f07   Krzysztof Helt   pm3fb: Preliminar...
3
4
5
6
7
8
   *
   *  Copyright (C) 2001 Romain Dolbeau <romain@dolbeau.org>.
   *
   *  Ported to 2.6 kernel on 1 May 2007 by Krzysztof Helt <krzysztof.h1@wp.pl>
   *	based on pm2fb.c
   *
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
9
   *  Based on code written by:
f23a06f07   Krzysztof Helt   pm3fb: Preliminar...
10
11
12
   *	   Sven Luther, <luther@dpt-info.u-strasbg.fr>
   *	   Alan Hourihane, <alanh@fairlite.demon.co.uk>
   *	   Russell King, <rmk@arm.linux.org.uk>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
13
14
15
   *  Based on linux/drivers/video/skeletonfb.c:
   *	Copyright (C) 1997 Geert Uytterhoeven
   *  Based on linux/driver/video/pm2fb.c:
f23a06f07   Krzysztof Helt   pm3fb: Preliminar...
16
17
   *	Copyright (C) 1998-1999 Ilario Nardinocchi (nardinoc@CS.UniBO.IT)
   *	Copyright (C) 1999 Jakub Jelinek (jakub@redhat.com)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
18
19
20
21
22
   *
   *  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
23
   */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
24
25
26
27
28
  #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
29
  #include <linux/slab.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
30
  #include <linux/delay.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
31
32
33
  #include <linux/fb.h>
  #include <linux/init.h>
  #include <linux/pci.h>
d5383fcc4   Krzysztof Helt   pm3fb: mtrr suppo...
34
35
36
  #ifdef CONFIG_MTRR
  #include <asm/mtrr.h>
  #endif
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
37

f23a06f07   Krzysztof Helt   pm3fb: Preliminar...
38
  #include <video/pm3fb.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
39

f23a06f07   Krzysztof Helt   pm3fb: Preliminar...
40
41
  #if !defined(CONFIG_PCI)
  #error "Only generic PCI cards supported."
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
42
  #endif
f23a06f07   Krzysztof Helt   pm3fb: Preliminar...
43
44
  #undef PM3FB_MASTER_DEBUG
  #ifdef PM3FB_MASTER_DEBUG
57bac0f08   Krzysztof Helt   pm3fb: checkpatch...
45
  #define DPRINTK(a, b...)	\
5ae121705   Harvey Harrison   video: replace re...
46
  	printk(KERN_DEBUG "pm3fb: %s: " a, __func__ , ## b)
f23a06f07   Krzysztof Helt   pm3fb: Preliminar...
47
  #else
57bac0f08   Krzysztof Helt   pm3fb: checkpatch...
48
  #define DPRINTK(a, b...)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
49
  #endif
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
50

b0a318e2d   Krzysztof Helt   pm3fb: imageblit ...
51
  #define PM3_PIXMAP_SIZE	(2048 * 4)
f23a06f07   Krzysztof Helt   pm3fb: Preliminar...
52
53
54
  /*
   * Driver data
   */
1d677a6df   Krzysztof Helt   pm3fb: hardware c...
55
  static int hwcursor = 1;
f23a06f07   Krzysztof Helt   pm3fb: Preliminar...
56
  static char *mode_option __devinitdata;
90ab5ee94   Rusty Russell   module_param: mak...
57
  static bool noaccel __devinitdata;
d5383fcc4   Krzysztof Helt   pm3fb: mtrr suppo...
58
59
60
  
  /* mtrr option */
  #ifdef CONFIG_MTRR
90ab5ee94   Rusty Russell   module_param: mak...
61
  static bool nomtrr __devinitdata;
d5383fcc4   Krzysztof Helt   pm3fb: mtrr suppo...
62
  #endif
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
63

f23a06f07   Krzysztof Helt   pm3fb: Preliminar...
64
  /*
f23a06f07   Krzysztof Helt   pm3fb: Preliminar...
65
66
67
68
69
70
71
72
73
   * This structure defines the hardware state of the graphics card. Normally
   * you place this in a header file in linux/include/video. This file usually
   * also includes register information. That allows other driver subsystems
   * and userland applications the ability to use the same header file to
   * avoid duplicate work and easy porting of software.
   */
  struct pm3_par {
  	unsigned char	__iomem *v_regs;/* virtual address of p_regs */
  	u32		video;		/* video flags before blanking */
57bac0f08   Krzysztof Helt   pm3fb: checkpatch...
74
  	u32		base;		/* screen base in 128 bits unit */
2686ba894   Krzysztof Helt   pm3fb: various fixes
75
  	u32		palette[16];
d5383fcc4   Krzysztof Helt   pm3fb: mtrr suppo...
76
  	int		mtrr_handle;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
77
  };
f23a06f07   Krzysztof Helt   pm3fb: Preliminar...
78
79
80
81
82
83
84
85
86
87
88
89
  /*
   * Here we define the default structs fb_fix_screeninfo and fb_var_screeninfo
   * if we don't use modedb. If we do use modedb see pm3fb_init how to use it
   * to get a fb_var_screeninfo. Otherwise define a default var as well.
   */
  static struct fb_fix_screeninfo pm3fb_fix __devinitdata = {
  	.id =		"Permedia3",
  	.type =		FB_TYPE_PACKED_PIXELS,
  	.visual =	FB_VISUAL_PSEUDOCOLOR,
  	.xpanstep =	1,
  	.ypanstep =	1,
  	.ywrapstep =	0,
a58d67ce7   Krzysztof Helt   pm3fb: fillrect a...
90
  	.accel =	FB_ACCEL_3DLABS_PERMEDIA3,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
91
  };
f23a06f07   Krzysztof Helt   pm3fb: Preliminar...
92
93
94
  /*
   * Utility functions
   */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
95

f23a06f07   Krzysztof Helt   pm3fb: Preliminar...
96
97
98
99
  static inline u32 PM3_READ_REG(struct pm3_par *par, s32 off)
  {
  	return fb_readl(par->v_regs + off);
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
100

f23a06f07   Krzysztof Helt   pm3fb: Preliminar...
101
102
103
104
  static inline void PM3_WRITE_REG(struct pm3_par *par, s32 off, u32 v)
  {
  	fb_writel(v, par->v_regs + off);
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
105

f23a06f07   Krzysztof Helt   pm3fb: Preliminar...
106
107
  static inline void PM3_WAIT(struct pm3_par *par, u32 n)
  {
deea62d37   Krzysztof Helt   pm3fb: replace bu...
108
109
  	while (PM3_READ_REG(par, PM3InFIFOSpace) < n)
  		cpu_relax();
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
110
  }
f23a06f07   Krzysztof Helt   pm3fb: Preliminar...
111
  static inline void PM3_WRITE_DAC_REG(struct pm3_par *par, unsigned r, u8 v)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
112
  {
2686ba894   Krzysztof Helt   pm3fb: various fixes
113
114
115
  	PM3_WAIT(par, 3);
  	PM3_WRITE_REG(par, PM3RD_IndexHigh, (r >> 8) & 0xff);
  	PM3_WRITE_REG(par, PM3RD_IndexLow, r & 0xff);
f23a06f07   Krzysztof Helt   pm3fb: Preliminar...
116
117
  	wmb();
  	PM3_WRITE_REG(par, PM3RD_IndexedData, v);
2686ba894   Krzysztof Helt   pm3fb: various fixes
118
  	wmb();
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
119
  }
f23a06f07   Krzysztof Helt   pm3fb: Preliminar...
120
121
  static inline void pm3fb_set_color(struct pm3_par *par, unsigned char regno,
  			unsigned char r, unsigned char g, unsigned char b)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
122
  {
2686ba894   Krzysztof Helt   pm3fb: various fixes
123
124
125
126
127
128
129
130
131
  	PM3_WAIT(par, 4);
  	PM3_WRITE_REG(par, PM3RD_PaletteWriteAddress, regno);
  	wmb();
  	PM3_WRITE_REG(par, PM3RD_PaletteData, r);
  	wmb();
  	PM3_WRITE_REG(par, PM3RD_PaletteData, g);
  	wmb();
  	PM3_WRITE_REG(par, PM3RD_PaletteData, b);
  	wmb();
f23a06f07   Krzysztof Helt   pm3fb: Preliminar...
132
133
134
135
136
137
  }
  
  static void pm3fb_clear_colormap(struct pm3_par *par,
  			unsigned char r, unsigned char g, unsigned char b)
  {
  	int i;
2686ba894   Krzysztof Helt   pm3fb: various fixes
138
  	for (i = 0; i < 256 ; i++)
f23a06f07   Krzysztof Helt   pm3fb: Preliminar...
139
  		pm3fb_set_color(par, i, r, g, b);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
140
  }
0ddf78491   Krzysztof Helt   pm3fb: improvemen...
141
  /* Calculating various clock parameters */
f23a06f07   Krzysztof Helt   pm3fb: Preliminar...
142
143
144
145
  static void pm3fb_calculate_clock(unsigned long reqclock,
  				unsigned char *prescale,
  				unsigned char *feedback,
  				unsigned char *postscale)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
146
147
148
149
  {
  	int f, pre, post;
  	unsigned long freq;
  	long freqerr = 1000;
f23a06f07   Krzysztof Helt   pm3fb: Preliminar...
150
  	long currerr;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
151
152
153
154
  
  	for (f = 1; f < 256; f++) {
  		for (pre = 1; pre < 256; pre++) {
  			for (post = 0; post < 5; post++) {
f23a06f07   Krzysztof Helt   pm3fb: Preliminar...
155
156
157
158
159
160
  				freq = ((2*PM3_REF_CLOCK * f) >> post) / pre;
  				currerr = (reqclock > freq)
  					? reqclock - freq
  					: freq - reqclock;
  				if (currerr < freqerr) {
  					freqerr = currerr;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
161
162
163
  					*feedback = f;
  					*prescale = pre;
  					*postscale = post;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
164
165
166
167
  				}
  			}
  		}
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
168
  }
2686ba894   Krzysztof Helt   pm3fb: various fixes
169
  static inline int pm3fb_depth(const struct fb_var_screeninfo *var)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
170
  {
0ddf78491   Krzysztof Helt   pm3fb: improvemen...
171
  	if (var->bits_per_pixel == 16)
2686ba894   Krzysztof Helt   pm3fb: various fixes
172
173
174
175
176
177
178
179
180
  		return var->red.length + var->green.length
  			+ var->blue.length;
  
  	return var->bits_per_pixel;
  }
  
  static inline int pm3fb_shift_bpp(unsigned bpp, int v)
  {
  	switch (bpp) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
181
182
  	case 8:
  		return (v >> 4);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
183
184
185
186
187
  	case 16:
  		return (v >> 3);
  	case 32:
  		return (v >> 2);
  	}
2686ba894   Krzysztof Helt   pm3fb: various fixes
188
189
  	DPRINTK("Unsupported depth %u
  ", bpp);
f23a06f07   Krzysztof Helt   pm3fb: Preliminar...
190
  	return 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
191
  }
a58d67ce7   Krzysztof Helt   pm3fb: fillrect a...
192
193
194
195
196
197
198
199
200
201
  /* acceleration */
  static int pm3fb_sync(struct fb_info *info)
  {
  	struct pm3_par *par = info->par;
  
  	PM3_WAIT(par, 2);
  	PM3_WRITE_REG(par, PM3FilterMode, PM3FilterModeSync);
  	PM3_WRITE_REG(par, PM3Sync, 0);
  	mb();
  	do {
deea62d37   Krzysztof Helt   pm3fb: replace bu...
202
203
  		while ((PM3_READ_REG(par, PM3OutFIFOWords)) == 0)
  			cpu_relax();
a58d67ce7   Krzysztof Helt   pm3fb: fillrect a...
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
  	} while ((PM3_READ_REG(par, PM3OutputFifo)) != PM3Sync_Tag);
  
  	return 0;
  }
  
  static void pm3fb_init_engine(struct fb_info *info)
  {
  	struct pm3_par *par = info->par;
  	const u32 width = (info->var.xres_virtual + 7) & ~7;
  
  	PM3_WAIT(par, 50);
  	PM3_WRITE_REG(par, PM3FilterMode, PM3FilterModeSync);
  	PM3_WRITE_REG(par, PM3StatisticMode, 0x0);
  	PM3_WRITE_REG(par, PM3DeltaMode, 0x0);
  	PM3_WRITE_REG(par, PM3RasterizerMode, 0x0);
  	PM3_WRITE_REG(par, PM3ScissorMode, 0x0);
  	PM3_WRITE_REG(par, PM3LineStippleMode, 0x0);
  	PM3_WRITE_REG(par, PM3AreaStippleMode, 0x0);
  	PM3_WRITE_REG(par, PM3GIDMode, 0x0);
  	PM3_WRITE_REG(par, PM3DepthMode, 0x0);
  	PM3_WRITE_REG(par, PM3StencilMode, 0x0);
  	PM3_WRITE_REG(par, PM3StencilData, 0x0);
  	PM3_WRITE_REG(par, PM3ColorDDAMode, 0x0);
  	PM3_WRITE_REG(par, PM3TextureCoordMode, 0x0);
  	PM3_WRITE_REG(par, PM3TextureIndexMode0, 0x0);
  	PM3_WRITE_REG(par, PM3TextureIndexMode1, 0x0);
  	PM3_WRITE_REG(par, PM3TextureReadMode, 0x0);
  	PM3_WRITE_REG(par, PM3LUTMode, 0x0);
  	PM3_WRITE_REG(par, PM3TextureFilterMode, 0x0);
  	PM3_WRITE_REG(par, PM3TextureCompositeMode, 0x0);
  	PM3_WRITE_REG(par, PM3TextureApplicationMode, 0x0);
  	PM3_WRITE_REG(par, PM3TextureCompositeColorMode1, 0x0);
  	PM3_WRITE_REG(par, PM3TextureCompositeAlphaMode1, 0x0);
  	PM3_WRITE_REG(par, PM3TextureCompositeColorMode0, 0x0);
  	PM3_WRITE_REG(par, PM3TextureCompositeAlphaMode0, 0x0);
  	PM3_WRITE_REG(par, PM3FogMode, 0x0);
  	PM3_WRITE_REG(par, PM3ChromaTestMode, 0x0);
  	PM3_WRITE_REG(par, PM3AlphaTestMode, 0x0);
  	PM3_WRITE_REG(par, PM3AntialiasMode, 0x0);
  	PM3_WRITE_REG(par, PM3YUVMode, 0x0);
  	PM3_WRITE_REG(par, PM3AlphaBlendColorMode, 0x0);
  	PM3_WRITE_REG(par, PM3AlphaBlendAlphaMode, 0x0);
  	PM3_WRITE_REG(par, PM3DitherMode, 0x0);
  	PM3_WRITE_REG(par, PM3LogicalOpMode, 0x0);
  	PM3_WRITE_REG(par, PM3RouterMode, 0x0);
  	PM3_WRITE_REG(par, PM3Window, 0x0);
  
  	PM3_WRITE_REG(par, PM3Config2D, 0x0);
  
  	PM3_WRITE_REG(par, PM3SpanColorMask, 0xffffffff);
  
  	PM3_WRITE_REG(par, PM3XBias, 0x0);
  	PM3_WRITE_REG(par, PM3YBias, 0x0);
  	PM3_WRITE_REG(par, PM3DeltaControl, 0x0);
  
  	PM3_WRITE_REG(par, PM3BitMaskPattern, 0xffffffff);
  
  	PM3_WRITE_REG(par, PM3FBDestReadEnables,
  			   PM3FBDestReadEnables_E(0xff) |
  			   PM3FBDestReadEnables_R(0xff) |
  			   PM3FBDestReadEnables_ReferenceAlpha(0xff));
  	PM3_WRITE_REG(par, PM3FBDestReadBufferAddr0, 0x0);
  	PM3_WRITE_REG(par, PM3FBDestReadBufferOffset0, 0x0);
  	PM3_WRITE_REG(par, PM3FBDestReadBufferWidth0,
  			   PM3FBDestReadBufferWidth_Width(width));
  
  	PM3_WRITE_REG(par, PM3FBDestReadMode,
  			   PM3FBDestReadMode_ReadEnable |
  			   PM3FBDestReadMode_Enable0);
  	PM3_WRITE_REG(par, PM3FBSourceReadBufferAddr, 0x0);
  	PM3_WRITE_REG(par, PM3FBSourceReadBufferOffset, 0x0);
  	PM3_WRITE_REG(par, PM3FBSourceReadBufferWidth,
  			   PM3FBSourceReadBufferWidth_Width(width));
  	PM3_WRITE_REG(par, PM3FBSourceReadMode,
  			   PM3FBSourceReadMode_Blocking |
  			   PM3FBSourceReadMode_ReadEnable);
  
  	PM3_WAIT(par, 2);
  	{
e7f76df96   Krzysztof Helt   pm3fb: copyarea a...
283
284
  		/* invert bits in bitmask */
  		unsigned long rm = 1 | (3 << 7);
a58d67ce7   Krzysztof Helt   pm3fb: fillrect a...
285
286
287
288
  		switch (info->var.bits_per_pixel) {
  		case 8:
  			PM3_WRITE_REG(par, PM3PixelSize,
  					   PM3PixelSize_GLOBAL_8BIT);
e7f76df96   Krzysztof Helt   pm3fb: copyarea a...
289
290
291
  #ifdef __BIG_ENDIAN
  			rm |= 3 << 15;
  #endif
a58d67ce7   Krzysztof Helt   pm3fb: fillrect a...
292
293
294
295
  			break;
  		case 16:
  			PM3_WRITE_REG(par, PM3PixelSize,
  					   PM3PixelSize_GLOBAL_16BIT);
e7f76df96   Krzysztof Helt   pm3fb: copyarea a...
296
297
298
  #ifdef __BIG_ENDIAN
  			rm |= 2 << 15;
  #endif
a58d67ce7   Krzysztof Helt   pm3fb: fillrect a...
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
  			break;
  		case 32:
  			PM3_WRITE_REG(par, PM3PixelSize,
  					   PM3PixelSize_GLOBAL_32BIT);
  			break;
  		default:
  			DPRINTK(1, "Unsupported depth %d
  ",
  				info->var.bits_per_pixel);
  			break;
  		}
  		PM3_WRITE_REG(par, PM3RasterizerMode, rm);
  	}
  
  	PM3_WAIT(par, 20);
  	PM3_WRITE_REG(par, PM3FBSoftwareWriteMask, 0xffffffff);
  	PM3_WRITE_REG(par, PM3FBHardwareWriteMask, 0xffffffff);
  	PM3_WRITE_REG(par, PM3FBWriteMode,
  			   PM3FBWriteMode_WriteEnable |
  			   PM3FBWriteMode_OpaqueSpan |
  			   PM3FBWriteMode_Enable0);
  	PM3_WRITE_REG(par, PM3FBWriteBufferAddr0, 0x0);
  	PM3_WRITE_REG(par, PM3FBWriteBufferOffset0, 0x0);
  	PM3_WRITE_REG(par, PM3FBWriteBufferWidth0,
  			   PM3FBWriteBufferWidth_Width(width));
  
  	PM3_WRITE_REG(par, PM3SizeOfFramebuffer, 0x0);
  	{
  		/* size in lines of FB */
  		unsigned long sofb = info->screen_size /
  			info->fix.line_length;
  		if (sofb > 4095)
  			PM3_WRITE_REG(par, PM3SizeOfFramebuffer, 4095);
  		else
  			PM3_WRITE_REG(par, PM3SizeOfFramebuffer, sofb);
  
  		switch (info->var.bits_per_pixel) {
  		case 8:
  			PM3_WRITE_REG(par, PM3DitherMode,
  					   (1 << 10) | (2 << 3));
  			break;
  		case 16:
  			PM3_WRITE_REG(par, PM3DitherMode,
  					   (1 << 10) | (1 << 3));
  			break;
  		case 32:
  			PM3_WRITE_REG(par, PM3DitherMode,
  					   (1 << 10) | (0 << 3));
  			break;
  		default:
  			DPRINTK(1, "Unsupported depth %d
  ",
  				info->current_par->depth);
  			break;
  		}
  	}
  
  	PM3_WRITE_REG(par, PM3dXDom, 0x0);
  	PM3_WRITE_REG(par, PM3dXSub, 0x0);
0ddf78491   Krzysztof Helt   pm3fb: improvemen...
358
  	PM3_WRITE_REG(par, PM3dY, 1 << 16);
a58d67ce7   Krzysztof Helt   pm3fb: fillrect a...
359
360
361
362
363
364
365
366
367
368
369
370
371
  	PM3_WRITE_REG(par, PM3StartXDom, 0x0);
  	PM3_WRITE_REG(par, PM3StartXSub, 0x0);
  	PM3_WRITE_REG(par, PM3StartY, 0x0);
  	PM3_WRITE_REG(par, PM3Count, 0x0);
  
  /* Disable LocalBuffer. better safe than sorry */
  	PM3_WRITE_REG(par, PM3LBDestReadMode, 0x0);
  	PM3_WRITE_REG(par, PM3LBDestReadEnables, 0x0);
  	PM3_WRITE_REG(par, PM3LBSourceReadMode, 0x0);
  	PM3_WRITE_REG(par, PM3LBWriteMode, 0x0);
  
  	pm3fb_sync(info);
  }
57bac0f08   Krzysztof Helt   pm3fb: checkpatch...
372
  static void pm3fb_fillrect(struct fb_info *info,
a58d67ce7   Krzysztof Helt   pm3fb: fillrect a...
373
374
375
376
377
  				const struct fb_fillrect *region)
  {
  	struct pm3_par *par = info->par;
  	struct fb_fillrect modded;
  	int vxres, vyres;
0ddf78491   Krzysztof Helt   pm3fb: improvemen...
378
  	int rop;
a58d67ce7   Krzysztof Helt   pm3fb: fillrect a...
379
  	u32 color = (info->fix.visual == FB_VISUAL_TRUECOLOR) ?
57bac0f08   Krzysztof Helt   pm3fb: checkpatch...
380
  		((u32 *)info->pseudo_palette)[region->color] : region->color;
a58d67ce7   Krzysztof Helt   pm3fb: fillrect a...
381
382
383
  
  	if (info->state != FBINFO_STATE_RUNNING)
  		return;
0ddf78491   Krzysztof Helt   pm3fb: improvemen...
384
  	if (info->flags & FBINFO_HWACCEL_DISABLED) {
a58d67ce7   Krzysztof Helt   pm3fb: fillrect a...
385
386
387
  		cfb_fillrect(info, region);
  		return;
  	}
0ddf78491   Krzysztof Helt   pm3fb: improvemen...
388
389
390
391
392
  	if (region->rop == ROP_COPY )
  		rop = PM3Config2D_ForegroundROP(0x3); /* GXcopy */
  	else
  		rop = PM3Config2D_ForegroundROP(0x6) | /* GXxor */
  			PM3Config2D_FBDestReadEnable;
a58d67ce7   Krzysztof Helt   pm3fb: fillrect a...
393
394
395
396
397
  
  	vxres = info->var.xres_virtual;
  	vyres = info->var.yres_virtual;
  
  	memcpy(&modded, region, sizeof(struct fb_fillrect));
57bac0f08   Krzysztof Helt   pm3fb: checkpatch...
398
399
  	if (!modded.width || !modded.height ||
  	    modded.dx >= vxres || modded.dy >= vyres)
a58d67ce7   Krzysztof Helt   pm3fb: fillrect a...
400
  		return;
57bac0f08   Krzysztof Helt   pm3fb: checkpatch...
401
  	if (modded.dx + modded.width  > vxres)
a58d67ce7   Krzysztof Helt   pm3fb: fillrect a...
402
  		modded.width  = vxres - modded.dx;
57bac0f08   Krzysztof Helt   pm3fb: checkpatch...
403
  	if (modded.dy + modded.height > vyres)
a58d67ce7   Krzysztof Helt   pm3fb: fillrect a...
404
  		modded.height = vyres - modded.dy;
57bac0f08   Krzysztof Helt   pm3fb: checkpatch...
405
  	if (info->var.bits_per_pixel == 8)
a58d67ce7   Krzysztof Helt   pm3fb: fillrect a...
406
  		color |= color << 8;
57bac0f08   Krzysztof Helt   pm3fb: checkpatch...
407
  	if (info->var.bits_per_pixel <= 16)
a58d67ce7   Krzysztof Helt   pm3fb: fillrect a...
408
409
410
  		color |= color << 16;
  
  	PM3_WAIT(par, 4);
e7f76df96   Krzysztof Helt   pm3fb: copyarea a...
411
  	/* ROP Ox3 is GXcopy */
a58d67ce7   Krzysztof Helt   pm3fb: fillrect a...
412
  	PM3_WRITE_REG(par, PM3Config2D,
e7f76df96   Krzysztof Helt   pm3fb: copyarea a...
413
414
  			PM3Config2D_UseConstantSource |
  			PM3Config2D_ForegroundROPEnable |
0ddf78491   Krzysztof Helt   pm3fb: improvemen...
415
  			rop |
e7f76df96   Krzysztof Helt   pm3fb: copyarea a...
416
  			PM3Config2D_FBWriteEnable);
a58d67ce7   Krzysztof Helt   pm3fb: fillrect a...
417
418
419
420
  
  	PM3_WRITE_REG(par, PM3ForegroundColor, color);
  
  	PM3_WRITE_REG(par, PM3RectanglePosition,
0ddf78491   Krzysztof Helt   pm3fb: improvemen...
421
422
  			PM3RectanglePosition_XOffset(modded.dx) |
  			PM3RectanglePosition_YOffset(modded.dy));
a58d67ce7   Krzysztof Helt   pm3fb: fillrect a...
423
424
425
426
427
428
  
  	PM3_WRITE_REG(par, PM3Render2D,
  		      PM3Render2D_XPositive |
  		      PM3Render2D_YPositive |
  		      PM3Render2D_Operation_Normal |
  		      PM3Render2D_SpanOperation |
0ddf78491   Krzysztof Helt   pm3fb: improvemen...
429
430
  		      PM3Render2D_Width(modded.width) |
  		      PM3Render2D_Height(modded.height));
a58d67ce7   Krzysztof Helt   pm3fb: fillrect a...
431
  }
e7f76df96   Krzysztof Helt   pm3fb: copyarea a...
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
  
  static void pm3fb_copyarea(struct fb_info *info,
  				const struct fb_copyarea *area)
  {
  	struct pm3_par *par = info->par;
  	struct fb_copyarea modded;
  	u32 vxres, vyres;
  	int x_align, o_x, o_y;
  
  	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;
57bac0f08   Krzysztof Helt   pm3fb: checkpatch...
452
453
454
  	if (!modded.width || !modded.height ||
  	    modded.sx >= vxres || modded.sy >= vyres ||
  	    modded.dx >= vxres || modded.dy >= vyres)
e7f76df96   Krzysztof Helt   pm3fb: copyarea a...
455
  		return;
57bac0f08   Krzysztof Helt   pm3fb: checkpatch...
456
  	if (modded.sx + modded.width > vxres)
e7f76df96   Krzysztof Helt   pm3fb: copyarea a...
457
  		modded.width = vxres - modded.sx;
57bac0f08   Krzysztof Helt   pm3fb: checkpatch...
458
  	if (modded.dx + modded.width > vxres)
e7f76df96   Krzysztof Helt   pm3fb: copyarea a...
459
  		modded.width = vxres - modded.dx;
57bac0f08   Krzysztof Helt   pm3fb: checkpatch...
460
  	if (modded.sy + modded.height > vyres)
e7f76df96   Krzysztof Helt   pm3fb: copyarea a...
461
  		modded.height = vyres - modded.sy;
57bac0f08   Krzysztof Helt   pm3fb: checkpatch...
462
  	if (modded.dy + modded.height > vyres)
e7f76df96   Krzysztof Helt   pm3fb: copyarea a...
463
464
465
466
467
468
469
470
471
472
473
474
475
  		modded.height = vyres - modded.dy;
  
  	o_x = modded.sx - modded.dx;	/*(sx > dx ) ? (sx - dx) : (dx - sx); */
  	o_y = modded.sy - modded.dy;	/*(sy > dy ) ? (sy - dy) : (dy - sy); */
  
  	x_align = (modded.sx & 0x1f);
  
  	PM3_WAIT(par, 6);
  
  	PM3_WRITE_REG(par, PM3Config2D,
  			PM3Config2D_UserScissorEnable |
  			PM3Config2D_ForegroundROPEnable |
  			PM3Config2D_Blocking |
0ddf78491   Krzysztof Helt   pm3fb: improvemen...
476
  			PM3Config2D_ForegroundROP(0x3) | /* Ox3 is GXcopy */
e7f76df96   Krzysztof Helt   pm3fb: copyarea a...
477
478
479
480
481
482
483
484
485
486
487
488
489
  			PM3Config2D_FBWriteEnable);
  
  	PM3_WRITE_REG(par, PM3ScissorMinXY,
  			((modded.dy & 0x0fff) << 16) | (modded.dx & 0x0fff));
  	PM3_WRITE_REG(par, PM3ScissorMaxXY,
  			(((modded.dy + modded.height) & 0x0fff) << 16) |
  			((modded.dx + modded.width) & 0x0fff));
  
  	PM3_WRITE_REG(par, PM3FBSourceReadBufferOffset,
  			PM3FBSourceReadBufferOffset_XOffset(o_x) |
  			PM3FBSourceReadBufferOffset_YOffset(o_y));
  
  	PM3_WRITE_REG(par, PM3RectanglePosition,
0ddf78491   Krzysztof Helt   pm3fb: improvemen...
490
491
  			PM3RectanglePosition_XOffset(modded.dx - x_align) |
  			PM3RectanglePosition_YOffset(modded.dy));
e7f76df96   Krzysztof Helt   pm3fb: copyarea a...
492
493
494
495
496
497
498
  
  	PM3_WRITE_REG(par, PM3Render2D,
  			((modded.sx > modded.dx) ? PM3Render2D_XPositive : 0) |
  			((modded.sy > modded.dy) ? PM3Render2D_YPositive : 0) |
  			PM3Render2D_Operation_Normal |
  			PM3Render2D_SpanOperation |
  			PM3Render2D_FBSourceReadEnable |
0ddf78491   Krzysztof Helt   pm3fb: improvemen...
499
500
  			PM3Render2D_Width(modded.width + x_align) |
  			PM3Render2D_Height(modded.height));
e7f76df96   Krzysztof Helt   pm3fb: copyarea a...
501
502
503
504
505
506
507
  }
  
  static void pm3fb_imageblit(struct fb_info *info, const struct fb_image *image)
  {
  	struct pm3_par *par = info->par;
  	u32 height = image->height;
  	u32 fgx, bgx;
57bac0f08   Krzysztof Helt   pm3fb: checkpatch...
508
  	const u32 *src = (const u32 *)image->data;
e7f76df96   Krzysztof Helt   pm3fb: copyarea a...
509

0ddf78491   Krzysztof Helt   pm3fb: improvemen...
510
511
512
513
514
515
  	if (info->state != FBINFO_STATE_RUNNING)
  		return;
  	if (info->flags & FBINFO_HWACCEL_DISABLED) {
  		cfb_imageblit(info, image);
  		return;
  	}
e7f76df96   Krzysztof Helt   pm3fb: copyarea a...
516
  	switch (info->fix.visual) {
57bac0f08   Krzysztof Helt   pm3fb: checkpatch...
517
518
519
520
521
522
523
524
525
  	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;
e7f76df96   Krzysztof Helt   pm3fb: copyarea a...
526
  	}
7654532db   Hannes Eder   pm3fb: fix sparse...
527
528
529
530
  	if (image->depth != 1) {
  		cfb_imageblit(info, image);
  		return;
  	}
57bac0f08   Krzysztof Helt   pm3fb: checkpatch...
531

e7f76df96   Krzysztof Helt   pm3fb: copyarea a...
532
533
534
535
536
537
538
539
  	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;
  	}
b0a318e2d   Krzysztof Helt   pm3fb: imageblit ...
540
  	PM3_WAIT(par, 7);
e7f76df96   Krzysztof Helt   pm3fb: copyarea a...
541
542
543
544
545
546
  
  	PM3_WRITE_REG(par, PM3ForegroundColor, fgx);
  	PM3_WRITE_REG(par, PM3BackgroundColor, bgx);
  
  	/* ROP Ox3 is GXcopy */
  	PM3_WRITE_REG(par, PM3Config2D,
b0a318e2d   Krzysztof Helt   pm3fb: imageblit ...
547
  			PM3Config2D_UserScissorEnable |
e7f76df96   Krzysztof Helt   pm3fb: copyarea a...
548
549
  			PM3Config2D_UseConstantSource |
  			PM3Config2D_ForegroundROPEnable |
0ddf78491   Krzysztof Helt   pm3fb: improvemen...
550
  			PM3Config2D_ForegroundROP(0x3) |
e7f76df96   Krzysztof Helt   pm3fb: copyarea a...
551
552
  			PM3Config2D_OpaqueSpan |
  			PM3Config2D_FBWriteEnable);
b0a318e2d   Krzysztof Helt   pm3fb: imageblit ...
553
554
555
556
557
  	PM3_WRITE_REG(par, PM3ScissorMinXY,
  			((image->dy & 0x0fff) << 16) | (image->dx & 0x0fff));
  	PM3_WRITE_REG(par, PM3ScissorMaxXY,
  			(((image->dy + image->height) & 0x0fff) << 16) |
  			((image->dx + image->width) & 0x0fff));
e7f76df96   Krzysztof Helt   pm3fb: copyarea a...
558
  	PM3_WRITE_REG(par, PM3RectanglePosition,
0ddf78491   Krzysztof Helt   pm3fb: improvemen...
559
560
  			PM3RectanglePosition_XOffset(image->dx) |
  			PM3RectanglePosition_YOffset(image->dy));
e7f76df96   Krzysztof Helt   pm3fb: copyarea a...
561
562
563
564
565
  	PM3_WRITE_REG(par, PM3Render2D,
  			PM3Render2D_XPositive |
  			PM3Render2D_YPositive |
  			PM3Render2D_Operation_SyncOnBitMask |
  			PM3Render2D_SpanOperation |
0ddf78491   Krzysztof Helt   pm3fb: improvemen...
566
567
  			PM3Render2D_Width(image->width) |
  			PM3Render2D_Height(image->height));
e7f76df96   Krzysztof Helt   pm3fb: copyarea a...
568
569
570
  
  
  	while (height--) {
c79ba28cc   Krzysztof Helt   pm3fb: 3 small fixes
571
572
  		int width = ((image->width + 7) >> 3)
  				+ info->pixmap.scan_align - 1;
b0a318e2d   Krzysztof Helt   pm3fb: imageblit ...
573
  		width >>= 2;
e7f76df96   Krzysztof Helt   pm3fb: copyarea a...
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
  
  		while (width >= PM3_FIFO_SIZE) {
  			int i = PM3_FIFO_SIZE - 1;
  
  			PM3_WAIT(par, PM3_FIFO_SIZE);
  			while (i--) {
  				PM3_WRITE_REG(par, PM3BitMaskPattern, *src);
  				src++;
  			}
  			width -= PM3_FIFO_SIZE - 1;
  		}
  
  		PM3_WAIT(par, width + 1);
  		while (width--) {
  			PM3_WRITE_REG(par, PM3BitMaskPattern, *src);
  			src++;
  		}
  	}
  }
a58d67ce7   Krzysztof Helt   pm3fb: fillrect a...
593
  /* end of acceleration functions */
1d677a6df   Krzysztof Helt   pm3fb: hardware c...
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
  /*
   *	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 pm3fb_cursor(struct fb_info *info, struct fb_cursor *cursor)
  {
  	struct pm3_par *par = info->par;
  	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;
  
  	mode = PM3RD_CursorMode_TYPE_X;
  	if (cursor->enable)
  		 mode |= PM3RD_CursorMode_CURSOR_ENABLE;
  
  	PM3_WRITE_DAC_REG(par, PM3RD_CursorMode, 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) {
  		int x = cursor->image.dx - info->var.xoffset;
  		int y = cursor->image.dy - info->var.yoffset;
  
  		PM3_WRITE_DAC_REG(par, PM3RD_CursorXLow, x & 0xff);
  		PM3_WRITE_DAC_REG(par, PM3RD_CursorXHigh, (x >> 8) & 0xf);
  		PM3_WRITE_DAC_REG(par, PM3RD_CursorYLow, y & 0xff);
  		PM3_WRITE_DAC_REG(par, PM3RD_CursorYHigh, (y >> 8) & 0xf);
  	}
  
  	if (cursor->set & FB_CUR_SETHOT) {
  		PM3_WRITE_DAC_REG(par, PM3RD_CursorHotSpotX,
  				  cursor->hot.x & 0x3f);
  		PM3_WRITE_DAC_REG(par, PM3RD_CursorHotSpotY,
  				  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 */
  		PM3_WRITE_DAC_REG(par, PM3RD_CursorPalette(39),
  				  cmap.red[fg_idx] >> 8 );
  		PM3_WRITE_DAC_REG(par, PM3RD_CursorPalette(40),
  				  cmap.green[fg_idx] >> 8 );
  		PM3_WRITE_DAC_REG(par, PM3RD_CursorPalette(41),
  				  cmap.blue[fg_idx] >> 8 );
  
  		PM3_WRITE_DAC_REG(par, PM3RD_CursorPalette(42),
  				  cmap.red[bg_idx] >> 8 );
  		PM3_WRITE_DAC_REG(par, PM3RD_CursorPalette(43),
  				  cmap.green[bg_idx] >> 8 );
  		PM3_WRITE_DAC_REG(par, PM3RD_CursorPalette(44),
  				  cmap.blue[bg_idx] >> 8 );
  	}
  
  	if (cursor->set & (FB_CUR_SETSHAPE | FB_CUR_SETIMAGE)) {
  		u8 *bitmap = (u8 *)cursor->image.data;
  		u8 *mask = (u8 *)cursor->mask;
  		int i;
  		int pos = PM3RD_CursorPattern(0);
  
  		for (i = 0; i < cursor->image.height; i++) {
  			int j = (cursor->image.width + 7) >> 3;
  			int k = 8 - j;
  
  			for (; j > 0; j--) {
  				u8 data = *bitmap ^ *mask;
  
  				if (cursor->rop == ROP_COPY)
  					data = *mask & *bitmap;
  				/* Upper 4 bits of bitmap data */
  				PM3_WRITE_DAC_REG(par, pos++,
  					cursor_bits_lookup[data >> 4] |
  					(cursor_bits_lookup[*mask >> 4] << 1));
  				/* Lower 4 bits of bitmap */
  				PM3_WRITE_DAC_REG(par, pos++,
  					cursor_bits_lookup[data & 0xf] |
  					(cursor_bits_lookup[*mask & 0xf] << 1));
  				bitmap++;
  				mask++;
  			}
  			for (; k > 0; k--) {
  				PM3_WRITE_DAC_REG(par, pos++, 0);
  				PM3_WRITE_DAC_REG(par, pos++, 0);
  			}
  		}
  		while (pos < PM3RD_CursorPattern(1024))
  			PM3_WRITE_DAC_REG(par, pos++, 0);
  	}
  	return 0;
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
704
  /* write the mode to registers */
f23a06f07   Krzysztof Helt   pm3fb: Preliminar...
705
  static void pm3fb_write_mode(struct fb_info *info)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
706
  {
f23a06f07   Krzysztof Helt   pm3fb: Preliminar...
707
  	struct pm3_par *par = info->par;
57bac0f08   Krzysztof Helt   pm3fb: checkpatch...
708
709
  	char tempsync = 0x00;
  	char tempmisc = 0x00;
f23a06f07   Krzysztof Helt   pm3fb: Preliminar...
710
711
712
713
714
715
716
717
718
719
  	const u32 hsstart = info->var.right_margin;
  	const u32 hsend = hsstart + info->var.hsync_len;
  	const u32 hbend = hsend + info->var.left_margin;
  	const u32 xres = (info->var.xres + 31) & ~31;
  	const u32 htotal = xres + hbend;
  	const u32 vsstart = info->var.lower_margin;
  	const u32 vsend = vsstart + info->var.vsync_len;
  	const u32 vbend = vsend + info->var.upper_margin;
  	const u32 vtotal = info->var.yres + vbend;
  	const u32 width = (info->var.xres_virtual + 7) & ~7;
2686ba894   Krzysztof Helt   pm3fb: various fixes
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
  	const unsigned bpp = info->var.bits_per_pixel;
  
  	PM3_WAIT(par, 20);
  	PM3_WRITE_REG(par, PM3MemBypassWriteMask, 0xffffffff);
  	PM3_WRITE_REG(par, PM3Aperture0, 0x00000000);
  	PM3_WRITE_REG(par, PM3Aperture1, 0x00000000);
  	PM3_WRITE_REG(par, PM3FIFODis, 0x00000007);
  
  	PM3_WRITE_REG(par, PM3HTotal,
  			   pm3fb_shift_bpp(bpp, htotal - 1));
  	PM3_WRITE_REG(par, PM3HsEnd,
  			   pm3fb_shift_bpp(bpp, hsend));
  	PM3_WRITE_REG(par, PM3HsStart,
  			   pm3fb_shift_bpp(bpp, hsstart));
  	PM3_WRITE_REG(par, PM3HbEnd,
  			   pm3fb_shift_bpp(bpp, hbend));
  	PM3_WRITE_REG(par, PM3HgEnd,
  			   pm3fb_shift_bpp(bpp, hbend));
  	PM3_WRITE_REG(par, PM3ScreenStride,
  			   pm3fb_shift_bpp(bpp, width));
  	PM3_WRITE_REG(par, PM3VTotal, vtotal - 1);
  	PM3_WRITE_REG(par, PM3VsEnd, vsend - 1);
  	PM3_WRITE_REG(par, PM3VsStart, vsstart - 1);
  	PM3_WRITE_REG(par, PM3VbEnd, vbend);
  
  	switch (bpp) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
746
  	case 8:
2686ba894   Krzysztof Helt   pm3fb: various fixes
747
  		PM3_WRITE_REG(par, PM3ByAperture1Mode,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
748
  				   PM3ByApertureMode_PIXELSIZE_8BIT);
2686ba894   Krzysztof Helt   pm3fb: various fixes
749
  		PM3_WRITE_REG(par, PM3ByAperture2Mode,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
750
751
  				   PM3ByApertureMode_PIXELSIZE_8BIT);
  		break;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
752
753
  	case 16:
  #ifndef __BIG_ENDIAN
2686ba894   Krzysztof Helt   pm3fb: various fixes
754
  		PM3_WRITE_REG(par, PM3ByAperture1Mode,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
755
  				   PM3ByApertureMode_PIXELSIZE_16BIT);
2686ba894   Krzysztof Helt   pm3fb: various fixes
756
  		PM3_WRITE_REG(par, PM3ByAperture2Mode,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
757
758
  				   PM3ByApertureMode_PIXELSIZE_16BIT);
  #else
2686ba894   Krzysztof Helt   pm3fb: various fixes
759
  		PM3_WRITE_REG(par, PM3ByAperture1Mode,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
760
761
  				   PM3ByApertureMode_PIXELSIZE_16BIT |
  				   PM3ByApertureMode_BYTESWAP_BADC);
2686ba894   Krzysztof Helt   pm3fb: various fixes
762
  		PM3_WRITE_REG(par, PM3ByAperture2Mode,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
763
764
765
766
767
768
769
  				   PM3ByApertureMode_PIXELSIZE_16BIT |
  				   PM3ByApertureMode_BYTESWAP_BADC);
  #endif /* ! __BIG_ENDIAN */
  		break;
  
  	case 32:
  #ifndef __BIG_ENDIAN
2686ba894   Krzysztof Helt   pm3fb: various fixes
770
  		PM3_WRITE_REG(par, PM3ByAperture1Mode,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
771
  				   PM3ByApertureMode_PIXELSIZE_32BIT);
2686ba894   Krzysztof Helt   pm3fb: various fixes
772
  		PM3_WRITE_REG(par, PM3ByAperture2Mode,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
773
774
  				   PM3ByApertureMode_PIXELSIZE_32BIT);
  #else
2686ba894   Krzysztof Helt   pm3fb: various fixes
775
  		PM3_WRITE_REG(par, PM3ByAperture1Mode,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
776
777
  				   PM3ByApertureMode_PIXELSIZE_32BIT |
  				   PM3ByApertureMode_BYTESWAP_DCBA);
2686ba894   Krzysztof Helt   pm3fb: various fixes
778
  		PM3_WRITE_REG(par, PM3ByAperture2Mode,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
779
780
781
782
783
784
  				   PM3ByApertureMode_PIXELSIZE_32BIT |
  				   PM3ByApertureMode_BYTESWAP_DCBA);
  #endif /* ! __BIG_ENDIAN */
  		break;
  
  	default:
2686ba894   Krzysztof Helt   pm3fb: various fixes
785
786
  		DPRINTK("Unsupported depth %d
  ", bpp);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
787
788
789
790
791
792
793
794
795
796
  		break;
  	}
  
  	/*
  	 * Oxygen VX1 - it appears that setting PM3VideoControl and
  	 * then PM3RD_SyncControl to the same SYNC settings undoes
  	 * any net change - they seem to xor together.  Only set the
  	 * sync options in PM3RD_SyncControl.  --rmk
  	 */
  	{
f23a06f07   Krzysztof Helt   pm3fb: Preliminar...
797
  		unsigned int video = par->video;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
798
799
800
801
802
  
  		video &= ~(PM3VideoControl_HSYNC_MASK |
  			   PM3VideoControl_VSYNC_MASK);
  		video |= PM3VideoControl_HSYNC_ACTIVE_HIGH |
  			 PM3VideoControl_VSYNC_ACTIVE_HIGH;
2686ba894   Krzysztof Helt   pm3fb: various fixes
803
  		PM3_WRITE_REG(par, PM3VideoControl, video);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
804
  	}
2686ba894   Krzysztof Helt   pm3fb: various fixes
805
  	PM3_WRITE_REG(par, PM3VClkCtl,
f23a06f07   Krzysztof Helt   pm3fb: Preliminar...
806
  			   (PM3_READ_REG(par, PM3VClkCtl) & 0xFFFFFFFC));
2686ba894   Krzysztof Helt   pm3fb: various fixes
807
808
  	PM3_WRITE_REG(par, PM3ScreenBase, par->base);
  	PM3_WRITE_REG(par, PM3ChipConfig,
f23a06f07   Krzysztof Helt   pm3fb: Preliminar...
809
  			   (PM3_READ_REG(par, PM3ChipConfig) & 0xFFFFFFFD));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
810

2686ba894   Krzysztof Helt   pm3fb: various fixes
811
  	wmb();
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
812
  	{
f23a06f07   Krzysztof Helt   pm3fb: Preliminar...
813
814
815
816
817
818
819
820
821
822
823
824
825
826
  		unsigned char uninitialized_var(m);	/* ClkPreScale */
  		unsigned char uninitialized_var(n);	/* ClkFeedBackScale */
  		unsigned char uninitialized_var(p);	/* ClkPostScale */
  		unsigned long pixclock = PICOS2KHZ(info->var.pixclock);
  
  		(void)pm3fb_calculate_clock(pixclock, &m, &n, &p);
  
  		DPRINTK("Pixclock: %ld, Pre: %d, Feedback: %d, Post: %d
  ",
  			pixclock, (int) m, (int) n, (int) p);
  
  		PM3_WRITE_DAC_REG(par, PM3RD_DClk0PreScale, m);
  		PM3_WRITE_DAC_REG(par, PM3RD_DClk0FeedbackScale, n);
  		PM3_WRITE_DAC_REG(par, PM3RD_DClk0PostScale, p);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
827
828
  	}
  	/*
f23a06f07   Krzysztof Helt   pm3fb: Preliminar...
829
  	   PM3_WRITE_DAC_REG(par, PM3RD_IndexControl, 0x00);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
830
831
  	 */
  	/*
f23a06f07   Krzysztof Helt   pm3fb: Preliminar...
832
  	   PM3_SLOW_WRITE_REG(par, PM3RD_IndexControl, 0x00);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
833
  	 */
f23a06f07   Krzysztof Helt   pm3fb: Preliminar...
834
  	if ((par->video & PM3VideoControl_HSYNC_MASK) ==
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
835
836
  	    PM3VideoControl_HSYNC_ACTIVE_HIGH)
  		tempsync |= PM3RD_SyncControl_HSYNC_ACTIVE_HIGH;
f23a06f07   Krzysztof Helt   pm3fb: Preliminar...
837
  	if ((par->video & PM3VideoControl_VSYNC_MASK) ==
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
838
839
  	    PM3VideoControl_VSYNC_ACTIVE_HIGH)
  		tempsync |= PM3RD_SyncControl_VSYNC_ACTIVE_HIGH;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
840

f23a06f07   Krzysztof Helt   pm3fb: Preliminar...
841
842
843
844
845
  	PM3_WRITE_DAC_REG(par, PM3RD_SyncControl, tempsync);
  	DPRINTK("PM3RD_SyncControl: %d
  ", tempsync);
  
  	PM3_WRITE_DAC_REG(par, PM3RD_DACControl, 0x00);
2686ba894   Krzysztof Helt   pm3fb: various fixes
846
  	switch (pm3fb_depth(&info->var)) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
847
  	case 8:
f23a06f07   Krzysztof Helt   pm3fb: Preliminar...
848
  		PM3_WRITE_DAC_REG(par, PM3RD_PixelSize,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
849
  				  PM3RD_PixelSize_8_BIT_PIXELS);
f23a06f07   Krzysztof Helt   pm3fb: Preliminar...
850
  		PM3_WRITE_DAC_REG(par, PM3RD_ColorFormat,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
851
852
853
854
855
  				  PM3RD_ColorFormat_CI8_COLOR |
  				  PM3RD_ColorFormat_COLOR_ORDER_BLUE_LOW);
  		tempmisc |= PM3RD_MiscControl_HIGHCOLOR_RES_ENABLE;
  		break;
  	case 12:
f23a06f07   Krzysztof Helt   pm3fb: Preliminar...
856
  		PM3_WRITE_DAC_REG(par, PM3RD_PixelSize,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
857
  				  PM3RD_PixelSize_16_BIT_PIXELS);
f23a06f07   Krzysztof Helt   pm3fb: Preliminar...
858
  		PM3_WRITE_DAC_REG(par, PM3RD_ColorFormat,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
859
860
861
862
863
  				  PM3RD_ColorFormat_4444_COLOR |
  				  PM3RD_ColorFormat_COLOR_ORDER_BLUE_LOW |
  				  PM3RD_ColorFormat_LINEAR_COLOR_EXT_ENABLE);
  		tempmisc |= PM3RD_MiscControl_DIRECTCOLOR_ENABLE |
  			PM3RD_MiscControl_HIGHCOLOR_RES_ENABLE;
f23a06f07   Krzysztof Helt   pm3fb: Preliminar...
864
  		break;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
865
  	case 15:
f23a06f07   Krzysztof Helt   pm3fb: Preliminar...
866
  		PM3_WRITE_DAC_REG(par, PM3RD_PixelSize,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
867
  				  PM3RD_PixelSize_16_BIT_PIXELS);
f23a06f07   Krzysztof Helt   pm3fb: Preliminar...
868
  		PM3_WRITE_DAC_REG(par, PM3RD_ColorFormat,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
869
870
871
872
873
  				  PM3RD_ColorFormat_5551_FRONT_COLOR |
  				  PM3RD_ColorFormat_COLOR_ORDER_BLUE_LOW |
  				  PM3RD_ColorFormat_LINEAR_COLOR_EXT_ENABLE);
  		tempmisc |= PM3RD_MiscControl_DIRECTCOLOR_ENABLE |
  			PM3RD_MiscControl_HIGHCOLOR_RES_ENABLE;
f23a06f07   Krzysztof Helt   pm3fb: Preliminar...
874
  		break;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
875
  	case 16:
f23a06f07   Krzysztof Helt   pm3fb: Preliminar...
876
  		PM3_WRITE_DAC_REG(par, PM3RD_PixelSize,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
877
  				  PM3RD_PixelSize_16_BIT_PIXELS);
f23a06f07   Krzysztof Helt   pm3fb: Preliminar...
878
  		PM3_WRITE_DAC_REG(par, PM3RD_ColorFormat,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
879
880
881
882
883
884
885
  				  PM3RD_ColorFormat_565_FRONT_COLOR |
  				  PM3RD_ColorFormat_COLOR_ORDER_BLUE_LOW |
  				  PM3RD_ColorFormat_LINEAR_COLOR_EXT_ENABLE);
  		tempmisc |= PM3RD_MiscControl_DIRECTCOLOR_ENABLE |
  			PM3RD_MiscControl_HIGHCOLOR_RES_ENABLE;
  		break;
  	case 32:
f23a06f07   Krzysztof Helt   pm3fb: Preliminar...
886
  		PM3_WRITE_DAC_REG(par, PM3RD_PixelSize,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
887
  				  PM3RD_PixelSize_32_BIT_PIXELS);
f23a06f07   Krzysztof Helt   pm3fb: Preliminar...
888
  		PM3_WRITE_DAC_REG(par, PM3RD_ColorFormat,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
889
890
891
892
893
894
  				  PM3RD_ColorFormat_8888_COLOR |
  				  PM3RD_ColorFormat_COLOR_ORDER_BLUE_LOW);
  		tempmisc |= PM3RD_MiscControl_DIRECTCOLOR_ENABLE |
  			PM3RD_MiscControl_HIGHCOLOR_RES_ENABLE;
  		break;
  	}
f23a06f07   Krzysztof Helt   pm3fb: Preliminar...
895
  	PM3_WRITE_DAC_REG(par, PM3RD_MiscControl, tempmisc);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
896
  }
f23a06f07   Krzysztof Helt   pm3fb: Preliminar...
897
898
899
  /*
   * hardware independent functions
   */
f23a06f07   Krzysztof Helt   pm3fb: Preliminar...
900
901
902
  static int pm3fb_check_var(struct fb_var_screeninfo *var, struct fb_info *info)
  {
  	u32 lpitch;
2686ba894   Krzysztof Helt   pm3fb: various fixes
903
904
  	unsigned bpp = var->red.length + var->green.length
  			+ var->blue.length + var->transp.length;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
905

0ddf78491   Krzysztof Helt   pm3fb: improvemen...
906
  	if (bpp != var->bits_per_pixel) {
2686ba894   Krzysztof Helt   pm3fb: various fixes
907
  		/* set predefined mode for bits_per_pixel settings */
57bac0f08   Krzysztof Helt   pm3fb: checkpatch...
908
  		switch (var->bits_per_pixel) {
2686ba894   Krzysztof Helt   pm3fb: various fixes
909
  		case 8:
57bac0f08   Krzysztof Helt   pm3fb: checkpatch...
910
911
912
913
914
915
  			var->red.length = 8;
  			var->green.length = 8;
  			var->blue.length = 8;
  			var->red.offset = 0;
  			var->green.offset = 0;
  			var->blue.offset = 0;
2686ba894   Krzysztof Helt   pm3fb: various fixes
916
917
918
919
  			var->transp.offset = 0;
  			var->transp.length = 0;
  			break;
  		case 16:
57bac0f08   Krzysztof Helt   pm3fb: checkpatch...
920
921
  			var->red.length = 5;
  			var->blue.length = 5;
2686ba894   Krzysztof Helt   pm3fb: various fixes
922
923
924
925
  			var->green.length = 6;
  			var->transp.length = 0;
  			break;
  		case 32:
57bac0f08   Krzysztof Helt   pm3fb: checkpatch...
926
927
928
  			var->red.length = 8;
  			var->green.length = 8;
  			var->blue.length = 8;
2686ba894   Krzysztof Helt   pm3fb: various fixes
929
930
931
  			var->transp.length = 8;
  			break;
  		default:
57bac0f08   Krzysztof Helt   pm3fb: checkpatch...
932
933
934
  			DPRINTK("depth not supported: %u
  ",
  				var->bits_per_pixel);
2686ba894   Krzysztof Helt   pm3fb: various fixes
935
936
937
938
  			return -EINVAL;
  		}
  	}
  	/* it is assumed BGRA order */
57bac0f08   Krzysztof Helt   pm3fb: checkpatch...
939
  	if (var->bits_per_pixel > 8 ) {
2686ba894   Krzysztof Helt   pm3fb: various fixes
940
941
942
943
  		var->blue.offset = 0;
  		var->green.offset = var->blue.length;
  		var->red.offset = var->green.offset + var->green.length;
  		var->transp.offset = var->red.offset + var->red.length;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
944
  	}
57bac0f08   Krzysztof Helt   pm3fb: checkpatch...
945
946
  	var->height = -1;
  	var->width = -1;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
947

f23a06f07   Krzysztof Helt   pm3fb: Preliminar...
948
  	if (var->xres != var->xres_virtual) {
57bac0f08   Krzysztof Helt   pm3fb: checkpatch...
949
950
951
  		DPRINTK("virtual x resolution != "
  			"physical x resolution not supported
  ");
f23a06f07   Krzysztof Helt   pm3fb: Preliminar...
952
953
  		return -EINVAL;
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
954

f23a06f07   Krzysztof Helt   pm3fb: Preliminar...
955
  	if (var->yres > var->yres_virtual) {
57bac0f08   Krzysztof Helt   pm3fb: checkpatch...
956
957
958
  		DPRINTK("virtual y resolution < "
  			"physical y resolution not possible
  ");
f23a06f07   Krzysztof Helt   pm3fb: Preliminar...
959
  		return -EINVAL;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
960
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
961

f23a06f07   Krzysztof Helt   pm3fb: Preliminar...
962
963
964
965
  	if (var->xoffset) {
  		DPRINTK("xoffset not supported
  ");
  		return -EINVAL;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
966
  	}
f23a06f07   Krzysztof Helt   pm3fb: Preliminar...
967
968
969
970
  	if ((var->vmode & FB_VMODE_MASK) == FB_VMODE_INTERLACED) {
  		DPRINTK("interlace not supported
  ");
  		return -EINVAL;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
971
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
972

f23a06f07   Krzysztof Helt   pm3fb: Preliminar...
973
  	var->xres = (var->xres + 31) & ~31; /* could sometimes be 8 */
0ddf78491   Krzysztof Helt   pm3fb: improvemen...
974
  	lpitch = var->xres * ((var->bits_per_pixel + 7) >> 3);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
975

f23a06f07   Krzysztof Helt   pm3fb: Preliminar...
976
977
978
979
980
  	if (var->xres < 200 || var->xres > 2048) {
  		DPRINTK("width not supported: %u
  ", var->xres);
  		return -EINVAL;
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
981

f23a06f07   Krzysztof Helt   pm3fb: Preliminar...
982
983
984
985
986
  	if (var->yres < 200 || var->yres > 4095) {
  		DPRINTK("height not supported: %u
  ", var->yres);
  		return -EINVAL;
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
987

f23a06f07   Krzysztof Helt   pm3fb: Preliminar...
988
989
990
991
992
993
994
995
  	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;
  	}
  
  	if (PICOS2KHZ(var->pixclock) > PM3_MAX_PIXCLOCK) {
57bac0f08   Krzysztof Helt   pm3fb: checkpatch...
996
997
998
  		DPRINTK("pixclock too high (%ldKHz)
  ",
  			PICOS2KHZ(var->pixclock));
f23a06f07   Krzysztof Helt   pm3fb: Preliminar...
999
  		return -EINVAL;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1000
  	}
f23a06f07   Krzysztof Helt   pm3fb: Preliminar...
1001
  	var->accel_flags = 0;	/* Can't mmap if this is on */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1002

f23a06f07   Krzysztof Helt   pm3fb: Preliminar...
1003
1004
1005
1006
1007
  	DPRINTK("Checking graphics mode at %dx%d depth %d
  ",
  		var->xres, var->yres, var->bits_per_pixel);
  	return 0;
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1008

f23a06f07   Krzysztof Helt   pm3fb: Preliminar...
1009
1010
1011
1012
  static int pm3fb_set_par(struct fb_info *info)
  {
  	struct pm3_par *par = info->par;
  	const u32 xres = (info->var.xres + 31) & ~31;
2686ba894   Krzysztof Helt   pm3fb: various fixes
1013
  	const unsigned bpp = info->var.bits_per_pixel;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1014

57bac0f08   Krzysztof Helt   pm3fb: checkpatch...
1015
  	par->base = pm3fb_shift_bpp(bpp, (info->var.yoffset * xres)
f23a06f07   Krzysztof Helt   pm3fb: Preliminar...
1016
1017
  					+ info->var.xoffset);
  	par->video = 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1018

f23a06f07   Krzysztof Helt   pm3fb: Preliminar...
1019
1020
1021
1022
  	if (info->var.sync & FB_SYNC_HOR_HIGH_ACT)
  		par->video |= PM3VideoControl_HSYNC_ACTIVE_HIGH;
  	else
  		par->video |= PM3VideoControl_HSYNC_ACTIVE_LOW;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1023

f23a06f07   Krzysztof Helt   pm3fb: Preliminar...
1024
1025
1026
1027
  	if (info->var.sync & FB_SYNC_VERT_HIGH_ACT)
  		par->video |= PM3VideoControl_VSYNC_ACTIVE_HIGH;
  	else
  		par->video |= PM3VideoControl_VSYNC_ACTIVE_LOW;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1028

f23a06f07   Krzysztof Helt   pm3fb: Preliminar...
1029
1030
  	if ((info->var.vmode & FB_VMODE_MASK) == FB_VMODE_DOUBLE)
  		par->video |= PM3VideoControl_LINE_DOUBLE_ON;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1031

0bd327ef2   Krzysztof Helt   pm3fb: switching ...
1032
  	if ((info->var.activate & FB_ACTIVATE_MASK) == FB_ACTIVATE_NOW)
f23a06f07   Krzysztof Helt   pm3fb: Preliminar...
1033
  		par->video |= PM3VideoControl_ENABLE;
0ddf78491   Krzysztof Helt   pm3fb: improvemen...
1034
  	else
f23a06f07   Krzysztof Helt   pm3fb: Preliminar...
1035
1036
  		DPRINTK("PM3Video disabled
  ");
0ddf78491   Krzysztof Helt   pm3fb: improvemen...
1037

2686ba894   Krzysztof Helt   pm3fb: various fixes
1038
  	switch (bpp) {
f23a06f07   Krzysztof Helt   pm3fb: Preliminar...
1039
1040
1041
  	case 8:
  		par->video |= PM3VideoControl_PIXELSIZE_8BIT;
  		break;
f23a06f07   Krzysztof Helt   pm3fb: Preliminar...
1042
1043
1044
1045
1046
1047
1048
1049
1050
1051
  	case 16:
  		par->video |= PM3VideoControl_PIXELSIZE_16BIT;
  		break;
  	case 32:
  		par->video |= PM3VideoControl_PIXELSIZE_32BIT;
  		break;
  	default:
  		DPRINTK("Unsupported depth
  ");
  		break;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1052
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1053

f23a06f07   Krzysztof Helt   pm3fb: Preliminar...
1054
  	info->fix.visual =
2686ba894   Krzysztof Helt   pm3fb: various fixes
1055
  		(bpp == 8) ? FB_VISUAL_PSEUDOCOLOR : FB_VISUAL_TRUECOLOR;
0ddf78491   Krzysztof Helt   pm3fb: improvemen...
1056
  	info->fix.line_length = ((info->var.xres_virtual + 7)  >> 3) * bpp;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1057

f23a06f07   Krzysztof Helt   pm3fb: Preliminar...
1058
1059
  /*	pm3fb_clear_memory(info, 0);*/
  	pm3fb_clear_colormap(par, 0, 0, 0);
f259ebb67   Krzysztof Helt   pm3fb: header fil...
1060
  	PM3_WRITE_DAC_REG(par, PM3RD_CursorMode, 0);
a58d67ce7   Krzysztof Helt   pm3fb: fillrect a...
1061
  	pm3fb_init_engine(info);
f23a06f07   Krzysztof Helt   pm3fb: Preliminar...
1062
1063
  	pm3fb_write_mode(info);
  	return 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1064
  }
f23a06f07   Krzysztof Helt   pm3fb: Preliminar...
1065
1066
1067
  static int pm3fb_setcolreg(unsigned regno, unsigned red, unsigned green,
  			   unsigned blue, unsigned transp,
  			   struct fb_info *info)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1068
  {
f23a06f07   Krzysztof Helt   pm3fb: Preliminar...
1069
1070
1071
1072
1073
1074
  	struct pm3_par *par = info->par;
  
  	if (regno >= 256)  /* no. of hw registers */
  	   return -EINVAL;
  
  	/* grayscale works only partially under directcolor */
57bac0f08   Krzysztof Helt   pm3fb: checkpatch...
1075
1076
  	/* grayscale = 0.30*R + 0.59*G + 0.11*B */
  	if (info->var.grayscale)
f23a06f07   Krzysztof Helt   pm3fb: Preliminar...
1077
  	   red = green = blue = (red * 77 + green * 151 + blue * 28) >> 8;
f23a06f07   Krzysztof Helt   pm3fb: Preliminar...
1078
1079
1080
1081
1082
1083
  
  	/* Directcolor:
  	 *   var->{color}.offset contains start of bitfield
  	 *   var->{color}.length contains length of bitfield
  	 *   {hardwarespecific} contains width of DAC
  	 *   pseudo_palette[X] is programmed to (X << red.offset) |
2686ba894   Krzysztof Helt   pm3fb: various fixes
1084
1085
  	 *					(X << green.offset) |
  	 *					(X << blue.offset)
f23a06f07   Krzysztof Helt   pm3fb: Preliminar...
1086
1087
1088
1089
1090
  	 *   RAMDAC[X] is programmed to (red, green, blue)
  	 *   color depth = SUM(var->{color}.length)
  	 *
  	 * Pseudocolor:
  	 *	var->{color}.offset is 0
57bac0f08   Krzysztof Helt   pm3fb: checkpatch...
1091
1092
  	 *	var->{color}.length contains width of DAC or the number
  	 *			of unique colors available (color depth)
f23a06f07   Krzysztof Helt   pm3fb: Preliminar...
1093
1094
1095
1096
  	 *	pseudo_palette is not used
  	 *	RAMDAC[X] is programmed to (red, green, blue)
  	 *	color depth = var->{color}.length
  	 */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1097

f23a06f07   Krzysztof Helt   pm3fb: Preliminar...
1098
1099
1100
1101
  	/*
  	 * This is the point where the color is converted to something that
  	 * is acceptable by the hardware.
  	 */
57bac0f08   Krzysztof Helt   pm3fb: checkpatch...
1102
  #define CNVT_TOHW(val, width) ((((val) << (width)) + 0x7FFF - (val)) >> 16)
f23a06f07   Krzysztof Helt   pm3fb: Preliminar...
1103
1104
1105
1106
1107
1108
1109
1110
1111
1112
1113
1114
1115
1116
1117
1118
1119
1120
1121
1122
1123
1124
  	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);
  #undef CNVT_TOHW
  
  	if (info->fix.visual == FB_VISUAL_TRUECOLOR ||
  	info->fix.visual == FB_VISUAL_DIRECTCOLOR) {
  		u32 v;
  
  		if (regno >= 16)
  			return -EINVAL;
  
  		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:
  			break;
  		case 16:
f23a06f07   Krzysztof Helt   pm3fb: Preliminar...
1125
  		case 32:
57bac0f08   Krzysztof Helt   pm3fb: checkpatch...
1126
  			((u32 *)(info->pseudo_palette))[regno] = v;
f23a06f07   Krzysztof Helt   pm3fb: Preliminar...
1127
1128
1129
  			break;
  		}
  		return 0;
57bac0f08   Krzysztof Helt   pm3fb: checkpatch...
1130
  	} else if (info->fix.visual == FB_VISUAL_PSEUDOCOLOR)
f23a06f07   Krzysztof Helt   pm3fb: Preliminar...
1131
  		pm3fb_set_color(par, regno, red, green, blue);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1132

f23a06f07   Krzysztof Helt   pm3fb: Preliminar...
1133
  	return 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1134
  }
f23a06f07   Krzysztof Helt   pm3fb: Preliminar...
1135
1136
  static int pm3fb_pan_display(struct fb_var_screeninfo *var,
  				 struct fb_info *info)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1137
  {
f23a06f07   Krzysztof Helt   pm3fb: Preliminar...
1138
  	struct pm3_par *par = info->par;
1fdb518f9   Laurent Pinchart   pm3fb: use displa...
1139
  	const u32 xres = (info->var.xres + 31) & ~31;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1140

1fdb518f9   Laurent Pinchart   pm3fb: use displa...
1141
  	par->base = pm3fb_shift_bpp(info->var.bits_per_pixel,
f23a06f07   Krzysztof Helt   pm3fb: Preliminar...
1142
1143
  					(var->yoffset * xres)
  					+ var->xoffset);
2686ba894   Krzysztof Helt   pm3fb: various fixes
1144
1145
  	PM3_WAIT(par, 1);
  	PM3_WRITE_REG(par, PM3ScreenBase, par->base);
f23a06f07   Krzysztof Helt   pm3fb: Preliminar...
1146
1147
  	return 0;
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1148

f23a06f07   Krzysztof Helt   pm3fb: Preliminar...
1149
1150
1151
1152
  static int pm3fb_blank(int blank_mode, struct fb_info *info)
  {
  	struct pm3_par *par = info->par;
  	u32 video = par->video;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1153

f23a06f07   Krzysztof Helt   pm3fb: Preliminar...
1154
1155
1156
1157
1158
1159
1160
1161
1162
1163
  	/*
  	 * Oxygen VX1 - it appears that setting PM3VideoControl and
  	 * then PM3RD_SyncControl to the same SYNC settings undoes
  	 * any net change - they seem to xor together.  Only set the
  	 * sync options in PM3RD_SyncControl.  --rmk
  	 */
  	video &= ~(PM3VideoControl_HSYNC_MASK |
  		   PM3VideoControl_VSYNC_MASK);
  	video |= PM3VideoControl_HSYNC_ACTIVE_HIGH |
  		 PM3VideoControl_VSYNC_ACTIVE_HIGH;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1164

f23a06f07   Krzysztof Helt   pm3fb: Preliminar...
1165
1166
  	switch (blank_mode) {
  	case FB_BLANK_UNBLANK:
2686ba894   Krzysztof Helt   pm3fb: various fixes
1167
  		video |= PM3VideoControl_ENABLE;
f23a06f07   Krzysztof Helt   pm3fb: Preliminar...
1168
  		break;
2686ba894   Krzysztof Helt   pm3fb: various fixes
1169
  	case FB_BLANK_NORMAL:
0ddf78491   Krzysztof Helt   pm3fb: improvemen...
1170
  		video &= ~PM3VideoControl_ENABLE;
f23a06f07   Krzysztof Helt   pm3fb: Preliminar...
1171
1172
  		break;
  	case FB_BLANK_HSYNC_SUSPEND:
2686ba894   Krzysztof Helt   pm3fb: various fixes
1173
1174
  		video &= ~(PM3VideoControl_HSYNC_MASK |
  			  PM3VideoControl_BLANK_ACTIVE_LOW);
f23a06f07   Krzysztof Helt   pm3fb: Preliminar...
1175
1176
  		break;
  	case FB_BLANK_VSYNC_SUSPEND:
2686ba894   Krzysztof Helt   pm3fb: various fixes
1177
1178
  		video &= ~(PM3VideoControl_VSYNC_MASK |
  			  PM3VideoControl_BLANK_ACTIVE_LOW);
f23a06f07   Krzysztof Helt   pm3fb: Preliminar...
1179
1180
  		break;
  	case FB_BLANK_POWERDOWN:
2686ba894   Krzysztof Helt   pm3fb: various fixes
1181
1182
1183
  		video &= ~(PM3VideoControl_HSYNC_MASK |
  			  PM3VideoControl_VSYNC_MASK |
  			  PM3VideoControl_BLANK_ACTIVE_LOW);
f23a06f07   Krzysztof Helt   pm3fb: Preliminar...
1184
1185
1186
1187
1188
  		break;
  	default:
  		DPRINTK("Unsupported blanking %d
  ", blank_mode);
  		return 1;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1189
  	}
2686ba894   Krzysztof Helt   pm3fb: various fixes
1190
  	PM3_WAIT(par, 1);
57bac0f08   Krzysztof Helt   pm3fb: checkpatch...
1191
  	PM3_WRITE_REG(par, PM3VideoControl, video);
f23a06f07   Krzysztof Helt   pm3fb: Preliminar...
1192
  	return 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1193
  }
f23a06f07   Krzysztof Helt   pm3fb: Preliminar...
1194
1195
1196
  	/*
  	 *  Frame buffer operations
  	 */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1197

f23a06f07   Krzysztof Helt   pm3fb: Preliminar...
1198
1199
1200
1201
1202
1203
  static struct fb_ops pm3fb_ops = {
  	.owner		= THIS_MODULE,
  	.fb_check_var	= pm3fb_check_var,
  	.fb_set_par	= pm3fb_set_par,
  	.fb_setcolreg	= pm3fb_setcolreg,
  	.fb_pan_display	= pm3fb_pan_display,
a58d67ce7   Krzysztof Helt   pm3fb: fillrect a...
1204
  	.fb_fillrect	= pm3fb_fillrect,
e7f76df96   Krzysztof Helt   pm3fb: copyarea a...
1205
1206
  	.fb_copyarea	= pm3fb_copyarea,
  	.fb_imageblit	= pm3fb_imageblit,
f23a06f07   Krzysztof Helt   pm3fb: Preliminar...
1207
  	.fb_blank	= pm3fb_blank,
a58d67ce7   Krzysztof Helt   pm3fb: fillrect a...
1208
  	.fb_sync	= pm3fb_sync,
1d677a6df   Krzysztof Helt   pm3fb: hardware c...
1209
  	.fb_cursor	= pm3fb_cursor,
f23a06f07   Krzysztof Helt   pm3fb: Preliminar...
1210
  };
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1211

f23a06f07   Krzysztof Helt   pm3fb: Preliminar...
1212
  /* ------------------------------------------------------------------------- */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1213

f23a06f07   Krzysztof Helt   pm3fb: Preliminar...
1214
1215
1216
  	/*
  	 *  Initialization
  	 */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1217

f23a06f07   Krzysztof Helt   pm3fb: Preliminar...
1218
1219
  /* mmio register are already mapped when this function is called */
  /* the pm3fb_fix.smem_start is also set */
050da932f   Adrian Bunk   drivers/video/pm3...
1220
  static unsigned long __devinit pm3fb_size_memory(struct pm3_par *par)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1221
  {
57bac0f08   Krzysztof Helt   pm3fb: checkpatch...
1222
1223
  	unsigned long	memsize = 0;
  	unsigned long	tempBypass, i, temp1, temp2;
f23a06f07   Krzysztof Helt   pm3fb: Preliminar...
1224
  	unsigned char	__iomem *screen_mem;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1225

2686ba894   Krzysztof Helt   pm3fb: various fixes
1226
  	pm3fb_fix.smem_len = 64 * 1024l * 1024; /* request full aperture size */
f23a06f07   Krzysztof Helt   pm3fb: Preliminar...
1227
1228
1229
1230
1231
1232
  	/* Linear frame buffer - request region and map it. */
  	if (!request_mem_region(pm3fb_fix.smem_start, pm3fb_fix.smem_len,
  				 "pm3fb smem")) {
  		printk(KERN_WARNING "pm3fb: Can't reserve smem.
  ");
  		return 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1233
  	}
f23a06f07   Krzysztof Helt   pm3fb: Preliminar...
1234
1235
1236
1237
1238
1239
1240
  	screen_mem =
  		ioremap_nocache(pm3fb_fix.smem_start, pm3fb_fix.smem_len);
  	if (!screen_mem) {
  		printk(KERN_WARNING "pm3fb: Can't ioremap smem area.
  ");
  		release_mem_region(pm3fb_fix.smem_start, pm3fb_fix.smem_len);
  		return 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1241
  	}
f23a06f07   Krzysztof Helt   pm3fb: Preliminar...
1242
1243
  	/* TODO: card-specific stuff, *before* accessing *any* FB memory */
  	/* For Appian Jeronimo 2000 board second head */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1244

f23a06f07   Krzysztof Helt   pm3fb: Preliminar...
1245
  	tempBypass = PM3_READ_REG(par, PM3MemBypassWriteMask);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1246

f23a06f07   Krzysztof Helt   pm3fb: Preliminar...
1247
1248
  	DPRINTK("PM3MemBypassWriteMask was: 0x%08lx
  ", tempBypass);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1249

2686ba894   Krzysztof Helt   pm3fb: various fixes
1250
1251
  	PM3_WAIT(par, 1);
  	PM3_WRITE_REG(par, PM3MemBypassWriteMask, 0xFFFFFFFF);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1252

57bac0f08   Krzysztof Helt   pm3fb: checkpatch...
1253
1254
1255
  	/* pm3 split up memory, replicates, and do a lot of
  	 * nasty stuff IMHO ;-)
  	 */
f23a06f07   Krzysztof Helt   pm3fb: Preliminar...
1256
1257
1258
1259
1260
  	for (i = 0; i < 32; i++) {
  		fb_writel(i * 0x00345678,
  			  (screen_mem + (i * 1048576)));
  		mb();
  		temp1 = fb_readl((screen_mem + (i * 1048576)));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1261

f23a06f07   Krzysztof Helt   pm3fb: Preliminar...
1262
1263
1264
  		/* Let's check for wrapover, write will fail at 16MB boundary */
  		if (temp1 == (i * 0x00345678))
  			memsize = i;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1265
  		else
f23a06f07   Krzysztof Helt   pm3fb: Preliminar...
1266
  			break;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1267
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1268

f23a06f07   Krzysztof Helt   pm3fb: Preliminar...
1269
1270
  	DPRINTK("First detect pass already got %ld MB
  ", memsize + 1);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1271

f23a06f07   Krzysztof Helt   pm3fb: Preliminar...
1272
1273
1274
  	if (memsize + 1 == i) {
  		for (i = 0; i < 32; i++) {
  			/* Clear first 32MB ; 0 is 0, no need to byteswap */
2686ba894   Krzysztof Helt   pm3fb: various fixes
1275
  			writel(0x0000000, (screen_mem + (i * 1048576)));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1276
  		}
2686ba894   Krzysztof Helt   pm3fb: various fixes
1277
  		wmb();
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1278

f23a06f07   Krzysztof Helt   pm3fb: Preliminar...
1279
1280
1281
1282
1283
1284
1285
1286
1287
1288
1289
1290
1291
  		for (i = 32; i < 64; i++) {
  			fb_writel(i * 0x00345678,
  				  (screen_mem + (i * 1048576)));
  			mb();
  			temp1 =
  			    fb_readl((screen_mem + (i * 1048576)));
  			temp2 =
  			    fb_readl((screen_mem + ((i - 32) * 1048576)));
  			/* different value, different RAM... */
  			if ((temp1 == (i * 0x00345678)) && (temp2 == 0))
  				memsize = i;
  			else
  				break;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1292
  		}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1293
  	}
f23a06f07   Krzysztof Helt   pm3fb: Preliminar...
1294
1295
  	DPRINTK("Second detect pass got %ld MB
  ", memsize + 1);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1296

2686ba894   Krzysztof Helt   pm3fb: various fixes
1297
1298
  	PM3_WAIT(par, 1);
  	PM3_WRITE_REG(par, PM3MemBypassWriteMask, tempBypass);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1299

f23a06f07   Krzysztof Helt   pm3fb: Preliminar...
1300
1301
1302
  	iounmap(screen_mem);
  	release_mem_region(pm3fb_fix.smem_start, pm3fb_fix.smem_len);
  	memsize = 1048576 * (memsize + 1);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1303

f23a06f07   Krzysztof Helt   pm3fb: Preliminar...
1304
1305
  	DPRINTK("Returning 0x%08lx bytes
  ", memsize);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1306

f23a06f07   Krzysztof Helt   pm3fb: Preliminar...
1307
  	return memsize;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1308
  }
f23a06f07   Krzysztof Helt   pm3fb: Preliminar...
1309
1310
  static int __devinit pm3fb_probe(struct pci_dev *dev,
  				  const struct pci_device_id *ent)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1311
  {
f23a06f07   Krzysztof Helt   pm3fb: Preliminar...
1312
1313
  	struct fb_info *info;
  	struct pm3_par *par;
57bac0f08   Krzysztof Helt   pm3fb: checkpatch...
1314
1315
1316
  	struct device *device = &dev->dev; /* for pci drivers */
  	int err;
  	int retval = -ENXIO;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1317

f23a06f07   Krzysztof Helt   pm3fb: Preliminar...
1318
1319
1320
1321
1322
  	err = pci_enable_device(dev);
  	if (err) {
  		printk(KERN_WARNING "pm3fb: Can't enable PCI dev: %d
  ", err);
  		return err;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1323
  	}
f23a06f07   Krzysztof Helt   pm3fb: Preliminar...
1324
1325
1326
1327
  	/*
  	 * Dynamically allocate info and par
  	 */
  	info = framebuffer_alloc(sizeof(struct pm3_par), device);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1328

f23a06f07   Krzysztof Helt   pm3fb: Preliminar...
1329
1330
1331
  	if (!info)
  		return -ENOMEM;
  	par = info->par;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1332

f23a06f07   Krzysztof Helt   pm3fb: Preliminar...
1333
1334
1335
1336
1337
1338
  	/*
  	 * Here we set the screen_base to the virtual memory address
  	 * for the framebuffer.
  	 */
  	pm3fb_fix.mmio_start = pci_resource_start(dev, 0);
  	pm3fb_fix.mmio_len = PM3_REGS_SIZE;
c79ba28cc   Krzysztof Helt   pm3fb: 3 small fixes
1339
1340
1341
1342
1343
  #if defined(__BIG_ENDIAN)
  	pm3fb_fix.mmio_start += PM3_REGS_SIZE;
  	DPRINTK("Adjusting register base for big-endian.
  ");
  #endif
f23a06f07   Krzysztof Helt   pm3fb: Preliminar...
1344
1345
1346
1347
1348
1349
1350
1351
1352
1353
1354
1355
1356
1357
1358
1359
1360
  
  	/* Registers - request region and map it. */
  	if (!request_mem_region(pm3fb_fix.mmio_start, pm3fb_fix.mmio_len,
  				 "pm3fb regbase")) {
  		printk(KERN_WARNING "pm3fb: Can't reserve regbase.
  ");
  		goto err_exit_neither;
  	}
  	par->v_regs =
  		ioremap_nocache(pm3fb_fix.mmio_start, pm3fb_fix.mmio_len);
  	if (!par->v_regs) {
  		printk(KERN_WARNING "pm3fb: Can't remap %s register area.
  ",
  			pm3fb_fix.id);
  		release_mem_region(pm3fb_fix.mmio_start, pm3fb_fix.mmio_len);
  		goto err_exit_neither;
  	}
f23a06f07   Krzysztof Helt   pm3fb: Preliminar...
1361
1362
1363
  	/* Linear frame buffer - request region and map it. */
  	pm3fb_fix.smem_start = pci_resource_start(dev, 1);
  	pm3fb_fix.smem_len = pm3fb_size_memory(par);
57bac0f08   Krzysztof Helt   pm3fb: checkpatch...
1364
  	if (!pm3fb_fix.smem_len) {
f23a06f07   Krzysztof Helt   pm3fb: Preliminar...
1365
1366
1367
  		printk(KERN_WARNING "pm3fb: Can't find memory on board.
  ");
  		goto err_exit_mmio;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1368
  	}
f23a06f07   Krzysztof Helt   pm3fb: Preliminar...
1369
1370
1371
1372
1373
  	if (!request_mem_region(pm3fb_fix.smem_start, pm3fb_fix.smem_len,
  				 "pm3fb smem")) {
  		printk(KERN_WARNING "pm3fb: Can't reserve smem.
  ");
  		goto err_exit_mmio;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1374
  	}
f23a06f07   Krzysztof Helt   pm3fb: Preliminar...
1375
1376
1377
1378
1379
1380
1381
  	info->screen_base =
  		ioremap_nocache(pm3fb_fix.smem_start, pm3fb_fix.smem_len);
  	if (!info->screen_base) {
  		printk(KERN_WARNING "pm3fb: Can't ioremap smem area.
  ");
  		release_mem_region(pm3fb_fix.smem_start, pm3fb_fix.smem_len);
  		goto err_exit_mmio;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1382
  	}
f23a06f07   Krzysztof Helt   pm3fb: Preliminar...
1383
  	info->screen_size = pm3fb_fix.smem_len;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1384

d5383fcc4   Krzysztof Helt   pm3fb: mtrr suppo...
1385
  #ifdef CONFIG_MTRR
57bac0f08   Krzysztof Helt   pm3fb: checkpatch...
1386
  	if (!nomtrr)
d5383fcc4   Krzysztof Helt   pm3fb: mtrr suppo...
1387
1388
1389
  		par->mtrr_handle = mtrr_add(pm3fb_fix.smem_start,
  						pm3fb_fix.smem_len,
  						MTRR_TYPE_WRCOMB, 1);
d5383fcc4   Krzysztof Helt   pm3fb: mtrr suppo...
1390
  #endif
f23a06f07   Krzysztof Helt   pm3fb: Preliminar...
1391
  	info->fbops = &pm3fb_ops;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1392

f23a06f07   Krzysztof Helt   pm3fb: Preliminar...
1393
  	par->video = PM3_READ_REG(par, PM3VideoControl);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1394

f23a06f07   Krzysztof Helt   pm3fb: Preliminar...
1395
1396
  	info->fix = pm3fb_fix;
  	info->pseudo_palette = par->palette;
a58d67ce7   Krzysztof Helt   pm3fb: fillrect a...
1397
  	info->flags = FBINFO_DEFAULT |
c79ba28cc   Krzysztof Helt   pm3fb: 3 small fixes
1398
1399
  			FBINFO_HWACCEL_XPAN |
  			FBINFO_HWACCEL_YPAN |
e7f76df96   Krzysztof Helt   pm3fb: copyarea a...
1400
1401
1402
  			FBINFO_HWACCEL_COPYAREA |
  			FBINFO_HWACCEL_IMAGEBLIT |
  			FBINFO_HWACCEL_FILLRECT;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1403

d5383fcc4   Krzysztof Helt   pm3fb: mtrr suppo...
1404
  	if (noaccel) {
57bac0f08   Krzysztof Helt   pm3fb: checkpatch...
1405
1406
1407
  		printk(KERN_DEBUG "disabling acceleration
  ");
  		info->flags |= FBINFO_HWACCEL_DISABLED;
d5383fcc4   Krzysztof Helt   pm3fb: mtrr suppo...
1408
  	}
b0a318e2d   Krzysztof Helt   pm3fb: imageblit ...
1409
1410
1411
1412
1413
1414
1415
1416
1417
1418
  	info->pixmap.addr = kmalloc(PM3_PIXMAP_SIZE, GFP_KERNEL);
  	if (!info->pixmap.addr) {
  		retval = -ENOMEM;
  		goto err_exit_pixmap;
  	}
  	info->pixmap.size = PM3_PIXMAP_SIZE;
  	info->pixmap.buf_align = 4;
  	info->pixmap.scan_align = 4;
  	info->pixmap.access_align = 32;
  	info->pixmap.flags = FB_PIXMAP_SYSTEM;
f23a06f07   Krzysztof Helt   pm3fb: Preliminar...
1419
1420
1421
1422
1423
1424
  	/*
  	 * This should give a reasonable default video mode. The following is
  	 * done when we can set a video mode.
  	 */
  	if (!mode_option)
  		mode_option = "640x480@60";
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1425

f23a06f07   Krzysztof Helt   pm3fb: Preliminar...
1426
  	retval = fb_find_mode(&info->var, info, mode_option, NULL, 0, NULL, 8);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1427

f23a06f07   Krzysztof Helt   pm3fb: Preliminar...
1428
1429
1430
  	if (!retval || retval == 4) {
  		retval = -EINVAL;
  		goto err_exit_both;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1431
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1432

f23a06f07   Krzysztof Helt   pm3fb: Preliminar...
1433
1434
1435
  	if (fb_alloc_cmap(&info->cmap, 256, 0) < 0) {
  		retval = -ENOMEM;
  		goto err_exit_both;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1436
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1437

f23a06f07   Krzysztof Helt   pm3fb: Preliminar...
1438
1439
1440
1441
  	/*
  	 * For drivers that can...
  	 */
  	pm3fb_check_var(&info->var, info);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1442

f23a06f07   Krzysztof Helt   pm3fb: Preliminar...
1443
1444
1445
  	if (register_framebuffer(info) < 0) {
  		retval = -EINVAL;
  		goto err_exit_all;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1446
  	}
f23a06f07   Krzysztof Helt   pm3fb: Preliminar...
1447
1448
1449
  	printk(KERN_INFO "fb%d: %s frame buffer device
  ", info->node,
  	   info->fix.id);
2686ba894   Krzysztof Helt   pm3fb: various fixes
1450
  	pci_set_drvdata(dev, info);
f23a06f07   Krzysztof Helt   pm3fb: Preliminar...
1451
  	return 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1452

f23a06f07   Krzysztof Helt   pm3fb: Preliminar...
1453
1454
1455
   err_exit_all:
  	fb_dealloc_cmap(&info->cmap);
   err_exit_both:
b0a318e2d   Krzysztof Helt   pm3fb: imageblit ...
1456
1457
  	kfree(info->pixmap.addr);
   err_exit_pixmap:
f23a06f07   Krzysztof Helt   pm3fb: Preliminar...
1458
1459
1460
1461
1462
1463
1464
1465
  	iounmap(info->screen_base);
  	release_mem_region(pm3fb_fix.smem_start, pm3fb_fix.smem_len);
   err_exit_mmio:
  	iounmap(par->v_regs);
  	release_mem_region(pm3fb_fix.mmio_start, pm3fb_fix.mmio_len);
   err_exit_neither:
  	framebuffer_release(info);
  	return retval;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1466
  }
f23a06f07   Krzysztof Helt   pm3fb: Preliminar...
1467
1468
1469
1470
  	/*
  	 *  Cleanup
  	 */
  static void __devexit pm3fb_remove(struct pci_dev *dev)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1471
  {
f23a06f07   Krzysztof Helt   pm3fb: Preliminar...
1472
  	struct fb_info *info = pci_get_drvdata(dev);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1473

f23a06f07   Krzysztof Helt   pm3fb: Preliminar...
1474
1475
1476
  	if (info) {
  		struct fb_fix_screeninfo *fix = &info->fix;
  		struct pm3_par *par = info->par;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1477

f23a06f07   Krzysztof Helt   pm3fb: Preliminar...
1478
1479
  		unregister_framebuffer(info);
  		fb_dealloc_cmap(&info->cmap);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1480

d5383fcc4   Krzysztof Helt   pm3fb: mtrr suppo...
1481
1482
1483
1484
1485
  #ifdef CONFIG_MTRR
  	if (par->mtrr_handle >= 0)
  		mtrr_del(par->mtrr_handle, info->fix.smem_start,
  			 info->fix.smem_len);
  #endif /* CONFIG_MTRR */
f23a06f07   Krzysztof Helt   pm3fb: Preliminar...
1486
1487
1488
1489
  		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);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1490

f23a06f07   Krzysztof Helt   pm3fb: Preliminar...
1491
  		pci_set_drvdata(dev, NULL);
b0a318e2d   Krzysztof Helt   pm3fb: imageblit ...
1492
  		kfree(info->pixmap.addr);
f23a06f07   Krzysztof Helt   pm3fb: Preliminar...
1493
  		framebuffer_release(info);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1494
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1495
  }
f23a06f07   Krzysztof Helt   pm3fb: Preliminar...
1496
1497
  static struct pci_device_id pm3fb_id_table[] = {
  	{ PCI_VENDOR_ID_3DLABS, 0x0a,
2686ba894   Krzysztof Helt   pm3fb: various fixes
1498
  	  PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 },
f23a06f07   Krzysztof Helt   pm3fb: Preliminar...
1499
1500
  	{ 0, }
  };
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1501

f23a06f07   Krzysztof Helt   pm3fb: Preliminar...
1502
1503
1504
1505
1506
1507
1508
  /* For PCI drivers */
  static struct pci_driver pm3fb_driver = {
  	.name =		"pm3fb",
  	.id_table =	pm3fb_id_table,
  	.probe =	pm3fb_probe,
  	.remove =	__devexit_p(pm3fb_remove),
  };
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1509

f23a06f07   Krzysztof Helt   pm3fb: Preliminar...
1510
  MODULE_DEVICE_TABLE(pci, pm3fb_id_table);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1511

d5383fcc4   Krzysztof Helt   pm3fb: mtrr suppo...
1512
1513
1514
1515
1516
1517
1518
1519
1520
1521
1522
1523
  #ifndef MODULE
  	/*
  	 *  Setup
  	 */
  
  /*
   * Only necessary if your driver takes special options,
   * otherwise we fall back on the generic fb_setup().
   */
  static int __init pm3fb_setup(char *options)
  {
  	char *this_opt;
75e1b6a84   Joe Perches   video: Fix spefic...
1524
  	/* Parse user specified options (`video=pm3fb:') */
d5383fcc4   Krzysztof Helt   pm3fb: mtrr suppo...
1525
1526
1527
1528
1529
1530
  	if (!options || !*options)
  		return 0;
  
  	while ((this_opt = strsep(&options, ",")) != NULL) {
  		if (!*this_opt)
  			continue;
57bac0f08   Krzysztof Helt   pm3fb: checkpatch...
1531
  		else if (!strncmp(this_opt, "noaccel", 7))
d5383fcc4   Krzysztof Helt   pm3fb: mtrr suppo...
1532
  			noaccel = 1;
1d677a6df   Krzysztof Helt   pm3fb: hardware c...
1533
1534
  		else if (!strncmp(this_opt, "hwcursor=", 9))
  			hwcursor = simple_strtoul(this_opt + 9, NULL, 0);
d5383fcc4   Krzysztof Helt   pm3fb: mtrr suppo...
1535
  #ifdef CONFIG_MTRR
57bac0f08   Krzysztof Helt   pm3fb: checkpatch...
1536
  		else if (!strncmp(this_opt, "nomtrr", 6))
d5383fcc4   Krzysztof Helt   pm3fb: mtrr suppo...
1537
1538
  			nomtrr = 1;
  #endif
57bac0f08   Krzysztof Helt   pm3fb: checkpatch...
1539
  		else
d5383fcc4   Krzysztof Helt   pm3fb: mtrr suppo...
1540
  			mode_option = this_opt;
d5383fcc4   Krzysztof Helt   pm3fb: mtrr suppo...
1541
1542
1543
1544
  	}
  	return 0;
  }
  #endif /* MODULE */
b309c050c   Adrian Bunk   pm3fb: possible c...
1545
  static int __init pm3fb_init(void)
2686ba894   Krzysztof Helt   pm3fb: various fixes
1546
  {
d5383fcc4   Krzysztof Helt   pm3fb: mtrr suppo...
1547
1548
1549
  	/*
  	 *  For kernel boot options (in 'video=pm3fb:<options>' format)
  	 */
f23a06f07   Krzysztof Helt   pm3fb: Preliminar...
1550
  #ifndef MODULE
d5383fcc4   Krzysztof Helt   pm3fb: mtrr suppo...
1551
1552
1553
  	char *option = NULL;
  
  	if (fb_get_options("pm3fb", &option))
f23a06f07   Krzysztof Helt   pm3fb: Preliminar...
1554
  		return -ENODEV;
d5383fcc4   Krzysztof Helt   pm3fb: mtrr suppo...
1555
  	pm3fb_setup(option);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1556
  #endif
d5383fcc4   Krzysztof Helt   pm3fb: mtrr suppo...
1557

f23a06f07   Krzysztof Helt   pm3fb: Preliminar...
1558
  	return pci_register_driver(&pm3fb_driver);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1559
  }
d5383fcc4   Krzysztof Helt   pm3fb: mtrr suppo...
1560
  #ifdef MODULE
f23a06f07   Krzysztof Helt   pm3fb: Preliminar...
1561
  static void __exit pm3fb_exit(void)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1562
  {
f23a06f07   Krzysztof Helt   pm3fb: Preliminar...
1563
  	pci_unregister_driver(&pm3fb_driver);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1564
  }
f23a06f07   Krzysztof Helt   pm3fb: Preliminar...
1565
  module_exit(pm3fb_exit);
d5383fcc4   Krzysztof Helt   pm3fb: mtrr suppo...
1566
1567
  #endif
  module_init(pm3fb_init);
4e65c6131   Krzysztof Helt   pm3fb: change opt...
1568
1569
  module_param(mode_option, charp, 0);
  MODULE_PARM_DESC(mode_option, "Initial video mode e.g. '648x480-8@60'");
d5383fcc4   Krzysztof Helt   pm3fb: mtrr suppo...
1570
1571
  module_param(noaccel, bool, 0);
  MODULE_PARM_DESC(noaccel, "Disable acceleration");
1d677a6df   Krzysztof Helt   pm3fb: hardware c...
1572
1573
1574
  module_param(hwcursor, int, 0644);
  MODULE_PARM_DESC(hwcursor, "Enable hardware cursor "
  			"(1=enable, 0=disable, default=1)");
d5383fcc4   Krzysztof Helt   pm3fb: mtrr suppo...
1575
1576
1577
1578
  #ifdef CONFIG_MTRR
  module_param(nomtrr, bool, 0);
  MODULE_PARM_DESC(nomtrr, "Disable MTRR support (0 or 1=disabled) (default=0)");
  #endif
f23a06f07   Krzysztof Helt   pm3fb: Preliminar...
1579

0ddf78491   Krzysztof Helt   pm3fb: improvemen...
1580
  MODULE_DESCRIPTION("Permedia3 framebuffer device driver");
f23a06f07   Krzysztof Helt   pm3fb: Preliminar...
1581
  MODULE_LICENSE("GPL");