📄 tridentfb.c
字号:
ca->width, ca->height);}static int tridentfb_sync(struct fb_info *info){ struct tridentfb_par *par = info->par; if (!(info->flags & FBINFO_HWACCEL_DISABLED)) par->wait_engine(par); return 0;}#else#define tridentfb_fillrect cfb_fillrect#define tridentfb_copyarea cfb_copyarea#define tridentfb_imageblit cfb_imageblit#endif /* CONFIG_FB_TRIDENT_ACCEL *//* * Hardware access functions */static inline unsigned char read3X4(struct tridentfb_par *par, int reg){ return vga_mm_rcrt(par->io_virt, reg);}static inline void write3X4(struct tridentfb_par *par, int reg, unsigned char val){ vga_mm_wcrt(par->io_virt, reg, val);}static inline unsigned char read3CE(struct tridentfb_par *par, unsigned char reg){ return vga_mm_rgfx(par->io_virt, reg);}static inline void writeAttr(struct tridentfb_par *par, int reg, unsigned char val){ fb_readb(par->io_virt + VGA_IS1_RC); /* flip-flop to index */ vga_mm_wattr(par->io_virt, reg, val);}static inline void write3CE(struct tridentfb_par *par, int reg, unsigned char val){ vga_mm_wgfx(par->io_virt, reg, val);}static void enable_mmio(struct tridentfb_par *par){ /* Goto New Mode */ vga_io_rseq(0x0B); /* Unprotect registers */ vga_io_wseq(NewMode1, 0x80); if (!is_oldprotect(par->chip_id)) vga_io_wseq(Protection, 0x92); /* Enable MMIO */ outb(PCIReg, 0x3D4); outb(inb(0x3D5) | 0x01, 0x3D5);}static void disable_mmio(struct tridentfb_par *par){ /* Goto New Mode */ vga_mm_rseq(par->io_virt, 0x0B); /* Unprotect registers */ vga_mm_wseq(par->io_virt, NewMode1, 0x80); if (!is_oldprotect(par->chip_id)) vga_mm_wseq(par->io_virt, Protection, 0x92); /* Disable MMIO */ t_outb(par, PCIReg, 0x3D4); t_outb(par, t_inb(par, 0x3D5) & ~0x01, 0x3D5);}static inline void crtc_unlock(struct tridentfb_par *par){ write3X4(par, VGA_CRTC_V_SYNC_END, read3X4(par, VGA_CRTC_V_SYNC_END) & 0x7F);}/* Return flat panel's maximum x resolution */static int __devinit get_nativex(struct tridentfb_par *par){ int x, y, tmp; if (nativex) return nativex; tmp = (read3CE(par, VertStretch) >> 4) & 3; switch (tmp) { case 0: x = 1280; y = 1024; break; case 2: x = 1024; y = 768; break; case 3: x = 800; y = 600; break; case 4: x = 1400; y = 1050; break; case 1: default: x = 640; y = 480; break; } output("%dx%d flat panel found\n", x, y); return x;}/* Set pitch */static inline void set_lwidth(struct tridentfb_par *par, int width){ write3X4(par, VGA_CRTC_OFFSET, width & 0xFF); write3X4(par, AddColReg, (read3X4(par, AddColReg) & 0xCF) | ((width & 0x300) >> 4));}/* For resolutions smaller than FP resolution stretch */static void screen_stretch(struct tridentfb_par *par){ if (par->chip_id != CYBERBLADEXPAi1) write3CE(par, BiosReg, 0); else write3CE(par, BiosReg, 8); write3CE(par, VertStretch, (read3CE(par, VertStretch) & 0x7C) | 1); write3CE(par, HorStretch, (read3CE(par, HorStretch) & 0x7C) | 1);}/* For resolutions smaller than FP resolution center */static inline void screen_center(struct tridentfb_par *par){ write3CE(par, VertStretch, (read3CE(par, VertStretch) & 0x7C) | 0x80); write3CE(par, HorStretch, (read3CE(par, HorStretch) & 0x7C) | 0x80);}/* Address of first shown pixel in display memory */static void set_screen_start(struct tridentfb_par *par, int base){ u8 tmp; write3X4(par, VGA_CRTC_START_LO, base & 0xFF); write3X4(par, VGA_CRTC_START_HI, (base & 0xFF00) >> 8); tmp = read3X4(par, CRTCModuleTest) & 0xDF; write3X4(par, CRTCModuleTest, tmp | ((base & 0x10000) >> 11)); tmp = read3X4(par, CRTHiOrd) & 0xF8; write3X4(par, CRTHiOrd, tmp | ((base & 0xE0000) >> 17));}/* Set dotclock frequency */static void set_vclk(struct tridentfb_par *par, unsigned long freq){ int m, n, k; unsigned long fi, d, di; unsigned char best_m = 0, best_n = 0, best_k = 0; unsigned char hi, lo; unsigned char shift = !is_oldclock(par->chip_id) ? 2 : 1; d = 20000; for (k = shift; k >= 0; k--) for (m = 1; m < 32; m++) { n = ((m + 2) << shift) - 8; for (n = (n < 0 ? 0 : n); n < 122; n++) { fi = ((14318l * (n + 8)) / (m + 2)) >> k; di = abs(fi - freq); if (di < d || (di == d && k == best_k)) { d = di; best_n = n; best_m = m; best_k = k; } if (fi > freq) break; } } if (is_oldclock(par->chip_id)) { lo = best_n | (best_m << 7); hi = (best_m >> 1) | (best_k << 4); } else { lo = best_n; hi = best_m | (best_k << 6); } if (is3Dchip(par->chip_id)) { vga_mm_wseq(par->io_virt, ClockHigh, hi); vga_mm_wseq(par->io_virt, ClockLow, lo); } else { t_outb(par, lo, 0x43C8); t_outb(par, hi, 0x43C9); } debug("VCLK = %X %X\n", hi, lo);}/* Set number of lines for flat panels*/static void set_number_of_lines(struct tridentfb_par *par, int lines){ int tmp = read3CE(par, CyberEnhance) & 0x8F; if (lines > 1024) tmp |= 0x50; else if (lines > 768) tmp |= 0x30; else if (lines > 600) tmp |= 0x20; else if (lines > 480) tmp |= 0x10; write3CE(par, CyberEnhance, tmp);}/* * If we see that FP is active we assume we have one. * Otherwise we have a CRT display. User can override. */static int __devinit is_flatpanel(struct tridentfb_par *par){ if (fp) return 1; if (crt || !iscyber(par->chip_id)) return 0; return (read3CE(par, FPConfig) & 0x10) ? 1 : 0;}/* Try detecting the video memory size */static unsigned int __devinit get_memsize(struct tridentfb_par *par){ unsigned char tmp, tmp2; unsigned int k; /* If memory size provided by user */ if (memsize) k = memsize * Kb; else switch (par->chip_id) { case CYBER9525DVD: k = 2560 * Kb; break; default: tmp = read3X4(par, SPR) & 0x0F; switch (tmp) { case 0x01: k = 512 * Kb; break; case 0x02: k = 6 * Mb; /* XP */ break; case 0x03: k = 1 * Mb; break; case 0x04: k = 8 * Mb; break; case 0x06: k = 10 * Mb; /* XP */ break; case 0x07: k = 2 * Mb; break; case 0x08: k = 12 * Mb; /* XP */ break; case 0x0A: k = 14 * Mb; /* XP */ break; case 0x0C: k = 16 * Mb; /* XP */ break; case 0x0E: /* XP */ tmp2 = vga_mm_rseq(par->io_virt, 0xC1); switch (tmp2) { case 0x00: k = 20 * Mb; break; case 0x01: k = 24 * Mb; break; case 0x10: k = 28 * Mb; break; case 0x11: k = 32 * Mb; break; default: k = 1 * Mb; break; } break; case 0x0F: k = 4 * Mb; break; default: k = 1 * Mb; break; } } k -= memdiff * Kb; output("framebuffer size = %d Kb\n", k / Kb); return k;}/* See if we can handle the video mode described in var */static int tridentfb_check_var(struct fb_var_screeninfo *var, struct fb_info *info){ struct tridentfb_par *par = info->par; int bpp = var->bits_per_pixel; int line_length; int ramdac = 230000; /* 230MHz for most 3D chips */ debug("enter\n"); /* check color depth */ if (bpp == 24) bpp = var->bits_per_pixel = 32; if (bpp != 8 && bpp != 16 && bpp != 32) return -EINVAL; if (par->chip_id == TGUI9440 && bpp == 32) return -EINVAL; /* check whether resolution fits on panel and in memory */ if (par->flatpanel && nativex && var->xres > nativex) return -EINVAL; /* various resolution checks */ var->xres = (var->xres + 7) & ~0x7; if (var->xres > var->xres_virtual) var->xres_virtual = var->xres; if (var->yres > var->yres_virtual) var->yres_virtual = var->yres; if (var->xres_virtual > 4095 || var->yres > 2048) return -EINVAL; /* prevent from position overflow for acceleration */ if (var->yres_virtual > 0xffff) return -EINVAL; line_length = var->xres_virtual * bpp / 8; if (!is3Dchip(par->chip_id) && !(info->flags & FBINFO_HWACCEL_DISABLED)) { /* acceleration requires line length to be power of 2 */ if (line_length <= 512) var->xres_virtual = 512 * 8 / bpp; else if (line_length <= 1024) var->xres_virtual = 1024 * 8 / bpp; else if (line_length <= 2048) var->xres_virtual = 2048 * 8 / bpp; else if (line_length <= 4096) var->xres_virtual = 4096 * 8 / bpp; else if (line_length <= 8192) var->xres_virtual = 8192 * 8 / bpp; else return -EINVAL; line_length = var->xres_virtual * bpp / 8; } /* datasheet specifies how to set panning only up to 4 MB */ if (line_length * (var->yres_virtual - var->yres) > (4 << 20)) var->yres_virtual = ((4 << 20) / line_length) + var->yres; if (line_length * var->yres_virtual > info->fix.smem_len) return -EINVAL; switch (bpp) { case 8: var->red.offset = 0; var->red.length = 8; var->green = var->red; var->blue = var->red; 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; } if (is_xp(par->chip_id)) ramdac = 350000; switch (par->chip_id) { case TGUI9440: ramdac = (bpp >= 16) ? 45000 : 90000; break; case CYBER9320: case TGUI9660: ramdac = 135000; break; case PROVIDIA9685: case CYBER9388: case CYBER9382: case CYBER9385: ramdac = 170000; break; } /* The clock is doubled for 32 bpp */ if (bpp == 32) ramdac /= 2; if (PICOS2KHZ(var->pixclock) > ramdac) return -EINVAL; debug("exit\n"); return 0;}/* Pan the display */static int tridentfb_pan_display(struct fb_var_screeninfo *var, struct fb_info *info){ struct tridentfb_par *par = info->par; unsigned int offset; debug("enter\n"); offset = (var->xoffset + (var->yoffset * var->xres_virtual)) * var->bits_per_pixel / 32; set_screen_start(par, offset); debug("exit\n"); return 0;}static inline void shadowmode_on(struct tridentfb_par *par){ write3CE(par, CyberControl, read3CE(par, CyberControl) | 0x81);}static inline void shadowmode_off(struct tridentfb_par *par){ write3CE(par, CyberControl, read3CE(par, CyberControl) & 0x7E);}/* Set the hardware to the requested video mode */static int tridentfb_set_par(struct fb_info *info){ struct tridentfb_par *par = info->par; u32 htotal, hdispend, hsyncstart, hsyncend, hblankstart, hblankend; u32 vtotal, vdispend, vsyncstart, vsyncend, vblankstart, vblankend; struct fb_var_screeninfo *var = &info->var; int bpp = var->bits_per_pixel; unsigned char tmp; unsigned long vclk; debug("enter\n"); hdispend = var->xres / 8 - 1; hsyncstart = (var->xres + var->right_margin) / 8; hsyncend = (var->xres + var->right_margin + var->hsync_len) / 8; htotal = (var->xres + var->left_margin + var->right_margin + var->hsync_len) / 8 - 5; hblankstart = hdispend + 1; hblankend = htotal + 3; vdispend = var->yres - 1; vsyncstart = var->yres + var->lower_margin; vsyncend = vsyncstart + var->vsync_len; vtotal = var->upper_margin + vsyncend - 2; vblankstart = vdispend + 1; vblankend = vtotal; if (info->var.vmode & FB_VMODE_INTERLACED) { vtotal /= 2; vdispend /= 2; vsyncstart /= 2; vsyncend /= 2; vblankstart /= 2; vblankend /= 2; } enable_mmio(par); crtc_unlock(par); write3CE(par, CyberControl, 8); tmp = 0xEB; if (var->sync & FB_SYNC_HOR_HIGH_ACT) tmp &= ~0x40; if (var->sync & FB_SYNC_VERT_HIGH_ACT) tmp &= ~0x80; if (par->flatpanel && var->xres < nativex) { /* * on flat panels with native size larger * than requested resolution decide whether * we stretch or center */ t_outb(par, tmp | 0xC0, VGA_MIS_W); shadowmode_on(par); if (center) screen_center(par); else if (stretch) screen_stretch(par); } else { t_outb(par, tmp, VGA_MIS_W); write3CE(par, CyberControl, 8); } /* vertical timing values */ write3X4(par, VGA_CRTC_V_TOTAL, vtotal & 0xFF); write3X4(par, VGA_CRTC_V_DISP_END, vdispend & 0xFF); write3X4(par, VGA_CRTC_V_SYNC_START, vsyncstart & 0xFF); write3X4(par, VGA_CRTC_V_SYNC_END, (vsyncend & 0x0F)); write3X4(par, VGA_CRTC_V_BLANK_START, vblankstart & 0xFF); write3X4(par, VGA_CRTC_V_BLANK_END, vblankend & 0xFF); /* horizontal timing values */ write3X4(par, VGA_CRTC_H_TOTAL, htotal & 0xFF); write3X4(par, VGA_CRTC_H_DISP, hdispend & 0xFF); write3X4(par, VGA_CRTC_H_SYNC_START, hsyncstart & 0xFF); write3X4(par, VGA_CRTC_H_SYNC_END, (hsyncend & 0x1F) | ((hblankend & 0x20) << 2)); write3X4(par, VGA_CRTC_H_BLANK_START, hblankstart & 0xFF); write3X4(par, VGA_CRTC_H_BLANK_END, hblankend & 0x1F); /* higher bits of vertical timing values */ tmp = 0x10; if (vtotal & 0x100) tmp |= 0x01; if (vdispend & 0x100) tmp |= 0x02; if (vsyncstart & 0x100) tmp |= 0x04; if (vblankstart & 0x100) tmp |= 0x08; if (vtotal & 0x200) tmp |= 0x20; if (vdispend & 0x200) tmp |= 0x40; if (vsyncstart & 0x200) tmp |= 0x80; write3X4(par, VGA_CRTC_OVERFLOW, tmp); tmp = read3X4(par, CRTHiOrd) & 0x07; tmp |= 0x08; /* line compare bit 10 */ if (vtotal & 0x400) tmp |= 0x80; if (vblankstart & 0x400) tmp |= 0x40; if (vsyncstart & 0x400) tmp |= 0x20; if (vdispend & 0x400) tmp |= 0x10; write3X4(par, CRTHiOrd, tmp);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -