[PATCH] update copyright and licensing
[linux-2.6/history.git] / drivers / video / cirrusfb.c
blobcec5a7d9de27746b52491f91e8d06f4e29e5ff43
1 /*
2 * drivers/video/clgenfb.c - driver for Cirrus Logic chipsets
4 * Copyright 1999-2001 Jeff Garzik <jgarzik@pobox.com>
6 * Contributors (thanks, all!)
8 * Jeff Rugen:
9 * Major contributions; Motorola PowerStack (PPC and PCI) support,
10 * GD54xx, 1280x1024 mode support, change MCLK based on VCLK.
12 * Geert Uytterhoeven:
13 * Excellent code review.
15 * Lars Hecking:
16 * Amiga updates and testing.
18 * Original clgenfb author: Frank Neumann
20 * Based on retz3fb.c and clgen.c:
21 * Copyright (C) 1997 Jes Sorensen
22 * Copyright (C) 1996 Frank Neumann
24 ***************************************************************
26 * Format this code with GNU indent '-kr -i8 -pcs' options.
28 * This file is subject to the terms and conditions of the GNU General Public
29 * License. See the file COPYING in the main directory of this archive
30 * for more details.
34 #define CLGEN_VERSION "1.9.9.1"
36 #include <linux/config.h>
37 #include <linux/module.h>
38 #include <linux/kernel.h>
39 #include <linux/errno.h>
40 #include <linux/string.h>
41 #include <linux/mm.h>
42 #include <linux/tty.h>
43 #include <linux/slab.h>
44 #include <linux/delay.h>
45 #include <linux/fb.h>
46 #include <linux/init.h>
47 #include <linux/selection.h>
48 #include <asm/pgtable.h>
50 #ifdef CONFIG_ZORRO
51 #include <linux/zorro.h>
52 #endif
53 #ifdef CONFIG_PCI
54 #include <linux/pci.h>
55 #endif
56 #ifdef CONFIG_AMIGA
57 #include <asm/amigahw.h>
58 #endif
59 #ifdef CONFIG_PPC_PREP
60 #include <asm/processor.h>
61 #define isPReP (_machine == _MACH_prep)
62 #else
63 #define isPReP 0
64 #endif
66 #include <video/fbcon.h>
67 #include <video/fbcon-mfb.h>
68 #include <video/fbcon-cfb8.h>
69 #include <video/fbcon-cfb16.h>
70 #include <video/fbcon-cfb24.h>
71 #include <video/fbcon-cfb32.h>
73 #include "clgenfb.h"
74 #include "vga.h"
77 /*****************************************************************
79 * debugging and utility macros
83 /* enable debug output? */
84 /* #define CLGEN_DEBUG 1 */
86 /* disable runtime assertions? */
87 /* #define CLGEN_NDEBUG */
89 /* debug output */
90 #ifdef CLGEN_DEBUG
91 #define DPRINTK(fmt, args...) printk(KERN_DEBUG "%s: " fmt, __FUNCTION__ , ## args)
92 #else
93 #define DPRINTK(fmt, args...)
94 #endif
96 /* debugging assertions */
97 #ifndef CLGEN_NDEBUG
98 #define assert(expr) \
99 if(!(expr)) { \
100 printk( "Assertion failed! %s,%s,%s,line=%d\n",\
101 #expr,__FILE__,__FUNCTION__,__LINE__); \
103 #else
104 #define assert(expr)
105 #endif
107 #ifdef TRUE
108 #undef TRUE
109 #endif
110 #ifdef FALSE
111 #undef FALSE
112 #endif
113 #define TRUE 1
114 #define FALSE 0
116 #define MB_ (1024*1024)
117 #define KB_ (1024)
119 #define MAX_NUM_BOARDS 7
122 /*****************************************************************
124 * chipset information
128 /* board types */
129 typedef enum {
130 BT_NONE = 0,
131 BT_SD64,
132 BT_PICCOLO,
133 BT_PICASSO,
134 BT_SPECTRUM,
135 BT_PICASSO4, /* GD5446 */
136 BT_ALPINE, /* GD543x/4x */
137 BT_GD5480,
138 BT_LAGUNA, /* GD546x */
139 } clgen_board_t;
143 * per-board-type information, used for enumerating and abstracting
144 * chip-specific information
145 * NOTE: MUST be in the same order as clgen_board_t in order to
146 * use direct indexing on this array
147 * NOTE: '__initdata' cannot be used as some of this info
148 * is required at runtime. Maybe separate into an init-only and
149 * a run-time table?
151 static const struct clgen_board_info_rec {
152 clgen_board_t btype; /* chipset enum, not strictly necessary, as
153 * clgen_board_info[] is directly indexed
154 * by this value */
155 char *name; /* ASCII name of chipset */
156 long maxclock; /* maximum video clock */
157 unsigned init_sr07 : 1; /* init SR07 during init_vgachip() */
158 unsigned init_sr1f : 1; /* write SR1F during init_vgachip() */
159 unsigned scrn_start_bit19 : 1; /* construct bit 19 of screen start address */
161 /* initial SR07 value, then for each mode */
162 unsigned char sr07;
163 unsigned char sr07_1bpp;
164 unsigned char sr07_1bpp_mux;
165 unsigned char sr07_8bpp;
166 unsigned char sr07_8bpp_mux;
168 unsigned char sr1f; /* SR1F VGA initial register value */
169 } clgen_board_info[] = {
170 { BT_NONE, }, /* dummy record */
171 { BT_SD64,
172 "CL SD64",
173 140000, /* the SD64/P4 have a higher max. videoclock */
174 TRUE,
175 TRUE,
176 TRUE,
177 0xF0,
178 0xF0,
179 0, /* unused, does not multiplex */
180 0xF1,
181 0, /* unused, does not multiplex */
182 0x20 },
183 { BT_PICCOLO,
184 "CL Piccolo",
185 90000,
186 TRUE,
187 TRUE,
188 FALSE,
189 0x80,
190 0x80,
191 0, /* unused, does not multiplex */
192 0x81,
193 0, /* unused, does not multiplex */
194 0x22 },
195 { BT_PICASSO,
196 "CL Picasso",
197 90000,
198 TRUE,
199 TRUE,
200 FALSE,
201 0x20,
202 0x20,
203 0, /* unused, does not multiplex */
204 0x21,
205 0, /* unused, does not multiplex */
206 0x22 },
207 { BT_SPECTRUM,
208 "CL Spectrum",
209 90000,
210 TRUE,
211 TRUE,
212 FALSE,
213 0x80,
214 0x80,
215 0, /* unused, does not multiplex */
216 0x81,
217 0, /* unused, does not multiplex */
218 0x22 },
219 { BT_PICASSO4,
220 "CL Picasso4",
221 140000, /* the SD64/P4 have a higher max. videoclock */
222 TRUE,
223 FALSE,
224 TRUE,
225 0x20,
226 0x20,
227 0, /* unused, does not multiplex */
228 0x21,
229 0, /* unused, does not multiplex */
230 0 },
231 { BT_ALPINE,
232 "CL Alpine",
233 110000, /* 135100 for some, 85500 for others */
234 TRUE,
235 TRUE,
236 TRUE,
237 0xA0,
238 0xA1,
239 0xA7,
240 0xA1,
241 0xA7,
242 0x1C },
243 { BT_GD5480,
244 "CL GD5480",
245 90000,
246 TRUE,
247 TRUE,
248 TRUE,
249 0x10,
250 0x11,
251 0, /* unused, does not multiplex */
252 0x11,
253 0, /* unused, does not multiplex */
254 0x1C },
255 { BT_LAGUNA,
256 "CL Laguna",
257 135100,
258 FALSE,
259 FALSE,
260 TRUE,
261 0, /* unused */
262 0, /* unused */
263 0, /* unused */
264 0, /* unused */
265 0, /* unused */
266 0 }, /* unused */
270 #ifdef CONFIG_PCI
271 /* the list of PCI devices for which we probe, and the
272 * order in which we do it */
273 static const struct {
274 clgen_board_t btype;
275 const char *nameOverride; /* XXX unused... for now */
276 unsigned short device;
277 } clgen_pci_probe_list[] __initdata = {
278 { BT_ALPINE, NULL, PCI_DEVICE_ID_CIRRUS_5436 },
279 { BT_ALPINE, NULL, PCI_DEVICE_ID_CIRRUS_5434_8 },
280 { BT_ALPINE, NULL, PCI_DEVICE_ID_CIRRUS_5434_4 },
281 { BT_ALPINE, NULL, PCI_DEVICE_ID_CIRRUS_5430 }, /* GD-5440 has identical id */
282 { BT_ALPINE, NULL, PCI_DEVICE_ID_CIRRUS_7543 },
283 { BT_ALPINE, NULL, PCI_DEVICE_ID_CIRRUS_7548 },
284 { BT_GD5480, NULL, PCI_DEVICE_ID_CIRRUS_5480 }, /* MacPicasso probably */
285 { BT_PICASSO4, NULL, PCI_DEVICE_ID_CIRRUS_5446 }, /* Picasso 4 is a GD5446 */
286 { BT_LAGUNA, "CL Laguna", PCI_DEVICE_ID_CIRRUS_5462 },
287 { BT_LAGUNA, "CL Laguna 3D", PCI_DEVICE_ID_CIRRUS_5464 },
288 { BT_LAGUNA, "CL Laguna 3DA", PCI_DEVICE_ID_CIRRUS_5465 },
290 #endif /* CONFIG_PCI */
293 #ifdef CONFIG_ZORRO
294 static const struct {
295 clgen_board_t btype;
296 zorro_id id, id2;
297 unsigned long size;
298 } clgen_zorro_probe_list[] __initdata = {
299 { BT_SD64,
300 ZORRO_PROD_HELFRICH_SD64_RAM,
301 ZORRO_PROD_HELFRICH_SD64_REG,
302 0x400000 },
303 { BT_PICCOLO,
304 ZORRO_PROD_HELFRICH_PICCOLO_RAM,
305 ZORRO_PROD_HELFRICH_PICCOLO_REG,
306 0x200000 },
307 { BT_PICASSO,
308 ZORRO_PROD_VILLAGE_TRONIC_PICASSO_II_II_PLUS_RAM,
309 ZORRO_PROD_VILLAGE_TRONIC_PICASSO_II_II_PLUS_REG,
310 0x200000 },
311 { BT_SPECTRUM,
312 ZORRO_PROD_GVP_EGS_28_24_SPECTRUM_RAM,
313 ZORRO_PROD_GVP_EGS_28_24_SPECTRUM_REG,
314 0x200000 },
315 { BT_PICASSO4,
316 ZORRO_PROD_VILLAGE_TRONIC_PICASSO_IV_Z3,
318 0x400000 },
320 #endif /* CONFIG_ZORRO */
324 struct clgenfb_par {
325 struct fb_var_screeninfo var;
327 __u32 line_length; /* in BYTES! */
328 __u32 visual;
329 __u32 type;
331 long freq;
332 long nom;
333 long den;
334 long div;
335 long multiplexing;
336 long mclk;
337 long divMCLK;
339 long HorizRes; /* The x resolution in pixel */
340 long HorizTotal;
341 long HorizDispEnd;
342 long HorizBlankStart;
343 long HorizBlankEnd;
344 long HorizSyncStart;
345 long HorizSyncEnd;
347 long VertRes; /* the physical y resolution in scanlines */
348 long VertTotal;
349 long VertDispEnd;
350 long VertSyncStart;
351 long VertSyncEnd;
352 long VertBlankStart;
353 long VertBlankEnd;
358 #ifdef CLGEN_DEBUG
359 typedef enum {
360 CRT,
362 } clgen_dbg_reg_class_t;
363 #endif /* CLGEN_DEBUG */
368 /* info about board */
369 struct clgenfb_info {
370 struct fb_info_gen gen;
372 caddr_t fbmem;
373 caddr_t regs;
374 caddr_t mem;
375 unsigned long size;
376 clgen_board_t btype;
377 int smallboard;
378 unsigned char SFR; /* Shadow of special function register */
380 unsigned long fbmem_phys;
381 unsigned long fbregs_phys;
383 struct clgenfb_par currentmode;
385 struct { u8 red, green, blue, pad; } palette[256];
387 union {
388 #ifdef FBCON_HAS_CFB16
389 u16 cfb16[16];
390 #endif
391 #ifdef FBCON_HAS_CFB24
392 u32 cfb24[16];
393 #endif
394 #ifdef FBCON_HAS_CFB32
395 u32 cfb32[16];
396 #endif
397 } fbcon_cmap;
399 #ifdef CONFIG_ZORRO
400 unsigned long board_addr,
401 board_size;
402 #endif
404 #ifdef CONFIG_PCI
405 struct pci_dev *pdev;
406 #endif
412 static struct display disp;
414 static struct clgenfb_info boards[MAX_NUM_BOARDS]; /* the boards */
416 static unsigned clgen_def_mode = 1;
417 static int noaccel = 0;
422 * Predefined Video Modes
425 static const struct {
426 const char *name;
427 struct fb_var_screeninfo var;
428 } clgenfb_predefined[] __initdata =
431 {"Autodetect", /* autodetect mode */
435 {"640x480", /* 640x480, 31.25 kHz, 60 Hz, 25 MHz PixClock */
437 640, 480, 640, 480, 0, 0, 8, 0,
438 {0, 8, 0},
439 {0, 8, 0},
440 {0, 8, 0},
441 {0, 0, 0},
442 0, 0, -1, -1, FB_ACCEL_NONE, 40000, 48, 16, 32, 8, 96, 4,
443 FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED
447 {"800x600", /* 800x600, 48 kHz, 76 Hz, 50 MHz PixClock */
449 800, 600, 800, 600, 0, 0, 8, 0,
450 {0, 8, 0},
451 {0, 8, 0},
452 {0, 8, 0},
453 {0, 0, 0},
454 0, 0, -1, -1, FB_ACCEL_NONE, 20000, 128, 16, 24, 2, 96, 6,
455 0, FB_VMODE_NONINTERLACED
460 Modeline from XF86Config:
461 Mode "1024x768" 80 1024 1136 1340 1432 768 770 774 805
463 {"1024x768", /* 1024x768, 55.8 kHz, 70 Hz, 80 MHz PixClock */
465 1024, 768, 1024, 768, 0, 0, 8, 0,
466 {0, 8, 0},
467 {0, 8, 0},
468 {0, 8, 0},
469 {0, 0, 0},
470 0, 0, -1, -1, FB_ACCEL_NONE, 12500, 144, 32, 30, 2, 192, 6,
471 0, FB_VMODE_NONINTERLACED
476 #define NUM_TOTAL_MODES ARRAY_SIZE(clgenfb_predefined)
477 static struct fb_var_screeninfo clgenfb_default;
480 * Frame Buffer Name
483 static const char *clgenfb_name = "CLgen";
485 /****************************************************************************/
486 /**** BEGIN PROTOTYPES ******************************************************/
489 /*--- Interface used by the world ------------------------------------------*/
490 int clgenfb_init (void);
491 int clgenfb_setup (char *options);
493 static int clgenfb_open (struct fb_info *info, int user);
494 static int clgenfb_release (struct fb_info *info, int user);
496 static int clgenfb_setcolreg (unsigned regno, unsigned red, unsigned green,
497 unsigned blue, unsigned transp,
498 struct fb_info *info);
500 /* function table of the above functions */
501 static struct fb_ops clgenfb_ops = {
502 .owner = THIS_MODULE,
503 .fb_open = clgenfb_open,
504 .fb_release = clgenfb_release,
505 .fb_get_fix = fbgen_get_fix,
506 .fb_get_var = fbgen_get_var,
507 .fb_set_var = fbgen_set_var,
508 .fb_get_cmap = fbgen_get_cmap,
509 .fb_set_cmap = gen_set_cmap,
510 .fb_setcolreg = clgenfb_setcolreg,
511 .fb_pan_display =fbgen_pan_display,
512 .fb_blank = fbgen_blank,
515 /*--- Hardware Specific Routines -------------------------------------------*/
516 static void clgen_detect (void);
517 static int clgen_encode_fix (struct fb_fix_screeninfo *fix, const void *par,
518 struct fb_info_gen *info);
519 static int clgen_decode_var (const struct fb_var_screeninfo *var, void *par,
520 struct fb_info_gen *info);
521 static int clgen_encode_var (struct fb_var_screeninfo *var, const void *par,
522 struct fb_info_gen *info);
523 static void clgen_get_par (void *par, struct fb_info_gen *info);
524 static void clgen_set_par (const void *par, struct fb_info_gen *info);
525 static int clgen_getcolreg (unsigned regno, unsigned *red, unsigned *green,
526 unsigned *blue, unsigned *transp,
527 struct fb_info *info);
528 static int clgen_pan_display (const struct fb_var_screeninfo *var,
529 struct fb_info_gen *info);
530 static int clgen_blank (int blank_mode, struct fb_info_gen *info);
532 static void clgen_set_disp (const void *par, struct display *disp,
533 struct fb_info_gen *info);
535 /* function table of the above functions */
536 static struct fbgen_hwswitch clgen_hwswitch =
538 clgen_detect,
539 clgen_encode_fix,
540 clgen_decode_var,
541 clgen_encode_var,
542 clgen_get_par,
543 clgen_set_par,
544 clgen_getcolreg,
545 clgen_pan_display,
546 clgen_blank,
547 clgen_set_disp
550 /* Text console acceleration */
552 #ifdef FBCON_HAS_CFB8
553 static void fbcon_clgen8_bmove (struct display *p, int sy, int sx,
554 int dy, int dx, int height, int width);
555 static void fbcon_clgen8_clear (struct vc_data *conp, struct display *p,
556 int sy, int sx, int height, int width);
558 static struct display_switch fbcon_clgen_8 = {
559 .setup = fbcon_cfb8_setup,
560 .bmove = fbcon_clgen8_bmove,
561 .clear = fbcon_clgen8_clear,
562 .putc = fbcon_cfb8_putc,
563 .putcs = fbcon_cfb8_putcs,
564 .revc = fbcon_cfb8_revc,
565 .clear_margins =fbcon_cfb8_clear_margins,
566 .fontwidthmask =FONTWIDTH (4) | FONTWIDTH (8) | FONTWIDTH (12) | FONTWIDTH (16)
568 #endif
569 #ifdef FBCON_HAS_CFB16
570 static void fbcon_clgen16_bmove (struct display *p, int sy, int sx,
571 int dy, int dx, int height, int width);
572 static void fbcon_clgen16_clear (struct vc_data *conp, struct display *p,
573 int sy, int sx, int height, int width);
574 static struct display_switch fbcon_clgen_16 = {
575 .setup = fbcon_cfb16_setup,
576 .bmove = fbcon_clgen16_bmove,
577 .clear = fbcon_clgen16_clear,
578 .putc = fbcon_cfb16_putc,
579 .putcs = fbcon_cfb16_putcs,
580 .revc = fbcon_cfb16_revc,
581 .clear_margins =fbcon_cfb16_clear_margins,
582 .fontwidthmask =FONTWIDTH (4) | FONTWIDTH (8) | FONTWIDTH (12) | FONTWIDTH (16)
584 #endif
585 #ifdef FBCON_HAS_CFB32
586 static void fbcon_clgen32_bmove (struct display *p, int sy, int sx,
587 int dy, int dx, int height, int width);
588 static void fbcon_clgen32_clear (struct vc_data *conp, struct display *p,
589 int sy, int sx, int height, int width);
590 static struct display_switch fbcon_clgen_32 = {
591 .setup = fbcon_cfb32_setup,
592 .bmove = fbcon_clgen32_bmove,
593 .clear = fbcon_clgen32_clear,
594 .putc = fbcon_cfb32_putc,
595 .putcs = fbcon_cfb32_putcs,
596 .revc = fbcon_cfb32_revc,
597 .clear_margins =fbcon_cfb32_clear_margins,
598 .fontwidthmask =FONTWIDTH (4) | FONTWIDTH (8) | FONTWIDTH (12) | FONTWIDTH (16)
600 #endif
604 /*--- Internal routines ----------------------------------------------------*/
605 static void init_vgachip (struct clgenfb_info *fb_info);
606 static void switch_monitor (struct clgenfb_info *fb_info, int on);
607 static void WGen (const struct clgenfb_info *fb_info,
608 int regnum, unsigned char val);
609 static unsigned char RGen (const struct clgenfb_info *fb_info, int regnum);
610 static void AttrOn (const struct clgenfb_info *fb_info);
611 static void WHDR (const struct clgenfb_info *fb_info, unsigned char val);
612 static void WSFR (struct clgenfb_info *fb_info, unsigned char val);
613 static void WSFR2 (struct clgenfb_info *fb_info, unsigned char val);
614 static void WClut (struct clgenfb_info *fb_info, unsigned char regnum, unsigned char red,
615 unsigned char green,
616 unsigned char blue);
617 #if 0
618 static void RClut (struct clgenfb_info *fb_info, unsigned char regnum, unsigned char *red,
619 unsigned char *green,
620 unsigned char *blue);
621 #endif
622 static void clgen_WaitBLT (caddr_t regbase);
623 static void clgen_BitBLT (caddr_t regbase, u_short curx, u_short cury,
624 u_short destx, u_short desty,
625 u_short width, u_short height,
626 u_short line_length);
627 static void clgen_RectFill (struct clgenfb_info *fb_info, u_short x, u_short y,
628 u_short width, u_short height,
629 u_char color, u_short line_length);
631 static void bestclock (long freq, long *best,
632 long *nom, long *den,
633 long *div, long maxfreq);
635 #ifdef CLGEN_DEBUG
636 static void clgen_dump (void);
637 static void clgen_dbg_reg_dump (caddr_t regbase);
638 static void clgen_dbg_print_regs (caddr_t regbase, clgen_dbg_reg_class_t reg_class,...);
639 static void clgen_dbg_print_byte (const char *name, unsigned char val);
640 #endif /* CLGEN_DEBUG */
642 /*** END PROTOTYPES ********************************************************/
643 /*****************************************************************************/
644 /*** BEGIN Interface Used by the World ***************************************/
646 static int opencount = 0;
648 /*--- Open /dev/fbx ---------------------------------------------------------*/
649 static int clgenfb_open (struct fb_info *info, int user)
651 if (opencount++ == 0)
652 switch_monitor ((struct clgenfb_info *) info, 1);
653 return 0;
656 /*--- Close /dev/fbx --------------------------------------------------------*/
657 static int clgenfb_release (struct fb_info *info, int user)
659 if (--opencount == 0)
660 switch_monitor ((struct clgenfb_info *) info, 0);
661 return 0;
664 /**** END Interface used by the World *************************************/
665 /****************************************************************************/
666 /**** BEGIN Hardware specific Routines **************************************/
668 static void clgen_detect (void)
670 DPRINTK ("ENTER\n");
671 DPRINTK ("EXIT\n");
674 static int clgen_encode_fix (struct fb_fix_screeninfo *fix, const void *par,
675 struct fb_info_gen *info)
677 struct clgenfb_par *_par = (struct clgenfb_par *) par;
678 struct clgenfb_info *_info = (struct clgenfb_info *) info;
680 DPRINTK ("ENTER\n");
682 memset (fix, 0, sizeof (struct fb_fix_screeninfo));
683 strcpy (fix->id, clgenfb_name);
685 if (_info->btype == BT_GD5480) {
686 /* Select proper byte-swapping aperture */
687 switch (_par->var.bits_per_pixel) {
688 case 1:
689 case 8:
690 fix->smem_start = _info->fbmem_phys;
691 break;
692 case 16:
693 fix->smem_start = _info->fbmem_phys + 1 * MB_;
694 break;
695 case 24:
696 case 32:
697 fix->smem_start = _info->fbmem_phys + 2 * MB_;
698 break;
700 } else {
701 fix->smem_start = _info->fbmem_phys;
704 /* monochrome: only 1 memory plane */
705 /* 8 bit and above: Use whole memory area */
706 fix->smem_len = _par->var.bits_per_pixel == 1 ? _info->size / 4
707 : _info->size;
708 fix->type = _par->type;
709 fix->type_aux = 0;
710 fix->visual = _par->visual;
711 fix->xpanstep = 1;
712 fix->ypanstep = 1;
713 fix->ywrapstep = 0;
714 fix->line_length = _par->line_length;
716 /* FIXME: map region at 0xB8000 if available, fill in here */
717 fix->mmio_start = 0;
718 fix->mmio_len = 0;
719 fix->accel = FB_ACCEL_NONE;
721 DPRINTK ("EXIT\n");
722 return 0;
727 /* Get a good MCLK value */
728 static long clgen_get_mclk (long freq, int bpp, long *div)
730 long mclk;
732 assert (div != NULL);
734 /* Calculate MCLK, in case VCLK is high enough to require > 50MHz.
735 * Assume a 64-bit data path for now. The formula is:
736 * ((B * PCLK * 2)/W) * 1.2
737 * B = bytes per pixel, PCLK = pixclock, W = data width in bytes */
738 mclk = ((bpp / 8) * freq * 2) / 4;
739 mclk = (mclk * 12) / 10;
740 if (mclk < 50000)
741 mclk = 50000;
742 DPRINTK ("Use MCLK of %ld kHz\n", mclk);
744 /* Calculate value for SR1F. Multiply by 2 so we can round up. */
745 mclk = ((mclk * 16) / 14318);
746 mclk = (mclk + 1) / 2;
747 DPRINTK ("Set SR1F[5:0] to 0x%lx\n", mclk);
749 /* Determine if we should use MCLK instead of VCLK, and if so, what we
750 * should divide it by to get VCLK */
751 switch (freq) {
752 case 24751 ... 25249:
753 *div = 2;
754 DPRINTK ("Using VCLK = MCLK/2\n");
755 break;
756 case 49501 ... 50499:
757 *div = 1;
758 DPRINTK ("Using VCLK = MCLK\n");
759 break;
760 default:
761 *div = 0;
762 break;
765 return mclk;
768 static int clgen_decode_var (const struct fb_var_screeninfo *var, void *par,
769 struct fb_info_gen *info)
771 long freq;
772 long maxclock;
773 int xres, hfront, hsync, hback;
774 int yres, vfront, vsync, vback;
775 int nom, den; /* translyting from pixels->bytes */
776 int i;
777 static struct {
778 int xres, yres;
779 } modes[] = { {
780 1600, 1280
781 }, {
782 1280, 1024
783 }, {
784 1024, 768
787 800, 600
788 }, {
789 640, 480
790 }, {
791 -1, -1
795 struct clgenfb_par *_par = (struct clgenfb_par *) par;
796 struct clgenfb_info *fb_info = (struct clgenfb_info *) info;
798 assert (var != NULL);
799 assert (par != NULL);
800 assert (info != NULL);
802 DPRINTK ("ENTER\n");
804 DPRINTK ("Requested: %dx%dx%d\n", var->xres, var->yres, var->bits_per_pixel);
805 DPRINTK (" virtual: %dx%d\n", var->xres_virtual, var->yres_virtual);
806 DPRINTK (" offset: (%d,%d)\n", var->xoffset, var->yoffset);
807 DPRINTK ("grayscale: %d\n", var->grayscale);
809 memset (par, 0, sizeof (struct clgenfb_par));
811 _par->var = *var;
813 switch (var->bits_per_pixel) {
814 case 1:
815 nom = 4;
816 den = 8;
817 break; /* 8 pixel per byte, only 1/4th of mem usable */
818 case 2 ... 8:
819 _par->var.bits_per_pixel = 8;
820 nom = 1;
821 den = 1;
822 break; /* 1 pixel == 1 byte */
823 case 9 ... 16:
824 _par->var.bits_per_pixel = 16;
825 nom = 2;
826 den = 1;
827 break; /* 2 bytes per pixel */
828 case 17 ... 24:
829 _par->var.bits_per_pixel = 24;
830 nom = 3;
831 den = 1;
832 break; /* 3 bytes per pixel */
833 case 25 ... 32:
834 _par->var.bits_per_pixel = 32;
835 nom = 4;
836 den = 1;
837 break; /* 4 bytes per pixel */
838 default:
839 printk ("clgen: mode %dx%dx%d rejected...color depth not supported.\n",
840 var->xres, var->yres, var->bits_per_pixel);
841 DPRINTK ("EXIT - EINVAL error\n");
842 return -EINVAL;
845 if (_par->var.xres * nom / den * _par->var.yres > fb_info->size) {
846 printk ("clgen: mode %dx%dx%d rejected...resolution too high to fit into video memory!\n",
847 var->xres, var->yres, var->bits_per_pixel);
848 DPRINTK ("EXIT - EINVAL error\n");
849 return -EINVAL;
851 /* use highest possible virtual resolution */
852 if (_par->var.xres_virtual == -1 &&
853 _par->var.yres_virtual == -1) {
854 printk ("clgen: using maximum available virtual resolution\n");
855 for (i = 0; modes[i].xres != -1; i++) {
856 if (modes[i].xres * nom / den * modes[i].yres < fb_info->size / 2)
857 break;
859 if (modes[i].xres == -1) {
860 printk ("clgen: could not find a virtual resolution that fits into video memory!!\n");
861 DPRINTK ("EXIT - EINVAL error\n");
862 return -EINVAL;
864 _par->var.xres_virtual = modes[i].xres;
865 _par->var.yres_virtual = modes[i].yres;
867 printk ("clgen: virtual resolution set to maximum of %dx%d\n",
868 _par->var.xres_virtual, _par->var.yres_virtual);
869 } else if (_par->var.xres_virtual == -1) {
870 /* FIXME: maximize X virtual resolution only */
871 } else if (_par->var.yres_virtual == -1) {
872 /* FIXME: maximize Y virtual resolution only */
874 if (_par->var.xoffset < 0)
875 _par->var.xoffset = 0;
876 if (_par->var.yoffset < 0)
877 _par->var.yoffset = 0;
879 /* truncate xoffset and yoffset to maximum if too high */
880 if (_par->var.xoffset > _par->var.xres_virtual - _par->var.xres)
881 _par->var.xoffset = _par->var.xres_virtual - _par->var.xres - 1;
883 if (_par->var.yoffset > _par->var.yres_virtual - _par->var.yres)
884 _par->var.yoffset = _par->var.yres_virtual - _par->var.yres - 1;
886 switch (_par->var.bits_per_pixel) {
887 case 1:
888 _par->line_length = _par->var.xres_virtual / 8;
889 _par->visual = FB_VISUAL_MONO10;
890 break;
892 case 8:
893 _par->line_length = _par->var.xres_virtual;
894 _par->visual = FB_VISUAL_PSEUDOCOLOR;
895 _par->var.red.offset = 0;
896 _par->var.red.length = 6;
897 _par->var.green.offset = 0;
898 _par->var.green.length = 6;
899 _par->var.blue.offset = 0;
900 _par->var.blue.length = 6;
901 break;
903 case 16:
904 _par->line_length = _par->var.xres_virtual * 2;
905 _par->visual = FB_VISUAL_DIRECTCOLOR;
906 if(isPReP) {
907 _par->var.red.offset = 2;
908 _par->var.green.offset = -3;
909 _par->var.blue.offset = 8;
910 } else {
911 _par->var.red.offset = 10;
912 _par->var.green.offset = 5;
913 _par->var.blue.offset = 0;
915 _par->var.red.length = 5;
916 _par->var.green.length = 5;
917 _par->var.blue.length = 5;
918 break;
920 case 24:
921 _par->line_length = _par->var.xres_virtual * 3;
922 _par->visual = FB_VISUAL_DIRECTCOLOR;
923 if(isPReP) {
924 _par->var.red.offset = 8;
925 _par->var.green.offset = 16;
926 _par->var.blue.offset = 24;
927 } else {
928 _par->var.red.offset = 16;
929 _par->var.green.offset = 8;
930 _par->var.blue.offset = 0;
932 _par->var.red.length = 8;
933 _par->var.green.length = 8;
934 _par->var.blue.length = 8;
935 break;
937 case 32:
938 _par->line_length = _par->var.xres_virtual * 4;
939 _par->visual = FB_VISUAL_DIRECTCOLOR;
940 if(isPReP) {
941 _par->var.red.offset = 8;
942 _par->var.green.offset = 16;
943 _par->var.blue.offset = 24;
944 } else {
945 _par->var.red.offset = 16;
946 _par->var.green.offset = 8;
947 _par->var.blue.offset = 0;
949 _par->var.red.length = 8;
950 _par->var.green.length = 8;
951 _par->var.blue.length = 8;
952 break;
954 default:
955 DPRINTK("Unsupported bpp size: %d\n", _par->var.bits_per_pixel);
956 assert (FALSE);
957 /* should never occur */
958 break;
961 _par->var.red.msb_right =
962 _par->var.green.msb_right =
963 _par->var.blue.msb_right =
964 _par->var.transp.offset =
965 _par->var.transp.length =
966 _par->var.transp.msb_right = 0;
968 _par->type = FB_TYPE_PACKED_PIXELS;
970 /* convert from ps to kHz */
971 freq = 1000000000 / var->pixclock;
973 DPRINTK ("desired pixclock: %ld kHz\n", freq);
975 maxclock = clgen_board_info[fb_info->btype].maxclock;
976 _par->multiplexing = 0;
978 /* If the frequency is greater than we can support, we might be able
979 * to use multiplexing for the video mode */
980 if (freq > maxclock) {
981 switch (fb_info->btype) {
982 case BT_ALPINE:
983 case BT_GD5480:
984 _par->multiplexing = 1;
985 break;
987 default:
988 printk (KERN_WARNING "clgen: ERROR: Frequency greater than maxclock (%ld kHz)\n", maxclock);
989 DPRINTK ("EXIT - return -EINVAL\n");
990 return -EINVAL;
993 #if 0
994 /* TODO: If we have a 1MB 5434, we need to put ourselves in a mode where
995 * the VCLK is double the pixel clock. */
996 switch (var->bits_per_pixel) {
997 case 16:
998 case 32:
999 if (_par->HorizRes <= 800)
1000 freq /= 2; /* Xbh has this type of clock for 32-bit */
1001 break;
1003 #endif
1005 bestclock (freq, &_par->freq, &_par->nom, &_par->den, &_par->div,
1006 maxclock);
1007 _par->mclk = clgen_get_mclk (freq, _par->var.bits_per_pixel, &_par->divMCLK);
1009 xres = _par->var.xres;
1010 hfront = _par->var.right_margin;
1011 hsync = _par->var.hsync_len;
1012 hback = _par->var.left_margin;
1014 yres = _par->var.yres;
1015 vfront = _par->var.lower_margin;
1016 vsync = _par->var.vsync_len;
1017 vback = _par->var.upper_margin;
1019 if (_par->var.vmode & FB_VMODE_DOUBLE) {
1020 yres *= 2;
1021 vfront *= 2;
1022 vsync *= 2;
1023 vback *= 2;
1024 } else if (_par->var.vmode & FB_VMODE_INTERLACED) {
1025 yres = (yres + 1) / 2;
1026 vfront = (vfront + 1) / 2;
1027 vsync = (vsync + 1) / 2;
1028 vback = (vback + 1) / 2;
1030 _par->HorizRes = xres;
1031 _par->HorizTotal = (xres + hfront + hsync + hback) / 8 - 5;
1032 _par->HorizDispEnd = xres / 8 - 1;
1033 _par->HorizBlankStart = xres / 8;
1034 _par->HorizBlankEnd = _par->HorizTotal + 5; /* does not count with "-5" */
1035 _par->HorizSyncStart = (xres + hfront) / 8 + 1;
1036 _par->HorizSyncEnd = (xres + hfront + hsync) / 8 + 1;
1038 _par->VertRes = yres;
1039 _par->VertTotal = yres + vfront + vsync + vback - 2;
1040 _par->VertDispEnd = yres - 1;
1041 _par->VertBlankStart = yres;
1042 _par->VertBlankEnd = _par->VertTotal;
1043 _par->VertSyncStart = yres + vfront - 1;
1044 _par->VertSyncEnd = yres + vfront + vsync - 1;
1046 if (_par->VertRes >= 1024) {
1047 _par->VertTotal /= 2;
1048 _par->VertSyncStart /= 2;
1049 _par->VertSyncEnd /= 2;
1050 _par->VertDispEnd /= 2;
1052 if (_par->multiplexing) {
1053 _par->HorizTotal /= 2;
1054 _par->HorizSyncStart /= 2;
1055 _par->HorizSyncEnd /= 2;
1056 _par->HorizDispEnd /= 2;
1058 if (_par->VertRes >= 1280) {
1059 printk (KERN_WARNING "clgen: ERROR: VerticalTotal >= 1280; special treatment required! (TODO)\n");
1060 DPRINTK ("EXIT - EINVAL error\n");
1061 return -EINVAL;
1063 DPRINTK ("EXIT\n");
1064 return 0;
1068 static int clgen_encode_var (struct fb_var_screeninfo *var, const void *par,
1069 struct fb_info_gen *info)
1071 DPRINTK ("ENTER\n");
1073 *var = ((struct clgenfb_par *) par)->var;
1075 DPRINTK ("EXIT\n");
1076 return 0;
1079 /* get current video mode */
1080 static void clgen_get_par (void *par, struct fb_info_gen *info)
1082 struct clgenfb_par *_par = (struct clgenfb_par *) par;
1083 struct clgenfb_info *_info = (struct clgenfb_info *) info;
1085 DPRINTK ("ENTER\n");
1087 *_par = _info->currentmode;
1089 DPRINTK ("EXIT\n");
1092 static void clgen_set_mclk (const struct clgenfb_info *fb_info, int val, int div)
1094 assert (fb_info != NULL);
1096 if (div == 2) {
1097 /* VCLK = MCLK/2 */
1098 unsigned char old = vga_rseq (fb_info->regs, CL_SEQR1E);
1099 vga_wseq (fb_info->regs, CL_SEQR1E, old | 0x1);
1100 vga_wseq (fb_info->regs, CL_SEQR1F, 0x40 | (val & 0x3f));
1101 } else if (div == 1) {
1102 /* VCLK = MCLK */
1103 unsigned char old = vga_rseq (fb_info->regs, CL_SEQR1E);
1104 vga_wseq (fb_info->regs, CL_SEQR1E, old & ~0x1);
1105 vga_wseq (fb_info->regs, CL_SEQR1F, 0x40 | (val & 0x3f));
1106 } else {
1107 vga_wseq (fb_info->regs, CL_SEQR1F, val & 0x3f);
1111 /*************************************************************************
1112 clgen_set_par()
1114 actually writes the values for a new video mode into the hardware,
1115 **************************************************************************/
1116 static void clgen_set_par (const void *par, struct fb_info_gen *info)
1118 unsigned char tmp;
1119 int offset = 0;
1120 struct clgenfb_par *_par = (struct clgenfb_par *) par;
1121 struct clgenfb_info *fb_info = (struct clgenfb_info *) info;
1122 const struct clgen_board_info_rec *bi;
1124 DPRINTK ("ENTER\n");
1125 DPRINTK ("Requested mode: %dx%dx%d\n",
1126 _par->var.xres, _par->var.yres, _par->var.bits_per_pixel);
1127 DPRINTK ("pixclock: %d\n", _par->var.pixclock);
1129 bi = &clgen_board_info[fb_info->btype];
1132 /* unlock register VGA_CRTC_H_TOTAL..CRT7 */
1133 vga_wcrt (fb_info->regs, VGA_CRTC_V_SYNC_END, 0x20); /* previously: 0x00) */
1135 /* if debugging is enabled, all parameters get output before writing */
1136 DPRINTK ("CRT0: %ld\n", _par->HorizTotal);
1137 vga_wcrt (fb_info->regs, VGA_CRTC_H_TOTAL, _par->HorizTotal);
1139 DPRINTK ("CRT1: %ld\n", _par->HorizDispEnd);
1140 vga_wcrt (fb_info->regs, VGA_CRTC_H_DISP, _par->HorizDispEnd);
1142 DPRINTK ("CRT2: %ld\n", _par->HorizBlankStart);
1143 vga_wcrt (fb_info->regs, VGA_CRTC_H_BLANK_START, _par->HorizBlankStart);
1145 DPRINTK ("CRT3: 128+%ld\n", _par->HorizBlankEnd % 32); /* + 128: Compatible read */
1146 vga_wcrt (fb_info->regs, VGA_CRTC_H_BLANK_END, 128 + (_par->HorizBlankEnd % 32));
1148 DPRINTK ("CRT4: %ld\n", _par->HorizSyncStart);
1149 vga_wcrt (fb_info->regs, VGA_CRTC_H_SYNC_START, _par->HorizSyncStart);
1151 tmp = _par->HorizSyncEnd % 32;
1152 if (_par->HorizBlankEnd & 32)
1153 tmp += 128;
1154 DPRINTK ("CRT5: %d\n", tmp);
1155 vga_wcrt (fb_info->regs, VGA_CRTC_H_SYNC_END, tmp);
1157 DPRINTK ("CRT6: %ld\n", _par->VertTotal & 0xff);
1158 vga_wcrt (fb_info->regs, VGA_CRTC_V_TOTAL, (_par->VertTotal & 0xff));
1160 tmp = 16; /* LineCompare bit #9 */
1161 if (_par->VertTotal & 256)
1162 tmp |= 1;
1163 if (_par->VertDispEnd & 256)
1164 tmp |= 2;
1165 if (_par->VertSyncStart & 256)
1166 tmp |= 4;
1167 if (_par->VertBlankStart & 256)
1168 tmp |= 8;
1169 if (_par->VertTotal & 512)
1170 tmp |= 32;
1171 if (_par->VertDispEnd & 512)
1172 tmp |= 64;
1173 if (_par->VertSyncStart & 512)
1174 tmp |= 128;
1175 DPRINTK ("CRT7: %d\n", tmp);
1176 vga_wcrt (fb_info->regs, VGA_CRTC_OVERFLOW, tmp);
1178 tmp = 0x40; /* LineCompare bit #8 */
1179 if (_par->VertBlankStart & 512)
1180 tmp |= 0x20;
1181 if (_par->var.vmode & FB_VMODE_DOUBLE)
1182 tmp |= 0x80;
1183 DPRINTK ("CRT9: %d\n", tmp);
1184 vga_wcrt (fb_info->regs, VGA_CRTC_MAX_SCAN, tmp);
1186 DPRINTK ("CRT10: %ld\n", _par->VertSyncStart & 0xff);
1187 vga_wcrt (fb_info->regs, VGA_CRTC_V_SYNC_START, (_par->VertSyncStart & 0xff));
1189 DPRINTK ("CRT11: 64+32+%ld\n", _par->VertSyncEnd % 16);
1190 vga_wcrt (fb_info->regs, VGA_CRTC_V_SYNC_END, (_par->VertSyncEnd % 16 + 64 + 32));
1192 DPRINTK ("CRT12: %ld\n", _par->VertDispEnd & 0xff);
1193 vga_wcrt (fb_info->regs, VGA_CRTC_V_DISP_END, (_par->VertDispEnd & 0xff));
1195 DPRINTK ("CRT15: %ld\n", _par->VertBlankStart & 0xff);
1196 vga_wcrt (fb_info->regs, VGA_CRTC_V_BLANK_START, (_par->VertBlankStart & 0xff));
1198 DPRINTK ("CRT16: %ld\n", _par->VertBlankEnd & 0xff);
1199 vga_wcrt (fb_info->regs, VGA_CRTC_V_BLANK_END, (_par->VertBlankEnd & 0xff));
1201 DPRINTK ("CRT18: 0xff\n");
1202 vga_wcrt (fb_info->regs, VGA_CRTC_LINE_COMPARE, 0xff);
1204 tmp = 0;
1205 if (_par->var.vmode & FB_VMODE_INTERLACED)
1206 tmp |= 1;
1207 if (_par->HorizBlankEnd & 64)
1208 tmp |= 16;
1209 if (_par->HorizBlankEnd & 128)
1210 tmp |= 32;
1211 if (_par->VertBlankEnd & 256)
1212 tmp |= 64;
1213 if (_par->VertBlankEnd & 512)
1214 tmp |= 128;
1216 DPRINTK ("CRT1a: %d\n", tmp);
1217 vga_wcrt (fb_info->regs, CL_CRT1A, tmp);
1219 /* set VCLK0 */
1220 /* hardware RefClock: 14.31818 MHz */
1221 /* formula: VClk = (OSC * N) / (D * (1+P)) */
1222 /* Example: VClk = (14.31818 * 91) / (23 * (1+1)) = 28.325 MHz */
1224 vga_wseq (fb_info->regs, CL_SEQRB, _par->nom);
1225 tmp = _par->den << 1;
1226 if (_par->div != 0)
1227 tmp |= 1;
1229 if ((fb_info->btype == BT_SD64) ||
1230 (fb_info->btype == BT_ALPINE) ||
1231 (fb_info->btype == BT_GD5480))
1232 tmp |= 0x80; /* 6 bit denom; ONLY 5434!!! (bugged me 10 days) */
1234 DPRINTK ("CL_SEQR1B: %ld\n", (long) tmp);
1235 vga_wseq (fb_info->regs, CL_SEQR1B, tmp);
1237 if (_par->VertRes >= 1024)
1238 /* 1280x1024 */
1239 vga_wcrt (fb_info->regs, VGA_CRTC_MODE, 0xc7);
1240 else
1241 /* mode control: VGA_CRTC_START_HI enable, ROTATE(?), 16bit
1242 * address wrap, no compat. */
1243 vga_wcrt (fb_info->regs, VGA_CRTC_MODE, 0xc3);
1245 /* HAEH? vga_wcrt (fb_info->regs, VGA_CRTC_V_SYNC_END, 0x20); * previously: 0x00 unlock VGA_CRTC_H_TOTAL..CRT7 */
1247 /* don't know if it would hurt to also program this if no interlaced */
1248 /* mode is used, but I feel better this way.. :-) */
1249 if (_par->var.vmode & FB_VMODE_INTERLACED)
1250 vga_wcrt (fb_info->regs, VGA_CRTC_REGS, _par->HorizTotal / 2);
1251 else
1252 vga_wcrt (fb_info->regs, VGA_CRTC_REGS, 0x00); /* interlace control */
1254 vga_wseq (fb_info->regs, VGA_SEQ_CHARACTER_MAP, 0);
1256 /* adjust horizontal/vertical sync type (low/high) */
1257 tmp = 0x03; /* enable display memory & CRTC I/O address for color mode */
1258 if (_par->var.sync & FB_SYNC_HOR_HIGH_ACT)
1259 tmp |= 0x40;
1260 if (_par->var.sync & FB_SYNC_VERT_HIGH_ACT)
1261 tmp |= 0x80;
1262 WGen (fb_info, VGA_MIS_W, tmp);
1264 vga_wcrt (fb_info->regs, VGA_CRTC_PRESET_ROW, 0); /* Screen A Preset Row-Scan register */
1265 vga_wcrt (fb_info->regs, VGA_CRTC_CURSOR_START, 0); /* text cursor on and start line */
1266 vga_wcrt (fb_info->regs, VGA_CRTC_CURSOR_END, 31); /* text cursor end line */
1268 /******************************************************
1270 * 1 bpp
1274 /* programming for different color depths */
1275 if (_par->var.bits_per_pixel == 1) {
1276 DPRINTK ("clgen: preparing for 1 bit deep display\n");
1277 vga_wgfx (fb_info->regs, VGA_GFX_MODE, 0); /* mode register */
1279 /* SR07 */
1280 switch (fb_info->btype) {
1281 case BT_SD64:
1282 case BT_PICCOLO:
1283 case BT_PICASSO:
1284 case BT_SPECTRUM:
1285 case BT_PICASSO4:
1286 case BT_ALPINE:
1287 case BT_GD5480:
1288 DPRINTK (" (for GD54xx)\n");
1289 vga_wseq (fb_info->regs, CL_SEQR7,
1290 _par->multiplexing ?
1291 bi->sr07_1bpp_mux : bi->sr07_1bpp);
1292 break;
1294 case BT_LAGUNA:
1295 DPRINTK (" (for GD546x)\n");
1296 vga_wseq (fb_info->regs, CL_SEQR7,
1297 vga_rseq (fb_info->regs, CL_SEQR7) & ~0x01);
1298 break;
1300 default:
1301 printk (KERN_WARNING "clgen: unknown Board\n");
1302 break;
1305 /* Extended Sequencer Mode */
1306 switch (fb_info->btype) {
1307 case BT_SD64:
1308 /* setting the SEQRF on SD64 is not necessary (only during init) */
1309 DPRINTK ("(for SD64)\n");
1310 vga_wseq (fb_info->regs, CL_SEQR1F, 0x1a); /* MCLK select */
1311 break;
1313 case BT_PICCOLO:
1314 DPRINTK ("(for Piccolo)\n");
1315 /* ### ueberall 0x22? */
1316 vga_wseq (fb_info->regs, CL_SEQR1F, 0x22); /* ##vorher 1c MCLK select */
1317 vga_wseq (fb_info->regs, CL_SEQRF, 0xb0); /* evtl d0 bei 1 bit? avoid FIFO underruns..? */
1318 break;
1320 case BT_PICASSO:
1321 DPRINTK ("(for Picasso)\n");
1322 vga_wseq (fb_info->regs, CL_SEQR1F, 0x22); /* ##vorher 22 MCLK select */
1323 vga_wseq (fb_info->regs, CL_SEQRF, 0xd0); /* ## vorher d0 avoid FIFO underruns..? */
1324 break;
1326 case BT_SPECTRUM:
1327 DPRINTK ("(for Spectrum)\n");
1328 /* ### ueberall 0x22? */
1329 vga_wseq (fb_info->regs, CL_SEQR1F, 0x22); /* ##vorher 1c MCLK select */
1330 vga_wseq (fb_info->regs, CL_SEQRF, 0xb0); /* evtl d0? avoid FIFO underruns..? */
1331 break;
1333 case BT_PICASSO4:
1334 case BT_ALPINE:
1335 case BT_GD5480:
1336 case BT_LAGUNA:
1337 DPRINTK (" (for GD54xx)\n");
1338 /* do nothing */
1339 break;
1341 default:
1342 printk (KERN_WARNING "clgen: unknown Board\n");
1343 break;
1346 WGen (fb_info, VGA_PEL_MSK, 0x01); /* pixel mask: pass-through for first plane */
1347 if (_par->multiplexing)
1348 WHDR (fb_info, 0x4a); /* hidden dac reg: 1280x1024 */
1349 else
1350 WHDR (fb_info, 0); /* hidden dac: nothing */
1351 vga_wseq (fb_info->regs, VGA_SEQ_MEMORY_MODE, 0x06); /* memory mode: odd/even, ext. memory */
1352 vga_wseq (fb_info->regs, VGA_SEQ_PLANE_WRITE, 0x01); /* plane mask: only write to first plane */
1353 offset = _par->var.xres_virtual / 16;
1356 /******************************************************
1358 * 8 bpp
1362 else if (_par->var.bits_per_pixel == 8) {
1363 DPRINTK ("clgen: preparing for 8 bit deep display\n");
1364 switch (fb_info->btype) {
1365 case BT_SD64:
1366 case BT_PICCOLO:
1367 case BT_PICASSO:
1368 case BT_SPECTRUM:
1369 case BT_PICASSO4:
1370 case BT_ALPINE:
1371 case BT_GD5480:
1372 DPRINTK (" (for GD54xx)\n");
1373 vga_wseq (fb_info->regs, CL_SEQR7,
1374 _par->multiplexing ?
1375 bi->sr07_8bpp_mux : bi->sr07_8bpp);
1376 break;
1378 case BT_LAGUNA:
1379 DPRINTK (" (for GD546x)\n");
1380 vga_wseq (fb_info->regs, CL_SEQR7,
1381 vga_rseq (fb_info->regs, CL_SEQR7) | 0x01);
1382 break;
1384 default:
1385 printk (KERN_WARNING "clgen: unknown Board\n");
1386 break;
1389 switch (fb_info->btype) {
1390 case BT_SD64:
1391 vga_wseq (fb_info->regs, CL_SEQR1F, 0x1d); /* MCLK select */
1392 break;
1394 case BT_PICCOLO:
1395 vga_wseq (fb_info->regs, CL_SEQR1F, 0x22); /* ### vorher 1c MCLK select */
1396 vga_wseq (fb_info->regs, CL_SEQRF, 0xb0); /* Fast Page-Mode writes */
1397 break;
1399 case BT_PICASSO:
1400 vga_wseq (fb_info->regs, CL_SEQR1F, 0x22); /* ### vorher 1c MCLK select */
1401 vga_wseq (fb_info->regs, CL_SEQRF, 0xb0); /* Fast Page-Mode writes */
1402 break;
1404 case BT_SPECTRUM:
1405 vga_wseq (fb_info->regs, CL_SEQR1F, 0x22); /* ### vorher 1c MCLK select */
1406 vga_wseq (fb_info->regs, CL_SEQRF, 0xb0); /* Fast Page-Mode writes */
1407 break;
1409 case BT_PICASSO4:
1410 #ifdef CONFIG_ZORRO
1411 vga_wseq (fb_info->regs, CL_SEQRF, 0xb8); /* ### INCOMPLETE!! */
1412 #endif
1413 /* vga_wseq (fb_info->regs, CL_SEQR1F, 0x1c); */
1414 break;
1416 case BT_ALPINE:
1417 DPRINTK (" (for GD543x)\n");
1418 clgen_set_mclk (fb_info, _par->mclk, _par->divMCLK);
1419 /* We already set SRF and SR1F */
1420 break;
1422 case BT_GD5480:
1423 case BT_LAGUNA:
1424 DPRINTK (" (for GD54xx)\n");
1425 /* do nothing */
1426 break;
1428 default:
1429 printk (KERN_WARNING "clgen: unknown Board\n");
1430 break;
1433 vga_wgfx (fb_info->regs, VGA_GFX_MODE, 64); /* mode register: 256 color mode */
1434 WGen (fb_info, VGA_PEL_MSK, 0xff); /* pixel mask: pass-through all planes */
1435 if (_par->multiplexing)
1436 WHDR (fb_info, 0x4a); /* hidden dac reg: 1280x1024 */
1437 else
1438 WHDR (fb_info, 0); /* hidden dac: nothing */
1439 vga_wseq (fb_info->regs, VGA_SEQ_MEMORY_MODE, 0x0a); /* memory mode: chain4, ext. memory */
1440 vga_wseq (fb_info->regs, VGA_SEQ_PLANE_WRITE, 0xff); /* plane mask: enable writing to all 4 planes */
1441 offset = _par->var.xres_virtual / 8;
1444 /******************************************************
1446 * 16 bpp
1450 else if (_par->var.bits_per_pixel == 16) {
1451 DPRINTK ("clgen: preparing for 16 bit deep display\n");
1452 switch (fb_info->btype) {
1453 case BT_SD64:
1454 vga_wseq (fb_info->regs, CL_SEQR7, 0xf7); /* Extended Sequencer Mode: 256c col. mode */
1455 vga_wseq (fb_info->regs, CL_SEQR1F, 0x1e); /* MCLK select */
1456 break;
1458 case BT_PICCOLO:
1459 vga_wseq (fb_info->regs, CL_SEQR7, 0x87);
1460 vga_wseq (fb_info->regs, CL_SEQRF, 0xb0); /* Fast Page-Mode writes */
1461 vga_wseq (fb_info->regs, CL_SEQR1F, 0x22); /* MCLK select */
1462 break;
1464 case BT_PICASSO:
1465 vga_wseq (fb_info->regs, CL_SEQR7, 0x27);
1466 vga_wseq (fb_info->regs, CL_SEQRF, 0xb0); /* Fast Page-Mode writes */
1467 vga_wseq (fb_info->regs, CL_SEQR1F, 0x22); /* MCLK select */
1468 break;
1470 case BT_SPECTRUM:
1471 vga_wseq (fb_info->regs, CL_SEQR7, 0x87);
1472 vga_wseq (fb_info->regs, CL_SEQRF, 0xb0); /* Fast Page-Mode writes */
1473 vga_wseq (fb_info->regs, CL_SEQR1F, 0x22); /* MCLK select */
1474 break;
1476 case BT_PICASSO4:
1477 vga_wseq (fb_info->regs, CL_SEQR7, 0x27);
1478 /* vga_wseq (fb_info->regs, CL_SEQR1F, 0x1c); */
1479 break;
1481 case BT_ALPINE:
1482 DPRINTK (" (for GD543x)\n");
1483 if (_par->HorizRes >= 1024)
1484 vga_wseq (fb_info->regs, CL_SEQR7, 0xa7);
1485 else
1486 vga_wseq (fb_info->regs, CL_SEQR7, 0xa3);
1487 clgen_set_mclk (fb_info, _par->mclk, _par->divMCLK);
1488 break;
1490 case BT_GD5480:
1491 DPRINTK (" (for GD5480)\n");
1492 vga_wseq (fb_info->regs, CL_SEQR7, 0x17);
1493 /* We already set SRF and SR1F */
1494 break;
1496 case BT_LAGUNA:
1497 DPRINTK (" (for GD546x)\n");
1498 vga_wseq (fb_info->regs, CL_SEQR7,
1499 vga_rseq (fb_info->regs, CL_SEQR7) & ~0x01);
1500 break;
1502 default:
1503 printk (KERN_WARNING "CLGEN: unknown Board\n");
1504 break;
1507 vga_wgfx (fb_info->regs, VGA_GFX_MODE, 64); /* mode register: 256 color mode */
1508 WGen (fb_info, VGA_PEL_MSK, 0xff); /* pixel mask: pass-through all planes */
1509 #ifdef CONFIG_PCI
1510 WHDR (fb_info, 0xc0); /* Copy Xbh */
1511 #elif defined(CONFIG_ZORRO)
1512 /* FIXME: CONFIG_PCI and CONFIG_ZORRO may be defined both */
1513 WHDR (fb_info, 0xa0); /* hidden dac reg: nothing special */
1514 #endif
1515 vga_wseq (fb_info->regs, VGA_SEQ_MEMORY_MODE, 0x0a); /* memory mode: chain4, ext. memory */
1516 vga_wseq (fb_info->regs, VGA_SEQ_PLANE_WRITE, 0xff); /* plane mask: enable writing to all 4 planes */
1517 offset = _par->var.xres_virtual / 4;
1520 /******************************************************
1522 * 32 bpp
1526 else if (_par->var.bits_per_pixel == 32) {
1527 DPRINTK ("clgen: preparing for 24/32 bit deep display\n");
1528 switch (fb_info->btype) {
1529 case BT_SD64:
1530 vga_wseq (fb_info->regs, CL_SEQR7, 0xf9); /* Extended Sequencer Mode: 256c col. mode */
1531 vga_wseq (fb_info->regs, CL_SEQR1F, 0x1e); /* MCLK select */
1532 break;
1534 case BT_PICCOLO:
1535 vga_wseq (fb_info->regs, CL_SEQR7, 0x85);
1536 vga_wseq (fb_info->regs, CL_SEQRF, 0xb0); /* Fast Page-Mode writes */
1537 vga_wseq (fb_info->regs, CL_SEQR1F, 0x22); /* MCLK select */
1538 break;
1540 case BT_PICASSO:
1541 vga_wseq (fb_info->regs, CL_SEQR7, 0x25);
1542 vga_wseq (fb_info->regs, CL_SEQRF, 0xb0); /* Fast Page-Mode writes */
1543 vga_wseq (fb_info->regs, CL_SEQR1F, 0x22); /* MCLK select */
1544 break;
1546 case BT_SPECTRUM:
1547 vga_wseq (fb_info->regs, CL_SEQR7, 0x85);
1548 vga_wseq (fb_info->regs, CL_SEQRF, 0xb0); /* Fast Page-Mode writes */
1549 vga_wseq (fb_info->regs, CL_SEQR1F, 0x22); /* MCLK select */
1550 break;
1552 case BT_PICASSO4:
1553 vga_wseq (fb_info->regs, CL_SEQR7, 0x25);
1554 /* vga_wseq (fb_info->regs, CL_SEQR1F, 0x1c); */
1555 break;
1557 case BT_ALPINE:
1558 DPRINTK (" (for GD543x)\n");
1559 vga_wseq (fb_info->regs, CL_SEQR7, 0xa9);
1560 clgen_set_mclk (fb_info, _par->mclk, _par->divMCLK);
1561 break;
1563 case BT_GD5480:
1564 DPRINTK (" (for GD5480)\n");
1565 vga_wseq (fb_info->regs, CL_SEQR7, 0x19);
1566 /* We already set SRF and SR1F */
1567 break;
1569 case BT_LAGUNA:
1570 DPRINTK (" (for GD546x)\n");
1571 vga_wseq (fb_info->regs, CL_SEQR7,
1572 vga_rseq (fb_info->regs, CL_SEQR7) & ~0x01);
1573 break;
1575 default:
1576 printk (KERN_WARNING "clgen: unknown Board\n");
1577 break;
1580 vga_wgfx (fb_info->regs, VGA_GFX_MODE, 64); /* mode register: 256 color mode */
1581 WGen (fb_info, VGA_PEL_MSK, 0xff); /* pixel mask: pass-through all planes */
1582 WHDR (fb_info, 0xc5); /* hidden dac reg: 8-8-8 mode (24 or 32) */
1583 vga_wseq (fb_info->regs, VGA_SEQ_MEMORY_MODE, 0x0a); /* memory mode: chain4, ext. memory */
1584 vga_wseq (fb_info->regs, VGA_SEQ_PLANE_WRITE, 0xff); /* plane mask: enable writing to all 4 planes */
1585 offset = _par->var.xres_virtual / 4;
1588 /******************************************************
1590 * unknown/unsupported bpp
1594 else {
1595 printk (KERN_ERR "clgen: What's this?? requested color depth == %d.\n",
1596 _par->var.bits_per_pixel);
1599 vga_wcrt (fb_info->regs, VGA_CRTC_OFFSET, offset & 0xff);
1600 tmp = 0x22;
1601 if (offset & 0x100)
1602 tmp |= 0x10; /* offset overflow bit */
1604 vga_wcrt (fb_info->regs, CL_CRT1B, tmp); /* screen start addr #16-18, fastpagemode cycles */
1606 if (fb_info->btype == BT_SD64 ||
1607 fb_info->btype == BT_PICASSO4 ||
1608 fb_info->btype == BT_ALPINE ||
1609 fb_info->btype == BT_GD5480)
1610 vga_wcrt (fb_info->regs, CL_CRT1D, 0x00); /* screen start address bit 19 */
1612 vga_wcrt (fb_info->regs, VGA_CRTC_CURSOR_HI, 0); /* text cursor location high */
1613 vga_wcrt (fb_info->regs, VGA_CRTC_CURSOR_LO, 0); /* text cursor location low */
1614 vga_wcrt (fb_info->regs, VGA_CRTC_UNDERLINE, 0); /* underline row scanline = at very bottom */
1616 vga_wattr (fb_info->regs, VGA_ATC_MODE, 1); /* controller mode */
1617 vga_wattr (fb_info->regs, VGA_ATC_OVERSCAN, 0); /* overscan (border) color */
1618 vga_wattr (fb_info->regs, VGA_ATC_PLANE_ENABLE, 15); /* color plane enable */
1619 vga_wattr (fb_info->regs, CL_AR33, 0); /* pixel panning */
1620 vga_wattr (fb_info->regs, VGA_ATC_COLOR_PAGE, 0); /* color select */
1622 /* [ EGS: SetOffset(); ] */
1623 /* From SetOffset(): Turn on VideoEnable bit in Attribute controller */
1624 AttrOn (fb_info);
1626 vga_wgfx (fb_info->regs, VGA_GFX_SR_VALUE, 0); /* set/reset register */
1627 vga_wgfx (fb_info->regs, VGA_GFX_SR_ENABLE, 0); /* set/reset enable */
1628 vga_wgfx (fb_info->regs, VGA_GFX_COMPARE_VALUE, 0); /* color compare */
1629 vga_wgfx (fb_info->regs, VGA_GFX_DATA_ROTATE, 0); /* data rotate */
1630 vga_wgfx (fb_info->regs, VGA_GFX_PLANE_READ, 0); /* read map select */
1631 vga_wgfx (fb_info->regs, VGA_GFX_MISC, 1); /* miscellaneous register */
1632 vga_wgfx (fb_info->regs, VGA_GFX_COMPARE_MASK, 15); /* color don't care */
1633 vga_wgfx (fb_info->regs, VGA_GFX_BIT_MASK, 255); /* bit mask */
1635 vga_wseq (fb_info->regs, CL_SEQR12, 0x0); /* graphics cursor attributes: nothing special */
1637 /* finally, turn on everything - turn off "FullBandwidth" bit */
1638 /* also, set "DotClock%2" bit where requested */
1639 tmp = 0x01;
1641 /*** FB_VMODE_CLOCK_HALVE in linux/fb.h not defined anymore ?
1642 if (var->vmode & FB_VMODE_CLOCK_HALVE)
1643 tmp |= 0x08;
1646 vga_wseq (fb_info->regs, VGA_SEQ_CLOCK_MODE, tmp);
1647 DPRINTK ("CL_SEQR1: %d\n", tmp);
1649 fb_info->currentmode = *_par;
1651 DPRINTK ("virtual offset: (%d,%d)\n", _par->var.xoffset, _par->var.yoffset);
1652 /* pan to requested offset */
1653 clgen_pan_display (&fb_info->currentmode.var, (struct fb_info_gen *) fb_info);
1655 #ifdef CLGEN_DEBUG
1656 clgen_dump ();
1657 #endif
1659 DPRINTK ("EXIT\n");
1660 return;
1664 static int clgen_getcolreg (unsigned regno, unsigned *red, unsigned *green,
1665 unsigned *blue, unsigned *transp,
1666 struct fb_info *info)
1668 struct clgenfb_info *fb_info = (struct clgenfb_info *)info;
1670 if (regno > 255)
1671 return 1;
1672 *red = fb_info->palette[regno].red;
1673 *green = fb_info->palette[regno].green;
1674 *blue = fb_info->palette[regno].blue;
1675 *transp = 0;
1676 return 0;
1680 static int clgenfb_setcolreg (unsigned regno, unsigned red, unsigned green,
1681 unsigned blue, unsigned transp,
1682 struct fb_info *info)
1684 struct clgenfb_info *fb_info = (struct clgenfb_info *) info;
1686 if (regno > 255)
1687 return -EINVAL;
1689 #ifdef FBCON_HAS_CFB8
1690 switch (fb_info->currentmode.var.bits_per_pixel) {
1691 case 8:
1692 /* "transparent" stuff is completely ignored. */
1693 WClut (fb_info, regno, red >> 10, green >> 10, blue >> 10);
1694 break;
1695 default:
1696 /* do nothing */
1697 break;
1699 #endif /* FBCON_HAS_CFB8 */
1701 fb_info->palette[regno].red = red;
1702 fb_info->palette[regno].green = green;
1703 fb_info->palette[regno].blue = blue;
1705 if (regno >= 16)
1706 return 0;
1708 switch (fb_info->currentmode.var.bits_per_pixel) {
1710 #ifdef FBCON_HAS_CFB16
1711 case 16:
1712 assert (regno < 16);
1713 if(isPReP) {
1714 fb_info->fbcon_cmap.cfb16[regno] =
1715 ((red & 0xf800) >> 9) |
1716 ((green & 0xf800) >> 14) |
1717 ((green & 0xf800) << 2) |
1718 ((blue & 0xf800) >> 3);
1719 } else {
1720 fb_info->fbcon_cmap.cfb16[regno] =
1721 ((red & 0xf800) >> 1) |
1722 ((green & 0xf800) >> 6) |
1723 ((blue & 0xf800) >> 11);
1725 #endif /* FBCON_HAS_CFB16 */
1727 #ifdef FBCON_HAS_CFB24
1728 case 24:
1729 assert (regno < 16);
1730 fb_info->fbcon_cmap.cfb24[regno] =
1731 (red << fb_info->currentmode.var.red.offset) |
1732 (green << fb_info->currentmode.var.green.offset) |
1733 (blue << fb_info->currentmode.var.blue.offset);
1734 break;
1735 #endif /* FBCON_HAS_CFB24 */
1737 #ifdef FBCON_HAS_CFB32
1738 case 32:
1739 assert (regno < 16);
1740 if(isPReP) {
1741 fb_info->fbcon_cmap.cfb32[regno] =
1742 ((red & 0xff00)) |
1743 ((green & 0xff00) << 8) |
1744 ((blue & 0xff00) << 16);
1745 } else {
1746 fb_info->fbcon_cmap.cfb32[regno] =
1747 ((red & 0xff00) << 8) |
1748 ((green & 0xff00)) |
1749 ((blue & 0xff00) >> 8);
1751 break;
1752 #endif /* FBCON_HAS_CFB32 */
1753 default:
1754 /* do nothing */
1755 break;
1758 return 0;
1761 /*************************************************************************
1762 clgen_pan_display()
1764 performs display panning - provided hardware permits this
1765 **************************************************************************/
1766 static int clgen_pan_display (const struct fb_var_screeninfo *var,
1767 struct fb_info_gen *info)
1769 int xoffset = 0;
1770 int yoffset = 0;
1771 unsigned long base;
1772 unsigned char tmp = 0, tmp2 = 0, xpix;
1773 struct clgenfb_info *fb_info = (struct clgenfb_info *) info;
1775 DPRINTK ("ENTER\n");
1777 /* no range checks for xoffset and yoffset, */
1778 /* as fbgen_pan_display has already done this */
1780 fb_info->currentmode.var.xoffset = var->xoffset;
1781 fb_info->currentmode.var.yoffset = var->yoffset;
1783 xoffset = var->xoffset * fb_info->currentmode.var.bits_per_pixel / 8;
1784 yoffset = var->yoffset;
1786 base = yoffset * fb_info->currentmode.line_length + xoffset;
1788 if (fb_info->currentmode.var.bits_per_pixel == 1) {
1789 /* base is already correct */
1790 xpix = (unsigned char) (var->xoffset % 8);
1791 } else {
1792 base /= 4;
1793 xpix = (unsigned char) ((xoffset % 4) * 2);
1796 /* lower 8 + 8 bits of screen start address */
1797 vga_wcrt (fb_info->regs, VGA_CRTC_START_LO, (unsigned char) (base & 0xff));
1798 vga_wcrt (fb_info->regs, VGA_CRTC_START_HI, (unsigned char) (base >> 8));
1800 /* construct bits 16, 17 and 18 of screen start address */
1801 if (base & 0x10000)
1802 tmp |= 0x01;
1803 if (base & 0x20000)
1804 tmp |= 0x04;
1805 if (base & 0x40000)
1806 tmp |= 0x08;
1808 tmp2 = (vga_rcrt (fb_info->regs, CL_CRT1B) & 0xf2) | tmp; /* 0xf2 is %11110010, exclude tmp bits */
1809 vga_wcrt (fb_info->regs, CL_CRT1B, tmp2);
1811 /* construct bit 19 of screen start address */
1812 if (clgen_board_info[fb_info->btype].scrn_start_bit19) {
1813 tmp2 = 0;
1814 if (base & 0x80000)
1815 tmp2 = 0x80;
1816 vga_wcrt (fb_info->regs, CL_CRT1D, tmp2);
1819 /* write pixel panning value to AR33; this does not quite work in 8bpp */
1820 /* ### Piccolo..? Will this work? */
1821 if (fb_info->currentmode.var.bits_per_pixel == 1)
1822 vga_wattr (fb_info->regs, CL_AR33, xpix);
1825 DPRINTK ("EXIT\n");
1826 return (0);
1830 static int clgen_blank (int blank_mode, struct fb_info_gen *info)
1833 * Blank the screen if blank_mode != 0, else unblank. If blank == NULL
1834 * then the caller blanks by setting the CLUT (Color Look Up Table) to all
1835 * black. Return 0 if blanking succeeded, != 0 if un-/blanking failed due
1836 * to e.g. a video mode which doesn't support it. Implements VESA suspend
1837 * and powerdown modes on hardware that supports disabling hsync/vsync:
1838 * blank_mode == 2: suspend vsync
1839 * blank_mode == 3: suspend hsync
1840 * blank_mode == 4: powerdown
1842 unsigned char val;
1843 static int current_mode = 0;
1844 struct clgenfb_info *fb_info = (struct clgenfb_info *) info;
1846 DPRINTK ("ENTER, blank mode = %d\n", blank_mode);
1848 if (current_mode == blank_mode) {
1849 DPRINTK ("EXIT, returning 0\n");
1850 return 0;
1853 /* Undo current */
1854 switch (current_mode) {
1855 case 0: /* Screen is normal */
1856 break;
1857 case 1: /* Screen is blanked */
1858 val = vga_rseq (fb_info->regs, VGA_SEQ_CLOCK_MODE);
1859 vga_wseq (fb_info->regs, VGA_SEQ_CLOCK_MODE, val & 0xdf); /* clear "FullBandwidth" bit */
1860 break;
1861 case 2: /* vsync suspended */
1862 case 3: /* hsync suspended */
1863 case 4: /* sceen is powered down */
1864 vga_wgfx (fb_info->regs, CL_GRE, 0x00);
1865 break;
1866 default:
1867 DPRINTK ("EXIT, returning 1\n");
1868 return 1;
1871 /* set new */
1872 switch (blank_mode) {
1873 case 0: /* Unblank screen */
1874 break;
1875 case 1: /* Blank screen */
1876 val = vga_rseq (fb_info->regs, VGA_SEQ_CLOCK_MODE);
1877 vga_wseq (fb_info->regs, VGA_SEQ_CLOCK_MODE, val | 0x20); /* set "FullBandwidth" bit */
1878 break;
1879 case 2: /* suspend vsync */
1880 vga_wgfx (fb_info->regs, CL_GRE, 0x04);
1881 break;
1882 case 3: /* suspend hsync */
1883 vga_wgfx (fb_info->regs, CL_GRE, 0x02);
1884 break;
1885 case 4: /* powerdown */
1886 vga_wgfx (fb_info->regs, CL_GRE, 0x06);
1887 break;
1888 default:
1889 DPRINTK ("EXIT, returning 1\n");
1890 return 1;
1893 current_mode = blank_mode;
1894 DPRINTK ("EXIT, returning 0\n");
1895 return 0;
1897 /**** END Hardware specific Routines **************************************/
1898 /****************************************************************************/
1899 /**** BEGIN Internal Routines ***********************************************/
1901 static void __init init_vgachip (struct clgenfb_info *fb_info)
1903 const struct clgen_board_info_rec *bi;
1905 DPRINTK ("ENTER\n");
1907 assert (fb_info != NULL);
1909 bi = &clgen_board_info[fb_info->btype];
1911 /* reset board globally */
1912 switch (fb_info->btype) {
1913 case BT_PICCOLO:
1914 WSFR (fb_info, 0x01);
1915 udelay (500);
1916 WSFR (fb_info, 0x51);
1917 udelay (500);
1918 break;
1919 case BT_PICASSO:
1920 WSFR2 (fb_info, 0xff);
1921 udelay (500);
1922 break;
1923 case BT_SD64:
1924 case BT_SPECTRUM:
1925 WSFR (fb_info, 0x1f);
1926 udelay (500);
1927 WSFR (fb_info, 0x4f);
1928 udelay (500);
1929 break;
1930 case BT_PICASSO4:
1931 vga_wcrt (fb_info->regs, CL_CRT51, 0x00); /* disable flickerfixer */
1932 mdelay (100);
1933 vga_wgfx (fb_info->regs, CL_GR2F, 0x00); /* from Klaus' NetBSD driver: */
1934 vga_wgfx (fb_info->regs, CL_GR33, 0x00); /* put blitter into 542x compat */
1935 vga_wgfx (fb_info->regs, CL_GR31, 0x00); /* mode */
1936 break;
1938 case BT_GD5480:
1939 vga_wgfx (fb_info->regs, CL_GR2F, 0x00); /* from Klaus' NetBSD driver: */
1940 break;
1942 case BT_ALPINE:
1943 /* Nothing to do to reset the board. */
1944 break;
1946 default:
1947 printk (KERN_ERR "clgen: Warning: Unknown board type\n");
1948 break;
1951 assert (fb_info->size > 0); /* make sure RAM size set by this point */
1953 /* assume it's a "large memory" board (2/4 MB) */
1954 fb_info->smallboard = FALSE;
1956 /* the P4 is not fully initialized here; I rely on it having been */
1957 /* inited under AmigaOS already, which seems to work just fine */
1958 /* (Klaus advised to do it this way) */
1960 if (fb_info->btype != BT_PICASSO4) {
1961 WGen (fb_info, CL_VSSM, 0x10); /* EGS: 0x16 */
1962 WGen (fb_info, CL_POS102, 0x01);
1963 WGen (fb_info, CL_VSSM, 0x08); /* EGS: 0x0e */
1965 if (fb_info->btype != BT_SD64)
1966 WGen (fb_info, CL_VSSM2, 0x01);
1968 vga_wseq (fb_info->regs, CL_SEQR0, 0x03); /* reset sequencer logic */
1970 vga_wseq (fb_info->regs, VGA_SEQ_CLOCK_MODE, 0x21); /* FullBandwidth (video off) and 8/9 dot clock */
1971 WGen (fb_info, VGA_MIS_W, 0xc1); /* polarity (-/-), disable access to display memory, VGA_CRTC_START_HI base address: color */
1973 /* vga_wgfx (fb_info->regs, CL_GRA, 0xce); "magic cookie" - doesn't make any sense to me.. */
1974 vga_wseq (fb_info->regs, CL_SEQR6, 0x12); /* unlock all extension registers */
1976 vga_wgfx (fb_info->regs, CL_GR31, 0x04); /* reset blitter */
1978 switch (fb_info->btype) {
1979 case BT_GD5480:
1980 vga_wseq (fb_info->regs, CL_SEQRF, 0x98);
1981 break;
1982 case BT_ALPINE:
1983 break;
1984 case BT_SD64:
1985 vga_wseq (fb_info->regs, CL_SEQRF, 0xb8);
1986 break;
1987 default:
1988 vga_wseq (fb_info->regs, CL_SEQR16, 0x0f);
1989 vga_wseq (fb_info->regs, CL_SEQRF, 0xb0);
1990 break;
1993 vga_wseq (fb_info->regs, VGA_SEQ_PLANE_WRITE, 0xff); /* plane mask: nothing */
1994 vga_wseq (fb_info->regs, VGA_SEQ_CHARACTER_MAP, 0x00); /* character map select: doesn't even matter in gx mode */
1995 vga_wseq (fb_info->regs, VGA_SEQ_MEMORY_MODE, 0x0e); /* memory mode: chain-4, no odd/even, ext. memory */
1997 /* controller-internal base address of video memory */
1998 if (bi->init_sr07)
1999 vga_wseq (fb_info->regs, CL_SEQR7, bi->sr07);
2001 /* vga_wseq (fb_info->regs, CL_SEQR8, 0x00); *//* EEPROM control: shouldn't be necessary to write to this at all.. */
2003 vga_wseq (fb_info->regs, CL_SEQR10, 0x00); /* graphics cursor X position (incomplete; position gives rem. 3 bits */
2004 vga_wseq (fb_info->regs, CL_SEQR11, 0x00); /* graphics cursor Y position (..."... ) */
2005 vga_wseq (fb_info->regs, CL_SEQR12, 0x00); /* graphics cursor attributes */
2006 vga_wseq (fb_info->regs, CL_SEQR13, 0x00); /* graphics cursor pattern address */
2008 /* writing these on a P4 might give problems.. */
2009 if (fb_info->btype != BT_PICASSO4) {
2010 vga_wseq (fb_info->regs, CL_SEQR17, 0x00); /* configuration readback and ext. color */
2011 vga_wseq (fb_info->regs, CL_SEQR18, 0x02); /* signature generator */
2014 /* MCLK select etc. */
2015 if (bi->init_sr1f)
2016 vga_wseq (fb_info->regs, CL_SEQR1F, bi->sr1f);
2018 vga_wcrt (fb_info->regs, VGA_CRTC_PRESET_ROW, 0x00); /* Screen A preset row scan: none */
2019 vga_wcrt (fb_info->regs, VGA_CRTC_CURSOR_START, 0x20); /* Text cursor start: disable text cursor */
2020 vga_wcrt (fb_info->regs, VGA_CRTC_CURSOR_END, 0x00); /* Text cursor end: - */
2021 vga_wcrt (fb_info->regs, VGA_CRTC_START_HI, 0x00); /* Screen start address high: 0 */
2022 vga_wcrt (fb_info->regs, VGA_CRTC_START_LO, 0x00); /* Screen start address low: 0 */
2023 vga_wcrt (fb_info->regs, VGA_CRTC_CURSOR_HI, 0x00); /* text cursor location high: 0 */
2024 vga_wcrt (fb_info->regs, VGA_CRTC_CURSOR_LO, 0x00); /* text cursor location low: 0 */
2026 vga_wcrt (fb_info->regs, VGA_CRTC_UNDERLINE, 0x00); /* Underline Row scanline: - */
2027 vga_wcrt (fb_info->regs, VGA_CRTC_MODE, 0xc3); /* mode control: timing enable, byte mode, no compat modes */
2028 vga_wcrt (fb_info->regs, VGA_CRTC_LINE_COMPARE, 0x00); /* Line Compare: not needed */
2029 /* ### add 0x40 for text modes with > 30 MHz pixclock */
2030 vga_wcrt (fb_info->regs, CL_CRT1B, 0x02); /* ext. display controls: ext.adr. wrap */
2032 vga_wgfx (fb_info->regs, VGA_GFX_SR_VALUE, 0x00); /* Set/Reset registes: - */
2033 vga_wgfx (fb_info->regs, VGA_GFX_SR_ENABLE, 0x00); /* Set/Reset enable: - */
2034 vga_wgfx (fb_info->regs, VGA_GFX_COMPARE_VALUE, 0x00); /* Color Compare: - */
2035 vga_wgfx (fb_info->regs, VGA_GFX_DATA_ROTATE, 0x00); /* Data Rotate: - */
2036 vga_wgfx (fb_info->regs, VGA_GFX_PLANE_READ, 0x00); /* Read Map Select: - */
2037 vga_wgfx (fb_info->regs, VGA_GFX_MODE, 0x00); /* Mode: conf. for 16/4/2 color mode, no odd/even, read/write mode 0 */
2038 vga_wgfx (fb_info->regs, VGA_GFX_MISC, 0x01); /* Miscellaneous: memory map base address, graphics mode */
2039 vga_wgfx (fb_info->regs, VGA_GFX_COMPARE_MASK, 0x0f); /* Color Don't care: involve all planes */
2040 vga_wgfx (fb_info->regs, VGA_GFX_BIT_MASK, 0xff); /* Bit Mask: no mask at all */
2041 if (fb_info->btype == BT_ALPINE)
2042 vga_wgfx (fb_info->regs, CL_GRB, 0x20); /* (5434 can't have bit 3 set for bitblt) */
2043 else
2044 vga_wgfx (fb_info->regs, CL_GRB, 0x28); /* Graphics controller mode extensions: finer granularity, 8byte data latches */
2046 vga_wgfx (fb_info->regs, CL_GRC, 0xff); /* Color Key compare: - */
2047 vga_wgfx (fb_info->regs, CL_GRD, 0x00); /* Color Key compare mask: - */
2048 vga_wgfx (fb_info->regs, CL_GRE, 0x00); /* Miscellaneous control: - */
2049 /* vga_wgfx (fb_info->regs, CL_GR10, 0x00); *//* Background color byte 1: - */
2050 /* vga_wgfx (fb_info->regs, CL_GR11, 0x00); */
2052 vga_wattr (fb_info->regs, VGA_ATC_PALETTE0, 0x00); /* Attribute Controller palette registers: "identity mapping" */
2053 vga_wattr (fb_info->regs, VGA_ATC_PALETTE1, 0x01);
2054 vga_wattr (fb_info->regs, VGA_ATC_PALETTE2, 0x02);
2055 vga_wattr (fb_info->regs, VGA_ATC_PALETTE3, 0x03);
2056 vga_wattr (fb_info->regs, VGA_ATC_PALETTE4, 0x04);
2057 vga_wattr (fb_info->regs, VGA_ATC_PALETTE5, 0x05);
2058 vga_wattr (fb_info->regs, VGA_ATC_PALETTE6, 0x06);
2059 vga_wattr (fb_info->regs, VGA_ATC_PALETTE7, 0x07);
2060 vga_wattr (fb_info->regs, VGA_ATC_PALETTE8, 0x08);
2061 vga_wattr (fb_info->regs, VGA_ATC_PALETTE9, 0x09);
2062 vga_wattr (fb_info->regs, VGA_ATC_PALETTEA, 0x0a);
2063 vga_wattr (fb_info->regs, VGA_ATC_PALETTEB, 0x0b);
2064 vga_wattr (fb_info->regs, VGA_ATC_PALETTEC, 0x0c);
2065 vga_wattr (fb_info->regs, VGA_ATC_PALETTED, 0x0d);
2066 vga_wattr (fb_info->regs, VGA_ATC_PALETTEE, 0x0e);
2067 vga_wattr (fb_info->regs, VGA_ATC_PALETTEF, 0x0f);
2069 vga_wattr (fb_info->regs, VGA_ATC_MODE, 0x01); /* Attribute Controller mode: graphics mode */
2070 vga_wattr (fb_info->regs, VGA_ATC_OVERSCAN, 0x00); /* Overscan color reg.: reg. 0 */
2071 vga_wattr (fb_info->regs, VGA_ATC_PLANE_ENABLE, 0x0f); /* Color Plane enable: Enable all 4 planes */
2072 /* ### vga_wattr (fb_info->regs, CL_AR33, 0x00); * Pixel Panning: - */
2073 vga_wattr (fb_info->regs, VGA_ATC_COLOR_PAGE, 0x00); /* Color Select: - */
2075 WGen (fb_info, VGA_PEL_MSK, 0xff); /* Pixel mask: no mask */
2077 if (fb_info->btype != BT_ALPINE && fb_info->btype != BT_GD5480)
2078 WGen (fb_info, VGA_MIS_W, 0xc3); /* polarity (-/-), enable display mem, VGA_CRTC_START_HI i/o base = color */
2080 vga_wgfx (fb_info->regs, CL_GR31, 0x04); /* BLT Start/status: Blitter reset */
2081 vga_wgfx (fb_info->regs, CL_GR31, 0x00); /* - " - : "end-of-reset" */
2083 /* CLUT setup */
2084 WClut (fb_info, 0, 0x00, 0x00, 0x00); /* background: black */
2085 WClut (fb_info, 1, 0x3f, 0x3f, 0x3f); /* foreground: white */
2086 WClut (fb_info, 2, 0x00, 0x20, 0x00);
2087 WClut (fb_info, 3, 0x00, 0x20, 0x20);
2088 WClut (fb_info, 4, 0x20, 0x00, 0x00);
2089 WClut (fb_info, 5, 0x20, 0x00, 0x20);
2090 WClut (fb_info, 6, 0x20, 0x10, 0x00);
2091 WClut (fb_info, 7, 0x20, 0x20, 0x20);
2092 WClut (fb_info, 8, 0x10, 0x10, 0x10);
2093 WClut (fb_info, 9, 0x10, 0x10, 0x30);
2094 WClut (fb_info, 10, 0x10, 0x30, 0x10);
2095 WClut (fb_info, 11, 0x10, 0x30, 0x30);
2096 WClut (fb_info, 12, 0x30, 0x10, 0x10);
2097 WClut (fb_info, 13, 0x30, 0x10, 0x30);
2098 WClut (fb_info, 14, 0x30, 0x30, 0x10);
2099 WClut (fb_info, 15, 0x30, 0x30, 0x30);
2101 /* the rest a grey ramp */
2103 int i;
2105 for (i = 16; i < 256; i++)
2106 WClut (fb_info, i, i >> 2, i >> 2, i >> 2);
2110 /* misc... */
2111 WHDR (fb_info, 0); /* Hidden DAC register: - */
2113 printk (KERN_INFO "clgen: This board has %ld bytes of DRAM memory\n", fb_info->size);
2114 DPRINTK ("EXIT\n");
2115 return;
2118 static void switch_monitor (struct clgenfb_info *fb_info, int on)
2120 #ifdef CONFIG_ZORRO /* only works on Zorro boards */
2121 static int IsOn = 0; /* XXX not ok for multiple boards */
2123 DPRINTK ("ENTER\n");
2125 if (fb_info->btype == BT_PICASSO4)
2126 return; /* nothing to switch */
2127 if (fb_info->btype == BT_ALPINE)
2128 return; /* nothing to switch */
2129 if (fb_info->btype == BT_GD5480)
2130 return; /* nothing to switch */
2131 if (fb_info->btype == BT_PICASSO) {
2132 if ((on && !IsOn) || (!on && IsOn))
2133 WSFR (fb_info, 0xff);
2135 DPRINTK ("EXIT\n");
2136 return;
2138 if (on) {
2139 switch (fb_info->btype) {
2140 case BT_SD64:
2141 WSFR (fb_info, fb_info->SFR | 0x21);
2142 break;
2143 case BT_PICCOLO:
2144 WSFR (fb_info, fb_info->SFR | 0x28);
2145 break;
2146 case BT_SPECTRUM:
2147 WSFR (fb_info, 0x6f);
2148 break;
2149 default: /* do nothing */ break;
2151 } else {
2152 switch (fb_info->btype) {
2153 case BT_SD64:
2154 WSFR (fb_info, fb_info->SFR & 0xde);
2155 break;
2156 case BT_PICCOLO:
2157 WSFR (fb_info, fb_info->SFR & 0xd7);
2158 break;
2159 case BT_SPECTRUM:
2160 WSFR (fb_info, 0x4f);
2161 break;
2162 default: /* do nothing */ break;
2166 DPRINTK ("EXIT\n");
2167 #endif /* CONFIG_ZORRO */
2170 static void clgen_set_disp (const void *par, struct display *disp,
2171 struct fb_info_gen *info)
2173 struct clgenfb_par *_par = (struct clgenfb_par *) par;
2174 struct clgenfb_info *fb_info = (struct clgenfb_info *) info;
2175 int accel_text;
2177 DPRINTK ("ENTER\n");
2179 assert (_par != NULL);
2180 assert (fb_info != NULL);
2182 accel_text = _par->var.accel_flags & FB_ACCELF_TEXT;
2184 printk ("Cirrus Logic video mode: ");
2185 info->info.screen_base = (char *) fb_info->fbmem;
2186 switch (_par->var.bits_per_pixel) {
2187 #ifdef FBCON_HAS_MFB
2188 case 1:
2189 printk ("monochrome\n");
2190 if (fb_info->btype == BT_GD5480)
2191 info->info.screen_base = (char *) fb_info->fbmem;
2192 disp->dispsw = &fbcon_mfb;
2193 break;
2194 #endif
2195 #ifdef FBCON_HAS_CFB8
2196 case 8:
2197 printk ("8 bit color depth\n");
2198 if (fb_info->btype == BT_GD5480)
2199 info->info.screen_base = (char *) fb_info->fbmem;
2200 if (accel_text)
2201 disp->dispsw = &fbcon_clgen_8;
2202 else
2203 disp->dispsw = &fbcon_cfb8;
2204 break;
2205 #endif
2206 #ifdef FBCON_HAS_CFB16
2207 case 16:
2208 printk ("16 bit color depth\n");
2209 if (accel_text)
2210 disp->dispsw = &fbcon_clgen_16;
2211 else
2212 disp->dispsw = &fbcon_cfb16;
2213 if (fb_info->btype == BT_GD5480)
2214 info->info.screen_base = (char *) fb_info->fbmem + 1 * MB_;
2215 disp->dispsw_data = fb_info->fbcon_cmap.cfb16;
2216 break;
2217 #endif
2218 #ifdef FBCON_HAS_CFB24
2219 case 24:
2220 printk ("24 bit color depth\n");
2221 disp->dispsw = &fbcon_cfb24;
2222 if (fb_info->btype == BT_GD5480)
2223 info->info.screen_base = (char *) fb_info->fbmem + 2 * MB_;
2224 disp->dispsw_data = fb_info->fbcon_cmap.cfb24;
2225 break;
2226 #endif
2227 #ifdef FBCON_HAS_CFB32
2228 case 32:
2229 printk ("32 bit color depth\n");
2230 if (accel_text)
2231 disp->dispsw = &fbcon_clgen_32;
2232 else
2233 disp->dispsw = &fbcon_cfb32;
2234 if (fb_info->btype == BT_GD5480)
2235 info->info.screen_base = (char *) fb_info->fbmem + 2 * MB_;
2236 disp->dispsw_data = fb_info->fbcon_cmap.cfb32;
2237 break;
2238 #endif
2240 default:
2241 printk ("unsupported color depth\n");
2242 disp->dispsw = &fbcon_dummy;
2243 disp->dispsw_data = NULL;
2244 break;
2247 DPRINTK ("EXIT\n");
2250 #ifdef FBCON_HAS_CFB8
2251 static void fbcon_clgen8_bmove (struct display *p, int sy, int sx,
2252 int dy, int dx, int height, int width)
2254 struct clgenfb_info *fb_info = (struct clgenfb_info *) p->fb_info;
2256 DPRINTK ("ENTER\n");
2258 sx *= fontwidth (p);
2259 sy *= fontheight (p);
2260 dx *= fontwidth (p);
2261 dy *= fontheight (p);
2262 width *= fontwidth (p);
2263 height *= fontheight (p);
2265 clgen_BitBLT (fb_info->regs, (unsigned short) sx, (unsigned short) sy,
2266 (unsigned short) dx, (unsigned short) dy,
2267 (unsigned short) width, (unsigned short) height,
2268 fb_info->currentmode.line_length);
2270 DPRINTK ("EXIT\n");
2273 static void fbcon_clgen8_clear (struct vc_data *conp, struct display *p,
2274 int sy, int sx, int height, int width)
2276 struct clgenfb_info *fb_info = (struct clgenfb_info *) p->fb_info;
2277 unsigned short col;
2279 DPRINTK ("ENTER\n");
2281 sx *= fontwidth (p);
2282 sy *= fontheight (p);
2283 width *= fontwidth (p);
2284 height *= fontheight (p);
2286 col = attr_bgcol_ec (p, conp);
2287 col &= 0xff;
2289 clgen_RectFill (fb_info, (unsigned short) sx, (unsigned short) sy,
2290 (unsigned short) width, (unsigned short) height,
2291 col, fb_info->currentmode.line_length);
2293 DPRINTK ("EXIT\n");
2296 #endif
2298 #ifdef FBCON_HAS_CFB16
2299 static void fbcon_clgen16_bmove (struct display *p, int sy, int sx,
2300 int dy, int dx, int height, int width)
2302 struct clgenfb_info *fb_info = (struct clgenfb_info *) p->fb_info;
2304 DPRINTK ("ENTER\n");
2306 sx *= fontwidth (p) * 2; /* 2 bytes/pixel */
2307 sy *= fontheight (p);
2308 dx *= fontwidth (p) * 2; /* 2 bytes/pixel */
2309 dy *= fontheight (p);
2310 width *= fontwidth (p) * 2; /* 2 bytes/pixel */
2311 height *= fontheight (p);
2313 clgen_BitBLT (fb_info->regs, (unsigned short) sx, (unsigned short) sy,
2314 (unsigned short) dx, (unsigned short) dy,
2315 (unsigned short) width, (unsigned short) height,
2316 fb_info->currentmode.line_length);
2318 DPRINTK ("EXIT\n");
2321 static void fbcon_clgen16_clear (struct vc_data *conp, struct display *p,
2322 int sy, int sx, int height, int width)
2324 struct clgenfb_info *fb_info = (struct clgenfb_info *) p->fb_info;
2325 unsigned short col;
2327 DPRINTK ("ENTER\n");
2329 sx *= fontwidth (p) * 2; /* 2 bytes/pixel */
2330 sy *= fontheight (p);
2331 width *= fontwidth (p) * 2; /* 2 bytes/pixel? */
2332 height *= fontheight (p);
2334 col = attr_bgcol_ec (p, conp);
2335 col &= 0xff;
2337 clgen_RectFill (fb_info, (unsigned short) sx, (unsigned short) sy,
2338 (unsigned short) width, (unsigned short) height,
2339 col, fb_info->currentmode.line_length);
2341 DPRINTK ("EXIT\n");
2344 #endif
2346 #ifdef FBCON_HAS_CFB32
2347 static void fbcon_clgen32_bmove (struct display *p, int sy, int sx,
2348 int dy, int dx, int height, int width)
2350 struct clgenfb_info *fb_info = (struct clgenfb_info *) p->fb_info;
2352 DPRINTK ("ENTER\n");
2354 sx *= fontwidth (p) * 4; /* 4 bytes/pixel */
2355 sy *= fontheight (p);
2356 dx *= fontwidth (p) * 4; /* 4 bytes/pixel */
2357 dy *= fontheight (p);
2358 width *= fontwidth (p) * 4; /* 4 bytes/pixel */
2359 height *= fontheight (p);
2361 clgen_BitBLT (fb_info->regs, (unsigned short) sx, (unsigned short) sy,
2362 (unsigned short) dx, (unsigned short) dy,
2363 (unsigned short) width, (unsigned short) height,
2364 fb_info->currentmode.line_length);
2366 DPRINTK ("EXIT\n");
2369 static void fbcon_clgen32_clear (struct vc_data *conp, struct display *p,
2370 int sy, int sx, int height, int width)
2372 struct clgenfb_info *fb_info = (struct clgenfb_info *) p->fb_info;
2374 unsigned short col;
2376 DPRINTK ("ENTER\n");
2378 sx *= fontwidth (p) * 4; /* 4 bytes/pixel */
2379 sy *= fontheight (p);
2380 width *= fontwidth (p) * 4; /* 4 bytes/pixel? */
2381 height *= fontheight (p);
2383 col = attr_bgcol_ec (p, conp);
2384 col &= 0xff;
2386 clgen_RectFill (fb_info, (unsigned short) sx, (unsigned short) sy,
2387 (unsigned short) width, (unsigned short) height,
2388 col, fb_info->currentmode.line_length);
2390 DPRINTK ("EXIT\n");
2393 #endif /* FBCON_HAS_CFB32 */
2398 #ifdef CONFIG_PPC_PREP
2399 #define PREP_VIDEO_BASE ((volatile unsigned long) 0xC0000000)
2400 #define PREP_IO_BASE ((volatile unsigned char *) 0x80000000)
2401 static void __init get_prep_addrs (unsigned long *display, unsigned long *registers)
2403 DPRINTK ("ENTER\n");
2405 *display = PREP_VIDEO_BASE;
2406 *registers = (unsigned long) PREP_IO_BASE;
2408 DPRINTK ("EXIT\n");
2411 #endif /* CONFIG_PPC_PREP */
2416 #ifdef CONFIG_PCI
2417 static int release_io_ports = 0;
2419 /* Pulled the logic from XFree86 Cirrus driver to get the memory size,
2420 * based on the DRAM bandwidth bit and DRAM bank switching bit. This
2421 * works with 1MB, 2MB and 4MB configurations (which the Motorola boards
2422 * seem to have. */
2423 static unsigned int __init clgen_get_memsize (caddr_t regbase)
2425 unsigned long mem;
2426 unsigned char SRF;
2428 DPRINTK ("ENTER\n");
2430 SRF = vga_rseq (regbase, CL_SEQRF);
2431 switch ((SRF & 0x18)) {
2432 case 0x08: mem = 512 * 1024; break;
2433 case 0x10: mem = 1024 * 1024; break;
2434 /* 64-bit DRAM data bus width; assume 2MB. Also indicates 2MB memory
2435 * on the 5430. */
2436 case 0x18: mem = 2048 * 1024; break;
2437 default: printk ("CLgenfb: Unknown memory size!\n");
2438 mem = 1024 * 1024;
2440 if (SRF & 0x80) {
2441 /* If DRAM bank switching is enabled, there must be twice as much
2442 * memory installed. (4MB on the 5434) */
2443 mem *= 2;
2445 /* TODO: Handling of GD5446/5480 (see XF86 sources ...) */
2446 return mem;
2448 DPRINTK ("EXIT\n");
2453 static struct pci_dev * __init clgen_pci_dev_get (clgen_board_t *btype)
2455 struct pci_dev *pdev;
2456 int i;
2458 DPRINTK ("ENTER\n");
2460 for (i = 0; i < ARRAY_SIZE(clgen_pci_probe_list); i++) {
2461 pdev = NULL;
2462 while ((pdev = pci_find_device (PCI_VENDOR_ID_CIRRUS,
2463 clgen_pci_probe_list[i].device, pdev)) != NULL) {
2464 if (pci_enable_device(pdev) == 0) {
2465 *btype = clgen_pci_probe_list[i].btype;
2466 DPRINTK ("EXIT, returning pdev=%p\n", pdev);
2467 return pdev;
2472 DPRINTK ("EXIT, returning NULL\n");
2473 return NULL;
2479 static void __init get_pci_addrs (const struct pci_dev *pdev,
2480 unsigned long *display, unsigned long *registers)
2482 assert (pdev != NULL);
2483 assert (display != NULL);
2484 assert (registers != NULL);
2486 DPRINTK ("ENTER\n");
2488 *display = 0;
2489 *registers = 0;
2491 /* This is a best-guess for now */
2493 if (pci_resource_flags(pdev, 0) & IORESOURCE_IO) {
2494 *display = pci_resource_start(pdev, 1);
2495 *registers = pci_resource_start(pdev, 0);
2496 } else {
2497 *display = pci_resource_start(pdev, 0);
2498 *registers = pci_resource_start(pdev, 1);
2501 assert (*display != 0);
2503 DPRINTK ("EXIT\n");
2507 static void __exit clgen_pci_unmap (struct clgenfb_info *info)
2509 iounmap (info->fbmem);
2510 release_mem_region(info->fbmem_phys, info->size);
2512 #if 0 /* if system didn't claim this region, we would... */
2513 release_mem_region(0xA0000, 65535);
2514 #endif
2516 if (release_io_ports)
2517 release_region(0x3C0, 32);
2521 static int __init clgen_pci_setup (struct clgenfb_info *info,
2522 clgen_board_t *btype)
2524 struct pci_dev *pdev;
2525 unsigned long board_addr, board_size;
2527 DPRINTK ("ENTER\n");
2529 pdev = clgen_pci_dev_get (btype);
2530 if (!pdev) {
2531 printk (KERN_ERR " Couldn't find PCI device\n");
2532 DPRINTK ("EXIT, returning 1\n");
2533 return 1;
2535 DPRINTK (" Found PCI device, base address 0 is 0x%lx, btype set to %d\n",
2536 pdev->resource[0].start, *btype);
2537 DPRINTK (" base address 1 is 0x%lx\n", pdev->resource[1].start);
2539 info->pdev = pdev;
2541 if(isPReP) {
2542 /* Xbh does this, though 0 seems to be the init value */
2543 pcibios_write_config_dword (0, pdev->devfn, PCI_BASE_ADDRESS_0,
2544 0x00000000);
2546 #ifdef CONFIG_PPC_PREP
2547 get_prep_addrs (&board_addr, &info->fbregs_phys);
2548 #endif
2549 } else {
2550 DPRINTK ("Attempt to get PCI info for Cirrus Graphics Card\n");
2551 get_pci_addrs (pdev, &board_addr, &info->fbregs_phys);
2554 DPRINTK ("Board address: 0x%lx, register address: 0x%lx\n", board_addr, info->fbregs_phys);
2556 if(isPReP) {
2557 /* PReP dies if we ioremap the IO registers, but it works w/out... */
2558 info->regs = (char *) info->fbregs_phys;
2559 } else
2560 info->regs = 0; /* FIXME: this forces VGA. alternatives? */
2562 if (*btype == BT_GD5480) {
2563 board_size = 32 * MB_;
2564 } else {
2565 board_size = clgen_get_memsize (info->regs);
2568 if (!request_mem_region(board_addr, board_size, "clgenfb")) {
2569 printk(KERN_ERR "clgen: cannot reserve region 0x%lx, abort\n",
2570 board_addr);
2571 return -1;
2573 #if 0 /* if the system didn't claim this region, we would... */
2574 if (!request_mem_region(0xA0000, 65535, "clgenfb")) {
2575 printk(KERN_ERR "clgen: cannot reserve region 0x%lx, abort\n",
2576 0xA0000L);
2577 release_mem_region(board_addr, board_size);
2578 return -1;
2580 #endif
2581 if (request_region(0x3C0, 32, "clgenfb"))
2582 release_io_ports = 1;
2584 info->fbmem = ioremap (board_addr, board_size);
2585 info->fbmem_phys = board_addr;
2586 info->size = board_size;
2588 printk (" RAM (%lu kB) at 0x%lx, ", info->size / KB_, board_addr);
2590 printk ("Cirrus Logic chipset on PCI bus\n");
2592 DPRINTK ("EXIT, returning 0\n");
2593 return 0;
2595 #endif /* CONFIG_PCI */
2600 #ifdef CONFIG_ZORRO
2601 static int __init clgen_zorro_find (struct zorro_dev **z_o,
2602 struct zorro_dev **z2_o,
2603 clgen_board_t *btype, unsigned long *size)
2605 struct zorro_dev *z = NULL;
2606 int i;
2608 assert (z_o != NULL);
2609 assert (btype != NULL);
2611 for (i = 0; i < ARRAY_SIZE(clgen_zorro_probe_list); i++)
2612 if ((z = zorro_find_device(clgen_zorro_probe_list[i].id, NULL)))
2613 break;
2615 if (z) {
2616 *z_o = z;
2617 if (clgen_zorro_probe_list[i].id2)
2618 *z2_o = zorro_find_device(clgen_zorro_probe_list[i].id2, NULL);
2619 else
2620 *z2_o = NULL;
2622 *btype = clgen_zorro_probe_list[i].btype;
2623 *size = clgen_zorro_probe_list[i].size;
2625 printk (KERN_INFO "clgen: %s board detected; ",
2626 clgen_board_info[*btype].name);
2628 return 0;
2631 printk (KERN_NOTICE "clgen: no supported board found.\n");
2632 return -1;
2636 static void __exit clgen_zorro_unmap (struct clgenfb_info *info)
2638 release_mem_region(info->board_addr, info->board_size);
2640 if (info->btype == BT_PICASSO4) {
2641 iounmap ((void *)info->board_addr);
2642 iounmap ((void *)info->fbmem_phys);
2643 } else {
2644 if (info->board_addr > 0x01000000)
2645 iounmap ((void *)info->board_addr);
2650 static int __init clgen_zorro_setup (struct clgenfb_info *info,
2651 clgen_board_t *btype)
2653 struct zorro_dev *z = NULL, *z2 = NULL;
2654 unsigned long board_addr, board_size, size;
2656 assert (info != NULL);
2657 assert (btype != NULL);
2659 if (clgen_zorro_find (&z, &z2, btype, &size))
2660 return -1;
2662 assert (z > 0);
2663 assert (z2 >= 0);
2664 assert (*btype != BT_NONE);
2666 info->board_addr = board_addr = z->resource.start;
2667 info->board_size = board_size = z->resource.end-z->resource.start+1;
2668 info->size = size;
2670 if (!request_mem_region(board_addr, board_size, "clgenfb")) {
2671 printk(KERN_ERR "clgen: cannot reserve region 0x%lx, abort\n",
2672 board_addr);
2673 return -1;
2676 printk (" RAM (%lu MB) at $%lx, ", board_size / MB_, board_addr);
2678 if (*btype == BT_PICASSO4) {
2679 printk (" REG at $%lx\n", board_addr + 0x600000);
2681 /* To be precise, for the P4 this is not the */
2682 /* begin of the board, but the begin of RAM. */
2683 /* for P4, map in its address space in 2 chunks (### TEST! ) */
2684 /* (note the ugly hardcoded 16M number) */
2685 info->regs = ioremap (board_addr, 16777216);
2686 DPRINTK ("clgen: Virtual address for board set to: $%p\n", info->regs);
2687 info->regs += 0x600000;
2688 info->fbregs_phys = board_addr + 0x600000;
2690 info->fbmem_phys = board_addr + 16777216;
2691 info->fbmem = ioremap (info->fbmem_phys, 16777216);
2692 } else {
2693 printk (" REG at $%lx\n", (unsigned long) z2->resource.start);
2695 info->fbmem_phys = board_addr;
2696 if (board_addr > 0x01000000)
2697 info->fbmem = ioremap (board_addr, board_size);
2698 else
2699 info->fbmem = (caddr_t) ZTWO_VADDR (board_addr);
2701 /* set address for REG area of board */
2702 info->regs = (caddr_t) ZTWO_VADDR (z2->resource.start);
2703 info->fbregs_phys = z2->resource.start;
2705 DPRINTK ("clgen: Virtual address for board set to: $%p\n", info->regs);
2708 printk (KERN_INFO "Cirrus Logic chipset on Zorro bus\n");
2710 return 0;
2712 #endif /* CONFIG_ZORRO */
2716 /********************************************************************/
2717 /* clgenfb_init() - master initialization function */
2718 /********************************************************************/
2719 int __init clgenfb_init(void)
2721 int err, j, k;
2723 clgen_board_t btype = BT_NONE;
2724 struct clgenfb_info *fb_info = NULL;
2726 DPRINTK ("ENTER\n");
2728 printk (KERN_INFO "clgen: Driver for Cirrus Logic based graphic boards, v" CLGEN_VERSION "\n");
2730 fb_info = &boards[0]; /* FIXME support multiple boards ... */
2732 #ifdef CONFIG_PCI
2733 if (clgen_pci_setup (fb_info, &btype)) { /* Also does OF setup */
2734 DPRINTK ("EXIT, returning -ENXIO\n");
2735 return -ENXIO;
2738 #elif defined(CONFIG_ZORRO)
2739 /* FIXME: CONFIG_PCI and CONFIG_ZORRO may both be defined */
2740 if (clgen_zorro_setup (fb_info, &btype)) {
2741 DPRINTK ("EXIT, returning -ENXIO\n");
2742 return -ENXIO;
2745 #else
2746 #error This driver requires Zorro or PCI bus.
2747 #endif /* !CONFIG_PCI, !CONFIG_ZORRO */
2749 /* sanity checks */
2750 assert (btype != BT_NONE);
2751 assert (btype == clgen_board_info[btype].btype);
2753 fb_info->btype = btype;
2755 DPRINTK ("clgen: (RAM start set to: 0x%p)\n", fb_info->fbmem);
2757 if (noaccel)
2759 printk("clgen: disabling text acceleration support\n");
2760 #ifdef FBCON_HAS_CFB8
2761 fbcon_clgen_8.bmove = fbcon_cfb8_bmove;
2762 fbcon_clgen_8.clear = fbcon_cfb8_clear;
2763 #endif
2764 #ifdef FBCON_HAS_CFB16
2765 fbcon_clgen_16.bmove = fbcon_cfb16_bmove;
2766 fbcon_clgen_16.clear = fbcon_cfb16_clear;
2767 #endif
2768 #ifdef FBCON_HAS_CFB32
2769 fbcon_clgen_32.bmove = fbcon_cfb32_bmove;
2770 fbcon_clgen_32.clear = fbcon_cfb32_clear;
2771 #endif
2774 init_vgachip (fb_info);
2776 /* set up a few more things, register framebuffer driver etc */
2777 fb_info->gen.parsize = sizeof (struct clgenfb_par);
2778 fb_info->gen.fbhw = &clgen_hwswitch;
2780 strlcpy (fb_info->gen.info.modename, clgen_board_info[btype].name,
2781 sizeof (fb_info->gen.info.modename));
2783 fb_info->gen.info.fbops = &clgenfb_ops;
2784 fb_info->gen.info.disp = &disp;
2785 fb_info->gen.info.currcon = -1;
2786 fb_info->gen.info.changevar = NULL;
2787 fb_info->gen.info.switch_con = &fbgen_switch;
2788 fb_info->gen.info.updatevar = &fbgen_update_var;
2789 fb_info->gen.info.flags = FBINFO_FLAG_DEFAULT;
2791 for (j = 0; j < 256; j++) {
2792 if (j < 16) {
2793 k = color_table[j];
2794 fb_info->palette[j].red = default_red[k];
2795 fb_info->palette[j].green = default_grn[k];
2796 fb_info->palette[j].blue = default_blu[k];
2797 } else {
2798 fb_info->palette[j].red =
2799 fb_info->palette[j].green =
2800 fb_info->palette[j].blue = j;
2804 /* now that we know the board has been registered n' stuff, we */
2805 /* can finally initialize it to a default mode */
2806 clgenfb_default = clgenfb_predefined[clgen_def_mode].var;
2807 clgenfb_default.activate = FB_ACTIVATE_NOW;
2808 clgenfb_default.yres_virtual = 480 * 3; /* for fast scrolling (YPAN-Mode) */
2809 err = fbgen_do_set_var (&clgenfb_default, 1, &fb_info->gen);
2811 if (err) {
2812 DPRINTK ("EXIT, returning -EINVAL\n");
2813 return -EINVAL;
2816 disp.var = clgenfb_default;
2817 fbgen_set_disp (-1, &fb_info->gen);
2818 do_install_cmap (0, &fb_info->gen.info);
2820 err = register_framebuffer (&fb_info->gen.info);
2821 if (err) {
2822 printk (KERN_ERR "clgen: ERROR - could not register fb device; err = %d!\n", err);
2823 DPRINTK ("EXIT, returning -EINVAL\n");
2824 return -EINVAL;
2826 DPRINTK ("EXIT, returning 0\n");
2827 return 0;
2833 * Cleanup (only needed for module)
2835 static void __exit clgenfb_cleanup (struct clgenfb_info *info)
2837 DPRINTK ("ENTER\n");
2839 #ifdef CONFIG_ZORRO
2840 switch_monitor (info, 0);
2842 clgen_zorro_unmap (info);
2843 #else
2844 clgen_pci_unmap (info);
2845 #endif /* CONFIG_ZORRO */
2847 unregister_framebuffer ((struct fb_info *) info);
2848 printk ("Framebuffer unregistered\n");
2850 DPRINTK ("EXIT\n");
2854 #ifndef MODULE
2855 int __init clgenfb_setup(char *options) {
2856 char *this_opt, s[32];
2857 int i;
2859 DPRINTK ("ENTER\n");
2861 if (!options || !*options)
2862 return 0;
2864 while ((this_opt = strsep (&options, ",")) != NULL) {
2865 if (!*this_opt) continue;
2867 DPRINTK("clgenfb_setup: option '%s'\n", this_opt);
2869 for (i = 0; i < NUM_TOTAL_MODES; i++) {
2870 sprintf (s, "mode:%s", clgenfb_predefined[i].name);
2871 if (strcmp (this_opt, s) == 0)
2872 clgen_def_mode = i;
2874 if (!strcmp(this_opt, "noaccel"))
2875 noaccel = 1;
2877 return 0;
2879 #endif
2883 * Modularization
2886 MODULE_AUTHOR("Copyright 1999,2000 Jeff Garzik <jgarzik@pobox.com>");
2887 MODULE_DESCRIPTION("Accelerated FBDev driver for Cirrus Logic chips");
2888 MODULE_LICENSE("GPL");
2890 static void __exit clgenfb_exit (void)
2892 DPRINTK ("ENTER\n");
2894 clgenfb_cleanup (&boards[0]); /* FIXME: support multiple boards */
2896 DPRINTK ("EXIT\n");
2899 #ifdef MODULE
2900 module_init(clgenfb_init);
2901 #endif
2902 module_exit(clgenfb_exit);
2905 /**********************************************************************/
2906 /* about the following functions - I have used the same names for the */
2907 /* functions as Markus Wild did in his Retina driver for NetBSD as */
2908 /* they just made sense for this purpose. Apart from that, I wrote */
2909 /* these functions myself. */
2910 /**********************************************************************/
2912 /*** WGen() - write into one of the external/general registers ***/
2913 static void WGen (const struct clgenfb_info *fb_info,
2914 int regnum, unsigned char val)
2916 unsigned long regofs = 0;
2918 if (fb_info->btype == BT_PICASSO) {
2919 /* Picasso II specific hack */
2920 /* if (regnum == VGA_PEL_IR || regnum == VGA_PEL_D || regnum == CL_VSSM2) */
2921 if (regnum == VGA_PEL_IR || regnum == VGA_PEL_D)
2922 regofs = 0xfff;
2925 vga_w (fb_info->regs, regofs + regnum, val);
2928 /*** RGen() - read out one of the external/general registers ***/
2929 static unsigned char RGen (const struct clgenfb_info *fb_info, int regnum)
2931 unsigned long regofs = 0;
2933 if (fb_info->btype == BT_PICASSO) {
2934 /* Picasso II specific hack */
2935 /* if (regnum == VGA_PEL_IR || regnum == VGA_PEL_D || regnum == CL_VSSM2) */
2936 if (regnum == VGA_PEL_IR || regnum == VGA_PEL_D)
2937 regofs = 0xfff;
2940 return vga_r (fb_info->regs, regofs + regnum);
2943 /*** AttrOn() - turn on VideoEnable for Attribute controller ***/
2944 static void AttrOn (const struct clgenfb_info *fb_info)
2946 assert (fb_info != NULL);
2948 DPRINTK ("ENTER\n");
2950 if (vga_rcrt (fb_info->regs, CL_CRT24) & 0x80) {
2951 /* if we're just in "write value" mode, write back the */
2952 /* same value as before to not modify anything */
2953 vga_w (fb_info->regs, VGA_ATT_IW,
2954 vga_r (fb_info->regs, VGA_ATT_R));
2956 /* turn on video bit */
2957 /* vga_w (fb_info->regs, VGA_ATT_IW, 0x20); */
2958 vga_w (fb_info->regs, VGA_ATT_IW, 0x33);
2960 /* dummy write on Reg0 to be on "write index" mode next time */
2961 vga_w (fb_info->regs, VGA_ATT_IW, 0x00);
2963 DPRINTK ("EXIT\n");
2966 /*** WHDR() - write into the Hidden DAC register ***/
2967 /* as the HDR is the only extension register that requires special treatment
2968 * (the other extension registers are accessible just like the "ordinary"
2969 * registers of their functional group) here is a specialized routine for
2970 * accessing the HDR
2972 static void WHDR (const struct clgenfb_info *fb_info, unsigned char val)
2974 unsigned char dummy;
2976 if (fb_info->btype == BT_PICASSO) {
2977 /* Klaus' hint for correct access to HDR on some boards */
2978 /* first write 0 to pixel mask (3c6) */
2979 WGen (fb_info, VGA_PEL_MSK, 0x00);
2980 udelay (200);
2981 /* next read dummy from pixel address (3c8) */
2982 dummy = RGen (fb_info, VGA_PEL_IW);
2983 udelay (200);
2985 /* now do the usual stuff to access the HDR */
2987 dummy = RGen (fb_info, VGA_PEL_MSK);
2988 udelay (200);
2989 dummy = RGen (fb_info, VGA_PEL_MSK);
2990 udelay (200);
2991 dummy = RGen (fb_info, VGA_PEL_MSK);
2992 udelay (200);
2993 dummy = RGen (fb_info, VGA_PEL_MSK);
2994 udelay (200);
2996 WGen (fb_info, VGA_PEL_MSK, val);
2997 udelay (200);
2999 if (fb_info->btype == BT_PICASSO) {
3000 /* now first reset HDR access counter */
3001 dummy = RGen (fb_info, VGA_PEL_IW);
3002 udelay (200);
3004 /* and at the end, restore the mask value */
3005 /* ## is this mask always 0xff? */
3006 WGen (fb_info, VGA_PEL_MSK, 0xff);
3007 udelay (200);
3012 /*** WSFR() - write to the "special function register" (SFR) ***/
3013 static void WSFR (struct clgenfb_info *fb_info, unsigned char val)
3015 #ifdef CONFIG_ZORRO
3016 assert (fb_info->regs != NULL);
3017 fb_info->SFR = val;
3018 z_writeb (val, fb_info->regs + 0x8000);
3019 #endif
3022 /* The Picasso has a second register for switching the monitor bit */
3023 static void WSFR2 (struct clgenfb_info *fb_info, unsigned char val)
3025 #ifdef CONFIG_ZORRO
3026 /* writing an arbitrary value to this one causes the monitor switcher */
3027 /* to flip to Amiga display */
3028 assert (fb_info->regs != NULL);
3029 fb_info->SFR = val;
3030 z_writeb (val, fb_info->regs + 0x9000);
3031 #endif
3035 /*** WClut - set CLUT entry (range: 0..63) ***/
3036 static void WClut (struct clgenfb_info *fb_info, unsigned char regnum, unsigned char red,
3037 unsigned char green, unsigned char blue)
3039 unsigned int data = VGA_PEL_D;
3041 /* address write mode register is not translated.. */
3042 vga_w (fb_info->regs, VGA_PEL_IW, regnum);
3044 if (fb_info->btype == BT_PICASSO || fb_info->btype == BT_PICASSO4 ||
3045 fb_info->btype == BT_ALPINE || fb_info->btype == BT_GD5480) {
3046 /* but DAC data register IS, at least for Picasso II */
3047 if (fb_info->btype == BT_PICASSO)
3048 data += 0xfff;
3049 vga_w (fb_info->regs, data, red);
3050 vga_w (fb_info->regs, data, green);
3051 vga_w (fb_info->regs, data, blue);
3052 } else {
3053 vga_w (fb_info->regs, data, blue);
3054 vga_w (fb_info->regs, data, green);
3055 vga_w (fb_info->regs, data, red);
3060 #if 0
3061 /*** RClut - read CLUT entry (range 0..63) ***/
3062 static void RClut (struct clgenfb_info *fb_info, unsigned char regnum, unsigned char *red,
3063 unsigned char *green, unsigned char *blue)
3065 unsigned int data = VGA_PEL_D;
3067 vga_w (fb_info->regs, VGA_PEL_IR, regnum);
3069 if (fb_info->btype == BT_PICASSO || fb_info->btype == BT_PICASSO4 ||
3070 fb_info->btype == BT_ALPINE || fb_info->btype == BT_GD5480) {
3071 if (fb_info->btype == BT_PICASSO)
3072 data += 0xfff;
3073 *red = vga_r (fb_info->regs, data);
3074 *green = vga_r (fb_info->regs, data);
3075 *blue = vga_r (fb_info->regs, data);
3076 } else {
3077 *blue = vga_r (fb_info->regs, data);
3078 *green = vga_r (fb_info->regs, data);
3079 *red = vga_r (fb_info->regs, data);
3082 #endif
3085 /*******************************************************************
3086 clgen_WaitBLT()
3088 Wait for the BitBLT engine to complete a possible earlier job
3089 *********************************************************************/
3091 /* FIXME: use interrupts instead */
3092 extern inline void clgen_WaitBLT (caddr_t regbase)
3094 /* now busy-wait until we're done */
3095 while (vga_rgfx (regbase, CL_GR31) & 0x08)
3096 /* do nothing */ ;
3099 /*******************************************************************
3100 clgen_BitBLT()
3102 perform accelerated "scrolling"
3103 ********************************************************************/
3105 static void clgen_BitBLT (caddr_t regbase, u_short curx, u_short cury, u_short destx, u_short desty,
3106 u_short width, u_short height, u_short line_length)
3108 u_short nwidth, nheight;
3109 u_long nsrc, ndest;
3110 u_char bltmode;
3112 DPRINTK ("ENTER\n");
3114 nwidth = width - 1;
3115 nheight = height - 1;
3117 bltmode = 0x00;
3118 /* if source adr < dest addr, do the Blt backwards */
3119 if (cury <= desty) {
3120 if (cury == desty) {
3121 /* if src and dest are on the same line, check x */
3122 if (curx < destx)
3123 bltmode |= 0x01;
3124 } else
3125 bltmode |= 0x01;
3127 if (!bltmode) {
3128 /* standard case: forward blitting */
3129 nsrc = (cury * line_length) + curx;
3130 ndest = (desty * line_length) + destx;
3131 } else {
3132 /* this means start addresses are at the end, counting backwards */
3133 nsrc = cury * line_length + curx + nheight * line_length + nwidth;
3134 ndest = desty * line_length + destx + nheight * line_length + nwidth;
3137 clgen_WaitBLT(regbase);
3140 run-down of registers to be programmed:
3141 destination pitch
3142 source pitch
3143 BLT width/height
3144 source start
3145 destination start
3146 BLT mode
3147 BLT ROP
3148 VGA_GFX_SR_VALUE / VGA_GFX_SR_ENABLE: "fill color"
3149 start/stop
3152 /* pitch: set to line_length */
3153 vga_wgfx (regbase, CL_GR24, line_length & 0xff); /* dest pitch low */
3154 vga_wgfx (regbase, CL_GR25, (line_length >> 8)); /* dest pitch hi */
3155 vga_wgfx (regbase, CL_GR26, line_length & 0xff); /* source pitch low */
3156 vga_wgfx (regbase, CL_GR27, (line_length >> 8)); /* source pitch hi */
3158 /* BLT width: actual number of pixels - 1 */
3159 vga_wgfx (regbase, CL_GR20, nwidth & 0xff); /* BLT width low */
3160 vga_wgfx (regbase, CL_GR21, (nwidth >> 8)); /* BLT width hi */
3162 /* BLT height: actual number of lines -1 */
3163 vga_wgfx (regbase, CL_GR22, nheight & 0xff); /* BLT height low */
3164 vga_wgfx (regbase, CL_GR23, (nheight >> 8)); /* BLT width hi */
3166 /* BLT destination */
3167 vga_wgfx (regbase, CL_GR28, (u_char) (ndest & 0xff)); /* BLT dest low */
3168 vga_wgfx (regbase, CL_GR29, (u_char) (ndest >> 8)); /* BLT dest mid */
3169 vga_wgfx (regbase, CL_GR2A, (u_char) (ndest >> 16)); /* BLT dest hi */
3171 /* BLT source */
3172 vga_wgfx (regbase, CL_GR2C, (u_char) (nsrc & 0xff)); /* BLT src low */
3173 vga_wgfx (regbase, CL_GR2D, (u_char) (nsrc >> 8)); /* BLT src mid */
3174 vga_wgfx (regbase, CL_GR2E, (u_char) (nsrc >> 16)); /* BLT src hi */
3176 /* BLT mode */
3177 vga_wgfx (regbase, CL_GR30, bltmode); /* BLT mode */
3179 /* BLT ROP: SrcCopy */
3180 vga_wgfx (regbase, CL_GR32, 0x0d); /* BLT ROP */
3182 /* and finally: GO! */
3183 vga_wgfx (regbase, CL_GR31, 0x02); /* BLT Start/status */
3185 DPRINTK ("EXIT\n");
3189 /*******************************************************************
3190 clgen_RectFill()
3192 perform accelerated rectangle fill
3193 ********************************************************************/
3195 static void clgen_RectFill (struct clgenfb_info *fb_info,
3196 u_short x, u_short y, u_short width, u_short height,
3197 u_char color, u_short line_length)
3199 u_short nwidth, nheight;
3200 u_long ndest;
3201 u_char op;
3203 DPRINTK ("ENTER\n");
3205 nwidth = width - 1;
3206 nheight = height - 1;
3208 ndest = (y * line_length) + x;
3210 clgen_WaitBLT(fb_info->regs);
3212 /* pitch: set to line_length */
3213 vga_wgfx (fb_info->regs, CL_GR24, line_length & 0xff); /* dest pitch low */
3214 vga_wgfx (fb_info->regs, CL_GR25, (line_length >> 8)); /* dest pitch hi */
3215 vga_wgfx (fb_info->regs, CL_GR26, line_length & 0xff); /* source pitch low */
3216 vga_wgfx (fb_info->regs, CL_GR27, (line_length >> 8)); /* source pitch hi */
3218 /* BLT width: actual number of pixels - 1 */
3219 vga_wgfx (fb_info->regs, CL_GR20, nwidth & 0xff); /* BLT width low */
3220 vga_wgfx (fb_info->regs, CL_GR21, (nwidth >> 8)); /* BLT width hi */
3222 /* BLT height: actual number of lines -1 */
3223 vga_wgfx (fb_info->regs, CL_GR22, nheight & 0xff); /* BLT height low */
3224 vga_wgfx (fb_info->regs, CL_GR23, (nheight >> 8)); /* BLT width hi */
3226 /* BLT destination */
3227 vga_wgfx (fb_info->regs, CL_GR28, (u_char) (ndest & 0xff)); /* BLT dest low */
3228 vga_wgfx (fb_info->regs, CL_GR29, (u_char) (ndest >> 8)); /* BLT dest mid */
3229 vga_wgfx (fb_info->regs, CL_GR2A, (u_char) (ndest >> 16)); /* BLT dest hi */
3231 /* BLT source: set to 0 (is a dummy here anyway) */
3232 vga_wgfx (fb_info->regs, CL_GR2C, 0x00); /* BLT src low */
3233 vga_wgfx (fb_info->regs, CL_GR2D, 0x00); /* BLT src mid */
3234 vga_wgfx (fb_info->regs, CL_GR2E, 0x00); /* BLT src hi */
3236 /* This is a ColorExpand Blt, using the */
3237 /* same color for foreground and background */
3238 vga_wgfx (fb_info->regs, VGA_GFX_SR_VALUE, color); /* foreground color */
3239 vga_wgfx (fb_info->regs, VGA_GFX_SR_ENABLE, color); /* background color */
3241 op = 0xc0;
3242 if (fb_info->currentmode.var.bits_per_pixel == 16) {
3243 vga_wgfx (fb_info->regs, CL_GR10, color); /* foreground color */
3244 vga_wgfx (fb_info->regs, CL_GR11, color); /* background color */
3245 op = 0x50;
3246 op = 0xd0;
3247 } else if (fb_info->currentmode.var.bits_per_pixel == 32) {
3248 vga_wgfx (fb_info->regs, CL_GR10, color); /* foreground color */
3249 vga_wgfx (fb_info->regs, CL_GR11, color); /* background color */
3250 vga_wgfx (fb_info->regs, CL_GR12, color); /* foreground color */
3251 vga_wgfx (fb_info->regs, CL_GR13, color); /* background color */
3252 vga_wgfx (fb_info->regs, CL_GR14, 0); /* foreground color */
3253 vga_wgfx (fb_info->regs, CL_GR15, 0); /* background color */
3254 op = 0x50;
3255 op = 0xf0;
3257 /* BLT mode: color expand, Enable 8x8 copy (faster?) */
3258 vga_wgfx (fb_info->regs, CL_GR30, op); /* BLT mode */
3260 /* BLT ROP: SrcCopy */
3261 vga_wgfx (fb_info->regs, CL_GR32, 0x0d); /* BLT ROP */
3263 /* and finally: GO! */
3264 vga_wgfx (fb_info->regs, CL_GR31, 0x02); /* BLT Start/status */
3266 DPRINTK ("EXIT\n");
3270 /**************************************************************************
3271 * bestclock() - determine closest possible clock lower(?) than the
3272 * desired pixel clock
3273 **************************************************************************/
3274 static void bestclock (long freq, long *best, long *nom,
3275 long *den, long *div, long maxfreq)
3277 long n, h, d, f;
3279 assert (best != NULL);
3280 assert (nom != NULL);
3281 assert (den != NULL);
3282 assert (div != NULL);
3283 assert (maxfreq > 0);
3285 *nom = 0;
3286 *den = 0;
3287 *div = 0;
3289 DPRINTK ("ENTER\n");
3291 if (freq < 8000)
3292 freq = 8000;
3294 if (freq > maxfreq)
3295 freq = maxfreq;
3297 *best = 0;
3298 f = freq * 10;
3300 for (n = 32; n < 128; n++) {
3301 d = (143181 * n) / f;
3302 if ((d >= 7) && (d <= 63)) {
3303 if (d > 31)
3304 d = (d / 2) * 2;
3305 h = (14318 * n) / d;
3306 if (abs (h - freq) < abs (*best - freq)) {
3307 *best = h;
3308 *nom = n;
3309 if (d < 32) {
3310 *den = d;
3311 *div = 0;
3312 } else {
3313 *den = d / 2;
3314 *div = 1;
3318 d = ((143181 * n) + f - 1) / f;
3319 if ((d >= 7) && (d <= 63)) {
3320 if (d > 31)
3321 d = (d / 2) * 2;
3322 h = (14318 * n) / d;
3323 if (abs (h - freq) < abs (*best - freq)) {
3324 *best = h;
3325 *nom = n;
3326 if (d < 32) {
3327 *den = d;
3328 *div = 0;
3329 } else {
3330 *den = d / 2;
3331 *div = 1;
3337 DPRINTK ("Best possible values for given frequency:\n");
3338 DPRINTK (" best: %ld kHz nom: %ld den: %ld div: %ld\n",
3339 freq, *nom, *den, *div);
3341 DPRINTK ("EXIT\n");
3345 /* -------------------------------------------------------------------------
3347 * debugging functions
3349 * -------------------------------------------------------------------------
3352 #ifdef CLGEN_DEBUG
3355 * clgen_dbg_print_byte
3356 * @name: name associated with byte value to be displayed
3357 * @val: byte value to be displayed
3359 * DESCRIPTION:
3360 * Display an indented string, along with a hexidecimal byte value, and
3361 * its decoded bits. Bits 7 through 0 are listed in left-to-right
3362 * order.
3365 static
3366 void clgen_dbg_print_byte (const char *name, unsigned char val)
3368 DPRINTK ("%8s = 0x%02X (bits 7-0: %c%c%c%c%c%c%c%c)\n",
3369 name, val,
3370 val & 0x80 ? '1' : '0',
3371 val & 0x40 ? '1' : '0',
3372 val & 0x20 ? '1' : '0',
3373 val & 0x10 ? '1' : '0',
3374 val & 0x08 ? '1' : '0',
3375 val & 0x04 ? '1' : '0',
3376 val & 0x02 ? '1' : '0',
3377 val & 0x01 ? '1' : '0');
3382 * clgen_dbg_print_regs
3383 * @base: If using newmmio, the newmmio base address, otherwise %NULL
3384 * @reg_class: type of registers to read: %CRT, or %SEQ
3386 * DESCRIPTION:
3387 * Dumps the given list of VGA CRTC registers. If @base is %NULL,
3388 * old-style I/O ports are queried for information, otherwise MMIO is
3389 * used at the given @base address to query the information.
3392 static
3393 void clgen_dbg_print_regs (caddr_t regbase, clgen_dbg_reg_class_t reg_class,...)
3395 va_list list;
3396 unsigned char val = 0;
3397 unsigned reg;
3398 char *name;
3400 va_start (list, reg_class);
3402 name = va_arg (list, char *);
3403 while (name != NULL) {
3404 reg = va_arg (list, int);
3406 switch (reg_class) {
3407 case CRT:
3408 val = vga_rcrt (regbase, (unsigned char) reg);
3409 break;
3410 case SEQ:
3411 val = vga_rseq (regbase, (unsigned char) reg);
3412 break;
3413 default:
3414 /* should never occur */
3415 assert (FALSE);
3416 break;
3419 clgen_dbg_print_byte (name, val);
3421 name = va_arg (list, char *);
3424 va_end (list);
3429 * clgen_dump
3430 * @clgeninfo:
3432 * DESCRIPTION:
3435 static
3436 void clgen_dump (void)
3438 clgen_dbg_reg_dump (NULL);
3443 * clgen_dbg_reg_dump
3444 * @base: If using newmmio, the newmmio base address, otherwise %NULL
3446 * DESCRIPTION:
3447 * Dumps a list of interesting VGA and CLGEN registers. If @base is %NULL,
3448 * old-style I/O ports are queried for information, otherwise MMIO is
3449 * used at the given @base address to query the information.
3452 static
3453 void clgen_dbg_reg_dump (caddr_t regbase)
3455 DPRINTK ("CLGEN VGA CRTC register dump:\n");
3457 clgen_dbg_print_regs (regbase, CRT,
3458 "CR00", 0x00,
3459 "CR01", 0x01,
3460 "CR02", 0x02,
3461 "CR03", 0x03,
3462 "CR04", 0x04,
3463 "CR05", 0x05,
3464 "CR06", 0x06,
3465 "CR07", 0x07,
3466 "CR08", 0x08,
3467 "CR09", 0x09,
3468 "CR0A", 0x0A,
3469 "CR0B", 0x0B,
3470 "CR0C", 0x0C,
3471 "CR0D", 0x0D,
3472 "CR0E", 0x0E,
3473 "CR0F", 0x0F,
3474 "CR10", 0x10,
3475 "CR11", 0x11,
3476 "CR12", 0x12,
3477 "CR13", 0x13,
3478 "CR14", 0x14,
3479 "CR15", 0x15,
3480 "CR16", 0x16,
3481 "CR17", 0x17,
3482 "CR18", 0x18,
3483 "CR22", 0x22,
3484 "CR24", 0x24,
3485 "CR26", 0x26,
3486 "CR2D", 0x2D,
3487 "CR2E", 0x2E,
3488 "CR2F", 0x2F,
3489 "CR30", 0x30,
3490 "CR31", 0x31,
3491 "CR32", 0x32,
3492 "CR33", 0x33,
3493 "CR34", 0x34,
3494 "CR35", 0x35,
3495 "CR36", 0x36,
3496 "CR37", 0x37,
3497 "CR38", 0x38,
3498 "CR39", 0x39,
3499 "CR3A", 0x3A,
3500 "CR3B", 0x3B,
3501 "CR3C", 0x3C,
3502 "CR3D", 0x3D,
3503 "CR3E", 0x3E,
3504 "CR3F", 0x3F,
3505 NULL);
3507 DPRINTK ("\n");
3509 DPRINTK ("CLGEN VGA SEQ register dump:\n");
3511 clgen_dbg_print_regs (regbase, SEQ,
3512 "SR00", 0x00,
3513 "SR01", 0x01,
3514 "SR02", 0x02,
3515 "SR03", 0x03,
3516 "SR04", 0x04,
3517 "SR08", 0x08,
3518 "SR09", 0x09,
3519 "SR0A", 0x0A,
3520 "SR0B", 0x0B,
3521 "SR0D", 0x0D,
3522 "SR10", 0x10,
3523 "SR11", 0x11,
3524 "SR12", 0x12,
3525 "SR13", 0x13,
3526 "SR14", 0x14,
3527 "SR15", 0x15,
3528 "SR16", 0x16,
3529 "SR17", 0x17,
3530 "SR18", 0x18,
3531 "SR19", 0x19,
3532 "SR1A", 0x1A,
3533 "SR1B", 0x1B,
3534 "SR1C", 0x1C,
3535 "SR1D", 0x1D,
3536 "SR1E", 0x1E,
3537 "SR1F", 0x1F,
3538 NULL);
3540 DPRINTK ("\n");
3543 #endif /* CLGEN_DEBUG */