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

📄 savagefb_driver.c

📁 linux-2.6.15.6
💻 C
📖 第 1 页 / 共 4 页
字号:
	par->CR91 = vga_in8 (0x3d5, par);	vga_out8 (0x3d4, 0xb0, par);	par->CRB0 = vga_in8 (0x3d5, par) | 0x80;	/* extended mode timing regs */	vga_out8 (0x3d4, 0x3b, par);	par->CR3B = vga_in8 (0x3d5, par);	vga_out8 (0x3d4, 0x3c, par);	par->CR3C = vga_in8 (0x3d5, par);	vga_out8 (0x3d4, 0x43, par);	par->CR43 = vga_in8 (0x3d5, par);	vga_out8 (0x3d4, 0x5d, par);	par->CR5D = vga_in8 (0x3d5, par);	vga_out8 (0x3d4, 0x5e, par);	par->CR5E = vga_in8 (0x3d5, par);	vga_out8 (0x3d4, 0x65, par);	par->CR65 = vga_in8 (0x3d5, par);	/* save seq extended regs for DCLK PLL programming */	vga_out8 (0x3c4, 0x0e, par);	par->SR0E = vga_in8 (0x3c5, par);	vga_out8 (0x3c4, 0x0f, par);	par->SR0F = vga_in8 (0x3c5, par);	vga_out8 (0x3c4, 0x10, par);	par->SR10 = vga_in8 (0x3c5, par);	vga_out8 (0x3c4, 0x11, par);	par->SR11 = vga_in8 (0x3c5, par);	vga_out8 (0x3c4, 0x12, par);	par->SR12 = vga_in8 (0x3c5, par);	vga_out8 (0x3c4, 0x13, par);	par->SR13 = vga_in8 (0x3c5, par);	vga_out8 (0x3c4, 0x29, par);	par->SR29 = vga_in8 (0x3c5, par);	vga_out8 (0x3c4, 0x15, par);	par->SR15 = vga_in8 (0x3c5, par);	vga_out8 (0x3c4, 0x30, par);	par->SR30 = vga_in8 (0x3c5, par);	vga_out8 (0x3c4, 0x18, par);	par->SR18 = vga_in8 (0x3c5, par);	/* Save flat panel expansion regsters. */	if (par->chip == S3_SAVAGE_MX) {		int i;		for (i = 0; i < 8; i++) {			vga_out8 (0x3c4, 0x54+i, par);			par->SR54[i] = vga_in8 (0x3c5, par);		}	}	vga_out8 (0x3d4, 0x66, par);	cr66 = vga_in8 (0x3d5, par);	vga_out8 (0x3d5, cr66 | 0x80, par);	vga_out8 (0x3d4, 0x3a, par);	cr3a = vga_in8 (0x3d5, par);	vga_out8 (0x3d5, cr3a | 0x80, par);	/* now save MIU regs */	if (par->chip != S3_SAVAGE_MX) {		par->MMPR0 = savage_in32(FIFO_CONTROL_REG, par);		par->MMPR1 = savage_in32(MIU_CONTROL_REG, par);		par->MMPR2 = savage_in32(STREAMS_TIMEOUT_REG, par);		par->MMPR3 = savage_in32(MISC_TIMEOUT_REG, par);	}	vga_out8 (0x3d4, 0x3a, par);	vga_out8 (0x3d5, cr3a, par);	vga_out8 (0x3d4, 0x66, par);	vga_out8 (0x3d5, cr66, par);}static void savage_update_var(struct fb_var_screeninfo *var, struct fb_videomode *modedb){	var->xres = var->xres_virtual = modedb->xres;	var->yres = modedb->yres;        if (var->yres_virtual < var->yres)	    var->yres_virtual = var->yres;        var->xoffset = var->yoffset = 0;        var->pixclock = modedb->pixclock;        var->left_margin = modedb->left_margin;        var->right_margin = modedb->right_margin;        var->upper_margin = modedb->upper_margin;        var->lower_margin = modedb->lower_margin;        var->hsync_len = modedb->hsync_len;        var->vsync_len = modedb->vsync_len;        var->sync = modedb->sync;        var->vmode = modedb->vmode;}static int savagefb_check_var (struct fb_var_screeninfo   *var,			       struct fb_info *info){	struct savagefb_par *par = (struct savagefb_par *)info->par;	int memlen, vramlen, mode_valid = 0;	DBG("savagefb_check_var");	var->transp.offset = 0;	var->transp.length = 0;	switch (var->bits_per_pixel) {	case 8:		var->red.offset = var->green.offset =			var->blue.offset = 0;		var->red.length = var->green.length =			var->blue.length = var->bits_per_pixel;		break;	case 16:		var->red.offset = 11;		var->red.length = 5;		var->green.offset = 5;		var->green.length = 6;		var->blue.offset = 0;		var->blue.length = 5;		break;	case 32:		var->transp.offset = 24;		var->transp.length = 8;		var->red.offset = 16;		var->red.length = 8;		var->green.offset = 8;		var->green.length = 8;		var->blue.offset = 0;		var->blue.length = 8;		break;	default:		return -EINVAL;	}	if (!info->monspecs.hfmax || !info->monspecs.vfmax ||	    !info->monspecs.dclkmax || !fb_validate_mode(var, info))		mode_valid = 1;	/* calculate modeline if supported by monitor */	if (!mode_valid && info->monspecs.gtf) {		if (!fb_get_mode(FB_MAXTIMINGS, 0, var, info))			mode_valid = 1;	}	if (!mode_valid) {		struct fb_videomode *mode;		mode = fb_find_best_mode(var, &info->modelist);		if (mode) {			savage_update_var(var, mode);			mode_valid = 1;		}	}	if (!mode_valid && info->monspecs.modedb_len)		return -EINVAL;	/* Is the mode larger than the LCD panel? */	if (par->SavagePanelWidth &&	    (var->xres > par->SavagePanelWidth ||	     var->yres > par->SavagePanelHeight)) {		printk (KERN_INFO "Mode (%dx%d) larger than the LCD panel "			"(%dx%d)\n", var->xres,  var->yres,			par->SavagePanelWidth,			par->SavagePanelHeight);		return -1;	}	if (var->yres_virtual < var->yres)		var->yres_virtual = var->yres;	if (var->xres_virtual < var->xres)		var->xres_virtual = var->xres;	vramlen = info->fix.smem_len;	memlen = var->xres_virtual * var->bits_per_pixel *		var->yres_virtual / 8;	if (memlen > vramlen) {		var->yres_virtual = vramlen * 8 /			(var->xres_virtual * var->bits_per_pixel);		memlen = var->xres_virtual * var->bits_per_pixel *			var->yres_virtual / 8;	}	/* we must round yres/xres down, we already rounded y/xres_virtual up	   if it was possible. We should return -EINVAL, but I disagree */	if (var->yres_virtual < var->yres)		var->yres = var->yres_virtual;	if (var->xres_virtual < var->xres)		var->xres = var->xres_virtual;	if (var->xoffset + var->xres > var->xres_virtual)		var->xoffset = var->xres_virtual - var->xres;	if (var->yoffset + var->yres > var->yres_virtual)		var->yoffset = var->yres_virtual - var->yres;	return 0;}static int savagefb_decode_var (struct fb_var_screeninfo   *var,				struct savagefb_par        *par){	struct xtimings timings;	int width, dclk, i, j; /*, refresh; */	unsigned int m, n, r;	unsigned char tmp = 0;	unsigned int pixclock = var->pixclock;	DBG("savagefb_decode_var");	memset (&timings, 0, sizeof(timings));	if (!pixclock) pixclock = 10000;	/* 10ns = 100MHz */	timings.Clock = 1000000000 / pixclock;	if (timings.Clock < 1) timings.Clock = 1;	timings.dblscan = var->vmode & FB_VMODE_DOUBLE;	timings.interlaced = var->vmode & FB_VMODE_INTERLACED;	timings.HDisplay = var->xres;	timings.HSyncStart = timings.HDisplay + var->right_margin;	timings.HSyncEnd = timings.HSyncStart + var->hsync_len;	timings.HTotal = timings.HSyncEnd + var->left_margin;	timings.VDisplay = var->yres;	timings.VSyncStart = timings.VDisplay + var->lower_margin;	timings.VSyncEnd = timings.VSyncStart + var->vsync_len;	timings.VTotal = timings.VSyncEnd + var->upper_margin;	timings.sync = var->sync;	par->depth  = var->bits_per_pixel;	par->vwidth = var->xres_virtual;	if (var->bits_per_pixel == 16  &&  par->chip == S3_SAVAGE3D) {		timings.HDisplay *= 2;		timings.HSyncStart *= 2;		timings.HSyncEnd *= 2;		timings.HTotal *= 2;	}	/*	 * This will allocate the datastructure and initialize all of the	 * generic VGA registers.	 */	vgaHWInit (var, par, &timings);	/* We need to set CR67 whether or not we use the BIOS. */	dclk = timings.Clock;	par->CR67 = 0x00;	switch( var->bits_per_pixel ) {	case 8:		if( (par->chip == S3_SAVAGE2000) && (dclk >= 230000) )			par->CR67 = 0x10;	/* 8bpp, 2 pixels/clock */		else			par->CR67 = 0x00;	/* 8bpp, 1 pixel/clock */		break;	case 15:		if ( S3_SAVAGE_MOBILE_SERIES(par->chip) ||		     ((par->chip == S3_SAVAGE2000) && (dclk >= 230000)) )			par->CR67 = 0x30;	/* 15bpp, 2 pixel/clock */		else			par->CR67 = 0x20;	/* 15bpp, 1 pixels/clock */		break;	case 16:		if( S3_SAVAGE_MOBILE_SERIES(par->chip) ||		    ((par->chip == S3_SAVAGE2000) && (dclk >= 230000)) )			par->CR67 = 0x50;	/* 16bpp, 2 pixel/clock */		else			par->CR67 = 0x40;	/* 16bpp, 1 pixels/clock */		break;	case 24:		par->CR67 = 0x70;		break;	case 32:		par->CR67 = 0xd0;		break;	}	/*	 * Either BIOS use is disabled, or we failed to find a suitable	 * match.  Fall back to traditional register-crunching.	 */	vga_out8 (0x3d4, 0x3a, par);	tmp = vga_in8 (0x3d5, par);	if (1 /*FIXME:psav->pci_burst*/)		par->CR3A = (tmp & 0x7f) | 0x15;	else		par->CR3A = tmp | 0x95;	par->CR53 = 0x00;	par->CR31 = 0x8c;	par->CR66 = 0x89;	vga_out8 (0x3d4, 0x58, par);	par->CR58 = vga_in8 (0x3d5, par) & 0x80;	par->CR58 |= 0x13;	par->SR15 = 0x03 | 0x80;	par->SR18 = 0x00;	par->CR43 = par->CR45 = par->CR65 = 0x00;	vga_out8 (0x3d4, 0x40, par);	par->CR40 = vga_in8 (0x3d5, par) & ~0x01;	par->MMPR0 = 0x010400;	par->MMPR1 = 0x00;	par->MMPR2 = 0x0808;	par->MMPR3 = 0x08080810;	SavageCalcClock (dclk, 1, 1, 127, 0, 4, 180000, 360000, &m, &n, &r);	/* m = 107; n = 4; r = 2; */	if (par->MCLK <= 0) {		par->SR10 = 255;		par->SR11 = 255;	} else {		common_calc_clock (par->MCLK, 1, 1, 31, 0, 3, 135000, 270000,				   &par->SR11, &par->SR10);		/*      par->SR10 = 80; // MCLK == 286000 */		/*      par->SR11 = 125; */	}	par->SR12 = (r << 6) | (n & 0x3f);	par->SR13 = m & 0xff;	par->SR29 = (r & 4) | (m & 0x100) >> 5 | (n & 0x40) >> 2;	if (var->bits_per_pixel < 24)		par->MMPR0 -= 0x8000;	else		par->MMPR0 -= 0x4000;	if (timings.interlaced)		par->CR42 = 0x20;	else		par->CR42 = 0x00;	par->CR34 = 0x10; /* display fifo */	i = ((((timings.HTotal >> 3) - 5) & 0x100) >> 8) |		((((timings.HDisplay >> 3) - 1) & 0x100) >> 7) |		((((timings.HSyncStart >> 3) - 1) & 0x100) >> 6) |		((timings.HSyncStart & 0x800) >> 7);	if ((timings.HSyncEnd >> 3) - (timings.HSyncStart >> 3) > 64)		i |= 0x08;	if ((timings.HSyncEnd >> 3) - (timings.HSyncStart >> 3) > 32)		i |= 0x20;	j = (par->CRTC[0] + ((i & 0x01) << 8) +	     par->CRTC[4] + ((i & 0x10) << 4) + 1) / 2;	if (j - (par->CRTC[4] + ((i & 0x10) << 4)) < 4) {		if (par->CRTC[4] + ((i & 0x10) << 4) + 4 <=		    par->CRTC[0] + ((i & 0x01) << 8))			j = par->CRTC[4] + ((i & 0x10) << 4) + 4;		else			j = par->CRTC[0] + ((i & 0x01) << 8) + 1;	}	par->CR3B = j & 0xff;	i |= (j & 0x100) >> 2;	par->CR3C = (par->CRTC[0] + ((i & 0x01) << 8)) / 2;	par->CR5D = i;	par->CR5E = (((timings.VTotal - 2) & 0x400) >> 10) |		(((timings.VDisplay - 1) & 0x400) >> 9) |		(((timings.VSyncStart) & 0x400) >> 8) |		(((timings.VSyncStart) & 0x400) >> 6) | 0x40;	width = (var->xres_virtual * ((var->bits_per_pixel+7) / 8)) >> 3;	par->CR91 = par->CRTC[19] = 0xff & width;	par->CR51 = (0x300 & width) >> 4;	par->CR90 = 0x80 | (width >> 8);	par->MiscOutReg |= 0x0c;	/* Set frame buffer description. */	if (var->bits_per_pixel <= 8)		par->CR50 = 0;	else if (var->bits_per_pixel <= 16)		par->CR50 = 0x10;	else		par->CR50 = 0x30;	if (var->xres_virtual <= 640)		par->CR50 |= 0x40;	else if (var->xres_virtual == 800)		par->CR50 |= 0x80;	else if (var->xres_virtual == 1024)		par->CR50 |= 0x00;	else if (var->xres_virtual == 1152)		par->CR50 |= 0x01;	else if (var->xres_virtual == 1280)		par->CR50 |= 0xc0;	else if (var->xres_virtual == 1600)		par->CR50 |= 0x81;	else		par->CR50 |= 0xc1;	/* Use GBD */	if( par->chip == S3_SAVAGE2000 )		par->CR33 = 0x08;	else		par->CR33 = 0x20;	par->CRTC[0x17] = 0xeb;	par->CR67 |= 1;	vga_out8(0x3d4, 0x36, par);	par->CR36 = vga_in8 (0x3d5, par);	vga_out8 (0x3d4, 0x68, par);	par->CR68 = vga_in8 (0x3d5, par);	par->CR69 = 0;	vga_out8 (0x3d4, 0x6f, par);	par->CR6F = vga_in8 (0x3d5, par);	vga_out8 (0x3d4, 0x86, par);	par->CR86 = vga_in8 (0x3d5, par);	vga_out8 (0x3d4, 0x88, par);	par->CR88 = vga_in8 (0x3d5, par) | 0x08;	vga_out8 (0x3d4, 0xb0, par);	par->CRB0 = vga_in8 (0x3d5, par) | 0x80;	return 0;}/* --------------------------------------------------------------------- *//* *    Set a single color register. Return != 0 for invalid regno. */static int savagefb_setcolreg(unsigned        regno,			      unsigned        red,			      unsigned        green,			      unsigned        blue,			      unsigned        transp,			      struct fb_info *info){	struct savagefb_par *par = (struct savagefb_par *)info->par;	if (regno >= NR_PALETTE)		return -EINVAL;	par->palette[regno].red    = red;	par->palette[regno].green  = green;	par->palette[regno].blue   = blue;	par->palette[regno].transp = transp;	switch (info->var.bits_per_pixel) {	case 8:		vga_out8 (0x3c8, regno, par);		vga_out8 (0x3c9, red   >> 10, par);		vga_out8 (0x3c9, green >> 10, par);		vga_out8 (0x3c9, blue  >> 10, par);		break;	case 16:		if (regno < 16)			((u32 *)info->pseudo_palette)[regno] =				((red   & 0xf800)      ) |				((green & 0xfc00) >>  5) |				((blue  & 0xf800) >> 11);		break;	case 24:		if (regno < 16)			((u32 *)info->pseudo_palette)[regno] =				((red    & 0xff00) <<  8) |				((green  & 0xff00)      ) |				((blue   & 0xff00) >>  8);		break;	case 32:		if (regno < 16)			((u32 *)info->pseudo_palette)[regno] =				((transp & 0xff00) << 16) |				((red    & 0xff00) <<  8) |				((green  & 0xff00)      ) |				((blue   & 0xff00) >>  8);		break;	default:		return 1;	}	return 0;}static void savagefb_set_par_int (struct savagefb_par  *par){	unsigned char tmp, cr3a, cr66, cr67;	DBG ("savagefb_set_par_int");	par->SavageWaitIdle (par);	vga_out8 (0x3c2, 0x23, par);	vga_out16 (0x3d4, 0x4838, par);	vga_out16 (0x3d4, 0xa539, par);	vga_out16 (0x3c4, 0x0608, par);	vgaHWProtect (par, 1);	/*	 * Some Savage/MX and /IX systems go nuts when trying to exit the	 * server after WindowMaker has displayed a gradient background.  I	 * haven't been able to find what causes it, but a non-destructive	 * switch to mode 3 here seems to eliminate the issue.	 */	VerticalRetraceWait(par);	vga_out8 (0x3d4, 0x67, par);	cr67 = vga_in8 (0x3d5, par);	vga_out8 (0x3d5, cr67/*par->CR67*/ & ~0x0c, par); /* no STREAMS yet */	vga_out8 (0x3d4, 0x23, par);	vga_out8 (0x3d5, 0x00, par);	vga_out8 (0x3d4, 0x26, par);	vga_out8 (0x3d5, 0x00, par);	/* restore extended regs */	vga_out8 (0x3d4, 0x66, par);	vga_out8 (0x3d5, par->CR66, par);	vga_out8 (0x3d4, 0x3a, par);	vga_out8 (0x3d5, par->CR3A, par);	vga_out8 (0x3d4, 0x31, par);	vga_out8 (0x3d5, par->CR31, par);	vga_out8 (0x3d4, 0x32, par);	vga_out8 (0x3d5, par->CR32, par);	vga_out8 (0x3d4, 0x58, par);	vga_out8 (0x3d5, par->CR58, par);	vga_out8 (0x3d4, 0x53, par);	vga_out8 (0x3d5, par->CR53 & 0x7f, par);	vga_out16 (0x3c4, 0x0608, par);	/* Restore DCLK registers. */	vga_out8 (0x3c4, 0x0e, par);	vga_out8 (0x3c5, par->SR0E, par);	vga_out8 (0x3c4, 0x0f, par);	vga_out8 (0x3c5, par->SR0F, par);	vga_out8 (0x3c4, 0x29, par);	vga_out8 (0x3c5, par->SR29, par);	vga_out8 (0x3c4, 0x15, par);	vga_out8 (0x3c5, par->SR15, par);	/* Restore flat panel expansion regsters. */	if( par->chip == S3_SAVAGE_MX ) {		int i;		for( i = 0; i < 8; i++ ) {			vga_out8 (0x3c4, 0x54+i, par);			vga_out8 (0x3c5, par->SR54[i], par);		}	}	vgaHWRestore (par);	/* extended mode timing registers */	vga_out8 (0x3d4, 0x53, par);	vga_out8 (0x3d5, par->CR53, par);	vga_out8 (0x3d4, 0x5d, par);	vga_out8 (0x3d5, par->CR5D, par);	vga_out8 (0x3d4, 0x5e, par);	vga_out8 (0x3d5, par->CR5E, par);	vga_out8 (0x3d4, 0x3b, par);	vga_out8 (0x3d5, par->CR3B, par);	vga_out8 (0x3d4, 0x3c, par);	vga_out8 (0x3d5, par->CR3C, par);	vga_out8 (0x3d4, 0x43, par);	vga_out8 (0x3d5, par->CR43, par);	vga_out8 (0x3d4, 0x65, par);	vga_out8 (0x3d5, par->CR65, par);	/* restore the desired video mode with cr67 */	vga_out8 (0x3d4, 0x67, par);	/* following part not present in X11 driver */	cr67 = vga_in8 (0x3d5, par) & 0xf;	vga_out8 (0x3d5, 0x50 | cr67, par);	udelay (10000);	vga_out8 (0x3d4, 0x67, par);	/* end of part */	vga_out8 (0x3d5, par->CR67 & ~0x0c, par);	/* other mode timing and extended regs */	vga_out8 (0x3d4, 0x34, par);	vga_out8 (0x3d5, par->CR34, par);	vga_out8 (0x3d4, 0x40, par);	vga_out8 (0x3d5, par->CR40, par);	vga_out8 (0x3d4, 0x42, par);	vga_out8 (0x3d5, par->CR42, par);	vga_out8 (0x3d4, 0x45, par);	vga_out8 (0x3d5, par->CR45, par);	vga_out8 (0x3d4, 0x50, par);	vga_out8 (0x3d5, par->CR50, par);	vga_out8 (0x3d4, 0x51, par);	vga_out8 (0x3d5, par->CR51, par);	/* memory timings */

⌨️ 快捷键说明

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