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