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

📄 jzlcd.c

📁 jzlcd linux参考代码
💻 C
📖 第 1 页 / 共 3 页
字号:
/* * linux/drivers/video/jzlcd.c -- Ingenic On-Chip LCD frame buffer device * * Copyright (C) 2005-2007, Ingenic Semiconductor Inc. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as * published by the Free Software Foundation. * */#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/dma-mapping.h>#include <linux/platform_device.h>#include <linux/pm.h>#include <linux/pm_legacy.h>#include <linux/kthread.h>#include <asm/irq.h>#include <asm/pgtable.h>#include <asm/system.h>#include <asm/uaccess.h>#include <asm/processor.h>#include <asm/jzsoc.h>#include "console/fbcon.h"#include "jzlcd.h"#undef DEBUG//#define DEBUG#ifdef DEBUG#define dprintk(x...)	printk(x)#else#define dprintk(x...)#endif#define print_err(f, arg...) printk(KERN_ERR DRIVER_NAME ": " f "\n", ## arg)#define print_warn(f, arg...) printk(KERN_WARNING DRIVER_NAME ": " f "\n", ## arg)#define print_info(f, arg...) printk(KERN_INFO DRIVER_NAME ": " f "\n", ## arg)#ifdef DEBUG#define print_dbg(f, arg...) printk("dbg::" __FILE__ ",LINE(%d): " f "\n", __LINE__, ## arg)#else#define print_dbg(f, arg...) do {} while (0)#endifstruct lcd_cfb_info {	struct fb_info		fb;	struct display_switch	*dispsw;	signed int		currcon;	int			func_use_count;	struct {		u16 red, green, blue;	} palette[NR_PALETTE];#ifdef CONFIG_PM	struct pm_dev		*pm;#endif#if defined(CONFIG_JZLCD_FRAMEBUFFER_ROTATE_SUPPORT)	struct task_struct *rotate_daemon_thread;#endif};static struct lcd_cfb_info *jzlcd_info;struct jzfb_info {	unsigned int cfg;	/* panel mode and pin usage etc. */	unsigned int w;	unsigned int h;	unsigned int bpp;	/* bit per pixel */	unsigned int fclk;	/* frame clk */	unsigned int hsw;	/* hsync width, in pclk */	unsigned int vsw;	/* vsync width, in line count */	unsigned int elw;	/* end of line, in pclk */	unsigned int blw;	/* begin of line, in pclk */	unsigned int efw;	/* end of frame, in line count */	unsigned int bfw;	/* begin of frame, in line count */};static struct jzfb_info jzfb = {#if defined(CONFIG_JZLCD_SHARP_LQ035Q7)	MODE_TFT_SHARP | PCLK_N | VSYNC_N,	240, 320, 16, 60, 1, 2, 1, 2, 0, 6#endif#if defined(CONFIG_JZLCD_SAMSUNG_LTS350Q1)	MODE_TFT_SAMSUNG | PCLK_N,	240, 320, 16, 60, 1, 2, (254-240), 0, 7, 0#endif#if defined(CONFIG_JZLCD_SAMSUNG_LTV350QVF04)	MODE_TFT_GEN | HSYNC_N | VSYNC_N,	320, 240, 16, 70, 19, 4, 20, 14, 18, 6#endif#if defined(CONFIG_JZLCD_SAMSUNG_LTP400WQF01)	MODE_TFT_GEN | HSYNC_N | VSYNC_N,	480, 272, 16, 60, 41, 10, 2, 2, 2, 2#endif#if defined(CONFIG_JZLCD_SAMSUNG_LTP400WQF02)	/* MODE_TFT_18BIT: JZ4740@ version */	MODE_TFT_GEN | MODE_TFT_18BIT | HSYNC_N | VSYNC_N,	480, 272, 32, 60, 41, 10, 2, 2, 2, 2#endif#if defined(CONFIG_JZLCD_TRULY_TFTG320240DTSW)	MODE_TFT_GEN | HSYNC_N | VSYNC_N | PCLK_N,	320, 240, 16, 85, 30, 3, 38, 20, 11, 8#endif#if defined(CONFIG_JZLCD_TRULY_TFTG320240DTSW_SERIAL)	MODE_8BIT_SERIAL_TFT | HSYNC_N | VSYNC_N | PCLK_N,	/* serial mode 280 lines, parallel mode 240 lines */	320, 280, 32, 60, (30*3), 3, (20*3), (38*3), 46, 23 #endif#if defined(CONFIG_JZLCD_AUO_A030FL01_V1)	MODE_TFT_GEN | MODE_TFT_18BIT | HSYNC_N | VSYNC_N,	480, 272, 32, 60, 39, 10, 8, 4, 4, 2#endif#if defined(CONFIG_JZLCD_TRULY_TFTG240320UTSW_63W_E)	MODE_TFT_GEN | HSYNC_N | VSYNC_N | PCLK_N | DE_N,	320, 240, 16, 60, 3, 3, 3, 3, 3, 85 /* 320x240 */#endif#if defined(CONFIG_JZLCD_FOXCONN_PT035TN01) && defined(CONFIG_JZ4740_PAVO)	MODE_TFT_GEN | HSYNC_N | VSYNC_N | MODE_TFT_18BIT | PCLK_N,//	320, 240, 18, 110, 1, 1, 10, 50, 10, 13	320, 240, 18, 80, 1, 1, 10, 50, 10, 13#endif#if defined(CONFIG_JZLCD_FOXCONN_PT035TN01) && !(defined(CONFIG_JZ4740_PAVO))	MODE_TFT_GEN | HSYNC_N | VSYNC_N  | PCLK_N,	320, 240, 16, 110, 1, 1, 10, 50, 10, 13#endif#if defined(CONFIG_JZLCD_INNOLUX_PT035TN01_SERIAL)	MODE_8BIT_SERIAL_TFT | PCLK_N | HSYNC_N | VSYNC_N,	320, 240, 32, 60, 1, 1, 10, 50, 10, 13#endif#if defined(CONFIG_JZLCD_HYNIX_HT10X21)	MODE_TFT_GEN | PCLK_N,	1024, 768, 16, 45, 1, 1, 75, 0, 3, 0#endif#if defined(CONFIG_JZLCD_TOSHIBA_LTM084P363)	MODE_TFT_GEN | PCLK_N,	800, 600, 16, 50, 1, 2, 199, 0, 2, 0#endif#if defined(CONFIG_JZLCD_INNOLUX_AT080TN42)	MODE_TFT_SHARP | PCLK_N,	800, 600, 16, 40, 1, 1, 255, 0, 34, 0 #endif#if defined(CONFIG_JZLCD_CSTN_800x600)	MODE_STN_COLOR_DUAL | STN_DAT_PIN8,	800, 600, 16, 30, 8, 1, 0, 0, 0, 0#endif#if defined(CONFIG_JZLCD_CSTN_320x240)	MODE_STN_COLOR_SINGLE | STN_DAT_PIN8,	320, 240, 16, 120, 8, 1, 8, 0, 0, 0#endif#if defined(CONFIG_JZLCD_MSTN_640x480)	MODE_STN_MONO_DUAL | STN_DAT_PIN4,	640, 480, 8, 110, 4, 1, 4, 0, 0, 0#endif#if defined(CONFIG_JZLCD_MSTN_320x240)	MODE_STN_MONO_SINGLE | STN_DAT_PIN4,	320, 240, 8, 110, 4, 1, 4, 0, 0, 0#endif#if defined(CONFIG_JZLCD_MSTN_480x320)	MODE_STN_MONO_SINGLE | STN_DAT_PIN8#if defined(CONFIG_JZLCD_MSTN_INVERSE)	| DATA_INVERSE#endif	, 480, 320, 8, 65, 8, 1, 8, 0, 0, 0#endif#if defined(CONFIG_JZLCD_MSTN_240x128)	MODE_STN_MONO_SINGLE | STN_DAT_PIN1#if defined(CONFIG_JZLCD_MSTN_INVERSE)	| DATA_INVERSE#endif	, 240, 128, 8, 100, 1, 1, 1, 0, 0, 0 #endif};static struct lcd_desc *lcd_desc_base;static struct lcd_desc *lcd_palette_desc;static struct lcd_desc *lcd_frame_desc0;static struct lcd_desc *lcd_frame_desc1;static unsigned char *lcd_palette;static unsigned char *lcd_frame[CONFIG_JZLCD_FRAMEBUFFER_MAX];struct jz_lcd_buffer_addrs_t jz_lcd_buffer_addrs;//extern struct display fb_display[MAX_NR_CONSOLES];#if defined(CONFIG_JZLCD_FRAMEBUFFER_ROTATE_SUPPORT)static unsigned char *lcd_frame_user_fb;/* default rotate angle */static volatile int rotate_angle = CONFIG_JZLCD_FRAMEBUFFER_DEFAULT_ROTATE_ANGLE;#endif#ifdef  DEBUGstatic void print_regs(void)	/* debug */{	printk("REG_LCD_CFG:\t0x%8.8x\n", REG_LCD_CFG);	printk("REG_LCD_VSYNC:\t0x%8.8x\n", REG_LCD_VSYNC);	printk("REG_LCD_HSYNC:\t0x%8.8x\n", REG_LCD_HSYNC);	printk("REG_LCD_VAT:\t0x%8.8x\n", REG_LCD_VAT);	printk("REG_LCD_DAH:\t0x%8.8x\n", REG_LCD_DAH);	printk("REG_LCD_DAV:\t0x%8.8x\n", REG_LCD_DAV);	printk("REG_LCD_PS:\t0x%8.8x\n", REG_LCD_PS);	printk("REG_LCD_CLS:\t0x%8.8x\n", REG_LCD_CLS);	printk("REG_LCD_SPL:\t0x%8.8x\n", REG_LCD_SPL);	printk("REG_LCD_REV:\t0x%8.8x\n", REG_LCD_REV);	printk("REG_LCD_CTRL:\t0x%8.8x\n", REG_LCD_CTRL);	printk("REG_LCD_STATE:\t0x%8.8x\n", REG_LCD_STATE);	printk("REG_LCD_IID:\t0x%8.8x\n", REG_LCD_IID);	printk("REG_LCD_DA0:\t0x%8.8x\n", REG_LCD_DA0);	printk("REG_LCD_SA0:\t0x%8.8x\n", REG_LCD_SA0);	printk("REG_LCD_FID0:\t0x%8.8x\n", REG_LCD_FID0);	printk("REG_LCD_CMD0:\t0x%8.8x\n", REG_LCD_CMD0);	printk("==================================\n");	printk("REG_LCD_VSYNC:\t%d:%d\n", REG_LCD_VSYNC>>16, REG_LCD_VSYNC&0xfff);	printk("REG_LCD_HSYNC:\t%d:%d\n", REG_LCD_HSYNC>>16, REG_LCD_HSYNC&0xfff);	printk("REG_LCD_VAT:\t%d:%d\n", REG_LCD_VAT>>16, REG_LCD_VAT&0xfff);	printk("REG_LCD_DAH:\t%d:%d\n", REG_LCD_DAH>>16, REG_LCD_DAH&0xfff);	printk("REG_LCD_DAV:\t%d:%d\n", REG_LCD_DAV>>16, REG_LCD_DAV&0xfff);	printk("==================================\n");}#else#define print_regs()#endif#if defined(CONFIG_JZLCD_FRAMEBUFFER_ROTATE_SUPPORT)static int jzfb_rotate_daemon_thread(void *info){	int i,j;	struct fb_info *fb = &jzlcd_info->fb;	while (!kthread_should_stop()) {#if (CONFIG_JZLCD_FRAMEBUFFER_BPP == 8)		unsigned char *plcd_frame = (unsigned char *)lcd_frame[0];		unsigned char *pfb = (unsigned char *) (fb->screen_base);#elif (CONFIG_JZLCD_FRAMEBUFFER_BPP == 16)		unsigned short *plcd_frame = (unsigned short *)lcd_frame[0];		unsigned short *pfb = (unsigned short *) (fb->screen_base);#elif (CONFIG_JZLCD_FRAMEBUFFER_BPP == 32)		unsigned int *plcd_frame = (unsigned int *)lcd_frame[0];		unsigned int *pfb = (unsigned int *) (fb->screen_base);#else#error	"ERROR, rotate not support this bpp."#endif		switch ( rotate_angle ) {		case FB_ROTATE_UR:			printk("%s, Warning, this shouldn't reache\n", __FUNCTION__);			ssleep(1);			break;		case FB_ROTATE_UD: /* cost about 30ms, can be accelrated by dma in the future */			plcd_frame += jzfb.w*jzfb.h -1;			for (i=0;i<jzfb.h*jzfb.w;i++)				*plcd_frame-- = *pfb++;			msleep(75);			break;		case FB_ROTATE_CW:  /* cost about 80ms */			for (i=1;i<fb->var.height+1; i++) {				for (j=1; j < fb->var.width+1; j++)					plcd_frame[j*fb->var.height-i] = *pfb++;			}			msleep(100); /* sleep 100ms */			break;		case FB_ROTATE_CCW:  /* cost about 80ms */			for (i=0;i<fb->var.height;i++) {				for ( j=fb->var.width-1;j>=0;j--)					plcd_frame[j*fb->var.height+i] = *pfb++;			}			msleep(100); /* sleep 100ms */			break;		default:	/* FB_ROTATE_UR */			dprintk("Unknown rotate(%d) type\n", rotate_angle);			ssleep(1);		}		dma_cache_wback_inv((unsigned int)(lcd_frame_user_fb), fb->fix.smem_len);	}	return 0;}/*  * rotate param angle: * 	0: FB_ROTATE_UR, 0'C * 	1: FB_ROTATE_CW, 90'C * 	2: FB_ROTATE_UD, 180'C * 	3: FB_ROTATE_CCW, 270'C */static int jzfb_rotate_change( int angle ){	struct fb_info *fb = &jzlcd_info->fb;	/* clear frame buffer */	memset((void*)lcd_frame_user_fb, 0x00, fb->fix.smem_len);	switch ( angle ) {	case FB_ROTATE_UR:		fb->var.width	= fb->var.xres = fb->var.xres_virtual = jzfb.w;		fb->var.height	= fb->var.yres = fb->var.yres_virtual = jzfb.h;		/* change lcd controller's data buffer to lcd_frame_user_fb*/		lcd_frame_desc0->databuf = virt_to_phys((void *)lcd_frame_user_fb);		if ( rotate_angle != FB_ROTATE_UR )			kthread_stop(jzlcd_info->rotate_daemon_thread);		rotate_angle = angle;		break;	case FB_ROTATE_UD:	case FB_ROTATE_CW:	case FB_ROTATE_CCW:		if ( angle == FB_ROTATE_UD ) {			fb->var.width	= fb->var.xres = fb->var.xres_virtual = jzfb.w;			fb->var.height	= fb->var.yres = fb->var.yres_virtual = jzfb.h;		}		else {	/* CW, CCW */			fb->var.width	= fb->var.xres = fb->var.xres_virtual = jzfb.h;			fb->var.height	= fb->var.yres = fb->var.yres_virtual = jzfb.w;		}		/* change lcd controller's data buffer to lcd_frame[0]*/		lcd_frame_desc0->databuf = virt_to_phys((void *)lcd_frame[0]);		if ( rotate_angle == FB_ROTATE_UR ||		\		     jzlcd_info->rotate_daemon_thread == NULL) 				jzlcd_info->rotate_daemon_thread = kthread_run( jzfb_rotate_daemon_thread, jzlcd_info, "%s", "jzlcd-rotate-daemon"); /* start rotate daemon */		rotate_angle = angle;		break;	default:		printk("Invalid angle(%d)\n", (unsigned int)angle);	}	fb->fix.line_length = fb->var.xres * CONFIG_JZLCD_FRAMEBUFFER_BPP/8;	dma_cache_wback_inv((unsigned int)(lcd_frame_desc0), sizeof(struct lcd_desc));		return 0;}void jzfb_fb_rotate(struct fb_info *fbi, int angle){	jzfb_rotate_change( angle/90 );}#endif	/* #if defined(CONFIG_JZLCD_FRAMEBUFFER_ROTATE_SUPPORT) */static inline u_int chan_to_field(u_int chan, struct fb_bitfield *bf){        chan &= 0xffff;        chan >>= 16 - bf->length;        return chan << bf->offset;}static int jzfb_setcolreg(u_int regno, u_int red, u_int green, u_int blue,			  u_int transp, struct fb_info *info){	struct lcd_cfb_info *cfb = (struct lcd_cfb_info *)info;	unsigned short *ptr, ctmp;//	print_dbg("regno:%d,RGBt:(%d,%d,%d,%d)\t", regno, red, green, blue, transp);	if (regno >= NR_PALETTE)		return 1;	cfb->palette[regno].red		= red ;	cfb->palette[regno].green	= green;	cfb->palette[regno].blue	= blue;	if (cfb->fb.var.bits_per_pixel <= 16) {		red	>>= 8;		green	>>= 8;		blue	>>= 8;		red	&= 0xff;		green	&= 0xff;		blue	&= 0xff;	}	switch (cfb->fb.var.bits_per_pixel) {	case 1:	case 2:	case 4:	case 8:		if (((jzfb.cfg & MODE_MASK) == MODE_STN_MONO_SINGLE) ||		    ((jzfb.cfg & MODE_MASK) == MODE_STN_MONO_DUAL)) {			ctmp = (77L * red + 150L * green + 29L * blue) >> 8;			ctmp = ((ctmp >> 3) << 11) | ((ctmp >> 2) << 5) |				(ctmp >> 3);		} else {			/* RGB 565 */			if (((red >> 3) == 0) && ((red >> 2) != 0))				red = 1 << 3;			if (((blue >> 3) == 0) && ((blue >> 2) != 0))				blue = 1 << 3;			ctmp = ((red >> 3) << 11) 				| ((green >> 2) << 5) | (blue >> 3);		}		ptr = (unsigned short *)lcd_palette;		ptr = (unsigned short *)(((u32)ptr)|0xa0000000);		ptr[regno] = ctmp;		break;			case 15:		if (regno < 16)			((u32 *)cfb->fb.pseudo_palette)[regno] =				((red >> 3) << 10) | 				((green >> 3) << 5) |				(blue >> 3);		break;	case 16:		if (regno < 16) {			((u32 *)cfb->fb.pseudo_palette)[regno] =				((red >> 3) << 11) | 				((green >> 2) << 5) |				(blue >> 3); 		}		break;	case 18:	case 24:	case 32:		if (regno < 16)			((u32 *)cfb->fb.pseudo_palette)[regno] =				(red << 16) | 				(green << 8) |				(blue << 0); /*		if (regno < 16) {			unsigned val;                        val  = chan_to_field(red, &cfb->fb.var.red);                        val |= chan_to_field(green, &cfb->fb.var.green);                        val |= chan_to_field(blue, &cfb->fb.var.blue);			((u32 *)cfb->fb.pseudo_palette)[regno] = val;		}*/		break;	}	return 0;}static int jzfb_ioctl (struct fb_info *fb, unsigned int cmd, unsigned long arg ){	int ret = 0;	void __user *argp = (void __user *)arg;	switch (cmd) {	case FBIOSETBACKLIGHT:		__lcd_set_backlight_level(arg);	/* We support 8 levels here. */		break;	case FBIODISPON:		__lcd_display_on();		break;	case FBIODISPOFF:		__lcd_display_off();		break;	case FBIOPRINT_REGS:		print_regs();		break;	case FBIOGETBUFADDRS:		if ( copy_to_user(argp, &jz_lcd_buffer_addrs,				  sizeof(struct jz_lcd_buffer_addrs_t)) )			return -EFAULT;		break;#if defined(CONFIG_JZLCD_FRAMEBUFFER_ROTATE_SUPPORT)	case FBIOROTATE:		ret = jzfb_rotate_change(arg);		break;#endif	/* defined(CONFIG_JZLCD_FRAMEBUFFER_ROTATE_SUPPORT) */	default:		printk("Warn: Command(%x) not support\n", cmd);		ret = -1;		break;	}	return ret;}/* Use mmap /dev/fb can only get a non-cacheable Virtual Address. */static int jzfb_mmap(struct fb_info *info, struct vm_area_struct *vma){	struct lcd_cfb_info *cfb = (struct lcd_cfb_info *)info;	unsigned long start;	unsigned long off;	u32 len;	off = vma->vm_pgoff << PAGE_SHIFT;	//fb->fb_get_fix(&fix, PROC_CONSOLE(info), info);	/* frame buffer memory */	start = cfb->fb.fix.smem_start;	len = PAGE_ALIGN((start & ~PAGE_MASK) + cfb->fb.fix.smem_len);	start &= PAGE_MASK;	if ((vma->vm_end - vma->vm_start + off) > len)		return -EINVAL;	off += start;	vma->vm_pgoff = off >> PAGE_SHIFT;	vma->vm_flags |= VM_IO;	vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot);	/* Uncacheable */#if 1 	pgprot_val(vma->vm_page_prot) &= ~_CACHE_MASK; 	pgprot_val(vma->vm_page_prot) |= _CACHE_UNCACHED;		/* Uncacheable *///	pgprot_val(vma->vm_page_prot) |= _CACHE_CACHABLE_NONCOHERENT;	/* Write-Through */#endif	if (io_remap_pfn_range(vma, vma->vm_start, off >> PAGE_SHIFT,			       vma->vm_end - vma->vm_start,			       vma->vm_page_prot)) {		return -EAGAIN;	}	return 0;}/* checks var and eventually tweaks it to something supported, * DO NOT MODIFY PAR */static int jzfb_check_var(struct fb_var_screeninfo *var, struct fb_info *info){	print_dbg("jzfb_check_var");	return 0;}/*  * set the video mode according to info->var */

⌨️ 快捷键说明

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