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