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 * Cliff Matthews <ctm@ardi.com>:
19 * 16bpp fix for CL-GD7548 (uses info from XFree86 4.2.0 source)
21 * Original clgenfb author: Frank Neumann
23 * Based on retz3fb.c and clgen.c:
24 * Copyright (C) 1997 Jes Sorensen
25 * Copyright (C) 1996 Frank Neumann
27 ***************************************************************
29 * Format this code with GNU indent '-kr -i8 -pcs' options.
31 * This file is subject to the terms and conditions of the GNU General Public
32 * License. See the file COPYING in the main directory of this archive
37 #define CLGEN_VERSION "1.9.9.1"
39 #include <linux/config.h>
40 #include <linux/module.h>
41 #include <linux/kernel.h>
42 #include <linux/errno.h>
43 #include <linux/string.h>
45 #include <linux/tty.h>
46 #include <linux/slab.h>
47 #include <linux/delay.h>
49 #include <linux/init.h>
50 #include <linux/selection.h>
51 #include <asm/pgtable.h>
54 #include <linux/zorro.h>
57 #include <linux/pci.h>
60 #include <asm/amigahw.h>
63 #include <asm/processor.h>
64 #define isPReP (_machine == _MACH_prep)
69 #include <video/fbcon.h>
70 #include <video/fbcon-mfb.h>
71 #include <video/fbcon-cfb8.h>
72 #include <video/fbcon-cfb16.h>
73 #include <video/fbcon-cfb24.h>
74 #include <video/fbcon-cfb32.h>
80 /*****************************************************************
82 * debugging and utility macros
86 /* enable debug output? */
87 /* #define CLGEN_DEBUG 1 */
89 /* disable runtime assertions? */
90 /* #define CLGEN_NDEBUG */
94 #define DPRINTK(fmt, args...) printk(KERN_DEBUG "%s: " fmt, __FUNCTION__ , ## args)
96 #define DPRINTK(fmt, args...)
99 /* debugging assertions */
101 #define assert(expr) \
103 printk( "Assertion failed! %s,%s,%s,line=%d\n",\
104 #expr,__FILE__,__FUNCTION__,__LINE__); \
119 #define MB_ (1024*1024)
122 #define MAX_NUM_BOARDS 7
125 /*****************************************************************
127 * chipset information
138 BT_PICASSO4, /* GD5446 */
139 BT_ALPINE, /* GD543x/4x */
141 BT_LAGUNA, /* GD546x */
146 * per-board-type information, used for enumerating and abstracting
147 * chip-specific information
148 * NOTE: MUST be in the same order as clgen_board_t in order to
149 * use direct indexing on this array
150 * NOTE: '__initdata' cannot be used as some of this info
151 * is required at runtime. Maybe separate into an init-only and
154 static const struct clgen_board_info_rec {
155 clgen_board_t btype; /* chipset enum, not strictly necessary, as
156 * clgen_board_info[] is directly indexed
158 char *name; /* ASCII name of chipset */
159 long maxclock; /* maximum video clock */
160 unsigned init_sr07 : 1; /* init SR07 during init_vgachip() */
161 unsigned init_sr1f : 1; /* write SR1F during init_vgachip() */
162 unsigned scrn_start_bit19 : 1; /* construct bit 19 of screen start address */
164 /* initial SR07 value, then for each mode */
166 unsigned char sr07_1bpp;
167 unsigned char sr07_1bpp_mux;
168 unsigned char sr07_8bpp;
169 unsigned char sr07_8bpp_mux;
171 unsigned char sr1f; /* SR1F VGA initial register value */
172 } clgen_board_info[] = {
173 { BT_NONE, }, /* dummy record */
176 140000, /* the SD64/P4 have a higher max. videoclock */
182 0, /* unused, does not multiplex */
184 0, /* unused, does not multiplex */
194 0, /* unused, does not multiplex */
196 0, /* unused, does not multiplex */
206 0, /* unused, does not multiplex */
208 0, /* unused, does not multiplex */
218 0, /* unused, does not multiplex */
220 0, /* unused, does not multiplex */
224 140000, /* the SD64/P4 have a higher max. videoclock */
230 0, /* unused, does not multiplex */
232 0, /* unused, does not multiplex */
236 110000, /* 135100 for some, 85500 for others */
254 0, /* unused, does not multiplex */
256 0, /* unused, does not multiplex */
274 /* the list of PCI devices for which we probe, and the
275 * order in which we do it */
276 static const struct {
278 const char *nameOverride; /* XXX unused... for now */
279 unsigned short device;
280 } clgen_pci_probe_list[] __initdata = {
281 { BT_ALPINE, NULL, PCI_DEVICE_ID_CIRRUS_5436 },
282 { BT_ALPINE, NULL, PCI_DEVICE_ID_CIRRUS_5434_8 },
283 { BT_ALPINE, NULL, PCI_DEVICE_ID_CIRRUS_5434_4 },
284 { BT_ALPINE, NULL, PCI_DEVICE_ID_CIRRUS_5430 }, /* GD-5440 has identical id */
285 { BT_ALPINE, NULL, PCI_DEVICE_ID_CIRRUS_7543 },
286 { BT_ALPINE, NULL, PCI_DEVICE_ID_CIRRUS_7548 },
287 { BT_GD5480, NULL, PCI_DEVICE_ID_CIRRUS_5480 }, /* MacPicasso probably */
288 { BT_PICASSO4, NULL, PCI_DEVICE_ID_CIRRUS_5446 }, /* Picasso 4 is a GD5446 */
289 { BT_LAGUNA, "CL Laguna", PCI_DEVICE_ID_CIRRUS_5462 },
290 { BT_LAGUNA, "CL Laguna 3D", PCI_DEVICE_ID_CIRRUS_5464 },
291 { BT_LAGUNA, "CL Laguna 3DA", PCI_DEVICE_ID_CIRRUS_5465 },
293 #endif /* CONFIG_PCI */
297 static const struct {
301 } clgen_zorro_probe_list[] __initdata = {
303 ZORRO_PROD_HELFRICH_SD64_RAM,
304 ZORRO_PROD_HELFRICH_SD64_REG,
307 ZORRO_PROD_HELFRICH_PICCOLO_RAM,
308 ZORRO_PROD_HELFRICH_PICCOLO_REG,
311 ZORRO_PROD_VILLAGE_TRONIC_PICASSO_II_II_PLUS_RAM,
312 ZORRO_PROD_VILLAGE_TRONIC_PICASSO_II_II_PLUS_REG,
315 ZORRO_PROD_GVP_EGS_28_24_SPECTRUM_RAM,
316 ZORRO_PROD_GVP_EGS_28_24_SPECTRUM_REG,
319 ZORRO_PROD_VILLAGE_TRONIC_PICASSO_IV_Z3,
323 #endif /* CONFIG_ZORRO */
328 struct fb_var_screeninfo var;
330 __u32 line_length; /* in BYTES! */
342 long HorizRes; /* The x resolution in pixel */
345 long HorizBlankStart;
350 long VertRes; /* the physical y resolution in scanlines */
365 } clgen_dbg_reg_class_t;
366 #endif /* CLGEN_DEBUG */
371 /* info about board */
372 struct clgenfb_info {
373 struct fb_info_gen gen;
381 unsigned char SFR; /* Shadow of special function register */
383 unsigned long fbmem_phys;
384 unsigned long fbregs_phys;
386 struct clgenfb_par currentmode;
388 struct { u8 red, green, blue, pad; } palette[256];
391 #ifdef FBCON_HAS_CFB16
394 #ifdef FBCON_HAS_CFB24
397 #ifdef FBCON_HAS_CFB32
403 unsigned long board_addr,
408 struct pci_dev *pdev;
409 #define IS_7548(x) ((x)->pdev->device == PCI_DEVICE_ID_CIRRUS_7548)
411 #define IS_7548(x) (FALSE)
418 static struct display disp;
420 static struct clgenfb_info boards[MAX_NUM_BOARDS]; /* the boards */
422 static unsigned clgen_def_mode = 1;
423 static int noaccel = 0;
428 * Predefined Video Modes
431 static const struct {
433 struct fb_var_screeninfo var;
434 } clgenfb_predefined[] __initdata =
437 {"Autodetect", /* autodetect mode */
441 {"640x480", /* 640x480, 31.25 kHz, 60 Hz, 25 MHz PixClock */
443 640, 480, 640, 480, 0, 0, 8, 0,
448 0, 0, -1, -1, FB_ACCEL_NONE, 40000, 48, 16, 32, 8, 96, 4,
449 FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED
453 {"800x600", /* 800x600, 48 kHz, 76 Hz, 50 MHz PixClock */
455 800, 600, 800, 600, 0, 0, 8, 0,
460 0, 0, -1, -1, FB_ACCEL_NONE, 20000, 128, 16, 24, 2, 96, 6,
461 0, FB_VMODE_NONINTERLACED
466 Modeline from XF86Config:
467 Mode "1024x768" 80 1024 1136 1340 1432 768 770 774 805
469 {"1024x768", /* 1024x768, 55.8 kHz, 70 Hz, 80 MHz PixClock */
471 1024, 768, 1024, 768, 0, 0, 8, 0,
476 0, 0, -1, -1, FB_ACCEL_NONE, 12500, 144, 32, 30, 2, 192, 6,
477 0, FB_VMODE_NONINTERLACED
482 #define NUM_TOTAL_MODES ARRAY_SIZE(clgenfb_predefined)
483 static struct fb_var_screeninfo clgenfb_default;
489 static const char *clgenfb_name = "CLgen";
491 /****************************************************************************/
492 /**** BEGIN PROTOTYPES ******************************************************/
495 /*--- Interface used by the world ------------------------------------------*/
496 int clgenfb_init (void);
497 int clgenfb_setup (char *options);
499 static int clgenfb_open (struct fb_info *info, int user);
500 static int clgenfb_release (struct fb_info *info, int user);
502 /* function table of the above functions */
503 static struct fb_ops clgenfb_ops = {
505 fb_open: clgenfb_open,
506 fb_release: clgenfb_release,
507 fb_get_fix: fbgen_get_fix,
508 fb_get_var: fbgen_get_var,
509 fb_set_var: fbgen_set_var,
510 fb_get_cmap: fbgen_get_cmap,
511 fb_set_cmap: fbgen_set_cmap,
512 fb_pan_display: fbgen_pan_display,
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_setcolreg (unsigned regno, unsigned red, unsigned green,
529 unsigned blue, unsigned transp,
530 struct fb_info *info);
531 static int clgen_pan_display (const struct fb_var_screeninfo *var,
532 struct fb_info_gen *info);
533 static int clgen_blank (int blank_mode, struct fb_info_gen *info);
535 static void clgen_set_disp (const void *par, struct display *disp,
536 struct fb_info_gen *info);
538 /* function table of the above functions */
539 static struct fbgen_hwswitch clgen_hwswitch =
554 /* Text console acceleration */
556 #ifdef FBCON_HAS_CFB8
557 static void fbcon_clgen8_bmove (struct display *p, int sy, int sx,
558 int dy, int dx, int height, int width);
559 static void fbcon_clgen8_clear (struct vc_data *conp, struct display *p,
560 int sy, int sx, int height, int width);
562 static struct display_switch fbcon_clgen_8 = {
563 setup: fbcon_cfb8_setup,
564 bmove: fbcon_clgen8_bmove,
565 clear: fbcon_clgen8_clear,
566 putc: fbcon_cfb8_putc,
567 putcs: fbcon_cfb8_putcs,
568 revc: fbcon_cfb8_revc,
569 clear_margins: fbcon_cfb8_clear_margins,
570 fontwidthmask: FONTWIDTH (4) | FONTWIDTH (8) | FONTWIDTH (12) | FONTWIDTH (16)
573 #ifdef FBCON_HAS_CFB16
574 static void fbcon_clgen16_bmove (struct display *p, int sy, int sx,
575 int dy, int dx, int height, int width);
576 static void fbcon_clgen16_clear (struct vc_data *conp, struct display *p,
577 int sy, int sx, int height, int width);
578 static struct display_switch fbcon_clgen_16 = {
579 setup: fbcon_cfb16_setup,
580 bmove: fbcon_clgen16_bmove,
581 clear: fbcon_clgen16_clear,
582 putc: fbcon_cfb16_putc,
583 putcs: fbcon_cfb16_putcs,
584 revc: fbcon_cfb16_revc,
585 clear_margins: fbcon_cfb16_clear_margins,
586 fontwidthmask: FONTWIDTH (4) | FONTWIDTH (8) | FONTWIDTH (12) | FONTWIDTH (16)
589 #ifdef FBCON_HAS_CFB32
590 static void fbcon_clgen32_bmove (struct display *p, int sy, int sx,
591 int dy, int dx, int height, int width);
592 static void fbcon_clgen32_clear (struct vc_data *conp, struct display *p,
593 int sy, int sx, int height, int width);
594 static struct display_switch fbcon_clgen_32 = {
595 setup: fbcon_cfb32_setup,
596 bmove: fbcon_clgen32_bmove,
597 clear: fbcon_clgen32_clear,
598 putc: fbcon_cfb32_putc,
599 putcs: fbcon_cfb32_putcs,
600 revc: fbcon_cfb32_revc,
601 clear_margins: fbcon_cfb32_clear_margins,
602 fontwidthmask: FONTWIDTH (4) | FONTWIDTH (8) | FONTWIDTH (12) | FONTWIDTH (16)
608 /*--- Internal routines ----------------------------------------------------*/
609 static void init_vgachip (struct clgenfb_info *fb_info);
610 static void switch_monitor (struct clgenfb_info *fb_info, int on);
611 static void WGen (const struct clgenfb_info *fb_info,
612 int regnum, unsigned char val);
613 static unsigned char RGen (const struct clgenfb_info *fb_info, int regnum);
614 static void AttrOn (const struct clgenfb_info *fb_info);
615 static void WHDR (const struct clgenfb_info *fb_info, unsigned char val);
616 static void WSFR (struct clgenfb_info *fb_info, unsigned char val);
617 static void WSFR2 (struct clgenfb_info *fb_info, unsigned char val);
618 static void WClut (struct clgenfb_info *fb_info, unsigned char regnum, unsigned char red,
622 static void RClut (struct clgenfb_info *fb_info, unsigned char regnum, unsigned char *red,
623 unsigned char *green,
624 unsigned char *blue);
626 static void clgen_WaitBLT (caddr_t regbase);
627 static void clgen_BitBLT (caddr_t regbase, u_short curx, u_short cury,
628 u_short destx, u_short desty,
629 u_short width, u_short height,
630 u_short line_length);
631 static void clgen_RectFill (struct clgenfb_info *fb_info, u_short x, u_short y,
632 u_short width, u_short height,
633 u_char color, u_short line_length);
635 static void bestclock (long freq, long *best,
636 long *nom, long *den,
637 long *div, long maxfreq);
640 static void clgen_dump (void);
641 static void clgen_dbg_reg_dump (caddr_t regbase);
642 static void clgen_dbg_print_regs (caddr_t regbase, clgen_dbg_reg_class_t reg_class,...);
643 static void clgen_dbg_print_byte (const char *name, unsigned char val);
644 #endif /* CLGEN_DEBUG */
646 /*** END PROTOTYPES ********************************************************/
647 /*****************************************************************************/
648 /*** BEGIN Interface Used by the World ***************************************/
650 static int opencount = 0;
652 /*--- Open /dev/fbx ---------------------------------------------------------*/
653 static int clgenfb_open (struct fb_info *info, int user)
655 if (opencount++ == 0)
656 switch_monitor ((struct clgenfb_info *) info, 1);
660 /*--- Close /dev/fbx --------------------------------------------------------*/
661 static int clgenfb_release (struct fb_info *info, int user)
663 if (--opencount == 0)
664 switch_monitor ((struct clgenfb_info *) info, 0);
668 /**** END Interface used by the World *************************************/
669 /****************************************************************************/
670 /**** BEGIN Hardware specific Routines **************************************/
672 static void clgen_detect (void)
678 static int clgen_encode_fix (struct fb_fix_screeninfo *fix, const void *par,
679 struct fb_info_gen *info)
681 struct clgenfb_par *_par = (struct clgenfb_par *) par;
682 struct clgenfb_info *_info = (struct clgenfb_info *) info;
686 memset (fix, 0, sizeof (struct fb_fix_screeninfo));
687 strcpy (fix->id, clgenfb_name);
689 if (_info->btype == BT_GD5480) {
690 /* Select proper byte-swapping aperture */
691 switch (_par->var.bits_per_pixel) {
694 fix->smem_start = _info->fbmem_phys;
697 fix->smem_start = _info->fbmem_phys + 1 * MB_;
701 fix->smem_start = _info->fbmem_phys + 2 * MB_;
705 fix->smem_start = _info->fbmem_phys;
708 /* monochrome: only 1 memory plane */
709 /* 8 bit and above: Use whole memory area */
710 fix->smem_len = _par->var.bits_per_pixel == 1 ? _info->size / 4
712 fix->type = _par->type;
714 fix->visual = _par->visual;
718 fix->line_length = _par->line_length;
720 /* FIXME: map region at 0xB8000 if available, fill in here */
723 fix->accel = FB_ACCEL_NONE;
731 /* Get a good MCLK value */
732 static long clgen_get_mclk (long freq, int bpp, long *div)
736 assert (div != NULL);
738 /* Calculate MCLK, in case VCLK is high enough to require > 50MHz.
739 * Assume a 64-bit data path for now. The formula is:
740 * ((B * PCLK * 2)/W) * 1.2
741 * B = bytes per pixel, PCLK = pixclock, W = data width in bytes */
742 mclk = ((bpp / 8) * freq * 2) / 4;
743 mclk = (mclk * 12) / 10;
746 DPRINTK ("Use MCLK of %ld kHz\n", mclk);
748 /* Calculate value for SR1F. Multiply by 2 so we can round up. */
749 mclk = ((mclk * 16) / 14318);
750 mclk = (mclk + 1) / 2;
751 DPRINTK ("Set SR1F[5:0] to 0x%lx\n", mclk);
753 /* Determine if we should use MCLK instead of VCLK, and if so, what we
754 * should divide it by to get VCLK */
756 case 24751 ... 25249:
758 DPRINTK ("Using VCLK = MCLK/2\n");
760 case 49501 ... 50499:
762 DPRINTK ("Using VCLK = MCLK\n");
772 static int clgen_decode_var (const struct fb_var_screeninfo *var, void *par,
773 struct fb_info_gen *info)
777 int xres, hfront, hsync, hback;
778 int yres, vfront, vsync, vback;
779 int nom, den; /* translyting from pixels->bytes */
799 struct clgenfb_par *_par = (struct clgenfb_par *) par;
800 struct clgenfb_info *fb_info = (struct clgenfb_info *) info;
802 assert (var != NULL);
803 assert (par != NULL);
804 assert (info != NULL);
808 DPRINTK ("Requested: %dx%dx%d\n", var->xres, var->yres, var->bits_per_pixel);
809 DPRINTK (" virtual: %dx%d\n", var->xres_virtual, var->yres_virtual);
810 DPRINTK (" offset: (%d,%d)\n", var->xoffset, var->yoffset);
811 DPRINTK ("grayscale: %d\n", var->grayscale);
813 memset (par, 0, sizeof (struct clgenfb_par));
817 switch (var->bits_per_pixel) {
821 break; /* 8 pixel per byte, only 1/4th of mem usable */
823 _par->var.bits_per_pixel = 8;
826 break; /* 1 pixel == 1 byte */
828 _par->var.bits_per_pixel = 16;
831 break; /* 2 bytes per pixel */
833 _par->var.bits_per_pixel = 24;
836 break; /* 3 bytes per pixel */
838 _par->var.bits_per_pixel = 32;
841 break; /* 4 bytes per pixel */
843 printk ("clgen: mode %dx%dx%d rejected...color depth not supported.\n",
844 var->xres, var->yres, var->bits_per_pixel);
845 DPRINTK ("EXIT - EINVAL error\n");
849 if (_par->var.xres * nom / den * _par->var.yres > fb_info->size) {
850 printk ("clgen: mode %dx%dx%d rejected...resolution too high to fit into video memory!\n",
851 var->xres, var->yres, var->bits_per_pixel);
852 DPRINTK ("EXIT - EINVAL error\n");
855 /* use highest possible virtual resolution */
856 if (_par->var.xres_virtual == -1 &&
857 _par->var.yres_virtual == -1) {
858 printk ("clgen: using maximum available virtual resolution\n");
859 for (i = 0; modes[i].xres != -1; i++) {
860 if (modes[i].xres * nom / den * modes[i].yres < fb_info->size / 2)
863 if (modes[i].xres == -1) {
864 printk ("clgen: could not find a virtual resolution that fits into video memory!!\n");
865 DPRINTK ("EXIT - EINVAL error\n");
868 _par->var.xres_virtual = modes[i].xres;
869 _par->var.yres_virtual = modes[i].yres;
871 printk ("clgen: virtual resolution set to maximum of %dx%d\n",
872 _par->var.xres_virtual, _par->var.yres_virtual);
873 } else if (_par->var.xres_virtual == -1) {
874 /* FIXME: maximize X virtual resolution only */
875 } else if (_par->var.yres_virtual == -1) {
876 /* FIXME: maximize Y virtual resolution only */
878 if (_par->var.xoffset < 0)
879 _par->var.xoffset = 0;
880 if (_par->var.yoffset < 0)
881 _par->var.yoffset = 0;
883 /* truncate xoffset and yoffset to maximum if too high */
884 if (_par->var.xoffset > _par->var.xres_virtual - _par->var.xres)
885 _par->var.xoffset = _par->var.xres_virtual - _par->var.xres - 1;
887 if (_par->var.yoffset > _par->var.yres_virtual - _par->var.yres)
888 _par->var.yoffset = _par->var.yres_virtual - _par->var.yres - 1;
890 switch (_par->var.bits_per_pixel) {
892 _par->line_length = _par->var.xres_virtual / 8;
893 _par->visual = FB_VISUAL_MONO10;
897 _par->line_length = _par->var.xres_virtual;
898 _par->visual = FB_VISUAL_PSEUDOCOLOR;
899 _par->var.red.offset = 0;
900 _par->var.red.length = 6;
901 _par->var.green.offset = 0;
902 _par->var.green.length = 6;
903 _par->var.blue.offset = 0;
904 _par->var.blue.length = 6;
908 _par->line_length = _par->var.xres_virtual * 2;
909 _par->visual = FB_VISUAL_DIRECTCOLOR;
911 _par->var.red.offset = 2;
912 _par->var.green.offset = -3;
913 _par->var.blue.offset = 8;
915 _par->var.red.offset = 10;
916 _par->var.green.offset = 5;
917 _par->var.blue.offset = 0;
919 _par->var.red.length = 5;
920 _par->var.green.length = 5;
921 _par->var.blue.length = 5;
925 _par->line_length = _par->var.xres_virtual * 3;
926 _par->visual = FB_VISUAL_DIRECTCOLOR;
928 _par->var.red.offset = 8;
929 _par->var.green.offset = 16;
930 _par->var.blue.offset = 24;
932 _par->var.red.offset = 16;
933 _par->var.green.offset = 8;
934 _par->var.blue.offset = 0;
936 _par->var.red.length = 8;
937 _par->var.green.length = 8;
938 _par->var.blue.length = 8;
942 _par->line_length = _par->var.xres_virtual * 4;
943 _par->visual = FB_VISUAL_DIRECTCOLOR;
945 _par->var.red.offset = 8;
946 _par->var.green.offset = 16;
947 _par->var.blue.offset = 24;
949 _par->var.red.offset = 16;
950 _par->var.green.offset = 8;
951 _par->var.blue.offset = 0;
953 _par->var.red.length = 8;
954 _par->var.green.length = 8;
955 _par->var.blue.length = 8;
959 DPRINTK("Unsupported bpp size: %d\n", _par->var.bits_per_pixel);
961 /* should never occur */
965 _par->var.red.msb_right =
966 _par->var.green.msb_right =
967 _par->var.blue.msb_right =
968 _par->var.transp.offset =
969 _par->var.transp.length =
970 _par->var.transp.msb_right = 0;
972 _par->type = FB_TYPE_PACKED_PIXELS;
974 /* convert from ps to kHz */
975 freq = 1000000000 / var->pixclock;
977 DPRINTK ("desired pixclock: %ld kHz\n", freq);
979 if (IS_7548(fb_info))
982 maxclock = clgen_board_info[fb_info->btype].maxclock;
983 _par->multiplexing = 0;
985 /* If the frequency is greater than we can support, we might be able
986 * to use multiplexing for the video mode */
987 if (freq > maxclock) {
988 switch (fb_info->btype) {
991 _par->multiplexing = 1;
995 printk (KERN_WARNING "clgen: ERROR: Frequency greater than maxclock (%ld kHz)\n", maxclock);
996 DPRINTK ("EXIT - return -EINVAL\n");
1001 /* TODO: If we have a 1MB 5434, we need to put ourselves in a mode where
1002 * the VCLK is double the pixel clock. */
1003 switch (var->bits_per_pixel) {
1006 if (_par->HorizRes <= 800)
1007 freq /= 2; /* Xbh has this type of clock for 32-bit */
1012 bestclock (freq, &_par->freq, &_par->nom, &_par->den, &_par->div,
1014 _par->mclk = clgen_get_mclk (freq, _par->var.bits_per_pixel, &_par->divMCLK);
1016 xres = _par->var.xres;
1017 hfront = _par->var.right_margin;
1018 hsync = _par->var.hsync_len;
1019 hback = _par->var.left_margin;
1021 yres = _par->var.yres;
1022 vfront = _par->var.lower_margin;
1023 vsync = _par->var.vsync_len;
1024 vback = _par->var.upper_margin;
1026 if (_par->var.vmode & FB_VMODE_DOUBLE) {
1031 } else if (_par->var.vmode & FB_VMODE_INTERLACED) {
1032 yres = (yres + 1) / 2;
1033 vfront = (vfront + 1) / 2;
1034 vsync = (vsync + 1) / 2;
1035 vback = (vback + 1) / 2;
1037 _par->HorizRes = xres;
1038 _par->HorizTotal = (xres + hfront + hsync + hback) / 8 - 5;
1039 _par->HorizDispEnd = xres / 8 - 1;
1040 _par->HorizBlankStart = xres / 8;
1041 _par->HorizBlankEnd = _par->HorizTotal + 5; /* does not count with "-5" */
1042 _par->HorizSyncStart = (xres + hfront) / 8 + 1;
1043 _par->HorizSyncEnd = (xres + hfront + hsync) / 8 + 1;
1045 _par->VertRes = yres;
1046 _par->VertTotal = yres + vfront + vsync + vback - 2;
1047 _par->VertDispEnd = yres - 1;
1048 _par->VertBlankStart = yres;
1049 _par->VertBlankEnd = _par->VertTotal;
1050 _par->VertSyncStart = yres + vfront - 1;
1051 _par->VertSyncEnd = yres + vfront + vsync - 1;
1053 if (_par->VertRes >= 1024) {
1054 _par->VertTotal /= 2;
1055 _par->VertSyncStart /= 2;
1056 _par->VertSyncEnd /= 2;
1057 _par->VertDispEnd /= 2;
1059 if (_par->multiplexing) {
1060 _par->HorizTotal /= 2;
1061 _par->HorizSyncStart /= 2;
1062 _par->HorizSyncEnd /= 2;
1063 _par->HorizDispEnd /= 2;
1065 if (_par->VertRes >= 1280) {
1066 printk (KERN_WARNING "clgen: ERROR: VerticalTotal >= 1280; special treatment required! (TODO)\n");
1067 DPRINTK ("EXIT - EINVAL error\n");
1075 static int clgen_encode_var (struct fb_var_screeninfo *var, const void *par,
1076 struct fb_info_gen *info)
1078 DPRINTK ("ENTER\n");
1080 *var = ((struct clgenfb_par *) par)->var;
1086 /* get current video mode */
1087 static void clgen_get_par (void *par, struct fb_info_gen *info)
1089 struct clgenfb_par *_par = (struct clgenfb_par *) par;
1090 struct clgenfb_info *_info = (struct clgenfb_info *) info;
1092 DPRINTK ("ENTER\n");
1094 *_par = _info->currentmode;
1099 static void clgen_set_mclk (const struct clgenfb_info *fb_info, int val, int div)
1101 assert (fb_info != NULL);
1105 unsigned char old = vga_rseq (fb_info->regs, CL_SEQR1E);
1106 vga_wseq (fb_info->regs, CL_SEQR1E, old | 0x1);
1107 vga_wseq (fb_info->regs, CL_SEQR1F, 0x40 | (val & 0x3f));
1108 } else if (div == 1) {
1110 unsigned char old = vga_rseq (fb_info->regs, CL_SEQR1E);
1111 vga_wseq (fb_info->regs, CL_SEQR1E, old & ~0x1);
1112 vga_wseq (fb_info->regs, CL_SEQR1F, 0x40 | (val & 0x3f));
1114 vga_wseq (fb_info->regs, CL_SEQR1F, val & 0x3f);
1118 /*************************************************************************
1121 actually writes the values for a new video mode into the hardware,
1122 **************************************************************************/
1123 static void clgen_set_par (const void *par, struct fb_info_gen *info)
1127 struct clgenfb_par *_par = (struct clgenfb_par *) par;
1128 struct clgenfb_info *fb_info = (struct clgenfb_info *) info;
1129 const struct clgen_board_info_rec *bi;
1131 DPRINTK ("ENTER\n");
1132 DPRINTK ("Requested mode: %dx%dx%d\n",
1133 _par->var.xres, _par->var.yres, _par->var.bits_per_pixel);
1134 DPRINTK ("pixclock: %d\n", _par->var.pixclock);
1136 bi = &clgen_board_info[fb_info->btype];
1139 /* unlock register VGA_CRTC_H_TOTAL..CRT7 */
1140 vga_wcrt (fb_info->regs, VGA_CRTC_V_SYNC_END, 0x20); /* previously: 0x00) */
1142 /* if debugging is enabled, all parameters get output before writing */
1143 DPRINTK ("CRT0: %ld\n", _par->HorizTotal);
1144 vga_wcrt (fb_info->regs, VGA_CRTC_H_TOTAL, _par->HorizTotal);
1146 DPRINTK ("CRT1: %ld\n", _par->HorizDispEnd);
1147 vga_wcrt (fb_info->regs, VGA_CRTC_H_DISP, _par->HorizDispEnd);
1149 DPRINTK ("CRT2: %ld\n", _par->HorizBlankStart);
1150 vga_wcrt (fb_info->regs, VGA_CRTC_H_BLANK_START, _par->HorizBlankStart);
1152 DPRINTK ("CRT3: 128+%ld\n", _par->HorizBlankEnd % 32); /* + 128: Compatible read */
1153 vga_wcrt (fb_info->regs, VGA_CRTC_H_BLANK_END, 128 + (_par->HorizBlankEnd % 32));
1155 DPRINTK ("CRT4: %ld\n", _par->HorizSyncStart);
1156 vga_wcrt (fb_info->regs, VGA_CRTC_H_SYNC_START, _par->HorizSyncStart);
1158 tmp = _par->HorizSyncEnd % 32;
1159 if (_par->HorizBlankEnd & 32)
1161 DPRINTK ("CRT5: %d\n", tmp);
1162 vga_wcrt (fb_info->regs, VGA_CRTC_H_SYNC_END, tmp);
1164 DPRINTK ("CRT6: %ld\n", _par->VertTotal & 0xff);
1165 vga_wcrt (fb_info->regs, VGA_CRTC_V_TOTAL, (_par->VertTotal & 0xff));
1167 tmp = 16; /* LineCompare bit #9 */
1168 if (_par->VertTotal & 256)
1170 if (_par->VertDispEnd & 256)
1172 if (_par->VertSyncStart & 256)
1174 if (_par->VertBlankStart & 256)
1176 if (_par->VertTotal & 512)
1178 if (_par->VertDispEnd & 512)
1180 if (_par->VertSyncStart & 512)
1182 DPRINTK ("CRT7: %d\n", tmp);
1183 vga_wcrt (fb_info->regs, VGA_CRTC_OVERFLOW, tmp);
1185 tmp = 0x40; /* LineCompare bit #8 */
1186 if (_par->VertBlankStart & 512)
1188 if (_par->var.vmode & FB_VMODE_DOUBLE)
1190 DPRINTK ("CRT9: %d\n", tmp);
1191 vga_wcrt (fb_info->regs, VGA_CRTC_MAX_SCAN, tmp);
1193 DPRINTK ("CRT10: %ld\n", _par->VertSyncStart & 0xff);
1194 vga_wcrt (fb_info->regs, VGA_CRTC_V_SYNC_START, (_par->VertSyncStart & 0xff));
1196 DPRINTK ("CRT11: 64+32+%ld\n", _par->VertSyncEnd % 16);
1197 vga_wcrt (fb_info->regs, VGA_CRTC_V_SYNC_END, (_par->VertSyncEnd % 16 + 64 + 32));
1199 DPRINTK ("CRT12: %ld\n", _par->VertDispEnd & 0xff);
1200 vga_wcrt (fb_info->regs, VGA_CRTC_V_DISP_END, (_par->VertDispEnd & 0xff));
1202 DPRINTK ("CRT15: %ld\n", _par->VertBlankStart & 0xff);
1203 vga_wcrt (fb_info->regs, VGA_CRTC_V_BLANK_START, (_par->VertBlankStart & 0xff));
1205 DPRINTK ("CRT16: %ld\n", _par->VertBlankEnd & 0xff);
1206 vga_wcrt (fb_info->regs, VGA_CRTC_V_BLANK_END, (_par->VertBlankEnd & 0xff));
1208 DPRINTK ("CRT18: 0xff\n");
1209 vga_wcrt (fb_info->regs, VGA_CRTC_LINE_COMPARE, 0xff);
1212 if (_par->var.vmode & FB_VMODE_INTERLACED)
1214 if (_par->HorizBlankEnd & 64)
1216 if (_par->HorizBlankEnd & 128)
1218 if (_par->VertBlankEnd & 256)
1220 if (_par->VertBlankEnd & 512)
1223 DPRINTK ("CRT1a: %d\n", tmp);
1224 vga_wcrt (fb_info->regs, CL_CRT1A, tmp);
1227 /* hardware RefClock: 14.31818 MHz */
1228 /* formula: VClk = (OSC * N) / (D * (1+P)) */
1229 /* Example: VClk = (14.31818 * 91) / (23 * (1+1)) = 28.325 MHz */
1231 vga_wseq (fb_info->regs, CL_SEQRB, _par->nom);
1232 tmp = _par->den << 1;
1236 if ((fb_info->btype == BT_SD64) ||
1237 (fb_info->btype == BT_ALPINE) ||
1238 (fb_info->btype == BT_GD5480))
1239 tmp |= 0x80; /* 6 bit denom; ONLY 5434!!! (bugged me 10 days) */
1241 DPRINTK ("CL_SEQR1B: %ld\n", (long) tmp);
1242 vga_wseq (fb_info->regs, CL_SEQR1B, tmp);
1244 if (_par->VertRes >= 1024)
1246 vga_wcrt (fb_info->regs, VGA_CRTC_MODE, 0xc7);
1248 /* mode control: VGA_CRTC_START_HI enable, ROTATE(?), 16bit
1249 * address wrap, no compat. */
1250 vga_wcrt (fb_info->regs, VGA_CRTC_MODE, 0xc3);
1252 /* HAEH? vga_wcrt (fb_info->regs, VGA_CRTC_V_SYNC_END, 0x20); * previously: 0x00 unlock VGA_CRTC_H_TOTAL..CRT7 */
1254 /* don't know if it would hurt to also program this if no interlaced */
1255 /* mode is used, but I feel better this way.. :-) */
1256 if (_par->var.vmode & FB_VMODE_INTERLACED)
1257 vga_wcrt (fb_info->regs, VGA_CRTC_REGS, _par->HorizTotal / 2);
1259 vga_wcrt (fb_info->regs, VGA_CRTC_REGS, 0x00); /* interlace control */
1261 vga_wseq (fb_info->regs, VGA_SEQ_CHARACTER_MAP, 0);
1263 /* adjust horizontal/vertical sync type (low/high) */
1264 tmp = 0x03; /* enable display memory & CRTC I/O address for color mode */
1265 if (_par->var.sync & FB_SYNC_HOR_HIGH_ACT)
1267 if (_par->var.sync & FB_SYNC_VERT_HIGH_ACT)
1269 WGen (fb_info, VGA_MIS_W, tmp);
1271 vga_wcrt (fb_info->regs, VGA_CRTC_PRESET_ROW, 0); /* Screen A Preset Row-Scan register */
1272 vga_wcrt (fb_info->regs, VGA_CRTC_CURSOR_START, 0); /* text cursor on and start line */
1273 vga_wcrt (fb_info->regs, VGA_CRTC_CURSOR_END, 31); /* text cursor end line */
1275 /******************************************************
1281 /* programming for different color depths */
1282 if (_par->var.bits_per_pixel == 1) {
1283 DPRINTK ("clgen: preparing for 1 bit deep display\n");
1284 vga_wgfx (fb_info->regs, VGA_GFX_MODE, 0); /* mode register */
1287 switch (fb_info->btype) {
1295 DPRINTK (" (for GD54xx)\n");
1296 vga_wseq (fb_info->regs, CL_SEQR7,
1297 _par->multiplexing ?
1298 bi->sr07_1bpp_mux : bi->sr07_1bpp);
1302 DPRINTK (" (for GD546x)\n");
1303 vga_wseq (fb_info->regs, CL_SEQR7,
1304 vga_rseq (fb_info->regs, CL_SEQR7) & ~0x01);
1308 printk (KERN_WARNING "clgen: unknown Board\n");
1312 /* Extended Sequencer Mode */
1313 switch (fb_info->btype) {
1315 /* setting the SEQRF on SD64 is not necessary (only during init) */
1316 DPRINTK ("(for SD64)\n");
1317 vga_wseq (fb_info->regs, CL_SEQR1F, 0x1a); /* MCLK select */
1321 DPRINTK ("(for Piccolo)\n");
1322 /* ### ueberall 0x22? */
1323 vga_wseq (fb_info->regs, CL_SEQR1F, 0x22); /* ##vorher 1c MCLK select */
1324 vga_wseq (fb_info->regs, CL_SEQRF, 0xb0); /* evtl d0 bei 1 bit? avoid FIFO underruns..? */
1328 DPRINTK ("(for Picasso)\n");
1329 vga_wseq (fb_info->regs, CL_SEQR1F, 0x22); /* ##vorher 22 MCLK select */
1330 vga_wseq (fb_info->regs, CL_SEQRF, 0xd0); /* ## vorher d0 avoid FIFO underruns..? */
1334 DPRINTK ("(for Spectrum)\n");
1335 /* ### ueberall 0x22? */
1336 vga_wseq (fb_info->regs, CL_SEQR1F, 0x22); /* ##vorher 1c MCLK select */
1337 vga_wseq (fb_info->regs, CL_SEQRF, 0xb0); /* evtl d0? avoid FIFO underruns..? */
1344 DPRINTK (" (for GD54xx)\n");
1349 printk (KERN_WARNING "clgen: unknown Board\n");
1353 WGen (fb_info, VGA_PEL_MSK, 0x01); /* pixel mask: pass-through for first plane */
1354 if (_par->multiplexing)
1355 WHDR (fb_info, 0x4a); /* hidden dac reg: 1280x1024 */
1357 WHDR (fb_info, 0); /* hidden dac: nothing */
1358 vga_wseq (fb_info->regs, VGA_SEQ_MEMORY_MODE, 0x06); /* memory mode: odd/even, ext. memory */
1359 vga_wseq (fb_info->regs, VGA_SEQ_PLANE_WRITE, 0x01); /* plane mask: only write to first plane */
1360 offset = _par->var.xres_virtual / 16;
1363 /******************************************************
1369 else if (_par->var.bits_per_pixel == 8) {
1370 DPRINTK ("clgen: preparing for 8 bit deep display\n");
1371 switch (fb_info->btype) {
1379 DPRINTK (" (for GD54xx)\n");
1380 vga_wseq (fb_info->regs, CL_SEQR7,
1381 _par->multiplexing ?
1382 bi->sr07_8bpp_mux : bi->sr07_8bpp);
1386 DPRINTK (" (for GD546x)\n");
1387 vga_wseq (fb_info->regs, CL_SEQR7,
1388 vga_rseq (fb_info->regs, CL_SEQR7) | 0x01);
1392 printk (KERN_WARNING "clgen: unknown Board\n");
1396 switch (fb_info->btype) {
1398 vga_wseq (fb_info->regs, CL_SEQR1F, 0x1d); /* MCLK select */
1402 vga_wseq (fb_info->regs, CL_SEQR1F, 0x22); /* ### vorher 1c MCLK select */
1403 vga_wseq (fb_info->regs, CL_SEQRF, 0xb0); /* Fast Page-Mode writes */
1407 vga_wseq (fb_info->regs, CL_SEQR1F, 0x22); /* ### vorher 1c MCLK select */
1408 vga_wseq (fb_info->regs, CL_SEQRF, 0xb0); /* Fast Page-Mode writes */
1412 vga_wseq (fb_info->regs, CL_SEQR1F, 0x22); /* ### vorher 1c MCLK select */
1413 vga_wseq (fb_info->regs, CL_SEQRF, 0xb0); /* Fast Page-Mode writes */
1418 vga_wseq (fb_info->regs, CL_SEQRF, 0xb8); /* ### INCOMPLETE!! */
1420 /* vga_wseq (fb_info->regs, CL_SEQR1F, 0x1c); */
1424 DPRINTK (" (for GD543x)\n");
1425 clgen_set_mclk (fb_info, _par->mclk, _par->divMCLK);
1426 /* We already set SRF and SR1F */
1431 DPRINTK (" (for GD54xx)\n");
1436 printk (KERN_WARNING "clgen: unknown Board\n");
1440 vga_wgfx (fb_info->regs, VGA_GFX_MODE, 64); /* mode register: 256 color mode */
1441 WGen (fb_info, VGA_PEL_MSK, 0xff); /* pixel mask: pass-through all planes */
1442 if (_par->multiplexing)
1443 WHDR (fb_info, 0x4a); /* hidden dac reg: 1280x1024 */
1445 WHDR (fb_info, 0); /* hidden dac: nothing */
1446 vga_wseq (fb_info->regs, VGA_SEQ_MEMORY_MODE, 0x0a); /* memory mode: chain4, ext. memory */
1447 vga_wseq (fb_info->regs, VGA_SEQ_PLANE_WRITE, 0xff); /* plane mask: enable writing to all 4 planes */
1448 offset = _par->var.xres_virtual / 8;
1451 /******************************************************
1457 else if (_par->var.bits_per_pixel == 16) {
1458 DPRINTK ("clgen: preparing for 16 bit deep display\n");
1459 switch (fb_info->btype) {
1461 vga_wseq (fb_info->regs, CL_SEQR7, 0xf7); /* Extended Sequencer Mode: 256c col. mode */
1462 vga_wseq (fb_info->regs, CL_SEQR1F, 0x1e); /* MCLK select */
1466 vga_wseq (fb_info->regs, CL_SEQR7, 0x87);
1467 vga_wseq (fb_info->regs, CL_SEQRF, 0xb0); /* Fast Page-Mode writes */
1468 vga_wseq (fb_info->regs, CL_SEQR1F, 0x22); /* MCLK select */
1472 vga_wseq (fb_info->regs, CL_SEQR7, 0x27);
1473 vga_wseq (fb_info->regs, CL_SEQRF, 0xb0); /* Fast Page-Mode writes */
1474 vga_wseq (fb_info->regs, CL_SEQR1F, 0x22); /* MCLK select */
1478 vga_wseq (fb_info->regs, CL_SEQR7, 0x87);
1479 vga_wseq (fb_info->regs, CL_SEQRF, 0xb0); /* Fast Page-Mode writes */
1480 vga_wseq (fb_info->regs, CL_SEQR1F, 0x22); /* MCLK select */
1484 vga_wseq (fb_info->regs, CL_SEQR7, 0x27);
1485 /* vga_wseq (fb_info->regs, CL_SEQR1F, 0x1c); */
1489 DPRINTK (" (for GD543x)\n");
1490 if (IS_7548(fb_info)) {
1491 vga_wseq (fb_info->regs, CL_SEQR7,
1492 (vga_rseq (fb_info->regs, CL_SEQR7) & 0xE0)
1494 WHDR (fb_info, 0xC1);
1496 if (_par->HorizRes >= 1024)
1497 vga_wseq (fb_info->regs, CL_SEQR7, 0xa7);
1499 vga_wseq (fb_info->regs, CL_SEQR7, 0xa3);
1501 clgen_set_mclk (fb_info, _par->mclk, _par->divMCLK);
1505 DPRINTK (" (for GD5480)\n");
1506 vga_wseq (fb_info->regs, CL_SEQR7, 0x17);
1507 /* We already set SRF and SR1F */
1511 DPRINTK (" (for GD546x)\n");
1512 vga_wseq (fb_info->regs, CL_SEQR7,
1513 vga_rseq (fb_info->regs, CL_SEQR7) & ~0x01);
1517 printk (KERN_WARNING "CLGEN: unknown Board\n");
1521 vga_wgfx (fb_info->regs, VGA_GFX_MODE, 64); /* mode register: 256 color mode */
1522 WGen (fb_info, VGA_PEL_MSK, 0xff); /* pixel mask: pass-through all planes */
1524 WHDR (fb_info, 0xc0); /* Copy Xbh */
1525 #elif defined(CONFIG_ZORRO)
1526 /* FIXME: CONFIG_PCI and CONFIG_ZORRO may be defined both */
1527 WHDR (fb_info, 0xa0); /* hidden dac reg: nothing special */
1529 vga_wseq (fb_info->regs, VGA_SEQ_MEMORY_MODE, 0x0a); /* memory mode: chain4, ext. memory */
1530 vga_wseq (fb_info->regs, VGA_SEQ_PLANE_WRITE, 0xff); /* plane mask: enable writing to all 4 planes */
1531 offset = _par->var.xres_virtual / 4;
1534 /******************************************************
1540 else if (_par->var.bits_per_pixel == 32) {
1541 DPRINTK ("clgen: preparing for 24/32 bit deep display\n");
1542 switch (fb_info->btype) {
1544 vga_wseq (fb_info->regs, CL_SEQR7, 0xf9); /* Extended Sequencer Mode: 256c col. mode */
1545 vga_wseq (fb_info->regs, CL_SEQR1F, 0x1e); /* MCLK select */
1549 vga_wseq (fb_info->regs, CL_SEQR7, 0x85);
1550 vga_wseq (fb_info->regs, CL_SEQRF, 0xb0); /* Fast Page-Mode writes */
1551 vga_wseq (fb_info->regs, CL_SEQR1F, 0x22); /* MCLK select */
1555 vga_wseq (fb_info->regs, CL_SEQR7, 0x25);
1556 vga_wseq (fb_info->regs, CL_SEQRF, 0xb0); /* Fast Page-Mode writes */
1557 vga_wseq (fb_info->regs, CL_SEQR1F, 0x22); /* MCLK select */
1561 vga_wseq (fb_info->regs, CL_SEQR7, 0x85);
1562 vga_wseq (fb_info->regs, CL_SEQRF, 0xb0); /* Fast Page-Mode writes */
1563 vga_wseq (fb_info->regs, CL_SEQR1F, 0x22); /* MCLK select */
1567 vga_wseq (fb_info->regs, CL_SEQR7, 0x25);
1568 /* vga_wseq (fb_info->regs, CL_SEQR1F, 0x1c); */
1572 DPRINTK (" (for GD543x)\n");
1573 vga_wseq (fb_info->regs, CL_SEQR7, 0xa9);
1574 clgen_set_mclk (fb_info, _par->mclk, _par->divMCLK);
1578 DPRINTK (" (for GD5480)\n");
1579 vga_wseq (fb_info->regs, CL_SEQR7, 0x19);
1580 /* We already set SRF and SR1F */
1584 DPRINTK (" (for GD546x)\n");
1585 vga_wseq (fb_info->regs, CL_SEQR7,
1586 vga_rseq (fb_info->regs, CL_SEQR7) & ~0x01);
1590 printk (KERN_WARNING "clgen: unknown Board\n");
1594 vga_wgfx (fb_info->regs, VGA_GFX_MODE, 64); /* mode register: 256 color mode */
1595 WGen (fb_info, VGA_PEL_MSK, 0xff); /* pixel mask: pass-through all planes */
1596 WHDR (fb_info, 0xc5); /* hidden dac reg: 8-8-8 mode (24 or 32) */
1597 vga_wseq (fb_info->regs, VGA_SEQ_MEMORY_MODE, 0x0a); /* memory mode: chain4, ext. memory */
1598 vga_wseq (fb_info->regs, VGA_SEQ_PLANE_WRITE, 0xff); /* plane mask: enable writing to all 4 planes */
1599 offset = _par->var.xres_virtual / 4;
1602 /******************************************************
1604 * unknown/unsupported bpp
1609 printk (KERN_ERR "clgen: What's this?? requested color depth == %d.\n",
1610 _par->var.bits_per_pixel);
1613 if (IS_7548(fb_info)) {
1614 vga_wseq (fb_info->regs, CL_SEQR2D,
1615 vga_rseq (fb_info->regs, CL_SEQR2D) | 0xC0);
1618 vga_wcrt (fb_info->regs, VGA_CRTC_OFFSET, offset & 0xff);
1621 tmp |= 0x10; /* offset overflow bit */
1623 vga_wcrt (fb_info->regs, CL_CRT1B, tmp); /* screen start addr #16-18, fastpagemode cycles */
1625 if (fb_info->btype == BT_SD64 ||
1626 fb_info->btype == BT_PICASSO4 ||
1627 fb_info->btype == BT_ALPINE ||
1628 fb_info->btype == BT_GD5480)
1629 vga_wcrt (fb_info->regs, CL_CRT1D, 0x00); /* screen start address bit 19 */
1631 vga_wcrt (fb_info->regs, VGA_CRTC_CURSOR_HI, 0); /* text cursor location high */
1632 vga_wcrt (fb_info->regs, VGA_CRTC_CURSOR_LO, 0); /* text cursor location low */
1633 vga_wcrt (fb_info->regs, VGA_CRTC_UNDERLINE, 0); /* underline row scanline = at very bottom */
1635 vga_wattr (fb_info->regs, VGA_ATC_MODE, 1); /* controller mode */
1636 vga_wattr (fb_info->regs, VGA_ATC_OVERSCAN, 0); /* overscan (border) color */
1637 vga_wattr (fb_info->regs, VGA_ATC_PLANE_ENABLE, 15); /* color plane enable */
1638 vga_wattr (fb_info->regs, CL_AR33, 0); /* pixel panning */
1639 vga_wattr (fb_info->regs, VGA_ATC_COLOR_PAGE, 0); /* color select */
1641 /* [ EGS: SetOffset(); ] */
1642 /* From SetOffset(): Turn on VideoEnable bit in Attribute controller */
1645 vga_wgfx (fb_info->regs, VGA_GFX_SR_VALUE, 0); /* set/reset register */
1646 vga_wgfx (fb_info->regs, VGA_GFX_SR_ENABLE, 0); /* set/reset enable */
1647 vga_wgfx (fb_info->regs, VGA_GFX_COMPARE_VALUE, 0); /* color compare */
1648 vga_wgfx (fb_info->regs, VGA_GFX_DATA_ROTATE, 0); /* data rotate */
1649 vga_wgfx (fb_info->regs, VGA_GFX_PLANE_READ, 0); /* read map select */
1650 vga_wgfx (fb_info->regs, VGA_GFX_MISC, 1); /* miscellaneous register */
1651 vga_wgfx (fb_info->regs, VGA_GFX_COMPARE_MASK, 15); /* color don't care */
1652 vga_wgfx (fb_info->regs, VGA_GFX_BIT_MASK, 255); /* bit mask */
1654 vga_wseq (fb_info->regs, CL_SEQR12, 0x0); /* graphics cursor attributes: nothing special */
1656 /* finally, turn on everything - turn off "FullBandwidth" bit */
1657 /* also, set "DotClock%2" bit where requested */
1660 /*** FB_VMODE_CLOCK_HALVE in linux/fb.h not defined anymore ?
1661 if (var->vmode & FB_VMODE_CLOCK_HALVE)
1665 vga_wseq (fb_info->regs, VGA_SEQ_CLOCK_MODE, tmp);
1666 DPRINTK ("CL_SEQR1: %d\n", tmp);
1668 fb_info->currentmode = *_par;
1670 DPRINTK ("virtual offset: (%d,%d)\n", _par->var.xoffset, _par->var.yoffset);
1671 /* pan to requested offset */
1672 clgen_pan_display (&fb_info->currentmode.var, (struct fb_info_gen *) fb_info);
1683 static int clgen_getcolreg (unsigned regno, unsigned *red, unsigned *green,
1684 unsigned *blue, unsigned *transp,
1685 struct fb_info *info)
1687 struct clgenfb_info *fb_info = (struct clgenfb_info *)info;
1691 *red = fb_info->palette[regno].red;
1692 *green = fb_info->palette[regno].green;
1693 *blue = fb_info->palette[regno].blue;
1699 static int clgen_setcolreg (unsigned regno, unsigned red, unsigned green,
1700 unsigned blue, unsigned transp,
1701 struct fb_info *info)
1703 struct clgenfb_info *fb_info = (struct clgenfb_info *) info;
1708 #ifdef FBCON_HAS_CFB8
1709 switch (fb_info->currentmode.var.bits_per_pixel) {
1711 /* "transparent" stuff is completely ignored. */
1712 WClut (fb_info, regno, red >> 10, green >> 10, blue >> 10);
1718 #endif /* FBCON_HAS_CFB8 */
1720 fb_info->palette[regno].red = red;
1721 fb_info->palette[regno].green = green;
1722 fb_info->palette[regno].blue = blue;
1727 switch (fb_info->currentmode.var.bits_per_pixel) {
1729 #ifdef FBCON_HAS_CFB16
1731 assert (regno < 16);
1733 fb_info->fbcon_cmap.cfb16[regno] =
1734 ((red & 0xf800) >> 9) |
1735 ((green & 0xf800) >> 14) |
1736 ((green & 0xf800) << 2) |
1737 ((blue & 0xf800) >> 3);
1739 fb_info->fbcon_cmap.cfb16[regno] =
1740 ((red & 0xf800) >> 1) |
1741 ((green & 0xf800) >> 6) |
1742 ((blue & 0xf800) >> 11);
1744 #endif /* FBCON_HAS_CFB16 */
1746 #ifdef FBCON_HAS_CFB24
1748 assert (regno < 16);
1749 fb_info->fbcon_cmap.cfb24[regno] =
1750 (red << fb_info->currentmode.var.red.offset) |
1751 (green << fb_info->currentmode.var.green.offset) |
1752 (blue << fb_info->currentmode.var.blue.offset);
1754 #endif /* FBCON_HAS_CFB24 */
1756 #ifdef FBCON_HAS_CFB32
1758 assert (regno < 16);
1760 fb_info->fbcon_cmap.cfb32[regno] =
1762 ((green & 0xff00) << 8) |
1763 ((blue & 0xff00) << 16);
1765 fb_info->fbcon_cmap.cfb32[regno] =
1766 ((red & 0xff00) << 8) |
1767 ((green & 0xff00)) |
1768 ((blue & 0xff00) >> 8);
1771 #endif /* FBCON_HAS_CFB32 */
1780 /*************************************************************************
1783 performs display panning - provided hardware permits this
1784 **************************************************************************/
1785 static int clgen_pan_display (const struct fb_var_screeninfo *var,
1786 struct fb_info_gen *info)
1791 unsigned char tmp = 0, tmp2 = 0, xpix;
1792 struct clgenfb_info *fb_info = (struct clgenfb_info *) info;
1794 DPRINTK ("ENTER\n");
1796 /* no range checks for xoffset and yoffset, */
1797 /* as fbgen_pan_display has already done this */
1799 fb_info->currentmode.var.xoffset = var->xoffset;
1800 fb_info->currentmode.var.yoffset = var->yoffset;
1802 xoffset = var->xoffset * fb_info->currentmode.var.bits_per_pixel / 8;
1803 yoffset = var->yoffset;
1805 base = yoffset * fb_info->currentmode.line_length + xoffset;
1807 if (fb_info->currentmode.var.bits_per_pixel == 1) {
1808 /* base is already correct */
1809 xpix = (unsigned char) (var->xoffset % 8);
1812 xpix = (unsigned char) ((xoffset % 4) * 2);
1815 /* lower 8 + 8 bits of screen start address */
1816 vga_wcrt (fb_info->regs, VGA_CRTC_START_LO, (unsigned char) (base & 0xff));
1817 vga_wcrt (fb_info->regs, VGA_CRTC_START_HI, (unsigned char) (base >> 8));
1819 /* construct bits 16, 17 and 18 of screen start address */
1827 tmp2 = (vga_rcrt (fb_info->regs, CL_CRT1B) & 0xf2) | tmp; /* 0xf2 is %11110010, exclude tmp bits */
1828 vga_wcrt (fb_info->regs, CL_CRT1B, tmp2);
1830 /* construct bit 19 of screen start address */
1831 if (clgen_board_info[fb_info->btype].scrn_start_bit19) {
1835 vga_wcrt (fb_info->regs, CL_CRT1D, tmp2);
1838 /* write pixel panning value to AR33; this does not quite work in 8bpp */
1839 /* ### Piccolo..? Will this work? */
1840 if (fb_info->currentmode.var.bits_per_pixel == 1)
1841 vga_wattr (fb_info->regs, CL_AR33, xpix);
1849 static int clgen_blank (int blank_mode, struct fb_info_gen *info)
1852 * Blank the screen if blank_mode != 0, else unblank. If blank == NULL
1853 * then the caller blanks by setting the CLUT (Color Look Up Table) to all
1854 * black. Return 0 if blanking succeeded, != 0 if un-/blanking failed due
1855 * to e.g. a video mode which doesn't support it. Implements VESA suspend
1856 * and powerdown modes on hardware that supports disabling hsync/vsync:
1857 * blank_mode == 2: suspend vsync
1858 * blank_mode == 3: suspend hsync
1859 * blank_mode == 4: powerdown
1862 static int current_mode = 0;
1863 struct clgenfb_info *fb_info = (struct clgenfb_info *) info;
1865 DPRINTK ("ENTER, blank mode = %d\n", blank_mode);
1867 if (current_mode == blank_mode) {
1868 DPRINTK ("EXIT, returning 0\n");
1873 switch (current_mode) {
1874 case 0: /* Screen is normal */
1876 case 1: /* Screen is blanked */
1877 val = vga_rseq (fb_info->regs, VGA_SEQ_CLOCK_MODE);
1878 vga_wseq (fb_info->regs, VGA_SEQ_CLOCK_MODE, val & 0xdf); /* clear "FullBandwidth" bit */
1880 case 2: /* vsync suspended */
1881 case 3: /* hsync suspended */
1882 case 4: /* sceen is powered down */
1883 vga_wgfx (fb_info->regs, CL_GRE, 0x00);
1886 DPRINTK ("EXIT, returning 1\n");
1891 switch (blank_mode) {
1892 case 0: /* Unblank screen */
1894 case 1: /* Blank screen */
1895 val = vga_rseq (fb_info->regs, VGA_SEQ_CLOCK_MODE);
1896 vga_wseq (fb_info->regs, VGA_SEQ_CLOCK_MODE, val | 0x20); /* set "FullBandwidth" bit */
1898 case 2: /* suspend vsync */
1899 vga_wgfx (fb_info->regs, CL_GRE, 0x04);
1901 case 3: /* suspend hsync */
1902 vga_wgfx (fb_info->regs, CL_GRE, 0x02);
1904 case 4: /* powerdown */
1905 vga_wgfx (fb_info->regs, CL_GRE, 0x06);
1908 DPRINTK ("EXIT, returning 1\n");
1912 current_mode = blank_mode;
1913 DPRINTK ("EXIT, returning 0\n");
1916 /**** END Hardware specific Routines **************************************/
1917 /****************************************************************************/
1918 /**** BEGIN Internal Routines ***********************************************/
1920 static void __init init_vgachip (struct clgenfb_info *fb_info)
1922 const struct clgen_board_info_rec *bi;
1924 DPRINTK ("ENTER\n");
1926 assert (fb_info != NULL);
1928 bi = &clgen_board_info[fb_info->btype];
1930 /* reset board globally */
1931 switch (fb_info->btype) {
1933 WSFR (fb_info, 0x01);
1935 WSFR (fb_info, 0x51);
1939 WSFR2 (fb_info, 0xff);
1944 WSFR (fb_info, 0x1f);
1946 WSFR (fb_info, 0x4f);
1950 vga_wcrt (fb_info->regs, CL_CRT51, 0x00); /* disable flickerfixer */
1952 vga_wgfx (fb_info->regs, CL_GR2F, 0x00); /* from Klaus' NetBSD driver: */
1953 vga_wgfx (fb_info->regs, CL_GR33, 0x00); /* put blitter into 542x compat */
1954 vga_wgfx (fb_info->regs, CL_GR31, 0x00); /* mode */
1958 vga_wgfx (fb_info->regs, CL_GR2F, 0x00); /* from Klaus' NetBSD driver: */
1962 /* Nothing to do to reset the board. */
1966 printk (KERN_ERR "clgen: Warning: Unknown board type\n");
1970 assert (fb_info->size > 0); /* make sure RAM size set by this point */
1972 /* assume it's a "large memory" board (2/4 MB) */
1973 fb_info->smallboard = FALSE;
1975 /* the P4 is not fully initialized here; I rely on it having been */
1976 /* inited under AmigaOS already, which seems to work just fine */
1977 /* (Klaus advised to do it this way) */
1979 if (fb_info->btype != BT_PICASSO4) {
1980 WGen (fb_info, CL_VSSM, 0x10); /* EGS: 0x16 */
1981 WGen (fb_info, CL_POS102, 0x01);
1982 WGen (fb_info, CL_VSSM, 0x08); /* EGS: 0x0e */
1984 if (fb_info->btype != BT_SD64)
1985 WGen (fb_info, CL_VSSM2, 0x01);
1987 vga_wseq (fb_info->regs, CL_SEQR0, 0x03); /* reset sequencer logic */
1989 vga_wseq (fb_info->regs, VGA_SEQ_CLOCK_MODE, 0x21); /* FullBandwidth (video off) and 8/9 dot clock */
1990 WGen (fb_info, VGA_MIS_W, 0xc1); /* polarity (-/-), disable access to display memory, VGA_CRTC_START_HI base address: color */
1992 /* vga_wgfx (fb_info->regs, CL_GRA, 0xce); "magic cookie" - doesn't make any sense to me.. */
1993 vga_wseq (fb_info->regs, CL_SEQR6, 0x12); /* unlock all extension registers */
1995 vga_wgfx (fb_info->regs, CL_GR31, 0x04); /* reset blitter */
1997 switch (fb_info->btype) {
1999 vga_wseq (fb_info->regs, CL_SEQRF, 0x98);
2004 vga_wseq (fb_info->regs, CL_SEQRF, 0xb8);
2007 vga_wseq (fb_info->regs, CL_SEQR16, 0x0f);
2008 vga_wseq (fb_info->regs, CL_SEQRF, 0xb0);
2012 vga_wseq (fb_info->regs, VGA_SEQ_PLANE_WRITE, 0xff); /* plane mask: nothing */
2013 vga_wseq (fb_info->regs, VGA_SEQ_CHARACTER_MAP, 0x00); /* character map select: doesn't even matter in gx mode */
2014 vga_wseq (fb_info->regs, VGA_SEQ_MEMORY_MODE, 0x0e); /* memory mode: chain-4, no odd/even, ext. memory */
2016 /* controller-internal base address of video memory */
2018 vga_wseq (fb_info->regs, CL_SEQR7, bi->sr07);
2020 /* vga_wseq (fb_info->regs, CL_SEQR8, 0x00); *//* EEPROM control: shouldn't be necessary to write to this at all.. */
2022 vga_wseq (fb_info->regs, CL_SEQR10, 0x00); /* graphics cursor X position (incomplete; position gives rem. 3 bits */
2023 vga_wseq (fb_info->regs, CL_SEQR11, 0x00); /* graphics cursor Y position (..."... ) */
2024 vga_wseq (fb_info->regs, CL_SEQR12, 0x00); /* graphics cursor attributes */
2025 vga_wseq (fb_info->regs, CL_SEQR13, 0x00); /* graphics cursor pattern address */
2027 /* writing these on a P4 might give problems.. */
2028 if (fb_info->btype != BT_PICASSO4) {
2029 vga_wseq (fb_info->regs, CL_SEQR17, 0x00); /* configuration readback and ext. color */
2030 vga_wseq (fb_info->regs, CL_SEQR18, 0x02); /* signature generator */
2033 /* MCLK select etc. */
2035 vga_wseq (fb_info->regs, CL_SEQR1F, bi->sr1f);
2037 vga_wcrt (fb_info->regs, VGA_CRTC_PRESET_ROW, 0x00); /* Screen A preset row scan: none */
2038 vga_wcrt (fb_info->regs, VGA_CRTC_CURSOR_START, 0x20); /* Text cursor start: disable text cursor */
2039 vga_wcrt (fb_info->regs, VGA_CRTC_CURSOR_END, 0x00); /* Text cursor end: - */
2040 vga_wcrt (fb_info->regs, VGA_CRTC_START_HI, 0x00); /* Screen start address high: 0 */
2041 vga_wcrt (fb_info->regs, VGA_CRTC_START_LO, 0x00); /* Screen start address low: 0 */
2042 vga_wcrt (fb_info->regs, VGA_CRTC_CURSOR_HI, 0x00); /* text cursor location high: 0 */
2043 vga_wcrt (fb_info->regs, VGA_CRTC_CURSOR_LO, 0x00); /* text cursor location low: 0 */
2045 vga_wcrt (fb_info->regs, VGA_CRTC_UNDERLINE, 0x00); /* Underline Row scanline: - */
2046 vga_wcrt (fb_info->regs, VGA_CRTC_MODE, 0xc3); /* mode control: timing enable, byte mode, no compat modes */
2047 vga_wcrt (fb_info->regs, VGA_CRTC_LINE_COMPARE, 0x00); /* Line Compare: not needed */
2048 /* ### add 0x40 for text modes with > 30 MHz pixclock */
2049 vga_wcrt (fb_info->regs, CL_CRT1B, 0x02); /* ext. display controls: ext.adr. wrap */
2051 vga_wgfx (fb_info->regs, VGA_GFX_SR_VALUE, 0x00); /* Set/Reset registes: - */
2052 vga_wgfx (fb_info->regs, VGA_GFX_SR_ENABLE, 0x00); /* Set/Reset enable: - */
2053 vga_wgfx (fb_info->regs, VGA_GFX_COMPARE_VALUE, 0x00); /* Color Compare: - */
2054 vga_wgfx (fb_info->regs, VGA_GFX_DATA_ROTATE, 0x00); /* Data Rotate: - */
2055 vga_wgfx (fb_info->regs, VGA_GFX_PLANE_READ, 0x00); /* Read Map Select: - */
2056 vga_wgfx (fb_info->regs, VGA_GFX_MODE, 0x00); /* Mode: conf. for 16/4/2 color mode, no odd/even, read/write mode 0 */
2057 vga_wgfx (fb_info->regs, VGA_GFX_MISC, 0x01); /* Miscellaneous: memory map base address, graphics mode */
2058 vga_wgfx (fb_info->regs, VGA_GFX_COMPARE_MASK, 0x0f); /* Color Don't care: involve all planes */
2059 vga_wgfx (fb_info->regs, VGA_GFX_BIT_MASK, 0xff); /* Bit Mask: no mask at all */
2060 if (fb_info->btype == BT_ALPINE)
2061 vga_wgfx (fb_info->regs, CL_GRB, 0x20); /* (5434 can't have bit 3 set for bitblt) */
2063 vga_wgfx (fb_info->regs, CL_GRB, 0x28); /* Graphics controller mode extensions: finer granularity, 8byte data latches */
2065 vga_wgfx (fb_info->regs, CL_GRC, 0xff); /* Color Key compare: - */
2066 vga_wgfx (fb_info->regs, CL_GRD, 0x00); /* Color Key compare mask: - */
2067 vga_wgfx (fb_info->regs, CL_GRE, 0x00); /* Miscellaneous control: - */
2068 /* vga_wgfx (fb_info->regs, CL_GR10, 0x00); *//* Background color byte 1: - */
2069 /* vga_wgfx (fb_info->regs, CL_GR11, 0x00); */
2071 vga_wattr (fb_info->regs, VGA_ATC_PALETTE0, 0x00); /* Attribute Controller palette registers: "identity mapping" */
2072 vga_wattr (fb_info->regs, VGA_ATC_PALETTE1, 0x01);
2073 vga_wattr (fb_info->regs, VGA_ATC_PALETTE2, 0x02);
2074 vga_wattr (fb_info->regs, VGA_ATC_PALETTE3, 0x03);
2075 vga_wattr (fb_info->regs, VGA_ATC_PALETTE4, 0x04);
2076 vga_wattr (fb_info->regs, VGA_ATC_PALETTE5, 0x05);
2077 vga_wattr (fb_info->regs, VGA_ATC_PALETTE6, 0x06);
2078 vga_wattr (fb_info->regs, VGA_ATC_PALETTE7, 0x07);
2079 vga_wattr (fb_info->regs, VGA_ATC_PALETTE8, 0x08);
2080 vga_wattr (fb_info->regs, VGA_ATC_PALETTE9, 0x09);
2081 vga_wattr (fb_info->regs, VGA_ATC_PALETTEA, 0x0a);
2082 vga_wattr (fb_info->regs, VGA_ATC_PALETTEB, 0x0b);
2083 vga_wattr (fb_info->regs, VGA_ATC_PALETTEC, 0x0c);
2084 vga_wattr (fb_info->regs, VGA_ATC_PALETTED, 0x0d);
2085 vga_wattr (fb_info->regs, VGA_ATC_PALETTEE, 0x0e);
2086 vga_wattr (fb_info->regs, VGA_ATC_PALETTEF, 0x0f);
2088 vga_wattr (fb_info->regs, VGA_ATC_MODE, 0x01); /* Attribute Controller mode: graphics mode */
2089 vga_wattr (fb_info->regs, VGA_ATC_OVERSCAN, 0x00); /* Overscan color reg.: reg. 0 */
2090 vga_wattr (fb_info->regs, VGA_ATC_PLANE_ENABLE, 0x0f); /* Color Plane enable: Enable all 4 planes */
2091 /* ### vga_wattr (fb_info->regs, CL_AR33, 0x00); * Pixel Panning: - */
2092 vga_wattr (fb_info->regs, VGA_ATC_COLOR_PAGE, 0x00); /* Color Select: - */
2094 WGen (fb_info, VGA_PEL_MSK, 0xff); /* Pixel mask: no mask */
2096 if (fb_info->btype != BT_ALPINE && fb_info->btype != BT_GD5480)
2097 WGen (fb_info, VGA_MIS_W, 0xc3); /* polarity (-/-), enable display mem, VGA_CRTC_START_HI i/o base = color */
2099 vga_wgfx (fb_info->regs, CL_GR31, 0x04); /* BLT Start/status: Blitter reset */
2100 vga_wgfx (fb_info->regs, CL_GR31, 0x00); /* - " - : "end-of-reset" */
2103 WClut (fb_info, 0, 0x00, 0x00, 0x00); /* background: black */
2104 WClut (fb_info, 1, 0x3f, 0x3f, 0x3f); /* foreground: white */
2105 WClut (fb_info, 2, 0x00, 0x20, 0x00);
2106 WClut (fb_info, 3, 0x00, 0x20, 0x20);
2107 WClut (fb_info, 4, 0x20, 0x00, 0x00);
2108 WClut (fb_info, 5, 0x20, 0x00, 0x20);
2109 WClut (fb_info, 6, 0x20, 0x10, 0x00);
2110 WClut (fb_info, 7, 0x20, 0x20, 0x20);
2111 WClut (fb_info, 8, 0x10, 0x10, 0x10);
2112 WClut (fb_info, 9, 0x10, 0x10, 0x30);
2113 WClut (fb_info, 10, 0x10, 0x30, 0x10);
2114 WClut (fb_info, 11, 0x10, 0x30, 0x30);
2115 WClut (fb_info, 12, 0x30, 0x10, 0x10);
2116 WClut (fb_info, 13, 0x30, 0x10, 0x30);
2117 WClut (fb_info, 14, 0x30, 0x30, 0x10);
2118 WClut (fb_info, 15, 0x30, 0x30, 0x30);
2120 /* the rest a grey ramp */
2124 for (i = 16; i < 256; i++)
2125 WClut (fb_info, i, i >> 2, i >> 2, i >> 2);
2130 WHDR (fb_info, 0); /* Hidden DAC register: - */
2132 printk (KERN_INFO "clgen: This board has %ld bytes of DRAM memory\n", fb_info->size);
2137 static void switch_monitor (struct clgenfb_info *fb_info, int on)
2139 #ifdef CONFIG_ZORRO /* only works on Zorro boards */
2140 static int IsOn = 0; /* XXX not ok for multiple boards */
2142 DPRINTK ("ENTER\n");
2144 if (fb_info->btype == BT_PICASSO4)
2145 return; /* nothing to switch */
2146 if (fb_info->btype == BT_ALPINE)
2147 return; /* nothing to switch */
2148 if (fb_info->btype == BT_GD5480)
2149 return; /* nothing to switch */
2150 if (fb_info->btype == BT_PICASSO) {
2151 if ((on && !IsOn) || (!on && IsOn))
2152 WSFR (fb_info, 0xff);
2158 switch (fb_info->btype) {
2160 WSFR (fb_info, fb_info->SFR | 0x21);
2163 WSFR (fb_info, fb_info->SFR | 0x28);
2166 WSFR (fb_info, 0x6f);
2168 default: /* do nothing */ break;
2171 switch (fb_info->btype) {
2173 WSFR (fb_info, fb_info->SFR & 0xde);
2176 WSFR (fb_info, fb_info->SFR & 0xd7);
2179 WSFR (fb_info, 0x4f);
2181 default: /* do nothing */ break;
2186 #endif /* CONFIG_ZORRO */
2189 static void clgen_set_disp (const void *par, struct display *disp,
2190 struct fb_info_gen *info)
2192 struct clgenfb_par *_par = (struct clgenfb_par *) par;
2193 struct clgenfb_info *fb_info = (struct clgenfb_info *) info;
2196 DPRINTK ("ENTER\n");
2198 assert (_par != NULL);
2199 assert (fb_info != NULL);
2201 accel_text = _par->var.accel_flags & FB_ACCELF_TEXT;
2203 printk ("Cirrus Logic video mode: ");
2204 disp->screen_base = (char *) fb_info->fbmem;
2205 switch (_par->var.bits_per_pixel) {
2206 #ifdef FBCON_HAS_MFB
2208 printk ("monochrome\n");
2209 if (fb_info->btype == BT_GD5480)
2210 disp->screen_base = (char *) fb_info->fbmem;
2211 disp->dispsw = &fbcon_mfb;
2214 #ifdef FBCON_HAS_CFB8
2216 printk ("8 bit color depth\n");
2217 if (fb_info->btype == BT_GD5480)
2218 disp->screen_base = (char *) fb_info->fbmem;
2220 disp->dispsw = &fbcon_clgen_8;
2222 disp->dispsw = &fbcon_cfb8;
2225 #ifdef FBCON_HAS_CFB16
2227 printk ("16 bit color depth\n");
2229 disp->dispsw = &fbcon_clgen_16;
2231 disp->dispsw = &fbcon_cfb16;
2232 if (fb_info->btype == BT_GD5480)
2233 disp->screen_base = (char *) fb_info->fbmem + 1 * MB_;
2234 disp->dispsw_data = fb_info->fbcon_cmap.cfb16;
2237 #ifdef FBCON_HAS_CFB24
2239 printk ("24 bit color depth\n");
2240 disp->dispsw = &fbcon_cfb24;
2241 if (fb_info->btype == BT_GD5480)
2242 disp->screen_base = (char *) fb_info->fbmem + 2 * MB_;
2243 disp->dispsw_data = fb_info->fbcon_cmap.cfb24;
2246 #ifdef FBCON_HAS_CFB32
2248 printk ("32 bit color depth\n");
2250 disp->dispsw = &fbcon_clgen_32;
2252 disp->dispsw = &fbcon_cfb32;
2253 if (fb_info->btype == BT_GD5480)
2254 disp->screen_base = (char *) fb_info->fbmem + 2 * MB_;
2255 disp->dispsw_data = fb_info->fbcon_cmap.cfb32;
2260 printk ("unsupported color depth\n");
2261 disp->dispsw = &fbcon_dummy;
2262 disp->dispsw_data = NULL;
2269 #ifdef FBCON_HAS_CFB8
2270 static void fbcon_clgen8_bmove (struct display *p, int sy, int sx,
2271 int dy, int dx, int height, int width)
2273 struct clgenfb_info *fb_info = (struct clgenfb_info *) p->fb_info;
2275 DPRINTK ("ENTER\n");
2277 sx *= fontwidth (p);
2278 sy *= fontheight (p);
2279 dx *= fontwidth (p);
2280 dy *= fontheight (p);
2281 width *= fontwidth (p);
2282 height *= fontheight (p);
2284 clgen_BitBLT (fb_info->regs, (unsigned short) sx, (unsigned short) sy,
2285 (unsigned short) dx, (unsigned short) dy,
2286 (unsigned short) width, (unsigned short) height,
2287 fb_info->currentmode.line_length);
2292 static void fbcon_clgen8_clear (struct vc_data *conp, struct display *p,
2293 int sy, int sx, int height, int width)
2295 struct clgenfb_info *fb_info = (struct clgenfb_info *) p->fb_info;
2298 DPRINTK ("ENTER\n");
2300 sx *= fontwidth (p);
2301 sy *= fontheight (p);
2302 width *= fontwidth (p);
2303 height *= fontheight (p);
2305 col = attr_bgcol_ec (p, conp);
2308 clgen_RectFill (fb_info, (unsigned short) sx, (unsigned short) sy,
2309 (unsigned short) width, (unsigned short) height,
2310 col, fb_info->currentmode.line_length);
2317 #ifdef FBCON_HAS_CFB16
2318 static void fbcon_clgen16_bmove (struct display *p, int sy, int sx,
2319 int dy, int dx, int height, int width)
2321 struct clgenfb_info *fb_info = (struct clgenfb_info *) p->fb_info;
2323 DPRINTK ("ENTER\n");
2325 sx *= fontwidth (p) * 2; /* 2 bytes/pixel */
2326 sy *= fontheight (p);
2327 dx *= fontwidth (p) * 2; /* 2 bytes/pixel */
2328 dy *= fontheight (p);
2329 width *= fontwidth (p) * 2; /* 2 bytes/pixel */
2330 height *= fontheight (p);
2332 clgen_BitBLT (fb_info->regs, (unsigned short) sx, (unsigned short) sy,
2333 (unsigned short) dx, (unsigned short) dy,
2334 (unsigned short) width, (unsigned short) height,
2335 fb_info->currentmode.line_length);
2340 static void fbcon_clgen16_clear (struct vc_data *conp, struct display *p,
2341 int sy, int sx, int height, int width)
2343 struct clgenfb_info *fb_info = (struct clgenfb_info *) p->fb_info;
2346 DPRINTK ("ENTER\n");
2348 sx *= fontwidth (p) * 2; /* 2 bytes/pixel */
2349 sy *= fontheight (p);
2350 width *= fontwidth (p) * 2; /* 2 bytes/pixel? */
2351 height *= fontheight (p);
2353 col = attr_bgcol_ec (p, conp);
2356 clgen_RectFill (fb_info, (unsigned short) sx, (unsigned short) sy,
2357 (unsigned short) width, (unsigned short) height,
2358 col, fb_info->currentmode.line_length);
2365 #ifdef FBCON_HAS_CFB32
2366 static void fbcon_clgen32_bmove (struct display *p, int sy, int sx,
2367 int dy, int dx, int height, int width)
2369 struct clgenfb_info *fb_info = (struct clgenfb_info *) p->fb_info;
2371 DPRINTK ("ENTER\n");
2373 sx *= fontwidth (p) * 4; /* 4 bytes/pixel */
2374 sy *= fontheight (p);
2375 dx *= fontwidth (p) * 4; /* 4 bytes/pixel */
2376 dy *= fontheight (p);
2377 width *= fontwidth (p) * 4; /* 4 bytes/pixel */
2378 height *= fontheight (p);
2380 clgen_BitBLT (fb_info->regs, (unsigned short) sx, (unsigned short) sy,
2381 (unsigned short) dx, (unsigned short) dy,
2382 (unsigned short) width, (unsigned short) height,
2383 fb_info->currentmode.line_length);
2388 static void fbcon_clgen32_clear (struct vc_data *conp, struct display *p,
2389 int sy, int sx, int height, int width)
2391 struct clgenfb_info *fb_info = (struct clgenfb_info *) p->fb_info;
2395 DPRINTK ("ENTER\n");
2397 sx *= fontwidth (p) * 4; /* 4 bytes/pixel */
2398 sy *= fontheight (p);
2399 width *= fontwidth (p) * 4; /* 4 bytes/pixel? */
2400 height *= fontheight (p);
2402 col = attr_bgcol_ec (p, conp);
2405 clgen_RectFill (fb_info, (unsigned short) sx, (unsigned short) sy,
2406 (unsigned short) width, (unsigned short) height,
2407 col, fb_info->currentmode.line_length);
2412 #endif /* FBCON_HAS_CFB32 */
2417 #ifdef CONFIG_ALL_PPC
2418 #define PREP_VIDEO_BASE ((volatile unsigned long) 0xC0000000)
2419 #define PREP_IO_BASE ((volatile unsigned char *) 0x80000000)
2420 static void __init get_prep_addrs (unsigned long *display, unsigned long *registers)
2422 DPRINTK ("ENTER\n");
2424 *display = PREP_VIDEO_BASE;
2425 *registers = (unsigned long) PREP_IO_BASE;
2430 #endif /* CONFIG_ALL_PPC */
2436 static int release_io_ports = 0;
2438 /* Pulled the logic from XFree86 Cirrus driver to get the memory size,
2439 * based on the DRAM bandwidth bit and DRAM bank switching bit. This
2440 * works with 1MB, 2MB and 4MB configurations (which the Motorola boards
2442 static unsigned int __init clgen_get_memsize (caddr_t regbase)
2447 DPRINTK ("ENTER\n");
2449 SRF = vga_rseq (regbase, CL_SEQRF);
2450 switch ((SRF & 0x18)) {
2451 case 0x08: mem = 512 * 1024; break;
2452 case 0x10: mem = 1024 * 1024; break;
2453 /* 64-bit DRAM data bus width; assume 2MB. Also indicates 2MB memory
2455 case 0x18: mem = 2048 * 1024; break;
2456 default: printk ("CLgenfb: Unknown memory size!\n");
2460 /* If DRAM bank switching is enabled, there must be twice as much
2461 * memory installed. (4MB on the 5434) */
2464 /* TODO: Handling of GD5446/5480 (see XF86 sources ...) */
2472 static struct pci_dev * __init clgen_pci_dev_get (clgen_board_t *btype)
2474 struct pci_dev *pdev;
2477 DPRINTK ("ENTER\n");
2479 for (i = 0; i < ARRAY_SIZE(clgen_pci_probe_list); i++) {
2481 while ((pdev = pci_find_device (PCI_VENDOR_ID_CIRRUS,
2482 clgen_pci_probe_list[i].device, pdev)) != NULL) {
2483 if (pci_enable_device(pdev) == 0) {
2484 *btype = clgen_pci_probe_list[i].btype;
2485 DPRINTK ("EXIT, returning pdev=%p\n", pdev);
2491 DPRINTK ("EXIT, returning NULL\n");
2498 static void __init get_pci_addrs (const struct pci_dev *pdev,
2499 unsigned long *display, unsigned long *registers)
2501 assert (pdev != NULL);
2502 assert (display != NULL);
2503 assert (registers != NULL);
2505 DPRINTK ("ENTER\n");
2510 /* This is a best-guess for now */
2512 if (pci_resource_flags(pdev, 0) & IORESOURCE_IO) {
2513 *display = pci_resource_start(pdev, 1);
2514 *registers = pci_resource_start(pdev, 0);
2516 *display = pci_resource_start(pdev, 0);
2517 *registers = pci_resource_start(pdev, 1);
2520 assert (*display != 0);
2526 static void __exit clgen_pci_unmap (struct clgenfb_info *info)
2528 iounmap (info->fbmem);
2529 release_mem_region(info->fbmem_phys, info->size);
2531 #if 0 /* if system didn't claim this region, we would... */
2532 release_mem_region(0xA0000, 65535);
2535 if (release_io_ports)
2536 release_region(0x3C0, 32);
2540 static int __init clgen_pci_setup (struct clgenfb_info *info,
2541 clgen_board_t *btype)
2543 struct pci_dev *pdev;
2544 unsigned long board_addr, board_size;
2546 DPRINTK ("ENTER\n");
2548 pdev = clgen_pci_dev_get (btype);
2550 printk (KERN_ERR " Couldn't find PCI device\n");
2551 DPRINTK ("EXIT, returning 1\n");
2554 DPRINTK (" Found PCI device, base address 0 is 0x%lx, btype set to %d\n",
2555 pdev->resource[0].start, *btype);
2556 DPRINTK (" base address 1 is 0x%lx\n", pdev->resource[1].start);
2561 /* Xbh does this, though 0 seems to be the init value */
2562 pcibios_write_config_dword (0, pdev->devfn, PCI_BASE_ADDRESS_0,
2565 #ifdef CONFIG_ALL_PPC
2566 get_prep_addrs (&board_addr, &info->fbregs_phys);
2569 DPRINTK ("Attempt to get PCI info for Cirrus Graphics Card\n");
2570 get_pci_addrs (pdev, &board_addr, &info->fbregs_phys);
2573 DPRINTK ("Board address: 0x%lx, register address: 0x%lx\n", board_addr, info->fbregs_phys);
2576 /* PReP dies if we ioremap the IO registers, but it works w/out... */
2577 info->regs = (char *) info->fbregs_phys;
2579 info->regs = 0; /* FIXME: this forces VGA. alternatives? */
2581 if (*btype == BT_GD5480) {
2582 board_size = 32 * MB_;
2584 board_size = clgen_get_memsize (info->regs);
2587 if (!request_mem_region(board_addr, board_size, "clgenfb")) {
2588 printk(KERN_ERR "clgen: cannot reserve region 0x%lx, abort\n",
2592 #if 0 /* if the system didn't claim this region, we would... */
2593 if (!request_mem_region(0xA0000, 65535, "clgenfb")) {
2594 printk(KERN_ERR "clgen: cannot reserve region 0x%lx, abort\n",
2596 release_mem_region(board_addr, board_size);
2600 if (request_region(0x3C0, 32, "clgenfb"))
2601 release_io_ports = 1;
2603 info->fbmem = ioremap (board_addr, board_size);
2604 info->fbmem_phys = board_addr;
2605 info->size = board_size;
2607 printk (" RAM (%lu kB) at 0x%lx, ", info->size / KB_, board_addr);
2609 printk ("Cirrus Logic chipset on PCI bus\n");
2611 DPRINTK ("EXIT, returning 0\n");
2614 #endif /* CONFIG_PCI */
2620 static int __init clgen_zorro_find (struct zorro_dev **z_o,
2621 struct zorro_dev **z2_o,
2622 clgen_board_t *btype, unsigned long *size)
2624 struct zorro_dev *z = NULL;
2627 assert (z_o != NULL);
2628 assert (btype != NULL);
2630 for (i = 0; i < ARRAY_SIZE(clgen_zorro_probe_list); i++)
2631 if ((z = zorro_find_device(clgen_zorro_probe_list[i].id, NULL)))
2636 if (clgen_zorro_probe_list[i].id2)
2637 *z2_o = zorro_find_device(clgen_zorro_probe_list[i].id2, NULL);
2641 *btype = clgen_zorro_probe_list[i].btype;
2642 *size = clgen_zorro_probe_list[i].size;
2644 printk (KERN_INFO "clgen: %s board detected; ",
2645 clgen_board_info[*btype].name);
2650 printk (KERN_NOTICE "clgen: no supported board found.\n");
2655 static void __exit clgen_zorro_unmap (struct clgenfb_info *info)
2657 release_mem_region(info->board_addr, info->board_size);
2659 if (info->btype == BT_PICASSO4) {
2660 iounmap ((void *)info->board_addr);
2661 iounmap ((void *)info->fbmem_phys);
2663 if (info->board_addr > 0x01000000)
2664 iounmap ((void *)info->board_addr);
2669 static int __init clgen_zorro_setup (struct clgenfb_info *info,
2670 clgen_board_t *btype)
2672 struct zorro_dev *z = NULL, *z2 = NULL;
2673 unsigned long board_addr, board_size, size;
2675 assert (info != NULL);
2676 assert (btype != NULL);
2678 if (clgen_zorro_find (&z, &z2, btype, &size))
2683 assert (*btype != BT_NONE);
2685 info->board_addr = board_addr = z->resource.start;
2686 info->board_size = board_size = z->resource.end-z->resource.start+1;
2689 if (!request_mem_region(board_addr, board_size, "clgenfb")) {
2690 printk(KERN_ERR "clgen: cannot reserve region 0x%lx, abort\n",
2695 printk (" RAM (%lu MB) at $%lx, ", board_size / MB_, board_addr);
2697 if (*btype == BT_PICASSO4) {
2698 printk (" REG at $%lx\n", board_addr + 0x600000);
2700 /* To be precise, for the P4 this is not the */
2701 /* begin of the board, but the begin of RAM. */
2702 /* for P4, map in its address space in 2 chunks (### TEST! ) */
2703 /* (note the ugly hardcoded 16M number) */
2704 info->regs = ioremap (board_addr, 16777216);
2705 DPRINTK ("clgen: Virtual address for board set to: $%p\n", info->regs);
2706 info->regs += 0x600000;
2707 info->fbregs_phys = board_addr + 0x600000;
2709 info->fbmem_phys = board_addr + 16777216;
2710 info->fbmem = ioremap (info->fbmem_phys, 16777216);
2712 printk (" REG at $%lx\n", (unsigned long) z2->resource.start);
2714 info->fbmem_phys = board_addr;
2715 if (board_addr > 0x01000000)
2716 info->fbmem = ioremap (board_addr, board_size);
2718 info->fbmem = (caddr_t) ZTWO_VADDR (board_addr);
2720 /* set address for REG area of board */
2721 info->regs = (caddr_t) ZTWO_VADDR (z2->resource.start);
2722 info->fbregs_phys = z2->resource.start;
2724 DPRINTK ("clgen: Virtual address for board set to: $%p\n", info->regs);
2727 printk (KERN_INFO "Cirrus Logic chipset on Zorro bus\n");
2731 #endif /* CONFIG_ZORRO */
2735 /********************************************************************/
2736 /* clgenfb_init() - master initialization function */
2737 /********************************************************************/
2738 int __init clgenfb_init(void)
2742 clgen_board_t btype = BT_NONE;
2743 struct clgenfb_info *fb_info = NULL;
2745 DPRINTK ("ENTER\n");
2747 printk (KERN_INFO "clgen: Driver for Cirrus Logic based graphic boards, v" CLGEN_VERSION "\n");
2749 fb_info = &boards[0]; /* FIXME support multiple boards ... */
2752 if (clgen_pci_setup (fb_info, &btype)) { /* Also does OF setup */
2753 DPRINTK ("EXIT, returning -ENXIO\n");
2757 #elif defined(CONFIG_ZORRO)
2758 /* FIXME: CONFIG_PCI and CONFIG_ZORRO may both be defined */
2759 if (clgen_zorro_setup (fb_info, &btype)) {
2760 DPRINTK ("EXIT, returning -ENXIO\n");
2765 #error This driver requires Zorro or PCI bus.
2766 #endif /* !CONFIG_PCI, !CONFIG_ZORRO */
2769 assert (btype != BT_NONE);
2770 assert (btype == clgen_board_info[btype].btype);
2772 fb_info->btype = btype;
2774 DPRINTK ("clgen: (RAM start set to: 0x%p)\n", fb_info->fbmem);
2778 printk("clgen: disabling text acceleration support\n");
2779 #ifdef FBCON_HAS_CFB8
2780 fbcon_clgen_8.bmove = fbcon_cfb8_bmove;
2781 fbcon_clgen_8.clear = fbcon_cfb8_clear;
2783 #ifdef FBCON_HAS_CFB16
2784 fbcon_clgen_16.bmove = fbcon_cfb16_bmove;
2785 fbcon_clgen_16.clear = fbcon_cfb16_clear;
2787 #ifdef FBCON_HAS_CFB32
2788 fbcon_clgen_32.bmove = fbcon_cfb32_bmove;
2789 fbcon_clgen_32.clear = fbcon_cfb32_clear;
2793 init_vgachip (fb_info);
2795 /* set up a few more things, register framebuffer driver etc */
2796 fb_info->gen.parsize = sizeof (struct clgenfb_par);
2797 fb_info->gen.fbhw = &clgen_hwswitch;
2799 strncpy (fb_info->gen.info.modename, clgen_board_info[btype].name,
2800 sizeof (fb_info->gen.info.modename));
2801 fb_info->gen.info.modename [sizeof (fb_info->gen.info.modename) - 1] = 0;
2803 fb_info->gen.info.node = -1;
2804 fb_info->gen.info.fbops = &clgenfb_ops;
2805 fb_info->gen.info.disp = &disp;
2806 fb_info->gen.info.changevar = NULL;
2807 fb_info->gen.info.switch_con = &fbgen_switch;
2808 fb_info->gen.info.updatevar = &fbgen_update_var;
2809 fb_info->gen.info.blank = &fbgen_blank;
2810 fb_info->gen.info.flags = FBINFO_FLAG_DEFAULT;
2812 for (j = 0; j < 256; j++) {
2815 fb_info->palette[j].red = default_red[k];
2816 fb_info->palette[j].green = default_grn[k];
2817 fb_info->palette[j].blue = default_blu[k];
2819 fb_info->palette[j].red =
2820 fb_info->palette[j].green =
2821 fb_info->palette[j].blue = j;
2825 /* now that we know the board has been registered n' stuff, we */
2826 /* can finally initialize it to a default mode */
2827 clgenfb_default = clgenfb_predefined[clgen_def_mode].var;
2828 clgenfb_default.activate = FB_ACTIVATE_NOW;
2829 clgenfb_default.yres_virtual = 480 * 3; /* for fast scrolling (YPAN-Mode) */
2830 err = fbgen_do_set_var (&clgenfb_default, 1, &fb_info->gen);
2833 DPRINTK ("EXIT, returning -EINVAL\n");
2837 disp.var = clgenfb_default;
2838 fbgen_set_disp (-1, &fb_info->gen);
2839 fbgen_install_cmap (0, &fb_info->gen);
2841 err = register_framebuffer (&fb_info->gen.info);
2843 printk (KERN_ERR "clgen: ERROR - could not register fb device; err = %d!\n", err);
2844 DPRINTK ("EXIT, returning -EINVAL\n");
2847 DPRINTK ("EXIT, returning 0\n");
2854 * Cleanup (only needed for module)
2856 static void __exit clgenfb_cleanup (struct clgenfb_info *info)
2858 DPRINTK ("ENTER\n");
2861 switch_monitor (info, 0);
2863 clgen_zorro_unmap (info);
2865 clgen_pci_unmap (info);
2866 #endif /* CONFIG_ZORRO */
2868 unregister_framebuffer ((struct fb_info *) info);
2869 printk ("Framebuffer unregistered\n");
2876 int __init clgenfb_setup(char *options) {
2877 char *this_opt, s[32];
2880 DPRINTK ("ENTER\n");
2882 if (!options || !*options)
2885 for (this_opt = strtok (options, ","); this_opt != NULL;
2886 this_opt = strtok (NULL, ",")) {
2887 if (!*this_opt) continue;
2889 DPRINTK("clgenfb_setup: option '%s'\n", this_opt);
2891 for (i = 0; i < NUM_TOTAL_MODES; i++) {
2892 sprintf (s, "mode:%s", clgenfb_predefined[i].name);
2893 if (strcmp (this_opt, s) == 0)
2896 if (!strcmp(this_opt, "noaccel"))
2908 MODULE_AUTHOR("Copyright 1999,2000 Jeff Garzik <jgarzik@pobox.com>");
2909 MODULE_DESCRIPTION("Accelerated FBDev driver for Cirrus Logic chips");
2910 MODULE_LICENSE("GPL");
2912 static void __exit clgenfb_exit (void)
2914 DPRINTK ("ENTER\n");
2916 clgenfb_cleanup (&boards[0]); /* FIXME: support multiple boards */
2922 module_init(clgenfb_init);
2924 module_exit(clgenfb_exit);
2927 /**********************************************************************/
2928 /* about the following functions - I have used the same names for the */
2929 /* functions as Markus Wild did in his Retina driver for NetBSD as */
2930 /* they just made sense for this purpose. Apart from that, I wrote */
2931 /* these functions myself. */
2932 /**********************************************************************/
2934 /*** WGen() - write into one of the external/general registers ***/
2935 static void WGen (const struct clgenfb_info *fb_info,
2936 int regnum, unsigned char val)
2938 unsigned long regofs = 0;
2940 if (fb_info->btype == BT_PICASSO) {
2941 /* Picasso II specific hack */
2942 /* if (regnum == VGA_PEL_IR || regnum == VGA_PEL_D || regnum == CL_VSSM2) */
2943 if (regnum == VGA_PEL_IR || regnum == VGA_PEL_D)
2947 vga_w (fb_info->regs, regofs + regnum, val);
2950 /*** RGen() - read out one of the external/general registers ***/
2951 static unsigned char RGen (const struct clgenfb_info *fb_info, int regnum)
2953 unsigned long regofs = 0;
2955 if (fb_info->btype == BT_PICASSO) {
2956 /* Picasso II specific hack */
2957 /* if (regnum == VGA_PEL_IR || regnum == VGA_PEL_D || regnum == CL_VSSM2) */
2958 if (regnum == VGA_PEL_IR || regnum == VGA_PEL_D)
2962 return vga_r (fb_info->regs, regofs + regnum);
2965 /*** AttrOn() - turn on VideoEnable for Attribute controller ***/
2966 static void AttrOn (const struct clgenfb_info *fb_info)
2968 assert (fb_info != NULL);
2970 DPRINTK ("ENTER\n");
2972 if (vga_rcrt (fb_info->regs, CL_CRT24) & 0x80) {
2973 /* if we're just in "write value" mode, write back the */
2974 /* same value as before to not modify anything */
2975 vga_w (fb_info->regs, VGA_ATT_IW,
2976 vga_r (fb_info->regs, VGA_ATT_R));
2978 /* turn on video bit */
2979 /* vga_w (fb_info->regs, VGA_ATT_IW, 0x20); */
2980 vga_w (fb_info->regs, VGA_ATT_IW, 0x33);
2982 /* dummy write on Reg0 to be on "write index" mode next time */
2983 vga_w (fb_info->regs, VGA_ATT_IW, 0x00);
2988 /*** WHDR() - write into the Hidden DAC register ***/
2989 /* as the HDR is the only extension register that requires special treatment
2990 * (the other extension registers are accessible just like the "ordinary"
2991 * registers of their functional group) here is a specialized routine for
2994 static void WHDR (const struct clgenfb_info *fb_info, unsigned char val)
2996 unsigned char dummy;
2998 if (fb_info->btype == BT_PICASSO) {
2999 /* Klaus' hint for correct access to HDR on some boards */
3000 /* first write 0 to pixel mask (3c6) */
3001 WGen (fb_info, VGA_PEL_MSK, 0x00);
3003 /* next read dummy from pixel address (3c8) */
3004 dummy = RGen (fb_info, VGA_PEL_IW);
3007 /* now do the usual stuff to access the HDR */
3009 dummy = RGen (fb_info, VGA_PEL_MSK);
3011 dummy = RGen (fb_info, VGA_PEL_MSK);
3013 dummy = RGen (fb_info, VGA_PEL_MSK);
3015 dummy = RGen (fb_info, VGA_PEL_MSK);
3018 WGen (fb_info, VGA_PEL_MSK, val);
3021 if (fb_info->btype == BT_PICASSO) {
3022 /* now first reset HDR access counter */
3023 dummy = RGen (fb_info, VGA_PEL_IW);
3026 /* and at the end, restore the mask value */
3027 /* ## is this mask always 0xff? */
3028 WGen (fb_info, VGA_PEL_MSK, 0xff);
3034 /*** WSFR() - write to the "special function register" (SFR) ***/
3035 static void WSFR (struct clgenfb_info *fb_info, unsigned char val)
3038 assert (fb_info->regs != NULL);
3040 z_writeb (val, fb_info->regs + 0x8000);
3044 /* The Picasso has a second register for switching the monitor bit */
3045 static void WSFR2 (struct clgenfb_info *fb_info, unsigned char val)
3048 /* writing an arbitrary value to this one causes the monitor switcher */
3049 /* to flip to Amiga display */
3050 assert (fb_info->regs != NULL);
3052 z_writeb (val, fb_info->regs + 0x9000);
3057 /*** WClut - set CLUT entry (range: 0..63) ***/
3058 static void WClut (struct clgenfb_info *fb_info, unsigned char regnum, unsigned char red,
3059 unsigned char green, unsigned char blue)
3061 unsigned int data = VGA_PEL_D;
3063 /* address write mode register is not translated.. */
3064 vga_w (fb_info->regs, VGA_PEL_IW, regnum);
3066 if (fb_info->btype == BT_PICASSO || fb_info->btype == BT_PICASSO4 ||
3067 fb_info->btype == BT_ALPINE || fb_info->btype == BT_GD5480) {
3068 /* but DAC data register IS, at least for Picasso II */
3069 if (fb_info->btype == BT_PICASSO)
3071 vga_w (fb_info->regs, data, red);
3072 vga_w (fb_info->regs, data, green);
3073 vga_w (fb_info->regs, data, blue);
3075 vga_w (fb_info->regs, data, blue);
3076 vga_w (fb_info->regs, data, green);
3077 vga_w (fb_info->regs, data, red);
3083 /*** RClut - read CLUT entry (range 0..63) ***/
3084 static void RClut (struct clgenfb_info *fb_info, unsigned char regnum, unsigned char *red,
3085 unsigned char *green, unsigned char *blue)
3087 unsigned int data = VGA_PEL_D;
3089 vga_w (fb_info->regs, VGA_PEL_IR, regnum);
3091 if (fb_info->btype == BT_PICASSO || fb_info->btype == BT_PICASSO4 ||
3092 fb_info->btype == BT_ALPINE || fb_info->btype == BT_GD5480) {
3093 if (fb_info->btype == BT_PICASSO)
3095 *red = vga_r (fb_info->regs, data);
3096 *green = vga_r (fb_info->regs, data);
3097 *blue = vga_r (fb_info->regs, data);
3099 *blue = vga_r (fb_info->regs, data);
3100 *green = vga_r (fb_info->regs, data);
3101 *red = vga_r (fb_info->regs, data);
3107 /*******************************************************************
3110 Wait for the BitBLT engine to complete a possible earlier job
3111 *********************************************************************/
3113 /* FIXME: use interrupts instead */
3114 static inline void clgen_WaitBLT (caddr_t regbase)
3116 /* now busy-wait until we're done */
3117 while (vga_rgfx (regbase, CL_GR31) & 0x08)
3121 /*******************************************************************
3124 perform accelerated "scrolling"
3125 ********************************************************************/
3127 static void clgen_BitBLT (caddr_t regbase, u_short curx, u_short cury, u_short destx, u_short desty,
3128 u_short width, u_short height, u_short line_length)
3130 u_short nwidth, nheight;
3134 DPRINTK ("ENTER\n");
3137 nheight = height - 1;
3140 /* if source adr < dest addr, do the Blt backwards */
3141 if (cury <= desty) {
3142 if (cury == desty) {
3143 /* if src and dest are on the same line, check x */
3150 /* standard case: forward blitting */
3151 nsrc = (cury * line_length) + curx;
3152 ndest = (desty * line_length) + destx;
3154 /* this means start addresses are at the end, counting backwards */
3155 nsrc = cury * line_length + curx + nheight * line_length + nwidth;
3156 ndest = desty * line_length + destx + nheight * line_length + nwidth;
3159 clgen_WaitBLT(regbase);
3162 run-down of registers to be programmed:
3170 VGA_GFX_SR_VALUE / VGA_GFX_SR_ENABLE: "fill color"
3174 /* pitch: set to line_length */
3175 vga_wgfx (regbase, CL_GR24, line_length & 0xff); /* dest pitch low */
3176 vga_wgfx (regbase, CL_GR25, (line_length >> 8)); /* dest pitch hi */
3177 vga_wgfx (regbase, CL_GR26, line_length & 0xff); /* source pitch low */
3178 vga_wgfx (regbase, CL_GR27, (line_length >> 8)); /* source pitch hi */
3180 /* BLT width: actual number of pixels - 1 */
3181 vga_wgfx (regbase, CL_GR20, nwidth & 0xff); /* BLT width low */
3182 vga_wgfx (regbase, CL_GR21, (nwidth >> 8)); /* BLT width hi */
3184 /* BLT height: actual number of lines -1 */
3185 vga_wgfx (regbase, CL_GR22, nheight & 0xff); /* BLT height low */
3186 vga_wgfx (regbase, CL_GR23, (nheight >> 8)); /* BLT width hi */
3188 /* BLT destination */
3189 vga_wgfx (regbase, CL_GR28, (u_char) (ndest & 0xff)); /* BLT dest low */
3190 vga_wgfx (regbase, CL_GR29, (u_char) (ndest >> 8)); /* BLT dest mid */
3191 vga_wgfx (regbase, CL_GR2A, (u_char) (ndest >> 16)); /* BLT dest hi */
3194 vga_wgfx (regbase, CL_GR2C, (u_char) (nsrc & 0xff)); /* BLT src low */
3195 vga_wgfx (regbase, CL_GR2D, (u_char) (nsrc >> 8)); /* BLT src mid */
3196 vga_wgfx (regbase, CL_GR2E, (u_char) (nsrc >> 16)); /* BLT src hi */
3199 vga_wgfx (regbase, CL_GR30, bltmode); /* BLT mode */
3201 /* BLT ROP: SrcCopy */
3202 vga_wgfx (regbase, CL_GR32, 0x0d); /* BLT ROP */
3204 /* and finally: GO! */
3205 vga_wgfx (regbase, CL_GR31, 0x02); /* BLT Start/status */
3211 /*******************************************************************
3214 perform accelerated rectangle fill
3215 ********************************************************************/
3217 static void clgen_RectFill (struct clgenfb_info *fb_info,
3218 u_short x, u_short y, u_short width, u_short height,
3219 u_char color, u_short line_length)
3221 u_short nwidth, nheight;
3225 DPRINTK ("ENTER\n");
3228 nheight = height - 1;
3230 ndest = (y * line_length) + x;
3232 clgen_WaitBLT(fb_info->regs);
3234 /* pitch: set to line_length */
3235 vga_wgfx (fb_info->regs, CL_GR24, line_length & 0xff); /* dest pitch low */
3236 vga_wgfx (fb_info->regs, CL_GR25, (line_length >> 8)); /* dest pitch hi */
3237 vga_wgfx (fb_info->regs, CL_GR26, line_length & 0xff); /* source pitch low */
3238 vga_wgfx (fb_info->regs, CL_GR27, (line_length >> 8)); /* source pitch hi */
3240 /* BLT width: actual number of pixels - 1 */
3241 vga_wgfx (fb_info->regs, CL_GR20, nwidth & 0xff); /* BLT width low */
3242 vga_wgfx (fb_info->regs, CL_GR21, (nwidth >> 8)); /* BLT width hi */
3244 /* BLT height: actual number of lines -1 */
3245 vga_wgfx (fb_info->regs, CL_GR22, nheight & 0xff); /* BLT height low */
3246 vga_wgfx (fb_info->regs, CL_GR23, (nheight >> 8)); /* BLT width hi */
3248 /* BLT destination */
3249 vga_wgfx (fb_info->regs, CL_GR28, (u_char) (ndest & 0xff)); /* BLT dest low */
3250 vga_wgfx (fb_info->regs, CL_GR29, (u_char) (ndest >> 8)); /* BLT dest mid */
3251 vga_wgfx (fb_info->regs, CL_GR2A, (u_char) (ndest >> 16)); /* BLT dest hi */
3253 /* BLT source: set to 0 (is a dummy here anyway) */
3254 vga_wgfx (fb_info->regs, CL_GR2C, 0x00); /* BLT src low */
3255 vga_wgfx (fb_info->regs, CL_GR2D, 0x00); /* BLT src mid */
3256 vga_wgfx (fb_info->regs, CL_GR2E, 0x00); /* BLT src hi */
3258 /* This is a ColorExpand Blt, using the */
3259 /* same color for foreground and background */
3260 vga_wgfx (fb_info->regs, VGA_GFX_SR_VALUE, color); /* foreground color */
3261 vga_wgfx (fb_info->regs, VGA_GFX_SR_ENABLE, color); /* background color */
3264 if (fb_info->currentmode.var.bits_per_pixel == 16) {
3265 vga_wgfx (fb_info->regs, CL_GR10, color); /* foreground color */
3266 vga_wgfx (fb_info->regs, CL_GR11, color); /* background color */
3269 } else if (fb_info->currentmode.var.bits_per_pixel == 32) {
3270 vga_wgfx (fb_info->regs, CL_GR10, color); /* foreground color */
3271 vga_wgfx (fb_info->regs, CL_GR11, color); /* background color */
3272 vga_wgfx (fb_info->regs, CL_GR12, color); /* foreground color */
3273 vga_wgfx (fb_info->regs, CL_GR13, color); /* background color */
3274 vga_wgfx (fb_info->regs, CL_GR14, 0); /* foreground color */
3275 vga_wgfx (fb_info->regs, CL_GR15, 0); /* background color */
3279 /* BLT mode: color expand, Enable 8x8 copy (faster?) */
3280 vga_wgfx (fb_info->regs, CL_GR30, op); /* BLT mode */
3282 /* BLT ROP: SrcCopy */
3283 vga_wgfx (fb_info->regs, CL_GR32, 0x0d); /* BLT ROP */
3285 /* and finally: GO! */
3286 vga_wgfx (fb_info->regs, CL_GR31, 0x02); /* BLT Start/status */
3292 /**************************************************************************
3293 * bestclock() - determine closest possible clock lower(?) than the
3294 * desired pixel clock
3295 **************************************************************************/
3296 static void bestclock (long freq, long *best, long *nom,
3297 long *den, long *div, long maxfreq)
3301 assert (best != NULL);
3302 assert (nom != NULL);
3303 assert (den != NULL);
3304 assert (div != NULL);
3305 assert (maxfreq > 0);
3311 DPRINTK ("ENTER\n");
3322 for (n = 32; n < 128; n++) {
3323 d = (143181 * n) / f;
3324 if ((d >= 7) && (d <= 63)) {
3327 h = (14318 * n) / d;
3328 if (abs (h - freq) < abs (*best - freq)) {
3340 d = ((143181 * n) + f - 1) / f;
3341 if ((d >= 7) && (d <= 63)) {
3344 h = (14318 * n) / d;
3345 if (abs (h - freq) < abs (*best - freq)) {
3359 DPRINTK ("Best possible values for given frequency:\n");
3360 DPRINTK (" best: %ld kHz nom: %ld den: %ld div: %ld\n",
3361 freq, *nom, *den, *div);
3367 /* -------------------------------------------------------------------------
3369 * debugging functions
3371 * -------------------------------------------------------------------------
3377 * clgen_dbg_print_byte
3378 * @name: name associated with byte value to be displayed
3379 * @val: byte value to be displayed
3382 * Display an indented string, along with a hexidecimal byte value, and
3383 * its decoded bits. Bits 7 through 0 are listed in left-to-right
3388 void clgen_dbg_print_byte (const char *name, unsigned char val)
3390 DPRINTK ("%8s = 0x%02X (bits 7-0: %c%c%c%c%c%c%c%c)\n",
3392 val & 0x80 ? '1' : '0',
3393 val & 0x40 ? '1' : '0',
3394 val & 0x20 ? '1' : '0',
3395 val & 0x10 ? '1' : '0',
3396 val & 0x08 ? '1' : '0',
3397 val & 0x04 ? '1' : '0',
3398 val & 0x02 ? '1' : '0',
3399 val & 0x01 ? '1' : '0');
3404 * clgen_dbg_print_regs
3405 * @base: If using newmmio, the newmmio base address, otherwise %NULL
3406 * @reg_class: type of registers to read: %CRT, or %SEQ
3409 * Dumps the given list of VGA CRTC registers. If @base is %NULL,
3410 * old-style I/O ports are queried for information, otherwise MMIO is
3411 * used at the given @base address to query the information.
3415 void clgen_dbg_print_regs (caddr_t regbase, clgen_dbg_reg_class_t reg_class,...)
3418 unsigned char val = 0;
3422 va_start (list, reg_class);
3424 name = va_arg (list, char *);
3425 while (name != NULL) {
3426 reg = va_arg (list, int);
3428 switch (reg_class) {
3430 val = vga_rcrt (regbase, (unsigned char) reg);
3433 val = vga_rseq (regbase, (unsigned char) reg);
3436 /* should never occur */
3441 clgen_dbg_print_byte (name, val);
3443 name = va_arg (list, char *);
3458 void clgen_dump (void)
3460 clgen_dbg_reg_dump (NULL);
3465 * clgen_dbg_reg_dump
3466 * @base: If using newmmio, the newmmio base address, otherwise %NULL
3469 * Dumps a list of interesting VGA and CLGEN registers. If @base is %NULL,
3470 * old-style I/O ports are queried for information, otherwise MMIO is
3471 * used at the given @base address to query the information.
3475 void clgen_dbg_reg_dump (caddr_t regbase)
3477 DPRINTK ("CLGEN VGA CRTC register dump:\n");
3479 clgen_dbg_print_regs (regbase, CRT,
3531 DPRINTK ("CLGEN VGA SEQ register dump:\n");
3533 clgen_dbg_print_regs (regbase, SEQ,
3565 #endif /* CLGEN_DEBUG */