Commit 34dfe0cd authored by James Simmons's avatar James Simmons

Merge heisenberg.transvirtual.com:/tmp/linus-2.5

into heisenberg.transvirtual.com:/tmp/fbdev-2.5
parents 65f0361a 8364a826
...@@ -262,7 +262,7 @@ if [ "$CONFIG_FB" = "y" ]; then ...@@ -262,7 +262,7 @@ if [ "$CONFIG_FB" = "y" ]; then
if [ "$CONFIG_FB_ACORN" = "y" -o "$CONFIG_FB_ATARI" = "y" -o \ if [ "$CONFIG_FB_ACORN" = "y" -o "$CONFIG_FB_ATARI" = "y" -o \
"$CONFIG_FB_ATY" = "y" -o "$CONFIG_FB_MAC" = "y" -o \ "$CONFIG_FB_ATY" = "y" -o "$CONFIG_FB_MAC" = "y" -o \
"$CONFIG_FB_OF" = "y" -o "$CONFIG_FB_TGA" = "y" -o \ "$CONFIG_FB_OF" = "y" -o "$CONFIG_FB_TGA" = "y" -o \
"$CONFIG_FB_NEOMAGIC" = "y" -o "$CONFIG_FB_PM3" = "y" -o \ "$CONFIG_FB_TX3912" = "y" -o "$CONFIG_FB_PM3" = "y" -o \
"$CONFIG_FB_TCX" = "y" -o "$CONFIG_FB_CGTHREE" = "y" -o \ "$CONFIG_FB_TCX" = "y" -o "$CONFIG_FB_CGTHREE" = "y" -o \
"$CONFIG_FB_CONTROL" = "y" -o "$CONFIG_FB_CLGEN" = "y" -o \ "$CONFIG_FB_CONTROL" = "y" -o "$CONFIG_FB_CLGEN" = "y" -o \
"$CONFIG_FB_CGFOURTEEN" = "y" -o "$CONFIG_FB_TRIDENT" = "y" -o \ "$CONFIG_FB_CGFOURTEEN" = "y" -o "$CONFIG_FB_TRIDENT" = "y" -o \
...@@ -275,13 +275,13 @@ if [ "$CONFIG_FB" = "y" ]; then ...@@ -275,13 +275,13 @@ if [ "$CONFIG_FB" = "y" ]; then
"$CONFIG_FB_SGIVW" = "y" -o "$CONFIG_FB_CYBER2000" = "y" -o \ "$CONFIG_FB_SGIVW" = "y" -o "$CONFIG_FB_CYBER2000" = "y" -o \
"$CONFIG_FB_SA1100" = "y" -o "$CONFIG_FB_SIS" = "y" -o \ "$CONFIG_FB_SA1100" = "y" -o "$CONFIG_FB_SIS" = "y" -o \
"$CONFIG_FB_PMAG_BA" = "y" -o "$CONFIG_FB_PMAGB_B" = "y" -o \ "$CONFIG_FB_PMAG_BA" = "y" -o "$CONFIG_FB_PMAGB_B" = "y" -o \
"$CONFIG_FB_MAXINE" = "y" -o "$CONFIG_FB_TX3912" = "y" ]; then "$CONFIG_FB_MAXINE" = "y" ]; then
define_tristate CONFIG_FBCON_CFB8 y define_tristate CONFIG_FBCON_CFB8 y
else else
if [ "$CONFIG_FB_ACORN" = "m" -o "$CONFIG_FB_ATARI" = "m" -o \ if [ "$CONFIG_FB_ACORN" = "m" -o "$CONFIG_FB_ATARI" = "m" -o \
"$CONFIG_FB_ATY" = "m" -o "$CONFIG_FB_MAC" = "m" -o \ "$CONFIG_FB_ATY" = "m" -o "$CONFIG_FB_MAC" = "m" -o \
"$CONFIG_FB_OF" = "m" -o "$CONFIG_FB_TGA" = "m" -o \ "$CONFIG_FB_OF" = "m" -o "$CONFIG_FB_TGA" = "m" -o \
"$CONFIG_FB_NEOMAGIC" = "m" -o "$CONFIG_FB_PM3" = "m" -o \ "$CONFIG_FB_SIS" = "m" -o "$CONFIG_FB_PM3" = "m" -o \
"$CONFIG_FB_TCX" = "m" -o "$CONFIG_FB_CGTHREE" = "m" -o \ "$CONFIG_FB_TCX" = "m" -o "$CONFIG_FB_CGTHREE" = "m" -o \
"$CONFIG_FB_CONTROL" = "m" -o "$CONFIG_FB_CLGEN" = "m" -o \ "$CONFIG_FB_CONTROL" = "m" -o "$CONFIG_FB_CLGEN" = "m" -o \
"$CONFIG_FB_CGFOURTEEN" = "m" -o "$CONFIG_FB_TRIDENT" = "m" -o \ "$CONFIG_FB_CGFOURTEEN" = "m" -o "$CONFIG_FB_TRIDENT" = "m" -o \
...@@ -294,12 +294,12 @@ if [ "$CONFIG_FB" = "y" ]; then ...@@ -294,12 +294,12 @@ if [ "$CONFIG_FB" = "y" ]; then
"$CONFIG_FB_SGIVW" = "m" -o "$CONFIG_FB_CYBER2000" = "m" -o \ "$CONFIG_FB_SGIVW" = "m" -o "$CONFIG_FB_CYBER2000" = "m" -o \
"$CONFIG_FB_PMAG_BA" = "m" -o "$CONFIG_FB_PMAGB_B" = "m" -o \ "$CONFIG_FB_PMAG_BA" = "m" -o "$CONFIG_FB_PMAGB_B" = "m" -o \
"$CONFIG_FB_MAXINE" = "m" -o "$CONFIG_FB_RADEON" = "m" -o \ "$CONFIG_FB_MAXINE" = "m" -o "$CONFIG_FB_RADEON" = "m" -o \
"$CONFIG_FB_SA1100" = "m" -o "$CONFIG_FB_SIS" = "m" ]; then "$CONFIG_FB_SA1100" = "m" ]; then
define_tristate CONFIG_FBCON_CFB8 m define_tristate CONFIG_FBCON_CFB8 m
fi fi
fi fi
if [ "$CONFIG_FB_ATARI" = "y" -o "$CONFIG_FB_ATY" = "y" -o \ if [ "$CONFIG_FB_ATARI" = "y" -o "$CONFIG_FB_ATY" = "y" -o \
"$CONFIG_FB_MAC" = "y" -o "$CONFIG_FB_NEOMAGIC" = "y" -o \ "$CONFIG_FB_MAC" = "y" -o "$CONFIG_FB_PVR2" = "y" -o \
"$CONFIG_FB_TRIDENT" = "y" -o "$CONFIG_FB_TBOX" = "y" -o \ "$CONFIG_FB_TRIDENT" = "y" -o "$CONFIG_FB_TBOX" = "y" -o \
"$CONFIG_FB_VOODOO1" = "y" -o "$CONFIG_FB_RADEON" = "y" -o \ "$CONFIG_FB_VOODOO1" = "y" -o "$CONFIG_FB_RADEON" = "y" -o \
"$CONFIG_FB_CONTROL" = "y" -o "$CONFIG_FB_CLGEN" = "y" -o \ "$CONFIG_FB_CONTROL" = "y" -o "$CONFIG_FB_CLGEN" = "y" -o \
...@@ -309,12 +309,11 @@ if [ "$CONFIG_FB" = "y" ]; then ...@@ -309,12 +309,11 @@ if [ "$CONFIG_FB" = "y" ]; then
"$CONFIG_FB_PM2" = "y" -o "$CONFIG_FB_SGIVW" = "y" -o \ "$CONFIG_FB_PM2" = "y" -o "$CONFIG_FB_SGIVW" = "y" -o \
"$CONFIG_FB_RIVA" = "y" -o "$CONFIG_FB_ATY128" = "y" -o \ "$CONFIG_FB_RIVA" = "y" -o "$CONFIG_FB_ATY128" = "y" -o \
"$CONFIG_FB_CYBER2000" = "y" -o "$CONFIG_FB_PM3" = "y" -o \ "$CONFIG_FB_CYBER2000" = "y" -o "$CONFIG_FB_PM3" = "y" -o \
"$CONFIG_FB_SIS" = "y" -o "$CONFIG_FB_SA1100" = "y" -o \ "$CONFIG_FB_SIS" = "y" -o "$CONFIG_FB_SA1100" = "y" ]; then
"$CONFIG_FB_PVR2" = "y" ]; then
define_tristate CONFIG_FBCON_CFB16 y define_tristate CONFIG_FBCON_CFB16 y
else else
if [ "$CONFIG_FB_ATARI" = "m" -o "$CONFIG_FB_ATY" = "m" -o \ if [ "$CONFIG_FB_ATARI" = "m" -o "$CONFIG_FB_ATY" = "m" -o \
"$CONFIG_FB_MAC" = "m" -o "$CONFIG_FB_NEOMAGIC" = "m" -o \ "$CONFIG_FB_MAC" = "m" -o "$CONFIG_FB_PVR2" = "m" -o \
"$CONFIG_FB_TRIDENT" = "m" -o "$CONFIG_FB_TBOX" = "m" -o \ "$CONFIG_FB_TRIDENT" = "m" -o "$CONFIG_FB_TBOX" = "m" -o \
"$CONFIG_FB_VOODOO1" = "m" -o "$CONFIG_FB_PM3" = "m" -o \ "$CONFIG_FB_VOODOO1" = "m" -o "$CONFIG_FB_PM3" = "m" -o \
"$CONFIG_FB_CONTROL" = "m" -o "$CONFIG_FB_CLGEN" = "m" -o \ "$CONFIG_FB_CONTROL" = "m" -o "$CONFIG_FB_CLGEN" = "m" -o \
...@@ -324,8 +323,7 @@ if [ "$CONFIG_FB" = "y" ]; then ...@@ -324,8 +323,7 @@ if [ "$CONFIG_FB" = "y" ]; then
"$CONFIG_FB_PM2" = "m" -o "$CONFIG_FB_SGIVW" = "m" -o \ "$CONFIG_FB_PM2" = "m" -o "$CONFIG_FB_SGIVW" = "m" -o \
"$CONFIG_FB_RIVA" = "m" -o "$CONFIG_FB_ATY128" = "m" -o \ "$CONFIG_FB_RIVA" = "m" -o "$CONFIG_FB_ATY128" = "m" -o \
"$CONFIG_FB_CYBER2000" = "m" -o "$CONFIG_FB_SIS" = "m" -o \ "$CONFIG_FB_CYBER2000" = "m" -o "$CONFIG_FB_SIS" = "m" -o \
"$CONFIG_FB_SA1100" = "m" -o "$CONFIG_FB_RADEON" = "m" -o \ "$CONFIG_FB_SA1100" = "m" -o "$CONFIG_FB_RADEON" = "m" ]; then
"$CONFIG_FB_PVR2" = "m" ]; then
define_tristate CONFIG_FBCON_CFB16 m define_tristate CONFIG_FBCON_CFB16 m
fi fi
fi fi
......
...@@ -48,13 +48,13 @@ obj-$(CONFIG_FB_Q40) += q40fb.o cfbfillrect.o cfbcopyarea.o cfbimgb ...@@ -48,13 +48,13 @@ obj-$(CONFIG_FB_Q40) += q40fb.o cfbfillrect.o cfbcopyarea.o cfbimgb
obj-$(CONFIG_FB_ATARI) += atafb.o obj-$(CONFIG_FB_ATARI) += atafb.o
obj-$(CONFIG_FB_ATY128) += aty128fb.o obj-$(CONFIG_FB_ATY128) += aty128fb.o
obj-$(CONFIG_FB_RADEON) += radeonfb.o obj-$(CONFIG_FB_RADEON) += radeonfb.o
obj-$(CONFIG_FB_NEOMAGIC) += neofb.o obj-$(CONFIG_FB_NEOMAGIC) += neofb.o cfbfillrect.o cfbcopyarea.o cfbimgblt.o
obj-$(CONFIG_FB_IGA) += igafb.o obj-$(CONFIG_FB_IGA) += igafb.o
obj-$(CONFIG_FB_CONTROL) += controlfb.o obj-$(CONFIG_FB_CONTROL) += controlfb.o
obj-$(CONFIG_FB_PLATINUM) += platinumfb.o obj-$(CONFIG_FB_PLATINUM) += platinumfb.o
obj-$(CONFIG_FB_VALKYRIE) += valkyriefb.o obj-$(CONFIG_FB_VALKYRIE) += valkyriefb.o
obj-$(CONFIG_FB_CT65550) += chipsfb.o obj-$(CONFIG_FB_CT65550) += chipsfb.o
obj-$(CONFIG_FB_ANAKIN) += anakinfb.o obj-$(CONFIG_FB_ANAKIN) += anakinfb.o cfbfillrect.o cfbcopyarea.o cfbimgblt.o
obj-$(CONFIG_FB_CLPS711X) += clps711xfb.o cfbfillrect.o cfbcopyarea.o cfbimgblt.o obj-$(CONFIG_FB_CLPS711X) += clps711xfb.o cfbfillrect.o cfbcopyarea.o cfbimgblt.o
obj-$(CONFIG_FB_CYBER) += cyberfb.o obj-$(CONFIG_FB_CYBER) += cyberfb.o
obj-$(CONFIG_FB_CYBER2000) += cyber2000fb.o obj-$(CONFIG_FB_CYBER2000) += cyber2000fb.o
......
...@@ -21,7 +21,6 @@ ...@@ -21,7 +21,6 @@
#include <asm/io.h> #include <asm/io.h>
#include <video/fbcon.h> #include <video/fbcon.h>
#include <video/fbcon-cfb16.h>
static u32 colreg[16]; static u32 colreg[16];
static struct fb_info fb_info; static struct fb_info fb_info;
......
...@@ -203,6 +203,9 @@ static struct fb_ops clps7111fb_ops = { ...@@ -203,6 +203,9 @@ static struct fb_ops clps7111fb_ops = {
fb_get_cmap: gen_get_cmap, fb_get_cmap: gen_get_cmap,
fb_setcolreg: clps7111fb_setcolreg, fb_setcolreg: clps7111fb_setcolreg,
fb_blank: clps7111fb_blank, fb_blank: clps7111fb_blank,
fb_fillrect: cfb_fillrect,
fb_copyarea: cfb_copyarea,
fb_imageblit: cfb_imageblit,
}; };
static int static int
......
...@@ -1729,8 +1729,9 @@ static int cyberpro_pci_resume(struct pci_dev *dev) ...@@ -1729,8 +1729,9 @@ static int cyberpro_pci_resume(struct pci_dev *dev)
} }
static struct pci_device_id cyberpro_pci_table[] __devinitdata = { static struct pci_device_id cyberpro_pci_table[] __devinitdata = {
{ PCI_VENDOR_ID_INTERG, PCI_DEVICE_ID_INTERG_1682, // Not yet
PCI_ANY_ID, PCI_ANY_ID, 0, 0, ID_IGA_1682 }, // { PCI_VENDOR_ID_INTERG, PCI_DEVICE_ID_INTERG_1682,
// PCI_ANY_ID, PCI_ANY_ID, 0, 0, ID_IGA_1682 },
{ PCI_VENDOR_ID_INTERG, PCI_DEVICE_ID_INTERG_2000, { PCI_VENDOR_ID_INTERG, PCI_DEVICE_ID_INTERG_2000,
PCI_ANY_ID, PCI_ANY_ID, 0, 0, ID_CYBERPRO_2000 }, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ID_CYBERPRO_2000 },
{ PCI_VENDOR_ID_INTERG, PCI_DEVICE_ID_INTERG_2010, { PCI_VENDOR_ID_INTERG, PCI_DEVICE_ID_INTERG_2010,
......
...@@ -11,6 +11,8 @@ ...@@ -11,6 +11,8 @@
* Public License. See the file COPYING in the main directory of this * Public License. See the file COPYING in the main directory of this
* archive for more details. * archive for more details.
* *
* 0.3.3
* - Porting over to new fbdev api. (jsimmons)
* *
* 0.3.2 * 0.3.2
* - got rid of all floating point (dok) * - got rid of all floating point (dok)
...@@ -66,768 +68,117 @@ ...@@ -66,768 +68,117 @@
#endif #endif
#include <video/fbcon.h> #include <video/fbcon.h>
#include <video/fbcon-cfb8.h> #include <video/neomagic.h>
#include <video/fbcon-cfb16.h>
#include <video/fbcon-cfb24.h>
#include <video/fbcon-cfb32.h>
#include "neofb.h" #define NEOFB_VERSION "0.3.3"
struct neofb_par default_par;
#define NEOFB_VERSION "0.3.2" /* --------------------------------------------------------------------- */
/* --------------------------------------------------------------------- */
static int disabled = 0;
static int internal = 0;
static int external = 0;
static int nostretch = 0;
static int nopciburst = 0;
#ifdef MODULE
MODULE_AUTHOR("(c) 2001-2002 Denis Oliver Kropp <dok@convergence.de>");
MODULE_LICENSE("GPL");
MODULE_DESCRIPTION("FBDev driver for NeoMagic PCI Chips");
MODULE_PARM(disabled, "i");
MODULE_PARM_DESC(disabled, "Disable this driver's initialization.");
MODULE_PARM(internal, "i");
MODULE_PARM_DESC(internal, "Enable output on internal LCD Display.");
MODULE_PARM(external, "i");
MODULE_PARM_DESC(external, "Enable output on external CRT.");
MODULE_PARM(nostretch, "i");
MODULE_PARM_DESC(nostretch, "Disable stretching of modes smaller than LCD.");
MODULE_PARM(nopciburst, "i");
MODULE_PARM_DESC(nopciburst, "Disable PCI burst mode.");
#endif
/* --------------------------------------------------------------------- */
static biosMode bios8[] = {
{ 320, 240, 0x40 },
{ 300, 400, 0x42 },
{ 640, 400, 0x20 },
{ 640, 480, 0x21 },
{ 800, 600, 0x23 },
{ 1024, 768, 0x25 },
};
static biosMode bios16[] = {
{ 320, 200, 0x2e },
{ 320, 240, 0x41 },
{ 300, 400, 0x43 },
{ 640, 480, 0x31 },
{ 800, 600, 0x34 },
{ 1024, 768, 0x37 },
};
static biosMode bios24[] = {
{ 640, 480, 0x32 },
{ 800, 600, 0x35 },
{ 1024, 768, 0x38 }
};
#ifdef NO_32BIT_SUPPORT_YET
/* FIXME: guessed values, wrong */
static biosMode bios32[] = {
{ 640, 480, 0x33 },
{ 800, 600, 0x36 },
{ 1024, 768, 0x39 }
};
#endif
static int neoFindMode (int xres, int yres, int depth)
{
int xres_s;
int i, size;
biosMode *mode;
switch (depth)
{
case 8:
size = sizeof(bios8) / sizeof(biosMode);
mode = bios8;
break;
case 16:
size = sizeof(bios16) / sizeof(biosMode);
mode = bios16;
break;
case 24:
size = sizeof(bios24) / sizeof(biosMode);
mode = bios24;
break;
#ifdef NO_32BIT_SUPPORT_YET
case 32:
size = sizeof(bios32) / sizeof(biosMode);
mode = bios32;
break;
#endif
default:
return 0;
}
for (i = 0; i < size; i++)
{
if (xres <= mode[i].x_res)
{
xres_s = mode[i].x_res;
for (; i < size; i++)
{
if (mode[i].x_res != xres_s)
return mode[i-1].mode;
if (yres <= mode[i].y_res)
return mode[i].mode;
}
}
}
return mode[size - 1].mode;
}
/* -------------------- Hardware specific routines ------------------------- */
/*
* Hardware Acceleration for Neo2200+
*/
static inline void neo2200_wait_idle (struct neofb_info *fb)
{
int waitcycles;
while (fb->neo2200->bltStat & 1)
waitcycles++;
}
static inline void neo2200_wait_fifo (struct neofb_info *fb,
int requested_fifo_space)
{
// ndev->neo.waitfifo_calls++;
// ndev->neo.waitfifo_sum += requested_fifo_space;
/* FIXME: does not work
if (neo_fifo_space < requested_fifo_space)
{
neo_fifo_waitcycles++;
while (1)
{
neo_fifo_space = (neo2200->bltStat >> 8);
if (neo_fifo_space >= requested_fifo_space)
break;
}
}
else
{
neo_fifo_cache_hits++;
}
neo_fifo_space -= requested_fifo_space;
*/
neo2200_wait_idle (fb);
}
static inline void neo2200_accel_init (struct neofb_info *fb,
struct fb_var_screeninfo *var)
{
Neo2200 *neo2200 = fb->neo2200;
u32 bltMod, pitch;
neo2200_wait_idle (fb);
switch (var->bits_per_pixel)
{
case 8:
bltMod = NEO_MODE1_DEPTH8;
pitch = var->xres_virtual;
break;
case 15:
case 16:
bltMod = NEO_MODE1_DEPTH16;
pitch = var->xres_virtual * 2;
break;
default:
printk( KERN_ERR "neofb: neo2200_accel_init: unexpected bits per pixel!\n" );
return;
}
neo2200->bltStat = bltMod << 16;
neo2200->pitch = (pitch << 16) | pitch;
}
static void neo2200_accel_setup (struct display *p)
{
struct neofb_info *fb = (struct neofb_info *)p->fb_info;
struct fb_var_screeninfo *var = &p->fb_info->var;
fb->dispsw->setup(p);
neo2200_accel_init (fb, var);
}
static void
neo2200_accel_bmove (struct display *p, int sy, int sx, int dy, int dx,
int height, int width)
{
struct neofb_info *fb = (struct neofb_info *)p->fb_info;
struct fb_var_screeninfo *var = &p->fb_info->var;
Neo2200 *neo2200 = fb->neo2200;
u_long src, dst;
int bpp, pitch, inc_y;
u_int fh, fw;
/* setting blitting direction does not work, so this case is unaccelerated */
if (sx != dx)
{
neo2200_wait_idle (fb);
fb->dispsw->bmove(p, sy, sx, dy, dx, height, width);
return;
}
bpp = (var->bits_per_pixel+7) / 8;
pitch = var->xres_virtual * bpp;
fw = fontwidth(p);
sx *= fw * bpp;
dx *= fw * bpp;
width *= fw;
fh = fontheight(p);
sy *= fh;
dy *= fh;
if (sy > dy)
inc_y = fh;
else
{
inc_y = -fh;
sy += (height - 1) * fh;
dy += (height - 1) * fh;
}
neo2200_wait_fifo (fb, 1);
/* set blt control */
neo2200->bltCntl = NEO_BC3_FIFO_EN |
NEO_BC3_SKIP_MAPPING | 0x0c0000;
/* looks silly, but setting the blitting direction did not work */
while (height--)
{
src = sx + sy * pitch;
dst = dx + dy * pitch;
neo2200_wait_fifo (fb, 3);
neo2200->srcStart = src;
neo2200->dstStart = dst;
neo2200->xyExt = (fh << 16) | (width & 0xffff);
sy += inc_y;
dy += inc_y;
}
}
static void
neo2200_accel_clear (struct vc_data *conp, struct display *p, int sy, int sx,
int height, int width)
{
struct neofb_info *fb = (struct neofb_info *)p->fb_info;
struct fb_var_screeninfo *var = &p->fb_info->var;
Neo2200 *neo2200 = fb->neo2200;
u_long dst;
u_int fw, fh;
u32 bgx = attr_bgcol_ec(p, conp);
fw = fontwidth(p);
fh = fontheight(p);
dst = sx * fw + sy * var->xres_virtual * fh;
width = width * fw;
height = height * fh;
neo2200_wait_fifo (fb, 4);
/* set blt control */
neo2200->bltCntl = NEO_BC3_FIFO_EN |
NEO_BC0_SRC_IS_FG |
NEO_BC3_SKIP_MAPPING | 0x0c0000;
switch (var->bits_per_pixel)
{
case 8:
neo2200->fgColor = bgx;
break;
case 16:
neo2200->fgColor = ((u16 *)(p->fb_info)->pseudo_palette)[bgx];
break;
}
neo2200->dstStart = dst * ((var->bits_per_pixel+7) / 8);
neo2200->xyExt = (height << 16) | (width & 0xffff);
}
static void
neo2200_accel_putc (struct vc_data *conp, struct display *p, int c,
int yy, int xx)
{
struct neofb_info *fb = (struct neofb_info *)p->fb_info;
neo2200_wait_idle (fb);
fb->dispsw->putc(conp, p, c, yy, xx);
}
static void
neo2200_accel_putcs (struct vc_data *conp, struct display *p,
const unsigned short *s, int count, int yy, int xx)
{
struct neofb_info *fb = (struct neofb_info *)p->fb_info;
neo2200_wait_idle (fb);
fb->dispsw->putcs(conp, p, s, count, yy, xx);
}
static void neo2200_accel_revc (struct display *p, int xx, int yy)
{
struct neofb_info *fb = (struct neofb_info *)p->fb_info;
neo2200_wait_idle (fb);
fb->dispsw->revc (p, xx, yy);
}
static void
neo2200_accel_clear_margins (struct vc_data *conp, struct display *p,
int bottom_only)
{
struct neofb_info *fb = (struct neofb_info *)p->fb_info;
fb->dispsw->clear_margins (conp, p, bottom_only);
}
static struct display_switch fbcon_neo2200_accel = {
setup: neo2200_accel_setup,
bmove: neo2200_accel_bmove,
clear: neo2200_accel_clear,
putc: neo2200_accel_putc,
putcs: neo2200_accel_putcs,
revc: neo2200_accel_revc,
clear_margins: neo2200_accel_clear_margins,
fontwidthmask: FONTWIDTH(8)|FONTWIDTH(16)
};
/* --------------------------------------------------------------------- */
/*
* Set a single color register. Return != 0 for invalid regno.
*/
static int neofb_setcolreg(u_int regno, u_int red, u_int green, u_int blue,
u_int transp, struct fb_info *fb)
{
struct neofb_info *info = (struct neofb_info *)fb;
if (regno >= NR_PALETTE)
return -EINVAL;
info->palette[regno].red = red;
info->palette[regno].green = green;
info->palette[regno].blue = blue;
info->palette[regno].transp = transp;
switch (fb->var.bits_per_pixel)
{
#ifdef FBCON_HAS_CFB8
case 8:
outb(regno, 0x3c8);
outb(red >> 10, 0x3c9);
outb(green >> 10, 0x3c9);
outb(blue >> 10, 0x3c9);
break;
#endif
#ifdef FBCON_HAS_CFB16
case 16:
if (regno < 16)
((u16 *)fb->pseudo_palette)[regno] = ((red & 0xf800) ) |
((green & 0xfc00) >> 5) |
((blue & 0xf800) >> 11);
break;
#endif
#ifdef FBCON_HAS_CFB24
case 24:
if (regno < 16)
((u32 *)fb->pseudo_palette)[regno] = ((red & 0xff00) << 8) |
((green & 0xff00) ) |
((blue & 0xff00) >> 8);
break;
#endif
#ifdef NO_32BIT_SUPPORT_YET
#ifdef FBCON_HAS_CFB32
case 32:
if (regno < 16)
((u32 *)fb->pseudo_palette)[regno] = ((transp & 0xff00) << 16) |
((red & 0xff00) << 8) |
((green & 0xff00) ) |
((blue & 0xff00) >> 8);
break;
#endif
#endif
default:
return 1;
}
return 0;
}
static void vgaHWLock (void)
{
/* Protect CRTC[0-7] */
VGAwCR (0x11, VGArCR (0x11) | 0x80);
}
static void vgaHWUnlock (void)
{
/* Unprotect CRTC[0-7] */
VGAwCR (0x11, VGArCR (0x11) & ~0x80);
}
static void neoLock (void)
{
VGAwGR (0x09, 0x00);
vgaHWLock();
}
static void neoUnlock (void)
{
vgaHWUnlock();
VGAwGR (0x09, 0x26);
}
/*
* vgaHWSeqReset
* perform a sequencer reset.
*/
void
vgaHWSeqReset(int start)
{
if (start)
VGAwSEQ (0x00, 0x01); /* Synchronous Reset */
else
VGAwSEQ (0x00, 0x03); /* End Reset */
}
void
vgaHWProtect(int on)
{
unsigned char tmp;
if (on)
{
/*
* Turn off screen and disable sequencer.
*/
tmp = VGArSEQ (0x01);
vgaHWSeqReset (1); /* start synchronous reset */
VGAwSEQ (0x01, tmp | 0x20); /* disable the display */
VGAenablePalette();
}
else
{
/*
* Reenable sequencer, then turn on screen.
*/
tmp = VGArSEQ (0x01);
VGAwSEQ (0x01, tmp & ~0x20); /* reenable display */
vgaHWSeqReset (0); /* clear synchronousreset */
VGAdisablePalette();
}
}
static void vgaHWRestore (const struct neofb_info *info,
const struct neofb_par *par)
{
int i;
VGAwMISC (par->MiscOutReg);
for (i = 1; i < 5; i++)
VGAwSEQ (i, par->Sequencer[i]);
/* Ensure CRTC registers 0-7 are unlocked by clearing bit 7 or CRTC[17] */
VGAwCR (17, par->CRTC[17] & ~0x80);
for (i = 0; i < 25; i++)
VGAwCR (i, par->CRTC[i]);
for (i = 0; i < 9; i++)
VGAwGR (i, par->Graphics[i]);
VGAenablePalette();
for (i = 0; i < 21; i++)
VGAwATTR (i, par->Attribute[i]);
VGAdisablePalette();
}
static void neofb_set_par (struct neofb_info *info,
const struct neofb_par *par)
{
unsigned char temp;
int i;
int clock_hi = 0;
DBG("neofb_set_par");
neoUnlock();
vgaHWProtect (1); /* Blank the screen */
/* linear colormap for non palettized modes */
switch (par->depth)
{
case 8:
break;
case 16:
for (i=0; i<64; i++)
{
outb(i, 0x3c8);
outb(i << 1, 0x3c9);
outb(i, 0x3c9);
outb(i << 1, 0x3c9);
}
break;
case 24:
#ifdef NO_32BIT_SUPPORT_YET
case 32:
#endif
for (i=0; i<256; i++)
{
outb(i, 0x3c8);
outb(i, 0x3c9);
outb(i, 0x3c9);
outb(i, 0x3c9);
}
break;
}
/* alread unlocked above */
/* BOGUS VGAwGR (0x09, 0x26);*/
/* don't know what this is, but it's 0 from bootup anyway */
VGAwGR (0x15, 0x00);
/* was set to 0x01 by my bios in text and vesa modes */
VGAwGR (0x0A, par->GeneralLockReg);
/*
* The color mode needs to be set before calling vgaHWRestore
* to ensure the DAC is initialized properly.
*
* NOTE: Make sure we don't change bits make sure we don't change
* any reserved bits.
*/
temp = VGArGR(0x90);
switch (info->accel)
{
case FB_ACCEL_NEOMAGIC_NM2070:
temp &= 0xF0; /* Save bits 7:4 */
temp |= (par->ExtColorModeSelect & ~0xF0);
break;
case FB_ACCEL_NEOMAGIC_NM2090:
case FB_ACCEL_NEOMAGIC_NM2093:
case FB_ACCEL_NEOMAGIC_NM2097:
case FB_ACCEL_NEOMAGIC_NM2160:
case FB_ACCEL_NEOMAGIC_NM2200:
case FB_ACCEL_NEOMAGIC_NM2230:
case FB_ACCEL_NEOMAGIC_NM2360:
case FB_ACCEL_NEOMAGIC_NM2380:
temp &= 0x70; /* Save bits 6:4 */
temp |= (par->ExtColorModeSelect & ~0x70);
break;
}
VGAwGR(0x90,temp);
/*
* In some rare cases a lockup might occur if we don't delay
* here. (Reported by Miles Lane)
*/
//mdelay(200);
/*
* Disable horizontal and vertical graphics and text expansions so
* that vgaHWRestore works properly.
*/
temp = VGArGR(0x25);
temp &= 0x39;
VGAwGR (0x25, temp);
/*
* Sleep for 200ms to make sure that the two operations above have
* had time to take effect.
*/
mdelay(200);
/*
* This function handles restoring the generic VGA registers. */
vgaHWRestore (info, par);
VGAwGR(0x0E, par->ExtCRTDispAddr);
VGAwGR(0x0F, par->ExtCRTOffset);
temp = VGArGR(0x10);
temp &= 0x0F; /* Save bits 3:0 */
temp |= (par->SysIfaceCntl1 & ~0x0F); /* VESA Bios sets bit 1! */
VGAwGR(0x10, temp);
VGAwGR(0x11, par->SysIfaceCntl2);
VGAwGR(0x15, 0 /*par->SingleAddrPage*/);
VGAwGR(0x16, 0 /*par->DualAddrPage*/);
temp = VGArGR(0x20);
switch (info->accel)
{
case FB_ACCEL_NEOMAGIC_NM2070:
temp &= 0xFC; /* Save bits 7:2 */
temp |= (par->PanelDispCntlReg1 & ~0xFC);
break;
case FB_ACCEL_NEOMAGIC_NM2090:
case FB_ACCEL_NEOMAGIC_NM2093:
case FB_ACCEL_NEOMAGIC_NM2097:
case FB_ACCEL_NEOMAGIC_NM2160:
temp &= 0xDC; /* Save bits 7:6,4:2 */
temp |= (par->PanelDispCntlReg1 & ~0xDC);
break;
case FB_ACCEL_NEOMAGIC_NM2200:
case FB_ACCEL_NEOMAGIC_NM2230:
case FB_ACCEL_NEOMAGIC_NM2360:
case FB_ACCEL_NEOMAGIC_NM2380:
temp &= 0x98; /* Save bits 7,4:3 */
temp |= (par->PanelDispCntlReg1 & ~0x98);
break;
}
VGAwGR(0x20, temp);
temp = VGArGR(0x25);
temp &= 0x38; /* Save bits 5:3 */
temp |= (par->PanelDispCntlReg2 & ~0x38);
VGAwGR(0x25, temp);
if (info->accel != FB_ACCEL_NEOMAGIC_NM2070)
{
temp = VGArGR(0x30);
temp &= 0xEF; /* Save bits 7:5 and bits 3:0 */
temp |= (par->PanelDispCntlReg3 & ~0xEF);
VGAwGR(0x30, temp);
}
VGAwGR(0x28, par->PanelVertCenterReg1);
VGAwGR(0x29, par->PanelVertCenterReg2);
VGAwGR(0x2a, par->PanelVertCenterReg3);
if (info->accel != FB_ACCEL_NEOMAGIC_NM2070)
{
VGAwGR(0x32, par->PanelVertCenterReg4);
VGAwGR(0x33, par->PanelHorizCenterReg1);
VGAwGR(0x34, par->PanelHorizCenterReg2);
VGAwGR(0x35, par->PanelHorizCenterReg3);
}
if (info->accel == FB_ACCEL_NEOMAGIC_NM2160)
VGAwGR(0x36, par->PanelHorizCenterReg4);
if (info->accel == FB_ACCEL_NEOMAGIC_NM2200 ||
info->accel == FB_ACCEL_NEOMAGIC_NM2230 ||
info->accel == FB_ACCEL_NEOMAGIC_NM2360 ||
info->accel == FB_ACCEL_NEOMAGIC_NM2380)
{
VGAwGR(0x36, par->PanelHorizCenterReg4);
VGAwGR(0x37, par->PanelVertCenterReg5);
VGAwGR(0x38, par->PanelHorizCenterReg5);
clock_hi = 1;
}
/* Program VCLK3 if needed. */ static int disabled = 0;
if (par->ProgramVCLK static int internal = 0;
&& ((VGArGR(0x9B) != par->VCLK3NumeratorLow) static int external = 0;
|| (VGArGR(0x9F) != par->VCLK3Denominator) static int nostretch = 0;
|| (clock_hi && ((VGArGR(0x8F) & ~0x0f) static int nopciburst = 0;
!= (par->VCLK3NumeratorHigh & ~0x0F)))))
{
VGAwGR(0x9B, par->VCLK3NumeratorLow);
if (clock_hi)
{
temp = VGArGR(0x8F);
temp &= 0x0F; /* Save bits 3:0 */
temp |= (par->VCLK3NumeratorHigh & ~0x0F);
VGAwGR(0x8F, temp);
}
VGAwGR(0x9F, par->VCLK3Denominator);
}
if (par->biosMode)
VGAwCR(0x23, par->biosMode);
VGAwGR (0x93, 0xc0); /* Gives 5x faster framebuffer writes !!! */ #ifdef MODULE
/* Program vertical extension register */ MODULE_AUTHOR("(c) 2001-2002 Denis Oliver Kropp <dok@convergence.de>");
if (info->accel == FB_ACCEL_NEOMAGIC_NM2200 || MODULE_LICENSE("GPL");
info->accel == FB_ACCEL_NEOMAGIC_NM2230 || MODULE_DESCRIPTION("FBDev driver for NeoMagic PCI Chips");
info->accel == FB_ACCEL_NEOMAGIC_NM2360 || MODULE_PARM(disabled, "i");
info->accel == FB_ACCEL_NEOMAGIC_NM2380) MODULE_PARM_DESC(disabled, "Disable this driver's initialization.");
{ MODULE_PARM(internal, "i");
VGAwCR(0x70, par->VerticalExt); MODULE_PARM_DESC(internal, "Enable output on internal LCD Display.");
} MODULE_PARM(external, "i");
MODULE_PARM_DESC(external, "Enable output on external CRT.");
MODULE_PARM(nostretch, "i");
MODULE_PARM_DESC(nostretch,
"Disable stretching of modes smaller than LCD.");
MODULE_PARM(nopciburst, "i");
MODULE_PARM_DESC(nopciburst, "Disable PCI burst mode.");
#endif
vgaHWProtect (0); /* Turn on screen */
/* Calling this also locks offset registers required in update_start */ /* --------------------------------------------------------------------- */
neoLock();
}
static void neofb_update_start (struct neofb_info *info, struct fb_var_screeninfo *var) static biosMode bios8[] = {
{ {320, 240, 0x40},
int oldExtCRTDispAddr; {300, 400, 0x42},
int Base; {640, 400, 0x20},
{640, 480, 0x21},
{800, 600, 0x23},
{1024, 768, 0x25},
};
DBG("neofb_update_start"); static biosMode bios16[] = {
{320, 200, 0x2e},
{320, 240, 0x41},
{300, 400, 0x43},
{640, 480, 0x31},
{800, 600, 0x34},
{1024, 768, 0x37},
};
Base = (var->yoffset * var->xres_virtual + var->xoffset) >> 2; static biosMode bios24[] = {
Base *= (var->bits_per_pixel + 7) / 8; {640, 480, 0x32},
{800, 600, 0x35},
{1024, 768, 0x38}
};
neoUnlock(); #ifdef NO_32BIT_SUPPORT_YET
/* FIXME: guessed values, wrong */
static biosMode bios32[] = {
{640, 480, 0x33},
{800, 600, 0x36},
{1024, 768, 0x39}
};
#endif
/* static int neoFindMode(int xres, int yres, int depth)
* These are the generic starting address registers. {
*/ int xres_s;
VGAwCR(0x0C, (Base & 0x00FF00) >> 8); int i, size;
VGAwCR(0x0D, (Base & 0x00FF)); biosMode *mode;
/* switch (depth) {
* Make sure we don't clobber some other bits that might already case 8:
* have been set. NOTE: NM2200 has a writable bit 3, but it shouldn't size = sizeof(bios8) / sizeof(biosMode);
* be needed. mode = bios8;
*/ break;
oldExtCRTDispAddr = VGArGR(0x0E); case 16:
VGAwGR(0x0E,(((Base >> 16) & 0x0f) | (oldExtCRTDispAddr & 0xf0))); size = sizeof(bios16) / sizeof(biosMode);
mode = bios16;
break;
case 24:
size = sizeof(bios24) / sizeof(biosMode);
mode = bios24;
break;
#ifdef NO_32BIT_SUPPORT_YET
case 32:
size = sizeof(bios32) / sizeof(biosMode);
mode = bios32;
break;
#endif
default:
return 0;
}
neoLock(); for (i = 0; i < size; i++) {
if (xres <= mode[i].x_res) {
xres_s = mode[i].x_res;
for (; i < size; i++) {
if (mode[i].x_res != xres_s)
return mode[i - 1].mode;
if (yres <= mode[i].y_res)
return mode[i].mode;
}
}
}
return mode[size - 1].mode;
} }
/* /*
...@@ -840,7 +191,8 @@ static void neofb_update_start (struct neofb_info *info, struct fb_var_screeninf ...@@ -840,7 +191,8 @@ static void neofb_update_start (struct neofb_info *info, struct fb_var_screeninf
#define MAX_D 31 #define MAX_D 31
#define MAX_F 1 #define MAX_F 1
static void neoCalcVCLK (const struct neofb_info *info, struct neofb_par *par, long freq) static void neoCalcVCLK(const struct fb_info *info,
struct neofb_par *par, long freq)
{ {
int n, d, f; int n, d, f;
int n_best = 0, d_best = 0, f_best = 0; int n_best = 0, d_best = 0, f_best = 0;
...@@ -849,15 +201,17 @@ static void neoCalcVCLK (const struct neofb_info *info, struct neofb_par *par, l ...@@ -849,15 +201,17 @@ static void neoCalcVCLK (const struct neofb_info *info, struct neofb_par *par, l
for (f = 0; f <= MAX_F; f++) for (f = 0; f <= MAX_F; f++)
for (n = 0; n <= MAX_N; n++) for (n = 0; n <= MAX_N; n++)
for (d = 0; d <= MAX_D; d++) for (d = 0; d <= MAX_D; d++) {
{
long f_out; /* 20.12 */ long f_out; /* 20.12 */
long f_diff; /* 20.12 */ long f_diff; /* 20.12 */
f_out = ((((n+1) << 12) / ((d+1)*(1<<f))) >> 12) * REF_FREQ; f_out =
f_diff = abs(f_out-f_target); ((((n + 1) << 12) / ((d +
if (f_diff < f_best_diff) 1) *
{ (1 << f))) >> 12)
* REF_FREQ;
f_diff = abs(f_out - f_target);
if (f_diff < f_best_diff) {
f_best_diff = f_diff; f_best_diff = f_diff;
n_best = n; n_best = n;
d_best = d; d_best = d;
...@@ -865,28 +219,25 @@ static void neoCalcVCLK (const struct neofb_info *info, struct neofb_par *par, l ...@@ -865,28 +219,25 @@ static void neoCalcVCLK (const struct neofb_info *info, struct neofb_par *par, l
} }
} }
if (info->accel == FB_ACCEL_NEOMAGIC_NM2200 || if (info->fix.accel == FB_ACCEL_NEOMAGIC_NM2200 ||
info->accel == FB_ACCEL_NEOMAGIC_NM2230 || info->fix.accel == FB_ACCEL_NEOMAGIC_NM2230 ||
info->accel == FB_ACCEL_NEOMAGIC_NM2360 || info->fix.accel == FB_ACCEL_NEOMAGIC_NM2360 ||
info->accel == FB_ACCEL_NEOMAGIC_NM2380) info->fix.accel == FB_ACCEL_NEOMAGIC_NM2380) {
{
/* NOT_DONE: We are trying the full range of the 2200 clock. /* NOT_DONE: We are trying the full range of the 2200 clock.
We should be able to try n up to 2047 */ We should be able to try n up to 2047 */
par->VCLK3NumeratorLow = n_best; par->VCLK3NumeratorLow = n_best;
par->VCLK3NumeratorHigh = (f_best << 7); par->VCLK3NumeratorHigh = (f_best << 7);
} } else
else
par->VCLK3NumeratorLow = n_best | (f_best << 7); par->VCLK3NumeratorLow = n_best | (f_best << 7);
par->VCLK3Denominator = d_best; par->VCLK3Denominator = d_best;
#ifdef NEOFB_DEBUG #ifdef NEOFB_DEBUG
printk ("neoVCLK: f:%d NumLow=%d NumHi=%d Den=%d Df=%d\n", printk("neoVCLK: f:%d NumLow=%d NumHi=%d Den=%d Df=%d\n",
f_target >> 12, f_target >> 12,
par->VCLK3NumeratorLow, par->VCLK3NumeratorLow,
par->VCLK3NumeratorHigh, par->VCLK3NumeratorHigh,
par->VCLK3Denominator, par->VCLK3Denominator, f_best_diff >> 12);
f_best_diff >> 12);
#endif #endif
} }
...@@ -896,10 +247,9 @@ static void neoCalcVCLK (const struct neofb_info *info, struct neofb_par *par, l ...@@ -896,10 +247,9 @@ static void neoCalcVCLK (const struct neofb_info *info, struct neofb_par *par, l
* Return FALSE on failure. * Return FALSE on failure.
*/ */
static int vgaHWInit (const struct fb_var_screeninfo *var, static int vgaHWInit(const struct fb_var_screeninfo *var,
const struct neofb_info *info, const struct fb_info *info,
struct neofb_par *par, struct neofb_par *par, struct xtimings *timings)
struct xtimings *timings)
{ {
par->MiscOutReg = 0x23; par->MiscOutReg = 0x23;
...@@ -933,8 +283,7 @@ static int vgaHWInit (const struct fb_var_screeninfo *var, ...@@ -933,8 +283,7 @@ static int vgaHWInit (const struct fb_var_screeninfo *var,
| (((timings->VDisplay - 1) & 0x100) >> 7) | (((timings->VDisplay - 1) & 0x100) >> 7)
| ((timings->VSyncStart & 0x100) >> 6) | ((timings->VSyncStart & 0x100) >> 6)
| (((timings->VDisplay - 1) & 0x100) >> 5) | (((timings->VDisplay - 1) & 0x100) >> 5)
| 0x10 | 0x10 | (((timings->VTotal - 2) & 0x200) >> 4)
| (((timings->VTotal - 2) & 0x200) >> 4)
| (((timings->VDisplay - 1) & 0x200) >> 3) | (((timings->VDisplay - 1) & 0x200) >> 3)
| ((timings->VSyncStart & 0x200) >> 2); | ((timings->VSyncStart & 0x200) >> 2);
par->CRTC[8] = 0x00; par->CRTC[8] = 0x00;
...@@ -979,47 +328,216 @@ static int vgaHWInit (const struct fb_var_screeninfo *var, ...@@ -979,47 +328,216 @@ static int vgaHWInit (const struct fb_var_screeninfo *var,
par->Graphics[8] = 0xFF; par->Graphics[8] = 0xFF;
par->Attribute[0] = 0x00; /* standard colormap translation */ par->Attribute[0] = 0x00; /* standard colormap translation */
par->Attribute[1] = 0x01; par->Attribute[1] = 0x01;
par->Attribute[2] = 0x02; par->Attribute[2] = 0x02;
par->Attribute[3] = 0x03; par->Attribute[3] = 0x03;
par->Attribute[4] = 0x04; par->Attribute[4] = 0x04;
par->Attribute[5] = 0x05; par->Attribute[5] = 0x05;
par->Attribute[6] = 0x06; par->Attribute[6] = 0x06;
par->Attribute[7] = 0x07; par->Attribute[7] = 0x07;
par->Attribute[8] = 0x08; par->Attribute[8] = 0x08;
par->Attribute[9] = 0x09; par->Attribute[9] = 0x09;
par->Attribute[10] = 0x0A; par->Attribute[10] = 0x0A;
par->Attribute[11] = 0x0B; par->Attribute[11] = 0x0B;
par->Attribute[12] = 0x0C; par->Attribute[12] = 0x0C;
par->Attribute[13] = 0x0D; par->Attribute[13] = 0x0D;
par->Attribute[14] = 0x0E; par->Attribute[14] = 0x0E;
par->Attribute[15] = 0x0F; par->Attribute[15] = 0x0F;
par->Attribute[16] = 0x41; par->Attribute[16] = 0x41;
par->Attribute[17] = 0xFF; par->Attribute[17] = 0xFF;
par->Attribute[18] = 0x0F; par->Attribute[18] = 0x0F;
par->Attribute[19] = 0x00; par->Attribute[19] = 0x00;
par->Attribute[20] = 0x00; par->Attribute[20] = 0x00;
return 0;
}
static void vgaHWLock(void)
{
/* Protect CRTC[0-7] */
VGAwCR(0x11, VGArCR(0x11) | 0x80);
}
static void vgaHWUnlock(void)
{
/* Unprotect CRTC[0-7] */
VGAwCR(0x11, VGArCR(0x11) & ~0x80);
}
static void neoLock(void)
{
VGAwGR(0x09, 0x00);
vgaHWLock();
}
static void neoUnlock(void)
{
vgaHWUnlock();
VGAwGR(0x09, 0x26);
}
/*
* vgaHWSeqReset
* perform a sequencer reset.
*/
void vgaHWSeqReset(int start)
{
if (start)
VGAwSEQ(0x00, 0x01); /* Synchronous Reset */
else
VGAwSEQ(0x00, 0x03); /* End Reset */
}
void vgaHWProtect(int on)
{
unsigned char tmp;
if (on) {
/*
* Turn off screen and disable sequencer.
*/
tmp = VGArSEQ(0x01);
vgaHWSeqReset(1); /* start synchronous reset */
VGAwSEQ(0x01, tmp | 0x20); /* disable the display */
VGAenablePalette();
} else {
/*
* Reenable sequencer, then turn on screen.
*/
tmp = VGArSEQ(0x01);
VGAwSEQ(0x01, tmp & ~0x20); /* reenable display */
vgaHWSeqReset(0); /* clear synchronousreset */
VGAdisablePalette();
}
}
static void vgaHWRestore(const struct fb_info *info,
const struct neofb_par *par)
{
int i;
VGAwMISC(par->MiscOutReg);
for (i = 1; i < 5; i++)
VGAwSEQ(i, par->Sequencer[i]);
/* Ensure CRTC registers 0-7 are unlocked by clearing bit 7 or CRTC[17] */
VGAwCR(17, par->CRTC[17] & ~0x80);
for (i = 0; i < 25; i++)
VGAwCR(i, par->CRTC[i]);
for (i = 0; i < 9; i++)
VGAwGR(i, par->Graphics[i]);
VGAenablePalette();
for (i = 0; i < 21; i++)
VGAwATTR(i, par->Attribute[i]);
VGAdisablePalette();
}
/* -------------------- Hardware specific routines ------------------------- */
/*
* Hardware Acceleration for Neo2200+
*/
static inline void neo2200_wait_idle(struct neofb_par *par)
{
int waitcycles;
while (par->neo2200->bltStat & 1)
waitcycles++;
}
static inline void neo2200_wait_fifo(struct neofb_par *par,
int requested_fifo_space)
{
// ndev->neo.waitfifo_calls++;
// ndev->neo.waitfifo_sum += requested_fifo_space;
/* FIXME: does not work
if (neo_fifo_space < requested_fifo_space)
{
neo_fifo_waitcycles++;
while (1)
{
neo_fifo_space = (neo2200->bltStat >> 8);
if (neo_fifo_space >= requested_fifo_space)
break;
}
}
else
{
neo_fifo_cache_hits++;
}
neo_fifo_space -= requested_fifo_space;
*/
neo2200_wait_idle(par);
}
static inline void neo2200_accel_init(struct fb_info *fb,
struct fb_var_screeninfo *var)
{
struct neofb_par *par = (struct neofb_par *) fb->par;
Neo2200 *neo2200 = par->neo2200;
u32 bltMod, pitch;
neo2200_wait_idle(par);
switch (var->bits_per_pixel) {
case 8:
bltMod = NEO_MODE1_DEPTH8;
pitch = var->xres_virtual;
break;
case 15:
case 16:
bltMod = NEO_MODE1_DEPTH16;
pitch = var->xres_virtual * 2;
break;
default:
printk(KERN_ERR
"neofb: neo2200_accel_init: unexpected bits per pixel!\n");
return;
}
return 0; neo2200->bltStat = bltMod << 16;
neo2200->pitch = (pitch << 16) | pitch;
} }
static int neofb_decode_var (struct fb_var_screeninfo *var, /* --------------------------------------------------------------------- */
const struct neofb_info *info,
struct neofb_par *par) static int
neofb_check_var(struct fb_var_screeninfo *var, struct fb_info *info)
{ {
struct neofb_par *par = (struct neofb_par *) info->par;
unsigned int pixclock = var->pixclock;
struct xtimings timings; struct xtimings timings;
int lcd_stretch;
int hoffset, voffset;
int memlen, vramlen; int memlen, vramlen;
int mode_ok = 0; int mode_ok = 0;
unsigned int pixclock = var->pixclock;
DBG("neofb_decode_var"); DBG("neofb_check_var");
if (!pixclock) pixclock = 10000; /* 10ns = 100MHz */ if (!pixclock)
pixclock = 10000; /* 10ns = 100MHz */
timings.pixclock = 1000000000 / pixclock; timings.pixclock = 1000000000 / pixclock;
if (timings.pixclock < 1) timings.pixclock = 1; if (timings.pixclock < 1)
timings.pixclock = 1;
if (timings.pixclock > par->maxClock)
return -EINVAL;
timings.dblscan = var->vmode & FB_VMODE_DOUBLE; timings.dblscan = var->vmode & FB_VMODE_DOUBLE;
timings.interlaced = var->vmode & FB_VMODE_INTERLACED; timings.interlaced = var->vmode & FB_VMODE_INTERLACED;
timings.HDisplay = var->xres; timings.HDisplay = var->xres;
...@@ -1032,24 +550,18 @@ static int neofb_decode_var (struct fb_var_screeninfo *var, ...@@ -1032,24 +550,18 @@ static int neofb_decode_var (struct fb_var_screeninfo *var,
timings.VTotal = timings.VSyncEnd + var->upper_margin; timings.VTotal = timings.VSyncEnd + var->upper_margin;
timings.sync = var->sync; timings.sync = var->sync;
if (timings.pixclock > info->maxClock)
return -EINVAL;
/* Is the mode larger than the LCD panel? */ /* Is the mode larger than the LCD panel? */
if ((var->xres > info->NeoPanelWidth) || if ((var->xres > par->NeoPanelWidth) ||
(var->yres > info->NeoPanelHeight)) (var->yres > par->NeoPanelHeight)) {
{ printk(KERN_INFO
printk (KERN_INFO "Mode (%dx%d) larger than the LCD panel (%dx%d)\n", "Mode (%dx%d) larger than the LCD panel (%dx%d)\n",
var->xres, var->xres, var->yres, par->NeoPanelWidth,
var->yres, par->NeoPanelHeight);
info->NeoPanelWidth,
info->NeoPanelHeight);
return -EINVAL; return -EINVAL;
} }
/* Is the mode one of the acceptable sizes? */ /* Is the mode one of the acceptable sizes? */
switch (var->xres) switch (var->xres) {
{
case 1280: case 1280:
if (var->yres == 1024) if (var->yres == 1024)
mode_ok = 1; mode_ok = 1;
...@@ -1068,58 +580,87 @@ static int neofb_decode_var (struct fb_var_screeninfo *var, ...@@ -1068,58 +580,87 @@ static int neofb_decode_var (struct fb_var_screeninfo *var,
break; break;
} }
if (!mode_ok) if (!mode_ok) {
{ printk(KERN_INFO
printk (KERN_INFO "Mode (%dx%d) won't display properly on LCD\n", "Mode (%dx%d) won't display properly on LCD\n",
var->xres, var->yres); var->xres, var->yres);
return -EINVAL; return -EINVAL;
} }
var->red.msb_right = 0;
var->green.msb_right = 0;
var->blue.msb_right = 0;
switch (var->bits_per_pixel) switch (var->bits_per_pixel) {
{ case 8: /* PSEUDOCOLOUR, 256 */
#ifdef FBCON_HAS_CFB8 var->transp.offset = 0;
case 8: var->transp.length = 0;
var->red.offset = 0;
var->red.length = 8;
var->green.offset = 0;
var->green.length = 8;
var->blue.offset = 0;
var->blue.length = 8;
break; break;
#endif
#ifdef FBCON_HAS_CFB16 case 16: /* DIRECTCOLOUR, 64k */
case 16: var->transp.offset = 0;
var->transp.length = 0;
var->red.offset = 11;
var->red.length = 5;
var->green.offset = 5;
var->green.length = 6;
var->blue.offset = 0;
var->blue.length = 5;
break; break;
#endif
#ifdef FBCON_HAS_CFB24 case 24: /* TRUECOLOUR, 16m */
case 24: var->transp.offset = 0;
var->transp.length = 0;
var->red.offset = 16;
var->red.length = 8;
var->green.offset = 8;
var->green.length = 8;
var->blue.offset = 0;
break; break;
#endif
#ifdef NO_32BIT_SUPPORT_YET #ifdef NO_32BIT_SUPPORT_YET
# ifdef FBCON_HAS_CFB32 case 32: /* TRUECOLOUR, 16m */
case 32: var->transp.offset = 24;
var->transp.length = 8;
var->red.offset = 16;
var->red.length = 8;
var->green.offset = 8;
var->green.length = 8;
var->blue.offset = 0;
var->blue.length = 8;
break; break;
# endif
#endif #endif
default: default:
printk(KERN_WARNING "neofb: no support for %dbpp\n",
var->bits_per_pixel);
return -EINVAL; return -EINVAL;
} }
par->depth = var->bits_per_pixel; vramlen = info->fix.smem_len;
if (vramlen > 4 * 1024 * 1024)
vramlen = info->video.len; vramlen = 4 * 1024 * 1024;
if (vramlen > 4*1024*1024)
vramlen = 4*1024*1024;
if (var->yres_virtual < var->yres) if (var->yres_virtual < var->yres)
var->yres_virtual = var->yres; var->yres_virtual = var->yres;
if (var->xres_virtual < var->xres) if (var->xres_virtual < var->xres)
var->xres_virtual = var->xres; var->xres_virtual = var->xres;
memlen = var->xres_virtual * var->bits_per_pixel * var->yres_virtual / 8; memlen =
if (memlen > vramlen) var->xres_virtual * var->bits_per_pixel * var->yres_virtual /
{ 8;
var->yres_virtual = vramlen * 8 / (var->xres_virtual * var->bits_per_pixel); if (memlen > vramlen) {
memlen = var->xres_virtual * var->bits_per_pixel * var->yres_virtual / 8; var->yres_virtual =
vramlen * 8 / (var->xres_virtual *
var->bits_per_pixel);
memlen =
var->xres_virtual * var->bits_per_pixel *
var->yres_virtual / 8;
} }
/* we must round yres/xres down, we already rounded y/xres_virtual up /* we must round yres/xres down, we already rounded y/xres_virtual up
...@@ -1133,13 +674,48 @@ static int neofb_decode_var (struct fb_var_screeninfo *var, ...@@ -1133,13 +674,48 @@ static int neofb_decode_var (struct fb_var_screeninfo *var,
if (var->yoffset + var->yres > var->yres_virtual) if (var->yoffset + var->yres > var->yres_virtual)
var->yoffset = var->yres_virtual - var->yres; var->yoffset = var->yres_virtual - var->yres;
if (var->bits_per_pixel >= 24 || !par->neo2200)
var->accel_flags &= ~FB_ACCELF_TEXT;
return 0;
}
static int neofb_set_par(struct fb_info *info)
{
struct neofb_par *par = (struct neofb_par *) info->par;
struct xtimings timings;
unsigned char temp;
int i, clock_hi = 0;
int lcd_stretch;
int hoffset, voffset;
DBG("neofb_set_par");
neoUnlock();
vgaHWProtect(1); /* Blank the screen */
timings.dblscan = info->var.vmode & FB_VMODE_DOUBLE;
timings.interlaced = info->var.vmode & FB_VMODE_INTERLACED;
timings.HDisplay = info->var.xres;
timings.HSyncStart = timings.HDisplay + info->var.right_margin;
timings.HSyncEnd = timings.HSyncStart + info->var.hsync_len;
timings.HTotal = timings.HSyncEnd + info->var.left_margin;
timings.VDisplay = info->var.yres;
timings.VSyncStart = timings.VDisplay + info->var.lower_margin;
timings.VSyncEnd = timings.VSyncStart + info->var.vsync_len;
timings.VTotal = timings.VSyncEnd + info->var.upper_margin;
timings.sync = info->var.sync;
timings.pixclock = PICOS2KHZ(info->var.pixclock);
if (timings.pixclock < 1)
timings.pixclock = 1;
/* /*
* This will allocate the datastructure and initialize all of the * This will allocate the datastructure and initialize all of the
* generic VGA registers. * generic VGA registers.
*/ */
if (vgaHWInit (var, info, par, &timings)) if (vgaHWInit(&info->var, info, par, &timings))
return -EINVAL; return -EINVAL;
/* /*
...@@ -1148,27 +724,26 @@ static int neofb_decode_var (struct fb_var_screeninfo *var, ...@@ -1148,27 +724,26 @@ static int neofb_decode_var (struct fb_var_screeninfo *var,
*/ */
par->Attribute[16] = 0x01; par->Attribute[16] = 0x01;
switch (var->bits_per_pixel) switch (info->var.bits_per_pixel) {
{
case 8: case 8:
par->CRTC[0x13] = var->xres_virtual >> 3; par->CRTC[0x13] = info->var.xres_virtual >> 3;
par->ExtCRTOffset = var->xres_virtual >> 11; par->ExtCRTOffset = info->var.xres_virtual >> 11;
par->ExtColorModeSelect = 0x11; par->ExtColorModeSelect = 0x11;
break; break;
case 16: case 16:
par->CRTC[0x13] = var->xres_virtual >> 2; par->CRTC[0x13] = info->var.xres_virtual >> 2;
par->ExtCRTOffset = var->xres_virtual >> 10; par->ExtCRTOffset = info->var.xres_virtual >> 10;
par->ExtColorModeSelect = 0x13; par->ExtColorModeSelect = 0x13;
break; break;
case 24: case 24:
par->CRTC[0x13] = (var->xres_virtual * 3) >> 3; par->CRTC[0x13] = (info->var.xres_virtual * 3) >> 3;
par->ExtCRTOffset = (var->xres_virtual * 3) >> 11; par->ExtCRTOffset = (info->var.xres_virtual * 3) >> 11;
par->ExtColorModeSelect = 0x14; par->ExtColorModeSelect = 0x14;
break; break;
#ifdef NO_32BIT_SUPPORT_YET #ifdef NO_32BIT_SUPPORT_YET
case 32: /* FIXME: guessed values */ case 32: /* FIXME: guessed values */
par->CRTC[0x13] = var->xres_virtual >> 1; par->CRTC[0x13] = info->var.xres_virtual >> 1;
par->ExtCRTOffset = var->xres_virtual >> 9; par->ExtCRTOffset = info->var.xres_virtual >> 9;
par->ExtColorModeSelect = 0x15; par->ExtColorModeSelect = 0x15;
break; break;
#endif #endif
...@@ -1179,13 +754,13 @@ static int neofb_decode_var (struct fb_var_screeninfo *var, ...@@ -1179,13 +754,13 @@ static int neofb_decode_var (struct fb_var_screeninfo *var,
par->ExtCRTDispAddr = 0x10; par->ExtCRTDispAddr = 0x10;
/* Vertical Extension */ /* Vertical Extension */
par->VerticalExt = (((timings.VTotal -2) & 0x400) >> 10 ) par->VerticalExt = (((timings.VTotal - 2) & 0x400) >> 10)
| (((timings.VDisplay -1) & 0x400) >> 9 ) | (((timings.VDisplay - 1) & 0x400) >> 9)
| (((timings.VSyncStart) & 0x400) >> 8 ) | (((timings.VSyncStart) & 0x400) >> 8)
| (((timings.VSyncStart) & 0x400) >> 7 ); | (((timings.VSyncStart) & 0x400) >> 7);
/* Fast write bursts on unless disabled. */ /* Fast write bursts on unless disabled. */
if (info->pci_burst) if (par->pci_burst)
par->SysIfaceCntl1 = 0x30; par->SysIfaceCntl1 = 0x30;
else else
par->SysIfaceCntl1 = 0x00; par->SysIfaceCntl1 = 0x00;
...@@ -1194,9 +769,9 @@ static int neofb_decode_var (struct fb_var_screeninfo *var, ...@@ -1194,9 +769,9 @@ static int neofb_decode_var (struct fb_var_screeninfo *var,
/* Enable any user specified display devices. */ /* Enable any user specified display devices. */
par->PanelDispCntlReg1 = 0x00; par->PanelDispCntlReg1 = 0x00;
if (info->internal_display) if (par->internal_display)
par->PanelDispCntlReg1 |= 0x02; par->PanelDispCntlReg1 |= 0x02;
if (info->external_display) if (par->external_display)
par->PanelDispCntlReg1 |= 0x01; par->PanelDispCntlReg1 |= 0x01;
/* If the user did not specify any display devices, then... */ /* If the user did not specify any display devices, then... */
...@@ -1206,8 +781,7 @@ static int neofb_decode_var (struct fb_var_screeninfo *var, ...@@ -1206,8 +781,7 @@ static int neofb_decode_var (struct fb_var_screeninfo *var,
} }
/* If we are using a fixed mode, then tell the chip we are. */ /* If we are using a fixed mode, then tell the chip we are. */
switch (var->xres) switch (info->var.xres) {
{
case 1280: case 1280:
par->PanelDispCntlReg1 |= 0x60; par->PanelDispCntlReg1 |= 0x60;
break; break;
...@@ -1223,8 +797,7 @@ static int neofb_decode_var (struct fb_var_screeninfo *var, ...@@ -1223,8 +797,7 @@ static int neofb_decode_var (struct fb_var_screeninfo *var,
} }
/* Setup shadow register locking. */ /* Setup shadow register locking. */
switch (par->PanelDispCntlReg1 & 0x03) switch (par->PanelDispCntlReg1 & 0x03) {
{
case 0x01: /* External CRT only mode: */ case 0x01: /* External CRT only mode: */
par->GeneralLockReg = 0x00; par->GeneralLockReg = 0x00;
/* We need to program the VCLK for external display only mode. */ /* We need to program the VCLK for external display only mode. */
...@@ -1247,12 +820,9 @@ static int neofb_decode_var (struct fb_var_screeninfo *var, ...@@ -1247,12 +820,9 @@ static int neofb_decode_var (struct fb_var_screeninfo *var,
par->PanelDispCntlReg2 = 0x00; par->PanelDispCntlReg2 = 0x00;
par->PanelDispCntlReg3 = 0x00; par->PanelDispCntlReg3 = 0x00;
if (info->lcd_stretch && if (par->lcd_stretch && (par->PanelDispCntlReg1 == 0x02) && /* LCD only */
(par->PanelDispCntlReg1 == 0x02) && /* LCD only */ (info->var.xres != par->NeoPanelWidth)) {
(var->xres != info->NeoPanelWidth)) switch (info->var.xres) {
{
switch (var->xres)
{
case 320: /* Needs testing. KEM -- 24 May 98 */ case 320: /* Needs testing. KEM -- 24 May 98 */
case 400: /* Needs testing. KEM -- 24 May 98 */ case 400: /* Needs testing. KEM -- 24 May 98 */
case 640: case 640:
...@@ -1265,8 +835,7 @@ static int neofb_decode_var (struct fb_var_screeninfo *var, ...@@ -1265,8 +835,7 @@ static int neofb_decode_var (struct fb_var_screeninfo *var,
lcd_stretch = 0; lcd_stretch = 0;
/* No stretching in these modes. */ /* No stretching in these modes. */
} }
} } else
else
lcd_stretch = 0; lcd_stretch = 0;
/* /*
...@@ -1285,35 +854,31 @@ static int neofb_decode_var (struct fb_var_screeninfo *var, ...@@ -1285,35 +854,31 @@ static int neofb_decode_var (struct fb_var_screeninfo *var,
par->PanelHorizCenterReg5 = 0x00; par->PanelHorizCenterReg5 = 0x00;
if (par->PanelDispCntlReg1 & 0x02) if (par->PanelDispCntlReg1 & 0x02) {
{ if (info->var.xres == par->NeoPanelWidth) {
if (var->xres == info->NeoPanelWidth)
{
/* /*
* No centering required when the requested display width * No centering required when the requested display width
* equals the panel width. * equals the panel width.
*/ */
} } else {
else
{
par->PanelDispCntlReg2 |= 0x01; par->PanelDispCntlReg2 |= 0x01;
par->PanelDispCntlReg3 |= 0x10; par->PanelDispCntlReg3 |= 0x10;
/* Calculate the horizontal and vertical offsets. */ /* Calculate the horizontal and vertical offsets. */
if (!lcd_stretch) if (!lcd_stretch) {
{ hoffset =
hoffset = ((info->NeoPanelWidth - var->xres) >> 4) - 1; ((par->NeoPanelWidth -
voffset = ((info->NeoPanelHeight - var->yres) >> 1) - 2; info->var.xres) >> 4) - 1;
} voffset =
else ((par->NeoPanelHeight -
{ info->var.yres) >> 1) - 2;
} else {
/* Stretched modes cannot be centered. */ /* Stretched modes cannot be centered. */
hoffset = 0; hoffset = 0;
voffset = 0; voffset = 0;
} }
switch (var->xres) switch (info->var.xres) {
{
case 320: /* Needs testing. KEM -- 24 May 98 */ case 320: /* Needs testing. KEM -- 24 May 98 */
par->PanelHorizCenterReg3 = hoffset; par->PanelHorizCenterReg3 = hoffset;
par->PanelVertCenterReg2 = voffset; par->PanelVertCenterReg2 = voffset;
...@@ -1342,210 +907,268 @@ static int neofb_decode_var (struct fb_var_screeninfo *var, ...@@ -1342,210 +907,268 @@ static int neofb_decode_var (struct fb_var_screeninfo *var,
} }
} }
par->biosMode = neoFindMode (var->xres, var->yres, var->bits_per_pixel); par->biosMode =
neoFindMode(info->var.xres, info->var.yres,
info->var.bits_per_pixel);
/* /*
* Calculate the VCLK that most closely matches the requested dot * Calculate the VCLK that most closely matches the requested dot
* clock. * clock.
*/ */
neoCalcVCLK (info, par, timings.pixclock); neoCalcVCLK(info, par, timings.pixclock);
/* Since we program the clocks ourselves, always use VCLK3. */ /* Since we program the clocks ourselves, always use VCLK3. */
par->MiscOutReg |= 0x0C; par->MiscOutReg |= 0x0C;
return 0; /* linear colormap for non palettized modes */
} switch (info->var.bits_per_pixel) {
case 8:
/* PseudoColor, 256 */
info->fix.visual = FB_VISUAL_PSEUDOCOLOR;
break;
case 16:
/* DirectColor, 64k */
info->fix.visual = FB_VISUAL_DIRECTCOLOR;
static int neofb_set_var (struct fb_var_screeninfo *var, int con, for (i = 0; i < 64; i++) {
struct fb_info *fb) outb(i, 0x3c8);
{
struct neofb_info *info = (struct neofb_info *)fb; outb(i << 1, 0x3c9);
struct display *display; outb(i, 0x3c9);
struct neofb_par par; outb(i << 1, 0x3c9);
int err, chgvar = 0; }
break;
case 24:
#ifdef NO_32BIT_SUPPORT_YET
case 32:
#endif
/* TrueColor, 16m */
info->fix.visual = FB_VISUAL_TRUECOLOR;
DBG("neofb_set_var"); for (i = 0; i < 256; i++) {
outb(i, 0x3c8);
err = neofb_decode_var (var, info, &par); outb(i, 0x3c9);
if (err) outb(i, 0x3c9);
return err; outb(i, 0x3c9);
}
break;
}
/* alread unlocked above */
/* BOGUS VGAwGR (0x09, 0x26); */
/* don't know what this is, but it's 0 from bootup anyway */
VGAwGR(0x15, 0x00);
/* was set to 0x01 by my bios in text and vesa modes */
VGAwGR(0x0A, par->GeneralLockReg);
/*
* The color mode needs to be set before calling vgaHWRestore
* to ensure the DAC is initialized properly.
*
* NOTE: Make sure we don't change bits make sure we don't change
* any reserved bits.
*/
temp = VGArGR(0x90);
switch (info->fix.accel) {
case FB_ACCEL_NEOMAGIC_NM2070:
temp &= 0xF0; /* Save bits 7:4 */
temp |= (par->ExtColorModeSelect & ~0xF0);
break;
case FB_ACCEL_NEOMAGIC_NM2090:
case FB_ACCEL_NEOMAGIC_NM2093:
case FB_ACCEL_NEOMAGIC_NM2097:
case FB_ACCEL_NEOMAGIC_NM2160:
case FB_ACCEL_NEOMAGIC_NM2200:
case FB_ACCEL_NEOMAGIC_NM2230:
case FB_ACCEL_NEOMAGIC_NM2360:
case FB_ACCEL_NEOMAGIC_NM2380:
temp &= 0x70; /* Save bits 6:4 */
temp |= (par->ExtColorModeSelect & ~0x70);
break;
}
VGAwGR(0x90, temp);
/*
* In some rare cases a lockup might occur if we don't delay
* here. (Reported by Miles Lane)
*/
//mdelay(200);
/*
* Disable horizontal and vertical graphics and text expansions so
* that vgaHWRestore works properly.
*/
temp = VGArGR(0x25);
temp &= 0x39;
VGAwGR(0x25, temp);
/*
* Sleep for 200ms to make sure that the two operations above have
* had time to take effect.
*/
mdelay(200);
/*
* This function handles restoring the generic VGA registers. */
vgaHWRestore(info, par);
VGAwGR(0x0E, par->ExtCRTDispAddr);
VGAwGR(0x0F, par->ExtCRTOffset);
temp = VGArGR(0x10);
temp &= 0x0F; /* Save bits 3:0 */
temp |= (par->SysIfaceCntl1 & ~0x0F); /* VESA Bios sets bit 1! */
VGAwGR(0x10, temp);
VGAwGR(0x11, par->SysIfaceCntl2);
VGAwGR(0x15, 0 /*par->SingleAddrPage */ );
VGAwGR(0x16, 0 /*par->DualAddrPage */ );
temp = VGArGR(0x20);
switch (info->fix.accel) {
case FB_ACCEL_NEOMAGIC_NM2070:
temp &= 0xFC; /* Save bits 7:2 */
temp |= (par->PanelDispCntlReg1 & ~0xFC);
break;
case FB_ACCEL_NEOMAGIC_NM2090:
case FB_ACCEL_NEOMAGIC_NM2093:
case FB_ACCEL_NEOMAGIC_NM2097:
case FB_ACCEL_NEOMAGIC_NM2160:
temp &= 0xDC; /* Save bits 7:6,4:2 */
temp |= (par->PanelDispCntlReg1 & ~0xDC);
break;
case FB_ACCEL_NEOMAGIC_NM2200:
case FB_ACCEL_NEOMAGIC_NM2230:
case FB_ACCEL_NEOMAGIC_NM2360:
case FB_ACCEL_NEOMAGIC_NM2380:
temp &= 0x98; /* Save bits 7,4:3 */
temp |= (par->PanelDispCntlReg1 & ~0x98);
break;
}
VGAwGR(0x20, temp);
temp = VGArGR(0x25);
temp &= 0x38; /* Save bits 5:3 */
temp |= (par->PanelDispCntlReg2 & ~0x38);
VGAwGR(0x25, temp);
if (info->fix.accel != FB_ACCEL_NEOMAGIC_NM2070) {
temp = VGArGR(0x30);
temp &= 0xEF; /* Save bits 7:5 and bits 3:0 */
temp |= (par->PanelDispCntlReg3 & ~0xEF);
VGAwGR(0x30, temp);
}
if (var->activate & FB_ACTIVATE_TEST) VGAwGR(0x28, par->PanelVertCenterReg1);
return 0; VGAwGR(0x29, par->PanelVertCenterReg2);
VGAwGR(0x2a, par->PanelVertCenterReg3);
if (con < 0) if (info->fix.accel != FB_ACCEL_NEOMAGIC_NM2070) {
{ VGAwGR(0x32, par->PanelVertCenterReg4);
display = fb->disp; VGAwGR(0x33, par->PanelHorizCenterReg1);
chgvar = 0; VGAwGR(0x34, par->PanelHorizCenterReg2);
} VGAwGR(0x35, par->PanelHorizCenterReg3);
else
{
display = fb_display + con;
if (fb->var.xres != var->xres)
chgvar = 1;
if (fb->var.yres != var->yres)
chgvar = 1;
if (fb->var.xres_virtual != var->xres_virtual)
chgvar = 1;
if (fb->var.yres_virtual != var->yres_virtual)
chgvar = 1;
if (fb->var.bits_per_pixel != var->bits_per_pixel)
chgvar = 1;
} }
if (!info->neo2200) if (info->fix.accel == FB_ACCEL_NEOMAGIC_NM2160)
var->accel_flags &= ~FB_ACCELF_TEXT; VGAwGR(0x36, par->PanelHorizCenterReg4);
var->red.msb_right = 0;
var->green.msb_right = 0;
var->blue.msb_right = 0;
switch (var->bits_per_pixel) if (info->fix.accel == FB_ACCEL_NEOMAGIC_NM2200 ||
{ info->fix.accel == FB_ACCEL_NEOMAGIC_NM2230 ||
#ifdef FBCON_HAS_CFB8 info->fix.accel == FB_ACCEL_NEOMAGIC_NM2360 ||
case 8: /* PSEUDOCOLOUR, 256 */ info->fix.accel == FB_ACCEL_NEOMAGIC_NM2380) {
var->transp.offset = 0; VGAwGR(0x36, par->PanelHorizCenterReg4);
var->transp.length = 0; VGAwGR(0x37, par->PanelVertCenterReg5);
var->red.offset = 0; VGAwGR(0x38, par->PanelHorizCenterReg5);
var->red.length = 8;
var->green.offset = 0;
var->green.length = 8;
var->blue.offset = 0;
var->blue.length = 8;
fb->fix.visual = FB_VISUAL_PSEUDOCOLOR; clock_hi = 1;
info->dispsw = &fbcon_cfb8; }
display->dispsw_data = NULL;
display->next_line = var->xres_virtual;
break;
#endif
#ifdef FBCON_HAS_CFB16 /* Program VCLK3 if needed. */
case 16: /* DIRECTCOLOUR, 64k */ if (par->ProgramVCLK && ((VGArGR(0x9B) != par->VCLK3NumeratorLow)
var->transp.offset = 0; || (VGArGR(0x9F) != par->VCLK3Denominator)
var->transp.length = 0; || (clock_hi && ((VGArGR(0x8F) & ~0x0f)
var->red.offset = 11; != (par->
var->red.length = 5; VCLK3NumeratorHigh &
var->green.offset = 5; ~0x0F))))) {
var->green.length = 6; VGAwGR(0x9B, par->VCLK3NumeratorLow);
var->blue.offset = 0; if (clock_hi) {
var->blue.length = 5; temp = VGArGR(0x8F);
temp &= 0x0F; /* Save bits 3:0 */
temp |= (par->VCLK3NumeratorHigh & ~0x0F);
VGAwGR(0x8F, temp);
}
VGAwGR(0x9F, par->VCLK3Denominator);
}
fb->fix.visual = FB_VISUAL_DIRECTCOLOR; if (par->biosMode)
info->dispsw = &fbcon_cfb16; VGAwCR(0x23, par->biosMode);
display->dispsw_data = fb->pseudo_palette;
display->next_line = var->xres_virtual * 2;
break;
#endif
#ifdef FBCON_HAS_CFB24 VGAwGR(0x93, 0xc0); /* Gives 5x faster framebuffer writes !!! */
case 24: /* TRUECOLOUR, 16m */
var->transp.offset = 0;
var->transp.length = 0;
var->red.offset = 16;
var->red.length = 8;
var->green.offset = 8;
var->green.length = 8;
var->blue.offset = 0;
var->blue.length = 8;
fb->fix.visual = FB_VISUAL_TRUECOLOR; /* Program vertical extension register */
info->dispsw = &fbcon_cfb24; if (info->fix.accel == FB_ACCEL_NEOMAGIC_NM2200 ||
display->dispsw_data = fb->pseudo_palette; info->fix.accel == FB_ACCEL_NEOMAGIC_NM2230 ||
display->next_line = var->xres_virtual * 3; info->fix.accel == FB_ACCEL_NEOMAGIC_NM2360 ||
info->fix.accel == FB_ACCEL_NEOMAGIC_NM2380) {
VGAwCR(0x70, par->VerticalExt);
}
var->accel_flags &= ~FB_ACCELF_TEXT;
break;
#endif
#ifdef NO_32BIT_SUPPORT_YET vgaHWProtect(0); /* Turn on screen */
# ifdef FBCON_HAS_CFB32
case 32: /* TRUECOLOUR, 16m */
var->transp.offset = 24;
var->transp.length = 8;
var->red.offset = 16;
var->red.length = 8;
var->green.offset = 8;
var->green.length = 8;
var->blue.offset = 0;
var->blue.length = 8;
fb->fix.visual = FB_VISUAL_TRUECOLOR; /* Calling this also locks offset registers required in update_start */
info->dispsw = &fbcon_cfb32; neoLock();
display->dispsw_data = fb->pseudo_palette;
display->next_line = var->xres_virtual * 4;
var->accel_flags &= ~FB_ACCELF_TEXT; info->fix.line_length =
break; info->var.xres_virtual * (info->var.bits_per_pixel >> 3);
# endif
#endif
default: if (info->var.accel_flags & FB_ACCELF_TEXT)
printk (KERN_WARNING "neofb: no support for %dbpp\n", var->bits_per_pixel); neo2200_accel_init(info, &info->var);
info->dispsw = &fbcon_dummy; return 0;
var->accel_flags &= ~FB_ACCELF_TEXT; }
break;
}
if (var->accel_flags & FB_ACCELF_TEXT) static void neofb_update_start(struct fb_info *info,
display->dispsw = &fbcon_neo2200_accel; struct fb_var_screeninfo *var)
else {
display->dispsw = info->dispsw; int oldExtCRTDispAddr;
int Base;
fb->fix.line_length = display->next_line; DBG("neofb_update_start");
display->line_length = fb->fix.line_length; Base = (var->yoffset * var->xres_virtual + var->xoffset) >> 2;
display->visual = fb->fix.visual; Base *= (var->bits_per_pixel + 7) / 8;
display->type = fb->fix.type;
display->type_aux = fb->fix.type_aux;
display->ypanstep = fb->fix.ypanstep;
display->ywrapstep = fb->fix.ywrapstep;
display->can_soft_blank = 1;
display->inverse = 0;
fb->var = *var; neoUnlock();
fb->var.activate &= ~FB_ACTIVATE_ALL;
/* /*
* Update the old var. The fbcon drivers still use this. * These are the generic starting address registers.
* Once they are using cfb->fb.var, this can be dropped.
* --rmk
*/ */
display->var = fb->var; VGAwCR(0x0C, (Base & 0x00FF00) >> 8);
VGAwCR(0x0D, (Base & 0x00FF));
/* /*
* If we are setting all the virtual consoles, also set the * Make sure we don't clobber some other bits that might already
* defaults used to create new consoles. * have been set. NOTE: NM2200 has a writable bit 3, but it shouldn't
* be needed.
*/ */
if (var->activate & FB_ACTIVATE_ALL) oldExtCRTDispAddr = VGArGR(0x0E);
fb->disp->var = fb->var; VGAwGR(0x0E, (((Base >> 16) & 0x0f) | (oldExtCRTDispAddr & 0xf0)));
if (chgvar && fb && fb->changevar)
fb->changevar (con);
if (con == info->fb.currcon)
{
if (chgvar || con < 0)
neofb_set_par (info, &par);
neofb_update_start (info, var);
fb_set_cmap (&fb->cmap, 1, fb);
if (var->accel_flags & FB_ACCELF_TEXT)
neo2200_accel_init (info, var);
}
return 0; neoLock();
} }
/* /*
* Pan or Wrap the Display * Pan or Wrap the Display
*/ */
static int neofb_pan_display (struct fb_var_screeninfo *var, int con, static int neofb_pan_display(struct fb_var_screeninfo *var, int con,
struct fb_info *fb) struct fb_info *fb)
{ {
struct neofb_info *info = (struct neofb_info *)fb; struct fb_info *info = (struct fb_info *) fb;
u_int y_bottom; u_int y_bottom;
y_bottom = var->yoffset; y_bottom = var->yoffset;
...@@ -1558,7 +1181,7 @@ static int neofb_pan_display (struct fb_var_screeninfo *var, int con, ...@@ -1558,7 +1181,7 @@ static int neofb_pan_display (struct fb_var_screeninfo *var, int con,
if (y_bottom > fb->var.yres_virtual) if (y_bottom > fb->var.yres_virtual)
return -EINVAL; return -EINVAL;
neofb_update_start (info, var); neofb_update_start(info, var);
fb->var.xoffset = var->xoffset; fb->var.xoffset = var->xoffset;
fb->var.yoffset = var->yoffset; fb->var.yoffset = var->yoffset;
...@@ -1571,71 +1194,54 @@ static int neofb_pan_display (struct fb_var_screeninfo *var, int con, ...@@ -1571,71 +1194,54 @@ static int neofb_pan_display (struct fb_var_screeninfo *var, int con,
return 0; return 0;
} }
static int neofb_setcolreg(u_int regno, u_int red, u_int green, u_int blue,
/* u_int transp, struct fb_info *fb)
* Update the `var' structure (called by fbcon.c)
*
* This call looks only at yoffset and the FB_VMODE_YWRAP flag in `var'.
* Since it's called by a kernel driver, no range checking is done.
*/
static int neofb_updatevar (int con, struct fb_info *fb)
{
struct neofb_info *info = (struct neofb_info *)fb;
neofb_update_start (info, &fb_display[con].var);
return 0;
}
static int neofb_switch (int con, struct fb_info *fb)
{ {
struct neofb_info *info = (struct neofb_info *)fb; if (regno >= NR_PALETTE)
struct display *disp; return -EINVAL;
struct fb_cmap *cmap;
if (info->fb.currcon >= 0) switch (fb->var.bits_per_pixel) {
{ case 8:
disp = fb_display + info->fb.currcon; outb(regno, 0x3c8);
/* outb(red >> 10, 0x3c9);
* Save the old colormap and video mode. outb(green >> 10, 0x3c9);
*/ outb(blue >> 10, 0x3c9);
disp->var = fb->var; break;
if (disp->cmap.len) case 16:
fb_copy_cmap(&fb->cmap, &disp->cmap, 0); if (regno < 16)
((u16 *) fb->pseudo_palette)[regno] =
((red & 0xf800)) | ((green & 0xfc00) >> 5) |
((blue & 0xf800) >> 11);
break;
case 24:
if (regno < 16)
((u32 *) fb->pseudo_palette)[regno] =
((red & 0xff00) << 8) | ((green & 0xff00)) |
((blue & 0xff00) >> 8);
break;
#ifdef NO_32BIT_SUPPORT_YET
case 32:
if (regno < 16)
((u32 *) fb->pseudo_palette)[regno] =
((transp & 0xff00) << 16) | ((red & 0xff00) <<
8) | ((green &
0xff00)) |
((blue & 0xff00) >> 8);
break;
#endif
default:
return 1;
} }
info->fb.currcon = con;
disp = fb_display + con;
/*
* Install the new colormap and change the video mode. By default,
* fbcon sets all the colormaps and video modes to the default
* values at bootup.
*
* Really, we want to set the colourmap size depending on the
* depth of the new video mode. For now, we leave it at its
* default 256 entry.
*/
if (disp->cmap.len)
cmap = &disp->cmap;
else
cmap = fb_default_cmap(1 << disp->var.bits_per_pixel);
fb_copy_cmap(cmap, &fb->cmap, 0);
disp->var.activate = FB_ACTIVATE_NOW;
neofb_set_var(&disp->var, con, fb);
return 0; return 0;
} }
/* /*
* (Un)Blank the display. * (Un)Blank the display.
*/ */
static int neofb_blank (int blank, struct fb_info *fb) static int neofb_blank(int blank, struct fb_info *fb)
{ {
// struct neofb_info *info = (struct neofb_info *)fb; // struct fb_info *info = (struct fb_info *)fb;
/* /*
* Blank the screen if blank_mode != 0, else unblank. If * Blank the screen if blank_mode != 0, else unblank. If
...@@ -1653,8 +1259,7 @@ static int neofb_blank (int blank, struct fb_info *fb) ...@@ -1653,8 +1259,7 @@ static int neofb_blank (int blank, struct fb_info *fb)
* run "setterm -powersave powerdown" to take advantage * run "setterm -powersave powerdown" to take advantage
*/ */
switch (blank) switch (blank) {
{
case 4: /* powerdown - both sync lines down */ case 4: /* powerdown - both sync lines down */
break; break;
case 3: /* hsync off */ case 3: /* hsync off */
...@@ -1669,16 +1274,132 @@ static int neofb_blank (int blank, struct fb_info *fb) ...@@ -1669,16 +1274,132 @@ static int neofb_blank (int blank, struct fb_info *fb)
return 0; return 0;
} }
static void
neo2200fb_fillrect(struct fb_info *info, struct fb_fillrect *rect)
{
struct neofb_par *par = (struct neofb_par *) info->par;
u_long dst, rop;
dst = rect->dx + rect->dy * info->var.xres_virtual;
rop = rect->rop ? 0x060000 : 0x0c0000;
neo2200_wait_fifo(par, 4);
/* set blt control */
par->neo2200->bltCntl = NEO_BC3_FIFO_EN |
NEO_BC0_SRC_IS_FG | NEO_BC3_SKIP_MAPPING |
// NEO_BC3_DST_XY_ADDR |
// NEO_BC3_SRC_XY_ADDR |
rop;
switch (info->var.bits_per_pixel) {
case 8:
par->neo2200->fgColor = rect->color;
break;
case 16:
par->neo2200->fgColor =
((u16 *) (info->pseudo_palette))[rect->color];
break;
}
par->neo2200->dstStart =
dst * ((info->var.bits_per_pixel + 7) / 8);
par->neo2200->xyExt =
(rect->height << 16) | (rect->width & 0xffff);
}
static void
neo2200fb_copyarea(struct fb_info *info, struct fb_copyarea *area)
{
struct neofb_par *par = (struct neofb_par *) info->par;
u_long src, dst, bltCntl;
bltCntl = NEO_BC3_FIFO_EN | NEO_BC3_SKIP_MAPPING | 0x0C0000;
if (area->sy < area->dy) {
area->sy += (area->height - 1);
area->dy += (area->height - 1);
bltCntl |= NEO_BC0_DST_Y_DEC | NEO_BC0_SRC_Y_DEC;
}
if (area->sx < area->dx) {
area->sx += (area->width - 1);
area->dx += (area->width - 1);
bltCntl |= NEO_BC0_X_DEC;
}
src =
area->sx * (info->var.bits_per_pixel >> 3) +
area->sy * info->fix.line_length;
dst =
area->dx * (info->var.bits_per_pixel >> 3) +
area->dy * info->fix.line_length;
neo2200_wait_fifo(par, 4);
/* set blt control */
par->neo2200->bltCntl = bltCntl;
par->neo2200->srcStart = src;
par->neo2200->dstStart = dst;
par->neo2200->xyExt =
(area->height << 16) | (area->width & 0xffff);
}
static void
neo2200fb_imageblit(struct fb_info *info, struct fb_image *image)
{
struct neofb_par *par = (struct neofb_par *) info->par;
neo2200_wait_idle(par);
switch (info->var.bits_per_pixel) {
case 8:
par->neo2200->fgColor = image->fg_color;
par->neo2200->bgColor = image->bg_color;
break;
case 16:
par->neo2200->fgColor =
((u16 *) (info->pseudo_palette))[image->fg_color];
par->neo2200->bgColor =
((u16 *) (info->pseudo_palette))[image->bg_color];
break;
}
par->neo2200->bltCntl = NEO_BC0_SYS_TO_VID |
NEO_BC0_SRC_MONO | NEO_BC3_SKIP_MAPPING |
// NEO_BC3_DST_XY_ADDR |
0x0c0000;
par->neo2200->srcStart = 0;
// par->neo2200->dstStart = (image->dy << 16) | (image->dx & 0xffff);
par->neo2200->dstStart =
((image->dx & 0xffff) * (info->var.bits_per_pixel >> 3) +
image->dy * info->fix.line_length);
par->neo2200->xyExt =
(image->height << 16) | (image->width & 0xffff);
memcpy(par->mmio_vbase + 0x100000, image->data,
(image->width * image->height) >> 3);
}
static struct fb_ops neofb_ops = { static struct fb_ops neofb_ops = {
owner: THIS_MODULE, owner: THIS_MODULE,
fb_set_var: neofb_set_var, fb_check_var: neofb_check_var,
fb_set_par: neofb_set_par,
fb_set_var: gen_set_var,
fb_get_fix: gen_get_fix,
fb_get_var: gen_get_var,
fb_get_cmap: gen_get_cmap,
fb_set_cmap: gen_set_cmap, fb_set_cmap: gen_set_cmap,
fb_setcolreg: neofb_setcolreg, fb_setcolreg: neofb_setcolreg,
fb_pan_display: neofb_pan_display, fb_pan_display: neofb_pan_display,
fb_blank: neofb_blank, fb_blank: neofb_blank,
fb_get_fix: gen_get_fix, fb_fillrect: cfb_fillrect,
fb_get_var: gen_get_var, fb_copyarea: cfb_copyarea,
fb_get_cmap: gen_get_cmap, fb_imageblit: cfb_imageblit,
}; };
/* --------------------------------------------------------------------- */ /* --------------------------------------------------------------------- */
...@@ -1697,7 +1418,6 @@ static struct fb_var_screeninfo __devinitdata neofb_var640x480x8 = { ...@@ -1697,7 +1418,6 @@ static struct fb_var_screeninfo __devinitdata neofb_var640x480x8 = {
lower_margin: 10, lower_margin: 10,
hsync_len: 96, hsync_len: 96,
vsync_len: 2, vsync_len: 2,
sync: 0,
vmode: FB_VMODE_NONINTERLACED vmode: FB_VMODE_NONINTERLACED
}; };
...@@ -1759,106 +1479,110 @@ static struct fb_var_screeninfo __devinitdata neofb_var1280x1024x8 = { ...@@ -1759,106 +1479,110 @@ static struct fb_var_screeninfo __devinitdata neofb_var1280x1024x8 = {
static struct fb_var_screeninfo *neofb_var = NULL; static struct fb_var_screeninfo *neofb_var = NULL;
static int __devinit neo_map_mmio(struct fb_info *info,
static int __devinit neo_map_mmio (struct neofb_info *info) struct pci_dev *dev)
{ {
struct neofb_par *par = (struct neofb_par *) info->par;
DBG("neo_map_mmio"); DBG("neo_map_mmio");
info->mmio.pbase = pci_resource_start (info->pcidev, 1); info->fix.mmio_start = pci_resource_start(dev, 1);
info->mmio.len = MMIO_SIZE; info->fix.mmio_len = MMIO_SIZE;
if (!request_mem_region (info->mmio.pbase, MMIO_SIZE, "memory mapped I/O")) if (!request_mem_region
{ (info->fix.mmio_start, MMIO_SIZE, "memory mapped I/O")) {
printk ("neofb: memory mapped IO in use\n"); printk("neofb: memory mapped IO in use\n");
return -EBUSY; return -EBUSY;
} }
info->mmio.vbase = ioremap (info->mmio.pbase, MMIO_SIZE); par->mmio_vbase = ioremap(info->fix.mmio_start, MMIO_SIZE);
if (!info->mmio.vbase) if (!par->mmio_vbase) {
{ printk("neofb: unable to map memory mapped IO\n");
printk ("neofb: unable to map memory mapped IO\n"); release_mem_region(info->fix.mmio_start,
release_mem_region (info->mmio.pbase, info->mmio.len); info->fix.mmio_len);
return -ENOMEM; return -ENOMEM;
} } else
else printk(KERN_INFO "neofb: mapped io at %p\n",
printk (KERN_INFO "neofb: mapped io at %p\n", info->mmio.vbase); par->mmio_vbase);
info->fb.fix.mmio_start = info->mmio.pbase;
info->fb.fix.mmio_len = info->mmio.len;
return 0; return 0;
} }
static void __devinit neo_unmap_mmio (struct neofb_info *info) static void __devinit neo_unmap_mmio(struct fb_info *info)
{ {
struct neofb_par *par = (struct neofb_par *) info->par;
DBG("neo_unmap_mmio"); DBG("neo_unmap_mmio");
if (info->mmio.vbase) if (par->mmio_vbase) {
{ iounmap(par->mmio_vbase);
iounmap (info->mmio.vbase); par->mmio_vbase = NULL;
info->mmio.vbase = NULL;
release_mem_region (info->mmio.pbase, info->mmio.len); release_mem_region(info->fix.mmio_start,
info->fix.mmio_len);
} }
} }
static int __devinit neo_map_video (struct neofb_info *info, int video_len) static int __devinit neo_map_video(struct fb_info *info,
struct pci_dev *dev, int video_len)
{ {
struct neofb_par *par = (struct neofb_par *) info->par;
DBG("neo_map_video"); DBG("neo_map_video");
info->video.pbase = pci_resource_start (info->pcidev, 0); info->fix.smem_start = pci_resource_start(dev, 0);
info->video.len = video_len; info->fix.smem_len = video_len;
if (!request_mem_region (info->video.pbase, info->video.len, "frame buffer")) if (!request_mem_region
{ (info->fix.smem_start, info->fix.smem_len, "frame buffer")) {
printk ("neofb: frame buffer in use\n"); printk("neofb: frame buffer in use\n");
return -EBUSY; return -EBUSY;
} }
info->video.vbase = ioremap (info->video.pbase, info->video.len); info->screen_base =
if (!info->video.vbase) ioremap(info->fix.smem_start, info->fix.smem_len);
{ if (!info->screen_base) {
printk ("neofb: unable to map screen memory\n"); printk("neofb: unable to map screen memory\n");
release_mem_region (info->video.pbase, info->video.len); release_mem_region(info->fix.smem_start,
info->fix.smem_len);
return -ENOMEM; return -ENOMEM;
} } else
else printk(KERN_INFO "neofb: mapped framebuffer at %p\n",
printk (KERN_INFO "neofb: mapped framebuffer at %p\n", info->video.vbase); info->screen_base);
info->fb.fix.smem_start = info->video.pbase;
info->fb.fix.smem_len = info->video.len;
info->fb.screen_base = info->video.vbase;
#ifdef CONFIG_MTRR #ifdef CONFIG_MTRR
info->video.mtrr = mtrr_add (info->video.pbase, pci_resource_len (info->pcidev, 0), MTRR_TYPE_WRCOMB, 1); par->mtrr =
mtrr_add(info->fix.smem_start, pci_resource_len(dev, 0),
MTRR_TYPE_WRCOMB, 1);
#endif #endif
/* Clear framebuffer, it's all white in memory after boot */ /* Clear framebuffer, it's all white in memory after boot */
memset (info->video.vbase, 0, info->video.len); memset(info->screen_base, 0, info->fix.smem_len);
return 0; return 0;
} }
static void __devinit neo_unmap_video (struct neofb_info *info) static void __devinit neo_unmap_video(struct fb_info *info)
{ {
struct neofb_par *par = (struct neofb_par *) info->par;
DBG("neo_unmap_video"); DBG("neo_unmap_video");
if (info->video.vbase) if (info->screen_base) {
{
#ifdef CONFIG_MTRR #ifdef CONFIG_MTRR
mtrr_del (info->video.mtrr, info->video.pbase, info->video.len); mtrr_del(par->mtrr, info->fix.smem_start,
info->fix.smem_len);
#endif #endif
iounmap (info->video.vbase); iounmap(info->screen_base);
info->video.vbase = NULL; info->screen_base = NULL;
info->fb.screen_base = NULL;
release_mem_region (info->video.pbase, info->video.len); release_mem_region(info->fix.smem_start,
info->fix.smem_len);
} }
} }
static int __devinit neo_init_hw (struct neofb_info *info) static int __devinit neo_init_hw(struct fb_info *info)
{ {
struct neofb_par *par = (struct neofb_par *) info->par;
int videoRam = 896; int videoRam = 896;
int maxClock = 65000; int maxClock = 65000;
int CursorMem = 1024; int CursorMem = 1024;
...@@ -1874,64 +1598,65 @@ static int __devinit neo_init_hw (struct neofb_info *info) ...@@ -1874,64 +1598,65 @@ static int __devinit neo_init_hw (struct neofb_info *info)
neoUnlock(); neoUnlock();
#if 0 #if 0
printk (KERN_DEBUG "--- Neo extended register dump ---\n"); printk(KERN_DEBUG "--- Neo extended register dump ---\n");
for (w=0; w<0x85; w++) for (w = 0; w < 0x85; w++)
printk (KERN_DEBUG "CR %p: %p\n", (void*)w, (void*)VGArCR (w)); printk(KERN_DEBUG "CR %p: %p\n", (void *) w,
for (w=0; w<0xC7; w++) (void *) VGArCR(w));
printk (KERN_DEBUG "GR %p: %p\n", (void*)w, (void*)VGArGR (w)); for (w = 0; w < 0xC7; w++)
printk(KERN_DEBUG "GR %p: %p\n", (void *) w,
(void *) VGArGR(w));
#endif #endif
/* Determine the panel type */ /* Determine the panel type */
VGAwGR(0x09,0x26); VGAwGR(0x09, 0x26);
type = VGArGR(0x21); type = VGArGR(0x21);
display = VGArGR(0x20); display = VGArGR(0x20);
/* Determine panel width -- used in NeoValidMode. */ /* Determine panel width -- used in NeoValidMode. */
w = VGArGR(0x20); w = VGArGR(0x20);
VGAwGR(0x09,0x00); VGAwGR(0x09, 0x00);
switch ((w & 0x18) >> 3) switch ((w & 0x18) >> 3) {
{
case 0x00: case 0x00:
info->NeoPanelWidth = 640; par->NeoPanelWidth = 640;
info->NeoPanelHeight = 480; par->NeoPanelHeight = 480;
neofb_var = &neofb_var640x480x8; neofb_var = &neofb_var640x480x8;
break; break;
case 0x01: case 0x01:
info->NeoPanelWidth = 800; par->NeoPanelWidth = 800;
info->NeoPanelHeight = 600; par->NeoPanelHeight = 600;
neofb_var = &neofb_var800x600x8; neofb_var = &neofb_var800x600x8;
break; break;
case 0x02: case 0x02:
info->NeoPanelWidth = 1024; par->NeoPanelWidth = 1024;
info->NeoPanelHeight = 768; par->NeoPanelHeight = 768;
neofb_var = &neofb_var1024x768x8; neofb_var = &neofb_var1024x768x8;
break; break;
case 0x03: case 0x03:
/* 1280x1024 panel support needs to be added */ /* 1280x1024 panel support needs to be added */
#ifdef NOT_DONE #ifdef NOT_DONE
info->NeoPanelWidth = 1280; par->NeoPanelWidth = 1280;
info->NeoPanelHeight = 1024; par->NeoPanelHeight = 1024;
neofb_var = &neofb_var1280x1024x8; neofb_var = &neofb_var1280x1024x8;
break; break;
#else #else
printk (KERN_ERR "neofb: Only 640x480, 800x600 and 1024x768 panels are currently supported\n"); printk(KERN_ERR
"neofb: Only 640x480, 800x600 and 1024x768 panels are currently supported\n");
return -1; return -1;
#endif #endif
default: default:
info->NeoPanelWidth = 640; par->NeoPanelWidth = 640;
info->NeoPanelHeight = 480; par->NeoPanelHeight = 480;
neofb_var = &neofb_var640x480x8; neofb_var = &neofb_var640x480x8;
break; break;
} }
printk (KERN_INFO "Panel is a %dx%d %s %s display\n", printk(KERN_INFO "Panel is a %dx%d %s %s display\n",
info->NeoPanelWidth, par->NeoPanelWidth,
info->NeoPanelHeight, par->NeoPanelHeight,
(type & 0x02) ? "color" : "monochrome", (type & 0x02) ? "color" : "monochrome",
(type & 0x10) ? "TFT" : "dual scan"); (type & 0x10) ? "TFT" : "dual scan");
switch (info->accel) switch (info->fix.accel) {
{
case FB_ACCEL_NEOMAGIC_NM2070: case FB_ACCEL_NEOMAGIC_NM2070:
videoRam = 896; videoRam = 896;
maxClock = 65000; maxClock = 65000;
...@@ -1978,7 +1703,7 @@ static int __devinit neo_init_hw (struct neofb_info *info) ...@@ -1978,7 +1703,7 @@ static int __devinit neo_init_hw (struct neofb_info *info)
maxWidth = 1280; maxWidth = 1280;
maxHeight = 1024; /* ???? */ maxHeight = 1024; /* ???? */
info->neo2200 = (Neo2200*) info->mmio.vbase; par->neo2200 = (Neo2200 *) par->mmio_vbase;
break; break;
case FB_ACCEL_NEOMAGIC_NM2230: case FB_ACCEL_NEOMAGIC_NM2230:
videoRam = 3008; videoRam = 3008;
...@@ -1989,7 +1714,7 @@ static int __devinit neo_init_hw (struct neofb_info *info) ...@@ -1989,7 +1714,7 @@ static int __devinit neo_init_hw (struct neofb_info *info)
maxWidth = 1280; maxWidth = 1280;
maxHeight = 1024; /* ???? */ maxHeight = 1024; /* ???? */
info->neo2200 = (Neo2200*) info->mmio.vbase; par->neo2200 = (Neo2200 *) par->mmio_vbase;
break; break;
case FB_ACCEL_NEOMAGIC_NM2360: case FB_ACCEL_NEOMAGIC_NM2360:
videoRam = 4096; videoRam = 4096;
...@@ -2000,7 +1725,7 @@ static int __devinit neo_init_hw (struct neofb_info *info) ...@@ -2000,7 +1725,7 @@ static int __devinit neo_init_hw (struct neofb_info *info)
maxWidth = 1280; maxWidth = 1280;
maxHeight = 1024; /* ???? */ maxHeight = 1024; /* ???? */
info->neo2200 = (Neo2200*) info->mmio.vbase; par->neo2200 = (Neo2200 *) par->mmio_vbase;
break; break;
case FB_ACCEL_NEOMAGIC_NM2380: case FB_ACCEL_NEOMAGIC_NM2380:
videoRam = 6144; videoRam = 6144;
...@@ -2011,155 +1736,154 @@ static int __devinit neo_init_hw (struct neofb_info *info) ...@@ -2011,155 +1736,154 @@ static int __devinit neo_init_hw (struct neofb_info *info)
maxWidth = 1280; maxWidth = 1280;
maxHeight = 1024; /* ???? */ maxHeight = 1024; /* ???? */
info->neo2200 = (Neo2200*) info->mmio.vbase; par->neo2200 = (Neo2200 *) par->mmio_vbase;
break; break;
} }
info->maxClock = maxClock; par->maxClock = maxClock;
return videoRam * 1024; return videoRam * 1024;
} }
static struct neofb_info * __devinit neo_alloc_fb_info (struct pci_dev *dev, static struct fb_info *__devinit neo_alloc_fb_info(struct pci_dev *dev, const struct
const struct pci_device_id *id) pci_device_id *id)
{ {
struct neofb_info *info; struct fb_info *info;
struct neofb_par *par;
info = kmalloc (sizeof(struct neofb_info) + sizeof(struct display) + info = kmalloc(sizeof(struct fb_info) + sizeof(struct display) +
sizeof(u32) * 16, GFP_KERNEL); sizeof(u32) * 16, GFP_KERNEL);
if (!info) if (!info)
return NULL; return NULL;
memset (info, 0, sizeof(struct neofb_info) + sizeof(struct display)); memset(info, 0, sizeof(struct fb_info) + sizeof(struct display));
info->fb.currcon = -1; par = &default_par;
info->pcidev = dev; memset(par, 0, sizeof(struct neofb_par));
info->accel = id->driver_data;
info->pci_burst = !nopciburst; info->currcon = -1;
info->lcd_stretch = !nostretch; info->fix.accel = id->driver_data;
if (!internal && !external) par->pci_burst = !nopciburst;
{ par->lcd_stretch = !nostretch;
info->internal_display = 1;
info->external_display = 0; if (!internal && !external) {
} par->internal_display = 1;
else par->external_display = 0;
{ } else {
info->internal_display = internal; par->internal_display = internal;
info->external_display = external; par->external_display = external;
} }
switch (info->accel) switch (info->fix.accel) {
{
case FB_ACCEL_NEOMAGIC_NM2070: case FB_ACCEL_NEOMAGIC_NM2070:
sprintf (info->fb.fix.id, "MagicGraph 128"); sprintf(info->fix.id, "MagicGraph 128");
break; break;
case FB_ACCEL_NEOMAGIC_NM2090: case FB_ACCEL_NEOMAGIC_NM2090:
sprintf (info->fb.fix.id, "MagicGraph 128V"); sprintf(info->fix.id, "MagicGraph 128V");
break; break;
case FB_ACCEL_NEOMAGIC_NM2093: case FB_ACCEL_NEOMAGIC_NM2093:
sprintf (info->fb.fix.id, "MagicGraph 128ZV"); sprintf(info->fix.id, "MagicGraph 128ZV");
break; break;
case FB_ACCEL_NEOMAGIC_NM2097: case FB_ACCEL_NEOMAGIC_NM2097:
sprintf (info->fb.fix.id, "MagicGraph 128ZV+"); sprintf(info->fix.id, "MagicGraph 128ZV+");
break; break;
case FB_ACCEL_NEOMAGIC_NM2160: case FB_ACCEL_NEOMAGIC_NM2160:
sprintf (info->fb.fix.id, "MagicGraph 128XD"); sprintf(info->fix.id, "MagicGraph 128XD");
break; break;
case FB_ACCEL_NEOMAGIC_NM2200: case FB_ACCEL_NEOMAGIC_NM2200:
sprintf (info->fb.fix.id, "MagicGraph 256AV"); sprintf(info->fix.id, "MagicGraph 256AV");
break; break;
case FB_ACCEL_NEOMAGIC_NM2230: case FB_ACCEL_NEOMAGIC_NM2230:
sprintf (info->fb.fix.id, "MagicGraph 256AV+"); sprintf(info->fix.id, "MagicGraph 256AV+");
break; break;
case FB_ACCEL_NEOMAGIC_NM2360: case FB_ACCEL_NEOMAGIC_NM2360:
sprintf (info->fb.fix.id, "MagicGraph 256ZX"); sprintf(info->fix.id, "MagicGraph 256ZX");
break; break;
case FB_ACCEL_NEOMAGIC_NM2380: case FB_ACCEL_NEOMAGIC_NM2380:
sprintf (info->fb.fix.id, "MagicGraph 256XL+"); sprintf(info->fix.id, "MagicGraph 256XL+");
break; break;
} }
info->fb.fix.type = FB_TYPE_PACKED_PIXELS; info->fix.type = FB_TYPE_PACKED_PIXELS;
info->fb.fix.type_aux = 0; info->fix.type_aux = 0;
info->fb.fix.xpanstep = 0; info->fix.xpanstep = 0;
info->fb.fix.ypanstep = 4; info->fix.ypanstep = 4;
info->fb.fix.ywrapstep = 0; info->fix.ywrapstep = 0;
info->fb.fix.accel = id->driver_data; info->fix.accel = id->driver_data;
info->fb.var.nonstd = 0; info->var.nonstd = 0;
info->fb.var.activate = FB_ACTIVATE_NOW; info->var.activate = FB_ACTIVATE_NOW;
info->fb.var.height = -1; info->var.height = -1;
info->fb.var.width = -1; info->var.width = -1;
info->fb.var.accel_flags = 0; info->var.accel_flags = 0;
strcpy (info->fb.modename, info->fb.fix.id); strcpy(info->modename, info->fix.id);
info->fb.fbops = &neofb_ops; info->fbops = &neofb_ops;
info->fb.changevar = NULL; info->changevar = NULL;
info->fb.switch_con = neofb_switch; info->switch_con = gen_switch;
info->fb.updatevar = neofb_updatevar; info->updatevar = gen_update_var;
info->fb.flags = FBINFO_FLAG_DEFAULT; info->flags = FBINFO_FLAG_DEFAULT;
info->fb.disp = (struct display *)(info + 1); info->par = par;
info->fb.pseudo_palette = (void *)(info->fb.disp + 1); info->disp = (struct display *) (info + 1);
info->pseudo_palette = (void *) (info->disp + 1);
fb_alloc_cmap (&info->fb.cmap, NR_PALETTE, 0); fb_alloc_cmap(&info->cmap, NR_PALETTE, 0);
return info; return info;
} }
static void __devinit neo_free_fb_info (struct neofb_info *info) static void __devinit neo_free_fb_info(struct fb_info *info)
{ {
if (info) if (info) {
{
/* /*
* Free the colourmap * Free the colourmap
*/ */
fb_alloc_cmap (&info->fb.cmap, 0, 0); fb_alloc_cmap(&info->cmap, 0, 0);
kfree (info); kfree(info);
} }
} }
/* --------------------------------------------------------------------- */ /* --------------------------------------------------------------------- */
static int __devinit neofb_probe (struct pci_dev* dev, const struct pci_device_id* id) static int __devinit neofb_probe(struct pci_dev *dev,
const struct pci_device_id *id)
{ {
struct neofb_info *info; struct fb_info *info;
u_int h_sync, v_sync; u_int h_sync, v_sync;
int err; int err;
int video_len; int video_len;
DBG("neofb_probe"); DBG("neofb_probe");
err = pci_enable_device (dev); err = pci_enable_device(dev);
if (err) if (err)
return err; return err;
err = -ENOMEM; err = -ENOMEM;
info = neo_alloc_fb_info (dev, id); info = neo_alloc_fb_info(dev, id);
if (!info) if (!info)
goto failed; goto failed;
err = neo_map_mmio (info); err = neo_map_mmio(info, dev);
if (err) if (err)
goto failed; goto failed;
video_len = neo_init_hw (info); video_len = neo_init_hw(info);
if (video_len < 0) if (video_len < 0) {
{
err = video_len; err = video_len;
goto failed; goto failed;
} }
err = neo_map_video (info, video_len); err = neo_map_video(info, dev, video_len);
if (err) if (err)
goto failed; goto failed;
neofb_set_var (neofb_var, -1, &info->fb); gen_set_var(neofb_var, -1, info);
/* /*
* Calculate the hsync and vsync frequencies. Note that * Calculate the hsync and vsync frequencies. Note that
...@@ -2167,24 +1891,26 @@ static int __devinit neofb_probe (struct pci_dev* dev, const struct pci_device_i ...@@ -2167,24 +1891,26 @@ static int __devinit neofb_probe (struct pci_dev* dev, const struct pci_device_i
* the precision and fit the results into 32-bit registers. * the precision and fit the results into 32-bit registers.
* (1953125000 * 512 = 1e12) * (1953125000 * 512 = 1e12)
*/ */
h_sync = 1953125000 / info->fb.var.pixclock; h_sync = 1953125000 / info->var.pixclock;
h_sync = h_sync * 512 / (info->fb.var.xres + info->fb.var.left_margin + h_sync =
info->fb.var.right_margin + info->fb.var.hsync_len); h_sync * 512 / (info->var.xres + info->var.left_margin +
v_sync = h_sync / (info->fb.var.yres + info->fb.var.upper_margin + info->var.right_margin + info->var.hsync_len);
info->fb.var.lower_margin + info->fb.var.vsync_len); v_sync =
h_sync / (info->var.yres + info->var.upper_margin +
info->var.lower_margin + info->var.vsync_len);
printk(KERN_INFO "neofb v" NEOFB_VERSION ": %dkB VRAM, using %dx%d, %d.%03dkHz, %dHz\n", printk(KERN_INFO "neofb v" NEOFB_VERSION
info->fb.fix.smem_len >> 10, ": %dkB VRAM, using %dx%d, %d.%03dkHz, %dHz\n",
info->fb.var.xres, info->fb.var.yres, info->fix.smem_len >> 10, info->var.xres,
h_sync / 1000, h_sync % 1000, v_sync); info->var.yres, h_sync / 1000, h_sync % 1000, v_sync);
err = register_framebuffer (&info->fb); err = register_framebuffer(info);
if (err < 0) if (err < 0)
goto failed; goto failed;
printk (KERN_INFO "fb%d: %s frame buffer device\n", printk(KERN_INFO "fb%d: %s frame buffer device\n",
GET_FB_IDX(info->fb.node), info->fb.modename); GET_FB_IDX(info->node), info->modename);
/* /*
* Our driver data * Our driver data
...@@ -2193,33 +1919,33 @@ static int __devinit neofb_probe (struct pci_dev* dev, const struct pci_device_i ...@@ -2193,33 +1919,33 @@ static int __devinit neofb_probe (struct pci_dev* dev, const struct pci_device_i
return 0; return 0;
failed: failed:
neo_unmap_video (info); neo_unmap_video(info);
neo_unmap_mmio (info); neo_unmap_mmio(info);
neo_free_fb_info (info); neo_free_fb_info(info);
return err; return err;
} }
static void __devexit neofb_remove (struct pci_dev *dev) static void __devexit neofb_remove(struct pci_dev *dev)
{ {
struct neofb_info *info = (struct neofb_info *)dev->driver_data; struct fb_info *info = (struct fb_info *) dev->driver_data;
DBG("neofb_remove"); DBG("neofb_remove");
if (info) if (info) {
{
/* /*
* If unregister_framebuffer fails, then * If unregister_framebuffer fails, then
* we will be leaving hooks that could cause * we will be leaving hooks that could cause
* oopsen laying around. * oopsen laying around.
*/ */
if (unregister_framebuffer (&info->fb)) if (unregister_framebuffer(info))
printk (KERN_WARNING "neofb: danger danger! Oopsen imminent!\n"); printk(KERN_WARNING
"neofb: danger danger! Oopsen imminent!\n");
neo_unmap_video (info); neo_unmap_video(info);
neo_unmap_mmio (info); neo_unmap_mmio(info);
neo_free_fb_info (info); neo_free_fb_info(info);
/* /*
* Ensure that the driver data is no longer * Ensure that the driver data is no longer
...@@ -2271,18 +1997,18 @@ static struct pci_driver neofb_driver = { ...@@ -2271,18 +1997,18 @@ static struct pci_driver neofb_driver = {
/* **************************** init-time only **************************** */ /* **************************** init-time only **************************** */
static void __init neo_init (void) static void __init neo_init(void)
{ {
DBG("neo_init"); DBG("neo_init");
pci_register_driver (&neofb_driver); pci_register_driver(&neofb_driver);
} }
/* **************************** exit-time only **************************** */ /* **************************** exit-time only **************************** */
static void __exit neo_done (void) static void __exit neo_done(void)
{ {
DBG("neo_done"); DBG("neo_done");
pci_unregister_driver (&neofb_driver); pci_unregister_driver(&neofb_driver);
} }
...@@ -2290,7 +2016,7 @@ static void __exit neo_done (void) ...@@ -2290,7 +2016,7 @@ static void __exit neo_done (void)
/* ************************* init in-kernel code ************************** */ /* ************************* init in-kernel code ************************** */
int __init neofb_setup (char *options) int __init neofb_setup(char *options)
{ {
char *this_opt; char *this_opt;
...@@ -2299,9 +2025,9 @@ int __init neofb_setup (char *options) ...@@ -2299,9 +2025,9 @@ int __init neofb_setup (char *options)
if (!options || !*options) if (!options || !*options)
return 0; return 0;
while ((this_opt = strsep(&options,",")) != NULL) while ((this_opt = strsep(&options, ",")) != NULL) {
{ if (!*this_opt)
if (!*this_opt) continue; continue;
if (!strncmp(this_opt, "disabled", 8)) if (!strncmp(this_opt, "disabled", 8))
disabled = 1; disabled = 1;
...@@ -2327,8 +2053,7 @@ int __init neofb_init(void) ...@@ -2327,8 +2053,7 @@ int __init neofb_init(void)
if (disabled) if (disabled)
return -ENXIO; return -ENXIO;
if (!initialized) if (!initialized) {
{
initialized = 1; initialized = 1;
neo_init(); neo_init();
} }
......
...@@ -76,15 +76,6 @@ ...@@ -76,15 +76,6 @@
#include <linux/timer.h> #include <linux/timer.h>
#include <linux/spinlock.h> #include <linux/spinlock.h>
#include <linux/kd.h>
#include <linux/console.h>
#include <linux/selection.h>
#include <linux/vt_kern.h>
#ifdef CONFIG_MTRR
#include <asm/mtrr.h>
#endif
#include <video/tdfx.h> #include <video/tdfx.h>
#include <video/fbcon.h> #include <video/fbcon.h>
...@@ -92,17 +83,7 @@ ...@@ -92,17 +83,7 @@
#define PCI_DEVICE_ID_3DFX_VOODOO5 0x0009 #define PCI_DEVICE_ID_3DFX_VOODOO5 0x0009
#endif #endif
#define TDFXF_HSYNC_ACT_HIGH 0x01 #undef TDFXFB_DEBUG
#define TDFXF_HSYNC_ACT_LOW 0x02
#define TDFXF_VSYNC_ACT_HIGH 0x04
#define TDFXF_VSYNC_ACT_LOW 0x08
#define TDFXF_LINE_DOUBLE 0x10
#define TDFXF_VIDEO_ENABLE 0x20
#define TDFXF_HSYNC_MASK 0x03
#define TDFXF_VSYNC_MASK 0x0c
//#define TDFXFB_DEBUG
#ifdef TDFXFB_DEBUG #ifdef TDFXFB_DEBUG
#define DPRINTK(a,b...) printk(KERN_DEBUG "fb: %s: " a, __FUNCTION__ , ## b) #define DPRINTK(a,b...) printk(KERN_DEBUG "fb: %s: " a, __FUNCTION__ , ## b)
#else #else
...@@ -113,230 +94,115 @@ ...@@ -113,230 +94,115 @@
#define VOODOO3_MAX_PIXCLOCK 300000.0 #define VOODOO3_MAX_PIXCLOCK 300000.0
#define VOODOO5_MAX_PIXCLOCK 350000.0 #define VOODOO5_MAX_PIXCLOCK 350000.0
struct tdfxfb_par { static struct fb_fix_screeninfo tdfx_fix __initdata = {
u32 pixclock; id: "3Dfx",
type: FB_TYPE_PACKED_PIXELS,
u32 baseline; visual: FB_VISUAL_PSEUDOCOLOR,
ypanstep: 1,
u32 width; ywrapstep: 1,
u32 height; accel: FB_ACCEL_3DFX_BANSHEE
u32 width_virt;
u32 height_virt;
u32 lpitch; /* line pitch, in bytes */
u32 ppitch; /* pixel pitch, in bits */
u32 bpp;
u32 hdispend;
u32 hsyncsta;
u32 hsyncend;
u32 htotal;
u32 vdispend;
u32 vsyncsta;
u32 vsyncend;
u32 vtotal;
u32 video;
u32 accel_flags;
u32 cmap_len;
}; };
struct fb_info_tdfx { static struct fb_var_screeninfo tdfx_var __initdata = {
struct fb_info fb_info; /* "640x480, 8 bpp @ 60 Hz */
xres: 640,
u16 dev; yres: 480,
u32 max_pixclock; xres_virtual: 640,
yres_virtual: 1024,
unsigned long regbase_phys; bits_per_pixel: 8,
void *regbase_virt; red: {0, 8, 0},
unsigned long regbase_size; blue: {0, 8, 0},
unsigned long bufbase_phys; green: {0, 8, 0},
void *bufbase_virt; activate: FB_ACTIVATE_NOW,
unsigned long bufbase_size; height: -1,
unsigned long iobase; width: -1,
accel_flags: FB_ACCELF_TEXT,
struct { pixclock: 39722,
unsigned red, green, blue, pad; left_margin: 40,
} palette[256]; right_margin: 24,
struct tdfxfb_par default_par; upper_margin: 32,
struct tdfxfb_par current_par; lower_margin: 11,
struct display disp; hsync_len: 96,
#if defined(FBCON_HAS_CFB16) || defined(FBCON_HAS_CFB24) || defined(FBCON_HAS_CFB32) vsync_len: 2,
union { vmode: FB_VMODE_NONINTERLACED
#ifdef FBCON_HAS_CFB16
u16 cfb16[16];
#endif
#ifdef FBCON_HAS_CFB24
u32 cfb24[16];
#endif
#ifdef FBCON_HAS_CFB32
u32 cfb32[16];
#endif
} fbcon_cmap;
#endif
struct {
int type;
int state;
int w, u, d;
int x, y, redraw;
unsigned long enable, disable;
unsigned long cursorimage;
struct timer_list timer;
} cursor;
spinlock_t DAClock;
#ifdef CONFIG_MTRR
int mtrr_idx;
#endif
}; };
/*
* Frame buffer device API
*/
static int tdfxfb_get_fix(struct fb_fix_screeninfo *fix,
int con, struct fb_info *fb);
static int tdfxfb_get_var(struct fb_var_screeninfo *var,
int con, struct fb_info *fb);
static int tdfxfb_set_var(struct fb_var_screeninfo *var,
int con, struct fb_info *fb);
static int tdfxfb_setcolreg(u_int regno,
u_int red,
u_int green,
u_int blue, u_int transp, struct fb_info *fb);
static int tdfxfb_pan_display(struct fb_var_screeninfo *var,
int con, struct fb_info *fb);
static int tdfxfb_get_cmap(struct fb_cmap *cmap,
int kspc, int con, struct fb_info *info);
static int tdfxfb_set_cmap(struct fb_cmap *cmap,
int kspc, int con, struct fb_info *info);
/*
* Interface to the low level console driver
*/
static int tdfxfb_switch_con(int con, struct fb_info *fb);
static int tdfxfb_updatevar(int con, struct fb_info *fb);
static int tdfxfb_blank(int blank, struct fb_info *fb);
/*
* Internal routines
*/
static void tdfxfb_set_par(const struct tdfxfb_par *par,
struct fb_info_tdfx *info);
static int tdfxfb_decode_var(const struct fb_var_screeninfo *var,
struct tdfxfb_par *par,
const struct fb_info_tdfx *info);
static int tdfxfb_encode_var(struct fb_var_screeninfo *var,
const struct tdfxfb_par *par,
const struct fb_info_tdfx *info);
static int tdfxfb_encode_fix(struct fb_fix_screeninfo *fix,
const struct tdfxfb_par *par,
const struct fb_info_tdfx *info);
static void tdfxfb_set_dispsw(struct display *disp,
struct fb_info_tdfx *info,
int bpp, int accel);
static int tdfxfb_getcolreg(u_int regno,
u_int * red,
u_int * green,
u_int * blue,
u_int * transp, struct fb_info *fb);
static void tdfxfb_hwcursor_init(void);
static void tdfxfb_createcursorshape(struct display *p);
static void tdfxfb_createcursor(struct display *p);
/*
* do_xxx: Hardware-specific functions
*/
static void do_pan_var(struct fb_var_screeninfo *var,
struct fb_info_tdfx *i);
static void do_flashcursor(unsigned long ptr);
static void do_bitblt(u32 curx, u32 cury, u32 dstx, u32 dsty,
u32 width, u32 height, u32 stride, u32 bpp);
static void do_fillrect(u32 x, u32 y, u32 w, u32 h,
u32 color, u32 stride, u32 bpp, u32 rop);
static void do_putc(u32 fgx, u32 bgx, struct display *p,
int c, int yy, int xx);
static void do_putcs(u32 fgx, u32 bgx, struct display *p,
const unsigned short *s, int count, int yy, int xx);
static u32 do_calc_pll(int freq, int *freq_out);
static void do_write_regs(struct banshee_reg *reg);
static unsigned long do_lfb_size(void);
/*
* Interface used by the world
*/
int tdfxfb_init(void);
void tdfxfb_setup(char *options, int *ints);
/* /*
* PCI driver prototypes * PCI driver prototypes
*/ */
static int tdfxfb_probe(struct pci_dev *pdev, static int tdfxfb_probe(struct pci_dev *pdev, const struct pci_device_id *id);
const struct pci_device_id *id);
static void tdfxfb_remove(struct pci_dev *pdev); static void tdfxfb_remove(struct pci_dev *pdev);
static struct fb_ops tdfxfb_ops = {
owner:THIS_MODULE,
fb_get_fix:tdfxfb_get_fix,
fb_get_var:tdfxfb_get_var,
fb_set_var:tdfxfb_set_var,
fb_get_cmap:tdfxfb_get_cmap,
fb_set_cmap:tdfxfb_set_cmap,
fb_setcolreg:tdfxfb_setcolreg,
fb_pan_display:tdfxfb_pan_display,
fb_blank:tdfxfb_blank,
};
static struct pci_device_id tdfxfb_id_table[] __devinitdata = { static struct pci_device_id tdfxfb_id_table[] __devinitdata = {
{PCI_VENDOR_ID_3DFX, PCI_DEVICE_ID_3DFX_BANSHEE, { PCI_VENDOR_ID_3DFX, PCI_DEVICE_ID_3DFX_BANSHEE,
PCI_ANY_ID, PCI_ANY_ID, PCI_BASE_CLASS_DISPLAY << 16, PCI_ANY_ID, PCI_ANY_ID, PCI_BASE_CLASS_DISPLAY << 16,
0xff0000, 0}, 0xff0000, 0 },
{PCI_VENDOR_ID_3DFX, PCI_DEVICE_ID_3DFX_VOODOO3, { PCI_VENDOR_ID_3DFX, PCI_DEVICE_ID_3DFX_VOODOO3,
PCI_ANY_ID, PCI_ANY_ID, PCI_BASE_CLASS_DISPLAY << 16, PCI_ANY_ID, PCI_ANY_ID, PCI_BASE_CLASS_DISPLAY << 16,
0xff0000, 0}, 0xff0000, 0 },
{PCI_VENDOR_ID_3DFX, PCI_DEVICE_ID_3DFX_VOODOO5, { PCI_VENDOR_ID_3DFX, PCI_DEVICE_ID_3DFX_VOODOO5,
PCI_ANY_ID, PCI_ANY_ID, PCI_BASE_CLASS_DISPLAY << 16, PCI_ANY_ID, PCI_ANY_ID, PCI_BASE_CLASS_DISPLAY << 16,
0xff0000, 0}, 0xff0000, 0 },
{0,} { 0, }
}; };
static struct pci_driver tdfxfb_driver = { static struct pci_driver tdfxfb_driver = {
name:"tdfxfb", name: "tdfxfb",
id_table:tdfxfb_id_table, id_table: tdfxfb_id_table,
probe:tdfxfb_probe, probe: tdfxfb_probe,
remove:__devexit_p(tdfxfb_remove), remove: tdfxfb_remove,
}; };
MODULE_DEVICE_TABLE(pci, tdfxfb_id_table); MODULE_DEVICE_TABLE(pci, tdfxfb_id_table);
struct mode { /*
char *name; * Frame buffer device API
struct fb_var_screeninfo var; */
} mode; int tdfxfb_init(void);
void tdfxfb_setup(char *options, int *ints);
/* 2.3.x kernels have a fb mode database, so supply only one backup default */
struct mode default_mode[] = { static int tdfxfb_check_var(struct fb_var_screeninfo *var, struct fb_info *fb);
{"640x480-8@60", /* @ 60 Hz */ static int tdfxfb_set_par(struct fb_info *info);
{ static int tdfxfb_setcolreg(u_int regno, u_int red, u_int green, u_int blue,
640, 480, 640, 1024, 0, 0, 8, 0, u_int transp, struct fb_info *info);
{0, 8, 0}, {0, 8, 0}, {0, 8, 0}, {0, 0, 0}, static int tdfxfb_blank(int blank, struct fb_info *info);
0, FB_ACTIVATE_NOW, -1, -1, FB_ACCELF_TEXT, static int tdfxfb_pan_display(struct fb_var_screeninfo *var, int con, struct fb_info *info);
39722, 40, 24, 32, 11, 96, 2, static void tdfxfb_fillrect(struct fb_info *info, struct fb_fillrect *rect);
0, FB_VMODE_NONINTERLACED} static void tdfxfb_copyarea(struct fb_info *info, struct fb_copyarea *area);
} static void tdfxfb_imageblit(struct fb_info *info, struct fb_image *image);
static struct fb_ops tdfxfb_ops = {
owner: THIS_MODULE,
fb_get_fix: gen_get_fix,
fb_get_var: gen_get_var,
fb_set_var: gen_set_var,
fb_get_cmap: gen_get_cmap,
fb_set_cmap: gen_set_cmap,
fb_check_var: tdfxfb_check_var,
fb_set_par: tdfxfb_set_par,
fb_setcolreg: tdfxfb_setcolreg,
fb_blank: tdfxfb_blank,
fb_pan_display: tdfxfb_pan_display,
fb_fillrect: tdfxfb_fillrect,
fb_copyarea: tdfxfb_copyarea,
fb_imageblit: tdfxfb_imageblit,
}; };
static struct fb_info_tdfx fb_info; /*
* do_xxx: Hardware-specific functions
*/
static u32 do_calc_pll(int freq, int *freq_out);
static void do_write_regs(struct banshee_reg *reg);
static unsigned long do_lfb_size(unsigned short);
/*
* Driver data
*/
static struct tdfx_par default_par;
static int noaccel = 0;
static int nopan = 0; static int nopan = 0;
static int nowrap = 1; // not implemented (yet) static int nowrap = 1; // not implemented (yet)
static int inverse = 0; static int inverse = 0;
#ifdef CONFIG_MTRR
static int nomtrr = 0;
#endif
static int nohwcursor = 0;
static char __initdata fontname[40] = { 0 };
static char *mode_option __initdata = NULL; static char *mode_option __initdata = NULL;
/* ------------------------------------------------------------------------- /* -------------------------------------------------------------------------
...@@ -344,98 +210,62 @@ static char *mode_option __initdata = NULL; ...@@ -344,98 +210,62 @@ static char *mode_option __initdata = NULL;
* ------------------------------------------------------------------------- */ * ------------------------------------------------------------------------- */
#ifdef VGA_REG_IO #ifdef VGA_REG_IO
static inline u8 vga_inb(u32 reg) static inline u8 vga_inb(u32 reg) { return inb(reg); }
{ static inline u16 vga_inw(u32 reg) { return inw(reg); }
return inb(reg); static inline u16 vga_inl(u32 reg) { return inl(reg); }
}
static inline u16 vga_inw(u32 reg)
{
return inw(reg);
}
static inline u16 vga_inl(u32 reg)
{
return inl(reg);
}
static inline void vga_outb(u32 reg, u8 val) static inline void vga_outb(u32 reg, u8 val) { outb(val, reg); }
{ static inline void vga_outw(u32 reg, u16 val) { outw(val, reg); }
outb(val, reg); static inline void vga_outl(u32 reg, u32 val) { outl(val, reg); }
}
static inline void vga_outw(u32 reg, u16 val)
{
outw(val, reg);
}
static inline void vga_outl(u32 reg, u32 val)
{
outl(val, reg);
}
#else #else
static inline u8 vga_inb(u32 reg) static inline u8 vga_inb(u32 reg) {
{ return inb(default_par.iobase + reg - 0x300);
return inb(fb_info.iobase + reg - 0x300);
} }
static inline u16 vga_inw(u32 reg) static inline u16 vga_inw(u32 reg) {
{ return inw(default_par.iobase + reg - 0x300);
return inw(fb_info.iobase + reg - 0x300);
} }
static inline u16 vga_inl(u32 reg) static inline u16 vga_inl(u32 reg) {
{ return inl(default_par.iobase + reg - 0x300);
return inl(fb_info.iobase + reg - 0x300);
} }
static inline void vga_outb(u32 reg, u8 val) {
static inline void vga_outb(u32 reg, u8 val) outb(val, default_par.iobase + reg - 0x300);
{
outb(val, fb_info.iobase + reg - 0x300);
} }
static inline void vga_outw(u32 reg, u16 val) static inline void vga_outw(u32 reg, u16 val) {
{ outw(val, default_par.iobase + reg - 0x300);
outw(val, fb_info.iobase + reg - 0x300);
} }
static inline void vga_outl(u32 reg, u32 val) static inline void vga_outl(u32 reg, u32 val) {
{ outl(val, default_par.iobase + reg - 0x300);
outl(val, fb_info.iobase + reg - 0x300);
} }
#endif #endif
static inline void gra_outb(u32 idx, u8 val) static inline void gra_outb(u32 idx, u8 val) {
{ vga_outb(GRA_I, idx); vga_outb(GRA_D, val);
vga_outb(GRA_I, idx);
vga_outb(GRA_D, val);
} }
static inline u8 gra_inb(u32 idx) static inline u8 gra_inb(u32 idx) {
{ vga_outb(GRA_I, idx); return vga_inb(GRA_D);
vga_outb(GRA_I, idx);
return vga_inb(GRA_D);
} }
static inline void seq_outb(u32 idx, u8 val) static inline void seq_outb(u32 idx, u8 val) {
{ vga_outb(SEQ_I, idx); vga_outb(SEQ_D, val);
vga_outb(SEQ_I, idx);
vga_outb(SEQ_D, val);
} }
static inline u8 seq_inb(u32 idx) static inline u8 seq_inb(u32 idx) {
{ vga_outb(SEQ_I, idx); return vga_inb(SEQ_D);
vga_outb(SEQ_I, idx);
return vga_inb(SEQ_D);
} }
static inline void crt_outb(u32 idx, u8 val) static inline void crt_outb(u32 idx, u8 val) {
{ vga_outb(CRT_I, idx); vga_outb(CRT_D, val);
vga_outb(CRT_I, idx);
vga_outb(CRT_D, val);
} }
static inline u8 crt_inb(u32 idx) static inline u8 crt_inb(u32 idx) {
{ vga_outb(CRT_I, idx); return vga_inb(CRT_D);
vga_outb(CRT_I, idx);
return vga_inb(CRT_D);
} }
static inline void att_outb(u32 idx, u8 val) static inline void att_outb(u32 idx, u8 val)
{ {
unsigned char tmp; unsigned char tmp;
tmp = vga_inb(IS1_R); tmp = vga_inb(IS1_R);
vga_outb(ATT_IW, idx); vga_outb(ATT_IW, idx);
vga_outb(ATT_IW, val); vga_outb(ATT_IW, val);
...@@ -444,6 +274,7 @@ static inline void att_outb(u32 idx, u8 val) ...@@ -444,6 +274,7 @@ static inline void att_outb(u32 idx, u8 val)
static inline u8 att_inb(u32 idx) static inline u8 att_inb(u32 idx)
{ {
unsigned char tmp; unsigned char tmp;
tmp = vga_inb(IS1_R); tmp = vga_inb(IS1_R);
vga_outb(ATT_IW, idx); vga_outb(ATT_IW, idx);
return vga_inb(ATT_IW); return vga_inb(ATT_IW);
...@@ -452,6 +283,7 @@ static inline u8 att_inb(u32 idx) ...@@ -452,6 +283,7 @@ static inline u8 att_inb(u32 idx)
static inline void vga_disable_video(void) static inline void vga_disable_video(void)
{ {
unsigned char s; unsigned char s;
s = seq_inb(0x01) | 0x20; s = seq_inb(0x01) | 0x20;
seq_outb(0x00, 0x01); seq_outb(0x00, 0x01);
seq_outb(0x01, s); seq_outb(0x01, s);
...@@ -461,6 +293,7 @@ static inline void vga_disable_video(void) ...@@ -461,6 +293,7 @@ static inline void vga_disable_video(void)
static inline void vga_enable_video(void) static inline void vga_enable_video(void)
{ {
unsigned char s; unsigned char s;
s = seq_inb(0x01) & 0xdf; s = seq_inb(0x01) & 0xdf;
seq_outb(0x00, 0x01); seq_outb(0x00, 0x01);
seq_outb(0x01, s); seq_outb(0x01, s);
...@@ -481,17 +314,17 @@ static inline void vga_enable_palette(void) ...@@ -481,17 +314,17 @@ static inline void vga_enable_palette(void)
static inline u32 tdfx_inl(unsigned int reg) static inline u32 tdfx_inl(unsigned int reg)
{ {
return readl(fb_info.regbase_virt + reg); return readl(default_par.regbase_virt + reg);
} }
static inline void tdfx_outl(unsigned int reg, u32 val) static inline void tdfx_outl(unsigned int reg, u32 val)
{ {
writel(val, fb_info.regbase_virt + reg); writel(val, default_par.regbase_virt + reg);
} }
static inline void banshee_make_room(int size) static inline void banshee_make_room(int size)
{ {
while ((tdfx_inl(STATUS) & 0x1f) < size); while((tdfx_inl(STATUS) & 0x1f) < size);
} }
static inline void banshee_wait_idle(void) static inline void banshee_wait_idle(void)
...@@ -501,10 +334,9 @@ static inline void banshee_wait_idle(void) ...@@ -501,10 +334,9 @@ static inline void banshee_wait_idle(void)
banshee_make_room(1); banshee_make_room(1);
tdfx_outl(COMMAND_3D, COMMAND_3D_NOP); tdfx_outl(COMMAND_3D, COMMAND_3D_NOP);
while (1) { while(1) {
i = (tdfx_inl(STATUS) & STATUS_BUSY) ? 0 : i + 1; i = (tdfx_inl(STATUS) & STATUS_BUSY) ? 0 : i + 1;
if (i == 3) if(i == 3) break;
break;
} }
} }
...@@ -518,239 +350,7 @@ static inline void do_setpalentry(unsigned regno, u32 c) ...@@ -518,239 +350,7 @@ static inline void do_setpalentry(unsigned regno, u32 c)
tdfx_outl(DACDATA, c); tdfx_outl(DACDATA, c);
} }
/* static u32 do_calc_pll(int freq, int* freq_out)
* Set the starting position of the visible screen to var->yoffset
*/
static void do_pan_var(struct fb_var_screeninfo *var,
struct fb_info_tdfx *i)
{
u32 addr;
addr = var->yoffset * i->current_par.lpitch;
banshee_make_room(1);
tdfx_outl(VIDDESKSTART, addr);
}
/*
* Invert the hardware cursor image (timerfunc)
*/
static void do_flashcursor(unsigned long ptr)
{
struct fb_info_tdfx *i = (struct fb_info_tdfx *) ptr;
unsigned long flags;
spin_lock_irqsave(&i->DAClock, flags);
banshee_make_room(1);
tdfx_outl(VIDPROCCFG,
tdfx_inl(VIDPROCCFG) ^ VIDCFG_HWCURSOR_ENABLE);
i->cursor.timer.expires = jiffies + HZ / 2;
add_timer(&i->cursor.timer);
spin_unlock_irqrestore(&i->DAClock, flags);
}
/*
* FillRect 2D command (solidfill or invert (via ROP_XOR))
*/
static void do_fillrect(u32 x, u32 y, u32 w, u32 h,
u32 color, u32 stride, u32 bpp, u32 rop)
{
u32 fmt = stride | ((bpp + ((bpp == 8) ? 0 : 8)) << 13);
banshee_make_room(5);
tdfx_outl(DSTFORMAT, fmt);
tdfx_outl(COLORFORE, color);
tdfx_outl(COMMAND_2D, COMMAND_2D_FILLRECT | (rop << 24));
tdfx_outl(DSTSIZE, w | (h << 16));
tdfx_outl(LAUNCH_2D, x | (y << 16));
banshee_wait_idle();
}
/*
* Screen-to-Screen BitBlt 2D command (for the bmove fb op.)
*/
static void do_bitblt(u32 curx,
u32 cury,
u32 dstx,
u32 dsty, u32 width, u32 height, u32 stride, u32 bpp)
{
u32 blitcmd = COMMAND_2D_S2S_BITBLT | (TDFX_ROP_COPY << 24);
u32 fmt = stride | ((bpp + ((bpp == 8) ? 0 : 8)) << 13);
if (curx <= dstx) {
//-X
blitcmd |= BIT(14);
curx += width - 1;
dstx += width - 1;
}
if (cury <= dsty) {
//-Y
blitcmd |= BIT(15);
cury += height - 1;
dsty += height - 1;
}
banshee_make_room(6);
tdfx_outl(SRCFORMAT, fmt);
tdfx_outl(DSTFORMAT, fmt);
tdfx_outl(COMMAND_2D, blitcmd);
tdfx_outl(DSTSIZE, width | (height << 16));
tdfx_outl(DSTXY, dstx | (dsty << 16));
tdfx_outl(LAUNCH_2D, curx | (cury << 16));
banshee_wait_idle();
}
static void do_putc(u32 fgx, u32 bgx,
struct display *p, int c, int yy, int xx)
{
int i;
int stride = fb_info.current_par.lpitch;
u32 bpp = fb_info.current_par.bpp;
int fw = (fontwidth(p) + 7) >> 3;
u8 *chardata =
p->fontdata + (c & p->charmask) * fontheight(p) * fw;
u32 fmt = stride | ((bpp + ((bpp == 8) ? 0 : 8)) << 13);
xx *= fontwidth(p);
yy *= fontheight(p);
banshee_make_room(8 + ((fontheight(p) * fw + 3) >> 2));
tdfx_outl(COLORFORE, fgx);
tdfx_outl(COLORBACK, bgx);
tdfx_outl(SRCXY, 0);
tdfx_outl(DSTXY, xx | (yy << 16));
tdfx_outl(COMMAND_2D,
COMMAND_2D_H2S_BITBLT | (TDFX_ROP_COPY << 24));
tdfx_outl(SRCFORMAT, 0x400000);
tdfx_outl(DSTFORMAT, fmt);
tdfx_outl(DSTSIZE, fontwidth(p) | (fontheight(p) << 16));
i = fontheight(p);
switch (fw) {
case 1:
while (i >= 4) {
tdfx_outl(LAUNCH_2D, *(u32 *) chardata);
chardata += 4;
i -= 4;
}
switch (i) {
case 0:
break;
case 1:
tdfx_outl(LAUNCH_2D, *chardata);
break;
case 2:
tdfx_outl(LAUNCH_2D, *(u16 *) chardata);
break;
case 3:
tdfx_outl(LAUNCH_2D,
*(u16 *) chardata | ((chardata[3]) <<
24));
break;
}
break;
case 2:
while (i >= 2) {
tdfx_outl(LAUNCH_2D, *(u32 *) chardata);
chardata += 4;
i -= 2;
}
if (i)
tdfx_outl(LAUNCH_2D, *(u16 *) chardata);
break;
default:
// Is there a font with width more that 16 pixels ?
for (i = fontheight(p); i > 0; i--) {
tdfx_outl(LAUNCH_2D, *(u32 *) chardata);
chardata += 4;
}
break;
}
banshee_wait_idle();
}
static void do_putcs(u32 fgx, u32 bgx,
struct display *p,
const unsigned short *s, int count, int yy, int xx)
{
int i;
int stride = fb_info.current_par.lpitch;
u32 bpp = fb_info.current_par.bpp;
int fw = (fontwidth(p) + 7) >> 3;
int w = fontwidth(p);
int h = fontheight(p);
int regsneed = 1 + ((h * fw + 3) >> 2);
u32 fmt = stride | ((bpp + ((bpp == 8) ? 0 : 8)) << 13);
xx *= w;
yy = (yy * h) << 16;
banshee_make_room(8);
tdfx_outl(COMMAND_3D, COMMAND_3D_NOP);
tdfx_outl(COLORFORE, fgx);
tdfx_outl(COLORBACK, bgx);
tdfx_outl(SRCFORMAT, 0x400000);
tdfx_outl(DSTFORMAT, fmt);
tdfx_outl(DSTSIZE, w | (h << 16));
tdfx_outl(SRCXY, 0);
tdfx_outl(COMMAND_2D,
COMMAND_2D_H2S_BITBLT | (TDFX_ROP_COPY << 24));
while (count--) {
u8 *chardata =
p->fontdata + (scr_readw(s++) & p->charmask) * h * fw;
banshee_make_room(regsneed);
tdfx_outl(DSTXY, xx | yy);
xx += w;
i = h;
switch (fw) {
case 1:
while (i >= 4) {
tdfx_outl(LAUNCH_2D, *(u32 *) chardata);
chardata += 4;
i -= 4;
}
switch (i) {
case 0:
break;
case 1:
tdfx_outl(LAUNCH_2D, *chardata);
break;
case 2:
tdfx_outl(LAUNCH_2D, *(u16 *) chardata);
break;
case 3:
tdfx_outl(LAUNCH_2D,
*(u16 *) chardata |
((chardata[3]) << 24));
break;
}
break;
case 2:
while (i >= 2) {
tdfx_outl(LAUNCH_2D, *(u32 *) chardata);
chardata += 4;
i -= 2;
}
if (i)
tdfx_outl(LAUNCH_2D, *(u16 *) chardata);
break;
default:
// Is there a font with width more that 16 pixels ?
for (; i > 0; i--) {
tdfx_outl(LAUNCH_2D, *(u32 *) chardata);
chardata += 4;
}
break;
}
}
banshee_wait_idle();
}
static u32 do_calc_pll(int freq, int *freq_out)
{ {
int m, n, k, best_m, best_n, best_k, f_cur, best_error; int m, n, k, best_m, best_n, best_k, f_cur, best_error;
int fref = 14318; int fref = 14318;
...@@ -762,10 +362,9 @@ static u32 do_calc_pll(int freq, int *freq_out) ...@@ -762,10 +362,9 @@ static u32 do_calc_pll(int freq, int *freq_out)
for (n = 1; n < 256; n++) { for (n = 1; n < 256; n++) {
for (m = 1; m < 64; m++) { for (m = 1; m < 64; m++) {
for (k = 0; k < 4; k++) { for (k = 0; k < 4; k++) {
f_cur = f_cur = fref*(n + 2)/(m + 2)/(1 << k);
fref * (n + 2) / (m + 2) / (1 << k);
if (abs(f_cur - freq) < best_error) { if (abs(f_cur - freq) < best_error) {
best_error = abs(f_cur - freq); best_error = abs(f_cur-freq);
best_n = n; best_n = n;
best_m = m; best_m = m;
best_k = k; best_k = k;
...@@ -776,12 +375,11 @@ static u32 do_calc_pll(int freq, int *freq_out) ...@@ -776,12 +375,11 @@ static u32 do_calc_pll(int freq, int *freq_out)
n = best_n; n = best_n;
m = best_m; m = best_m;
k = best_k; k = best_k;
*freq_out = fref * (n + 2) / (m + 2) / (1 << k); *freq_out = fref*(n + 2)/(m + 2)/(1 << k);
return (n << 8) | (m << 2) | k; return (n << 8) | (m << 2) | k;
} }
static void do_write_regs(struct banshee_reg *reg) static void do_write_regs(struct banshee_reg* reg)
{ {
int i; int i;
...@@ -824,16 +422,9 @@ static void do_write_regs(struct banshee_reg *reg) ...@@ -824,16 +422,9 @@ static void do_write_regs(struct banshee_reg *reg)
tdfx_outl(VGAINIT0, reg->vgainit0); tdfx_outl(VGAINIT0, reg->vgainit0);
tdfx_outl(DACMODE, reg->dacmode); tdfx_outl(DACMODE, reg->dacmode);
tdfx_outl(VIDDESKSTRIDE, reg->stride); tdfx_outl(VIDDESKSTRIDE, reg->stride);
if (nohwcursor) {
tdfx_outl(HWCURPATADDR, 0); tdfx_outl(HWCURPATADDR, 0);
} else {
tdfx_outl(HWCURPATADDR, reg->curspataddr);
tdfx_outl(HWCURC0, reg->cursc0);
tdfx_outl(HWCURC1, reg->cursc1);
tdfx_outl(HWCURLOC, reg->cursloc);
}
tdfx_outl(VIDSCREENSIZE, reg->screensize); tdfx_outl(VIDSCREENSIZE,reg->screensize);
tdfx_outl(VIDDESKSTART, reg->startaddr); tdfx_outl(VIDDESKSTART, reg->startaddr);
tdfx_outl(VIDPROCCFG, reg->vidcfg); tdfx_outl(VIDPROCCFG, reg->vidcfg);
tdfx_outl(VGAINIT1, reg->vgainit1); tdfx_outl(VGAINIT1, reg->vgainit1);
...@@ -852,7 +443,7 @@ static void do_write_regs(struct banshee_reg *reg) ...@@ -852,7 +443,7 @@ static void do_write_regs(struct banshee_reg *reg)
banshee_wait_idle(); banshee_wait_idle();
} }
static unsigned long do_lfb_size(void) static unsigned long do_lfb_size(unsigned short dev_id)
{ {
u32 draminit0 = 0; u32 draminit0 = 0;
u32 draminit1 = 0; u32 draminit1 = 0;
...@@ -863,14 +454,14 @@ static unsigned long do_lfb_size(void) ...@@ -863,14 +454,14 @@ static unsigned long do_lfb_size(void)
draminit0 = tdfx_inl(DRAMINIT0); draminit0 = tdfx_inl(DRAMINIT0);
draminit1 = tdfx_inl(DRAMINIT1); draminit1 = tdfx_inl(DRAMINIT1);
if ((fb_info.dev == PCI_DEVICE_ID_3DFX_BANSHEE) || if ((dev_id == PCI_DEVICE_ID_3DFX_BANSHEE) ||
(fb_info.dev == PCI_DEVICE_ID_3DFX_VOODOO3)) { (dev_id == PCI_DEVICE_ID_3DFX_VOODOO3)) {
sgram_p = (draminit1 & DRAMINIT1_MEM_SDRAM) ? 0 : 1; sgram_p = (draminit1 & DRAMINIT1_MEM_SDRAM) ? 0 : 1;
lfbsize = sgram_p ? lfbsize = sgram_p ?
(((draminit0 & DRAMINIT0_SGRAM_NUM) ? 2 : 1) * (((draminit0 & DRAMINIT0_SGRAM_NUM) ? 2 : 1) *
((draminit0 & DRAMINIT0_SGRAM_TYPE) ? 8 : 4) * 1024 * ((draminit0 & DRAMINIT0_SGRAM_TYPE) ? 8 : 4) * 1024 * 1024) :
1024) : 16 * 1024 * 1024; 16 * 1024 * 1024;
} else { } else {
/* Voodoo4/5 */ /* Voodoo4/5 */
u32 chips, psize, banks; u32 chips, psize, banks;
...@@ -881,7 +472,6 @@ static unsigned long do_lfb_size(void) ...@@ -881,7 +472,6 @@ static unsigned long do_lfb_size(void)
lfbsize = chips * psize * banks; lfbsize = chips * psize * banks;
lfbsize <<= 20; lfbsize <<= 20;
} }
/* disable block writes for SDRAM (why?) */ /* disable block writes for SDRAM (why?) */
miscinit1 = tdfx_inl(MISCINIT1); miscinit1 = tdfx_inl(MISCINIT1);
miscinit1 |= sgram_p ? 0 : MISCINIT1_2DBLOCK_DIS; miscinit1 |= sgram_p ? 0 : MISCINIT1_2DBLOCK_DIS;
...@@ -889,306 +479,155 @@ static unsigned long do_lfb_size(void) ...@@ -889,306 +479,155 @@ static unsigned long do_lfb_size(void)
banshee_make_room(1); banshee_make_room(1);
tdfx_outl(MISCINIT1, miscinit1); tdfx_outl(MISCINIT1, miscinit1);
return lfbsize; return lfbsize;
} }
/* ------------------------------------------------------------------------- /* ------------------------------------------------------------------------- */
* Hardware independent part, interface to the world
* ------------------------------------------------------------------------- */
#define tdfx_cfb24_putc tdfx_cfb32_putc
#define tdfx_cfb24_putcs tdfx_cfb32_putcs
#define tdfx_cfb24_clear tdfx_cfb32_clear
static void tdfx_cfbX_clear_margins(struct vc_data *conp, static int tdfxfb_check_var(struct fb_var_screeninfo *var,struct fb_info *info)
struct display *p, int bottom_only)
{ {
unsigned int cw = fontwidth(p); struct tdfx_par *par = (struct tdfx_par *) info->par;
unsigned int ch = fontheight(p); u32 lpitch;
unsigned int rw = p->var.xres % cw; // it be in a non-standard mode or not?
unsigned int bh = p->var.yres % ch;
unsigned int rs = p->var.xres - rw;
unsigned int bs = p->var.yres - bh;
if (!bottom_only && rw) {
do_fillrect(p->var.xoffset + rs, 0,
rw, p->var.yres_virtual, 0,
fb_info.current_par.lpitch,
fb_info.current_par.bpp, TDFX_ROP_COPY);
}
if (bh) { if (var->bits_per_pixel != 8 && var->bits_per_pixel != 16 &&
do_fillrect(p->var.xoffset, p->var.yoffset + bs, var->bits_per_pixel != 24 && var->bits_per_pixel != 32) {
rs, bh, 0, DPRINTK("depth not supported: %u\n", var->bits_per_pixel);
fb_info.current_par.lpitch, return -EINVAL;
fb_info.current_par.bpp, TDFX_ROP_COPY);
} }
}
static void tdfx_cfbX_bmove(struct display *p,
int sy,
int sx, int dy, int dx, int height, int width)
{
do_bitblt(fontwidth(p) * sx,
fontheight(p) * sy,
fontwidth(p) * dx,
fontheight(p) * dy,
fontwidth(p) * width,
fontheight(p) * height,
fb_info.current_par.lpitch, fb_info.current_par.bpp);
}
static void tdfx_cfb8_putc(struct vc_data *conp,
struct display *p, int c, int yy, int xx)
{
u32 fgx, bgx;
fgx = attr_fgcol(p, c);
bgx = attr_bgcol(p, c);
do_putc(fgx, bgx, p, c, yy, xx);
}
static void tdfx_cfb16_putc(struct vc_data *conp, if (var->xres != var->xres_virtual) {
struct display *p, int c, int yy, int xx) DPRINTK("virtual x resolution != physical x resolution not supported\n");
{ return -EINVAL;
u32 fgx, bgx; }
fgx = ((u16 *) p->dispsw_data)[attr_fgcol(p, c)];
bgx = ((u16 *) p->dispsw_data)[attr_bgcol(p, c)];
do_putc(fgx, bgx, p, c, yy, xx);
}
static void tdfx_cfb32_putc(struct vc_data *conp, if (var->yres > var->yres_virtual) {
struct display *p, int c, int yy, int xx) DPRINTK("virtual y resolution < physical y resolution not possible\n");
{ return -EINVAL;
u32 fgx, bgx; }
fgx = ((u32 *) p->dispsw_data)[attr_fgcol(p, c)];
bgx = ((u32 *) p->dispsw_data)[attr_bgcol(p, c)];
do_putc(fgx, bgx, p, c, yy, xx);
}
static void tdfx_cfb8_putcs(struct vc_data *conp,
struct display *p,
const unsigned short *s, int count, int yy,
int xx)
{
u16 c = scr_readw(s);
u32 fgx = attr_fgcol(p, c);
u32 bgx = attr_bgcol(p, c);
do_putcs(fgx, bgx, p, s, count, yy, xx);
}
static void tdfx_cfb16_putcs(struct vc_data *conp,
struct display *p,
const unsigned short *s, int count, int yy,
int xx)
{
u16 c = scr_readw(s);
u32 fgx = ((u16 *) p->dispsw_data)[attr_fgcol(p, c)];
u32 bgx = ((u16 *) p->dispsw_data)[attr_bgcol(p, c)];
do_putcs(fgx, bgx, p, s, count, yy, xx);
}
static void tdfx_cfb32_putcs(struct vc_data *conp,
struct display *p,
const unsigned short *s, int count, int yy,
int xx)
{
u16 c = scr_readw(s);
u32 fgx = ((u32 *) p->dispsw_data)[attr_fgcol(p, c)];
u32 bgx = ((u32 *) p->dispsw_data)[attr_bgcol(p, c)];
do_putcs(fgx, bgx, p, s, count, yy, xx);
}
static void tdfx_cfb8_clear(struct vc_data *conp, if (var->xoffset) {
struct display *p, DPRINTK("xoffset not supported\n");
int sy, int sx, int height, int width) return -EINVAL;
{ }
u32 bg;
bg = attr_bgcol_ec(p, conp);
do_fillrect(fontwidth(p) * sx,
fontheight(p) * sy,
fontwidth(p) * width,
fontheight(p) * height,
bg,
fb_info.current_par.lpitch,
fb_info.current_par.bpp, TDFX_ROP_COPY);
}
static void tdfx_cfb16_clear(struct vc_data *conp, /* fixme: does Voodoo3 support interlace? Banshee doesn't */
struct display *p, if ((var->vmode & FB_VMODE_MASK) == FB_VMODE_INTERLACED) {
int sy, int sx, int height, int width) DPRINTK("interlace not supported\n");
{ return -EINVAL;
u32 bg; }
bg = ((u16 *) p->dispsw_data)[attr_bgcol_ec(p, conp)];
do_fillrect(fontwidth(p) * sx,
fontheight(p) * sy,
fontwidth(p) * width,
fontheight(p) * height,
bg,
fb_info.current_par.lpitch,
fb_info.current_par.bpp, TDFX_ROP_COPY);
}
static void tdfx_cfb32_clear(struct vc_data *conp, var->xres = (var->xres + 15) & ~15; /* could sometimes be 8 */
struct display *p, lpitch = var->xres * ((var->bits_per_pixel + 7)>>3);
int sy, int sx, int height, int width)
{
u32 bg;
bg = ((u32 *) p->dispsw_data)[attr_bgcol_ec(p, conp)];
do_fillrect(fontwidth(p) * sx,
fontheight(p) * sy,
fontwidth(p) * width,
fontheight(p) * height,
bg,
fb_info.current_par.lpitch,
fb_info.current_par.bpp, TDFX_ROP_COPY);
}
static void tdfx_cfbX_revc(struct display *p, int xx, int yy)
{
int bpp = fb_info.current_par.bpp;
do_fillrect(xx * fontwidth(p), yy * fontheight(p), if (var->xres < 320 || var->xres > 2048) {
fontwidth(p), fontheight(p), DPRINTK("width not supported: %u\n", var->xres);
(bpp == 8) ? 0x0f : 0xffffffff, return -EINVAL;
fb_info.current_par.lpitch, bpp, TDFX_ROP_XOR); }
} if (var->yres < 200 || var->yres > 2048) {
static void tdfx_cfbX_cursor(struct display *p, int mode, int x, int y) DPRINTK("height not supported: %u\n", var->yres);
{ return -EINVAL;
unsigned long flags;
int tip;
struct fb_info_tdfx *info = (struct fb_info_tdfx *) p->fb_info;
tip = p->conp->vc_cursor_type & CUR_HWMASK;
if (mode == CM_ERASE) {
if (info->cursor.state != CM_ERASE) {
spin_lock_irqsave(&info->DAClock, flags);
info->cursor.state = CM_ERASE;
del_timer(&(info->cursor.timer));
tdfx_outl(VIDPROCCFG, info->cursor.disable);
spin_unlock_irqrestore(&info->DAClock, flags);
} }
return;
if (lpitch * var->yres_virtual > info->fix.smem_len) {
DPRINTK("no memory for screen (%ux%ux%u)\n",
var->xres, var->yres_virtual, var->bits_per_pixel);
return -EINVAL;
} }
if ((p->conp->vc_cursor_type & CUR_HWMASK) != info->cursor.type)
tdfxfb_createcursor(p); if (PICOS2KHZ(var->pixclock) > par->max_pixclock) {
x *= fontwidth(p); DPRINTK("pixclock too high (%ldKHz)\n",PICOS2KHZ(var->pixclock));
y *= fontheight(p); return -EINVAL;
y -= p->var.yoffset;
spin_lock_irqsave(&info->DAClock, flags);
if ((x != info->cursor.x) ||
(y != info->cursor.y) || (info->cursor.redraw)) {
info->cursor.x = x;
info->cursor.y = y;
info->cursor.redraw = 0;
x += 63;
y += 63;
banshee_make_room(2);
tdfx_outl(VIDPROCCFG, info->cursor.disable);
tdfx_outl(HWCURLOC, (y << 16) + x);
/* fix cursor color - XFree86 forgets to restore it properly */
tdfx_outl(HWCURC0, 0);
tdfx_outl(HWCURC1, 0xffffff);
} }
info->cursor.state = CM_DRAW;
mod_timer(&info->cursor.timer, jiffies + HZ / 2);
banshee_make_room(1);
tdfx_outl(VIDPROCCFG, info->cursor.enable);
spin_unlock_irqrestore(&info->DAClock, flags);
return;
}
#ifdef FBCON_HAS_CFB8 switch(var->bits_per_pixel) {
static struct display_switch fbcon_banshee8 = { case 8:
setup:fbcon_cfb8_setup, var->red.length = var->green.length = var->blue.length = 8;
bmove:tdfx_cfbX_bmove, break;
clear:tdfx_cfb8_clear, case 16:
putc:tdfx_cfb8_putc, var->red.offset = 11;
putcs:tdfx_cfb8_putcs, var->red.length = 5;
revc:tdfx_cfbX_revc, var->green.offset = 5;
cursor:tdfx_cfbX_cursor, var->green.length = 6;
clear_margins:tdfx_cfbX_clear_margins, var->blue.offset = 0;
fontwidthmask:FONTWIDTHRANGE(8, 12) var->blue.length = 5;
}; break;
#endif case 24:
#ifdef FBCON_HAS_CFB16 var->red.offset=16;
static struct display_switch fbcon_banshee16 = { var->green.offset=8;
setup:fbcon_cfb16_setup, var->blue.offset=0;
bmove:tdfx_cfbX_bmove, var->red.length = var->green.length = var->blue.length = 8;
clear:tdfx_cfb16_clear, case 32:
putc:tdfx_cfb16_putc, var->red.offset = 16;
putcs:tdfx_cfb16_putcs, var->green.offset = 8;
revc:tdfx_cfbX_revc, var->blue.offset = 0;
cursor:tdfx_cfbX_cursor, var->red.length = var->green.length = var->blue.length = 8;
clear_margins:tdfx_cfbX_clear_margins, break;
fontwidthmask:FONTWIDTHRANGE(8, 12) }
}; var->height = var->width = -1;
#endif
#ifdef FBCON_HAS_CFB24
static struct display_switch fbcon_banshee24 = {
setup:fbcon_cfb24_setup,
bmove:tdfx_cfbX_bmove,
clear:tdfx_cfb24_clear,
putc:tdfx_cfb24_putc,
putcs:tdfx_cfb24_putcs,
revc:tdfx_cfbX_revc,
cursor:tdfx_cfbX_cursor,
clear_margins:tdfx_cfbX_clear_margins,
fontwidthmask:FONTWIDTHRANGE(8, 12)
};
#endif
#ifdef FBCON_HAS_CFB32
static struct display_switch fbcon_banshee32 = {
setup:fbcon_cfb32_setup,
bmove:tdfx_cfbX_bmove,
clear:tdfx_cfb32_clear,
putc:tdfx_cfb32_putc,
putcs:tdfx_cfb32_putcs,
revc:tdfx_cfbX_revc,
cursor:tdfx_cfbX_cursor,
clear_margins:tdfx_cfbX_clear_margins,
fontwidthmask:FONTWIDTHRANGE(8, 12)
};
#endif
/* ------------------------------------------------------------------------- */ var->accel_flags = FB_ACCELF_TEXT;
DPRINTK("Checking graphics mode at %dx%d depth %d\n", var->xres, var->yres, var->bits_per_pixel);
return 0;
}
static void tdfxfb_set_par(const struct tdfxfb_par *par, static int tdfxfb_set_par(struct fb_info *info)
struct fb_info_tdfx *info)
{ {
struct fb_info_tdfx *i = (struct fb_info_tdfx *) info; struct tdfx_par *par = (struct tdfx_par *) info->par;
struct banshee_reg reg; u32 hdispend, hsyncsta, hsyncend, htotal;
u32 cpp;
u32 hd, hs, he, ht, hbs, hbe; u32 hd, hs, he, ht, hbs, hbe;
u32 vd, vs, ve, vt, vbs, vbe; u32 vd, vs, ve, vt, vbs, vbe;
u32 wd; struct banshee_reg reg;
int fout; int fout, freq;
int freq; u32 wd, cpp;
info->cmap.len = (info->var.bits_per_pixel == 8) ? 256 : 16;
par->baseline = 0;
memset(&reg, 0, sizeof(reg)); memset(&reg, 0, sizeof(reg));
cpp = (info->var.bits_per_pixel + 7)/8;
reg.vidcfg = VIDCFG_VIDPROC_ENABLE | VIDCFG_DESK_ENABLE | VIDCFG_CURS_X11 | ((cpp - 1) << VIDCFG_PIXFMT_SHIFT) | (cpp != 1 ? VIDCFG_CLUT_BYPASS : 0);
cpp = (par->bpp + 7) / 8; /* PLL settings */
freq = PICOS2KHZ(info->var.pixclock);
reg.dacmode = 0;
reg.vidcfg &= ~VIDCFG_2X;
wd = (par->hdispend >> 3) - 1; hdispend = info->var.xres;
hsyncsta = hdispend + info->var.right_margin;
hsyncend = hsyncsta + info->var.hsync_len;
htotal = hsyncend + info->var.left_margin;
if (freq > par->max_pixclock/2) {
freq = freq > par->max_pixclock ? par->max_pixclock : freq;
reg.dacmode |= DACMODE_2X;
reg.vidcfg |= VIDCFG_2X;
hdispend >>= 1;
hsyncsta >>= 1;
hsyncend >>= 1;
htotal >>= 1;
}
hd = (par->hdispend >> 3) - 1; hd = wd = (hdispend >> 3) - 1;
hs = (par->hsyncsta >> 3) - 1; hs = (hsyncsta >> 3) - 1;
he = (par->hsyncend >> 3) - 1; he = (hsyncend >> 3) - 1;
ht = (par->htotal >> 3) - 1; ht = (htotal >> 3) - 1;
hbs = hd; hbs = hd;
hbe = ht; hbe = ht;
vd = par->vdispend - 1; vbs = vd = info->var.yres - 1;
vs = par->vsyncsta - 1; vs = vd + info->var.lower_margin;
ve = par->vsyncend - 1; ve = vs + info->var.vsync_len;
vt = par->vtotal - 2; vbe = vt = ve + info->var.upper_margin - 1;
vbs = vd;
vbe = vt;
/* this is all pretty standard VGA register stuffing */ /* this is all pretty standard VGA register stuffing */
reg.misc[0x00] = reg.misc[0x00] = 0x0f |
0x0f | (info->var.xres < 400 ? 0xa0 :
(par->hdispend < 400 ? 0xa0 : info->var.xres < 480 ? 0x60 :
par->hdispend < 480 ? 0x60 : info->var.xres < 768 ? 0xe0 : 0x20);
par->hdispend < 768 ? 0xe0 : 0x20);
reg.gra[0x00] = 0x00; reg.gra[0x00] = 0x00;
reg.gra[0x01] = 0x00; reg.gra[0x01] = 0x00;
...@@ -1235,14 +674,13 @@ static void tdfxfb_set_par(const struct tdfxfb_par *par, ...@@ -1235,14 +674,13 @@ static void tdfxfb_set_par(const struct tdfxfb_par *par,
reg.crt[0x04] = hs; reg.crt[0x04] = hs;
reg.crt[0x05] = ((hbe & 0x20) << 2) | (he & 0x1f); reg.crt[0x05] = ((hbe & 0x20) << 2) | (he & 0x1f);
reg.crt[0x06] = vt; reg.crt[0x06] = vt;
reg.crt[0x07] = reg.crt[0x07] = ((vs & 0x200) >> 2) |
((vs & 0x200) >> 2) |
((vd & 0x200) >> 3) | ((vd & 0x200) >> 3) |
((vt & 0x200) >> 4) | ((vt & 0x200) >> 4) | 0x10 |
0x10 |
((vbs & 0x100) >> 5) | ((vbs & 0x100) >> 5) |
((vs & 0x100) >> 6) | ((vs & 0x100) >> 6) |
((vd & 0x100) >> 7) | ((vt & 0x100) >> 8); ((vd & 0x100) >> 7) |
((vt & 0x100) >> 8);
reg.crt[0x08] = 0x00; reg.crt[0x08] = 0x00;
reg.crt[0x09] = 0x40 | ((vbs & 0x200) >> 4); reg.crt[0x09] = 0x40 | ((vbs & 0x200) >> 4);
reg.crt[0x0a] = 0x00; reg.crt[0x0a] = 0x00;
...@@ -1266,47 +704,37 @@ static void tdfxfb_set_par(const struct tdfxfb_par *par, ...@@ -1266,47 +704,37 @@ static void tdfxfb_set_par(const struct tdfxfb_par *par,
((hd & 0x100) >> 6) | ((hd & 0x100) >> 6) |
((hbs & 0x100) >> 4) | ((hbs & 0x100) >> 4) |
((hbe & 0x40) >> 1) | ((hbe & 0x40) >> 1) |
((hs & 0x100) >> 2) | ((he & 0x20) << 2)); ((hs & 0x100) >> 2) |
((he & 0x20) << 2));
reg.ext[0x01] = (((vt & 0x400) >> 10) | reg.ext[0x01] = (((vt & 0x400) >> 10) |
((vd & 0x400) >> 8) | ((vd & 0x400) >> 8) |
((vbs & 0x400) >> 6) | ((vbe & 0x400) >> 4)); ((vbs & 0x400) >> 6) |
((vbe & 0x400) >> 4));
reg.vgainit0 = reg.vgainit0 = VGAINIT0_8BIT_DAC |
VGAINIT0_8BIT_DAC |
VGAINIT0_EXT_ENABLE | VGAINIT0_EXT_ENABLE |
VGAINIT0_WAKEUP_3C3 | VGAINIT0_WAKEUP_3C3 |
VGAINIT0_ALT_READBACK | VGAINIT0_EXTSHIFTOUT; VGAINIT0_ALT_READBACK |
VGAINIT0_EXTSHIFTOUT;
reg.vgainit1 = tdfx_inl(VGAINIT1) & 0x1fffff; reg.vgainit1 = tdfx_inl(VGAINIT1) & 0x1fffff;
reg.vidcfg =
VIDCFG_VIDPROC_ENABLE |
VIDCFG_DESK_ENABLE |
VIDCFG_CURS_X11 |
((cpp - 1) << VIDCFG_PIXFMT_SHIFT) |
(cpp != 1 ? VIDCFG_CLUT_BYPASS : 0);
fb_info.cursor.enable = reg.vidcfg | VIDCFG_HWCURSOR_ENABLE;
fb_info.cursor.disable = reg.vidcfg;
reg.stride = par->width * cpp;
reg.cursloc = 0; reg.cursloc = 0;
reg.cursc0 = 0; reg.cursc0 = 0;
reg.cursc1 = 0xffffff; reg.cursc1 = 0xffffff;
reg.curspataddr = fb_info.cursor.cursorimage; reg.stride = info->var.xres * cpp;
reg.startaddr = par->baseline * reg.stride; reg.startaddr = par->baseline * reg.stride;
reg.srcbase = reg.startaddr; reg.srcbase = reg.startaddr;
reg.dstbase = reg.startaddr; reg.dstbase = reg.startaddr;
/* PLL settings */ /* PLL settings */
freq = par->pixclock; freq = PICOS2KHZ(info->var.pixclock);
reg.dacmode &= ~DACMODE_2X; reg.dacmode &= ~DACMODE_2X;
reg.vidcfg &= ~VIDCFG_2X; reg.vidcfg &= ~VIDCFG_2X;
if (freq > i->max_pixclock / 2) { if (freq > par->max_pixclock/2) {
freq = freq > i->max_pixclock ? i->max_pixclock : freq; freq = freq > par->max_pixclock ? par->max_pixclock : freq;
reg.dacmode |= DACMODE_2X; reg.dacmode |= DACMODE_2X;
reg.vidcfg |= VIDCFG_2X; reg.vidcfg |= VIDCFG_2X;
} }
...@@ -1316,13 +744,12 @@ static void tdfxfb_set_par(const struct tdfxfb_par *par, ...@@ -1316,13 +744,12 @@ static void tdfxfb_set_par(const struct tdfxfb_par *par,
reg.gfxpll = do_calc_pll(..., &fout); reg.gfxpll = do_calc_pll(..., &fout);
#endif #endif
reg.screensize = par->width | (par->height << 12); reg.screensize = info->var.xres | (info->var.yres << 12);
reg.vidcfg &= ~VIDCFG_HALF_MODE; reg.vidcfg &= ~VIDCFG_HALF_MODE;
reg.miscinit0 = tdfx_inl(MISCINIT0); reg.miscinit0 = tdfx_inl(MISCINIT0);
#if defined(__BIG_ENDIAN) #if defined(__BIG_ENDIAN)
switch (par->bpp) { switch (info->var.bits_per_pixel) {
case 8: case 8:
reg.miscinit0 &= ~(1 << 30); reg.miscinit0 &= ~(1 << 30);
reg.miscinit0 &= ~(1 << 31); reg.miscinit0 &= ~(1 << 31);
...@@ -1338,431 +765,211 @@ static void tdfxfb_set_par(const struct tdfxfb_par *par, ...@@ -1338,431 +765,211 @@ static void tdfxfb_set_par(const struct tdfxfb_par *par,
break; break;
} }
#endif #endif
do_write_regs(&reg); do_write_regs(&reg);
i->current_par = *par; /* Now change fb_fix_screeninfo according to changes in par */
info->fix.line_length = info->var.xres * ((info->var.bits_per_pixel + 7)>>3);
info->fix.visual = (info->var.bits_per_pixel == 8)
? FB_VISUAL_PSEUDOCOLOR
: FB_VISUAL_TRUECOLOR;
DPRINTK("Graphics mode is now set at %dx%d depth %d\n", info->var.xres, info->var.yres, info->var.bits_per_pixel);
return 0;
} }
static int tdfxfb_decode_var(const struct fb_var_screeninfo *var, static int tdfxfb_setcolreg(unsigned regno, unsigned red, unsigned green,
struct tdfxfb_par *par, unsigned blue,unsigned transp,struct fb_info *info)
const struct fb_info_tdfx *info)
{ {
struct fb_info_tdfx *i = (struct fb_info_tdfx *) info; u32 rgbcol;
if (var->bits_per_pixel != 8 &&
var->bits_per_pixel != 16 &&
var->bits_per_pixel != 24 && var->bits_per_pixel != 32) {
DPRINTK("depth not supported: %u\n", var->bits_per_pixel);
return -EINVAL;
}
if ((var->vmode & FB_VMODE_MASK) == FB_VMODE_INTERLACED) {
DPRINTK("interlace not supported\n");
return -EINVAL;
}
if (var->xoffset) {
DPRINTK("xoffset not supported\n");
return -EINVAL;
}
if (var->xres != var->xres_virtual) {
DPRINTK
("virtual x resolution != physical x resolution not supported\n");
return -EINVAL;
}
if (var->yres > var->yres_virtual) {
DPRINTK
("virtual y resolution < physical y resolution not possible\n");
return -EINVAL;
}
/* fixme: does Voodoo3 support interlace? Banshee doesn't */
if ((var->vmode & FB_VMODE_MASK) == FB_VMODE_INTERLACED) {
DPRINTK("interlace not supported\n");
return -EINVAL;
}
memset(par, 0, sizeof(struct tdfxfb_par));
switch (i->dev) {
case PCI_DEVICE_ID_3DFX_BANSHEE:
case PCI_DEVICE_ID_3DFX_VOODOO3:
case PCI_DEVICE_ID_3DFX_VOODOO5:
par->width = (var->xres + 15) & ~15; /* could sometimes be 8 */
par->width_virt = par->width;
par->height = var->yres;
par->height_virt = var->yres_virtual;
par->bpp = var->bits_per_pixel;
par->ppitch = var->bits_per_pixel;
par->lpitch = par->width * ((par->ppitch + 7) >> 3);
par->cmap_len = (par->bpp == 8) ? 256 : 16;
par->baseline = 0;
if (par->width < 320 || par->width > 2048) {
DPRINTK("width not supported: %u\n", par->width);
return -EINVAL;
}
if (par->height < 200 || par->height > 2048) {
DPRINTK("height not supported: %u\n", par->height);
return -EINVAL;
}
if (par->lpitch * par->height_virt > i->bufbase_size) {
DPRINTK("no memory for screen (%ux%ux%u)\n",
par->width, par->height_virt, par->bpp);
return -EINVAL;
}
par->pixclock = PICOS2KHZ(var->pixclock);
if (par->pixclock > i->max_pixclock) {
DPRINTK("pixclock too high (%uKHz)\n",
par->pixclock);
return -EINVAL;
}
par->hdispend = var->xres;
par->hsyncsta = par->hdispend + var->right_margin;
par->hsyncend = par->hsyncsta + var->hsync_len;
par->htotal = par->hsyncend + var->left_margin;
par->vdispend = var->yres;
par->vsyncsta = par->vdispend + var->lower_margin;
par->vsyncend = par->vsyncsta + var->vsync_len;
par->vtotal = par->vsyncend + var->upper_margin;
if (var->sync & FB_SYNC_HOR_HIGH_ACT)
par->video |= TDFXF_HSYNC_ACT_HIGH;
else
par->video |= TDFXF_HSYNC_ACT_LOW;
if (var->sync & FB_SYNC_VERT_HIGH_ACT)
par->video |= TDFXF_VSYNC_ACT_HIGH;
else
par->video |= TDFXF_VSYNC_ACT_LOW;
if ((var->vmode & FB_VMODE_MASK) == FB_VMODE_DOUBLE)
par->video |= TDFXF_LINE_DOUBLE;
if (var->activate == FB_ACTIVATE_NOW)
par->video |= TDFXF_VIDEO_ENABLE;
}
if (var->accel_flags & FB_ACCELF_TEXT)
par->accel_flags = FB_ACCELF_TEXT;
else
par->accel_flags = 0;
return 0; if (regno >= info->cmap.len) return 1;
}
static int tdfxfb_encode_var(struct fb_var_screeninfo *var, switch (info->fix.visual) {
const struct tdfxfb_par *par, case FB_VISUAL_PSEUDOCOLOR:
const struct fb_info_tdfx *info) rgbcol =(((u32)red & 0xff00) << 8) |
{ (((u32)green & 0xff00) << 0) |
struct fb_var_screeninfo v; (((u32)blue & 0xff00) >> 8);
do_setpalentry(regno, rgbcol);
memset(&v, 0, sizeof(struct fb_var_screeninfo));
v.xres_virtual = par->width_virt;
v.yres_virtual = par->height_virt;
v.xres = par->width;
v.yres = par->height;
v.right_margin = par->hsyncsta - par->hdispend;
v.hsync_len = par->hsyncend - par->hsyncsta;
v.left_margin = par->htotal - par->hsyncend;
v.lower_margin = par->vsyncsta - par->vdispend;
v.vsync_len = par->vsyncend - par->vsyncsta;
v.upper_margin = par->vtotal - par->vsyncend;
v.bits_per_pixel = par->bpp;
switch (par->bpp) {
case 8:
v.red.length = v.green.length = v.blue.length = 8;
break; break;
case 16: /* Truecolor has no hardware color palettes. */
v.red.offset = 11; case FB_VISUAL_TRUECOLOR:
v.red.length = 5; rgbcol = (red << info->var.red.offset) |
v.green.offset = 5; (green << info->var.green.offset) |
v.green.length = 6; (blue << info->var.blue.offset) |
v.blue.offset = 0; (transp << info->var.transp.offset);
v.blue.length = 5; if (info->var.bits_per_pixel <= 16)
((u16*)(info->pseudo_palette))[regno] = rgbcol;
else
((u32*)(info->pseudo_palette))[regno] = rgbcol;
break; break;
case 24: default:
v.red.offset = 16; DPRINTK("bad depth %u\n", info->var.bits_per_pixel);
v.green.offset = 8;
v.blue.offset = 0;
v.red.length = v.green.length = v.blue.length = 8;
case 32:
v.red.offset = 16;
v.green.offset = 8;
v.blue.offset = 0;
v.red.length = v.green.length = v.blue.length = 8;
break; break;
} }
v.height = v.width = -1;
v.pixclock = KHZ2PICOS(par->pixclock);
if ((par->video & TDFXF_HSYNC_MASK) == TDFXF_HSYNC_ACT_HIGH)
v.sync |= FB_SYNC_HOR_HIGH_ACT;
if ((par->video & TDFXF_VSYNC_MASK) == TDFXF_VSYNC_ACT_HIGH)
v.sync |= FB_SYNC_VERT_HIGH_ACT;
if (par->video & TDFXF_LINE_DOUBLE)
v.vmode = FB_VMODE_DOUBLE;
*var = v;
return 0; return 0;
} }
static int tdfxfb_encode_fix(struct fb_fix_screeninfo *fix, /* 0 unblank, 1 blank, 2 no vsync, 3 no hsync, 4 off */
const struct tdfxfb_par *par, static int tdfxfb_blank(int blank, struct fb_info *info)
const struct fb_info_tdfx *info)
{ {
memset(fix, 0, sizeof(struct fb_fix_screeninfo)); u32 dacmode, state = 0, vgablank = 0;
switch (info->dev) { dacmode = tdfx_inl(DACMODE);
case PCI_DEVICE_ID_3DFX_BANSHEE:
strcpy(fix->id, "3Dfx Banshee"); switch (blank) {
case 0: /* Screen: On; HSync: On, VSync: On */
state = 0;
vgablank = 0;
break; break;
case PCI_DEVICE_ID_3DFX_VOODOO3: case 1: /* Screen: Off; HSync: On, VSync: On */
strcpy(fix->id, "3Dfx Voodoo3"); state = 0;
vgablank = 1;
break; break;
case PCI_DEVICE_ID_3DFX_VOODOO5: case 2: /* Screen: Off; HSync: On, VSync: Off */
strcpy(fix->id, "3Dfx Voodoo5"); state = BIT(3);
vgablank = 1;
break;
case 3: /* Screen: Off; HSync: Off, VSync: On */
state = BIT(1);
vgablank = 1;
break;
case 4: /* Screen: Off; HSync: Off, VSync: Off */
state = BIT(1) | BIT(3);
vgablank = 1;
break; break;
default:
return -EINVAL;
} }
fix->smem_start = info->bufbase_phys; dacmode &= ~(BIT(1) | BIT(3));
fix->smem_len = info->bufbase_size; dacmode |= state;
fix->mmio_start = info->regbase_phys; banshee_make_room(1);
fix->mmio_len = info->regbase_size; tdfx_outl(DACMODE, dacmode);
fix->accel = FB_ACCEL_3DFX_BANSHEE; if (vgablank)
fix->type = FB_TYPE_PACKED_PIXELS; vga_disable_video();
fix->type_aux = 0; else
fix->line_length = par->lpitch; vga_enable_video();
fix->visual = (par->bpp == 8)
? FB_VISUAL_PSEUDOCOLOR : FB_VISUAL_DIRECTCOLOR;
fix->xpanstep = 0;
fix->ypanstep = nopan ? 0 : 1;
fix->ywrapstep = nowrap ? 0 : 1;
return 0; return 0;
} }
static int tdfxfb_get_fix(struct fb_fix_screeninfo *fix, /*
int con, struct fb_info *fb) * Set the starting position of the visible screen to var->yoffset
*/
static int tdfxfb_pan_display(struct fb_var_screeninfo *var, int con,
struct fb_info *info)
{ {
const struct fb_info_tdfx *info = (struct fb_info_tdfx *) fb; u32 addr;
struct tdfxfb_par par;
if (con == -1) if (nopan || var->xoffset || (var->yoffset > var->yres_virtual))
par = info->default_par; return -EINVAL;
else if ((var->yoffset + var->yres > var->yres_virtual && nowrap))
tdfxfb_decode_var(&fb_display[con].var, &par, info); return -EINVAL;
tdfxfb_encode_fix(fix, &par, info);
return 0;
}
static int tdfxfb_get_var(struct fb_var_screeninfo *var, addr = var->yoffset * info->fix.line_length;
int con, struct fb_info *fb) banshee_make_room(1);
{ tdfx_outl(VIDDESKSTART, addr);
const struct fb_info_tdfx *info = (struct fb_info_tdfx *) fb;
if (con == -1) info->var.xoffset = var->xoffset;
tdfxfb_encode_var(var, &info->default_par, info); info->var.yoffset = var->yoffset;
else
*var = fb_display[con].var;
return 0; return 0;
} }
static void tdfxfb_set_dispsw(struct display *disp, /*
struct fb_info_tdfx *info, * FillRect 2D command (solidfill or invert (via ROP_XOR))
int bpp, int accel) */
static void tdfxfb_fillrect(struct fb_info *info, struct fb_fillrect *rect)
{ {
u32 bpp = info->var.bits_per_pixel;
u32 stride = info->fix.line_length;
u32 fmt= stride | ((bpp+((bpp==8) ? 0 : 8)) << 13);
int tdfx_rop;
if (disp->dispsw && disp->conp) if (rect->rop == ROP_COPY)
fb_con.con_cursor(disp->conp, CM_ERASE); tdfx_rop = TDFX_ROP_COPY;
switch (bpp) { else
#ifdef FBCON_HAS_CFB8 tdfx_rop = TDFX_ROP_XOR;
case 8:
disp->dispsw = noaccel ? &fbcon_cfb8 : &fbcon_banshee8;
if (nohwcursor)
fbcon_banshee8.cursor = NULL;
break;
#endif
#ifdef FBCON_HAS_CFB16
case 16:
disp->dispsw = noaccel ? &fbcon_cfb16 : &fbcon_banshee16;
disp->dispsw_data = info->fbcon_cmap.cfb16;
if (nohwcursor)
fbcon_banshee16.cursor = NULL;
break;
#endif
#ifdef FBCON_HAS_CFB24
case 24:
disp->dispsw = noaccel ? &fbcon_cfb24 : &fbcon_banshee24;
disp->dispsw_data = info->fbcon_cmap.cfb24;
if (nohwcursor)
fbcon_banshee24.cursor = NULL;
break;
#endif
#ifdef FBCON_HAS_CFB32
case 32:
disp->dispsw = noaccel ? &fbcon_cfb32 : &fbcon_banshee32;
disp->dispsw_data = info->fbcon_cmap.cfb32;
if (nohwcursor)
fbcon_banshee32.cursor = NULL;
break;
#endif
default:
disp->dispsw = &fbcon_dummy;
}
banshee_make_room(5);
tdfx_outl(DSTFORMAT, fmt);
tdfx_outl(COLORFORE, rect->color);
tdfx_outl(COMMAND_2D, COMMAND_2D_FILLRECT | (tdfx_rop << 24));
tdfx_outl(DSTSIZE, rect->width | (rect->height << 16));
tdfx_outl(LAUNCH_2D, rect->dx | (rect->dy << 16));
banshee_wait_idle();
} }
static int tdfxfb_set_var(struct fb_var_screeninfo *var, /*
int con, struct fb_info *fb) * Screen-to-Screen BitBlt 2D command (for the bmove fb op.)
*/
static void tdfxfb_copyarea(struct fb_info *info, struct fb_copyarea *area)
{ {
struct fb_info_tdfx *info = (struct fb_info_tdfx *) fb; u32 bpp = info->var.bits_per_pixel;
struct tdfxfb_par par; u32 stride = info->fix.line_length;
struct display *display; u32 blitcmd = COMMAND_2D_S2S_BITBLT | (TDFX_ROP_COPY << 24);
int oldxres, oldyres, oldvxres, oldvyres, oldbpp, oldaccel, accel, u32 fmt = stride | ((bpp+((bpp==8) ? 0 : 8)) << 13);
err;
int activate = var->activate;
int j, k;
if (con >= 0)
display = &fb_display[con];
else
display = fb->disp; /* used during initialization */
if ((err = tdfxfb_decode_var(var, &par, info)))
return err;
tdfxfb_encode_var(var, &par, info);
if ((activate & FB_ACTIVATE_MASK) == FB_ACTIVATE_NOW) {
oldxres = display->var.xres;
oldyres = display->var.yres;
oldvxres = display->var.xres_virtual;
oldvyres = display->var.yres_virtual;
oldbpp = display->var.bits_per_pixel;
oldaccel = display->var.accel_flags;
display->var = *var;
if (con < 0 ||
oldxres != var->xres ||
oldyres != var->yres ||
oldvxres != var->xres_virtual ||
oldvyres != var->yres_virtual ||
oldbpp != var->bits_per_pixel ||
oldaccel != var->accel_flags) {
struct fb_fix_screeninfo fix;
tdfxfb_encode_fix(&fix, &par, info);
display->visual = fix.visual;
display->type = fix.type;
display->type_aux = fix.type_aux;
display->ypanstep = fix.ypanstep;
display->ywrapstep = fix.ywrapstep;
display->line_length = fix.line_length;
display->next_line = fix.line_length;
display->can_soft_blank = 1;
display->inverse = inverse;
accel = var->accel_flags & FB_ACCELF_TEXT;
tdfxfb_set_dispsw(display, info, par.bpp, accel);
if (nopan)
display->scrollmode = SCROLL_YREDRAW;
if (info->fb_info.changevar)
(*info->fb_info.changevar) (con);
}
if (var->bits_per_pixel == 8)
for (j = 0; j < 16; j++) {
k = color_table[j];
fb_info.palette[j].red = default_red[k];
fb_info.palette[j].green = default_grn[k];
fb_info.palette[j].blue = default_blu[k];
}
del_timer(&(info->cursor.timer)); if (area->sx <= area->dx) {
fb_info.cursor.state = CM_ERASE; //-X
if (!info->fb_info.display_fg || blitcmd |= BIT(14);
info->fb_info.display_fg->vc_num == con || con < 0) area->sx += area->width - 1;
tdfxfb_set_par(&par, info); area->dx += area->width - 1;
if (!nohwcursor)
if (display && display->conp)
tdfxfb_createcursor(display);
info->cursor.redraw = 1;
if (oldbpp != var->bits_per_pixel || con < 0) {
if ((err = fb_alloc_cmap(&display->cmap, 0, 0)))
return err;
do_install_cmap(con, &(info->fb_info));
} }
if (area->sy <= area->dy) {
//-Y
blitcmd |= BIT(15);
area->sy += area->height - 1;
area->dy += area->height - 1;
} }
return 0; banshee_make_room(6);
}
static int tdfxfb_pan_display(struct fb_var_screeninfo *var,
int con, struct fb_info *fb)
{
struct fb_info_tdfx *i = (struct fb_info_tdfx *) fb;
if (nopan)
return -EINVAL;
if (var->xoffset)
return -EINVAL;
if (var->yoffset > var->yres_virtual)
return -EINVAL;
if (nowrap && (var->yoffset + var->yres > var->yres_virtual))
return -EINVAL;
if (con == fb->currcon)
do_pan_var(var, i);
fb_display[con].var.xoffset = var->xoffset; tdfx_outl(SRCFORMAT, fmt);
fb_display[con].var.yoffset = var->yoffset; tdfx_outl(DSTFORMAT, fmt);
return 0; tdfx_outl(COMMAND_2D, blitcmd);
tdfx_outl(DSTSIZE, area->width | (area->height << 16));
tdfx_outl(DSTXY, area->dx | (area->dy << 16));
tdfx_outl(LAUNCH_2D, area->sx | (area->sy << 16));
banshee_wait_idle();
} }
static int tdfxfb_get_cmap(struct fb_cmap *cmap, static void tdfxfb_imageblit(struct fb_info *info, struct fb_image *pixmap)
int kspc, int con, struct fb_info *fb)
{ {
int size = pixmap->height*((pixmap->width*pixmap->depth + 7)>>3);
int i, stride = info->fix.line_length;
u32 bpp = info->var.bits_per_pixel;
u32 dstfmt = stride | ((bpp+((bpp==8) ? 0 : 8)) << 13);
u8 *chardata = (u8 *) pixmap->data;
u32 srcfmt;
struct fb_info_tdfx *i = (struct fb_info_tdfx *) fb; if (pixmap->depth == 1) {
struct display *d = (con < 0) ? fb->disp : fb_display + con; banshee_make_room(8 + ((size + 3) >> 2));
tdfx_outl(COLORFORE, pixmap->fg_color);
if (con == fb->currcon) { tdfx_outl(COLORBACK, pixmap->bg_color);
/* current console? */ srcfmt = 0x400000;
return fb_get_cmap(cmap, kspc, tdfxfb_getcolreg, fb);
} else if (d->cmap.len) {
/* non default colormap? */
fb_copy_cmap(&d->cmap, cmap, kspc ? 0 : 2);
} else { } else {
fb_copy_cmap(fb_default_cmap(i->current_par.cmap_len), banshee_make_room(6 + ((size + 3) >> 2));
cmap, kspc ? 0 : 2); srcfmt = stride | ((bpp+((bpp==8) ? 0 : 8)) << 13) | 0x400000;
} }
return 0;
}
static int tdfxfb_set_cmap(struct fb_cmap *cmap,
int kspc, int con, struct fb_info *fb)
{
struct display *d = (con < 0) ? fb->disp : fb_display + con;
struct fb_info_tdfx *i = (struct fb_info_tdfx *) fb;
int cmap_len = (i->current_par.bpp == 8) ? 256 : 16; tdfx_outl(SRCXY, 0);
if (d->cmap.len != cmap_len) { tdfx_outl(DSTXY, pixmap->dx | (pixmap->dy << 16));
int err; tdfx_outl(COMMAND_2D, COMMAND_2D_H2S_BITBLT | (TDFX_ROP_COPY << 24));
if ((err = fb_alloc_cmap(&d->cmap, cmap_len, 0))) tdfx_outl(SRCFORMAT, srcfmt);
return err; tdfx_outl(DSTFORMAT, dstfmt);
tdfx_outl(DSTSIZE, pixmap->width | (pixmap->height << 16));
/* Send four bytes at a time of data */
for (i = (size >> 2) ; i > 0; i--) {
tdfx_outl(LAUNCH_2D,*(u32*)chardata);
chardata += 4;
} }
if (con == fb->currcon) {
/* current console? */ /* Send the leftovers now */
return fb_set_cmap(cmap, kspc, fb); i = size%4;
} else { switch (i) {
fb_copy_cmap(cmap, &d->cmap, kspc ? 0 : 1); case 0: break;
case 1: tdfx_outl(LAUNCH_2D,*chardata); break;
case 2: tdfx_outl(LAUNCH_2D,*(u16*)chardata); break;
case 3: tdfx_outl(LAUNCH_2D,*(u16*)chardata | ((chardata[3]) << 24)); break;
} }
return 0; banshee_wait_idle();
} }
/** /**
...@@ -1777,143 +984,132 @@ static int tdfxfb_set_cmap(struct fb_cmap *cmap, ...@@ -1777,143 +984,132 @@ static int tdfxfb_set_cmap(struct fb_cmap *cmap,
static int __devinit tdfxfb_probe(struct pci_dev *pdev, static int __devinit tdfxfb_probe(struct pci_dev *pdev,
const struct pci_device_id *id) const struct pci_device_id *id)
{ {
struct fb_var_screeninfo var; struct fb_info *info;
char *name = NULL; int size, err;
if ((err = pci_enable_device(pdev))) {
printk(KERN_WARNING "tdfxfb: Can't enable pdev: %d\n", err);
return err;
}
info = kmalloc(sizeof(struct fb_info) + sizeof(struct display) +
sizeof(u32) * 16, GFP_KERNEL);
if (!info) return -ENXIO;
fb_info.dev = pdev->device; memset(info, 0, sizeof(info) + sizeof(struct display) + sizeof(u32) * 16);
/* Configure the default fb_fix_screeninfo first */
switch (pdev->device) { switch (pdev->device) {
case PCI_DEVICE_ID_3DFX_BANSHEE: case PCI_DEVICE_ID_3DFX_BANSHEE:
fb_info.max_pixclock = BANSHEE_MAX_PIXCLOCK; strcat(tdfx_fix.id, " Banshee");
name = "Banshee"; default_par.max_pixclock = BANSHEE_MAX_PIXCLOCK;
break; break;
case PCI_DEVICE_ID_3DFX_VOODOO3: case PCI_DEVICE_ID_3DFX_VOODOO3:
fb_info.max_pixclock = VOODOO3_MAX_PIXCLOCK; strcat(tdfx_fix.id, " Voodoo3");
name = "Voodoo3"; default_par.max_pixclock = VOODOO3_MAX_PIXCLOCK;
break; break;
case PCI_DEVICE_ID_3DFX_VOODOO5: case PCI_DEVICE_ID_3DFX_VOODOO5:
fb_info.max_pixclock = VOODOO5_MAX_PIXCLOCK; strcat(tdfx_fix.id, " Voodoo5");
name = "Voodoo5"; default_par.max_pixclock = VOODOO5_MAX_PIXCLOCK;
break; break;
} }
fb_info.regbase_phys = pci_resource_start(pdev, 0); tdfx_fix.mmio_start = pci_resource_start(pdev, 0);
fb_info.regbase_size = 1 << 24; tdfx_fix.mmio_len = 1 << 24;
fb_info.regbase_virt = default_par.regbase_virt = ioremap_nocache(tdfx_fix.mmio_start, 1<<24);
ioremap_nocache(fb_info.regbase_phys, 1 << 24); if (!default_par.regbase_virt) {
printk("fb: Can't remap %s register area.\n", tdfx_fix.id);
if (!fb_info.regbase_virt) {
printk(KERN_WARNING "fb: Can't remap %s register area.\n",
name);
return -ENXIO; return -ENXIO;
} }
fb_info.bufbase_phys = pci_resource_start(pdev, 1); if (!request_mem_region(pci_resource_start(pdev, 0),
pci_resource_len(pdev, 0), "tdfx regbase")) {
if (!(fb_info.bufbase_size = do_lfb_size())) { printk(KERN_WARNING "tdfxfb: Can't reserve regbase\n");
iounmap(fb_info.regbase_virt); iounmap(default_par.regbase_virt);
printk(KERN_WARNING "fb: Can't count %s memory.\n", name);
return -ENXIO; return -ENXIO;
} }
fb_info.bufbase_virt = ioremap_nocache(fb_info.bufbase_phys, tdfx_fix.smem_start = pci_resource_start(pdev, 1);
fb_info.bufbase_size); if (!(tdfx_fix.smem_len = do_lfb_size(pdev->device))) {
iounmap(default_par.regbase_virt);
printk("fb: Can't count %s memory.\n", tdfx_fix.id);
return -ENXIO;
}
if (!fb_info.regbase_virt) { if (!request_mem_region(pci_resource_start(pdev, 1),
printk(KERN_WARNING "fb: Can't remap %s framebuffer.\n", pci_resource_len(pdev, 1), "tdfx smem")) {
name); printk(KERN_WARNING "tdfxfb: Can't reserve smem\n");
iounmap(fb_info.regbase_virt); release_mem_region(pci_resource_start(pdev, 0),
pci_resource_len(pdev, 0));
iounmap(default_par.regbase_virt);
return -ENXIO; return -ENXIO;
} }
fb_info.iobase = pci_resource_start(pdev, 2); info->screen_base = ioremap_nocache(tdfx_fix.smem_start,
tdfx_fix.smem_len);
if (!info->screen_base) {
printk("fb: Can't remap %s framebuffer.\n", tdfx_fix.id);
iounmap(default_par.regbase_virt);
return -ENXIO;
}
printk("fb: %s memory = %ldK\n", name, fb_info.bufbase_size >> 10); default_par.iobase = pci_resource_start(pdev, 2);
#ifdef CONFIG_MTRR if (!request_region(pci_resource_start(pdev, 2),
if (!nomtrr) { pci_resource_len(pdev, 2), "tdfx iobase")) {
fb_info.mtrr_idx = mtrr_add(fb_info.bufbase_phys, printk(KERN_WARNING "tdfxfb: Can't reserve iobase\n");
fb_info.bufbase_size, release_mem_region(pci_resource_start(pdev, 1),
MTRR_TYPE_WRCOMB, 1); pci_resource_len(pdev, 1));
printk(KERN_INFO "fb: MTRR's turned on\n"); release_mem_region(pci_resource_start(pdev, 0),
pci_resource_len(pdev, 0));
iounmap(default_par.regbase_virt);
iounmap(info->screen_base);
return -ENXIO;
} }
#endif
printk("fb: %s memory = %dK\n", tdfx_fix.id, tdfx_fix.smem_len >> 10);
/* clear framebuffer memory */ /* clear framebuffer memory */
memset_io(fb_info.bufbase_virt, 0, fb_info.bufbase_size); memset_io(info->screen_base, 0, tdfx_fix.smem_len);
fb_info.fb_info.currcon = -1;
if (!nohwcursor)
tdfxfb_hwcursor_init();
init_timer(&fb_info.cursor.timer);
fb_info.cursor.timer.function = do_flashcursor;
fb_info.cursor.timer.data = (unsigned long) (&fb_info);
fb_info.cursor.state = CM_ERASE;
spin_lock_init(&fb_info.DAClock);
strcpy(fb_info.fb_info.modename, "3Dfx ");
strcat(fb_info.fb_info.modename, name);
fb_info.fb_info.changevar = NULL;
fb_info.fb_info.node = NODEV;
fb_info.fb_info.fbops = &tdfxfb_ops;
fb_info.fb_info.disp = &fb_info.disp;
fb_info.fb_info.currcon = -1;
strcpy(fb_info.fb_info.fontname, fontname);
fb_info.fb_info.switch_con = &tdfxfb_switch_con;
fb_info.fb_info.updatevar = &tdfxfb_updatevar;
fb_info.fb_info.flags = FBINFO_FLAG_DEFAULT;
memset(&var, 0, sizeof(var));
if (!mode_option || !fb_find_mode(&var, &fb_info.fb_info,
mode_option, NULL, 0, NULL, 8))
var = default_mode[0].var;
noaccel ? (var.accel_flags &= ~FB_ACCELF_TEXT) :
(var.accel_flags |= FB_ACCELF_TEXT);
if (tdfxfb_decode_var(&var, &fb_info.default_par, &fb_info)) {
/*
* ugh -- can't use the mode from the mode db. (or command
* line), so try the default
*/
printk(KERN_NOTICE tdfx_fix.ypanstep = nopan ? 0 : 1;
"tdfxfb: can't decode the supplied video mode, using default\n"); tdfx_fix.ywrapstep = nowrap ? 0 : 1;
var = default_mode[0].var; info->node = NODEV;
info->fbops = &tdfxfb_ops;
info->fix = tdfx_fix;
info->par = &default_par;
info->disp = (struct display *)(info + 1);
info->pseudo_palette = (void *)(info->disp + 1);
info->flags = FBINFO_FLAG_DEFAULT;
noaccel ? (var.accel_flags &= ~FB_ACCELF_TEXT) : /* The below feilds will go away !!!! */
(var.accel_flags |= FB_ACCELF_TEXT); strcpy(info->modename, info->fix.id);
info->currcon = -1;
info->switch_con = gen_switch;
info->updatevar = gen_update_var;
if (tdfxfb_decode_var if (!mode_option)
(&var, &fb_info.default_par, &fb_info)) { mode_option = "640x480@60";
/* this is getting really bad!... */
printk(KERN_WARNING
"tdfxfb: can't decode default video mode\n");
return -ENXIO;
}
}
fb_info.fb_info.screen_base = fb_info.bufbase_virt; err = fb_find_mode(&info->var, info, mode_option, NULL, 0, NULL, 8);
fb_info.disp.var = var; if (!err || err == 4)
info->var = tdfx_var;
if (tdfxfb_set_var(&var, -1, &fb_info.fb_info)) { size = (info->var.bits_per_pixel == 8) ? 256 : 16;
printk(KERN_WARNING fb_alloc_cmap(&info->cmap, size, 0);
"tdfxfb: can't set default video mode\n");
return -ENXIO; gen_set_var(&info->var, -1, info);
}
if (register_framebuffer(&fb_info.fb_info) < 0) { if (register_framebuffer(info) < 0) {
printk(KERN_WARNING printk("tdfxfb: can't register framebuffer\n");
"tdfxfb: can't register framebuffer\n");
return -ENXIO; return -ENXIO;
} }
/*
printk(KERN_INFO "fb%d: %s frame buffer device\n", * Our driver data
GET_FB_IDX(fb_info.fb_info.node), fb_info.fb_info.modename); */
pdev->driver_data = info;
return 0; return 0;
} }
...@@ -1928,19 +1124,20 @@ static int __devinit tdfxfb_probe(struct pci_dev *pdev, ...@@ -1928,19 +1124,20 @@ static int __devinit tdfxfb_probe(struct pci_dev *pdev,
*/ */
static void __devexit tdfxfb_remove(struct pci_dev *pdev) static void __devexit tdfxfb_remove(struct pci_dev *pdev)
{ {
unregister_framebuffer(&fb_info.fb_info); struct fb_info *info = (struct fb_info *)pdev->driver_data;
del_timer_sync(&fb_info.cursor.timer); struct tdfx_par *par = (struct tdfx_par *) info->par;
#ifdef CONFIG_MTRR
if (!nomtrr) {
mtrr_del(fb_info.mtrr_idx, fb_info.bufbase_phys,
fb_info.bufbase_size);
printk("fb: MTRR's turned off\n");
}
#endif
iounmap(fb_info.regbase_virt); unregister_framebuffer(info);
iounmap(fb_info.bufbase_virt); iounmap(par->regbase_virt);
iounmap(info->screen_base);
/* Clean up after reserved regions */
release_region(pci_resource_start(pdev, 2),
pci_resource_len(pdev, 2));
release_mem_region(pci_resource_start(pdev, 1),
pci_resource_len(pdev, 1));
release_mem_region(pci_resource_start(pdev, 0),
pci_resource_len(pdev, 0));
} }
int __init tdfxfb_init(void) int __init tdfxfb_init(void)
...@@ -1956,7 +1153,8 @@ static void __exit tdfxfb_exit(void) ...@@ -1956,7 +1153,8 @@ static void __exit tdfxfb_exit(void)
MODULE_AUTHOR("Hannu Mallat <hmallat@cc.hut.fi>"); MODULE_AUTHOR("Hannu Mallat <hmallat@cc.hut.fi>");
MODULE_DESCRIPTION("3Dfx framebuffer device driver"); MODULE_DESCRIPTION("3Dfx framebuffer device driver");
MODULE_LICENSE("GPL"); MODULE_LICENSE("GPL");
MODULE_PARM(noaccel, "i");
MODULE_PARM_DESC(noaccel, "Disable hardware acceleration (1 = disabled), enabled by default.");
#ifdef MODULE #ifdef MODULE
module_init(tdfxfb_init); module_init(tdfxfb_init);
...@@ -1967,7 +1165,7 @@ module_exit(tdfxfb_exit); ...@@ -1967,7 +1165,7 @@ module_exit(tdfxfb_exit);
#ifndef MODULE #ifndef MODULE
void tdfxfb_setup(char *options, int *ints) void tdfxfb_setup(char *options, int *ints)
{ {
char *this_opt; char* this_opt;
if (!options || !*options) if (!options || !*options)
return; return;
...@@ -1978,20 +1176,10 @@ void tdfxfb_setup(char *options, int *ints) ...@@ -1978,20 +1176,10 @@ void tdfxfb_setup(char *options, int *ints)
if (!strcmp(this_opt, "inverse")) { if (!strcmp(this_opt, "inverse")) {
inverse = 1; inverse = 1;
fb_invert_cmaps(); fb_invert_cmaps();
} else if (!strcmp(this_opt, "noaccel")) { } else if(!strcmp(this_opt, "nopan")) {
noaccel = nopan = nowrap = nohwcursor = 1;
} else if (!strcmp(this_opt, "nopan")) {
nopan = 1; nopan = 1;
} else if (!strcmp(this_opt, "nowrap")) { } else if(!strcmp(this_opt, "nowrap")) {
nowrap = 1; nowrap = 1;
} else if (!strcmp(this_opt, "nohwcursor")) {
nohwcursor = 1;
#ifdef CONFIG_MTRR
} else if (!strcmp(this_opt, "nomtrr")) {
nomtrr = 1;
#endif
} else if (!strncmp(this_opt, "font:", 5)) {
strncpy(fontname, this_opt + 5, 40);
} else { } else {
mode_option = this_opt; mode_option = this_opt;
} }
...@@ -1999,267 +1187,3 @@ void tdfxfb_setup(char *options, int *ints) ...@@ -1999,267 +1187,3 @@ void tdfxfb_setup(char *options, int *ints)
} }
#endif #endif
static int tdfxfb_switch_con(int con, struct fb_info *fb)
{
struct fb_info_tdfx *info = (struct fb_info_tdfx *) fb;
struct tdfxfb_par par;
int old_con = fb->currcon;
int set_par = 1;
/* Do we have to save the colormap? */
if (fb->currcon >= 0)
if (fb_display[fb->currcon].cmap.len)
fb_get_cmap(&fb_display[fb->currcon].cmap, 1,
tdfxfb_getcolreg, fb);
fb->currcon = con;
fb_display[fb->currcon].var.activate = FB_ACTIVATE_NOW;
tdfxfb_decode_var(&fb_display[con].var, &par, info);
if (old_con >= 0 && vt_cons[old_con]->vc_mode != KD_GRAPHICS) {
/* check if we have to change video registers */
struct tdfxfb_par old_par;
tdfxfb_decode_var(&fb_display[old_con].var, &old_par,
info);
if (!memcmp(&par, &old_par, sizeof(par)))
set_par = 0; /* avoid flicker */
}
if (set_par)
tdfxfb_set_par(&par, info);
if (fb_display[con].dispsw && fb_display[con].conp)
fb_con.con_cursor(fb_display[con].conp, CM_ERASE);
del_timer(&(info->cursor.timer));
fb_info.cursor.state = CM_ERASE;
if (!nohwcursor)
if (fb_display[con].conp)
tdfxfb_createcursor(&fb_display[con]);
info->cursor.redraw = 1;
tdfxfb_set_dispsw(&fb_display[con],
info, par.bpp, par.accel_flags & FB_ACCELF_TEXT);
do_install_cmap(con, fb);
tdfxfb_updatevar(con, fb);
return 1;
}
/* 0 unblank, 1 blank, 2 no vsync, 3 no hsync, 4 off */
static int tdfxfb_blank(int blank, struct fb_info *fb)
{
u32 dacmode, state = 0, vgablank = 0;
dacmode = tdfx_inl(DACMODE);
switch (blank) {
case 0: /* Screen: On; HSync: On, VSync: On */
state = 0;
vgablank = 0;
break;
case 1: /* Screen: Off; HSync: On, VSync: On */
state = 0;
vgablank = 1;
break;
case 2: /* Screen: Off; HSync: On, VSync: Off */
state = BIT(3);
vgablank = 1;
break;
case 3: /* Screen: Off; HSync: Off, VSync: On */
state = BIT(1);
vgablank = 1;
break;
case 4: /* Screen: Off; HSync: Off, VSync: Off */
state = BIT(1) | BIT(3);
vgablank = 1;
break;
}
dacmode &= ~(BIT(1) | BIT(3));
dacmode |= state;
banshee_make_room(1);
tdfx_outl(DACMODE, dacmode);
if (vgablank)
vga_disable_video();
else
vga_enable_video();
return 0;
}
static int tdfxfb_updatevar(int con, struct fb_info *fb)
{
struct fb_info_tdfx *i = (struct fb_info_tdfx *) fb;
if ((con == fb->currcon) && (!nopan))
do_pan_var(&fb_display[con].var, i);
return 0;
}
static int tdfxfb_getcolreg(unsigned regno,
unsigned *red,
unsigned *green,
unsigned *blue,
unsigned *transp, struct fb_info *fb)
{
struct fb_info_tdfx *i = (struct fb_info_tdfx *) fb;
if (regno > i->current_par.cmap_len)
return 1;
*red = i->palette[regno].red;
*green = i->palette[regno].green;
*blue = i->palette[regno].blue;
*transp = 0;
return 0;
}
static int tdfxfb_setcolreg(unsigned regno,
unsigned red,
unsigned green,
unsigned blue,
unsigned transp, struct fb_info *info)
{
struct fb_info_tdfx *i = (struct fb_info_tdfx *) info;
#ifdef FBCON_HAS_CFB8
u32 rgbcol;
#endif
if (regno >= i->current_par.cmap_len)
return 1;
i->palette[regno].red = red;
i->palette[regno].green = green;
i->palette[regno].blue = blue;
switch (i->current_par.bpp) {
#ifdef FBCON_HAS_CFB8
case 8:
rgbcol = (((u32) red & 0xff00) << 8) |
(((u32) green & 0xff00) << 0) |
(((u32) blue & 0xff00) >> 8);
do_setpalentry(regno, rgbcol);
break;
#endif
#ifdef FBCON_HAS_CFB16
case 16:
i->fbcon_cmap.cfb16[regno] =
(((u32) red & 0xf800) >> 0) |
(((u32) green & 0xfc00) >> 5) |
(((u32) blue & 0xf800) >> 11);
break;
#endif
#ifdef FBCON_HAS_CFB24
case 24:
i->fbcon_cmap.cfb24[regno] =
(((u32) red & 0xff00) << 8) |
(((u32) green & 0xff00) << 0) |
(((u32) blue & 0xff00) >> 8);
break;
#endif
#ifdef FBCON_HAS_CFB32
case 32:
i->fbcon_cmap.cfb32[regno] =
(((u32) red & 0xff00) << 8) |
(((u32) green & 0xff00) << 0) |
(((u32) blue & 0xff00) >> 8);
break;
#endif
default:
DPRINTK("bad depth %u\n", i->current_par.bpp);
break;
}
return 0;
}
static void tdfxfb_createcursorshape(struct display *p)
{
unsigned int h, cu, cd;
h = fontheight(p);
cd = h;
if (cd >= 10)
cd--;
fb_info.cursor.type = p->conp->vc_cursor_type & CUR_HWMASK;
switch (fb_info.cursor.type) {
case CUR_NONE:
cu = cd;
break;
case CUR_UNDERLINE:
cu = cd - 2;
break;
case CUR_LOWER_THIRD:
cu = (h * 2) / 3;
break;
case CUR_LOWER_HALF:
cu = h / 2;
break;
case CUR_TWO_THIRDS:
cu = h / 3;
break;
case CUR_BLOCK:
default:
cu = 0;
cd = h;
break;
}
fb_info.cursor.w = fontwidth(p);
fb_info.cursor.u = cu;
fb_info.cursor.d = cd;
}
static void tdfxfb_createcursor(struct display *p)
{
u8 *cursorbase;
u32 xline;
unsigned int i;
unsigned int h, to;
tdfxfb_createcursorshape(p);
xline = ~((1 << (32 - fb_info.cursor.w)) - 1);
#ifdef __LITTLE_ENDIAN
xline = swab32(xline);
#endif
cursorbase = (u8 *) fb_info.bufbase_virt;
h = fb_info.cursor.cursorimage;
to = fb_info.cursor.u;
for (i = 0; i < to; i++) {
writel(0, cursorbase + h);
writel(0, cursorbase + h + 4);
writel(~0, cursorbase + h + 8);
writel(~0, cursorbase + h + 12);
h += 16;
}
to = fb_info.cursor.d;
for (; i < to; i++) {
writel(xline, cursorbase + h);
writel(0, cursorbase + h + 4);
writel(~0, cursorbase + h + 8);
writel(~0, cursorbase + h + 12);
h += 16;
}
for (; i < 64; i++) {
writel(0, cursorbase + h);
writel(0, cursorbase + h + 4);
writel(~0, cursorbase + h + 8);
writel(~0, cursorbase + h + 12);
h += 16;
}
}
static void tdfxfb_hwcursor_init(void)
{
unsigned int start;
start = (fb_info.bufbase_size - 1024) & PAGE_MASK;
fb_info.bufbase_size = start;
fb_info.cursor.cursorimage = fb_info.bufbase_size;
printk("tdfxfb: reserving 1024 bytes for the hwcursor at %p\n",
fb_info.regbase_virt + fb_info.cursor.cursorimage);
}
/* /*
* linux/drivers/video/neofb.h -- NeoMagic Framebuffer Driver * linux/include/video/neo_reg.h -- NeoMagic Framebuffer Driver
* *
* Copyright (c) 2001 Denis Oliver Kropp <dok@convergence.de> * Copyright (c) 2001 Denis Oliver Kropp <dok@convergence.de>
* *
...@@ -8,6 +8,54 @@ ...@@ -8,6 +8,54 @@
* archive for more details. * archive for more details.
*/ */
#define NEO_BS0_BLT_BUSY 0x00000001
#define NEO_BS0_FIFO_AVAIL 0x00000002
#define NEO_BS0_FIFO_PEND 0x00000004
#define NEO_BC0_DST_Y_DEC 0x00000001
#define NEO_BC0_X_DEC 0x00000002
#define NEO_BC0_SRC_TRANS 0x00000004
#define NEO_BC0_SRC_IS_FG 0x00000008
#define NEO_BC0_SRC_Y_DEC 0x00000010
#define NEO_BC0_FILL_PAT 0x00000020
#define NEO_BC0_SRC_MONO 0x00000040
#define NEO_BC0_SYS_TO_VID 0x00000080
#define NEO_BC1_DEPTH8 0x00000100
#define NEO_BC1_DEPTH16 0x00000200
#define NEO_BC1_X_320 0x00000400
#define NEO_BC1_X_640 0x00000800
#define NEO_BC1_X_800 0x00000c00
#define NEO_BC1_X_1024 0x00001000
#define NEO_BC1_X_1152 0x00001400
#define NEO_BC1_X_1280 0x00001800
#define NEO_BC1_X_1600 0x00001c00
#define NEO_BC1_DST_TRANS 0x00002000
#define NEO_BC1_MSTR_BLT 0x00004000
#define NEO_BC1_FILTER_Z 0x00008000
#define NEO_BC2_WR_TR_DST 0x00800000
#define NEO_BC3_SRC_XY_ADDR 0x01000000
#define NEO_BC3_DST_XY_ADDR 0x02000000
#define NEO_BC3_CLIP_ON 0x04000000
#define NEO_BC3_FIFO_EN 0x08000000
#define NEO_BC3_BLT_ON_ADDR 0x10000000
#define NEO_BC3_SKIP_MAPPING 0x80000000
#define NEO_MODE1_DEPTH8 0x0100
#define NEO_MODE1_DEPTH16 0x0200
#define NEO_MODE1_DEPTH24 0x0300
#define NEO_MODE1_X_320 0x0400
#define NEO_MODE1_X_640 0x0800
#define NEO_MODE1_X_800 0x0c00
#define NEO_MODE1_X_1024 0x1000
#define NEO_MODE1_X_1152 0x1400
#define NEO_MODE1_X_1280 0x1800
#define NEO_MODE1_X_1600 0x1c00
#define NEO_MODE1_BLT_ON_ADDR 0x2000
#ifdef __KERNEL__
#ifdef NEOFB_DEBUG #ifdef NEOFB_DEBUG
# define DBG(x) printk (KERN_DEBUG "neofb: %s\n", (x)); # define DBG(x) printk (KERN_DEBUG "neofb: %s\n", (x));
...@@ -15,7 +63,6 @@ ...@@ -15,7 +63,6 @@
# define DBG(x) # define DBG(x)
#endif #endif
#define PCI_CHIP_NM2070 0x0001 #define PCI_CHIP_NM2070 0x0001
#define PCI_CHIP_NM2090 0x0002 #define PCI_CHIP_NM2090 0x0002
#define PCI_CHIP_NM2093 0x0003 #define PCI_CHIP_NM2093 0x0003
...@@ -78,8 +125,6 @@ typedef volatile struct { ...@@ -78,8 +125,6 @@ typedef volatile struct {
struct neofb_par { struct neofb_par {
int depth;
unsigned char MiscOutReg; /* Misc */ unsigned char MiscOutReg; /* Misc */
unsigned char CRTC[25]; /* Crtc Controller */ unsigned char CRTC[25]; /* Crtc Controller */
unsigned char Sequencer[5]; /* Video Sequencer */ unsigned char Sequencer[5]; /* Video Sequencer */
...@@ -113,31 +158,11 @@ struct neofb_par { ...@@ -113,31 +158,11 @@ struct neofb_par {
unsigned char VCLK3NumeratorHigh; unsigned char VCLK3NumeratorHigh;
unsigned char VCLK3Denominator; unsigned char VCLK3Denominator;
unsigned char VerticalExt; unsigned char VerticalExt;
};
struct neofb_info {
struct fb_info fb;
struct display_switch *dispsw;
struct pci_dev *pcidev;
int accel;
char *name;
struct {
u8 *vbase;
u32 pbase;
u32 len;
#ifdef CONFIG_MTRR #ifdef CONFIG_MTRR
int mtrr; int mtrr;
#endif #endif
} video; u8 *mmio_vbase;
struct {
u8 *vbase;
u32 pbase;
u32 len;
} mmio;
Neo2200 *neo2200; Neo2200 *neo2200;
...@@ -151,20 +176,14 @@ struct neofb_info { ...@@ -151,20 +176,14 @@ struct neofb_info {
int lcd_stretch; int lcd_stretch;
int internal_display; int internal_display;
int external_display; int external_display;
struct {
u16 red, green, blue, transp;
} palette[NR_PALETTE];
}; };
typedef struct { typedef struct {
int x_res; int x_res;
int y_res; int y_res;
int mode; int mode;
} biosMode; } biosMode;
/* vga IO functions */ /* vga IO functions */
static inline u8 VGArCR (u8 index) static inline u8 VGArCR (u8 index)
{ {
...@@ -241,51 +260,5 @@ static inline void VGAwMISC (u8 value) ...@@ -241,51 +260,5 @@ static inline void VGAwMISC (u8 value)
{ {
outb (value, 0x3c2); outb (value, 0x3c2);
} }
#endif
#define NEO_BS0_BLT_BUSY 0x00000001
#define NEO_BS0_FIFO_AVAIL 0x00000002
#define NEO_BS0_FIFO_PEND 0x00000004
#define NEO_BC0_DST_Y_DEC 0x00000001
#define NEO_BC0_X_DEC 0x00000002
#define NEO_BC0_SRC_TRANS 0x00000004
#define NEO_BC0_SRC_IS_FG 0x00000008
#define NEO_BC0_SRC_Y_DEC 0x00000010
#define NEO_BC0_FILL_PAT 0x00000020
#define NEO_BC0_SRC_MONO 0x00000040
#define NEO_BC0_SYS_TO_VID 0x00000080
#define NEO_BC1_DEPTH8 0x00000100
#define NEO_BC1_DEPTH16 0x00000200
#define NEO_BC1_X_320 0x00000400
#define NEO_BC1_X_640 0x00000800
#define NEO_BC1_X_800 0x00000c00
#define NEO_BC1_X_1024 0x00001000
#define NEO_BC1_X_1152 0x00001400
#define NEO_BC1_X_1280 0x00001800
#define NEO_BC1_X_1600 0x00001c00
#define NEO_BC1_DST_TRANS 0x00002000
#define NEO_BC1_MSTR_BLT 0x00004000
#define NEO_BC1_FILTER_Z 0x00008000
#define NEO_BC2_WR_TR_DST 0x00800000
#define NEO_BC3_SRC_XY_ADDR 0x01000000
#define NEO_BC3_DST_XY_ADDR 0x02000000
#define NEO_BC3_CLIP_ON 0x04000000
#define NEO_BC3_FIFO_EN 0x08000000
#define NEO_BC3_BLT_ON_ADDR 0x10000000
#define NEO_BC3_SKIP_MAPPING 0x80000000
#define NEO_MODE1_DEPTH8 0x0100
#define NEO_MODE1_DEPTH16 0x0200
#define NEO_MODE1_DEPTH24 0x0300
#define NEO_MODE1_X_320 0x0400
#define NEO_MODE1_X_640 0x0800
#define NEO_MODE1_X_800 0x0c00
#define NEO_MODE1_X_1024 0x1000
#define NEO_MODE1_X_1152 0x1400
#define NEO_MODE1_X_1280 0x1800
#define NEO_MODE1_X_1600 0x1c00
#define NEO_MODE1_BLT_ON_ADDR 0x2000
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment