summaryrefslogtreecommitdiffstats
path: root/drivers
diff options
context:
space:
mode:
authorKnut Petersen <Knut_Petersen@t-online.de>2006-01-09 15:04:20 +0100
committerLinus Torvalds <torvalds@g5.osdl.org>2006-01-09 10:00:36 -0800
commit44637a12f80b80157d9c1bc5b7d6ef09c9e05713 (patch)
tree17384805725f7b429685ba4cad0d9488d93f9f25 /drivers
parent8b78e83bfbc12f7e9bdefd400abdfde9e6c9ac51 (diff)
[PATCH] Update cyblafb driver
This is a major update to the cyblafb framebuffer driver. Most of the stuff has been tested in the mm tree. Main advantages: ============ - vxres > xres support - ywrap and xpan support - much faster for almost all modes (e.g. 1280x1024-16bpp draws more than 41 full screens of text instead of about 25 full screens of text per second on authors Epia 5000) - module init/exit code fixed - bugs triggered by console rotation fixed - lots of minor improvements - startup modes suitable for high performance scrolling in all directions This diff also contains a lot of white space fixes. No side effects are possible, only one single graphics core is affected. Signed-off-by: Knut Petersen <Knut_Petersen@t-online.de> Signed-off-by: Linus Torvalds <torvalds@osdl.org>
Diffstat (limited to 'drivers')
-rw-r--r--drivers/video/Kconfig2
-rw-r--r--drivers/video/cyblafb.c1523
2 files changed, 875 insertions, 650 deletions
diff --git a/drivers/video/Kconfig b/drivers/video/Kconfig
index cc8e3bf5001b..3f04427c9026 100644
--- a/drivers/video/Kconfig
+++ b/drivers/video/Kconfig
@@ -1151,7 +1151,7 @@ config FB_VOODOO1
config FB_CYBLA
tristate "Cyberblade/i1 support"
- depends on FB && PCI
+ depends on FB && PCI && X86_32 && !64BIT
select FB_CFB_IMAGEBLIT
select VIDEO_SELECT
---help---
diff --git a/drivers/video/cyblafb.c b/drivers/video/cyblafb.c
index 03fbe83d71a8..e9f5dee67e3c 100644
--- a/drivers/video/cyblafb.c
+++ b/drivers/video/cyblafb.c
@@ -7,11 +7,12 @@
* tridentfb.c by Jani Monoses
* see files above for further credits
*
- * TODO:
- *
*/
#define CYBLAFB_DEBUG 0
+#define CYBLAFB_KD_GRAPHICS_QUIRK 1
+
+#define CYBLAFB_PIXMAPSIZE 8192
#include <linux/config.h>
#include <linux/module.h>
@@ -22,7 +23,7 @@
#include <asm/types.h>
#include <video/cyblafb.h>
-#define VERSION "0.54"
+#define VERSION "0.62"
struct cyblafb_par {
u32 pseudo_pal[16];
@@ -32,7 +33,9 @@ struct cyblafb_par {
static struct fb_fix_screeninfo cyblafb_fix __devinitdata = {
.id = "CyBla",
.type = FB_TYPE_PACKED_PIXELS,
+ .xpanstep = 1,
.ypanstep = 1,
+ .ywrapstep = 1,
.visual = FB_VISUAL_PSEUDOCOLOR,
.accel = FB_ACCEL_NONE,
};
@@ -43,8 +46,9 @@ static int ref __devinitdata = 75;
static int fp __devinitdata;
static int crt __devinitdata;
static int memsize __devinitdata;
-static int vesafb __devinitdata;
+static int basestride;
+static int vesafb;
static int nativex;
static int center;
static int stretch;
@@ -52,26 +56,50 @@ static int pciwb = 1;
static int pcirb = 1;
static int pciwr = 1;
static int pcirr = 1;
+static int disabled;
static int verbosity;
static int displaytype;
-static void __iomem * io_virt; // iospace virtual memory address
-
-module_param(mode,charp,0);
-module_param(bpp,int,0);
-module_param(ref,int,0);
-module_param(fp,int,0);
-module_param(crt,int,0);
-module_param(nativex,int,0);
-module_param(center,int,0);
-module_param(stretch,int,0);
-module_param(pciwb,int,0);
-module_param(pcirb,int,0);
-module_param(pciwr,int,0);
-module_param(pcirr,int,0);
-module_param(memsize,int,0);
-module_param(verbosity,int,0);
-module_param(vesafb,int,0);
+static void __iomem *io_virt; // iospace virtual memory address
+
+module_param(mode, charp, 0);
+module_param(bpp, int, 0);
+module_param(ref, int, 0);
+module_param(fp, int, 0);
+module_param(crt, int, 0);
+module_param(nativex, int, 0);
+module_param(center, int, 0);
+module_param(stretch, int, 0);
+module_param(pciwb, int, 0);
+module_param(pcirb, int, 0);
+module_param(pciwr, int, 0);
+module_param(pcirr, int, 0);
+module_param(memsize, int, 0);
+module_param(verbosity, int, 0);
+
+//=========================================
+//
+// Well, we have to fix the upper layers.
+// Until this has been done, we work around
+// the bugs.
+//
+//=========================================
+
+#if (CYBLAFB_KD_GRAPHICS_QUIRK && CYBLAFB_DEBUG)
+ if (disabled) { \
+ printk("********\n");\
+ dump_stack();\
+ return val;\
+ }
+
+#elif CYBLAFB_KD_GRAPHICS_QUIRK
+#define KD_GRAPHICS_RETURN(val)\
+ if (disabled) {\
+ return val;\
+ }
+#else
+#define KD_GRAPHICS_RETURN(val)
+#endif
//=========================================
//
@@ -79,10 +107,10 @@ module_param(vesafb,int,0);
//
//=========================================
-#define out8(r,v) writeb(v,io_virt+r)
-#define out32(r,v) writel(v,io_virt+r)
-#define in8(r) readb(io_virt+r)
-#define in32(r) readl(io_virt+r)
+#define out8(r, v) writeb(v, io_virt + r)
+#define out32(r, v) writel(v, io_virt + r)
+#define in8(r) readb(io_virt + r)
+#define in32(r) readl(io_virt + r)
//======================================
//
@@ -90,47 +118,47 @@ module_param(vesafb,int,0);
//
//======================================
-static inline unsigned char read3X4(int reg)
+static inline u8 read3X4(u32 reg)
{
- out8(0x3D4,reg);
+ out8(0x3D4, reg);
return in8(0x3D5);
}
-static inline unsigned char read3C4(int reg)
+static inline u8 read3C4(u32 reg)
{
- out8(0x3C4,reg);
+ out8(0x3C4, reg);
return in8(0x3C5);
}
-static inline unsigned char read3CE(int reg)
+static inline u8 read3CE(u32 reg)
{
- out8(0x3CE,reg);
+ out8(0x3CE, reg);
return in8(0x3CF);
}
-static inline void write3X4(int reg,unsigned char val)
+static inline void write3X4(u32 reg, u8 val)
{
- out8(0x3D4,reg);
- out8(0x3D5,val);
+ out8(0x3D4, reg);
+ out8(0x3D5, val);
}
-static inline void write3C4(int reg,unsigned char val)
+static inline void write3C4(u32 reg, u8 val)
{
- out8(0x3C4,reg);
- out8(0x3C5,val);
+ out8(0x3C4, reg);
+ out8(0x3C5, val);
}
-static inline void write3CE(int reg,unsigned char val)
+static inline void write3CE(u32 reg, u8 val)
{
- out8(0x3CE,reg);
- out8(0x3CF,val);
+ out8(0x3CE, reg);
+ out8(0x3CF, val);
}
-static inline void write3C0(int reg,unsigned char val)
+static inline void write3C0(u32 reg, u8 val)
{
- in8(0x3DA); // read to reset index
- out8(0x3C0,reg);
- out8(0x3C0,val);
+ in8(0x3DA); // read to reset index
+ out8(0x3C0, reg);
+ out8(0x3C0, val);
}
//=================================================
@@ -139,58 +167,62 @@ static inline void write3C0(int reg,unsigned char val)
//
//=================================================
-static inline void enable_mmio(void)
+static void enable_mmio(void)
{
- int tmp;
+ u8 tmp;
- outb(0x0B,0x3C4);
+ outb(0x0B, 0x3C4);
inb(0x3C5); // Set NEW mode
- outb(SR0E,0x3C4); // write enable a lot of extended ports
- outb(0x80,0x3C5);
+ outb(SR0E, 0x3C4); // write enable a lot of extended ports
+ outb(0x80, 0x3C5);
- outb(SR11,0x3C4); // write enable those extended ports that
- outb(0x87,0x3C5); // are not affected by SR0E_New
+ outb(SR11, 0x3C4); // write enable those extended ports that
+ outb(0x87, 0x3C5); // are not affected by SR0E_New
- outb(CR1E,0x3d4); // clear write protect bit for port 0x3c2
- tmp=inb(0x3d5) & 0xBF;
- outb(CR1E,0x3d4);
- outb(tmp,0x3d5);
+ outb(CR1E, 0x3d4); // clear write protect bit for port 0x3c2
+ tmp = inb(0x3d5) & 0xBF;
+ outb(CR1E, 0x3d4);
+ outb(tmp, 0x3d5);
- outb(CR39,0x3D4);
- outb(inb(0x3D5)|0x01,0x3D5); // Enable mmio, everything else untouched
+ outb(CR39, 0x3D4);
+ outb(inb(0x3D5) | 0x01, 0x3D5); // Enable mmio
}
//=================================================
//
// Set pixel clock VCLK1
-// - multipliers set elswhere
-// - freq in units of 0.01 MHz
+// - multipliers set elswhere
+// - freq in units of 0.01 MHz
+//
+// Hardware bug: SR18 >= 250 is broken for the
+// cyberblade/i1
//
//=================================================
static void set_vclk(struct cyblafb_par *par, int freq)
{
- u32 m,n,k;
- int f,fi,d,di;
- u8 lo=0,hi=0;
+ u32 m, n, k;
+ int f, fi, d, di;
+ u8 lo = 0, hi = 0;
d = 2000;
k = freq >= 10000 ? 0 : freq >= 5000 ? 1 : freq >= 2500 ? 2 : 3;
- for(m = 0;m<64;m++)
- for(n = 0;n<250;n++) { // max 249 is a hardware limit for cybla/i1 !
- fi = (int)(((5864727*(n+8))/((m+2)*(1<<k)))>>12);
- if ((di = abs(fi - freq)) < d) {
- d = di;
- f = fi;
- lo = (u8) n;
- hi = (u8) ((k<<6) | m);
+ for (m = 0; m < 64; m++)
+ for (n = 0; n < 250; n++) {
+ fi = (int)(((5864727 * (n + 8)) /
+ ((m + 2) * (1 << k))) >> 12);
+ if ((di = abs(fi - freq)) < d) {
+ d = di;
+ f = fi;
+ lo = (u8) n;
+ hi = (u8) ((k << 6) | m);
+ }
}
- }
- write3C4(SR19,hi);
- write3C4(SR18,lo);
- if(verbosity > 1)
+ write3C4(SR19, hi);
+ write3C4(SR18, lo);
+ if (verbosity > 0)
output("pixclock = %d.%02d MHz, k/m/n %x %x %x\n",
- freq/100,freq%100,(hi&0xc0)>>6,hi&0x3f,lo);
+ freq / 100, freq % 100, (hi & 0xc0) >> 6, hi & 0x3f, lo);
}
//================================================
@@ -199,83 +231,83 @@ static void set_vclk(struct cyblafb_par *par, int freq)
//
//================================================
-static void cyblafb_setup_GE(int pitch,int bpp)
+static void cyblafb_setup_GE(int pitch, int bpp)
{
- int base = (pitch>>3)<<20;
+ KD_GRAPHICS_RETURN();
switch (bpp) {
- case 8: base |= (0<<29); break;
- case 15: base |= (5<<29); break;
- case 16: base |= (1<<29); break;
- case 24:
- case 32: base |= (2<<29); break;
+ case 8:
+ basestride = ((pitch >> 3) << 20) | (0 << 29);
+ break;
+ case 15:
+ basestride = ((pitch >> 3) << 20) | (5 << 29);
+ break;
+ case 16:
+ basestride = ((pitch >> 3) << 20) | (1 << 29);
+ break;
+ case 24:
+ case 32:
+ basestride = ((pitch >> 3) << 20) | (2 << 29);
+ break;
}
- write3X4(CR36,0x90); // reset GE
- write3X4(CR36,0x80); // enable GE
-
- out32(GE24,1<<7); // reset all GE pointers
- out32(GE24,0);
-
- write3X4(CR2D,0x00); // GE Timinigs, no delays
-
- out32(GEB8,base); // Destination Stride / Buffer Base 0, p 133
- out32(GEBC,base); // Destination Stride / Buffer Base 1, p 133
- out32(GEC0,base); // Destination Stride / Buffer Base 2, p 133
- out32(GEC4,base); // Destination Stride / Buffer Base 3, p 133
- out32(GEC8,base); // Source Stride / Buffer Base 0, p 133
- out32(GECC,base); // Source Stride / Buffer Base 1, p 133
- out32(GED0,base); // Source Stride / Buffer Base 2, p 133
- out32(GED4,base); // Source Stride / Buffer Base 3, p 133
- out32(GE6C,0); // Pattern and Style, p 129, ok
+ write3X4(CR36, 0x90); // reset GE
+ write3X4(CR36, 0x80); // enable GE
+ out32(GE24, 1 << 7); // reset all GE pointers by toggling
+ out32(GE24, 0); // d7 of GE24
+ write3X4(CR2D, 0x00); // GE Timinigs, no delays
+ out32(GE6C, 0); // Pattern and Style, p 129, ok
}
//=====================================================================
//
-// Although this is a .fb_sync function that could be enabled in
-// cyblafb_ops, we do not include it there. We sync immediately before
-// new GE operations to improve performance.
+// Cyberblade specific syncing
+//
+// A timeout might be caused by disabled mmio.
+// Cause:
+// - bit CR39 & 1 == 0 upon return, X trident driver bug
+// - kdm bug (KD_GRAPHICS not set on first switch)
+// - kernel design flaw (it believes in the correctness
+// of kdm/X
+// First we try to sync ignoring that problem, as most of the
+// time that will succeed immediately and the enable_mmio()
+// would only degrade performance.
//
//=====================================================================
static int cyblafb_sync(struct fb_info *info)
{
- int status, i=100000;
- while( ((status=in32(GE20)) & 0xFA800000) && i != 0)
+ u32 status, i = 100000;
+
+ KD_GRAPHICS_RETURN(0);
+
+ while (((status = in32(GE20)) & 0xFe800000) && i != 0)
i--;
if (i == 0) {
- // The timeout might be caused by disabled mmio.
- // Cause:
- // - bit CR39 & 1 == 0 upon return, X trident driver bug
- // - kdm bug (KD_GRAPHICS not set on first switch)
- // - kernel design flaw (it believes in the correctness
- // of kdm/X
- // So we make sure that mmio is enabled first ...
enable_mmio();
-// show_trace(NULL,&status);
- i=1000000;
- while( ((status=in32(GE20)) & 0xFA800000) && i != 0)
+ i = 1000000;
+ while (((status = in32(GE20)) & 0xFA800000) && i != 0)
i--;
if (i == 0) {
- output("GE Timeout, status: %x\n",status);
- if(status & 0x80000000)
+ output("GE Timeout, status: %x\n", status);
+ if (status & 0x80000000)
output("Bresenham Engine : Busy\n");
- if(status & 0x40000000)
+ if (status & 0x40000000)
output("Setup Engine : Busy\n");
- if(status & 0x20000000)
+ if (status & 0x20000000)
output("SP / DPE : Busy\n");
- if(status & 0x10000000)
+ if (status & 0x10000000)
output("Memory Interface : Busy\n");
- if(status & 0x08000000)
+ if (status & 0x08000000)
output("Com Lst Proc : Busy\n");
- if(status & 0x04000000)
+ if (status & 0x04000000)
output("Block Write : Busy\n");
- if(status & 0x02000000)
+ if (status & 0x02000000)
output("Command Buffer : Full\n");
- if(status & 0x01000000)
+ if (status & 0x01000000)
output("RESERVED : Busy\n");
- if(status & 0x00800000)
+ if (status & 0x00800000)
output("PCI Write Buffer : Busy\n");
cyblafb_setup_GE(info->var.xres,
info->var.bits_per_pixel);
@@ -291,142 +323,193 @@ static int cyblafb_sync(struct fb_info *info)
//
//==============================
-static void cyblafb_fillrect(struct fb_info * info,
- const struct fb_fillrect *fr)
+static void cyblafb_fillrect(struct fb_info *info, const struct fb_fillrect *fr)
{
- int bpp = info->var.bits_per_pixel;
- int col;
+ u32 bpp = info->var.bits_per_pixel, col, desty, height;
+
+ KD_GRAPHICS_RETURN();
switch (bpp) {
- default:
- case 8: col = fr->color;
- col |= col <<8;
- col |= col <<16;
- break;
- case 16: col = ((u32 *)(info->pseudo_palette))[fr->color];
- col |= col <<16;
- break;
- case 32: col = ((u32 *)(info->pseudo_palette))[fr->color];
- break;
+ default:
+ case 8:
+ col = fr->color;
+ col |= col << 8;
+ col |= col << 16;
+ break;
+ case 16:
+ col = ((u32 *) (info->pseudo_palette))[fr->color];
+ col |= col << 16;
+ break;
+ case 32:
+ col = ((u32 *) (info->pseudo_palette))[fr->color];
+ break;
}
- cyblafb_sync(info);
-
- out32(GE60,col);
- out32(GE48,fr->rop ? 0x66:ROP_S);
- out32(GE44,0x20000000|1<<19|1<<4|2<<2);
- out32(GE08,point(fr->dx,fr->dy));
- out32(GE0C,point(fr->dx+fr->width-1,fr->dy+fr->height-1));
-
+ desty = fr->dy;
+ height = fr->height;
+ while (height) {
+ out32(GEB8, basestride | ((desty * info->var.xres_virtual *
+ bpp) >> 6));
+ out32(GE60, col);
+ out32(GE48, fr->rop ? 0x66 : ROP_S);
+ out32(GE44, 0x20000000 | 1 << 19 | 1 << 4 | 2 << 2);
+ out32(GE08, point(fr->dx, 0));
+ out32(GE0C, point(fr->dx + fr->width - 1,
+ height > 4096 ? 4095 : height - 1));
+ if (likely(height <= 4096))
+ return;
+ desty += 4096;
+ height -= 4096;
+ }
}
-//==============================
+//================================================
//
// Cyberblade specific copyarea
//
-//==============================
+// This function silently assumes that it never
+// will be called with width or height exceeding
+// 4096.
+//
+//================================================
-static void cyblafb_copyarea(struct fb_info *info,
- const struct fb_copyarea *ca)
+static void cyblafb_copyarea(struct fb_info *info, const struct fb_copyarea *ca)
{
- __u32 s1,s2,d1,d2;
- int direction;
+ u32 s1, s2, d1, d2, direction;
+
+ KD_GRAPHICS_RETURN();
+
+ s1 = point(ca->sx, 0);
+ s2 = point(ca->sx + ca->width - 1, ca->height - 1);
+ d1 = point(ca->dx, 0);
+ d2 = point(ca->dx + ca->width - 1, ca->height - 1);
- s1 = point(ca->sx,ca->sy);
- s2 = point(ca->sx+ca->width-1,ca->sy+ca->height-1);
- d1 = point(ca->dx,ca->dy);
- d2 = point(ca->dx+ca->width-1,ca->dy+ca->height-1);
if ((ca->sy > ca->dy) || ((ca->sy == ca->dy) && (ca->sx > ca->dx)))
direction = 0;
else
direction = 2;
- cyblafb_sync(info);
-
- out32(GE44,0xa0000000|1<<19|1<<2|direction);
- out32(GE00,direction?s2:s1);
- out32(GE04,direction?s1:s2);
- out32(GE08,direction?d2:d1);
- out32(GE0C,direction?d1:d2);
-
+ out32(GEB8, basestride | ((ca->dy * info->var.xres_virtual *
+ info->var.bits_per_pixel) >> 6));
+ out32(GEC8, basestride | ((ca->sy * info->var.xres_virtual *
+ info->var.bits_per_pixel) >> 6));
+ out32(GE44, 0xa0000000 | 1 << 19 | 1 << 2 | direction);
+ out32(GE00, direction ? s2 : s1);
+ out32(GE04, direction ? s1 : s2);
+ out32(GE08, direction ? d2 : d1);
+ out32(GE0C, direction ? d1 : d2);
}
//=======================================================================
//
// Cyberblade specific imageblit
//
-// Accelerated for the most usual case, blitting 1-bit deep character
-// character images. Everything else is passed to the generic imageblit.
+// Accelerated for the most usual case, blitting 1 - bit deep
+// character images. Everything else is passed to the generic imageblit
+// unless it is so insane that it is better to printk an alert.
+//
+// Hardware bug: _Never_ blit across pixel column 2048, that will lock
+// the system. We split those blit requests into three blitting
+// operations.
//
//=======================================================================
static void cyblafb_imageblit(struct fb_info *info,
const struct fb_image *image)
{
-
u32 fgcol, bgcol;
+ u32 *pd = (u32 *) image->data;
+ u32 bpp = info->var.bits_per_pixel;
- int i;
- int bpp = info->var.bits_per_pixel;
- int index = 0;
- int index_end=image->height * image->width / 8;
- int width_dds=image->width / 32;
- int width_dbs=image->width % 32;
-
- if (image->depth != 1 || bpp < 8 || bpp > 32 || bpp % 8 != 0 ||
- image->width % 8 != 0 || image->width == 0 || image->height == 0) {
- cfb_imageblit(info,image);
+ KD_GRAPHICS_RETURN();
+
+ // Used only for drawing the penguine (image->depth > 1)
+ if (image->depth != 1) {
+ cfb_imageblit(info, image);
+ return;
+ }
+ // That should never happen, but it would be fatal
+ if (image->width == 0 || image->height == 0) {
+ output("imageblit: width/height 0 detected\n");
return;
}
if (info->fix.visual == FB_VISUAL_TRUECOLOR ||
info->fix.visual == FB_VISUAL_DIRECTCOLOR) {
- fgcol = ((u32*)(info->pseudo_palette))[image->fg_color];
- bgcol = ((u32*)(info->pseudo_palette))[image->bg_color];
+ fgcol = ((u32 *) (info->pseudo_palette))[image->fg_color];
+ bgcol = ((u32 *) (info->pseudo_palette))[image->bg_color];
} else {
fgcol = image->fg_color;
bgcol = image->bg_color;
}
switch (bpp) {
- case 8:
- fgcol |= fgcol <<8; fgcol |= fgcol <<16;
- bgcol |= bgcol <<8; bgcol |= bgcol <<16;
- break;
- case 16:
- fgcol |= fgcol <<16;
- bgcol |= bgcol <<16;
- break;
- default:
- break;
+ case 8:
+ fgcol |= fgcol << 8;
+ bgcol |= bgcol << 8;
+ case 16:
+ fgcol |= fgcol << 16;
+ bgcol |= bgcol << 16;
+ default:
+ break;
}
- cyblafb_sync(info);
-
- out32(GE60,fgcol);
- out32(GE64,bgcol);
- out32(GE44,0xa0000000 | 1<<20 | 1<<19);
- out32(GE08,point(image->dx,image->dy));
- out32(GE0C,point(image->dx+image->width-1,image->dy+image->height-1));
+ out32(GEB8, basestride | ((image->dy * info->var.xres_virtual *
+ bpp) >> 6));
+ out32(GE60, fgcol);
+ out32(GE64, bgcol);
+
+ if (!(image->dx < 2048 && (image->dx + image->width - 1) >= 2048)) {
+ u32 dds = ((image->width + 31) >> 5) * image->height;
+ out32(GE44, 0xa0000000 | 1 << 20 | 1 << 19);
+ out32(GE08, point(image->dx, 0));
+ out32(GE0C, point(image->dx + image->width - 1,
+ image->height - 1));
+ while (dds--)
+ out32(GE9C, *pd++);
+ } else {
+ int i, j;
+ u32 ddstotal = (image->width + 31) >> 5;
+ u32 ddsleft = (2048 - image->dx + 31) >> 5;
+ u32 skipleft = ddstotal - ddsleft;
+
+ out32(GE44, 0xa0000000 | 1 << 20 | 1 << 19);
+ out32(GE08, point(image->dx, 0));
+ out32(GE0C, point(2048 - 1, image->height - 1));
+ for (i = 0; i < image->height; i++) {
+ for (j = 0; j < ddsleft; j++)
+ out32(GE9C, *pd++);
+ pd += skipleft;
+ }
- while(index < index_end) {
- const char *p = image->data + index;
- for(i=0;i<width_dds;i++) {
- out32(GE9C,*(u32*)p);
- p+=4;
- index+=4;
+ if (image->dx % 32) {
+ out32(GE44, 0xa0000000 | 1 << 20 | 1 << 19);
+ out32(GE08, point(2048, 0));
+ if (image->width > ddsleft << 5)
+ out32(GE0C, point(image->dx + (ddsleft << 5) -
+ 1, image->height - 1));
+ else
+ out32(GE0C, point(image->dx + image->width - 1,
+ image->height - 1));
+ pd = ((u32 *) image->data) + ddstotal - skipleft - 1;
+ for (i = 0; i < image->height; i++) {
+ out32(GE9C, swab32(swab32(*pd) << ((32 -
+ (image->dx & 31)) & 31)));
+ pd += ddstotal;
+ }
}
- switch(width_dbs) {
- case 0: break;
- case 8: out32(GE9C,*(u8*)p);
- index+=1;
- break;
- case 16: out32(GE9C,*(u16*)p);
- index+=2;
- break;
- case 24: out32(GE9C,*(u16*)p | *(u8*)(p+2)<<16);
- index+=3;
- break;
+
+ if (skipleft) {
+ out32(GE44, 0xa0000000 | 1 << 20 | 1 << 19);
+ out32(GE08, point(image->dx + (ddsleft << 5), 0));
+ out32(GE0C, point(image->dx + image->width - 1,
+ image->height - 1));
+ pd = (u32 *) image->data;
+ for (i = 0; i < image->height; i++) {
+ pd += ddsleft;
+ for (j = 0; j < skipleft; j++)
+ out32(GE9C, *pd++);
+ }
}
}
}
@@ -443,7 +526,6 @@ static int cyblafb_check_var(struct fb_var_screeninfo *var,
struct fb_info *info)
{
int bpp = var->bits_per_pixel;
- int s,t,maxvyres;
//
// we try to support 8, 16, 24 and 32 bpp modes,
@@ -453,9 +535,9 @@ static int cyblafb_check_var(struct fb_var_screeninfo *var,
// (This is what tridentfb does ... will be changed in the future)
//
//
- if ( bpp % 8 != 0 || bpp < 8 || bpp >32)
+ if (bpp % 8 != 0 || bpp < 8 || bpp > 32)
bpp = 8;
- if (bpp == 24 )
+ if (bpp == 24)
bpp = var->bits_per_pixel = 32;
//
@@ -472,65 +554,93 @@ static int cyblafb_check_var(struct fb_var_screeninfo *var,
return -EINVAL;
//
- // xres != xres_virtual is broken, fail if such an
- // unusual mode is requested
+ // we do not allow vclk to exceed 230 MHz. If the requested
+ // vclk is too high, we default to 200 MHz
//
- if (var->xres != var->xres_virtual)
- return -EINVAL;
+ if ((bpp == 32 ? 200000000 : 100000000) / var->pixclock > 23000)
+ var->pixclock = (bpp == 32 ? 200000000 : 100000000) / 20000;
//
- // we do not allow vclk to exceed 230 MHz
+ // enforce (h|v)sync_len limits
//
- if ((bpp==32 ? 200000000 : 100000000) / var->pixclock > 23000)
- return -EINVAL;
+ var->hsync_len &= ~7;
+ if(var->hsync_len > 248)
+ var->hsync_len = 248;
+
+ var->vsync_len &= 15;
//
- // calc max yres_virtual that would fit in memory
- // and max yres_virtual that could be used for scrolling
- // and use minimum of the results as maxvyres
- //
- // adjust vyres_virtual to maxvyres if necessary
- // fail if requested yres is bigger than maxvyres
+ // Enforce horizontal and vertical hardware limits.
+ // 1600x1200 is mentioned as a maximum, but higher resolutions could
+ // work with slow refresh, small margins and short sync.
//
- s = (0x1fffff / (var->xres * bpp/8)) + var->yres;
- t = info->fix.smem_len / (var->xres * bpp/8);
- maxvyres = t < s ? t : s;
- if (maxvyres < var->yres_virtual)
- var->yres_virtual=maxvyres;
- if (maxvyres < var->yres)
+ var->xres &= ~7;
+
+ if (((var->xres + var->left_margin + var->right_margin +
+ var->hsync_len) > (bpp == 32 ? 2040 : 4088)) ||
+ ((var->yres + var->upper_margin + var->lower_margin +
+ var->vsync_len) > 2047))
return -EINVAL;
- switch (bpp) {
- case 8:
- var->red.offset = 0;
- var->green.offset = 0;
- var->blue.offset = 0;
- var->red.length = 6;
- var->green.length = 6;
- var->blue.length = 6;
- break;
- case 16:
- var->red.offset = 11;
- var->green.offset = 5;
- var->blue.offset = 0;
- var->red.length = 5;
- var->green.length = 6;
- var->blue.length = 5;
- break;
- case 32:
- var->red.offset = 16;
- var->green.offset = 8;
- var->blue.offset = 0;
- var->red.length = 8;
- var->green.length = 8;
- var->blue.length = 8;
- break;
- default:
+ if ((var->xres > 1600) || (var->yres > 1200))
+ output("Mode %dx%d exceeds documented limits.\n",
+ var->xres, var->yres);
+ //
+ // try to be smart about (x|y)res_virtual problems.
+ //
+ if (var->xres > var->xres_virtual)
+ var->xres_virtual = var->xres;
+ if (var->yres > var->yres_virtual)
+ var->yres_virtual = var->yres;
+
+ if (bpp == 8 || bpp == 16) {
+ if (var->xres_virtual > 4088)
+ var->xres_virtual = 4088;
+ } else {
+ if (var->xres_virtual > 2040)
+ var->xres_virtual = 2040;
+ }
+ var->xres_virtual &= ~7;
+ while (var->xres_virtual * var->yres_virtual * bpp / 8 >
+ info->fix.smem_len) {
+ if (var->yres_virtual > var->yres)
+ var->yres_virtual--;
+ else if (var->xres_virtual > var->xres)
+ var->xres_virtual -= 8;
+ else
return -EINVAL;
}
- return 0;
+ switch (bpp) {
+ case 8:
+ var->red.offset = 0;
+ var->green.offset = 0;
+ var->blue.offset = 0;
+ var->red.length = 6;
+ var->green.length = 6;
+ var->blue.length = 6;
+ break;
+ case 16:
+ var->red.offset = 11;
+ var->green.offset = 5;
+ var->blue.offset = 0;
+ var->red.length = 5;
+ var->green.length = 6;
+ var->blue.length = 5;
+ break;
+ case 32:
+ var->red.offset = 16;
+ var->green.offset = 8;
+ var->blue.offset = 0;
+ var->red.length = 8;
+ var->green.length = 8;
+ var->blue.length = 8;
+ break;
+ default:
+ return -EINVAL;
+ }
+ return 0;
}
//=====================================================================
@@ -543,23 +653,25 @@ static int cyblafb_check_var(struct fb_var_screeninfo *var,
// it, so it is also safe to be used here. BTW: datasheet CR0E on page
// 90 really is CR1E, the real CRE is documented on page 72.
//
+// BUT:
+//
+// As of internal version 0.60 we do not use vga panning any longer.
+// Vga panning did not allow us the use of all available video memory
+// and thus prevented ywrap scrolling. We do use the "right view"
+// register now.
+//
+//
//=====================================================================
static int cyblafb_pan_display(struct fb_var_screeninfo *var,
struct fb_info *info)
{
- unsigned int offset;
+ KD_GRAPHICS_RETURN(0);
- offset=(var->xoffset+(var->yoffset*var->xres))*var->bits_per_pixel/32;
info->var.xoffset = var->xoffset;
info->var.yoffset = var->yoffset;
-
- write3X4(CR0D,offset & 0xFF);
- write3X4(CR0C,(offset & 0xFF00) >> 8);
- write3X4(CR1E,(read3X4(CR1E) & 0xDF) | ((offset & 0x10000) >> 11));
- write3X4(CR27,(read3X4(CR27) & 0xF8) | ((offset & 0xE0000) >> 17));
- write3X4(CR2B,(read3X4(CR2B) & 0xDF) | ((offset & 0x100000) >> 15));
-
+ out32(GE10, 0x80000000 | ((var->xoffset + (var->yoffset *
+ var->xres_virtual)) * var->bits_per_pixel / 32));
return 0;
}
@@ -578,56 +690,96 @@ static void regdump(struct cyblafb_par *par)
return;
printk("\n");
- for(i=0; i<=0xff; i++) {
- outb(i,0x3d4);
- printk("CR%02x=%02x ",i,inb(0x3d5));
- if (i%16==15)
+ for (i = 0; i <= 0xff; i++) {
+ outb(i, 0x3d4);
+ printk("CR%02x=%02x ", i, inb(0x3d5));
+ if (i % 16 == 15)
printk("\n");
}
- outb(0x30,0x3ce);
- outb(inb(0x3cf) | 0x40,0x3cf);
- for(i=0; i<=0x1f; i++) {
- if (i==0 || (i>2 && i<8) || i==0x10 || i==0x11 || i==0x16) {
- outb(i,0x3d4);
- printk("CR%02x=%02x ",i,inb(0x3d5));
+ outb(0x30, 0x3ce);
+ outb(inb(0x3cf) | 0x40, 0x3cf);
+ for (i = 0; i <= 0x1f; i++) {
+ if (i == 0 || (i > 2 && i < 8) || i == 0x10 || i == 0x11
+ || i == 0x16) {
+ outb(i, 0x3d4);
+ printk("CR%02x=%02x ", i, inb(0x3d5));
} else
printk("------- ");
- if (i%16==15)
+ if (i % 16 == 15)
printk("\n");
}
- outb(0x30,0x3ce);
- outb(inb(0x3cf) & 0xbf,0x3cf);
+ outb(0x30, 0x3ce);
+ outb(inb(0x3cf) & 0xbf, 0x3cf);
printk("\n");
- for(i=0; i<=0x7f; i++) {
- outb(i,0x3ce);
- printk("GR%02x=%02x ",i,inb(0x3cf));
- if (i%16==15)
+ for (i = 0; i <= 0x7f; i++) {
+ outb(i, 0x3ce);
+ printk("GR%02x=%02x ", i, inb(0x3cf));
+ if (i % 16 == 15)
printk("\n");
}
printk("\n");
- for(i=0; i<=0xff; i++) {
- outb(i,0x3c4);
- printk("SR%02x=%02x ",i,inb(0x3c5));
- if (i%16==15)
+ for (i = 0; i <= 0xff; i++) {
+ outb(i, 0x3c4);
+ printk("SR%02x=%02x ", i, inb(0x3c5));
+ if (i % 16 == 15)
printk("\n");
}
printk("\n");
- for(i=0; i <= 0x1F; i++) {
- inb(0x3da); // next access is index!
- outb(i,0x3c0);
- printk("AR%02x=%02x ",i,inb(0x3c1));
- if (i%16==15)
+ for (i = 0; i <= 0x1F; i++) {
+ inb(0x3da); // next access is index!
+ outb(i, 0x3c0);
+ printk("AR%02x=%02x ", i, inb(0x3c1));
+ if (i % 16 == 15)
printk("\n");
}
printk("\n");
- inb(0x3DA); // reset internal flag to 3c0 index
- outb(0x20,0x3C0); // enable attr
+ inb(0x3DA); // reset internal flag to 3c0 index
+ outb(0x20, 0x3C0); // enable attr
+
+ return;
+}
+
+//=======================================================================
+//
+// Save State
+//
+// This function is called while a switch to KD_TEXT is in progress,
+// before any of the other functions are called.
+//
+//=======================================================================
+static void cyblafb_save_state(struct fb_info *info)
+{
+ struct cyblafb_par *par = info->par;
+ if (verbosity > 0)
+ output("Switching to KD_TEXT\n");
+ disabled = 0;
+ regdump(par);
+ enable_mmio();
+ return;
+}
+
+//=======================================================================
+//
+// Restore State
+//
+// This function is called while a switch to KD_GRAPHICS is in progress,
+// We have to turn on vga style panning registers again because the
+// trident driver of X does not know about GE10.
+//
+//=======================================================================
+
+static void cyblafb_restore_state(struct fb_info *info)
+{
+ if (verbosity > 0)
+ output("Switching to KD_GRAPHICS\n");
+ out32(GE10, 0);
+ disabled = 1;
return;
}
@@ -640,32 +792,34 @@ static void regdump(struct cyblafb_par *par)
static int cyblafb_set_par(struct fb_info *info)
{
struct cyblafb_par *par = info->par;
- u32
- htotal,hdispend,hsyncstart,hsyncend,hblankstart,hblankend,preendfetch,
- vtotal,vdispend,vsyncstart,vsyncend,vblankstart,vblankend;
+ u32 htotal, hdispend, hsyncstart, hsyncend, hblankstart,
+ hblankend, preendfetch, vtotal, vdispend, vsyncstart,
+ vsyncend, vblankstart, vblankend;
struct fb_var_screeninfo *var = &info->var;
int bpp = var->bits_per_pixel;
int i;
+ KD_GRAPHICS_RETURN(0);
+
if (verbosity > 0)
output("Switching to new mode: "
"fbset -g %d %d %d %d %d -t %d %d %d %d %d %d %d\n",
- var->xres,var->yres,var->xres_virtual,
- var->yres_virtual,var->bits_per_pixel,var->pixclock,
- var->left_margin,var->right_margin,var->upper_margin,
- var->lower_margin,var->hsync_len,var->vsync_len);
+ var->xres, var->yres, var->xres_virtual,
+ var->yres_virtual, var->bits_per_pixel, var->pixclock,
+ var->left_margin, var->right_margin, var->upper_margin,
+ var->lower_margin, var->hsync_len, var->vsync_len);
htotal = (var->xres + var->left_margin + var->right_margin +
- var->hsync_len) / 8 - 5;
- hdispend = var->xres/8 - 1;
- hsyncstart = (var->xres + var->right_margin)/8;
- hsyncend = var->hsync_len/8;
+ var->hsync_len) / 8 - 5;
+ hdispend = var->xres / 8 - 1;
+ hsyncstart = (var->xres + var->right_margin) / 8;
+ hsyncend = var->hsync_len / 8;
hblankstart = hdispend + 1;
hblankend = htotal + 3; // should be htotal + 5, bios does it this way
- preendfetch = ((var->xres >> 3) + 1) * ((bpp+1) >> 3);
+ preendfetch = ((var->xres >> 3) + 1) * ((bpp + 1) >> 3);
vtotal = var->yres + var->upper_margin + var->lower_margin +
- var->vsync_len - 2;
+ var->vsync_len - 2;
vdispend = var->yres - 1;
vsyncstart = var->yres + var->lower_margin;
vblankstart = var->yres;
@@ -674,101 +828,99 @@ static int cyblafb_set_par(struct fb_info *info)
enable_mmio(); // necessary! ... check X ...
- write3X4(CR11,read3X4(CR11) & 0x7F); // unlock cr00 .. cr07
+ write3X4(CR11, read3X4(CR11) & 0x7F); // unlock cr00 .. cr07
- write3CE(GR30,8);
+ write3CE(GR30, 8);
if ((displaytype == DISPLAY_FP) && var->xres < nativex) {
// stretch or center ?
- out8(0x3C2,0xEB);
+ out8(0x3C2, 0xEB);
- write3CE(GR30,read3CE(GR30) | 0x81); // shadow mode on
+ write3CE(GR30, read3CE(GR30) | 0x81); // shadow mode on
if (center) {
- write3CE(GR52,(read3CE(GR52) & 0x7C) | 0x80);
- write3CE(GR53,(read3CE(GR53) & 0x7C) | 0x80);
- }
- else if (s