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

📄 sgivwfb.c

📁 Linux环境下视频显示卡设备的驱动程序源代码
💻 C
📖 第 1 页 / 共 2 页
字号:
/* *  linux/drivers/video/sgivwfb.c -- SGI DBE frame buffer device * *	Copyright (C) 1999 Silicon Graphics, Inc. *      Jeffrey Newquist, newquist@engr.sgi.som * *  This file is subject to the terms and conditions of the GNU General Public *  License. See the file COPYING in the main directory of this archive for *  more details. */#include <linux/module.h>#include <linux/kernel.h>#include <linux/mm.h>#include <linux/errno.h>#include <linux/delay.h>#include <linux/fb.h>#include <linux/init.h>#include <linux/ioport.h>#include <linux/platform_device.h>#include <asm/io.h>#include <asm/mtrr.h>#include <asm/visws/sgivw.h>#define INCLUDE_TIMING_TABLE_DATA#define DBE_REG_BASE par->regs#include <video/sgivw.h>struct sgivw_par {	struct asregs *regs;	u32 cmap_fifo;	u_long timing_num;};#define FLATPANEL_SGI_1600SW	5/* *  RAM we reserve for the frame buffer. This defines the maximum screen *  size * *  The default can be overridden if the driver is compiled as a module */static int ypan = 0;static int ywrap = 0;static int flatpanel_id = -1;static struct fb_fix_screeninfo sgivwfb_fix __initdata = {	.id		= "SGI Vis WS FB",	.type		= FB_TYPE_PACKED_PIXELS,        .visual		= FB_VISUAL_PSEUDOCOLOR,	.mmio_start	= DBE_REG_PHYS,	.mmio_len	= DBE_REG_SIZE,        .accel		= FB_ACCEL_NONE,	.line_length	= 640,};static struct fb_var_screeninfo sgivwfb_var __initdata = {	/* 640x480, 8 bpp */	.xres		= 640,	.yres		= 480,	.xres_virtual	= 640,	.yres_virtual	= 480,	.bits_per_pixel	= 8,	.red		= { 0, 8, 0 },	.green		= { 0, 8, 0 },	.blue		= { 0, 8, 0 },	.height		= -1,	.width		= -1,	.pixclock	= 20000,	.left_margin	= 64,	.right_margin	= 64,	.upper_margin	= 32,	.lower_margin	= 32,	.hsync_len	= 64,	.vsync_len	= 2,	.vmode		= FB_VMODE_NONINTERLACED};static struct fb_var_screeninfo sgivwfb_var1600sw __initdata = {	/* 1600x1024, 8 bpp */	.xres		= 1600,	.yres		= 1024,	.xres_virtual	= 1600,	.yres_virtual	= 1024,	.bits_per_pixel	= 8,	.red		= { 0, 8, 0 },	.green		= { 0, 8, 0 },	.blue		= { 0, 8, 0 },	.height		= -1,	.width		= -1,	.pixclock	= 9353,	.left_margin	= 20,	.right_margin	= 30,	.upper_margin	= 37,	.lower_margin	= 3,	.hsync_len	= 20,	.vsync_len	= 3,	.vmode		= FB_VMODE_NONINTERLACED};/* *  Interface used by the world */int sgivwfb_init(void);static int sgivwfb_check_var(struct fb_var_screeninfo *var, struct fb_info *info);static int sgivwfb_set_par(struct fb_info *info);static int sgivwfb_setcolreg(u_int regno, u_int red, u_int green,			     u_int blue, u_int transp,			     struct fb_info *info);static int sgivwfb_mmap(struct fb_info *info,			struct vm_area_struct *vma);static struct fb_ops sgivwfb_ops = {	.owner		= THIS_MODULE,	.fb_check_var	= sgivwfb_check_var,	.fb_set_par	= sgivwfb_set_par,	.fb_setcolreg	= sgivwfb_setcolreg,	.fb_fillrect	= cfb_fillrect,	.fb_copyarea	= cfb_copyarea,	.fb_imageblit	= cfb_imageblit,	.fb_mmap	= sgivwfb_mmap,};/* *  Internal routines */static unsigned long bytes_per_pixel(int bpp){	switch (bpp) {		case 8:			return 1;		case 16:			return 2;		case 32:			return 4;		default:			printk(KERN_INFO "sgivwfb: unsupported bpp %d\n", bpp);			return 0;	}}static unsigned long get_line_length(int xres_virtual, int bpp){	return (xres_virtual * bytes_per_pixel(bpp));}/* * Function:	dbe_TurnOffDma * Parameters:	(None) * Description:	This should turn off the monitor and dbe.  This is used *              when switching between the serial console and the graphics *              console. */static void dbe_TurnOffDma(struct sgivw_par *par){	unsigned int readVal;	int i;	// Check to see if things are already turned off:	// 1) Check to see if dbe is not using the internal dotclock.	// 2) Check to see if the xy counter in dbe is already off.	DBE_GETREG(ctrlstat, readVal);	if (GET_DBE_FIELD(CTRLSTAT, PCLKSEL, readVal) < 2)		return;	DBE_GETREG(vt_xy, readVal);	if (GET_DBE_FIELD(VT_XY, VT_FREEZE, readVal) == 1)		return;	// Otherwise, turn off dbe	DBE_GETREG(ovr_control, readVal);	SET_DBE_FIELD(OVR_CONTROL, OVR_DMA_ENABLE, readVal, 0);	DBE_SETREG(ovr_control, readVal);	udelay(1000);	DBE_GETREG(frm_control, readVal);	SET_DBE_FIELD(FRM_CONTROL, FRM_DMA_ENABLE, readVal, 0);	DBE_SETREG(frm_control, readVal);	udelay(1000);	DBE_GETREG(did_control, readVal);	SET_DBE_FIELD(DID_CONTROL, DID_DMA_ENABLE, readVal, 0);	DBE_SETREG(did_control, readVal);	udelay(1000);	// XXX HACK:	//	//    This was necessary for GBE--we had to wait through two	//    vertical retrace periods before the pixel DMA was	//    turned off for sure.  I've left this in for now, in	//    case dbe needs it.	for (i = 0; i < 10000; i++) {		DBE_GETREG(frm_inhwctrl, readVal);		if (GET_DBE_FIELD(FRM_INHWCTRL, FRM_DMA_ENABLE, readVal) ==		    0)			udelay(10);		else {			DBE_GETREG(ovr_inhwctrl, readVal);			if (GET_DBE_FIELD			    (OVR_INHWCTRL, OVR_DMA_ENABLE, readVal) == 0)				udelay(10);			else {				DBE_GETREG(did_inhwctrl, readVal);				if (GET_DBE_FIELD				    (DID_INHWCTRL, DID_DMA_ENABLE,				     readVal) == 0)					udelay(10);				else					break;			}		}	}}/* *  Set the User Defined Part of the Display. Again if par use it to get *  real video mode. */static int sgivwfb_check_var(struct fb_var_screeninfo *var, 			     struct fb_info *info){	struct sgivw_par *par = (struct sgivw_par *)info->par;	struct dbe_timing_info *timing;	u_long line_length;	u_long min_mode;	int req_dot;	int test_mode;	/*	 *  FB_VMODE_CONUPDATE and FB_VMODE_SMOOTH_XPAN are equal!	 *  as FB_VMODE_SMOOTH_XPAN is only used internally	 */	if (var->vmode & FB_VMODE_CONUPDATE) {		var->vmode |= FB_VMODE_YWRAP;		var->xoffset = info->var.xoffset;		var->yoffset = info->var.yoffset;	}	/* XXX FIXME - forcing var's */	var->xoffset = 0;	var->yoffset = 0;	/* Limit bpp to 8, 16, and 32 */	if (var->bits_per_pixel <= 8)		var->bits_per_pixel = 8;	else if (var->bits_per_pixel <= 16)		var->bits_per_pixel = 16;	else if (var->bits_per_pixel <= 32)		var->bits_per_pixel = 32;	else		return -EINVAL;	var->grayscale = 0;	/* No grayscale for now */	/* determine valid resolution and timing */	for (min_mode = 0; min_mode < DBE_VT_SIZE; min_mode++) {		if (dbeVTimings[min_mode].width >= var->xres &&		    dbeVTimings[min_mode].height >= var->yres)			break;	}	if (min_mode == DBE_VT_SIZE)		return -EINVAL;	/* Resolution to high */	/* XXX FIXME - should try to pick best refresh rate */	/* for now, pick closest dot-clock within 3MHz */	req_dot = PICOS2KHZ(var->pixclock);	printk(KERN_INFO "sgivwfb: requested pixclock=%d ps (%d KHz)\n",	       var->pixclock, req_dot);	test_mode = min_mode;	while (dbeVTimings[min_mode].width == dbeVTimings[test_mode].width) {		if (dbeVTimings[test_mode].cfreq + 3000 > req_dot)			break;		test_mode++;	}	if (dbeVTimings[min_mode].width != dbeVTimings[test_mode].width)		test_mode--;	min_mode = test_mode;	timing = &dbeVTimings[min_mode];	printk(KERN_INFO "sgivwfb: granted dot-clock=%d KHz\n", timing->cfreq);	/* Adjust virtual resolution, if necessary */	if (var->xres > var->xres_virtual || (!ywrap && !ypan))		var->xres_virtual = var->xres;	if (var->yres > var->yres_virtual || (!ywrap && !ypan))		var->yres_virtual = var->yres;	/*	 *  Memory limit	 */	line_length = get_line_length(var->xres_virtual, var->bits_per_pixel);	if (line_length * var->yres_virtual > sgivwfb_mem_size)		return -ENOMEM;	/* Virtual resolution to high */	info->fix.line_length = line_length;	switch (var->bits_per_pixel) {	case 8:		var->red.offset = 0;		var->red.length = 8;		var->green.offset = 0;		var->green.length = 8;		var->blue.offset = 0;		var->blue.length = 8;		var->transp.offset = 0;		var->transp.length = 0;		break;	case 16:		/* RGBA 5551 */		var->red.offset = 11;		var->red.length = 5;		var->green.offset = 6;		var->green.length = 5;		var->blue.offset = 1;		var->blue.length = 5;		var->transp.offset = 0;		var->transp.length = 0;		break;	case 32:		/* RGB 8888 */		var->red.offset = 0;		var->red.length = 8;		var->green.offset = 8;		var->green.length = 8;		var->blue.offset = 16;		var->blue.length = 8;		var->transp.offset = 24;		var->transp.length = 8;		break;	}	var->red.msb_right = 0;	var->green.msb_right = 0;	var->blue.msb_right = 0;	var->transp.msb_right = 0;	/* set video timing information */	var->pixclock = KHZ2PICOS(timing->cfreq);	var->left_margin = timing->htotal - timing->hsync_end;	var->right_margin = timing->hsync_start - timing->width;	var->upper_margin = timing->vtotal - timing->vsync_end;	var->lower_margin = timing->vsync_start - timing->height;	var->hsync_len = timing->hsync_end - timing->hsync_start;	var->vsync_len = timing->vsync_end - timing->vsync_start;	/* Ouch. This breaks the rules but timing_num is only important if you	* change a video mode */	par->timing_num = min_mode;	printk(KERN_INFO "sgivwfb: new video mode xres=%d yres=%d bpp=%d\n",		var->xres, var->yres, var->bits_per_pixel);	printk(KERN_INFO "         vxres=%d vyres=%d\n", var->xres_virtual,		var->yres_virtual);	return 0;}/* *  Setup flatpanel related registers. */static void sgivwfb_setup_flatpanel(struct sgivw_par *par, struct dbe_timing_info *currentTiming){	int fp_wid, fp_hgt, fp_vbs, fp_vbe;	u32 outputVal = 0;	SET_DBE_FIELD(VT_FLAGS, HDRV_INVERT, outputVal, 		(currentTiming->flags & FB_SYNC_HOR_HIGH_ACT) ? 0 : 1);	SET_DBE_FIELD(VT_FLAGS, VDRV_INVERT, outputVal, 		(currentTiming->flags & FB_SYNC_VERT_HIGH_ACT) ? 0 : 1);	DBE_SETREG(vt_flags, outputVal);	/* Turn on the flat panel */	switch (flatpanel_id) {		case FLATPANEL_SGI_1600SW:			fp_wid = 1600;			fp_hgt = 1024;			fp_vbs = 0;			fp_vbe = 1600;			currentTiming->pll_m = 4;			currentTiming->pll_n = 1;			currentTiming->pll_p = 0;			break;		default:      			fp_wid = fp_hgt = fp_vbs = fp_vbe = 0xfff;  	}	outputVal = 0;	SET_DBE_FIELD(FP_DE, FP_DE_ON, outputVal, fp_vbs);	SET_DBE_FIELD(FP_DE, FP_DE_OFF, outputVal, fp_vbe);	DBE_SETREG(fp_de, outputVal);	outputVal = 0;	SET_DBE_FIELD(FP_HDRV, FP_HDRV_OFF, outputVal, fp_wid);	DBE_SETREG(fp_hdrv, outputVal);	outputVal = 0;	SET_DBE_FIELD(FP_VDRV, FP_VDRV_ON, outputVal, 1);	SET_DBE_FIELD(FP_VDRV, FP_VDRV_OFF, outputVal, fp_hgt + 1);	DBE_SETREG(fp_vdrv, outputVal);}/* *  Set the hardware according to 'par'. */static int sgivwfb_set_par(struct fb_info *info){	struct sgivw_par *par = info->par;	int i, j, htmp, temp;	u32 readVal, outputVal;	int wholeTilesX, maxPixelsPerTileX;	int frmWrite1, frmWrite2, frmWrite3b;	struct dbe_timing_info *currentTiming; /* Current Video Timing */	int xpmax, ypmax;	// Monitor resolution	int bytesPerPixel;	// Bytes per pixel	currentTiming = &dbeVTimings[par->timing_num];	bytesPerPixel = bytes_per_pixel(info->var.bits_per_pixel);	xpmax = currentTiming->width;	ypmax = currentTiming->height;	/* dbe_InitGraphicsBase(); */	/* Turn on dotclock PLL */	DBE_SETREG(ctrlstat, 0x20000000);	dbe_TurnOffDma(par);	/* dbe_CalculateScreenParams(); */	maxPixelsPerTileX = 512 / bytesPerPixel;	wholeTilesX = xpmax / maxPixelsPerTileX;	if (wholeTilesX * maxPixelsPerTileX < xpmax)		wholeTilesX++;	printk(KERN_DEBUG "sgivwfb: pixPerTile=%d wholeTilesX=%d\n",	       maxPixelsPerTileX, wholeTilesX);	/* dbe_InitGammaMap(); */	udelay(10);	for (i = 0; i < 256; i++) {		DBE_ISETREG(gmap, i, (i << 24) | (i << 16) | (i << 8));	}	/* dbe_TurnOn(); */	DBE_GETREG(vt_xy, readVal);	if (GET_DBE_FIELD(VT_XY, VT_FREEZE, readVal) == 1) {		DBE_SETREG(vt_xy, 0x00000000);

⌨️ 快捷键说明

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