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 + -
显示快捷键?