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_INFO "cirrusfb: couldn't find Cirrus Logic 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 static 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 */