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

📄 omap_fb.c

📁 omap3 linux 2.6 用nocc去除了冗余代码
💻 C
📖 第 1 页 / 共 4 页
字号:
/* * drivers/video/omap24xxfb.c * * Framebuffer driver for OMAP24xx display controller. * * Copyright (C) 2004-2005-2006 Texas Instruments, Inc. * * Author: 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/ioport.h>#include <linux/types.h>#include <linux/dma-mapping.h>#include <linux/init.h>#include <linux/smp_lock.h>#include <linux/interrupt.h>#include <linux/console.h>#include <linux/platform_device.h>#include <asm/irq.h>#include <asm/arch/clock.h>#include <asm/uaccess.h>#define PM_DEBUG 1#include <linux/notifier.h>#include <linux/pm.h>#include <asm/arch/display.h>#include "omap_fb.h"#undef DEBUG#define DBGENTER#define DBGLEAVE#define DBGENTER_c#define OMAPFB_DEVICE	"omap24xxfb"#define OMAPFB_DRIVER	"omap24xxfb"#define FB_NAME 	"omap24xxfb"	/* 16 chars max */#define SCHEDULE_WAIT	0#define BUSY_WAIT	1/* To use the rotation feature, include this in your boot params:	video=omap24xxfb:rotation=[0|90|180|270]*/int omap24xxfb_rotation = -1;	// -1 = no rotation supportint omap24xxfb_mirroring = 0;	// the status of mirroring#define omap_rotation_index(rotation_deg) \		(rotation_deg == 90)?(270/90): \		(rotation_deg == 270)?(90/90): \		(rotation_deg == 180)?(180/90): \		(0/90)#define omap_rot_mirror_index(rotation_deg) \		(rotation_deg == 90)?(90/90): \		(rotation_deg == 270)?(270/90): \		(rotation_deg == 180)?(0/90): \		(180/90)struct omap24xxfb_info {	/* The fb_info structure must be first! */	struct fb_info info;	dma_addr_t mmio_base_phys;	dma_addr_t fb_base_phys;	unsigned long fb_size;	unsigned long mmio_base;	unsigned long fb_base;	wait_queue_head_t vsync_wait;	unsigned long vsync_cnt;	u32 pseudo_palette[17];	u32 *palette;	dma_addr_t palette_phys;	/* Period of the graphics clock in picoseconds.	 * This is is the input to the pixel clock divider.	 */	unsigned long gfx_clk_period;	unsigned int hsync;	/* horizontal sync frequency in Hz */	unsigned int vsync;	/* vertical sync frequency in Hz */	unsigned long timeout;	/* register update timeout period in ticks */	int alloc_fb_mem;	int asleep;	int blanked;	int rotation_support;	int rotation_deg;	dma_addr_t sms_rot_phy[4];	unsigned long sms_rot_virt[4];	unsigned long vrfb_size;};static struct omap24xxfb_info *saved_oinfo;static struct fb_var_screeninfo default_var;int	fb_out_layer = OMAP2_GRAPHICS;extern void get_panel_default_var(struct fb_var_screeninfo *var, int output_dev);extern u32 get_panel_pixclock_max(int output_dev);extern u32 get_panel_pixclock_min(int output_dev);extern void enable_backlight(void);extern void disable_backlight(void);int omap24xx_get_dss1_clock(void);extern int omap24xxfb_set_output_layer(int layer);/******************************************************************************//* Platform-specific customization for the framebuffer driver. *//* omap24xxfb_gfx_clk_period() must return the period (in picoseconds) of the * graphics timebase clock.  This clock is the input to the pixel clock * divider. * * prototype: * unsigned long omap24xxfb_gfx_clk_period(void); */#define omap24xxfb_gfx_clk_period() (1000000000UL/(omap24xx_get_dss1_clock()/1000))/* omap24xxfb_fb_base() must return the physical base address of the * framebuffer.  If the address is non-zero, then the framebuffer memory is * ioremap'd.  If the address is zero, then the framebuffer memory is * dynamically allocated by the driver. * * prototype: * unsigned long omap24xxfb_fb_base(void); */#define omap24xxfb_fb_base() 0/* omap24xxfb_fb_size() must return the size of the framebuffer in bytes. * The framebuffer is only ioremap'd (or kmalloc'd) at driver initialization * time.  It does not change when the video mode (resolution and color depth) * changes, so it must be large enough for all video modes that are to be * supported. * * In non-rotation mode, we're allocating a framebuffer 2 times the size of * the physical display. This is to support double buffering. The panning ioctl * can be used to switch between the two different framebuffer regions, so * you effectively have an onscreen framebuffer and two offscreen framebuffers. * * In rotation mode vrfb line length is fixed that is 2048 pixels.  So * allocating buffer size of 2048 * 640 * 4.  640 is max y resolution and * 4 is for 32bpps mode.  Panning is not supported with rotation so * allocating only 1 buffer. * prototype: * unsigned long omap24xxfb_fb_size(void); */#define omap24xxfb_fb_size(rotation) \	rotation ? (2048 * 640 * (32/8)) : (720 * 576 * (32/8) * 2) /* 720 x 576 is the max framebuffer size we allow for TV (PAL) *//* omap24xxfb_vrfb_size() must return the size of the virtual rotated * framebuffer. * * prototype: * unsigned long omap24xxfb_fb_size(void); */#define omap24xxfb_vrfb_size()	(MAX_PIXELS_PER_LINE * 640 * (32/8))/* omap24xx_display_pixclock_max() must return the maximum pixclock period * supported by the display. * * prototype: * unsigned int omap24xx_display_pixclock_max(void); */#define omap24xx_display_pixclock_max(ouput_dev) \		(get_panel_pixclock_max(output_dev))/* omap24xx_display_pixclock_min() must return the minimum pixclock period * supported by the display. * * prototype: * unsigned int omap24xx_display_pixclock_min(void); */#define omap24xx_display_pixclock_min(output_dev) \		(get_panel_pixclock_min(output_dev))/* omap24xxfb_default_var() must return a pointer to a default * fb_var_screeninfo struct that will be used to set the initial video mode. * If this video mode is invalid (as determined by omap24xxfb_check_var) then * the driver will fail to initialize. * * prototype: * struct fb_var_screeninfo *omap24xxfb_default_var(void); */static struct fb_var_screeninfo *omap24xxfb_default_var(void){	struct fb_var_screeninfo *v = &default_var;	int output_dev = omap2_disp_get_output_dev(OMAP2_GRAPHICS);	u32 tmp;	get_panel_default_var(v, output_dev);	if (omap24xxfb_rotation >= 0) {		v->xres_virtual = v->yres_virtual = max(v->xres, v->yres);		switch(omap24xxfb_rotation) {			case 0:			default:				v->xoffset	= 0;				v->yoffset	= 0;				v->rotate	= 0;				break;			case 90:				tmp = v->xres, v->xres = v->yres, v->yres = tmp;				v->xoffset	= 0;				v->yoffset	= 0;				v->rotate	= 90;				break;			case 180:				v->xoffset	= 0;				v->yoffset	= 0;				v->rotate 	= 180;				break;			case 270:				tmp = v->xres, v->xres = v->yres, v->yres = tmp;				v->xoffset	= 0;				v->yoffset	= 0;				v->rotate 	= 270;				break;		}	}	return v;}/* omap24xxfb_check_mode() must check the video mode specified in a * fb_var_screeninfo struct and return 0 if the mode is supported and non-zero * if the mode is not supported.  omap24xxfb_check_mode() is permitted to * modify the var to make it conform to a supported mode. * * prototype: * int omap24xxfb_check_mode(const struct omap24xxfb_info *oinfo, *			     struct fb_var_screeninfo *var); */static intomap24xxfb_check_mode(const struct omap24xxfb_info *oinfo,		      struct fb_var_screeninfo *var){	u32 pixclock, clkdiv;	u32 display_xres, display_yres;	int output_dev;	omap2_disp_get_dss();	output_dev = omap2_disp_get_output_dev(OMAP2_GRAPHICS);	omap2_disp_get_panel_size(output_dev, &display_xres, &display_yres);	if (oinfo->rotation_support) {		if (var->rotate % 90 != 0) {			omap2_disp_put_dss();				return -EINVAL;		}		if (!((var->bits_per_pixel == 8) ||					(var->bits_per_pixel == 16)||					(var->bits_per_pixel == 32))) {			omap2_disp_put_dss();			return -EINVAL;		}		switch (var->rotate) {			case 0:			case 180:			default:				if ((var->xres > display_xres) ||						(var->yres > display_yres)) {					omap2_disp_put_dss();					return -EINVAL;				}				break;			case 90:			case 270:				if ((var->xres > display_yres) ||						(var->yres > display_xres)) {					omap2_disp_put_dss();					return -EINVAL;				}				break;		}	} else {		if ((var->xres > display_xres) ||				(var->yres > display_yres)) {			omap2_disp_put_dss();			return -EINVAL;		}	}	pixclock = (var->pixclock > 0) ? var->pixclock :		omap24xx_display_pixclock_max(output_dev);	if (pixclock < omap24xx_display_pixclock_min(output_dev)){		omap2_disp_put_dss();		return -EINVAL;	}	clkdiv = pixclock / oinfo->gfx_clk_period;	pixclock = oinfo->gfx_clk_period * clkdiv;	if (pixclock > omap24xx_display_pixclock_max(output_dev)) {		omap2_disp_put_dss();		return -EINVAL;	}	/* due to round-down error in division, the pixclock may fall below	   the lower threshold of the panel. Fix that by adding 1 to clkdiv.	   */	if (pixclock < omap24xx_display_pixclock_min(output_dev))		clkdiv = clkdiv + 1;	if (clkdiv < 2)		/* minimum divisor is 2 */		clkdiv = 2;	else if (clkdiv > 255)		clkdiv = 255;	/* maximum divisor is 255 */	/* recalculate pixclock and change the var structure */	pixclock = oinfo->gfx_clk_period * clkdiv;	omap2_disp_put_dss();	return 0;}struct omap24xxfb_suspend_data {	/* Power management suspend lockout stuff */	int suspended;	wait_queue_head_t suspend_wq;};static struct omap24xxfb_suspend_data fb_suspend_data;#define omap24xxfb_suspend_lockout_fp(s,f) \	if ((s)->suspended) {\		if ((f)->f_flags & O_NONBLOCK)\			return -EBUSY;\		wait_event_interruptible((s)->suspend_wq,\					 (s)->suspended == 0);\	}#define omap24xxfb_suspend_lockout(s) \	if ((s)->suspended) {\		wait_event_interruptible((s)->suspend_wq,\					 (s)->suspended == 0);\	}/******************************************************************************//* Bits-per-pixel and color depth aren't quite the same thing.  The OMAP24xx * display controller supports color depths of 1, 2, 4, 8, 12, 16, and 24 bits. * Color depth and bits-per-pixel are the same for depths of 1, 2, 4, 8, and * 16 bits, but for a color depth of 12 bits the pixel data is padded to * 16 bits-per-pixel, and for a color depth of 24 bits the pixel data is padded * to 32 bits-per-pixel. */static inline intvar_to_depth(const struct fb_var_screeninfo *var){	DBGENTER;	switch (var->bits_per_pixel) {		case 1:		case 2:		case 4:		case 8:		default:			return var->bits_per_pixel;		case 16:			if ((var->red.length + var->green.length						+ var->blue.length) == 12) {				return 12;			}			else				return 16;		case 32:			if (var->transp.length > 0)				return 32;			else				return 24;	}	DBGLEAVE;}/* Calculate the horizontal sync frequency in Hertz * with a resolution of 250Hz. */static unsigned inthorizontal_sync_freq(const struct fb_var_screeninfo *var){	unsigned int hsf, hs, nom, den;	unsigned int xres, yres;	int output_dev = omap2_disp_get_output_dev(OMAP2_GRAPHICS);	DBGENTER;	/* Calculate the number of pixels per clock. */	omap2_disp_pixels_per_clock(&nom, &den);	/* get the horizontal display resolution */	omap2_disp_get_panel_size(output_dev, &xres, &yres);	hs = (xres*den)/nom	 	+ (var->left_margin + var->right_margin + var->hsync_len);	if ((var->pixclock > 0) && (hs > 0))		hsf = (4000000000UL/(var->pixclock*hs))*250;		/* pixclock is in picoseconds		 * 10^12 / (pixclock*hs) = 4 * 10^9 * 250 / (pixclock*hs)		*/	else		hsf = 0;	DBGLEAVE;	return hsf;}/* Calculate the vertical sync frequency in Hertz. */static unsigned intvertical_sync_freq(const struct fb_var_screeninfo *var){	unsigned int vsf, vs;	unsigned int xres, yres;	int output_dev = omap2_disp_get_output_dev(OMAP2_GRAPHICS);	DBGENTER;	/* get the vertical display resolution */	omap2_disp_get_panel_size(output_dev, &xres, &yres);	vs = yres + var->upper_margin + var->lower_margin + var->vsync_len;	if (vs > 0)		vsf = horizontal_sync_freq(var)/vs;	else		vsf = 0;	DBGLEAVE;	return vsf;}/* Interrupt service routine. */static voidomap24xxfb_isr(void *arg, struct pt_regs *regs, u32 irqstatus){	struct omap24xxfb_info *oinfo = (struct omap24xxfb_info *) arg;	++oinfo->vsync_cnt;	wake_up_interruptible(&oinfo->vsync_wait);}/* Wait for a vsync interrupt.  This routine sleeps so it can only be called * from process context. */static intomap24xxfb_wait_for_vsync(struct omap24xxfb_info *oinfo){	wait_queue_t wqt;	unsigned long cnt;	int ret;	unsigned int mask = 0;	DBGENTER;	mask = (DISPC_IRQSTATUS_EVSYNC_ODD | DISPC_IRQSTATUS_EVSYNC_EVEN 			| DISPC_IRQSTATUS_VSYNC);	omap2_disp_irqenable(omap24xxfb_isr,mask);	init_waitqueue_entry(&wqt, current);	cnt = oinfo->vsync_cnt;	ret = wait_event_interruptible_timeout(oinfo->vsync_wait,			cnt != oinfo->vsync_cnt, oinfo->timeout);	/* 	 * If the GFX is on TV, then wait for another VSYNC 	 * to compensate for Interlaced scan 	 */	if(omap2_disp_get_output_dev(OMAP2_GRAPHICS) == OMAP2_OUTPUT_TV){		if(ret<0){			cnt = oinfo->vsync_cnt;			ret = wait_event_interruptible_timeout(					oinfo->vsync_wait, 					cnt != oinfo->vsync_cnt, 					oinfo->timeout);		}	}	omap2_disp_irqdisable(omap24xxfb_isr,~(mask));	DBGLEAVE;	if (ret < 0)		return ret;	if (ret == 0)		return -ETIMEDOUT;	return 0;}/* The GO bit needs to be set for the shadowed registers to take effect in * hardware. Once the hardware is ready, the GO bit will be reset. Per the * hardware specifications, we should not change any display controller * registers until the GO bit is reset. * This function polls the GO bit and waits until it is reset. * If the function may be called when the interrupts are disabled (jiffies * not running). In such cases, the 'count' variable helps to exit the loop * incase the bit gets stuck. */static voidwait_for_reg_sync(int busy_wait, unsigned long timeout){

⌨️ 快捷键说明

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