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

📄 davincifb.c

📁 基于ti公司davinci系统linux下vpbe驱动程序
💻 C
📖 第 1 页 / 共 4 页
字号:
/* * drivers/video/davincifb.c * * Framebuffer driver for Texas Instruments DaVinci display controller. * * Copyright (C) 2006 Texas Instruments, Inc. * Rishi Bhattacharya <support@ti.com> * * Leveraged from the framebuffer driver for OMAP24xx * written by Andy Lowe (source@mvista.com) * Copyright (C) 2004 MontaVista Software, Inc. * * This file is licensed under the terms of the GNU General Public License * version 2. This program is licensed "as is" without any warranty of any * kind, whether express or implied. */#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/interrupt.h>#include <asm/irq.h>#include <asm/uaccess.h>#include <video/davincifb.h>#include <asm/system.h>#define DAVINCIFB_DEVICE "davincifb"#define DAVINCIFB_DRIVER "davincifb"/* Output Format Selection  */#ifdef 	DEBUG#define	DBGENTER printk(DAVINCIFB_DEVICE ": Entered %s\n", __FUNCTION__)#define	DBGEXIT	 printk(DAVINCIFB_DEVICE ": Exited %s\n", __FUNCTION__)#define	RETURN(x)						\do {								\	int __ret = (x);					\	printk("Exited %s : ret %d\n", __FUNCTION__, __ret);	\	return __ret; 						\} while(0)#else#define	DBGENTER#define	DBGEXIT#define	RETURN(x)	return (x)#endif#define MULTIPLE_BUFFERING	1#ifdef MULTIPLE_BUFFERING#define DOUBLE_BUF	2#define TRIPLE_BUF	3#else#define DOUBLE_BUF	1#define TRIPLE_BUF	1#endif/* * display controller register I/O routines */static __inline__ u32 dispc_reg_in(u32 offset){	return (inl(offset));}static __inline__ u32 dispc_reg_out(u32 offset, u32 val){	outl(val, offset);	return (val);}static __inline__ u32 dispc_reg_merge(u32 offset, u32 val, u32 mask){	u32 addr = offset;	u32 new_val = (inl(addr) & ~mask) | (val & mask);	outl(new_val, addr);	return (new_val);}/* There are 4 framebuffers, each represented by an fb_info and * a dm_win_info structure */#define OSD0_FBNAME	"dm_osd0_fb"#define OSD1_FBNAME	"dm_osd1_fb"#define VID0_FBNAME	"dm_vid0_fb"#define VID1_FBNAME	"dm_vid1_fb"/* usage:	if (is_win(info->fix.id, OSD0)) ... */#define is_win(name, x) ((strcmp(name, x ## _FBNAME) == 0) ? 1 : 0)struct dm_win_info {	struct fb_info info;	/* X and Y position */	unsigned int x, y;	/* framebuffer area */	dma_addr_t fb_base_phys;	unsigned long fb_base;	unsigned long fb_size;	u32 pseudo_palette[17];	/* flag to identify if framebuffer area is fixed already or not */	int alloc_fb_mem;	unsigned long sdram_address;	struct dm_info *dm;};static struct dm_info {	struct dm_win_info *osd0;	struct dm_win_info *osd1;	struct dm_win_info *vid0;	struct dm_win_info *vid1;	/* to map the registers */	dma_addr_t mmio_base_phys;	unsigned long mmio_base;	unsigned long mmio_size;	wait_queue_head_t vsync_wait;	unsigned long vsync_cnt;	int timeout;	/* this is the function that configures the output device (NTSC/PAL/LCD)	 * for the required output format (composite/s-video/component/rgb)	 */	void (*output_device_config) (int on);	struct device *dev;} dm_static;static struct dm_info *dm = &dm_static;static struct fb_ops davincifb_ops;#define BASEX		0x80#define BASEY		0x12#define DISP_XRES	720#define DISP_YRES	480#define DISP_MEMY	576/* Random value chosen for now. Should be within the panel's supported range */#define LCD_PANEL_CLOCK	180000/* All window widths have to be rounded up to a multiple of 32 bytes *//* The OSD0 window has to be always within VID0. Plus, since it is in RGB565 * mode, it _cannot_ overlap with VID1. * For defaults, we are setting the OSD0 window to be displayed in the top * left quadrant of the screen, and the VID1 in the bottom right quadrant. * So the default 'xres' and 'yres' are set to  half of the screen width and * height respectively. Note however that the framebuffer size is allocated * for the full screen size so the user can change the 'xres' and 'yres' by * using the FBIOPUT_VSCREENINFO ioctl within the limits of the screen size. */#define round_32(width)	((((width) + 31) / 32) * 32 )#define OSD0_XRES	round_32((DISP_XRES)*16/8) * 8/16	/* pixels */#define OSD0_YRES	DISP_YRES#define OSD0_FB_PHY	0#define OSD0_FB_SIZE	(round_32((DISP_XRES)*16/8) * DISP_MEMY * DOUBLE_BUF)			/* 16 bpp, Double buffered */static struct fb_var_screeninfo osd0_default_var = {	.xres = OSD0_XRES,	.yres = OSD0_YRES,	.xres_virtual = OSD0_XRES,	.yres_virtual = OSD0_YRES * DOUBLE_BUF,	.xoffset = 0,	.yoffset = 0,	.bits_per_pixel = 16,	.grayscale = 0,	.red = {11, 5, 0},	.green = {5, 6, 0},	.blue = {0, 5, 0},	.transp = {0, 0, 0},	.nonstd = 0,	.activate = FB_ACTIVATE_NOW,	.height = -1,	.width = -1,	.accel_flags = 0,	.pixclock = LCD_PANEL_CLOCK,	/* picoseconds */	.left_margin = 40,	/* pixclocks */	.right_margin = 4,	/* pixclocks */	.upper_margin = 8,	/* line clocks */	.lower_margin = 2,	/* line clocks */	.hsync_len = 4,		/* pixclocks */	.vsync_len = 2,		/* line clocks */	.sync = 0,	.vmode = FB_VMODE_INTERLACED,};/* Using the full screen for OSD1 by default */#define OSD1_XRES	round_32(DISP_XRES*4/8) * 8/4	/* pixels */#define OSD1_YRES	DISP_YRES#define OSD1_FB_PHY	0#define OSD1_FB_SIZE	(round_32(DISP_XRES*4/8) * DISP_MEMY * DOUBLE_BUF)static struct fb_var_screeninfo osd1_default_var = {	.xres = DISP_XRES,	.yres = OSD1_YRES,	.xres_virtual = OSD1_XRES,	.yres_virtual = OSD1_YRES * DOUBLE_BUF,	.xoffset = 0,	.yoffset = 0,	.bits_per_pixel = 4,	.activate = FB_ACTIVATE_NOW,	.accel_flags = 0,	.pixclock = LCD_PANEL_CLOCK,	/* picoseconds */	.vmode = FB_VMODE_INTERLACED,};/* Using the full screen for OSD0 by default */#define VID0_XRES	round_32(DISP_XRES*16/8) * 8/16	/* pixels */#define VID0_YRES	DISP_YRES#define VID0_FB_PHY	0#define VID0_FB_SIZE	(round_32(DISP_XRES*16/8) * DISP_MEMY * TRIPLE_BUF)static struct fb_var_screeninfo vid0_default_var = {	.xres = VID0_XRES,	.yres = VID0_YRES,	.xres_virtual = VID0_XRES,	.yres_virtual = VID0_YRES * TRIPLE_BUF,	.xoffset = 0,	.yoffset = 0,	.bits_per_pixel = 16,	.activate = FB_ACTIVATE_NOW,	.accel_flags = 0,	.pixclock = LCD_PANEL_CLOCK,	/* picoseconds */	.vmode = FB_VMODE_INTERLACED,};/* Using the bottom right quadrant of the screen screen for VID1 by default, * but keeping the framebuffer allocated for the full screen, so the user can * change the 'xres' and 'yres' later using the FBIOPUT_VSCREENINFO ioctl. */#define VID1_BPP	16	/* Video1 can be in YUV or RGB888 format */#define VID1_XRES round_32(DISP_XRES*16/8) * 8/16	/* pixels */#define VID1_YRES DISP_YRES#define VID1_FB_PHY	0#define VID1_FB_SIZE (round_32(DISP_XRES*16/8) * DISP_MEMY * TRIPLE_BUF)static struct fb_var_screeninfo vid1_default_var = {	.xres = VID1_XRES,	.yres = VID1_YRES,	.xres_virtual = VID1_XRES,	.yres_virtual = VID1_YRES * TRIPLE_BUF,	.xoffset = 0,	.yoffset = 0,	.bits_per_pixel = VID1_BPP,	.activate = FB_ACTIVATE_NOW,	.accel_flags = 0,	.pixclock = LCD_PANEL_CLOCK,	/* picoseconds */	.vmode = FB_VMODE_INTERLACED,};#define	x_pos(w)	((w)->x)#define	y_pos(w)	((w)->y)static struct dmparams_t {	u8 output;	u8 format;	u8 windows;		/* bitmap flag based on VID0, VID1, OSD0, OSD1				 * definitions in header file */	u32 vid0_xres;	u32 vid0_yres;	u32 vid0_xpos;	u32 vid0_ypos;	u32 vid1_xres;	u32 vid1_yres;	u32 vid1_xpos;	u32 vid1_ypos;	u32 osd0_xres;	u32 osd0_yres;	u32 osd0_xpos;	u32 osd0_ypos;	u32 osd1_xres;	u32 osd1_yres;	u32 osd1_xpos;	u32 osd1_ypos;} dmparams = {	NTSC,		/* output */	    COMPOSITE,		/* format */	    (1 << VID0) | (1 << VID1) | (1 << OSD0) | (1 << OSD1),	    /* windows registered */	    720, 480, 0, 0,	/* vid0 size and position */	    720, 480, 0, 0,	/* vid1 size and position */	    720, 480, 0, 0,	/* osd0 size and position */	    720, 480, 0, 0,	/* osd1 size and position */};/* Must do checks against the limits of the output device */static int davincifb_venc_check_mode(const struct dm_win_info *w,				     const struct fb_var_screeninfo *var){	DBGENTER;	RETURN(0);}static void set_sdram_params(char *id, u32 addr, u32 line_length);static irqreturn_t davincifb_isr(int irq, void *arg, struct pt_regs *regs){	struct dm_info *dm = (struct dm_info *)arg;	unsigned long addr=0;	if ((dispc_reg_in(VENC_VSTAT) & 0x00000010) == 0x10) {		xchg(&addr, dm->osd0->sdram_address);		if (addr) {			set_sdram_params(dm->osd0->info.fix.id,					 dm->osd0->sdram_address,					 dm->osd0->info.fix.line_length);			dm->osd0->sdram_address = 0;		}		addr = 0;		xchg(&addr, dm->osd1->sdram_address);		if (addr) {			set_sdram_params(dm->osd1->info.fix.id,					 dm->osd1->sdram_address,					 dm->osd1->info.fix.line_length);			dm->osd1->sdram_address = 0;		}		addr = 0;		xchg(&addr, dm->vid0->sdram_address);		if (addr) {			set_sdram_params(dm->vid0->info.fix.id,					 dm->vid0->sdram_address,					 dm->vid0->info.fix.line_length);			dm->vid0->sdram_address = 0;		}		addr = 0;		xchg(&addr, dm->vid1->sdram_address);		if (addr) {			set_sdram_params(dm->vid1->info.fix.id,					 dm->vid1->sdram_address,					 dm->vid1->info.fix.line_length);			dm->vid1->sdram_address = 0;		}		return IRQ_HANDLED;	} else {		++dm->vsync_cnt;		wake_up_interruptible(&dm->vsync_wait);		return IRQ_HANDLED;	}	return IRQ_HANDLED;}/* Wait for a vsync interrupt.  This routine sleeps so it can only be called * from process context. */static int davincifb_wait_for_vsync(struct dm_win_info *w){	struct dm_info *dm = w->dm;	wait_queue_t wq;	unsigned long cnt;	int ret;	DBGENTER;	init_waitqueue_entry(&wq, current);	cnt = dm->vsync_cnt;	ret = wait_event_interruptible_timeout(dm->vsync_wait,					       cnt != dm->vsync_cnt,					       dm->timeout);	if (ret < 0)		RETURN(ret);	if (ret == 0)		RETURN(-ETIMEDOUT);	RETURN(0);}/* Sets a uniform attribute value over a rectangular area on the attribute * window. The attribute value (0 to 7) is passed through the fb_fillrect's * color parameter. */static int davincifb_set_attr_blend(struct fb_fillrect *r){	struct fb_info *info = &dm->osd1->info;	struct fb_var_screeninfo *var = &dm->osd1->info.var;	unsigned long start = 0;	u8 blend;	u32 width_bytes;	if (r->dx + r->width > var->xres_virtual)		return -EINVAL;	if (r->dy + r->height > var->yres_virtual)		return -EINVAL;	if (r->color < 0 || r->color > 7)		return -EINVAL;	/* since bits_per_pixel = 4, this will truncate the width if it is	 * not even. Similarly r->dx will be rounded down to an even pixel.	 * ... Do we want to return an error otherwise?	 */	width_bytes = r->width * var->bits_per_pixel / 8;	start = dm->osd1->fb_base + r->dy * info->fix.line_length	    + r->dx * var->bits_per_pixel / 8;	blend = (((u8) r->color & 0xf) << 4) | ((u8) r->color);	while (r->height--) {		start += info->fix.line_length;		memset((void *)start, blend, width_bytes);	}	return 0;}/* These position parameters are given through fb_var_screeninfo. * xp = var.reserved[0], yp = var.reserved[1], * xl = var.xres, yl = var.yres */static void set_win_position(char *id, u32 xp, u32 yp, u32 xl, u32 yl){	int i = 0;	DBGENTER;	if (is_win(id, VID0)) {		i = 0;	} else if (is_win(id, VID1)) {		i = 1;	} else if (is_win(id, OSD0)) {		i = 2;	} else if (is_win(id, OSD1)) {		i = 3;	}	dispc_reg_out(OSD_WINXP(i), xp);	dispc_reg_out(OSD_WINYP(i), yp);	dispc_reg_out(OSD_WINXL(i), xl);	dispc_reg_out(OSD_WINYL(i), yl);	DBGEXIT;}static inline void get_win_position(struct dm_win_info *w,				    u32 * xp, u32 * yp, u32 * xl, u32 * yl){	struct fb_var_screeninfo *v = &w->info.var;	*xp = x_pos(w);	*yp = y_pos(w);	*xl = v->xres;	*yl = v->yres;}/* Returns 1 if the windows overlap, 0 otherwise */static int window_overlap(struct dm_win_info *w, u32 xp, u32 yp, u32 xl, u32 yl){	u32 _xp = 0, _yp = 0, _xl = 0, _yl = 0;#define OVERLAP(x1, y1, x2, y2, x3, y3, x4, y4)		\(!(	((x1)<(x3) && (x2)<(x3)) || ((x1)>(x4) && (x2)>(x4)) ||	\	((y1)<(y3) && (y2)<(y3)) || ((y1)>(y4) && (y2)>(y4)) )	\)	DBGENTER;	if (!w)		RETURN(0);	get_win_position(w, &_xp, &_yp, &_xl, &_yl);

⌨️ 快捷键说明

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