| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 1 | /* | 
 | 2 |  * linux/drivers/video/savagefb.c -- S3 Savage Framebuffer Driver | 
 | 3 |  * | 
 | 4 |  * Copyright (c) 2001-2002  Denis Oliver Kropp <dok@directfb.org> | 
 | 5 |  *                          Sven Neumann <neo@directfb.org> | 
 | 6 |  * | 
 | 7 |  * | 
 | 8 |  * Card specific code is based on XFree86's savage driver. | 
 | 9 |  * Framebuffer framework code is based on code of cyber2000fb and tdfxfb. | 
 | 10 |  * | 
 | 11 |  * This file is subject to the terms and conditions of the GNU General | 
 | 12 |  * Public License.  See the file COPYING in the main directory of this | 
 | 13 |  * archive for more details. | 
 | 14 |  * | 
 | 15 |  * 0.4.0 (neo) | 
 | 16 |  *  - hardware accelerated clear and move | 
 | 17 |  * | 
 | 18 |  * 0.3.2 (dok) | 
 | 19 |  *  - wait for vertical retrace before writing to cr67 | 
 | 20 |  *    at the beginning of savagefb_set_par | 
 | 21 |  *  - use synchronization registers cr23 and cr26 | 
 | 22 |  * | 
 | 23 |  * 0.3.1 (dok) | 
 | 24 |  *  - reset 3D engine | 
 | 25 |  *  - don't return alpha bits for 32bit format | 
 | 26 |  * | 
 | 27 |  * 0.3.0 (dok) | 
 | 28 |  *  - added WaitIdle functions for all Savage types | 
 | 29 |  *  - do WaitIdle before mode switching | 
 | 30 |  *  - code cleanup | 
 | 31 |  * | 
 | 32 |  * 0.2.0 (dok) | 
 | 33 |  *  - first working version | 
 | 34 |  * | 
 | 35 |  * | 
 | 36 |  * TODO | 
 | 37 |  * - clock validations in decode_var | 
 | 38 |  * | 
 | 39 |  * BUGS | 
 | 40 |  * - white margin on bootup | 
 | 41 |  * | 
 | 42 |  */ | 
 | 43 |  | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 44 | #include <linux/module.h> | 
 | 45 | #include <linux/kernel.h> | 
 | 46 | #include <linux/errno.h> | 
 | 47 | #include <linux/string.h> | 
 | 48 | #include <linux/mm.h> | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 49 | #include <linux/slab.h> | 
 | 50 | #include <linux/delay.h> | 
 | 51 | #include <linux/fb.h> | 
 | 52 | #include <linux/pci.h> | 
 | 53 | #include <linux/init.h> | 
 | 54 | #include <linux/console.h> | 
 | 55 |  | 
 | 56 | #include <asm/io.h> | 
 | 57 | #include <asm/irq.h> | 
 | 58 | #include <asm/pgtable.h> | 
 | 59 | #include <asm/system.h> | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 60 |  | 
 | 61 | #ifdef CONFIG_MTRR | 
 | 62 | #include <asm/mtrr.h> | 
 | 63 | #endif | 
 | 64 |  | 
 | 65 | #include "savagefb.h" | 
 | 66 |  | 
 | 67 |  | 
 | 68 | #define SAVAGEFB_VERSION "0.4.0_2.6" | 
 | 69 |  | 
 | 70 | /* --------------------------------------------------------------------- */ | 
 | 71 |  | 
 | 72 |  | 
| Jean Delvare | 3e42f0b | 2006-04-18 22:22:09 -0700 | [diff] [blame] | 73 | static char *mode_option __devinitdata = NULL; | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 74 |  | 
 | 75 | #ifdef MODULE | 
 | 76 |  | 
 | 77 | MODULE_AUTHOR("(c) 2001-2002  Denis Oliver Kropp <dok@directfb.org>"); | 
 | 78 | MODULE_LICENSE("GPL"); | 
 | 79 | MODULE_DESCRIPTION("FBDev driver for S3 Savage PCI/AGP Chips"); | 
 | 80 |  | 
 | 81 | #endif | 
 | 82 |  | 
 | 83 |  | 
 | 84 | /* --------------------------------------------------------------------- */ | 
 | 85 |  | 
| Antonino A. Daplas | 026fbe1 | 2006-06-26 00:26:36 -0700 | [diff] [blame] | 86 | static void vgaHWSeqReset(struct savagefb_par *par, int start) | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 87 | { | 
 | 88 | 	if (start) | 
| Antonino A. Daplas | 026fbe1 | 2006-06-26 00:26:36 -0700 | [diff] [blame] | 89 | 		VGAwSEQ(0x00, 0x01, par);	/* Synchronous Reset */ | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 90 | 	else | 
| Antonino A. Daplas | 026fbe1 | 2006-06-26 00:26:36 -0700 | [diff] [blame] | 91 | 		VGAwSEQ(0x00, 0x03, par);	/* End Reset */ | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 92 | } | 
 | 93 |  | 
| Antonino A. Daplas | 026fbe1 | 2006-06-26 00:26:36 -0700 | [diff] [blame] | 94 | static void vgaHWProtect(struct savagefb_par *par, int on) | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 95 | { | 
 | 96 | 	unsigned char tmp; | 
 | 97 |  | 
 | 98 | 	if (on) { | 
 | 99 | 		/* | 
 | 100 | 		 * Turn off screen and disable sequencer. | 
 | 101 | 		 */ | 
| Antonino A. Daplas | 026fbe1 | 2006-06-26 00:26:36 -0700 | [diff] [blame] | 102 | 		tmp = VGArSEQ(0x01, par); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 103 |  | 
| Antonino A. Daplas | 026fbe1 | 2006-06-26 00:26:36 -0700 | [diff] [blame] | 104 | 		vgaHWSeqReset(par, 1);	        /* start synchronous reset */ | 
 | 105 | 		VGAwSEQ(0x01, tmp | 0x20, par);/* disable the display */ | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 106 |  | 
| Antonino A. Daplas | 1cc650c | 2005-11-07 01:00:41 -0800 | [diff] [blame] | 107 | 		VGAenablePalette(par); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 108 | 	} else { | 
 | 109 | 		/* | 
 | 110 | 		 * Reenable sequencer, then turn on screen. | 
 | 111 | 		 */ | 
 | 112 |  | 
| Antonino A. Daplas | 026fbe1 | 2006-06-26 00:26:36 -0700 | [diff] [blame] | 113 | 		tmp = VGArSEQ(0x01, par); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 114 |  | 
| Antonino A. Daplas | 026fbe1 | 2006-06-26 00:26:36 -0700 | [diff] [blame] | 115 | 		VGAwSEQ(0x01, tmp & ~0x20, par);/* reenable display */ | 
 | 116 | 		vgaHWSeqReset(par, 0);	        /* clear synchronous reset */ | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 117 |  | 
| Antonino A. Daplas | 1cc650c | 2005-11-07 01:00:41 -0800 | [diff] [blame] | 118 | 		VGAdisablePalette(par); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 119 | 	} | 
 | 120 | } | 
 | 121 |  | 
| Antonino A. Daplas | 026fbe1 | 2006-06-26 00:26:36 -0700 | [diff] [blame] | 122 | static void vgaHWRestore(struct savagefb_par  *par, struct savage_reg *reg) | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 123 | { | 
 | 124 | 	int i; | 
 | 125 |  | 
| Antonino A. Daplas | 026fbe1 | 2006-06-26 00:26:36 -0700 | [diff] [blame] | 126 | 	VGAwMISC(reg->MiscOutReg, par); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 127 |  | 
 | 128 | 	for (i = 1; i < 5; i++) | 
| Antonino A. Daplas | 026fbe1 | 2006-06-26 00:26:36 -0700 | [diff] [blame] | 129 | 		VGAwSEQ(i, reg->Sequencer[i], par); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 130 |  | 
 | 131 | 	/* Ensure CRTC registers 0-7 are unlocked by clearing bit 7 or | 
 | 132 | 	   CRTC[17] */ | 
| Antonino A. Daplas | 026fbe1 | 2006-06-26 00:26:36 -0700 | [diff] [blame] | 133 | 	VGAwCR(17, reg->CRTC[17] & ~0x80, par); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 134 |  | 
 | 135 | 	for (i = 0; i < 25; i++) | 
| Antonino A. Daplas | 026fbe1 | 2006-06-26 00:26:36 -0700 | [diff] [blame] | 136 | 		VGAwCR(i, reg->CRTC[i], par); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 137 |  | 
 | 138 | 	for (i = 0; i < 9; i++) | 
| Antonino A. Daplas | 026fbe1 | 2006-06-26 00:26:36 -0700 | [diff] [blame] | 139 | 		VGAwGR(i, reg->Graphics[i], par); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 140 |  | 
| Antonino A. Daplas | 1cc650c | 2005-11-07 01:00:41 -0800 | [diff] [blame] | 141 | 	VGAenablePalette(par); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 142 |  | 
 | 143 | 	for (i = 0; i < 21; i++) | 
| Antonino A. Daplas | 026fbe1 | 2006-06-26 00:26:36 -0700 | [diff] [blame] | 144 | 		VGAwATTR(i, reg->Attribute[i], par); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 145 |  | 
| Antonino A. Daplas | 1cc650c | 2005-11-07 01:00:41 -0800 | [diff] [blame] | 146 | 	VGAdisablePalette(par); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 147 | } | 
 | 148 |  | 
| Antonino A. Daplas | 026fbe1 | 2006-06-26 00:26:36 -0700 | [diff] [blame] | 149 | static void vgaHWInit(struct fb_var_screeninfo *var, | 
 | 150 | 		      struct savagefb_par            *par, | 
 | 151 | 		      struct xtimings                *timings, | 
 | 152 | 		      struct savage_reg              *reg) | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 153 | { | 
| Antonino A. Daplas | 2356614 | 2006-06-26 00:26:23 -0700 | [diff] [blame] | 154 | 	reg->MiscOutReg = 0x23; | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 155 |  | 
 | 156 | 	if (!(timings->sync & FB_SYNC_HOR_HIGH_ACT)) | 
| Antonino A. Daplas | 2356614 | 2006-06-26 00:26:23 -0700 | [diff] [blame] | 157 | 		reg->MiscOutReg |= 0x40; | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 158 |  | 
 | 159 | 	if (!(timings->sync & FB_SYNC_VERT_HIGH_ACT)) | 
| Antonino A. Daplas | 2356614 | 2006-06-26 00:26:23 -0700 | [diff] [blame] | 160 | 		reg->MiscOutReg |= 0x80; | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 161 |  | 
 | 162 | 	/* | 
 | 163 | 	 * Time Sequencer | 
 | 164 | 	 */ | 
| Antonino A. Daplas | 2356614 | 2006-06-26 00:26:23 -0700 | [diff] [blame] | 165 | 	reg->Sequencer[0x00] = 0x00; | 
 | 166 | 	reg->Sequencer[0x01] = 0x01; | 
 | 167 | 	reg->Sequencer[0x02] = 0x0F; | 
 | 168 | 	reg->Sequencer[0x03] = 0x00;          /* Font select */ | 
 | 169 | 	reg->Sequencer[0x04] = 0x0E;          /* Misc */ | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 170 |  | 
 | 171 | 	/* | 
 | 172 | 	 * CRTC Controller | 
 | 173 | 	 */ | 
| Antonino A. Daplas | 2356614 | 2006-06-26 00:26:23 -0700 | [diff] [blame] | 174 | 	reg->CRTC[0x00] = (timings->HTotal >> 3) - 5; | 
 | 175 | 	reg->CRTC[0x01] = (timings->HDisplay >> 3) - 1; | 
 | 176 | 	reg->CRTC[0x02] = (timings->HSyncStart >> 3) - 1; | 
 | 177 | 	reg->CRTC[0x03] = (((timings->HSyncEnd >> 3)  - 1) & 0x1f) | 0x80; | 
 | 178 | 	reg->CRTC[0x04] = (timings->HSyncStart >> 3); | 
 | 179 | 	reg->CRTC[0x05] = ((((timings->HSyncEnd >> 3) - 1) & 0x20) << 2) | | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 180 | 		(((timings->HSyncEnd >> 3)) & 0x1f); | 
| Antonino A. Daplas | 2356614 | 2006-06-26 00:26:23 -0700 | [diff] [blame] | 181 | 	reg->CRTC[0x06] = (timings->VTotal - 2) & 0xFF; | 
 | 182 | 	reg->CRTC[0x07] = (((timings->VTotal - 2) & 0x100) >> 8) | | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 183 | 		(((timings->VDisplay - 1) & 0x100) >> 7) | | 
 | 184 | 		((timings->VSyncStart & 0x100) >> 6) | | 
 | 185 | 		(((timings->VSyncStart - 1) & 0x100) >> 5) | | 
 | 186 | 		0x10 | | 
 | 187 | 		(((timings->VTotal - 2) & 0x200) >> 4) | | 
 | 188 | 		(((timings->VDisplay - 1) & 0x200) >> 3) | | 
 | 189 | 		((timings->VSyncStart & 0x200) >> 2); | 
| Antonino A. Daplas | 2356614 | 2006-06-26 00:26:23 -0700 | [diff] [blame] | 190 | 	reg->CRTC[0x08] = 0x00; | 
 | 191 | 	reg->CRTC[0x09] = (((timings->VSyncStart - 1) & 0x200) >> 4) | 0x40; | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 192 |  | 
 | 193 | 	if (timings->dblscan) | 
| Antonino A. Daplas | 2356614 | 2006-06-26 00:26:23 -0700 | [diff] [blame] | 194 | 		reg->CRTC[0x09] |= 0x80; | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 195 |  | 
| Antonino A. Daplas | 2356614 | 2006-06-26 00:26:23 -0700 | [diff] [blame] | 196 | 	reg->CRTC[0x0a] = 0x00; | 
 | 197 | 	reg->CRTC[0x0b] = 0x00; | 
 | 198 | 	reg->CRTC[0x0c] = 0x00; | 
 | 199 | 	reg->CRTC[0x0d] = 0x00; | 
 | 200 | 	reg->CRTC[0x0e] = 0x00; | 
 | 201 | 	reg->CRTC[0x0f] = 0x00; | 
 | 202 | 	reg->CRTC[0x10] = timings->VSyncStart & 0xff; | 
 | 203 | 	reg->CRTC[0x11] = (timings->VSyncEnd & 0x0f) | 0x20; | 
 | 204 | 	reg->CRTC[0x12] = (timings->VDisplay - 1) & 0xff; | 
 | 205 | 	reg->CRTC[0x13] = var->xres_virtual >> 4; | 
 | 206 | 	reg->CRTC[0x14] = 0x00; | 
 | 207 | 	reg->CRTC[0x15] = (timings->VSyncStart - 1) & 0xff; | 
 | 208 | 	reg->CRTC[0x16] = (timings->VSyncEnd - 1) & 0xff; | 
 | 209 | 	reg->CRTC[0x17] = 0xc3; | 
 | 210 | 	reg->CRTC[0x18] = 0xff; | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 211 |  | 
 | 212 | 	/* | 
 | 213 | 	 * are these unnecessary? | 
 | 214 | 	 * vgaHWHBlankKGA(mode, regp, 0, KGA_FIX_OVERSCAN|KGA_ENABLE_ON_ZERO); | 
 | 215 | 	 * vgaHWVBlankKGA(mode, regp, 0, KGA_FIX_OVERSCAN|KGA_ENABLE_ON_ZERO); | 
 | 216 | 	 */ | 
 | 217 |  | 
 | 218 | 	/* | 
 | 219 | 	 * Graphics Display Controller | 
 | 220 | 	 */ | 
| Antonino A. Daplas | 2356614 | 2006-06-26 00:26:23 -0700 | [diff] [blame] | 221 | 	reg->Graphics[0x00] = 0x00; | 
 | 222 | 	reg->Graphics[0x01] = 0x00; | 
 | 223 | 	reg->Graphics[0x02] = 0x00; | 
 | 224 | 	reg->Graphics[0x03] = 0x00; | 
 | 225 | 	reg->Graphics[0x04] = 0x00; | 
 | 226 | 	reg->Graphics[0x05] = 0x40; | 
 | 227 | 	reg->Graphics[0x06] = 0x05;   /* only map 64k VGA memory !!!! */ | 
 | 228 | 	reg->Graphics[0x07] = 0x0F; | 
 | 229 | 	reg->Graphics[0x08] = 0xFF; | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 230 |  | 
 | 231 |  | 
| Antonino A. Daplas | 2356614 | 2006-06-26 00:26:23 -0700 | [diff] [blame] | 232 | 	reg->Attribute[0x00]  = 0x00; /* standard colormap translation */ | 
 | 233 | 	reg->Attribute[0x01]  = 0x01; | 
 | 234 | 	reg->Attribute[0x02]  = 0x02; | 
 | 235 | 	reg->Attribute[0x03]  = 0x03; | 
 | 236 | 	reg->Attribute[0x04]  = 0x04; | 
 | 237 | 	reg->Attribute[0x05]  = 0x05; | 
 | 238 | 	reg->Attribute[0x06]  = 0x06; | 
 | 239 | 	reg->Attribute[0x07]  = 0x07; | 
 | 240 | 	reg->Attribute[0x08]  = 0x08; | 
 | 241 | 	reg->Attribute[0x09]  = 0x09; | 
 | 242 | 	reg->Attribute[0x0a] = 0x0A; | 
 | 243 | 	reg->Attribute[0x0b] = 0x0B; | 
 | 244 | 	reg->Attribute[0x0c] = 0x0C; | 
 | 245 | 	reg->Attribute[0x0d] = 0x0D; | 
 | 246 | 	reg->Attribute[0x0e] = 0x0E; | 
 | 247 | 	reg->Attribute[0x0f] = 0x0F; | 
 | 248 | 	reg->Attribute[0x10] = 0x41; | 
 | 249 | 	reg->Attribute[0x11] = 0xFF; | 
 | 250 | 	reg->Attribute[0x12] = 0x0F; | 
 | 251 | 	reg->Attribute[0x13] = 0x00; | 
 | 252 | 	reg->Attribute[0x14] = 0x00; | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 253 | } | 
 | 254 |  | 
 | 255 | /* -------------------- Hardware specific routines ------------------------- */ | 
 | 256 |  | 
 | 257 | /* | 
 | 258 |  * Hardware Acceleration for SavageFB | 
 | 259 |  */ | 
 | 260 |  | 
 | 261 | /* Wait for fifo space */ | 
 | 262 | static void | 
 | 263 | savage3D_waitfifo(struct savagefb_par *par, int space) | 
 | 264 | { | 
 | 265 | 	int slots = MAXFIFO - space; | 
 | 266 |  | 
| Antonino A. Daplas | 1cc650c | 2005-11-07 01:00:41 -0800 | [diff] [blame] | 267 | 	while ((savage_in32(0x48C00, par) & 0x0000ffff) > slots); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 268 | } | 
 | 269 |  | 
 | 270 | static void | 
 | 271 | savage4_waitfifo(struct savagefb_par *par, int space) | 
 | 272 | { | 
 | 273 | 	int slots = MAXFIFO - space; | 
 | 274 |  | 
| Antonino A. Daplas | 1cc650c | 2005-11-07 01:00:41 -0800 | [diff] [blame] | 275 | 	while ((savage_in32(0x48C60, par) & 0x001fffff) > slots); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 276 | } | 
 | 277 |  | 
 | 278 | static void | 
 | 279 | savage2000_waitfifo(struct savagefb_par *par, int space) | 
 | 280 | { | 
 | 281 | 	int slots = MAXFIFO - space; | 
 | 282 |  | 
| Antonino A. Daplas | 1cc650c | 2005-11-07 01:00:41 -0800 | [diff] [blame] | 283 | 	while ((savage_in32(0x48C60, par) & 0x0000ffff) > slots); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 284 | } | 
 | 285 |  | 
 | 286 | /* Wait for idle accelerator */ | 
 | 287 | static void | 
 | 288 | savage3D_waitidle(struct savagefb_par *par) | 
 | 289 | { | 
| Antonino A. Daplas | 1cc650c | 2005-11-07 01:00:41 -0800 | [diff] [blame] | 290 | 	while ((savage_in32(0x48C00, par) & 0x0008ffff) != 0x80000); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 291 | } | 
 | 292 |  | 
 | 293 | static void | 
 | 294 | savage4_waitidle(struct savagefb_par *par) | 
 | 295 | { | 
| Antonino A. Daplas | 1cc650c | 2005-11-07 01:00:41 -0800 | [diff] [blame] | 296 | 	while ((savage_in32(0x48C60, par) & 0x00a00000) != 0x00a00000); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 297 | } | 
 | 298 |  | 
 | 299 | static void | 
 | 300 | savage2000_waitidle(struct savagefb_par *par) | 
 | 301 | { | 
| Antonino A. Daplas | 1cc650c | 2005-11-07 01:00:41 -0800 | [diff] [blame] | 302 | 	while ((savage_in32(0x48C60, par) & 0x009fffff)); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 303 | } | 
 | 304 |  | 
| Antonino A. Daplas | f8020dc | 2006-06-26 00:26:24 -0700 | [diff] [blame] | 305 | #ifdef CONFIG_FB_SAVAGE_ACCEL | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 306 | static void | 
| Antonino A. Daplas | 026fbe1 | 2006-06-26 00:26:36 -0700 | [diff] [blame] | 307 | SavageSetup2DEngine(struct savagefb_par  *par) | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 308 | { | 
 | 309 | 	unsigned long GlobalBitmapDescriptor; | 
 | 310 |  | 
 | 311 | 	GlobalBitmapDescriptor = 1 | 8 | BCI_BD_BW_DISABLE; | 
| Antonino A. Daplas | 026fbe1 | 2006-06-26 00:26:36 -0700 | [diff] [blame] | 312 | 	BCI_BD_SET_BPP(GlobalBitmapDescriptor, par->depth); | 
 | 313 | 	BCI_BD_SET_STRIDE(GlobalBitmapDescriptor, par->vwidth); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 314 |  | 
 | 315 | 	switch(par->chip) { | 
 | 316 | 	case S3_SAVAGE3D: | 
 | 317 | 	case S3_SAVAGE_MX: | 
 | 318 | 		/* Disable BCI */ | 
| Antonino A. Daplas | 1cc650c | 2005-11-07 01:00:41 -0800 | [diff] [blame] | 319 | 		savage_out32(0x48C18, savage_in32(0x48C18, par) & 0x3FF0, par); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 320 | 		/* Setup BCI command overflow buffer */ | 
| Antonino A. Daplas | 1cc650c | 2005-11-07 01:00:41 -0800 | [diff] [blame] | 321 | 		savage_out32(0x48C14, | 
 | 322 | 			     (par->cob_offset >> 11) | (par->cob_index << 29), | 
 | 323 | 			     par); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 324 | 		/* Program shadow status update. */ | 
| Antonino A. Daplas | 1cc650c | 2005-11-07 01:00:41 -0800 | [diff] [blame] | 325 | 		savage_out32(0x48C10, 0x78207220, par); | 
 | 326 | 		savage_out32(0x48C0C, 0, par); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 327 | 		/* Enable BCI and command overflow buffer */ | 
| Antonino A. Daplas | 1cc650c | 2005-11-07 01:00:41 -0800 | [diff] [blame] | 328 | 		savage_out32(0x48C18, savage_in32(0x48C18, par) | 0x0C, par); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 329 | 		break; | 
 | 330 | 	case S3_SAVAGE4: | 
 | 331 | 	case S3_PROSAVAGE: | 
 | 332 | 	case S3_SUPERSAVAGE: | 
 | 333 | 		/* Disable BCI */ | 
| Antonino A. Daplas | 1cc650c | 2005-11-07 01:00:41 -0800 | [diff] [blame] | 334 | 		savage_out32(0x48C18, savage_in32(0x48C18, par) & 0x3FF0, par); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 335 | 		/* Program shadow status update */ | 
| Antonino A. Daplas | 1cc650c | 2005-11-07 01:00:41 -0800 | [diff] [blame] | 336 | 		savage_out32(0x48C10, 0x00700040, par); | 
 | 337 | 		savage_out32(0x48C0C, 0, par); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 338 | 		/* Enable BCI without the COB */ | 
| Antonino A. Daplas | 1cc650c | 2005-11-07 01:00:41 -0800 | [diff] [blame] | 339 | 		savage_out32(0x48C18, savage_in32(0x48C18, par) | 0x08, par); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 340 | 		break; | 
 | 341 | 	case S3_SAVAGE2000: | 
 | 342 | 		/* Disable BCI */ | 
| Antonino A. Daplas | 1cc650c | 2005-11-07 01:00:41 -0800 | [diff] [blame] | 343 | 		savage_out32(0x48C18, 0, par); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 344 | 		/* Setup BCI command overflow buffer */ | 
| Antonino A. Daplas | 1cc650c | 2005-11-07 01:00:41 -0800 | [diff] [blame] | 345 | 		savage_out32(0x48C18, | 
 | 346 | 			     (par->cob_offset >> 7) | (par->cob_index), | 
 | 347 | 			     par); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 348 | 		/* Disable shadow status update */ | 
| Antonino A. Daplas | 1cc650c | 2005-11-07 01:00:41 -0800 | [diff] [blame] | 349 | 		savage_out32(0x48A30, 0, par); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 350 | 		/* Enable BCI and command overflow buffer */ | 
| Antonino A. Daplas | 1cc650c | 2005-11-07 01:00:41 -0800 | [diff] [blame] | 351 | 		savage_out32(0x48C18, savage_in32(0x48C18, par) | 0x00280000, | 
 | 352 | 			     par); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 353 | 		break; | 
 | 354 | 	    default: | 
 | 355 | 		break; | 
 | 356 | 	} | 
 | 357 | 	/* Turn on 16-bit register access. */ | 
| Antonino A. Daplas | 1cc650c | 2005-11-07 01:00:41 -0800 | [diff] [blame] | 358 | 	vga_out8(0x3d4, 0x31, par); | 
 | 359 | 	vga_out8(0x3d5, 0x0c, par); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 360 |  | 
 | 361 | 	/* Set stride to use GBD. */ | 
| Antonino A. Daplas | 026fbe1 | 2006-06-26 00:26:36 -0700 | [diff] [blame] | 362 | 	vga_out8(0x3d4, 0x50, par); | 
 | 363 | 	vga_out8(0x3d5, vga_in8(0x3d5, par) | 0xC1, par); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 364 |  | 
 | 365 | 	/* Enable 2D engine. */ | 
| Antonino A. Daplas | 026fbe1 | 2006-06-26 00:26:36 -0700 | [diff] [blame] | 366 | 	vga_out8(0x3d4, 0x40, par); | 
 | 367 | 	vga_out8(0x3d5, 0x01, par); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 368 |  | 
| Antonino A. Daplas | 026fbe1 | 2006-06-26 00:26:36 -0700 | [diff] [blame] | 369 | 	savage_out32(MONO_PAT_0, ~0, par); | 
 | 370 | 	savage_out32(MONO_PAT_1, ~0, par); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 371 |  | 
 | 372 | 	/* Setup plane masks */ | 
| Antonino A. Daplas | 026fbe1 | 2006-06-26 00:26:36 -0700 | [diff] [blame] | 373 | 	savage_out32(0x8128, ~0, par); /* enable all write planes */ | 
 | 374 | 	savage_out32(0x812C, ~0, par); /* enable all read planes */ | 
 | 375 | 	savage_out16(0x8134, 0x27, par); | 
 | 376 | 	savage_out16(0x8136, 0x07, par); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 377 |  | 
 | 378 | 	/* Now set the GBD */ | 
 | 379 | 	par->bci_ptr = 0; | 
| Antonino A. Daplas | 026fbe1 | 2006-06-26 00:26:36 -0700 | [diff] [blame] | 380 | 	par->SavageWaitFifo(par, 4); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 381 |  | 
| Antonino A. Daplas | 026fbe1 | 2006-06-26 00:26:36 -0700 | [diff] [blame] | 382 | 	BCI_SEND(BCI_CMD_SETREG | (1 << 16) | BCI_GBD1); | 
 | 383 | 	BCI_SEND(0); | 
 | 384 | 	BCI_SEND(BCI_CMD_SETREG | (1 << 16) | BCI_GBD2); | 
 | 385 | 	BCI_SEND(GlobalBitmapDescriptor); | 
| Antonino A. Daplas | 5b60046 | 2007-03-16 13:38:18 -0800 | [diff] [blame] | 386 |  | 
 | 387 | 	/* | 
 | 388 | 	 * I don't know why, sending this twice fixes the intial black screen, | 
 | 389 | 	 * prevents X from crashing at least in Toshiba laptops with SavageIX. | 
 | 390 | 	 * --Tony | 
 | 391 | 	 */ | 
 | 392 | 	par->bci_ptr = 0; | 
 | 393 | 	par->SavageWaitFifo(par, 4); | 
 | 394 |  | 
 | 395 | 	BCI_SEND(BCI_CMD_SETREG | (1 << 16) | BCI_GBD1); | 
 | 396 | 	BCI_SEND(0); | 
 | 397 | 	BCI_SEND(BCI_CMD_SETREG | (1 << 16) | BCI_GBD2); | 
 | 398 | 	BCI_SEND(GlobalBitmapDescriptor); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 399 | } | 
 | 400 |  | 
| Antonino A. Daplas | f8020dc | 2006-06-26 00:26:24 -0700 | [diff] [blame] | 401 | static void savagefb_set_clip(struct fb_info *info) | 
 | 402 | { | 
 | 403 | 	struct savagefb_par *par = info->par; | 
 | 404 | 	int cmd; | 
 | 405 |  | 
 | 406 | 	cmd = BCI_CMD_NOP | BCI_CMD_CLIP_NEW; | 
 | 407 | 	par->bci_ptr = 0; | 
 | 408 | 	par->SavageWaitFifo(par,3); | 
 | 409 | 	BCI_SEND(cmd); | 
 | 410 | 	BCI_SEND(BCI_CLIP_TL(0, 0)); | 
 | 411 | 	BCI_SEND(BCI_CLIP_BR(0xfff, 0xfff)); | 
 | 412 | } | 
 | 413 | #else | 
| Antonino A. Daplas | 026fbe1 | 2006-06-26 00:26:36 -0700 | [diff] [blame] | 414 | static void SavageSetup2DEngine(struct savagefb_par  *par) {} | 
| Antonino A. Daplas | f8020dc | 2006-06-26 00:26:24 -0700 | [diff] [blame] | 415 |  | 
 | 416 | #endif | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 417 |  | 
 | 418 | static void SavageCalcClock(long freq, int min_m, int min_n1, int max_n1, | 
 | 419 | 			    int min_n2, int max_n2, long freq_min, | 
 | 420 | 			    long freq_max, unsigned int *mdiv, | 
 | 421 | 			    unsigned int *ndiv, unsigned int *r) | 
 | 422 | { | 
 | 423 | 	long diff, best_diff; | 
 | 424 | 	unsigned int m; | 
 | 425 | 	unsigned char n1, n2, best_n1=16+2, best_n2=2, best_m=125+2; | 
 | 426 |  | 
 | 427 | 	if (freq < freq_min / (1 << max_n2)) { | 
| Antonino A. Daplas | 026fbe1 | 2006-06-26 00:26:36 -0700 | [diff] [blame] | 428 | 		printk(KERN_ERR "invalid frequency %ld Khz\n", freq); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 429 | 		freq = freq_min / (1 << max_n2); | 
 | 430 | 	} | 
 | 431 | 	if (freq > freq_max / (1 << min_n2)) { | 
| Antonino A. Daplas | 026fbe1 | 2006-06-26 00:26:36 -0700 | [diff] [blame] | 432 | 		printk(KERN_ERR "invalid frequency %ld Khz\n", freq); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 433 | 		freq = freq_max / (1 << min_n2); | 
 | 434 | 	} | 
 | 435 |  | 
 | 436 | 	/* work out suitable timings */ | 
 | 437 | 	best_diff = freq; | 
 | 438 |  | 
 | 439 | 	for (n2=min_n2; n2<=max_n2; n2++) { | 
 | 440 | 		for (n1=min_n1+2; n1<=max_n1+2; n1++) { | 
 | 441 | 			m = (freq * n1 * (1 << n2) + HALF_BASE_FREQ) / | 
 | 442 | 				BASE_FREQ; | 
 | 443 | 			if (m < min_m+2 || m > 127+2) | 
 | 444 | 				continue; | 
 | 445 | 			if ((m * BASE_FREQ >= freq_min * n1) && | 
 | 446 | 			    (m * BASE_FREQ <= freq_max * n1)) { | 
 | 447 | 				diff = freq * (1 << n2) * n1 - BASE_FREQ * m; | 
 | 448 | 				if (diff < 0) | 
 | 449 | 					diff = -diff; | 
 | 450 | 				if (diff < best_diff) { | 
 | 451 | 					best_diff = diff; | 
 | 452 | 					best_m = m; | 
 | 453 | 					best_n1 = n1; | 
 | 454 | 					best_n2 = n2; | 
 | 455 | 				} | 
 | 456 | 			} | 
 | 457 | 		} | 
 | 458 | 	} | 
 | 459 |  | 
 | 460 | 	*ndiv = best_n1 - 2; | 
 | 461 | 	*r = best_n2; | 
 | 462 | 	*mdiv = best_m - 2; | 
 | 463 | } | 
 | 464 |  | 
 | 465 | static int common_calc_clock(long freq, int min_m, int min_n1, int max_n1, | 
 | 466 | 			     int min_n2, int max_n2, long freq_min, | 
 | 467 | 			     long freq_max, unsigned char *mdiv, | 
 | 468 | 			     unsigned char *ndiv) | 
 | 469 | { | 
 | 470 | 	long diff, best_diff; | 
 | 471 | 	unsigned int m; | 
 | 472 | 	unsigned char n1, n2; | 
 | 473 | 	unsigned char best_n1 = 16+2, best_n2 = 2, best_m = 125+2; | 
 | 474 |  | 
 | 475 | 	best_diff = freq; | 
 | 476 |  | 
 | 477 | 	for (n2 = min_n2; n2 <= max_n2; n2++) { | 
 | 478 | 		for (n1 = min_n1+2; n1 <= max_n1+2; n1++) { | 
 | 479 | 			m = (freq * n1 * (1 << n2) + HALF_BASE_FREQ) / | 
 | 480 | 				BASE_FREQ; | 
 | 481 | 			if (m < min_m + 2 || m > 127+2) | 
 | 482 | 				continue; | 
| Antonino A. Daplas | 026fbe1 | 2006-06-26 00:26:36 -0700 | [diff] [blame] | 483 | 			if ((m * BASE_FREQ >= freq_min * n1) && | 
 | 484 | 			    (m * BASE_FREQ <= freq_max * n1)) { | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 485 | 				diff = freq * (1 << n2) * n1 - BASE_FREQ * m; | 
| Antonino A. Daplas | 026fbe1 | 2006-06-26 00:26:36 -0700 | [diff] [blame] | 486 | 				if (diff < 0) | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 487 | 					diff = -diff; | 
| Antonino A. Daplas | 026fbe1 | 2006-06-26 00:26:36 -0700 | [diff] [blame] | 488 | 				if (diff < best_diff) { | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 489 | 					best_diff = diff; | 
 | 490 | 					best_m = m; | 
 | 491 | 					best_n1 = n1; | 
 | 492 | 					best_n2 = n2; | 
 | 493 | 				} | 
 | 494 | 			} | 
 | 495 | 		} | 
 | 496 | 	} | 
 | 497 |  | 
| Antonino A. Daplas | 026fbe1 | 2006-06-26 00:26:36 -0700 | [diff] [blame] | 498 | 	if (max_n1 == 63) | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 499 | 		*ndiv = (best_n1 - 2) | (best_n2 << 6); | 
 | 500 | 	else | 
 | 501 | 		*ndiv = (best_n1 - 2) | (best_n2 << 5); | 
 | 502 |  | 
 | 503 | 	*mdiv = best_m - 2; | 
 | 504 |  | 
 | 505 | 	return 0; | 
 | 506 | } | 
 | 507 |  | 
 | 508 | #ifdef SAVAGEFB_DEBUG | 
 | 509 | /* This function is used to debug, it prints out the contents of s3 regs */ | 
 | 510 |  | 
| Antonino A. Daplas | d8ad7e0 | 2007-03-16 13:38:18 -0800 | [diff] [blame] | 511 | static void SavagePrintRegs(struct savagefb_par *par) | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 512 | { | 
 | 513 | 	unsigned char i; | 
 | 514 | 	int vgaCRIndex = 0x3d4; | 
 | 515 | 	int vgaCRReg = 0x3d5; | 
 | 516 |  | 
 | 517 | 	printk(KERN_DEBUG "SR    x0 x1 x2 x3 x4 x5 x6 x7 x8 x9 xA xB xC xD xE " | 
| Antonino A. Daplas | 026fbe1 | 2006-06-26 00:26:36 -0700 | [diff] [blame] | 518 | 	       "xF"); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 519 |  | 
| Antonino A. Daplas | 026fbe1 | 2006-06-26 00:26:36 -0700 | [diff] [blame] | 520 | 	for (i = 0; i < 0x70; i++) { | 
 | 521 | 		if (!(i % 16)) | 
 | 522 | 			printk(KERN_DEBUG "\nSR%xx ", i >> 4); | 
 | 523 | 		vga_out8(0x3c4, i, par); | 
 | 524 | 		printk(KERN_DEBUG " %02x", vga_in8(0x3c5, par)); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 525 | 	} | 
 | 526 |  | 
 | 527 | 	printk(KERN_DEBUG "\n\nCR    x0 x1 x2 x3 x4 x5 x6 x7 x8 x9 xA xB xC " | 
| Antonino A. Daplas | 026fbe1 | 2006-06-26 00:26:36 -0700 | [diff] [blame] | 528 | 	       "xD xE xF"); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 529 |  | 
| Antonino A. Daplas | 026fbe1 | 2006-06-26 00:26:36 -0700 | [diff] [blame] | 530 | 	for (i = 0; i < 0xB7; i++) { | 
 | 531 | 		if (!(i % 16)) | 
 | 532 | 			printk(KERN_DEBUG "\nCR%xx ", i >> 4); | 
 | 533 | 		vga_out8(vgaCRIndex, i, par); | 
 | 534 | 		printk(KERN_DEBUG " %02x", vga_in8(vgaCRReg, par)); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 535 | 	} | 
 | 536 |  | 
 | 537 | 	printk(KERN_DEBUG "\n\n"); | 
 | 538 | } | 
 | 539 | #endif | 
 | 540 |  | 
 | 541 | /* --------------------------------------------------------------------- */ | 
 | 542 |  | 
| Antonino A. Daplas | 2356614 | 2006-06-26 00:26:23 -0700 | [diff] [blame] | 543 | static void savage_get_default_par(struct savagefb_par *par, struct savage_reg *reg) | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 544 | { | 
 | 545 | 	unsigned char cr3a, cr53, cr66; | 
 | 546 |  | 
| Antonino A. Daplas | 026fbe1 | 2006-06-26 00:26:36 -0700 | [diff] [blame] | 547 | 	vga_out16(0x3d4, 0x4838, par); | 
 | 548 | 	vga_out16(0x3d4, 0xa039, par); | 
 | 549 | 	vga_out16(0x3c4, 0x0608, par); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 550 |  | 
| Antonino A. Daplas | 026fbe1 | 2006-06-26 00:26:36 -0700 | [diff] [blame] | 551 | 	vga_out8(0x3d4, 0x66, par); | 
 | 552 | 	cr66 = vga_in8(0x3d5, par); | 
 | 553 | 	vga_out8(0x3d5, cr66 | 0x80, par); | 
 | 554 | 	vga_out8(0x3d4, 0x3a, par); | 
 | 555 | 	cr3a = vga_in8(0x3d5, par); | 
 | 556 | 	vga_out8(0x3d5, cr3a | 0x80, par); | 
 | 557 | 	vga_out8(0x3d4, 0x53, par); | 
 | 558 | 	cr53 = vga_in8(0x3d5, par); | 
 | 559 | 	vga_out8(0x3d5, cr53 & 0x7f, par); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 560 |  | 
| Antonino A. Daplas | 026fbe1 | 2006-06-26 00:26:36 -0700 | [diff] [blame] | 561 | 	vga_out8(0x3d4, 0x66, par); | 
 | 562 | 	vga_out8(0x3d5, cr66, par); | 
 | 563 | 	vga_out8(0x3d4, 0x3a, par); | 
 | 564 | 	vga_out8(0x3d5, cr3a, par); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 565 |  | 
| Antonino A. Daplas | 026fbe1 | 2006-06-26 00:26:36 -0700 | [diff] [blame] | 566 | 	vga_out8(0x3d4, 0x66, par); | 
 | 567 | 	vga_out8(0x3d5, cr66, par); | 
 | 568 | 	vga_out8(0x3d4, 0x3a, par); | 
 | 569 | 	vga_out8(0x3d5, cr3a, par); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 570 |  | 
 | 571 | 	/* unlock extended seq regs */ | 
| Antonino A. Daplas | 026fbe1 | 2006-06-26 00:26:36 -0700 | [diff] [blame] | 572 | 	vga_out8(0x3c4, 0x08, par); | 
 | 573 | 	reg->SR08 = vga_in8(0x3c5, par); | 
 | 574 | 	vga_out8(0x3c5, 0x06, par); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 575 |  | 
 | 576 | 	/* now save all the extended regs we need */ | 
| Antonino A. Daplas | 026fbe1 | 2006-06-26 00:26:36 -0700 | [diff] [blame] | 577 | 	vga_out8(0x3d4, 0x31, par); | 
 | 578 | 	reg->CR31 = vga_in8(0x3d5, par); | 
 | 579 | 	vga_out8(0x3d4, 0x32, par); | 
 | 580 | 	reg->CR32 = vga_in8(0x3d5, par); | 
 | 581 | 	vga_out8(0x3d4, 0x34, par); | 
 | 582 | 	reg->CR34 = vga_in8(0x3d5, par); | 
 | 583 | 	vga_out8(0x3d4, 0x36, par); | 
 | 584 | 	reg->CR36 = vga_in8(0x3d5, par); | 
 | 585 | 	vga_out8(0x3d4, 0x3a, par); | 
 | 586 | 	reg->CR3A = vga_in8(0x3d5, par); | 
 | 587 | 	vga_out8(0x3d4, 0x40, par); | 
 | 588 | 	reg->CR40 = vga_in8(0x3d5, par); | 
 | 589 | 	vga_out8(0x3d4, 0x42, par); | 
 | 590 | 	reg->CR42 = vga_in8(0x3d5, par); | 
 | 591 | 	vga_out8(0x3d4, 0x45, par); | 
 | 592 | 	reg->CR45 = vga_in8(0x3d5, par); | 
 | 593 | 	vga_out8(0x3d4, 0x50, par); | 
 | 594 | 	reg->CR50 = vga_in8(0x3d5, par); | 
 | 595 | 	vga_out8(0x3d4, 0x51, par); | 
 | 596 | 	reg->CR51 = vga_in8(0x3d5, par); | 
 | 597 | 	vga_out8(0x3d4, 0x53, par); | 
 | 598 | 	reg->CR53 = vga_in8(0x3d5, par); | 
 | 599 | 	vga_out8(0x3d4, 0x58, par); | 
 | 600 | 	reg->CR58 = vga_in8(0x3d5, par); | 
 | 601 | 	vga_out8(0x3d4, 0x60, par); | 
 | 602 | 	reg->CR60 = vga_in8(0x3d5, par); | 
 | 603 | 	vga_out8(0x3d4, 0x66, par); | 
 | 604 | 	reg->CR66 = vga_in8(0x3d5, par); | 
 | 605 | 	vga_out8(0x3d4, 0x67, par); | 
 | 606 | 	reg->CR67 = vga_in8(0x3d5, par); | 
 | 607 | 	vga_out8(0x3d4, 0x68, par); | 
 | 608 | 	reg->CR68 = vga_in8(0x3d5, par); | 
 | 609 | 	vga_out8(0x3d4, 0x69, par); | 
 | 610 | 	reg->CR69 = vga_in8(0x3d5, par); | 
 | 611 | 	vga_out8(0x3d4, 0x6f, par); | 
 | 612 | 	reg->CR6F = vga_in8(0x3d5, par); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 613 |  | 
| Antonino A. Daplas | 026fbe1 | 2006-06-26 00:26:36 -0700 | [diff] [blame] | 614 | 	vga_out8(0x3d4, 0x33, par); | 
 | 615 | 	reg->CR33 = vga_in8(0x3d5, par); | 
 | 616 | 	vga_out8(0x3d4, 0x86, par); | 
 | 617 | 	reg->CR86 = vga_in8(0x3d5, par); | 
 | 618 | 	vga_out8(0x3d4, 0x88, par); | 
 | 619 | 	reg->CR88 = vga_in8(0x3d5, par); | 
 | 620 | 	vga_out8(0x3d4, 0x90, par); | 
 | 621 | 	reg->CR90 = vga_in8(0x3d5, par); | 
 | 622 | 	vga_out8(0x3d4, 0x91, par); | 
 | 623 | 	reg->CR91 = vga_in8(0x3d5, par); | 
 | 624 | 	vga_out8(0x3d4, 0xb0, par); | 
 | 625 | 	reg->CRB0 = vga_in8(0x3d5, par) | 0x80; | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 626 |  | 
 | 627 | 	/* extended mode timing regs */ | 
| Antonino A. Daplas | 026fbe1 | 2006-06-26 00:26:36 -0700 | [diff] [blame] | 628 | 	vga_out8(0x3d4, 0x3b, par); | 
 | 629 | 	reg->CR3B = vga_in8(0x3d5, par); | 
 | 630 | 	vga_out8(0x3d4, 0x3c, par); | 
 | 631 | 	reg->CR3C = vga_in8(0x3d5, par); | 
 | 632 | 	vga_out8(0x3d4, 0x43, par); | 
 | 633 | 	reg->CR43 = vga_in8(0x3d5, par); | 
 | 634 | 	vga_out8(0x3d4, 0x5d, par); | 
 | 635 | 	reg->CR5D = vga_in8(0x3d5, par); | 
 | 636 | 	vga_out8(0x3d4, 0x5e, par); | 
 | 637 | 	reg->CR5E = vga_in8(0x3d5, par); | 
 | 638 | 	vga_out8(0x3d4, 0x65, par); | 
 | 639 | 	reg->CR65 = vga_in8(0x3d5, par); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 640 |  | 
 | 641 | 	/* save seq extended regs for DCLK PLL programming */ | 
| Antonino A. Daplas | 026fbe1 | 2006-06-26 00:26:36 -0700 | [diff] [blame] | 642 | 	vga_out8(0x3c4, 0x0e, par); | 
 | 643 | 	reg->SR0E = vga_in8(0x3c5, par); | 
 | 644 | 	vga_out8(0x3c4, 0x0f, par); | 
 | 645 | 	reg->SR0F = vga_in8(0x3c5, par); | 
 | 646 | 	vga_out8(0x3c4, 0x10, par); | 
 | 647 | 	reg->SR10 = vga_in8(0x3c5, par); | 
 | 648 | 	vga_out8(0x3c4, 0x11, par); | 
 | 649 | 	reg->SR11 = vga_in8(0x3c5, par); | 
 | 650 | 	vga_out8(0x3c4, 0x12, par); | 
 | 651 | 	reg->SR12 = vga_in8(0x3c5, par); | 
 | 652 | 	vga_out8(0x3c4, 0x13, par); | 
 | 653 | 	reg->SR13 = vga_in8(0x3c5, par); | 
 | 654 | 	vga_out8(0x3c4, 0x29, par); | 
 | 655 | 	reg->SR29 = vga_in8(0x3c5, par); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 656 |  | 
| Antonino A. Daplas | 026fbe1 | 2006-06-26 00:26:36 -0700 | [diff] [blame] | 657 | 	vga_out8(0x3c4, 0x15, par); | 
 | 658 | 	reg->SR15 = vga_in8(0x3c5, par); | 
 | 659 | 	vga_out8(0x3c4, 0x30, par); | 
 | 660 | 	reg->SR30 = vga_in8(0x3c5, par); | 
 | 661 | 	vga_out8(0x3c4, 0x18, par); | 
 | 662 | 	reg->SR18 = vga_in8(0x3c5, par); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 663 |  | 
 | 664 | 	/* Save flat panel expansion regsters. */ | 
 | 665 | 	if (par->chip == S3_SAVAGE_MX) { | 
 | 666 | 		int i; | 
 | 667 |  | 
 | 668 | 		for (i = 0; i < 8; i++) { | 
| Antonino A. Daplas | 026fbe1 | 2006-06-26 00:26:36 -0700 | [diff] [blame] | 669 | 			vga_out8(0x3c4, 0x54+i, par); | 
 | 670 | 			reg->SR54[i] = vga_in8(0x3c5, par); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 671 | 		} | 
 | 672 | 	} | 
 | 673 |  | 
| Antonino A. Daplas | 026fbe1 | 2006-06-26 00:26:36 -0700 | [diff] [blame] | 674 | 	vga_out8(0x3d4, 0x66, par); | 
 | 675 | 	cr66 = vga_in8(0x3d5, par); | 
 | 676 | 	vga_out8(0x3d5, cr66 | 0x80, par); | 
 | 677 | 	vga_out8(0x3d4, 0x3a, par); | 
 | 678 | 	cr3a = vga_in8(0x3d5, par); | 
 | 679 | 	vga_out8(0x3d5, cr3a | 0x80, par); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 680 |  | 
 | 681 | 	/* now save MIU regs */ | 
 | 682 | 	if (par->chip != S3_SAVAGE_MX) { | 
| Antonino A. Daplas | 2356614 | 2006-06-26 00:26:23 -0700 | [diff] [blame] | 683 | 		reg->MMPR0 = savage_in32(FIFO_CONTROL_REG, par); | 
 | 684 | 		reg->MMPR1 = savage_in32(MIU_CONTROL_REG, par); | 
 | 685 | 		reg->MMPR2 = savage_in32(STREAMS_TIMEOUT_REG, par); | 
 | 686 | 		reg->MMPR3 = savage_in32(MISC_TIMEOUT_REG, par); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 687 | 	} | 
 | 688 |  | 
| Antonino A. Daplas | 026fbe1 | 2006-06-26 00:26:36 -0700 | [diff] [blame] | 689 | 	vga_out8(0x3d4, 0x3a, par); | 
 | 690 | 	vga_out8(0x3d5, cr3a, par); | 
 | 691 | 	vga_out8(0x3d4, 0x66, par); | 
 | 692 | 	vga_out8(0x3d5, cr66, par); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 693 | } | 
 | 694 |  | 
| Antonino A. Daplas | f8020dc | 2006-06-26 00:26:24 -0700 | [diff] [blame] | 695 | static void savage_set_default_par(struct savagefb_par *par, | 
 | 696 | 				struct savage_reg *reg) | 
 | 697 | { | 
 | 698 | 	unsigned char cr3a, cr53, cr66; | 
 | 699 |  | 
 | 700 | 	vga_out16(0x3d4, 0x4838, par); | 
 | 701 | 	vga_out16(0x3d4, 0xa039, par); | 
 | 702 | 	vga_out16(0x3c4, 0x0608, par); | 
 | 703 |  | 
 | 704 | 	vga_out8(0x3d4, 0x66, par); | 
 | 705 | 	cr66 = vga_in8(0x3d5, par); | 
 | 706 | 	vga_out8(0x3d5, cr66 | 0x80, par); | 
 | 707 | 	vga_out8(0x3d4, 0x3a, par); | 
 | 708 | 	cr3a = vga_in8(0x3d5, par); | 
 | 709 | 	vga_out8(0x3d5, cr3a | 0x80, par); | 
 | 710 | 	vga_out8(0x3d4, 0x53, par); | 
 | 711 | 	cr53 = vga_in8(0x3d5, par); | 
 | 712 | 	vga_out8(0x3d5, cr53 & 0x7f, par); | 
 | 713 |  | 
 | 714 | 	vga_out8(0x3d4, 0x66, par); | 
 | 715 | 	vga_out8(0x3d5, cr66, par); | 
 | 716 | 	vga_out8(0x3d4, 0x3a, par); | 
 | 717 | 	vga_out8(0x3d5, cr3a, par); | 
 | 718 |  | 
 | 719 | 	vga_out8(0x3d4, 0x66, par); | 
 | 720 | 	vga_out8(0x3d5, cr66, par); | 
 | 721 | 	vga_out8(0x3d4, 0x3a, par); | 
 | 722 | 	vga_out8(0x3d5, cr3a, par); | 
 | 723 |  | 
 | 724 | 	/* unlock extended seq regs */ | 
 | 725 | 	vga_out8(0x3c4, 0x08, par); | 
 | 726 | 	vga_out8(0x3c5, reg->SR08, par); | 
 | 727 | 	vga_out8(0x3c5, 0x06, par); | 
 | 728 |  | 
 | 729 | 	/* now restore all the extended regs we need */ | 
 | 730 | 	vga_out8(0x3d4, 0x31, par); | 
 | 731 | 	vga_out8(0x3d5, reg->CR31, par); | 
 | 732 | 	vga_out8(0x3d4, 0x32, par); | 
 | 733 | 	vga_out8(0x3d5, reg->CR32, par); | 
 | 734 | 	vga_out8(0x3d4, 0x34, par); | 
 | 735 | 	vga_out8(0x3d5, reg->CR34, par); | 
 | 736 | 	vga_out8(0x3d4, 0x36, par); | 
 | 737 | 	vga_out8(0x3d5,reg->CR36, par); | 
 | 738 | 	vga_out8(0x3d4, 0x3a, par); | 
 | 739 | 	vga_out8(0x3d5, reg->CR3A, par); | 
 | 740 | 	vga_out8(0x3d4, 0x40, par); | 
 | 741 | 	vga_out8(0x3d5, reg->CR40, par); | 
 | 742 | 	vga_out8(0x3d4, 0x42, par); | 
 | 743 | 	vga_out8(0x3d5, reg->CR42, par); | 
 | 744 | 	vga_out8(0x3d4, 0x45, par); | 
 | 745 | 	vga_out8(0x3d5, reg->CR45, par); | 
 | 746 | 	vga_out8(0x3d4, 0x50, par); | 
 | 747 | 	vga_out8(0x3d5, reg->CR50, par); | 
 | 748 | 	vga_out8(0x3d4, 0x51, par); | 
 | 749 | 	vga_out8(0x3d5, reg->CR51, par); | 
 | 750 | 	vga_out8(0x3d4, 0x53, par); | 
 | 751 | 	vga_out8(0x3d5, reg->CR53, par); | 
 | 752 | 	vga_out8(0x3d4, 0x58, par); | 
 | 753 | 	vga_out8(0x3d5, reg->CR58, par); | 
 | 754 | 	vga_out8(0x3d4, 0x60, par); | 
 | 755 | 	vga_out8(0x3d5, reg->CR60, par); | 
 | 756 | 	vga_out8(0x3d4, 0x66, par); | 
 | 757 | 	vga_out8(0x3d5, reg->CR66, par); | 
 | 758 | 	vga_out8(0x3d4, 0x67, par); | 
 | 759 | 	vga_out8(0x3d5, reg->CR67, par); | 
 | 760 | 	vga_out8(0x3d4, 0x68, par); | 
 | 761 | 	vga_out8(0x3d5, reg->CR68, par); | 
 | 762 | 	vga_out8(0x3d4, 0x69, par); | 
 | 763 | 	vga_out8(0x3d5, reg->CR69, par); | 
 | 764 | 	vga_out8(0x3d4, 0x6f, par); | 
 | 765 | 	vga_out8(0x3d5, reg->CR6F, par); | 
 | 766 |  | 
 | 767 | 	vga_out8(0x3d4, 0x33, par); | 
 | 768 | 	vga_out8(0x3d5, reg->CR33, par); | 
 | 769 | 	vga_out8(0x3d4, 0x86, par); | 
 | 770 | 	vga_out8(0x3d5, reg->CR86, par); | 
 | 771 | 	vga_out8(0x3d4, 0x88, par); | 
 | 772 | 	vga_out8(0x3d5, reg->CR88, par); | 
 | 773 | 	vga_out8(0x3d4, 0x90, par); | 
 | 774 | 	vga_out8(0x3d5, reg->CR90, par); | 
 | 775 | 	vga_out8(0x3d4, 0x91, par); | 
 | 776 | 	vga_out8(0x3d5, reg->CR91, par); | 
 | 777 | 	vga_out8(0x3d4, 0xb0, par); | 
 | 778 | 	vga_out8(0x3d5, reg->CRB0, par); | 
 | 779 |  | 
 | 780 | 	/* extended mode timing regs */ | 
 | 781 | 	vga_out8(0x3d4, 0x3b, par); | 
 | 782 | 	vga_out8(0x3d5, reg->CR3B, par); | 
 | 783 | 	vga_out8(0x3d4, 0x3c, par); | 
 | 784 | 	vga_out8(0x3d5, reg->CR3C, par); | 
 | 785 | 	vga_out8(0x3d4, 0x43, par); | 
 | 786 | 	vga_out8(0x3d5, reg->CR43, par); | 
 | 787 | 	vga_out8(0x3d4, 0x5d, par); | 
 | 788 | 	vga_out8(0x3d5, reg->CR5D, par); | 
 | 789 | 	vga_out8(0x3d4, 0x5e, par); | 
 | 790 | 	vga_out8(0x3d5, reg->CR5E, par); | 
 | 791 | 	vga_out8(0x3d4, 0x65, par); | 
 | 792 | 	vga_out8(0x3d5, reg->CR65, par); | 
 | 793 |  | 
 | 794 | 	/* save seq extended regs for DCLK PLL programming */ | 
 | 795 | 	vga_out8(0x3c4, 0x0e, par); | 
 | 796 | 	vga_out8(0x3c5, reg->SR0E, par); | 
 | 797 | 	vga_out8(0x3c4, 0x0f, par); | 
 | 798 | 	vga_out8(0x3c5, reg->SR0F, par); | 
 | 799 | 	vga_out8(0x3c4, 0x10, par); | 
 | 800 | 	vga_out8(0x3c5, reg->SR10, par); | 
 | 801 | 	vga_out8(0x3c4, 0x11, par); | 
 | 802 | 	vga_out8(0x3c5, reg->SR11, par); | 
 | 803 | 	vga_out8(0x3c4, 0x12, par); | 
 | 804 | 	vga_out8(0x3c5, reg->SR12, par); | 
 | 805 | 	vga_out8(0x3c4, 0x13, par); | 
 | 806 | 	vga_out8(0x3c5, reg->SR13, par); | 
 | 807 | 	vga_out8(0x3c4, 0x29, par); | 
 | 808 | 	vga_out8(0x3c5, reg->SR29, par); | 
 | 809 |  | 
 | 810 | 	vga_out8(0x3c4, 0x15, par); | 
 | 811 | 	vga_out8(0x3c5, reg->SR15, par); | 
 | 812 | 	vga_out8(0x3c4, 0x30, par); | 
 | 813 | 	vga_out8(0x3c5, reg->SR30, par); | 
 | 814 | 	vga_out8(0x3c4, 0x18, par); | 
 | 815 | 	vga_out8(0x3c5, reg->SR18, par); | 
 | 816 |  | 
 | 817 | 	/* Save flat panel expansion regsters. */ | 
 | 818 | 	if (par->chip == S3_SAVAGE_MX) { | 
 | 819 | 		int i; | 
 | 820 |  | 
 | 821 | 		for (i = 0; i < 8; i++) { | 
 | 822 | 			vga_out8(0x3c4, 0x54+i, par); | 
 | 823 | 			vga_out8(0x3c5, reg->SR54[i], par); | 
 | 824 | 		} | 
 | 825 | 	} | 
 | 826 |  | 
 | 827 | 	vga_out8(0x3d4, 0x66, par); | 
 | 828 | 	cr66 = vga_in8(0x3d5, par); | 
 | 829 | 	vga_out8(0x3d5, cr66 | 0x80, par); | 
 | 830 | 	vga_out8(0x3d4, 0x3a, par); | 
 | 831 | 	cr3a = vga_in8(0x3d5, par); | 
 | 832 | 	vga_out8(0x3d5, cr3a | 0x80, par); | 
 | 833 |  | 
 | 834 | 	/* now save MIU regs */ | 
 | 835 | 	if (par->chip != S3_SAVAGE_MX) { | 
 | 836 | 		savage_out32(FIFO_CONTROL_REG, reg->MMPR0, par); | 
 | 837 | 		savage_out32(MIU_CONTROL_REG, reg->MMPR1, par); | 
 | 838 | 		savage_out32(STREAMS_TIMEOUT_REG, reg->MMPR2, par); | 
 | 839 | 		savage_out32(MISC_TIMEOUT_REG, reg->MMPR3, par); | 
 | 840 | 	} | 
 | 841 |  | 
 | 842 | 	vga_out8(0x3d4, 0x3a, par); | 
 | 843 | 	vga_out8(0x3d5, cr3a, par); | 
 | 844 | 	vga_out8(0x3d4, 0x66, par); | 
 | 845 | 	vga_out8(0x3d5, cr66, par); | 
 | 846 | } | 
 | 847 |  | 
| Geert Uytterhoeven | 9791d76 | 2007-02-12 00:55:19 -0800 | [diff] [blame] | 848 | static void savage_update_var(struct fb_var_screeninfo *var, | 
 | 849 | 			      const struct fb_videomode *modedb) | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 850 | { | 
 | 851 | 	var->xres = var->xres_virtual = modedb->xres; | 
 | 852 | 	var->yres = modedb->yres; | 
 | 853 |         if (var->yres_virtual < var->yres) | 
 | 854 | 	    var->yres_virtual = var->yres; | 
 | 855 |         var->xoffset = var->yoffset = 0; | 
 | 856 |         var->pixclock = modedb->pixclock; | 
 | 857 |         var->left_margin = modedb->left_margin; | 
 | 858 |         var->right_margin = modedb->right_margin; | 
 | 859 |         var->upper_margin = modedb->upper_margin; | 
 | 860 |         var->lower_margin = modedb->lower_margin; | 
 | 861 |         var->hsync_len = modedb->hsync_len; | 
 | 862 |         var->vsync_len = modedb->vsync_len; | 
 | 863 |         var->sync = modedb->sync; | 
 | 864 |         var->vmode = modedb->vmode; | 
 | 865 | } | 
 | 866 |  | 
| Antonino A. Daplas | 026fbe1 | 2006-06-26 00:26:36 -0700 | [diff] [blame] | 867 | static int savagefb_check_var(struct fb_var_screeninfo   *var, | 
 | 868 | 			      struct fb_info *info) | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 869 | { | 
| Antonino A. Daplas | b8901b0 | 2006-01-09 20:53:02 -0800 | [diff] [blame] | 870 | 	struct savagefb_par *par = info->par; | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 871 | 	int memlen, vramlen, mode_valid = 0; | 
 | 872 |  | 
 | 873 | 	DBG("savagefb_check_var"); | 
 | 874 |  | 
 | 875 | 	var->transp.offset = 0; | 
 | 876 | 	var->transp.length = 0; | 
 | 877 | 	switch (var->bits_per_pixel) { | 
 | 878 | 	case 8: | 
 | 879 | 		var->red.offset = var->green.offset = | 
 | 880 | 			var->blue.offset = 0; | 
 | 881 | 		var->red.length = var->green.length = | 
 | 882 | 			var->blue.length = var->bits_per_pixel; | 
 | 883 | 		break; | 
 | 884 | 	case 16: | 
 | 885 | 		var->red.offset = 11; | 
 | 886 | 		var->red.length = 5; | 
 | 887 | 		var->green.offset = 5; | 
 | 888 | 		var->green.length = 6; | 
 | 889 | 		var->blue.offset = 0; | 
 | 890 | 		var->blue.length = 5; | 
 | 891 | 		break; | 
 | 892 | 	case 32: | 
 | 893 | 		var->transp.offset = 24; | 
 | 894 | 		var->transp.length = 8; | 
 | 895 | 		var->red.offset = 16; | 
 | 896 | 		var->red.length = 8; | 
 | 897 | 		var->green.offset = 8; | 
 | 898 | 		var->green.length = 8; | 
 | 899 | 		var->blue.offset = 0; | 
 | 900 | 		var->blue.length = 8; | 
 | 901 | 		break; | 
 | 902 |  | 
 | 903 | 	default: | 
 | 904 | 		return -EINVAL; | 
 | 905 | 	} | 
 | 906 |  | 
 | 907 | 	if (!info->monspecs.hfmax || !info->monspecs.vfmax || | 
 | 908 | 	    !info->monspecs.dclkmax || !fb_validate_mode(var, info)) | 
 | 909 | 		mode_valid = 1; | 
 | 910 |  | 
 | 911 | 	/* calculate modeline if supported by monitor */ | 
 | 912 | 	if (!mode_valid && info->monspecs.gtf) { | 
 | 913 | 		if (!fb_get_mode(FB_MAXTIMINGS, 0, var, info)) | 
 | 914 | 			mode_valid = 1; | 
 | 915 | 	} | 
 | 916 |  | 
 | 917 | 	if (!mode_valid) { | 
| Geert Uytterhoeven | 9791d76 | 2007-02-12 00:55:19 -0800 | [diff] [blame] | 918 | 		const struct fb_videomode *mode; | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 919 |  | 
 | 920 | 		mode = fb_find_best_mode(var, &info->modelist); | 
 | 921 | 		if (mode) { | 
 | 922 | 			savage_update_var(var, mode); | 
 | 923 | 			mode_valid = 1; | 
 | 924 | 		} | 
 | 925 | 	} | 
 | 926 |  | 
 | 927 | 	if (!mode_valid && info->monspecs.modedb_len) | 
 | 928 | 		return -EINVAL; | 
 | 929 |  | 
 | 930 | 	/* Is the mode larger than the LCD panel? */ | 
 | 931 | 	if (par->SavagePanelWidth && | 
 | 932 | 	    (var->xres > par->SavagePanelWidth || | 
 | 933 | 	     var->yres > par->SavagePanelHeight)) { | 
| Antonino A. Daplas | 026fbe1 | 2006-06-26 00:26:36 -0700 | [diff] [blame] | 934 | 		printk(KERN_INFO "Mode (%dx%d) larger than the LCD panel " | 
 | 935 | 		       "(%dx%d)\n", var->xres,  var->yres, | 
 | 936 | 		       par->SavagePanelWidth, | 
 | 937 | 		       par->SavagePanelHeight); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 938 | 		return -1; | 
 | 939 | 	} | 
 | 940 |  | 
 | 941 | 	if (var->yres_virtual < var->yres) | 
 | 942 | 		var->yres_virtual = var->yres; | 
 | 943 | 	if (var->xres_virtual < var->xres) | 
 | 944 | 		var->xres_virtual = var->xres; | 
 | 945 |  | 
 | 946 | 	vramlen = info->fix.smem_len; | 
 | 947 |  | 
 | 948 | 	memlen = var->xres_virtual * var->bits_per_pixel * | 
 | 949 | 		var->yres_virtual / 8; | 
 | 950 | 	if (memlen > vramlen) { | 
 | 951 | 		var->yres_virtual = vramlen * 8 / | 
 | 952 | 			(var->xres_virtual * var->bits_per_pixel); | 
 | 953 | 		memlen = var->xres_virtual * var->bits_per_pixel * | 
 | 954 | 			var->yres_virtual / 8; | 
 | 955 | 	} | 
 | 956 |  | 
 | 957 | 	/* we must round yres/xres down, we already rounded y/xres_virtual up | 
 | 958 | 	   if it was possible. We should return -EINVAL, but I disagree */ | 
 | 959 | 	if (var->yres_virtual < var->yres) | 
 | 960 | 		var->yres = var->yres_virtual; | 
 | 961 | 	if (var->xres_virtual < var->xres) | 
 | 962 | 		var->xres = var->xres_virtual; | 
 | 963 | 	if (var->xoffset + var->xres > var->xres_virtual) | 
 | 964 | 		var->xoffset = var->xres_virtual - var->xres; | 
 | 965 | 	if (var->yoffset + var->yres > var->yres_virtual) | 
 | 966 | 		var->yoffset = var->yres_virtual - var->yres; | 
 | 967 |  | 
 | 968 | 	return 0; | 
 | 969 | } | 
 | 970 |  | 
 | 971 |  | 
| Antonino A. Daplas | 026fbe1 | 2006-06-26 00:26:36 -0700 | [diff] [blame] | 972 | static int savagefb_decode_var(struct fb_var_screeninfo   *var, | 
 | 973 | 			       struct savagefb_par        *par, | 
 | 974 | 			       struct savage_reg          *reg) | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 975 | { | 
 | 976 | 	struct xtimings timings; | 
 | 977 | 	int width, dclk, i, j; /*, refresh; */ | 
 | 978 | 	unsigned int m, n, r; | 
 | 979 | 	unsigned char tmp = 0; | 
 | 980 | 	unsigned int pixclock = var->pixclock; | 
 | 981 |  | 
 | 982 | 	DBG("savagefb_decode_var"); | 
 | 983 |  | 
| Antonino A. Daplas | 026fbe1 | 2006-06-26 00:26:36 -0700 | [diff] [blame] | 984 | 	memset(&timings, 0, sizeof(timings)); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 985 |  | 
 | 986 | 	if (!pixclock) pixclock = 10000;	/* 10ns = 100MHz */ | 
 | 987 | 	timings.Clock = 1000000000 / pixclock; | 
 | 988 | 	if (timings.Clock < 1) timings.Clock = 1; | 
 | 989 | 	timings.dblscan = var->vmode & FB_VMODE_DOUBLE; | 
 | 990 | 	timings.interlaced = var->vmode & FB_VMODE_INTERLACED; | 
 | 991 | 	timings.HDisplay = var->xres; | 
 | 992 | 	timings.HSyncStart = timings.HDisplay + var->right_margin; | 
 | 993 | 	timings.HSyncEnd = timings.HSyncStart + var->hsync_len; | 
 | 994 | 	timings.HTotal = timings.HSyncEnd + var->left_margin; | 
 | 995 | 	timings.VDisplay = var->yres; | 
 | 996 | 	timings.VSyncStart = timings.VDisplay + var->lower_margin; | 
 | 997 | 	timings.VSyncEnd = timings.VSyncStart + var->vsync_len; | 
 | 998 | 	timings.VTotal = timings.VSyncEnd + var->upper_margin; | 
 | 999 | 	timings.sync = var->sync; | 
 | 1000 |  | 
 | 1001 |  | 
 | 1002 | 	par->depth  = var->bits_per_pixel; | 
 | 1003 | 	par->vwidth = var->xres_virtual; | 
 | 1004 |  | 
 | 1005 | 	if (var->bits_per_pixel == 16  &&  par->chip == S3_SAVAGE3D) { | 
 | 1006 | 		timings.HDisplay *= 2; | 
 | 1007 | 		timings.HSyncStart *= 2; | 
 | 1008 | 		timings.HSyncEnd *= 2; | 
 | 1009 | 		timings.HTotal *= 2; | 
 | 1010 | 	} | 
 | 1011 |  | 
 | 1012 | 	/* | 
 | 1013 | 	 * This will allocate the datastructure and initialize all of the | 
 | 1014 | 	 * generic VGA registers. | 
 | 1015 | 	 */ | 
| Antonino A. Daplas | 026fbe1 | 2006-06-26 00:26:36 -0700 | [diff] [blame] | 1016 | 	vgaHWInit(var, par, &timings, reg); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 1017 |  | 
 | 1018 | 	/* We need to set CR67 whether or not we use the BIOS. */ | 
 | 1019 |  | 
 | 1020 | 	dclk = timings.Clock; | 
| Antonino A. Daplas | 2356614 | 2006-06-26 00:26:23 -0700 | [diff] [blame] | 1021 | 	reg->CR67 = 0x00; | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 1022 |  | 
| Antonino A. Daplas | 026fbe1 | 2006-06-26 00:26:36 -0700 | [diff] [blame] | 1023 | 	switch(var->bits_per_pixel) { | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 1024 | 	case 8: | 
| Antonino A. Daplas | 026fbe1 | 2006-06-26 00:26:36 -0700 | [diff] [blame] | 1025 | 		if ((par->chip == S3_SAVAGE2000) && (dclk >= 230000)) | 
| Antonino A. Daplas | 2356614 | 2006-06-26 00:26:23 -0700 | [diff] [blame] | 1026 | 			reg->CR67 = 0x10;	/* 8bpp, 2 pixels/clock */ | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 1027 | 		else | 
| Antonino A. Daplas | 2356614 | 2006-06-26 00:26:23 -0700 | [diff] [blame] | 1028 | 			reg->CR67 = 0x00;	/* 8bpp, 1 pixel/clock */ | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 1029 | 		break; | 
 | 1030 | 	case 15: | 
| Antonino A. Daplas | 026fbe1 | 2006-06-26 00:26:36 -0700 | [diff] [blame] | 1031 | 		if (S3_SAVAGE_MOBILE_SERIES(par->chip) || | 
 | 1032 | 		    ((par->chip == S3_SAVAGE2000) && (dclk >= 230000))) | 
| Antonino A. Daplas | 2356614 | 2006-06-26 00:26:23 -0700 | [diff] [blame] | 1033 | 			reg->CR67 = 0x30;	/* 15bpp, 2 pixel/clock */ | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 1034 | 		else | 
| Antonino A. Daplas | 2356614 | 2006-06-26 00:26:23 -0700 | [diff] [blame] | 1035 | 			reg->CR67 = 0x20;	/* 15bpp, 1 pixels/clock */ | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 1036 | 		break; | 
 | 1037 | 	case 16: | 
| Antonino A. Daplas | 026fbe1 | 2006-06-26 00:26:36 -0700 | [diff] [blame] | 1038 | 		if (S3_SAVAGE_MOBILE_SERIES(par->chip) || | 
 | 1039 | 		   ((par->chip == S3_SAVAGE2000) && (dclk >= 230000))) | 
| Antonino A. Daplas | 2356614 | 2006-06-26 00:26:23 -0700 | [diff] [blame] | 1040 | 			reg->CR67 = 0x50;	/* 16bpp, 2 pixel/clock */ | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 1041 | 		else | 
| Antonino A. Daplas | 2356614 | 2006-06-26 00:26:23 -0700 | [diff] [blame] | 1042 | 			reg->CR67 = 0x40;	/* 16bpp, 1 pixels/clock */ | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 1043 | 		break; | 
 | 1044 | 	case 24: | 
| Antonino A. Daplas | 2356614 | 2006-06-26 00:26:23 -0700 | [diff] [blame] | 1045 | 		reg->CR67 = 0x70; | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 1046 | 		break; | 
 | 1047 | 	case 32: | 
| Antonino A. Daplas | 2356614 | 2006-06-26 00:26:23 -0700 | [diff] [blame] | 1048 | 		reg->CR67 = 0xd0; | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 1049 | 		break; | 
 | 1050 | 	} | 
 | 1051 |  | 
 | 1052 | 	/* | 
 | 1053 | 	 * Either BIOS use is disabled, or we failed to find a suitable | 
 | 1054 | 	 * match.  Fall back to traditional register-crunching. | 
 | 1055 | 	 */ | 
 | 1056 |  | 
| Antonino A. Daplas | 026fbe1 | 2006-06-26 00:26:36 -0700 | [diff] [blame] | 1057 | 	vga_out8(0x3d4, 0x3a, par); | 
 | 1058 | 	tmp = vga_in8(0x3d5, par); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 1059 | 	if (1 /*FIXME:psav->pci_burst*/) | 
| Antonino A. Daplas | 2356614 | 2006-06-26 00:26:23 -0700 | [diff] [blame] | 1060 | 		reg->CR3A = (tmp & 0x7f) | 0x15; | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 1061 | 	else | 
| Antonino A. Daplas | 2356614 | 2006-06-26 00:26:23 -0700 | [diff] [blame] | 1062 | 		reg->CR3A = tmp | 0x95; | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 1063 |  | 
| Antonino A. Daplas | 2356614 | 2006-06-26 00:26:23 -0700 | [diff] [blame] | 1064 | 	reg->CR53 = 0x00; | 
 | 1065 | 	reg->CR31 = 0x8c; | 
 | 1066 | 	reg->CR66 = 0x89; | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 1067 |  | 
| Antonino A. Daplas | 026fbe1 | 2006-06-26 00:26:36 -0700 | [diff] [blame] | 1068 | 	vga_out8(0x3d4, 0x58, par); | 
 | 1069 | 	reg->CR58 = vga_in8(0x3d5, par) & 0x80; | 
| Antonino A. Daplas | 2356614 | 2006-06-26 00:26:23 -0700 | [diff] [blame] | 1070 | 	reg->CR58 |= 0x13; | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 1071 |  | 
| Antonino A. Daplas | 2356614 | 2006-06-26 00:26:23 -0700 | [diff] [blame] | 1072 | 	reg->SR15 = 0x03 | 0x80; | 
 | 1073 | 	reg->SR18 = 0x00; | 
 | 1074 | 	reg->CR43 = reg->CR45 = reg->CR65 = 0x00; | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 1075 |  | 
| Antonino A. Daplas | 026fbe1 | 2006-06-26 00:26:36 -0700 | [diff] [blame] | 1076 | 	vga_out8(0x3d4, 0x40, par); | 
 | 1077 | 	reg->CR40 = vga_in8(0x3d5, par) & ~0x01; | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 1078 |  | 
| Antonino A. Daplas | 2356614 | 2006-06-26 00:26:23 -0700 | [diff] [blame] | 1079 | 	reg->MMPR0 = 0x010400; | 
 | 1080 | 	reg->MMPR1 = 0x00; | 
 | 1081 | 	reg->MMPR2 = 0x0808; | 
 | 1082 | 	reg->MMPR3 = 0x08080810; | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 1083 |  | 
| Antonino A. Daplas | 026fbe1 | 2006-06-26 00:26:36 -0700 | [diff] [blame] | 1084 | 	SavageCalcClock(dclk, 1, 1, 127, 0, 4, 180000, 360000, &m, &n, &r); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 1085 | 	/* m = 107; n = 4; r = 2; */ | 
 | 1086 |  | 
 | 1087 | 	if (par->MCLK <= 0) { | 
| Antonino A. Daplas | 2356614 | 2006-06-26 00:26:23 -0700 | [diff] [blame] | 1088 | 		reg->SR10 = 255; | 
 | 1089 | 		reg->SR11 = 255; | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 1090 | 	} else { | 
| Antonino A. Daplas | 026fbe1 | 2006-06-26 00:26:36 -0700 | [diff] [blame] | 1091 | 		common_calc_clock(par->MCLK, 1, 1, 31, 0, 3, 135000, 270000, | 
| Antonino A. Daplas | 2356614 | 2006-06-26 00:26:23 -0700 | [diff] [blame] | 1092 | 				   ®->SR11, ®->SR10); | 
 | 1093 | 		/*      reg->SR10 = 80; // MCLK == 286000 */ | 
 | 1094 | 		/*      reg->SR11 = 125; */ | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 1095 | 	} | 
 | 1096 |  | 
| Antonino A. Daplas | 2356614 | 2006-06-26 00:26:23 -0700 | [diff] [blame] | 1097 | 	reg->SR12 = (r << 6) | (n & 0x3f); | 
 | 1098 | 	reg->SR13 = m & 0xff; | 
 | 1099 | 	reg->SR29 = (r & 4) | (m & 0x100) >> 5 | (n & 0x40) >> 2; | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 1100 |  | 
 | 1101 | 	if (var->bits_per_pixel < 24) | 
| Antonino A. Daplas | 2356614 | 2006-06-26 00:26:23 -0700 | [diff] [blame] | 1102 | 		reg->MMPR0 -= 0x8000; | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 1103 | 	else | 
| Antonino A. Daplas | 2356614 | 2006-06-26 00:26:23 -0700 | [diff] [blame] | 1104 | 		reg->MMPR0 -= 0x4000; | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 1105 |  | 
 | 1106 | 	if (timings.interlaced) | 
| Antonino A. Daplas | 2356614 | 2006-06-26 00:26:23 -0700 | [diff] [blame] | 1107 | 		reg->CR42 = 0x20; | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 1108 | 	else | 
| Antonino A. Daplas | 2356614 | 2006-06-26 00:26:23 -0700 | [diff] [blame] | 1109 | 		reg->CR42 = 0x00; | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 1110 |  | 
| Antonino A. Daplas | 2356614 | 2006-06-26 00:26:23 -0700 | [diff] [blame] | 1111 | 	reg->CR34 = 0x10; /* display fifo */ | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 1112 |  | 
 | 1113 | 	i = ((((timings.HTotal >> 3) - 5) & 0x100) >> 8) | | 
 | 1114 | 		((((timings.HDisplay >> 3) - 1) & 0x100) >> 7) | | 
 | 1115 | 		((((timings.HSyncStart >> 3) - 1) & 0x100) >> 6) | | 
 | 1116 | 		((timings.HSyncStart & 0x800) >> 7); | 
 | 1117 |  | 
 | 1118 | 	if ((timings.HSyncEnd >> 3) - (timings.HSyncStart >> 3) > 64) | 
 | 1119 | 		i |= 0x08; | 
 | 1120 | 	if ((timings.HSyncEnd >> 3) - (timings.HSyncStart >> 3) > 32) | 
 | 1121 | 		i |= 0x20; | 
 | 1122 |  | 
| Antonino A. Daplas | 2356614 | 2006-06-26 00:26:23 -0700 | [diff] [blame] | 1123 | 	j = (reg->CRTC[0] + ((i & 0x01) << 8) + | 
 | 1124 | 	     reg->CRTC[4] + ((i & 0x10) << 4) + 1) / 2; | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 1125 |  | 
| Antonino A. Daplas | 2356614 | 2006-06-26 00:26:23 -0700 | [diff] [blame] | 1126 | 	if (j - (reg->CRTC[4] + ((i & 0x10) << 4)) < 4) { | 
 | 1127 | 		if (reg->CRTC[4] + ((i & 0x10) << 4) + 4 <= | 
 | 1128 | 		    reg->CRTC[0] + ((i & 0x01) << 8)) | 
 | 1129 | 			j = reg->CRTC[4] + ((i & 0x10) << 4) + 4; | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 1130 | 		else | 
| Antonino A. Daplas | 2356614 | 2006-06-26 00:26:23 -0700 | [diff] [blame] | 1131 | 			j = reg->CRTC[0] + ((i & 0x01) << 8) + 1; | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 1132 | 	} | 
 | 1133 |  | 
| Antonino A. Daplas | 2356614 | 2006-06-26 00:26:23 -0700 | [diff] [blame] | 1134 | 	reg->CR3B = j & 0xff; | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 1135 | 	i |= (j & 0x100) >> 2; | 
| Antonino A. Daplas | 2356614 | 2006-06-26 00:26:23 -0700 | [diff] [blame] | 1136 | 	reg->CR3C = (reg->CRTC[0] + ((i & 0x01) << 8)) / 2; | 
 | 1137 | 	reg->CR5D = i; | 
 | 1138 | 	reg->CR5E = (((timings.VTotal - 2) & 0x400) >> 10) | | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 1139 | 		(((timings.VDisplay - 1) & 0x400) >> 9) | | 
 | 1140 | 		(((timings.VSyncStart) & 0x400) >> 8) | | 
 | 1141 | 		(((timings.VSyncStart) & 0x400) >> 6) | 0x40; | 
 | 1142 | 	width = (var->xres_virtual * ((var->bits_per_pixel+7) / 8)) >> 3; | 
| Antonino A. Daplas | 2356614 | 2006-06-26 00:26:23 -0700 | [diff] [blame] | 1143 | 	reg->CR91 = reg->CRTC[19] = 0xff & width; | 
 | 1144 | 	reg->CR51 = (0x300 & width) >> 4; | 
 | 1145 | 	reg->CR90 = 0x80 | (width >> 8); | 
 | 1146 | 	reg->MiscOutReg |= 0x0c; | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 1147 |  | 
 | 1148 | 	/* Set frame buffer description. */ | 
 | 1149 |  | 
 | 1150 | 	if (var->bits_per_pixel <= 8) | 
| Antonino A. Daplas | 2356614 | 2006-06-26 00:26:23 -0700 | [diff] [blame] | 1151 | 		reg->CR50 = 0; | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 1152 | 	else if (var->bits_per_pixel <= 16) | 
| Antonino A. Daplas | 2356614 | 2006-06-26 00:26:23 -0700 | [diff] [blame] | 1153 | 		reg->CR50 = 0x10; | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 1154 | 	else | 
| Antonino A. Daplas | 2356614 | 2006-06-26 00:26:23 -0700 | [diff] [blame] | 1155 | 		reg->CR50 = 0x30; | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 1156 |  | 
 | 1157 | 	if (var->xres_virtual <= 640) | 
| Antonino A. Daplas | 2356614 | 2006-06-26 00:26:23 -0700 | [diff] [blame] | 1158 | 		reg->CR50 |= 0x40; | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 1159 | 	else if (var->xres_virtual == 800) | 
| Antonino A. Daplas | 2356614 | 2006-06-26 00:26:23 -0700 | [diff] [blame] | 1160 | 		reg->CR50 |= 0x80; | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 1161 | 	else if (var->xres_virtual == 1024) | 
| Antonino A. Daplas | 2356614 | 2006-06-26 00:26:23 -0700 | [diff] [blame] | 1162 | 		reg->CR50 |= 0x00; | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 1163 | 	else if (var->xres_virtual == 1152) | 
| Antonino A. Daplas | 2356614 | 2006-06-26 00:26:23 -0700 | [diff] [blame] | 1164 | 		reg->CR50 |= 0x01; | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 1165 | 	else if (var->xres_virtual == 1280) | 
| Antonino A. Daplas | 2356614 | 2006-06-26 00:26:23 -0700 | [diff] [blame] | 1166 | 		reg->CR50 |= 0xc0; | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 1167 | 	else if (var->xres_virtual == 1600) | 
| Antonino A. Daplas | 2356614 | 2006-06-26 00:26:23 -0700 | [diff] [blame] | 1168 | 		reg->CR50 |= 0x81; | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 1169 | 	else | 
| Antonino A. Daplas | 2356614 | 2006-06-26 00:26:23 -0700 | [diff] [blame] | 1170 | 		reg->CR50 |= 0xc1;	/* Use GBD */ | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 1171 |  | 
| Antonino A. Daplas | 026fbe1 | 2006-06-26 00:26:36 -0700 | [diff] [blame] | 1172 | 	if (par->chip == S3_SAVAGE2000) | 
| Antonino A. Daplas | 2356614 | 2006-06-26 00:26:23 -0700 | [diff] [blame] | 1173 | 		reg->CR33 = 0x08; | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 1174 | 	else | 
| Antonino A. Daplas | 2356614 | 2006-06-26 00:26:23 -0700 | [diff] [blame] | 1175 | 		reg->CR33 = 0x20; | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 1176 |  | 
| Antonino A. Daplas | 2356614 | 2006-06-26 00:26:23 -0700 | [diff] [blame] | 1177 | 	reg->CRTC[0x17] = 0xeb; | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 1178 |  | 
| Antonino A. Daplas | 2356614 | 2006-06-26 00:26:23 -0700 | [diff] [blame] | 1179 | 	reg->CR67 |= 1; | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 1180 |  | 
| Antonino A. Daplas | 1cc650c | 2005-11-07 01:00:41 -0800 | [diff] [blame] | 1181 | 	vga_out8(0x3d4, 0x36, par); | 
| Antonino A. Daplas | 026fbe1 | 2006-06-26 00:26:36 -0700 | [diff] [blame] | 1182 | 	reg->CR36 = vga_in8(0x3d5, par); | 
 | 1183 | 	vga_out8(0x3d4, 0x68, par); | 
 | 1184 | 	reg->CR68 = vga_in8(0x3d5, par); | 
| Antonino A. Daplas | 2356614 | 2006-06-26 00:26:23 -0700 | [diff] [blame] | 1185 | 	reg->CR69 = 0; | 
| Antonino A. Daplas | 026fbe1 | 2006-06-26 00:26:36 -0700 | [diff] [blame] | 1186 | 	vga_out8(0x3d4, 0x6f, par); | 
 | 1187 | 	reg->CR6F = vga_in8(0x3d5, par); | 
 | 1188 | 	vga_out8(0x3d4, 0x86, par); | 
 | 1189 | 	reg->CR86 = vga_in8(0x3d5, par); | 
 | 1190 | 	vga_out8(0x3d4, 0x88, par); | 
 | 1191 | 	reg->CR88 = vga_in8(0x3d5, par) | 0x08; | 
 | 1192 | 	vga_out8(0x3d4, 0xb0, par); | 
 | 1193 | 	reg->CRB0 = vga_in8(0x3d5, par) | 0x80; | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 1194 |  | 
 | 1195 | 	return 0; | 
 | 1196 | } | 
 | 1197 |  | 
 | 1198 | /* --------------------------------------------------------------------- */ | 
 | 1199 |  | 
 | 1200 | /* | 
 | 1201 |  *    Set a single color register. Return != 0 for invalid regno. | 
 | 1202 |  */ | 
 | 1203 | static int savagefb_setcolreg(unsigned        regno, | 
 | 1204 | 			      unsigned        red, | 
 | 1205 | 			      unsigned        green, | 
 | 1206 | 			      unsigned        blue, | 
 | 1207 | 			      unsigned        transp, | 
 | 1208 | 			      struct fb_info *info) | 
 | 1209 | { | 
| Antonino A. Daplas | b8901b0 | 2006-01-09 20:53:02 -0800 | [diff] [blame] | 1210 | 	struct savagefb_par *par = info->par; | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 1211 |  | 
 | 1212 | 	if (regno >= NR_PALETTE) | 
 | 1213 | 		return -EINVAL; | 
 | 1214 |  | 
 | 1215 | 	par->palette[regno].red    = red; | 
 | 1216 | 	par->palette[regno].green  = green; | 
 | 1217 | 	par->palette[regno].blue   = blue; | 
 | 1218 | 	par->palette[regno].transp = transp; | 
 | 1219 |  | 
 | 1220 | 	switch (info->var.bits_per_pixel) { | 
 | 1221 | 	case 8: | 
| Antonino A. Daplas | 026fbe1 | 2006-06-26 00:26:36 -0700 | [diff] [blame] | 1222 | 		vga_out8(0x3c8, regno, par); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 1223 |  | 
| Antonino A. Daplas | 026fbe1 | 2006-06-26 00:26:36 -0700 | [diff] [blame] | 1224 | 		vga_out8(0x3c9, red   >> 10, par); | 
 | 1225 | 		vga_out8(0x3c9, green >> 10, par); | 
 | 1226 | 		vga_out8(0x3c9, blue  >> 10, par); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 1227 | 		break; | 
 | 1228 |  | 
 | 1229 | 	case 16: | 
 | 1230 | 		if (regno < 16) | 
 | 1231 | 			((u32 *)info->pseudo_palette)[regno] = | 
 | 1232 | 				((red   & 0xf800)      ) | | 
 | 1233 | 				((green & 0xfc00) >>  5) | | 
 | 1234 | 				((blue  & 0xf800) >> 11); | 
 | 1235 | 		break; | 
 | 1236 |  | 
 | 1237 | 	case 24: | 
 | 1238 | 		if (regno < 16) | 
 | 1239 | 			((u32 *)info->pseudo_palette)[regno] = | 
 | 1240 | 				((red    & 0xff00) <<  8) | | 
 | 1241 | 				((green  & 0xff00)      ) | | 
 | 1242 | 				((blue   & 0xff00) >>  8); | 
 | 1243 | 		break; | 
 | 1244 | 	case 32: | 
 | 1245 | 		if (regno < 16) | 
 | 1246 | 			((u32 *)info->pseudo_palette)[regno] = | 
 | 1247 | 				((transp & 0xff00) << 16) | | 
 | 1248 | 				((red    & 0xff00) <<  8) | | 
 | 1249 | 				((green  & 0xff00)      ) | | 
 | 1250 | 				((blue   & 0xff00) >>  8); | 
 | 1251 | 		break; | 
 | 1252 |  | 
 | 1253 | 	default: | 
 | 1254 | 		return 1; | 
 | 1255 | 	} | 
 | 1256 |  | 
 | 1257 | 	return 0; | 
 | 1258 | } | 
 | 1259 |  | 
| Antonino A. Daplas | 026fbe1 | 2006-06-26 00:26:36 -0700 | [diff] [blame] | 1260 | static void savagefb_set_par_int(struct savagefb_par  *par, struct savage_reg *reg) | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 1261 | { | 
 | 1262 | 	unsigned char tmp, cr3a, cr66, cr67; | 
 | 1263 |  | 
| Antonino A. Daplas | 026fbe1 | 2006-06-26 00:26:36 -0700 | [diff] [blame] | 1264 | 	DBG("savagefb_set_par_int"); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 1265 |  | 
| Antonino A. Daplas | 026fbe1 | 2006-06-26 00:26:36 -0700 | [diff] [blame] | 1266 | 	par->SavageWaitIdle(par); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 1267 |  | 
| Antonino A. Daplas | 026fbe1 | 2006-06-26 00:26:36 -0700 | [diff] [blame] | 1268 | 	vga_out8(0x3c2, 0x23, par); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 1269 |  | 
| Antonino A. Daplas | 026fbe1 | 2006-06-26 00:26:36 -0700 | [diff] [blame] | 1270 | 	vga_out16(0x3d4, 0x4838, par); | 
 | 1271 | 	vga_out16(0x3d4, 0xa539, par); | 
 | 1272 | 	vga_out16(0x3c4, 0x0608, par); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 1273 |  | 
| Antonino A. Daplas | 026fbe1 | 2006-06-26 00:26:36 -0700 | [diff] [blame] | 1274 | 	vgaHWProtect(par, 1); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 1275 |  | 
 | 1276 | 	/* | 
 | 1277 | 	 * Some Savage/MX and /IX systems go nuts when trying to exit the | 
 | 1278 | 	 * server after WindowMaker has displayed a gradient background.  I | 
 | 1279 | 	 * haven't been able to find what causes it, but a non-destructive | 
 | 1280 | 	 * switch to mode 3 here seems to eliminate the issue. | 
 | 1281 | 	 */ | 
 | 1282 |  | 
| Antonino A. Daplas | 1cc650c | 2005-11-07 01:00:41 -0800 | [diff] [blame] | 1283 | 	VerticalRetraceWait(par); | 
| Antonino A. Daplas | 026fbe1 | 2006-06-26 00:26:36 -0700 | [diff] [blame] | 1284 | 	vga_out8(0x3d4, 0x67, par); | 
 | 1285 | 	cr67 = vga_in8(0x3d5, par); | 
 | 1286 | 	vga_out8(0x3d5, cr67/*par->CR67*/ & ~0x0c, par); /* no STREAMS yet */ | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 1287 |  | 
| Antonino A. Daplas | 026fbe1 | 2006-06-26 00:26:36 -0700 | [diff] [blame] | 1288 | 	vga_out8(0x3d4, 0x23, par); | 
 | 1289 | 	vga_out8(0x3d5, 0x00, par); | 
 | 1290 | 	vga_out8(0x3d4, 0x26, par); | 
 | 1291 | 	vga_out8(0x3d5, 0x00, par); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 1292 |  | 
 | 1293 | 	/* restore extended regs */ | 
| Antonino A. Daplas | 026fbe1 | 2006-06-26 00:26:36 -0700 | [diff] [blame] | 1294 | 	vga_out8(0x3d4, 0x66, par); | 
 | 1295 | 	vga_out8(0x3d5, reg->CR66, par); | 
 | 1296 | 	vga_out8(0x3d4, 0x3a, par); | 
 | 1297 | 	vga_out8(0x3d5, reg->CR3A, par); | 
 | 1298 | 	vga_out8(0x3d4, 0x31, par); | 
 | 1299 | 	vga_out8(0x3d5, reg->CR31, par); | 
 | 1300 | 	vga_out8(0x3d4, 0x32, par); | 
 | 1301 | 	vga_out8(0x3d5, reg->CR32, par); | 
 | 1302 | 	vga_out8(0x3d4, 0x58, par); | 
 | 1303 | 	vga_out8(0x3d5, reg->CR58, par); | 
 | 1304 | 	vga_out8(0x3d4, 0x53, par); | 
 | 1305 | 	vga_out8(0x3d5, reg->CR53 & 0x7f, par); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 1306 |  | 
| Antonino A. Daplas | 026fbe1 | 2006-06-26 00:26:36 -0700 | [diff] [blame] | 1307 | 	vga_out16(0x3c4, 0x0608, par); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 1308 |  | 
 | 1309 | 	/* Restore DCLK registers. */ | 
 | 1310 |  | 
| Antonino A. Daplas | 026fbe1 | 2006-06-26 00:26:36 -0700 | [diff] [blame] | 1311 | 	vga_out8(0x3c4, 0x0e, par); | 
 | 1312 | 	vga_out8(0x3c5, reg->SR0E, par); | 
 | 1313 | 	vga_out8(0x3c4, 0x0f, par); | 
 | 1314 | 	vga_out8(0x3c5, reg->SR0F, par); | 
 | 1315 | 	vga_out8(0x3c4, 0x29, par); | 
 | 1316 | 	vga_out8(0x3c5, reg->SR29, par); | 
 | 1317 | 	vga_out8(0x3c4, 0x15, par); | 
 | 1318 | 	vga_out8(0x3c5, reg->SR15, par); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 1319 |  | 
 | 1320 | 	/* Restore flat panel expansion regsters. */ | 
| Antonino A. Daplas | 026fbe1 | 2006-06-26 00:26:36 -0700 | [diff] [blame] | 1321 | 	if (par->chip == S3_SAVAGE_MX) { | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 1322 | 		int i; | 
 | 1323 |  | 
| Antonino A. Daplas | 026fbe1 | 2006-06-26 00:26:36 -0700 | [diff] [blame] | 1324 | 		for (i = 0; i < 8; i++) { | 
 | 1325 | 			vga_out8(0x3c4, 0x54+i, par); | 
 | 1326 | 			vga_out8(0x3c5, reg->SR54[i], par); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 1327 | 		} | 
 | 1328 | 	} | 
 | 1329 |  | 
| Antonino A. Daplas | 2356614 | 2006-06-26 00:26:23 -0700 | [diff] [blame] | 1330 | 	vgaHWRestore (par, reg); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 1331 |  | 
 | 1332 | 	/* extended mode timing registers */ | 
| Antonino A. Daplas | 026fbe1 | 2006-06-26 00:26:36 -0700 | [diff] [blame] | 1333 | 	vga_out8(0x3d4, 0x53, par); | 
 | 1334 | 	vga_out8(0x3d5, reg->CR53, par); | 
 | 1335 | 	vga_out8(0x3d4, 0x5d, par); | 
 | 1336 | 	vga_out8(0x3d5, reg->CR5D, par); | 
 | 1337 | 	vga_out8(0x3d4, 0x5e, par); | 
 | 1338 | 	vga_out8(0x3d5, reg->CR5E, par); | 
 | 1339 | 	vga_out8(0x3d4, 0x3b, par); | 
 | 1340 | 	vga_out8(0x3d5, reg->CR3B, par); | 
 | 1341 | 	vga_out8(0x3d4, 0x3c, par); | 
 | 1342 | 	vga_out8(0x3d5, reg->CR3C, par); | 
 | 1343 | 	vga_out8(0x3d4, 0x43, par); | 
 | 1344 | 	vga_out8(0x3d5, reg->CR43, par); | 
 | 1345 | 	vga_out8(0x3d4, 0x65, par); | 
 | 1346 | 	vga_out8(0x3d5, reg->CR65, par); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 1347 |  | 
 | 1348 | 	/* restore the desired video mode with cr67 */ | 
| Antonino A. Daplas | 026fbe1 | 2006-06-26 00:26:36 -0700 | [diff] [blame] | 1349 | 	vga_out8(0x3d4, 0x67, par); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 1350 | 	/* following part not present in X11 driver */ | 
| Antonino A. Daplas | 026fbe1 | 2006-06-26 00:26:36 -0700 | [diff] [blame] | 1351 | 	cr67 = vga_in8(0x3d5, par) & 0xf; | 
 | 1352 | 	vga_out8(0x3d5, 0x50 | cr67, par); | 
 | 1353 | 	udelay(10000); | 
 | 1354 | 	vga_out8(0x3d4, 0x67, par); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 1355 | 	/* end of part */ | 
| Antonino A. Daplas | 026fbe1 | 2006-06-26 00:26:36 -0700 | [diff] [blame] | 1356 | 	vga_out8(0x3d5, reg->CR67 & ~0x0c, par); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 1357 |  | 
 | 1358 | 	/* other mode timing and extended regs */ | 
| Antonino A. Daplas | 026fbe1 | 2006-06-26 00:26:36 -0700 | [diff] [blame] | 1359 | 	vga_out8(0x3d4, 0x34, par); | 
 | 1360 | 	vga_out8(0x3d5, reg->CR34, par); | 
 | 1361 | 	vga_out8(0x3d4, 0x40, par); | 
 | 1362 | 	vga_out8(0x3d5, reg->CR40, par); | 
 | 1363 | 	vga_out8(0x3d4, 0x42, par); | 
 | 1364 | 	vga_out8(0x3d5, reg->CR42, par); | 
 | 1365 | 	vga_out8(0x3d4, 0x45, par); | 
 | 1366 | 	vga_out8(0x3d5, reg->CR45, par); | 
 | 1367 | 	vga_out8(0x3d4, 0x50, par); | 
 | 1368 | 	vga_out8(0x3d5, reg->CR50, par); | 
 | 1369 | 	vga_out8(0x3d4, 0x51, par); | 
 | 1370 | 	vga_out8(0x3d5, reg->CR51, par); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 1371 |  | 
 | 1372 | 	/* memory timings */ | 
| Antonino A. Daplas | 026fbe1 | 2006-06-26 00:26:36 -0700 | [diff] [blame] | 1373 | 	vga_out8(0x3d4, 0x36, par); | 
 | 1374 | 	vga_out8(0x3d5, reg->CR36, par); | 
 | 1375 | 	vga_out8(0x3d4, 0x60, par); | 
 | 1376 | 	vga_out8(0x3d5, reg->CR60, par); | 
 | 1377 | 	vga_out8(0x3d4, 0x68, par); | 
 | 1378 | 	vga_out8(0x3d5, reg->CR68, par); | 
 | 1379 | 	vga_out8(0x3d4, 0x69, par); | 
 | 1380 | 	vga_out8(0x3d5, reg->CR69, par); | 
 | 1381 | 	vga_out8(0x3d4, 0x6f, par); | 
 | 1382 | 	vga_out8(0x3d5, reg->CR6F, par); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 1383 |  | 
| Antonino A. Daplas | 026fbe1 | 2006-06-26 00:26:36 -0700 | [diff] [blame] | 1384 | 	vga_out8(0x3d4, 0x33, par); | 
 | 1385 | 	vga_out8(0x3d5, reg->CR33, par); | 
 | 1386 | 	vga_out8(0x3d4, 0x86, par); | 
 | 1387 | 	vga_out8(0x3d5, reg->CR86, par); | 
 | 1388 | 	vga_out8(0x3d4, 0x88, par); | 
 | 1389 | 	vga_out8(0x3d5, reg->CR88, par); | 
 | 1390 | 	vga_out8(0x3d4, 0x90, par); | 
 | 1391 | 	vga_out8(0x3d5, reg->CR90, par); | 
 | 1392 | 	vga_out8(0x3d4, 0x91, par); | 
 | 1393 | 	vga_out8(0x3d5, reg->CR91, par); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 1394 |  | 
 | 1395 | 	if (par->chip == S3_SAVAGE4) { | 
| Antonino A. Daplas | 026fbe1 | 2006-06-26 00:26:36 -0700 | [diff] [blame] | 1396 | 		vga_out8(0x3d4, 0xb0, par); | 
 | 1397 | 		vga_out8(0x3d5, reg->CRB0, par); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 1398 | 	} | 
 | 1399 |  | 
| Antonino A. Daplas | 026fbe1 | 2006-06-26 00:26:36 -0700 | [diff] [blame] | 1400 | 	vga_out8(0x3d4, 0x32, par); | 
 | 1401 | 	vga_out8(0x3d5, reg->CR32, par); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 1402 |  | 
 | 1403 | 	/* unlock extended seq regs */ | 
| Antonino A. Daplas | 026fbe1 | 2006-06-26 00:26:36 -0700 | [diff] [blame] | 1404 | 	vga_out8(0x3c4, 0x08, par); | 
 | 1405 | 	vga_out8(0x3c5, 0x06, par); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 1406 |  | 
 | 1407 | 	/* Restore extended sequencer regs for MCLK. SR10 == 255 indicates | 
 | 1408 | 	 * that we should leave the default SR10 and SR11 values there. | 
 | 1409 | 	 */ | 
| Antonino A. Daplas | 2356614 | 2006-06-26 00:26:23 -0700 | [diff] [blame] | 1410 | 	if (reg->SR10 != 255) { | 
| Antonino A. Daplas | 026fbe1 | 2006-06-26 00:26:36 -0700 | [diff] [blame] | 1411 | 		vga_out8(0x3c4, 0x10, par); | 
 | 1412 | 		vga_out8(0x3c5, reg->SR10, par); | 
 | 1413 | 		vga_out8(0x3c4, 0x11, par); | 
 | 1414 | 		vga_out8(0x3c5, reg->SR11, par); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 1415 | 	} | 
 | 1416 |  | 
 | 1417 | 	/* restore extended seq regs for dclk */ | 
| Antonino A. Daplas | 026fbe1 | 2006-06-26 00:26:36 -0700 | [diff] [blame] | 1418 | 	vga_out8(0x3c4, 0x0e, par); | 
 | 1419 | 	vga_out8(0x3c5, reg->SR0E, par); | 
 | 1420 | 	vga_out8(0x3c4, 0x0f, par); | 
 | 1421 | 	vga_out8(0x3c5, reg->SR0F, par); | 
 | 1422 | 	vga_out8(0x3c4, 0x12, par); | 
 | 1423 | 	vga_out8(0x3c5, reg->SR12, par); | 
 | 1424 | 	vga_out8(0x3c4, 0x13, par); | 
 | 1425 | 	vga_out8(0x3c5, reg->SR13, par); | 
 | 1426 | 	vga_out8(0x3c4, 0x29, par); | 
 | 1427 | 	vga_out8(0x3c5, reg->SR29, par); | 
 | 1428 | 	vga_out8(0x3c4, 0x18, par); | 
 | 1429 | 	vga_out8(0x3c5, reg->SR18, par); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 1430 |  | 
 | 1431 | 	/* load new m, n pll values for dclk & mclk */ | 
| Antonino A. Daplas | 026fbe1 | 2006-06-26 00:26:36 -0700 | [diff] [blame] | 1432 | 	vga_out8(0x3c4, 0x15, par); | 
 | 1433 | 	tmp = vga_in8(0x3c5, par) & ~0x21; | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 1434 |  | 
| Antonino A. Daplas | 026fbe1 | 2006-06-26 00:26:36 -0700 | [diff] [blame] | 1435 | 	vga_out8(0x3c5, tmp | 0x03, par); | 
 | 1436 | 	vga_out8(0x3c5, tmp | 0x23, par); | 
 | 1437 | 	vga_out8(0x3c5, tmp | 0x03, par); | 
 | 1438 | 	vga_out8(0x3c5, reg->SR15, par); | 
 | 1439 | 	udelay(100); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 1440 |  | 
| Antonino A. Daplas | 026fbe1 | 2006-06-26 00:26:36 -0700 | [diff] [blame] | 1441 | 	vga_out8(0x3c4, 0x30, par); | 
 | 1442 | 	vga_out8(0x3c5, reg->SR30, par); | 
 | 1443 | 	vga_out8(0x3c4, 0x08, par); | 
 | 1444 | 	vga_out8(0x3c5, reg->SR08, par); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 1445 |  | 
 | 1446 | 	/* now write out cr67 in full, possibly starting STREAMS */ | 
| Antonino A. Daplas | 1cc650c | 2005-11-07 01:00:41 -0800 | [diff] [blame] | 1447 | 	VerticalRetraceWait(par); | 
| Antonino A. Daplas | 026fbe1 | 2006-06-26 00:26:36 -0700 | [diff] [blame] | 1448 | 	vga_out8(0x3d4, 0x67, par); | 
 | 1449 | 	vga_out8(0x3d5, reg->CR67, par); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 1450 |  | 
| Antonino A. Daplas | 026fbe1 | 2006-06-26 00:26:36 -0700 | [diff] [blame] | 1451 | 	vga_out8(0x3d4, 0x66, par); | 
 | 1452 | 	cr66 = vga_in8(0x3d5, par); | 
 | 1453 | 	vga_out8(0x3d5, cr66 | 0x80, par); | 
 | 1454 | 	vga_out8(0x3d4, 0x3a, par); | 
 | 1455 | 	cr3a = vga_in8(0x3d5, par); | 
 | 1456 | 	vga_out8(0x3d5, cr3a | 0x80, par); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 1457 |  | 
 | 1458 | 	if (par->chip != S3_SAVAGE_MX) { | 
| Antonino A. Daplas | 1cc650c | 2005-11-07 01:00:41 -0800 | [diff] [blame] | 1459 | 		VerticalRetraceWait(par); | 
| Antonino A. Daplas | 026fbe1 | 2006-06-26 00:26:36 -0700 | [diff] [blame] | 1460 | 		savage_out32(FIFO_CONTROL_REG, reg->MMPR0, par); | 
 | 1461 | 		par->SavageWaitIdle(par); | 
 | 1462 | 		savage_out32(MIU_CONTROL_REG, reg->MMPR1, par); | 
 | 1463 | 		par->SavageWaitIdle(par); | 
 | 1464 | 		savage_out32(STREAMS_TIMEOUT_REG, reg->MMPR2, par); | 
 | 1465 | 		par->SavageWaitIdle(par); | 
 | 1466 | 		savage_out32(MISC_TIMEOUT_REG, reg->MMPR3, par); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 1467 | 	} | 
 | 1468 |  | 
| Antonino A. Daplas | 026fbe1 | 2006-06-26 00:26:36 -0700 | [diff] [blame] | 1469 | 	vga_out8(0x3d4, 0x66, par); | 
 | 1470 | 	vga_out8(0x3d5, cr66, par); | 
 | 1471 | 	vga_out8(0x3d4, 0x3a, par); | 
 | 1472 | 	vga_out8(0x3d5, cr3a, par); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 1473 |  | 
| Antonino A. Daplas | 026fbe1 | 2006-06-26 00:26:36 -0700 | [diff] [blame] | 1474 | 	SavageSetup2DEngine(par); | 
 | 1475 | 	vgaHWProtect(par, 0); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 1476 | } | 
 | 1477 |  | 
| Antonino A. Daplas | 026fbe1 | 2006-06-26 00:26:36 -0700 | [diff] [blame] | 1478 | static void savagefb_update_start(struct savagefb_par      *par, | 
 | 1479 | 				  struct fb_var_screeninfo *var) | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 1480 | { | 
 | 1481 | 	int base; | 
 | 1482 |  | 
 | 1483 | 	base = ((var->yoffset * var->xres_virtual + (var->xoffset & ~1)) | 
 | 1484 | 		* ((var->bits_per_pixel+7) / 8)) >> 2; | 
 | 1485 |  | 
 | 1486 | 	/* now program the start address registers */ | 
| Antonino A. Daplas | 1cc650c | 2005-11-07 01:00:41 -0800 | [diff] [blame] | 1487 | 	vga_out16(0x3d4, (base & 0x00ff00) | 0x0c, par); | 
 | 1488 | 	vga_out16(0x3d4, ((base & 0x00ff) << 8) | 0x0d, par); | 
| Antonino A. Daplas | 026fbe1 | 2006-06-26 00:26:36 -0700 | [diff] [blame] | 1489 | 	vga_out8(0x3d4, 0x69, par); | 
 | 1490 | 	vga_out8(0x3d5, (base & 0x7f0000) >> 16, par); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 1491 | } | 
 | 1492 |  | 
 | 1493 |  | 
 | 1494 | static void savagefb_set_fix(struct fb_info *info) | 
 | 1495 | { | 
 | 1496 | 	info->fix.line_length = info->var.xres_virtual * | 
 | 1497 | 		info->var.bits_per_pixel / 8; | 
 | 1498 |  | 
| Antonino A. Daplas | 6d83b0b | 2005-11-08 21:39:05 -0800 | [diff] [blame] | 1499 | 	if (info->var.bits_per_pixel == 8) { | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 1500 | 		info->fix.visual      = FB_VISUAL_PSEUDOCOLOR; | 
| Antonino A. Daplas | 6d83b0b | 2005-11-08 21:39:05 -0800 | [diff] [blame] | 1501 | 		info->fix.xpanstep    = 4; | 
 | 1502 | 	} else { | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 1503 | 		info->fix.visual      = FB_VISUAL_TRUECOLOR; | 
| Antonino A. Daplas | 6d83b0b | 2005-11-08 21:39:05 -0800 | [diff] [blame] | 1504 | 		info->fix.xpanstep    = 2; | 
 | 1505 | 	} | 
 | 1506 |  | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 1507 | } | 
 | 1508 |  | 
| Antonino A. Daplas | 026fbe1 | 2006-06-26 00:26:36 -0700 | [diff] [blame] | 1509 | static int savagefb_set_par(struct fb_info *info) | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 1510 | { | 
| Antonino A. Daplas | b8901b0 | 2006-01-09 20:53:02 -0800 | [diff] [blame] | 1511 | 	struct savagefb_par *par = info->par; | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 1512 | 	struct fb_var_screeninfo *var = &info->var; | 
 | 1513 | 	int err; | 
 | 1514 |  | 
 | 1515 | 	DBG("savagefb_set_par"); | 
| Antonino A. Daplas | 026fbe1 | 2006-06-26 00:26:36 -0700 | [diff] [blame] | 1516 | 	err = savagefb_decode_var(var, par, &par->state); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 1517 | 	if (err) | 
 | 1518 | 		return err; | 
 | 1519 |  | 
 | 1520 | 	if (par->dacSpeedBpp <= 0) { | 
 | 1521 | 		if (var->bits_per_pixel > 24) | 
 | 1522 | 			par->dacSpeedBpp = par->clock[3]; | 
 | 1523 | 		else if (var->bits_per_pixel >= 24) | 
 | 1524 | 			par->dacSpeedBpp = par->clock[2]; | 
 | 1525 | 		else if ((var->bits_per_pixel > 8) && (var->bits_per_pixel < 24)) | 
 | 1526 | 			par->dacSpeedBpp = par->clock[1]; | 
 | 1527 | 		else if (var->bits_per_pixel <= 8) | 
 | 1528 | 			par->dacSpeedBpp = par->clock[0]; | 
 | 1529 | 	} | 
 | 1530 |  | 
 | 1531 | 	/* Set ramdac limits */ | 
 | 1532 | 	par->maxClock = par->dacSpeedBpp; | 
 | 1533 | 	par->minClock = 10000; | 
 | 1534 |  | 
| Antonino A. Daplas | 026fbe1 | 2006-06-26 00:26:36 -0700 | [diff] [blame] | 1535 | 	savagefb_set_par_int(par, &par->state); | 
 | 1536 | 	fb_set_cmap(&info->cmap, info); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 1537 | 	savagefb_set_fix(info); | 
 | 1538 | 	savagefb_set_clip(info); | 
 | 1539 |  | 
| Antonino A. Daplas | d8ad7e0 | 2007-03-16 13:38:18 -0800 | [diff] [blame] | 1540 | 	SavagePrintRegs(par); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 1541 | 	return 0; | 
 | 1542 | } | 
 | 1543 |  | 
 | 1544 | /* | 
 | 1545 |  *    Pan or Wrap the Display | 
 | 1546 |  */ | 
| Antonino A. Daplas | 026fbe1 | 2006-06-26 00:26:36 -0700 | [diff] [blame] | 1547 | static int savagefb_pan_display(struct fb_var_screeninfo *var, | 
 | 1548 | 				struct fb_info           *info) | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 1549 | { | 
| Antonino A. Daplas | b8901b0 | 2006-01-09 20:53:02 -0800 | [diff] [blame] | 1550 | 	struct savagefb_par *par = info->par; | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 1551 |  | 
| Antonino A. Daplas | 026fbe1 | 2006-06-26 00:26:36 -0700 | [diff] [blame] | 1552 | 	savagefb_update_start(par, var); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 1553 | 	return 0; | 
 | 1554 | } | 
 | 1555 |  | 
| Antonino A. Daplas | 1377671 | 2005-09-09 13:04:35 -0700 | [diff] [blame] | 1556 | static int savagefb_blank(int blank, struct fb_info *info) | 
 | 1557 | { | 
 | 1558 | 	struct savagefb_par *par = info->par; | 
 | 1559 | 	u8 sr8 = 0, srd = 0; | 
 | 1560 |  | 
 | 1561 | 	if (par->display_type == DISP_CRT) { | 
| Antonino A. Daplas | 1cc650c | 2005-11-07 01:00:41 -0800 | [diff] [blame] | 1562 | 		vga_out8(0x3c4, 0x08, par); | 
 | 1563 | 		sr8 = vga_in8(0x3c5, par); | 
| Antonino A. Daplas | 1377671 | 2005-09-09 13:04:35 -0700 | [diff] [blame] | 1564 | 		sr8 |= 0x06; | 
| Antonino A. Daplas | 1cc650c | 2005-11-07 01:00:41 -0800 | [diff] [blame] | 1565 | 		vga_out8(0x3c5, sr8, par); | 
 | 1566 | 		vga_out8(0x3c4, 0x0d, par); | 
 | 1567 | 		srd = vga_in8(0x3c5, par); | 
| Krzysztof Helt | b9f9d47 | 2009-11-11 14:26:25 -0800 | [diff] [blame] | 1568 | 		srd &= 0x50; | 
| Antonino A. Daplas | 1377671 | 2005-09-09 13:04:35 -0700 | [diff] [blame] | 1569 |  | 
 | 1570 | 		switch (blank) { | 
 | 1571 | 		case FB_BLANK_UNBLANK: | 
 | 1572 | 		case FB_BLANK_NORMAL: | 
 | 1573 | 			break; | 
 | 1574 | 		case FB_BLANK_VSYNC_SUSPEND: | 
 | 1575 | 			srd |= 0x10; | 
 | 1576 | 			break; | 
 | 1577 | 		case FB_BLANK_HSYNC_SUSPEND: | 
 | 1578 | 			srd |= 0x40; | 
 | 1579 | 			break; | 
 | 1580 | 		case FB_BLANK_POWERDOWN: | 
 | 1581 | 			srd |= 0x50; | 
 | 1582 | 			break; | 
 | 1583 | 		} | 
 | 1584 |  | 
| Antonino A. Daplas | 1cc650c | 2005-11-07 01:00:41 -0800 | [diff] [blame] | 1585 | 		vga_out8(0x3c4, 0x0d, par); | 
 | 1586 | 		vga_out8(0x3c5, srd, par); | 
| Antonino A. Daplas | 1377671 | 2005-09-09 13:04:35 -0700 | [diff] [blame] | 1587 | 	} | 
 | 1588 |  | 
 | 1589 | 	if (par->display_type == DISP_LCD || | 
 | 1590 | 	    par->display_type == DISP_DFP) { | 
 | 1591 | 		switch(blank) { | 
 | 1592 | 		case FB_BLANK_UNBLANK: | 
 | 1593 | 		case FB_BLANK_NORMAL: | 
| Antonino A. Daplas | 1cc650c | 2005-11-07 01:00:41 -0800 | [diff] [blame] | 1594 | 			vga_out8(0x3c4, 0x31, par); /* SR31 bit 4 - FP enable */ | 
 | 1595 | 			vga_out8(0x3c5, vga_in8(0x3c5, par) | 0x10, par); | 
| Antonino A. Daplas | 1377671 | 2005-09-09 13:04:35 -0700 | [diff] [blame] | 1596 | 			break; | 
 | 1597 | 		case FB_BLANK_VSYNC_SUSPEND: | 
 | 1598 | 		case FB_BLANK_HSYNC_SUSPEND: | 
 | 1599 | 		case FB_BLANK_POWERDOWN: | 
| Antonino A. Daplas | 1cc650c | 2005-11-07 01:00:41 -0800 | [diff] [blame] | 1600 | 			vga_out8(0x3c4, 0x31, par); /* SR31 bit 4 - FP enable */ | 
 | 1601 | 			vga_out8(0x3c5, vga_in8(0x3c5, par) & ~0x10, par); | 
| Antonino A. Daplas | 1377671 | 2005-09-09 13:04:35 -0700 | [diff] [blame] | 1602 | 			break; | 
 | 1603 | 		} | 
 | 1604 | 	} | 
 | 1605 |  | 
 | 1606 | 	return (blank == FB_BLANK_NORMAL) ? 1 : 0; | 
 | 1607 | } | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 1608 |  | 
| Antonino A. Daplas | 22d832e | 2007-05-08 00:38:36 -0700 | [diff] [blame] | 1609 | static int savagefb_open(struct fb_info *info, int user) | 
 | 1610 | { | 
 | 1611 | 	struct savagefb_par *par = info->par; | 
 | 1612 |  | 
 | 1613 | 	mutex_lock(&par->open_lock); | 
 | 1614 |  | 
 | 1615 | 	if (!par->open_count) { | 
 | 1616 | 		memset(&par->vgastate, 0, sizeof(par->vgastate)); | 
 | 1617 | 		par->vgastate.flags = VGA_SAVE_CMAP | VGA_SAVE_FONTS | | 
 | 1618 | 			VGA_SAVE_MODE; | 
 | 1619 | 		par->vgastate.vgabase = par->mmio.vbase + 0x8000; | 
 | 1620 | 		save_vga(&par->vgastate); | 
 | 1621 | 		savage_get_default_par(par, &par->initial); | 
 | 1622 | 	} | 
 | 1623 |  | 
 | 1624 | 	par->open_count++; | 
 | 1625 | 	mutex_unlock(&par->open_lock); | 
 | 1626 | 	return 0; | 
 | 1627 | } | 
 | 1628 |  | 
 | 1629 | static int savagefb_release(struct fb_info *info, int user) | 
 | 1630 | { | 
 | 1631 | 	struct savagefb_par *par = info->par; | 
 | 1632 |  | 
 | 1633 | 	mutex_lock(&par->open_lock); | 
 | 1634 |  | 
 | 1635 | 	if (par->open_count == 1) { | 
 | 1636 | 		savage_set_default_par(par, &par->initial); | 
 | 1637 | 		restore_vga(&par->vgastate); | 
 | 1638 | 	} | 
 | 1639 |  | 
 | 1640 | 	par->open_count--; | 
 | 1641 | 	mutex_unlock(&par->open_lock); | 
 | 1642 | 	return 0; | 
 | 1643 | } | 
 | 1644 |  | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 1645 | static struct fb_ops savagefb_ops = { | 
 | 1646 | 	.owner          = THIS_MODULE, | 
| Antonino A. Daplas | 22d832e | 2007-05-08 00:38:36 -0700 | [diff] [blame] | 1647 | 	.fb_open        = savagefb_open, | 
 | 1648 | 	.fb_release     = savagefb_release, | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 1649 | 	.fb_check_var   = savagefb_check_var, | 
 | 1650 | 	.fb_set_par     = savagefb_set_par, | 
 | 1651 | 	.fb_setcolreg   = savagefb_setcolreg, | 
 | 1652 | 	.fb_pan_display = savagefb_pan_display, | 
| Antonino A. Daplas | 1377671 | 2005-09-09 13:04:35 -0700 | [diff] [blame] | 1653 | 	.fb_blank       = savagefb_blank, | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 1654 | #if defined(CONFIG_FB_SAVAGE_ACCEL) | 
 | 1655 | 	.fb_fillrect    = savagefb_fillrect, | 
 | 1656 | 	.fb_copyarea    = savagefb_copyarea, | 
 | 1657 | 	.fb_imageblit   = savagefb_imageblit, | 
 | 1658 | 	.fb_sync        = savagefb_sync, | 
 | 1659 | #else | 
 | 1660 | 	.fb_fillrect    = cfb_fillrect, | 
 | 1661 | 	.fb_copyarea    = cfb_copyarea, | 
 | 1662 | 	.fb_imageblit   = cfb_imageblit, | 
 | 1663 | #endif | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 1664 | }; | 
 | 1665 |  | 
 | 1666 | /* --------------------------------------------------------------------- */ | 
 | 1667 |  | 
 | 1668 | static struct fb_var_screeninfo __devinitdata savagefb_var800x600x8 = { | 
 | 1669 | 	.accel_flags =	FB_ACCELF_TEXT, | 
 | 1670 | 	.xres =		800, | 
 | 1671 | 	.yres =		600, | 
 | 1672 | 	.xres_virtual =  800, | 
 | 1673 | 	.yres_virtual =  600, | 
 | 1674 | 	.bits_per_pixel = 8, | 
 | 1675 | 	.pixclock =	25000, | 
 | 1676 | 	.left_margin =	88, | 
 | 1677 | 	.right_margin =	40, | 
 | 1678 | 	.upper_margin =	23, | 
 | 1679 | 	.lower_margin =	1, | 
 | 1680 | 	.hsync_len =	128, | 
 | 1681 | 	.vsync_len =	4, | 
 | 1682 | 	.sync =		FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, | 
 | 1683 | 	.vmode =	FB_VMODE_NONINTERLACED | 
 | 1684 | }; | 
 | 1685 |  | 
| Antonino A. Daplas | 026fbe1 | 2006-06-26 00:26:36 -0700 | [diff] [blame] | 1686 | static void savage_enable_mmio(struct savagefb_par *par) | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 1687 | { | 
 | 1688 | 	unsigned char val; | 
 | 1689 |  | 
| Antonino A. Daplas | 026fbe1 | 2006-06-26 00:26:36 -0700 | [diff] [blame] | 1690 | 	DBG("savage_enable_mmio\n"); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 1691 |  | 
| Antonino A. Daplas | 026fbe1 | 2006-06-26 00:26:36 -0700 | [diff] [blame] | 1692 | 	val = vga_in8(0x3c3, par); | 
 | 1693 | 	vga_out8(0x3c3, val | 0x01, par); | 
 | 1694 | 	val = vga_in8(0x3cc, par); | 
 | 1695 | 	vga_out8(0x3c2, val | 0x01, par); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 1696 |  | 
 | 1697 | 	if (par->chip >= S3_SAVAGE4) { | 
| Antonino A. Daplas | 026fbe1 | 2006-06-26 00:26:36 -0700 | [diff] [blame] | 1698 | 		vga_out8(0x3d4, 0x40, par); | 
 | 1699 | 		val = vga_in8(0x3d5, par); | 
 | 1700 | 		vga_out8(0x3d5, val | 1, par); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 1701 | 	} | 
 | 1702 | } | 
 | 1703 |  | 
 | 1704 |  | 
| Antonino A. Daplas | 026fbe1 | 2006-06-26 00:26:36 -0700 | [diff] [blame] | 1705 | static void savage_disable_mmio(struct savagefb_par *par) | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 1706 | { | 
 | 1707 | 	unsigned char val; | 
 | 1708 |  | 
| Antonino A. Daplas | 026fbe1 | 2006-06-26 00:26:36 -0700 | [diff] [blame] | 1709 | 	DBG("savage_disable_mmio\n"); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 1710 |  | 
| Antonino A. Daplas | 026fbe1 | 2006-06-26 00:26:36 -0700 | [diff] [blame] | 1711 | 	if (par->chip >= S3_SAVAGE4) { | 
 | 1712 | 		vga_out8(0x3d4, 0x40, par); | 
 | 1713 | 		val = vga_in8(0x3d5, par); | 
 | 1714 | 		vga_out8(0x3d5, val | 1, par); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 1715 | 	} | 
 | 1716 | } | 
 | 1717 |  | 
 | 1718 |  | 
| Antonino A. Daplas | 026fbe1 | 2006-06-26 00:26:36 -0700 | [diff] [blame] | 1719 | static int __devinit savage_map_mmio(struct fb_info *info) | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 1720 | { | 
| Antonino A. Daplas | b8901b0 | 2006-01-09 20:53:02 -0800 | [diff] [blame] | 1721 | 	struct savagefb_par *par = info->par; | 
| Antonino A. Daplas | 026fbe1 | 2006-06-26 00:26:36 -0700 | [diff] [blame] | 1722 | 	DBG("savage_map_mmio"); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 1723 |  | 
| Antonino A. Daplas | 026fbe1 | 2006-06-26 00:26:36 -0700 | [diff] [blame] | 1724 | 	if (S3_SAVAGE3D_SERIES(par->chip)) | 
 | 1725 | 		par->mmio.pbase = pci_resource_start(par->pcidev, 0) + | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 1726 | 			SAVAGE_NEWMMIO_REGBASE_S3; | 
 | 1727 | 	else | 
| Antonino A. Daplas | 026fbe1 | 2006-06-26 00:26:36 -0700 | [diff] [blame] | 1728 | 		par->mmio.pbase = pci_resource_start(par->pcidev, 0) + | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 1729 | 			SAVAGE_NEWMMIO_REGBASE_S4; | 
 | 1730 |  | 
 | 1731 | 	par->mmio.len = SAVAGE_NEWMMIO_REGSIZE; | 
 | 1732 |  | 
| Antonino A. Daplas | 026fbe1 | 2006-06-26 00:26:36 -0700 | [diff] [blame] | 1733 | 	par->mmio.vbase = ioremap(par->mmio.pbase, par->mmio.len); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 1734 | 	if (!par->mmio.vbase) { | 
| Antonino A. Daplas | 026fbe1 | 2006-06-26 00:26:36 -0700 | [diff] [blame] | 1735 | 		printk("savagefb: unable to map memory mapped IO\n"); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 1736 | 		return -ENOMEM; | 
 | 1737 | 	} else | 
| Antonino A. Daplas | 026fbe1 | 2006-06-26 00:26:36 -0700 | [diff] [blame] | 1738 | 		printk(KERN_INFO "savagefb: mapped io at %p\n", | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 1739 | 			par->mmio.vbase); | 
 | 1740 |  | 
 | 1741 | 	info->fix.mmio_start = par->mmio.pbase; | 
 | 1742 | 	info->fix.mmio_len   = par->mmio.len; | 
 | 1743 |  | 
| Al Viro | 0d3e8fe | 2005-04-26 07:43:41 -0700 | [diff] [blame] | 1744 | 	par->bci_base = (u32 __iomem *)(par->mmio.vbase + BCI_BUFFER_OFFSET); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 1745 | 	par->bci_ptr  = 0; | 
 | 1746 |  | 
| Antonino A. Daplas | 026fbe1 | 2006-06-26 00:26:36 -0700 | [diff] [blame] | 1747 | 	savage_enable_mmio(par); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 1748 |  | 
 | 1749 | 	return 0; | 
 | 1750 | } | 
 | 1751 |  | 
| Antonino A. Daplas | 026fbe1 | 2006-06-26 00:26:36 -0700 | [diff] [blame] | 1752 | static void savage_unmap_mmio(struct fb_info *info) | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 1753 | { | 
| Antonino A. Daplas | b8901b0 | 2006-01-09 20:53:02 -0800 | [diff] [blame] | 1754 | 	struct savagefb_par *par = info->par; | 
| Antonino A. Daplas | 026fbe1 | 2006-06-26 00:26:36 -0700 | [diff] [blame] | 1755 | 	DBG("savage_unmap_mmio"); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 1756 |  | 
 | 1757 | 	savage_disable_mmio(par); | 
 | 1758 |  | 
 | 1759 | 	if (par->mmio.vbase) { | 
| Al Viro | 0d3e8fe | 2005-04-26 07:43:41 -0700 | [diff] [blame] | 1760 | 		iounmap(par->mmio.vbase); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 1761 | 		par->mmio.vbase = NULL; | 
 | 1762 | 	} | 
 | 1763 | } | 
 | 1764 |  | 
| Antonino A. Daplas | 026fbe1 | 2006-06-26 00:26:36 -0700 | [diff] [blame] | 1765 | static int __devinit savage_map_video(struct fb_info *info, | 
 | 1766 | 				      int video_len) | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 1767 | { | 
| Antonino A. Daplas | b8901b0 | 2006-01-09 20:53:02 -0800 | [diff] [blame] | 1768 | 	struct savagefb_par *par = info->par; | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 1769 | 	int resource; | 
 | 1770 |  | 
 | 1771 | 	DBG("savage_map_video"); | 
 | 1772 |  | 
| Antonino A. Daplas | 026fbe1 | 2006-06-26 00:26:36 -0700 | [diff] [blame] | 1773 | 	if (S3_SAVAGE3D_SERIES(par->chip)) | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 1774 | 		resource = 0; | 
 | 1775 | 	else | 
 | 1776 | 		resource = 1; | 
 | 1777 |  | 
| Antonino A. Daplas | 026fbe1 | 2006-06-26 00:26:36 -0700 | [diff] [blame] | 1778 | 	par->video.pbase = pci_resource_start(par->pcidev, resource); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 1779 | 	par->video.len   = video_len; | 
| Antonino A. Daplas | 026fbe1 | 2006-06-26 00:26:36 -0700 | [diff] [blame] | 1780 | 	par->video.vbase = ioremap(par->video.pbase, par->video.len); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 1781 |  | 
 | 1782 | 	if (!par->video.vbase) { | 
| Antonino A. Daplas | 026fbe1 | 2006-06-26 00:26:36 -0700 | [diff] [blame] | 1783 | 		printk("savagefb: unable to map screen memory\n"); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 1784 | 		return -ENOMEM; | 
 | 1785 | 	} else | 
| Antonino A. Daplas | 026fbe1 | 2006-06-26 00:26:36 -0700 | [diff] [blame] | 1786 | 		printk(KERN_INFO "savagefb: mapped framebuffer at %p, " | 
 | 1787 | 		       "pbase == %x\n", par->video.vbase, par->video.pbase); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 1788 |  | 
 | 1789 | 	info->fix.smem_start = par->video.pbase; | 
 | 1790 | 	info->fix.smem_len   = par->video.len - par->cob_size; | 
 | 1791 | 	info->screen_base    = par->video.vbase; | 
 | 1792 |  | 
 | 1793 | #ifdef CONFIG_MTRR | 
| Antonino A. Daplas | 026fbe1 | 2006-06-26 00:26:36 -0700 | [diff] [blame] | 1794 | 	par->video.mtrr = mtrr_add(par->video.pbase, video_len, | 
 | 1795 | 				   MTRR_TYPE_WRCOMB, 1); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 1796 | #endif | 
 | 1797 |  | 
 | 1798 | 	/* Clear framebuffer, it's all white in memory after boot */ | 
| Antonino A. Daplas | 026fbe1 | 2006-06-26 00:26:36 -0700 | [diff] [blame] | 1799 | 	memset_io(par->video.vbase, 0, par->video.len); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 1800 |  | 
 | 1801 | 	return 0; | 
 | 1802 | } | 
 | 1803 |  | 
| Antonino A. Daplas | 026fbe1 | 2006-06-26 00:26:36 -0700 | [diff] [blame] | 1804 | static void savage_unmap_video(struct fb_info *info) | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 1805 | { | 
| Antonino A. Daplas | b8901b0 | 2006-01-09 20:53:02 -0800 | [diff] [blame] | 1806 | 	struct savagefb_par *par = info->par; | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 1807 |  | 
 | 1808 | 	DBG("savage_unmap_video"); | 
 | 1809 |  | 
 | 1810 | 	if (par->video.vbase) { | 
 | 1811 | #ifdef CONFIG_MTRR | 
| Antonino A. Daplas | 026fbe1 | 2006-06-26 00:26:36 -0700 | [diff] [blame] | 1812 | 		mtrr_del(par->video.mtrr, par->video.pbase, par->video.len); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 1813 | #endif | 
 | 1814 |  | 
| Antonino A. Daplas | 026fbe1 | 2006-06-26 00:26:36 -0700 | [diff] [blame] | 1815 | 		iounmap(par->video.vbase); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 1816 | 		par->video.vbase = NULL; | 
 | 1817 | 		info->screen_base = NULL; | 
 | 1818 | 	} | 
 | 1819 | } | 
 | 1820 |  | 
| Antonino A. Daplas | 026fbe1 | 2006-06-26 00:26:36 -0700 | [diff] [blame] | 1821 | static int savage_init_hw(struct savagefb_par *par) | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 1822 | { | 
 | 1823 | 	unsigned char config1, m, n, n1, n2, sr8, cr3f, cr66 = 0, tmp; | 
 | 1824 |  | 
 | 1825 | 	static unsigned char RamSavage3D[] = { 8, 4, 4, 2 }; | 
 | 1826 | 	static unsigned char RamSavage4[] =  { 2, 4, 8, 12, 16, 32, 64, 32 }; | 
 | 1827 | 	static unsigned char RamSavageMX[] = { 2, 8, 4, 16, 8, 16, 4, 16 }; | 
 | 1828 | 	static unsigned char RamSavageNB[] = { 0, 2, 4, 8, 16, 32, 2, 2 }; | 
| Antonino A. Daplas | 1377671 | 2005-09-09 13:04:35 -0700 | [diff] [blame] | 1829 | 	int videoRam, videoRambytes, dvi; | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 1830 |  | 
 | 1831 | 	DBG("savage_init_hw"); | 
 | 1832 |  | 
 | 1833 | 	/* unprotect CRTC[0-7] */ | 
| Antonino A. Daplas | 1cc650c | 2005-11-07 01:00:41 -0800 | [diff] [blame] | 1834 | 	vga_out8(0x3d4, 0x11, par); | 
 | 1835 | 	tmp = vga_in8(0x3d5, par); | 
 | 1836 | 	vga_out8(0x3d5, tmp & 0x7f, par); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 1837 |  | 
 | 1838 | 	/* unlock extended regs */ | 
| Antonino A. Daplas | 1cc650c | 2005-11-07 01:00:41 -0800 | [diff] [blame] | 1839 | 	vga_out16(0x3d4, 0x4838, par); | 
 | 1840 | 	vga_out16(0x3d4, 0xa039, par); | 
 | 1841 | 	vga_out16(0x3c4, 0x0608, par); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 1842 |  | 
| Antonino A. Daplas | 1cc650c | 2005-11-07 01:00:41 -0800 | [diff] [blame] | 1843 | 	vga_out8(0x3d4, 0x40, par); | 
 | 1844 | 	tmp = vga_in8(0x3d5, par); | 
 | 1845 | 	vga_out8(0x3d5, tmp & ~0x01, par); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 1846 |  | 
 | 1847 | 	/* unlock sys regs */ | 
| Antonino A. Daplas | 1cc650c | 2005-11-07 01:00:41 -0800 | [diff] [blame] | 1848 | 	vga_out8(0x3d4, 0x38, par); | 
 | 1849 | 	vga_out8(0x3d5, 0x48, par); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 1850 |  | 
 | 1851 | 	/* Unlock system registers. */ | 
| Antonino A. Daplas | 1cc650c | 2005-11-07 01:00:41 -0800 | [diff] [blame] | 1852 | 	vga_out16(0x3d4, 0x4838, par); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 1853 |  | 
 | 1854 | 	/* Next go on to detect amount of installed ram */ | 
 | 1855 |  | 
| Antonino A. Daplas | 1cc650c | 2005-11-07 01:00:41 -0800 | [diff] [blame] | 1856 | 	vga_out8(0x3d4, 0x36, par);            /* for register CR36 (CONFG_REG1), */ | 
 | 1857 | 	config1 = vga_in8(0x3d5, par);    /* get amount of vram installed */ | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 1858 |  | 
 | 1859 | 	/* Compute the amount of video memory and offscreen memory. */ | 
 | 1860 |  | 
 | 1861 | 	switch  (par->chip) { | 
 | 1862 | 	case S3_SAVAGE3D: | 
| Antonino A. Daplas | 026fbe1 | 2006-06-26 00:26:36 -0700 | [diff] [blame] | 1863 | 		videoRam = RamSavage3D[(config1 & 0xC0) >> 6 ] * 1024; | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 1864 | 		break; | 
 | 1865 |  | 
 | 1866 | 	case S3_SAVAGE4: | 
 | 1867 | 		/* | 
 | 1868 | 		 * The Savage4 has one ugly special case to consider.  On | 
 | 1869 | 		 * systems with 4 banks of 2Mx32 SDRAM, the BIOS says 4MB | 
 | 1870 | 		 * when it really means 8MB.  Why do it the same when you | 
 | 1871 | 		 * can do it different... | 
 | 1872 | 		 */ | 
| Antonino A. Daplas | 1cc650c | 2005-11-07 01:00:41 -0800 | [diff] [blame] | 1873 | 		vga_out8(0x3d4, 0x68, par);	/* memory control 1 */ | 
| Antonino A. Daplas | 026fbe1 | 2006-06-26 00:26:36 -0700 | [diff] [blame] | 1874 | 		if ((vga_in8(0x3d5, par) & 0xC0) == (0x01 << 6)) | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 1875 | 			RamSavage4[1] = 8; | 
 | 1876 |  | 
 | 1877 | 		/*FALLTHROUGH*/ | 
 | 1878 |  | 
 | 1879 | 	case S3_SAVAGE2000: | 
| Antonino A. Daplas | 026fbe1 | 2006-06-26 00:26:36 -0700 | [diff] [blame] | 1880 | 		videoRam = RamSavage4[(config1 & 0xE0) >> 5] * 1024; | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 1881 | 		break; | 
 | 1882 |  | 
 | 1883 | 	case S3_SAVAGE_MX: | 
 | 1884 | 	case S3_SUPERSAVAGE: | 
| Antonino A. Daplas | 026fbe1 | 2006-06-26 00:26:36 -0700 | [diff] [blame] | 1885 | 		videoRam = RamSavageMX[(config1 & 0x0E) >> 1] * 1024; | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 1886 | 		break; | 
 | 1887 |  | 
 | 1888 | 	case S3_PROSAVAGE: | 
| Antonino A. Daplas | 026fbe1 | 2006-06-26 00:26:36 -0700 | [diff] [blame] | 1889 | 		videoRam = RamSavageNB[(config1 & 0xE0) >> 5] * 1024; | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 1890 | 		break; | 
 | 1891 |  | 
 | 1892 | 	default: | 
 | 1893 | 		/* How did we get here? */ | 
 | 1894 | 		videoRam = 0; | 
 | 1895 | 		break; | 
 | 1896 | 	} | 
 | 1897 |  | 
 | 1898 | 	videoRambytes = videoRam * 1024; | 
 | 1899 |  | 
| Antonino A. Daplas | 026fbe1 | 2006-06-26 00:26:36 -0700 | [diff] [blame] | 1900 | 	printk(KERN_INFO "savagefb: probed videoram:  %dk\n", videoRam); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 1901 |  | 
 | 1902 | 	/* reset graphics engine to avoid memory corruption */ | 
| Antonino A. Daplas | 026fbe1 | 2006-06-26 00:26:36 -0700 | [diff] [blame] | 1903 | 	vga_out8(0x3d4, 0x66, par); | 
 | 1904 | 	cr66 = vga_in8(0x3d5, par); | 
 | 1905 | 	vga_out8(0x3d5, cr66 | 0x02, par); | 
 | 1906 | 	udelay(10000); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 1907 |  | 
| Antonino A. Daplas | 026fbe1 | 2006-06-26 00:26:36 -0700 | [diff] [blame] | 1908 | 	vga_out8(0x3d4, 0x66, par); | 
 | 1909 | 	vga_out8(0x3d5, cr66 & ~0x02, par);	/* clear reset flag */ | 
 | 1910 | 	udelay(10000); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 1911 |  | 
 | 1912 |  | 
 | 1913 | 	/* | 
 | 1914 | 	 * reset memory interface, 3D engine, AGP master, PCI master, | 
 | 1915 | 	 * master engine unit, motion compensation/LPB | 
 | 1916 | 	 */ | 
| Antonino A. Daplas | 026fbe1 | 2006-06-26 00:26:36 -0700 | [diff] [blame] | 1917 | 	vga_out8(0x3d4, 0x3f, par); | 
 | 1918 | 	cr3f = vga_in8(0x3d5, par); | 
 | 1919 | 	vga_out8(0x3d5, cr3f | 0x08, par); | 
 | 1920 | 	udelay(10000); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 1921 |  | 
| Antonino A. Daplas | 026fbe1 | 2006-06-26 00:26:36 -0700 | [diff] [blame] | 1922 | 	vga_out8(0x3d4, 0x3f, par); | 
 | 1923 | 	vga_out8(0x3d5, cr3f & ~0x08, par);	/* clear reset flags */ | 
 | 1924 | 	udelay(10000); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 1925 |  | 
 | 1926 | 	/* Savage ramdac speeds */ | 
 | 1927 | 	par->numClocks = 4; | 
 | 1928 | 	par->clock[0] = 250000; | 
 | 1929 | 	par->clock[1] = 250000; | 
 | 1930 | 	par->clock[2] = 220000; | 
 | 1931 | 	par->clock[3] = 220000; | 
 | 1932 |  | 
 | 1933 | 	/* detect current mclk */ | 
| Antonino A. Daplas | 1cc650c | 2005-11-07 01:00:41 -0800 | [diff] [blame] | 1934 | 	vga_out8(0x3c4, 0x08, par); | 
 | 1935 | 	sr8 = vga_in8(0x3c5, par); | 
 | 1936 | 	vga_out8(0x3c5, 0x06, par); | 
 | 1937 | 	vga_out8(0x3c4, 0x10, par); | 
 | 1938 | 	n = vga_in8(0x3c5, par); | 
 | 1939 | 	vga_out8(0x3c4, 0x11, par); | 
 | 1940 | 	m = vga_in8(0x3c5, par); | 
 | 1941 | 	vga_out8(0x3c4, 0x08, par); | 
 | 1942 | 	vga_out8(0x3c5, sr8, par); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 1943 | 	m &= 0x7f; | 
 | 1944 | 	n1 = n & 0x1f; | 
 | 1945 | 	n2 = (n >> 5) & 0x03; | 
 | 1946 | 	par->MCLK = ((1431818 * (m+2)) / (n1+2) / (1 << n2) + 50) / 100; | 
| Antonino A. Daplas | 026fbe1 | 2006-06-26 00:26:36 -0700 | [diff] [blame] | 1947 | 	printk(KERN_INFO "savagefb: Detected current MCLK value of %d kHz\n", | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 1948 | 		par->MCLK); | 
 | 1949 |  | 
| Antonino A. Daplas | 1377671 | 2005-09-09 13:04:35 -0700 | [diff] [blame] | 1950 | 	/* check for DVI/flat panel */ | 
 | 1951 | 	dvi = 0; | 
 | 1952 |  | 
 | 1953 | 	if (par->chip == S3_SAVAGE4) { | 
 | 1954 | 		unsigned char sr30 = 0x00; | 
 | 1955 |  | 
| Antonino A. Daplas | 1cc650c | 2005-11-07 01:00:41 -0800 | [diff] [blame] | 1956 | 		vga_out8(0x3c4, 0x30, par); | 
| Antonino A. Daplas | 1377671 | 2005-09-09 13:04:35 -0700 | [diff] [blame] | 1957 | 		/* clear bit 1 */ | 
| Antonino A. Daplas | 1cc650c | 2005-11-07 01:00:41 -0800 | [diff] [blame] | 1958 | 		vga_out8(0x3c5, vga_in8(0x3c5, par) & ~0x02, par); | 
 | 1959 | 		sr30 = vga_in8(0x3c5, par); | 
| Antonino A. Daplas | 1377671 | 2005-09-09 13:04:35 -0700 | [diff] [blame] | 1960 | 		if (sr30 & 0x02 /*0x04 */) { | 
 | 1961 | 			dvi = 1; | 
 | 1962 | 			printk("savagefb: Digital Flat Panel Detected\n"); | 
 | 1963 | 		} | 
 | 1964 | 	} | 
 | 1965 |  | 
| Antonino A. Daplas | 7b6a186 | 2005-09-15 20:58:57 +0800 | [diff] [blame] | 1966 | 	if (S3_SAVAGE_MOBILE_SERIES(par->chip) && !par->crtonly) | 
| Antonino A. Daplas | 1377671 | 2005-09-09 13:04:35 -0700 | [diff] [blame] | 1967 | 		par->display_type = DISP_LCD; | 
 | 1968 | 	else if (dvi || (par->chip == S3_SAVAGE4 && par->dvi)) | 
 | 1969 | 		par->display_type = DISP_DFP; | 
 | 1970 | 	else | 
 | 1971 | 		par->display_type = DISP_CRT; | 
 | 1972 |  | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 1973 | 	/* Check LCD panel parrmation */ | 
 | 1974 |  | 
| Antonino A. Daplas | 7b6a186 | 2005-09-15 20:58:57 +0800 | [diff] [blame] | 1975 | 	if (par->display_type == DISP_LCD) { | 
| Antonino A. Daplas | 026fbe1 | 2006-06-26 00:26:36 -0700 | [diff] [blame] | 1976 | 		unsigned char cr6b = VGArCR(0x6b, par); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 1977 |  | 
| Antonino A. Daplas | 026fbe1 | 2006-06-26 00:26:36 -0700 | [diff] [blame] | 1978 | 		int panelX = (VGArSEQ(0x61, par) + | 
 | 1979 | 			      ((VGArSEQ(0x66, par) & 0x02) << 7) + 1) * 8; | 
 | 1980 | 		int panelY = (VGArSEQ(0x69, par) + | 
 | 1981 | 			      ((VGArSEQ(0x6e, par) & 0x70) << 4) + 1); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 1982 |  | 
 | 1983 | 		char * sTechnology = "Unknown"; | 
 | 1984 |  | 
 | 1985 | 		/* OK, I admit it.  I don't know how to limit the max dot clock | 
 | 1986 | 		 * for LCD panels of various sizes.  I thought I copied the | 
 | 1987 | 		 * formula from the BIOS, but many users have parrmed me of | 
 | 1988 | 		 * my folly. | 
 | 1989 | 		 * | 
 | 1990 | 		 * Instead, I'll abandon any attempt to automatically limit the | 
 | 1991 | 		 * clock, and add an LCDClock option to XF86Config.  Some day, | 
 | 1992 | 		 * I should come back to this. | 
 | 1993 | 		 */ | 
 | 1994 |  | 
 | 1995 | 		enum ACTIVE_DISPLAYS { /* These are the bits in CR6B */ | 
 | 1996 | 			ActiveCRT = 0x01, | 
 | 1997 | 			ActiveLCD = 0x02, | 
 | 1998 | 			ActiveTV = 0x04, | 
 | 1999 | 			ActiveCRT2 = 0x20, | 
 | 2000 | 			ActiveDUO = 0x80 | 
 | 2001 | 		}; | 
 | 2002 |  | 
| Antonino A. Daplas | 026fbe1 | 2006-06-26 00:26:36 -0700 | [diff] [blame] | 2003 | 		if ((VGArSEQ(0x39, par) & 0x03) == 0) { | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 2004 | 			sTechnology = "TFT"; | 
| Antonino A. Daplas | 026fbe1 | 2006-06-26 00:26:36 -0700 | [diff] [blame] | 2005 | 		} else if ((VGArSEQ(0x30, par) & 0x01) == 0) { | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 2006 | 			sTechnology = "DSTN"; | 
 | 2007 | 		} else 	{ | 
 | 2008 | 			sTechnology = "STN"; | 
 | 2009 | 		} | 
 | 2010 |  | 
| Antonino A. Daplas | 026fbe1 | 2006-06-26 00:26:36 -0700 | [diff] [blame] | 2011 | 		printk(KERN_INFO "savagefb: %dx%d %s LCD panel detected %s\n", | 
 | 2012 | 		       panelX, panelY, sTechnology, | 
 | 2013 | 		       cr6b & ActiveLCD ? "and active" : "but not active"); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 2014 |  | 
| Antonino A. Daplas | 026fbe1 | 2006-06-26 00:26:36 -0700 | [diff] [blame] | 2015 | 		if (cr6b & ActiveLCD) 	{ | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 2016 | 			/* | 
 | 2017 | 			 * If the LCD is active and panel expansion is enabled, | 
 | 2018 | 			 * we probably want to kill the HW cursor. | 
 | 2019 | 			 */ | 
 | 2020 |  | 
| Antonino A. Daplas | 026fbe1 | 2006-06-26 00:26:36 -0700 | [diff] [blame] | 2021 | 			printk(KERN_INFO "savagefb: Limiting video mode to " | 
 | 2022 | 				"%dx%d\n", panelX, panelY); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 2023 |  | 
 | 2024 | 			par->SavagePanelWidth = panelX; | 
 | 2025 | 			par->SavagePanelHeight = panelY; | 
 | 2026 |  | 
| Antonino A. Daplas | 1377671 | 2005-09-09 13:04:35 -0700 | [diff] [blame] | 2027 | 		} else | 
 | 2028 | 			par->display_type = DISP_CRT; | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 2029 | 	} | 
 | 2030 |  | 
| Antonino A. Daplas | 026fbe1 | 2006-06-26 00:26:36 -0700 | [diff] [blame] | 2031 | 	savage_get_default_par(par, &par->state); | 
| Antonino A. Daplas | 2356614 | 2006-06-26 00:26:23 -0700 | [diff] [blame] | 2032 | 	par->save = par->state; | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 2033 |  | 
| Antonino A. Daplas | 026fbe1 | 2006-06-26 00:26:36 -0700 | [diff] [blame] | 2034 | 	if (S3_SAVAGE4_SERIES(par->chip)) { | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 2035 | 		/* | 
 | 2036 | 		 * The Savage4 and ProSavage have COB coherency bugs which | 
 | 2037 | 		 * render the buffer useless.  We disable it. | 
 | 2038 | 		 */ | 
 | 2039 | 		par->cob_index = 2; | 
 | 2040 | 		par->cob_size = 0x8000 << par->cob_index; | 
 | 2041 | 		par->cob_offset = videoRambytes; | 
 | 2042 | 	} else { | 
 | 2043 | 		/* We use 128kB for the COB on all chips. */ | 
 | 2044 |  | 
 | 2045 | 		par->cob_index  = 7; | 
 | 2046 | 		par->cob_size   = 0x400 << par->cob_index; | 
 | 2047 | 		par->cob_offset = videoRambytes - par->cob_size; | 
 | 2048 | 	} | 
 | 2049 |  | 
 | 2050 | 	return videoRambytes; | 
 | 2051 | } | 
 | 2052 |  | 
| Antonino A. Daplas | 026fbe1 | 2006-06-26 00:26:36 -0700 | [diff] [blame] | 2053 | static int __devinit savage_init_fb_info(struct fb_info *info, | 
 | 2054 | 					 struct pci_dev *dev, | 
 | 2055 | 					 const struct pci_device_id *id) | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 2056 | { | 
| Antonino A. Daplas | b8901b0 | 2006-01-09 20:53:02 -0800 | [diff] [blame] | 2057 | 	struct savagefb_par *par = info->par; | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 2058 | 	int err = 0; | 
 | 2059 |  | 
 | 2060 | 	par->pcidev  = dev; | 
 | 2061 |  | 
 | 2062 | 	info->fix.type	   = FB_TYPE_PACKED_PIXELS; | 
 | 2063 | 	info->fix.type_aux	   = 0; | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 2064 | 	info->fix.ypanstep	   = 1; | 
 | 2065 | 	info->fix.ywrapstep   = 0; | 
 | 2066 | 	info->fix.accel       = id->driver_data; | 
 | 2067 |  | 
 | 2068 | 	switch (info->fix.accel) { | 
 | 2069 | 	case FB_ACCEL_SUPERSAVAGE: | 
 | 2070 | 		par->chip = S3_SUPERSAVAGE; | 
| Antonino A. Daplas | 026fbe1 | 2006-06-26 00:26:36 -0700 | [diff] [blame] | 2071 | 		snprintf(info->fix.id, 16, "SuperSavage"); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 2072 | 		break; | 
 | 2073 | 	case FB_ACCEL_SAVAGE4: | 
 | 2074 | 		par->chip = S3_SAVAGE4; | 
| Antonino A. Daplas | 026fbe1 | 2006-06-26 00:26:36 -0700 | [diff] [blame] | 2075 | 		snprintf(info->fix.id, 16, "Savage4"); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 2076 | 		break; | 
 | 2077 | 	case FB_ACCEL_SAVAGE3D: | 
 | 2078 | 		par->chip = S3_SAVAGE3D; | 
| Antonino A. Daplas | 026fbe1 | 2006-06-26 00:26:36 -0700 | [diff] [blame] | 2079 | 		snprintf(info->fix.id, 16, "Savage3D"); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 2080 | 		break; | 
 | 2081 | 	case FB_ACCEL_SAVAGE3D_MV: | 
 | 2082 | 		par->chip = S3_SAVAGE3D; | 
| Antonino A. Daplas | 026fbe1 | 2006-06-26 00:26:36 -0700 | [diff] [blame] | 2083 | 		snprintf(info->fix.id, 16, "Savage3D-MV"); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 2084 | 		break; | 
 | 2085 | 	case FB_ACCEL_SAVAGE2000: | 
 | 2086 | 		par->chip = S3_SAVAGE2000; | 
| Antonino A. Daplas | 026fbe1 | 2006-06-26 00:26:36 -0700 | [diff] [blame] | 2087 | 		snprintf(info->fix.id, 16, "Savage2000"); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 2088 | 		break; | 
 | 2089 | 	case FB_ACCEL_SAVAGE_MX_MV: | 
 | 2090 | 		par->chip = S3_SAVAGE_MX; | 
| Antonino A. Daplas | 026fbe1 | 2006-06-26 00:26:36 -0700 | [diff] [blame] | 2091 | 		snprintf(info->fix.id, 16, "Savage/MX-MV"); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 2092 | 		break; | 
 | 2093 | 	case FB_ACCEL_SAVAGE_MX: | 
 | 2094 | 		par->chip = S3_SAVAGE_MX; | 
| Antonino A. Daplas | 026fbe1 | 2006-06-26 00:26:36 -0700 | [diff] [blame] | 2095 | 		snprintf(info->fix.id, 16, "Savage/MX"); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 2096 | 		break; | 
 | 2097 | 	case FB_ACCEL_SAVAGE_IX_MV: | 
 | 2098 | 		par->chip = S3_SAVAGE_MX; | 
| Antonino A. Daplas | 026fbe1 | 2006-06-26 00:26:36 -0700 | [diff] [blame] | 2099 | 		snprintf(info->fix.id, 16, "Savage/IX-MV"); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 2100 | 		break; | 
 | 2101 | 	case FB_ACCEL_SAVAGE_IX: | 
 | 2102 | 		par->chip = S3_SAVAGE_MX; | 
| Antonino A. Daplas | 026fbe1 | 2006-06-26 00:26:36 -0700 | [diff] [blame] | 2103 | 		snprintf(info->fix.id, 16, "Savage/IX"); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 2104 | 		break; | 
 | 2105 | 	case FB_ACCEL_PROSAVAGE_PM: | 
 | 2106 | 		par->chip = S3_PROSAVAGE; | 
| Antonino A. Daplas | 026fbe1 | 2006-06-26 00:26:36 -0700 | [diff] [blame] | 2107 | 		snprintf(info->fix.id, 16, "ProSavagePM"); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 2108 | 		break; | 
 | 2109 | 	case FB_ACCEL_PROSAVAGE_KM: | 
 | 2110 | 		par->chip = S3_PROSAVAGE; | 
| Antonino A. Daplas | 026fbe1 | 2006-06-26 00:26:36 -0700 | [diff] [blame] | 2111 | 		snprintf(info->fix.id, 16, "ProSavageKM"); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 2112 | 		break; | 
 | 2113 | 	case FB_ACCEL_S3TWISTER_P: | 
| Antonino A. Daplas | 7b6a186 | 2005-09-15 20:58:57 +0800 | [diff] [blame] | 2114 | 		par->chip = S3_PROSAVAGE; | 
| Antonino A. Daplas | 026fbe1 | 2006-06-26 00:26:36 -0700 | [diff] [blame] | 2115 | 		snprintf(info->fix.id, 16, "TwisterP"); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 2116 | 		break; | 
 | 2117 | 	case FB_ACCEL_S3TWISTER_K: | 
| Antonino A. Daplas | 7b6a186 | 2005-09-15 20:58:57 +0800 | [diff] [blame] | 2118 | 		par->chip = S3_PROSAVAGE; | 
| Antonino A. Daplas | 026fbe1 | 2006-06-26 00:26:36 -0700 | [diff] [blame] | 2119 | 		snprintf(info->fix.id, 16, "TwisterK"); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 2120 | 		break; | 
 | 2121 | 	case FB_ACCEL_PROSAVAGE_DDR: | 
| Antonino A. Daplas | 7b6a186 | 2005-09-15 20:58:57 +0800 | [diff] [blame] | 2122 | 		par->chip = S3_PROSAVAGE; | 
| Antonino A. Daplas | 026fbe1 | 2006-06-26 00:26:36 -0700 | [diff] [blame] | 2123 | 		snprintf(info->fix.id, 16, "ProSavageDDR"); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 2124 | 		break; | 
 | 2125 | 	case FB_ACCEL_PROSAVAGE_DDRK: | 
 | 2126 | 		par->chip = S3_PROSAVAGE; | 
| Antonino A. Daplas | 026fbe1 | 2006-06-26 00:26:36 -0700 | [diff] [blame] | 2127 | 		snprintf(info->fix.id, 16, "ProSavage8"); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 2128 | 		break; | 
 | 2129 | 	} | 
 | 2130 |  | 
 | 2131 | 	if (S3_SAVAGE3D_SERIES(par->chip)) { | 
 | 2132 | 		par->SavageWaitIdle = savage3D_waitidle; | 
 | 2133 | 		par->SavageWaitFifo = savage3D_waitfifo; | 
 | 2134 | 	} else if (S3_SAVAGE4_SERIES(par->chip) || | 
 | 2135 | 		   S3_SUPERSAVAGE == par->chip) { | 
 | 2136 | 		par->SavageWaitIdle = savage4_waitidle; | 
 | 2137 | 		par->SavageWaitFifo = savage4_waitfifo; | 
 | 2138 | 	} else { | 
 | 2139 | 		par->SavageWaitIdle = savage2000_waitidle; | 
 | 2140 | 		par->SavageWaitFifo = savage2000_waitfifo; | 
 | 2141 | 	} | 
 | 2142 |  | 
 | 2143 | 	info->var.nonstd      = 0; | 
 | 2144 | 	info->var.activate    = FB_ACTIVATE_NOW; | 
 | 2145 | 	info->var.width       = -1; | 
 | 2146 | 	info->var.height      = -1; | 
 | 2147 | 	info->var.accel_flags = 0; | 
 | 2148 |  | 
 | 2149 | 	info->fbops          = &savagefb_ops; | 
 | 2150 | 	info->flags          = FBINFO_DEFAULT | | 
 | 2151 | 		               FBINFO_HWACCEL_YPAN | | 
 | 2152 | 		               FBINFO_HWACCEL_XPAN; | 
 | 2153 |  | 
 | 2154 | 	info->pseudo_palette = par->pseudo_palette; | 
 | 2155 |  | 
 | 2156 | #if defined(CONFIG_FB_SAVAGE_ACCEL) | 
 | 2157 | 	/* FIFO size + padding for commands */ | 
| Yoann Padioleau | dd00cc4 | 2007-07-19 01:49:03 -0700 | [diff] [blame] | 2158 | 	info->pixmap.addr = kcalloc(8, 1024, GFP_KERNEL); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 2159 |  | 
 | 2160 | 	err = -ENOMEM; | 
 | 2161 | 	if (info->pixmap.addr) { | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 2162 | 		info->pixmap.size = 8*1024; | 
 | 2163 | 		info->pixmap.scan_align = 4; | 
 | 2164 | 		info->pixmap.buf_align = 4; | 
| James Simmons | 58a6064 | 2005-06-21 17:17:08 -0700 | [diff] [blame] | 2165 | 		info->pixmap.access_align = 32; | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 2166 |  | 
| Antonino A. Daplas | 026fbe1 | 2006-06-26 00:26:36 -0700 | [diff] [blame] | 2167 | 		err = fb_alloc_cmap(&info->cmap, NR_PALETTE, 0); | 
| Olaf Hering | 6062bfa | 2005-09-09 13:04:55 -0700 | [diff] [blame] | 2168 | 		if (!err) | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 2169 | 		info->flags |= FBINFO_HWACCEL_COPYAREA | | 
 | 2170 | 	                       FBINFO_HWACCEL_FILLRECT | | 
 | 2171 | 		               FBINFO_HWACCEL_IMAGEBLIT; | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 2172 | 	} | 
 | 2173 | #endif | 
 | 2174 | 	return err; | 
 | 2175 | } | 
 | 2176 |  | 
 | 2177 | /* --------------------------------------------------------------------- */ | 
 | 2178 |  | 
| Antonino A. Daplas | 026fbe1 | 2006-06-26 00:26:36 -0700 | [diff] [blame] | 2179 | static int __devinit savagefb_probe(struct pci_dev* dev, | 
 | 2180 | 				    const struct pci_device_id* id) | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 2181 | { | 
 | 2182 | 	struct fb_info *info; | 
 | 2183 | 	struct savagefb_par *par; | 
 | 2184 | 	u_int h_sync, v_sync; | 
 | 2185 | 	int err, lpitch; | 
 | 2186 | 	int video_len; | 
 | 2187 |  | 
 | 2188 | 	DBG("savagefb_probe"); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 2189 |  | 
 | 2190 | 	info = framebuffer_alloc(sizeof(struct savagefb_par), &dev->dev); | 
 | 2191 | 	if (!info) | 
 | 2192 | 		return -ENOMEM; | 
 | 2193 | 	par = info->par; | 
| Antonino A. Daplas | 22d832e | 2007-05-08 00:38:36 -0700 | [diff] [blame] | 2194 | 	mutex_init(&par->open_lock); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 2195 | 	err = pci_enable_device(dev); | 
 | 2196 | 	if (err) | 
 | 2197 | 		goto failed_enable; | 
 | 2198 |  | 
| Olaf Hering | 6062bfa | 2005-09-09 13:04:55 -0700 | [diff] [blame] | 2199 | 	if ((err = pci_request_regions(dev, "savagefb"))) { | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 2200 | 		printk(KERN_ERR "cannot request PCI regions\n"); | 
 | 2201 | 		goto failed_enable; | 
 | 2202 | 	} | 
 | 2203 |  | 
 | 2204 | 	err = -ENOMEM; | 
 | 2205 |  | 
| Olaf Hering | 6062bfa | 2005-09-09 13:04:55 -0700 | [diff] [blame] | 2206 | 	if ((err = savage_init_fb_info(info, dev, id))) | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 2207 | 		goto failed_init; | 
 | 2208 |  | 
 | 2209 | 	err = savage_map_mmio(info); | 
 | 2210 | 	if (err) | 
 | 2211 | 		goto failed_mmio; | 
 | 2212 |  | 
 | 2213 | 	video_len = savage_init_hw(par); | 
| Olaf Hering | 6062bfa | 2005-09-09 13:04:55 -0700 | [diff] [blame] | 2214 | 	/* FIXME: cant be negative */ | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 2215 | 	if (video_len < 0) { | 
 | 2216 | 		err = video_len; | 
 | 2217 | 		goto failed_mmio; | 
 | 2218 | 	} | 
 | 2219 |  | 
 | 2220 | 	err = savage_map_video(info, video_len); | 
 | 2221 | 	if (err) | 
 | 2222 | 		goto failed_video; | 
 | 2223 |  | 
 | 2224 | 	INIT_LIST_HEAD(&info->modelist); | 
 | 2225 | #if defined(CONFIG_FB_SAVAGE_I2C) | 
 | 2226 | 	savagefb_create_i2c_busses(info); | 
| Antonino A. Daplas | 1377671 | 2005-09-09 13:04:35 -0700 | [diff] [blame] | 2227 | 	savagefb_probe_i2c_connector(info, &par->edid); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 2228 | 	fb_edid_to_monspecs(par->edid, &info->monspecs); | 
| Antonino A. Daplas | 8d57f22 | 2006-03-11 03:27:25 -0800 | [diff] [blame] | 2229 | 	kfree(par->edid); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 2230 | 	fb_videomode_to_modelist(info->monspecs.modedb, | 
 | 2231 | 				 info->monspecs.modedb_len, | 
 | 2232 | 				 &info->modelist); | 
 | 2233 | #endif | 
 | 2234 | 	info->var = savagefb_var800x600x8; | 
 | 2235 |  | 
 | 2236 | 	if (mode_option) { | 
 | 2237 | 		fb_find_mode(&info->var, info, mode_option, | 
 | 2238 | 			     info->monspecs.modedb, info->monspecs.modedb_len, | 
 | 2239 | 			     NULL, 8); | 
 | 2240 | 	} else if (info->monspecs.modedb != NULL) { | 
| Geert Uytterhoeven | 9791d76 | 2007-02-12 00:55:19 -0800 | [diff] [blame] | 2241 | 		const struct fb_videomode *mode; | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 2242 |  | 
| Geert Uytterhoeven | 9791d76 | 2007-02-12 00:55:19 -0800 | [diff] [blame] | 2243 | 		mode = fb_find_best_display(&info->monspecs, &info->modelist); | 
 | 2244 | 		savage_update_var(&info->var, mode); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 2245 | 	} | 
 | 2246 |  | 
 | 2247 | 	/* maximize virtual vertical length */ | 
 | 2248 | 	lpitch = info->var.xres_virtual*((info->var.bits_per_pixel + 7) >> 3); | 
 | 2249 | 	info->var.yres_virtual = info->fix.smem_len/lpitch; | 
 | 2250 |  | 
 | 2251 | 	if (info->var.yres_virtual < info->var.yres) | 
 | 2252 | 		goto failed; | 
 | 2253 |  | 
 | 2254 | #if defined(CONFIG_FB_SAVAGE_ACCEL) | 
 | 2255 | 	/* | 
 | 2256 | 	 * The clipping coordinates are masked with 0xFFF, so limit our | 
 | 2257 | 	 * virtual resolutions to these sizes. | 
 | 2258 | 	 */ | 
 | 2259 | 	if (info->var.yres_virtual > 0x1000) | 
 | 2260 | 		info->var.yres_virtual = 0x1000; | 
 | 2261 |  | 
 | 2262 | 	if (info->var.xres_virtual > 0x1000) | 
 | 2263 | 		info->var.xres_virtual = 0x1000; | 
 | 2264 | #endif | 
 | 2265 | 	savagefb_check_var(&info->var, info); | 
 | 2266 | 	savagefb_set_fix(info); | 
 | 2267 |  | 
 | 2268 | 	/* | 
 | 2269 | 	 * Calculate the hsync and vsync frequencies.  Note that | 
 | 2270 | 	 * we split the 1e12 constant up so that we can preserve | 
 | 2271 | 	 * the precision and fit the results into 32-bit registers. | 
 | 2272 | 	 *  (1953125000 * 512 = 1e12) | 
 | 2273 | 	 */ | 
 | 2274 | 	h_sync = 1953125000 / info->var.pixclock; | 
 | 2275 | 	h_sync = h_sync * 512 / (info->var.xres + info->var.left_margin + | 
 | 2276 | 				 info->var.right_margin + | 
 | 2277 | 				 info->var.hsync_len); | 
 | 2278 | 	v_sync = h_sync / (info->var.yres + info->var.upper_margin + | 
 | 2279 | 			   info->var.lower_margin + info->var.vsync_len); | 
 | 2280 |  | 
 | 2281 | 	printk(KERN_INFO "savagefb v" SAVAGEFB_VERSION ": " | 
 | 2282 | 	       "%dkB VRAM, using %dx%d, %d.%03dkHz, %dHz\n", | 
 | 2283 | 	       info->fix.smem_len >> 10, | 
 | 2284 | 	       info->var.xres, info->var.yres, | 
 | 2285 | 	       h_sync / 1000, h_sync % 1000, v_sync); | 
 | 2286 |  | 
 | 2287 |  | 
 | 2288 | 	fb_destroy_modedb(info->monspecs.modedb); | 
 | 2289 | 	info->monspecs.modedb = NULL; | 
 | 2290 |  | 
| Antonino A. Daplas | 026fbe1 | 2006-06-26 00:26:36 -0700 | [diff] [blame] | 2291 | 	err = register_framebuffer(info); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 2292 | 	if (err < 0) | 
 | 2293 | 		goto failed; | 
 | 2294 |  | 
| Antonino A. Daplas | 026fbe1 | 2006-06-26 00:26:36 -0700 | [diff] [blame] | 2295 | 	printk(KERN_INFO "fb: S3 %s frame buffer device\n", | 
 | 2296 | 	       info->fix.id); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 2297 |  | 
 | 2298 | 	/* | 
 | 2299 | 	 * Our driver data | 
 | 2300 | 	 */ | 
 | 2301 | 	pci_set_drvdata(dev, info); | 
 | 2302 |  | 
 | 2303 | 	return 0; | 
 | 2304 |  | 
 | 2305 |  failed: | 
 | 2306 | #ifdef CONFIG_FB_SAVAGE_I2C | 
 | 2307 | 	savagefb_delete_i2c_busses(info); | 
 | 2308 | #endif | 
| Antonino A. Daplas | 026fbe1 | 2006-06-26 00:26:36 -0700 | [diff] [blame] | 2309 | 	fb_alloc_cmap(&info->cmap, 0, 0); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 2310 | 	savage_unmap_video(info); | 
 | 2311 |  failed_video: | 
| Antonino A. Daplas | 026fbe1 | 2006-06-26 00:26:36 -0700 | [diff] [blame] | 2312 | 	savage_unmap_mmio(info); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 2313 |  failed_mmio: | 
 | 2314 | 	kfree(info->pixmap.addr); | 
 | 2315 |  failed_init: | 
 | 2316 | 	pci_release_regions(dev); | 
 | 2317 |  failed_enable: | 
 | 2318 | 	framebuffer_release(info); | 
 | 2319 |  | 
 | 2320 | 	return err; | 
 | 2321 | } | 
 | 2322 |  | 
| Antonino A. Daplas | 026fbe1 | 2006-06-26 00:26:36 -0700 | [diff] [blame] | 2323 | static void __devexit savagefb_remove(struct pci_dev *dev) | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 2324 | { | 
| Antonino A. Daplas | b8901b0 | 2006-01-09 20:53:02 -0800 | [diff] [blame] | 2325 | 	struct fb_info *info = pci_get_drvdata(dev); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 2326 |  | 
 | 2327 | 	DBG("savagefb_remove"); | 
 | 2328 |  | 
 | 2329 | 	if (info) { | 
 | 2330 | 		/* | 
 | 2331 | 		 * If unregister_framebuffer fails, then | 
 | 2332 | 		 * we will be leaving hooks that could cause | 
 | 2333 | 		 * oopsen laying around. | 
 | 2334 | 		 */ | 
| Antonino A. Daplas | 026fbe1 | 2006-06-26 00:26:36 -0700 | [diff] [blame] | 2335 | 		if (unregister_framebuffer(info)) | 
 | 2336 | 			printk(KERN_WARNING "savagefb: danger danger! " | 
 | 2337 | 			       "Oopsen imminent!\n"); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 2338 |  | 
 | 2339 | #ifdef CONFIG_FB_SAVAGE_I2C | 
 | 2340 | 		savagefb_delete_i2c_busses(info); | 
 | 2341 | #endif | 
| Antonino A. Daplas | 026fbe1 | 2006-06-26 00:26:36 -0700 | [diff] [blame] | 2342 | 		fb_alloc_cmap(&info->cmap, 0, 0); | 
 | 2343 | 		savage_unmap_video(info); | 
 | 2344 | 		savage_unmap_mmio(info); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 2345 | 		kfree(info->pixmap.addr); | 
 | 2346 | 		pci_release_regions(dev); | 
 | 2347 | 		framebuffer_release(info); | 
 | 2348 |  | 
 | 2349 | 		/* | 
 | 2350 | 		 * Ensure that the driver data is no longer | 
 | 2351 | 		 * valid. | 
 | 2352 | 		 */ | 
 | 2353 | 		pci_set_drvdata(dev, NULL); | 
 | 2354 | 	} | 
 | 2355 | } | 
 | 2356 |  | 
| David Brownell | c78a7c2 | 2006-08-14 23:11:06 -0700 | [diff] [blame] | 2357 | static int savagefb_suspend(struct pci_dev *dev, pm_message_t mesg) | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 2358 | { | 
| Antonino A. Daplas | b8901b0 | 2006-01-09 20:53:02 -0800 | [diff] [blame] | 2359 | 	struct fb_info *info = pci_get_drvdata(dev); | 
 | 2360 | 	struct savagefb_par *par = info->par; | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 2361 |  | 
 | 2362 | 	DBG("savagefb_suspend"); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 2363 |  | 
| David Brownell | c78a7c2 | 2006-08-14 23:11:06 -0700 | [diff] [blame] | 2364 | 	if (mesg.event == PM_EVENT_PRETHAW) | 
 | 2365 | 		mesg.event = PM_EVENT_FREEZE; | 
 | 2366 | 	par->pm_state = mesg.event; | 
 | 2367 | 	dev->dev.power.power_state = mesg; | 
| Antonino A. Daplas | 1377671 | 2005-09-09 13:04:35 -0700 | [diff] [blame] | 2368 |  | 
 | 2369 | 	/* | 
 | 2370 | 	 * For PM_EVENT_FREEZE, do not power down so the console | 
 | 2371 | 	 * can remain active. | 
 | 2372 | 	 */ | 
| David Brownell | c78a7c2 | 2006-08-14 23:11:06 -0700 | [diff] [blame] | 2373 | 	if (mesg.event == PM_EVENT_FREEZE) | 
| Antonino A. Daplas | 1377671 | 2005-09-09 13:04:35 -0700 | [diff] [blame] | 2374 | 		return 0; | 
| Antonino A. Daplas | 1377671 | 2005-09-09 13:04:35 -0700 | [diff] [blame] | 2375 |  | 
| Torben Hohn | ac751ef | 2011-01-25 15:07:35 -0800 | [diff] [blame] | 2376 | 	console_lock(); | 
| Antonino A. Daplas | 1377671 | 2005-09-09 13:04:35 -0700 | [diff] [blame] | 2377 | 	fb_set_suspend(info, 1); | 
 | 2378 |  | 
 | 2379 | 	if (info->fbops->fb_sync) | 
 | 2380 | 		info->fbops->fb_sync(info); | 
 | 2381 |  | 
 | 2382 | 	savagefb_blank(FB_BLANK_POWERDOWN, info); | 
| Antonino A. Daplas | f8020dc | 2006-06-26 00:26:24 -0700 | [diff] [blame] | 2383 | 	savage_set_default_par(par, &par->save); | 
| Antonino A. Daplas | 1377671 | 2005-09-09 13:04:35 -0700 | [diff] [blame] | 2384 | 	savage_disable_mmio(par); | 
 | 2385 | 	pci_save_state(dev); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 2386 | 	pci_disable_device(dev); | 
| David Brownell | c78a7c2 | 2006-08-14 23:11:06 -0700 | [diff] [blame] | 2387 | 	pci_set_power_state(dev, pci_choose_state(dev, mesg)); | 
| Torben Hohn | ac751ef | 2011-01-25 15:07:35 -0800 | [diff] [blame] | 2388 | 	console_unlock(); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 2389 |  | 
 | 2390 | 	return 0; | 
 | 2391 | } | 
 | 2392 |  | 
| Antonino A. Daplas | 026fbe1 | 2006-06-26 00:26:36 -0700 | [diff] [blame] | 2393 | static int savagefb_resume(struct pci_dev* dev) | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 2394 | { | 
| Antonino A. Daplas | b8901b0 | 2006-01-09 20:53:02 -0800 | [diff] [blame] | 2395 | 	struct fb_info *info = pci_get_drvdata(dev); | 
 | 2396 | 	struct savagefb_par *par = info->par; | 
| Antonino A. Daplas | 1377671 | 2005-09-09 13:04:35 -0700 | [diff] [blame] | 2397 | 	int cur_state = par->pm_state; | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 2398 |  | 
 | 2399 | 	DBG("savage_resume"); | 
 | 2400 |  | 
| Antonino A. Daplas | 1377671 | 2005-09-09 13:04:35 -0700 | [diff] [blame] | 2401 | 	par->pm_state = PM_EVENT_ON; | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 2402 |  | 
| Antonino A. Daplas | 1377671 | 2005-09-09 13:04:35 -0700 | [diff] [blame] | 2403 | 	/* | 
 | 2404 | 	 * The adapter was not powered down coming back from a | 
 | 2405 | 	 * PM_EVENT_FREEZE. | 
 | 2406 | 	 */ | 
 | 2407 | 	if (cur_state == PM_EVENT_FREEZE) { | 
 | 2408 | 		pci_set_power_state(dev, PCI_D0); | 
 | 2409 | 		return 0; | 
 | 2410 | 	} | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 2411 |  | 
| Torben Hohn | ac751ef | 2011-01-25 15:07:35 -0800 | [diff] [blame] | 2412 | 	console_lock(); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 2413 |  | 
| Antonino A. Daplas | 1377671 | 2005-09-09 13:04:35 -0700 | [diff] [blame] | 2414 | 	pci_set_power_state(dev, PCI_D0); | 
 | 2415 | 	pci_restore_state(dev); | 
 | 2416 |  | 
| Antonino A. Daplas | 026fbe1 | 2006-06-26 00:26:36 -0700 | [diff] [blame] | 2417 | 	if (pci_enable_device(dev)) | 
| Antonino A. Daplas | 1377671 | 2005-09-09 13:04:35 -0700 | [diff] [blame] | 2418 | 		DBG("err"); | 
 | 2419 |  | 
 | 2420 | 	pci_set_master(dev); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 2421 | 	savage_enable_mmio(par); | 
 | 2422 | 	savage_init_hw(par); | 
| Antonino A. Daplas | f8020dc | 2006-06-26 00:26:24 -0700 | [diff] [blame] | 2423 | 	savagefb_set_par(info); | 
| Antonino A. Daplas | 026fbe1 | 2006-06-26 00:26:36 -0700 | [diff] [blame] | 2424 | 	fb_set_suspend(info, 0); | 
| Antonino A. Daplas | f8020dc | 2006-06-26 00:26:24 -0700 | [diff] [blame] | 2425 | 	savagefb_blank(FB_BLANK_UNBLANK, info); | 
| Torben Hohn | ac751ef | 2011-01-25 15:07:35 -0800 | [diff] [blame] | 2426 | 	console_unlock(); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 2427 |  | 
 | 2428 | 	return 0; | 
 | 2429 | } | 
 | 2430 |  | 
 | 2431 |  | 
 | 2432 | static struct pci_device_id savagefb_devices[] __devinitdata = { | 
 | 2433 | 	{PCI_VENDOR_ID_S3, PCI_CHIP_SUPSAV_MX128, | 
 | 2434 | 	 PCI_ANY_ID, PCI_ANY_ID, 0, 0, FB_ACCEL_SUPERSAVAGE}, | 
 | 2435 |  | 
 | 2436 | 	{PCI_VENDOR_ID_S3, PCI_CHIP_SUPSAV_MX64, | 
 | 2437 | 	 PCI_ANY_ID, PCI_ANY_ID, 0, 0, FB_ACCEL_SUPERSAVAGE}, | 
 | 2438 |  | 
 | 2439 | 	{PCI_VENDOR_ID_S3, PCI_CHIP_SUPSAV_MX64C, | 
 | 2440 | 	 PCI_ANY_ID, PCI_ANY_ID, 0, 0, FB_ACCEL_SUPERSAVAGE}, | 
 | 2441 |  | 
 | 2442 | 	{PCI_VENDOR_ID_S3, PCI_CHIP_SUPSAV_IX128SDR, | 
 | 2443 | 	 PCI_ANY_ID, PCI_ANY_ID, 0, 0, FB_ACCEL_SUPERSAVAGE}, | 
 | 2444 |  | 
 | 2445 | 	{PCI_VENDOR_ID_S3, PCI_CHIP_SUPSAV_IX128DDR, | 
 | 2446 | 	 PCI_ANY_ID, PCI_ANY_ID, 0, 0, FB_ACCEL_SUPERSAVAGE}, | 
 | 2447 |  | 
 | 2448 | 	{PCI_VENDOR_ID_S3, PCI_CHIP_SUPSAV_IX64SDR, | 
 | 2449 | 	 PCI_ANY_ID, PCI_ANY_ID, 0, 0, FB_ACCEL_SUPERSAVAGE}, | 
 | 2450 |  | 
 | 2451 | 	{PCI_VENDOR_ID_S3, PCI_CHIP_SUPSAV_IX64DDR, | 
 | 2452 | 	 PCI_ANY_ID, PCI_ANY_ID, 0, 0, FB_ACCEL_SUPERSAVAGE}, | 
 | 2453 |  | 
 | 2454 | 	{PCI_VENDOR_ID_S3, PCI_CHIP_SUPSAV_IXCSDR, | 
 | 2455 | 	 PCI_ANY_ID, PCI_ANY_ID, 0, 0, FB_ACCEL_SUPERSAVAGE}, | 
 | 2456 |  | 
 | 2457 | 	{PCI_VENDOR_ID_S3, PCI_CHIP_SUPSAV_IXCDDR, | 
 | 2458 | 	 PCI_ANY_ID, PCI_ANY_ID, 0, 0, FB_ACCEL_SUPERSAVAGE}, | 
 | 2459 |  | 
 | 2460 | 	{PCI_VENDOR_ID_S3, PCI_CHIP_SAVAGE4, | 
 | 2461 | 	 PCI_ANY_ID, PCI_ANY_ID, 0, 0, FB_ACCEL_SAVAGE4}, | 
 | 2462 |  | 
 | 2463 | 	{PCI_VENDOR_ID_S3, PCI_CHIP_SAVAGE3D, | 
 | 2464 | 	 PCI_ANY_ID, PCI_ANY_ID, 0, 0, FB_ACCEL_SAVAGE3D}, | 
 | 2465 |  | 
 | 2466 | 	{PCI_VENDOR_ID_S3, PCI_CHIP_SAVAGE3D_MV, | 
 | 2467 | 	 PCI_ANY_ID, PCI_ANY_ID, 0, 0, FB_ACCEL_SAVAGE3D_MV}, | 
 | 2468 |  | 
 | 2469 | 	{PCI_VENDOR_ID_S3, PCI_CHIP_SAVAGE2000, | 
 | 2470 | 	 PCI_ANY_ID, PCI_ANY_ID, 0, 0, FB_ACCEL_SAVAGE2000}, | 
 | 2471 |  | 
 | 2472 | 	{PCI_VENDOR_ID_S3, PCI_CHIP_SAVAGE_MX_MV, | 
 | 2473 | 	 PCI_ANY_ID, PCI_ANY_ID, 0, 0, FB_ACCEL_SAVAGE_MX_MV}, | 
 | 2474 |  | 
 | 2475 | 	{PCI_VENDOR_ID_S3, PCI_CHIP_SAVAGE_MX, | 
 | 2476 | 	 PCI_ANY_ID, PCI_ANY_ID, 0, 0, FB_ACCEL_SAVAGE_MX}, | 
 | 2477 |  | 
 | 2478 | 	{PCI_VENDOR_ID_S3, PCI_CHIP_SAVAGE_IX_MV, | 
 | 2479 | 	 PCI_ANY_ID, PCI_ANY_ID, 0, 0, FB_ACCEL_SAVAGE_IX_MV}, | 
 | 2480 |  | 
 | 2481 | 	{PCI_VENDOR_ID_S3, PCI_CHIP_SAVAGE_IX, | 
 | 2482 | 	 PCI_ANY_ID, PCI_ANY_ID, 0, 0, FB_ACCEL_SAVAGE_IX}, | 
 | 2483 |  | 
 | 2484 | 	{PCI_VENDOR_ID_S3, PCI_CHIP_PROSAVAGE_PM, | 
 | 2485 | 	 PCI_ANY_ID, PCI_ANY_ID, 0, 0, FB_ACCEL_PROSAVAGE_PM}, | 
 | 2486 |  | 
 | 2487 | 	{PCI_VENDOR_ID_S3, PCI_CHIP_PROSAVAGE_KM, | 
 | 2488 | 	 PCI_ANY_ID, PCI_ANY_ID, 0, 0, FB_ACCEL_PROSAVAGE_KM}, | 
 | 2489 |  | 
 | 2490 | 	{PCI_VENDOR_ID_S3, PCI_CHIP_S3TWISTER_P, | 
 | 2491 | 	 PCI_ANY_ID, PCI_ANY_ID, 0, 0, FB_ACCEL_S3TWISTER_P}, | 
 | 2492 |  | 
 | 2493 | 	{PCI_VENDOR_ID_S3, PCI_CHIP_S3TWISTER_K, | 
 | 2494 | 	 PCI_ANY_ID, PCI_ANY_ID, 0, 0, FB_ACCEL_S3TWISTER_K}, | 
 | 2495 |  | 
 | 2496 | 	{PCI_VENDOR_ID_S3, PCI_CHIP_PROSAVAGE_DDR, | 
 | 2497 | 	 PCI_ANY_ID, PCI_ANY_ID, 0, 0, FB_ACCEL_PROSAVAGE_DDR}, | 
 | 2498 |  | 
 | 2499 | 	{PCI_VENDOR_ID_S3, PCI_CHIP_PROSAVAGE_DDRK, | 
 | 2500 | 	 PCI_ANY_ID, PCI_ANY_ID, 0, 0, FB_ACCEL_PROSAVAGE_DDRK}, | 
 | 2501 |  | 
 | 2502 | 	{0, 0, 0, 0, 0, 0, 0} | 
 | 2503 | }; | 
 | 2504 |  | 
 | 2505 | MODULE_DEVICE_TABLE(pci, savagefb_devices); | 
 | 2506 |  | 
 | 2507 | static struct pci_driver savagefb_driver = { | 
 | 2508 | 	.name =     "savagefb", | 
 | 2509 | 	.id_table = savagefb_devices, | 
 | 2510 | 	.probe =    savagefb_probe, | 
 | 2511 | 	.suspend =  savagefb_suspend, | 
 | 2512 | 	.resume =   savagefb_resume, | 
 | 2513 | 	.remove =   __devexit_p(savagefb_remove) | 
 | 2514 | }; | 
 | 2515 |  | 
 | 2516 | /* **************************** exit-time only **************************** */ | 
 | 2517 |  | 
| Antonino A. Daplas | 026fbe1 | 2006-06-26 00:26:36 -0700 | [diff] [blame] | 2518 | static void __exit savage_done(void) | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 2519 | { | 
 | 2520 | 	DBG("savage_done"); | 
| Antonino A. Daplas | 026fbe1 | 2006-06-26 00:26:36 -0700 | [diff] [blame] | 2521 | 	pci_unregister_driver(&savagefb_driver); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 2522 | } | 
 | 2523 |  | 
 | 2524 |  | 
 | 2525 | /* ************************* init in-kernel code ************************** */ | 
 | 2526 |  | 
 | 2527 | static int __init savagefb_setup(char *options) | 
 | 2528 | { | 
 | 2529 | #ifndef MODULE | 
 | 2530 | 	char *this_opt; | 
 | 2531 |  | 
 | 2532 | 	if (!options || !*options) | 
 | 2533 | 		return 0; | 
 | 2534 |  | 
 | 2535 | 	while ((this_opt = strsep(&options, ",")) != NULL) { | 
 | 2536 | 		mode_option = this_opt; | 
 | 2537 | 	} | 
 | 2538 | #endif /* !MODULE */ | 
 | 2539 | 	return 0; | 
 | 2540 | } | 
 | 2541 |  | 
 | 2542 | static int __init savagefb_init(void) | 
 | 2543 | { | 
 | 2544 | 	char *option; | 
 | 2545 |  | 
 | 2546 | 	DBG("savagefb_init"); | 
 | 2547 |  | 
 | 2548 | 	if (fb_get_options("savagefb", &option)) | 
 | 2549 | 		return -ENODEV; | 
 | 2550 |  | 
 | 2551 | 	savagefb_setup(option); | 
| Antonino A. Daplas | 026fbe1 | 2006-06-26 00:26:36 -0700 | [diff] [blame] | 2552 | 	return pci_register_driver(&savagefb_driver); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 2553 |  | 
 | 2554 | } | 
 | 2555 |  | 
 | 2556 | module_init(savagefb_init); | 
 | 2557 | module_exit(savage_done); | 
| Antonino A. Daplas | c52890c | 2005-09-09 13:09:59 -0700 | [diff] [blame] | 2558 |  | 
 | 2559 | module_param(mode_option, charp, 0); | 
 | 2560 | MODULE_PARM_DESC(mode_option, "Specify initial video mode"); |