RT-AC66 3.0.0.4.374.130 core
[tomato.git] / release / src-rt-6.x / linux / linux-2.6 / drivers / video / cirrusfb.c
blob8269d704ab2a2c27731490b3eeb39b203c9f80f3
1 /*
2 * drivers/video/cirrusfb.c - driver for Cirrus Logic chipsets
4 * Copyright 1999-2001 Jeff Garzik <jgarzik@pobox.com>
6 * Contributors (thanks, all!)
8 * David Eger:
9 * Overhaul for Linux 2.6
11 * Jeff Rugen:
12 * Major contributions; Motorola PowerStack (PPC and PCI) support,
13 * GD54xx, 1280x1024 mode support, change MCLK based on VCLK.
15 * Geert Uytterhoeven:
16 * Excellent code review.
18 * Lars Hecking:
19 * Amiga updates and testing.
21 * Original cirrusfb author: Frank Neumann
23 * Based on retz3fb.c and cirrusfb.c:
24 * Copyright (C) 1997 Jes Sorensen
25 * Copyright (C) 1996 Frank Neumann
27 ***************************************************************
29 * Format this code with GNU indent '-kr -i8 -pcs' options.
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.
37 #define CIRRUSFB_VERSION "2.0-pre2"
39 #include <linux/module.h>
40 #include <linux/kernel.h>
41 #include <linux/errno.h>
42 #include <linux/string.h>
43 #include <linux/mm.h>
44 #include <linux/slab.h>
45 #include <linux/delay.h>
46 #include <linux/fb.h>
47 #include <linux/init.h>
48 #include <linux/selection.h>
49 #include <asm/pgtable.h>
51 #ifdef CONFIG_ZORRO
52 #include <linux/zorro.h>
53 #endif
54 #ifdef CONFIG_PCI
55 #include <linux/pci.h>
56 #endif
57 #ifdef CONFIG_AMIGA
58 #include <asm/amigahw.h>
59 #endif
60 #ifdef CONFIG_PPC_PREP
61 #include <asm/machdep.h>
62 #define isPReP (machine_is(prep))
63 #else
64 #define isPReP 0
65 #endif
67 #include "video/vga.h"
68 #include "video/cirrus.h"
71 /*****************************************************************
73 * debugging and utility macros
77 /* enable debug output? */
78 /* #define CIRRUSFB_DEBUG 1 */
80 /* disable runtime assertions? */
81 /* #define CIRRUSFB_NDEBUG */
83 /* debug output */
84 #ifdef CIRRUSFB_DEBUG
85 #define DPRINTK(fmt, args...) printk(KERN_DEBUG "%s: " fmt, __FUNCTION__ , ## args)
86 #else
87 #define DPRINTK(fmt, args...)
88 #endif
90 /* debugging assertions */
91 #ifndef CIRRUSFB_NDEBUG
92 #define assert(expr) \
93 if(!(expr)) { \
94 printk( "Assertion failed! %s,%s,%s,line=%d\n",\
95 #expr,__FILE__,__FUNCTION__,__LINE__); \
97 #else
98 #define assert(expr)
99 #endif
101 #define MB_ (1024*1024)
102 #define KB_ (1024)
104 #define MAX_NUM_BOARDS 7
107 /*****************************************************************
109 * chipset information
113 /* board types */
114 typedef enum {
115 BT_NONE = 0,
116 BT_SD64,
117 BT_PICCOLO,
118 BT_PICASSO,
119 BT_SPECTRUM,
120 BT_PICASSO4, /* GD5446 */
121 BT_ALPINE, /* GD543x/4x */
122 BT_GD5480,
123 BT_LAGUNA, /* GD546x */
124 } cirrusfb_board_t;
128 * per-board-type information, used for enumerating and abstracting
129 * chip-specific information
130 * NOTE: MUST be in the same order as cirrusfb_board_t in order to
131 * use direct indexing on this array
132 * NOTE: '__initdata' cannot be used as some of this info
133 * is required at runtime. Maybe separate into an init-only and
134 * a run-time table?
136 static const struct cirrusfb_board_info_rec {
137 char *name; /* ASCII name of chipset */
138 long maxclock[5]; /* maximum video clock */
139 /* for 1/4bpp, 8bpp 15/16bpp, 24bpp, 32bpp - numbers from xorg code */
140 bool init_sr07 : 1; /* init SR07 during init_vgachip() */
141 bool init_sr1f : 1; /* write SR1F during init_vgachip() */
142 bool scrn_start_bit19 : 1; /* construct bit 19 of screen start address */
144 /* initial SR07 value, then for each mode */
145 unsigned char sr07;
146 unsigned char sr07_1bpp;
147 unsigned char sr07_1bpp_mux;
148 unsigned char sr07_8bpp;
149 unsigned char sr07_8bpp_mux;
151 unsigned char sr1f; /* SR1F VGA initial register value */
152 } cirrusfb_board_info[] = {
153 [BT_SD64] = {
154 .name = "CL SD64",
155 .maxclock = {
156 /* guess */
157 /* the SD64/P4 have a higher max. videoclock */
158 140000, 140000, 140000, 140000, 140000,
160 .init_sr07 = true,
161 .init_sr1f = true,
162 .scrn_start_bit19 = true,
163 .sr07 = 0xF0,
164 .sr07_1bpp = 0xF0,
165 .sr07_8bpp = 0xF1,
166 .sr1f = 0x20
168 [BT_PICCOLO] = {
169 .name = "CL Piccolo",
170 .maxclock = {
171 /* guess */
172 90000, 90000, 90000, 90000, 90000
174 .init_sr07 = true,
175 .init_sr1f = true,
176 .scrn_start_bit19 = false,
177 .sr07 = 0x80,
178 .sr07_1bpp = 0x80,
179 .sr07_8bpp = 0x81,
180 .sr1f = 0x22
182 [BT_PICASSO] = {
183 .name = "CL Picasso",
184 .maxclock = {
185 /* guess */
186 90000, 90000, 90000, 90000, 90000
188 .init_sr07 = true,
189 .init_sr1f = true,
190 .scrn_start_bit19 = false,
191 .sr07 = 0x20,
192 .sr07_1bpp = 0x20,
193 .sr07_8bpp = 0x21,
194 .sr1f = 0x22
196 [BT_SPECTRUM] = {
197 .name = "CL Spectrum",
198 .maxclock = {
199 /* guess */
200 90000, 90000, 90000, 90000, 90000
202 .init_sr07 = true,
203 .init_sr1f = true,
204 .scrn_start_bit19 = false,
205 .sr07 = 0x80,
206 .sr07_1bpp = 0x80,
207 .sr07_8bpp = 0x81,
208 .sr1f = 0x22
210 [BT_PICASSO4] = {
211 .name = "CL Picasso4",
212 .maxclock = {
213 135100, 135100, 85500, 85500, 0
215 .init_sr07 = true,
216 .init_sr1f = false,
217 .scrn_start_bit19 = true,
218 .sr07 = 0x20,
219 .sr07_1bpp = 0x20,
220 .sr07_8bpp = 0x21,
221 .sr1f = 0
223 [BT_ALPINE] = {
224 .name = "CL Alpine",
225 .maxclock = {
226 /* for the GD5430. GD5446 can do more... */
227 85500, 85500, 50000, 28500, 0
229 .init_sr07 = true,
230 .init_sr1f = true,
231 .scrn_start_bit19 = true,
232 .sr07 = 0xA0,
233 .sr07_1bpp = 0xA1,
234 .sr07_1bpp_mux = 0xA7,
235 .sr07_8bpp = 0xA1,
236 .sr07_8bpp_mux = 0xA7,
237 .sr1f = 0x1C
239 [BT_GD5480] = {
240 .name = "CL GD5480",
241 .maxclock = {
242 135100, 200000, 200000, 135100, 135100
244 .init_sr07 = true,
245 .init_sr1f = true,
246 .scrn_start_bit19 = true,
247 .sr07 = 0x10,
248 .sr07_1bpp = 0x11,
249 .sr07_8bpp = 0x11,
250 .sr1f = 0x1C
252 [BT_LAGUNA] = {
253 .name = "CL Laguna",
254 .maxclock = {
255 /* guess */
256 135100, 135100, 135100, 135100, 135100,
258 .init_sr07 = false,
259 .init_sr1f = false,
260 .scrn_start_bit19 = true,
265 #ifdef CONFIG_PCI
266 #define CHIP(id, btype) \
267 { PCI_VENDOR_ID_CIRRUS, id, PCI_ANY_ID, PCI_ANY_ID, 0, 0, (btype) }
269 static struct pci_device_id cirrusfb_pci_table[] = {
270 CHIP( PCI_DEVICE_ID_CIRRUS_5436, BT_ALPINE ),
271 CHIP( PCI_DEVICE_ID_CIRRUS_5434_8, BT_ALPINE ),
272 CHIP( PCI_DEVICE_ID_CIRRUS_5434_4, BT_ALPINE ),
273 CHIP( PCI_DEVICE_ID_CIRRUS_5430, BT_ALPINE ), /* GD-5440 is same id */
274 CHIP( PCI_DEVICE_ID_CIRRUS_7543, BT_ALPINE ),
275 CHIP( PCI_DEVICE_ID_CIRRUS_7548, BT_ALPINE ),
276 CHIP( PCI_DEVICE_ID_CIRRUS_5480, BT_GD5480 ), /* MacPicasso likely */
277 CHIP( PCI_DEVICE_ID_CIRRUS_5446, BT_PICASSO4 ), /* Picasso 4 is 5446 */
278 CHIP( PCI_DEVICE_ID_CIRRUS_5462, BT_LAGUNA ), /* CL Laguna */
279 CHIP( PCI_DEVICE_ID_CIRRUS_5464, BT_LAGUNA ), /* CL Laguna 3D */
280 CHIP( PCI_DEVICE_ID_CIRRUS_5465, BT_LAGUNA ), /* CL Laguna 3DA*/
281 { 0, }
283 MODULE_DEVICE_TABLE(pci, cirrusfb_pci_table);
284 #undef CHIP
285 #endif /* CONFIG_PCI */
288 #ifdef CONFIG_ZORRO
289 static const struct zorro_device_id cirrusfb_zorro_table[] = {
291 .id = ZORRO_PROD_HELFRICH_SD64_RAM,
292 .driver_data = BT_SD64,
293 }, {
294 .id = ZORRO_PROD_HELFRICH_PICCOLO_RAM,
295 .driver_data = BT_PICCOLO,
296 }, {
297 .id = ZORRO_PROD_VILLAGE_TRONIC_PICASSO_II_II_PLUS_RAM,
298 .driver_data = BT_PICASSO,
299 }, {
300 .id = ZORRO_PROD_GVP_EGS_28_24_SPECTRUM_RAM,
301 .driver_data = BT_SPECTRUM,
302 }, {
303 .id = ZORRO_PROD_VILLAGE_TRONIC_PICASSO_IV_Z3,
304 .driver_data = BT_PICASSO4,
306 { 0 }
309 static const struct {
310 zorro_id id2;
311 unsigned long size;
312 } cirrusfb_zorro_table2[] = {
313 [BT_SD64] = {
314 .id2 = ZORRO_PROD_HELFRICH_SD64_REG,
315 .size = 0x400000
317 [BT_PICCOLO] = {
318 .id2 = ZORRO_PROD_HELFRICH_PICCOLO_REG,
319 .size = 0x200000
321 [BT_PICASSO] = {
322 .id2 = ZORRO_PROD_VILLAGE_TRONIC_PICASSO_II_II_PLUS_REG,
323 .size = 0x200000
325 [BT_SPECTRUM] = {
326 .id2 = ZORRO_PROD_GVP_EGS_28_24_SPECTRUM_REG,
327 .size = 0x200000
329 [BT_PICASSO4] = {
330 .id2 = 0,
331 .size = 0x400000
334 #endif /* CONFIG_ZORRO */
337 struct cirrusfb_regs {
338 __u32 line_length; /* in BYTES! */
339 __u32 visual;
340 __u32 type;
342 long freq;
343 long nom;
344 long den;
345 long div;
346 long multiplexing;
347 long mclk;
348 long divMCLK;
350 long HorizRes; /* The x resolution in pixel */
351 long HorizTotal;
352 long HorizDispEnd;
353 long HorizBlankStart;
354 long HorizBlankEnd;
355 long HorizSyncStart;
356 long HorizSyncEnd;
358 long VertRes; /* the physical y resolution in scanlines */
359 long VertTotal;
360 long VertDispEnd;
361 long VertSyncStart;
362 long VertSyncEnd;
363 long VertBlankStart;
364 long VertBlankEnd;
369 #ifdef CIRRUSFB_DEBUG
370 typedef enum {
371 CRT,
373 } cirrusfb_dbg_reg_class_t;
374 #endif /* CIRRUSFB_DEBUG */
379 /* info about board */
380 struct cirrusfb_info {
381 struct fb_info *info;
383 u8 __iomem *fbmem;
384 u8 __iomem *regbase;
385 u8 __iomem *mem;
386 unsigned long size;
387 cirrusfb_board_t btype;
388 unsigned char SFR; /* Shadow of special function register */
390 unsigned long fbmem_phys;
391 unsigned long fbregs_phys;
393 struct cirrusfb_regs currentmode;
394 int blank_mode;
396 u32 pseudo_palette[16];
397 struct { u8 red, green, blue, pad; } palette[256];
399 #ifdef CONFIG_ZORRO
400 struct zorro_dev *zdev;
401 #endif
402 #ifdef CONFIG_PCI
403 struct pci_dev *pdev;
404 #endif
405 void (*unmap)(struct cirrusfb_info *cinfo);
409 static unsigned cirrusfb_def_mode = 1;
410 static int noaccel = 0;
413 * Predefined Video Modes
416 static const struct {
417 const char *name;
418 struct fb_var_screeninfo var;
419 } cirrusfb_predefined[] = {
421 /* autodetect mode */
422 .name = "Autodetect",
423 }, {
424 /* 640x480, 31.25 kHz, 60 Hz, 25 MHz PixClock */
425 .name = "640x480",
426 .var = {
427 .xres = 640,
428 .yres = 480,
429 .xres_virtual = 640,
430 .yres_virtual = 480,
431 .bits_per_pixel = 8,
432 .red = { .length = 8 },
433 .green = { .length = 8 },
434 .blue = { .length = 8 },
435 .width = -1,
436 .height = -1,
437 .pixclock = 40000,
438 .left_margin = 48,
439 .right_margin = 16,
440 .upper_margin = 32,
441 .lower_margin = 8,
442 .hsync_len = 96,
443 .vsync_len = 4,
444 .sync = FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
445 .vmode = FB_VMODE_NONINTERLACED
447 }, {
448 /* 800x600, 48 kHz, 76 Hz, 50 MHz PixClock */
449 .name = "800x600",
450 .var = {
451 .xres = 800,
452 .yres = 600,
453 .xres_virtual = 800,
454 .yres_virtual = 600,
455 .bits_per_pixel = 8,
456 .red = { .length = 8 },
457 .green = { .length = 8 },
458 .blue = { .length = 8 },
459 .width = -1,
460 .height = -1,
461 .pixclock = 20000,
462 .left_margin = 128,
463 .right_margin = 16,
464 .upper_margin = 24,
465 .lower_margin = 2,
466 .hsync_len = 96,
467 .vsync_len = 6,
468 .vmode = FB_VMODE_NONINTERLACED
470 }, {
472 * Modeline from XF86Config:
473 * Mode "1024x768" 80 1024 1136 1340 1432 768 770 774 805
475 /* 1024x768, 55.8 kHz, 70 Hz, 80 MHz PixClock */
476 .name = "1024x768",
477 .var = {
478 .xres = 1024,
479 .yres = 768,
480 .xres_virtual = 1024,
481 .yres_virtual = 768,
482 .bits_per_pixel = 8,
483 .red = { .length = 8 },
484 .green = { .length = 8 },
485 .blue = { .length = 8 },
486 .width = -1,
487 .height = -1,
488 .pixclock = 12500,
489 .left_margin = 144,
490 .right_margin = 32,
491 .upper_margin = 30,
492 .lower_margin = 2,
493 .hsync_len = 192,
494 .vsync_len = 6,
495 .vmode = FB_VMODE_NONINTERLACED
500 #define NUM_TOTAL_MODES ARRAY_SIZE(cirrusfb_predefined)
502 /****************************************************************************/
503 /**** BEGIN PROTOTYPES ******************************************************/
506 /*--- Interface used by the world ------------------------------------------*/
507 static int cirrusfb_init (void);
508 #ifndef MODULE
509 static int cirrusfb_setup (char *options);
510 #endif
512 static int cirrusfb_open (struct fb_info *info, int user);
513 static int cirrusfb_release (struct fb_info *info, int user);
514 static int cirrusfb_setcolreg (unsigned regno, unsigned red, unsigned green,
515 unsigned blue, unsigned transp,
516 struct fb_info *info);
517 static int cirrusfb_check_var (struct fb_var_screeninfo *var,
518 struct fb_info *info);
519 static int cirrusfb_set_par (struct fb_info *info);
520 static int cirrusfb_pan_display (struct fb_var_screeninfo *var,
521 struct fb_info *info);
522 static int cirrusfb_blank (int blank_mode, struct fb_info *info);
523 static void cirrusfb_fillrect (struct fb_info *info, const struct fb_fillrect *region);
524 static void cirrusfb_copyarea(struct fb_info *info, const struct fb_copyarea *area);
525 static void cirrusfb_imageblit(struct fb_info *info, const struct fb_image *image);
527 /* function table of the above functions */
528 static struct fb_ops cirrusfb_ops = {
529 .owner = THIS_MODULE,
530 .fb_open = cirrusfb_open,
531 .fb_release = cirrusfb_release,
532 .fb_setcolreg = cirrusfb_setcolreg,
533 .fb_check_var = cirrusfb_check_var,
534 .fb_set_par = cirrusfb_set_par,
535 .fb_pan_display = cirrusfb_pan_display,
536 .fb_blank = cirrusfb_blank,
537 .fb_fillrect = cirrusfb_fillrect,
538 .fb_copyarea = cirrusfb_copyarea,
539 .fb_imageblit = cirrusfb_imageblit,
542 /*--- Hardware Specific Routines -------------------------------------------*/
543 static int cirrusfb_decode_var (const struct fb_var_screeninfo *var,
544 struct cirrusfb_regs *regs,
545 const struct fb_info *info);
546 /*--- Internal routines ----------------------------------------------------*/
547 static void init_vgachip (struct cirrusfb_info *cinfo);
548 static void switch_monitor (struct cirrusfb_info *cinfo, int on);
549 static void WGen (const struct cirrusfb_info *cinfo,
550 int regnum, unsigned char val);
551 static unsigned char RGen (const struct cirrusfb_info *cinfo, int regnum);
552 static void AttrOn (const struct cirrusfb_info *cinfo);
553 static void WHDR (const struct cirrusfb_info *cinfo, unsigned char val);
554 static void WSFR (struct cirrusfb_info *cinfo, unsigned char val);
555 static void WSFR2 (struct cirrusfb_info *cinfo, unsigned char val);
556 static void WClut (struct cirrusfb_info *cinfo, unsigned char regnum, unsigned char red,
557 unsigned char green,
558 unsigned char blue);
559 #if 0
560 static void RClut (struct cirrusfb_info *cinfo, unsigned char regnum, unsigned char *red,
561 unsigned char *green,
562 unsigned char *blue);
563 #endif
564 static void cirrusfb_WaitBLT (u8 __iomem *regbase);
565 static void cirrusfb_BitBLT (u8 __iomem *regbase, int bits_per_pixel,
566 u_short curx, u_short cury,
567 u_short destx, u_short desty,
568 u_short width, u_short height,
569 u_short line_length);
570 static void cirrusfb_RectFill (u8 __iomem *regbase, int bits_per_pixel,
571 u_short x, u_short y,
572 u_short width, u_short height,
573 u_char color, u_short line_length);
575 static void bestclock (long freq, long *best,
576 long *nom, long *den,
577 long *div, long maxfreq);
579 #ifdef CIRRUSFB_DEBUG
580 static void cirrusfb_dump (void);
581 static void cirrusfb_dbg_reg_dump (caddr_t regbase);
582 static void cirrusfb_dbg_print_regs (caddr_t regbase, cirrusfb_dbg_reg_class_t reg_class,...);
583 static void cirrusfb_dbg_print_byte (const char *name, unsigned char val);
584 #endif /* CIRRUSFB_DEBUG */
586 /*** END PROTOTYPES ********************************************************/
587 /*****************************************************************************/
588 /*** BEGIN Interface Used by the World ***************************************/
590 static int opencount = 0;
592 /*--- Open /dev/fbx ---------------------------------------------------------*/
593 static int cirrusfb_open (struct fb_info *info, int user)
595 if (opencount++ == 0)
596 switch_monitor (info->par, 1);
597 return 0;
600 /*--- Close /dev/fbx --------------------------------------------------------*/
601 static int cirrusfb_release (struct fb_info *info, int user)
603 if (--opencount == 0)
604 switch_monitor (info->par, 0);
605 return 0;
608 /**** END Interface used by the World *************************************/
609 /****************************************************************************/
610 /**** BEGIN Hardware specific Routines **************************************/
612 /* Get a good MCLK value */
613 static long cirrusfb_get_mclk (long freq, int bpp, long *div)
615 long mclk;
617 assert (div != NULL);
619 /* Calculate MCLK, in case VCLK is high enough to require > 50MHz.
620 * Assume a 64-bit data path for now. The formula is:
621 * ((B * PCLK * 2)/W) * 1.2
622 * B = bytes per pixel, PCLK = pixclock, W = data width in bytes */
623 mclk = ((bpp / 8) * freq * 2) / 4;
624 mclk = (mclk * 12) / 10;
625 if (mclk < 50000)
626 mclk = 50000;
627 DPRINTK ("Use MCLK of %ld kHz\n", mclk);
629 /* Calculate value for SR1F. Multiply by 2 so we can round up. */
630 mclk = ((mclk * 16) / 14318);
631 mclk = (mclk + 1) / 2;
632 DPRINTK ("Set SR1F[5:0] to 0x%lx\n", mclk);
634 /* Determine if we should use MCLK instead of VCLK, and if so, what we
635 * should divide it by to get VCLK */
636 switch (freq) {
637 case 24751 ... 25249:
638 *div = 2;
639 DPRINTK ("Using VCLK = MCLK/2\n");
640 break;
641 case 49501 ... 50499:
642 *div = 1;
643 DPRINTK ("Using VCLK = MCLK\n");
644 break;
645 default:
646 *div = 0;
647 break;
650 return mclk;
653 static int cirrusfb_check_var(struct fb_var_screeninfo *var,
654 struct fb_info *info)
656 struct cirrusfb_info *cinfo = info->par;
657 int nom, den; /* translyting from pixels->bytes */
658 int yres, i;
659 static struct { int xres, yres; } modes[] =
660 { { 1600, 1280 },
661 { 1280, 1024 },
662 { 1024, 768 },
663 { 800, 600 },
664 { 640, 480 },
665 { -1, -1 } };
667 switch (var->bits_per_pixel) {
668 case 0 ... 1:
669 var->bits_per_pixel = 1;
670 nom = 4;
671 den = 8;
672 break; /* 8 pixel per byte, only 1/4th of mem usable */
673 case 2 ... 8:
674 var->bits_per_pixel = 8;
675 nom = 1;
676 den = 1;
677 break; /* 1 pixel == 1 byte */
678 case 9 ... 16:
679 var->bits_per_pixel = 16;
680 nom = 2;
681 den = 1;
682 break; /* 2 bytes per pixel */
683 case 17 ... 24:
684 var->bits_per_pixel = 24;
685 nom = 3;
686 den = 1;
687 break; /* 3 bytes per pixel */
688 case 25 ... 32:
689 var->bits_per_pixel = 32;
690 nom = 4;
691 den = 1;
692 break; /* 4 bytes per pixel */
693 default:
694 printk ("cirrusfb: mode %dx%dx%d rejected...color depth not supported.\n",
695 var->xres, var->yres, var->bits_per_pixel);
696 DPRINTK ("EXIT - EINVAL error\n");
697 return -EINVAL;
700 if (var->xres * nom / den * var->yres > cinfo->size) {
701 printk ("cirrusfb: mode %dx%dx%d rejected...resolution too high to fit into video memory!\n",
702 var->xres, var->yres, var->bits_per_pixel);
703 DPRINTK ("EXIT - EINVAL error\n");
704 return -EINVAL;
707 /* use highest possible virtual resolution */
708 if (var->xres_virtual == -1 &&
709 var->yres_virtual == -1) {
710 printk ("cirrusfb: using maximum available virtual resolution\n");
711 for (i = 0; modes[i].xres != -1; i++) {
712 if (modes[i].xres * nom / den * modes[i].yres < cinfo->size / 2)
713 break;
715 if (modes[i].xres == -1) {
716 printk ("cirrusfb: could not find a virtual resolution that fits into video memory!!\n");
717 DPRINTK ("EXIT - EINVAL error\n");
718 return -EINVAL;
720 var->xres_virtual = modes[i].xres;
721 var->yres_virtual = modes[i].yres;
723 printk ("cirrusfb: virtual resolution set to maximum of %dx%d\n",
724 var->xres_virtual, var->yres_virtual);
727 if (var->xres_virtual < var->xres)
728 var->xres_virtual = var->xres;
729 if (var->yres_virtual < var->yres)
730 var->yres_virtual = var->yres;
732 if (var->xoffset < 0)
733 var->xoffset = 0;
734 if (var->yoffset < 0)
735 var->yoffset = 0;
737 /* truncate xoffset and yoffset to maximum if too high */
738 if (var->xoffset > var->xres_virtual - var->xres)
739 var->xoffset = var->xres_virtual - var->xres - 1;
740 if (var->yoffset > var->yres_virtual - var->yres)
741 var->yoffset = var->yres_virtual - var->yres - 1;
743 switch (var->bits_per_pixel) {
744 case 1:
745 var->red.offset = 0;
746 var->red.length = 1;
747 var->green.offset = 0;
748 var->green.length = 1;
749 var->blue.offset = 0;
750 var->blue.length = 1;
751 break;
753 case 8:
754 var->red.offset = 0;
755 var->red.length = 6;
756 var->green.offset = 0;
757 var->green.length = 6;
758 var->blue.offset = 0;
759 var->blue.length = 6;
760 break;
762 case 16:
763 if(isPReP) {
764 var->red.offset = 2;
765 var->green.offset = -3;
766 var->blue.offset = 8;
767 } else {
768 var->red.offset = 10;
769 var->green.offset = 5;
770 var->blue.offset = 0;
772 var->red.length = 5;
773 var->green.length = 5;
774 var->blue.length = 5;
775 break;
777 case 24:
778 if(isPReP) {
779 var->red.offset = 8;
780 var->green.offset = 16;
781 var->blue.offset = 24;
782 } else {
783 var->red.offset = 16;
784 var->green.offset = 8;
785 var->blue.offset = 0;
787 var->red.length = 8;
788 var->green.length = 8;
789 var->blue.length = 8;
790 break;
792 case 32:
793 if(isPReP) {
794 var->red.offset = 8;
795 var->green.offset = 16;
796 var->blue.offset = 24;
797 } else {
798 var->red.offset = 16;
799 var->green.offset = 8;
800 var->blue.offset = 0;
802 var->red.length = 8;
803 var->green.length = 8;
804 var->blue.length = 8;
805 break;
807 default:
808 DPRINTK("Unsupported bpp size: %d\n", var->bits_per_pixel);
809 assert(false);
810 /* should never occur */
811 break;
814 var->red.msb_right =
815 var->green.msb_right =
816 var->blue.msb_right =
817 var->transp.offset =
818 var->transp.length =
819 var->transp.msb_right = 0;
821 yres = var->yres;
822 if (var->vmode & FB_VMODE_DOUBLE)
823 yres *= 2;
824 else if (var->vmode & FB_VMODE_INTERLACED)
825 yres = (yres + 1) / 2;
827 if (yres >= 1280) {
828 printk (KERN_WARNING "cirrusfb: ERROR: VerticalTotal >= 1280; special treatment required! (TODO)\n");
829 DPRINTK ("EXIT - EINVAL error\n");
830 return -EINVAL;
833 return 0;
836 static int cirrusfb_decode_var (const struct fb_var_screeninfo *var,
837 struct cirrusfb_regs *regs,
838 const struct fb_info *info)
840 long freq;
841 long maxclock;
842 int maxclockidx = 0;
843 struct cirrusfb_info *cinfo = info->par;
844 int xres, hfront, hsync, hback;
845 int yres, vfront, vsync, vback;
847 switch(var->bits_per_pixel) {
848 case 1:
849 regs->line_length = var->xres_virtual / 8;
850 regs->visual = FB_VISUAL_MONO10;
851 maxclockidx = 0;
852 break;
854 case 8:
855 regs->line_length = var->xres_virtual;
856 regs->visual = FB_VISUAL_PSEUDOCOLOR;
857 maxclockidx = 1;
858 break;
860 case 16:
861 regs->line_length = var->xres_virtual * 2;
862 regs->visual = FB_VISUAL_DIRECTCOLOR;
863 maxclockidx = 2;
864 break;
866 case 24:
867 regs->line_length = var->xres_virtual * 3;
868 regs->visual = FB_VISUAL_DIRECTCOLOR;
869 maxclockidx = 3;
870 break;
872 case 32:
873 regs->line_length = var->xres_virtual * 4;
874 regs->visual = FB_VISUAL_DIRECTCOLOR;
875 maxclockidx = 4;
876 break;
878 default:
879 DPRINTK("Unsupported bpp size: %d\n", var->bits_per_pixel);
880 assert(false);
881 /* should never occur */
882 break;
885 regs->type = FB_TYPE_PACKED_PIXELS;
887 /* convert from ps to kHz */
888 freq = 1000000000 / var->pixclock;
890 DPRINTK ("desired pixclock: %ld kHz\n", freq);
892 maxclock = cirrusfb_board_info[cinfo->btype].maxclock[maxclockidx];
893 regs->multiplexing = 0;
895 /* If the frequency is greater than we can support, we might be able
896 * to use multiplexing for the video mode */
897 if (freq > maxclock) {
898 switch (cinfo->btype) {
899 case BT_ALPINE:
900 case BT_GD5480:
901 regs->multiplexing = 1;
902 break;
904 default:
905 printk (KERN_WARNING "cirrusfb: ERROR: Frequency greater than maxclock (%ld kHz)\n", maxclock);
906 DPRINTK ("EXIT - return -EINVAL\n");
907 return -EINVAL;
910 #if 0
911 /* TODO: If we have a 1MB 5434, we need to put ourselves in a mode where
912 * the VCLK is double the pixel clock. */
913 switch (var->bits_per_pixel) {
914 case 16:
915 case 32:
916 if (regs->HorizRes <= 800)
917 freq /= 2; /* Xbh has this type of clock for 32-bit */
918 break;
920 #endif
922 bestclock (freq, &regs->freq, &regs->nom, &regs->den, &regs->div,
923 maxclock);
924 regs->mclk = cirrusfb_get_mclk (freq, var->bits_per_pixel, &regs->divMCLK);
926 xres = var->xres;
927 hfront = var->right_margin;
928 hsync = var->hsync_len;
929 hback = var->left_margin;
931 yres = var->yres;
932 vfront = var->lower_margin;
933 vsync = var->vsync_len;
934 vback = var->upper_margin;
936 if (var->vmode & FB_VMODE_DOUBLE) {
937 yres *= 2;
938 vfront *= 2;
939 vsync *= 2;
940 vback *= 2;
941 } else if (var->vmode & FB_VMODE_INTERLACED) {
942 yres = (yres + 1) / 2;
943 vfront = (vfront + 1) / 2;
944 vsync = (vsync + 1) / 2;
945 vback = (vback + 1) / 2;
947 regs->HorizRes = xres;
948 regs->HorizTotal = (xres + hfront + hsync + hback) / 8 - 5;
949 regs->HorizDispEnd = xres / 8 - 1;
950 regs->HorizBlankStart = xres / 8;
951 regs->HorizBlankEnd = regs->HorizTotal + 5; /* does not count with "-5" */
952 regs->HorizSyncStart = (xres + hfront) / 8 + 1;
953 regs->HorizSyncEnd = (xres + hfront + hsync) / 8 + 1;
955 regs->VertRes = yres;
956 regs->VertTotal = yres + vfront + vsync + vback - 2;
957 regs->VertDispEnd = yres - 1;
958 regs->VertBlankStart = yres;
959 regs->VertBlankEnd = regs->VertTotal;
960 regs->VertSyncStart = yres + vfront - 1;
961 regs->VertSyncEnd = yres + vfront + vsync - 1;
963 if (regs->VertRes >= 1024) {
964 regs->VertTotal /= 2;
965 regs->VertSyncStart /= 2;
966 regs->VertSyncEnd /= 2;
967 regs->VertDispEnd /= 2;
969 if (regs->multiplexing) {
970 regs->HorizTotal /= 2;
971 regs->HorizSyncStart /= 2;
972 regs->HorizSyncEnd /= 2;
973 regs->HorizDispEnd /= 2;
976 return 0;
980 static void cirrusfb_set_mclk (const struct cirrusfb_info *cinfo, int val, int div)
982 assert (cinfo != NULL);
984 if (div == 2) {
985 /* VCLK = MCLK/2 */
986 unsigned char old = vga_rseq (cinfo->regbase, CL_SEQR1E);
987 vga_wseq (cinfo->regbase, CL_SEQR1E, old | 0x1);
988 vga_wseq (cinfo->regbase, CL_SEQR1F, 0x40 | (val & 0x3f));
989 } else if (div == 1) {
990 /* VCLK = MCLK */
991 unsigned char old = vga_rseq (cinfo->regbase, CL_SEQR1E);
992 vga_wseq (cinfo->regbase, CL_SEQR1E, old & ~0x1);
993 vga_wseq (cinfo->regbase, CL_SEQR1F, 0x40 | (val & 0x3f));
994 } else {
995 vga_wseq (cinfo->regbase, CL_SEQR1F, val & 0x3f);
999 /*************************************************************************
1000 cirrusfb_set_par_foo()
1002 actually writes the values for a new video mode into the hardware,
1003 **************************************************************************/
1004 static int cirrusfb_set_par_foo (struct fb_info *info)
1006 struct cirrusfb_info *cinfo = info->par;
1007 struct fb_var_screeninfo *var = &info->var;
1008 struct cirrusfb_regs regs;
1009 u8 __iomem *regbase = cinfo->regbase;
1010 unsigned char tmp;
1011 int offset = 0, err;
1012 const struct cirrusfb_board_info_rec *bi;
1014 DPRINTK ("ENTER\n");
1015 DPRINTK ("Requested mode: %dx%dx%d\n",
1016 var->xres, var->yres, var->bits_per_pixel);
1017 DPRINTK ("pixclock: %d\n", var->pixclock);
1019 init_vgachip (cinfo);
1021 err = cirrusfb_decode_var(var, &regs, info);
1022 if(err) {
1023 /* should never happen */
1024 DPRINTK("mode change aborted. invalid var.\n");
1025 return -EINVAL;
1028 bi = &cirrusfb_board_info[cinfo->btype];
1031 /* unlock register VGA_CRTC_H_TOTAL..CRT7 */
1032 vga_wcrt (regbase, VGA_CRTC_V_SYNC_END, 0x20); /* previously: 0x00) */
1034 /* if debugging is enabled, all parameters get output before writing */
1035 DPRINTK ("CRT0: %ld\n", regs.HorizTotal);
1036 vga_wcrt (regbase, VGA_CRTC_H_TOTAL, regs.HorizTotal);
1038 DPRINTK ("CRT1: %ld\n", regs.HorizDispEnd);
1039 vga_wcrt (regbase, VGA_CRTC_H_DISP, regs.HorizDispEnd);
1041 DPRINTK ("CRT2: %ld\n", regs.HorizBlankStart);
1042 vga_wcrt (regbase, VGA_CRTC_H_BLANK_START, regs.HorizBlankStart);
1044 DPRINTK ("CRT3: 128+%ld\n", regs.HorizBlankEnd % 32); /* + 128: Compatible read */
1045 vga_wcrt (regbase, VGA_CRTC_H_BLANK_END, 128 + (regs.HorizBlankEnd % 32));
1047 DPRINTK ("CRT4: %ld\n", regs.HorizSyncStart);
1048 vga_wcrt (regbase, VGA_CRTC_H_SYNC_START, regs.HorizSyncStart);
1050 tmp = regs.HorizSyncEnd % 32;
1051 if (regs.HorizBlankEnd & 32)
1052 tmp += 128;
1053 DPRINTK ("CRT5: %d\n", tmp);
1054 vga_wcrt (regbase, VGA_CRTC_H_SYNC_END, tmp);
1056 DPRINTK ("CRT6: %ld\n", regs.VertTotal & 0xff);
1057 vga_wcrt (regbase, VGA_CRTC_V_TOTAL, (regs.VertTotal & 0xff));
1059 tmp = 16; /* LineCompare bit #9 */
1060 if (regs.VertTotal & 256)
1061 tmp |= 1;
1062 if (regs.VertDispEnd & 256)
1063 tmp |= 2;
1064 if (regs.VertSyncStart & 256)
1065 tmp |= 4;
1066 if (regs.VertBlankStart & 256)
1067 tmp |= 8;
1068 if (regs.VertTotal & 512)
1069 tmp |= 32;
1070 if (regs.VertDispEnd & 512)
1071 tmp |= 64;
1072 if (regs.VertSyncStart & 512)
1073 tmp |= 128;
1074 DPRINTK ("CRT7: %d\n", tmp);
1075 vga_wcrt (regbase, VGA_CRTC_OVERFLOW, tmp);
1077 tmp = 0x40; /* LineCompare bit #8 */
1078 if (regs.VertBlankStart & 512)
1079 tmp |= 0x20;
1080 if (var->vmode & FB_VMODE_DOUBLE)
1081 tmp |= 0x80;
1082 DPRINTK ("CRT9: %d\n", tmp);
1083 vga_wcrt (regbase, VGA_CRTC_MAX_SCAN, tmp);
1085 DPRINTK ("CRT10: %ld\n", regs.VertSyncStart & 0xff);
1086 vga_wcrt (regbase, VGA_CRTC_V_SYNC_START, (regs.VertSyncStart & 0xff));
1088 DPRINTK ("CRT11: 64+32+%ld\n", regs.VertSyncEnd % 16);
1089 vga_wcrt (regbase, VGA_CRTC_V_SYNC_END, (regs.VertSyncEnd % 16 + 64 + 32));
1091 DPRINTK ("CRT12: %ld\n", regs.VertDispEnd & 0xff);
1092 vga_wcrt (regbase, VGA_CRTC_V_DISP_END, (regs.VertDispEnd & 0xff));
1094 DPRINTK ("CRT15: %ld\n", regs.VertBlankStart & 0xff);
1095 vga_wcrt (regbase, VGA_CRTC_V_BLANK_START, (regs.VertBlankStart & 0xff));
1097 DPRINTK ("CRT16: %ld\n", regs.VertBlankEnd & 0xff);
1098 vga_wcrt (regbase, VGA_CRTC_V_BLANK_END, (regs.VertBlankEnd & 0xff));
1100 DPRINTK ("CRT18: 0xff\n");
1101 vga_wcrt (regbase, VGA_CRTC_LINE_COMPARE, 0xff);
1103 tmp = 0;
1104 if (var->vmode & FB_VMODE_INTERLACED)
1105 tmp |= 1;
1106 if (regs.HorizBlankEnd & 64)
1107 tmp |= 16;
1108 if (regs.HorizBlankEnd & 128)
1109 tmp |= 32;
1110 if (regs.VertBlankEnd & 256)
1111 tmp |= 64;
1112 if (regs.VertBlankEnd & 512)
1113 tmp |= 128;
1115 DPRINTK ("CRT1a: %d\n", tmp);
1116 vga_wcrt (regbase, CL_CRT1A, tmp);
1118 /* set VCLK0 */
1119 /* hardware RefClock: 14.31818 MHz */
1120 /* formula: VClk = (OSC * N) / (D * (1+P)) */
1121 /* Example: VClk = (14.31818 * 91) / (23 * (1+1)) = 28.325 MHz */
1123 vga_wseq (regbase, CL_SEQRB, regs.nom);
1124 tmp = regs.den << 1;
1125 if (regs.div != 0)
1126 tmp |= 1;
1128 if ((cinfo->btype == BT_SD64) ||
1129 (cinfo->btype == BT_ALPINE) ||
1130 (cinfo->btype == BT_GD5480))
1131 tmp |= 0x80; /* 6 bit denom; ONLY 5434!!! (bugged me 10 days) */
1133 DPRINTK ("CL_SEQR1B: %ld\n", (long) tmp);
1134 vga_wseq (regbase, CL_SEQR1B, tmp);
1136 if (regs.VertRes >= 1024)
1137 /* 1280x1024 */
1138 vga_wcrt (regbase, VGA_CRTC_MODE, 0xc7);
1139 else
1140 /* mode control: VGA_CRTC_START_HI enable, ROTATE(?), 16bit
1141 * address wrap, no compat. */
1142 vga_wcrt (regbase, VGA_CRTC_MODE, 0xc3);
1144 /* HAEH? vga_wcrt (regbase, VGA_CRTC_V_SYNC_END, 0x20); * previously: 0x00 unlock VGA_CRTC_H_TOTAL..CRT7 */
1146 /* don't know if it would hurt to also program this if no interlaced */
1147 /* mode is used, but I feel better this way.. :-) */
1148 if (var->vmode & FB_VMODE_INTERLACED)
1149 vga_wcrt (regbase, VGA_CRTC_REGS, regs.HorizTotal / 2);
1150 else
1151 vga_wcrt (regbase, VGA_CRTC_REGS, 0x00); /* interlace control */
1153 vga_wseq (regbase, VGA_SEQ_CHARACTER_MAP, 0);
1155 /* adjust horizontal/vertical sync type (low/high) */
1156 tmp = 0x03; /* enable display memory & CRTC I/O address for color mode */
1157 if (var->sync & FB_SYNC_HOR_HIGH_ACT)
1158 tmp |= 0x40;
1159 if (var->sync & FB_SYNC_VERT_HIGH_ACT)
1160 tmp |= 0x80;
1161 WGen (cinfo, VGA_MIS_W, tmp);
1163 vga_wcrt (regbase, VGA_CRTC_PRESET_ROW, 0); /* Screen A Preset Row-Scan register */
1164 vga_wcrt (regbase, VGA_CRTC_CURSOR_START, 0); /* text cursor on and start line */
1165 vga_wcrt (regbase, VGA_CRTC_CURSOR_END, 31); /* text cursor end line */
1167 /******************************************************
1169 * 1 bpp
1173 /* programming for different color depths */
1174 if (var->bits_per_pixel == 1) {
1175 DPRINTK ("cirrusfb: preparing for 1 bit deep display\n");
1176 vga_wgfx (regbase, VGA_GFX_MODE, 0); /* mode register */
1178 /* SR07 */
1179 switch (cinfo->btype) {
1180 case BT_SD64:
1181 case BT_PICCOLO:
1182 case BT_PICASSO:
1183 case BT_SPECTRUM:
1184 case BT_PICASSO4:
1185 case BT_ALPINE:
1186 case BT_GD5480:
1187 DPRINTK (" (for GD54xx)\n");
1188 vga_wseq (regbase, CL_SEQR7,
1189 regs.multiplexing ?
1190 bi->sr07_1bpp_mux : bi->sr07_1bpp);
1191 break;
1193 case BT_LAGUNA:
1194 DPRINTK (" (for GD546x)\n");
1195 vga_wseq (regbase, CL_SEQR7,
1196 vga_rseq (regbase, CL_SEQR7) & ~0x01);
1197 break;
1199 default:
1200 printk (KERN_WARNING "cirrusfb: unknown Board\n");
1201 break;
1204 /* Extended Sequencer Mode */
1205 switch (cinfo->btype) {
1206 case BT_SD64:
1207 /* setting the SEQRF on SD64 is not necessary (only during init) */
1208 DPRINTK ("(for SD64)\n");
1209 vga_wseq (regbase, CL_SEQR1F, 0x1a); /* MCLK select */
1210 break;
1212 case BT_PICCOLO:
1213 DPRINTK ("(for Piccolo)\n");
1214 /* ### ueberall 0x22? */
1215 vga_wseq (regbase, CL_SEQR1F, 0x22); /* ##vorher 1c MCLK select */
1216 vga_wseq (regbase, CL_SEQRF, 0xb0); /* evtl d0 bei 1 bit? avoid FIFO underruns..? */
1217 break;
1219 case BT_PICASSO:
1220 DPRINTK ("(for Picasso)\n");
1221 vga_wseq (regbase, CL_SEQR1F, 0x22); /* ##vorher 22 MCLK select */
1222 vga_wseq (regbase, CL_SEQRF, 0xd0); /* ## vorher d0 avoid FIFO underruns..? */
1223 break;
1225 case BT_SPECTRUM:
1226 DPRINTK ("(for Spectrum)\n");
1227 /* ### ueberall 0x22? */
1228 vga_wseq (regbase, CL_SEQR1F, 0x22); /* ##vorher 1c MCLK select */
1229 vga_wseq (regbase, CL_SEQRF, 0xb0); /* evtl d0? avoid FIFO underruns..? */
1230 break;
1232 case BT_PICASSO4:
1233 case BT_ALPINE:
1234 case BT_GD5480:
1235 case BT_LAGUNA:
1236 DPRINTK (" (for GD54xx)\n");
1237 /* do nothing */
1238 break;
1240 default:
1241 printk (KERN_WARNING "cirrusfb: unknown Board\n");
1242 break;
1245 WGen (cinfo, VGA_PEL_MSK, 0x01); /* pixel mask: pass-through for first plane */
1246 if (regs.multiplexing)
1247 WHDR (cinfo, 0x4a); /* hidden dac reg: 1280x1024 */
1248 else
1249 WHDR (cinfo, 0); /* hidden dac: nothing */
1250 vga_wseq (regbase, VGA_SEQ_MEMORY_MODE, 0x06); /* memory mode: odd/even, ext. memory */
1251 vga_wseq (regbase, VGA_SEQ_PLANE_WRITE, 0x01); /* plane mask: only write to first plane */
1252 offset = var->xres_virtual / 16;
1255 /******************************************************
1257 * 8 bpp
1261 else if (var->bits_per_pixel == 8) {
1262 DPRINTK ("cirrusfb: preparing for 8 bit deep display\n");
1263 switch (cinfo->btype) {
1264 case BT_SD64:
1265 case BT_PICCOLO:
1266 case BT_PICASSO:
1267 case BT_SPECTRUM:
1268 case BT_PICASSO4:
1269 case BT_ALPINE:
1270 case BT_GD5480:
1271 DPRINTK (" (for GD54xx)\n");
1272 vga_wseq (regbase, CL_SEQR7,
1273 regs.multiplexing ?
1274 bi->sr07_8bpp_mux : bi->sr07_8bpp);
1275 break;
1277 case BT_LAGUNA:
1278 DPRINTK (" (for GD546x)\n");
1279 vga_wseq (regbase, CL_SEQR7,
1280 vga_rseq (regbase, CL_SEQR7) | 0x01);
1281 break;
1283 default:
1284 printk (KERN_WARNING "cirrusfb: unknown Board\n");
1285 break;
1288 switch (cinfo->btype) {
1289 case BT_SD64:
1290 vga_wseq (regbase, CL_SEQR1F, 0x1d); /* MCLK select */
1291 break;
1293 case BT_PICCOLO:
1294 vga_wseq (regbase, CL_SEQR1F, 0x22); /* ### vorher 1c MCLK select */
1295 vga_wseq (regbase, CL_SEQRF, 0xb0); /* Fast Page-Mode writes */
1296 break;
1298 case BT_PICASSO:
1299 vga_wseq (regbase, CL_SEQR1F, 0x22); /* ### vorher 1c MCLK select */
1300 vga_wseq (regbase, CL_SEQRF, 0xb0); /* Fast Page-Mode writes */
1301 break;
1303 case BT_SPECTRUM:
1304 vga_wseq (regbase, CL_SEQR1F, 0x22); /* ### vorher 1c MCLK select */
1305 vga_wseq (regbase, CL_SEQRF, 0xb0); /* Fast Page-Mode writes */
1306 break;
1308 case BT_PICASSO4:
1309 #ifdef CONFIG_ZORRO
1310 vga_wseq (regbase, CL_SEQRF, 0xb8); /* ### INCOMPLETE!! */
1311 #endif
1312 /* vga_wseq (regbase, CL_SEQR1F, 0x1c); */
1313 break;
1315 case BT_ALPINE:
1316 DPRINTK (" (for GD543x)\n");
1317 cirrusfb_set_mclk (cinfo, regs.mclk, regs.divMCLK);
1318 /* We already set SRF and SR1F */
1319 break;
1321 case BT_GD5480:
1322 case BT_LAGUNA:
1323 DPRINTK (" (for GD54xx)\n");
1324 /* do nothing */
1325 break;
1327 default:
1328 printk (KERN_WARNING "cirrusfb: unknown Board\n");
1329 break;
1332 vga_wgfx (regbase, VGA_GFX_MODE, 64); /* mode register: 256 color mode */
1333 WGen (cinfo, VGA_PEL_MSK, 0xff); /* pixel mask: pass-through all planes */
1334 if (regs.multiplexing)
1335 WHDR (cinfo, 0x4a); /* hidden dac reg: 1280x1024 */
1336 else
1337 WHDR (cinfo, 0); /* hidden dac: nothing */
1338 vga_wseq (regbase, VGA_SEQ_MEMORY_MODE, 0x0a); /* memory mode: chain4, ext. memory */
1339 vga_wseq (regbase, VGA_SEQ_PLANE_WRITE, 0xff); /* plane mask: enable writing to all 4 planes */
1340 offset = var->xres_virtual / 8;
1343 /******************************************************
1345 * 16 bpp
1349 else if (var->bits_per_pixel == 16) {
1350 DPRINTK ("cirrusfb: preparing for 16 bit deep display\n");
1351 switch (cinfo->btype) {
1352 case BT_SD64:
1353 vga_wseq (regbase, CL_SEQR7, 0xf7); /* Extended Sequencer Mode: 256c col. mode */
1354 vga_wseq (regbase, CL_SEQR1F, 0x1e); /* MCLK select */
1355 break;
1357 case BT_PICCOLO:
1358 vga_wseq (regbase, CL_SEQR7, 0x87);
1359 vga_wseq (regbase, CL_SEQRF, 0xb0); /* Fast Page-Mode writes */
1360 vga_wseq (regbase, CL_SEQR1F, 0x22); /* MCLK select */
1361 break;
1363 case BT_PICASSO:
1364 vga_wseq (regbase, CL_SEQR7, 0x27);
1365 vga_wseq (regbase, CL_SEQRF, 0xb0); /* Fast Page-Mode writes */
1366 vga_wseq (regbase, CL_SEQR1F, 0x22); /* MCLK select */
1367 break;
1369 case BT_SPECTRUM:
1370 vga_wseq (regbase, CL_SEQR7, 0x87);
1371 vga_wseq (regbase, CL_SEQRF, 0xb0); /* Fast Page-Mode writes */
1372 vga_wseq (regbase, CL_SEQR1F, 0x22); /* MCLK select */
1373 break;
1375 case BT_PICASSO4:
1376 vga_wseq (regbase, CL_SEQR7, 0x27);
1377 /* vga_wseq (regbase, CL_SEQR1F, 0x1c); */
1378 break;
1380 case BT_ALPINE:
1381 DPRINTK (" (for GD543x)\n");
1382 if (regs.HorizRes >= 1024)
1383 vga_wseq (regbase, CL_SEQR7, 0xa7);
1384 else
1385 vga_wseq (regbase, CL_SEQR7, 0xa3);
1386 cirrusfb_set_mclk (cinfo, regs.mclk, regs.divMCLK);
1387 break;
1389 case BT_GD5480:
1390 DPRINTK (" (for GD5480)\n");
1391 vga_wseq (regbase, CL_SEQR7, 0x17);
1392 /* We already set SRF and SR1F */
1393 break;
1395 case BT_LAGUNA:
1396 DPRINTK (" (for GD546x)\n");
1397 vga_wseq (regbase, CL_SEQR7,
1398 vga_rseq (regbase, CL_SEQR7) & ~0x01);
1399 break;
1401 default:
1402 printk (KERN_WARNING "CIRRUSFB: unknown Board\n");
1403 break;
1406 vga_wgfx (regbase, VGA_GFX_MODE, 64); /* mode register: 256 color mode */
1407 WGen (cinfo, VGA_PEL_MSK, 0xff); /* pixel mask: pass-through all planes */
1408 #ifdef CONFIG_PCI
1409 WHDR (cinfo, 0xc0); /* Copy Xbh */
1410 #elif defined(CONFIG_ZORRO)
1411 /* FIXME: CONFIG_PCI and CONFIG_ZORRO may be defined both */
1412 WHDR (cinfo, 0xa0); /* hidden dac reg: nothing special */
1413 #endif
1414 vga_wseq (regbase, VGA_SEQ_MEMORY_MODE, 0x0a); /* memory mode: chain4, ext. memory */
1415 vga_wseq (regbase, VGA_SEQ_PLANE_WRITE, 0xff); /* plane mask: enable writing to all 4 planes */
1416 offset = var->xres_virtual / 4;
1419 /******************************************************
1421 * 32 bpp
1425 else if (var->bits_per_pixel == 32) {
1426 DPRINTK ("cirrusfb: preparing for 24/32 bit deep display\n");
1427 switch (cinfo->btype) {
1428 case BT_SD64:
1429 vga_wseq (regbase, CL_SEQR7, 0xf9); /* Extended Sequencer Mode: 256c col. mode */
1430 vga_wseq (regbase, CL_SEQR1F, 0x1e); /* MCLK select */
1431 break;
1433 case BT_PICCOLO:
1434 vga_wseq (regbase, CL_SEQR7, 0x85);
1435 vga_wseq (regbase, CL_SEQRF, 0xb0); /* Fast Page-Mode writes */
1436 vga_wseq (regbase, CL_SEQR1F, 0x22); /* MCLK select */
1437 break;
1439 case BT_PICASSO:
1440 vga_wseq (regbase, CL_SEQR7, 0x25);
1441 vga_wseq (regbase, CL_SEQRF, 0xb0); /* Fast Page-Mode writes */
1442 vga_wseq (regbase, CL_SEQR1F, 0x22); /* MCLK select */
1443 break;
1445 case BT_SPECTRUM:
1446 vga_wseq (regbase, CL_SEQR7, 0x85);
1447 vga_wseq (regbase, CL_SEQRF, 0xb0); /* Fast Page-Mode writes */
1448 vga_wseq (regbase, CL_SEQR1F, 0x22); /* MCLK select */
1449 break;
1451 case BT_PICASSO4:
1452 vga_wseq (regbase, CL_SEQR7, 0x25);
1453 /* vga_wseq (regbase, CL_SEQR1F, 0x1c); */
1454 break;
1456 case BT_ALPINE:
1457 DPRINTK (" (for GD543x)\n");
1458 vga_wseq (regbase, CL_SEQR7, 0xa9);
1459 cirrusfb_set_mclk (cinfo, regs.mclk, regs.divMCLK);
1460 break;
1462 case BT_GD5480:
1463 DPRINTK (" (for GD5480)\n");
1464 vga_wseq (regbase, CL_SEQR7, 0x19);
1465 /* We already set SRF and SR1F */
1466 break;
1468 case BT_LAGUNA:
1469 DPRINTK (" (for GD546x)\n");
1470 vga_wseq (regbase, CL_SEQR7,
1471 vga_rseq (regbase, CL_SEQR7) & ~0x01);
1472 break;
1474 default:
1475 printk (KERN_WARNING "cirrusfb: unknown Board\n");
1476 break;
1479 vga_wgfx (regbase, VGA_GFX_MODE, 64); /* mode register: 256 color mode */
1480 WGen (cinfo, VGA_PEL_MSK, 0xff); /* pixel mask: pass-through all planes */
1481 WHDR (cinfo, 0xc5); /* hidden dac reg: 8-8-8 mode (24 or 32) */
1482 vga_wseq (regbase, VGA_SEQ_MEMORY_MODE, 0x0a); /* memory mode: chain4, ext. memory */
1483 vga_wseq (regbase, VGA_SEQ_PLANE_WRITE, 0xff); /* plane mask: enable writing to all 4 planes */
1484 offset = var->xres_virtual / 4;
1487 /******************************************************
1489 * unknown/unsupported bpp
1493 else {
1494 printk (KERN_ERR "cirrusfb: What's this?? requested color depth == %d.\n",
1495 var->bits_per_pixel);
1498 vga_wcrt (regbase, VGA_CRTC_OFFSET, offset & 0xff);
1499 tmp = 0x22;
1500 if (offset & 0x100)
1501 tmp |= 0x10; /* offset overflow bit */
1503 vga_wcrt (regbase, CL_CRT1B, tmp); /* screen start addr #16-18, fastpagemode cycles */
1505 if (cinfo->btype == BT_SD64 ||
1506 cinfo->btype == BT_PICASSO4 ||
1507 cinfo->btype == BT_ALPINE ||
1508 cinfo->btype == BT_GD5480)
1509 vga_wcrt (regbase, CL_CRT1D, 0x00); /* screen start address bit 19 */
1511 vga_wcrt (regbase, VGA_CRTC_CURSOR_HI, 0); /* text cursor location high */
1512 vga_wcrt (regbase, VGA_CRTC_CURSOR_LO, 0); /* text cursor location low */
1513 vga_wcrt (regbase, VGA_CRTC_UNDERLINE, 0); /* underline row scanline = at very bottom */
1515 vga_wattr (regbase, VGA_ATC_MODE, 1); /* controller mode */
1516 vga_wattr (regbase, VGA_ATC_OVERSCAN, 0); /* overscan (border) color */
1517 vga_wattr (regbase, VGA_ATC_PLANE_ENABLE, 15); /* color plane enable */
1518 vga_wattr (regbase, CL_AR33, 0); /* pixel panning */
1519 vga_wattr (regbase, VGA_ATC_COLOR_PAGE, 0); /* color select */
1521 /* [ EGS: SetOffset(); ] */
1522 /* From SetOffset(): Turn on VideoEnable bit in Attribute controller */
1523 AttrOn (cinfo);
1525 vga_wgfx (regbase, VGA_GFX_SR_VALUE, 0); /* set/reset register */
1526 vga_wgfx (regbase, VGA_GFX_SR_ENABLE, 0); /* set/reset enable */
1527 vga_wgfx (regbase, VGA_GFX_COMPARE_VALUE, 0); /* color compare */
1528 vga_wgfx (regbase, VGA_GFX_DATA_ROTATE, 0); /* data rotate */
1529 vga_wgfx (regbase, VGA_GFX_PLANE_READ, 0); /* read map select */
1530 vga_wgfx (regbase, VGA_GFX_MISC, 1); /* miscellaneous register */
1531 vga_wgfx (regbase, VGA_GFX_COMPARE_MASK, 15); /* color don't care */
1532 vga_wgfx (regbase, VGA_GFX_BIT_MASK, 255); /* bit mask */
1534 vga_wseq (regbase, CL_SEQR12, 0x0); /* graphics cursor attributes: nothing special */
1536 /* finally, turn on everything - turn off "FullBandwidth" bit */
1537 /* also, set "DotClock%2" bit where requested */
1538 tmp = 0x01;
1540 /*** FB_VMODE_CLOCK_HALVE in linux/fb.h not defined anymore ?
1541 if (var->vmode & FB_VMODE_CLOCK_HALVE)
1542 tmp |= 0x08;
1545 vga_wseq (regbase, VGA_SEQ_CLOCK_MODE, tmp);
1546 DPRINTK ("CL_SEQR1: %d\n", tmp);
1548 cinfo->currentmode = regs;
1549 info->fix.type = regs.type;
1550 info->fix.visual = regs.visual;
1551 info->fix.line_length = regs.line_length;
1553 /* pan to requested offset */
1554 cirrusfb_pan_display (var, info);
1556 #ifdef CIRRUSFB_DEBUG
1557 cirrusfb_dump ();
1558 #endif
1560 DPRINTK ("EXIT\n");
1561 return 0;
1564 /* for some reason incomprehensible to me, cirrusfb requires that you write
1565 * the registers twice for the settings to take..grr. -dte */
1566 static int cirrusfb_set_par (struct fb_info *info)
1568 cirrusfb_set_par_foo (info);
1569 return cirrusfb_set_par_foo (info);
1572 static int cirrusfb_setcolreg (unsigned regno, unsigned red, unsigned green,
1573 unsigned blue, unsigned transp,
1574 struct fb_info *info)
1576 struct cirrusfb_info *cinfo = info->par;
1578 if (regno > 255)
1579 return -EINVAL;
1581 if (info->fix.visual == FB_VISUAL_TRUECOLOR) {
1582 u32 v;
1583 red >>= (16 - info->var.red.length);
1584 green >>= (16 - info->var.green.length);
1585 blue >>= (16 - info->var.blue.length);
1587 if (regno>=16)
1588 return 1;
1589 v = (red << info->var.red.offset) |
1590 (green << info->var.green.offset) |
1591 (blue << info->var.blue.offset);
1593 switch (info->var.bits_per_pixel) {
1594 case 8:
1595 cinfo->pseudo_palette[regno] = v;
1596 break;
1597 case 16:
1598 cinfo->pseudo_palette[regno] = v;
1599 break;
1600 case 24:
1601 case 32:
1602 cinfo->pseudo_palette[regno] = v;
1603 break;
1605 return 0;
1608 cinfo->palette[regno].red = red;
1609 cinfo->palette[regno].green = green;
1610 cinfo->palette[regno].blue = blue;
1612 if (info->var.bits_per_pixel == 8) {
1613 WClut (cinfo, regno, red >> 10, green >> 10, blue >> 10);
1616 return 0;
1620 /*************************************************************************
1621 cirrusfb_pan_display()
1623 performs display panning - provided hardware permits this
1624 **************************************************************************/
1625 static int cirrusfb_pan_display (struct fb_var_screeninfo *var,
1626 struct fb_info *info)
1628 int xoffset = 0;
1629 int yoffset = 0;
1630 unsigned long base;
1631 unsigned char tmp = 0, tmp2 = 0, xpix;
1632 struct cirrusfb_info *cinfo = info->par;
1634 DPRINTK ("ENTER\n");
1635 DPRINTK ("virtual offset: (%d,%d)\n", var->xoffset, var->yoffset);
1637 /* no range checks for xoffset and yoffset, */
1638 /* as fb_pan_display has already done this */
1639 if (var->vmode & FB_VMODE_YWRAP)
1640 return -EINVAL;
1642 info->var.xoffset = var->xoffset;
1643 info->var.yoffset = var->yoffset;
1645 xoffset = var->xoffset * info->var.bits_per_pixel / 8;
1646 yoffset = var->yoffset;
1648 base = yoffset * cinfo->currentmode.line_length + xoffset;
1650 if (info->var.bits_per_pixel == 1) {
1651 /* base is already correct */
1652 xpix = (unsigned char) (var->xoffset % 8);
1653 } else {
1654 base /= 4;
1655 xpix = (unsigned char) ((xoffset % 4) * 2);
1658 cirrusfb_WaitBLT(cinfo->regbase); /* make sure all the BLT's are done */
1660 /* lower 8 + 8 bits of screen start address */
1661 vga_wcrt (cinfo->regbase, VGA_CRTC_START_LO, (unsigned char) (base & 0xff));
1662 vga_wcrt (cinfo->regbase, VGA_CRTC_START_HI, (unsigned char) (base >> 8));
1664 /* construct bits 16, 17 and 18 of screen start address */
1665 if (base & 0x10000)
1666 tmp |= 0x01;
1667 if (base & 0x20000)
1668 tmp |= 0x04;
1669 if (base & 0x40000)
1670 tmp |= 0x08;
1672 tmp2 = (vga_rcrt (cinfo->regbase, CL_CRT1B) & 0xf2) | tmp; /* 0xf2 is %11110010, exclude tmp bits */
1673 vga_wcrt (cinfo->regbase, CL_CRT1B, tmp2);
1675 /* construct bit 19 of screen start address */
1676 if (cirrusfb_board_info[cinfo->btype].scrn_start_bit19) {
1677 tmp2 = 0;
1678 if (base & 0x80000)
1679 tmp2 = 0x80;
1680 vga_wcrt (cinfo->regbase, CL_CRT1D, tmp2);
1683 /* write pixel panning value to AR33; this does not quite work in 8bpp */
1684 /* ### Piccolo..? Will this work? */
1685 if (info->var.bits_per_pixel == 1)
1686 vga_wattr (cinfo->regbase, CL_AR33, xpix);
1688 cirrusfb_WaitBLT (cinfo->regbase);
1690 DPRINTK ("EXIT\n");
1691 return (0);
1695 static int cirrusfb_blank (int blank_mode, struct fb_info *info)
1698 * Blank the screen if blank_mode != 0, else unblank. If blank == NULL
1699 * then the caller blanks by setting the CLUT (Color Look Up Table) to all
1700 * black. Return 0 if blanking succeeded, != 0 if un-/blanking failed due
1701 * to e.g. a video mode which doesn't support it. Implements VESA suspend
1702 * and powerdown modes on hardware that supports disabling hsync/vsync:
1703 * blank_mode == 2: suspend vsync
1704 * blank_mode == 3: suspend hsync
1705 * blank_mode == 4: powerdown
1707 unsigned char val;
1708 struct cirrusfb_info *cinfo = info->par;
1709 int current_mode = cinfo->blank_mode;
1711 DPRINTK ("ENTER, blank mode = %d\n", blank_mode);
1713 if (info->state != FBINFO_STATE_RUNNING ||
1714 current_mode == blank_mode) {
1715 DPRINTK ("EXIT, returning 0\n");
1716 return 0;
1719 /* Undo current */
1720 if (current_mode == FB_BLANK_NORMAL ||
1721 current_mode == FB_BLANK_UNBLANK) {
1722 /* unblank the screen */
1723 val = vga_rseq (cinfo->regbase, VGA_SEQ_CLOCK_MODE);
1724 vga_wseq (cinfo->regbase, VGA_SEQ_CLOCK_MODE, val & 0xdf); /* clear "FullBandwidth" bit */
1725 /* and undo VESA suspend trickery */
1726 vga_wgfx (cinfo->regbase, CL_GRE, 0x00);
1729 /* set new */
1730 if(blank_mode > FB_BLANK_NORMAL) {
1731 /* blank the screen */
1732 val = vga_rseq (cinfo->regbase, VGA_SEQ_CLOCK_MODE);
1733 vga_wseq (cinfo->regbase, VGA_SEQ_CLOCK_MODE, val | 0x20); /* set "FullBandwidth" bit */
1736 switch (blank_mode) {
1737 case FB_BLANK_UNBLANK:
1738 case FB_BLANK_NORMAL:
1739 break;
1740 case FB_BLANK_VSYNC_SUSPEND:
1741 vga_wgfx (cinfo->regbase, CL_GRE, 0x04);
1742 break;
1743 case FB_BLANK_HSYNC_SUSPEND:
1744 vga_wgfx (cinfo->regbase, CL_GRE, 0x02);
1745 break;
1746 case FB_BLANK_POWERDOWN:
1747 vga_wgfx (cinfo->regbase, CL_GRE, 0x06);
1748 break;
1749 default:
1750 DPRINTK ("EXIT, returning 1\n");
1751 return 1;
1754 cinfo->blank_mode = blank_mode;
1755 DPRINTK ("EXIT, returning 0\n");
1757 /* Let fbcon do a soft blank for us */
1758 return (blank_mode == FB_BLANK_NORMAL) ? 1 : 0;
1760 /**** END Hardware specific Routines **************************************/
1761 /****************************************************************************/
1762 /**** BEGIN Internal Routines ***********************************************/
1764 static void init_vgachip (struct cirrusfb_info *cinfo)
1766 const struct cirrusfb_board_info_rec *bi;
1768 DPRINTK ("ENTER\n");
1770 assert (cinfo != NULL);
1772 bi = &cirrusfb_board_info[cinfo->btype];
1774 /* reset board globally */
1775 switch (cinfo->btype) {
1776 case BT_PICCOLO:
1777 WSFR (cinfo, 0x01);
1778 udelay (500);
1779 WSFR (cinfo, 0x51);
1780 udelay (500);
1781 break;
1782 case BT_PICASSO:
1783 WSFR2 (cinfo, 0xff);
1784 udelay (500);
1785 break;
1786 case BT_SD64:
1787 case BT_SPECTRUM:
1788 WSFR (cinfo, 0x1f);
1789 udelay (500);
1790 WSFR (cinfo, 0x4f);
1791 udelay (500);
1792 break;
1793 case BT_PICASSO4:
1794 vga_wcrt (cinfo->regbase, CL_CRT51, 0x00); /* disable flickerfixer */
1795 mdelay (100);
1796 vga_wgfx (cinfo->regbase, CL_GR2F, 0x00); /* from Klaus' NetBSD driver: */
1797 vga_wgfx (cinfo->regbase, CL_GR33, 0x00); /* put blitter into 542x compat */
1798 vga_wgfx (cinfo->regbase, CL_GR31, 0x00); /* mode */
1799 break;
1801 case BT_GD5480:
1802 vga_wgfx (cinfo->regbase, CL_GR2F, 0x00); /* from Klaus' NetBSD driver: */
1803 break;
1805 case BT_ALPINE:
1806 /* Nothing to do to reset the board. */
1807 break;
1809 default:
1810 printk (KERN_ERR "cirrusfb: Warning: Unknown board type\n");
1811 break;
1814 assert (cinfo->size > 0); /* make sure RAM size set by this point */
1816 /* the P4 is not fully initialized here; I rely on it having been */
1817 /* inited under AmigaOS already, which seems to work just fine */
1818 /* (Klaus advised to do it this way) */
1820 if (cinfo->btype != BT_PICASSO4) {
1821 WGen (cinfo, CL_VSSM, 0x10); /* EGS: 0x16 */
1822 WGen (cinfo, CL_POS102, 0x01);
1823 WGen (cinfo, CL_VSSM, 0x08); /* EGS: 0x0e */
1825 if (cinfo->btype != BT_SD64)
1826 WGen (cinfo, CL_VSSM2, 0x01);
1828 vga_wseq (cinfo->regbase, CL_SEQR0, 0x03); /* reset sequencer logic */
1830 vga_wseq (cinfo->regbase, VGA_SEQ_CLOCK_MODE, 0x21); /* FullBandwidth (video off) and 8/9 dot clock */
1831 WGen (cinfo, VGA_MIS_W, 0xc1); /* polarity (-/-), disable access to display memory, VGA_CRTC_START_HI base address: color */
1833 /* vga_wgfx (cinfo->regbase, CL_GRA, 0xce); "magic cookie" - doesn't make any sense to me.. */
1834 vga_wseq (cinfo->regbase, CL_SEQR6, 0x12); /* unlock all extension registers */
1836 vga_wgfx (cinfo->regbase, CL_GR31, 0x04); /* reset blitter */
1838 switch (cinfo->btype) {
1839 case BT_GD5480:
1840 vga_wseq (cinfo->regbase, CL_SEQRF, 0x98);
1841 break;
1842 case BT_ALPINE:
1843 break;
1844 case BT_SD64:
1845 vga_wseq (cinfo->regbase, CL_SEQRF, 0xb8);
1846 break;
1847 default:
1848 vga_wseq (cinfo->regbase, CL_SEQR16, 0x0f);
1849 vga_wseq (cinfo->regbase, CL_SEQRF, 0xb0);
1850 break;
1853 vga_wseq (cinfo->regbase, VGA_SEQ_PLANE_WRITE, 0xff); /* plane mask: nothing */
1854 vga_wseq (cinfo->regbase, VGA_SEQ_CHARACTER_MAP, 0x00); /* character map select: doesn't even matter in gx mode */
1855 vga_wseq (cinfo->regbase, VGA_SEQ_MEMORY_MODE, 0x0e); /* memory mode: chain-4, no odd/even, ext. memory */
1857 /* controller-internal base address of video memory */
1858 if (bi->init_sr07)
1859 vga_wseq (cinfo->regbase, CL_SEQR7, bi->sr07);
1861 /* vga_wseq (cinfo->regbase, CL_SEQR8, 0x00); *//* EEPROM control: shouldn't be necessary to write to this at all.. */
1863 vga_wseq (cinfo->regbase, CL_SEQR10, 0x00); /* graphics cursor X position (incomplete; position gives rem. 3 bits */
1864 vga_wseq (cinfo->regbase, CL_SEQR11, 0x00); /* graphics cursor Y position (..."... ) */
1865 vga_wseq (cinfo->regbase, CL_SEQR12, 0x00); /* graphics cursor attributes */
1866 vga_wseq (cinfo->regbase, CL_SEQR13, 0x00); /* graphics cursor pattern address */
1868 /* writing these on a P4 might give problems.. */
1869 if (cinfo->btype != BT_PICASSO4) {
1870 vga_wseq (cinfo->regbase, CL_SEQR17, 0x00); /* configuration readback and ext. color */
1871 vga_wseq (cinfo->regbase, CL_SEQR18, 0x02); /* signature generator */
1874 /* MCLK select etc. */
1875 if (bi->init_sr1f)
1876 vga_wseq (cinfo->regbase, CL_SEQR1F, bi->sr1f);
1878 vga_wcrt (cinfo->regbase, VGA_CRTC_PRESET_ROW, 0x00); /* Screen A preset row scan: none */
1879 vga_wcrt (cinfo->regbase, VGA_CRTC_CURSOR_START, 0x20); /* Text cursor start: disable text cursor */
1880 vga_wcrt (cinfo->regbase, VGA_CRTC_CURSOR_END, 0x00); /* Text cursor end: - */
1881 vga_wcrt (cinfo->regbase, VGA_CRTC_START_HI, 0x00); /* Screen start address high: 0 */
1882 vga_wcrt (cinfo->regbase, VGA_CRTC_START_LO, 0x00); /* Screen start address low: 0 */
1883 vga_wcrt (cinfo->regbase, VGA_CRTC_CURSOR_HI, 0x00); /* text cursor location high: 0 */
1884 vga_wcrt (cinfo->regbase, VGA_CRTC_CURSOR_LO, 0x00); /* text cursor location low: 0 */
1886 vga_wcrt (cinfo->regbase, VGA_CRTC_UNDERLINE, 0x00); /* Underline Row scanline: - */
1887 vga_wcrt (cinfo->regbase, VGA_CRTC_MODE, 0xc3); /* mode control: timing enable, byte mode, no compat modes */
1888 vga_wcrt (cinfo->regbase, VGA_CRTC_LINE_COMPARE, 0x00); /* Line Compare: not needed */
1889 /* ### add 0x40 for text modes with > 30 MHz pixclock */
1890 vga_wcrt (cinfo->regbase, CL_CRT1B, 0x02); /* ext. display controls: ext.adr. wrap */
1892 vga_wgfx (cinfo->regbase, VGA_GFX_SR_VALUE, 0x00); /* Set/Reset registes: - */
1893 vga_wgfx (cinfo->regbase, VGA_GFX_SR_ENABLE, 0x00); /* Set/Reset enable: - */
1894 vga_wgfx (cinfo->regbase, VGA_GFX_COMPARE_VALUE, 0x00); /* Color Compare: - */
1895 vga_wgfx (cinfo->regbase, VGA_GFX_DATA_ROTATE, 0x00); /* Data Rotate: - */
1896 vga_wgfx (cinfo->regbase, VGA_GFX_PLANE_READ, 0x00); /* Read Map Select: - */
1897 vga_wgfx (cinfo->regbase, VGA_GFX_MODE, 0x00); /* Mode: conf. for 16/4/2 color mode, no odd/even, read/write mode 0 */
1898 vga_wgfx (cinfo->regbase, VGA_GFX_MISC, 0x01); /* Miscellaneous: memory map base address, graphics mode */
1899 vga_wgfx (cinfo->regbase, VGA_GFX_COMPARE_MASK, 0x0f); /* Color Don't care: involve all planes */
1900 vga_wgfx (cinfo->regbase, VGA_GFX_BIT_MASK, 0xff); /* Bit Mask: no mask at all */
1901 if (cinfo->btype == BT_ALPINE)
1902 vga_wgfx (cinfo->regbase, CL_GRB, 0x20); /* (5434 can't have bit 3 set for bitblt) */
1903 else
1904 vga_wgfx (cinfo->regbase, CL_GRB, 0x28); /* Graphics controller mode extensions: finer granularity, 8byte data latches */
1906 vga_wgfx (cinfo->regbase, CL_GRC, 0xff); /* Color Key compare: - */
1907 vga_wgfx (cinfo->regbase, CL_GRD, 0x00); /* Color Key compare mask: - */
1908 vga_wgfx (cinfo->regbase, CL_GRE, 0x00); /* Miscellaneous control: - */
1909 /* vga_wgfx (cinfo->regbase, CL_GR10, 0x00); *//* Background color byte 1: - */
1910 /* vga_wgfx (cinfo->regbase, CL_GR11, 0x00); */
1912 vga_wattr (cinfo->regbase, VGA_ATC_PALETTE0, 0x00); /* Attribute Controller palette registers: "identity mapping" */
1913 vga_wattr (cinfo->regbase, VGA_ATC_PALETTE1, 0x01);
1914 vga_wattr (cinfo->regbase, VGA_ATC_PALETTE2, 0x02);
1915 vga_wattr (cinfo->regbase, VGA_ATC_PALETTE3, 0x03);
1916 vga_wattr (cinfo->regbase, VGA_ATC_PALETTE4, 0x04);
1917 vga_wattr (cinfo->regbase, VGA_ATC_PALETTE5, 0x05);
1918 vga_wattr (cinfo->regbase, VGA_ATC_PALETTE6, 0x06);
1919 vga_wattr (cinfo->regbase, VGA_ATC_PALETTE7, 0x07);
1920 vga_wattr (cinfo->regbase, VGA_ATC_PALETTE8, 0x08);
1921 vga_wattr (cinfo->regbase, VGA_ATC_PALETTE9, 0x09);
1922 vga_wattr (cinfo->regbase, VGA_ATC_PALETTEA, 0x0a);
1923 vga_wattr (cinfo->regbase, VGA_ATC_PALETTEB, 0x0b);
1924 vga_wattr (cinfo->regbase, VGA_ATC_PALETTEC, 0x0c);
1925 vga_wattr (cinfo->regbase, VGA_ATC_PALETTED, 0x0d);
1926 vga_wattr (cinfo->regbase, VGA_ATC_PALETTEE, 0x0e);
1927 vga_wattr (cinfo->regbase, VGA_ATC_PALETTEF, 0x0f);
1929 vga_wattr (cinfo->regbase, VGA_ATC_MODE, 0x01); /* Attribute Controller mode: graphics mode */
1930 vga_wattr (cinfo->regbase, VGA_ATC_OVERSCAN, 0x00); /* Overscan color reg.: reg. 0 */
1931 vga_wattr (cinfo->regbase, VGA_ATC_PLANE_ENABLE, 0x0f); /* Color Plane enable: Enable all 4 planes */
1932 /* ### vga_wattr (cinfo->regbase, CL_AR33, 0x00); * Pixel Panning: - */
1933 vga_wattr (cinfo->regbase, VGA_ATC_COLOR_PAGE, 0x00); /* Color Select: - */
1935 WGen (cinfo, VGA_PEL_MSK, 0xff); /* Pixel mask: no mask */
1937 if (cinfo->btype != BT_ALPINE && cinfo->btype != BT_GD5480)
1938 WGen (cinfo, VGA_MIS_W, 0xc3); /* polarity (-/-), enable display mem, VGA_CRTC_START_HI i/o base = color */
1940 vga_wgfx (cinfo->regbase, CL_GR31, 0x04); /* BLT Start/status: Blitter reset */
1941 vga_wgfx (cinfo->regbase, CL_GR31, 0x00); /* - " - : "end-of-reset" */
1943 /* misc... */
1944 WHDR (cinfo, 0); /* Hidden DAC register: - */
1946 printk (KERN_DEBUG "cirrusfb: This board has %ld bytes of DRAM memory\n", cinfo->size);
1947 DPRINTK ("EXIT\n");
1948 return;
1951 static void switch_monitor (struct cirrusfb_info *cinfo, int on)
1953 #ifdef CONFIG_ZORRO /* only works on Zorro boards */
1954 static int IsOn = 0; /* XXX not ok for multiple boards */
1956 DPRINTK ("ENTER\n");
1958 if (cinfo->btype == BT_PICASSO4)
1959 return; /* nothing to switch */
1960 if (cinfo->btype == BT_ALPINE)
1961 return; /* nothing to switch */
1962 if (cinfo->btype == BT_GD5480)
1963 return; /* nothing to switch */
1964 if (cinfo->btype == BT_PICASSO) {
1965 if ((on && !IsOn) || (!on && IsOn))
1966 WSFR (cinfo, 0xff);
1968 DPRINTK ("EXIT\n");
1969 return;
1971 if (on) {
1972 switch (cinfo->btype) {
1973 case BT_SD64:
1974 WSFR (cinfo, cinfo->SFR | 0x21);
1975 break;
1976 case BT_PICCOLO:
1977 WSFR (cinfo, cinfo->SFR | 0x28);
1978 break;
1979 case BT_SPECTRUM:
1980 WSFR (cinfo, 0x6f);
1981 break;
1982 default: /* do nothing */ break;
1984 } else {
1985 switch (cinfo->btype) {
1986 case BT_SD64:
1987 WSFR (cinfo, cinfo->SFR & 0xde);
1988 break;
1989 case BT_PICCOLO:
1990 WSFR (cinfo, cinfo->SFR & 0xd7);
1991 break;
1992 case BT_SPECTRUM:
1993 WSFR (cinfo, 0x4f);
1994 break;
1995 default: /* do nothing */ break;
1999 DPRINTK ("EXIT\n");
2000 #endif /* CONFIG_ZORRO */
2004 /******************************************/
2005 /* Linux 2.6-style accelerated functions */
2006 /******************************************/
2008 static void cirrusfb_prim_fillrect(struct cirrusfb_info *cinfo,
2009 const struct fb_fillrect *region)
2011 int m; /* bytes per pixel */
2012 u32 color = (cinfo->info->fix.visual == FB_VISUAL_TRUECOLOR) ?
2013 cinfo->pseudo_palette[region->color] : region->color;
2015 if(cinfo->info->var.bits_per_pixel == 1) {
2016 cirrusfb_RectFill(cinfo->regbase, cinfo->info->var.bits_per_pixel,
2017 region->dx / 8, region->dy,
2018 region->width / 8, region->height,
2019 color,
2020 cinfo->currentmode.line_length);
2021 } else {
2022 m = ( cinfo->info->var.bits_per_pixel + 7 ) / 8;
2023 cirrusfb_RectFill(cinfo->regbase, cinfo->info->var.bits_per_pixel,
2024 region->dx * m, region->dy,
2025 region->width * m, region->height,
2026 color,
2027 cinfo->currentmode.line_length);
2029 return;
2032 static void cirrusfb_fillrect (struct fb_info *info, const struct fb_fillrect *region)
2034 struct cirrusfb_info *cinfo = info->par;
2035 struct fb_fillrect modded;
2036 int vxres, vyres;
2038 if (info->state != FBINFO_STATE_RUNNING)
2039 return;
2040 if (info->flags & FBINFO_HWACCEL_DISABLED) {
2041 cfb_fillrect(info, region);
2042 return;
2045 vxres = info->var.xres_virtual;
2046 vyres = info->var.yres_virtual;
2048 memcpy(&modded, region, sizeof(struct fb_fillrect));
2050 if(!modded.width || !modded.height ||
2051 modded.dx >= vxres || modded.dy >= vyres)
2052 return;
2054 if(modded.dx + modded.width > vxres) modded.width = vxres - modded.dx;
2055 if(modded.dy + modded.height > vyres) modded.height = vyres - modded.dy;
2057 cirrusfb_prim_fillrect(cinfo, &modded);
2060 static void cirrusfb_prim_copyarea(struct cirrusfb_info *cinfo,
2061 const struct fb_copyarea *area)
2063 int m; /* bytes per pixel */
2064 if(cinfo->info->var.bits_per_pixel == 1) {
2065 cirrusfb_BitBLT(cinfo->regbase, cinfo->info->var.bits_per_pixel,
2066 area->sx / 8, area->sy,
2067 area->dx / 8, area->dy,
2068 area->width / 8, area->height,
2069 cinfo->currentmode.line_length);
2070 } else {
2071 m = ( cinfo->info->var.bits_per_pixel + 7 ) / 8;
2072 cirrusfb_BitBLT(cinfo->regbase, cinfo->info->var.bits_per_pixel,
2073 area->sx * m, area->sy,
2074 area->dx * m, area->dy,
2075 area->width * m, area->height,
2076 cinfo->currentmode.line_length);
2078 return;
2082 static void cirrusfb_copyarea(struct fb_info *info, const struct fb_copyarea *area)
2084 struct cirrusfb_info *cinfo = info->par;
2085 struct fb_copyarea modded;
2086 u32 vxres, vyres;
2087 modded.sx = area->sx;
2088 modded.sy = area->sy;
2089 modded.dx = area->dx;
2090 modded.dy = area->dy;
2091 modded.width = area->width;
2092 modded.height = area->height;
2094 if (info->state != FBINFO_STATE_RUNNING)
2095 return;
2096 if (info->flags & FBINFO_HWACCEL_DISABLED) {
2097 cfb_copyarea(info, area);
2098 return;
2101 vxres = info->var.xres_virtual;
2102 vyres = info->var.yres_virtual;
2104 if(!modded.width || !modded.height ||
2105 modded.sx >= vxres || modded.sy >= vyres ||
2106 modded.dx >= vxres || modded.dy >= vyres)
2107 return;
2109 if(modded.sx + modded.width > vxres) modded.width = vxres - modded.sx;
2110 if(modded.dx + modded.width > vxres) modded.width = vxres - modded.dx;
2111 if(modded.sy + modded.height > vyres) modded.height = vyres - modded.sy;
2112 if(modded.dy + modded.height > vyres) modded.height = vyres - modded.dy;
2114 cirrusfb_prim_copyarea(cinfo, &modded);
2117 static void cirrusfb_imageblit(struct fb_info *info, const struct fb_image *image)
2119 struct cirrusfb_info *cinfo = info->par;
2121 cirrusfb_WaitBLT(cinfo->regbase);
2122 cfb_imageblit(info, image);
2126 #ifdef CONFIG_PPC_PREP
2127 #define PREP_VIDEO_BASE ((volatile unsigned long) 0xC0000000)
2128 #define PREP_IO_BASE ((volatile unsigned char *) 0x80000000)
2129 static void get_prep_addrs (unsigned long *display, unsigned long *registers)
2131 DPRINTK ("ENTER\n");
2133 *display = PREP_VIDEO_BASE;
2134 *registers = (unsigned long) PREP_IO_BASE;
2136 DPRINTK ("EXIT\n");
2139 #endif /* CONFIG_PPC_PREP */
2142 #ifdef CONFIG_PCI
2143 static int release_io_ports = 0;
2145 /* Pulled the logic from XFree86 Cirrus driver to get the memory size,
2146 * based on the DRAM bandwidth bit and DRAM bank switching bit. This
2147 * works with 1MB, 2MB and 4MB configurations (which the Motorola boards
2148 * seem to have. */
2149 static unsigned int cirrusfb_get_memsize (u8 __iomem *regbase)
2151 unsigned long mem;
2152 unsigned char SRF;
2154 DPRINTK ("ENTER\n");
2156 SRF = vga_rseq (regbase, CL_SEQRF);
2157 switch ((SRF & 0x18)) {
2158 case 0x08: mem = 512 * 1024; break;
2159 case 0x10: mem = 1024 * 1024; break;
2160 /* 64-bit DRAM data bus width; assume 2MB. Also indicates 2MB memory
2161 * on the 5430. */
2162 case 0x18: mem = 2048 * 1024; break;
2163 default: printk ("CLgenfb: Unknown memory size!\n");
2164 mem = 1024 * 1024;
2166 if (SRF & 0x80) {
2167 /* If DRAM bank switching is enabled, there must be twice as much
2168 * memory installed. (4MB on the 5434) */
2169 mem *= 2;
2171 /* TODO: Handling of GD5446/5480 (see XF86 sources ...) */
2173 DPRINTK ("EXIT\n");
2174 return mem;
2179 static void get_pci_addrs (const struct pci_dev *pdev,
2180 unsigned long *display, unsigned long *registers)
2182 assert (pdev != NULL);
2183 assert (display != NULL);
2184 assert (registers != NULL);
2186 DPRINTK ("ENTER\n");
2188 *display = 0;
2189 *registers = 0;
2191 /* This is a best-guess for now */
2193 if (pci_resource_flags(pdev, 0) & IORESOURCE_IO) {
2194 *display = pci_resource_start(pdev, 1);
2195 *registers = pci_resource_start(pdev, 0);
2196 } else {
2197 *display = pci_resource_start(pdev, 0);
2198 *registers = pci_resource_start(pdev, 1);
2201 assert (*display != 0);
2203 DPRINTK ("EXIT\n");
2207 static void cirrusfb_pci_unmap (struct cirrusfb_info *cinfo)
2209 struct pci_dev *pdev = cinfo->pdev;
2211 iounmap(cinfo->fbmem);
2212 #if 0 /* if system didn't claim this region, we would... */
2213 release_mem_region(0xA0000, 65535);
2214 #endif
2215 if (release_io_ports)
2216 release_region(0x3C0, 32);
2217 pci_release_regions(pdev);
2218 framebuffer_release(cinfo->info);
2220 #endif /* CONFIG_PCI */
2223 #ifdef CONFIG_ZORRO
2224 static void __devexit cirrusfb_zorro_unmap (struct cirrusfb_info *cinfo)
2226 zorro_release_device(cinfo->zdev);
2228 if (cinfo->btype == BT_PICASSO4) {
2229 cinfo->regbase -= 0x600000;
2230 iounmap ((void *)cinfo->regbase);
2231 iounmap ((void *)cinfo->fbmem);
2232 } else {
2233 if (zorro_resource_start(cinfo->zdev) > 0x01000000)
2234 iounmap ((void *)cinfo->fbmem);
2236 framebuffer_release(cinfo->info);
2238 #endif /* CONFIG_ZORRO */
2240 static int cirrusfb_set_fbinfo(struct cirrusfb_info *cinfo)
2242 struct fb_info *info = cinfo->info;
2243 struct fb_var_screeninfo *var = &info->var;
2245 info->par = cinfo;
2246 info->pseudo_palette = cinfo->pseudo_palette;
2247 info->flags = FBINFO_DEFAULT
2248 | FBINFO_HWACCEL_XPAN
2249 | FBINFO_HWACCEL_YPAN
2250 | FBINFO_HWACCEL_FILLRECT
2251 | FBINFO_HWACCEL_COPYAREA;
2252 if (noaccel)
2253 info->flags |= FBINFO_HWACCEL_DISABLED;
2254 info->fbops = &cirrusfb_ops;
2255 info->screen_base = cinfo->fbmem;
2256 if (cinfo->btype == BT_GD5480) {
2257 if (var->bits_per_pixel == 16)
2258 info->screen_base += 1 * MB_;
2259 if (var->bits_per_pixel == 24 || var->bits_per_pixel == 32)
2260 info->screen_base += 2 * MB_;
2263 /* Fill fix common fields */
2264 strlcpy(info->fix.id, cirrusfb_board_info[cinfo->btype].name,
2265 sizeof(info->fix.id));
2267 /* monochrome: only 1 memory plane */
2268 /* 8 bit and above: Use whole memory area */
2269 info->fix.smem_start = cinfo->fbmem_phys;
2270 info->fix.smem_len = (var->bits_per_pixel == 1) ? cinfo->size / 4 : cinfo->size;
2271 info->fix.type = cinfo->currentmode.type;
2272 info->fix.type_aux = 0;
2273 info->fix.visual = cinfo->currentmode.visual;
2274 info->fix.xpanstep = 1;
2275 info->fix.ypanstep = 1;
2276 info->fix.ywrapstep = 0;
2277 info->fix.line_length = cinfo->currentmode.line_length;
2279 /* FIXME: map region at 0xB8000 if available, fill in here */
2280 info->fix.mmio_start = cinfo->fbregs_phys;
2281 info->fix.mmio_len = 0;
2282 info->fix.accel = FB_ACCEL_NONE;
2284 fb_alloc_cmap(&info->cmap, 256, 0);
2286 return 0;
2289 static int cirrusfb_register(struct cirrusfb_info *cinfo)
2291 struct fb_info *info;
2292 int err;
2293 cirrusfb_board_t btype;
2295 DPRINTK ("ENTER\n");
2297 printk (KERN_INFO "cirrusfb: Driver for Cirrus Logic based graphic boards, v" CIRRUSFB_VERSION "\n");
2299 info = cinfo->info;
2300 btype = cinfo->btype;
2302 /* sanity checks */
2303 assert (btype != BT_NONE);
2305 DPRINTK ("cirrusfb: (RAM start set to: 0x%p)\n", cinfo->fbmem);
2307 /* Make pretend we've set the var so our structures are in a "good" */
2308 /* state, even though we haven't written the mode to the hw yet... */
2309 info->var = cirrusfb_predefined[cirrusfb_def_mode].var;
2310 info->var.activate = FB_ACTIVATE_NOW;
2312 err = cirrusfb_decode_var(&info->var, &cinfo->currentmode, info);
2313 if (err < 0) {
2314 /* should never happen */
2315 DPRINTK("choking on default var... umm, no good.\n");
2316 goto err_unmap_cirrusfb;
2319 /* set all the vital stuff */
2320 cirrusfb_set_fbinfo(cinfo);
2322 err = register_framebuffer(info);
2323 if (err < 0) {
2324 printk (KERN_ERR "cirrusfb: could not register fb device; err = %d!\n", err);
2325 goto err_dealloc_cmap;
2328 DPRINTK ("EXIT, returning 0\n");
2329 return 0;
2331 err_dealloc_cmap:
2332 fb_dealloc_cmap(&info->cmap);
2333 err_unmap_cirrusfb:
2334 cinfo->unmap(cinfo);
2335 return err;
2338 static void __devexit cirrusfb_cleanup (struct fb_info *info)
2340 struct cirrusfb_info *cinfo = info->par;
2341 DPRINTK ("ENTER\n");
2343 switch_monitor (cinfo, 0);
2345 unregister_framebuffer (info);
2346 fb_dealloc_cmap (&info->cmap);
2347 printk ("Framebuffer unregistered\n");
2348 cinfo->unmap(cinfo);
2350 DPRINTK ("EXIT\n");
2354 #ifdef CONFIG_PCI
2355 static int cirrusfb_pci_register (struct pci_dev *pdev,
2356 const struct pci_device_id *ent)
2358 struct cirrusfb_info *cinfo;
2359 struct fb_info *info;
2360 cirrusfb_board_t btype;
2361 unsigned long board_addr, board_size;
2362 int ret;
2364 ret = pci_enable_device(pdev);
2365 if (ret < 0) {
2366 printk(KERN_ERR "cirrusfb: Cannot enable PCI device\n");
2367 goto err_out;
2370 info = framebuffer_alloc(sizeof(struct cirrusfb_info), &pdev->dev);
2371 if (!info) {
2372 printk(KERN_ERR "cirrusfb: could not allocate memory\n");
2373 ret = -ENOMEM;
2374 goto err_disable;
2377 cinfo = info->par;
2378 cinfo->info = info;
2379 cinfo->pdev = pdev;
2380 cinfo->btype = btype = (cirrusfb_board_t) ent->driver_data;
2382 DPRINTK (" Found PCI device, base address 0 is 0x%lx, btype set to %d\n",
2383 pdev->resource[0].start, btype);
2384 DPRINTK (" base address 1 is 0x%lx\n", pdev->resource[1].start);
2386 if(isPReP) {
2387 pci_write_config_dword (pdev, PCI_BASE_ADDRESS_0, 0x00000000);
2388 #ifdef CONFIG_PPC_PREP
2389 get_prep_addrs (&board_addr, &cinfo->fbregs_phys);
2390 #endif
2391 /* PReP dies if we ioremap the IO registers, but it works w/out... */
2392 cinfo->regbase = (char __iomem *) cinfo->fbregs_phys;
2393 } else {
2394 DPRINTK ("Attempt to get PCI info for Cirrus Graphics Card\n");
2395 get_pci_addrs (pdev, &board_addr, &cinfo->fbregs_phys);
2396 cinfo->regbase = NULL; /* FIXME: this forces VGA. alternatives? */
2399 DPRINTK ("Board address: 0x%lx, register address: 0x%lx\n", board_addr, cinfo->fbregs_phys);
2401 board_size = (btype == BT_GD5480) ?
2402 32 * MB_ : cirrusfb_get_memsize (cinfo->regbase);
2404 ret = pci_request_regions(pdev, "cirrusfb");
2405 if (ret <0) {
2406 printk(KERN_ERR "cirrusfb: cannot reserve region 0x%lx, abort\n",
2407 board_addr);
2408 goto err_release_fb;
2410 #if 0 /* if the system didn't claim this region, we would... */
2411 if (!request_mem_region(0xA0000, 65535, "cirrusfb")) {
2412 printk(KERN_ERR "cirrusfb: cannot reserve region 0x%lx, abort\n"
2414 0xA0000L);
2415 ret = -EBUSY;
2416 goto err_release_regions;
2418 #endif
2419 if (request_region(0x3C0, 32, "cirrusfb"))
2420 release_io_ports = 1;
2422 cinfo->fbmem = ioremap(board_addr, board_size);
2423 if (!cinfo->fbmem) {
2424 ret = -EIO;
2425 goto err_release_legacy;
2428 cinfo->fbmem_phys = board_addr;
2429 cinfo->size = board_size;
2430 cinfo->unmap = cirrusfb_pci_unmap;
2432 printk (" RAM (%lu kB) at 0xx%lx, ", cinfo->size / KB_, board_addr);
2433 printk ("Cirrus Logic chipset on PCI bus\n");
2434 pci_set_drvdata(pdev, info);
2436 ret = cirrusfb_register(cinfo);
2437 if (ret)
2438 iounmap(cinfo->fbmem);
2439 return ret;
2441 err_release_legacy:
2442 if (release_io_ports)
2443 release_region(0x3C0, 32);
2444 #if 0
2445 release_mem_region(0xA0000, 65535);
2446 err_release_regions:
2447 #endif
2448 pci_release_regions(pdev);
2449 err_release_fb:
2450 framebuffer_release(info);
2451 err_disable:
2452 err_out:
2453 return ret;
2456 static void __devexit cirrusfb_pci_unregister (struct pci_dev *pdev)
2458 struct fb_info *info = pci_get_drvdata(pdev);
2459 DPRINTK ("ENTER\n");
2461 cirrusfb_cleanup (info);
2463 DPRINTK ("EXIT\n");
2466 static struct pci_driver cirrusfb_pci_driver = {
2467 .name = "cirrusfb",
2468 .id_table = cirrusfb_pci_table,
2469 .probe = cirrusfb_pci_register,
2470 .remove = __devexit_p(cirrusfb_pci_unregister),
2471 #ifdef CONFIG_PM
2472 #if 0
2473 .suspend = cirrusfb_pci_suspend,
2474 .resume = cirrusfb_pci_resume,
2475 #endif
2476 #endif
2478 #endif /* CONFIG_PCI */
2481 #ifdef CONFIG_ZORRO
2482 static int cirrusfb_zorro_register(struct zorro_dev *z,
2483 const struct zorro_device_id *ent)
2485 struct cirrusfb_info *cinfo;
2486 struct fb_info *info;
2487 cirrusfb_board_t btype;
2488 struct zorro_dev *z2 = NULL;
2489 unsigned long board_addr, board_size, size;
2490 int ret;
2492 btype = ent->driver_data;
2493 if (cirrusfb_zorro_table2[btype].id2)
2494 z2 = zorro_find_device(cirrusfb_zorro_table2[btype].id2, NULL);
2495 size = cirrusfb_zorro_table2[btype].size;
2496 printk(KERN_INFO "cirrusfb: %s board detected; ",
2497 cirrusfb_board_info[btype].name);
2499 info = framebuffer_alloc(sizeof(struct cirrusfb_info), &z->dev);
2500 if (!info) {
2501 printk (KERN_ERR "cirrusfb: could not allocate memory\n");
2502 ret = -ENOMEM;
2503 goto err_out;
2506 cinfo = info->par;
2507 cinfo->info = info;
2508 cinfo->btype = btype;
2510 assert (z > 0);
2511 assert (z2 >= 0);
2512 assert (btype != BT_NONE);
2514 cinfo->zdev = z;
2515 board_addr = zorro_resource_start(z);
2516 board_size = zorro_resource_len(z);
2517 cinfo->size = size;
2519 if (!zorro_request_device(z, "cirrusfb")) {
2520 printk(KERN_ERR "cirrusfb: cannot reserve region 0x%lx, abort\n",
2521 board_addr);
2522 ret = -EBUSY;
2523 goto err_release_fb;
2526 printk (" RAM (%lu MB) at $%lx, ", board_size / MB_, board_addr);
2528 ret = -EIO;
2530 if (btype == BT_PICASSO4) {
2531 printk (" REG at $%lx\n", board_addr + 0x600000);
2533 /* To be precise, for the P4 this is not the */
2534 /* begin of the board, but the begin of RAM. */
2535 /* for P4, map in its address space in 2 chunks (### TEST! ) */
2536 /* (note the ugly hardcoded 16M number) */
2537 cinfo->regbase = ioremap (board_addr, 16777216);
2538 if (!cinfo->regbase)
2539 goto err_release_region;
2541 DPRINTK ("cirrusfb: Virtual address for board set to: $%p\n", cinfo->regbase);
2542 cinfo->regbase += 0x600000;
2543 cinfo->fbregs_phys = board_addr + 0x600000;
2545 cinfo->fbmem_phys = board_addr + 16777216;
2546 cinfo->fbmem = ioremap (cinfo->fbmem_phys, 16777216);
2547 if (!cinfo->fbmem)
2548 goto err_unmap_regbase;
2549 } else {
2550 printk (" REG at $%lx\n", (unsigned long) z2->resource.start);
2552 cinfo->fbmem_phys = board_addr;
2553 if (board_addr > 0x01000000)
2554 cinfo->fbmem = ioremap (board_addr, board_size);
2555 else
2556 cinfo->fbmem = (caddr_t) ZTWO_VADDR (board_addr);
2557 if (!cinfo->fbmem)
2558 goto err_release_region;
2560 /* set address for REG area of board */
2561 cinfo->regbase = (caddr_t) ZTWO_VADDR (z2->resource.start);
2562 cinfo->fbregs_phys = z2->resource.start;
2564 DPRINTK ("cirrusfb: Virtual address for board set to: $%p\n", cinfo->regbase);
2566 cinfo->unmap = cirrusfb_zorro_unmap;
2568 printk (KERN_INFO "Cirrus Logic chipset on Zorro bus\n");
2569 zorro_set_drvdata(z, info);
2571 ret = cirrusfb_register(cinfo);
2572 if (ret) {
2573 if (btype == BT_PICASSO4) {
2574 iounmap(cinfo->fbmem);
2575 iounmap(cinfo->regbase - 0x600000);
2576 } else if (board_addr > 0x01000000)
2577 iounmap(cinfo->fbmem);
2579 return ret;
2581 err_unmap_regbase:
2582 /* Parental advisory: explicit hack */
2583 iounmap(cinfo->regbase - 0x600000);
2584 err_release_region:
2585 release_region(board_addr, board_size);
2586 err_release_fb:
2587 framebuffer_release(info);
2588 err_out:
2589 return ret;
2592 void __devexit cirrusfb_zorro_unregister(struct zorro_dev *z)
2594 struct fb_info *info = zorro_get_drvdata(z);
2595 DPRINTK ("ENTER\n");
2597 cirrusfb_cleanup (info);
2599 DPRINTK ("EXIT\n");
2602 static struct zorro_driver cirrusfb_zorro_driver = {
2603 .name = "cirrusfb",
2604 .id_table = cirrusfb_zorro_table,
2605 .probe = cirrusfb_zorro_register,
2606 .remove = __devexit_p(cirrusfb_zorro_unregister),
2608 #endif /* CONFIG_ZORRO */
2610 static int __init cirrusfb_init(void)
2612 int error = 0;
2614 #ifndef MODULE
2615 char *option = NULL;
2617 if (fb_get_options("cirrusfb", &option))
2618 return -ENODEV;
2619 cirrusfb_setup(option);
2620 #endif
2622 #ifdef CONFIG_ZORRO
2623 error |= zorro_register_driver(&cirrusfb_zorro_driver);
2624 #endif
2625 #ifdef CONFIG_PCI
2626 error |= pci_register_driver(&cirrusfb_pci_driver);
2627 #endif
2628 return error;
2633 #ifndef MODULE
2634 static int __init cirrusfb_setup(char *options) {
2635 char *this_opt, s[32];
2636 int i;
2638 DPRINTK ("ENTER\n");
2640 if (!options || !*options)
2641 return 0;
2643 while ((this_opt = strsep (&options, ",")) != NULL) {
2644 if (!*this_opt) continue;
2646 DPRINTK("cirrusfb_setup: option '%s'\n", this_opt);
2648 for (i = 0; i < NUM_TOTAL_MODES; i++) {
2649 sprintf (s, "mode:%s", cirrusfb_predefined[i].name);
2650 if (strcmp (this_opt, s) == 0)
2651 cirrusfb_def_mode = i;
2653 if (!strcmp(this_opt, "noaccel"))
2654 noaccel = 1;
2656 return 0;
2658 #endif
2662 * Modularization
2665 MODULE_AUTHOR("Copyright 1999,2000 Jeff Garzik <jgarzik@pobox.com>");
2666 MODULE_DESCRIPTION("Accelerated FBDev driver for Cirrus Logic chips");
2667 MODULE_LICENSE("GPL");
2669 static void __exit cirrusfb_exit (void)
2671 #ifdef CONFIG_PCI
2672 pci_unregister_driver(&cirrusfb_pci_driver);
2673 #endif
2674 #ifdef CONFIG_ZORRO
2675 zorro_unregister_driver(&cirrusfb_zorro_driver);
2676 #endif
2679 module_init(cirrusfb_init);
2681 #ifdef MODULE
2682 module_exit(cirrusfb_exit);
2683 #endif
2686 /**********************************************************************/
2687 /* about the following functions - I have used the same names for the */
2688 /* functions as Markus Wild did in his Retina driver for NetBSD as */
2689 /* they just made sense for this purpose. Apart from that, I wrote */
2690 /* these functions myself. */
2691 /**********************************************************************/
2693 /*** WGen() - write into one of the external/general registers ***/
2694 static void WGen (const struct cirrusfb_info *cinfo,
2695 int regnum, unsigned char val)
2697 unsigned long regofs = 0;
2699 if (cinfo->btype == BT_PICASSO) {
2700 /* Picasso II specific hack */
2701 /* if (regnum == VGA_PEL_IR || regnum == VGA_PEL_D || regnum == CL_VSSM2) */
2702 if (regnum == VGA_PEL_IR || regnum == VGA_PEL_D)
2703 regofs = 0xfff;
2706 vga_w (cinfo->regbase, regofs + regnum, val);
2709 /*** RGen() - read out one of the external/general registers ***/
2710 static unsigned char RGen (const struct cirrusfb_info *cinfo, int regnum)
2712 unsigned long regofs = 0;
2714 if (cinfo->btype == BT_PICASSO) {
2715 /* Picasso II specific hack */
2716 /* if (regnum == VGA_PEL_IR || regnum == VGA_PEL_D || regnum == CL_VSSM2) */
2717 if (regnum == VGA_PEL_IR || regnum == VGA_PEL_D)
2718 regofs = 0xfff;
2721 return vga_r (cinfo->regbase, regofs + regnum);
2724 /*** AttrOn() - turn on VideoEnable for Attribute controller ***/
2725 static void AttrOn (const struct cirrusfb_info *cinfo)
2727 assert (cinfo != NULL);
2729 DPRINTK ("ENTER\n");
2731 if (vga_rcrt (cinfo->regbase, CL_CRT24) & 0x80) {
2732 /* if we're just in "write value" mode, write back the */
2733 /* same value as before to not modify anything */
2734 vga_w (cinfo->regbase, VGA_ATT_IW,
2735 vga_r (cinfo->regbase, VGA_ATT_R));
2737 /* turn on video bit */
2738 /* vga_w (cinfo->regbase, VGA_ATT_IW, 0x20); */
2739 vga_w (cinfo->regbase, VGA_ATT_IW, 0x33);
2741 /* dummy write on Reg0 to be on "write index" mode next time */
2742 vga_w (cinfo->regbase, VGA_ATT_IW, 0x00);
2744 DPRINTK ("EXIT\n");
2747 /*** WHDR() - write into the Hidden DAC register ***/
2748 /* as the HDR is the only extension register that requires special treatment
2749 * (the other extension registers are accessible just like the "ordinary"
2750 * registers of their functional group) here is a specialized routine for
2751 * accessing the HDR
2753 static void WHDR (const struct cirrusfb_info *cinfo, unsigned char val)
2755 unsigned char dummy;
2757 if (cinfo->btype == BT_PICASSO) {
2758 /* Klaus' hint for correct access to HDR on some boards */
2759 /* first write 0 to pixel mask (3c6) */
2760 WGen (cinfo, VGA_PEL_MSK, 0x00);
2761 udelay (200);
2762 /* next read dummy from pixel address (3c8) */
2763 dummy = RGen (cinfo, VGA_PEL_IW);
2764 udelay (200);
2766 /* now do the usual stuff to access the HDR */
2768 dummy = RGen (cinfo, VGA_PEL_MSK);
2769 udelay (200);
2770 dummy = RGen (cinfo, VGA_PEL_MSK);
2771 udelay (200);
2772 dummy = RGen (cinfo, VGA_PEL_MSK);
2773 udelay (200);
2774 dummy = RGen (cinfo, VGA_PEL_MSK);
2775 udelay (200);
2777 WGen (cinfo, VGA_PEL_MSK, val);
2778 udelay (200);
2780 if (cinfo->btype == BT_PICASSO) {
2781 /* now first reset HDR access counter */
2782 dummy = RGen (cinfo, VGA_PEL_IW);
2783 udelay (200);
2785 /* and at the end, restore the mask value */
2786 /* ## is this mask always 0xff? */
2787 WGen (cinfo, VGA_PEL_MSK, 0xff);
2788 udelay (200);
2793 /*** WSFR() - write to the "special function register" (SFR) ***/
2794 static void WSFR (struct cirrusfb_info *cinfo, unsigned char val)
2796 #ifdef CONFIG_ZORRO
2797 assert (cinfo->regbase != NULL);
2798 cinfo->SFR = val;
2799 z_writeb (val, cinfo->regbase + 0x8000);
2800 #endif
2803 /* The Picasso has a second register for switching the monitor bit */
2804 static void WSFR2 (struct cirrusfb_info *cinfo, unsigned char val)
2806 #ifdef CONFIG_ZORRO
2807 /* writing an arbitrary value to this one causes the monitor switcher */
2808 /* to flip to Amiga display */
2809 assert (cinfo->regbase != NULL);
2810 cinfo->SFR = val;
2811 z_writeb (val, cinfo->regbase + 0x9000);
2812 #endif
2816 /*** WClut - set CLUT entry (range: 0..63) ***/
2817 static void WClut (struct cirrusfb_info *cinfo, unsigned char regnum, unsigned char red,
2818 unsigned char green, unsigned char blue)
2820 unsigned int data = VGA_PEL_D;
2822 /* address write mode register is not translated.. */
2823 vga_w (cinfo->regbase, VGA_PEL_IW, regnum);
2825 if (cinfo->btype == BT_PICASSO || cinfo->btype == BT_PICASSO4 ||
2826 cinfo->btype == BT_ALPINE || cinfo->btype == BT_GD5480) {
2827 /* but DAC data register IS, at least for Picasso II */
2828 if (cinfo->btype == BT_PICASSO)
2829 data += 0xfff;
2830 vga_w (cinfo->regbase, data, red);
2831 vga_w (cinfo->regbase, data, green);
2832 vga_w (cinfo->regbase, data, blue);
2833 } else {
2834 vga_w (cinfo->regbase, data, blue);
2835 vga_w (cinfo->regbase, data, green);
2836 vga_w (cinfo->regbase, data, red);
2841 #if 0
2842 /*** RClut - read CLUT entry (range 0..63) ***/
2843 static void RClut (struct cirrusfb_info *cinfo, unsigned char regnum, unsigned char *red,
2844 unsigned char *green, unsigned char *blue)
2846 unsigned int data = VGA_PEL_D;
2848 vga_w (cinfo->regbase, VGA_PEL_IR, regnum);
2850 if (cinfo->btype == BT_PICASSO || cinfo->btype == BT_PICASSO4 ||
2851 cinfo->btype == BT_ALPINE || cinfo->btype == BT_GD5480) {
2852 if (cinfo->btype == BT_PICASSO)
2853 data += 0xfff;
2854 *red = vga_r (cinfo->regbase, data);
2855 *green = vga_r (cinfo->regbase, data);
2856 *blue = vga_r (cinfo->regbase, data);
2857 } else {
2858 *blue = vga_r (cinfo->regbase, data);
2859 *green = vga_r (cinfo->regbase, data);
2860 *red = vga_r (cinfo->regbase, data);
2863 #endif
2866 /*******************************************************************
2867 cirrusfb_WaitBLT()
2869 Wait for the BitBLT engine to complete a possible earlier job
2870 *********************************************************************/
2872 /* FIXME: use interrupts instead */
2873 static void cirrusfb_WaitBLT (u8 __iomem *regbase)
2875 /* now busy-wait until we're done */
2876 while (vga_rgfx (regbase, CL_GR31) & 0x08)
2877 /* do nothing */ ;
2880 /*******************************************************************
2881 cirrusfb_BitBLT()
2883 perform accelerated "scrolling"
2884 ********************************************************************/
2886 static void cirrusfb_BitBLT (u8 __iomem *regbase, int bits_per_pixel,
2887 u_short curx, u_short cury, u_short destx, u_short desty,
2888 u_short width, u_short height, u_short line_length)
2890 u_short nwidth, nheight;
2891 u_long nsrc, ndest;
2892 u_char bltmode;
2894 DPRINTK ("ENTER\n");
2896 nwidth = width - 1;
2897 nheight = height - 1;
2899 bltmode = 0x00;
2900 /* if source adr < dest addr, do the Blt backwards */
2901 if (cury <= desty) {
2902 if (cury == desty) {
2903 /* if src and dest are on the same line, check x */
2904 if (curx < destx)
2905 bltmode |= 0x01;
2906 } else
2907 bltmode |= 0x01;
2909 if (!bltmode) {
2910 /* standard case: forward blitting */
2911 nsrc = (cury * line_length) + curx;
2912 ndest = (desty * line_length) + destx;
2913 } else {
2914 /* this means start addresses are at the end, counting backwards */
2915 nsrc = cury * line_length + curx + nheight * line_length + nwidth;
2916 ndest = desty * line_length + destx + nheight * line_length + nwidth;
2920 run-down of registers to be programmed:
2921 destination pitch
2922 source pitch
2923 BLT width/height
2924 source start
2925 destination start
2926 BLT mode
2927 BLT ROP
2928 VGA_GFX_SR_VALUE / VGA_GFX_SR_ENABLE: "fill color"
2929 start/stop
2932 cirrusfb_WaitBLT(regbase);
2934 /* pitch: set to line_length */
2935 vga_wgfx (regbase, CL_GR24, line_length & 0xff); /* dest pitch low */
2936 vga_wgfx (regbase, CL_GR25, (line_length >> 8)); /* dest pitch hi */
2937 vga_wgfx (regbase, CL_GR26, line_length & 0xff); /* source pitch low */
2938 vga_wgfx (regbase, CL_GR27, (line_length >> 8)); /* source pitch hi */
2940 /* BLT width: actual number of pixels - 1 */
2941 vga_wgfx (regbase, CL_GR20, nwidth & 0xff); /* BLT width low */
2942 vga_wgfx (regbase, CL_GR21, (nwidth >> 8)); /* BLT width hi */
2944 /* BLT height: actual number of lines -1 */
2945 vga_wgfx (regbase, CL_GR22, nheight & 0xff); /* BLT height low */
2946 vga_wgfx (regbase, CL_GR23, (nheight >> 8)); /* BLT width hi */
2948 /* BLT destination */
2949 vga_wgfx (regbase, CL_GR28, (u_char) (ndest & 0xff)); /* BLT dest low */
2950 vga_wgfx (regbase, CL_GR29, (u_char) (ndest >> 8)); /* BLT dest mid */
2951 vga_wgfx (regbase, CL_GR2A, (u_char) (ndest >> 16)); /* BLT dest hi */
2953 /* BLT source */
2954 vga_wgfx (regbase, CL_GR2C, (u_char) (nsrc & 0xff)); /* BLT src low */
2955 vga_wgfx (regbase, CL_GR2D, (u_char) (nsrc >> 8)); /* BLT src mid */
2956 vga_wgfx (regbase, CL_GR2E, (u_char) (nsrc >> 16)); /* BLT src hi */
2958 /* BLT mode */
2959 vga_wgfx (regbase, CL_GR30, bltmode); /* BLT mode */
2961 /* BLT ROP: SrcCopy */
2962 vga_wgfx (regbase, CL_GR32, 0x0d); /* BLT ROP */
2964 /* and finally: GO! */
2965 vga_wgfx (regbase, CL_GR31, 0x02); /* BLT Start/status */
2967 DPRINTK ("EXIT\n");
2971 /*******************************************************************
2972 cirrusfb_RectFill()
2974 perform accelerated rectangle fill
2975 ********************************************************************/
2977 static void cirrusfb_RectFill (u8 __iomem *regbase, int bits_per_pixel,
2978 u_short x, u_short y, u_short width, u_short height,
2979 u_char color, u_short line_length)
2981 u_short nwidth, nheight;
2982 u_long ndest;
2983 u_char op;
2985 DPRINTK ("ENTER\n");
2987 nwidth = width - 1;
2988 nheight = height - 1;
2990 ndest = (y * line_length) + x;
2992 cirrusfb_WaitBLT(regbase);
2994 /* pitch: set to line_length */
2995 vga_wgfx (regbase, CL_GR24, line_length & 0xff); /* dest pitch low */
2996 vga_wgfx (regbase, CL_GR25, (line_length >> 8)); /* dest pitch hi */
2997 vga_wgfx (regbase, CL_GR26, line_length & 0xff); /* source pitch low */
2998 vga_wgfx (regbase, CL_GR27, (line_length >> 8)); /* source pitch hi */
3000 /* BLT width: actual number of pixels - 1 */
3001 vga_wgfx (regbase, CL_GR20, nwidth & 0xff); /* BLT width low */
3002 vga_wgfx (regbase, CL_GR21, (nwidth >> 8)); /* BLT width hi */
3004 /* BLT height: actual number of lines -1 */
3005 vga_wgfx (regbase, CL_GR22, nheight & 0xff); /* BLT height low */
3006 vga_wgfx (regbase, CL_GR23, (nheight >> 8)); /* BLT width hi */
3008 /* BLT destination */
3009 vga_wgfx (regbase, CL_GR28, (u_char) (ndest & 0xff)); /* BLT dest low */
3010 vga_wgfx (regbase, CL_GR29, (u_char) (ndest >> 8)); /* BLT dest mid */
3011 vga_wgfx (regbase, CL_GR2A, (u_char) (ndest >> 16)); /* BLT dest hi */
3013 /* BLT source: set to 0 (is a dummy here anyway) */
3014 vga_wgfx (regbase, CL_GR2C, 0x00); /* BLT src low */
3015 vga_wgfx (regbase, CL_GR2D, 0x00); /* BLT src mid */
3016 vga_wgfx (regbase, CL_GR2E, 0x00); /* BLT src hi */
3018 /* This is a ColorExpand Blt, using the */
3019 /* same color for foreground and background */
3020 vga_wgfx (regbase, VGA_GFX_SR_VALUE, color); /* foreground color */
3021 vga_wgfx (regbase, VGA_GFX_SR_ENABLE, color); /* background color */
3023 op = 0xc0;
3024 if (bits_per_pixel == 16) {
3025 vga_wgfx (regbase, CL_GR10, color); /* foreground color */
3026 vga_wgfx (regbase, CL_GR11, color); /* background color */
3027 op = 0x50;
3028 op = 0xd0;
3029 } else if (bits_per_pixel == 32) {
3030 vga_wgfx (regbase, CL_GR10, color); /* foreground color */
3031 vga_wgfx (regbase, CL_GR11, color); /* background color */
3032 vga_wgfx (regbase, CL_GR12, color); /* foreground color */
3033 vga_wgfx (regbase, CL_GR13, color); /* background color */
3034 vga_wgfx (regbase, CL_GR14, 0); /* foreground color */
3035 vga_wgfx (regbase, CL_GR15, 0); /* background color */
3036 op = 0x50;
3037 op = 0xf0;
3039 /* BLT mode: color expand, Enable 8x8 copy (faster?) */
3040 vga_wgfx (regbase, CL_GR30, op); /* BLT mode */
3042 /* BLT ROP: SrcCopy */
3043 vga_wgfx (regbase, CL_GR32, 0x0d); /* BLT ROP */
3045 /* and finally: GO! */
3046 vga_wgfx (regbase, CL_GR31, 0x02); /* BLT Start/status */
3048 DPRINTK ("EXIT\n");
3052 /**************************************************************************
3053 * bestclock() - determine closest possible clock lower(?) than the
3054 * desired pixel clock
3055 **************************************************************************/
3056 static void bestclock (long freq, long *best, long *nom,
3057 long *den, long *div, long maxfreq)
3059 long n, h, d, f;
3061 assert (best != NULL);
3062 assert (nom != NULL);
3063 assert (den != NULL);
3064 assert (div != NULL);
3065 assert (maxfreq > 0);
3067 *nom = 0;
3068 *den = 0;
3069 *div = 0;
3071 DPRINTK ("ENTER\n");
3073 if (freq < 8000)
3074 freq = 8000;
3076 if (freq > maxfreq)
3077 freq = maxfreq;
3079 *best = 0;
3080 f = freq * 10;
3082 for (n = 32; n < 128; n++) {
3083 d = (143181 * n) / f;
3084 if ((d >= 7) && (d <= 63)) {
3085 if (d > 31)
3086 d = (d / 2) * 2;
3087 h = (14318 * n) / d;
3088 if (abs (h - freq) < abs (*best - freq)) {
3089 *best = h;
3090 *nom = n;
3091 if (d < 32) {
3092 *den = d;
3093 *div = 0;
3094 } else {
3095 *den = d / 2;
3096 *div = 1;
3100 d = ((143181 * n) + f - 1) / f;
3101 if ((d >= 7) && (d <= 63)) {
3102 if (d > 31)
3103 d = (d / 2) * 2;
3104 h = (14318 * n) / d;
3105 if (abs (h - freq) < abs (*best - freq)) {
3106 *best = h;
3107 *nom = n;
3108 if (d < 32) {
3109 *den = d;
3110 *div = 0;
3111 } else {
3112 *den = d / 2;
3113 *div = 1;
3119 DPRINTK ("Best possible values for given frequency:\n");
3120 DPRINTK (" best: %ld kHz nom: %ld den: %ld div: %ld\n",
3121 freq, *nom, *den, *div);
3123 DPRINTK ("EXIT\n");
3127 /* -------------------------------------------------------------------------
3129 * debugging functions
3131 * -------------------------------------------------------------------------
3134 #ifdef CIRRUSFB_DEBUG
3137 * cirrusfb_dbg_print_byte
3138 * @name: name associated with byte value to be displayed
3139 * @val: byte value to be displayed
3141 * DESCRIPTION:
3142 * Display an indented string, along with a hexidecimal byte value, and
3143 * its decoded bits. Bits 7 through 0 are listed in left-to-right
3144 * order.
3147 static
3148 void cirrusfb_dbg_print_byte (const char *name, unsigned char val)
3150 DPRINTK ("%8s = 0x%02X (bits 7-0: %c%c%c%c%c%c%c%c)\n",
3151 name, val,
3152 val & 0x80 ? '1' : '0',
3153 val & 0x40 ? '1' : '0',
3154 val & 0x20 ? '1' : '0',
3155 val & 0x10 ? '1' : '0',
3156 val & 0x08 ? '1' : '0',
3157 val & 0x04 ? '1' : '0',
3158 val & 0x02 ? '1' : '0',
3159 val & 0x01 ? '1' : '0');
3164 * cirrusfb_dbg_print_regs
3165 * @base: If using newmmio, the newmmio base address, otherwise %NULL
3166 * @reg_class: type of registers to read: %CRT, or %SEQ
3168 * DESCRIPTION:
3169 * Dumps the given list of VGA CRTC registers. If @base is %NULL,
3170 * old-style I/O ports are queried for information, otherwise MMIO is
3171 * used at the given @base address to query the information.
3174 static
3175 void cirrusfb_dbg_print_regs (caddr_t regbase, cirrusfb_dbg_reg_class_t reg_class,...)
3177 va_list list;
3178 unsigned char val = 0;
3179 unsigned reg;
3180 char *name;
3182 va_start (list, reg_class);
3184 name = va_arg (list, char *);
3185 while (name != NULL) {
3186 reg = va_arg (list, int);
3188 switch (reg_class) {
3189 case CRT:
3190 val = vga_rcrt (regbase, (unsigned char) reg);
3191 break;
3192 case SEQ:
3193 val = vga_rseq (regbase, (unsigned char) reg);
3194 break;
3195 default:
3196 /* should never occur */
3197 assert(false);
3198 break;
3201 cirrusfb_dbg_print_byte (name, val);
3203 name = va_arg (list, char *);
3206 va_end (list);
3211 * cirrusfb_dump
3212 * @cirrusfbinfo:
3214 * DESCRIPTION:
3217 static
3218 void cirrusfb_dump (void)
3220 cirrusfb_dbg_reg_dump (NULL);
3225 * cirrusfb_dbg_reg_dump
3226 * @base: If using newmmio, the newmmio base address, otherwise %NULL
3228 * DESCRIPTION:
3229 * Dumps a list of interesting VGA and CIRRUSFB registers. If @base is %NULL,
3230 * old-style I/O ports are queried for information, otherwise MMIO is
3231 * used at the given @base address to query the information.
3234 static
3235 void cirrusfb_dbg_reg_dump (caddr_t regbase)
3237 DPRINTK ("CIRRUSFB VGA CRTC register dump:\n");
3239 cirrusfb_dbg_print_regs (regbase, CRT,
3240 "CR00", 0x00,
3241 "CR01", 0x01,
3242 "CR02", 0x02,
3243 "CR03", 0x03,
3244 "CR04", 0x04,
3245 "CR05", 0x05,
3246 "CR06", 0x06,
3247 "CR07", 0x07,
3248 "CR08", 0x08,
3249 "CR09", 0x09,
3250 "CR0A", 0x0A,
3251 "CR0B", 0x0B,
3252 "CR0C", 0x0C,
3253 "CR0D", 0x0D,
3254 "CR0E", 0x0E,
3255 "CR0F", 0x0F,
3256 "CR10", 0x10,
3257 "CR11", 0x11,
3258 "CR12", 0x12,
3259 "CR13", 0x13,
3260 "CR14", 0x14,
3261 "CR15", 0x15,
3262 "CR16", 0x16,
3263 "CR17", 0x17,
3264 "CR18", 0x18,
3265 "CR22", 0x22,
3266 "CR24", 0x24,
3267 "CR26", 0x26,
3268 "CR2D", 0x2D,
3269 "CR2E", 0x2E,
3270 "CR2F", 0x2F,
3271 "CR30", 0x30,
3272 "CR31", 0x31,
3273 "CR32", 0x32,
3274 "CR33", 0x33,
3275 "CR34", 0x34,
3276 "CR35", 0x35,
3277 "CR36", 0x36,
3278 "CR37", 0x37,
3279 "CR38", 0x38,
3280 "CR39", 0x39,
3281 "CR3A", 0x3A,
3282 "CR3B", 0x3B,
3283 "CR3C", 0x3C,
3284 "CR3D", 0x3D,
3285 "CR3E", 0x3E,
3286 "CR3F", 0x3F,
3287 NULL);
3289 DPRINTK ("\n");
3291 DPRINTK ("CIRRUSFB VGA SEQ register dump:\n");
3293 cirrusfb_dbg_print_regs (regbase, SEQ,
3294 "SR00", 0x00,
3295 "SR01", 0x01,
3296 "SR02", 0x02,
3297 "SR03", 0x03,
3298 "SR04", 0x04,
3299 "SR08", 0x08,
3300 "SR09", 0x09,
3301 "SR0A", 0x0A,
3302 "SR0B", 0x0B,
3303 "SR0D", 0x0D,
3304 "SR10", 0x10,
3305 "SR11", 0x11,
3306 "SR12", 0x12,
3307 "SR13", 0x13,
3308 "SR14", 0x14,
3309 "SR15", 0x15,
3310 "SR16", 0x16,
3311 "SR17", 0x17,
3312 "SR18", 0x18,
3313 "SR19", 0x19,
3314 "SR1A", 0x1A,
3315 "SR1B", 0x1B,
3316 "SR1C", 0x1C,
3317 "SR1D", 0x1D,
3318 "SR1E", 0x1E,
3319 "SR1F", 0x1F,
3320 NULL);
3322 DPRINTK ("\n");
3325 #endif /* CIRRUSFB_DEBUG */