2 * drivers/video/clgenfb.c - driver for Cirrus Logic chipsets
4 * Copyright 1999-2001 Jeff Garzik <jgarzik@pobox.com>
6 * Contributors (thanks, all!)
9 * Major contributions; Motorola PowerStack (PPC and PCI) support,
10 * GD54xx, 1280x1024 mode support, change MCLK based on VCLK.
13 * Excellent code review.
16 * Amiga updates and testing.
18 * Original clgenfb author: Frank Neumann
20 * Based on retz3fb.c and clgen.c:
21 * Copyright (C) 1997 Jes Sorensen
22 * Copyright (C) 1996 Frank Neumann
24 ***************************************************************
26 * Format this code with GNU indent '-kr -i8 -pcs' options.
28 * This file is subject to the terms and conditions of the GNU General Public
29 * License. See the file COPYING in the main directory of this archive
34 #define CLGEN_VERSION "1.9.9.1"
36 #include <linux/config.h>
37 #include <linux/module.h>
38 #include <linux/kernel.h>
39 #include <linux/errno.h>
40 #include <linux/string.h>
42 #include <linux/tty.h>
43 #include <linux/slab.h>
44 #include <linux/delay.h>
46 #include <linux/init.h>
47 #include <linux/selection.h>
48 #include <asm/pgtable.h>
51 #include <linux/zorro.h>
54 #include <linux/pci.h>
57 #include <asm/amigahw.h>
59 #ifdef CONFIG_PPC_PREP
60 #include <asm/processor.h>
61 #define isPReP (_machine == _MACH_prep)
66 #include <video/fbcon.h>
67 #include <video/fbcon-mfb.h>
68 #include <video/fbcon-cfb8.h>
69 #include <video/fbcon-cfb16.h>
70 #include <video/fbcon-cfb24.h>
71 #include <video/fbcon-cfb32.h>
77 /*****************************************************************
79 * debugging and utility macros
83 /* enable debug output? */
84 /* #define CLGEN_DEBUG 1 */
86 /* disable runtime assertions? */
87 /* #define CLGEN_NDEBUG */
91 #define DPRINTK(fmt, args...) printk(KERN_DEBUG "%s: " fmt, __FUNCTION__ , ## args)
93 #define DPRINTK(fmt, args...)
96 /* debugging assertions */
98 #define assert(expr) \
100 printk( "Assertion failed! %s,%s,%s,line=%d\n",\
101 #expr,__FILE__,__FUNCTION__,__LINE__); \
116 #define MB_ (1024*1024)
119 #define MAX_NUM_BOARDS 7
122 /*****************************************************************
124 * chipset information
135 BT_PICASSO4
, /* GD5446 */
136 BT_ALPINE
, /* GD543x/4x */
138 BT_LAGUNA
, /* GD546x */
143 * per-board-type information, used for enumerating and abstracting
144 * chip-specific information
145 * NOTE: MUST be in the same order as clgen_board_t in order to
146 * use direct indexing on this array
147 * NOTE: '__initdata' cannot be used as some of this info
148 * is required at runtime. Maybe separate into an init-only and
151 static const struct clgen_board_info_rec
{
152 clgen_board_t btype
; /* chipset enum, not strictly necessary, as
153 * clgen_board_info[] is directly indexed
155 char *name
; /* ASCII name of chipset */
156 long maxclock
; /* maximum video clock */
157 unsigned init_sr07
: 1; /* init SR07 during init_vgachip() */
158 unsigned init_sr1f
: 1; /* write SR1F during init_vgachip() */
159 unsigned scrn_start_bit19
: 1; /* construct bit 19 of screen start address */
161 /* initial SR07 value, then for each mode */
163 unsigned char sr07_1bpp
;
164 unsigned char sr07_1bpp_mux
;
165 unsigned char sr07_8bpp
;
166 unsigned char sr07_8bpp_mux
;
168 unsigned char sr1f
; /* SR1F VGA initial register value */
169 } clgen_board_info
[] = {
170 { BT_NONE
, }, /* dummy record */
173 140000, /* the SD64/P4 have a higher max. videoclock */
179 0, /* unused, does not multiplex */
181 0, /* unused, does not multiplex */
191 0, /* unused, does not multiplex */
193 0, /* unused, does not multiplex */
203 0, /* unused, does not multiplex */
205 0, /* unused, does not multiplex */
215 0, /* unused, does not multiplex */
217 0, /* unused, does not multiplex */
221 140000, /* the SD64/P4 have a higher max. videoclock */
227 0, /* unused, does not multiplex */
229 0, /* unused, does not multiplex */
233 110000, /* 135100 for some, 85500 for others */
251 0, /* unused, does not multiplex */
253 0, /* unused, does not multiplex */
271 /* the list of PCI devices for which we probe, and the
272 * order in which we do it */
273 static const struct {
275 const char *nameOverride
; /* XXX unused... for now */
276 unsigned short device
;
277 } clgen_pci_probe_list
[] __initdata
= {
278 { BT_ALPINE
, NULL
, PCI_DEVICE_ID_CIRRUS_5436
},
279 { BT_ALPINE
, NULL
, PCI_DEVICE_ID_CIRRUS_5434_8
},
280 { BT_ALPINE
, NULL
, PCI_DEVICE_ID_CIRRUS_5434_4
},
281 { BT_ALPINE
, NULL
, PCI_DEVICE_ID_CIRRUS_5430
}, /* GD-5440 has identical id */
282 { BT_ALPINE
, NULL
, PCI_DEVICE_ID_CIRRUS_7543
},
283 { BT_ALPINE
, NULL
, PCI_DEVICE_ID_CIRRUS_7548
},
284 { BT_GD5480
, NULL
, PCI_DEVICE_ID_CIRRUS_5480
}, /* MacPicasso probably */
285 { BT_PICASSO4
, NULL
, PCI_DEVICE_ID_CIRRUS_5446
}, /* Picasso 4 is a GD5446 */
286 { BT_LAGUNA
, "CL Laguna", PCI_DEVICE_ID_CIRRUS_5462
},
287 { BT_LAGUNA
, "CL Laguna 3D", PCI_DEVICE_ID_CIRRUS_5464
},
288 { BT_LAGUNA
, "CL Laguna 3DA", PCI_DEVICE_ID_CIRRUS_5465
},
290 #endif /* CONFIG_PCI */
294 static const struct {
298 } clgen_zorro_probe_list
[] __initdata
= {
300 ZORRO_PROD_HELFRICH_SD64_RAM
,
301 ZORRO_PROD_HELFRICH_SD64_REG
,
304 ZORRO_PROD_HELFRICH_PICCOLO_RAM
,
305 ZORRO_PROD_HELFRICH_PICCOLO_REG
,
308 ZORRO_PROD_VILLAGE_TRONIC_PICASSO_II_II_PLUS_RAM
,
309 ZORRO_PROD_VILLAGE_TRONIC_PICASSO_II_II_PLUS_REG
,
312 ZORRO_PROD_GVP_EGS_28_24_SPECTRUM_RAM
,
313 ZORRO_PROD_GVP_EGS_28_24_SPECTRUM_REG
,
316 ZORRO_PROD_VILLAGE_TRONIC_PICASSO_IV_Z3
,
320 #endif /* CONFIG_ZORRO */
325 struct fb_var_screeninfo var
;
327 __u32 line_length
; /* in BYTES! */
339 long HorizRes
; /* The x resolution in pixel */
342 long HorizBlankStart
;
347 long VertRes
; /* the physical y resolution in scanlines */
362 } clgen_dbg_reg_class_t
;
363 #endif /* CLGEN_DEBUG */
368 /* info about board */
369 struct clgenfb_info
{
370 struct fb_info_gen gen
;
378 unsigned char SFR
; /* Shadow of special function register */
380 unsigned long fbmem_phys
;
381 unsigned long fbregs_phys
;
383 struct clgenfb_par currentmode
;
385 struct { u8 red
, green
, blue
, pad
; } palette
[256];
388 #ifdef FBCON_HAS_CFB16
391 #ifdef FBCON_HAS_CFB24
394 #ifdef FBCON_HAS_CFB32
400 unsigned long board_addr
,
405 struct pci_dev
*pdev
;
412 static struct display disp
;
414 static struct clgenfb_info boards
[MAX_NUM_BOARDS
]; /* the boards */
416 static unsigned clgen_def_mode
= 1;
417 static int noaccel
= 0;
422 * Predefined Video Modes
425 static const struct {
427 struct fb_var_screeninfo var
;
428 } clgenfb_predefined
[] __initdata
=
431 {"Autodetect", /* autodetect mode */
435 {"640x480", /* 640x480, 31.25 kHz, 60 Hz, 25 MHz PixClock */
437 640, 480, 640, 480, 0, 0, 8, 0,
442 0, 0, -1, -1, FB_ACCEL_NONE
, 40000, 48, 16, 32, 8, 96, 4,
443 FB_SYNC_HOR_HIGH_ACT
| FB_SYNC_VERT_HIGH_ACT
, FB_VMODE_NONINTERLACED
447 {"800x600", /* 800x600, 48 kHz, 76 Hz, 50 MHz PixClock */
449 800, 600, 800, 600, 0, 0, 8, 0,
454 0, 0, -1, -1, FB_ACCEL_NONE
, 20000, 128, 16, 24, 2, 96, 6,
455 0, FB_VMODE_NONINTERLACED
460 Modeline from XF86Config:
461 Mode "1024x768" 80 1024 1136 1340 1432 768 770 774 805
463 {"1024x768", /* 1024x768, 55.8 kHz, 70 Hz, 80 MHz PixClock */
465 1024, 768, 1024, 768, 0, 0, 8, 0,
470 0, 0, -1, -1, FB_ACCEL_NONE
, 12500, 144, 32, 30, 2, 192, 6,
471 0, FB_VMODE_NONINTERLACED
476 #define NUM_TOTAL_MODES ARRAY_SIZE(clgenfb_predefined)
477 static struct fb_var_screeninfo clgenfb_default
;
483 static const char *clgenfb_name
= "CLgen";
485 /****************************************************************************/
486 /**** BEGIN PROTOTYPES ******************************************************/
489 /*--- Interface used by the world ------------------------------------------*/
490 int clgenfb_init (void);
491 int clgenfb_setup (char *options
);
493 static int clgenfb_open (struct fb_info
*info
, int user
);
494 static int clgenfb_release (struct fb_info
*info
, int user
);
496 static int clgenfb_setcolreg (unsigned regno
, unsigned red
, unsigned green
,
497 unsigned blue
, unsigned transp
,
498 struct fb_info
*info
);
500 /* function table of the above functions */
501 static struct fb_ops clgenfb_ops
= {
502 .owner
= THIS_MODULE
,
503 .fb_open
= clgenfb_open
,
504 .fb_release
= clgenfb_release
,
505 .fb_get_fix
= fbgen_get_fix
,
506 .fb_get_var
= fbgen_get_var
,
507 .fb_set_var
= fbgen_set_var
,
508 .fb_get_cmap
= fbgen_get_cmap
,
509 .fb_set_cmap
= gen_set_cmap
,
510 .fb_setcolreg
= clgenfb_setcolreg
,
511 .fb_pan_display
=fbgen_pan_display
,
512 .fb_blank
= fbgen_blank
,
515 /*--- Hardware Specific Routines -------------------------------------------*/
516 static void clgen_detect (void);
517 static int clgen_encode_fix (struct fb_fix_screeninfo
*fix
, const void *par
,
518 struct fb_info_gen
*info
);
519 static int clgen_decode_var (const struct fb_var_screeninfo
*var
, void *par
,
520 struct fb_info_gen
*info
);
521 static int clgen_encode_var (struct fb_var_screeninfo
*var
, const void *par
,
522 struct fb_info_gen
*info
);
523 static void clgen_get_par (void *par
, struct fb_info_gen
*info
);
524 static void clgen_set_par (const void *par
, struct fb_info_gen
*info
);
525 static int clgen_getcolreg (unsigned regno
, unsigned *red
, unsigned *green
,
526 unsigned *blue
, unsigned *transp
,
527 struct fb_info
*info
);
528 static int clgen_pan_display (const struct fb_var_screeninfo
*var
,
529 struct fb_info_gen
*info
);
530 static int clgen_blank (int blank_mode
, struct fb_info_gen
*info
);
532 static void clgen_set_disp (const void *par
, struct display
*disp
,
533 struct fb_info_gen
*info
);
535 /* function table of the above functions */
536 static struct fbgen_hwswitch clgen_hwswitch
=
550 /* Text console acceleration */
552 #ifdef FBCON_HAS_CFB8
553 static void fbcon_clgen8_bmove (struct display
*p
, int sy
, int sx
,
554 int dy
, int dx
, int height
, int width
);
555 static void fbcon_clgen8_clear (struct vc_data
*conp
, struct display
*p
,
556 int sy
, int sx
, int height
, int width
);
558 static struct display_switch fbcon_clgen_8
= {
559 .setup
= fbcon_cfb8_setup
,
560 .bmove
= fbcon_clgen8_bmove
,
561 .clear
= fbcon_clgen8_clear
,
562 .putc
= fbcon_cfb8_putc
,
563 .putcs
= fbcon_cfb8_putcs
,
564 .revc
= fbcon_cfb8_revc
,
565 .clear_margins
=fbcon_cfb8_clear_margins
,
566 .fontwidthmask
=FONTWIDTH (4) | FONTWIDTH (8) | FONTWIDTH (12) | FONTWIDTH (16)
569 #ifdef FBCON_HAS_CFB16
570 static void fbcon_clgen16_bmove (struct display
*p
, int sy
, int sx
,
571 int dy
, int dx
, int height
, int width
);
572 static void fbcon_clgen16_clear (struct vc_data
*conp
, struct display
*p
,
573 int sy
, int sx
, int height
, int width
);
574 static struct display_switch fbcon_clgen_16
= {
575 .setup
= fbcon_cfb16_setup
,
576 .bmove
= fbcon_clgen16_bmove
,
577 .clear
= fbcon_clgen16_clear
,
578 .putc
= fbcon_cfb16_putc
,
579 .putcs
= fbcon_cfb16_putcs
,
580 .revc
= fbcon_cfb16_revc
,
581 .clear_margins
=fbcon_cfb16_clear_margins
,
582 .fontwidthmask
=FONTWIDTH (4) | FONTWIDTH (8) | FONTWIDTH (12) | FONTWIDTH (16)
585 #ifdef FBCON_HAS_CFB32
586 static void fbcon_clgen32_bmove (struct display
*p
, int sy
, int sx
,
587 int dy
, int dx
, int height
, int width
);
588 static void fbcon_clgen32_clear (struct vc_data
*conp
, struct display
*p
,
589 int sy
, int sx
, int height
, int width
);
590 static struct display_switch fbcon_clgen_32
= {
591 .setup
= fbcon_cfb32_setup
,
592 .bmove
= fbcon_clgen32_bmove
,
593 .clear
= fbcon_clgen32_clear
,
594 .putc
= fbcon_cfb32_putc
,
595 .putcs
= fbcon_cfb32_putcs
,
596 .revc
= fbcon_cfb32_revc
,
597 .clear_margins
=fbcon_cfb32_clear_margins
,
598 .fontwidthmask
=FONTWIDTH (4) | FONTWIDTH (8) | FONTWIDTH (12) | FONTWIDTH (16)
604 /*--- Internal routines ----------------------------------------------------*/
605 static void init_vgachip (struct clgenfb_info
*fb_info
);
606 static void switch_monitor (struct clgenfb_info
*fb_info
, int on
);
607 static void WGen (const struct clgenfb_info
*fb_info
,
608 int regnum
, unsigned char val
);
609 static unsigned char RGen (const struct clgenfb_info
*fb_info
, int regnum
);
610 static void AttrOn (const struct clgenfb_info
*fb_info
);
611 static void WHDR (const struct clgenfb_info
*fb_info
, unsigned char val
);
612 static void WSFR (struct clgenfb_info
*fb_info
, unsigned char val
);
613 static void WSFR2 (struct clgenfb_info
*fb_info
, unsigned char val
);
614 static void WClut (struct clgenfb_info
*fb_info
, unsigned char regnum
, unsigned char red
,
618 static void RClut (struct clgenfb_info
*fb_info
, unsigned char regnum
, unsigned char *red
,
619 unsigned char *green
,
620 unsigned char *blue
);
622 static void clgen_WaitBLT (caddr_t regbase
);
623 static void clgen_BitBLT (caddr_t regbase
, u_short curx
, u_short cury
,
624 u_short destx
, u_short desty
,
625 u_short width
, u_short height
,
626 u_short line_length
);
627 static void clgen_RectFill (struct clgenfb_info
*fb_info
, u_short x
, u_short y
,
628 u_short width
, u_short height
,
629 u_char color
, u_short line_length
);
631 static void bestclock (long freq
, long *best
,
632 long *nom
, long *den
,
633 long *div
, long maxfreq
);
636 static void clgen_dump (void);
637 static void clgen_dbg_reg_dump (caddr_t regbase
);
638 static void clgen_dbg_print_regs (caddr_t regbase
, clgen_dbg_reg_class_t reg_class
,...);
639 static void clgen_dbg_print_byte (const char *name
, unsigned char val
);
640 #endif /* CLGEN_DEBUG */
642 /*** END PROTOTYPES ********************************************************/
643 /*****************************************************************************/
644 /*** BEGIN Interface Used by the World ***************************************/
646 static int opencount
= 0;
648 /*--- Open /dev/fbx ---------------------------------------------------------*/
649 static int clgenfb_open (struct fb_info
*info
, int user
)
651 if (opencount
++ == 0)
652 switch_monitor ((struct clgenfb_info
*) info
, 1);
656 /*--- Close /dev/fbx --------------------------------------------------------*/
657 static int clgenfb_release (struct fb_info
*info
, int user
)
659 if (--opencount
== 0)
660 switch_monitor ((struct clgenfb_info
*) info
, 0);
664 /**** END Interface used by the World *************************************/
665 /****************************************************************************/
666 /**** BEGIN Hardware specific Routines **************************************/
668 static void clgen_detect (void)
674 static int clgen_encode_fix (struct fb_fix_screeninfo
*fix
, const void *par
,
675 struct fb_info_gen
*info
)
677 struct clgenfb_par
*_par
= (struct clgenfb_par
*) par
;
678 struct clgenfb_info
*_info
= (struct clgenfb_info
*) info
;
682 memset (fix
, 0, sizeof (struct fb_fix_screeninfo
));
683 strcpy (fix
->id
, clgenfb_name
);
685 if (_info
->btype
== BT_GD5480
) {
686 /* Select proper byte-swapping aperture */
687 switch (_par
->var
.bits_per_pixel
) {
690 fix
->smem_start
= _info
->fbmem_phys
;
693 fix
->smem_start
= _info
->fbmem_phys
+ 1 * MB_
;
697 fix
->smem_start
= _info
->fbmem_phys
+ 2 * MB_
;
701 fix
->smem_start
= _info
->fbmem_phys
;
704 /* monochrome: only 1 memory plane */
705 /* 8 bit and above: Use whole memory area */
706 fix
->smem_len
= _par
->var
.bits_per_pixel
== 1 ? _info
->size
/ 4
708 fix
->type
= _par
->type
;
710 fix
->visual
= _par
->visual
;
714 fix
->line_length
= _par
->line_length
;
716 /* FIXME: map region at 0xB8000 if available, fill in here */
719 fix
->accel
= FB_ACCEL_NONE
;
727 /* Get a good MCLK value */
728 static long clgen_get_mclk (long freq
, int bpp
, long *div
)
732 assert (div
!= NULL
);
734 /* Calculate MCLK, in case VCLK is high enough to require > 50MHz.
735 * Assume a 64-bit data path for now. The formula is:
736 * ((B * PCLK * 2)/W) * 1.2
737 * B = bytes per pixel, PCLK = pixclock, W = data width in bytes */
738 mclk
= ((bpp
/ 8) * freq
* 2) / 4;
739 mclk
= (mclk
* 12) / 10;
742 DPRINTK ("Use MCLK of %ld kHz\n", mclk
);
744 /* Calculate value for SR1F. Multiply by 2 so we can round up. */
745 mclk
= ((mclk
* 16) / 14318);
746 mclk
= (mclk
+ 1) / 2;
747 DPRINTK ("Set SR1F[5:0] to 0x%lx\n", mclk
);
749 /* Determine if we should use MCLK instead of VCLK, and if so, what we
750 * should divide it by to get VCLK */
752 case 24751 ... 25249:
754 DPRINTK ("Using VCLK = MCLK/2\n");
756 case 49501 ... 50499:
758 DPRINTK ("Using VCLK = MCLK\n");
768 static int clgen_decode_var (const struct fb_var_screeninfo
*var
, void *par
,
769 struct fb_info_gen
*info
)
773 int xres
, hfront
, hsync
, hback
;
774 int yres
, vfront
, vsync
, vback
;
775 int nom
, den
; /* translyting from pixels->bytes */
795 struct clgenfb_par
*_par
= (struct clgenfb_par
*) par
;
796 struct clgenfb_info
*fb_info
= (struct clgenfb_info
*) info
;
798 assert (var
!= NULL
);
799 assert (par
!= NULL
);
800 assert (info
!= NULL
);
804 DPRINTK ("Requested: %dx%dx%d\n", var
->xres
, var
->yres
, var
->bits_per_pixel
);
805 DPRINTK (" virtual: %dx%d\n", var
->xres_virtual
, var
->yres_virtual
);
806 DPRINTK (" offset: (%d,%d)\n", var
->xoffset
, var
->yoffset
);
807 DPRINTK ("grayscale: %d\n", var
->grayscale
);
809 memset (par
, 0, sizeof (struct clgenfb_par
));
813 switch (var
->bits_per_pixel
) {
817 break; /* 8 pixel per byte, only 1/4th of mem usable */
819 _par
->var
.bits_per_pixel
= 8;
822 break; /* 1 pixel == 1 byte */
824 _par
->var
.bits_per_pixel
= 16;
827 break; /* 2 bytes per pixel */
829 _par
->var
.bits_per_pixel
= 24;
832 break; /* 3 bytes per pixel */
834 _par
->var
.bits_per_pixel
= 32;
837 break; /* 4 bytes per pixel */
839 printk ("clgen: mode %dx%dx%d rejected...color depth not supported.\n",
840 var
->xres
, var
->yres
, var
->bits_per_pixel
);
841 DPRINTK ("EXIT - EINVAL error\n");
845 if (_par
->var
.xres
* nom
/ den
* _par
->var
.yres
> fb_info
->size
) {
846 printk ("clgen: mode %dx%dx%d rejected...resolution too high to fit into video memory!\n",
847 var
->xres
, var
->yres
, var
->bits_per_pixel
);
848 DPRINTK ("EXIT - EINVAL error\n");
851 /* use highest possible virtual resolution */
852 if (_par
->var
.xres_virtual
== -1 &&
853 _par
->var
.yres_virtual
== -1) {
854 printk ("clgen: using maximum available virtual resolution\n");
855 for (i
= 0; modes
[i
].xres
!= -1; i
++) {
856 if (modes
[i
].xres
* nom
/ den
* modes
[i
].yres
< fb_info
->size
/ 2)
859 if (modes
[i
].xres
== -1) {
860 printk ("clgen: could not find a virtual resolution that fits into video memory!!\n");
861 DPRINTK ("EXIT - EINVAL error\n");
864 _par
->var
.xres_virtual
= modes
[i
].xres
;
865 _par
->var
.yres_virtual
= modes
[i
].yres
;
867 printk ("clgen: virtual resolution set to maximum of %dx%d\n",
868 _par
->var
.xres_virtual
, _par
->var
.yres_virtual
);
869 } else if (_par
->var
.xres_virtual
== -1) {
870 /* FIXME: maximize X virtual resolution only */
871 } else if (_par
->var
.yres_virtual
== -1) {
872 /* FIXME: maximize Y virtual resolution only */
874 if (_par
->var
.xoffset
< 0)
875 _par
->var
.xoffset
= 0;
876 if (_par
->var
.yoffset
< 0)
877 _par
->var
.yoffset
= 0;
879 /* truncate xoffset and yoffset to maximum if too high */
880 if (_par
->var
.xoffset
> _par
->var
.xres_virtual
- _par
->var
.xres
)
881 _par
->var
.xoffset
= _par
->var
.xres_virtual
- _par
->var
.xres
- 1;
883 if (_par
->var
.yoffset
> _par
->var
.yres_virtual
- _par
->var
.yres
)
884 _par
->var
.yoffset
= _par
->var
.yres_virtual
- _par
->var
.yres
- 1;
886 switch (_par
->var
.bits_per_pixel
) {
888 _par
->line_length
= _par
->var
.xres_virtual
/ 8;
889 _par
->visual
= FB_VISUAL_MONO10
;
893 _par
->line_length
= _par
->var
.xres_virtual
;
894 _par
->visual
= FB_VISUAL_PSEUDOCOLOR
;
895 _par
->var
.red
.offset
= 0;
896 _par
->var
.red
.length
= 6;
897 _par
->var
.green
.offset
= 0;
898 _par
->var
.green
.length
= 6;
899 _par
->var
.blue
.offset
= 0;
900 _par
->var
.blue
.length
= 6;
904 _par
->line_length
= _par
->var
.xres_virtual
* 2;
905 _par
->visual
= FB_VISUAL_DIRECTCOLOR
;
907 _par
->var
.red
.offset
= 2;
908 _par
->var
.green
.offset
= -3;
909 _par
->var
.blue
.offset
= 8;
911 _par
->var
.red
.offset
= 10;
912 _par
->var
.green
.offset
= 5;
913 _par
->var
.blue
.offset
= 0;
915 _par
->var
.red
.length
= 5;
916 _par
->var
.green
.length
= 5;
917 _par
->var
.blue
.length
= 5;
921 _par
->line_length
= _par
->var
.xres_virtual
* 3;
922 _par
->visual
= FB_VISUAL_DIRECTCOLOR
;
924 _par
->var
.red
.offset
= 8;
925 _par
->var
.green
.offset
= 16;
926 _par
->var
.blue
.offset
= 24;
928 _par
->var
.red
.offset
= 16;
929 _par
->var
.green
.offset
= 8;
930 _par
->var
.blue
.offset
= 0;
932 _par
->var
.red
.length
= 8;
933 _par
->var
.green
.length
= 8;
934 _par
->var
.blue
.length
= 8;
938 _par
->line_length
= _par
->var
.xres_virtual
* 4;
939 _par
->visual
= FB_VISUAL_DIRECTCOLOR
;
941 _par
->var
.red
.offset
= 8;
942 _par
->var
.green
.offset
= 16;
943 _par
->var
.blue
.offset
= 24;
945 _par
->var
.red
.offset
= 16;
946 _par
->var
.green
.offset
= 8;
947 _par
->var
.blue
.offset
= 0;
949 _par
->var
.red
.length
= 8;
950 _par
->var
.green
.length
= 8;
951 _par
->var
.blue
.length
= 8;
955 DPRINTK("Unsupported bpp size: %d\n", _par
->var
.bits_per_pixel
);
957 /* should never occur */
961 _par
->var
.red
.msb_right
=
962 _par
->var
.green
.msb_right
=
963 _par
->var
.blue
.msb_right
=
964 _par
->var
.transp
.offset
=
965 _par
->var
.transp
.length
=
966 _par
->var
.transp
.msb_right
= 0;
968 _par
->type
= FB_TYPE_PACKED_PIXELS
;
970 /* convert from ps to kHz */
971 freq
= 1000000000 / var
->pixclock
;
973 DPRINTK ("desired pixclock: %ld kHz\n", freq
);
975 maxclock
= clgen_board_info
[fb_info
->btype
].maxclock
;
976 _par
->multiplexing
= 0;
978 /* If the frequency is greater than we can support, we might be able
979 * to use multiplexing for the video mode */
980 if (freq
> maxclock
) {
981 switch (fb_info
->btype
) {
984 _par
->multiplexing
= 1;
988 printk (KERN_WARNING
"clgen: ERROR: Frequency greater than maxclock (%ld kHz)\n", maxclock
);
989 DPRINTK ("EXIT - return -EINVAL\n");
994 /* TODO: If we have a 1MB 5434, we need to put ourselves in a mode where
995 * the VCLK is double the pixel clock. */
996 switch (var
->bits_per_pixel
) {
999 if (_par
->HorizRes
<= 800)
1000 freq
/= 2; /* Xbh has this type of clock for 32-bit */
1005 bestclock (freq
, &_par
->freq
, &_par
->nom
, &_par
->den
, &_par
->div
,
1007 _par
->mclk
= clgen_get_mclk (freq
, _par
->var
.bits_per_pixel
, &_par
->divMCLK
);
1009 xres
= _par
->var
.xres
;
1010 hfront
= _par
->var
.right_margin
;
1011 hsync
= _par
->var
.hsync_len
;
1012 hback
= _par
->var
.left_margin
;
1014 yres
= _par
->var
.yres
;
1015 vfront
= _par
->var
.lower_margin
;
1016 vsync
= _par
->var
.vsync_len
;
1017 vback
= _par
->var
.upper_margin
;
1019 if (_par
->var
.vmode
& FB_VMODE_DOUBLE
) {
1024 } else if (_par
->var
.vmode
& FB_VMODE_INTERLACED
) {
1025 yres
= (yres
+ 1) / 2;
1026 vfront
= (vfront
+ 1) / 2;
1027 vsync
= (vsync
+ 1) / 2;
1028 vback
= (vback
+ 1) / 2;
1030 _par
->HorizRes
= xres
;
1031 _par
->HorizTotal
= (xres
+ hfront
+ hsync
+ hback
) / 8 - 5;
1032 _par
->HorizDispEnd
= xres
/ 8 - 1;
1033 _par
->HorizBlankStart
= xres
/ 8;
1034 _par
->HorizBlankEnd
= _par
->HorizTotal
+ 5; /* does not count with "-5" */
1035 _par
->HorizSyncStart
= (xres
+ hfront
) / 8 + 1;
1036 _par
->HorizSyncEnd
= (xres
+ hfront
+ hsync
) / 8 + 1;
1038 _par
->VertRes
= yres
;
1039 _par
->VertTotal
= yres
+ vfront
+ vsync
+ vback
- 2;
1040 _par
->VertDispEnd
= yres
- 1;
1041 _par
->VertBlankStart
= yres
;
1042 _par
->VertBlankEnd
= _par
->VertTotal
;
1043 _par
->VertSyncStart
= yres
+ vfront
- 1;
1044 _par
->VertSyncEnd
= yres
+ vfront
+ vsync
- 1;
1046 if (_par
->VertRes
>= 1024) {
1047 _par
->VertTotal
/= 2;
1048 _par
->VertSyncStart
/= 2;
1049 _par
->VertSyncEnd
/= 2;
1050 _par
->VertDispEnd
/= 2;
1052 if (_par
->multiplexing
) {
1053 _par
->HorizTotal
/= 2;
1054 _par
->HorizSyncStart
/= 2;
1055 _par
->HorizSyncEnd
/= 2;
1056 _par
->HorizDispEnd
/= 2;
1058 if (_par
->VertRes
>= 1280) {
1059 printk (KERN_WARNING
"clgen: ERROR: VerticalTotal >= 1280; special treatment required! (TODO)\n");
1060 DPRINTK ("EXIT - EINVAL error\n");
1068 static int clgen_encode_var (struct fb_var_screeninfo
*var
, const void *par
,
1069 struct fb_info_gen
*info
)
1071 DPRINTK ("ENTER\n");
1073 *var
= ((struct clgenfb_par
*) par
)->var
;
1079 /* get current video mode */
1080 static void clgen_get_par (void *par
, struct fb_info_gen
*info
)
1082 struct clgenfb_par
*_par
= (struct clgenfb_par
*) par
;
1083 struct clgenfb_info
*_info
= (struct clgenfb_info
*) info
;
1085 DPRINTK ("ENTER\n");
1087 *_par
= _info
->currentmode
;
1092 static void clgen_set_mclk (const struct clgenfb_info
*fb_info
, int val
, int div
)
1094 assert (fb_info
!= NULL
);
1098 unsigned char old
= vga_rseq (fb_info
->regs
, CL_SEQR1E
);
1099 vga_wseq (fb_info
->regs
, CL_SEQR1E
, old
| 0x1);
1100 vga_wseq (fb_info
->regs
, CL_SEQR1F
, 0x40 | (val
& 0x3f));
1101 } else if (div
== 1) {
1103 unsigned char old
= vga_rseq (fb_info
->regs
, CL_SEQR1E
);
1104 vga_wseq (fb_info
->regs
, CL_SEQR1E
, old
& ~0x1);
1105 vga_wseq (fb_info
->regs
, CL_SEQR1F
, 0x40 | (val
& 0x3f));
1107 vga_wseq (fb_info
->regs
, CL_SEQR1F
, val
& 0x3f);
1111 /*************************************************************************
1114 actually writes the values for a new video mode into the hardware,
1115 **************************************************************************/
1116 static void clgen_set_par (const void *par
, struct fb_info_gen
*info
)
1120 struct clgenfb_par
*_par
= (struct clgenfb_par
*) par
;
1121 struct clgenfb_info
*fb_info
= (struct clgenfb_info
*) info
;
1122 const struct clgen_board_info_rec
*bi
;
1124 DPRINTK ("ENTER\n");
1125 DPRINTK ("Requested mode: %dx%dx%d\n",
1126 _par
->var
.xres
, _par
->var
.yres
, _par
->var
.bits_per_pixel
);
1127 DPRINTK ("pixclock: %d\n", _par
->var
.pixclock
);
1129 bi
= &clgen_board_info
[fb_info
->btype
];
1132 /* unlock register VGA_CRTC_H_TOTAL..CRT7 */
1133 vga_wcrt (fb_info
->regs
, VGA_CRTC_V_SYNC_END
, 0x20); /* previously: 0x00) */
1135 /* if debugging is enabled, all parameters get output before writing */
1136 DPRINTK ("CRT0: %ld\n", _par
->HorizTotal
);
1137 vga_wcrt (fb_info
->regs
, VGA_CRTC_H_TOTAL
, _par
->HorizTotal
);
1139 DPRINTK ("CRT1: %ld\n", _par
->HorizDispEnd
);
1140 vga_wcrt (fb_info
->regs
, VGA_CRTC_H_DISP
, _par
->HorizDispEnd
);
1142 DPRINTK ("CRT2: %ld\n", _par
->HorizBlankStart
);
1143 vga_wcrt (fb_info
->regs
, VGA_CRTC_H_BLANK_START
, _par
->HorizBlankStart
);
1145 DPRINTK ("CRT3: 128+%ld\n", _par
->HorizBlankEnd
% 32); /* + 128: Compatible read */
1146 vga_wcrt (fb_info
->regs
, VGA_CRTC_H_BLANK_END
, 128 + (_par
->HorizBlankEnd
% 32));
1148 DPRINTK ("CRT4: %ld\n", _par
->HorizSyncStart
);
1149 vga_wcrt (fb_info
->regs
, VGA_CRTC_H_SYNC_START
, _par
->HorizSyncStart
);
1151 tmp
= _par
->HorizSyncEnd
% 32;
1152 if (_par
->HorizBlankEnd
& 32)
1154 DPRINTK ("CRT5: %d\n", tmp
);
1155 vga_wcrt (fb_info
->regs
, VGA_CRTC_H_SYNC_END
, tmp
);
1157 DPRINTK ("CRT6: %ld\n", _par
->VertTotal
& 0xff);
1158 vga_wcrt (fb_info
->regs
, VGA_CRTC_V_TOTAL
, (_par
->VertTotal
& 0xff));
1160 tmp
= 16; /* LineCompare bit #9 */
1161 if (_par
->VertTotal
& 256)
1163 if (_par
->VertDispEnd
& 256)
1165 if (_par
->VertSyncStart
& 256)
1167 if (_par
->VertBlankStart
& 256)
1169 if (_par
->VertTotal
& 512)
1171 if (_par
->VertDispEnd
& 512)
1173 if (_par
->VertSyncStart
& 512)
1175 DPRINTK ("CRT7: %d\n", tmp
);
1176 vga_wcrt (fb_info
->regs
, VGA_CRTC_OVERFLOW
, tmp
);
1178 tmp
= 0x40; /* LineCompare bit #8 */
1179 if (_par
->VertBlankStart
& 512)
1181 if (_par
->var
.vmode
& FB_VMODE_DOUBLE
)
1183 DPRINTK ("CRT9: %d\n", tmp
);
1184 vga_wcrt (fb_info
->regs
, VGA_CRTC_MAX_SCAN
, tmp
);
1186 DPRINTK ("CRT10: %ld\n", _par
->VertSyncStart
& 0xff);
1187 vga_wcrt (fb_info
->regs
, VGA_CRTC_V_SYNC_START
, (_par
->VertSyncStart
& 0xff));
1189 DPRINTK ("CRT11: 64+32+%ld\n", _par
->VertSyncEnd
% 16);
1190 vga_wcrt (fb_info
->regs
, VGA_CRTC_V_SYNC_END
, (_par
->VertSyncEnd
% 16 + 64 + 32));
1192 DPRINTK ("CRT12: %ld\n", _par
->VertDispEnd
& 0xff);
1193 vga_wcrt (fb_info
->regs
, VGA_CRTC_V_DISP_END
, (_par
->VertDispEnd
& 0xff));
1195 DPRINTK ("CRT15: %ld\n", _par
->VertBlankStart
& 0xff);
1196 vga_wcrt (fb_info
->regs
, VGA_CRTC_V_BLANK_START
, (_par
->VertBlankStart
& 0xff));
1198 DPRINTK ("CRT16: %ld\n", _par
->VertBlankEnd
& 0xff);
1199 vga_wcrt (fb_info
->regs
, VGA_CRTC_V_BLANK_END
, (_par
->VertBlankEnd
& 0xff));
1201 DPRINTK ("CRT18: 0xff\n");
1202 vga_wcrt (fb_info
->regs
, VGA_CRTC_LINE_COMPARE
, 0xff);
1205 if (_par
->var
.vmode
& FB_VMODE_INTERLACED
)
1207 if (_par
->HorizBlankEnd
& 64)
1209 if (_par
->HorizBlankEnd
& 128)
1211 if (_par
->VertBlankEnd
& 256)
1213 if (_par
->VertBlankEnd
& 512)
1216 DPRINTK ("CRT1a: %d\n", tmp
);
1217 vga_wcrt (fb_info
->regs
, CL_CRT1A
, tmp
);
1220 /* hardware RefClock: 14.31818 MHz */
1221 /* formula: VClk = (OSC * N) / (D * (1+P)) */
1222 /* Example: VClk = (14.31818 * 91) / (23 * (1+1)) = 28.325 MHz */
1224 vga_wseq (fb_info
->regs
, CL_SEQRB
, _par
->nom
);
1225 tmp
= _par
->den
<< 1;
1229 if ((fb_info
->btype
== BT_SD64
) ||
1230 (fb_info
->btype
== BT_ALPINE
) ||
1231 (fb_info
->btype
== BT_GD5480
))
1232 tmp
|= 0x80; /* 6 bit denom; ONLY 5434!!! (bugged me 10 days) */
1234 DPRINTK ("CL_SEQR1B: %ld\n", (long) tmp
);
1235 vga_wseq (fb_info
->regs
, CL_SEQR1B
, tmp
);
1237 if (_par
->VertRes
>= 1024)
1239 vga_wcrt (fb_info
->regs
, VGA_CRTC_MODE
, 0xc7);
1241 /* mode control: VGA_CRTC_START_HI enable, ROTATE(?), 16bit
1242 * address wrap, no compat. */
1243 vga_wcrt (fb_info
->regs
, VGA_CRTC_MODE
, 0xc3);
1245 /* HAEH? vga_wcrt (fb_info->regs, VGA_CRTC_V_SYNC_END, 0x20); * previously: 0x00 unlock VGA_CRTC_H_TOTAL..CRT7 */
1247 /* don't know if it would hurt to also program this if no interlaced */
1248 /* mode is used, but I feel better this way.. :-) */
1249 if (_par
->var
.vmode
& FB_VMODE_INTERLACED
)
1250 vga_wcrt (fb_info
->regs
, VGA_CRTC_REGS
, _par
->HorizTotal
/ 2);
1252 vga_wcrt (fb_info
->regs
, VGA_CRTC_REGS
, 0x00); /* interlace control */
1254 vga_wseq (fb_info
->regs
, VGA_SEQ_CHARACTER_MAP
, 0);
1256 /* adjust horizontal/vertical sync type (low/high) */
1257 tmp
= 0x03; /* enable display memory & CRTC I/O address for color mode */
1258 if (_par
->var
.sync
& FB_SYNC_HOR_HIGH_ACT
)
1260 if (_par
->var
.sync
& FB_SYNC_VERT_HIGH_ACT
)
1262 WGen (fb_info
, VGA_MIS_W
, tmp
);
1264 vga_wcrt (fb_info
->regs
, VGA_CRTC_PRESET_ROW
, 0); /* Screen A Preset Row-Scan register */
1265 vga_wcrt (fb_info
->regs
, VGA_CRTC_CURSOR_START
, 0); /* text cursor on and start line */
1266 vga_wcrt (fb_info
->regs
, VGA_CRTC_CURSOR_END
, 31); /* text cursor end line */
1268 /******************************************************
1274 /* programming for different color depths */
1275 if (_par
->var
.bits_per_pixel
== 1) {
1276 DPRINTK ("clgen: preparing for 1 bit deep display\n");
1277 vga_wgfx (fb_info
->regs
, VGA_GFX_MODE
, 0); /* mode register */
1280 switch (fb_info
->btype
) {
1288 DPRINTK (" (for GD54xx)\n");
1289 vga_wseq (fb_info
->regs
, CL_SEQR7
,
1290 _par
->multiplexing
?
1291 bi
->sr07_1bpp_mux
: bi
->sr07_1bpp
);
1295 DPRINTK (" (for GD546x)\n");
1296 vga_wseq (fb_info
->regs
, CL_SEQR7
,
1297 vga_rseq (fb_info
->regs
, CL_SEQR7
) & ~0x01);
1301 printk (KERN_WARNING
"clgen: unknown Board\n");
1305 /* Extended Sequencer Mode */
1306 switch (fb_info
->btype
) {
1308 /* setting the SEQRF on SD64 is not necessary (only during init) */
1309 DPRINTK ("(for SD64)\n");
1310 vga_wseq (fb_info
->regs
, CL_SEQR1F
, 0x1a); /* MCLK select */
1314 DPRINTK ("(for Piccolo)\n");
1315 /* ### ueberall 0x22? */
1316 vga_wseq (fb_info
->regs
, CL_SEQR1F
, 0x22); /* ##vorher 1c MCLK select */
1317 vga_wseq (fb_info
->regs
, CL_SEQRF
, 0xb0); /* evtl d0 bei 1 bit? avoid FIFO underruns..? */
1321 DPRINTK ("(for Picasso)\n");
1322 vga_wseq (fb_info
->regs
, CL_SEQR1F
, 0x22); /* ##vorher 22 MCLK select */
1323 vga_wseq (fb_info
->regs
, CL_SEQRF
, 0xd0); /* ## vorher d0 avoid FIFO underruns..? */
1327 DPRINTK ("(for Spectrum)\n");
1328 /* ### ueberall 0x22? */
1329 vga_wseq (fb_info
->regs
, CL_SEQR1F
, 0x22); /* ##vorher 1c MCLK select */
1330 vga_wseq (fb_info
->regs
, CL_SEQRF
, 0xb0); /* evtl d0? avoid FIFO underruns..? */
1337 DPRINTK (" (for GD54xx)\n");
1342 printk (KERN_WARNING
"clgen: unknown Board\n");
1346 WGen (fb_info
, VGA_PEL_MSK
, 0x01); /* pixel mask: pass-through for first plane */
1347 if (_par
->multiplexing
)
1348 WHDR (fb_info
, 0x4a); /* hidden dac reg: 1280x1024 */
1350 WHDR (fb_info
, 0); /* hidden dac: nothing */
1351 vga_wseq (fb_info
->regs
, VGA_SEQ_MEMORY_MODE
, 0x06); /* memory mode: odd/even, ext. memory */
1352 vga_wseq (fb_info
->regs
, VGA_SEQ_PLANE_WRITE
, 0x01); /* plane mask: only write to first plane */
1353 offset
= _par
->var
.xres_virtual
/ 16;
1356 /******************************************************
1362 else if (_par
->var
.bits_per_pixel
== 8) {
1363 DPRINTK ("clgen: preparing for 8 bit deep display\n");
1364 switch (fb_info
->btype
) {
1372 DPRINTK (" (for GD54xx)\n");
1373 vga_wseq (fb_info
->regs
, CL_SEQR7
,
1374 _par
->multiplexing
?
1375 bi
->sr07_8bpp_mux
: bi
->sr07_8bpp
);
1379 DPRINTK (" (for GD546x)\n");
1380 vga_wseq (fb_info
->regs
, CL_SEQR7
,
1381 vga_rseq (fb_info
->regs
, CL_SEQR7
) | 0x01);
1385 printk (KERN_WARNING
"clgen: unknown Board\n");
1389 switch (fb_info
->btype
) {
1391 vga_wseq (fb_info
->regs
, CL_SEQR1F
, 0x1d); /* MCLK select */
1395 vga_wseq (fb_info
->regs
, CL_SEQR1F
, 0x22); /* ### vorher 1c MCLK select */
1396 vga_wseq (fb_info
->regs
, CL_SEQRF
, 0xb0); /* Fast Page-Mode writes */
1400 vga_wseq (fb_info
->regs
, CL_SEQR1F
, 0x22); /* ### vorher 1c MCLK select */
1401 vga_wseq (fb_info
->regs
, CL_SEQRF
, 0xb0); /* Fast Page-Mode writes */
1405 vga_wseq (fb_info
->regs
, CL_SEQR1F
, 0x22); /* ### vorher 1c MCLK select */
1406 vga_wseq (fb_info
->regs
, CL_SEQRF
, 0xb0); /* Fast Page-Mode writes */
1411 vga_wseq (fb_info
->regs
, CL_SEQRF
, 0xb8); /* ### INCOMPLETE!! */
1413 /* vga_wseq (fb_info->regs, CL_SEQR1F, 0x1c); */
1417 DPRINTK (" (for GD543x)\n");
1418 clgen_set_mclk (fb_info
, _par
->mclk
, _par
->divMCLK
);
1419 /* We already set SRF and SR1F */
1424 DPRINTK (" (for GD54xx)\n");
1429 printk (KERN_WARNING
"clgen: unknown Board\n");
1433 vga_wgfx (fb_info
->regs
, VGA_GFX_MODE
, 64); /* mode register: 256 color mode */
1434 WGen (fb_info
, VGA_PEL_MSK
, 0xff); /* pixel mask: pass-through all planes */
1435 if (_par
->multiplexing
)
1436 WHDR (fb_info
, 0x4a); /* hidden dac reg: 1280x1024 */
1438 WHDR (fb_info
, 0); /* hidden dac: nothing */
1439 vga_wseq (fb_info
->regs
, VGA_SEQ_MEMORY_MODE
, 0x0a); /* memory mode: chain4, ext. memory */
1440 vga_wseq (fb_info
->regs
, VGA_SEQ_PLANE_WRITE
, 0xff); /* plane mask: enable writing to all 4 planes */
1441 offset
= _par
->var
.xres_virtual
/ 8;
1444 /******************************************************
1450 else if (_par
->var
.bits_per_pixel
== 16) {
1451 DPRINTK ("clgen: preparing for 16 bit deep display\n");
1452 switch (fb_info
->btype
) {
1454 vga_wseq (fb_info
->regs
, CL_SEQR7
, 0xf7); /* Extended Sequencer Mode: 256c col. mode */
1455 vga_wseq (fb_info
->regs
, CL_SEQR1F
, 0x1e); /* MCLK select */
1459 vga_wseq (fb_info
->regs
, CL_SEQR7
, 0x87);
1460 vga_wseq (fb_info
->regs
, CL_SEQRF
, 0xb0); /* Fast Page-Mode writes */
1461 vga_wseq (fb_info
->regs
, CL_SEQR1F
, 0x22); /* MCLK select */
1465 vga_wseq (fb_info
->regs
, CL_SEQR7
, 0x27);
1466 vga_wseq (fb_info
->regs
, CL_SEQRF
, 0xb0); /* Fast Page-Mode writes */
1467 vga_wseq (fb_info
->regs
, CL_SEQR1F
, 0x22); /* MCLK select */
1471 vga_wseq (fb_info
->regs
, CL_SEQR7
, 0x87);
1472 vga_wseq (fb_info
->regs
, CL_SEQRF
, 0xb0); /* Fast Page-Mode writes */
1473 vga_wseq (fb_info
->regs
, CL_SEQR1F
, 0x22); /* MCLK select */
1477 vga_wseq (fb_info
->regs
, CL_SEQR7
, 0x27);
1478 /* vga_wseq (fb_info->regs, CL_SEQR1F, 0x1c); */
1482 DPRINTK (" (for GD543x)\n");
1483 if (_par
->HorizRes
>= 1024)
1484 vga_wseq (fb_info
->regs
, CL_SEQR7
, 0xa7);
1486 vga_wseq (fb_info
->regs
, CL_SEQR7
, 0xa3);
1487 clgen_set_mclk (fb_info
, _par
->mclk
, _par
->divMCLK
);
1491 DPRINTK (" (for GD5480)\n");
1492 vga_wseq (fb_info
->regs
, CL_SEQR7
, 0x17);
1493 /* We already set SRF and SR1F */
1497 DPRINTK (" (for GD546x)\n");
1498 vga_wseq (fb_info
->regs
, CL_SEQR7
,
1499 vga_rseq (fb_info
->regs
, CL_SEQR7
) & ~0x01);
1503 printk (KERN_WARNING
"CLGEN: unknown Board\n");
1507 vga_wgfx (fb_info
->regs
, VGA_GFX_MODE
, 64); /* mode register: 256 color mode */
1508 WGen (fb_info
, VGA_PEL_MSK
, 0xff); /* pixel mask: pass-through all planes */
1510 WHDR (fb_info
, 0xc0); /* Copy Xbh */
1511 #elif defined(CONFIG_ZORRO)
1512 /* FIXME: CONFIG_PCI and CONFIG_ZORRO may be defined both */
1513 WHDR (fb_info
, 0xa0); /* hidden dac reg: nothing special */
1515 vga_wseq (fb_info
->regs
, VGA_SEQ_MEMORY_MODE
, 0x0a); /* memory mode: chain4, ext. memory */
1516 vga_wseq (fb_info
->regs
, VGA_SEQ_PLANE_WRITE
, 0xff); /* plane mask: enable writing to all 4 planes */
1517 offset
= _par
->var
.xres_virtual
/ 4;
1520 /******************************************************
1526 else if (_par
->var
.bits_per_pixel
== 32) {
1527 DPRINTK ("clgen: preparing for 24/32 bit deep display\n");
1528 switch (fb_info
->btype
) {
1530 vga_wseq (fb_info
->regs
, CL_SEQR7
, 0xf9); /* Extended Sequencer Mode: 256c col. mode */
1531 vga_wseq (fb_info
->regs
, CL_SEQR1F
, 0x1e); /* MCLK select */
1535 vga_wseq (fb_info
->regs
, CL_SEQR7
, 0x85);
1536 vga_wseq (fb_info
->regs
, CL_SEQRF
, 0xb0); /* Fast Page-Mode writes */
1537 vga_wseq (fb_info
->regs
, CL_SEQR1F
, 0x22); /* MCLK select */
1541 vga_wseq (fb_info
->regs
, CL_SEQR7
, 0x25);
1542 vga_wseq (fb_info
->regs
, CL_SEQRF
, 0xb0); /* Fast Page-Mode writes */
1543 vga_wseq (fb_info
->regs
, CL_SEQR1F
, 0x22); /* MCLK select */
1547 vga_wseq (fb_info
->regs
, CL_SEQR7
, 0x85);
1548 vga_wseq (fb_info
->regs
, CL_SEQRF
, 0xb0); /* Fast Page-Mode writes */
1549 vga_wseq (fb_info
->regs
, CL_SEQR1F
, 0x22); /* MCLK select */
1553 vga_wseq (fb_info
->regs
, CL_SEQR7
, 0x25);
1554 /* vga_wseq (fb_info->regs, CL_SEQR1F, 0x1c); */
1558 DPRINTK (" (for GD543x)\n");
1559 vga_wseq (fb_info
->regs
, CL_SEQR7
, 0xa9);
1560 clgen_set_mclk (fb_info
, _par
->mclk
, _par
->divMCLK
);
1564 DPRINTK (" (for GD5480)\n");
1565 vga_wseq (fb_info
->regs
, CL_SEQR7
, 0x19);
1566 /* We already set SRF and SR1F */
1570 DPRINTK (" (for GD546x)\n");
1571 vga_wseq (fb_info
->regs
, CL_SEQR7
,
1572 vga_rseq (fb_info
->regs
, CL_SEQR7
) & ~0x01);
1576 printk (KERN_WARNING
"clgen: unknown Board\n");
1580 vga_wgfx (fb_info
->regs
, VGA_GFX_MODE
, 64); /* mode register: 256 color mode */
1581 WGen (fb_info
, VGA_PEL_MSK
, 0xff); /* pixel mask: pass-through all planes */
1582 WHDR (fb_info
, 0xc5); /* hidden dac reg: 8-8-8 mode (24 or 32) */
1583 vga_wseq (fb_info
->regs
, VGA_SEQ_MEMORY_MODE
, 0x0a); /* memory mode: chain4, ext. memory */
1584 vga_wseq (fb_info
->regs
, VGA_SEQ_PLANE_WRITE
, 0xff); /* plane mask: enable writing to all 4 planes */
1585 offset
= _par
->var
.xres_virtual
/ 4;
1588 /******************************************************
1590 * unknown/unsupported bpp
1595 printk (KERN_ERR
"clgen: What's this?? requested color depth == %d.\n",
1596 _par
->var
.bits_per_pixel
);
1599 vga_wcrt (fb_info
->regs
, VGA_CRTC_OFFSET
, offset
& 0xff);
1602 tmp
|= 0x10; /* offset overflow bit */
1604 vga_wcrt (fb_info
->regs
, CL_CRT1B
, tmp
); /* screen start addr #16-18, fastpagemode cycles */
1606 if (fb_info
->btype
== BT_SD64
||
1607 fb_info
->btype
== BT_PICASSO4
||
1608 fb_info
->btype
== BT_ALPINE
||
1609 fb_info
->btype
== BT_GD5480
)
1610 vga_wcrt (fb_info
->regs
, CL_CRT1D
, 0x00); /* screen start address bit 19 */
1612 vga_wcrt (fb_info
->regs
, VGA_CRTC_CURSOR_HI
, 0); /* text cursor location high */
1613 vga_wcrt (fb_info
->regs
, VGA_CRTC_CURSOR_LO
, 0); /* text cursor location low */
1614 vga_wcrt (fb_info
->regs
, VGA_CRTC_UNDERLINE
, 0); /* underline row scanline = at very bottom */
1616 vga_wattr (fb_info
->regs
, VGA_ATC_MODE
, 1); /* controller mode */
1617 vga_wattr (fb_info
->regs
, VGA_ATC_OVERSCAN
, 0); /* overscan (border) color */
1618 vga_wattr (fb_info
->regs
, VGA_ATC_PLANE_ENABLE
, 15); /* color plane enable */
1619 vga_wattr (fb_info
->regs
, CL_AR33
, 0); /* pixel panning */
1620 vga_wattr (fb_info
->regs
, VGA_ATC_COLOR_PAGE
, 0); /* color select */
1622 /* [ EGS: SetOffset(); ] */
1623 /* From SetOffset(): Turn on VideoEnable bit in Attribute controller */
1626 vga_wgfx (fb_info
->regs
, VGA_GFX_SR_VALUE
, 0); /* set/reset register */
1627 vga_wgfx (fb_info
->regs
, VGA_GFX_SR_ENABLE
, 0); /* set/reset enable */
1628 vga_wgfx (fb_info
->regs
, VGA_GFX_COMPARE_VALUE
, 0); /* color compare */
1629 vga_wgfx (fb_info
->regs
, VGA_GFX_DATA_ROTATE
, 0); /* data rotate */
1630 vga_wgfx (fb_info
->regs
, VGA_GFX_PLANE_READ
, 0); /* read map select */
1631 vga_wgfx (fb_info
->regs
, VGA_GFX_MISC
, 1); /* miscellaneous register */
1632 vga_wgfx (fb_info
->regs
, VGA_GFX_COMPARE_MASK
, 15); /* color don't care */
1633 vga_wgfx (fb_info
->regs
, VGA_GFX_BIT_MASK
, 255); /* bit mask */
1635 vga_wseq (fb_info
->regs
, CL_SEQR12
, 0x0); /* graphics cursor attributes: nothing special */
1637 /* finally, turn on everything - turn off "FullBandwidth" bit */
1638 /* also, set "DotClock%2" bit where requested */
1641 /*** FB_VMODE_CLOCK_HALVE in linux/fb.h not defined anymore ?
1642 if (var->vmode & FB_VMODE_CLOCK_HALVE)
1646 vga_wseq (fb_info
->regs
, VGA_SEQ_CLOCK_MODE
, tmp
);
1647 DPRINTK ("CL_SEQR1: %d\n", tmp
);
1649 fb_info
->currentmode
= *_par
;
1651 DPRINTK ("virtual offset: (%d,%d)\n", _par
->var
.xoffset
, _par
->var
.yoffset
);
1652 /* pan to requested offset */
1653 clgen_pan_display (&fb_info
->currentmode
.var
, (struct fb_info_gen
*) fb_info
);
1664 static int clgen_getcolreg (unsigned regno
, unsigned *red
, unsigned *green
,
1665 unsigned *blue
, unsigned *transp
,
1666 struct fb_info
*info
)
1668 struct clgenfb_info
*fb_info
= (struct clgenfb_info
*)info
;
1672 *red
= fb_info
->palette
[regno
].red
;
1673 *green
= fb_info
->palette
[regno
].green
;
1674 *blue
= fb_info
->palette
[regno
].blue
;
1680 static int clgenfb_setcolreg (unsigned regno
, unsigned red
, unsigned green
,
1681 unsigned blue
, unsigned transp
,
1682 struct fb_info
*info
)
1684 struct clgenfb_info
*fb_info
= (struct clgenfb_info
*) info
;
1689 #ifdef FBCON_HAS_CFB8
1690 switch (fb_info
->currentmode
.var
.bits_per_pixel
) {
1692 /* "transparent" stuff is completely ignored. */
1693 WClut (fb_info
, regno
, red
>> 10, green
>> 10, blue
>> 10);
1699 #endif /* FBCON_HAS_CFB8 */
1701 fb_info
->palette
[regno
].red
= red
;
1702 fb_info
->palette
[regno
].green
= green
;
1703 fb_info
->palette
[regno
].blue
= blue
;
1708 switch (fb_info
->currentmode
.var
.bits_per_pixel
) {
1710 #ifdef FBCON_HAS_CFB16
1712 assert (regno
< 16);
1714 fb_info
->fbcon_cmap
.cfb16
[regno
] =
1715 ((red
& 0xf800) >> 9) |
1716 ((green
& 0xf800) >> 14) |
1717 ((green
& 0xf800) << 2) |
1718 ((blue
& 0xf800) >> 3);
1720 fb_info
->fbcon_cmap
.cfb16
[regno
] =
1721 ((red
& 0xf800) >> 1) |
1722 ((green
& 0xf800) >> 6) |
1723 ((blue
& 0xf800) >> 11);
1725 #endif /* FBCON_HAS_CFB16 */
1727 #ifdef FBCON_HAS_CFB24
1729 assert (regno
< 16);
1730 fb_info
->fbcon_cmap
.cfb24
[regno
] =
1731 (red
<< fb_info
->currentmode
.var
.red
.offset
) |
1732 (green
<< fb_info
->currentmode
.var
.green
.offset
) |
1733 (blue
<< fb_info
->currentmode
.var
.blue
.offset
);
1735 #endif /* FBCON_HAS_CFB24 */
1737 #ifdef FBCON_HAS_CFB32
1739 assert (regno
< 16);
1741 fb_info
->fbcon_cmap
.cfb32
[regno
] =
1743 ((green
& 0xff00) << 8) |
1744 ((blue
& 0xff00) << 16);
1746 fb_info
->fbcon_cmap
.cfb32
[regno
] =
1747 ((red
& 0xff00) << 8) |
1748 ((green
& 0xff00)) |
1749 ((blue
& 0xff00) >> 8);
1752 #endif /* FBCON_HAS_CFB32 */
1761 /*************************************************************************
1764 performs display panning - provided hardware permits this
1765 **************************************************************************/
1766 static int clgen_pan_display (const struct fb_var_screeninfo
*var
,
1767 struct fb_info_gen
*info
)
1772 unsigned char tmp
= 0, tmp2
= 0, xpix
;
1773 struct clgenfb_info
*fb_info
= (struct clgenfb_info
*) info
;
1775 DPRINTK ("ENTER\n");
1777 /* no range checks for xoffset and yoffset, */
1778 /* as fbgen_pan_display has already done this */
1780 fb_info
->currentmode
.var
.xoffset
= var
->xoffset
;
1781 fb_info
->currentmode
.var
.yoffset
= var
->yoffset
;
1783 xoffset
= var
->xoffset
* fb_info
->currentmode
.var
.bits_per_pixel
/ 8;
1784 yoffset
= var
->yoffset
;
1786 base
= yoffset
* fb_info
->currentmode
.line_length
+ xoffset
;
1788 if (fb_info
->currentmode
.var
.bits_per_pixel
== 1) {
1789 /* base is already correct */
1790 xpix
= (unsigned char) (var
->xoffset
% 8);
1793 xpix
= (unsigned char) ((xoffset
% 4) * 2);
1796 /* lower 8 + 8 bits of screen start address */
1797 vga_wcrt (fb_info
->regs
, VGA_CRTC_START_LO
, (unsigned char) (base
& 0xff));
1798 vga_wcrt (fb_info
->regs
, VGA_CRTC_START_HI
, (unsigned char) (base
>> 8));
1800 /* construct bits 16, 17 and 18 of screen start address */
1808 tmp2
= (vga_rcrt (fb_info
->regs
, CL_CRT1B
) & 0xf2) | tmp
; /* 0xf2 is %11110010, exclude tmp bits */
1809 vga_wcrt (fb_info
->regs
, CL_CRT1B
, tmp2
);
1811 /* construct bit 19 of screen start address */
1812 if (clgen_board_info
[fb_info
->btype
].scrn_start_bit19
) {
1816 vga_wcrt (fb_info
->regs
, CL_CRT1D
, tmp2
);
1819 /* write pixel panning value to AR33; this does not quite work in 8bpp */
1820 /* ### Piccolo..? Will this work? */
1821 if (fb_info
->currentmode
.var
.bits_per_pixel
== 1)
1822 vga_wattr (fb_info
->regs
, CL_AR33
, xpix
);
1830 static int clgen_blank (int blank_mode
, struct fb_info_gen
*info
)
1833 * Blank the screen if blank_mode != 0, else unblank. If blank == NULL
1834 * then the caller blanks by setting the CLUT (Color Look Up Table) to all
1835 * black. Return 0 if blanking succeeded, != 0 if un-/blanking failed due
1836 * to e.g. a video mode which doesn't support it. Implements VESA suspend
1837 * and powerdown modes on hardware that supports disabling hsync/vsync:
1838 * blank_mode == 2: suspend vsync
1839 * blank_mode == 3: suspend hsync
1840 * blank_mode == 4: powerdown
1843 static int current_mode
= 0;
1844 struct clgenfb_info
*fb_info
= (struct clgenfb_info
*) info
;
1846 DPRINTK ("ENTER, blank mode = %d\n", blank_mode
);
1848 if (current_mode
== blank_mode
) {
1849 DPRINTK ("EXIT, returning 0\n");
1854 switch (current_mode
) {
1855 case 0: /* Screen is normal */
1857 case 1: /* Screen is blanked */
1858 val
= vga_rseq (fb_info
->regs
, VGA_SEQ_CLOCK_MODE
);
1859 vga_wseq (fb_info
->regs
, VGA_SEQ_CLOCK_MODE
, val
& 0xdf); /* clear "FullBandwidth" bit */
1861 case 2: /* vsync suspended */
1862 case 3: /* hsync suspended */
1863 case 4: /* sceen is powered down */
1864 vga_wgfx (fb_info
->regs
, CL_GRE
, 0x00);
1867 DPRINTK ("EXIT, returning 1\n");
1872 switch (blank_mode
) {
1873 case 0: /* Unblank screen */
1875 case 1: /* Blank screen */
1876 val
= vga_rseq (fb_info
->regs
, VGA_SEQ_CLOCK_MODE
);
1877 vga_wseq (fb_info
->regs
, VGA_SEQ_CLOCK_MODE
, val
| 0x20); /* set "FullBandwidth" bit */
1879 case 2: /* suspend vsync */
1880 vga_wgfx (fb_info
->regs
, CL_GRE
, 0x04);
1882 case 3: /* suspend hsync */
1883 vga_wgfx (fb_info
->regs
, CL_GRE
, 0x02);
1885 case 4: /* powerdown */
1886 vga_wgfx (fb_info
->regs
, CL_GRE
, 0x06);
1889 DPRINTK ("EXIT, returning 1\n");
1893 current_mode
= blank_mode
;
1894 DPRINTK ("EXIT, returning 0\n");
1897 /**** END Hardware specific Routines **************************************/
1898 /****************************************************************************/
1899 /**** BEGIN Internal Routines ***********************************************/
1901 static void __init
init_vgachip (struct clgenfb_info
*fb_info
)
1903 const struct clgen_board_info_rec
*bi
;
1905 DPRINTK ("ENTER\n");
1907 assert (fb_info
!= NULL
);
1909 bi
= &clgen_board_info
[fb_info
->btype
];
1911 /* reset board globally */
1912 switch (fb_info
->btype
) {
1914 WSFR (fb_info
, 0x01);
1916 WSFR (fb_info
, 0x51);
1920 WSFR2 (fb_info
, 0xff);
1925 WSFR (fb_info
, 0x1f);
1927 WSFR (fb_info
, 0x4f);
1931 vga_wcrt (fb_info
->regs
, CL_CRT51
, 0x00); /* disable flickerfixer */
1933 vga_wgfx (fb_info
->regs
, CL_GR2F
, 0x00); /* from Klaus' NetBSD driver: */
1934 vga_wgfx (fb_info
->regs
, CL_GR33
, 0x00); /* put blitter into 542x compat */
1935 vga_wgfx (fb_info
->regs
, CL_GR31
, 0x00); /* mode */
1939 vga_wgfx (fb_info
->regs
, CL_GR2F
, 0x00); /* from Klaus' NetBSD driver: */
1943 /* Nothing to do to reset the board. */
1947 printk (KERN_ERR
"clgen: Warning: Unknown board type\n");
1951 assert (fb_info
->size
> 0); /* make sure RAM size set by this point */
1953 /* assume it's a "large memory" board (2/4 MB) */
1954 fb_info
->smallboard
= FALSE
;
1956 /* the P4 is not fully initialized here; I rely on it having been */
1957 /* inited under AmigaOS already, which seems to work just fine */
1958 /* (Klaus advised to do it this way) */
1960 if (fb_info
->btype
!= BT_PICASSO4
) {
1961 WGen (fb_info
, CL_VSSM
, 0x10); /* EGS: 0x16 */
1962 WGen (fb_info
, CL_POS102
, 0x01);
1963 WGen (fb_info
, CL_VSSM
, 0x08); /* EGS: 0x0e */
1965 if (fb_info
->btype
!= BT_SD64
)
1966 WGen (fb_info
, CL_VSSM2
, 0x01);
1968 vga_wseq (fb_info
->regs
, CL_SEQR0
, 0x03); /* reset sequencer logic */
1970 vga_wseq (fb_info
->regs
, VGA_SEQ_CLOCK_MODE
, 0x21); /* FullBandwidth (video off) and 8/9 dot clock */
1971 WGen (fb_info
, VGA_MIS_W
, 0xc1); /* polarity (-/-), disable access to display memory, VGA_CRTC_START_HI base address: color */
1973 /* vga_wgfx (fb_info->regs, CL_GRA, 0xce); "magic cookie" - doesn't make any sense to me.. */
1974 vga_wseq (fb_info
->regs
, CL_SEQR6
, 0x12); /* unlock all extension registers */
1976 vga_wgfx (fb_info
->regs
, CL_GR31
, 0x04); /* reset blitter */
1978 switch (fb_info
->btype
) {
1980 vga_wseq (fb_info
->regs
, CL_SEQRF
, 0x98);
1985 vga_wseq (fb_info
->regs
, CL_SEQRF
, 0xb8);
1988 vga_wseq (fb_info
->regs
, CL_SEQR16
, 0x0f);
1989 vga_wseq (fb_info
->regs
, CL_SEQRF
, 0xb0);
1993 vga_wseq (fb_info
->regs
, VGA_SEQ_PLANE_WRITE
, 0xff); /* plane mask: nothing */
1994 vga_wseq (fb_info
->regs
, VGA_SEQ_CHARACTER_MAP
, 0x00); /* character map select: doesn't even matter in gx mode */
1995 vga_wseq (fb_info
->regs
, VGA_SEQ_MEMORY_MODE
, 0x0e); /* memory mode: chain-4, no odd/even, ext. memory */
1997 /* controller-internal base address of video memory */
1999 vga_wseq (fb_info
->regs
, CL_SEQR7
, bi
->sr07
);
2001 /* vga_wseq (fb_info->regs, CL_SEQR8, 0x00); *//* EEPROM control: shouldn't be necessary to write to this at all.. */
2003 vga_wseq (fb_info
->regs
, CL_SEQR10
, 0x00); /* graphics cursor X position (incomplete; position gives rem. 3 bits */
2004 vga_wseq (fb_info
->regs
, CL_SEQR11
, 0x00); /* graphics cursor Y position (..."... ) */
2005 vga_wseq (fb_info
->regs
, CL_SEQR12
, 0x00); /* graphics cursor attributes */
2006 vga_wseq (fb_info
->regs
, CL_SEQR13
, 0x00); /* graphics cursor pattern address */
2008 /* writing these on a P4 might give problems.. */
2009 if (fb_info
->btype
!= BT_PICASSO4
) {
2010 vga_wseq (fb_info
->regs
, CL_SEQR17
, 0x00); /* configuration readback and ext. color */
2011 vga_wseq (fb_info
->regs
, CL_SEQR18
, 0x02); /* signature generator */
2014 /* MCLK select etc. */
2016 vga_wseq (fb_info
->regs
, CL_SEQR1F
, bi
->sr1f
);
2018 vga_wcrt (fb_info
->regs
, VGA_CRTC_PRESET_ROW
, 0x00); /* Screen A preset row scan: none */
2019 vga_wcrt (fb_info
->regs
, VGA_CRTC_CURSOR_START
, 0x20); /* Text cursor start: disable text cursor */
2020 vga_wcrt (fb_info
->regs
, VGA_CRTC_CURSOR_END
, 0x00); /* Text cursor end: - */
2021 vga_wcrt (fb_info
->regs
, VGA_CRTC_START_HI
, 0x00); /* Screen start address high: 0 */
2022 vga_wcrt (fb_info
->regs
, VGA_CRTC_START_LO
, 0x00); /* Screen start address low: 0 */
2023 vga_wcrt (fb_info
->regs
, VGA_CRTC_CURSOR_HI
, 0x00); /* text cursor location high: 0 */
2024 vga_wcrt (fb_info
->regs
, VGA_CRTC_CURSOR_LO
, 0x00); /* text cursor location low: 0 */
2026 vga_wcrt (fb_info
->regs
, VGA_CRTC_UNDERLINE
, 0x00); /* Underline Row scanline: - */
2027 vga_wcrt (fb_info
->regs
, VGA_CRTC_MODE
, 0xc3); /* mode control: timing enable, byte mode, no compat modes */
2028 vga_wcrt (fb_info
->regs
, VGA_CRTC_LINE_COMPARE
, 0x00); /* Line Compare: not needed */
2029 /* ### add 0x40 for text modes with > 30 MHz pixclock */
2030 vga_wcrt (fb_info
->regs
, CL_CRT1B
, 0x02); /* ext. display controls: ext.adr. wrap */
2032 vga_wgfx (fb_info
->regs
, VGA_GFX_SR_VALUE
, 0x00); /* Set/Reset registes: - */
2033 vga_wgfx (fb_info
->regs
, VGA_GFX_SR_ENABLE
, 0x00); /* Set/Reset enable: - */
2034 vga_wgfx (fb_info
->regs
, VGA_GFX_COMPARE_VALUE
, 0x00); /* Color Compare: - */
2035 vga_wgfx (fb_info
->regs
, VGA_GFX_DATA_ROTATE
, 0x00); /* Data Rotate: - */
2036 vga_wgfx (fb_info
->regs
, VGA_GFX_PLANE_READ
, 0x00); /* Read Map Select: - */
2037 vga_wgfx (fb_info
->regs
, VGA_GFX_MODE
, 0x00); /* Mode: conf. for 16/4/2 color mode, no odd/even, read/write mode 0 */
2038 vga_wgfx (fb_info
->regs
, VGA_GFX_MISC
, 0x01); /* Miscellaneous: memory map base address, graphics mode */
2039 vga_wgfx (fb_info
->regs
, VGA_GFX_COMPARE_MASK
, 0x0f); /* Color Don't care: involve all planes */
2040 vga_wgfx (fb_info
->regs
, VGA_GFX_BIT_MASK
, 0xff); /* Bit Mask: no mask at all */
2041 if (fb_info
->btype
== BT_ALPINE
)
2042 vga_wgfx (fb_info
->regs
, CL_GRB
, 0x20); /* (5434 can't have bit 3 set for bitblt) */
2044 vga_wgfx (fb_info
->regs
, CL_GRB
, 0x28); /* Graphics controller mode extensions: finer granularity, 8byte data latches */
2046 vga_wgfx (fb_info
->regs
, CL_GRC
, 0xff); /* Color Key compare: - */
2047 vga_wgfx (fb_info
->regs
, CL_GRD
, 0x00); /* Color Key compare mask: - */
2048 vga_wgfx (fb_info
->regs
, CL_GRE
, 0x00); /* Miscellaneous control: - */
2049 /* vga_wgfx (fb_info->regs, CL_GR10, 0x00); *//* Background color byte 1: - */
2050 /* vga_wgfx (fb_info->regs, CL_GR11, 0x00); */
2052 vga_wattr (fb_info
->regs
, VGA_ATC_PALETTE0
, 0x00); /* Attribute Controller palette registers: "identity mapping" */
2053 vga_wattr (fb_info
->regs
, VGA_ATC_PALETTE1
, 0x01);
2054 vga_wattr (fb_info
->regs
, VGA_ATC_PALETTE2
, 0x02);
2055 vga_wattr (fb_info
->regs
, VGA_ATC_PALETTE3
, 0x03);
2056 vga_wattr (fb_info
->regs
, VGA_ATC_PALETTE4
, 0x04);
2057 vga_wattr (fb_info
->regs
, VGA_ATC_PALETTE5
, 0x05);
2058 vga_wattr (fb_info
->regs
, VGA_ATC_PALETTE6
, 0x06);
2059 vga_wattr (fb_info
->regs
, VGA_ATC_PALETTE7
, 0x07);
2060 vga_wattr (fb_info
->regs
, VGA_ATC_PALETTE8
, 0x08);
2061 vga_wattr (fb_info
->regs
, VGA_ATC_PALETTE9
, 0x09);
2062 vga_wattr (fb_info
->regs
, VGA_ATC_PALETTEA
, 0x0a);
2063 vga_wattr (fb_info
->regs
, VGA_ATC_PALETTEB
, 0x0b);
2064 vga_wattr (fb_info
->regs
, VGA_ATC_PALETTEC
, 0x0c);
2065 vga_wattr (fb_info
->regs
, VGA_ATC_PALETTED
, 0x0d);
2066 vga_wattr (fb_info
->regs
, VGA_ATC_PALETTEE
, 0x0e);
2067 vga_wattr (fb_info
->regs
, VGA_ATC_PALETTEF
, 0x0f);
2069 vga_wattr (fb_info
->regs
, VGA_ATC_MODE
, 0x01); /* Attribute Controller mode: graphics mode */
2070 vga_wattr (fb_info
->regs
, VGA_ATC_OVERSCAN
, 0x00); /* Overscan color reg.: reg. 0 */
2071 vga_wattr (fb_info
->regs
, VGA_ATC_PLANE_ENABLE
, 0x0f); /* Color Plane enable: Enable all 4 planes */
2072 /* ### vga_wattr (fb_info->regs, CL_AR33, 0x00); * Pixel Panning: - */
2073 vga_wattr (fb_info
->regs
, VGA_ATC_COLOR_PAGE
, 0x00); /* Color Select: - */
2075 WGen (fb_info
, VGA_PEL_MSK
, 0xff); /* Pixel mask: no mask */
2077 if (fb_info
->btype
!= BT_ALPINE
&& fb_info
->btype
!= BT_GD5480
)
2078 WGen (fb_info
, VGA_MIS_W
, 0xc3); /* polarity (-/-), enable display mem, VGA_CRTC_START_HI i/o base = color */
2080 vga_wgfx (fb_info
->regs
, CL_GR31
, 0x04); /* BLT Start/status: Blitter reset */
2081 vga_wgfx (fb_info
->regs
, CL_GR31
, 0x00); /* - " - : "end-of-reset" */
2084 WClut (fb_info
, 0, 0x00, 0x00, 0x00); /* background: black */
2085 WClut (fb_info
, 1, 0x3f, 0x3f, 0x3f); /* foreground: white */
2086 WClut (fb_info
, 2, 0x00, 0x20, 0x00);
2087 WClut (fb_info
, 3, 0x00, 0x20, 0x20);
2088 WClut (fb_info
, 4, 0x20, 0x00, 0x00);
2089 WClut (fb_info
, 5, 0x20, 0x00, 0x20);
2090 WClut (fb_info
, 6, 0x20, 0x10, 0x00);
2091 WClut (fb_info
, 7, 0x20, 0x20, 0x20);
2092 WClut (fb_info
, 8, 0x10, 0x10, 0x10);
2093 WClut (fb_info
, 9, 0x10, 0x10, 0x30);
2094 WClut (fb_info
, 10, 0x10, 0x30, 0x10);
2095 WClut (fb_info
, 11, 0x10, 0x30, 0x30);
2096 WClut (fb_info
, 12, 0x30, 0x10, 0x10);
2097 WClut (fb_info
, 13, 0x30, 0x10, 0x30);
2098 WClut (fb_info
, 14, 0x30, 0x30, 0x10);
2099 WClut (fb_info
, 15, 0x30, 0x30, 0x30);
2101 /* the rest a grey ramp */
2105 for (i
= 16; i
< 256; i
++)
2106 WClut (fb_info
, i
, i
>> 2, i
>> 2, i
>> 2);
2111 WHDR (fb_info
, 0); /* Hidden DAC register: - */
2113 printk (KERN_INFO
"clgen: This board has %ld bytes of DRAM memory\n", fb_info
->size
);
2118 static void switch_monitor (struct clgenfb_info
*fb_info
, int on
)
2120 #ifdef CONFIG_ZORRO /* only works on Zorro boards */
2121 static int IsOn
= 0; /* XXX not ok for multiple boards */
2123 DPRINTK ("ENTER\n");
2125 if (fb_info
->btype
== BT_PICASSO4
)
2126 return; /* nothing to switch */
2127 if (fb_info
->btype
== BT_ALPINE
)
2128 return; /* nothing to switch */
2129 if (fb_info
->btype
== BT_GD5480
)
2130 return; /* nothing to switch */
2131 if (fb_info
->btype
== BT_PICASSO
) {
2132 if ((on
&& !IsOn
) || (!on
&& IsOn
))
2133 WSFR (fb_info
, 0xff);
2139 switch (fb_info
->btype
) {
2141 WSFR (fb_info
, fb_info
->SFR
| 0x21);
2144 WSFR (fb_info
, fb_info
->SFR
| 0x28);
2147 WSFR (fb_info
, 0x6f);
2149 default: /* do nothing */ break;
2152 switch (fb_info
->btype
) {
2154 WSFR (fb_info
, fb_info
->SFR
& 0xde);
2157 WSFR (fb_info
, fb_info
->SFR
& 0xd7);
2160 WSFR (fb_info
, 0x4f);
2162 default: /* do nothing */ break;
2167 #endif /* CONFIG_ZORRO */
2170 static void clgen_set_disp (const void *par
, struct display
*disp
,
2171 struct fb_info_gen
*info
)
2173 struct clgenfb_par
*_par
= (struct clgenfb_par
*) par
;
2174 struct clgenfb_info
*fb_info
= (struct clgenfb_info
*) info
;
2177 DPRINTK ("ENTER\n");
2179 assert (_par
!= NULL
);
2180 assert (fb_info
!= NULL
);
2182 accel_text
= _par
->var
.accel_flags
& FB_ACCELF_TEXT
;
2184 printk ("Cirrus Logic video mode: ");
2185 info
->info
.screen_base
= (char *) fb_info
->fbmem
;
2186 switch (_par
->var
.bits_per_pixel
) {
2187 #ifdef FBCON_HAS_MFB
2189 printk ("monochrome\n");
2190 if (fb_info
->btype
== BT_GD5480
)
2191 info
->info
.screen_base
= (char *) fb_info
->fbmem
;
2192 disp
->dispsw
= &fbcon_mfb
;
2195 #ifdef FBCON_HAS_CFB8
2197 printk ("8 bit color depth\n");
2198 if (fb_info
->btype
== BT_GD5480
)
2199 info
->info
.screen_base
= (char *) fb_info
->fbmem
;
2201 disp
->dispsw
= &fbcon_clgen_8
;
2203 disp
->dispsw
= &fbcon_cfb8
;
2206 #ifdef FBCON_HAS_CFB16
2208 printk ("16 bit color depth\n");
2210 disp
->dispsw
= &fbcon_clgen_16
;
2212 disp
->dispsw
= &fbcon_cfb16
;
2213 if (fb_info
->btype
== BT_GD5480
)
2214 info
->info
.screen_base
= (char *) fb_info
->fbmem
+ 1 * MB_
;
2215 disp
->dispsw_data
= fb_info
->fbcon_cmap
.cfb16
;
2218 #ifdef FBCON_HAS_CFB24
2220 printk ("24 bit color depth\n");
2221 disp
->dispsw
= &fbcon_cfb24
;
2222 if (fb_info
->btype
== BT_GD5480
)
2223 info
->info
.screen_base
= (char *) fb_info
->fbmem
+ 2 * MB_
;
2224 disp
->dispsw_data
= fb_info
->fbcon_cmap
.cfb24
;
2227 #ifdef FBCON_HAS_CFB32
2229 printk ("32 bit color depth\n");
2231 disp
->dispsw
= &fbcon_clgen_32
;
2233 disp
->dispsw
= &fbcon_cfb32
;
2234 if (fb_info
->btype
== BT_GD5480
)
2235 info
->info
.screen_base
= (char *) fb_info
->fbmem
+ 2 * MB_
;
2236 disp
->dispsw_data
= fb_info
->fbcon_cmap
.cfb32
;
2241 printk ("unsupported color depth\n");
2242 disp
->dispsw
= &fbcon_dummy
;
2243 disp
->dispsw_data
= NULL
;
2250 #ifdef FBCON_HAS_CFB8
2251 static void fbcon_clgen8_bmove (struct display
*p
, int sy
, int sx
,
2252 int dy
, int dx
, int height
, int width
)
2254 struct clgenfb_info
*fb_info
= (struct clgenfb_info
*) p
->fb_info
;
2256 DPRINTK ("ENTER\n");
2258 sx
*= fontwidth (p
);
2259 sy
*= fontheight (p
);
2260 dx
*= fontwidth (p
);
2261 dy
*= fontheight (p
);
2262 width
*= fontwidth (p
);
2263 height
*= fontheight (p
);
2265 clgen_BitBLT (fb_info
->regs
, (unsigned short) sx
, (unsigned short) sy
,
2266 (unsigned short) dx
, (unsigned short) dy
,
2267 (unsigned short) width
, (unsigned short) height
,
2268 fb_info
->currentmode
.line_length
);
2273 static void fbcon_clgen8_clear (struct vc_data
*conp
, struct display
*p
,
2274 int sy
, int sx
, int height
, int width
)
2276 struct clgenfb_info
*fb_info
= (struct clgenfb_info
*) p
->fb_info
;
2279 DPRINTK ("ENTER\n");
2281 sx
*= fontwidth (p
);
2282 sy
*= fontheight (p
);
2283 width
*= fontwidth (p
);
2284 height
*= fontheight (p
);
2286 col
= attr_bgcol_ec (p
, conp
);
2289 clgen_RectFill (fb_info
, (unsigned short) sx
, (unsigned short) sy
,
2290 (unsigned short) width
, (unsigned short) height
,
2291 col
, fb_info
->currentmode
.line_length
);
2298 #ifdef FBCON_HAS_CFB16
2299 static void fbcon_clgen16_bmove (struct display
*p
, int sy
, int sx
,
2300 int dy
, int dx
, int height
, int width
)
2302 struct clgenfb_info
*fb_info
= (struct clgenfb_info
*) p
->fb_info
;
2304 DPRINTK ("ENTER\n");
2306 sx
*= fontwidth (p
) * 2; /* 2 bytes/pixel */
2307 sy
*= fontheight (p
);
2308 dx
*= fontwidth (p
) * 2; /* 2 bytes/pixel */
2309 dy
*= fontheight (p
);
2310 width
*= fontwidth (p
) * 2; /* 2 bytes/pixel */
2311 height
*= fontheight (p
);
2313 clgen_BitBLT (fb_info
->regs
, (unsigned short) sx
, (unsigned short) sy
,
2314 (unsigned short) dx
, (unsigned short) dy
,
2315 (unsigned short) width
, (unsigned short) height
,
2316 fb_info
->currentmode
.line_length
);
2321 static void fbcon_clgen16_clear (struct vc_data
*conp
, struct display
*p
,
2322 int sy
, int sx
, int height
, int width
)
2324 struct clgenfb_info
*fb_info
= (struct clgenfb_info
*) p
->fb_info
;
2327 DPRINTK ("ENTER\n");
2329 sx
*= fontwidth (p
) * 2; /* 2 bytes/pixel */
2330 sy
*= fontheight (p
);
2331 width
*= fontwidth (p
) * 2; /* 2 bytes/pixel? */
2332 height
*= fontheight (p
);
2334 col
= attr_bgcol_ec (p
, conp
);
2337 clgen_RectFill (fb_info
, (unsigned short) sx
, (unsigned short) sy
,
2338 (unsigned short) width
, (unsigned short) height
,
2339 col
, fb_info
->currentmode
.line_length
);
2346 #ifdef FBCON_HAS_CFB32
2347 static void fbcon_clgen32_bmove (struct display
*p
, int sy
, int sx
,
2348 int dy
, int dx
, int height
, int width
)
2350 struct clgenfb_info
*fb_info
= (struct clgenfb_info
*) p
->fb_info
;
2352 DPRINTK ("ENTER\n");
2354 sx
*= fontwidth (p
) * 4; /* 4 bytes/pixel */
2355 sy
*= fontheight (p
);
2356 dx
*= fontwidth (p
) * 4; /* 4 bytes/pixel */
2357 dy
*= fontheight (p
);
2358 width
*= fontwidth (p
) * 4; /* 4 bytes/pixel */
2359 height
*= fontheight (p
);
2361 clgen_BitBLT (fb_info
->regs
, (unsigned short) sx
, (unsigned short) sy
,
2362 (unsigned short) dx
, (unsigned short) dy
,
2363 (unsigned short) width
, (unsigned short) height
,
2364 fb_info
->currentmode
.line_length
);
2369 static void fbcon_clgen32_clear (struct vc_data
*conp
, struct display
*p
,
2370 int sy
, int sx
, int height
, int width
)
2372 struct clgenfb_info
*fb_info
= (struct clgenfb_info
*) p
->fb_info
;
2376 DPRINTK ("ENTER\n");
2378 sx
*= fontwidth (p
) * 4; /* 4 bytes/pixel */
2379 sy
*= fontheight (p
);
2380 width
*= fontwidth (p
) * 4; /* 4 bytes/pixel? */
2381 height
*= fontheight (p
);
2383 col
= attr_bgcol_ec (p
, conp
);
2386 clgen_RectFill (fb_info
, (unsigned short) sx
, (unsigned short) sy
,
2387 (unsigned short) width
, (unsigned short) height
,
2388 col
, fb_info
->currentmode
.line_length
);
2393 #endif /* FBCON_HAS_CFB32 */
2398 #ifdef CONFIG_PPC_PREP
2399 #define PREP_VIDEO_BASE ((volatile unsigned long) 0xC0000000)
2400 #define PREP_IO_BASE ((volatile unsigned char *) 0x80000000)
2401 static void __init
get_prep_addrs (unsigned long *display
, unsigned long *registers
)
2403 DPRINTK ("ENTER\n");
2405 *display
= PREP_VIDEO_BASE
;
2406 *registers
= (unsigned long) PREP_IO_BASE
;
2411 #endif /* CONFIG_PPC_PREP */
2417 static int release_io_ports
= 0;
2419 /* Pulled the logic from XFree86 Cirrus driver to get the memory size,
2420 * based on the DRAM bandwidth bit and DRAM bank switching bit. This
2421 * works with 1MB, 2MB and 4MB configurations (which the Motorola boards
2423 static unsigned int __init
clgen_get_memsize (caddr_t regbase
)
2428 DPRINTK ("ENTER\n");
2430 SRF
= vga_rseq (regbase
, CL_SEQRF
);
2431 switch ((SRF
& 0x18)) {
2432 case 0x08: mem
= 512 * 1024; break;
2433 case 0x10: mem
= 1024 * 1024; break;
2434 /* 64-bit DRAM data bus width; assume 2MB. Also indicates 2MB memory
2436 case 0x18: mem
= 2048 * 1024; break;
2437 default: printk ("CLgenfb: Unknown memory size!\n");
2441 /* If DRAM bank switching is enabled, there must be twice as much
2442 * memory installed. (4MB on the 5434) */
2445 /* TODO: Handling of GD5446/5480 (see XF86 sources ...) */
2453 static struct pci_dev
* __init
clgen_pci_dev_get (clgen_board_t
*btype
)
2455 struct pci_dev
*pdev
;
2458 DPRINTK ("ENTER\n");
2460 for (i
= 0; i
< ARRAY_SIZE(clgen_pci_probe_list
); i
++) {
2462 while ((pdev
= pci_find_device (PCI_VENDOR_ID_CIRRUS
,
2463 clgen_pci_probe_list
[i
].device
, pdev
)) != NULL
) {
2464 if (pci_enable_device(pdev
) == 0) {
2465 *btype
= clgen_pci_probe_list
[i
].btype
;
2466 DPRINTK ("EXIT, returning pdev=%p\n", pdev
);
2472 DPRINTK ("EXIT, returning NULL\n");
2479 static void __init
get_pci_addrs (const struct pci_dev
*pdev
,
2480 unsigned long *display
, unsigned long *registers
)
2482 assert (pdev
!= NULL
);
2483 assert (display
!= NULL
);
2484 assert (registers
!= NULL
);
2486 DPRINTK ("ENTER\n");
2491 /* This is a best-guess for now */
2493 if (pci_resource_flags(pdev
, 0) & IORESOURCE_IO
) {
2494 *display
= pci_resource_start(pdev
, 1);
2495 *registers
= pci_resource_start(pdev
, 0);
2497 *display
= pci_resource_start(pdev
, 0);
2498 *registers
= pci_resource_start(pdev
, 1);
2501 assert (*display
!= 0);
2507 static void __exit
clgen_pci_unmap (struct clgenfb_info
*info
)
2509 iounmap (info
->fbmem
);
2510 release_mem_region(info
->fbmem_phys
, info
->size
);
2512 #if 0 /* if system didn't claim this region, we would... */
2513 release_mem_region(0xA0000, 65535);
2516 if (release_io_ports
)
2517 release_region(0x3C0, 32);
2521 static int __init
clgen_pci_setup (struct clgenfb_info
*info
,
2522 clgen_board_t
*btype
)
2524 struct pci_dev
*pdev
;
2525 unsigned long board_addr
, board_size
;
2527 DPRINTK ("ENTER\n");
2529 pdev
= clgen_pci_dev_get (btype
);
2531 printk (KERN_ERR
" Couldn't find PCI device\n");
2532 DPRINTK ("EXIT, returning 1\n");
2535 DPRINTK (" Found PCI device, base address 0 is 0x%lx, btype set to %d\n",
2536 pdev
->resource
[0].start
, *btype
);
2537 DPRINTK (" base address 1 is 0x%lx\n", pdev
->resource
[1].start
);
2542 /* Xbh does this, though 0 seems to be the init value */
2543 pcibios_write_config_dword (0, pdev
->devfn
, PCI_BASE_ADDRESS_0
,
2546 #ifdef CONFIG_PPC_PREP
2547 get_prep_addrs (&board_addr
, &info
->fbregs_phys
);
2550 DPRINTK ("Attempt to get PCI info for Cirrus Graphics Card\n");
2551 get_pci_addrs (pdev
, &board_addr
, &info
->fbregs_phys
);
2554 DPRINTK ("Board address: 0x%lx, register address: 0x%lx\n", board_addr
, info
->fbregs_phys
);
2557 /* PReP dies if we ioremap the IO registers, but it works w/out... */
2558 info
->regs
= (char *) info
->fbregs_phys
;
2560 info
->regs
= 0; /* FIXME: this forces VGA. alternatives? */
2562 if (*btype
== BT_GD5480
) {
2563 board_size
= 32 * MB_
;
2565 board_size
= clgen_get_memsize (info
->regs
);
2568 if (!request_mem_region(board_addr
, board_size
, "clgenfb")) {
2569 printk(KERN_ERR
"clgen: cannot reserve region 0x%lx, abort\n",
2573 #if 0 /* if the system didn't claim this region, we would... */
2574 if (!request_mem_region(0xA0000, 65535, "clgenfb")) {
2575 printk(KERN_ERR
"clgen: cannot reserve region 0x%lx, abort\n",
2577 release_mem_region(board_addr
, board_size
);
2581 if (request_region(0x3C0, 32, "clgenfb"))
2582 release_io_ports
= 1;
2584 info
->fbmem
= ioremap (board_addr
, board_size
);
2585 info
->fbmem_phys
= board_addr
;
2586 info
->size
= board_size
;
2588 printk (" RAM (%lu kB) at 0x%lx, ", info
->size
/ KB_
, board_addr
);
2590 printk ("Cirrus Logic chipset on PCI bus\n");
2592 DPRINTK ("EXIT, returning 0\n");
2595 #endif /* CONFIG_PCI */
2601 static int __init
clgen_zorro_find (struct zorro_dev
**z_o
,
2602 struct zorro_dev
**z2_o
,
2603 clgen_board_t
*btype
, unsigned long *size
)
2605 struct zorro_dev
*z
= NULL
;
2608 assert (z_o
!= NULL
);
2609 assert (btype
!= NULL
);
2611 for (i
= 0; i
< ARRAY_SIZE(clgen_zorro_probe_list
); i
++)
2612 if ((z
= zorro_find_device(clgen_zorro_probe_list
[i
].id
, NULL
)))
2617 if (clgen_zorro_probe_list
[i
].id2
)
2618 *z2_o
= zorro_find_device(clgen_zorro_probe_list
[i
].id2
, NULL
);
2622 *btype
= clgen_zorro_probe_list
[i
].btype
;
2623 *size
= clgen_zorro_probe_list
[i
].size
;
2625 printk (KERN_INFO
"clgen: %s board detected; ",
2626 clgen_board_info
[*btype
].name
);
2631 printk (KERN_NOTICE
"clgen: no supported board found.\n");
2636 static void __exit
clgen_zorro_unmap (struct clgenfb_info
*info
)
2638 release_mem_region(info
->board_addr
, info
->board_size
);
2640 if (info
->btype
== BT_PICASSO4
) {
2641 iounmap ((void *)info
->board_addr
);
2642 iounmap ((void *)info
->fbmem_phys
);
2644 if (info
->board_addr
> 0x01000000)
2645 iounmap ((void *)info
->board_addr
);
2650 static int __init
clgen_zorro_setup (struct clgenfb_info
*info
,
2651 clgen_board_t
*btype
)
2653 struct zorro_dev
*z
= NULL
, *z2
= NULL
;
2654 unsigned long board_addr
, board_size
, size
;
2656 assert (info
!= NULL
);
2657 assert (btype
!= NULL
);
2659 if (clgen_zorro_find (&z
, &z2
, btype
, &size
))
2664 assert (*btype
!= BT_NONE
);
2666 info
->board_addr
= board_addr
= z
->resource
.start
;
2667 info
->board_size
= board_size
= z
->resource
.end
-z
->resource
.start
+1;
2670 if (!request_mem_region(board_addr
, board_size
, "clgenfb")) {
2671 printk(KERN_ERR
"clgen: cannot reserve region 0x%lx, abort\n",
2676 printk (" RAM (%lu MB) at $%lx, ", board_size
/ MB_
, board_addr
);
2678 if (*btype
== BT_PICASSO4
) {
2679 printk (" REG at $%lx\n", board_addr
+ 0x600000);
2681 /* To be precise, for the P4 this is not the */
2682 /* begin of the board, but the begin of RAM. */
2683 /* for P4, map in its address space in 2 chunks (### TEST! ) */
2684 /* (note the ugly hardcoded 16M number) */
2685 info
->regs
= ioremap (board_addr
, 16777216);
2686 DPRINTK ("clgen: Virtual address for board set to: $%p\n", info
->regs
);
2687 info
->regs
+= 0x600000;
2688 info
->fbregs_phys
= board_addr
+ 0x600000;
2690 info
->fbmem_phys
= board_addr
+ 16777216;
2691 info
->fbmem
= ioremap (info
->fbmem_phys
, 16777216);
2693 printk (" REG at $%lx\n", (unsigned long) z2
->resource
.start
);
2695 info
->fbmem_phys
= board_addr
;
2696 if (board_addr
> 0x01000000)
2697 info
->fbmem
= ioremap (board_addr
, board_size
);
2699 info
->fbmem
= (caddr_t
) ZTWO_VADDR (board_addr
);
2701 /* set address for REG area of board */
2702 info
->regs
= (caddr_t
) ZTWO_VADDR (z2
->resource
.start
);
2703 info
->fbregs_phys
= z2
->resource
.start
;
2705 DPRINTK ("clgen: Virtual address for board set to: $%p\n", info
->regs
);
2708 printk (KERN_INFO
"Cirrus Logic chipset on Zorro bus\n");
2712 #endif /* CONFIG_ZORRO */
2716 /********************************************************************/
2717 /* clgenfb_init() - master initialization function */
2718 /********************************************************************/
2719 int __init
clgenfb_init(void)
2723 clgen_board_t btype
= BT_NONE
;
2724 struct clgenfb_info
*fb_info
= NULL
;
2726 DPRINTK ("ENTER\n");
2728 printk (KERN_INFO
"clgen: Driver for Cirrus Logic based graphic boards, v" CLGEN_VERSION
"\n");
2730 fb_info
= &boards
[0]; /* FIXME support multiple boards ... */
2733 if (clgen_pci_setup (fb_info
, &btype
)) { /* Also does OF setup */
2734 DPRINTK ("EXIT, returning -ENXIO\n");
2738 #elif defined(CONFIG_ZORRO)
2739 /* FIXME: CONFIG_PCI and CONFIG_ZORRO may both be defined */
2740 if (clgen_zorro_setup (fb_info
, &btype
)) {
2741 DPRINTK ("EXIT, returning -ENXIO\n");
2746 #error This driver requires Zorro or PCI bus.
2747 #endif /* !CONFIG_PCI, !CONFIG_ZORRO */
2750 assert (btype
!= BT_NONE
);
2751 assert (btype
== clgen_board_info
[btype
].btype
);
2753 fb_info
->btype
= btype
;
2755 DPRINTK ("clgen: (RAM start set to: 0x%p)\n", fb_info
->fbmem
);
2759 printk("clgen: disabling text acceleration support\n");
2760 #ifdef FBCON_HAS_CFB8
2761 fbcon_clgen_8
.bmove
= fbcon_cfb8_bmove
;
2762 fbcon_clgen_8
.clear
= fbcon_cfb8_clear
;
2764 #ifdef FBCON_HAS_CFB16
2765 fbcon_clgen_16
.bmove
= fbcon_cfb16_bmove
;
2766 fbcon_clgen_16
.clear
= fbcon_cfb16_clear
;
2768 #ifdef FBCON_HAS_CFB32
2769 fbcon_clgen_32
.bmove
= fbcon_cfb32_bmove
;
2770 fbcon_clgen_32
.clear
= fbcon_cfb32_clear
;
2774 init_vgachip (fb_info
);
2776 /* set up a few more things, register framebuffer driver etc */
2777 fb_info
->gen
.parsize
= sizeof (struct clgenfb_par
);
2778 fb_info
->gen
.fbhw
= &clgen_hwswitch
;
2780 strlcpy (fb_info
->gen
.info
.modename
, clgen_board_info
[btype
].name
,
2781 sizeof (fb_info
->gen
.info
.modename
));
2783 fb_info
->gen
.info
.fbops
= &clgenfb_ops
;
2784 fb_info
->gen
.info
.disp
= &disp
;
2785 fb_info
->gen
.info
.currcon
= -1;
2786 fb_info
->gen
.info
.changevar
= NULL
;
2787 fb_info
->gen
.info
.switch_con
= &fbgen_switch
;
2788 fb_info
->gen
.info
.updatevar
= &fbgen_update_var
;
2789 fb_info
->gen
.info
.flags
= FBINFO_FLAG_DEFAULT
;
2791 for (j
= 0; j
< 256; j
++) {
2794 fb_info
->palette
[j
].red
= default_red
[k
];
2795 fb_info
->palette
[j
].green
= default_grn
[k
];
2796 fb_info
->palette
[j
].blue
= default_blu
[k
];
2798 fb_info
->palette
[j
].red
=
2799 fb_info
->palette
[j
].green
=
2800 fb_info
->palette
[j
].blue
= j
;
2804 /* now that we know the board has been registered n' stuff, we */
2805 /* can finally initialize it to a default mode */
2806 clgenfb_default
= clgenfb_predefined
[clgen_def_mode
].var
;
2807 clgenfb_default
.activate
= FB_ACTIVATE_NOW
;
2808 clgenfb_default
.yres_virtual
= 480 * 3; /* for fast scrolling (YPAN-Mode) */
2809 err
= fbgen_do_set_var (&clgenfb_default
, 1, &fb_info
->gen
);
2812 DPRINTK ("EXIT, returning -EINVAL\n");
2816 disp
.var
= clgenfb_default
;
2817 fbgen_set_disp (-1, &fb_info
->gen
);
2818 do_install_cmap (0, &fb_info
->gen
.info
);
2820 err
= register_framebuffer (&fb_info
->gen
.info
);
2822 printk (KERN_ERR
"clgen: ERROR - could not register fb device; err = %d!\n", err
);
2823 DPRINTK ("EXIT, returning -EINVAL\n");
2826 DPRINTK ("EXIT, returning 0\n");
2833 * Cleanup (only needed for module)
2835 static void __exit
clgenfb_cleanup (struct clgenfb_info
*info
)
2837 DPRINTK ("ENTER\n");
2840 switch_monitor (info
, 0);
2842 clgen_zorro_unmap (info
);
2844 clgen_pci_unmap (info
);
2845 #endif /* CONFIG_ZORRO */
2847 unregister_framebuffer ((struct fb_info
*) info
);
2848 printk ("Framebuffer unregistered\n");
2855 int __init
clgenfb_setup(char *options
) {
2856 char *this_opt
, s
[32];
2859 DPRINTK ("ENTER\n");
2861 if (!options
|| !*options
)
2864 while ((this_opt
= strsep (&options
, ",")) != NULL
) {
2865 if (!*this_opt
) continue;
2867 DPRINTK("clgenfb_setup: option '%s'\n", this_opt
);
2869 for (i
= 0; i
< NUM_TOTAL_MODES
; i
++) {
2870 sprintf (s
, "mode:%s", clgenfb_predefined
[i
].name
);
2871 if (strcmp (this_opt
, s
) == 0)
2874 if (!strcmp(this_opt
, "noaccel"))
2886 MODULE_AUTHOR("Copyright 1999,2000 Jeff Garzik <jgarzik@pobox.com>");
2887 MODULE_DESCRIPTION("Accelerated FBDev driver for Cirrus Logic chips");
2888 MODULE_LICENSE("GPL");
2890 static void __exit
clgenfb_exit (void)
2892 DPRINTK ("ENTER\n");
2894 clgenfb_cleanup (&boards
[0]); /* FIXME: support multiple boards */
2900 module_init(clgenfb_init
);
2902 module_exit(clgenfb_exit
);
2905 /**********************************************************************/
2906 /* about the following functions - I have used the same names for the */
2907 /* functions as Markus Wild did in his Retina driver for NetBSD as */
2908 /* they just made sense for this purpose. Apart from that, I wrote */
2909 /* these functions myself. */
2910 /**********************************************************************/
2912 /*** WGen() - write into one of the external/general registers ***/
2913 static void WGen (const struct clgenfb_info
*fb_info
,
2914 int regnum
, unsigned char val
)
2916 unsigned long regofs
= 0;
2918 if (fb_info
->btype
== BT_PICASSO
) {
2919 /* Picasso II specific hack */
2920 /* if (regnum == VGA_PEL_IR || regnum == VGA_PEL_D || regnum == CL_VSSM2) */
2921 if (regnum
== VGA_PEL_IR
|| regnum
== VGA_PEL_D
)
2925 vga_w (fb_info
->regs
, regofs
+ regnum
, val
);
2928 /*** RGen() - read out one of the external/general registers ***/
2929 static unsigned char RGen (const struct clgenfb_info
*fb_info
, int regnum
)
2931 unsigned long regofs
= 0;
2933 if (fb_info
->btype
== BT_PICASSO
) {
2934 /* Picasso II specific hack */
2935 /* if (regnum == VGA_PEL_IR || regnum == VGA_PEL_D || regnum == CL_VSSM2) */
2936 if (regnum
== VGA_PEL_IR
|| regnum
== VGA_PEL_D
)
2940 return vga_r (fb_info
->regs
, regofs
+ regnum
);
2943 /*** AttrOn() - turn on VideoEnable for Attribute controller ***/
2944 static void AttrOn (const struct clgenfb_info
*fb_info
)
2946 assert (fb_info
!= NULL
);
2948 DPRINTK ("ENTER\n");
2950 if (vga_rcrt (fb_info
->regs
, CL_CRT24
) & 0x80) {
2951 /* if we're just in "write value" mode, write back the */
2952 /* same value as before to not modify anything */
2953 vga_w (fb_info
->regs
, VGA_ATT_IW
,
2954 vga_r (fb_info
->regs
, VGA_ATT_R
));
2956 /* turn on video bit */
2957 /* vga_w (fb_info->regs, VGA_ATT_IW, 0x20); */
2958 vga_w (fb_info
->regs
, VGA_ATT_IW
, 0x33);
2960 /* dummy write on Reg0 to be on "write index" mode next time */
2961 vga_w (fb_info
->regs
, VGA_ATT_IW
, 0x00);
2966 /*** WHDR() - write into the Hidden DAC register ***/
2967 /* as the HDR is the only extension register that requires special treatment
2968 * (the other extension registers are accessible just like the "ordinary"
2969 * registers of their functional group) here is a specialized routine for
2972 static void WHDR (const struct clgenfb_info
*fb_info
, unsigned char val
)
2974 unsigned char dummy
;
2976 if (fb_info
->btype
== BT_PICASSO
) {
2977 /* Klaus' hint for correct access to HDR on some boards */
2978 /* first write 0 to pixel mask (3c6) */
2979 WGen (fb_info
, VGA_PEL_MSK
, 0x00);
2981 /* next read dummy from pixel address (3c8) */
2982 dummy
= RGen (fb_info
, VGA_PEL_IW
);
2985 /* now do the usual stuff to access the HDR */
2987 dummy
= RGen (fb_info
, VGA_PEL_MSK
);
2989 dummy
= RGen (fb_info
, VGA_PEL_MSK
);
2991 dummy
= RGen (fb_info
, VGA_PEL_MSK
);
2993 dummy
= RGen (fb_info
, VGA_PEL_MSK
);
2996 WGen (fb_info
, VGA_PEL_MSK
, val
);
2999 if (fb_info
->btype
== BT_PICASSO
) {
3000 /* now first reset HDR access counter */
3001 dummy
= RGen (fb_info
, VGA_PEL_IW
);
3004 /* and at the end, restore the mask value */
3005 /* ## is this mask always 0xff? */
3006 WGen (fb_info
, VGA_PEL_MSK
, 0xff);
3012 /*** WSFR() - write to the "special function register" (SFR) ***/
3013 static void WSFR (struct clgenfb_info
*fb_info
, unsigned char val
)
3016 assert (fb_info
->regs
!= NULL
);
3018 z_writeb (val
, fb_info
->regs
+ 0x8000);
3022 /* The Picasso has a second register for switching the monitor bit */
3023 static void WSFR2 (struct clgenfb_info
*fb_info
, unsigned char val
)
3026 /* writing an arbitrary value to this one causes the monitor switcher */
3027 /* to flip to Amiga display */
3028 assert (fb_info
->regs
!= NULL
);
3030 z_writeb (val
, fb_info
->regs
+ 0x9000);
3035 /*** WClut - set CLUT entry (range: 0..63) ***/
3036 static void WClut (struct clgenfb_info
*fb_info
, unsigned char regnum
, unsigned char red
,
3037 unsigned char green
, unsigned char blue
)
3039 unsigned int data
= VGA_PEL_D
;
3041 /* address write mode register is not translated.. */
3042 vga_w (fb_info
->regs
, VGA_PEL_IW
, regnum
);
3044 if (fb_info
->btype
== BT_PICASSO
|| fb_info
->btype
== BT_PICASSO4
||
3045 fb_info
->btype
== BT_ALPINE
|| fb_info
->btype
== BT_GD5480
) {
3046 /* but DAC data register IS, at least for Picasso II */
3047 if (fb_info
->btype
== BT_PICASSO
)
3049 vga_w (fb_info
->regs
, data
, red
);
3050 vga_w (fb_info
->regs
, data
, green
);
3051 vga_w (fb_info
->regs
, data
, blue
);
3053 vga_w (fb_info
->regs
, data
, blue
);
3054 vga_w (fb_info
->regs
, data
, green
);
3055 vga_w (fb_info
->regs
, data
, red
);
3061 /*** RClut - read CLUT entry (range 0..63) ***/
3062 static void RClut (struct clgenfb_info
*fb_info
, unsigned char regnum
, unsigned char *red
,
3063 unsigned char *green
, unsigned char *blue
)
3065 unsigned int data
= VGA_PEL_D
;
3067 vga_w (fb_info
->regs
, VGA_PEL_IR
, regnum
);
3069 if (fb_info
->btype
== BT_PICASSO
|| fb_info
->btype
== BT_PICASSO4
||
3070 fb_info
->btype
== BT_ALPINE
|| fb_info
->btype
== BT_GD5480
) {
3071 if (fb_info
->btype
== BT_PICASSO
)
3073 *red
= vga_r (fb_info
->regs
, data
);
3074 *green
= vga_r (fb_info
->regs
, data
);
3075 *blue
= vga_r (fb_info
->regs
, data
);
3077 *blue
= vga_r (fb_info
->regs
, data
);
3078 *green
= vga_r (fb_info
->regs
, data
);
3079 *red
= vga_r (fb_info
->regs
, data
);
3085 /*******************************************************************
3088 Wait for the BitBLT engine to complete a possible earlier job
3089 *********************************************************************/
3091 /* FIXME: use interrupts instead */
3092 extern inline void clgen_WaitBLT (caddr_t regbase
)
3094 /* now busy-wait until we're done */
3095 while (vga_rgfx (regbase
, CL_GR31
) & 0x08)
3099 /*******************************************************************
3102 perform accelerated "scrolling"
3103 ********************************************************************/
3105 static void clgen_BitBLT (caddr_t regbase
, u_short curx
, u_short cury
, u_short destx
, u_short desty
,
3106 u_short width
, u_short height
, u_short line_length
)
3108 u_short nwidth
, nheight
;
3112 DPRINTK ("ENTER\n");
3115 nheight
= height
- 1;
3118 /* if source adr < dest addr, do the Blt backwards */
3119 if (cury
<= desty
) {
3120 if (cury
== desty
) {
3121 /* if src and dest are on the same line, check x */
3128 /* standard case: forward blitting */
3129 nsrc
= (cury
* line_length
) + curx
;
3130 ndest
= (desty
* line_length
) + destx
;
3132 /* this means start addresses are at the end, counting backwards */
3133 nsrc
= cury
* line_length
+ curx
+ nheight
* line_length
+ nwidth
;
3134 ndest
= desty
* line_length
+ destx
+ nheight
* line_length
+ nwidth
;
3137 clgen_WaitBLT(regbase
);
3140 run-down of registers to be programmed:
3148 VGA_GFX_SR_VALUE / VGA_GFX_SR_ENABLE: "fill color"
3152 /* pitch: set to line_length */
3153 vga_wgfx (regbase
, CL_GR24
, line_length
& 0xff); /* dest pitch low */
3154 vga_wgfx (regbase
, CL_GR25
, (line_length
>> 8)); /* dest pitch hi */
3155 vga_wgfx (regbase
, CL_GR26
, line_length
& 0xff); /* source pitch low */
3156 vga_wgfx (regbase
, CL_GR27
, (line_length
>> 8)); /* source pitch hi */
3158 /* BLT width: actual number of pixels - 1 */
3159 vga_wgfx (regbase
, CL_GR20
, nwidth
& 0xff); /* BLT width low */
3160 vga_wgfx (regbase
, CL_GR21
, (nwidth
>> 8)); /* BLT width hi */
3162 /* BLT height: actual number of lines -1 */
3163 vga_wgfx (regbase
, CL_GR22
, nheight
& 0xff); /* BLT height low */
3164 vga_wgfx (regbase
, CL_GR23
, (nheight
>> 8)); /* BLT width hi */
3166 /* BLT destination */
3167 vga_wgfx (regbase
, CL_GR28
, (u_char
) (ndest
& 0xff)); /* BLT dest low */
3168 vga_wgfx (regbase
, CL_GR29
, (u_char
) (ndest
>> 8)); /* BLT dest mid */
3169 vga_wgfx (regbase
, CL_GR2A
, (u_char
) (ndest
>> 16)); /* BLT dest hi */
3172 vga_wgfx (regbase
, CL_GR2C
, (u_char
) (nsrc
& 0xff)); /* BLT src low */
3173 vga_wgfx (regbase
, CL_GR2D
, (u_char
) (nsrc
>> 8)); /* BLT src mid */
3174 vga_wgfx (regbase
, CL_GR2E
, (u_char
) (nsrc
>> 16)); /* BLT src hi */
3177 vga_wgfx (regbase
, CL_GR30
, bltmode
); /* BLT mode */
3179 /* BLT ROP: SrcCopy */
3180 vga_wgfx (regbase
, CL_GR32
, 0x0d); /* BLT ROP */
3182 /* and finally: GO! */
3183 vga_wgfx (regbase
, CL_GR31
, 0x02); /* BLT Start/status */
3189 /*******************************************************************
3192 perform accelerated rectangle fill
3193 ********************************************************************/
3195 static void clgen_RectFill (struct clgenfb_info
*fb_info
,
3196 u_short x
, u_short y
, u_short width
, u_short height
,
3197 u_char color
, u_short line_length
)
3199 u_short nwidth
, nheight
;
3203 DPRINTK ("ENTER\n");
3206 nheight
= height
- 1;
3208 ndest
= (y
* line_length
) + x
;
3210 clgen_WaitBLT(fb_info
->regs
);
3212 /* pitch: set to line_length */
3213 vga_wgfx (fb_info
->regs
, CL_GR24
, line_length
& 0xff); /* dest pitch low */
3214 vga_wgfx (fb_info
->regs
, CL_GR25
, (line_length
>> 8)); /* dest pitch hi */
3215 vga_wgfx (fb_info
->regs
, CL_GR26
, line_length
& 0xff); /* source pitch low */
3216 vga_wgfx (fb_info
->regs
, CL_GR27
, (line_length
>> 8)); /* source pitch hi */
3218 /* BLT width: actual number of pixels - 1 */
3219 vga_wgfx (fb_info
->regs
, CL_GR20
, nwidth
& 0xff); /* BLT width low */
3220 vga_wgfx (fb_info
->regs
, CL_GR21
, (nwidth
>> 8)); /* BLT width hi */
3222 /* BLT height: actual number of lines -1 */
3223 vga_wgfx (fb_info
->regs
, CL_GR22
, nheight
& 0xff); /* BLT height low */
3224 vga_wgfx (fb_info
->regs
, CL_GR23
, (nheight
>> 8)); /* BLT width hi */
3226 /* BLT destination */
3227 vga_wgfx (fb_info
->regs
, CL_GR28
, (u_char
) (ndest
& 0xff)); /* BLT dest low */
3228 vga_wgfx (fb_info
->regs
, CL_GR29
, (u_char
) (ndest
>> 8)); /* BLT dest mid */
3229 vga_wgfx (fb_info
->regs
, CL_GR2A
, (u_char
) (ndest
>> 16)); /* BLT dest hi */
3231 /* BLT source: set to 0 (is a dummy here anyway) */
3232 vga_wgfx (fb_info
->regs
, CL_GR2C
, 0x00); /* BLT src low */
3233 vga_wgfx (fb_info
->regs
, CL_GR2D
, 0x00); /* BLT src mid */
3234 vga_wgfx (fb_info
->regs
, CL_GR2E
, 0x00); /* BLT src hi */
3236 /* This is a ColorExpand Blt, using the */
3237 /* same color for foreground and background */
3238 vga_wgfx (fb_info
->regs
, VGA_GFX_SR_VALUE
, color
); /* foreground color */
3239 vga_wgfx (fb_info
->regs
, VGA_GFX_SR_ENABLE
, color
); /* background color */
3242 if (fb_info
->currentmode
.var
.bits_per_pixel
== 16) {
3243 vga_wgfx (fb_info
->regs
, CL_GR10
, color
); /* foreground color */
3244 vga_wgfx (fb_info
->regs
, CL_GR11
, color
); /* background color */
3247 } else if (fb_info
->currentmode
.var
.bits_per_pixel
== 32) {
3248 vga_wgfx (fb_info
->regs
, CL_GR10
, color
); /* foreground color */
3249 vga_wgfx (fb_info
->regs
, CL_GR11
, color
); /* background color */
3250 vga_wgfx (fb_info
->regs
, CL_GR12
, color
); /* foreground color */
3251 vga_wgfx (fb_info
->regs
, CL_GR13
, color
); /* background color */
3252 vga_wgfx (fb_info
->regs
, CL_GR14
, 0); /* foreground color */
3253 vga_wgfx (fb_info
->regs
, CL_GR15
, 0); /* background color */
3257 /* BLT mode: color expand, Enable 8x8 copy (faster?) */
3258 vga_wgfx (fb_info
->regs
, CL_GR30
, op
); /* BLT mode */
3260 /* BLT ROP: SrcCopy */
3261 vga_wgfx (fb_info
->regs
, CL_GR32
, 0x0d); /* BLT ROP */
3263 /* and finally: GO! */
3264 vga_wgfx (fb_info
->regs
, CL_GR31
, 0x02); /* BLT Start/status */
3270 /**************************************************************************
3271 * bestclock() - determine closest possible clock lower(?) than the
3272 * desired pixel clock
3273 **************************************************************************/
3274 static void bestclock (long freq
, long *best
, long *nom
,
3275 long *den
, long *div
, long maxfreq
)
3279 assert (best
!= NULL
);
3280 assert (nom
!= NULL
);
3281 assert (den
!= NULL
);
3282 assert (div
!= NULL
);
3283 assert (maxfreq
> 0);
3289 DPRINTK ("ENTER\n");
3300 for (n
= 32; n
< 128; n
++) {
3301 d
= (143181 * n
) / f
;
3302 if ((d
>= 7) && (d
<= 63)) {
3305 h
= (14318 * n
) / d
;
3306 if (abs (h
- freq
) < abs (*best
- freq
)) {
3318 d
= ((143181 * n
) + f
- 1) / f
;
3319 if ((d
>= 7) && (d
<= 63)) {
3322 h
= (14318 * n
) / d
;
3323 if (abs (h
- freq
) < abs (*best
- freq
)) {
3337 DPRINTK ("Best possible values for given frequency:\n");
3338 DPRINTK (" best: %ld kHz nom: %ld den: %ld div: %ld\n",
3339 freq
, *nom
, *den
, *div
);
3345 /* -------------------------------------------------------------------------
3347 * debugging functions
3349 * -------------------------------------------------------------------------
3355 * clgen_dbg_print_byte
3356 * @name: name associated with byte value to be displayed
3357 * @val: byte value to be displayed
3360 * Display an indented string, along with a hexidecimal byte value, and
3361 * its decoded bits. Bits 7 through 0 are listed in left-to-right
3366 void clgen_dbg_print_byte (const char *name
, unsigned char val
)
3368 DPRINTK ("%8s = 0x%02X (bits 7-0: %c%c%c%c%c%c%c%c)\n",
3370 val
& 0x80 ? '1' : '0',
3371 val
& 0x40 ? '1' : '0',
3372 val
& 0x20 ? '1' : '0',
3373 val
& 0x10 ? '1' : '0',
3374 val
& 0x08 ? '1' : '0',
3375 val
& 0x04 ? '1' : '0',
3376 val
& 0x02 ? '1' : '0',
3377 val
& 0x01 ? '1' : '0');
3382 * clgen_dbg_print_regs
3383 * @base: If using newmmio, the newmmio base address, otherwise %NULL
3384 * @reg_class: type of registers to read: %CRT, or %SEQ
3387 * Dumps the given list of VGA CRTC registers. If @base is %NULL,
3388 * old-style I/O ports are queried for information, otherwise MMIO is
3389 * used at the given @base address to query the information.
3393 void clgen_dbg_print_regs (caddr_t regbase
, clgen_dbg_reg_class_t reg_class
,...)
3396 unsigned char val
= 0;
3400 va_start (list
, reg_class
);
3402 name
= va_arg (list
, char *);
3403 while (name
!= NULL
) {
3404 reg
= va_arg (list
, int);
3406 switch (reg_class
) {
3408 val
= vga_rcrt (regbase
, (unsigned char) reg
);
3411 val
= vga_rseq (regbase
, (unsigned char) reg
);
3414 /* should never occur */
3419 clgen_dbg_print_byte (name
, val
);
3421 name
= va_arg (list
, char *);
3436 void clgen_dump (void)
3438 clgen_dbg_reg_dump (NULL
);
3443 * clgen_dbg_reg_dump
3444 * @base: If using newmmio, the newmmio base address, otherwise %NULL
3447 * Dumps a list of interesting VGA and CLGEN registers. If @base is %NULL,
3448 * old-style I/O ports are queried for information, otherwise MMIO is
3449 * used at the given @base address to query the information.
3453 void clgen_dbg_reg_dump (caddr_t regbase
)
3455 DPRINTK ("CLGEN VGA CRTC register dump:\n");
3457 clgen_dbg_print_regs (regbase
, CRT
,
3509 DPRINTK ("CLGEN VGA SEQ register dump:\n");
3511 clgen_dbg_print_regs (regbase
, SEQ
,
3543 #endif /* CLGEN_DEBUG */