File: /usr/src/linux/drivers/video/imsttfb.c

1     /*
2      *  drivers/video/imsttfb.c -- frame buffer device for IMS TwinTurbo
3      *
4      *  This file is derived from the powermac console "imstt" driver:
5      *  Copyright (C) 1997 Sigurdur Asgeirsson
6      *  With additional hacking by Jeffrey Kuskin (jsk@mojave.stanford.edu)
7      *  Modified by Danilo Beuche 1998
8      *  Some register values added by Damien Doligez, INRIA Rocquencourt
9      *  Various cleanups by Paul Mundt (lethal@chaoticdreams.org)
10      *
11      *  This file was written by Ryan Nielsen (ran@krazynet.com)
12      *  Most of the frame buffer device stuff was copied from atyfb.c
13      *
14      *  This file is subject to the terms and conditions of the GNU General Public
15      *  License. See the file COPYING in the main directory of this archive for
16      *  more details.
17      */
18     
19     #include <linux/config.h>
20     #include <linux/module.h>
21     #include <linux/kernel.h>
22     #include <linux/errno.h>
23     #include <linux/string.h>
24     #include <linux/mm.h>
25     #include <linux/tty.h>
26     #include <linux/slab.h>
27     #include <linux/vmalloc.h>
28     #include <linux/delay.h>
29     #include <linux/interrupt.h>
30     #include <linux/fb.h>
31     #include <linux/console.h>
32     #include <linux/selection.h>
33     #include <linux/init.h>
34     #include <linux/pci.h>
35     #include <asm/io.h>
36     #include <asm/uaccess.h>
37     
38     #if defined(CONFIG_PPC)
39     #include <linux/nvram.h>
40     #include <asm/prom.h>
41     #include <asm/pci-bridge.h>
42     #include <video/macmodes.h>
43     #endif
44     
45     #include <video/fbcon.h>
46     #include <video/fbcon-cfb8.h>
47     #include <video/fbcon-cfb16.h>
48     #include <video/fbcon-cfb24.h>
49     #include <video/fbcon-cfb32.h>
50     
51     #ifndef __powerpc__
52     #define eieio()		/* Enforce In-order Execution of I/O */
53     #endif
54     
55     /* TwinTurbo (Cosmo) registers */
56     enum {
57     	S1SA	=  0, /* 0x00 */
58     	S2SA	=  1, /* 0x04 */
59     	SP	=  2, /* 0x08 */
60     	DSA	=  3, /* 0x0C */
61     	CNT	=  4, /* 0x10 */
62     	DP_OCTL	=  5, /* 0x14 */
63     	CLR	=  6, /* 0x18 */
64     	BI	=  8, /* 0x20 */
65     	MBC	=  9, /* 0x24 */
66     	BLTCTL	= 10, /* 0x28 */
67     
68     	/* Scan Timing Generator Registers */
69     	HES	= 12, /* 0x30 */
70     	HEB	= 13, /* 0x34 */
71     	HSB	= 14, /* 0x38 */
72     	HT	= 15, /* 0x3C */
73     	VES	= 16, /* 0x40 */
74     	VEB	= 17, /* 0x44 */
75     	VSB	= 18, /* 0x48 */
76     	VT	= 19, /* 0x4C */
77     	HCIV	= 20, /* 0x50 */
78     	VCIV	= 21, /* 0x54 */
79     	TCDR	= 22, /* 0x58 */
80     	VIL	= 23, /* 0x5C */
81     	STGCTL	= 24, /* 0x60 */
82     
83     	/* Screen Refresh Generator Registers */
84     	SSR	= 25, /* 0x64 */
85     	HRIR	= 26, /* 0x68 */
86     	SPR	= 27, /* 0x6C */
87     	CMR	= 28, /* 0x70 */
88     	SRGCTL	= 29, /* 0x74 */
89     
90     	/* RAM Refresh Generator Registers */
91     	RRCIV	= 30, /* 0x78 */
92     	RRSC	= 31, /* 0x7C */
93     	RRCR	= 34, /* 0x88 */
94     
95     	/* System Registers */
96     	GIOE	= 32, /* 0x80 */
97     	GIO	= 33, /* 0x84 */
98     	SCR	= 35, /* 0x8C */
99     	SSTATUS	= 36, /* 0x90 */
100     	PRC	= 37, /* 0x94 */
101     
102     #if 0	
103     	/* PCI Registers */
104     	DVID	= 0x00000000L,
105     	SC	= 0x00000004L,
106     	CCR	= 0x00000008L,
107     	OG	= 0x0000000CL,
108     	BARM	= 0x00000010L,
109     	BARER	= 0x00000030L,
110     #endif
111     };
112     
113     /* IBM 624 RAMDAC Direct Registers */
114     enum {
115     	PADDRW	= 0x00,
116     	PDATA	= 0x04,
117     	PPMASK	= 0x08,
118     	PADDRR	= 0x0c,
119     	PIDXLO	= 0x10,	
120     	PIDXHI	= 0x14,	
121     	PIDXDATA= 0x18,
122     	PIDXCTL	= 0x1c
123     };
124     
125     /* IBM 624 RAMDAC Indirect Registers */
126     enum {
127     	CLKCTL		= 0x02,	/* (0x01) Miscellaneous Clock Control */
128     	SYNCCTL		= 0x03,	/* (0x00) Sync Control */
129     	HSYNCPOS	= 0x04,	/* (0x00) Horizontal Sync Position */
130     	PWRMNGMT	= 0x05,	/* (0x00) Power Management */
131     	DACOP		= 0x06,	/* (0x02) DAC Operation */
132     	PALETCTL	= 0x07,	/* (0x00) Palette Control */
133     	SYSCLKCTL	= 0x08,	/* (0x01) System Clock Control */
134     	PIXFMT		= 0x0a,	/* () Pixel Format  [bpp >> 3 + 2] */
135     	BPP8		= 0x0b,	/* () 8 Bits/Pixel Control */
136     	BPP16		= 0x0c, /* () 16 Bits/Pixel Control  [bit 1=1 for 565] */
137     	BPP24		= 0x0d,	/* () 24 Bits/Pixel Control */
138     	BPP32		= 0x0e,	/* () 32 Bits/Pixel Control */
139     	PIXCTL1		= 0x10, /* (0x05) Pixel PLL Control 1 */
140     	PIXCTL2		= 0x11,	/* (0x00) Pixel PLL Control 2 */
141     	SYSCLKN		= 0x15,	/* () System Clock N (System PLL Reference Divider) */
142     	SYSCLKM		= 0x16,	/* () System Clock M (System PLL VCO Divider) */
143     	SYSCLKP		= 0x17,	/* () System Clock P */
144     	SYSCLKC		= 0x18,	/* () System Clock C */
145     	/*
146     	 * Dot clock rate is 20MHz * (m + 1) / ((n + 1) * (p ? 2 * p : 1)
147     	 * c is charge pump bias which depends on the VCO frequency  
148     	 */
149     	PIXM0		= 0x20,	/* () Pixel M 0 */
150     	PIXN0		= 0x21,	/* () Pixel N 0 */
151     	PIXP0		= 0x22,	/* () Pixel P 0 */
152     	PIXC0		= 0x23,	/* () Pixel C 0 */
153     	CURSCTL		= 0x30,	/* (0x00) Cursor Control */
154     	CURSXLO		= 0x31,	/* () Cursor X position, low 8 bits */
155     	CURSXHI		= 0x32,	/* () Cursor X position, high 8 bits */
156     	CURSYLO		= 0x33,	/* () Cursor Y position, low 8 bits */
157     	CURSYHI		= 0x34,	/* () Cursor Y position, high 8 bits */
158     	CURSHOTX	= 0x35,	/* () Cursor Hot Spot X */
159     	CURSHOTY	= 0x36,	/* () Cursor Hot Spot Y */
160     	CURSACCTL	= 0x37,	/* () Advanced Cursor Control Enable */
161     	CURSACATTR	= 0x38,	/* () Advanced Cursor Attribute */
162     	CURS1R		= 0x40,	/* () Cursor 1 Red */
163     	CURS1G		= 0x41,	/* () Cursor 1 Green */
164     	CURS1B		= 0x42,	/* () Cursor 1 Blue */
165     	CURS2R		= 0x43,	/* () Cursor 2 Red */
166     	CURS2G		= 0x44,	/* () Cursor 2 Green */
167     	CURS2B		= 0x45,	/* () Cursor 2 Blue */
168     	CURS3R		= 0x46,	/* () Cursor 3 Red */
169     	CURS3G		= 0x47,	/* () Cursor 3 Green */
170     	CURS3B		= 0x48,	/* () Cursor 3 Blue */
171     	BORDR		= 0x60,	/* () Border Color Red */
172     	BORDG		= 0x61,	/* () Border Color Green */
173     	BORDB		= 0x62,	/* () Border Color Blue */
174     	MISCTL1		= 0x70,	/* (0x00) Miscellaneous Control 1 */
175     	MISCTL2		= 0x71,	/* (0x00) Miscellaneous Control 2 */
176     	MISCTL3		= 0x72,	/* (0x00) Miscellaneous Control 3 */
177     	KEYCTL		= 0x78	/* (0x00) Key Control/DB Operation */
178     };
179     
180     /* TI TVP 3030 RAMDAC Direct Registers */
181     enum {
182     	TVPADDRW = 0x00,	/* 0  Palette/Cursor RAM Write Address/Index */
183     	TVPPDATA = 0x04,	/* 1  Palette Data RAM Data */
184     	TVPPMASK = 0x08,	/* 2  Pixel Read-Mask */
185     	TVPPADRR = 0x0c,	/* 3  Palette/Cursor RAM Read Address */
186     	TVPCADRW = 0x10,	/* 4  Cursor/Overscan Color Write Address */
187     	TVPCDATA = 0x14,	/* 5  Cursor/Overscan Color Data */
188     				/* 6  reserved */
189     	TVPCADRR = 0x1c,	/* 7  Cursor/Overscan Color Read Address */
190     				/* 8  reserved */
191     	TVPDCCTL = 0x24,	/* 9  Direct Cursor Control */
192     	TVPIDATA = 0x28,	/* 10 Index Data */
193     	TVPCRDAT = 0x2c,	/* 11 Cursor RAM Data */
194     	TVPCXPOL = 0x30,	/* 12 Cursor-Position X LSB */
195     	TVPCXPOH = 0x34,	/* 13 Cursor-Position X MSB */
196     	TVPCYPOL = 0x38,	/* 14 Cursor-Position Y LSB */
197     	TVPCYPOH = 0x3c,	/* 15 Cursor-Position Y MSB */
198     };
199     
200     /* TI TVP 3030 RAMDAC Indirect Registers */
201     enum {
202     	TVPIRREV = 0x01,	/* Silicon Revision [RO] */
203     	TVPIRICC = 0x06,	/* Indirect Cursor Control 	(0x00) */
204     	TVPIRBRC = 0x07,	/* Byte Router Control 	(0xe4) */
205     	TVPIRLAC = 0x0f,	/* Latch Control 		(0x06) */
206     	TVPIRTCC = 0x18,	/* True Color Control  	(0x80) */
207     	TVPIRMXC = 0x19,	/* Multiplex Control		(0x98) */
208     	TVPIRCLS = 0x1a,	/* Clock Selection		(0x07) */
209     	TVPIRPPG = 0x1c,	/* Palette Page		(0x00) */
210     	TVPIRGEC = 0x1d,	/* General Control 		(0x00) */
211     	TVPIRMIC = 0x1e,	/* Miscellaneous Control	(0x00) */
212     	TVPIRPLA = 0x2c,	/* PLL Address */
213     	TVPIRPPD = 0x2d,	/* Pixel Clock PLL Data */
214     	TVPIRMPD = 0x2e,	/* Memory Clock PLL Data */
215     	TVPIRLPD = 0x2f,	/* Loop Clock PLL Data */
216     	TVPIRCKL = 0x30,	/* Color-Key Overlay Low */
217     	TVPIRCKH = 0x31,	/* Color-Key Overlay High */
218     	TVPIRCRL = 0x32,	/* Color-Key Red Low */
219     	TVPIRCRH = 0x33,	/* Color-Key Red High */
220     	TVPIRCGL = 0x34,	/* Color-Key Green Low */
221     	TVPIRCGH = 0x35,	/* Color-Key Green High */
222     	TVPIRCBL = 0x36,	/* Color-Key Blue Low */
223     	TVPIRCBH = 0x37,	/* Color-Key Blue High */
224     	TVPIRCKC = 0x38,	/* Color-Key Control 		(0x00) */
225     	TVPIRMLC = 0x39,	/* MCLK/Loop Clock Control	(0x18) */
226     	TVPIRSEN = 0x3a,	/* Sense Test			(0x00) */
227     	TVPIRTMD = 0x3b,	/* Test Mode Data */
228     	TVPIRRML = 0x3c,	/* CRC Remainder LSB [RO] */
229     	TVPIRRMM = 0x3d,	/* CRC Remainder MSB [RO] */
230     	TVPIRRMS = 0x3e,	/* CRC  Bit Select [WO] */
231     	TVPIRDID = 0x3f,	/* Device ID [RO] 		(0x30) */
232     	TVPIRRES = 0xff		/* Software Reset [WO] */
233     };
234     
235     struct initvalues {
236     	__u8 addr, value;
237     };
238     
239     static struct initvalues ibm_initregs[] __initdata = {
240     	{ CLKCTL,	0x21 },
241     	{ SYNCCTL,	0x00 },
242     	{ HSYNCPOS,	0x00 },
243     	{ PWRMNGMT,	0x00 },
244     	{ DACOP,	0x02 },
245     	{ PALETCTL,	0x00 },
246     	{ SYSCLKCTL,	0x01 },
247     
248     	/*
249     	 * Note that colors in X are correct only if all video data is
250     	 * passed through the palette in the DAC.  That is, "indirect
251     	 * color" must be configured.  This is the case for the IBM DAC
252     	 * used in the 2MB and 4MB cards, at least.
253     	 */
254     	{ BPP8,		0x00 },
255     	{ BPP16,	0x01 },
256     	{ BPP24,	0x00 },
257     	{ BPP32,	0x00 },
258     
259     	{ PIXCTL1,	0x05 },
260     	{ PIXCTL2,	0x00 },
261     	{ SYSCLKN,	0x08 },
262     	{ SYSCLKM,	0x4f },
263     	{ SYSCLKP,	0x00 },
264     	{ SYSCLKC,	0x00 },
265     	{ CURSCTL,	0x00 },
266     	{ CURSACCTL,	0x01 },
267     	{ CURSACATTR,	0xa8 },
268     	{ CURS1R,	0xff },
269     	{ CURS1G,	0xff },
270     	{ CURS1B,	0xff },
271     	{ CURS2R,	0xff },
272     	{ CURS2G,	0xff },
273     	{ CURS2B,	0xff },
274     	{ CURS3R,	0xff },
275     	{ CURS3G,	0xff },
276     	{ CURS3B,	0xff },
277     	{ BORDR,	0xff },
278     	{ BORDG,	0xff },
279     	{ BORDB,	0xff },
280     	{ MISCTL1,	0x01 },
281     	{ MISCTL2,	0x45 },
282     	{ MISCTL3,	0x00 },
283     	{ KEYCTL,	0x00 }
284     };
285     
286     static struct initvalues tvp_initregs[] __initdata = {
287     	{ TVPIRICC,	0x00 },
288     	{ TVPIRBRC,	0xe4 },
289     	{ TVPIRLAC,	0x06 },
290     	{ TVPIRTCC,	0x80 },
291     	{ TVPIRMXC,	0x4d },
292     	{ TVPIRCLS,	0x05 },
293     	{ TVPIRPPG,	0x00 },
294     	{ TVPIRGEC,	0x00 },
295     	{ TVPIRMIC,	0x08 },
296     	{ TVPIRCKL,	0xff },
297     	{ TVPIRCKH,	0xff },
298     	{ TVPIRCRL,	0xff },
299     	{ TVPIRCRH,	0xff },
300     	{ TVPIRCGL,	0xff },
301     	{ TVPIRCGH,	0xff },
302     	{ TVPIRCBL,	0xff },
303     	{ TVPIRCBH,	0xff },
304     	{ TVPIRCKC,	0x00 },
305     	{ TVPIRPLA,	0x00 },
306     	{ TVPIRPPD,	0xc0 },
307     	{ TVPIRPPD,	0xd5 },
308     	{ TVPIRPPD,	0xea },
309     	{ TVPIRPLA,	0x00 },
310     	{ TVPIRMPD,	0xb9 },
311     	{ TVPIRMPD,	0x3a },
312     	{ TVPIRMPD,	0xb1 },
313     	{ TVPIRPLA,	0x00 },
314     	{ TVPIRLPD,	0xc1 },
315     	{ TVPIRLPD,	0x3d },
316     	{ TVPIRLPD,	0xf3 },
317     };
318     
319     struct imstt_regvals {
320     	__u32 pitch;
321     	__u16 hes, heb, hsb, ht, ves, veb, vsb, vt, vil;
322     	__u8 pclk_m, pclk_n, pclk_p;
323     	/* Values of the tvp which change depending on colormode x resolution */
324     	__u8 mlc[3];	/* Memory Loop Config 0x39 */
325     	__u8 lckl_p[3];	/* P value of LCKL PLL */
326     };
327     
328     struct imstt_cursor {
329     	struct timer_list timer;
330     	int enable;
331     	int on;
332     	int vbl_cnt;
333     	int blink_rate;
334     	__u16 x, y, width, height;
335     };
336     
337     struct fb_info_imstt {
338     	struct fb_info info;
339     	struct fb_fix_screeninfo fix;
340     	struct display disp;
341     	struct display_switch dispsw;
342     	union {
343     #ifdef FBCON_HAS_CFB16
344     		__u16 cfb16[16];
345     #endif
346     #ifdef FBCON_HAS_CFB24
347     		__u32 cfb24[16];
348     #endif
349     #ifdef FBCON_HAS_CFB32
350     		__u32 cfb32[16];
351     #endif
352     	} fbcon_cmap;
353     	struct {
354     		__u8 red, green, blue;
355     	} palette[256];
356     	struct imstt_regvals init;
357     	struct imstt_cursor cursor;
358     	unsigned long frame_buffer_phys;
359     	unsigned long board_size;
360     	__u8 *frame_buffer;
361     	unsigned long dc_regs_phys;
362     	__u32 *dc_regs;
363     	unsigned long cmap_regs_phys;
364     	__u8 *cmap_regs;
365     	__u32 total_vram;
366     	__u32 ramdac;
367     };
368     
369     enum {
370     	IBM = 0,
371     	TVP = 1
372     };
373     
374     #define USE_NV_MODES		1
375     #define INIT_BPP		8
376     #define INIT_XRES		640
377     #define INIT_YRES		480
378     #define CURSOR_BLINK_RATE	20
379     #define CURSOR_DRAW_DELAY	2
380     
381     static int currcon = 0;
382     static int inverse = 0;
383     static char fontname[40] __initdata = { 0 };
384     static char curblink __initdata = 1;
385     static char noaccel __initdata = 0;
386     #if defined(CONFIG_PPC)
387     static signed char init_vmode __initdata = -1, init_cmode __initdata = -1;
388     #endif
389     
390     static struct imstt_regvals tvp_reg_init_2 = {
391     	512,
392     	0x0002, 0x0006, 0x0026, 0x0028, 0x0003, 0x0016, 0x0196, 0x0197, 0x0196,
393     	0xec, 0x2a, 0xf3,
394     	{ 0x3c, 0x3b, 0x39 }, { 0xf3, 0xf3, 0xf3 }
395     };
396     
397     static struct imstt_regvals tvp_reg_init_6 = {
398     	640,
399     	0x0004, 0x0009, 0x0031, 0x0036, 0x0003, 0x002a, 0x020a, 0x020d, 0x020a,
400     	0xef, 0x2e, 0xb2,
401     	{ 0x39, 0x39, 0x38 }, { 0xf3, 0xf3, 0xf3 }
402     };
403     
404     static struct imstt_regvals tvp_reg_init_12 = {
405     	800,
406     	0x0005, 0x000e, 0x0040, 0x0042, 0x0003, 0x018, 0x270, 0x271, 0x270,
407     	0xf6, 0x2e, 0xf2,
408     	{ 0x3a, 0x39, 0x38 }, { 0xf3, 0xf3, 0xf3 }
409     };
410     
411     static struct imstt_regvals tvp_reg_init_13 = {
412     	832,
413     	0x0004, 0x0011, 0x0045, 0x0048, 0x0003, 0x002a, 0x029a, 0x029b, 0x0000,
414     	0xfe, 0x3e, 0xf1,
415     	{ 0x39, 0x38, 0x38 }, { 0xf3, 0xf3, 0xf2 }
416     };
417     
418     static struct imstt_regvals tvp_reg_init_17 = {
419     	1024,
420     	0x0006, 0x0210, 0x0250, 0x0053, 0x1003, 0x0021, 0x0321, 0x0324, 0x0000,
421     	0xfc, 0x3a, 0xf1,
422     	{ 0x39, 0x38, 0x38 }, { 0xf3, 0xf3, 0xf2 }
423     };
424     
425     static struct imstt_regvals tvp_reg_init_18 = {
426     	1152,
427       	0x0009, 0x0011, 0x059, 0x5b, 0x0003, 0x0031, 0x0397, 0x039a, 0x0000, 
428     	0xfd, 0x3a, 0xf1,
429     	{ 0x39, 0x38, 0x38 }, { 0xf3, 0xf3, 0xf2 }
430     };
431     
432     static struct imstt_regvals tvp_reg_init_19 = {
433     	1280,
434     	0x0009, 0x0016, 0x0066, 0x0069, 0x0003, 0x0027, 0x03e7, 0x03e8, 0x03e7,
435     	0xf7, 0x36, 0xf0,
436     	{ 0x38, 0x38, 0x38 }, { 0xf3, 0xf2, 0xf1 }
437     };
438     
439     static struct imstt_regvals tvp_reg_init_20 = {
440     	1280,
441     	0x0009, 0x0018, 0x0068, 0x006a, 0x0003, 0x0029, 0x0429, 0x042a, 0x0000,
442     	0xf0, 0x2d, 0xf0,
443     	{ 0x38, 0x38, 0x38 }, { 0xf3, 0xf2, 0xf1 }
444     };
445     
446     /*
447      * PCI driver prototypes
448      */
449     static int imsttfb_probe(struct pci_dev *pdev, const struct pci_device_id *ent);
450     static void imsttfb_remove(struct pci_dev *pdev);
451     
452     static __u32
453     getclkMHz (struct fb_info_imstt *p)
454     {
455     	__u32 clk_m, clk_n, clk_p;
456     
457     	clk_m = p->init.pclk_m;
458     	clk_n = p->init.pclk_n;
459     	clk_p = p->init.pclk_p;
460     
461     	return 20 * (clk_m + 1) / ((clk_n + 1) * (clk_p ? 2 * clk_p : 1));
462     }
463     
464     static void
465     setclkMHz (struct fb_info_imstt *p, __u32 MHz)
466     {
467     	__u32 clk_m, clk_n, clk_p, x, stage, spilled;
468     
469     	clk_m = clk_n = clk_p = 0;
470     	stage = spilled = 0;
471     	for (;;) {
472     		switch (stage) {
473     			case 0:
474     				clk_m++;
475     				break;
476     			case 1:
477     				clk_n++;
478     				break;
479     		}
480     		x = 20 * (clk_m + 1) / ((clk_n + 1) * (clk_p ? 2 * clk_p : 1));
481     		if (x == MHz)
482     			break;
483     		if (x > MHz) {
484     			spilled = 1;
485     			stage = 1;
486     		} else if (spilled && x < MHz) {
487     			stage = 0;
488     		}
489     	}
490     
491     	p->init.pclk_m = clk_m;
492     	p->init.pclk_n = clk_n;
493     	p->init.pclk_p = clk_p;
494     }
495     
496     static struct imstt_regvals *
497     compute_imstt_regvals_ibm (struct fb_info_imstt *p, int xres, int yres)
498     {
499     	struct imstt_regvals *init = &p->init;
500     	__u32 MHz, hes, heb, veb, htp, vtp;
501     
502     	switch (xres) {
503     		case 640:
504     			hes = 0x0008; heb = 0x0012; veb = 0x002a; htp = 10; vtp = 2;
505     			MHz = 30 /* .25 */ ;
506     			break;
507     		case 832:
508     			hes = 0x0005; heb = 0x0020; veb = 0x0028; htp = 8; vtp = 3;
509     			MHz = 57 /* .27_ */ ;
510     			break;
511     		case 1024:
512     			hes = 0x000a; heb = 0x001c; veb = 0x0020; htp = 8; vtp = 3;
513     			MHz = 80;
514     			break;
515     		case 1152:
516     			hes = 0x0012; heb = 0x0022; veb = 0x0031; htp = 4; vtp = 3;
517     			MHz = 101 /* .6_ */ ;
518     			break;
519     		case 1280:
520     			hes = 0x0012; heb = 0x002f; veb = 0x0029; htp = 4; vtp = 1;
521     			MHz = yres == 960 ? 126 : 135;
522     			break;
523     		case 1600:
524     			hes = 0x0018; heb = 0x0040; veb = 0x002a; htp = 4; vtp = 3;
525     			MHz = 200;
526     			break;
527     		default:
528     			return 0;
529     	}
530     
531     	setclkMHz(p, MHz);
532     
533     	init->hes = hes;
534     	init->heb = heb;
535     	init->hsb = init->heb + (xres >> 3);
536     	init->ht = init->hsb + htp;
537     	init->ves = 0x0003;
538     	init->veb = veb;
539     	init->vsb = init->veb + yres;
540     	init->vt = init->vsb + vtp;
541     	init->vil = init->vsb;
542     
543     	init->pitch = xres;
544     
545     	return init;
546     }
547     
548     static struct imstt_regvals *
549     compute_imstt_regvals_tvp (struct fb_info_imstt *p, int xres, int yres)
550     {
551     	struct imstt_regvals *init;
552     
553     	switch (xres) {
554     		case 512:
555     			init = &tvp_reg_init_2;
556     			break;
557     		case 640:
558     			init = &tvp_reg_init_6;
559     			break;
560     		case 800:
561     			init = &tvp_reg_init_12;
562     			break;
563     		case 832:
564     			init = &tvp_reg_init_13;
565     			break;
566     		case 1024:
567     			init = &tvp_reg_init_17;
568     			break;
569     		case 1152:
570     			init = &tvp_reg_init_18;
571     			break;
572     		case 1280:
573     			init = yres == 960 ? &tvp_reg_init_19 : &tvp_reg_init_20;
574     			break;
575     		default:
576     			return 0;
577     	}
578     	p->init = *init;
579     
580     	return init;
581     }
582     
583     static struct imstt_regvals *
584     compute_imstt_regvals (struct fb_info_imstt *p, u_int xres, u_int yres)
585     {
586     	if (p->ramdac == IBM)
587     		return compute_imstt_regvals_ibm(p, xres, yres);
588     	else
589     		return compute_imstt_regvals_tvp(p, xres, yres);
590     }
591     
592     static void
593     set_imstt_regvals_ibm (struct fb_info_imstt *p, u_int bpp)
594     {
595     	struct imstt_regvals *init = &p->init;
596     	__u8 pformat = (bpp >> 3) + 2;
597     
598     	p->cmap_regs[PIDXHI] = 0;		eieio();
599     	p->cmap_regs[PIDXLO] = PIXM0;		eieio();
600     	p->cmap_regs[PIDXDATA] = init->pclk_m;	eieio();
601     	p->cmap_regs[PIDXLO] = PIXN0;		eieio();
602     	p->cmap_regs[PIDXDATA] = init->pclk_n;	eieio();
603     	p->cmap_regs[PIDXLO] = PIXP0;		eieio();
604     	p->cmap_regs[PIDXDATA] = init->pclk_p;	eieio();
605     	p->cmap_regs[PIDXLO] = PIXC0;		eieio();
606     	p->cmap_regs[PIDXDATA] = 0x02;		eieio();
607     
608     	p->cmap_regs[PIDXLO] = PIXFMT;		eieio();
609     	p->cmap_regs[PIDXDATA] = pformat;	eieio();
610     }
611     
612     static void
613     set_imstt_regvals_tvp (struct fb_info_imstt *p, u_int bpp)
614     {
615     	struct imstt_regvals *init = &p->init;
616     	__u8 tcc, mxc, lckl_n, mic;
617     	__u8 mlc, lckl_p;
618     
619     	switch (bpp) {
620     		case 8:
621     			tcc = 0x80;
622     			mxc = 0x4d;
623     			lckl_n = 0xc1;
624     			mlc = init->mlc[0];
625     			lckl_p = init->lckl_p[0];
626     			break;
627     		case 16:
628     			tcc = 0x44;
629     			mxc = 0x55;
630     			lckl_n = 0xe1;
631     			mlc = init->mlc[1];
632     			lckl_p = init->lckl_p[1];
633     			break;
634     		case 24:
635     			tcc = 0x5e;
636     			mxc = 0x5d;
637     			lckl_n = 0xf1;
638     			mlc = init->mlc[2];
639     			lckl_p = init->lckl_p[2];
640     			break;
641     		case 32:
642     			tcc = 0x46;
643     			mxc = 0x5d;
644     			lckl_n = 0xf1;
645     			mlc = init->mlc[2];
646     			lckl_p = init->lckl_p[2];
647     			break;
648     	}
649     	mic = 0x08;
650     
651     	p->cmap_regs[TVPADDRW] = TVPIRPLA;	eieio();
652     	p->cmap_regs[TVPIDATA] = 0x00;		eieio();
653     	p->cmap_regs[TVPADDRW] = TVPIRPPD;	eieio();
654     	p->cmap_regs[TVPIDATA] = init->pclk_m;	eieio();
655     	p->cmap_regs[TVPADDRW] = TVPIRPPD;	eieio();
656     	p->cmap_regs[TVPIDATA] = init->pclk_n;	eieio();
657     	p->cmap_regs[TVPADDRW] = TVPIRPPD;	eieio();
658     	p->cmap_regs[TVPIDATA] = init->pclk_p;	eieio();
659     
660     	p->cmap_regs[TVPADDRW] = TVPIRTCC;	eieio();
661     	p->cmap_regs[TVPIDATA] = tcc;		eieio();
662     	p->cmap_regs[TVPADDRW] = TVPIRMXC;	eieio();
663     	p->cmap_regs[TVPIDATA] = mxc;		eieio();
664     	p->cmap_regs[TVPADDRW] = TVPIRMIC;	eieio();
665     	p->cmap_regs[TVPIDATA] = mic;		eieio();
666     
667     	p->cmap_regs[TVPADDRW] = TVPIRPLA;	eieio();
668     	p->cmap_regs[TVPIDATA] = 0x00;		eieio();
669     	p->cmap_regs[TVPADDRW] = TVPIRLPD;	eieio();
670     	p->cmap_regs[TVPIDATA] = lckl_n;	eieio();
671     
672     	p->cmap_regs[TVPADDRW] = TVPIRPLA;	eieio();
673     	p->cmap_regs[TVPIDATA] = 0x15;		eieio();
674     	p->cmap_regs[TVPADDRW] = TVPIRMLC;	eieio();
675     	p->cmap_regs[TVPIDATA] = mlc;		eieio();
676     
677     	p->cmap_regs[TVPADDRW] = TVPIRPLA;	eieio();
678     	p->cmap_regs[TVPIDATA] = 0x2a;		eieio();
679     	p->cmap_regs[TVPADDRW] = TVPIRLPD;	eieio();
680     	p->cmap_regs[TVPIDATA] = lckl_p;	eieio();
681     }
682     
683     static void
684     set_imstt_regvals (struct fb_info_imstt *p, u_int bpp)
685     {
686     	struct imstt_regvals *init = &p->init;
687     	__u32 ctl, pitch, byteswap, scr;
688     
689     	if (p->ramdac == IBM)
690     		set_imstt_regvals_ibm(p, bpp);
691     	else
692     		set_imstt_regvals_tvp(p, bpp);
693     
694       /*
695        * From what I (jsk) can gather poking around with MacsBug,
696        * bits 8 and 9 in the SCR register control endianness
697        * correction (byte swapping).  These bits must be set according
698        * to the color depth as follows:
699        *     Color depth    Bit 9   Bit 8
700        *     ==========     =====   =====
701        *        8bpp          0       0
702        *       16bpp          0       1
703        *       32bpp          1       1
704        */
705     	switch (bpp) {
706     		case 8:
707     			ctl = 0x17b1;
708     			pitch = init->pitch >> 2;
709     			byteswap = 0x000;
710     			break;
711     		case 16:
712     			ctl = 0x17b3;
713     			pitch = init->pitch >> 1;
714     			byteswap = 0x100;
715     			break;
716     		case 24:
717     			ctl = 0x17b9;
718     			pitch = init->pitch - (p->init.pitch >> 2);
719     			byteswap = 0x200;
720     			break;
721     		case 32:
722     			ctl = 0x17b5;
723     			pitch = init->pitch;
724     			byteswap = 0x300;
725     			break;
726     	}
727     	if (p->ramdac == TVP)
728     		ctl -= 0x30;
729     
730     	out_le32(&p->dc_regs[HES], init->hes);
731     	out_le32(&p->dc_regs[HEB], init->heb);
732     	out_le32(&p->dc_regs[HSB], init->hsb);
733     	out_le32(&p->dc_regs[HT], init->ht);
734     	out_le32(&p->dc_regs[VES], init->ves);
735     	out_le32(&p->dc_regs[VEB], init->veb);
736     	out_le32(&p->dc_regs[VSB], init->vsb);
737     	out_le32(&p->dc_regs[VT], init->vt);
738     	out_le32(&p->dc_regs[VIL], init->vil);
739     	out_le32(&p->dc_regs[HCIV], 1);
740     	out_le32(&p->dc_regs[VCIV], 1);
741     	out_le32(&p->dc_regs[TCDR], 4);
742     	out_le32(&p->dc_regs[RRCIV], 1);
743     	out_le32(&p->dc_regs[RRSC], 0x980);
744     	out_le32(&p->dc_regs[RRCR], 0x11);
745     
746     	if (p->ramdac == IBM) {
747     		out_le32(&p->dc_regs[HRIR], 0x0100);
748     		out_le32(&p->dc_regs[CMR], 0x00ff);
749     		out_le32(&p->dc_regs[SRGCTL], 0x0073);
750     	} else {
751     		out_le32(&p->dc_regs[HRIR], 0x0200);
752     		out_le32(&p->dc_regs[CMR], 0x01ff);
753     		out_le32(&p->dc_regs[SRGCTL], 0x0003);
754     	}
755     
756     	switch (p->total_vram) {
757     		case 0x200000:
758     			scr = 0x059d | byteswap;
759     			break;
760     		/* case 0x400000:
761     		   case 0x800000: */
762     		default:
763     			pitch >>= 1;
764     			scr = 0x150dd | byteswap;
765     			break;
766     	}
767     
768     	out_le32(&p->dc_regs[SCR], scr);
769     	out_le32(&p->dc_regs[SPR], pitch);
770     	out_le32(&p->dc_regs[STGCTL], ctl);
771     }
772     
773     static inline void
774     set_offset (struct display *disp, struct fb_info_imstt *p)
775     {
776     	__u32 off = disp->var.yoffset * (disp->line_length >> 3)
777     		    + ((disp->var.xoffset * (disp->var.bits_per_pixel >> 3)) >> 3);
778     	out_le32(&p->dc_regs[SSR], off);
779     }
780     
781     static inline void
782     set_555 (struct fb_info_imstt *p)
783     {
784     	if (p->ramdac == IBM) {
785     		p->cmap_regs[PIDXHI] = 0;	eieio();
786     		p->cmap_regs[PIDXLO] = BPP16;	eieio();
787     		p->cmap_regs[PIDXDATA] = 0x01;	eieio();
788     	} else {
789     		p->cmap_regs[TVPADDRW] = TVPIRTCC;	eieio();
790     		p->cmap_regs[TVPIDATA] = 0x44;		eieio();
791     	}
792     }
793     
794     static inline void
795     set_565 (struct fb_info_imstt *p)
796     {
797     	if (p->ramdac == IBM) {
798     		p->cmap_regs[PIDXHI] = 0;	eieio();
799     		p->cmap_regs[PIDXLO] = BPP16;	eieio();
800     		p->cmap_regs[PIDXDATA] = 0x03;	eieio();
801     	} else {
802     		p->cmap_regs[TVPADDRW] = TVPIRTCC;	eieio();
803     		p->cmap_regs[TVPIDATA] = 0x45;		eieio();
804     	}
805     }
806     
807     static void
808     imstt_set_cursor (struct fb_info_imstt *p, int on)
809     {
810     	struct imstt_cursor *c = &p->cursor;
811     
812     	if (p->ramdac == IBM) {
813     		p->cmap_regs[PIDXHI] = 0;	eieio();
814     		if (!on) {
815     			p->cmap_regs[PIDXLO] = CURSCTL;	eieio();
816     			p->cmap_regs[PIDXDATA] = 0x00;	eieio();
817     		} else {
818     			p->cmap_regs[PIDXLO] = CURSXHI;		eieio();
819     			p->cmap_regs[PIDXDATA] = c->x >> 8;	eieio();
820     			p->cmap_regs[PIDXLO] = CURSXLO;		eieio();
821     			p->cmap_regs[PIDXDATA] = c->x & 0xff;	eieio();
822     			p->cmap_regs[PIDXLO] = CURSYHI;		eieio();
823     			p->cmap_regs[PIDXDATA] = c->y >> 8;	eieio();
824     			p->cmap_regs[PIDXLO] = CURSYLO;		eieio();
825     			p->cmap_regs[PIDXDATA] = c->y & 0xff;	eieio();
826     			p->cmap_regs[PIDXLO] = CURSCTL;		eieio();
827     			p->cmap_regs[PIDXDATA] = 0x02;		eieio();
828     		}
829     	} else {
830     		if (!on) {
831     			p->cmap_regs[TVPADDRW] = TVPIRICC;	eieio();
832     			p->cmap_regs[TVPIDATA] = 0x00;		eieio();
833     		} else {
834     			__u16 x = c->x + 0x40, y = c->y + 0x40;
835     
836     			p->cmap_regs[TVPCXPOH] = x >> 8;	eieio();
837     			p->cmap_regs[TVPCXPOL] = x & 0xff;	eieio();
838     			p->cmap_regs[TVPCYPOH] = y >> 8;	eieio();
839     			p->cmap_regs[TVPCYPOL] = y & 0xff;	eieio();
840     			p->cmap_regs[TVPADDRW] = TVPIRICC;	eieio();
841     			p->cmap_regs[TVPIDATA] = 0x02;		eieio();
842     		}
843     	}
844     }
845     
846     static void
847     imsttfbcon_cursor (struct display *disp, int mode, int x, int y)
848     {
849     	struct fb_info_imstt *p = (struct fb_info_imstt *)disp->fb_info;
850     	struct imstt_cursor *c = &p->cursor;
851     
852     	x *= fontwidth(disp);
853     	y *= fontheight(disp);
854     
855     	if (c->x == x && c->y == y && (mode == CM_ERASE) == !c->enable)
856     		return;
857     
858     	c->enable = 0;
859     	if (c->on)
860     		imstt_set_cursor(p, 0);
861     	c->x = x - disp->var.xoffset;
862     	c->y = y - disp->var.yoffset;
863     
864     	switch (mode) {
865     		case CM_ERASE:
866     			c->on = 0;
867     			break;
868     		case CM_DRAW:
869     		case CM_MOVE:
870     			if (c->on)
871     				imstt_set_cursor(p, c->on);
872     			else
873     				c->vbl_cnt = CURSOR_DRAW_DELAY;
874     			c->enable = 1;
875     			break;
876     	}
877     }
878     
879     static int
880     imsttfbcon_set_font (struct display *disp, int width, int height)
881     {
882     	struct fb_info_imstt *p = (struct fb_info_imstt *)disp->fb_info;
883     	struct imstt_cursor *c = &p->cursor;
884     	u_int x, y;
885     	__u8 fgc;
886     
887     	if (width > 32 || height > 32)
888     		return -EINVAL;
889     
890     	c->height = height;
891     	c->width = width;
892     
893     	fgc = ~attr_bgcol_ec(disp, disp->conp);
894     
895     	if (p->ramdac == IBM) {
896     		p->cmap_regs[PIDXHI] = 1;	eieio();
897     		for (x = 0; x < 0x100; x++) {
898     			p->cmap_regs[PIDXLO] = x;	eieio();
899     			p->cmap_regs[PIDXDATA] = 0x00;	eieio();
900     		}
901     		p->cmap_regs[PIDXHI] = 1;	eieio();
902     		for (y = 0; y < height; y++)
903     			for (x = 0; x < width >> 2; x++) {
904     				p->cmap_regs[PIDXLO] = x + y * 8;	eieio();
905     				p->cmap_regs[PIDXDATA] = 0xff;		eieio();
906     			}
907     		p->cmap_regs[PIDXHI] = 0;	eieio();
908     		p->cmap_regs[PIDXLO] = CURS1R;	eieio();
909     		p->cmap_regs[PIDXDATA] = fgc;	eieio();
910     		p->cmap_regs[PIDXLO] = CURS1G;	eieio();
911     		p->cmap_regs[PIDXDATA] = fgc;	eieio();
912     		p->cmap_regs[PIDXLO] = CURS1B;	eieio();
913     		p->cmap_regs[PIDXDATA] = fgc;	eieio();
914     		p->cmap_regs[PIDXLO] = CURS2R;	eieio();
915     		p->cmap_regs[PIDXDATA] = fgc;	eieio();
916     		p->cmap_regs[PIDXLO] = CURS2G;	eieio();
917     		p->cmap_regs[PIDXDATA] = fgc;	eieio();
918     		p->cmap_regs[PIDXLO] = CURS2B;	eieio();
919     		p->cmap_regs[PIDXDATA] = fgc;	eieio();
920     		p->cmap_regs[PIDXLO] = CURS3R;	eieio();
921     		p->cmap_regs[PIDXDATA] = fgc;	eieio();
922     		p->cmap_regs[PIDXLO] = CURS3G;	eieio();
923     		p->cmap_regs[PIDXDATA] = fgc;	eieio();
924     		p->cmap_regs[PIDXLO] = CURS3B;	eieio();
925     		p->cmap_regs[PIDXDATA] = fgc;	eieio();
926     	} else {
927     		p->cmap_regs[TVPADDRW] = TVPIRICC;	eieio();
928     		p->cmap_regs[TVPIDATA] &= 0x03;		eieio();
929     		p->cmap_regs[TVPADDRW] = 0;		eieio();
930     		for (x = 0; x < 0x200; x++) {
931     			p->cmap_regs[TVPCRDAT] = 0x00;	eieio();
932     		}
933     		for (x = 0; x < 0x200; x++) {
934     			p->cmap_regs[TVPCRDAT] = 0xff;	eieio();
935     		}
936     		p->cmap_regs[TVPADDRW] = TVPIRICC;	eieio();
937     		p->cmap_regs[TVPIDATA] &= 0x03;		eieio();
938     		for (y = 0; y < height; y++)
939     			for (x = 0; x < width >> 3; x++) {
940     				p->cmap_regs[TVPADDRW] = x + y * 8;	eieio();
941     				p->cmap_regs[TVPCRDAT] = 0xff;		eieio();
942     			}
943     		p->cmap_regs[TVPADDRW] = TVPIRICC;	eieio();
944     		p->cmap_regs[TVPIDATA] |= 0x08;		eieio();
945     		for (y = 0; y < height; y++)
946     			for (x = 0; x < width >> 3; x++) {
947     				p->cmap_regs[TVPADDRW] = x + y * 8;	eieio();
948     				p->cmap_regs[TVPCRDAT] = 0xff;		eieio();
949     			}
950     		p->cmap_regs[TVPCADRW] = 0x00;	eieio();
951     		for (x = 0; x < 12; x++) {
952     			p->cmap_regs[TVPCDATA] = fgc;	eieio();
953     		}
954     	}
955     
956     	return 1;
957     }
958     
959     static void
960     imstt_cursor_timer_handler (unsigned long dev_addr)
961     {
962     	struct fb_info_imstt *p = (struct fb_info_imstt *)dev_addr;
963     	struct imstt_cursor *c = &p->cursor;
964     
965     	if (!c->enable)
966     		goto out;
967     
968     	if (c->vbl_cnt && --c->vbl_cnt == 0) {
969     		c->on ^= 1;
970     		imstt_set_cursor(p, c->on);
971     		c->vbl_cnt = c->blink_rate;
972     	}
973     
974     out:
975     	c->timer.expires = jiffies + (HZ / 50);
976     	add_timer(&c->timer);
977     }
978     
979     static void __init 
980     imstt_cursor_init (struct fb_info_imstt *p)
981     {
982     	struct imstt_cursor *c = &p->cursor;
983     
984     	imsttfbcon_set_font(&p->disp, fontwidth(&p->disp), fontheight(&p->disp));
985     
986     	c->enable = 1;
987     	c->on = 1;
988     	c->x = c->y = 0;
989     	c->blink_rate = 0;
990     	c->vbl_cnt = CURSOR_DRAW_DELAY;
991     
992     	if (curblink) {
993     		c->blink_rate = CURSOR_BLINK_RATE;
994     		init_timer(&c->timer);
995     		c->timer.expires = jiffies + (HZ / 50);
996     		c->timer.data = (unsigned long)p;
997     		c->timer.function = imstt_cursor_timer_handler;
998     		add_timer(&c->timer);
999     	}
1000     }
1001     
1002     static void
1003     imsttfbcon_bmove (struct display *disp, int sy, int sx, int dy, int dx, int height, int width)
1004     {
1005     	struct fb_info_imstt *p = (struct fb_info_imstt *)disp->fb_info;
1006     	__u32	Bpp, line_pitch,
1007     		fb_offset_old, fb_offset_new,
1008     		sp, dp_octl, cnt, bltctl;
1009     
1010     	Bpp = disp->var.bits_per_pixel >> 3,
1011     
1012     	sy *= fontheight(disp);
1013     	sx *= fontwidth(disp);
1014     	sx *= Bpp;
1015     	dy *= fontheight(disp);
1016     	dx *= fontwidth(disp);
1017     	dx *= Bpp;
1018     	height *= fontheight(disp);
1019     	height--;
1020     	width *= fontwidth(disp);
1021     	width *= Bpp;
1022     	width--;
1023     
1024     	line_pitch = disp->line_length;
1025     	bltctl = 0x05;
1026     	sp = line_pitch << 16;
1027     	cnt = height << 16;
1028     
1029     	if (sy < dy) {
1030     		sy += height;
1031     		dy += height;
1032     		sp |= -(line_pitch) & 0xffff;
1033     		dp_octl = -(line_pitch) & 0xffff;
1034     	} else {
1035     		sp |= line_pitch;
1036     		dp_octl = line_pitch;
1037     	}
1038     	if (sx < dx) {
1039     		sx += width;
1040     		dx += width;
1041     		bltctl |= 0x80;
1042     		cnt |= -(width) & 0xffff;
1043     	} else {
1044     		cnt |= width;
1045     	}
1046     	fb_offset_old = sy * line_pitch + sx;
1047     	fb_offset_new = dy * line_pitch + dx;
1048     
1049     	while(in_le32(&p->dc_regs[SSTATUS]) & 0x80);
1050     	out_le32(&p->dc_regs[S1SA], fb_offset_old);
1051     	out_le32(&p->dc_regs[SP], sp);
1052     	out_le32(&p->dc_regs[DSA], fb_offset_new);
1053     	out_le32(&p->dc_regs[CNT], cnt);
1054     	out_le32(&p->dc_regs[DP_OCTL], dp_octl);
1055     	out_le32(&p->dc_regs[BLTCTL], bltctl);
1056     	while(in_le32(&p->dc_regs[SSTATUS]) & 0x80);
1057     	while(in_le32(&p->dc_regs[SSTATUS]) & 0x40);
1058     }
1059     
1060     static void
1061     imsttfbcon_clear (struct vc_data *conp, struct display *disp,
1062     		  int sy, int sx, int height, int width)
1063     {
1064     	struct fb_info_imstt *p = (struct fb_info_imstt *)disp->fb_info;
1065     	__u32 Bpp, line_pitch, bgc;
1066     
1067     	bgc = attr_bgcol_ec(disp, conp);
1068     	bgc |= (bgc << 8);
1069     	bgc |= (bgc << 16);
1070     
1071     	Bpp = disp->var.bits_per_pixel >> 3,
1072     	line_pitch = disp->line_length;
1073     
1074     	sy *= fontheight(disp);
1075     	sy *= line_pitch;
1076     	sx *= fontwidth(disp);
1077     	sx *= Bpp;
1078     	height *= fontheight(disp);
1079     	height--;
1080     	width *= fontwidth(disp);
1081     	width *= Bpp;
1082     	width--;
1083     
1084     	while(in_le32(&p->dc_regs[SSTATUS]) & 0x80);
1085     	out_le32(&p->dc_regs[DSA], sy + sx);
1086     	out_le32(&p->dc_regs[CNT], (height << 16) | width);
1087     	out_le32(&p->dc_regs[DP_OCTL], line_pitch);
1088     	out_le32(&p->dc_regs[BI], 0xffffffff);
1089     	out_le32(&p->dc_regs[MBC], 0xffffffff);
1090     	out_le32(&p->dc_regs[CLR], bgc);
1091     	out_le32(&p->dc_regs[BLTCTL], 0x840); /* 0x200000 */
1092     	while(in_le32(&p->dc_regs[SSTATUS]) & 0x80);
1093     	while(in_le32(&p->dc_regs[SSTATUS]) & 0x40);
1094     }
1095     
1096     static void
1097     imsttfbcon_revc (struct display *disp, int sx, int sy)
1098     {
1099     	struct fb_info_imstt *p = (struct fb_info_imstt *)disp->fb_info;
1100     	__u32 Bpp, line_pitch, height, width;
1101     
1102     	Bpp = disp->var.bits_per_pixel >> 3,
1103     	line_pitch = disp->line_length;
1104     
1105     	height = fontheight(disp);
1106     	width = fontwidth(disp) * Bpp;
1107     	sy *= height;
1108     	sy *= line_pitch;
1109     	sx *= width;
1110     	height--;
1111     	width--;
1112     
1113     	while(in_le32(&p->dc_regs[SSTATUS]) & 0x80);
1114     	out_le32(&p->dc_regs[DSA], sy + sx);
1115     	out_le32(&p->dc_regs[S1SA], sy + sx);
1116     	out_le32(&p->dc_regs[CNT], (height << 16) | width);
1117     	out_le32(&p->dc_regs[DP_OCTL], line_pitch);
1118     	out_le32(&p->dc_regs[SP], line_pitch);
1119     	out_le32(&p->dc_regs[BLTCTL], 0x40005);
1120     	while(in_le32(&p->dc_regs[SSTATUS]) & 0x80);
1121     	while(in_le32(&p->dc_regs[SSTATUS]) & 0x40);
1122     }
1123     
1124     #ifdef FBCON_HAS_CFB8
1125     static struct display_switch fbcon_imstt8 = {
1126     	setup:		fbcon_cfb8_setup,
1127     	bmove:		imsttfbcon_bmove,
1128     	clear:		imsttfbcon_clear,
1129     	putc:		fbcon_cfb8_putc,
1130     	putcs:		fbcon_cfb8_putcs,
1131     	revc:		imsttfbcon_revc,
1132     	cursor:		imsttfbcon_cursor,
1133     	set_font:	imsttfbcon_set_font,
1134     	clear_margins:	fbcon_cfb8_clear_margins,
1135     	fontwidthmask:	FONTWIDTH(4)|FONTWIDTH(8)|FONTWIDTH(12)|FONTWIDTH(16)
1136     };
1137     #endif
1138     #ifdef FBCON_HAS_CFB16
1139     static struct display_switch fbcon_imstt16 = {
1140     	setup:		fbcon_cfb16_setup,
1141     	bmove:		imsttfbcon_bmove,
1142     	clear:		imsttfbcon_clear,
1143     	putc:		fbcon_cfb16_putc,
1144     	putcs:		fbcon_cfb16_putcs,
1145     	revc:		imsttfbcon_revc,
1146     	cursor:		imsttfbcon_cursor,
1147     	set_font:	imsttfbcon_set_font,
1148     	clear_margins:	fbcon_cfb16_clear_margins,
1149     	fontwidthmask:	FONTWIDTH(4)|FONTWIDTH(8)|FONTWIDTH(12)|FONTWIDTH(16)
1150     };
1151     #endif
1152     #ifdef FBCON_HAS_CFB24
1153     static struct display_switch fbcon_imstt24 = {
1154     	setup:		fbcon_cfb24_setup,
1155     	bmove:		imsttfbcon_bmove,
1156     	clear:		imsttfbcon_clear,
1157     	putc:		fbcon_cfb24_putc,
1158     	putcs:		fbcon_cfb24_putcs,
1159     	revc:		imsttfbcon_revc,
1160     	cursor:		imsttfbcon_cursor,
1161     	set_font:	imsttfbcon_set_font,
1162     	clear_margins:	fbcon_cfb24_clear_margins,
1163     	fontwidthmask:	FONTWIDTH(4)|FONTWIDTH(8)|FONTWIDTH(12)|FONTWIDTH(16)
1164     };
1165     #endif
1166     #ifdef FBCON_HAS_CFB32
1167     static struct display_switch fbcon_imstt32 = {
1168     	setup:		fbcon_cfb32_setup,
1169     	bmove:		imsttfbcon_bmove,
1170     	clear:		imsttfbcon_clear,
1171     	putc:		fbcon_cfb32_putc,
1172     	putcs:		fbcon_cfb32_putcs,
1173     	revc:		imsttfbcon_revc,
1174     	cursor:		imsttfbcon_cursor,
1175     	set_font:	imsttfbcon_set_font,
1176     	clear_margins:	fbcon_cfb32_clear_margins,
1177     	fontwidthmask:	FONTWIDTH(4)|FONTWIDTH(8)|FONTWIDTH(12)|FONTWIDTH(16)
1178     };
1179     #endif
1180     
1181     #ifdef CONFIG_FB_COMPAT_XPMAC
1182     #include <asm/vc_ioctl.h>
1183     
1184     extern struct vc_mode display_info;
1185     extern struct fb_info *console_fb_info;
1186     
1187     static void
1188     set_display_info (struct display *disp)
1189     {
1190     	display_info.width = disp->var.xres;
1191     	display_info.height = disp->var.yres;
1192     	display_info.depth = disp->var.bits_per_pixel;
1193     	display_info.pitch = disp->line_length;
1194     
1195     	switch (disp->var.xres) {
1196     		case 512:
1197     			display_info.mode = 2;
1198     			break;
1199     		case 640:
1200     			display_info.mode = 6;
1201     			break;
1202     		case 800:
1203     			display_info.mode = 12;
1204     			break;
1205     		case 832:
1206     			display_info.mode = 13;
1207     			break;
1208     		case 1024:
1209     			display_info.mode = 17;
1210     			break;
1211     		case 1152:
1212     			display_info.mode = 18;
1213     			break;
1214     		case 1280:
1215     			display_info.mode = disp->var.yres == 960 ? 19 : 20;
1216     			break;
1217     		default:
1218     			display_info.mode = 0;
1219     	}
1220     }
1221     #endif
1222     
1223     static int
1224     imsttfb_getcolreg (u_int regno, u_int *red, u_int *green,
1225     		   u_int *blue, u_int *transp, struct fb_info *info)
1226     {
1227     	struct fb_info_imstt *p = (struct fb_info_imstt *)info;
1228     
1229     	if (regno > 255)
1230     		return 1;
1231     	*red = (p->palette[regno].red << 8) | p->palette[regno].red;
1232     	*green = (p->palette[regno].green << 8) | p->palette[regno].green;
1233     	*blue = (p->palette[regno].blue << 8) | p->palette[regno].blue;
1234     	*transp = 0;
1235     
1236     	return 0;
1237     }
1238     
1239     static int
1240     imsttfb_setcolreg (u_int regno, u_int red, u_int green, u_int blue,
1241     		   u_int transp, struct fb_info *info)
1242     {
1243     	struct fb_info_imstt *p = (struct fb_info_imstt *)info;
1244     	u_int bpp = fb_display[currcon].var.bits_per_pixel;
1245     
1246     	if (regno > 255)
1247     		return 1;
1248     
1249     	red >>= 8;
1250     	green >>= 8;
1251     	blue >>= 8;
1252     
1253     	p->palette[regno].red = red;
1254     	p->palette[regno].green = green;
1255     	p->palette[regno].blue = blue;
1256     
1257     	/* PADDRW/PDATA are the same as TVPPADDRW/TVPPDATA */
1258     	if (0 && bpp == 16)	/* screws up X */
1259     		p->cmap_regs[PADDRW] = regno << 3;
1260     	else
1261     		p->cmap_regs[PADDRW] = regno;
1262     	eieio();
1263     
1264     	p->cmap_regs[PDATA] = red;	eieio();
1265     	p->cmap_regs[PDATA] = green;	eieio();
1266     	p->cmap_regs[PDATA] = blue;	eieio();
1267     
1268     	if (regno < 16)
1269     		switch (bpp) {
1270     #ifdef FBCON_HAS_CFB16
1271     			case 16:
1272     				p->fbcon_cmap.cfb16[regno] = (regno << (fb_display[currcon].var.green.length == 5 ? 10 : 11)) | (regno << 5) | regno;
1273     				break;
1274     #endif
1275     #ifdef FBCON_HAS_CFB24
1276     			case 24:
1277     				p->fbcon_cmap.cfb24[regno] = (regno << 16) | (regno << 8) | regno;
1278     				break;
1279     #endif
1280     #ifdef FBCON_HAS_CFB32
1281     			case 32: {
1282     				int i = (regno << 8) | regno;
1283     				p->fbcon_cmap.cfb32[regno] = (i << 16) | i;
1284     				break;
1285     			}
1286     #endif
1287     		}
1288     
1289     	return 0;
1290     }
1291     
1292     static void
1293     do_install_cmap (int con, struct fb_info *info)
1294     {
1295     	if (fb_display[con].cmap.len)
1296     		fb_set_cmap(&fb_display[con].cmap, 1, imsttfb_setcolreg, info);
1297     	else {
1298     		u_int size = fb_display[con].var.bits_per_pixel == 16 ? 32 : 256;
1299     		fb_set_cmap(fb_default_cmap(size), 1, imsttfb_setcolreg, info);
1300     	}
1301     }
1302     
1303     static int
1304     imsttfb_get_fix (struct fb_fix_screeninfo *fix, int con, struct fb_info *info)
1305     {
1306     	struct fb_info_imstt *p = (struct fb_info_imstt *)info;
1307     	struct fb_var_screeninfo *var = &fb_display[con].var;
1308     
1309     	*fix = p->fix;
1310     	fix->visual = var->bits_per_pixel == 8 ? FB_VISUAL_PSEUDOCOLOR
1311     					       : FB_VISUAL_DIRECTCOLOR;
1312     	fix->line_length = var->xres * (var->bits_per_pixel >> 3);
1313     
1314     	return 0;
1315     }
1316     
1317     static int
1318     imsttfb_get_var (struct fb_var_screeninfo *var, int con, struct fb_info *info)
1319     {
1320     	*var = fb_display[con].var;
1321     
1322     	return 0;
1323     }
1324     
1325     static void
1326     set_dispsw (struct display *disp, struct fb_info_imstt *p)
1327     {
1328     	u_int accel = disp->var.accel_flags & FB_ACCELF_TEXT;
1329     
1330     	if (disp->conp && disp->conp->vc_sw && disp->conp->vc_sw->con_cursor)
1331     		disp->conp->vc_sw->con_cursor(disp->conp, CM_ERASE);
1332     
1333     	p->dispsw = fbcon_dummy;
1334     	disp->dispsw = &p->dispsw;
1335     	disp->dispsw_data = 0;
1336     	switch (disp->var.bits_per_pixel) {
1337     		case 8:
1338     			disp->var.red.offset = 0;
1339     			disp->var.red.length = 8;
1340     			disp->var.green.offset = 0;
1341     			disp->var.green.length = 8;
1342     			disp->var.blue.offset = 0;
1343     			disp->var.blue.length = 8;
1344     			disp->var.transp.offset = 0;
1345     			disp->var.transp.length = 0;
1346     #ifdef FBCON_HAS_CFB8
1347     			p->dispsw = accel ? fbcon_imstt8 : fbcon_cfb8;
1348     #endif
1349     			break;
1350     		case 16:	/* RGB 555 or 565 */
1351     			if (disp->var.green.length != 6)
1352     				disp->var.red.offset = 10;
1353     			disp->var.red.length = 5;
1354     			disp->var.green.offset = 5;
1355     			if (disp->var.green.length != 6)
1356     				disp->var.green.length = 5;
1357     			disp->var.blue.offset = 0;
1358     			disp->var.blue.length = 5;
1359     			disp->var.transp.offset = 0;
1360     			disp->var.transp.length = 0;
1361     #ifdef FBCON_HAS_CFB16
1362     			p->dispsw = accel ? fbcon_imstt16 : fbcon_cfb16;
1363     			disp->dispsw_data = p->fbcon_cmap.cfb16;
1364     #endif
1365     			break;
1366     		case 24:	/* RGB 888 */
1367     			disp->var.red.offset = 16;
1368     			disp->var.red.length = 8;
1369     			disp->var.green.offset = 8;
1370     			disp->var.green.length = 8;
1371     			disp->var.blue.offset = 0;
1372     			disp->var.blue.length = 8;
1373     			disp->var.transp.offset = 0;
1374     			disp->var.transp.length = 0;
1375     #ifdef FBCON_HAS_CFB24
1376     			p->dispsw = accel ? fbcon_imstt24 : fbcon_cfb24;
1377     			disp->dispsw_data = p->fbcon_cmap.cfb24;
1378     #endif
1379     			break;
1380     		case 32:	/* RGBA 8888 */
1381     			disp->var.red.offset = 16;
1382     			disp->var.red.length = 8;
1383     			disp->var.green.offset = 8;
1384     			disp->var.green.length = 8;
1385     			disp->var.blue.offset = 0;
1386     			disp->var.blue.length = 8;
1387     			disp->var.transp.offset = 24;
1388     			disp->var.transp.length = 8;
1389     #ifdef FBCON_HAS_CFB32
1390     			p->dispsw = accel ? fbcon_imstt32 : fbcon_cfb32;
1391     			disp->dispsw_data = p->fbcon_cmap.cfb32;
1392     #endif
1393     			break;
1394     	}
1395     
1396     	if (accel && p->ramdac != IBM) {
1397     		p->dispsw.cursor = 0;
1398     		p->dispsw.set_font = 0;
1399     	}
1400     
1401     #ifdef CONFIG_FB_COMPAT_XPMAC
1402     	set_display_info(disp);
1403     #endif
1404     }
1405     
1406     static void
1407     set_disp (struct display *disp, struct fb_info_imstt *p)
1408     {
1409     	u_int accel = disp->var.accel_flags & FB_ACCELF_TEXT;
1410     
1411     	disp->fb_info = &p->info;
1412     
1413     	set_dispsw(disp, p);
1414     
1415     	disp->visual = disp->var.bits_per_pixel == 8 ? FB_VISUAL_PSEUDOCOLOR
1416     					 	     : FB_VISUAL_DIRECTCOLOR;
1417     	disp->screen_base = (__u8 *)p->frame_buffer;
1418     	disp->visual = p->fix.visual;
1419     	disp->type = p->fix.type;
1420     	disp->type_aux = p->fix.type_aux;
1421     	disp->line_length = disp->var.xres * (disp->var.bits_per_pixel >> 3);
1422     	disp->can_soft_blank = 1;
1423     	disp->inverse = inverse;
1424     	disp->ypanstep = 1;
1425     	disp->ywrapstep = 0;
1426     	if (accel) {
1427     		disp->scrollmode = SCROLL_YNOMOVE;
1428     		if (disp->var.yres == disp->var.yres_virtual) {
1429     			__u32 vram = (p->total_vram - (PAGE_SIZE << 2));
1430     			disp->var.yres_virtual = ((vram << 3) / disp->var.bits_per_pixel) / disp->var.xres_virtual;
1431     			if (disp->var.yres_virtual < disp->var.yres)
1432     				disp->var.yres_virtual = disp->var.yres;
1433     		}
1434     	} else {
1435     		disp->scrollmode = SCROLL_YREDRAW;
1436     	}
1437     
1438     	disp->var.activate = 0;
1439     	disp->var.red.msb_right = 0;
1440     	disp->var.green.msb_right = 0;
1441     	disp->var.blue.msb_right = 0;
1442     	disp->var.transp.msb_right = 0;
1443     	disp->var.height = -1;
1444     	disp->var.width = -1;
1445     	disp->var.vmode = FB_VMODE_NONINTERLACED;
1446     	disp->var.left_margin = disp->var.right_margin = 16;
1447     	disp->var.upper_margin = disp->var.lower_margin = 16;
1448     	disp->var.hsync_len = disp->var.vsync_len = 8;
1449     }
1450     
1451     static int
1452     imsttfb_set_var (struct fb_var_screeninfo *var, int con, struct fb_info *info)
1453     {
1454     	struct fb_info_imstt *p = (struct fb_info_imstt *)info;
1455     	struct display *disp;
1456     	u_int oldbpp, oldxres, oldyres, oldgreenlen, oldaccel;
1457     
1458     	disp = &fb_display[con];
1459     
1460     	if ((var->bits_per_pixel != 8 && var->bits_per_pixel != 16
1461     	    && var->bits_per_pixel != 24 && var->bits_per_pixel != 32)
1462     	    || var->xres_virtual < var->xres || var->yres_virtual < var->yres
1463     	    || var->nonstd
1464     	    || (var->vmode & FB_VMODE_MASK) != FB_VMODE_NONINTERLACED)
1465     		return -EINVAL;
1466     
1467     	if ((var->xres * var->yres) * (var->bits_per_pixel >> 3) > p->total_vram
1468     	    || (var->xres_virtual * var->yres_virtual) * (var->bits_per_pixel >> 3) > p->total_vram)
1469     		return -EINVAL;
1470     
1471     	if (!((var->activate & FB_ACTIVATE_MASK) == FB_ACTIVATE_NOW))
1472     		return 0;
1473     
1474     	if (!compute_imstt_regvals(p, var->xres, var->yres))
1475     		return -EINVAL;
1476     
1477     	oldbpp = disp->var.bits_per_pixel;
1478     	oldxres = disp->var.xres;
1479     	oldyres = disp->var.yres;
1480     	oldgreenlen = disp->var.green.length;
1481     	oldaccel = disp->var.accel_flags;
1482     
1483     	disp->var.bits_per_pixel = var->bits_per_pixel;
1484     	disp->var.xres = var->xres;
1485     	disp->var.yres = var->yres;
1486     	disp->var.xres_virtual = var->xres_virtual;
1487     	disp->var.yres_virtual = var->yres_virtual;
1488     	disp->var.green.length = var->green.length;
1489     	disp->var.accel_flags = var->accel_flags;
1490     
1491     	set_disp(disp, p);
1492     
1493     	if (info->changevar)
1494     		(*info->changevar)(con);
1495     
1496     	if (con == currcon) {
1497     		if (oldgreenlen != disp->var.green.length) {
1498     			if (disp->var.green.length == 6)
1499     				set_565(p);
1500     			else
1501     				set_555(p);
1502     		}
1503     		if (oldxres != disp->var.xres || oldyres != disp->var.yres || oldbpp != disp->var.bits_per_pixel)
1504     			set_imstt_regvals(p, disp->var.bits_per_pixel);
1505     			
1506     	}
1507     	disp->var.pixclock = 1000000 / getclkMHz(p);
1508     
1509     	if (oldbpp != disp->var.bits_per_pixel) {
1510     		int err = fb_alloc_cmap(&disp->cmap, 0, 0);
1511     		if (err)
1512     			return err;
1513     		do_install_cmap(con, info);
1514     	}
1515     	*var = disp->var;
1516     
1517     	return 0;
1518     }
1519     
1520     static int
1521     imsttfb_pan_display (struct fb_var_screeninfo *var, int con, struct fb_info *info)
1522     {
1523     	struct fb_info_imstt *p = (struct fb_info_imstt *)info;
1524     	struct display *disp = &fb_display[con];
1525     
1526     	if (var->xoffset + disp->var.xres > disp->var.xres_virtual
1527     	    || var->yoffset + disp->var.yres > disp->var.yres_virtual)
1528     		return -EINVAL;
1529     
1530     	disp->var.xoffset = var->xoffset;
1531     	disp->var.yoffset = var->yoffset;
1532     	if (con == currcon)
1533     		set_offset(disp, p);
1534     
1535     	return 0;
1536     }
1537     
1538     static int
1539     imsttfb_get_cmap (struct fb_cmap *cmap, int kspc, int con, struct fb_info *info)
1540     {
1541     	if (con == currcon)	/* current console? */
1542     		return fb_get_cmap(cmap, kspc, imsttfb_getcolreg, info);
1543     	else if (fb_display[con].cmap.len)	/* non default colormap? */
1544     		fb_copy_cmap(&fb_display[con].cmap, cmap, kspc ? 0 : 2);
1545     	else {
1546     		u_int size = fb_display[con].var.bits_per_pixel == 16 ? 32 : 256;
1547     		fb_copy_cmap(fb_default_cmap(size), cmap, kspc ? 0 : 2);
1548     	}
1549     
1550     	return 0;
1551     }
1552     
1553     static int
1554     imsttfb_set_cmap (struct fb_cmap *cmap, int kspc, int con, struct fb_info *info)
1555     {
1556     	int err;
1557     
1558     	if (!fb_display[con].cmap.len) {	/* no colormap allocated? */
1559     		int size = fb_display[con].var.bits_per_pixel == 16 ? 32 : 256;
1560     		if ((err = fb_alloc_cmap(&fb_display[con].cmap, size, 0)))
1561     			return err;
1562     	}
1563     	if (con == currcon)			/* current console? */
1564     		return fb_set_cmap(cmap, kspc, imsttfb_setcolreg, info);
1565     	else
1566     		fb_copy_cmap(cmap, &fb_display[con].cmap, kspc ? 0 : 1);
1567     
1568     	return 0;
1569     }
1570     
1571     #define FBIMSTT_SETREG		0x545401
1572     #define FBIMSTT_GETREG		0x545402
1573     #define FBIMSTT_SETCMAPREG	0x545403
1574     #define FBIMSTT_GETCMAPREG	0x545404
1575     #define FBIMSTT_SETIDXREG	0x545405
1576     #define FBIMSTT_GETIDXREG	0x545406
1577     
1578     static int
1579     imsttfb_ioctl (struct inode *inode, struct file *file, u_int cmd,
1580     	       u_long arg, int con, struct fb_info *info)
1581     {
1582     	struct fb_info_imstt *p = (struct fb_info_imstt *)info;
1583     	__u8 idx[2];
1584     	__u32 reg[2];
1585     
1586     	switch (cmd) {
1587     		case FBIMSTT_SETREG:
1588     			if (copy_from_user(reg, (void *)arg, 8) || reg[0] > (0x1000 - sizeof(reg[0])) / sizeof(reg[0]))
1589     				return -EFAULT;
1590     			out_le32(&p->dc_regs[reg[0]], reg[1]);
1591     			return 0;
1592     		case FBIMSTT_GETREG:
1593     			if (copy_from_user(reg, (void *)arg, 4) || reg[0] > (0x1000 - sizeof(reg[0])) / sizeof(reg[0]))
1594     				return -EFAULT;
1595     			reg[1] = in_le32(&p->dc_regs[reg[0]]);
1596     			if (copy_to_user((void *)(arg + 4), &reg[1], 4))
1597     				return -EFAULT;
1598     			return 0;
1599     		case FBIMSTT_SETCMAPREG:
1600     			if (copy_from_user(reg, (void *)arg, 8) || reg[0] > (0x1000 - sizeof(reg[0])) / sizeof(reg[0]))
1601     				return -EFAULT;
1602     			out_le32(&((u_int *)p->cmap_regs)[reg[0]], reg[1]);
1603     			return 0;
1604     		case FBIMSTT_GETCMAPREG:
1605     			if (copy_from_user(reg, (void *)arg, 4) || reg[0] > (0x1000 - sizeof(reg[0])) / sizeof(reg[0]))
1606     				return -EFAULT;
1607     			reg[1] = in_le32(&((u_int *)p->cmap_regs)[reg[0]]);
1608     			if (copy_to_user((void *)(arg + 4), &reg[1], 4))
1609     				return -EFAULT;
1610     			return 0;
1611     		case FBIMSTT_SETIDXREG:
1612     			if (copy_from_user(idx, (void *)arg, 2))
1613     				return -EFAULT;
1614     			p->cmap_regs[PIDXHI] = 0;		eieio();
1615     			p->cmap_regs[PIDXLO] = idx[0];		eieio();
1616     			p->cmap_regs[PIDXDATA] = idx[1];	eieio();
1617     			return 0;
1618     		case FBIMSTT_GETIDXREG:
1619     			if (copy_from_user(idx, (void *)arg, 1))
1620     				return -EFAULT;
1621     			p->cmap_regs[PIDXHI] = 0;		eieio();
1622     			p->cmap_regs[PIDXLO] = idx[0];		eieio();
1623     			idx[1] = p->cmap_regs[PIDXDATA];
1624     			if (copy_to_user((void *)(arg + 1), &idx[1], 1))
1625     				return -EFAULT;
1626     			return 0;
1627     		default:
1628     			return -ENOIOCTLCMD;
1629     	}
1630     }
1631     
1632     static struct pci_device_id imsttfb_pci_tbl[] __devinitdata = {
1633     	{ PCI_VENDOR_ID_IMS, PCI_DEVICE_ID_IMS_TT128,
1634     	  PCI_ANY_ID, PCI_ANY_ID, 0, 0, IBM },
1635     	{ PCI_VENDOR_ID_IMS, PCI_DEVICE_ID_IMS_TT3D,
1636     	  PCI_ANY_ID, PCI_ANY_ID, 0, 0, TVP },
1637     	{ 0, }
1638     };
1639     
1640     MODULE_DEVICE_TABLE(pci, imsttfb_pci_tbl);
1641     
1642     static struct pci_driver imsttfb_pci_driver = {
1643     	name:		"imsttfb",
1644     	id_table:	imsttfb_pci_tbl,
1645     	probe:		imsttfb_probe,
1646     	remove:		imsttfb_remove,
1647     };
1648     
1649     static struct fb_ops imsttfb_ops = {
1650     	owner:		THIS_MODULE,
1651     	fb_get_fix:	imsttfb_get_fix,
1652     	fb_get_var:	imsttfb_get_var,
1653     	fb_set_var:	imsttfb_set_var,
1654     	fb_get_cmap:	imsttfb_get_cmap,
1655     	fb_set_cmap:	imsttfb_set_cmap,
1656     	fb_pan_display:	imsttfb_pan_display,
1657     	fb_ioctl:	imsttfb_ioctl,
1658     };
1659     
1660     static int
1661     imsttfbcon_switch (int con, struct fb_info *info)
1662     {
1663     	struct fb_info_imstt *p = (struct fb_info_imstt *)info;
1664     	struct display *old = &fb_display[currcon], *new = &fb_display[con];
1665     
1666     	if (old->cmap.len)
1667     		fb_get_cmap(&old->cmap, 1, imsttfb_getcolreg, info);
1668     
1669     	if (old->conp && old->conp->vc_sw && old->conp->vc_sw->con_cursor)
1670     		old->conp->vc_sw->con_cursor(old->conp, CM_ERASE);
1671     
1672     	currcon = con;
1673     
1674     	if (old->var.xres != new->var.xres
1675     	    || old->var.yres != new->var.yres
1676     	    || old->var.bits_per_pixel != new->var.bits_per_pixel
1677     	    || old->var.green.length != new->var.green.length
1678     	    || old->var.accel_flags != new->var.accel_flags) {
1679     		set_dispsw(new, p);
1680     		if (!compute_imstt_regvals(p, new->var.xres, new->var.yres))
1681     			return -1;
1682     		if (new->var.bits_per_pixel == 16) {
1683     			if (new->var.green.length == 6)
1684     				set_565(p);
1685     			else
1686     				set_555(p);
1687     		}
1688     		set_imstt_regvals(p, new->var.bits_per_pixel);
1689     	}
1690     	set_offset(new, p);
1691     
1692     	imsttfbcon_set_font(new, fontwidth(new), fontheight(new));
1693     
1694     	do_install_cmap(con, info);
1695     
1696     	return 0;
1697     }
1698     
1699     static int
1700     imsttfbcon_updatevar (int con, struct fb_info *info)
1701     {
1702     	struct fb_info_imstt *p = (struct fb_info_imstt *)info;
1703     	struct display *disp = &fb_display[con];
1704     
1705     	if (con != currcon)
1706     		goto out;
1707     
1708     	if (p->ramdac == IBM)
1709     		imsttfbcon_cursor(disp, CM_ERASE, p->cursor.x, p->cursor.y);
1710     
1711     	set_offset(disp, p);
1712     
1713     out:
1714     	return 0;
1715     }
1716     
1717     static void
1718     imsttfbcon_blank (int blank, struct fb_info *info)
1719     {
1720     	struct fb_info_imstt *p = (struct fb_info_imstt *)info;
1721     	__u32 ctrl;
1722     
1723     	ctrl = in_le32(&p->dc_regs[STGCTL]);
1724     	if (blank > 0) {
1725     		switch (blank - 1) {
1726     			case VESA_NO_BLANKING:
1727     			case VESA_POWERDOWN:
1728     				ctrl &= ~0x00000380;
1729     				if (p->ramdac == IBM) {
1730     					p->cmap_regs[PIDXHI] = 0;	eieio();
1731     					p->cmap_regs[PIDXLO] = MISCTL2;	eieio();
1732     					p->cmap_regs[PIDXDATA] = 0x55;	eieio();
1733     					p->cmap_regs[PIDXLO] = MISCTL1;	eieio();
1734     					p->cmap_regs[PIDXDATA] = 0x11;	eieio();
1735     					p->cmap_regs[PIDXLO] = SYNCCTL;	eieio();
1736     					p->cmap_regs[PIDXDATA] = 0x0f;	eieio();
1737     					p->cmap_regs[PIDXLO] = PWRMNGMT;eieio();
1738     					p->cmap_regs[PIDXDATA] = 0x1f;	eieio();
1739     					p->cmap_regs[PIDXLO] = CLKCTL;	eieio();
1740     					p->cmap_regs[PIDXDATA] = 0xc0;
1741     				}
1742     				break;
1743     			case VESA_VSYNC_SUSPEND:
1744     				ctrl &= ~0x00000020;
1745     				break;
1746     			case VESA_HSYNC_SUSPEND:
1747     				ctrl &= ~0x00000010;
1748     				break;
1749     		}
1750     	} else {
1751     		if (p->ramdac == IBM) {
1752     			ctrl |= 0x000017b0;
1753     			p->cmap_regs[PIDXHI] = 0;	eieio();
1754     			p->cmap_regs[PIDXLO] = CLKCTL;	eieio();
1755     			p->cmap_regs[PIDXDATA] = 0x01;	eieio();
1756     			p->cmap_regs[PIDXLO] = PWRMNGMT;eieio();
1757     			p->cmap_regs[PIDXDATA] = 0x00;	eieio();
1758     			p->cmap_regs[PIDXLO] = SYNCCTL;	eieio();
1759     			p->cmap_regs[PIDXDATA] = 0x00;	eieio();
1760     			p->cmap_regs[PIDXLO] = MISCTL1;	eieio();
1761     			p->cmap_regs[PIDXDATA] = 0x01;	eieio();
1762     			p->cmap_regs[PIDXLO] = MISCTL2;	eieio();
1763     			p->cmap_regs[PIDXDATA] = 0x45;	eieio();
1764     		} else
1765     			ctrl |= 0x00001780;
1766     	}
1767     	out_le32(&p->dc_regs[STGCTL], ctrl);
1768     }
1769     
1770     static void __init 
1771     init_imstt(struct fb_info_imstt *p)
1772     {
1773     	__u32 i, tmp;
1774     	__u32 *ip, *end;
1775     
1776     	tmp = in_le32(&p->dc_regs[PRC]);
1777     	if (p->ramdac == IBM)
1778     		p->total_vram = (tmp & 0x0004) ? 0x400000 : 0x200000;
1779     	else
1780     		p->total_vram = 0x800000;
1781     
1782     	ip = (__u32 *)p->frame_buffer;
1783     	end = (__u32 *)(p->frame_buffer + p->total_vram);
1784     	while (ip < end)
1785     		*ip++ = 0;
1786     
1787     	/* initialize the card */
1788     	tmp = in_le32(&p->dc_regs[STGCTL]);
1789     	out_le32(&p->dc_regs[STGCTL], tmp & ~0x1);
1790     	out_le32(&p->dc_regs[SSR], 0);
1791     
1792     	/* set default values for DAC registers */ 
1793     	if (p->ramdac == IBM) {
1794     		p->cmap_regs[PPMASK] = 0xff;	eieio();
1795     		p->cmap_regs[PIDXHI] = 0;	eieio();
1796     		for (i = 0; i < sizeof(ibm_initregs) / sizeof(*ibm_initregs); i++) {
1797     			p->cmap_regs[PIDXLO] = ibm_initregs[i].addr;	eieio();
1798     			p->cmap_regs[PIDXDATA] = ibm_initregs[i].value;	eieio();
1799     		}
1800     	} else {
1801     		for (i = 0; i < sizeof(tvp_initregs) / sizeof(*tvp_initregs); i++) {
1802     			p->cmap_regs[TVPADDRW] = tvp_initregs[i].addr;	eieio();
1803     			p->cmap_regs[TVPIDATA] = tvp_initregs[i].value;	eieio();
1804     		}
1805     	}
1806     
1807     #if USE_NV_MODES && defined(CONFIG_PPC)
1808     	{
1809     		int vmode = init_vmode, cmode = init_cmode;
1810     
1811     		if (vmode == -1) {
1812     			vmode = nvram_read_byte(NV_VMODE);
1813     			if (vmode <= 0 || vmode > VMODE_MAX)
1814     				vmode = VMODE_640_480_67;
1815     		}
1816     		if (cmode == -1) {
1817     			cmode = nvram_read_byte(NV_CMODE);
1818     			if (cmode < CMODE_8 || cmode > CMODE_32)
1819     				cmode = CMODE_8;
1820     		}
1821     		if (mac_vmode_to_var(vmode, cmode, &p->disp.var)) {
1822     			p->disp.var.xres = p->disp.var.xres_virtual = INIT_XRES;
1823     			p->disp.var.yres = p->disp.var.yres_virtual = INIT_YRES;
1824     			p->disp.var.bits_per_pixel = INIT_BPP;
1825     		}
1826     	}
1827     #else
1828     	p->disp.var.xres = p->disp.var.xres_virtual = INIT_XRES;
1829     	p->disp.var.yres = p->disp.var.yres_virtual = INIT_YRES;
1830     	p->disp.var.bits_per_pixel = INIT_BPP;
1831     #endif
1832     
1833     	if ((p->disp.var.xres * p->disp.var.yres) * (p->disp.var.bits_per_pixel >> 3) > p->total_vram
1834     	    || !(compute_imstt_regvals(p, p->disp.var.xres, p->disp.var.yres))) {
1835     		printk("imsttfb: %ux%ux%u not supported\n", p->disp.var.xres, p->disp.var.yres, p->disp.var.bits_per_pixel);
1836     		kfree(p);
1837     		return;
1838     	}
1839     
1840     	sprintf(p->fix.id, "IMS TT (%s)", p->ramdac == IBM ? "IBM" : "TVP");
1841     	p->fix.smem_start = p->frame_buffer_phys;
1842     	p->fix.smem_len = p->total_vram;
1843     	p->fix.mmio_start = p->dc_regs_phys;
1844     	p->fix.mmio_len = 0x1000;
1845     	p->fix.accel = FB_ACCEL_IMS_TWINTURBO;
1846     	p->fix.type = FB_TYPE_PACKED_PIXELS;
1847     	p->fix.visual = p->disp.var.bits_per_pixel == 8 ? FB_VISUAL_PSEUDOCOLOR
1848     							: FB_VISUAL_DIRECTCOLOR;
1849     	p->fix.line_length = p->disp.var.xres * (p->disp.var.bits_per_pixel >> 3);
1850     	p->fix.xpanstep = 8;
1851     	p->fix.ypanstep = 1;
1852     	p->fix.ywrapstep = 0;
1853     
1854     	p->disp.var.accel_flags = noaccel ? 0 : FB_ACCELF_TEXT;
1855     	set_disp(&p->disp, p);
1856     
1857     	if (!noaccel && p->ramdac == IBM)
1858     		imstt_cursor_init(p);
1859     	if (p->disp.var.green.length == 6)
1860     		set_565(p);
1861     	else
1862     		set_555(p);
1863     	set_imstt_regvals(p, p->disp.var.bits_per_pixel);
1864     
1865     	p->disp.var.pixclock = 1000000 / getclkMHz(p);
1866     
1867     	strcpy(p->info.modename, p->fix.id);
1868     	strcpy(p->info.fontname, fontname);
1869     	p->info.node = -1;
1870     	p->info.fbops = &imsttfb_ops;
1871     	p->info.disp = &p->disp;
1872     	p->info.changevar = 0;
1873     	p->info.switch_con = &imsttfbcon_switch;
1874     	p->info.updatevar = &imsttfbcon_updatevar;
1875     	p->info.blank = &imsttfbcon_blank;
1876     	p->info.flags = FBINFO_FLAG_DEFAULT;
1877     
1878     	for (i = 0; i < 16; i++) {
1879     		u_int j = color_table[i];
1880     		p->palette[i].red = default_red[j];
1881     		p->palette[i].green = default_grn[j];
1882     		p->palette[i].blue = default_blu[j];
1883     	}
1884     
1885     	if (register_framebuffer(&p->info) < 0) {
1886     		kfree(p);
1887     		return;
1888     	}
1889     
1890     	i = GET_FB_IDX(p->info.node);
1891     	tmp = (in_le32(&p->dc_regs[SSTATUS]) & 0x0f00) >> 8;
1892     	printk("fb%u: %s frame buffer; %uMB vram; chip version %u\n",
1893     		i, p->fix.id, p->total_vram >> 20, tmp);
1894     
1895     #ifdef CONFIG_FB_COMPAT_XPMAC
1896     	strncpy(display_info.name, "IMS,tt128mb", sizeof(display_info.name));
1897     	display_info.fb_address = p->frame_buffer_phys;
1898     	display_info.cmap_adr_address = p->cmap_regs_phys + PADDRW;
1899     	display_info.cmap_data_address = p->cmap_regs_phys + PDATA;
1900     	display_info.disp_reg_address = p->dc_regs_phys;
1901     	if (!console_fb_info)
1902     		console_fb_info = &p->info;
1903     #endif /* CONFIG_FB_COMPAT_XPMAC */
1904     }
1905     
1906     static int __devinit
1907     imsttfb_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
1908     {
1909     	struct fb_info_imstt *p;
1910     	unsigned long addr, size;
1911     
1912     	addr = pci_resource_start (pdev, 0);
1913     	size = pci_resource_len (pdev, 0);
1914     
1915     	p = kmalloc(sizeof(struct fb_info_imstt), GFP_KERNEL);
1916     
1917     	if (!p) {
1918     		printk(KERN_ERR "imsttfb: Can't allocate memory\n");
1919     		return -ENOMEM;
1920     	}
1921     
1922     	memset(p, 0, sizeof(struct fb_info_imstt));
1923     
1924     	if (!request_mem_region(addr, size, "imsttfb")) {
1925     		printk(KERN_ERR "imsttfb: Can't reserve memory region\n");
1926     		kfree(p);
1927     		return -ENODEV;
1928     	}
1929     
1930     	switch (pdev->device) {
1931     		case PCI_DEVICE_ID_IMS_TT128: /* IMS,tt128mbA */
1932     			p->ramdac = IBM;
1933     			break;
1934     		case PCI_DEVICE_ID_IMS_TT3D:  /* IMS,tt3d */
1935     			p->ramdac = TVP;
1936     			break;
1937     		default:
1938     			printk(KERN_INFO "imsttfb: Device 0x%lx unknown, "
1939     					 "contact maintainer.\n", pdev->device);
1940     			return -ENODEV;
1941     	}
1942     
1943     	p->frame_buffer_phys = addr;
1944     	p->board_size = size;
1945     	p->frame_buffer = (__u8 *)ioremap(addr, p->ramdac == IBM ? 0x400000 : 0x800000);
1946     	p->dc_regs_phys = addr + 0x800000;
1947     	p->dc_regs = (__u32 *)ioremap(addr + 0x800000, 0x1000);
1948     	p->cmap_regs_phys = addr + 0x840000;
1949     	p->cmap_regs = (__u8 *)ioremap(addr + 0x840000, 0x1000);
1950     
1951     	init_imstt(p);
1952     
1953     	pdev->driver_data = p;
1954     
1955     	return 0;
1956     }
1957     
1958     static void __devexit
1959     imsttfb_remove(struct pci_dev *pdev)
1960     {
1961     	struct fb_info_imstt *p = (struct fb_info_imstt *)pdev->driver_data;
1962     
1963     	unregister_framebuffer(&p->info);
1964     	iounmap(p->cmap_regs);
1965     	iounmap(p->dc_regs);
1966     	iounmap(p->frame_buffer);
1967     	release_mem_region(p->frame_buffer_phys, p->board_size);
1968     	kfree(p);
1969     }
1970     
1971     #ifndef MODULE
1972     int __init 
1973     imsttfb_setup(char *options)
1974     {
1975     	char *this_opt;
1976     
1977     	if (!options || !*options)
1978     		return 0;
1979     
1980     	for (this_opt = strtok(options, ","); this_opt;
1981     	     this_opt = strtok(NULL, ",")) {
1982     		if (!strncmp(this_opt, "font:", 5)) {
1983     			char *p;
1984     			int i;
1985     
1986     			p = this_opt + 5;
1987     			for (i = 0; i < sizeof(fontname) - 1; i++)
1988     				if (!*p || *p == ' ' || *p == ',')
1989     					break;
1990     			memcpy(fontname, this_opt + 5, i);
1991     			fontname[i] = 0;
1992     		} else if (!strncmp(this_opt, "noblink", 7)) {
1993     			curblink = 0;
1994     		} else if (!strncmp(this_opt, "noaccel", 7)) {
1995     			noaccel = 1;
1996     		} else if (!strncmp(this_opt, "inverse", 7)) {
1997     			inverse = 1;
1998     			fb_invert_cmaps();
1999     		}
2000     #if defined(CONFIG_PPC)
2001     		else if (!strncmp(this_opt, "vmode:", 6)) {
2002     			int vmode = simple_strtoul(this_opt+6, NULL, 0);
2003     			if (vmode > 0 && vmode <= VMODE_MAX)
2004     				init_vmode = vmode;
2005     		} else if (!strncmp(this_opt, "cmode:", 6)) {
2006     			int cmode = simple_strtoul(this_opt+6, NULL, 0);
2007     			switch (cmode) {
2008     				case CMODE_8:
2009     				case 8:
2010     					init_cmode = CMODE_8;
2011     					break;
2012     				case CMODE_16:
2013     				case 15:
2014     				case 16:
2015     					init_cmode = CMODE_16;
2016     					break;
2017     				case CMODE_32:
2018     				case 24:
2019     				case 32:
2020     					init_cmode = CMODE_32;
2021     					break;
2022     			}
2023     		}
2024     #endif
2025     	}
2026     	return 0;
2027     }
2028     
2029     #endif /* MODULE */
2030     
2031     int __init imsttfb_init(void)
2032     {
2033     	return pci_module_init(&imsttfb_pci_driver);
2034     }
2035      
2036     static void __exit imsttfb_exit(void)
2037     {
2038     	pci_unregister_driver(&imsttfb_pci_driver);
2039     }
2040     
2041     #ifdef MODULE
2042     MODULE_LICENSE("GPL");
2043     module_init(imsttfb_init);
2044     #endif
2045     module_exit(imsttfb_exit);
2046     
2047