⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 epson1356fb.c

📁 S3C44B0X下的LCD (framebuffer)驱动资料与相关代码
💻 C
📖 第 1 页 / 共 5 页
字号:
/* *	epson1356fb.c  --  Epson SED1356 Framebuffer Driver * *	Copyright 2001, 2002, 2003 MontaVista Software Inc. *	Author: MontaVista Software, Inc. *		stevel@mvista.com or source@mvista.com * *	This program is free software; you can redistribute  it and/or modify it *	under  the terms of  the GNU General  Public License as published by the *	Free Software Foundation;  either version 2 of the  License, or (at your *	option) any later version. * *	THIS  SOFTWARE  IS PROVIDED   ``AS  IS'' AND   ANY  EXPRESS OR IMPLIED *	WARRANTIES,   INCLUDING, BUT NOT  LIMITED  TO, THE IMPLIED WARRANTIES OF *	MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN *	NO  EVENT  SHALL   THE AUTHOR  BE    LIABLE FOR ANY   DIRECT, INDIRECT, *	INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT *	NOT LIMITED   TO, PROCUREMENT OF  SUBSTITUTE GOODS  OR SERVICES; LOSS OF *	USE, DATA,  OR PROFITS; OR  BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON *	ANY THEORY OF LIABILITY, WHETHER IN  CONTRACT, STRICT LIABILITY, OR TORT *	(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF *	THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * *	You should have received a copy of the  GNU General Public License along *	with this program; if not, write  to the Free Software Foundation, Inc., *	675 Mass Ave, Cambridge, MA 02139, USA. * *  *	TODO: * *	Revision history *	03.12.2001  0.1   Initial release * */#include <linux/config.h>#include <linux/version.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/vmalloc.h>#include <linux/delay.h>#include <linux/interrupt.h>#include <linux/fb.h>#include <linux/selection.h>#include <linux/console.h>#include <linux/init.h>#include <linux/pci.h>#include <linux/nvram.h>#include <linux/kd.h>#include <linux/vt_kern.h>#include <asm/io.h>#include <asm/uaccess.h>#include <linux/timer.h>#include <linux/pagemap.h>#include <asm/pgalloc.h>#include <asm/uaccess.h>#include <asm/tlb.h>#ifdef CONFIG_MTRR#include <asm/mtrr.h>#endif#include <video/fbcon.h>#include <video/fbcon-cfb8.h>#include <video/fbcon-cfb16.h>#include <video/fbcon-cfb24.h>#include <video/fbcon-cfb32.h>#include <linux/spinlock.h>#include <video/e1356fb.h>#ifdef CONFIG_SOC_AU1X00#include <asm/au1000.h>#endif#define E1356FB_DEBUG 1#undef E1356FB_VERBOSE_DEBUG#undef SHADOW_FRAME_BUFFER#include "epson1356fb.h"static char *options;MODULE_PARM(options, "s");/* *  Frame buffer device API */static int e1356fb_open(struct fb_info *fb, int user);static int e1356fb_release(struct fb_info *fb, int user);static int e1356fb_get_fix(struct fb_fix_screeninfo* fix, 			   int con,			   struct fb_info* fb);static int e1356fb_get_var(struct fb_var_screeninfo* var, 			   int con,			   struct fb_info* fb);static int e1356fb_set_var(struct fb_var_screeninfo* var,			   int con,			   struct fb_info* fb);static int e1356fb_pan_display(struct fb_var_screeninfo* var, 			       int con,			       struct fb_info* fb);static int e1356fb_get_cmap(struct fb_cmap *cmap, 			    int kspc, 			    int con,			    struct fb_info* info);static int e1356fb_set_cmap(struct fb_cmap* cmap, 			    int kspc, 			    int con,			    struct fb_info* info);static int e1356fb_ioctl(struct inode* inode, 			 struct file* file, 			 u_int cmd,			 u_long arg, 			 int con, 			 struct fb_info* info);static int e1356fb_mmap(struct fb_info *info,			struct file *file,			struct vm_area_struct *vma);/* *  Interface to the low level console driver */static int  e1356fb_switch_con(int con, 			       struct fb_info* fb);static int  e1356fb_updatevar(int con, 			      struct fb_info* fb);static void e1356fb_blank(int blank, 			  struct fb_info* fb);/* *  Internal routines */static void e1356fb_set_par(const struct e1356fb_par* par,			    struct fb_info_e1356* 			    info);static int  e1356fb_var_to_par(const struct fb_var_screeninfo *var,			       struct e1356fb_par* par,			       const struct fb_info_e1356* info);static int  e1356fb_par_to_var(struct fb_var_screeninfo* var,			       struct e1356fb_par* par,			       const struct fb_info_e1356* info);static int  e1356fb_encode_fix(struct fb_fix_screeninfo* fix,			       const struct e1356fb_par* par,			       const struct fb_info_e1356* info);static void e1356fb_set_dispsw(struct display* disp, 			       struct fb_info_e1356* info,			       int bpp, 			       int accel);static int  e1356fb_getcolreg(u_int regno,			      u_int* red, 			      u_int* green, 			      u_int* blue,			      u_int* transp, 			      struct fb_info* fb);static int  e1356fb_setcolreg(u_int regno, 			      u_int red, 			      u_int green, 			      u_int blue,			      u_int transp, 			      struct fb_info* fb);static void  e1356fb_install_cmap(struct display *d, 				  struct fb_info *info);static void e1356fb_hwcursor_init(struct fb_info_e1356* info);static void e1356fb_createcursorshape(struct display* p);static void e1356fb_createcursor(struct display * p);  /* * do_xxx: Hardware-specific functions */static void  do_pan_var(struct fb_var_screeninfo* var,			struct fb_info_e1356* i);static void  do_flashcursor(unsigned long ptr);static void  doBlt_Move(const struct e1356fb_par* par,			struct fb_info_e1356* i,			blt_info_t* blt);static void  doBlt_SolidFill(const struct e1356fb_par* par,			     struct fb_info_e1356* i,			     blt_info_t* blt);/* *  Interface used by the world */int e1356fb_init(void);void e1356fb_setup(char *options, int *ints);static int currcon = 0;static struct fb_ops e1356fb_ops = {	owner:	THIS_MODULE,	fb_open:        e1356fb_open,	fb_release:     e1356fb_release,	fb_get_fix:	e1356fb_get_fix,	fb_get_var:	e1356fb_get_var,	fb_set_var:	e1356fb_set_var,	fb_get_cmap:    e1356fb_get_cmap,	fb_set_cmap:    e1356fb_set_cmap,	fb_pan_display: e1356fb_pan_display,	fb_ioctl:	e1356fb_ioctl,	fb_mmap:        e1356fb_mmap,};#define PCI_VENDOR_ID_EPSON         0x10f4#define PCI_DEVICE_ID_EPSON_SDU1356 0x1300static struct fb_info_e1356 fb_info;static struct e1356fb_fix boot_fix; // boot optionsstatic struct e1356fb_par boot_par; // boot options/* -------------------------------------------------------------------------  *                      Hardware-specific funcions * ------------------------------------------------------------------------- *//* * The SED1356 has only a 16-bit wide data bus, so some embedded * implementations with 32-bit CPU's (Alchemy Pb1000) may not * correctly emulate a 32-bit write to the framebuffer by splitting * the write into two seperate 16-bit writes. So it is safest to * only do byte or half-word writes to the fb. This routine assumes * fbaddr is atleast aligned on a half-word boundary. */static inline voidfbfill(u16* fbaddr, u8 val, int size){	u16 valw = (u16)val | ((u16)val << 8);	for ( ; size >= 2; size -= 2)		writew(valw, fbaddr++);	if (size)		writeb(val, (u8*)fbaddr);}static inline inte1356_wait_bitclr(u8* reg, u8 bit, int timeout){	while (readb(reg) & bit) {		udelay(10);		if (!--timeout)			break;	}	return timeout;}static inline inte1356_wait_bitset(u8* reg, u8 bit, int timeout){	while (!(readb(reg) & bit)) {		udelay(10);		if (!--timeout)			break;	}	return timeout;}static struct fb_videomode panel_modedb[] = {	{		/* 320x240 @ 109 Hz, 33.3 kHz hsync */		NULL, 109, 320, 240, KHZ2PICOS(MAX_PIXCLOCK/3),		16, 16, 32, 24, 48, 8,		0, FB_VMODE_NONINTERLACED	}, {		/* 640x480 @ 84 Hz, 48.1 kHz hsync */		NULL, 84, 640, 480, KHZ2PICOS(MAX_PIXCLOCK/1),		96, 32, 32, 48, 64, 8,		0, FB_VMODE_NONINTERLACED	}, {		/* 800x600 @ 76 Hz, 46.3 kHz hsync */		NULL, 76, 800, 600, KHZ2PICOS(MAX_PIXCLOCK/1),		32, 10, 1, 1, 22, 1,		0, FB_VMODE_NONINTERLACED	}};static struct fb_videomode crt_modedb[] = {	{		/* 320x240 @ 84 Hz, 31.25 kHz hsync */		NULL, 84, 320, 240, KHZ2PICOS(MAX_PIXCLOCK/2),		128, 128, 60, 60, 64, 8,		0, FB_VMODE_NONINTERLACED	}, {		/* 320x240 @ 109 Hz, 33.3 kHz hsync */		NULL, 109, 320, 240, KHZ2PICOS(MAX_PIXCLOCK/3),		16, 16, 32, 24, 48, 8,		0, FB_VMODE_NONINTERLACED	}, {		/* 512x384 @ 77 Hz, 31.25 kHz hsync */		NULL, 77, 512, 384, KHZ2PICOS(MAX_PIXCLOCK/2),		48, 16, 16, 1, 64, 3,		0, FB_VMODE_NONINTERLACED	}, {		/* 640x400 @ 88 Hz, 43.1 kHz hsync */		NULL, 88, 640, 400, KHZ2PICOS(MAX_PIXCLOCK/1),		128, 96, 32, 48, 64, 8,		0, FB_VMODE_NONINTERLACED	}, {		/* 640x480 @ 84 Hz, 48.1 kHz hsync */		NULL, 84, 640, 480, KHZ2PICOS(MAX_PIXCLOCK/1),		96, 32, 32, 48, 64, 8,		0, FB_VMODE_NONINTERLACED	}, {		/* 768x576 @ 62 Hz, 38.5 kHz hsync */		NULL, 62, 768, 576, KHZ2PICOS(MAX_PIXCLOCK/1),		144, 16, 28, 6, 112, 4,		0, FB_VMODE_NONINTERLACED	}, {		/* 800x600 @ 60 Hz, 37.9 kHz hsync */		NULL, 60, 800, 600, KHZ2PICOS(MAX_PIXCLOCK/1),		88, 40, 23, 1, 128, 4,		FB_SYNC_HOR_HIGH_ACT|FB_SYNC_VERT_HIGH_ACT,		FB_VMODE_NONINTERLACED	}};static struct fb_videomode ntsc_modedb[] = {	{		/* 640x480 @ 62 Hz, requires flicker filter */		//NULL, 62, 640, 480, 34921, 213, 57, 20, 2, 0, 0,		NULL, 62, 640, 480, KHZ2PICOS(2*NTSC_PIXCLOCK),		200, 70, 15, 7, 0, 0,		FB_SYNC_BROADCAST, FB_VMODE_NONINTERLACED	}};static struct fb_videomode pal_modedb[] = {	{		/* 640x480 @ 56 Hz, requires flicker filter */		NULL, 56, 640, 480, KHZ2PICOS(2*PAL_PIXCLOCK),		350, 145, 49, 23, 0, 0,		FB_SYNC_BROADCAST, FB_VMODE_NONINTERLACED	}};static inline voidfb_videomode_to_var(struct fb_videomode* mode,		    struct fb_var_screeninfo*var){	var->xres = mode->xres;	var->yres = mode->yres;	var->pixclock = mode->pixclock;	var->left_margin = mode->left_margin;	var->right_margin = mode->right_margin;	var->upper_margin = mode->upper_margin;	var->lower_margin = mode->lower_margin;	var->hsync_len = mode->hsync_len;	var->vsync_len = mode->vsync_len;	var->sync = mode->sync;	var->vmode = mode->vmode;}static inte1356fb_get_mode(const struct fb_info_e1356 *info,		 int xres,		 int yres,		 struct fb_videomode ** modedb,		 struct fb_videomode ** mode){	struct fb_videomode * ret;	int i, dbsize;	if (IS_PANEL(info->fix.disp_type)) {		ret = panel_modedb;		dbsize = sizeof(panel_modedb)/sizeof(struct fb_videomode);	} else if (info->fix.disp_type == DISP_TYPE_CRT) {		ret = crt_modedb;		dbsize = sizeof(crt_modedb)/sizeof(struct fb_videomode);	} else if (info->fix.disp_type == DISP_TYPE_NTSC) {		ret = ntsc_modedb;		dbsize = sizeof(ntsc_modedb)/sizeof(struct fb_videomode);	} else {		ret = pal_modedb;		dbsize = sizeof(pal_modedb)/sizeof(struct fb_videomode);	}		if (modedb)		*modedb = ret;	for (i=0; i<dbsize; i++) {		if (xres == ret[i].xres && yres == ret[i].yres) {			*mode = &ret[i];			break;		}	}	if (i == dbsize)		return -EINVAL;	return dbsize;}#ifdef E1356FB_VERBOSE_DEBUGstatic voiddump_par(const struct e1356fb_par* par){	DPRINTK("width:       %d\n", par->width);	DPRINTK("height:      %d\n", par->height);	DPRINTK("width_virt:  %d\n", par->width_virt);	DPRINTK("height_virt: %d\n", par->height_virt);	DPRINTK("bpp:         %d\n", par->bpp);	DPRINTK("pixclock:    %d\n", par->ipclk.pixclk);	DPRINTK("horiz_ndp:   %d\n", par->horiz_ndp);	DPRINTK("vert_ndp:    %d\n", par->vert_ndp);	DPRINTK("hsync_pol:   %d\n", par->hsync_pol);	DPRINTK("hsync_start: %d\n", par->hsync_start);	DPRINTK("hsync_width: %d\n", par->hsync_width);	DPRINTK("vsync_pol:   %d\n", par->vsync_pol);	DPRINTK("vsync_start: %d\n", par->vsync_start);	DPRINTK("vsync_width: %d\n", par->vsync_width);	DPRINTK("cmap_len:    %d\n", par->cmap_len);}static voiddump_display_regs(reg_dispcfg_t* dispcfg, reg_dispmode_t* dispmode){	DPRINTK("hdw:            0x%02x\n", readb(&dispcfg->hdw));	DPRINTK("hndp:           0x%02x\n", readb(&dispcfg->hndp));	DPRINTK("hsync_start:    0x%02x\n", readb(&dispcfg->hsync_start));	DPRINTK("hsync_pulse:    0x%02x\n", readb(&dispcfg->hsync_pulse));	DPRINTK("vdh0:           0x%02x\n", readb(&dispcfg->vdh0));	DPRINTK("vdh1:           0x%02x\n", readb(&dispcfg->vdh1));	DPRINTK("vndp:           0x%02x\n", readb(&dispcfg->vndp));	DPRINTK("vsync_start:    0x%02x\n", readb(&dispcfg->vsync_start));	DPRINTK("vsync_pulse:    0x%02x\n", readb(&dispcfg->vsync_pulse));	DPRINTK("tv_output_ctrl: 0x%02x\n\n", readb(&dispcfg->tv_output_ctrl));	DPRINTK("disp_mode:        0x%02x\n", readb(&dispmode->disp_mode));	DPRINTK("lcd_misc:         0x%02x\n", readb(&dispmode->lcd_misc));	DPRINTK("start_addr0:      0x%02x\n", readb(&dispmode->start_addr0));	DPRINTK("start_addr1:      0x%02x\n", readb(&dispmode->start_addr1));	DPRINTK("start_addr2:      0x%02x\n", readb(&dispmode->start_addr2));	DPRINTK("mem_addr_offset0: 0x%02x\n", readb(&dispmode->mem_addr_offset0));	DPRINTK("mem_addr_offset1: 0x%02x\n", readb(&dispmode->mem_addr_offset1));	DPRINTK("pixel_panning:    0x%02x\n", readb(&dispmode->pixel_panning));	DPRINTK("fifo_high_thresh: 0x%02x\n", readb(&dispmode->fifo_high_thresh));	DPRINTK("fifo_low_thresh:  0x%02x\n", readb(&dispmode->fifo_low_thresh));}static voiddump_fb(u8* base, int len){	int i;	DPRINTK("FB memory dump, start 0x%p, len %d", base, len);	for (i=0; i<len; i++) {		if (!(i%16))			printk("\n%p: %02x ", &base[i], readb(&base[i]));		else			printk("%02x ", readb(&base[i]));	}	printk("\n");}#endif // E1356FB_VERBOSE_DEBUG// Input:  ipclk->clksrc, ipclk->pixclk_d// Output: ipclk->pixclk, ipclk->error, and ipclk->divisorstatic intget_nearest_pixclk_div(pixclock_info_t* ipclk, int x2){	int pixclk_d = ipclk->pixclk_d;	int clksrc = ipclk->clksrc;	if (x2) clksrc *= 2;	if (clksrc < (3*pixclk_d+1)/2)		ipclk->divisor = 1;	else if (clksrc < (5*pixclk_d+1)/2)		ipclk->divisor = 2;	else if (clksrc < (7*pixclk_d+1)/2)		ipclk->divisor = 3;	else if (clksrc < (9*pixclk_d+1)/2)		ipclk->divisor = 4;	else		return -ENXIO;	ipclk->pixclk = clksrc / ipclk->divisor;	ipclk->error = (100*(pixclk_d - ipclk->pixclk)) / pixclk_d;	return 0;}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -