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

📄 bf537_lq035fb.c

📁 Linux 2.6内核下
💻 C
字号:
/* * drivers/video/bf537_lq035fb.c * Analog Devices Blackfin(BF537 STAMP) + TFT LCD. * */#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/ioport.h>#include <linux/init.h>#include <linux/types.h>#include <linux/interrupt.h>#include <linux/sched.h>#include <linux/timer.h>#include <linux/device.h>#include <linux/dma-mapping.h>#include <linux/platform_device.h>#include <asm/blackfin.h>#include <asm/irq.h>#include <asm/dpmc.h>#include <asm/dma-mapping.h>#include <asm/dma.h>#include <asm/uaccess.h>#include <asm/semaphore.h>#include <asm/mach/cdefBF537.h>//fb#define START_LINES		8#define U_LINES 		(9)#define LCD_XRES		320			/**< \brief Width.*/#define LCD_YRES		240			/**< \brief Height.*/#define LCD_BPP 		16			/**< \brief Bits per pixel.*/#define BYTES_PER_ROW		((LCD_XRES / 8) * LCD_BPP)#define UPPER_MARGIN		19#define LOWER_MARGIN		4#define FB_BUFSIZE		((LCD_XRES * LCD_YRES / 8) * LCD_BPP)	/**< \brief Size of Framebuffer.*/#define FB_BUFSIZE_DMA		((LCD_XRES * (LCD_YRES+UPPER_MARGIN+LOWER_MARGIN) / 8) * LCD_BPP)#define Th 			408#define	Ths			30#define	Tv			(Th * 263)#define	Tvs			(Th * 4)#define	Tep			320/*	IHS-DEN time  	min	36 type 68 max 88*/#define The			68/*	IVS-DEN time	type 18 * Th*/#define Tve			(18 * Th)/*	when SYNC mode is used, 	1st data start from 68th CLK afer IHS failing.*/#define LATENCY_AFTER_Hv	68#define	_DEBUG#ifdef	_DEBUG #define DBG(args...)		printk(args)#else#define DBG(args...)		do{} while(0)#endifstatic volatile int open_count;static struct fb_info bfin_lq035_fb;/*	only one program can use framebuffer device.*/static struct semaphore sem_one;static u16*		fb_buffer;	/* RGB Buffer */static dma_addr_t 	dma_handle; 	/* ? */static u32 lq035_fb_pseudo_palette[16];static struct fb_var_screeninfo bfin_lq035_fb_defined = {	.xres		= LCD_XRES,	.yres		= LCD_YRES,	.xres_virtual	= LCD_XRES,	.yres_virtual	= LCD_YRES,	.bits_per_pixel	= LCD_BPP,		.activate	= FB_ACTIVATE_NOW,	.height		= -1,	.width		= -1,		.pixclock	= ((u32)1000000 / 3.58),	.left_margin	= LATENCY_AFTER_Hv,	.right_margin	= Th - LATENCY_AFTER_Hv - LCD_XRES,	.upper_margin	= UPPER_MARGIN * Th,	.lower_margin	= LOWER_MARGIN * Th,	.hsync_len	= Ths,	.vsync_len	= Tvs,		/*	Interpretation of offset for color fields: All offsets are from the right,	 *	inside a "pixel" value, which is exactly 'bits_per_pixel' wide (means: you	 *	can use the offset as right argument to <<). A pixel afterwards is a bit	 *	stream and is written to video memory as that unmodified. This implies	 *	big-endian byte order if bits_per_pixel is greater than 8.	 *	 *	struct fb_bitfield	 *	{	 *		__u32 offset;		beginning of bitfield	 *		__u32 length;		length of bitfield	 *		__u32 msb_right;	 != 0 : Most significant bit is	 *	}	 *	so RGB2PIXEL should be 	 *	if (TRUECOLOR)	 *	{	 *		pixel = (B>>(16-b.len))<<b.off | (G>>(16-g.len))<<g.off | (R>>(16-r.len))<<r.off;	 *	}	 */	.red		= {11, 5, 0},	.green		= {5, 6, 0},	.blue		= {0, 5, 0},	.transp		= {0, 0, 0},};static struct fb_fix_screeninfo bfin_lq035_fb_fix __initdata = {	.id 		= "BF537_lq035fb",	.smem_len 	= FB_BUFSIZE,	.type		= FB_TYPE_PACKED_PIXELS,	.visual		= FB_VISUAL_TRUECOLOR,	.xpanstep	= 0,	.ypanstep	= 0,	.line_length	= BYTES_PER_ROW,	.accel		= FB_ACCEL_NONE,};static void config_timers (void) /* CHECKME */{	/*		timer0		h_sync		timer1		v_sync		timer2		DN	*/		bfin_write_TIMER_DISABLE(TIMDIS0 | TIMDIS1 | TIMDIS2);	__builtin_bfin_ssync();		/*		TIMER0 is used for H-sync.	*/	bfin_write_TIMER0_CONFIG(PWM_OUT | PERIOD_CNT | CLK_SEL | TIN_SEL | EMU_RUN);	bfin_write_TIMER0_WIDTH(Ths);//Ths = 30	bfin_write_TIMER0_PERIOD(Th);//Th = 408	__builtin_bfin_ssync();			bfin_write_TIMER1_CONFIG(PWM_OUT | PERIOD_CNT | CLK_SEL | TIN_SEL | EMU_RUN);	bfin_write_TIMER1_WIDTH(Tvs);//3*Th=1224 4*Th=1632 MAX=5*Th=2040 	bfin_write_TIMER1_PERIOD(Tv);//262.5*Th 263*Th=107304	__builtin_bfin_ssync();		/*		the pin should fixed low,because this driver used SYNC mode.		so both WIDTH and PERIOD are useless.	*/	bfin_write_TIMER2_CONFIG(PWM_OUT | PERIOD_CNT | CLK_SEL | TIN_SEL | EMU_RUN | PULSE_HI);	bfin_write_TIMER2_WIDTH(Tep);//Tep=320	bfin_write_TIMER2_PERIOD(Th);//Th	__builtin_bfin_ssync();}static int config_dma (void){	assert(fb_buffer);	if (request_dma(CH_PPI, "BF537_PPI_DMA") < 0)		return -EFAULT;		set_dma_config(CH_PPI, set_bfin_dma_config(DIR_READ, 				   DMA_FLOW_AUTO, INTR_DISABLE, DIMENSION_2D, DATA_SIZE_16));		set_dma_x_count(CH_PPI, LCD_XRES);	set_dma_x_modify(CH_PPI, 2);		set_dma_y_count(CH_PPI, LCD_YRES + UPPER_MARGIN + LOWER_MARGIN);	set_dma_y_modify(CH_PPI, 2);	set_dma_start_addr(CH_PPI, ((unsigned long)fb_buffer));		return 0;}static void config_ppi (void){	bfin_write_PPI_CONTROL((POLS | DLEN_16 | 0x10 | XFR_TYPE | PORT_DIR) & (~PORT_EN));	/*		after PPI_FS1 is asserted, 		there is a latency of 1 PPI_CLK cylc,		and then there is a delay for the number of		PPI_CLK cycles programmed into PPI_DELAY.		No further DMA takes place until the next		PPI_FS1 sync.		so the latency should minus one.	*/	bfin_write_PPI_DELAY(LATENCY_AFTER_Hv - 1);	/*		this register holds the number of samples to write out 		through the PPI per line, minus one.	*/	bfin_write_PPI_COUNT(LCD_XRES - 1);}static void init_ports(void){		//*pEBIU_AMGCTL |= 0x0100;	bfin_write_EBIU_AMGCTL(bfin_read_EBIU_AMGCTL() | 0x0100);		//*pPORTG_FER |= 0xffff;	bfin_write_PORTG_FER(bfin_read_PORTG_FER() | 0xffff);	//*pPORTF_FER |= 0xffc0;	bfin_write_PORTF_FER(bfin_read_PORTF_FER() | 0xffc0); 	//*pPORTF_FER &= ~((1U<<0)|(1U<<1)|(1U<<2)|(1U<<3)|(1U<<4)|(1U<<5));	__builtin_bfin_ssync();}static int bfin_lq035_fb_mmap(struct fb_info *info, struct vm_area_struct * vma){	DBG("on mapping\n");		vma->vm_start = (unsigned long)(fb_buffer) + (LCD_XRES * UPPER_MARGIN * LCD_BPP / 8);	vma->vm_end = vma->vm_start + FB_BUFSIZE;		vma->vm_flags |=  VM_MAYSHARE;	return 0;}static int bfin_lq035_fb_check_var(struct fb_var_screeninfo *var, struct fb_info *info){	*var = info->var;	return 0;}static int hw_init(void){	init_ports();	config_dma();	config_ppi();	config_timers();	__builtin_bfin_ssync();		bfin_write_PPI_CONTROL(bfin_read_PPI_CONTROL() | PORT_EN);	__builtin_bfin_ssync();	enable_dma(CH_PPI);	bfin_write_TIMER_ENABLE(TIMEN0 | TIMEN1);	__builtin_bfin_ssync();		return 0;	}static int hw_deinit(void){	bfin_write_TIMER_DISABLE(TIMDIS0 | TIMDIS1);	__builtin_bfin_ssync();	bfin_write_PPI_CONTROL(bfin_read_PPI_CONTROL() & ~PORT_EN);	__builtin_bfin_ssync();	free_dma(CH_PPI);		return 0;}static int bfin_lq035_fb_setcolreg(u_int regno, u_int red, u_int green, u_int blue,								u_int transp, struct fb_info *info){	u32 pseudo_val;	DBG("setcolreg: %d: rgb=%d,%d,%d, tr=%d\n",	regno, red, green, blue, transp);	if (info->var.grayscale)		red = green = blue = (19595*red + 38470*green + 7471*blue) >> 16;	switch (info->fix.visual)	{		case FB_VISUAL_TRUECOLOR:			if (regno >= 16)				return -EINVAL;			/* deal with creating pseudo-palette entries */			pseudo_val  = (red   >> (16 - info->var.red.length)) << info->var.red.offset;			pseudo_val |= (green >> (16 - info->var.green.length)) << info->var.green.offset;			pseudo_val |= (blue  >> (16 - info->var.blue.length)) << info->var.blue.offset;			DBG("setcolreg: pseudo %d, val %08x\n",	regno, pseudo_val);			((u32 *)info->pseudo_palette)[regno] = pseudo_val;			break;		case FB_VISUAL_PSEUDOCOLOR:			break;		default:			return -ENOSYS;	}	return 0;	}static struct fb_ops bfin_lq035_fb_ops = {	.owner		= THIS_MODULE,	.fb_mmap	= bfin_lq035_fb_mmap,	.fb_setcolreg	= bfin_lq035_fb_setcolreg,	.fb_fillrect 	= cfb_fillrect,	.fb_copyarea 	= cfb_copyarea,	.fb_imageblit 	= cfb_imageblit,	.fb_check_var	= bfin_lq035_fb_check_var,};static int __init bfin_lq035_fb_init(void){	DBG("LCD FrameBuffer initializing...\n");	init_MUTEX(&sem_one);		////allocate memory, fb_buffer is a pointer to char	fb_buffer = dma_alloc_coherent(NULL, FB_BUFSIZE_DMA, &dma_handle, GFP_KERNEL);		if (NULL == fb_buffer)	{		printk(KERN_ERR "BF537 FB: couldn't allocate dma buffer.\n");		return -ENOMEM;	}		////initialise fb_buffer with 0xff	memset(fb_buffer, 0xff, FB_BUFSIZE_DMA);		////bfin_lq035_fb is a struct of fb_info	////initialise address of buffer		//bfin_lq035_fb.screen_base	= (void*)fb_buffer;	//bfin_lq035_fb_fix.smem_start    = (int)fb_buffer;	bfin_lq035_fb.screen_base = (void*)((u32)(fb_buffer) + (LCD_XRES * UPPER_MARGIN * LCD_BPP / 8));	bfin_lq035_fb_fix.smem_start = (u32)(fb_buffer) + (LCD_XRES * UPPER_MARGIN * LCD_BPP / 8);				bfin_lq035_fb.fbops		= &bfin_lq035_fb_ops;	bfin_lq035_fb.var		= bfin_lq035_fb_defined;	bfin_lq035_fb.fix		= bfin_lq035_fb_fix;	bfin_lq035_fb.flags		= FBINFO_DEFAULT;	//bfin_lq035_fb.pseudo_palette = &lq035_fb_pseudo_palette;	bfin_lq035_fb.pseudo_palette = lq035_fb_pseudo_palette;		hw_init();		if (register_framebuffer(&bfin_lq035_fb) < 0)	{		printk(KERN_ERR "BF537 FB: unable to register framebuffer.\n");				dma_free_coherent(NULL, FB_BUFSIZE_DMA, fb_buffer, dma_handle);		fb_buffer = NULL;		return -EINVAL;	}	return 0;}static void __exit bfin_lq035_fb_exit(void){	hw_deinit();	if (NULL != fb_buffer)		dma_free_coherent(NULL, FB_BUFSIZE_DMA, fb_buffer, dma_handle);	unregister_framebuffer(&bfin_lq035_fb);		DBG("Unregister LCD driver.\n");}#ifdef MODULEMODULE_LICENSE("GPL");#endifmodule_init(bfin_lq035_fb_init);module_exit(bfin_lq035_fb_exit);

⌨️ 快捷键说明

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