ep93xxfb.c
来自「非常珍贵的LINUX下的专门针对CIRRUS公司的EP93XX平台的驱动源代码」· C语言 代码 · 共 2,214 行 · 第 1/4 页
C
2,214 行
/****************************************************************************** * * Reminder about setting up /dev device nodes: * * console c 5,1 to virtual console driver * so that Linux bootup is visible * when fb is console. * * fb link /dev/fb0 used by applications * * fb0 c 29,0 to fbmem device * * tty link /dev/console recommended by BinZ for * tty0 link /dev/console older Linux applications * * *============================================================================= * Hardware Details *============================================================================= * * 1. Display controller uses system memory, not a dedicated frame buffer * RAM. This means that display controller bandwidth to RAM steals from * CPU bandwidth to RAM. * * So if bandwidth to memory is about 80MB/s assuming that * all accesses are 16 byte blocks taking 10 clocks on 50MHz * system bus. Then 640x480x8 60Hz is about 19MB/s, or * 1/4 of bus bandwidth which should not impact us badly. * * 2. Dual hw palettes are a way to avoid sparkle and allow updating at * anytime, not just during blank period. Pending hw palette switch * takes place once per frame during blank. * * So we keep the master palette copy in memory and update the active hw * palette by updating the inactive hw palette and then switching. * * The only complication is writing palette while switch is pending. * We assume LUTSTAT is updated synchronously with bus clock so that * writes to LUT complete to either RAM0 or RAM1, even if request to * switch RAMs comes in asynchronously, in the middle of write to LUT. * * 3. Some timing registers must be unlocked before access. * *****************************************************************************/#include <linux/config.h>#include <linux/module.h>#include <linux/kernel.h>#include <linux/sched.h>#include <linux/errno.h>#include <linux/delay.h>#include <linux/string.h>#include <linux/ctype.h>#include <linux/mm.h>#include <linux/tty.h>#include <linux/slab.h>#include <linux/init.h>#include <linux/fb.h>#include <linux/delay.h>#include <linux/wrapper.h>#include <asm/hardware.h>#include <asm/io.h>#include <asm/irq.h>#include <asm/mach-types.h>#include <asm/uaccess.h>#include <asm/proc/pgtable.h>//TBD some of these may not be needed until full implementation#include <video/fbcon.h>#include <video/fbcon-mfb.h>#include <video/fbcon-cfb4.h>#include <video/fbcon-cfb8.h>#include <video/fbcon-cfb16.h>#include "ep93xxfb.h"#define RasterSetLocked(registername,value) \ do { \ outl( 0xAA, REALITI_SWLOCK ); \ outl( value, registername); \ } while(0) //hzh/* * Debug macros */#ifdef DEBUG# define DPRINTK(fmt, args...) printk("%s: " fmt, __FUNCTION__ , ## args)#else# define DPRINTK(fmt, args...)#endif// Max palette entries over all video modes#define MAX_PALETTE_NUM_ENTRIES 256// Max X resolution and Y resolution depend on whether LCD is supported,// and the monitor type.#define MAX_CRT_XRES 640#define MAX_CRT_YRES 480// Max bpp is fixed for low resolutions, but fundamentally depends on the// memory bandwidth which the system can allocate to the raster engine,// and so depends on application.//// TBD can create an array which determines max bpp based on passed// TBD in resolutions.//#ifdef CONFIG_FB_EP93XX_8BPP#define MAX_BPP 8#elif defined(CONFIG_FB_EP93XX_16BPP_565)#define MAX_BPP 16#else#define MAX_BPP 32#endif// Framebuffer max mem size in bytes over all video modes// Note: mypar not valid yet so need hard numbers here.#define FB_MAX_MEM_SIZE ((MAX_CRT_XRES * MAX_CRT_YRES * MAX_BPP)/8)// Framebuffer mapped mem size in bytes// This will be an integral number of pages.#define FB_MAPPED_MEM_SIZE (PAGE_ALIGN(FB_MAX_MEM_SIZE + PAGE_SIZE))/* Minimum X and Y resolutions *///TBD how realistic is this for CRT??//#define MIN_XRES 64//#define MIN_YRES 64#define EP93XX_NAME "EP93XX"#define NR_MONTYPES 1/* Local LCD controller parameters *//* These can be reduced by making better use of fb_var_screeninfo parameters.*//* Several duplicates exist in the two structures. */struct ep93xxfb_par{ dma_addr_t p_screen_base; unsigned char *v_screen_base; unsigned long screen_size; unsigned int palette_size; unsigned int xres; unsigned int yres; unsigned int bits_per_pixel; int montype; unsigned int currcon; unsigned int visual; u16 palette[16]; // Funky 16 table lookup used by // "optional" Parameter.};//TBD Linux fbmon.c tries to check monitor support for requested mode.//TBD But 2.4.0 test11 has removed this code from the build./* Fake monspecs to fill in fbinfo structure *///TBD strict VGA monitor has 60,60 instead of 50,65static struct fb_monspecs __initdata monspecs = { 30000, 70000, 50, 65, 0 /* Generic, not fixed frequency */};static char default_font_storage[40];static char *default_font = "Acorn8x8";#if defined (CONFIG_FB_LCD_EP93XX)#define DEFAULT_MODE 1 //lgy 640*480#elif defined (CONFIG_FB_CX25871)#define DEFAULT_MODE 3#elif defined (CONFIG_FB_CRT_EP93XX)#define DEFAULT_MODE 0#else#error What Display Setting was that!!!#endifstatic int mode = DEFAULT_MODE;#ifdef CONFIG_FB_CX25871_OVERSCAN#define DEFAULT_OVERSCAN 1#else#define DEFAULT_OVERSCAN 0#endifstatic int overscan = DEFAULT_OVERSCAN;typedef struct _DisplayTimingValues{ const char *Name; unsigned long DisplayID; int (* RasterConfigure)(struct _DisplayTimingValues *pTimingValues); unsigned short Refresh; unsigned long VDiv; unsigned short HRes; unsigned short HFrontPorch; unsigned short HBackPorch; unsigned short HSyncWidth; unsigned short HTotalClocks; unsigned short VRes; unsigned short VFrontPorch; unsigned short VBackPorch; unsigned short VSyncWidth; unsigned short VTotalClocks;} DisplayTimingValues;typedef int (* fRasterConfigure)(DisplayTimingValues *);typedef enum{ CRT_GENERIC, Philips_LB064V02A1, CX25871, Sharp} DisplayType;#define TIMING_VALUES(NAME, DISPID, FUNC, REFRESH, VDIV, \ HRES, HFP, HBP, HSYNC, VRES, VFP, VBP, VSYNC) \{ \ Name:NAME, \ DISPID, FUNC, REFRESH, VDIV, \ HRES, HFP, HBP, HSYNC, (HRES + HFP + HBP + HSYNC), \ VRES, VFP, VBP, VSYNC, (VRES + VFP + VBP + VSYNC) \}static void InitializeCX25871For640x480NTSC(void);static int Conexant_CX25871(DisplayTimingValues *pTimingValues);static int PhilipsLCD(DisplayTimingValues *pTimingValues);DisplayTimingValues static TimingValues[]={ // // 640x480 Progressive Scan // TIMING_VALUES("CRT_GENERIC", CRT_GENERIC, (fRasterConfigure)0, 60, 0x0000c108, 640, 48, 16, 96, 480, 32, 11, 2), // // 640x480 Progressive Scan Philips LB064V02A1 on EDB9312 Board. //// TIMING_VALUES("Philips LB064V02A1", Philips_LB064V02A1,// PhilipsLCD,// 68, 0x0000c107, 640, 16, 48, 96, 480, 11, 31, 2),/* #define VBPD ((33-1)&0xff) #define VFPD ((10-1)&0xff) #define VSPW ((2-1) &0x3f) #define HBPD ((104-1)&0x7f) #define HFPD ((16-1)&0xff) #define HSPW ((96-1)&0xff) lcdcon1 : LCD1_BPP_16T | LCD1_PNR_TFT | LCD1_CLKVAL(8), lcdcon2 : LCD2_VBPD(20)| LCD2_VFPD(0) | LCD2_VSPW(0), lcdcon3 : LCD3_HBPD(55) | LCD3_HFPD (5), lcdcon4 : LCD4_HSPW(1) | LCD4_MVAL(13), lcdcon5 : (1<<11) | (1<<8) |(1<<9)|(1)|(1<<10) , */ TIMING_VALUES("CRT_GENERIC", CRT_GENERIC, (fRasterConfigure)0, 58, 0xc128, 320, 55, 1, 10, 240, 20, 2, 2), //TIMING_VALUES("CRT_GENERIC", CRT_GENERIC, // (fRasterConfigure)0, // 68, 0x0000c107, 640, 105, 10, 120, 480, 32, 2, 2), // // Sharp LQ64D343 LCD Panel // TIMING_VALUES("Sharp LQ64d343", CRT_GENERIC, (fRasterConfigure)0, 60, 0x0000c205, 640, 32, 32, 96, 480, 34, 34, 4), // // 640x480 NTSC Support for Conexant CX25871 // TIMING_VALUES("Conexant CX25871", CX25871, Conexant_CX25871, 60, 0x0000c317, 640, 0, 0, 0, 480, 0, 0, 0), // 4 // Sharp 240X320 LCD @46Hz Pirogressive Scan, lgy // TIMING_VALUES("CRT_GENERIC", CRT_GENERIC, (fRasterConfigure)0, 58, 0xc128, 240, 8, 8, 6, 320, 2, 2, 4),};#define NUM_TIMING_VALUES (sizeof(TimingValues)/sizeof(DisplayTimingValues))unsigned int master_palette[256]; /* master copy of palette data *///TBD Before fbcon started, the driver calls set_var with con=-1//TBD which initializes global_disp and puts ptr to it in info.//TBD Later on display console array keeps track of display settings.static struct display global_disp; /* Initial Display Settings */static struct fb_info fb_info; // initialized in init_fbinfo()static struct ep93xxfb_par mypar;static int ep93xxfb_get_fix(struct fb_fix_screeninfo *fix, int con, struct fb_info *info);static int ep93xxfb_get_var(struct fb_var_screeninfo *var, int con, struct fb_info *info);static int ep93xxfb_set_var(struct fb_var_screeninfo *var, int con, struct fb_info *info);static int ep93xxfb_get_cmap(struct fb_cmap *cmap, int kspc, int con, struct fb_info *info);static int ep93xxfb_set_cmap(struct fb_cmap *cmap, int kspc, int con, struct fb_info *info);static int ep93xxfb_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg, int con, struct fb_info *info);static int ep93xxfb_switch(int con, struct fb_info *info);static void ep93xxfb_blank(int blank, struct fb_info *info);static int MapFramebuffer(void);static int ConfigureRaster(struct fb_var_screeninfo *var, DisplayTimingValues *pTimingValues);static struct fb_ops ep93xxfb_ops = { owner: THIS_MODULE, fb_get_fix: ep93xxfb_get_fix, fb_get_var: ep93xxfb_get_var, fb_set_var: ep93xxfb_set_var, fb_get_cmap: ep93xxfb_get_cmap, fb_set_cmap: ep93xxfb_set_cmap, fb_ioctl: ep93xxfb_ioctl,};//-----------------------------------------------------------------------------// Local functions//-----------------------------------------------------------------------------/* * ep93xxfb_palette_write: * Encode palette data to 24bit palette format. * Write palette data to the master palette and inactive hw palette * switch palettes. And handle asynchronous palette switches. */static inline voidep93xxfb_palette_write(u_int regno, u_int red, u_int green, u_int blue, u_int trans){ unsigned int cont, i, pal; // pal = ((red & 0xFF00) << 8) | (green & 0xFF00) | ((blue & 0xFF00) >> 8); master_palette[regno] = pal; outl( pal, (COLOR_LUT+(regno<<2)) ); cont = inl(LUTCONT); if ((cont&LUTCONT_STAT && cont&LUTCONT_RAM1) || (!(cont&LUTCONT_STAT) && !(cont&LUTCONT_RAM1))) { for (i=0; i< 256; i++) // Update inactive LUT outl( master_palette[i], (COLOR_LUT+(i<<2)) ); // Switch active LUTs next frame outl( cont ^ LUTCONT_RAM1, LUTCONT ); }}static inline voidep93xxfb_palette_read(u_int regno, u_int *red, u_int *green, u_int *blue, u_int *trans){ // Only supports color LUT, not gray LUT unsigned int pal; // Read only needs to access master palette, not hw palettes. pal = master_palette[regno]; //TBD LCD mode may change LUT from R/G/B order to B/G/R order *red = (pal >> 8) & 0xFF00; *green = pal & 0xFF00; *blue = (pal << 8) & 0xFF00; *trans = 0;}//-----------------------------------------------------------------------------// Helper functions for fb driver//-----------------------------------------------------------------------------static intep93xxfb_getcolreg(u_int regno, u_int *red, u_int *green, u_int *blue, u_int *trans, struct fb_info *info){ if (regno >= mypar.palette_size) return 1; ep93xxfb_palette_read(regno, red, green, blue, trans); return 0;}static inline u_intchan_to_field(u_int chan, struct fb_bitfield *bf){ chan &= 0xffff; chan >>= 16 - bf->length; return chan << bf->offset;}static intep93xxfb_setcolreg(u_int regno, u_int red, u_int green, u_int blue, u_int trans, struct fb_info *info){ u_int val; if (regno >= mypar.palette_size) return 1; switch (info->disp->visual) { case FB_VISUAL_TRUECOLOR: if (regno < 16) { u16 *pal = info->pseudo_palette; val = chan_to_field(red, &info->var.red); val |= chan_to_field(green, &info->var.green); val |= chan_to_field(blue, &info->var.blue); pal[regno] = val; } break; case FB_VISUAL_PSEUDOCOLOR: ep93xxfb_palette_write(regno, red, green, blue, trans); break; } return 0;}//TBD Warning: fbmem.c ioctl could result in any of the helper functions being//TBD called with con=-1, which happens when info->display_fg == NULL,//TBD which presumably is only during initialization of fbcon.//TBD Is there any other condition under which con=-1?//TBD Maybe we do not even need to support it!static intep93xxfb_get_cmap(struct fb_cmap *cmap, int kspc, int con, struct fb_info *info){ int err = 0; //TBD does not expect call with con=-1 if currcon!=-1 if (con == -1) DPRINTK("get_cmap called with con=-1\n"); DPRINTK("mypar.visual=%d\n", mypar.visual); if (con == mypar.currcon) err = fb_get_cmap(cmap, kspc, ep93xxfb_getcolreg, info); else if (fb_display[con].cmap.len) fb_copy_cmap(&fb_display[con].cmap, cmap, kspc ? 0 : 2); else fb_copy_cmap(fb_default_cmap(mypar.palette_size), cmap, kspc ? 0 : 2); return err;}static intep93xxfb_set_cmap(struct fb_cmap *cmap, int kspc, int con, struct fb_info *info){ int err = 0; // // What kind of request is this??? // if (con == -1) { DPRINTK("ERROR set_cmap called with con=-1\n"); return(-1); } DPRINTK("mypar.visual=%d\n", mypar.visual); if (!fb_display[con].cmap.len) err = fb_alloc_cmap(&fb_display[con].cmap, mypar.palette_size, 0); if (!err) { if (con == mypar.currcon) err = fb_set_cmap(cmap, kspc, ep93xxfb_setcolreg, info); fb_copy_cmap(cmap, &fb_display[con].cmap, kspc ? 0 : 1); } return err;}static unsigned long cursor_data[64][4];static voidep93xxfb_cursor(struct ep93xx_cursor *cursor){ unsigned long data[64 * 4]; long i, x, y, save; if (cursor->flags & CURSOR_OFF) outl(inl(CURSORXYLOC) & ~0x00008000, CURSORXYLOC); if (cursor->flags & CURSOR_SETSHAPE) { copy_from_user(data, cursor->data, cursor->width * cursor->height / 4); save = inl(CURSORXYLOC); outl(save & ~0x00008000, CURSORXYLOC); for (y = 0, i = 0; y < cursor->height; y++) { for (x = 0; x < cursor->width; x += 16) cursor_data[y][x] = data[i++]; } outl(virt_to_phys(cursor_data), CURSOR_ADR_START); outl(virt_to_phys(cursor_data), CURSOR_ADR_RESET); outl(0x00000300 | ((cursor->height - 1) << 2) | ((cursor->width - 1) >> 4), CURSORSIZE); outl(save, CURSORXYLOC); } if (cursor->flags & CURSOR_SETCOLOR) { outl(cursor->color1, CURSORCOLOR1); outl(cursor->color2, CURSORCOLOR2); outl(cursor->blinkcolor1, CURSORBLINK1); outl(cursor->blinkcolor2, CURSORBLINK2); } if (cursor->flags & CURSOR_BLINK) { if (cursor->blinkrate) outl(0x00000100 | cursor->blinkrate, CURSORBLINK); else outl(0x000000ff, CURSORBLINK); } if (cursor->flags & CURSOR_MOVE) { x = (inl(HACTIVESTRTSTOP) & 0x000003ff) - cursor->dx - 2; y = (inl(VACTIVESTRTSTOP) & 0x000003ff) - cursor->dy; outl((inl(CURSORXYLOC) & 0x8000) | (y << 16) | x, CURSORXYLOC); } if (cursor->flags & CURSOR_ON) outl(inl(CURSORXYLOC) | 0x00008000, CURSORXYLOC);
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?