initial commit with v2.6.9
[linux-2.6.9-moxart.git] / drivers / video / cirrusfb.c
blob8132b3bf262fda5321cbe126200eb8077a47b919
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/config.h>
40 #include <linux/module.h>
41 #include <linux/kernel.h>
42 #include <linux/errno.h>
43 #include <linux/string.h>
44 #include <linux/mm.h>
45 #include <linux/tty.h>
46 #include <linux/slab.h>
47 #include <linux/delay.h>
48 #include <linux/fb.h>
49 #include <linux/init.h>
50 #include <linux/selection.h>
51 #include <asm/pgtable.h>
53 #ifdef CONFIG_ZORRO
54 #include <linux/zorro.h>
55 #endif
56 #ifdef CONFIG_PCI
57 #include <linux/pci.h>
58 #endif
59 #ifdef CONFIG_AMIGA
60 #include <asm/amigahw.h>
61 #endif
62 #ifdef CONFIG_PPC_PREP
63 #include <asm/processor.h>
64 #define isPReP (_machine == _MACH_prep)
65 #else
66 #define isPReP 0
67 #endif
69 #include "video/vga.h"
70 #include "video/cirrus.h"
73 /*****************************************************************
75 * debugging and utility macros
79 /* enable debug output? */
80 /* #define CIRRUSFB_DEBUG 1 */
82 /* disable runtime assertions? */
83 /* #define CIRRUSFB_NDEBUG */
85 /* debug output */
86 #ifdef CIRRUSFB_DEBUG
87 #define DPRINTK(fmt, args...) printk(KERN_DEBUG "%s: " fmt, __FUNCTION__ , ## args)
88 #else
89 #define DPRINTK(fmt, args...)
90 #endif
92 /* debugging assertions */
93 #ifndef CIRRUSFB_NDEBUG
94 #define assert(expr) \
95 if(!(expr)) { \
96 printk( "Assertion failed! %s,%s,%s,line=%d\n",\
97 #expr,__FILE__,__FUNCTION__,__LINE__); \
99 #else
100 #define assert(expr)
101 #endif
103 #ifdef TRUE
104 #undef TRUE
105 #endif
106 #ifdef FALSE
107 #undef FALSE
108 #endif
109 #define TRUE 1
110 #define FALSE 0
112 #define MB_ (1024*1024)
113 #define KB_ (1024)
115 #define MAX_NUM_BOARDS 7
118 /*****************************************************************
120 * chipset information
124 /* board types */
125 typedef enum {
126 BT_NONE = 0,
127 BT_SD64,
128 BT_PICCOLO,
129 BT_PICASSO,
130 BT_SPECTRUM,
131 BT_PICASSO4, /* GD5446 */
132 BT_ALPINE, /* GD543x/4x */
133 BT_GD5480,
134 BT_LAGUNA, /* GD546x */
135 } cirrusfb_board_t;
139 * per-board-type information, used for enumerating and abstracting
140 * chip-specific information
141 * NOTE: MUST be in the same order as cirrusfb_board_t in order to
142 * use direct indexing on this array
143 * NOTE: '__initdata' cannot be used as some of this info
144 * is required at runtime. Maybe separate into an init-only and
145 * a run-time table?
147 static const struct cirrusfb_board_info_rec {
148 char *name; /* ASCII name of chipset */
149 long maxclock[5]; /* maximum video clock */
150 /* for 1/4bpp, 8bpp 15/16bpp, 24bpp, 32bpp - numbers from xorg code */
151 unsigned init_sr07 : 1; /* init SR07 during init_vgachip() */
152 unsigned init_sr1f : 1; /* write SR1F during init_vgachip() */
153 unsigned scrn_start_bit19 : 1; /* construct bit 19 of screen start address */
155 /* initial SR07 value, then for each mode */
156 unsigned char sr07;
157 unsigned char sr07_1bpp;
158 unsigned char sr07_1bpp_mux;
159 unsigned char sr07_8bpp;
160 unsigned char sr07_8bpp_mux;
162 unsigned char sr1f; /* SR1F VGA initial register value */
163 } cirrusfb_board_info[] = {
164 [BT_SD64] = {
165 .name = "CL SD64",
166 .maxclock = {
167 /* guess */
168 /* the SD64/P4 have a higher max. videoclock */
169 140000, 140000, 140000, 140000, 140000,
171 .init_sr07 = TRUE,
172 .init_sr1f = TRUE,
173 .scrn_start_bit19 = TRUE,
174 .sr07 = 0xF0,
175 .sr07_1bpp = 0xF0,
176 .sr07_8bpp = 0xF1,
177 .sr1f = 0x20
179 [BT_PICCOLO] = {
180 .name = "CL Piccolo",
181 .maxclock = {
182 /* guess */
183 90000, 90000, 90000, 90000, 90000
185 .init_sr07 = TRUE,
186 .init_sr1f = TRUE,
187 .scrn_start_bit19 = FALSE,
188 .sr07 = 0x80,
189 .sr07_1bpp = 0x80,
190 .sr07_8bpp = 0x81,
191 .sr1f = 0x22
193 [BT_PICASSO] = {
194 .name = "CL Picasso",
195 .maxclock = {
196 /* guess */
197 90000, 90000, 90000, 90000, 90000
199 .init_sr07 = TRUE,
200 .init_sr1f = TRUE,
201 .scrn_start_bit19 = FALSE,
202 .sr07 = 0x20,
203 .sr07_1bpp = 0x20,
204 .sr07_8bpp = 0x21,
205 .sr1f = 0x22
207 [BT_SPECTRUM] = {
208 .name = "CL Spectrum",
209 .maxclock = {
210 /* guess */
211 90000, 90000, 90000, 90000, 90000
213 .init_sr07 = TRUE,
214 .init_sr1f = TRUE,
215 .scrn_start_bit19 = FALSE,
216 .sr07 = 0x80,
217 .sr07_1bpp = 0x80,
218 .sr07_8bpp = 0x81,
219 .sr1f = 0x22
221 [BT_PICASSO4] = {
222 .name = "CL Picasso4",
223 .maxclock = {
224 135100, 135100, 85500, 85500, 0
226 .init_sr07 = TRUE,
227 .init_sr1f = FALSE,
228 .scrn_start_bit19 = TRUE,
229 .sr07 = 0x20,
230 .sr07_1bpp = 0x20,
231 .sr07_8bpp = 0x21,
232 .sr1f = 0
234 [BT_ALPINE] = {
235 .name = "CL Alpine",
236 .maxclock = {
237 /* for the GD5430. GD5446 can do more... */
238 85500, 85500, 50000, 28500, 0
240 .init_sr07 = TRUE,
241 .init_sr1f = TRUE,
242 .scrn_start_bit19 = TRUE,
243 .sr07 = 0xA0,
244 .sr07_1bpp = 0xA1,
245 .sr07_1bpp_mux = 0xA7,
246 .sr07_8bpp = 0xA1,
247 .sr07_8bpp_mux = 0xA7,
248 .sr1f = 0x1C
250 [BT_GD5480] = {
251 .name = "CL GD5480",
252 .maxclock = {
253 135100, 200000, 200000, 135100, 135100
255 .init_sr07 = TRUE,
256 .init_sr1f = TRUE,
257 .scrn_start_bit19 = TRUE,
258 .sr07 = 0x10,
259 .sr07_1bpp = 0x11,
260 .sr07_8bpp = 0x11,
261 .sr1f = 0x1C
263 [BT_LAGUNA] = {
264 .name = "CL Laguna",
265 .maxclock = {
266 /* guess */
267 135100, 135100, 135100, 135100, 135100,
269 .init_sr07 = FALSE,
270 .init_sr1f = FALSE,
271 .scrn_start_bit19 = TRUE,
276 #ifdef CONFIG_PCI
277 #define CHIP(id, btype) \
278 { PCI_VENDOR_ID_CIRRUS, PCI_DEVICE_ID_##id, PCI_ANY_ID, PCI_ANY_ID, 0, 0, (btype) }
280 static struct pci_device_id cirrusfb_pci_table[] = {
281 CHIP( CIRRUS_5436, BT_ALPINE ),
282 CHIP( CIRRUS_5434_8, BT_ALPINE ),
283 CHIP( CIRRUS_5434_4, BT_ALPINE ),
284 CHIP( CIRRUS_5430, BT_ALPINE ), /* GD-5440 has identical id */
285 CHIP( CIRRUS_7543, BT_ALPINE ),
286 CHIP( CIRRUS_7548, BT_ALPINE ),
287 CHIP( CIRRUS_5480, BT_GD5480 ), /* MacPicasso probably */
288 CHIP( CIRRUS_5446, BT_PICASSO4 ), /* Picasso 4 is a GD5446 */
289 CHIP( CIRRUS_5462, BT_LAGUNA ), /* CL Laguna */
290 CHIP( CIRRUS_5464, BT_LAGUNA ), /* CL Laguna 3D */
291 CHIP( CIRRUS_5465, BT_LAGUNA ), /* CL Laguna 3DA*/
292 { 0, }
294 MODULE_DEVICE_TABLE(pci, cirrusfb_pci_table);
295 #undef CHIP
296 #endif /* CONFIG_PCI */
299 #ifdef CONFIG_ZORRO
300 static const struct zorro_device_id cirrusfb_zorro_table[] = {
302 .id = ZORRO_PROD_HELFRICH_SD64_RAM,
303 .driver_data = BT_SD64,
304 }, {
305 .id = ZORRO_PROD_HELFRICH_PICCOLO_RAM,
306 .driver_data = BT_PICCOLO,
307 }, {
308 .id = ZORRO_PROD_VILLAGE_TRONIC_PICASSO_II_II_PLUS_RAM,
309 .driver_data = BT_PICASSO,
310 }, {
311 .id = ZORRO_PROD_GVP_EGS_28_24_SPECTRUM_RAM,
312 .driver_data = BT_SPECTRUM,
313 }, {
314 .id = ZORRO_PROD_VILLAGE_TRONIC_PICASSO_IV_Z3,
315 .driver_data = BT_PICASSO4,
317 { 0 }
320 static const struct {
321 zorro_id id2;
322 unsigned long size;
323 } cirrusfb_zorro_table2[] = {
324 [BT_SD64] = {
325 .id2 = ZORRO_PROD_HELFRICH_SD64_REG,
326 .size = 0x400000
328 [BT_PICCOLO] = {
329 .id2 = ZORRO_PROD_HELFRICH_PICCOLO_REG,
330 .size = 0x200000
332 [BT_PICASSO] = {
333 .id2 = ZORRO_PROD_VILLAGE_TRONIC_PICASSO_II_II_PLUS_REG,
334 .size = 0x200000
336 [BT_SPECTRUM] = {
337 .id2 = ZORRO_PROD_GVP_EGS_28_24_SPECTRUM_REG,
338 .size = 0x200000
340 [BT_PICASSO4] = {
341 .id2 = 0,
342 .size = 0x400000
345 #endif /* CONFIG_ZORRO */
348 struct cirrusfb_regs {
349 __u32 line_length; /* in BYTES! */
350 __u32 visual;
351 __u32 type;
353 long freq;
354 long nom;
355 long den;
356 long div;
357 long multiplexing;
358 long mclk;
359 long divMCLK;
361 long HorizRes; /* The x resolution in pixel */
362 long HorizTotal;
363 long HorizDispEnd;
364 long HorizBlankStart;
365 long HorizBlankEnd;
366 long HorizSyncStart;
367 long HorizSyncEnd;
369 long VertRes; /* the physical y resolution in scanlines */
370 long VertTotal;
371 long VertDispEnd;
372 long VertSyncStart;
373 long VertSyncEnd;
374 long VertBlankStart;
375 long VertBlankEnd;
380 #ifdef CIRRUSFB_DEBUG
381 typedef enum {
382 CRT,
384 } cirrusfb_dbg_reg_class_t;
385 #endif /* CIRRUSFB_DEBUG */
390 /* info about board */
391 struct cirrusfb_info {
392 struct fb_info *info;
394 caddr_t fbmem;
395 caddr_t regbase;
396 caddr_t mem;
397 unsigned long size;
398 cirrusfb_board_t btype;
399 unsigned char SFR; /* Shadow of special function register */
401 unsigned long fbmem_phys;
402 unsigned long fbregs_phys;
404 struct cirrusfb_regs currentmode;
405 int blank_mode;
407 u32 pseudo_palette[17];
408 struct { u8 red, green, blue, pad; } palette[256];
410 #ifdef CONFIG_ZORRO
411 struct zorro_dev *zdev;
412 #endif
413 #ifdef CONFIG_PCI
414 struct pci_dev *pdev;
415 #endif
416 void (*unmap)(struct cirrusfb_info *cinfo);
420 static unsigned cirrusfb_def_mode = 1;
421 static int noaccel = 0;
424 * Predefined Video Modes
427 static const struct {
428 const char *name;
429 struct fb_var_screeninfo var;
430 } cirrusfb_predefined[] = {
432 /* autodetect mode */
433 .name = "Autodetect",
434 }, {
435 /* 640x480, 31.25 kHz, 60 Hz, 25 MHz PixClock */
436 .name = "640x480",
437 .var = {
438 .xres = 640,
439 .yres = 480,
440 .xres_virtual = 640,
441 .yres_virtual = 480,
442 .bits_per_pixel = 8,
443 .red = { .length = 8 },
444 .green = { .length = 8 },
445 .blue = { .length = 8 },
446 .width = -1,
447 .height = -1,
448 .pixclock = 40000,
449 .left_margin = 48,
450 .right_margin = 16,
451 .upper_margin = 32,
452 .lower_margin = 8,
453 .hsync_len = 96,
454 .vsync_len = 4,
455 .sync = FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
456 .vmode = FB_VMODE_NONINTERLACED
458 }, {
459 /* 800x600, 48 kHz, 76 Hz, 50 MHz PixClock */
460 .name = "800x600",
461 .var = {
462 .xres = 800,
463 .yres = 600,
464 .xres_virtual = 800,
465 .yres_virtual = 600,
466 .bits_per_pixel = 8,
467 .red = { .length = 8 },
468 .green = { .length = 8 },
469 .blue = { .length = 8 },
470 .width = -1,
471 .height = -1,
472 .pixclock = 20000,
473 .left_margin = 128,
474 .right_margin = 16,
475 .upper_margin = 24,
476 .lower_margin = 2,
477 .hsync_len = 96,
478 .vsync_len = 6,
479 .vmode = FB_VMODE_NONINTERLACED
481 }, {
483 * Modeline from XF86Config:
484 * Mode "1024x768" 80 1024 1136 1340 1432 768 770 774 805
486 /* 1024x768, 55.8 kHz, 70 Hz, 80 MHz PixClock */
487 .name = "1024x768",
488 .var = {
489 .xres = 1024,
490 .yres = 768,
491 .xres_virtual = 1024,
492 .yres_virtual = 768,
493 .bits_per_pixel = 8,
494 .red = { .length = 8 },
495 .green = { .length = 8 },
496 .blue = { .length = 8 },
497 .width = -1,
498 .height = -1,
499 .pixclock = 12500,
500 .left_margin = 144,
501 .right_margin = 32,
502 .upper_margin = 30,
503 .lower_margin = 2,
504 .hsync_len = 192,
505 .vsync_len = 6,
506 .vmode = FB_VMODE_NONINTERLACED
511 #define NUM_TOTAL_MODES ARRAY_SIZE(cirrusfb_predefined)
513 /****************************************************************************/
514 /**** BEGIN PROTOTYPES ******************************************************/
517 /*--- Interface used by the world ------------------------------------------*/
518 int cirrusfb_init (void);
519 int cirrusfb_setup (char *options);
521 int cirrusfb_open (struct fb_info *info, int user);
522 int cirrusfb_release (struct fb_info *info, int user);
523 int cirrusfb_setcolreg (unsigned regno, unsigned red, unsigned green,
524 unsigned blue, unsigned transp,
525 struct fb_info *info);
526 int cirrusfb_check_var (struct fb_var_screeninfo *var,
527 struct fb_info *info);
528 int cirrusfb_set_par (struct fb_info *info);
529 int cirrusfb_pan_display (struct fb_var_screeninfo *var,
530 struct fb_info *info);
531 int cirrusfb_blank (int blank_mode, struct fb_info *info);
532 void cirrusfb_fillrect (struct fb_info *info, const struct fb_fillrect *region);
533 void cirrusfb_copyarea(struct fb_info *info, const struct fb_copyarea *area);
534 void cirrusfb_imageblit(struct fb_info *info, const struct fb_image *image);
536 /* function table of the above functions */
537 static struct fb_ops cirrusfb_ops = {
538 .owner = THIS_MODULE,
539 .fb_open = cirrusfb_open,
540 .fb_release = cirrusfb_release,
541 .fb_setcolreg = cirrusfb_setcolreg,
542 .fb_check_var = cirrusfb_check_var,
543 .fb_set_par = cirrusfb_set_par,
544 .fb_pan_display = cirrusfb_pan_display,
545 .fb_blank = cirrusfb_blank,
546 .fb_fillrect = cirrusfb_fillrect,
547 .fb_copyarea = cirrusfb_copyarea,
548 .fb_imageblit = cirrusfb_imageblit,
549 .fb_cursor = soft_cursor,
552 /*--- Hardware Specific Routines -------------------------------------------*/
553 static int cirrusfb_decode_var (const struct fb_var_screeninfo *var,
554 struct cirrusfb_regs *regs,
555 const struct fb_info *info);
556 /*--- Internal routines ----------------------------------------------------*/
557 static void init_vgachip (struct cirrusfb_info *cinfo);
558 static void switch_monitor (struct cirrusfb_info *cinfo, int on);
559 static void WGen (const struct cirrusfb_info *cinfo,
560 int regnum, unsigned char val);
561 static unsigned char RGen (const struct cirrusfb_info *cinfo, int regnum);
562 static void AttrOn (const struct cirrusfb_info *cinfo);
563 static void WHDR (const struct cirrusfb_info *cinfo, unsigned char val);
564 static void WSFR (struct cirrusfb_info *cinfo, unsigned char val);
565 static void WSFR2 (struct cirrusfb_info *cinfo, unsigned char val);
566 static void WClut (struct cirrusfb_info *cinfo, unsigned char regnum, unsigned char red,
567 unsigned char green,
568 unsigned char blue);
569 #if 0
570 static void RClut (struct cirrusfb_info *cinfo, unsigned char regnum, unsigned char *red,
571 unsigned char *green,
572 unsigned char *blue);
573 #endif
574 static void cirrusfb_WaitBLT (caddr_t regbase);
575 static void cirrusfb_BitBLT (caddr_t regbase, int bits_per_pixel,
576 u_short curx, u_short cury,
577 u_short destx, u_short desty,
578 u_short width, u_short height,
579 u_short line_length);
580 static void cirrusfb_RectFill (caddr_t regbase, int bits_per_pixel,
581 u_short x, u_short y,
582 u_short width, u_short height,
583 u_char color, u_short line_length);
585 static void bestclock (long freq, long *best,
586 long *nom, long *den,
587 long *div, long maxfreq);
589 #ifdef CIRRUSFB_DEBUG
590 static void cirrusfb_dump (void);
591 static void cirrusfb_dbg_reg_dump (caddr_t regbase);
592 static void cirrusfb_dbg_print_regs (caddr_t regbase, cirrusfb_dbg_reg_class_t reg_class,...);
593 static void cirrusfb_dbg_print_byte (const char *name, unsigned char val);
594 #endif /* CIRRUSFB_DEBUG */
596 /*** END PROTOTYPES ********************************************************/
597 /*****************************************************************************/
598 /*** BEGIN Interface Used by the World ***************************************/
600 static int opencount = 0;
602 /*--- Open /dev/fbx ---------------------------------------------------------*/
603 int cirrusfb_open (struct fb_info *info, int user)
605 if (opencount++ == 0)
606 switch_monitor (info->par, 1);
607 return 0;
610 /*--- Close /dev/fbx --------------------------------------------------------*/
611 int cirrusfb_release (struct fb_info *info, int user)
613 if (--opencount == 0)
614 switch_monitor (info->par, 0);
615 return 0;
618 /**** END Interface used by the World *************************************/
619 /****************************************************************************/
620 /**** BEGIN Hardware specific Routines **************************************/
622 /* Get a good MCLK value */
623 static long cirrusfb_get_mclk (long freq, int bpp, long *div)
625 long mclk;
627 assert (div != NULL);
629 /* Calculate MCLK, in case VCLK is high enough to require > 50MHz.
630 * Assume a 64-bit data path for now. The formula is:
631 * ((B * PCLK * 2)/W) * 1.2
632 * B = bytes per pixel, PCLK = pixclock, W = data width in bytes */
633 mclk = ((bpp / 8) * freq * 2) / 4;
634 mclk = (mclk * 12) / 10;
635 if (mclk < 50000)
636 mclk = 50000;
637 DPRINTK ("Use MCLK of %ld kHz\n", mclk);
639 /* Calculate value for SR1F. Multiply by 2 so we can round up. */
640 mclk = ((mclk * 16) / 14318);
641 mclk = (mclk + 1) / 2;
642 DPRINTK ("Set SR1F[5:0] to 0x%lx\n", mclk);
644 /* Determine if we should use MCLK instead of VCLK, and if so, what we
645 * should divide it by to get VCLK */
646 switch (freq) {
647 case 24751 ... 25249:
648 *div = 2;
649 DPRINTK ("Using VCLK = MCLK/2\n");
650 break;
651 case 49501 ... 50499:
652 *div = 1;
653 DPRINTK ("Using VCLK = MCLK\n");
654 break;
655 default:
656 *div = 0;
657 break;
660 return mclk;
663 int cirrusfb_check_var(struct fb_var_screeninfo *var,
664 struct fb_info *info)
666 struct cirrusfb_info *cinfo = info->par;
667 int nom, den; /* translyting from pixels->bytes */
668 int yres, i;
669 static struct { int xres, yres; } modes[] =
670 { { 1600, 1280 },
671 { 1280, 1024 },
672 { 1024, 768 },
673 { 800, 600 },
674 { 640, 480 },
675 { -1, -1 } };
677 switch (var->bits_per_pixel) {
678 case 0 ... 1:
679 var->bits_per_pixel = 1;
680 nom = 4;
681 den = 8;
682 break; /* 8 pixel per byte, only 1/4th of mem usable */
683 case 2 ... 8:
684 var->bits_per_pixel = 8;
685 nom = 1;
686 den = 1;
687 break; /* 1 pixel == 1 byte */
688 case 9 ... 16:
689 var->bits_per_pixel = 16;
690 nom = 2;
691 den = 1;
692 break; /* 2 bytes per pixel */
693 case 17 ... 24:
694 var->bits_per_pixel = 24;
695 nom = 3;
696 den = 1;
697 break; /* 3 bytes per pixel */
698 case 25 ... 32:
699 var->bits_per_pixel = 32;
700 nom = 4;
701 den = 1;
702 break; /* 4 bytes per pixel */
703 default:
704 printk ("cirrusfb: mode %dx%dx%d rejected...color depth not supported.\n",
705 var->xres, var->yres, var->bits_per_pixel);
706 DPRINTK ("EXIT - EINVAL error\n");
707 return -EINVAL;
710 if (var->xres * nom / den * var->yres > cinfo->size) {
711 printk ("cirrusfb: mode %dx%dx%d rejected...resolution too high to fit into video memory!\n",
712 var->xres, var->yres, var->bits_per_pixel);
713 DPRINTK ("EXIT - EINVAL error\n");
714 return -EINVAL;
717 /* use highest possible virtual resolution */
718 if (var->xres_virtual == -1 &&
719 var->yres_virtual == -1) {
720 printk ("cirrusfb: using maximum available virtual resolution\n");
721 for (i = 0; modes[i].xres != -1; i++) {
722 if (modes[i].xres * nom / den * modes[i].yres < cinfo->size / 2)
723 break;
725 if (modes[i].xres == -1) {
726 printk ("cirrusfb: could not find a virtual resolution that fits into video memory!!\n");
727 DPRINTK ("EXIT - EINVAL error\n");
728 return -EINVAL;
730 var->xres_virtual = modes[i].xres;
731 var->yres_virtual = modes[i].yres;
733 printk ("cirrusfb: virtual resolution set to maximum of %dx%d\n",
734 var->xres_virtual, var->yres_virtual);
737 if (var->xres_virtual < var->xres)
738 var->xres_virtual = var->xres;
739 if (var->yres_virtual < var->yres)
740 var->yres_virtual = var->yres;
742 if (var->xoffset < 0)
743 var->xoffset = 0;
744 if (var->yoffset < 0)
745 var->yoffset = 0;
747 /* truncate xoffset and yoffset to maximum if too high */
748 if (var->xoffset > var->xres_virtual - var->xres)
749 var->xoffset = var->xres_virtual - var->xres - 1;
750 if (var->yoffset > var->yres_virtual - var->yres)
751 var->yoffset = var->yres_virtual - var->yres - 1;
753 switch (var->bits_per_pixel) {
754 case 1:
755 var->red.offset = 0;
756 var->red.length = 1;
757 var->green.offset = 0;
758 var->green.length = 1;
759 var->blue.offset = 0;
760 var->blue.length = 1;
761 break;
763 case 8:
764 var->red.offset = 0;
765 var->red.length = 6;
766 var->green.offset = 0;
767 var->green.length = 6;
768 var->blue.offset = 0;
769 var->blue.length = 6;
770 break;
772 case 16:
773 if(isPReP) {
774 var->red.offset = 2;
775 var->green.offset = -3;
776 var->blue.offset = 8;
777 } else {
778 var->red.offset = 10;
779 var->green.offset = 5;
780 var->blue.offset = 0;
782 var->red.length = 5;
783 var->green.length = 5;
784 var->blue.length = 5;
785 break;
787 case 24:
788 if(isPReP) {
789 var->red.offset = 8;
790 var->green.offset = 16;
791 var->blue.offset = 24;
792 } else {
793 var->red.offset = 16;
794 var->green.offset = 8;
795 var->blue.offset = 0;
797 var->red.length = 8;
798 var->green.length = 8;
799 var->blue.length = 8;
800 break;
802 case 32:
803 if(isPReP) {
804 var->red.offset = 8;
805 var->green.offset = 16;
806 var->blue.offset = 24;
807 } else {
808 var->red.offset = 16;
809 var->green.offset = 8;
810 var->blue.offset = 0;
812 var->red.length = 8;
813 var->green.length = 8;
814 var->blue.length = 8;
815 break;
817 default:
818 DPRINTK("Unsupported bpp size: %d\n", var->bits_per_pixel);
819 assert (FALSE);
820 /* should never occur */
821 break;
824 var->red.msb_right =
825 var->green.msb_right =
826 var->blue.msb_right =
827 var->transp.offset =
828 var->transp.length =
829 var->transp.msb_right = 0;
831 yres = var->yres;
832 if (var->vmode & FB_VMODE_DOUBLE)
833 yres *= 2;
834 else if (var->vmode & FB_VMODE_INTERLACED)
835 yres = (yres + 1) / 2;
837 if (yres >= 1280) {
838 printk (KERN_WARNING "cirrusfb: ERROR: VerticalTotal >= 1280; special treatment required! (TODO)\n");
839 DPRINTK ("EXIT - EINVAL error\n");
840 return -EINVAL;
843 return 0;
846 static int cirrusfb_decode_var (const struct fb_var_screeninfo *var,
847 struct cirrusfb_regs *regs,
848 const struct fb_info *info)
850 long freq;
851 long maxclock;
852 int maxclockidx = 0;
853 struct cirrusfb_info *cinfo = info->par;
854 int xres, hfront, hsync, hback;
855 int yres, vfront, vsync, vback;
857 switch(var->bits_per_pixel) {
858 case 1:
859 regs->line_length = var->xres_virtual / 8;
860 regs->visual = FB_VISUAL_MONO10;
861 maxclockidx = 0;
862 break;
864 case 8:
865 regs->line_length = var->xres_virtual;
866 regs->visual = FB_VISUAL_PSEUDOCOLOR;
867 maxclockidx = 1;
868 break;
870 case 16:
871 regs->line_length = var->xres_virtual * 2;
872 regs->visual = FB_VISUAL_DIRECTCOLOR;
873 maxclockidx = 2;
874 break;
876 case 24:
877 regs->line_length = var->xres_virtual * 3;
878 regs->visual = FB_VISUAL_DIRECTCOLOR;
879 maxclockidx = 3;
880 break;
882 case 32:
883 regs->line_length = var->xres_virtual * 4;
884 regs->visual = FB_VISUAL_DIRECTCOLOR;
885 maxclockidx = 4;
886 break;
888 default:
889 DPRINTK("Unsupported bpp size: %d\n", var->bits_per_pixel);
890 assert (FALSE);
891 /* should never occur */
892 break;
895 regs->type = FB_TYPE_PACKED_PIXELS;
897 /* convert from ps to kHz */
898 freq = 1000000000 / var->pixclock;
900 DPRINTK ("desired pixclock: %ld kHz\n", freq);
902 maxclock = cirrusfb_board_info[cinfo->btype].maxclock[maxclockidx];
903 regs->multiplexing = 0;
905 /* If the frequency is greater than we can support, we might be able
906 * to use multiplexing for the video mode */
907 if (freq > maxclock) {
908 switch (cinfo->btype) {
909 case BT_ALPINE:
910 case BT_GD5480:
911 regs->multiplexing = 1;
912 break;
914 default:
915 printk (KERN_WARNING "cirrusfb: ERROR: Frequency greater than maxclock (%ld kHz)\n", maxclock);
916 DPRINTK ("EXIT - return -EINVAL\n");
917 return -EINVAL;
920 #if 0
921 /* TODO: If we have a 1MB 5434, we need to put ourselves in a mode where
922 * the VCLK is double the pixel clock. */
923 switch (var->bits_per_pixel) {
924 case 16:
925 case 32:
926 if (regs->HorizRes <= 800)
927 freq /= 2; /* Xbh has this type of clock for 32-bit */
928 break;
930 #endif
932 bestclock (freq, &regs->freq, &regs->nom, &regs->den, &regs->div,
933 maxclock);
934 regs->mclk = cirrusfb_get_mclk (freq, var->bits_per_pixel, &regs->divMCLK);
936 xres = var->xres;
937 hfront = var->right_margin;
938 hsync = var->hsync_len;
939 hback = var->left_margin;
941 yres = var->yres;
942 vfront = var->lower_margin;
943 vsync = var->vsync_len;
944 vback = var->upper_margin;
946 if (var->vmode & FB_VMODE_DOUBLE) {
947 yres *= 2;
948 vfront *= 2;
949 vsync *= 2;
950 vback *= 2;
951 } else if (var->vmode & FB_VMODE_INTERLACED) {
952 yres = (yres + 1) / 2;
953 vfront = (vfront + 1) / 2;
954 vsync = (vsync + 1) / 2;
955 vback = (vback + 1) / 2;
957 regs->HorizRes = xres;
958 regs->HorizTotal = (xres + hfront + hsync + hback) / 8 - 5;
959 regs->HorizDispEnd = xres / 8 - 1;
960 regs->HorizBlankStart = xres / 8;
961 regs->HorizBlankEnd = regs->HorizTotal + 5; /* does not count with "-5" */
962 regs->HorizSyncStart = (xres + hfront) / 8 + 1;
963 regs->HorizSyncEnd = (xres + hfront + hsync) / 8 + 1;
965 regs->VertRes = yres;
966 regs->VertTotal = yres + vfront + vsync + vback - 2;
967 regs->VertDispEnd = yres - 1;
968 regs->VertBlankStart = yres;
969 regs->VertBlankEnd = regs->VertTotal;
970 regs->VertSyncStart = yres + vfront - 1;
971 regs->VertSyncEnd = yres + vfront + vsync - 1;
973 if (regs->VertRes >= 1024) {
974 regs->VertTotal /= 2;
975 regs->VertSyncStart /= 2;
976 regs->VertSyncEnd /= 2;
977 regs->VertDispEnd /= 2;
979 if (regs->multiplexing) {
980 regs->HorizTotal /= 2;
981 regs->HorizSyncStart /= 2;
982 regs->HorizSyncEnd /= 2;
983 regs->HorizDispEnd /= 2;
986 return 0;
990 static void cirrusfb_set_mclk (const struct cirrusfb_info *cinfo, int val, int div)
992 assert (cinfo != NULL);
994 if (div == 2) {
995 /* VCLK = MCLK/2 */
996 unsigned char old = vga_rseq (cinfo->regbase, CL_SEQR1E);
997 vga_wseq (cinfo->regbase, CL_SEQR1E, old | 0x1);
998 vga_wseq (cinfo->regbase, CL_SEQR1F, 0x40 | (val & 0x3f));
999 } else if (div == 1) {
1000 /* VCLK = MCLK */
1001 unsigned char old = vga_rseq (cinfo->regbase, CL_SEQR1E);
1002 vga_wseq (cinfo->regbase, CL_SEQR1E, old & ~0x1);
1003 vga_wseq (cinfo->regbase, CL_SEQR1F, 0x40 | (val & 0x3f));
1004 } else {
1005 vga_wseq (cinfo->regbase, CL_SEQR1F, val & 0x3f);
1009 /*************************************************************************
1010 cirrusfb_set_par_foo()
1012 actually writes the values for a new video mode into the hardware,
1013 **************************************************************************/
1014 static int cirrusfb_set_par_foo (struct fb_info *info)
1016 struct cirrusfb_info *cinfo = info->par;
1017 struct fb_var_screeninfo *var = &info->var;
1018 struct cirrusfb_regs regs;
1019 caddr_t regbase = cinfo->regbase;
1020 unsigned char tmp;
1021 int offset = 0, err;
1022 const struct cirrusfb_board_info_rec *bi;
1024 DPRINTK ("ENTER\n");
1025 DPRINTK ("Requested mode: %dx%dx%d\n",
1026 var->xres, var->yres, var->bits_per_pixel);
1027 DPRINTK ("pixclock: %d\n", var->pixclock);
1029 init_vgachip (cinfo);
1031 err = cirrusfb_decode_var(var, &regs, info);
1032 if(err) {
1033 /* should never happen */
1034 DPRINTK("mode change aborted. invalid var.\n");
1035 return -EINVAL;
1038 bi = &cirrusfb_board_info[cinfo->btype];
1041 /* unlock register VGA_CRTC_H_TOTAL..CRT7 */
1042 vga_wcrt (regbase, VGA_CRTC_V_SYNC_END, 0x20); /* previously: 0x00) */
1044 /* if debugging is enabled, all parameters get output before writing */
1045 DPRINTK ("CRT0: %ld\n", regs.HorizTotal);
1046 vga_wcrt (regbase, VGA_CRTC_H_TOTAL, regs.HorizTotal);
1048 DPRINTK ("CRT1: %ld\n", regs.HorizDispEnd);
1049 vga_wcrt (regbase, VGA_CRTC_H_DISP, regs.HorizDispEnd);
1051 DPRINTK ("CRT2: %ld\n", regs.HorizBlankStart);
1052 vga_wcrt (regbase, VGA_CRTC_H_BLANK_START, regs.HorizBlankStart);
1054 DPRINTK ("CRT3: 128+%ld\n", regs.HorizBlankEnd % 32); /* + 128: Compatible read */
1055 vga_wcrt (regbase, VGA_CRTC_H_BLANK_END, 128 + (regs.HorizBlankEnd % 32));
1057 DPRINTK ("CRT4: %ld\n", regs.HorizSyncStart);
1058 vga_wcrt (regbase, VGA_CRTC_H_SYNC_START, regs.HorizSyncStart);
1060 tmp = regs.HorizSyncEnd % 32;
1061 if (regs.HorizBlankEnd & 32)
1062 tmp += 128;
1063 DPRINTK ("CRT5: %d\n", tmp);
1064 vga_wcrt (regbase, VGA_CRTC_H_SYNC_END, tmp);
1066 DPRINTK ("CRT6: %ld\n", regs.VertTotal & 0xff);
1067 vga_wcrt (regbase, VGA_CRTC_V_TOTAL, (regs.VertTotal & 0xff));
1069 tmp = 16; /* LineCompare bit #9 */
1070 if (regs.VertTotal & 256)
1071 tmp |= 1;
1072 if (regs.VertDispEnd & 256)
1073 tmp |= 2;
1074 if (regs.VertSyncStart & 256)
1075 tmp |= 4;
1076 if (regs.VertBlankStart & 256)
1077 tmp |= 8;
1078 if (regs.VertTotal & 512)
1079 tmp |= 32;
1080 if (regs.VertDispEnd & 512)
1081 tmp |= 64;
1082 if (regs.VertSyncStart & 512)
1083 tmp |= 128;
1084 DPRINTK ("CRT7: %d\n", tmp);
1085 vga_wcrt (regbase, VGA_CRTC_OVERFLOW, tmp);
1087 tmp = 0x40; /* LineCompare bit #8 */
1088 if (regs.VertBlankStart & 512)
1089 tmp |= 0x20;
1090 if (var->vmode & FB_VMODE_DOUBLE)
1091 tmp |= 0x80;
1092 DPRINTK ("CRT9: %d\n", tmp);
1093 vga_wcrt (regbase, VGA_CRTC_MAX_SCAN, tmp);
1095 DPRINTK ("CRT10: %ld\n", regs.VertSyncStart & 0xff);
1096 vga_wcrt (regbase, VGA_CRTC_V_SYNC_START, (regs.VertSyncStart & 0xff));
1098 DPRINTK ("CRT11: 64+32+%ld\n", regs.VertSyncEnd % 16);
1099 vga_wcrt (regbase, VGA_CRTC_V_SYNC_END, (regs.VertSyncEnd % 16 + 64 + 32));
1101 DPRINTK ("CRT12: %ld\n", regs.VertDispEnd & 0xff);
1102 vga_wcrt (regbase, VGA_CRTC_V_DISP_END, (regs.VertDispEnd & 0xff));
1104 DPRINTK ("CRT15: %ld\n", regs.VertBlankStart & 0xff);
1105 vga_wcrt (regbase, VGA_CRTC_V_BLANK_START, (regs.VertBlankStart & 0xff));
1107 DPRINTK ("CRT16: %ld\n", regs.VertBlankEnd & 0xff);
1108 vga_wcrt (regbase, VGA_CRTC_V_BLANK_END, (regs.VertBlankEnd & 0xff));
1110 DPRINTK ("CRT18: 0xff\n");
1111 vga_wcrt (regbase, VGA_CRTC_LINE_COMPARE, 0xff);
1113 tmp = 0;
1114 if (var->vmode & FB_VMODE_INTERLACED)
1115 tmp |= 1;
1116 if (regs.HorizBlankEnd & 64)
1117 tmp |= 16;
1118 if (regs.HorizBlankEnd & 128)
1119 tmp |= 32;
1120 if (regs.VertBlankEnd & 256)
1121 tmp |= 64;
1122 if (regs.VertBlankEnd & 512)
1123 tmp |= 128;
1125 DPRINTK ("CRT1a: %d\n", tmp);
1126 vga_wcrt (regbase, CL_CRT1A, tmp);
1128 /* set VCLK0 */
1129 /* hardware RefClock: 14.31818 MHz */
1130 /* formula: VClk = (OSC * N) / (D * (1+P)) */
1131 /* Example: VClk = (14.31818 * 91) / (23 * (1+1)) = 28.325 MHz */
1133 vga_wseq (regbase, CL_SEQRB, regs.nom);
1134 tmp = regs.den << 1;
1135 if (regs.div != 0)
1136 tmp |= 1;
1138 if ((cinfo->btype == BT_SD64) ||
1139 (cinfo->btype == BT_ALPINE) ||
1140 (cinfo->btype == BT_GD5480))
1141 tmp |= 0x80; /* 6 bit denom; ONLY 5434!!! (bugged me 10 days) */
1143 DPRINTK ("CL_SEQR1B: %ld\n", (long) tmp);
1144 vga_wseq (regbase, CL_SEQR1B, tmp);
1146 if (regs.VertRes >= 1024)
1147 /* 1280x1024 */
1148 vga_wcrt (regbase, VGA_CRTC_MODE, 0xc7);
1149 else
1150 /* mode control: VGA_CRTC_START_HI enable, ROTATE(?), 16bit
1151 * address wrap, no compat. */
1152 vga_wcrt (regbase, VGA_CRTC_MODE, 0xc3);
1154 /* HAEH? vga_wcrt (regbase, VGA_CRTC_V_SYNC_END, 0x20); * previously: 0x00 unlock VGA_CRTC_H_TOTAL..CRT7 */
1156 /* don't know if it would hurt to also program this if no interlaced */
1157 /* mode is used, but I feel better this way.. :-) */
1158 if (var->vmode & FB_VMODE_INTERLACED)
1159 vga_wcrt (regbase, VGA_CRTC_REGS, regs.HorizTotal / 2);
1160 else
1161 vga_wcrt (regbase, VGA_CRTC_REGS, 0x00); /* interlace control */
1163 vga_wseq (regbase, VGA_SEQ_CHARACTER_MAP, 0);
1165 /* adjust horizontal/vertical sync type (low/high) */
1166 tmp = 0x03; /* enable display memory & CRTC I/O address for color mode */
1167 if (var->sync & FB_SYNC_HOR_HIGH_ACT)
1168 tmp |= 0x40;
1169 if (var->sync & FB_SYNC_VERT_HIGH_ACT)
1170 tmp |= 0x80;
1171 WGen (cinfo, VGA_MIS_W, tmp);
1173 vga_wcrt (regbase, VGA_CRTC_PRESET_ROW, 0); /* Screen A Preset Row-Scan register */
1174 vga_wcrt (regbase, VGA_CRTC_CURSOR_START, 0); /* text cursor on and start line */
1175 vga_wcrt (regbase, VGA_CRTC_CURSOR_END, 31); /* text cursor end line */
1177 /******************************************************
1179 * 1 bpp
1183 /* programming for different color depths */
1184 if (var->bits_per_pixel == 1) {
1185 DPRINTK ("cirrusfb: preparing for 1 bit deep display\n");
1186 vga_wgfx (regbase, VGA_GFX_MODE, 0); /* mode register */
1188 /* SR07 */
1189 switch (cinfo->btype) {
1190 case BT_SD64:
1191 case BT_PICCOLO:
1192 case BT_PICASSO:
1193 case BT_SPECTRUM:
1194 case BT_PICASSO4:
1195 case BT_ALPINE:
1196 case BT_GD5480:
1197 DPRINTK (" (for GD54xx)\n");
1198 vga_wseq (regbase, CL_SEQR7,
1199 regs.multiplexing ?
1200 bi->sr07_1bpp_mux : bi->sr07_1bpp);
1201 break;
1203 case BT_LAGUNA:
1204 DPRINTK (" (for GD546x)\n");
1205 vga_wseq (regbase, CL_SEQR7,
1206 vga_rseq (regbase, CL_SEQR7) & ~0x01);
1207 break;
1209 default:
1210 printk (KERN_WARNING "cirrusfb: unknown Board\n");
1211 break;
1214 /* Extended Sequencer Mode */
1215 switch (cinfo->btype) {
1216 case BT_SD64:
1217 /* setting the SEQRF on SD64 is not necessary (only during init) */
1218 DPRINTK ("(for SD64)\n");
1219 vga_wseq (regbase, CL_SEQR1F, 0x1a); /* MCLK select */
1220 break;
1222 case BT_PICCOLO:
1223 DPRINTK ("(for Piccolo)\n");
1224 /* ### ueberall 0x22? */
1225 vga_wseq (regbase, CL_SEQR1F, 0x22); /* ##vorher 1c MCLK select */
1226 vga_wseq (regbase, CL_SEQRF, 0xb0); /* evtl d0 bei 1 bit? avoid FIFO underruns..? */
1227 break;
1229 case BT_PICASSO:
1230 DPRINTK ("(for Picasso)\n");
1231 vga_wseq (regbase, CL_SEQR1F, 0x22); /* ##vorher 22 MCLK select */
1232 vga_wseq (regbase, CL_SEQRF, 0xd0); /* ## vorher d0 avoid FIFO underruns..? */
1233 break;
1235 case BT_SPECTRUM:
1236 DPRINTK ("(for Spectrum)\n");
1237 /* ### ueberall 0x22? */
1238 vga_wseq (regbase, CL_SEQR1F, 0x22); /* ##vorher 1c MCLK select */
1239 vga_wseq (regbase, CL_SEQRF, 0xb0); /* evtl d0? avoid FIFO underruns..? */
1240 break;
1242 case BT_PICASSO4:
1243 case BT_ALPINE:
1244 case BT_GD5480:
1245 case BT_LAGUNA:
1246 DPRINTK (" (for GD54xx)\n");
1247 /* do nothing */
1248 break;
1250 default:
1251 printk (KERN_WARNING "cirrusfb: unknown Board\n");
1252 break;
1255 WGen (cinfo, VGA_PEL_MSK, 0x01); /* pixel mask: pass-through for first plane */
1256 if (regs.multiplexing)
1257 WHDR (cinfo, 0x4a); /* hidden dac reg: 1280x1024 */
1258 else
1259 WHDR (cinfo, 0); /* hidden dac: nothing */
1260 vga_wseq (regbase, VGA_SEQ_MEMORY_MODE, 0x06); /* memory mode: odd/even, ext. memory */
1261 vga_wseq (regbase, VGA_SEQ_PLANE_WRITE, 0x01); /* plane mask: only write to first plane */
1262 offset = var->xres_virtual / 16;
1265 /******************************************************
1267 * 8 bpp
1271 else if (var->bits_per_pixel == 8) {
1272 DPRINTK ("cirrusfb: preparing for 8 bit deep display\n");
1273 switch (cinfo->btype) {
1274 case BT_SD64:
1275 case BT_PICCOLO:
1276 case BT_PICASSO:
1277 case BT_SPECTRUM:
1278 case BT_PICASSO4:
1279 case BT_ALPINE:
1280 case BT_GD5480:
1281 DPRINTK (" (for GD54xx)\n");
1282 vga_wseq (regbase, CL_SEQR7,
1283 regs.multiplexing ?
1284 bi->sr07_8bpp_mux : bi->sr07_8bpp);
1285 break;
1287 case BT_LAGUNA:
1288 DPRINTK (" (for GD546x)\n");
1289 vga_wseq (regbase, CL_SEQR7,
1290 vga_rseq (regbase, CL_SEQR7) | 0x01);
1291 break;
1293 default:
1294 printk (KERN_WARNING "cirrusfb: unknown Board\n");
1295 break;
1298 switch (cinfo->btype) {
1299 case BT_SD64:
1300 vga_wseq (regbase, CL_SEQR1F, 0x1d); /* MCLK select */
1301 break;
1303 case BT_PICCOLO:
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_PICASSO:
1309 vga_wseq (regbase, CL_SEQR1F, 0x22); /* ### vorher 1c MCLK select */
1310 vga_wseq (regbase, CL_SEQRF, 0xb0); /* Fast Page-Mode writes */
1311 break;
1313 case BT_SPECTRUM:
1314 vga_wseq (regbase, CL_SEQR1F, 0x22); /* ### vorher 1c MCLK select */
1315 vga_wseq (regbase, CL_SEQRF, 0xb0); /* Fast Page-Mode writes */
1316 break;
1318 case BT_PICASSO4:
1319 #ifdef CONFIG_ZORRO
1320 vga_wseq (regbase, CL_SEQRF, 0xb8); /* ### INCOMPLETE!! */
1321 #endif
1322 /* vga_wseq (regbase, CL_SEQR1F, 0x1c); */
1323 break;
1325 case BT_ALPINE:
1326 DPRINTK (" (for GD543x)\n");
1327 cirrusfb_set_mclk (cinfo, regs.mclk, regs.divMCLK);
1328 /* We already set SRF and SR1F */
1329 break;
1331 case BT_GD5480:
1332 case BT_LAGUNA:
1333 DPRINTK (" (for GD54xx)\n");
1334 /* do nothing */
1335 break;
1337 default:
1338 printk (KERN_WARNING "cirrusfb: unknown Board\n");
1339 break;
1342 vga_wgfx (regbase, VGA_GFX_MODE, 64); /* mode register: 256 color mode */
1343 WGen (cinfo, VGA_PEL_MSK, 0xff); /* pixel mask: pass-through all planes */
1344 if (regs.multiplexing)
1345 WHDR (cinfo, 0x4a); /* hidden dac reg: 1280x1024 */
1346 else
1347 WHDR (cinfo, 0); /* hidden dac: nothing */
1348 vga_wseq (regbase, VGA_SEQ_MEMORY_MODE, 0x0a); /* memory mode: chain4, ext. memory */
1349 vga_wseq (regbase, VGA_SEQ_PLANE_WRITE, 0xff); /* plane mask: enable writing to all 4 planes */
1350 offset = var->xres_virtual / 8;
1353 /******************************************************
1355 * 16 bpp
1359 else if (var->bits_per_pixel == 16) {
1360 DPRINTK ("cirrusfb: preparing for 16 bit deep display\n");
1361 switch (cinfo->btype) {
1362 case BT_SD64:
1363 vga_wseq (regbase, CL_SEQR7, 0xf7); /* Extended Sequencer Mode: 256c col. mode */
1364 vga_wseq (regbase, CL_SEQR1F, 0x1e); /* MCLK select */
1365 break;
1367 case BT_PICCOLO:
1368 vga_wseq (regbase, CL_SEQR7, 0x87);
1369 vga_wseq (regbase, CL_SEQRF, 0xb0); /* Fast Page-Mode writes */
1370 vga_wseq (regbase, CL_SEQR1F, 0x22); /* MCLK select */
1371 break;
1373 case BT_PICASSO:
1374 vga_wseq (regbase, CL_SEQR7, 0x27);
1375 vga_wseq (regbase, CL_SEQRF, 0xb0); /* Fast Page-Mode writes */
1376 vga_wseq (regbase, CL_SEQR1F, 0x22); /* MCLK select */
1377 break;
1379 case BT_SPECTRUM:
1380 vga_wseq (regbase, CL_SEQR7, 0x87);
1381 vga_wseq (regbase, CL_SEQRF, 0xb0); /* Fast Page-Mode writes */
1382 vga_wseq (regbase, CL_SEQR1F, 0x22); /* MCLK select */
1383 break;
1385 case BT_PICASSO4:
1386 vga_wseq (regbase, CL_SEQR7, 0x27);
1387 /* vga_wseq (regbase, CL_SEQR1F, 0x1c); */
1388 break;
1390 case BT_ALPINE:
1391 DPRINTK (" (for GD543x)\n");
1392 if (regs.HorizRes >= 1024)
1393 vga_wseq (regbase, CL_SEQR7, 0xa7);
1394 else
1395 vga_wseq (regbase, CL_SEQR7, 0xa3);
1396 cirrusfb_set_mclk (cinfo, regs.mclk, regs.divMCLK);
1397 break;
1399 case BT_GD5480:
1400 DPRINTK (" (for GD5480)\n");
1401 vga_wseq (regbase, CL_SEQR7, 0x17);
1402 /* We already set SRF and SR1F */
1403 break;
1405 case BT_LAGUNA:
1406 DPRINTK (" (for GD546x)\n");
1407 vga_wseq (regbase, CL_SEQR7,
1408 vga_rseq (regbase, CL_SEQR7) & ~0x01);
1409 break;
1411 default:
1412 printk (KERN_WARNING "CIRRUSFB: unknown Board\n");
1413 break;
1416 vga_wgfx (regbase, VGA_GFX_MODE, 64); /* mode register: 256 color mode */
1417 WGen (cinfo, VGA_PEL_MSK, 0xff); /* pixel mask: pass-through all planes */
1418 #ifdef CONFIG_PCI
1419 WHDR (cinfo, 0xc0); /* Copy Xbh */
1420 #elif defined(CONFIG_ZORRO)
1421 /* FIXME: CONFIG_PCI and CONFIG_ZORRO may be defined both */
1422 WHDR (cinfo, 0xa0); /* hidden dac reg: nothing special */
1423 #endif
1424 vga_wseq (regbase, VGA_SEQ_MEMORY_MODE, 0x0a); /* memory mode: chain4, ext. memory */
1425 vga_wseq (regbase, VGA_SEQ_PLANE_WRITE, 0xff); /* plane mask: enable writing to all 4 planes */
1426 offset = var->xres_virtual / 4;
1429 /******************************************************
1431 * 32 bpp
1435 else if (var->bits_per_pixel == 32) {
1436 DPRINTK ("cirrusfb: preparing for 24/32 bit deep display\n");
1437 switch (cinfo->btype) {
1438 case BT_SD64:
1439 vga_wseq (regbase, CL_SEQR7, 0xf9); /* Extended Sequencer Mode: 256c col. mode */
1440 vga_wseq (regbase, CL_SEQR1F, 0x1e); /* MCLK select */
1441 break;
1443 case BT_PICCOLO:
1444 vga_wseq (regbase, CL_SEQR7, 0x85);
1445 vga_wseq (regbase, CL_SEQRF, 0xb0); /* Fast Page-Mode writes */
1446 vga_wseq (regbase, CL_SEQR1F, 0x22); /* MCLK select */
1447 break;
1449 case BT_PICASSO:
1450 vga_wseq (regbase, CL_SEQR7, 0x25);
1451 vga_wseq (regbase, CL_SEQRF, 0xb0); /* Fast Page-Mode writes */
1452 vga_wseq (regbase, CL_SEQR1F, 0x22); /* MCLK select */
1453 break;
1455 case BT_SPECTRUM:
1456 vga_wseq (regbase, CL_SEQR7, 0x85);
1457 vga_wseq (regbase, CL_SEQRF, 0xb0); /* Fast Page-Mode writes */
1458 vga_wseq (regbase, CL_SEQR1F, 0x22); /* MCLK select */
1459 break;
1461 case BT_PICASSO4:
1462 vga_wseq (regbase, CL_SEQR7, 0x25);
1463 /* vga_wseq (regbase, CL_SEQR1F, 0x1c); */
1464 break;
1466 case BT_ALPINE:
1467 DPRINTK (" (for GD543x)\n");
1468 vga_wseq (regbase, CL_SEQR7, 0xa9);
1469 cirrusfb_set_mclk (cinfo, regs.mclk, regs.divMCLK);
1470 break;
1472 case BT_GD5480:
1473 DPRINTK (" (for GD5480)\n");
1474 vga_wseq (regbase, CL_SEQR7, 0x19);
1475 /* We already set SRF and SR1F */
1476 break;
1478 case BT_LAGUNA:
1479 DPRINTK (" (for GD546x)\n");
1480 vga_wseq (regbase, CL_SEQR7,
1481 vga_rseq (regbase, CL_SEQR7) & ~0x01);
1482 break;
1484 default:
1485 printk (KERN_WARNING "cirrusfb: unknown Board\n");
1486 break;
1489 vga_wgfx (regbase, VGA_GFX_MODE, 64); /* mode register: 256 color mode */
1490 WGen (cinfo, VGA_PEL_MSK, 0xff); /* pixel mask: pass-through all planes */
1491 WHDR (cinfo, 0xc5); /* hidden dac reg: 8-8-8 mode (24 or 32) */
1492 vga_wseq (regbase, VGA_SEQ_MEMORY_MODE, 0x0a); /* memory mode: chain4, ext. memory */
1493 vga_wseq (regbase, VGA_SEQ_PLANE_WRITE, 0xff); /* plane mask: enable writing to all 4 planes */
1494 offset = var->xres_virtual / 4;
1497 /******************************************************
1499 * unknown/unsupported bpp
1503 else {
1504 printk (KERN_ERR "cirrusfb: What's this?? requested color depth == %d.\n",
1505 var->bits_per_pixel);
1508 vga_wcrt (regbase, VGA_CRTC_OFFSET, offset & 0xff);
1509 tmp = 0x22;
1510 if (offset & 0x100)
1511 tmp |= 0x10; /* offset overflow bit */
1513 vga_wcrt (regbase, CL_CRT1B, tmp); /* screen start addr #16-18, fastpagemode cycles */
1515 if (cinfo->btype == BT_SD64 ||
1516 cinfo->btype == BT_PICASSO4 ||
1517 cinfo->btype == BT_ALPINE ||
1518 cinfo->btype == BT_GD5480)
1519 vga_wcrt (regbase, CL_CRT1D, 0x00); /* screen start address bit 19 */
1521 vga_wcrt (regbase, VGA_CRTC_CURSOR_HI, 0); /* text cursor location high */
1522 vga_wcrt (regbase, VGA_CRTC_CURSOR_LO, 0); /* text cursor location low */
1523 vga_wcrt (regbase, VGA_CRTC_UNDERLINE, 0); /* underline row scanline = at very bottom */
1525 vga_wattr (regbase, VGA_ATC_MODE, 1); /* controller mode */
1526 vga_wattr (regbase, VGA_ATC_OVERSCAN, 0); /* overscan (border) color */
1527 vga_wattr (regbase, VGA_ATC_PLANE_ENABLE, 15); /* color plane enable */
1528 vga_wattr (regbase, CL_AR33, 0); /* pixel panning */
1529 vga_wattr (regbase, VGA_ATC_COLOR_PAGE, 0); /* color select */
1531 /* [ EGS: SetOffset(); ] */
1532 /* From SetOffset(): Turn on VideoEnable bit in Attribute controller */
1533 AttrOn (cinfo);
1535 vga_wgfx (regbase, VGA_GFX_SR_VALUE, 0); /* set/reset register */
1536 vga_wgfx (regbase, VGA_GFX_SR_ENABLE, 0); /* set/reset enable */
1537 vga_wgfx (regbase, VGA_GFX_COMPARE_VALUE, 0); /* color compare */
1538 vga_wgfx (regbase, VGA_GFX_DATA_ROTATE, 0); /* data rotate */
1539 vga_wgfx (regbase, VGA_GFX_PLANE_READ, 0); /* read map select */
1540 vga_wgfx (regbase, VGA_GFX_MISC, 1); /* miscellaneous register */
1541 vga_wgfx (regbase, VGA_GFX_COMPARE_MASK, 15); /* color don't care */
1542 vga_wgfx (regbase, VGA_GFX_BIT_MASK, 255); /* bit mask */
1544 vga_wseq (regbase, CL_SEQR12, 0x0); /* graphics cursor attributes: nothing special */
1546 /* finally, turn on everything - turn off "FullBandwidth" bit */
1547 /* also, set "DotClock%2" bit where requested */
1548 tmp = 0x01;
1550 /*** FB_VMODE_CLOCK_HALVE in linux/fb.h not defined anymore ?
1551 if (var->vmode & FB_VMODE_CLOCK_HALVE)
1552 tmp |= 0x08;
1555 vga_wseq (regbase, VGA_SEQ_CLOCK_MODE, tmp);
1556 DPRINTK ("CL_SEQR1: %d\n", tmp);
1558 cinfo->currentmode = regs;
1559 info->fix.type = regs.type;
1560 info->fix.visual = regs.visual;
1561 info->fix.line_length = regs.line_length;
1563 /* pan to requested offset */
1564 cirrusfb_pan_display (var, info);
1566 #ifdef CIRRUSFB_DEBUG
1567 cirrusfb_dump ();
1568 #endif
1570 DPRINTK ("EXIT\n");
1571 return 0;
1574 /* for some reason incomprehensible to me, cirrusfb requires that you write
1575 * the registers twice for the settings to take..grr. -dte */
1576 int cirrusfb_set_par (struct fb_info *info)
1578 cirrusfb_set_par_foo (info);
1579 return cirrusfb_set_par_foo (info);
1582 int cirrusfb_setcolreg (unsigned regno, unsigned red, unsigned green,
1583 unsigned blue, unsigned transp,
1584 struct fb_info *info)
1586 struct cirrusfb_info *cinfo = info->par;
1588 if (regno > 255)
1589 return -EINVAL;
1591 if (info->fix.visual == FB_VISUAL_TRUECOLOR) {
1592 u32 v;
1593 red >>= (16 - info->var.red.length);
1594 green >>= (16 - info->var.green.length);
1595 blue >>= (16 - info->var.blue.length);
1597 if (regno>=16)
1598 return 1;
1599 v = (red << info->var.red.offset) |
1600 (green << info->var.green.offset) |
1601 (blue << info->var.blue.offset);
1603 switch (info->var.bits_per_pixel) {
1604 case 8:
1605 ((u8*)(info->pseudo_palette))[regno] = v;
1606 break;
1607 case 16:
1608 ((u16*)(info->pseudo_palette))[regno] = v;
1609 break;
1610 case 24:
1611 case 32:
1612 ((u32*)(info->pseudo_palette))[regno] = v;
1613 break;
1615 return 0;
1618 cinfo->palette[regno].red = red;
1619 cinfo->palette[regno].green = green;
1620 cinfo->palette[regno].blue = blue;
1622 if (info->var.bits_per_pixel == 8) {
1623 WClut (cinfo, regno, red >> 10, green >> 10, blue >> 10);
1626 return 0;
1630 /*************************************************************************
1631 cirrusfb_pan_display()
1633 performs display panning - provided hardware permits this
1634 **************************************************************************/
1635 int cirrusfb_pan_display (struct fb_var_screeninfo *var,
1636 struct fb_info *info)
1638 int xoffset = 0;
1639 int yoffset = 0;
1640 unsigned long base;
1641 unsigned char tmp = 0, tmp2 = 0, xpix;
1642 struct cirrusfb_info *cinfo = info->par;
1644 DPRINTK ("ENTER\n");
1645 DPRINTK ("virtual offset: (%d,%d)\n", var->xoffset, var->yoffset);
1647 /* no range checks for xoffset and yoffset, */
1648 /* as fb_pan_display has already done this */
1649 if (var->vmode & FB_VMODE_YWRAP)
1650 return -EINVAL;
1652 info->var.xoffset = var->xoffset;
1653 info->var.yoffset = var->yoffset;
1655 xoffset = var->xoffset * info->var.bits_per_pixel / 8;
1656 yoffset = var->yoffset;
1658 base = yoffset * cinfo->currentmode.line_length + xoffset;
1660 if (info->var.bits_per_pixel == 1) {
1661 /* base is already correct */
1662 xpix = (unsigned char) (var->xoffset % 8);
1663 } else {
1664 base /= 4;
1665 xpix = (unsigned char) ((xoffset % 4) * 2);
1668 cirrusfb_WaitBLT(cinfo->regbase); /* make sure all the BLT's are done */
1670 /* lower 8 + 8 bits of screen start address */
1671 vga_wcrt (cinfo->regbase, VGA_CRTC_START_LO, (unsigned char) (base & 0xff));
1672 vga_wcrt (cinfo->regbase, VGA_CRTC_START_HI, (unsigned char) (base >> 8));
1674 /* construct bits 16, 17 and 18 of screen start address */
1675 if (base & 0x10000)
1676 tmp |= 0x01;
1677 if (base & 0x20000)
1678 tmp |= 0x04;
1679 if (base & 0x40000)
1680 tmp |= 0x08;
1682 tmp2 = (vga_rcrt (cinfo->regbase, CL_CRT1B) & 0xf2) | tmp; /* 0xf2 is %11110010, exclude tmp bits */
1683 vga_wcrt (cinfo->regbase, CL_CRT1B, tmp2);
1685 /* construct bit 19 of screen start address */
1686 if (cirrusfb_board_info[cinfo->btype].scrn_start_bit19) {
1687 tmp2 = 0;
1688 if (base & 0x80000)
1689 tmp2 = 0x80;
1690 vga_wcrt (cinfo->regbase, CL_CRT1D, tmp2);
1693 /* write pixel panning value to AR33; this does not quite work in 8bpp */
1694 /* ### Piccolo..? Will this work? */
1695 if (info->var.bits_per_pixel == 1)
1696 vga_wattr (cinfo->regbase, CL_AR33, xpix);
1698 cirrusfb_WaitBLT (cinfo->regbase);
1700 DPRINTK ("EXIT\n");
1701 return (0);
1705 int cirrusfb_blank (int blank_mode, struct fb_info *info)
1708 * Blank the screen if blank_mode != 0, else unblank. If blank == NULL
1709 * then the caller blanks by setting the CLUT (Color Look Up Table) to all
1710 * black. Return 0 if blanking succeeded, != 0 if un-/blanking failed due
1711 * to e.g. a video mode which doesn't support it. Implements VESA suspend
1712 * and powerdown modes on hardware that supports disabling hsync/vsync:
1713 * blank_mode == 2: suspend vsync
1714 * blank_mode == 3: suspend hsync
1715 * blank_mode == 4: powerdown
1717 unsigned char val;
1718 struct cirrusfb_info *cinfo = info->par;
1719 int current_mode = cinfo->blank_mode;
1721 DPRINTK ("ENTER, blank mode = %d\n", blank_mode);
1723 if (info->state != FBINFO_STATE_RUNNING ||
1724 current_mode == blank_mode) {
1725 DPRINTK ("EXIT, returning 0\n");
1726 return 0;
1729 /* Undo current */
1730 if (current_mode != VESA_NO_BLANKING) {
1731 /* unblank the screen */
1732 val = vga_rseq (cinfo->regbase, VGA_SEQ_CLOCK_MODE);
1733 vga_wseq (cinfo->regbase, VGA_SEQ_CLOCK_MODE, val & 0xdf); /* clear "FullBandwidth" bit */
1734 /* and undo VESA suspend trickery */
1735 vga_wgfx (cinfo->regbase, CL_GRE, 0x00);
1738 /* set new */
1739 if(blank_mode != VESA_NO_BLANKING) {
1740 /* blank the screen */
1741 val = vga_rseq (cinfo->regbase, VGA_SEQ_CLOCK_MODE);
1742 vga_wseq (cinfo->regbase, VGA_SEQ_CLOCK_MODE, val | 0x20); /* set "FullBandwidth" bit */
1745 switch (blank_mode) {
1746 case VESA_NO_BLANKING:
1747 break;
1748 case VESA_VSYNC_SUSPEND:
1749 vga_wgfx (cinfo->regbase, CL_GRE, 0x04);
1750 break;
1751 case VESA_HSYNC_SUSPEND:
1752 vga_wgfx (cinfo->regbase, CL_GRE, 0x02);
1753 break;
1754 case VESA_POWERDOWN:
1755 vga_wgfx (cinfo->regbase, CL_GRE, 0x06);
1756 break;
1757 default:
1758 DPRINTK ("EXIT, returning 1\n");
1759 return 1;
1762 cinfo->blank_mode = blank_mode;
1763 DPRINTK ("EXIT, returning 0\n");
1764 return 0;
1766 /**** END Hardware specific Routines **************************************/
1767 /****************************************************************************/
1768 /**** BEGIN Internal Routines ***********************************************/
1770 static void init_vgachip (struct cirrusfb_info *cinfo)
1772 const struct cirrusfb_board_info_rec *bi;
1774 DPRINTK ("ENTER\n");
1776 assert (cinfo != NULL);
1778 bi = &cirrusfb_board_info[cinfo->btype];
1780 /* reset board globally */
1781 switch (cinfo->btype) {
1782 case BT_PICCOLO:
1783 WSFR (cinfo, 0x01);
1784 udelay (500);
1785 WSFR (cinfo, 0x51);
1786 udelay (500);
1787 break;
1788 case BT_PICASSO:
1789 WSFR2 (cinfo, 0xff);
1790 udelay (500);
1791 break;
1792 case BT_SD64:
1793 case BT_SPECTRUM:
1794 WSFR (cinfo, 0x1f);
1795 udelay (500);
1796 WSFR (cinfo, 0x4f);
1797 udelay (500);
1798 break;
1799 case BT_PICASSO4:
1800 vga_wcrt (cinfo->regbase, CL_CRT51, 0x00); /* disable flickerfixer */
1801 mdelay (100);
1802 vga_wgfx (cinfo->regbase, CL_GR2F, 0x00); /* from Klaus' NetBSD driver: */
1803 vga_wgfx (cinfo->regbase, CL_GR33, 0x00); /* put blitter into 542x compat */
1804 vga_wgfx (cinfo->regbase, CL_GR31, 0x00); /* mode */
1805 break;
1807 case BT_GD5480:
1808 vga_wgfx (cinfo->regbase, CL_GR2F, 0x00); /* from Klaus' NetBSD driver: */
1809 break;
1811 case BT_ALPINE:
1812 /* Nothing to do to reset the board. */
1813 break;
1815 default:
1816 printk (KERN_ERR "cirrusfb: Warning: Unknown board type\n");
1817 break;
1820 assert (cinfo->size > 0); /* make sure RAM size set by this point */
1822 /* the P4 is not fully initialized here; I rely on it having been */
1823 /* inited under AmigaOS already, which seems to work just fine */
1824 /* (Klaus advised to do it this way) */
1826 if (cinfo->btype != BT_PICASSO4) {
1827 WGen (cinfo, CL_VSSM, 0x10); /* EGS: 0x16 */
1828 WGen (cinfo, CL_POS102, 0x01);
1829 WGen (cinfo, CL_VSSM, 0x08); /* EGS: 0x0e */
1831 if (cinfo->btype != BT_SD64)
1832 WGen (cinfo, CL_VSSM2, 0x01);
1834 vga_wseq (cinfo->regbase, CL_SEQR0, 0x03); /* reset sequencer logic */
1836 vga_wseq (cinfo->regbase, VGA_SEQ_CLOCK_MODE, 0x21); /* FullBandwidth (video off) and 8/9 dot clock */
1837 WGen (cinfo, VGA_MIS_W, 0xc1); /* polarity (-/-), disable access to display memory, VGA_CRTC_START_HI base address: color */
1839 /* vga_wgfx (cinfo->regbase, CL_GRA, 0xce); "magic cookie" - doesn't make any sense to me.. */
1840 vga_wseq (cinfo->regbase, CL_SEQR6, 0x12); /* unlock all extension registers */
1842 vga_wgfx (cinfo->regbase, CL_GR31, 0x04); /* reset blitter */
1844 switch (cinfo->btype) {
1845 case BT_GD5480:
1846 vga_wseq (cinfo->regbase, CL_SEQRF, 0x98);
1847 break;
1848 case BT_ALPINE:
1849 break;
1850 case BT_SD64:
1851 vga_wseq (cinfo->regbase, CL_SEQRF, 0xb8);
1852 break;
1853 default:
1854 vga_wseq (cinfo->regbase, CL_SEQR16, 0x0f);
1855 vga_wseq (cinfo->regbase, CL_SEQRF, 0xb0);
1856 break;
1859 vga_wseq (cinfo->regbase, VGA_SEQ_PLANE_WRITE, 0xff); /* plane mask: nothing */
1860 vga_wseq (cinfo->regbase, VGA_SEQ_CHARACTER_MAP, 0x00); /* character map select: doesn't even matter in gx mode */
1861 vga_wseq (cinfo->regbase, VGA_SEQ_MEMORY_MODE, 0x0e); /* memory mode: chain-4, no odd/even, ext. memory */
1863 /* controller-internal base address of video memory */
1864 if (bi->init_sr07)
1865 vga_wseq (cinfo->regbase, CL_SEQR7, bi->sr07);
1867 /* vga_wseq (cinfo->regbase, CL_SEQR8, 0x00); *//* EEPROM control: shouldn't be necessary to write to this at all.. */
1869 vga_wseq (cinfo->regbase, CL_SEQR10, 0x00); /* graphics cursor X position (incomplete; position gives rem. 3 bits */
1870 vga_wseq (cinfo->regbase, CL_SEQR11, 0x00); /* graphics cursor Y position (..."... ) */
1871 vga_wseq (cinfo->regbase, CL_SEQR12, 0x00); /* graphics cursor attributes */
1872 vga_wseq (cinfo->regbase, CL_SEQR13, 0x00); /* graphics cursor pattern address */
1874 /* writing these on a P4 might give problems.. */
1875 if (cinfo->btype != BT_PICASSO4) {
1876 vga_wseq (cinfo->regbase, CL_SEQR17, 0x00); /* configuration readback and ext. color */
1877 vga_wseq (cinfo->regbase, CL_SEQR18, 0x02); /* signature generator */
1880 /* MCLK select etc. */
1881 if (bi->init_sr1f)
1882 vga_wseq (cinfo->regbase, CL_SEQR1F, bi->sr1f);
1884 vga_wcrt (cinfo->regbase, VGA_CRTC_PRESET_ROW, 0x00); /* Screen A preset row scan: none */
1885 vga_wcrt (cinfo->regbase, VGA_CRTC_CURSOR_START, 0x20); /* Text cursor start: disable text cursor */
1886 vga_wcrt (cinfo->regbase, VGA_CRTC_CURSOR_END, 0x00); /* Text cursor end: - */
1887 vga_wcrt (cinfo->regbase, VGA_CRTC_START_HI, 0x00); /* Screen start address high: 0 */
1888 vga_wcrt (cinfo->regbase, VGA_CRTC_START_LO, 0x00); /* Screen start address low: 0 */
1889 vga_wcrt (cinfo->regbase, VGA_CRTC_CURSOR_HI, 0x00); /* text cursor location high: 0 */
1890 vga_wcrt (cinfo->regbase, VGA_CRTC_CURSOR_LO, 0x00); /* text cursor location low: 0 */
1892 vga_wcrt (cinfo->regbase, VGA_CRTC_UNDERLINE, 0x00); /* Underline Row scanline: - */
1893 vga_wcrt (cinfo->regbase, VGA_CRTC_MODE, 0xc3); /* mode control: timing enable, byte mode, no compat modes */
1894 vga_wcrt (cinfo->regbase, VGA_CRTC_LINE_COMPARE, 0x00); /* Line Compare: not needed */
1895 /* ### add 0x40 for text modes with > 30 MHz pixclock */
1896 vga_wcrt (cinfo->regbase, CL_CRT1B, 0x02); /* ext. display controls: ext.adr. wrap */
1898 vga_wgfx (cinfo->regbase, VGA_GFX_SR_VALUE, 0x00); /* Set/Reset registes: - */
1899 vga_wgfx (cinfo->regbase, VGA_GFX_SR_ENABLE, 0x00); /* Set/Reset enable: - */
1900 vga_wgfx (cinfo->regbase, VGA_GFX_COMPARE_VALUE, 0x00); /* Color Compare: - */
1901 vga_wgfx (cinfo->regbase, VGA_GFX_DATA_ROTATE, 0x00); /* Data Rotate: - */
1902 vga_wgfx (cinfo->regbase, VGA_GFX_PLANE_READ, 0x00); /* Read Map Select: - */
1903 vga_wgfx (cinfo->regbase, VGA_GFX_MODE, 0x00); /* Mode: conf. for 16/4/2 color mode, no odd/even, read/write mode 0 */
1904 vga_wgfx (cinfo->regbase, VGA_GFX_MISC, 0x01); /* Miscellaneous: memory map base address, graphics mode */
1905 vga_wgfx (cinfo->regbase, VGA_GFX_COMPARE_MASK, 0x0f); /* Color Don't care: involve all planes */
1906 vga_wgfx (cinfo->regbase, VGA_GFX_BIT_MASK, 0xff); /* Bit Mask: no mask at all */
1907 if (cinfo->btype == BT_ALPINE)
1908 vga_wgfx (cinfo->regbase, CL_GRB, 0x20); /* (5434 can't have bit 3 set for bitblt) */
1909 else
1910 vga_wgfx (cinfo->regbase, CL_GRB, 0x28); /* Graphics controller mode extensions: finer granularity, 8byte data latches */
1912 vga_wgfx (cinfo->regbase, CL_GRC, 0xff); /* Color Key compare: - */
1913 vga_wgfx (cinfo->regbase, CL_GRD, 0x00); /* Color Key compare mask: - */
1914 vga_wgfx (cinfo->regbase, CL_GRE, 0x00); /* Miscellaneous control: - */
1915 /* vga_wgfx (cinfo->regbase, CL_GR10, 0x00); *//* Background color byte 1: - */
1916 /* vga_wgfx (cinfo->regbase, CL_GR11, 0x00); */
1918 vga_wattr (cinfo->regbase, VGA_ATC_PALETTE0, 0x00); /* Attribute Controller palette registers: "identity mapping" */
1919 vga_wattr (cinfo->regbase, VGA_ATC_PALETTE1, 0x01);
1920 vga_wattr (cinfo->regbase, VGA_ATC_PALETTE2, 0x02);
1921 vga_wattr (cinfo->regbase, VGA_ATC_PALETTE3, 0x03);
1922 vga_wattr (cinfo->regbase, VGA_ATC_PALETTE4, 0x04);
1923 vga_wattr (cinfo->regbase, VGA_ATC_PALETTE5, 0x05);
1924 vga_wattr (cinfo->regbase, VGA_ATC_PALETTE6, 0x06);
1925 vga_wattr (cinfo->regbase, VGA_ATC_PALETTE7, 0x07);
1926 vga_wattr (cinfo->regbase, VGA_ATC_PALETTE8, 0x08);
1927 vga_wattr (cinfo->regbase, VGA_ATC_PALETTE9, 0x09);
1928 vga_wattr (cinfo->regbase, VGA_ATC_PALETTEA, 0x0a);
1929 vga_wattr (cinfo->regbase, VGA_ATC_PALETTEB, 0x0b);
1930 vga_wattr (cinfo->regbase, VGA_ATC_PALETTEC, 0x0c);
1931 vga_wattr (cinfo->regbase, VGA_ATC_PALETTED, 0x0d);
1932 vga_wattr (cinfo->regbase, VGA_ATC_PALETTEE, 0x0e);
1933 vga_wattr (cinfo->regbase, VGA_ATC_PALETTEF, 0x0f);
1935 vga_wattr (cinfo->regbase, VGA_ATC_MODE, 0x01); /* Attribute Controller mode: graphics mode */
1936 vga_wattr (cinfo->regbase, VGA_ATC_OVERSCAN, 0x00); /* Overscan color reg.: reg. 0 */
1937 vga_wattr (cinfo->regbase, VGA_ATC_PLANE_ENABLE, 0x0f); /* Color Plane enable: Enable all 4 planes */
1938 /* ### vga_wattr (cinfo->regbase, CL_AR33, 0x00); * Pixel Panning: - */
1939 vga_wattr (cinfo->regbase, VGA_ATC_COLOR_PAGE, 0x00); /* Color Select: - */
1941 WGen (cinfo, VGA_PEL_MSK, 0xff); /* Pixel mask: no mask */
1943 if (cinfo->btype != BT_ALPINE && cinfo->btype != BT_GD5480)
1944 WGen (cinfo, VGA_MIS_W, 0xc3); /* polarity (-/-), enable display mem, VGA_CRTC_START_HI i/o base = color */
1946 vga_wgfx (cinfo->regbase, CL_GR31, 0x04); /* BLT Start/status: Blitter reset */
1947 vga_wgfx (cinfo->regbase, CL_GR31, 0x00); /* - " - : "end-of-reset" */
1949 /* misc... */
1950 WHDR (cinfo, 0); /* Hidden DAC register: - */
1952 printk (KERN_DEBUG "cirrusfb: This board has %ld bytes of DRAM memory\n", cinfo->size);
1953 DPRINTK ("EXIT\n");
1954 return;
1957 static void switch_monitor (struct cirrusfb_info *cinfo, int on)
1959 #ifdef CONFIG_ZORRO /* only works on Zorro boards */
1960 static int IsOn = 0; /* XXX not ok for multiple boards */
1962 DPRINTK ("ENTER\n");
1964 if (cinfo->btype == BT_PICASSO4)
1965 return; /* nothing to switch */
1966 if (cinfo->btype == BT_ALPINE)
1967 return; /* nothing to switch */
1968 if (cinfo->btype == BT_GD5480)
1969 return; /* nothing to switch */
1970 if (cinfo->btype == BT_PICASSO) {
1971 if ((on && !IsOn) || (!on && IsOn))
1972 WSFR (cinfo, 0xff);
1974 DPRINTK ("EXIT\n");
1975 return;
1977 if (on) {
1978 switch (cinfo->btype) {
1979 case BT_SD64:
1980 WSFR (cinfo, cinfo->SFR | 0x21);
1981 break;
1982 case BT_PICCOLO:
1983 WSFR (cinfo, cinfo->SFR | 0x28);
1984 break;
1985 case BT_SPECTRUM:
1986 WSFR (cinfo, 0x6f);
1987 break;
1988 default: /* do nothing */ break;
1990 } else {
1991 switch (cinfo->btype) {
1992 case BT_SD64:
1993 WSFR (cinfo, cinfo->SFR & 0xde);
1994 break;
1995 case BT_PICCOLO:
1996 WSFR (cinfo, cinfo->SFR & 0xd7);
1997 break;
1998 case BT_SPECTRUM:
1999 WSFR (cinfo, 0x4f);
2000 break;
2001 default: /* do nothing */ break;
2005 DPRINTK ("EXIT\n");
2006 #endif /* CONFIG_ZORRO */
2010 /******************************************/
2011 /* Linux 2.6-style accelerated functions */
2012 /******************************************/
2014 static void cirrusfb_prim_fillrect(struct cirrusfb_info *cinfo,
2015 const struct fb_fillrect *region)
2017 int m; /* bytes per pixel */
2018 if(cinfo->info->var.bits_per_pixel == 1) {
2019 cirrusfb_RectFill(cinfo->regbase, cinfo->info->var.bits_per_pixel,
2020 region->dx / 8, region->dy,
2021 region->width / 8, region->height,
2022 region->color,
2023 cinfo->currentmode.line_length);
2024 } else {
2025 m = ( cinfo->info->var.bits_per_pixel + 7 ) / 8;
2026 cirrusfb_RectFill(cinfo->regbase, cinfo->info->var.bits_per_pixel,
2027 region->dx * m, region->dy,
2028 region->width * m, region->height,
2029 region->color,
2030 cinfo->currentmode.line_length);
2032 return;
2035 void cirrusfb_fillrect (struct fb_info *info, const struct fb_fillrect *region)
2037 struct cirrusfb_info *cinfo = info->par;
2038 struct fb_fillrect modded;
2039 int vxres, vyres;
2041 if (info->state != FBINFO_STATE_RUNNING)
2042 return;
2043 if (info->flags & FBINFO_HWACCEL_DISABLED) {
2044 cfb_fillrect(info, region);
2045 return;
2048 vxres = info->var.xres_virtual;
2049 vyres = info->var.yres_virtual;
2051 memcpy(&modded, region, sizeof(struct fb_fillrect));
2053 if(!modded.width || !modded.height ||
2054 modded.dx >= vxres || modded.dy >= vyres)
2055 return;
2057 if(modded.dx + modded.width > vxres) modded.width = vxres - modded.dx;
2058 if(modded.dy + modded.height > vyres) modded.height = vyres - modded.dy;
2060 cirrusfb_prim_fillrect(cinfo, &modded);
2063 static void cirrusfb_prim_copyarea(struct cirrusfb_info *cinfo,
2064 const struct fb_copyarea *area)
2066 int m; /* bytes per pixel */
2067 if(cinfo->info->var.bits_per_pixel == 1) {
2068 cirrusfb_BitBLT(cinfo->regbase, cinfo->info->var.bits_per_pixel,
2069 area->sx / 8, area->sy,
2070 area->dx / 8, area->dy,
2071 area->width / 8, area->height,
2072 cinfo->currentmode.line_length);
2073 } else {
2074 m = ( cinfo->info->var.bits_per_pixel + 7 ) / 8;
2075 cirrusfb_BitBLT(cinfo->regbase, cinfo->info->var.bits_per_pixel,
2076 area->sx * m, area->sy,
2077 area->dx * m, area->dy,
2078 area->width * m, area->height,
2079 cinfo->currentmode.line_length);
2081 return;
2085 void cirrusfb_copyarea(struct fb_info *info, const struct fb_copyarea *area)
2087 struct cirrusfb_info *cinfo = info->par;
2088 struct fb_copyarea modded;
2089 u32 vxres, vyres;
2090 modded.sx = area->sx;
2091 modded.sy = area->sy;
2092 modded.dx = area->dx;
2093 modded.dy = area->dy;
2094 modded.width = area->width;
2095 modded.height = area->height;
2097 if (info->state != FBINFO_STATE_RUNNING)
2098 return;
2099 if (info->flags & FBINFO_HWACCEL_DISABLED) {
2100 cfb_copyarea(info, area);
2101 return;
2104 vxres = info->var.xres_virtual;
2105 vyres = info->var.yres_virtual;
2107 if(!modded.width || !modded.height ||
2108 modded.sx >= vxres || modded.sy >= vyres ||
2109 modded.dx >= vxres || modded.dy >= vyres)
2110 return;
2112 if(modded.sx + modded.width > vxres) modded.width = vxres - modded.sx;
2113 if(modded.dx + modded.width > vxres) modded.width = vxres - modded.dx;
2114 if(modded.sy + modded.height > vyres) modded.height = vyres - modded.sy;
2115 if(modded.dy + modded.height > vyres) modded.height = vyres - modded.dy;
2117 cirrusfb_prim_copyarea(cinfo, &modded);
2120 void cirrusfb_imageblit(struct fb_info *info, const struct fb_image *image)
2122 struct cirrusfb_info *cinfo = info->par;
2124 cirrusfb_WaitBLT(cinfo->regbase);
2125 cfb_imageblit(info, image);
2129 #ifdef CONFIG_PPC_PREP
2130 #define PREP_VIDEO_BASE ((volatile unsigned long) 0xC0000000)
2131 #define PREP_IO_BASE ((volatile unsigned char *) 0x80000000)
2132 static void get_prep_addrs (unsigned long *display, unsigned long *registers)
2134 DPRINTK ("ENTER\n");
2136 *display = PREP_VIDEO_BASE;
2137 *registers = (unsigned long) PREP_IO_BASE;
2139 DPRINTK ("EXIT\n");
2142 #endif /* CONFIG_PPC_PREP */
2145 #ifdef CONFIG_PCI
2146 static int release_io_ports = 0;
2148 /* Pulled the logic from XFree86 Cirrus driver to get the memory size,
2149 * based on the DRAM bandwidth bit and DRAM bank switching bit. This
2150 * works with 1MB, 2MB and 4MB configurations (which the Motorola boards
2151 * seem to have. */
2152 static unsigned int cirrusfb_get_memsize (caddr_t regbase)
2154 unsigned long mem;
2155 unsigned char SRF;
2157 DPRINTK ("ENTER\n");
2159 SRF = vga_rseq (regbase, CL_SEQRF);
2160 switch ((SRF & 0x18)) {
2161 case 0x08: mem = 512 * 1024; break;
2162 case 0x10: mem = 1024 * 1024; break;
2163 /* 64-bit DRAM data bus width; assume 2MB. Also indicates 2MB memory
2164 * on the 5430. */
2165 case 0x18: mem = 2048 * 1024; break;
2166 default: printk ("CLgenfb: Unknown memory size!\n");
2167 mem = 1024 * 1024;
2169 if (SRF & 0x80) {
2170 /* If DRAM bank switching is enabled, there must be twice as much
2171 * memory installed. (4MB on the 5434) */
2172 mem *= 2;
2174 /* TODO: Handling of GD5446/5480 (see XF86 sources ...) */
2176 DPRINTK ("EXIT\n");
2177 return mem;
2182 static void get_pci_addrs (const struct pci_dev *pdev,
2183 unsigned long *display, unsigned long *registers)
2185 assert (pdev != NULL);
2186 assert (display != NULL);
2187 assert (registers != NULL);
2189 DPRINTK ("ENTER\n");
2191 *display = 0;
2192 *registers = 0;
2194 /* This is a best-guess for now */
2196 if (pci_resource_flags(pdev, 0) & IORESOURCE_IO) {
2197 *display = pci_resource_start(pdev, 1);
2198 *registers = pci_resource_start(pdev, 0);
2199 } else {
2200 *display = pci_resource_start(pdev, 0);
2201 *registers = pci_resource_start(pdev, 1);
2204 assert (*display != 0);
2206 DPRINTK ("EXIT\n");
2210 static void cirrusfb_pci_unmap (struct cirrusfb_info *cinfo)
2212 struct pci_dev *pdev = cinfo->pdev;
2214 iounmap(cinfo->fbmem);
2215 #if 0 /* if system didn't claim this region, we would... */
2216 release_mem_region(0xA0000, 65535);
2217 #endif
2218 if (release_io_ports)
2219 release_region(0x3C0, 32);
2220 pci_release_regions(pdev);
2221 framebuffer_release(cinfo->info);
2222 pci_disable_device(pdev);
2224 #endif /* CONFIG_PCI */
2227 #ifdef CONFIG_ZORRO
2228 static void __devexit cirrusfb_zorro_unmap (struct cirrusfb_info *cinfo)
2230 zorro_release_device(cinfo->zdev);
2232 if (cinfo->btype == BT_PICASSO4) {
2233 cinfo->regbase -= 0x600000;
2234 iounmap ((void *)cinfo->regbase);
2235 iounmap ((void *)cinfo->fbmem);
2236 } else {
2237 if (zorro_resource_start(cinfo->zdev) > 0x01000000)
2238 iounmap ((void *)cinfo->fbmem);
2240 framebuffer_release(cinfo->info);
2242 #endif /* CONFIG_ZORRO */
2244 static int cirrusfb_set_fbinfo(struct cirrusfb_info *cinfo)
2246 struct fb_info *info = cinfo->info;
2247 struct fb_var_screeninfo *var = &info->var;
2249 info->currcon = -1;
2250 info->par = cinfo;
2251 info->pseudo_palette = cinfo->pseudo_palette;
2252 info->flags = FBINFO_DEFAULT
2253 | FBINFO_HWACCEL_XPAN
2254 | FBINFO_HWACCEL_YPAN
2255 | FBINFO_HWACCEL_FILLRECT
2256 | FBINFO_HWACCEL_COPYAREA;
2257 if (noaccel)
2258 info->flags |= FBINFO_HWACCEL_DISABLED;
2259 info->fbops = &cirrusfb_ops;
2260 info->screen_base = cinfo->fbmem;
2261 if (cinfo->btype == BT_GD5480) {
2262 if (var->bits_per_pixel == 16)
2263 info->screen_base += 1 * MB_;
2264 if (var->bits_per_pixel == 24 || var->bits_per_pixel == 32)
2265 info->screen_base += 2 * MB_;
2268 /* Fill fix common fields */
2269 strlcpy(info->fix.id, cirrusfb_board_info[cinfo->btype].name,
2270 sizeof(info->fix.id));
2272 /* monochrome: only 1 memory plane */
2273 /* 8 bit and above: Use whole memory area */
2274 info->fix.smem_start = cinfo->fbmem_phys;
2275 info->fix.smem_len = (var->bits_per_pixel == 1) ? cinfo->size / 4 : cinfo->size;
2276 info->fix.type = cinfo->currentmode.type;
2277 info->fix.type_aux = 0;
2278 info->fix.visual = cinfo->currentmode.visual;
2279 info->fix.xpanstep = 1;
2280 info->fix.ypanstep = 1;
2281 info->fix.ywrapstep = 0;
2282 info->fix.line_length = cinfo->currentmode.line_length;
2284 /* FIXME: map region at 0xB8000 if available, fill in here */
2285 info->fix.mmio_start = cinfo->fbregs_phys;
2286 info->fix.mmio_len = 0;
2287 info->fix.accel = FB_ACCEL_NONE;
2289 fb_alloc_cmap(&info->cmap, 256, 0);
2291 return 0;
2294 static int cirrusfb_register(struct cirrusfb_info *cinfo)
2296 struct fb_info *info;
2297 int err;
2298 cirrusfb_board_t btype;
2300 DPRINTK ("ENTER\n");
2302 printk (KERN_INFO "cirrusfb: Driver for Cirrus Logic based graphic boards, v" CIRRUSFB_VERSION "\n");
2304 info = cinfo->info;
2305 btype = cinfo->btype;
2307 /* sanity checks */
2308 assert (btype != BT_NONE);
2310 DPRINTK ("cirrusfb: (RAM start set to: 0x%p)\n", cinfo->fbmem);
2312 /* Make pretend we've set the var so our structures are in a "good" */
2313 /* state, even though we haven't written the mode to the hw yet... */
2314 info->var = cirrusfb_predefined[cirrusfb_def_mode].var;
2315 info->var.activate = FB_ACTIVATE_NOW;
2317 err = cirrusfb_decode_var(&info->var, &cinfo->currentmode, info);
2318 if (err < 0) {
2319 /* should never happen */
2320 DPRINTK("choking on default var... umm, no good.\n");
2321 goto err_unmap_cirrusfb;
2324 /* set all the vital stuff */
2325 cirrusfb_set_fbinfo(cinfo);
2327 err = register_framebuffer(info);
2328 if (err < 0) {
2329 printk (KERN_ERR "cirrusfb: could not register fb device; err = %d!\n", err);
2330 goto err_dealloc_cmap;
2333 DPRINTK ("EXIT, returning 0\n");
2334 return 0;
2336 err_dealloc_cmap:
2337 fb_dealloc_cmap(&info->cmap);
2338 err_unmap_cirrusfb:
2339 cinfo->unmap(cinfo);
2340 return err;
2343 static void __devexit cirrusfb_cleanup (struct fb_info *info)
2345 struct cirrusfb_info *cinfo = info->par;
2346 DPRINTK ("ENTER\n");
2348 switch_monitor (cinfo, 0);
2350 unregister_framebuffer (info);
2351 fb_dealloc_cmap (&info->cmap);
2352 printk ("Framebuffer unregistered\n");
2353 cinfo->unmap(cinfo);
2355 DPRINTK ("EXIT\n");
2359 #ifdef CONFIG_PCI
2360 static int cirrusfb_pci_register (struct pci_dev *pdev,
2361 const struct pci_device_id *ent)
2363 struct cirrusfb_info *cinfo;
2364 struct fb_info *info;
2365 cirrusfb_board_t btype;
2366 unsigned long board_addr, board_size;
2367 int ret;
2369 ret = pci_enable_device(pdev);
2370 if (ret < 0) {
2371 printk(KERN_ERR "cirrusfb: Cannot enable PCI device\n");
2372 goto err_out;
2375 info = framebuffer_alloc(sizeof(struct cirrusfb_info), &pdev->dev);
2376 if (!info) {
2377 printk(KERN_ERR "cirrusfb: could not allocate memory\n");
2378 ret = -ENOMEM;
2379 goto err_disable;
2382 cinfo = info->par;
2383 cinfo->info = info;
2384 cinfo->pdev = pdev;
2385 cinfo->btype = btype = (cirrusfb_board_t) ent->driver_data;
2387 DPRINTK (" Found PCI device, base address 0 is 0x%lx, btype set to %d\n",
2388 pdev->resource[0].start, btype);
2389 DPRINTK (" base address 1 is 0x%lx\n", pdev->resource[1].start);
2391 if(isPReP) {
2392 pci_write_config_dword (pdev, PCI_BASE_ADDRESS_0, 0x00000000);
2393 #ifdef CONFIG_PPC_PREP
2394 get_prep_addrs (&board_addr, &cinfo->fbregs_phys);
2395 #endif
2396 /* PReP dies if we ioremap the IO registers, but it works w/out... */
2397 cinfo->regbase = (char *) cinfo->fbregs_phys;
2398 } else {
2399 DPRINTK ("Attempt to get PCI info for Cirrus Graphics Card\n");
2400 get_pci_addrs (pdev, &board_addr, &cinfo->fbregs_phys);
2401 cinfo->regbase = NULL; /* FIXME: this forces VGA. alternatives? */
2404 DPRINTK ("Board address: 0x%lx, register address: 0x%lx\n", board_addr, cinfo->fbregs_phys);
2406 board_size = (btype == BT_GD5480) ?
2407 32 * MB_ : cirrusfb_get_memsize (cinfo->regbase);
2409 ret = pci_request_regions(pdev, "cirrusfb");
2410 if (ret <0) {
2411 printk(KERN_ERR "cirrusfb: cannot reserve region 0x%lx, abort\n",
2412 board_addr);
2413 goto err_release_fb;
2415 #if 0 /* if the system didn't claim this region, we would... */
2416 if (!request_mem_region(0xA0000, 65535, "cirrusfb")) {
2417 printk(KERN_ERR "cirrusfb: cannot reserve region 0x%lx, abort\n"
2419 0xA0000L);
2420 ret = -EBUSY;
2421 goto err_release_regions;
2423 #endif
2424 if (request_region(0x3C0, 32, "cirrusfb"))
2425 release_io_ports = 1;
2427 cinfo->fbmem = ioremap(board_addr, board_size);
2428 if (!cinfo->fbmem) {
2429 ret = -EIO;
2430 goto err_release_legacy;
2433 cinfo->fbmem_phys = board_addr;
2434 cinfo->size = board_size;
2435 cinfo->unmap = cirrusfb_pci_unmap;
2437 printk (" RAM (%lu kB) at 0xx%lx, ", cinfo->size / KB_, board_addr);
2438 printk ("Cirrus Logic chipset on PCI bus\n");
2439 pci_set_drvdata(pdev, info);
2441 return cirrusfb_register(cinfo);
2443 err_release_legacy:
2444 if (release_io_ports)
2445 release_region(0x3C0, 32);
2446 #if 0
2447 release_mem_region(0xA0000, 65535);
2448 err_release_regions:
2449 #endif
2450 pci_release_regions(pdev);
2451 err_release_fb:
2452 framebuffer_release(info);
2453 err_disable:
2454 pci_disable_device(pdev);
2455 err_out:
2456 return ret;
2459 void __devexit cirrusfb_pci_unregister (struct pci_dev *pdev)
2461 struct fb_info *info = pci_get_drvdata(pdev);
2462 DPRINTK ("ENTER\n");
2464 cirrusfb_cleanup (info);
2466 DPRINTK ("EXIT\n");
2469 static struct pci_driver cirrusfb_pci_driver = {
2470 .name = "cirrusfb",
2471 .id_table = cirrusfb_pci_table,
2472 .probe = cirrusfb_pci_register,
2473 .remove = __devexit_p(cirrusfb_pci_unregister),
2474 #ifdef CONFIG_PM
2475 #if 0
2476 .suspend = cirrusfb_pci_suspend,
2477 .resume = cirrusfb_pci_resume,
2478 #endif
2479 #endif
2481 #endif /* CONFIG_PCI */
2484 #ifdef CONFIG_ZORRO
2485 static int cirrusfb_zorro_register(struct zorro_dev *z,
2486 const struct zorro_device_id *ent)
2488 struct cirrusfb_info *cinfo;
2489 struct fb_info *info;
2490 cirrusfb_board_t btype;
2491 struct zorro_dev *z2 = NULL;
2492 unsigned long board_addr, board_size, size;
2493 int ret;
2495 btype = ent->driver_data;
2496 if (cirrusfb_zorro_table2[btype].id2)
2497 z2 = zorro_find_device(cirrusfb_zorro_table2[btype].id2, NULL);
2498 size = cirrusfb_zorro_table2[btype].size;
2499 printk(KERN_INFO "cirrusfb: %s board detected; ",
2500 cirrusfb_board_info[btype].name);
2502 info = framebuffer_alloc(sizeof(struct cirrusfb_info), &z->dev);
2503 if (!info) {
2504 printk (KERN_ERR "cirrusfb: could not allocate memory\n");
2505 ret = -ENOMEM;
2506 goto err_out;
2509 cinfo = info->par;
2510 cinfo->info = info;
2511 cinfo->btype = btype;
2513 assert (z > 0);
2514 assert (z2 >= 0);
2515 assert (btype != BT_NONE);
2517 cinfo->zdev = z;
2518 board_addr = zorro_resource_start(z);
2519 board_size = zorro_resource_len(z);
2520 cinfo->size = size;
2522 if (!zorro_request_device(z, "cirrusfb")) {
2523 printk(KERN_ERR "cirrusfb: cannot reserve region 0x%lx, abort\n",
2524 board_addr);
2525 ret = -EBUSY;
2526 goto err_release_fb;
2529 printk (" RAM (%lu MB) at $%lx, ", board_size / MB_, board_addr);
2531 ret = -EIO;
2533 if (btype == BT_PICASSO4) {
2534 printk (" REG at $%lx\n", board_addr + 0x600000);
2536 /* To be precise, for the P4 this is not the */
2537 /* begin of the board, but the begin of RAM. */
2538 /* for P4, map in its address space in 2 chunks (### TEST! ) */
2539 /* (note the ugly hardcoded 16M number) */
2540 cinfo->regbase = ioremap (board_addr, 16777216);
2541 if (!cinfo->regbase)
2542 goto err_release_region;
2544 DPRINTK ("cirrusfb: Virtual address for board set to: $%p\n", cinfo->regbase);
2545 cinfo->regbase += 0x600000;
2546 cinfo->fbregs_phys = board_addr + 0x600000;
2548 cinfo->fbmem_phys = board_addr + 16777216;
2549 cinfo->fbmem = ioremap (cinfo->fbmem_phys, 16777216);
2550 if (!cinfo->fbmem)
2551 goto err_unmap_regbase;
2552 } else {
2553 printk (" REG at $%lx\n", (unsigned long) z2->resource.start);
2555 cinfo->fbmem_phys = board_addr;
2556 if (board_addr > 0x01000000)
2557 cinfo->fbmem = ioremap (board_addr, board_size);
2558 else
2559 cinfo->fbmem = (caddr_t) ZTWO_VADDR (board_addr);
2560 if (!cinfo->fbmem)
2561 goto err_release_region;
2563 /* set address for REG area of board */
2564 cinfo->regbase = (caddr_t) ZTWO_VADDR (z2->resource.start);
2565 cinfo->fbregs_phys = z2->resource.start;
2567 DPRINTK ("cirrusfb: Virtual address for board set to: $%p\n", cinfo->regbase);
2569 cinfo->unmap = cirrusfb_zorro_unmap;
2571 printk (KERN_INFO "Cirrus Logic chipset on Zorro bus\n");
2572 zorro_set_drvdata(z, info);
2574 return cirrusfb_register(cinfo);
2576 err_unmap_regbase:
2577 /* Parental advisory: explicit hack */
2578 iounmap(cinfo->regbase - 0x600000);
2579 err_release_region:
2580 release_region(board_addr, board_size);
2581 err_release_fb:
2582 framebuffer_release(info);
2583 err_out:
2584 return ret;
2587 void __devexit cirrusfb_zorro_unregister(struct zorro_dev *z)
2589 struct fb_info *info = zorro_get_drvdata(z);
2590 DPRINTK ("ENTER\n");
2592 cirrusfb_cleanup (info);
2594 DPRINTK ("EXIT\n");
2597 static struct zorro_driver cirrusfb_zorro_driver = {
2598 .name = "cirrusfb",
2599 .id_table = cirrusfb_zorro_table,
2600 .probe = cirrusfb_zorro_register,
2601 .remove = __devexit_p(cirrusfb_zorro_unregister),
2603 #endif /* CONFIG_ZORRO */
2605 int __init cirrusfb_init(void)
2607 int error = 0;
2609 #ifndef MODULE
2610 char *option = NULL;
2612 if (fb_get_options("cirrusfb", &option))
2613 return -ENODEV;
2614 cirrusfb_setup(option);
2615 #endif
2617 #ifdef CONFIG_ZORRO
2618 error |= zorro_module_init(&cirrusfb_zorro_driver);
2619 #endif
2620 #ifdef CONFIG_PCI
2621 error |= pci_module_init(&cirrusfb_pci_driver);
2622 #endif
2623 return error;
2628 #ifndef MODULE
2629 int __init cirrusfb_setup(char *options) {
2630 char *this_opt, s[32];
2631 int i;
2633 DPRINTK ("ENTER\n");
2635 if (!options || !*options)
2636 return 0;
2638 while ((this_opt = strsep (&options, ",")) != NULL) {
2639 if (!*this_opt) continue;
2641 DPRINTK("cirrusfb_setup: option '%s'\n", this_opt);
2643 for (i = 0; i < NUM_TOTAL_MODES; i++) {
2644 sprintf (s, "mode:%s", cirrusfb_predefined[i].name);
2645 if (strcmp (this_opt, s) == 0)
2646 cirrusfb_def_mode = i;
2648 if (!strcmp(this_opt, "noaccel"))
2649 noaccel = 1;
2651 return 0;
2653 #endif
2657 * Modularization
2660 MODULE_AUTHOR("Copyright 1999,2000 Jeff Garzik <jgarzik@pobox.com>");
2661 MODULE_DESCRIPTION("Accelerated FBDev driver for Cirrus Logic chips");
2662 MODULE_LICENSE("GPL");
2664 void __exit cirrusfb_exit (void)
2666 #ifdef CONFIG_PCI
2667 pci_unregister_driver(&cirrusfb_pci_driver);
2668 #endif
2669 #ifdef CONFIG_ZORRO
2670 zorro_unregister_driver(&cirrusfb_zorro_driver);
2671 #endif
2674 module_init(cirrusfb_init);
2676 #ifdef MODULE
2677 module_exit(cirrusfb_exit);
2678 #endif
2681 /**********************************************************************/
2682 /* about the following functions - I have used the same names for the */
2683 /* functions as Markus Wild did in his Retina driver for NetBSD as */
2684 /* they just made sense for this purpose. Apart from that, I wrote */
2685 /* these functions myself. */
2686 /**********************************************************************/
2688 /*** WGen() - write into one of the external/general registers ***/
2689 static void WGen (const struct cirrusfb_info *cinfo,
2690 int regnum, unsigned char val)
2692 unsigned long regofs = 0;
2694 if (cinfo->btype == BT_PICASSO) {
2695 /* Picasso II specific hack */
2696 /* if (regnum == VGA_PEL_IR || regnum == VGA_PEL_D || regnum == CL_VSSM2) */
2697 if (regnum == VGA_PEL_IR || regnum == VGA_PEL_D)
2698 regofs = 0xfff;
2701 vga_w (cinfo->regbase, regofs + regnum, val);
2704 /*** RGen() - read out one of the external/general registers ***/
2705 static unsigned char RGen (const struct cirrusfb_info *cinfo, int regnum)
2707 unsigned long regofs = 0;
2709 if (cinfo->btype == BT_PICASSO) {
2710 /* Picasso II specific hack */
2711 /* if (regnum == VGA_PEL_IR || regnum == VGA_PEL_D || regnum == CL_VSSM2) */
2712 if (regnum == VGA_PEL_IR || regnum == VGA_PEL_D)
2713 regofs = 0xfff;
2716 return vga_r (cinfo->regbase, regofs + regnum);
2719 /*** AttrOn() - turn on VideoEnable for Attribute controller ***/
2720 static void AttrOn (const struct cirrusfb_info *cinfo)
2722 assert (cinfo != NULL);
2724 DPRINTK ("ENTER\n");
2726 if (vga_rcrt (cinfo->regbase, CL_CRT24) & 0x80) {
2727 /* if we're just in "write value" mode, write back the */
2728 /* same value as before to not modify anything */
2729 vga_w (cinfo->regbase, VGA_ATT_IW,
2730 vga_r (cinfo->regbase, VGA_ATT_R));
2732 /* turn on video bit */
2733 /* vga_w (cinfo->regbase, VGA_ATT_IW, 0x20); */
2734 vga_w (cinfo->regbase, VGA_ATT_IW, 0x33);
2736 /* dummy write on Reg0 to be on "write index" mode next time */
2737 vga_w (cinfo->regbase, VGA_ATT_IW, 0x00);
2739 DPRINTK ("EXIT\n");
2742 /*** WHDR() - write into the Hidden DAC register ***/
2743 /* as the HDR is the only extension register that requires special treatment
2744 * (the other extension registers are accessible just like the "ordinary"
2745 * registers of their functional group) here is a specialized routine for
2746 * accessing the HDR
2748 static void WHDR (const struct cirrusfb_info *cinfo, unsigned char val)
2750 unsigned char dummy;
2752 if (cinfo->btype == BT_PICASSO) {
2753 /* Klaus' hint for correct access to HDR on some boards */
2754 /* first write 0 to pixel mask (3c6) */
2755 WGen (cinfo, VGA_PEL_MSK, 0x00);
2756 udelay (200);
2757 /* next read dummy from pixel address (3c8) */
2758 dummy = RGen (cinfo, VGA_PEL_IW);
2759 udelay (200);
2761 /* now do the usual stuff to access the HDR */
2763 dummy = RGen (cinfo, VGA_PEL_MSK);
2764 udelay (200);
2765 dummy = RGen (cinfo, VGA_PEL_MSK);
2766 udelay (200);
2767 dummy = RGen (cinfo, VGA_PEL_MSK);
2768 udelay (200);
2769 dummy = RGen (cinfo, VGA_PEL_MSK);
2770 udelay (200);
2772 WGen (cinfo, VGA_PEL_MSK, val);
2773 udelay (200);
2775 if (cinfo->btype == BT_PICASSO) {
2776 /* now first reset HDR access counter */
2777 dummy = RGen (cinfo, VGA_PEL_IW);
2778 udelay (200);
2780 /* and at the end, restore the mask value */
2781 /* ## is this mask always 0xff? */
2782 WGen (cinfo, VGA_PEL_MSK, 0xff);
2783 udelay (200);
2788 /*** WSFR() - write to the "special function register" (SFR) ***/
2789 static void WSFR (struct cirrusfb_info *cinfo, unsigned char val)
2791 #ifdef CONFIG_ZORRO
2792 assert (cinfo->regbase != NULL);
2793 cinfo->SFR = val;
2794 z_writeb (val, cinfo->regbase + 0x8000);
2795 #endif
2798 /* The Picasso has a second register for switching the monitor bit */
2799 static void WSFR2 (struct cirrusfb_info *cinfo, unsigned char val)
2801 #ifdef CONFIG_ZORRO
2802 /* writing an arbitrary value to this one causes the monitor switcher */
2803 /* to flip to Amiga display */
2804 assert (cinfo->regbase != NULL);
2805 cinfo->SFR = val;
2806 z_writeb (val, cinfo->regbase + 0x9000);
2807 #endif
2811 /*** WClut - set CLUT entry (range: 0..63) ***/
2812 static void WClut (struct cirrusfb_info *cinfo, unsigned char regnum, unsigned char red,
2813 unsigned char green, unsigned char blue)
2815 unsigned int data = VGA_PEL_D;
2817 /* address write mode register is not translated.. */
2818 vga_w (cinfo->regbase, VGA_PEL_IW, regnum);
2820 if (cinfo->btype == BT_PICASSO || cinfo->btype == BT_PICASSO4 ||
2821 cinfo->btype == BT_ALPINE || cinfo->btype == BT_GD5480) {
2822 /* but DAC data register IS, at least for Picasso II */
2823 if (cinfo->btype == BT_PICASSO)
2824 data += 0xfff;
2825 vga_w (cinfo->regbase, data, red);
2826 vga_w (cinfo->regbase, data, green);
2827 vga_w (cinfo->regbase, data, blue);
2828 } else {
2829 vga_w (cinfo->regbase, data, blue);
2830 vga_w (cinfo->regbase, data, green);
2831 vga_w (cinfo->regbase, data, red);
2836 #if 0
2837 /*** RClut - read CLUT entry (range 0..63) ***/
2838 static void RClut (struct cirrusfb_info *cinfo, unsigned char regnum, unsigned char *red,
2839 unsigned char *green, unsigned char *blue)
2841 unsigned int data = VGA_PEL_D;
2843 vga_w (cinfo->regbase, VGA_PEL_IR, regnum);
2845 if (cinfo->btype == BT_PICASSO || cinfo->btype == BT_PICASSO4 ||
2846 cinfo->btype == BT_ALPINE || cinfo->btype == BT_GD5480) {
2847 if (cinfo->btype == BT_PICASSO)
2848 data += 0xfff;
2849 *red = vga_r (cinfo->regbase, data);
2850 *green = vga_r (cinfo->regbase, data);
2851 *blue = vga_r (cinfo->regbase, data);
2852 } else {
2853 *blue = vga_r (cinfo->regbase, data);
2854 *green = vga_r (cinfo->regbase, data);
2855 *red = vga_r (cinfo->regbase, data);
2858 #endif
2861 /*******************************************************************
2862 cirrusfb_WaitBLT()
2864 Wait for the BitBLT engine to complete a possible earlier job
2865 *********************************************************************/
2867 /* FIXME: use interrupts instead */
2868 static void cirrusfb_WaitBLT (caddr_t regbase)
2870 /* now busy-wait until we're done */
2871 while (vga_rgfx (regbase, CL_GR31) & 0x08)
2872 /* do nothing */ ;
2875 /*******************************************************************
2876 cirrusfb_BitBLT()
2878 perform accelerated "scrolling"
2879 ********************************************************************/
2881 static void cirrusfb_BitBLT (caddr_t regbase, int bits_per_pixel,
2882 u_short curx, u_short cury, u_short destx, u_short desty,
2883 u_short width, u_short height, u_short line_length)
2885 u_short nwidth, nheight;
2886 u_long nsrc, ndest;
2887 u_char bltmode;
2889 DPRINTK ("ENTER\n");
2891 nwidth = width - 1;
2892 nheight = height - 1;
2894 bltmode = 0x00;
2895 /* if source adr < dest addr, do the Blt backwards */
2896 if (cury <= desty) {
2897 if (cury == desty) {
2898 /* if src and dest are on the same line, check x */
2899 if (curx < destx)
2900 bltmode |= 0x01;
2901 } else
2902 bltmode |= 0x01;
2904 if (!bltmode) {
2905 /* standard case: forward blitting */
2906 nsrc = (cury * line_length) + curx;
2907 ndest = (desty * line_length) + destx;
2908 } else {
2909 /* this means start addresses are at the end, counting backwards */
2910 nsrc = cury * line_length + curx + nheight * line_length + nwidth;
2911 ndest = desty * line_length + destx + nheight * line_length + nwidth;
2915 run-down of registers to be programmed:
2916 destination pitch
2917 source pitch
2918 BLT width/height
2919 source start
2920 destination start
2921 BLT mode
2922 BLT ROP
2923 VGA_GFX_SR_VALUE / VGA_GFX_SR_ENABLE: "fill color"
2924 start/stop
2927 cirrusfb_WaitBLT(regbase);
2929 /* pitch: set to line_length */
2930 vga_wgfx (regbase, CL_GR24, line_length & 0xff); /* dest pitch low */
2931 vga_wgfx (regbase, CL_GR25, (line_length >> 8)); /* dest pitch hi */
2932 vga_wgfx (regbase, CL_GR26, line_length & 0xff); /* source pitch low */
2933 vga_wgfx (regbase, CL_GR27, (line_length >> 8)); /* source pitch hi */
2935 /* BLT width: actual number of pixels - 1 */
2936 vga_wgfx (regbase, CL_GR20, nwidth & 0xff); /* BLT width low */
2937 vga_wgfx (regbase, CL_GR21, (nwidth >> 8)); /* BLT width hi */
2939 /* BLT height: actual number of lines -1 */
2940 vga_wgfx (regbase, CL_GR22, nheight & 0xff); /* BLT height low */
2941 vga_wgfx (regbase, CL_GR23, (nheight >> 8)); /* BLT width hi */
2943 /* BLT destination */
2944 vga_wgfx (regbase, CL_GR28, (u_char) (ndest & 0xff)); /* BLT dest low */
2945 vga_wgfx (regbase, CL_GR29, (u_char) (ndest >> 8)); /* BLT dest mid */
2946 vga_wgfx (regbase, CL_GR2A, (u_char) (ndest >> 16)); /* BLT dest hi */
2948 /* BLT source */
2949 vga_wgfx (regbase, CL_GR2C, (u_char) (nsrc & 0xff)); /* BLT src low */
2950 vga_wgfx (regbase, CL_GR2D, (u_char) (nsrc >> 8)); /* BLT src mid */
2951 vga_wgfx (regbase, CL_GR2E, (u_char) (nsrc >> 16)); /* BLT src hi */
2953 /* BLT mode */
2954 vga_wgfx (regbase, CL_GR30, bltmode); /* BLT mode */
2956 /* BLT ROP: SrcCopy */
2957 vga_wgfx (regbase, CL_GR32, 0x0d); /* BLT ROP */
2959 /* and finally: GO! */
2960 vga_wgfx (regbase, CL_GR31, 0x02); /* BLT Start/status */
2962 DPRINTK ("EXIT\n");
2966 /*******************************************************************
2967 cirrusfb_RectFill()
2969 perform accelerated rectangle fill
2970 ********************************************************************/
2972 static void cirrusfb_RectFill (caddr_t regbase, int bits_per_pixel,
2973 u_short x, u_short y, u_short width, u_short height,
2974 u_char color, u_short line_length)
2976 u_short nwidth, nheight;
2977 u_long ndest;
2978 u_char op;
2980 DPRINTK ("ENTER\n");
2982 nwidth = width - 1;
2983 nheight = height - 1;
2985 ndest = (y * line_length) + x;
2987 cirrusfb_WaitBLT(regbase);
2989 /* pitch: set to line_length */
2990 vga_wgfx (regbase, CL_GR24, line_length & 0xff); /* dest pitch low */
2991 vga_wgfx (regbase, CL_GR25, (line_length >> 8)); /* dest pitch hi */
2992 vga_wgfx (regbase, CL_GR26, line_length & 0xff); /* source pitch low */
2993 vga_wgfx (regbase, CL_GR27, (line_length >> 8)); /* source pitch hi */
2995 /* BLT width: actual number of pixels - 1 */
2996 vga_wgfx (regbase, CL_GR20, nwidth & 0xff); /* BLT width low */
2997 vga_wgfx (regbase, CL_GR21, (nwidth >> 8)); /* BLT width hi */
2999 /* BLT height: actual number of lines -1 */
3000 vga_wgfx (regbase, CL_GR22, nheight & 0xff); /* BLT height low */
3001 vga_wgfx (regbase, CL_GR23, (nheight >> 8)); /* BLT width hi */
3003 /* BLT destination */
3004 vga_wgfx (regbase, CL_GR28, (u_char) (ndest & 0xff)); /* BLT dest low */
3005 vga_wgfx (regbase, CL_GR29, (u_char) (ndest >> 8)); /* BLT dest mid */
3006 vga_wgfx (regbase, CL_GR2A, (u_char) (ndest >> 16)); /* BLT dest hi */
3008 /* BLT source: set to 0 (is a dummy here anyway) */
3009 vga_wgfx (regbase, CL_GR2C, 0x00); /* BLT src low */
3010 vga_wgfx (regbase, CL_GR2D, 0x00); /* BLT src mid */
3011 vga_wgfx (regbase, CL_GR2E, 0x00); /* BLT src hi */
3013 /* This is a ColorExpand Blt, using the */
3014 /* same color for foreground and background */
3015 vga_wgfx (regbase, VGA_GFX_SR_VALUE, color); /* foreground color */
3016 vga_wgfx (regbase, VGA_GFX_SR_ENABLE, color); /* background color */
3018 op = 0xc0;
3019 if (bits_per_pixel == 16) {
3020 vga_wgfx (regbase, CL_GR10, color); /* foreground color */
3021 vga_wgfx (regbase, CL_GR11, color); /* background color */
3022 op = 0x50;
3023 op = 0xd0;
3024 } else if (bits_per_pixel == 32) {
3025 vga_wgfx (regbase, CL_GR10, color); /* foreground color */
3026 vga_wgfx (regbase, CL_GR11, color); /* background color */
3027 vga_wgfx (regbase, CL_GR12, color); /* foreground color */
3028 vga_wgfx (regbase, CL_GR13, color); /* background color */
3029 vga_wgfx (regbase, CL_GR14, 0); /* foreground color */
3030 vga_wgfx (regbase, CL_GR15, 0); /* background color */
3031 op = 0x50;
3032 op = 0xf0;
3034 /* BLT mode: color expand, Enable 8x8 copy (faster?) */
3035 vga_wgfx (regbase, CL_GR30, op); /* BLT mode */
3037 /* BLT ROP: SrcCopy */
3038 vga_wgfx (regbase, CL_GR32, 0x0d); /* BLT ROP */
3040 /* and finally: GO! */
3041 vga_wgfx (regbase, CL_GR31, 0x02); /* BLT Start/status */
3043 DPRINTK ("EXIT\n");
3047 /**************************************************************************
3048 * bestclock() - determine closest possible clock lower(?) than the
3049 * desired pixel clock
3050 **************************************************************************/
3051 static void bestclock (long freq, long *best, long *nom,
3052 long *den, long *div, long maxfreq)
3054 long n, h, d, f;
3056 assert (best != NULL);
3057 assert (nom != NULL);
3058 assert (den != NULL);
3059 assert (div != NULL);
3060 assert (maxfreq > 0);
3062 *nom = 0;
3063 *den = 0;
3064 *div = 0;
3066 DPRINTK ("ENTER\n");
3068 if (freq < 8000)
3069 freq = 8000;
3071 if (freq > maxfreq)
3072 freq = maxfreq;
3074 *best = 0;
3075 f = freq * 10;
3077 for (n = 32; n < 128; n++) {
3078 d = (143181 * n) / f;
3079 if ((d >= 7) && (d <= 63)) {
3080 if (d > 31)
3081 d = (d / 2) * 2;
3082 h = (14318 * n) / d;
3083 if (abs (h - freq) < abs (*best - freq)) {
3084 *best = h;
3085 *nom = n;
3086 if (d < 32) {
3087 *den = d;
3088 *div = 0;
3089 } else {
3090 *den = d / 2;
3091 *div = 1;
3095 d = ((143181 * n) + f - 1) / f;
3096 if ((d >= 7) && (d <= 63)) {
3097 if (d > 31)
3098 d = (d / 2) * 2;
3099 h = (14318 * n) / d;
3100 if (abs (h - freq) < abs (*best - freq)) {
3101 *best = h;
3102 *nom = n;
3103 if (d < 32) {
3104 *den = d;
3105 *div = 0;
3106 } else {
3107 *den = d / 2;
3108 *div = 1;
3114 DPRINTK ("Best possible values for given frequency:\n");
3115 DPRINTK (" best: %ld kHz nom: %ld den: %ld div: %ld\n",
3116 freq, *nom, *den, *div);
3118 DPRINTK ("EXIT\n");
3122 /* -------------------------------------------------------------------------
3124 * debugging functions
3126 * -------------------------------------------------------------------------
3129 #ifdef CIRRUSFB_DEBUG
3132 * cirrusfb_dbg_print_byte
3133 * @name: name associated with byte value to be displayed
3134 * @val: byte value to be displayed
3136 * DESCRIPTION:
3137 * Display an indented string, along with a hexidecimal byte value, and
3138 * its decoded bits. Bits 7 through 0 are listed in left-to-right
3139 * order.
3142 static
3143 void cirrusfb_dbg_print_byte (const char *name, unsigned char val)
3145 DPRINTK ("%8s = 0x%02X (bits 7-0: %c%c%c%c%c%c%c%c)\n",
3146 name, val,
3147 val & 0x80 ? '1' : '0',
3148 val & 0x40 ? '1' : '0',
3149 val & 0x20 ? '1' : '0',
3150 val & 0x10 ? '1' : '0',
3151 val & 0x08 ? '1' : '0',
3152 val & 0x04 ? '1' : '0',
3153 val & 0x02 ? '1' : '0',
3154 val & 0x01 ? '1' : '0');
3159 * cirrusfb_dbg_print_regs
3160 * @base: If using newmmio, the newmmio base address, otherwise %NULL
3161 * @reg_class: type of registers to read: %CRT, or %SEQ
3163 * DESCRIPTION:
3164 * Dumps the given list of VGA CRTC registers. If @base is %NULL,
3165 * old-style I/O ports are queried for information, otherwise MMIO is
3166 * used at the given @base address to query the information.
3169 static
3170 void cirrusfb_dbg_print_regs (caddr_t regbase, cirrusfb_dbg_reg_class_t reg_class,...)
3172 va_list list;
3173 unsigned char val = 0;
3174 unsigned reg;
3175 char *name;
3177 va_start (list, reg_class);
3179 name = va_arg (list, char *);
3180 while (name != NULL) {
3181 reg = va_arg (list, int);
3183 switch (reg_class) {
3184 case CRT:
3185 val = vga_rcrt (regbase, (unsigned char) reg);
3186 break;
3187 case SEQ:
3188 val = vga_rseq (regbase, (unsigned char) reg);
3189 break;
3190 default:
3191 /* should never occur */
3192 assert (FALSE);
3193 break;
3196 cirrusfb_dbg_print_byte (name, val);
3198 name = va_arg (list, char *);
3201 va_end (list);
3206 * cirrusfb_dump
3207 * @cirrusfbinfo:
3209 * DESCRIPTION:
3212 static
3213 void cirrusfb_dump (void)
3215 cirrusfb_dbg_reg_dump (NULL);
3220 * cirrusfb_dbg_reg_dump
3221 * @base: If using newmmio, the newmmio base address, otherwise %NULL
3223 * DESCRIPTION:
3224 * Dumps a list of interesting VGA and CIRRUSFB registers. If @base is %NULL,
3225 * old-style I/O ports are queried for information, otherwise MMIO is
3226 * used at the given @base address to query the information.
3229 static
3230 void cirrusfb_dbg_reg_dump (caddr_t regbase)
3232 DPRINTK ("CIRRUSFB VGA CRTC register dump:\n");
3234 cirrusfb_dbg_print_regs (regbase, CRT,
3235 "CR00", 0x00,
3236 "CR01", 0x01,
3237 "CR02", 0x02,
3238 "CR03", 0x03,
3239 "CR04", 0x04,
3240 "CR05", 0x05,
3241 "CR06", 0x06,
3242 "CR07", 0x07,
3243 "CR08", 0x08,
3244 "CR09", 0x09,
3245 "CR0A", 0x0A,
3246 "CR0B", 0x0B,
3247 "CR0C", 0x0C,
3248 "CR0D", 0x0D,
3249 "CR0E", 0x0E,
3250 "CR0F", 0x0F,
3251 "CR10", 0x10,
3252 "CR11", 0x11,
3253 "CR12", 0x12,
3254 "CR13", 0x13,
3255 "CR14", 0x14,
3256 "CR15", 0x15,
3257 "CR16", 0x16,
3258 "CR17", 0x17,
3259 "CR18", 0x18,
3260 "CR22", 0x22,
3261 "CR24", 0x24,
3262 "CR26", 0x26,
3263 "CR2D", 0x2D,
3264 "CR2E", 0x2E,
3265 "CR2F", 0x2F,
3266 "CR30", 0x30,
3267 "CR31", 0x31,
3268 "CR32", 0x32,
3269 "CR33", 0x33,
3270 "CR34", 0x34,
3271 "CR35", 0x35,
3272 "CR36", 0x36,
3273 "CR37", 0x37,
3274 "CR38", 0x38,
3275 "CR39", 0x39,
3276 "CR3A", 0x3A,
3277 "CR3B", 0x3B,
3278 "CR3C", 0x3C,
3279 "CR3D", 0x3D,
3280 "CR3E", 0x3E,
3281 "CR3F", 0x3F,
3282 NULL);
3284 DPRINTK ("\n");
3286 DPRINTK ("CIRRUSFB VGA SEQ register dump:\n");
3288 cirrusfb_dbg_print_regs (regbase, SEQ,
3289 "SR00", 0x00,
3290 "SR01", 0x01,
3291 "SR02", 0x02,
3292 "SR03", 0x03,
3293 "SR04", 0x04,
3294 "SR08", 0x08,
3295 "SR09", 0x09,
3296 "SR0A", 0x0A,
3297 "SR0B", 0x0B,
3298 "SR0D", 0x0D,
3299 "SR10", 0x10,
3300 "SR11", 0x11,
3301 "SR12", 0x12,
3302 "SR13", 0x13,
3303 "SR14", 0x14,
3304 "SR15", 0x15,
3305 "SR16", 0x16,
3306 "SR17", 0x17,
3307 "SR18", 0x18,
3308 "SR19", 0x19,
3309 "SR1A", 0x1A,
3310 "SR1B", 0x1B,
3311 "SR1C", 0x1C,
3312 "SR1D", 0x1D,
3313 "SR1E", 0x1E,
3314 "SR1F", 0x1F,
3315 NULL);
3317 DPRINTK ("\n");
3320 #endif /* CIRRUSFB_DEBUG */