static int neofb_set_par()

in fbdev/neofb.c [720:1166]


static int neofb_set_par(struct fb_info *info)
{
	struct neofb_par *par = info->par;
	unsigned char temp;
	int i, clock_hi = 0;
	int lcd_stretch;
	int hoffset, voffset;
	int vsync_start, vtotal;

	DBG("neofb_set_par");

	neoUnlock();

	vgaHWProtect(1);	/* Blank the screen */

	vsync_start = info->var.yres + info->var.lower_margin;
	vtotal = vsync_start + info->var.vsync_len + info->var.upper_margin;

	/*
	 * This will allocate the datastructure and initialize all of the
	 * generic VGA registers.
	 */

	if (vgaHWInit(&info->var, par))
		return -EINVAL;

	/*
	 * The default value assigned by vgaHW.c is 0x41, but this does
	 * not work for NeoMagic.
	 */
	par->Attribute[16] = 0x01;

	switch (info->var.bits_per_pixel) {
	case 8:
		par->CRTC[0x13] = info->var.xres_virtual >> 3;
		par->ExtCRTOffset = info->var.xres_virtual >> 11;
		par->ExtColorModeSelect = 0x11;
		break;
	case 16:
		par->CRTC[0x13] = info->var.xres_virtual >> 2;
		par->ExtCRTOffset = info->var.xres_virtual >> 10;
		par->ExtColorModeSelect = 0x13;
		break;
	case 24:
		par->CRTC[0x13] = (info->var.xres_virtual * 3) >> 3;
		par->ExtCRTOffset = (info->var.xres_virtual * 3) >> 11;
		par->ExtColorModeSelect = 0x14;
		break;
#ifdef NO_32BIT_SUPPORT_YET
	case 32:		/* FIXME: guessed values */
		par->CRTC[0x13] = info->var.xres_virtual >> 1;
		par->ExtCRTOffset = info->var.xres_virtual >> 9;
		par->ExtColorModeSelect = 0x15;
		break;
#endif
	default:
		break;
	}

	par->ExtCRTDispAddr = 0x10;

	/* Vertical Extension */
	par->VerticalExt = (((vtotal - 2) & 0x400) >> 10)
	    | (((info->var.yres - 1) & 0x400) >> 9)
	    | (((vsync_start) & 0x400) >> 8)
	    | (((vsync_start) & 0x400) >> 7);

	/* Fast write bursts on unless disabled. */
	if (par->pci_burst)
		par->SysIfaceCntl1 = 0x30;
	else
		par->SysIfaceCntl1 = 0x00;

	par->SysIfaceCntl2 = 0xc0;	/* VESA Bios sets this to 0x80! */

	/* Initialize: by default, we want display config register to be read */
	par->PanelDispCntlRegRead = 1;

	/* Enable any user specified display devices. */
	par->PanelDispCntlReg1 = 0x00;
	if (par->internal_display)
		par->PanelDispCntlReg1 |= 0x02;
	if (par->external_display)
		par->PanelDispCntlReg1 |= 0x01;

	/* If the user did not specify any display devices, then... */
	if (par->PanelDispCntlReg1 == 0x00) {
		/* Default to internal (i.e., LCD) only. */
		par->PanelDispCntlReg1 = vga_rgfx(NULL, 0x20) & 0x03;
	}

	/* If we are using a fixed mode, then tell the chip we are. */
	switch (info->var.xres) {
	case 1280:
		par->PanelDispCntlReg1 |= 0x60;
		break;
	case 1024:
		par->PanelDispCntlReg1 |= 0x40;
		break;
	case 800:
		par->PanelDispCntlReg1 |= 0x20;
		break;
	case 640:
	default:
		break;
	}

	/* Setup shadow register locking. */
	switch (par->PanelDispCntlReg1 & 0x03) {
	case 0x01:		/* External CRT only mode: */
		par->GeneralLockReg = 0x00;
		/* We need to program the VCLK for external display only mode. */
		par->ProgramVCLK = 1;
		break;
	case 0x02:		/* Internal LCD only mode: */
	case 0x03:		/* Simultaneous internal/external (LCD/CRT) mode: */
		par->GeneralLockReg = 0x01;
		/* Don't program the VCLK when using the LCD. */
		par->ProgramVCLK = 0;
		break;
	}

	/*
	 * If the screen is to be stretched, turn on stretching for the
	 * various modes.
	 *
	 * OPTION_LCD_STRETCH means stretching should be turned off!
	 */
	par->PanelDispCntlReg2 = 0x00;
	par->PanelDispCntlReg3 = 0x00;

	if (par->lcd_stretch && (par->PanelDispCntlReg1 == 0x02) &&	/* LCD only */
	    (info->var.xres != par->NeoPanelWidth)) {
		switch (info->var.xres) {
		case 320:	/* Needs testing.  KEM -- 24 May 98 */
		case 400:	/* Needs testing.  KEM -- 24 May 98 */
		case 640:
		case 800:
		case 1024:
			lcd_stretch = 1;
			par->PanelDispCntlReg2 |= 0xC6;
			break;
		default:
			lcd_stretch = 0;
			/* No stretching in these modes. */
		}
	} else
		lcd_stretch = 0;

	/*
	 * If the screen is to be centerd, turn on the centering for the
	 * various modes.
	 */
	par->PanelVertCenterReg1 = 0x00;
	par->PanelVertCenterReg2 = 0x00;
	par->PanelVertCenterReg3 = 0x00;
	par->PanelVertCenterReg4 = 0x00;
	par->PanelVertCenterReg5 = 0x00;
	par->PanelHorizCenterReg1 = 0x00;
	par->PanelHorizCenterReg2 = 0x00;
	par->PanelHorizCenterReg3 = 0x00;
	par->PanelHorizCenterReg4 = 0x00;
	par->PanelHorizCenterReg5 = 0x00;


	if (par->PanelDispCntlReg1 & 0x02) {
		if (info->var.xres == par->NeoPanelWidth) {
			/*
			 * No centering required when the requested display width
			 * equals the panel width.
			 */
		} else {
			par->PanelDispCntlReg2 |= 0x01;
			par->PanelDispCntlReg3 |= 0x10;

			/* Calculate the horizontal and vertical offsets. */
			if (!lcd_stretch) {
				hoffset =
				    ((par->NeoPanelWidth -
				      info->var.xres) >> 4) - 1;
				voffset =
				    ((par->NeoPanelHeight -
				      info->var.yres) >> 1) - 2;
			} else {
				/* Stretched modes cannot be centered. */
				hoffset = 0;
				voffset = 0;
			}

			switch (info->var.xres) {
			case 320:	/* Needs testing.  KEM -- 24 May 98 */
				par->PanelHorizCenterReg3 = hoffset;
				par->PanelVertCenterReg2 = voffset;
				break;
			case 400:	/* Needs testing.  KEM -- 24 May 98 */
				par->PanelHorizCenterReg4 = hoffset;
				par->PanelVertCenterReg1 = voffset;
				break;
			case 640:
				par->PanelHorizCenterReg1 = hoffset;
				par->PanelVertCenterReg3 = voffset;
				break;
			case 800:
				par->PanelHorizCenterReg2 = hoffset;
				par->PanelVertCenterReg4 = voffset;
				break;
			case 1024:
				par->PanelHorizCenterReg5 = hoffset;
				par->PanelVertCenterReg5 = voffset;
				break;
			case 1280:
			default:
				/* No centering in these modes. */
				break;
			}
		}
	}

	par->biosMode =
	    neoFindMode(info->var.xres, info->var.yres,
			info->var.bits_per_pixel);

	/*
	 * Calculate the VCLK that most closely matches the requested dot
	 * clock.
	 */
	neoCalcVCLK(info, par, PICOS2KHZ(info->var.pixclock));

	/* Since we program the clocks ourselves, always use VCLK3. */
	par->MiscOutReg |= 0x0C;

	/* alread unlocked above */
	/* BOGUS  vga_wgfx(NULL, 0x09, 0x26); */

	/* don't know what this is, but it's 0 from bootup anyway */
	vga_wgfx(NULL, 0x15, 0x00);

	/* was set to 0x01 by my bios in text and vesa modes */
	vga_wgfx(NULL, 0x0A, par->GeneralLockReg);

	/*
	 * The color mode needs to be set before calling vgaHWRestore
	 * to ensure the DAC is initialized properly.
	 *
	 * NOTE: Make sure we don't change bits make sure we don't change
	 * any reserved bits.
	 */
	temp = vga_rgfx(NULL, 0x90);
	switch (info->fix.accel) {
	case FB_ACCEL_NEOMAGIC_NM2070:
		temp &= 0xF0;	/* Save bits 7:4 */
		temp |= (par->ExtColorModeSelect & ~0xF0);
		break;
	case FB_ACCEL_NEOMAGIC_NM2090:
	case FB_ACCEL_NEOMAGIC_NM2093:
	case FB_ACCEL_NEOMAGIC_NM2097:
	case FB_ACCEL_NEOMAGIC_NM2160:
	case FB_ACCEL_NEOMAGIC_NM2200:
	case FB_ACCEL_NEOMAGIC_NM2230:
	case FB_ACCEL_NEOMAGIC_NM2360:
	case FB_ACCEL_NEOMAGIC_NM2380:
		temp &= 0x70;	/* Save bits 6:4 */
		temp |= (par->ExtColorModeSelect & ~0x70);
		break;
	}

	vga_wgfx(NULL, 0x90, temp);

	/*
	 * In some rare cases a lockup might occur if we don't delay
	 * here. (Reported by Miles Lane)
	 */
	//mdelay(200);

	/*
	 * Disable horizontal and vertical graphics and text expansions so
	 * that vgaHWRestore works properly.
	 */
	temp = vga_rgfx(NULL, 0x25);
	temp &= 0x39;
	vga_wgfx(NULL, 0x25, temp);

	/*
	 * Sleep for 200ms to make sure that the two operations above have
	 * had time to take effect.
	 */
	mdelay(200);

	/*
	 * This function handles restoring the generic VGA registers.  */
	vgaHWRestore(info, par);

	/* linear colormap for non palettized modes */
	switch (info->var.bits_per_pixel) {
	case 8:
		/* PseudoColor, 256 */
		info->fix.visual = FB_VISUAL_PSEUDOCOLOR;
		break;
	case 16:
		/* TrueColor, 64k */
		info->fix.visual = FB_VISUAL_TRUECOLOR;

		for (i = 0; i < 64; i++) {
			outb(i, 0x3c8);

			outb(i << 1, 0x3c9);
			outb(i, 0x3c9);
			outb(i << 1, 0x3c9);
		}
		break;
	case 24:
#ifdef NO_32BIT_SUPPORT_YET
	case 32:
#endif
		/* TrueColor, 16m */
		info->fix.visual = FB_VISUAL_TRUECOLOR;

		for (i = 0; i < 256; i++) {
			outb(i, 0x3c8);

			outb(i, 0x3c9);
			outb(i, 0x3c9);
			outb(i, 0x3c9);
		}
		break;
	}

	vga_wgfx(NULL, 0x0E, par->ExtCRTDispAddr);
	vga_wgfx(NULL, 0x0F, par->ExtCRTOffset);
	temp = vga_rgfx(NULL, 0x10);
	temp &= 0x0F;		/* Save bits 3:0 */
	temp |= (par->SysIfaceCntl1 & ~0x0F);	/* VESA Bios sets bit 1! */
	vga_wgfx(NULL, 0x10, temp);

	vga_wgfx(NULL, 0x11, par->SysIfaceCntl2);
	vga_wgfx(NULL, 0x15, 0 /*par->SingleAddrPage */ );
	vga_wgfx(NULL, 0x16, 0 /*par->DualAddrPage */ );

	temp = vga_rgfx(NULL, 0x20);
	switch (info->fix.accel) {
	case FB_ACCEL_NEOMAGIC_NM2070:
		temp &= 0xFC;	/* Save bits 7:2 */
		temp |= (par->PanelDispCntlReg1 & ~0xFC);
		break;
	case FB_ACCEL_NEOMAGIC_NM2090:
	case FB_ACCEL_NEOMAGIC_NM2093:
	case FB_ACCEL_NEOMAGIC_NM2097:
	case FB_ACCEL_NEOMAGIC_NM2160:
		temp &= 0xDC;	/* Save bits 7:6,4:2 */
		temp |= (par->PanelDispCntlReg1 & ~0xDC);
		break;
	case FB_ACCEL_NEOMAGIC_NM2200:
	case FB_ACCEL_NEOMAGIC_NM2230:
	case FB_ACCEL_NEOMAGIC_NM2360:
	case FB_ACCEL_NEOMAGIC_NM2380:
		temp &= 0x98;	/* Save bits 7,4:3 */
		temp |= (par->PanelDispCntlReg1 & ~0x98);
		break;
	}
	vga_wgfx(NULL, 0x20, temp);

	temp = vga_rgfx(NULL, 0x25);
	temp &= 0x38;		/* Save bits 5:3 */
	temp |= (par->PanelDispCntlReg2 & ~0x38);
	vga_wgfx(NULL, 0x25, temp);

	if (info->fix.accel != FB_ACCEL_NEOMAGIC_NM2070) {
		temp = vga_rgfx(NULL, 0x30);
		temp &= 0xEF;	/* Save bits 7:5 and bits 3:0 */
		temp |= (par->PanelDispCntlReg3 & ~0xEF);
		vga_wgfx(NULL, 0x30, temp);
	}

	vga_wgfx(NULL, 0x28, par->PanelVertCenterReg1);
	vga_wgfx(NULL, 0x29, par->PanelVertCenterReg2);
	vga_wgfx(NULL, 0x2a, par->PanelVertCenterReg3);

	if (info->fix.accel != FB_ACCEL_NEOMAGIC_NM2070) {
		vga_wgfx(NULL, 0x32, par->PanelVertCenterReg4);
		vga_wgfx(NULL, 0x33, par->PanelHorizCenterReg1);
		vga_wgfx(NULL, 0x34, par->PanelHorizCenterReg2);
		vga_wgfx(NULL, 0x35, par->PanelHorizCenterReg3);
	}

	if (info->fix.accel == FB_ACCEL_NEOMAGIC_NM2160)
		vga_wgfx(NULL, 0x36, par->PanelHorizCenterReg4);

	if (info->fix.accel == FB_ACCEL_NEOMAGIC_NM2200 ||
	    info->fix.accel == FB_ACCEL_NEOMAGIC_NM2230 ||
	    info->fix.accel == FB_ACCEL_NEOMAGIC_NM2360 ||
	    info->fix.accel == FB_ACCEL_NEOMAGIC_NM2380) {
		vga_wgfx(NULL, 0x36, par->PanelHorizCenterReg4);
		vga_wgfx(NULL, 0x37, par->PanelVertCenterReg5);
		vga_wgfx(NULL, 0x38, par->PanelHorizCenterReg5);

		clock_hi = 1;
	}

	/* Program VCLK3 if needed. */
	if (par->ProgramVCLK && ((vga_rgfx(NULL, 0x9B) != par->VCLK3NumeratorLow)
				 || (vga_rgfx(NULL, 0x9F) != par->VCLK3Denominator)
				 || (clock_hi && ((vga_rgfx(NULL, 0x8F) & ~0x0f)
						  != (par->VCLK3NumeratorHigh &
						      ~0x0F))))) {
		vga_wgfx(NULL, 0x9B, par->VCLK3NumeratorLow);
		if (clock_hi) {
			temp = vga_rgfx(NULL, 0x8F);
			temp &= 0x0F;	/* Save bits 3:0 */
			temp |= (par->VCLK3NumeratorHigh & ~0x0F);
			vga_wgfx(NULL, 0x8F, temp);
		}
		vga_wgfx(NULL, 0x9F, par->VCLK3Denominator);
	}

	if (par->biosMode)
		vga_wcrt(NULL, 0x23, par->biosMode);

	vga_wgfx(NULL, 0x93, 0xc0);	/* Gives 5x faster framebuffer writes !!! */

	/* Program vertical extension register */
	if (info->fix.accel == FB_ACCEL_NEOMAGIC_NM2200 ||
	    info->fix.accel == FB_ACCEL_NEOMAGIC_NM2230 ||
	    info->fix.accel == FB_ACCEL_NEOMAGIC_NM2360 ||
	    info->fix.accel == FB_ACCEL_NEOMAGIC_NM2380) {
		vga_wcrt(NULL, 0x70, par->VerticalExt);
	}

	vgaHWProtect(0);	/* Turn on screen */

	/* Calling this also locks offset registers required in update_start */
	neoLock(&par->state);

	info->fix.line_length =
	    info->var.xres_virtual * (info->var.bits_per_pixel >> 3);

	switch (info->fix.accel) {
		case FB_ACCEL_NEOMAGIC_NM2200:
		case FB_ACCEL_NEOMAGIC_NM2230: 
		case FB_ACCEL_NEOMAGIC_NM2360: 
		case FB_ACCEL_NEOMAGIC_NM2380: 
			neo2200_accel_init(info, &info->var);
			break;
		default:
			break;
	}	
	return 0;
}