1 /*
2  * Permedia2 framebuffer driver.
3  * Copyright (c) 1998-1999 Ilario Nardinocchi (nardinoc@CS.UniBO.IT)
4  * Copyright (c) 1999 Jakub Jelinek (jakub@redhat.com)
5  * Based on linux/drivers/video/skeletonfb.c by Geert Uytterhoeven.
6  * --------------------------------------------------------------------------
7  * $Id: pm2fb.c,v 1.163 1999/02/21 14:06:49 illo Exp $
8  * --------------------------------------------------------------------------
9  * TODO multiple boards support
10  * --------------------------------------------------------------------------
11  * This file is subject to the terms and conditions of the GNU General Public
12  * License.  See the file COPYING in the main directory of this archive
13  * for more details.
14  */
15 
16 #include <linux/config.h>
17 #include <linux/module.h>
18 #include <linux/kernel.h>
19 #include <linux/errno.h>
20 #include <linux/string.h>
21 #include <linux/mm.h>
22 #include <linux/tty.h>
23 #include <linux/slab.h>
24 #include <linux/vmalloc.h>
25 #include <linux/delay.h>
26 #include <linux/interrupt.h>
27 #include <linux/fb.h>
28 #include <linux/selection.h>
29 #include <linux/console.h>
30 #include <linux/init.h>
31 #include <linux/pci.h>
32 #include <asm/system.h>
33 #include <asm/io.h>
34 #include <asm/uaccess.h>
35 #include <video/fbcon.h>
36 #include <video/fbcon-cfb8.h>
37 #include <video/fbcon-cfb16.h>
38 #include <video/fbcon-cfb24.h>
39 #include <video/fbcon-cfb32.h>
40 #include "pm2fb.h"
41 #include "cvisionppc.h"
42 #ifdef __sparc__
43 #include <asm/pbm.h>
44 #include <asm/fbio.h>
45 #endif
46 
47 #if !defined(__LITTLE_ENDIAN) && !defined(__BIG_ENDIAN)
48 #error	"The endianness of the target host has not been defined."
49 #endif
50 
51 #if defined(__BIG_ENDIAN) && !defined(__sparc__)
52 #define PM2FB_BE_APERTURE
53 #endif
54 
55 /* Need to debug this some more */
56 #undef PM2FB_HW_CURSOR
57 
58 #if defined(CONFIG_FB_PM2_PCI) && !defined(CONFIG_PCI)
59 #undef CONFIG_FB_PM2_PCI
60 #warning "support for Permedia2 PCI boards with no generic PCI support!"
61 #endif
62 
63 #undef PM2FB_MASTER_DEBUG
64 #ifdef PM2FB_MASTER_DEBUG
65 #define DPRINTK(a,b...)	printk(KERN_DEBUG "pm2fb: %s: " a, __FUNCTION__ , ## b)
66 #else
67 #define DPRINTK(a,b...)
68 #endif
69 
70 #define PICOS2KHZ(a) (1000000000UL/(a))
71 #define KHZ2PICOS(a) (1000000000UL/(a))
72 
73 /*
74  * The _DEFINITIVE_ memory mapping/unmapping functions.
75  * This is due to the fact that they're changing soooo often...
76  */
77 #define MMAP(a,b)	ioremap((unsigned long )(a), b)
78 #define UNMAP(a,b)	iounmap(a)
79 
80 /*
81  * The _DEFINITIVE_ memory i/o barrier functions.
82  * This is due to the fact that they're changing soooo often...
83  */
84 #define DEFW()		wmb()
85 #define DEFR()		rmb()
86 #define DEFRW()		mb()
87 
88 #ifndef MIN
89 #define MIN(a,b) ((a)<(b)?(a):(b))
90 #endif
91 
92 #ifndef MAX
93 #define MAX(a,b) ((a)>(b)?(a):(b))
94 #endif
95 
96 struct pm2fb_par {
97 	u32 pixclock;		/* pixclock in KHz */
98 	u32 width;		/* width of virtual screen */
99 	u32 height;		/* height of virtual screen */
100 	u32 hsstart;		/* horiz. sync start */
101 	u32 hsend;		/* horiz. sync end */
102 	u32 hbend;		/* horiz. blank end (also gate end) */
103 	u32 htotal;		/* total width (w/ sync & blank) */
104 	u32 vsstart;		/* vert. sync start */
105 	u32 vsend;		/* vert. sync end */
106 	u32 vbend;		/* vert. blank end */
107 	u32 vtotal;		/* total height (w/ sync & blank) */
108 	u32 stride;		/* screen stride */
109 	u32 base;		/* screen base (xoffset+yoffset) */
110 	u32 depth;		/* screen depth (8, 16, 24 or 32) */
111 	u32 video;		/* video control (hsync,vsync) */
112 };
113 
114 #define OPTF_OLD_MEM		(1L<<0)
115 #define OPTF_YPAN		(1L<<1)
116 #define OPTF_VIRTUAL		(1L<<2)
117 #define OPTF_USER		(1L<<3)
118 static struct {
119 	char font[40];
120 	u32 flags;
121 	struct pm2fb_par user_mode;
122 } pm2fb_options =
123 #ifdef __sparc__
124 	/* For some reason Raptor is not happy with the low-end mode */
125 	{"\0", 0L, {31499,640,480,4,20,50,209,0,3,20,499,80,0,8,121}};
126 #else
127 	{"\0", 0L, {25174,640,480,4,28,40,199,9,11,45,524,80,0,8,121}};
128 #endif
129 
130 static char curblink __initdata = 1;
131 
132 static struct {
133 	char name[16];
134 	struct pm2fb_par par;
135 } user_mode[] __initdata = {
136 	{"640x480-60",
137 		{25174,640,480,4,28,40,199,9,11,45,524,80,0,8,121}},
138 	{"640x480-72",
139 		{31199,640,480,6,16,48,207,8,10,39,518,80,0,8,121}},
140 	{"640x480-75",
141 		{31499,640,480,4,20,50,209,0,3,20,499,80,0,8,121}},
142 	{"640x480-90",
143 		{39909,640,480,8,18,48,207,24,38,53,532,80,0,8,121}},
144 	{"640x480-100",
145 		{44899,640,480,8,40,52,211,21,33,51,530,80,0,8,121}},
146 	{"800x600-56",
147 		{35999,800,600,6,24,56,255,0,2,25,624,100,0,8,41}},
148 	{"800x600-60",
149 		{40000,800,600,10,42,64,263,0,4,28,627,100,0,8,41}},
150 	{"800x600-70",
151 		{44899,800,600,6,42,52,251,8,20,36,635,100,0,8,105}},
152 	{"800x600-72",
153 		{50000,800,600,14,44,60,259,36,42,66,665,100,0,8,41}},
154 	{"800x600-75",
155 		{49497,800,600,4,24,64,263,0,3,25,624,100,0,8,41}},
156 	{"800x600-90",
157 		{56637,800,600,2,18,48,247,7,18,35,634,100,0,8,41}},
158 	{"800x600-100",
159 		{67499,800,600,0,16,70,269,6,10,25,624,100,0,8,41}},
160 	{"1024x768-60",
161 		{64998,1024,768,6,40,80,335,2,8,38,805,128,0,8,121}},
162 	{"1024x768-70",
163 		{74996,1024,768,6,40,76,331,2,8,38,805,128,0,8,121}},
164 	{"1024x768-72",
165 		{74996,1024,768,6,40,66,321,2,8,38,805,128,0,8,121}},
166 	{"1024x768-75",
167 		{78932,1024,768,4,28,72,327,0,3,32,799,128,0,8,41}},
168 	{"1024x768-90",
169 		{100000,1024,768,0,24,72,327,20,35,77,844,128,0,8,121}},
170 	{"1024x768-100",
171 		{109998,1024,768,0,22,92,347,0,7,24,791,128,0,8,121}},
172 	{"1024x768-illo",
173 		{120322,1024,768,12,48,120,375,3,7,32,799,128,0,8,41}},
174 	{"1152x864-60",
175 		{80000,1152,864,16,44,76,363,5,10,52,915,144,0,8,41}},
176 	{"1152x864-70",
177 		{100000,1152,864,10,48,90,377,12,23,81,944,144,0,8,41}},
178 	{"1152x864-75",
179 		{109998,1152,864,6,42,78,365,44,52,138,1001,144,0,8,41}},
180 	{"1152x864-80",
181 		{109998,1152,864,4,32,72,359,29,36,94,957,144,0,8,41}},
182 	{"1280x1024-60",
183 		{107991,1280,1024,12,40,102,421,0,3,42,1065,160,0,8,41}},
184 	{"1280x1024-70",
185 		{125992,1280,1024,20,48,102,421,0,5,42,1065,160,0,8,41}},
186 	{"1280x1024-74",
187 		{134989,1280,1024,8,44,108,427,0,29,40,1063,160,0,8,41}},
188 	{"1280x1024-75",
189 		{134989,1280,1024,4,40,102,421,0,3,42,1065,160,0,8,41}},
190 	{"1600x1200-60",
191 		{155981,1600,1200,8,48,112,511,9,17,70,1269,200,0,8,121}},
192 	{"1600x1200-66",
193 		{171998,1600,1200,10,44,120,519,2,5,53,1252,200,0,8,121}},
194 	{"1600x1200-76",
195 		{197980,1600,1200,10,44,120,519,2,7,50,1249,200,0,8,121}},
196 	{"\0", },
197 };
198 
199 #ifdef CONFIG_FB_PM2_PCI
200 struct pm2pci_par {
201 	u32 mem_config;
202 	u32 mem_control;
203 	u32 boot_address;
204 	struct pci_dev* dev;
205 };
206 #endif
207 
208 #define DEFAULT_CURSOR_BLINK_RATE       (20)
209 #define CURSOR_DRAW_DELAY               (2)
210 
211 struct pm2_cursor {
212     int	enable;
213     int on;
214     int vbl_cnt;
215     int blink_rate;
216     struct {
217         u16 x, y;
218     } pos, hot, size;
219     u8 color[6];
220     u8 bits[8][64];
221     u8 mask[8][64];
222     struct timer_list *timer;
223 };
224 
225 static const char permedia2_name[16]="Permedia2";
226 
227 static struct pm2fb_info {
228 	struct fb_info_gen gen;
229 	int board;			/* Permedia2 board index (see
230 					   board_table[] below) */
231 	pm2type_t type;
232 	struct {
233 		unsigned long  fb_base;	/* physical framebuffer memory base */
234 		u32 fb_size;		/* framebuffer memory size */
235 		unsigned long  rg_base;	/* physical register memory base */
236 		unsigned long  p_fb;	/* physical address of frame buffer */
237 		unsigned char* v_fb;	/* virtual address of frame buffer */
238 		unsigned long  p_regs;	/* physical address of registers
239 					   region, must be rg_base or
240 					   rg_base+PM2_REGS_SIZE depending on
241 					   the host endianness */
242 		unsigned char* v_regs;	/* virtual address of p_regs */
243 	} regions;
244 	union {				/* here, the per-board par structs */
245 #ifdef CONFIG_FB_PM2_CVPPC
246 		struct cvppc_par cvppc;	/* CVisionPPC data */
247 #endif
248 #ifdef CONFIG_FB_PM2_PCI
249 		struct pm2pci_par pci;	/* Permedia2 PCI boards data */
250 #endif
251 	} board_par;
252 	struct pm2fb_par current_par;	/* displayed screen */
253 	int current_par_valid;
254 	u32 memclock;			/* memclock (set by the per-board
255 					   		init routine) */
256 	struct display disp;
257 	struct {
258 		u8 transp;
259 		u8 red;
260 		u8 green;
261 		u8 blue;
262 	} palette[256];
263 	union {
264 #ifdef FBCON_HAS_CFB16
265 		u16 cmap16[16];
266 #endif
267 #ifdef FBCON_HAS_CFB24
268 		u32 cmap24[16];
269 #endif
270 #ifdef FBCON_HAS_CFB32
271 		u32 cmap32[16];
272 #endif
273 	} cmap;
274 	struct pm2_cursor *cursor;
275 } fb_info;
276 
277 #ifdef CONFIG_FB_PM2_CVPPC
278 static int cvppc_detect(struct pm2fb_info*);
279 static void cvppc_init(struct pm2fb_info*);
280 #endif
281 
282 #ifdef CONFIG_FB_PM2_PCI
283 static int pm2pci_detect(struct pm2fb_info*);
284 static void pm2pci_init(struct pm2fb_info*);
285 #endif
286 
287 #ifdef PM2FB_HW_CURSOR
288 static void pm2fb_cursor(struct display *p, int mode, int x, int y);
289 static int pm2fb_set_font(struct display *d, int width, int height);
290 static struct pm2_cursor *pm2_init_cursor(struct pm2fb_info *fb);
291 static void pm2v_set_cursor_color(struct pm2fb_info *fb, u8 *red, u8 *green, u8 *blue);
292 static void pm2v_set_cursor_shape(struct pm2fb_info *fb);
293 static u8 cursor_color_map[2] = { 0, 0xff };
294 #else
295 #define pm2fb_cursor NULL
296 #define pm2fb_set_font NULL
297 #endif
298 
299 /*
300  * Table of the supported Permedia2 based boards.
301  * Three hooks are defined for each board:
302  * detect(): should return 1 if the related board has been detected, 0
303  *           otherwise. It should also fill the fields 'regions.fb_base',
304  *           'regions.fb_size', 'regions.rg_base' and 'memclock' in the
305  *           passed pm2fb_info structure.
306  * init(): called immediately after the reset of the Permedia2 chip.
307  *         It should reset the memory controller if needed (the MClk
308  *         is set shortly afterwards by the caller).
309  * cleanup(): called after the driver has been unregistered.
310  *
311  * the init and cleanup pointers can be NULL.
312  */
313 static const struct {
314 	int (*detect)(struct pm2fb_info*);
315 	void (*init)(struct pm2fb_info*);
316 	void (*cleanup)(struct pm2fb_info*);
317 	char name[32];
318 } board_table[] = {
319 #ifdef CONFIG_FB_PM2_PCI
320 	{ pm2pci_detect, pm2pci_init, NULL, "Permedia2 PCI board" },
321 #endif
322 #ifdef CONFIG_FB_PM2_CVPPC
323 	{ cvppc_detect, cvppc_init, NULL, "CVisionPPC/BVisionPPC" },
324 #endif
325 	{ NULL, }
326 };
327 
328 /*
329  * partial products for the supported horizontal resolutions.
330  */
331 #define PACKPP(p0,p1,p2)	(((p2)<<6)|((p1)<<3)|(p0))
332 static const struct {
333 	u16 width;
334 	u16 pp;
335 } pp_table[] = {
336 	{ 32,	PACKPP(1, 0, 0) }, { 64,	PACKPP(1, 1, 0) },
337 	{ 96,	PACKPP(1, 1, 1) }, { 128,	PACKPP(2, 1, 1) },
338 	{ 160,	PACKPP(2, 2, 1) }, { 192,	PACKPP(2, 2, 2) },
339 	{ 224,	PACKPP(3, 2, 1) }, { 256,	PACKPP(3, 2, 2) },
340 	{ 288,	PACKPP(3, 3, 1) }, { 320,	PACKPP(3, 3, 2) },
341 	{ 384,	PACKPP(3, 3, 3) }, { 416,	PACKPP(4, 3, 1) },
342 	{ 448,	PACKPP(4, 3, 2) }, { 512,	PACKPP(4, 3, 3) },
343 	{ 544,	PACKPP(4, 4, 1) }, { 576,	PACKPP(4, 4, 2) },
344 	{ 640,	PACKPP(4, 4, 3) }, { 768,	PACKPP(4, 4, 4) },
345 	{ 800,	PACKPP(5, 4, 1) }, { 832,	PACKPP(5, 4, 2) },
346 	{ 896,	PACKPP(5, 4, 3) }, { 1024,	PACKPP(5, 4, 4) },
347 	{ 1056,	PACKPP(5, 5, 1) }, { 1088,	PACKPP(5, 5, 2) },
348 	{ 1152,	PACKPP(5, 5, 3) }, { 1280,	PACKPP(5, 5, 4) },
349 	{ 1536,	PACKPP(5, 5, 5) }, { 1568,	PACKPP(6, 5, 1) },
350 	{ 1600,	PACKPP(6, 5, 2) }, { 1664,	PACKPP(6, 5, 3) },
351 	{ 1792,	PACKPP(6, 5, 4) }, { 2048,	PACKPP(6, 5, 5) },
352 	{ 0,	0 } };
353 
354 static void pm2fb_detect(void);
355 static int pm2fb_encode_fix(struct fb_fix_screeninfo* fix,
356 				const void* par, struct fb_info_gen* info);
357 static int pm2fb_decode_var(const struct fb_var_screeninfo* var,
358 					void* par, struct fb_info_gen* info);
359 static int pm2fb_encode_var(struct fb_var_screeninfo* var,
360 				const void* par, struct fb_info_gen* info);
361 static void pm2fb_get_par(void* par, struct fb_info_gen* info);
362 static void pm2fb_set_par(const void* par, struct fb_info_gen* info);
363 static int pm2fb_getcolreg(unsigned regno,
364 			unsigned* red, unsigned* green, unsigned* blue,
365 				unsigned* transp, struct fb_info* info);
366 static int pm2fb_setcolreg(unsigned regno,
367 			unsigned red, unsigned green, unsigned blue,
368 				unsigned transp, struct fb_info* info);
369 static int pm2fb_blank(int blank_mode, struct fb_info_gen* info);
370 static int pm2fb_pan_display(const struct fb_var_screeninfo* var,
371 					struct fb_info_gen* info);
372 static void pm2fb_set_disp(const void* par, struct display* disp,
373 						struct fb_info_gen* info);
374 
375 static struct fbgen_hwswitch pm2fb_hwswitch={
376 	pm2fb_detect, pm2fb_encode_fix, pm2fb_decode_var,
377 	pm2fb_encode_var, pm2fb_get_par, pm2fb_set_par,
378 	pm2fb_getcolreg, pm2fb_setcolreg, pm2fb_pan_display,
379 	pm2fb_blank, pm2fb_set_disp
380 };
381 
382 static struct fb_ops pm2fb_ops={
383 	owner:		THIS_MODULE,
384 	fb_get_fix:	fbgen_get_fix,
385 	fb_get_var:	fbgen_get_var,
386 	fb_set_var:	fbgen_set_var,
387 	fb_get_cmap:	fbgen_get_cmap,
388 	fb_set_cmap:	fbgen_set_cmap,
389 	fb_pan_display:	fbgen_pan_display,
390 };
391 
392 /***************************************************************************
393  * Begin of Permedia2 specific functions
394  ***************************************************************************/
395 
RD32(unsigned char * base,s32 off)396 inline static u32 RD32(unsigned char* base, s32 off) {
397 
398 	return readl(base+off);
399 }
400 
WR32(unsigned char * base,s32 off,u32 v)401 inline static void WR32(unsigned char* base, s32 off, u32 v) {
402 
403 	writel(v, base+off);
404 }
405 
pm2_RD(struct pm2fb_info * p,s32 off)406 inline static u32 pm2_RD(struct pm2fb_info* p, s32 off) {
407 
408 	return RD32(p->regions.v_regs, off);
409 }
410 
pm2_WR(struct pm2fb_info * p,s32 off,u32 v)411 inline static void pm2_WR(struct pm2fb_info* p, s32 off, u32 v) {
412 
413 	WR32(p->regions.v_regs, off, v);
414 }
415 
pm2_RDAC_RD(struct pm2fb_info * p,s32 idx)416 inline static u32 pm2_RDAC_RD(struct pm2fb_info* p, s32 idx) {
417 
418 	int index = PM2R_RD_INDEXED_DATA;
419 	switch (p->type) {
420 	case PM2_TYPE_PERMEDIA2:
421 		pm2_WR(p, PM2R_RD_PALETTE_WRITE_ADDRESS, idx);
422 		break;
423 	case PM2_TYPE_PERMEDIA2V:
424 		pm2_WR(p, PM2VR_RD_INDEX_LOW, idx & 0xff);
425 		index = PM2VR_RD_INDEXED_DATA;
426 		break;
427 	}
428 	DEFRW();
429 	return pm2_RD(p, index);
430 }
431 
pm2_RDAC_WR(struct pm2fb_info * p,s32 idx,u32 v)432 inline static void pm2_RDAC_WR(struct pm2fb_info* p, s32 idx,
433 						u32 v) {
434 
435 	int index = PM2R_RD_INDEXED_DATA;
436 	switch (p->type) {
437 	case PM2_TYPE_PERMEDIA2:
438 		pm2_WR(p, PM2R_RD_PALETTE_WRITE_ADDRESS, idx);
439 		break;
440 	case PM2_TYPE_PERMEDIA2V:
441 		pm2_WR(p, PM2VR_RD_INDEX_LOW, idx & 0xff);
442 		index = PM2VR_RD_INDEXED_DATA;
443 		break;
444 	}
445 	DEFRW();
446 	pm2_WR(p, index, v);
447 }
448 
pm2v_RDAC_RD(struct pm2fb_info * p,s32 idx)449 inline static u32 pm2v_RDAC_RD(struct pm2fb_info* p, s32 idx) {
450 
451 	pm2_WR(p, PM2VR_RD_INDEX_LOW, idx & 0xff);
452 	DEFRW();
453 	return pm2_RD(p, PM2VR_RD_INDEXED_DATA);
454 }
455 
pm2v_RDAC_WR(struct pm2fb_info * p,s32 idx,u32 v)456 inline static void pm2v_RDAC_WR(struct pm2fb_info* p, s32 idx,
457 						u32 v) {
458 
459 	pm2_WR(p, PM2VR_RD_INDEX_LOW, idx & 0xff);
460 	DEFRW();
461 	pm2_WR(p, PM2VR_RD_INDEXED_DATA, v);
462 }
463 
464 #ifdef CONFIG_FB_PM2_FIFO_DISCONNECT
465 #define WAIT_FIFO(p,a)
466 #else
WAIT_FIFO(struct pm2fb_info * p,u32 a)467 inline static void WAIT_FIFO(struct pm2fb_info* p, u32 a) {
468 
469 	while(pm2_RD(p, PM2R_IN_FIFO_SPACE)<a);
470 	DEFRW();
471 }
472 #endif
473 
partprod(u32 xres)474 static u32 partprod(u32 xres) {
475 	int i;
476 
477 	for (i=0; pp_table[i].width && pp_table[i].width!=xres; i++);
478 	if (!pp_table[i].width)
479 		DPRINTK("invalid width %u\n", xres);
480 	return pp_table[i].pp;
481 }
482 
to3264(u32 timing,int bpp,int is64)483 static u32 to3264(u32 timing, int bpp, int is64) {
484 
485 	switch (bpp) {
486 		case 8:
487 			timing=timing>>(2+is64);
488 			break;
489 		case 16:
490 			timing=timing>>(1+is64);
491 			break;
492 		case 24:
493 			timing=(timing*3)>>(2+is64);
494 			break;
495 		case 32:
496 			if (is64)
497 				timing=timing>>1;
498 			break;
499 	}
500 	return timing;
501 }
502 
from3264(u32 timing,int bpp,int is64)503 static u32 from3264(u32 timing, int bpp, int is64) {
504 
505 	switch (bpp) {
506 		case 8:
507 			timing=timing<<(2+is64);
508 			break;
509 		case 16:
510 			timing=timing<<(1+is64);
511 			break;
512 		case 24:
513 			timing=(timing<<(2+is64))/3;
514 			break;
515 		case 32:
516 			if (is64)
517 				timing=timing<<1;
518 			break;
519 	}
520 	return timing;
521 }
522 
pm2_mnp(u32 clk,unsigned char * mm,unsigned char * nn,unsigned char * pp)523 static void pm2_mnp(u32 clk, unsigned char* mm, unsigned char* nn,
524 		unsigned char* pp) {
525 	unsigned char m;
526 	unsigned char n;
527 	unsigned char p;
528 	u32 f;
529 	s32 curr;
530 	s32 delta=100000;
531 
532 	*mm=*nn=*pp=0;
533 	for (n=2; n<15; n++) {
534 		for (m=2; m; m++) {
535 			f=PM2_REFERENCE_CLOCK*m/n;
536 			if (f>=150000 && f<=300000) {
537 				for (p=0; p<5; p++, f>>=1) {
538 					curr=clk>f?clk-f:f-clk;
539 					if (curr<delta) {
540 						delta=curr;
541 						*mm=m;
542 						*nn=n;
543 						*pp=p;
544 					}
545 				}
546 			}
547 		}
548 	}
549 }
550 
pm2v_mnp(u32 clk,unsigned char * mm,unsigned char * nn,unsigned char * pp)551 static void pm2v_mnp(u32 clk, unsigned char* mm, unsigned char* nn,
552 		unsigned char* pp) {
553 	unsigned char m;
554 	unsigned char n;
555 	unsigned char p;
556 	u32 f;
557 	s32 delta=1000;
558 
559 	*mm=*nn=*pp=0;
560 	for (n=1; n; n++) {
561 		for (m=1; m; m++) {
562 			for (p=0; p<2; p++) {
563 				f=PM2_REFERENCE_CLOCK*n/(m * (1<<(p+1)));
564 				if (clk>f-delta && clk<f+delta) {
565 					delta=clk>f?clk-f:f-clk;
566 					*mm=m;
567 					*nn=n;
568 					*pp=p;
569 				}
570 			}
571 		}
572 	}
573 }
574 
wait_pm2(struct pm2fb_info * i)575 static void wait_pm2(struct pm2fb_info* i) {
576 
577 	WAIT_FIFO(i, 1);
578 	pm2_WR(i, PM2R_SYNC, 0);
579 	DEFRW();
580 	do {
581 		while (pm2_RD(i, PM2R_OUT_FIFO_WORDS)==0);
582 		DEFR();
583 	} while (pm2_RD(i, PM2R_OUT_FIFO)!=PM2TAG(PM2R_SYNC));
584 }
585 
pm2_set_memclock(struct pm2fb_info * info,u32 clk)586 static void pm2_set_memclock(struct pm2fb_info* info, u32 clk) {
587 	int i;
588 	unsigned char m, n, p;
589 
590 	pm2_mnp(clk, &m, &n, &p);
591 	WAIT_FIFO(info, 10);
592 	pm2_RDAC_WR(info, PM2I_RD_MEMORY_CLOCK_3, 6);
593 	DEFW();
594 	pm2_RDAC_WR(info, PM2I_RD_MEMORY_CLOCK_1, m);
595 	pm2_RDAC_WR(info, PM2I_RD_MEMORY_CLOCK_2, n);
596 	DEFW();
597 	pm2_RDAC_WR(info, PM2I_RD_MEMORY_CLOCK_3, 8|p);
598 	DEFW();
599 	pm2_RDAC_RD(info, PM2I_RD_MEMORY_CLOCK_STATUS);
600 	DEFR();
601 	for (i=256; i &&
602 		!(pm2_RD(info, PM2R_RD_INDEXED_DATA)&PM2F_PLL_LOCKED); i--);
603 }
604 
pm2_set_pixclock(struct pm2fb_info * info,u32 clk)605 static void pm2_set_pixclock(struct pm2fb_info* info, u32 clk) {
606 	int i;
607 	unsigned char m, n, p;
608 
609 	switch (info->type) {
610 	case PM2_TYPE_PERMEDIA2:
611 		pm2_mnp(clk, &m, &n, &p);
612 		WAIT_FIFO(info, 10);
613 		pm2_RDAC_WR(info, PM2I_RD_PIXEL_CLOCK_A3, 0);
614 		DEFW();
615 		pm2_RDAC_WR(info, PM2I_RD_PIXEL_CLOCK_A1, m);
616 		pm2_RDAC_WR(info, PM2I_RD_PIXEL_CLOCK_A2, n);
617 		DEFW();
618 		pm2_RDAC_WR(info, PM2I_RD_PIXEL_CLOCK_A3, 8|p);
619 		DEFW();
620 		pm2_RDAC_RD(info, PM2I_RD_PIXEL_CLOCK_STATUS);
621 		DEFR();
622 		for (i=256; i &&
623 		     !(pm2_RD(info, PM2R_RD_INDEXED_DATA)&PM2F_PLL_LOCKED); i--);
624 		break;
625 	case PM2_TYPE_PERMEDIA2V:
626 		pm2v_mnp(clk/2, &m, &n, &p);
627 		WAIT_FIFO(info, 8);
628 		pm2_WR(info, PM2VR_RD_INDEX_HIGH, PM2VI_RD_CLK0_PRESCALE >> 8);
629 		pm2v_RDAC_WR(info, PM2VI_RD_CLK0_PRESCALE, m);
630 		pm2v_RDAC_WR(info, PM2VI_RD_CLK0_FEEDBACK, n);
631 		pm2v_RDAC_WR(info, PM2VI_RD_CLK0_POSTSCALE, p);
632 		pm2_WR(info, PM2VR_RD_INDEX_HIGH, 0);
633 		break;
634 	}
635 }
636 
clear_palette(struct pm2fb_info * p)637 static void clear_palette(struct pm2fb_info* p) {
638 	int i=256;
639 
640 	WAIT_FIFO(p, 1);
641 	pm2_WR(p, PM2R_RD_PALETTE_WRITE_ADDRESS, 0);
642 	DEFW();
643 	while (i--) {
644 		WAIT_FIFO(p, 3);
645 		pm2_WR(p, PM2R_RD_PALETTE_DATA, 0);
646 		pm2_WR(p, PM2R_RD_PALETTE_DATA, 0);
647 		pm2_WR(p, PM2R_RD_PALETTE_DATA, 0);
648 	}
649 }
650 
set_color(struct pm2fb_info * p,unsigned char regno,unsigned char r,unsigned char g,unsigned char b)651 static void set_color(struct pm2fb_info* p, unsigned char regno,
652 			unsigned char r, unsigned char g, unsigned char b) {
653 
654 	WAIT_FIFO(p, 4);
655 	pm2_WR(p, PM2R_RD_PALETTE_WRITE_ADDRESS, regno);
656 	DEFW();
657 	pm2_WR(p, PM2R_RD_PALETTE_DATA, r);
658 	DEFW();
659 	pm2_WR(p, PM2R_RD_PALETTE_DATA, g);
660 	DEFW();
661 	pm2_WR(p, PM2R_RD_PALETTE_DATA, b);
662 }
663 
set_aperture(struct pm2fb_info * i,struct pm2fb_par * p)664 static void set_aperture(struct pm2fb_info* i, struct pm2fb_par* p) {
665 
666 	WAIT_FIFO(i, 2);
667 #ifdef __LITTLE_ENDIAN
668 	pm2_WR(i, PM2R_APERTURE_ONE, 0);
669 	pm2_WR(i, PM2R_APERTURE_TWO, 0);
670 #else
671 	switch (p->depth) {
672 		case 8:
673 		case 24:
674 			pm2_WR(i, PM2R_APERTURE_ONE, 0);
675 			pm2_WR(i, PM2R_APERTURE_TWO, 1);
676 			break;
677 		case 16:
678 			pm2_WR(i, PM2R_APERTURE_ONE, 2);
679 			pm2_WR(i, PM2R_APERTURE_TWO, 1);
680 			break;
681 		case 32:
682 			pm2_WR(i, PM2R_APERTURE_ONE, 1);
683 			pm2_WR(i, PM2R_APERTURE_TWO, 1);
684 			break;
685 	}
686 #endif
687 }
688 
set_screen(struct pm2fb_info * i,struct pm2fb_par * p)689 static void set_screen(struct pm2fb_info* i, struct pm2fb_par* p) {
690 	u32 clrmode=0;
691 	u32 txtmap=0;
692 	u32 pixsize=0;
693 	u32 clrformat=0;
694 	u32 xres;
695 	u32 video, tmp;
696 
697 	if (i->type == PM2_TYPE_PERMEDIA2V) {
698 		WAIT_FIFO(i, 1);
699 		pm2_WR(i, PM2VR_RD_INDEX_HIGH, 0);
700 	}
701 	xres=(p->width+31)&~31;
702 	set_aperture(i, p);
703 	DEFRW();
704 	WAIT_FIFO(i, 27);
705 	pm2_RDAC_WR(i, PM2I_RD_COLOR_KEY_CONTROL, p->depth==8?0:
706 						PM2F_COLOR_KEY_TEST_OFF);
707 	switch (p->depth) {
708 		case 8:
709 			pm2_WR(i, PM2R_FB_READ_PIXEL, 0);
710 			clrformat=0x0e;
711 			break;
712 		case 16:
713 			pm2_WR(i, PM2R_FB_READ_PIXEL, 1);
714 			clrmode=PM2F_RD_TRUECOLOR|0x06;
715 			txtmap=PM2F_TEXTEL_SIZE_16;
716 			pixsize=1;
717 			clrformat=0x70;
718 			break;
719 		case 32:
720 			pm2_WR(i, PM2R_FB_READ_PIXEL, 2);
721 			clrmode=PM2F_RD_TRUECOLOR|0x08;
722 			txtmap=PM2F_TEXTEL_SIZE_32;
723 			pixsize=2;
724 			clrformat=0x20;
725 			break;
726 		case 24:
727 			pm2_WR(i, PM2R_FB_READ_PIXEL, 4);
728 			clrmode=PM2F_RD_TRUECOLOR|0x09;
729 			txtmap=PM2F_TEXTEL_SIZE_24;
730 			pixsize=4;
731 			clrformat=0x20;
732 			break;
733 	}
734 	pm2_WR(i, PM2R_SCREEN_SIZE, (p->height<<16)|p->width);
735 	pm2_WR(i, PM2R_SCISSOR_MODE, PM2F_SCREEN_SCISSOR_ENABLE);
736 	pm2_WR(i, PM2R_FB_WRITE_MODE, PM2F_FB_WRITE_ENABLE);
737 	pm2_WR(i, PM2R_FB_READ_MODE, partprod(xres));
738 	pm2_WR(i, PM2R_LB_READ_MODE, partprod(xres));
739 	pm2_WR(i, PM2R_TEXTURE_MAP_FORMAT, txtmap|partprod(xres));
740 	pm2_WR(i, PM2R_H_TOTAL, p->htotal);
741 	pm2_WR(i, PM2R_HS_START, p->hsstart);
742 	pm2_WR(i, PM2R_HS_END, p->hsend);
743 	pm2_WR(i, PM2R_HG_END, p->hbend);
744 	pm2_WR(i, PM2R_HB_END, p->hbend);
745 	pm2_WR(i, PM2R_V_TOTAL, p->vtotal);
746 	pm2_WR(i, PM2R_VS_START, p->vsstart);
747 	pm2_WR(i, PM2R_VS_END, p->vsend);
748 	pm2_WR(i, PM2R_VB_END, p->vbend);
749 	pm2_WR(i, PM2R_SCREEN_STRIDE, p->stride);
750 	DEFW();
751 	pm2_WR(i, PM2R_SCREEN_BASE, p->base);
752 	/* HW cursor needs /VSYNC for recognizing vert retrace */
753 	video=p->video & ~(PM2F_HSYNC_ACT_LOW|PM2F_VSYNC_ACT_LOW);
754 	video|=PM2F_HSYNC_ACT_HIGH|PM2F_VSYNC_ACT_HIGH;
755 	switch (i->type) {
756 	case PM2_TYPE_PERMEDIA2:
757 		tmp = PM2F_RD_PALETTE_WIDTH_8;
758 		pm2_RDAC_WR(i, PM2I_RD_COLOR_MODE, PM2F_RD_COLOR_MODE_RGB|
759 						   PM2F_RD_GUI_ACTIVE|clrmode);
760 		if ((p->video & PM2F_HSYNC_ACT_LOW) == PM2F_HSYNC_ACT_LOW)
761 			tmp |= 4; /* invert hsync */
762 		if ((p->video & PM2F_HSYNC_ACT_LOW) == PM2F_HSYNC_ACT_LOW)
763 			tmp |= 8; /* invert vsync */
764 		pm2_RDAC_WR(i, PM2I_RD_MISC_CONTROL, tmp);
765 		break;
766 	case PM2_TYPE_PERMEDIA2V:
767 		tmp = 0;
768 		pm2v_RDAC_WR(i, PM2VI_RD_PIXEL_SIZE, pixsize);
769 		pm2v_RDAC_WR(i, PM2VI_RD_COLOR_FORMAT, clrformat);
770 		if ((p->video & PM2F_HSYNC_ACT_LOW) == PM2F_HSYNC_ACT_LOW)
771 			tmp |= 1; /* invert hsync */
772 		if ((p->video & PM2F_HSYNC_ACT_LOW) == PM2F_HSYNC_ACT_LOW)
773 			tmp |= 4; /* invert vsync */
774 		pm2v_RDAC_WR(i, PM2VI_RD_SYNC_CONTROL, tmp);
775 		pm2v_RDAC_WR(i, PM2VI_RD_MISC_CONTROL, 1);
776 		break;
777 	}
778 	pm2_WR(i, PM2R_VIDEO_CONTROL, video);
779 	pm2_set_pixclock(i, p->pixclock);
780 };
781 
782 /*
783  * copy with packed pixels (8/16bpp only).
784  */
pm2fb_pp_copy(struct pm2fb_info * i,s32 xsrc,s32 ysrc,s32 x,s32 y,s32 w,s32 h)785 static void pm2fb_pp_copy(struct pm2fb_info* i, s32 xsrc, s32 ysrc,
786 					s32 x, s32 y, s32 w, s32 h) {
787 	s32 scale=i->current_par.depth==8?2:1;
788 	s32 offset;
789 
790 	if (!w || !h)
791 		return;
792 	WAIT_FIFO(i, 7);
793 	pm2_WR(i, PM2R_CONFIG,	PM2F_CONFIG_FB_WRITE_ENABLE|
794 				PM2F_CONFIG_FB_PACKED_DATA|
795 				PM2F_CONFIG_FB_READ_SOURCE_ENABLE);
796 	pm2_WR(i, PM2R_FB_PIXEL_OFFSET, 0);
797 	pm2_WR(i, PM2R_FB_SOURCE_DELTA,	((ysrc-y)&0xfff)<<16|
798 						((xsrc-x)&0xfff));
799 	offset=(x&0x3)-(xsrc&0x3);
800 	pm2_WR(i, PM2R_RECTANGLE_ORIGIN, (y<<16)|(x>>scale));
801 	pm2_WR(i, PM2R_RECTANGLE_SIZE, (h<<16)|((w+7)>>scale));
802 	pm2_WR(i, PM2R_PACKED_DATA_LIMITS, (offset<<29)|(x<<16)|(x+w));
803 	DEFW();
804 	pm2_WR(i, PM2R_RENDER,	PM2F_RENDER_RECTANGLE|
805 				(x<xsrc?PM2F_INCREASE_X:0)|
806 				(y<ysrc?PM2F_INCREASE_Y:0));
807 	wait_pm2(i);
808 }
809 
810 /*
811  * block operation. copy=0: rectangle fill, copy=1: rectangle copy.
812  */
pm2fb_block_op(struct pm2fb_info * i,int copy,s32 xsrc,s32 ysrc,s32 x,s32 y,s32 w,s32 h,u32 color)813 static void pm2fb_block_op(struct pm2fb_info* i, int copy,
814 					s32 xsrc, s32 ysrc,
815 					s32 x, s32 y, s32 w, s32 h,
816 					u32 color) {
817 
818 	if (!w || !h)
819 		return;
820 	WAIT_FIFO(i, 6);
821 	pm2_WR(i, PM2R_CONFIG,	PM2F_CONFIG_FB_WRITE_ENABLE|
822 				PM2F_CONFIG_FB_READ_SOURCE_ENABLE);
823 	pm2_WR(i, PM2R_FB_PIXEL_OFFSET, 0);
824 	if (copy)
825 		pm2_WR(i, PM2R_FB_SOURCE_DELTA,	((ysrc-y)&0xfff)<<16|
826 							((xsrc-x)&0xfff));
827 	else
828 		pm2_WR(i, PM2R_FB_BLOCK_COLOR, color);
829 	pm2_WR(i, PM2R_RECTANGLE_ORIGIN, (y<<16)|x);
830 	pm2_WR(i, PM2R_RECTANGLE_SIZE, (h<<16)|w);
831 	DEFW();
832 	pm2_WR(i, PM2R_RENDER,	PM2F_RENDER_RECTANGLE|
833 				(x<xsrc?PM2F_INCREASE_X:0)|
834 				(y<ysrc?PM2F_INCREASE_Y:0)|
835 				(copy?0:PM2F_RENDER_FASTFILL));
836 	wait_pm2(i);
837 }
838 
839 /***************************************************************************
840  * Begin of generic initialization functions
841  ***************************************************************************/
842 
pm2fb_reset(struct pm2fb_info * p)843 static void pm2fb_reset(struct pm2fb_info* p) {
844 
845 	if (p->type == PM2_TYPE_PERMEDIA2V)
846 		pm2_WR(p, PM2VR_RD_INDEX_HIGH, 0);
847 	pm2_WR(p, PM2R_RESET_STATUS, 0);
848 	DEFRW();
849 	while (pm2_RD(p, PM2R_RESET_STATUS)&PM2F_BEING_RESET);
850 	DEFRW();
851 #ifdef CONFIG_FB_PM2_FIFO_DISCONNECT
852 	DPRINTK("FIFO disconnect enabled\n");
853 	pm2_WR(p, PM2R_FIFO_DISCON, 1);
854 	DEFRW();
855 #endif
856 	if (board_table[p->board].init)
857 		board_table[p->board].init(p);
858 	WAIT_FIFO(p, 48);
859 	pm2_WR(p, PM2R_CHIP_CONFIG, pm2_RD(p, PM2R_CHIP_CONFIG)&
860 					~(PM2F_VGA_ENABLE|PM2F_VGA_FIXED));
861 	pm2_WR(p, PM2R_BYPASS_WRITE_MASK, ~(0L));
862 	pm2_WR(p, PM2R_FRAMEBUFFER_WRITE_MASK, ~(0L));
863 	pm2_WR(p, PM2R_FIFO_CONTROL, 0);
864 	pm2_WR(p, PM2R_FILTER_MODE, PM2F_SYNCHRONIZATION);
865 	pm2_WR(p, PM2R_APERTURE_ONE, 0);
866 	pm2_WR(p, PM2R_APERTURE_TWO, 0);
867 	pm2_WR(p, PM2R_LB_READ_FORMAT, 0);
868 	pm2_WR(p, PM2R_LB_WRITE_FORMAT, 0);
869 	pm2_WR(p, PM2R_LB_READ_MODE, 0);
870 	pm2_WR(p, PM2R_LB_SOURCE_OFFSET, 0);
871 	pm2_WR(p, PM2R_FB_SOURCE_OFFSET, 0);
872 	pm2_WR(p, PM2R_FB_PIXEL_OFFSET, 0);
873 	pm2_WR(p, PM2R_WINDOW_ORIGIN, 0);
874 	pm2_WR(p, PM2R_FB_WINDOW_BASE, 0);
875 	pm2_WR(p, PM2R_LB_WINDOW_BASE, 0);
876 	pm2_WR(p, PM2R_FB_SOFT_WRITE_MASK, ~(0L));
877 	pm2_WR(p, PM2R_FB_HARD_WRITE_MASK, ~(0L));
878 	pm2_WR(p, PM2R_FB_READ_PIXEL, 0);
879 	pm2_WR(p, PM2R_DITHER_MODE, 0);
880 	pm2_WR(p, PM2R_AREA_STIPPLE_MODE, 0);
881 	pm2_WR(p, PM2R_DEPTH_MODE, 0);
882 	pm2_WR(p, PM2R_STENCIL_MODE, 0);
883 	pm2_WR(p, PM2R_TEXTURE_ADDRESS_MODE, 0);
884 	pm2_WR(p, PM2R_TEXTURE_READ_MODE, 0);
885 	pm2_WR(p, PM2R_TEXEL_LUT_MODE, 0);
886 	pm2_WR(p, PM2R_YUV_MODE, 0);
887 	pm2_WR(p, PM2R_COLOR_DDA_MODE, 0);
888 	pm2_WR(p, PM2R_TEXTURE_COLOR_MODE, 0);
889 	pm2_WR(p, PM2R_FOG_MODE, 0);
890 	pm2_WR(p, PM2R_ALPHA_BLEND_MODE, 0);
891 	pm2_WR(p, PM2R_LOGICAL_OP_MODE, 0);
892 	pm2_WR(p, PM2R_STATISTICS_MODE, 0);
893 	pm2_WR(p, PM2R_SCISSOR_MODE, 0);
894 	switch (p->type) {
895 	case PM2_TYPE_PERMEDIA2:
896 		pm2_RDAC_WR(p, PM2I_RD_MODE_CONTROL, 0); /* no overlay */
897 		pm2_RDAC_WR(p, PM2I_RD_CURSOR_CONTROL, 0);
898 		pm2_RDAC_WR(p, PM2I_RD_MISC_CONTROL, PM2F_RD_PALETTE_WIDTH_8);
899 		break;
900 	case PM2_TYPE_PERMEDIA2V:
901 		pm2v_RDAC_WR(p, PM2VI_RD_MISC_CONTROL, 1); /* 8bit */
902 		break;
903 	}
904 	pm2_RDAC_WR(p, PM2I_RD_COLOR_KEY_CONTROL, 0);
905 	pm2_RDAC_WR(p, PM2I_RD_OVERLAY_KEY, 0);
906 	pm2_RDAC_WR(p, PM2I_RD_RED_KEY, 0);
907 	pm2_RDAC_WR(p, PM2I_RD_GREEN_KEY, 0);
908 	pm2_RDAC_WR(p, PM2I_RD_BLUE_KEY, 0);
909 	clear_palette(p);
910 	if (p->memclock)
911 		pm2_set_memclock(p, p->memclock);
912 }
913 
pm2fb_conf(struct pm2fb_info * p)914 static int __init pm2fb_conf(struct pm2fb_info* p){
915 
916 	for (p->board=0; board_table[p->board].detect &&
917 			!(board_table[p->board].detect(p)); p->board++);
918 	if (!board_table[p->board].detect) {
919 		DPRINTK("no board found.\n");
920 		return 0;
921 	}
922 	DPRINTK("found board: %s\n", board_table[p->board].name);
923 
924 	p->regions.p_fb=p->regions.fb_base;
925 	if (!request_mem_region(p->regions.p_fb, p->regions.fb_size,
926 		    		"pm2fb")) {
927 		printk (KERN_ERR "pm2fb: cannot reserve fb memory, abort\n");
928 		return 0;
929 	}
930 	p->regions.v_fb=MMAP(p->regions.p_fb, p->regions.fb_size);
931 
932 #ifndef PM2FB_BE_APERTURE
933 	p->regions.p_regs=p->regions.rg_base;
934 #else
935 	p->regions.p_regs=p->regions.rg_base+PM2_REGS_SIZE;
936 #endif
937 	if (!request_mem_region(p->regions.p_regs, PM2_REGS_SIZE, "pm2fb")) {
938 		printk (KERN_ERR "pm2fb: cannot reserve mmio memory, abort\n");
939 		UNMAP(p->regions.v_fb, p->regions.fb_size);
940 		return 0;
941 	}
942 	p->regions.v_regs=MMAP(p->regions.p_regs, PM2_REGS_SIZE);
943 
944 #ifdef PM2FB_HW_CURSOR
945 	p->cursor = pm2_init_cursor(p);
946 #endif
947 	return 1;
948 }
949 
950 /***************************************************************************
951  * Begin of per-board initialization functions
952  ***************************************************************************/
953 
954 /*
955  * Phase5 CvisionPPC/BVisionPPC
956  */
957 #ifdef CONFIG_FB_PM2_CVPPC
cvppc_PCI_init(struct cvppc_par * p)958 static int cvppc_PCI_init(struct cvppc_par* p) {
959 	extern u32 powerup_PCI_present;
960 
961 	if (!powerup_PCI_present) {
962 		DPRINTK("no PCI bridge detected\n");
963 		return 0;
964 	}
965 	if (!(p->pci_config=MMAP(CVPPC_PCI_CONFIG, 256))) {
966 		DPRINTK("unable to map PCI config region\n");
967 		return 0;
968 	}
969 	if (RD32(p->pci_config, PCI_VENDOR_ID)!=
970 			((PCI_DEVICE_ID_TI_TVP4020<<16)|PCI_VENDOR_ID_TI)) {
971 		DPRINTK("bad vendorID/deviceID\n");
972 		return 0;
973 	}
974 	if (!(p->pci_bridge=MMAP(CSPPC_PCI_BRIDGE, 256))) {
975 		DPRINTK("unable to map PCI bridge\n");
976 		return 0;
977 	}
978 	WR32(p->pci_bridge, CSPPC_BRIDGE_ENDIAN, CSPPCF_BRIDGE_BIG_ENDIAN);
979 	DEFW();
980 	if (pm2fb_options.flags & OPTF_OLD_MEM)
981 		WR32(p->pci_config, PCI_CACHE_LINE_SIZE, 0xff00);
982 	WR32(p->pci_config, PCI_BASE_ADDRESS_0, CVPPC_REGS_REGION);
983 	WR32(p->pci_config, PCI_BASE_ADDRESS_1, CVPPC_FB_APERTURE_ONE);
984 	WR32(p->pci_config, PCI_BASE_ADDRESS_2, CVPPC_FB_APERTURE_TWO);
985 	WR32(p->pci_config, PCI_ROM_ADDRESS, CVPPC_ROM_ADDRESS);
986 	DEFW();
987 	WR32(p->pci_config, PCI_COMMAND, 0xef000000 |
988 						PCI_COMMAND_IO |
989 						PCI_COMMAND_MEMORY |
990 						PCI_COMMAND_MASTER);
991 	return 1;
992 }
993 
cvppc_detect(struct pm2fb_info * p)994 static int __init cvppc_detect(struct pm2fb_info* p) {
995 
996 	if (!cvppc_PCI_init(&p->board_par.cvppc))
997 		return 0;
998 	p->type = PM2_TYPE_PERMEDIA2;
999 	p->regions.fb_base=CVPPC_FB_APERTURE_ONE;
1000 	p->regions.fb_size=CVPPC_FB_SIZE;
1001 	p->regions.rg_base=CVPPC_REGS_REGION;
1002 	p->memclock=CVPPC_MEMCLOCK;
1003 	return 1;
1004 }
1005 
cvppc_init(struct pm2fb_info * p)1006 static void cvppc_init(struct pm2fb_info* p) {
1007 
1008 	WAIT_FIFO(p, 3);
1009 	pm2_WR(p, PM2R_MEM_CONTROL, 0);
1010 	pm2_WR(p, PM2R_BOOT_ADDRESS, 0x30);
1011 	DEFW();
1012 	if (pm2fb_options.flags & OPTF_OLD_MEM)
1013 		pm2_WR(p, PM2R_MEM_CONFIG, CVPPC_MEM_CONFIG_OLD);
1014 	else
1015 		pm2_WR(p, PM2R_MEM_CONFIG, CVPPC_MEM_CONFIG_NEW);
1016 }
1017 #endif /* CONFIG_FB_PM2_CVPPC */
1018 
1019 /*
1020  * Generic PCI detection routines
1021  */
1022 #ifdef CONFIG_FB_PM2_PCI
1023 struct {
1024 	unsigned short vendor, device;
1025 	char *name;
1026 	pm2type_t type;
1027 } pm2pci_cards[] __initdata = {
1028 { PCI_VENDOR_ID_TI, PCI_DEVICE_ID_TI_TVP4020, "Texas Instruments TVP4020", PM2_TYPE_PERMEDIA2 },
1029 { PCI_VENDOR_ID_3DLABS, PCI_DEVICE_ID_3DLABS_PERMEDIA2, "3dLabs Permedia 2", PM2_TYPE_PERMEDIA2 },
1030 { PCI_VENDOR_ID_3DLABS, PCI_DEVICE_ID_3DLABS_PERMEDIA2V, "3dLabs Permedia 2v", PM2_TYPE_PERMEDIA2V },
1031 { 0, 0 }
1032 };
1033 
pm2pci_detect(struct pm2fb_info * p)1034 static int __init pm2pci_detect(struct pm2fb_info* p) {
1035 	struct pm2pci_par* pci=&p->board_par.pci;
1036 	struct pci_dev* dev;
1037 	int i;
1038 	unsigned char* m;
1039 #ifdef __sparc__
1040 	struct pcidev_cookie *pcp;
1041 #endif
1042 
1043 	memset(pci, 0, sizeof(struct pm2pci_par));
1044 	if (!pci_present()) {
1045 		DPRINTK("no PCI bus found.\n");
1046 		return 0;
1047 	}
1048 	DPRINTK("scanning PCI bus for known chipsets...\n");
1049 
1050 	pci_for_each_dev(dev) {
1051 		for (i = 0; pm2pci_cards[i].vendor; i++)
1052 			if (pm2pci_cards[i].vendor == dev->vendor &&
1053 			    pm2pci_cards[i].device == dev->device) {
1054 				pci->dev = dev;
1055 				p->type = pm2pci_cards[i].type;
1056 				DPRINTK("... found %s\n", pm2pci_cards[i].name);
1057 				break;
1058 			}
1059 		if (pci->dev)
1060 			break;
1061 	}
1062 	if (!pci->dev) {
1063 		DPRINTK("no PCI board found.\n");
1064 		return 0;
1065 	}
1066 	DPRINTK("PCI board @%08lx %08lx %08lx rom %08lx\n",
1067 			pci->dev->resource[0].start,
1068 			pci->dev->resource[1].start,
1069 			pci->dev->resource[2].start,
1070 			pci->dev->resource[PCI_ROM_RESOURCE].start);
1071 #ifdef __sparc__
1072 	p->regions.rg_base= pci->dev->resource[0].start;
1073 	p->regions.fb_base= pci->dev->resource[1].start;
1074 	pcp = pci->dev->sysdata;
1075 	/* If the user has not asked for a particular mode, lets guess */
1076 	if (pcp->prom_node && !(pm2fb_options.flags & OPTF_USER)) {
1077 		char timing[256], *q, *r;
1078 		unsigned long w, h;
1079 		int i;
1080 		prom_getstring(pcp->prom_node, "timing-numbers", timing, 256);
1081 		/* FIXME: Find out what the actual pixclock is and other values as well */
1082 		if (timing[0]) {
1083 			w = simple_strtoul(timing, &q, 0);
1084 			h = 0;
1085 			if (q == timing) w = 0;
1086 			if (w) {
1087 				for (i = 0; i < 3; i++) {
1088 					for (r = q; *r && (*r < '0' || *r > '9'); r++);
1089 					simple_strtoul(r, &q, 0);
1090 					if (r == q) break;
1091 				}
1092 				if (i < 3) w = 0;
1093 			}
1094 			if (w) {
1095 				for (r = q; *r && (*r < '0' || *r > '9'); r++);
1096 				h = simple_strtoul(r, &q, 0);
1097 				if (r == q) w = 0;
1098 			}
1099 			if (w == 640 && h == 480) w = 0;
1100 			if (w) {
1101 				for (i=0; user_mode[i].name[0] &&
1102 					  (w != user_mode[i].par.width ||
1103 					   h != user_mode[i].par.height); i++);
1104 				if (user_mode[i].name[0])
1105 					memcpy(&p->current_par, &user_mode[i].par, sizeof(user_mode[i].par));
1106 			}
1107 		}
1108 	}
1109 #else
1110 	if (pm2fb_options.flags & OPTF_VIRTUAL) {
1111 		p->regions.rg_base = __pa(pci_resource_start(pci->dev, 0));
1112 		p->regions.fb_base = __pa(pci_resource_start(pci->dev, 1));
1113 	}
1114 	else {
1115 		p->regions.rg_base = pci_resource_start(pci->dev, 0);
1116 		p->regions.fb_base = pci_resource_start(pci->dev, 1);
1117 	}
1118 #endif
1119 #ifdef PM2FB_BE_APERTURE
1120 	p->regions.rg_base += PM2_REGS_SIZE;
1121 #endif
1122 	if ((m=MMAP(p->regions.rg_base, PM2_REGS_SIZE))) {
1123 		pci->mem_control=RD32(m, PM2R_MEM_CONTROL);
1124 		pci->boot_address=RD32(m, PM2R_BOOT_ADDRESS);
1125 		pci->mem_config=RD32(m, PM2R_MEM_CONFIG);
1126 		switch (pci->mem_config & PM2F_MEM_CONFIG_RAM_MASK) {
1127 			case PM2F_MEM_BANKS_1:
1128 				p->regions.fb_size=0x200000;
1129 				break;
1130 			case PM2F_MEM_BANKS_2:
1131 				p->regions.fb_size=0x400000;
1132 				break;
1133 			case PM2F_MEM_BANKS_3:
1134 				p->regions.fb_size=0x600000;
1135 				break;
1136 			case PM2F_MEM_BANKS_4:
1137 				p->regions.fb_size=0x800000;
1138 				break;
1139 		}
1140 		p->memclock=CVPPC_MEMCLOCK;
1141 		UNMAP(m, PM2_REGS_SIZE);
1142 		return 1;
1143 	}
1144 	DPRINTK("MMAP() failed.\n");
1145 	return 0;
1146 }
1147 
pm2pci_init(struct pm2fb_info * p)1148 static void pm2pci_init(struct pm2fb_info* p) {
1149 	struct pm2pci_par* pci=&p->board_par.pci;
1150 
1151 	WAIT_FIFO(p, 3);
1152 	pm2_WR(p, PM2R_MEM_CONTROL, pci->mem_control);
1153 	pm2_WR(p, PM2R_BOOT_ADDRESS, pci->boot_address);
1154 	DEFW();
1155 	pm2_WR(p, PM2R_MEM_CONFIG, pci->mem_config);
1156 }
1157 #endif /* CONFIG_FB_PM2_PCI */
1158 
1159 /***************************************************************************
1160  * Console hw acceleration
1161  ***************************************************************************/
1162 
1163 
pm2fb_blank(int blank_mode,struct fb_info_gen * info)1164 static int pm2fb_blank(int blank_mode, struct fb_info_gen* info) {
1165 	struct pm2fb_info* i=(struct pm2fb_info* )info;
1166 	u32 video;
1167 
1168 	if (!i->current_par_valid)
1169 		return 1;
1170 	video=i->current_par.video;
1171 	if (blank_mode>0) {
1172 		switch (blank_mode-1) {
1173 			case VESA_NO_BLANKING:		/* FIXME */
1174 				video=video&~(PM2F_VIDEO_ENABLE);
1175 				break;
1176 			case VESA_HSYNC_SUSPEND:
1177 				video=video&~(PM2F_HSYNC_MASK|
1178 						PM2F_BLANK_LOW);
1179 				break;
1180 			case VESA_VSYNC_SUSPEND:
1181 				video=video&~(PM2F_VSYNC_MASK|
1182 						PM2F_BLANK_LOW);
1183 				break;
1184 			case VESA_POWERDOWN:
1185 				video=video&~(PM2F_VSYNC_MASK|
1186 						PM2F_HSYNC_MASK|
1187 						PM2F_BLANK_LOW);
1188 				break;
1189 		}
1190 	}
1191 	WAIT_FIFO(i, 1);
1192 	pm2_WR(i, PM2R_VIDEO_CONTROL, video);
1193 	return 0;
1194 }
1195 
pm2fb_pan_display(const struct fb_var_screeninfo * var,struct fb_info_gen * info)1196 static int pm2fb_pan_display(const struct fb_var_screeninfo* var,
1197 					struct fb_info_gen* info) {
1198 	struct pm2fb_info* i=(struct pm2fb_info* )info;
1199 
1200 	if (!i->current_par_valid)
1201 		return -EINVAL;
1202 	i->current_par.base=to3264(var->yoffset*i->current_par.width+
1203 				var->xoffset, i->current_par.depth, 1);
1204 	WAIT_FIFO(i, 1);
1205 	pm2_WR(i, PM2R_SCREEN_BASE, i->current_par.base);
1206 	return 0;
1207 }
1208 
pm2fb_pp_bmove(struct display * p,int sy,int sx,int dy,int dx,int height,int width)1209 static void pm2fb_pp_bmove(struct display* p, int sy, int sx,
1210 				int dy, int dx, int height, int width) {
1211 
1212 	if (fontwidthlog(p)) {
1213 		sx=sx<<fontwidthlog(p);
1214 		dx=dx<<fontwidthlog(p);
1215 		width=width<<fontwidthlog(p);
1216 	}
1217 	else {
1218 		sx=sx*fontwidth(p);
1219 		dx=dx*fontwidth(p);
1220 		width=width*fontwidth(p);
1221 	}
1222 	sy=sy*fontheight(p);
1223 	dy=dy*fontheight(p);
1224 	height=height*fontheight(p);
1225 	pm2fb_pp_copy((struct pm2fb_info* )p->fb_info, sx, sy, dx,
1226 							dy, width, height);
1227 }
1228 
pm2fb_bmove(struct display * p,int sy,int sx,int dy,int dx,int height,int width)1229 static void pm2fb_bmove(struct display* p, int sy, int sx,
1230 				int dy, int dx, int height, int width) {
1231 
1232 	if (fontwidthlog(p)) {
1233 		sx=sx<<fontwidthlog(p);
1234 		dx=dx<<fontwidthlog(p);
1235 		width=width<<fontwidthlog(p);
1236 	}
1237 	else {
1238 		sx=sx*fontwidth(p);
1239 		dx=dx*fontwidth(p);
1240 		width=width*fontwidth(p);
1241 	}
1242 	sy=sy*fontheight(p);
1243 	dy=dy*fontheight(p);
1244 	height=height*fontheight(p);
1245 	pm2fb_block_op((struct pm2fb_info* )p->fb_info, 1, sx, sy, dx, dy,
1246 							width, height, 0);
1247 }
1248 
1249 #ifdef FBCON_HAS_CFB8
pm2fb_clear8(struct vc_data * conp,struct display * p,int sy,int sx,int height,int width)1250 static void pm2fb_clear8(struct vc_data* conp, struct display* p,
1251 				int sy, int sx, int height, int width) {
1252 	u32 c;
1253 
1254 	sx=sx*fontwidth(p);
1255 	width=width*fontwidth(p);
1256 	sy=sy*fontheight(p);
1257 	height=height*fontheight(p);
1258 	c=attr_bgcol_ec(p, conp);
1259 	c|=c<<8;
1260 	c|=c<<16;
1261 	pm2fb_block_op((struct pm2fb_info* )p->fb_info, 0, 0, 0, sx, sy,
1262 							width, height, c);
1263 }
1264 
pm2fb_clear_margins8(struct vc_data * conp,struct display * p,int bottom_only)1265 static void pm2fb_clear_margins8(struct vc_data* conp, struct display* p,
1266 							int bottom_only) {
1267 	u32 c;
1268 	u32 sx;
1269 	u32 sy;
1270 
1271 	c=attr_bgcol_ec(p, conp);
1272 	c|=c<<8;
1273 	c|=c<<16;
1274 	sx=conp->vc_cols*fontwidth(p);
1275 	sy=conp->vc_rows*fontheight(p);
1276 	if (!bottom_only)
1277 		pm2fb_block_op((struct pm2fb_info* )p->fb_info, 0, 0, 0,
1278 			sx, 0, (p->var.xres-sx), p->var.yres_virtual, c);
1279 	pm2fb_block_op((struct pm2fb_info* )p->fb_info, 0, 0, 0,
1280 				0, p->var.yoffset+sy, sx, p->var.yres-sy, c);
1281 }
1282 
1283 static struct display_switch pm2_cfb8 = {
1284 	setup:		fbcon_cfb8_setup,
1285 	bmove:		pm2fb_pp_bmove,
1286 #ifdef __alpha__
1287 	/* Not sure why, but this works and the other does not. */
1288 	/* Also, perhaps we need a separate routine to wait for the
1289 	   blitter to stop before doing this? */
1290 	/* In addition, maybe we need to do this for 16 and 32 bit depths? */
1291 	clear:		fbcon_cfb8_clear,
1292 #else
1293 	clear:		pm2fb_clear8,
1294 #endif
1295 	putc:		fbcon_cfb8_putc,
1296 	putcs:		fbcon_cfb8_putcs,
1297 	revc:		fbcon_cfb8_revc,
1298 	cursor:		pm2fb_cursor,
1299 	set_font:	pm2fb_set_font,
1300 	clear_margins:	pm2fb_clear_margins8,
1301 	fontwidthmask:	FONTWIDTH(4)|FONTWIDTH(8)|FONTWIDTH(12)|FONTWIDTH(16) };
1302 #endif /* FBCON_HAS_CFB8 */
1303 
1304 #ifdef FBCON_HAS_CFB16
pm2fb_clear16(struct vc_data * conp,struct display * p,int sy,int sx,int height,int width)1305 static void pm2fb_clear16(struct vc_data* conp, struct display* p,
1306 				int sy, int sx, int height, int width) {
1307 	u32 c;
1308 
1309 	sx=sx*fontwidth(p);
1310 	width=width*fontwidth(p);
1311 	sy=sy*fontheight(p);
1312 	height=height*fontheight(p);
1313 	c=((u16 *)p->dispsw_data)[attr_bgcol_ec(p, conp)];
1314 	c|=c<<16;
1315 	pm2fb_block_op((struct pm2fb_info* )p->fb_info, 0, 0, 0, sx, sy,
1316 							width, height, c);
1317 }
1318 
pm2fb_clear_margins16(struct vc_data * conp,struct display * p,int bottom_only)1319 static void pm2fb_clear_margins16(struct vc_data* conp, struct display* p,
1320 							int bottom_only) {
1321 	u32 c;
1322 	u32 sx;
1323 	u32 sy;
1324 
1325 	c = ((u16 *)p->dispsw_data)[attr_bgcol_ec(p, conp)];
1326 	c|=c<<16;
1327 	sx=conp->vc_cols*fontwidth(p);
1328 	sy=conp->vc_rows*fontheight(p);
1329 	if (!bottom_only)
1330 		pm2fb_block_op((struct pm2fb_info* )p->fb_info, 0, 0, 0,
1331 			sx, 0, (p->var.xres-sx), p->var.yres_virtual, c);
1332 	pm2fb_block_op((struct pm2fb_info* )p->fb_info, 0, 0, 0,
1333 				0, p->var.yoffset+sy, sx, p->var.yres-sy, c);
1334 }
1335 
1336 static struct display_switch pm2_cfb16 = {
1337 	setup:		fbcon_cfb16_setup,
1338 	bmove:		pm2fb_pp_bmove,
1339 	clear:		pm2fb_clear16,
1340 	putc:		fbcon_cfb16_putc,
1341 	putcs:		fbcon_cfb16_putcs,
1342 	revc:		fbcon_cfb16_revc,
1343 	cursor:		pm2fb_cursor,
1344 	set_font:	pm2fb_set_font,
1345 	clear_margins:	pm2fb_clear_margins16,
1346 	fontwidthmask:	FONTWIDTH(4)|FONTWIDTH(8)|FONTWIDTH(12)|FONTWIDTH(16)
1347 };
1348 #endif /* FBCON_HAS_CFB16 */
1349 
1350 #ifdef FBCON_HAS_CFB24
1351 /*
1352  * fast fill for 24bpp works only when red==green==blue
1353  */
pm2fb_clear24(struct vc_data * conp,struct display * p,int sy,int sx,int height,int width)1354 static void pm2fb_clear24(struct vc_data* conp, struct display* p,
1355 				int sy, int sx, int height, int width) {
1356 	struct pm2fb_info* i=(struct pm2fb_info* )p->fb_info;
1357 	u32 c;
1358 
1359 	c=attr_bgcol_ec(p, conp);
1360 	if (		i->palette[c].red==i->palette[c].green &&
1361 			i->palette[c].green==i->palette[c].blue) {
1362 		c=((u32 *)p->dispsw_data)[c];
1363 		c|=(c&0xff0000)<<8;
1364 		sx=sx*fontwidth(p);
1365 		width=width*fontwidth(p);
1366 		sy=sy*fontheight(p);
1367 		height=height*fontheight(p);
1368 		pm2fb_block_op(i, 0, 0, 0, sx, sy, width, height, c);
1369 	}
1370 	else
1371 		fbcon_cfb24_clear(conp, p, sy, sx, height, width);
1372 
1373 }
1374 
pm2fb_clear_margins24(struct vc_data * conp,struct display * p,int bottom_only)1375 static void pm2fb_clear_margins24(struct vc_data* conp, struct display* p,
1376 							int bottom_only) {
1377 	struct pm2fb_info* i=(struct pm2fb_info* )p->fb_info;
1378 	u32 c;
1379 	u32 sx;
1380 	u32 sy;
1381 
1382 	c=attr_bgcol_ec(p, conp);
1383 	if (		i->palette[c].red==i->palette[c].green &&
1384 			i->palette[c].green==i->palette[c].blue) {
1385 		c=((u32 *)p->dispsw_data)[c];
1386 		c|=(c&0xff0000)<<8;
1387 		sx=conp->vc_cols*fontwidth(p);
1388 		sy=conp->vc_rows*fontheight(p);
1389 		if (!bottom_only)
1390 		pm2fb_block_op(i, 0, 0, 0, sx, 0, (p->var.xres-sx),
1391 							p->var.yres_virtual, c);
1392 		pm2fb_block_op(i, 0, 0, 0, 0, p->var.yoffset+sy,
1393 						sx, p->var.yres-sy, c);
1394 	}
1395 	else
1396 		fbcon_cfb24_clear_margins(conp, p, bottom_only);
1397 
1398 }
1399 
1400 static struct display_switch pm2_cfb24 = {
1401 	setup:		fbcon_cfb24_setup,
1402 	bmove:		pm2fb_bmove,
1403 	clear:		pm2fb_clear24,
1404 	putc:		fbcon_cfb24_putc,
1405 	putcs:		fbcon_cfb24_putcs,
1406 	revc:		fbcon_cfb24_revc,
1407 	cursor:		pm2fb_cursor,
1408 	set_font:	pm2fb_set_font,
1409 	clear_margins:	pm2fb_clear_margins24,
1410 	fontwidthmask:	FONTWIDTH(4)|FONTWIDTH(8)|FONTWIDTH(12)|FONTWIDTH(16)
1411 };
1412 #endif /* FBCON_HAS_CFB24 */
1413 
1414 #ifdef FBCON_HAS_CFB32
pm2fb_clear32(struct vc_data * conp,struct display * p,int sy,int sx,int height,int width)1415 static void pm2fb_clear32(struct vc_data* conp, struct display* p,
1416 				int sy, int sx, int height, int width) {
1417 	u32 c;
1418 
1419 	sx=sx*fontwidth(p);
1420 	width=width*fontwidth(p);
1421 	sy=sy*fontheight(p);
1422 	height=height*fontheight(p);
1423 	c=((u32 *)p->dispsw_data)[attr_bgcol_ec(p, conp)];
1424 	pm2fb_block_op((struct pm2fb_info* )p->fb_info, 0, 0, 0, sx, sy,
1425 							width, height, c);
1426 }
1427 
pm2fb_clear_margins32(struct vc_data * conp,struct display * p,int bottom_only)1428 static void pm2fb_clear_margins32(struct vc_data* conp, struct display* p,
1429 							int bottom_only) {
1430 	u32 c;
1431 	u32 sx;
1432 	u32 sy;
1433 
1434 	c = ((u32 *)p->dispsw_data)[attr_bgcol_ec(p, conp)];
1435 	sx=conp->vc_cols*fontwidth(p);
1436 	sy=conp->vc_rows*fontheight(p);
1437 	if (!bottom_only)
1438 		pm2fb_block_op((struct pm2fb_info* )p->fb_info, 0, 0, 0,
1439 			sx, 0, (p->var.xres-sx), p->var.yres_virtual, c);
1440 	pm2fb_block_op((struct pm2fb_info* )p->fb_info, 0, 0, 0,
1441 				0, p->var.yoffset+sy, sx, p->var.yres-sy, c);
1442 }
1443 
1444 static struct display_switch pm2_cfb32 = {
1445 	setup:		fbcon_cfb32_setup,
1446 	bmove:		pm2fb_bmove,
1447 	clear:		pm2fb_clear32,
1448 	putc:		fbcon_cfb32_putc,
1449 	putcs:		fbcon_cfb32_putcs,
1450 	revc:		fbcon_cfb32_revc,
1451 	cursor:		pm2fb_cursor,
1452 	set_font:	pm2fb_set_font,
1453 	clear_margins:	pm2fb_clear_margins32,
1454 	fontwidthmask:	FONTWIDTH(4)|FONTWIDTH(8)|FONTWIDTH(12)|FONTWIDTH(16)
1455 };
1456 #endif /* FBCON_HAS_CFB32 */
1457 
1458 /***************************************************************************
1459  * Framebuffer functions
1460  ***************************************************************************/
1461 
pm2fb_detect(void)1462 static void pm2fb_detect(void) {}
1463 
pm2fb_encode_fix(struct fb_fix_screeninfo * fix,const void * par,struct fb_info_gen * info)1464 static int pm2fb_encode_fix(struct fb_fix_screeninfo* fix,
1465 			const void* par, struct fb_info_gen* info) {
1466 	struct pm2fb_info* i=(struct pm2fb_info* )info;
1467 	struct pm2fb_par* p=(struct pm2fb_par* )par;
1468 
1469 	strcpy(fix->id, permedia2_name);
1470 	fix->smem_start=i->regions.p_fb;
1471 	fix->smem_len=i->regions.fb_size;
1472 	fix->mmio_start=i->regions.p_regs;
1473 	fix->mmio_len=PM2_REGS_SIZE;
1474 	fix->accel=FB_ACCEL_3DLABS_PERMEDIA2;
1475 	fix->type=FB_TYPE_PACKED_PIXELS;
1476 	fix->visual=p->depth==8?FB_VISUAL_PSEUDOCOLOR:FB_VISUAL_TRUECOLOR;
1477 	if (i->current_par_valid)
1478 		fix->line_length=i->current_par.width*(i->current_par.depth/8);
1479 	else
1480 		fix->line_length=0;
1481 	fix->xpanstep=p->depth==24?8:64/p->depth;
1482 	fix->ypanstep=1;
1483 	fix->ywrapstep=0;
1484 	return 0;
1485 }
1486 
1487 #ifdef PM2FB_MASTER_DEBUG
pm2fb_display_var(const struct fb_var_screeninfo * var)1488 static void pm2fb_display_var(const struct fb_var_screeninfo* var) {
1489 
1490 	printk( KERN_DEBUG
1491 "- struct fb_var_screeninfo ---------------------------------------------------\n");
1492 	printk( KERN_DEBUG
1493 		"resolution: %ux%ux%u (virtual %ux%u+%u+%u)\n",
1494 			var->xres, var->yres, var->bits_per_pixel,
1495 			var->xres_virtual, var->yres_virtual,
1496 			var->xoffset, var->yoffset);
1497 	printk( KERN_DEBUG
1498 		"color: %c%c "
1499 		"R(%u,%u,%u), G(%u,%u,%u), B(%u,%u,%u), T(%u,%u,%u)\n",
1500 			var->grayscale?'G':'C', var->nonstd?'N':'S',
1501 			var->red.offset, var->red.length, var->red.msb_right,
1502 			var->green.offset, var->green.length, var->green.msb_right,
1503 			var->blue.offset, var->blue.length, var->blue.msb_right,
1504 			var->transp.offset, var->transp.length,
1505 			var->transp.msb_right);
1506 	printk( KERN_DEBUG
1507 		"timings: %ups (%u,%u)-(%u,%u)+%u+%u\n",
1508 		var->pixclock,
1509 		var->left_margin, var->upper_margin, var->right_margin,
1510 		var->lower_margin, var->hsync_len, var->vsync_len);
1511 	printk(	KERN_DEBUG
1512 		"activate %08x accel_flags %08x sync %08x vmode %08x\n",
1513 		var->activate, var->accel_flags, var->sync, var->vmode);
1514 	printk(	KERN_DEBUG
1515 "------------------------------------------------------------------------------\n");
1516 }
1517 
1518 #define pm2fb_decode_var pm2fb_wrapped_decode_var
1519 #endif
1520 
pm2fb_decode_var(const struct fb_var_screeninfo * var,void * par,struct fb_info_gen * info)1521 static int pm2fb_decode_var(const struct fb_var_screeninfo* var,
1522 				void* par, struct fb_info_gen* info) {
1523 	struct pm2fb_info* i=(struct pm2fb_info* )info;
1524 	struct pm2fb_par p;
1525 	u32 xres;
1526 	int data64;
1527 
1528 	memset(&p, 0, sizeof(struct pm2fb_par));
1529 	p.width=(var->xres_virtual+7)&~7;
1530 	p.height=var->yres_virtual;
1531 	p.depth=(var->bits_per_pixel+7)&~7;
1532 	p.depth=p.depth>32?32:p.depth;
1533 	data64=p.depth>8 || i->type == PM2_TYPE_PERMEDIA2V;
1534 	xres=(var->xres+31)&~31;
1535 	if (p.width<xres+var->xoffset)
1536 		p.width=xres+var->xoffset;
1537 	if (p.height<var->yres+var->yoffset)
1538 		p.height=var->yres+var->yoffset;
1539 	if (!partprod(xres)) {
1540 		DPRINTK("width not supported: %u\n", xres);
1541 		return -EINVAL;
1542 	}
1543 	if (p.width>2047) {
1544 		DPRINTK("virtual width not supported: %u\n", p.width);
1545 		return -EINVAL;
1546 	}
1547 	if (var->yres<200) {
1548 		DPRINTK("height not supported: %u\n",
1549 						(u32 )var->yres);
1550 		return -EINVAL;
1551 	}
1552 	if (p.height<200 || p.height>2047) {
1553 		DPRINTK("virtual height not supported: %u\n", p.height);
1554 		return -EINVAL;
1555 	}
1556 	if (p.depth>32) {
1557 		DPRINTK("depth not supported: %u\n", p.depth);
1558 		return -EINVAL;
1559 	}
1560 	if (p.width*p.height*p.depth/8>i->regions.fb_size) {
1561 		DPRINTK("no memory for screen (%ux%ux%u)\n",
1562 						p.width, p.height, p.depth);
1563 		return -EINVAL;
1564 	}
1565 	p.pixclock=PICOS2KHZ(var->pixclock);
1566 	if (p.pixclock>PM2_MAX_PIXCLOCK) {
1567 		DPRINTK("pixclock too high (%uKHz)\n", p.pixclock);
1568 		return -EINVAL;
1569 	}
1570 	p.hsstart=to3264(var->right_margin, p.depth, data64);
1571 	p.hsend=p.hsstart+to3264(var->hsync_len, p.depth, data64);
1572 	p.hbend=p.hsend+to3264(var->left_margin, p.depth, data64);
1573 	p.htotal=to3264(xres, p.depth, data64)+p.hbend-1;
1574 	p.vsstart=var->lower_margin?var->lower_margin-1:0;	/* FIXME! */
1575 	p.vsend=var->lower_margin+var->vsync_len-1;
1576 	p.vbend=var->lower_margin+var->vsync_len+var->upper_margin;
1577 	p.vtotal=var->yres+p.vbend-1;
1578 	p.stride=to3264(p.width, p.depth, 1);
1579 	p.base=to3264(var->yoffset*xres+var->xoffset, p.depth, 1);
1580 	if (data64)
1581 		p.video|=PM2F_DATA_64_ENABLE;
1582 	if (var->sync & FB_SYNC_HOR_HIGH_ACT)
1583 		p.video|=PM2F_HSYNC_ACT_HIGH;
1584 	else
1585 		p.video|=PM2F_HSYNC_ACT_LOW;
1586 	if (var->sync & FB_SYNC_VERT_HIGH_ACT)
1587 		p.video|=PM2F_VSYNC_ACT_HIGH;
1588 	else
1589 		p.video|=PM2F_VSYNC_ACT_LOW;
1590 	if ((var->vmode & FB_VMODE_MASK)==FB_VMODE_INTERLACED) {
1591 		DPRINTK("interlaced not supported\n");
1592 		return -EINVAL;
1593 	}
1594 	if ((var->vmode & FB_VMODE_MASK)==FB_VMODE_DOUBLE)
1595 		p.video|=PM2F_LINE_DOUBLE;
1596 	if (var->activate==FB_ACTIVATE_NOW)
1597 		p.video|=PM2F_VIDEO_ENABLE;
1598 	*((struct pm2fb_par* )par)=p;
1599 	return 0;
1600 }
1601 
1602 #ifdef PM2FB_MASTER_DEBUG
1603 #undef pm2fb_decode_var
1604 
pm2fb_decode_var(const struct fb_var_screeninfo * var,void * par,struct fb_info_gen * info)1605 static int pm2fb_decode_var(const struct fb_var_screeninfo* var,
1606 				void* par, struct fb_info_gen* info) {
1607 	int result;
1608 
1609 	result=pm2fb_wrapped_decode_var(var, par, info);
1610 	pm2fb_display_var(var);
1611 	return result;
1612 }
1613 #endif
1614 
pm2fb_encode_var(struct fb_var_screeninfo * var,const void * par,struct fb_info_gen * info)1615 static int pm2fb_encode_var(struct fb_var_screeninfo* var,
1616 				const void* par, struct fb_info_gen* info) {
1617 	struct pm2fb_par* p=(struct pm2fb_par* )par;
1618 	struct fb_var_screeninfo v;
1619 	u32 base;
1620 
1621 	memset(&v, 0, sizeof(struct fb_var_screeninfo));
1622 	v.xres_virtual=p->width;
1623 	v.yres_virtual=p->height;
1624 	v.xres=(p->htotal+1)-p->hbend;
1625 	v.yres=(p->vtotal+1)-p->vbend;
1626 	v.right_margin=p->hsstart;
1627 	v.hsync_len=p->hsend-p->hsstart;
1628 	v.left_margin=p->hbend-p->hsend;
1629 	v.lower_margin=p->vsstart+1;
1630 	v.vsync_len=p->vsend-v.lower_margin+1;
1631 	v.upper_margin=p->vbend-v.lower_margin-v.vsync_len;
1632 	v.bits_per_pixel=p->depth;
1633 	if (p->video & PM2F_DATA_64_ENABLE) {
1634 		v.xres=v.xres<<1;
1635 		v.right_margin=v.right_margin<<1;
1636 		v.hsync_len=v.hsync_len<<1;
1637 		v.left_margin=v.left_margin<<1;
1638 	}
1639 	switch (p->depth) {
1640 		case 8:
1641 			v.red.length=v.green.length=v.blue.length=8;
1642 			v.xres=v.xres<<2;
1643 			v.right_margin=v.right_margin<<2;
1644 			v.hsync_len=v.hsync_len<<2;
1645 			v.left_margin=v.left_margin<<2;
1646 			break;
1647 		case 16:
1648 			v.red.offset=11;
1649 			v.red.length=5;
1650 			v.green.offset=5;
1651 			v.green.length=6;
1652 			v.blue.length=5;
1653 			v.xres=v.xres<<1;
1654 			v.right_margin=v.right_margin<<1;
1655 			v.hsync_len=v.hsync_len<<1;
1656 			v.left_margin=v.left_margin<<1;
1657 			break;
1658 		case 32:
1659 			v.transp.offset=24;
1660 			v.red.offset=16;
1661 			v.green.offset=8;
1662 			v.red.length=v.green.length=v.blue.length=
1663 							v.transp.length=8;
1664 			break;
1665 		case 24:
1666 			v.blue.offset=16;
1667 			v.green.offset=8;
1668 			v.red.length=v.green.length=v.blue.length=8;
1669 			v.xres=(v.xres<<2)/3;
1670 			v.right_margin=(v.right_margin<<2)/3;
1671 			v.hsync_len=(v.hsync_len<<2)/3;
1672 			v.left_margin=(v.left_margin<<2)/3;
1673 			break;
1674 	}
1675 	base=from3264(p->base, p->depth, 1);
1676 	v.xoffset=base%v.xres;
1677 	v.yoffset=base/v.xres;
1678 	v.height=v.width=-1;
1679 	v.pixclock=KHZ2PICOS(p->pixclock);
1680 	if ((p->video & PM2F_HSYNC_MASK)==PM2F_HSYNC_ACT_HIGH)
1681 		v.sync|=FB_SYNC_HOR_HIGH_ACT;
1682 	if ((p->video & PM2F_VSYNC_MASK)==PM2F_VSYNC_ACT_HIGH)
1683 		v.sync|=FB_SYNC_VERT_HIGH_ACT;
1684 	if (p->video & PM2F_LINE_DOUBLE)
1685 		v.vmode=FB_VMODE_DOUBLE;
1686 	*var=v;
1687 	return 0;
1688 }
1689 
set_user_mode(struct pm2fb_info * i)1690 static void set_user_mode(struct pm2fb_info* i) {
1691 
1692 	if (pm2fb_options.flags & OPTF_YPAN) {
1693 		int h = i->current_par.height;
1694 		i->current_par.height=i->regions.fb_size/
1695 			(i->current_par.width*i->current_par.depth/8);
1696 		i->current_par.height=MIN(i->current_par.height,2047);
1697 		i->current_par.height=MAX(i->current_par.height,h);
1698 	}
1699 }
1700 
pm2fb_get_par(void * par,struct fb_info_gen * info)1701 static void pm2fb_get_par(void* par, struct fb_info_gen* info) {
1702 	struct pm2fb_info* i=(struct pm2fb_info* )info;
1703 
1704 	if (!i->current_par_valid) {
1705 		set_user_mode(i);
1706 		pm2fb_reset(i);
1707 		set_screen(i, &i->current_par);
1708 		i->current_par_valid=1;
1709 	}
1710 	*((struct pm2fb_par* )par)=i->current_par;
1711 }
1712 
pm2fb_set_par(const void * par,struct fb_info_gen * info)1713 static void pm2fb_set_par(const void* par, struct fb_info_gen* info) {
1714 	struct pm2fb_info* i=(struct pm2fb_info* )info;
1715 	struct pm2fb_par* p;
1716 
1717 	p=(struct pm2fb_par* )par;
1718 	if (i->current_par_valid) {
1719 		i->current_par.base=p->base;
1720 		if (!memcmp(p, &i->current_par, sizeof(struct pm2fb_par))) {
1721 			WAIT_FIFO(i, 1);
1722 			pm2_WR(i, PM2R_SCREEN_BASE, p->base);
1723 			return;
1724 		}
1725 	}
1726 	set_screen(i, p);
1727 	i->current_par=*p;
1728 	i->current_par_valid=1;
1729 #ifdef PM2FB_HW_CURSOR
1730 	if (i->cursor) {
1731 		pm2v_set_cursor_color(i, cursor_color_map, cursor_color_map, cursor_color_map);
1732 		pm2v_set_cursor_shape(i);
1733 	}
1734 #endif
1735 }
1736 
pm2fb_getcolreg(unsigned regno,unsigned * red,unsigned * green,unsigned * blue,unsigned * transp,struct fb_info * info)1737 static int pm2fb_getcolreg(unsigned regno,
1738 			unsigned* red, unsigned* green, unsigned* blue,
1739 				unsigned* transp, struct fb_info* info) {
1740 	struct pm2fb_info* i=(struct pm2fb_info* )info;
1741 
1742 	if (regno<256) {
1743 		*red=i->palette[regno].red<<8|i->palette[regno].red;
1744 		*green=i->palette[regno].green<<8|i->palette[regno].green;
1745 		*blue=i->palette[regno].blue<<8|i->palette[regno].blue;
1746 		*transp=i->palette[regno].transp<<8|i->palette[regno].transp;
1747 	}
1748 	return regno>255;
1749 }
1750 
pm2fb_setcolreg(unsigned regno,unsigned red,unsigned green,unsigned blue,unsigned transp,struct fb_info * info)1751 static int pm2fb_setcolreg(unsigned regno,
1752 			unsigned red, unsigned green, unsigned blue,
1753 				unsigned transp, struct fb_info* info) {
1754 	struct pm2fb_info* i=(struct pm2fb_info* )info;
1755 
1756 	if (regno<16) {
1757 		switch (i->current_par.depth) {
1758 #ifdef FBCON_HAS_CFB8
1759 			case 8:
1760 				break;
1761 #endif
1762 #ifdef FBCON_HAS_CFB16
1763 			case 16:
1764 				i->cmap.cmap16[regno]=
1765 					((u32 )red & 0xf800) |
1766 					(((u32 )green & 0xfc00)>>5) |
1767 					(((u32 )blue & 0xf800)>>11);
1768 				break;
1769 #endif
1770 #ifdef FBCON_HAS_CFB24
1771 			case 24:
1772 				i->cmap.cmap24[regno]=
1773 					(((u32 )blue & 0xff00) << 8) |
1774 					((u32 )green & 0xff00) |
1775 					(((u32 )red & 0xff00) >> 8);
1776 				break;
1777 #endif
1778 #ifdef FBCON_HAS_CFB32
1779 			case 32:
1780 	   			i->cmap.cmap32[regno]=
1781 					(((u32 )transp & 0xff00) << 16) |
1782 		    			(((u32 )red & 0xff00) << 8) |
1783 					(((u32 )green & 0xff00)) |
1784 			 		(((u32 )blue & 0xff00) >> 8);
1785 				break;
1786 #endif
1787 			default:
1788 				DPRINTK("bad depth %u\n",
1789 						i->current_par.depth);
1790 				break;
1791 		}
1792 	}
1793 	if (regno<256) {
1794 		i->palette[regno].red=red >> 8;
1795 		i->palette[regno].green=green >> 8;
1796 		i->palette[regno].blue=blue >> 8;
1797 		i->palette[regno].transp=transp >> 8;
1798 		if (i->current_par.depth==8)
1799 			set_color(i, regno, red>>8, green>>8, blue>>8);
1800 	}
1801 	return regno>255;
1802 }
1803 
pm2fb_set_disp(const void * par,struct display * disp,struct fb_info_gen * info)1804 static void pm2fb_set_disp(const void* par, struct display* disp,
1805 						   struct fb_info_gen* info) {
1806 	struct pm2fb_info* i=(struct pm2fb_info* )info;
1807 	unsigned long flags;
1808 	unsigned long depth;
1809 
1810 	save_flags(flags);
1811 	cli();
1812 	disp->screen_base = i->regions.v_fb;
1813 	switch (depth=((struct pm2fb_par* )par)->depth) {
1814 #ifdef FBCON_HAS_CFB8
1815 		case 8:
1816 			disp->dispsw=&pm2_cfb8;
1817 			break;
1818 #endif
1819 #ifdef FBCON_HAS_CFB16
1820 		case 16:
1821 			disp->dispsw=&pm2_cfb16;
1822 			disp->dispsw_data=i->cmap.cmap16;
1823 			break;
1824 #endif
1825 #ifdef FBCON_HAS_CFB24
1826 		case 24:
1827 			disp->dispsw=&pm2_cfb24;
1828 			disp->dispsw_data=i->cmap.cmap24;
1829 			break;
1830 #endif
1831 #ifdef FBCON_HAS_CFB32
1832 		case 32:
1833 			disp->dispsw=&pm2_cfb32;
1834 			disp->dispsw_data=i->cmap.cmap32;
1835 			break;
1836 #endif
1837 		default:
1838 			disp->dispsw=&fbcon_dummy;
1839 			break;
1840 	}
1841 	restore_flags(flags);
1842 }
1843 
1844 #ifdef PM2FB_HW_CURSOR
1845 /***************************************************************************
1846  * Hardware cursor support
1847  ***************************************************************************/
1848 
1849 static u8 cursor_bits_lookup[16] = {
1850 	0x00, 0x40, 0x10, 0x50, 0x04, 0x44, 0x14, 0x54,
1851 	0x01, 0x41, 0x11, 0x51, 0x05, 0x45, 0x15, 0x55
1852 };
1853 
1854 static u8 cursor_mask_lookup[16] = {
1855 	0x00, 0x80, 0x20, 0xa0, 0x08, 0x88, 0x28, 0xa8,
1856 	0x02, 0x82, 0x22, 0xa2, 0x0a, 0x8a, 0x2a, 0xaa
1857 };
1858 
pm2v_set_cursor_color(struct pm2fb_info * fb,u8 * red,u8 * green,u8 * blue)1859 static void pm2v_set_cursor_color(struct pm2fb_info *fb, u8 *red, u8 *green, u8 *blue)
1860 {
1861 	struct pm2_cursor *c = fb->cursor;
1862 	int i;
1863 
1864 	for (i = 0; i < 2; i++) {
1865 		c->color[3*i] = red[i];
1866 		c->color[3*i+1] = green[i];
1867 		c->color[3*i+2] = blue[i];
1868 	}
1869 
1870 	WAIT_FIFO(fb, 14);
1871 	pm2_WR(fb, PM2VR_RD_INDEX_HIGH, PM2VI_RD_CURSOR_PALETTE >> 8);
1872 	for (i = 0; i < 6; i++)
1873 		pm2v_RDAC_WR(fb, PM2VI_RD_CURSOR_PALETTE+i, c->color[i]);
1874 	pm2_WR(fb, PM2VR_RD_INDEX_HIGH, 0);
1875 }
1876 
pm2v_set_cursor_shape(struct pm2fb_info * fb)1877 static void pm2v_set_cursor_shape(struct pm2fb_info *fb)
1878 {
1879 	struct pm2_cursor *c = fb->cursor;
1880 	u8 m, b;
1881 	int i, x, y;
1882 
1883 	WAIT_FIFO(fb, 1);
1884 	pm2_WR(fb, PM2VR_RD_INDEX_HIGH, PM2VI_RD_CURSOR_PATTERN >> 8);
1885 	for (y = 0, i = 0; y < c->size.y; y++) {
1886 		WAIT_FIFO(fb, 32);
1887 		for (x = 0; x < c->size.x >> 3; x++) {
1888 			m = c->mask[x][y];
1889 			b = c->bits[x][y];
1890 			pm2v_RDAC_WR(fb, PM2VI_RD_CURSOR_PATTERN + i,
1891 				     cursor_mask_lookup[m >> 4] |
1892 				     cursor_bits_lookup[(b & m) >> 4]);
1893 			pm2v_RDAC_WR(fb, PM2VI_RD_CURSOR_PATTERN + i + 1,
1894 				     cursor_mask_lookup[m & 0x0f] |
1895 				     cursor_bits_lookup[(b & m) & 0x0f]);
1896 			i+=2;
1897 		}
1898 		for ( ; x < 8; x++) {
1899 			pm2v_RDAC_WR(fb, PM2VI_RD_CURSOR_PATTERN + i, 0);
1900 			pm2v_RDAC_WR(fb, PM2VI_RD_CURSOR_PATTERN + i + 1, 0);
1901 			i+=2;
1902 		}
1903 	}
1904 	for (; y < 64; y++) {
1905 		WAIT_FIFO(fb, 32);
1906 		for (x = 0; x < 8; x++) {
1907 			pm2v_RDAC_WR(fb, PM2VI_RD_CURSOR_PATTERN + i, 0);
1908 			pm2v_RDAC_WR(fb, PM2VI_RD_CURSOR_PATTERN + i + 1, 0);
1909 			i+=2;
1910 		}
1911 	}
1912 	WAIT_FIFO(fb, 1);
1913 	pm2_WR(fb, PM2VR_RD_INDEX_HIGH, 0);
1914 }
1915 
pm2v_set_cursor(struct pm2fb_info * fb,int on)1916 static void pm2v_set_cursor(struct pm2fb_info *fb, int on)
1917 {
1918 	struct pm2_cursor *c = fb->cursor;
1919 	int x = c->pos.x;
1920 
1921 	if (!on) x = 4000;
1922 	WAIT_FIFO(fb, 14);
1923 	pm2v_RDAC_WR(fb, PM2VI_RD_CURSOR_X_LOW, x & 0xff);
1924 	pm2v_RDAC_WR(fb, PM2VI_RD_CURSOR_X_HIGH, (x >> 8) & 0x0f);
1925 	pm2v_RDAC_WR(fb, PM2VI_RD_CURSOR_Y_LOW, c->pos.y & 0xff);
1926 	pm2v_RDAC_WR(fb, PM2VI_RD_CURSOR_Y_HIGH, (c->pos.y >> 8) & 0x0f);
1927 	pm2v_RDAC_WR(fb, PM2VI_RD_CURSOR_X_HOT, c->hot.x & 0x3f);
1928 	pm2v_RDAC_WR(fb, PM2VI_RD_CURSOR_Y_HOT, c->hot.y & 0x3f);
1929 	pm2v_RDAC_WR(fb, PM2VI_RD_CURSOR_MODE, 0x11);
1930 }
1931 
pm2_cursor_timer_handler(unsigned long dev_addr)1932 static void pm2_cursor_timer_handler(unsigned long dev_addr)
1933 {
1934 	struct pm2fb_info *fb = (struct pm2fb_info *)dev_addr;
1935 
1936 	if (!fb->cursor->enable)
1937 		goto out;
1938 
1939 	if (fb->cursor->vbl_cnt && --fb->cursor->vbl_cnt == 0) {
1940 		fb->cursor->on ^= 1;
1941 		pm2v_set_cursor(fb, fb->cursor->on);
1942 		fb->cursor->vbl_cnt = fb->cursor->blink_rate;
1943 	}
1944 
1945 out:
1946 	fb->cursor->timer->expires = jiffies + (HZ / 50);
1947 	add_timer(fb->cursor->timer);
1948 }
1949 
pm2fb_cursor(struct display * p,int mode,int x,int y)1950 static void pm2fb_cursor(struct display *p, int mode, int x, int y)
1951 {
1952 	struct pm2fb_info *fb = (struct pm2fb_info *)p->fb_info;
1953 	struct pm2_cursor *c = fb->cursor;
1954 
1955 	if (!c) return;
1956 
1957 	x *= fontwidth(p);
1958 	y *= fontheight(p);
1959 	if (c->pos.x == x && c->pos.y == y && (mode == CM_ERASE) == !c->enable)
1960 		return;
1961 
1962 	c->enable = 0;
1963 	if (c->on)
1964 		pm2v_set_cursor(fb, 0);
1965 	c->pos.x = x;
1966 	c->pos.y = y;
1967 
1968 	switch (mode) {
1969 	case CM_ERASE:
1970 		c->on = 0;
1971 		break;
1972 
1973 	case CM_DRAW:
1974 	case CM_MOVE:
1975 		if (c->on)
1976 			pm2v_set_cursor(fb, 1);
1977 		else
1978 			c->vbl_cnt = CURSOR_DRAW_DELAY;
1979 		c->enable = 1;
1980 		break;
1981 	}
1982 }
1983 
pm2_init_cursor(struct pm2fb_info * fb)1984 static struct pm2_cursor * __init pm2_init_cursor(struct pm2fb_info *fb)
1985 {
1986 	struct pm2_cursor *cursor;
1987 
1988 	if (fb->type != PM2_TYPE_PERMEDIA2V)
1989 		return 0; /* FIXME: Support hw cursor everywhere */
1990 
1991 	cursor = kmalloc(sizeof(struct pm2_cursor), GFP_ATOMIC);
1992 	if (!cursor)
1993 		return 0;
1994 	memset(cursor, 0, sizeof(*cursor));
1995 
1996 	cursor->timer = kmalloc(sizeof(*cursor->timer), GFP_KERNEL);
1997 	if (!cursor->timer) {
1998 		kfree(cursor);
1999 		return 0;
2000 	}
2001 	memset(cursor->timer, 0, sizeof(*cursor->timer));
2002 
2003 	cursor->blink_rate = DEFAULT_CURSOR_BLINK_RATE;
2004 
2005 	if (curblink) {
2006 		init_timer(cursor->timer);
2007 		cursor->timer->expires = jiffies + (HZ / 50);
2008 		cursor->timer->data = (unsigned long)fb;
2009 		cursor->timer->function = pm2_cursor_timer_handler;
2010 		add_timer(cursor->timer);
2011 	}
2012 
2013 	return cursor;
2014 }
2015 
pm2fb_set_font(struct display * d,int width,int height)2016 static int pm2fb_set_font(struct display *d, int width, int height)
2017 {
2018 	struct pm2fb_info *fb = (struct pm2fb_info *)d->fb_info;
2019 	struct pm2_cursor *c = fb->cursor;
2020 	int i, j;
2021 
2022 	if (c) {
2023 		if (!width || !height) {
2024 			width = 8;
2025 			height = 16;
2026 		}
2027 
2028 		c->hot.x = 0;
2029 		c->hot.y = 0;
2030 		c->size.x = width;
2031 		c->size.y = height;
2032 
2033 		memset(c->bits, 0xff, sizeof(c->bits));
2034 		memset(c->mask, 0, sizeof(c->mask));
2035 
2036 		for (i = 0, j = width; j >= 0; j -= 8, i++) {
2037 			c->mask[i][height-2] = (j >= 8) ? 0xff : (0xff << (8 - j));
2038 			c->mask[i][height-1] = (j >= 8) ? 0xff : (0xff << (8 - j));
2039 		}
2040 
2041 		pm2v_set_cursor_color(fb, cursor_color_map, cursor_color_map, cursor_color_map);
2042 		pm2v_set_cursor_shape(fb);
2043 	}
2044 	return 1;
2045 }
2046 #endif /* PM2FB_HW_CURSOR */
2047 
2048 /***************************************************************************
2049  * Begin of public functions
2050  ***************************************************************************/
2051 
2052 #ifdef MODULE
pm2fb_cleanup(void)2053 static void pm2fb_cleanup(void) {
2054 	struct pm2fb_info* i = &fb_info;
2055 
2056 	unregister_framebuffer((struct fb_info *)i);
2057 	pm2fb_reset(i);
2058 
2059 	UNMAP(i->regions.v_fb, i->regions.fb_size);
2060 	release_mem_region(i->regions.p_fb, i->regions.fb_size);
2061 
2062 	UNMAP(i->regions.v_regs, PM2_REGS_SIZE);
2063 	release_mem_region(i->regions.p_regs, PM2_REGS_SIZE);
2064 
2065 	if (board_table[i->board].cleanup)
2066 		board_table[i->board].cleanup(i);
2067 }
2068 #endif /* MODULE */
2069 
pm2fb_init(void)2070 int __init pm2fb_init(void){
2071 
2072 	MOD_INC_USE_COUNT;
2073 	memset(&fb_info, 0, sizeof(fb_info));
2074 	memcpy(&fb_info.current_par, &pm2fb_options.user_mode, sizeof(fb_info.current_par));
2075 	if (!pm2fb_conf(&fb_info)) {
2076 		MOD_DEC_USE_COUNT;
2077 		return -ENXIO;
2078 	}
2079 	pm2fb_reset(&fb_info);
2080 	fb_info.disp.scrollmode=SCROLL_YNOMOVE;
2081 	fb_info.gen.parsize=sizeof(struct pm2fb_par);
2082 	fb_info.gen.fbhw=&pm2fb_hwswitch;
2083 	strcpy(fb_info.gen.info.modename, permedia2_name);
2084 	fb_info.gen.info.flags=FBINFO_FLAG_DEFAULT;
2085 	fb_info.gen.info.fbops=&pm2fb_ops;
2086 	fb_info.gen.info.disp=&fb_info.disp;
2087 	strcpy(fb_info.gen.info.fontname, pm2fb_options.font);
2088 	fb_info.gen.info.switch_con=&fbgen_switch;
2089 	fb_info.gen.info.updatevar=&fbgen_update_var;
2090 	fb_info.gen.info.blank=&fbgen_blank;
2091 	fbgen_get_var(&fb_info.disp.var, -1, &fb_info.gen.info);
2092 	fbgen_do_set_var(&fb_info.disp.var, 1, &fb_info.gen);
2093 	fbgen_set_disp(-1, &fb_info.gen);
2094 	fbgen_install_cmap(0, &fb_info.gen);
2095 	if (register_framebuffer(&fb_info.gen.info)<0) {
2096 		printk(KERN_ERR "pm2fb: unable to register.\n");
2097 		MOD_DEC_USE_COUNT;
2098 		return -EINVAL;
2099 	}
2100 	printk(KERN_INFO "fb%d: %s (%s), using %uK of video memory.\n",
2101 				GET_FB_IDX(fb_info.gen.info.node),
2102 				board_table[fb_info.board].name,
2103 				permedia2_name,
2104 				(u32 )(fb_info.regions.fb_size>>10));
2105 	return 0;
2106 }
2107 
pm2fb_mode_setup(char * options)2108 static void __init pm2fb_mode_setup(char* options){
2109 	int i;
2110 
2111 	for (i=0; user_mode[i].name[0] &&
2112 		strcmp(options, user_mode[i].name); i++);
2113 	if (user_mode[i].name[0]) {
2114 		memcpy(&pm2fb_options.user_mode, &user_mode[i].par,
2115 					sizeof(pm2fb_options.user_mode));
2116 		pm2fb_options.flags |= OPTF_USER;
2117 	}
2118 }
2119 
pm2fb_font_setup(char * options)2120 static void __init pm2fb_font_setup(char* options){
2121 
2122 	strncpy(pm2fb_options.font, options, sizeof(pm2fb_options.font));
2123 	pm2fb_options.font[sizeof(pm2fb_options.font)-1]='\0';
2124 }
2125 
pm2fb_setup(char * options)2126 int __init pm2fb_setup(char* options){
2127 	char* next;
2128 
2129 	while (options) {
2130 		if ((next=strchr(options, ',')))
2131 			*(next++)='\0';
2132 		if (!strncmp(options, "font:", 5))
2133 			pm2fb_font_setup(options+5);
2134 		else if (!strncmp(options, "mode:", 5))
2135 			pm2fb_mode_setup(options+5);
2136 		else if (!strcmp(options, "ypan"))
2137 			pm2fb_options.flags |= OPTF_YPAN;
2138 		else if (!strcmp(options, "oldmem"))
2139 			pm2fb_options.flags |= OPTF_OLD_MEM;
2140 		else if (!strcmp(options, "virtual"))
2141 			pm2fb_options.flags |= OPTF_VIRTUAL;
2142 		else if (!strcmp(options, "noblink"))
2143 			curblink = 0;
2144 		options=next;
2145 	}
2146 	return 0;
2147 }
2148 
2149 /***************************************************************************
2150  * Begin of module functions
2151  ***************************************************************************/
2152 
2153 #ifdef MODULE
2154 
2155 MODULE_LICENSE("GPL");
2156 
2157 static char *mode = NULL;
2158 
2159 MODULE_PARM(mode, "s");
2160 
init_module(void)2161 int __init init_module(void) {
2162 
2163 	if (mode) pm2fb_mode_setup(mode);
2164 	return pm2fb_init();
2165 }
2166 
cleanup_module(void)2167 void cleanup_module(void) {
2168 
2169 	pm2fb_cleanup();
2170 }
2171 #endif /* MODULE */
2172 
2173 /***************************************************************************
2174  * That's all folks!
2175  ***************************************************************************/
2176