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