diff options
author | Knut Petersen <Knut_Petersen@t-online.de> | 2006-01-09 15:04:20 +0100 |
---|---|---|
committer | Linus Torvalds <torvalds@g5.osdl.org> | 2006-01-09 10:00:36 -0800 |
commit | 44637a12f80b80157d9c1bc5b7d6ef09c9e05713 (patch) | |
tree | 17384805725f7b429685ba4cad0d9488d93f9f25 /drivers/video/cyblafb.c | |
parent | 8b78e83bfbc12f7e9bdefd400abdfde9e6c9ac51 (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/video/cyblafb.c')
-rw-r--r-- | drivers/video/cyblafb.c | 1523 |
1 files changed, 874 insertions, 649 deletions
diff --git a/drivers/video/cyblafb.c b/drivers/video/cyblafb.c index 03fbe83d71a..e9f5dee67e3 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 (stretch) { - write3CE(GR5D,0); - write3CE(GR52,(read3CE(GR52) & 0x7C) | 1); - write3CE(GR53,(read3CE(GR53) & 0x7C) | 1); + write3CE(GR52, (read3CE(GR52) & 0x7C) | 0x80); + write3CE(GR53, (read3CE(GR53) & 0x7C) | 0x80); + } else if (stretch) { + write3CE(GR5D, 0); + write3CE(GR52, (read3CE(GR52) & 0x7C) | 1); + write3CE(GR53, (read3CE(GR53) & 0x7C) | 1); } } e |