1 diff -Naur linux-2.4.18-pre6/Documentation/Configure.help linux/Documentation/Configure.help
2 --- linux-2.4.18-pre6/Documentation/Configure.help Wed Jan 23 13:38:48 2002
3 +++ linux/Documentation/Configure.help Wed Jan 23 13:42:09 2002
5 This driver supports the L7200 Color LCD.
6 Say Y if you want graphics support.
8 +NeoMagic display support (EXPERIMENTAL)
10 + This driver supports notebooks with NeoMagic PCI chips.
11 + Say Y if you have such a graphics card.
13 + The driver is also available as a module ( = code which can be
14 + inserted and removed from the running kernel whenever you want). The
15 + module will be called neofb.o. If you want to compile it as a
16 + module, say M here and read Documentation/modules.txt.
18 PowerMac "control" frame buffer device support
20 This driver supports a frame buffer for the graphics adapter in the
21 diff -Naur linux-2.4.18-pre6/drivers/video/Config.in linux/drivers/video/Config.in
22 --- linux-2.4.18-pre6/drivers/video/Config.in Wed Jan 23 13:38:53 2002
23 +++ linux/drivers/video/Config.in Wed Jan 23 13:42:09 2002
25 bool ' SIS 630/540/730 support' CONFIG_FB_SIS_300
26 bool ' SIS 315H/315 support' CONFIG_FB_SIS_315
28 + tristate ' NeoMagic display support (EXPERIMENTAL)' CONFIG_FB_NEOMAGIC
29 tristate ' 3Dfx Banshee/Voodoo3 display support (EXPERIMENTAL)' CONFIG_FB_3DFX
30 tristate ' 3Dfx Voodoo Graphics (sst1) support (EXPERIMENTAL)' CONFIG_FB_VOODOO1
33 "$CONFIG_FB_SA1100" = "y" -o "$CONFIG_FB_3DFX" = "y" -o \
34 "$CONFIG_FB_PMAG_BA" = "y" -o "$CONFIG_FB_PMAGB_B" = "y" -o \
35 "$CONFIG_FB_MAXINE" = "y" -o "$CONFIG_FB_TX3912" = "y" -o \
36 - "$CONFIG_FB_SIS" = "y" ]; then
37 + "$CONFIG_FB_SIS" = "y" -o "$CONFIG_FB_NEOMAGIC" = "y" ]; then
38 define_tristate CONFIG_FBCON_CFB8 y
40 if [ "$CONFIG_FB_ACORN" = "m" -o "$CONFIG_FB_ATARI" = "m" -o \
42 "$CONFIG_FB_PMAG_BA" = "m" -o "$CONFIG_FB_PMAGB_B" = "m" -o \
43 "$CONFIG_FB_MAXINE" = "m" -o "$CONFIG_FB_RADEON" = "m" -o \
44 "$CONFIG_FB_SA1100" = "m" -o "$CONFIG_FB_SIS" = "m" -o \
45 - "$CONFIG_FB_TX3912" = "m" ]; then
46 + "$CONFIG_FB_TX3912" = "m" -o "$CONFIG_FB_NEOMAGIC" = "m" ]; then
47 define_tristate CONFIG_FBCON_CFB8 m
51 "$CONFIG_FB_RIVA" = "y" -o "$CONFIG_FB_ATY128" = "y" -o \
52 "$CONFIG_FB_CYBER2000" = "y" -o "$CONFIG_FB_3DFX" = "y" -o \
53 "$CONFIG_FB_SIS" = "y" -o "$CONFIG_FB_SA1100" = "y" -o \
54 - "$CONFIG_FB_PVR2" = "y" -o "$CONFIG_FB_VOODOO1" = "y" ]; then
55 + "$CONFIG_FB_PVR2" = "y" -o "$CONFIG_FB_VOODOO1" = "y" -o \
56 + "$CONFIG_FB_NEOMAGIC" = "y" ]; then
57 define_tristate CONFIG_FBCON_CFB16 y
59 if [ "$CONFIG_FB_ATARI" = "m" -o "$CONFIG_FB_ATY" = "m" -o \
61 "$CONFIG_FB_RIVA" = "m" -o "$CONFIG_FB_ATY128" = "m" -o \
62 "$CONFIG_FB_CYBER2000" = "m" -o "$CONFIG_FB_SIS" = "m" -o \
63 "$CONFIG_FB_SA1100" = "m" -o "$CONFIG_FB_RADEON" = "m" -o \
64 - "$CONFIG_FB_PVR2" = "m" -o "$CONFIG_FB_VOODOO1" = "m" ]; then
65 + "$CONFIG_FB_PVR2" = "m" -o "$CONFIG_FB_VOODOO1" = "m" -o \
66 + "$CONFIG_FB_NEOMAGIC" = "m" ]; then
67 define_tristate CONFIG_FBCON_CFB16 m
71 "$CONFIG_FB_MATROX" = "y" -o "$CONFIG_FB_PM2" = "y" -o \
72 "$CONFIG_FB_ATY128" = "y" -o "$CONFIG_FB_RADEON" = "y" -o \
73 "$CONFIG_FB_CYBER2000" = "y" -o "$CONFIG_FB_PVR2" = "y" -o \
74 - "$CONFIG_FB_VOODOO1" = "y" ]; then
75 + "$CONFIG_FB_VOODOO1" = "y" -o "$CONFIG_FB_NEOMAGIC" = "y" ]; then
76 define_tristate CONFIG_FBCON_CFB24 y
78 if [ "$CONFIG_FB_ATY" = "m" -o "$CONFIG_FB_VIRTUAL" = "m" -o \
80 "$CONFIG_FB_MATROX" = "m" -o "$CONFIG_FB_PM2" = "m" -o \
81 "$CONFIG_FB_ATY128" = "m" -o "$CONFIG_FB_RADEON" = "m" -o \
82 "$CONFIG_FB_CYBER2000" = "m" -o "$CONFIG_FB_PVR2" = "m" -o \
83 - "$CONFIG_FB_VOODOO1" = "m" ]; then
84 + "$CONFIG_FB_VOODOO1" = "m" -o "$CONFIG_FB_NEOMAGIC" = "y" ]; then
85 define_tristate CONFIG_FBCON_CFB24 m
88 diff -Naur linux-2.4.18-pre6/drivers/video/Makefile linux/drivers/video/Makefile
89 --- linux-2.4.18-pre6/drivers/video/Makefile Thu Oct 25 22:53:52 2001
90 +++ linux/drivers/video/Makefile Wed Jan 23 13:42:09 2002
92 obj-$(CONFIG_FB_ATARI) += atafb.o
93 obj-$(CONFIG_FB_ATY128) += aty128fb.o
94 obj-$(CONFIG_FB_RADEON) += radeonfb.o
95 +obj-$(CONFIG_FB_NEOMAGIC) += neofb.o
96 obj-$(CONFIG_FB_IGA) += igafb.o
97 obj-$(CONFIG_FB_CONTROL) += controlfb.o
98 obj-$(CONFIG_FB_PLATINUM) += platinumfb.o
99 diff -Naur linux-2.4.18-pre6/drivers/video/fbmem.c linux/drivers/video/fbmem.c
100 --- linux-2.4.18-pre6/drivers/video/fbmem.c Fri Dec 21 18:41:55 2001
101 +++ linux/drivers/video/fbmem.c Wed Jan 23 13:42:09 2002
103 extern int atyfb_setup(char*);
104 extern int aty128fb_init(void);
105 extern int aty128fb_setup(char*);
106 +extern int neofb_init(void);
107 +extern int neofb_setup(char*);
108 extern int igafb_init(void);
109 extern int igafb_setup(char*);
110 extern int imsttfb_init(void);
113 #ifdef CONFIG_FB_ATY128
114 { "aty128fb", aty128fb_init, aty128fb_setup },
116 +#ifdef CONFIG_FB_NEOMAGIC
117 + { "neo", neofb_init, neofb_setup },
119 #ifdef CONFIG_FB_VIRGE
120 { "virge", virgefb_init, virgefb_setup },
121 diff -Naur linux-2.4.18-pre6/drivers/video/neofb.c linux/drivers/video/neofb.c
122 --- linux-2.4.18-pre6/drivers/video/neofb.c Thu Jan 1 01:00:00 1970
123 +++ linux/drivers/video/neofb.c Wed Jan 23 13:50:08 2002
126 + * linux/drivers/video/neofb.c -- NeoMagic Framebuffer Driver
128 + * Copyright (c) 2001 Denis Oliver Kropp <dok@convergence.de>
131 + * Card specific code is based on XFree86's neomagic driver.
132 + * Framebuffer framework code is based on code of cyber2000fb.
134 + * This file is subject to the terms and conditions of the GNU General
135 + * Public License. See the file COPYING in the main directory of this
136 + * archive for more details.
140 + * - added module license (dok)
143 + * - hardware accelerated clear and move for 2200 and above (dok)
144 + * - maximum allowed dotclock is handled now (dok)
147 + * - correct panning after X usage (dok)
148 + * - added module and kernel parameters (dok)
149 + * - no stretching if external display is enabled (dok)
152 + * - initial version (dok)
156 + * - ioctl for internal/external switching
158 + * - 32bit depth support, maybe impossible
159 + * - disable pan-on-sync, need specs
162 + * - white margin on bootup like with tdfxfb (colormap problem?)
166 +#include <linux/config.h>
167 +#include <linux/module.h>
168 +#include <linux/kernel.h>
169 +#include <linux/errno.h>
170 +#include <linux/string.h>
171 +#include <linux/mm.h>
172 +#include <linux/tty.h>
173 +#include <linux/malloc.h>
174 +#include <linux/delay.h>
175 +#include <linux/fb.h>
176 +#include <linux/pci.h>
177 +#include <linux/init.h>
180 +#include <asm/irq.h>
181 +#include <asm/pgtable.h>
182 +#include <asm/system.h>
183 +#include <asm/uaccess.h>
186 +#include <asm/mtrr.h>
189 +#include <video/fbcon.h>
190 +#include <video/fbcon-cfb8.h>
191 +#include <video/fbcon-cfb16.h>
192 +#include <video/fbcon-cfb24.h>
193 +#include <video/fbcon-cfb32.h>
198 +#define NEOFB_VERSION "0.3.1"
200 +/* --------------------------------------------------------------------- */
202 +static int disabled = 0;
203 +static int internal = 0;
204 +static int external = 0;
205 +static int nostretch = 0;
206 +static int nopciburst = 0;
211 +MODULE_AUTHOR("(c) 2001-2002 Denis Oliver Kropp <dok@convergence.de>");
212 +MODULE_LICENSE("GPL");
213 +MODULE_DESCRIPTION("FBDev driver for NeoMagic PCI Chips");
214 +MODULE_PARM(disabled, "i");
215 +MODULE_PARM_DESC(disabled, "Disable this driver's initialization.");
216 +MODULE_PARM(internal, "i");
217 +MODULE_PARM_DESC(internal, "Enable output on internal LCD Display.");
218 +MODULE_PARM(external, "i");
219 +MODULE_PARM_DESC(external, "Enable output on external CRT.");
220 +MODULE_PARM(nostretch, "i");
221 +MODULE_PARM_DESC(nostretch, "Disable stretching of modes smaller than LCD.");
222 +MODULE_PARM(nopciburst, "i");
223 +MODULE_PARM_DESC(nopciburst, "Disable PCI burst mode.");
228 +/* --------------------------------------------------------------------- */
230 +static biosMode bios8[] = {
231 + { 320, 240, 0x40 },
232 + { 300, 400, 0x42 },
233 + { 640, 400, 0x20 },
234 + { 640, 480, 0x21 },
235 + { 800, 600, 0x23 },
236 + { 1024, 768, 0x25 },
239 +static biosMode bios16[] = {
240 + { 320, 200, 0x2e },
241 + { 320, 240, 0x41 },
242 + { 300, 400, 0x43 },
243 + { 640, 480, 0x31 },
244 + { 800, 600, 0x34 },
245 + { 1024, 768, 0x37 },
248 +static biosMode bios24[] = {
249 + { 640, 480, 0x32 },
250 + { 800, 600, 0x35 },
251 + { 1024, 768, 0x38 }
254 +#ifdef NO_32BIT_SUPPORT_YET
255 +/* FIXME: guessed values, wrong */
256 +static biosMode bios32[] = {
257 + { 640, 480, 0x33 },
258 + { 800, 600, 0x36 },
259 + { 1024, 768, 0x39 }
263 +static int neoFindMode (int xres, int yres, int depth)
272 + size = sizeof(bios8) / sizeof(biosMode);
276 + size = sizeof(bios16) / sizeof(biosMode);
280 + size = sizeof(bios24) / sizeof(biosMode);
283 +#ifdef NO_32BIT_SUPPORT_YET
285 + size = sizeof(bios32) / sizeof(biosMode);
293 + for (i = 0; i < size; i++)
295 + if (xres <= mode[i].x_res)
297 + xres_s = mode[i].x_res;
298 + for (; i < size; i++)
300 + if (mode[i].x_res != xres_s)
301 + return mode[i-1].mode;
302 + if (yres <= mode[i].y_res)
303 + return mode[i].mode;
307 + return mode[size - 1].mode;
310 +/* -------------------- Hardware specific routines ------------------------- */
313 + * Hardware Acceleration for Neo2200+
315 +static inline void neo2200_wait_idle (struct neofb_info *fb)
319 + while (fb->neo2200->bltStat & 1)
323 +static inline void neo2200_wait_fifo (struct neofb_info *fb,
324 + int requested_fifo_space)
326 + // ndev->neo.waitfifo_calls++;
327 + // ndev->neo.waitfifo_sum += requested_fifo_space;
329 + /* FIXME: does not work
330 + if (neo_fifo_space < requested_fifo_space)
332 + neo_fifo_waitcycles++;
336 + neo_fifo_space = (neo2200->bltStat >> 8);
337 + if (neo_fifo_space >= requested_fifo_space)
343 + neo_fifo_cache_hits++;
346 + neo_fifo_space -= requested_fifo_space;
349 + neo2200_wait_idle (fb);
352 +static inline void neo2200_accel_init (struct neofb_info *fb,
353 + struct fb_var_screeninfo *var)
355 + Neo2200 *neo2200 = fb->neo2200;
358 + neo2200_wait_idle (fb);
360 + switch (var->bits_per_pixel)
363 + bltMod = NEO_MODE1_DEPTH8;
364 + pitch = var->xres_virtual;
368 + bltMod = NEO_MODE1_DEPTH16;
369 + pitch = var->xres_virtual * 2;
372 + printk( KERN_ERR "neofb: neo2200_accel_init: unexpected bits per pixel!\n" );
376 + neo2200->bltStat = bltMod << 16;
377 + neo2200->pitch = (pitch << 16) | pitch;
380 +static void neo2200_accel_setup (struct display *p)
382 + struct neofb_info *fb = (struct neofb_info *)p->fb_info;
383 + struct fb_var_screeninfo *var = &p->fb_info->var;
385 + fb->dispsw->setup(p);
387 + neo2200_accel_init (fb, var);
391 +neo2200_accel_bmove (struct display *p, int sy, int sx, int dy, int dx,
392 + int height, int width)
394 + struct neofb_info *fb = (struct neofb_info *)p->fb_info;
395 + struct fb_var_screeninfo *var = &p->fb_info->var;
396 + Neo2200 *neo2200 = fb->neo2200;
398 + int bpp, pitch, inc_y;
401 + /* setting blitting direction does not work, so this case is unaccelerated */
404 + neo2200_wait_idle (fb);
405 + fb->dispsw->bmove(p, sy, sx, dy, dx, height, width);
409 + bpp = (var->bits_per_pixel+7) / 8;
410 + pitch = var->xres_virtual * bpp;
417 + fh = fontheight(p);
426 + sy += (height - 1) * fh;
427 + dy += (height - 1) * fh;
430 + neo2200_wait_fifo (fb, 1);
432 + /* set blt control */
433 + neo2200->bltCntl = NEO_BC3_FIFO_EN |
434 + NEO_BC3_SKIP_MAPPING | 0x0c0000;
436 + /* looks silly, but setting the blitting direction did not work */
439 + src = sx + sy * pitch;
440 + dst = dx + dy * pitch;
442 + neo2200_wait_fifo (fb, 3);
444 + neo2200->srcStart = src;
445 + neo2200->dstStart = dst;
446 + neo2200->xyExt = (fh << 16) | (width & 0xffff);
454 +neo2200_accel_clear (struct vc_data *conp, struct display *p, int sy, int sx,
455 + int height, int width)
457 + struct neofb_info *fb = (struct neofb_info *)p->fb_info;
458 + struct fb_var_screeninfo *var = &p->fb_info->var;
459 + Neo2200 *neo2200 = fb->neo2200;
462 + u32 bgx = attr_bgcol_ec(p, conp);
465 + fh = fontheight(p);
467 + dst = sx * fw + sy * var->xres_virtual * fh;
468 + width = width * fw;
469 + height = height * fh;
471 + neo2200_wait_fifo (fb, 4);
473 + /* set blt control */
474 + neo2200->bltCntl = NEO_BC3_FIFO_EN |
475 + NEO_BC0_SRC_IS_FG |
476 + NEO_BC3_SKIP_MAPPING | 0x0c0000;
478 + switch (var->bits_per_pixel)
481 + neo2200->fgColor = bgx;
484 + neo2200->fgColor = ((u16 *)(p->fb_info)->pseudo_palette)[bgx];
488 + neo2200->dstStart = dst * ((var->bits_per_pixel+7) / 8);
490 + neo2200->xyExt = (height << 16) | (width & 0xffff);
494 +neo2200_accel_putc (struct vc_data *conp, struct display *p, int c,
497 + struct neofb_info *fb = (struct neofb_info *)p->fb_info;
499 + neo2200_wait_idle (fb);
500 + fb->dispsw->putc(conp, p, c, yy, xx);
504 +neo2200_accel_putcs (struct vc_data *conp, struct display *p,
505 + const unsigned short *s, int count, int yy, int xx)
507 + struct neofb_info *fb = (struct neofb_info *)p->fb_info;
509 + neo2200_wait_idle (fb);
510 + fb->dispsw->putcs(conp, p, s, count, yy, xx);
513 +static void neo2200_accel_revc (struct display *p, int xx, int yy)
515 + struct neofb_info *fb = (struct neofb_info *)p->fb_info;
517 + neo2200_wait_idle (fb);
518 + fb->dispsw->revc (p, xx, yy);
522 +neo2200_accel_clear_margins (struct vc_data *conp, struct display *p,
525 + struct neofb_info *fb = (struct neofb_info *)p->fb_info;
527 + fb->dispsw->clear_margins (conp, p, bottom_only);
530 +static struct display_switch fbcon_neo2200_accel = {
531 + setup: neo2200_accel_setup,
532 + bmove: neo2200_accel_bmove,
533 + clear: neo2200_accel_clear,
534 + putc: neo2200_accel_putc,
535 + putcs: neo2200_accel_putcs,
536 + revc: neo2200_accel_revc,
537 + clear_margins: neo2200_accel_clear_margins,
538 + fontwidthmask: FONTWIDTH(8)|FONTWIDTH(16)
542 +/* --------------------------------------------------------------------- */
545 + * Set a single color register. Return != 0 for invalid regno.
547 +static int neo_setcolreg(u_int regno, u_int red, u_int green, u_int blue,
548 + u_int transp, struct fb_info *fb)
550 + struct neofb_info *info = (struct neofb_info *)fb;
552 + if (regno >= NR_PALETTE)
555 + info->palette[regno].red = red;
556 + info->palette[regno].green = green;
557 + info->palette[regno].blue = blue;
558 + info->palette[regno].transp = transp;
560 + switch (fb->var.bits_per_pixel)
562 +#ifdef FBCON_HAS_CFB8
564 + outb(regno, 0x3c8);
566 + outb(red >> 10, 0x3c9);
567 + outb(green >> 10, 0x3c9);
568 + outb(blue >> 10, 0x3c9);
572 +#ifdef FBCON_HAS_CFB16
575 + ((u16 *)fb->pseudo_palette)[regno] = ((red & 0xf800) ) |
576 + ((green & 0xfc00) >> 5) |
577 + ((blue & 0xf800) >> 11);
581 +#ifdef FBCON_HAS_CFB24
584 + ((u32 *)fb->pseudo_palette)[regno] = ((red & 0xff00) << 8) |
585 + ((green & 0xff00) ) |
586 + ((blue & 0xff00) >> 8);
590 +#ifdef NO_32BIT_SUPPORT_YET
591 +#ifdef FBCON_HAS_CFB32
594 + ((u32 *)fb->pseudo_palette)[regno] = ((transp & 0xff00) << 16) |
595 + ((red & 0xff00) << 8) |
596 + ((green & 0xff00) ) |
597 + ((blue & 0xff00) >> 8);
609 +static void vgaHWLock (void)
611 + /* Protect CRTC[0-7] */
612 + VGAwCR (0x11, VGArCR (0x11) | 0x80);
615 +static void vgaHWUnlock (void)
617 + /* Unprotect CRTC[0-7] */
618 + VGAwCR (0x11, VGArCR (0x11) & ~0x80);
621 +static void neoLock (void)
623 + VGAwGR (0x09, 0x00);
627 +static void neoUnlock (void)
630 + VGAwGR (0x09, 0x26);
635 + * perform a sequencer reset.
638 +vgaHWSeqReset(int start)
641 + VGAwSEQ (0x00, 0x01); /* Synchronous Reset */
643 + VGAwSEQ (0x00, 0x03); /* End Reset */
647 +vgaHWProtect(int on)
654 + * Turn off screen and disable sequencer.
656 + tmp = VGArSEQ (0x01);
658 + vgaHWSeqReset (1); /* start synchronous reset */
659 + VGAwSEQ (0x01, tmp | 0x20); /* disable the display */
661 + VGAenablePalette();
666 + * Reenable sequencer, then turn on screen.
669 + tmp = VGArSEQ (0x01);
671 + VGAwSEQ (0x01, tmp & ~0x20); /* reenable display */
672 + vgaHWSeqReset (0); /* clear synchronousreset */
674 + VGAdisablePalette();
678 +static void vgaHWRestore (const struct neofb_info *info,
679 + const struct neofb_par *par)
683 + VGAwMISC (par->MiscOutReg);
685 + for (i = 1; i < 5; i++)
686 + VGAwSEQ (i, par->Sequencer[i]);
688 + /* Ensure CRTC registers 0-7 are unlocked by clearing bit 7 or CRTC[17] */
689 + VGAwCR (17, par->CRTC[17] & ~0x80);
691 + for (i = 0; i < 25; i++)
692 + VGAwCR (i, par->CRTC[i]);
694 + for (i = 0; i < 9; i++)
695 + VGAwGR (i, par->Graphics[i]);
697 + VGAenablePalette();
699 + for (i = 0; i < 21; i++)
700 + VGAwATTR (i, par->Attribute[i]);
702 + VGAdisablePalette();
705 +static void neofb_set_par (struct neofb_info *info,
706 + const struct neofb_par *par)
708 + unsigned char temp;
712 + DBG("neofb_set_par");
716 + vgaHWProtect (1); /* Blank the screen */
718 + /* linear colormap for non palettized modes */
719 + switch (par->depth)
724 + for (i=0; i<64; i++)
728 + outb(i << 1, 0x3c9);
730 + outb(i << 1, 0x3c9);
734 +#ifdef NO_32BIT_SUPPORT_YET
737 + for (i=0; i<256; i++)
748 + /* alread unlocked above */
749 + /* BOGUS VGAwGR (0x09, 0x26);*/
751 + /* don't know what this is, but it's 0 from bootup anyway */
752 + VGAwGR (0x15, 0x00);
754 + /* was set to 0x01 by my bios in text and vesa modes */
755 + VGAwGR (0x0A, par->GeneralLockReg);
758 + * The color mode needs to be set before calling vgaHWRestore
759 + * to ensure the DAC is initialized properly.
761 + * NOTE: Make sure we don't change bits make sure we don't change
762 + * any reserved bits.
764 + temp = VGArGR(0x90);
765 + switch (info->accel)
767 + case FB_ACCEL_NEOMAGIC_NM2070:
768 + temp &= 0xF0; /* Save bits 7:4 */
769 + temp |= (par->ExtColorModeSelect & ~0xF0);
771 + case FB_ACCEL_NEOMAGIC_NM2090:
772 + case FB_ACCEL_NEOMAGIC_NM2093:
773 + case FB_ACCEL_NEOMAGIC_NM2097:
774 + case FB_ACCEL_NEOMAGIC_NM2160:
775 + case FB_ACCEL_NEOMAGIC_NM2200:
776 + case FB_ACCEL_NEOMAGIC_NM2230:
777 + case FB_ACCEL_NEOMAGIC_NM2360:
778 + case FB_ACCEL_NEOMAGIC_NM2380:
779 + temp &= 0x70; /* Save bits 6:4 */
780 + temp |= (par->ExtColorModeSelect & ~0x70);
787 + * In some rare cases a lockup might occur if we don't delay
788 + * here. (Reported by Miles Lane)
793 + * Disable horizontal and vertical graphics and text expansions so
794 + * that vgaHWRestore works properly.
796 + temp = VGArGR(0x25);
798 + VGAwGR (0x25, temp);
801 + * Sleep for 200ms to make sure that the two operations above have
802 + * had time to take effect.
807 + * This function handles restoring the generic VGA registers. */
808 + vgaHWRestore (info, par);
811 + VGAwGR(0x0E, par->ExtCRTDispAddr);
812 + VGAwGR(0x0F, par->ExtCRTOffset);
813 + temp = VGArGR(0x10);
814 + temp &= 0x0F; /* Save bits 3:0 */
815 + temp |= (par->SysIfaceCntl1 & ~0x0F); /* VESA Bios sets bit 1! */
816 + VGAwGR(0x10, temp);
818 + VGAwGR(0x11, par->SysIfaceCntl2);
819 + VGAwGR(0x15, 0 /*par->SingleAddrPage*/);
820 + VGAwGR(0x16, 0 /*par->DualAddrPage*/);
822 + temp = VGArGR(0x20);
823 + switch (info->accel)
825 + case FB_ACCEL_NEOMAGIC_NM2070:
826 + temp &= 0xFC; /* Save bits 7:2 */
827 + temp |= (par->PanelDispCntlReg1 & ~0xFC);
829 + case FB_ACCEL_NEOMAGIC_NM2090:
830 + case FB_ACCEL_NEOMAGIC_NM2093:
831 + case FB_ACCEL_NEOMAGIC_NM2097:
832 + case FB_ACCEL_NEOMAGIC_NM2160:
833 + temp &= 0xDC; /* Save bits 7:6,4:2 */
834 + temp |= (par->PanelDispCntlReg1 & ~0xDC);
836 + case FB_ACCEL_NEOMAGIC_NM2200:
837 + case FB_ACCEL_NEOMAGIC_NM2230:
838 + case FB_ACCEL_NEOMAGIC_NM2360:
839 + case FB_ACCEL_NEOMAGIC_NM2380:
840 + temp &= 0x98; /* Save bits 7,4:3 */
841 + temp |= (par->PanelDispCntlReg1 & ~0x98);
844 + VGAwGR(0x20, temp);
846 + temp = VGArGR(0x25);
847 + temp &= 0x38; /* Save bits 5:3 */
848 + temp |= (par->PanelDispCntlReg2 & ~0x38);
849 + VGAwGR(0x25, temp);
851 + if (info->accel != FB_ACCEL_NEOMAGIC_NM2070)
853 + temp = VGArGR(0x30);
854 + temp &= 0xEF; /* Save bits 7:5 and bits 3:0 */
855 + temp |= (par->PanelDispCntlReg3 & ~0xEF);
856 + VGAwGR(0x30, temp);
859 + VGAwGR(0x28, par->PanelVertCenterReg1);
860 + VGAwGR(0x29, par->PanelVertCenterReg2);
861 + VGAwGR(0x2a, par->PanelVertCenterReg3);
863 + if (info->accel != FB_ACCEL_NEOMAGIC_NM2070)
865 + VGAwGR(0x32, par->PanelVertCenterReg4);
866 + VGAwGR(0x33, par->PanelHorizCenterReg1);
867 + VGAwGR(0x34, par->PanelHorizCenterReg2);
868 + VGAwGR(0x35, par->PanelHorizCenterReg3);
871 + if (info->accel == FB_ACCEL_NEOMAGIC_NM2160)
872 + VGAwGR(0x36, par->PanelHorizCenterReg4);
874 + if (info->accel == FB_ACCEL_NEOMAGIC_NM2200 ||
875 + info->accel == FB_ACCEL_NEOMAGIC_NM2230 ||
876 + info->accel == FB_ACCEL_NEOMAGIC_NM2360 ||
877 + info->accel == FB_ACCEL_NEOMAGIC_NM2380)
879 + VGAwGR(0x36, par->PanelHorizCenterReg4);
880 + VGAwGR(0x37, par->PanelVertCenterReg5);
881 + VGAwGR(0x38, par->PanelHorizCenterReg5);
886 + /* Program VCLK3 if needed. */
887 + if (par->ProgramVCLK
888 + && ((VGArGR(0x9B) != par->VCLK3NumeratorLow)
889 + || (VGArGR(0x9F) != par->VCLK3Denominator)
890 + || (clock_hi && ((VGArGR(0x8F) & ~0x0f)
891 + != (par->VCLK3NumeratorHigh & ~0x0F)))))
893 + VGAwGR(0x9B, par->VCLK3NumeratorLow);
896 + temp = VGArGR(0x8F);
897 + temp &= 0x0F; /* Save bits 3:0 */
898 + temp |= (par->VCLK3NumeratorHigh & ~0x0F);
899 + VGAwGR(0x8F, temp);
901 + VGAwGR(0x9F, par->VCLK3Denominator);
905 + VGAwCR(0x23, par->biosMode);
907 + VGAwGR (0x93, 0xc0); /* Gives 5x faster framebuffer writes !!! */
909 + /* Program vertical extension register */
910 + if (info->accel == FB_ACCEL_NEOMAGIC_NM2200 ||
911 + info->accel == FB_ACCEL_NEOMAGIC_NM2230 ||
912 + info->accel == FB_ACCEL_NEOMAGIC_NM2360 ||
913 + info->accel == FB_ACCEL_NEOMAGIC_NM2380)
915 + VGAwCR(0x70, par->VerticalExt);
919 + vgaHWProtect (0); /* Turn on screen */
921 + /* Calling this also locks offset registers required in update_start */
925 +static void neofb_update_start (struct neofb_info *info, struct fb_var_screeninfo *var)
927 + int oldExtCRTDispAddr;
930 + DBG("neofb_update_start");
932 + Base = (var->yoffset * var->xres_virtual + var->xoffset) >> 2;
933 + Base *= (var->bits_per_pixel + 7) / 8;
938 + * These are the generic starting address registers.
940 + VGAwCR(0x0C, (Base & 0x00FF00) >> 8);
941 + VGAwCR(0x0D, (Base & 0x00FF));
944 + * Make sure we don't clobber some other bits that might already
945 + * have been set. NOTE: NM2200 has a writable bit 3, but it shouldn't
948 + oldExtCRTDispAddr = VGArGR(0x0E);
949 + VGAwGR(0x0E,(((Base >> 16) & 0x0f) | (oldExtCRTDispAddr & 0xf0)));
957 +static int neofb_set_cmap(struct fb_cmap *cmap, int kspc, int con,
958 + struct fb_info *fb)
960 + struct neofb_info *info = (struct neofb_info *)fb;
961 + struct display* disp = (con < 0) ? fb->disp : (fb_display + con);
962 + struct fb_cmap *dcmap = &disp->cmap;
965 + /* no colormap allocated? */
970 + if (fb->var.bits_per_pixel == 8)
975 + err = fb_alloc_cmap (dcmap, size, 0);
979 + * we should be able to remove this test once fbcon has been
982 + if (!err && con == info->currcon)
984 + err = fb_set_cmap (cmap, kspc, neo_setcolreg, fb);
989 + fb_copy_cmap (cmap, dcmap, kspc ? 0 : 1);
997 + * Determine the closest clock frequency to the one requested.
999 +#define REF_FREQ 14.31818
1004 +static void neoCalcVCLK (const struct neofb_info *info, struct neofb_par *par, long freq)
1009 + int n_best = 0, d_best = 0, f_best = 0;
1010 + double f_best_diff = 999999.0;
1011 + double f_target = freq/1000.0;
1013 + for (f = 0; f <= MAX_F; f++)
1014 + for (n = 0; n <= MAX_N; n++)
1015 + for (d = 0; d <= MAX_D; d++)
1017 + f_out = (n+1.0)/((d+1.0)*(1<<f))*REF_FREQ;
1018 + f_diff = abs(f_out-f_target);
1019 + if (f_diff < f_best_diff)
1021 + f_best_diff = f_diff;
1028 + if (info->accel == FB_ACCEL_NEOMAGIC_NM2200 ||
1029 + info->accel == FB_ACCEL_NEOMAGIC_NM2230 ||
1030 + info->accel == FB_ACCEL_NEOMAGIC_NM2360 ||
1031 + info->accel == FB_ACCEL_NEOMAGIC_NM2380)
1033 + /* NOT_DONE: We are trying the full range of the 2200 clock.
1034 + We should be able to try n up to 2047 */
1035 + par->VCLK3NumeratorLow = n_best;
1036 + par->VCLK3NumeratorHigh = (f_best << 7);
1039 + par->VCLK3NumeratorLow = n_best | (f_best << 7);
1041 + par->VCLK3Denominator = d_best;
1044 + printk ("neoVCLK: f:%f NumLow=%d NumHi=%d Den=%d Df=%f\n",
1046 + par->VCLK3NumeratorLow,
1047 + par->VCLK3NumeratorHigh,
1048 + par->VCLK3Denominator,
1055 + * Handle the initialization, etc. of a screen.
1056 + * Return FALSE on failure.
1059 +static int vgaHWInit (const struct fb_var_screeninfo *var,
1060 + const struct neofb_info *info,
1061 + struct neofb_par *par,
1062 + struct xtimings *timings)
1064 + par->MiscOutReg = 0x23;
1066 + if (!(timings->sync & FB_SYNC_HOR_HIGH_ACT))
1067 + par->MiscOutReg |= 0x40;
1069 + if (!(timings->sync & FB_SYNC_VERT_HIGH_ACT))
1070 + par->MiscOutReg |= 0x80;
1075 + par->Sequencer[0] = 0x00;
1076 + par->Sequencer[1] = 0x01;
1077 + par->Sequencer[2] = 0x0F;
1078 + par->Sequencer[3] = 0x00; /* Font select */
1079 + par->Sequencer[4] = 0x0E; /* Misc */
1084 + par->CRTC[0] = (timings->HTotal >> 3) - 5;
1085 + par->CRTC[1] = (timings->HDisplay >> 3) - 1;
1086 + par->CRTC[2] = (timings->HDisplay >> 3) - 1;
1087 + par->CRTC[3] = (((timings->HTotal >> 3) - 1) & 0x1F) | 0x80;
1088 + par->CRTC[4] = (timings->HSyncStart >> 3);
1089 + par->CRTC[5] = ((((timings->HTotal >> 3) - 1) & 0x20) << 2)
1090 + | (((timings->HSyncEnd >> 3)) & 0x1F);
1091 + par->CRTC[6] = (timings->VTotal - 2) & 0xFF;
1092 + par->CRTC[7] = (((timings->VTotal - 2) & 0x100) >> 8)
1093 + | (((timings->VDisplay - 1) & 0x100) >> 7)
1094 + | ((timings->VSyncStart & 0x100) >> 6)
1095 + | (((timings->VDisplay - 1) & 0x100) >> 5)
1097 + | (((timings->VTotal - 2) & 0x200) >> 4)
1098 + | (((timings->VDisplay - 1) & 0x200) >> 3)
1099 + | ((timings->VSyncStart & 0x200) >> 2);
1100 + par->CRTC[8] = 0x00;
1101 + par->CRTC[9] = (((timings->VDisplay - 1) & 0x200) >> 4) | 0x40;
1103 + if (timings->dblscan)
1104 + par->CRTC[9] |= 0x80;
1106 + par->CRTC[10] = 0x00;
1107 + par->CRTC[11] = 0x00;
1108 + par->CRTC[12] = 0x00;
1109 + par->CRTC[13] = 0x00;
1110 + par->CRTC[14] = 0x00;
1111 + par->CRTC[15] = 0x00;
1112 + par->CRTC[16] = timings->VSyncStart & 0xFF;
1113 + par->CRTC[17] = (timings->VSyncEnd & 0x0F) | 0x20;
1114 + par->CRTC[18] = (timings->VDisplay - 1) & 0xFF;
1115 + par->CRTC[19] = var->xres_virtual >> 4;
1116 + par->CRTC[20] = 0x00;
1117 + par->CRTC[21] = (timings->VDisplay - 1) & 0xFF;
1118 + par->CRTC[22] = (timings->VTotal - 1) & 0xFF;
1119 + par->CRTC[23] = 0xC3;
1120 + par->CRTC[24] = 0xFF;
1123 + * are these unnecessary?
1124 + * vgaHWHBlankKGA(mode, regp, 0, KGA_FIX_OVERSCAN | KGA_ENABLE_ON_ZERO);
1125 + * vgaHWVBlankKGA(mode, regp, 0, KGA_FIX_OVERSCAN | KGA_ENABLE_ON_ZERO);
1129 + * Graphics Display Controller
1131 + par->Graphics[0] = 0x00;
1132 + par->Graphics[1] = 0x00;
1133 + par->Graphics[2] = 0x00;
1134 + par->Graphics[3] = 0x00;
1135 + par->Graphics[4] = 0x00;
1136 + par->Graphics[5] = 0x40;
1137 + par->Graphics[6] = 0x05; /* only map 64k VGA memory !!!! */
1138 + par->Graphics[7] = 0x0F;
1139 + par->Graphics[8] = 0xFF;
1142 + par->Attribute[0] = 0x00; /* standard colormap translation */
1143 + par->Attribute[1] = 0x01;
1144 + par->Attribute[2] = 0x02;
1145 + par->Attribute[3] = 0x03;
1146 + par->Attribute[4] = 0x04;
1147 + par->Attribute[5] = 0x05;
1148 + par->Attribute[6] = 0x06;
1149 + par->Attribute[7] = 0x07;
1150 + par->Attribute[8] = 0x08;
1151 + par->Attribute[9] = 0x09;
1152 + par->Attribute[10] = 0x0A;
1153 + par->Attribute[11] = 0x0B;
1154 + par->Attribute[12] = 0x0C;
1155 + par->Attribute[13] = 0x0D;
1156 + par->Attribute[14] = 0x0E;
1157 + par->Attribute[15] = 0x0F;
1158 + par->Attribute[16] = 0x41;
1159 + par->Attribute[17] = 0xFF;
1160 + par->Attribute[18] = 0x0F;
1161 + par->Attribute[19] = 0x00;
1162 + par->Attribute[20] = 0x00;
1167 +static int neofb_decode_var (struct fb_var_screeninfo *var,
1168 + const struct neofb_info *info,
1169 + struct neofb_par *par)
1171 + struct xtimings timings;
1173 + int hoffset, voffset;
1174 + int memlen, vramlen;
1176 + unsigned int pixclock = var->pixclock;
1178 + DBG("neofb_decode_var");
1180 + if (!pixclock) pixclock = 10000; /* 10ns = 100MHz */
1181 + timings.pixclock = 1000000000 / pixclock;
1182 + if (timings.pixclock < 1) timings.pixclock = 1;
1183 + timings.dblscan = var->vmode & FB_VMODE_DOUBLE;
1184 + timings.interlaced = var->vmode & FB_VMODE_INTERLACED;
1185 + timings.HDisplay = var->xres;
1186 + timings.HSyncStart = timings.HDisplay + var->right_margin;
1187 + timings.HSyncEnd = timings.HSyncStart + var->hsync_len;
1188 + timings.HTotal = timings.HSyncEnd + var->left_margin;
1189 + timings.VDisplay = var->yres;
1190 + timings.VSyncStart = timings.VDisplay + var->lower_margin;
1191 + timings.VSyncEnd = timings.VSyncStart + var->vsync_len;
1192 + timings.VTotal = timings.VSyncEnd + var->upper_margin;
1193 + timings.sync = var->sync;
1195 + if (timings.pixclock > info->maxClock)
1198 + /* Is the mode larger than the LCD panel? */
1199 + if ((var->xres > info->NeoPanelWidth) ||
1200 + (var->yres > info->NeoPanelHeight))
1202 + printk (KERN_INFO "Mode (%dx%d) larger than the LCD panel (%dx%d)\n",
1205 + info->NeoPanelWidth,
1206 + info->NeoPanelHeight);
1210 + /* Is the mode one of the acceptable sizes? */
1211 + switch (var->xres)
1214 + if (var->yres == 1024)
1218 + if (var->yres == 768)
1222 + if (var->yres == 600)
1226 + if (var->yres == 480)
1233 + printk (KERN_INFO "Mode (%dx%d) won't display properly on LCD\n",
1234 + var->xres, var->yres);
1239 + switch (var->bits_per_pixel)
1241 +#ifdef FBCON_HAS_CFB8
1246 +#ifdef FBCON_HAS_CFB16
1251 +#ifdef FBCON_HAS_CFB24
1256 +#ifdef NO_32BIT_SUPPORT_YET
1257 +# ifdef FBCON_HAS_CFB32
1267 + par->depth = var->bits_per_pixel;
1269 + vramlen = info->video.len;
1270 + if (vramlen > 4*1024*1024)
1271 + vramlen = 4*1024*1024;
1273 + if (var->yres_virtual < var->yres)
1274 + var->yres_virtual = var->yres;
1275 + if (var->xres_virtual < var->xres)
1276 + var->xres_virtual = var->xres;
1278 + memlen = var->xres_virtual * var->bits_per_pixel * var->yres_virtual / 8;
1279 + if (memlen > vramlen)
1281 + var->yres_virtual = vramlen * 8 / (var->xres_virtual * var->bits_per_pixel);
1282 + memlen = var->xres_virtual * var->bits_per_pixel * var->yres_virtual / 8;
1285 + /* we must round yres/xres down, we already rounded y/xres_virtual up
1286 + if it was possible. We should return -EINVAL, but I disagree */
1287 + if (var->yres_virtual < var->yres)
1288 + var->yres = var->yres_virtual;
1289 + if (var->xres_virtual < var->xres)
1290 + var->xres = var->xres_virtual;
1291 + if (var->xoffset + var->xres > var->xres_virtual)
1292 + var->xoffset = var->xres_virtual - var->xres;
1293 + if (var->yoffset + var->yres > var->yres_virtual)
1294 + var->yoffset = var->yres_virtual - var->yres;
1298 + * This will allocate the datastructure and initialize all of the
1299 + * generic VGA registers.
1302 + if (vgaHWInit (var, info, par, &timings))
1306 + * The default value assigned by vgaHW.c is 0x41, but this does
1307 + * not work for NeoMagic.
1309 + par->Attribute[16] = 0x01;
1311 + switch (var->bits_per_pixel)
1314 + par->CRTC[0x13] = var->xres_virtual >> 3;
1315 + par->ExtCRTOffset = var->xres_virtual >> 11;
1316 + par->ExtColorModeSelect = 0x11;
1319 + par->CRTC[0x13] = var->xres_virtual >> 2;
1320 + par->ExtCRTOffset = var->xres_virtual >> 10;
1321 + par->ExtColorModeSelect = 0x13;
1324 + par->CRTC[0x13] = (var->xres_virtual * 3) >> 3;
1325 + par->ExtCRTOffset = (var->xres_virtual * 3) >> 11;
1326 + par->ExtColorModeSelect = 0x14;
1328 +#ifdef NO_32BIT_SUPPORT_YET
1329 + case 32: /* FIXME: guessed values */
1330 + par->CRTC[0x13] = var->xres_virtual >> 1;
1331 + par->ExtCRTOffset = var->xres_virtual >> 9;
1332 + par->ExtColorModeSelect = 0x15;
1339 + par->ExtCRTDispAddr = 0x10;
1341 + /* Vertical Extension */
1342 + par->VerticalExt = (((timings.VTotal -2) & 0x400) >> 10 )
1343 + | (((timings.VDisplay -1) & 0x400) >> 9 )
1344 + | (((timings.VSyncStart) & 0x400) >> 8 )
1345 + | (((timings.VSyncStart) & 0x400) >> 7 );
1347 + /* Fast write bursts on unless disabled. */
1348 + if (info->pci_burst)
1349 + par->SysIfaceCntl1 = 0x30;
1351 + par->SysIfaceCntl1 = 0x00;
1353 + par->SysIfaceCntl2 = 0xc0; /* VESA Bios sets this to 0x80! */
1355 + /* Enable any user specified display devices. */
1356 + par->PanelDispCntlReg1 = 0x00;
1357 + if (info->internal_display)
1358 + par->PanelDispCntlReg1 |= 0x02;
1359 + if (info->external_display)
1360 + par->PanelDispCntlReg1 |= 0x01;
1362 + /* If the user did not specify any display devices, then... */
1363 + if (par->PanelDispCntlReg1 == 0x00) {
1364 + /* Default to internal (i.e., LCD) only. */
1365 + par->PanelDispCntlReg1 |= 0x02;
1368 + /* If we are using a fixed mode, then tell the chip we are. */
1369 + switch (var->xres)
1372 + par->PanelDispCntlReg1 |= 0x60;
1375 + par->PanelDispCntlReg1 |= 0x40;
1378 + par->PanelDispCntlReg1 |= 0x20;
1385 + /* Setup shadow register locking. */
1386 + switch (par->PanelDispCntlReg1 & 0x03)
1388 + case 0x01: /* External CRT only mode: */
1389 + par->GeneralLockReg = 0x00;
1390 + /* We need to program the VCLK for external display only mode. */
1391 + par->ProgramVCLK = 1;
1393 + case 0x02: /* Internal LCD only mode: */
1394 + case 0x03: /* Simultaneous internal/external (LCD/CRT) mode: */
1395 + par->GeneralLockReg = 0x01;
1396 + /* Don't program the VCLK when using the LCD. */
1397 + par->ProgramVCLK = 0;
1402 + * If the screen is to be stretched, turn on stretching for the
1405 + * OPTION_LCD_STRETCH means stretching should be turned off!
1407 + par->PanelDispCntlReg2 = 0x00;
1408 + par->PanelDispCntlReg3 = 0x00;
1410 + if (info->lcd_stretch &&
1411 + (par->PanelDispCntlReg1 == 0x02) && /* LCD only */
1412 + (var->xres != info->NeoPanelWidth))
1414 + switch (var->xres)
1416 + case 320: /* Needs testing. KEM -- 24 May 98 */
1417 + case 400: /* Needs testing. KEM -- 24 May 98 */
1422 + par->PanelDispCntlReg2 |= 0xC6;
1426 + /* No stretching in these modes. */
1433 + * If the screen is to be centerd, turn on the centering for the
1436 + par->PanelVertCenterReg1 = 0x00;
1437 + par->PanelVertCenterReg2 = 0x00;
1438 + par->PanelVertCenterReg3 = 0x00;
1439 + par->PanelVertCenterReg4 = 0x00;
1440 + par->PanelVertCenterReg5 = 0x00;
1441 + par->PanelHorizCenterReg1 = 0x00;
1442 + par->PanelHorizCenterReg2 = 0x00;
1443 + par->PanelHorizCenterReg3 = 0x00;
1444 + par->PanelHorizCenterReg4 = 0x00;
1445 + par->PanelHorizCenterReg5 = 0x00;
1448 + if (par->PanelDispCntlReg1 & 0x02)
1450 + if (var->xres == info->NeoPanelWidth)
1453 + * No centering required when the requested display width
1454 + * equals the panel width.
1459 + par->PanelDispCntlReg2 |= 0x01;
1460 + par->PanelDispCntlReg3 |= 0x10;
1462 + /* Calculate the horizontal and vertical offsets. */
1465 + hoffset = ((info->NeoPanelWidth - var->xres) >> 4) - 1;
1466 + voffset = ((info->NeoPanelHeight - var->yres) >> 1) - 2;
1470 + /* Stretched modes cannot be centered. */
1475 + switch (var->xres)
1477 + case 320: /* Needs testing. KEM -- 24 May 98 */
1478 + par->PanelHorizCenterReg3 = hoffset;
1479 + par->PanelVertCenterReg2 = voffset;
1481 + case 400: /* Needs testing. KEM -- 24 May 98 */
1482 + par->PanelHorizCenterReg4 = hoffset;
1483 + par->PanelVertCenterReg1 = voffset;
1486 + par->PanelHorizCenterReg1 = hoffset;
1487 + par->PanelVertCenterReg3 = voffset;
1490 + par->PanelHorizCenterReg2 = hoffset;
1491 + par->PanelVertCenterReg4 = voffset;
1494 + par->PanelHorizCenterReg5 = hoffset;
1495 + par->PanelVertCenterReg5 = voffset;
1499 + /* No centering in these modes. */
1505 + par->biosMode = neoFindMode (var->xres, var->yres, var->bits_per_pixel);
1508 + * Calculate the VCLK that most closely matches the requested dot
1511 + neoCalcVCLK (info, par, timings.pixclock);
1513 + /* Since we program the clocks ourselves, always use VCLK3. */
1514 + par->MiscOutReg |= 0x0C;
1519 +static int neofb_set_var (struct fb_var_screeninfo *var, int con,
1520 + struct fb_info *fb)
1522 + struct neofb_info *info = (struct neofb_info *)fb;
1523 + struct display *display;
1524 + struct neofb_par par;
1525 + int err, chgvar = 0;
1527 + DBG("neofb_set_var");
1529 + err = neofb_decode_var (var, info, &par);
1533 + if (var->activate & FB_ACTIVATE_TEST)
1538 + display = fb->disp;
1543 + display = fb_display + con;
1545 + if (fb->var.xres != var->xres)
1547 + if (fb->var.yres != var->yres)
1549 + if (fb->var.xres_virtual != var->xres_virtual)
1551 + if (fb->var.yres_virtual != var->yres_virtual)
1553 + if (fb->var.bits_per_pixel != var->bits_per_pixel)
1557 + if (!info->neo2200)
1558 + var->accel_flags &= ~FB_ACCELF_TEXT;
1560 + var->red.msb_right = 0;
1561 + var->green.msb_right = 0;
1562 + var->blue.msb_right = 0;
1564 + switch (var->bits_per_pixel)
1566 +#ifdef FBCON_HAS_CFB8
1567 + case 8: /* PSEUDOCOLOUR, 256 */
1568 + var->transp.offset = 0;
1569 + var->transp.length = 0;
1570 + var->red.offset = 0;
1571 + var->red.length = 8;
1572 + var->green.offset = 0;
1573 + var->green.length = 8;
1574 + var->blue.offset = 0;
1575 + var->blue.length = 8;
1577 + fb->fix.visual = FB_VISUAL_PSEUDOCOLOR;
1578 + info->dispsw = &fbcon_cfb8;
1579 + display->dispsw_data = NULL;
1580 + display->next_line = var->xres_virtual;
1584 +#ifdef FBCON_HAS_CFB16
1585 + case 16: /* DIRECTCOLOUR, 64k */
1586 + var->transp.offset = 0;
1587 + var->transp.length = 0;
1588 + var->red.offset = 11;
1589 + var->red.length = 5;
1590 + var->green.offset = 5;
1591 + var->green.length = 6;
1592 + var->blue.offset = 0;
1593 + var->blue.length = 5;
1595 + fb->fix.visual = FB_VISUAL_DIRECTCOLOR;
1596 + info->dispsw = &fbcon_cfb16;
1597 + display->dispsw_data = fb->pseudo_palette;
1598 + display->next_line = var->xres_virtual * 2;
1602 +#ifdef FBCON_HAS_CFB24
1603 + case 24: /* TRUECOLOUR, 16m */
1604 + var->transp.offset = 0;
1605 + var->transp.length = 0;
1606 + var->red.offset = 16;
1607 + var->red.length = 8;
1608 + var->green.offset = 8;
1609 + var->green.length = 8;
1610 + var->blue.offset = 0;
1611 + var->blue.length = 8;
1613 + fb->fix.visual = FB_VISUAL_TRUECOLOR;
1614 + info->dispsw = &fbcon_cfb24;
1615 + display->dispsw_data = fb->pseudo_palette;
1616 + display->next_line = var->xres_virtual * 3;
1618 + var->accel_flags &= ~FB_ACCELF_TEXT;
1622 +#ifdef NO_32BIT_SUPPORT_YET
1623 +# ifdef FBCON_HAS_CFB32
1624 + case 32: /* TRUECOLOUR, 16m */
1625 + var->transp.offset = 24;
1626 + var->transp.length = 8;
1627 + var->red.offset = 16;
1628 + var->red.length = 8;
1629 + var->green.offset = 8;
1630 + var->green.length = 8;
1631 + var->blue.offset = 0;
1632 + var->blue.length = 8;
1634 + fb->fix.visual = FB_VISUAL_TRUECOLOR;
1635 + info->dispsw = &fbcon_cfb32;
1636 + display->dispsw_data = fb->pseudo_palette;
1637 + display->next_line = var->xres_virtual * 4;
1639 + var->accel_flags &= ~FB_ACCELF_TEXT;
1645 + printk (KERN_WARNING "neofb: no support for %dbpp\n", var->bits_per_pixel);
1646 + info->dispsw = &fbcon_dummy;
1647 + var->accel_flags &= ~FB_ACCELF_TEXT;
1651 + if (var->accel_flags & FB_ACCELF_TEXT)
1652 + display->dispsw = &fbcon_neo2200_accel;
1654 + display->dispsw = info->dispsw;
1656 + fb->fix.line_length = display->next_line;
1658 + display->screen_base = fb->screen_base;
1659 + display->line_length = fb->fix.line_length;
1660 + display->visual = fb->fix.visual;
1661 + display->type = fb->fix.type;
1662 + display->type_aux = fb->fix.type_aux;
1663 + display->ypanstep = fb->fix.ypanstep;
1664 + display->ywrapstep = fb->fix.ywrapstep;
1665 + display->can_soft_blank = 1;
1666 + display->inverse = 0;
1669 + fb->var.activate &= ~FB_ACTIVATE_ALL;
1672 + * Update the old var. The fbcon drivers still use this.
1673 + * Once they are using cfb->fb.var, this can be dropped.
1676 + display->var = fb->var;
1679 + * If we are setting all the virtual consoles, also set the
1680 + * defaults used to create new consoles.
1682 + if (var->activate & FB_ACTIVATE_ALL)
1683 + fb->disp->var = fb->var;
1685 + if (chgvar && fb && fb->changevar)
1686 + fb->changevar (con);
1688 + if (con == info->currcon)
1690 + if (chgvar || con < 0)
1691 + neofb_set_par (info, &par);
1693 + neofb_update_start (info, var);
1694 + fb_set_cmap (&fb->cmap, 1, neo_setcolreg, fb);
1696 + if (var->accel_flags & FB_ACCELF_TEXT)
1697 + neo2200_accel_init (info, var);
1704 + * Pan or Wrap the Display
1706 +static int neofb_pan_display (struct fb_var_screeninfo *var, int con,
1707 + struct fb_info *fb)
1709 + struct neofb_info *info = (struct neofb_info *)fb;
1712 + y_bottom = var->yoffset;
1714 + if (!(var->vmode & FB_VMODE_YWRAP))
1715 + y_bottom += var->yres;
1717 + if (var->xoffset > (var->xres_virtual - var->xres))
1719 + if (y_bottom > fb->var.yres_virtual)
1722 + neofb_update_start (info, var);
1724 + fb->var.xoffset = var->xoffset;
1725 + fb->var.yoffset = var->yoffset;
1727 + if (var->vmode & FB_VMODE_YWRAP)
1728 + fb->var.vmode |= FB_VMODE_YWRAP;
1730 + fb->var.vmode &= ~FB_VMODE_YWRAP;
1737 + * Update the `var' structure (called by fbcon.c)
1739 + * This call looks only at yoffset and the FB_VMODE_YWRAP flag in `var'.
1740 + * Since it's called by a kernel driver, no range checking is done.
1742 +static int neofb_updatevar (int con, struct fb_info *fb)
1744 + struct neofb_info *info = (struct neofb_info *)fb;
1746 + neofb_update_start (info, &fb_display[con].var);
1751 +static int neofb_switch (int con, struct fb_info *fb)
1753 + struct neofb_info *info = (struct neofb_info *)fb;
1754 + struct display *disp;
1755 + struct fb_cmap *cmap;
1757 + if (info->currcon >= 0)
1759 + disp = fb_display + info->currcon;
1762 + * Save the old colormap and video mode.
1764 + disp->var = fb->var;
1765 + if (disp->cmap.len)
1766 + fb_copy_cmap(&fb->cmap, &disp->cmap, 0);
1769 + info->currcon = con;
1770 + disp = fb_display + con;
1773 + * Install the new colormap and change the video mode. By default,
1774 + * fbcon sets all the colormaps and video modes to the default
1775 + * values at bootup.
1777 + * Really, we want to set the colourmap size depending on the
1778 + * depth of the new video mode. For now, we leave it at its
1779 + * default 256 entry.
1781 + if (disp->cmap.len)
1782 + cmap = &disp->cmap;
1784 + cmap = fb_default_cmap(1 << disp->var.bits_per_pixel);
1786 + fb_copy_cmap(cmap, &fb->cmap, 0);
1788 + disp->var.activate = FB_ACTIVATE_NOW;
1789 + neofb_set_var(&disp->var, con, fb);
1795 + * (Un)Blank the display.
1797 +static void neofb_blank (int blank, struct fb_info *fb)
1799 + // struct neofb_info *info = (struct neofb_info *)fb;
1802 + * Blank the screen if blank_mode != 0, else unblank. If
1803 + * blank == NULL then the caller blanks by setting the CLUT
1804 + * (Color Look Up Table) to all black. Return 0 if blanking
1805 + * succeeded, != 0 if un-/blanking failed due to e.g. a
1806 + * video mode which doesn't support it. Implements VESA
1807 + * suspend and powerdown modes on hardware that supports
1808 + * disabling hsync/vsync:
1809 + * blank_mode == 2: suspend vsync
1810 + * blank_mode == 3: suspend hsync
1811 + * blank_mode == 4: powerdown
1813 + * wms...Enable VESA DMPS compatible powerdown mode
1814 + * run "setterm -powersave powerdown" to take advantage
1819 + case 4: /* powerdown - both sync lines down */
1821 + case 3: /* hsync off */
1823 + case 2: /* vsync off */
1825 + case 1: /* just software blanking of screen */
1827 + default: /* case 0, or anything else: unblank */
1833 + * Get the currently displayed virtual consoles colormap.
1835 +static int gen_get_cmap (struct fb_cmap *cmap, int kspc, int con, struct fb_info *fb)
1837 + fb_copy_cmap (&fb->cmap, cmap, kspc ? 0 : 2);
1842 + * Get the currently displayed virtual consoles fixed part of the display.
1844 +static int gen_get_fix (struct fb_fix_screeninfo *fix, int con, struct fb_info *fb)
1851 + * Get the current user defined part of the display.
1853 +static int gen_get_var (struct fb_var_screeninfo *var, int con, struct fb_info *fb)
1859 +static struct fb_ops neofb_ops = {
1860 + owner: THIS_MODULE,
1861 + fb_set_var: neofb_set_var,
1862 + fb_set_cmap: neofb_set_cmap,
1863 + fb_pan_display: neofb_pan_display,
1864 + fb_get_fix: gen_get_fix,
1865 + fb_get_var: gen_get_var,
1866 + fb_get_cmap: gen_get_cmap,
1869 +/* --------------------------------------------------------------------- */
1871 +static struct fb_var_screeninfo __devinitdata neofb_var640x480x8 = {
1872 + accel_flags: FB_ACCELF_TEXT,
1875 + xres_virtual: 640,
1876 + yres_virtual: 30000,
1877 + bits_per_pixel: 8,
1886 + vmode: FB_VMODE_NONINTERLACED
1889 +static struct fb_var_screeninfo __devinitdata neofb_var800x600x8 = {
1890 + accel_flags: FB_ACCELF_TEXT,
1893 + xres_virtual: 800,
1894 + yres_virtual: 30000,
1895 + bits_per_pixel: 8,
1903 + sync: FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
1904 + vmode: FB_VMODE_NONINTERLACED
1907 +static struct fb_var_screeninfo __devinitdata neofb_var1024x768x8 = {
1908 + accel_flags: FB_ACCELF_TEXT,
1911 + xres_virtual: 1024,
1912 + yres_virtual: 30000,
1913 + bits_per_pixel: 8,
1921 + sync: FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
1922 + vmode: FB_VMODE_NONINTERLACED
1926 +static struct fb_var_screeninfo __devinitdata neofb_var1280x1024x8 = {
1927 + accel_flags: FB_ACCELF_TEXT,
1930 + xres_virtual: 1280,
1931 + yres_virtual: 30000,
1932 + bits_per_pixel: 8,
1940 + sync: FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
1941 + vmode: FB_VMODE_NONINTERLACED
1945 +static struct fb_var_screeninfo *neofb_var = NULL;
1948 +static int __devinit neo_map_mmio (struct neofb_info *info)
1950 + DBG("neo_map_mmio");
1952 + info->mmio.pbase = pci_resource_start (info->pcidev, 1);
1953 + info->mmio.len = MMIO_SIZE;
1955 + if (!request_mem_region (info->mmio.pbase, MMIO_SIZE, "memory mapped I/O"))
1957 + printk ("neofb: memory mapped IO in use\n");
1961 + info->mmio.vbase = ioremap (info->mmio.pbase, MMIO_SIZE);
1962 + if (!info->mmio.vbase)
1964 + printk ("neofb: unable to map memory mapped IO\n");
1965 + release_mem_region (info->mmio.pbase, info->mmio.len);
1969 + printk (KERN_INFO "neofb: mapped io at %p\n", info->mmio.vbase);
1971 + info->fb.fix.mmio_start = info->mmio.pbase;
1972 + info->fb.fix.mmio_len = info->mmio.len;
1977 +static void __devinit neo_unmap_mmio (struct neofb_info *info)
1979 + DBG("neo_unmap_mmio");
1981 + if (info->mmio.vbase)
1983 + iounmap (info->mmio.vbase);
1984 + info->mmio.vbase = NULL;
1986 + release_mem_region (info->mmio.pbase, info->mmio.len);
1990 +static int __devinit neo_map_video (struct neofb_info *info, int video_len)
1992 + DBG("neo_map_video");
1994 + info->video.pbase = pci_resource_start (info->pcidev, 0);
1995 + info->video.len = video_len;
1997 + if (!request_mem_region (info->video.pbase, info->video.len, "frame buffer"))
1999 + printk ("neofb: frame buffer in use\n");
2003 + info->video.vbase = ioremap (info->video.pbase, info->video.len);
2004 + if (!info->video.vbase)
2006 + printk ("neofb: unable to map screen memory\n");
2007 + release_mem_region (info->video.pbase, info->video.len);
2011 + printk (KERN_INFO "neofb: mapped framebuffer at %p\n", info->video.vbase);
2013 + info->fb.fix.smem_start = info->video.pbase;
2014 + info->fb.fix.smem_len = info->video.len;
2015 + info->fb.screen_base = info->video.vbase;
2018 + info->video.mtrr = mtrr_add (info->video.pbase, pci_resource_len (info->pcidev, 0), MTRR_TYPE_WRCOMB, 1);
2021 + /* Clear framebuffer, it's all white in memory after boot */
2022 + memset (info->video.vbase, 0, info->video.len);
2027 +static void __devinit neo_unmap_video (struct neofb_info *info)
2029 + DBG("neo_unmap_video");
2031 + if (info->video.vbase)
2034 + mtrr_del (info->video.mtrr, info->video.pbase, info->video.len);
2037 + iounmap (info->video.vbase);
2038 + info->video.vbase = NULL;
2039 + info->fb.screen_base = NULL;
2041 + release_mem_region (info->video.pbase, info->video.len);
2045 +static int __devinit neo_init_hw (struct neofb_info *info)
2047 + int videoRam = 896;
2048 + int maxClock = 65000;
2049 + int CursorMem = 1024;
2050 + int CursorOff = 0x100;
2051 + int linearSize = 1024;
2052 + int maxWidth = 1024;
2053 + int maxHeight = 1024;
2054 + unsigned char type, display;
2057 + DBG("neo_init_hw");
2062 + printk (KERN_DEBUG "--- Neo extended register dump ---\n");
2063 + for (w=0; w<0x85; w++)
2064 + printk (KERN_DEBUG "CR %p: %p\n", (void*)w, (void*)VGArCR (w));
2065 + for (w=0; w<0xC7; w++)
2066 + printk (KERN_DEBUG "GR %p: %p\n", (void*)w, (void*)VGArGR (w));
2069 + /* Determine the panel type */
2070 + VGAwGR(0x09,0x26);
2071 + type = VGArGR(0x21);
2072 + display = VGArGR(0x20);
2074 + /* Determine panel width -- used in NeoValidMode. */
2076 + VGAwGR(0x09,0x00);
2077 + switch ((w & 0x18) >> 3)
2080 + info->NeoPanelWidth = 640;
2081 + info->NeoPanelHeight = 480;
2082 + neofb_var = &neofb_var640x480x8;
2085 + info->NeoPanelWidth = 800;
2086 + info->NeoPanelHeight = 600;
2087 + neofb_var = &neofb_var800x600x8;
2090 + info->NeoPanelWidth = 1024;
2091 + info->NeoPanelHeight = 768;
2092 + neofb_var = &neofb_var1024x768x8;
2095 + /* 1280x1024 panel support needs to be added */
2097 + info->NeoPanelWidth = 1280;
2098 + info->NeoPanelHeight = 1024;
2099 + neofb_var = &neofb_var1280x1024x8;
2102 + printk (KERN_ERR "neofb: Only 640x480, 800x600 and 1024x768 panels are currently supported\n");
2106 + info->NeoPanelWidth = 640;
2107 + info->NeoPanelHeight = 480;
2108 + neofb_var = &neofb_var640x480x8;
2112 + printk (KERN_INFO "Panel is a %dx%d %s %s display\n",
2113 + info->NeoPanelWidth,
2114 + info->NeoPanelHeight,
2115 + (type & 0x02) ? "color" : "monochrome",
2116 + (type & 0x10) ? "TFT" : "dual scan");
2118 + switch (info->accel)
2120 + case FB_ACCEL_NEOMAGIC_NM2070:
2124 + CursorOff = 0x100;
2125 + linearSize = 1024;
2129 + case FB_ACCEL_NEOMAGIC_NM2090:
2130 + case FB_ACCEL_NEOMAGIC_NM2093:
2134 + CursorOff = 0x100;
2135 + linearSize = 2048;
2139 + case FB_ACCEL_NEOMAGIC_NM2097:
2143 + CursorOff = 0x100;
2144 + linearSize = 2048;
2148 + case FB_ACCEL_NEOMAGIC_NM2160:
2152 + CursorOff = 0x100;
2153 + linearSize = 2048;
2157 + case FB_ACCEL_NEOMAGIC_NM2200:
2159 + maxClock = 110000;
2161 + CursorOff = 0x1000;
2162 + linearSize = 4096;
2164 + maxHeight = 1024; /* ???? */
2166 + info->neo2200 = (Neo2200*) info->mmio.vbase;
2168 + case FB_ACCEL_NEOMAGIC_NM2230:
2170 + maxClock = 110000;
2172 + CursorOff = 0x1000;
2173 + linearSize = 4096;
2175 + maxHeight = 1024; /* ???? */
2177 + info->neo2200 = (Neo2200*) info->mmio.vbase;
2179 + case FB_ACCEL_NEOMAGIC_NM2360:
2181 + maxClock = 110000;
2183 + CursorOff = 0x1000;
2184 + linearSize = 4096;
2186 + maxHeight = 1024; /* ???? */
2188 + info->neo2200 = (Neo2200*) info->mmio.vbase;
2190 + case FB_ACCEL_NEOMAGIC_NM2380:
2192 + maxClock = 110000;
2194 + CursorOff = 0x1000;
2195 + linearSize = 8192;
2197 + maxHeight = 1024; /* ???? */
2199 + info->neo2200 = (Neo2200*) info->mmio.vbase;
2203 + info->maxClock = maxClock;
2205 + return videoRam * 1024;
2209 +static struct neofb_info * __devinit neo_alloc_fb_info (struct pci_dev *dev,
2210 + const struct pci_device_id *id)
2212 + struct neofb_info *info;
2214 + info = kmalloc (sizeof(struct neofb_info) + sizeof(struct display) +
2215 + sizeof(u32) * 16, GFP_KERNEL);
2220 + memset (info, 0, sizeof(struct neofb_info) + sizeof(struct display));
2222 + info->currcon = -1;
2223 + info->pcidev = dev;
2224 + info->accel = id->driver_data;
2226 + info->pci_burst = !nopciburst;
2227 + info->lcd_stretch = !nostretch;
2229 + if (!internal && !external)
2231 + info->internal_display = 1;
2232 + info->external_display = 0;
2236 + info->internal_display = internal;
2237 + info->external_display = external;
2240 + switch (info->accel)
2242 + case FB_ACCEL_NEOMAGIC_NM2070:
2243 + sprintf (info->fb.fix.id, "MagicGraph 128");
2245 + case FB_ACCEL_NEOMAGIC_NM2090:
2246 + sprintf (info->fb.fix.id, "MagicGraph 128V");
2248 + case FB_ACCEL_NEOMAGIC_NM2093:
2249 + sprintf (info->fb.fix.id, "MagicGraph 128ZV");
2251 + case FB_ACCEL_NEOMAGIC_NM2097:
2252 + sprintf (info->fb.fix.id, "MagicGraph 128ZV+");
2254 + case FB_ACCEL_NEOMAGIC_NM2160:
2255 + sprintf (info->fb.fix.id, "MagicGraph 128XD");
2257 + case FB_ACCEL_NEOMAGIC_NM2200:
2258 + sprintf (info->fb.fix.id, "MagicGraph 256AV");
2260 + case FB_ACCEL_NEOMAGIC_NM2230:
2261 + sprintf (info->fb.fix.id, "MagicGraph 256AV+");
2263 + case FB_ACCEL_NEOMAGIC_NM2360:
2264 + sprintf (info->fb.fix.id, "MagicGraph 256ZX");
2266 + case FB_ACCEL_NEOMAGIC_NM2380:
2267 + sprintf (info->fb.fix.id, "MagicGraph 256XL+");
2271 + info->fb.fix.type = FB_TYPE_PACKED_PIXELS;
2272 + info->fb.fix.type_aux = 0;
2273 + info->fb.fix.xpanstep = 0;
2274 + info->fb.fix.ypanstep = 4;
2275 + info->fb.fix.ywrapstep = 0;
2276 + info->fb.fix.accel = id->driver_data;
2278 + info->fb.var.nonstd = 0;
2279 + info->fb.var.activate = FB_ACTIVATE_NOW;
2280 + info->fb.var.height = -1;
2281 + info->fb.var.width = -1;
2282 + info->fb.var.accel_flags = 0;
2284 + strcpy (info->fb.modename, info->fb.fix.id);
2286 + info->fb.fbops = &neofb_ops;
2287 + info->fb.changevar = NULL;
2288 + info->fb.switch_con = neofb_switch;
2289 + info->fb.updatevar = neofb_updatevar;
2290 + info->fb.blank = neofb_blank;
2291 + info->fb.flags = FBINFO_FLAG_DEFAULT;
2292 + info->fb.disp = (struct display *)(info + 1);
2293 + info->fb.pseudo_palette = (void *)(info->fb.disp + 1);
2295 + fb_alloc_cmap (&info->fb.cmap, NR_PALETTE, 0);
2300 +static void __devinit neo_free_fb_info (struct neofb_info *info)
2305 + * Free the colourmap
2307 + fb_alloc_cmap (&info->fb.cmap, 0, 0);
2313 +/* --------------------------------------------------------------------- */
2315 +static int __devinit neofb_probe (struct pci_dev* dev, const struct pci_device_id* id)
2317 + struct neofb_info *info;
2318 + u_int h_sync, v_sync;
2322 + DBG("neofb_probe");
2324 + err = pci_enable_device (dev);
2329 + info = neo_alloc_fb_info (dev, id);
2333 + err = neo_map_mmio (info);
2337 + video_len = neo_init_hw (info);
2338 + if (video_len < 0)
2344 + err = neo_map_video (info, video_len);
2348 + neofb_set_var (neofb_var, -1, &info->fb);
2351 + * Calculate the hsync and vsync frequencies. Note that
2352 + * we split the 1e12 constant up so that we can preserve
2353 + * the precision and fit the results into 32-bit registers.
2354 + * (1953125000 * 512 = 1e12)
2356 + h_sync = 1953125000 / info->fb.var.pixclock;
2357 + h_sync = h_sync * 512 / (info->fb.var.xres + info->fb.var.left_margin +
2358 + info->fb.var.right_margin + info->fb.var.hsync_len);
2359 + v_sync = h_sync / (info->fb.var.yres + info->fb.var.upper_margin +
2360 + info->fb.var.lower_margin + info->fb.var.vsync_len);
2362 + printk(KERN_INFO "neofb v" NEOFB_VERSION ": %dkB VRAM, using %dx%d, %d.%03dkHz, %dHz\n",
2363 + info->fb.fix.smem_len >> 10,
2364 + info->fb.var.xres, info->fb.var.yres,
2365 + h_sync / 1000, h_sync % 1000, v_sync);
2368 + err = register_framebuffer (&info->fb);
2372 + printk (KERN_INFO "fb%d: %s frame buffer device\n",
2373 + GET_FB_IDX(info->fb.node), info->fb.modename);
2378 + dev->driver_data = info;
2383 + neo_unmap_video (info);
2384 + neo_unmap_mmio (info);
2385 + neo_free_fb_info (info);
2390 +static void __devexit neofb_remove (struct pci_dev *dev)
2392 + struct neofb_info *info = (struct neofb_info *)dev->driver_data;
2394 + DBG("neofb_remove");
2399 + * If unregister_framebuffer fails, then
2400 + * we will be leaving hooks that could cause
2401 + * oopsen laying around.
2403 + if (unregister_framebuffer (&info->fb))
2404 + printk (KERN_WARNING "neofb: danger danger! Oopsen imminent!\n");
2406 + neo_unmap_video (info);
2407 + neo_unmap_mmio (info);
2408 + neo_free_fb_info (info);
2411 + * Ensure that the driver data is no longer
2414 + dev->driver_data = NULL;
2418 +static struct pci_device_id neofb_devices[] __devinitdata = {
2419 + {PCI_VENDOR_ID_NEOMAGIC, PCI_CHIP_NM2070,
2420 + PCI_ANY_ID, PCI_ANY_ID, 0, 0, FB_ACCEL_NEOMAGIC_NM2070},
2422 + {PCI_VENDOR_ID_NEOMAGIC, PCI_CHIP_NM2090,
2423 + PCI_ANY_ID, PCI_ANY_ID, 0, 0, FB_ACCEL_NEOMAGIC_NM2090},
2425 + {PCI_VENDOR_ID_NEOMAGIC, PCI_CHIP_NM2093,
2426 + PCI_ANY_ID, PCI_ANY_ID, 0, 0, FB_ACCEL_NEOMAGIC_NM2093},
2428 + {PCI_VENDOR_ID_NEOMAGIC, PCI_CHIP_NM2097,
2429 + PCI_ANY_ID, PCI_ANY_ID, 0, 0, FB_ACCEL_NEOMAGIC_NM2097},
2431 + {PCI_VENDOR_ID_NEOMAGIC, PCI_CHIP_NM2160,
2432 + PCI_ANY_ID, PCI_ANY_ID, 0, 0, FB_ACCEL_NEOMAGIC_NM2160},
2434 + {PCI_VENDOR_ID_NEOMAGIC, PCI_CHIP_NM2200,
2435 + PCI_ANY_ID, PCI_ANY_ID, 0, 0, FB_ACCEL_NEOMAGIC_NM2200},
2437 + {PCI_VENDOR_ID_NEOMAGIC, PCI_CHIP_NM2230,
2438 + PCI_ANY_ID, PCI_ANY_ID, 0, 0, FB_ACCEL_NEOMAGIC_NM2230},
2440 + {PCI_VENDOR_ID_NEOMAGIC, PCI_CHIP_NM2360,
2441 + PCI_ANY_ID, PCI_ANY_ID, 0, 0, FB_ACCEL_NEOMAGIC_NM2360},
2443 + {PCI_VENDOR_ID_NEOMAGIC, PCI_CHIP_NM2380,
2444 + PCI_ANY_ID, PCI_ANY_ID, 0, 0, FB_ACCEL_NEOMAGIC_NM2380},
2446 + {0, 0, 0, 0, 0, 0, 0}
2449 +MODULE_DEVICE_TABLE(pci, neofb_devices);
2451 +static struct pci_driver neofb_driver = {
2453 + id_table: neofb_devices,
2454 + probe: neofb_probe,
2455 + remove: neofb_remove
2458 +/* **************************** init-time only **************************** */
2460 +static void __init neo_init (void)
2463 + pci_register_driver (&neofb_driver);
2466 +/* **************************** exit-time only **************************** */
2468 +static void __exit neo_done (void)
2471 + pci_unregister_driver (&neofb_driver);
2477 +/* ************************* init in-kernel code ************************** */
2479 +int __init neofb_setup (char *options)
2483 + DBG("neofb_setup");
2485 + if (!options || !*options)
2488 + for (this_opt=strtok(options,","); this_opt; this_opt=strtok(NULL,","))
2490 + if (!*this_opt) continue;
2492 + if (!strncmp(this_opt, "disabled", 8))
2494 + if (!strncmp(this_opt, "internal", 8))
2496 + if (!strncmp(this_opt, "external", 8))
2498 + if (!strncmp(this_opt, "nostretch", 9))
2500 + if (!strncmp(this_opt, "nopciburst", 10))
2507 +static int __init initialized = 0;
2509 +int __init neofb_init(void)
2511 + DBG("neofb_init");
2522 + /* never return failure, user can hotplug card later... */
2528 +/* *************************** init module code **************************** */
2530 +int __init init_module(void)
2532 + DBG("init_module");
2539 + /* never return failure; user can hotplug card later... */
2543 +#endif /* MODULE */
2545 +module_exit(neo_done);
2546 diff -Naur linux-2.4.18-pre6/drivers/video/neofb.h linux/drivers/video/neofb.h
2547 --- linux-2.4.18-pre6/drivers/video/neofb.h Thu Jan 1 01:00:00 1970
2548 +++ linux/drivers/video/neofb.h Wed Jan 23 13:42:09 2002
2551 + * linux/drivers/video/neofb.h -- NeoMagic Framebuffer Driver
2553 + * Copyright (c) 2001 Denis Oliver Kropp <dok@convergence.de>
2555 + * This file is subject to the terms and conditions of the GNU General
2556 + * Public License. See the file COPYING in the main directory of this
2557 + * archive for more details.
2562 +# define DBG(x) printk (KERN_DEBUG "neofb: %s\n", (x));
2568 +#define PCI_CHIP_NM2070 0x0001
2569 +#define PCI_CHIP_NM2090 0x0002
2570 +#define PCI_CHIP_NM2093 0x0003
2571 +#define PCI_CHIP_NM2097 0x0083
2572 +#define PCI_CHIP_NM2160 0x0004
2573 +#define PCI_CHIP_NM2200 0x0005
2574 +#define PCI_CHIP_NM2230 0x0025
2575 +#define PCI_CHIP_NM2360 0x0006
2576 +#define PCI_CHIP_NM2380 0x0016
2580 + unsigned int pixclock;
2581 + unsigned int HDisplay;
2582 + unsigned int HSyncStart;
2583 + unsigned int HSyncEnd;
2584 + unsigned int HTotal;
2585 + unsigned int VDisplay;
2586 + unsigned int VSyncStart;
2587 + unsigned int VSyncEnd;
2588 + unsigned int VTotal;
2589 + unsigned int sync;
2595 +/* --------------------------------------------------------------------- */
2597 +typedef volatile struct {
2606 + __u32 srcBitOffset;
2612 + __u32 reserved1[19];
2621 +#define NR_PALETTE 256
2623 +#define MMIO_SIZE 0x200000
2625 +#define NEO_EXT_CR_MAX 0x85
2626 +#define NEO_EXT_GR_MAX 0xC7
2632 + unsigned char MiscOutReg; /* Misc */
2633 + unsigned char CRTC[25]; /* Crtc Controller */
2634 + unsigned char Sequencer[5]; /* Video Sequencer */
2635 + unsigned char Graphics[9]; /* Video Graphics */
2636 + unsigned char Attribute[21]; /* Video Atribute */
2638 + unsigned char GeneralLockReg;
2639 + unsigned char ExtCRTDispAddr;
2640 + unsigned char ExtCRTOffset;
2641 + unsigned char SysIfaceCntl1;
2642 + unsigned char SysIfaceCntl2;
2643 + unsigned char ExtColorModeSelect;
2644 + unsigned char biosMode;
2646 + unsigned char PanelDispCntlReg1;
2647 + unsigned char PanelDispCntlReg2;
2648 + unsigned char PanelDispCntlReg3;
2649 + unsigned char PanelVertCenterReg1;
2650 + unsigned char PanelVertCenterReg2;
2651 + unsigned char PanelVertCenterReg3;
2652 + unsigned char PanelVertCenterReg4;
2653 + unsigned char PanelVertCenterReg5;
2654 + unsigned char PanelHorizCenterReg1;
2655 + unsigned char PanelHorizCenterReg2;
2656 + unsigned char PanelHorizCenterReg3;
2657 + unsigned char PanelHorizCenterReg4;
2658 + unsigned char PanelHorizCenterReg5;
2661 + unsigned char VCLK3NumeratorLow;
2662 + unsigned char VCLK3NumeratorHigh;
2663 + unsigned char VCLK3Denominator;
2664 + unsigned char VerticalExt;
2667 +struct neofb_info {
2669 + struct fb_info fb;
2670 + struct display_switch *dispsw;
2672 + struct pci_dev *pcidev;
2697 + int NeoPanelWidth;
2698 + int NeoPanelHeight;
2704 + int internal_display;
2705 + int external_display;
2708 + u16 red, green, blue, transp;
2709 + } palette[NR_PALETTE];
2720 +/* vga IO functions */
2721 +static inline u8 VGArCR (u8 index)
2723 + outb (index, 0x3d4);
2724 + return inb (0x3d5);
2727 +static inline void VGAwCR (u8 index, u8 val)
2729 + outb (index, 0x3d4);
2730 + outb (val, 0x3d5);
2733 +static inline u8 VGArGR (u8 index)
2735 + outb (index, 0x3ce);
2736 + return inb (0x3cf);
2739 +static inline void VGAwGR (u8 index, u8 val)
2741 + outb (index, 0x3ce);
2742 + outb (val, 0x3cf);
2745 +static inline u8 VGArSEQ (u8 index)
2747 + outb (index, 0x3c4);
2748 + return inb (0x3c5);
2751 +static inline void VGAwSEQ (u8 index, u8 val)
2753 + outb (index, 0x3c4);
2754 + outb (val, 0x3c5);
2758 +static int paletteEnabled = 0;
2760 +static inline void VGAenablePalette (void)
2764 + tmp = inb (0x3da);
2765 + outb (0x00, 0x3c0);
2766 + paletteEnabled = 1;
2769 +static inline void VGAdisablePalette (void)
2773 + tmp = inb (0x3da);
2774 + outb (0x20, 0x3c0);
2775 + paletteEnabled = 0;
2778 +static inline void VGAwATTR (u8 index, u8 value)
2782 + if (paletteEnabled)
2787 + tmp = inb (0x3da);
2788 + outb (index, 0x3c0);
2789 + outb (value, 0x3c0);
2792 +static inline void VGAwMISC (u8 value)
2794 + outb (value, 0x3c2);
2798 +#define NEO_BS0_BLT_BUSY 0x00000001
2799 +#define NEO_BS0_FIFO_AVAIL 0x00000002
2800 +#define NEO_BS0_FIFO_PEND 0x00000004
2802 +#define NEO_BC0_DST_Y_DEC 0x00000001
2803 +#define NEO_BC0_X_DEC 0x00000002
2804 +#define NEO_BC0_SRC_TRANS 0x00000004
2805 +#define NEO_BC0_SRC_IS_FG 0x00000008
2806 +#define NEO_BC0_SRC_Y_DEC 0x00000010
2807 +#define NEO_BC0_FILL_PAT 0x00000020
2808 +#define NEO_BC0_SRC_MONO 0x00000040
2809 +#define NEO_BC0_SYS_TO_VID 0x00000080
2811 +#define NEO_BC1_DEPTH8 0x00000100
2812 +#define NEO_BC1_DEPTH16 0x00000200
2813 +#define NEO_BC1_X_320 0x00000400
2814 +#define NEO_BC1_X_640 0x00000800
2815 +#define NEO_BC1_X_800 0x00000c00
2816 +#define NEO_BC1_X_1024 0x00001000
2817 +#define NEO_BC1_X_1152 0x00001400
2818 +#define NEO_BC1_X_1280 0x00001800
2819 +#define NEO_BC1_X_1600 0x00001c00
2820 +#define NEO_BC1_DST_TRANS 0x00002000
2821 +#define NEO_BC1_MSTR_BLT 0x00004000
2822 +#define NEO_BC1_FILTER_Z 0x00008000
2824 +#define NEO_BC2_WR_TR_DST 0x00800000
2826 +#define NEO_BC3_SRC_XY_ADDR 0x01000000
2827 +#define NEO_BC3_DST_XY_ADDR 0x02000000
2828 +#define NEO_BC3_CLIP_ON 0x04000000
2829 +#define NEO_BC3_FIFO_EN 0x08000000
2830 +#define NEO_BC3_BLT_ON_ADDR 0x10000000
2831 +#define NEO_BC3_SKIP_MAPPING 0x80000000
2833 +#define NEO_MODE1_DEPTH8 0x0100
2834 +#define NEO_MODE1_DEPTH16 0x0200
2835 +#define NEO_MODE1_DEPTH24 0x0300
2836 +#define NEO_MODE1_X_320 0x0400
2837 +#define NEO_MODE1_X_640 0x0800
2838 +#define NEO_MODE1_X_800 0x0c00
2839 +#define NEO_MODE1_X_1024 0x1000
2840 +#define NEO_MODE1_X_1152 0x1400
2841 +#define NEO_MODE1_X_1280 0x1800
2842 +#define NEO_MODE1_X_1600 0x1c00
2843 +#define NEO_MODE1_BLT_ON_ADDR 0x2000
2844 diff -Naur linux-2.4.18-pre6/include/linux/fb.h linux/include/linux/fb.h
2845 --- linux-2.4.18-pre6/include/linux/fb.h Mon Dec 11 22:16:53 2000
2846 +++ linux/include/linux/fb.h Wed Jan 23 13:42:09 2002
2848 #define FB_ACCEL_IGS_CYBER5000 35 /* CyberPro 5000 */
2849 #define FB_ACCEL_SIS_GLAMOUR 36 /* SiS 300/630/540 */
2852 +#define FB_ACCEL_NEOMAGIC_NM2070 90 /* NeoMagic NM2070 */
2853 +#define FB_ACCEL_NEOMAGIC_NM2090 91 /* NeoMagic NM2090 */
2854 +#define FB_ACCEL_NEOMAGIC_NM2093 92 /* NeoMagic NM2093 */
2855 +#define FB_ACCEL_NEOMAGIC_NM2097 93 /* NeoMagic NM2097 */
2856 +#define FB_ACCEL_NEOMAGIC_NM2160 94 /* NeoMagic NM2160 */
2857 +#define FB_ACCEL_NEOMAGIC_NM2200 95 /* NeoMagic NM2200 */
2858 +#define FB_ACCEL_NEOMAGIC_NM2230 96 /* NeoMagic NM2230 */
2859 +#define FB_ACCEL_NEOMAGIC_NM2360 97 /* NeoMagic NM2360 */
2860 +#define FB_ACCEL_NEOMAGIC_NM2380 98 /* NeoMagic NM2380 */
2863 struct fb_fix_screeninfo {
2864 char id[16]; /* identification string eg "TT Builtin" */
2865 unsigned long smem_start; /* Start of frame buffer mem */