📄 cyblafb.c
字号:
/* * Frame buffer driver for Trident Cyberblade/i1 graphics core * * Copyright 2005 Knut Petersen <Knut_Petersen@t-online.de> * * CREDITS: * tridentfb.c by Jani Monoses * see files above for further credits * */#define CYBLAFB_DEBUG 0#define CYBLAFB_KD_GRAPHICS_QUIRK 1#define CYBLAFB_PIXMAPSIZE 8192#include <linux/module.h>#include <linux/string.h>#include <linux/fb.h>#include <linux/init.h>#include <linux/pci.h>#include <asm/types.h>#include <video/cyblafb.h>#define VERSION "0.62"struct cyblafb_par { u32 pseudo_pal[16]; struct fb_ops ops;};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,};static char *mode __devinitdata = NULL;static int bpp __devinitdata = 8;static int ref __devinitdata = 75;static int fp __devinitdata;static int crt __devinitdata;static int memsize __devinitdata;static int basestride;static int vesafb;static int nativex;static int center;static int stretch;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 addressmodule_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//=========================================//// Port access macros for memory mapped io////=========================================#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)//======================================//// Hardware access inline functions////======================================static inline u8 read3X4(u32 reg){ out8(0x3D4, reg); return in8(0x3D5);}static inline u8 read3C4(u32 reg){ out8(0x3C4, reg); return in8(0x3C5);}static inline u8 read3CE(u32 reg){ out8(0x3CE, reg); return in8(0x3CF);}static inline void write3X4(u32 reg, u8 val){ out8(0x3D4, reg); out8(0x3D5, val);}static inline void write3C4(u32 reg, u8 val){ out8(0x3C4, reg); out8(0x3C5, val);}static inline void write3CE(u32 reg, u8 val){ out8(0x3CE, reg); out8(0x3CF, val);}static inline void write3C0(u32 reg, u8 val){ in8(0x3DA); // read to reset index out8(0x3C0, reg); out8(0x3C0, val);}//=================================================//// Enable memory mapped io and unprotect registers////=================================================static void enable_mmio(void){ u8 tmp; outb(0x0B, 0x3C4); inb(0x3C5); // Set NEW mode 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(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}//=================================================//// Set pixel clock VCLK1// - 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; 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++) { 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 > 0) output("pixclock = %d.%02d MHz, k/m/n %x %x %x\n", freq / 100, freq % 100, (hi & 0xc0) >> 6, hi & 0x3f, lo);}//================================================//// Cyberblade specific Graphics Engine (GE) setup////================================================static void cyblafb_setup_GE(int pitch, int bpp){ KD_GRAPHICS_RETURN(); switch (bpp) { 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 by toggling out32(GE24, 0); // d7 of GE24 write3X4(CR2D, 0x00); // GE Timinigs, no delays out32(GE6C, 0); // Pattern and Style, p 129, ok}//=====================================================================//// 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){ u32 status, i = 100000; KD_GRAPHICS_RETURN(0); while (((status = in32(GE20)) & 0xFe800000) && i != 0) i--; if (i == 0) { enable_mmio(); i = 1000000; while (((status = in32(GE20)) & 0xFA800000) && i != 0) i--; if (i == 0) { output("GE Timeout, status: %x\n", status); if (status & 0x80000000) output("Bresenham Engine : Busy\n"); if (status & 0x40000000) output("Setup Engine : Busy\n"); if (status & 0x20000000) output("SP / DPE : Busy\n"); if (status & 0x10000000) output("Memory Interface : Busy\n"); if (status & 0x08000000) output("Com Lst Proc : Busy\n"); if (status & 0x04000000) output("Block Write : Busy\n"); if (status & 0x02000000) output("Command Buffer : Full\n"); if (status & 0x01000000) output("RESERVED : Busy\n"); if (status & 0x00800000) output("PCI Write Buffer : Busy\n"); cyblafb_setup_GE(info->var.xres, info->var.bits_per_pixel); } } return 0;}//==============================//// Cyberblade specific fillrect////==============================static void cyblafb_fillrect(struct fb_info *info, const struct fb_fillrect *fr){ 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; } 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){ 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); if ((ca->sy > ca->dy) || ((ca->sy == ca->dy) && (ca->sx > ca->dx))) direction = 0; else direction = 2; 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 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; 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]; } else { fgcol = image->fg_color; bgcol = image->bg_color; } switch (bpp) { case 8: fgcol |= fgcol << 8; bgcol |= bgcol << 8; case 16: fgcol |= fgcol << 16; bgcol |= bgcol << 16; default: break; } 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; } 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; } } 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++); } } }}//==========================================================//// Check if video mode is acceptable. We change var->??? if// video mode is slightly off or return error otherwise.// info->??? must not be changed!////==========================================================static int cyblafb_check_var(struct fb_var_screeninfo *var, struct fb_info *info){ int bpp = var->bits_per_pixel; // // we try to support 8, 16, 24 and 32 bpp modes, // default to 8 // // there is a 24 bpp mode, but for now we change requests to 32 bpp // (This is what tridentfb does ... will be changed in the future) // // if (bpp % 8 != 0 || bpp < 8 || bpp > 32) bpp = 8; if (bpp == 24) bpp = var->bits_per_pixel = 32; // // interlaced modes are broken, fail if one is requested // if (var->vmode & FB_VMODE_INTERLACED) return -EINVAL; // // fail if requested resolution is higher than physical // flatpanel resolution // if ((displaytype == DISPLAY_FP) && nativex && var->xres > nativex) return -EINVAL; // // we do not allow vclk to exceed 230 MHz. If the requested // vclk is too high, we default to 200 MHz // if ((bpp == 32 ? 200000000 : 100000000) / var->pixclock > 23000) var->pixclock = (bpp == 32 ? 200000000 : 100000000) / 20000; //
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -