brintos

brintos / linux-shallow public Read only

0
0
Text · 54.9 KiB · 632ba24 Raw
2228 lines · c
1/*2 * linux/drivers/video/neofb.c -- NeoMagic Framebuffer Driver3 *4 * Copyright (c) 2001-2002  Denis Oliver Kropp <dok@directfb.org>5 *6 *7 * Card specific code is based on XFree86's neomagic driver.8 * Framebuffer framework code is based on code of cyber2000fb.9 *10 * This file is subject to the terms and conditions of the GNU General11 * Public License.  See the file COPYING in the main directory of this12 * archive for more details.13 *14 *15 * 0.4.116 *  - Cosmetic changes (dok)17 *18 * 0.419 *  - Toshiba Libretto support, allow modes larger than LCD size if20 *    LCD is disabled, keep BIOS settings if internal/external display21 *    haven't been enabled explicitly22 *                          (Thomas J. Moore <dark@mama.indstate.edu>)23 *24 * 0.3.325 *  - Porting over to new fbdev api. (jsimmons)26 *27 * 0.3.228 *  - got rid of all floating point (dok)29 *30 * 0.3.131 *  - added module license (dok)32 *33 * 0.334 *  - hardware accelerated clear and move for 2200 and above (dok)35 *  - maximum allowed dotclock is handled now (dok)36 *37 * 0.2.138 *  - correct panning after X usage (dok)39 *  - added module and kernel parameters (dok)40 *  - no stretching if external display is enabled (dok)41 *42 * 0.243 *  - initial version (dok)44 *45 *46 * TODO47 * - ioctl for internal/external switching48 * - blanking49 * - 32bit depth support, maybe impossible50 * - disable pan-on-sync, need specs51 *52 * BUGS53 * - white margin on bootup like with tdfxfb (colormap problem?)54 *55 */56 57#include <linux/aperture.h>58#include <linux/module.h>59#include <linux/kernel.h>60#include <linux/errno.h>61#include <linux/string.h>62#include <linux/mm.h>63#include <linux/slab.h>64#include <linux/delay.h>65#include <linux/fb.h>66#include <linux/pci.h>67#include <linux/init.h>68#ifdef CONFIG_TOSHIBA69#include <linux/toshiba.h>70#endif71 72#include <asm/io.h>73#include <asm/irq.h>74#include <video/vga.h>75#include <video/neomagic.h>76 77#define NEOFB_VERSION "0.4.2"78 79/* --------------------------------------------------------------------- */80 81static bool internal;82static bool external;83static bool libretto;84static bool nostretch;85static bool nopciburst;86static char *mode_option = NULL;87 88#ifdef MODULE89 90MODULE_AUTHOR("(c) 2001-2002  Denis Oliver Kropp <dok@convergence.de>");91MODULE_LICENSE("GPL");92MODULE_DESCRIPTION("FBDev driver for NeoMagic PCI Chips");93module_param(internal, bool, 0);94MODULE_PARM_DESC(internal, "Enable output on internal LCD Display.");95module_param(external, bool, 0);96MODULE_PARM_DESC(external, "Enable output on external CRT.");97module_param(libretto, bool, 0);98MODULE_PARM_DESC(libretto, "Force Libretto 100/110 800x480 LCD.");99module_param(nostretch, bool, 0);100MODULE_PARM_DESC(nostretch,101		 "Disable stretching of modes smaller than LCD.");102module_param(nopciburst, bool, 0);103MODULE_PARM_DESC(nopciburst, "Disable PCI burst mode.");104module_param(mode_option, charp, 0);105MODULE_PARM_DESC(mode_option, "Preferred video mode ('640x480-8@60', etc)");106 107#endif108 109 110/* --------------------------------------------------------------------- */111 112static biosMode bios8[] = {113	{320, 240, 0x40},114	{300, 400, 0x42},115	{640, 400, 0x20},116	{640, 480, 0x21},117	{800, 600, 0x23},118	{1024, 768, 0x25},119};120 121static biosMode bios16[] = {122	{320, 200, 0x2e},123	{320, 240, 0x41},124	{300, 400, 0x43},125	{640, 480, 0x31},126	{800, 600, 0x34},127	{1024, 768, 0x37},128};129 130static biosMode bios24[] = {131	{640, 480, 0x32},132	{800, 600, 0x35},133	{1024, 768, 0x38}134};135 136#ifdef NO_32BIT_SUPPORT_YET137/* FIXME: guessed values, wrong */138static biosMode bios32[] = {139	{640, 480, 0x33},140	{800, 600, 0x36},141	{1024, 768, 0x39}142};143#endif144 145static inline void write_le32(int regindex, u32 val, const struct neofb_par *par)146{147	writel(val, par->neo2200 + par->cursorOff + regindex);148}149 150static int neoFindMode(int xres, int yres, int depth)151{152	int xres_s;153	int i, size;154	biosMode *mode;155 156	switch (depth) {157	case 8:158		size = ARRAY_SIZE(bios8);159		mode = bios8;160		break;161	case 16:162		size = ARRAY_SIZE(bios16);163		mode = bios16;164		break;165	case 24:166		size = ARRAY_SIZE(bios24);167		mode = bios24;168		break;169#ifdef NO_32BIT_SUPPORT_YET170	case 32:171		size = ARRAY_SIZE(bios32);172		mode = bios32;173		break;174#endif175	default:176		return 0;177	}178 179	for (i = 0; i < size; i++) {180		if (xres <= mode[i].x_res) {181			xres_s = mode[i].x_res;182			for (; i < size; i++) {183				if (mode[i].x_res != xres_s)184					return mode[i - 1].mode;185				if (yres <= mode[i].y_res)186					return mode[i].mode;187			}188		}189	}190	return mode[size - 1].mode;191}192 193/*194 * neoCalcVCLK --195 *196 * Determine the closest clock frequency to the one requested.197 */198#define MAX_N 127199#define MAX_D 31200#define MAX_F 1201 202static void neoCalcVCLK(const struct fb_info *info,203			struct neofb_par *par, long freq)204{205	int n, d, f;206	int n_best = 0, d_best = 0, f_best = 0;207	long f_best_diff = 0x7ffff;208 209	for (f = 0; f <= MAX_F; f++)210		for (d = 0; d <= MAX_D; d++)211			for (n = 0; n <= MAX_N; n++) {212				long f_out;213				long f_diff;214 215				f_out = ((14318 * (n + 1)) / (d + 1)) >> f;216				f_diff = abs(f_out - freq);217				if (f_diff <= f_best_diff) {218					f_best_diff = f_diff;219					n_best = n;220					d_best = d;221					f_best = f;222				}223				if (f_out > freq)224					break;225			}226 227	if (info->fix.accel == FB_ACCEL_NEOMAGIC_NM2200 ||228	    info->fix.accel == FB_ACCEL_NEOMAGIC_NM2230 ||229	    info->fix.accel == FB_ACCEL_NEOMAGIC_NM2360 ||230	    info->fix.accel == FB_ACCEL_NEOMAGIC_NM2380) {231		/* NOT_DONE:  We are trying the full range of the 2200 clock.232		   We should be able to try n up to 2047 */233		par->VCLK3NumeratorLow = n_best;234		par->VCLK3NumeratorHigh = (f_best << 7);235	} else236		par->VCLK3NumeratorLow = n_best | (f_best << 7);237 238	par->VCLK3Denominator = d_best;239 240#ifdef NEOFB_DEBUG241	printk(KERN_DEBUG "neoVCLK: f:%ld NumLow=%d NumHi=%d Den=%d Df=%ld\n",242	       freq,243	       par->VCLK3NumeratorLow,244	       par->VCLK3NumeratorHigh,245	       par->VCLK3Denominator, f_best_diff);246#endif247}248 249/*250 * vgaHWInit --251 *      Handle the initialization, etc. of a screen.252 *      Return FALSE on failure.253 */254 255static int vgaHWInit(const struct fb_var_screeninfo *var,256		     struct neofb_par *par)257{258	int hsync_end = var->xres + var->right_margin + var->hsync_len;259	int htotal = (hsync_end + var->left_margin) >> 3;260	int vsync_start = var->yres + var->lower_margin;261	int vsync_end = vsync_start + var->vsync_len;262	int vtotal = vsync_end + var->upper_margin;263 264	par->MiscOutReg = 0x23;265 266	if (!(var->sync & FB_SYNC_HOR_HIGH_ACT))267		par->MiscOutReg |= 0x40;268 269	if (!(var->sync & FB_SYNC_VERT_HIGH_ACT))270		par->MiscOutReg |= 0x80;271 272	/*273	 * Time Sequencer274	 */275	par->Sequencer[0] = 0x00;276	par->Sequencer[1] = 0x01;277	par->Sequencer[2] = 0x0F;278	par->Sequencer[3] = 0x00;	/* Font select */279	par->Sequencer[4] = 0x0E;	/* Misc */280 281	/*282	 * CRTC Controller283	 */284	par->CRTC[0] = htotal - 5;285	par->CRTC[1] = (var->xres >> 3) - 1;286	par->CRTC[2] = (var->xres >> 3) - 1;287	par->CRTC[3] = ((htotal - 1) & 0x1F) | 0x80;288	par->CRTC[4] = ((var->xres + var->right_margin) >> 3);289	par->CRTC[5] = (((htotal - 1) & 0x20) << 2)290	    | (((hsync_end >> 3)) & 0x1F);291	par->CRTC[6] = (vtotal - 2) & 0xFF;292	par->CRTC[7] = (((vtotal - 2) & 0x100) >> 8)293	    | (((var->yres - 1) & 0x100) >> 7)294	    | ((vsync_start & 0x100) >> 6)295	    | (((var->yres - 1) & 0x100) >> 5)296	    | 0x10 | (((vtotal - 2) & 0x200) >> 4)297	    | (((var->yres - 1) & 0x200) >> 3)298	    | ((vsync_start & 0x200) >> 2);299	par->CRTC[8] = 0x00;300	par->CRTC[9] = (((var->yres - 1) & 0x200) >> 4) | 0x40;301 302	if (var->vmode & FB_VMODE_DOUBLE)303		par->CRTC[9] |= 0x80;304 305	par->CRTC[10] = 0x00;306	par->CRTC[11] = 0x00;307	par->CRTC[12] = 0x00;308	par->CRTC[13] = 0x00;309	par->CRTC[14] = 0x00;310	par->CRTC[15] = 0x00;311	par->CRTC[16] = vsync_start & 0xFF;312	par->CRTC[17] = (vsync_end & 0x0F) | 0x20;313	par->CRTC[18] = (var->yres - 1) & 0xFF;314	par->CRTC[19] = var->xres_virtual >> 4;315	par->CRTC[20] = 0x00;316	par->CRTC[21] = (var->yres - 1) & 0xFF;317	par->CRTC[22] = (vtotal - 1) & 0xFF;318	par->CRTC[23] = 0xC3;319	par->CRTC[24] = 0xFF;320 321	/*322	 * are these unnecessary?323	 * vgaHWHBlankKGA(mode, regp, 0, KGA_FIX_OVERSCAN | KGA_ENABLE_ON_ZERO);324	 * vgaHWVBlankKGA(mode, regp, 0, KGA_FIX_OVERSCAN | KGA_ENABLE_ON_ZERO);325	 */326 327	/*328	 * Graphics Display Controller329	 */330	par->Graphics[0] = 0x00;331	par->Graphics[1] = 0x00;332	par->Graphics[2] = 0x00;333	par->Graphics[3] = 0x00;334	par->Graphics[4] = 0x00;335	par->Graphics[5] = 0x40;336	par->Graphics[6] = 0x05;	/* only map 64k VGA memory !!!! */337	par->Graphics[7] = 0x0F;338	par->Graphics[8] = 0xFF;339 340 341	par->Attribute[0] = 0x00;	/* standard colormap translation */342	par->Attribute[1] = 0x01;343	par->Attribute[2] = 0x02;344	par->Attribute[3] = 0x03;345	par->Attribute[4] = 0x04;346	par->Attribute[5] = 0x05;347	par->Attribute[6] = 0x06;348	par->Attribute[7] = 0x07;349	par->Attribute[8] = 0x08;350	par->Attribute[9] = 0x09;351	par->Attribute[10] = 0x0A;352	par->Attribute[11] = 0x0B;353	par->Attribute[12] = 0x0C;354	par->Attribute[13] = 0x0D;355	par->Attribute[14] = 0x0E;356	par->Attribute[15] = 0x0F;357	par->Attribute[16] = 0x41;358	par->Attribute[17] = 0xFF;359	par->Attribute[18] = 0x0F;360	par->Attribute[19] = 0x00;361	par->Attribute[20] = 0x00;362	return 0;363}364 365static void vgaHWLock(struct vgastate *state)366{367	/* Protect CRTC[0-7] */368	vga_wcrt(state->vgabase, 0x11, vga_rcrt(state->vgabase, 0x11) | 0x80);369}370 371static void vgaHWUnlock(void)372{373	/* Unprotect CRTC[0-7] */374	vga_wcrt(NULL, 0x11, vga_rcrt(NULL, 0x11) & ~0x80);375}376 377static void neoLock(struct vgastate *state)378{379	vga_wgfx(state->vgabase, 0x09, 0x00);380	vgaHWLock(state);381}382 383static void neoUnlock(void)384{385	vgaHWUnlock();386	vga_wgfx(NULL, 0x09, 0x26);387}388 389/*390 * VGA Palette management391 */392static int paletteEnabled = 0;393 394static inline void VGAenablePalette(void)395{396	vga_r(NULL, VGA_IS1_RC);397	vga_w(NULL, VGA_ATT_W, 0x00);398	paletteEnabled = 1;399}400 401static inline void VGAdisablePalette(void)402{403	vga_r(NULL, VGA_IS1_RC);404	vga_w(NULL, VGA_ATT_W, 0x20);405	paletteEnabled = 0;406}407 408static inline void VGAwATTR(u8 index, u8 value)409{410	if (paletteEnabled)411		index &= ~0x20;412	else413		index |= 0x20;414 415	vga_r(NULL, VGA_IS1_RC);416	vga_wattr(NULL, index, value);417}418 419static void vgaHWProtect(int on)420{421	unsigned char tmp;422 423	tmp = vga_rseq(NULL, 0x01);424	if (on) {425		/*426		 * Turn off screen and disable sequencer.427		 */428		vga_wseq(NULL, 0x00, 0x01);		/* Synchronous Reset */429		vga_wseq(NULL, 0x01, tmp | 0x20);	/* disable the display */430 431		VGAenablePalette();432	} else {433		/*434		 * Reenable sequencer, then turn on screen.435		 */436		vga_wseq(NULL, 0x01, tmp & ~0x20);	/* reenable display */437		vga_wseq(NULL, 0x00, 0x03);		/* clear synchronousreset */438 439		VGAdisablePalette();440	}441}442 443static void vgaHWRestore(const struct fb_info *info,444			 const struct neofb_par *par)445{446	int i;447 448	vga_w(NULL, VGA_MIS_W, par->MiscOutReg);449 450	for (i = 1; i < 5; i++)451		vga_wseq(NULL, i, par->Sequencer[i]);452 453	/* Ensure CRTC registers 0-7 are unlocked by clearing bit 7 or CRTC[17] */454	vga_wcrt(NULL, 17, par->CRTC[17] & ~0x80);455 456	for (i = 0; i < 25; i++)457		vga_wcrt(NULL, i, par->CRTC[i]);458 459	for (i = 0; i < 9; i++)460		vga_wgfx(NULL, i, par->Graphics[i]);461 462	VGAenablePalette();463 464	for (i = 0; i < 21; i++)465		VGAwATTR(i, par->Attribute[i]);466 467	VGAdisablePalette();468}469 470 471/* -------------------- Hardware specific routines ------------------------- */472 473/*474 * Hardware Acceleration for Neo2200+475 */476static inline int neo2200_sync(struct fb_info *info)477{478	struct neofb_par *par = info->par;479 480	while (readl(&par->neo2200->bltStat) & 1)481		cpu_relax();482	return 0;483}484 485static inline void neo2200_wait_fifo(struct fb_info *info,486				     int requested_fifo_space)487{488	//  ndev->neo.waitfifo_calls++;489	//  ndev->neo.waitfifo_sum += requested_fifo_space;490 491	/* FIXME: does not work492	   if (neo_fifo_space < requested_fifo_space)493	   {494	   neo_fifo_waitcycles++;495 496	   while (1)497	   {498	   neo_fifo_space = (neo2200->bltStat >> 8);499	   if (neo_fifo_space >= requested_fifo_space)500	   break;501	   }502	   }503	   else504	   {505	   neo_fifo_cache_hits++;506	   }507 508	   neo_fifo_space -= requested_fifo_space;509	 */510 511	neo2200_sync(info);512}513 514static inline void neo2200_accel_init(struct fb_info *info,515				      struct fb_var_screeninfo *var)516{517	struct neofb_par *par = info->par;518	Neo2200 __iomem *neo2200 = par->neo2200;519	u32 bltMod, pitch;520 521	neo2200_sync(info);522 523	switch (var->bits_per_pixel) {524	case 8:525		bltMod = NEO_MODE1_DEPTH8;526		pitch = var->xres_virtual;527		break;528	case 15:529	case 16:530		bltMod = NEO_MODE1_DEPTH16;531		pitch = var->xres_virtual * 2;532		break;533	case 24:534		bltMod = NEO_MODE1_DEPTH24;535		pitch = var->xres_virtual * 3;536		break;537	default:538		printk(KERN_ERR539		       "neofb: neo2200_accel_init: unexpected bits per pixel!\n");540		return;541	}542 543	writel(bltMod << 16, &neo2200->bltStat);544	writel((pitch << 16) | pitch, &neo2200->pitch);545}546 547/* --------------------------------------------------------------------- */548 549static int550neofb_open(struct fb_info *info, int user)551{552	struct neofb_par *par = info->par;553 554	if (!par->ref_count) {555		memset(&par->state, 0, sizeof(struct vgastate));556		par->state.flags = VGA_SAVE_MODE | VGA_SAVE_FONTS;557		save_vga(&par->state);558	}559	par->ref_count++;560 561	return 0;562}563 564static int565neofb_release(struct fb_info *info, int user)566{567	struct neofb_par *par = info->par;568 569	if (!par->ref_count)570		return -EINVAL;571 572	if (par->ref_count == 1) {573		restore_vga(&par->state);574	}575	par->ref_count--;576 577	return 0;578}579 580static int581neofb_check_var(struct fb_var_screeninfo *var, struct fb_info *info)582{583	struct neofb_par *par = info->par;584	int memlen, vramlen;585	int mode_ok = 0;586 587	DBG("neofb_check_var");588 589	if (!var->pixclock || PICOS2KHZ(var->pixclock) > par->maxClock)590		return -EINVAL;591 592	/* Is the mode larger than the LCD panel? */593	if (par->internal_display &&594            ((var->xres > par->NeoPanelWidth) ||595	     (var->yres > par->NeoPanelHeight))) {596		printk(KERN_INFO597		       "Mode (%dx%d) larger than the LCD panel (%dx%d)\n",598		       var->xres, var->yres, par->NeoPanelWidth,599		       par->NeoPanelHeight);600		return -EINVAL;601	}602 603	/* Is the mode one of the acceptable sizes? */604	if (!par->internal_display)605		mode_ok = 1;606	else {607		switch (var->xres) {608		case 1280:609			if (var->yres == 1024)610				mode_ok = 1;611			break;612		case 1024:613			if (var->yres == 768)614				mode_ok = 1;615			break;616		case 800:617			if (var->yres == (par->libretto ? 480 : 600))618				mode_ok = 1;619			break;620		case 640:621			if (var->yres == 480)622				mode_ok = 1;623			break;624		}625	}626 627	if (!mode_ok) {628		printk(KERN_INFO629		       "Mode (%dx%d) won't display properly on LCD\n",630		       var->xres, var->yres);631		return -EINVAL;632	}633 634	var->red.msb_right = 0;635	var->green.msb_right = 0;636	var->blue.msb_right = 0;637	var->transp.msb_right = 0;638 639	var->transp.offset = 0;640	var->transp.length = 0;641	switch (var->bits_per_pixel) {642	case 8:		/* PSEUDOCOLOUR, 256 */643		var->red.offset = 0;644		var->red.length = 8;645		var->green.offset = 0;646		var->green.length = 8;647		var->blue.offset = 0;648		var->blue.length = 8;649		break;650 651	case 16:		/* DIRECTCOLOUR, 64k */652		var->red.offset = 11;653		var->red.length = 5;654		var->green.offset = 5;655		var->green.length = 6;656		var->blue.offset = 0;657		var->blue.length = 5;658		break;659 660	case 24:		/* TRUECOLOUR, 16m */661		var->red.offset = 16;662		var->red.length = 8;663		var->green.offset = 8;664		var->green.length = 8;665		var->blue.offset = 0;666		var->blue.length = 8;667		break;668 669#ifdef NO_32BIT_SUPPORT_YET670	case 32:		/* TRUECOLOUR, 16m */671		var->transp.offset = 24;672		var->transp.length = 8;673		var->red.offset = 16;674		var->red.length = 8;675		var->green.offset = 8;676		var->green.length = 8;677		var->blue.offset = 0;678		var->blue.length = 8;679		break;680#endif681	default:682		printk(KERN_WARNING "neofb: no support for %dbpp\n",683		       var->bits_per_pixel);684		return -EINVAL;685	}686 687	vramlen = info->fix.smem_len;688	if (vramlen > 4 * 1024 * 1024)689		vramlen = 4 * 1024 * 1024;690 691	if (var->xres_virtual < var->xres)692		var->xres_virtual = var->xres;693 694	memlen = var->xres_virtual * var->bits_per_pixel * var->yres_virtual >> 3;695 696	if (memlen > vramlen) {697		var->yres_virtual =  vramlen * 8 / (var->xres_virtual *698				   	var->bits_per_pixel);699		memlen = var->xres_virtual * var->bits_per_pixel *700				var->yres_virtual / 8;701	}702 703	/* we must round yres/xres down, we already rounded y/xres_virtual up704	   if it was possible. We should return -EINVAL, but I disagree */705	if (var->yres_virtual < var->yres)706		var->yres = var->yres_virtual;707	if (var->xoffset + var->xres > var->xres_virtual)708		var->xoffset = var->xres_virtual - var->xres;709	if (var->yoffset + var->yres > var->yres_virtual)710		var->yoffset = var->yres_virtual - var->yres;711 712	var->nonstd = 0;713	var->height = -1;714	var->width = -1;715 716	if (var->bits_per_pixel >= 24 || !par->neo2200)717		var->accel_flags &= ~FB_ACCELF_TEXT;718	return 0;719}720 721static int neofb_set_par(struct fb_info *info)722{723	struct neofb_par *par = info->par;724	unsigned char temp;725	int i, clock_hi = 0;726	int lcd_stretch;727	int hoffset, voffset;728	int vsync_start, vtotal;729 730	DBG("neofb_set_par");731 732	neoUnlock();733 734	vgaHWProtect(1);	/* Blank the screen */735 736	vsync_start = info->var.yres + info->var.lower_margin;737	vtotal = vsync_start + info->var.vsync_len + info->var.upper_margin;738 739	/*740	 * This will allocate the datastructure and initialize all of the741	 * generic VGA registers.742	 */743 744	if (vgaHWInit(&info->var, par))745		return -EINVAL;746 747	/*748	 * The default value assigned by vgaHW.c is 0x41, but this does749	 * not work for NeoMagic.750	 */751	par->Attribute[16] = 0x01;752 753	switch (info->var.bits_per_pixel) {754	case 8:755		par->CRTC[0x13] = info->var.xres_virtual >> 3;756		par->ExtCRTOffset = info->var.xres_virtual >> 11;757		par->ExtColorModeSelect = 0x11;758		break;759	case 16:760		par->CRTC[0x13] = info->var.xres_virtual >> 2;761		par->ExtCRTOffset = info->var.xres_virtual >> 10;762		par->ExtColorModeSelect = 0x13;763		break;764	case 24:765		par->CRTC[0x13] = (info->var.xres_virtual * 3) >> 3;766		par->ExtCRTOffset = (info->var.xres_virtual * 3) >> 11;767		par->ExtColorModeSelect = 0x14;768		break;769#ifdef NO_32BIT_SUPPORT_YET770	case 32:		/* FIXME: guessed values */771		par->CRTC[0x13] = info->var.xres_virtual >> 1;772		par->ExtCRTOffset = info->var.xres_virtual >> 9;773		par->ExtColorModeSelect = 0x15;774		break;775#endif776	default:777		break;778	}779 780	par->ExtCRTDispAddr = 0x10;781 782	/* Vertical Extension */783	par->VerticalExt = (((vtotal - 2) & 0x400) >> 10)784	    | (((info->var.yres - 1) & 0x400) >> 9)785	    | (((vsync_start) & 0x400) >> 8)786	    | (((vsync_start) & 0x400) >> 7);787 788	/* Fast write bursts on unless disabled. */789	if (par->pci_burst)790		par->SysIfaceCntl1 = 0x30;791	else792		par->SysIfaceCntl1 = 0x00;793 794	par->SysIfaceCntl2 = 0xc0;	/* VESA Bios sets this to 0x80! */795 796	/* Initialize: by default, we want display config register to be read */797	par->PanelDispCntlRegRead = 1;798 799	/* Enable any user specified display devices. */800	par->PanelDispCntlReg1 = 0x00;801	if (par->internal_display)802		par->PanelDispCntlReg1 |= 0x02;803	if (par->external_display)804		par->PanelDispCntlReg1 |= 0x01;805 806	/* If the user did not specify any display devices, then... */807	if (par->PanelDispCntlReg1 == 0x00) {808		/* Default to internal (i.e., LCD) only. */809		par->PanelDispCntlReg1 = vga_rgfx(NULL, 0x20) & 0x03;810	}811 812	/* If we are using a fixed mode, then tell the chip we are. */813	switch (info->var.xres) {814	case 1280:815		par->PanelDispCntlReg1 |= 0x60;816		break;817	case 1024:818		par->PanelDispCntlReg1 |= 0x40;819		break;820	case 800:821		par->PanelDispCntlReg1 |= 0x20;822		break;823	case 640:824	default:825		break;826	}827 828	/* Setup shadow register locking. */829	switch (par->PanelDispCntlReg1 & 0x03) {830	case 0x01:		/* External CRT only mode: */831		par->GeneralLockReg = 0x00;832		/* We need to program the VCLK for external display only mode. */833		par->ProgramVCLK = 1;834		break;835	case 0x02:		/* Internal LCD only mode: */836	case 0x03:		/* Simultaneous internal/external (LCD/CRT) mode: */837		par->GeneralLockReg = 0x01;838		/* Don't program the VCLK when using the LCD. */839		par->ProgramVCLK = 0;840		break;841	}842 843	/*844	 * If the screen is to be stretched, turn on stretching for the845	 * various modes.846	 *847	 * OPTION_LCD_STRETCH means stretching should be turned off!848	 */849	par->PanelDispCntlReg2 = 0x00;850	par->PanelDispCntlReg3 = 0x00;851 852	if (par->lcd_stretch && (par->PanelDispCntlReg1 == 0x02) &&	/* LCD only */853	    (info->var.xres != par->NeoPanelWidth)) {854		switch (info->var.xres) {855		case 320:	/* Needs testing.  KEM -- 24 May 98 */856		case 400:	/* Needs testing.  KEM -- 24 May 98 */857		case 640:858		case 800:859		case 1024:860			lcd_stretch = 1;861			par->PanelDispCntlReg2 |= 0xC6;862			break;863		default:864			lcd_stretch = 0;865			/* No stretching in these modes. */866		}867	} else868		lcd_stretch = 0;869 870	/*871	 * If the screen is to be centerd, turn on the centering for the872	 * various modes.873	 */874	par->PanelVertCenterReg1 = 0x00;875	par->PanelVertCenterReg2 = 0x00;876	par->PanelVertCenterReg3 = 0x00;877	par->PanelVertCenterReg4 = 0x00;878	par->PanelVertCenterReg5 = 0x00;879	par->PanelHorizCenterReg1 = 0x00;880	par->PanelHorizCenterReg2 = 0x00;881	par->PanelHorizCenterReg3 = 0x00;882	par->PanelHorizCenterReg4 = 0x00;883	par->PanelHorizCenterReg5 = 0x00;884 885 886	if (par->PanelDispCntlReg1 & 0x02) {887		if (info->var.xres == par->NeoPanelWidth) {888			/*889			 * No centering required when the requested display width890			 * equals the panel width.891			 */892		} else {893			par->PanelDispCntlReg2 |= 0x01;894			par->PanelDispCntlReg3 |= 0x10;895 896			/* Calculate the horizontal and vertical offsets. */897			if (!lcd_stretch) {898				hoffset =899				    ((par->NeoPanelWidth -900				      info->var.xres) >> 4) - 1;901				voffset =902				    ((par->NeoPanelHeight -903				      info->var.yres) >> 1) - 2;904			} else {905				/* Stretched modes cannot be centered. */906				hoffset = 0;907				voffset = 0;908			}909 910			switch (info->var.xres) {911			case 320:	/* Needs testing.  KEM -- 24 May 98 */912				par->PanelHorizCenterReg3 = hoffset;913				par->PanelVertCenterReg2 = voffset;914				break;915			case 400:	/* Needs testing.  KEM -- 24 May 98 */916				par->PanelHorizCenterReg4 = hoffset;917				par->PanelVertCenterReg1 = voffset;918				break;919			case 640:920				par->PanelHorizCenterReg1 = hoffset;921				par->PanelVertCenterReg3 = voffset;922				break;923			case 800:924				par->PanelHorizCenterReg2 = hoffset;925				par->PanelVertCenterReg4 = voffset;926				break;927			case 1024:928				par->PanelHorizCenterReg5 = hoffset;929				par->PanelVertCenterReg5 = voffset;930				break;931			case 1280:932			default:933				/* No centering in these modes. */934				break;935			}936		}937	}938 939	par->biosMode =940	    neoFindMode(info->var.xres, info->var.yres,941			info->var.bits_per_pixel);942 943	/*944	 * Calculate the VCLK that most closely matches the requested dot945	 * clock.946	 */947	neoCalcVCLK(info, par, PICOS2KHZ(info->var.pixclock));948 949	/* Since we program the clocks ourselves, always use VCLK3. */950	par->MiscOutReg |= 0x0C;951 952	/* alread unlocked above */953	/* BOGUS  vga_wgfx(NULL, 0x09, 0x26); */954 955	/* don't know what this is, but it's 0 from bootup anyway */956	vga_wgfx(NULL, 0x15, 0x00);957 958	/* was set to 0x01 by my bios in text and vesa modes */959	vga_wgfx(NULL, 0x0A, par->GeneralLockReg);960 961	/*962	 * The color mode needs to be set before calling vgaHWRestore963	 * to ensure the DAC is initialized properly.964	 *965	 * NOTE: Make sure we don't change bits make sure we don't change966	 * any reserved bits.967	 */968	temp = vga_rgfx(NULL, 0x90);969	switch (info->fix.accel) {970	case FB_ACCEL_NEOMAGIC_NM2070:971		temp &= 0xF0;	/* Save bits 7:4 */972		temp |= (par->ExtColorModeSelect & ~0xF0);973		break;974	case FB_ACCEL_NEOMAGIC_NM2090:975	case FB_ACCEL_NEOMAGIC_NM2093:976	case FB_ACCEL_NEOMAGIC_NM2097:977	case FB_ACCEL_NEOMAGIC_NM2160:978	case FB_ACCEL_NEOMAGIC_NM2200:979	case FB_ACCEL_NEOMAGIC_NM2230:980	case FB_ACCEL_NEOMAGIC_NM2360:981	case FB_ACCEL_NEOMAGIC_NM2380:982		temp &= 0x70;	/* Save bits 6:4 */983		temp |= (par->ExtColorModeSelect & ~0x70);984		break;985	}986 987	vga_wgfx(NULL, 0x90, temp);988 989	/*990	 * In some rare cases a lockup might occur if we don't delay991	 * here. (Reported by Miles Lane)992	 */993	//mdelay(200);994 995	/*996	 * Disable horizontal and vertical graphics and text expansions so997	 * that vgaHWRestore works properly.998	 */999	temp = vga_rgfx(NULL, 0x25);1000	temp &= 0x39;1001	vga_wgfx(NULL, 0x25, temp);1002 1003	/*1004	 * Sleep for 200ms to make sure that the two operations above have1005	 * had time to take effect.1006	 */1007	mdelay(200);1008 1009	/*1010	 * This function handles restoring the generic VGA registers.  */1011	vgaHWRestore(info, par);1012 1013	/* linear colormap for non palettized modes */1014	switch (info->var.bits_per_pixel) {1015	case 8:1016		/* PseudoColor, 256 */1017		info->fix.visual = FB_VISUAL_PSEUDOCOLOR;1018		break;1019	case 16:1020		/* TrueColor, 64k */1021		info->fix.visual = FB_VISUAL_TRUECOLOR;1022 1023		for (i = 0; i < 64; i++) {1024			outb(i, 0x3c8);1025 1026			outb(i << 1, 0x3c9);1027			outb(i, 0x3c9);1028			outb(i << 1, 0x3c9);1029		}1030		break;1031	case 24:1032#ifdef NO_32BIT_SUPPORT_YET1033	case 32:1034#endif1035		/* TrueColor, 16m */1036		info->fix.visual = FB_VISUAL_TRUECOLOR;1037 1038		for (i = 0; i < 256; i++) {1039			outb(i, 0x3c8);1040 1041			outb(i, 0x3c9);1042			outb(i, 0x3c9);1043			outb(i, 0x3c9);1044		}1045		break;1046	}1047 1048	vga_wgfx(NULL, 0x0E, par->ExtCRTDispAddr);1049	vga_wgfx(NULL, 0x0F, par->ExtCRTOffset);1050	temp = vga_rgfx(NULL, 0x10);1051	temp &= 0x0F;		/* Save bits 3:0 */1052	temp |= (par->SysIfaceCntl1 & ~0x0F);	/* VESA Bios sets bit 1! */1053	vga_wgfx(NULL, 0x10, temp);1054 1055	vga_wgfx(NULL, 0x11, par->SysIfaceCntl2);1056	vga_wgfx(NULL, 0x15, 0 /*par->SingleAddrPage */ );1057	vga_wgfx(NULL, 0x16, 0 /*par->DualAddrPage */ );1058 1059	temp = vga_rgfx(NULL, 0x20);1060	switch (info->fix.accel) {1061	case FB_ACCEL_NEOMAGIC_NM2070:1062		temp &= 0xFC;	/* Save bits 7:2 */1063		temp |= (par->PanelDispCntlReg1 & ~0xFC);1064		break;1065	case FB_ACCEL_NEOMAGIC_NM2090:1066	case FB_ACCEL_NEOMAGIC_NM2093:1067	case FB_ACCEL_NEOMAGIC_NM2097:1068	case FB_ACCEL_NEOMAGIC_NM2160:1069		temp &= 0xDC;	/* Save bits 7:6,4:2 */1070		temp |= (par->PanelDispCntlReg1 & ~0xDC);1071		break;1072	case FB_ACCEL_NEOMAGIC_NM2200:1073	case FB_ACCEL_NEOMAGIC_NM2230:1074	case FB_ACCEL_NEOMAGIC_NM2360:1075	case FB_ACCEL_NEOMAGIC_NM2380:1076		temp &= 0x98;	/* Save bits 7,4:3 */1077		temp |= (par->PanelDispCntlReg1 & ~0x98);1078		break;1079	}1080	vga_wgfx(NULL, 0x20, temp);1081 1082	temp = vga_rgfx(NULL, 0x25);1083	temp &= 0x38;		/* Save bits 5:3 */1084	temp |= (par->PanelDispCntlReg2 & ~0x38);1085	vga_wgfx(NULL, 0x25, temp);1086 1087	if (info->fix.accel != FB_ACCEL_NEOMAGIC_NM2070) {1088		temp = vga_rgfx(NULL, 0x30);1089		temp &= 0xEF;	/* Save bits 7:5 and bits 3:0 */1090		temp |= (par->PanelDispCntlReg3 & ~0xEF);1091		vga_wgfx(NULL, 0x30, temp);1092	}1093 1094	vga_wgfx(NULL, 0x28, par->PanelVertCenterReg1);1095	vga_wgfx(NULL, 0x29, par->PanelVertCenterReg2);1096	vga_wgfx(NULL, 0x2a, par->PanelVertCenterReg3);1097 1098	if (info->fix.accel != FB_ACCEL_NEOMAGIC_NM2070) {1099		vga_wgfx(NULL, 0x32, par->PanelVertCenterReg4);1100		vga_wgfx(NULL, 0x33, par->PanelHorizCenterReg1);1101		vga_wgfx(NULL, 0x34, par->PanelHorizCenterReg2);1102		vga_wgfx(NULL, 0x35, par->PanelHorizCenterReg3);1103	}1104 1105	if (info->fix.accel == FB_ACCEL_NEOMAGIC_NM2160)1106		vga_wgfx(NULL, 0x36, par->PanelHorizCenterReg4);1107 1108	if (info->fix.accel == FB_ACCEL_NEOMAGIC_NM2200 ||1109	    info->fix.accel == FB_ACCEL_NEOMAGIC_NM2230 ||1110	    info->fix.accel == FB_ACCEL_NEOMAGIC_NM2360 ||1111	    info->fix.accel == FB_ACCEL_NEOMAGIC_NM2380) {1112		vga_wgfx(NULL, 0x36, par->PanelHorizCenterReg4);1113		vga_wgfx(NULL, 0x37, par->PanelVertCenterReg5);1114		vga_wgfx(NULL, 0x38, par->PanelHorizCenterReg5);1115 1116		clock_hi = 1;1117	}1118 1119	/* Program VCLK3 if needed. */1120	if (par->ProgramVCLK && ((vga_rgfx(NULL, 0x9B) != par->VCLK3NumeratorLow)1121				 || (vga_rgfx(NULL, 0x9F) != par->VCLK3Denominator)1122				 || (clock_hi && ((vga_rgfx(NULL, 0x8F) & ~0x0f)1123						  != (par->VCLK3NumeratorHigh &1124						      ~0x0F))))) {1125		vga_wgfx(NULL, 0x9B, par->VCLK3NumeratorLow);1126		if (clock_hi) {1127			temp = vga_rgfx(NULL, 0x8F);1128			temp &= 0x0F;	/* Save bits 3:0 */1129			temp |= (par->VCLK3NumeratorHigh & ~0x0F);1130			vga_wgfx(NULL, 0x8F, temp);1131		}1132		vga_wgfx(NULL, 0x9F, par->VCLK3Denominator);1133	}1134 1135	if (par->biosMode)1136		vga_wcrt(NULL, 0x23, par->biosMode);1137 1138	vga_wgfx(NULL, 0x93, 0xc0);	/* Gives 5x faster framebuffer writes !!! */1139 1140	/* Program vertical extension register */1141	if (info->fix.accel == FB_ACCEL_NEOMAGIC_NM2200 ||1142	    info->fix.accel == FB_ACCEL_NEOMAGIC_NM2230 ||1143	    info->fix.accel == FB_ACCEL_NEOMAGIC_NM2360 ||1144	    info->fix.accel == FB_ACCEL_NEOMAGIC_NM2380) {1145		vga_wcrt(NULL, 0x70, par->VerticalExt);1146	}1147 1148	vgaHWProtect(0);	/* Turn on screen */1149 1150	/* Calling this also locks offset registers required in update_start */1151	neoLock(&par->state);1152 1153	info->fix.line_length =1154	    info->var.xres_virtual * (info->var.bits_per_pixel >> 3);1155 1156	switch (info->fix.accel) {1157		case FB_ACCEL_NEOMAGIC_NM2200:1158		case FB_ACCEL_NEOMAGIC_NM2230:1159		case FB_ACCEL_NEOMAGIC_NM2360:1160		case FB_ACCEL_NEOMAGIC_NM2380:1161			neo2200_accel_init(info, &info->var);1162			break;1163		default:1164			break;1165	}1166	return 0;1167}1168 1169/*1170 *    Pan or Wrap the Display1171 */1172static int neofb_pan_display(struct fb_var_screeninfo *var,1173			     struct fb_info *info)1174{1175	struct neofb_par *par = info->par;1176	struct vgastate *state = &par->state;1177	int oldExtCRTDispAddr;1178	int Base;1179 1180	DBG("neofb_update_start");1181 1182	Base = (var->yoffset * info->var.xres_virtual + var->xoffset) >> 2;1183	Base *= (info->var.bits_per_pixel + 7) / 8;1184 1185	neoUnlock();1186 1187	/*1188	 * These are the generic starting address registers.1189	 */1190	vga_wcrt(state->vgabase, 0x0C, (Base & 0x00FF00) >> 8);1191	vga_wcrt(state->vgabase, 0x0D, (Base & 0x00FF));1192 1193	/*1194	 * Make sure we don't clobber some other bits that might already1195	 * have been set. NOTE: NM2200 has a writable bit 3, but it shouldn't1196	 * be needed.1197	 */1198	oldExtCRTDispAddr = vga_rgfx(NULL, 0x0E);1199	vga_wgfx(state->vgabase, 0x0E, (((Base >> 16) & 0x0f) | (oldExtCRTDispAddr & 0xf0)));1200 1201	neoLock(state);1202 1203	return 0;1204}1205 1206static int neofb_setcolreg(u_int regno, u_int red, u_int green, u_int blue,1207			   u_int transp, struct fb_info *fb)1208{1209	if (regno >= fb->cmap.len || regno > 255)1210		return -EINVAL;1211 1212	if (fb->var.bits_per_pixel <= 8) {1213		outb(regno, 0x3c8);1214 1215		outb(red >> 10, 0x3c9);1216		outb(green >> 10, 0x3c9);1217		outb(blue >> 10, 0x3c9);1218	} else if (regno < 16) {1219		switch (fb->var.bits_per_pixel) {1220		case 16:1221			((u32 *) fb->pseudo_palette)[regno] =1222				((red & 0xf800)) | ((green & 0xfc00) >> 5) |1223				((blue & 0xf800) >> 11);1224			break;1225		case 24:1226			((u32 *) fb->pseudo_palette)[regno] =1227				((red & 0xff00) << 8) | ((green & 0xff00)) |1228				((blue & 0xff00) >> 8);1229			break;1230#ifdef NO_32BIT_SUPPORT_YET1231		case 32:1232			((u32 *) fb->pseudo_palette)[regno] =1233				((transp & 0xff00) << 16) | ((red & 0xff00) << 8) |1234				((green & 0xff00)) | ((blue & 0xff00) >> 8);1235			break;1236#endif1237		default:1238			return 1;1239		}1240	}1241 1242	return 0;1243}1244 1245/*1246 *    (Un)Blank the display.1247 */1248static int neofb_blank(int blank_mode, struct fb_info *info)1249{1250	/*1251	 *  Blank the screen if blank_mode != 0, else unblank.1252	 *  Return 0 if blanking succeeded, != 0 if un-/blanking failed due to1253	 *  e.g. a video mode which doesn't support it. Implements VESA suspend1254	 *  and powerdown modes for monitors, and backlight control on LCDs.1255	 *    blank_mode == 0: unblanked (backlight on)1256	 *    blank_mode == 1: blank (backlight on)1257	 *    blank_mode == 2: suspend vsync (backlight off)1258	 *    blank_mode == 3: suspend hsync (backlight off)1259	 *    blank_mode == 4: powerdown (backlight off)1260	 *1261	 *  wms...Enable VESA DPMS compatible powerdown mode1262	 *  run "setterm -powersave powerdown" to take advantage1263	 */1264	struct neofb_par *par = info->par;1265	int seqflags, lcdflags, dpmsflags, reg, tmpdisp;1266 1267	/*1268	 * Read back the register bits related to display configuration. They might1269	 * have been changed underneath the driver via Fn key stroke.1270	 */1271	neoUnlock();1272	tmpdisp = vga_rgfx(NULL, 0x20) & 0x03;1273	neoLock(&par->state);1274 1275	/* In case we blank the screen, we want to store the possibly new1276	 * configuration in the driver. During un-blank, we re-apply this setting,1277	 * since the LCD bit will be cleared in order to switch off the backlight.1278	 */1279	if (par->PanelDispCntlRegRead) {1280		par->PanelDispCntlReg1 = tmpdisp;1281	}1282	par->PanelDispCntlRegRead = !blank_mode;1283 1284	switch (blank_mode) {1285	case FB_BLANK_POWERDOWN:	/* powerdown - both sync lines down */1286		seqflags = VGA_SR01_SCREEN_OFF; /* Disable sequencer */1287		lcdflags = 0;			/* LCD off */1288		dpmsflags = NEO_GR01_SUPPRESS_HSYNC |1289			    NEO_GR01_SUPPRESS_VSYNC;1290#ifdef CONFIG_TOSHIBA1291		/* Do we still need this ? */1292		/* attempt to turn off backlight on toshiba; also turns off external */1293		{1294			SMMRegisters regs;1295 1296			regs.eax = 0xff00; /* HCI_SET */1297			regs.ebx = 0x0002; /* HCI_BACKLIGHT */1298			regs.ecx = 0x0000; /* HCI_DISABLE */1299			tosh_smm(&regs);1300		}1301#endif1302		break;1303	case FB_BLANK_HSYNC_SUSPEND:		/* hsync off */1304		seqflags = VGA_SR01_SCREEN_OFF;	/* Disable sequencer */1305		lcdflags = 0;			/* LCD off */1306		dpmsflags = NEO_GR01_SUPPRESS_HSYNC;1307		break;1308	case FB_BLANK_VSYNC_SUSPEND:		/* vsync off */1309		seqflags = VGA_SR01_SCREEN_OFF;	/* Disable sequencer */1310		lcdflags = 0;			/* LCD off */1311		dpmsflags = NEO_GR01_SUPPRESS_VSYNC;1312		break;1313	case FB_BLANK_NORMAL:		/* just blank screen (backlight stays on) */1314		seqflags = VGA_SR01_SCREEN_OFF;	/* Disable sequencer */1315		/*1316		 * During a blank operation with the LID shut, we might store "LCD off"1317		 * by mistake. Due to timing issues, the BIOS may switch the lights1318		 * back on, and we turn it back off once we "unblank".1319		 *1320		 * So here is an attempt to implement ">=" - if we are in the process1321		 * of unblanking, and the LCD bit is unset in the driver but set in the1322		 * register, we must keep it.1323		 */1324		lcdflags = ((par->PanelDispCntlReg1 | tmpdisp) & 0x02); /* LCD normal */1325		dpmsflags = 0x00;	/* no hsync/vsync suppression */1326		break;1327	case FB_BLANK_UNBLANK:		/* unblank */1328		seqflags = 0;			/* Enable sequencer */1329		lcdflags = ((par->PanelDispCntlReg1 | tmpdisp) & 0x02); /* LCD normal */1330		dpmsflags = 0x00;	/* no hsync/vsync suppression */1331#ifdef CONFIG_TOSHIBA1332		/* Do we still need this ? */1333		/* attempt to re-enable backlight/external on toshiba */1334		{1335			SMMRegisters regs;1336 1337			regs.eax = 0xff00; /* HCI_SET */1338			regs.ebx = 0x0002; /* HCI_BACKLIGHT */1339			regs.ecx = 0x0001; /* HCI_ENABLE */1340			tosh_smm(&regs);1341		}1342#endif1343		break;1344	default:	/* Anything else we don't understand; return 1 to tell1345			 * fb_blank we didn't aactually do anything */1346		return 1;1347	}1348 1349	neoUnlock();1350	reg = (vga_rseq(NULL, 0x01) & ~0x20) | seqflags;1351	vga_wseq(NULL, 0x01, reg);1352	reg = (vga_rgfx(NULL, 0x20) & ~0x02) | lcdflags;1353	vga_wgfx(NULL, 0x20, reg);1354	reg = (vga_rgfx(NULL, 0x01) & ~0xF0) | 0x80 | dpmsflags;1355	vga_wgfx(NULL, 0x01, reg);1356	neoLock(&par->state);1357	return 0;1358}1359 1360static void1361neo2200_fillrect(struct fb_info *info, const struct fb_fillrect *rect)1362{1363	struct neofb_par *par = info->par;1364	u_long dst, rop;1365 1366	dst = rect->dx + rect->dy * info->var.xres_virtual;1367	rop = rect->rop ? 0x060000 : 0x0c0000;1368 1369	neo2200_wait_fifo(info, 4);1370 1371	/* set blt control */1372	writel(NEO_BC3_FIFO_EN |1373	       NEO_BC0_SRC_IS_FG | NEO_BC3_SKIP_MAPPING |1374	       //               NEO_BC3_DST_XY_ADDR  |1375	       //               NEO_BC3_SRC_XY_ADDR  |1376	       rop, &par->neo2200->bltCntl);1377 1378	switch (info->var.bits_per_pixel) {1379	case 8:1380		writel(rect->color, &par->neo2200->fgColor);1381		break;1382	case 16:1383	case 24:1384		writel(((u32 *) (info->pseudo_palette))[rect->color],1385		       &par->neo2200->fgColor);1386		break;1387	}1388 1389	writel(dst * ((info->var.bits_per_pixel + 7) >> 3),1390	       &par->neo2200->dstStart);1391	writel((rect->height << 16) | (rect->width & 0xffff),1392	       &par->neo2200->xyExt);1393}1394 1395static void1396neo2200_copyarea(struct fb_info *info, const struct fb_copyarea *area)1397{1398	u32 sx = area->sx, sy = area->sy, dx = area->dx, dy = area->dy;1399	struct neofb_par *par = info->par;1400	u_long src, dst, bltCntl;1401 1402	bltCntl = NEO_BC3_FIFO_EN | NEO_BC3_SKIP_MAPPING | 0x0C0000;1403 1404	if ((dy > sy) || ((dy == sy) && (dx > sx))) {1405		/* Start with the lower right corner */1406		sy += (area->height - 1);1407		dy += (area->height - 1);1408		sx += (area->width - 1);1409		dx += (area->width - 1);1410 1411		bltCntl |= NEO_BC0_X_DEC | NEO_BC0_DST_Y_DEC | NEO_BC0_SRC_Y_DEC;1412	}1413 1414	src = sx * (info->var.bits_per_pixel >> 3) + sy*info->fix.line_length;1415	dst = dx * (info->var.bits_per_pixel >> 3) + dy*info->fix.line_length;1416 1417	neo2200_wait_fifo(info, 4);1418 1419	/* set blt control */1420	writel(bltCntl, &par->neo2200->bltCntl);1421 1422	writel(src, &par->neo2200->srcStart);1423	writel(dst, &par->neo2200->dstStart);1424	writel((area->height << 16) | (area->width & 0xffff),1425	       &par->neo2200->xyExt);1426}1427 1428static void1429neo2200_imageblit(struct fb_info *info, const struct fb_image *image)1430{1431	struct neofb_par *par = info->par;1432	int s_pitch = (image->width * image->depth + 7) >> 3;1433	int scan_align = info->pixmap.scan_align - 1;1434	int buf_align = info->pixmap.buf_align - 1;1435	int bltCntl_flags, d_pitch, data_len;1436 1437	// The data is padded for the hardware1438	d_pitch = (s_pitch + scan_align) & ~scan_align;1439	data_len = ((d_pitch * image->height) + buf_align) & ~buf_align;1440 1441	neo2200_sync(info);1442 1443	if (image->depth == 1) {1444		if (info->var.bits_per_pixel == 24 && image->width < 16) {1445			/* FIXME. There is a bug with accelerated color-expanded1446			 * transfers in 24 bit mode if the image being transferred1447			 * is less than 16 bits wide. This is due to insufficient1448			 * padding when writing the image. We need to adjust1449			 * struct fb_pixmap. Not yet done. */1450			cfb_imageblit(info, image);1451			return;1452		}1453		bltCntl_flags = NEO_BC0_SRC_MONO;1454	} else if (image->depth == info->var.bits_per_pixel) {1455		bltCntl_flags = 0;1456	} else {1457		/* We don't currently support hardware acceleration if image1458		 * depth is different from display */1459		cfb_imageblit(info, image);1460		return;1461	}1462 1463	switch (info->var.bits_per_pixel) {1464	case 8:1465		writel(image->fg_color, &par->neo2200->fgColor);1466		writel(image->bg_color, &par->neo2200->bgColor);1467		break;1468	case 16:1469	case 24:1470		writel(((u32 *) (info->pseudo_palette))[image->fg_color],1471		       &par->neo2200->fgColor);1472		writel(((u32 *) (info->pseudo_palette))[image->bg_color],1473		       &par->neo2200->bgColor);1474		break;1475	}1476 1477	writel(NEO_BC0_SYS_TO_VID |1478		NEO_BC3_SKIP_MAPPING | bltCntl_flags |1479		// NEO_BC3_DST_XY_ADDR |1480		0x0c0000, &par->neo2200->bltCntl);1481 1482	writel(0, &par->neo2200->srcStart);1483//      par->neo2200->dstStart = (image->dy << 16) | (image->dx & 0xffff);1484	writel(((image->dx & 0xffff) * (info->var.bits_per_pixel >> 3) +1485		image->dy * info->fix.line_length), &par->neo2200->dstStart);1486	writel((image->height << 16) | (image->width & 0xffff),1487	       &par->neo2200->xyExt);1488 1489	memcpy_toio(par->mmio_vbase + 0x100000, image->data, data_len);1490}1491 1492static void1493neofb_fillrect(struct fb_info *info, const struct fb_fillrect *rect)1494{1495	switch (info->fix.accel) {1496		case FB_ACCEL_NEOMAGIC_NM2200:1497		case FB_ACCEL_NEOMAGIC_NM2230:1498		case FB_ACCEL_NEOMAGIC_NM2360:1499		case FB_ACCEL_NEOMAGIC_NM2380:1500			neo2200_fillrect(info, rect);1501			break;1502		default:1503			cfb_fillrect(info, rect);1504			break;1505	}1506}1507 1508static void1509neofb_copyarea(struct fb_info *info, const struct fb_copyarea *area)1510{1511	switch (info->fix.accel) {1512		case FB_ACCEL_NEOMAGIC_NM2200:1513		case FB_ACCEL_NEOMAGIC_NM2230:1514		case FB_ACCEL_NEOMAGIC_NM2360:1515		case FB_ACCEL_NEOMAGIC_NM2380:1516			neo2200_copyarea(info, area);1517			break;1518		default:1519			cfb_copyarea(info, area);1520			break;1521	}1522}1523 1524static void1525neofb_imageblit(struct fb_info *info, const struct fb_image *image)1526{1527	switch (info->fix.accel) {1528		case FB_ACCEL_NEOMAGIC_NM2200:1529		case FB_ACCEL_NEOMAGIC_NM2230:1530		case FB_ACCEL_NEOMAGIC_NM2360:1531		case FB_ACCEL_NEOMAGIC_NM2380:1532			neo2200_imageblit(info, image);1533			break;1534		default:1535			cfb_imageblit(info, image);1536			break;1537	}1538}1539 1540static int1541neofb_sync(struct fb_info *info)1542{1543	switch (info->fix.accel) {1544		case FB_ACCEL_NEOMAGIC_NM2200:1545		case FB_ACCEL_NEOMAGIC_NM2230:1546		case FB_ACCEL_NEOMAGIC_NM2360:1547		case FB_ACCEL_NEOMAGIC_NM2380:1548			neo2200_sync(info);1549			break;1550		default:1551			break;1552	}1553	return 0;1554}1555 1556/*1557static void1558neofb_draw_cursor(struct fb_info *info, u8 *dst, u8 *src, unsigned int width)1559{1560	//memset_io(info->sprite.addr, 0xff, 1);1561}1562 1563static int1564neofb_cursor(struct fb_info *info, struct fb_cursor *cursor)1565{1566	struct neofb_par *par = (struct neofb_par *) info->par;1567 1568	* Disable cursor *1569	write_le32(NEOREG_CURSCNTL, ~NEO_CURS_ENABLE, par);1570 1571	if (cursor->set & FB_CUR_SETPOS) {1572		u32 x = cursor->image.dx;1573		u32 y = cursor->image.dy;1574 1575		info->cursor.image.dx = x;1576		info->cursor.image.dy = y;1577		write_le32(NEOREG_CURSX, x, par);1578		write_le32(NEOREG_CURSY, y, par);1579	}1580 1581	if (cursor->set & FB_CUR_SETSIZE) {1582		info->cursor.image.height = cursor->image.height;1583		info->cursor.image.width = cursor->image.width;1584	}1585 1586	if (cursor->set & FB_CUR_SETHOT)1587		info->cursor.hot = cursor->hot;1588 1589	if (cursor->set & FB_CUR_SETCMAP) {1590		if (cursor->image.depth == 1) {1591			u32 fg = cursor->image.fg_color;1592			u32 bg = cursor->image.bg_color;1593 1594			info->cursor.image.fg_color = fg;1595			info->cursor.image.bg_color = bg;1596 1597			fg = ((fg & 0xff0000) >> 16) | ((fg & 0xff) << 16) | (fg & 0xff00);1598			bg = ((bg & 0xff0000) >> 16) | ((bg & 0xff) << 16) | (bg & 0xff00);1599			write_le32(NEOREG_CURSFGCOLOR, fg, par);1600			write_le32(NEOREG_CURSBGCOLOR, bg, par);1601		}1602	}1603 1604	if (cursor->set & FB_CUR_SETSHAPE)1605		fb_load_cursor_image(info);1606 1607	if (info->cursor.enable)1608		write_le32(NEOREG_CURSCNTL, NEO_CURS_ENABLE, par);1609	return 0;1610}1611*/1612 1613static const struct fb_ops neofb_ops = {1614	.owner		= THIS_MODULE,1615	.fb_open	= neofb_open,1616	.fb_release	= neofb_release,1617	__FB_DEFAULT_IOMEM_OPS_RDWR,1618	.fb_check_var	= neofb_check_var,1619	.fb_set_par	= neofb_set_par,1620	.fb_setcolreg	= neofb_setcolreg,1621	.fb_pan_display	= neofb_pan_display,1622	.fb_blank	= neofb_blank,1623	.fb_sync	= neofb_sync,1624	.fb_fillrect	= neofb_fillrect,1625	.fb_copyarea	= neofb_copyarea,1626	.fb_imageblit	= neofb_imageblit,1627	__FB_DEFAULT_IOMEM_OPS_MMAP,1628};1629 1630/* --------------------------------------------------------------------- */1631 1632static struct fb_videomode mode800x480 = {1633	.xres           = 800,1634	.yres           = 480,1635	.pixclock       = 25000,1636	.left_margin    = 88,1637	.right_margin   = 40,1638	.upper_margin   = 23,1639	.lower_margin   = 1,1640	.hsync_len      = 128,1641	.vsync_len      = 4,1642	.sync           = FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,1643	.vmode          = FB_VMODE_NONINTERLACED1644};1645 1646static int neo_map_mmio(struct fb_info *info, struct pci_dev *dev)1647{1648	struct neofb_par *par = info->par;1649 1650	DBG("neo_map_mmio");1651 1652	switch (info->fix.accel) {1653		case FB_ACCEL_NEOMAGIC_NM2070:1654			info->fix.mmio_start = pci_resource_start(dev, 0)+1655				0x100000;1656			break;1657		case FB_ACCEL_NEOMAGIC_NM2090:1658		case FB_ACCEL_NEOMAGIC_NM2093:1659			info->fix.mmio_start = pci_resource_start(dev, 0)+1660				0x200000;1661			break;1662		case FB_ACCEL_NEOMAGIC_NM2160:1663		case FB_ACCEL_NEOMAGIC_NM2097:1664		case FB_ACCEL_NEOMAGIC_NM2200:1665		case FB_ACCEL_NEOMAGIC_NM2230:1666		case FB_ACCEL_NEOMAGIC_NM2360:1667		case FB_ACCEL_NEOMAGIC_NM2380:1668			info->fix.mmio_start = pci_resource_start(dev, 1);1669			break;1670		default:1671			info->fix.mmio_start = pci_resource_start(dev, 0);1672	}1673	info->fix.mmio_len = MMIO_SIZE;1674 1675	if (!request_mem_region1676	    (info->fix.mmio_start, MMIO_SIZE, "memory mapped I/O")) {1677		printk("neofb: memory mapped IO in use\n");1678		return -EBUSY;1679	}1680 1681	par->mmio_vbase = ioremap(info->fix.mmio_start, MMIO_SIZE);1682	if (!par->mmio_vbase) {1683		printk("neofb: unable to map memory mapped IO\n");1684		release_mem_region(info->fix.mmio_start,1685				   info->fix.mmio_len);1686		return -ENOMEM;1687	} else1688		printk(KERN_INFO "neofb: mapped io at %p\n",1689		       par->mmio_vbase);1690	return 0;1691}1692 1693static void neo_unmap_mmio(struct fb_info *info)1694{1695	struct neofb_par *par = info->par;1696 1697	DBG("neo_unmap_mmio");1698 1699	iounmap(par->mmio_vbase);1700	par->mmio_vbase = NULL;1701 1702	release_mem_region(info->fix.mmio_start,1703			   info->fix.mmio_len);1704}1705 1706static int neo_map_video(struct fb_info *info, struct pci_dev *dev,1707			 int video_len)1708{1709	//unsigned long addr;1710	struct neofb_par *par = info->par;1711 1712	DBG("neo_map_video");1713 1714	info->fix.smem_start = pci_resource_start(dev, 0);1715	info->fix.smem_len = video_len;1716 1717	if (!request_mem_region(info->fix.smem_start, info->fix.smem_len,1718				"frame buffer")) {1719		printk("neofb: frame buffer in use\n");1720		return -EBUSY;1721	}1722 1723	info->screen_base =1724	    ioremap_wc(info->fix.smem_start, info->fix.smem_len);1725	if (!info->screen_base) {1726		printk("neofb: unable to map screen memory\n");1727		release_mem_region(info->fix.smem_start,1728				   info->fix.smem_len);1729		return -ENOMEM;1730	} else1731		printk(KERN_INFO "neofb: mapped framebuffer at %p\n",1732		       info->screen_base);1733 1734	par->wc_cookie = arch_phys_wc_add(info->fix.smem_start,1735					  pci_resource_len(dev, 0));1736 1737	/* Clear framebuffer, it's all white in memory after boot */1738	memset_io(info->screen_base, 0, info->fix.smem_len);1739 1740	/* Allocate Cursor drawing pad.1741	info->fix.smem_len -= PAGE_SIZE;1742	addr = info->fix.smem_start + info->fix.smem_len;1743	write_le32(NEOREG_CURSMEMPOS, ((0x000f & (addr >> 10)) << 8) |1744					((0x0ff0 & (addr >> 10)) >> 4), par);1745	addr = (unsigned long) info->screen_base + info->fix.smem_len;1746	info->sprite.addr = (u8 *) addr; */1747	return 0;1748}1749 1750static void neo_unmap_video(struct fb_info *info)1751{1752	struct neofb_par *par = info->par;1753 1754	DBG("neo_unmap_video");1755 1756	arch_phys_wc_del(par->wc_cookie);1757	iounmap(info->screen_base);1758	info->screen_base = NULL;1759 1760	release_mem_region(info->fix.smem_start,1761			   info->fix.smem_len);1762}1763 1764static int neo_scan_monitor(struct fb_info *info)1765{1766	struct neofb_par *par = info->par;1767	unsigned char type, display;1768	int w;1769 1770	// Eventually we will have i2c support.1771	info->monspecs.modedb = kmalloc(sizeof(struct fb_videomode), GFP_KERNEL);1772	if (!info->monspecs.modedb)1773		return -ENOMEM;1774	info->monspecs.modedb_len = 1;1775 1776	/* Determine the panel type */1777	vga_wgfx(NULL, 0x09, 0x26);1778	type = vga_rgfx(NULL, 0x21);1779	display = vga_rgfx(NULL, 0x20);1780	if (!par->internal_display && !par->external_display) {1781		par->internal_display = display & 2 || !(display & 3) ? 1 : 0;1782		par->external_display = display & 1;1783		printk (KERN_INFO "Autodetected %s display\n",1784			par->internal_display && par->external_display ? "simultaneous" :1785			par->internal_display ? "internal" : "external");1786	}1787 1788	/* Determine panel width -- used in NeoValidMode. */1789	w = vga_rgfx(NULL, 0x20);1790	vga_wgfx(NULL, 0x09, 0x00);1791	switch ((w & 0x18) >> 3) {1792	case 0x00:1793		// 640x480@601794		par->NeoPanelWidth = 640;1795		par->NeoPanelHeight = 480;1796		memcpy(info->monspecs.modedb, &vesa_modes[3], sizeof(struct fb_videomode));1797		break;1798	case 0x01:1799		par->NeoPanelWidth = 800;1800		if (par->libretto) {1801			par->NeoPanelHeight = 480;1802			memcpy(info->monspecs.modedb, &mode800x480, sizeof(struct fb_videomode));1803		} else {1804			// 800x600@601805			par->NeoPanelHeight = 600;1806			memcpy(info->monspecs.modedb, &vesa_modes[8], sizeof(struct fb_videomode));1807		}1808		break;1809	case 0x02:1810		// 1024x768@601811		par->NeoPanelWidth = 1024;1812		par->NeoPanelHeight = 768;1813		memcpy(info->monspecs.modedb, &vesa_modes[13], sizeof(struct fb_videomode));1814		break;1815	case 0x03:1816		/* 1280x1024@60 panel support needs to be added */1817#ifdef NOT_DONE1818		par->NeoPanelWidth = 1280;1819		par->NeoPanelHeight = 1024;1820		memcpy(info->monspecs.modedb, &vesa_modes[20], sizeof(struct fb_videomode));1821		break;1822#else1823		printk(KERN_ERR1824		       "neofb: Only 640x480, 800x600/480 and 1024x768 panels are currently supported\n");1825		kfree(info->monspecs.modedb);1826		return -1;1827#endif1828	default:1829		// 640x480@601830		par->NeoPanelWidth = 640;1831		par->NeoPanelHeight = 480;1832		memcpy(info->monspecs.modedb, &vesa_modes[3], sizeof(struct fb_videomode));1833		break;1834	}1835 1836	printk(KERN_INFO "Panel is a %dx%d %s %s display\n",1837	       par->NeoPanelWidth,1838	       par->NeoPanelHeight,1839	       (type & 0x02) ? "color" : "monochrome",1840	       (type & 0x10) ? "TFT" : "dual scan");1841	return 0;1842}1843 1844static int neo_init_hw(struct fb_info *info)1845{1846	struct neofb_par *par = info->par;1847	int videoRam = 896;1848	int maxClock = 65000;1849	int CursorOff = 0x100;1850 1851	DBG("neo_init_hw");1852 1853	neoUnlock();1854 1855#if 01856	printk(KERN_DEBUG "--- Neo extended register dump ---\n");1857	for (int w = 0; w < 0x85; w++)1858		printk(KERN_DEBUG "CR %p: %p\n", (void *) w,1859		       (void *) vga_rcrt(NULL, w));1860	for (int w = 0; w < 0xC7; w++)1861		printk(KERN_DEBUG "GR %p: %p\n", (void *) w,1862		       (void *) vga_rgfx(NULL, w));1863#endif1864	switch (info->fix.accel) {1865	case FB_ACCEL_NEOMAGIC_NM2070:1866		videoRam = 896;1867		maxClock = 65000;1868		break;1869	case FB_ACCEL_NEOMAGIC_NM2090:1870	case FB_ACCEL_NEOMAGIC_NM2093:1871	case FB_ACCEL_NEOMAGIC_NM2097:1872		videoRam = 1152;1873		maxClock = 80000;1874		break;1875	case FB_ACCEL_NEOMAGIC_NM2160:1876		videoRam = 2048;1877		maxClock = 90000;1878		break;1879	case FB_ACCEL_NEOMAGIC_NM2200:1880		videoRam = 2560;1881		maxClock = 110000;1882		break;1883	case FB_ACCEL_NEOMAGIC_NM2230:1884		videoRam = 3008;1885		maxClock = 110000;1886		break;1887	case FB_ACCEL_NEOMAGIC_NM2360:1888		videoRam = 4096;1889		maxClock = 110000;1890		break;1891	case FB_ACCEL_NEOMAGIC_NM2380:1892		videoRam = 6144;1893		maxClock = 110000;1894		break;1895	}1896	switch (info->fix.accel) {1897	case FB_ACCEL_NEOMAGIC_NM2070:1898	case FB_ACCEL_NEOMAGIC_NM2090:1899	case FB_ACCEL_NEOMAGIC_NM2093:1900		CursorOff = 0x100;1901		break;1902	case FB_ACCEL_NEOMAGIC_NM2097:1903	case FB_ACCEL_NEOMAGIC_NM2160:1904		CursorOff = 0x100;1905		break;1906	case FB_ACCEL_NEOMAGIC_NM2200:1907	case FB_ACCEL_NEOMAGIC_NM2230:1908	case FB_ACCEL_NEOMAGIC_NM2360:1909	case FB_ACCEL_NEOMAGIC_NM2380:1910		CursorOff = 0x1000;1911 1912		par->neo2200 = (Neo2200 __iomem *) par->mmio_vbase;1913		break;1914	}1915/*1916	info->sprite.size = CursorMem;1917	info->sprite.scan_align = 1;1918	info->sprite.buf_align = 1;1919	info->sprite.flags = FB_PIXMAP_IO;1920	info->sprite.outbuf = neofb_draw_cursor;1921*/1922	par->maxClock = maxClock;1923	par->cursorOff = CursorOff;1924	return videoRam * 1024;1925}1926 1927 1928static struct fb_info *neo_alloc_fb_info(struct pci_dev *dev,1929					 const struct pci_device_id *id)1930{1931	struct fb_info *info;1932	struct neofb_par *par;1933 1934	info = framebuffer_alloc(sizeof(struct neofb_par), &dev->dev);1935 1936	if (!info)1937		return NULL;1938 1939	par = info->par;1940 1941	info->fix.accel = id->driver_data;1942 1943	par->pci_burst = !nopciburst;1944	par->lcd_stretch = !nostretch;1945	par->libretto = libretto;1946 1947	par->internal_display = internal;1948	par->external_display = external;1949	info->flags = FBINFO_HWACCEL_YPAN;1950 1951	switch (info->fix.accel) {1952	case FB_ACCEL_NEOMAGIC_NM2070:1953		strscpy(info->fix.id, "MagicGraph128", sizeof(info->fix.id));1954		break;1955	case FB_ACCEL_NEOMAGIC_NM2090:1956		strscpy(info->fix.id, "MagicGraph128V", sizeof(info->fix.id));1957		break;1958	case FB_ACCEL_NEOMAGIC_NM2093:1959		strscpy(info->fix.id, "MagicGraph128ZV", sizeof(info->fix.id));1960		break;1961	case FB_ACCEL_NEOMAGIC_NM2097:1962		strscpy(info->fix.id, "Mag.Graph128ZV+", sizeof(info->fix.id));1963		break;1964	case FB_ACCEL_NEOMAGIC_NM2160:1965		strscpy(info->fix.id, "MagicGraph128XD", sizeof(info->fix.id));1966		break;1967	case FB_ACCEL_NEOMAGIC_NM2200:1968		strscpy(info->fix.id, "MagicGraph256AV", sizeof(info->fix.id));1969		info->flags |= FBINFO_HWACCEL_IMAGEBLIT |1970		               FBINFO_HWACCEL_COPYAREA |1971                	       FBINFO_HWACCEL_FILLRECT;1972		break;1973	case FB_ACCEL_NEOMAGIC_NM2230:1974		strscpy(info->fix.id, "Mag.Graph256AV+", sizeof(info->fix.id));1975		info->flags |= FBINFO_HWACCEL_IMAGEBLIT |1976		               FBINFO_HWACCEL_COPYAREA |1977                	       FBINFO_HWACCEL_FILLRECT;1978		break;1979	case FB_ACCEL_NEOMAGIC_NM2360:1980		strscpy(info->fix.id, "MagicGraph256ZX", sizeof(info->fix.id));1981		info->flags |= FBINFO_HWACCEL_IMAGEBLIT |1982		               FBINFO_HWACCEL_COPYAREA |1983                	       FBINFO_HWACCEL_FILLRECT;1984		break;1985	case FB_ACCEL_NEOMAGIC_NM2380:1986		strscpy(info->fix.id, "Mag.Graph256XL+", sizeof(info->fix.id));1987		info->flags |= FBINFO_HWACCEL_IMAGEBLIT |1988		               FBINFO_HWACCEL_COPYAREA |1989                	       FBINFO_HWACCEL_FILLRECT;1990		break;1991	}1992 1993	info->fix.type = FB_TYPE_PACKED_PIXELS;1994	info->fix.type_aux = 0;1995	info->fix.xpanstep = 0;1996	info->fix.ypanstep = 4;1997	info->fix.ywrapstep = 0;1998	info->fix.accel = id->driver_data;1999 2000	info->fbops = &neofb_ops;2001	info->pseudo_palette = par->palette;2002	return info;2003}2004 2005static void neo_free_fb_info(struct fb_info *info)2006{2007	if (info) {2008		/*2009		 * Free the colourmap2010		 */2011		fb_dealloc_cmap(&info->cmap);2012		framebuffer_release(info);2013	}2014}2015 2016/* --------------------------------------------------------------------- */2017 2018static int neofb_probe(struct pci_dev *dev, const struct pci_device_id *id)2019{2020	struct fb_info *info;2021	u_int h_sync, v_sync;2022	int video_len, err;2023 2024	DBG("neofb_probe");2025 2026	err = aperture_remove_conflicting_pci_devices(dev, "neofb");2027	if (err)2028		return err;2029 2030	err = pci_enable_device(dev);2031	if (err)2032		return err;2033 2034	err = -ENOMEM;2035	info = neo_alloc_fb_info(dev, id);2036	if (!info)2037		return err;2038 2039	err = neo_map_mmio(info, dev);2040	if (err)2041		goto err_map_mmio;2042 2043	err = neo_scan_monitor(info);2044	if (err)2045		goto err_scan_monitor;2046 2047	video_len = neo_init_hw(info);2048	if (video_len < 0) {2049		err = video_len;2050		goto err_init_hw;2051	}2052 2053	err = neo_map_video(info, dev, video_len);2054	if (err)2055		goto err_init_hw;2056 2057	if (!fb_find_mode(&info->var, info, mode_option, NULL, 0,2058			info->monspecs.modedb, 16)) {2059		printk(KERN_ERR "neofb: Unable to find usable video mode.\n");2060		err = -EINVAL;2061		goto err_map_video;2062	}2063 2064	/*2065	 * Calculate the hsync and vsync frequencies.  Note that2066	 * we split the 1e12 constant up so that we can preserve2067	 * the precision and fit the results into 32-bit registers.2068	 *  (1953125000 * 512 = 1e12)2069	 */2070	h_sync = 1953125000 / info->var.pixclock;2071	h_sync =2072	    h_sync * 512 / (info->var.xres + info->var.left_margin +2073			    info->var.right_margin + info->var.hsync_len);2074	v_sync =2075	    h_sync / (info->var.yres + info->var.upper_margin +2076		      info->var.lower_margin + info->var.vsync_len);2077 2078	printk(KERN_INFO "neofb v" NEOFB_VERSION2079	       ": %dkB VRAM, using %dx%d, %d.%03dkHz, %dHz\n",2080	       info->fix.smem_len >> 10, info->var.xres,2081	       info->var.yres, h_sync / 1000, h_sync % 1000, v_sync);2082 2083	err = fb_alloc_cmap(&info->cmap, 256, 0);2084	if (err < 0)2085		goto err_map_video;2086 2087	err = register_framebuffer(info);2088	if (err < 0)2089		goto err_reg_fb;2090 2091	fb_info(info, "%s frame buffer device\n", info->fix.id);2092 2093	/*2094	 * Our driver data2095	 */2096	pci_set_drvdata(dev, info);2097	return 0;2098 2099err_reg_fb:2100	fb_dealloc_cmap(&info->cmap);2101err_map_video:2102	neo_unmap_video(info);2103err_init_hw:2104	fb_destroy_modedb(info->monspecs.modedb);2105err_scan_monitor:2106	neo_unmap_mmio(info);2107err_map_mmio:2108	neo_free_fb_info(info);2109	return err;2110}2111 2112static void neofb_remove(struct pci_dev *dev)2113{2114	struct fb_info *info = pci_get_drvdata(dev);2115 2116	DBG("neofb_remove");2117 2118	if (info) {2119		unregister_framebuffer(info);2120 2121		neo_unmap_video(info);2122		fb_destroy_modedb(info->monspecs.modedb);2123		neo_unmap_mmio(info);2124		neo_free_fb_info(info);2125	}2126}2127 2128static const struct pci_device_id neofb_devices[] = {2129	{PCI_VENDOR_ID_NEOMAGIC, PCI_CHIP_NM2070,2130	 PCI_ANY_ID, PCI_ANY_ID, 0, 0, FB_ACCEL_NEOMAGIC_NM2070},2131 2132	{PCI_VENDOR_ID_NEOMAGIC, PCI_CHIP_NM2090,2133	 PCI_ANY_ID, PCI_ANY_ID, 0, 0, FB_ACCEL_NEOMAGIC_NM2090},2134 2135	{PCI_VENDOR_ID_NEOMAGIC, PCI_CHIP_NM2093,2136	 PCI_ANY_ID, PCI_ANY_ID, 0, 0, FB_ACCEL_NEOMAGIC_NM2093},2137 2138	{PCI_VENDOR_ID_NEOMAGIC, PCI_CHIP_NM2097,2139	 PCI_ANY_ID, PCI_ANY_ID, 0, 0, FB_ACCEL_NEOMAGIC_NM2097},2140 2141	{PCI_VENDOR_ID_NEOMAGIC, PCI_CHIP_NM2160,2142	 PCI_ANY_ID, PCI_ANY_ID, 0, 0, FB_ACCEL_NEOMAGIC_NM2160},2143 2144	{PCI_VENDOR_ID_NEOMAGIC, PCI_CHIP_NM2200,2145	 PCI_ANY_ID, PCI_ANY_ID, 0, 0, FB_ACCEL_NEOMAGIC_NM2200},2146 2147	{PCI_VENDOR_ID_NEOMAGIC, PCI_CHIP_NM2230,2148	 PCI_ANY_ID, PCI_ANY_ID, 0, 0, FB_ACCEL_NEOMAGIC_NM2230},2149 2150	{PCI_VENDOR_ID_NEOMAGIC, PCI_CHIP_NM2360,2151	 PCI_ANY_ID, PCI_ANY_ID, 0, 0, FB_ACCEL_NEOMAGIC_NM2360},2152 2153	{PCI_VENDOR_ID_NEOMAGIC, PCI_CHIP_NM2380,2154	 PCI_ANY_ID, PCI_ANY_ID, 0, 0, FB_ACCEL_NEOMAGIC_NM2380},2155 2156	{0, 0, 0, 0, 0, 0, 0}2157};2158 2159MODULE_DEVICE_TABLE(pci, neofb_devices);2160 2161static struct pci_driver neofb_driver = {2162	.name =		"neofb",2163	.id_table =	neofb_devices,2164	.probe =	neofb_probe,2165	.remove =	neofb_remove,2166};2167 2168/* ************************* init in-kernel code ************************** */2169 2170#ifndef MODULE2171static int __init neofb_setup(char *options)2172{2173	char *this_opt;2174 2175	DBG("neofb_setup");2176 2177	if (!options || !*options)2178		return 0;2179 2180	while ((this_opt = strsep(&options, ",")) != NULL) {2181		if (!*this_opt)2182			continue;2183 2184		if (!strncmp(this_opt, "internal", 8))2185			internal = 1;2186		else if (!strncmp(this_opt, "external", 8))2187			external = 1;2188		else if (!strncmp(this_opt, "nostretch", 9))2189			nostretch = 1;2190		else if (!strncmp(this_opt, "nopciburst", 10))2191			nopciburst = 1;2192		else if (!strncmp(this_opt, "libretto", 8))2193			libretto = 1;2194		else2195			mode_option = this_opt;2196	}2197	return 0;2198}2199#endif  /*  MODULE  */2200 2201static int __init neofb_init(void)2202{2203#ifndef MODULE2204	char *option = NULL;2205#endif2206 2207	if (fb_modesetting_disabled("neofb"))2208		return -ENODEV;2209 2210#ifndef MODULE2211	if (fb_get_options("neofb", &option))2212		return -ENODEV;2213	neofb_setup(option);2214#endif2215	return pci_register_driver(&neofb_driver);2216}2217 2218module_init(neofb_init);2219 2220#ifdef MODULE2221static void __exit neofb_exit(void)2222{2223	pci_unregister_driver(&neofb_driver);2224}2225 2226module_exit(neofb_exit);2227#endif				/* MODULE */2228