xref: /OK3568_Linux_fs/kernel/drivers/video/fbdev/cirrusfb.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
1*4882a593Smuzhiyun /*
2*4882a593Smuzhiyun  * drivers/video/cirrusfb.c - driver for Cirrus Logic chipsets
3*4882a593Smuzhiyun  *
4*4882a593Smuzhiyun  * Copyright 1999-2001 Jeff Garzik <jgarzik@pobox.com>
5*4882a593Smuzhiyun  *
6*4882a593Smuzhiyun  * Contributors (thanks, all!)
7*4882a593Smuzhiyun  *
8*4882a593Smuzhiyun  *	David Eger:
9*4882a593Smuzhiyun  *	Overhaul for Linux 2.6
10*4882a593Smuzhiyun  *
11*4882a593Smuzhiyun  *      Jeff Rugen:
12*4882a593Smuzhiyun  *      Major contributions;  Motorola PowerStack (PPC and PCI) support,
13*4882a593Smuzhiyun  *      GD54xx, 1280x1024 mode support, change MCLK based on VCLK.
14*4882a593Smuzhiyun  *
15*4882a593Smuzhiyun  *	Geert Uytterhoeven:
16*4882a593Smuzhiyun  *	Excellent code review.
17*4882a593Smuzhiyun  *
18*4882a593Smuzhiyun  *	Lars Hecking:
19*4882a593Smuzhiyun  *	Amiga updates and testing.
20*4882a593Smuzhiyun  *
21*4882a593Smuzhiyun  * Original cirrusfb author:  Frank Neumann
22*4882a593Smuzhiyun  *
23*4882a593Smuzhiyun  * Based on retz3fb.c and cirrusfb.c:
24*4882a593Smuzhiyun  *      Copyright (C) 1997 Jes Sorensen
25*4882a593Smuzhiyun  *      Copyright (C) 1996 Frank Neumann
26*4882a593Smuzhiyun  *
27*4882a593Smuzhiyun  ***************************************************************
28*4882a593Smuzhiyun  *
29*4882a593Smuzhiyun  * Format this code with GNU indent '-kr -i8 -pcs' options.
30*4882a593Smuzhiyun  *
31*4882a593Smuzhiyun  * This file is subject to the terms and conditions of the GNU General Public
32*4882a593Smuzhiyun  * License.  See the file COPYING in the main directory of this archive
33*4882a593Smuzhiyun  * for more details.
34*4882a593Smuzhiyun  *
35*4882a593Smuzhiyun  */
36*4882a593Smuzhiyun 
37*4882a593Smuzhiyun #include <linux/module.h>
38*4882a593Smuzhiyun #include <linux/kernel.h>
39*4882a593Smuzhiyun #include <linux/errno.h>
40*4882a593Smuzhiyun #include <linux/string.h>
41*4882a593Smuzhiyun #include <linux/mm.h>
42*4882a593Smuzhiyun #include <linux/delay.h>
43*4882a593Smuzhiyun #include <linux/fb.h>
44*4882a593Smuzhiyun #include <linux/init.h>
45*4882a593Smuzhiyun 
46*4882a593Smuzhiyun #ifdef CONFIG_ZORRO
47*4882a593Smuzhiyun #include <linux/zorro.h>
48*4882a593Smuzhiyun #endif
49*4882a593Smuzhiyun #ifdef CONFIG_PCI
50*4882a593Smuzhiyun #include <linux/pci.h>
51*4882a593Smuzhiyun #endif
52*4882a593Smuzhiyun #ifdef CONFIG_AMIGA
53*4882a593Smuzhiyun #include <asm/amigahw.h>
54*4882a593Smuzhiyun #endif
55*4882a593Smuzhiyun 
56*4882a593Smuzhiyun #include <video/vga.h>
57*4882a593Smuzhiyun #include <video/cirrus.h>
58*4882a593Smuzhiyun 
59*4882a593Smuzhiyun /*****************************************************************
60*4882a593Smuzhiyun  *
61*4882a593Smuzhiyun  * debugging and utility macros
62*4882a593Smuzhiyun  *
63*4882a593Smuzhiyun  */
64*4882a593Smuzhiyun 
65*4882a593Smuzhiyun /* disable runtime assertions? */
66*4882a593Smuzhiyun /* #define CIRRUSFB_NDEBUG */
67*4882a593Smuzhiyun 
68*4882a593Smuzhiyun /* debugging assertions */
69*4882a593Smuzhiyun #ifndef CIRRUSFB_NDEBUG
70*4882a593Smuzhiyun #define assert(expr) \
71*4882a593Smuzhiyun 	if (!(expr)) { \
72*4882a593Smuzhiyun 		printk("Assertion failed! %s,%s,%s,line=%d\n", \
73*4882a593Smuzhiyun 		#expr, __FILE__, __func__, __LINE__); \
74*4882a593Smuzhiyun 	}
75*4882a593Smuzhiyun #else
76*4882a593Smuzhiyun #define assert(expr)
77*4882a593Smuzhiyun #endif
78*4882a593Smuzhiyun 
79*4882a593Smuzhiyun #define MB_ (1024 * 1024)
80*4882a593Smuzhiyun 
81*4882a593Smuzhiyun /*****************************************************************
82*4882a593Smuzhiyun  *
83*4882a593Smuzhiyun  * chipset information
84*4882a593Smuzhiyun  *
85*4882a593Smuzhiyun  */
86*4882a593Smuzhiyun 
87*4882a593Smuzhiyun /* board types */
88*4882a593Smuzhiyun enum cirrus_board {
89*4882a593Smuzhiyun 	BT_NONE = 0,
90*4882a593Smuzhiyun 	BT_SD64,	/* GD5434 */
91*4882a593Smuzhiyun 	BT_PICCOLO,	/* GD5426 */
92*4882a593Smuzhiyun 	BT_PICASSO,	/* GD5426 or GD5428 */
93*4882a593Smuzhiyun 	BT_SPECTRUM,	/* GD5426 or GD5428 */
94*4882a593Smuzhiyun 	BT_PICASSO4,	/* GD5446 */
95*4882a593Smuzhiyun 	BT_ALPINE,	/* GD543x/4x */
96*4882a593Smuzhiyun 	BT_GD5480,
97*4882a593Smuzhiyun 	BT_LAGUNA,	/* GD5462/64 */
98*4882a593Smuzhiyun 	BT_LAGUNAB,	/* GD5465 */
99*4882a593Smuzhiyun };
100*4882a593Smuzhiyun 
101*4882a593Smuzhiyun /*
102*4882a593Smuzhiyun  * per-board-type information, used for enumerating and abstracting
103*4882a593Smuzhiyun  * chip-specific information
104*4882a593Smuzhiyun  * NOTE: MUST be in the same order as enum cirrus_board in order to
105*4882a593Smuzhiyun  * use direct indexing on this array
106*4882a593Smuzhiyun  * NOTE: '__initdata' cannot be used as some of this info
107*4882a593Smuzhiyun  * is required at runtime.  Maybe separate into an init-only and
108*4882a593Smuzhiyun  * a run-time table?
109*4882a593Smuzhiyun  */
110*4882a593Smuzhiyun static const struct cirrusfb_board_info_rec {
111*4882a593Smuzhiyun 	char *name;		/* ASCII name of chipset */
112*4882a593Smuzhiyun 	long maxclock[5];		/* maximum video clock */
113*4882a593Smuzhiyun 	/* for  1/4bpp, 8bpp 15/16bpp, 24bpp, 32bpp - numbers from xorg code */
114*4882a593Smuzhiyun 	bool init_sr07 : 1; /* init SR07 during init_vgachip() */
115*4882a593Smuzhiyun 	bool init_sr1f : 1; /* write SR1F during init_vgachip() */
116*4882a593Smuzhiyun 	/* construct bit 19 of screen start address */
117*4882a593Smuzhiyun 	bool scrn_start_bit19 : 1;
118*4882a593Smuzhiyun 
119*4882a593Smuzhiyun 	/* initial SR07 value, then for each mode */
120*4882a593Smuzhiyun 	unsigned char sr07;
121*4882a593Smuzhiyun 	unsigned char sr07_1bpp;
122*4882a593Smuzhiyun 	unsigned char sr07_1bpp_mux;
123*4882a593Smuzhiyun 	unsigned char sr07_8bpp;
124*4882a593Smuzhiyun 	unsigned char sr07_8bpp_mux;
125*4882a593Smuzhiyun 
126*4882a593Smuzhiyun 	unsigned char sr1f;	/* SR1F VGA initial register value */
127*4882a593Smuzhiyun } cirrusfb_board_info[] = {
128*4882a593Smuzhiyun 	[BT_SD64] = {
129*4882a593Smuzhiyun 		.name			= "CL SD64",
130*4882a593Smuzhiyun 		.maxclock		= {
131*4882a593Smuzhiyun 			/* guess */
132*4882a593Smuzhiyun 			/* the SD64/P4 have a higher max. videoclock */
133*4882a593Smuzhiyun 			135100, 135100, 85500, 85500, 0
134*4882a593Smuzhiyun 		},
135*4882a593Smuzhiyun 		.init_sr07		= true,
136*4882a593Smuzhiyun 		.init_sr1f		= true,
137*4882a593Smuzhiyun 		.scrn_start_bit19	= true,
138*4882a593Smuzhiyun 		.sr07			= 0xF0,
139*4882a593Smuzhiyun 		.sr07_1bpp		= 0xF0,
140*4882a593Smuzhiyun 		.sr07_1bpp_mux		= 0xF6,
141*4882a593Smuzhiyun 		.sr07_8bpp		= 0xF1,
142*4882a593Smuzhiyun 		.sr07_8bpp_mux		= 0xF7,
143*4882a593Smuzhiyun 		.sr1f			= 0x1E
144*4882a593Smuzhiyun 	},
145*4882a593Smuzhiyun 	[BT_PICCOLO] = {
146*4882a593Smuzhiyun 		.name			= "CL Piccolo",
147*4882a593Smuzhiyun 		.maxclock		= {
148*4882a593Smuzhiyun 			/* guess */
149*4882a593Smuzhiyun 			90000, 90000, 90000, 90000, 90000
150*4882a593Smuzhiyun 		},
151*4882a593Smuzhiyun 		.init_sr07		= true,
152*4882a593Smuzhiyun 		.init_sr1f		= true,
153*4882a593Smuzhiyun 		.scrn_start_bit19	= false,
154*4882a593Smuzhiyun 		.sr07			= 0x80,
155*4882a593Smuzhiyun 		.sr07_1bpp		= 0x80,
156*4882a593Smuzhiyun 		.sr07_8bpp		= 0x81,
157*4882a593Smuzhiyun 		.sr1f			= 0x22
158*4882a593Smuzhiyun 	},
159*4882a593Smuzhiyun 	[BT_PICASSO] = {
160*4882a593Smuzhiyun 		.name			= "CL Picasso",
161*4882a593Smuzhiyun 		.maxclock		= {
162*4882a593Smuzhiyun 			/* guess */
163*4882a593Smuzhiyun 			90000, 90000, 90000, 90000, 90000
164*4882a593Smuzhiyun 		},
165*4882a593Smuzhiyun 		.init_sr07		= true,
166*4882a593Smuzhiyun 		.init_sr1f		= true,
167*4882a593Smuzhiyun 		.scrn_start_bit19	= false,
168*4882a593Smuzhiyun 		.sr07			= 0x20,
169*4882a593Smuzhiyun 		.sr07_1bpp		= 0x20,
170*4882a593Smuzhiyun 		.sr07_8bpp		= 0x21,
171*4882a593Smuzhiyun 		.sr1f			= 0x22
172*4882a593Smuzhiyun 	},
173*4882a593Smuzhiyun 	[BT_SPECTRUM] = {
174*4882a593Smuzhiyun 		.name			= "CL Spectrum",
175*4882a593Smuzhiyun 		.maxclock		= {
176*4882a593Smuzhiyun 			/* guess */
177*4882a593Smuzhiyun 			90000, 90000, 90000, 90000, 90000
178*4882a593Smuzhiyun 		},
179*4882a593Smuzhiyun 		.init_sr07		= true,
180*4882a593Smuzhiyun 		.init_sr1f		= true,
181*4882a593Smuzhiyun 		.scrn_start_bit19	= false,
182*4882a593Smuzhiyun 		.sr07			= 0x80,
183*4882a593Smuzhiyun 		.sr07_1bpp		= 0x80,
184*4882a593Smuzhiyun 		.sr07_8bpp		= 0x81,
185*4882a593Smuzhiyun 		.sr1f			= 0x22
186*4882a593Smuzhiyun 	},
187*4882a593Smuzhiyun 	[BT_PICASSO4] = {
188*4882a593Smuzhiyun 		.name			= "CL Picasso4",
189*4882a593Smuzhiyun 		.maxclock		= {
190*4882a593Smuzhiyun 			135100, 135100, 85500, 85500, 0
191*4882a593Smuzhiyun 		},
192*4882a593Smuzhiyun 		.init_sr07		= true,
193*4882a593Smuzhiyun 		.init_sr1f		= false,
194*4882a593Smuzhiyun 		.scrn_start_bit19	= true,
195*4882a593Smuzhiyun 		.sr07			= 0xA0,
196*4882a593Smuzhiyun 		.sr07_1bpp		= 0xA0,
197*4882a593Smuzhiyun 		.sr07_1bpp_mux		= 0xA6,
198*4882a593Smuzhiyun 		.sr07_8bpp		= 0xA1,
199*4882a593Smuzhiyun 		.sr07_8bpp_mux		= 0xA7,
200*4882a593Smuzhiyun 		.sr1f			= 0
201*4882a593Smuzhiyun 	},
202*4882a593Smuzhiyun 	[BT_ALPINE] = {
203*4882a593Smuzhiyun 		.name			= "CL Alpine",
204*4882a593Smuzhiyun 		.maxclock		= {
205*4882a593Smuzhiyun 			/* for the GD5430.  GD5446 can do more... */
206*4882a593Smuzhiyun 			85500, 85500, 50000, 28500, 0
207*4882a593Smuzhiyun 		},
208*4882a593Smuzhiyun 		.init_sr07		= true,
209*4882a593Smuzhiyun 		.init_sr1f		= true,
210*4882a593Smuzhiyun 		.scrn_start_bit19	= true,
211*4882a593Smuzhiyun 		.sr07			= 0xA0,
212*4882a593Smuzhiyun 		.sr07_1bpp		= 0xA0,
213*4882a593Smuzhiyun 		.sr07_1bpp_mux		= 0xA6,
214*4882a593Smuzhiyun 		.sr07_8bpp		= 0xA1,
215*4882a593Smuzhiyun 		.sr07_8bpp_mux		= 0xA7,
216*4882a593Smuzhiyun 		.sr1f			= 0x1C
217*4882a593Smuzhiyun 	},
218*4882a593Smuzhiyun 	[BT_GD5480] = {
219*4882a593Smuzhiyun 		.name			= "CL GD5480",
220*4882a593Smuzhiyun 		.maxclock		= {
221*4882a593Smuzhiyun 			135100, 200000, 200000, 135100, 135100
222*4882a593Smuzhiyun 		},
223*4882a593Smuzhiyun 		.init_sr07		= true,
224*4882a593Smuzhiyun 		.init_sr1f		= true,
225*4882a593Smuzhiyun 		.scrn_start_bit19	= true,
226*4882a593Smuzhiyun 		.sr07			= 0x10,
227*4882a593Smuzhiyun 		.sr07_1bpp		= 0x11,
228*4882a593Smuzhiyun 		.sr07_8bpp		= 0x11,
229*4882a593Smuzhiyun 		.sr1f			= 0x1C
230*4882a593Smuzhiyun 	},
231*4882a593Smuzhiyun 	[BT_LAGUNA] = {
232*4882a593Smuzhiyun 		.name			= "CL Laguna",
233*4882a593Smuzhiyun 		.maxclock		= {
234*4882a593Smuzhiyun 			/* taken from X11 code */
235*4882a593Smuzhiyun 			170000, 170000, 170000, 170000, 135100,
236*4882a593Smuzhiyun 		},
237*4882a593Smuzhiyun 		.init_sr07		= false,
238*4882a593Smuzhiyun 		.init_sr1f		= false,
239*4882a593Smuzhiyun 		.scrn_start_bit19	= true,
240*4882a593Smuzhiyun 	},
241*4882a593Smuzhiyun 	[BT_LAGUNAB] = {
242*4882a593Smuzhiyun 		.name			= "CL Laguna AGP",
243*4882a593Smuzhiyun 		.maxclock		= {
244*4882a593Smuzhiyun 			/* taken from X11 code */
245*4882a593Smuzhiyun 			170000, 250000, 170000, 170000, 135100,
246*4882a593Smuzhiyun 		},
247*4882a593Smuzhiyun 		.init_sr07		= false,
248*4882a593Smuzhiyun 		.init_sr1f		= false,
249*4882a593Smuzhiyun 		.scrn_start_bit19	= true,
250*4882a593Smuzhiyun 	}
251*4882a593Smuzhiyun };
252*4882a593Smuzhiyun 
253*4882a593Smuzhiyun #ifdef CONFIG_PCI
254*4882a593Smuzhiyun #define CHIP(id, btype) \
255*4882a593Smuzhiyun 	{ PCI_VENDOR_ID_CIRRUS, id, PCI_ANY_ID, PCI_ANY_ID, 0, 0, (btype) }
256*4882a593Smuzhiyun 
257*4882a593Smuzhiyun static struct pci_device_id cirrusfb_pci_table[] = {
258*4882a593Smuzhiyun 	CHIP(PCI_DEVICE_ID_CIRRUS_5436, BT_ALPINE),
259*4882a593Smuzhiyun 	CHIP(PCI_DEVICE_ID_CIRRUS_5434_8, BT_SD64),
260*4882a593Smuzhiyun 	CHIP(PCI_DEVICE_ID_CIRRUS_5434_4, BT_SD64),
261*4882a593Smuzhiyun 	CHIP(PCI_DEVICE_ID_CIRRUS_5430, BT_ALPINE), /* GD-5440 is same id */
262*4882a593Smuzhiyun 	CHIP(PCI_DEVICE_ID_CIRRUS_7543, BT_ALPINE),
263*4882a593Smuzhiyun 	CHIP(PCI_DEVICE_ID_CIRRUS_7548, BT_ALPINE),
264*4882a593Smuzhiyun 	CHIP(PCI_DEVICE_ID_CIRRUS_5480, BT_GD5480), /* MacPicasso likely */
265*4882a593Smuzhiyun 	CHIP(PCI_DEVICE_ID_CIRRUS_5446, BT_PICASSO4), /* Picasso 4 is 5446 */
266*4882a593Smuzhiyun 	CHIP(PCI_DEVICE_ID_CIRRUS_5462, BT_LAGUNA), /* CL Laguna */
267*4882a593Smuzhiyun 	CHIP(PCI_DEVICE_ID_CIRRUS_5464, BT_LAGUNA), /* CL Laguna 3D */
268*4882a593Smuzhiyun 	CHIP(PCI_DEVICE_ID_CIRRUS_5465, BT_LAGUNAB), /* CL Laguna 3DA*/
269*4882a593Smuzhiyun 	{ 0, }
270*4882a593Smuzhiyun };
271*4882a593Smuzhiyun MODULE_DEVICE_TABLE(pci, cirrusfb_pci_table);
272*4882a593Smuzhiyun #undef CHIP
273*4882a593Smuzhiyun #endif /* CONFIG_PCI */
274*4882a593Smuzhiyun 
275*4882a593Smuzhiyun #ifdef CONFIG_ZORRO
276*4882a593Smuzhiyun struct zorrocl {
277*4882a593Smuzhiyun 	enum cirrus_board type;	/* Board type */
278*4882a593Smuzhiyun 	u32 regoffset;		/* Offset of registers in first Zorro device */
279*4882a593Smuzhiyun 	u32 ramsize;		/* Size of video RAM in first Zorro device */
280*4882a593Smuzhiyun 				/* If zero, use autoprobe on RAM device */
281*4882a593Smuzhiyun 	u32 ramoffset;		/* Offset of video RAM in first Zorro device */
282*4882a593Smuzhiyun 	zorro_id ramid;		/* Zorro ID of RAM device */
283*4882a593Smuzhiyun 	zorro_id ramid2;	/* Zorro ID of optional second RAM device */
284*4882a593Smuzhiyun };
285*4882a593Smuzhiyun 
286*4882a593Smuzhiyun static const struct zorrocl zcl_sd64 = {
287*4882a593Smuzhiyun 	.type		= BT_SD64,
288*4882a593Smuzhiyun 	.ramid		= ZORRO_PROD_HELFRICH_SD64_RAM,
289*4882a593Smuzhiyun };
290*4882a593Smuzhiyun 
291*4882a593Smuzhiyun static const struct zorrocl zcl_piccolo = {
292*4882a593Smuzhiyun 	.type		= BT_PICCOLO,
293*4882a593Smuzhiyun 	.ramid		= ZORRO_PROD_HELFRICH_PICCOLO_RAM,
294*4882a593Smuzhiyun };
295*4882a593Smuzhiyun 
296*4882a593Smuzhiyun static const struct zorrocl zcl_picasso = {
297*4882a593Smuzhiyun 	.type		= BT_PICASSO,
298*4882a593Smuzhiyun 	.ramid		= ZORRO_PROD_VILLAGE_TRONIC_PICASSO_II_II_PLUS_RAM,
299*4882a593Smuzhiyun };
300*4882a593Smuzhiyun 
301*4882a593Smuzhiyun static const struct zorrocl zcl_spectrum = {
302*4882a593Smuzhiyun 	.type		= BT_SPECTRUM,
303*4882a593Smuzhiyun 	.ramid		= ZORRO_PROD_GVP_EGS_28_24_SPECTRUM_RAM,
304*4882a593Smuzhiyun };
305*4882a593Smuzhiyun 
306*4882a593Smuzhiyun static const struct zorrocl zcl_picasso4_z3 = {
307*4882a593Smuzhiyun 	.type		= BT_PICASSO4,
308*4882a593Smuzhiyun 	.regoffset	= 0x00600000,
309*4882a593Smuzhiyun 	.ramsize	= 4 * MB_,
310*4882a593Smuzhiyun 	.ramoffset	= 0x01000000,	/* 0x02000000 for 64 MiB boards */
311*4882a593Smuzhiyun };
312*4882a593Smuzhiyun 
313*4882a593Smuzhiyun static const struct zorrocl zcl_picasso4_z2 = {
314*4882a593Smuzhiyun 	.type		= BT_PICASSO4,
315*4882a593Smuzhiyun 	.regoffset	= 0x10000,
316*4882a593Smuzhiyun 	.ramid		= ZORRO_PROD_VILLAGE_TRONIC_PICASSO_IV_Z2_RAM1,
317*4882a593Smuzhiyun 	.ramid2		= ZORRO_PROD_VILLAGE_TRONIC_PICASSO_IV_Z2_RAM2,
318*4882a593Smuzhiyun };
319*4882a593Smuzhiyun 
320*4882a593Smuzhiyun 
321*4882a593Smuzhiyun static const struct zorro_device_id cirrusfb_zorro_table[] = {
322*4882a593Smuzhiyun 	{
323*4882a593Smuzhiyun 		.id		= ZORRO_PROD_HELFRICH_SD64_REG,
324*4882a593Smuzhiyun 		.driver_data	= (unsigned long)&zcl_sd64,
325*4882a593Smuzhiyun 	}, {
326*4882a593Smuzhiyun 		.id		= ZORRO_PROD_HELFRICH_PICCOLO_REG,
327*4882a593Smuzhiyun 		.driver_data	= (unsigned long)&zcl_piccolo,
328*4882a593Smuzhiyun 	}, {
329*4882a593Smuzhiyun 		.id	= ZORRO_PROD_VILLAGE_TRONIC_PICASSO_II_II_PLUS_REG,
330*4882a593Smuzhiyun 		.driver_data	= (unsigned long)&zcl_picasso,
331*4882a593Smuzhiyun 	}, {
332*4882a593Smuzhiyun 		.id		= ZORRO_PROD_GVP_EGS_28_24_SPECTRUM_REG,
333*4882a593Smuzhiyun 		.driver_data	= (unsigned long)&zcl_spectrum,
334*4882a593Smuzhiyun 	}, {
335*4882a593Smuzhiyun 		.id		= ZORRO_PROD_VILLAGE_TRONIC_PICASSO_IV_Z3,
336*4882a593Smuzhiyun 		.driver_data	= (unsigned long)&zcl_picasso4_z3,
337*4882a593Smuzhiyun 	}, {
338*4882a593Smuzhiyun 		.id		= ZORRO_PROD_VILLAGE_TRONIC_PICASSO_IV_Z2_REG,
339*4882a593Smuzhiyun 		.driver_data	= (unsigned long)&zcl_picasso4_z2,
340*4882a593Smuzhiyun 	},
341*4882a593Smuzhiyun 	{ 0 }
342*4882a593Smuzhiyun };
343*4882a593Smuzhiyun MODULE_DEVICE_TABLE(zorro, cirrusfb_zorro_table);
344*4882a593Smuzhiyun #endif /* CONFIG_ZORRO */
345*4882a593Smuzhiyun 
346*4882a593Smuzhiyun #ifdef CIRRUSFB_DEBUG
347*4882a593Smuzhiyun enum cirrusfb_dbg_reg_class {
348*4882a593Smuzhiyun 	CRT,
349*4882a593Smuzhiyun 	SEQ
350*4882a593Smuzhiyun };
351*4882a593Smuzhiyun #endif		/* CIRRUSFB_DEBUG */
352*4882a593Smuzhiyun 
353*4882a593Smuzhiyun /* info about board */
354*4882a593Smuzhiyun struct cirrusfb_info {
355*4882a593Smuzhiyun 	u8 __iomem *regbase;
356*4882a593Smuzhiyun 	u8 __iomem *laguna_mmio;
357*4882a593Smuzhiyun 	enum cirrus_board btype;
358*4882a593Smuzhiyun 	unsigned char SFR;	/* Shadow of special function register */
359*4882a593Smuzhiyun 
360*4882a593Smuzhiyun 	int multiplexing;
361*4882a593Smuzhiyun 	int doubleVCLK;
362*4882a593Smuzhiyun 	int blank_mode;
363*4882a593Smuzhiyun 	u32 pseudo_palette[16];
364*4882a593Smuzhiyun 
365*4882a593Smuzhiyun 	void (*unmap)(struct fb_info *info);
366*4882a593Smuzhiyun };
367*4882a593Smuzhiyun 
368*4882a593Smuzhiyun static bool noaccel;
369*4882a593Smuzhiyun static char *mode_option = "640x480@60";
370*4882a593Smuzhiyun 
371*4882a593Smuzhiyun /****************************************************************************/
372*4882a593Smuzhiyun /**** BEGIN PROTOTYPES ******************************************************/
373*4882a593Smuzhiyun 
374*4882a593Smuzhiyun /*--- Interface used by the world ------------------------------------------*/
375*4882a593Smuzhiyun static int cirrusfb_pan_display(struct fb_var_screeninfo *var,
376*4882a593Smuzhiyun 				struct fb_info *info);
377*4882a593Smuzhiyun 
378*4882a593Smuzhiyun /*--- Internal routines ----------------------------------------------------*/
379*4882a593Smuzhiyun static void init_vgachip(struct fb_info *info);
380*4882a593Smuzhiyun static void switch_monitor(struct cirrusfb_info *cinfo, int on);
381*4882a593Smuzhiyun static void WGen(const struct cirrusfb_info *cinfo,
382*4882a593Smuzhiyun 		 int regnum, unsigned char val);
383*4882a593Smuzhiyun static unsigned char RGen(const struct cirrusfb_info *cinfo, int regnum);
384*4882a593Smuzhiyun static void AttrOn(const struct cirrusfb_info *cinfo);
385*4882a593Smuzhiyun static void WHDR(const struct cirrusfb_info *cinfo, unsigned char val);
386*4882a593Smuzhiyun static void WSFR(struct cirrusfb_info *cinfo, unsigned char val);
387*4882a593Smuzhiyun static void WSFR2(struct cirrusfb_info *cinfo, unsigned char val);
388*4882a593Smuzhiyun static void WClut(struct cirrusfb_info *cinfo, unsigned char regnum,
389*4882a593Smuzhiyun 		  unsigned char red, unsigned char green, unsigned char blue);
390*4882a593Smuzhiyun #if 0
391*4882a593Smuzhiyun static void RClut(struct cirrusfb_info *cinfo, unsigned char regnum,
392*4882a593Smuzhiyun 		  unsigned char *red, unsigned char *green,
393*4882a593Smuzhiyun 		  unsigned char *blue);
394*4882a593Smuzhiyun #endif
395*4882a593Smuzhiyun static void cirrusfb_WaitBLT(u8 __iomem *regbase);
396*4882a593Smuzhiyun static void cirrusfb_BitBLT(u8 __iomem *regbase, int bits_per_pixel,
397*4882a593Smuzhiyun 			    u_short curx, u_short cury,
398*4882a593Smuzhiyun 			    u_short destx, u_short desty,
399*4882a593Smuzhiyun 			    u_short width, u_short height,
400*4882a593Smuzhiyun 			    u_short line_length);
401*4882a593Smuzhiyun static void cirrusfb_RectFill(u8 __iomem *regbase, int bits_per_pixel,
402*4882a593Smuzhiyun 			      u_short x, u_short y,
403*4882a593Smuzhiyun 			      u_short width, u_short height,
404*4882a593Smuzhiyun 			      u32 fg_color, u32 bg_color,
405*4882a593Smuzhiyun 			      u_short line_length, u_char blitmode);
406*4882a593Smuzhiyun 
407*4882a593Smuzhiyun static void bestclock(long freq, int *nom, int *den, int *div);
408*4882a593Smuzhiyun 
409*4882a593Smuzhiyun #ifdef CIRRUSFB_DEBUG
410*4882a593Smuzhiyun static void cirrusfb_dbg_reg_dump(struct fb_info *info, caddr_t regbase);
411*4882a593Smuzhiyun static void cirrusfb_dbg_print_regs(struct fb_info *info,
412*4882a593Smuzhiyun 				    caddr_t regbase,
413*4882a593Smuzhiyun 				    enum cirrusfb_dbg_reg_class reg_class, ...);
414*4882a593Smuzhiyun #endif /* CIRRUSFB_DEBUG */
415*4882a593Smuzhiyun 
416*4882a593Smuzhiyun /*** END   PROTOTYPES ********************************************************/
417*4882a593Smuzhiyun /*****************************************************************************/
418*4882a593Smuzhiyun /*** BEGIN Interface Used by the World ***************************************/
419*4882a593Smuzhiyun 
is_laguna(const struct cirrusfb_info * cinfo)420*4882a593Smuzhiyun static inline int is_laguna(const struct cirrusfb_info *cinfo)
421*4882a593Smuzhiyun {
422*4882a593Smuzhiyun 	return cinfo->btype == BT_LAGUNA || cinfo->btype == BT_LAGUNAB;
423*4882a593Smuzhiyun }
424*4882a593Smuzhiyun 
425*4882a593Smuzhiyun static int opencount;
426*4882a593Smuzhiyun 
427*4882a593Smuzhiyun /*--- Open /dev/fbx ---------------------------------------------------------*/
cirrusfb_open(struct fb_info * info,int user)428*4882a593Smuzhiyun static int cirrusfb_open(struct fb_info *info, int user)
429*4882a593Smuzhiyun {
430*4882a593Smuzhiyun 	if (opencount++ == 0)
431*4882a593Smuzhiyun 		switch_monitor(info->par, 1);
432*4882a593Smuzhiyun 	return 0;
433*4882a593Smuzhiyun }
434*4882a593Smuzhiyun 
435*4882a593Smuzhiyun /*--- Close /dev/fbx --------------------------------------------------------*/
cirrusfb_release(struct fb_info * info,int user)436*4882a593Smuzhiyun static int cirrusfb_release(struct fb_info *info, int user)
437*4882a593Smuzhiyun {
438*4882a593Smuzhiyun 	if (--opencount == 0)
439*4882a593Smuzhiyun 		switch_monitor(info->par, 0);
440*4882a593Smuzhiyun 	return 0;
441*4882a593Smuzhiyun }
442*4882a593Smuzhiyun 
443*4882a593Smuzhiyun /**** END   Interface used by the World *************************************/
444*4882a593Smuzhiyun /****************************************************************************/
445*4882a593Smuzhiyun /**** BEGIN Hardware specific Routines **************************************/
446*4882a593Smuzhiyun 
447*4882a593Smuzhiyun /* Check if the MCLK is not a better clock source */
cirrusfb_check_mclk(struct fb_info * info,long freq)448*4882a593Smuzhiyun static int cirrusfb_check_mclk(struct fb_info *info, long freq)
449*4882a593Smuzhiyun {
450*4882a593Smuzhiyun 	struct cirrusfb_info *cinfo = info->par;
451*4882a593Smuzhiyun 	long mclk = vga_rseq(cinfo->regbase, CL_SEQR1F) & 0x3f;
452*4882a593Smuzhiyun 
453*4882a593Smuzhiyun 	/* Read MCLK value */
454*4882a593Smuzhiyun 	mclk = (14318 * mclk) >> 3;
455*4882a593Smuzhiyun 	dev_dbg(info->device, "Read MCLK of %ld kHz\n", mclk);
456*4882a593Smuzhiyun 
457*4882a593Smuzhiyun 	/* Determine if we should use MCLK instead of VCLK, and if so, what we
458*4882a593Smuzhiyun 	 * should divide it by to get VCLK
459*4882a593Smuzhiyun 	 */
460*4882a593Smuzhiyun 
461*4882a593Smuzhiyun 	if (abs(freq - mclk) < 250) {
462*4882a593Smuzhiyun 		dev_dbg(info->device, "Using VCLK = MCLK\n");
463*4882a593Smuzhiyun 		return 1;
464*4882a593Smuzhiyun 	} else if (abs(freq - (mclk / 2)) < 250) {
465*4882a593Smuzhiyun 		dev_dbg(info->device, "Using VCLK = MCLK/2\n");
466*4882a593Smuzhiyun 		return 2;
467*4882a593Smuzhiyun 	}
468*4882a593Smuzhiyun 
469*4882a593Smuzhiyun 	return 0;
470*4882a593Smuzhiyun }
471*4882a593Smuzhiyun 
cirrusfb_check_pixclock(struct fb_var_screeninfo * var,struct fb_info * info)472*4882a593Smuzhiyun static int cirrusfb_check_pixclock(struct fb_var_screeninfo *var,
473*4882a593Smuzhiyun 				   struct fb_info *info)
474*4882a593Smuzhiyun {
475*4882a593Smuzhiyun 	long freq;
476*4882a593Smuzhiyun 	long maxclock;
477*4882a593Smuzhiyun 	struct cirrusfb_info *cinfo = info->par;
478*4882a593Smuzhiyun 	unsigned maxclockidx = var->bits_per_pixel >> 3;
479*4882a593Smuzhiyun 
480*4882a593Smuzhiyun 	/* convert from ps to kHz */
481*4882a593Smuzhiyun 	freq = PICOS2KHZ(var->pixclock ? : 1);
482*4882a593Smuzhiyun 
483*4882a593Smuzhiyun 	maxclock = cirrusfb_board_info[cinfo->btype].maxclock[maxclockidx];
484*4882a593Smuzhiyun 	cinfo->multiplexing = 0;
485*4882a593Smuzhiyun 
486*4882a593Smuzhiyun 	/* If the frequency is greater than we can support, we might be able
487*4882a593Smuzhiyun 	 * to use multiplexing for the video mode */
488*4882a593Smuzhiyun 	if (freq > maxclock) {
489*4882a593Smuzhiyun 		var->pixclock = KHZ2PICOS(maxclock);
490*4882a593Smuzhiyun 
491*4882a593Smuzhiyun 		while ((freq = PICOS2KHZ(var->pixclock)) > maxclock)
492*4882a593Smuzhiyun 			var->pixclock++;
493*4882a593Smuzhiyun 	}
494*4882a593Smuzhiyun 	dev_dbg(info->device, "desired pixclock: %ld kHz\n", freq);
495*4882a593Smuzhiyun 
496*4882a593Smuzhiyun 	/*
497*4882a593Smuzhiyun 	 * Additional constraint: 8bpp uses DAC clock doubling to allow maximum
498*4882a593Smuzhiyun 	 * pixel clock
499*4882a593Smuzhiyun 	 */
500*4882a593Smuzhiyun 	if (var->bits_per_pixel == 8) {
501*4882a593Smuzhiyun 		switch (cinfo->btype) {
502*4882a593Smuzhiyun 		case BT_ALPINE:
503*4882a593Smuzhiyun 		case BT_SD64:
504*4882a593Smuzhiyun 		case BT_PICASSO4:
505*4882a593Smuzhiyun 			if (freq > 85500)
506*4882a593Smuzhiyun 				cinfo->multiplexing = 1;
507*4882a593Smuzhiyun 			break;
508*4882a593Smuzhiyun 		case BT_GD5480:
509*4882a593Smuzhiyun 			if (freq > 135100)
510*4882a593Smuzhiyun 				cinfo->multiplexing = 1;
511*4882a593Smuzhiyun 			break;
512*4882a593Smuzhiyun 
513*4882a593Smuzhiyun 		default:
514*4882a593Smuzhiyun 			break;
515*4882a593Smuzhiyun 		}
516*4882a593Smuzhiyun 	}
517*4882a593Smuzhiyun 
518*4882a593Smuzhiyun 	/* If we have a 1MB 5434, we need to put ourselves in a mode where
519*4882a593Smuzhiyun 	 * the VCLK is double the pixel clock. */
520*4882a593Smuzhiyun 	cinfo->doubleVCLK = 0;
521*4882a593Smuzhiyun 	if (cinfo->btype == BT_SD64 && info->fix.smem_len <= MB_ &&
522*4882a593Smuzhiyun 	    var->bits_per_pixel == 16) {
523*4882a593Smuzhiyun 		cinfo->doubleVCLK = 1;
524*4882a593Smuzhiyun 	}
525*4882a593Smuzhiyun 
526*4882a593Smuzhiyun 	return 0;
527*4882a593Smuzhiyun }
528*4882a593Smuzhiyun 
cirrusfb_check_var(struct fb_var_screeninfo * var,struct fb_info * info)529*4882a593Smuzhiyun static int cirrusfb_check_var(struct fb_var_screeninfo *var,
530*4882a593Smuzhiyun 			      struct fb_info *info)
531*4882a593Smuzhiyun {
532*4882a593Smuzhiyun 	int yres;
533*4882a593Smuzhiyun 	/* memory size in pixels */
534*4882a593Smuzhiyun 	unsigned pixels = info->screen_size * 8 / var->bits_per_pixel;
535*4882a593Smuzhiyun 	struct cirrusfb_info *cinfo = info->par;
536*4882a593Smuzhiyun 
537*4882a593Smuzhiyun 	switch (var->bits_per_pixel) {
538*4882a593Smuzhiyun 	case 1:
539*4882a593Smuzhiyun 		var->red.offset = 0;
540*4882a593Smuzhiyun 		var->red.length = 1;
541*4882a593Smuzhiyun 		var->green = var->red;
542*4882a593Smuzhiyun 		var->blue = var->red;
543*4882a593Smuzhiyun 		break;
544*4882a593Smuzhiyun 
545*4882a593Smuzhiyun 	case 8:
546*4882a593Smuzhiyun 		var->red.offset = 0;
547*4882a593Smuzhiyun 		var->red.length = 8;
548*4882a593Smuzhiyun 		var->green = var->red;
549*4882a593Smuzhiyun 		var->blue = var->red;
550*4882a593Smuzhiyun 		break;
551*4882a593Smuzhiyun 
552*4882a593Smuzhiyun 	case 16:
553*4882a593Smuzhiyun 		var->red.offset = 11;
554*4882a593Smuzhiyun 		var->green.offset = 5;
555*4882a593Smuzhiyun 		var->blue.offset = 0;
556*4882a593Smuzhiyun 		var->red.length = 5;
557*4882a593Smuzhiyun 		var->green.length = 6;
558*4882a593Smuzhiyun 		var->blue.length = 5;
559*4882a593Smuzhiyun 		break;
560*4882a593Smuzhiyun 
561*4882a593Smuzhiyun 	case 24:
562*4882a593Smuzhiyun 		var->red.offset = 16;
563*4882a593Smuzhiyun 		var->green.offset = 8;
564*4882a593Smuzhiyun 		var->blue.offset = 0;
565*4882a593Smuzhiyun 		var->red.length = 8;
566*4882a593Smuzhiyun 		var->green.length = 8;
567*4882a593Smuzhiyun 		var->blue.length = 8;
568*4882a593Smuzhiyun 		break;
569*4882a593Smuzhiyun 
570*4882a593Smuzhiyun 	default:
571*4882a593Smuzhiyun 		dev_dbg(info->device,
572*4882a593Smuzhiyun 			"Unsupported bpp size: %d\n", var->bits_per_pixel);
573*4882a593Smuzhiyun 		return -EINVAL;
574*4882a593Smuzhiyun 	}
575*4882a593Smuzhiyun 
576*4882a593Smuzhiyun 	if (var->xres_virtual < var->xres)
577*4882a593Smuzhiyun 		var->xres_virtual = var->xres;
578*4882a593Smuzhiyun 	/* use highest possible virtual resolution */
579*4882a593Smuzhiyun 	if (var->yres_virtual == -1) {
580*4882a593Smuzhiyun 		var->yres_virtual = pixels / var->xres_virtual;
581*4882a593Smuzhiyun 
582*4882a593Smuzhiyun 		dev_info(info->device,
583*4882a593Smuzhiyun 			 "virtual resolution set to maximum of %dx%d\n",
584*4882a593Smuzhiyun 			 var->xres_virtual, var->yres_virtual);
585*4882a593Smuzhiyun 	}
586*4882a593Smuzhiyun 	if (var->yres_virtual < var->yres)
587*4882a593Smuzhiyun 		var->yres_virtual = var->yres;
588*4882a593Smuzhiyun 
589*4882a593Smuzhiyun 	if (var->xres_virtual * var->yres_virtual > pixels) {
590*4882a593Smuzhiyun 		dev_err(info->device, "mode %dx%dx%d rejected... "
591*4882a593Smuzhiyun 		      "virtual resolution too high to fit into video memory!\n",
592*4882a593Smuzhiyun 			var->xres_virtual, var->yres_virtual,
593*4882a593Smuzhiyun 			var->bits_per_pixel);
594*4882a593Smuzhiyun 		return -EINVAL;
595*4882a593Smuzhiyun 	}
596*4882a593Smuzhiyun 
597*4882a593Smuzhiyun 	/* truncate xoffset and yoffset to maximum if too high */
598*4882a593Smuzhiyun 	if (var->xoffset > var->xres_virtual - var->xres)
599*4882a593Smuzhiyun 		var->xoffset = var->xres_virtual - var->xres - 1;
600*4882a593Smuzhiyun 	if (var->yoffset > var->yres_virtual - var->yres)
601*4882a593Smuzhiyun 		var->yoffset = var->yres_virtual - var->yres - 1;
602*4882a593Smuzhiyun 
603*4882a593Smuzhiyun 	var->red.msb_right =
604*4882a593Smuzhiyun 	    var->green.msb_right =
605*4882a593Smuzhiyun 	    var->blue.msb_right =
606*4882a593Smuzhiyun 	    var->transp.offset =
607*4882a593Smuzhiyun 	    var->transp.length =
608*4882a593Smuzhiyun 	    var->transp.msb_right = 0;
609*4882a593Smuzhiyun 
610*4882a593Smuzhiyun 	yres = var->yres;
611*4882a593Smuzhiyun 	if (var->vmode & FB_VMODE_DOUBLE)
612*4882a593Smuzhiyun 		yres *= 2;
613*4882a593Smuzhiyun 	else if (var->vmode & FB_VMODE_INTERLACED)
614*4882a593Smuzhiyun 		yres = (yres + 1) / 2;
615*4882a593Smuzhiyun 
616*4882a593Smuzhiyun 	if (yres >= 1280) {
617*4882a593Smuzhiyun 		dev_err(info->device, "ERROR: VerticalTotal >= 1280; "
618*4882a593Smuzhiyun 			"special treatment required! (TODO)\n");
619*4882a593Smuzhiyun 		return -EINVAL;
620*4882a593Smuzhiyun 	}
621*4882a593Smuzhiyun 
622*4882a593Smuzhiyun 	if (cirrusfb_check_pixclock(var, info))
623*4882a593Smuzhiyun 		return -EINVAL;
624*4882a593Smuzhiyun 
625*4882a593Smuzhiyun 	if (!is_laguna(cinfo))
626*4882a593Smuzhiyun 		var->accel_flags = FB_ACCELF_TEXT;
627*4882a593Smuzhiyun 
628*4882a593Smuzhiyun 	return 0;
629*4882a593Smuzhiyun }
630*4882a593Smuzhiyun 
cirrusfb_set_mclk_as_source(const struct fb_info * info,int div)631*4882a593Smuzhiyun static void cirrusfb_set_mclk_as_source(const struct fb_info *info, int div)
632*4882a593Smuzhiyun {
633*4882a593Smuzhiyun 	struct cirrusfb_info *cinfo = info->par;
634*4882a593Smuzhiyun 	unsigned char old1f, old1e;
635*4882a593Smuzhiyun 
636*4882a593Smuzhiyun 	assert(cinfo != NULL);
637*4882a593Smuzhiyun 	old1f = vga_rseq(cinfo->regbase, CL_SEQR1F) & ~0x40;
638*4882a593Smuzhiyun 
639*4882a593Smuzhiyun 	if (div) {
640*4882a593Smuzhiyun 		dev_dbg(info->device, "Set %s as pixclock source.\n",
641*4882a593Smuzhiyun 			(div == 2) ? "MCLK/2" : "MCLK");
642*4882a593Smuzhiyun 		old1f |= 0x40;
643*4882a593Smuzhiyun 		old1e = vga_rseq(cinfo->regbase, CL_SEQR1E) & ~0x1;
644*4882a593Smuzhiyun 		if (div == 2)
645*4882a593Smuzhiyun 			old1e |= 1;
646*4882a593Smuzhiyun 
647*4882a593Smuzhiyun 		vga_wseq(cinfo->regbase, CL_SEQR1E, old1e);
648*4882a593Smuzhiyun 	}
649*4882a593Smuzhiyun 	vga_wseq(cinfo->regbase, CL_SEQR1F, old1f);
650*4882a593Smuzhiyun }
651*4882a593Smuzhiyun 
652*4882a593Smuzhiyun /*************************************************************************
653*4882a593Smuzhiyun 	cirrusfb_set_par_foo()
654*4882a593Smuzhiyun 
655*4882a593Smuzhiyun 	actually writes the values for a new video mode into the hardware,
656*4882a593Smuzhiyun **************************************************************************/
cirrusfb_set_par_foo(struct fb_info * info)657*4882a593Smuzhiyun static int cirrusfb_set_par_foo(struct fb_info *info)
658*4882a593Smuzhiyun {
659*4882a593Smuzhiyun 	struct cirrusfb_info *cinfo = info->par;
660*4882a593Smuzhiyun 	struct fb_var_screeninfo *var = &info->var;
661*4882a593Smuzhiyun 	u8 __iomem *regbase = cinfo->regbase;
662*4882a593Smuzhiyun 	unsigned char tmp;
663*4882a593Smuzhiyun 	int pitch;
664*4882a593Smuzhiyun 	const struct cirrusfb_board_info_rec *bi;
665*4882a593Smuzhiyun 	int hdispend, hsyncstart, hsyncend, htotal;
666*4882a593Smuzhiyun 	int yres, vdispend, vsyncstart, vsyncend, vtotal;
667*4882a593Smuzhiyun 	long freq;
668*4882a593Smuzhiyun 	int nom, den, div;
669*4882a593Smuzhiyun 	unsigned int control = 0, format = 0, threshold = 0;
670*4882a593Smuzhiyun 
671*4882a593Smuzhiyun 	dev_dbg(info->device, "Requested mode: %dx%dx%d\n",
672*4882a593Smuzhiyun 	       var->xres, var->yres, var->bits_per_pixel);
673*4882a593Smuzhiyun 
674*4882a593Smuzhiyun 	switch (var->bits_per_pixel) {
675*4882a593Smuzhiyun 	case 1:
676*4882a593Smuzhiyun 		info->fix.line_length = var->xres_virtual / 8;
677*4882a593Smuzhiyun 		info->fix.visual = FB_VISUAL_MONO10;
678*4882a593Smuzhiyun 		break;
679*4882a593Smuzhiyun 
680*4882a593Smuzhiyun 	case 8:
681*4882a593Smuzhiyun 		info->fix.line_length = var->xres_virtual;
682*4882a593Smuzhiyun 		info->fix.visual = FB_VISUAL_PSEUDOCOLOR;
683*4882a593Smuzhiyun 		break;
684*4882a593Smuzhiyun 
685*4882a593Smuzhiyun 	case 16:
686*4882a593Smuzhiyun 	case 24:
687*4882a593Smuzhiyun 		info->fix.line_length = var->xres_virtual *
688*4882a593Smuzhiyun 					var->bits_per_pixel >> 3;
689*4882a593Smuzhiyun 		info->fix.visual = FB_VISUAL_TRUECOLOR;
690*4882a593Smuzhiyun 		break;
691*4882a593Smuzhiyun 	}
692*4882a593Smuzhiyun 	info->fix.type = FB_TYPE_PACKED_PIXELS;
693*4882a593Smuzhiyun 
694*4882a593Smuzhiyun 	init_vgachip(info);
695*4882a593Smuzhiyun 
696*4882a593Smuzhiyun 	bi = &cirrusfb_board_info[cinfo->btype];
697*4882a593Smuzhiyun 
698*4882a593Smuzhiyun 	hsyncstart = var->xres + var->right_margin;
699*4882a593Smuzhiyun 	hsyncend = hsyncstart + var->hsync_len;
700*4882a593Smuzhiyun 	htotal = (hsyncend + var->left_margin) / 8;
701*4882a593Smuzhiyun 	hdispend = var->xres / 8;
702*4882a593Smuzhiyun 	hsyncstart = hsyncstart / 8;
703*4882a593Smuzhiyun 	hsyncend = hsyncend / 8;
704*4882a593Smuzhiyun 
705*4882a593Smuzhiyun 	vdispend = var->yres;
706*4882a593Smuzhiyun 	vsyncstart = vdispend + var->lower_margin;
707*4882a593Smuzhiyun 	vsyncend = vsyncstart + var->vsync_len;
708*4882a593Smuzhiyun 	vtotal = vsyncend + var->upper_margin;
709*4882a593Smuzhiyun 
710*4882a593Smuzhiyun 	if (var->vmode & FB_VMODE_DOUBLE) {
711*4882a593Smuzhiyun 		vdispend *= 2;
712*4882a593Smuzhiyun 		vsyncstart *= 2;
713*4882a593Smuzhiyun 		vsyncend *= 2;
714*4882a593Smuzhiyun 		vtotal *= 2;
715*4882a593Smuzhiyun 	} else if (var->vmode & FB_VMODE_INTERLACED) {
716*4882a593Smuzhiyun 		vdispend = (vdispend + 1) / 2;
717*4882a593Smuzhiyun 		vsyncstart = (vsyncstart + 1) / 2;
718*4882a593Smuzhiyun 		vsyncend = (vsyncend + 1) / 2;
719*4882a593Smuzhiyun 		vtotal = (vtotal + 1) / 2;
720*4882a593Smuzhiyun 	}
721*4882a593Smuzhiyun 	yres = vdispend;
722*4882a593Smuzhiyun 	if (yres >= 1024) {
723*4882a593Smuzhiyun 		vtotal /= 2;
724*4882a593Smuzhiyun 		vsyncstart /= 2;
725*4882a593Smuzhiyun 		vsyncend /= 2;
726*4882a593Smuzhiyun 		vdispend /= 2;
727*4882a593Smuzhiyun 	}
728*4882a593Smuzhiyun 
729*4882a593Smuzhiyun 	vdispend -= 1;
730*4882a593Smuzhiyun 	vsyncstart -= 1;
731*4882a593Smuzhiyun 	vsyncend -= 1;
732*4882a593Smuzhiyun 	vtotal -= 2;
733*4882a593Smuzhiyun 
734*4882a593Smuzhiyun 	if (cinfo->multiplexing) {
735*4882a593Smuzhiyun 		htotal /= 2;
736*4882a593Smuzhiyun 		hsyncstart /= 2;
737*4882a593Smuzhiyun 		hsyncend /= 2;
738*4882a593Smuzhiyun 		hdispend /= 2;
739*4882a593Smuzhiyun 	}
740*4882a593Smuzhiyun 
741*4882a593Smuzhiyun 	htotal -= 5;
742*4882a593Smuzhiyun 	hdispend -= 1;
743*4882a593Smuzhiyun 	hsyncstart += 1;
744*4882a593Smuzhiyun 	hsyncend += 1;
745*4882a593Smuzhiyun 
746*4882a593Smuzhiyun 	/* unlock register VGA_CRTC_H_TOTAL..CRT7 */
747*4882a593Smuzhiyun 	vga_wcrt(regbase, VGA_CRTC_V_SYNC_END, 0x20);	/* previously: 0x00) */
748*4882a593Smuzhiyun 
749*4882a593Smuzhiyun 	/* if debugging is enabled, all parameters get output before writing */
750*4882a593Smuzhiyun 	dev_dbg(info->device, "CRT0: %d\n", htotal);
751*4882a593Smuzhiyun 	vga_wcrt(regbase, VGA_CRTC_H_TOTAL, htotal);
752*4882a593Smuzhiyun 
753*4882a593Smuzhiyun 	dev_dbg(info->device, "CRT1: %d\n", hdispend);
754*4882a593Smuzhiyun 	vga_wcrt(regbase, VGA_CRTC_H_DISP, hdispend);
755*4882a593Smuzhiyun 
756*4882a593Smuzhiyun 	dev_dbg(info->device, "CRT2: %d\n", var->xres / 8);
757*4882a593Smuzhiyun 	vga_wcrt(regbase, VGA_CRTC_H_BLANK_START, var->xres / 8);
758*4882a593Smuzhiyun 
759*4882a593Smuzhiyun 	/*  + 128: Compatible read */
760*4882a593Smuzhiyun 	dev_dbg(info->device, "CRT3: 128+%d\n", (htotal + 5) % 32);
761*4882a593Smuzhiyun 	vga_wcrt(regbase, VGA_CRTC_H_BLANK_END,
762*4882a593Smuzhiyun 		 128 + ((htotal + 5) % 32));
763*4882a593Smuzhiyun 
764*4882a593Smuzhiyun 	dev_dbg(info->device, "CRT4: %d\n", hsyncstart);
765*4882a593Smuzhiyun 	vga_wcrt(regbase, VGA_CRTC_H_SYNC_START, hsyncstart);
766*4882a593Smuzhiyun 
767*4882a593Smuzhiyun 	tmp = hsyncend % 32;
768*4882a593Smuzhiyun 	if ((htotal + 5) & 32)
769*4882a593Smuzhiyun 		tmp += 128;
770*4882a593Smuzhiyun 	dev_dbg(info->device, "CRT5: %d\n", tmp);
771*4882a593Smuzhiyun 	vga_wcrt(regbase, VGA_CRTC_H_SYNC_END, tmp);
772*4882a593Smuzhiyun 
773*4882a593Smuzhiyun 	dev_dbg(info->device, "CRT6: %d\n", vtotal & 0xff);
774*4882a593Smuzhiyun 	vga_wcrt(regbase, VGA_CRTC_V_TOTAL, vtotal & 0xff);
775*4882a593Smuzhiyun 
776*4882a593Smuzhiyun 	tmp = 16;		/* LineCompare bit #9 */
777*4882a593Smuzhiyun 	if (vtotal & 256)
778*4882a593Smuzhiyun 		tmp |= 1;
779*4882a593Smuzhiyun 	if (vdispend & 256)
780*4882a593Smuzhiyun 		tmp |= 2;
781*4882a593Smuzhiyun 	if (vsyncstart & 256)
782*4882a593Smuzhiyun 		tmp |= 4;
783*4882a593Smuzhiyun 	if ((vdispend + 1) & 256)
784*4882a593Smuzhiyun 		tmp |= 8;
785*4882a593Smuzhiyun 	if (vtotal & 512)
786*4882a593Smuzhiyun 		tmp |= 32;
787*4882a593Smuzhiyun 	if (vdispend & 512)
788*4882a593Smuzhiyun 		tmp |= 64;
789*4882a593Smuzhiyun 	if (vsyncstart & 512)
790*4882a593Smuzhiyun 		tmp |= 128;
791*4882a593Smuzhiyun 	dev_dbg(info->device, "CRT7: %d\n", tmp);
792*4882a593Smuzhiyun 	vga_wcrt(regbase, VGA_CRTC_OVERFLOW, tmp);
793*4882a593Smuzhiyun 
794*4882a593Smuzhiyun 	tmp = 0x40;		/* LineCompare bit #8 */
795*4882a593Smuzhiyun 	if ((vdispend + 1) & 512)
796*4882a593Smuzhiyun 		tmp |= 0x20;
797*4882a593Smuzhiyun 	if (var->vmode & FB_VMODE_DOUBLE)
798*4882a593Smuzhiyun 		tmp |= 0x80;
799*4882a593Smuzhiyun 	dev_dbg(info->device, "CRT9: %d\n", tmp);
800*4882a593Smuzhiyun 	vga_wcrt(regbase, VGA_CRTC_MAX_SCAN, tmp);
801*4882a593Smuzhiyun 
802*4882a593Smuzhiyun 	dev_dbg(info->device, "CRT10: %d\n", vsyncstart & 0xff);
803*4882a593Smuzhiyun 	vga_wcrt(regbase, VGA_CRTC_V_SYNC_START, vsyncstart & 0xff);
804*4882a593Smuzhiyun 
805*4882a593Smuzhiyun 	dev_dbg(info->device, "CRT11: 64+32+%d\n", vsyncend % 16);
806*4882a593Smuzhiyun 	vga_wcrt(regbase, VGA_CRTC_V_SYNC_END, vsyncend % 16 + 64 + 32);
807*4882a593Smuzhiyun 
808*4882a593Smuzhiyun 	dev_dbg(info->device, "CRT12: %d\n", vdispend & 0xff);
809*4882a593Smuzhiyun 	vga_wcrt(regbase, VGA_CRTC_V_DISP_END, vdispend & 0xff);
810*4882a593Smuzhiyun 
811*4882a593Smuzhiyun 	dev_dbg(info->device, "CRT15: %d\n", (vdispend + 1) & 0xff);
812*4882a593Smuzhiyun 	vga_wcrt(regbase, VGA_CRTC_V_BLANK_START, (vdispend + 1) & 0xff);
813*4882a593Smuzhiyun 
814*4882a593Smuzhiyun 	dev_dbg(info->device, "CRT16: %d\n", vtotal & 0xff);
815*4882a593Smuzhiyun 	vga_wcrt(regbase, VGA_CRTC_V_BLANK_END, vtotal & 0xff);
816*4882a593Smuzhiyun 
817*4882a593Smuzhiyun 	dev_dbg(info->device, "CRT18: 0xff\n");
818*4882a593Smuzhiyun 	vga_wcrt(regbase, VGA_CRTC_LINE_COMPARE, 0xff);
819*4882a593Smuzhiyun 
820*4882a593Smuzhiyun 	tmp = 0;
821*4882a593Smuzhiyun 	if (var->vmode & FB_VMODE_INTERLACED)
822*4882a593Smuzhiyun 		tmp |= 1;
823*4882a593Smuzhiyun 	if ((htotal + 5) & 64)
824*4882a593Smuzhiyun 		tmp |= 16;
825*4882a593Smuzhiyun 	if ((htotal + 5) & 128)
826*4882a593Smuzhiyun 		tmp |= 32;
827*4882a593Smuzhiyun 	if (vtotal & 256)
828*4882a593Smuzhiyun 		tmp |= 64;
829*4882a593Smuzhiyun 	if (vtotal & 512)
830*4882a593Smuzhiyun 		tmp |= 128;
831*4882a593Smuzhiyun 
832*4882a593Smuzhiyun 	dev_dbg(info->device, "CRT1a: %d\n", tmp);
833*4882a593Smuzhiyun 	vga_wcrt(regbase, CL_CRT1A, tmp);
834*4882a593Smuzhiyun 
835*4882a593Smuzhiyun 	freq = PICOS2KHZ(var->pixclock);
836*4882a593Smuzhiyun 	if (var->bits_per_pixel == 24)
837*4882a593Smuzhiyun 		if (cinfo->btype == BT_ALPINE || cinfo->btype == BT_SD64)
838*4882a593Smuzhiyun 			freq *= 3;
839*4882a593Smuzhiyun 	if (cinfo->multiplexing)
840*4882a593Smuzhiyun 		freq /= 2;
841*4882a593Smuzhiyun 	if (cinfo->doubleVCLK)
842*4882a593Smuzhiyun 		freq *= 2;
843*4882a593Smuzhiyun 
844*4882a593Smuzhiyun 	bestclock(freq, &nom, &den, &div);
845*4882a593Smuzhiyun 
846*4882a593Smuzhiyun 	dev_dbg(info->device, "VCLK freq: %ld kHz  nom: %d  den: %d  div: %d\n",
847*4882a593Smuzhiyun 		freq, nom, den, div);
848*4882a593Smuzhiyun 
849*4882a593Smuzhiyun 	/* set VCLK0 */
850*4882a593Smuzhiyun 	/* hardware RefClock: 14.31818 MHz */
851*4882a593Smuzhiyun 	/* formula: VClk = (OSC * N) / (D * (1+P)) */
852*4882a593Smuzhiyun 	/* Example: VClk = (14.31818 * 91) / (23 * (1+1)) = 28.325 MHz */
853*4882a593Smuzhiyun 
854*4882a593Smuzhiyun 	if (cinfo->btype == BT_ALPINE || cinfo->btype == BT_PICASSO4 ||
855*4882a593Smuzhiyun 	    cinfo->btype == BT_SD64) {
856*4882a593Smuzhiyun 		/* if freq is close to mclk or mclk/2 select mclk
857*4882a593Smuzhiyun 		 * as clock source
858*4882a593Smuzhiyun 		 */
859*4882a593Smuzhiyun 		int divMCLK = cirrusfb_check_mclk(info, freq);
860*4882a593Smuzhiyun 		if (divMCLK)
861*4882a593Smuzhiyun 			nom = 0;
862*4882a593Smuzhiyun 		cirrusfb_set_mclk_as_source(info, divMCLK);
863*4882a593Smuzhiyun 	}
864*4882a593Smuzhiyun 	if (is_laguna(cinfo)) {
865*4882a593Smuzhiyun 		long pcifc = fb_readl(cinfo->laguna_mmio + 0x3fc);
866*4882a593Smuzhiyun 		unsigned char tile = fb_readb(cinfo->laguna_mmio + 0x407);
867*4882a593Smuzhiyun 		unsigned short tile_control;
868*4882a593Smuzhiyun 
869*4882a593Smuzhiyun 		if (cinfo->btype == BT_LAGUNAB) {
870*4882a593Smuzhiyun 			tile_control = fb_readw(cinfo->laguna_mmio + 0x2c4);
871*4882a593Smuzhiyun 			tile_control &= ~0x80;
872*4882a593Smuzhiyun 			fb_writew(tile_control, cinfo->laguna_mmio + 0x2c4);
873*4882a593Smuzhiyun 		}
874*4882a593Smuzhiyun 
875*4882a593Smuzhiyun 		fb_writel(pcifc | 0x10000000l, cinfo->laguna_mmio + 0x3fc);
876*4882a593Smuzhiyun 		fb_writeb(tile & 0x3f, cinfo->laguna_mmio + 0x407);
877*4882a593Smuzhiyun 		control = fb_readw(cinfo->laguna_mmio + 0x402);
878*4882a593Smuzhiyun 		threshold = fb_readw(cinfo->laguna_mmio + 0xea);
879*4882a593Smuzhiyun 		control &= ~0x6800;
880*4882a593Smuzhiyun 		format = 0;
881*4882a593Smuzhiyun 		threshold &= 0xffc0 & 0x3fbf;
882*4882a593Smuzhiyun 	}
883*4882a593Smuzhiyun 	if (nom) {
884*4882a593Smuzhiyun 		tmp = den << 1;
885*4882a593Smuzhiyun 		if (div != 0)
886*4882a593Smuzhiyun 			tmp |= 1;
887*4882a593Smuzhiyun 		/* 6 bit denom; ONLY 5434!!! (bugged me 10 days) */
888*4882a593Smuzhiyun 		if ((cinfo->btype == BT_SD64) ||
889*4882a593Smuzhiyun 		    (cinfo->btype == BT_ALPINE) ||
890*4882a593Smuzhiyun 		    (cinfo->btype == BT_GD5480))
891*4882a593Smuzhiyun 			tmp |= 0x80;
892*4882a593Smuzhiyun 
893*4882a593Smuzhiyun 		/* Laguna chipset has reversed clock registers */
894*4882a593Smuzhiyun 		if (is_laguna(cinfo)) {
895*4882a593Smuzhiyun 			vga_wseq(regbase, CL_SEQRE, tmp);
896*4882a593Smuzhiyun 			vga_wseq(regbase, CL_SEQR1E, nom);
897*4882a593Smuzhiyun 		} else {
898*4882a593Smuzhiyun 			vga_wseq(regbase, CL_SEQRE, nom);
899*4882a593Smuzhiyun 			vga_wseq(regbase, CL_SEQR1E, tmp);
900*4882a593Smuzhiyun 		}
901*4882a593Smuzhiyun 	}
902*4882a593Smuzhiyun 
903*4882a593Smuzhiyun 	if (yres >= 1024)
904*4882a593Smuzhiyun 		/* 1280x1024 */
905*4882a593Smuzhiyun 		vga_wcrt(regbase, VGA_CRTC_MODE, 0xc7);
906*4882a593Smuzhiyun 	else
907*4882a593Smuzhiyun 		/* mode control: VGA_CRTC_START_HI enable, ROTATE(?), 16bit
908*4882a593Smuzhiyun 		 * address wrap, no compat. */
909*4882a593Smuzhiyun 		vga_wcrt(regbase, VGA_CRTC_MODE, 0xc3);
910*4882a593Smuzhiyun 
911*4882a593Smuzhiyun 	/* don't know if it would hurt to also program this if no interlaced */
912*4882a593Smuzhiyun 	/* mode is used, but I feel better this way.. :-) */
913*4882a593Smuzhiyun 	if (var->vmode & FB_VMODE_INTERLACED)
914*4882a593Smuzhiyun 		vga_wcrt(regbase, VGA_CRTC_REGS, htotal / 2);
915*4882a593Smuzhiyun 	else
916*4882a593Smuzhiyun 		vga_wcrt(regbase, VGA_CRTC_REGS, 0x00);	/* interlace control */
917*4882a593Smuzhiyun 
918*4882a593Smuzhiyun 	/* adjust horizontal/vertical sync type (low/high), use VCLK3 */
919*4882a593Smuzhiyun 	/* enable display memory & CRTC I/O address for color mode */
920*4882a593Smuzhiyun 	tmp = 0x03 | 0xc;
921*4882a593Smuzhiyun 	if (var->sync & FB_SYNC_HOR_HIGH_ACT)
922*4882a593Smuzhiyun 		tmp |= 0x40;
923*4882a593Smuzhiyun 	if (var->sync & FB_SYNC_VERT_HIGH_ACT)
924*4882a593Smuzhiyun 		tmp |= 0x80;
925*4882a593Smuzhiyun 	WGen(cinfo, VGA_MIS_W, tmp);
926*4882a593Smuzhiyun 
927*4882a593Smuzhiyun 	/* text cursor on and start line */
928*4882a593Smuzhiyun 	vga_wcrt(regbase, VGA_CRTC_CURSOR_START, 0);
929*4882a593Smuzhiyun 	/* text cursor end line */
930*4882a593Smuzhiyun 	vga_wcrt(regbase, VGA_CRTC_CURSOR_END, 31);
931*4882a593Smuzhiyun 
932*4882a593Smuzhiyun 	/******************************************************
933*4882a593Smuzhiyun 	 *
934*4882a593Smuzhiyun 	 * 1 bpp
935*4882a593Smuzhiyun 	 *
936*4882a593Smuzhiyun 	 */
937*4882a593Smuzhiyun 
938*4882a593Smuzhiyun 	/* programming for different color depths */
939*4882a593Smuzhiyun 	if (var->bits_per_pixel == 1) {
940*4882a593Smuzhiyun 		dev_dbg(info->device, "preparing for 1 bit deep display\n");
941*4882a593Smuzhiyun 		vga_wgfx(regbase, VGA_GFX_MODE, 0);	/* mode register */
942*4882a593Smuzhiyun 
943*4882a593Smuzhiyun 		/* SR07 */
944*4882a593Smuzhiyun 		switch (cinfo->btype) {
945*4882a593Smuzhiyun 		case BT_SD64:
946*4882a593Smuzhiyun 		case BT_PICCOLO:
947*4882a593Smuzhiyun 		case BT_PICASSO:
948*4882a593Smuzhiyun 		case BT_SPECTRUM:
949*4882a593Smuzhiyun 		case BT_PICASSO4:
950*4882a593Smuzhiyun 		case BT_ALPINE:
951*4882a593Smuzhiyun 		case BT_GD5480:
952*4882a593Smuzhiyun 			vga_wseq(regbase, CL_SEQR7,
953*4882a593Smuzhiyun 				 cinfo->multiplexing ?
954*4882a593Smuzhiyun 					bi->sr07_1bpp_mux : bi->sr07_1bpp);
955*4882a593Smuzhiyun 			break;
956*4882a593Smuzhiyun 
957*4882a593Smuzhiyun 		case BT_LAGUNA:
958*4882a593Smuzhiyun 		case BT_LAGUNAB:
959*4882a593Smuzhiyun 			vga_wseq(regbase, CL_SEQR7,
960*4882a593Smuzhiyun 				vga_rseq(regbase, CL_SEQR7) & ~0x01);
961*4882a593Smuzhiyun 			break;
962*4882a593Smuzhiyun 
963*4882a593Smuzhiyun 		default:
964*4882a593Smuzhiyun 			dev_warn(info->device, "unknown Board\n");
965*4882a593Smuzhiyun 			break;
966*4882a593Smuzhiyun 		}
967*4882a593Smuzhiyun 
968*4882a593Smuzhiyun 		/* Extended Sequencer Mode */
969*4882a593Smuzhiyun 		switch (cinfo->btype) {
970*4882a593Smuzhiyun 
971*4882a593Smuzhiyun 		case BT_PICCOLO:
972*4882a593Smuzhiyun 		case BT_SPECTRUM:
973*4882a593Smuzhiyun 			/* evtl d0 bei 1 bit? avoid FIFO underruns..? */
974*4882a593Smuzhiyun 			vga_wseq(regbase, CL_SEQRF, 0xb0);
975*4882a593Smuzhiyun 			break;
976*4882a593Smuzhiyun 
977*4882a593Smuzhiyun 		case BT_PICASSO:
978*4882a593Smuzhiyun 			/* ## vorher d0 avoid FIFO underruns..? */
979*4882a593Smuzhiyun 			vga_wseq(regbase, CL_SEQRF, 0xd0);
980*4882a593Smuzhiyun 			break;
981*4882a593Smuzhiyun 
982*4882a593Smuzhiyun 		case BT_SD64:
983*4882a593Smuzhiyun 		case BT_PICASSO4:
984*4882a593Smuzhiyun 		case BT_ALPINE:
985*4882a593Smuzhiyun 		case BT_GD5480:
986*4882a593Smuzhiyun 		case BT_LAGUNA:
987*4882a593Smuzhiyun 		case BT_LAGUNAB:
988*4882a593Smuzhiyun 			/* do nothing */
989*4882a593Smuzhiyun 			break;
990*4882a593Smuzhiyun 
991*4882a593Smuzhiyun 		default:
992*4882a593Smuzhiyun 			dev_warn(info->device, "unknown Board\n");
993*4882a593Smuzhiyun 			break;
994*4882a593Smuzhiyun 		}
995*4882a593Smuzhiyun 
996*4882a593Smuzhiyun 		/* pixel mask: pass-through for first plane */
997*4882a593Smuzhiyun 		WGen(cinfo, VGA_PEL_MSK, 0x01);
998*4882a593Smuzhiyun 		if (cinfo->multiplexing)
999*4882a593Smuzhiyun 			/* hidden dac reg: 1280x1024 */
1000*4882a593Smuzhiyun 			WHDR(cinfo, 0x4a);
1001*4882a593Smuzhiyun 		else
1002*4882a593Smuzhiyun 			/* hidden dac: nothing */
1003*4882a593Smuzhiyun 			WHDR(cinfo, 0);
1004*4882a593Smuzhiyun 		/* memory mode: odd/even, ext. memory */
1005*4882a593Smuzhiyun 		vga_wseq(regbase, VGA_SEQ_MEMORY_MODE, 0x06);
1006*4882a593Smuzhiyun 		/* plane mask: only write to first plane */
1007*4882a593Smuzhiyun 		vga_wseq(regbase, VGA_SEQ_PLANE_WRITE, 0x01);
1008*4882a593Smuzhiyun 	}
1009*4882a593Smuzhiyun 
1010*4882a593Smuzhiyun 	/******************************************************
1011*4882a593Smuzhiyun 	 *
1012*4882a593Smuzhiyun 	 * 8 bpp
1013*4882a593Smuzhiyun 	 *
1014*4882a593Smuzhiyun 	 */
1015*4882a593Smuzhiyun 
1016*4882a593Smuzhiyun 	else if (var->bits_per_pixel == 8) {
1017*4882a593Smuzhiyun 		dev_dbg(info->device, "preparing for 8 bit deep display\n");
1018*4882a593Smuzhiyun 		switch (cinfo->btype) {
1019*4882a593Smuzhiyun 		case BT_SD64:
1020*4882a593Smuzhiyun 		case BT_PICCOLO:
1021*4882a593Smuzhiyun 		case BT_PICASSO:
1022*4882a593Smuzhiyun 		case BT_SPECTRUM:
1023*4882a593Smuzhiyun 		case BT_PICASSO4:
1024*4882a593Smuzhiyun 		case BT_ALPINE:
1025*4882a593Smuzhiyun 		case BT_GD5480:
1026*4882a593Smuzhiyun 			vga_wseq(regbase, CL_SEQR7,
1027*4882a593Smuzhiyun 				  cinfo->multiplexing ?
1028*4882a593Smuzhiyun 					bi->sr07_8bpp_mux : bi->sr07_8bpp);
1029*4882a593Smuzhiyun 			break;
1030*4882a593Smuzhiyun 
1031*4882a593Smuzhiyun 		case BT_LAGUNA:
1032*4882a593Smuzhiyun 		case BT_LAGUNAB:
1033*4882a593Smuzhiyun 			vga_wseq(regbase, CL_SEQR7,
1034*4882a593Smuzhiyun 				vga_rseq(regbase, CL_SEQR7) | 0x01);
1035*4882a593Smuzhiyun 			threshold |= 0x10;
1036*4882a593Smuzhiyun 			break;
1037*4882a593Smuzhiyun 
1038*4882a593Smuzhiyun 		default:
1039*4882a593Smuzhiyun 			dev_warn(info->device, "unknown Board\n");
1040*4882a593Smuzhiyun 			break;
1041*4882a593Smuzhiyun 		}
1042*4882a593Smuzhiyun 
1043*4882a593Smuzhiyun 		switch (cinfo->btype) {
1044*4882a593Smuzhiyun 		case BT_PICCOLO:
1045*4882a593Smuzhiyun 		case BT_PICASSO:
1046*4882a593Smuzhiyun 		case BT_SPECTRUM:
1047*4882a593Smuzhiyun 			/* Fast Page-Mode writes */
1048*4882a593Smuzhiyun 			vga_wseq(regbase, CL_SEQRF, 0xb0);
1049*4882a593Smuzhiyun 			break;
1050*4882a593Smuzhiyun 
1051*4882a593Smuzhiyun 		case BT_PICASSO4:
1052*4882a593Smuzhiyun #ifdef CONFIG_ZORRO
1053*4882a593Smuzhiyun 			/* ### INCOMPLETE!! */
1054*4882a593Smuzhiyun 			vga_wseq(regbase, CL_SEQRF, 0xb8);
1055*4882a593Smuzhiyun #endif
1056*4882a593Smuzhiyun 		case BT_ALPINE:
1057*4882a593Smuzhiyun 		case BT_SD64:
1058*4882a593Smuzhiyun 		case BT_GD5480:
1059*4882a593Smuzhiyun 		case BT_LAGUNA:
1060*4882a593Smuzhiyun 		case BT_LAGUNAB:
1061*4882a593Smuzhiyun 			/* do nothing */
1062*4882a593Smuzhiyun 			break;
1063*4882a593Smuzhiyun 
1064*4882a593Smuzhiyun 		default:
1065*4882a593Smuzhiyun 			dev_warn(info->device, "unknown board\n");
1066*4882a593Smuzhiyun 			break;
1067*4882a593Smuzhiyun 		}
1068*4882a593Smuzhiyun 
1069*4882a593Smuzhiyun 		/* mode register: 256 color mode */
1070*4882a593Smuzhiyun 		vga_wgfx(regbase, VGA_GFX_MODE, 64);
1071*4882a593Smuzhiyun 		if (cinfo->multiplexing)
1072*4882a593Smuzhiyun 			/* hidden dac reg: 1280x1024 */
1073*4882a593Smuzhiyun 			WHDR(cinfo, 0x4a);
1074*4882a593Smuzhiyun 		else
1075*4882a593Smuzhiyun 			/* hidden dac: nothing */
1076*4882a593Smuzhiyun 			WHDR(cinfo, 0);
1077*4882a593Smuzhiyun 	}
1078*4882a593Smuzhiyun 
1079*4882a593Smuzhiyun 	/******************************************************
1080*4882a593Smuzhiyun 	 *
1081*4882a593Smuzhiyun 	 * 16 bpp
1082*4882a593Smuzhiyun 	 *
1083*4882a593Smuzhiyun 	 */
1084*4882a593Smuzhiyun 
1085*4882a593Smuzhiyun 	else if (var->bits_per_pixel == 16) {
1086*4882a593Smuzhiyun 		dev_dbg(info->device, "preparing for 16 bit deep display\n");
1087*4882a593Smuzhiyun 		switch (cinfo->btype) {
1088*4882a593Smuzhiyun 		case BT_PICCOLO:
1089*4882a593Smuzhiyun 		case BT_SPECTRUM:
1090*4882a593Smuzhiyun 			vga_wseq(regbase, CL_SEQR7, 0x87);
1091*4882a593Smuzhiyun 			/* Fast Page-Mode writes */
1092*4882a593Smuzhiyun 			vga_wseq(regbase, CL_SEQRF, 0xb0);
1093*4882a593Smuzhiyun 			break;
1094*4882a593Smuzhiyun 
1095*4882a593Smuzhiyun 		case BT_PICASSO:
1096*4882a593Smuzhiyun 			vga_wseq(regbase, CL_SEQR7, 0x27);
1097*4882a593Smuzhiyun 			/* Fast Page-Mode writes */
1098*4882a593Smuzhiyun 			vga_wseq(regbase, CL_SEQRF, 0xb0);
1099*4882a593Smuzhiyun 			break;
1100*4882a593Smuzhiyun 
1101*4882a593Smuzhiyun 		case BT_SD64:
1102*4882a593Smuzhiyun 		case BT_PICASSO4:
1103*4882a593Smuzhiyun 		case BT_ALPINE:
1104*4882a593Smuzhiyun 			/* Extended Sequencer Mode: 256c col. mode */
1105*4882a593Smuzhiyun 			vga_wseq(regbase, CL_SEQR7,
1106*4882a593Smuzhiyun 					cinfo->doubleVCLK ? 0xa3 : 0xa7);
1107*4882a593Smuzhiyun 			break;
1108*4882a593Smuzhiyun 
1109*4882a593Smuzhiyun 		case BT_GD5480:
1110*4882a593Smuzhiyun 			vga_wseq(regbase, CL_SEQR7, 0x17);
1111*4882a593Smuzhiyun 			/* We already set SRF and SR1F */
1112*4882a593Smuzhiyun 			break;
1113*4882a593Smuzhiyun 
1114*4882a593Smuzhiyun 		case BT_LAGUNA:
1115*4882a593Smuzhiyun 		case BT_LAGUNAB:
1116*4882a593Smuzhiyun 			vga_wseq(regbase, CL_SEQR7,
1117*4882a593Smuzhiyun 				vga_rseq(regbase, CL_SEQR7) & ~0x01);
1118*4882a593Smuzhiyun 			control |= 0x2000;
1119*4882a593Smuzhiyun 			format |= 0x1400;
1120*4882a593Smuzhiyun 			threshold |= 0x10;
1121*4882a593Smuzhiyun 			break;
1122*4882a593Smuzhiyun 
1123*4882a593Smuzhiyun 		default:
1124*4882a593Smuzhiyun 			dev_warn(info->device, "unknown Board\n");
1125*4882a593Smuzhiyun 			break;
1126*4882a593Smuzhiyun 		}
1127*4882a593Smuzhiyun 
1128*4882a593Smuzhiyun 		/* mode register: 256 color mode */
1129*4882a593Smuzhiyun 		vga_wgfx(regbase, VGA_GFX_MODE, 64);
1130*4882a593Smuzhiyun #ifdef CONFIG_PCI
1131*4882a593Smuzhiyun 		WHDR(cinfo, cinfo->doubleVCLK ? 0xe1 : 0xc1);
1132*4882a593Smuzhiyun #elif defined(CONFIG_ZORRO)
1133*4882a593Smuzhiyun 		/* FIXME: CONFIG_PCI and CONFIG_ZORRO may be defined both */
1134*4882a593Smuzhiyun 		WHDR(cinfo, 0xa0);	/* hidden dac reg: nothing special */
1135*4882a593Smuzhiyun #endif
1136*4882a593Smuzhiyun 	}
1137*4882a593Smuzhiyun 
1138*4882a593Smuzhiyun 	/******************************************************
1139*4882a593Smuzhiyun 	 *
1140*4882a593Smuzhiyun 	 * 24 bpp
1141*4882a593Smuzhiyun 	 *
1142*4882a593Smuzhiyun 	 */
1143*4882a593Smuzhiyun 
1144*4882a593Smuzhiyun 	else if (var->bits_per_pixel == 24) {
1145*4882a593Smuzhiyun 		dev_dbg(info->device, "preparing for 24 bit deep display\n");
1146*4882a593Smuzhiyun 		switch (cinfo->btype) {
1147*4882a593Smuzhiyun 		case BT_PICCOLO:
1148*4882a593Smuzhiyun 		case BT_SPECTRUM:
1149*4882a593Smuzhiyun 			vga_wseq(regbase, CL_SEQR7, 0x85);
1150*4882a593Smuzhiyun 			/* Fast Page-Mode writes */
1151*4882a593Smuzhiyun 			vga_wseq(regbase, CL_SEQRF, 0xb0);
1152*4882a593Smuzhiyun 			break;
1153*4882a593Smuzhiyun 
1154*4882a593Smuzhiyun 		case BT_PICASSO:
1155*4882a593Smuzhiyun 			vga_wseq(regbase, CL_SEQR7, 0x25);
1156*4882a593Smuzhiyun 			/* Fast Page-Mode writes */
1157*4882a593Smuzhiyun 			vga_wseq(regbase, CL_SEQRF, 0xb0);
1158*4882a593Smuzhiyun 			break;
1159*4882a593Smuzhiyun 
1160*4882a593Smuzhiyun 		case BT_SD64:
1161*4882a593Smuzhiyun 		case BT_PICASSO4:
1162*4882a593Smuzhiyun 		case BT_ALPINE:
1163*4882a593Smuzhiyun 			/* Extended Sequencer Mode: 256c col. mode */
1164*4882a593Smuzhiyun 			vga_wseq(regbase, CL_SEQR7, 0xa5);
1165*4882a593Smuzhiyun 			break;
1166*4882a593Smuzhiyun 
1167*4882a593Smuzhiyun 		case BT_GD5480:
1168*4882a593Smuzhiyun 			vga_wseq(regbase, CL_SEQR7, 0x15);
1169*4882a593Smuzhiyun 			/* We already set SRF and SR1F */
1170*4882a593Smuzhiyun 			break;
1171*4882a593Smuzhiyun 
1172*4882a593Smuzhiyun 		case BT_LAGUNA:
1173*4882a593Smuzhiyun 		case BT_LAGUNAB:
1174*4882a593Smuzhiyun 			vga_wseq(regbase, CL_SEQR7,
1175*4882a593Smuzhiyun 				vga_rseq(regbase, CL_SEQR7) & ~0x01);
1176*4882a593Smuzhiyun 			control |= 0x4000;
1177*4882a593Smuzhiyun 			format |= 0x2400;
1178*4882a593Smuzhiyun 			threshold |= 0x20;
1179*4882a593Smuzhiyun 			break;
1180*4882a593Smuzhiyun 
1181*4882a593Smuzhiyun 		default:
1182*4882a593Smuzhiyun 			dev_warn(info->device, "unknown Board\n");
1183*4882a593Smuzhiyun 			break;
1184*4882a593Smuzhiyun 		}
1185*4882a593Smuzhiyun 
1186*4882a593Smuzhiyun 		/* mode register: 256 color mode */
1187*4882a593Smuzhiyun 		vga_wgfx(regbase, VGA_GFX_MODE, 64);
1188*4882a593Smuzhiyun 		/* hidden dac reg: 8-8-8 mode (24 or 32) */
1189*4882a593Smuzhiyun 		WHDR(cinfo, 0xc5);
1190*4882a593Smuzhiyun 	}
1191*4882a593Smuzhiyun 
1192*4882a593Smuzhiyun 	/******************************************************
1193*4882a593Smuzhiyun 	 *
1194*4882a593Smuzhiyun 	 * unknown/unsupported bpp
1195*4882a593Smuzhiyun 	 *
1196*4882a593Smuzhiyun 	 */
1197*4882a593Smuzhiyun 
1198*4882a593Smuzhiyun 	else
1199*4882a593Smuzhiyun 		dev_err(info->device,
1200*4882a593Smuzhiyun 			"What's this? requested color depth == %d.\n",
1201*4882a593Smuzhiyun 			var->bits_per_pixel);
1202*4882a593Smuzhiyun 
1203*4882a593Smuzhiyun 	pitch = info->fix.line_length >> 3;
1204*4882a593Smuzhiyun 	vga_wcrt(regbase, VGA_CRTC_OFFSET, pitch & 0xff);
1205*4882a593Smuzhiyun 	tmp = 0x22;
1206*4882a593Smuzhiyun 	if (pitch & 0x100)
1207*4882a593Smuzhiyun 		tmp |= 0x10;	/* offset overflow bit */
1208*4882a593Smuzhiyun 
1209*4882a593Smuzhiyun 	/* screen start addr #16-18, fastpagemode cycles */
1210*4882a593Smuzhiyun 	vga_wcrt(regbase, CL_CRT1B, tmp);
1211*4882a593Smuzhiyun 
1212*4882a593Smuzhiyun 	/* screen start address bit 19 */
1213*4882a593Smuzhiyun 	if (cirrusfb_board_info[cinfo->btype].scrn_start_bit19)
1214*4882a593Smuzhiyun 		vga_wcrt(regbase, CL_CRT1D, (pitch >> 9) & 1);
1215*4882a593Smuzhiyun 
1216*4882a593Smuzhiyun 	if (is_laguna(cinfo)) {
1217*4882a593Smuzhiyun 		tmp = 0;
1218*4882a593Smuzhiyun 		if ((htotal + 5) & 256)
1219*4882a593Smuzhiyun 			tmp |= 128;
1220*4882a593Smuzhiyun 		if (hdispend & 256)
1221*4882a593Smuzhiyun 			tmp |= 64;
1222*4882a593Smuzhiyun 		if (hsyncstart & 256)
1223*4882a593Smuzhiyun 			tmp |= 48;
1224*4882a593Smuzhiyun 		if (vtotal & 1024)
1225*4882a593Smuzhiyun 			tmp |= 8;
1226*4882a593Smuzhiyun 		if (vdispend & 1024)
1227*4882a593Smuzhiyun 			tmp |= 4;
1228*4882a593Smuzhiyun 		if (vsyncstart & 1024)
1229*4882a593Smuzhiyun 			tmp |= 3;
1230*4882a593Smuzhiyun 
1231*4882a593Smuzhiyun 		vga_wcrt(regbase, CL_CRT1E, tmp);
1232*4882a593Smuzhiyun 		dev_dbg(info->device, "CRT1e: %d\n", tmp);
1233*4882a593Smuzhiyun 	}
1234*4882a593Smuzhiyun 
1235*4882a593Smuzhiyun 	/* pixel panning */
1236*4882a593Smuzhiyun 	vga_wattr(regbase, CL_AR33, 0);
1237*4882a593Smuzhiyun 
1238*4882a593Smuzhiyun 	/* [ EGS: SetOffset(); ] */
1239*4882a593Smuzhiyun 	/* From SetOffset(): Turn on VideoEnable bit in Attribute controller */
1240*4882a593Smuzhiyun 	AttrOn(cinfo);
1241*4882a593Smuzhiyun 
1242*4882a593Smuzhiyun 	if (is_laguna(cinfo)) {
1243*4882a593Smuzhiyun 		/* no tiles */
1244*4882a593Smuzhiyun 		fb_writew(control | 0x1000, cinfo->laguna_mmio + 0x402);
1245*4882a593Smuzhiyun 		fb_writew(format, cinfo->laguna_mmio + 0xc0);
1246*4882a593Smuzhiyun 		fb_writew(threshold, cinfo->laguna_mmio + 0xea);
1247*4882a593Smuzhiyun 	}
1248*4882a593Smuzhiyun 	/* finally, turn on everything - turn off "FullBandwidth" bit */
1249*4882a593Smuzhiyun 	/* also, set "DotClock%2" bit where requested */
1250*4882a593Smuzhiyun 	tmp = 0x01;
1251*4882a593Smuzhiyun 
1252*4882a593Smuzhiyun /*** FB_VMODE_CLOCK_HALVE in linux/fb.h not defined anymore ?
1253*4882a593Smuzhiyun     if (var->vmode & FB_VMODE_CLOCK_HALVE)
1254*4882a593Smuzhiyun 	tmp |= 0x08;
1255*4882a593Smuzhiyun */
1256*4882a593Smuzhiyun 
1257*4882a593Smuzhiyun 	vga_wseq(regbase, VGA_SEQ_CLOCK_MODE, tmp);
1258*4882a593Smuzhiyun 	dev_dbg(info->device, "CL_SEQR1: %d\n", tmp);
1259*4882a593Smuzhiyun 
1260*4882a593Smuzhiyun #ifdef CIRRUSFB_DEBUG
1261*4882a593Smuzhiyun 	cirrusfb_dbg_reg_dump(info, NULL);
1262*4882a593Smuzhiyun #endif
1263*4882a593Smuzhiyun 
1264*4882a593Smuzhiyun 	return 0;
1265*4882a593Smuzhiyun }
1266*4882a593Smuzhiyun 
1267*4882a593Smuzhiyun /* for some reason incomprehensible to me, cirrusfb requires that you write
1268*4882a593Smuzhiyun  * the registers twice for the settings to take..grr. -dte */
cirrusfb_set_par(struct fb_info * info)1269*4882a593Smuzhiyun static int cirrusfb_set_par(struct fb_info *info)
1270*4882a593Smuzhiyun {
1271*4882a593Smuzhiyun 	cirrusfb_set_par_foo(info);
1272*4882a593Smuzhiyun 	return cirrusfb_set_par_foo(info);
1273*4882a593Smuzhiyun }
1274*4882a593Smuzhiyun 
cirrusfb_setcolreg(unsigned regno,unsigned red,unsigned green,unsigned blue,unsigned transp,struct fb_info * info)1275*4882a593Smuzhiyun static int cirrusfb_setcolreg(unsigned regno, unsigned red, unsigned green,
1276*4882a593Smuzhiyun 			      unsigned blue, unsigned transp,
1277*4882a593Smuzhiyun 			      struct fb_info *info)
1278*4882a593Smuzhiyun {
1279*4882a593Smuzhiyun 	struct cirrusfb_info *cinfo = info->par;
1280*4882a593Smuzhiyun 
1281*4882a593Smuzhiyun 	if (regno > 255)
1282*4882a593Smuzhiyun 		return -EINVAL;
1283*4882a593Smuzhiyun 
1284*4882a593Smuzhiyun 	if (info->fix.visual == FB_VISUAL_TRUECOLOR) {
1285*4882a593Smuzhiyun 		u32 v;
1286*4882a593Smuzhiyun 		red >>= (16 - info->var.red.length);
1287*4882a593Smuzhiyun 		green >>= (16 - info->var.green.length);
1288*4882a593Smuzhiyun 		blue >>= (16 - info->var.blue.length);
1289*4882a593Smuzhiyun 
1290*4882a593Smuzhiyun 		if (regno >= 16)
1291*4882a593Smuzhiyun 			return 1;
1292*4882a593Smuzhiyun 		v = (red << info->var.red.offset) |
1293*4882a593Smuzhiyun 		    (green << info->var.green.offset) |
1294*4882a593Smuzhiyun 		    (blue << info->var.blue.offset);
1295*4882a593Smuzhiyun 
1296*4882a593Smuzhiyun 		cinfo->pseudo_palette[regno] = v;
1297*4882a593Smuzhiyun 		return 0;
1298*4882a593Smuzhiyun 	}
1299*4882a593Smuzhiyun 
1300*4882a593Smuzhiyun 	if (info->var.bits_per_pixel == 8)
1301*4882a593Smuzhiyun 		WClut(cinfo, regno, red >> 10, green >> 10, blue >> 10);
1302*4882a593Smuzhiyun 
1303*4882a593Smuzhiyun 	return 0;
1304*4882a593Smuzhiyun 
1305*4882a593Smuzhiyun }
1306*4882a593Smuzhiyun 
1307*4882a593Smuzhiyun /*************************************************************************
1308*4882a593Smuzhiyun 	cirrusfb_pan_display()
1309*4882a593Smuzhiyun 
1310*4882a593Smuzhiyun 	performs display panning - provided hardware permits this
1311*4882a593Smuzhiyun **************************************************************************/
cirrusfb_pan_display(struct fb_var_screeninfo * var,struct fb_info * info)1312*4882a593Smuzhiyun static int cirrusfb_pan_display(struct fb_var_screeninfo *var,
1313*4882a593Smuzhiyun 				struct fb_info *info)
1314*4882a593Smuzhiyun {
1315*4882a593Smuzhiyun 	int xoffset;
1316*4882a593Smuzhiyun 	unsigned long base;
1317*4882a593Smuzhiyun 	unsigned char tmp, xpix;
1318*4882a593Smuzhiyun 	struct cirrusfb_info *cinfo = info->par;
1319*4882a593Smuzhiyun 
1320*4882a593Smuzhiyun 	/* no range checks for xoffset and yoffset,   */
1321*4882a593Smuzhiyun 	/* as fb_pan_display has already done this */
1322*4882a593Smuzhiyun 	if (var->vmode & FB_VMODE_YWRAP)
1323*4882a593Smuzhiyun 		return -EINVAL;
1324*4882a593Smuzhiyun 
1325*4882a593Smuzhiyun 	xoffset = var->xoffset * info->var.bits_per_pixel / 8;
1326*4882a593Smuzhiyun 
1327*4882a593Smuzhiyun 	base = var->yoffset * info->fix.line_length + xoffset;
1328*4882a593Smuzhiyun 
1329*4882a593Smuzhiyun 	if (info->var.bits_per_pixel == 1) {
1330*4882a593Smuzhiyun 		/* base is already correct */
1331*4882a593Smuzhiyun 		xpix = (unsigned char) (var->xoffset % 8);
1332*4882a593Smuzhiyun 	} else {
1333*4882a593Smuzhiyun 		base /= 4;
1334*4882a593Smuzhiyun 		xpix = (unsigned char) ((xoffset % 4) * 2);
1335*4882a593Smuzhiyun 	}
1336*4882a593Smuzhiyun 
1337*4882a593Smuzhiyun 	if (!is_laguna(cinfo))
1338*4882a593Smuzhiyun 		cirrusfb_WaitBLT(cinfo->regbase);
1339*4882a593Smuzhiyun 
1340*4882a593Smuzhiyun 	/* lower 8 + 8 bits of screen start address */
1341*4882a593Smuzhiyun 	vga_wcrt(cinfo->regbase, VGA_CRTC_START_LO, base & 0xff);
1342*4882a593Smuzhiyun 	vga_wcrt(cinfo->regbase, VGA_CRTC_START_HI, (base >> 8) & 0xff);
1343*4882a593Smuzhiyun 
1344*4882a593Smuzhiyun 	/* 0xf2 is %11110010, exclude tmp bits */
1345*4882a593Smuzhiyun 	tmp = vga_rcrt(cinfo->regbase, CL_CRT1B) & 0xf2;
1346*4882a593Smuzhiyun 	/* construct bits 16, 17 and 18 of screen start address */
1347*4882a593Smuzhiyun 	if (base & 0x10000)
1348*4882a593Smuzhiyun 		tmp |= 0x01;
1349*4882a593Smuzhiyun 	if (base & 0x20000)
1350*4882a593Smuzhiyun 		tmp |= 0x04;
1351*4882a593Smuzhiyun 	if (base & 0x40000)
1352*4882a593Smuzhiyun 		tmp |= 0x08;
1353*4882a593Smuzhiyun 
1354*4882a593Smuzhiyun 	vga_wcrt(cinfo->regbase, CL_CRT1B, tmp);
1355*4882a593Smuzhiyun 
1356*4882a593Smuzhiyun 	/* construct bit 19 of screen start address */
1357*4882a593Smuzhiyun 	if (cirrusfb_board_info[cinfo->btype].scrn_start_bit19) {
1358*4882a593Smuzhiyun 		tmp = vga_rcrt(cinfo->regbase, CL_CRT1D);
1359*4882a593Smuzhiyun 		if (is_laguna(cinfo))
1360*4882a593Smuzhiyun 			tmp = (tmp & ~0x18) | ((base >> 16) & 0x18);
1361*4882a593Smuzhiyun 		else
1362*4882a593Smuzhiyun 			tmp = (tmp & ~0x80) | ((base >> 12) & 0x80);
1363*4882a593Smuzhiyun 		vga_wcrt(cinfo->regbase, CL_CRT1D, tmp);
1364*4882a593Smuzhiyun 	}
1365*4882a593Smuzhiyun 
1366*4882a593Smuzhiyun 	/* write pixel panning value to AR33; this does not quite work in 8bpp
1367*4882a593Smuzhiyun 	 *
1368*4882a593Smuzhiyun 	 * ### Piccolo..? Will this work?
1369*4882a593Smuzhiyun 	 */
1370*4882a593Smuzhiyun 	if (info->var.bits_per_pixel == 1)
1371*4882a593Smuzhiyun 		vga_wattr(cinfo->regbase, CL_AR33, xpix);
1372*4882a593Smuzhiyun 
1373*4882a593Smuzhiyun 	return 0;
1374*4882a593Smuzhiyun }
1375*4882a593Smuzhiyun 
cirrusfb_blank(int blank_mode,struct fb_info * info)1376*4882a593Smuzhiyun static int cirrusfb_blank(int blank_mode, struct fb_info *info)
1377*4882a593Smuzhiyun {
1378*4882a593Smuzhiyun 	/*
1379*4882a593Smuzhiyun 	 * Blank the screen if blank_mode != 0, else unblank. If blank == NULL
1380*4882a593Smuzhiyun 	 * then the caller blanks by setting the CLUT (Color Look Up Table)
1381*4882a593Smuzhiyun 	 * to all black. Return 0 if blanking succeeded, != 0 if un-/blanking
1382*4882a593Smuzhiyun 	 * failed due to e.g. a video mode which doesn't support it.
1383*4882a593Smuzhiyun 	 * Implements VESA suspend and powerdown modes on hardware that
1384*4882a593Smuzhiyun 	 * supports disabling hsync/vsync:
1385*4882a593Smuzhiyun 	 *   blank_mode == 2: suspend vsync
1386*4882a593Smuzhiyun 	 *   blank_mode == 3: suspend hsync
1387*4882a593Smuzhiyun 	 *   blank_mode == 4: powerdown
1388*4882a593Smuzhiyun 	 */
1389*4882a593Smuzhiyun 	unsigned char val;
1390*4882a593Smuzhiyun 	struct cirrusfb_info *cinfo = info->par;
1391*4882a593Smuzhiyun 	int current_mode = cinfo->blank_mode;
1392*4882a593Smuzhiyun 
1393*4882a593Smuzhiyun 	dev_dbg(info->device, "ENTER, blank mode = %d\n", blank_mode);
1394*4882a593Smuzhiyun 
1395*4882a593Smuzhiyun 	if (info->state != FBINFO_STATE_RUNNING ||
1396*4882a593Smuzhiyun 	    current_mode == blank_mode) {
1397*4882a593Smuzhiyun 		dev_dbg(info->device, "EXIT, returning 0\n");
1398*4882a593Smuzhiyun 		return 0;
1399*4882a593Smuzhiyun 	}
1400*4882a593Smuzhiyun 
1401*4882a593Smuzhiyun 	/* Undo current */
1402*4882a593Smuzhiyun 	if (current_mode == FB_BLANK_NORMAL ||
1403*4882a593Smuzhiyun 	    current_mode == FB_BLANK_UNBLANK)
1404*4882a593Smuzhiyun 		/* clear "FullBandwidth" bit */
1405*4882a593Smuzhiyun 		val = 0;
1406*4882a593Smuzhiyun 	else
1407*4882a593Smuzhiyun 		/* set "FullBandwidth" bit */
1408*4882a593Smuzhiyun 		val = 0x20;
1409*4882a593Smuzhiyun 
1410*4882a593Smuzhiyun 	val |= vga_rseq(cinfo->regbase, VGA_SEQ_CLOCK_MODE) & 0xdf;
1411*4882a593Smuzhiyun 	vga_wseq(cinfo->regbase, VGA_SEQ_CLOCK_MODE, val);
1412*4882a593Smuzhiyun 
1413*4882a593Smuzhiyun 	switch (blank_mode) {
1414*4882a593Smuzhiyun 	case FB_BLANK_UNBLANK:
1415*4882a593Smuzhiyun 	case FB_BLANK_NORMAL:
1416*4882a593Smuzhiyun 		val = 0x00;
1417*4882a593Smuzhiyun 		break;
1418*4882a593Smuzhiyun 	case FB_BLANK_VSYNC_SUSPEND:
1419*4882a593Smuzhiyun 		val = 0x04;
1420*4882a593Smuzhiyun 		break;
1421*4882a593Smuzhiyun 	case FB_BLANK_HSYNC_SUSPEND:
1422*4882a593Smuzhiyun 		val = 0x02;
1423*4882a593Smuzhiyun 		break;
1424*4882a593Smuzhiyun 	case FB_BLANK_POWERDOWN:
1425*4882a593Smuzhiyun 		val = 0x06;
1426*4882a593Smuzhiyun 		break;
1427*4882a593Smuzhiyun 	default:
1428*4882a593Smuzhiyun 		dev_dbg(info->device, "EXIT, returning 1\n");
1429*4882a593Smuzhiyun 		return 1;
1430*4882a593Smuzhiyun 	}
1431*4882a593Smuzhiyun 
1432*4882a593Smuzhiyun 	vga_wgfx(cinfo->regbase, CL_GRE, val);
1433*4882a593Smuzhiyun 
1434*4882a593Smuzhiyun 	cinfo->blank_mode = blank_mode;
1435*4882a593Smuzhiyun 	dev_dbg(info->device, "EXIT, returning 0\n");
1436*4882a593Smuzhiyun 
1437*4882a593Smuzhiyun 	/* Let fbcon do a soft blank for us */
1438*4882a593Smuzhiyun 	return (blank_mode == FB_BLANK_NORMAL) ? 1 : 0;
1439*4882a593Smuzhiyun }
1440*4882a593Smuzhiyun 
1441*4882a593Smuzhiyun /**** END   Hardware specific Routines **************************************/
1442*4882a593Smuzhiyun /****************************************************************************/
1443*4882a593Smuzhiyun /**** BEGIN Internal Routines ***********************************************/
1444*4882a593Smuzhiyun 
init_vgachip(struct fb_info * info)1445*4882a593Smuzhiyun static void init_vgachip(struct fb_info *info)
1446*4882a593Smuzhiyun {
1447*4882a593Smuzhiyun 	struct cirrusfb_info *cinfo = info->par;
1448*4882a593Smuzhiyun 	const struct cirrusfb_board_info_rec *bi;
1449*4882a593Smuzhiyun 
1450*4882a593Smuzhiyun 	assert(cinfo != NULL);
1451*4882a593Smuzhiyun 
1452*4882a593Smuzhiyun 	bi = &cirrusfb_board_info[cinfo->btype];
1453*4882a593Smuzhiyun 
1454*4882a593Smuzhiyun 	/* reset board globally */
1455*4882a593Smuzhiyun 	switch (cinfo->btype) {
1456*4882a593Smuzhiyun 	case BT_PICCOLO:
1457*4882a593Smuzhiyun 		WSFR(cinfo, 0x01);
1458*4882a593Smuzhiyun 		udelay(500);
1459*4882a593Smuzhiyun 		WSFR(cinfo, 0x51);
1460*4882a593Smuzhiyun 		udelay(500);
1461*4882a593Smuzhiyun 		break;
1462*4882a593Smuzhiyun 	case BT_PICASSO:
1463*4882a593Smuzhiyun 		WSFR2(cinfo, 0xff);
1464*4882a593Smuzhiyun 		udelay(500);
1465*4882a593Smuzhiyun 		break;
1466*4882a593Smuzhiyun 	case BT_SD64:
1467*4882a593Smuzhiyun 	case BT_SPECTRUM:
1468*4882a593Smuzhiyun 		WSFR(cinfo, 0x1f);
1469*4882a593Smuzhiyun 		udelay(500);
1470*4882a593Smuzhiyun 		WSFR(cinfo, 0x4f);
1471*4882a593Smuzhiyun 		udelay(500);
1472*4882a593Smuzhiyun 		break;
1473*4882a593Smuzhiyun 	case BT_PICASSO4:
1474*4882a593Smuzhiyun 		/* disable flickerfixer */
1475*4882a593Smuzhiyun 		vga_wcrt(cinfo->regbase, CL_CRT51, 0x00);
1476*4882a593Smuzhiyun 		mdelay(100);
1477*4882a593Smuzhiyun 		/* mode */
1478*4882a593Smuzhiyun 		vga_wgfx(cinfo->regbase, CL_GR31, 0x00);
1479*4882a593Smuzhiyun 		fallthrough;
1480*4882a593Smuzhiyun 	case BT_GD5480:
1481*4882a593Smuzhiyun 		/* from Klaus' NetBSD driver: */
1482*4882a593Smuzhiyun 		vga_wgfx(cinfo->regbase, CL_GR2F, 0x00);
1483*4882a593Smuzhiyun 		fallthrough;
1484*4882a593Smuzhiyun 	case BT_ALPINE:
1485*4882a593Smuzhiyun 		/* put blitter into 542x compat */
1486*4882a593Smuzhiyun 		vga_wgfx(cinfo->regbase, CL_GR33, 0x00);
1487*4882a593Smuzhiyun 		break;
1488*4882a593Smuzhiyun 
1489*4882a593Smuzhiyun 	case BT_LAGUNA:
1490*4882a593Smuzhiyun 	case BT_LAGUNAB:
1491*4882a593Smuzhiyun 		/* Nothing to do to reset the board. */
1492*4882a593Smuzhiyun 		break;
1493*4882a593Smuzhiyun 
1494*4882a593Smuzhiyun 	default:
1495*4882a593Smuzhiyun 		dev_err(info->device, "Warning: Unknown board type\n");
1496*4882a593Smuzhiyun 		break;
1497*4882a593Smuzhiyun 	}
1498*4882a593Smuzhiyun 
1499*4882a593Smuzhiyun 	/* make sure RAM size set by this point */
1500*4882a593Smuzhiyun 	assert(info->screen_size > 0);
1501*4882a593Smuzhiyun 
1502*4882a593Smuzhiyun 	/* the P4 is not fully initialized here; I rely on it having been */
1503*4882a593Smuzhiyun 	/* inited under AmigaOS already, which seems to work just fine    */
1504*4882a593Smuzhiyun 	/* (Klaus advised to do it this way)			      */
1505*4882a593Smuzhiyun 
1506*4882a593Smuzhiyun 	if (cinfo->btype != BT_PICASSO4) {
1507*4882a593Smuzhiyun 		WGen(cinfo, CL_VSSM, 0x10);	/* EGS: 0x16 */
1508*4882a593Smuzhiyun 		WGen(cinfo, CL_POS102, 0x01);
1509*4882a593Smuzhiyun 		WGen(cinfo, CL_VSSM, 0x08);	/* EGS: 0x0e */
1510*4882a593Smuzhiyun 
1511*4882a593Smuzhiyun 		if (cinfo->btype != BT_SD64)
1512*4882a593Smuzhiyun 			WGen(cinfo, CL_VSSM2, 0x01);
1513*4882a593Smuzhiyun 
1514*4882a593Smuzhiyun 		/* reset sequencer logic */
1515*4882a593Smuzhiyun 		vga_wseq(cinfo->regbase, VGA_SEQ_RESET, 0x03);
1516*4882a593Smuzhiyun 
1517*4882a593Smuzhiyun 		/* FullBandwidth (video off) and 8/9 dot clock */
1518*4882a593Smuzhiyun 		vga_wseq(cinfo->regbase, VGA_SEQ_CLOCK_MODE, 0x21);
1519*4882a593Smuzhiyun 
1520*4882a593Smuzhiyun 		/* "magic cookie" - doesn't make any sense to me.. */
1521*4882a593Smuzhiyun /*      vga_wgfx(cinfo->regbase, CL_GRA, 0xce);   */
1522*4882a593Smuzhiyun 		/* unlock all extension registers */
1523*4882a593Smuzhiyun 		vga_wseq(cinfo->regbase, CL_SEQR6, 0x12);
1524*4882a593Smuzhiyun 
1525*4882a593Smuzhiyun 		switch (cinfo->btype) {
1526*4882a593Smuzhiyun 		case BT_GD5480:
1527*4882a593Smuzhiyun 			vga_wseq(cinfo->regbase, CL_SEQRF, 0x98);
1528*4882a593Smuzhiyun 			break;
1529*4882a593Smuzhiyun 		case BT_ALPINE:
1530*4882a593Smuzhiyun 		case BT_LAGUNA:
1531*4882a593Smuzhiyun 		case BT_LAGUNAB:
1532*4882a593Smuzhiyun 			break;
1533*4882a593Smuzhiyun 		case BT_SD64:
1534*4882a593Smuzhiyun #ifdef CONFIG_ZORRO
1535*4882a593Smuzhiyun 			vga_wseq(cinfo->regbase, CL_SEQRF, 0xb8);
1536*4882a593Smuzhiyun #endif
1537*4882a593Smuzhiyun 			break;
1538*4882a593Smuzhiyun 		default:
1539*4882a593Smuzhiyun 			vga_wseq(cinfo->regbase, CL_SEQR16, 0x0f);
1540*4882a593Smuzhiyun 			vga_wseq(cinfo->regbase, CL_SEQRF, 0xb0);
1541*4882a593Smuzhiyun 			break;
1542*4882a593Smuzhiyun 		}
1543*4882a593Smuzhiyun 	}
1544*4882a593Smuzhiyun 	/* plane mask: nothing */
1545*4882a593Smuzhiyun 	vga_wseq(cinfo->regbase, VGA_SEQ_PLANE_WRITE, 0xff);
1546*4882a593Smuzhiyun 	/* character map select: doesn't even matter in gx mode */
1547*4882a593Smuzhiyun 	vga_wseq(cinfo->regbase, VGA_SEQ_CHARACTER_MAP, 0x00);
1548*4882a593Smuzhiyun 	/* memory mode: chain4, ext. memory */
1549*4882a593Smuzhiyun 	vga_wseq(cinfo->regbase, VGA_SEQ_MEMORY_MODE, 0x0a);
1550*4882a593Smuzhiyun 
1551*4882a593Smuzhiyun 	/* controller-internal base address of video memory */
1552*4882a593Smuzhiyun 	if (bi->init_sr07)
1553*4882a593Smuzhiyun 		vga_wseq(cinfo->regbase, CL_SEQR7, bi->sr07);
1554*4882a593Smuzhiyun 
1555*4882a593Smuzhiyun 	/*  vga_wseq(cinfo->regbase, CL_SEQR8, 0x00); */
1556*4882a593Smuzhiyun 	/* EEPROM control: shouldn't be necessary to write to this at all.. */
1557*4882a593Smuzhiyun 
1558*4882a593Smuzhiyun 	/* graphics cursor X position (incomplete; position gives rem. 3 bits */
1559*4882a593Smuzhiyun 	vga_wseq(cinfo->regbase, CL_SEQR10, 0x00);
1560*4882a593Smuzhiyun 	/* graphics cursor Y position (..."... ) */
1561*4882a593Smuzhiyun 	vga_wseq(cinfo->regbase, CL_SEQR11, 0x00);
1562*4882a593Smuzhiyun 	/* graphics cursor attributes */
1563*4882a593Smuzhiyun 	vga_wseq(cinfo->regbase, CL_SEQR12, 0x00);
1564*4882a593Smuzhiyun 	/* graphics cursor pattern address */
1565*4882a593Smuzhiyun 	vga_wseq(cinfo->regbase, CL_SEQR13, 0x00);
1566*4882a593Smuzhiyun 
1567*4882a593Smuzhiyun 	/* writing these on a P4 might give problems..  */
1568*4882a593Smuzhiyun 	if (cinfo->btype != BT_PICASSO4) {
1569*4882a593Smuzhiyun 		/* configuration readback and ext. color */
1570*4882a593Smuzhiyun 		vga_wseq(cinfo->regbase, CL_SEQR17, 0x00);
1571*4882a593Smuzhiyun 		/* signature generator */
1572*4882a593Smuzhiyun 		vga_wseq(cinfo->regbase, CL_SEQR18, 0x02);
1573*4882a593Smuzhiyun 	}
1574*4882a593Smuzhiyun 
1575*4882a593Smuzhiyun 	/* Screen A preset row scan: none */
1576*4882a593Smuzhiyun 	vga_wcrt(cinfo->regbase, VGA_CRTC_PRESET_ROW, 0x00);
1577*4882a593Smuzhiyun 	/* Text cursor start: disable text cursor */
1578*4882a593Smuzhiyun 	vga_wcrt(cinfo->regbase, VGA_CRTC_CURSOR_START, 0x20);
1579*4882a593Smuzhiyun 	/* Text cursor end: - */
1580*4882a593Smuzhiyun 	vga_wcrt(cinfo->regbase, VGA_CRTC_CURSOR_END, 0x00);
1581*4882a593Smuzhiyun 	/* text cursor location high: 0 */
1582*4882a593Smuzhiyun 	vga_wcrt(cinfo->regbase, VGA_CRTC_CURSOR_HI, 0x00);
1583*4882a593Smuzhiyun 	/* text cursor location low: 0 */
1584*4882a593Smuzhiyun 	vga_wcrt(cinfo->regbase, VGA_CRTC_CURSOR_LO, 0x00);
1585*4882a593Smuzhiyun 
1586*4882a593Smuzhiyun 	/* Underline Row scanline: - */
1587*4882a593Smuzhiyun 	vga_wcrt(cinfo->regbase, VGA_CRTC_UNDERLINE, 0x00);
1588*4882a593Smuzhiyun 	/* ### add 0x40 for text modes with > 30 MHz pixclock */
1589*4882a593Smuzhiyun 	/* ext. display controls: ext.adr. wrap */
1590*4882a593Smuzhiyun 	vga_wcrt(cinfo->regbase, CL_CRT1B, 0x02);
1591*4882a593Smuzhiyun 
1592*4882a593Smuzhiyun 	/* Set/Reset registers: - */
1593*4882a593Smuzhiyun 	vga_wgfx(cinfo->regbase, VGA_GFX_SR_VALUE, 0x00);
1594*4882a593Smuzhiyun 	/* Set/Reset enable: - */
1595*4882a593Smuzhiyun 	vga_wgfx(cinfo->regbase, VGA_GFX_SR_ENABLE, 0x00);
1596*4882a593Smuzhiyun 	/* Color Compare: - */
1597*4882a593Smuzhiyun 	vga_wgfx(cinfo->regbase, VGA_GFX_COMPARE_VALUE, 0x00);
1598*4882a593Smuzhiyun 	/* Data Rotate: - */
1599*4882a593Smuzhiyun 	vga_wgfx(cinfo->regbase, VGA_GFX_DATA_ROTATE, 0x00);
1600*4882a593Smuzhiyun 	/* Read Map Select: - */
1601*4882a593Smuzhiyun 	vga_wgfx(cinfo->regbase, VGA_GFX_PLANE_READ, 0x00);
1602*4882a593Smuzhiyun 	/* Mode: conf. for 16/4/2 color mode, no odd/even, read/write mode 0 */
1603*4882a593Smuzhiyun 	vga_wgfx(cinfo->regbase, VGA_GFX_MODE, 0x00);
1604*4882a593Smuzhiyun 	/* Miscellaneous: memory map base address, graphics mode */
1605*4882a593Smuzhiyun 	vga_wgfx(cinfo->regbase, VGA_GFX_MISC, 0x01);
1606*4882a593Smuzhiyun 	/* Color Don't care: involve all planes */
1607*4882a593Smuzhiyun 	vga_wgfx(cinfo->regbase, VGA_GFX_COMPARE_MASK, 0x0f);
1608*4882a593Smuzhiyun 	/* Bit Mask: no mask at all */
1609*4882a593Smuzhiyun 	vga_wgfx(cinfo->regbase, VGA_GFX_BIT_MASK, 0xff);
1610*4882a593Smuzhiyun 
1611*4882a593Smuzhiyun 	if (cinfo->btype == BT_ALPINE || cinfo->btype == BT_SD64 ||
1612*4882a593Smuzhiyun 	    is_laguna(cinfo))
1613*4882a593Smuzhiyun 		/* (5434 can't have bit 3 set for bitblt) */
1614*4882a593Smuzhiyun 		vga_wgfx(cinfo->regbase, CL_GRB, 0x20);
1615*4882a593Smuzhiyun 	else
1616*4882a593Smuzhiyun 	/* Graphics controller mode extensions: finer granularity,
1617*4882a593Smuzhiyun 	 * 8byte data latches
1618*4882a593Smuzhiyun 	 */
1619*4882a593Smuzhiyun 		vga_wgfx(cinfo->regbase, CL_GRB, 0x28);
1620*4882a593Smuzhiyun 
1621*4882a593Smuzhiyun 	vga_wgfx(cinfo->regbase, CL_GRC, 0xff);	/* Color Key compare: - */
1622*4882a593Smuzhiyun 	vga_wgfx(cinfo->regbase, CL_GRD, 0x00);	/* Color Key compare mask: - */
1623*4882a593Smuzhiyun 	vga_wgfx(cinfo->regbase, CL_GRE, 0x00);	/* Miscellaneous control: - */
1624*4882a593Smuzhiyun 	/* Background color byte 1: - */
1625*4882a593Smuzhiyun 	/*  vga_wgfx (cinfo->regbase, CL_GR10, 0x00); */
1626*4882a593Smuzhiyun 	/*  vga_wgfx (cinfo->regbase, CL_GR11, 0x00); */
1627*4882a593Smuzhiyun 
1628*4882a593Smuzhiyun 	/* Attribute Controller palette registers: "identity mapping" */
1629*4882a593Smuzhiyun 	vga_wattr(cinfo->regbase, VGA_ATC_PALETTE0, 0x00);
1630*4882a593Smuzhiyun 	vga_wattr(cinfo->regbase, VGA_ATC_PALETTE1, 0x01);
1631*4882a593Smuzhiyun 	vga_wattr(cinfo->regbase, VGA_ATC_PALETTE2, 0x02);
1632*4882a593Smuzhiyun 	vga_wattr(cinfo->regbase, VGA_ATC_PALETTE3, 0x03);
1633*4882a593Smuzhiyun 	vga_wattr(cinfo->regbase, VGA_ATC_PALETTE4, 0x04);
1634*4882a593Smuzhiyun 	vga_wattr(cinfo->regbase, VGA_ATC_PALETTE5, 0x05);
1635*4882a593Smuzhiyun 	vga_wattr(cinfo->regbase, VGA_ATC_PALETTE6, 0x06);
1636*4882a593Smuzhiyun 	vga_wattr(cinfo->regbase, VGA_ATC_PALETTE7, 0x07);
1637*4882a593Smuzhiyun 	vga_wattr(cinfo->regbase, VGA_ATC_PALETTE8, 0x08);
1638*4882a593Smuzhiyun 	vga_wattr(cinfo->regbase, VGA_ATC_PALETTE9, 0x09);
1639*4882a593Smuzhiyun 	vga_wattr(cinfo->regbase, VGA_ATC_PALETTEA, 0x0a);
1640*4882a593Smuzhiyun 	vga_wattr(cinfo->regbase, VGA_ATC_PALETTEB, 0x0b);
1641*4882a593Smuzhiyun 	vga_wattr(cinfo->regbase, VGA_ATC_PALETTEC, 0x0c);
1642*4882a593Smuzhiyun 	vga_wattr(cinfo->regbase, VGA_ATC_PALETTED, 0x0d);
1643*4882a593Smuzhiyun 	vga_wattr(cinfo->regbase, VGA_ATC_PALETTEE, 0x0e);
1644*4882a593Smuzhiyun 	vga_wattr(cinfo->regbase, VGA_ATC_PALETTEF, 0x0f);
1645*4882a593Smuzhiyun 
1646*4882a593Smuzhiyun 	/* Attribute Controller mode: graphics mode */
1647*4882a593Smuzhiyun 	vga_wattr(cinfo->regbase, VGA_ATC_MODE, 0x01);
1648*4882a593Smuzhiyun 	/* Overscan color reg.: reg. 0 */
1649*4882a593Smuzhiyun 	vga_wattr(cinfo->regbase, VGA_ATC_OVERSCAN, 0x00);
1650*4882a593Smuzhiyun 	/* Color Plane enable: Enable all 4 planes */
1651*4882a593Smuzhiyun 	vga_wattr(cinfo->regbase, VGA_ATC_PLANE_ENABLE, 0x0f);
1652*4882a593Smuzhiyun 	/* Color Select: - */
1653*4882a593Smuzhiyun 	vga_wattr(cinfo->regbase, VGA_ATC_COLOR_PAGE, 0x00);
1654*4882a593Smuzhiyun 
1655*4882a593Smuzhiyun 	WGen(cinfo, VGA_PEL_MSK, 0xff);	/* Pixel mask: no mask */
1656*4882a593Smuzhiyun 
1657*4882a593Smuzhiyun 	/* BLT Start/status: Blitter reset */
1658*4882a593Smuzhiyun 	vga_wgfx(cinfo->regbase, CL_GR31, 0x04);
1659*4882a593Smuzhiyun 	/* - " -	   : "end-of-reset" */
1660*4882a593Smuzhiyun 	vga_wgfx(cinfo->regbase, CL_GR31, 0x00);
1661*4882a593Smuzhiyun 
1662*4882a593Smuzhiyun 	/* misc... */
1663*4882a593Smuzhiyun 	WHDR(cinfo, 0);	/* Hidden DAC register: - */
1664*4882a593Smuzhiyun 	return;
1665*4882a593Smuzhiyun }
1666*4882a593Smuzhiyun 
switch_monitor(struct cirrusfb_info * cinfo,int on)1667*4882a593Smuzhiyun static void switch_monitor(struct cirrusfb_info *cinfo, int on)
1668*4882a593Smuzhiyun {
1669*4882a593Smuzhiyun #ifdef CONFIG_ZORRO /* only works on Zorro boards */
1670*4882a593Smuzhiyun 	static int IsOn = 0;	/* XXX not ok for multiple boards */
1671*4882a593Smuzhiyun 
1672*4882a593Smuzhiyun 	if (cinfo->btype == BT_PICASSO4)
1673*4882a593Smuzhiyun 		return;		/* nothing to switch */
1674*4882a593Smuzhiyun 	if (cinfo->btype == BT_ALPINE)
1675*4882a593Smuzhiyun 		return;		/* nothing to switch */
1676*4882a593Smuzhiyun 	if (cinfo->btype == BT_GD5480)
1677*4882a593Smuzhiyun 		return;		/* nothing to switch */
1678*4882a593Smuzhiyun 	if (cinfo->btype == BT_PICASSO) {
1679*4882a593Smuzhiyun 		if ((on && !IsOn) || (!on && IsOn))
1680*4882a593Smuzhiyun 			WSFR(cinfo, 0xff);
1681*4882a593Smuzhiyun 		return;
1682*4882a593Smuzhiyun 	}
1683*4882a593Smuzhiyun 	if (on) {
1684*4882a593Smuzhiyun 		switch (cinfo->btype) {
1685*4882a593Smuzhiyun 		case BT_SD64:
1686*4882a593Smuzhiyun 			WSFR(cinfo, cinfo->SFR | 0x21);
1687*4882a593Smuzhiyun 			break;
1688*4882a593Smuzhiyun 		case BT_PICCOLO:
1689*4882a593Smuzhiyun 			WSFR(cinfo, cinfo->SFR | 0x28);
1690*4882a593Smuzhiyun 			break;
1691*4882a593Smuzhiyun 		case BT_SPECTRUM:
1692*4882a593Smuzhiyun 			WSFR(cinfo, 0x6f);
1693*4882a593Smuzhiyun 			break;
1694*4882a593Smuzhiyun 		default: /* do nothing */ break;
1695*4882a593Smuzhiyun 		}
1696*4882a593Smuzhiyun 	} else {
1697*4882a593Smuzhiyun 		switch (cinfo->btype) {
1698*4882a593Smuzhiyun 		case BT_SD64:
1699*4882a593Smuzhiyun 			WSFR(cinfo, cinfo->SFR & 0xde);
1700*4882a593Smuzhiyun 			break;
1701*4882a593Smuzhiyun 		case BT_PICCOLO:
1702*4882a593Smuzhiyun 			WSFR(cinfo, cinfo->SFR & 0xd7);
1703*4882a593Smuzhiyun 			break;
1704*4882a593Smuzhiyun 		case BT_SPECTRUM:
1705*4882a593Smuzhiyun 			WSFR(cinfo, 0x4f);
1706*4882a593Smuzhiyun 			break;
1707*4882a593Smuzhiyun 		default: /* do nothing */
1708*4882a593Smuzhiyun 			break;
1709*4882a593Smuzhiyun 		}
1710*4882a593Smuzhiyun 	}
1711*4882a593Smuzhiyun #endif /* CONFIG_ZORRO */
1712*4882a593Smuzhiyun }
1713*4882a593Smuzhiyun 
1714*4882a593Smuzhiyun /******************************************/
1715*4882a593Smuzhiyun /* Linux 2.6-style  accelerated functions */
1716*4882a593Smuzhiyun /******************************************/
1717*4882a593Smuzhiyun 
cirrusfb_sync(struct fb_info * info)1718*4882a593Smuzhiyun static int cirrusfb_sync(struct fb_info *info)
1719*4882a593Smuzhiyun {
1720*4882a593Smuzhiyun 	struct cirrusfb_info *cinfo = info->par;
1721*4882a593Smuzhiyun 
1722*4882a593Smuzhiyun 	if (!is_laguna(cinfo)) {
1723*4882a593Smuzhiyun 		while (vga_rgfx(cinfo->regbase, CL_GR31) & 0x03)
1724*4882a593Smuzhiyun 			cpu_relax();
1725*4882a593Smuzhiyun 	}
1726*4882a593Smuzhiyun 	return 0;
1727*4882a593Smuzhiyun }
1728*4882a593Smuzhiyun 
cirrusfb_fillrect(struct fb_info * info,const struct fb_fillrect * region)1729*4882a593Smuzhiyun static void cirrusfb_fillrect(struct fb_info *info,
1730*4882a593Smuzhiyun 			      const struct fb_fillrect *region)
1731*4882a593Smuzhiyun {
1732*4882a593Smuzhiyun 	struct fb_fillrect modded;
1733*4882a593Smuzhiyun 	int vxres, vyres;
1734*4882a593Smuzhiyun 	struct cirrusfb_info *cinfo = info->par;
1735*4882a593Smuzhiyun 	int m = info->var.bits_per_pixel;
1736*4882a593Smuzhiyun 	u32 color = (info->fix.visual == FB_VISUAL_TRUECOLOR) ?
1737*4882a593Smuzhiyun 		cinfo->pseudo_palette[region->color] : region->color;
1738*4882a593Smuzhiyun 
1739*4882a593Smuzhiyun 	if (info->state != FBINFO_STATE_RUNNING)
1740*4882a593Smuzhiyun 		return;
1741*4882a593Smuzhiyun 	if (info->flags & FBINFO_HWACCEL_DISABLED) {
1742*4882a593Smuzhiyun 		cfb_fillrect(info, region);
1743*4882a593Smuzhiyun 		return;
1744*4882a593Smuzhiyun 	}
1745*4882a593Smuzhiyun 
1746*4882a593Smuzhiyun 	vxres = info->var.xres_virtual;
1747*4882a593Smuzhiyun 	vyres = info->var.yres_virtual;
1748*4882a593Smuzhiyun 
1749*4882a593Smuzhiyun 	memcpy(&modded, region, sizeof(struct fb_fillrect));
1750*4882a593Smuzhiyun 
1751*4882a593Smuzhiyun 	if (!modded.width || !modded.height ||
1752*4882a593Smuzhiyun 	   modded.dx >= vxres || modded.dy >= vyres)
1753*4882a593Smuzhiyun 		return;
1754*4882a593Smuzhiyun 
1755*4882a593Smuzhiyun 	if (modded.dx + modded.width  > vxres)
1756*4882a593Smuzhiyun 		modded.width  = vxres - modded.dx;
1757*4882a593Smuzhiyun 	if (modded.dy + modded.height > vyres)
1758*4882a593Smuzhiyun 		modded.height = vyres - modded.dy;
1759*4882a593Smuzhiyun 
1760*4882a593Smuzhiyun 	cirrusfb_RectFill(cinfo->regbase,
1761*4882a593Smuzhiyun 			  info->var.bits_per_pixel,
1762*4882a593Smuzhiyun 			  (region->dx * m) / 8, region->dy,
1763*4882a593Smuzhiyun 			  (region->width * m) / 8, region->height,
1764*4882a593Smuzhiyun 			  color, color,
1765*4882a593Smuzhiyun 			  info->fix.line_length, 0x40);
1766*4882a593Smuzhiyun }
1767*4882a593Smuzhiyun 
cirrusfb_copyarea(struct fb_info * info,const struct fb_copyarea * area)1768*4882a593Smuzhiyun static void cirrusfb_copyarea(struct fb_info *info,
1769*4882a593Smuzhiyun 			      const struct fb_copyarea *area)
1770*4882a593Smuzhiyun {
1771*4882a593Smuzhiyun 	struct fb_copyarea modded;
1772*4882a593Smuzhiyun 	u32 vxres, vyres;
1773*4882a593Smuzhiyun 	struct cirrusfb_info *cinfo = info->par;
1774*4882a593Smuzhiyun 	int m = info->var.bits_per_pixel;
1775*4882a593Smuzhiyun 
1776*4882a593Smuzhiyun 	if (info->state != FBINFO_STATE_RUNNING)
1777*4882a593Smuzhiyun 		return;
1778*4882a593Smuzhiyun 	if (info->flags & FBINFO_HWACCEL_DISABLED) {
1779*4882a593Smuzhiyun 		cfb_copyarea(info, area);
1780*4882a593Smuzhiyun 		return;
1781*4882a593Smuzhiyun 	}
1782*4882a593Smuzhiyun 
1783*4882a593Smuzhiyun 	vxres = info->var.xres_virtual;
1784*4882a593Smuzhiyun 	vyres = info->var.yres_virtual;
1785*4882a593Smuzhiyun 	memcpy(&modded, area, sizeof(struct fb_copyarea));
1786*4882a593Smuzhiyun 
1787*4882a593Smuzhiyun 	if (!modded.width || !modded.height ||
1788*4882a593Smuzhiyun 	   modded.sx >= vxres || modded.sy >= vyres ||
1789*4882a593Smuzhiyun 	   modded.dx >= vxres || modded.dy >= vyres)
1790*4882a593Smuzhiyun 		return;
1791*4882a593Smuzhiyun 
1792*4882a593Smuzhiyun 	if (modded.sx + modded.width > vxres)
1793*4882a593Smuzhiyun 		modded.width = vxres - modded.sx;
1794*4882a593Smuzhiyun 	if (modded.dx + modded.width > vxres)
1795*4882a593Smuzhiyun 		modded.width = vxres - modded.dx;
1796*4882a593Smuzhiyun 	if (modded.sy + modded.height > vyres)
1797*4882a593Smuzhiyun 		modded.height = vyres - modded.sy;
1798*4882a593Smuzhiyun 	if (modded.dy + modded.height > vyres)
1799*4882a593Smuzhiyun 		modded.height = vyres - modded.dy;
1800*4882a593Smuzhiyun 
1801*4882a593Smuzhiyun 	cirrusfb_BitBLT(cinfo->regbase, info->var.bits_per_pixel,
1802*4882a593Smuzhiyun 			(area->sx * m) / 8, area->sy,
1803*4882a593Smuzhiyun 			(area->dx * m) / 8, area->dy,
1804*4882a593Smuzhiyun 			(area->width * m) / 8, area->height,
1805*4882a593Smuzhiyun 			info->fix.line_length);
1806*4882a593Smuzhiyun 
1807*4882a593Smuzhiyun }
1808*4882a593Smuzhiyun 
cirrusfb_imageblit(struct fb_info * info,const struct fb_image * image)1809*4882a593Smuzhiyun static void cirrusfb_imageblit(struct fb_info *info,
1810*4882a593Smuzhiyun 			       const struct fb_image *image)
1811*4882a593Smuzhiyun {
1812*4882a593Smuzhiyun 	struct cirrusfb_info *cinfo = info->par;
1813*4882a593Smuzhiyun 	unsigned char op = (info->var.bits_per_pixel == 24) ? 0xc : 0x4;
1814*4882a593Smuzhiyun 
1815*4882a593Smuzhiyun 	if (info->state != FBINFO_STATE_RUNNING)
1816*4882a593Smuzhiyun 		return;
1817*4882a593Smuzhiyun 	/* Alpine/SD64 does not work at 24bpp ??? */
1818*4882a593Smuzhiyun 	if (info->flags & FBINFO_HWACCEL_DISABLED || image->depth != 1)
1819*4882a593Smuzhiyun 		cfb_imageblit(info, image);
1820*4882a593Smuzhiyun 	else if ((cinfo->btype == BT_ALPINE || cinfo->btype == BT_SD64) &&
1821*4882a593Smuzhiyun 		  op == 0xc)
1822*4882a593Smuzhiyun 		cfb_imageblit(info, image);
1823*4882a593Smuzhiyun 	else {
1824*4882a593Smuzhiyun 		unsigned size = ((image->width + 7) >> 3) * image->height;
1825*4882a593Smuzhiyun 		int m = info->var.bits_per_pixel;
1826*4882a593Smuzhiyun 		u32 fg, bg;
1827*4882a593Smuzhiyun 
1828*4882a593Smuzhiyun 		if (info->var.bits_per_pixel == 8) {
1829*4882a593Smuzhiyun 			fg = image->fg_color;
1830*4882a593Smuzhiyun 			bg = image->bg_color;
1831*4882a593Smuzhiyun 		} else {
1832*4882a593Smuzhiyun 			fg = ((u32 *)(info->pseudo_palette))[image->fg_color];
1833*4882a593Smuzhiyun 			bg = ((u32 *)(info->pseudo_palette))[image->bg_color];
1834*4882a593Smuzhiyun 		}
1835*4882a593Smuzhiyun 		if (info->var.bits_per_pixel == 24) {
1836*4882a593Smuzhiyun 			/* clear background first */
1837*4882a593Smuzhiyun 			cirrusfb_RectFill(cinfo->regbase,
1838*4882a593Smuzhiyun 					  info->var.bits_per_pixel,
1839*4882a593Smuzhiyun 					  (image->dx * m) / 8, image->dy,
1840*4882a593Smuzhiyun 					  (image->width * m) / 8,
1841*4882a593Smuzhiyun 					  image->height,
1842*4882a593Smuzhiyun 					  bg, bg,
1843*4882a593Smuzhiyun 					  info->fix.line_length, 0x40);
1844*4882a593Smuzhiyun 		}
1845*4882a593Smuzhiyun 		cirrusfb_RectFill(cinfo->regbase,
1846*4882a593Smuzhiyun 				  info->var.bits_per_pixel,
1847*4882a593Smuzhiyun 				  (image->dx * m) / 8, image->dy,
1848*4882a593Smuzhiyun 				  (image->width * m) / 8, image->height,
1849*4882a593Smuzhiyun 				  fg, bg,
1850*4882a593Smuzhiyun 				  info->fix.line_length, op);
1851*4882a593Smuzhiyun 		memcpy(info->screen_base, image->data, size);
1852*4882a593Smuzhiyun 	}
1853*4882a593Smuzhiyun }
1854*4882a593Smuzhiyun 
1855*4882a593Smuzhiyun #ifdef CONFIG_PCI
1856*4882a593Smuzhiyun static int release_io_ports;
1857*4882a593Smuzhiyun 
1858*4882a593Smuzhiyun /* Pulled the logic from XFree86 Cirrus driver to get the memory size,
1859*4882a593Smuzhiyun  * based on the DRAM bandwidth bit and DRAM bank switching bit.  This
1860*4882a593Smuzhiyun  * works with 1MB, 2MB and 4MB configurations (which the Motorola boards
1861*4882a593Smuzhiyun  * seem to have. */
cirrusfb_get_memsize(struct fb_info * info,u8 __iomem * regbase)1862*4882a593Smuzhiyun static unsigned int cirrusfb_get_memsize(struct fb_info *info,
1863*4882a593Smuzhiyun 					 u8 __iomem *regbase)
1864*4882a593Smuzhiyun {
1865*4882a593Smuzhiyun 	unsigned long mem;
1866*4882a593Smuzhiyun 	struct cirrusfb_info *cinfo = info->par;
1867*4882a593Smuzhiyun 
1868*4882a593Smuzhiyun 	if (is_laguna(cinfo)) {
1869*4882a593Smuzhiyun 		unsigned char SR14 = vga_rseq(regbase, CL_SEQR14);
1870*4882a593Smuzhiyun 
1871*4882a593Smuzhiyun 		mem = ((SR14 & 7) + 1) << 20;
1872*4882a593Smuzhiyun 	} else {
1873*4882a593Smuzhiyun 		unsigned char SRF = vga_rseq(regbase, CL_SEQRF);
1874*4882a593Smuzhiyun 		switch ((SRF & 0x18)) {
1875*4882a593Smuzhiyun 		case 0x08:
1876*4882a593Smuzhiyun 			mem = 512 * 1024;
1877*4882a593Smuzhiyun 			break;
1878*4882a593Smuzhiyun 		case 0x10:
1879*4882a593Smuzhiyun 			mem = 1024 * 1024;
1880*4882a593Smuzhiyun 			break;
1881*4882a593Smuzhiyun 		/* 64-bit DRAM data bus width; assume 2MB.
1882*4882a593Smuzhiyun 		 * Also indicates 2MB memory on the 5430.
1883*4882a593Smuzhiyun 		 */
1884*4882a593Smuzhiyun 		case 0x18:
1885*4882a593Smuzhiyun 			mem = 2048 * 1024;
1886*4882a593Smuzhiyun 			break;
1887*4882a593Smuzhiyun 		default:
1888*4882a593Smuzhiyun 			dev_warn(info->device, "Unknown memory size!\n");
1889*4882a593Smuzhiyun 			mem = 1024 * 1024;
1890*4882a593Smuzhiyun 		}
1891*4882a593Smuzhiyun 		/* If DRAM bank switching is enabled, there must be
1892*4882a593Smuzhiyun 		 * twice as much memory installed. (4MB on the 5434)
1893*4882a593Smuzhiyun 		 */
1894*4882a593Smuzhiyun 		if (cinfo->btype != BT_ALPINE && (SRF & 0x80) != 0)
1895*4882a593Smuzhiyun 			mem *= 2;
1896*4882a593Smuzhiyun 	}
1897*4882a593Smuzhiyun 
1898*4882a593Smuzhiyun 	/* TODO: Handling of GD5446/5480 (see XF86 sources ...) */
1899*4882a593Smuzhiyun 	return mem;
1900*4882a593Smuzhiyun }
1901*4882a593Smuzhiyun 
get_pci_addrs(const struct pci_dev * pdev,unsigned long * display,unsigned long * registers)1902*4882a593Smuzhiyun static void get_pci_addrs(const struct pci_dev *pdev,
1903*4882a593Smuzhiyun 			  unsigned long *display, unsigned long *registers)
1904*4882a593Smuzhiyun {
1905*4882a593Smuzhiyun 	assert(pdev != NULL);
1906*4882a593Smuzhiyun 	assert(display != NULL);
1907*4882a593Smuzhiyun 	assert(registers != NULL);
1908*4882a593Smuzhiyun 
1909*4882a593Smuzhiyun 	*display = 0;
1910*4882a593Smuzhiyun 	*registers = 0;
1911*4882a593Smuzhiyun 
1912*4882a593Smuzhiyun 	/* This is a best-guess for now */
1913*4882a593Smuzhiyun 
1914*4882a593Smuzhiyun 	if (pci_resource_flags(pdev, 0) & IORESOURCE_IO) {
1915*4882a593Smuzhiyun 		*display = pci_resource_start(pdev, 1);
1916*4882a593Smuzhiyun 		*registers = pci_resource_start(pdev, 0);
1917*4882a593Smuzhiyun 	} else {
1918*4882a593Smuzhiyun 		*display = pci_resource_start(pdev, 0);
1919*4882a593Smuzhiyun 		*registers = pci_resource_start(pdev, 1);
1920*4882a593Smuzhiyun 	}
1921*4882a593Smuzhiyun 
1922*4882a593Smuzhiyun 	assert(*display != 0);
1923*4882a593Smuzhiyun }
1924*4882a593Smuzhiyun 
cirrusfb_pci_unmap(struct fb_info * info)1925*4882a593Smuzhiyun static void cirrusfb_pci_unmap(struct fb_info *info)
1926*4882a593Smuzhiyun {
1927*4882a593Smuzhiyun 	struct pci_dev *pdev = to_pci_dev(info->device);
1928*4882a593Smuzhiyun 	struct cirrusfb_info *cinfo = info->par;
1929*4882a593Smuzhiyun 
1930*4882a593Smuzhiyun 	if (cinfo->laguna_mmio == NULL)
1931*4882a593Smuzhiyun 		iounmap(cinfo->laguna_mmio);
1932*4882a593Smuzhiyun 	iounmap(info->screen_base);
1933*4882a593Smuzhiyun #if 0 /* if system didn't claim this region, we would... */
1934*4882a593Smuzhiyun 	release_mem_region(0xA0000, 65535);
1935*4882a593Smuzhiyun #endif
1936*4882a593Smuzhiyun 	if (release_io_ports)
1937*4882a593Smuzhiyun 		release_region(0x3C0, 32);
1938*4882a593Smuzhiyun 	pci_release_regions(pdev);
1939*4882a593Smuzhiyun }
1940*4882a593Smuzhiyun #endif /* CONFIG_PCI */
1941*4882a593Smuzhiyun 
1942*4882a593Smuzhiyun #ifdef CONFIG_ZORRO
cirrusfb_zorro_unmap(struct fb_info * info)1943*4882a593Smuzhiyun static void cirrusfb_zorro_unmap(struct fb_info *info)
1944*4882a593Smuzhiyun {
1945*4882a593Smuzhiyun 	struct cirrusfb_info *cinfo = info->par;
1946*4882a593Smuzhiyun 	struct zorro_dev *zdev = to_zorro_dev(info->device);
1947*4882a593Smuzhiyun 
1948*4882a593Smuzhiyun 	if (info->fix.smem_start > 16 * MB_)
1949*4882a593Smuzhiyun 		iounmap(info->screen_base);
1950*4882a593Smuzhiyun 	if (info->fix.mmio_start > 16 * MB_)
1951*4882a593Smuzhiyun 		iounmap(cinfo->regbase);
1952*4882a593Smuzhiyun 
1953*4882a593Smuzhiyun 	zorro_release_device(zdev);
1954*4882a593Smuzhiyun }
1955*4882a593Smuzhiyun #endif /* CONFIG_ZORRO */
1956*4882a593Smuzhiyun 
1957*4882a593Smuzhiyun /* function table of the above functions */
1958*4882a593Smuzhiyun static const struct fb_ops cirrusfb_ops = {
1959*4882a593Smuzhiyun 	.owner		= THIS_MODULE,
1960*4882a593Smuzhiyun 	.fb_open	= cirrusfb_open,
1961*4882a593Smuzhiyun 	.fb_release	= cirrusfb_release,
1962*4882a593Smuzhiyun 	.fb_setcolreg	= cirrusfb_setcolreg,
1963*4882a593Smuzhiyun 	.fb_check_var	= cirrusfb_check_var,
1964*4882a593Smuzhiyun 	.fb_set_par	= cirrusfb_set_par,
1965*4882a593Smuzhiyun 	.fb_pan_display = cirrusfb_pan_display,
1966*4882a593Smuzhiyun 	.fb_blank	= cirrusfb_blank,
1967*4882a593Smuzhiyun 	.fb_fillrect	= cirrusfb_fillrect,
1968*4882a593Smuzhiyun 	.fb_copyarea	= cirrusfb_copyarea,
1969*4882a593Smuzhiyun 	.fb_sync	= cirrusfb_sync,
1970*4882a593Smuzhiyun 	.fb_imageblit	= cirrusfb_imageblit,
1971*4882a593Smuzhiyun };
1972*4882a593Smuzhiyun 
cirrusfb_set_fbinfo(struct fb_info * info)1973*4882a593Smuzhiyun static int cirrusfb_set_fbinfo(struct fb_info *info)
1974*4882a593Smuzhiyun {
1975*4882a593Smuzhiyun 	struct cirrusfb_info *cinfo = info->par;
1976*4882a593Smuzhiyun 	struct fb_var_screeninfo *var = &info->var;
1977*4882a593Smuzhiyun 
1978*4882a593Smuzhiyun 	info->pseudo_palette = cinfo->pseudo_palette;
1979*4882a593Smuzhiyun 	info->flags = FBINFO_DEFAULT
1980*4882a593Smuzhiyun 		    | FBINFO_HWACCEL_XPAN
1981*4882a593Smuzhiyun 		    | FBINFO_HWACCEL_YPAN
1982*4882a593Smuzhiyun 		    | FBINFO_HWACCEL_FILLRECT
1983*4882a593Smuzhiyun 		    | FBINFO_HWACCEL_IMAGEBLIT
1984*4882a593Smuzhiyun 		    | FBINFO_HWACCEL_COPYAREA;
1985*4882a593Smuzhiyun 	if (noaccel || is_laguna(cinfo)) {
1986*4882a593Smuzhiyun 		info->flags |= FBINFO_HWACCEL_DISABLED;
1987*4882a593Smuzhiyun 		info->fix.accel = FB_ACCEL_NONE;
1988*4882a593Smuzhiyun 	} else
1989*4882a593Smuzhiyun 		info->fix.accel = FB_ACCEL_CIRRUS_ALPINE;
1990*4882a593Smuzhiyun 
1991*4882a593Smuzhiyun 	info->fbops = &cirrusfb_ops;
1992*4882a593Smuzhiyun 
1993*4882a593Smuzhiyun 	if (cinfo->btype == BT_GD5480) {
1994*4882a593Smuzhiyun 		if (var->bits_per_pixel == 16)
1995*4882a593Smuzhiyun 			info->screen_base += 1 * MB_;
1996*4882a593Smuzhiyun 		if (var->bits_per_pixel == 32)
1997*4882a593Smuzhiyun 			info->screen_base += 2 * MB_;
1998*4882a593Smuzhiyun 	}
1999*4882a593Smuzhiyun 
2000*4882a593Smuzhiyun 	/* Fill fix common fields */
2001*4882a593Smuzhiyun 	strlcpy(info->fix.id, cirrusfb_board_info[cinfo->btype].name,
2002*4882a593Smuzhiyun 		sizeof(info->fix.id));
2003*4882a593Smuzhiyun 
2004*4882a593Smuzhiyun 	/* monochrome: only 1 memory plane */
2005*4882a593Smuzhiyun 	/* 8 bit and above: Use whole memory area */
2006*4882a593Smuzhiyun 	info->fix.smem_len   = info->screen_size;
2007*4882a593Smuzhiyun 	if (var->bits_per_pixel == 1)
2008*4882a593Smuzhiyun 		info->fix.smem_len /= 4;
2009*4882a593Smuzhiyun 	info->fix.type_aux   = 0;
2010*4882a593Smuzhiyun 	info->fix.xpanstep   = 1;
2011*4882a593Smuzhiyun 	info->fix.ypanstep   = 1;
2012*4882a593Smuzhiyun 	info->fix.ywrapstep  = 0;
2013*4882a593Smuzhiyun 
2014*4882a593Smuzhiyun 	/* FIXME: map region at 0xB8000 if available, fill in here */
2015*4882a593Smuzhiyun 	info->fix.mmio_len   = 0;
2016*4882a593Smuzhiyun 
2017*4882a593Smuzhiyun 	fb_alloc_cmap(&info->cmap, 256, 0);
2018*4882a593Smuzhiyun 
2019*4882a593Smuzhiyun 	return 0;
2020*4882a593Smuzhiyun }
2021*4882a593Smuzhiyun 
cirrusfb_register(struct fb_info * info)2022*4882a593Smuzhiyun static int cirrusfb_register(struct fb_info *info)
2023*4882a593Smuzhiyun {
2024*4882a593Smuzhiyun 	struct cirrusfb_info *cinfo = info->par;
2025*4882a593Smuzhiyun 	int err;
2026*4882a593Smuzhiyun 
2027*4882a593Smuzhiyun 	/* sanity checks */
2028*4882a593Smuzhiyun 	assert(cinfo->btype != BT_NONE);
2029*4882a593Smuzhiyun 
2030*4882a593Smuzhiyun 	/* set all the vital stuff */
2031*4882a593Smuzhiyun 	cirrusfb_set_fbinfo(info);
2032*4882a593Smuzhiyun 
2033*4882a593Smuzhiyun 	dev_dbg(info->device, "(RAM start set to: 0x%p)\n", info->screen_base);
2034*4882a593Smuzhiyun 
2035*4882a593Smuzhiyun 	err = fb_find_mode(&info->var, info, mode_option, NULL, 0, NULL, 8);
2036*4882a593Smuzhiyun 	if (!err) {
2037*4882a593Smuzhiyun 		dev_dbg(info->device, "wrong initial video mode\n");
2038*4882a593Smuzhiyun 		err = -EINVAL;
2039*4882a593Smuzhiyun 		goto err_dealloc_cmap;
2040*4882a593Smuzhiyun 	}
2041*4882a593Smuzhiyun 
2042*4882a593Smuzhiyun 	info->var.activate = FB_ACTIVATE_NOW;
2043*4882a593Smuzhiyun 
2044*4882a593Smuzhiyun 	err = cirrusfb_check_var(&info->var, info);
2045*4882a593Smuzhiyun 	if (err < 0) {
2046*4882a593Smuzhiyun 		/* should never happen */
2047*4882a593Smuzhiyun 		dev_dbg(info->device,
2048*4882a593Smuzhiyun 			"choking on default var... umm, no good.\n");
2049*4882a593Smuzhiyun 		goto err_dealloc_cmap;
2050*4882a593Smuzhiyun 	}
2051*4882a593Smuzhiyun 
2052*4882a593Smuzhiyun 	err = register_framebuffer(info);
2053*4882a593Smuzhiyun 	if (err < 0) {
2054*4882a593Smuzhiyun 		dev_err(info->device,
2055*4882a593Smuzhiyun 			"could not register fb device; err = %d!\n", err);
2056*4882a593Smuzhiyun 		goto err_dealloc_cmap;
2057*4882a593Smuzhiyun 	}
2058*4882a593Smuzhiyun 
2059*4882a593Smuzhiyun 	return 0;
2060*4882a593Smuzhiyun 
2061*4882a593Smuzhiyun err_dealloc_cmap:
2062*4882a593Smuzhiyun 	fb_dealloc_cmap(&info->cmap);
2063*4882a593Smuzhiyun 	return err;
2064*4882a593Smuzhiyun }
2065*4882a593Smuzhiyun 
cirrusfb_cleanup(struct fb_info * info)2066*4882a593Smuzhiyun static void cirrusfb_cleanup(struct fb_info *info)
2067*4882a593Smuzhiyun {
2068*4882a593Smuzhiyun 	struct cirrusfb_info *cinfo = info->par;
2069*4882a593Smuzhiyun 
2070*4882a593Smuzhiyun 	switch_monitor(cinfo, 0);
2071*4882a593Smuzhiyun 	unregister_framebuffer(info);
2072*4882a593Smuzhiyun 	fb_dealloc_cmap(&info->cmap);
2073*4882a593Smuzhiyun 	dev_dbg(info->device, "Framebuffer unregistered\n");
2074*4882a593Smuzhiyun 	cinfo->unmap(info);
2075*4882a593Smuzhiyun 	framebuffer_release(info);
2076*4882a593Smuzhiyun }
2077*4882a593Smuzhiyun 
2078*4882a593Smuzhiyun #ifdef CONFIG_PCI
cirrusfb_pci_register(struct pci_dev * pdev,const struct pci_device_id * ent)2079*4882a593Smuzhiyun static int cirrusfb_pci_register(struct pci_dev *pdev,
2080*4882a593Smuzhiyun 				 const struct pci_device_id *ent)
2081*4882a593Smuzhiyun {
2082*4882a593Smuzhiyun 	struct cirrusfb_info *cinfo;
2083*4882a593Smuzhiyun 	struct fb_info *info;
2084*4882a593Smuzhiyun 	unsigned long board_addr, board_size;
2085*4882a593Smuzhiyun 	int ret;
2086*4882a593Smuzhiyun 
2087*4882a593Smuzhiyun 	ret = pci_enable_device(pdev);
2088*4882a593Smuzhiyun 	if (ret < 0) {
2089*4882a593Smuzhiyun 		printk(KERN_ERR "cirrusfb: Cannot enable PCI device\n");
2090*4882a593Smuzhiyun 		goto err_out;
2091*4882a593Smuzhiyun 	}
2092*4882a593Smuzhiyun 
2093*4882a593Smuzhiyun 	info = framebuffer_alloc(sizeof(struct cirrusfb_info), &pdev->dev);
2094*4882a593Smuzhiyun 	if (!info) {
2095*4882a593Smuzhiyun 		ret = -ENOMEM;
2096*4882a593Smuzhiyun 		goto err_out;
2097*4882a593Smuzhiyun 	}
2098*4882a593Smuzhiyun 
2099*4882a593Smuzhiyun 	cinfo = info->par;
2100*4882a593Smuzhiyun 	cinfo->btype = (enum cirrus_board) ent->driver_data;
2101*4882a593Smuzhiyun 
2102*4882a593Smuzhiyun 	dev_dbg(info->device,
2103*4882a593Smuzhiyun 		" Found PCI device, base address 0 is 0x%Lx, btype set to %d\n",
2104*4882a593Smuzhiyun 		(unsigned long long)pdev->resource[0].start,  cinfo->btype);
2105*4882a593Smuzhiyun 	dev_dbg(info->device, " base address 1 is 0x%Lx\n",
2106*4882a593Smuzhiyun 		(unsigned long long)pdev->resource[1].start);
2107*4882a593Smuzhiyun 
2108*4882a593Smuzhiyun 	dev_dbg(info->device,
2109*4882a593Smuzhiyun 		"Attempt to get PCI info for Cirrus Graphics Card\n");
2110*4882a593Smuzhiyun 	get_pci_addrs(pdev, &board_addr, &info->fix.mmio_start);
2111*4882a593Smuzhiyun 	/* FIXME: this forces VGA.  alternatives? */
2112*4882a593Smuzhiyun 	cinfo->regbase = NULL;
2113*4882a593Smuzhiyun 	cinfo->laguna_mmio = ioremap(info->fix.mmio_start, 0x1000);
2114*4882a593Smuzhiyun 
2115*4882a593Smuzhiyun 	dev_dbg(info->device, "Board address: 0x%lx, register address: 0x%lx\n",
2116*4882a593Smuzhiyun 		board_addr, info->fix.mmio_start);
2117*4882a593Smuzhiyun 
2118*4882a593Smuzhiyun 	board_size = (cinfo->btype == BT_GD5480) ?
2119*4882a593Smuzhiyun 		32 * MB_ : cirrusfb_get_memsize(info, cinfo->regbase);
2120*4882a593Smuzhiyun 
2121*4882a593Smuzhiyun 	ret = pci_request_regions(pdev, "cirrusfb");
2122*4882a593Smuzhiyun 	if (ret < 0) {
2123*4882a593Smuzhiyun 		dev_err(info->device, "cannot reserve region 0x%lx, abort\n",
2124*4882a593Smuzhiyun 			board_addr);
2125*4882a593Smuzhiyun 		goto err_release_fb;
2126*4882a593Smuzhiyun 	}
2127*4882a593Smuzhiyun #if 0 /* if the system didn't claim this region, we would... */
2128*4882a593Smuzhiyun 	if (!request_mem_region(0xA0000, 65535, "cirrusfb")) {
2129*4882a593Smuzhiyun 		dev_err(info->device, "cannot reserve region 0x%lx, abort\n",
2130*4882a593Smuzhiyun 			0xA0000L);
2131*4882a593Smuzhiyun 		ret = -EBUSY;
2132*4882a593Smuzhiyun 		goto err_release_regions;
2133*4882a593Smuzhiyun 	}
2134*4882a593Smuzhiyun #endif
2135*4882a593Smuzhiyun 	if (request_region(0x3C0, 32, "cirrusfb"))
2136*4882a593Smuzhiyun 		release_io_ports = 1;
2137*4882a593Smuzhiyun 
2138*4882a593Smuzhiyun 	info->screen_base = ioremap(board_addr, board_size);
2139*4882a593Smuzhiyun 	if (!info->screen_base) {
2140*4882a593Smuzhiyun 		ret = -EIO;
2141*4882a593Smuzhiyun 		goto err_release_legacy;
2142*4882a593Smuzhiyun 	}
2143*4882a593Smuzhiyun 
2144*4882a593Smuzhiyun 	info->fix.smem_start = board_addr;
2145*4882a593Smuzhiyun 	info->screen_size = board_size;
2146*4882a593Smuzhiyun 	cinfo->unmap = cirrusfb_pci_unmap;
2147*4882a593Smuzhiyun 
2148*4882a593Smuzhiyun 	dev_info(info->device,
2149*4882a593Smuzhiyun 		 "Cirrus Logic chipset on PCI bus, RAM (%lu kB) at 0x%lx\n",
2150*4882a593Smuzhiyun 		 info->screen_size >> 10, board_addr);
2151*4882a593Smuzhiyun 	pci_set_drvdata(pdev, info);
2152*4882a593Smuzhiyun 
2153*4882a593Smuzhiyun 	ret = cirrusfb_register(info);
2154*4882a593Smuzhiyun 	if (!ret)
2155*4882a593Smuzhiyun 		return 0;
2156*4882a593Smuzhiyun 
2157*4882a593Smuzhiyun 	iounmap(info->screen_base);
2158*4882a593Smuzhiyun err_release_legacy:
2159*4882a593Smuzhiyun 	if (release_io_ports)
2160*4882a593Smuzhiyun 		release_region(0x3C0, 32);
2161*4882a593Smuzhiyun #if 0
2162*4882a593Smuzhiyun 	release_mem_region(0xA0000, 65535);
2163*4882a593Smuzhiyun err_release_regions:
2164*4882a593Smuzhiyun #endif
2165*4882a593Smuzhiyun 	pci_release_regions(pdev);
2166*4882a593Smuzhiyun err_release_fb:
2167*4882a593Smuzhiyun 	if (cinfo->laguna_mmio != NULL)
2168*4882a593Smuzhiyun 		iounmap(cinfo->laguna_mmio);
2169*4882a593Smuzhiyun 	framebuffer_release(info);
2170*4882a593Smuzhiyun err_out:
2171*4882a593Smuzhiyun 	return ret;
2172*4882a593Smuzhiyun }
2173*4882a593Smuzhiyun 
cirrusfb_pci_unregister(struct pci_dev * pdev)2174*4882a593Smuzhiyun static void cirrusfb_pci_unregister(struct pci_dev *pdev)
2175*4882a593Smuzhiyun {
2176*4882a593Smuzhiyun 	struct fb_info *info = pci_get_drvdata(pdev);
2177*4882a593Smuzhiyun 
2178*4882a593Smuzhiyun 	cirrusfb_cleanup(info);
2179*4882a593Smuzhiyun }
2180*4882a593Smuzhiyun 
2181*4882a593Smuzhiyun static struct pci_driver cirrusfb_pci_driver = {
2182*4882a593Smuzhiyun 	.name		= "cirrusfb",
2183*4882a593Smuzhiyun 	.id_table	= cirrusfb_pci_table,
2184*4882a593Smuzhiyun 	.probe		= cirrusfb_pci_register,
2185*4882a593Smuzhiyun 	.remove		= cirrusfb_pci_unregister,
2186*4882a593Smuzhiyun #ifdef CONFIG_PM
2187*4882a593Smuzhiyun #if 0
2188*4882a593Smuzhiyun 	.suspend	= cirrusfb_pci_suspend,
2189*4882a593Smuzhiyun 	.resume		= cirrusfb_pci_resume,
2190*4882a593Smuzhiyun #endif
2191*4882a593Smuzhiyun #endif
2192*4882a593Smuzhiyun };
2193*4882a593Smuzhiyun #endif /* CONFIG_PCI */
2194*4882a593Smuzhiyun 
2195*4882a593Smuzhiyun #ifdef CONFIG_ZORRO
cirrusfb_zorro_register(struct zorro_dev * z,const struct zorro_device_id * ent)2196*4882a593Smuzhiyun static int cirrusfb_zorro_register(struct zorro_dev *z,
2197*4882a593Smuzhiyun 				   const struct zorro_device_id *ent)
2198*4882a593Smuzhiyun {
2199*4882a593Smuzhiyun 	struct fb_info *info;
2200*4882a593Smuzhiyun 	int error;
2201*4882a593Smuzhiyun 	const struct zorrocl *zcl;
2202*4882a593Smuzhiyun 	enum cirrus_board btype;
2203*4882a593Smuzhiyun 	unsigned long regbase, ramsize, rambase;
2204*4882a593Smuzhiyun 	struct cirrusfb_info *cinfo;
2205*4882a593Smuzhiyun 
2206*4882a593Smuzhiyun 	info = framebuffer_alloc(sizeof(struct cirrusfb_info), &z->dev);
2207*4882a593Smuzhiyun 	if (!info)
2208*4882a593Smuzhiyun 		return -ENOMEM;
2209*4882a593Smuzhiyun 
2210*4882a593Smuzhiyun 	zcl = (const struct zorrocl *)ent->driver_data;
2211*4882a593Smuzhiyun 	btype = zcl->type;
2212*4882a593Smuzhiyun 	regbase = zorro_resource_start(z) + zcl->regoffset;
2213*4882a593Smuzhiyun 	ramsize = zcl->ramsize;
2214*4882a593Smuzhiyun 	if (ramsize) {
2215*4882a593Smuzhiyun 		rambase = zorro_resource_start(z) + zcl->ramoffset;
2216*4882a593Smuzhiyun 		if (zorro_resource_len(z) == 64 * MB_) {
2217*4882a593Smuzhiyun 			/* Quirk for 64 MiB Picasso IV */
2218*4882a593Smuzhiyun 			rambase += zcl->ramoffset;
2219*4882a593Smuzhiyun 		}
2220*4882a593Smuzhiyun 	} else {
2221*4882a593Smuzhiyun 		struct zorro_dev *ram = zorro_find_device(zcl->ramid, NULL);
2222*4882a593Smuzhiyun 		if (!ram || !zorro_resource_len(ram)) {
2223*4882a593Smuzhiyun 			dev_err(info->device, "No video RAM found\n");
2224*4882a593Smuzhiyun 			error = -ENODEV;
2225*4882a593Smuzhiyun 			goto err_release_fb;
2226*4882a593Smuzhiyun 		}
2227*4882a593Smuzhiyun 		rambase = zorro_resource_start(ram);
2228*4882a593Smuzhiyun 		ramsize = zorro_resource_len(ram);
2229*4882a593Smuzhiyun 		if (zcl->ramid2 &&
2230*4882a593Smuzhiyun 		    (ram = zorro_find_device(zcl->ramid2, NULL))) {
2231*4882a593Smuzhiyun 			if (zorro_resource_start(ram) != rambase + ramsize) {
2232*4882a593Smuzhiyun 				dev_warn(info->device,
2233*4882a593Smuzhiyun 					 "Skipping non-contiguous RAM at %pR\n",
2234*4882a593Smuzhiyun 					 &ram->resource);
2235*4882a593Smuzhiyun 			} else {
2236*4882a593Smuzhiyun 				ramsize += zorro_resource_len(ram);
2237*4882a593Smuzhiyun 			}
2238*4882a593Smuzhiyun 		}
2239*4882a593Smuzhiyun 	}
2240*4882a593Smuzhiyun 
2241*4882a593Smuzhiyun 	dev_info(info->device,
2242*4882a593Smuzhiyun 		 "%s board detected, REG at 0x%lx, %lu MiB RAM at 0x%lx\n",
2243*4882a593Smuzhiyun 		 cirrusfb_board_info[btype].name, regbase, ramsize / MB_,
2244*4882a593Smuzhiyun 		 rambase);
2245*4882a593Smuzhiyun 
2246*4882a593Smuzhiyun 	if (!zorro_request_device(z, "cirrusfb")) {
2247*4882a593Smuzhiyun 		dev_err(info->device, "Cannot reserve %pR\n", &z->resource);
2248*4882a593Smuzhiyun 		error = -EBUSY;
2249*4882a593Smuzhiyun 		goto err_release_fb;
2250*4882a593Smuzhiyun 	}
2251*4882a593Smuzhiyun 
2252*4882a593Smuzhiyun 	cinfo = info->par;
2253*4882a593Smuzhiyun 	cinfo->btype = btype;
2254*4882a593Smuzhiyun 
2255*4882a593Smuzhiyun 	info->fix.mmio_start = regbase;
2256*4882a593Smuzhiyun 	cinfo->regbase = regbase > 16 * MB_ ? ioremap(regbase, 64 * 1024)
2257*4882a593Smuzhiyun 					    : ZTWO_VADDR(regbase);
2258*4882a593Smuzhiyun 	if (!cinfo->regbase) {
2259*4882a593Smuzhiyun 		dev_err(info->device, "Cannot map registers\n");
2260*4882a593Smuzhiyun 		error = -EIO;
2261*4882a593Smuzhiyun 		goto err_release_dev;
2262*4882a593Smuzhiyun 	}
2263*4882a593Smuzhiyun 
2264*4882a593Smuzhiyun 	info->fix.smem_start = rambase;
2265*4882a593Smuzhiyun 	info->screen_size = ramsize;
2266*4882a593Smuzhiyun 	info->screen_base = rambase > 16 * MB_ ? ioremap(rambase, ramsize)
2267*4882a593Smuzhiyun 					       : ZTWO_VADDR(rambase);
2268*4882a593Smuzhiyun 	if (!info->screen_base) {
2269*4882a593Smuzhiyun 		dev_err(info->device, "Cannot map video RAM\n");
2270*4882a593Smuzhiyun 		error = -EIO;
2271*4882a593Smuzhiyun 		goto err_unmap_reg;
2272*4882a593Smuzhiyun 	}
2273*4882a593Smuzhiyun 
2274*4882a593Smuzhiyun 	cinfo->unmap = cirrusfb_zorro_unmap;
2275*4882a593Smuzhiyun 
2276*4882a593Smuzhiyun 	dev_info(info->device,
2277*4882a593Smuzhiyun 		 "Cirrus Logic chipset on Zorro bus, RAM (%lu MiB) at 0x%lx\n",
2278*4882a593Smuzhiyun 		 ramsize / MB_, rambase);
2279*4882a593Smuzhiyun 
2280*4882a593Smuzhiyun 	/* MCLK select etc. */
2281*4882a593Smuzhiyun 	if (cirrusfb_board_info[btype].init_sr1f)
2282*4882a593Smuzhiyun 		vga_wseq(cinfo->regbase, CL_SEQR1F,
2283*4882a593Smuzhiyun 			 cirrusfb_board_info[btype].sr1f);
2284*4882a593Smuzhiyun 
2285*4882a593Smuzhiyun 	error = cirrusfb_register(info);
2286*4882a593Smuzhiyun 	if (error) {
2287*4882a593Smuzhiyun 		dev_err(info->device, "Failed to register device, error %d\n",
2288*4882a593Smuzhiyun 			error);
2289*4882a593Smuzhiyun 		goto err_unmap_ram;
2290*4882a593Smuzhiyun 	}
2291*4882a593Smuzhiyun 
2292*4882a593Smuzhiyun 	zorro_set_drvdata(z, info);
2293*4882a593Smuzhiyun 	return 0;
2294*4882a593Smuzhiyun 
2295*4882a593Smuzhiyun err_unmap_ram:
2296*4882a593Smuzhiyun 	if (rambase > 16 * MB_)
2297*4882a593Smuzhiyun 		iounmap(info->screen_base);
2298*4882a593Smuzhiyun 
2299*4882a593Smuzhiyun err_unmap_reg:
2300*4882a593Smuzhiyun 	if (regbase > 16 * MB_)
2301*4882a593Smuzhiyun 		iounmap(cinfo->regbase);
2302*4882a593Smuzhiyun err_release_dev:
2303*4882a593Smuzhiyun 	zorro_release_device(z);
2304*4882a593Smuzhiyun err_release_fb:
2305*4882a593Smuzhiyun 	framebuffer_release(info);
2306*4882a593Smuzhiyun 	return error;
2307*4882a593Smuzhiyun }
2308*4882a593Smuzhiyun 
cirrusfb_zorro_unregister(struct zorro_dev * z)2309*4882a593Smuzhiyun void cirrusfb_zorro_unregister(struct zorro_dev *z)
2310*4882a593Smuzhiyun {
2311*4882a593Smuzhiyun 	struct fb_info *info = zorro_get_drvdata(z);
2312*4882a593Smuzhiyun 
2313*4882a593Smuzhiyun 	cirrusfb_cleanup(info);
2314*4882a593Smuzhiyun 	zorro_set_drvdata(z, NULL);
2315*4882a593Smuzhiyun }
2316*4882a593Smuzhiyun 
2317*4882a593Smuzhiyun static struct zorro_driver cirrusfb_zorro_driver = {
2318*4882a593Smuzhiyun 	.name		= "cirrusfb",
2319*4882a593Smuzhiyun 	.id_table	= cirrusfb_zorro_table,
2320*4882a593Smuzhiyun 	.probe		= cirrusfb_zorro_register,
2321*4882a593Smuzhiyun 	.remove		= cirrusfb_zorro_unregister,
2322*4882a593Smuzhiyun };
2323*4882a593Smuzhiyun #endif /* CONFIG_ZORRO */
2324*4882a593Smuzhiyun 
2325*4882a593Smuzhiyun #ifndef MODULE
cirrusfb_setup(char * options)2326*4882a593Smuzhiyun static int __init cirrusfb_setup(char *options)
2327*4882a593Smuzhiyun {
2328*4882a593Smuzhiyun 	char *this_opt;
2329*4882a593Smuzhiyun 
2330*4882a593Smuzhiyun 	if (!options || !*options)
2331*4882a593Smuzhiyun 		return 0;
2332*4882a593Smuzhiyun 
2333*4882a593Smuzhiyun 	while ((this_opt = strsep(&options, ",")) != NULL) {
2334*4882a593Smuzhiyun 		if (!*this_opt)
2335*4882a593Smuzhiyun 			continue;
2336*4882a593Smuzhiyun 
2337*4882a593Smuzhiyun 		if (!strcmp(this_opt, "noaccel"))
2338*4882a593Smuzhiyun 			noaccel = 1;
2339*4882a593Smuzhiyun 		else if (!strncmp(this_opt, "mode:", 5))
2340*4882a593Smuzhiyun 			mode_option = this_opt + 5;
2341*4882a593Smuzhiyun 		else
2342*4882a593Smuzhiyun 			mode_option = this_opt;
2343*4882a593Smuzhiyun 	}
2344*4882a593Smuzhiyun 	return 0;
2345*4882a593Smuzhiyun }
2346*4882a593Smuzhiyun #endif
2347*4882a593Smuzhiyun 
2348*4882a593Smuzhiyun     /*
2349*4882a593Smuzhiyun      *  Modularization
2350*4882a593Smuzhiyun      */
2351*4882a593Smuzhiyun 
2352*4882a593Smuzhiyun MODULE_AUTHOR("Copyright 1999,2000 Jeff Garzik <jgarzik@pobox.com>");
2353*4882a593Smuzhiyun MODULE_DESCRIPTION("Accelerated FBDev driver for Cirrus Logic chips");
2354*4882a593Smuzhiyun MODULE_LICENSE("GPL");
2355*4882a593Smuzhiyun 
cirrusfb_init(void)2356*4882a593Smuzhiyun static int __init cirrusfb_init(void)
2357*4882a593Smuzhiyun {
2358*4882a593Smuzhiyun 	int error = 0;
2359*4882a593Smuzhiyun 
2360*4882a593Smuzhiyun #ifndef MODULE
2361*4882a593Smuzhiyun 	char *option = NULL;
2362*4882a593Smuzhiyun 
2363*4882a593Smuzhiyun 	if (fb_get_options("cirrusfb", &option))
2364*4882a593Smuzhiyun 		return -ENODEV;
2365*4882a593Smuzhiyun 	cirrusfb_setup(option);
2366*4882a593Smuzhiyun #endif
2367*4882a593Smuzhiyun 
2368*4882a593Smuzhiyun #ifdef CONFIG_ZORRO
2369*4882a593Smuzhiyun 	error |= zorro_register_driver(&cirrusfb_zorro_driver);
2370*4882a593Smuzhiyun #endif
2371*4882a593Smuzhiyun #ifdef CONFIG_PCI
2372*4882a593Smuzhiyun 	error |= pci_register_driver(&cirrusfb_pci_driver);
2373*4882a593Smuzhiyun #endif
2374*4882a593Smuzhiyun 	return error;
2375*4882a593Smuzhiyun }
2376*4882a593Smuzhiyun 
cirrusfb_exit(void)2377*4882a593Smuzhiyun static void __exit cirrusfb_exit(void)
2378*4882a593Smuzhiyun {
2379*4882a593Smuzhiyun #ifdef CONFIG_PCI
2380*4882a593Smuzhiyun 	pci_unregister_driver(&cirrusfb_pci_driver);
2381*4882a593Smuzhiyun #endif
2382*4882a593Smuzhiyun #ifdef CONFIG_ZORRO
2383*4882a593Smuzhiyun 	zorro_unregister_driver(&cirrusfb_zorro_driver);
2384*4882a593Smuzhiyun #endif
2385*4882a593Smuzhiyun }
2386*4882a593Smuzhiyun 
2387*4882a593Smuzhiyun module_init(cirrusfb_init);
2388*4882a593Smuzhiyun 
2389*4882a593Smuzhiyun module_param(mode_option, charp, 0);
2390*4882a593Smuzhiyun MODULE_PARM_DESC(mode_option, "Initial video mode e.g. '648x480-8@60'");
2391*4882a593Smuzhiyun module_param(noaccel, bool, 0);
2392*4882a593Smuzhiyun MODULE_PARM_DESC(noaccel, "Disable acceleration");
2393*4882a593Smuzhiyun 
2394*4882a593Smuzhiyun #ifdef MODULE
2395*4882a593Smuzhiyun module_exit(cirrusfb_exit);
2396*4882a593Smuzhiyun #endif
2397*4882a593Smuzhiyun 
2398*4882a593Smuzhiyun /**********************************************************************/
2399*4882a593Smuzhiyun /* about the following functions - I have used the same names for the */
2400*4882a593Smuzhiyun /* functions as Markus Wild did in his Retina driver for NetBSD as    */
2401*4882a593Smuzhiyun /* they just made sense for this purpose. Apart from that, I wrote    */
2402*4882a593Smuzhiyun /* these functions myself.					    */
2403*4882a593Smuzhiyun /**********************************************************************/
2404*4882a593Smuzhiyun 
2405*4882a593Smuzhiyun /*** WGen() - write into one of the external/general registers ***/
WGen(const struct cirrusfb_info * cinfo,int regnum,unsigned char val)2406*4882a593Smuzhiyun static void WGen(const struct cirrusfb_info *cinfo,
2407*4882a593Smuzhiyun 		  int regnum, unsigned char val)
2408*4882a593Smuzhiyun {
2409*4882a593Smuzhiyun 	unsigned long regofs = 0;
2410*4882a593Smuzhiyun 
2411*4882a593Smuzhiyun 	if (cinfo->btype == BT_PICASSO) {
2412*4882a593Smuzhiyun 		/* Picasso II specific hack */
2413*4882a593Smuzhiyun /*	      if (regnum == VGA_PEL_IR || regnum == VGA_PEL_D ||
2414*4882a593Smuzhiyun 		  regnum == CL_VSSM2) */
2415*4882a593Smuzhiyun 		if (regnum == VGA_PEL_IR || regnum == VGA_PEL_D)
2416*4882a593Smuzhiyun 			regofs = 0xfff;
2417*4882a593Smuzhiyun 	}
2418*4882a593Smuzhiyun 
2419*4882a593Smuzhiyun 	vga_w(cinfo->regbase, regofs + regnum, val);
2420*4882a593Smuzhiyun }
2421*4882a593Smuzhiyun 
2422*4882a593Smuzhiyun /*** RGen() - read out one of the external/general registers ***/
RGen(const struct cirrusfb_info * cinfo,int regnum)2423*4882a593Smuzhiyun static unsigned char RGen(const struct cirrusfb_info *cinfo, int regnum)
2424*4882a593Smuzhiyun {
2425*4882a593Smuzhiyun 	unsigned long regofs = 0;
2426*4882a593Smuzhiyun 
2427*4882a593Smuzhiyun 	if (cinfo->btype == BT_PICASSO) {
2428*4882a593Smuzhiyun 		/* Picasso II specific hack */
2429*4882a593Smuzhiyun /*	      if (regnum == VGA_PEL_IR || regnum == VGA_PEL_D ||
2430*4882a593Smuzhiyun 		  regnum == CL_VSSM2) */
2431*4882a593Smuzhiyun 		if (regnum == VGA_PEL_IR || regnum == VGA_PEL_D)
2432*4882a593Smuzhiyun 			regofs = 0xfff;
2433*4882a593Smuzhiyun 	}
2434*4882a593Smuzhiyun 
2435*4882a593Smuzhiyun 	return vga_r(cinfo->regbase, regofs + regnum);
2436*4882a593Smuzhiyun }
2437*4882a593Smuzhiyun 
2438*4882a593Smuzhiyun /*** AttrOn() - turn on VideoEnable for Attribute controller ***/
AttrOn(const struct cirrusfb_info * cinfo)2439*4882a593Smuzhiyun static void AttrOn(const struct cirrusfb_info *cinfo)
2440*4882a593Smuzhiyun {
2441*4882a593Smuzhiyun 	assert(cinfo != NULL);
2442*4882a593Smuzhiyun 
2443*4882a593Smuzhiyun 	if (vga_rcrt(cinfo->regbase, CL_CRT24) & 0x80) {
2444*4882a593Smuzhiyun 		/* if we're just in "write value" mode, write back the */
2445*4882a593Smuzhiyun 		/* same value as before to not modify anything */
2446*4882a593Smuzhiyun 		vga_w(cinfo->regbase, VGA_ATT_IW,
2447*4882a593Smuzhiyun 		      vga_r(cinfo->regbase, VGA_ATT_R));
2448*4882a593Smuzhiyun 	}
2449*4882a593Smuzhiyun 	/* turn on video bit */
2450*4882a593Smuzhiyun /*      vga_w(cinfo->regbase, VGA_ATT_IW, 0x20); */
2451*4882a593Smuzhiyun 	vga_w(cinfo->regbase, VGA_ATT_IW, 0x33);
2452*4882a593Smuzhiyun 
2453*4882a593Smuzhiyun 	/* dummy write on Reg0 to be on "write index" mode next time */
2454*4882a593Smuzhiyun 	vga_w(cinfo->regbase, VGA_ATT_IW, 0x00);
2455*4882a593Smuzhiyun }
2456*4882a593Smuzhiyun 
2457*4882a593Smuzhiyun /*** WHDR() - write into the Hidden DAC register ***/
2458*4882a593Smuzhiyun /* as the HDR is the only extension register that requires special treatment
2459*4882a593Smuzhiyun  * (the other extension registers are accessible just like the "ordinary"
2460*4882a593Smuzhiyun  * registers of their functional group) here is a specialized routine for
2461*4882a593Smuzhiyun  * accessing the HDR
2462*4882a593Smuzhiyun  */
WHDR(const struct cirrusfb_info * cinfo,unsigned char val)2463*4882a593Smuzhiyun static void WHDR(const struct cirrusfb_info *cinfo, unsigned char val)
2464*4882a593Smuzhiyun {
2465*4882a593Smuzhiyun 	unsigned char dummy;
2466*4882a593Smuzhiyun 
2467*4882a593Smuzhiyun 	if (is_laguna(cinfo))
2468*4882a593Smuzhiyun 		return;
2469*4882a593Smuzhiyun 	if (cinfo->btype == BT_PICASSO) {
2470*4882a593Smuzhiyun 		/* Klaus' hint for correct access to HDR on some boards */
2471*4882a593Smuzhiyun 		/* first write 0 to pixel mask (3c6) */
2472*4882a593Smuzhiyun 		WGen(cinfo, VGA_PEL_MSK, 0x00);
2473*4882a593Smuzhiyun 		udelay(200);
2474*4882a593Smuzhiyun 		/* next read dummy from pixel address (3c8) */
2475*4882a593Smuzhiyun 		dummy = RGen(cinfo, VGA_PEL_IW);
2476*4882a593Smuzhiyun 		udelay(200);
2477*4882a593Smuzhiyun 	}
2478*4882a593Smuzhiyun 	/* now do the usual stuff to access the HDR */
2479*4882a593Smuzhiyun 
2480*4882a593Smuzhiyun 	dummy = RGen(cinfo, VGA_PEL_MSK);
2481*4882a593Smuzhiyun 	udelay(200);
2482*4882a593Smuzhiyun 	dummy = RGen(cinfo, VGA_PEL_MSK);
2483*4882a593Smuzhiyun 	udelay(200);
2484*4882a593Smuzhiyun 	dummy = RGen(cinfo, VGA_PEL_MSK);
2485*4882a593Smuzhiyun 	udelay(200);
2486*4882a593Smuzhiyun 	dummy = RGen(cinfo, VGA_PEL_MSK);
2487*4882a593Smuzhiyun 	udelay(200);
2488*4882a593Smuzhiyun 
2489*4882a593Smuzhiyun 	WGen(cinfo, VGA_PEL_MSK, val);
2490*4882a593Smuzhiyun 	udelay(200);
2491*4882a593Smuzhiyun 
2492*4882a593Smuzhiyun 	if (cinfo->btype == BT_PICASSO) {
2493*4882a593Smuzhiyun 		/* now first reset HDR access counter */
2494*4882a593Smuzhiyun 		dummy = RGen(cinfo, VGA_PEL_IW);
2495*4882a593Smuzhiyun 		udelay(200);
2496*4882a593Smuzhiyun 
2497*4882a593Smuzhiyun 		/* and at the end, restore the mask value */
2498*4882a593Smuzhiyun 		/* ## is this mask always 0xff? */
2499*4882a593Smuzhiyun 		WGen(cinfo, VGA_PEL_MSK, 0xff);
2500*4882a593Smuzhiyun 		udelay(200);
2501*4882a593Smuzhiyun 	}
2502*4882a593Smuzhiyun }
2503*4882a593Smuzhiyun 
2504*4882a593Smuzhiyun /*** WSFR() - write to the "special function register" (SFR) ***/
WSFR(struct cirrusfb_info * cinfo,unsigned char val)2505*4882a593Smuzhiyun static void WSFR(struct cirrusfb_info *cinfo, unsigned char val)
2506*4882a593Smuzhiyun {
2507*4882a593Smuzhiyun #ifdef CONFIG_ZORRO
2508*4882a593Smuzhiyun 	assert(cinfo->regbase != NULL);
2509*4882a593Smuzhiyun 	cinfo->SFR = val;
2510*4882a593Smuzhiyun 	z_writeb(val, cinfo->regbase + 0x8000);
2511*4882a593Smuzhiyun #endif
2512*4882a593Smuzhiyun }
2513*4882a593Smuzhiyun 
2514*4882a593Smuzhiyun /* The Picasso has a second register for switching the monitor bit */
WSFR2(struct cirrusfb_info * cinfo,unsigned char val)2515*4882a593Smuzhiyun static void WSFR2(struct cirrusfb_info *cinfo, unsigned char val)
2516*4882a593Smuzhiyun {
2517*4882a593Smuzhiyun #ifdef CONFIG_ZORRO
2518*4882a593Smuzhiyun 	/* writing an arbitrary value to this one causes the monitor switcher */
2519*4882a593Smuzhiyun 	/* to flip to Amiga display */
2520*4882a593Smuzhiyun 	assert(cinfo->regbase != NULL);
2521*4882a593Smuzhiyun 	cinfo->SFR = val;
2522*4882a593Smuzhiyun 	z_writeb(val, cinfo->regbase + 0x9000);
2523*4882a593Smuzhiyun #endif
2524*4882a593Smuzhiyun }
2525*4882a593Smuzhiyun 
2526*4882a593Smuzhiyun /*** WClut - set CLUT entry (range: 0..63) ***/
WClut(struct cirrusfb_info * cinfo,unsigned char regnum,unsigned char red,unsigned char green,unsigned char blue)2527*4882a593Smuzhiyun static void WClut(struct cirrusfb_info *cinfo, unsigned char regnum, unsigned char red,
2528*4882a593Smuzhiyun 	    unsigned char green, unsigned char blue)
2529*4882a593Smuzhiyun {
2530*4882a593Smuzhiyun 	unsigned int data = VGA_PEL_D;
2531*4882a593Smuzhiyun 
2532*4882a593Smuzhiyun 	/* address write mode register is not translated.. */
2533*4882a593Smuzhiyun 	vga_w(cinfo->regbase, VGA_PEL_IW, regnum);
2534*4882a593Smuzhiyun 
2535*4882a593Smuzhiyun 	if (cinfo->btype == BT_PICASSO || cinfo->btype == BT_PICASSO4 ||
2536*4882a593Smuzhiyun 	    cinfo->btype == BT_ALPINE || cinfo->btype == BT_GD5480 ||
2537*4882a593Smuzhiyun 	    cinfo->btype == BT_SD64 || is_laguna(cinfo)) {
2538*4882a593Smuzhiyun 		/* but DAC data register IS, at least for Picasso II */
2539*4882a593Smuzhiyun 		if (cinfo->btype == BT_PICASSO)
2540*4882a593Smuzhiyun 			data += 0xfff;
2541*4882a593Smuzhiyun 		vga_w(cinfo->regbase, data, red);
2542*4882a593Smuzhiyun 		vga_w(cinfo->regbase, data, green);
2543*4882a593Smuzhiyun 		vga_w(cinfo->regbase, data, blue);
2544*4882a593Smuzhiyun 	} else {
2545*4882a593Smuzhiyun 		vga_w(cinfo->regbase, data, blue);
2546*4882a593Smuzhiyun 		vga_w(cinfo->regbase, data, green);
2547*4882a593Smuzhiyun 		vga_w(cinfo->regbase, data, red);
2548*4882a593Smuzhiyun 	}
2549*4882a593Smuzhiyun }
2550*4882a593Smuzhiyun 
2551*4882a593Smuzhiyun #if 0
2552*4882a593Smuzhiyun /*** RClut - read CLUT entry (range 0..63) ***/
2553*4882a593Smuzhiyun static void RClut(struct cirrusfb_info *cinfo, unsigned char regnum, unsigned char *red,
2554*4882a593Smuzhiyun 	    unsigned char *green, unsigned char *blue)
2555*4882a593Smuzhiyun {
2556*4882a593Smuzhiyun 	unsigned int data = VGA_PEL_D;
2557*4882a593Smuzhiyun 
2558*4882a593Smuzhiyun 	vga_w(cinfo->regbase, VGA_PEL_IR, regnum);
2559*4882a593Smuzhiyun 
2560*4882a593Smuzhiyun 	if (cinfo->btype == BT_PICASSO || cinfo->btype == BT_PICASSO4 ||
2561*4882a593Smuzhiyun 	    cinfo->btype == BT_ALPINE || cinfo->btype == BT_GD5480) {
2562*4882a593Smuzhiyun 		if (cinfo->btype == BT_PICASSO)
2563*4882a593Smuzhiyun 			data += 0xfff;
2564*4882a593Smuzhiyun 		*red = vga_r(cinfo->regbase, data);
2565*4882a593Smuzhiyun 		*green = vga_r(cinfo->regbase, data);
2566*4882a593Smuzhiyun 		*blue = vga_r(cinfo->regbase, data);
2567*4882a593Smuzhiyun 	} else {
2568*4882a593Smuzhiyun 		*blue = vga_r(cinfo->regbase, data);
2569*4882a593Smuzhiyun 		*green = vga_r(cinfo->regbase, data);
2570*4882a593Smuzhiyun 		*red = vga_r(cinfo->regbase, data);
2571*4882a593Smuzhiyun 	}
2572*4882a593Smuzhiyun }
2573*4882a593Smuzhiyun #endif
2574*4882a593Smuzhiyun 
2575*4882a593Smuzhiyun /*******************************************************************
2576*4882a593Smuzhiyun 	cirrusfb_WaitBLT()
2577*4882a593Smuzhiyun 
2578*4882a593Smuzhiyun 	Wait for the BitBLT engine to complete a possible earlier job
2579*4882a593Smuzhiyun *********************************************************************/
2580*4882a593Smuzhiyun 
2581*4882a593Smuzhiyun /* FIXME: use interrupts instead */
cirrusfb_WaitBLT(u8 __iomem * regbase)2582*4882a593Smuzhiyun static void cirrusfb_WaitBLT(u8 __iomem *regbase)
2583*4882a593Smuzhiyun {
2584*4882a593Smuzhiyun 	while (vga_rgfx(regbase, CL_GR31) & 0x08)
2585*4882a593Smuzhiyun 		cpu_relax();
2586*4882a593Smuzhiyun }
2587*4882a593Smuzhiyun 
2588*4882a593Smuzhiyun /*******************************************************************
2589*4882a593Smuzhiyun 	cirrusfb_BitBLT()
2590*4882a593Smuzhiyun 
2591*4882a593Smuzhiyun 	perform accelerated "scrolling"
2592*4882a593Smuzhiyun ********************************************************************/
2593*4882a593Smuzhiyun 
cirrusfb_set_blitter(u8 __iomem * regbase,u_short nwidth,u_short nheight,u_long nsrc,u_long ndest,u_short bltmode,u_short line_length)2594*4882a593Smuzhiyun static void cirrusfb_set_blitter(u8 __iomem *regbase,
2595*4882a593Smuzhiyun 			    u_short nwidth, u_short nheight,
2596*4882a593Smuzhiyun 			    u_long nsrc, u_long ndest,
2597*4882a593Smuzhiyun 			    u_short bltmode, u_short line_length)
2598*4882a593Smuzhiyun 
2599*4882a593Smuzhiyun {
2600*4882a593Smuzhiyun 	/* pitch: set to line_length */
2601*4882a593Smuzhiyun 	/* dest pitch low */
2602*4882a593Smuzhiyun 	vga_wgfx(regbase, CL_GR24, line_length & 0xff);
2603*4882a593Smuzhiyun 	/* dest pitch hi */
2604*4882a593Smuzhiyun 	vga_wgfx(regbase, CL_GR25, line_length >> 8);
2605*4882a593Smuzhiyun 	/* source pitch low */
2606*4882a593Smuzhiyun 	vga_wgfx(regbase, CL_GR26, line_length & 0xff);
2607*4882a593Smuzhiyun 	/* source pitch hi */
2608*4882a593Smuzhiyun 	vga_wgfx(regbase, CL_GR27, line_length >> 8);
2609*4882a593Smuzhiyun 
2610*4882a593Smuzhiyun 	/* BLT width: actual number of pixels - 1 */
2611*4882a593Smuzhiyun 	/* BLT width low */
2612*4882a593Smuzhiyun 	vga_wgfx(regbase, CL_GR20, nwidth & 0xff);
2613*4882a593Smuzhiyun 	/* BLT width hi */
2614*4882a593Smuzhiyun 	vga_wgfx(regbase, CL_GR21, nwidth >> 8);
2615*4882a593Smuzhiyun 
2616*4882a593Smuzhiyun 	/* BLT height: actual number of lines -1 */
2617*4882a593Smuzhiyun 	/* BLT height low */
2618*4882a593Smuzhiyun 	vga_wgfx(regbase, CL_GR22, nheight & 0xff);
2619*4882a593Smuzhiyun 	/* BLT width hi */
2620*4882a593Smuzhiyun 	vga_wgfx(regbase, CL_GR23, nheight >> 8);
2621*4882a593Smuzhiyun 
2622*4882a593Smuzhiyun 	/* BLT destination */
2623*4882a593Smuzhiyun 	/* BLT dest low */
2624*4882a593Smuzhiyun 	vga_wgfx(regbase, CL_GR28, (u_char) (ndest & 0xff));
2625*4882a593Smuzhiyun 	/* BLT dest mid */
2626*4882a593Smuzhiyun 	vga_wgfx(regbase, CL_GR29, (u_char) (ndest >> 8));
2627*4882a593Smuzhiyun 	/* BLT dest hi */
2628*4882a593Smuzhiyun 	vga_wgfx(regbase, CL_GR2A, (u_char) (ndest >> 16));
2629*4882a593Smuzhiyun 
2630*4882a593Smuzhiyun 	/* BLT source */
2631*4882a593Smuzhiyun 	/* BLT src low */
2632*4882a593Smuzhiyun 	vga_wgfx(regbase, CL_GR2C, (u_char) (nsrc & 0xff));
2633*4882a593Smuzhiyun 	/* BLT src mid */
2634*4882a593Smuzhiyun 	vga_wgfx(regbase, CL_GR2D, (u_char) (nsrc >> 8));
2635*4882a593Smuzhiyun 	/* BLT src hi */
2636*4882a593Smuzhiyun 	vga_wgfx(regbase, CL_GR2E, (u_char) (nsrc >> 16));
2637*4882a593Smuzhiyun 
2638*4882a593Smuzhiyun 	/* BLT mode */
2639*4882a593Smuzhiyun 	vga_wgfx(regbase, CL_GR30, bltmode);	/* BLT mode */
2640*4882a593Smuzhiyun 
2641*4882a593Smuzhiyun 	/* BLT ROP: SrcCopy */
2642*4882a593Smuzhiyun 	vga_wgfx(regbase, CL_GR32, 0x0d);	/* BLT ROP */
2643*4882a593Smuzhiyun 
2644*4882a593Smuzhiyun 	/* and finally: GO! */
2645*4882a593Smuzhiyun 	vga_wgfx(regbase, CL_GR31, 0x02);	/* BLT Start/status */
2646*4882a593Smuzhiyun }
2647*4882a593Smuzhiyun 
2648*4882a593Smuzhiyun /*******************************************************************
2649*4882a593Smuzhiyun 	cirrusfb_BitBLT()
2650*4882a593Smuzhiyun 
2651*4882a593Smuzhiyun 	perform accelerated "scrolling"
2652*4882a593Smuzhiyun ********************************************************************/
2653*4882a593Smuzhiyun 
cirrusfb_BitBLT(u8 __iomem * regbase,int bits_per_pixel,u_short curx,u_short cury,u_short destx,u_short desty,u_short width,u_short height,u_short line_length)2654*4882a593Smuzhiyun static void cirrusfb_BitBLT(u8 __iomem *regbase, int bits_per_pixel,
2655*4882a593Smuzhiyun 			    u_short curx, u_short cury,
2656*4882a593Smuzhiyun 			    u_short destx, u_short desty,
2657*4882a593Smuzhiyun 			    u_short width, u_short height,
2658*4882a593Smuzhiyun 			    u_short line_length)
2659*4882a593Smuzhiyun {
2660*4882a593Smuzhiyun 	u_short nwidth = width - 1;
2661*4882a593Smuzhiyun 	u_short nheight = height - 1;
2662*4882a593Smuzhiyun 	u_long nsrc, ndest;
2663*4882a593Smuzhiyun 	u_char bltmode;
2664*4882a593Smuzhiyun 
2665*4882a593Smuzhiyun 	bltmode = 0x00;
2666*4882a593Smuzhiyun 	/* if source adr < dest addr, do the Blt backwards */
2667*4882a593Smuzhiyun 	if (cury <= desty) {
2668*4882a593Smuzhiyun 		if (cury == desty) {
2669*4882a593Smuzhiyun 			/* if src and dest are on the same line, check x */
2670*4882a593Smuzhiyun 			if (curx < destx)
2671*4882a593Smuzhiyun 				bltmode |= 0x01;
2672*4882a593Smuzhiyun 		} else
2673*4882a593Smuzhiyun 			bltmode |= 0x01;
2674*4882a593Smuzhiyun 	}
2675*4882a593Smuzhiyun 	/* standard case: forward blitting */
2676*4882a593Smuzhiyun 	nsrc = (cury * line_length) + curx;
2677*4882a593Smuzhiyun 	ndest = (desty * line_length) + destx;
2678*4882a593Smuzhiyun 	if (bltmode) {
2679*4882a593Smuzhiyun 		/* this means start addresses are at the end,
2680*4882a593Smuzhiyun 		 * counting backwards
2681*4882a593Smuzhiyun 		 */
2682*4882a593Smuzhiyun 		nsrc += nheight * line_length + nwidth;
2683*4882a593Smuzhiyun 		ndest += nheight * line_length + nwidth;
2684*4882a593Smuzhiyun 	}
2685*4882a593Smuzhiyun 
2686*4882a593Smuzhiyun 	cirrusfb_WaitBLT(regbase);
2687*4882a593Smuzhiyun 
2688*4882a593Smuzhiyun 	cirrusfb_set_blitter(regbase, nwidth, nheight,
2689*4882a593Smuzhiyun 			    nsrc, ndest, bltmode, line_length);
2690*4882a593Smuzhiyun }
2691*4882a593Smuzhiyun 
2692*4882a593Smuzhiyun /*******************************************************************
2693*4882a593Smuzhiyun 	cirrusfb_RectFill()
2694*4882a593Smuzhiyun 
2695*4882a593Smuzhiyun 	perform accelerated rectangle fill
2696*4882a593Smuzhiyun ********************************************************************/
2697*4882a593Smuzhiyun 
cirrusfb_RectFill(u8 __iomem * regbase,int bits_per_pixel,u_short x,u_short y,u_short width,u_short height,u32 fg_color,u32 bg_color,u_short line_length,u_char blitmode)2698*4882a593Smuzhiyun static void cirrusfb_RectFill(u8 __iomem *regbase, int bits_per_pixel,
2699*4882a593Smuzhiyun 		     u_short x, u_short y, u_short width, u_short height,
2700*4882a593Smuzhiyun 		     u32 fg_color, u32 bg_color, u_short line_length,
2701*4882a593Smuzhiyun 		     u_char blitmode)
2702*4882a593Smuzhiyun {
2703*4882a593Smuzhiyun 	u_long ndest = (y * line_length) + x;
2704*4882a593Smuzhiyun 	u_char op;
2705*4882a593Smuzhiyun 
2706*4882a593Smuzhiyun 	cirrusfb_WaitBLT(regbase);
2707*4882a593Smuzhiyun 
2708*4882a593Smuzhiyun 	/* This is a ColorExpand Blt, using the */
2709*4882a593Smuzhiyun 	/* same color for foreground and background */
2710*4882a593Smuzhiyun 	vga_wgfx(regbase, VGA_GFX_SR_VALUE, bg_color);
2711*4882a593Smuzhiyun 	vga_wgfx(regbase, VGA_GFX_SR_ENABLE, fg_color);
2712*4882a593Smuzhiyun 
2713*4882a593Smuzhiyun 	op = 0x80;
2714*4882a593Smuzhiyun 	if (bits_per_pixel >= 16) {
2715*4882a593Smuzhiyun 		vga_wgfx(regbase, CL_GR10, bg_color >> 8);
2716*4882a593Smuzhiyun 		vga_wgfx(regbase, CL_GR11, fg_color >> 8);
2717*4882a593Smuzhiyun 		op = 0x90;
2718*4882a593Smuzhiyun 	}
2719*4882a593Smuzhiyun 	if (bits_per_pixel >= 24) {
2720*4882a593Smuzhiyun 		vga_wgfx(regbase, CL_GR12, bg_color >> 16);
2721*4882a593Smuzhiyun 		vga_wgfx(regbase, CL_GR13, fg_color >> 16);
2722*4882a593Smuzhiyun 		op = 0xa0;
2723*4882a593Smuzhiyun 	}
2724*4882a593Smuzhiyun 	if (bits_per_pixel == 32) {
2725*4882a593Smuzhiyun 		vga_wgfx(regbase, CL_GR14, bg_color >> 24);
2726*4882a593Smuzhiyun 		vga_wgfx(regbase, CL_GR15, fg_color >> 24);
2727*4882a593Smuzhiyun 		op = 0xb0;
2728*4882a593Smuzhiyun 	}
2729*4882a593Smuzhiyun 	cirrusfb_set_blitter(regbase, width - 1, height - 1,
2730*4882a593Smuzhiyun 			    0, ndest, op | blitmode, line_length);
2731*4882a593Smuzhiyun }
2732*4882a593Smuzhiyun 
2733*4882a593Smuzhiyun /**************************************************************************
2734*4882a593Smuzhiyun  * bestclock() - determine closest possible clock lower(?) than the
2735*4882a593Smuzhiyun  * desired pixel clock
2736*4882a593Smuzhiyun  **************************************************************************/
bestclock(long freq,int * nom,int * den,int * div)2737*4882a593Smuzhiyun static void bestclock(long freq, int *nom, int *den, int *div)
2738*4882a593Smuzhiyun {
2739*4882a593Smuzhiyun 	int n, d;
2740*4882a593Smuzhiyun 	long h, diff;
2741*4882a593Smuzhiyun 
2742*4882a593Smuzhiyun 	assert(nom != NULL);
2743*4882a593Smuzhiyun 	assert(den != NULL);
2744*4882a593Smuzhiyun 	assert(div != NULL);
2745*4882a593Smuzhiyun 
2746*4882a593Smuzhiyun 	*nom = 0;
2747*4882a593Smuzhiyun 	*den = 0;
2748*4882a593Smuzhiyun 	*div = 0;
2749*4882a593Smuzhiyun 
2750*4882a593Smuzhiyun 	if (freq < 8000)
2751*4882a593Smuzhiyun 		freq = 8000;
2752*4882a593Smuzhiyun 
2753*4882a593Smuzhiyun 	diff = freq;
2754*4882a593Smuzhiyun 
2755*4882a593Smuzhiyun 	for (n = 32; n < 128; n++) {
2756*4882a593Smuzhiyun 		int s = 0;
2757*4882a593Smuzhiyun 
2758*4882a593Smuzhiyun 		d = (14318 * n) / freq;
2759*4882a593Smuzhiyun 		if ((d >= 7) && (d <= 63)) {
2760*4882a593Smuzhiyun 			int temp = d;
2761*4882a593Smuzhiyun 
2762*4882a593Smuzhiyun 			if (temp > 31) {
2763*4882a593Smuzhiyun 				s = 1;
2764*4882a593Smuzhiyun 				temp >>= 1;
2765*4882a593Smuzhiyun 			}
2766*4882a593Smuzhiyun 			h = ((14318 * n) / temp) >> s;
2767*4882a593Smuzhiyun 			h = h > freq ? h - freq : freq - h;
2768*4882a593Smuzhiyun 			if (h < diff) {
2769*4882a593Smuzhiyun 				diff = h;
2770*4882a593Smuzhiyun 				*nom = n;
2771*4882a593Smuzhiyun 				*den = temp;
2772*4882a593Smuzhiyun 				*div = s;
2773*4882a593Smuzhiyun 			}
2774*4882a593Smuzhiyun 		}
2775*4882a593Smuzhiyun 		d++;
2776*4882a593Smuzhiyun 		if ((d >= 7) && (d <= 63)) {
2777*4882a593Smuzhiyun 			if (d > 31) {
2778*4882a593Smuzhiyun 				s = 1;
2779*4882a593Smuzhiyun 				d >>= 1;
2780*4882a593Smuzhiyun 			}
2781*4882a593Smuzhiyun 			h = ((14318 * n) / d) >> s;
2782*4882a593Smuzhiyun 			h = h > freq ? h - freq : freq - h;
2783*4882a593Smuzhiyun 			if (h < diff) {
2784*4882a593Smuzhiyun 				diff = h;
2785*4882a593Smuzhiyun 				*nom = n;
2786*4882a593Smuzhiyun 				*den = d;
2787*4882a593Smuzhiyun 				*div = s;
2788*4882a593Smuzhiyun 			}
2789*4882a593Smuzhiyun 		}
2790*4882a593Smuzhiyun 	}
2791*4882a593Smuzhiyun }
2792*4882a593Smuzhiyun 
2793*4882a593Smuzhiyun /* -------------------------------------------------------------------------
2794*4882a593Smuzhiyun  *
2795*4882a593Smuzhiyun  * debugging functions
2796*4882a593Smuzhiyun  *
2797*4882a593Smuzhiyun  * -------------------------------------------------------------------------
2798*4882a593Smuzhiyun  */
2799*4882a593Smuzhiyun 
2800*4882a593Smuzhiyun #ifdef CIRRUSFB_DEBUG
2801*4882a593Smuzhiyun 
2802*4882a593Smuzhiyun /**
2803*4882a593Smuzhiyun  * cirrusfb_dbg_print_regs
2804*4882a593Smuzhiyun  * @base: If using newmmio, the newmmio base address, otherwise %NULL
2805*4882a593Smuzhiyun  * @reg_class: type of registers to read: %CRT, or %SEQ
2806*4882a593Smuzhiyun  *
2807*4882a593Smuzhiyun  * DESCRIPTION:
2808*4882a593Smuzhiyun  * Dumps the given list of VGA CRTC registers.  If @base is %NULL,
2809*4882a593Smuzhiyun  * old-style I/O ports are queried for information, otherwise MMIO is
2810*4882a593Smuzhiyun  * used at the given @base address to query the information.
2811*4882a593Smuzhiyun  */
2812*4882a593Smuzhiyun 
cirrusfb_dbg_print_regs(struct fb_info * info,caddr_t regbase,enum cirrusfb_dbg_reg_class reg_class,...)2813*4882a593Smuzhiyun static void cirrusfb_dbg_print_regs(struct fb_info *info,
2814*4882a593Smuzhiyun 				    caddr_t regbase,
2815*4882a593Smuzhiyun 				    enum cirrusfb_dbg_reg_class reg_class, ...)
2816*4882a593Smuzhiyun {
2817*4882a593Smuzhiyun 	va_list list;
2818*4882a593Smuzhiyun 	unsigned char val = 0;
2819*4882a593Smuzhiyun 	unsigned reg;
2820*4882a593Smuzhiyun 	char *name;
2821*4882a593Smuzhiyun 
2822*4882a593Smuzhiyun 	va_start(list, reg_class);
2823*4882a593Smuzhiyun 
2824*4882a593Smuzhiyun 	name = va_arg(list, char *);
2825*4882a593Smuzhiyun 	while (name != NULL) {
2826*4882a593Smuzhiyun 		reg = va_arg(list, int);
2827*4882a593Smuzhiyun 
2828*4882a593Smuzhiyun 		switch (reg_class) {
2829*4882a593Smuzhiyun 		case CRT:
2830*4882a593Smuzhiyun 			val = vga_rcrt(regbase, (unsigned char) reg);
2831*4882a593Smuzhiyun 			break;
2832*4882a593Smuzhiyun 		case SEQ:
2833*4882a593Smuzhiyun 			val = vga_rseq(regbase, (unsigned char) reg);
2834*4882a593Smuzhiyun 			break;
2835*4882a593Smuzhiyun 		default:
2836*4882a593Smuzhiyun 			/* should never occur */
2837*4882a593Smuzhiyun 			assert(false);
2838*4882a593Smuzhiyun 			break;
2839*4882a593Smuzhiyun 		}
2840*4882a593Smuzhiyun 
2841*4882a593Smuzhiyun 		dev_dbg(info->device, "%8s = 0x%02X\n", name, val);
2842*4882a593Smuzhiyun 
2843*4882a593Smuzhiyun 		name = va_arg(list, char *);
2844*4882a593Smuzhiyun 	}
2845*4882a593Smuzhiyun 
2846*4882a593Smuzhiyun 	va_end(list);
2847*4882a593Smuzhiyun }
2848*4882a593Smuzhiyun 
2849*4882a593Smuzhiyun /**
2850*4882a593Smuzhiyun  * cirrusfb_dbg_reg_dump
2851*4882a593Smuzhiyun  * @base: If using newmmio, the newmmio base address, otherwise %NULL
2852*4882a593Smuzhiyun  *
2853*4882a593Smuzhiyun  * DESCRIPTION:
2854*4882a593Smuzhiyun  * Dumps a list of interesting VGA and CIRRUSFB registers.  If @base is %NULL,
2855*4882a593Smuzhiyun  * old-style I/O ports are queried for information, otherwise MMIO is
2856*4882a593Smuzhiyun  * used at the given @base address to query the information.
2857*4882a593Smuzhiyun  */
2858*4882a593Smuzhiyun 
cirrusfb_dbg_reg_dump(struct fb_info * info,caddr_t regbase)2859*4882a593Smuzhiyun static void cirrusfb_dbg_reg_dump(struct fb_info *info, caddr_t regbase)
2860*4882a593Smuzhiyun {
2861*4882a593Smuzhiyun 	dev_dbg(info->device, "VGA CRTC register dump:\n");
2862*4882a593Smuzhiyun 
2863*4882a593Smuzhiyun 	cirrusfb_dbg_print_regs(info, regbase, CRT,
2864*4882a593Smuzhiyun 			   "CR00", 0x00,
2865*4882a593Smuzhiyun 			   "CR01", 0x01,
2866*4882a593Smuzhiyun 			   "CR02", 0x02,
2867*4882a593Smuzhiyun 			   "CR03", 0x03,
2868*4882a593Smuzhiyun 			   "CR04", 0x04,
2869*4882a593Smuzhiyun 			   "CR05", 0x05,
2870*4882a593Smuzhiyun 			   "CR06", 0x06,
2871*4882a593Smuzhiyun 			   "CR07", 0x07,
2872*4882a593Smuzhiyun 			   "CR08", 0x08,
2873*4882a593Smuzhiyun 			   "CR09", 0x09,
2874*4882a593Smuzhiyun 			   "CR0A", 0x0A,
2875*4882a593Smuzhiyun 			   "CR0B", 0x0B,
2876*4882a593Smuzhiyun 			   "CR0C", 0x0C,
2877*4882a593Smuzhiyun 			   "CR0D", 0x0D,
2878*4882a593Smuzhiyun 			   "CR0E", 0x0E,
2879*4882a593Smuzhiyun 			   "CR0F", 0x0F,
2880*4882a593Smuzhiyun 			   "CR10", 0x10,
2881*4882a593Smuzhiyun 			   "CR11", 0x11,
2882*4882a593Smuzhiyun 			   "CR12", 0x12,
2883*4882a593Smuzhiyun 			   "CR13", 0x13,
2884*4882a593Smuzhiyun 			   "CR14", 0x14,
2885*4882a593Smuzhiyun 			   "CR15", 0x15,
2886*4882a593Smuzhiyun 			   "CR16", 0x16,
2887*4882a593Smuzhiyun 			   "CR17", 0x17,
2888*4882a593Smuzhiyun 			   "CR18", 0x18,
2889*4882a593Smuzhiyun 			   "CR22", 0x22,
2890*4882a593Smuzhiyun 			   "CR24", 0x24,
2891*4882a593Smuzhiyun 			   "CR26", 0x26,
2892*4882a593Smuzhiyun 			   "CR2D", 0x2D,
2893*4882a593Smuzhiyun 			   "CR2E", 0x2E,
2894*4882a593Smuzhiyun 			   "CR2F", 0x2F,
2895*4882a593Smuzhiyun 			   "CR30", 0x30,
2896*4882a593Smuzhiyun 			   "CR31", 0x31,
2897*4882a593Smuzhiyun 			   "CR32", 0x32,
2898*4882a593Smuzhiyun 			   "CR33", 0x33,
2899*4882a593Smuzhiyun 			   "CR34", 0x34,
2900*4882a593Smuzhiyun 			   "CR35", 0x35,
2901*4882a593Smuzhiyun 			   "CR36", 0x36,
2902*4882a593Smuzhiyun 			   "CR37", 0x37,
2903*4882a593Smuzhiyun 			   "CR38", 0x38,
2904*4882a593Smuzhiyun 			   "CR39", 0x39,
2905*4882a593Smuzhiyun 			   "CR3A", 0x3A,
2906*4882a593Smuzhiyun 			   "CR3B", 0x3B,
2907*4882a593Smuzhiyun 			   "CR3C", 0x3C,
2908*4882a593Smuzhiyun 			   "CR3D", 0x3D,
2909*4882a593Smuzhiyun 			   "CR3E", 0x3E,
2910*4882a593Smuzhiyun 			   "CR3F", 0x3F,
2911*4882a593Smuzhiyun 			   NULL);
2912*4882a593Smuzhiyun 
2913*4882a593Smuzhiyun 	dev_dbg(info->device, "\n");
2914*4882a593Smuzhiyun 
2915*4882a593Smuzhiyun 	dev_dbg(info->device, "VGA SEQ register dump:\n");
2916*4882a593Smuzhiyun 
2917*4882a593Smuzhiyun 	cirrusfb_dbg_print_regs(info, regbase, SEQ,
2918*4882a593Smuzhiyun 			   "SR00", 0x00,
2919*4882a593Smuzhiyun 			   "SR01", 0x01,
2920*4882a593Smuzhiyun 			   "SR02", 0x02,
2921*4882a593Smuzhiyun 			   "SR03", 0x03,
2922*4882a593Smuzhiyun 			   "SR04", 0x04,
2923*4882a593Smuzhiyun 			   "SR08", 0x08,
2924*4882a593Smuzhiyun 			   "SR09", 0x09,
2925*4882a593Smuzhiyun 			   "SR0A", 0x0A,
2926*4882a593Smuzhiyun 			   "SR0B", 0x0B,
2927*4882a593Smuzhiyun 			   "SR0D", 0x0D,
2928*4882a593Smuzhiyun 			   "SR10", 0x10,
2929*4882a593Smuzhiyun 			   "SR11", 0x11,
2930*4882a593Smuzhiyun 			   "SR12", 0x12,
2931*4882a593Smuzhiyun 			   "SR13", 0x13,
2932*4882a593Smuzhiyun 			   "SR14", 0x14,
2933*4882a593Smuzhiyun 			   "SR15", 0x15,
2934*4882a593Smuzhiyun 			   "SR16", 0x16,
2935*4882a593Smuzhiyun 			   "SR17", 0x17,
2936*4882a593Smuzhiyun 			   "SR18", 0x18,
2937*4882a593Smuzhiyun 			   "SR19", 0x19,
2938*4882a593Smuzhiyun 			   "SR1A", 0x1A,
2939*4882a593Smuzhiyun 			   "SR1B", 0x1B,
2940*4882a593Smuzhiyun 			   "SR1C", 0x1C,
2941*4882a593Smuzhiyun 			   "SR1D", 0x1D,
2942*4882a593Smuzhiyun 			   "SR1E", 0x1E,
2943*4882a593Smuzhiyun 			   "SR1F", 0x1F,
2944*4882a593Smuzhiyun 			   NULL);
2945*4882a593Smuzhiyun 
2946*4882a593Smuzhiyun 	dev_dbg(info->device, "\n");
2947*4882a593Smuzhiyun }
2948*4882a593Smuzhiyun 
2949*4882a593Smuzhiyun #endif				/* CIRRUSFB_DEBUG */
2950*4882a593Smuzhiyun 
2951