pm2fb.c
来自「Linux Kernel 2.6.9 for OMAP1710」· C语言 代码 · 共 1,289 行 · 第 1/3 页
C
1,289 行
/* * Permedia2 framebuffer driver. * * 2.5/2.6 driver: * Copyright (c) 2003 Jim Hague (jim.hague@acm.org) * * based on 2.4 driver: * Copyright (c) 1998-2000 Ilario Nardinocchi (nardinoc@CS.UniBO.IT) * Copyright (c) 1999 Jakub Jelinek (jakub@redhat.com) * * and additional input from James Simmon's port of Hannu Mallat's tdfx * driver. * * $Id$ * * I have a Creative Graphics Blaster Exxtreme card - pm2fb on x86. * I have no access to other pm2fb implementations, and cannot test * on them. Therefore for now I am omitting Sparc and CVision code. * * Multiple boards support has been on the TODO list for ages. * Don't expect this to change. * * This file is subject to the terms and conditions of the GNU General Public * License. See the file COPYING in the main directory of this archive for * more details. * * */#include <linux/config.h>#include <linux/module.h>#include <linux/kernel.h>#include <linux/errno.h>#include <linux/string.h>#include <linux/mm.h>#include <linux/tty.h>#include <linux/slab.h>#include <linux/delay.h>#include <linux/fb.h>#include <linux/init.h>#include <linux/pci.h>#include <video/permedia2.h>#include <video/cvisionppc.h>#if !defined(__LITTLE_ENDIAN) && !defined(__BIG_ENDIAN)#error "The endianness of the target host has not been defined."#endif#if defined(__BIG_ENDIAN) && !defined(__sparc__)#define PM2FB_BE_APERTURE#endif#if !defined(CONFIG_PCI)#error "Only generic PCI cards supported."#endif#undef PM2FB_MASTER_DEBUG#ifdef PM2FB_MASTER_DEBUG#define DPRINTK(a,b...) printk(KERN_DEBUG "pm2fb: %s: " a, __FUNCTION__ , ## b)#else#define DPRINTK(a,b...)#endif/* * The 2.4 driver calls reset_card() at init time, where it also sets the * initial mode. I don't think the driver should touch the chip until * the console sets a video mode. So I was calling this at the start * of setting a mode. However, certainly on 1280x1024 depth 16 on my * PCI Graphics Blaster Exxtreme this causes the display to smear * slightly. I don't know why. Guesses to jim.hague@acm.org. */#undef RESET_CARD_ON_MODE_SET/* * Driver data */static char *mode __initdata = NULL;/* * The XFree GLINT driver will (I think to implement hardware cursor * support on TVP4010 and similar where there is no RAMDAC - see * comment in set_video) always request +ve sync regardless of what * the mode requires. This screws me because I have a Sun * fixed-frequency monitor which absolutely has to have -ve sync. So * these flags allow the user to specify that requests for +ve sync * should be silently turned in -ve sync. */static int lowhsync __initdata = 0;static int lowvsync __initdata = 0; /* * The hardware state of the graphics card that isn't part of the * screeninfo. */struct pm2fb_par{ pm2type_t type; /* Board type */ u32 fb_size; /* framebuffer memory size */ unsigned char* v_fb; /* virtual address of frame buffer */ unsigned char* v_regs; /* virtual address of p_regs */ u32 memclock; /* memclock */ u32 video; /* video flags before blanking */};/* * Here we define the default structs fb_fix_screeninfo and fb_var_screeninfo * if we don't use modedb. */static struct fb_fix_screeninfo pm2fb_fix __initdata = { .id = "", .type = FB_TYPE_PACKED_PIXELS, .visual = FB_VISUAL_PSEUDOCOLOR, .xpanstep = 1, .ypanstep = 1, .ywrapstep = 0, .accel = FB_ACCEL_NONE,};/* * Default video mode. In case the modedb doesn't work, or we're * a module (in which case modedb doesn't really work). */static struct fb_var_screeninfo pm2fb_var __initdata = { /* "640x480, 8 bpp @ 60 Hz */ .xres = 640, .yres = 480, .xres_virtual = 640, .yres_virtual = 480, .bits_per_pixel =8, .red = {0, 8, 0}, .blue = {0, 8, 0}, .green = {0, 8, 0}, .activate = FB_ACTIVATE_NOW, .height = -1, .width = -1, .accel_flags = 0, .pixclock = 39721, .left_margin = 40, .right_margin = 24, .upper_margin = 32, .lower_margin = 11, .hsync_len = 96, .vsync_len = 2, .vmode = FB_VMODE_NONINTERLACED};/* * Utility functions */inline static u32 RD32(unsigned char* base, s32 off){ return fb_readl(base + off);}inline static void WR32(unsigned char* base, s32 off, u32 v){ fb_writel(v, base + off);}inline static u32 pm2_RD(struct pm2fb_par* p, s32 off){ return RD32(p->v_regs, off);}inline static void pm2_WR(struct pm2fb_par* p, s32 off, u32 v){ WR32(p->v_regs, off, v);}inline static u32 pm2_RDAC_RD(struct pm2fb_par* p, s32 idx){ int index = PM2R_RD_INDEXED_DATA; switch (p->type) { case PM2_TYPE_PERMEDIA2: pm2_WR(p, PM2R_RD_PALETTE_WRITE_ADDRESS, idx); break; case PM2_TYPE_PERMEDIA2V: pm2_WR(p, PM2VR_RD_INDEX_LOW, idx & 0xff); index = PM2VR_RD_INDEXED_DATA; break; } mb(); return pm2_RD(p, index);}inline static void pm2_RDAC_WR(struct pm2fb_par* p, s32 idx, u32 v){ int index = PM2R_RD_INDEXED_DATA; switch (p->type) { case PM2_TYPE_PERMEDIA2: pm2_WR(p, PM2R_RD_PALETTE_WRITE_ADDRESS, idx); break; case PM2_TYPE_PERMEDIA2V: pm2_WR(p, PM2VR_RD_INDEX_LOW, idx & 0xff); index = PM2VR_RD_INDEXED_DATA; break; } mb(); pm2_WR(p, index, v);}inline static u32 pm2v_RDAC_RD(struct pm2fb_par* p, s32 idx){ pm2_WR(p, PM2VR_RD_INDEX_LOW, idx & 0xff); mb(); return pm2_RD(p, PM2VR_RD_INDEXED_DATA);}inline static void pm2v_RDAC_WR(struct pm2fb_par* p, s32 idx, u32 v){ pm2_WR(p, PM2VR_RD_INDEX_LOW, idx & 0xff); mb(); pm2_WR(p, PM2VR_RD_INDEXED_DATA, v);}#ifdef CONFIG_FB_PM2_FIFO_DISCONNECT#define WAIT_FIFO(p,a)#elseinline static void WAIT_FIFO(struct pm2fb_par* p, u32 a){ while( pm2_RD(p, PM2R_IN_FIFO_SPACE) < a ); mb();}#endif/* * partial products for the supported horizontal resolutions. */#define PACKPP(p0,p1,p2) (((p2) << 6) | ((p1) << 3) | (p0))static const struct { u16 width; u16 pp;} pp_table[] = { { 32, PACKPP(1, 0, 0) }, { 64, PACKPP(1, 1, 0) }, { 96, PACKPP(1, 1, 1) }, { 128, PACKPP(2, 1, 1) }, { 160, PACKPP(2, 2, 1) }, { 192, PACKPP(2, 2, 2) }, { 224, PACKPP(3, 2, 1) }, { 256, PACKPP(3, 2, 2) }, { 288, PACKPP(3, 3, 1) }, { 320, PACKPP(3, 3, 2) }, { 384, PACKPP(3, 3, 3) }, { 416, PACKPP(4, 3, 1) }, { 448, PACKPP(4, 3, 2) }, { 512, PACKPP(4, 3, 3) }, { 544, PACKPP(4, 4, 1) }, { 576, PACKPP(4, 4, 2) }, { 640, PACKPP(4, 4, 3) }, { 768, PACKPP(4, 4, 4) }, { 800, PACKPP(5, 4, 1) }, { 832, PACKPP(5, 4, 2) }, { 896, PACKPP(5, 4, 3) }, { 1024, PACKPP(5, 4, 4) }, { 1056, PACKPP(5, 5, 1) }, { 1088, PACKPP(5, 5, 2) }, { 1152, PACKPP(5, 5, 3) }, { 1280, PACKPP(5, 5, 4) }, { 1536, PACKPP(5, 5, 5) }, { 1568, PACKPP(6, 5, 1) }, { 1600, PACKPP(6, 5, 2) }, { 1664, PACKPP(6, 5, 3) }, { 1792, PACKPP(6, 5, 4) }, { 2048, PACKPP(6, 5, 5) }, { 0, 0 } };static u32 partprod(u32 xres){ int i; for (i = 0; pp_table[i].width && pp_table[i].width != xres; i++) ; if ( pp_table[i].width == 0 ) DPRINTK("invalid width %u\n", xres); return pp_table[i].pp;}static u32 to3264(u32 timing, int bpp, int is64){ switch (bpp) { case 8: timing >>= 2 + is64; break; case 16: timing >>= 1 + is64; break; case 24: timing = (timing * 3) >> (2 + is64); break; case 32: if (is64) timing >>= 1; break; } return timing;}static void pm2_mnp(u32 clk, unsigned char* mm, unsigned char* nn, unsigned char* pp){ unsigned char m; unsigned char n; unsigned char p; u32 f; s32 curr; s32 delta = 100000; *mm = *nn = *pp = 0; for (n = 2; n < 15; n++) { for (m = 2; m; m++) { f = PM2_REFERENCE_CLOCK * m / n; if (f >= 150000 && f <= 300000) { for ( p = 0; p < 5; p++, f >>= 1) { curr = ( clk > f ) ? clk - f : f - clk; if ( curr < delta ) { delta=curr; *mm=m; *nn=n; *pp=p; } } } } }}static void pm2v_mnp(u32 clk, unsigned char* mm, unsigned char* nn, unsigned char* pp){ unsigned char m; unsigned char n; unsigned char p; u32 f; s32 delta = 1000; *mm = *nn = *pp = 0; for (n = 1; n; n++) { for ( m = 1; m; m++) { for ( p = 0; p < 2; p++) { f = PM2_REFERENCE_CLOCK * n / (m * (1 << (p + 1))); if ( clk > f - delta && clk < f + delta ) { delta = ( clk > f ) ? clk - f : f - clk; *mm=m; *nn=n; *pp=p; } } } }}static void clear_palette(struct pm2fb_par* p) { int i=256; WAIT_FIFO(p, 1); pm2_WR(p, PM2R_RD_PALETTE_WRITE_ADDRESS, 0); wmb(); while (i--) { WAIT_FIFO(p, 3); pm2_WR(p, PM2R_RD_PALETTE_DATA, 0); pm2_WR(p, PM2R_RD_PALETTE_DATA, 0); pm2_WR(p, PM2R_RD_PALETTE_DATA, 0); }}#ifdef RESET_CARD_ON_MODE_SETstatic void reset_card(struct pm2fb_par* p){ if (p->type == PM2_TYPE_PERMEDIA2V) pm2_WR(p, PM2VR_RD_INDEX_HIGH, 0); pm2_WR(p, PM2R_RESET_STATUS, 0); mb(); while (pm2_RD(p, PM2R_RESET_STATUS) & PM2F_BEING_RESET) ; mb();#ifdef CONFIG_FB_PM2_FIFO_DISCONNECT DPRINTK("FIFO disconnect enabled\n"); pm2_WR(p, PM2R_FIFO_DISCON, 1); mb();#endif}#endifstatic void reset_config(struct pm2fb_par* p){ WAIT_FIFO(p, 52); pm2_WR(p, PM2R_CHIP_CONFIG, pm2_RD(p, PM2R_CHIP_CONFIG)& ~(PM2F_VGA_ENABLE|PM2F_VGA_FIXED)); pm2_WR(p, PM2R_BYPASS_WRITE_MASK, ~(0L)); pm2_WR(p, PM2R_FRAMEBUFFER_WRITE_MASK, ~(0L)); pm2_WR(p, PM2R_FIFO_CONTROL, 0); pm2_WR(p, PM2R_APERTURE_ONE, 0); pm2_WR(p, PM2R_APERTURE_TWO, 0); pm2_WR(p, PM2R_RASTERIZER_MODE, 0); pm2_WR(p, PM2R_DELTA_MODE, PM2F_DELTA_ORDER_RGB); pm2_WR(p, PM2R_LB_READ_FORMAT, 0); pm2_WR(p, PM2R_LB_WRITE_FORMAT, 0); pm2_WR(p, PM2R_LB_READ_MODE, 0); pm2_WR(p, PM2R_LB_SOURCE_OFFSET, 0); pm2_WR(p, PM2R_FB_SOURCE_OFFSET, 0); pm2_WR(p, PM2R_FB_PIXEL_OFFSET, 0); pm2_WR(p, PM2R_FB_WINDOW_BASE, 0); pm2_WR(p, PM2R_LB_WINDOW_BASE, 0); pm2_WR(p, PM2R_FB_SOFT_WRITE_MASK, ~(0L)); pm2_WR(p, PM2R_FB_HARD_WRITE_MASK, ~(0L)); pm2_WR(p, PM2R_FB_READ_PIXEL, 0); pm2_WR(p, PM2R_DITHER_MODE, 0); pm2_WR(p, PM2R_AREA_STIPPLE_MODE, 0); pm2_WR(p, PM2R_DEPTH_MODE, 0); pm2_WR(p, PM2R_STENCIL_MODE, 0); pm2_WR(p, PM2R_TEXTURE_ADDRESS_MODE, 0); pm2_WR(p, PM2R_TEXTURE_READ_MODE, 0); pm2_WR(p, PM2R_TEXEL_LUT_MODE, 0); pm2_WR(p, PM2R_YUV_MODE, 0); pm2_WR(p, PM2R_COLOR_DDA_MODE, 0); pm2_WR(p, PM2R_TEXTURE_COLOR_MODE, 0); pm2_WR(p, PM2R_FOG_MODE, 0); pm2_WR(p, PM2R_ALPHA_BLEND_MODE, 0); pm2_WR(p, PM2R_LOGICAL_OP_MODE, 0); pm2_WR(p, PM2R_STATISTICS_MODE, 0); pm2_WR(p, PM2R_SCISSOR_MODE, 0); pm2_WR(p, PM2R_FILTER_MODE, PM2F_SYNCHRONIZATION); switch (p->type) { case PM2_TYPE_PERMEDIA2: pm2_RDAC_WR(p, PM2I_RD_MODE_CONTROL, 0); /* no overlay */ pm2_RDAC_WR(p, PM2I_RD_CURSOR_CONTROL, 0); pm2_RDAC_WR(p, PM2I_RD_MISC_CONTROL, PM2F_RD_PALETTE_WIDTH_8); break; case PM2_TYPE_PERMEDIA2V: pm2v_RDAC_WR(p, PM2VI_RD_MISC_CONTROL, 1); /* 8bit */ break; } pm2_RDAC_WR(p, PM2I_RD_COLOR_KEY_CONTROL, 0); pm2_RDAC_WR(p, PM2I_RD_OVERLAY_KEY, 0); pm2_RDAC_WR(p, PM2I_RD_RED_KEY, 0); pm2_RDAC_WR(p, PM2I_RD_GREEN_KEY, 0); pm2_RDAC_WR(p, PM2I_RD_BLUE_KEY, 0);}static void set_aperture(struct pm2fb_par* p, u32 depth){ WAIT_FIFO(p, 4);#ifdef __LITTLE_ENDIAN
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?